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