1/*
2 * Copyright (c) 2008-2013 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
71#include <netinet/in.h>
72#include <net/pfkeyv2.h>
73
74#include <ctype.h>
75#include <err.h>
76#include <errno.h>
77#include <limits.h>
78#include <netdb.h>
79#include <nlist.h>
80#include <paths.h>
81#include <stdio.h>
82#include <stdlib.h>
83#include <string.h>
84#include <unistd.h>
85#include "netstat.h"
86#include <sys/types.h>
87#include <sys/sysctl.h>
88
89#ifdef __APPLE__
90#include <TargetConditionals.h>
91#endif
92
93/*
94 * ----------------------------------------------------------------------------
95 * "THE BEER-WARE LICENSE" (Revision 42):
96 * <phk@FreeBSD.org> wrote this file.  As long as you retain this notice you
97 * can do whatever you want with this stuff. If we meet some day, and you think
98 * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
99 * ----------------------------------------------------------------------------
100 *
101 * $Id: main.c,v 1.8 2004/10/14 22:24:09 lindak Exp $
102 *
103 */
104
105struct protox {
106	void	(*pr_cblocks)(uint32_t, char *, int);
107					/* control blocks printing routine */
108	void	(*pr_stats)(uint32_t, char *, int);
109					/* statistics printing routine */
110	void	(*pr_istats)(char *);	/* per/if statistics printing routine */
111	char	*pr_name;		/* well-known name */
112	int	pr_protocol;
113} protox[] = {
114	{ protopr,	tcp_stats,	NULL,	"tcp",	IPPROTO_TCP },
115	{ protopr,	udp_stats,	NULL,	"udp",	IPPROTO_UDP },
116	{ protopr,	NULL,		NULL,	"divert", IPPROTO_DIVERT },
117	{ protopr,	ip_stats,	NULL,	"ip",	IPPROTO_RAW },
118	{ protopr,	icmp_stats,	NULL,	"icmp",	IPPROTO_ICMP },
119	{ protopr,	igmp_stats,	NULL,	"igmp",	IPPROTO_IGMP },
120#ifdef IPSEC
121	{ NULL,		ipsec_stats,	NULL,	"ipsec", IPPROTO_ESP},
122#endif
123	{ NULL,		arp_stats,	NULL,	"arp",	0 },
124#if TARGET_OS_EMBEDDED
125	{ mptcppr,	mptcp_stats,	NULL,	"mptcp", IPPROTO_TCP },
126#endif
127	{ NULL,		NULL,		NULL,	NULL,	0 }
128};
129
130#ifdef INET6
131struct protox ip6protox[] = {
132	{ protopr,	tcp_stats,	NULL,	"tcp",	IPPROTO_TCP },
133	{ protopr,	udp_stats,	NULL,	"udp",	IPPROTO_UDP },
134	{ protopr,	ip6_stats,	ip6_ifstats,	"ip6",	IPPROTO_RAW },
135	{ protopr,	icmp6_stats,	icmp6_ifstats,	"icmp6",IPPROTO_ICMPV6 },
136#ifdef IPSEC
137	{ NULL,		ipsec_stats,	NULL,	"ipsec6", IPPROTO_ESP },
138#endif
139#ifdef notyet
140	{ NULL,		pim6_stats,	NULL,	"pim6",	0 },
141#endif
142	{ NULL,		rip6_stats,	NULL,	"rip6",	IPPROTO_RAW },
143#if TARGET_OS_EMBEDDED
144	{ mptcppr,	mptcp_stats,	NULL,	"mptcp", IPPROTO_TCP },
145#endif
146	{ NULL,		NULL,		NULL,	NULL,	0 }
147};
148#endif /*INET6*/
149
150#ifdef IPSEC
151struct protox pfkeyprotox[] = {
152	{ NULL,		pfkey_stats,	NULL,	"pfkey", PF_KEY_V2 },
153	{ NULL,		NULL,		NULL,	NULL,	0 }
154};
155#endif
156
157struct protox *protoprotox[] = {
158	protox,
159#ifdef INET6
160	ip6protox,
161#endif
162#ifdef IPSEC
163	pfkeyprotox,
164#endif
165	NULL
166};
167
168static void printproto (struct protox *, char *);
169static void usage (void);
170static struct protox *name2protox (char *);
171static struct protox *knownname (char *);
172#ifdef SRVCACHE
173extern void _serv_cache_close();
174#endif
175
176int	Aflag;		/* show addresses of protocol control block */
177int	aflag;		/* show all sockets (including servers) */
178int	bflag;		/* show i/f total bytes in/out */
179int	cflag;		/* show specific classq */
180int	dflag;		/* show i/f dropped packets */
181int	Fflag;		/* show i/f forwarded packets */
182#if defined(__APPLE__)
183int	gflag;		/* show group (multicast) routing or stats */
184#endif
185int	iflag;		/* show interfaces */
186int	lflag;		/* show routing table with use and ref */
187int	Lflag;		/* show size of listen queues */
188int	mflag;		/* show memory stats */
189int	nflag;		/* show addresses numerically */
190static int pflag;	/* show given protocol */
191int	prioflag = -1;	/* show packet priority statistics */
192int	Rflag;		/* show reachability information */
193int	rflag;		/* show routing tables (or routing stats) */
194int	sflag;		/* show protocol statistics */
195int	tflag;		/* show i/f watchdog timers */
196int	vflag;		/* more verbose */
197int	Wflag;		/* wide display */
198int	qflag;		/* classq stats display */
199int	Qflag;		/* opportunistic polling stats display */
200int	xflag;		/* show extended link-layer reachability information */
201
202int	cq = -1;	/* send classq index (-1 for all) */
203int	interval;	/* repeat interval for i/f stats */
204
205char	*interface;	/* desired i/f for stats, or NULL for all i/fs */
206int	unit;		/* unit number for above */
207
208int	af;		/* address family */
209
210int
211main(argc, argv)
212	int argc;
213	char *argv[];
214{
215	register struct protox *tp = NULL;  /* for printing cblocks & stats */
216	int ch;
217
218	af = AF_UNSPEC;
219
220	while ((ch = getopt(argc, argv, "Aabc:dFf:gI:iLlmnP:p:qQrRstuvWw:x")) != -1)
221		switch(ch) {
222		case 'A':
223			Aflag = 1;
224			break;
225		case 'a':
226			aflag = 1;
227			break;
228		case 'b':
229			bflag = 1;
230			break;
231		case 'c':
232			cflag = 1;
233			cq = atoi(optarg);
234			break;
235		case 'd':
236			dflag = 1;
237			break;
238		case 'F':
239			Fflag = 1;
240			break;
241		case 'f':
242			if (strcmp(optarg, "ipx") == 0)
243				af = AF_IPX;
244			else if (strcmp(optarg, "inet") == 0)
245				af = AF_INET;
246#ifdef INET6
247			else if (strcmp(optarg, "inet6") == 0)
248				af = AF_INET6;
249#endif /*INET6*/
250#ifdef INET6
251			else if (strcmp(optarg, "pfkey") == 0)
252				af = PF_KEY;
253#endif /*INET6*/
254			else if (strcmp(optarg, "unix") == 0)
255				af = AF_UNIX;
256			else {
257				errx(1, "%s: unknown address family", optarg);
258			}
259			break;
260#if defined(__APPLE__)
261		case 'g':
262			gflag = 1;
263			break;
264#endif
265		case 'I': {
266			char *cp;
267
268			iflag = 1;
269			for (cp = interface = optarg; isalpha(*cp); cp++)
270				continue;
271			unit = atoi(cp);
272			break;
273		}
274		case 'i':
275			iflag = 1;
276			break;
277		case 'l':
278			lflag = 1;
279			break;
280		case 'L':
281			Lflag = 1;
282			break;
283		case 'm':
284			mflag++;
285			break;
286		case 'n':
287			nflag = 1;
288			break;
289		case 'P':
290			prioflag = atoi(optarg);
291			break;
292		case 'p':
293			if ((tp = name2protox(optarg)) == NULL) {
294				errx(1,
295				     "%s: unknown or uninstrumented protocol",
296				     optarg);
297			}
298			pflag = 1;
299			break;
300		case 'q':
301			qflag++;
302			break;
303		case 'Q':
304			Qflag++;
305			break;
306		case 'R':
307			Rflag = 1;
308			break;
309		case 'r':
310			rflag = 1;
311			break;
312		case 's':
313			++sflag;
314			break;
315		case 't':
316			tflag = 1;
317			break;
318		case 'u':
319			af = AF_UNIX;
320			break;
321		case 'v':
322			vflag++;
323			break;
324		case 'W':
325			Wflag = 1;
326			break;
327		case 'w':
328			interval = atoi(optarg);
329			iflag = 1;
330			break;
331		case 'x':
332			xflag = 1;
333			Rflag = 1;
334			break;
335		case '?':
336		default:
337			usage();
338		}
339	argv += optind;
340	argc -= optind;
341
342#define	BACKWARD_COMPATIBILITY
343#ifdef	BACKWARD_COMPATIBILITY
344	if (*argv) {
345		if (isdigit(**argv)) {
346			interval = atoi(*argv);
347			if (interval <= 0)
348				usage();
349			++argv;
350			iflag = 1;
351		}
352	}
353#endif
354
355	if (mflag) {
356		mbpr();
357		exit(0);
358	}
359	if (iflag && !sflag && !gflag && !qflag && !Qflag) {
360		if (Rflag)
361			intpr_ri(NULL);
362		else
363			intpr(NULL);
364		exit(0);
365	}
366	if (rflag) {
367		if (sflag)
368			rt_stats();
369		else
370			routepr();
371		exit(0);
372	}
373	if (qflag || Qflag) {
374		if (interface == NULL) {
375			fprintf(stderr, "%s statistics option "
376			    "requires interface name\n", qflag ? "Queue" :
377			    "Polling");
378		} else if (qflag) {
379			aqstatpr();
380		} else {
381			rxpollstatpr();
382		}
383		exit(0);
384	}
385
386#if defined(__APPLE__)
387	if (gflag) {
388#if !TARGET_OS_EMBEDDED
389		if (sflag) {
390			if (af == AF_INET || af == AF_UNSPEC)
391				mrt_stats();
392#ifdef INET6
393			if (af == AF_INET6 || af == AF_UNSPEC)
394				mrt6_stats();
395#endif
396		} else {
397			if (af == AF_INET || af == AF_UNSPEC)
398				mroutepr();
399#ifdef INET6
400			if (af == AF_INET6 || af == AF_UNSPEC)
401				mroute6pr();
402#endif
403		}
404#endif /* !TARGET_OS_EMBEDDED */
405		ifmalist_dump();
406		exit(0);
407	}
408#endif
409
410	if (tp) {
411		printproto(tp, tp->pr_name);
412		exit(0);
413	}
414	if (af == AF_INET || af == AF_UNSPEC)
415		for (tp = protox; tp->pr_name; tp++)
416			printproto(tp, tp->pr_name);
417#ifdef INET6
418	if (af == AF_INET6 || af == AF_UNSPEC)
419		for (tp = ip6protox; tp->pr_name; tp++)
420			printproto(tp, tp->pr_name);
421#endif /*INET6*/
422#ifdef IPSEC
423	if (af == PF_KEY || af == AF_UNSPEC)
424		for (tp = pfkeyprotox; tp->pr_name; tp++)
425			printproto(tp, tp->pr_name);
426#endif /*IPSEC*/
427	if ((af == AF_UNIX || af == AF_UNSPEC) && !Lflag && !sflag)
428		unixpr();
429#ifdef SRVCACHE
430	_serv_cache_close();
431#endif
432	exit(0);
433}
434
435/*
436 * Print out protocol statistics or control blocks (per sflag).
437 * If the interface was not specifically requested, and the symbol
438 * is not in the namelist, ignore this one.
439 */
440static void
441printproto(tp, name)
442	register struct protox *tp;
443	char *name;
444{
445	void (*pr)(uint32_t, char *, int);
446	uint32_t off;
447
448	if (sflag) {
449		if (iflag && !pflag) {
450			if (tp->pr_istats)
451				intpr(tp->pr_istats);
452			else if (vflag)
453				printf("%s: no per-interface stats routine\n",
454				    tp->pr_name);
455			return;
456		}
457		else {
458			pr = tp->pr_stats;
459			if (!pr) {
460				if (pflag && vflag)
461					printf("%s: no stats routine\n",
462					    tp->pr_name);
463				return;
464			}
465			off = tp->pr_protocol;
466		}
467	} else {
468		pr = tp->pr_cblocks;
469		if (!pr) {
470			if (pflag && vflag)
471				printf("%s: no PCB routine\n", tp->pr_name);
472			return;
473		}
474		off = tp->pr_protocol;
475	}
476	if (pr != NULL) {
477		if (sflag && iflag && pflag)
478			intervalpr(pr, off, name, af);
479		else
480			(*pr)(off, name, af);
481	} else {
482		printf("### no stats for %s\n", name);
483	}
484}
485
486char *
487plural(int n)
488{
489	return (n != 1 ? "s" : "");
490}
491
492char *
493plurales(int n)
494{
495	return (n != 1 ? "es" : "");
496}
497
498char *
499pluralies(int n)
500{
501	return (n != 1 ? "ies" : "y");
502}
503
504/*
505 * Find the protox for the given "well-known" name.
506 */
507static struct protox *
508knownname(char *name)
509{
510	struct protox **tpp, *tp;
511
512	for (tpp = protoprotox; *tpp; tpp++)
513		for (tp = *tpp; tp->pr_name; tp++)
514			if (strcmp(tp->pr_name, name) == 0)
515				return (tp);
516	return (NULL);
517}
518
519/*
520 * Find the protox corresponding to name.
521 */
522static struct protox *
523name2protox(char *name)
524{
525	struct protox *tp;
526	char **alias;			/* alias from p->aliases */
527	struct protoent *p;
528
529	/*
530	 * Try to find the name in the list of "well-known" names. If that
531	 * fails, check if name is an alias for an Internet protocol.
532	 */
533	if ((tp = knownname(name)) != NULL)
534		return (tp);
535
536	setprotoent(1);			/* make protocol lookup cheaper */
537	while ((p = getprotoent()) != NULL) {
538		/* assert: name not same as p->name */
539		for (alias = p->p_aliases; *alias; alias++)
540			if (strcmp(name, *alias) == 0) {
541				endprotoent();
542				return (knownname(p->p_name));
543			}
544	}
545	endprotoent();
546	return (NULL);
547}
548
549#define	NETSTAT_USAGE "\
550Usage:	netstat [-AaLlnW] [-f address_family | -p protocol]\n\
551	netstat [-gilns] [-f address_family]\n\
552	netstat -i | -I interface [-w wait] [-abdgRt]\n\
553	netstat -s [-s] [-f address_family | -p protocol] [-w wait]\n\
554	netstat -i | -I interface -s [-f address_family | -p protocol]\n\
555	netstat -m [-m]\n\
556	netstat -r [-Aaln] [-f address_family]\n\
557	netstat -rs [-s]\n\
558"
559
560static void
561usage(void)
562{
563	(void) fprintf(stderr, "%s\n", NETSTAT_USAGE);
564	exit(1);
565}
566
567int
568print_time(void)
569{
570    time_t now;
571    struct tm tm;
572    int num_written = 0;
573
574    (void) time(&now);
575    (void) localtime_r(&now, &tm);
576
577    num_written += printf("%02d:%02d:%02d ", tm.tm_hour, tm.tm_min, tm.tm_sec);
578
579    return (num_written);
580}
581
582