1 /* $OpenBSD: if.c,v 1.60 2009/02/07 15:06:04 chl 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 #include <sys/param.h> 34 #include <sys/types.h> 35 #include <sys/protosw.h> 36 #include <sys/socket.h> 37 #include <sys/sysctl.h> 38 39 #include <net/if.h> 40 #include <net/if_dl.h> 41 #include <net/if_types.h> 42 #include <net/route.h> 43 #include <netinet/in.h> 44 #include <netinet/in_var.h> 45 #include <netinet/if_ether.h> 46 #include <arpa/inet.h> 47 48 #include <err.h> 49 #include <limits.h> 50 #include <signal.h> 51 #include <stdio.h> 52 #include <stdlib.h> 53 #include <string.h> 54 #include <unistd.h> 55 56 #include "netstat.h" 57 58 static void print_addr(struct sockaddr *, struct sockaddr **, struct if_data *); 59 static void sidewaysintpr(u_int); 60 static void catchalarm(int); 61 static void get_rtaddrs(int, struct sockaddr *, struct sockaddr **); 62 static void fetchifs(void); 63 64 /* 65 * Print a description of the network interfaces. 66 * NOTE: ifnetaddr is the location of the kernel global "ifnet", 67 * which is a TAILQ_HEAD. 68 */ 69 void 70 intpr(int interval) 71 { 72 struct if_msghdr ifm; 73 int mib[6] = { CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0 }; 74 char name[IFNAMSIZ + 1]; /* + 1 for the '*' */ 75 char *buf, *next, *lim, *cp; 76 struct rt_msghdr *rtm; 77 struct ifa_msghdr *ifam; 78 struct if_data *ifd; 79 struct sockaddr *sa, *rti_info[RTAX_MAX]; 80 struct sockaddr_dl *sdl; 81 u_int64_t total = 0; 82 size_t len; 83 84 if (interval) { 85 sidewaysintpr((unsigned)interval); 86 return; 87 } 88 89 if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1) 90 err(1, "sysctl"); 91 if ((buf = malloc(len)) == NULL) 92 err(1, NULL); 93 if (sysctl(mib, 6, buf, &len, NULL, 0) == -1) 94 err(1, "sysctl"); 95 96 printf("%-7.7s %-5.5s %-11.11s %-17.17s ", 97 "Name", "Mtu", "Network", "Address"); 98 if (bflag) 99 printf("%10.10s %10.10s", "Ibytes", "Obytes"); 100 else 101 printf("%8.8s %5.5s %8.8s %5.5s %5.5s", 102 "Ipkts", "Ierrs", "Opkts", "Oerrs", "Colls"); 103 if (tflag) 104 printf(" %s", "Time"); 105 if (dflag) 106 printf(" %s", "Drop"); 107 putchar('\n'); 108 109 lim = buf + len; 110 for (next = buf; next < lim; next += rtm->rtm_msglen) { 111 rtm = (struct rt_msghdr *)next; 112 if (rtm->rtm_version != RTM_VERSION) 113 continue; 114 switch (rtm->rtm_type) { 115 case RTM_IFINFO: 116 total = 0; 117 bcopy(next, &ifm, sizeof ifm); 118 ifd = &ifm.ifm_data; 119 120 sa = (struct sockaddr *)(next + rtm->rtm_hdrlen); 121 get_rtaddrs(ifm.ifm_addrs, sa, rti_info); 122 123 sdl = (struct sockaddr_dl *)rti_info[RTAX_IFP]; 124 if (sdl == NULL || sdl->sdl_family != AF_LINK) 125 continue; 126 bzero(name, sizeof(name)); 127 if (sdl->sdl_nlen >= IFNAMSIZ) 128 memcpy(name, sdl->sdl_data, IFNAMSIZ - 1); 129 else if (sdl->sdl_nlen > 0) 130 memcpy(name, sdl->sdl_data, sdl->sdl_nlen); 131 132 if (interface != 0 && strcmp(name, interface) != 0) 133 continue; 134 135 /* mark inactive interfaces with a '*' */ 136 cp = strchr(name, '\0'); 137 if ((ifm.ifm_flags & IFF_UP) == 0) 138 *cp++ = '*'; 139 *cp = '\0'; 140 141 if (qflag) { 142 total = ifd->ifi_ibytes + ifd->ifi_obytes + 143 ifd->ifi_ipackets + ifd->ifi_ierrors + 144 ifd->ifi_opackets + ifd->ifi_oerrors + 145 ifd->ifi_collisions; 146 if (tflag) 147 total += 0; // XXX ifnet.if_timer; 148 if (dflag) 149 total += 0; // XXX ifnet.if_snd.ifq_drops; 150 if (total == 0) 151 continue; 152 } 153 154 printf("%-7s %-5ld ", name, ifd->ifi_mtu); 155 print_addr(rti_info[RTAX_IFP], rti_info, ifd); 156 break; 157 case RTM_NEWADDR: 158 if (qflag && total == 0) 159 continue; 160 if (interface != 0 && strcmp(name, interface) != 0) 161 continue; 162 163 ifam = (struct ifa_msghdr *)next; 164 if ((ifam->ifam_addrs & (RTA_NETMASK | RTA_IFA | 165 RTA_BRD)) == 0) 166 break; 167 168 sa = (struct sockaddr *)(next + rtm->rtm_hdrlen); 169 get_rtaddrs(ifam->ifam_addrs, sa, rti_info); 170 171 printf("%-7s %-5ld ", name, ifd->ifi_mtu); 172 print_addr(rti_info[RTAX_IFA], rti_info, ifd); 173 break; 174 } 175 } 176 free(buf); 177 } 178 179 static void 180 print_addr(struct sockaddr *sa, struct sockaddr **rtinfo, struct if_data *ifd) 181 { 182 struct sockaddr_dl *sdl; 183 struct sockaddr_in *sin; 184 struct sockaddr_in6 *sin6; 185 char *cp; 186 int m, n; 187 188 switch (sa->sa_family) { 189 case AF_UNSPEC: 190 printf("%-11.11s ", "none"); 191 printf("%-17.17s ", "none"); 192 break; 193 case AF_INET: 194 sin = (struct sockaddr_in *)sa; 195 cp = netname4(sin->sin_addr.s_addr, 196 ((struct sockaddr_in *)rtinfo[RTAX_NETMASK])->sin_addr.s_addr); 197 if (vflag) 198 n = strlen(cp) < 11 ? 11 : strlen(cp); 199 else 200 n = 11; 201 printf("%-*.*s ", n, n, cp); 202 cp = routename4(sin->sin_addr.s_addr); 203 if (vflag) 204 n = strlen(cp) < 17 ? 17 : strlen(cp); 205 else 206 n = 17; 207 printf("%-*.*s ", n, n, cp); 208 209 #if 0 210 if (aflag) { 211 u_long multiaddr; 212 struct in_multi inm; 213 214 multiaddr = (u_long)LIST_FIRST(&ifaddr.in.ia_multiaddrs); 215 while (multiaddr != 0) { 216 kread(multiaddr, &inm, sizeof inm); 217 printf("\n%25s %-17.17s ", "", 218 routename4(inm.inm_addr.s_addr)); 219 multiaddr = (u_long)LIST_NEXT(&inm, inm_list); 220 } 221 } 222 #endif 223 break; 224 case AF_INET6: 225 sin6 = (struct sockaddr_in6 *)sa; 226 #ifdef __KAME__ 227 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { 228 sin6->sin6_scope_id = 229 ntohs(*(u_int16_t *) 230 &sin6->sin6_addr.s6_addr[2]); 231 sin6->sin6_addr.s6_addr[2] = 0; 232 sin6->sin6_addr.s6_addr[3] = 0; 233 } 234 #endif 235 cp = netname6(sin6, 236 (struct sockaddr_in6 *)rtinfo[RTAX_NETMASK]); 237 if (vflag) 238 n = strlen(cp) < 11 ? 11 : strlen(cp); 239 else 240 n = 11; 241 printf("%-*.*s ", n, n, cp); 242 cp = routename6(sin6); 243 if (vflag) 244 n = strlen(cp) < 17 ? 17 : strlen(cp); 245 else 246 n = 17; 247 printf("%-*.*s ", n, n, cp); 248 #if 0 249 if (aflag) { 250 u_long multiaddr; 251 struct in6_multi inm; 252 struct sockaddr_in6 m6; 253 254 multiaddr = (u_long)LIST_FIRST(&ifaddr.in6.ia6_multiaddrs); 255 while (multiaddr != 0) { 256 kread(multiaddr, &inm, sizeof inm); 257 memset(&m6, 0, sizeof(m6)); 258 m6.sin6_len = sizeof(struct sockaddr_in6); 259 m6.sin6_family = AF_INET6; 260 m6.sin6_addr = inm.in6m_addr; 261 #ifdef __KAME__ 262 if (IN6_IS_ADDR_MC_LINKLOCAL(&m6.sin6_addr) || 263 IN6_IS_ADDR_MC_INTFACELOCAL(&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)LIST_NEXT(&inm, in6m_entry); 279 } 280 } 281 #endif 282 break; 283 case AF_APPLETALK: 284 printf("atlk:%-12s",atalk_print(sa,0x10) ); 285 printf("%-12s ",atalk_print(sa,0x0b) ); 286 break; 287 case AF_LINK: 288 sdl = (struct sockaddr_dl *)sa; 289 m = printf("%-11.11s ", "<Link>"); 290 if (sdl->sdl_type == IFT_ETHER || 291 sdl->sdl_type == IFT_CARP || 292 sdl->sdl_type == IFT_FDDI || 293 sdl->sdl_type == IFT_ISO88025) 294 printf("%-17.17s ", 295 ether_ntoa((struct ether_addr *)LLADDR(sdl))); 296 else { 297 cp = (char *)LLADDR(sdl); 298 n = sdl->sdl_alen; 299 goto hexprint; 300 } 301 break; 302 default: 303 m = printf("(%d)", sa->sa_family); 304 for (cp = sa->sa_len + (char *)sa; 305 --cp > sa->sa_data && (*cp == 0);) {} 306 n = cp - sa->sa_data + 1; 307 cp = sa->sa_data; 308 hexprint: 309 while (--n >= 0) 310 m += printf("%x%c", *cp++ & 0xff, 311 n > 0 ? '.' : ' '); 312 m = 30 - m; 313 while (m-- > 0) 314 putchar(' '); 315 break; 316 } 317 if (bflag) 318 printf("%10llu %10llu", 319 ifd->ifi_ibytes, ifd->ifi_obytes); 320 else 321 printf("%8llu %5llu %8llu %5llu %5llu", 322 ifd->ifi_ipackets, ifd->ifi_ierrors, 323 ifd->ifi_opackets, ifd->ifi_oerrors, 324 ifd->ifi_collisions); 325 if (tflag) 326 printf(" %4d", 0 /* XXX ifnet.if_timer */); 327 if (dflag) 328 printf(" %4d", 0 /* XXX ifnet.if_snd.ifq_drops */); 329 putchar('\n'); 330 } 331 332 struct iftot { 333 char ift_name[IFNAMSIZ]; /* interface name */ 334 u_int64_t ift_ip; /* input packets */ 335 u_int64_t ift_ib; /* input bytes */ 336 u_int64_t ift_ie; /* input errors */ 337 u_int64_t ift_op; /* output packets */ 338 u_int64_t ift_ob; /* output bytes */ 339 u_int64_t ift_oe; /* output errors */ 340 u_int64_t ift_co; /* collisions */ 341 u_int64_t ift_dr; /* drops */ 342 } ip_cur, ip_old, sum_cur, sum_old; 343 344 volatile sig_atomic_t signalled; /* set if alarm goes off "early" */ 345 346 /* 347 * Print a running summary of interface statistics. 348 * Repeat display every interval seconds, showing statistics 349 * collected over that interval. Assumes that interval is non-zero. 350 * First line printed at top of screen is always cumulative. 351 */ 352 static void 353 sidewaysintpr(unsigned int interval) 354 { 355 struct ifnet ifnet; 356 sigset_t emptyset; 357 int line; 358 359 fetchifs(); 360 if (ip_cur.ift_name[0] == '\0') { 361 fprintf(stderr, "%s: %s: unknown interface\n", 362 __progname, interface); 363 exit(1); 364 } 365 366 (void)signal(SIGALRM, catchalarm); 367 signalled = 0; 368 (void)alarm(interval); 369 banner: 370 if (bflag) 371 printf("%7.7s in %8.8s %6.6s out %5.5s", 372 ip_cur.ift_name, " ", 373 ip_cur.ift_name, " "); 374 else 375 printf("%5.5s in %5.5s%5.5s out %5.5s %5.5s", 376 ip_cur.ift_name, " ", 377 ip_cur.ift_name, " ", " "); 378 if (dflag) 379 printf(" %5.5s", " "); 380 381 if (bflag) 382 printf(" %7.7s in %8.8s %6.6s out %5.5s", 383 "total", " ", "total", " "); 384 else 385 printf(" %5.5s in %5.5s%5.5s out %5.5s %5.5s", 386 "total", " ", "total", " ", " "); 387 if (dflag) 388 printf(" %5.5s", " "); 389 putchar('\n'); 390 if (bflag) 391 printf("%10.10s %8.8s %10.10s %5.5s", 392 "bytes", " ", "bytes", " "); 393 else 394 printf("%8.8s %5.5s %8.8s %5.5s %5.5s", 395 "packets", "errs", "packets", "errs", "colls"); 396 if (dflag) 397 printf(" %5.5s", "drops"); 398 399 if (bflag) 400 printf(" %10.10s %8.8s %10.10s %5.5s", 401 "bytes", " ", "bytes", " "); 402 else 403 printf(" %8.8s %5.5s %8.8s %5.5s %5.5s", 404 "packets", "errs", "packets", "errs", "colls"); 405 if (dflag) 406 printf(" %5.5s", "drops"); 407 putchar('\n'); 408 fflush(stdout); 409 line = 0; 410 bzero(&ip_old, sizeof(ip_old)); 411 bzero(&sum_old, sizeof(sum_old)); 412 loop: 413 bzero(&sum_cur, sizeof(sum_cur)); 414 415 fetchifs(); 416 417 if (bflag) 418 printf("%10llu %8.8s %10llu %5.5s", 419 ip_cur.ift_ib - ip_old.ift_ib, " ", 420 ip_cur.ift_ob - ip_old.ift_ob, " "); 421 else 422 printf("%8llu %5llu %8llu %5llu %5llu", 423 ip_cur.ift_ip - ip_old.ift_ip, 424 ip_cur.ift_ie - ip_old.ift_ie, 425 ip_cur.ift_op - ip_old.ift_op, 426 ip_cur.ift_oe - ip_old.ift_oe, 427 ip_cur.ift_co - ip_old.ift_co); 428 if (dflag) 429 printf(" %5llu", 430 /* XXX ifnet.if_snd.ifq_drops - ip->ift_dr); */ 431 0); 432 433 ip_old = ip_cur; 434 435 if (bflag) 436 printf(" %10llu %8.8s %10llu %5.5s", 437 sum_cur.ift_ib - sum_old.ift_ib, " ", 438 sum_cur.ift_ob - sum_old.ift_ob, " "); 439 else 440 printf(" %8llu %5llu %8llu %5llu %5llu", 441 sum_cur.ift_ip - sum_old.ift_ip, 442 sum_cur.ift_ie - sum_old.ift_ie, 443 sum_cur.ift_op - sum_old.ift_op, 444 sum_cur.ift_oe - sum_old.ift_oe, 445 sum_cur.ift_co - sum_old.ift_co); 446 if (dflag) 447 printf(" %5llu", sum_cur.ift_dr - sum_old.ift_dr); 448 449 sum_old = sum_cur; 450 451 putchar('\n'); 452 fflush(stdout); 453 line++; 454 sigemptyset(&emptyset); 455 if (!signalled) 456 sigsuspend(&emptyset); 457 signalled = 0; 458 (void)alarm(interval); 459 if (line == 21) 460 goto banner; 461 goto loop; 462 /*NOTREACHED*/ 463 } 464 465 /* 466 * Called if an interval expires before sidewaysintpr has completed a loop. 467 * Sets a flag to not wait for the alarm. 468 */ 469 /* ARGSUSED */ 470 static void 471 catchalarm(int signo) 472 { 473 signalled = 1; 474 } 475 476 static void 477 get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) 478 { 479 int i; 480 481 for (i = 0; i < RTAX_MAX; i++) { 482 if (addrs & (1 << i)) { 483 rti_info[i] = sa; 484 sa = (struct sockaddr *)((char *)(sa) + 485 roundup(sa->sa_len, sizeof(long))); 486 } else 487 rti_info[i] = NULL; 488 } 489 } 490 491 static void 492 fetchifs(void) 493 { 494 struct if_msghdr ifm; 495 int mib[6] = { CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0 }; 496 struct rt_msghdr *rtm; 497 struct if_data *ifd; 498 struct sockaddr *sa, *rti_info[RTAX_MAX]; 499 struct sockaddr_dl *sdl; 500 char *buf, *next, *lim; 501 char name[IFNAMSIZ]; 502 size_t len; 503 504 if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1) 505 err(1, "sysctl"); 506 if ((buf = malloc(len)) == NULL) 507 err(1, NULL); 508 if (sysctl(mib, 6, buf, &len, NULL, 0) == -1) 509 err(1, "sysctl"); 510 511 lim = buf + len; 512 for (next = buf; next < lim; next += rtm->rtm_msglen) { 513 rtm = (struct rt_msghdr *)next; 514 if (rtm->rtm_version != RTM_VERSION) 515 continue; 516 switch (rtm->rtm_type) { 517 case RTM_IFINFO: 518 bcopy(next, &ifm, sizeof ifm); 519 ifd = &ifm.ifm_data; 520 521 sa = (struct sockaddr *)(next + rtm->rtm_hdrlen); 522 get_rtaddrs(ifm.ifm_addrs, sa, rti_info); 523 524 sdl = (struct sockaddr_dl *)rti_info[RTAX_IFP]; 525 if (sdl == NULL || sdl->sdl_family != AF_LINK) 526 continue; 527 bzero(name, sizeof(name)); 528 if (sdl->sdl_nlen >= IFNAMSIZ) 529 memcpy(name, sdl->sdl_data, IFNAMSIZ - 1); 530 else if (sdl->sdl_nlen > 0) 531 memcpy(name, sdl->sdl_data, sdl->sdl_nlen); 532 533 if (interface != NULL && !strcmp(name, interface)) { 534 strlcpy(ip_cur.ift_name, name, 535 sizeof(ip_cur.ift_name)); 536 ip_cur.ift_ip = ifd->ifi_ipackets; 537 ip_cur.ift_ib = ifd->ifi_ibytes; 538 ip_cur.ift_ie = ifd->ifi_ierrors; 539 ip_cur.ift_op = ifd->ifi_opackets; 540 ip_cur.ift_ob = ifd->ifi_obytes; 541 ip_cur.ift_oe = ifd->ifi_oerrors; 542 ip_cur.ift_co = ifd->ifi_collisions; 543 ip_cur.ift_dr = 0; 544 /* XXX ifnet.if_snd.ifq_drops */ 545 } 546 547 sum_cur.ift_ip += ifd->ifi_ipackets; 548 sum_cur.ift_ib += ifd->ifi_ibytes; 549 sum_cur.ift_ie += ifd->ifi_ierrors; 550 sum_cur.ift_op += ifd->ifi_opackets; 551 sum_cur.ift_ob += ifd->ifi_obytes; 552 sum_cur.ift_oe += ifd->ifi_oerrors; 553 sum_cur.ift_co += ifd->ifi_collisions; 554 sum_cur.ift_dr += 0; /* XXX ifnet.if_snd.ifq_drops */ 555 break; 556 } 557 } 558 if (interface == NULL) { 559 strlcpy(ip_cur.ift_name, name, 560 sizeof(ip_cur.ift_name)); 561 ip_cur.ift_ip = ifd->ifi_ipackets; 562 ip_cur.ift_ib = ifd->ifi_ibytes; 563 ip_cur.ift_ie = ifd->ifi_ierrors; 564 ip_cur.ift_op = ifd->ifi_opackets; 565 ip_cur.ift_ob = ifd->ifi_obytes; 566 ip_cur.ift_oe = ifd->ifi_oerrors; 567 ip_cur.ift_co = ifd->ifi_collisions; 568 ip_cur.ift_dr = 0; 569 /* XXX ifnet.if_snd.ifq_drops */ 570 } 571 free(buf); 572 } 573