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