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