xref: /original-bsd/usr.bin/netstat/main.c (revision 4e9331e4)
1 /*
2  * Copyright (c) 1983, 1988 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 
18 #ifndef lint
19 char copyright[] =
20 "@(#) Copyright (c) 1983, 1988 Regents of the University of California.\n\
21  All rights reserved.\n";
22 #endif /* not lint */
23 
24 #ifndef lint
25 static char sccsid[] = "@(#)main.c	5.16 (Berkeley) 09/25/89";
26 #endif /* not lint */
27 
28 #include <sys/param.h>
29 #include <sys/vmmac.h>
30 #include <sys/socket.h>
31 #include <sys/file.h>
32 #include <machine/pte.h>
33 #include <ctype.h>
34 #include <errno.h>
35 #include <netdb.h>
36 #include <nlist.h>
37 #include <stdio.h>
38 #include <paths.h>
39 
40 struct nlist nl[] = {
41 #define	N_MBSTAT	0
42 	{ "_mbstat" },
43 #define	N_IPSTAT	1
44 	{ "_ipstat" },
45 #define	N_TCB		2
46 	{ "_tcb" },
47 #define	N_TCPSTAT	3
48 	{ "_tcpstat" },
49 #define	N_UDB		4
50 	{ "_udb" },
51 #define	N_UDPSTAT	5
52 	{ "_udpstat" },
53 #define	N_RAWCB		6
54 	{ "_rawcb" },
55 #define	N_SYSMAP	7
56 	{ "_Sysmap" },
57 #define	N_SYSSIZE	8
58 	{ "_Syssize" },
59 #define	N_IFNET		9
60 	{ "_ifnet" },
61 #define	N_IMP		10
62 	{ "_imp_softc" },
63 #define	N_RTHOST	11
64 	{ "_rthost" },
65 #define	N_RTNET		12
66 	{ "_rtnet" },
67 #define	N_ICMPSTAT	13
68 	{ "_icmpstat" },
69 #define	N_RTSTAT	14
70 	{ "_rtstat" },
71 #define	N_NFILE		15
72 	{ "_nfile" },
73 #define	N_FILE		16
74 	{ "_file" },
75 #define	N_UNIXSW	17
76 	{ "_unixsw" },
77 #define N_RTHASHSIZE	18
78 	{ "_rthashsize" },
79 #define N_IDP		19
80 	{ "_nspcb"},
81 #define N_IDPSTAT	20
82 	{ "_idpstat"},
83 #define N_SPPSTAT	21
84 	{ "_spp_istat"},
85 #define N_NSERR		22
86 	{ "_ns_errstat"},
87 #define	N_CLNPSTAT	23
88 	{ "_clnp_stat"},
89 #define	IN_TP		24
90 	{ "_tp_inpcb" },
91 #define	ISO_TP		25
92 	{ "_tp_isopcb" },
93 #define	ISO_X25		26
94 	{ "_x25_isopcb" },
95 #define	N_TPSTAT	27
96 	{ "_tp_stat" },
97 #define	N_X25STAT	28
98 	{ "_x25_stat" },
99 #define	N_ESISSTAT	29
100 	{ "_esis_stat"},
101 #define N_NIMP		30
102 	{ "_nimp"},
103 #define N_RTREE		31
104 	{ "_radix_node_head"},
105 	"",
106 };
107 
108 /* internet protocols */
109 extern	int protopr();
110 extern	int tcp_stats(), udp_stats(), ip_stats(), icmp_stats();
111 /* ns protocols */
112 extern	int nsprotopr();
113 extern	int spp_stats(), idp_stats(), nserr_stats();
114 /* iso protocols */
115 extern	int iso_protopr();
116 extern	int tp_stats(), esis_stats(), clnp_stats();
117 
118 #define NULLPROTOX	((struct protox *) 0)
119 struct protox {
120 	u_char	pr_index;		/* index into nlist of cb head */
121 	u_char	pr_sindex;		/* index into nlist of stat block */
122 	u_char	pr_wanted;		/* 1 if wanted, 0 otherwise */
123 	int	(*pr_cblocks)();	/* control blocks printing routine */
124 	int	(*pr_stats)();		/* statistics printing routine */
125 	char	*pr_name;		/* well-known name */
126 } protox[] = {
127 	{ N_TCB,	N_TCPSTAT,	1,	protopr,
128 	  tcp_stats,	"tcp" },
129 	{ N_UDB,	N_UDPSTAT,	1,	protopr,
130 	  udp_stats,	"udp" },
131 	{ IN_TP,	N_TPSTAT,	1,	protopr,
132 	  tp_stats,	"tpip" },
133 	{ -1,		N_IPSTAT,	1,	0,
134 	  ip_stats,	"ip" },
135 	{ -1,		N_ICMPSTAT,	1,	0,
136 	  icmp_stats,	"icmp" },
137 	{ -1,		-1,		0,	0,
138 	  0,		0 }
139 };
140 
141 struct protox nsprotox[] = {
142 	{ N_IDP,	N_IDPSTAT,	1,	nsprotopr,
143 	  idp_stats,	"idp" },
144 	{ N_IDP,	N_SPPSTAT,	1,	nsprotopr,
145 	  spp_stats,	"spp" },
146 	{ -1,		N_NSERR,	1,	0,
147 	  nserr_stats,	"ns_err" },
148 	{ -1,		-1,		0,	0,
149 	  0,		0 }
150 };
151 
152 struct protox isoprotox[] = {
153 	{ ISO_TP,	N_TPSTAT,	1,	iso_protopr,
154 	  tp_stats,	"tp" },
155 #ifdef notdef
156 	{ ISO_X25,	N_X25STAT,	1,	x25_protopr,
157 	  x25_stats,	"x25" },
158 #endif
159 	{ -1,		N_CLNPSTAT,	1,	 0,
160 	  clnp_stats,	"clnp"},
161 	{ -1,		N_ESISSTAT,	1,	 0,
162 	  esis_stats,	"esis"},
163 	{ -1,		-1,		0,	0,
164 	  0,		0 }
165 };
166 
167 struct protox *protoprotox[] = { protox, nsprotox, isoprotox, NULLPROTOX };
168 
169 struct	pte *Sysmap;
170 
171 char	*system = _PATH_UNIX;
172 char	*kmemf = _PATH_KMEM;
173 int	kmem;
174 int	kflag;
175 int	Aflag;
176 int	aflag;
177 int	hflag;
178 int	iflag;
179 int	mflag;
180 int	nflag;
181 int	pflag;
182 int	rflag;
183 int	sflag;
184 int	tflag;
185 int	dflag;
186 int	interval;
187 char	*interface;
188 int	unit;
189 
190 int	af = AF_UNSPEC;
191 
192 extern	char *malloc();
193 extern	off_t lseek();
194 
195 main(argc, argv)
196 	int argc;
197 	char *argv[];
198 {
199 	extern char *optarg;
200 	extern int optind;
201 	register struct protoent *p;
202 	register struct protox *tp;	/* for printing cblocks & stats */
203 	struct protox *name2protox();	/* for -p */
204 	int ch;
205 
206 	while ((ch = getopt(argc, argv, "AI:af:himnp:drstu")) != EOF)
207 		switch((char)ch) {
208 		case 'A':
209 			Aflag++;
210 			break;
211 		case 'I': {
212 			char *cp;
213 
214 			iflag++;
215 			for (cp = interface = optarg; isalpha(*cp); cp++);
216 			unit = atoi(cp);
217 			*cp = '\0';
218 			break;
219 		}
220 		case 'a':
221 			aflag++;
222 			break;
223 		case 'd':
224 			dflag++;
225 			break;
226 		case 'f':
227 			if (strcmp(optarg, "ns") == 0)
228 				af = AF_NS;
229 			else if (strcmp(optarg, "inet") == 0)
230 				af = AF_INET;
231 			else if (strcmp(optarg, "unix") == 0)
232 				af = AF_UNIX;
233 			else if (strcmp(optarg, "iso") == 0)
234 				af = AF_ISO;
235 			else {
236 				fprintf(stderr, "%s: unknown address family\n", optarg);
237 				exit(10);
238 			}
239 			break;
240 		case 'h':
241 			hflag++;
242 			break;
243 		case 'i':
244 			iflag++;
245 			break;
246 		case 'm':
247 			mflag++;
248 			break;
249 		case 'n':
250 			nflag++;
251 			break;
252 		case 'p':
253 			if ((tp = name2protox(optarg)) == NULLPROTOX) {
254 				fprintf(stderr, "%s: unknown or uninstrumented protocol\n", optarg);
255 				exit(10);
256 			}
257 			pflag++;
258 			break;
259 		case 'r':
260 			rflag++;
261 			break;
262 		case 's':
263 			sflag++;
264 			break;
265 		case 't':
266 			tflag++;
267 			break;
268 		case 'u':
269 			af = AF_UNIX;
270 			break;
271 		case '?':
272 		default:
273 			usage();
274 		}
275 	argv += optind;
276 	argc -= optind;
277 
278 	if (argc > 0) {
279 		if (isdigit(argv[0][0])) {
280 			interval = atoi(argv[0]);
281 			if (interval <= 0)
282 				usage();
283 			argv++, argc--;
284 			iflag++;
285 		}
286 		if (argc > 0) {
287 			system = *argv;
288 			argv++, argc--;
289 			if (argc > 0) {
290 				kmemf = *argv;
291 				kflag++;
292 			}
293 		}
294 	}
295 	if (nlist(system, nl) < 0 || nl[0].n_type == 0) {
296 		fprintf(stderr, "%s: no namelist\n", system);
297 		exit(1);
298 	}
299 	kmem = open(kmemf, O_RDONLY);
300 	if (kmem < 0) {
301 		perror(kmemf);
302 		exit(1);
303 	}
304 	if (kflag) {
305 		off_t off;
306 
307 		Sysmap = (struct pte *)
308 		   malloc((u_int)(nl[N_SYSSIZE].n_value * sizeof(struct pte)));
309 		if (!Sysmap) {
310 			fputs("netstat: can't get memory for Sysmap.\n", stderr);
311 			exit(1);
312 		}
313 		off = nl[N_SYSMAP].n_value & ~KERNBASE;
314 		(void)lseek(kmem, off, L_SET);
315 		(void)read(kmem, (char *)Sysmap,
316 		    (int)(nl[N_SYSSIZE].n_value * sizeof(struct pte)));
317 	}
318 	if (mflag) {
319 		mbpr((off_t)nl[N_MBSTAT].n_value);
320 		exit(0);
321 	}
322 	if (pflag) {
323 		if (tp->pr_stats)
324 			(*tp->pr_stats)(nl[tp->pr_sindex].n_value,
325 				tp->pr_name);
326 		else
327 			printf("%s: no stats routine\n", tp->pr_name);
328 		exit(0);
329 	}
330 	if (hflag) {
331 		hostpr(nl[N_IMP].n_value, nl[N_NIMP].n_value);
332 		exit(0);
333 	}
334 	/*
335 	 * Keep file descriptors open to avoid overhead
336 	 * of open/close on each call to get* routines.
337 	 */
338 	sethostent(1);
339 	setnetent(1);
340 	if (iflag) {
341 		intpr(interval, nl[N_IFNET].n_value);
342 		exit(0);
343 	}
344 	if (rflag) {
345 		if (sflag)
346 			rt_stats((off_t)nl[N_RTSTAT].n_value);
347 		else
348 			routepr((off_t)nl[N_RTHOST].n_value,
349 				(off_t)nl[N_RTNET].n_value,
350 				(off_t)nl[N_RTHASHSIZE].n_value,
351 				(off_t)nl[N_RTREE].n_value);
352 		exit(0);
353 	}
354     if (af == AF_INET || af == AF_UNSPEC) {
355 	setprotoent(1);
356 	setservent(1);
357 	while (p = getprotoent()) {
358 
359 		for (tp = protox; tp->pr_name; tp++)
360 			if (strcmp(tp->pr_name, p->p_name) == 0)
361 				break;
362 		if (tp->pr_name == 0 || tp->pr_wanted == 0)
363 			continue;
364 		if (sflag) {
365 			if (tp->pr_stats)
366 				(*tp->pr_stats)(nl[tp->pr_sindex].n_value,
367 					p->p_name);
368 		} else
369 			if (tp->pr_cblocks)
370 				(*tp->pr_cblocks)(nl[tp->pr_index].n_value,
371 					p->p_name);
372 	}
373 	endprotoent();
374     }
375     if (af == AF_NS || af == AF_UNSPEC) {
376 	for (tp = nsprotox; tp->pr_name; tp++) {
377 		if (sflag) {
378 			if (tp->pr_stats)
379 				(*tp->pr_stats)(nl[tp->pr_sindex].n_value,
380 					tp->pr_name);
381 		} else
382 			if (tp->pr_cblocks)
383 				(*tp->pr_cblocks)(nl[tp->pr_index].n_value,
384 					tp->pr_name);
385 	}
386     }
387     if (af == AF_ISO || af == AF_UNSPEC) {
388 	for (tp = isoprotox; tp->pr_name; tp++) {
389 		if (sflag) {
390 			if (tp->pr_stats)
391 				(*tp->pr_stats)(nl[tp->pr_sindex].n_value,
392 					tp->pr_name);
393 		} else
394 			if (tp->pr_cblocks)
395 				(*tp->pr_cblocks)(nl[tp->pr_index].n_value,
396 					tp->pr_name);
397 	}
398     }
399     if ((af == AF_UNIX || af == AF_UNSPEC) && !sflag)
400 	    unixpr((off_t)nl[N_NFILE].n_value, (off_t)nl[N_FILE].n_value,
401 		(struct protosw *)nl[N_UNIXSW].n_value);
402     if (af == AF_UNSPEC && sflag)
403 	impstats(nl[N_IMP].n_value, nl[N_NIMP].n_value);
404     exit(0);
405 }
406 
407 /*
408  * Seek into the kernel for a value.
409  */
410 off_t
411 klseek(fd, base, off)
412 	int fd, off;
413 	off_t base;
414 {
415 	if (kflag) {
416 		/* get kernel pte */
417 		base &= ~KERNBASE;
418 		base = ctob(Sysmap[btop(base)].pg_pfnum) + (base & PGOFSET);
419 	}
420 	return (lseek(fd, base, off));
421 }
422 
423 char *
424 plural(n)
425 	int n;
426 {
427 
428 	return (n != 1 ? "s" : "");
429 }
430 
431 /*
432  * Find the protox for the given "well-known" name.
433  */
434 struct protox *
435 knownname(name)
436 	char *name;
437 {
438 	struct protox **tpp, *tp;
439 
440 	for (tpp = protoprotox; *tpp; tpp++)
441 	    for (tp = *tpp; tp->pr_name; tp++)
442 		if (strcmp(tp->pr_name, name) == 0)
443 			return(tp);
444 	return(NULLPROTOX);
445 }
446 
447 /*
448  * Find the protox corresponding to name.
449  */
450 struct protox *
451 name2protox(name)
452 	char *name;
453 {
454 	struct protox *tp;
455 	char **alias;			/* alias from p->aliases */
456 	struct protoent *p;
457 
458 	/*
459 	 * Try to find the name in the list of "well-known" names. If that
460 	 * fails, check if name is an alias for an Internet protocol.
461 	 */
462 	if (tp = knownname(name))
463 		return(tp);
464 
465 	setprotoent(1);			/* make protocol lookup cheaper */
466 	while (p = getprotoent()) {
467 		/* assert: name not same as p->name */
468 		for (alias = p->p_aliases; *alias; alias++)
469 			if (strcmp(name, *alias) == 0) {
470 				endprotoent();
471 				return(knownname(p->p_name));
472 			}
473 	}
474 	endprotoent();
475 	return(NULLPROTOX);
476 }
477 
478 usage()
479 {
480 	fputs("usage: netstat [-Aan] [-f address_family] [system] [core]\n               [-himnrs] [-f address_family] [system] [core]\n               [-n] [-I interface] interval [system] [core]\n", stderr);
481 	exit(1);
482 }
483