2 * SPDX-License-Identifier: BSD-3-Clause
4 * Copyright (c) 1983, 1988, 1993
5 * Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
33 static char const copyright[] =
34 "@(#) Copyright (c) 1983, 1988, 1993\n\
35 Regents of the University of California. All rights reserved.\n";
40 static char sccsid[] = "@(#)main.c 8.4 (Berkeley) 3/1/94";
44 #include <sys/cdefs.h>
45 #include <sys/param.h>
50 #include <sys/protosw.h>
51 #include <sys/socket.h>
52 #include <sys/socketvar.h>
53 #include <sys/sysctl.h>
55 #include <netinet/in.h>
58 #include <netgraph/ng_socket.h>
82 static struct protox {
83 int pr_index; /* index into nlist of cb head */
84 int pr_sindex; /* index into nlist of stat block */
85 u_char pr_wanted; /* 1 if wanted, 0 otherwise */
86 void (*pr_cblocks)(u_long, const char *, int, int);
87 /* control blocks printing routine */
88 void (*pr_stats)(u_long, const char *, int, int);
89 /* statistics printing routine */
90 void (*pr_istats)(char *); /* per/if statistics printing routine */
91 const char *pr_name; /* well-known name */
92 int pr_usesysctl; /* non-zero if we use sysctl, not kvm */
95 { -1 , N_TCPSTAT, 1, protopr,
96 tcp_stats, NULL, "tcp", 1, IPPROTO_TCP },
97 { -1 , N_UDPSTAT, 1, protopr,
98 udp_stats, NULL, "udp", 1, IPPROTO_UDP },
100 { -1, N_SCTPSTAT, 1, sctp_protopr,
101 sctp_stats, NULL, "sctp", 1, IPPROTO_SCTP },
104 { -1, -1, 1, protopr,
105 NULL, NULL, "sdp", 1, IPPROTO_TCP },
107 { -1 , -1, 1, protopr,
108 divert_stats, NULL, "divert", 1, 0 },
109 { -1 , N_IPSTAT, 1, protopr,
110 ip_stats, NULL, "ip", 1, IPPROTO_RAW },
111 { -1 , N_ICMPSTAT, 1, protopr,
112 icmp_stats, NULL, "icmp", 1, IPPROTO_ICMP },
113 { -1 , N_IGMPSTAT, 1, protopr,
114 igmp_stats, NULL, "igmp", 1, IPPROTO_IGMP },
116 { -1, N_IPSEC4STAT, 1, NULL, /* keep as compat */
117 ipsec_stats, NULL, "ipsec", 1, 0},
118 { -1, N_AHSTAT, 1, NULL,
119 ah_stats, NULL, "ah", 1, 0},
120 { -1, N_ESPSTAT, 1, NULL,
121 esp_stats, NULL, "esp", 1, 0},
122 { -1, N_IPCOMPSTAT, 1, NULL,
123 ipcomp_stats, NULL, "ipcomp", 1, 0},
125 { -1 , N_PIMSTAT, 1, protopr,
126 pim_stats, NULL, "pim", 1, IPPROTO_PIM },
127 { -1, N_CARPSTATS, 1, NULL,
128 carp_stats, NULL, "carp", 1, 0 },
130 { -1, N_PFSYNCSTATS, 1, NULL,
131 pfsync_stats, NULL, "pfsync", 1, 0 },
133 { -1, N_ARPSTAT, 1, NULL,
134 arp_stats, NULL, "arp", 1, 0 },
136 NULL, NULL, NULL, 0, 0 }
140 static struct protox ip6protox[] = {
141 { -1 , N_TCPSTAT, 1, protopr,
142 tcp_stats, NULL, "tcp", 1, IPPROTO_TCP },
143 { -1 , N_UDPSTAT, 1, protopr,
144 udp_stats, NULL, "udp", 1, IPPROTO_UDP },
145 { -1 , N_IP6STAT, 1, protopr,
146 ip6_stats, ip6_ifstats, "ip6", 1, IPPROTO_RAW },
147 { -1 , N_ICMP6STAT, 1, protopr,
148 icmp6_stats, icmp6_ifstats, "icmp6", 1, IPPROTO_ICMPV6 },
150 { -1, -1, 1, protopr,
151 NULL, NULL, "sdp", 1, IPPROTO_TCP },
154 { -1, N_IPSEC6STAT, 1, NULL,
155 ipsec_stats, NULL, "ipsec6", 1, 0 },
158 { -1, N_PIM6STAT, 1, NULL,
159 pim6_stats, NULL, "pim6", 1, 0 },
161 { -1, N_RIP6STAT, 1, NULL,
162 rip6_stats, NULL, "rip6", 1, 0 },
164 NULL, NULL, NULL, 0, 0 }
169 static struct protox pfkeyprotox[] = {
170 { -1, N_PFKEYSTAT, 1, NULL,
171 pfkey_stats, NULL, "pfkey", 0, 0 },
173 NULL, NULL, NULL, 0, 0 }
178 static struct protox netgraphprotox[] = {
179 { N_NGSOCKLIST, -1, 1, netgraphprotopr,
180 NULL, NULL, "ctrl", 0, 0 },
181 { N_NGSOCKLIST, -1, 1, netgraphprotopr,
182 NULL, NULL, "data", 0, 0 },
184 NULL, NULL, NULL, 0, 0 }
188 static struct protox *protoprotox[] = {
198 static void printproto(struct protox *, const char *, bool *);
199 static void usage(void) __dead2;
200 static struct protox *name2protox(const char *);
201 static struct protox *knownname(const char *);
203 static int kresolve_list(struct nlist *_nl);
206 static char *nlistf = NULL, *memf = NULL;
208 int Aflag; /* show addresses of protocol control block */
209 int aflag; /* show all sockets (including servers) */
210 static int Bflag; /* show information about bpf consumers */
211 int bflag; /* show i/f total bytes in/out */
212 int cflag; /* show TCP congestion control stack */
213 int Cflag; /* show congestion control algo and vars */
214 int dflag; /* show i/f dropped packets */
215 int gflag; /* show group (multicast) routing or stats */
216 int hflag; /* show counters in human readable format */
217 int iflag; /* show interfaces */
218 int Lflag; /* show size of listen queues */
219 int mflag; /* show memory stats */
220 int noutputs = 0; /* how much outputs before we exit */
221 int numeric_addr; /* show addresses numerically */
222 int numeric_port; /* show ports numerically */
223 int Oflag; /* show nhgrp objects*/
224 int oflag; /* show nexthop objects*/
225 int Pflag; /* show TCP log ID */
226 static int pflag; /* show given protocol */
227 static int Qflag; /* show netisr information */
228 int rflag; /* show routing tables (or routing stats) */
229 int Rflag; /* show flow / RSS statistics */
230 int sflag; /* show protocol statistics */
231 int Wflag; /* wide display */
232 int Tflag; /* TCP Information */
233 int xflag; /* extra information, includes all socket buffer info */
234 int zflag; /* zero stats */
236 int interval; /* repeat interval for i/f stats */
238 char *interface; /* desired i/f for stats, or NULL for all i/fs */
239 int unit; /* unit number for above */
241 char *jail_name; /* desired jail to operate in */
244 static int af; /* address family */
245 int live; /* true if we are examining a live system */
248 main(int argc, char *argv[])
250 struct protox *tp = NULL; /* for printing cblocks & stats */
261 argc = xo_parse_args(argc, argv);
265 while ((ch = getopt(argc, argv, "46AaBbCcdF:f:ghI:ij:LlM:mN:nOoPp:Qq:RrSTsuWw:xz"))
272 errx(1, "IPv4 support is not compiled in");
279 errx(1, "IPv6 support is not compiled in");
304 fib = strtol(optarg, &endptr, 0);
305 if (*endptr != '\0' ||
306 (fib == 0 && (errno == EINVAL || errno == ERANGE)))
307 xo_errx(1, "%s: invalid fib", optarg);
310 if (strcmp(optarg, "inet") == 0)
313 else if (strcmp(optarg, "inet6") == 0)
317 else if (strcmp(optarg, "pfkey") == 0)
320 else if (strcmp(optarg, "unix") == 0 ||
321 strcmp(optarg, "local") == 0)
324 else if (strcmp(optarg, "ng") == 0
325 || strcmp(optarg, "netgraph") == 0)
328 else if (strcmp(optarg, "link") == 0)
331 xo_errx(1, "%s: unknown address family",
345 for (cp = interface = optarg; isalpha(*cp); cp++)
359 errx(1, "Jail support is not compiled in");
375 numeric_addr = numeric_port = 1;
387 if ((tp = name2protox(optarg)) == NULL) {
388 xo_errx(1, "%s: unknown or uninstrumented "
397 noutputs = atoi(optarg);
421 interval = atoi(optarg);
440 #define BACKWARD_COMPATIBILITY
441 #ifdef BACKWARD_COMPATIBILITY
443 if (isdigit(**argv)) {
444 interval = atoi(*argv);
459 if (jail_name != NULL) {
460 jid = jail_getid(jail_name);
462 errx(1, "Jail not found");
463 if (jail_attach(jid) != 0)
464 errx(1, "Cannot attach to jail");
469 * Discard setgid privileges if not the running kernel so that bad
470 * guys can't print interesting stuff from kernel memory.
472 live = (nlistf == NULL && memf == NULL);
474 if (setgid(getgid()) != 0)
475 xo_err(-1, "setgid");
476 /* Load all necessary kvm symbols */
481 xo_errx(1, "-x and -T are incompatible, pick one.");
486 bpf_stats(interface);
492 if (kread(0, NULL, 0) == 0)
493 mbpr(kvmd, nl[N_SFSTAT].n_value);
501 if (kread(0, NULL, 0) == 0)
510 * Keep file descriptors open to avoid overhead
511 * of open/close on each call to get* routines.
517 * This does not make sense any more with DNS being default over
518 * the files. Doing a setXXXXent(1) causes a tcp connection to be
519 * used for the queries, which is slower.
522 if (iflag && !sflag) {
523 xo_open_container("statistics");
525 xo_close_container("statistics");
530 xo_open_container("statistics");
538 xo_close_container("statistics");
543 xo_open_container("statistics");
544 nhops_print(fib, af);
545 xo_close_container("statistics");
550 xo_open_container("statistics");
551 nhgrp_print(fib, af);
552 xo_close_container("statistics");
560 xo_open_container("statistics");
562 if (af == AF_INET || af == AF_UNSPEC)
565 if (af == AF_INET6 || af == AF_UNSPEC)
569 if (af == AF_INET || af == AF_UNSPEC)
572 if (af == AF_INET6 || af == AF_UNSPEC)
576 xo_close_container("statistics");
582 xo_open_container("statistics");
583 printproto(tp, tp->pr_name, &first);
585 xo_close_list("socket");
586 xo_close_container("statistics");
591 xo_open_container("statistics");
592 if (af == AF_INET || af == AF_UNSPEC)
593 for (tp = protox; tp->pr_name; tp++)
594 printproto(tp, tp->pr_name, &first);
596 if (af == AF_INET6 || af == AF_UNSPEC)
597 for (tp = ip6protox; tp->pr_name; tp++)
598 printproto(tp, tp->pr_name, &first);
601 if (af == PF_KEY || af == AF_UNSPEC)
602 for (tp = pfkeyprotox; tp->pr_name; tp++)
603 printproto(tp, tp->pr_name, &first);
606 if (af == AF_NETGRAPH || af == AF_UNSPEC)
607 for (tp = netgraphprotox; tp->pr_name; tp++)
608 printproto(tp, tp->pr_name, &first);
609 #endif /* NETGRAPH */
610 if ((af == AF_UNIX || af == AF_UNSPEC) && !sflag)
611 unixpr(nl[N_UNP_COUNT].n_value, nl[N_UNP_GENCNT].n_value,
612 nl[N_UNP_DHEAD].n_value, nl[N_UNP_SHEAD].n_value,
613 nl[N_UNP_SPHEAD].n_value, &first);
616 xo_close_list("socket");
617 xo_close_container("statistics");
623 fetch_stats_internal(const char *sysctlname, u_long off, void *stats,
624 size_t len, kreadfn_t kreadfn, int zero)
629 memset(stats, 0, len);
631 error = sysctlbyname(sysctlname, NULL, NULL, stats,
634 error = sysctlbyname(sysctlname, stats, &len, NULL, 0);
635 if (error == -1 && errno != ENOENT)
636 xo_warn("sysctl %s", sysctlname);
640 error = kreadfn(off, stats, len);
646 fetch_stats(const char *sysctlname, u_long off, void *stats,
647 size_t len, kreadfn_t kreadfn)
650 return (fetch_stats_internal(sysctlname, off, stats, len, kreadfn,
655 fetch_stats_ro(const char *sysctlname, u_long off, void *stats,
656 size_t len, kreadfn_t kreadfn)
659 return (fetch_stats_internal(sysctlname, off, stats, len, kreadfn, 0));
663 * Print out protocol statistics or control blocks (per sflag).
664 * If the interface was not specifically requested, and the symbol
665 * is not in the namelist, ignore this one.
668 printproto(struct protox *tp, const char *name, bool *first)
670 void (*pr)(u_long, const char *, int, int);
672 bool doingdblocks = false;
677 intpr(tp->pr_istats, af);
679 xo_message("%s: no per-interface stats routine",
686 xo_message("%s: no stats routine",
690 if (tp->pr_usesysctl && live)
692 else if (tp->pr_sindex < 0) {
694 xo_message("%s: stats routine doesn't "
695 "work on cores", tp->pr_name);
698 off = nl[tp->pr_sindex].n_value;
705 xo_message("%s: no PCB routine", tp->pr_name);
708 if (tp->pr_usesysctl && live)
710 else if (tp->pr_index < 0) {
712 xo_message("%s: PCB routine doesn't work on "
713 "cores", tp->pr_name);
716 off = nl[tp->pr_index].n_value;
718 if (pr != NULL && (off || (live && tp->pr_usesysctl) ||
720 if (doingdblocks && *first) {
721 xo_open_list("socket");
725 (*pr)(off, name, af, tp->pr_protocol);
732 char errbuf[_POSIX2_LINE_MAX];
737 kvmd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
738 if (setgid(getgid()) != 0)
739 xo_err(-1, "setgid");
742 xo_warnx("kvm not available: %s", errbuf);
750 * Resolve symbol list, return 0 on success.
753 kresolve_list(struct nlist *_nl)
756 if ((kvmd == NULL) && (kvmd_init() != 0))
759 if (_nl[0].n_type != 0)
762 if (kvm_nlist(kvmd, _nl) < 0) {
764 xo_errx(1, "%s: kvm_nlist: %s", nlistf,
767 xo_errx(1, "kvm_nlist: %s", kvm_geterr(kvmd));
774 * Wrapper of kvm_dpcpu_setcpu().
777 kset_dpcpu(u_int cpuid)
780 if ((kvmd == NULL) && (kvmd_init() != 0))
781 xo_errx(-1, "%s: kvm is not available", __func__);
783 if (kvm_dpcpu_setcpu(kvmd, cpuid) < 0)
784 xo_errx(-1, "%s: kvm_dpcpu_setcpu(%u): %s", __func__,
785 cpuid, kvm_geterr(kvmd));
790 * Read kernel memory, return 0 on success.
793 kread(u_long addr, void *buf, size_t size)
801 if (kvm_read(kvmd, addr, buf, size) != (ssize_t)size) {
802 xo_warnx("%s", kvm_geterr(kvmd));
809 * Read single counter(9).
812 kread_counter(u_long addr)
818 return (kvm_counter_u64_fetch(kvmd, addr));
822 * Read an array of N counters in kernel memory into array of N uint64_t's.
825 kread_counters(u_long addr, void *buf, size_t size)
834 if (size % sizeof(uint64_t) != 0) {
835 xo_warnx("kread_counters: invalid counter set size");
839 n = size / sizeof(uint64_t);
840 if ((counters = malloc(n * sizeof(u_long))) == NULL)
841 xo_err(-1, "malloc");
842 if (kread(addr, counters, n * sizeof(u_long)) < 0) {
848 for (i = 0; i < n; i++)
849 c[i] = kvm_counter_u64_fetch(kvmd, counters[i]);
858 return (n != 1 ? "s" : "");
862 plurales(uintmax_t n)
864 return (n != 1 ? "es" : "");
868 pluralies(uintmax_t n)
870 return (n != 1 ? "ies" : "y");
874 * Find the protox for the given "well-known" name.
876 static struct protox *
877 knownname(const char *name)
879 struct protox **tpp, *tp;
881 for (tpp = protoprotox; *tpp; tpp++)
882 for (tp = *tpp; tp->pr_name; tp++)
883 if (strcmp(tp->pr_name, name) == 0)
889 * Find the protox corresponding to name.
891 static struct protox *
892 name2protox(const char *name)
895 char **alias; /* alias from p->aliases */
899 * Try to find the name in the list of "well-known" names. If that
900 * fails, check if name is an alias for an Internet protocol.
902 if ((tp = knownname(name)) != NULL)
905 setprotoent(1); /* make protocol lookup cheaper */
906 while ((p = getprotoent()) != NULL) {
907 /* assert: name not same as p->name */
908 for (alias = p->p_aliases; *alias; alias++)
909 if (strcmp(name, *alias) == 0) {
911 return (knownname(p->p_name));
921 (void)xo_error("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
922 "usage: netstat [-j jail] [-46AaCcLnRSTWx] [-f protocol_family | -p protocol]\n"
923 " [-M core] [-N system]",
924 " netstat [-j jail] -i | -I interface [-46abdhnW] [-f address_family]\n"
925 " [-M core] [-N system]",
926 " netstat [-j jail] -w wait [-I interface] [-46d] [-M core] [-N system]\n"
928 " netstat [-j jail] -s [-46sz] [-f protocol_family | -p protocol]\n"
929 " [-M core] [-N system]",
930 " netstat [-j jail] -i | -I interface -s [-46s]\n"
931 " [-f protocol_family | -p protocol] [-M core] [-N system]",
932 " netstat [-j jail] -m [-M core] [-N system]",
933 " netstat [-j jail] -B [-z] [-I interface]",
934 " netstat [-j jail] -r [-46AnW] [-F fibnum] [-f address_family]\n"
935 " [-M core] [-N system]",
936 " netstat [-j jail] -rs [-s] [-M core] [-N system]",
937 " netstat [-j jail] -g [-46W] [-f address_family] [-M core] [-N system]",
938 " netstat [-j jail] -gs [-46s] [-f address_family] [-M core] [-N system]",
939 " netstat [-j jail] -Q");