ipsec_output.c revision 319599
1112758Ssam/*- 2112758Ssam * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting 3315514Sae * Copyright (c) 2016 Andrey V. Elsukov <ae@FreeBSD.org> 4112758Ssam * All rights reserved. 5112758Ssam * 6112758Ssam * Redistribution and use in source and binary forms, with or without 7112758Ssam * modification, are permitted provided that the following conditions 8112758Ssam * are met: 9112758Ssam * 1. Redistributions of source code must retain the above copyright 10112758Ssam * notice, this list of conditions and the following disclaimer. 11112758Ssam * 2. Redistributions in binary form must reproduce the above copyright 12112758Ssam * notice, this list of conditions and the following disclaimer in the 13112758Ssam * documentation and/or other materials provided with the distribution. 14112758Ssam * 15112758Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16112758Ssam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17112758Ssam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18112758Ssam * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19112758Ssam * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20112758Ssam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21112758Ssam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22112758Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23112758Ssam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24112758Ssam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25112758Ssam * SUCH DAMAGE. 26112758Ssam * 27112758Ssam * $FreeBSD: stable/11/sys/netipsec/ipsec_output.c 319599 2017-06-05 11:11:07Z ae $ 28112758Ssam */ 29105197Ssam 30105197Ssam/* 31105197Ssam * IPsec output processing. 32105197Ssam */ 33105197Ssam#include "opt_inet.h" 34105197Ssam#include "opt_inet6.h" 35105197Ssam#include "opt_ipsec.h" 36315514Sae#include "opt_sctp.h" 37105197Ssam 38105197Ssam#include <sys/param.h> 39105197Ssam#include <sys/systm.h> 40105197Ssam#include <sys/mbuf.h> 41105197Ssam#include <sys/domain.h> 42105197Ssam#include <sys/protosw.h> 43105197Ssam#include <sys/socket.h> 44105197Ssam#include <sys/errno.h> 45291292Sae#include <sys/hhook.h> 46105197Ssam#include <sys/syslog.h> 47105197Ssam 48105197Ssam#include <net/if.h> 49291292Sae#include <net/if_enc.h> 50257176Sglebius#include <net/if_var.h> 51195699Srwatson#include <net/vnet.h> 52105197Ssam 53105197Ssam#include <netinet/in.h> 54105197Ssam#include <netinet/in_systm.h> 55105197Ssam#include <netinet/ip.h> 56105197Ssam#include <netinet/ip_var.h> 57105197Ssam#include <netinet/in_var.h> 58105197Ssam#include <netinet/ip_ecn.h> 59105197Ssam#ifdef INET6 60105197Ssam#include <netinet6/ip6_ecn.h> 61105197Ssam#endif 62105197Ssam 63105197Ssam#include <netinet/ip6.h> 64105197Ssam#ifdef INET6 65105197Ssam#include <netinet6/ip6_var.h> 66281692Sae#include <netinet6/scope6_var.h> 67105197Ssam#endif 68105197Ssam#include <netinet/in_pcb.h> 69105197Ssam#ifdef INET6 70105197Ssam#include <netinet/icmp6.h> 71105197Ssam#endif 72315514Sae#ifdef SCTP 73315514Sae#include <netinet/sctp_crc32.h> 74315514Sae#endif 75105197Ssam 76315514Sae#include <netinet/udp.h> 77315514Sae#include <netipsec/ah.h> 78315514Sae#include <netipsec/esp.h> 79105197Ssam#include <netipsec/ipsec.h> 80105197Ssam#ifdef INET6 81105197Ssam#include <netipsec/ipsec6.h> 82105197Ssam#endif 83105197Ssam#include <netipsec/ah_var.h> 84105197Ssam#include <netipsec/esp_var.h> 85105197Ssam#include <netipsec/ipcomp_var.h> 86105197Ssam 87105197Ssam#include <netipsec/xform.h> 88105197Ssam 89105197Ssam#include <netipsec/key.h> 90105197Ssam#include <netipsec/keydb.h> 91105197Ssam#include <netipsec/key_debug.h> 92105197Ssam 93105197Ssam#include <machine/in_cksum.h> 94105197Ssam 95315514Sae#define IPSEC_OSTAT_INC(proto, name) do { \ 96315514Sae if ((proto) == IPPROTO_ESP) \ 97315514Sae ESPSTAT_INC(esps_##name); \ 98315514Sae else if ((proto) == IPPROTO_AH)\ 99315514Sae AHSTAT_INC(ahs_##name); \ 100315514Sae else \ 101315514Sae IPCOMPSTAT_INC(ipcomps_##name); \ 102315514Sae} while (0) 103315514Sae 104315514Saestatic int ipsec_encap(struct mbuf **mp, struct secasindex *saidx); 105315514Sae 106315514Sae#ifdef INET 107315514Saestatic struct secasvar * 108315514Saeipsec4_allocsa(struct mbuf *m, struct secpolicy *sp, u_int *pidx, int *error) 109315514Sae{ 110315514Sae struct secasindex *saidx, tmpsaidx; 111315514Sae struct ipsecrequest *isr; 112315514Sae struct sockaddr_in *sin; 113315514Sae struct secasvar *sav; 114315514Sae struct ip *ip; 115315514Sae 116315514Sae /* 117315514Sae * Check system global policy controls. 118315514Sae */ 119315514Saenext: 120315514Sae isr = sp->req[*pidx]; 121315514Sae if ((isr->saidx.proto == IPPROTO_ESP && !V_esp_enable) || 122315514Sae (isr->saidx.proto == IPPROTO_AH && !V_ah_enable) || 123315514Sae (isr->saidx.proto == IPPROTO_IPCOMP && !V_ipcomp_enable)) { 124315514Sae DPRINTF(("%s: IPsec outbound packet dropped due" 125315514Sae " to policy (check your sysctls)\n", __func__)); 126315514Sae IPSEC_OSTAT_INC(isr->saidx.proto, pdrops); 127315514Sae *error = EHOSTUNREACH; 128315514Sae return (NULL); 129315514Sae } 130315514Sae /* 131315514Sae * Craft SA index to search for proper SA. Note that 132315514Sae * we only initialize unspecified SA peers for transport 133315514Sae * mode; for tunnel mode they must already be filled in. 134315514Sae */ 135315514Sae if (isr->saidx.mode == IPSEC_MODE_TRANSPORT) { 136315514Sae saidx = &tmpsaidx; 137315514Sae *saidx = isr->saidx; 138315514Sae ip = mtod(m, struct ip *); 139315514Sae if (saidx->src.sa.sa_len == 0) { 140315514Sae sin = &saidx->src.sin; 141315514Sae sin->sin_len = sizeof(*sin); 142315514Sae sin->sin_family = AF_INET; 143315514Sae sin->sin_port = IPSEC_PORT_ANY; 144315514Sae sin->sin_addr = ip->ip_src; 145315514Sae } 146315514Sae if (saidx->dst.sa.sa_len == 0) { 147315514Sae sin = &saidx->dst.sin; 148315514Sae sin->sin_len = sizeof(*sin); 149315514Sae sin->sin_family = AF_INET; 150315514Sae sin->sin_port = IPSEC_PORT_ANY; 151315514Sae sin->sin_addr = ip->ip_dst; 152315514Sae } 153315514Sae } else 154315514Sae saidx = &sp->req[*pidx]->saidx; 155315514Sae /* 156315514Sae * Lookup SA and validate it. 157315514Sae */ 158315514Sae sav = key_allocsa_policy(sp, saidx, error); 159315514Sae if (sav == NULL) { 160315514Sae IPSECSTAT_INC(ips_out_nosa); 161315514Sae if (*error != 0) 162315514Sae return (NULL); 163315514Sae if (ipsec_get_reqlevel(sp, *pidx) != IPSEC_LEVEL_REQUIRE) { 164315514Sae /* 165315514Sae * We have no SA and policy that doesn't require 166315514Sae * this IPsec transform, thus we can continue w/o 167315514Sae * IPsec processing, i.e. return EJUSTRETURN. 168315514Sae * But first check if there is some bundled transform. 169315514Sae */ 170315514Sae if (sp->tcount > ++(*pidx)) 171315514Sae goto next; 172315514Sae *error = EJUSTRETURN; 173315514Sae } 174315514Sae return (NULL); 175315514Sae } 176315514Sae IPSEC_ASSERT(sav->tdb_xform != NULL, ("SA with NULL tdb_xform")); 177315514Sae return (sav); 178315514Sae} 179315514Sae 180315514Sae/* 181315514Sae * IPsec output logic for IPv4. 182315514Sae */ 183315514Saestatic int 184315514Saeipsec4_perform_request(struct mbuf *m, struct secpolicy *sp, u_int idx) 185315514Sae{ 186315514Sae struct ipsec_ctx_data ctx; 187315514Sae union sockaddr_union *dst; 188315514Sae struct secasvar *sav; 189315514Sae struct ip *ip; 190315514Sae int error, i, off; 191315514Sae 192315514Sae IPSEC_ASSERT(idx < sp->tcount, ("Wrong IPsec request index %d", idx)); 193315514Sae 194315514Sae /* 195315514Sae * We hold the reference to SP. Content of SP couldn't be changed. 196315514Sae * Craft secasindex and do lookup for suitable SA. 197315514Sae * Then do encapsulation if needed and call xform's output. 198315514Sae * We need to store SP in the xform callback parameters. 199315514Sae * In xform callback we will extract SP and it can be used to 200315514Sae * determine next transform. At the end of transform we can 201315514Sae * release reference to SP. 202315514Sae */ 203315514Sae sav = ipsec4_allocsa(m, sp, &idx, &error); 204315514Sae if (sav == NULL) { 205315514Sae if (error == EJUSTRETURN) { /* No IPsec required */ 206315514Sae key_freesp(&sp); 207315514Sae return (error); 208315514Sae } 209315514Sae goto bad; 210315514Sae } 211315514Sae /* 212315514Sae * XXXAE: most likely ip_sum at this point is wrong. 213315514Sae */ 214315514Sae IPSEC_INIT_CTX(&ctx, &m, sav, AF_INET, IPSEC_ENC_BEFORE); 215315514Sae if ((error = ipsec_run_hhooks(&ctx, HHOOK_TYPE_IPSEC_OUT)) != 0) 216315514Sae goto bad; 217315514Sae 218315514Sae ip = mtod(m, struct ip *); 219315514Sae dst = &sav->sah->saidx.dst; 220315514Sae /* Do the appropriate encapsulation, if necessary */ 221315514Sae if (sp->req[idx]->saidx.mode == IPSEC_MODE_TUNNEL || /* Tunnel requ'd */ 222315514Sae dst->sa.sa_family != AF_INET || /* PF mismatch */ 223315514Sae (dst->sa.sa_family == AF_INET && /* Proxy */ 224315514Sae dst->sin.sin_addr.s_addr != INADDR_ANY && 225315514Sae dst->sin.sin_addr.s_addr != ip->ip_dst.s_addr)) { 226315514Sae /* Fix IPv4 header checksum and length */ 227315514Sae ip->ip_len = htons(m->m_pkthdr.len); 228315514Sae ip->ip_sum = 0; 229315514Sae ip->ip_sum = in_cksum(m, ip->ip_hl << 2); 230315514Sae error = ipsec_encap(&m, &sav->sah->saidx); 231315514Sae if (error != 0) { 232319599Sae DPRINTF(("%s: encapsulation for SPI 0x%08x failed " 233319599Sae "with error %d\n", __func__, ntohl(sav->spi), 234319599Sae error)); 235315514Sae /* XXXAE: IPSEC_OSTAT_INC(tunnel); */ 236315514Sae goto bad; 237315514Sae } 238315514Sae } 239315514Sae 240315514Sae IPSEC_INIT_CTX(&ctx, &m, sav, dst->sa.sa_family, IPSEC_ENC_AFTER); 241315514Sae if ((error = ipsec_run_hhooks(&ctx, HHOOK_TYPE_IPSEC_OUT)) != 0) 242315514Sae goto bad; 243315514Sae 244315514Sae /* 245315514Sae * Dispatch to the appropriate IPsec transform logic. The 246315514Sae * packet will be returned for transmission after crypto 247315514Sae * processing, etc. are completed. 248315514Sae * 249315514Sae * NB: m & sav are ``passed to caller'' who's responsible for 250315514Sae * reclaiming their resources. 251315514Sae */ 252315514Sae switch(dst->sa.sa_family) { 253315514Sae case AF_INET: 254315514Sae ip = mtod(m, struct ip *); 255315514Sae i = ip->ip_hl << 2; 256315514Sae off = offsetof(struct ip, ip_p); 257315514Sae break; 258315514Sae#ifdef INET6 259315514Sae case AF_INET6: 260315514Sae i = sizeof(struct ip6_hdr); 261315514Sae off = offsetof(struct ip6_hdr, ip6_nxt); 262315514Sae break; 263315514Sae#endif /* INET6 */ 264315514Sae default: 265315514Sae DPRINTF(("%s: unsupported protocol family %u\n", 266315514Sae __func__, dst->sa.sa_family)); 267315514Sae error = EPFNOSUPPORT; 268315514Sae IPSEC_OSTAT_INC(sav->sah->saidx.proto, nopf); 269315514Sae goto bad; 270315514Sae } 271315514Sae error = (*sav->tdb_xform->xf_output)(m, sp, sav, idx, i, off); 272315514Sae return (error); 273315514Saebad: 274315514Sae IPSECSTAT_INC(ips_out_inval); 275315514Sae if (m != NULL) 276315514Sae m_freem(m); 277315514Sae if (sav != NULL) 278315514Sae key_freesav(&sav); 279315514Sae key_freesp(&sp); 280315514Sae return (error); 281315514Sae} 282315514Sae 283315514Saeint 284315514Saeipsec4_process_packet(struct mbuf *m, struct secpolicy *sp, 285315514Sae struct inpcb *inp) 286315514Sae{ 287315514Sae 288315514Sae return (ipsec4_perform_request(m, sp, 0)); 289315514Sae} 290315514Sae 291315514Saestatic int 292315514Saeipsec4_common_output(struct mbuf *m, struct inpcb *inp, int forwarding) 293315514Sae{ 294315514Sae struct secpolicy *sp; 295315514Sae int error; 296315514Sae 297315514Sae /* Lookup for the corresponding outbound security policy */ 298315514Sae sp = ipsec4_checkpolicy(m, inp, &error); 299315514Sae if (sp == NULL) { 300315514Sae if (error == -EINVAL) { 301315514Sae /* Discarded by policy. */ 302315514Sae m_freem(m); 303315514Sae return (EACCES); 304315514Sae } 305315514Sae return (0); /* No IPsec required. */ 306315514Sae } 307315514Sae 308315514Sae /* 309315514Sae * Usually we have to have tunnel mode IPsec security policy 310315514Sae * when we are forwarding a packet. Otherwise we could not handle 311315514Sae * encrypted replies, because they are not destined for us. But 312315514Sae * some users are doing source address translation for forwarded 313315514Sae * packets, and thus, even if they are forwarded, the replies will 314315514Sae * return back to us. 315315514Sae */ 316315514Sae if (!forwarding) { 317315514Sae /* 318315514Sae * Do delayed checksums now because we send before 319315514Sae * this is done in the normal processing path. 320315514Sae */ 321315514Sae if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { 322315514Sae in_delayed_cksum(m); 323315514Sae m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; 324315514Sae } 325315514Sae#ifdef SCTP 326315514Sae if (m->m_pkthdr.csum_flags & CSUM_SCTP) { 327315514Sae struct ip *ip = mtod(m, struct ip *); 328315514Sae 329315514Sae sctp_delayed_cksum(m, (uint32_t)(ip->ip_hl << 2)); 330315514Sae m->m_pkthdr.csum_flags &= ~CSUM_SCTP; 331315514Sae } 332194062Svanhu#endif 333315514Sae } 334315514Sae /* NB: callee frees mbuf and releases reference to SP */ 335315514Sae error = ipsec4_process_packet(m, sp, inp); 336315514Sae if (error == EJUSTRETURN) { 337315514Sae /* 338315514Sae * We had a SP with a level of 'use' and no SA. We 339315514Sae * will just continue to process the packet without 340315514Sae * IPsec processing and return without error. 341315514Sae */ 342315514Sae return (0); 343315514Sae } 344315514Sae if (error == 0) 345315514Sae return (EINPROGRESS); /* consumed by IPsec */ 346315514Sae return (error); 347315514Sae} 348194062Svanhu 349315514Sae/* 350315514Sae * IPSEC_OUTPUT() method implementation for IPv4. 351315514Sae * 0 - no IPsec handling needed 352315514Sae * other values - mbuf consumed by IPsec. 353315514Sae */ 354105197Ssamint 355315514Saeipsec4_output(struct mbuf *m, struct inpcb *inp) 356105197Ssam{ 357315514Sae 358315514Sae /* 359315514Sae * If the packet is resubmitted to ip_output (e.g. after 360315514Sae * AH, ESP, etc. processing), there will be a tag to bypass 361315514Sae * the lookup and related policy checking. 362315514Sae */ 363315514Sae if (m_tag_find(m, PACKET_TAG_IPSEC_OUT_DONE, NULL) != NULL) 364315514Sae return (0); 365315514Sae 366315514Sae return (ipsec4_common_output(m, inp, 0)); 367315514Sae} 368315514Sae 369315514Sae/* 370315514Sae * IPSEC_FORWARD() method implementation for IPv4. 371315514Sae * 0 - no IPsec handling needed 372315514Sae * other values - mbuf consumed by IPsec. 373315514Sae */ 374315514Saeint 375315514Saeipsec4_forward(struct mbuf *m) 376315514Sae{ 377315514Sae 378315514Sae /* 379315514Sae * Check if this packet has an active inbound SP and needs to be 380315514Sae * dropped instead of forwarded. 381315514Sae */ 382315514Sae if (ipsec4_in_reject(m, NULL) != 0) { 383315514Sae m_freem(m); 384315514Sae return (EACCES); 385315514Sae } 386315514Sae return (ipsec4_common_output(m, NULL, 1)); 387315514Sae} 388315514Sae#endif 389315514Sae 390315514Sae#ifdef INET6 391315514Saestatic int 392315514Saein6_sa_equal_addrwithscope(const struct sockaddr_in6 *sa, 393315514Sae const struct in6_addr *ia) 394315514Sae{ 395315514Sae struct in6_addr ia2; 396315514Sae 397315514Sae if (IN6_IS_SCOPE_LINKLOCAL(&sa->sin6_addr)) { 398315514Sae memcpy(&ia2, &sa->sin6_addr, sizeof(ia2)); 399315514Sae ia2.s6_addr16[1] = htons(sa->sin6_scope_id); 400315514Sae return (IN6_ARE_ADDR_EQUAL(ia, &ia2)); 401315514Sae } 402315514Sae return (IN6_ARE_ADDR_EQUAL(&sa->sin6_addr, ia)); 403315514Sae} 404315514Sae 405315514Saestatic struct secasvar * 406315514Saeipsec6_allocsa(struct mbuf *m, struct secpolicy *sp, u_int *pidx, int *error) 407315514Sae{ 408315514Sae struct secasindex *saidx, tmpsaidx; 409315514Sae struct ipsecrequest *isr; 410315514Sae struct sockaddr_in6 *sin6; 411105197Ssam struct secasvar *sav; 412315514Sae struct ip6_hdr *ip6; 413315514Sae 414315514Sae /* 415315514Sae * Check system global policy controls. 416315514Sae */ 417315514Saenext: 418315514Sae isr = sp->req[*pidx]; 419315514Sae if ((isr->saidx.proto == IPPROTO_ESP && !V_esp_enable) || 420315514Sae (isr->saidx.proto == IPPROTO_AH && !V_ah_enable) || 421315514Sae (isr->saidx.proto == IPPROTO_IPCOMP && !V_ipcomp_enable)) { 422315514Sae DPRINTF(("%s: IPsec outbound packet dropped due" 423315514Sae " to policy (check your sysctls)\n", __func__)); 424315514Sae IPSEC_OSTAT_INC(isr->saidx.proto, pdrops); 425315514Sae *error = EHOSTUNREACH; 426315514Sae return (NULL); 427315514Sae } 428315514Sae /* 429315514Sae * Craft SA index to search for proper SA. Note that 430315514Sae * we only fillin unspecified SA peers for transport 431315514Sae * mode; for tunnel mode they must already be filled in. 432315514Sae */ 433315514Sae if (isr->saidx.mode == IPSEC_MODE_TRANSPORT) { 434315514Sae saidx = &tmpsaidx; 435315514Sae *saidx = isr->saidx; 436315514Sae ip6 = mtod(m, struct ip6_hdr *); 437315514Sae if (saidx->src.sin6.sin6_len == 0) { 438315514Sae sin6 = (struct sockaddr_in6 *)&saidx->src; 439315514Sae sin6->sin6_len = sizeof(*sin6); 440315514Sae sin6->sin6_family = AF_INET6; 441315514Sae sin6->sin6_port = IPSEC_PORT_ANY; 442315514Sae sin6->sin6_addr = ip6->ip6_src; 443315514Sae if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) { 444315514Sae /* fix scope id for comparing SPD */ 445315514Sae sin6->sin6_addr.s6_addr16[1] = 0; 446315514Sae sin6->sin6_scope_id = 447315514Sae ntohs(ip6->ip6_src.s6_addr16[1]); 448315514Sae } 449315514Sae } 450315514Sae if (saidx->dst.sin6.sin6_len == 0) { 451315514Sae sin6 = (struct sockaddr_in6 *)&saidx->dst; 452315514Sae sin6->sin6_len = sizeof(*sin6); 453315514Sae sin6->sin6_family = AF_INET6; 454315514Sae sin6->sin6_port = IPSEC_PORT_ANY; 455315514Sae sin6->sin6_addr = ip6->ip6_dst; 456315514Sae if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) { 457315514Sae /* fix scope id for comparing SPD */ 458315514Sae sin6->sin6_addr.s6_addr16[1] = 0; 459315514Sae sin6->sin6_scope_id = 460315514Sae ntohs(ip6->ip6_dst.s6_addr16[1]); 461315514Sae } 462315514Sae } 463315514Sae } else 464315514Sae saidx = &sp->req[*pidx]->saidx; 465315514Sae /* 466315514Sae * Lookup SA and validate it. 467315514Sae */ 468315514Sae sav = key_allocsa_policy(sp, saidx, error); 469315514Sae if (sav == NULL) { 470315514Sae IPSEC6STAT_INC(ips_out_nosa); 471315514Sae if (*error != 0) 472315514Sae return (NULL); 473315514Sae if (ipsec_get_reqlevel(sp, *pidx) != IPSEC_LEVEL_REQUIRE) { 474315514Sae /* 475315514Sae * We have no SA and policy that doesn't require 476315514Sae * this IPsec transform, thus we can continue w/o 477315514Sae * IPsec processing, i.e. return EJUSTRETURN. 478315514Sae * But first check if there is some bundled transform. 479315514Sae */ 480315514Sae if (sp->tcount > ++(*pidx)) 481315514Sae goto next; 482315514Sae *error = EJUSTRETURN; 483315514Sae } 484315514Sae return (NULL); 485315514Sae } 486315514Sae IPSEC_ASSERT(sav->tdb_xform != NULL, ("SA with NULL tdb_xform")); 487315514Sae return (sav); 488315514Sae} 489315514Sae 490315514Sae/* 491315514Sae * IPsec output logic for IPv6. 492315514Sae */ 493315514Saestatic int 494315514Saeipsec6_perform_request(struct mbuf *m, struct secpolicy *sp, u_int idx) 495315514Sae{ 496315514Sae struct ipsec_ctx_data ctx; 497315514Sae union sockaddr_union *dst; 498315514Sae struct secasvar *sav; 499315514Sae struct ip6_hdr *ip6; 500315514Sae int error, i, off; 501315514Sae 502315514Sae IPSEC_ASSERT(idx < sp->tcount, ("Wrong IPsec request index %d", idx)); 503315514Sae 504315514Sae sav = ipsec6_allocsa(m, sp, &idx, &error); 505315514Sae if (sav == NULL) { 506315514Sae if (error == EJUSTRETURN) { /* No IPsec required */ 507315514Sae key_freesp(&sp); 508315514Sae return (error); 509315514Sae } 510315514Sae goto bad; 511315514Sae } 512315514Sae 513315514Sae /* Fix IP length in case if it is not set yet. */ 514315514Sae ip6 = mtod(m, struct ip6_hdr *); 515315514Sae ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6)); 516315514Sae 517315514Sae IPSEC_INIT_CTX(&ctx, &m, sav, AF_INET6, IPSEC_ENC_BEFORE); 518315514Sae if ((error = ipsec_run_hhooks(&ctx, HHOOK_TYPE_IPSEC_OUT)) != 0) 519315514Sae goto bad; 520315514Sae 521315514Sae ip6 = mtod(m, struct ip6_hdr *); /* pfil can change mbuf */ 522315514Sae dst = &sav->sah->saidx.dst; 523315514Sae 524315514Sae /* Do the appropriate encapsulation, if necessary */ 525315514Sae if (sp->req[idx]->saidx.mode == IPSEC_MODE_TUNNEL || /* Tunnel requ'd */ 526315514Sae dst->sa.sa_family != AF_INET6 || /* PF mismatch */ 527315514Sae ((dst->sa.sa_family == AF_INET6) && 528315514Sae (!IN6_IS_ADDR_UNSPECIFIED(&dst->sin6.sin6_addr)) && 529315514Sae (!in6_sa_equal_addrwithscope(&dst->sin6, &ip6->ip6_dst)))) { 530315514Sae if (m->m_pkthdr.len - sizeof(*ip6) > IPV6_MAXPACKET) { 531315514Sae /* No jumbogram support. */ 532315514Sae error = ENXIO; /*XXX*/ 533315514Sae goto bad; 534315514Sae } 535315514Sae error = ipsec_encap(&m, &sav->sah->saidx); 536315514Sae if (error != 0) { 537319599Sae DPRINTF(("%s: encapsulation for SPI 0x%08x failed " 538319599Sae "with error %d\n", __func__, ntohl(sav->spi), 539319599Sae error)); 540315514Sae /* XXXAE: IPSEC_OSTAT_INC(tunnel); */ 541315514Sae goto bad; 542315514Sae } 543315514Sae } 544315514Sae 545315514Sae IPSEC_INIT_CTX(&ctx, &m, sav, dst->sa.sa_family, IPSEC_ENC_AFTER); 546315514Sae if ((error = ipsec_run_hhooks(&ctx, HHOOK_TYPE_IPSEC_OUT)) != 0) 547315514Sae goto bad; 548315514Sae 549315514Sae switch(dst->sa.sa_family) { 550315514Sae#ifdef INET 551315514Sae case AF_INET: 552315514Sae { 553315514Sae struct ip *ip; 554315514Sae ip = mtod(m, struct ip *); 555315514Sae i = ip->ip_hl << 2; 556315514Sae off = offsetof(struct ip, ip_p); 557315514Sae } 558315514Sae break; 559315514Sae#endif /* AF_INET */ 560315514Sae case AF_INET6: 561315514Sae i = sizeof(struct ip6_hdr); 562315514Sae off = offsetof(struct ip6_hdr, ip6_nxt); 563315514Sae break; 564315514Sae default: 565315514Sae DPRINTF(("%s: unsupported protocol family %u\n", 566315514Sae __func__, dst->sa.sa_family)); 567315514Sae error = EPFNOSUPPORT; 568315514Sae IPSEC_OSTAT_INC(sav->sah->saidx.proto, nopf); 569315514Sae goto bad; 570315514Sae } 571315514Sae error = (*sav->tdb_xform->xf_output)(m, sp, sav, idx, i, off); 572315514Sae return (error); 573315514Saebad: 574315514Sae IPSEC6STAT_INC(ips_out_inval); 575315514Sae if (m != NULL) 576315514Sae m_freem(m); 577315514Sae if (sav != NULL) 578315514Sae key_freesav(&sav); 579315514Sae key_freesp(&sp); 580315514Sae return (error); 581315514Sae} 582315514Sae 583315514Saeint 584315514Saeipsec6_process_packet(struct mbuf *m, struct secpolicy *sp, 585315514Sae struct inpcb *inp) 586315514Sae{ 587315514Sae 588315514Sae return (ipsec6_perform_request(m, sp, 0)); 589315514Sae} 590315514Sae 591315514Saestatic int 592315514Saeipsec6_common_output(struct mbuf *m, struct inpcb *inp, int forwarding) 593315514Sae{ 594315514Sae struct secpolicy *sp; 595315514Sae int error; 596315514Sae 597315514Sae /* Lookup for the corresponding outbound security policy */ 598315514Sae sp = ipsec6_checkpolicy(m, inp, &error); 599315514Sae if (sp == NULL) { 600315514Sae if (error == -EINVAL) { 601315514Sae /* Discarded by policy. */ 602315514Sae m_freem(m); 603315514Sae return (EACCES); 604315514Sae } 605315514Sae return (0); /* No IPsec required. */ 606315514Sae } 607315514Sae 608315514Sae if (!forwarding) { 609315514Sae /* 610315514Sae * Do delayed checksums now because we send before 611315514Sae * this is done in the normal processing path. 612315514Sae */ 613315514Sae if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA_IPV6) { 614315514Sae in6_delayed_cksum(m, m->m_pkthdr.len - 615315514Sae sizeof(struct ip6_hdr), sizeof(struct ip6_hdr)); 616315514Sae m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA_IPV6; 617315514Sae } 618315514Sae#ifdef SCTP 619315514Sae if (m->m_pkthdr.csum_flags & CSUM_SCTP_IPV6) { 620315514Sae sctp_delayed_cksum(m, sizeof(struct ip6_hdr)); 621315514Sae m->m_pkthdr.csum_flags &= ~CSUM_SCTP_IPV6; 622315514Sae } 623315514Sae#endif 624315514Sae } 625315514Sae /* NB: callee frees mbuf and releases reference to SP */ 626315514Sae error = ipsec6_process_packet(m, sp, inp); 627315514Sae if (error == EJUSTRETURN) { 628315514Sae /* 629315514Sae * We had a SP with a level of 'use' and no SA. We 630315514Sae * will just continue to process the packet without 631315514Sae * IPsec processing and return without error. 632315514Sae */ 633315514Sae return (0); 634315514Sae } 635315514Sae if (error == 0) 636315514Sae return (EINPROGRESS); /* consumed by IPsec */ 637315514Sae return (error); 638315514Sae} 639315514Sae 640315514Sae/* 641315514Sae * IPSEC_OUTPUT() method implementation for IPv6. 642315514Sae * 0 - no IPsec handling needed 643315514Sae * other values - mbuf consumed by IPsec. 644315514Sae */ 645315514Saeint 646315514Saeipsec6_output(struct mbuf *m, struct inpcb *inp) 647315514Sae{ 648315514Sae 649315514Sae /* 650315514Sae * If the packet is resubmitted to ip_output (e.g. after 651315514Sae * AH, ESP, etc. processing), there will be a tag to bypass 652315514Sae * the lookup and related policy checking. 653315514Sae */ 654315514Sae if (m_tag_find(m, PACKET_TAG_IPSEC_OUT_DONE, NULL) != NULL) 655315514Sae return (0); 656315514Sae 657315514Sae return (ipsec6_common_output(m, inp, 0)); 658315514Sae} 659315514Sae 660315514Sae/* 661315514Sae * IPSEC_FORWARD() method implementation for IPv6. 662315514Sae * 0 - no IPsec handling needed 663315514Sae * other values - mbuf consumed by IPsec. 664315514Sae */ 665315514Saeint 666315514Saeipsec6_forward(struct mbuf *m) 667315514Sae{ 668315514Sae 669315514Sae /* 670315514Sae * Check if this packet has an active inbound SP and needs to be 671315514Sae * dropped instead of forwarded. 672315514Sae */ 673315514Sae if (ipsec6_in_reject(m, NULL) != 0) { 674315514Sae m_freem(m); 675315514Sae return (EACCES); 676315514Sae } 677315514Sae return (ipsec6_common_output(m, NULL, 1)); 678315514Sae} 679315514Sae#endif /* INET6 */ 680315514Sae 681315514Saeint 682315514Saeipsec_process_done(struct mbuf *m, struct secpolicy *sp, struct secasvar *sav, 683315514Sae u_int idx) 684315514Sae{ 685315514Sae struct xform_history *xh; 686105197Ssam struct secasindex *saidx; 687315514Sae struct m_tag *mtag; 688105197Ssam int error; 689105197Ssam 690105197Ssam saidx = &sav->sah->saidx; 691105197Ssam switch (saidx->dst.sa.sa_family) { 692105197Ssam#ifdef INET 693105197Ssam case AF_INET: 694105197Ssam /* Fix the header length, for AH processing. */ 695105197Ssam mtod(m, struct ip *)->ip_len = htons(m->m_pkthdr.len); 696105197Ssam break; 697105197Ssam#endif /* INET */ 698105197Ssam#ifdef INET6 699105197Ssam case AF_INET6: 700105197Ssam /* Fix the header length, for AH processing. */ 701105197Ssam if (m->m_pkthdr.len < sizeof (struct ip6_hdr)) { 702105197Ssam error = ENXIO; 703105197Ssam goto bad; 704105197Ssam } 705105197Ssam if (m->m_pkthdr.len - sizeof (struct ip6_hdr) > IPV6_MAXPACKET) { 706105197Ssam /* No jumbogram support. */ 707105197Ssam error = ENXIO; /*?*/ 708105197Ssam goto bad; 709105197Ssam } 710105197Ssam mtod(m, struct ip6_hdr *)->ip6_plen = 711105197Ssam htons(m->m_pkthdr.len - sizeof(struct ip6_hdr)); 712105197Ssam break; 713105197Ssam#endif /* INET6 */ 714105197Ssam default: 715120585Ssam DPRINTF(("%s: unknown protocol family %u\n", __func__, 716105197Ssam saidx->dst.sa.sa_family)); 717105197Ssam error = ENXIO; 718105197Ssam goto bad; 719105197Ssam } 720105197Ssam 721105197Ssam /* 722315514Sae * Add a record of what we've done to the packet. 723105197Ssam */ 724315514Sae mtag = m_tag_get(PACKET_TAG_IPSEC_OUT_DONE, sizeof(*xh), M_NOWAIT); 725105197Ssam if (mtag == NULL) { 726120585Ssam DPRINTF(("%s: could not get packet tag\n", __func__)); 727105197Ssam error = ENOMEM; 728105197Ssam goto bad; 729105197Ssam } 730105197Ssam 731315514Sae xh = (struct xform_history *)(mtag + 1); 732315514Sae xh->dst = saidx->dst; 733315514Sae xh->proto = saidx->proto; 734315514Sae xh->mode = saidx->mode; 735315514Sae xh->spi = sav->spi; 736105197Ssam m_tag_prepend(m, mtag); 737105197Ssam 738286095Seri key_sa_recordxfer(sav, m); /* record data transfer */ 739286095Seri 740105197Ssam /* 741105197Ssam * If there's another (bundled) SA to apply, do so. 742105197Ssam * Note that this puts a burden on the kernel stack size. 743105197Ssam * If this is a problem we'll need to introduce a queue 744105197Ssam * to set the packet on so we can unwind the stack before 745105197Ssam * doing further processing. 746105197Ssam */ 747315514Sae if (++idx < sp->tcount) { 748221129Sbz switch (saidx->dst.sa.sa_family) { 749221129Sbz#ifdef INET 750221129Sbz case AF_INET: 751315514Sae key_freesav(&sav); 752274467Sae IPSECSTAT_INC(ips_out_bundlesa); 753315514Sae return (ipsec4_perform_request(m, sp, idx)); 754221129Sbz /* NOTREACHED */ 755221129Sbz#endif 756221129Sbz#ifdef INET6 757221129Sbz case AF_INET6: 758315514Sae key_freesav(&sav); 759274467Sae IPSEC6STAT_INC(ips_out_bundlesa); 760315514Sae return (ipsec6_perform_request(m, sp, idx)); 761221129Sbz /* NOTREACHED */ 762221129Sbz#endif /* INET6 */ 763221129Sbz default: 764221129Sbz DPRINTF(("%s: unknown protocol family %u\n", __func__, 765221129Sbz saidx->dst.sa.sa_family)); 766315514Sae error = EPFNOSUPPORT; 767221129Sbz goto bad; 768221129Sbz } 769105197Ssam } 770105197Ssam 771315514Sae key_freesp(&sp), sp = NULL; /* Release reference to SP */ 772315514Sae#ifdef INET 773105197Ssam /* 774315514Sae * Do UDP encapsulation if SA requires it. 775315514Sae */ 776315514Sae if (sav->natt != NULL) { 777315514Sae error = udp_ipsec_output(m, sav); 778315514Sae if (error != 0) 779315514Sae goto bad; 780315514Sae } 781315514Sae#endif /* INET */ 782315514Sae /* 783105197Ssam * We're done with IPsec processing, transmit the packet using the 784282139Sae * appropriate network protocol (IP or IPv6). 785105197Ssam */ 786105197Ssam switch (saidx->dst.sa.sa_family) { 787105197Ssam#ifdef INET 788105197Ssam case AF_INET: 789315514Sae key_freesav(&sav); 790105197Ssam return ip_output(m, NULL, NULL, IP_RAWOUTPUT, NULL, NULL); 791105197Ssam#endif /* INET */ 792105197Ssam#ifdef INET6 793105197Ssam case AF_INET6: 794315514Sae key_freesav(&sav); 795105197Ssam return ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL); 796105197Ssam#endif /* INET6 */ 797105197Ssam } 798105197Ssam panic("ipsec_process_done"); 799105197Ssambad: 800105197Ssam m_freem(m); 801315514Sae key_freesav(&sav); 802315514Sae if (sp != NULL) 803315514Sae key_freesp(&sp); 804105197Ssam return (error); 805105197Ssam} 806105197Ssam 807315514Sae/* 808315514Sae * ipsec_prepend() is optimized version of M_PREPEND(). 809315514Sae * ipsec_encap() is called by IPsec output routine for tunnel mode SA. 810315514Sae * It is expected that after IP encapsulation some IPsec transform will 811315514Sae * be performed. Each IPsec transform inserts its variable length header 812315514Sae * just after outer IP header using m_makespace(). If given mbuf has not 813315514Sae * enough free space at the beginning, we allocate new mbuf and reserve 814315514Sae * some space at the beginning and at the end. 815315514Sae * This helps avoid allocating of new mbuf and data copying in m_makespace(), 816315514Sae * we place outer header in the middle of mbuf's data with reserved leading 817315514Sae * and trailing space: 818315514Sae * [ LEADINGSPACE ][ Outer IP header ][ TRAILINGSPACE ] 819315514Sae * LEADINGSPACE will be used to add ethernet header, TRAILINGSPACE will 820315514Sae * be used to inject AH/ESP/IPCOMP header. 821315514Sae */ 822315514Sae#define IPSEC_TRAILINGSPACE (sizeof(struct udphdr) +/* NAT-T */ \ 823315514Sae max(sizeof(struct newesp) + EALG_MAX_BLOCK_LEN, /* ESP + IV */ \ 824315514Sae sizeof(struct newah) + HASH_MAX_LEN /* AH + ICV */)) 825315514Saestatic struct mbuf * 826315514Saeipsec_prepend(struct mbuf *m, int len, int how) 827105197Ssam{ 828315514Sae struct mbuf *n; 829105197Ssam 830315514Sae M_ASSERTPKTHDR(m); 831315514Sae IPSEC_ASSERT(len < MHLEN, ("wrong length")); 832315514Sae if (M_LEADINGSPACE(m) >= len) { 833315514Sae /* No need to allocate new mbuf. */ 834315514Sae m->m_data -= len; 835315514Sae m->m_len += len; 836315514Sae m->m_pkthdr.len += len; 837315514Sae return (m); 838105197Ssam } 839315514Sae n = m_gethdr(how, m->m_type); 840315514Sae if (n == NULL) { 841315514Sae m_freem(m); 842315514Sae return (NULL); 843105197Ssam } 844315514Sae m_move_pkthdr(n, m); 845315514Sae n->m_next = m; 846315514Sae if (len + IPSEC_TRAILINGSPACE < M_SIZE(n)) 847315514Sae m_align(n, len + IPSEC_TRAILINGSPACE); 848315514Sae n->m_len = len; 849315514Sae n->m_pkthdr.len += len; 850315514Sae return (n); 851105197Ssam} 852105197Ssam 853281692Saestatic int 854281692Saeipsec_encap(struct mbuf **mp, struct secasindex *saidx) 855281692Sae{ 856281692Sae#ifdef INET6 857281692Sae struct ip6_hdr *ip6; 858281692Sae#endif 859281692Sae struct ip *ip; 860281692Sae int setdf; 861281692Sae uint8_t itos, proto; 862281692Sae 863281692Sae ip = mtod(*mp, struct ip *); 864281692Sae switch (ip->ip_v) { 865105197Ssam#ifdef INET 866281692Sae case IPVERSION: 867281692Sae proto = IPPROTO_IPIP; 868281692Sae /* 869281692Sae * Collect IP_DF state from the inner header 870281692Sae * and honor system-wide control of how to handle it. 871281692Sae */ 872281692Sae switch (V_ip4_ipsec_dfbit) { 873281692Sae case 0: /* clear in outer header */ 874281692Sae case 1: /* set in outer header */ 875281692Sae setdf = V_ip4_ipsec_dfbit; 876281692Sae break; 877281692Sae default:/* propagate to outer header */ 878297014Sae setdf = (ip->ip_off & htons(IP_DF)) != 0; 879281692Sae } 880281692Sae itos = ip->ip_tos; 881281692Sae break; 882281692Sae#endif 883281692Sae#ifdef INET6 884281692Sae case (IPV6_VERSION >> 4): 885281692Sae proto = IPPROTO_IPV6; 886281692Sae ip6 = mtod(*mp, struct ip6_hdr *); 887281692Sae itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; 888281692Sae setdf = V_ip4_ipsec_dfbit ? 1: 0; 889281692Sae /* scoped address handling */ 890281692Sae in6_clearscope(&ip6->ip6_src); 891281692Sae in6_clearscope(&ip6->ip6_dst); 892281692Sae break; 893281692Sae#endif 894281692Sae default: 895281692Sae return (EAFNOSUPPORT); 896281692Sae } 897281692Sae switch (saidx->dst.sa.sa_family) { 898281692Sae#ifdef INET 899281692Sae case AF_INET: 900281692Sae if (saidx->src.sa.sa_family != AF_INET || 901281692Sae saidx->src.sin.sin_addr.s_addr == INADDR_ANY || 902281692Sae saidx->dst.sin.sin_addr.s_addr == INADDR_ANY) 903281692Sae return (EINVAL); 904315514Sae *mp = ipsec_prepend(*mp, sizeof(struct ip), M_NOWAIT); 905281692Sae if (*mp == NULL) 906281692Sae return (ENOBUFS); 907281692Sae ip = mtod(*mp, struct ip *); 908281692Sae ip->ip_v = IPVERSION; 909281692Sae ip->ip_hl = sizeof(struct ip) >> 2; 910281692Sae ip->ip_p = proto; 911281692Sae ip->ip_len = htons((*mp)->m_pkthdr.len); 912281692Sae ip->ip_ttl = V_ip_defttl; 913281692Sae ip->ip_sum = 0; 914281692Sae ip->ip_off = setdf ? htons(IP_DF): 0; 915281692Sae ip->ip_src = saidx->src.sin.sin_addr; 916281692Sae ip->ip_dst = saidx->dst.sin.sin_addr; 917281692Sae ip_ecn_ingress(V_ip4_ipsec_ecn, &ip->ip_tos, &itos); 918281692Sae ip_fillid(ip); 919281692Sae break; 920281692Sae#endif /* INET */ 921281692Sae#ifdef INET6 922281692Sae case AF_INET6: 923281692Sae if (saidx->src.sa.sa_family != AF_INET6 || 924281692Sae IN6_IS_ADDR_UNSPECIFIED(&saidx->src.sin6.sin6_addr) || 925281692Sae IN6_IS_ADDR_UNSPECIFIED(&saidx->dst.sin6.sin6_addr)) 926281692Sae return (EINVAL); 927315514Sae *mp = ipsec_prepend(*mp, sizeof(struct ip6_hdr), M_NOWAIT); 928281692Sae if (*mp == NULL) 929281692Sae return (ENOBUFS); 930281692Sae ip6 = mtod(*mp, struct ip6_hdr *); 931281692Sae ip6->ip6_flow = 0; 932281692Sae ip6->ip6_vfc = IPV6_VERSION; 933281692Sae ip6->ip6_hlim = V_ip6_defhlim; 934281692Sae ip6->ip6_nxt = proto; 935281692Sae ip6->ip6_dst = saidx->dst.sin6.sin6_addr; 936281693Sae /* For link-local address embed scope zone id */ 937281693Sae if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) 938281693Sae ip6->ip6_dst.s6_addr16[1] = 939281693Sae htons(saidx->dst.sin6.sin6_scope_id & 0xffff); 940281692Sae ip6->ip6_src = saidx->src.sin6.sin6_addr; 941281693Sae if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) 942281693Sae ip6->ip6_src.s6_addr16[1] = 943281693Sae htons(saidx->src.sin6.sin6_scope_id & 0xffff); 944281692Sae ip6->ip6_plen = htons((*mp)->m_pkthdr.len - sizeof(*ip6)); 945281692Sae ip_ecn_ingress(V_ip6_ipsec_ecn, &proto, &itos); 946281692Sae ip6->ip6_flow |= htonl((uint32_t)proto << 20); 947281692Sae break; 948281692Sae#endif /* INET6 */ 949281692Sae default: 950281692Sae return (EAFNOSUPPORT); 951281692Sae } 952315514Sae (*mp)->m_flags &= ~(M_BCAST | M_MCAST); 953281692Sae return (0); 954281692Sae} 955281692Sae 956