]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/netstat/main.c
OpenSSL: Vendor import of OpenSSL 3.0.13
[FreeBSD/FreeBSD.git] / usr.bin / netstat / main.c
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
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/param.h>
33 #include <sys/file.h>
34 #ifdef JAIL
35 #include <sys/jail.h>
36 #endif
37 #include <sys/protosw.h>
38 #include <sys/socket.h>
39 #include <sys/socketvar.h>
40 #include <sys/sysctl.h>
41
42 #include <netinet/in.h>
43
44 #ifdef NETGRAPH
45 #include <netgraph/ng_socket.h>
46 #endif
47
48 #include <ctype.h>
49 #include <err.h>
50 #include <errno.h>
51 #ifdef JAIL
52 #include <jail.h>
53 #endif
54 #include <kvm.h>
55 #include <limits.h>
56 #include <netdb.h>
57 #include <nlist.h>
58 #include <paths.h>
59 #include <stdint.h>
60 #include <stdio.h>
61 #include <stdlib.h>
62 #include <stdbool.h>
63 #include <string.h>
64 #include <unistd.h>
65 #include "netstat.h"
66 #include "nl_defs.h"
67 #include <libxo/xo.h>
68
69 static struct protox {
70         int     pr_index;               /* index into nlist of cb head */
71         int     pr_sindex;              /* index into nlist of stat block */
72         u_char  pr_wanted;              /* 1 if wanted, 0 otherwise */
73         void    (*pr_cblocks)(u_long, const char *, int, int);
74                                         /* control blocks printing routine */
75         void    (*pr_stats)(u_long, const char *, int, int);
76                                         /* statistics printing routine */
77         void    (*pr_istats)(char *);   /* per/if statistics printing routine */
78         const char      *pr_name;               /* well-known name */
79         int     pr_usesysctl;           /* non-zero if we use sysctl, not kvm */
80         int     pr_protocol;
81 } protox[] = {
82         { -1    ,       N_TCPSTAT,      1,      protopr,
83           tcp_stats,    NULL,           "tcp",  1,      IPPROTO_TCP },
84         { -1    ,       N_UDPSTAT,      1,      protopr,
85           udp_stats,    NULL,           "udp",  1,      IPPROTO_UDP },
86 #ifdef SCTP
87         { -1,           N_SCTPSTAT,     1,      sctp_protopr,
88           sctp_stats,   NULL,           "sctp", 1,      IPPROTO_SCTP },
89 #endif
90 #ifdef SDP
91         { -1,           -1,             1,      protopr,
92          NULL,          NULL,           "sdp",  1,      IPPROTO_TCP },
93 #endif
94         { -1    ,       -1,             1,      protopr,
95           divert_stats, NULL,           "divert", 1,    0 },
96         { -1    ,       N_IPSTAT,       1,      protopr,
97           ip_stats,     NULL,           "ip",   1,      IPPROTO_RAW },
98         { -1    ,       N_ICMPSTAT,     1,      protopr,
99           icmp_stats,   NULL,           "icmp", 1,      IPPROTO_ICMP },
100         { -1    ,       N_IGMPSTAT,     1,      protopr,
101           igmp_stats,   NULL,           "igmp", 1,      IPPROTO_IGMP },
102 #ifdef IPSEC
103         { -1,           N_IPSEC4STAT,   1,      NULL,   /* keep as compat */
104           ipsec_stats,  NULL,           "ipsec", 1,     0},
105         { -1,           N_AHSTAT,       1,      NULL,
106           ah_stats,     NULL,           "ah",   1,      0},
107         { -1,           N_ESPSTAT,      1,      NULL,
108           esp_stats,    NULL,           "esp",  1,      0},
109         { -1,           N_IPCOMPSTAT,   1,      NULL,
110           ipcomp_stats, NULL,           "ipcomp", 1,    0},
111 #endif
112         { -1    ,       N_PIMSTAT,      1,      protopr,
113           pim_stats,    NULL,           "pim",  1,      IPPROTO_PIM },
114         { -1,           N_CARPSTATS,    1,      NULL,
115           carp_stats,   NULL,           "carp", 1,      0 },
116 #ifdef PF
117         { -1,           N_PFSYNCSTATS,  1,      NULL,
118           pfsync_stats, NULL,           "pfsync", 1,    0 },
119         { -1,           N_PFLOWSTATS,   1,      NULL,
120           pflow_stats,  NULL,           "pflow", 1,     0 },
121 #endif
122         { -1,           N_ARPSTAT,      1,      NULL,
123           arp_stats,    NULL,           "arp", 1,       0 },
124         { -1,           -1,             0,      NULL,
125           NULL,         NULL,           NULL,   0,      0 }
126 };
127
128 #ifdef INET6
129 static struct protox ip6protox[] = {
130         { -1    ,       N_TCPSTAT,      1,      protopr,
131           tcp_stats,    NULL,           "tcp",  1,      IPPROTO_TCP },
132         { -1    ,       N_UDPSTAT,      1,      protopr,
133           udp_stats,    NULL,           "udp",  1,      IPPROTO_UDP },
134         { -1    ,       N_IP6STAT,      1,      protopr,
135           ip6_stats,    ip6_ifstats,    "ip6",  1,      IPPROTO_RAW },
136         { -1    ,       N_ICMP6STAT,    1,      protopr,
137           icmp6_stats,  icmp6_ifstats,  "icmp6", 1,     IPPROTO_ICMPV6 },
138 #ifdef SDP
139         { -1,           -1,             1,      protopr,
140          NULL,          NULL,           "sdp",  1,      IPPROTO_TCP },
141 #endif
142 #ifdef IPSEC
143         { -1,           N_IPSEC6STAT,   1,      NULL,
144           ipsec_stats,  NULL,           "ipsec6", 1,    0 },
145 #endif
146 #ifdef notyet
147         { -1,           N_PIM6STAT,     1,      NULL,
148           pim6_stats,   NULL,           "pim6", 1,      0 },
149 #endif
150         { -1,           N_RIP6STAT,     1,      NULL,
151           rip6_stats,   NULL,           "rip6", 1,      0 },
152         { -1,           -1,             0,      NULL,
153           NULL,         NULL,           NULL,   0,      0 }
154 };
155 #endif /*INET6*/
156
157 #ifdef IPSEC
158 static struct protox pfkeyprotox[] = {
159         { -1,           N_PFKEYSTAT,    1,      NULL,
160           pfkey_stats,  NULL,           "pfkey", 0,     0 },
161         { -1,           -1,             0,      NULL,
162           NULL,         NULL,           NULL,   0,      0 }
163 };
164 #endif
165
166 #ifdef NETGRAPH
167 static struct protox netgraphprotox[] = {
168         { N_NGSOCKLIST, -1,             1,      netgraphprotopr,
169           NULL,         NULL,           "ctrl", 0,      0 },
170         { N_NGSOCKLIST, -1,             1,      netgraphprotopr,
171           NULL,         NULL,           "data", 0,      0 },
172         { -1,           -1,             0,      NULL,
173           NULL,         NULL,           NULL,   0,      0 }
174 };
175 #endif
176
177 static struct protox *protoprotox[] = {
178                                          protox,
179 #ifdef INET6
180                                          ip6protox,
181 #endif
182 #ifdef IPSEC
183                                          pfkeyprotox,
184 #endif
185                                          NULL };
186
187 static void printproto(struct protox *, const char *, bool *);
188 static void usage(void) __dead2;
189 static struct protox *name2protox(const char *);
190 static struct protox *knownname(const char *);
191
192 static int kresolve_list(struct nlist *_nl);
193
194 static kvm_t *kvmd;
195 static char *nlistf = NULL, *memf = NULL;
196
197 int     Aflag;          /* show addresses of protocol control block */
198 int     aflag;          /* show all sockets (including servers) */
199 static int      Bflag;          /* show information about bpf consumers */
200 int     bflag;          /* show i/f total bytes in/out */
201 int     cflag;          /* show TCP congestion control stack */
202 int     Cflag;          /* show congestion control algo and vars */
203 int     dflag;          /* show i/f dropped packets */
204 int     gflag;          /* show group (multicast) routing or stats */
205 int     hflag;          /* show counters in human readable format */
206 int     iflag;          /* show interfaces */
207 int     Lflag;          /* show size of listen queues */
208 int     mflag;          /* show memory stats */
209 int     noutputs = 0;   /* how much outputs before we exit */
210 int     numeric_addr;   /* show addresses numerically */
211 int     numeric_port;   /* show ports numerically */
212 int     Oflag;          /* show nhgrp objects*/
213 int     oflag;          /* show nexthop objects*/
214 int     Pflag;          /* show TCP log ID */
215 static int pflag;       /* show given protocol */
216 static int      Qflag;          /* show netisr information */
217 int     rflag;          /* show routing tables (or routing stats) */
218 int     Rflag;          /* show flow / RSS statistics */
219 int     sflag;          /* show protocol statistics */
220 int     Wflag;          /* wide display */
221 int     Tflag;          /* TCP Information */
222 int     xflag;          /* extra information, includes all socket buffer info */
223 int     zflag;          /* zero stats */
224
225 int     interval;       /* repeat interval for i/f stats */
226
227 char    *interface;     /* desired i/f for stats, or NULL for all i/fs */
228 int     unit;           /* unit number for above */
229 #ifdef JAIL
230 char    *jail_name;     /* desired jail to operate in */
231 #endif
232
233 static int      af;             /* address family */
234 int     live;           /* true if we are examining a live system */
235
236 int
237 main(int argc, char *argv[])
238 {
239         struct protox *tp = NULL;  /* for printing cblocks & stats */
240         int ch;
241         int fib = -1;
242         char *endptr;
243         bool first = true;
244 #ifdef JAIL
245         int jid;
246 #endif
247
248         af = AF_UNSPEC;
249
250         argc = xo_parse_args(argc, argv);
251         if (argc < 0)
252                 exit(EXIT_FAILURE);
253
254         while ((ch = getopt(argc, argv, "46AaBbCcdF:f:ghI:ij:LlM:mN:nOoPp:Qq:RrSTsuWw:xz"))
255             != -1)
256                 switch(ch) {
257                 case '4':
258 #ifdef INET
259                         af = AF_INET;
260 #else
261                         errx(1, "IPv4 support is not compiled in");
262 #endif
263                         break;
264                 case '6':
265 #ifdef INET6
266                         af = AF_INET6;
267 #else
268                         errx(1, "IPv6 support is not compiled in");
269 #endif
270                         break;
271                 case 'A':
272                         Aflag = 1;
273                         break;
274                 case 'a':
275                         aflag = 1;
276                         break;
277                 case 'B':
278                         Bflag = 1;
279                         break;
280                 case 'b':
281                         bflag = 1;
282                         break;
283                 case 'c':
284                         cflag = 1;
285                         break;
286                 case 'C':
287                         Cflag = 1;
288                         break;
289                 case 'd':
290                         dflag = 1;
291                         break;
292                 case 'F':
293                         fib = strtol(optarg, &endptr, 0);
294                         if (*endptr != '\0' ||
295                             (fib == 0 && (errno == EINVAL || errno == ERANGE)))
296                                 xo_errx(1, "%s: invalid fib", optarg);
297                         break;
298                 case 'f':
299                         if (strcmp(optarg, "inet") == 0)
300                                 af = AF_INET;
301 #ifdef INET6
302                         else if (strcmp(optarg, "inet6") == 0)
303                                 af = AF_INET6;
304 #endif
305 #ifdef IPSEC
306                         else if (strcmp(optarg, "pfkey") == 0)
307                                 af = PF_KEY;
308 #endif
309                         else if (strcmp(optarg, "unix") == 0 ||
310                                  strcmp(optarg, "local") == 0)
311                                 af = AF_UNIX;
312 #ifdef NETGRAPH
313                         else if (strcmp(optarg, "ng") == 0
314                             || strcmp(optarg, "netgraph") == 0)
315                                 af = AF_NETGRAPH;
316 #endif
317                         else if (strcmp(optarg, "link") == 0)
318                                 af = AF_LINK;
319                         else {
320                                 xo_errx(1, "%s: unknown address family",
321                                     optarg);
322                         }
323                         break;
324                 case 'g':
325                         gflag = 1;
326                         break;
327                 case 'h':
328                         hflag = 1;
329                         break;
330                 case 'I': {
331                         char *cp;
332
333                         iflag = 1;
334                         for (cp = interface = optarg; isalpha(*cp); cp++)
335                                 continue;
336                         unit = atoi(cp);
337                         break;
338                 }
339                 case 'i':
340                         iflag = 1;
341                         break;
342                 case 'j':
343 #ifdef JAIL
344                         if (optarg == NULL)
345                                 usage();
346                         jail_name = optarg;
347 #else
348                         errx(1, "Jail support is not compiled in");
349 #endif
350                         break;
351                 case 'L':
352                         Lflag = 1;
353                         break;
354                 case 'M':
355                         memf = optarg;
356                         break;
357                 case 'm':
358                         mflag = 1;
359                         break;
360                 case 'N':
361                         nlistf = optarg;
362                         break;
363                 case 'n':
364                         numeric_addr = numeric_port = 1;
365                         break;
366                 case 'o':
367                         oflag = 1;
368                         break;
369                 case 'O':
370                         Oflag = 1;
371                         break;
372                 case 'P':
373                         Pflag = 1;
374                         break;
375                 case 'p':
376                         if ((tp = name2protox(optarg)) == NULL) {
377                                 xo_errx(1, "%s: unknown or uninstrumented "
378                                     "protocol", optarg);
379                         }
380                         pflag = 1;
381                         break;
382                 case 'Q':
383                         Qflag = 1;
384                         break;
385                 case 'q':
386                         noutputs = atoi(optarg);
387                         if (noutputs != 0)
388                                 noutputs++;
389                         break;
390                 case 'r':
391                         rflag = 1;
392                         break;
393                 case 'R':
394                         Rflag = 1;
395                         break;
396                 case 's':
397                         ++sflag;
398                         break;
399                 case 'S':
400                         numeric_addr = 1;
401                         break;
402                 case 'u':
403                         af = AF_UNIX;
404                         break;
405                 case 'W':
406                 case 'l':
407                         Wflag = 1;
408                         break;
409                 case 'w':
410                         interval = atoi(optarg);
411                         iflag = 1;
412                         break;
413                 case 'T':
414                         Tflag = 1;
415                         break;
416                 case 'x':
417                         xflag = 1;
418                         break;
419                 case 'z':
420                         zflag = 1;
421                         break;
422                 case '?':
423                 default:
424                         usage();
425                 }
426         argv += optind;
427         argc -= optind;
428
429 #define BACKWARD_COMPATIBILITY
430 #ifdef  BACKWARD_COMPATIBILITY
431         if (*argv) {
432                 if (isdigit(**argv)) {
433                         interval = atoi(*argv);
434                         if (interval <= 0)
435                                 usage();
436                         ++argv;
437                         iflag = 1;
438                 }
439                 if (*argv) {
440                         nlistf = *argv;
441                         if (*++argv)
442                                 memf = *argv;
443                 }
444         }
445 #endif
446
447 #ifdef JAIL
448         if (jail_name != NULL) {
449                 jid = jail_getid(jail_name);
450                 if (jid == -1)
451                         errx(1, "Jail not found");
452                 if (jail_attach(jid) != 0)
453                         errx(1, "Cannot attach to jail");
454         }
455 #endif
456
457         /*
458          * Discard setgid privileges if not the running kernel so that bad
459          * guys can't print interesting stuff from kernel memory.
460          */
461         live = (nlistf == NULL && memf == NULL);
462         if (!live) {
463                 if (setgid(getgid()) != 0)
464                         xo_err(-1, "setgid");
465                 /* Load all necessary kvm symbols */
466                 kresolve_list(nl);
467         }
468
469         if (xflag && Tflag)
470                 xo_errx(1, "-x and -T are incompatible, pick one.");
471
472         if (Bflag) {
473                 if (!live)
474                         usage();
475                 bpf_stats(interface);
476                 xo_finish();
477                 exit(0);
478         }
479         if (mflag) {
480                 if (!live) {
481                         if (kread(0, NULL, 0) == 0)
482                                 mbpr(kvmd, nl[N_SFSTAT].n_value);
483                 } else
484                         mbpr(NULL, 0);
485                 xo_finish();
486                 exit(0);
487         }
488         if (Qflag) {
489                 if (!live) {
490                         if (kread(0, NULL, 0) == 0)
491                                 netisr_stats();
492                 } else
493                         netisr_stats();
494                 xo_finish();
495                 exit(0);
496         }
497 #if 0
498         /*
499          * Keep file descriptors open to avoid overhead
500          * of open/close on each call to get* routines.
501          */
502         sethostent(1);
503         setnetent(1);
504 #else
505         /*
506          * This does not make sense any more with DNS being default over
507          * the files.  Doing a setXXXXent(1) causes a tcp connection to be
508          * used for the queries, which is slower.
509          */
510 #endif
511         if (iflag && !sflag) {
512                 xo_open_container("statistics");
513                 intpr(NULL, af);
514                 xo_close_container("statistics");
515                 xo_finish();
516                 exit(0);
517         }
518         if (rflag) {
519                 xo_open_container("statistics");
520                 if (sflag) {
521                         if (live) {
522                                 kresolve_list(nl);
523                         }
524                         rt_stats();
525                 } else
526                         routepr(fib, af);
527                 xo_close_container("statistics");
528                 xo_finish();
529                 exit(0);
530         }
531         if (oflag) {
532                 xo_open_container("statistics");
533                 nhops_print(fib, af);
534                 xo_close_container("statistics");
535                 xo_finish();
536                 exit(0);
537         }
538         if (Oflag) {
539                 xo_open_container("statistics");
540                 nhgrp_print(fib, af);
541                 xo_close_container("statistics");
542                 xo_finish();
543                 exit(0);
544         }
545
546
547
548         if (gflag) {
549                 xo_open_container("statistics");
550                 if (sflag) {
551                         if (af == AF_INET || af == AF_UNSPEC)
552                                 mrt_stats();
553 #ifdef INET6
554                         if (af == AF_INET6 || af == AF_UNSPEC)
555                                 mrt6_stats();
556 #endif
557                 } else {
558                         if (af == AF_INET || af == AF_UNSPEC)
559                                 mroutepr();
560 #ifdef INET6
561                         if (af == AF_INET6 || af == AF_UNSPEC)
562                                 mroute6pr();
563 #endif
564                 }
565                 xo_close_container("statistics");
566                 xo_finish();
567                 exit(0);
568         }
569
570         if (tp) {
571                 xo_open_container("statistics");
572                 printproto(tp, tp->pr_name, &first);
573                 if (!first)
574                         xo_close_list("socket");
575                 xo_close_container("statistics");
576                 xo_finish();
577                 exit(0);
578         }
579
580         xo_open_container("statistics");
581         if (af == AF_INET || af == AF_UNSPEC)
582                 for (tp = protox; tp->pr_name; tp++)
583                         printproto(tp, tp->pr_name, &first);
584 #ifdef INET6
585         if (af == AF_INET6 || af == AF_UNSPEC)
586                 for (tp = ip6protox; tp->pr_name; tp++)
587                         printproto(tp, tp->pr_name, &first);
588 #endif /*INET6*/
589 #ifdef IPSEC
590         if (af == PF_KEY || af == AF_UNSPEC)
591                 for (tp = pfkeyprotox; tp->pr_name; tp++)
592                         printproto(tp, tp->pr_name, &first);
593 #endif /*IPSEC*/
594 #ifdef NETGRAPH
595         if (af == AF_NETGRAPH || af == AF_UNSPEC)
596                 for (tp = netgraphprotox; tp->pr_name; tp++)
597                         printproto(tp, tp->pr_name, &first);
598 #endif /* NETGRAPH */
599         if ((af == AF_UNIX || af == AF_UNSPEC) && !sflag)
600                 unixpr(nl[N_UNP_COUNT].n_value, nl[N_UNP_GENCNT].n_value,
601                     nl[N_UNP_DHEAD].n_value, nl[N_UNP_SHEAD].n_value,
602                     nl[N_UNP_SPHEAD].n_value, &first);
603
604         if (!first)
605                 xo_close_list("socket");
606         xo_close_container("statistics");
607         xo_finish();
608         exit(0);
609 }
610
611 static int
612 fetch_stats_internal(const char *sysctlname, u_long off, void *stats,
613     size_t len, kreadfn_t kreadfn, int zero)
614 {
615         int error;
616
617         if (live) {
618                 memset(stats, 0, len);
619                 if (zero)
620                         error = sysctlbyname(sysctlname, NULL, NULL, stats,
621                             len);
622                 else
623                         error = sysctlbyname(sysctlname, stats, &len, NULL, 0);
624                 if (error == -1 && errno != ENOENT)
625                         xo_warn("sysctl %s", sysctlname);
626         } else {
627                 if (off == 0)
628                         return (1);
629                 error = kreadfn(off, stats, len);
630         }
631         return (error);
632 }
633
634 int
635 fetch_stats(const char *sysctlname, u_long off, void *stats,
636     size_t len, kreadfn_t kreadfn)
637 {
638
639         return (fetch_stats_internal(sysctlname, off, stats, len, kreadfn,
640     zflag));
641 }
642
643 int
644 fetch_stats_ro(const char *sysctlname, u_long off, void *stats,
645     size_t len, kreadfn_t kreadfn)
646 {
647
648         return (fetch_stats_internal(sysctlname, off, stats, len, kreadfn, 0));
649 }
650
651 /*
652  * Print out protocol statistics or control blocks (per sflag).
653  * If the interface was not specifically requested, and the symbol
654  * is not in the namelist, ignore this one.
655  */
656 static void
657 printproto(struct protox *tp, const char *name, bool *first)
658 {
659         void (*pr)(u_long, const char *, int, int);
660         u_long off;
661         bool doingdblocks = false;
662
663         if (sflag) {
664                 if (iflag) {
665                         if (tp->pr_istats)
666                                 intpr(tp->pr_istats, af);
667                         else if (pflag)
668                                 xo_message("%s: no per-interface stats routine",
669                                     tp->pr_name);
670                         return;
671                 } else {
672                         pr = tp->pr_stats;
673                         if (!pr) {
674                                 if (pflag)
675                                         xo_message("%s: no stats routine",
676                                             tp->pr_name);
677                                 return;
678                         }
679                         if (tp->pr_usesysctl && live)
680                                 off = 0;
681                         else if (tp->pr_sindex < 0) {
682                                 if (pflag)
683                                         xo_message("%s: stats routine doesn't "
684                                             "work on cores", tp->pr_name);
685                                 return;
686                         } else
687                                 off = nl[tp->pr_sindex].n_value;
688                 }
689         } else {
690                 doingdblocks = true;
691                 pr = tp->pr_cblocks;
692                 if (!pr) {
693                         if (pflag)
694                                 xo_message("%s: no PCB routine", tp->pr_name);
695                         return;
696                 }
697                 if (tp->pr_usesysctl && live)
698                         off = 0;
699                 else if (tp->pr_index < 0) {
700                         if (pflag)
701                                 xo_message("%s: PCB routine doesn't work on "
702                                     "cores", tp->pr_name);
703                         return;
704                 } else
705                         off = nl[tp->pr_index].n_value;
706         }
707         if (pr != NULL && (off || (live && tp->pr_usesysctl) ||
708             af != AF_UNSPEC)) {
709                 if (doingdblocks && *first) {
710                         xo_open_list("socket");
711                         *first = false;
712                 }
713
714                 (*pr)(off, name, af, tp->pr_protocol);
715         }
716 }
717
718 static int
719 kvmd_init(void)
720 {
721         char errbuf[_POSIX2_LINE_MAX];
722
723         if (kvmd != NULL)
724                 return (0);
725
726         kvmd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
727         if (setgid(getgid()) != 0)
728                 xo_err(-1, "setgid");
729
730         if (kvmd == NULL) {
731                 xo_warnx("kvm not available: %s", errbuf);
732                 return (-1);
733         }
734
735         return (0);
736 }
737
738 /*
739  * Resolve symbol list, return 0 on success.
740  */
741 static int
742 kresolve_list(struct nlist *_nl)
743 {
744
745         if ((kvmd == NULL) && (kvmd_init() != 0))
746                 return (-1);
747
748         if (_nl[0].n_type != 0)
749                 return (0);
750
751         if (kvm_nlist(kvmd, _nl) < 0) {
752                 if (nlistf)
753                         xo_errx(1, "%s: kvm_nlist: %s", nlistf,
754                             kvm_geterr(kvmd));
755                 else
756                         xo_errx(1, "kvm_nlist: %s", kvm_geterr(kvmd));
757         }
758
759         return (0);
760 }
761
762 /*
763  * Wrapper of kvm_dpcpu_setcpu().
764  */
765 void
766 kset_dpcpu(u_int cpuid)
767 {
768
769         if ((kvmd == NULL) && (kvmd_init() != 0))
770                 xo_errx(-1, "%s: kvm is not available", __func__);
771
772         if (kvm_dpcpu_setcpu(kvmd, cpuid) < 0)
773                 xo_errx(-1, "%s: kvm_dpcpu_setcpu(%u): %s", __func__,
774                     cpuid, kvm_geterr(kvmd)); 
775         return;
776 }
777
778 /*
779  * Read kernel memory, return 0 on success.
780  */
781 int
782 kread(u_long addr, void *buf, size_t size)
783 {
784
785         if (kvmd_init() < 0)
786                 return (-1);
787
788         if (!buf)
789                 return (0);
790         if (kvm_read(kvmd, addr, buf, size) != (ssize_t)size) {
791                 xo_warnx("%s", kvm_geterr(kvmd));
792                 return (-1);
793         }
794         return (0);
795 }
796
797 /*
798  * Read single counter(9).
799  */
800 uint64_t
801 kread_counter(u_long addr)
802 {
803
804         if (kvmd_init() < 0)
805                 return (-1);
806
807         return (kvm_counter_u64_fetch(kvmd, addr));
808 }
809
810 /*
811  * Read an array of N counters in kernel memory into array of N uint64_t's.
812  */
813 int
814 kread_counters(u_long addr, void *buf, size_t size)
815 {
816         uint64_t *c;
817         u_long *counters;
818         size_t i, n;
819
820         if (kvmd_init() < 0)
821                 return (-1);
822
823         if (size % sizeof(uint64_t) != 0) {
824                 xo_warnx("kread_counters: invalid counter set size");
825                 return (-1);
826         }
827
828         n = size / sizeof(uint64_t);
829         if ((counters = malloc(n * sizeof(u_long))) == NULL)
830                 xo_err(-1, "malloc");
831         if (kread(addr, counters, n * sizeof(u_long)) < 0) {
832                 free(counters);
833                 return (-1);
834         }
835
836         c = buf;
837         for (i = 0; i < n; i++)
838                 c[i] = kvm_counter_u64_fetch(kvmd, counters[i]);
839
840         free(counters);
841         return (0);
842 }
843
844 const char *
845 plural(uintmax_t n)
846 {
847         return (n != 1 ? "s" : "");
848 }
849
850 const char *
851 plurales(uintmax_t n)
852 {
853         return (n != 1 ? "es" : "");
854 }
855
856 const char *
857 pluralies(uintmax_t n)
858 {
859         return (n != 1 ? "ies" : "y");
860 }
861
862 /*
863  * Find the protox for the given "well-known" name.
864  */
865 static struct protox *
866 knownname(const char *name)
867 {
868         struct protox **tpp, *tp;
869
870         for (tpp = protoprotox; *tpp; tpp++)
871                 for (tp = *tpp; tp->pr_name; tp++)
872                         if (strcmp(tp->pr_name, name) == 0)
873                                 return (tp);
874         return (NULL);
875 }
876
877 /*
878  * Find the protox corresponding to name.
879  */
880 static struct protox *
881 name2protox(const char *name)
882 {
883         struct protox *tp;
884         char **alias;                   /* alias from p->aliases */
885         struct protoent *p;
886
887         /*
888          * Try to find the name in the list of "well-known" names. If that
889          * fails, check if name is an alias for an Internet protocol.
890          */
891         if ((tp = knownname(name)) != NULL)
892                 return (tp);
893
894         setprotoent(1);                 /* make protocol lookup cheaper */
895         while ((p = getprotoent()) != NULL) {
896                 /* assert: name not same as p->name */
897                 for (alias = p->p_aliases; *alias; alias++)
898                         if (strcmp(name, *alias) == 0) {
899                                 endprotoent();
900                                 return (knownname(p->p_name));
901                         }
902         }
903         endprotoent();
904         return (NULL);
905 }
906
907 static void
908 usage(void)
909 {
910         (void)xo_error("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
911 "usage: netstat [-j jail] [-46AaCcLnRSTWx] [-f protocol_family | -p protocol]\n"
912 "               [-M core] [-N system]",
913 "       netstat [-j jail] -i | -I interface [-46abdhnW] [-f address_family]\n"
914 "               [-M core] [-N system]",
915 "       netstat [-j jail] -w wait [-I interface] [-46d] [-M core] [-N system]\n"
916 "               [-q howmany]",
917 "       netstat [-j jail] -s [-46sz] [-f protocol_family | -p protocol]\n"
918 "               [-M core] [-N system]",
919 "       netstat [-j jail] -i | -I interface -s [-46s]\n"
920 "               [-f protocol_family | -p protocol] [-M core] [-N system]",
921 "       netstat [-j jail] -m [-M core] [-N system]",
922 "       netstat [-j jail] -B [-z] [-I interface]",
923 "       netstat [-j jail] -r [-46AnW] [-F fibnum] [-f address_family]\n"
924 "               [-M core] [-N system]",
925 "       netstat [-j jail] -rs [-s] [-M core] [-N system]",
926 "       netstat [-j jail] -g [-46W] [-f address_family] [-M core] [-N system]",
927 "       netstat [-j jail] -gs [-46s] [-f address_family] [-M core] [-N system]",
928 "       netstat [-j jail] -Q");
929         xo_finish();
930         exit(1);
931 }