Use <fcntl.h> instead of <sys/file.h> for open()'s prototype and flags.
[dragonfly.git] / usr.bin / netstat / main.c
1 /*
2  * Copyright (c) 1983, 1988, 1993
3  *      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  * 3. 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  * @(#) Copyright (c) 1983, 1988, 1993 Regents of the University of California.  All rights reserved.
30  * @(#)main.c   8.4 (Berkeley) 3/1/94
31  * $FreeBSD: src/usr.bin/netstat/main.c,v 1.34.2.12 2001/09/17 15:17:46 ru Exp $
32  */
33
34 #include <sys/param.h>
35 #include <sys/protosw.h>
36 #include <sys/socket.h>
37 #include <sys/sysctl.h>
38
39 #include <netinet/in.h>
40
41 #include <netgraph/socket/ng_socket.h>
42
43 #include <ctype.h>
44 #include <err.h>
45 #include <errno.h>
46 #include <fcntl.h>
47 #include <kvm.h>
48 #include <limits.h>
49 #include <netdb.h>
50 #include <nlist.h>
51 #include <paths.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <unistd.h>
56 #include "netstat.h"
57
58 static struct nlist nl[] = {
59 #define N_IFNET         0
60         { .n_name = "_ifnet" },
61 #define N_IMP           1
62         { .n_name = "_imp_softc" },
63 #define N_RTSTAT        2
64         { .n_name = "_rtstat" },
65 #define N_UNIXSW        3
66         { .n_name = "_localsw" },
67 #define N_IDP           4
68         { .n_name = "_nspcb"},
69 #define N_IDPSTAT       5
70         { .n_name = "_idpstat"},
71 #define N_SPPSTAT       6
72         { .n_name = "_spp_istat"},
73 #define N_NSERR         7
74         { .n_name = "_ns_errstat"},
75 #define N_CLNPSTAT      8
76         { .n_name = "_clnp_stat"},
77 #define IN_NOTUSED      9
78         { .n_name = "_tp_inpcb" },
79 #define ISO_TP          10
80         { .n_name = "_tp_refinfo" },
81 #define N_TPSTAT        11
82         { .n_name = "_tp_stat" },
83 #define N_ESISSTAT      12
84         { .n_name = "_esis_stat"},
85 #define N_NIMP          13
86         { .n_name = "_nimp"},
87 #define N_RTREE         14
88         { .n_name = "_rt_tables"},
89 #define N_CLTP          15
90         { .n_name = "_cltb"},
91 #define N_CLTPSTAT      16
92         { .n_name = "_cltpstat"},
93 #define N_NFILE         17
94         { .n_name = "_nfile" },
95 #define N_FILE          18
96         { .n_name = "_file" },
97 #define N_MRTSTAT       19
98         { .n_name = "_mrtstat" },
99 #define N_MFCTABLE      20
100         { .n_name = "_mfctable" },
101 #define N_VIFTABLE      21
102         { .n_name = "_viftable" },
103 #define N_NGSOCKS       22
104         { .n_name = "_ngsocklist"},
105 #define N_IP6STAT       23
106         { .n_name = "_ip6stat" },
107 #define N_ICMP6STAT     24
108         { .n_name = "_icmp6stat" },
109 #define N_PIM6STAT      25
110         { .n_name = "_pim6stat" },
111 #define N_MRT6PROTO     26
112         { .n_name = "_ip6_mrtproto" },
113 #define N_MRT6STAT      27
114         { .n_name = "_mrt6stat" },
115 #define N_MF6CTABLE     28
116         { .n_name = "_mf6ctable" },
117 #define N_MIF6TABLE     29
118         { .n_name = "_mif6table" },
119 #define N_MBSTAT        30
120         { .n_name = "_mbstat" },
121 #define N_MBTYPES       31
122         { .n_name = "_mbtypes" },
123 #define N_NMBCLUSTERS   32
124         { .n_name = "_nmbclusters" },
125 #define N_NMBUFS        33
126         { .n_name = "_nmbufs" },
127 #define N_RTTRASH       34
128         { .n_name = "_rttrash" },
129 #define N_NCPUS         35
130         { .n_name = "_ncpus" },
131 #define N_CARPSTAT      36
132         { .n_name = "_carpstats" },
133 #define N_NMBJCLUSTERS  37
134         { .n_name = "_nmbjclusters" },
135         { .n_name = NULL },
136 };
137
138 struct protox {
139         u_char  pr_index;               /* index into nlist of cb head */
140         u_char  pr_sindex;              /* index into nlist of stat block */
141         u_char  pr_wanted;              /* 1 if wanted, 0 otherwise */
142         void    (*pr_cblocks)(u_long, const char *, int);
143                                         /* control blocks printing routine */
144         void    (*pr_stats)(u_long, const char *, int);
145                                         /* statistics printing routine */
146         void    (*pr_istats)(char *);   /* per/if statistics printing routine */
147         const char *pr_name;            /* well-known name */
148         u_int   pr_usesysctl;           /* true if we use sysctl, not kvm */
149 } protox[] = {
150         { -1,           -1,             1,      protopr,
151           tcp_stats,    NULL,           "tcp",  IPPROTO_TCP },
152         { -1,           -1,             1,      protopr,
153           udp_stats,    NULL,           "udp",  IPPROTO_UDP },
154         { -1,           -1,             1,      protopr,
155           NULL,         NULL,           "divert",IPPROTO_DIVERT },
156         { -1,           -1,             1,      protopr,
157           ip_stats,     NULL,           "ip",   IPPROTO_RAW },
158         { -1,           -1,             1,      protopr,
159           icmp_stats,   NULL,           "icmp", IPPROTO_ICMP },
160         { -1,           -1,             1,      protopr,
161           igmp_stats,   NULL,           "igmp", IPPROTO_IGMP },
162         { -1,           N_CARPSTAT,     1,      0,
163           carp_stats,   NULL,           "carp",         0},
164         { -1,           -1,             0,      0,
165           0,            NULL,           NULL,           0}
166 };
167
168 #ifdef INET6
169 struct protox ip6protox[] = {
170         { -1,           -1,             1,      protopr,
171           tcp_stats,    NULL,           "tcp",  IPPROTO_TCP },
172         { -1,           -1,             1,      protopr,
173           udp_stats,    NULL,           "udp",  IPPROTO_UDP },
174         { -1,           N_IP6STAT,      1,      protopr,
175           ip6_stats,    ip6_ifstats,    "ip6",  IPPROTO_RAW },
176         { -1,           N_ICMP6STAT,    1,      protopr,
177           icmp6_stats,  icmp6_ifstats,  "icmp6",IPPROTO_ICMPV6 },
178 #ifdef notyet
179         { -1,           N_PIM6STAT,     1,      0,
180           pim6_stats,   NULL,           "pim6", 0 },
181 #endif
182         { -1,           -1,             1,      0,
183           rip6_stats,   NULL,           "rip6", 0 },
184         { -1,           -1,             1,      protopr,
185           pim_stats,    NULL,           "pim",  IPPROTO_PIM },
186         { -1,           -1,             0,      0,
187           0,            NULL,           0,      0 }
188 };
189 #endif /*INET6*/
190
191 struct protox netgraphprotox[] = {
192         { N_NGSOCKS,    -1,             1,      netgraphprotopr,
193           NULL,         NULL,           "ctrl", 0 },
194         { N_NGSOCKS,    -1,             1,      netgraphprotopr,
195           NULL,         NULL,           "data", 0 },
196         { -1,           -1,             0,      0,
197           0,            NULL,           NULL,   0 }
198 };
199
200 struct protox *protoprotox[] = {
201                                          protox,
202 #ifdef INET6
203                                          ip6protox,
204 #endif
205                                          NULL };
206
207 static void printproto (struct protox *, const char *, u_long);
208 static void usage (void);
209 static struct protox *name2protox (char *);
210 static struct protox *knownname (char *);
211
212 static kvm_t *kvmd;
213 static char *nlistf = NULL, *memf = NULL;
214
215 int     Aflag;          /* show addresses of protocol control block */
216 int     aflag;          /* show all sockets (including servers) */
217 int     bflag;          /* show i/f total bytes in/out */
218 int     cpuflag = -1;   /* dump route table from specific cpu */
219 int     dflag;          /* show i/f dropped packets */
220 int     gflag;          /* show group (multicast) routing or stats */
221 int     hflag;          /* show counters in human readable format */
222 int     iflag;          /* show interfaces */
223 int     Lflag;          /* show size of listen queues */
224 int     mflag;          /* show memory stats */
225 int     Pflag;          /* show more protocol info (go past 80 columns) */
226 int     numeric_addr;   /* show addresses numerically */
227 int     numeric_port;   /* show ports numerically */
228 static int pflag;       /* show given protocol */
229 int     rflag;          /* show routing tables (or routing stats) */
230 int     sflag;          /* show protocol statistics */
231 int     tflag;          /* show i/f watchdog timers */
232 int     Bflag;          /* show buffer limit instead of buffer use */
233 int     Wflag;          /* wide display */
234 int     zflag;          /* zero stats */
235
236 int     interval;       /* repeat interval for i/f stats */
237
238 char    *interface;     /* desired i/f for stats, or NULL for all i/fs */
239 int     unit;           /* unit number for above */
240
241 int     af;             /* address family */
242
243 int
244 main(int argc, char **argv)
245 {
246         struct protox *tp = NULL;  /* for printing cblocks & stats */
247         int ch;
248         int n;
249         size_t nsz;
250
251         af = AF_UNSPEC;
252
253         while ((ch = getopt(argc, argv, "Aabc:df:ghI:iLlM:mN:nPp:rSsBtuWw:z")) != -1)
254                 switch(ch) {
255                 case 'A':
256                         Aflag = 1;
257                         break;
258                 case 'a':
259                         aflag = 1;
260                         break;
261                 case 'b':
262                         bflag = 1;
263                         break;
264                 case 'c':
265                         nsz = sizeof(n);
266                         sysctlbyname("net.netisr.ncpus", &n, &nsz, NULL, 0);
267                         cpuflag = strtol(optarg, NULL, 0);
268                         if (cpuflag < 0 || cpuflag >= n) {
269                                 errx(1, "cpu%d does not have network data",
270                                     cpuflag);
271                         }
272                         break;
273                 case 'd':
274                         dflag = 1;
275                         break;
276                 case 'f':
277                         if (strcmp(optarg, "inet") == 0)
278                                 af = AF_INET;
279 #ifdef INET6
280                         else if (strcmp(optarg, "inet6") == 0)
281                                 af = AF_INET6;
282 #endif /*INET6*/
283                         else if (strcmp(optarg, "unix") == 0)
284                                 af = AF_UNIX;
285                         else if (strcmp(optarg, "ng") == 0
286                             || strcmp(optarg, "netgraph") == 0)
287                                 af = AF_NETGRAPH;
288                         else if (strcmp(optarg, "link") == 0)
289                                 af = AF_LINK;
290                         else if (strcmp(optarg, "mpls") == 0)
291                                 af = AF_MPLS;
292                         else {
293                                 errx(1, "%s: unknown address family", optarg);
294                         }
295                         break;
296                 case 'g':
297                         gflag = 1;
298                         break;
299                 case 'h':
300                         hflag = 1;
301                         break;
302                 case 'I': {
303                         char *cp;
304
305                         iflag = 1;
306                         for (cp = interface = optarg; isalpha(*cp); cp++)
307                                 continue;
308                         unit = atoi(cp);
309                         break;
310                 }
311                 case 'i':
312                         iflag = 1;
313                         break;
314                 case 'L':
315                         Lflag = 1;
316                         break;
317                 case 'M':
318                         memf = optarg;
319                         break;
320                 case 'm':
321                         mflag = 1;
322                         break;
323                 case 'N':
324                         nlistf = optarg;
325                         break;
326                 case 'n':
327                         numeric_addr = numeric_port = 1;
328                         break;
329                 case 'P':
330                         Pflag = 1;
331                         break;
332                 case 'p':
333                         if ((tp = name2protox(optarg)) == NULL) {
334                                 errx(1, 
335                                      "%s: unknown or uninstrumented protocol",
336                                      optarg);
337                         }
338                         pflag = 1;
339                         break;
340                 case 'r':
341                         rflag = 1;
342                         break;
343                 case 's':
344                         ++sflag;
345                         break;
346                 case 'S':
347                         numeric_addr = 1;
348                         break;
349                 case 'B':
350                         Bflag = 1;
351                         break;
352                 case 't':
353                         tflag = 1;
354                         break;
355                 case 'u':
356                         af = AF_UNIX;
357                         break;
358                 case 'W':
359                 case 'l':
360                         Wflag = 1;
361                         break;
362                 case 'w':
363                         interval = atoi(optarg);
364                         iflag = 1;
365                         break;
366                 case 'z':
367                         zflag = 1;
368                         break;
369                 case '?':
370                 default:
371                         usage();
372                 }
373         argv += optind;
374         argc -= optind;
375
376 #define BACKWARD_COMPATIBILITY
377 #ifdef  BACKWARD_COMPATIBILITY
378         if (*argv) {
379                 if (isdigit(**argv)) {
380                         interval = atoi(*argv);
381                         if (interval <= 0)
382                                 usage();
383                         ++argv;
384                         iflag = 1;
385                 }
386                 if (*argv) {
387                         nlistf = *argv;
388                         if (*++argv)
389                                 memf = *argv;
390                 }
391         }
392 #endif
393
394         /*
395          * Discard setgid privileges if not the running kernel so that bad
396          * guys can't print interesting stuff from kernel memory.
397          */
398         if (nlistf != NULL || memf != NULL)
399                 setgid(getgid());
400
401         if (mflag) {
402                 if (memf != NULL) {
403                         if (kread(0, 0, 0) == 0)
404                                 mbpr(nl[N_MBSTAT].n_value,
405                                     nl[N_MBTYPES].n_value,
406                                     nl[N_NMBCLUSTERS].n_value,
407                                     nl[N_NMBJCLUSTERS].n_value,
408                                     nl[N_NMBUFS].n_value,
409                                     nl[N_NCPUS].n_value);
410                 } else {
411                         mbpr(0, 0, 0, 0, 0, 0);
412                 }
413                 exit(0);
414         }
415 #if 0
416         /*
417          * Keep file descriptors open to avoid overhead
418          * of open/close on each call to get* routines.
419          */
420         sethostent(1);
421         setnetent(1);
422 #else
423         /*
424          * This does not make sense any more with DNS being default over
425          * the files.  Doing a setXXXXent(1) causes a tcp connection to be
426          * used for the queries, which is slower.
427          */
428 #endif
429         if (iflag && !sflag) {
430                 kread(0, 0, 0);
431                 intpr(interval, nl[N_IFNET].n_value, NULL, nl[N_NCPUS].n_value);
432                 exit(0);
433         }
434         if (rflag) {
435                 kread(0, 0, 0);
436                 if (sflag)
437                         rt_stats();
438                 else
439                         routepr(nl[N_RTREE].n_value);
440                 exit(0);
441         }
442         if (gflag) {
443                 kread(0, 0, 0);
444                 if (sflag) {
445                         if (af == AF_INET || af == AF_UNSPEC)
446                                 mrt_stats(nl[N_MRTSTAT].n_value);
447 #ifdef INET6
448                         if (af == AF_INET6 || af == AF_UNSPEC)
449                                 mrt6_stats(nl[N_MRT6STAT].n_value);
450 #endif
451                 } else {
452                         if (af == AF_INET || af == AF_UNSPEC)
453                                 mroutepr(nl[N_MFCTABLE].n_value,
454                                          nl[N_VIFTABLE].n_value);
455 #ifdef INET6
456                         if (af == AF_INET6 || af == AF_UNSPEC)
457                                 mroute6pr(nl[N_MF6CTABLE].n_value,
458                                           nl[N_MIF6TABLE].n_value);
459 #endif
460                 }
461                 exit(0);
462         }
463
464         kread(0, 0, 0);
465         if (tp) {
466                 printproto(tp, tp->pr_name, nl[N_NCPUS].n_value);
467                 exit(0);
468         }
469         if (af == AF_INET || af == AF_UNSPEC)
470                 for (tp = protox; tp->pr_name; tp++)
471                         printproto(tp, tp->pr_name, nl[N_NCPUS].n_value);
472 #ifdef INET6
473         if (af == AF_INET6 || af == AF_UNSPEC)
474                 for (tp = ip6protox; tp->pr_name; tp++)
475                         printproto(tp, tp->pr_name, nl[N_NCPUS].n_value);
476 #endif /*INET6*/
477         if (af == AF_NETGRAPH || af == AF_UNSPEC)
478                 for (tp = netgraphprotox; tp->pr_name; tp++)
479                         printproto(tp, tp->pr_name, nl[N_NCPUS].n_value);
480         if ((af == AF_UNIX || af == AF_UNSPEC) && !Lflag && !sflag)
481                 unixpr();
482         exit(0);
483 }
484
485 /*
486  * Print out protocol statistics or control blocks (per sflag).
487  * If the interface was not specifically requested, and the symbol
488  * is not in the namelist, ignore this one.
489  */
490 static void
491 printproto(struct protox *tp, const char *name, u_long ncpusaddr)
492 {
493         void (*pr)(u_long, const char *, int);
494         u_long off;
495
496         if (sflag) {
497                 if (iflag) {
498                         if (tp->pr_istats)
499                                 intpr(interval, nl[N_IFNET].n_value,
500                                       tp->pr_istats, ncpusaddr);
501                         else if (pflag)
502                                 printf("%s: no per-interface stats routine\n",
503                                     tp->pr_name);
504                         return;
505                 }
506                 else {
507                         pr = tp->pr_stats;
508                         if (!pr) {
509                                 if (pflag)
510                                         printf("%s: no stats routine\n",
511                                             tp->pr_name);
512                                 return;
513                         }
514                         off = tp->pr_usesysctl ? tp->pr_usesysctl 
515                                 : nl[tp->pr_sindex].n_value;
516                 }
517         } else {
518                 pr = tp->pr_cblocks;
519                 if (!pr) {
520                         if (pflag)
521                                 printf("%s: no PCB routine\n", tp->pr_name);
522                         return;
523                 }
524                 off = tp->pr_usesysctl ? tp->pr_usesysctl
525                         : nl[tp->pr_index].n_value;
526         }
527         if (pr != NULL && (off || af != AF_UNSPEC))
528                 (*pr)(off, name, af);
529 }
530
531 /*
532  * Read kernel memory, return 0 on success.
533  */
534 int
535 kread(u_long addr, char *buf, int size)
536 {
537         if (kvmd == NULL) {
538                 /*
539                  * XXX.
540                  */
541                 kvmd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf);
542                 if (kvmd != NULL) {
543                         if (kvm_nlist(kvmd, nl) < 0) {
544                                 if(nlistf)
545                                         errx(1, "%s: kvm_nlist: %s", nlistf,
546                                              kvm_geterr(kvmd));
547                                 else
548                                         errx(1, "kvm_nlist: %s", kvm_geterr(kvmd));
549                         }
550
551                         if (nl[0].n_type == 0) {
552                                 if(nlistf)
553                                         errx(1, "%s: no namelist", nlistf);
554                                 else
555                                         errx(1, "no namelist");
556                         }
557                 } else {
558                         warnx("kvm not available");
559                         return(-1);
560                 }
561         }
562         if (!buf)
563                 return (0);
564         if (kvm_read(kvmd, addr, buf, size) != size) {
565                 warnx("%s", kvm_geterr(kvmd));
566                 return (-1);
567         }
568         return (0);
569 }
570
571 const char *
572 plural(int n)
573 {
574         return (n != 1 ? "s" : "");
575 }
576
577 const char *
578 plurales(int n)
579 {
580         return (n != 1 ? "es" : "");
581 }
582
583 /*
584  * Find the protox for the given "well-known" name.
585  */
586 static struct protox *
587 knownname(char *name)
588 {
589         struct protox **tpp, *tp;
590
591         for (tpp = protoprotox; *tpp; tpp++)
592                 for (tp = *tpp; tp->pr_name; tp++)
593                         if (strcmp(tp->pr_name, name) == 0)
594                                 return (tp);
595         return (NULL);
596 }
597
598 /*
599  * Find the protox corresponding to name.
600  */
601 static struct protox *
602 name2protox(char *name)
603 {
604         struct protox *tp;
605         char **alias;                   /* alias from p->aliases */
606         struct protoent *p;
607
608         /*
609          * Try to find the name in the list of "well-known" names. If that
610          * fails, check if name is an alias for an Internet protocol.
611          */
612         if ((tp = knownname(name)) != NULL)
613                 return (tp);
614
615         setprotoent(1);                 /* make protocol lookup cheaper */
616         while ((p = getprotoent()) != NULL) {
617                 /* assert: name not same as p->name */
618                 for (alias = p->p_aliases; *alias; alias++)
619                         if (strcmp(name, *alias) == 0) {
620                                 endprotoent();
621                                 return (knownname(p->p_name));
622                         }
623         }
624         endprotoent();
625         return (NULL);
626 }
627
628 static void
629 usage(void)
630 {
631         (void)fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
632 "usage: netstat [-AaLnPSW] [-c cpu] [-f protocol_family | -p protocol]\n"
633 "               [-M core] [-N system]",
634 "       netstat -i | -I interface [-aBbdhnt] [-f address_family]\n"
635 "               [-M core] [-N system]",
636 "       netstat -w wait [-I interface] [-dh] [-M core] [-N system]",
637 "       netstat -s [-s] [-z] [-f protocol_family | -p protocol] [-M core]",
638 "       netstat -i | -I interface -s [-f protocol_family | -p protocol]\n"
639 "               [-M core] [-N system]",
640 "       netstat -m [-M core] [-N system]",
641 "       netstat -r [-AanW] [-f address_family] [-M core] [-N system]",
642 "       netstat -rs [-s] [-M core] [-N system]",
643 "       netstat -g [-W] [-f address_family] [-M core] [-N system]",
644 "       netstat -gs [-s] [-f address_family] [-M core] [-N system]");
645         exit(1);
646 }