1 /* $OpenBSD: if.c,v 1.36 2003/07/10 00:06:51 david Exp $ */ 2 /* $NetBSD: if.c,v 1.16.4.2 1996/06/07 21:46:46 thorpej Exp $ */ 3 4 /* 5 * Copyright (c) 1983, 1988, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #ifndef lint 34 #if 0 35 static char sccsid[] = "from: @(#)if.c 8.2 (Berkeley) 2/21/94"; 36 #else 37 static char *rcsid = "$OpenBSD: if.c,v 1.36 2003/07/10 00:06:51 david Exp $"; 38 #endif 39 #endif /* not lint */ 40 41 #include <sys/types.h> 42 #include <sys/protosw.h> 43 #include <sys/socket.h> 44 45 #include <net/if.h> 46 #include <net/if_dl.h> 47 #include <net/if_types.h> 48 #include <netinet/in.h> 49 #include <netinet/in_var.h> 50 #include <netinet/if_ether.h> 51 #include <netns/ns.h> 52 #include <netns/ns_if.h> 53 #include <netipx/ipx.h> 54 #include <netipx/ipx_if.h> 55 #include <netiso/iso.h> 56 #include <netiso/iso_var.h> 57 #include <arpa/inet.h> 58 59 #include <limits.h> 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 /* 75 * Print a description of the network interfaces. 76 * NOTE: ifnetaddr is the location of the kernel global "ifnet", 77 * which is a TAILQ_HEAD. 78 */ 79 void 80 intpr(int interval, u_long ifnetaddr) 81 { 82 struct ifnet ifnet; 83 union { 84 struct ifaddr ifa; 85 struct in_ifaddr in; 86 #ifdef INET6 87 struct in6_ifaddr in6; 88 #endif 89 struct ns_ifaddr ns; 90 struct ipx_ifaddr ipx; 91 struct iso_ifaddr iso; 92 } ifaddr; 93 u_long total, ifaddraddr; 94 struct sockaddr *sa; 95 struct ifnet_head ifhead; /* TAILQ_HEAD */ 96 char name[IFNAMSIZ]; 97 98 if (ifnetaddr == 0) { 99 printf("ifnet: symbol not defined\n"); 100 return; 101 } 102 if (interval) { 103 sidewaysintpr((unsigned)interval, ifnetaddr); 104 return; 105 } 106 107 /* 108 * Find the pointer to the first ifnet structure. Replace 109 * the pointer to the TAILQ_HEAD with the actual pointer 110 * to the first list element. 111 */ 112 if (kread(ifnetaddr, (char *)&ifhead, sizeof ifhead)) 113 return; 114 ifnetaddr = (u_long)ifhead.tqh_first; 115 116 printf("%-7.7s %-5.5s %-11.11s %-17.17s ", 117 "Name", "Mtu", "Network", "Address"); 118 if (bflag) 119 printf("%10.10s %10.10s", "Ibytes", "Obytes"); 120 else 121 printf("%8.8s %5.5s %8.8s %5.5s %5.5s", 122 "Ipkts", "Ierrs", "Opkts", "Oerrs", "Colls"); 123 if (tflag) 124 printf(" %s", "Time"); 125 if (dflag) 126 printf(" %s", "Drop"); 127 putchar('\n'); 128 ifaddraddr = 0; 129 while (ifnetaddr || ifaddraddr) { 130 struct sockaddr_in *sin; 131 #ifdef INET6 132 struct sockaddr_in6 *sin6; 133 #endif 134 char *cp; 135 int n, m; 136 137 if (ifaddraddr == 0) { 138 if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet)) 139 return; 140 bcopy(ifnet.if_xname, name, IFNAMSIZ); 141 name[IFNAMSIZ - 1] = '\0'; /* sanity */ 142 ifnetaddr = (u_long)ifnet.if_list.tqe_next; 143 if (interface != 0 && strcmp(name, interface) != 0) 144 continue; 145 cp = strchr(name, '\0'); 146 if ((ifnet.if_flags & IFF_UP) == 0) 147 *cp++ = '*'; 148 *cp = '\0'; 149 ifaddraddr = (u_long)ifnet.if_addrlist.tqh_first; 150 } 151 152 if (qflag) { 153 total = ifnet.if_ibytes + ifnet.if_obytes + 154 ifnet.if_ipackets + ifnet.if_ierrors + 155 ifnet.if_opackets + ifnet.if_oerrors + 156 ifnet.if_collisions; 157 if (tflag) 158 total += ifnet.if_timer; 159 if (dflag) 160 total += ifnet.if_snd.ifq_drops; 161 if (total == 0) { 162 ifaddraddr = 0; 163 continue; 164 } 165 } 166 167 printf("%-7.7s %-5ld ", name, ifnet.if_mtu); 168 if (ifaddraddr == 0) { 169 printf("%-11.11s ", "none"); 170 printf("%-15.15s ", "none"); 171 } else { 172 if (kread(ifaddraddr, (char *)&ifaddr, sizeof ifaddr)) { 173 ifaddraddr = 0; 174 continue; 175 } 176 #define CP(x) ((char *)(x)) 177 cp = (CP(ifaddr.ifa.ifa_addr) - CP(ifaddraddr)) + 178 CP(&ifaddr); sa = (struct sockaddr *)cp; 179 switch (sa->sa_family) { 180 case AF_UNSPEC: 181 printf("%-11.11s ", "none"); 182 printf("%-17.17s ", "none"); 183 break; 184 case AF_INET: 185 sin = (struct sockaddr_in *)sa; 186 #ifdef notdef 187 /* can't use inet_makeaddr because kernel 188 * keeps nets unshifted. 189 */ 190 in = inet_makeaddr(ifaddr.in.ia_subnet, 191 INADDR_ANY); 192 cp = netname(in.s_addr, 193 ifaddr.in.ia_subnetmask); 194 #else 195 cp = netname(ifaddr.in.ia_subnet, 196 ifaddr.in.ia_subnetmask); 197 #endif 198 if (vflag) 199 n = strlen(cp) < 11 ? 11 : strlen(cp); 200 else 201 n = 11; 202 printf("%-*.*s ", n, n, cp); 203 cp = routename(sin->sin_addr.s_addr); 204 if (vflag) 205 n = strlen(cp) < 17 ? 17 : strlen(cp); 206 else 207 n = 17; 208 printf("%-*.*s ", n, n, cp); 209 210 if (aflag) { 211 u_long multiaddr; 212 struct in_multi inm; 213 214 multiaddr = (u_long)ifaddr.in.ia_multiaddrs.lh_first; 215 while (multiaddr != 0) { 216 kread(multiaddr, (char *)&inm, 217 sizeof inm); 218 printf("\n%25s %-17.17s ", "", 219 routename(inm.inm_addr.s_addr)); 220 multiaddr = (u_long)inm.inm_list.le_next; 221 } 222 } 223 break; 224 #ifdef INET6 225 case AF_INET6: 226 sin6 = (struct sockaddr_in6 *)sa; 227 #ifdef __KAME__ 228 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { 229 sin6->sin6_scope_id = 230 ntohs(*(u_int16_t *) 231 &sin6->sin6_addr.s6_addr[2]); 232 sin6->sin6_addr.s6_addr[2] = 0; 233 sin6->sin6_addr.s6_addr[3] = 0; 234 } 235 #endif 236 cp = netname6(&ifaddr.in6.ia_addr, 237 &ifaddr.in6.ia_prefixmask.sin6_addr); 238 if (vflag) 239 n = strlen(cp) < 11 ? 11 : strlen(cp); 240 else 241 n = 11; 242 printf("%-*.*s ", n, n, cp); 243 cp = routename6(sin6); 244 if (vflag) 245 n = strlen(cp) < 17 ? 17 : strlen(cp); 246 else 247 n = 17; 248 printf("%-*.*s ", n, n, cp); 249 if (aflag) { 250 u_long multiaddr; 251 struct in6_multi inm; 252 struct sockaddr_in6 m6; 253 254 multiaddr = (u_long)ifaddr.in6.ia6_multiaddrs.lh_first; 255 while (multiaddr != 0) { 256 kread(multiaddr, (char *)&inm, 257 sizeof inm); 258 memset(&m6, 0, sizeof(m6)); 259 m6.sin6_len = sizeof(struct sockaddr_in6); 260 m6.sin6_family = AF_INET6; 261 m6.sin6_addr = inm.in6m_addr; 262 #ifdef __KAME__ 263 if (IN6_IS_ADDR_MC_LINKLOCAL(&m6.sin6_addr)) { 264 m6.sin6_scope_id = 265 ntohs(*(u_int16_t *) 266 &m6.sin6_addr.s6_addr[2]); 267 m6.sin6_addr.s6_addr[2] = 0; 268 m6.sin6_addr.s6_addr[3] = 0; 269 } 270 #endif 271 cp = routename6(&m6); 272 if (vflag) 273 n = strlen(cp) < 17 ? 17 : strlen(cp); 274 else 275 n = 17; 276 printf("\n%25s %-*.*s ", "", 277 n, n, cp); 278 multiaddr = (u_long)inm.in6m_entry.le_next; 279 } 280 } 281 break; 282 #endif 283 case AF_IPX: 284 { 285 struct sockaddr_ipx *sipx = 286 (struct sockaddr_ipx *)sa; 287 u_long net; 288 char netnum[8]; 289 290 *(union ipx_net *)&net = sipx->sipx_addr.ipx_net; 291 snprintf(netnum, sizeof netnum, "%xH", 292 ntohl(net)); 293 upHex(netnum); 294 printf("ipx:%-8s", netnum); 295 printf("%-17s ", 296 ipx_phost((struct sockaddr *)sipx)); 297 } 298 break; 299 case AF_APPLETALK: 300 printf("atlk:%-12s",atalk_print(sa,0x10) ); 301 printf("%-12s ",atalk_print(sa,0x0b) ); 302 break; 303 case AF_NS: 304 { 305 struct sockaddr_ns *sns = 306 (struct sockaddr_ns *)sa; 307 u_long net; 308 char netnum[8]; 309 310 *(union ns_net *)&net = sns->sns_addr.x_net; 311 snprintf(netnum, sizeof netnum, "%xH", 312 ntohl(net)); 313 upHex(netnum); 314 printf("ns:%-8s ", netnum); 315 printf("%-17s ", 316 ns_phost((struct sockaddr *)sns)); 317 } 318 break; 319 case AF_LINK: 320 { 321 struct sockaddr_dl *sdl = 322 (struct sockaddr_dl *)sa; 323 m = printf("%-11.11s ", "<Link>"); 324 if (sdl->sdl_type == IFT_ETHER || 325 sdl->sdl_type == IFT_FDDI || 326 sdl->sdl_type == IFT_ISO88025) 327 printf("%-17.17s ", 328 ether_ntoa((struct ether_addr *)LLADDR(sdl))); 329 else { 330 cp = (char *)LLADDR(sdl); 331 n = sdl->sdl_alen; 332 goto hexprint; 333 } 334 } 335 break; 336 default: 337 m = printf("(%d)", sa->sa_family); 338 for (cp = sa->sa_len + (char *)sa; 339 --cp > sa->sa_data && (*cp == 0);) {} 340 n = cp - sa->sa_data + 1; 341 cp = sa->sa_data; 342 hexprint: 343 while (--n >= 0) 344 m += printf("%x%c", *cp++ & 0xff, 345 n > 0 ? '.' : ' '); 346 m = 30 - m; 347 while (m-- > 0) 348 putchar(' '); 349 break; 350 } 351 ifaddraddr = (u_long)ifaddr.ifa.ifa_list.tqe_next; 352 } 353 if (bflag) 354 printf("%10lu %10lu", 355 ifnet.if_ibytes, ifnet.if_obytes); 356 else 357 printf("%8lu %5lu %8lu %5lu %5lu", 358 ifnet.if_ipackets, ifnet.if_ierrors, 359 ifnet.if_opackets, ifnet.if_oerrors, 360 ifnet.if_collisions); 361 if (tflag) 362 printf(" %4d", ifnet.if_timer); 363 if (dflag) 364 printf(" %4d", ifnet.if_snd.ifq_drops); 365 putchar('\n'); 366 } 367 } 368 369 #define MAXIF 100 370 struct iftot { 371 char ift_name[IFNAMSIZ]; /* interface name */ 372 int ift_ip; /* input packets */ 373 int ift_ib; /* input bytes */ 374 int ift_ie; /* input errors */ 375 int ift_op; /* output packets */ 376 int ift_ob; /* output bytes */ 377 int ift_oe; /* output errors */ 378 int ift_co; /* collisions */ 379 int ift_dr; /* drops */ 380 } iftot[MAXIF]; 381 382 volatile sig_atomic_t signalled; /* set if alarm goes off "early" */ 383 384 /* 385 * Print a running summary of interface statistics. 386 * Repeat display every interval seconds, showing statistics 387 * collected over that interval. Assumes that interval is non-zero. 388 * First line printed at top of screen is always cumulative. 389 */ 390 static void 391 sidewaysintpr(unsigned int interval, u_long off) 392 { 393 struct ifnet ifnet; 394 u_long firstifnet; 395 struct iftot *ip, *total; 396 int line; 397 struct iftot *lastif, *sum, *interesting; 398 struct ifnet_head ifhead; /* TAILQ_HEAD */ 399 sigset_t emptyset; 400 401 /* 402 * Find the pointer to the first ifnet structure. Replace 403 * the pointer to the TAILQ_HEAD with the actual pointer 404 * to the first list element. 405 */ 406 if (kread(off, (char *)&ifhead, sizeof ifhead)) 407 return; 408 firstifnet = (u_long)ifhead.tqh_first; 409 410 lastif = iftot; 411 sum = iftot + MAXIF - 1; 412 total = sum - 1; 413 interesting = (interface == NULL) ? iftot : NULL; 414 for (off = firstifnet, ip = iftot; off;) { 415 if (kread(off, (char *)&ifnet, sizeof ifnet)) 416 break; 417 bzero(ip->ift_name, sizeof(ip->ift_name)); 418 snprintf(ip->ift_name, IFNAMSIZ, "%s", ifnet.if_xname); 419 if (interface && strcmp(ifnet.if_xname, interface) == 0) 420 interesting = ip; 421 ip++; 422 if (ip >= iftot + MAXIF - 2) 423 break; 424 off = (u_long)ifnet.if_list.tqe_next; 425 } 426 if (interesting == NULL) { 427 fprintf(stderr, "%s: %s: unknown interface\n", 428 __progname, interface); 429 exit(1); 430 } 431 lastif = ip; 432 433 (void)signal(SIGALRM, catchalarm); 434 signalled = NO; 435 (void)alarm(interval); 436 banner: 437 if (bflag) 438 printf("%7.7s in %8.8s %6.6s out %5.5s", 439 interesting->ift_name, " ", 440 interesting->ift_name, " "); 441 else 442 printf("%5.5s in %5.5s%5.5s out %5.5s %5.5s", 443 interesting->ift_name, " ", 444 interesting->ift_name, " ", " "); 445 if (dflag) 446 printf(" %5.5s", " "); 447 if (lastif - iftot > 0) { 448 if (bflag) 449 printf(" %7.7s in %8.8s %6.6s out %5.5s", 450 "total", " ", "total", " "); 451 else 452 printf(" %5.5s in %5.5s%5.5s out %5.5s %5.5s", 453 "total", " ", "total", " ", " "); 454 if (dflag) 455 printf(" %5.5s", " "); 456 } 457 for (ip = iftot; ip < iftot + MAXIF; ip++) { 458 ip->ift_ip = 0; 459 ip->ift_ib = 0; 460 ip->ift_ie = 0; 461 ip->ift_op = 0; 462 ip->ift_ob = 0; 463 ip->ift_oe = 0; 464 ip->ift_co = 0; 465 ip->ift_dr = 0; 466 } 467 putchar('\n'); 468 if (bflag) 469 printf("%10.10s %8.8s %10.10s %5.5s", 470 "bytes", " ", "bytes", " "); 471 else 472 printf("%8.8s %5.5s %8.8s %5.5s %5.5s", 473 "packets", "errs", "packets", "errs", "colls"); 474 if (dflag) 475 printf(" %5.5s", "drops"); 476 if (lastif - iftot > 0) { 477 if (bflag) 478 printf(" %10.10s %8.8s %10.10s %5.5s", 479 "bytes", " ", "bytes", " "); 480 else 481 printf(" %8.8s %5.5s %8.8s %5.5s %5.5s", 482 "packets", "errs", "packets", "errs", "colls"); 483 if (dflag) 484 printf(" %5.5s", "drops"); 485 } 486 putchar('\n'); 487 fflush(stdout); 488 line = 0; 489 loop: 490 sum->ift_ip = 0; 491 sum->ift_ib = 0; 492 sum->ift_ie = 0; 493 sum->ift_op = 0; 494 sum->ift_ob = 0; 495 sum->ift_oe = 0; 496 sum->ift_co = 0; 497 sum->ift_dr = 0; 498 for (off = firstifnet, ip = iftot; off && ip < lastif; ip++) { 499 if (kread(off, (char *)&ifnet, sizeof ifnet)) { 500 off = 0; 501 continue; 502 } 503 if (ip == interesting) { 504 if (bflag) 505 printf("%10lu %8.8s %10lu %5.5s", 506 ifnet.if_ibytes - ip->ift_ib, " ", 507 ifnet.if_obytes - ip->ift_ob, " "); 508 else 509 printf("%8lu %5lu %8lu %5lu %5lu", 510 ifnet.if_ipackets - ip->ift_ip, 511 ifnet.if_ierrors - ip->ift_ie, 512 ifnet.if_opackets - ip->ift_op, 513 ifnet.if_oerrors - ip->ift_oe, 514 ifnet.if_collisions - ip->ift_co); 515 if (dflag) 516 printf(" %5d", 517 ifnet.if_snd.ifq_drops - ip->ift_dr); 518 } 519 ip->ift_ip = ifnet.if_ipackets; 520 ip->ift_ib = ifnet.if_ibytes; 521 ip->ift_ie = ifnet.if_ierrors; 522 ip->ift_op = ifnet.if_opackets; 523 ip->ift_ob = ifnet.if_obytes; 524 ip->ift_oe = ifnet.if_oerrors; 525 ip->ift_co = ifnet.if_collisions; 526 ip->ift_dr = ifnet.if_snd.ifq_drops; 527 sum->ift_ip += ip->ift_ip; 528 sum->ift_ib += ip->ift_ib; 529 sum->ift_ie += ip->ift_ie; 530 sum->ift_op += ip->ift_op; 531 sum->ift_ob += ip->ift_ob; 532 sum->ift_oe += ip->ift_oe; 533 sum->ift_co += ip->ift_co; 534 sum->ift_dr += ip->ift_dr; 535 off = (u_long)ifnet.if_list.tqe_next; 536 } 537 if (lastif - iftot > 0) { 538 if (bflag) 539 printf(" %10lu %8.8s %10lu %5.5s", 540 (unsigned long)sum->ift_ib - total->ift_ib, " ", 541 (unsigned long)sum->ift_ob - total->ift_ob, " "); 542 else 543 printf(" %8lu %5lu %8lu %5lu %5lu", 544 (unsigned long)sum->ift_ip - total->ift_ip, 545 (unsigned long)sum->ift_ie - total->ift_ie, 546 (unsigned long)sum->ift_op - total->ift_op, 547 (unsigned long)sum->ift_oe - total->ift_oe, 548 (unsigned long)sum->ift_co - total->ift_co); 549 if (dflag) 550 printf(" %5d", sum->ift_dr - total->ift_dr); 551 } 552 *total = *sum; 553 putchar('\n'); 554 fflush(stdout); 555 line++; 556 sigemptyset(&emptyset); 557 if (!signalled) 558 sigsuspend(&emptyset); 559 signalled = NO; 560 (void)alarm(interval); 561 if (line == 21) 562 goto banner; 563 goto loop; 564 /*NOTREACHED*/ 565 } 566 567 /* 568 * Called if an interval expires before sidewaysintpr has completed a loop. 569 * Sets a flag to not wait for the alarm. 570 */ 571 static void 572 catchalarm(int signo) 573 { 574 signalled = YES; 575 } 576