diff options
author | sam <sam@FreeBSD.org> | 2003-09-29 22:57:43 +0000 |
---|---|---|
committer | sam <sam@FreeBSD.org> | 2003-09-29 22:57:43 +0000 |
commit | 0a6c1d4242d4d23328bf77b152fe0864e2db7f35 (patch) | |
tree | 8a7531562577bbc1732a8f3b1aa8301245449cab /sys/netipsec/ipsec_input.c | |
parent | 9dc7c620e432a011a3fdcfb8183076ad041baeac (diff) | |
download | FreeBSD-src-0a6c1d4242d4d23328bf77b152fe0864e2db7f35.zip FreeBSD-src-0a6c1d4242d4d23328bf77b152fe0864e2db7f35.tar.gz |
MFp4: portability work, general cleanup, locking fixes
change 38496
o add ipsec_osdep.h that holds os-specific definitions for portability
o s/KASSERT/IPSEC_ASSERT/ for portability
o s/SPLASSERT/IPSEC_SPLASSERT/ for portability
o remove function names from ASSERT strings since line#+file pinpints
the location
o use __func__ uniformly to reduce string storage
o convert some random #ifdef DIAGNOSTIC code to assertions
o remove some debuggging assertions no longer needed
change 38498
o replace numerous bogus panic's with equally bogus assertions
that at least go away on a production system
change 38502 + 38530
o change explicit mtx operations to #defines to simplify
future changes to a different lock type
change 38531
o hookup ipv4 ctlinput paths to a noop routine; we should be
handling path mtu changes at least
o correct potential null pointer deref in ipsec4_common_input_cb
chnage 38685
o fix locking for bundled SA's and for when key exchange is required
change 38770
o eliminate recursion on the SAHTREE lock
change 38804
o cleanup some types: long -> time_t
o remove refrence to dead #define
change 38805
o correct some types: long -> time_t
o add scan generation # to secpolicy to deal with locking issues
change 38806
o use LIST_FOREACH_SAFE instead of handrolled code
o change key_flush_spd to drop the sptree lock before purging
an entry to avoid lock recursion and to avoid holding the lock
over a long-running operation
o misc cleanups of tangled and twisty code
There is still much to do here but for now things look to be
working again.
Supported by: FreeBSD Foundation
Diffstat (limited to 'sys/netipsec/ipsec_input.c')
-rw-r--r-- | sys/netipsec/ipsec_input.c | 281 |
1 files changed, 146 insertions, 135 deletions
diff --git a/sys/netipsec/ipsec_input.c b/sys/netipsec/ipsec_input.c index 0512b66..9eefa4d 100644 --- a/sys/netipsec/ipsec_input.c +++ b/sys/netipsec/ipsec_input.c @@ -91,11 +91,11 @@ #include <machine/in_cksum.h> #include <machine/stdarg.h> -#include <net/net_osdep.h> - #define IPSEC_ISTAT(p,x,y,z) ((p) == IPPROTO_ESP ? (x)++ : \ (p) == IPPROTO_AH ? (y)++ : (z)++) +static void ipsec4_common_ctlinput(int, struct sockaddr *, void *, int); + /* * ipsec_common_input gets called when an IPsec-protected packet * is received by IPv4 or IPv6. It's job is to find the right SA @@ -113,7 +113,7 @@ ipsec_common_input(struct mbuf *m, int skip, int protoff, int af, int sproto) IPSEC_ISTAT(sproto, espstat.esps_input, ahstat.ahs_input, ipcompstat.ipcomps_input); - KASSERT(m != NULL, ("ipsec_common_input: null packet")); + IPSEC_ASSERT(m != NULL, ("null packet")); if ((sproto == IPPROTO_ESP && !esp_enable) || (sproto == IPPROTO_AH && !ah_enable) || @@ -128,7 +128,7 @@ ipsec_common_input(struct mbuf *m, int skip, int protoff, int af, int sproto) m_freem(m); IPSEC_ISTAT(sproto, espstat.esps_hdrops, ahstat.ahs_hdrops, ipcompstat.ipcomps_hdrops); - DPRINTF(("ipsec_common_input: packet too small\n")); + DPRINTF(("%s: packet too small\n", __func__)); return EINVAL; } @@ -170,8 +170,7 @@ ipsec_common_input(struct mbuf *m, int skip, int protoff, int af, int sproto) break; #endif /* INET6 */ default: - DPRINTF(("ipsec_common_input: unsupported protocol " - "family %u\n", af)); + DPRINTF(("%s: unsupported protocol family %u\n", __func__, af)); m_freem(m); IPSEC_ISTAT(sproto, espstat.esps_nopf, ahstat.ahs_nopf, ipcompstat.ipcomps_nopf); @@ -181,9 +180,8 @@ ipsec_common_input(struct mbuf *m, int skip, int protoff, int af, int sproto) /* NB: only pass dst since key_allocsa follows RFC2401 */ sav = KEY_ALLOCSA(&dst_address, sproto, spi); if (sav == NULL) { - DPRINTF(("ipsec_common_input: no key association found for" - " SA %s/%08lx/%u\n", - ipsec_address(&dst_address), + DPRINTF(("%s: no key association found for SA %s/%08lx/%u\n", + __func__, ipsec_address(&dst_address), (u_long) ntohl(spi), sproto)); IPSEC_ISTAT(sproto, espstat.esps_notdb, ahstat.ahs_notdb, ipcompstat.ipcomps_notdb); @@ -192,9 +190,8 @@ ipsec_common_input(struct mbuf *m, int skip, int protoff, int af, int sproto) } if (sav->tdb_xform == NULL) { - DPRINTF(("ipsec_common_input: attempted to use uninitialized" - " SA %s/%08lx/%u\n", - ipsec_address(&dst_address), + DPRINTF(("%s: attempted to use uninitialized SA %s/%08lx/%u\n", + __func__, ipsec_address(&dst_address), (u_long) ntohl(spi), sproto)); IPSEC_ISTAT(sproto, espstat.esps_noxform, ahstat.ahs_noxform, ipcompstat.ipcomps_noxform); @@ -236,12 +233,26 @@ ah4_input(struct mbuf *m, int off) { ipsec4_common_input(m, off, IPPROTO_AH); } +void +ah4_ctlinput(int cmd, struct sockaddr *sa, void *v) +{ + if (sa->sa_family == AF_INET && + sa->sa_len == sizeof(struct sockaddr_in)) + ipsec4_common_ctlinput(cmd, sa, v, IPPROTO_AH); +} void esp4_input(struct mbuf *m, int off) { ipsec4_common_input(m, off, IPPROTO_ESP); } +void +esp4_ctlinput(int cmd, struct sockaddr *sa, void *v) +{ + if (sa->sa_family == AF_INET && + sa->sa_len == sizeof(struct sockaddr_in)) + ipsec4_common_ctlinput(cmd, sa, v, IPPROTO_ESP); +} void ipcomp4_input(struct mbuf *m, int off) @@ -266,25 +277,22 @@ ipsec4_common_input_cb(struct mbuf *m, struct secasvar *sav, struct secasindex *saidx; int error; -#if 0 - SPLASSERT(net, "ipsec4_common_input_cb"); -#endif + IPSEC_SPLASSERT_SOFTNET(__func__); - KASSERT(m != NULL, ("ipsec4_common_input_cb: null mbuf")); - KASSERT(sav != NULL, ("ipsec4_common_input_cb: null SA")); - KASSERT(sav->sah != NULL, ("ipsec4_common_input_cb: null SAH")); + IPSEC_ASSERT(m != NULL, ("null mbuf")); + IPSEC_ASSERT(sav != NULL, ("null SA")); + IPSEC_ASSERT(sav->sah != NULL, ("null SAH")); saidx = &sav->sah->saidx; af = saidx->dst.sa.sa_family; - KASSERT(af == AF_INET, ("ipsec4_common_input_cb: unexpected af %u",af)); + IPSEC_ASSERT(af == AF_INET, ("unexpected af %u", af)); sproto = saidx->proto; - KASSERT(sproto == IPPROTO_ESP || sproto == IPPROTO_AH || + IPSEC_ASSERT(sproto == IPPROTO_ESP || sproto == IPPROTO_AH || sproto == IPPROTO_IPCOMP, - ("ipsec4_common_input_cb: unexpected security protocol %u", - sproto)); + ("unexpected security protocol %u", sproto)); /* Sanity check */ if (m == NULL) { - DPRINTF(("ipsec4_common_input_cb: null mbuf")); + DPRINTF(("%s: null mbuf", __func__)); IPSEC_ISTAT(sproto, espstat.esps_badkcr, ahstat.ahs_badkcr, ipcompstat.ipcomps_badkcr); KEY_FREESAV(&sav); @@ -294,9 +302,8 @@ ipsec4_common_input_cb(struct mbuf *m, struct secasvar *sav, if (skip != 0) { /* Fix IPv4 header */ if (m->m_len < skip && (m = m_pullup(m, skip)) == NULL) { - DPRINTF(("ipsec4_common_input_cb: processing failed " - "for SA %s/%08lx\n", - ipsec_address(&sav->sah->saidx.dst), + DPRINTF(("%s: processing failed for SA %s/%08lx\n", + __func__, ipsec_address(&sav->sah->saidx.dst), (u_long) ntohl(sav->spi))); IPSEC_ISTAT(sproto, espstat.esps_hdrops, ahstat.ahs_hdrops, ipcompstat.ipcomps_hdrops); @@ -343,9 +350,9 @@ ipsec4_common_input_cb(struct mbuf *m, struct secasvar *sav, (saidx->proxy.sa.sa_family != AF_INET && saidx->proxy.sa.sa_family != 0)) { - DPRINTF(("ipsec4_common_input_cb: inner " - "source address %s doesn't correspond to " - "expected proxy source %s, SA %s/%08lx\n", + DPRINTF(("%s: inner source address %s doesn't " + "correspond to expected proxy source %s, " + "SA %s/%08lx\n", __func__, inet_ntoa4(ipn.ip_src), ipsp_address(saidx->proxy), ipsp_address(saidx->dst), @@ -387,9 +394,9 @@ ipsec4_common_input_cb(struct mbuf *m, struct secasvar *sav, (saidx->proxy.sa.sa_family != AF_INET6 && saidx->proxy.sa.sa_family != 0)) { - DPRINTF(("ipsec4_common_input_cb: inner " - "source address %s doesn't correspond to " - "expected proxy source %s, SA %s/%08lx\n", + DPRINTF(("%s: inner source address %s doesn't " + "correspond to expected proxy source %s, " + "SA %s/%08lx\n", __func__, ip6_sprintf(&ip6n.ip6_src), ipsec_address(&saidx->proxy), ipsec_address(&saidx->dst), @@ -417,7 +424,7 @@ ipsec4_common_input_cb(struct mbuf *m, struct secasvar *sav, mtag = m_tag_get(PACKET_TAG_IPSEC_IN_DONE, sizeof(struct tdb_ident), M_NOWAIT); if (mtag == NULL) { - DPRINTF(("ipsec4_common_input_cb: failed to get tag\n")); + DPRINTF(("%s: failed to get tag\n", __func__)); IPSEC_ISTAT(sproto, espstat.esps_hdrops, ahstat.ahs_hdrops, ipcompstat.ipcomps_hdrops); error = ENOMEM; @@ -444,8 +451,8 @@ ipsec4_common_input_cb(struct mbuf *m, struct secasvar *sav, IPSEC_ISTAT(sproto, espstat.esps_qfull, ahstat.ahs_qfull, ipcompstat.ipcomps_qfull); - DPRINTF(("ipsec4_common_input_cb: queue full; " - "proto %u packet dropped\n", sproto)); + DPRINTF(("%s: queue full; proto %u packet dropped\n", + __func__, sproto)); return ENOBUFS; } return 0; @@ -453,6 +460,12 @@ bad: m_freem(m); return error; } + +void +ipsec4_common_ctlinput(int cmd, struct sockaddr *sa, void *v, int proto) +{ + /* XXX nothing just yet */ +} #endif /* INET */ #ifdef INET6 @@ -465,7 +478,7 @@ ipsec6_common_input(struct mbuf **mp, int *offp, int proto) struct ip6_ext ip6e; if (*offp < sizeof(struct ip6_hdr)) { - DPRINTF(("ipsec6_common_input: bad offset %u\n", *offp)); + DPRINTF(("%s: bad offset %u\n", __func__, *offp)); return IPPROTO_DONE; } else if (*offp == sizeof(struct ip6_hdr)) { protoff = offsetof(struct ip6_hdr, ip6_nxt); @@ -482,13 +495,13 @@ ipsec6_common_input(struct mbuf **mp, int *offp, int proto) l = (ip6e.ip6e_len + 2) << 2; else l = (ip6e.ip6e_len + 1) << 3; - KASSERT(l > 0, ("ah6_input: l went zero or negative")); + IPSEC_ASSERT(l > 0, ("l went zero or negative")); } while (protoff + l < *offp); /* Malformed packet check */ if (protoff + l != *offp) { - DPRINTF(("ipsec6_common_input: bad packet header chain, " - "protoff %u, l %u, off %u\n", protoff, l, *offp)); + DPRINTF(("%s: bad packet header chain, protoff %u, " + "l %u, off %u\n", __func__, protoff, l, *offp)); IPSEC_ISTAT(proto, espstat.esps_hdrops, ahstat.ahs_hdrops, ipcompstat.ipcomps_hdrops); @@ -502,82 +515,6 @@ ipsec6_common_input(struct mbuf **mp, int *offp, int proto) return IPPROTO_DONE; } -void -esp6_ctlinput(int cmd, struct sockaddr *sa, void *d) -{ - if (sa->sa_family != AF_INET6 || - sa->sa_len != sizeof(struct sockaddr_in6)) - return; - if ((unsigned)cmd >= PRC_NCMDS) - return; - - /* if the parameter is from icmp6, decode it. */ - if (d != NULL) { - struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d; - struct mbuf *m = ip6cp->ip6c_m; - int off = ip6cp->ip6c_off; - - struct ip6ctlparam ip6cp1; - - /* - * Notify the error to all possible sockets via pfctlinput2. - * Since the upper layer information (such as protocol type, - * source and destination ports) is embedded in the encrypted - * data and might have been cut, we can't directly call - * an upper layer ctlinput function. However, the pcbnotify - * function will consider source and destination addresses - * as well as the flow info value, and may be able to find - * some PCB that should be notified. - * Although pfctlinput2 will call esp6_ctlinput(), there is - * no possibility of an infinite loop of function calls, - * because we don't pass the inner IPv6 header. - */ - bzero(&ip6cp1, sizeof(ip6cp1)); - ip6cp1.ip6c_src = ip6cp->ip6c_src; - pfctlinput2(cmd, sa, (void *)&ip6cp1); - - /* - * Then go to special cases that need ESP header information. - * XXX: We assume that when ip6 is non NULL, - * M and OFF are valid. - */ - - if (cmd == PRC_MSGSIZE) { - struct secasvar *sav; - u_int32_t spi; - int valid; - - /* check header length before using m_copydata */ - if (m->m_pkthdr.len < off + sizeof (struct esp)) - return; - m_copydata(m, off + offsetof(struct esp, esp_spi), - sizeof(u_int32_t), (caddr_t) &spi); - /* - * Check to see if we have a valid SA corresponding to - * the address in the ICMP message payload. - */ - sav = KEY_ALLOCSA((union sockaddr_union *)sa, - IPPROTO_ESP, spi); - valid = (sav != NULL); - if (sav) - KEY_FREESAV(&sav); - - /* XXX Further validation? */ - - /* - * Depending on whether the SA is "valid" and - * routing table size (mtudisc_{hi,lo}wat), we will: - * - recalcurate the new MTU and create the - * corresponding routing entry, or - * - ignore the MTU change notification. - */ - icmp6_mtudisc_update(ip6cp, valid); - } - } else { - /* we normally notify any pcb here */ - } -} - /* * IPsec input callback, called by the transform callback. Takes care of * filtering and other sanity checks on the processed packet. @@ -595,22 +532,20 @@ ipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip, int proto u_int8_t nxt8; int error, nest; - KASSERT(m != NULL, ("ipsec6_common_input_cb: null mbuf")); - KASSERT(sav != NULL, ("ipsec6_common_input_cb: null SA")); - KASSERT(sav->sah != NULL, ("ipsec6_common_input_cb: null SAH")); + IPSEC_ASSERT(m != NULL, ("null mbuf")); + IPSEC_ASSERT(sav != NULL, ("null SA")); + IPSEC_ASSERT(sav->sah != NULL, ("null SAH")); saidx = &sav->sah->saidx; af = saidx->dst.sa.sa_family; - KASSERT(af == AF_INET6, - ("ipsec6_common_input_cb: unexpected af %u", af)); + IPSEC_ASSERT(af == AF_INET6, ("unexpected af %u", af)); sproto = saidx->proto; - KASSERT(sproto == IPPROTO_ESP || sproto == IPPROTO_AH || + IPSEC_ASSERT(sproto == IPPROTO_ESP || sproto == IPPROTO_AH || sproto == IPPROTO_IPCOMP, - ("ipsec6_common_input_cb: unexpected security protocol %u", - sproto)); + ("unexpected security protocol %u", sproto)); /* Sanity check */ if (m == NULL) { - DPRINTF(("ipsec4_common_input_cb: null mbuf")); + DPRINTF(("%s: null mbuf", __func__)); IPSEC_ISTAT(sproto, espstat.esps_badkcr, ahstat.ahs_badkcr, ipcompstat.ipcomps_badkcr); error = EINVAL; @@ -621,8 +556,8 @@ ipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip, int proto if (m->m_len < sizeof(struct ip6_hdr) && (m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) { - DPRINTF(("ipsec_common_input_cb: processing failed " - "for SA %s/%08lx\n", ipsec_address(&sav->sah->saidx.dst), + DPRINTF(("%s: processing failed for SA %s/%08lx\n", + __func__, ipsec_address(&sav->sah->saidx.dst), (u_long) ntohl(sav->spi))); IPSEC_ISTAT(sproto, espstat.esps_hdrops, ahstat.ahs_hdrops, @@ -663,9 +598,9 @@ ipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip, int proto (saidx->proxy.sa.sa_family != AF_INET && saidx->proxy.sa.sa_family != 0)) { - DPRINTF(("ipsec_common_input_cb: inner " - "source address %s doesn't correspond to " - "expected proxy source %s, SA %s/%08lx\n", + DPRINTF(("%s: inner source address %s doesn't " + "correspond to expected proxy source %s, " + "SA %s/%08lx\n", __func__, inet_ntoa4(ipn.ip_src), ipsec_address(&saidx->proxy), ipsec_address(&saidx->dst), @@ -707,9 +642,9 @@ ipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip, int proto (saidx->proxy.sa.sa_family != AF_INET6 && saidx->proxy.sa.sa_family != 0)) { - DPRINTF(("ipsec_common_input_cb: inner " - "source address %s doesn't correspond to " - "expected proxy source %s, SA %s/%08lx\n", + DPRINTF(("%s: inner source address %s doesn't " + "correspond to expected proxy source %s, " + "SA %s/%08lx\n", __func__, ip6_sprintf(&ip6n.ip6_src), ipsec_address(&saidx->proxy), ipsec_address(&saidx->dst), @@ -735,8 +670,7 @@ ipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip, int proto mtag = m_tag_get(PACKET_TAG_IPSEC_IN_DONE, sizeof(struct tdb_ident), M_NOWAIT); if (mtag == NULL) { - DPRINTF(("ipsec_common_input_cb: failed to " - "get tag\n")); + DPRINTF(("%s: failed to get tag\n", __func__)); IPSEC_ISTAT(sproto, espstat.esps_hdrops, ahstat.ahs_hdrops, ipcompstat.ipcomps_hdrops); error = ENOMEM; @@ -750,7 +684,8 @@ ipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip, int proto m_tag_prepend(m, mtag); } else { - mt->m_tag_id = PACKET_TAG_IPSEC_IN_DONE; + if (mt != NULL) + mt->m_tag_id = PACKET_TAG_IPSEC_IN_DONE; /* XXX do we need to mark m_flags??? */ } @@ -800,4 +735,80 @@ bad: m_freem(m); return error; } + +void +esp6_ctlinput(int cmd, struct sockaddr *sa, void *d) +{ + if (sa->sa_family != AF_INET6 || + sa->sa_len != sizeof(struct sockaddr_in6)) + return; + if ((unsigned)cmd >= PRC_NCMDS) + return; + + /* if the parameter is from icmp6, decode it. */ + if (d != NULL) { + struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d; + struct mbuf *m = ip6cp->ip6c_m; + int off = ip6cp->ip6c_off; + + struct ip6ctlparam ip6cp1; + + /* + * Notify the error to all possible sockets via pfctlinput2. + * Since the upper layer information (such as protocol type, + * source and destination ports) is embedded in the encrypted + * data and might have been cut, we can't directly call + * an upper layer ctlinput function. However, the pcbnotify + * function will consider source and destination addresses + * as well as the flow info value, and may be able to find + * some PCB that should be notified. + * Although pfctlinput2 will call esp6_ctlinput(), there is + * no possibility of an infinite loop of function calls, + * because we don't pass the inner IPv6 header. + */ + bzero(&ip6cp1, sizeof(ip6cp1)); + ip6cp1.ip6c_src = ip6cp->ip6c_src; + pfctlinput2(cmd, sa, (void *)&ip6cp1); + + /* + * Then go to special cases that need ESP header information. + * XXX: We assume that when ip6 is non NULL, + * M and OFF are valid. + */ + + if (cmd == PRC_MSGSIZE) { + struct secasvar *sav; + u_int32_t spi; + int valid; + + /* check header length before using m_copydata */ + if (m->m_pkthdr.len < off + sizeof (struct esp)) + return; + m_copydata(m, off + offsetof(struct esp, esp_spi), + sizeof(u_int32_t), (caddr_t) &spi); + /* + * Check to see if we have a valid SA corresponding to + * the address in the ICMP message payload. + */ + sav = KEY_ALLOCSA((union sockaddr_union *)sa, + IPPROTO_ESP, spi); + valid = (sav != NULL); + if (sav) + KEY_FREESAV(&sav); + + /* XXX Further validation? */ + + /* + * Depending on whether the SA is "valid" and + * routing table size (mtudisc_{hi,lo}wat), we will: + * - recalcurate the new MTU and create the + * corresponding routing entry, or + * - ignore the MTU change notification. + */ + icmp6_mtudisc_update(ip6cp, valid); + } + } else { + /* we normally notify any pcb here */ + } +} #endif /* INET6 */ |