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