xref: /f-stack/tools/netstat/main.c (revision 2bfe3f2e)
1 /*-
2  * Copyright (c) 1983, 1988, 1993
3  *	Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 4. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #ifndef lint
31 static char const copyright[] =
32 "@(#) Copyright (c) 1983, 1988, 1993\n\
33 	Regents of the University of California.  All rights reserved.\n";
34 #endif /* not lint */
35 
36 #if 0
37 #ifndef lint
38 static char sccsid[] = "@(#)main.c	8.4 (Berkeley) 3/1/94";
39 #endif /* not lint */
40 #endif
41 
42 #include <sys/cdefs.h>
43 __FBSDID("$FreeBSD$");
44 
45 #include <sys/param.h>
46 #include <sys/file.h>
47 #include <sys/protosw.h>
48 #include <sys/socket.h>
49 #include <sys/socketvar.h>
50 #include <sys/sysctl.h>
51 
52 #include <netinet/in.h>
53 
54 #ifdef NETGRAPH
55 #include <netgraph/ng_socket.h>
56 #endif
57 
58 #include <ctype.h>
59 #include <err.h>
60 #include <errno.h>
61 #ifndef FSTACK
62 #include <kvm.h>
63 #endif
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 #ifdef FSTACK
79 #include "ff_ipc.h"
80 #endif
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 	{ N_TCBINFO,	N_TCPSTAT,	1,	protopr,
96 	  tcp_stats,	NULL,		"tcp",	1,	IPPROTO_TCP },
97 	{ N_UDBINFO,	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 	{ N_DIVCBINFO,	-1,		1,	protopr,
108 	  NULL,		NULL,		"divert", 1,	IPPROTO_DIVERT },
109 	{ N_RIPCBINFO,	N_IPSTAT,	1,	protopr,
110 	  ip_stats,	NULL,		"ip",	1,	IPPROTO_RAW },
111 	{ N_RIPCBINFO,	N_ICMPSTAT,	1,	protopr,
112 	  icmp_stats,	NULL,		"icmp",	1,	IPPROTO_ICMP },
113 	{ N_RIPCBINFO,	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 	{ N_RIPCBINFO,	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 	{ N_TCBINFO,	N_TCPSTAT,	1,	protopr,
142 	  tcp_stats,	NULL,		"tcp",	1,	IPPROTO_TCP },
143 	{ N_UDBINFO,	N_UDPSTAT,	1,	protopr,
144 	  udp_stats,	NULL,		"udp",	1,	IPPROTO_UDP },
145 	{ N_RIPCBINFO,	N_IP6STAT,	1,	protopr,
146 	  ip6_stats,	ip6_ifstats,	"ip6",	1,	IPPROTO_RAW },
147 	{ N_RIPCBINFO,	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);
200 static struct protox *name2protox(const char *);
201 static struct protox *knownname(const char *);
202 
203 #ifndef FSTACK
204 static int kresolve_list(struct nlist *_nl);
205 
206 static kvm_t *kvmd;
207 #endif
208 static char *nlistf = NULL, *memf = NULL;
209 
210 int	Aflag;		/* show addresses of protocol control block */
211 int	aflag;		/* show all sockets (including servers) */
212 static int	Bflag;		/* show information about bpf consumers */
213 int	bflag;		/* show i/f total bytes in/out */
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 static int pflag;	/* show given protocol */
224 static int	Qflag;		/* show netisr information */
225 int	rflag;		/* show routing tables (or routing stats) */
226 int	Rflag;		/* show flow / RSS statistics */
227 int	sflag;		/* show protocol statistics */
228 int	Wflag;		/* wide display */
229 int	Tflag;		/* TCP Information */
230 int	xflag;		/* extra information, includes all socket buffer info */
231 int	zflag;		/* zero stats */
232 
233 int	interval;	/* repeat interval for i/f stats */
234 
235 char	*interface;	/* desired i/f for stats, or NULL for all i/fs */
236 int	unit;		/* unit number for above */
237 
238 static int	af;		/* address family */
239 int	live;		/* true if we are examining a live system */
240 
241 int
242 main(int argc, char *argv[])
243 {
244 	struct protox *tp = NULL;  /* for printing cblocks & stats */
245 	int ch;
246 	int fib = -1;
247 	char *endptr;
248 	bool first = true;
249 
250 #ifdef FSTACK
251 	ff_ipc_init();
252 #endif
253 
254 	af = AF_UNSPEC;
255 
256 	argc = xo_parse_args(argc, argv);
257 	if (argc < 0)
258 		exit(EXIT_FAILURE);
259 
260 #ifndef FSTACK
261 	while ((ch = getopt(argc, argv, "46AaBbdF:f:ghI:iLlM:mN:np:Qq:RrSTsuWw:xz"))
262 #else
263 	while ((ch = getopt(argc, argv, "46AaBbdF:f:ghI:iLlnp:Qq:RrSTsuWw:xzP:"))
264 #endif
265 	    != -1)
266 		switch(ch) {
267 		case '4':
268 #ifdef INET
269 			af = AF_INET;
270 #else
271 			errx(1, "IPv4 support is not compiled in");
272 #endif
273 			break;
274 		case '6':
275 #ifdef INET6
276 			af = AF_INET6;
277 #else
278 			errx(1, "IPv6 support is not compiled in");
279 #endif
280 			break;
281 		case 'A':
282 			Aflag = 1;
283 			break;
284 		case 'a':
285 			aflag = 1;
286 			break;
287 		case 'B':
288 			Bflag = 1;
289 			break;
290 		case 'b':
291 			bflag = 1;
292 			break;
293 		case 'd':
294 			dflag = 1;
295 			break;
296 		case 'F':
297 			fib = strtol(optarg, &endptr, 0);
298 			if (*endptr != '\0' ||
299 			    (fib == 0 && (errno == EINVAL || errno == ERANGE)))
300 				xo_errx(1, "%s: invalid fib", optarg);
301 			break;
302 		case 'f':
303 			if (strcmp(optarg, "inet") == 0)
304 				af = AF_INET;
305 #ifdef INET6
306 			else if (strcmp(optarg, "inet6") == 0)
307 				af = AF_INET6;
308 #endif
309 #ifdef IPSEC
310 			else if (strcmp(optarg, "pfkey") == 0)
311 				af = PF_KEY;
312 #endif
313 			else if (strcmp(optarg, "unix") == 0 ||
314 				 strcmp(optarg, "local") == 0)
315 				af = AF_UNIX;
316 #ifdef NETGRAPH
317 			else if (strcmp(optarg, "ng") == 0
318 			    || strcmp(optarg, "netgraph") == 0)
319 				af = AF_NETGRAPH;
320 #endif
321 			else if (strcmp(optarg, "link") == 0)
322 				af = AF_LINK;
323 			else {
324 				xo_errx(1, "%s: unknown address family",
325 				    optarg);
326 			}
327 			break;
328 		case 'g':
329 			gflag = 1;
330 			break;
331 		case 'h':
332 			hflag = 1;
333 			break;
334 		case 'I': {
335 			char *cp;
336 
337 			iflag = 1;
338 			for (cp = interface = optarg; isalpha(*cp); cp++)
339 				continue;
340 			unit = atoi(cp);
341 			break;
342 		}
343 		case 'i':
344 			iflag = 1;
345 			break;
346 		case 'L':
347 			Lflag = 1;
348 			break;
349 #ifndef FSTACK
350 		case 'M':
351 			memf = optarg;
352 			break;
353 		case 'm':
354 			mflag = 1;
355 			break;
356 		case 'N':
357 			nlistf = optarg;
358 			break;
359 #endif
360 		case 'n':
361 			numeric_addr = numeric_port = 1;
362 			break;
363 		case 'p':
364 			if ((tp = name2protox(optarg)) == NULL) {
365 				xo_errx(1, "%s: unknown or uninstrumented "
366 				    "protocol", optarg);
367 			}
368 			pflag = 1;
369 			break;
370 		case 'Q':
371 			Qflag = 1;
372 			break;
373 		case 'q':
374 			noutputs = atoi(optarg);
375 			if (noutputs != 0)
376 				noutputs++;
377 			break;
378 		case 'r':
379 			rflag = 1;
380 			break;
381 		case 'R':
382 			Rflag = 1;
383 			break;
384 		case 's':
385 			++sflag;
386 			break;
387 		case 'S':
388 			numeric_addr = 1;
389 			break;
390 		case 'u':
391 			af = AF_UNIX;
392 			break;
393 		case 'W':
394 		case 'l':
395 			Wflag = 1;
396 			break;
397 		case 'w':
398 			interval = atoi(optarg);
399 			iflag = 1;
400 			break;
401 		case 'T':
402 			Tflag = 1;
403 			break;
404 		case 'x':
405 			xflag = 1;
406 			break;
407 		case 'z':
408 			zflag = 1;
409 			break;
410 #ifdef FSTACK
411         case 'P':
412             ff_set_proc_id(atoi(optarg));
413             break;
414 #endif
415 		case '?':
416 		default:
417 			usage();
418 		}
419 	argv += optind;
420 	argc -= optind;
421 
422 #define	BACKWARD_COMPATIBILITY
423 #ifdef	BACKWARD_COMPATIBILITY
424 	if (*argv) {
425 		if (isdigit(**argv)) {
426 			interval = atoi(*argv);
427 			if (interval <= 0)
428 				usage();
429 			++argv;
430 			iflag = 1;
431 		}
432 		if (*argv) {
433 			nlistf = *argv;
434 			if (*++argv)
435 				memf = *argv;
436 		}
437 	}
438 #endif
439 
440 	/*
441 	 * Discard setgid privileges if not the running kernel so that bad
442 	 * guys can't print interesting stuff from kernel memory.
443 	 */
444 #ifndef FSTACK
445 	live = (nlistf == NULL && memf == NULL);
446 #else
447     live = 1;
448 #endif
449 	if (!live) {
450 		if (setgid(getgid()) != 0)
451 			xo_err(-1, "setgid");
452 	}
453 
454 	if (xflag && Tflag)
455 		xo_errx(1, "-x and -T are incompatible, pick one.");
456 
457 	if (Bflag) {
458 		if (!live)
459 			usage();
460 		bpf_stats(interface);
461 		xo_finish();
462 		exit(0);
463 	}
464 	if (mflag) {
465 		if (!live) {
466 #ifndef FSTACK
467 			if (kread(0, NULL, 0) == 0)
468 				mbpr(kvmd, nl[N_SFSTAT].n_value);
469 #endif
470 		} else
471 			mbpr(NULL, 0);
472 		xo_finish();
473 		exit(0);
474 	}
475 	if (Qflag) {
476 		if (!live) {
477 #ifndef FSTACK
478 			if (kread(0, NULL, 0) == 0)
479 				netisr_stats();
480 #endif
481 		} else
482 			netisr_stats();
483 		xo_finish();
484 		exit(0);
485 	}
486 
487 #if 0
488 	/*
489 	 * Keep file descriptors open to avoid overhead
490 	 * of open/close on each call to get* routines.
491 	 */
492 	sethostent(1);
493 	setnetent(1);
494 #else
495 	/*
496 	 * This does not make sense any more with DNS being default over
497 	 * the files.  Doing a setXXXXent(1) causes a tcp connection to be
498 	 * used for the queries, which is slower.
499 	 */
500 #endif
501 	if (iflag && !sflag) {
502 		xo_open_container("statistics");
503 		intpr(NULL, af);
504 		xo_close_container("statistics");
505 		xo_finish();
506 		exit(0);
507 	}
508 	if (rflag) {
509 		xo_open_container("statistics");
510 		if (sflag) {
511 			rt_stats();
512 			flowtable_stats();
513 		} else
514 			routepr(fib, af);
515 		xo_close_container("statistics");
516 		xo_finish();
517 		exit(0);
518 	}
519 
520 	if (gflag) {
521 		xo_open_container("statistics");
522 		if (sflag) {
523 			if (af == AF_INET || af == AF_UNSPEC)
524 				mrt_stats();
525 #ifdef INET6
526 			if (af == AF_INET6 || af == AF_UNSPEC)
527 				mrt6_stats();
528 #endif
529 		} else {
530 			if (af == AF_INET || af == AF_UNSPEC)
531 				mroutepr();
532 #ifdef INET6
533 			if (af == AF_INET6 || af == AF_UNSPEC)
534 				mroute6pr();
535 #endif
536 		}
537 		xo_close_container("statistics");
538 		xo_finish();
539 		exit(0);
540 	}
541 
542 #ifndef FSTACK
543 	/* Load all necessary kvm symbols */
544 	kresolve_list(nl);
545 #endif
546 
547 	if (tp) {
548 		xo_open_container("statistics");
549 		printproto(tp, tp->pr_name, &first);
550 		if (!first)
551 			xo_close_list("socket");
552 		xo_close_container("statistics");
553 		xo_finish();
554 		exit(0);
555 	}
556 
557 	xo_open_container("statistics");
558 	if (af == AF_INET || af == AF_UNSPEC)
559 		for (tp = protox; tp->pr_name; tp++)
560 			printproto(tp, tp->pr_name, &first);
561 #ifdef INET6
562 	if (af == AF_INET6 || af == AF_UNSPEC)
563 		for (tp = ip6protox; tp->pr_name; tp++)
564 			printproto(tp, tp->pr_name, &first);
565 #endif /*INET6*/
566 #ifdef IPSEC
567 	if (af == PF_KEY || af == AF_UNSPEC)
568 		for (tp = pfkeyprotox; tp->pr_name; tp++)
569 			printproto(tp, tp->pr_name, &first);
570 #endif /*IPSEC*/
571 #ifdef NETGRAPH
572 	if (af == AF_NETGRAPH || af == AF_UNSPEC)
573 		for (tp = netgraphprotox; tp->pr_name; tp++)
574 			printproto(tp, tp->pr_name, &first);
575 #endif /* NETGRAPH */
576 	if ((af == AF_UNIX || af == AF_UNSPEC) && !sflag)
577 		unixpr(nl[N_UNP_COUNT].n_value, nl[N_UNP_GENCNT].n_value,
578 		    nl[N_UNP_DHEAD].n_value, nl[N_UNP_SHEAD].n_value,
579 		    nl[N_UNP_SPHEAD].n_value, &first);
580 
581 	if (!first)
582 		xo_close_list("socket");
583 	xo_close_container("statistics");
584 	xo_finish();
585 	exit(0);
586 }
587 
588 static int
589 fetch_stats_internal(const char *sysctlname, u_long off, void *stats,
590     size_t len, kreadfn_t kreadfn, int zero)
591 {
592 	int error;
593 
594 	if (live) {
595 		memset(stats, 0, len);
596 		if (zero)
597 			error = sysctlbyname(sysctlname, NULL, NULL, stats,
598 			    len);
599 		else
600 			error = sysctlbyname(sysctlname, stats, &len, NULL, 0);
601 		if (error == -1 && errno != ENOENT)
602 			xo_warn("sysctl %s", sysctlname);
603 	} else {
604 		if (off == 0)
605 			return (1);
606 		error = kreadfn(off, stats, len);
607 	}
608 	return (error);
609 }
610 
611 int
612 fetch_stats(const char *sysctlname, u_long off, void *stats,
613     size_t len, kreadfn_t kreadfn)
614 {
615 
616 	return (fetch_stats_internal(sysctlname, off, stats, len, kreadfn,
617     zflag));
618 }
619 
620 int
621 fetch_stats_ro(const char *sysctlname, u_long off, void *stats,
622     size_t len, kreadfn_t kreadfn)
623 {
624 
625 	return (fetch_stats_internal(sysctlname, off, stats, len, kreadfn, 0));
626 }
627 
628 /*
629  * Print out protocol statistics or control blocks (per sflag).
630  * If the interface was not specifically requested, and the symbol
631  * is not in the namelist, ignore this one.
632  */
633 static void
634 printproto(struct protox *tp, const char *name, bool *first)
635 {
636 	void (*pr)(u_long, const char *, int, int);
637 	u_long off;
638 	bool doingdblocks = false;
639 
640 	if (sflag) {
641 		if (iflag) {
642 			if (tp->pr_istats)
643 				intpr(tp->pr_istats, af);
644 			else if (pflag)
645 				xo_message("%s: no per-interface stats routine",
646 				    tp->pr_name);
647 			return;
648 		} else {
649 			pr = tp->pr_stats;
650 			if (!pr) {
651 				if (pflag)
652 					xo_message("%s: no stats routine",
653 					    tp->pr_name);
654 				return;
655 			}
656 			if (tp->pr_usesysctl && live)
657 				off = 0;
658 			else if (tp->pr_sindex < 0) {
659 				if (pflag)
660 					xo_message("%s: stats routine doesn't "
661 					    "work on cores", tp->pr_name);
662 				return;
663 			} else
664 				off = nl[tp->pr_sindex].n_value;
665 		}
666 	} else {
667 		doingdblocks = true;
668 		pr = tp->pr_cblocks;
669 		if (!pr) {
670 			if (pflag)
671 				xo_message("%s: no PCB routine", tp->pr_name);
672 			return;
673 		}
674 		if (tp->pr_usesysctl && live)
675 			off = 0;
676 		else if (tp->pr_index < 0) {
677 			if (pflag)
678 				xo_message("%s: PCB routine doesn't work on "
679 				    "cores", tp->pr_name);
680 			return;
681 		} else
682 			off = nl[tp->pr_index].n_value;
683 	}
684 	if (pr != NULL && (off || (live && tp->pr_usesysctl) ||
685 	    af != AF_UNSPEC)) {
686 		if (doingdblocks && *first) {
687 			xo_open_list("socket");
688 			*first = false;
689 		}
690 
691 		(*pr)(off, name, af, tp->pr_protocol);
692 	}
693 }
694 
695 #ifndef FSTACK
696 static int
697 kvmd_init(void)
698 {
699 	char errbuf[_POSIX2_LINE_MAX];
700 
701 	if (kvmd != NULL)
702 		return (0);
703 
704 	kvmd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
705 	if (setgid(getgid()) != 0)
706 		xo_err(-1, "setgid");
707 
708 	if (kvmd == NULL) {
709 		xo_warnx("kvm not available: %s", errbuf);
710 		return (-1);
711 	}
712 
713 	return (0);
714 }
715 
716 /*
717  * Resolve symbol list, return 0 on success.
718  */
719 static int
720 kresolve_list(struct nlist *_nl)
721 {
722 
723 	if ((kvmd == NULL) && (kvmd_init() != 0))
724 		return (-1);
725 
726 	if (_nl[0].n_type != 0)
727 		return (0);
728 
729 	if (kvm_nlist(kvmd, _nl) < 0) {
730 		if (nlistf)
731 			xo_errx(1, "%s: kvm_nlist: %s", nlistf,
732 			    kvm_geterr(kvmd));
733 		else
734 			xo_errx(1, "kvm_nlist: %s", kvm_geterr(kvmd));
735 	}
736 
737 	return (0);
738 }
739 
740 /*
741  * Wrapper of kvm_dpcpu_setcpu().
742  */
743 void
744 kset_dpcpu(u_int cpuid)
745 {
746 
747 	if ((kvmd == NULL) && (kvmd_init() != 0))
748 		xo_errx(-1, "%s: kvm is not available", __func__);
749 
750 	if (kvm_dpcpu_setcpu(kvmd, cpuid) < 0)
751 		xo_errx(-1, "%s: kvm_dpcpu_setcpu(%u): %s", __func__,
752 		    cpuid, kvm_geterr(kvmd));
753 	return;
754 }
755 
756 /*
757  * Read kernel memory, return 0 on success.
758  */
759 int
760 kread(u_long addr, void *buf, size_t size)
761 {
762 
763 	if (kvmd_init() < 0)
764 		return (-1);
765 
766 	if (!buf)
767 		return (0);
768 	if (kvm_read(kvmd, addr, buf, size) != (ssize_t)size) {
769 		xo_warnx("%s", kvm_geterr(kvmd));
770 		return (-1);
771 	}
772 	return (0);
773 }
774 
775 /*
776  * Read single counter(9).
777  */
778 uint64_t
779 kread_counter(u_long addr)
780 {
781 
782 	if (kvmd_init() < 0)
783 		return (-1);
784 
785 	return (kvm_counter_u64_fetch(kvmd, addr));
786 }
787 
788 /*
789  * Read an array of N counters in kernel memory into array of N uint64_t's.
790  */
791 int
792 kread_counters(u_long addr, void *buf, size_t size)
793 {
794 	uint64_t *c;
795 	u_long *counters;
796 	size_t i, n;
797 
798 	if (kvmd_init() < 0)
799 		return (-1);
800 
801 	if (size % sizeof(uint64_t) != 0) {
802 		xo_warnx("kread_counters: invalid counter set size");
803 		return (-1);
804 	}
805 
806 	n = size / sizeof(uint64_t);
807 	if ((counters = malloc(n * sizeof(u_long))) == NULL)
808 		xo_err(-1, "malloc");
809 	if (kread(addr, counters, n * sizeof(u_long)) < 0) {
810 		free(counters);
811 		return (-1);
812 	}
813 
814 	c = buf;
815 	for (i = 0; i < n; i++)
816 		c[i] = kvm_counter_u64_fetch(kvmd, counters[i]);
817 
818 	free(counters);
819 	return (0);
820 }
821 
822 #else
823 int
824 kread(u_long addr, void *buf, size_t size)
825 {
826 	return 0;
827 }
828 
829 uint64_t
830 kread_counter(u_long addr)
831 {
832 	return 0;
833 }
834 
835 int
836 kread_counters(u_long addr, void *buf, size_t size)
837 {
838 	return 0;
839 }
840 void
841 kset_dpcpu(u_int cpuid)
842 {
843 
844 }
845 
846 #endif
847 
848 const char *
849 plural(uintmax_t n)
850 {
851 	return (n != 1 ? "s" : "");
852 }
853 
854 const char *
855 plurales(uintmax_t n)
856 {
857 	return (n != 1 ? "es" : "");
858 }
859 
860 const char *
861 pluralies(uintmax_t n)
862 {
863 	return (n != 1 ? "ies" : "y");
864 }
865 
866 /*
867  * Find the protox for the given "well-known" name.
868  */
869 static struct protox *
870 knownname(const char *name)
871 {
872 	struct protox **tpp, *tp;
873 
874 	for (tpp = protoprotox; *tpp; tpp++)
875 		for (tp = *tpp; tp->pr_name; tp++)
876 			if (strcmp(tp->pr_name, name) == 0)
877 				return (tp);
878 	return (NULL);
879 }
880 
881 /*
882  * Find the protox corresponding to name.
883  */
884 static struct protox *
885 name2protox(const char *name)
886 {
887 	struct protox *tp;
888 	char **alias;			/* alias from p->aliases */
889 	struct protoent *p;
890 
891 	/*
892 	 * Try to find the name in the list of "well-known" names. If that
893 	 * fails, check if name is an alias for an Internet protocol.
894 	 */
895 	if ((tp = knownname(name)) != NULL)
896 		return (tp);
897 
898 	setprotoent(1);			/* make protocol lookup cheaper */
899 	while ((p = getprotoent()) != NULL) {
900 		/* assert: name not same as p->name */
901 		for (alias = p->p_aliases; *alias; alias++)
902 			if (strcmp(name, *alias) == 0) {
903 				endprotoent();
904 				return (knownname(p->p_name));
905 			}
906 	}
907 	endprotoent();
908 	return (NULL);
909 }
910 
911 static void
912 usage(void)
913 {
914 	(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",
915 #ifndef FSTACK
916 "usage: netstat [-46AaLnRSTWx] [-f protocol_family | -p protocol]\n"
917 "               [-M core] [-N system]",
918 "       netstat -i | -I interface [-46abdhnW] [-f address_family]\n"
919 "               [-M core] [-N system]",
920 "       netstat -w wait [-I interface] [-46d] [-M core] [-N system]\n"
921 "               [-q howmany]",
922 "       netstat -s [-46sz] [-f protocol_family | -p protocol]\n"
923 "               [-M core] [-N system]",
924 "       netstat -i | -I interface -s [-46s]\n"
925 "               [-f protocol_family | -p protocol] [-M core] [-N system]",
926 "       netstat -m [-M core] [-N system]",
927 "       netstat -B [-z] [-I interface]",
928 "       netstat -r [-46AnW] [-F fibnum] [-f address_family]\n"
929 "               [-M core] [-N system]",
930 "       netstat -rs [-s] [-M core] [-N system]",
931 "       netstat -g [-46W] [-f address_family] [-M core] [-N system]",
932 "       netstat -gs [-46s] [-f address_family] [-M core] [-N system]",
933 "       netstat -Q");
934 #else
935 "usage: netstat -P <f-stack proc_id> [-46AaLnRSTWx] [-f protocol_family | -p protocol]",
936 "       netstat -P <f-stack proc_id> -i | -I interface [-46abdhnW] [-f address_family]",
937 "       netstat -P <f-stack proc_id> -w wait [-I interface] [-46d] [-q howmany]",
938 "       netstat -P <f-stack proc_id> -s [-46sz] [-f protocol_family | -p protocol]",
939 "       netstat -P <f-stack proc_id> -i | -I interface -s [-46s]\n"
940 "               [-f protocol_family | -p protocol]",
941 "       netstat -P <f-stack proc_id> -B [-z] [-I interface]",
942 "       netstat -P <f-stack proc_id> -r [-46AnW] [-F fibnum] [-f address_family]",
943 "       netstat -P <f-stack proc_id> -rs [-s]",
944 "       netstat -P <f-stack proc_id> -g [-46W] [-f address_family]",
945 "       netstat -P <f-stack proc_id> -gs [-46s] [-f address_family]",
946 "       netstat -P <f-stack proc_id> -Q");
947 
948 #endif
949 	xo_finish();
950 	exit(1);
951 }
952