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