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