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