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