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