1 /* 2 * Copyright (c) 1983, 1988, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * @(#)if.c 8.3 (Berkeley) 4/28/95 34 * $FreeBSD: src/usr.bin/netstat/if.c,v 1.32.2.9 2001/09/17 14:35:46 ru Exp $ 35 * $DragonFly: src/usr.bin/netstat/if.c,v 1.12 2008/03/07 11:34:21 sephe Exp $ 36 */ 37 38 #define _KERNEL_STRUCTURES 39 #include <sys/param.h> 40 #include <sys/protosw.h> 41 #include <sys/socket.h> 42 #include <sys/sysctl.h> 43 #include <sys/time.h> 44 45 #include <net/if.h> 46 #include <net/if_var.h> 47 #include <net/if_dl.h> 48 #include <net/if_types.h> 49 #include <net/ethernet.h> 50 #include <netinet/in.h> 51 #include <netinet/in_var.h> 52 #include <netproto/ipx/ipx.h> 53 #include <netproto/ipx/ipx_if.h> 54 #ifdef ISO 55 #include <netiso/iso.h> 56 #include <netiso/iso_var.h> 57 #endif 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 66 #include "netstat.h" 67 68 #define YES 1 69 #define NO 0 70 71 static void sidewaysintpr (u_int, u_long); 72 static void catchalarm (int); 73 74 #ifdef INET6 75 static char ntop_buf[INET6_ADDRSTRLEN]; /* for inet_ntop() */ 76 #endif 77 78 79 /* 80 * Display a formatted value, or a '-' in the same space. 81 */ 82 static void 83 show_stat(const char *fmt, int width, u_long value, short showvalue) 84 { 85 char newfmt[32]; 86 87 /* Construct the format string */ 88 if (showvalue) { 89 sprintf(newfmt, "%%%d%s", width, fmt); 90 printf(newfmt, value); 91 } else { 92 sprintf(newfmt, "%%%ds", width); 93 printf(newfmt, "-"); 94 } 95 } 96 97 98 99 /* 100 * Print a description of the network interfaces. 101 */ 102 void 103 intpr(int interval1, u_long ifnetaddr, void (*pfunc)(char *)) 104 { 105 struct ifnet ifnet; 106 struct ifaddr_container ifac; 107 struct ifnethead ifnethead; 108 union { 109 struct ifaddr ifa; 110 struct in_ifaddr in; 111 #ifdef INET6 112 struct in6_ifaddr in6; 113 #endif 114 struct ipx_ifaddr ipx; 115 #ifdef ISO 116 struct iso_ifaddr iso; 117 #endif 118 } ifaddr; 119 u_long ifaddraddr; 120 u_long ifaddrcont_addr; 121 u_long ifaddrfound; 122 u_long ifnetfound; 123 u_long opackets; 124 u_long ipackets; 125 u_long obytes; 126 u_long ibytes; 127 u_long oerrors; 128 u_long ierrors; 129 u_long collisions; 130 short timer; 131 int drops; 132 struct sockaddr *sa = NULL; 133 char name[IFNAMSIZ]; 134 short network_layer; 135 short link_layer; 136 137 if (ifnetaddr == 0) { 138 printf("ifnet: symbol not defined\n"); 139 return; 140 } 141 if (interval1) { 142 sidewaysintpr((unsigned)interval1, ifnetaddr); 143 return; 144 } 145 if (kread(ifnetaddr, (char *)&ifnethead, sizeof ifnethead)) 146 return; 147 ifnetaddr = (u_long)TAILQ_FIRST(&ifnethead); 148 if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet)) 149 return; 150 151 if (!pfunc) { 152 printf("%-7.7s %-5.5s %-13.13s %-15.15s %8.8s %5.5s", 153 "Name", "Mtu", "Network", "Address", "Ipkts", "Ierrs"); 154 if (bflag) 155 printf(" %10.10s","Ibytes"); 156 printf(" %8.8s %5.5s", "Opkts", "Oerrs"); 157 if (bflag) 158 printf(" %10.10s","Obytes"); 159 printf(" %5s", "Coll"); 160 if (tflag) 161 printf(" %s", "Time"); 162 if (dflag) 163 printf(" %s", "Drop"); 164 putchar('\n'); 165 } 166 ifaddraddr = 0; 167 while (ifnetaddr || ifaddraddr) { 168 struct sockaddr_in *sin; 169 #ifdef INET6 170 struct sockaddr_in6 *sin6; 171 #endif 172 char *cp; 173 int n, m; 174 175 network_layer = 0; 176 link_layer = 0; 177 178 if (ifaddraddr == 0) { 179 struct ifaddrhead head; 180 181 ifnetfound = ifnetaddr; 182 if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet)) 183 return; 184 strlcpy(name, ifnet.if_xname, sizeof(name)); 185 ifnetaddr = (u_long)TAILQ_NEXT(&ifnet, if_link); 186 if (interface != 0 && (strcmp(name, interface) != 0)) 187 continue; 188 cp = strchr(name, '\0'); 189 190 if (pfunc) { 191 (*pfunc)(name); 192 continue; 193 } 194 195 if ((ifnet.if_flags&IFF_UP) == 0) 196 *cp++ = '*'; 197 *cp = '\0'; 198 199 if (kread((u_long)ifnet.if_addrheads, 200 (char *)&head, sizeof(head))) 201 return; 202 203 ifaddrcont_addr = 204 (u_long)TAILQ_FIRST(&head); 205 if (ifaddrcont_addr == 0) { 206 ifaddraddr = 0; 207 } else { 208 if (kread(ifaddrcont_addr, (char *)&ifac, 209 sizeof(ifac))) 210 return; 211 ifaddraddr = (u_long)ifac.ifa; 212 } 213 } 214 ifaddrfound = ifaddraddr; 215 216 /* 217 * Get the interface stats. These may get 218 * overriden below on a per-interface basis. 219 */ 220 opackets = ifnet.if_opackets; 221 ipackets = ifnet.if_ipackets; 222 obytes = ifnet.if_obytes; 223 ibytes = ifnet.if_ibytes; 224 oerrors = ifnet.if_oerrors; 225 ierrors = ifnet.if_ierrors; 226 collisions = ifnet.if_collisions; 227 timer = ifnet.if_timer; 228 drops = ifnet.if_snd.ifq_drops; 229 230 if (ifaddraddr == 0) { 231 printf("%-7.7s %-5lu ", name, ifnet.if_mtu); 232 printf("%-13.13s ", "none"); 233 printf("%-15.15s ", "none"); 234 } else { 235 if (kread(ifaddraddr, (char *)&ifaddr, sizeof ifaddr)) { 236 ifaddraddr = 0; 237 continue; 238 } 239 #define CP(x) ((char *)(x)) 240 cp = (CP(ifaddr.ifa.ifa_addr) - CP(ifaddraddr)) + 241 CP(&ifaddr); 242 sa = (struct sockaddr *)cp; 243 if (af != AF_UNSPEC && sa->sa_family != af) { 244 ifaddrcont_addr = 245 (u_long)TAILQ_NEXT(&ifac, ifa_link); 246 if (ifaddrcont_addr == 0) { 247 ifaddraddr = 0; 248 } else { 249 if (kread(ifaddrcont_addr, 250 (char *)&ifac, sizeof(ifac))) { 251 ifaddraddr = 0; 252 continue; 253 } 254 ifaddraddr = (u_long)ifac.ifa; 255 } 256 continue; 257 } 258 printf("%-7.7s %-5lu ", name, ifnet.if_mtu); 259 switch (sa->sa_family) { 260 case AF_UNSPEC: 261 printf("%-13.13s ", "none"); 262 printf("%-15.15s ", "none"); 263 break; 264 case AF_INET: 265 sin = (struct sockaddr_in *)sa; 266 #ifdef notdef 267 /* can't use inet_makeaddr because kernel 268 * keeps nets unshifted. 269 */ 270 in = inet_makeaddr(ifaddr.in.ia_subnet, 271 INADDR_ANY); 272 printf("%-13.13s ", netname(in.s_addr, 273 ifaddr.in.ia_subnetmask)); 274 #else 275 printf("%-13.13s ", 276 netname(htonl(ifaddr.in.ia_subnet), 277 ifaddr.in.ia_subnetmask)); 278 #endif 279 printf("%-15.15s ", 280 routename(sin->sin_addr.s_addr)); 281 282 network_layer = 1; 283 break; 284 #ifdef INET6 285 case AF_INET6: 286 sin6 = (struct sockaddr_in6 *)sa; 287 printf("%-11.11s ", 288 netname6(&ifaddr.in6.ia_addr, 289 &ifaddr.in6.ia_prefixmask.sin6_addr)); 290 printf("%-17.17s ", 291 inet_ntop(AF_INET6, 292 &sin6->sin6_addr, 293 ntop_buf, sizeof(ntop_buf))); 294 295 network_layer = 1; 296 break; 297 #endif /*INET6*/ 298 case AF_IPX: 299 { 300 struct sockaddr_ipx *sipx = 301 (struct sockaddr_ipx *)sa; 302 u_long net; 303 char netnum[10]; 304 305 *(union ipx_net *) &net = sipx->sipx_addr.x_net; 306 sprintf(netnum, "%lx", (u_long)ntohl(net)); 307 printf("ipx:%-8s ", netnum); 308 /* printf("ipx:%-8s ", netname(net, 0L)); */ 309 printf("%-15s ", 310 ipx_phost((struct sockaddr *)sipx)); 311 } 312 break; 313 314 case AF_APPLETALK: 315 printf("atalk:%-12.12s ",atalk_print(sa,0x10) ); 316 printf("%-9.9s ",atalk_print(sa,0x0b) ); 317 break; 318 case AF_LINK: 319 { 320 struct sockaddr_dl *sdl = 321 (struct sockaddr_dl *)sa; 322 char linknum[10]; 323 cp = (char *)LLADDR(sdl); 324 n = sdl->sdl_alen; 325 sprintf(linknum, "<Link#%d>", sdl->sdl_index); 326 m = printf("%-11.11s ", linknum); 327 } 328 goto hexprint; 329 default: 330 m = printf("(%d)", sa->sa_family); 331 for (cp = sa->sa_len + (char *)sa; 332 --cp > sa->sa_data && (*cp == 0);) {} 333 n = cp - sa->sa_data + 1; 334 cp = sa->sa_data; 335 hexprint: 336 while (--n >= 0) 337 m += printf("%02x%c", *cp++ & 0xff, 338 n > 0 ? ':' : ' '); 339 m = 30 - m; 340 while (m-- > 0) 341 putchar(' '); 342 343 link_layer = 1; 344 break; 345 } 346 347 /* 348 * Fixup the statistics for interfaces that 349 * update stats for their network addresses 350 */ 351 if (network_layer) { 352 opackets = ifaddr.in.ia_ifa.if_opackets; 353 ipackets = ifaddr.in.ia_ifa.if_ipackets; 354 obytes = ifaddr.in.ia_ifa.if_obytes; 355 ibytes = ifaddr.in.ia_ifa.if_ibytes; 356 } 357 358 ifaddrcont_addr = 359 (u_long)TAILQ_NEXT(&ifac, ifa_link); 360 if (ifaddrcont_addr == 0) { 361 ifaddraddr = 0; 362 } else { 363 if (kread(ifaddrcont_addr, 364 (char *)&ifac, sizeof(ifac))) { 365 ifaddraddr = 0; 366 } else { 367 ifaddraddr = (u_long)ifac.ifa; 368 } 369 } 370 } 371 372 show_stat("lu", 8, ipackets, link_layer|network_layer); 373 printf(" "); 374 show_stat("lu", 5, ierrors, link_layer); 375 printf(" "); 376 if (bflag) { 377 show_stat("lu", 10, ibytes, link_layer|network_layer); 378 printf(" "); 379 } 380 show_stat("lu", 8, opackets, link_layer|network_layer); 381 printf(" "); 382 show_stat("lu", 5, oerrors, link_layer); 383 printf(" "); 384 if (bflag) { 385 show_stat("lu", 10, obytes, link_layer|network_layer); 386 printf(" "); 387 } 388 show_stat("lu", 5, collisions, link_layer); 389 if (tflag) { 390 printf(" "); 391 show_stat("d", 3, timer, link_layer); 392 } 393 if (dflag) { 394 printf(" "); 395 show_stat("d", 3, drops, link_layer); 396 } 397 putchar('\n'); 398 if (aflag && ifaddrfound) { 399 /* 400 * Print family's multicast addresses 401 */ 402 struct ifmultiaddr *multiaddr; 403 struct ifmultiaddr ifma; 404 union { 405 struct sockaddr sa; 406 struct sockaddr_in in; 407 #ifdef INET6 408 struct sockaddr_in6 in6; 409 #endif /* INET6 */ 410 struct sockaddr_dl dl; 411 } msa; 412 const char *fmt; 413 414 TAILQ_FOREACH(multiaddr, &ifnet.if_multiaddrs, ifma_link) { 415 if (kread((u_long)multiaddr, (char *)&ifma, 416 sizeof ifma)) 417 break; 418 multiaddr = &ifma; 419 if (kread((u_long)ifma.ifma_addr, (char *)&msa, 420 sizeof msa)) 421 break; 422 if (msa.sa.sa_family != sa->sa_family) 423 continue; 424 425 fmt = 0; 426 switch (msa.sa.sa_family) { 427 case AF_INET: 428 fmt = routename(msa.in.sin_addr.s_addr); 429 break; 430 #ifdef INET6 431 case AF_INET6: 432 printf("%23s %-19.19s(refs: %d)\n", "", 433 inet_ntop(AF_INET6, 434 &msa.in6.sin6_addr, 435 ntop_buf, 436 sizeof(ntop_buf)), 437 ifma.ifma_refcount); 438 break; 439 #endif /* INET6 */ 440 case AF_LINK: 441 switch (msa.dl.sdl_type) { 442 case IFT_ETHER: 443 case IFT_FDDI: 444 fmt = ether_ntoa( 445 (struct ether_addr *) 446 LLADDR(&msa.dl)); 447 break; 448 } 449 break; 450 } 451 if (fmt) 452 printf("%23s %s\n", "", fmt); 453 } 454 } 455 } 456 } 457 458 struct iftot { 459 SLIST_ENTRY(iftot) chain; 460 char ift_name[IFNAMSIZ]; /* interface name */ 461 u_long ift_ip; /* input packets */ 462 u_long ift_ie; /* input errors */ 463 u_long ift_op; /* output packets */ 464 u_long ift_oe; /* output errors */ 465 u_long ift_co; /* collisions */ 466 u_int ift_dr; /* drops */ 467 u_long ift_ib; /* input bytes */ 468 u_long ift_ob; /* output bytes */ 469 }; 470 471 u_char signalled; /* set if alarm goes off "early" */ 472 473 /* 474 * Print a running summary of interface statistics. 475 * Repeat display every interval1 seconds, showing statistics 476 * collected over that interval. Assumes that interval1 is non-zero. 477 * First line printed at top of screen is always cumulative. 478 * XXX - should be rewritten to use ifmib(4). 479 */ 480 static void 481 sidewaysintpr(unsigned interval1, u_long off) 482 { 483 struct ifnet ifnet; 484 u_long firstifnet; 485 struct ifnethead ifnethead; 486 struct iftot *iftot, *ip, *ipn, *total, *sum, *interesting; 487 int line; 488 int oldmask, first; 489 u_long interesting_off; 490 491 if (kread(off, (char *)&ifnethead, sizeof ifnethead)) 492 return; 493 firstifnet = (u_long)TAILQ_FIRST(&ifnethead); 494 495 if ((iftot = malloc(sizeof(struct iftot))) == NULL) { 496 printf("malloc failed\n"); 497 exit(1); 498 } 499 memset(iftot, 0, sizeof(struct iftot)); 500 501 interesting = NULL; 502 interesting_off = 0; 503 for (off = firstifnet, ip = iftot; off;) { 504 char name[IFNAMSIZ]; 505 506 if (kread(off, (char *)&ifnet, sizeof ifnet)) 507 break; 508 strlcpy(name, ifnet.if_xname, sizeof(name)); 509 if (interface && strcmp(name, interface) == 0) { 510 interesting = ip; 511 interesting_off = off; 512 } 513 snprintf(ip->ift_name, 16, "(%s)", name); 514 if ((ipn = malloc(sizeof(struct iftot))) == NULL) { 515 printf("malloc failed\n"); 516 exit(1); 517 } 518 memset(ipn, 0, sizeof(struct iftot)); 519 SLIST_NEXT(ip, chain) = ipn; 520 ip = ipn; 521 off = (u_long)TAILQ_NEXT(&ifnet, if_link); 522 } 523 if ((total = malloc(sizeof(struct iftot))) == NULL) { 524 printf("malloc failed\n"); 525 exit(1); 526 } 527 memset(total, 0, sizeof(struct iftot)); 528 if ((sum = malloc(sizeof(struct iftot))) == NULL) { 529 printf("malloc failed\n"); 530 exit(1); 531 } 532 memset(sum, 0, sizeof(struct iftot)); 533 534 535 (void)signal(SIGALRM, catchalarm); 536 signalled = NO; 537 (void)alarm(interval1); 538 first = 1; 539 banner: 540 printf("%17s %14s %16s", "input", 541 interesting ? interesting->ift_name : "(Total)", "output"); 542 putchar('\n'); 543 printf("%10s %5s %10s %10s %5s %10s %5s", 544 "packets", "errs", "bytes", "packets", "errs", "bytes", "colls"); 545 if (dflag) 546 printf(" %5.5s", "drops"); 547 putchar('\n'); 548 fflush(stdout); 549 line = 0; 550 loop: 551 if (interesting != NULL) { 552 ip = interesting; 553 if (kread(interesting_off, (char *)&ifnet, sizeof ifnet)) { 554 printf("???\n"); 555 exit(1); 556 }; 557 if (!first) { 558 printf("%10lu %5lu %10lu %10lu %5lu %10lu %5lu", 559 ifnet.if_ipackets - ip->ift_ip, 560 ifnet.if_ierrors - ip->ift_ie, 561 ifnet.if_ibytes - ip->ift_ib, 562 ifnet.if_opackets - ip->ift_op, 563 ifnet.if_oerrors - ip->ift_oe, 564 ifnet.if_obytes - ip->ift_ob, 565 ifnet.if_collisions - ip->ift_co); 566 if (dflag) 567 printf(" %5u", ifnet.if_snd.ifq_drops - ip->ift_dr); 568 } 569 ip->ift_ip = ifnet.if_ipackets; 570 ip->ift_ie = ifnet.if_ierrors; 571 ip->ift_ib = ifnet.if_ibytes; 572 ip->ift_op = ifnet.if_opackets; 573 ip->ift_oe = ifnet.if_oerrors; 574 ip->ift_ob = ifnet.if_obytes; 575 ip->ift_co = ifnet.if_collisions; 576 ip->ift_dr = ifnet.if_snd.ifq_drops; 577 } else { 578 sum->ift_ip = 0; 579 sum->ift_ie = 0; 580 sum->ift_ib = 0; 581 sum->ift_op = 0; 582 sum->ift_oe = 0; 583 sum->ift_ob = 0; 584 sum->ift_co = 0; 585 sum->ift_dr = 0; 586 for (off = firstifnet, ip = iftot; 587 off && SLIST_NEXT(ip, chain) != NULL; 588 ip = SLIST_NEXT(ip, chain)) { 589 if (kread(off, (char *)&ifnet, sizeof ifnet)) { 590 off = 0; 591 continue; 592 } 593 sum->ift_ip += ifnet.if_ipackets; 594 sum->ift_ie += ifnet.if_ierrors; 595 sum->ift_ib += ifnet.if_ibytes; 596 sum->ift_op += ifnet.if_opackets; 597 sum->ift_oe += ifnet.if_oerrors; 598 sum->ift_ob += ifnet.if_obytes; 599 sum->ift_co += ifnet.if_collisions; 600 sum->ift_dr += ifnet.if_snd.ifq_drops; 601 off = (u_long)TAILQ_NEXT(&ifnet, if_link); 602 } 603 if (!first) { 604 printf("%10lu %5lu %10lu %10lu %5lu %10lu %5lu", 605 sum->ift_ip - total->ift_ip, 606 sum->ift_ie - total->ift_ie, 607 sum->ift_ib - total->ift_ib, 608 sum->ift_op - total->ift_op, 609 sum->ift_oe - total->ift_oe, 610 sum->ift_ob - total->ift_ob, 611 sum->ift_co - total->ift_co); 612 if (dflag) 613 printf(" %5u", sum->ift_dr - total->ift_dr); 614 } 615 *total = *sum; 616 } 617 if (!first) 618 putchar('\n'); 619 fflush(stdout); 620 oldmask = sigblock(sigmask(SIGALRM)); 621 if (! signalled) { 622 sigpause(0); 623 } 624 sigsetmask(oldmask); 625 signalled = NO; 626 (void)alarm(interval1); 627 line++; 628 first = 0; 629 if (line == 21) 630 goto banner; 631 else 632 goto loop; 633 /*NOTREACHED*/ 634 } 635 636 /* 637 * Called if an interval expires before sidewaysintpr has completed a loop. 638 * Sets a flag to not wait for the alarm. 639 */ 640 static void 641 catchalarm(int signo __unused) 642 { 643 signalled = YES; 644 } 645