main.c revision 1.1.1.1 1 /*
2 * Copyright (c) 1983, 1988, 1993
3 * Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #ifndef lint
35 char copyright[] =
36 "@(#) Copyright (c) 1983, 1988, 1993\n\
37 Regents of the University of California. All rights reserved.\n";
38 #endif /* not lint */
39
40 #ifndef lint
41 static char sccsid[] = "@(#)main.c 8.4 (Berkeley) 3/1/94";
42 #endif /* not lint */
43
44 #include <sys/param.h>
45 #include <sys/file.h>
46 #include <sys/protosw.h>
47 #include <sys/socket.h>
48
49 #include <netinet/in.h>
50
51 #include <ctype.h>
52 #include <errno.h>
53 #include <kvm.h>
54 #include <limits.h>
55 #include <netdb.h>
56 #include <nlist.h>
57 #include <paths.h>
58 #include <stdio.h>
59 #include <stdlib.h>
60 #include <string.h>
61 #include <unistd.h>
62 #include "netstat.h"
63
64 struct nlist nl[] = {
65 #define N_MBSTAT 0
66 { "_mbstat" },
67 #define N_IPSTAT 1
68 { "_ipstat" },
69 #define N_TCB 2
70 { "_tcb" },
71 #define N_TCPSTAT 3
72 { "_tcpstat" },
73 #define N_UDB 4
74 { "_udb" },
75 #define N_UDPSTAT 5
76 { "_udpstat" },
77 #define N_IFNET 6
78 { "_ifnet" },
79 #define N_IMP 7
80 { "_imp_softc" },
81 #define N_ICMPSTAT 8
82 { "_icmpstat" },
83 #define N_RTSTAT 9
84 { "_rtstat" },
85 #define N_UNIXSW 10
86 { "_unixsw" },
87 #define N_IDP 11
88 { "_nspcb"},
89 #define N_IDPSTAT 12
90 { "_idpstat"},
91 #define N_SPPSTAT 13
92 { "_spp_istat"},
93 #define N_NSERR 14
94 { "_ns_errstat"},
95 #define N_CLNPSTAT 15
96 { "_clnp_stat"},
97 #define IN_NOTUSED 16
98 { "_tp_inpcb" },
99 #define ISO_TP 17
100 { "_tp_refinfo" },
101 #define N_TPSTAT 18
102 { "_tp_stat" },
103 #define N_ESISSTAT 19
104 { "_esis_stat"},
105 #define N_NIMP 20
106 { "_nimp"},
107 #define N_RTREE 21
108 { "_rt_tables"},
109 #define N_CLTP 22
110 { "_cltb"},
111 #define N_CLTPSTAT 23
112 { "_cltpstat"},
113 #define N_NFILE 24
114 { "_nfile" },
115 #define N_FILE 25
116 { "_file" },
117 #define N_IGMPSTAT 26
118 { "_igmpstat" },
119 #define N_MRTPROTO 27
120 { "_ip_mrtproto" },
121 #define N_MRTSTAT 28
122 { "_mrtstat" },
123 #define N_MRTTABLE 29
124 { "_mrttable" },
125 #define N_VIFTABLE 30
126 { "_viftable" },
127 "",
128 };
129
130 struct protox {
131 u_char pr_index; /* index into nlist of cb head */
132 u_char pr_sindex; /* index into nlist of stat block */
133 u_char pr_wanted; /* 1 if wanted, 0 otherwise */
134 void (*pr_cblocks)(); /* control blocks printing routine */
135 void (*pr_stats)(); /* statistics printing routine */
136 char *pr_name; /* well-known name */
137 } protox[] = {
138 { N_TCB, N_TCPSTAT, 1, protopr,
139 tcp_stats, "tcp" },
140 { N_UDB, N_UDPSTAT, 1, protopr,
141 udp_stats, "udp" },
142 { -1, N_IPSTAT, 1, 0,
143 ip_stats, "ip" },
144 { -1, N_ICMPSTAT, 1, 0,
145 icmp_stats, "icmp" },
146 { -1, N_IGMPSTAT, 1, 0,
147 igmp_stats, "igmp" },
148 { -1, -1, 0, 0,
149 0, 0 }
150 };
151
152 struct protox nsprotox[] = {
153 { N_IDP, N_IDPSTAT, 1, nsprotopr,
154 idp_stats, "idp" },
155 { N_IDP, N_SPPSTAT, 1, nsprotopr,
156 spp_stats, "spp" },
157 { -1, N_NSERR, 1, 0,
158 nserr_stats, "ns_err" },
159 { -1, -1, 0, 0,
160 0, 0 }
161 };
162
163 struct protox isoprotox[] = {
164 { ISO_TP, N_TPSTAT, 1, iso_protopr,
165 tp_stats, "tp" },
166 { N_CLTP, N_CLTPSTAT, 1, iso_protopr,
167 cltp_stats, "cltp" },
168 { -1, N_CLNPSTAT, 1, 0,
169 clnp_stats, "clnp"},
170 { -1, N_ESISSTAT, 1, 0,
171 esis_stats, "esis"},
172 { -1, -1, 0, 0,
173 0, 0 }
174 };
175
176 struct protox *protoprotox[] = { protox, nsprotox, isoprotox, NULL };
177
178 static void printproto __P((struct protox *, char *));
179 static void usage __P((void));
180 static struct protox *name2protox __P((char *));
181 static struct protox *knownname __P((char *));
182
183 kvm_t *kvmd;
184
185 int
186 main(argc, argv)
187 int argc;
188 char *argv[];
189 {
190 extern char *optarg;
191 extern int optind;
192 register struct protoent *p;
193 register struct protox *tp; /* for printing cblocks & stats */
194 register char *cp;
195 int ch;
196 char *nlistf = NULL, *memf = NULL;
197 char buf[_POSIX2_LINE_MAX];
198
199 if (cp = rindex(argv[0], '/'))
200 prog = cp + 1;
201 else
202 prog = argv[0];
203 af = AF_UNSPEC;
204
205 while ((ch = getopt(argc, argv, "Aadf:ghI:iM:mN:np:rstuw:")) != EOF)
206 switch(ch) {
207 case 'A':
208 Aflag = 1;
209 break;
210 case 'a':
211 aflag = 1;
212 break;
213 case 'd':
214 dflag = 1;
215 break;
216 case 'f':
217 if (strcmp(optarg, "ns") == 0)
218 af = AF_NS;
219 else if (strcmp(optarg, "inet") == 0)
220 af = AF_INET;
221 else if (strcmp(optarg, "unix") == 0)
222 af = AF_UNIX;
223 else if (strcmp(optarg, "iso") == 0)
224 af = AF_ISO;
225 else {
226 (void)fprintf(stderr,
227 "%s: %s: unknown address family\n",
228 prog, optarg);
229 exit(1);
230 }
231 break;
232 case 'g':
233 gflag = 1;
234 break;
235 case 'I': {
236 char *cp;
237
238 iflag = 1;
239 for (cp = interface = optarg; isalpha(*cp); cp++)
240 continue;
241 unit = atoi(cp);
242 *cp = '\0';
243 break;
244 }
245 case 'i':
246 iflag = 1;
247 break;
248 case 'M':
249 memf = optarg;
250 break;
251 case 'm':
252 mflag = 1;
253 break;
254 case 'N':
255 nlistf = optarg;
256 break;
257 case 'n':
258 nflag = 1;
259 break;
260 case 'p':
261 if ((tp = name2protox(optarg)) == NULL) {
262 (void)fprintf(stderr,
263 "%s: %s: unknown or uninstrumented protocol\n",
264 prog, optarg);
265 exit(1);
266 }
267 pflag = 1;
268 break;
269 case 'r':
270 rflag = 1;
271 break;
272 case 's':
273 ++sflag;
274 break;
275 case 't':
276 tflag = 1;
277 break;
278 case 'u':
279 af = AF_UNIX;
280 break;
281 case 'w':
282 interval = atoi(optarg);
283 iflag = 1;
284 break;
285 case '?':
286 default:
287 usage();
288 }
289 argv += optind;
290 argc -= optind;
291
292 #define BACKWARD_COMPATIBILITY
293 #ifdef BACKWARD_COMPATIBILITY
294 if (*argv) {
295 if (isdigit(**argv)) {
296 interval = atoi(*argv);
297 if (interval <= 0)
298 usage();
299 ++argv;
300 iflag = 1;
301 }
302 if (*argv) {
303 nlistf = *argv;
304 if (*++argv)
305 memf = *argv;
306 }
307 }
308 #endif
309
310 /*
311 * Discard setgid privileges if not the running kernel so that bad
312 * guys can't print interesting stuff from kernel memory.
313 */
314 if (nlistf != NULL || memf != NULL)
315 setgid(getgid());
316
317 if ((kvmd = kvm_open(nlistf, memf, NULL, O_RDONLY, prog)) == NULL) {
318 fprintf(stderr, "%s: kvm_open: %s\n", prog, buf);
319 exit(1);
320 }
321 if (kvm_nlist(kvmd, nl) < 0 || nl[0].n_type == 0) {
322 if (nlistf)
323 fprintf(stderr, "%s: %s: no namelist\n", prog, nlistf);
324 else
325 fprintf(stderr, "%s: no namelist\n", prog);
326 exit(1);
327 }
328 if (mflag) {
329 mbpr(nl[N_MBSTAT].n_value);
330 exit(0);
331 }
332 if (pflag) {
333 if (tp->pr_stats)
334 (*tp->pr_stats)(nl[tp->pr_sindex].n_value,
335 tp->pr_name);
336 else
337 printf("%s: no stats routine\n", tp->pr_name);
338 exit(0);
339 }
340 /*
341 * Keep file descriptors open to avoid overhead
342 * of open/close on each call to get* routines.
343 */
344 sethostent(1);
345 setnetent(1);
346 if (iflag) {
347 intpr(interval, nl[N_IFNET].n_value);
348 exit(0);
349 }
350 if (rflag) {
351 if (sflag)
352 rt_stats(nl[N_RTSTAT].n_value);
353 else
354 routepr(nl[N_RTREE].n_value);
355 exit(0);
356 }
357 if (gflag) {
358 if (sflag)
359 mrt_stats(nl[N_MRTPROTO].n_value,
360 nl[N_MRTSTAT].n_value);
361 else
362 mroutepr(nl[N_MRTPROTO].n_value,
363 nl[N_MRTTABLE].n_value,
364 nl[N_VIFTABLE].n_value);
365 exit(0);
366 }
367 if (af == AF_INET || af == AF_UNSPEC) {
368 setprotoent(1);
369 setservent(1);
370 /* ugh, this is O(MN) ... why do we do this? */
371 while (p = getprotoent()) {
372 for (tp = protox; tp->pr_name; tp++)
373 if (strcmp(tp->pr_name, p->p_name) == 0)
374 break;
375 if (tp->pr_name == 0 || tp->pr_wanted == 0)
376 continue;
377 printproto(tp, p->p_name);
378 }
379 endprotoent();
380 }
381 if (af == AF_NS || af == AF_UNSPEC)
382 for (tp = nsprotox; tp->pr_name; tp++)
383 printproto(tp, tp->pr_name);
384 if (af == AF_ISO || af == AF_UNSPEC)
385 for (tp = isoprotox; tp->pr_name; tp++)
386 printproto(tp, tp->pr_name);
387 if ((af == AF_UNIX || af == AF_UNSPEC) && !sflag)
388 unixpr(nl[N_UNIXSW].n_value);
389 exit(0);
390 }
391
392 /*
393 * Print out protocol statistics or control blocks (per sflag).
394 * If the interface was not specifically requested, and the symbol
395 * is not in the namelist, ignore this one.
396 */
397 static void
398 printproto(tp, name)
399 register struct protox *tp;
400 char *name;
401 {
402 void (*pr)();
403 u_long off;
404
405 if (sflag) {
406 pr = tp->pr_stats;
407 off = nl[tp->pr_sindex].n_value;
408 } else {
409 pr = tp->pr_cblocks;
410 off = nl[tp->pr_index].n_value;
411 }
412 if (pr != NULL && (off || af != AF_UNSPEC))
413 (*pr)(off, name);
414 }
415
416 /*
417 * Read kernel memory, return 0 on success.
418 */
419 int
420 kread(addr, buf, size)
421 u_long addr;
422 char *buf;
423 int size;
424 {
425
426 if (kvm_read(kvmd, addr, buf, size) != size) {
427 /* XXX this duplicates kvm_read's error printout */
428 (void)fprintf(stderr, "%s: kvm_read %s\n", prog,
429 kvm_geterr(kvmd));
430 return (-1);
431 }
432 return (0);
433 }
434
435 char *
436 plural(n)
437 int n;
438 {
439 return (n != 1 ? "s" : "");
440 }
441
442 char *
443 plurales(n)
444 int n;
445 {
446 return (n != 1 ? "es" : "");
447 }
448
449 /*
450 * Find the protox for the given "well-known" name.
451 */
452 static struct protox *
453 knownname(name)
454 char *name;
455 {
456 struct protox **tpp, *tp;
457
458 for (tpp = protoprotox; *tpp; tpp++)
459 for (tp = *tpp; tp->pr_name; tp++)
460 if (strcmp(tp->pr_name, name) == 0)
461 return (tp);
462 return (NULL);
463 }
464
465 /*
466 * Find the protox corresponding to name.
467 */
468 static struct protox *
469 name2protox(name)
470 char *name;
471 {
472 struct protox *tp;
473 char **alias; /* alias from p->aliases */
474 struct protoent *p;
475
476 /*
477 * Try to find the name in the list of "well-known" names. If that
478 * fails, check if name is an alias for an Internet protocol.
479 */
480 if (tp = knownname(name))
481 return (tp);
482
483 setprotoent(1); /* make protocol lookup cheaper */
484 while (p = getprotoent()) {
485 /* assert: name not same as p->name */
486 for (alias = p->p_aliases; *alias; alias++)
487 if (strcmp(name, *alias) == 0) {
488 endprotoent();
489 return (knownname(p->p_name));
490 }
491 }
492 endprotoent();
493 return (NULL);
494 }
495
496 static void
497 usage()
498 {
499 (void)fprintf(stderr,
500 "usage: %s [-Aan] [-f address_family] [-M core] [-N system]\n", prog);
501 (void)fprintf(stderr,
502 " %s [-ghimnrs] [-f address_family] [-M core] [-N system]\n", prog);
503 (void)fprintf(stderr,
504 " %s [-n] [-I interface] [-M core] [-N system] [-w wait]\n", prog);
505 (void)fprintf(stderr,
506 " %s [-M core] [-N system] [-p protocol]\n", prog);
507 exit(1);
508 }
509