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