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