Index: head/usr.bin/netstat/ipsec.c =================================================================== --- head/usr.bin/netstat/ipsec.c (revision 292393) +++ head/usr.bin/netstat/ipsec.c (revision 292394) @@ -1,445 +1,455 @@ /* $KAME: ipsec.c,v 1.33 2003/07/25 09:54:32 itojun Exp $ */ /*- * Copyright (c) 2005 NTT Multimedia Communications Laboratories, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /*- * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /*- * Copyright (c) 1983, 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if 0 #ifndef lint static char sccsid[] = "@(#)inet.c 8.5 (Berkeley) 5/24/95"; #endif /* not lint */ #endif #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #ifdef IPSEC #include #include #include #include #endif #include #include #include #include #include #include #include "netstat.h" #ifdef IPSEC struct val2str { int val; const char *str; }; static struct val2str ipsec_ahnames[] = { { SADB_AALG_NONE, "none", }, { SADB_AALG_MD5HMAC, "hmac-md5", }, { SADB_AALG_SHA1HMAC, "hmac-sha1", }, { SADB_X_AALG_MD5, "md5", }, { SADB_X_AALG_SHA, "sha", }, { SADB_X_AALG_NULL, "null", }, #ifdef SADB_X_AALG_SHA2_256 { SADB_X_AALG_SHA2_256, "hmac-sha2-256", }, #endif #ifdef SADB_X_AALG_SHA2_384 { SADB_X_AALG_SHA2_384, "hmac-sha2-384", }, #endif #ifdef SADB_X_AALG_SHA2_512 { SADB_X_AALG_SHA2_512, "hmac-sha2-512", }, #endif #ifdef SADB_X_AALG_RIPEMD160HMAC { SADB_X_AALG_RIPEMD160HMAC, "hmac-ripemd160", }, #endif #ifdef SADB_X_AALG_AES_XCBC_MAC { SADB_X_AALG_AES_XCBC_MAC, "aes-xcbc-mac", }, #endif { -1, NULL }, }; static struct val2str ipsec_espnames[] = { { SADB_EALG_NONE, "none", }, { SADB_EALG_DESCBC, "des-cbc", }, { SADB_EALG_3DESCBC, "3des-cbc", }, { SADB_EALG_NULL, "null", }, { SADB_X_EALG_CAST128CBC, "cast128-cbc", }, { SADB_X_EALG_BLOWFISHCBC, "blowfish-cbc", }, #ifdef SADB_X_EALG_RIJNDAELCBC { SADB_X_EALG_RIJNDAELCBC, "rijndael-cbc", }, #endif #ifdef SADB_X_EALG_AESCTR { SADB_X_EALG_AESCTR, "aes-ctr", }, #endif #ifdef SADB_X_EALG_AESGCM16 { SADB_X_EALG_AESGCM16, "aes-gcm-16", }, #endif { -1, NULL }, }; static struct val2str ipsec_compnames[] = { { SADB_X_CALG_NONE, "none", }, { SADB_X_CALG_OUI, "oui", }, { SADB_X_CALG_DEFLATE, "deflate", }, { SADB_X_CALG_LZS, "lzs", }, { -1, NULL }, }; static void print_ipsecstats(const struct ipsecstat *ipsecstat); static void print_ipsecstats(const struct ipsecstat *ipsecstat) { xo_open_container("ipsec-statistics"); #define p(f, m) if (ipsecstat->f || sflag <= 1) \ xo_emit(m, (uintmax_t)ipsecstat->f, plural(ipsecstat->f)) p(ips_in_polvio, "\t{:dropped-policy-violation/%ju} " "{N:/inbound packet%s violated process security policy}\n"); p(ips_in_nomem, "\t{:dropped-no-memory/%ju} " "{N:/inbound packet%s failed due to insufficient memory}\n"); p(ips_in_inval, "\t{:dropped-invalid/%ju} " "{N:/invalid inbound packet%s}\n"); p(ips_out_polvio, "\t{:discarded-policy-violation/%ju} " "{N:/outbound packet%s violated process security policy}\n"); p(ips_out_nosa, "\t{:discarded-no-sa/%ju} " "{N:/outbound packet%s with no SA available}\n"); p(ips_out_nomem, "\t{:discarded-no-memory/%ju} " "{N:/outbound packet%s failed due to insufficient memory}\n"); p(ips_out_noroute, "\t{:discarded-no-route/%ju} " "{N:/outbound packet%s with no route available}\n"); p(ips_out_inval, "\t{:discarded-invalid/%ju} " "{N:/invalid outbound packet%s}\n"); p(ips_out_bundlesa, "\t{:send-bundled-sa/%ju} " "{N:/outbound packet%s with bundled SAs}\n"); p(ips_mbcoalesced, "\t{:mbufs-coalesced-during-clone/%ju} " "{N:/mbuf%s coalesced during clone}\n"); p(ips_clcoalesced, "\t{:clusters-coalesced-during-clone/%ju} " "{N:/cluster%s coalesced during clone}\n"); p(ips_clcopied, "\t{:clusters-copied-during-clone/%ju} " "{N:/cluster%s copied during clone}\n"); p(ips_mbinserted, "\t{:mbufs-inserted/%ju} " "{N:/mbuf%s inserted during makespace}\n"); #undef p xo_close_container("ipsec-statistics"); } void ipsec_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct ipsecstat ipsecstat; - if (off == 0) - return; + if (strcmp(name, "ipsec6") == 0) { + if (fetch_stats("net.inet6.ipsec6.ipsecstats", off,&ipsecstat, + sizeof(ipsecstat), kread_counters) != 0) + return; + } else { + if (fetch_stats("net.inet.ipsec.ipsecstats", off, &ipsecstat, + sizeof(ipsecstat), kread_counters) != 0) + return; + } + xo_emit("{T:/%s}:\n", name); - kread_counters(off, (char *)&ipsecstat, sizeof(ipsecstat)); print_ipsecstats(&ipsecstat); } static void print_ahstats(const struct ahstat *ahstat); static void print_espstats(const struct espstat *espstat); static void print_ipcompstats(const struct ipcompstat *ipcompstat); /* * Dump IPSEC statistics structure. */ static void ipsec_hist_new(const uint64_t *hist, size_t histmax, const struct val2str *name, const char *title, const char *cname) { int first; size_t proto; const struct val2str *p; first = 1; for (proto = 0; proto < histmax; proto++) { if (hist[proto] <= 0) continue; if (first) { xo_open_list(cname); xo_emit("\t{T:/%s histogram}:\n", title); first = 0; } xo_open_instance(cname); for (p = name; p && p->str; p++) { if (p->val == (int)proto) break; } if (p && p->str) { xo_emit("\t\t{k:name}: {:count/%ju}\n", p->str, (uintmax_t)hist[proto]); } else { xo_emit("\t\t#{k:name/%lu}: {:count/%ju}\n", (unsigned long)proto, (uintmax_t)hist[proto]); } xo_close_instance(cname); } if (!first) xo_close_list(cname); } static void print_ahstats(const struct ahstat *ahstat) { xo_open_container("ah-statictics"); #define p(f, n, m) if (ahstat->f || sflag <= 1) \ xo_emit("\t{:" n "/%ju} {N:/" m "}\n", \ (uintmax_t)ahstat->f, plural(ahstat->f)) #define hist(f, n, t, c) \ ipsec_hist_new((f), sizeof(f)/sizeof(f[0]), (n), (t), (c)) p(ahs_hdrops, "dropped-short-header", "packet%s shorter than header shows"); p(ahs_nopf, "dropped-bad-protocol", "packet%s dropped; protocol family not supported"); p(ahs_notdb, "dropped-no-tdb", "packet%s dropped; no TDB"); p(ahs_badkcr, "dropped-bad-kcr", "packet%s dropped; bad KCR"); p(ahs_qfull, "dropped-queue-full", "packet%s dropped; queue full"); p(ahs_noxform, "dropped-no-transform", "packet%s dropped; no transform"); p(ahs_wrap, "replay-counter-wraps", "replay counter wrap%s"); p(ahs_badauth, "dropped-bad-auth", "packet%s dropped; bad authentication detected"); p(ahs_badauthl, "dropped-bad-auth-level", "packet%s dropped; bad authentication length"); p(ahs_replay, "possile-replay-detected", "possible replay packet%s detected"); p(ahs_input, "received-packets", "packet%s in"); p(ahs_output, "send-packets", "packet%s out"); p(ahs_invalid, "dropped-bad-tdb", "packet%s dropped; invalid TDB"); p(ahs_ibytes, "received-bytes", "byte%s in"); p(ahs_obytes, "send-bytes", "byte%s out"); p(ahs_toobig, "dropped-too-large", "packet%s dropped; larger than IP_MAXPACKET"); p(ahs_pdrops, "dropped-policy-violation", "packet%s blocked due to policy"); p(ahs_crypto, "crypto-failures", "crypto processing failure%s"); p(ahs_tunnel, "tunnel-failures", "tunnel sanity check failure%s"); hist(ahstat->ahs_hist, ipsec_ahnames, "AH output", "ah-output-histogram"); #undef p #undef hist xo_close_container("ah-statictics"); } void ah_stats(u_long off, const char *name, int family __unused, int proto __unused) { struct ahstat ahstat; - if (off == 0) + if (fetch_stats("net.inet.ah.stats", off, &ahstat, + sizeof(ahstat), kread_counters) != 0) return; + xo_emit("{T:/%s}:\n", name); - kread_counters(off, (char *)&ahstat, sizeof(ahstat)); print_ahstats(&ahstat); } static void print_espstats(const struct espstat *espstat) { xo_open_container("esp-statictics"); #define p(f, n, m) if (espstat->f || sflag <= 1) \ xo_emit("\t{:" n "/%ju} {N:/" m "}\n", \ (uintmax_t)espstat->f, plural(espstat->f)) #define hist(f, n, t, c) \ ipsec_hist_new((f), sizeof(f)/sizeof(f[0]), (n), (t), (c)); p(esps_hdrops, "dropped-short-header", "packet%s shorter than header shows"); p(esps_nopf, "dropped-bad-protocol", "packet%s dropped; protocol family not supported"); p(esps_notdb, "dropped-no-tdb", "packet%s dropped; no TDB"); p(esps_badkcr, "dropped-bad-kcr", "packet%s dropped; bad KCR"); p(esps_qfull, "dropped-queue-full", "packet%s dropped; queue full"); p(esps_noxform, "dropped-no-transform", "packet%s dropped; no transform"); p(esps_badilen, "dropped-bad-length", "packet%s dropped; bad ilen"); p(esps_wrap, "replay-counter-wraps", "replay counter wrap%s"); p(esps_badenc, "dropped-bad-crypto", "packet%s dropped; bad encryption detected"); p(esps_badauth, "dropped-bad-auth", "packet%s dropped; bad authentication detected"); p(esps_replay, "possible-replay-detected", "possible replay packet%s detected"); p(esps_input, "received-packets", "packet%s in"); p(esps_output, "sent-packets", "packet%s out"); p(esps_invalid, "dropped-bad-tdb", "packet%s dropped; invalid TDB"); p(esps_ibytes, "receieve-bytes", "byte%s in"); p(esps_obytes, "sent-bytes", "byte%s out"); p(esps_toobig, "dropped-too-large", "packet%s dropped; larger than IP_MAXPACKET"); p(esps_pdrops, "dropped-policy-violation", "packet%s blocked due to policy"); p(esps_crypto, "crypto-failures", "crypto processing failure%s"); p(esps_tunnel, "tunnel-failures", "tunnel sanity check failure%s"); hist(espstat->esps_hist, ipsec_espnames, "ESP output", "esp-output-histogram"); #undef p #undef hist xo_close_container("esp-statictics"); } void esp_stats(u_long off, const char *name, int family __unused, int proto __unused) { struct espstat espstat; - if (off == 0) + if (fetch_stats("net.inet.esp.stats", off, &espstat, + sizeof(espstat), kread_counters) != 0) return; + xo_emit("{T:/%s}:\n", name); - kread_counters(off, (char *)&espstat, sizeof(espstat)); print_espstats(&espstat); } static void print_ipcompstats(const struct ipcompstat *ipcompstat) { xo_open_container("ipcomp-statictics"); #define p(f, n, m) if (ipcompstat->f || sflag <= 1) \ xo_emit("\t{:" n "/%ju} {N:/" m "}\n", \ (uintmax_t)ipcompstat->f, plural(ipcompstat->f)) #define hist(f, n, t, c) \ ipsec_hist_new((f), sizeof(f)/sizeof(f[0]), (n), (t), (c)); p(ipcomps_hdrops, "dropped-short-header", "packet%s shorter than header shows"); p(ipcomps_nopf, "dropped-bad-protocol", "packet%s dropped; protocol family not supported"); p(ipcomps_notdb, "dropped-no-tdb", "packet%s dropped; no TDB"); p(ipcomps_badkcr, "dropped-bad-kcr", "packet%s dropped; bad KCR"); p(ipcomps_qfull, "dropped-queue-full", "packet%s dropped; queue full"); p(ipcomps_noxform, "dropped-no-transform", "packet%s dropped; no transform"); p(ipcomps_wrap, "replay-counter-wraps", "replay counter wrap%s"); p(ipcomps_input, "receieve-packets", "packet%s in"); p(ipcomps_output, "sent-packets", "packet%s out"); p(ipcomps_invalid, "dropped-bad-tdb", "packet%s dropped; invalid TDB"); p(ipcomps_ibytes, "receieved-bytes", "byte%s in"); p(ipcomps_obytes, "sent-bytes", "byte%s out"); p(ipcomps_toobig, "dropped-too-large", "packet%s dropped; larger than IP_MAXPACKET"); p(ipcomps_pdrops, "dropped-policy-violation", "packet%s blocked due to policy"); p(ipcomps_crypto, "crypto-failure", "crypto processing failure%s"); hist(ipcompstat->ipcomps_hist, ipsec_compnames, "COMP output", "comp-output-histogram"); p(ipcomps_threshold, "sent-uncompressed-small-packets", "packet%s sent uncompressed; size < compr. algo. threshold"); p(ipcomps_uncompr, "sent-uncompressed-useless-packets", "packet%s sent uncompressed; compression was useless"); #undef p #undef hist xo_close_container("ipcomp-statictics"); } void ipcomp_stats(u_long off, const char *name, int family __unused, int proto __unused) { struct ipcompstat ipcompstat; - if (off == 0) + if (fetch_stats("net.inet.ipcomp.stats", off, &ipcompstat, + sizeof(ipcompstat), kread_counters) != 0) return; + xo_emit("{T:/%s}:\n", name); - kread_counters(off, (char *)&ipcompstat, sizeof(ipcompstat)); print_ipcompstats(&ipcompstat); } #endif /*IPSEC*/ Index: head/usr.bin/netstat/main.c =================================================================== --- head/usr.bin/netstat/main.c (revision 292393) +++ head/usr.bin/netstat/main.c (revision 292394) @@ -1,857 +1,857 @@ /*- * Copyright (c) 1983, 1988, 1993 * Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static char const copyright[] = "@(#) Copyright (c) 1983, 1988, 1993\n\ Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #if 0 #ifndef lint static char sccsid[] = "@(#)main.c 8.4 (Berkeley) 3/1/94"; #endif /* not lint */ #endif #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #ifdef NETGRAPH #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "netstat.h" #include "nl_defs.h" #include static struct protox { int pr_index; /* index into nlist of cb head */ int pr_sindex; /* index into nlist of stat block */ u_char pr_wanted; /* 1 if wanted, 0 otherwise */ void (*pr_cblocks)(u_long, const char *, int, int); /* control blocks printing routine */ void (*pr_stats)(u_long, const char *, int, int); /* statistics printing routine */ void (*pr_istats)(char *); /* per/if statistics printing routine */ const char *pr_name; /* well-known name */ int pr_usesysctl; /* non-zero if we use sysctl, not kvm */ int pr_protocol; } protox[] = { { N_TCBINFO, N_TCPSTAT, 1, protopr, tcp_stats, NULL, "tcp", 1, IPPROTO_TCP }, { N_UDBINFO, N_UDPSTAT, 1, protopr, udp_stats, NULL, "udp", 1, IPPROTO_UDP }, #ifdef SCTP { -1, N_SCTPSTAT, 1, sctp_protopr, sctp_stats, NULL, "sctp", 1, IPPROTO_SCTP }, #endif #ifdef SDP { -1, -1, 1, protopr, NULL, NULL, "sdp", 1, IPPROTO_TCP }, #endif { N_DIVCBINFO, -1, 1, protopr, NULL, NULL, "divert", 1, IPPROTO_DIVERT }, { N_RIPCBINFO, N_IPSTAT, 1, protopr, ip_stats, NULL, "ip", 1, IPPROTO_RAW }, { N_RIPCBINFO, N_ICMPSTAT, 1, protopr, icmp_stats, NULL, "icmp", 1, IPPROTO_ICMP }, { N_RIPCBINFO, N_IGMPSTAT, 1, protopr, igmp_stats, NULL, "igmp", 1, IPPROTO_IGMP }, #ifdef IPSEC { -1, N_IPSEC4STAT, 1, NULL, /* keep as compat */ - ipsec_stats, NULL, "ipsec", 0, 0}, + ipsec_stats, NULL, "ipsec", 1, 0}, { -1, N_AHSTAT, 1, NULL, - ah_stats, NULL, "ah", 0, 0}, + ah_stats, NULL, "ah", 1, 0}, { -1, N_ESPSTAT, 1, NULL, - esp_stats, NULL, "esp", 0, 0}, + esp_stats, NULL, "esp", 1, 0}, { -1, N_IPCOMPSTAT, 1, NULL, - ipcomp_stats, NULL, "ipcomp", 0, 0}, + ipcomp_stats, NULL, "ipcomp", 1, 0}, #endif { N_RIPCBINFO, N_PIMSTAT, 1, protopr, pim_stats, NULL, "pim", 1, IPPROTO_PIM }, { -1, N_CARPSTATS, 1, NULL, carp_stats, NULL, "carp", 1, 0 }, #ifdef PF { -1, N_PFSYNCSTATS, 1, NULL, pfsync_stats, NULL, "pfsync", 1, 0 }, #endif { -1, N_ARPSTAT, 1, NULL, arp_stats, NULL, "arp", 1, 0 }, { -1, -1, 0, NULL, NULL, NULL, NULL, 0, 0 } }; #ifdef INET6 static struct protox ip6protox[] = { { N_TCBINFO, N_TCPSTAT, 1, protopr, tcp_stats, NULL, "tcp", 1, IPPROTO_TCP }, { N_UDBINFO, N_UDPSTAT, 1, protopr, udp_stats, NULL, "udp", 1, IPPROTO_UDP }, { N_RIPCBINFO, N_IP6STAT, 1, protopr, ip6_stats, ip6_ifstats, "ip6", 1, IPPROTO_RAW }, { N_RIPCBINFO, N_ICMP6STAT, 1, protopr, icmp6_stats, icmp6_ifstats, "icmp6", 1, IPPROTO_ICMPV6 }, #ifdef SDP { -1, -1, 1, protopr, NULL, NULL, "sdp", 1, IPPROTO_TCP }, #endif #ifdef IPSEC { -1, N_IPSEC6STAT, 1, NULL, - ipsec_stats, NULL, "ipsec6", 0, 0 }, + ipsec_stats, NULL, "ipsec6", 1, 0 }, #endif #ifdef notyet { -1, N_PIM6STAT, 1, NULL, pim6_stats, NULL, "pim6", 1, 0 }, #endif { -1, N_RIP6STAT, 1, NULL, rip6_stats, NULL, "rip6", 1, 0 }, { -1, -1, 0, NULL, NULL, NULL, NULL, 0, 0 } }; #endif /*INET6*/ #ifdef IPSEC static struct protox pfkeyprotox[] = { { -1, N_PFKEYSTAT, 1, NULL, pfkey_stats, NULL, "pfkey", 0, 0 }, { -1, -1, 0, NULL, NULL, NULL, NULL, 0, 0 } }; #endif #ifdef NETGRAPH static struct protox netgraphprotox[] = { { N_NGSOCKLIST, -1, 1, netgraphprotopr, NULL, NULL, "ctrl", 0, 0 }, { N_NGSOCKLIST, -1, 1, netgraphprotopr, NULL, NULL, "data", 0, 0 }, { -1, -1, 0, NULL, NULL, NULL, NULL, 0, 0 } }; #endif static struct protox *protoprotox[] = { protox, #ifdef INET6 ip6protox, #endif #ifdef IPSEC pfkeyprotox, #endif NULL }; static void printproto(struct protox *, const char *, bool *); static void usage(void); static struct protox *name2protox(const char *); static struct protox *knownname(const char *); static int kresolve_list(struct nlist *_nl); static kvm_t *kvmd; static char *nlistf = NULL, *memf = NULL; int Aflag; /* show addresses of protocol control block */ int aflag; /* show all sockets (including servers) */ static int Bflag; /* show information about bpf consumers */ int bflag; /* show i/f total bytes in/out */ int dflag; /* show i/f dropped packets */ int gflag; /* show group (multicast) routing or stats */ int hflag; /* show counters in human readable format */ int iflag; /* show interfaces */ int Lflag; /* show size of listen queues */ int mflag; /* show memory stats */ int noutputs = 0; /* how much outputs before we exit */ int numeric_addr; /* show addresses numerically */ int numeric_port; /* show ports numerically */ static int pflag; /* show given protocol */ static int Qflag; /* show netisr information */ int rflag; /* show routing tables (or routing stats) */ int Rflag; /* show flow / RSS statistics */ int sflag; /* show protocol statistics */ int Wflag; /* wide display */ int Tflag; /* TCP Information */ int xflag; /* extra information, includes all socket buffer info */ int zflag; /* zero stats */ int interval; /* repeat interval for i/f stats */ char *interface; /* desired i/f for stats, or NULL for all i/fs */ int unit; /* unit number for above */ static int af; /* address family */ int live; /* true if we are examining a live system */ int main(int argc, char *argv[]) { struct protox *tp = NULL; /* for printing cblocks & stats */ int ch; int fib = -1; char *endptr; bool first = true; af = AF_UNSPEC; argc = xo_parse_args(argc, argv); if (argc < 0) exit(EXIT_FAILURE); while ((ch = getopt(argc, argv, "46AaBbdF:f:ghI:iLlM:mN:np:Qq:RrSTsuWw:xz")) != -1) switch(ch) { case '4': #ifdef INET af = AF_INET; #else errx(1, "IPv4 support is not compiled in"); #endif break; case '6': #ifdef INET6 af = AF_INET6; #else errx(1, "IPv6 support is not compiled in"); #endif break; case 'A': Aflag = 1; break; case 'a': aflag = 1; break; case 'B': Bflag = 1; break; case 'b': bflag = 1; break; case 'd': dflag = 1; break; case 'F': fib = strtol(optarg, &endptr, 0); if (*endptr != '\0' || (fib == 0 && (errno == EINVAL || errno == ERANGE))) xo_errx(1, "%s: invalid fib", optarg); break; case 'f': if (strcmp(optarg, "inet") == 0) af = AF_INET; #ifdef INET6 else if (strcmp(optarg, "inet6") == 0) af = AF_INET6; #endif #ifdef IPSEC else if (strcmp(optarg, "pfkey") == 0) af = PF_KEY; #endif else if (strcmp(optarg, "unix") == 0 || strcmp(optarg, "local") == 0) af = AF_UNIX; #ifdef NETGRAPH else if (strcmp(optarg, "ng") == 0 || strcmp(optarg, "netgraph") == 0) af = AF_NETGRAPH; #endif else if (strcmp(optarg, "link") == 0) af = AF_LINK; else { xo_errx(1, "%s: unknown address family", optarg); } break; case 'g': gflag = 1; break; case 'h': hflag = 1; break; case 'I': { char *cp; iflag = 1; for (cp = interface = optarg; isalpha(*cp); cp++) continue; unit = atoi(cp); break; } case 'i': iflag = 1; break; case 'L': Lflag = 1; break; case 'M': memf = optarg; break; case 'm': mflag = 1; break; case 'N': nlistf = optarg; break; case 'n': numeric_addr = numeric_port = 1; break; case 'p': if ((tp = name2protox(optarg)) == NULL) { xo_errx(1, "%s: unknown or uninstrumented " "protocol", optarg); } pflag = 1; break; case 'Q': Qflag = 1; break; case 'q': noutputs = atoi(optarg); if (noutputs != 0) noutputs++; break; case 'r': rflag = 1; break; case 'R': Rflag = 1; break; case 's': ++sflag; break; case 'S': numeric_addr = 1; break; case 'u': af = AF_UNIX; break; case 'W': case 'l': Wflag = 1; break; case 'w': interval = atoi(optarg); iflag = 1; break; case 'T': Tflag = 1; break; case 'x': xflag = 1; break; case 'z': zflag = 1; break; case '?': default: usage(); } argv += optind; argc -= optind; #define BACKWARD_COMPATIBILITY #ifdef BACKWARD_COMPATIBILITY if (*argv) { if (isdigit(**argv)) { interval = atoi(*argv); if (interval <= 0) usage(); ++argv; iflag = 1; } if (*argv) { nlistf = *argv; if (*++argv) memf = *argv; } } #endif /* * Discard setgid privileges if not the running kernel so that bad * guys can't print interesting stuff from kernel memory. */ live = (nlistf == NULL && memf == NULL); if (!live) { if (setgid(getgid()) != 0) xo_err(-1, "setgid"); } if (xflag && Tflag) xo_errx(1, "-x and -T are incompatible, pick one."); if (Bflag) { if (!live) usage(); bpf_stats(interface); xo_finish(); exit(0); } if (mflag) { if (!live) { if (kread(0, NULL, 0) == 0) mbpr(kvmd, nl[N_SFSTAT].n_value); } else mbpr(NULL, 0); xo_finish(); exit(0); } if (Qflag) { if (!live) { if (kread(0, NULL, 0) == 0) netisr_stats(); } else netisr_stats(); xo_finish(); exit(0); } #if 0 /* * Keep file descriptors open to avoid overhead * of open/close on each call to get* routines. */ sethostent(1); setnetent(1); #else /* * This does not make sense any more with DNS being default over * the files. Doing a setXXXXent(1) causes a tcp connection to be * used for the queries, which is slower. */ #endif if (iflag && !sflag) { xo_open_container("statistics"); intpr(NULL, af); xo_close_container("statistics"); xo_finish(); exit(0); } if (rflag) { xo_open_container("statistics"); if (sflag) { rt_stats(); flowtable_stats(); } else routepr(fib, af); xo_close_container("statistics"); xo_finish(); exit(0); } if (gflag) { xo_open_container("statistics"); if (sflag) { if (af == AF_INET || af == AF_UNSPEC) mrt_stats(); #ifdef INET6 if (af == AF_INET6 || af == AF_UNSPEC) mrt6_stats(); #endif } else { if (af == AF_INET || af == AF_UNSPEC) mroutepr(); #ifdef INET6 if (af == AF_INET6 || af == AF_UNSPEC) mroute6pr(); #endif } xo_close_container("statistics"); xo_finish(); exit(0); } /* Load all necessary kvm symbols */ kresolve_list(nl); if (tp) { xo_open_container("statistics"); printproto(tp, tp->pr_name, &first); if (!first) xo_close_list("socket"); xo_close_container("statistics"); xo_finish(); exit(0); } xo_open_container("statistics"); if (af == AF_INET || af == AF_UNSPEC) for (tp = protox; tp->pr_name; tp++) printproto(tp, tp->pr_name, &first); #ifdef INET6 if (af == AF_INET6 || af == AF_UNSPEC) for (tp = ip6protox; tp->pr_name; tp++) printproto(tp, tp->pr_name, &first); #endif /*INET6*/ #ifdef IPSEC if (af == PF_KEY || af == AF_UNSPEC) for (tp = pfkeyprotox; tp->pr_name; tp++) printproto(tp, tp->pr_name, &first); #endif /*IPSEC*/ #ifdef NETGRAPH if (af == AF_NETGRAPH || af == AF_UNSPEC) for (tp = netgraphprotox; tp->pr_name; tp++) printproto(tp, tp->pr_name, &first); #endif /* NETGRAPH */ if ((af == AF_UNIX || af == AF_UNSPEC) && !sflag) unixpr(nl[N_UNP_COUNT].n_value, nl[N_UNP_GENCNT].n_value, nl[N_UNP_DHEAD].n_value, nl[N_UNP_SHEAD].n_value, nl[N_UNP_SPHEAD].n_value, &first); if (!first) xo_close_list("socket"); xo_close_container("statistics"); xo_finish(); exit(0); } int fetch_stats(const char *sysctlname, u_long off, void *stats, size_t len, int (*kreadfn)(u_long, void *, size_t)) { int error; if (live) { memset(stats, 0, len); if (zflag) error = sysctlbyname(sysctlname, NULL, NULL, stats, len); else error = sysctlbyname(sysctlname, stats, &len, NULL, 0); if (error == -1 && errno != ENOENT) xo_warn("sysctl %s", sysctlname); } else { if (off == 0) return (1); error = kreadfn(off, stats, len); } return (error); } /* * Print out protocol statistics or control blocks (per sflag). * If the interface was not specifically requested, and the symbol * is not in the namelist, ignore this one. */ static void printproto(struct protox *tp, const char *name, bool *first) { void (*pr)(u_long, const char *, int, int); u_long off; bool doingdblocks = false; if (sflag) { if (iflag) { if (tp->pr_istats) intpr(tp->pr_istats, af); else if (pflag) xo_message("%s: no per-interface stats routine", tp->pr_name); return; } else { pr = tp->pr_stats; if (!pr) { if (pflag) xo_message("%s: no stats routine", tp->pr_name); return; } if (tp->pr_usesysctl && live) off = 0; else if (tp->pr_sindex < 0) { if (pflag) xo_message("%s: stats routine doesn't " "work on cores", tp->pr_name); return; } else off = nl[tp->pr_sindex].n_value; } } else { doingdblocks = true; pr = tp->pr_cblocks; if (!pr) { if (pflag) xo_message("%s: no PCB routine", tp->pr_name); return; } if (tp->pr_usesysctl && live) off = 0; else if (tp->pr_index < 0) { if (pflag) xo_message("%s: PCB routine doesn't work on " "cores", tp->pr_name); return; } else off = nl[tp->pr_index].n_value; } if (pr != NULL && (off || (live && tp->pr_usesysctl) || af != AF_UNSPEC)) { if (doingdblocks && *first) { xo_open_list("socket"); *first = false; } (*pr)(off, name, af, tp->pr_protocol); } } static int kvmd_init(void) { char errbuf[_POSIX2_LINE_MAX]; if (kvmd != NULL) return (0); kvmd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf); if (setgid(getgid()) != 0) xo_err(-1, "setgid"); if (kvmd == NULL) { xo_warnx("kvm not available: %s", errbuf); return (-1); } return (0); } /* * Resolve symbol list, return 0 on success. */ static int kresolve_list(struct nlist *_nl) { if ((kvmd == NULL) && (kvmd_init() != 0)) return (-1); if (_nl[0].n_type != 0) return (0); if (kvm_nlist(kvmd, _nl) < 0) { if (nlistf) xo_errx(1, "%s: kvm_nlist: %s", nlistf, kvm_geterr(kvmd)); else xo_errx(1, "kvm_nlist: %s", kvm_geterr(kvmd)); } return (0); } /* * Wrapper of kvm_dpcpu_setcpu(). */ void kset_dpcpu(u_int cpuid) { if ((kvmd == NULL) && (kvmd_init() != 0)) xo_errx(-1, "%s: kvm is not available", __func__); if (kvm_dpcpu_setcpu(kvmd, cpuid) < 0) xo_errx(-1, "%s: kvm_dpcpu_setcpu(%u): %s", __func__, cpuid, kvm_geterr(kvmd)); return; } /* * Read kernel memory, return 0 on success. */ int kread(u_long addr, void *buf, size_t size) { if (kvmd_init() < 0) return (-1); if (!buf) return (0); if (kvm_read(kvmd, addr, buf, size) != (ssize_t)size) { xo_warnx("%s", kvm_geterr(kvmd)); return (-1); } return (0); } /* * Read single counter(9). */ uint64_t kread_counter(u_long addr) { if (kvmd_init() < 0) return (-1); return (kvm_counter_u64_fetch(kvmd, addr)); } /* * Read an array of N counters in kernel memory into array of N uint64_t's. */ int kread_counters(u_long addr, void *buf, size_t size) { uint64_t *c; u_long *counters; size_t i, n; if (kvmd_init() < 0) return (-1); if (size % sizeof(uint64_t) != 0) { xo_warnx("kread_counters: invalid counter set size"); return (-1); } n = size / sizeof(uint64_t); if ((counters = malloc(n * sizeof(u_long))) == NULL) xo_err(-1, "malloc"); if (kread(addr, counters, n * sizeof(u_long)) < 0) { free(counters); return (-1); } c = buf; for (i = 0; i < n; i++) c[i] = kvm_counter_u64_fetch(kvmd, counters[i]); free(counters); return (0); } const char * plural(uintmax_t n) { return (n != 1 ? "s" : ""); } const char * plurales(uintmax_t n) { return (n != 1 ? "es" : ""); } const char * pluralies(uintmax_t n) { return (n != 1 ? "ies" : "y"); } /* * Find the protox for the given "well-known" name. */ static struct protox * knownname(const char *name) { struct protox **tpp, *tp; for (tpp = protoprotox; *tpp; tpp++) for (tp = *tpp; tp->pr_name; tp++) if (strcmp(tp->pr_name, name) == 0) return (tp); return (NULL); } /* * Find the protox corresponding to name. */ static struct protox * name2protox(const char *name) { struct protox *tp; char **alias; /* alias from p->aliases */ struct protoent *p; /* * Try to find the name in the list of "well-known" names. If that * fails, check if name is an alias for an Internet protocol. */ if ((tp = knownname(name)) != NULL) return (tp); setprotoent(1); /* make protocol lookup cheaper */ while ((p = getprotoent()) != NULL) { /* assert: name not same as p->name */ for (alias = p->p_aliases; *alias; alias++) if (strcmp(name, *alias) == 0) { endprotoent(); return (knownname(p->p_name)); } } endprotoent(); return (NULL); } static void usage(void) { (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", "usage: netstat [-46AaLnRSTWx] [-f protocol_family | -p protocol]\n" " [-M core] [-N system]", " netstat -i | -I interface [-46abdhnW] [-f address_family]\n" " [-M core] [-N system]", " netstat -w wait [-I interface] [-46d] [-M core] [-N system]\n" " [-q howmany]", " netstat -s [-46sz] [-f protocol_family | -p protocol]\n" " [-M core] [-N system]", " netstat -i | -I interface -s [-46s]\n" " [-f protocol_family | -p protocol] [-M core] [-N system]", " netstat -m [-M core] [-N system]", " netstat -B [-z] [-I interface]", " netstat -r [-46AnW] [-F fibnum] [-f address_family]\n" " [-M core] [-N system]", " netstat -rs [-s] [-M core] [-N system]", " netstat -g [-46W] [-f address_family] [-M core] [-N system]", " netstat -gs [-46s] [-f address_family] [-M core] [-N system]", " netstat -Q"); xo_finish(); exit(1); }