1 /* $NetBSD: if.c,v 1.48 2001/04/06 05:10:28 itojun 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. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include <sys/cdefs.h> 37 #ifndef lint 38 #if 0 39 static char sccsid[] = "from: @(#)if.c 8.2 (Berkeley) 2/21/94"; 40 #else 41 __RCSID("$NetBSD: if.c,v 1.48 2001/04/06 05:10:28 itojun Exp $"); 42 #endif 43 #endif /* not lint */ 44 45 #include <sys/types.h> 46 #include <sys/protosw.h> 47 #include <sys/socket.h> 48 49 #include <net/if.h> 50 #include <net/if_dl.h> 51 #include <net/if_types.h> 52 #include <netinet/in.h> 53 #include <netinet/in_var.h> 54 #include <netns/ns.h> 55 #include <netns/ns_if.h> 56 #include <netiso/iso.h> 57 #include <netiso/iso_var.h> 58 #include <arpa/inet.h> 59 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 struct ns_ifaddr ns; 94 struct iso_ifaddr iso; 95 } ifaddr; 96 u_long ifaddraddr; 97 struct sockaddr *sa; 98 struct ifnet_head ifhead; /* TAILQ_HEAD */ 99 char name[IFNAMSIZ + 1]; /* + 1 for `*' */ 100 #ifdef INET6 101 char hbuf[NI_MAXHOST]; /* for getnameinfo() */ 102 #ifdef KAME_SCOPEID 103 const int niflag = NI_NUMERICHOST | NI_WITHSCOPEID; 104 #else 105 const int niflag = NI_NUMERICHOST; 106 #endif 107 #endif 108 109 if (ifnetaddr == 0) { 110 printf("ifnet: symbol not defined\n"); 111 return; 112 } 113 if (interval) { 114 sidewaysintpr((unsigned)interval, ifnetaddr); 115 return; 116 } 117 118 /* 119 * Find the pointer to the first ifnet structure. Replace 120 * the pointer to the TAILQ_HEAD with the actual pointer 121 * to the first list element. 122 */ 123 if (kread(ifnetaddr, (char *)&ifhead, sizeof ifhead)) 124 return; 125 ifnetaddr = (u_long)ifhead.tqh_first; 126 127 if (!sflag & !pflag) { 128 if (bflag) { 129 printf("%-5.5s %-5.5s %-13.13s %-17.17s " 130 "%10.10s %10.10s", 131 "Name", "Mtu", "Network", "Address", 132 "Ibytes", "Obytes"); 133 } else { 134 printf("%-5.5s %-5.5s %-13.13s %-17.17s " 135 "%8.8s %5.5s %8.8s %5.5s %5.5s", 136 "Name", "Mtu", "Network", "Address", "Ipkts", "Ierrs", 137 "Opkts", "Oerrs", "Colls"); 138 } 139 if (tflag) 140 printf(" %4.4s", "Time"); 141 if (dflag) 142 printf(" %5.5s", "Drops"); 143 putchar('\n'); 144 } 145 ifaddraddr = 0; 146 while (ifnetaddr || ifaddraddr) { 147 struct sockaddr_in *sin; 148 #ifdef INET6 149 struct sockaddr_in6 *sin6; 150 #endif /* INET6 */ 151 char *cp; 152 int n, m; 153 154 if (ifaddraddr == 0) { 155 if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet)) 156 return; 157 memmove(name, ifnet.if_xname, IFNAMSIZ); 158 name[IFNAMSIZ - 1] = '\0'; /* sanity */ 159 ifnetaddr = (u_long)ifnet.if_list.tqe_next; 160 if (interface != 0 && strcmp(name, interface) != 0) 161 continue; 162 cp = strchr(name, '\0'); 163 164 if (pfunc) { 165 (*pfunc)(name); 166 continue; 167 } 168 169 if ((ifnet.if_flags & IFF_UP) == 0) 170 *cp++ = '*'; 171 *cp = '\0'; 172 ifaddraddr = (u_long)ifnet.if_addrlist.tqh_first; 173 } 174 if (vflag) 175 n = strlen(name) < 5 ? 5 : strlen(name); 176 else 177 n = 5; 178 printf("%-*.*s %-5llu ", n, n, name, 179 (unsigned long long)ifnet.if_mtu); 180 if (ifaddraddr == 0) { 181 printf("%-13.13s ", "none"); 182 printf("%-17.17s ", "none"); 183 } else { 184 char hexsep = '.'; /* for hexprint */ 185 const char hexfmt[] = "%02x%c"; /* for hexprint */ 186 if (kread(ifaddraddr, (char *)&ifaddr, sizeof ifaddr)) { 187 ifaddraddr = 0; 188 continue; 189 } 190 #define CP(x) ((char *)(x)) 191 cp = (CP(ifaddr.ifa.ifa_addr) - CP(ifaddraddr)) + 192 CP(&ifaddr); sa = (struct sockaddr *)cp; 193 switch (sa->sa_family) { 194 case AF_UNSPEC: 195 printf("%-13.13s ", "none"); 196 printf("%-17.17s ", "none"); 197 break; 198 case AF_INET: 199 sin = (struct sockaddr_in *)sa; 200 #ifdef notdef 201 /* 202 * can't use inet_makeaddr because kernel 203 * keeps nets unshifted. 204 */ 205 in = inet_makeaddr(ifaddr.in.ia_subnet, 206 INADDR_ANY); 207 cp = netname(in.s_addr, 208 ifaddr.in.ia_subnetmask); 209 #else 210 cp = netname(ifaddr.in.ia_subnet, 211 ifaddr.in.ia_subnetmask); 212 #endif 213 if (vflag) 214 n = strlen(cp) < 13 ? 13 : strlen(cp); 215 else 216 n = 13; 217 printf("%-*.*s ", n, n, cp); 218 cp = routename(sin->sin_addr.s_addr); 219 if (vflag) 220 n = strlen(cp) < 17 ? 17 : strlen(cp); 221 else 222 n = 17; 223 printf("%-*.*s ", n, n, cp); 224 if (aflag) { 225 u_long multiaddr; 226 struct in_multi inm; 227 228 multiaddr = (u_long) 229 ifaddr.in.ia_multiaddrs.lh_first; 230 while (multiaddr != 0) { 231 kread(multiaddr, (char *)&inm, 232 sizeof inm); 233 printf("\n%25s %-17.17s ", "", 234 routename( 235 inm.inm_addr.s_addr)); 236 multiaddr = 237 (u_long)inm.inm_list.le_next; 238 } 239 } 240 break; 241 #ifdef INET6 242 case AF_INET6: 243 sin6 = (struct sockaddr_in6 *)sa; 244 #ifdef KAME_SCOPEID 245 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { 246 sin6->sin6_scope_id = 247 ntohs(*(u_int16_t *) 248 &sin6->sin6_addr.s6_addr[2]); 249 /* too little width */ 250 if (!vflag) 251 sin6->sin6_scope_id = 0; 252 sin6->sin6_addr.s6_addr[2] = 0; 253 sin6->sin6_addr.s6_addr[3] = 0; 254 } 255 #endif 256 cp = netname6(&ifaddr.in6.ia_addr, 257 &ifaddr.in6.ia_prefixmask.sin6_addr); 258 if (vflag) 259 n = strlen(cp) < 13 ? 13 : strlen(cp); 260 else 261 n = 13; 262 printf("%-*.*s ", n, n, cp); 263 if (getnameinfo((struct sockaddr *)sin6, 264 sin6->sin6_len, 265 hbuf, sizeof(hbuf), NULL, 0, 266 niflag) != 0) { 267 cp = "?"; 268 } else 269 cp = hbuf; 270 if (vflag) 271 n = strlen(cp) < 17 ? 17 : strlen(cp); 272 else 273 n = 17; 274 printf("%-*.*s ", n, n, cp); 275 if (aflag) { 276 u_long multiaddr; 277 struct in6_multi inm; 278 struct sockaddr_in6 sin6; 279 280 multiaddr = (u_long) 281 ifaddr.in6.ia6_multiaddrs.lh_first; 282 while (multiaddr != 0) { 283 kread(multiaddr, (char *)&inm, 284 sizeof inm); 285 memset(&sin6, 0, sizeof(sin6)); 286 sin6.sin6_len = sizeof(struct sockaddr_in6); 287 sin6.sin6_family = AF_INET6; 288 sin6.sin6_addr = inm.in6m_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 if (getnameinfo((struct sockaddr *)&sin6, 295 sin6.sin6_len, hbuf, 296 sizeof(hbuf), NULL, 0, 297 niflag) != 0) { 298 strlcpy(hbuf, "??", 299 sizeof(hbuf)); 300 } 301 cp = hbuf; 302 if (vflag) 303 n = strlen(cp) < 17 304 ? 17 : strlen(cp); 305 else 306 n = 17; 307 printf("\n%25s %-*.*s ", "", 308 n, n, cp); 309 multiaddr = 310 (u_long)inm.in6m_entry.le_next; 311 } 312 } 313 break; 314 #endif /*INET6*/ 315 #ifndef SMALL 316 case AF_APPLETALK: 317 printf("atalk:%-7.7s ", 318 atalk_print(sa,0x10)); 319 printf("%-17.17s ", atalk_print(sa,0x0b)); 320 break; 321 case AF_NS: 322 { 323 struct sockaddr_ns *sns = 324 (struct sockaddr_ns *)sa; 325 u_long net; 326 char netnum[8]; 327 328 *(union ns_net *)&net = sns->sns_addr.x_net; 329 (void)snprintf(netnum, sizeof(netnum), "%xH", 330 (u_int32_t)ntohl(net)); 331 upHex(netnum); 332 printf("ns:%-10s ", netnum); 333 printf("%-17.17s ", 334 ns_phost((struct sockaddr *)sns)); 335 } 336 break; 337 #endif 338 case AF_LINK: 339 { 340 struct sockaddr_dl *sdl = 341 (struct sockaddr_dl *)sa; 342 cp = (char *)LLADDR(sdl); 343 if (sdl->sdl_type == IFT_FDDI 344 || sdl->sdl_type == IFT_ETHER 345 || sdl->sdl_type == IFT_IEEE1394) 346 hexsep = ':'; 347 n = sdl->sdl_alen; 348 if (sdl->sdl_type == IFT_IEEE1394 349 && sdl->sdl_len > 8) 350 n = 8; /* XXX */ 351 } 352 m = printf("%-13.13s ", "<Link>"); 353 goto hexprint; 354 default: 355 m = printf("(%d)", sa->sa_family); 356 for (cp = sa->sa_len + (char *)sa; 357 --cp > sa->sa_data && (*cp == 0);) {} 358 n = cp - sa->sa_data + 1; 359 cp = sa->sa_data; 360 hexprint: 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 ifnet ifnet; 418 u_long firstifnet; 419 struct iftot *ip, *total; 420 int line; 421 struct iftot *lastif, *sum, *interesting; 422 struct ifnet_head ifhead; /* TAILQ_HEAD */ 423 int oldmask; 424 425 /* 426 * Find the pointer to the first ifnet structure. Replace 427 * the pointer to the TAILQ_HEAD with the actual pointer 428 * to the first list element. 429 */ 430 if (kread(off, (char *)&ifhead, sizeof ifhead)) 431 return; 432 firstifnet = (u_long)ifhead.tqh_first; 433 434 lastif = iftot; 435 sum = iftot + MAXIF - 1; 436 total = sum - 1; 437 interesting = (interface == NULL) ? iftot : NULL; 438 for (off = firstifnet, ip = iftot; off;) { 439 if (kread(off, (char *)&ifnet, sizeof ifnet)) 440 break; 441 memset(ip->ift_name, 0, sizeof(ip->ift_name)); 442 snprintf(ip->ift_name, IFNAMSIZ, "%s", ifnet.if_xname); 443 if (interface && strcmp(ifnet.if_xname, interface) == 0) 444 interesting = ip; 445 ip++; 446 if (ip >= iftot + MAXIF - 2) 447 break; 448 off = (u_long)ifnet.if_list.tqe_next; 449 } 450 if (interesting == NULL) { 451 fprintf(stderr, "%s: %s: unknown interface\n", 452 getprogname(), interface); 453 exit(1); 454 } 455 lastif = ip; 456 457 (void)signal(SIGALRM, catchalarm); 458 signalled = NO; 459 (void)alarm(interval); 460 banner: 461 if (bflag) 462 printf("%7.7s in %8.8s %6.6s out %5.5s", 463 interesting->ift_name, " ", 464 interesting->ift_name, " "); 465 else 466 printf("%5.5s in %5.5s%5.5s out %5.5s %5.5s", 467 interesting->ift_name, " ", 468 interesting->ift_name, " ", " "); 469 if (dflag) 470 printf(" %5.5s", " "); 471 if (lastif - iftot > 0) { 472 if (bflag) 473 printf(" %7.7s in %8.8s %6.6s out %5.5s", 474 "total", " ", "total", " "); 475 else 476 printf(" %5.5s in %5.5s%5.5s out %5.5s %5.5s", 477 "total", " ", "total", " ", " "); 478 if (dflag) 479 printf(" %5.5s", " "); 480 } 481 for (ip = iftot; ip < iftot + MAXIF; ip++) { 482 ip->ift_ip = 0; 483 ip->ift_ib = 0; 484 ip->ift_ie = 0; 485 ip->ift_op = 0; 486 ip->ift_ob = 0; 487 ip->ift_oe = 0; 488 ip->ift_co = 0; 489 ip->ift_dr = 0; 490 } 491 putchar('\n'); 492 if (bflag) 493 printf("%10.10s %8.8s %10.10s %5.5s", 494 "bytes", " ", "bytes", " "); 495 else 496 printf("%8.8s %5.5s %8.8s %5.5s %5.5s", 497 "packets", "errs", "packets", "errs", "colls"); 498 if (dflag) 499 printf(" %5.5s", "drops"); 500 if (lastif - iftot > 0) { 501 if (bflag) 502 printf(" %10.10s %8.8s %10.10s %5.5s", 503 "bytes", " ", "bytes", " "); 504 else 505 printf(" %8.8s %5.5s %8.8s %5.5s %5.5s", 506 "packets", "errs", "packets", "errs", "colls"); 507 if (dflag) 508 printf(" %5.5s", "drops"); 509 } 510 putchar('\n'); 511 fflush(stdout); 512 line = 0; 513 loop: 514 sum->ift_ip = 0; 515 sum->ift_ib = 0; 516 sum->ift_ie = 0; 517 sum->ift_op = 0; 518 sum->ift_ob = 0; 519 sum->ift_oe = 0; 520 sum->ift_co = 0; 521 sum->ift_dr = 0; 522 for (off = firstifnet, ip = iftot; off && ip < lastif; ip++) { 523 if (kread(off, (char *)&ifnet, sizeof ifnet)) { 524 off = 0; 525 continue; 526 } 527 if (ip == interesting) { 528 if (bflag) { 529 printf("%10llu %8.8s %10llu %5.5s", 530 (unsigned long long)(ifnet.if_ibytes - 531 ip->ift_ib), " ", 532 (unsigned long long)(ifnet.if_obytes - 533 ip->ift_ob), " "); 534 } else { 535 printf("%8llu %5llu %8llu %5llu %5llu", 536 (unsigned long long) 537 (ifnet.if_ipackets - ip->ift_ip), 538 (unsigned long long) 539 (ifnet.if_ierrors - ip->ift_ie), 540 (unsigned long long) 541 (ifnet.if_opackets - ip->ift_op), 542 (unsigned long long) 543 (ifnet.if_oerrors - ip->ift_oe), 544 (unsigned long long) 545 (ifnet.if_collisions - ip->ift_co)); 546 } 547 if (dflag) 548 printf(" %5llu", 549 (unsigned long long) 550 (ifnet.if_snd.ifq_drops - ip->ift_dr)); 551 } 552 ip->ift_ip = ifnet.if_ipackets; 553 ip->ift_ib = ifnet.if_ibytes; 554 ip->ift_ie = ifnet.if_ierrors; 555 ip->ift_op = ifnet.if_opackets; 556 ip->ift_ob = ifnet.if_obytes; 557 ip->ift_oe = ifnet.if_oerrors; 558 ip->ift_co = ifnet.if_collisions; 559 ip->ift_dr = ifnet.if_snd.ifq_drops; 560 sum->ift_ip += ip->ift_ip; 561 sum->ift_ib += ip->ift_ib; 562 sum->ift_ie += ip->ift_ie; 563 sum->ift_op += ip->ift_op; 564 sum->ift_ob += ip->ift_ob; 565 sum->ift_oe += ip->ift_oe; 566 sum->ift_co += ip->ift_co; 567 sum->ift_dr += ip->ift_dr; 568 off = (u_long)ifnet.if_list.tqe_next; 569 } 570 if (lastif - iftot > 0) { 571 if (bflag) { 572 printf(" %10llu %8.8s %10llu %5.5s", 573 (unsigned long long) 574 (sum->ift_ib - total->ift_ib), " ", 575 (unsigned long long) 576 (sum->ift_ob - total->ift_ob), " "); 577 } else { 578 printf(" %8llu %5llu %8llu %5llu %5llu", 579 (unsigned long long) 580 (sum->ift_ip - total->ift_ip), 581 (unsigned long long) 582 (sum->ift_ie - total->ift_ie), 583 (unsigned long long) 584 (sum->ift_op - total->ift_op), 585 (unsigned long long) 586 (sum->ift_oe - total->ift_oe), 587 (unsigned long long) 588 (sum->ift_co - total->ift_co)); 589 } 590 if (dflag) 591 printf(" %5llu", 592 (unsigned long long)(sum->ift_dr - total->ift_dr)); 593 } 594 *total = *sum; 595 putchar('\n'); 596 fflush(stdout); 597 line++; 598 oldmask = sigblock(sigmask(SIGALRM)); 599 if (! signalled) { 600 sigpause(0); 601 } 602 sigsetmask(oldmask); 603 signalled = NO; 604 (void)alarm(interval); 605 if (line == 21) 606 goto banner; 607 goto loop; 608 /*NOTREACHED*/ 609 } 610 611 /* 612 * Called if an interval expires before sidewaysintpr has completed a loop. 613 * Sets a flag to not wait for the alarm. 614 */ 615 static void 616 catchalarm(signo) 617 int signo; 618 { 619 620 signalled = YES; 621 } 622