xref: /csrg-svn/usr.bin/netstat/main.c (revision 66291)
121988Sdist /*
263410Sbostic  * Copyright (c) 1983, 1988, 1993
363410Sbostic  *	Regents of the University of California.  All rights reserved.
433451Skarels  *
542748Sbostic  * %sccs.include.redist.c%
621988Sdist  */
721988Sdist 
87907Ssam #ifndef lint
921988Sdist char copyright[] =
1063410Sbostic "@(#) Copyright (c) 1983, 1988, 1993\n\
1163410Sbostic 	Regents of the University of California.  All rights reserved.\n";
1233623Sbostic #endif /* not lint */
137907Ssam 
1421988Sdist #ifndef lint
15*66291Sbostic static char sccsid[] = "@(#)main.c	8.4 (Berkeley) 03/01/94";
1633623Sbostic #endif /* not lint */
1721988Sdist 
187907Ssam #include <sys/param.h>
1954721Ssklower #include <sys/file.h>
2053698Ssklower #include <sys/protosw.h>
2124301Ssklower #include <sys/socket.h>
2254721Ssklower 
2354721Ssklower #include <netinet/in.h>
2454721Ssklower 
2554721Ssklower #include <ctype.h>
267907Ssam #include <errno.h>
2754721Ssklower #include <kvm.h>
2854721Ssklower #include <limits.h>
297907Ssam #include <netdb.h>
307907Ssam #include <nlist.h>
3154721Ssklower #include <paths.h>
327907Ssam #include <stdio.h>
3348576Sbostic #include <stdlib.h>
3448576Sbostic #include <string.h>
3554721Ssklower #include <unistd.h>
3653698Ssklower #include "netstat.h"
377907Ssam 
387907Ssam struct nlist nl[] = {
397907Ssam #define	N_MBSTAT	0
407907Ssam 	{ "_mbstat" },
417907Ssam #define	N_IPSTAT	1
427907Ssam 	{ "_ipstat" },
437907Ssam #define	N_TCB		2
447907Ssam 	{ "_tcb" },
457907Ssam #define	N_TCPSTAT	3
467907Ssam 	{ "_tcpstat" },
477907Ssam #define	N_UDB		4
487907Ssam 	{ "_udb" },
497907Ssam #define	N_UDPSTAT	5
507907Ssam 	{ "_udpstat" },
5148576Sbostic #define	N_IFNET		6
527907Ssam 	{ "_ifnet" },
5348576Sbostic #define	N_IMP		7
5433450Skarels 	{ "_imp_softc" },
5550681Skarels #define	N_ICMPSTAT	8
5611536Ssam 	{ "_icmpstat" },
5750681Skarels #define	N_RTSTAT	9
5812839Ssam 	{ "_rtstat" },
5950681Skarels #define	N_UNIXSW	10
6016561Ssam 	{ "_unixsw" },
6150681Skarels #define N_IDP		11
6224301Ssklower 	{ "_nspcb"},
6350681Skarels #define N_IDPSTAT	12
6424301Ssklower 	{ "_idpstat"},
6550681Skarels #define N_SPPSTAT	13
6624301Ssklower 	{ "_spp_istat"},
6750681Skarels #define N_NSERR		14
6824301Ssklower 	{ "_ns_errstat"},
6950681Skarels #define	N_CLNPSTAT	15
7039213Ssklower 	{ "_clnp_stat"},
7152248Ssklower #define	IN_NOTUSED	16
7239213Ssklower 	{ "_tp_inpcb" },
7350681Skarels #define	ISO_TP		17
7452248Ssklower 	{ "_tp_refinfo" },
7550681Skarels #define	N_TPSTAT	18
7639213Ssklower 	{ "_tp_stat" },
7750681Skarels #define	N_ESISSTAT	19
7839213Ssklower 	{ "_esis_stat"},
7950681Skarels #define N_NIMP		20
8033450Skarels 	{ "_nimp"},
8150681Skarels #define N_RTREE		21
8250884Ssklower 	{ "_rt_tables"},
8350681Skarels #define N_CLTP		22
8440838Ssklower 	{ "_cltb"},
8550681Skarels #define N_CLTPSTAT	23
8640838Ssklower 	{ "_cltpstat"},
8754721Ssklower #define	N_NFILE		24
8854721Ssklower 	{ "_nfile" },
8954721Ssklower #define	N_FILE		25
9054721Ssklower 	{ "_file" },
9154721Ssklower #define N_IGMPSTAT	26
9254721Ssklower 	{ "_igmpstat" },
9354721Ssklower #define N_MRTPROTO	27
9454721Ssklower 	{ "_ip_mrtproto" },
9554721Ssklower #define N_MRTSTAT	28
9654721Ssklower 	{ "_mrtstat" },
9754721Ssklower #define N_MRTTABLE	29
9854721Ssklower 	{ "_mrttable" },
9954721Ssklower #define N_VIFTABLE	30
10054721Ssklower 	{ "_viftable" },
10111536Ssam 	"",
1027907Ssam };
1037907Ssam 
1047907Ssam struct protox {
1059569Ssam 	u_char	pr_index;		/* index into nlist of cb head */
1069569Ssam 	u_char	pr_sindex;		/* index into nlist of stat block */
1079569Ssam 	u_char	pr_wanted;		/* 1 if wanted, 0 otherwise */
10853698Ssklower 	void	(*pr_cblocks)();	/* control blocks printing routine */
10953698Ssklower 	void	(*pr_stats)();		/* statistics printing routine */
1109569Ssam 	char	*pr_name;		/* well-known name */
11125917Skarels } protox[] = {
1129569Ssam 	{ N_TCB,	N_TCPSTAT,	1,	protopr,
1139569Ssam 	  tcp_stats,	"tcp" },
1149569Ssam 	{ N_UDB,	N_UDPSTAT,	1,	protopr,
1159569Ssam 	  udp_stats,	"udp" },
1169569Ssam 	{ -1,		N_IPSTAT,	1,	0,
1179569Ssam 	  ip_stats,	"ip" },
11811536Ssam 	{ -1,		N_ICMPSTAT,	1,	0,
11911536Ssam 	  icmp_stats,	"icmp" },
12058024Sandrew 	{ -1,		N_IGMPSTAT,	1,	0,
12158024Sandrew 	  igmp_stats,	"igmp" },
1229569Ssam 	{ -1,		-1,		0,	0,
1239569Ssam 	  0,		0 }
1247907Ssam };
1257907Ssam 
12624301Ssklower struct protox nsprotox[] = {
12724301Ssklower 	{ N_IDP,	N_IDPSTAT,	1,	nsprotopr,
12824301Ssklower 	  idp_stats,	"idp" },
12924301Ssklower 	{ N_IDP,	N_SPPSTAT,	1,	nsprotopr,
13024301Ssklower 	  spp_stats,	"spp" },
13124301Ssklower 	{ -1,		N_NSERR,	1,	0,
13224301Ssklower 	  nserr_stats,	"ns_err" },
13324301Ssklower 	{ -1,		-1,		0,	0,
13424301Ssklower 	  0,		0 }
13524301Ssklower };
13624301Ssklower 
13739213Ssklower struct protox isoprotox[] = {
13839213Ssklower 	{ ISO_TP,	N_TPSTAT,	1,	iso_protopr,
13939213Ssklower 	  tp_stats,	"tp" },
14040838Ssklower 	{ N_CLTP,	N_CLTPSTAT,	1,	iso_protopr,
14140838Ssklower 	  cltp_stats,	"cltp" },
14239213Ssklower 	{ -1,		N_CLNPSTAT,	1,	 0,
14339213Ssklower 	  clnp_stats,	"clnp"},
14439213Ssklower 	{ -1,		N_ESISSTAT,	1,	 0,
14539213Ssklower 	  esis_stats,	"esis"},
14639213Ssklower 	{ -1,		-1,		0,	0,
14739213Ssklower 	  0,		0 }
14839213Ssklower };
14939213Ssklower 
15048576Sbostic struct protox *protoprotox[] = { protox, nsprotox, isoprotox, NULL };
15139213Ssklower 
15253698Ssklower static void printproto __P((struct protox *, char *));
153*66291Sbostic static void usage __P((void));
15453698Ssklower static struct protox *name2protox __P((char *));
15553698Ssklower static struct protox *knownname __P((char *));
1567907Ssam 
15753698Ssklower kvm_t *kvmd;
15827886Skarels 
15953698Ssklower int
main(argc,argv)1607907Ssam main(argc, argv)
1617907Ssam 	int argc;
162*66291Sbostic 	char *argv[];
1637907Ssam {
16433623Sbostic 	extern char *optarg;
16533623Sbostic 	extern int optind;
1667907Ssam 	register struct protoent *p;
16729754Skupfer 	register struct protox *tp;	/* for printing cblocks & stats */
16853698Ssklower 	register char *cp;
16933623Sbostic 	int ch;
17053698Ssklower 	char *nlistf = NULL, *memf = NULL;
17153698Ssklower 	char buf[_POSIX2_LINE_MAX];
1727907Ssam 
17353698Ssklower 	if (cp = rindex(argv[0], '/'))
17453698Ssklower 		prog = cp + 1;
17553698Ssklower 	else
17653698Ssklower 		prog = argv[0];
17753698Ssklower 	af = AF_UNSPEC;
17853698Ssklower 
17965395Sbostic 	while ((ch = getopt(argc, argv, "Aadf:ghI:iM:mN:np:rstuw:")) != EOF)
18055010Sbostic 		switch(ch) {
1817907Ssam 		case 'A':
18248576Sbostic 			Aflag = 1;
1837907Ssam 			break;
1847907Ssam 		case 'a':
18548576Sbostic 			aflag = 1;
1867907Ssam 			break;
18734270Skarels 		case 'd':
18848576Sbostic 			dflag = 1;
18934270Skarels 			break;
19033623Sbostic 		case 'f':
19133623Sbostic 			if (strcmp(optarg, "ns") == 0)
19233623Sbostic 				af = AF_NS;
19333623Sbostic 			else if (strcmp(optarg, "inet") == 0)
19433623Sbostic 				af = AF_INET;
19533623Sbostic 			else if (strcmp(optarg, "unix") == 0)
19633623Sbostic 				af = AF_UNIX;
19739213Ssklower 			else if (strcmp(optarg, "iso") == 0)
19839213Ssklower 				af = AF_ISO;
19933623Sbostic 			else {
20048576Sbostic 				(void)fprintf(stderr,
20153698Ssklower 				    "%s: %s: unknown address family\n",
20253698Ssklower 				    prog, optarg);
20348576Sbostic 				exit(1);
20433623Sbostic 			}
20533623Sbostic 			break;
20665395Sbostic 		case 'g':
20765395Sbostic 			gflag = 1;
20865395Sbostic 			break;
20948576Sbostic 		case 'I': {
21048576Sbostic 			char *cp;
21148576Sbostic 
21248576Sbostic 			iflag = 1;
21353698Ssklower 			for (cp = interface = optarg; isalpha(*cp); cp++)
21453698Ssklower 				continue;
21548576Sbostic 			unit = atoi(cp);
21648576Sbostic 			*cp = '\0';
21748576Sbostic 			break;
21848576Sbostic 		}
2197907Ssam 		case 'i':
22048576Sbostic 			iflag = 1;
2217907Ssam 			break;
22248576Sbostic 		case 'M':
22352252Sbostic 			memf = optarg;
22448576Sbostic 			break;
2257907Ssam 		case 'm':
22648576Sbostic 			mflag = 1;
2277907Ssam 			break;
22848576Sbostic 		case 'N':
22952252Sbostic 			nlistf = optarg;
23048576Sbostic 			break;
2317907Ssam 		case 'n':
23248576Sbostic 			nflag = 1;
2337907Ssam 			break;
23433623Sbostic 		case 'p':
23548576Sbostic 			if ((tp = name2protox(optarg)) == NULL) {
23648576Sbostic 				(void)fprintf(stderr,
23753698Ssklower 				    "%s: %s: unknown or uninstrumented protocol\n",
23853698Ssklower 				    prog, optarg);
23948576Sbostic 				exit(1);
24033623Sbostic 			}
24148576Sbostic 			pflag = 1;
24233623Sbostic 			break;
2437907Ssam 		case 'r':
24448576Sbostic 			rflag = 1;
2457907Ssam 			break;
2467907Ssam 		case 's':
24753698Ssklower 			++sflag;
2487907Ssam 			break;
2497907Ssam 		case 't':
25048576Sbostic 			tflag = 1;
2517907Ssam 			break;
25216561Ssam 		case 'u':
25327886Skarels 			af = AF_UNIX;
25416561Ssam 			break;
25548576Sbostic 		case 'w':
25648576Sbostic 			interval = atoi(optarg);
25765329Sbostic 			iflag = 1;
25848576Sbostic 			break;
25933623Sbostic 		case '?':
26033623Sbostic 		default:
26133623Sbostic 			usage();
26233623Sbostic 		}
26333623Sbostic 	argv += optind;
26433623Sbostic 	argc -= optind;
26516561Ssam 
26648576Sbostic #define	BACKWARD_COMPATIBILITY
26748576Sbostic #ifdef	BACKWARD_COMPATIBILITY
26848576Sbostic 	if (*argv) {
26948576Sbostic 		if (isdigit(**argv)) {
27048576Sbostic 			interval = atoi(*argv);
27133623Sbostic 			if (interval <= 0)
27233623Sbostic 				usage();
27348576Sbostic 			++argv;
27448576Sbostic 			iflag = 1;
27533623Sbostic 		}
27648576Sbostic 		if (*argv) {
27752252Sbostic 			nlistf = *argv;
27853698Ssklower 			if (*++argv)
27952252Sbostic 				memf = *argv;
2807907Ssam 		}
2817907Ssam 	}
28248576Sbostic #endif
28353698Ssklower 
28452252Sbostic 	/*
28552252Sbostic 	 * Discard setgid privileges if not the running kernel so that bad
28652252Sbostic 	 * guys can't print interesting stuff from kernel memory.
28752252Sbostic 	 */
28852252Sbostic 	if (nlistf != NULL || memf != NULL)
28952252Sbostic 		setgid(getgid());
29052252Sbostic 
29153698Ssklower 	if ((kvmd = kvm_open(nlistf, memf, NULL, O_RDONLY, prog)) == NULL) {
29253698Ssklower 		fprintf(stderr, "%s: kvm_open: %s\n", prog, buf);
2937907Ssam 		exit(1);
2947907Ssam 	}
29553698Ssklower 	if (kvm_nlist(kvmd, nl) < 0 || nl[0].n_type == 0) {
29653698Ssklower 		if (nlistf)
29753698Ssklower 			fprintf(stderr, "%s: %s: no namelist\n", prog, nlistf);
29853698Ssklower 		else
29953698Ssklower 			fprintf(stderr, "%s: no namelist\n", prog);
3007907Ssam 		exit(1);
3017907Ssam 	}
3027907Ssam 	if (mflag) {
30354761Ssklower 		mbpr(nl[N_MBSTAT].n_value);
3047907Ssam 		exit(0);
3057907Ssam 	}
30629754Skupfer 	if (pflag) {
30729754Skupfer 		if (tp->pr_stats)
30833623Sbostic 			(*tp->pr_stats)(nl[tp->pr_sindex].n_value,
30929754Skupfer 				tp->pr_name);
31029754Skupfer 		else
31129754Skupfer 			printf("%s: no stats routine\n", tp->pr_name);
31229754Skupfer 		exit(0);
31329754Skupfer 	}
3147907Ssam 	/*
3157907Ssam 	 * Keep file descriptors open to avoid overhead
3167907Ssam 	 * of open/close on each call to get* routines.
3177907Ssam 	 */
3187907Ssam 	sethostent(1);
3197907Ssam 	setnetent(1);
3208331Ssam 	if (iflag) {
3218331Ssam 		intpr(interval, nl[N_IFNET].n_value);
3228331Ssam 		exit(0);
3238331Ssam 	}
3247907Ssam 	if (rflag) {
32512839Ssam 		if (sflag)
32654761Ssklower 			rt_stats(nl[N_RTSTAT].n_value);
32712839Ssam 		else
32854761Ssklower 			routepr(nl[N_RTREE].n_value);
3297907Ssam 		exit(0);
3307907Ssam 	}
33165395Sbostic 	if (gflag) {
33254721Ssklower 		if (sflag)
33354761Ssklower 			mrt_stats(nl[N_MRTPROTO].n_value,
33454761Ssklower 			    nl[N_MRTSTAT].n_value);
33554721Ssklower 		else
33654761Ssklower 			mroutepr(nl[N_MRTPROTO].n_value,
33754761Ssklower 			    nl[N_MRTTABLE].n_value,
33854761Ssklower 			    nl[N_VIFTABLE].n_value);
33954721Ssklower 		exit(0);
34054721Ssklower 	}
34153698Ssklower 	if (af == AF_INET || af == AF_UNSPEC) {
34253698Ssklower 		setprotoent(1);
34353698Ssklower 		setservent(1);
34453698Ssklower 		/* ugh, this is O(MN) ... why do we do this? */
34553698Ssklower 		while (p = getprotoent()) {
34653698Ssklower 			for (tp = protox; tp->pr_name; tp++)
34753698Ssklower 				if (strcmp(tp->pr_name, p->p_name) == 0)
34853698Ssklower 					break;
34953698Ssklower 			if (tp->pr_name == 0 || tp->pr_wanted == 0)
35053698Ssklower 				continue;
35153698Ssklower 			printproto(tp, p->p_name);
35253698Ssklower 		}
35353698Ssklower 		endprotoent();
35453698Ssklower 	}
35553698Ssklower 	if (af == AF_NS || af == AF_UNSPEC)
35653698Ssklower 		for (tp = nsprotox; tp->pr_name; tp++)
35753698Ssklower 			printproto(tp, tp->pr_name);
35853698Ssklower 	if (af == AF_ISO || af == AF_UNSPEC)
35953698Ssklower 		for (tp = isoprotox; tp->pr_name; tp++)
36053698Ssklower 			printproto(tp, tp->pr_name);
36153698Ssklower 	if ((af == AF_UNIX || af == AF_UNSPEC) && !sflag)
36254761Ssklower 		unixpr(nl[N_UNIXSW].n_value);
36353698Ssklower 	exit(0);
36453698Ssklower }
3657907Ssam 
36653698Ssklower /*
36753698Ssklower  * Print out protocol statistics or control blocks (per sflag).
36853698Ssklower  * If the interface was not specifically requested, and the symbol
36953698Ssklower  * is not in the namelist, ignore this one.
37053698Ssklower  */
37153698Ssklower static void
printproto(tp,name)37253698Ssklower printproto(tp, name)
37353698Ssklower 	register struct protox *tp;
37453698Ssklower 	char *name;
37553698Ssklower {
37653698Ssklower 	void (*pr)();
37754761Ssklower 	u_long off;
37853698Ssklower 
37953698Ssklower 	if (sflag) {
38053698Ssklower 		pr = tp->pr_stats;
38153698Ssklower 		off = nl[tp->pr_sindex].n_value;
38253698Ssklower 	} else {
38353698Ssklower 		pr = tp->pr_cblocks;
38453698Ssklower 		off = nl[tp->pr_index].n_value;
3857907Ssam 	}
38653698Ssklower 	if (pr != NULL && (off || af != AF_UNSPEC))
38753698Ssklower 		(*pr)(off, name);
38853698Ssklower }
38953698Ssklower 
39053698Ssklower /*
39153698Ssklower  * Read kernel memory, return 0 on success.
39253698Ssklower  */
39353698Ssklower int
kread(addr,buf,size)39453698Ssklower kread(addr, buf, size)
39554761Ssklower 	u_long addr;
39653698Ssklower 	char *buf;
39753698Ssklower 	int size;
39853698Ssklower {
39953698Ssklower 
40053698Ssklower 	if (kvm_read(kvmd, addr, buf, size) != size) {
40153698Ssklower 		/* XXX this duplicates kvm_read's error printout */
40253698Ssklower 		(void)fprintf(stderr, "%s: kvm_read %s\n", prog,
40353698Ssklower 		    kvm_geterr(kvmd));
40453698Ssklower 		return (-1);
40524301Ssklower 	}
40653698Ssklower 	return (0);
4077907Ssam }
4087907Ssam 
40912839Ssam char *
plural(n)41012839Ssam plural(n)
41112839Ssam 	int n;
41212839Ssam {
41312839Ssam 	return (n != 1 ? "s" : "");
41412839Ssam }
41529754Skupfer 
41654721Ssklower char *
plurales(n)41754721Ssklower plurales(n)
41854721Ssklower 	int n;
41954721Ssklower {
42054721Ssklower 	return (n != 1 ? "es" : "");
42154721Ssklower }
42254721Ssklower 
42329754Skupfer /*
42429754Skupfer  * Find the protox for the given "well-known" name.
42529754Skupfer  */
42653698Ssklower static struct protox *
knownname(name)42729754Skupfer knownname(name)
42829754Skupfer 	char *name;
42929754Skupfer {
43039213Ssklower 	struct protox **tpp, *tp;
43133623Sbostic 
43239213Ssklower 	for (tpp = protoprotox; *tpp; tpp++)
43353698Ssklower 		for (tp = *tpp; tp->pr_name; tp++)
43453698Ssklower 			if (strcmp(tp->pr_name, name) == 0)
43553698Ssklower 				return (tp);
43653698Ssklower 	return (NULL);
43729754Skupfer }
43829754Skupfer 
43929754Skupfer /*
44029754Skupfer  * Find the protox corresponding to name.
44129754Skupfer  */
44253698Ssklower static struct protox *
name2protox(name)44329754Skupfer name2protox(name)
44429754Skupfer 	char *name;
44529754Skupfer {
44629754Skupfer 	struct protox *tp;
44729754Skupfer 	char **alias;			/* alias from p->aliases */
44829754Skupfer 	struct protoent *p;
44933623Sbostic 
45029754Skupfer 	/*
45129754Skupfer 	 * Try to find the name in the list of "well-known" names. If that
45229754Skupfer 	 * fails, check if name is an alias for an Internet protocol.
45329754Skupfer 	 */
45429754Skupfer 	if (tp = knownname(name))
45553698Ssklower 		return (tp);
45633623Sbostic 
45729754Skupfer 	setprotoent(1);			/* make protocol lookup cheaper */
45829754Skupfer 	while (p = getprotoent()) {
45929754Skupfer 		/* assert: name not same as p->name */
46029754Skupfer 		for (alias = p->p_aliases; *alias; alias++)
46129754Skupfer 			if (strcmp(name, *alias) == 0) {
46229754Skupfer 				endprotoent();
46353698Ssklower 				return (knownname(p->p_name));
46429754Skupfer 			}
46529754Skupfer 	}
46629754Skupfer 	endprotoent();
46753698Ssklower 	return (NULL);
46829754Skupfer }
46933623Sbostic 
47053698Ssklower static void
usage()47133623Sbostic usage()
47233623Sbostic {
47348576Sbostic 	(void)fprintf(stderr,
47453698Ssklower "usage: %s [-Aan] [-f address_family] [-M core] [-N system]\n", prog);
47548576Sbostic 	(void)fprintf(stderr,
476*66291Sbostic "       %s [-ghimnrs] [-f address_family] [-M core] [-N system]\n", prog);
47748576Sbostic 	(void)fprintf(stderr,
478*66291Sbostic "       %s [-n] [-I interface] [-M core] [-N system] [-w wait]\n", prog);
47948576Sbostic 	(void)fprintf(stderr,
480*66291Sbostic "       %s [-M core] [-N system] [-p protocol]\n", prog);
48133623Sbostic 	exit(1);
48233623Sbostic }
483