Annotation of src/usr.bin/netstat/main.c, Revision 1.71
1.71 ! deraadt 1: /* $OpenBSD: main.c,v 1.70 2007/12/11 20:14:45 deraadt Exp $ */
1.2 deraadt 2: /* $NetBSD: main.c,v 1.9 1996/05/07 02:55:02 thorpej Exp $ */
1.1 deraadt 3:
4: /*
5: * Copyright (c) 1983, 1988, 1993
6: * Regents of the University of California. All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
1.36 millert 16: * 3. Neither the name of the University nor the names of its contributors
1.1 deraadt 17: * may be used to endorse or promote products derived from this software
18: * without specific prior written permission.
19: *
20: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30: * SUCH DAMAGE.
31: */
32:
33: #ifndef lint
34: char copyright[] =
35: "@(#) Copyright (c) 1983, 1988, 1993\n\
36: Regents of the University of California. All rights reserved.\n";
37: #endif /* not lint */
38:
39: #ifndef lint
40: #if 0
41: static char sccsid[] = "from: @(#)main.c 8.4 (Berkeley) 3/1/94";
42: #else
1.71 ! deraadt 43: static char *rcsid = "$OpenBSD: main.c,v 1.70 2007/12/11 20:14:45 deraadt Exp $";
1.1 deraadt 44: #endif
45: #endif /* not lint */
46:
47: #include <sys/param.h>
48: #include <sys/file.h>
49: #include <sys/protosw.h>
50: #include <sys/socket.h>
51:
1.68 claudio 52: #include <net/route.h>
1.1 deraadt 53: #include <netinet/in.h>
54:
55: #include <ctype.h>
1.61 djm 56: #include <err.h>
1.1 deraadt 57: #include <errno.h>
58: #include <kvm.h>
59: #include <limits.h>
60: #include <netdb.h>
61: #include <nlist.h>
62: #include <paths.h>
63: #include <stdio.h>
64: #include <stdlib.h>
65: #include <string.h>
66: #include <unistd.h>
67: #include "netstat.h"
68:
69: struct nlist nl[] = {
1.71 ! deraadt 70: #define N_TCBTABLE 0
1.1 deraadt 71: { "_tcbtable" },
1.71 ! deraadt 72: #define N_UDBTABLE 1
1.1 deraadt 73: { "_udbtable" },
1.71 ! deraadt 74: #define N_DDPCB 2
! 75: { "_ddpcb"},
! 76: #define N_IFNET 3
1.1 deraadt 77: { "_ifnet" },
1.71 ! deraadt 78: #define N_UNIXSW 4
1.1 deraadt 79: { "_unixsw" },
1.71 ! deraadt 80:
! 81: #define N_MFCHASHTBL 5
1.1 deraadt 82: { "_mfchashtbl" },
1.71 ! deraadt 83: #define N_MFCHASH 6
1.1 deraadt 84: { "_mfchash" },
1.71 ! deraadt 85: #define N_VIFTABLE 7
1.1 deraadt 86: { "_viftable" },
1.71 ! deraadt 87:
! 88: #define N_MF6CTABLE 8
1.19 itojun 89: { "_mf6ctable" },
1.71 ! deraadt 90: #define N_MIF6TABLE 9
1.19 itojun 91: { "_mif6table" },
1.71 ! deraadt 92:
! 93: #define N_RTREE 10
! 94: { "_rt_tables"},
! 95: #define N_RTMASK 11
! 96: { "_mask_rnhead" },
! 97: #define N_AF2RTAFIDX 12
! 98: { "_af2rtafidx" },
! 99: #define N_RTBLIDMAX 13
! 100: { "_rtbl_id_max" },
! 101:
! 102: #define N_RAWIPTABLE 14
1.40 markus 103: { "_rawcbtable" },
1.71 ! deraadt 104: #define N_RAWIP6TABLE 15
1.40 markus 105: { "_rawin6pcbtable" },
1.71 ! deraadt 106:
! 107: #define N_RTSTAT 16
! 108: { "_rtstat" },
! 109:
1.55 deraadt 110: { ""}
1.1 deraadt 111: };
112:
113: struct protox {
1.38 deraadt 114: u_char pr_index; /* index into nlist of cb head */
115: void (*pr_cblocks)(u_long, char *); /* control blocks printing routine */
1.71 ! deraadt 116: void (*pr_stats)(char *); /* statistics printing routine */
1.59 markus 117: void (*pr_dump)(u_long); /* pcb printing routine */
1.38 deraadt 118: char *pr_name; /* well-known name */
1.1 deraadt 119: } protox[] = {
1.71 ! deraadt 120: { N_TCBTABLE, protopr, tcp_stats, tcp_dump, "tcp" },
! 121: { N_UDBTABLE, protopr, udp_stats, NULL, "udp" },
! 122: { N_RAWIPTABLE, protopr, ip_stats, NULL, "ip" },
! 123: { -1, NULL, icmp_stats, NULL, "icmp" },
! 124: { -1, NULL, igmp_stats, NULL, "igmp" },
! 125: { -1, NULL, ah_stats, NULL, "ah" },
! 126: { -1, NULL, esp_stats, NULL, "esp" },
! 127: { -1, NULL, ipip_stats, NULL, "ipencap" },
! 128: { -1, NULL, etherip_stats, NULL, "etherip" },
! 129: { -1, NULL, ipcomp_stats, NULL, "ipcomp" },
! 130: { -1, NULL, carp_stats, NULL, "carp" },
! 131: { -1, NULL, pfsync_stats, NULL, "pfsync" },
! 132: { -1, NULL, pim_stats, NULL, "pim" },
! 133: { -1, NULL, NULL, NULL, NULL }
1.1 deraadt 134: };
135:
1.19 itojun 136: struct protox ip6protox[] = {
1.71 ! deraadt 137: { N_TCBTABLE, ip6protopr, NULL, tcp_dump, "tcp" },
! 138: { N_UDBTABLE, ip6protopr, NULL, NULL, "udp" },
! 139: { N_RAWIP6TABLE,ip6protopr, ip6_stats, NULL, "ip6" },
! 140: { -1, NULL, icmp6_stats, NULL, "icmp6" },
! 141: { -1, NULL, pim6_stats, NULL, "pim6" },
! 142: { -1, NULL, rip6_stats, NULL, "rip6" },
! 143: { -1, NULL, NULL, NULL, NULL }
1.19 itojun 144: };
145:
1.12 denny 146: struct protox atalkprotox[] = {
1.71 ! deraadt 147: { N_DDPCB, atalkprotopr, ddp_stats, NULL, "ddp" },
! 148: { -1, NULL, NULL, NULL, NULL }
1.12 denny 149: };
150:
1.34 deraadt 151: struct protox *protoprotox[] = {
1.66 henning 152: protox, ip6protox, atalkprotox, NULL
1.34 deraadt 153: };
1.1 deraadt 154:
1.30 millert 155: static void printproto(struct protox *, char *);
156: static void usage(void);
157: static struct protox *name2protox(char *);
158: static struct protox *knownname(char *);
1.1 deraadt 159:
160: kvm_t *kvmd;
161:
162: int
1.34 deraadt 163: main(int argc, char *argv[])
1.1 deraadt 164: {
165: extern char *optarg;
166: extern int optind;
1.68 claudio 167: const char *errstr;
1.28 mpech 168: struct protoent *p;
169: struct protox *tp = NULL; /* for printing cblocks & stats */
1.1 deraadt 170: int ch;
1.59 markus 171: char *nlistf = NULL, *memf = NULL, *ep;
1.1 deraadt 172: char buf[_POSIX2_LINE_MAX];
1.61 djm 173: gid_t gid;
1.59 markus 174: u_long pcbaddr = 0;
1.68 claudio 175: u_int tableid = 0;
1.1 deraadt 176:
177: af = AF_UNSPEC;
178:
1.68 claudio 179: while ((ch = getopt(argc, argv, "AabdFf:gI:ilM:mN:np:P:qrsT:tuvW:w:")) != -1)
1.31 deraadt 180: switch (ch) {
1.1 deraadt 181: case 'A':
182: Aflag = 1;
183: break;
184: case 'a':
185: aflag = 1;
1.24 camield 186: break;
187: case 'b':
188: bflag = 1;
1.1 deraadt 189: break;
190: case 'd':
191: dflag = 1;
1.64 pyr 192: break;
193: case 'F':
194: Fflag = 1;
1.1 deraadt 195: break;
196: case 'f':
1.4 mickey 197: if (strcmp(optarg, "inet") == 0)
1.1 deraadt 198: af = AF_INET;
1.19 itojun 199: else if (strcmp(optarg, "inet6") == 0)
200: af = AF_INET6;
1.7 kstailey 201: else if (strcmp(optarg, "local") == 0)
202: af = AF_LOCAL;
1.1 deraadt 203: else if (strcmp(optarg, "unix") == 0)
204: af = AF_UNIX;
1.10 angelos 205: else if (strcmp(optarg, "encap") == 0)
1.16 angelos 206: af = PF_KEY;
1.12 denny 207: else if (strcmp(optarg, "atalk") == 0)
208: af = AF_APPLETALK;
1.63 claudio 209: else if (strcmp(optarg, "mask") == 0)
210: af = 0xff;
1.1 deraadt 211: else {
212: (void)fprintf(stderr,
213: "%s: %s: unknown address family\n",
1.2 deraadt 214: __progname, optarg);
1.1 deraadt 215: exit(1);
216: }
217: break;
218: case 'g':
219: gflag = 1;
220: break;
1.2 deraadt 221: case 'I':
1.1 deraadt 222: iflag = 1;
1.2 deraadt 223: interface = optarg;
1.1 deraadt 224: break;
225: case 'i':
226: iflag = 1;
227: break;
1.19 itojun 228: case 'l':
229: lflag = 1;
230: break;
1.1 deraadt 231: case 'M':
232: memf = optarg;
233: break;
234: case 'm':
235: mflag = 1;
236: break;
237: case 'N':
238: nlistf = optarg;
239: break;
240: case 'n':
241: nflag = 1;
242: break;
243: case 'p':
244: if ((tp = name2protox(optarg)) == NULL) {
245: (void)fprintf(stderr,
1.42 jmc 246: "%s: %s: unknown protocol\n",
1.2 deraadt 247: __progname, optarg);
1.1 deraadt 248: exit(1);
249: }
250: pflag = 1;
1.27 brian 251: break;
1.59 markus 252: case 'P':
253: errno = 0;
254: pcbaddr = strtoul(optarg, &ep, 16);
255: if (optarg[0] == '\0' || *ep != '\0' ||
256: errno == ERANGE) {
257: (void)fprintf(stderr,
258: "%s: %s: invalid PCB address\n",
259: __progname, optarg);
260: exit(1);
261: }
262: Pflag = 1;
263: break;
1.27 brian 264: case 'q':
265: qflag = 1;
1.1 deraadt 266: break;
267: case 'r':
268: rflag = 1;
1.46 cedric 269: break;
1.1 deraadt 270: case 's':
271: ++sflag;
272: break;
1.68 claudio 273: case 'T':
274: tableid = strtonum(optarg, 0, RT_TABLEID_MAX, &errstr);
275: if (errstr)
276: errx(1, "invalid table id: %s", errstr);
277: break;
1.1 deraadt 278: case 't':
279: tflag = 1;
280: break;
281: case 'u':
282: af = AF_UNIX;
1.13 peter 283: break;
284: case 'v':
285: vflag = 1;
1.1 deraadt 286: break;
1.56 reyk 287: case 'W':
288: Wflag = 1;
289: interface = optarg;
290: break;
1.1 deraadt 291: case 'w':
292: interval = atoi(optarg);
293: iflag = 1;
294: break;
295: case '?':
296: default:
297: usage();
298: }
299: argv += optind;
300: argc -= optind;
301:
1.33 deraadt 302: /*
1.56 reyk 303: * Show per-interface statistics which don't need access to
304: * kernel memory (they're using IOCTLs)
305: */
306: if (Wflag) {
307: if (interface == NULL)
308: usage();
309: net80211_ifstats(interface);
310: exit(0);
311: }
312:
313: /*
1.33 deraadt 314: * Discard setgid privileges if not the running kernel so that bad
315: * guys can't print interesting stuff from kernel memory.
1.59 markus 316: * Dumping PCB info is also restricted.
1.33 deraadt 317: */
1.61 djm 318: gid = getgid();
319: if (nlistf != NULL || memf != NULL || Pflag)
320: if (setresgid(gid, gid, gid) == -1)
321: err(1, "setresgid");
1.62 claudio 322: if (nlistf == NULL && memf == NULL && rflag && !Aflag) {
323: /* printing the routing table no longer needs kvm */
324: if (setresgid(gid, gid, gid) == -1)
325: err(1, "setresgid");
326: if (sflag)
327: rt_stats(1, 0);
328: else
1.68 claudio 329: p_rttables(af, tableid);
1.62 claudio 330: exit(0);
331: }
1.33 deraadt 332: if ((kvmd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY,
333: buf)) == NULL) {
334: fprintf(stderr, "%s: kvm_open: %s\n", __progname, buf);
335: exit(1);
336: }
1.61 djm 337:
338: if (nlistf == NULL && memf == NULL && !Pflag)
339: if (setresgid(gid, gid, gid) == -1)
340: err(1, "setresgid");
1.33 deraadt 341:
1.1 deraadt 342: #define BACKWARD_COMPATIBILITY
343: #ifdef BACKWARD_COMPATIBILITY
344: if (*argv) {
345: if (isdigit(**argv)) {
346: interval = atoi(*argv);
347: if (interval <= 0)
348: usage();
349: ++argv;
350: iflag = 1;
351: }
352: if (*argv) {
353: nlistf = *argv;
354: if (*++argv)
355: memf = *argv;
356: }
357: }
358: #endif
1.14 deraadt 359:
1.1 deraadt 360: if (kvm_nlist(kvmd, nl) < 0 || nl[0].n_type == 0) {
361: if (nlistf)
1.2 deraadt 362: fprintf(stderr, "%s: %s: no namelist\n", __progname,
363: nlistf);
1.1 deraadt 364: else
1.2 deraadt 365: fprintf(stderr, "%s: no namelist\n", __progname);
1.1 deraadt 366: exit(1);
367: }
368: if (mflag) {
1.70 deraadt 369: mbpr();
1.1 deraadt 370: exit(0);
371: }
372: if (pflag) {
1.45 markus 373: printproto(tp, tp->pr_name);
1.59 markus 374: exit(0);
375: }
376: if (Pflag) {
377: if (tp == NULL && (tp = name2protox("tcp")) == NULL) {
378: (void)fprintf(stderr,
379: "%s: %s: unknown protocol\n",
380: __progname, "tcp");
381: exit(1);
382: }
383: if (tp->pr_dump)
384: (tp->pr_dump)(pcbaddr);
1.1 deraadt 385: exit(0);
386: }
387: /*
388: * Keep file descriptors open to avoid overhead
389: * of open/close on each call to get* routines.
390: */
391: sethostent(1);
392: setnetent(1);
1.71 ! deraadt 393:
1.1 deraadt 394: if (iflag) {
395: intpr(interval, nl[N_IFNET].n_value);
396: exit(0);
397: }
398: if (rflag) {
399: if (sflag)
1.62 claudio 400: rt_stats(0, nl[N_RTSTAT].n_value);
1.1 deraadt 401: else
1.63 claudio 402: routepr(nl[N_RTREE].n_value, nl[N_RTMASK].n_value,
403: nl[N_AF2RTAFIDX].n_value, nl[N_RTBLIDMAX].n_value);
1.1 deraadt 404: exit(0);
405: }
406: if (gflag) {
1.19 itojun 407: if (sflag) {
408: if (af == AF_INET || af == AF_UNSPEC)
1.71 ! deraadt 409: mrt_stats();
1.19 itojun 410: if (af == AF_INET6 || af == AF_UNSPEC)
1.71 ! deraadt 411: mrt6_stats();
1.70 deraadt 412: } else {
1.19 itojun 413: if (af == AF_INET || af == AF_UNSPEC)
1.71 ! deraadt 414: mroutepr(nl[N_MFCHASHTBL].n_value,
1.19 itojun 415: nl[N_MFCHASH].n_value,
416: nl[N_VIFTABLE].n_value);
417: if (af == AF_INET6 || af == AF_UNSPEC)
1.71 ! deraadt 418: mroute6pr(nl[N_MF6CTABLE].n_value,
1.19 itojun 419: nl[N_MIF6TABLE].n_value);
420: }
1.1 deraadt 421: exit(0);
422: }
423: if (af == AF_INET || af == AF_UNSPEC) {
424: setprotoent(1);
425: setservent(1);
426: /* ugh, this is O(MN) ... why do we do this? */
1.11 millert 427: while ((p = getprotoent())) {
1.1 deraadt 428: for (tp = protox; tp->pr_name; tp++)
429: if (strcmp(tp->pr_name, p->p_name) == 0)
430: break;
1.71 ! deraadt 431: if (tp->pr_name == 0)
1.1 deraadt 432: continue;
433: printproto(tp, p->p_name);
434: }
435: endprotoent();
436: }
1.19 itojun 437: if (af == AF_INET6 || af == AF_UNSPEC)
438: for (tp = ip6protox; tp->pr_name; tp++)
439: printproto(tp, tp->pr_name);
1.1 deraadt 440: if ((af == AF_UNIX || af == AF_UNSPEC) && !sflag)
441: unixpr(nl[N_UNIXSW].n_value);
1.12 denny 442: if (af == AF_APPLETALK || af == AF_UNSPEC)
443: for (tp = atalkprotox; tp->pr_name; tp++)
444: printproto(tp, tp->pr_name);
1.1 deraadt 445: exit(0);
446: }
447:
448: /*
449: * Print out protocol statistics or control blocks (per sflag).
450: * If the interface was not specifically requested, and the symbol
451: * is not in the namelist, ignore this one.
452: */
453: static void
1.34 deraadt 454: printproto(struct protox *tp, char *name)
1.1 deraadt 455: {
456: if (sflag) {
1.71 ! deraadt 457: if (tp->pr_stats != NULL)
! 458: (*tp->pr_stats)(name);
1.1 deraadt 459: } else {
1.71 ! deraadt 460: u_char i = tp->pr_index;
! 461: if (tp->pr_cblocks != NULL &&
! 462: i < sizeof(nl) / sizeof(nl[0]) &&
! 463: (nl[i].n_value || af != AF_UNSPEC))
! 464: (*tp->pr_cblocks)(nl[i].n_value, name);
1.1 deraadt 465: }
466: }
467:
468: /*
469: * Read kernel memory, return 0 on success.
470: */
471: int
1.53 jaredy 472: kread(u_long addr, void *buf, int size)
1.1 deraadt 473: {
474:
475: if (kvm_read(kvmd, addr, buf, size) != size) {
1.2 deraadt 476: (void)fprintf(stderr, "%s: %s\n", __progname,
1.1 deraadt 477: kvm_geterr(kvmd));
478: return (-1);
479: }
480: return (0);
481: }
482:
483: char *
1.34 deraadt 484: plural(int n)
1.1 deraadt 485: {
486: return (n != 1 ? "s" : "");
487: }
488:
489: char *
1.34 deraadt 490: plurales(int n)
1.1 deraadt 491: {
492: return (n != 1 ? "es" : "");
493: }
494:
495: /*
496: * Find the protox for the given "well-known" name.
497: */
498: static struct protox *
1.34 deraadt 499: knownname(char *name)
1.1 deraadt 500: {
501: struct protox **tpp, *tp;
502:
503: for (tpp = protoprotox; *tpp; tpp++)
504: for (tp = *tpp; tp->pr_name; tp++)
505: if (strcmp(tp->pr_name, name) == 0)
506: return (tp);
507: return (NULL);
508: }
509:
510: /*
511: * Find the protox corresponding to name.
512: */
513: static struct protox *
1.34 deraadt 514: name2protox(char *name)
1.1 deraadt 515: {
516: struct protox *tp;
517: char **alias; /* alias from p->aliases */
518: struct protoent *p;
519:
520: /*
521: * Try to find the name in the list of "well-known" names. If that
522: * fails, check if name is an alias for an Internet protocol.
523: */
1.11 millert 524: if ((tp = knownname(name)))
1.1 deraadt 525: return (tp);
526:
527: setprotoent(1); /* make protocol lookup cheaper */
1.11 millert 528: while ((p = getprotoent())) {
1.1 deraadt 529: /* assert: name not same as p->name */
530: for (alias = p->p_aliases; *alias; alias++)
531: if (strcmp(name, *alias) == 0) {
532: endprotoent();
533: return (knownname(p->p_name));
534: }
535: }
536: endprotoent();
537: return (NULL);
538: }
539:
540: static void
1.34 deraadt 541: usage(void)
1.1 deraadt 542: {
543: (void)fprintf(stderr,
1.60 jaredy 544: "usage: %s [-Aan] [-f address_family] [-M core] [-N system]\n"
1.69 sobrado 545: " %s [-bdFgilmnqrstu] [-f address_family] [-M core] [-N system]\n"
546: " [-T tableid]\n"
1.60 jaredy 547: " %s [-bdn] [-I interface] [-M core] [-N system] [-w wait]\n"
548: " %s [-M core] [-N system] -P pcbaddr\n"
549: " %s [-s] [-M core] [-N system] [-p protocol]\n"
550: " %s [-a] [-f address_family] [-i | -I interface]\n"
551: " %s [-W interface]\n",
552: __progname, __progname, __progname, __progname,
553: __progname, __progname, __progname);
1.1 deraadt 554: exit(1);
555: }