main.c revision 12316
1132718Skan/*
2132718Skan * Copyright (c) 1983, 1988, 1993
3132718Skan *	Regents of the University of California.  All rights reserved.
452284Sobrien *
552284Sobrien * Redistribution and use in source and binary forms, with or without
652284Sobrien * modification, are permitted provided that the following conditions
752284Sobrien * are met:
852284Sobrien * 1. Redistributions of source code must retain the above copyright
952284Sobrien *    notice, this list of conditions and the following disclaimer.
1052284Sobrien * 2. Redistributions in binary form must reproduce the above copyright
11132718Skan *    notice, this list of conditions and the following disclaimer in the
1252284Sobrien *    documentation and/or other materials provided with the distribution.
13132718Skan * 3. All advertising materials mentioning features or use of this software
1452284Sobrien *    must display the following acknowledgement:
1552284Sobrien *	This product includes software developed by the University of
1652284Sobrien *	California, Berkeley and its contributors.
1752284Sobrien * 4. Neither the name of the University nor the names of its contributors
18132718Skan *    may be used to endorse or promote products derived from this software
1952284Sobrien *    without specific prior written permission.
2052284Sobrien *
2152284Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2252284Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2352284Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24132718Skan * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25169689Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26169689Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2752284Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2890075Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2952284Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30117395Skan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31117395Skan * SUCH DAMAGE.
3252284Sobrien */
3352284Sobrien
34117395Skan#ifndef lint
3552284Sobrienchar copyright[] =
3652284Sobrien"@(#) Copyright (c) 1983, 1988, 1993\n\
3752284Sobrien	Regents of the University of California.  All rights reserved.\n";
3852284Sobrien#endif /* not lint */
39132718Skan
40132718Skan#ifndef lint
4190075Sobrienstatic char sccsid[] = "@(#)main.c	8.4 (Berkeley) 3/1/94";
4290075Sobrien#endif /* not lint */
4352284Sobrien
44132718Skan#include <sys/param.h>
4552284Sobrien#include <sys/file.h>
4652284Sobrien#include <sys/protosw.h>
4752284Sobrien#include <sys/socket.h>
4852284Sobrien
4952284Sobrien#include <netinet/in.h>
5052284Sobrien
5152284Sobrien#include <ctype.h>
5252284Sobrien#include <errno.h>
5352284Sobrien#include <kvm.h>
5452284Sobrien#include <limits.h>
5552284Sobrien#include <netdb.h>
5652284Sobrien#include <nlist.h>
57169689Skan#include <paths.h>
58169689Skan#include <stdio.h>
5952284Sobrien#include <stdlib.h>
60117395Skan#include <string.h>
61117395Skan#include <unistd.h>
62117395Skan#include <err.h>
63117395Skan#include "netstat.h"
64117395Skan
65117395Skanstruct nlist nl[] = {
66117395Skan#define	N_MBSTAT	0
67117395Skan	{ "_mbstat" },
68117395Skan#define	N_IPSTAT	1
69117395Skan	{ "_ipstat" },
70117395Skan#define	N_TCB		2
71117395Skan	{ "_tcb" },
72117395Skan#define	N_TCPSTAT	3
73117395Skan	{ "_tcpstat" },
74117395Skan#define	N_UDB		4
75117395Skan	{ "_udb" },
76132718Skan#define	N_UDPSTAT	5
77117395Skan	{ "_udpstat" },
78132718Skan#define	N_IFNET		6
79117395Skan	{ "_ifnet" },
80117395Skan#define	N_IMP		7
81117395Skan	{ "_imp_softc" },
82117395Skan#define	N_ICMPSTAT	8
8352284Sobrien	{ "_icmpstat" },
8452284Sobrien#define	N_RTSTAT	9
8552284Sobrien	{ "_rtstat" },
8652284Sobrien#define	N_UNIXSW	10
87169689Skan	{ "_localsw" },
8852284Sobrien#define N_IDP		11
89117395Skan	{ "_nspcb"},
9090075Sobrien#define N_IDPSTAT	12
9152284Sobrien	{ "_idpstat"},
9252284Sobrien#define N_SPPSTAT	13
9352284Sobrien	{ "_spp_istat"},
9452284Sobrien#define N_NSERR		14
9552284Sobrien	{ "_ns_errstat"},
9690075Sobrien#define	N_CLNPSTAT	15
97132718Skan	{ "_clnp_stat"},
98132718Skan#define	IN_NOTUSED	16
9952284Sobrien	{ "_tp_inpcb" },
10052284Sobrien#define	ISO_TP		17
10152284Sobrien	{ "_tp_refinfo" },
10252284Sobrien#define	N_TPSTAT	18
10352284Sobrien	{ "_tp_stat" },
10452284Sobrien#define	N_ESISSTAT	19
10552284Sobrien	{ "_esis_stat"},
10652284Sobrien#define N_NIMP		20
10752284Sobrien	{ "_nimp"},
10852284Sobrien#define N_RTREE		21
10952284Sobrien	{ "_rt_tables"},
11052284Sobrien#define N_CLTP		22
11152284Sobrien	{ "_cltb"},
11252284Sobrien#define N_CLTPSTAT	23
11352284Sobrien	{ "_cltpstat"},
11452284Sobrien#define	N_NFILE		24
11552284Sobrien	{ "_nfile" },
11652284Sobrien#define	N_FILE		25
11752284Sobrien	{ "_file" },
11852284Sobrien#define N_IGMPSTAT	26
11952284Sobrien	{ "_igmpstat" },
12052284Sobrien#define N_MRTPROTO	27
12152284Sobrien	{ "_ip_mrtproto" },
12252284Sobrien#define N_MRTSTAT	28
12352284Sobrien	{ "_mrtstat" },
12452284Sobrien#define N_MFCTABLE	29
12552284Sobrien	{ "_mfctable" },
12652284Sobrien#define N_VIFTABLE	30
12752284Sobrien	{ "_viftable" },
12852284Sobrien#define N_IPX		31
12952284Sobrien	{ "_ipxpcb"},
13052284Sobrien#define N_IPXSTAT	32
13152284Sobrien	{ "_ipxstat"},
13252284Sobrien#define N_SPXSTAT	33
13352284Sobrien	{ "_spx_istat"},
13452284Sobrien#define N_IPXERR	34
13552284Sobrien	{ "_ipx_errstat"},
13652284Sobrien	"",
13752284Sobrien};
13890075Sobrien
13952284Sobrienstruct protox {
14052284Sobrien	u_char	pr_index;		/* index into nlist of cb head */
14152284Sobrien	u_char	pr_sindex;		/* index into nlist of stat block */
14252284Sobrien	u_char	pr_wanted;		/* 1 if wanted, 0 otherwise */
14352284Sobrien	void	(*pr_cblocks)();	/* control blocks printing routine */
14452284Sobrien	void	(*pr_stats)();		/* statistics printing routine */
145132718Skan	char	*pr_name;		/* well-known name */
14652284Sobrien} protox[] = {
14752284Sobrien	{ N_TCB,	N_TCPSTAT,	1,	protopr,
14852284Sobrien	  tcp_stats,	"tcp" },
14952284Sobrien	{ N_UDB,	N_UDPSTAT,	1,	protopr,
150132718Skan	  udp_stats,	"udp" },
15190075Sobrien	{ -1,		N_IPSTAT,	1,	0,
152132718Skan	  ip_stats,	"ip" },
15390075Sobrien	{ -1,		N_ICMPSTAT,	1,	0,
15452284Sobrien	  icmp_stats,	"icmp" },
15552284Sobrien	{ -1,		N_IGMPSTAT,	1,	0,
156132718Skan	  igmp_stats,	"igmp" },
15752284Sobrien	{ -1,		-1,		0,	0,
15852284Sobrien	  0,		0 }
15952284Sobrien};
16052284Sobrien
16152284Sobrienstruct protox ipxprotox[] = {
16252284Sobrien	{ N_IPX,	N_IPXSTAT,	1,	ipxprotopr,
16352284Sobrien	  ipx_stats,	"ipx" },
16452284Sobrien	{ N_IPX,	N_SPXSTAT,	1,	ipxprotopr,
16552284Sobrien	  spx_stats,	"spx" },
16652284Sobrien	{ -1,		N_IPXERR,	1,	0,
16752284Sobrien	  ipxerr_stats,	"ipx_err" },
16852284Sobrien	{ -1,		-1,		0,	0,
16952284Sobrien	  0,		0 }
17052284Sobrien};
17152284Sobrien
17252284Sobrienstruct protox nsprotox[] = {
17352284Sobrien	{ N_IDP,	N_IDPSTAT,	1,	nsprotopr,
17452284Sobrien	  idp_stats,	"idp" },
17552284Sobrien	{ N_IDP,	N_SPPSTAT,	1,	nsprotopr,
17652284Sobrien	  spp_stats,	"spp" },
17752284Sobrien	{ -1,		N_NSERR,	1,	0,
17852284Sobrien	  nserr_stats,	"ns_err" },
17952284Sobrien	{ -1,		-1,		0,	0,
18052284Sobrien	  0,		0 }
18152284Sobrien};
18252284Sobrien
18352284Sobrienstruct protox isoprotox[] = {
18452284Sobrien	{ ISO_TP,	N_TPSTAT,	1,	iso_protopr,
18552284Sobrien	  tp_stats,	"tp" },
186132718Skan	{ N_CLTP,	N_CLTPSTAT,	1,	iso_protopr,
18790075Sobrien	  cltp_stats,	"cltp" },
188132718Skan	{ -1,		N_CLNPSTAT,	1,	 0,
189132718Skan	  clnp_stats,	"clnp"},
19052284Sobrien	{ -1,		N_ESISSTAT,	1,	 0,
19152284Sobrien	  esis_stats,	"esis"},
192132718Skan	{ -1,		-1,		0,	0,
19352284Sobrien	  0,		0 }
19452284Sobrien};
19552284Sobrien
19652284Sobrienstruct protox *protoprotox[] = { protox, ipxprotox, nsprotox, isoprotox, NULL };
19752284Sobrien
19852284Sobrienstatic void printproto __P((struct protox *, char *));
19952284Sobrienstatic void usage __P((void));
20090075Sobrienstatic struct protox *name2protox __P((char *));
20152284Sobrienstatic struct protox *knownname __P((char *));
20252284Sobrien
20352284Sobrienkvm_t *kvmd;
20452284Sobrien
20552284Sobrienint
20652284Sobrienmain(argc, argv)
20752284Sobrien	int argc;
20852284Sobrien	char *argv[];
20952284Sobrien{
21052284Sobrien	extern char *optarg;
21152284Sobrien	extern int optind;
21252284Sobrien	register struct protoent *p;
21352284Sobrien	register struct protox *tp;	/* for printing cblocks & stats */
21452284Sobrien	register char *cp;
21552284Sobrien	int ch;
21652284Sobrien	char *nlistf = NULL, *memf = NULL;
21752284Sobrien	char buf[_POSIX2_LINE_MAX];
21852284Sobrien	char buf2[_POSIX2_LINE_MAX];
21952284Sobrien
22052284Sobrien	if (cp = rindex(argv[0], '/'))
22152284Sobrien		prog = cp + 1;
22252284Sobrien	else
22352284Sobrien		prog = argv[0];
22452284Sobrien	af = AF_UNSPEC;
22552284Sobrien
22690075Sobrien	while ((ch = getopt(argc, argv, "Aabdf:ghI:iM:mN:np:rstuw:")) != EOF)
22752284Sobrien		switch(ch) {
22852284Sobrien		case 'A':
22952284Sobrien			Aflag = 1;
23052284Sobrien			break;
23152284Sobrien		case 'a':
23252284Sobrien			aflag = 1;
23352284Sobrien			break;
23452284Sobrien		case 'b':
235117395Skan			bflag = 1;
236117395Skan			break;
237117395Skan		case 'd':
238117395Skan			dflag = 1;
239117395Skan			break;
240117395Skan		case 'f':
241132718Skan			if (strcmp(optarg, "ns") == 0)
242132718Skan				af = AF_NS;
243132718Skan			else if (strcmp(optarg, "ipx") == 0)
244132718Skan				af = AF_IPX;
245132718Skan			else if (strcmp(optarg, "inet") == 0)
246132718Skan				af = AF_INET;
247132718Skan			else if (strcmp(optarg, "unix") == 0)
248132718Skan				af = AF_UNIX;
249132718Skan			else if (strcmp(optarg, "iso") == 0)
250132718Skan				af = AF_ISO;
251132718Skan			else {
252132718Skan				errx(1, "%s: unknown address family", optarg);
253132718Skan			}
254132718Skan			break;
255132718Skan		case 'g':
256132718Skan			gflag = 1;
257132718Skan			break;
258132718Skan		case 'I': {
259132718Skan			char *cp;
260132718Skan
261132718Skan			iflag = 1;
262132718Skan			for (cp = interface = optarg; isalpha(*cp); cp++)
26396263Sobrien				continue;
26452284Sobrien			unit = atoi(cp);
265117395Skan			break;
26652284Sobrien		}
26752284Sobrien		case 'i':
26852284Sobrien			iflag = 1;
26952284Sobrien			break;
27052284Sobrien		case 'M':
27152284Sobrien			memf = optarg;
27252284Sobrien			break;
27390075Sobrien		case 'm':
27452284Sobrien			mflag = 1;
27552284Sobrien			break;
27690075Sobrien		case 'N':
27752284Sobrien			nlistf = optarg;
27852284Sobrien			break;
27952284Sobrien		case 'n':
28052284Sobrien			nflag = 1;
28190075Sobrien			break;
28252284Sobrien		case 'p':
28352284Sobrien			if ((tp = name2protox(optarg)) == NULL) {
28452284Sobrien				errx(1,
28552284Sobrien				     "%s: unknown or uninstrumented protocol",
28652284Sobrien				     optarg);
28752284Sobrien			}
28852284Sobrien			pflag = 1;
28952284Sobrien			break;
29052284Sobrien		case 'r':
29152284Sobrien			rflag = 1;
29252284Sobrien			break;
29352284Sobrien		case 's':
29452284Sobrien			++sflag;
29590075Sobrien			break;
29652284Sobrien		case 't':
29752284Sobrien			tflag = 1;
29852284Sobrien			break;
29952284Sobrien		case 'u':
30052284Sobrien			af = AF_UNIX;
30152284Sobrien			break;
30252284Sobrien		case 'w':
30352284Sobrien			interval = atoi(optarg);
30452284Sobrien			iflag = 1;
30552284Sobrien			break;
30652284Sobrien		case '?':
30752284Sobrien		default:
30852284Sobrien			usage();
30952284Sobrien		}
31052284Sobrien	argv += optind;
31152284Sobrien	argc -= optind;
31252284Sobrien
31390075Sobrien#define	BACKWARD_COMPATIBILITY
31490075Sobrien#ifdef	BACKWARD_COMPATIBILITY
31552284Sobrien	if (*argv) {
31652284Sobrien		if (isdigit(**argv)) {
31752284Sobrien			interval = atoi(*argv);
31852284Sobrien			if (interval <= 0)
31952284Sobrien				usage();
32052284Sobrien			++argv;
32152284Sobrien			iflag = 1;
32252284Sobrien		}
32352284Sobrien		if (*argv) {
32452284Sobrien			nlistf = *argv;
32552284Sobrien			if (*++argv)
32652284Sobrien				memf = *argv;
327117395Skan		}
32852284Sobrien	}
329117395Skan#endif
330117395Skan
331117395Skan	/*
332117395Skan	 * Discard setgid privileges if not the running kernel so that bad
33352284Sobrien	 * guys can't print interesting stuff from kernel memory.
33452284Sobrien	 */
33552284Sobrien	if (nlistf != NULL || memf != NULL)
33652284Sobrien		setgid(getgid());
33790075Sobrien
33852284Sobrien	kvmd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf);
339169689Skan	if (kvmd == NULL) {
340169689Skan		errx(1, "kvm_open: %s", buf);
34152284Sobrien	}
342132718Skan	if (kvm_nlist(kvmd, nl) < 0) {
343117395Skan		if(nlistf)
344169689Skan			errx(1, "%s: kvm_nlist: %s", nlistf, kvm_geterr(kvmd));
34552284Sobrien		else
34652284Sobrien			errx(1, "kvm_nlist: %s", kvm_geterr(kvmd));
34796263Sobrien	}
34852284Sobrien
34990075Sobrien	if (nl[0].n_type == 0) {
35090075Sobrien		if(nlistf)
35152284Sobrien			errx(1, "%s: no namelist", nlistf);
35290075Sobrien		else
35352284Sobrien			errx(1, "no namelist");
35452284Sobrien	}
35590075Sobrien	if (mflag) {
35652284Sobrien		mbpr(nl[N_MBSTAT].n_value);
35752284Sobrien		exit(0);
358132718Skan	}
35996263Sobrien	if (pflag) {
36096263Sobrien		if (tp->pr_stats)
36196263Sobrien			(*tp->pr_stats)(nl[tp->pr_sindex].n_value,
36296263Sobrien				tp->pr_name);
36396263Sobrien		else
36496263Sobrien			printf("%s: no stats routine\n", tp->pr_name);
36596263Sobrien		exit(0);
366	}
367	/*
368	 * Keep file descriptors open to avoid overhead
369	 * of open/close on each call to get* routines.
370	 */
371	sethostent(1);
372	setnetent(1);
373	if (iflag) {
374		intpr(interval, nl[N_IFNET].n_value);
375		exit(0);
376	}
377	if (rflag) {
378		if (sflag)
379			rt_stats(nl[N_RTSTAT].n_value);
380		else
381			routepr(nl[N_RTREE].n_value);
382		exit(0);
383	}
384	if (gflag) {
385		if (sflag)
386			mrt_stats(nl[N_MRTPROTO].n_value,
387			    nl[N_MRTSTAT].n_value);
388		else
389			mroutepr(nl[N_MRTPROTO].n_value,
390			    nl[N_MFCTABLE].n_value,
391			    nl[N_VIFTABLE].n_value);
392		exit(0);
393	}
394	if (af == AF_INET || af == AF_UNSPEC) {
395		setprotoent(1);
396		setservent(1);
397		/* ugh, this is O(MN) ... why do we do this? */
398		while (p = getprotoent()) {
399			for (tp = protox; tp->pr_name; tp++)
400				if (strcmp(tp->pr_name, p->p_name) == 0)
401					break;
402			if (tp->pr_name == 0 || tp->pr_wanted == 0)
403				continue;
404			printproto(tp, p->p_name);
405		}
406		endprotoent();
407	}
408	if (af == AF_IPX || af == AF_UNSPEC)
409		for (tp = ipxprotox; tp->pr_name; tp++)
410			printproto(tp, tp->pr_name);
411	if (af == AF_NS || af == AF_UNSPEC)
412		for (tp = nsprotox; tp->pr_name; tp++)
413			printproto(tp, tp->pr_name);
414	if (af == AF_ISO || af == AF_UNSPEC)
415		for (tp = isoprotox; tp->pr_name; tp++)
416			printproto(tp, tp->pr_name);
417	if ((af == AF_UNIX || af == AF_UNSPEC) && !sflag)
418		unixpr(nl[N_UNIXSW].n_value);
419	exit(0);
420}
421
422/*
423 * Print out protocol statistics or control blocks (per sflag).
424 * If the interface was not specifically requested, and the symbol
425 * is not in the namelist, ignore this one.
426 */
427static void
428printproto(tp, name)
429	register struct protox *tp;
430	char *name;
431{
432	void (*pr)();
433	u_long off;
434
435	if (sflag) {
436		pr = tp->pr_stats;
437		off = nl[tp->pr_sindex].n_value;
438	} else {
439		pr = tp->pr_cblocks;
440		off = nl[tp->pr_index].n_value;
441	}
442	if (pr != NULL && (off || af != AF_UNSPEC))
443		(*pr)(off, name);
444}
445
446/*
447 * Read kernel memory, return 0 on success.
448 */
449int
450kread(addr, buf, size)
451	u_long addr;
452	char *buf;
453	int size;
454{
455
456	if (kvm_read(kvmd, addr, buf, size) != size) {
457		warnx("%s", kvm_geterr(kvmd));
458		return (-1);
459	}
460	return (0);
461}
462
463char *
464plural(n)
465	int n;
466{
467	return (n != 1 ? "s" : "");
468}
469
470char *
471plurales(n)
472	int n;
473{
474	return (n != 1 ? "es" : "");
475}
476
477/*
478 * Find the protox for the given "well-known" name.
479 */
480static struct protox *
481knownname(name)
482	char *name;
483{
484	struct protox **tpp, *tp;
485
486	for (tpp = protoprotox; *tpp; tpp++)
487		for (tp = *tpp; tp->pr_name; tp++)
488			if (strcmp(tp->pr_name, name) == 0)
489				return (tp);
490	return (NULL);
491}
492
493/*
494 * Find the protox corresponding to name.
495 */
496static struct protox *
497name2protox(name)
498	char *name;
499{
500	struct protox *tp;
501	char **alias;			/* alias from p->aliases */
502	struct protoent *p;
503
504	/*
505	 * Try to find the name in the list of "well-known" names. If that
506	 * fails, check if name is an alias for an Internet protocol.
507	 */
508	if (tp = knownname(name))
509		return (tp);
510
511	setprotoent(1);			/* make protocol lookup cheaper */
512	while (p = getprotoent()) {
513		/* assert: name not same as p->name */
514		for (alias = p->p_aliases; *alias; alias++)
515			if (strcmp(name, *alias) == 0) {
516				endprotoent();
517				return (knownname(p->p_name));
518			}
519	}
520	endprotoent();
521	return (NULL);
522}
523
524static void
525usage()
526{
527	(void)fprintf(stderr,
528"usage: %s [-Aan] [-f address_family] [-M core] [-N system]\n", prog);
529	(void)fprintf(stderr,
530"       %s [-bdghimnrs] [-f address_family] [-M core] [-N system]\n", prog);
531	(void)fprintf(stderr,
532"       %s [-bdn] [-I interface] [-M core] [-N system] [-w wait]\n", prog);
533	(void)fprintf(stderr,
534"       %s [-M core] [-N system] [-p protocol]\n", prog);
535	exit(1);
536}
537