1aaea26efSSam Leffler /*- 2aaea26efSSam Leffler * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting 3aaea26efSSam Leffler * All rights reserved. 4aaea26efSSam Leffler * 5aaea26efSSam Leffler * Redistribution and use in source and binary forms, with or without 6aaea26efSSam Leffler * modification, are permitted provided that the following conditions 7aaea26efSSam Leffler * are met: 8aaea26efSSam Leffler * 1. Redistributions of source code must retain the above copyright 9aaea26efSSam Leffler * notice, this list of conditions and the following disclaimer. 10aaea26efSSam Leffler * 2. Redistributions in binary form must reproduce the above copyright 11aaea26efSSam Leffler * notice, this list of conditions and the following disclaimer in the 12aaea26efSSam Leffler * documentation and/or other materials provided with the distribution. 13aaea26efSSam Leffler * 14aaea26efSSam Leffler * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15aaea26efSSam Leffler * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16aaea26efSSam Leffler * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17aaea26efSSam Leffler * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18aaea26efSSam Leffler * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19aaea26efSSam Leffler * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20aaea26efSSam Leffler * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21aaea26efSSam Leffler * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22aaea26efSSam Leffler * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23aaea26efSSam Leffler * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24aaea26efSSam Leffler * SUCH DAMAGE. 25aaea26efSSam Leffler * 26aaea26efSSam Leffler * $FreeBSD$ 27aaea26efSSam Leffler */ 2888768458SSam Leffler 2988768458SSam Leffler /* 3088768458SSam Leffler * IPsec output processing. 3188768458SSam Leffler */ 3288768458SSam Leffler #include "opt_inet.h" 3388768458SSam Leffler #include "opt_inet6.h" 3488768458SSam Leffler #include "opt_ipsec.h" 3588768458SSam Leffler 3688768458SSam Leffler #include <sys/param.h> 3788768458SSam Leffler #include <sys/systm.h> 3888768458SSam Leffler #include <sys/mbuf.h> 3988768458SSam Leffler #include <sys/domain.h> 4088768458SSam Leffler #include <sys/protosw.h> 4188768458SSam Leffler #include <sys/socket.h> 4288768458SSam Leffler #include <sys/errno.h> 4388768458SSam Leffler #include <sys/syslog.h> 4488768458SSam Leffler 4588768458SSam Leffler #include <net/if.h> 4688768458SSam Leffler #include <net/route.h> 4788768458SSam Leffler 4888768458SSam Leffler #include <netinet/in.h> 4988768458SSam Leffler #include <netinet/in_systm.h> 5088768458SSam Leffler #include <netinet/ip.h> 5188768458SSam Leffler #include <netinet/ip_var.h> 5288768458SSam Leffler #include <netinet/in_var.h> 5388768458SSam Leffler #include <netinet/ip_ecn.h> 5488768458SSam Leffler #ifdef INET6 5588768458SSam Leffler #include <netinet6/ip6_ecn.h> 5688768458SSam Leffler #endif 5788768458SSam Leffler 5888768458SSam Leffler #include <netinet/ip6.h> 5988768458SSam Leffler #ifdef INET6 6088768458SSam Leffler #include <netinet6/ip6_var.h> 6188768458SSam Leffler #endif 6288768458SSam Leffler #include <netinet/in_pcb.h> 6388768458SSam Leffler #ifdef INET6 6488768458SSam Leffler #include <netinet/icmp6.h> 6588768458SSam Leffler #endif 6688768458SSam Leffler 6788768458SSam Leffler #include <netipsec/ipsec.h> 6888768458SSam Leffler #ifdef INET6 6988768458SSam Leffler #include <netipsec/ipsec6.h> 7088768458SSam Leffler #endif 7188768458SSam Leffler #include <netipsec/ah_var.h> 7288768458SSam Leffler #include <netipsec/esp_var.h> 7388768458SSam Leffler #include <netipsec/ipcomp_var.h> 7488768458SSam Leffler 7588768458SSam Leffler #include <netipsec/xform.h> 7688768458SSam Leffler 7788768458SSam Leffler #include <netipsec/key.h> 7888768458SSam Leffler #include <netipsec/keydb.h> 7988768458SSam Leffler #include <netipsec/key_debug.h> 8088768458SSam Leffler 8188768458SSam Leffler #include <machine/in_cksum.h> 8288768458SSam Leffler 8388768458SSam Leffler int 8488768458SSam Leffler ipsec_process_done(struct mbuf *m, struct ipsecrequest *isr) 8588768458SSam Leffler { 8688768458SSam Leffler struct tdb_ident *tdbi; 8788768458SSam Leffler struct m_tag *mtag; 8888768458SSam Leffler struct secasvar *sav; 8988768458SSam Leffler struct secasindex *saidx; 9088768458SSam Leffler int error; 9188768458SSam Leffler 9288768458SSam Leffler #if 0 9388768458SSam Leffler SPLASSERT(net, "ipsec_process_done"); 9488768458SSam Leffler #endif 9588768458SSam Leffler 9688768458SSam Leffler KASSERT(m != NULL, ("ipsec_process_done: null mbuf")); 9788768458SSam Leffler KASSERT(isr != NULL, ("ipsec_process_done: null ISR")); 9888768458SSam Leffler sav = isr->sav; 9988768458SSam Leffler KASSERT(sav != NULL, ("ipsec_process_done: null SA")); 10088768458SSam Leffler KASSERT(sav->sah != NULL, ("ipsec_process_done: null SAH")); 10188768458SSam Leffler 10288768458SSam Leffler saidx = &sav->sah->saidx; 10388768458SSam Leffler switch (saidx->dst.sa.sa_family) { 10488768458SSam Leffler #ifdef INET 10588768458SSam Leffler case AF_INET: 10688768458SSam Leffler /* Fix the header length, for AH processing. */ 10788768458SSam Leffler mtod(m, struct ip *)->ip_len = htons(m->m_pkthdr.len); 10888768458SSam Leffler break; 10988768458SSam Leffler #endif /* INET */ 11088768458SSam Leffler #ifdef INET6 11188768458SSam Leffler case AF_INET6: 11288768458SSam Leffler /* Fix the header length, for AH processing. */ 11388768458SSam Leffler if (m->m_pkthdr.len < sizeof (struct ip6_hdr)) { 11488768458SSam Leffler error = ENXIO; 11588768458SSam Leffler goto bad; 11688768458SSam Leffler } 11788768458SSam Leffler if (m->m_pkthdr.len - sizeof (struct ip6_hdr) > IPV6_MAXPACKET) { 11888768458SSam Leffler /* No jumbogram support. */ 11988768458SSam Leffler error = ENXIO; /*?*/ 12088768458SSam Leffler goto bad; 12188768458SSam Leffler } 12288768458SSam Leffler mtod(m, struct ip6_hdr *)->ip6_plen = 12388768458SSam Leffler htons(m->m_pkthdr.len - sizeof(struct ip6_hdr)); 12488768458SSam Leffler break; 12588768458SSam Leffler #endif /* INET6 */ 12688768458SSam Leffler default: 12788768458SSam Leffler DPRINTF(("ipsec_process_done: unknown protocol family %u\n", 12888768458SSam Leffler saidx->dst.sa.sa_family)); 12988768458SSam Leffler error = ENXIO; 13088768458SSam Leffler goto bad; 13188768458SSam Leffler } 13288768458SSam Leffler 13388768458SSam Leffler /* 13488768458SSam Leffler * Add a record of what we've done or what needs to be done to the 13588768458SSam Leffler * packet. 13688768458SSam Leffler */ 13788768458SSam Leffler mtag = m_tag_get(PACKET_TAG_IPSEC_OUT_DONE, 13888768458SSam Leffler sizeof(struct tdb_ident), M_NOWAIT); 13988768458SSam Leffler if (mtag == NULL) { 14088768458SSam Leffler DPRINTF(("ipsec_process_done: could not get packet tag\n")); 14188768458SSam Leffler error = ENOMEM; 14288768458SSam Leffler goto bad; 14388768458SSam Leffler } 14488768458SSam Leffler 14588768458SSam Leffler tdbi = (struct tdb_ident *)(mtag + 1); 14688768458SSam Leffler tdbi->dst = saidx->dst; 14788768458SSam Leffler tdbi->proto = saidx->proto; 14888768458SSam Leffler tdbi->spi = sav->spi; 14988768458SSam Leffler m_tag_prepend(m, mtag); 15088768458SSam Leffler 15188768458SSam Leffler /* 15288768458SSam Leffler * If there's another (bundled) SA to apply, do so. 15388768458SSam Leffler * Note that this puts a burden on the kernel stack size. 15488768458SSam Leffler * If this is a problem we'll need to introduce a queue 15588768458SSam Leffler * to set the packet on so we can unwind the stack before 15688768458SSam Leffler * doing further processing. 15788768458SSam Leffler */ 15888768458SSam Leffler if (isr->next) { 15988768458SSam Leffler newipsecstat.ips_out_bundlesa++; 16088768458SSam Leffler return ipsec4_process_packet(m, isr->next, 0, 0); 16188768458SSam Leffler } 16288768458SSam Leffler 16388768458SSam Leffler /* 16488768458SSam Leffler * We're done with IPsec processing, transmit the packet using the 16588768458SSam Leffler * appropriate network protocol (IP or IPv6). SPD lookup will be 16688768458SSam Leffler * performed again there. 16788768458SSam Leffler */ 16888768458SSam Leffler switch (saidx->dst.sa.sa_family) { 16988768458SSam Leffler #ifdef INET 17088768458SSam Leffler struct ip *ip; 17188768458SSam Leffler case AF_INET: 17288768458SSam Leffler ip = mtod(m, struct ip *); 17388768458SSam Leffler ip->ip_len = ntohs(ip->ip_len); 17488768458SSam Leffler ip->ip_off = ntohs(ip->ip_off); 17588768458SSam Leffler 17688768458SSam Leffler return ip_output(m, NULL, NULL, IP_RAWOUTPUT, NULL, NULL); 17788768458SSam Leffler #endif /* INET */ 17888768458SSam Leffler #ifdef INET6 17988768458SSam Leffler case AF_INET6: 18088768458SSam Leffler /* 18188768458SSam Leffler * We don't need massage, IPv6 header fields are always in 18288768458SSam Leffler * net endian. 18388768458SSam Leffler */ 18488768458SSam Leffler return ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL); 18588768458SSam Leffler #endif /* INET6 */ 18688768458SSam Leffler } 18788768458SSam Leffler panic("ipsec_process_done"); 18888768458SSam Leffler bad: 18988768458SSam Leffler m_freem(m); 19088768458SSam Leffler KEY_FREESAV(&sav); 19188768458SSam Leffler return (error); 19288768458SSam Leffler } 19388768458SSam Leffler 19488768458SSam Leffler static struct ipsecrequest * 19588768458SSam Leffler ipsec_nextisr( 19688768458SSam Leffler struct mbuf *m, 19788768458SSam Leffler struct ipsecrequest *isr, 19888768458SSam Leffler int af, 19988768458SSam Leffler struct secasindex *saidx, 20088768458SSam Leffler int *error 20188768458SSam Leffler ) 20288768458SSam Leffler { 20388768458SSam Leffler #define IPSEC_OSTAT(x,y,z) (isr->saidx.proto == IPPROTO_ESP ? (x)++ : \ 20488768458SSam Leffler isr->saidx.proto == IPPROTO_AH ? (y)++ : (z)++) 20588768458SSam Leffler struct secasvar *sav; 20688768458SSam Leffler 20788768458SSam Leffler #if 0 20888768458SSam Leffler SPLASSERT(net, "ipsec_nextisr"); 20988768458SSam Leffler #endif 21088768458SSam Leffler KASSERT(af == AF_INET || af == AF_INET6, 21188768458SSam Leffler ("ipsec_nextisr: invalid address family %u", af)); 21288768458SSam Leffler again: 21388768458SSam Leffler /* 21488768458SSam Leffler * Craft SA index to search for proper SA. Note that 21588768458SSam Leffler * we only fillin unspecified SA peers for transport 21688768458SSam Leffler * mode; for tunnel mode they must already be filled in. 21788768458SSam Leffler */ 21888768458SSam Leffler *saidx = isr->saidx; 21988768458SSam Leffler if (isr->saidx.mode == IPSEC_MODE_TRANSPORT) { 22088768458SSam Leffler /* Fillin unspecified SA peers only for transport mode */ 22188768458SSam Leffler if (af == AF_INET) { 22288768458SSam Leffler struct sockaddr_in *sin; 22388768458SSam Leffler struct ip *ip = mtod(m, struct ip *); 22488768458SSam Leffler 22588768458SSam Leffler if (saidx->src.sa.sa_len == 0) { 22688768458SSam Leffler sin = &saidx->src.sin; 22788768458SSam Leffler sin->sin_len = sizeof(*sin); 22888768458SSam Leffler sin->sin_family = AF_INET; 22988768458SSam Leffler sin->sin_port = IPSEC_PORT_ANY; 23088768458SSam Leffler sin->sin_addr = ip->ip_src; 23188768458SSam Leffler } 23288768458SSam Leffler if (saidx->dst.sa.sa_len == 0) { 23388768458SSam Leffler sin = &saidx->dst.sin; 23488768458SSam Leffler sin->sin_len = sizeof(*sin); 23588768458SSam Leffler sin->sin_family = AF_INET; 23688768458SSam Leffler sin->sin_port = IPSEC_PORT_ANY; 23788768458SSam Leffler sin->sin_addr = ip->ip_dst; 23888768458SSam Leffler } 23988768458SSam Leffler } else { 24088768458SSam Leffler struct sockaddr_in6 *sin6; 24188768458SSam Leffler struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 24288768458SSam Leffler 24388768458SSam Leffler if (saidx->src.sin6.sin6_len == 0) { 24488768458SSam Leffler sin6 = (struct sockaddr_in6 *)&saidx->src; 24588768458SSam Leffler sin6->sin6_len = sizeof(*sin6); 24688768458SSam Leffler sin6->sin6_family = AF_INET6; 24788768458SSam Leffler sin6->sin6_port = IPSEC_PORT_ANY; 24888768458SSam Leffler sin6->sin6_addr = ip6->ip6_src; 24988768458SSam Leffler if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) { 25088768458SSam Leffler /* fix scope id for comparing SPD */ 25188768458SSam Leffler sin6->sin6_addr.s6_addr16[1] = 0; 25288768458SSam Leffler sin6->sin6_scope_id = 25388768458SSam Leffler ntohs(ip6->ip6_src.s6_addr16[1]); 25488768458SSam Leffler } 25588768458SSam Leffler } 25688768458SSam Leffler if (saidx->dst.sin6.sin6_len == 0) { 25788768458SSam Leffler sin6 = (struct sockaddr_in6 *)&saidx->dst; 25888768458SSam Leffler sin6->sin6_len = sizeof(*sin6); 25988768458SSam Leffler sin6->sin6_family = AF_INET6; 26088768458SSam Leffler sin6->sin6_port = IPSEC_PORT_ANY; 26188768458SSam Leffler sin6->sin6_addr = ip6->ip6_dst; 26288768458SSam Leffler if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) { 26388768458SSam Leffler /* fix scope id for comparing SPD */ 26488768458SSam Leffler sin6->sin6_addr.s6_addr16[1] = 0; 26588768458SSam Leffler sin6->sin6_scope_id = 26688768458SSam Leffler ntohs(ip6->ip6_dst.s6_addr16[1]); 26788768458SSam Leffler } 26888768458SSam Leffler } 26988768458SSam Leffler } 27088768458SSam Leffler } 27188768458SSam Leffler 27288768458SSam Leffler /* 27388768458SSam Leffler * Lookup SA and validate it. 27488768458SSam Leffler */ 27588768458SSam Leffler *error = key_checkrequest(isr, saidx); 27688768458SSam Leffler if (*error != 0) { 27788768458SSam Leffler /* 27888768458SSam Leffler * IPsec processing is required, but no SA found. 27988768458SSam Leffler * I assume that key_acquire() had been called 28088768458SSam Leffler * to get/establish the SA. Here I discard 28188768458SSam Leffler * this packet because it is responsibility for 28288768458SSam Leffler * upper layer to retransmit the packet. 28388768458SSam Leffler */ 28488768458SSam Leffler newipsecstat.ips_out_nosa++; 28588768458SSam Leffler goto bad; 28688768458SSam Leffler } 28788768458SSam Leffler sav = isr->sav; 28888768458SSam Leffler if (sav == NULL) { /* XXX valid return */ 28988768458SSam Leffler KASSERT(ipsec_get_reqlevel(isr) == IPSEC_LEVEL_USE, 29088768458SSam Leffler ("ipsec_nextisr: no SA found, but required; level %u", 29188768458SSam Leffler ipsec_get_reqlevel(isr))); 29288768458SSam Leffler isr = isr->next; 29388768458SSam Leffler if (isr == NULL) { 29488768458SSam Leffler /*XXXstatistic??*/ 29588768458SSam Leffler *error = EINVAL; /*XXX*/ 29688768458SSam Leffler return isr; 29788768458SSam Leffler } 29888768458SSam Leffler goto again; 29988768458SSam Leffler } 30088768458SSam Leffler 30188768458SSam Leffler /* 30288768458SSam Leffler * Check system global policy controls. 30388768458SSam Leffler */ 30488768458SSam Leffler if ((isr->saidx.proto == IPPROTO_ESP && !esp_enable) || 30588768458SSam Leffler (isr->saidx.proto == IPPROTO_AH && !ah_enable) || 30688768458SSam Leffler (isr->saidx.proto == IPPROTO_IPCOMP && !ipcomp_enable)) { 30788768458SSam Leffler DPRINTF(("ipsec_nextisr: IPsec outbound packet dropped due" 30888768458SSam Leffler " to policy (check your sysctls)\n")); 30988768458SSam Leffler IPSEC_OSTAT(espstat.esps_pdrops, ahstat.ahs_pdrops, 31088768458SSam Leffler ipcompstat.ipcomps_pdrops); 31188768458SSam Leffler *error = EHOSTUNREACH; 31288768458SSam Leffler goto bad; 31388768458SSam Leffler } 31488768458SSam Leffler 31588768458SSam Leffler /* 31688768458SSam Leffler * Sanity check the SA contents for the caller 31788768458SSam Leffler * before they invoke the xform output method. 31888768458SSam Leffler */ 31988768458SSam Leffler if (sav->tdb_xform == NULL) { 32088768458SSam Leffler DPRINTF(("ipsec_nextisr: no transform for SA\n")); 32188768458SSam Leffler IPSEC_OSTAT(espstat.esps_noxform, ahstat.ahs_noxform, 32288768458SSam Leffler ipcompstat.ipcomps_noxform); 32388768458SSam Leffler *error = EHOSTUNREACH; 32488768458SSam Leffler goto bad; 32588768458SSam Leffler } 32688768458SSam Leffler return isr; 32788768458SSam Leffler bad: 32888768458SSam Leffler KASSERT(*error != 0, ("ipsec_nextisr: error return w/ no error code")); 32988768458SSam Leffler return NULL; 33088768458SSam Leffler #undef IPSEC_OSTAT 33188768458SSam Leffler } 33288768458SSam Leffler 33388768458SSam Leffler #ifdef INET 33488768458SSam Leffler /* 33588768458SSam Leffler * IPsec output logic for IPv4. 33688768458SSam Leffler */ 33788768458SSam Leffler int 33888768458SSam Leffler ipsec4_process_packet( 33988768458SSam Leffler struct mbuf *m, 34088768458SSam Leffler struct ipsecrequest *isr, 34188768458SSam Leffler int flags, 34288768458SSam Leffler int tunalready) 34388768458SSam Leffler { 34488768458SSam Leffler struct secasindex saidx; 34588768458SSam Leffler struct secasvar *sav; 34688768458SSam Leffler struct ip *ip; 34788768458SSam Leffler int s, error, i, off; 34888768458SSam Leffler 34988768458SSam Leffler KASSERT(m != NULL, ("ipsec4_process_packet: null mbuf")); 35088768458SSam Leffler KASSERT(isr != NULL, ("ipsec4_process_packet: null isr")); 35188768458SSam Leffler 35288768458SSam Leffler s = splnet(); /* insure SA contents don't change */ 35388768458SSam Leffler 35488768458SSam Leffler isr = ipsec_nextisr(m, isr, AF_INET, &saidx, &error); 35588768458SSam Leffler if (isr == NULL) 35688768458SSam Leffler goto bad; 35788768458SSam Leffler 35888768458SSam Leffler sav = isr->sav; 35988768458SSam Leffler if (!tunalready) { 36088768458SSam Leffler union sockaddr_union *dst = &sav->sah->saidx.dst; 36188768458SSam Leffler int setdf; 36288768458SSam Leffler 36388768458SSam Leffler /* 36488768458SSam Leffler * Collect IP_DF state from the outer header. 36588768458SSam Leffler */ 36688768458SSam Leffler if (dst->sa.sa_family == AF_INET) { 36788768458SSam Leffler if (m->m_len < sizeof (struct ip) && 36888768458SSam Leffler (m = m_pullup(m, sizeof (struct ip))) == NULL) { 36988768458SSam Leffler error = ENOBUFS; 37088768458SSam Leffler goto bad; 37188768458SSam Leffler } 37288768458SSam Leffler ip = mtod(m, struct ip *); 37388768458SSam Leffler /* Honor system-wide control of how to handle IP_DF */ 37488768458SSam Leffler switch (ip4_ipsec_dfbit) { 37588768458SSam Leffler case 0: /* clear in outer header */ 37688768458SSam Leffler case 1: /* set in outer header */ 37788768458SSam Leffler setdf = ip4_ipsec_dfbit; 37888768458SSam Leffler break; 37988768458SSam Leffler default: /* propagate to outer header */ 38088768458SSam Leffler setdf = ntohs(ip->ip_off & IP_DF); 38188768458SSam Leffler break; 38288768458SSam Leffler } 38388768458SSam Leffler } else { 38488768458SSam Leffler ip = NULL; /* keep compiler happy */ 38588768458SSam Leffler setdf = 0; 38688768458SSam Leffler } 38788768458SSam Leffler /* Do the appropriate encapsulation, if necessary */ 38888768458SSam Leffler if (isr->saidx.mode == IPSEC_MODE_TUNNEL || /* Tunnel requ'd */ 38988768458SSam Leffler dst->sa.sa_family != AF_INET || /* PF mismatch */ 39088768458SSam Leffler #if 0 39188768458SSam Leffler (sav->flags & SADB_X_SAFLAGS_TUNNEL) || /* Tunnel requ'd */ 39288768458SSam Leffler sav->tdb_xform->xf_type == XF_IP4 || /* ditto */ 39388768458SSam Leffler #endif 39488768458SSam Leffler (dst->sa.sa_family == AF_INET && /* Proxy */ 39588768458SSam Leffler dst->sin.sin_addr.s_addr != INADDR_ANY && 39688768458SSam Leffler dst->sin.sin_addr.s_addr != ip->ip_dst.s_addr)) { 39788768458SSam Leffler struct mbuf *mp; 39888768458SSam Leffler 39988768458SSam Leffler /* Fix IPv4 header checksum and length */ 40088768458SSam Leffler if (m->m_len < sizeof (struct ip) && 40188768458SSam Leffler (m = m_pullup(m, sizeof (struct ip))) == NULL) { 40288768458SSam Leffler error = ENOBUFS; 40388768458SSam Leffler goto bad; 40488768458SSam Leffler } 40588768458SSam Leffler ip = mtod(m, struct ip *); 40688768458SSam Leffler ip->ip_len = htons(m->m_pkthdr.len); 40788768458SSam Leffler ip->ip_sum = 0; 40888768458SSam Leffler #ifdef _IP_VHL 40988768458SSam Leffler if (ip->ip_vhl == IP_VHL_BORING) 41088768458SSam Leffler ip->ip_sum = in_cksum_hdr(ip); 41188768458SSam Leffler else 41288768458SSam Leffler ip->ip_sum = in_cksum(m, 41388768458SSam Leffler _IP_VHL_HL(ip->ip_vhl) << 2); 41488768458SSam Leffler #else 41588768458SSam Leffler ip->ip_sum = in_cksum(m, ip->ip_hl << 2); 41688768458SSam Leffler #endif 41788768458SSam Leffler 41888768458SSam Leffler /* Encapsulate the packet */ 41988768458SSam Leffler error = ipip_output(m, isr, &mp, 0, 0); 42088768458SSam Leffler if (mp == NULL && !error) { 42188768458SSam Leffler /* Should never happen. */ 42288768458SSam Leffler DPRINTF(("ipsec4_process_packet: ipip_output " 42388768458SSam Leffler "returns no mbuf and no error!")); 42488768458SSam Leffler error = EFAULT; 42588768458SSam Leffler } 42688768458SSam Leffler if (error) { 42788768458SSam Leffler if (mp) 42888768458SSam Leffler m_freem(mp); 42988768458SSam Leffler goto bad; 43088768458SSam Leffler } 43188768458SSam Leffler m = mp, mp = NULL; 43288768458SSam Leffler /* 43388768458SSam Leffler * ipip_output clears IP_DF in the new header. If 43488768458SSam Leffler * we need to propagate IP_DF from the outer header, 43588768458SSam Leffler * then we have to do it here. 43688768458SSam Leffler * 43788768458SSam Leffler * XXX shouldn't assume what ipip_output does. 43888768458SSam Leffler */ 43988768458SSam Leffler if (dst->sa.sa_family == AF_INET && setdf) { 44088768458SSam Leffler if (m->m_len < sizeof (struct ip) && 44188768458SSam Leffler (m = m_pullup(m, sizeof (struct ip))) == NULL) { 44288768458SSam Leffler error = ENOBUFS; 44388768458SSam Leffler goto bad; 44488768458SSam Leffler } 44588768458SSam Leffler ip = mtod(m, struct ip *); 44688768458SSam Leffler ip->ip_off = ntohs(ip->ip_off); 44788768458SSam Leffler ip->ip_off |= IP_DF; 44888768458SSam Leffler ip->ip_off = htons(ip->ip_off); 44988768458SSam Leffler } 45088768458SSam Leffler } 45188768458SSam Leffler } 45288768458SSam Leffler 45388768458SSam Leffler /* 45488768458SSam Leffler * Dispatch to the appropriate IPsec transform logic. The 45588768458SSam Leffler * packet will be returned for transmission after crypto 45688768458SSam Leffler * processing, etc. are completed. For encapsulation we 45788768458SSam Leffler * bypass this call because of the explicit call done above 45888768458SSam Leffler * (necessary to deal with IP_DF handling for IPv4). 45988768458SSam Leffler * 46088768458SSam Leffler * NB: m & sav are ``passed to caller'' who's reponsible for 46188768458SSam Leffler * for reclaiming their resources. 46288768458SSam Leffler */ 46388768458SSam Leffler if (sav->tdb_xform->xf_type != XF_IP4) { 46488768458SSam Leffler ip = mtod(m, struct ip *); 46588768458SSam Leffler i = ip->ip_hl << 2; 46688768458SSam Leffler off = offsetof(struct ip, ip_p); 46788768458SSam Leffler error = (*sav->tdb_xform->xf_output)(m, isr, NULL, i, off); 46888768458SSam Leffler } else { 46988768458SSam Leffler error = ipsec_process_done(m, isr); 47088768458SSam Leffler } 47188768458SSam Leffler splx(s); 47288768458SSam Leffler return error; 47388768458SSam Leffler bad: 47488768458SSam Leffler splx(s); 47588768458SSam Leffler if (m) 47688768458SSam Leffler m_freem(m); 47788768458SSam Leffler return error; 47888768458SSam Leffler } 47988768458SSam Leffler #endif 48088768458SSam Leffler 48188768458SSam Leffler #ifdef INET6 48288768458SSam Leffler /* 48388768458SSam Leffler * Chop IP6 header from the payload. 48488768458SSam Leffler */ 48588768458SSam Leffler static struct mbuf * 48688768458SSam Leffler ipsec6_splithdr(struct mbuf *m) 48788768458SSam Leffler { 48888768458SSam Leffler struct mbuf *mh; 48988768458SSam Leffler struct ip6_hdr *ip6; 49088768458SSam Leffler int hlen; 49188768458SSam Leffler 49288768458SSam Leffler KASSERT(m->m_len >= sizeof (struct ip6_hdr), 49388768458SSam Leffler ("ipsec6_splithdr: first mbuf too short, len %u", m->m_len)); 49488768458SSam Leffler ip6 = mtod(m, struct ip6_hdr *); 49588768458SSam Leffler hlen = sizeof(struct ip6_hdr); 49688768458SSam Leffler if (m->m_len > hlen) { 497a163d034SWarner Losh MGETHDR(mh, M_DONTWAIT, MT_HEADER); 49888768458SSam Leffler if (!mh) { 49988768458SSam Leffler m_freem(m); 50088768458SSam Leffler return NULL; 50188768458SSam Leffler } 5029967cafcSSam Leffler M_MOVE_PKTHDR(mh, m); 50388768458SSam Leffler MH_ALIGN(mh, hlen); 50488768458SSam Leffler m->m_len -= hlen; 50588768458SSam Leffler m->m_data += hlen; 50688768458SSam Leffler mh->m_next = m; 50788768458SSam Leffler m = mh; 50888768458SSam Leffler m->m_len = hlen; 50988768458SSam Leffler bcopy((caddr_t)ip6, mtod(m, caddr_t), hlen); 51088768458SSam Leffler } else if (m->m_len < hlen) { 51188768458SSam Leffler m = m_pullup(m, hlen); 51288768458SSam Leffler if (!m) 51388768458SSam Leffler return NULL; 51488768458SSam Leffler } 51588768458SSam Leffler return m; 51688768458SSam Leffler } 51788768458SSam Leffler 51888768458SSam Leffler /* 51988768458SSam Leffler * IPsec output logic for IPv6, transport mode. 52088768458SSam Leffler */ 52188768458SSam Leffler int 52288768458SSam Leffler ipsec6_output_trans( 52388768458SSam Leffler struct ipsec_output_state *state, 52488768458SSam Leffler u_char *nexthdrp, 52588768458SSam Leffler struct mbuf *mprev, 52688768458SSam Leffler struct secpolicy *sp, 52788768458SSam Leffler int flags, 52888768458SSam Leffler int *tun) 52988768458SSam Leffler { 53088768458SSam Leffler struct ipsecrequest *isr; 53188768458SSam Leffler struct secasindex saidx; 53288768458SSam Leffler int error = 0; 53388768458SSam Leffler struct mbuf *m; 53488768458SSam Leffler 53588768458SSam Leffler KASSERT(state != NULL, ("ipsec6_output: null state")); 53688768458SSam Leffler KASSERT(state->m != NULL, ("ipsec6_output: null m")); 53788768458SSam Leffler KASSERT(nexthdrp != NULL, ("ipsec6_output: null nexthdrp")); 53888768458SSam Leffler KASSERT(mprev != NULL, ("ipsec6_output: null mprev")); 53988768458SSam Leffler KASSERT(sp != NULL, ("ipsec6_output: null sp")); 54088768458SSam Leffler KASSERT(tun != NULL, ("ipsec6_output: null tun")); 54188768458SSam Leffler 54288768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DATA, 54388768458SSam Leffler printf("ipsec6_output_trans: applyed SP\n"); 54488768458SSam Leffler kdebug_secpolicy(sp)); 54588768458SSam Leffler 54688768458SSam Leffler isr = sp->req; 54788768458SSam Leffler if (isr->saidx.mode == IPSEC_MODE_TUNNEL) { 54888768458SSam Leffler /* the rest will be handled by ipsec6_output_tunnel() */ 54988768458SSam Leffler *tun = 1; /* need tunnel-mode processing */ 55088768458SSam Leffler return 0; 55188768458SSam Leffler } 55288768458SSam Leffler 55388768458SSam Leffler *tun = 0; 55488768458SSam Leffler m = state->m; 55588768458SSam Leffler 55688768458SSam Leffler isr = ipsec_nextisr(m, isr, AF_INET6, &saidx, &error); 55788768458SSam Leffler if (isr == NULL) { 55888768458SSam Leffler #ifdef notdef 55988768458SSam Leffler /* XXX should notification be done for all errors ? */ 56088768458SSam Leffler /* 56188768458SSam Leffler * Notify the fact that the packet is discarded 56288768458SSam Leffler * to ourselves. I believe this is better than 56388768458SSam Leffler * just silently discarding. (jinmei@kame.net) 56488768458SSam Leffler * XXX: should we restrict the error to TCP packets? 56588768458SSam Leffler * XXX: should we directly notify sockets via 56688768458SSam Leffler * pfctlinputs? 56788768458SSam Leffler */ 56888768458SSam Leffler icmp6_error(m, ICMP6_DST_UNREACH, 56988768458SSam Leffler ICMP6_DST_UNREACH_ADMIN, 0); 57088768458SSam Leffler m = NULL; /* NB: icmp6_error frees mbuf */ 57188768458SSam Leffler #endif 57288768458SSam Leffler goto bad; 57388768458SSam Leffler } 57488768458SSam Leffler 57588768458SSam Leffler return (*isr->sav->tdb_xform->xf_output)(m, isr, NULL, 57688768458SSam Leffler sizeof (struct ip6_hdr), 57788768458SSam Leffler offsetof(struct ip6_hdr, ip6_nxt)); 57888768458SSam Leffler bad: 57988768458SSam Leffler if (m) 58088768458SSam Leffler m_freem(m); 58188768458SSam Leffler state->m = NULL; 58288768458SSam Leffler return error; 58388768458SSam Leffler } 58488768458SSam Leffler 58588768458SSam Leffler static int 58688768458SSam Leffler ipsec6_encapsulate(struct mbuf *m, struct secasvar *sav) 58788768458SSam Leffler { 58888768458SSam Leffler struct ip6_hdr *oip6; 58988768458SSam Leffler struct ip6_hdr *ip6; 59088768458SSam Leffler size_t plen; 59188768458SSam Leffler 59288768458SSam Leffler /* can't tunnel between different AFs */ 59388768458SSam Leffler if (sav->sah->saidx.src.sa.sa_family != AF_INET6 || 59488768458SSam Leffler sav->sah->saidx.dst.sa.sa_family != AF_INET6) { 59588768458SSam Leffler m_freem(m); 59688768458SSam Leffler return EINVAL; 59788768458SSam Leffler } 59888768458SSam Leffler KASSERT(m->m_len != sizeof (struct ip6_hdr), 59988768458SSam Leffler ("ipsec6_encapsulate: mbuf wrong size; len %u", m->m_len)); 60088768458SSam Leffler 60188768458SSam Leffler 60288768458SSam Leffler /* 60388768458SSam Leffler * grow the mbuf to accomodate the new IPv6 header. 60488768458SSam Leffler */ 60588768458SSam Leffler plen = m->m_pkthdr.len; 60688768458SSam Leffler if (M_LEADINGSPACE(m->m_next) < sizeof(struct ip6_hdr)) { 60788768458SSam Leffler struct mbuf *n; 608a163d034SWarner Losh MGET(n, M_DONTWAIT, MT_DATA); 60988768458SSam Leffler if (!n) { 61088768458SSam Leffler m_freem(m); 61188768458SSam Leffler return ENOBUFS; 61288768458SSam Leffler } 61388768458SSam Leffler n->m_len = sizeof(struct ip6_hdr); 61488768458SSam Leffler n->m_next = m->m_next; 61588768458SSam Leffler m->m_next = n; 61688768458SSam Leffler m->m_pkthdr.len += sizeof(struct ip6_hdr); 61788768458SSam Leffler oip6 = mtod(n, struct ip6_hdr *); 61888768458SSam Leffler } else { 61988768458SSam Leffler m->m_next->m_len += sizeof(struct ip6_hdr); 62088768458SSam Leffler m->m_next->m_data -= sizeof(struct ip6_hdr); 62188768458SSam Leffler m->m_pkthdr.len += sizeof(struct ip6_hdr); 62288768458SSam Leffler oip6 = mtod(m->m_next, struct ip6_hdr *); 62388768458SSam Leffler } 62488768458SSam Leffler ip6 = mtod(m, struct ip6_hdr *); 62588768458SSam Leffler ovbcopy((caddr_t)ip6, (caddr_t)oip6, sizeof(struct ip6_hdr)); 62688768458SSam Leffler 62788768458SSam Leffler /* Fake link-local scope-class addresses */ 62888768458SSam Leffler if (IN6_IS_SCOPE_LINKLOCAL(&oip6->ip6_src)) 62988768458SSam Leffler oip6->ip6_src.s6_addr16[1] = 0; 63088768458SSam Leffler if (IN6_IS_SCOPE_LINKLOCAL(&oip6->ip6_dst)) 63188768458SSam Leffler oip6->ip6_dst.s6_addr16[1] = 0; 63288768458SSam Leffler 63388768458SSam Leffler /* construct new IPv6 header. see RFC 2401 5.1.2.2 */ 63488768458SSam Leffler /* ECN consideration. */ 63588768458SSam Leffler ip6_ecn_ingress(ip6_ipsec_ecn, &ip6->ip6_flow, &oip6->ip6_flow); 63688768458SSam Leffler if (plen < IPV6_MAXPACKET - sizeof(struct ip6_hdr)) 63788768458SSam Leffler ip6->ip6_plen = htons(plen); 63888768458SSam Leffler else { 63988768458SSam Leffler /* ip6->ip6_plen will be updated in ip6_output() */ 64088768458SSam Leffler } 64188768458SSam Leffler ip6->ip6_nxt = IPPROTO_IPV6; 64288768458SSam Leffler sav->sah->saidx.src.sin6.sin6_addr = ip6->ip6_src; 64388768458SSam Leffler sav->sah->saidx.dst.sin6.sin6_addr = ip6->ip6_dst; 64488768458SSam Leffler ip6->ip6_hlim = IPV6_DEFHLIM; 64588768458SSam Leffler 64688768458SSam Leffler /* XXX Should ip6_src be updated later ? */ 64788768458SSam Leffler 64888768458SSam Leffler return 0; 64988768458SSam Leffler } 65088768458SSam Leffler 65188768458SSam Leffler /* 65288768458SSam Leffler * IPsec output logic for IPv6, tunnel mode. 65388768458SSam Leffler */ 65488768458SSam Leffler int 65588768458SSam Leffler ipsec6_output_tunnel(struct ipsec_output_state *state, struct secpolicy *sp, int flags) 65688768458SSam Leffler { 65788768458SSam Leffler struct ip6_hdr *ip6; 65888768458SSam Leffler struct ipsecrequest *isr; 65988768458SSam Leffler struct secasindex saidx; 66088768458SSam Leffler int error; 66188768458SSam Leffler struct sockaddr_in6* dst6; 66288768458SSam Leffler struct mbuf *m; 66388768458SSam Leffler 66488768458SSam Leffler KASSERT(state != NULL, ("ipsec6_output: null state")); 66588768458SSam Leffler KASSERT(state->m != NULL, ("ipsec6_output: null m")); 66688768458SSam Leffler KASSERT(sp != NULL, ("ipsec6_output: null sp")); 66788768458SSam Leffler 66888768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DATA, 66988768458SSam Leffler printf("ipsec6_output_tunnel: applyed SP\n"); 67088768458SSam Leffler kdebug_secpolicy(sp)); 67188768458SSam Leffler 67288768458SSam Leffler m = state->m; 67388768458SSam Leffler /* 67488768458SSam Leffler * transport mode ipsec (before the 1st tunnel mode) is already 67588768458SSam Leffler * processed by ipsec6_output_trans(). 67688768458SSam Leffler */ 67788768458SSam Leffler for (isr = sp->req; isr; isr = isr->next) { 67888768458SSam Leffler if (isr->saidx.mode == IPSEC_MODE_TUNNEL) 67988768458SSam Leffler break; 68088768458SSam Leffler } 68188768458SSam Leffler isr = ipsec_nextisr(m, isr, AF_INET6, &saidx, &error); 68288768458SSam Leffler if (isr == NULL) 68388768458SSam Leffler goto bad; 68488768458SSam Leffler 68588768458SSam Leffler /* 68688768458SSam Leffler * There may be the case that SA status will be changed when 68788768458SSam Leffler * we are refering to one. So calling splsoftnet(). 68888768458SSam Leffler */ 68988768458SSam Leffler if (isr->saidx.mode == IPSEC_MODE_TUNNEL) { 69088768458SSam Leffler /* 69188768458SSam Leffler * build IPsec tunnel. 69288768458SSam Leffler */ 69388768458SSam Leffler /* XXX should be processed with other familiy */ 69488768458SSam Leffler if (isr->sav->sah->saidx.src.sa.sa_family != AF_INET6) { 69588768458SSam Leffler ipseclog((LOG_ERR, "ipsec6_output_tunnel: " 69688768458SSam Leffler "family mismatched between inner and outer, spi=%u\n", 69788768458SSam Leffler ntohl(isr->sav->spi))); 69888768458SSam Leffler newipsecstat.ips_out_inval++; 69988768458SSam Leffler error = EAFNOSUPPORT; 70088768458SSam Leffler goto bad; 70188768458SSam Leffler } 70288768458SSam Leffler 70388768458SSam Leffler m = ipsec6_splithdr(m); 70488768458SSam Leffler if (!m) { 70588768458SSam Leffler newipsecstat.ips_out_nomem++; 70688768458SSam Leffler error = ENOMEM; 70788768458SSam Leffler goto bad; 70888768458SSam Leffler } 70988768458SSam Leffler error = ipsec6_encapsulate(m, isr->sav); 71088768458SSam Leffler if (error) { 71188768458SSam Leffler m = NULL; 71288768458SSam Leffler goto bad; 71388768458SSam Leffler } 71488768458SSam Leffler ip6 = mtod(m, struct ip6_hdr *); 71588768458SSam Leffler 71688768458SSam Leffler state->ro = &isr->sav->sah->sa_route; 71788768458SSam Leffler state->dst = (struct sockaddr *)&state->ro->ro_dst; 71888768458SSam Leffler dst6 = (struct sockaddr_in6 *)state->dst; 71988768458SSam Leffler if (state->ro->ro_rt 72088768458SSam Leffler && ((state->ro->ro_rt->rt_flags & RTF_UP) == 0 72188768458SSam Leffler || !IN6_ARE_ADDR_EQUAL(&dst6->sin6_addr, &ip6->ip6_dst))) { 72288768458SSam Leffler RTFREE(state->ro->ro_rt); 72388768458SSam Leffler state->ro->ro_rt = NULL; 72488768458SSam Leffler } 72588768458SSam Leffler if (state->ro->ro_rt == 0) { 72688768458SSam Leffler bzero(dst6, sizeof(*dst6)); 72788768458SSam Leffler dst6->sin6_family = AF_INET6; 72888768458SSam Leffler dst6->sin6_len = sizeof(*dst6); 72988768458SSam Leffler dst6->sin6_addr = ip6->ip6_dst; 73088768458SSam Leffler rtalloc(state->ro); 73188768458SSam Leffler } 73288768458SSam Leffler if (state->ro->ro_rt == 0) { 73388768458SSam Leffler ip6stat.ip6s_noroute++; 73488768458SSam Leffler newipsecstat.ips_out_noroute++; 73588768458SSam Leffler error = EHOSTUNREACH; 73688768458SSam Leffler goto bad; 73788768458SSam Leffler } 73888768458SSam Leffler 73988768458SSam Leffler /* adjust state->dst if tunnel endpoint is offlink */ 74088768458SSam Leffler if (state->ro->ro_rt->rt_flags & RTF_GATEWAY) { 74188768458SSam Leffler state->dst = (struct sockaddr *)state->ro->ro_rt->rt_gateway; 74288768458SSam Leffler dst6 = (struct sockaddr_in6 *)state->dst; 74388768458SSam Leffler } 74488768458SSam Leffler } 74588768458SSam Leffler 74688768458SSam Leffler m = ipsec6_splithdr(m); 74788768458SSam Leffler if (!m) { 74888768458SSam Leffler newipsecstat.ips_out_nomem++; 74988768458SSam Leffler error = ENOMEM; 75088768458SSam Leffler goto bad; 75188768458SSam Leffler } 75288768458SSam Leffler ip6 = mtod(m, struct ip6_hdr *); 75388768458SSam Leffler return (*isr->sav->tdb_xform->xf_output)(m, isr, NULL, 75488768458SSam Leffler sizeof (struct ip6_hdr), 75588768458SSam Leffler offsetof(struct ip6_hdr, ip6_nxt)); 75688768458SSam Leffler bad: 75788768458SSam Leffler if (m) 75888768458SSam Leffler m_freem(m); 75988768458SSam Leffler state->m = NULL; 76088768458SSam Leffler return error; 76188768458SSam Leffler } 76288768458SSam Leffler #endif /*INET6*/ 763