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