xref: /openbsd-src/usr.bin/netstat/if.c (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
1 /*	$OpenBSD: if.c,v 1.24 2001/07/18 17:17:39 pvalchev Exp $	*/
2 /*	$NetBSD: if.c,v 1.16.4.2 1996/06/07 21:46:46 thorpej Exp $	*/
3 
4 /*
5  * Copyright (c) 1983, 1988, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by the University of
19  *	California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36 
37 #ifndef lint
38 #if 0
39 static char sccsid[] = "from: @(#)if.c	8.2 (Berkeley) 2/21/94";
40 #else
41 static char *rcsid = "$OpenBSD: if.c,v 1.24 2001/07/18 17:17:39 pvalchev Exp $";
42 #endif
43 #endif /* not lint */
44 
45 #include <sys/types.h>
46 #include <sys/protosw.h>
47 #include <sys/socket.h>
48 
49 #include <net/if.h>
50 #include <net/if_dl.h>
51 #include <net/if_types.h>
52 #include <netinet/in.h>
53 #include <netinet/in_var.h>
54 #include <netinet/if_ether.h>
55 #include <netns/ns.h>
56 #include <netns/ns_if.h>
57 #include <netipx/ipx.h>
58 #include <netipx/ipx_if.h>
59 #include <netiso/iso.h>
60 #include <netiso/iso_var.h>
61 #include <arpa/inet.h>
62 
63 #include <limits.h>
64 #include <signal.h>
65 #include <stdio.h>
66 #include <string.h>
67 #include <unistd.h>
68 
69 #include "netstat.h"
70 
71 #define	YES	1
72 #define	NO	0
73 
74 static void sidewaysintpr __P((u_int, u_long));
75 static void catchalarm __P((int));
76 
77 /*
78  * Print a description of the network interfaces.
79  * NOTE: ifnetaddr is the location of the kernel global "ifnet",
80  * which is a TAILQ_HEAD.
81  */
82 void
83 intpr(interval, ifnetaddr)
84 	int interval;
85 	u_long ifnetaddr;
86 {
87 	struct ifnet ifnet;
88 	union {
89 		struct ifaddr ifa;
90 		struct in_ifaddr in;
91 #ifdef INET6
92 		struct in6_ifaddr in6;
93 #endif
94 		struct ns_ifaddr ns;
95 		struct ipx_ifaddr ipx;
96 		struct iso_ifaddr iso;
97 	} ifaddr;
98 	u_long ifaddraddr;
99 	struct sockaddr *sa;
100 	struct ifnet_head ifhead;	/* TAILQ_HEAD */
101 	char name[IFNAMSIZ];
102 
103 	if (ifnetaddr == 0) {
104 		printf("ifnet: symbol not defined\n");
105 		return;
106 	}
107 	if (interval) {
108 		sidewaysintpr((unsigned)interval, ifnetaddr);
109 		return;
110 	}
111 
112 	/*
113 	 * Find the pointer to the first ifnet structure.  Replace
114 	 * the pointer to the TAILQ_HEAD with the actual pointer
115 	 * to the first list element.
116 	 */
117 	if (kread(ifnetaddr, (char *)&ifhead, sizeof ifhead))
118 		return;
119 	ifnetaddr = (u_long)ifhead.tqh_first;
120 
121 	printf("%-7.7s %-5.5s %-11.11s %-17.17s ",
122 	       "Name", "Mtu", "Network", "Address");
123 	if (bflag)
124 		printf("%10.10s %10.10s", "Ibytes", "Obytes");
125 	else
126 		printf("%8.8s %5.5s %8.8s %5.5s %5.5s",
127 		    "Ipkts", "Ierrs", "Opkts", "Oerrs", "Colls");
128 	if (tflag)
129 		printf(" %s", "Time");
130 	if (dflag)
131 		printf(" %s", "Drop");
132 	putchar('\n');
133 	ifaddraddr = 0;
134 	while (ifnetaddr || ifaddraddr) {
135 		struct sockaddr_in *sin;
136 #ifdef INET6
137 		struct sockaddr_in6 *sin6;
138 #endif
139 		register char *cp;
140 		int n, m;
141 
142 		if (ifaddraddr == 0) {
143 			if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet))
144 				return;
145 			bcopy(ifnet.if_xname, name, IFNAMSIZ);
146 			name[IFNAMSIZ - 1] = '\0';	/* sanity */
147 			ifnetaddr = (u_long)ifnet.if_list.tqe_next;
148 			if (interface != 0 && strcmp(name, interface) != 0)
149 				continue;
150 			cp = strchr(name, '\0');
151 			if ((ifnet.if_flags & IFF_UP) == 0)
152 				*cp++ = '*';
153 			*cp = '\0';
154 			ifaddraddr = (u_long)ifnet.if_addrlist.tqh_first;
155 		}
156 		printf("%-7.7s %-5ld ", name, ifnet.if_mtu);
157 		if (ifaddraddr == 0) {
158 			printf("%-11.11s ", "none");
159 			printf("%-15.15s ", "none");
160 		} else {
161 			if (kread(ifaddraddr, (char *)&ifaddr, sizeof ifaddr)) {
162 				ifaddraddr = 0;
163 				continue;
164 			}
165 #define CP(x) ((char *)(x))
166 			cp = (CP(ifaddr.ifa.ifa_addr) - CP(ifaddraddr)) +
167 				CP(&ifaddr); sa = (struct sockaddr *)cp;
168 			switch (sa->sa_family) {
169 			case AF_UNSPEC:
170 				printf("%-11.11s ", "none");
171 				printf("%-17.17s ", "none");
172 				break;
173 			case AF_INET:
174 				sin = (struct sockaddr_in *)sa;
175 #ifdef notdef
176 				/* can't use inet_makeaddr because kernel
177 				 * keeps nets unshifted.
178 				 */
179 				in = inet_makeaddr(ifaddr.in.ia_subnet,
180 					INADDR_ANY);
181 				cp = netname(in.s_addr,
182 			    	    ifaddr.in.ia_subnetmask);
183 #else
184 				cp = netname(ifaddr.in.ia_subnet,
185 				    ifaddr.in.ia_subnetmask);
186 #endif
187 				if (vflag)
188 					n = strlen(cp) < 11 ? 11 : strlen(cp);
189 				else
190 					n = 11;
191 				printf("%-*.*s ", n, n, cp);
192 				cp = routename(sin->sin_addr.s_addr);
193 				if (vflag)
194 					n = strlen(cp) < 17 ? 17 : strlen(cp);
195 				else
196 					n = 17;
197 				printf("%-*.*s ", n, n, cp);
198 
199 				if (aflag) {
200 					u_long multiaddr;
201 					struct in_multi inm;
202 
203 					multiaddr = (u_long)ifaddr.in.ia_multiaddrs.lh_first;
204 					while (multiaddr != 0) {
205 						kread(multiaddr, (char *)&inm,
206 						    sizeof inm);
207 						printf("\n%25s %-17.17s ", "",
208 						    routename(inm.inm_addr.s_addr));
209 						multiaddr = (u_long)inm.inm_list.le_next;
210 					}
211 				}
212 				break;
213 #ifdef INET6
214 			case AF_INET6:
215 				sin6 = (struct sockaddr_in6 *)sa;
216 #ifdef KAME_SCOPEID
217 				if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
218 					sin6->sin6_scope_id =
219 						ntohs(*(u_int16_t *)
220 						  &sin6->sin6_addr.s6_addr[2]);
221 					/* too little width */
222 					if (!vflag)
223 						sin6->sin6_scope_id = 0;
224 					sin6->sin6_addr.s6_addr[2] = 0;
225 					sin6->sin6_addr.s6_addr[3] = 0;
226 				}
227 #endif
228 				cp = netname6(&ifaddr.in6.ia_addr,
229 					&ifaddr.in6.ia_prefixmask.sin6_addr);
230 				if (vflag)
231 					n = strlen(cp) < 11 ? 11 : strlen(cp);
232 				else
233 					n = 11;
234 				printf("%-*.*s ", n, n, cp);
235 				cp = routename6(sin6);
236 				if (vflag)
237 					n = strlen(cp) < 17 ? 17 : strlen(cp);
238 				else
239 					n = 17;
240 				printf("%-*.*s ", n, n, cp);
241 				if (aflag) {
242 					u_long multiaddr;
243 					struct in6_multi inm;
244 					char hbuf[INET6_ADDRSTRLEN];
245 
246 					multiaddr = (u_long)ifaddr.in6.ia6_multiaddrs.lh_first;
247 					while (multiaddr != 0) {
248 						kread(multiaddr, (char *)&inm,
249 						    sizeof inm);
250 						inet_ntop(AF_INET6, &inm.in6m_addr,
251 							hbuf, sizeof(hbuf));
252 						if (vflag)
253 							n = strlen(hbuf) < 17 ? 17 : strlen(hbuf);
254 						else
255 							n = 17;
256 						printf("\n%25s %-*.*s ", "",
257 						    n, n, hbuf);
258 						multiaddr = (u_long)inm.in6m_entry.le_next;
259 					}
260 				}
261 				break;
262 #endif
263 			case AF_IPX:
264 				{
265 				struct sockaddr_ipx *sipx =
266 					(struct sockaddr_ipx *)sa;
267 				u_long net;
268 				char netnum[8];
269 
270 				*(union ipx_net *)&net = sipx->sipx_addr.ipx_net;
271 				snprintf(netnum, sizeof netnum, "%xH",
272 				    ntohl(net));
273 				upHex(netnum);
274 				printf("ipx:%-8s", netnum);
275 				printf("%-17s ",
276 				    ipx_phost((struct sockaddr *)sipx));
277 				}
278 				break;
279 			case AF_APPLETALK:
280 				printf("atlk:%-12s",atalk_print(sa,0x10) );
281 				printf("%-12s ",atalk_print(sa,0x0b) );
282 				break;
283 			case AF_NS:
284 				{
285 				struct sockaddr_ns *sns =
286 					(struct sockaddr_ns *)sa;
287 				u_long net;
288 				char netnum[8];
289 
290 				*(union ns_net *)&net = sns->sns_addr.x_net;
291 				snprintf(netnum, sizeof netnum, "%xH",
292 				    ntohl(net));
293 				upHex(netnum);
294 				printf("ns:%-8s ", netnum);
295 				printf("%-17s ",
296 				    ns_phost((struct sockaddr *)sns));
297 				}
298 				break;
299 			case AF_LINK:
300 				{
301 				struct sockaddr_dl *sdl =
302 					(struct sockaddr_dl *)sa;
303 				m = printf("%-11.11s ", "<Link>");
304 				if (sdl->sdl_type == IFT_ETHER ||
305 				    sdl->sdl_type == IFT_FDDI ||
306 				    sdl->sdl_type == IFT_ISO88025)
307 					printf("%-17.17s ",
308 					    ether_ntoa((struct ether_addr *)LLADDR(sdl)));
309 				else {
310 					cp = (char *)LLADDR(sdl);
311 					n = sdl->sdl_alen;
312 					goto hexprint;
313 				}
314 				}
315 				break;
316 			default:
317 				m = printf("(%d)", sa->sa_family);
318 				for (cp = sa->sa_len + (char *)sa;
319 					--cp > sa->sa_data && (*cp == 0);) {}
320 				n = cp - sa->sa_data + 1;
321 				cp = sa->sa_data;
322 			hexprint:
323 				while (--n >= 0)
324 					m += printf("%x%c", *cp++ & 0xff,
325 						    n > 0 ? '.' : ' ');
326 				m = 30 - m;
327 				while (m-- > 0)
328 					putchar(' ');
329 				break;
330 			}
331 			ifaddraddr = (u_long)ifaddr.ifa.ifa_list.tqe_next;
332 		}
333 		if (bflag)
334 			printf("%10lu %10lu",
335 			    ifnet.if_ibytes, ifnet.if_obytes);
336 		else
337 			printf("%8lu %5lu %8lu %5lu %5lu",
338 			    ifnet.if_ipackets, ifnet.if_ierrors,
339 			    ifnet.if_opackets, ifnet.if_oerrors,
340 			    ifnet.if_collisions);
341 		if (tflag)
342 			printf(" %4d", ifnet.if_timer);
343 		if (dflag)
344 			printf(" %4d", ifnet.if_snd.ifq_drops);
345 		putchar('\n');
346 	}
347 }
348 
349 #define	MAXIF	100
350 struct	iftot {
351 	char	ift_name[IFNAMSIZ];	/* interface name */
352 	int	ift_ip;			/* input packets */
353 	int	ift_ib;			/* input bytes */
354 	int	ift_ie;			/* input errors */
355 	int	ift_op;			/* output packets */
356 	int	ift_ob;			/* output bytes */
357 	int	ift_oe;			/* output errors */
358 	int	ift_co;			/* collisions */
359 	int	ift_dr;			/* drops */
360 } iftot[MAXIF];
361 
362 u_char	signalled;			/* set if alarm goes off "early" */
363 
364 /*
365  * Print a running summary of interface statistics.
366  * Repeat display every interval seconds, showing statistics
367  * collected over that interval.  Assumes that interval is non-zero.
368  * First line printed at top of screen is always cumulative.
369  */
370 static void
371 sidewaysintpr(interval, off)
372 	unsigned interval;
373 	u_long off;
374 {
375 	struct ifnet ifnet;
376 	u_long firstifnet;
377 	register struct iftot *ip, *total;
378 	register int line;
379 	struct iftot *lastif, *sum, *interesting;
380 	struct ifnet_head ifhead;	/* TAILQ_HEAD */
381 	int oldmask;
382 
383 	/*
384 	 * Find the pointer to the first ifnet structure.  Replace
385 	 * the pointer to the TAILQ_HEAD with the actual pointer
386 	 * to the first list element.
387 	 */
388 	if (kread(off, (char *)&ifhead, sizeof ifhead))
389 		return;
390 	firstifnet = (u_long)ifhead.tqh_first;
391 
392 	lastif = iftot;
393 	sum = iftot + MAXIF - 1;
394 	total = sum - 1;
395 	interesting = (interface == NULL) ? iftot : NULL;
396 	for (off = firstifnet, ip = iftot; off;) {
397 		if (kread(off, (char *)&ifnet, sizeof ifnet))
398 			break;
399 		bzero(ip->ift_name, sizeof(ip->ift_name));
400 		snprintf(ip->ift_name, IFNAMSIZ, "%s", ifnet.if_xname);
401 		if (interface && strcmp(ifnet.if_xname, interface) == 0)
402 			interesting = ip;
403 		ip++;
404 		if (ip >= iftot + MAXIF - 2)
405 			break;
406 		off = (u_long)ifnet.if_list.tqe_next;
407 	}
408 	if (interesting == NULL) {
409 		fprintf(stderr, "%s: %s: unknown interface\n",
410 		    __progname, interface);
411 		exit(1);
412 	}
413 	lastif = ip;
414 
415 	(void)signal(SIGALRM, catchalarm);
416 	signalled = NO;
417 	(void)alarm(interval);
418 banner:
419 	if (bflag)
420 		printf("%7.7s in %8.8s %6.6s out %5.5s",
421 		    interesting->ift_name, " ",
422 		    interesting->ift_name, " ");
423 	else
424 		printf("%5.5s in %5.5s%5.5s out %5.5s %5.5s",
425 		    interesting->ift_name, " ",
426 		    interesting->ift_name, " ", " ");
427 	if (dflag)
428 		printf(" %5.5s", " ");
429 	if (lastif - iftot > 0) {
430 		if (bflag)
431 			printf("  %7.7s in %8.8s %6.6s out %5.5s",
432 			    "total", " ", "total", " ");
433 		else
434 			printf("  %5.5s in %5.5s%5.5s out %5.5s %5.5s",
435 			    "total", " ", "total", " ", " ");
436 		if (dflag)
437 			printf(" %5.5s", " ");
438 	}
439 	for (ip = iftot; ip < iftot + MAXIF; ip++) {
440 		ip->ift_ip = 0;
441 		ip->ift_ib = 0;
442 		ip->ift_ie = 0;
443 		ip->ift_op = 0;
444 		ip->ift_ob = 0;
445 		ip->ift_oe = 0;
446 		ip->ift_co = 0;
447 		ip->ift_dr = 0;
448 	}
449 	putchar('\n');
450 	if (bflag)
451 		printf("%10.10s %8.8s %10.10s %5.5s",
452 		    "bytes", " ", "bytes", " ");
453 	else
454 		printf("%8.8s %5.5s %8.8s %5.5s %5.5s",
455 		    "packets", "errs", "packets", "errs", "colls");
456 	if (dflag)
457 		printf(" %5.5s", "drops");
458 	if (lastif - iftot > 0) {
459 		if (bflag)
460 			printf("  %10.10s %8.8s %10.10s %5.5s",
461 			    "bytes", " ", "bytes", " ");
462 		else
463 			printf("  %8.8s %5.5s %8.8s %5.5s %5.5s",
464 			    "packets", "errs", "packets", "errs", "colls");
465 		if (dflag)
466 			printf(" %5.5s", "drops");
467 	}
468 	putchar('\n');
469 	fflush(stdout);
470 	line = 0;
471 loop:
472 	sum->ift_ip = 0;
473 	sum->ift_ib = 0;
474 	sum->ift_ie = 0;
475 	sum->ift_op = 0;
476 	sum->ift_ob = 0;
477 	sum->ift_oe = 0;
478 	sum->ift_co = 0;
479 	sum->ift_dr = 0;
480 	for (off = firstifnet, ip = iftot; off && ip < lastif; ip++) {
481 		if (kread(off, (char *)&ifnet, sizeof ifnet)) {
482 			off = 0;
483 			continue;
484 		}
485 		if (ip == interesting) {
486 			if (bflag)
487 				printf("%10lu %8.8s %10lu %5.5s",
488 				    ifnet.if_ibytes - ip->ift_ib, " ",
489 				    ifnet.if_obytes - ip->ift_ob, " ");
490 			else
491 				printf("%8lu %5lu %8lu %5lu %5lu",
492 				    ifnet.if_ipackets - ip->ift_ip,
493 				    ifnet.if_ierrors - ip->ift_ie,
494 				    ifnet.if_opackets - ip->ift_op,
495 				    ifnet.if_oerrors - ip->ift_oe,
496 				    ifnet.if_collisions - ip->ift_co);
497 			if (dflag)
498 				printf(" %5d",
499 				    ifnet.if_snd.ifq_drops - ip->ift_dr);
500 		}
501 		ip->ift_ip = ifnet.if_ipackets;
502 		ip->ift_ib = ifnet.if_ibytes;
503 		ip->ift_ie = ifnet.if_ierrors;
504 		ip->ift_op = ifnet.if_opackets;
505 		ip->ift_ob = ifnet.if_obytes;
506 		ip->ift_oe = ifnet.if_oerrors;
507 		ip->ift_co = ifnet.if_collisions;
508 		ip->ift_dr = ifnet.if_snd.ifq_drops;
509 		sum->ift_ip += ip->ift_ip;
510 		sum->ift_ib += ip->ift_ib;
511 		sum->ift_ie += ip->ift_ie;
512 		sum->ift_op += ip->ift_op;
513 		sum->ift_ob += ip->ift_ob;
514 		sum->ift_oe += ip->ift_oe;
515 		sum->ift_co += ip->ift_co;
516 		sum->ift_dr += ip->ift_dr;
517 		off = (u_long)ifnet.if_list.tqe_next;
518 	}
519 	if (lastif - iftot > 0) {
520 		if (bflag)
521 			printf("  %10lu %8.8s %10lu %5.5s",
522 			    (unsigned long)sum->ift_ib -  total->ift_ib, " ",
523 			    (unsigned long)sum->ift_ob -  total->ift_ob, " ");
524 		else
525 			printf("  %8lu %5lu %8lu %5lu %5lu",
526 			    (unsigned long)sum->ift_ip - total->ift_ip,
527 			    (unsigned long)sum->ift_ie - total->ift_ie,
528 			    (unsigned long)sum->ift_op - total->ift_op,
529 			    (unsigned long)sum->ift_oe - total->ift_oe,
530 			    (unsigned long)sum->ift_co - total->ift_co);
531 		if (dflag)
532 			printf(" %5d", sum->ift_dr - total->ift_dr);
533 	}
534 	*total = *sum;
535 	putchar('\n');
536 	fflush(stdout);
537 	line++;
538 	oldmask = sigblock(sigmask(SIGALRM));
539 	if (! signalled) {
540 		sigpause(0);
541 	}
542 	sigsetmask(oldmask);
543 	signalled = NO;
544 	(void)alarm(interval);
545 	if (line == 21)
546 		goto banner;
547 	goto loop;
548 	/*NOTREACHED*/
549 }
550 
551 /*
552  * Called if an interval expires before sidewaysintpr has completed a loop.
553  * Sets a flag to not wait for the alarm.
554  */
555 static void
556 catchalarm(signo)
557 	int signo;
558 {
559 	signalled = YES;
560 }
561