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