1 /* $NetBSD: main.c,v 1.104 2022/10/24 08:11:25 msaitoh 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.104 2022/10/24 08:11:25 msaitoh 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_PPPOEDISCINQ 41
186 { "_ppoediscinq", 0, 0, 0, 0 },
187 #define N_PPPOEINQ 42
188 { "_ppoeinq", 0, 0, 0, 0 },
189 #define N_HARDCLOCK_TICKS 43
190 { "_hardclock_ticks", 0, 0, 0, 0 },
191 #define N_PIMSTAT 44
192 { "_pimstat", 0, 0, 0, 0 },
193 #define N_CARPSTAT 45
194 { "_carpstats", 0, 0, 0, 0 }, /* not available via kvm */
195 #define N_PFSYNCSTAT 46
196 { "_pfsyncstats", 0, 0, 0, 0}, /* not available via kvm */
197 { "", 0, 0, 0, 0 },
198 };
199
200 struct protox {
201 u_char pr_index; /* index into nlist of cb head */
202 u_char pr_sindex; /* index into nlist of stat block */
203 u_char pr_wanted; /* 1 if wanted, 0 otherwise */
204 void (*pr_cblocks) /* control blocks printing routine */
205 (u_long, const char *);
206 void (*pr_stats) /* statistics printing routine */
207 (u_long, const char *);
208 void (*pr_istats) /* per/if statistics printing routine */
209 (const char *);
210 void (*pr_dump) /* PCB state dump routine */
211 (u_long, const char *, u_long);
212 const char *pr_name; /* well-known name */
213 } protox[] = {
214 { N_TCBTABLE, N_TCPSTAT, 1, protopr,
215 tcp_stats, NULL, tcp_dump, "tcp" },
216 { N_UDBTABLE, N_UDPSTAT, 1, protopr,
217 udp_stats, NULL, 0, "udp" },
218 { -1, N_IPSTAT, 1, 0,
219 ip_stats, NULL, 0, "ip" },
220 { -1, N_ICMPSTAT, 1, 0,
221 icmp_stats, NULL, 0, "icmp" },
222 { -1, N_IGMPSTAT, 1, 0,
223 igmp_stats, NULL, 0, "igmp" },
224 { -1, N_CARPSTAT, 1, 0,
225 carp_stats, NULL, 0, "carp" },
226 #ifdef IPSEC
227 { -1, N_IPSECSTAT, 1, 0,
228 fast_ipsec_stats, NULL, 0, "ipsec" },
229 #endif
230 { -1, N_PIMSTAT, 1, 0,
231 pim_stats, NULL, 0, "pim" },
232 { -1, N_PFSYNCSTAT, 1, 0,
233 pfsync_stats, NULL, 0, "pfsync" },
234 { -1, -1, 0, 0,
235 0, NULL, 0, 0 }
236 };
237
238 #ifdef INET6
239 struct protox ip6protox[] = {
240 { -1, N_IP6STAT, 1, 0,
241 ip6_stats, ip6_ifstats, 0, "ip6" },
242 { -1, N_ICMP6STAT, 1, 0,
243 icmp6_stats, icmp6_ifstats, 0, "icmp6" },
244 #ifdef TCP6
245 { N_TCBTABLE, N_TCP6STAT, 1, ip6protopr,
246 tcp6_stats, NULL, tcp6_dump, "tcp6" },
247 #else
248 { N_TCBTABLE, N_TCP6STAT, 1, ip6protopr,
249 tcp_stats, NULL, tcp6_dump, "tcp6" },
250 #endif
251 { N_UDBTABLE, N_UDP6STAT, 1, ip6protopr,
252 udp6_stats, NULL, 0, "udp6" },
253 #ifdef IPSEC
254 { -1, N_IPSEC6STAT, 1, 0,
255 fast_ipsec_stats, NULL, 0, "ipsec6" },
256 #endif
257 { -1, N_PIM6STAT, 1, 0,
258 pim6_stats, NULL, 0, "pim6" },
259 { -1, N_RIP6STAT, 1, 0,
260 rip6_stats, NULL, 0, "rip6" },
261 { -1, -1, 0, 0,
262 0, NULL, 0, 0 }
263 };
264 #endif
265
266 struct protox arpprotox[] = {
267 { -1, N_ARPSTAT, 1, 0,
268 arp_stats, NULL, 0, "arp" },
269 { -1, -1, 0, 0,
270 0, NULL, 0, 0 }
271 };
272
273 #ifdef IPSEC
274 struct protox pfkeyprotox[] = {
275 { -1, N_PFKEYSTAT, 1, 0,
276 pfkey_stats, NULL, 0, "pfkey" },
277 { -1, -1, 0, 0,
278 0, NULL, 0, 0 }
279 };
280 #endif
281
282 #ifndef SMALL
283 struct protox atalkprotox[] = {
284 { N_DDPCB, N_DDPSTAT, 1, atalkprotopr,
285 ddp_stats, NULL, 0, "ddp" },
286 { -1, -1, 0, 0,
287 0, NULL, 0, NULL }
288 };
289 #endif
290
291 struct protox *protoprotox[] = { protox,
292 #ifdef INET6
293 ip6protox,
294 #endif
295 arpprotox,
296 #ifdef IPSEC
297 pfkeyprotox,
298 #endif
299 #ifndef SMALL
300 atalkprotox,
301 #endif
302 NULL };
303
304 const struct softintrq {
305 const char *siq_name;
306 int siq_index;
307 } softintrq[] = {
308 { "arpintrq", N_ARPINTRQ },
309 { "atintrq1", N_ATINTRQ1 },
310 { "atintrq2", N_ATINTRQ2 },
311 { "ppoediscinq", N_PPPOEDISCINQ },
312 { "ppoeinq", N_PPPOEINQ },
313 { NULL, -1 },
314 };
315
316 static void printproto(struct protox *, const char *);
317 static void print_softintrq(void);
318 __dead static void usage(void);
319 static struct protox *name2protox(const char *);
320 static struct protox *knownname(const char *);
321 static void prepare(const char *, const char *, struct protox *tp);
322 static kvm_t *prepare_kvmd(const char *, const char *, char *);
323
324 static kvm_t *kvmd = NULL;
325 gid_t egid;
326 int interval; /* repeat interval for i/f stats */
327 static const char *nlistf = NULL, *memf = NULL;
328
329 kvm_t *
get_kvmd(void)330 get_kvmd(void)
331 {
332 char buf[_POSIX2_LINE_MAX];
333
334 if (kvmd != NULL)
335 return kvmd;
336 if ((kvmd = prepare_kvmd(nlistf, memf, buf)) == NULL)
337 errx(1, "kvm error: %s", buf);
338 return kvmd;
339 }
340
341 static kvm_t *
prepare_kvmd(const char * nf,const char * mf,char * errbuf)342 prepare_kvmd(const char *nf, const char *mf, char *errbuf)
343 {
344 kvm_t *k;
345
346 (void)setegid(egid);
347 k = kvm_openfiles(nf, mf, NULL, O_RDONLY, errbuf);
348 (void)setgid(getgid());
349 return k;
350 }
351
352 void
prepare(const char * nf,const char * mf,struct protox * tp)353 prepare(const char *nf, const char *mf, struct protox *tp)
354 {
355 char buf[_POSIX2_LINE_MAX];
356
357 /*
358 * Try to figure out if we can use sysctl or not.
359 */
360 if (nf != NULL || mf != NULL) {
361 /* Of course, we can't use sysctl with dumps. */
362 if (force_sysctl)
363 errx(EXIT_FAILURE, "can't use sysctl with dumps");
364
365 /*
366 * If we have -M or -N, we're not dealing with live memory
367 * or want to use kvm interface explicitly. It is sometimes
368 * useful to dig inside of kernel without extending
369 * sysctl interface (i.e., without rebuilding kernel).
370 */
371 use_sysctl = 0;
372 } else if (qflag ||
373 #ifndef SMALL
374 gflag ||
375 #endif
376 (pflag && tp->pr_sindex == N_PIMSTAT) ||
377 Pflag) {
378 /* These flags are not yet supported via sysctl(3). */
379 use_sysctl = 0;
380 } else {
381 /* We can use sysctl(3). */
382 use_sysctl = 1;
383 }
384
385 if (force_sysctl && !use_sysctl) {
386 /* Let the user know what's about to happen. */
387 warnx("forcing sysctl usage even though it might not be "
388 "supported");
389 use_sysctl = 1;
390 }
391
392 kvmd = prepare_kvmd(nf, mf, buf);
393
394 if (!use_sysctl) {
395
396 if (kvmd == NULL)
397 errx(1, "kvm error: %s", buf);
398 if (kvm_nlist(kvmd, nl) < 0 || nl[0].n_type == 0) {
399 if (nf)
400 errx(1, "%s: no namelist", nf);
401 else
402 errx(1, "no namelist");
403 }
404 } else
405 (void)setgid(getgid());
406 }
407
408 int
main(int argc,char * argv[])409 main(int argc, char *argv[])
410 {
411 struct protoent *p;
412 struct protox *tp; /* for printing cblocks & stats */
413 int ch;
414 char *cp;
415 char *afname, *afnames;
416 u_long pcbaddr;
417
418 if (prog_init) {
419 if (prog_init() == -1)
420 err(1, "init failed");
421 force_sysctl = 1; /* cheap trick */
422 }
423
424 egid = getegid();
425 (void)setegid(getgid());
426 tp = NULL;
427 af = AF_UNSPEC;
428 afnames = NULL;
429 pcbaddr = 0;
430
431 while ((ch = getopt(argc, argv,
432 "AabBdf:ghI:LliM:mN:nP:p:qrsStTuVvw:X")) != -1)
433 switch (ch) {
434 case 'A':
435 Aflag = RT_AFLAG;
436 break;
437 case 'a':
438 aflag = 1;
439 break;
440 case 'b':
441 bflag = 1;
442 break;
443 case 'B':
444 Bflag = 1;
445 break;
446 case 'd':
447 dflag = 1;
448 break;
449 case 'f':
450 afnames = optarg;
451 break;
452 #ifndef SMALL
453 case 'g':
454 gflag = 1;
455 break;
456 #endif
457 case 'h':
458 hflag = 1;
459 break;
460 case 'I':
461 iflag = 1;
462 interface = optarg;
463 break;
464 case 'i':
465 iflag = 1;
466 break;
467 case 'L':
468 Lflag = RT_LFLAG;
469 break;
470 case 'l':
471 lflag = 1;
472 break;
473 case 'M':
474 memf = optarg;
475 break;
476 case 'm':
477 mflag = 1;
478 break;
479 case 'N':
480 nlistf = optarg;
481 break;
482 case 'n':
483 numeric_addr = numeric_port = nflag = RT_NFLAG;
484 break;
485 case 'P':
486 errno = 0;
487 pcbaddr = strtoul(optarg, &cp, 16);
488 if (*cp != '\0' || errno == ERANGE)
489 errx(1, "invalid PCB address %s", optarg);
490 Pflag = 1;
491 break;
492 case 'p':
493 if ((tp = name2protox(optarg)) == NULL)
494 errx(1,
495 "%s: unknown or uninstrumented protocol",
496 optarg);
497 pflag = 1;
498 break;
499 case 'q':
500 qflag = 1;
501 break;
502 case 'r':
503 rflag = 1;
504 break;
505 case 's':
506 ++sflag;
507 break;
508 case 'S':
509 numeric_addr = 1;
510 break;
511 case 't':
512 tflag = 1;
513 break;
514 case 'T':
515 tagflag = RT_TFLAG;
516 break;
517 case 'u':
518 af = AF_LOCAL;
519 break;
520 case 'V':
521 Vflag++;
522 break;
523 case 'v':
524 vflag = RT_VFLAG;
525 break;
526 case 'w':
527 interval = atoi(optarg);
528 iflag = 1;
529 break;
530 case 'X':
531 force_sysctl = 1;
532 break;
533 case '?':
534 default:
535 usage();
536 }
537 argv += optind;
538 argc -= optind;
539
540 #define BACKWARD_COMPATIBILITY
541 #ifdef BACKWARD_COMPATIBILITY
542 if (*argv) {
543 if (isdigit((unsigned char)**argv)) {
544 interval = atoi(*argv);
545 if (interval <= 0)
546 usage();
547 ++argv;
548 iflag = 1;
549 }
550 if (*argv) {
551 nlistf = *argv;
552 if (*++argv)
553 memf = *argv;
554 }
555 }
556 #endif
557
558 prepare(nlistf, memf, tp);
559
560 #ifndef SMALL
561 if (Bflag) {
562 if (sflag)
563 bpf_stats();
564 else
565 bpf_dump(interface);
566 exit(0);
567 }
568 #endif
569
570 if (mflag) {
571 mbpr(nl[N_MBSTAT].n_value, nl[N_MSIZE].n_value,
572 nl[N_MCLBYTES].n_value, nl[N_MBPOOL].n_value,
573 nl[N_MCLPOOL].n_value);
574 exit(0);
575 }
576 if (Pflag) {
577 if (tp == NULL) {
578 /* Default to TCP. */
579 tp = name2protox("tcp");
580 }
581 if (tp->pr_dump)
582 (*tp->pr_dump)(nl[tp->pr_index].n_value, tp->pr_name,
583 pcbaddr);
584 else
585 printf("%s: no PCB dump routine\n", tp->pr_name);
586 exit(0);
587 }
588 if (pflag) {
589 if (iflag && tp->pr_istats)
590 intpr(interval, nl[N_IFNET_LIST].n_value,
591 tp->pr_istats);
592 else if (tp->pr_stats)
593 (*tp->pr_stats)(nl[tp->pr_sindex].n_value,
594 tp->pr_name);
595 else
596 printf("%s: no stats routine\n", tp->pr_name);
597 exit(0);
598 }
599 if (qflag) {
600 print_softintrq();
601 exit(0);
602 }
603 /*
604 * Keep file descriptors open to avoid overhead
605 * of open/close on each call to get* routines.
606 */
607 sethostent(1);
608 setnetent(1);
609 /*
610 * If -f was used afnames != NULL, loop over the address families.
611 * Otherwise do this at least once (with af == AF_UNSPEC).
612 */
613 afname = NULL;
614 do {
615 if (afnames != NULL) {
616 afname = strsep(&afnames, ",");
617 if (afname == NULL)
618 break; /* Exit early */
619 if (strcmp(afname, "inet") == 0)
620 af = AF_INET;
621 else if (strcmp(afname, "inet6") == 0)
622 af = AF_INET6;
623 else if (strcmp(afname, "arp") == 0)
624 af = AF_ARP;
625 else if (strcmp(afname, "pfkey") == 0)
626 af = PF_KEY;
627 else if (strcmp(afname, "unix") == 0
628 || strcmp(afname, "local") == 0)
629 af = AF_LOCAL;
630 else if (strcmp(afname, "atalk") == 0)
631 af = AF_APPLETALK;
632 else if (strcmp(afname, "mpls") == 0)
633 af = AF_MPLS;
634 else {
635 warnx("%s: unknown address family",
636 afname);
637 continue;
638 }
639 }
640
641 if (iflag) {
642 if (af != AF_UNSPEC)
643 goto protostat;
644
645 intpr(interval, nl[N_IFNET_LIST].n_value, NULL);
646 break;
647 }
648 if (rflag) {
649 if (sflag)
650 rt_stats(use_sysctl ? 0 :
651 nl[N_RTSTAT].n_value);
652 else {
653 if (use_sysctl)
654 p_rttables(af,
655 nflag|tagflag|vflag|Lflag, 0, ~0);
656 else
657 routepr(nl[N_RTREE].n_value);
658 }
659 break;
660 }
661 #ifndef SMALL
662 if (gflag) {
663 if (sflag) {
664 if (af == AF_INET || af == AF_UNSPEC)
665 mrt_stats(nl[N_MRTPROTO].n_value,
666 nl[N_MRTSTAT].n_value);
667 #ifdef INET6
668 if (af == AF_INET6 || af == AF_UNSPEC)
669 mrt6_stats(nl[N_MRT6PROTO].n_value,
670 nl[N_MRT6STAT].n_value);
671 #endif
672 }
673 else {
674 if (af == AF_INET || af == AF_UNSPEC)
675 mroutepr(nl[N_MRTPROTO].n_value,
676 nl[N_MFCHASHTBL].n_value,
677 nl[N_MFCHASH].n_value,
678 nl[N_VIFTABLE].n_value);
679 #ifdef INET6
680 if (af == AF_INET6 || af == AF_UNSPEC)
681 mroute6pr(nl[N_MRT6PROTO].n_value,
682 nl[N_MF6CTABLE].n_value,
683 nl[N_MIF6TABLE].n_value);
684 #endif
685 }
686 break;
687 }
688 #endif
689 protostat:
690 if (af == AF_INET || af == AF_UNSPEC) {
691 setprotoent(1);
692 setservent(1);
693 /* ugh, this is O(MN) ... why do we do this? */
694 while ((p = getprotoent()) != NULL) {
695 for (tp = protox; tp->pr_name; tp++)
696 if (strcmp(tp->pr_name, p->p_name) == 0)
697 break;
698 if (tp->pr_name == 0 || tp->pr_wanted == 0)
699 continue;
700 printproto(tp, p->p_name);
701 tp->pr_wanted = 0;
702 }
703 endprotoent();
704 for (tp = protox; tp->pr_name; tp++)
705 if (tp->pr_wanted)
706 printproto(tp, tp->pr_name);
707 }
708 #ifdef INET6
709 if (af == AF_INET6 || af == AF_UNSPEC)
710 for (tp = ip6protox; tp->pr_name; tp++)
711 printproto(tp, tp->pr_name);
712 #endif
713 if (af == AF_ARP || af == AF_UNSPEC)
714 for (tp = arpprotox; tp->pr_name; tp++)
715 printproto(tp, tp->pr_name);
716 #ifdef IPSEC
717 if (af == PF_KEY || af == AF_UNSPEC)
718 for (tp = pfkeyprotox; tp->pr_name; tp++)
719 printproto(tp, tp->pr_name);
720 #endif
721 #ifndef SMALL
722 if (af == AF_APPLETALK || af == AF_UNSPEC)
723 for (tp = atalkprotox; tp->pr_name; tp++)
724 printproto(tp, tp->pr_name);
725 if ((af == AF_LOCAL || af == AF_UNSPEC) && !sflag)
726 unixpr(nl[N_UNIXSW].n_value);
727 #endif
728 } while (afnames != NULL && afname != NULL);
729 exit(0);
730 }
731
732 /*
733 * Print out protocol statistics or control blocks (per sflag).
734 * If the interface was not specifically requested, and the symbol
735 * is not in the namelist, ignore this one.
736 */
737 static void
printproto(struct protox * tp,const char * name)738 printproto(struct protox *tp, const char *name)
739 {
740 void (*pr)(u_long, const char *);
741 u_long off;
742
743 if (sflag) {
744 if (iflag) {
745 if (tp->pr_istats)
746 intpr(interval, nl[N_IFNET_LIST].n_value,
747 tp->pr_istats);
748 return;
749 }
750 else {
751 pr = tp->pr_stats;
752 off = nl[tp->pr_sindex].n_value;
753 }
754 } else {
755 pr = tp->pr_cblocks;
756 off = nl[tp->pr_index].n_value;
757 }
758 if (pr != NULL && ((off || af != AF_UNSPEC) || use_sysctl))
759 (*pr)(off, name);
760 }
761
762 /*
763 * Print softintrq status.
764 */
765 void
print_softintrq(void)766 print_softintrq(void)
767 {
768 struct ifqueue intrq, *ifq = &intrq;
769 const struct softintrq *siq;
770 u_long off;
771
772 for (siq = softintrq; siq->siq_name != NULL; siq++) {
773 off = nl[siq->siq_index].n_value;
774 if (off == 0)
775 continue;
776
777 kread(off, (char *)ifq, sizeof(*ifq));
778 printf("%s:\n", siq->siq_name);
779 printf("\tqueue length: %d\n", ifq->ifq_len);
780 printf("\tmaximum queue length: %d\n", ifq->ifq_maxlen);
781 printf("\tpackets dropped: %" PRIu64 "\n", ifq->ifq_drops);
782 }
783 }
784
785 /*
786 * Read kernel memory, return 0 on success.
787 */
788 int
kread(u_long addr,char * buf,int size)789 kread(u_long addr, char *buf, int size)
790 {
791
792 if (kvm_read(kvmd, addr, buf, size) != size) {
793 warnx("%s", kvm_geterr(kvmd));
794 return -1;
795 }
796 return 0;
797 }
798
799 const char *
plural(int n)800 plural(int n)
801 {
802
803 return (n != 1 ? "s" : "");
804 }
805
806 const char *
plurales(int n)807 plurales(int n)
808 {
809
810 return (n != 1 ? "es" : "");
811 }
812
813 int
get_hardticks(void)814 get_hardticks(void)
815 {
816 int hardticks;
817
818 kread(nl[N_HARDCLOCK_TICKS].n_value, (char *)&hardticks,
819 sizeof(hardticks));
820 return hardticks;
821 }
822
823 /*
824 * Find the protox for the given "well-known" name.
825 */
826 static struct protox *
knownname(const char * name)827 knownname(const char *name)
828 {
829 struct protox **tpp, *tp;
830
831 for (tpp = protoprotox; *tpp; tpp++)
832 for (tp = *tpp; tp->pr_name; tp++)
833 if (strcmp(tp->pr_name, name) == 0)
834 return tp;
835 return NULL;
836 }
837
838 /*
839 * Find the protox corresponding to name.
840 */
841 static struct protox *
name2protox(const char * name)842 name2protox(const char *name)
843 {
844 struct protox *tp;
845 char **alias; /* alias from p->aliases */
846 struct protoent *p;
847
848 /*
849 * Try to find the name in the list of "well-known" names. If that
850 * fails, check if name is an alias for an Internet protocol.
851 */
852 if ((tp = knownname(name)) != NULL)
853 return tp;
854
855 setprotoent(1); /* make protocol lookup cheaper */
856 while ((p = getprotoent()) != NULL) {
857 /* assert: name not same as p->name */
858 for (alias = p->p_aliases; *alias; alias++)
859 if (strcmp(name, *alias) == 0) {
860 endprotoent();
861 return knownname(p->p_name);
862 }
863 }
864 endprotoent();
865 return NULL;
866 }
867
868 static void
usage(void)869 usage(void)
870 {
871 const char *progname = getprogname();
872
873 (void)fprintf(stderr,
874 "usage: %s [-Aan] [-f address_family[,family ...]] [-M core] [-N system]\n", progname);
875 (void)fprintf(stderr,
876 " %s [-bdgiLmnqrsSv] [-f address_family[,family ...]] [-M core] [-N system]\n",
877 progname);
878 (void)fprintf(stderr,
879 " %s [-dn] [-I interface] [-M core] [-N system] [-w wait]\n", progname);
880 (void)fprintf(stderr,
881 " %s [-p protocol] [-M core] [-N system]\n", progname);
882 (void)fprintf(stderr,
883 " %s [-p protocol] [-M core] [-N system] -P pcbaddr\n", progname);
884 (void)fprintf(stderr,
885 " %s [-p protocol] [-i] [-I Interface] \n", progname);
886 (void)fprintf(stderr,
887 " %s [-s] [-f address_family[,family ...]] [-i] [-I Interface]\n", progname);
888 (void)fprintf(stderr,
889 " %s [-s] [-B] [-I interface]\n", progname);
890 exit(1);
891 }
892