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