main.c revision 1.99.8.1 1 /* $NetBSD: main.c,v 1.99.8.1 2022/09/12 14:29:19 martin 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. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 #ifndef lint
34 __COPYRIGHT("@(#) Copyright (c) 1983, 1988, 1993\
35 Regents of the University of California. All rights reserved.");
36 #endif /* not lint */
37
38 #ifndef lint
39 #if 0
40 static char sccsid[] = "from: @(#)main.c 8.4 (Berkeley) 3/1/94";
41 #else
42 __RCSID("$NetBSD: main.c,v 1.99.8.1 2022/09/12 14:29:19 martin Exp $");
43 #endif
44 #endif /* not lint */
45
46 #include <sys/param.h>
47 #include <sys/file.h>
48 #include <sys/protosw.h>
49 #include <sys/socket.h>
50
51 #include <net/if.h>
52 #include <netinet/in.h>
53
54 #include <ctype.h>
55 #include <err.h>
56 #include <errno.h>
57 #include <kvm.h>
58 #include <limits.h>
59 #include <netdb.h>
60 #include <nlist.h>
61 #include <paths.h>
62 #include <stdio.h>
63 #include <stdlib.h>
64 #include <string.h>
65 #include <unistd.h>
66 #include "netstat.h"
67 #include "rtutil.h"
68 #include "prog_ops.h"
69
70 int Aflag;
71 int aflag;
72 int Bflag;
73 int bflag;
74 int dflag;
75 #ifndef SMALL
76 int gflag;
77 #endif
78 int hflag;
79 int iflag;
80 int Lflag;
81 int lflag;
82 int mflag;
83 int numeric_addr;
84 int numeric_port;
85 int nflag;
86 int Pflag;
87 int pflag;
88 int qflag;
89 int rflag;
90 int sflag;
91 int tagflag;
92 int tflag;
93 int Vflag;
94 int vflag;
95
96 char *interface;
97
98 int af;
99 int use_sysctl;
100 int force_sysctl;
101
102 struct nlist nl[] = {
103 #define N_MBSTAT 0
104 { "_mbstat", 0, 0, 0, 0 },
105 #define N_IPSTAT 1
106 { "_ipstat", 0, 0, 0, 0 }, /* not available via kvm */
107 #define N_TCBTABLE 2
108 { "_tcbtable", 0, 0, 0, 0 },
109 #define N_TCPSTAT 3
110 { "_tcpstat", 0, 0, 0, 0 }, /* not available via kvm */
111 #define N_UDBTABLE 4
112 { "_udbtable", 0, 0, 0, 0 },
113 #define N_UDPSTAT 5
114 { "_udpstat", 0, 0, 0, 0 }, /* not available via kvm */
115 #define N_IFNET_LIST 6
116 { "_ifnet_list", 0, 0, 0, 0 },
117 #define N_ICMPSTAT 7
118 { "_icmpstat", 0, 0, 0, 0 }, /* not available via kvm */
119 #define N_RTSTAT 8
120 { "_rtstat", 0, 0, 0, 0 },
121 #define N_UNIXSW 9
122 { "_unixsw", 0, 0, 0, 0 },
123 #define N_RTREE 10
124 { "_rt_tables", 0, 0, 0, 0 },
125 #define N_NFILE 11
126 { "_nfile", 0, 0, 0, 0 },
127 #define N_IGMPSTAT 12
128 { "_igmpstat", 0, 0, 0, 0 }, /* not available via kvm */
129 #define N_MRTPROTO 13
130 { "_ip_mrtproto", 0, 0, 0, 0 },
131 #define N_MRTSTAT 14
132 { "_mrtstat", 0, 0, 0, 0 },
133 #define N_MFCHASHTBL 15
134 { "_mfchashtbl", 0, 0, 0, 0 },
135 #define N_MFCHASH 16
136 { "_mfchash", 0, 0, 0, 0 },
137 #define N_VIFTABLE 17
138 { "_viftable", 0, 0, 0, 0 },
139 #define N_MSIZE 18
140 { "_msize", 0, 0, 0, 0 },
141 #define N_MCLBYTES 19
142 { "_mclbytes", 0, 0, 0, 0 },
143 #define N_DDPSTAT 20
144 { "_ddpstat", 0, 0, 0, 0 }, /* not available via kvm */
145 #define N_DDPCB 21
146 { "_ddpcb", 0, 0, 0, 0 },
147 #define N_MBPOOL 22
148 { "_mbpool", 0, 0, 0, 0 },
149 #define N_MCLPOOL 23
150 { "_mclpool", 0, 0, 0, 0 },
151 #define N_IP6STAT 24
152 { "_ip6stat", 0, 0, 0, 0 }, /* not available via kvm */
153 #define N_TCP6STAT 25
154 { "_tcp6stat", 0, 0, 0, 0 }, /* not available via kvm */
155 #define N_UDP6STAT 26
156 { "_udp6stat", 0, 0, 0, 0 }, /* not available via kvm */
157 #define N_ICMP6STAT 27
158 { "_icmp6stat", 0, 0, 0, 0 }, /* not available via kvm */
159 #define N_IPSECSTAT 28
160 { "_ipsecstat", 0, 0, 0, 0 }, /* not available via kvm */
161 #define N_IPSEC6STAT 29
162 { "_ipsec6stat", 0, 0, 0, 0 }, /* not available via kvm */
163 #define N_PIM6STAT 30
164 { "_pim6stat", 0, 0, 0, 0 }, /* not available via kvm */
165 #define N_MRT6PROTO 31
166 { "_ip6_mrtproto", 0, 0, 0, 0 },
167 #define N_MRT6STAT 32
168 { "_mrt6stat", 0, 0, 0, 0 },
169 #define N_MF6CTABLE 33
170 { "_mf6ctable", 0, 0, 0, 0 },
171 #define N_MIF6TABLE 34
172 { "_mif6table", 0, 0, 0, 0 },
173 #define N_PFKEYSTAT 35
174 { "_pfkeystat", 0, 0, 0, 0 }, /* not available via kvm */
175 #define N_ARPSTAT 36
176 { "_arpstat", 0, 0, 0, 0 }, /* not available via kvm */
177 #define N_RIP6STAT 37
178 { "_rip6stat", 0, 0, 0, 0 }, /* not available via kvm */
179 #define N_ARPINTRQ 38
180 { "_arpintrq", 0, 0, 0, 0 },
181 #define N_ATINTRQ1 39
182 { "_atintrq1", 0, 0, 0, 0 },
183 #define N_ATINTRQ2 40
184 { "_atintrq2", 0, 0, 0, 0 },
185 #define N_NATMINTRQ 41
186 { "_natmintrq", 0, 0, 0, 0 },
187 #define N_PPPOEDISCINQ 42
188 { "_ppoediscinq", 0, 0, 0, 0 },
189 #define N_PPPOEINQ 43
190 { "_ppoeinq", 0, 0, 0, 0 },
191 #define N_HARDCLOCK_TICKS 44
192 { "_hardclock_ticks", 0, 0, 0, 0 },
193 #define N_PIMSTAT 45
194 { "_pimstat", 0, 0, 0, 0 },
195 #define N_CARPSTAT 46
196 { "_carpstats", 0, 0, 0, 0 }, /* not available via kvm */
197 #define N_PFSYNCSTAT 47
198 { "_pfsyncstats", 0, 0, 0, 0}, /* not available via kvm */
199 { "", 0, 0, 0, 0 },
200 };
201
202 struct protox {
203 u_char pr_index; /* index into nlist of cb head */
204 u_char pr_sindex; /* index into nlist of stat block */
205 u_char pr_wanted; /* 1 if wanted, 0 otherwise */
206 void (*pr_cblocks) /* control blocks printing routine */
207 (u_long, const char *);
208 void (*pr_stats) /* statistics printing routine */
209 (u_long, const char *);
210 void (*pr_istats) /* per/if statistics printing routine */
211 (const char *);
212 void (*pr_dump) /* PCB state dump routine */
213 (u_long, const char *, u_long);
214 const char *pr_name; /* well-known name */
215 } protox[] = {
216 { N_TCBTABLE, N_TCPSTAT, 1, protopr,
217 tcp_stats, NULL, tcp_dump, "tcp" },
218 { N_UDBTABLE, N_UDPSTAT, 1, protopr,
219 udp_stats, NULL, 0, "udp" },
220 { -1, N_IPSTAT, 1, 0,
221 ip_stats, NULL, 0, "ip" },
222 { -1, N_ICMPSTAT, 1, 0,
223 icmp_stats, NULL, 0, "icmp" },
224 { -1, N_IGMPSTAT, 1, 0,
225 igmp_stats, NULL, 0, "igmp" },
226 { -1, N_CARPSTAT, 1, 0,
227 carp_stats, NULL, 0, "carp" },
228 #ifdef IPSEC
229 { -1, N_IPSECSTAT, 1, 0,
230 fast_ipsec_stats, NULL, 0, "ipsec" },
231 #endif
232 { -1, N_PIMSTAT, 1, 0,
233 pim_stats, NULL, 0, "pim" },
234 { -1, N_PFSYNCSTAT, 1, 0,
235 pfsync_stats, NULL, 0, "pfsync" },
236 { -1, -1, 0, 0,
237 0, NULL, 0, 0 }
238 };
239
240 #ifdef INET6
241 struct protox ip6protox[] = {
242 { -1, N_IP6STAT, 1, 0,
243 ip6_stats, ip6_ifstats, 0, "ip6" },
244 { -1, N_ICMP6STAT, 1, 0,
245 icmp6_stats, icmp6_ifstats, 0, "icmp6" },
246 #ifdef TCP6
247 { N_TCBTABLE, N_TCP6STAT, 1, ip6protopr,
248 tcp6_stats, NULL, tcp6_dump, "tcp6" },
249 #else
250 { N_TCBTABLE, N_TCP6STAT, 1, ip6protopr,
251 tcp_stats, NULL, tcp6_dump, "tcp6" },
252 #endif
253 { N_UDBTABLE, N_UDP6STAT, 1, ip6protopr,
254 udp6_stats, NULL, 0, "udp6" },
255 #ifdef IPSEC
256 { -1, N_IPSEC6STAT, 1, 0,
257 fast_ipsec_stats, NULL, 0, "ipsec6" },
258 #endif
259 { -1, N_PIM6STAT, 1, 0,
260 pim6_stats, NULL, 0, "pim6" },
261 { -1, N_RIP6STAT, 1, 0,
262 rip6_stats, NULL, 0, "rip6" },
263 { -1, -1, 0, 0,
264 0, NULL, 0, 0 }
265 };
266 #endif
267
268 struct protox arpprotox[] = {
269 { -1, N_ARPSTAT, 1, 0,
270 arp_stats, NULL, 0, "arp" },
271 { -1, -1, 0, 0,
272 0, NULL, 0, 0 }
273 };
274
275 #ifdef IPSEC
276 struct protox pfkeyprotox[] = {
277 { -1, N_PFKEYSTAT, 1, 0,
278 pfkey_stats, NULL, 0, "pfkey" },
279 { -1, -1, 0, 0,
280 0, NULL, 0, 0 }
281 };
282 #endif
283
284 #ifndef SMALL
285 struct protox atalkprotox[] = {
286 { N_DDPCB, N_DDPSTAT, 1, atalkprotopr,
287 ddp_stats, NULL, 0, "ddp" },
288 { -1, -1, 0, 0,
289 0, NULL, 0, NULL }
290 };
291 #endif
292
293 struct protox *protoprotox[] = { protox,
294 #ifdef INET6
295 ip6protox,
296 #endif
297 arpprotox,
298 #ifdef IPSEC
299 pfkeyprotox,
300 #endif
301 #ifndef SMALL
302 atalkprotox,
303 #endif
304 NULL };
305
306 const struct softintrq {
307 const char *siq_name;
308 int siq_index;
309 } softintrq[] = {
310 { "arpintrq", N_ARPINTRQ },
311 { "atintrq1", N_ATINTRQ1 },
312 { "atintrq2", N_ATINTRQ2 },
313 { "natmintrq", N_NATMINTRQ },
314 { "ppoediscinq", N_PPPOEDISCINQ },
315 { "ppoeinq", N_PPPOEINQ },
316 { NULL, -1 },
317 };
318
319 static void printproto(struct protox *, const char *);
320 static void print_softintrq(void);
321 __dead static void usage(void);
322 static struct protox *name2protox(const char *);
323 static struct protox *knownname(const char *);
324 static void prepare(const char *, const char *, struct protox *tp);
325 static kvm_t *prepare_kvmd(const char *, const char *, char *);
326
327 static kvm_t *kvmd = NULL;
328 gid_t egid;
329 int interval; /* repeat interval for i/f stats */
330 static const char *nlistf = NULL, *memf = NULL;
331
332 kvm_t *
333 get_kvmd(void)
334 {
335 char buf[_POSIX2_LINE_MAX];
336
337 if (kvmd != NULL)
338 return kvmd;
339 if ((kvmd = prepare_kvmd(nlistf, memf, buf)) == NULL)
340 errx(1, "kvm error: %s", buf);
341 return kvmd;
342 }
343
344 static kvm_t *
345 prepare_kvmd(const char *nf, const char *mf, char *errbuf)
346 {
347 kvm_t *k;
348
349 (void)setegid(egid);
350 k = kvm_openfiles(nf, mf, NULL, O_RDONLY, errbuf);
351 (void)setgid(getgid());
352 return k;
353 }
354
355 void
356 prepare(const char *nf, const char *mf, struct protox *tp)
357 {
358 char buf[_POSIX2_LINE_MAX];
359
360 /*
361 * Try to figure out if we can use sysctl or not.
362 */
363 if (nf != NULL || mf != NULL) {
364 /* Of course, we can't use sysctl with dumps. */
365 if (force_sysctl)
366 errx(EXIT_FAILURE, "can't use sysctl with dumps");
367
368 /*
369 * If we have -M or -N, we're not dealing with live memory
370 * or want to use kvm interface explicitly. It is sometimes
371 * useful to dig inside of kernel without extending
372 * sysctl interface (i.e., without rebuilding kernel).
373 */
374 use_sysctl = 0;
375 } else if (qflag ||
376 #ifndef SMALL
377 gflag ||
378 #endif
379 (pflag && tp->pr_sindex == N_PIMSTAT) ||
380 Pflag) {
381 /* These flags are not yet supported via sysctl(3). */
382 use_sysctl = 0;
383 } else {
384 /* We can use sysctl(3). */
385 use_sysctl = 1;
386 }
387
388 if (force_sysctl && !use_sysctl) {
389 /* Let the user know what's about to happen. */
390 warnx("forcing sysctl usage even though it might not be "
391 "supported");
392 use_sysctl = 1;
393 }
394
395 kvmd = prepare_kvmd(nf, mf, buf);
396
397 if (!use_sysctl) {
398
399 if (kvmd == NULL)
400 errx(1, "kvm error: %s", buf);
401 if (kvm_nlist(kvmd, nl) < 0 || nl[0].n_type == 0) {
402 if (nf)
403 errx(1, "%s: no namelist", nf);
404 else
405 errx(1, "no namelist");
406 }
407 } else
408 (void)setgid(getgid());
409 }
410
411 int
412 main(int argc, char *argv[])
413 {
414 struct protoent *p;
415 struct protox *tp; /* for printing cblocks & stats */
416 int ch;
417 char *cp;
418 char *afname, *afnames;
419 u_long pcbaddr;
420
421 if (prog_init) {
422 if (prog_init() == -1)
423 err(1, "init failed");
424 force_sysctl = 1; /* cheap trick */
425 }
426
427 egid = getegid();
428 (void)setegid(getgid());
429 tp = NULL;
430 af = AF_UNSPEC;
431 afnames = NULL;
432 pcbaddr = 0;
433
434 while ((ch = getopt(argc, argv,
435 "AabBdf:ghI:LliM:mN:nP:p:qrsStTuVvw:X")) != -1)
436 switch (ch) {
437 case 'A':
438 Aflag = RT_AFLAG;
439 break;
440 case 'a':
441 aflag = 1;
442 break;
443 case 'b':
444 bflag = 1;
445 break;
446 case 'B':
447 Bflag = 1;
448 break;
449 case 'd':
450 dflag = 1;
451 break;
452 case 'f':
453 afnames = optarg;
454 break;
455 #ifndef SMALL
456 case 'g':
457 gflag = 1;
458 break;
459 #endif
460 case 'h':
461 hflag = 1;
462 break;
463 case 'I':
464 iflag = 1;
465 interface = optarg;
466 break;
467 case 'i':
468 iflag = 1;
469 break;
470 case 'L':
471 Lflag = RT_LFLAG;
472 break;
473 case 'l':
474 lflag = 1;
475 break;
476 case 'M':
477 memf = optarg;
478 break;
479 case 'm':
480 mflag = 1;
481 break;
482 case 'N':
483 nlistf = optarg;
484 break;
485 case 'n':
486 numeric_addr = numeric_port = nflag = RT_NFLAG;
487 break;
488 case 'P':
489 errno = 0;
490 pcbaddr = strtoul(optarg, &cp, 16);
491 if (*cp != '\0' || errno == ERANGE)
492 errx(1, "invalid PCB address %s", optarg);
493 Pflag = 1;
494 break;
495 case 'p':
496 if ((tp = name2protox(optarg)) == NULL)
497 errx(1,
498 "%s: unknown or uninstrumented protocol",
499 optarg);
500 pflag = 1;
501 break;
502 case 'q':
503 qflag = 1;
504 break;
505 case 'r':
506 rflag = 1;
507 break;
508 case 's':
509 ++sflag;
510 break;
511 case 'S':
512 numeric_addr = 1;
513 break;
514 case 't':
515 tflag = 1;
516 break;
517 case 'T':
518 tagflag = RT_TFLAG;
519 break;
520 case 'u':
521 af = AF_LOCAL;
522 break;
523 case 'V':
524 Vflag++;
525 break;
526 case 'v':
527 vflag = RT_VFLAG;
528 break;
529 case 'w':
530 interval = atoi(optarg);
531 iflag = 1;
532 break;
533 case 'X':
534 force_sysctl = 1;
535 break;
536 case '?':
537 default:
538 usage();
539 }
540 argv += optind;
541 argc -= optind;
542
543 #define BACKWARD_COMPATIBILITY
544 #ifdef BACKWARD_COMPATIBILITY
545 if (*argv) {
546 if (isdigit((unsigned char)**argv)) {
547 interval = atoi(*argv);
548 if (interval <= 0)
549 usage();
550 ++argv;
551 iflag = 1;
552 }
553 if (*argv) {
554 nlistf = *argv;
555 if (*++argv)
556 memf = *argv;
557 }
558 }
559 #endif
560
561 prepare(nlistf, memf, tp);
562
563 #ifndef SMALL
564 if (Bflag) {
565 if (sflag)
566 bpf_stats();
567 else
568 bpf_dump(interface);
569 exit(0);
570 }
571 #endif
572
573 if (mflag) {
574 mbpr(nl[N_MBSTAT].n_value, nl[N_MSIZE].n_value,
575 nl[N_MCLBYTES].n_value, nl[N_MBPOOL].n_value,
576 nl[N_MCLPOOL].n_value);
577 exit(0);
578 }
579 if (Pflag) {
580 if (tp == NULL) {
581 /* Default to TCP. */
582 tp = name2protox("tcp");
583 }
584 if (tp->pr_dump)
585 (*tp->pr_dump)(nl[tp->pr_index].n_value, tp->pr_name,
586 pcbaddr);
587 else
588 printf("%s: no PCB dump routine\n", tp->pr_name);
589 exit(0);
590 }
591 if (pflag) {
592 if (iflag && tp->pr_istats)
593 intpr(interval, nl[N_IFNET_LIST].n_value,
594 tp->pr_istats);
595 else if (tp->pr_stats)
596 (*tp->pr_stats)(nl[tp->pr_sindex].n_value,
597 tp->pr_name);
598 else
599 printf("%s: no stats routine\n", tp->pr_name);
600 exit(0);
601 }
602 if (qflag) {
603 print_softintrq();
604 exit(0);
605 }
606 /*
607 * Keep file descriptors open to avoid overhead
608 * of open/close on each call to get* routines.
609 */
610 sethostent(1);
611 setnetent(1);
612 /*
613 * If -f was used afnames != NULL, loop over the address families.
614 * Otherwise do this at least once (with af == AF_UNSPEC).
615 */
616 afname = NULL;
617 do {
618 if (afnames != NULL) {
619 afname = strsep(&afnames, ",");
620 if (afname == NULL)
621 break; /* Exit early */
622 if (strcmp(afname, "inet") == 0)
623 af = AF_INET;
624 else if (strcmp(afname, "inet6") == 0)
625 af = AF_INET6;
626 else if (strcmp(afname, "arp") == 0)
627 af = AF_ARP;
628 else if (strcmp(afname, "pfkey") == 0)
629 af = PF_KEY;
630 else if (strcmp(afname, "unix") == 0
631 || strcmp(afname, "local") == 0)
632 af = AF_LOCAL;
633 else if (strcmp(afname, "atalk") == 0)
634 af = AF_APPLETALK;
635 else if (strcmp(afname, "mpls") == 0)
636 af = AF_MPLS;
637 else {
638 warnx("%s: unknown address family",
639 afname);
640 continue;
641 }
642 }
643
644 if (iflag) {
645 if (af != AF_UNSPEC)
646 goto protostat;
647
648 intpr(interval, nl[N_IFNET_LIST].n_value, NULL);
649 break;
650 }
651 if (rflag) {
652 if (sflag)
653 rt_stats(use_sysctl ? 0 :
654 nl[N_RTSTAT].n_value);
655 else {
656 if (use_sysctl)
657 p_rttables(af,
658 nflag|tagflag|vflag|Lflag, 0, ~0);
659 else
660 routepr(nl[N_RTREE].n_value);
661 }
662 break;
663 }
664 #ifndef SMALL
665 if (gflag) {
666 if (sflag) {
667 if (af == AF_INET || af == AF_UNSPEC)
668 mrt_stats(nl[N_MRTPROTO].n_value,
669 nl[N_MRTSTAT].n_value);
670 #ifdef INET6
671 if (af == AF_INET6 || af == AF_UNSPEC)
672 mrt6_stats(nl[N_MRT6PROTO].n_value,
673 nl[N_MRT6STAT].n_value);
674 #endif
675 }
676 else {
677 if (af == AF_INET || af == AF_UNSPEC)
678 mroutepr(nl[N_MRTPROTO].n_value,
679 nl[N_MFCHASHTBL].n_value,
680 nl[N_MFCHASH].n_value,
681 nl[N_VIFTABLE].n_value);
682 #ifdef INET6
683 if (af == AF_INET6 || af == AF_UNSPEC)
684 mroute6pr(nl[N_MRT6PROTO].n_value,
685 nl[N_MF6CTABLE].n_value,
686 nl[N_MIF6TABLE].n_value);
687 #endif
688 }
689 break;
690 }
691 #endif
692 protostat:
693 if (af == AF_INET || af == AF_UNSPEC) {
694 setprotoent(1);
695 setservent(1);
696 /* ugh, this is O(MN) ... why do we do this? */
697 while ((p = getprotoent()) != NULL) {
698 for (tp = protox; tp->pr_name; tp++)
699 if (strcmp(tp->pr_name, p->p_name) == 0)
700 break;
701 if (tp->pr_name == 0 || tp->pr_wanted == 0)
702 continue;
703 printproto(tp, p->p_name);
704 tp->pr_wanted = 0;
705 }
706 endprotoent();
707 for (tp = protox; tp->pr_name; tp++)
708 if (tp->pr_wanted)
709 printproto(tp, tp->pr_name);
710 }
711 #ifdef INET6
712 if (af == AF_INET6 || af == AF_UNSPEC)
713 for (tp = ip6protox; tp->pr_name; tp++)
714 printproto(tp, tp->pr_name);
715 #endif
716 if (af == AF_ARP || af == AF_UNSPEC)
717 for (tp = arpprotox; tp->pr_name; tp++)
718 printproto(tp, tp->pr_name);
719 #ifdef IPSEC
720 if (af == PF_KEY || af == AF_UNSPEC)
721 for (tp = pfkeyprotox; tp->pr_name; tp++)
722 printproto(tp, tp->pr_name);
723 #endif
724 #ifndef SMALL
725 if (af == AF_APPLETALK || af == AF_UNSPEC)
726 for (tp = atalkprotox; tp->pr_name; tp++)
727 printproto(tp, tp->pr_name);
728 if ((af == AF_LOCAL || af == AF_UNSPEC) && !sflag)
729 unixpr(nl[N_UNIXSW].n_value);
730 #endif
731 } while (afnames != NULL && afname != NULL);
732 exit(0);
733 }
734
735 /*
736 * Print out protocol statistics or control blocks (per sflag).
737 * If the interface was not specifically requested, and the symbol
738 * is not in the namelist, ignore this one.
739 */
740 static void
741 printproto(struct protox *tp, const char *name)
742 {
743 void (*pr)(u_long, const char *);
744 u_long off;
745
746 if (sflag) {
747 if (iflag) {
748 if (tp->pr_istats)
749 intpr(interval, nl[N_IFNET_LIST].n_value,
750 tp->pr_istats);
751 return;
752 }
753 else {
754 pr = tp->pr_stats;
755 off = nl[tp->pr_sindex].n_value;
756 }
757 } else {
758 pr = tp->pr_cblocks;
759 off = nl[tp->pr_index].n_value;
760 }
761 if (pr != NULL && ((off || af != AF_UNSPEC) || use_sysctl))
762 (*pr)(off, name);
763 }
764
765 /*
766 * Print softintrq status.
767 */
768 void
769 print_softintrq(void)
770 {
771 struct ifqueue intrq, *ifq = &intrq;
772 const struct softintrq *siq;
773 u_long off;
774
775 for (siq = softintrq; siq->siq_name != NULL; siq++) {
776 off = nl[siq->siq_index].n_value;
777 if (off == 0)
778 continue;
779
780 kread(off, (char *)ifq, sizeof(*ifq));
781 printf("%s:\n", siq->siq_name);
782 printf("\tqueue length: %d\n", ifq->ifq_len);
783 printf("\tmaximum queue length: %d\n", ifq->ifq_maxlen);
784 printf("\tpackets dropped: %d\n", ifq->ifq_drops);
785 }
786 }
787
788 /*
789 * Read kernel memory, return 0 on success.
790 */
791 int
792 kread(u_long addr, char *buf, int size)
793 {
794
795 if (kvm_read(kvmd, addr, buf, size) != size) {
796 warnx("%s", kvm_geterr(kvmd));
797 return -1;
798 }
799 return 0;
800 }
801
802 const char *
803 plural(int n)
804 {
805
806 return (n != 1 ? "s" : "");
807 }
808
809 const char *
810 plurales(int n)
811 {
812
813 return (n != 1 ? "es" : "");
814 }
815
816 int
817 get_hardticks(void)
818 {
819 int hardticks;
820
821 kread(nl[N_HARDCLOCK_TICKS].n_value, (char *)&hardticks,
822 sizeof(hardticks));
823 return hardticks;
824 }
825
826 /*
827 * Find the protox for the given "well-known" name.
828 */
829 static struct protox *
830 knownname(const char *name)
831 {
832 struct protox **tpp, *tp;
833
834 for (tpp = protoprotox; *tpp; tpp++)
835 for (tp = *tpp; tp->pr_name; tp++)
836 if (strcmp(tp->pr_name, name) == 0)
837 return tp;
838 return NULL;
839 }
840
841 /*
842 * Find the protox corresponding to name.
843 */
844 static struct protox *
845 name2protox(const char *name)
846 {
847 struct protox *tp;
848 char **alias; /* alias from p->aliases */
849 struct protoent *p;
850
851 /*
852 * Try to find the name in the list of "well-known" names. If that
853 * fails, check if name is an alias for an Internet protocol.
854 */
855 if ((tp = knownname(name)) != NULL)
856 return tp;
857
858 setprotoent(1); /* make protocol lookup cheaper */
859 while ((p = getprotoent()) != NULL) {
860 /* assert: name not same as p->name */
861 for (alias = p->p_aliases; *alias; alias++)
862 if (strcmp(name, *alias) == 0) {
863 endprotoent();
864 return knownname(p->p_name);
865 }
866 }
867 endprotoent();
868 return NULL;
869 }
870
871 static void
872 usage(void)
873 {
874 const char *progname = getprogname();
875
876 (void)fprintf(stderr,
877 "usage: %s [-Aan] [-f address_family[,family ...]] [-M core] [-N system]\n", progname);
878 (void)fprintf(stderr,
879 " %s [-bdgiLmnqrsSv] [-f address_family[,family ...]] [-M core] [-N system]\n",
880 progname);
881 (void)fprintf(stderr,
882 " %s [-dn] [-I interface] [-M core] [-N system] [-w wait]\n", progname);
883 (void)fprintf(stderr,
884 " %s [-p protocol] [-M core] [-N system]\n", progname);
885 (void)fprintf(stderr,
886 " %s [-p protocol] [-M core] [-N system] -P pcbaddr\n", progname);
887 (void)fprintf(stderr,
888 " %s [-p protocol] [-i] [-I Interface] \n", progname);
889 (void)fprintf(stderr,
890 " %s [-s] [-f address_family[,family ...]] [-i] [-I Interface]\n", progname);
891 (void)fprintf(stderr,
892 " %s [-s] [-B] [-I interface]\n", progname);
893 exit(1);
894 }
895