1aaea26efSSam Leffler /* $OpenBSD: ipsec_input.c,v 1.63 2003/02/20 18:35:43 deraadt Exp $ */ 2c398230bSWarner Losh /*- 3aaea26efSSam Leffler * The authors of this code are John Ioannidis (ji@tla.org), 4aaea26efSSam Leffler * Angelos D. Keromytis (kermit@csd.uch.gr) and 5aaea26efSSam Leffler * Niels Provos (provos@physnet.uni-hamburg.de). 6aaea26efSSam Leffler * 7aaea26efSSam Leffler * This code was written by John Ioannidis for BSD/OS in Athens, Greece, 8aaea26efSSam Leffler * in November 1995. 9aaea26efSSam Leffler * 10aaea26efSSam Leffler * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996, 11aaea26efSSam Leffler * by Angelos D. Keromytis. 12aaea26efSSam Leffler * 13aaea26efSSam Leffler * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis 14aaea26efSSam Leffler * and Niels Provos. 15aaea26efSSam Leffler * 16aaea26efSSam Leffler * Additional features in 1999 by Angelos D. Keromytis. 17aaea26efSSam Leffler * 18aaea26efSSam Leffler * Copyright (C) 1995, 1996, 1997, 1998, 1999 by John Ioannidis, 19aaea26efSSam Leffler * Angelos D. Keromytis and Niels Provos. 20aaea26efSSam Leffler * Copyright (c) 2001, Angelos D. Keromytis. 21fcf59617SAndrey V. Elsukov * Copyright (c) 2016 Andrey V. Elsukov <ae@FreeBSD.org> 22aaea26efSSam Leffler * 23aaea26efSSam Leffler * Permission to use, copy, and modify this software with or without fee 24aaea26efSSam Leffler * is hereby granted, provided that this entire notice is included in 25aaea26efSSam Leffler * all copies of any software which is or includes a copy or 26aaea26efSSam Leffler * modification of this software. 27aaea26efSSam Leffler * You may use this code under the GNU public license if you so wish. Please 28aaea26efSSam Leffler * contribute changes back to the authors under this freer than GPL license 29aaea26efSSam Leffler * so that we may further the use of strong encryption without limitations to 30aaea26efSSam Leffler * all. 31aaea26efSSam Leffler * 32aaea26efSSam Leffler * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR 33aaea26efSSam Leffler * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY 34aaea26efSSam Leffler * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE 35aaea26efSSam Leffler * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR 36aaea26efSSam Leffler * PURPOSE. 37aaea26efSSam Leffler */ 3888768458SSam Leffler 3988768458SSam Leffler /* 4088768458SSam Leffler * IPsec input processing. 4188768458SSam Leffler */ 4288768458SSam Leffler 43fcf59617SAndrey V. Elsukov #include <sys/cdefs.h> 4488768458SSam Leffler #include "opt_inet.h" 4588768458SSam Leffler #include "opt_inet6.h" 4688768458SSam Leffler #include "opt_ipsec.h" 4788768458SSam Leffler 4888768458SSam Leffler #include <sys/param.h> 4988768458SSam Leffler #include <sys/systm.h> 5088768458SSam Leffler #include <sys/malloc.h> 5188768458SSam Leffler #include <sys/mbuf.h> 5288768458SSam Leffler #include <sys/domain.h> 5388768458SSam Leffler #include <sys/protosw.h> 5488768458SSam Leffler #include <sys/socket.h> 5588768458SSam Leffler #include <sys/errno.h> 56ef91a976SAndrey V. Elsukov #include <sys/hhook.h> 5788768458SSam Leffler #include <sys/syslog.h> 5888768458SSam Leffler 5988768458SSam Leffler #include <net/if.h> 6076039bc8SGleb Smirnoff #include <net/if_var.h> 61ef91a976SAndrey V. Elsukov #include <net/if_enc.h> 623d0d5b21SJustin Hibbits #include <net/if_private.h> 6388768458SSam Leffler #include <net/netisr.h> 64eddfbb76SRobert Watson #include <net/vnet.h> 6588768458SSam Leffler 6688768458SSam Leffler #include <netinet/in.h> 67e68b3792SGleb Smirnoff #include <netinet/in_pcb.h> 6888768458SSam Leffler #include <netinet/in_systm.h> 6988768458SSam Leffler #include <netinet/ip.h> 7088768458SSam Leffler #include <netinet/ip_var.h> 71d9d59bb1SWojciech Macek #include <netinet/ip_icmp.h> 7288768458SSam Leffler #include <netinet/in_var.h> 73d9d59bb1SWojciech Macek #include <netinet/tcp_var.h> 7488768458SSam Leffler 7588768458SSam Leffler #include <netinet/ip6.h> 7688768458SSam Leffler #ifdef INET6 7788768458SSam Leffler #include <netinet6/ip6_var.h> 7888768458SSam Leffler #endif 7988768458SSam Leffler #include <netinet/in_pcb.h> 8088768458SSam Leffler #ifdef INET6 8188768458SSam Leffler #include <netinet/icmp6.h> 8288768458SSam Leffler #endif 8388768458SSam Leffler 8488768458SSam Leffler #include <netipsec/ipsec.h> 8588768458SSam Leffler #ifdef INET6 8688768458SSam Leffler #include <netipsec/ipsec6.h> 8788768458SSam Leffler #endif 88809fef29SGleb Smirnoff #include <netipsec/ipsec_support.h> 8988768458SSam Leffler #include <netipsec/ah_var.h> 9088768458SSam Leffler #include <netipsec/esp.h> 9188768458SSam Leffler #include <netipsec/esp_var.h> 9288768458SSam Leffler #include <netipsec/ipcomp_var.h> 93*ef2a572bSKonstantin Belousov #include <netipsec/ipsec_offload.h> 9488768458SSam Leffler 9588768458SSam Leffler #include <netipsec/key.h> 9688768458SSam Leffler #include <netipsec/keydb.h> 97fcf59617SAndrey V. Elsukov #include <netipsec/key_debug.h> 9888768458SSam Leffler 9988768458SSam Leffler #include <netipsec/xform.h> 10088768458SSam Leffler 10188768458SSam Leffler #include <machine/in_cksum.h> 10288768458SSam Leffler #include <machine/stdarg.h> 10388768458SSam Leffler 104a04d64d8SAndrey V. Elsukov #define IPSEC_ISTAT(proto, name) do { \ 105a04d64d8SAndrey V. Elsukov if ((proto) == IPPROTO_ESP) \ 106a04d64d8SAndrey V. Elsukov ESPSTAT_INC(esps_##name); \ 107a04d64d8SAndrey V. Elsukov else if ((proto) == IPPROTO_AH) \ 108a04d64d8SAndrey V. Elsukov AHSTAT_INC(ahs_##name); \ 109a04d64d8SAndrey V. Elsukov else \ 110a04d64d8SAndrey V. Elsukov IPCOMPSTAT_INC(ipcomps_##name); \ 111a04d64d8SAndrey V. Elsukov } while (0) 11288768458SSam Leffler 11388768458SSam Leffler /* 11488768458SSam Leffler * ipsec_common_input gets called when an IPsec-protected packet 11594294cadSThomas Quinot * is received by IPv4 or IPv6. Its job is to find the right SA 116ceda1e7cSBjoern A. Zeeb * and call the appropriate transform. The transform callback 11788768458SSam Leffler * takes care of further processing (like ingress filtering). 11888768458SSam Leffler */ 119fcf59617SAndrey V. Elsukov static int 12088768458SSam Leffler ipsec_common_input(struct mbuf *m, int skip, int protoff, int af, int sproto) 12188768458SSam Leffler { 1227f1f6591SAndrey V. Elsukov IPSEC_DEBUG_DECLARE(char buf[IPSEC_ADDRSTRLEN]); 12388768458SSam Leffler union sockaddr_union dst_address; 12488768458SSam Leffler struct secasvar *sav; 125fcf59617SAndrey V. Elsukov uint32_t spi; 1266464079fSSam Leffler int error; 12788768458SSam Leffler 128a04d64d8SAndrey V. Elsukov IPSEC_ISTAT(sproto, input); 12988768458SSam Leffler 1309ffa9677SSam Leffler IPSEC_ASSERT(m != NULL, ("null packet")); 13188768458SSam Leffler 132f4760821SBjoern A. Zeeb IPSEC_ASSERT(sproto == IPPROTO_ESP || sproto == IPPROTO_AH || 133f4760821SBjoern A. Zeeb sproto == IPPROTO_IPCOMP, 134f4760821SBjoern A. Zeeb ("unexpected security protocol %u", sproto)); 135f4760821SBjoern A. Zeeb 136603724d3SBjoern A. Zeeb if ((sproto == IPPROTO_ESP && !V_esp_enable) || 137603724d3SBjoern A. Zeeb (sproto == IPPROTO_AH && !V_ah_enable) || 138603724d3SBjoern A. Zeeb (sproto == IPPROTO_IPCOMP && !V_ipcomp_enable)) { 13988768458SSam Leffler m_freem(m); 140a04d64d8SAndrey V. Elsukov IPSEC_ISTAT(sproto, pdrops); 14188768458SSam Leffler return EOPNOTSUPP; 14288768458SSam Leffler } 14388768458SSam Leffler 14488768458SSam Leffler if (m->m_pkthdr.len - skip < 2 * sizeof (u_int32_t)) { 14588768458SSam Leffler m_freem(m); 146a04d64d8SAndrey V. Elsukov IPSEC_ISTAT(sproto, hdrops); 1479ffa9677SSam Leffler DPRINTF(("%s: packet too small\n", __func__)); 14888768458SSam Leffler return EINVAL; 14988768458SSam Leffler } 15088768458SSam Leffler 15188768458SSam Leffler /* Retrieve the SPI from the relevant IPsec header */ 15288768458SSam Leffler if (sproto == IPPROTO_ESP) 15388768458SSam Leffler m_copydata(m, skip, sizeof(u_int32_t), (caddr_t) &spi); 15488768458SSam Leffler else if (sproto == IPPROTO_AH) 15588768458SSam Leffler m_copydata(m, skip + sizeof(u_int32_t), sizeof(u_int32_t), 15688768458SSam Leffler (caddr_t) &spi); 15788768458SSam Leffler else if (sproto == IPPROTO_IPCOMP) { 15888768458SSam Leffler u_int16_t cpi; 15988768458SSam Leffler m_copydata(m, skip + sizeof(u_int16_t), sizeof(u_int16_t), 16088768458SSam Leffler (caddr_t) &cpi); 16188768458SSam Leffler spi = ntohl(htons(cpi)); 16288768458SSam Leffler } 16388768458SSam Leffler 16488768458SSam Leffler /* 16588768458SSam Leffler * Find the SA and (indirectly) call the appropriate 16688768458SSam Leffler * kernel crypto routine. The resulting mbuf chain is a valid 16788768458SSam Leffler * IP packet ready to go through input processing. 16888768458SSam Leffler */ 16988768458SSam Leffler bzero(&dst_address, sizeof (dst_address)); 17088768458SSam Leffler dst_address.sa.sa_family = af; 17188768458SSam Leffler switch (af) { 17288768458SSam Leffler #ifdef INET 17388768458SSam Leffler case AF_INET: 17488768458SSam Leffler dst_address.sin.sin_len = sizeof(struct sockaddr_in); 17588768458SSam Leffler m_copydata(m, offsetof(struct ip, ip_dst), 17688768458SSam Leffler sizeof(struct in_addr), 17788768458SSam Leffler (caddr_t) &dst_address.sin.sin_addr); 17888768458SSam Leffler break; 17988768458SSam Leffler #endif /* INET */ 18088768458SSam Leffler #ifdef INET6 18188768458SSam Leffler case AF_INET6: 18288768458SSam Leffler dst_address.sin6.sin6_len = sizeof(struct sockaddr_in6); 18388768458SSam Leffler m_copydata(m, offsetof(struct ip6_hdr, ip6_dst), 18488768458SSam Leffler sizeof(struct in6_addr), 18588768458SSam Leffler (caddr_t) &dst_address.sin6.sin6_addr); 1861ae800e7SAndrey V. Elsukov /* We keep addresses in SADB without embedded scope id */ 1871ae800e7SAndrey V. Elsukov if (IN6_IS_SCOPE_LINKLOCAL(&dst_address.sin6.sin6_addr)) { 1881ae800e7SAndrey V. Elsukov /* XXX: sa6_recoverscope() */ 1891ae800e7SAndrey V. Elsukov dst_address.sin6.sin6_scope_id = 1901ae800e7SAndrey V. Elsukov ntohs(dst_address.sin6.sin6_addr.s6_addr16[1]); 1911ae800e7SAndrey V. Elsukov dst_address.sin6.sin6_addr.s6_addr16[1] = 0; 1921ae800e7SAndrey V. Elsukov } 19388768458SSam Leffler break; 19488768458SSam Leffler #endif /* INET6 */ 19588768458SSam Leffler default: 1969ffa9677SSam Leffler DPRINTF(("%s: unsupported protocol family %u\n", __func__, af)); 19788768458SSam Leffler m_freem(m); 198a04d64d8SAndrey V. Elsukov IPSEC_ISTAT(sproto, nopf); 19988768458SSam Leffler return EPFNOSUPPORT; 20088768458SSam Leffler } 20188768458SSam Leffler 20288768458SSam Leffler /* NB: only pass dst since key_allocsa follows RFC2401 */ 203fcf59617SAndrey V. Elsukov sav = key_allocsa(&dst_address, sproto, spi); 20488768458SSam Leffler if (sav == NULL) { 2059ffa9677SSam Leffler DPRINTF(("%s: no key association found for SA %s/%08lx/%u\n", 206962ac6c7SAndrey V. Elsukov __func__, ipsec_address(&dst_address, buf, sizeof(buf)), 20788768458SSam Leffler (u_long) ntohl(spi), sproto)); 208a04d64d8SAndrey V. Elsukov IPSEC_ISTAT(sproto, notdb); 20988768458SSam Leffler m_freem(m); 21088768458SSam Leffler return ENOENT; 21188768458SSam Leffler } 21288768458SSam Leffler 21388768458SSam Leffler if (sav->tdb_xform == NULL) { 2149ffa9677SSam Leffler DPRINTF(("%s: attempted to use uninitialized SA %s/%08lx/%u\n", 215962ac6c7SAndrey V. Elsukov __func__, ipsec_address(&dst_address, buf, sizeof(buf)), 21688768458SSam Leffler (u_long) ntohl(spi), sproto)); 217a04d64d8SAndrey V. Elsukov IPSEC_ISTAT(sproto, noxform); 218fcf59617SAndrey V. Elsukov key_freesav(&sav); 21988768458SSam Leffler m_freem(m); 22088768458SSam Leffler return ENXIO; 22188768458SSam Leffler } 22288768458SSam Leffler 22388768458SSam Leffler /* 22488768458SSam Leffler * Call appropriate transform and return -- callback takes care of 22588768458SSam Leffler * everything else. 22688768458SSam Leffler */ 22788768458SSam Leffler error = (*sav->tdb_xform->xf_input)(m, sav, skip, protoff); 228fcf59617SAndrey V. Elsukov return (error); 22988768458SSam Leffler } 23088768458SSam Leffler 23188768458SSam Leffler #ifdef INET 232fcf59617SAndrey V. Elsukov /* 233fcf59617SAndrey V. Elsukov * IPSEC_INPUT() method implementation for IPv4. 234fcf59617SAndrey V. Elsukov * 0 - Permitted by inbound security policy for further processing. 235fcf59617SAndrey V. Elsukov * EACCES - Forbidden by inbound security policy. 236fcf59617SAndrey V. Elsukov * EINPROGRESS - consumed by IPsec. 237fcf59617SAndrey V. Elsukov */ 2388f5a8818SKevin Lo int 239fcf59617SAndrey V. Elsukov ipsec4_input(struct mbuf *m, int offset, int proto) 240e8539d32SSam Leffler { 241*ef2a572bSKonstantin Belousov int error; 242*ef2a572bSKonstantin Belousov 243*ef2a572bSKonstantin Belousov error = ipsec_accel_input(m, offset, proto); 244*ef2a572bSKonstantin Belousov if (error != ENXIO) 245*ef2a572bSKonstantin Belousov return (error); 2468f5a8818SKevin Lo 247fcf59617SAndrey V. Elsukov switch (proto) { 248fcf59617SAndrey V. Elsukov case IPPROTO_AH: 249fcf59617SAndrey V. Elsukov case IPPROTO_ESP: 250fcf59617SAndrey V. Elsukov case IPPROTO_IPCOMP: 251fcf59617SAndrey V. Elsukov /* Do inbound IPsec processing for AH/ESP/IPCOMP */ 252fcf59617SAndrey V. Elsukov ipsec_common_input(m, offset, 253fcf59617SAndrey V. Elsukov offsetof(struct ip, ip_p), AF_INET, proto); 254fcf59617SAndrey V. Elsukov return (EINPROGRESS); /* mbuf consumed by IPsec */ 255fcf59617SAndrey V. Elsukov default: 256fcf59617SAndrey V. Elsukov /* 257fcf59617SAndrey V. Elsukov * Protocols with further headers get their IPsec treatment 258fcf59617SAndrey V. Elsukov * within the protocol specific processing. 259fcf59617SAndrey V. Elsukov */ 260489482e2SGleb Smirnoff switch (proto) { 261489482e2SGleb Smirnoff case IPPROTO_ICMP: 262489482e2SGleb Smirnoff case IPPROTO_IGMP: 263489482e2SGleb Smirnoff case IPPROTO_IPV4: 264489482e2SGleb Smirnoff case IPPROTO_IPV6: 265489482e2SGleb Smirnoff case IPPROTO_RSVP: 266489482e2SGleb Smirnoff case IPPROTO_GRE: 267489482e2SGleb Smirnoff case IPPROTO_MOBILE: 268489482e2SGleb Smirnoff case IPPROTO_ETHERIP: 269489482e2SGleb Smirnoff case IPPROTO_PIM: 270489482e2SGleb Smirnoff case IPPROTO_SCTP: 271489482e2SGleb Smirnoff break; 272489482e2SGleb Smirnoff default: 273fcf59617SAndrey V. Elsukov return (0); 274489482e2SGleb Smirnoff } 275fcf59617SAndrey V. Elsukov }; 276fcf59617SAndrey V. Elsukov /* 277fcf59617SAndrey V. Elsukov * Enforce IPsec policy checking if we are seeing last header. 278fcf59617SAndrey V. Elsukov */ 279fcf59617SAndrey V. Elsukov if (ipsec4_in_reject(m, NULL) != 0) { 280fcf59617SAndrey V. Elsukov /* Forbidden by inbound security policy */ 281fcf59617SAndrey V. Elsukov m_freem(m); 282fcf59617SAndrey V. Elsukov return (EACCES); 283e8539d32SSam Leffler } 284fcf59617SAndrey V. Elsukov return (0); 285e8539d32SSam Leffler } 286e8539d32SSam Leffler 287d9d59bb1SWojciech Macek int 288fcb3f813SGleb Smirnoff ipsec4_ctlinput(ipsec_ctlinput_param_t param) 289d9d59bb1SWojciech Macek { 290fcb3f813SGleb Smirnoff struct icmp *icp = param.icmp; 291fcb3f813SGleb Smirnoff struct ip *ip = &icp->icmp_ip; 292fcb3f813SGleb Smirnoff struct sockaddr_in icmpsrc = { 293fcb3f813SGleb Smirnoff .sin_len = sizeof(struct sockaddr_in), 294fcb3f813SGleb Smirnoff .sin_family = AF_INET, 295fcb3f813SGleb Smirnoff .sin_addr = ip->ip_dst, 296fcb3f813SGleb Smirnoff }; 297d9d59bb1SWojciech Macek struct in_conninfo inc; 298d9d59bb1SWojciech Macek struct secasvar *sav; 299d9d59bb1SWojciech Macek uint32_t pmtu, spi; 300863871d3SKornel Dulęba uint32_t max_pmtu; 30110eb2a2bSMark Johnston uint8_t proto; 302d9d59bb1SWojciech Macek 303d9d59bb1SWojciech Macek pmtu = ntohs(icp->icmp_nextmtu); 304d9d59bb1SWojciech Macek 305d9d59bb1SWojciech Macek if (pmtu < V_ip4_ipsec_min_pmtu) 306d9d59bb1SWojciech Macek return (EINVAL); 307d9d59bb1SWojciech Macek 30810eb2a2bSMark Johnston proto = ip->ip_p; 30910eb2a2bSMark Johnston if (proto != IPPROTO_ESP && proto != IPPROTO_AH && 31010eb2a2bSMark Johnston proto != IPPROTO_IPCOMP) 31110eb2a2bSMark Johnston return (EINVAL); 31210eb2a2bSMark Johnston 313d9d59bb1SWojciech Macek memcpy(&spi, (caddr_t)ip + (ip->ip_hl << 2), sizeof(spi)); 314fcb3f813SGleb Smirnoff sav = key_allocsa((union sockaddr_union *)&icmpsrc, proto, spi); 315d9d59bb1SWojciech Macek if (sav == NULL) 316d9d59bb1SWojciech Macek return (ENOENT); 317d9d59bb1SWojciech Macek 318d9d59bb1SWojciech Macek key_freesav(&sav); 319d9d59bb1SWojciech Macek 320d9d59bb1SWojciech Macek memset(&inc, 0, sizeof(inc)); 321fcb3f813SGleb Smirnoff inc.inc_faddr = ip->ip_dst; 322863871d3SKornel Dulęba 323863871d3SKornel Dulęba /* Update pmtu only if its smaller than the current one. */ 324863871d3SKornel Dulęba max_pmtu = tcp_hc_getmtu(&inc); 325863871d3SKornel Dulęba if (max_pmtu == 0) 326863871d3SKornel Dulęba max_pmtu = tcp_maxmtu(&inc, NULL); 327863871d3SKornel Dulęba 328863871d3SKornel Dulęba if (pmtu < max_pmtu) 329d9d59bb1SWojciech Macek tcp_hc_updatemtu(&inc, pmtu); 330863871d3SKornel Dulęba 331d9d59bb1SWojciech Macek return (0); 332d9d59bb1SWojciech Macek } 333d9d59bb1SWojciech Macek 33488768458SSam Leffler /* 33588768458SSam Leffler * IPsec input callback for INET protocols. 33688768458SSam Leffler * This routine is called as the transform callback. 33788768458SSam Leffler * Takes care of filtering and other sanity checks on 33888768458SSam Leffler * the processed packet. 33988768458SSam Leffler */ 34088768458SSam Leffler int 341f0514a8bSAndrey V. Elsukov ipsec4_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip, 342f0514a8bSAndrey V. Elsukov int protoff) 34388768458SSam Leffler { 3447f1f6591SAndrey V. Elsukov IPSEC_DEBUG_DECLARE(char buf[IPSEC_ADDRSTRLEN]); 345f82eb2a6SJohn Baldwin struct epoch_tracker et; 346ef91a976SAndrey V. Elsukov struct ipsec_ctx_data ctx; 347fcf59617SAndrey V. Elsukov struct xform_history *xh; 34888768458SSam Leffler struct secasindex *saidx; 349fcf59617SAndrey V. Elsukov struct m_tag *mtag; 350fcf59617SAndrey V. Elsukov struct ip *ip; 351fcf59617SAndrey V. Elsukov int error, prot, af, sproto, isr_prot; 35288768458SSam Leffler 3539ffa9677SSam Leffler IPSEC_ASSERT(sav != NULL, ("null SA")); 3549ffa9677SSam Leffler IPSEC_ASSERT(sav->sah != NULL, ("null SAH")); 35588768458SSam Leffler saidx = &sav->sah->saidx; 35688768458SSam Leffler af = saidx->dst.sa.sa_family; 3579ffa9677SSam Leffler IPSEC_ASSERT(af == AF_INET, ("unexpected af %u", af)); 35888768458SSam Leffler sproto = saidx->proto; 3599ffa9677SSam Leffler IPSEC_ASSERT(sproto == IPPROTO_ESP || sproto == IPPROTO_AH || 36088768458SSam Leffler sproto == IPPROTO_IPCOMP, 3619ffa9677SSam Leffler ("unexpected security protocol %u", sproto)); 36288768458SSam Leffler 36388768458SSam Leffler if (skip != 0) { 364d2bffb14SGleb Smirnoff /* 365d2bffb14SGleb Smirnoff * Fix IPv4 header 366d2bffb14SGleb Smirnoff */ 36788768458SSam Leffler if (m->m_len < skip && (m = m_pullup(m, skip)) == NULL) { 3689ffa9677SSam Leffler DPRINTF(("%s: processing failed for SA %s/%08lx\n", 369962ac6c7SAndrey V. Elsukov __func__, ipsec_address(&sav->sah->saidx.dst, 370962ac6c7SAndrey V. Elsukov buf, sizeof(buf)), (u_long) ntohl(sav->spi))); 371a04d64d8SAndrey V. Elsukov IPSEC_ISTAT(sproto, hdrops); 37288768458SSam Leffler error = ENOBUFS; 373590d0715SMateusz Guzik goto bad_noepoch; 37488768458SSam Leffler } 37588768458SSam Leffler 37688768458SSam Leffler ip = mtod(m, struct ip *); 37788768458SSam Leffler ip->ip_len = htons(m->m_pkthdr.len); 37888768458SSam Leffler ip->ip_sum = 0; 37988768458SSam Leffler ip->ip_sum = in_cksum(m, ip->ip_hl << 2); 38088768458SSam Leffler } else { 38188768458SSam Leffler ip = mtod(m, struct ip *); 38288768458SSam Leffler } 38388768458SSam Leffler prot = ip->ip_p; 384fcf59617SAndrey V. Elsukov /* 385fcf59617SAndrey V. Elsukov * Check that we have NAT-T enabled and apply transport mode 386fcf59617SAndrey V. Elsukov * decapsulation NAT procedure (RFC3948). 387fcf59617SAndrey V. Elsukov * Do this before invoking into the PFIL. 388fcf59617SAndrey V. Elsukov */ 389fcf59617SAndrey V. Elsukov if (sav->natt != NULL && 390fcf59617SAndrey V. Elsukov (prot == IPPROTO_UDP || prot == IPPROTO_TCP)) 391fcf59617SAndrey V. Elsukov udp_ipsec_adjust_cksum(m, sav, prot, skip); 39288768458SSam Leffler 393590d0715SMateusz Guzik /* 394590d0715SMateusz Guzik * Needed for ipsec_run_hooks and netisr_queue_src 395590d0715SMateusz Guzik */ 396590d0715SMateusz Guzik NET_EPOCH_ENTER(et); 397590d0715SMateusz Guzik 3981a01e0e7SAndrey V. Elsukov IPSEC_INIT_CTX(&ctx, &m, NULL, sav, AF_INET, IPSEC_ENC_BEFORE); 399ef91a976SAndrey V. Elsukov if ((error = ipsec_run_hhooks(&ctx, HHOOK_TYPE_IPSEC_IN)) != 0) 400ef91a976SAndrey V. Elsukov goto bad; 401fcf59617SAndrey V. Elsukov ip = mtod(m, struct ip *); /* update pointer */ 402aaf2cfc0SVANHULLEBUS Yvan 40388768458SSam Leffler /* IP-in-IP encapsulation */ 404a28b277aSAndrey V. Elsukov if (prot == IPPROTO_IPIP && 405a28b277aSAndrey V. Elsukov saidx->mode != IPSEC_MODE_TRANSPORT) { 4064dbc6e51SSam Leffler if (m->m_pkthdr.len - skip < sizeof(struct ip)) { 407a04d64d8SAndrey V. Elsukov IPSEC_ISTAT(sproto, hdrops); 4084dbc6e51SSam Leffler error = EINVAL; 4094dbc6e51SSam Leffler goto bad; 4104dbc6e51SSam Leffler } 411aaf2cfc0SVANHULLEBUS Yvan /* enc0: strip outer IPv4 header */ 412aaf2cfc0SVANHULLEBUS Yvan m_striphdr(m, 0, ip->ip_hl << 2); 41388768458SSam Leffler } 41449ddabdfSPawel Jakub Dawidek #ifdef INET6 41588768458SSam Leffler /* IPv6-in-IP encapsulation. */ 4161f194d8aSAndrey V. Elsukov else if (prot == IPPROTO_IPV6 && 417a28b277aSAndrey V. Elsukov saidx->mode != IPSEC_MODE_TRANSPORT) { 4184dbc6e51SSam Leffler if (m->m_pkthdr.len - skip < sizeof(struct ip6_hdr)) { 419a04d64d8SAndrey V. Elsukov IPSEC_ISTAT(sproto, hdrops); 4204dbc6e51SSam Leffler error = EINVAL; 4214dbc6e51SSam Leffler goto bad; 4224dbc6e51SSam Leffler } 423aaf2cfc0SVANHULLEBUS Yvan /* enc0: strip IPv4 header, keep IPv6 header only */ 424aaf2cfc0SVANHULLEBUS Yvan m_striphdr(m, 0, ip->ip_hl << 2); 42588768458SSam Leffler } 42688768458SSam Leffler #endif /* INET6 */ 4271f194d8aSAndrey V. Elsukov else if (prot != IPPROTO_IPV6 && saidx->mode == IPSEC_MODE_ANY) { 4281f194d8aSAndrey V. Elsukov /* 4291f194d8aSAndrey V. Elsukov * When mode is wildcard, inner protocol is IPv6 and 4301f194d8aSAndrey V. Elsukov * we have no INET6 support - drop this packet a bit later. 431fcf59617SAndrey V. Elsukov * In other cases we assume transport mode. Set prot to 432fcf59617SAndrey V. Elsukov * correctly choose netisr. 4331f194d8aSAndrey V. Elsukov */ 4341f194d8aSAndrey V. Elsukov prot = IPPROTO_IPIP; 4351f194d8aSAndrey V. Elsukov } 43688768458SSam Leffler 43788768458SSam Leffler /* 43888768458SSam Leffler * Record what we've done to the packet (under what SA it was 439f0514a8bSAndrey V. Elsukov * processed). 44088768458SSam Leffler */ 441f0514a8bSAndrey V. Elsukov if (sproto != IPPROTO_IPCOMP) { 44288768458SSam Leffler mtag = m_tag_get(PACKET_TAG_IPSEC_IN_DONE, 443fcf59617SAndrey V. Elsukov sizeof(struct xform_history), M_NOWAIT); 44488768458SSam Leffler if (mtag == NULL) { 4459ffa9677SSam Leffler DPRINTF(("%s: failed to get tag\n", __func__)); 446a04d64d8SAndrey V. Elsukov IPSEC_ISTAT(sproto, hdrops); 44788768458SSam Leffler error = ENOMEM; 44888768458SSam Leffler goto bad; 44988768458SSam Leffler } 45088768458SSam Leffler 451fcf59617SAndrey V. Elsukov xh = (struct xform_history *)(mtag + 1); 452fcf59617SAndrey V. Elsukov bcopy(&saidx->dst, &xh->dst, saidx->dst.sa.sa_len); 453fcf59617SAndrey V. Elsukov xh->spi = sav->spi; 454fcf59617SAndrey V. Elsukov xh->proto = sproto; 455fcf59617SAndrey V. Elsukov xh->mode = saidx->mode; 45688768458SSam Leffler m_tag_prepend(m, mtag); 45788768458SSam Leffler } 45888768458SSam Leffler 45988768458SSam Leffler key_sa_recordxfer(sav, m); /* record data transfer */ 46088768458SSam Leffler 461a28b277aSAndrey V. Elsukov /* 462a28b277aSAndrey V. Elsukov * In transport mode requeue decrypted mbuf back to IPv4 protocol 463a28b277aSAndrey V. Elsukov * handler. This is necessary to correctly expose rcvif. 464a28b277aSAndrey V. Elsukov */ 465a28b277aSAndrey V. Elsukov if (saidx->mode == IPSEC_MODE_TRANSPORT) 466a28b277aSAndrey V. Elsukov prot = IPPROTO_IPIP; 46788768458SSam Leffler /* 46888768458SSam Leffler * Re-dispatch via software interrupt. 46988768458SSam Leffler */ 470aaf2cfc0SVANHULLEBUS Yvan switch (prot) { 471aaf2cfc0SVANHULLEBUS Yvan case IPPROTO_IPIP: 472aaf2cfc0SVANHULLEBUS Yvan isr_prot = NETISR_IP; 473ef91a976SAndrey V. Elsukov af = AF_INET; 474aaf2cfc0SVANHULLEBUS Yvan break; 475aaf2cfc0SVANHULLEBUS Yvan #ifdef INET6 476aaf2cfc0SVANHULLEBUS Yvan case IPPROTO_IPV6: 477aaf2cfc0SVANHULLEBUS Yvan isr_prot = NETISR_IPV6; 478ef91a976SAndrey V. Elsukov af = AF_INET6; 479aaf2cfc0SVANHULLEBUS Yvan break; 480aaf2cfc0SVANHULLEBUS Yvan #endif 481aaf2cfc0SVANHULLEBUS Yvan default: 482aaf2cfc0SVANHULLEBUS Yvan DPRINTF(("%s: cannot handle inner ip proto %d\n", 483aaf2cfc0SVANHULLEBUS Yvan __func__, prot)); 484aaf2cfc0SVANHULLEBUS Yvan IPSEC_ISTAT(sproto, nopf); 485aaf2cfc0SVANHULLEBUS Yvan error = EPFNOSUPPORT; 486aaf2cfc0SVANHULLEBUS Yvan goto bad; 487aaf2cfc0SVANHULLEBUS Yvan } 488aaf2cfc0SVANHULLEBUS Yvan 4891a01e0e7SAndrey V. Elsukov IPSEC_INIT_CTX(&ctx, &m, NULL, sav, af, IPSEC_ENC_AFTER); 490ef91a976SAndrey V. Elsukov if ((error = ipsec_run_hhooks(&ctx, HHOOK_TYPE_IPSEC_IN)) != 0) 491ef91a976SAndrey V. Elsukov goto bad; 492fcf59617SAndrey V. Elsukov 493fcf59617SAndrey V. Elsukov /* Handle virtual tunneling interfaces */ 494fcf59617SAndrey V. Elsukov if (saidx->mode == IPSEC_MODE_TUNNEL) 495fcf59617SAndrey V. Elsukov error = ipsec_if_input(m, sav, af); 496fcf59617SAndrey V. Elsukov if (error == 0) { 497aaf2cfc0SVANHULLEBUS Yvan error = netisr_queue_src(isr_prot, (uintptr_t)sav->spi, m); 498aaf2cfc0SVANHULLEBUS Yvan if (error) { 499a04d64d8SAndrey V. Elsukov IPSEC_ISTAT(sproto, qfull); 5009ffa9677SSam Leffler DPRINTF(("%s: queue full; proto %u packet dropped\n", 5019ffa9677SSam Leffler __func__, sproto)); 50288768458SSam Leffler } 503fcf59617SAndrey V. Elsukov } 504590d0715SMateusz Guzik NET_EPOCH_EXIT(et); 505fcf59617SAndrey V. Elsukov key_freesav(&sav); 506fcf59617SAndrey V. Elsukov return (error); 50788768458SSam Leffler bad: 508590d0715SMateusz Guzik NET_EPOCH_EXIT(et); 509590d0715SMateusz Guzik bad_noepoch: 510fcf59617SAndrey V. Elsukov key_freesav(&sav); 511fcf59617SAndrey V. Elsukov if (m != NULL) 51288768458SSam Leffler m_freem(m); 513fcf59617SAndrey V. Elsukov return (error); 5149ffa9677SSam Leffler } 51588768458SSam Leffler #endif /* INET */ 51688768458SSam Leffler 51788768458SSam Leffler #ifdef INET6 518489482e2SGleb Smirnoff static bool 519489482e2SGleb Smirnoff ipsec6_lasthdr(int proto) 520489482e2SGleb Smirnoff { 521489482e2SGleb Smirnoff 522489482e2SGleb Smirnoff switch (proto) { 523489482e2SGleb Smirnoff case IPPROTO_IPV4: 524489482e2SGleb Smirnoff case IPPROTO_IPV6: 525489482e2SGleb Smirnoff case IPPROTO_GRE: 526489482e2SGleb Smirnoff case IPPROTO_ICMPV6: 527489482e2SGleb Smirnoff case IPPROTO_ETHERIP: 528489482e2SGleb Smirnoff case IPPROTO_PIM: 529489482e2SGleb Smirnoff case IPPROTO_SCTP: 530489482e2SGleb Smirnoff return (true); 531489482e2SGleb Smirnoff default: 532489482e2SGleb Smirnoff return (false); 533489482e2SGleb Smirnoff }; 534489482e2SGleb Smirnoff } 535489482e2SGleb Smirnoff 536fcf59617SAndrey V. Elsukov /* 537fcf59617SAndrey V. Elsukov * IPSEC_INPUT() method implementation for IPv6. 538fcf59617SAndrey V. Elsukov * 0 - Permitted by inbound security policy for further processing. 539fcf59617SAndrey V. Elsukov * EACCES - Forbidden by inbound security policy. 540fcf59617SAndrey V. Elsukov * EINPROGRESS - consumed by IPsec. 541fcf59617SAndrey V. Elsukov */ 54288768458SSam Leffler int 543fcf59617SAndrey V. Elsukov ipsec6_input(struct mbuf *m, int offset, int proto) 54488768458SSam Leffler { 545*ef2a572bSKonstantin Belousov int error; 546*ef2a572bSKonstantin Belousov 547*ef2a572bSKonstantin Belousov error = ipsec_accel_input(m, offset, proto); 548*ef2a572bSKonstantin Belousov if (error != ENXIO) 549*ef2a572bSKonstantin Belousov return (error); 55088768458SSam Leffler 551fcf59617SAndrey V. Elsukov switch (proto) { 552fcf59617SAndrey V. Elsukov case IPPROTO_AH: 553fcf59617SAndrey V. Elsukov case IPPROTO_ESP: 554fcf59617SAndrey V. Elsukov case IPPROTO_IPCOMP: 555fcf59617SAndrey V. Elsukov /* Do inbound IPsec processing for AH/ESP/IPCOMP */ 556fcf59617SAndrey V. Elsukov ipsec_common_input(m, offset, 557fcf59617SAndrey V. Elsukov offsetof(struct ip6_hdr, ip6_nxt), AF_INET6, proto); 558fcf59617SAndrey V. Elsukov return (EINPROGRESS); /* mbuf consumed by IPsec */ 559fcf59617SAndrey V. Elsukov default: 560fcf59617SAndrey V. Elsukov /* 561fcf59617SAndrey V. Elsukov * Protocols with further headers get their IPsec treatment 562fcf59617SAndrey V. Elsukov * within the protocol specific processing. 563fcf59617SAndrey V. Elsukov */ 564489482e2SGleb Smirnoff if (!ipsec6_lasthdr(proto)) 565fcf59617SAndrey V. Elsukov return (0); 566fcf59617SAndrey V. Elsukov /* FALLTHROUGH */ 567fcf59617SAndrey V. Elsukov }; 568fcf59617SAndrey V. Elsukov /* 569fcf59617SAndrey V. Elsukov * Enforce IPsec policy checking if we are seeing last header. 570fcf59617SAndrey V. Elsukov */ 571fcf59617SAndrey V. Elsukov if (ipsec6_in_reject(m, NULL) != 0) { 572fcf59617SAndrey V. Elsukov /* Forbidden by inbound security policy */ 573fcf59617SAndrey V. Elsukov m_freem(m); 574fcf59617SAndrey V. Elsukov return (EACCES); 57588768458SSam Leffler } 576fcf59617SAndrey V. Elsukov return (0); 57788768458SSam Leffler } 57888768458SSam Leffler 579d9d59bb1SWojciech Macek int 580fcb3f813SGleb Smirnoff ipsec6_ctlinput(ipsec_ctlinput_param_t param) 581d9d59bb1SWojciech Macek { 582d9d59bb1SWojciech Macek return (0); 583d9d59bb1SWojciech Macek } 584d9d59bb1SWojciech Macek 58578b1fc05SGleb Smirnoff extern ipproto_input_t *ip6_protox[]; 58678b1fc05SGleb Smirnoff 5879ffa9677SSam Leffler /* 5889ffa9677SSam Leffler * IPsec input callback, called by the transform callback. Takes care of 5899ffa9677SSam Leffler * filtering and other sanity checks on the processed packet. 5909ffa9677SSam Leffler */ 5919ffa9677SSam Leffler int 592f0514a8bSAndrey V. Elsukov ipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip, 593f0514a8bSAndrey V. Elsukov int protoff) 5949ffa9677SSam Leffler { 5957f1f6591SAndrey V. Elsukov IPSEC_DEBUG_DECLARE(char buf[IPSEC_ADDRSTRLEN]); 596f82eb2a6SJohn Baldwin struct epoch_tracker et; 597ef91a976SAndrey V. Elsukov struct ipsec_ctx_data ctx; 598fcf59617SAndrey V. Elsukov struct xform_history *xh; 599fcf59617SAndrey V. Elsukov struct secasindex *saidx; 6009ffa9677SSam Leffler struct ip6_hdr *ip6; 6019ffa9677SSam Leffler struct m_tag *mtag; 602fcf59617SAndrey V. Elsukov int prot, af, sproto; 6031d3b268cSAndrey V. Elsukov int nxt, isr_prot; 6049ffa9677SSam Leffler int error, nest; 605fcf59617SAndrey V. Elsukov uint8_t nxt8; 6069ffa9677SSam Leffler 6079ffa9677SSam Leffler IPSEC_ASSERT(sav != NULL, ("null SA")); 6089ffa9677SSam Leffler IPSEC_ASSERT(sav->sah != NULL, ("null SAH")); 6099ffa9677SSam Leffler saidx = &sav->sah->saidx; 6109ffa9677SSam Leffler af = saidx->dst.sa.sa_family; 6119ffa9677SSam Leffler IPSEC_ASSERT(af == AF_INET6, ("unexpected af %u", af)); 6129ffa9677SSam Leffler sproto = saidx->proto; 6139ffa9677SSam Leffler IPSEC_ASSERT(sproto == IPPROTO_ESP || sproto == IPPROTO_AH || 6149ffa9677SSam Leffler sproto == IPPROTO_IPCOMP, 6159ffa9677SSam Leffler ("unexpected security protocol %u", sproto)); 6169ffa9677SSam Leffler 617590d0715SMateusz Guzik NET_EPOCH_ENTER(et); 618590d0715SMateusz Guzik 6199ffa9677SSam Leffler /* Fix IPv6 header */ 6209ffa9677SSam Leffler if (m->m_len < sizeof(struct ip6_hdr) && 6219ffa9677SSam Leffler (m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) { 6229ffa9677SSam Leffler DPRINTF(("%s: processing failed for SA %s/%08lx\n", 623962ac6c7SAndrey V. Elsukov __func__, ipsec_address(&sav->sah->saidx.dst, buf, 624962ac6c7SAndrey V. Elsukov sizeof(buf)), (u_long) ntohl(sav->spi))); 6259ffa9677SSam Leffler 626a04d64d8SAndrey V. Elsukov IPSEC_ISTAT(sproto, hdrops); 6279ffa9677SSam Leffler error = EACCES; 6289ffa9677SSam Leffler goto bad; 6299ffa9677SSam Leffler } 6309ffa9677SSam Leffler 6311a01e0e7SAndrey V. Elsukov IPSEC_INIT_CTX(&ctx, &m, NULL, sav, af, IPSEC_ENC_BEFORE); 632ef91a976SAndrey V. Elsukov if ((error = ipsec_run_hhooks(&ctx, HHOOK_TYPE_IPSEC_IN)) != 0) 633ef91a976SAndrey V. Elsukov goto bad; 634fcf59617SAndrey V. Elsukov 635fcf59617SAndrey V. Elsukov ip6 = mtod(m, struct ip6_hdr *); 636fcf59617SAndrey V. Elsukov ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr)); 637fcf59617SAndrey V. Elsukov 6389ffa9677SSam Leffler /* Save protocol */ 639612faae7SAndrey V. Elsukov m_copydata(m, protoff, 1, &nxt8); 640612faae7SAndrey V. Elsukov prot = nxt8; 6419ffa9677SSam Leffler 64280044c78SXavier Beaudouin /* 64380044c78SXavier Beaudouin * Check that we have NAT-T enabled and apply transport mode 64480044c78SXavier Beaudouin * decapsulation NAT procedure (RFC3948). 64580044c78SXavier Beaudouin * Do this before invoking into the PFIL. 64680044c78SXavier Beaudouin */ 64780044c78SXavier Beaudouin if (sav->natt != NULL && 64880044c78SXavier Beaudouin (prot == IPPROTO_UDP || prot == IPPROTO_TCP)) 64980044c78SXavier Beaudouin udp_ipsec_adjust_cksum(m, sav, prot, skip); 65080044c78SXavier Beaudouin 651612faae7SAndrey V. Elsukov /* IPv6-in-IP encapsulation */ 652612faae7SAndrey V. Elsukov if (prot == IPPROTO_IPV6 && 653612faae7SAndrey V. Elsukov saidx->mode != IPSEC_MODE_TRANSPORT) { 654612faae7SAndrey V. Elsukov if (m->m_pkthdr.len - skip < sizeof(struct ip6_hdr)) { 655612faae7SAndrey V. Elsukov IPSEC_ISTAT(sproto, hdrops); 656612faae7SAndrey V. Elsukov error = EINVAL; 657612faae7SAndrey V. Elsukov goto bad; 658612faae7SAndrey V. Elsukov } 659612faae7SAndrey V. Elsukov /* ip6n will now contain the inner IPv6 header. */ 660612faae7SAndrey V. Elsukov m_striphdr(m, 0, skip); 661612faae7SAndrey V. Elsukov skip = 0; 662612faae7SAndrey V. Elsukov } 6639ffa9677SSam Leffler #ifdef INET 6649ffa9677SSam Leffler /* IP-in-IP encapsulation */ 665612faae7SAndrey V. Elsukov else if (prot == IPPROTO_IPIP && 666612faae7SAndrey V. Elsukov saidx->mode != IPSEC_MODE_TRANSPORT) { 6679ffa9677SSam Leffler if (m->m_pkthdr.len - skip < sizeof(struct ip)) { 668a04d64d8SAndrey V. Elsukov IPSEC_ISTAT(sproto, hdrops); 6699ffa9677SSam Leffler error = EINVAL; 6709ffa9677SSam Leffler goto bad; 6719ffa9677SSam Leffler } 6729ffa9677SSam Leffler /* ipn will now contain the inner IPv4 header */ 673aaf2cfc0SVANHULLEBUS Yvan m_striphdr(m, 0, skip); 674aaf2cfc0SVANHULLEBUS Yvan skip = 0; 6759ffa9677SSam Leffler } 6769ffa9677SSam Leffler #endif /* INET */ 677612faae7SAndrey V. Elsukov else { 678612faae7SAndrey V. Elsukov prot = IPPROTO_IPV6; /* for correct BPF processing */ 6799ffa9677SSam Leffler } 6809ffa9677SSam Leffler 6819ffa9677SSam Leffler /* 6829ffa9677SSam Leffler * Record what we've done to the packet (under what SA it was 683f0514a8bSAndrey V. Elsukov * processed). 6849ffa9677SSam Leffler */ 685f0514a8bSAndrey V. Elsukov if (sproto != IPPROTO_IPCOMP) { 6869ffa9677SSam Leffler mtag = m_tag_get(PACKET_TAG_IPSEC_IN_DONE, 687fcf59617SAndrey V. Elsukov sizeof(struct xform_history), M_NOWAIT); 6889ffa9677SSam Leffler if (mtag == NULL) { 6899ffa9677SSam Leffler DPRINTF(("%s: failed to get tag\n", __func__)); 690a04d64d8SAndrey V. Elsukov IPSEC_ISTAT(sproto, hdrops); 6919ffa9677SSam Leffler error = ENOMEM; 6929ffa9677SSam Leffler goto bad; 6939ffa9677SSam Leffler } 6949ffa9677SSam Leffler 695fcf59617SAndrey V. Elsukov xh = (struct xform_history *)(mtag + 1); 696fcf59617SAndrey V. Elsukov bcopy(&saidx->dst, &xh->dst, saidx->dst.sa.sa_len); 697fcf59617SAndrey V. Elsukov xh->spi = sav->spi; 698fcf59617SAndrey V. Elsukov xh->proto = sproto; 699fcf59617SAndrey V. Elsukov xh->mode = saidx->mode; 7009ffa9677SSam Leffler m_tag_prepend(m, mtag); 7019ffa9677SSam Leffler } 7029ffa9677SSam Leffler 7039ffa9677SSam Leffler key_sa_recordxfer(sav, m); 7049ffa9677SSam Leffler 705aaf2cfc0SVANHULLEBUS Yvan #ifdef INET 706aaf2cfc0SVANHULLEBUS Yvan if (prot == IPPROTO_IPIP) 707ef91a976SAndrey V. Elsukov af = AF_INET; 708ef91a976SAndrey V. Elsukov else 70919ad9831SBjoern A. Zeeb #endif 710ef91a976SAndrey V. Elsukov af = AF_INET6; 7111a01e0e7SAndrey V. Elsukov IPSEC_INIT_CTX(&ctx, &m, NULL, sav, af, IPSEC_ENC_AFTER); 712ef91a976SAndrey V. Elsukov if ((error = ipsec_run_hhooks(&ctx, HHOOK_TYPE_IPSEC_IN)) != 0) 713ef91a976SAndrey V. Elsukov goto bad; 7141d3b268cSAndrey V. Elsukov if (skip == 0) { 7151d3b268cSAndrey V. Elsukov /* 7161d3b268cSAndrey V. Elsukov * We stripped outer IPv6 header. 7171d3b268cSAndrey V. Elsukov * Now we should requeue decrypted packet via netisr. 7181d3b268cSAndrey V. Elsukov */ 7191d3b268cSAndrey V. Elsukov switch (prot) { 7201d3b268cSAndrey V. Elsukov #ifdef INET 7211d3b268cSAndrey V. Elsukov case IPPROTO_IPIP: 7221d3b268cSAndrey V. Elsukov isr_prot = NETISR_IP; 7231d3b268cSAndrey V. Elsukov break; 7241d3b268cSAndrey V. Elsukov #endif 7251d3b268cSAndrey V. Elsukov case IPPROTO_IPV6: 7261d3b268cSAndrey V. Elsukov isr_prot = NETISR_IPV6; 7271d3b268cSAndrey V. Elsukov break; 7281d3b268cSAndrey V. Elsukov default: 7291d3b268cSAndrey V. Elsukov DPRINTF(("%s: cannot handle inner ip proto %d\n", 7301d3b268cSAndrey V. Elsukov __func__, prot)); 7311d3b268cSAndrey V. Elsukov IPSEC_ISTAT(sproto, nopf); 7321d3b268cSAndrey V. Elsukov error = EPFNOSUPPORT; 7331d3b268cSAndrey V. Elsukov goto bad; 7341d3b268cSAndrey V. Elsukov } 735fcf59617SAndrey V. Elsukov /* Handle virtual tunneling interfaces */ 736fcf59617SAndrey V. Elsukov if (saidx->mode == IPSEC_MODE_TUNNEL) 737fcf59617SAndrey V. Elsukov error = ipsec_if_input(m, sav, af); 738fcf59617SAndrey V. Elsukov if (error == 0) { 739fcf59617SAndrey V. Elsukov error = netisr_queue_src(isr_prot, 740fcf59617SAndrey V. Elsukov (uintptr_t)sav->spi, m); 7411d3b268cSAndrey V. Elsukov if (error) { 7421d3b268cSAndrey V. Elsukov IPSEC_ISTAT(sproto, qfull); 743fcf59617SAndrey V. Elsukov DPRINTF(("%s: queue full; proto %u packet" 744fcf59617SAndrey V. Elsukov " dropped\n", __func__, sproto)); 7451d3b268cSAndrey V. Elsukov } 746fcf59617SAndrey V. Elsukov } 747590d0715SMateusz Guzik NET_EPOCH_EXIT(et); 748fcf59617SAndrey V. Elsukov key_freesav(&sav); 7491d3b268cSAndrey V. Elsukov return (error); 7501d3b268cSAndrey V. Elsukov } 7519ffa9677SSam Leffler /* 7529ffa9677SSam Leffler * See the end of ip6_input for this logic. 7539ffa9677SSam Leffler * IPPROTO_IPV[46] case will be processed just like other ones 7549ffa9677SSam Leffler */ 7559ffa9677SSam Leffler nest = 0; 7569ffa9677SSam Leffler nxt = nxt8; 7579ffa9677SSam Leffler while (nxt != IPPROTO_DONE) { 758603724d3SBjoern A. Zeeb if (V_ip6_hdrnestlimit && (++nest > V_ip6_hdrnestlimit)) { 7599cb8d207SAndrey V. Elsukov IP6STAT_INC(ip6s_toomanyhdr); 7609ffa9677SSam Leffler error = EINVAL; 761590d0715SMateusz Guzik goto bad; 7629ffa9677SSam Leffler } 7639ffa9677SSam Leffler 7649ffa9677SSam Leffler /* 7659ffa9677SSam Leffler * Protection against faulty packet - there should be 7669ffa9677SSam Leffler * more sanity checks in header chain processing. 7679ffa9677SSam Leffler */ 7689ffa9677SSam Leffler if (m->m_pkthdr.len < skip) { 7699cb8d207SAndrey V. Elsukov IP6STAT_INC(ip6s_tooshort); 7709ffa9677SSam Leffler in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated); 7719ffa9677SSam Leffler error = EINVAL; 772590d0715SMateusz Guzik goto bad; 7739ffa9677SSam Leffler } 7749ffa9677SSam Leffler /* 7759ffa9677SSam Leffler * Enforce IPsec policy checking if we are seeing last header. 7769ffa9677SSam Leffler * note that we do not visit this with protocols with pcb layer 7779ffa9677SSam Leffler * code - like udp/tcp/raw ip. 7789ffa9677SSam Leffler */ 779489482e2SGleb Smirnoff if (ipsec6_lasthdr(nxt) && ipsec6_in_reject(m, NULL)) { 7809ffa9677SSam Leffler error = EINVAL; 781590d0715SMateusz Guzik goto bad; 7829ffa9677SSam Leffler } 78378b1fc05SGleb Smirnoff nxt = ip6_protox[nxt](&m, &skip, nxt); 7849ffa9677SSam Leffler } 785f82eb2a6SJohn Baldwin NET_EPOCH_EXIT(et); 786fcf59617SAndrey V. Elsukov key_freesav(&sav); 787fcf59617SAndrey V. Elsukov return (0); 7889ffa9677SSam Leffler bad: 789590d0715SMateusz Guzik NET_EPOCH_EXIT(et); 790fcf59617SAndrey V. Elsukov key_freesav(&sav); 7919ffa9677SSam Leffler if (m) 7929ffa9677SSam Leffler m_freem(m); 793fcf59617SAndrey V. Elsukov return (error); 79488768458SSam Leffler } 79588768458SSam Leffler #endif /* INET6 */ 796