1 /*        $NetBSD: main.c,v 1.105 2023/08/18 13:18:17 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.105 2023/08/18 13:18:17 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_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                               nsbpf_stats();
564                     else
565                               nsbpf_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