main.c revision 263335
1189251Ssam/*-
2252726Srpaulo * Copyright (c) 1983, 1988, 1993
3252726Srpaulo *	Regents of the University of California.  All rights reserved.
4189251Ssam *
5252726Srpaulo * Redistribution and use in source and binary forms, with or without
6252726Srpaulo * modification, are permitted provided that the following conditions
7189251Ssam * are met:
8189251Ssam * 1. Redistributions of source code must retain the above copyright
9189251Ssam *    notice, this list of conditions and the following disclaimer.
10189251Ssam * 2. Redistributions in binary form must reproduce the above copyright
11189251Ssam *    notice, this list of conditions and the following disclaimer in the
12214734Srpaulo *    documentation and/or other materials provided with the distribution.
13214734Srpaulo * 4. Neither the name of the University nor the names of its contributors
14189251Ssam *    may be used to endorse or promote products derived from this software
15189251Ssam *    without specific prior written permission.
16189251Ssam *
17189251Ssam * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18189251Ssam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19189251Ssam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20189251Ssam * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21189251Ssam * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22189251Ssam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23189251Ssam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24189251Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25189251Ssam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26189251Ssam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27189251Ssam * SUCH DAMAGE.
28189251Ssam */
29189251Ssam
30189251Ssam#ifndef lint
31189251Ssamchar const copyright[] =
32189251Ssam"@(#) Copyright (c) 1983, 1988, 1993\n\
33189251Ssam	Regents of the University of California.  All rights reserved.\n";
34189251Ssam#endif /* not lint */
35189251Ssam
36189251Ssam#if 0
37189251Ssam#ifndef lint
38189251Ssamstatic char sccsid[] = "@(#)main.c	8.4 (Berkeley) 3/1/94";
39189251Ssam#endif /* not lint */
40189251Ssam#endif
41189251Ssam
42189251Ssam#include <sys/cdefs.h>
43189251Ssam__FBSDID("$FreeBSD: stable/10/usr.bin/netstat/main.c 263335 2014-03-19 09:36:29Z glebius $");
44189251Ssam
45189251Ssam#include <sys/param.h>
46252726Srpaulo#include <sys/file.h>
47252726Srpaulo#include <sys/protosw.h>
48189251Ssam#include <sys/socket.h>
49189251Ssam#include <sys/socketvar.h>
50189251Ssam
51189251Ssam#include <netinet/in.h>
52189251Ssam
53189251Ssam#ifdef NETGRAPH
54189251Ssam#include <netgraph/ng_socket.h>
55189251Ssam#endif
56189251Ssam
57189251Ssam#include <ctype.h>
58189251Ssam#include <err.h>
59189251Ssam#include <errno.h>
60189251Ssam#include <kvm.h>
61189251Ssam#include <limits.h>
62252726Srpaulo#include <netdb.h>
63252726Srpaulo#include <nlist.h>
64189251Ssam#include <paths.h>
65189251Ssam#include <stdint.h>
66189251Ssam#include <stdio.h>
67189251Ssam#include <stdlib.h>
68189251Ssam#include <string.h>
69189251Ssam#include <unistd.h>
70189251Ssam#include "netstat.h"
71189251Ssam
72189251Ssamstatic struct nlist nl[] = {
73189251Ssam#define	N_IFNET		0
74189251Ssam	{ .n_name = "_ifnet" },		/* XXXGL: can be deleted */
75189251Ssam#define	N_RTSTAT	1
76189251Ssam	{ .n_name = "_rtstat" },
77189251Ssam#define	N_RTREE		2
78189251Ssam	{ .n_name = "_rt_tables"},
79189251Ssam#define	N_MRTSTAT	3
80189251Ssam	{ .n_name = "_mrtstat" },
81189251Ssam#define	N_MFCHASHTBL	4
82189251Ssam	{ .n_name = "_mfchashtbl" },
83189251Ssam#define	N_VIFTABLE	5
84189251Ssam	{ .n_name = "_viftable" },
85189251Ssam#define	N_IPX		6
86189251Ssam	{ .n_name = "_ipxpcb_list"},
87189251Ssam#define	N_IPXSTAT	7
88189251Ssam	{ .n_name = "_ipxstat"},
89189251Ssam#define	N_SPXSTAT	8
90189251Ssam	{ .n_name = "_spx_istat"},
91189251Ssam#define	N_DDPSTAT	9
92189251Ssam	{ .n_name = "_ddpstat"},
93189251Ssam#define	N_DDPCB		10
94189251Ssam	{ .n_name = "_ddpcb"},
95189251Ssam#define	N_NGSOCKS	11
96189251Ssam	{ .n_name = "_ngsocklist"},
97189251Ssam#define	N_IP6STAT	12
98189251Ssam	{ .n_name = "_ip6stat" },
99189251Ssam#define	N_ICMP6STAT	13
100189251Ssam	{ .n_name = "_icmp6stat" },
101189251Ssam#define	N_IPSECSTAT	14
102189251Ssam	{ .n_name = "_ipsec4stat" },
103189251Ssam#define	N_IPSEC6STAT	15
104189251Ssam	{ .n_name = "_ipsec6stat" },
105189251Ssam#define	N_PIM6STAT	16
106189251Ssam	{ .n_name = "_pim6stat" },
107189251Ssam#define	N_MRT6STAT	17
108189251Ssam	{ .n_name = "_mrt6stat" },
109189251Ssam#define	N_MF6CTABLE	18
110189251Ssam	{ .n_name = "_mf6ctable" },
111189251Ssam#define	N_MIF6TABLE	19
112189251Ssam	{ .n_name = "_mif6table" },
113189251Ssam#define	N_PFKEYSTAT	20
114252726Srpaulo	{ .n_name = "_pfkeystat" },
115189251Ssam#define	N_RTTRASH	21
116189251Ssam	{ .n_name = "_rttrash" },
117189251Ssam#define	N_CARPSTAT	22
118189251Ssam	{ .n_name = "_carpstats" },
119189251Ssam#define	N_PFSYNCSTAT	23
120189251Ssam	{ .n_name = "_pfsyncstats" },
121189251Ssam#define	N_AHSTAT	24
122189251Ssam	{ .n_name = "_ahstat" },
123189251Ssam#define	N_ESPSTAT	25
124189251Ssam	{ .n_name = "_espstat" },
125189251Ssam#define	N_IPCOMPSTAT	26
126189251Ssam	{ .n_name = "_ipcompstat" },
127189251Ssam#define	N_TCPSTAT	27
128189251Ssam	{ .n_name = "_tcpstat" },
129189251Ssam#define	N_UDPSTAT	28
130252726Srpaulo	{ .n_name = "_udpstat" },
131252726Srpaulo#define	N_IPSTAT	29
132252726Srpaulo	{ .n_name = "_ipstat" },
133189251Ssam#define	N_ICMPSTAT	30
134189251Ssam	{ .n_name = "_icmpstat" },
135189251Ssam#define	N_IGMPSTAT	31
136189251Ssam	{ .n_name = "_igmpstat" },
137189251Ssam#define	N_PIMSTAT	32
138252726Srpaulo	{ .n_name = "_pimstat" },
139252726Srpaulo#define	N_TCBINFO	33
140252726Srpaulo	{ .n_name = "_tcbinfo" },
141252726Srpaulo#define	N_UDBINFO	34
142252726Srpaulo	{ .n_name = "_udbinfo" },
143252726Srpaulo#define	N_DIVCBINFO	35
144252726Srpaulo	{ .n_name = "_divcbinfo" },
145189251Ssam#define	N_RIPCBINFO	36
146189251Ssam	{ .n_name = "_ripcbinfo" },
147189251Ssam#define	N_UNP_COUNT	37
148189251Ssam	{ .n_name = "_unp_count" },
149189251Ssam#define	N_UNP_GENCNT	38
150189251Ssam	{ .n_name = "_unp_gencnt" },
151189251Ssam#define	N_UNP_DHEAD	39
152189251Ssam	{ .n_name = "_unp_dhead" },
153189251Ssam#define	N_UNP_SHEAD	40
154189251Ssam	{ .n_name = "_unp_shead" },
155189251Ssam#define	N_RIP6STAT	41
156189251Ssam	{ .n_name = "_rip6stat" },
157189251Ssam#define	N_SCTPSTAT	42
158189251Ssam	{ .n_name = "_sctpstat" },
159189251Ssam#define	N_MFCTABLESIZE	43
160252726Srpaulo	{ .n_name = "_mfctablesize" },
161189251Ssam#define	N_ARPSTAT       44
162189251Ssam	{ .n_name = "_arpstat" },
163189251Ssam#define	N_UNP_SPHEAD	45
164189251Ssam	{ .n_name = "unp_sphead" },
165189251Ssam#define	N_SFSTAT	46
166189251Ssam	{ .n_name = "_sfstat"},
167189251Ssam	{ .n_name = NULL },
168189251Ssam};
169189251Ssam
170189251Ssamstruct protox {
171189251Ssam	int	pr_index;		/* index into nlist of cb head */
172189251Ssam	int	pr_sindex;		/* index into nlist of stat block */
173189251Ssam	u_char	pr_wanted;		/* 1 if wanted, 0 otherwise */
174189251Ssam	void	(*pr_cblocks)(u_long, const char *, int, int);
175189251Ssam					/* control blocks printing routine */
176189251Ssam	void	(*pr_stats)(u_long, const char *, int, int);
177189251Ssam					/* statistics printing routine */
178189251Ssam	void	(*pr_istats)(char *);	/* per/if statistics printing routine */
179189251Ssam	const char	*pr_name;		/* well-known name */
180189251Ssam	int	pr_usesysctl;		/* non-zero if we use sysctl, not kvm */
181189251Ssam	int	pr_protocol;
182189251Ssam} protox[] = {
183189251Ssam	{ N_TCBINFO,	N_TCPSTAT,	1,	protopr,
184189251Ssam	  tcp_stats,	NULL,		"tcp",	1,	IPPROTO_TCP },
185189251Ssam	{ N_UDBINFO,	N_UDPSTAT,	1,	protopr,
186189251Ssam	  udp_stats,	NULL,		"udp",	1,	IPPROTO_UDP },
187189251Ssam#ifdef SCTP
188189251Ssam	{ -1,		N_SCTPSTAT,	1,	sctp_protopr,
189189251Ssam	  sctp_stats,	NULL,		"sctp",	1,	IPPROTO_SCTP },
190189251Ssam#endif
191189251Ssam#ifdef SDP
192189251Ssam	{ -1,		-1,		1,	protopr,
193189251Ssam	 NULL,		NULL,		"sdp",	1,	IPPROTO_TCP },
194189251Ssam#endif
195189251Ssam	{ N_DIVCBINFO,	-1,		1,	protopr,
196189251Ssam	  NULL,		NULL,		"divert", 1,	IPPROTO_DIVERT },
197189251Ssam	{ N_RIPCBINFO,	N_IPSTAT,	1,	protopr,
198189251Ssam	  ip_stats,	NULL,		"ip",	1,	IPPROTO_RAW },
199189251Ssam	{ N_RIPCBINFO,	N_ICMPSTAT,	1,	protopr,
200189251Ssam	  icmp_stats,	NULL,		"icmp",	1,	IPPROTO_ICMP },
201189251Ssam	{ N_RIPCBINFO,	N_IGMPSTAT,	1,	protopr,
202189251Ssam	  igmp_stats,	NULL,		"igmp",	1,	IPPROTO_IGMP },
203189251Ssam#ifdef IPSEC
204189251Ssam	{ -1,		N_IPSECSTAT,	1,	NULL,	/* keep as compat */
205189251Ssam	  ipsec_stats,	NULL,		"ipsec", 0,	0},
206189251Ssam	{ -1,		N_AHSTAT,	1,	NULL,
207189251Ssam	  ah_stats,	NULL,		"ah",	0,	0},
208189251Ssam	{ -1,		N_ESPSTAT,	1,	NULL,
209189251Ssam	  esp_stats,	NULL,		"esp",	0,	0},
210252726Srpaulo	{ -1,		N_IPCOMPSTAT,	1,	NULL,
211189251Ssam	  ipcomp_stats,	NULL,		"ipcomp", 0,	0},
212189251Ssam#endif
213189251Ssam	{ N_RIPCBINFO,	N_PIMSTAT,	1,	protopr,
214189251Ssam	  pim_stats,	NULL,		"pim",	1,	IPPROTO_PIM },
215189251Ssam	{ -1,		N_CARPSTAT,	1,	NULL,
216189251Ssam	  carp_stats,	NULL,		"carp",	1,	0 },
217189251Ssam#ifdef PF
218189251Ssam	{ -1,		N_PFSYNCSTAT,	1,	NULL,
219189251Ssam	  pfsync_stats,	NULL,		"pfsync", 1,	0 },
220189251Ssam#endif
221189251Ssam	{ -1,		N_ARPSTAT,	1,	NULL,
222189251Ssam	  arp_stats,	NULL,		"arp", 1,	0 },
223189251Ssam	{ -1,		-1,		0,	NULL,
224189251Ssam	  NULL,		NULL,		NULL,	0,	0 }
225189251Ssam};
226189251Ssam
227189251Ssam#ifdef INET6
228189251Ssamstruct protox ip6protox[] = {
229189251Ssam	{ N_TCBINFO,	N_TCPSTAT,	1,	protopr,
230189251Ssam	  tcp_stats,	NULL,		"tcp",	1,	IPPROTO_TCP },
231189251Ssam	{ N_UDBINFO,	N_UDPSTAT,	1,	protopr,
232189251Ssam	  udp_stats,	NULL,		"udp",	1,	IPPROTO_UDP },
233189251Ssam	{ N_RIPCBINFO,	N_IP6STAT,	1,	protopr,
234189251Ssam	  ip6_stats,	ip6_ifstats,	"ip6",	1,	IPPROTO_RAW },
235189251Ssam	{ N_RIPCBINFO,	N_ICMP6STAT,	1,	protopr,
236189251Ssam	  icmp6_stats,	icmp6_ifstats,	"icmp6", 1,	IPPROTO_ICMPV6 },
237189251Ssam#ifdef SDP
238252726Srpaulo	{ -1,		-1,		1,	protopr,
239252726Srpaulo	 NULL,		NULL,		"sdp",	1,	IPPROTO_TCP },
240189251Ssam#endif
241189251Ssam#ifdef IPSEC
242189251Ssam	{ -1,		N_IPSEC6STAT,	1,	NULL,
243189251Ssam	  ipsec_stats,	NULL,		"ipsec6", 0,	0 },
244189251Ssam#endif
245189251Ssam#ifdef notyet
246189251Ssam	{ -1,		N_PIM6STAT,	1,	NULL,
247189251Ssam	  pim6_stats,	NULL,		"pim6",	1,	0 },
248252726Srpaulo#endif
249252726Srpaulo	{ -1,		N_RIP6STAT,	1,	NULL,
250252726Srpaulo	  rip6_stats,	NULL,		"rip6",	1,	0 },
251252726Srpaulo	{ -1,		-1,		0,	NULL,
252252726Srpaulo	  NULL,		NULL,		NULL,	0,	0 }
253252726Srpaulo};
254252726Srpaulo#endif /*INET6*/
255252726Srpaulo
256252726Srpaulo#ifdef IPSEC
257252726Srpaulostruct protox pfkeyprotox[] = {
258252726Srpaulo	{ -1,		N_PFKEYSTAT,	1,	NULL,
259252726Srpaulo	  pfkey_stats,	NULL,		"pfkey", 0,	0 },
260252726Srpaulo	{ -1,		-1,		0,	NULL,
261252726Srpaulo	  NULL,		NULL,		NULL,	0,	0 }
262252726Srpaulo};
263252726Srpaulo#endif
264252726Srpaulo
265252726Srpaulostruct protox atalkprotox[] = {
266252726Srpaulo	{ N_DDPCB,	N_DDPSTAT,	1,	atalkprotopr,
267252726Srpaulo	  ddp_stats,	NULL,		"ddp",	0,	0 },
268252726Srpaulo	{ -1,		-1,		0,	NULL,
269252726Srpaulo	  NULL,		NULL,		NULL,	0,	0 }
270252726Srpaulo};
271252726Srpaulo#ifdef NETGRAPH
272252726Srpaulostruct protox netgraphprotox[] = {
273252726Srpaulo	{ N_NGSOCKS,	-1,		1,	netgraphprotopr,
274252726Srpaulo	  NULL,		NULL,		"ctrl",	0,	0 },
275252726Srpaulo	{ N_NGSOCKS,	-1,		1,	netgraphprotopr,
276252726Srpaulo	  NULL,		NULL,		"data",	0,	0 },
277252726Srpaulo	{ -1,		-1,		0,	NULL,
278252726Srpaulo	  NULL,		NULL,		NULL,	0,	0 }
279252726Srpaulo};
280252726Srpaulo#endif
281252726Srpaulo#ifdef IPX
282252726Srpaulostruct protox ipxprotox[] = {
283252726Srpaulo	{ N_IPX,	N_IPXSTAT,	1,	ipxprotopr,
284252726Srpaulo	  ipx_stats,	NULL,		"ipx",	0,	0 },
285252726Srpaulo	{ N_IPX,	N_SPXSTAT,	1,	ipxprotopr,
286252726Srpaulo	  spx_stats,	NULL,		"spx",	0,	0 },
287252726Srpaulo	{ -1,		-1,		0,	NULL,
288189251Ssam	  NULL,		NULL,		0,	0,	0 }
289189251Ssam};
290189251Ssam#endif
291189251Ssam
292189251Ssamstruct protox *protoprotox[] = {
293189251Ssam					 protox,
294189251Ssam#ifdef INET6
295189251Ssam					 ip6protox,
296189251Ssam#endif
297189251Ssam#ifdef IPSEC
298189251Ssam					 pfkeyprotox,
299189251Ssam#endif
300189251Ssam#ifdef IPX
301189251Ssam					 ipxprotox,
302189251Ssam#endif
303189251Ssam					 atalkprotox, NULL };
304252726Srpaulo
305189251Ssamstatic void printproto(struct protox *, const char *);
306189251Ssamstatic void usage(void);
307189251Ssamstatic struct protox *name2protox(const char *);
308189251Ssamstatic struct protox *knownname(const char *);
309189251Ssam
310189251Ssamstatic kvm_t *kvmd;
311189251Ssamstatic char *nlistf = NULL, *memf = NULL;
312189251Ssam
313189251Ssamint	Aflag;		/* show addresses of protocol control block */
314189251Ssamint	aflag;		/* show all sockets (including servers) */
315189251Ssamint	Bflag;		/* show information about bpf consumers */
316189251Ssamint	bflag;		/* show i/f total bytes in/out */
317189251Ssamint	dflag;		/* show i/f dropped packets */
318189251Ssamint	gflag;		/* show group (multicast) routing or stats */
319189251Ssamint	hflag;		/* show counters in human readable format */
320189251Ssamint	iflag;		/* show interfaces */
321189251Ssamint	Lflag;		/* show size of listen queues */
322189251Ssamint	mflag;		/* show memory stats */
323189251Ssamint	noutputs = 0;	/* how much outputs before we exit */
324189251Ssamint	numeric_addr;	/* show addresses numerically */
325189251Ssamint	numeric_port;	/* show ports numerically */
326189251Ssamstatic int pflag;	/* show given protocol */
327189251Ssamint	Qflag;		/* show netisr information */
328189251Ssamint	rflag;		/* show routing tables (or routing stats) */
329189251Ssamint	sflag;		/* show protocol statistics */
330189251Ssamint	Wflag;		/* wide display */
331189251Ssamint	Tflag;		/* TCP Information */
332189251Ssamint	xflag;		/* extra information, includes all socket buffer info */
333189251Ssamint	zflag;		/* zero stats */
334189251Ssam
335189251Ssamint	interval;	/* repeat interval for i/f stats */
336189251Ssam
337189251Ssamchar	*interface;	/* desired i/f for stats, or NULL for all i/fs */
338189251Ssamint	unit;		/* unit number for above */
339189251Ssam
340189251Ssamint	af;		/* address family */
341189251Ssamint	live;		/* true if we are examining a live system */
342189251Ssam
343189251Ssamint
344189251Ssammain(int argc, char *argv[])
345189251Ssam{
346189251Ssam	struct protox *tp = NULL;  /* for printing cblocks & stats */
347189251Ssam	int ch;
348189251Ssam	int fib = -1;
349189251Ssam	char *endptr;
350189251Ssam
351189251Ssam	af = AF_UNSPEC;
352189251Ssam
353189251Ssam	while ((ch = getopt(argc, argv, "AaBbdF:f:ghI:iLlM:mN:np:Qq:rSTsuWw:xz"))
354189251Ssam	    != -1)
355189251Ssam		switch(ch) {
356189251Ssam		case 'A':
357189251Ssam			Aflag = 1;
358189251Ssam			break;
359189251Ssam		case 'a':
360189251Ssam			aflag = 1;
361189251Ssam			break;
362189251Ssam		case 'B':
363189251Ssam			Bflag = 1;
364189251Ssam			break;
365189251Ssam		case 'b':
366189251Ssam			bflag = 1;
367189251Ssam			break;
368189251Ssam		case 'd':
369189251Ssam			dflag = 1;
370189251Ssam			break;
371189251Ssam		case 'F':
372189251Ssam			fib = strtol(optarg, &endptr, 0);
373189251Ssam			if (*endptr != '\0' ||
374189251Ssam			    (fib == 0 && (errno == EINVAL || errno == ERANGE)))
375189251Ssam				errx(1, "%s: invalid fib", optarg);
376189251Ssam			break;
377189251Ssam		case 'f':
378189251Ssam			if (strcmp(optarg, "ipx") == 0)
379189251Ssam				af = AF_IPX;
380189251Ssam			else if (strcmp(optarg, "inet") == 0)
381189251Ssam				af = AF_INET;
382189251Ssam#ifdef INET6
383189251Ssam			else if (strcmp(optarg, "inet6") == 0)
384189251Ssam				af = AF_INET6;
385189251Ssam#endif
386189251Ssam#ifdef IPSEC
387189251Ssam			else if (strcmp(optarg, "pfkey") == 0)
388189251Ssam				af = PF_KEY;
389189251Ssam#endif
390189251Ssam			else if (strcmp(optarg, "unix") == 0)
391189251Ssam				af = AF_UNIX;
392189251Ssam			else if (strcmp(optarg, "atalk") == 0)
393189251Ssam				af = AF_APPLETALK;
394189251Ssam#ifdef NETGRAPH
395189251Ssam			else if (strcmp(optarg, "ng") == 0
396189251Ssam			    || strcmp(optarg, "netgraph") == 0)
397189251Ssam				af = AF_NETGRAPH;
398189251Ssam#endif
399189251Ssam			else if (strcmp(optarg, "link") == 0)
400189251Ssam				af = AF_LINK;
401189251Ssam			else {
402189251Ssam				errx(1, "%s: unknown address family", optarg);
403189251Ssam			}
404189251Ssam			break;
405189251Ssam		case 'g':
406189251Ssam			gflag = 1;
407189251Ssam			break;
408189251Ssam		case 'h':
409189251Ssam			hflag = 1;
410189251Ssam			break;
411189251Ssam		case 'I': {
412189251Ssam			char *cp;
413189251Ssam
414189251Ssam			iflag = 1;
415189251Ssam			for (cp = interface = optarg; isalpha(*cp); cp++)
416189251Ssam				continue;
417189251Ssam			unit = atoi(cp);
418189251Ssam			break;
419189251Ssam		}
420189251Ssam		case 'i':
421189251Ssam			iflag = 1;
422189251Ssam			break;
423189251Ssam		case 'L':
424189251Ssam			Lflag = 1;
425189251Ssam			break;
426189251Ssam		case 'M':
427189251Ssam			memf = optarg;
428189251Ssam			break;
429189251Ssam		case 'm':
430189251Ssam			mflag = 1;
431189251Ssam			break;
432189251Ssam		case 'N':
433189251Ssam			nlistf = optarg;
434189251Ssam			break;
435189251Ssam		case 'n':
436189251Ssam			numeric_addr = numeric_port = 1;
437189251Ssam			break;
438189251Ssam		case 'p':
439189251Ssam			if ((tp = name2protox(optarg)) == NULL) {
440189251Ssam				errx(1,
441189251Ssam				     "%s: unknown or uninstrumented protocol",
442189251Ssam				     optarg);
443189251Ssam			}
444189251Ssam			pflag = 1;
445189251Ssam			break;
446252726Srpaulo		case 'Q':
447252726Srpaulo			Qflag = 1;
448189251Ssam			break;
449189251Ssam		case 'q':
450189251Ssam			noutputs = atoi(optarg);
451189251Ssam			if (noutputs != 0)
452189251Ssam				noutputs++;
453189251Ssam			break;
454189251Ssam		case 'r':
455189251Ssam			rflag = 1;
456189251Ssam			break;
457189251Ssam		case 's':
458189251Ssam			++sflag;
459189251Ssam			break;
460189251Ssam		case 'S':
461189251Ssam			numeric_addr = 1;
462189251Ssam			break;
463189251Ssam		case 'u':
464189251Ssam			af = AF_UNIX;
465189251Ssam			break;
466189251Ssam		case 'W':
467189251Ssam		case 'l':
468189251Ssam			Wflag = 1;
469189251Ssam			break;
470189251Ssam		case 'w':
471189251Ssam			interval = atoi(optarg);
472189251Ssam			iflag = 1;
473189251Ssam			break;
474189251Ssam		case 'T':
475189251Ssam			Tflag = 1;
476189251Ssam			break;
477189251Ssam		case 'x':
478189251Ssam			xflag = 1;
479189251Ssam			break;
480189251Ssam		case 'z':
481189251Ssam			zflag = 1;
482189251Ssam			break;
483189251Ssam		case '?':
484189251Ssam		default:
485189251Ssam			usage();
486189251Ssam		}
487189251Ssam	argv += optind;
488189251Ssam	argc -= optind;
489189251Ssam
490189251Ssam#define	BACKWARD_COMPATIBILITY
491189251Ssam#ifdef	BACKWARD_COMPATIBILITY
492189251Ssam	if (*argv) {
493189251Ssam		if (isdigit(**argv)) {
494189251Ssam			interval = atoi(*argv);
495189251Ssam			if (interval <= 0)
496189251Ssam				usage();
497189251Ssam			++argv;
498189251Ssam			iflag = 1;
499189251Ssam		}
500189251Ssam		if (*argv) {
501189251Ssam			nlistf = *argv;
502189251Ssam			if (*++argv)
503189251Ssam				memf = *argv;
504189251Ssam		}
505189251Ssam	}
506189251Ssam#endif
507189251Ssam
508189251Ssam	/*
509189251Ssam	 * Discard setgid privileges if not the running kernel so that bad
510189251Ssam	 * guys can't print interesting stuff from kernel memory.
511189251Ssam	 */
512189251Ssam	live = (nlistf == NULL && memf == NULL);
513189251Ssam	if (!live)
514189251Ssam		setgid(getgid());
515189251Ssam
516189251Ssam	if (xflag && Tflag)
517189251Ssam		errx(1, "-x and -T are incompatible, pick one.");
518189251Ssam
519189251Ssam	if (Bflag) {
520189251Ssam		if (!live)
521189251Ssam			usage();
522189251Ssam		bpf_stats(interface);
523189251Ssam		exit(0);
524189251Ssam	}
525189251Ssam	if (mflag) {
526189251Ssam		if (!live) {
527189251Ssam			if (kread(0, NULL, 0) == 0)
528189251Ssam				mbpr(kvmd, nl[N_SFSTAT].n_value);
529189251Ssam		} else
530189251Ssam			mbpr(NULL, 0);
531189251Ssam		exit(0);
532189251Ssam	}
533189251Ssam	if (Qflag) {
534189251Ssam		if (!live) {
535189251Ssam			if (kread(0, NULL, 0) == 0)
536189251Ssam				netisr_stats(kvmd);
537189251Ssam		} else
538189251Ssam			netisr_stats(NULL);
539189251Ssam		exit(0);
540189251Ssam	}
541189251Ssam#if 0
542189251Ssam	/*
543189251Ssam	 * Keep file descriptors open to avoid overhead
544189251Ssam	 * of open/close on each call to get* routines.
545189251Ssam	 */
546189251Ssam	sethostent(1);
547189251Ssam	setnetent(1);
548189251Ssam#else
549189251Ssam	/*
550189251Ssam	 * This does not make sense any more with DNS being default over
551189251Ssam	 * the files.  Doing a setXXXXent(1) causes a tcp connection to be
552189251Ssam	 * used for the queries, which is slower.
553189251Ssam	 */
554189251Ssam#endif
555189251Ssam	if (iflag && !sflag) {
556189251Ssam		intpr(interval, NULL, af);
557189251Ssam		exit(0);
558189251Ssam	}
559189251Ssam	if (rflag) {
560189251Ssam		if (sflag) {
561189251Ssam			rt_stats();
562189251Ssam			flowtable_stats();
563189251Ssam		} else
564189251Ssam			routepr(fib, af);
565189251Ssam		exit(0);
566189251Ssam	}
567189251Ssam
568189251Ssam	if (gflag) {
569189251Ssam		if (sflag) {
570189251Ssam			if (af == AF_INET || af == AF_UNSPEC)
571189251Ssam				mrt_stats();
572189251Ssam#ifdef INET6
573189251Ssam			if (af == AF_INET6 || af == AF_UNSPEC)
574189251Ssam				mrt6_stats();
575189251Ssam#endif
576189251Ssam		} else {
577189251Ssam			if (af == AF_INET || af == AF_UNSPEC)
578189251Ssam				mroutepr();
579189251Ssam#ifdef INET6
580189251Ssam			if (af == AF_INET6 || af == AF_UNSPEC)
581189251Ssam				mroute6pr();
582189251Ssam#endif
583189251Ssam		}
584189251Ssam		exit(0);
585189251Ssam	}
586189251Ssam
587189251Ssam	/* Load all necessary kvm symbols */
588189251Ssam	kresolve_list(nl);
589189251Ssam
590189251Ssam	if (tp) {
591189251Ssam		printproto(tp, tp->pr_name);
592189251Ssam		exit(0);
593189251Ssam	}
594189251Ssam	if (af == AF_INET || af == AF_UNSPEC)
595189251Ssam		for (tp = protox; tp->pr_name; tp++)
596189251Ssam			printproto(tp, tp->pr_name);
597189251Ssam#ifdef INET6
598189251Ssam	if (af == AF_INET6 || af == AF_UNSPEC)
599189251Ssam		for (tp = ip6protox; tp->pr_name; tp++)
600189251Ssam			printproto(tp, tp->pr_name);
601189251Ssam#endif /*INET6*/
602189251Ssam#ifdef IPSEC
603189251Ssam	if (af == PF_KEY || af == AF_UNSPEC)
604189251Ssam		for (tp = pfkeyprotox; tp->pr_name; tp++)
605189251Ssam			printproto(tp, tp->pr_name);
606189251Ssam#endif /*IPSEC*/
607189251Ssam#ifdef IPX
608189251Ssam	if (af == AF_IPX || af == AF_UNSPEC) {
609189251Ssam		for (tp = ipxprotox; tp->pr_name; tp++)
610189251Ssam			printproto(tp, tp->pr_name);
611189251Ssam	}
612189251Ssam#endif /* IPX */
613189251Ssam	if (af == AF_APPLETALK || af == AF_UNSPEC)
614189251Ssam		for (tp = atalkprotox; tp->pr_name; tp++)
615189251Ssam			printproto(tp, tp->pr_name);
616189251Ssam#ifdef NETGRAPH
617189251Ssam	if (af == AF_NETGRAPH || af == AF_UNSPEC)
618189251Ssam		for (tp = netgraphprotox; tp->pr_name; tp++)
619189251Ssam			printproto(tp, tp->pr_name);
620189251Ssam#endif /* NETGRAPH */
621	if ((af == AF_UNIX || af == AF_UNSPEC) && !sflag)
622		unixpr(nl[N_UNP_COUNT].n_value, nl[N_UNP_GENCNT].n_value,
623		    nl[N_UNP_DHEAD].n_value, nl[N_UNP_SHEAD].n_value,
624		    nl[N_UNP_SPHEAD].n_value);
625	exit(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 */
633static void
634printproto(struct protox *tp, const char *name)
635{
636	void (*pr)(u_long, const char *, int, int);
637	u_long off;
638
639	if (sflag) {
640		if (iflag) {
641			if (tp->pr_istats)
642				intpr(interval, tp->pr_istats, af);
643			else if (pflag)
644				printf("%s: no per-interface stats routine\n",
645				    tp->pr_name);
646			return;
647		} else {
648			pr = tp->pr_stats;
649			if (!pr) {
650				if (pflag)
651					printf("%s: no stats routine\n",
652					    tp->pr_name);
653				return;
654			}
655			if (tp->pr_usesysctl && live)
656				off = 0;
657			else if (tp->pr_sindex < 0) {
658				if (pflag)
659					printf(
660				    "%s: stats routine doesn't work on cores\n",
661					    tp->pr_name);
662				return;
663			} else
664				off = nl[tp->pr_sindex].n_value;
665		}
666	} else {
667		pr = tp->pr_cblocks;
668		if (!pr) {
669			if (pflag)
670				printf("%s: no PCB routine\n", tp->pr_name);
671			return;
672		}
673		if (tp->pr_usesysctl && live)
674			off = 0;
675		else if (tp->pr_index < 0) {
676			if (pflag)
677				printf(
678				    "%s: PCB routine doesn't work on cores\n",
679				    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		(*pr)(off, name, af, tp->pr_protocol);
687}
688
689static int
690kvmd_init(void)
691{
692	char errbuf[_POSIX2_LINE_MAX];
693
694	if (kvmd != NULL)
695		return (0);
696
697	kvmd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
698	setgid(getgid());
699
700	if (kvmd == NULL) {
701		warnx("kvm not available: %s", errbuf);
702		return (-1);
703	}
704
705	return (0);
706}
707
708/*
709 * Resolve symbol list, return 0 on success.
710 */
711int
712kresolve_list(struct nlist *_nl)
713{
714
715	if ((kvmd == NULL) && (kvmd_init() != 0))
716		return (-1);
717
718	if (_nl[0].n_type != 0)
719		return (0);
720
721	if (kvm_nlist(kvmd, _nl) < 0) {
722		if (nlistf)
723			errx(1, "%s: kvm_nlist: %s", nlistf,
724			     kvm_geterr(kvmd));
725		else
726			errx(1, "kvm_nlist: %s", kvm_geterr(kvmd));
727	}
728
729	return (0);
730}
731
732/*
733 * Read kernel memory, return 0 on success.
734 */
735int
736kread(u_long addr, void *buf, size_t size)
737{
738
739	if (kvmd_init() < 0)
740		return (-1);
741
742	if (!buf)
743		return (0);
744	if (kvm_read(kvmd, addr, buf, size) != (ssize_t)size) {
745		warnx("%s", kvm_geterr(kvmd));
746		return (-1);
747	}
748	return (0);
749}
750
751/*
752 * Read an array of N counters in kernel memory into array of N uint64_t's.
753 */
754int
755kread_counters(u_long addr, void *buf, size_t size)
756{
757	uint64_t *c = buf;
758
759	if (kvmd_init() < 0)
760		return (-1);
761
762	if (kread(addr, buf, size) < 0)
763		return (-1);
764
765	while (size != 0) {
766		*c = kvm_counter_u64_fetch(kvmd, *c);
767		size -= sizeof(*c);
768		c++;
769	}
770	return (0);
771}
772
773const char *
774plural(uintmax_t n)
775{
776	return (n != 1 ? "s" : "");
777}
778
779const char *
780plurales(uintmax_t n)
781{
782	return (n != 1 ? "es" : "");
783}
784
785const char *
786pluralies(uintmax_t n)
787{
788	return (n != 1 ? "ies" : "y");
789}
790
791/*
792 * Find the protox for the given "well-known" name.
793 */
794static struct protox *
795knownname(const char *name)
796{
797	struct protox **tpp, *tp;
798
799	for (tpp = protoprotox; *tpp; tpp++)
800		for (tp = *tpp; tp->pr_name; tp++)
801			if (strcmp(tp->pr_name, name) == 0)
802				return (tp);
803	return (NULL);
804}
805
806/*
807 * Find the protox corresponding to name.
808 */
809static struct protox *
810name2protox(const char *name)
811{
812	struct protox *tp;
813	char **alias;			/* alias from p->aliases */
814	struct protoent *p;
815
816	/*
817	 * Try to find the name in the list of "well-known" names. If that
818	 * fails, check if name is an alias for an Internet protocol.
819	 */
820	if ((tp = knownname(name)) != NULL)
821		return (tp);
822
823	setprotoent(1);			/* make protocol lookup cheaper */
824	while ((p = getprotoent()) != NULL) {
825		/* assert: name not same as p->name */
826		for (alias = p->p_aliases; *alias; alias++)
827			if (strcmp(name, *alias) == 0) {
828				endprotoent();
829				return (knownname(p->p_name));
830			}
831	}
832	endprotoent();
833	return (NULL);
834}
835
836static void
837usage(void)
838{
839	(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",
840"usage: netstat [-AaLnSTWx] [-f protocol_family | -p protocol]\n"
841"               [-M core] [-N system]",
842"       netstat -i | -I interface [-abdhnW] [-f address_family]\n"
843"               [-M core] [-N system]",
844"       netstat -w wait [-I interface] [-d] [-M core] [-N system] [-q howmany]",
845"       netstat -s [-s] [-z] [-f protocol_family | -p protocol]\n"
846"               [-M core] [-N system]",
847"       netstat -i | -I interface -s [-f protocol_family | -p protocol]\n"
848"               [-M core] [-N system]",
849"       netstat -m [-M core] [-N system]",
850"       netstat -B [-I interface]",
851"       netstat -r [-AanW] [-f address_family] [-M core] [-N system]",
852"       netstat -rs [-s] [-M core] [-N system]",
853"       netstat -g [-W] [-f address_family] [-M core] [-N system]",
854"       netstat -gs [-s] [-f address_family] [-M core] [-N system]",
855"       netstat -Q");
856	exit(1);
857}
858