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