if.c revision 291101
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 291101 2015-11-20 16:10:58Z ume $"); 39 40#include <sys/param.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 u_int ifn_len_max = 5; 235 236 if (interval) 237 return sidewaysintpr(interval); 238 239 if (getifaddrs(&ifap) != 0) 240 err(EX_OSERR, "getifaddrs"); 241 if (aflag && getifmaddrs(&ifmap) != 0) 242 err(EX_OSERR, "getifmaddrs"); 243 244 if (Wflag) { 245 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 246 if (interface != NULL && 247 strcmp(ifa->ifa_name, interface) != 0) 248 continue; 249 if (af != AF_UNSPEC && ifa->ifa_addr->sa_family != af) 250 continue; 251 ifn_len_max = MAX(ifn_len_max, strlen(ifa->ifa_name)); 252 } 253 } 254 255 if (!pfunc) { 256 printf("%-*.*s", ifn_len_max, ifn_len_max, "Name"); 257 printf(" %5.5s %-13.13s %-17.17s %8.8s %5.5s %5.5s", 258 "Mtu", "Network", "Address", "Ipkts", "Ierrs", "Idrop"); 259 if (bflag) 260 printf(" %10.10s","Ibytes"); 261 printf(" %8.8s %5.5s", "Opkts", "Oerrs"); 262 if (bflag) 263 printf(" %10.10s","Obytes"); 264 printf(" %5s", "Coll"); 265 if (dflag) 266 printf(" %s", "Drop"); 267 putchar('\n'); 268 } 269 270 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 271 bool network = false, link = false; 272 273 if (interface != NULL && strcmp(ifa->ifa_name, interface) != 0) 274 continue; 275 276 if (pfunc) { 277 char *name; 278 279 name = ifa->ifa_name; 280 (*pfunc)(name); 281 282 /* 283 * Skip all ifaddrs belonging to same interface. 284 */ 285 while(ifa->ifa_next != NULL && 286 (strcmp(ifa->ifa_next->ifa_name, name) == 0)) { 287 ifa = ifa->ifa_next; 288 } 289 continue; 290 } 291 292 if (af != AF_UNSPEC && ifa->ifa_addr->sa_family != af) 293 continue; 294 295 printf("%-*.*s", ifn_len_max, ifn_len_max, ifa->ifa_name); 296 297#define IFA_MTU(ifa) (((struct if_data *)(ifa)->ifa_data)->ifi_mtu) 298 show_stat("lu", 6, IFA_MTU(ifa), IFA_MTU(ifa), 0); 299#undef IFA_MTU 300 301 switch (ifa->ifa_addr->sa_family) { 302 case AF_UNSPEC: 303 printf("%-13.13s ", "none"); 304 printf("%-15.15s ", "none"); 305 break; 306 case AF_INET: 307 { 308 struct sockaddr_in *sin, *mask; 309 310 sin = (struct sockaddr_in *)ifa->ifa_addr; 311 mask = (struct sockaddr_in *)ifa->ifa_netmask; 312 printf("%-13.13s ", netname(sin->sin_addr.s_addr, 313 mask->sin_addr.s_addr)); 314 printf("%-17.17s ", 315 routename(sin->sin_addr.s_addr)); 316 317 network = true; 318 break; 319 } 320#ifdef INET6 321 case AF_INET6: 322 { 323 struct sockaddr_in6 *sin6, *mask; 324 325 sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; 326 mask = (struct sockaddr_in6 *)ifa->ifa_netmask; 327 328 printf("%-13.13s ", netname6(sin6, &mask->sin6_addr)); 329 getnameinfo(ifa->ifa_addr, ifa->ifa_addr->sa_len, 330 addr_buf, sizeof(addr_buf), 0, 0, NI_NUMERICHOST); 331 printf("%-17.17s ", addr_buf); 332 333 network = 1; 334 break; 335 } 336#endif /* INET6 */ 337 case AF_IPX: 338 { 339 struct sockaddr_ipx *sipx; 340 u_long net; 341 char netnum[10]; 342 343 sipx = (struct sockaddr_ipx *)ifa->ifa_addr; 344 *(union ipx_net *) &net = sipx->sipx_addr.x_net; 345 346 sprintf(netnum, "%lx", (u_long)ntohl(net)); 347 printf("ipx:%-8s ", netnum); 348 printf("%-17s ", ipx_phost((struct sockaddr *)sipx)); 349 350 network = 1; 351 break; 352 } 353 case AF_APPLETALK: 354 printf("atalk:%-12.12s ", 355 atalk_print(ifa->ifa_addr, 0x10)); 356 printf("%-11.11s ", 357 atalk_print(ifa->ifa_addr, 0x0b)); 358 break; 359 case AF_LINK: 360 { 361 struct sockaddr_dl *sdl; 362 char *cp, linknum[10]; 363 int n, m; 364 365 sdl = (struct sockaddr_dl *)ifa->ifa_addr; 366 cp = (char *)LLADDR(sdl); 367 n = sdl->sdl_alen; 368 sprintf(linknum, "<Link#%d>", sdl->sdl_index); 369 m = printf("%-13.13s ", linknum); 370 371 while ((--n >= 0) && (m < 30)) 372 m += printf("%02x%c", *cp++ & 0xff, 373 n > 0 ? ':' : ' '); 374 m = 32 - m; 375 while (m-- > 0) 376 putchar(' '); 377 378 link = 1; 379 break; 380 } 381 } 382 383#define IFA_STAT(s) (((struct if_data *)ifa->ifa_data)->ifi_ ## s) 384 show_stat("lu", 8, IFA_STAT(ipackets), link|network, 1); 385 show_stat("lu", 5, IFA_STAT(ierrors), link, 1); 386 show_stat("lu", 5, IFA_STAT(iqdrops), link, 1); 387 if (bflag) 388 show_stat("lu", 10, IFA_STAT(ibytes), link|network, 0); 389 show_stat("lu", 8, IFA_STAT(opackets), link|network, 1); 390 show_stat("lu", 5, IFA_STAT(oerrors), link, 1); 391 if (bflag) 392 show_stat("lu", 10, IFA_STAT(obytes), link|network, 0); 393 show_stat("NRSlu", 5, IFA_STAT(collisions), link, 1); 394 if (dflag) 395 show_stat("LSlu", 5, IFA_STAT(oqdrops), link, 1); 396 putchar('\n'); 397 398 if (!aflag) 399 continue; 400 401 /* 402 * Print family's multicast addresses. 403 */ 404 for (ifma = next_ifma(ifmap, ifa->ifa_name, 405 ifa->ifa_addr->sa_family); 406 ifma != NULL; 407 ifma = next_ifma(ifma, ifa->ifa_name, 408 ifa->ifa_addr->sa_family)) { 409 const char *fmt = NULL; 410 411 switch (ifma->ifma_addr->sa_family) { 412 case AF_INET: 413 { 414 struct sockaddr_in *sin; 415 416 sin = (struct sockaddr_in *)ifma->ifma_addr; 417 fmt = routename(sin->sin_addr.s_addr); 418 break; 419 } 420#ifdef INET6 421 case AF_INET6: 422 423 /* in6_fillscopeid(&msa.in6); */ 424 getnameinfo(ifma->ifma_addr, 425 ifma->ifma_addr->sa_len, addr_buf, 426 sizeof(addr_buf), 0, 0, NI_NUMERICHOST); 427 printf("%*s %s\n", 428 Wflag ? 27 : 25, "", addr_buf); 429 break; 430#endif /* INET6 */ 431 case AF_LINK: 432 { 433 struct sockaddr_dl *sdl; 434 435 sdl = (struct sockaddr_dl *)ifma->ifma_addr; 436 switch (sdl->sdl_type) { 437 case IFT_ETHER: 438 case IFT_FDDI: 439 fmt = ether_ntoa( 440 (struct ether_addr *)LLADDR(sdl)); 441 break; 442 } 443 break; 444 } 445 } 446 447 if (fmt) { 448 printf("%*s %-17.17s", 449 Wflag ? 27 : 25, "", fmt); 450 if (ifma->ifma_addr->sa_family == AF_LINK) { 451 printf(" %8lu", IFA_STAT(imcasts)); 452 printf("%*s", bflag ? 17 : 6, ""); 453 printf(" %8lu", IFA_STAT(omcasts)); 454 } 455 putchar('\n'); 456 } 457 458 ifma = ifma->ifma_next; 459 } 460 } 461 462 freeifaddrs(ifap); 463 if (aflag) 464 freeifmaddrs(ifmap); 465} 466 467struct iftot { 468 u_long ift_ip; /* input packets */ 469 u_long ift_ie; /* input errors */ 470 u_long ift_id; /* input drops */ 471 u_long ift_op; /* output packets */ 472 u_long ift_oe; /* output errors */ 473 u_long ift_od; /* output drops */ 474 u_long ift_co; /* collisions */ 475 u_long ift_ib; /* input bytes */ 476 u_long ift_ob; /* output bytes */ 477}; 478 479/* 480 * Obtain stats for interface(s). 481 */ 482static void 483fill_iftot(struct iftot *st) 484{ 485 struct ifaddrs *ifap, *ifa; 486 bool found = false; 487 488 if (getifaddrs(&ifap) != 0) 489 err(EX_OSERR, "getifaddrs"); 490 491 bzero(st, sizeof(*st)); 492 493 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 494 if (ifa->ifa_addr->sa_family != AF_LINK) 495 continue; 496 if (interface) { 497 if (strcmp(ifa->ifa_name, interface) == 0) 498 found = true; 499 else 500 continue; 501 } 502 503 st->ift_ip += IFA_STAT(ipackets); 504 st->ift_ie += IFA_STAT(ierrors); 505 st->ift_id += IFA_STAT(iqdrops); 506 st->ift_ib += IFA_STAT(ibytes); 507 st->ift_op += IFA_STAT(opackets); 508 st->ift_oe += IFA_STAT(oerrors); 509 st->ift_od += IFA_STAT(oqdrops); 510 st->ift_ob += IFA_STAT(obytes); 511 st->ift_co += IFA_STAT(collisions); 512 } 513 514 if (interface && found == false) 515 err(EX_DATAERR, "interface %s not found", interface); 516 517 freeifaddrs(ifap); 518} 519 520/* 521 * Set a flag to indicate that a signal from the periodic itimer has been 522 * caught. 523 */ 524static sig_atomic_t signalled; 525static void 526catchalarm(int signo __unused) 527{ 528 signalled = true; 529} 530 531/* 532 * Print a running summary of interface statistics. 533 * Repeat display every interval seconds, showing statistics 534 * collected over that interval. Assumes that interval is non-zero. 535 * First line printed at top of screen is always cumulative. 536 */ 537static void 538sidewaysintpr(int interval) 539{ 540 struct iftot ift[2], *new, *old; 541 struct itimerval interval_it; 542 int oldmask, line; 543 544 new = &ift[0]; 545 old = &ift[1]; 546 fill_iftot(old); 547 548 (void)signal(SIGALRM, catchalarm); 549 signalled = false; 550 interval_it.it_interval.tv_sec = interval; 551 interval_it.it_interval.tv_usec = 0; 552 interval_it.it_value = interval_it.it_interval; 553 setitimer(ITIMER_REAL, &interval_it, NULL); 554 555banner: 556 printf("%17s %14s %16s", "input", 557 interface != NULL ? interface : "(Total)", "output"); 558 putchar('\n'); 559 printf("%10s %5s %5s %10s %10s %5s %10s %5s", 560 "packets", "errs", "idrops", "bytes", "packets", "errs", "bytes", 561 "colls"); 562 if (dflag) 563 printf(" %5.5s", "drops"); 564 putchar('\n'); 565 fflush(stdout); 566 line = 0; 567 568loop: 569 if ((noutputs != 0) && (--noutputs == 0)) 570 exit(0); 571 oldmask = sigblock(sigmask(SIGALRM)); 572 while (!signalled) 573 sigpause(0); 574 signalled = false; 575 sigsetmask(oldmask); 576 line++; 577 578 fill_iftot(new); 579 580 show_stat("lu", 10, new->ift_ip - old->ift_ip, 1, 1); 581 show_stat("lu", 5, new->ift_ie - old->ift_ie, 1, 1); 582 show_stat("lu", 5, new->ift_id - old->ift_id, 1, 1); 583 show_stat("lu", 10, new->ift_ib - old->ift_ib, 1, 0); 584 show_stat("lu", 10, new->ift_op - old->ift_op, 1, 1); 585 show_stat("lu", 5, new->ift_oe - old->ift_oe, 1, 1); 586 show_stat("lu", 10, new->ift_ob - old->ift_ob, 1, 0); 587 show_stat("NRSlu", 5, new->ift_co - old->ift_co, 1, 1); 588 if (dflag) 589 show_stat("LSlu", 5, new->ift_od - old->ift_od, 1, 1); 590 putchar('\n'); 591 fflush(stdout); 592 593 if (new == &ift[0]) { 594 new = &ift[1]; 595 old = &ift[0]; 596 } else { 597 new = &ift[0]; 598 old = &ift[1]; 599 } 600 601 if (line == 21) 602 goto banner; 603 else 604 goto loop; 605 606 /* NOTREACHED */ 607} 608