if.c revision 1.106
1236099Sdes/* $NetBSD: if.c,v 1.106 2022/10/24 08:11:25 msaitoh Exp $ */ 2236099Sdes 3236099Sdes/* 4236099Sdes * Copyright (c) 1983, 1988, 1993 5236099Sdes * The Regents of the University of California. All rights reserved. 6236099Sdes * 7236099Sdes * Redistribution and use in source and binary forms, with or without 8236099Sdes * modification, are permitted provided that the following conditions 9255376Sdes * are met: 10236099Sdes * 1. Redistributions of source code must retain the above copyright 11236099Sdes * notice, this list of conditions and the following disclaimer. 12236099Sdes * 2. Redistributions in binary form must reproduce the above copyright 13236099Sdes * notice, this list of conditions and the following disclaimer in the 14236099Sdes * documentation and/or other materials provided with the distribution. 15236099Sdes * 3. Neither the name of the University nor the names of its contributors 16236099Sdes * may be used to endorse or promote products derived from this software 17236099Sdes * without specific prior written permission. 18236099Sdes * 19236099Sdes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20236099Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21236099Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22236099Sdes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23236099Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24236099Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25236099Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26236099Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27236099Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28236099Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29255376Sdes * SUCH DAMAGE. 30236099Sdes */ 31236099Sdes 32236099Sdes#include <sys/cdefs.h> 33236099Sdes#ifndef lint 34236099Sdes#if 0 35236099Sdesstatic char sccsid[] = "from: @(#)if.c 8.2 (Berkeley) 2/21/94"; 36236099Sdes#else 37236099Sdes__RCSID("$NetBSD: if.c,v 1.106 2022/10/24 08:11:25 msaitoh Exp $"); 38236099Sdes#endif 39236099Sdes#endif /* not lint */ 40236099Sdes 41236099Sdes#include <sys/param.h> 42236099Sdes#include <sys/types.h> 43236099Sdes#include <sys/protosw.h> 44236099Sdes#include <sys/socket.h> 45236099Sdes#include <sys/time.h> 46236099Sdes#include <sys/sysctl.h> 47236099Sdes#include <sys/ioctl.h> 48236099Sdes 49236099Sdes#include <net/if.h> 50236099Sdes#include <net/if_dl.h> 51236099Sdes#include <net/if_types.h> 52236099Sdes#include <net/route.h> 53236099Sdes#include <netinet/in.h> 54236099Sdes#include <netinet/in_var.h> 55236099Sdes#include <arpa/inet.h> 56236099Sdes 57236099Sdes#include <kvm.h> 58236099Sdes#include <signal.h> 59236099Sdes#include <stdio.h> 60236099Sdes#include <stdlib.h> 61236099Sdes#include <string.h> 62236099Sdes#include <unistd.h> 63236099Sdes#include <netdb.h> 64236099Sdes#include <err.h> 65236099Sdes 66236099Sdes#include "netstat.h" 67236099Sdes#include "rtutil.h" 68236099Sdes#include "prog_ops.h" 69236099Sdes 70236099Sdes#define MAXIF 100 71236099Sdes 72236099Sdes#define HUMBUF_SIZE 7 73236099Sdes 74236099Sdesstruct iftot { 75236099Sdes char ift_name[IFNAMSIZ]; /* interface name */ 76236099Sdes uint64_t ift_ip; /* input packets */ 77236099Sdes uint64_t ift_ib; /* input bytes */ 78236099Sdes uint64_t ift_ie; /* input errors */ 79236099Sdes uint64_t ift_iq; /* input drops */ 80236099Sdes uint64_t ift_op; /* output packets */ 81236099Sdes uint64_t ift_ob; /* output bytes */ 82236099Sdes uint64_t ift_oe; /* output errors */ 83236099Sdes uint64_t ift_oq; /* output drops */ 84236099Sdes uint64_t ift_co; /* collisions */ 85236099Sdes}; 86236099Sdes 87236099Sdesstruct if_data_ext { 88236099Sdes uint64_t ifi_oqdrops; 89236099Sdes}; 90236099Sdes 91236099Sdesstatic void set_lines(void); 92236099Sdesstatic void print_addr(const int, struct sockaddr *, struct sockaddr **, 93236099Sdes struct if_data *, struct ifnet *, struct if_data_ext *); 94236099Sdesstatic void sidewaysintpr(u_int, u_long); 95236099Sdes 96236099Sdesstatic void iftot_banner(struct iftot *); 97236099Sdesstatic void iftot_print_sum(struct iftot *, struct iftot *); 98236099Sdesstatic void iftot_print(struct iftot *, struct iftot *); 99236099Sdes 100236099Sdesstatic void catchalarm(int); 101236099Sdesstatic void get_rtaddrs(int, struct sockaddr *, struct sockaddr **); 102236099Sdesstatic void fetchifs(void); 103236099Sdes 104236099Sdesstatic int if_data_ext_get(const char *, struct if_data_ext *); 105236099Sdesstatic void intpr_sysctl(void); 106236099Sdesstatic void intpr_kvm(u_long, void (*)(const char *)); 107236099Sdes 108236099Sdesstruct iftot iftot[MAXIF], ip_cur, ip_old, sum_cur, sum_old; 109236099Sdesstatic sig_atomic_t signalled; /* set when alarm goes off */ 110236099Sdes 111236099Sdesstatic unsigned redraw_lines = 21; 112236099Sdes 113236099Sdesstatic void 114236099Sdesset_lines(void) 115236099Sdes{ 116236099Sdes static bool first = true; 117236099Sdes struct ttysize ts; 118236099Sdes 119236099Sdes if (!first) 120236099Sdes return; 121236099Sdes first = false; 122236099Sdes if (ioctl(STDOUT_FILENO, TIOCGSIZE, &ts) != -1 && ts.ts_lines) 123236099Sdes redraw_lines = ts.ts_lines - 3; 124236099Sdes} 125236099Sdes 126236099Sdes 127236099Sdes/* 128236099Sdes * Print a description of the network interfaces. 129236099Sdes * NOTE: ifnetaddr is the location of the kernel global "ifnet", 130236099Sdes * which is a TAILQ_HEAD. 131236099Sdes */ 132236099Sdesvoid 133236099Sdesintpr(int interval, u_long ifnetaddr, void (*pfunc)(const char *)) 134236099Sdes{ 135236099Sdes 136236099Sdes if (interval) { 137236099Sdes sidewaysintpr((unsigned)interval, ifnetaddr); 138236099Sdes return; 139236099Sdes } 140236099Sdes 141236099Sdes if (use_sysctl) 142236099Sdes intpr_sysctl(); 143236099Sdes else 144236099Sdes intpr_kvm(ifnetaddr, pfunc); 145236099Sdes} 146236099Sdes 147236099Sdesstatic void 148236099Sdesintpr_header(void) 149236099Sdes{ 150236099Sdes 151236099Sdes if (!sflag && !pflag) { 152236099Sdes if (bflag) { 153236099Sdes printf("%-5.5s %-5.5s %-13.13s %-17.17s " 154236099Sdes "%10.10s %10.10s", 155236099Sdes "Name", "Mtu", "Network", "Address", 156 "Ibytes", "Obytes"); 157 } else { 158 printf("%-5.5s %-5.5s %-13.13s %-17.17s " 159 "%8.8s %5.5s", 160 "Name", "Mtu", "Network", "Address", "Ipkts", "Ierrs"); 161 if (dflag) 162 printf(" %6.6s", "Idrops"); 163 printf(" %8.8s %5.5s %5.5s", 164 "Opkts", "Oerrs", "Colls"); 165 } 166 if (dflag) 167 printf(" %6.6s", "Odrops"); 168 if (tflag) 169 printf(" %4.4s", "Time"); 170 putchar('\n'); 171 } 172} 173 174int 175if_data_ext_get(const char *ifname, struct if_data_ext *dext) 176{ 177 char namebuf[1024]; 178 size_t len; 179 int drops; 180 181 /* For sysctl */ 182 snprintf(namebuf, sizeof(namebuf), 183 "net.interfaces.%s.sndq.drops", ifname); 184 len = sizeof(drops); 185 if (sysctlbyname(namebuf, &drops, &len, NULL, 0) 186 == -1) { 187 warnx("'%s' not found", namebuf); 188 dext->ifi_oqdrops = 0; 189 return -1; 190 } else 191 dext->ifi_oqdrops = drops; 192 193 return 0; 194} 195 196static void 197intpr_sysctl(void) 198{ 199 struct if_msghdr *ifm; 200 int mib[6] = { CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0 }; 201 static char *buf = NULL; 202 static size_t olen; 203 char *next, *lim, *cp; 204 struct rt_msghdr *rtm; 205 struct ifa_msghdr *ifam; 206 struct if_data *ifd = NULL; 207 struct sockaddr *sa, *rti_info[RTAX_MAX]; 208 struct sockaddr_dl *sdl; 209 uint64_t total = 0; 210 size_t len; 211 int did = 1, rtax = 0, n; 212 char name[IFNAMSIZ + 1]; /* + 1 for `*' */ 213 char origname[IFNAMSIZ]; /* without `*' */ 214 int ifindex = 0; 215 216 if (prog_sysctl(mib, 6, NULL, &len, NULL, 0) == -1) 217 err(1, "sysctl"); 218 if (len > olen) { 219 free(buf); 220 if ((buf = malloc(len)) == NULL) 221 err(1, NULL); 222 olen = len; 223 } 224 if (prog_sysctl(mib, 6, buf, &len, NULL, 0) == -1) 225 err(1, "sysctl"); 226 227 intpr_header(); 228 229 lim = buf + len; 230 for (next = buf; next < lim; next += rtm->rtm_msglen) { 231 struct if_data_ext dext; 232 233 rtm = (struct rt_msghdr *)next; 234 if (rtm->rtm_version != RTM_VERSION) 235 continue; 236 switch (rtm->rtm_type) { 237 case RTM_IFINFO: 238 total = 0; 239 ifm = (struct if_msghdr *)next; 240 ifd = &ifm->ifm_data; 241 242 sa = (struct sockaddr *)(ifm + 1); 243 get_rtaddrs(ifm->ifm_addrs, sa, rti_info); 244 245 sdl = (struct sockaddr_dl *)rti_info[RTAX_IFP]; 246 if (sdl == NULL || sdl->sdl_family != AF_LINK) 247 continue; 248 249 bzero(name, sizeof(name)); 250 if (sdl->sdl_nlen >= IFNAMSIZ) 251 memcpy(name, sdl->sdl_data, IFNAMSIZ - 1); 252 else if (sdl->sdl_nlen > 0) 253 memcpy(name, sdl->sdl_data, sdl->sdl_nlen); 254 255 if (interface != NULL && strcmp(name, interface) != 0) 256 continue; 257 258 ifindex = sdl->sdl_index; 259 260 /* Keep the original name */ 261 strcpy(origname, name); 262 263 /* Mark inactive interfaces with a '*' */ 264 cp = strchr(name, '\0'); 265 if ((ifm->ifm_flags & IFF_UP) == 0) { 266 *cp++ = '*'; 267 *cp = '\0'; 268 } 269 270 if (qflag) { 271 total = ifd->ifi_ibytes + ifd->ifi_obytes + 272 ifd->ifi_ipackets + ifd->ifi_ierrors + 273 ifd->ifi_opackets + ifd->ifi_oerrors + 274 ifd->ifi_collisions; 275 if (dflag) 276 total += ifd->ifi_iqdrops; 277 if (total == 0) 278 continue; 279 } 280 /* Skip the first one */ 281 if (did) { 282 did = 0; 283 continue; 284 } 285 rtax = RTAX_IFP; 286 break; 287 case RTM_NEWADDR: 288 if (qflag && total == 0) 289 continue; 290 if (interface != NULL && strcmp(name, interface) != 0) 291 continue; 292 ifam = (struct ifa_msghdr *)next; 293 if ((ifam->ifam_addrs & (RTA_NETMASK | RTA_IFA | 294 RTA_BRD)) == 0) 295 break; 296 297 sa = (struct sockaddr *)(ifam + 1); 298 299 get_rtaddrs(ifam->ifam_addrs, sa, rti_info); 300 rtax = RTAX_IFA; 301 did = 1; 302 break; 303 default: 304 continue; 305 } 306 if (vflag) 307 n = strlen(name) < 5 ? 5 : strlen(name); 308 else 309 n = 5; 310 311 printf("%-*.*s %-5" PRIu64 " ", n, n, name, ifd->ifi_mtu); 312 if (dflag) 313 if_data_ext_get(origname, &dext); 314 315 print_addr(ifindex, rti_info[rtax], rti_info, ifd, 316 NULL, dflag ? &dext : NULL); 317 } 318} 319 320union ifaddr_u { 321 struct ifaddr ifa; 322 struct in_ifaddr in; 323#ifdef INET6 324 struct in6_ifaddr in6; 325#endif /* INET6 */ 326}; 327 328static void 329ifname_to_ifdata(int s, const char *ifname, struct if_data * const ifd) 330{ 331 struct ifdatareq ifdr; 332 333 memset(ifd, 0, sizeof(*ifd)); 334 strlcpy(ifdr.ifdr_name, ifname, sizeof(ifdr.ifdr_name)); 335 if (ioctl(s, SIOCGIFDATA, &ifdr) != 0) 336 return; 337 memcpy(ifd, &ifdr.ifdr_data, sizeof(ifdr.ifdr_data)); 338} 339 340static void 341intpr_kvm(u_long ifnetaddr, void (*pfunc)(const char *)) 342{ 343 struct ifnet ifnet; 344 struct if_data ifd; 345 union ifaddr_u ifaddr; 346 u_long ifaddraddr; 347 struct ifnet_head ifhead; /* TAILQ_HEAD */ 348 char name[IFNAMSIZ + 1]; /* + 1 for `*' */ 349 int s; 350 351 if (ifnetaddr == 0) { 352 printf("ifnet: symbol not defined\n"); 353 return; 354 } 355 356 /* 357 * Find the pointer to the first ifnet structure. Replace 358 * the pointer to the TAILQ_HEAD with the actual pointer 359 * to the first list element. 360 */ 361 if (kread(ifnetaddr, (char *)&ifhead, sizeof ifhead)) 362 return; 363 ifnetaddr = (u_long)ifhead.tqh_first; 364 365 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) 366 return; 367 368 intpr_header(); 369 370 ifaddraddr = 0; 371 while (ifnetaddr || ifaddraddr) { 372 char *cp; 373 int n; 374 375 if (ifaddraddr == 0) { 376 if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet)) 377 return; 378 memmove(name, ifnet.if_xname, IFNAMSIZ); 379 name[IFNAMSIZ - 1] = '\0'; /* sanity */ 380 ifnetaddr = (u_long)ifnet.if_list.tqe_next; 381 if (interface != NULL && strcmp(name, interface) != 0) 382 continue; 383 cp = strchr(name, '\0'); 384 385 if (pfunc) { 386 (*pfunc)(name); 387 continue; 388 } 389 390 if ((ifnet.if_flags & IFF_UP) == 0) 391 *cp++ = '*'; 392 *cp = '\0'; 393 ifaddraddr = (u_long)ifnet.if_addrlist.tqh_first; 394 } 395 if (vflag) 396 n = strlen(name) < 5 ? 5 : strlen(name); 397 else 398 n = 5; 399 printf("%-*.*s %-5llu ", n, n, name, 400 (unsigned long long)ifnet.if_mtu); 401 if (ifaddraddr == 0) { 402 printf("%-13.13s ", "none"); 403 printf("%-17.17s ", "none"); 404 } else { 405 struct sockaddr *sa; 406 407 if (kread(ifaddraddr, (char *)&ifaddr, sizeof ifaddr)) 408 { 409 ifaddraddr = 0; 410 continue; 411 } 412#define CP(x) ((char *)(x)) 413 cp = (CP(ifaddr.ifa.ifa_addr) - CP(ifaddraddr)) + 414 CP(&ifaddr); 415 sa = (struct sockaddr *)cp; 416 ifname_to_ifdata(s, name, &ifd); 417 print_addr(ifnet.if_index, sa, (void *)&ifaddr, 418 &ifd, &ifnet, NULL); 419 } 420 ifaddraddr = (u_long)ifaddr.ifa.ifa_list.tqe_next; 421 } 422 close(s); 423} 424 425static void 426mc_print(const int ifindex, const size_t ias, const char *oid, int *mcast_oids, 427 void (*pr)(const void *)) 428{ 429 uint8_t *mcast_addrs, *p; 430 const size_t incr = 2 * ias + sizeof(uint32_t); 431 size_t len; 432 433 if (mcast_oids[0] == 0) { 434 size_t oidlen = 4; 435 if (sysctlnametomib(oid, mcast_oids, &oidlen) == -1) { 436 warnx("'%s' not found", oid); 437 return; 438 } 439 if (oidlen != 3) { 440 warnx("Wrong OID path for '%s'", oid); 441 return; 442 } 443 } 444 445 if (mcast_oids[3] == ifindex) 446 return; 447 mcast_oids[3] = ifindex; 448 449 mcast_addrs = asysctl(mcast_oids, 4, &len); 450 if (mcast_addrs == NULL && len != 0) { 451 warn("failed to read '%s'", oid); 452 return; 453 } 454 if (len) { 455 p = mcast_addrs; 456 while (len >= incr) { 457 (*pr)((p + ias)); 458 p += incr; 459 len -= incr; 460 } 461 } 462 free(mcast_addrs); 463} 464 465#ifdef INET6 466static void 467ia6_print(const struct in6_addr *ia) 468{ 469 struct sockaddr_in6 as6; 470 char hbuf[NI_MAXHOST]; /* for getnameinfo() */ 471 int n; 472 473 memset(&as6, 0, sizeof(as6)); 474 as6.sin6_len = sizeof(struct sockaddr_in6); 475 as6.sin6_family = AF_INET6; 476 as6.sin6_addr = *ia; 477 inet6_getscopeid(&as6, INET6_IS_ADDR_MC_LINKLOCAL); 478 if (getnameinfo((struct sockaddr *)&as6, as6.sin6_len, hbuf, 479 sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) { 480 strlcpy(hbuf, "??", sizeof(hbuf)); 481 } 482 if (vflag) 483 n = strlen(hbuf) < 17 ? 17 : strlen(hbuf); 484 else 485 n = 17; 486 printf("\n%25s %-*.*s ", "", n, n, hbuf); 487} 488 489static void 490mc6_print(const int ifindex) 491{ 492 static int mcast_oids[4]; 493 494 mc_print(ifindex, sizeof(struct in6_addr), "net.inet6.multicast", 495 mcast_oids, (void (*)(const void *))ia6_print); 496} 497#endif 498 499static void 500ia4_print(const struct in_addr *ia) 501{ 502 printf("\n%25s %-17.17s ", "", routename4(ia->s_addr, nflag)); 503} 504 505static void 506mc4_print(const int ifindex) 507{ 508 static int mcast_oids[4]; 509 510 mc_print(ifindex, sizeof(struct in_addr), "net.inet.multicast", 511 mcast_oids, (void (*)(const void *))ia4_print); 512} 513 514static void 515print_addr(const int ifindex, struct sockaddr *sa, struct sockaddr **rtinfo, 516 struct if_data *ifd, struct ifnet *ifnet, struct if_data_ext *dext) 517{ 518 char hexsep = '.'; /* for hexprint */ 519 static const char hexfmt[] = "%02x%c"; /* for hexprint */ 520 char hbuf[NI_MAXHOST]; /* for getnameinfo() */ 521#ifdef INET6 522 const int niflag = NI_NUMERICHOST; 523 struct sockaddr_in6 *sin6, *netmask6; 524#endif 525 struct sockaddr_in netmask; 526 struct sockaddr_in *sin; 527 char *cp; 528 int n, m; 529 530 switch (sa->sa_family) { 531 case AF_UNSPEC: 532 printf("%-13.13s ", "none"); 533 printf("%-17.17s ", "none"); 534 break; 535 case AF_INET: 536 sin = (struct sockaddr_in *)sa; 537 if (use_sysctl) { 538 netmask = 539 *((struct sockaddr_in *)rtinfo[RTAX_NETMASK]); 540 } else { 541 struct in_ifaddr *ifaddr_in = (void *)rtinfo; 542 netmask.sin_addr.s_addr = ifaddr_in->ia_subnetmask; 543 } 544 cp = netname4(sin, &netmask, nflag); 545 if (vflag) 546 n = strlen(cp) < 13 ? 13 : strlen(cp); 547 else 548 n = 13; 549 printf("%-*.*s ", n, n, cp); 550 cp = routename4(sin->sin_addr.s_addr, nflag); 551 if (vflag) 552 n = strlen(cp) < 17 ? 17 : strlen(cp); 553 else 554 n = 17; 555 printf("%-*.*s ", n, n, cp); 556 557 if (!aflag) 558 break; 559 if (ifnet) { 560 u_long multiaddr; 561 struct in_multi inm; 562 union ifaddr_u *ifaddr = (union ifaddr_u *)rtinfo; 563 564 multiaddr = (u_long)ifaddr->in.ia_multiaddrs.lh_first; 565 while (multiaddr != 0) { 566 kread(multiaddr, (char *)&inm, sizeof inm); 567 ia4_print(&inm.inm_addr); 568 multiaddr = (u_long)inm.inm_list.le_next; 569 } 570 } else 571 mc4_print(ifindex); 572 break; 573#ifdef INET6 574 case AF_INET6: 575 sin6 = (struct sockaddr_in6 *)sa; 576 inet6_getscopeid(sin6, INET6_IS_ADDR_LINKLOCAL); 577#ifdef __KAME__ 578 if (!vflag) 579 sin6->sin6_scope_id = 0; 580#endif 581 582 if (use_sysctl) 583 netmask6 = (struct sockaddr_in6 *)rtinfo[RTAX_NETMASK]; 584 else { 585 struct in6_ifaddr *ifaddr_in6 = (void *)rtinfo; 586 netmask6 = &ifaddr_in6->ia_prefixmask; 587 } 588 589 cp = netname6(sin6, netmask6, nflag); 590 if (vflag) 591 n = strlen(cp) < 13 ? 13 : strlen(cp); 592 else 593 n = 13; 594 printf("%-*.*s ", n, n, cp); 595 if (getnameinfo((struct sockaddr *)sin6, 596 sin6->sin6_len, 597 hbuf, sizeof(hbuf), NULL, 0, 598 niflag) != 0) { 599 strlcpy(hbuf, "?", sizeof(hbuf)); 600 } 601 cp = hbuf; 602 if (vflag) 603 n = strlen(cp) < 17 ? 17 : strlen(cp); 604 else 605 n = 17; 606 printf("%-*.*s ", n, n, cp); 607 608 if (!aflag) 609 break; 610 if (ifnet) { 611 u_long multiaddr; 612 struct in6_multi inm; 613 union ifaddr_u *ifaddr = (union ifaddr_u *)rtinfo; 614 615 multiaddr = (u_long)ifaddr->in6._ia6_multiaddrs.lh_first; 616 while (multiaddr != 0) { 617 kread(multiaddr, (char *)&inm, sizeof inm); 618 ia6_print(&inm.in6m_addr); 619 multiaddr = (u_long)inm.in6m_entry.le_next; 620 } 621 } else 622 mc6_print(ifindex); 623 break; 624#endif /*INET6*/ 625#ifndef SMALL 626 case AF_APPLETALK: 627 printf("atalk:%-7.7s ", atalk_print(sa, 0x10)); 628 printf("%-17.17s ", atalk_print(sa, 0x0b)); 629 break; 630#endif 631 case AF_LINK: 632 printf("%-13.13s ", "<Link>"); 633 if (getnameinfo(sa, sa->sa_len, 634 hbuf, sizeof(hbuf), NULL, 0, 635 NI_NUMERICHOST) != 0) { 636 strlcpy(hbuf, "?", sizeof(hbuf)); 637 } 638 cp = hbuf; 639 if (vflag) 640 n = strlen(cp) < 17 ? 17 : strlen(cp); 641 else 642 n = 17; 643 printf("%-*.*s ", n, n, cp); 644 break; 645 646 default: 647 m = printf("(%d)", sa->sa_family); 648 for (cp = sa->sa_len + (char *)sa; 649 --cp > sa->sa_data && (*cp == 0);) {} 650 n = cp - sa->sa_data + 1; 651 cp = sa->sa_data; 652 653 while (--n >= 0) 654 m += printf(hexfmt, *cp++ & 0xff, 655 n > 0 ? hexsep : ' '); 656 m = 32 - m; 657 while (m-- > 0) 658 putchar(' '); 659 break; 660 } 661 662 if (bflag) { 663 char humbuf[HUMBUF_SIZE]; 664 665 if (hflag && humanize_number(humbuf, sizeof(humbuf), 666 ifd->ifi_ibytes, "", HN_AUTOSCALE, HN_NOSPACE | HN_B) > 0) 667 printf("%10s ", humbuf); 668 else 669 printf("%10llu ", (unsigned long long)ifd->ifi_ibytes); 670 671 if (hflag && humanize_number(humbuf, sizeof(humbuf), 672 ifd->ifi_obytes, "", HN_AUTOSCALE, HN_NOSPACE | HN_B) > 0) 673 printf("%10s", humbuf); 674 else 675 printf("%10llu", (unsigned long long)ifd->ifi_obytes); 676 } else { 677 printf("%8llu %5llu", 678 (unsigned long long)ifd->ifi_ipackets, 679 (unsigned long long)ifd->ifi_ierrors); 680 if (dflag) 681 printf(" %6" PRIu64, ifd->ifi_iqdrops); 682 printf(" %8llu %5llu %5llu", 683 (unsigned long long)ifd->ifi_opackets, 684 (unsigned long long)ifd->ifi_oerrors, 685 (unsigned long long)ifd->ifi_collisions); 686 } 687 if (dflag) 688 printf(" %6" PRIu64, ifnet ? 689 ifnet->if_snd.ifq_drops : dext->ifi_oqdrops); 690 if (tflag) 691 printf(" %4d", ifnet ? ifnet->if_timer : 0); 692 putchar('\n'); 693} 694 695static void 696iftot_banner(struct iftot *ift) 697{ 698 if (bflag) 699 printf("%7.7s in %8.8s %6.6s out %5.5s", 700 ift->ift_name, " ", 701 ift->ift_name, " "); 702 else 703 printf("%5.5s in %5.5s%5.5s out %5.5s %5.5s", 704 ift->ift_name, " ", 705 ift->ift_name, " ", " "); 706 if (dflag) 707 printf(" %5.5s", " "); 708 709 if (bflag) 710 printf(" %7.7s in %8.8s %6.6s out %5.5s", 711 "total", " ", "total", " "); 712 else 713 printf(" %5.5s in %5.5s%5.5s out %5.5s %5.5s", 714 "total", " ", "total", " ", " "); 715 if (dflag) 716 printf(" %5.5s", " "); 717 putchar('\n'); 718 if (bflag) 719 printf("%10.10s %8.8s %10.10s %5.5s", 720 "bytes", " ", "bytes", " "); 721 else 722 printf("%8.8s %5.5s %8.8s %5.5s %5.5s", 723 "packets", "errs", "packets", "errs", "colls"); 724 if (dflag) 725 printf(" %5.5s", "drops"); 726 727 if (bflag) 728 printf(" %10.10s %8.8s %10.10s %5.5s", 729 "bytes", " ", "bytes", " "); 730 else 731 printf(" %8.8s %5.5s %8.8s %5.5s %5.5s", 732 "packets", "errs", "packets", "errs", "colls"); 733 if (dflag) 734 printf(" %5.5s", "drops"); 735 putchar('\n'); 736 fflush(stdout); 737} 738 739static void 740iftot_print(struct iftot *cur, struct iftot *old) 741{ 742 if (bflag) 743 printf("%10" PRIu64 " %8.8s %10" PRIu64 " %5.5s", 744 cur->ift_ib - old->ift_ib, " ", 745 cur->ift_ob - old->ift_ob, " "); 746 else 747 printf("%8" PRIu64 " %5" PRIu64 " %8" PRIu64 " %5" PRIu64 " %5" PRIu64, 748 cur->ift_ip - old->ift_ip, 749 cur->ift_ie - old->ift_ie, 750 cur->ift_op - old->ift_op, 751 cur->ift_oe - old->ift_oe, 752 cur->ift_co - old->ift_co); 753 if (dflag) 754 printf(" %5" PRIu64, cur->ift_oq - old->ift_oq); 755} 756 757static void 758iftot_print_sum(struct iftot *cur, struct iftot *old) 759{ 760 if (bflag) 761 printf(" %10" PRIu64 " %8.8s %10" PRIu64 " %5.5s", 762 cur->ift_ib - old->ift_ib, " ", 763 cur->ift_ob - old->ift_ob, " "); 764 else 765 printf(" %8" PRIu64 " %5" PRIu64 " %8" PRIu64 " %5" PRIu64 " %5" PRIu64, 766 cur->ift_ip - old->ift_ip, 767 cur->ift_ie - old->ift_ie, 768 cur->ift_op - old->ift_op, 769 cur->ift_oe - old->ift_oe, 770 cur->ift_co - old->ift_co); 771 772 if (dflag) 773 printf(" %5" PRIu64, cur->ift_oq - old->ift_oq); 774} 775 776__dead static void 777sidewaysintpr_sysctl(unsigned interval) 778{ 779 struct itimerval it; 780 sigset_t emptyset; 781 sigset_t noalrm; 782 unsigned line; 783 784 set_lines(); 785 786 fetchifs(); 787 if (ip_cur.ift_name[0] == '\0') { 788 fprintf(stderr, "%s: %s: unknown interface\n", 789 getprogname(), interface); 790 exit(1); 791 } 792 793 sigemptyset(&emptyset); 794 sigemptyset(&noalrm); 795 sigaddset(&noalrm, SIGALRM); 796 sigprocmask(SIG_SETMASK, &noalrm, NULL); 797 798 signalled = 0; 799 (void)signal(SIGALRM, catchalarm); 800 801 it.it_interval.tv_sec = it.it_value.tv_sec = interval; 802 it.it_interval.tv_usec = it.it_value.tv_usec = 0; 803 setitimer(ITIMER_REAL, &it, NULL); 804 805banner: 806 iftot_banner(&ip_cur); 807 808 line = 0; 809 bzero(&ip_old, sizeof(ip_old)); 810 bzero(&sum_old, sizeof(sum_old)); 811loop: 812 bzero(&sum_cur, sizeof(sum_cur)); 813 814 fetchifs(); 815 816 iftot_print(&ip_cur, &ip_old); 817 818 ip_old = ip_cur; 819 820 iftot_print_sum(&sum_cur, &sum_old); 821 822 sum_old = sum_cur; 823 824 putchar('\n'); 825 fflush(stdout); 826 line++; 827 if (signalled == 0) 828 sigsuspend(&emptyset); 829 830 signalled = 0; 831 if (line == redraw_lines) 832 goto banner; 833 goto loop; 834 /*NOTREACHED*/ 835} 836 837static void 838sidewaysintpr_kvm(unsigned interval, u_long off) 839{ 840 struct itimerval it; 841 sigset_t emptyset; 842 sigset_t noalrm; 843 struct ifnet ifnet; 844 struct if_data ifd; 845 u_long firstifnet; 846 struct iftot *ip, *total; 847 unsigned line; 848 struct iftot *lastif, *sum, *interesting; 849 struct ifnet_head ifhead; /* TAILQ_HEAD */ 850 int s; 851 852 set_lines(); 853 854 /* 855 * Find the pointer to the first ifnet structure. Replace 856 * the pointer to the TAILQ_HEAD with the actual pointer 857 * to the first list element. 858 */ 859 if (kread(off, (char *)&ifhead, sizeof ifhead)) 860 return; 861 firstifnet = (u_long)ifhead.tqh_first; 862 863 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) 864 return; 865 866 lastif = iftot; 867 sum = iftot + MAXIF - 1; 868 total = sum - 1; 869 interesting = (interface == NULL) ? iftot : NULL; 870 for (off = firstifnet, ip = iftot; off;) { 871 if (kread(off, (char *)&ifnet, sizeof ifnet)) 872 break; 873 memset(ip->ift_name, 0, sizeof(ip->ift_name)); 874 snprintf(ip->ift_name, IFNAMSIZ, "%s", ifnet.if_xname); 875 if (interface && strcmp(ifnet.if_xname, interface) == 0) 876 interesting = ip; 877 ip++; 878 if (ip >= iftot + MAXIF - 2) 879 break; 880 off = (u_long)ifnet.if_list.tqe_next; 881 } 882 if (interesting == NULL) { 883 fprintf(stderr, "%s: %s: unknown interface\n", 884 getprogname(), interface); 885 exit(1); 886 } 887 lastif = ip; 888 889 sigemptyset(&emptyset); 890 sigemptyset(&noalrm); 891 sigaddset(&noalrm, SIGALRM); 892 sigprocmask(SIG_SETMASK, &noalrm, NULL); 893 894 signalled = 0; 895 (void)signal(SIGALRM, catchalarm); 896 897 it.it_interval.tv_sec = it.it_value.tv_sec = interval; 898 it.it_interval.tv_usec = it.it_value.tv_usec = 0; 899 setitimer(ITIMER_REAL, &it, NULL); 900 901banner: 902 if (bflag) 903 printf("%7.7s in %8.8s %6.6s out %5.5s", 904 interesting->ift_name, " ", 905 interesting->ift_name, " "); 906 else 907 printf("%5.5s in %5.5s%5.5s out %5.5s %5.5s", 908 interesting->ift_name, " ", 909 interesting->ift_name, " ", " "); 910 if (dflag) 911 printf(" %5.5s", " "); 912 if (lastif - iftot > 0) { 913 if (bflag) 914 printf(" %7.7s in %8.8s %6.6s out %5.5s", 915 "total", " ", "total", " "); 916 else 917 printf(" %5.5s in %5.5s%5.5s out %5.5s %5.5s", 918 "total", " ", "total", " ", " "); 919 if (dflag) 920 printf(" %5.5s", " "); 921 } 922 for (ip = iftot; ip < iftot + MAXIF; ip++) { 923 ip->ift_ip = 0; 924 ip->ift_ib = 0; 925 ip->ift_ie = 0; 926 ip->ift_iq = 0; 927 ip->ift_op = 0; 928 ip->ift_ob = 0; 929 ip->ift_oe = 0; 930 ip->ift_oq = 0; 931 ip->ift_co = 0; 932 } 933 putchar('\n'); 934 if (bflag) 935 printf("%10.10s %8.8s %10.10s %5.5s", 936 "bytes", " ", "bytes", " "); 937 else 938 printf("%8.8s %5.5s %8.8s %5.5s %5.5s", 939 "packets", "errs", "packets", "errs", "colls"); 940 if (dflag) 941 printf(" %5.5s", "drops"); 942 if (lastif - iftot > 0) { 943 if (bflag) 944 printf(" %10.10s %8.8s %10.10s %5.5s", 945 "bytes", " ", "bytes", " "); 946 else 947 printf(" %8.8s %5.5s %8.8s %5.5s %5.5s", 948 "packets", "errs", "packets", "errs", "colls"); 949 if (dflag) 950 printf(" %5.5s", "drops"); 951 } 952 putchar('\n'); 953 fflush(stdout); 954 line = 0; 955loop: 956 sum->ift_ip = 0; 957 sum->ift_ib = 0; 958 sum->ift_ie = 0; 959 sum->ift_iq = 0; 960 sum->ift_op = 0; 961 sum->ift_ob = 0; 962 sum->ift_oe = 0; 963 sum->ift_oq = 0; 964 sum->ift_co = 0; 965 for (off = firstifnet, ip = iftot; off && ip < lastif; ip++) { 966 if (kread(off, (char *)&ifnet, sizeof ifnet)) { 967 off = 0; 968 continue; 969 } 970 ifname_to_ifdata(s, ip->ift_name, &ifd); 971 if (ip == interesting) { 972 if (bflag) { 973 char humbuf[HUMBUF_SIZE]; 974 975 if (hflag && humanize_number(humbuf, 976 sizeof(humbuf), 977 ifd.ifi_ibytes - ip->ift_ib, "", 978 HN_AUTOSCALE, HN_NOSPACE | HN_B) > 0) 979 printf("%10s %8.8s ", humbuf, " "); 980 else 981 printf("%10llu %8.8s ", 982 (unsigned long long) 983 (ifd.ifi_ibytes-ip->ift_ib), " "); 984 985 if (hflag && humanize_number(humbuf, 986 sizeof(humbuf), 987 ifd.ifi_obytes - ip->ift_ob, "", 988 HN_AUTOSCALE, HN_NOSPACE | HN_B) > 0) 989 printf("%10s %5.5s", humbuf, " "); 990 else 991 printf("%10llu %5.5s", 992 (unsigned long long) 993 (ifd.ifi_obytes-ip->ift_ob), " "); 994 } else { 995 printf("%8llu %5llu %8llu %5llu %5llu", 996 (unsigned long long) 997 (ifd.ifi_ipackets - ip->ift_ip), 998 (unsigned long long) 999 (ifd.ifi_ierrors - ip->ift_ie), 1000 (unsigned long long) 1001 (ifd.ifi_opackets - ip->ift_op), 1002 (unsigned long long) 1003 (ifd.ifi_oerrors - ip->ift_oe), 1004 (unsigned long long) 1005 (ifd.ifi_collisions - ip->ift_co)); 1006 } 1007 if (dflag) 1008 printf(" %5" PRIu64, 1009 ifnet.if_snd.ifq_drops - ip->ift_oq); 1010 } 1011 ip->ift_ip = ifd.ifi_ipackets; 1012 ip->ift_ib = ifd.ifi_ibytes; 1013 ip->ift_ie = ifd.ifi_ierrors; 1014 ip->ift_op = ifd.ifi_opackets; 1015 ip->ift_ob = ifd.ifi_obytes; 1016 ip->ift_oe = ifd.ifi_oerrors; 1017 ip->ift_co = ifd.ifi_collisions; 1018 ip->ift_oq = ifnet.if_snd.ifq_drops; 1019 sum->ift_ip += ip->ift_ip; 1020 sum->ift_ib += ip->ift_ib; 1021 sum->ift_ie += ip->ift_ie; 1022 sum->ift_op += ip->ift_op; 1023 sum->ift_ob += ip->ift_ob; 1024 sum->ift_oe += ip->ift_oe; 1025 sum->ift_co += ip->ift_co; 1026 sum->ift_oq += ip->ift_oq; 1027 off = (u_long)ifnet.if_list.tqe_next; 1028 } 1029 if (lastif - iftot > 0) { 1030 if (bflag) { 1031 char humbuf[HUMBUF_SIZE]; 1032 1033 if (hflag && humanize_number(humbuf, 1034 sizeof(humbuf), sum->ift_ib - total->ift_ib, "", 1035 HN_AUTOSCALE, HN_NOSPACE | HN_B) > 0) 1036 printf(" %10s %8.8s ", humbuf, " "); 1037 else 1038 printf(" %10llu %8.8s ", 1039 (unsigned long long) 1040 (sum->ift_ib - total->ift_ib), " "); 1041 1042 if (hflag && humanize_number(humbuf, 1043 sizeof(humbuf), sum->ift_ob - total->ift_ob, "", 1044 HN_AUTOSCALE, HN_NOSPACE | HN_B) > 0) 1045 printf("%10s %5.5s", humbuf, " "); 1046 else 1047 printf("%10llu %5.5s", 1048 (unsigned long long) 1049 (sum->ift_ob - total->ift_ob), " "); 1050 } else { 1051 printf(" %8llu %5llu %8llu %5llu %5llu", 1052 (unsigned long long) 1053 (sum->ift_ip - total->ift_ip), 1054 (unsigned long long) 1055 (sum->ift_ie - total->ift_ie), 1056 (unsigned long long) 1057 (sum->ift_op - total->ift_op), 1058 (unsigned long long) 1059 (sum->ift_oe - total->ift_oe), 1060 (unsigned long long) 1061 (sum->ift_co - total->ift_co)); 1062 } 1063 if (dflag) 1064 printf(" %5llu", 1065 (unsigned long long)(sum->ift_oq - total->ift_oq)); 1066 } 1067 *total = *sum; 1068 putchar('\n'); 1069 fflush(stdout); 1070 line++; 1071 if (signalled == 0) 1072 sigsuspend(&emptyset); 1073 1074 signalled = 0; 1075 if (line == redraw_lines) 1076 goto banner; 1077 goto loop; 1078 /*NOTREACHED*/ 1079} 1080 1081/* 1082 * Print a running summary of interface statistics. 1083 * Repeat display every interval seconds, showing statistics 1084 * collected over that interval. Assumes that interval is non-zero. 1085 * First line printed at top of screen is always cumulative. 1086 */ 1087static void 1088sidewaysintpr(unsigned int interval, u_long off) 1089{ 1090 1091 if (use_sysctl) 1092 sidewaysintpr_sysctl(interval); 1093 else 1094 sidewaysintpr_kvm(interval, off); 1095} 1096 1097/* 1098 * Called if an interval expires before sidewaysintpr has completed a loop. 1099 * Sets a flag to not wait for the alarm. 1100 */ 1101static void 1102catchalarm(int signo) 1103{ 1104 1105 signalled = true; 1106} 1107 1108static void 1109get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) 1110{ 1111 int i; 1112 1113 for (i = 0; i < RTAX_MAX; i++) { 1114 if (addrs & (1 << i)) { 1115 rti_info[i] = sa; 1116 sa = (struct sockaddr *)((char *)(sa) + 1117 RT_ROUNDUP(sa->sa_len)); 1118 } else 1119 rti_info[i] = NULL; 1120 } 1121} 1122 1123static void 1124fetchifs(void) 1125{ 1126 struct if_msghdr *ifm; 1127 int mib[6] = { CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0 }; 1128 struct rt_msghdr *rtm; 1129 struct if_data *ifd = NULL; 1130 struct sockaddr *sa, *rti_info[RTAX_MAX]; 1131 struct sockaddr_dl *sdl; 1132 static char *buf = NULL; 1133 static size_t olen; 1134 struct if_data_ext dext; 1135 char *next, *lim; 1136 char name[IFNAMSIZ]; 1137 size_t len; 1138 1139 if (prog_sysctl(mib, 6, NULL, &len, NULL, 0) == -1) 1140 err(1, "sysctl"); 1141 if (len > olen) { 1142 free(buf); 1143 if ((buf = malloc(len)) == NULL) 1144 err(1, NULL); 1145 olen = len; 1146 } 1147 if (prog_sysctl(mib, 6, buf, &len, NULL, 0) == -1) 1148 err(1, "sysctl"); 1149 1150 memset(&dext, 0, sizeof(dext)); 1151 lim = buf + len; 1152 for (next = buf; next < lim; next += rtm->rtm_msglen) { 1153 rtm = (struct rt_msghdr *)next; 1154 if (rtm->rtm_version != RTM_VERSION) 1155 continue; 1156 switch (rtm->rtm_type) { 1157 case RTM_IFINFO: 1158 ifm = (struct if_msghdr *)next; 1159 ifd = &ifm->ifm_data; 1160 1161 sa = (struct sockaddr *)(ifm + 1); 1162 get_rtaddrs(ifm->ifm_addrs, sa, rti_info); 1163 1164 sdl = (struct sockaddr_dl *)rti_info[RTAX_IFP]; 1165 if (sdl == NULL || sdl->sdl_family != AF_LINK) 1166 continue; 1167 bzero(name, sizeof(name)); 1168 if (sdl->sdl_nlen >= IFNAMSIZ) 1169 memcpy(name, sdl->sdl_data, IFNAMSIZ - 1); 1170 else if (sdl->sdl_nlen > 0) 1171 memcpy(name, sdl->sdl_data, sdl->sdl_nlen); 1172 1173 if_data_ext_get(name, &dext); 1174 1175 if (interface != NULL && !strcmp(name, interface)) { 1176 strlcpy(ip_cur.ift_name, name, 1177 sizeof(ip_cur.ift_name)); 1178 ip_cur.ift_ip = ifd->ifi_ipackets; 1179 ip_cur.ift_ib = ifd->ifi_ibytes; 1180 ip_cur.ift_ie = ifd->ifi_ierrors; 1181 ip_cur.ift_op = ifd->ifi_opackets; 1182 ip_cur.ift_ob = ifd->ifi_obytes; 1183 ip_cur.ift_oe = ifd->ifi_oerrors; 1184 ip_cur.ift_co = ifd->ifi_collisions; 1185 ip_cur.ift_iq = ifd->ifi_iqdrops; 1186 ip_cur.ift_oq = dext.ifi_oqdrops; 1187 } 1188 1189 sum_cur.ift_ip += ifd->ifi_ipackets; 1190 sum_cur.ift_ib += ifd->ifi_ibytes; 1191 sum_cur.ift_ie += ifd->ifi_ierrors; 1192 sum_cur.ift_op += ifd->ifi_opackets; 1193 sum_cur.ift_ob += ifd->ifi_obytes; 1194 sum_cur.ift_oe += ifd->ifi_oerrors; 1195 sum_cur.ift_co += ifd->ifi_collisions; 1196 sum_cur.ift_iq += ifd->ifi_iqdrops; 1197 sum_cur.ift_oq += dext.ifi_oqdrops; 1198 break; 1199 } 1200 } 1201 if (interface == NULL) { 1202 strlcpy(ip_cur.ift_name, name, 1203 sizeof(ip_cur.ift_name)); 1204 ip_cur.ift_ip = ifd->ifi_ipackets; 1205 ip_cur.ift_ib = ifd->ifi_ibytes; 1206 ip_cur.ift_ie = ifd->ifi_ierrors; 1207 ip_cur.ift_op = ifd->ifi_opackets; 1208 ip_cur.ift_ob = ifd->ifi_obytes; 1209 ip_cur.ift_oe = ifd->ifi_oerrors; 1210 ip_cur.ift_co = ifd->ifi_collisions; 1211 ip_cur.ift_iq = ifd->ifi_iqdrops; 1212 ip_cur.ift_oq = dext.ifi_oqdrops; 1213 } 1214} 1215