diff options
author | itojun <itojun@FreeBSD.org> | 2000-07-04 16:35:15 +0000 |
---|---|---|
committer | itojun <itojun@FreeBSD.org> | 2000-07-04 16:35:15 +0000 |
commit | 5f4e854de19331a53788d6100bbcd42845056bc1 (patch) | |
tree | 3ff8c876a5868b103fb8713055d83e29a3fa38d5 /sys/netinet6/ah_input.c | |
parent | bdc16885232d771a99d7dfc247cd27a44cd061f9 (diff) | |
download | FreeBSD-src-5f4e854de19331a53788d6100bbcd42845056bc1.zip FreeBSD-src-5f4e854de19331a53788d6100bbcd42845056bc1.tar.gz |
sync with kame tree as of july00. tons of bug fixes/improvements.
API changes:
- additional IPv6 ioctls
- IPsec PF_KEY API was changed, it is mandatory to upgrade setkey(8).
(also syntax change)
Diffstat (limited to 'sys/netinet6/ah_input.c')
-rw-r--r-- | sys/netinet6/ah_input.c | 445 |
1 files changed, 358 insertions, 87 deletions
diff --git a/sys/netinet6/ah_input.c b/sys/netinet6/ah_input.c index e8aa77e..1f59bf9 100644 --- a/sys/netinet6/ah_input.c +++ b/sys/netinet6/ah_input.c @@ -1,3 +1,6 @@ +/* $FreeBSD$ */ +/* $KAME: ah_input.c,v 1.29 2000/05/29 08:33:53 itojun Exp $ */ + /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. @@ -25,8 +28,6 @@ * 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. - * - * $FreeBSD$ */ /* @@ -35,7 +36,6 @@ #include "opt_inet.h" #include "opt_inet6.h" -#include "opt_ipsec.h" #include <sys/param.h> #include <sys/systm.h> @@ -64,15 +64,17 @@ #endif #ifdef INET6 -#include <netinet6/ip6.h> +#include <netinet/ip6.h> #include <netinet6/ip6_var.h> -#include <netinet6/icmp6.h> +#include <netinet/icmp6.h> #endif #include <netinet6/ipsec.h> -#include <netinet6/ah.h> #ifdef INET6 #include <netinet6/ipsec6.h> +#endif +#include <netinet6/ah.h> +#ifdef INET6 #include <netinet6/ah6.h> #endif #include <netkey/key.h> @@ -83,19 +85,24 @@ #define KEYDEBUG(lev,arg) #endif -#include <netinet/ipprotosw.h> - #include <machine/stdarg.h> #include <net/net_osdep.h> +#define IPLEN_FLIPPED + #ifdef INET +#include <netinet/ipprotosw.h> extern struct ipprotosw inetsw[]; void -ah4_input(m, off, proto) +#if __STDC__ +ah4_input(struct mbuf *m, ...) +#else +ah4_input(m, va_alist) struct mbuf *m; - int off, proto; + va_dcl +#endif { struct ip *ip; struct ah *ah; @@ -108,12 +115,20 @@ ah4_input(m, off, proto) u_int16_t nxt; size_t hlen; int s; + int off, proto; + va_list ap; + va_start(ap, m); + off = va_arg(ap, int); + proto = va_arg(ap, int); + va_end(ap); + +#ifndef PULLDOWN_TEST if (m->m_len < off + sizeof(struct newah)) { m = m_pullup(m, off + sizeof(struct newah)); if (!m) { - printf("IPv4 AH input: can't pullup;" - "dropping the packet for simplicity\n"); + ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup;" + "dropping the packet for simplicity\n")); ipsecstat.in_inval++; goto fail; } @@ -121,6 +136,16 @@ ah4_input(m, off, proto) ip = mtod(m, struct ip *); ah = (struct ah *)(((caddr_t)ip) + off); +#else + ip = mtod(m, struct ip *); + IP6_EXTHDR_GET(ah, struct ah *, m, off, sizeof(struct newah)); + if (ah == NULL) { + ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup;" + "dropping the packet for simplicity\n")); + ipsecstat.in_inval++; + goto fail; + } +#endif nxt = ah->ah_nxt; #ifdef _IP_VHL hlen = IP_VHL_HL(ip->ip_vhl) << 2; @@ -134,9 +159,9 @@ ah4_input(m, off, proto) if ((sav = key_allocsa(AF_INET, (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst, IPPROTO_AH, spi)) == 0) { - printf("IPv4 AH input: no key association found for spi %u;" - "dropping the packet for simplicity\n", - (u_int32_t)ntohl(spi)); + ipseclog((LOG_WARNING, + "IPv4 AH input: no key association found for spi %u\n", + (u_int32_t)ntohl(spi))); ipsecstat.in_nosa++; goto fail; } @@ -144,17 +169,16 @@ ah4_input(m, off, proto) printf("DP ah4_input called to allocate SA:%p\n", sav)); if (sav->state != SADB_SASTATE_MATURE && sav->state != SADB_SASTATE_DYING) { - printf("IPv4 AH input: non-mature/dying SA found for spi %u; " - "dropping the packet for simplicity\n", - (u_int32_t)ntohl(spi)); + ipseclog((LOG_DEBUG, + "IPv4 AH input: non-mature/dying SA found for spi %u\n", + (u_int32_t)ntohl(spi))); ipsecstat.in_badspi++; goto fail; } if (sav->alg_auth == SADB_AALG_NONE) { - printf("IPv4 AH input: unspecified authentication algorithm " - "for spi %u;" - "dropping the packet for simplicity\n", - (u_int32_t)ntohl(spi)); + ipseclog((LOG_DEBUG, "IPv4 AH input: " + "unspecified authentication algorithm for spi %u\n", + (u_int32_t)ntohl(spi))); ipsecstat.in_badspi++; goto fail; } @@ -172,20 +196,49 @@ ah4_input(m, off, proto) sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4; + /* + * Here, we do not do "siz1 == siz". This is because the way + * RFC240[34] section 2 is written. They do not require truncation + * to 96 bits. + * For example, Microsoft IPsec stack attaches 160 bits of + * authentication data for both hmac-md5 and hmac-sha1. For hmac-sha1, + * 32 bits of padding is attached. + * + * There are two downsides to this specification. + * They have no real harm, however, they leave us fuzzy feeling. + * - if we attach more than 96 bits of authentication data onto AH, + * we will never notice about possible modification by rogue + * intermediate nodes. + * Since extra bits in AH checksum is never used, this constitutes + * no real issue, however, it is wacky. + * - even if the peer attaches big authentication data, we will never + * notice the difference, since longer authentication data will just + * work. + * + * We may need some clarification in the spec. + */ + if (siz1 < siz) { + ipseclog((LOG_NOTICE, "sum length too short in IPv4 AH input " + "(%lu, should be at least %lu): %s\n", + (u_long)siz1, (u_long)siz, + ipsec4_logpacketstr(ip, spi))); + ipsecstat.in_inval++; + goto fail; + } if ((ah->ah_len << 2) - sizoff != siz1) { - log(LOG_NOTICE, "sum length mismatch in IPv4 AH input " - "(%d should be %u): %s\n", - (ah->ah_len << 2) - sizoff, (unsigned int)siz1, - ipsec4_logpacketstr(ip, spi)); + ipseclog((LOG_NOTICE, "sum length mismatch in IPv4 AH input " + "(%d should be %lu): %s\n", + (ah->ah_len << 2) - sizoff, (u_long)siz1, + ipsec4_logpacketstr(ip, spi))); ipsecstat.in_inval++; goto fail; } +#ifndef PULLDOWN_TEST if (m->m_len < off + sizeof(struct ah) + sizoff + siz1) { m = m_pullup(m, off + sizeof(struct ah) + sizoff + siz1); if (!m) { - printf("IPv4 AH input: can't pullup;" - "dropping the packet for simplicity\n"); + ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup\n")); ipsecstat.in_inval++; goto fail; } @@ -193,6 +246,15 @@ ah4_input(m, off, proto) ip = mtod(m, struct ip *); ah = (struct ah *)(((caddr_t)ip) + off); } +#else + IP6_EXTHDR_GET(ah, struct ah *, m, off, + sizeof(struct ah) + sizoff + siz1); + if (ah == NULL) { + ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup\n")); + ipsecstat.in_inval++; + goto fail; + } +#endif } /* @@ -203,9 +265,9 @@ ah4_input(m, off, proto) ; /*okey*/ else { ipsecstat.in_ahreplay++; - log(LOG_AUTH, "replay packet in IPv4 AH input: %s %s\n", - ipsec4_logpacketstr(ip, spi), - ipsec_logsastr(sav)); + ipseclog((LOG_WARNING, + "replay packet in IPv4 AH input: %s %s\n", + ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav))); goto fail; } } @@ -216,12 +278,14 @@ ah4_input(m, off, proto) */ cksum = malloc(siz1, M_TEMP, M_NOWAIT); if (!cksum) { - printf("IPv4 AH input: couldn't alloc temporary region for cksum\n"); + ipseclog((LOG_DEBUG, "IPv4 AH input: " + "couldn't alloc temporary region for cksum\n")); ipsecstat.in_inval++; goto fail; } - + { +#if 1 /* * some of IP header fields are flipped to the host endian. * convert them back to network endian. VERY stupid. @@ -229,18 +293,21 @@ ah4_input(m, off, proto) ip->ip_len = htons(ip->ip_len + hlen); ip->ip_id = htons(ip->ip_id); ip->ip_off = htons(ip->ip_off); - if (ah4_calccksum(m, (caddr_t)cksum, algo, sav)) { +#endif + if (ah4_calccksum(m, (caddr_t)cksum, siz1, algo, sav)) { free(cksum, M_TEMP); ipsecstat.in_inval++; goto fail; } ipsecstat.in_ahhist[sav->alg_auth]++; +#if 1 /* * flip them back. */ ip->ip_len = ntohs(ip->ip_len) - hlen; ip->ip_id = ntohs(ip->ip_id); ip->ip_off = ntohs(ip->ip_off); +#endif } { @@ -255,9 +322,9 @@ ah4_input(m, off, proto) } if (bcmp(sumpos, cksum, siz) != 0) { - log(LOG_AUTH, "checksum mismatch in IPv4 AH input: %s %s\n", - ipsec4_logpacketstr(ip, spi), - ipsec_logsastr(sav)); + ipseclog((LOG_WARNING, + "checksum mismatch in IPv4 AH input: %s %s\n", + ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav))); free(cksum, M_TEMP); ipsecstat.in_ahauthfail++; goto fail; @@ -269,23 +336,66 @@ ah4_input(m, off, proto) m->m_flags |= M_AUTHIPHDR; m->m_flags |= M_AUTHIPDGM; - /* M_AUTH related flags might be cleared here in the future */ +#if 0 + /* + * looks okey, but we need more sanity check. + * XXX should elaborate. + */ + if (ah->ah_nxt == IPPROTO_IPIP || ah->ah_nxt == IPPROTO_IP) { + struct ip *nip; + size_t sizoff; + + sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4; + + if (m->m_len < off + sizeof(struct ah) + sizoff + siz1 + hlen) { + m = m_pullup(m, off + sizeof(struct ah) + + sizoff + siz1 + hlen); + if (!m) { + ipseclog((LOG_DEBUG, + "IPv4 AH input: can't pullup\n")); + ipsecstat.in_inval++; + goto fail; + } + } + + nip = (struct ip *)((u_char *)(ah + 1) + sizoff + siz1); + if (nip->ip_src.s_addr != ip->ip_src.s_addr + || nip->ip_dst.s_addr != ip->ip_dst.s_addr) { + m->m_flags &= ~M_AUTHIPHDR; + m->m_flags &= ~M_AUTHIPDGM; + } + } +#ifdef INET6 + else if (ah->ah_nxt == IPPROTO_IPV6) { + m->m_flags &= ~M_AUTHIPHDR; + m->m_flags &= ~M_AUTHIPDGM; + } +#endif /*INET6*/ +#endif /*0*/ if (m->m_flags & M_AUTHIPHDR && m->m_flags & M_AUTHIPDGM) { +#if 0 + ipseclog((LOG_DEBUG, + "IPv4 AH input: authentication succeess\n")); +#endif ipsecstat.in_ahauthsucc++; } else { - log(LOG_AUTH, "authentication failed in IPv4 AH input: %s %s\n", - ipsec4_logpacketstr(ip, spi), - ipsec_logsastr(sav)); + ipseclog((LOG_WARNING, + "authentication failed in IPv4 AH input: %s %s\n", + ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav))); ipsecstat.in_ahauthfail++; + goto fail; } /* * update sequence number. */ if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) { - (void)ipsec_updatereplay(ntohl(((struct newah *)ah)->ah_seq), sav); + if (ipsec_updatereplay(ntohl(((struct newah *)ah)->ah_seq), sav)) { + ipsecstat.in_ahreplay++; + goto fail; + } } /* was it transmitted over the IPsec tunnel SA? */ @@ -321,13 +431,22 @@ ah4_input(m, off, proto) ip_ecn_egress(ip4_ipsec_ecn, &tos, &ip->ip_tos); if (!key_checktunnelsanity(sav, AF_INET, (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst)) { - log(LOG_NOTICE, "ipsec tunnel address mismatch in IPv4 AH input: %s %s\n", - ipsec4_logpacketstr(ip, spi), - ipsec_logsastr(sav)); + ipseclog((LOG_NOTICE, "ipsec tunnel address mismatch " + "in IPv4 AH input: %s %s\n", + ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav))); ipsecstat.in_inval++; goto fail; } +#if 0 /* XXX should we call ipfw rather than ipsec_in_reject? */ + /* drop it if it does not match the default policy */ + if (ipsec4_in_reject(m, NULL)) { + ipsecstat.in_polvio++; + goto fail; + } +#endif + +#if 1 /* * Should the inner packet be considered authentic? * My current answer is: NO. @@ -349,6 +468,7 @@ ah4_input(m, off, proto) */ m->m_flags &= ~M_AUTHIPHDR; m->m_flags &= ~M_AUTHIPDGM; +#endif key_sa_recordxfer(sav, m); @@ -365,8 +485,6 @@ ah4_input(m, off, proto) } else { /* * strip off AH. - * We do deep-copy since KAME requires that - * the packet is placed in a single external mbuf. */ size_t stripsiz = 0; @@ -379,17 +497,62 @@ ah4_input(m, off, proto) } ip = mtod(m, struct ip *); +#ifndef PULLDOWN_TEST + /* + * We do deep-copy since KAME requires that + * the packet is placed in a single external mbuf. + */ ovbcopy((caddr_t)ip, (caddr_t)(((u_char *)ip) + stripsiz), off); m->m_data += stripsiz; m->m_len -= stripsiz; m->m_pkthdr.len -= stripsiz; +#else + /* + * even in m_pulldown case, we need to strip off AH so that + * we can compute checksum for multiple AH correctly. + */ + if (m->m_len >= stripsiz + off) { + ovbcopy((caddr_t)ip, ((caddr_t)ip) + stripsiz, off); + m->m_data += stripsiz; + m->m_len -= stripsiz; + m->m_pkthdr.len -= stripsiz; + } else { + /* + * this comes with no copy if the boundary is on + * cluster + */ + struct mbuf *n; + n = m_split(m, off, M_DONTWAIT); + if (n == NULL) { + /* m is retained by m_split */ + goto fail; + } + m_adj(n, stripsiz); + m_cat(m, n); + /* m_cat does not update m_pkthdr.len */ + m->m_pkthdr.len += n->m_pkthdr.len; + } +#endif + + if (m->m_len < sizeof(*ip)) { + m = m_pullup(m, sizeof(*ip)); + if (m == NULL) { + ipsecstat.in_inval++; + goto fail; + } + } ip = mtod(m, struct ip *); - /*ip_len is in host endian*/ +#ifdef IPLEN_FLIPPED ip->ip_len = ip->ip_len - stripsiz; +#else + ip->ip_len = htons(ntohs(ip->ip_len) - stripsiz); +#endif ip->ip_p = nxt; /* forget about IP hdr checksum, the check has already been passed */ + key_sa_recordxfer(sav, m); + if (nxt != IPPROTO_DONE) (*inetsw[ip_protox[nxt]].pr_input)(m, off, nxt); else @@ -436,18 +599,26 @@ ah6_input(mp, offp, proto) u_int16_t nxt; int s; +#ifndef PULLDOWN_TEST IP6_EXTHDR_CHECK(m, off, sizeof(struct ah), IPPROTO_DONE); - + ah = (struct ah *)(mtod(m, caddr_t) + off); +#else + IP6_EXTHDR_GET(ah, struct ah *, m, off, sizeof(struct newah)); + if (ah == NULL) { + ipseclog((LOG_DEBUG, "IPv6 AH input: can't pullup\n")); + ipsecstat.in_inval++; + return IPPROTO_DONE; + } +#endif ip6 = mtod(m, struct ip6_hdr *); - ah = (struct ah *)(((caddr_t)ip6) + off); - nxt = ah->ah_nxt; /* find the sassoc. */ spi = ah->ah_spi; if (ntohs(ip6->ip6_plen) == 0) { - printf("IPv6 AH input: AH with IPv6 jumbogram is not supported.\n"); + ipseclog((LOG_ERR, "IPv6 AH input: " + "AH with IPv6 jumbogram is not supported.\n")); ipsec6stat.in_inval++; goto fail; } @@ -455,9 +626,9 @@ ah6_input(mp, offp, proto) if ((sav = key_allocsa(AF_INET6, (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst, IPPROTO_AH, spi)) == 0) { - printf("IPv6 AH input: no key association found for spi %u;" - "dropping the packet for simplicity\n", - (u_int32_t)ntohl(spi)); + ipseclog((LOG_WARNING, + "IPv6 AH input: no key association found for spi %u\n", + (u_int32_t)ntohl(spi))); ipsec6stat.in_nosa++; goto fail; } @@ -465,17 +636,16 @@ ah6_input(mp, offp, proto) printf("DP ah6_input called to allocate SA:%p\n", sav)); if (sav->state != SADB_SASTATE_MATURE && sav->state != SADB_SASTATE_DYING) { - printf("IPv6 AH input: non-mature/dying SA found for spi %u; " - "dropping the packet for simplicity\n", - (u_int32_t)ntohl(spi)); + ipseclog((LOG_DEBUG, + "IPv6 AH input: non-mature/dying SA found for spi %u; ", + (u_int32_t)ntohl(spi))); ipsec6stat.in_badspi++; goto fail; } if (sav->alg_auth == SADB_AALG_NONE) { - printf("IPv6 AH input: unspecified authentication algorithm " - "for spi %u;" - "dropping the packet for simplicity\n", - (u_int32_t)ntohl(spi)); + ipseclog((LOG_DEBUG, "IPv6 AH input: " + "unspecified authentication algorithm for spi %u\n", + (u_int32_t)ntohl(spi))); ipsec6stat.in_badspi++; goto fail; } @@ -493,15 +663,38 @@ ah6_input(mp, offp, proto) sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4; + /* + * Here, we do not do "siz1 == siz". See ah4_input() for complete + * description. + */ + if (siz1 < siz) { + ipseclog((LOG_NOTICE, "sum length too short in IPv6 AH input " + "(%lu, should be at least %lu): %s\n", + (u_long)siz1, (u_long)siz, + ipsec6_logpacketstr(ip6, spi))); + ipsec6stat.in_inval++; + goto fail; + } if ((ah->ah_len << 2) - sizoff != siz1) { - log(LOG_NOTICE, "sum length mismatch in IPv6 AH input " - "(%d should be %u): %s\n", - (ah->ah_len << 2) - sizoff, (unsigned int)siz1, - ipsec6_logpacketstr(ip6, spi)); + ipseclog((LOG_NOTICE, "sum length mismatch in IPv6 AH input " + "(%d should be %lu): %s\n", + (ah->ah_len << 2) - sizoff, (u_long)siz1, + ipsec6_logpacketstr(ip6, spi))); ipsec6stat.in_inval++; goto fail; } +#ifndef PULLDOWN_TEST IP6_EXTHDR_CHECK(m, off, sizeof(struct ah) + sizoff + siz1, IPPROTO_DONE); +#else + IP6_EXTHDR_GET(ah, struct ah *, m, off, + sizeof(struct ah) + sizoff + siz1); + if (ah == NULL) { + ipseclog((LOG_NOTICE, "couldn't pullup gather IPv6 AH checksum part")); + ipsecstat.in_inval++; + m = NULL; + goto fail; + } +#endif } /* @@ -512,9 +705,10 @@ ah6_input(mp, offp, proto) ; /*okey*/ else { ipsec6stat.in_ahreplay++; - log(LOG_AUTH, "replay packet in IPv6 AH input: %s %s\n", - ipsec6_logpacketstr(ip6, spi), - ipsec_logsastr(sav)); + ipseclog((LOG_WARNING, + "replay packet in IPv6 AH input: %s %s\n", + ipsec6_logpacketstr(ip6, spi), + ipsec_logsastr(sav))); goto fail; } } @@ -525,12 +719,13 @@ ah6_input(mp, offp, proto) */ cksum = malloc(siz1, M_TEMP, M_NOWAIT); if (!cksum) { - printf("IPv6 AH input: couldn't alloc temporary region for cksum\n"); + ipseclog((LOG_DEBUG, "IPv6 AH input: " + "couldn't alloc temporary region for cksum\n")); ipsec6stat.in_inval++; goto fail; } - - if (ah6_calccksum(m, (caddr_t)cksum, algo, sav)) { + + if (ah6_calccksum(m, (caddr_t)cksum, siz1, algo, sav)) { free(cksum, M_TEMP); ipsec6stat.in_inval++; goto fail; @@ -549,9 +744,9 @@ ah6_input(mp, offp, proto) } if (bcmp(sumpos, cksum, siz) != 0) { - log(LOG_AUTH, "checksum mismatch in IPv6 AH input: %s %s\n", - ipsec6_logpacketstr(ip6, spi), - ipsec_logsastr(sav)); + ipseclog((LOG_WARNING, + "checksum mismatch in IPv6 AH input: %s %s\n", + ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav))); free(cksum, M_TEMP); ipsec6stat.in_ahauthfail++; goto fail; @@ -563,23 +758,58 @@ ah6_input(mp, offp, proto) m->m_flags |= M_AUTHIPHDR; m->m_flags |= M_AUTHIPDGM; - /* M_AUTH related flags might be cleared here in the future */ +#if 0 + /* + * looks okey, but we need more sanity check. + * XXX should elaborate. + */ + if (ah->ah_nxt == IPPROTO_IPV6) { + struct ip6_hdr *nip6; + size_t sizoff; + + sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4; + + IP6_EXTHDR_CHECK(m, off, sizeof(struct ah) + sizoff + siz1 + + sizeof(struct ip6_hdr), IPPROTO_DONE); + + nip6 = (struct ip6_hdr *)((u_char *)(ah + 1) + sizoff + siz1); + if (!IN6_ARE_ADDR_EQUAL(&nip6->ip6_src, &ip6->ip6_src) + || !IN6_ARE_ADDR_EQUAL(&nip6->ip6_dst, &ip6->ip6_dst)) { + m->m_flags &= ~M_AUTHIPHDR; + m->m_flags &= ~M_AUTHIPDGM; + } + } else if (ah->ah_nxt == IPPROTO_IPIP) { + m->m_flags &= ~M_AUTHIPHDR; + m->m_flags &= ~M_AUTHIPDGM; + } else if (ah->ah_nxt == IPPROTO_IP) { + m->m_flags &= ~M_AUTHIPHDR; + m->m_flags &= ~M_AUTHIPDGM; + } +#endif if (m->m_flags & M_AUTHIPHDR && m->m_flags & M_AUTHIPDGM) { +#if 0 + ipseclog((LOG_DEBUG, + "IPv6 AH input: authentication succeess\n")); +#endif ipsec6stat.in_ahauthsucc++; } else { - log(LOG_AUTH, "authentication failed in IPv6 AH input: %s %s\n", - ipsec6_logpacketstr(ip6, spi), - ipsec_logsastr(sav)); + ipseclog((LOG_WARNING, + "authentication failed in IPv6 AH input: %s %s\n", + ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav))); ipsec6stat.in_ahauthfail++; + goto fail; } /* * update sequence number. */ if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) { - (void)ipsec_updatereplay(ntohl(((struct newah *)ah)->ah_seq), sav); + if (ipsec_updatereplay(ntohl(((struct newah *)ah)->ah_seq), sav)) { + ipsec6stat.in_ahreplay++; + goto fail; + } } /* was it transmitted over the IPsec tunnel SA? */ @@ -619,19 +849,30 @@ ah6_input(mp, offp, proto) ip6_ecn_egress(ip6_ipsec_ecn, &flowinfo, &ip6->ip6_flow); if (!key_checktunnelsanity(sav, AF_INET6, (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst)) { - log(LOG_NOTICE, "ipsec tunnel address mismatch in IPv6 AH input: %s %s\n", - ipsec6_logpacketstr(ip6, spi), - ipsec_logsastr(sav)); + ipseclog((LOG_NOTICE, "ipsec tunnel address mismatch " + "in IPv6 AH input: %s %s\n", + ipsec6_logpacketstr(ip6, spi), + ipsec_logsastr(sav))); ipsec6stat.in_inval++; goto fail; } +#if 0 /* XXX should we call ipfw rather than ipsec_in_reject? */ + /* drop it if it does not match the default policy */ + if (ipsec6_in_reject(m, NULL)) { + ipsec6stat.in_polvio++; + goto fail; + } +#endif + +#if 1 /* * should the inner packet be considered authentic? * see comment in ah4_input(). */ m->m_flags &= ~M_AUTHIPHDR; m->m_flags &= ~M_AUTHIPDGM; +#endif key_sa_recordxfer(sav, m); @@ -648,8 +889,6 @@ ah6_input(mp, offp, proto) } else { /* * strip off AH. - * We do deep-copy since KAME requires that - * the packet is placed in a single mbuf. */ size_t stripsiz = 0; char *prvnxtp; @@ -671,13 +910,45 @@ ah6_input(mp, offp, proto) } ip6 = mtod(m, struct ip6_hdr *); - ovbcopy((caddr_t)ip6, (caddr_t)(((u_char *)ip6) + stripsiz), - off); +#ifndef PULLDOWN_TEST + /* + * We do deep-copy since KAME requires that + * the packet is placed in a single mbuf. + */ + ovbcopy((caddr_t)ip6, ((caddr_t)ip6) + stripsiz, off); m->m_data += stripsiz; m->m_len -= stripsiz; m->m_pkthdr.len -= stripsiz; +#else + /* + * even in m_pulldown case, we need to strip off AH so that + * we can compute checksum for multiple AH correctly. + */ + if (m->m_len >= stripsiz + off) { + ovbcopy((caddr_t)ip6, ((caddr_t)ip6) + stripsiz, off); + m->m_data += stripsiz; + m->m_len -= stripsiz; + m->m_pkthdr.len -= stripsiz; + } else { + /* + * this comes with no copy if the boundary is on + * cluster + */ + struct mbuf *n; + n = m_split(m, off, M_DONTWAIT); + if (n == NULL) { + /* m is retained by m_split */ + goto fail; + } + m_adj(n, stripsiz); + m_cat(m, n); + /* m_cat does not update m_pkthdr.len */ + m->m_pkthdr.len += n->m_pkthdr.len; + } +#endif ip6 = mtod(m, struct ip6_hdr *); + /* XXX jumbogram */ ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - stripsiz); key_sa_recordxfer(sav, m); |