1105197Ssam/* $FreeBSD$ */ 2112758Ssam/* $OpenBSD: ipsec_input.c,v 1.63 2003/02/20 18:35:43 deraadt Exp $ */ 3139823Simp/*- 4112758Ssam * The authors of this code are John Ioannidis (ji@tla.org), 5112758Ssam * Angelos D. Keromytis (kermit@csd.uch.gr) and 6112758Ssam * Niels Provos (provos@physnet.uni-hamburg.de). 7112758Ssam * 8112758Ssam * This code was written by John Ioannidis for BSD/OS in Athens, Greece, 9112758Ssam * in November 1995. 10112758Ssam * 11112758Ssam * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996, 12112758Ssam * by Angelos D. Keromytis. 13112758Ssam * 14112758Ssam * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis 15112758Ssam * and Niels Provos. 16112758Ssam * 17112758Ssam * Additional features in 1999 by Angelos D. Keromytis. 18112758Ssam * 19112758Ssam * Copyright (C) 1995, 1996, 1997, 1998, 1999 by John Ioannidis, 20112758Ssam * Angelos D. Keromytis and Niels Provos. 21112758Ssam * Copyright (c) 2001, Angelos D. Keromytis. 22112758Ssam * 23112758Ssam * Permission to use, copy, and modify this software with or without fee 24112758Ssam * is hereby granted, provided that this entire notice is included in 25112758Ssam * all copies of any software which is or includes a copy or 26112758Ssam * modification of this software. 27112758Ssam * You may use this code under the GNU public license if you so wish. Please 28112758Ssam * contribute changes back to the authors under this freer than GPL license 29112758Ssam * so that we may further the use of strong encryption without limitations to 30112758Ssam * all. 31112758Ssam * 32112758Ssam * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR 33112758Ssam * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY 34112758Ssam * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE 35112758Ssam * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR 36112758Ssam * PURPOSE. 37112758Ssam */ 38105197Ssam 39105197Ssam/* 40105197Ssam * IPsec input processing. 41105197Ssam */ 42105197Ssam 43105197Ssam#include "opt_inet.h" 44105197Ssam#include "opt_inet6.h" 45105197Ssam#include "opt_ipsec.h" 46159965Sthompsa#include "opt_enc.h" 47105197Ssam 48105197Ssam#include <sys/param.h> 49105197Ssam#include <sys/systm.h> 50105197Ssam#include <sys/malloc.h> 51105197Ssam#include <sys/mbuf.h> 52105197Ssam#include <sys/domain.h> 53105197Ssam#include <sys/protosw.h> 54105197Ssam#include <sys/socket.h> 55105197Ssam#include <sys/errno.h> 56105197Ssam#include <sys/syslog.h> 57105197Ssam 58105197Ssam#include <net/if.h> 59171497Sbz#include <net/pfil.h> 60105197Ssam#include <net/netisr.h> 61195699Srwatson#include <net/vnet.h> 62105197Ssam 63105197Ssam#include <netinet/in.h> 64105197Ssam#include <netinet/in_systm.h> 65105197Ssam#include <netinet/ip.h> 66105197Ssam#include <netinet/ip_var.h> 67105197Ssam#include <netinet/in_var.h> 68105197Ssam 69105197Ssam#include <netinet/ip6.h> 70105197Ssam#ifdef INET6 71105197Ssam#include <netinet6/ip6_var.h> 72105197Ssam#endif 73105197Ssam#include <netinet/in_pcb.h> 74105197Ssam#ifdef INET6 75105197Ssam#include <netinet/icmp6.h> 76105197Ssam#endif 77105197Ssam 78105197Ssam#include <netipsec/ipsec.h> 79105197Ssam#ifdef INET6 80105197Ssam#include <netipsec/ipsec6.h> 81105197Ssam#endif 82105197Ssam#include <netipsec/ah_var.h> 83105197Ssam#include <netipsec/esp.h> 84105197Ssam#include <netipsec/esp_var.h> 85105197Ssam#include <netipsec/ipcomp_var.h> 86105197Ssam 87105197Ssam#include <netipsec/key.h> 88105197Ssam#include <netipsec/keydb.h> 89105197Ssam 90105197Ssam#include <netipsec/xform.h> 91105197Ssam#include <netinet6/ip6protosw.h> 92105197Ssam 93105197Ssam#include <machine/in_cksum.h> 94105197Ssam#include <machine/stdarg.h> 95105197Ssam 96181627Svanhu#ifdef DEV_ENC 97181627Svanhu#include <net/if_enc.h> 98181627Svanhu#endif 99181627Svanhu 100181627Svanhu 101252028Sae#define IPSEC_ISTAT(proto, name) do { \ 102252028Sae if ((proto) == IPPROTO_ESP) \ 103252028Sae ESPSTAT_INC(esps_##name); \ 104252028Sae else if ((proto) == IPPROTO_AH) \ 105252028Sae AHSTAT_INC(ahs_##name); \ 106252028Sae else \ 107252028Sae IPCOMPSTAT_INC(ipcomps_##name); \ 108252028Sae} while (0) 109105197Ssam 110193947Sbz#ifdef INET 111120585Ssamstatic void ipsec4_common_ctlinput(int, struct sockaddr *, void *, int); 112193947Sbz#endif 113120585Ssam 114105197Ssam/* 115105197Ssam * ipsec_common_input gets called when an IPsec-protected packet 116214351Sthomas * is received by IPv4 or IPv6. Its job is to find the right SA 117170793Sbz * and call the appropriate transform. The transform callback 118105197Ssam * takes care of further processing (like ingress filtering). 119105197Ssam */ 120105197Ssamstatic int 121105197Ssamipsec_common_input(struct mbuf *m, int skip, int protoff, int af, int sproto) 122105197Ssam{ 123105197Ssam union sockaddr_union dst_address; 124105197Ssam struct secasvar *sav; 125105197Ssam u_int32_t spi; 126119643Ssam int error; 127221129Sbz#ifdef INET 128194062Svanhu#ifdef IPSEC_NAT_T 129194062Svanhu struct m_tag *tag; 130194062Svanhu#endif 131221129Sbz#endif 132105197Ssam 133252028Sae IPSEC_ISTAT(sproto, input); 134105197Ssam 135120585Ssam IPSEC_ASSERT(m != NULL, ("null packet")); 136105197Ssam 137170792Sbz IPSEC_ASSERT(sproto == IPPROTO_ESP || sproto == IPPROTO_AH || 138170792Sbz sproto == IPPROTO_IPCOMP, 139170792Sbz ("unexpected security protocol %u", sproto)); 140170792Sbz 141181803Sbz if ((sproto == IPPROTO_ESP && !V_esp_enable) || 142181803Sbz (sproto == IPPROTO_AH && !V_ah_enable) || 143181803Sbz (sproto == IPPROTO_IPCOMP && !V_ipcomp_enable)) { 144105197Ssam m_freem(m); 145252028Sae IPSEC_ISTAT(sproto, pdrops); 146105197Ssam return EOPNOTSUPP; 147105197Ssam } 148105197Ssam 149105197Ssam if (m->m_pkthdr.len - skip < 2 * sizeof (u_int32_t)) { 150105197Ssam m_freem(m); 151252028Sae IPSEC_ISTAT(sproto, hdrops); 152120585Ssam DPRINTF(("%s: packet too small\n", __func__)); 153105197Ssam return EINVAL; 154105197Ssam } 155105197Ssam 156105197Ssam /* Retrieve the SPI from the relevant IPsec header */ 157105197Ssam if (sproto == IPPROTO_ESP) 158105197Ssam m_copydata(m, skip, sizeof(u_int32_t), (caddr_t) &spi); 159105197Ssam else if (sproto == IPPROTO_AH) 160105197Ssam m_copydata(m, skip + sizeof(u_int32_t), sizeof(u_int32_t), 161105197Ssam (caddr_t) &spi); 162105197Ssam else if (sproto == IPPROTO_IPCOMP) { 163105197Ssam u_int16_t cpi; 164105197Ssam m_copydata(m, skip + sizeof(u_int16_t), sizeof(u_int16_t), 165105197Ssam (caddr_t) &cpi); 166105197Ssam spi = ntohl(htons(cpi)); 167105197Ssam } 168105197Ssam 169105197Ssam /* 170105197Ssam * Find the SA and (indirectly) call the appropriate 171105197Ssam * kernel crypto routine. The resulting mbuf chain is a valid 172105197Ssam * IP packet ready to go through input processing. 173105197Ssam */ 174105197Ssam bzero(&dst_address, sizeof (dst_address)); 175105197Ssam dst_address.sa.sa_family = af; 176105197Ssam switch (af) { 177105197Ssam#ifdef INET 178105197Ssam case AF_INET: 179105197Ssam dst_address.sin.sin_len = sizeof(struct sockaddr_in); 180105197Ssam m_copydata(m, offsetof(struct ip, ip_dst), 181105197Ssam sizeof(struct in_addr), 182105197Ssam (caddr_t) &dst_address.sin.sin_addr); 183194062Svanhu#ifdef IPSEC_NAT_T 184194062Svanhu /* Find the source port for NAT-T; see udp*_espdecap. */ 185194062Svanhu tag = m_tag_find(m, PACKET_TAG_IPSEC_NAT_T_PORTS, NULL); 186194062Svanhu if (tag != NULL) 187194062Svanhu dst_address.sin.sin_port = ((u_int16_t *)(tag + 1))[1]; 188194062Svanhu#endif /* IPSEC_NAT_T */ 189105197Ssam break; 190105197Ssam#endif /* INET */ 191105197Ssam#ifdef INET6 192105197Ssam case AF_INET6: 193105197Ssam dst_address.sin6.sin6_len = sizeof(struct sockaddr_in6); 194105197Ssam m_copydata(m, offsetof(struct ip6_hdr, ip6_dst), 195105197Ssam sizeof(struct in6_addr), 196105197Ssam (caddr_t) &dst_address.sin6.sin6_addr); 197105197Ssam break; 198105197Ssam#endif /* INET6 */ 199105197Ssam default: 200120585Ssam DPRINTF(("%s: unsupported protocol family %u\n", __func__, af)); 201105197Ssam m_freem(m); 202252028Sae IPSEC_ISTAT(sproto, nopf); 203105197Ssam return EPFNOSUPPORT; 204105197Ssam } 205105197Ssam 206105197Ssam /* NB: only pass dst since key_allocsa follows RFC2401 */ 207105197Ssam sav = KEY_ALLOCSA(&dst_address, sproto, spi); 208105197Ssam if (sav == NULL) { 209120585Ssam DPRINTF(("%s: no key association found for SA %s/%08lx/%u\n", 210120585Ssam __func__, ipsec_address(&dst_address), 211105197Ssam (u_long) ntohl(spi), sproto)); 212252028Sae IPSEC_ISTAT(sproto, notdb); 213105197Ssam m_freem(m); 214105197Ssam return ENOENT; 215105197Ssam } 216105197Ssam 217105197Ssam if (sav->tdb_xform == NULL) { 218120585Ssam DPRINTF(("%s: attempted to use uninitialized SA %s/%08lx/%u\n", 219120585Ssam __func__, ipsec_address(&dst_address), 220105197Ssam (u_long) ntohl(spi), sproto)); 221252028Sae IPSEC_ISTAT(sproto, noxform); 222105197Ssam KEY_FREESAV(&sav); 223105197Ssam m_freem(m); 224105197Ssam return ENXIO; 225105197Ssam } 226105197Ssam 227105197Ssam /* 228105197Ssam * Call appropriate transform and return -- callback takes care of 229105197Ssam * everything else. 230105197Ssam */ 231105197Ssam error = (*sav->tdb_xform->xf_input)(m, sav, skip, protoff); 232105197Ssam KEY_FREESAV(&sav); 233105197Ssam return error; 234105197Ssam} 235105197Ssam 236105197Ssam#ifdef INET 237105197Ssam/* 238105197Ssam * Common input handler for IPv4 AH, ESP, and IPCOMP. 239105197Ssam */ 240105197Ssamint 241105197Ssamipsec4_common_input(struct mbuf *m, ...) 242105197Ssam{ 243105197Ssam va_list ap; 244105197Ssam int off, nxt; 245105197Ssam 246105197Ssam va_start(ap, m); 247105197Ssam off = va_arg(ap, int); 248105197Ssam nxt = va_arg(ap, int); 249105197Ssam va_end(ap); 250105197Ssam 251105197Ssam return ipsec_common_input(m, off, offsetof(struct ip, ip_p), 252105197Ssam AF_INET, nxt); 253105197Ssam} 254105197Ssam 255106680Ssamvoid 256106680Ssamah4_input(struct mbuf *m, int off) 257106680Ssam{ 258106680Ssam ipsec4_common_input(m, off, IPPROTO_AH); 259106680Ssam} 260120585Ssamvoid 261120585Ssamah4_ctlinput(int cmd, struct sockaddr *sa, void *v) 262120585Ssam{ 263120585Ssam if (sa->sa_family == AF_INET && 264120585Ssam sa->sa_len == sizeof(struct sockaddr_in)) 265120585Ssam ipsec4_common_ctlinput(cmd, sa, v, IPPROTO_AH); 266120585Ssam} 267106680Ssam 268106680Ssamvoid 269106680Ssamesp4_input(struct mbuf *m, int off) 270106680Ssam{ 271106680Ssam ipsec4_common_input(m, off, IPPROTO_ESP); 272106680Ssam} 273120585Ssamvoid 274120585Ssamesp4_ctlinput(int cmd, struct sockaddr *sa, void *v) 275120585Ssam{ 276120585Ssam if (sa->sa_family == AF_INET && 277120585Ssam sa->sa_len == sizeof(struct sockaddr_in)) 278120585Ssam ipsec4_common_ctlinput(cmd, sa, v, IPPROTO_ESP); 279120585Ssam} 280106680Ssam 281106680Ssamvoid 282106680Ssamipcomp4_input(struct mbuf *m, int off) 283106680Ssam{ 284106680Ssam ipsec4_common_input(m, off, IPPROTO_IPCOMP); 285106680Ssam} 286106680Ssam 287105197Ssam/* 288105197Ssam * IPsec input callback for INET protocols. 289105197Ssam * This routine is called as the transform callback. 290105197Ssam * Takes care of filtering and other sanity checks on 291105197Ssam * the processed packet. 292105197Ssam */ 293105197Ssamint 294105197Ssamipsec4_common_input_cb(struct mbuf *m, struct secasvar *sav, 295105197Ssam int skip, int protoff, struct m_tag *mt) 296105197Ssam{ 297274132Sae int prot, af, sproto, isr_prot; 298105197Ssam struct ip *ip; 299105197Ssam struct m_tag *mtag; 300105197Ssam struct tdb_ident *tdbi; 301105197Ssam struct secasindex *saidx; 302105197Ssam int error; 303165222Sbz#ifdef INET6 304165118Sbz#ifdef notyet 305165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 306165118Sbz#endif 307165118Sbz#endif 308105197Ssam 309120585Ssam IPSEC_ASSERT(m != NULL, ("null mbuf")); 310120585Ssam IPSEC_ASSERT(sav != NULL, ("null SA")); 311120585Ssam IPSEC_ASSERT(sav->sah != NULL, ("null SAH")); 312105197Ssam saidx = &sav->sah->saidx; 313105197Ssam af = saidx->dst.sa.sa_family; 314120585Ssam IPSEC_ASSERT(af == AF_INET, ("unexpected af %u", af)); 315105197Ssam sproto = saidx->proto; 316120585Ssam IPSEC_ASSERT(sproto == IPPROTO_ESP || sproto == IPPROTO_AH || 317105197Ssam sproto == IPPROTO_IPCOMP, 318120585Ssam ("unexpected security protocol %u", sproto)); 319105197Ssam 320105197Ssam /* Sanity check */ 321105197Ssam if (m == NULL) { 322120585Ssam DPRINTF(("%s: null mbuf", __func__)); 323252028Sae IPSEC_ISTAT(sproto, badkcr); 324105197Ssam KEY_FREESAV(&sav); 325105197Ssam return EINVAL; 326105197Ssam } 327105197Ssam 328105197Ssam if (skip != 0) { 329241922Sglebius /* 330241922Sglebius * Fix IPv4 header 331241922Sglebius * XXXGL: do we need this entire block? 332241922Sglebius */ 333105197Ssam if (m->m_len < skip && (m = m_pullup(m, skip)) == NULL) { 334120585Ssam DPRINTF(("%s: processing failed for SA %s/%08lx\n", 335120585Ssam __func__, ipsec_address(&sav->sah->saidx.dst), 336105197Ssam (u_long) ntohl(sav->spi))); 337252028Sae IPSEC_ISTAT(sproto, hdrops); 338105197Ssam error = ENOBUFS; 339105197Ssam goto bad; 340105197Ssam } 341105197Ssam 342105197Ssam ip = mtod(m, struct ip *); 343105197Ssam ip->ip_len = htons(m->m_pkthdr.len); 344105197Ssam ip->ip_sum = 0; 345105197Ssam ip->ip_sum = in_cksum(m, ip->ip_hl << 2); 346105197Ssam } else { 347105197Ssam ip = mtod(m, struct ip *); 348105197Ssam } 349105197Ssam prot = ip->ip_p; 350105197Ssam 351274132Sae#ifdef DEV_ENC 352274132Sae encif->if_ipackets++; 353274132Sae encif->if_ibytes += m->m_pkthdr.len; 354274132Sae 355274794Sae /* Pass the mbuf to enc0 for bpf and pfil. */ 356274132Sae ipsec_bpf(m, sav, AF_INET, ENC_IN|ENC_BEFORE); 357274794Sae if ((error = ipsec_filter(&m, PFIL_IN, ENC_IN|ENC_BEFORE)) != 0) 358274794Sae return (error); 359274132Sae#endif /* DEV_ENC */ 360274132Sae 361105197Ssam /* IP-in-IP encapsulation */ 362274132Sae if (prot == IPPROTO_IPIP && 363274132Sae saidx->mode != IPSEC_MODE_TRANSPORT) { 364105197Ssam 365118888Ssam if (m->m_pkthdr.len - skip < sizeof(struct ip)) { 366252028Sae IPSEC_ISTAT(sproto, hdrops); 367118888Ssam error = EINVAL; 368118888Ssam goto bad; 369118888Ssam } 370274132Sae /* enc0: strip outer IPv4 header */ 371274132Sae m_striphdr(m, 0, ip->ip_hl << 2); 372105197Ssam 373274132Sae#ifdef notyet 374105197Ssam /* XXX PROXY address isn't recorded in SAH */ 375105197Ssam /* 376105197Ssam * Check that the inner source address is the same as 377105197Ssam * the proxy address, if available. 378105197Ssam */ 379105197Ssam if ((saidx->proxy.sa.sa_family == AF_INET && 380105197Ssam saidx->proxy.sin.sin_addr.s_addr != 381105197Ssam INADDR_ANY && 382105197Ssam ipn.ip_src.s_addr != 383105197Ssam saidx->proxy.sin.sin_addr.s_addr) || 384105197Ssam (saidx->proxy.sa.sa_family != AF_INET && 385105197Ssam saidx->proxy.sa.sa_family != 0)) { 386105197Ssam 387120585Ssam DPRINTF(("%s: inner source address %s doesn't " 388120585Ssam "correspond to expected proxy source %s, " 389120585Ssam "SA %s/%08lx\n", __func__, 390105197Ssam inet_ntoa4(ipn.ip_src), 391105197Ssam ipsp_address(saidx->proxy), 392105197Ssam ipsp_address(saidx->dst), 393105197Ssam (u_long) ntohl(sav->spi))); 394105197Ssam 395252028Sae IPSEC_ISTAT(sproto, pdrops); 396105197Ssam error = EACCES; 397105197Ssam goto bad; 398105197Ssam } 399274132Sae#endif /* notyet */ 400105197Ssam } 401159237Spjd#ifdef INET6 402105197Ssam /* IPv6-in-IP encapsulation. */ 403274469Sae else if (prot == IPPROTO_IPV6 && 404274132Sae saidx->mode != IPSEC_MODE_TRANSPORT) { 405105197Ssam 406118888Ssam if (m->m_pkthdr.len - skip < sizeof(struct ip6_hdr)) { 407252028Sae IPSEC_ISTAT(sproto, hdrops); 408118888Ssam error = EINVAL; 409118888Ssam goto bad; 410118888Ssam } 411274132Sae /* enc0: strip IPv4 header, keep IPv6 header only */ 412274132Sae m_striphdr(m, 0, ip->ip_hl << 2); 413274132Sae#ifdef notyet 414105197Ssam /* 415105197Ssam * Check that the inner source address is the same as 416105197Ssam * the proxy address, if available. 417105197Ssam */ 418105197Ssam if ((saidx->proxy.sa.sa_family == AF_INET6 && 419105197Ssam !IN6_IS_ADDR_UNSPECIFIED(&saidx->proxy.sin6.sin6_addr) && 420105197Ssam !IN6_ARE_ADDR_EQUAL(&ip6n.ip6_src, 421105197Ssam &saidx->proxy.sin6.sin6_addr)) || 422105197Ssam (saidx->proxy.sa.sa_family != AF_INET6 && 423105197Ssam saidx->proxy.sa.sa_family != 0)) { 424105197Ssam 425120585Ssam DPRINTF(("%s: inner source address %s doesn't " 426120585Ssam "correspond to expected proxy source %s, " 427120585Ssam "SA %s/%08lx\n", __func__, 428165118Sbz ip6_sprintf(ip6buf, &ip6n.ip6_src), 429105197Ssam ipsec_address(&saidx->proxy), 430105197Ssam ipsec_address(&saidx->dst), 431105197Ssam (u_long) ntohl(sav->spi))); 432105197Ssam 433252028Sae IPSEC_ISTAT(sproto, pdrops); 434105197Ssam error = EACCES; 435105197Ssam goto bad; 436105197Ssam } 437274132Sae#endif /* notyet */ 438105197Ssam } 439105197Ssam#endif /* INET6 */ 440274469Sae else if (prot != IPPROTO_IPV6 && saidx->mode == IPSEC_MODE_ANY) { 441274469Sae /* 442274469Sae * When mode is wildcard, inner protocol is IPv6 and 443274469Sae * we have no INET6 support - drop this packet a bit later. 444274469Sae * In other cases we assume transport mode and outer 445274469Sae * header was already stripped in xform_xxx_cb. 446274469Sae */ 447274469Sae prot = IPPROTO_IPIP; 448274469Sae } 449105197Ssam 450105197Ssam /* 451105197Ssam * Record what we've done to the packet (under what SA it was 452105197Ssam * processed). If we've been passed an mtag, it means the packet 453105197Ssam * was already processed by an ethernet/crypto combo card and 454105197Ssam * thus has a tag attached with all the right information, but 455105197Ssam * with a PACKET_TAG_IPSEC_IN_CRYPTO_DONE as opposed to 456105197Ssam * PACKET_TAG_IPSEC_IN_DONE type; in that case, just change the type. 457105197Ssam */ 458105197Ssam if (mt == NULL && sproto != IPPROTO_IPCOMP) { 459105197Ssam mtag = m_tag_get(PACKET_TAG_IPSEC_IN_DONE, 460105197Ssam sizeof(struct tdb_ident), M_NOWAIT); 461105197Ssam if (mtag == NULL) { 462120585Ssam DPRINTF(("%s: failed to get tag\n", __func__)); 463252028Sae IPSEC_ISTAT(sproto, hdrops); 464105197Ssam error = ENOMEM; 465105197Ssam goto bad; 466105197Ssam } 467105197Ssam 468105197Ssam tdbi = (struct tdb_ident *)(mtag + 1); 469105197Ssam bcopy(&saidx->dst, &tdbi->dst, saidx->dst.sa.sa_len); 470105197Ssam tdbi->proto = sproto; 471105197Ssam tdbi->spi = sav->spi; 472174054Sbz /* Cache those two for enc(4) in xform_ipip. */ 473174054Sbz tdbi->alg_auth = sav->alg_auth; 474174054Sbz tdbi->alg_enc = sav->alg_enc; 475105197Ssam 476105197Ssam m_tag_prepend(m, mtag); 477170797Sbz } else if (mt != NULL) { 478105197Ssam mt->m_tag_id = PACKET_TAG_IPSEC_IN_DONE; 479105197Ssam /* XXX do we need to mark m_flags??? */ 480105197Ssam } 481105197Ssam 482105197Ssam key_sa_recordxfer(sav, m); /* record data transfer */ 483105197Ssam 484274132Sae /* 485274132Sae * In transport mode requeue decrypted mbuf back to IPv4 protocol 486274132Sae * handler. This is necessary to correctly expose rcvif. 487274132Sae */ 488274132Sae if (saidx->mode == IPSEC_MODE_TRANSPORT) 489274132Sae prot = IPPROTO_IPIP; 490159965Sthompsa#ifdef DEV_ENC 491105197Ssam /* 492274132Sae * Pass the mbuf to enc0 for bpf and pfil. 493159965Sthompsa */ 494274132Sae if (prot == IPPROTO_IPIP) 495274132Sae ipsec_bpf(m, sav, AF_INET, ENC_IN|ENC_AFTER); 496274132Sae#ifdef INET6 497274132Sae if (prot == IPPROTO_IPV6) 498274132Sae ipsec_bpf(m, sav, AF_INET6, ENC_IN|ENC_AFTER); 499159965Sthompsa#endif 500159965Sthompsa 501274132Sae if ((error = ipsec_filter(&m, PFIL_IN, ENC_IN|ENC_AFTER)) != 0) 502274132Sae return (error); 503274132Sae#endif /* DEV_ENC */ 504274132Sae 505159965Sthompsa /* 506105197Ssam * Re-dispatch via software interrupt. 507105197Ssam */ 508274132Sae 509274132Sae switch (prot) { 510274132Sae case IPPROTO_IPIP: 511274132Sae isr_prot = NETISR_IP; 512274132Sae break; 513274132Sae#ifdef INET6 514274132Sae case IPPROTO_IPV6: 515274132Sae isr_prot = NETISR_IPV6; 516274132Sae break; 517274132Sae#endif 518274132Sae default: 519274132Sae DPRINTF(("%s: cannot handle inner ip proto %d\n", 520274132Sae __func__, prot)); 521274132Sae IPSEC_ISTAT(sproto, nopf); 522274132Sae error = EPFNOSUPPORT; 523274132Sae goto bad; 524274132Sae } 525274132Sae 526274132Sae error = netisr_queue_src(isr_prot, (uintptr_t)sav->spi, m); 527274132Sae if (error) { 528252028Sae IPSEC_ISTAT(sproto, qfull); 529120585Ssam DPRINTF(("%s: queue full; proto %u packet dropped\n", 530120585Ssam __func__, sproto)); 531134391Sandre return error; 532105197Ssam } 533105197Ssam return 0; 534105197Ssambad: 535105197Ssam m_freem(m); 536105197Ssam return error; 537105197Ssam} 538120585Ssam 539120585Ssamvoid 540120585Ssamipsec4_common_ctlinput(int cmd, struct sockaddr *sa, void *v, int proto) 541120585Ssam{ 542120585Ssam /* XXX nothing just yet */ 543120585Ssam} 544105197Ssam#endif /* INET */ 545105197Ssam 546105197Ssam#ifdef INET6 547105197Ssam/* IPv6 AH wrapper. */ 548105197Ssamint 549105197Ssamipsec6_common_input(struct mbuf **mp, int *offp, int proto) 550105197Ssam{ 551105197Ssam int l = 0; 552105197Ssam int protoff; 553105197Ssam struct ip6_ext ip6e; 554105197Ssam 555105197Ssam if (*offp < sizeof(struct ip6_hdr)) { 556120585Ssam DPRINTF(("%s: bad offset %u\n", __func__, *offp)); 557105197Ssam return IPPROTO_DONE; 558105197Ssam } else if (*offp == sizeof(struct ip6_hdr)) { 559105197Ssam protoff = offsetof(struct ip6_hdr, ip6_nxt); 560105197Ssam } else { 561105197Ssam /* Chase down the header chain... */ 562105197Ssam protoff = sizeof(struct ip6_hdr); 563105197Ssam 564105197Ssam do { 565105197Ssam protoff += l; 566105197Ssam m_copydata(*mp, protoff, sizeof(ip6e), 567105197Ssam (caddr_t) &ip6e); 568105197Ssam 569105197Ssam if (ip6e.ip6e_nxt == IPPROTO_AH) 570105197Ssam l = (ip6e.ip6e_len + 2) << 2; 571105197Ssam else 572105197Ssam l = (ip6e.ip6e_len + 1) << 3; 573120585Ssam IPSEC_ASSERT(l > 0, ("l went zero or negative")); 574105197Ssam } while (protoff + l < *offp); 575105197Ssam 576105197Ssam /* Malformed packet check */ 577105197Ssam if (protoff + l != *offp) { 578120585Ssam DPRINTF(("%s: bad packet header chain, protoff %u, " 579120585Ssam "l %u, off %u\n", __func__, protoff, l, *offp)); 580252028Sae IPSEC_ISTAT(proto, hdrops); 581105197Ssam m_freem(*mp); 582105197Ssam *mp = NULL; 583105197Ssam return IPPROTO_DONE; 584105197Ssam } 585105197Ssam protoff += offsetof(struct ip6_ext, ip6e_nxt); 586105197Ssam } 587105197Ssam (void) ipsec_common_input(*mp, *offp, protoff, AF_INET6, proto); 588105197Ssam return IPPROTO_DONE; 589105197Ssam} 590105197Ssam 591105197Ssam/* 592105197Ssam * IPsec input callback, called by the transform callback. Takes care of 593105197Ssam * filtering and other sanity checks on the processed packet. 594105197Ssam */ 595105197Ssamint 596105197Ssamipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip, int protoff, 597105197Ssam struct m_tag *mt) 598105197Ssam{ 599105197Ssam int prot, af, sproto; 600105197Ssam struct ip6_hdr *ip6; 601105197Ssam struct m_tag *mtag; 602105197Ssam struct tdb_ident *tdbi; 603105197Ssam struct secasindex *saidx; 604105197Ssam int nxt; 605105197Ssam u_int8_t nxt8; 606105197Ssam int error, nest; 607165118Sbz#ifdef notyet 608165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 609165118Sbz#endif 610105197Ssam 611120585Ssam IPSEC_ASSERT(m != NULL, ("null mbuf")); 612120585Ssam IPSEC_ASSERT(sav != NULL, ("null SA")); 613120585Ssam IPSEC_ASSERT(sav->sah != NULL, ("null SAH")); 614105197Ssam saidx = &sav->sah->saidx; 615105197Ssam af = saidx->dst.sa.sa_family; 616120585Ssam IPSEC_ASSERT(af == AF_INET6, ("unexpected af %u", af)); 617105197Ssam sproto = saidx->proto; 618120585Ssam IPSEC_ASSERT(sproto == IPPROTO_ESP || sproto == IPPROTO_AH || 619105197Ssam sproto == IPPROTO_IPCOMP, 620120585Ssam ("unexpected security protocol %u", sproto)); 621105197Ssam 622105197Ssam /* Sanity check */ 623105197Ssam if (m == NULL) { 624120585Ssam DPRINTF(("%s: null mbuf", __func__)); 625252028Sae IPSEC_ISTAT(sproto, badkcr); 626105197Ssam error = EINVAL; 627105197Ssam goto bad; 628105197Ssam } 629105197Ssam 630105197Ssam /* Fix IPv6 header */ 631105197Ssam if (m->m_len < sizeof(struct ip6_hdr) && 632105197Ssam (m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) { 633105197Ssam 634120585Ssam DPRINTF(("%s: processing failed for SA %s/%08lx\n", 635120585Ssam __func__, ipsec_address(&sav->sah->saidx.dst), 636105197Ssam (u_long) ntohl(sav->spi))); 637105197Ssam 638252028Sae IPSEC_ISTAT(sproto, hdrops); 639105197Ssam error = EACCES; 640105197Ssam goto bad; 641105197Ssam } 642105197Ssam 643105197Ssam ip6 = mtod(m, struct ip6_hdr *); 644105197Ssam ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr)); 645105197Ssam 646105197Ssam /* Save protocol */ 647274755Sae m_copydata(m, protoff, 1, &nxt8); 648274755Sae prot = nxt8; 649105197Ssam 650274132Sae#ifdef DEV_ENC 651274132Sae encif->if_ipackets++; 652274132Sae encif->if_ibytes += m->m_pkthdr.len; 653274132Sae 654274794Sae /* Pass the mbuf to enc0 for bpf and pfil. */ 655274132Sae ipsec_bpf(m, sav, AF_INET6, ENC_IN|ENC_BEFORE); 656274794Sae if ((error = ipsec_filter(&m, PFIL_IN, ENC_IN|ENC_BEFORE)) != 0) 657274794Sae return (error); 658274132Sae#endif /* DEV_ENC */ 659274132Sae 660274755Sae /* IPv6-in-IP encapsulation */ 661274755Sae if (prot == IPPROTO_IPV6 && 662274755Sae saidx->mode != IPSEC_MODE_TRANSPORT) { 663274755Sae if (m->m_pkthdr.len - skip < sizeof(struct ip6_hdr)) { 664252028Sae IPSEC_ISTAT(sproto, hdrops); 665118888Ssam error = EINVAL; 666118888Ssam goto bad; 667118888Ssam } 668274755Sae /* ip6n will now contain the inner IPv6 header. */ 669274755Sae m_striphdr(m, 0, skip); 670274132Sae skip = 0; 671274132Sae#ifdef notyet 672105197Ssam /* 673105197Ssam * Check that the inner source address is the same as 674105197Ssam * the proxy address, if available. 675105197Ssam */ 676274755Sae if ((saidx->proxy.sa.sa_family == AF_INET6 && 677274755Sae !IN6_IS_ADDR_UNSPECIFIED(&saidx->proxy.sin6.sin6_addr) && 678274755Sae !IN6_ARE_ADDR_EQUAL(&ip6n.ip6_src, 679274755Sae &saidx->proxy.sin6.sin6_addr)) || 680274755Sae (saidx->proxy.sa.sa_family != AF_INET6 && 681105197Ssam saidx->proxy.sa.sa_family != 0)) { 682105197Ssam 683120585Ssam DPRINTF(("%s: inner source address %s doesn't " 684120585Ssam "correspond to expected proxy source %s, " 685120585Ssam "SA %s/%08lx\n", __func__, 686274755Sae ip6_sprintf(ip6buf, &ip6n.ip6_src), 687105197Ssam ipsec_address(&saidx->proxy), 688105197Ssam ipsec_address(&saidx->dst), 689105197Ssam (u_long) ntohl(sav->spi))); 690105197Ssam 691252028Sae IPSEC_ISTAT(sproto, pdrops); 692105197Ssam error = EACCES; 693105197Ssam goto bad; 694105197Ssam } 695274132Sae#endif /* notyet */ 696105197Ssam } 697274755Sae#ifdef INET 698274755Sae /* IP-in-IP encapsulation */ 699274755Sae else if (prot == IPPROTO_IPIP && 700274755Sae saidx->mode != IPSEC_MODE_TRANSPORT) { 701274755Sae if (m->m_pkthdr.len - skip < sizeof(struct ip)) { 702252028Sae IPSEC_ISTAT(sproto, hdrops); 703118888Ssam error = EINVAL; 704118888Ssam goto bad; 705118888Ssam } 706274755Sae /* ipn will now contain the inner IPv4 header */ 707274755Sae m_striphdr(m, 0, skip); 708274132Sae skip = 0; 709274132Sae#ifdef notyet 710105197Ssam /* 711105197Ssam * Check that the inner source address is the same as 712105197Ssam * the proxy address, if available. 713105197Ssam */ 714274755Sae if ((saidx->proxy.sa.sa_family == AF_INET && 715274755Sae saidx->proxy.sin.sin_addr.s_addr != INADDR_ANY && 716274755Sae ipn.ip_src.s_addr != saidx->proxy.sin.sin_addr.s_addr) || 717274755Sae (saidx->proxy.sa.sa_family != AF_INET && 718105197Ssam saidx->proxy.sa.sa_family != 0)) { 719105197Ssam 720120585Ssam DPRINTF(("%s: inner source address %s doesn't " 721120585Ssam "correspond to expected proxy source %s, " 722120585Ssam "SA %s/%08lx\n", __func__, 723274755Sae inet_ntoa4(ipn.ip_src), 724105197Ssam ipsec_address(&saidx->proxy), 725105197Ssam ipsec_address(&saidx->dst), 726105197Ssam (u_long) ntohl(sav->spi))); 727105197Ssam 728252028Sae IPSEC_ISTAT(sproto, pdrops); 729105197Ssam error = EACCES; 730105197Ssam goto bad; 731105197Ssam } 732274132Sae#endif /* notyet */ 733159215Sgnn } 734274755Sae#endif /* INET */ 735274755Sae else { 736274755Sae prot = IPPROTO_IPV6; /* for correct BPF processing */ 737274755Sae } 738105197Ssam 739105197Ssam /* 740105197Ssam * Record what we've done to the packet (under what SA it was 741105197Ssam * processed). If we've been passed an mtag, it means the packet 742105197Ssam * was already processed by an ethernet/crypto combo card and 743105197Ssam * thus has a tag attached with all the right information, but 744105197Ssam * with a PACKET_TAG_IPSEC_IN_CRYPTO_DONE as opposed to 745105197Ssam * PACKET_TAG_IPSEC_IN_DONE type; in that case, just change the type. 746105197Ssam */ 747105197Ssam if (mt == NULL && sproto != IPPROTO_IPCOMP) { 748105197Ssam mtag = m_tag_get(PACKET_TAG_IPSEC_IN_DONE, 749105197Ssam sizeof(struct tdb_ident), M_NOWAIT); 750105197Ssam if (mtag == NULL) { 751120585Ssam DPRINTF(("%s: failed to get tag\n", __func__)); 752252028Sae IPSEC_ISTAT(sproto, hdrops); 753105197Ssam error = ENOMEM; 754105197Ssam goto bad; 755105197Ssam } 756105197Ssam 757105197Ssam tdbi = (struct tdb_ident *)(mtag + 1); 758105197Ssam bcopy(&saidx->dst, &tdbi->dst, sizeof(union sockaddr_union)); 759105197Ssam tdbi->proto = sproto; 760105197Ssam tdbi->spi = sav->spi; 761174054Sbz /* Cache those two for enc(4) in xform_ipip. */ 762174054Sbz tdbi->alg_auth = sav->alg_auth; 763174054Sbz tdbi->alg_enc = sav->alg_enc; 764105197Ssam 765105197Ssam m_tag_prepend(m, mtag); 766105197Ssam } else { 767120585Ssam if (mt != NULL) 768120585Ssam mt->m_tag_id = PACKET_TAG_IPSEC_IN_DONE; 769105197Ssam /* XXX do we need to mark m_flags??? */ 770105197Ssam } 771105197Ssam 772105197Ssam key_sa_recordxfer(sav, m); 773105197Ssam 774174054Sbz#ifdef DEV_ENC 775174054Sbz /* 776274132Sae * Pass the mbuf to enc0 for bpf and pfil. 777174054Sbz */ 778274132Sae#ifdef INET 779274132Sae if (prot == IPPROTO_IPIP) 780274132Sae ipsec_bpf(m, sav, AF_INET, ENC_IN|ENC_AFTER); 781174054Sbz#endif 782274132Sae if (prot == IPPROTO_IPV6) 783274132Sae ipsec_bpf(m, sav, AF_INET6, ENC_IN|ENC_AFTER); 784174054Sbz 785274132Sae if ((error = ipsec_filter(&m, PFIL_IN, ENC_IN|ENC_AFTER)) != 0) 786274132Sae return (error); 787274132Sae#endif /* DEV_ENC */ 788105197Ssam /* 789105197Ssam * See the end of ip6_input for this logic. 790105197Ssam * IPPROTO_IPV[46] case will be processed just like other ones 791105197Ssam */ 792105197Ssam nest = 0; 793105197Ssam nxt = nxt8; 794105197Ssam while (nxt != IPPROTO_DONE) { 795181803Sbz if (V_ip6_hdrnestlimit && (++nest > V_ip6_hdrnestlimit)) { 796249294Sae IP6STAT_INC(ip6s_toomanyhdr); 797105197Ssam error = EINVAL; 798105197Ssam goto bad; 799105197Ssam } 800105197Ssam 801105197Ssam /* 802105197Ssam * Protection against faulty packet - there should be 803105197Ssam * more sanity checks in header chain processing. 804105197Ssam */ 805105197Ssam if (m->m_pkthdr.len < skip) { 806249294Sae IP6STAT_INC(ip6s_tooshort); 807105197Ssam in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated); 808105197Ssam error = EINVAL; 809105197Ssam goto bad; 810105197Ssam } 811105197Ssam /* 812105197Ssam * Enforce IPsec policy checking if we are seeing last header. 813105197Ssam * note that we do not visit this with protocols with pcb layer 814105197Ssam * code - like udp/tcp/raw ip. 815105197Ssam */ 816105197Ssam if ((inet6sw[ip6_protox[nxt]].pr_flags & PR_LASTHDR) != 0 && 817105197Ssam ipsec6_in_reject(m, NULL)) { 818105197Ssam error = EINVAL; 819105197Ssam goto bad; 820105197Ssam } 821105197Ssam nxt = (*inet6sw[ip6_protox[nxt]].pr_input)(&m, &skip, nxt); 822105197Ssam } 823105197Ssam return 0; 824105197Ssambad: 825105197Ssam if (m) 826105197Ssam m_freem(m); 827105197Ssam return error; 828105197Ssam} 829120585Ssam 830120585Ssamvoid 831120585Ssamesp6_ctlinput(int cmd, struct sockaddr *sa, void *d) 832120585Ssam{ 833172149Sgnn struct ip6ctlparam *ip6cp = NULL; 834172149Sgnn struct mbuf *m = NULL; 835172149Sgnn struct ip6_hdr *ip6; 836172149Sgnn int off; 837172149Sgnn 838120585Ssam if (sa->sa_family != AF_INET6 || 839120585Ssam sa->sa_len != sizeof(struct sockaddr_in6)) 840120585Ssam return; 841120585Ssam if ((unsigned)cmd >= PRC_NCMDS) 842120585Ssam return; 843120585Ssam 844120585Ssam /* if the parameter is from icmp6, decode it. */ 845172149Sgnn if (d != NULL) { 846172149Sgnn ip6cp = (struct ip6ctlparam *)d; 847172149Sgnn m = ip6cp->ip6c_m; 848172149Sgnn ip6 = ip6cp->ip6c_ip6; 849172149Sgnn off = ip6cp->ip6c_off; 850172149Sgnn } else { 851172149Sgnn m = NULL; 852172149Sgnn ip6 = NULL; 853172149Sgnn off = 0; /* calm gcc */ 854172149Sgnn } 855120585Ssam 856172149Sgnn if (ip6 != NULL) { 857172149Sgnn 858120585Ssam struct ip6ctlparam ip6cp1; 859120585Ssam 860120585Ssam /* 861120585Ssam * Notify the error to all possible sockets via pfctlinput2. 862120585Ssam * Since the upper layer information (such as protocol type, 863120585Ssam * source and destination ports) is embedded in the encrypted 864120585Ssam * data and might have been cut, we can't directly call 865120585Ssam * an upper layer ctlinput function. However, the pcbnotify 866120585Ssam * function will consider source and destination addresses 867120585Ssam * as well as the flow info value, and may be able to find 868120585Ssam * some PCB that should be notified. 869120585Ssam * Although pfctlinput2 will call esp6_ctlinput(), there is 870120585Ssam * no possibility of an infinite loop of function calls, 871120585Ssam * because we don't pass the inner IPv6 header. 872120585Ssam */ 873120585Ssam bzero(&ip6cp1, sizeof(ip6cp1)); 874120585Ssam ip6cp1.ip6c_src = ip6cp->ip6c_src; 875120585Ssam pfctlinput2(cmd, sa, (void *)&ip6cp1); 876120585Ssam 877120585Ssam /* 878120585Ssam * Then go to special cases that need ESP header information. 879120585Ssam * XXX: We assume that when ip6 is non NULL, 880120585Ssam * M and OFF are valid. 881120585Ssam */ 882120585Ssam 883120585Ssam if (cmd == PRC_MSGSIZE) { 884120585Ssam struct secasvar *sav; 885120585Ssam u_int32_t spi; 886120585Ssam int valid; 887120585Ssam 888120585Ssam /* check header length before using m_copydata */ 889120585Ssam if (m->m_pkthdr.len < off + sizeof (struct esp)) 890120585Ssam return; 891120585Ssam m_copydata(m, off + offsetof(struct esp, esp_spi), 892120585Ssam sizeof(u_int32_t), (caddr_t) &spi); 893120585Ssam /* 894120585Ssam * Check to see if we have a valid SA corresponding to 895120585Ssam * the address in the ICMP message payload. 896120585Ssam */ 897120585Ssam sav = KEY_ALLOCSA((union sockaddr_union *)sa, 898120585Ssam IPPROTO_ESP, spi); 899120585Ssam valid = (sav != NULL); 900120585Ssam if (sav) 901120585Ssam KEY_FREESAV(&sav); 902120585Ssam 903120585Ssam /* XXX Further validation? */ 904120585Ssam 905120585Ssam /* 906120585Ssam * Depending on whether the SA is "valid" and 907120585Ssam * routing table size (mtudisc_{hi,lo}wat), we will: 908120585Ssam * - recalcurate the new MTU and create the 909120585Ssam * corresponding routing entry, or 910120585Ssam * - ignore the MTU change notification. 911120585Ssam */ 912120585Ssam icmp6_mtudisc_update(ip6cp, valid); 913120585Ssam } 914120585Ssam } else { 915120585Ssam /* we normally notify any pcb here */ 916120585Ssam } 917120585Ssam} 918105197Ssam#endif /* INET6 */ 919