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