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