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