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