diff options
Diffstat (limited to 'sys/netipsec/ipsec_input.c')
-rw-r--r-- | sys/netipsec/ipsec_input.c | 118 |
1 files changed, 64 insertions, 54 deletions
diff --git a/sys/netipsec/ipsec_input.c b/sys/netipsec/ipsec_input.c index 66de530..8fb74ff 100644 --- a/sys/netipsec/ipsec_input.c +++ b/sys/netipsec/ipsec_input.c @@ -117,9 +117,10 @@ static void ipsec4_common_ctlinput(int, struct sockaddr *, void *, int); * and call the appropriate transform. The transform callback * takes care of further processing (like ingress filtering). */ -static int +int ipsec_common_input(struct mbuf *m, int skip, int protoff, int af, int sproto) { + char buf[INET6_ADDRSTRLEN]; union sockaddr_union dst_address; struct secasvar *sav; u_int32_t spi; @@ -194,6 +195,13 @@ ipsec_common_input(struct mbuf *m, int skip, int protoff, int af, int sproto) m_copydata(m, offsetof(struct ip6_hdr, ip6_dst), sizeof(struct in6_addr), (caddr_t) &dst_address.sin6.sin6_addr); + /* We keep addresses in SADB without embedded scope id */ + if (IN6_IS_SCOPE_LINKLOCAL(&dst_address.sin6.sin6_addr)) { + /* XXX: sa6_recoverscope() */ + dst_address.sin6.sin6_scope_id = + ntohs(dst_address.sin6.sin6_addr.s6_addr16[1]); + dst_address.sin6.sin6_addr.s6_addr16[1] = 0; + } break; #endif /* INET6 */ default: @@ -207,8 +215,8 @@ ipsec_common_input(struct mbuf *m, int skip, int protoff, int af, int sproto) sav = KEY_ALLOCSA(&dst_address, sproto, spi); if (sav == NULL) { DPRINTF(("%s: no key association found for SA %s/%08lx/%u\n", - __func__, ipsec_address(&dst_address), - (u_long) ntohl(spi), sproto)); + __func__, ipsec_address(&dst_address, buf, sizeof(buf)), + (u_long) ntohl(spi), sproto)); IPSEC_ISTAT(sproto, notdb); m_freem(m); return ENOENT; @@ -216,8 +224,8 @@ ipsec_common_input(struct mbuf *m, int skip, int protoff, int af, int sproto) if (sav->tdb_xform == NULL) { DPRINTF(("%s: attempted to use uninitialized SA %s/%08lx/%u\n", - __func__, ipsec_address(&dst_address), - (u_long) ntohl(spi), sproto)); + __func__, ipsec_address(&dst_address, buf, sizeof(buf)), + (u_long) ntohl(spi), sproto)); IPSEC_ISTAT(sproto, noxform); KEY_FREESAV(&sav); m_freem(m); @@ -234,28 +242,11 @@ ipsec_common_input(struct mbuf *m, int skip, int protoff, int af, int sproto) } #ifdef INET -/* - * Common input handler for IPv4 AH, ESP, and IPCOMP. - */ -int -ipsec4_common_input(struct mbuf *m, ...) -{ - va_list ap; - int off, nxt; - - va_start(ap, m); - off = va_arg(ap, int); - nxt = va_arg(ap, int); - va_end(ap); - - return ipsec_common_input(m, off, offsetof(struct ip, ip_p), - AF_INET, nxt); -} - void ah4_input(struct mbuf *m, int off) { - ipsec4_common_input(m, off, IPPROTO_AH); + ipsec_common_input(m, off, offsetof(struct ip, ip_p), + AF_INET, IPPROTO_AH); } void ah4_ctlinput(int cmd, struct sockaddr *sa, void *v) @@ -268,7 +259,8 @@ ah4_ctlinput(int cmd, struct sockaddr *sa, void *v) void esp4_input(struct mbuf *m, int off) { - ipsec4_common_input(m, off, IPPROTO_ESP); + ipsec_common_input(m, off, offsetof(struct ip, ip_p), + AF_INET, IPPROTO_ESP); } void esp4_ctlinput(int cmd, struct sockaddr *sa, void *v) @@ -281,7 +273,8 @@ esp4_ctlinput(int cmd, struct sockaddr *sa, void *v) void ipcomp4_input(struct mbuf *m, int off) { - ipsec4_common_input(m, off, IPPROTO_IPCOMP); + ipsec_common_input(m, off, offsetof(struct ip, ip_p), + AF_INET, IPPROTO_IPCOMP); } /* @@ -291,9 +284,10 @@ ipcomp4_input(struct mbuf *m, int off) * the processed packet. */ int -ipsec4_common_input_cb(struct mbuf *m, struct secasvar *sav, - int skip, int protoff, struct m_tag *mt) +ipsec4_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip, + int protoff) { + char buf[INET6_ADDRSTRLEN]; int prot, af, sproto, isr_prot; struct ip *ip; struct m_tag *mtag; @@ -332,8 +326,8 @@ ipsec4_common_input_cb(struct mbuf *m, struct secasvar *sav, */ if (m->m_len < skip && (m = m_pullup(m, skip)) == NULL) { DPRINTF(("%s: processing failed for SA %s/%08lx\n", - __func__, ipsec_address(&sav->sah->saidx.dst), - (u_long) ntohl(sav->spi))); + __func__, ipsec_address(&sav->sah->saidx.dst, + buf, sizeof(buf)), (u_long) ntohl(sav->spi))); IPSEC_ISTAT(sproto, hdrops); error = ENOBUFS; goto bad; @@ -356,6 +350,7 @@ ipsec4_common_input_cb(struct mbuf *m, struct secasvar *sav, ipsec_bpf(m, sav, AF_INET, ENC_IN|ENC_BEFORE); if ((error = ipsec_filter(&m, PFIL_IN, ENC_IN|ENC_BEFORE)) != 0) return (error); + ip = mtod(m, struct ip *); #endif /* DEV_ENC */ /* IP-in-IP encapsulation */ @@ -449,13 +444,9 @@ ipsec4_common_input_cb(struct mbuf *m, struct secasvar *sav, /* * Record what we've done to the packet (under what SA it was - * processed). If we've been passed an mtag, it means the packet - * was already processed by an ethernet/crypto combo card and - * thus has a tag attached with all the right information, but - * with a PACKET_TAG_IPSEC_IN_CRYPTO_DONE as opposed to - * PACKET_TAG_IPSEC_IN_DONE type; in that case, just change the type. + * processed). */ - if (mt == NULL && sproto != IPPROTO_IPCOMP) { + if (sproto != IPPROTO_IPCOMP) { mtag = m_tag_get(PACKET_TAG_IPSEC_IN_DONE, sizeof(struct tdb_ident), M_NOWAIT); if (mtag == NULL) { @@ -474,9 +465,6 @@ ipsec4_common_input_cb(struct mbuf *m, struct secasvar *sav, tdbi->alg_enc = sav->alg_enc; m_tag_prepend(m, mtag); - } else if (mt != NULL) { - mt->m_tag_id = PACKET_TAG_IPSEC_IN_DONE; - /* XXX do we need to mark m_flags??? */ } key_sa_recordxfer(sav, m); /* record data transfer */ @@ -593,15 +581,16 @@ ipsec6_common_input(struct mbuf **mp, int *offp, int proto) * filtering and other sanity checks on the processed packet. */ int -ipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip, int protoff, - struct m_tag *mt) +ipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip, + int protoff) { + char buf[INET6_ADDRSTRLEN]; int prot, af, sproto; struct ip6_hdr *ip6; struct m_tag *mtag; struct tdb_ident *tdbi; struct secasindex *saidx; - int nxt; + int nxt, isr_prot; u_int8_t nxt8; int error, nest; #ifdef notyet @@ -632,8 +621,8 @@ ipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip, int proto (m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) { DPRINTF(("%s: processing failed for SA %s/%08lx\n", - __func__, ipsec_address(&sav->sah->saidx.dst), - (u_long) ntohl(sav->spi))); + __func__, ipsec_address(&sav->sah->saidx.dst, buf, + sizeof(buf)), (u_long) ntohl(sav->spi))); IPSEC_ISTAT(sproto, hdrops); error = EACCES; @@ -738,13 +727,9 @@ ipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip, int proto /* * Record what we've done to the packet (under what SA it was - * processed). If we've been passed an mtag, it means the packet - * was already processed by an ethernet/crypto combo card and - * thus has a tag attached with all the right information, but - * with a PACKET_TAG_IPSEC_IN_CRYPTO_DONE as opposed to - * PACKET_TAG_IPSEC_IN_DONE type; in that case, just change the type. + * processed). */ - if (mt == NULL && sproto != IPPROTO_IPCOMP) { + if (sproto != IPPROTO_IPCOMP) { mtag = m_tag_get(PACKET_TAG_IPSEC_IN_DONE, sizeof(struct tdb_ident), M_NOWAIT); if (mtag == NULL) { @@ -763,10 +748,6 @@ ipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip, int proto tdbi->alg_enc = sav->alg_enc; m_tag_prepend(m, mtag); - } else { - if (mt != NULL) - mt->m_tag_id = PACKET_TAG_IPSEC_IN_DONE; - /* XXX do we need to mark m_flags??? */ } key_sa_recordxfer(sav, m); @@ -785,6 +766,35 @@ ipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip, int proto if ((error = ipsec_filter(&m, PFIL_IN, ENC_IN|ENC_AFTER)) != 0) return (error); #endif /* DEV_ENC */ + if (skip == 0) { + /* + * We stripped outer IPv6 header. + * Now we should requeue decrypted packet via netisr. + */ + switch (prot) { +#ifdef INET + case IPPROTO_IPIP: + isr_prot = NETISR_IP; + break; +#endif + case IPPROTO_IPV6: + isr_prot = NETISR_IPV6; + break; + default: + DPRINTF(("%s: cannot handle inner ip proto %d\n", + __func__, prot)); + IPSEC_ISTAT(sproto, nopf); + error = EPFNOSUPPORT; + goto bad; + } + error = netisr_queue_src(isr_prot, (uintptr_t)sav->spi, m); + if (error) { + IPSEC_ISTAT(sproto, qfull); + DPRINTF(("%s: queue full; proto %u packet dropped\n", + __func__, sproto)); + } + return (error); + } /* * See the end of ip6_input for this logic. * IPPROTO_IPV[46] case will be processed just like other ones |