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