Index: head/sys/netipsec/ipcomp_var.h =================================================================== --- head/sys/netipsec/ipcomp_var.h (revision 199945) +++ head/sys/netipsec/ipcomp_var.h (revision 199946) @@ -1,69 +1,73 @@ /* $FreeBSD$ */ /* $KAME: ipcomp.h,v 1.8 2000/09/26 07:55:14 itojun Exp $ */ /*- * Copyright (C) 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. */ #ifndef _NETIPSEC_IPCOMP_VAR_H_ #define _NETIPSEC_IPCOMP_VAR_H_ /* * These define the algorithm indices into the histogram. They're * presently based on the PF_KEY v2 protocol values which is bogus; * they should be decoupled from the protocol at which time we can * pack them and reduce the size of the array to a minimum. */ #define IPCOMP_ALG_MAX 8 +#define IPCOMPSTAT_VERSION 1 struct ipcompstat { u_int32_t ipcomps_hdrops; /* Packet shorter than header shows */ u_int32_t ipcomps_nopf; /* Protocol family not supported */ u_int32_t ipcomps_notdb; u_int32_t ipcomps_badkcr; u_int32_t ipcomps_qfull; u_int32_t ipcomps_noxform; u_int32_t ipcomps_wrap; u_int32_t ipcomps_input; /* Input IPcomp packets */ u_int32_t ipcomps_output; /* Output IPcomp packets */ u_int32_t ipcomps_invalid;/* Trying to use an invalid TDB */ u_int64_t ipcomps_ibytes; /* Input bytes */ u_int64_t ipcomps_obytes; /* Output bytes */ u_int32_t ipcomps_toobig; /* Packet got > IP_MAXPACKET */ u_int32_t ipcomps_pdrops; /* Packet blocked due to policy */ u_int32_t ipcomps_crypto; /* "Crypto" processing failure */ u_int32_t ipcomps_hist[IPCOMP_ALG_MAX];/* Per-algorithm op count */ + u_int32_t version; /* Version of this structure. */ + u_int32_t ipcomps_threshold; /* Packet < comp. algo. threshold. */ + u_int32_t ipcomps_uncompr; /* Compression was useles. */ }; #ifdef _KERNEL VNET_DECLARE(int, ipcomp_enable); #define V_ipcomp_enable VNET(ipcomp_enable) VNET_DECLARE(struct ipcompstat, ipcompstat); #define V_ipcompstat VNET(ipcompstat) #endif /* _KERNEL */ #endif /*_NETIPSEC_IPCOMP_VAR_H_*/ Index: head/sys/netipsec/xform_ipcomp.c =================================================================== --- head/sys/netipsec/xform_ipcomp.c (revision 199945) +++ head/sys/netipsec/xform_ipcomp.c (revision 199946) @@ -1,611 +1,623 @@ /* $FreeBSD$ */ /* $OpenBSD: ip_ipcomp.c,v 1.1 2001/07/05 12:08:52 jjbg Exp $ */ /*- * Copyright (c) 2001 Jean-Jacques Bernard-Gundol (jj@wabbitt.org) * * 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. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. */ /* IP payload compression protocol (IPComp), see RFC 2393 */ #include "opt_inet.h" #include "opt_inet6.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef INET6 #include #include #endif #include #include #include #include #include #include #include VNET_DEFINE(int, ipcomp_enable) = 0; VNET_DEFINE(struct ipcompstat, ipcompstat); SYSCTL_DECL(_net_inet_ipcomp); SYSCTL_VNET_INT(_net_inet_ipcomp, OID_AUTO, ipcomp_enable, CTLFLAG_RW, &VNET_NAME(ipcomp_enable), 0, ""); SYSCTL_VNET_STRUCT(_net_inet_ipcomp, IPSECCTL_STATS, stats, CTLFLAG_RD, &VNET_NAME(ipcompstat), ipcompstat, ""); static int ipcomp_input_cb(struct cryptop *crp); static int ipcomp_output_cb(struct cryptop *crp); struct comp_algo * ipcomp_algorithm_lookup(int alg) { if (alg >= IPCOMP_ALG_MAX) return NULL; switch (alg) { case SADB_X_CALG_DEFLATE: return &comp_algo_deflate; } return NULL; } /* * ipcomp_init() is called when an CPI is being set up. */ static int ipcomp_init(struct secasvar *sav, struct xformsw *xsp) { struct comp_algo *tcomp; struct cryptoini cric; /* NB: algorithm really comes in alg_enc and not alg_comp! */ tcomp = ipcomp_algorithm_lookup(sav->alg_enc); if (tcomp == NULL) { DPRINTF(("%s: unsupported compression algorithm %d\n", __func__, sav->alg_comp)); return EINVAL; } sav->alg_comp = sav->alg_enc; /* set for doing histogram */ sav->tdb_xform = xsp; sav->tdb_compalgxform = tcomp; /* Initialize crypto session */ bzero(&cric, sizeof (cric)); cric.cri_alg = sav->tdb_compalgxform->type; return crypto_newsession(&sav->tdb_cryptoid, &cric, V_crypto_support); } /* * ipcomp_zeroize() used when IPCA is deleted */ static int ipcomp_zeroize(struct secasvar *sav) { int err; err = crypto_freesession(sav->tdb_cryptoid); sav->tdb_cryptoid = 0; return err; } /* * ipcomp_input() gets called to uncompress an input packet */ static int ipcomp_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff) { struct tdb_crypto *tc; struct cryptodesc *crdc; struct cryptop *crp; int hlen = IPCOMP_HLENGTH; /* Get crypto descriptors */ crp = crypto_getreq(1); if (crp == NULL) { m_freem(m); DPRINTF(("%s: no crypto descriptors\n", __func__)); V_ipcompstat.ipcomps_crypto++; return ENOBUFS; } /* Get IPsec-specific opaque pointer */ tc = (struct tdb_crypto *) malloc(sizeof (*tc), M_XDATA, M_NOWAIT|M_ZERO); if (tc == NULL) { m_freem(m); crypto_freereq(crp); DPRINTF(("%s: cannot allocate tdb_crypto\n", __func__)); V_ipcompstat.ipcomps_crypto++; return ENOBUFS; } crdc = crp->crp_desc; crdc->crd_skip = skip + hlen; crdc->crd_len = m->m_pkthdr.len - (skip + hlen); crdc->crd_inject = skip; tc->tc_ptr = 0; /* Decompression operation */ crdc->crd_alg = sav->tdb_compalgxform->type; /* Crypto operation descriptor */ crp->crp_ilen = m->m_pkthdr.len - (skip + hlen); crp->crp_flags = CRYPTO_F_IMBUF | CRYPTO_F_CBIFSYNC; crp->crp_buf = (caddr_t) m; crp->crp_callback = ipcomp_input_cb; crp->crp_sid = sav->tdb_cryptoid; crp->crp_opaque = (caddr_t) tc; /* These are passed as-is to the callback */ tc->tc_spi = sav->spi; tc->tc_dst = sav->sah->saidx.dst; tc->tc_proto = sav->sah->saidx.proto; tc->tc_protoff = protoff; tc->tc_skip = skip; return crypto_dispatch(crp); } #ifdef INET6 #define IPSEC_COMMON_INPUT_CB(m, sav, skip, protoff, mtag) do { \ if (saidx->dst.sa.sa_family == AF_INET6) { \ error = ipsec6_common_input_cb(m, sav, skip, protoff, mtag); \ } else { \ error = ipsec4_common_input_cb(m, sav, skip, protoff, mtag); \ } \ } while (0) #else #define IPSEC_COMMON_INPUT_CB(m, sav, skip, protoff, mtag) \ (error = ipsec4_common_input_cb(m, sav, skip, protoff, mtag)) #endif /* * IPComp input callback from the crypto driver. */ static int ipcomp_input_cb(struct cryptop *crp) { struct cryptodesc *crd; struct tdb_crypto *tc; int skip, protoff; struct mtag *mtag; struct mbuf *m; struct secasvar *sav; struct secasindex *saidx; int hlen = IPCOMP_HLENGTH, error, clen; u_int8_t nproto; caddr_t addr; crd = crp->crp_desc; tc = (struct tdb_crypto *) crp->crp_opaque; IPSEC_ASSERT(tc != NULL, ("null opaque crypto data area!")); skip = tc->tc_skip; protoff = tc->tc_protoff; mtag = (struct mtag *) tc->tc_ptr; m = (struct mbuf *) crp->crp_buf; sav = KEY_ALLOCSA(&tc->tc_dst, tc->tc_proto, tc->tc_spi); if (sav == NULL) { V_ipcompstat.ipcomps_notdb++; DPRINTF(("%s: SA expired while in crypto\n", __func__)); error = ENOBUFS; /*XXX*/ goto bad; } saidx = &sav->sah->saidx; IPSEC_ASSERT(saidx->dst.sa.sa_family == AF_INET || saidx->dst.sa.sa_family == AF_INET6, ("unexpected protocol family %u", saidx->dst.sa.sa_family)); /* Check for crypto errors */ if (crp->crp_etype) { /* Reset the session ID */ if (sav->tdb_cryptoid != 0) sav->tdb_cryptoid = crp->crp_sid; if (crp->crp_etype == EAGAIN) { KEY_FREESAV(&sav); return crypto_dispatch(crp); } V_ipcompstat.ipcomps_noxform++; DPRINTF(("%s: crypto error %d\n", __func__, crp->crp_etype)); error = crp->crp_etype; goto bad; } /* Shouldn't happen... */ if (m == NULL) { V_ipcompstat.ipcomps_crypto++; DPRINTF(("%s: null mbuf returned from crypto\n", __func__)); error = EINVAL; goto bad; } V_ipcompstat.ipcomps_hist[sav->alg_comp]++; clen = crp->crp_olen; /* Length of data after processing */ /* Release the crypto descriptors */ free(tc, M_XDATA), tc = NULL; crypto_freereq(crp), crp = NULL; /* In case it's not done already, adjust the size of the mbuf chain */ m->m_pkthdr.len = clen + hlen + skip; if (m->m_len < skip + hlen && (m = m_pullup(m, skip + hlen)) == 0) { V_ipcompstat.ipcomps_hdrops++; /*XXX*/ DPRINTF(("%s: m_pullup failed\n", __func__)); error = EINVAL; /*XXX*/ goto bad; } /* Keep the next protocol field */ addr = (caddr_t) mtod(m, struct ip *) + skip; nproto = ((struct ipcomp *) addr)->comp_nxt; /* Remove the IPCOMP header */ error = m_striphdr(m, skip, hlen); if (error) { V_ipcompstat.ipcomps_hdrops++; DPRINTF(("%s: bad mbuf chain, IPCA %s/%08lx\n", __func__, ipsec_address(&sav->sah->saidx.dst), (u_long) ntohl(sav->spi))); goto bad; } /* Restore the Next Protocol field */ m_copyback(m, protoff, sizeof (u_int8_t), (u_int8_t *) &nproto); IPSEC_COMMON_INPUT_CB(m, sav, skip, protoff, NULL); KEY_FREESAV(&sav); return error; bad: if (sav) KEY_FREESAV(&sav); if (m) m_freem(m); if (tc != NULL) free(tc, M_XDATA); if (crp) crypto_freereq(crp); return error; } /* * IPComp output routine, called by ipsec[46]_process_packet() */ static int ipcomp_output( struct mbuf *m, struct ipsecrequest *isr, struct mbuf **mp, int skip, int protoff ) { struct secasvar *sav; struct comp_algo *ipcompx; int error, ralen, maxpacketsize; struct cryptodesc *crdc; struct cryptop *crp; struct tdb_crypto *tc; sav = isr->sav; IPSEC_ASSERT(sav != NULL, ("null SA")); ipcompx = sav->tdb_compalgxform; IPSEC_ASSERT(ipcompx != NULL, ("null compression xform")); /* * Do not touch the packet in case our payload to compress * is lower than the minimal threshold of the compression * alogrithm. We will just send out the data uncompressed. * See RFC 3173, 2.2. Non-Expansion Policy. */ if (m->m_pkthdr.len <= ipcompx->minlen) { - /* XXX-BZ V_ipcompstat.threshold++; */ + V_ipcompstat.ipcomps_threshold++; return ipsec_process_done(m, isr); } ralen = m->m_pkthdr.len - skip; /* Raw payload length before comp. */ V_ipcompstat.ipcomps_output++; /* Check for maximum packet size violations. */ switch (sav->sah->saidx.dst.sa.sa_family) { #ifdef INET case AF_INET: maxpacketsize = IP_MAXPACKET; break; #endif /* INET */ #ifdef INET6 case AF_INET6: maxpacketsize = IPV6_MAXPACKET; break; #endif /* INET6 */ default: V_ipcompstat.ipcomps_nopf++; DPRINTF(("%s: unknown/unsupported protocol family %d, " "IPCA %s/%08lx\n", __func__, sav->sah->saidx.dst.sa.sa_family, ipsec_address(&sav->sah->saidx.dst), (u_long) ntohl(sav->spi))); error = EPFNOSUPPORT; goto bad; } if (ralen + skip + IPCOMP_HLENGTH > maxpacketsize) { V_ipcompstat.ipcomps_toobig++; DPRINTF(("%s: packet in IPCA %s/%08lx got too big " "(len %u, max len %u)\n", __func__, ipsec_address(&sav->sah->saidx.dst), (u_long) ntohl(sav->spi), ralen + skip + IPCOMP_HLENGTH, maxpacketsize)); error = EMSGSIZE; goto bad; } /* Update the counters */ V_ipcompstat.ipcomps_obytes += m->m_pkthdr.len - skip; m = m_unshare(m, M_NOWAIT); if (m == NULL) { V_ipcompstat.ipcomps_hdrops++; DPRINTF(("%s: cannot clone mbuf chain, IPCA %s/%08lx\n", __func__, ipsec_address(&sav->sah->saidx.dst), (u_long) ntohl(sav->spi))); error = ENOBUFS; goto bad; } /* Ok now, we can pass to the crypto processing. */ /* Get crypto descriptors */ crp = crypto_getreq(1); if (crp == NULL) { V_ipcompstat.ipcomps_crypto++; DPRINTF(("%s: failed to acquire crypto descriptor\n",__func__)); error = ENOBUFS; goto bad; } crdc = crp->crp_desc; /* Compression descriptor */ crdc->crd_skip = skip; crdc->crd_len = ralen; crdc->crd_flags = CRD_F_COMP; crdc->crd_inject = skip; /* Compression operation */ crdc->crd_alg = ipcompx->type; /* IPsec-specific opaque crypto info */ tc = (struct tdb_crypto *) malloc(sizeof(struct tdb_crypto), M_XDATA, M_NOWAIT|M_ZERO); if (tc == NULL) { V_ipcompstat.ipcomps_crypto++; DPRINTF(("%s: failed to allocate tdb_crypto\n", __func__)); crypto_freereq(crp); error = ENOBUFS; goto bad; } tc->tc_isr = isr; tc->tc_spi = sav->spi; tc->tc_dst = sav->sah->saidx.dst; tc->tc_proto = sav->sah->saidx.proto; tc->tc_protoff = protoff; tc->tc_skip = skip; /* Crypto operation descriptor */ crp->crp_ilen = m->m_pkthdr.len; /* Total input length */ crp->crp_flags = CRYPTO_F_IMBUF | CRYPTO_F_CBIFSYNC; crp->crp_buf = (caddr_t) m; crp->crp_callback = ipcomp_output_cb; crp->crp_opaque = (caddr_t) tc; crp->crp_sid = sav->tdb_cryptoid; return crypto_dispatch(crp); bad: if (m) m_freem(m); return (error); } /* * IPComp output callback from the crypto driver. */ static int ipcomp_output_cb(struct cryptop *crp) { struct tdb_crypto *tc; struct ipsecrequest *isr; struct secasvar *sav; struct mbuf *m; int error, skip; tc = (struct tdb_crypto *) crp->crp_opaque; IPSEC_ASSERT(tc != NULL, ("null opaque data area!")); m = (struct mbuf *) crp->crp_buf; skip = tc->tc_skip; isr = tc->tc_isr; IPSECREQUEST_LOCK(isr); sav = KEY_ALLOCSA(&tc->tc_dst, tc->tc_proto, tc->tc_spi); if (sav == NULL) { V_ipcompstat.ipcomps_notdb++; DPRINTF(("%s: SA expired while in crypto\n", __func__)); error = ENOBUFS; /*XXX*/ goto bad; } IPSEC_ASSERT(isr->sav == sav, ("SA changed\n")); /* Check for crypto errors */ if (crp->crp_etype) { /* Reset the session ID */ if (sav->tdb_cryptoid != 0) sav->tdb_cryptoid = crp->crp_sid; if (crp->crp_etype == EAGAIN) { KEY_FREESAV(&sav); IPSECREQUEST_UNLOCK(isr); return crypto_dispatch(crp); } V_ipcompstat.ipcomps_noxform++; DPRINTF(("%s: crypto error %d\n", __func__, crp->crp_etype)); error = crp->crp_etype; goto bad; } /* Shouldn't happen... */ if (m == NULL) { V_ipcompstat.ipcomps_crypto++; DPRINTF(("%s: bogus return buffer from crypto\n", __func__)); error = EINVAL; goto bad; } V_ipcompstat.ipcomps_hist[sav->alg_comp]++; if (crp->crp_ilen - skip > crp->crp_olen) { struct mbuf *mo; struct ipcomp *ipcomp; int roff; uint8_t prot; /* Compression helped, inject IPCOMP header. */ mo = m_makespace(m, skip, IPCOMP_HLENGTH, &roff); if (mo == NULL) { V_ipcompstat.ipcomps_wrap++; DPRINTF(("%s: IPCOMP header inject failed for IPCA %s/%08lx\n", __func__, ipsec_address(&sav->sah->saidx.dst), (u_long) ntohl(sav->spi))); error = ENOBUFS; goto bad; } ipcomp = (struct ipcomp *)(mtod(mo, caddr_t) + roff); /* Initialize the IPCOMP header */ /* XXX alignment always correct? */ switch (sav->sah->saidx.dst.sa.sa_family) { #ifdef INET case AF_INET: ipcomp->comp_nxt = mtod(m, struct ip *)->ip_p; break; #endif /* INET */ #ifdef INET6 case AF_INET6: ipcomp->comp_nxt = mtod(m, struct ip6_hdr *)->ip6_nxt; break; #endif } ipcomp->comp_flags = 0; ipcomp->comp_cpi = htons((u_int16_t) ntohl(sav->spi)); /* Fix Next Protocol in IPv4/IPv6 header */ prot = IPPROTO_IPCOMP; m_copyback(m, tc->tc_protoff, sizeof(u_int8_t), (u_char *)&prot); /* Adjust the length in the IP header */ switch (sav->sah->saidx.dst.sa.sa_family) { #ifdef INET case AF_INET: mtod(m, struct ip *)->ip_len = htons(m->m_pkthdr.len); break; #endif /* INET */ #ifdef INET6 case AF_INET6: mtod(m, struct ip6_hdr *)->ip6_plen = htons(m->m_pkthdr.len) - sizeof(struct ip6_hdr); break; #endif /* INET6 */ default: V_ipcompstat.ipcomps_nopf++; DPRINTF(("%s: unknown/unsupported protocol " "family %d, IPCA %s/%08lx\n", __func__, sav->sah->saidx.dst.sa.sa_family, ipsec_address(&sav->sah->saidx.dst), (u_long) ntohl(sav->spi))); error = EPFNOSUPPORT; goto bad; } } else { - /* compression was useless, we have lost time */ - /* XXX add statistic */ + /* Compression was useless, we have lost time. */ + V_ipcompstat.ipcomps_uncompr++; + DPRINTF(("%s: compressions was useless %d - %d <= %d\n", + __func__, crp->crp_ilen, skip, crp->crp_olen)); /* XXX remember state to not compress the next couple * of packets, RFC 3173, 2.2. Non-Expansion Policy */ } /* Release the crypto descriptor */ free(tc, M_XDATA); crypto_freereq(crp); /* NB: m is reclaimed by ipsec_process_done. */ error = ipsec_process_done(m, isr); KEY_FREESAV(&sav); IPSECREQUEST_UNLOCK(isr); return error; bad: if (sav) KEY_FREESAV(&sav); IPSECREQUEST_UNLOCK(isr); if (m) m_freem(m); free(tc, M_XDATA); crypto_freereq(crp); return error; } static struct xformsw ipcomp_xformsw = { XF_IPCOMP, XFT_COMP, "IPcomp", ipcomp_init, ipcomp_zeroize, ipcomp_input, ipcomp_output }; static void ipcomp_attach(void) { xform_register(&ipcomp_xformsw); } SYSINIT(ipcomp_xform_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_MIDDLE, ipcomp_attach, NULL); + +static void +vnet_ipcomp_attach(const void *unused __unused) +{ + + V_ipcompstat.version = IPCOMPSTAT_VERSION; +} + +VNET_SYSINIT(vnet_ipcomp_xform_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_MIDDLE, + vnet_ipcomp_attach, NULL); Index: head/usr.bin/netstat/ipsec.c =================================================================== --- head/usr.bin/netstat/ipsec.c (revision 199945) +++ head/usr.bin/netstat/ipsec.c (revision 199946) @@ -1,464 +1,474 @@ /* $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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 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 "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 { -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 ipsec_hist(const u_quad_t *hist, size_t histmax, const struct val2str *name, const char *title); static void print_ipsecstats(const struct ipsecstat *ipsecstat); /* * Dump IPSEC statistics structure. */ static void ipsec_hist(const u_quad_t *hist, size_t histmax, const struct val2str *name, const char *title) { int first; size_t proto; const struct val2str *p; first = 1; for (proto = 0; proto < histmax; proto++) { if (hist[proto] <= 0) continue; if (first) { printf("\t%s histogram:\n", title); first = 0; } for (p = name; p && p->str; p++) { if (p->val == (int)proto) break; } if (p && p->str) { printf("\t\t%s: %ju\n", p->str, (uintmax_t)hist[proto]); } else { printf("\t\t#%ld: %ju\n", (long)proto, (uintmax_t)hist[proto]); } } } static void print_ipsecstats(const struct ipsecstat *ipsecstat) { #define p(f, m) if (ipsecstat->f || sflag <= 1) \ printf(m, (uintmax_t)ipsecstat->f, plural(ipsecstat->f)) #define pes(f, m) if (ipsecstat->f || sflag <= 1) \ printf(m, (uintmax_t)ipsecstat->f, plurales(ipsecstat->f)) #define hist(f, n, t) \ ipsec_hist((f), sizeof(f)/sizeof(f[0]), (n), (t)); p(in_success, "\t%ju inbound packet%s processed successfully\n"); p(in_polvio, "\t%ju inbound packet%s violated process security " "policy\n"); p(in_nosa, "\t%ju inbound packet%s with no SA available\n"); p(in_inval, "\t%ju invalid inbound packet%s\n"); p(in_nomem, "\t%ju inbound packet%s failed due to insufficient memory\n"); p(in_badspi, "\t%ju inbound packet%s failed getting SPI\n"); p(in_ahreplay, "\t%ju inbound packet%s failed on AH replay check\n"); p(in_espreplay, "\t%ju inbound packet%s failed on ESP replay check\n"); p(in_ahauthsucc, "\t%ju inbound packet%s considered authentic\n"); p(in_ahauthfail, "\t%ju inbound packet%s failed on authentication\n"); hist(ipsecstat->in_ahhist, ipsec_ahnames, "AH input"); hist(ipsecstat->in_esphist, ipsec_espnames, "ESP input"); hist(ipsecstat->in_comphist, ipsec_compnames, "IPComp input"); p(out_success, "\t%ju outbound packet%s processed successfully\n"); p(out_polvio, "\t%ju outbound packet%s violated process security " "policy\n"); p(out_nosa, "\t%ju outbound packet%s with no SA available\n"); p(out_inval, "\t%ju invalid outbound packet%s\n"); p(out_nomem, "\t%ju outbound packet%s failed due to insufficient memory\n"); p(out_noroute, "\t%ju outbound packet%s with no route\n"); hist(ipsecstat->out_ahhist, ipsec_ahnames, "AH output"); hist(ipsecstat->out_esphist, ipsec_espnames, "ESP output"); hist(ipsecstat->out_comphist, ipsec_compnames, "IPComp output"); p(spdcachelookup, "\t%ju SPD cache lookup%s\n"); pes(spdcachemiss, "\t%ju SPD cache miss%s\n"); #undef pes #undef hist p(ips_in_polvio, "\t%ju inbound packet%s violated process " "security policy\n"); p(ips_out_polvio, "\t%ju outbound packet%s violated process " "security policy\n"); p(ips_out_nosa, "\t%ju outbound packet%s with no SA available\n"); p(ips_out_nomem, "\t%ju outbound packet%s failed due to " "insufficient memory\n"); p(ips_out_noroute, "\t%ju outbound packet%s with no route " "available\n"); p(ips_out_inval, "\t%ju invalid outbound packet%s\n"); p(ips_out_bundlesa, "\t%ju outbound packet%s with bundled SAs\n"); p(ips_mbcoalesced, "\t%ju mbuf%s coalesced during clone\n"); p(ips_clcoalesced, "\t%ju cluster%s coalesced during clone\n"); p(ips_clcopied, "\t%ju cluster%s copied during clone\n"); p(ips_mbinserted, "\t%ju mbuf%s inserted during makespace\n"); #undef p } void ipsec_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct ipsecstat ipsecstat; if (off == 0) return; printf ("%s:\n", name); kread(off, (char *)&ipsecstat, sizeof(ipsecstat)); print_ipsecstats(&ipsecstat); } static void ipsec_hist_new(const u_int32_t *hist, size_t histmax, const struct val2str *name, const char *title); 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 u_int32_t *hist, size_t histmax, const struct val2str *name, const char *title) { int first; size_t proto; const struct val2str *p; first = 1; for (proto = 0; proto < histmax; proto++) { if (hist[proto] <= 0) continue; if (first) { printf("\t%s histogram:\n", title); first = 0; } for (p = name; p && p->str; p++) { if (p->val == (int)proto) break; } if (p && p->str) { printf("\t\t%s: %u\n", p->str, hist[proto]); } else { printf("\t\t#%lu: %u\n", (unsigned long)proto, hist[proto]); } } } static void print_ahstats(const struct ahstat *ahstat) { #define p32(f, m) if (ahstat->f || sflag <= 1) \ printf("\t%u" m, (unsigned int)ahstat->f, plural(ahstat->f)) #define p64(f, m) if (ahstat->f || sflag <= 1) \ printf("\t%ju" m, (uintmax_t)ahstat->f, plural(ahstat->f)) #define hist(f, n, t) \ ipsec_hist_new((f), sizeof(f)/sizeof(f[0]), (n), (t)); p32(ahs_hdrops, " packet%s shorter than header shows\n"); p32(ahs_nopf, " packet%s dropped; protocol family not supported\n"); p32(ahs_notdb, " packet%s dropped; no TDB\n"); p32(ahs_badkcr, " packet%s dropped; bad KCR\n"); p32(ahs_qfull, " packet%s dropped; queue full\n"); p32(ahs_noxform, " packet%s dropped; no transform\n"); p32(ahs_wrap, " replay counter wrap%s\n"); p32(ahs_badauth, " packet%s dropped; bad authentication detected\n"); p32(ahs_badauthl, " packet%s dropped; bad authentication length\n"); p32(ahs_replay, " possible replay packet%s detected\n"); p32(ahs_input, " packet%s in\n"); p32(ahs_output, " packet%s out\n"); p32(ahs_invalid, " packet%s dropped; invalid TDB\n"); p64(ahs_ibytes, " byte%s in\n"); p64(ahs_obytes, " byte%s out\n"); p32(ahs_toobig, " packet%s dropped; larger than IP_MAXPACKET\n"); p32(ahs_pdrops, " packet%s blocked due to policy\n"); p32(ahs_crypto, " crypto processing failure%s\n"); p32(ahs_tunnel, " tunnel sanity check failure%s\n"); hist(ahstat->ahs_hist, ipsec_ahnames, "AH output"); #undef p32 #undef p64 #undef hist } void ah_stats(u_long off, const char *name, int family __unused, int proto __unused) { struct ahstat ahstat; if (off == 0) return; printf ("%s:\n", name); kread(off, (char *)&ahstat, sizeof(ahstat)); print_ahstats(&ahstat); } static void print_espstats(const struct espstat *espstat) { #define p32(f, m) if (espstat->f || sflag <= 1) \ printf("\t%u" m, (unsigned int)espstat->f, plural(espstat->f)) #define p64(f, m) if (espstat->f || sflag <= 1) \ printf("\t%ju" m, (uintmax_t)espstat->f, plural(espstat->f)) #define hist(f, n, t) \ ipsec_hist_new((f), sizeof(f)/sizeof(f[0]), (n), (t)); p32(esps_hdrops, " packet%s shorter than header shows\n"); p32(esps_nopf, " packet%s dropped; protocol family not supported\n"); p32(esps_notdb, " packet%s dropped; no TDB\n"); p32(esps_badkcr, " packet%s dropped; bad KCR\n"); p32(esps_qfull, " packet%s dropped; queue full\n"); p32(esps_noxform, " packet%s dropped; no transform\n"); p32(esps_badilen, " packet%s dropped; bad ilen\n"); p32(esps_wrap, " replay counter wrap%s\n"); p32(esps_badenc, " packet%s dropped; bad encryption detected\n"); p32(esps_badauth, " packet%s dropped; bad authentication detected\n"); p32(esps_replay, " possible replay packet%s detected\n"); p32(esps_input, " packet%s in\n"); p32(esps_output, " packet%s out\n"); p32(esps_invalid, " packet%s dropped; invalid TDB\n"); p64(esps_ibytes, " byte%s in\n"); p64(esps_obytes, " byte%s out\n"); p32(esps_toobig, " packet%s dropped; larger than IP_MAXPACKET\n"); p32(esps_pdrops, " packet%s blocked due to policy\n"); p32(esps_crypto, " crypto processing failure%s\n"); p32(esps_tunnel, " tunnel sanity check failure%s\n"); hist(espstat->esps_hist, ipsec_espnames, "ESP output"); #undef p32 #undef p64 #undef hist } void esp_stats(u_long off, const char *name, int family __unused, int proto __unused) { struct espstat espstat; if (off == 0) return; printf ("%s:\n", name); kread(off, (char *)&espstat, sizeof(espstat)); print_espstats(&espstat); } static void print_ipcompstats(const struct ipcompstat *ipcompstat) { + uint32_t version; #define p32(f, m) if (ipcompstat->f || sflag <= 1) \ printf("\t%u" m, (unsigned int)ipcompstat->f, plural(ipcompstat->f)) #define p64(f, m) if (ipcompstat->f || sflag <= 1) \ printf("\t%ju" m, (uintmax_t)ipcompstat->f, plural(ipcompstat->f)) #define hist(f, n, t) \ ipsec_hist_new((f), sizeof(f)/sizeof(f[0]), (n), (t)); +#ifndef IPCOMPSTAT_VERSION + version = 0; +#else + version = ipcompstat->version; +#endif p32(ipcomps_hdrops, " packet%s shorter than header shows\n"); p32(ipcomps_nopf, " packet%s dropped; protocol family not supported\n"); p32(ipcomps_notdb, " packet%s dropped; no TDB\n"); p32(ipcomps_badkcr, " packet%s dropped; bad KCR\n"); p32(ipcomps_qfull, " packet%s dropped; queue full\n"); p32(ipcomps_noxform, " packet%s dropped; no transform\n"); p32(ipcomps_wrap, " replay counter wrap%s\n"); p32(ipcomps_input, " packet%s in\n"); p32(ipcomps_output, " packet%s out\n"); p32(ipcomps_invalid, " packet%s dropped; invalid TDB\n"); p64(ipcomps_ibytes, " byte%s in\n"); p64(ipcomps_obytes, " byte%s out\n"); p32(ipcomps_toobig, " packet%s dropped; larger than IP_MAXPACKET\n"); p32(ipcomps_pdrops, " packet%s blocked due to policy\n"); p32(ipcomps_crypto, " crypto processing failure%s\n"); hist(ipcompstat->ipcomps_hist, ipsec_compnames, "COMP output"); + if (version >= 1) { + p32(ipcomps_threshold, " packet%s sent uncompressed; size < compr. algo. threshold\n"); + p32(ipcomps_uncompr, " packet%s sent uncompressed; compression was useless\n"); + } #undef p32 #undef p64 #undef hist } void ipcomp_stats(u_long off, const char *name, int family __unused, int proto __unused) { struct ipcompstat ipcompstat; if (off == 0) return; printf ("%s:\n", name); kread(off, (char *)&ipcompstat, sizeof(ipcompstat)); print_ipcompstats(&ipcompstat); } #endif /*IPSEC*/