1/*
2 * Copyright (c) 2008-2014 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28/*
29 * Copyright (c) 1983, 1988, 1993
30 *	Regents of the University of California.  All rights reserved.
31 *
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
34 * are met:
35 * 1. Redistributions of source code must retain the above copyright
36 *    notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 *    notice, this list of conditions and the following disclaimer in the
39 *    documentation and/or other materials provided with the distribution.
40 * 3. All advertising materials mentioning features or use of this software
41 *    must display the following acknowledgement:
42 *	This product includes software developed by the University of
43 *	California, Berkeley and its contributors.
44 * 4. Neither the name of the University nor the names of its contributors
45 *    may be used to endorse or promote products derived from this software
46 *    without specific prior written permission.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
59 */
60
61#ifndef lint
62char const copyright[] =
63"@(#) Copyright (c) 1983, 1988, 1993\n\
64	Regents of the University of California.  All rights reserved.\n";
65#endif /* not lint */
66
67#include <sys/param.h>
68#include <sys/file.h>
69#include <sys/socket.h>
70#include <sys/sys_domain.h>
71
72#include <netinet/in.h>
73#include <net/pfkeyv2.h>
74
75#include <ctype.h>
76#include <err.h>
77#include <errno.h>
78#include <limits.h>
79#include <netdb.h>
80#include <nlist.h>
81#include <paths.h>
82#include <stdio.h>
83#include <stdlib.h>
84#include <string.h>
85#include <unistd.h>
86#include "netstat.h"
87#include <sys/types.h>
88#include <sys/sysctl.h>
89
90#ifdef __APPLE__
91#include <TargetConditionals.h>
92#endif
93
94/*
95 * ----------------------------------------------------------------------------
96 * "THE BEER-WARE LICENSE" (Revision 42):
97 * <phk@FreeBSD.org> wrote this file.  As long as you retain this notice you
98 * can do whatever you want with this stuff. If we meet some day, and you think
99 * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
100 * ----------------------------------------------------------------------------
101 *
102 * $Id: main.c,v 1.8 2004/10/14 22:24:09 lindak Exp $
103 *
104 */
105
106struct protox {
107	void	(*pr_cblocks)(uint32_t, char *, int);
108					/* control blocks printing routine */
109	void	(*pr_stats)(uint32_t, char *, int);
110					/* statistics printing routine */
111	void	(*pr_istats)(char *);	/* per/if statistics printing routine */
112	char	*pr_name;		/* well-known name */
113	int	pr_protocol;
114} protox[] = {
115	{ protopr,	tcp_stats,	NULL,	"tcp",	IPPROTO_TCP },
116	{ protopr,	udp_stats,	NULL,	"udp",	IPPROTO_UDP },
117	{ protopr,	NULL,		NULL,	"divert", IPPROTO_DIVERT },
118	{ protopr,	ip_stats,	NULL,	"ip",	IPPROTO_RAW },
119	{ protopr,	icmp_stats,	NULL,	"icmp",	IPPROTO_ICMP },
120	{ protopr,	igmp_stats,	NULL,	"igmp",	IPPROTO_IGMP },
121#ifdef IPSEC
122	{ NULL,		ipsec_stats,	NULL,	"ipsec", IPPROTO_ESP},
123#endif
124	{ NULL,		arp_stats,	NULL,	"arp",	0 },
125	{ mptcppr,	mptcp_stats,	NULL,	"mptcp", IPPROTO_TCP },
126	{ NULL,		NULL,		NULL,	NULL,	0 }
127};
128
129#ifdef INET6
130struct protox ip6protox[] = {
131	{ protopr,	tcp_stats,	NULL,	"tcp",	IPPROTO_TCP },
132	{ protopr,	udp_stats,	NULL,	"udp",	IPPROTO_UDP },
133	{ protopr,	ip6_stats,	ip6_ifstats,	"ip6",	IPPROTO_RAW },
134	{ protopr,	icmp6_stats,	icmp6_ifstats,	"icmp6",IPPROTO_ICMPV6 },
135#ifdef IPSEC
136	{ NULL,		ipsec_stats,	NULL,	"ipsec6", IPPROTO_ESP },
137#endif
138	{ NULL,		rip6_stats,	NULL,	"rip6",	IPPROTO_RAW },
139	{ mptcppr,	mptcp_stats,	NULL,	"mptcp", IPPROTO_TCP },
140	{ NULL,		NULL,		NULL,	NULL,	0 }
141};
142#endif /*INET6*/
143
144#ifdef IPSEC
145struct protox pfkeyprotox[] = {
146	{ NULL,		pfkey_stats,	NULL,	"pfkey", PF_KEY_V2 },
147	{ NULL,		NULL,		NULL,	NULL,	0 }
148};
149#endif
150
151
152struct protox systmprotox[] = {
153	{ systmpr,	NULL,		NULL,	"reg", 0 },
154	{ systmpr,	kevt_stats,		NULL,	"kevt", SYSPROTO_EVENT },
155	{ systmpr,	kctl_stats,	NULL,	"kctl", SYSPROTO_CONTROL },
156	{ NULL,		NULL,		NULL,	NULL,	0 }
157};
158
159struct protox *protoprotox[] = {
160	protox,
161#ifdef INET6
162	ip6protox,
163#endif
164#ifdef IPSEC
165	pfkeyprotox,
166#endif
167	systmprotox,
168	NULL
169};
170
171static void printproto (struct protox *, char *);
172static void usage (void);
173static struct protox *name2protox (char *);
174static struct protox *knownname (char *);
175#ifdef SRVCACHE
176extern void _serv_cache_close();
177#endif
178
179int	Aflag;		/* show addresses of protocol control block */
180int	aflag;		/* show all sockets (including servers) */
181int	bflag;		/* show i/f total bytes in/out */
182int	cflag;		/* show specific classq */
183int	dflag;		/* show i/f dropped packets */
184int	Fflag;		/* show i/f forwarded packets */
185#if defined(__APPLE__)
186int	gflag;		/* show group (multicast) routing or stats */
187#endif
188int	iflag;		/* show interfaces */
189int	lflag;		/* show routing table with use and ref */
190int	Lflag;		/* show size of listen queues */
191int	mflag;		/* show memory stats */
192int	nflag;		/* show addresses numerically */
193static int pflag;	/* show given protocol */
194int	prioflag = -1;	/* show packet priority statistics */
195int	Rflag;		/* show reachability information */
196int	rflag;		/* show routing tables (or routing stats) */
197int	sflag;		/* show protocol statistics */
198int	tflag;		/* show i/f watchdog timers */
199int	vflag;		/* more verbose */
200int	Wflag;		/* wide display */
201int	qflag;		/* classq stats display */
202int	Qflag;		/* opportunistic polling stats display */
203int	xflag;		/* show extended link-layer reachability information */
204
205int	cq = -1;	/* send classq index (-1 for all) */
206int	interval;	/* repeat interval for i/f stats */
207
208char	*interface;	/* desired i/f for stats, or NULL for all i/fs */
209int	unit;		/* unit number for above */
210
211int	af;		/* address family */
212
213int
214main(argc, argv)
215	int argc;
216	char *argv[];
217{
218	register struct protox *tp = NULL;  /* for printing cblocks & stats */
219	int ch;
220
221	af = AF_UNSPEC;
222
223	while ((ch = getopt(argc, argv, "Aabc:dFf:gI:iLlmnP:p:qQrRstuvWw:x")) != -1)
224		switch(ch) {
225		case 'A':
226			Aflag = 1;
227			break;
228		case 'a':
229			aflag = 1;
230			break;
231		case 'b':
232			bflag = 1;
233			break;
234		case 'c':
235			cflag = 1;
236			cq = atoi(optarg);
237			break;
238		case 'd':
239			dflag = 1;
240			break;
241		case 'F':
242			Fflag = 1;
243			break;
244		case 'f':
245			if (strcmp(optarg, "ipx") == 0)
246				af = AF_IPX;
247			else if (strcmp(optarg, "inet") == 0)
248				af = AF_INET;
249#ifdef INET6
250			else if (strcmp(optarg, "inet6") == 0)
251				af = AF_INET6;
252#endif /*INET6*/
253#ifdef INET6
254			else if (strcmp(optarg, "pfkey") == 0)
255				af = PF_KEY;
256#endif /*INET6*/
257                        else if (strcmp(optarg, "unix") == 0)
258                                af = AF_UNIX;
259                        else if (strcmp(optarg, "systm") == 0)
260                                af = AF_SYSTEM;
261			else {
262				errx(1, "%s: unknown address family", optarg);
263			}
264			break;
265#if defined(__APPLE__)
266		case 'g':
267			gflag = 1;
268			break;
269#endif
270		case 'I': {
271			char *cp;
272
273			iflag = 1;
274			for (cp = interface = optarg; isalpha(*cp); cp++)
275				continue;
276			unit = atoi(cp);
277			break;
278		}
279		case 'i':
280			iflag = 1;
281			break;
282		case 'l':
283			lflag = 1;
284			break;
285		case 'L':
286			Lflag = 1;
287			break;
288		case 'm':
289			mflag++;
290			break;
291		case 'n':
292			nflag = 1;
293			break;
294		case 'P':
295			prioflag = atoi(optarg);
296			break;
297		case 'p':
298			if ((tp = name2protox(optarg)) == NULL) {
299				errx(1,
300				     "%s: unknown or uninstrumented protocol",
301				     optarg);
302			}
303			pflag = 1;
304			break;
305		case 'q':
306			qflag++;
307			break;
308		case 'Q':
309			Qflag++;
310			break;
311		case 'R':
312			Rflag = 1;
313			break;
314		case 'r':
315			rflag = 1;
316			break;
317		case 's':
318			++sflag;
319			break;
320		case 't':
321			tflag = 1;
322			break;
323		case 'u':
324			af = AF_UNIX;
325			break;
326		case 'v':
327			vflag++;
328			break;
329		case 'W':
330			Wflag = 1;
331			break;
332		case 'w':
333			interval = atoi(optarg);
334			iflag = 1;
335			break;
336		case 'x':
337			xflag = 1;
338			Rflag = 1;
339			break;
340		case '?':
341		default:
342			usage();
343		}
344	argv += optind;
345	argc -= optind;
346
347#define	BACKWARD_COMPATIBILITY
348#ifdef	BACKWARD_COMPATIBILITY
349	if (*argv) {
350		if (isdigit(**argv)) {
351			interval = atoi(*argv);
352			if (interval <= 0)
353				usage();
354			++argv;
355			iflag = 1;
356		}
357	}
358#endif
359
360	if (mflag) {
361		mbpr();
362		exit(0);
363	}
364	if (iflag && !sflag && !gflag && !qflag && !Qflag) {
365		if (Rflag)
366			intpr_ri(NULL);
367		else
368			intpr(NULL);
369		exit(0);
370	}
371	if (rflag) {
372		if (sflag)
373			rt_stats();
374		else
375			routepr();
376		exit(0);
377	}
378	if (qflag || Qflag) {
379		if (interface == NULL) {
380			fprintf(stderr, "%s statistics option "
381			    "requires interface name\n", qflag ? "Queue" :
382			    "Polling");
383		} else if (qflag) {
384			aqstatpr();
385		} else {
386			rxpollstatpr();
387		}
388		exit(0);
389	}
390
391#if defined(__APPLE__)
392	if (gflag) {
393		ifmalist_dump();
394		exit(0);
395	}
396#endif
397
398	if (tp) {
399		printproto(tp, tp->pr_name);
400		exit(0);
401	}
402	if (af == AF_INET || af == AF_UNSPEC)
403		for (tp = protox; tp->pr_name; tp++)
404			printproto(tp, tp->pr_name);
405#ifdef INET6
406	if (af == AF_INET6 || af == AF_UNSPEC)
407		for (tp = ip6protox; tp->pr_name; tp++)
408			printproto(tp, tp->pr_name);
409#endif /*INET6*/
410#ifdef IPSEC
411	if (af == PF_KEY || af == AF_UNSPEC)
412		for (tp = pfkeyprotox; tp->pr_name; tp++)
413			printproto(tp, tp->pr_name);
414#endif /*IPSEC*/
415	if ((af == AF_UNIX || af == AF_UNSPEC) && !Lflag && !sflag)
416		unixpr();
417
418	if ((af == AF_SYSTEM || af == AF_UNSPEC) && !Lflag)
419		for (tp = systmprotox; tp->pr_name; tp++)
420			printproto(tp, tp->pr_name);
421
422#ifdef SRVCACHE
423	_serv_cache_close();
424#endif
425	exit(0);
426}
427
428/*
429 * Print out protocol statistics or control blocks (per sflag).
430 * If the interface was not specifically requested, and the symbol
431 * is not in the namelist, ignore this one.
432 */
433static void
434printproto(tp, name)
435	register struct protox *tp;
436	char *name;
437{
438	void (*pr)(uint32_t, char *, int);
439	uint32_t off;
440
441	if (sflag) {
442		if (iflag && !pflag) {
443			if (tp->pr_istats)
444				intpr(tp->pr_istats);
445			else if (vflag)
446				printf("%s: no per-interface stats routine\n",
447				    tp->pr_name);
448			return;
449		}
450		else {
451			pr = tp->pr_stats;
452			if (!pr) {
453				if (pflag && vflag)
454					printf("%s: no stats routine\n",
455					    tp->pr_name);
456				return;
457			}
458			off = tp->pr_protocol;
459		}
460	} else {
461		pr = tp->pr_cblocks;
462		if (!pr) {
463			if (pflag && vflag)
464				printf("%s: no PCB routine\n", tp->pr_name);
465			return;
466		}
467		off = tp->pr_protocol;
468	}
469	if (pr != NULL) {
470		if (sflag && iflag && pflag)
471			intervalpr(pr, off, name, af);
472		else
473			(*pr)(off, name, af);
474	} else {
475		printf("### no stats for %s\n", name);
476	}
477}
478
479char *
480plural(int n)
481{
482	return (n != 1 ? "s" : "");
483}
484
485char *
486plurales(int n)
487{
488	return (n != 1 ? "es" : "");
489}
490
491char *
492pluralies(int n)
493{
494	return (n != 1 ? "ies" : "y");
495}
496
497/*
498 * Find the protox for the given "well-known" name.
499 */
500static struct protox *
501knownname(char *name)
502{
503	struct protox **tpp, *tp;
504
505	for (tpp = protoprotox; *tpp; tpp++)
506		for (tp = *tpp; tp->pr_name; tp++)
507			if (strcmp(tp->pr_name, name) == 0)
508				return (tp);
509	return (NULL);
510}
511
512/*
513 * Find the protox corresponding to name.
514 */
515static struct protox *
516name2protox(char *name)
517{
518	struct protox *tp;
519	char **alias;			/* alias from p->aliases */
520	struct protoent *p;
521
522	/*
523	 * Try to find the name in the list of "well-known" names. If that
524	 * fails, check if name is an alias for an Internet protocol.
525	 */
526	if ((tp = knownname(name)) != NULL)
527		return (tp);
528
529	setprotoent(1);			/* make protocol lookup cheaper */
530	while ((p = getprotoent()) != NULL) {
531		/* assert: name not same as p->name */
532		for (alias = p->p_aliases; *alias; alias++)
533			if (strcmp(name, *alias) == 0) {
534				endprotoent();
535				return (knownname(p->p_name));
536			}
537	}
538	endprotoent();
539	return (NULL);
540}
541
542#define	NETSTAT_USAGE "\
543Usage:	netstat [-AaLlnW] [-f address_family | -p protocol]\n\
544	netstat [-gilns] [-f address_family]\n\
545	netstat -i | -I interface [-w wait] [-abdgRt]\n\
546	netstat -s [-s] [-f address_family | -p protocol] [-w wait]\n\
547	netstat -i | -I interface -s [-f address_family | -p protocol]\n\
548	netstat -m [-m]\n\
549	netstat -r [-Aaln] [-f address_family]\n\
550	netstat -rs [-s]\n\
551"
552
553static void
554usage(void)
555{
556	(void) fprintf(stderr, "%s\n", NETSTAT_USAGE);
557	exit(1);
558}
559
560int
561print_time(void)
562{
563    time_t now;
564    struct tm tm;
565    int num_written = 0;
566
567    (void) time(&now);
568    (void) localtime_r(&now, &tm);
569
570    num_written += printf("%02d:%02d:%02d ", tm.tm_hour, tm.tm_min, tm.tm_sec);
571
572    return (num_written);
573}
574
575