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