if.c revision 287593
1/*- 2 * Copyright (c) 2013 Gleb Smirnoff <glebius@FreeBSD.org> 3 * Copyright (c) 1983, 1988, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 4. Neither the name of the University nor the names of its contributors 15 * may be used to endorse or promote products derived from this software 16 * without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31#if 0 32#ifndef lint 33static char sccsid[] = "@(#)if.c 8.3 (Berkeley) 4/28/95"; 34#endif /* not lint */ 35#endif 36 37#include <sys/cdefs.h> 38__FBSDID("$FreeBSD: stable/10/usr.bin/netstat/if.c 287593 2015-09-09 08:40:17Z hrs $"); 39 40#include <sys/types.h> 41#include <sys/protosw.h> 42#include <sys/socket.h> 43#include <sys/socketvar.h> 44#include <sys/sysctl.h> 45#include <sys/time.h> 46 47#define _IFI_OQDROPS 48#include <net/if.h> 49#include <net/if_var.h> 50#include <net/if_dl.h> 51#include <net/if_types.h> 52#include <net/ethernet.h> 53#include <netinet/in.h> 54#include <netinet/in_var.h> 55#include <netipx/ipx.h> 56#include <netipx/ipx_if.h> 57#include <arpa/inet.h> 58#ifdef PF 59#include <net/pfvar.h> 60#include <net/if_pfsync.h> 61#endif 62 63#include <err.h> 64#include <errno.h> 65#include <ifaddrs.h> 66#include <libutil.h> 67#ifdef INET6 68#include <netdb.h> 69#endif 70#include <signal.h> 71#include <stdbool.h> 72#include <stdint.h> 73#include <stdio.h> 74#include <stdlib.h> 75#include <string.h> 76#include <sysexits.h> 77#include <unistd.h> 78 79#include "netstat.h" 80 81static void sidewaysintpr(int); 82 83#ifdef INET6 84static char addr_buf[NI_MAXHOST]; /* for getnameinfo() */ 85#endif 86 87#ifdef PF 88static const char* pfsyncacts[] = { 89 /* PFSYNC_ACT_CLR */ "clear all request", 90 /* PFSYNC_ACT_INS */ "state insert", 91 /* PFSYNC_ACT_INS_ACK */ "state inserted ack", 92 /* PFSYNC_ACT_UPD */ "state update", 93 /* PFSYNC_ACT_UPD_C */ "compressed state update", 94 /* PFSYNC_ACT_UPD_REQ */ "uncompressed state request", 95 /* PFSYNC_ACT_DEL */ "state delete", 96 /* PFSYNC_ACT_DEL_C */ "compressed state delete", 97 /* PFSYNC_ACT_INS_F */ "fragment insert", 98 /* PFSYNC_ACT_DEL_F */ "fragment delete", 99 /* PFSYNC_ACT_BUS */ "bulk update mark", 100 /* PFSYNC_ACT_TDB */ "TDB replay counter update", 101 /* PFSYNC_ACT_EOF */ "end of frame mark", 102}; 103 104static void 105pfsync_acts_stats(const char *fmt, uint64_t *a) 106{ 107 int i; 108 109 for (i = 0; i < PFSYNC_ACT_MAX; i++, a++) 110 if (*a || sflag <= 1) 111 printf(fmt, *a, pfsyncacts[i], plural(*a)); 112} 113 114/* 115 * Dump pfsync statistics structure. 116 */ 117void 118pfsync_stats(u_long off, const char *name, int af1 __unused, int proto __unused) 119{ 120 struct pfsyncstats pfsyncstat, zerostat; 121 size_t len = sizeof(struct pfsyncstats); 122 123 if (live) { 124 if (zflag) 125 memset(&zerostat, 0, len); 126 if (sysctlbyname("net.pfsync.stats", &pfsyncstat, &len, 127 zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { 128 if (errno != ENOENT) 129 warn("sysctl: net.pfsync.stats"); 130 return; 131 } 132 } else 133 kread(off, &pfsyncstat, len); 134 135 printf("%s:\n", name); 136 137#define p(f, m) if (pfsyncstat.f || sflag <= 1) \ 138 printf(m, (uintmax_t)pfsyncstat.f, plural(pfsyncstat.f)) 139 140 p(pfsyncs_ipackets, "\t%ju packet%s received (IPv4)\n"); 141 p(pfsyncs_ipackets6, "\t%ju packet%s received (IPv6)\n"); 142 pfsync_acts_stats("\t %ju %s%s received\n", 143 &pfsyncstat.pfsyncs_iacts[0]); 144 p(pfsyncs_badif, "\t\t%ju packet%s discarded for bad interface\n"); 145 p(pfsyncs_badttl, "\t\t%ju packet%s discarded for bad ttl\n"); 146 p(pfsyncs_hdrops, "\t\t%ju packet%s shorter than header\n"); 147 p(pfsyncs_badver, "\t\t%ju packet%s discarded for bad version\n"); 148 p(pfsyncs_badauth, "\t\t%ju packet%s discarded for bad HMAC\n"); 149 p(pfsyncs_badact,"\t\t%ju packet%s discarded for bad action\n"); 150 p(pfsyncs_badlen, "\t\t%ju packet%s discarded for short packet\n"); 151 p(pfsyncs_badval, "\t\t%ju state%s discarded for bad values\n"); 152 p(pfsyncs_stale, "\t\t%ju stale state%s\n"); 153 p(pfsyncs_badstate, "\t\t%ju failed state lookup/insert%s\n"); 154 p(pfsyncs_opackets, "\t%ju packet%s sent (IPv4)\n"); 155 p(pfsyncs_opackets6, "\t%ju packet%s sent (IPv6)\n"); 156 pfsync_acts_stats("\t %ju %s%s sent\n", 157 &pfsyncstat.pfsyncs_oacts[0]); 158 p(pfsyncs_onomem, "\t\t%ju failure%s due to mbuf memory error\n"); 159 p(pfsyncs_oerrors, "\t\t%ju send error%s\n"); 160#undef p 161} 162#endif /* PF */ 163 164/* 165 * Display a formatted value, or a '-' in the same space. 166 */ 167static void 168show_stat(const char *fmt, int width, u_long value, short showvalue, 169 int div1000) 170{ 171 const char *lsep, *rsep; 172 char newfmt[32]; 173 174 lsep = ""; 175 if (strncmp(fmt, "LS", 2) == 0) { 176 lsep = " "; 177 fmt += 2; 178 } 179 rsep = " "; 180 if (strncmp(fmt, "NRS", 3) == 0) { 181 rsep = ""; 182 fmt += 3; 183 } 184 if (showvalue == 0) { 185 /* Print just dash. */ 186 sprintf(newfmt, "%s%%%ds%s", lsep, width, rsep); 187 printf(newfmt, "-"); 188 return; 189 } 190 191 if (hflag) { 192 char buf[5]; 193 194 /* Format in human readable form. */ 195 humanize_number(buf, sizeof(buf), (int64_t)value, "", 196 HN_AUTOSCALE, HN_NOSPACE | HN_DECIMAL | \ 197 ((div1000) ? HN_DIVISOR_1000 : 0)); 198 sprintf(newfmt, "%s%%%ds%s", lsep, width, rsep); 199 printf(newfmt, buf); 200 } else { 201 /* Construct the format string. */ 202 sprintf(newfmt, "%s%%%d%s%s", lsep, width, fmt, rsep); 203 printf(newfmt, value); 204 } 205} 206 207/* 208 * Find next multiaddr for a given interface name. 209 */ 210static struct ifmaddrs * 211next_ifma(struct ifmaddrs *ifma, const char *name, const sa_family_t family) 212{ 213 214 for(; ifma != NULL; ifma = ifma->ifma_next) { 215 struct sockaddr_dl *sdl; 216 217 sdl = (struct sockaddr_dl *)ifma->ifma_name; 218 if (ifma->ifma_addr->sa_family == family && 219 strcmp(sdl->sdl_data, name) == 0) 220 break; 221 } 222 223 return (ifma); 224} 225 226/* 227 * Print a description of the network interfaces. 228 */ 229void 230intpr(int interval, void (*pfunc)(char *), int af) 231{ 232 struct ifaddrs *ifap, *ifa; 233 struct ifmaddrs *ifmap, *ifma; 234 235 if (interval) 236 return sidewaysintpr(interval); 237 238 if (getifaddrs(&ifap) != 0) 239 err(EX_OSERR, "getifaddrs"); 240 if (aflag && getifmaddrs(&ifmap) != 0) 241 err(EX_OSERR, "getifmaddrs"); 242 243 if (!pfunc) { 244 if (Wflag) 245 printf("%-7.7s", "Name"); 246 else 247 printf("%-5.5s", "Name"); 248 printf(" %5.5s %-13.13s %-17.17s %8.8s %5.5s %5.5s", 249 "Mtu", "Network", "Address", "Ipkts", "Ierrs", "Idrop"); 250 if (bflag) 251 printf(" %10.10s","Ibytes"); 252 printf(" %8.8s %5.5s", "Opkts", "Oerrs"); 253 if (bflag) 254 printf(" %10.10s","Obytes"); 255 printf(" %5s", "Coll"); 256 if (dflag) 257 printf(" %s", "Drop"); 258 putchar('\n'); 259 } 260 261 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 262 bool network = false, link = false; 263 264 if (interface != NULL && strcmp(ifa->ifa_name, interface) != 0) 265 continue; 266 267 if (pfunc) { 268 char *name; 269 270 name = ifa->ifa_name; 271 (*pfunc)(name); 272 273 /* 274 * Skip all ifaddrs belonging to same interface. 275 */ 276 while(ifa->ifa_next != NULL && 277 (strcmp(ifa->ifa_next->ifa_name, name) == 0)) { 278 ifa = ifa->ifa_next; 279 } 280 continue; 281 } 282 283 if (af != AF_UNSPEC && ifa->ifa_addr->sa_family != af) 284 continue; 285 286 if (Wflag) 287 printf("%-7.7s", ifa->ifa_name); 288 else 289 printf("%-5.5s", ifa->ifa_name); 290 291#define IFA_MTU(ifa) (((struct if_data *)(ifa)->ifa_data)->ifi_mtu) 292 show_stat("lu", 6, IFA_MTU(ifa), IFA_MTU(ifa), 0); 293#undef IFA_MTU 294 295 switch (ifa->ifa_addr->sa_family) { 296 case AF_UNSPEC: 297 printf("%-13.13s ", "none"); 298 printf("%-15.15s ", "none"); 299 break; 300 case AF_INET: 301 { 302 struct sockaddr_in *sin, *mask; 303 304 sin = (struct sockaddr_in *)ifa->ifa_addr; 305 mask = (struct sockaddr_in *)ifa->ifa_netmask; 306 printf("%-13.13s ", netname(sin->sin_addr.s_addr, 307 mask->sin_addr.s_addr)); 308 printf("%-17.17s ", 309 routename(sin->sin_addr.s_addr)); 310 311 network = true; 312 break; 313 } 314#ifdef INET6 315 case AF_INET6: 316 { 317 struct sockaddr_in6 *sin6, *mask; 318 319 sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; 320 mask = (struct sockaddr_in6 *)ifa->ifa_netmask; 321 322 printf("%-13.13s ", netname6(sin6, &mask->sin6_addr)); 323 getnameinfo(ifa->ifa_addr, ifa->ifa_addr->sa_len, 324 addr_buf, sizeof(addr_buf), 0, 0, NI_NUMERICHOST); 325 printf("%-17.17s ", addr_buf); 326 327 network = 1; 328 break; 329 } 330#endif /* INET6 */ 331 case AF_IPX: 332 { 333 struct sockaddr_ipx *sipx; 334 u_long net; 335 char netnum[10]; 336 337 sipx = (struct sockaddr_ipx *)ifa->ifa_addr; 338 *(union ipx_net *) &net = sipx->sipx_addr.x_net; 339 340 sprintf(netnum, "%lx", (u_long)ntohl(net)); 341 printf("ipx:%-8s ", netnum); 342 printf("%-17s ", ipx_phost((struct sockaddr *)sipx)); 343 344 network = 1; 345 break; 346 } 347 case AF_APPLETALK: 348 printf("atalk:%-12.12s ", 349 atalk_print(ifa->ifa_addr, 0x10)); 350 printf("%-11.11s ", 351 atalk_print(ifa->ifa_addr, 0x0b)); 352 break; 353 case AF_LINK: 354 { 355 struct sockaddr_dl *sdl; 356 char *cp, linknum[10]; 357 int n, m; 358 359 sdl = (struct sockaddr_dl *)ifa->ifa_addr; 360 cp = (char *)LLADDR(sdl); 361 n = sdl->sdl_alen; 362 sprintf(linknum, "<Link#%d>", sdl->sdl_index); 363 m = printf("%-13.13s ", linknum); 364 365 while ((--n >= 0) && (m < 30)) 366 m += printf("%02x%c", *cp++ & 0xff, 367 n > 0 ? ':' : ' '); 368 m = 32 - m; 369 while (m-- > 0) 370 putchar(' '); 371 372 link = 1; 373 break; 374 } 375 } 376 377#define IFA_STAT(s) (((struct if_data *)ifa->ifa_data)->ifi_ ## s) 378 show_stat("lu", 8, IFA_STAT(ipackets), link|network, 1); 379 show_stat("lu", 5, IFA_STAT(ierrors), link, 1); 380 show_stat("lu", 5, IFA_STAT(iqdrops), link, 1); 381 if (bflag) 382 show_stat("lu", 10, IFA_STAT(ibytes), link|network, 0); 383 show_stat("lu", 8, IFA_STAT(opackets), link|network, 1); 384 show_stat("lu", 5, IFA_STAT(oerrors), link, 1); 385 if (bflag) 386 show_stat("lu", 10, IFA_STAT(obytes), link|network, 0); 387 show_stat("NRSlu", 5, IFA_STAT(collisions), link, 1); 388 if (dflag) 389 show_stat("LSlu", 5, IFA_STAT(oqdrops), link, 1); 390 putchar('\n'); 391 392 if (!aflag) 393 continue; 394 395 /* 396 * Print family's multicast addresses. 397 */ 398 for (ifma = next_ifma(ifmap, ifa->ifa_name, 399 ifa->ifa_addr->sa_family); 400 ifma != NULL; 401 ifma = next_ifma(ifma, ifa->ifa_name, 402 ifa->ifa_addr->sa_family)) { 403 const char *fmt = NULL; 404 405 switch (ifma->ifma_addr->sa_family) { 406 case AF_INET: 407 { 408 struct sockaddr_in *sin; 409 410 sin = (struct sockaddr_in *)ifma->ifma_addr; 411 fmt = routename(sin->sin_addr.s_addr); 412 break; 413 } 414#ifdef INET6 415 case AF_INET6: 416 417 /* in6_fillscopeid(&msa.in6); */ 418 getnameinfo(ifma->ifma_addr, 419 ifma->ifma_addr->sa_len, addr_buf, 420 sizeof(addr_buf), 0, 0, NI_NUMERICHOST); 421 printf("%*s %s\n", 422 Wflag ? 27 : 25, "", addr_buf); 423 break; 424#endif /* INET6 */ 425 case AF_LINK: 426 { 427 struct sockaddr_dl *sdl; 428 429 sdl = (struct sockaddr_dl *)ifma->ifma_addr; 430 switch (sdl->sdl_type) { 431 case IFT_ETHER: 432 case IFT_FDDI: 433 fmt = ether_ntoa( 434 (struct ether_addr *)LLADDR(sdl)); 435 break; 436 } 437 break; 438 } 439 } 440 441 if (fmt) { 442 printf("%*s %-17.17s", 443 Wflag ? 27 : 25, "", fmt); 444 if (ifma->ifma_addr->sa_family == AF_LINK) { 445 printf(" %8lu", IFA_STAT(imcasts)); 446 printf("%*s", bflag ? 17 : 6, ""); 447 printf(" %8lu", IFA_STAT(omcasts)); 448 } 449 putchar('\n'); 450 } 451 452 ifma = ifma->ifma_next; 453 } 454 } 455 456 freeifaddrs(ifap); 457 if (aflag) 458 freeifmaddrs(ifmap); 459} 460 461struct iftot { 462 u_long ift_ip; /* input packets */ 463 u_long ift_ie; /* input errors */ 464 u_long ift_id; /* input drops */ 465 u_long ift_op; /* output packets */ 466 u_long ift_oe; /* output errors */ 467 u_long ift_od; /* output drops */ 468 u_long ift_co; /* collisions */ 469 u_long ift_ib; /* input bytes */ 470 u_long ift_ob; /* output bytes */ 471}; 472 473/* 474 * Obtain stats for interface(s). 475 */ 476static void 477fill_iftot(struct iftot *st) 478{ 479 struct ifaddrs *ifap, *ifa; 480 bool found = false; 481 482 if (getifaddrs(&ifap) != 0) 483 err(EX_OSERR, "getifaddrs"); 484 485 bzero(st, sizeof(*st)); 486 487 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 488 if (ifa->ifa_addr->sa_family != AF_LINK) 489 continue; 490 if (interface) { 491 if (strcmp(ifa->ifa_name, interface) == 0) 492 found = true; 493 else 494 continue; 495 } 496 497 st->ift_ip += IFA_STAT(ipackets); 498 st->ift_ie += IFA_STAT(ierrors); 499 st->ift_id += IFA_STAT(iqdrops); 500 st->ift_ib += IFA_STAT(ibytes); 501 st->ift_op += IFA_STAT(opackets); 502 st->ift_oe += IFA_STAT(oerrors); 503 st->ift_od += IFA_STAT(oqdrops); 504 st->ift_ob += IFA_STAT(obytes); 505 st->ift_co += IFA_STAT(collisions); 506 } 507 508 if (interface && found == false) 509 err(EX_DATAERR, "interface %s not found", interface); 510 511 freeifaddrs(ifap); 512} 513 514/* 515 * Set a flag to indicate that a signal from the periodic itimer has been 516 * caught. 517 */ 518static sig_atomic_t signalled; 519static void 520catchalarm(int signo __unused) 521{ 522 signalled = true; 523} 524 525/* 526 * Print a running summary of interface statistics. 527 * Repeat display every interval seconds, showing statistics 528 * collected over that interval. Assumes that interval is non-zero. 529 * First line printed at top of screen is always cumulative. 530 */ 531static void 532sidewaysintpr(int interval) 533{ 534 struct iftot ift[2], *new, *old; 535 struct itimerval interval_it; 536 int oldmask, line; 537 538 new = &ift[0]; 539 old = &ift[1]; 540 fill_iftot(old); 541 542 (void)signal(SIGALRM, catchalarm); 543 signalled = false; 544 interval_it.it_interval.tv_sec = interval; 545 interval_it.it_interval.tv_usec = 0; 546 interval_it.it_value = interval_it.it_interval; 547 setitimer(ITIMER_REAL, &interval_it, NULL); 548 549banner: 550 printf("%17s %14s %16s", "input", 551 interface != NULL ? interface : "(Total)", "output"); 552 putchar('\n'); 553 printf("%10s %5s %5s %10s %10s %5s %10s %5s", 554 "packets", "errs", "idrops", "bytes", "packets", "errs", "bytes", 555 "colls"); 556 if (dflag) 557 printf(" %5.5s", "drops"); 558 putchar('\n'); 559 fflush(stdout); 560 line = 0; 561 562loop: 563 if ((noutputs != 0) && (--noutputs == 0)) 564 exit(0); 565 oldmask = sigblock(sigmask(SIGALRM)); 566 while (!signalled) 567 sigpause(0); 568 signalled = false; 569 sigsetmask(oldmask); 570 line++; 571 572 fill_iftot(new); 573 574 show_stat("lu", 10, new->ift_ip - old->ift_ip, 1, 1); 575 show_stat("lu", 5, new->ift_ie - old->ift_ie, 1, 1); 576 show_stat("lu", 5, new->ift_id - old->ift_id, 1, 1); 577 show_stat("lu", 10, new->ift_ib - old->ift_ib, 1, 0); 578 show_stat("lu", 10, new->ift_op - old->ift_op, 1, 1); 579 show_stat("lu", 5, new->ift_oe - old->ift_oe, 1, 1); 580 show_stat("lu", 10, new->ift_ob - old->ift_ob, 1, 0); 581 show_stat("NRSlu", 5, new->ift_co - old->ift_co, 1, 1); 582 if (dflag) 583 show_stat("LSlu", 5, new->ift_od - old->ift_od, 1, 1); 584 putchar('\n'); 585 fflush(stdout); 586 587 if (new == &ift[0]) { 588 new = &ift[1]; 589 old = &ift[0]; 590 } else { 591 new = &ift[0]; 592 old = &ift[1]; 593 } 594 595 if (line == 21) 596 goto banner; 597 else 598 goto loop; 599 600 /* NOTREACHED */ 601} 602