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