ipsec_input.c revision 252028
1105197Ssam/* $FreeBSD: head/sys/netipsec/ipsec_input.c 252028 2013-06-20 11:44:16Z ae $ */ 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/route.h> 61105197Ssam#include <net/netisr.h> 62195699Srwatson#include <net/vnet.h> 63105197Ssam 64105197Ssam#include <netinet/in.h> 65105197Ssam#include <netinet/in_systm.h> 66105197Ssam#include <netinet/ip.h> 67105197Ssam#include <netinet/ip_var.h> 68105197Ssam#include <netinet/in_var.h> 69105197Ssam 70105197Ssam#include <netinet/ip6.h> 71105197Ssam#ifdef INET6 72105197Ssam#include <netinet6/ip6_var.h> 73105197Ssam#endif 74105197Ssam#include <netinet/in_pcb.h> 75105197Ssam#ifdef INET6 76105197Ssam#include <netinet/icmp6.h> 77105197Ssam#endif 78105197Ssam 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.h> 85105197Ssam#include <netipsec/esp_var.h> 86105197Ssam#include <netipsec/ipcomp_var.h> 87105197Ssam 88105197Ssam#include <netipsec/key.h> 89105197Ssam#include <netipsec/keydb.h> 90105197Ssam 91105197Ssam#include <netipsec/xform.h> 92105197Ssam#include <netinet6/ip6protosw.h> 93105197Ssam 94105197Ssam#include <machine/in_cksum.h> 95105197Ssam#include <machine/stdarg.h> 96105197Ssam 97181627Svanhu#ifdef DEV_ENC 98181627Svanhu#include <net/if_enc.h> 99181627Svanhu#endif 100181627Svanhu 101181627Svanhu 102252028Sae#define IPSEC_ISTAT(proto, name) do { \ 103252028Sae if ((proto) == IPPROTO_ESP) \ 104252028Sae ESPSTAT_INC(esps_##name); \ 105252028Sae else if ((proto) == IPPROTO_AH) \ 106252028Sae AHSTAT_INC(ahs_##name); \ 107252028Sae else \ 108252028Sae IPCOMPSTAT_INC(ipcomps_##name); \ 109252028Sae} while (0) 110105197Ssam 111193947Sbz#ifdef INET 112120585Ssamstatic void ipsec4_common_ctlinput(int, struct sockaddr *, void *, int); 113193947Sbz#endif 114120585Ssam 115105197Ssam/* 116105197Ssam * ipsec_common_input gets called when an IPsec-protected packet 117214351Sthomas * is received by IPv4 or IPv6. Its job is to find the right SA 118170793Sbz * and call the appropriate transform. The transform callback 119105197Ssam * takes care of further processing (like ingress filtering). 120105197Ssam */ 121105197Ssamstatic int 122105197Ssamipsec_common_input(struct mbuf *m, int skip, int protoff, int af, int sproto) 123105197Ssam{ 124105197Ssam union sockaddr_union dst_address; 125105197Ssam struct secasvar *sav; 126105197Ssam u_int32_t spi; 127119643Ssam int error; 128221129Sbz#ifdef INET 129194062Svanhu#ifdef IPSEC_NAT_T 130194062Svanhu struct m_tag *tag; 131194062Svanhu#endif 132221129Sbz#endif 133105197Ssam 134252028Sae IPSEC_ISTAT(sproto, input); 135105197Ssam 136120585Ssam IPSEC_ASSERT(m != NULL, ("null packet")); 137105197Ssam 138170792Sbz IPSEC_ASSERT(sproto == IPPROTO_ESP || sproto == IPPROTO_AH || 139170792Sbz sproto == IPPROTO_IPCOMP, 140170792Sbz ("unexpected security protocol %u", sproto)); 141170792Sbz 142181803Sbz if ((sproto == IPPROTO_ESP && !V_esp_enable) || 143181803Sbz (sproto == IPPROTO_AH && !V_ah_enable) || 144181803Sbz (sproto == IPPROTO_IPCOMP && !V_ipcomp_enable)) { 145105197Ssam m_freem(m); 146252028Sae IPSEC_ISTAT(sproto, pdrops); 147105197Ssam return EOPNOTSUPP; 148105197Ssam } 149105197Ssam 150105197Ssam if (m->m_pkthdr.len - skip < 2 * sizeof (u_int32_t)) { 151105197Ssam m_freem(m); 152252028Sae IPSEC_ISTAT(sproto, hdrops); 153120585Ssam DPRINTF(("%s: packet too small\n", __func__)); 154105197Ssam return EINVAL; 155105197Ssam } 156105197Ssam 157105197Ssam /* Retrieve the SPI from the relevant IPsec header */ 158105197Ssam if (sproto == IPPROTO_ESP) 159105197Ssam m_copydata(m, skip, sizeof(u_int32_t), (caddr_t) &spi); 160105197Ssam else if (sproto == IPPROTO_AH) 161105197Ssam m_copydata(m, skip + sizeof(u_int32_t), sizeof(u_int32_t), 162105197Ssam (caddr_t) &spi); 163105197Ssam else if (sproto == IPPROTO_IPCOMP) { 164105197Ssam u_int16_t cpi; 165105197Ssam m_copydata(m, skip + sizeof(u_int16_t), sizeof(u_int16_t), 166105197Ssam (caddr_t) &cpi); 167105197Ssam spi = ntohl(htons(cpi)); 168105197Ssam } 169105197Ssam 170105197Ssam /* 171105197Ssam * Find the SA and (indirectly) call the appropriate 172105197Ssam * kernel crypto routine. The resulting mbuf chain is a valid 173105197Ssam * IP packet ready to go through input processing. 174105197Ssam */ 175105197Ssam bzero(&dst_address, sizeof (dst_address)); 176105197Ssam dst_address.sa.sa_family = af; 177105197Ssam switch (af) { 178105197Ssam#ifdef INET 179105197Ssam case AF_INET: 180105197Ssam dst_address.sin.sin_len = sizeof(struct sockaddr_in); 181105197Ssam m_copydata(m, offsetof(struct ip, ip_dst), 182105197Ssam sizeof(struct in_addr), 183105197Ssam (caddr_t) &dst_address.sin.sin_addr); 184194062Svanhu#ifdef IPSEC_NAT_T 185194062Svanhu /* Find the source port for NAT-T; see udp*_espdecap. */ 186194062Svanhu tag = m_tag_find(m, PACKET_TAG_IPSEC_NAT_T_PORTS, NULL); 187194062Svanhu if (tag != NULL) 188194062Svanhu dst_address.sin.sin_port = ((u_int16_t *)(tag + 1))[1]; 189194062Svanhu#endif /* IPSEC_NAT_T */ 190105197Ssam break; 191105197Ssam#endif /* INET */ 192105197Ssam#ifdef INET6 193105197Ssam case AF_INET6: 194105197Ssam dst_address.sin6.sin6_len = sizeof(struct sockaddr_in6); 195105197Ssam m_copydata(m, offsetof(struct ip6_hdr, ip6_dst), 196105197Ssam sizeof(struct in6_addr), 197105197Ssam (caddr_t) &dst_address.sin6.sin6_addr); 198105197Ssam break; 199105197Ssam#endif /* INET6 */ 200105197Ssam default: 201120585Ssam DPRINTF(("%s: unsupported protocol family %u\n", __func__, af)); 202105197Ssam m_freem(m); 203252028Sae IPSEC_ISTAT(sproto, nopf); 204105197Ssam return EPFNOSUPPORT; 205105197Ssam } 206105197Ssam 207105197Ssam /* NB: only pass dst since key_allocsa follows RFC2401 */ 208105197Ssam sav = KEY_ALLOCSA(&dst_address, sproto, spi); 209105197Ssam if (sav == NULL) { 210120585Ssam DPRINTF(("%s: no key association found for SA %s/%08lx/%u\n", 211120585Ssam __func__, ipsec_address(&dst_address), 212105197Ssam (u_long) ntohl(spi), sproto)); 213252028Sae IPSEC_ISTAT(sproto, notdb); 214105197Ssam m_freem(m); 215105197Ssam return ENOENT; 216105197Ssam } 217105197Ssam 218105197Ssam if (sav->tdb_xform == NULL) { 219120585Ssam DPRINTF(("%s: attempted to use uninitialized SA %s/%08lx/%u\n", 220120585Ssam __func__, ipsec_address(&dst_address), 221105197Ssam (u_long) ntohl(spi), sproto)); 222252028Sae IPSEC_ISTAT(sproto, noxform); 223105197Ssam KEY_FREESAV(&sav); 224105197Ssam m_freem(m); 225105197Ssam return ENXIO; 226105197Ssam } 227105197Ssam 228105197Ssam /* 229105197Ssam * Call appropriate transform and return -- callback takes care of 230105197Ssam * everything else. 231105197Ssam */ 232105197Ssam error = (*sav->tdb_xform->xf_input)(m, sav, skip, protoff); 233105197Ssam KEY_FREESAV(&sav); 234105197Ssam return error; 235105197Ssam} 236105197Ssam 237105197Ssam#ifdef INET 238105197Ssam/* 239105197Ssam * Common input handler for IPv4 AH, ESP, and IPCOMP. 240105197Ssam */ 241105197Ssamint 242105197Ssamipsec4_common_input(struct mbuf *m, ...) 243105197Ssam{ 244105197Ssam va_list ap; 245105197Ssam int off, nxt; 246105197Ssam 247105197Ssam va_start(ap, m); 248105197Ssam off = va_arg(ap, int); 249105197Ssam nxt = va_arg(ap, int); 250105197Ssam va_end(ap); 251105197Ssam 252105197Ssam return ipsec_common_input(m, off, offsetof(struct ip, ip_p), 253105197Ssam AF_INET, nxt); 254105197Ssam} 255105197Ssam 256106680Ssamvoid 257106680Ssamah4_input(struct mbuf *m, int off) 258106680Ssam{ 259106680Ssam ipsec4_common_input(m, off, IPPROTO_AH); 260106680Ssam} 261120585Ssamvoid 262120585Ssamah4_ctlinput(int cmd, struct sockaddr *sa, void *v) 263120585Ssam{ 264120585Ssam if (sa->sa_family == AF_INET && 265120585Ssam sa->sa_len == sizeof(struct sockaddr_in)) 266120585Ssam ipsec4_common_ctlinput(cmd, sa, v, IPPROTO_AH); 267120585Ssam} 268106680Ssam 269106680Ssamvoid 270106680Ssamesp4_input(struct mbuf *m, int off) 271106680Ssam{ 272106680Ssam ipsec4_common_input(m, off, IPPROTO_ESP); 273106680Ssam} 274120585Ssamvoid 275120585Ssamesp4_ctlinput(int cmd, struct sockaddr *sa, void *v) 276120585Ssam{ 277120585Ssam if (sa->sa_family == AF_INET && 278120585Ssam sa->sa_len == sizeof(struct sockaddr_in)) 279120585Ssam ipsec4_common_ctlinput(cmd, sa, v, IPPROTO_ESP); 280120585Ssam} 281106680Ssam 282106680Ssamvoid 283106680Ssamipcomp4_input(struct mbuf *m, int off) 284106680Ssam{ 285106680Ssam ipsec4_common_input(m, off, IPPROTO_IPCOMP); 286106680Ssam} 287106680Ssam 288105197Ssam/* 289105197Ssam * IPsec input callback for INET protocols. 290105197Ssam * This routine is called as the transform callback. 291105197Ssam * Takes care of filtering and other sanity checks on 292105197Ssam * the processed packet. 293105197Ssam */ 294105197Ssamint 295105197Ssamipsec4_common_input_cb(struct mbuf *m, struct secasvar *sav, 296105197Ssam int skip, int protoff, struct m_tag *mt) 297105197Ssam{ 298105197Ssam int prot, af, sproto; 299105197Ssam struct ip *ip; 300105197Ssam struct m_tag *mtag; 301105197Ssam struct tdb_ident *tdbi; 302105197Ssam struct secasindex *saidx; 303105197Ssam int error; 304165222Sbz#ifdef INET6 305165118Sbz#ifdef notyet 306165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 307165118Sbz#endif 308165118Sbz#endif 309105197Ssam 310120585Ssam IPSEC_ASSERT(m != NULL, ("null mbuf")); 311120585Ssam IPSEC_ASSERT(sav != NULL, ("null SA")); 312120585Ssam IPSEC_ASSERT(sav->sah != NULL, ("null SAH")); 313105197Ssam saidx = &sav->sah->saidx; 314105197Ssam af = saidx->dst.sa.sa_family; 315120585Ssam IPSEC_ASSERT(af == AF_INET, ("unexpected af %u", af)); 316105197Ssam sproto = saidx->proto; 317120585Ssam IPSEC_ASSERT(sproto == IPPROTO_ESP || sproto == IPPROTO_AH || 318105197Ssam sproto == IPPROTO_IPCOMP, 319120585Ssam ("unexpected security protocol %u", sproto)); 320105197Ssam 321105197Ssam /* Sanity check */ 322105197Ssam if (m == NULL) { 323120585Ssam DPRINTF(("%s: null mbuf", __func__)); 324252028Sae IPSEC_ISTAT(sproto, badkcr); 325105197Ssam KEY_FREESAV(&sav); 326105197Ssam return EINVAL; 327105197Ssam } 328105197Ssam 329105197Ssam if (skip != 0) { 330241922Sglebius /* 331241922Sglebius * Fix IPv4 header 332241922Sglebius * XXXGL: do we need this entire block? 333241922Sglebius */ 334105197Ssam if (m->m_len < skip && (m = m_pullup(m, skip)) == NULL) { 335120585Ssam DPRINTF(("%s: processing failed for SA %s/%08lx\n", 336120585Ssam __func__, ipsec_address(&sav->sah->saidx.dst), 337105197Ssam (u_long) ntohl(sav->spi))); 338252028Sae IPSEC_ISTAT(sproto, hdrops); 339105197Ssam error = ENOBUFS; 340105197Ssam goto bad; 341105197Ssam } 342105197Ssam 343105197Ssam ip = mtod(m, struct ip *); 344105197Ssam ip->ip_len = htons(m->m_pkthdr.len); 345105197Ssam ip->ip_sum = 0; 346105197Ssam ip->ip_sum = in_cksum(m, ip->ip_hl << 2); 347105197Ssam } else { 348105197Ssam ip = mtod(m, struct ip *); 349105197Ssam } 350105197Ssam prot = ip->ip_p; 351105197Ssam 352159215Sgnn#ifdef notyet 353105197Ssam /* IP-in-IP encapsulation */ 354105197Ssam if (prot == IPPROTO_IPIP) { 355105197Ssam struct ip ipn; 356105197Ssam 357118888Ssam if (m->m_pkthdr.len - skip < sizeof(struct ip)) { 358252028Sae IPSEC_ISTAT(sproto, hdrops); 359118888Ssam error = EINVAL; 360118888Ssam goto bad; 361118888Ssam } 362105197Ssam /* ipn will now contain the inner IPv4 header */ 363105197Ssam m_copydata(m, ip->ip_hl << 2, sizeof(struct ip), 364105197Ssam (caddr_t) &ipn); 365105197Ssam 366105197Ssam /* XXX PROXY address isn't recorded in SAH */ 367105197Ssam /* 368105197Ssam * Check that the inner source address is the same as 369105197Ssam * the proxy address, if available. 370105197Ssam */ 371105197Ssam if ((saidx->proxy.sa.sa_family == AF_INET && 372105197Ssam saidx->proxy.sin.sin_addr.s_addr != 373105197Ssam INADDR_ANY && 374105197Ssam ipn.ip_src.s_addr != 375105197Ssam saidx->proxy.sin.sin_addr.s_addr) || 376105197Ssam (saidx->proxy.sa.sa_family != AF_INET && 377105197Ssam saidx->proxy.sa.sa_family != 0)) { 378105197Ssam 379120585Ssam DPRINTF(("%s: inner source address %s doesn't " 380120585Ssam "correspond to expected proxy source %s, " 381120585Ssam "SA %s/%08lx\n", __func__, 382105197Ssam inet_ntoa4(ipn.ip_src), 383105197Ssam ipsp_address(saidx->proxy), 384105197Ssam ipsp_address(saidx->dst), 385105197Ssam (u_long) ntohl(sav->spi))); 386105197Ssam 387252028Sae IPSEC_ISTAT(sproto, pdrops); 388105197Ssam error = EACCES; 389105197Ssam goto bad; 390105197Ssam } 391105197Ssam } 392159237Spjd#ifdef INET6 393105197Ssam /* IPv6-in-IP encapsulation. */ 394105197Ssam if (prot == IPPROTO_IPV6) { 395105197Ssam struct ip6_hdr ip6n; 396105197Ssam 397118888Ssam if (m->m_pkthdr.len - skip < sizeof(struct ip6_hdr)) { 398252028Sae IPSEC_ISTAT(sproto, hdrops); 399118888Ssam error = EINVAL; 400118888Ssam goto bad; 401118888Ssam } 402105197Ssam /* ip6n will now contain the inner IPv6 header. */ 403105197Ssam m_copydata(m, ip->ip_hl << 2, sizeof(struct ip6_hdr), 404105197Ssam (caddr_t) &ip6n); 405105197Ssam 406105197Ssam /* 407105197Ssam * Check that the inner source address is the same as 408105197Ssam * the proxy address, if available. 409105197Ssam */ 410105197Ssam if ((saidx->proxy.sa.sa_family == AF_INET6 && 411105197Ssam !IN6_IS_ADDR_UNSPECIFIED(&saidx->proxy.sin6.sin6_addr) && 412105197Ssam !IN6_ARE_ADDR_EQUAL(&ip6n.ip6_src, 413105197Ssam &saidx->proxy.sin6.sin6_addr)) || 414105197Ssam (saidx->proxy.sa.sa_family != AF_INET6 && 415105197Ssam saidx->proxy.sa.sa_family != 0)) { 416105197Ssam 417120585Ssam DPRINTF(("%s: inner source address %s doesn't " 418120585Ssam "correspond to expected proxy source %s, " 419120585Ssam "SA %s/%08lx\n", __func__, 420165118Sbz ip6_sprintf(ip6buf, &ip6n.ip6_src), 421105197Ssam ipsec_address(&saidx->proxy), 422105197Ssam ipsec_address(&saidx->dst), 423105197Ssam (u_long) ntohl(sav->spi))); 424105197Ssam 425252028Sae IPSEC_ISTAT(sproto, pdrops); 426105197Ssam error = EACCES; 427105197Ssam goto bad; 428105197Ssam } 429105197Ssam } 430105197Ssam#endif /* INET6 */ 431159215Sgnn#endif /*XXX*/ 432105197Ssam 433105197Ssam /* 434105197Ssam * Record what we've done to the packet (under what SA it was 435105197Ssam * processed). If we've been passed an mtag, it means the packet 436105197Ssam * was already processed by an ethernet/crypto combo card and 437105197Ssam * thus has a tag attached with all the right information, but 438105197Ssam * with a PACKET_TAG_IPSEC_IN_CRYPTO_DONE as opposed to 439105197Ssam * PACKET_TAG_IPSEC_IN_DONE type; in that case, just change the type. 440105197Ssam */ 441105197Ssam if (mt == NULL && sproto != IPPROTO_IPCOMP) { 442105197Ssam mtag = m_tag_get(PACKET_TAG_IPSEC_IN_DONE, 443105197Ssam sizeof(struct tdb_ident), M_NOWAIT); 444105197Ssam if (mtag == NULL) { 445120585Ssam DPRINTF(("%s: failed to get tag\n", __func__)); 446252028Sae IPSEC_ISTAT(sproto, hdrops); 447105197Ssam error = ENOMEM; 448105197Ssam goto bad; 449105197Ssam } 450105197Ssam 451105197Ssam tdbi = (struct tdb_ident *)(mtag + 1); 452105197Ssam bcopy(&saidx->dst, &tdbi->dst, saidx->dst.sa.sa_len); 453105197Ssam tdbi->proto = sproto; 454105197Ssam tdbi->spi = sav->spi; 455174054Sbz /* Cache those two for enc(4) in xform_ipip. */ 456174054Sbz tdbi->alg_auth = sav->alg_auth; 457174054Sbz tdbi->alg_enc = sav->alg_enc; 458105197Ssam 459105197Ssam m_tag_prepend(m, mtag); 460170797Sbz } else if (mt != NULL) { 461105197Ssam mt->m_tag_id = PACKET_TAG_IPSEC_IN_DONE; 462105197Ssam /* XXX do we need to mark m_flags??? */ 463105197Ssam } 464105197Ssam 465105197Ssam key_sa_recordxfer(sav, m); /* record data transfer */ 466105197Ssam 467159965Sthompsa#ifdef DEV_ENC 468181627Svanhu encif->if_ipackets++; 469181627Svanhu encif->if_ibytes += m->m_pkthdr.len; 470181627Svanhu 471105197Ssam /* 472159965Sthompsa * Pass the mbuf to enc0 for bpf and pfil. We will filter the IPIP 473159965Sthompsa * packet later after it has been decapsulated. 474159965Sthompsa */ 475174054Sbz ipsec_bpf(m, sav, AF_INET, ENC_IN|ENC_BEFORE); 476159965Sthompsa 477159965Sthompsa if (prot != IPPROTO_IPIP) 478174054Sbz if ((error = ipsec_filter(&m, PFIL_IN, ENC_IN|ENC_BEFORE)) != 0) 479159965Sthompsa return (error); 480159965Sthompsa#endif 481159965Sthompsa 482159965Sthompsa /* 483105197Ssam * Re-dispatch via software interrupt. 484105197Ssam */ 485208508Sbz if ((error = netisr_queue_src(NETISR_IP, (uintptr_t)sav->spi, m))) { 486252028Sae IPSEC_ISTAT(sproto, qfull); 487120585Ssam DPRINTF(("%s: queue full; proto %u packet dropped\n", 488120585Ssam __func__, sproto)); 489134391Sandre return error; 490105197Ssam } 491105197Ssam return 0; 492105197Ssambad: 493105197Ssam m_freem(m); 494105197Ssam return error; 495105197Ssam} 496120585Ssam 497120585Ssamvoid 498120585Ssamipsec4_common_ctlinput(int cmd, struct sockaddr *sa, void *v, int proto) 499120585Ssam{ 500120585Ssam /* XXX nothing just yet */ 501120585Ssam} 502105197Ssam#endif /* INET */ 503105197Ssam 504105197Ssam#ifdef INET6 505105197Ssam/* IPv6 AH wrapper. */ 506105197Ssamint 507105197Ssamipsec6_common_input(struct mbuf **mp, int *offp, int proto) 508105197Ssam{ 509105197Ssam int l = 0; 510105197Ssam int protoff; 511105197Ssam struct ip6_ext ip6e; 512105197Ssam 513105197Ssam if (*offp < sizeof(struct ip6_hdr)) { 514120585Ssam DPRINTF(("%s: bad offset %u\n", __func__, *offp)); 515105197Ssam return IPPROTO_DONE; 516105197Ssam } else if (*offp == sizeof(struct ip6_hdr)) { 517105197Ssam protoff = offsetof(struct ip6_hdr, ip6_nxt); 518105197Ssam } else { 519105197Ssam /* Chase down the header chain... */ 520105197Ssam protoff = sizeof(struct ip6_hdr); 521105197Ssam 522105197Ssam do { 523105197Ssam protoff += l; 524105197Ssam m_copydata(*mp, protoff, sizeof(ip6e), 525105197Ssam (caddr_t) &ip6e); 526105197Ssam 527105197Ssam if (ip6e.ip6e_nxt == IPPROTO_AH) 528105197Ssam l = (ip6e.ip6e_len + 2) << 2; 529105197Ssam else 530105197Ssam l = (ip6e.ip6e_len + 1) << 3; 531120585Ssam IPSEC_ASSERT(l > 0, ("l went zero or negative")); 532105197Ssam } while (protoff + l < *offp); 533105197Ssam 534105197Ssam /* Malformed packet check */ 535105197Ssam if (protoff + l != *offp) { 536120585Ssam DPRINTF(("%s: bad packet header chain, protoff %u, " 537120585Ssam "l %u, off %u\n", __func__, protoff, l, *offp)); 538252028Sae IPSEC_ISTAT(proto, hdrops); 539105197Ssam m_freem(*mp); 540105197Ssam *mp = NULL; 541105197Ssam return IPPROTO_DONE; 542105197Ssam } 543105197Ssam protoff += offsetof(struct ip6_ext, ip6e_nxt); 544105197Ssam } 545105197Ssam (void) ipsec_common_input(*mp, *offp, protoff, AF_INET6, proto); 546105197Ssam return IPPROTO_DONE; 547105197Ssam} 548105197Ssam 549105197Ssam/* 550105197Ssam * IPsec input callback, called by the transform callback. Takes care of 551105197Ssam * filtering and other sanity checks on the processed packet. 552105197Ssam */ 553105197Ssamint 554105197Ssamipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip, int protoff, 555105197Ssam struct m_tag *mt) 556105197Ssam{ 557105197Ssam int prot, af, sproto; 558105197Ssam struct ip6_hdr *ip6; 559105197Ssam struct m_tag *mtag; 560105197Ssam struct tdb_ident *tdbi; 561105197Ssam struct secasindex *saidx; 562105197Ssam int nxt; 563105197Ssam u_int8_t nxt8; 564105197Ssam int error, nest; 565165118Sbz#ifdef notyet 566165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 567165118Sbz#endif 568105197Ssam 569120585Ssam IPSEC_ASSERT(m != NULL, ("null mbuf")); 570120585Ssam IPSEC_ASSERT(sav != NULL, ("null SA")); 571120585Ssam IPSEC_ASSERT(sav->sah != NULL, ("null SAH")); 572105197Ssam saidx = &sav->sah->saidx; 573105197Ssam af = saidx->dst.sa.sa_family; 574120585Ssam IPSEC_ASSERT(af == AF_INET6, ("unexpected af %u", af)); 575105197Ssam sproto = saidx->proto; 576120585Ssam IPSEC_ASSERT(sproto == IPPROTO_ESP || sproto == IPPROTO_AH || 577105197Ssam sproto == IPPROTO_IPCOMP, 578120585Ssam ("unexpected security protocol %u", sproto)); 579105197Ssam 580105197Ssam /* Sanity check */ 581105197Ssam if (m == NULL) { 582120585Ssam DPRINTF(("%s: null mbuf", __func__)); 583252028Sae IPSEC_ISTAT(sproto, badkcr); 584105197Ssam error = EINVAL; 585105197Ssam goto bad; 586105197Ssam } 587105197Ssam 588105197Ssam /* Fix IPv6 header */ 589105197Ssam if (m->m_len < sizeof(struct ip6_hdr) && 590105197Ssam (m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) { 591105197Ssam 592120585Ssam DPRINTF(("%s: processing failed for SA %s/%08lx\n", 593120585Ssam __func__, ipsec_address(&sav->sah->saidx.dst), 594105197Ssam (u_long) ntohl(sav->spi))); 595105197Ssam 596252028Sae IPSEC_ISTAT(sproto, hdrops); 597105197Ssam error = EACCES; 598105197Ssam goto bad; 599105197Ssam } 600105197Ssam 601105197Ssam ip6 = mtod(m, struct ip6_hdr *); 602105197Ssam ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr)); 603105197Ssam 604105197Ssam /* Save protocol */ 605105197Ssam m_copydata(m, protoff, 1, (unsigned char *) &prot); 606105197Ssam 607159215Sgnn#ifdef notyet 608105197Ssam#ifdef INET 609105197Ssam /* IP-in-IP encapsulation */ 610105197Ssam if (prot == IPPROTO_IPIP) { 611105197Ssam struct ip ipn; 612105197Ssam 613118888Ssam if (m->m_pkthdr.len - skip < sizeof(struct ip)) { 614252028Sae IPSEC_ISTAT(sproto, hdrops); 615118888Ssam error = EINVAL; 616118888Ssam goto bad; 617118888Ssam } 618105197Ssam /* ipn will now contain the inner IPv4 header */ 619105197Ssam m_copydata(m, skip, sizeof(struct ip), (caddr_t) &ipn); 620105197Ssam 621105197Ssam /* 622105197Ssam * Check that the inner source address is the same as 623105197Ssam * the proxy address, if available. 624105197Ssam */ 625105197Ssam if ((saidx->proxy.sa.sa_family == AF_INET && 626105197Ssam saidx->proxy.sin.sin_addr.s_addr != INADDR_ANY && 627105197Ssam ipn.ip_src.s_addr != saidx->proxy.sin.sin_addr.s_addr) || 628105197Ssam (saidx->proxy.sa.sa_family != AF_INET && 629105197Ssam saidx->proxy.sa.sa_family != 0)) { 630105197Ssam 631120585Ssam DPRINTF(("%s: inner source address %s doesn't " 632120585Ssam "correspond to expected proxy source %s, " 633120585Ssam "SA %s/%08lx\n", __func__, 634105197Ssam inet_ntoa4(ipn.ip_src), 635105197Ssam ipsec_address(&saidx->proxy), 636105197Ssam ipsec_address(&saidx->dst), 637105197Ssam (u_long) ntohl(sav->spi))); 638105197Ssam 639252028Sae IPSEC_ISTAT(sproto, pdrops); 640105197Ssam error = EACCES; 641105197Ssam goto bad; 642105197Ssam } 643105197Ssam } 644105197Ssam#endif /* INET */ 645105197Ssam 646105197Ssam /* IPv6-in-IP encapsulation */ 647105197Ssam if (prot == IPPROTO_IPV6) { 648105197Ssam struct ip6_hdr ip6n; 649105197Ssam 650118888Ssam if (m->m_pkthdr.len - skip < sizeof(struct ip6_hdr)) { 651252028Sae IPSEC_ISTAT(sproto, hdrops); 652118888Ssam error = EINVAL; 653118888Ssam goto bad; 654118888Ssam } 655105197Ssam /* ip6n will now contain the inner IPv6 header. */ 656105197Ssam m_copydata(m, skip, sizeof(struct ip6_hdr), 657105197Ssam (caddr_t) &ip6n); 658105197Ssam 659105197Ssam /* 660105197Ssam * Check that the inner source address is the same as 661105197Ssam * the proxy address, if available. 662105197Ssam */ 663105197Ssam if ((saidx->proxy.sa.sa_family == AF_INET6 && 664105197Ssam !IN6_IS_ADDR_UNSPECIFIED(&saidx->proxy.sin6.sin6_addr) && 665105197Ssam !IN6_ARE_ADDR_EQUAL(&ip6n.ip6_src, 666105197Ssam &saidx->proxy.sin6.sin6_addr)) || 667105197Ssam (saidx->proxy.sa.sa_family != AF_INET6 && 668105197Ssam saidx->proxy.sa.sa_family != 0)) { 669105197Ssam 670120585Ssam DPRINTF(("%s: inner source address %s doesn't " 671120585Ssam "correspond to expected proxy source %s, " 672120585Ssam "SA %s/%08lx\n", __func__, 673165118Sbz ip6_sprintf(ip6buf, &ip6n.ip6_src), 674105197Ssam ipsec_address(&saidx->proxy), 675105197Ssam ipsec_address(&saidx->dst), 676105197Ssam (u_long) ntohl(sav->spi))); 677105197Ssam 678252028Sae IPSEC_ISTAT(sproto, pdrops); 679105197Ssam error = EACCES; 680105197Ssam goto bad; 681105197Ssam } 682159215Sgnn } 683105197Ssam#endif /*XXX*/ 684105197Ssam 685105197Ssam /* 686105197Ssam * Record what we've done to the packet (under what SA it was 687105197Ssam * processed). If we've been passed an mtag, it means the packet 688105197Ssam * was already processed by an ethernet/crypto combo card and 689105197Ssam * thus has a tag attached with all the right information, but 690105197Ssam * with a PACKET_TAG_IPSEC_IN_CRYPTO_DONE as opposed to 691105197Ssam * PACKET_TAG_IPSEC_IN_DONE type; in that case, just change the type. 692105197Ssam */ 693105197Ssam if (mt == NULL && sproto != IPPROTO_IPCOMP) { 694105197Ssam mtag = m_tag_get(PACKET_TAG_IPSEC_IN_DONE, 695105197Ssam sizeof(struct tdb_ident), M_NOWAIT); 696105197Ssam if (mtag == NULL) { 697120585Ssam DPRINTF(("%s: failed to get tag\n", __func__)); 698252028Sae IPSEC_ISTAT(sproto, hdrops); 699105197Ssam error = ENOMEM; 700105197Ssam goto bad; 701105197Ssam } 702105197Ssam 703105197Ssam tdbi = (struct tdb_ident *)(mtag + 1); 704105197Ssam bcopy(&saidx->dst, &tdbi->dst, sizeof(union sockaddr_union)); 705105197Ssam tdbi->proto = sproto; 706105197Ssam tdbi->spi = sav->spi; 707174054Sbz /* Cache those two for enc(4) in xform_ipip. */ 708174054Sbz tdbi->alg_auth = sav->alg_auth; 709174054Sbz tdbi->alg_enc = sav->alg_enc; 710105197Ssam 711105197Ssam m_tag_prepend(m, mtag); 712105197Ssam } else { 713120585Ssam if (mt != NULL) 714120585Ssam mt->m_tag_id = PACKET_TAG_IPSEC_IN_DONE; 715105197Ssam /* XXX do we need to mark m_flags??? */ 716105197Ssam } 717105197Ssam 718105197Ssam key_sa_recordxfer(sav, m); 719105197Ssam 720174054Sbz#ifdef DEV_ENC 721181627Svanhu encif->if_ipackets++; 722181627Svanhu encif->if_ibytes += m->m_pkthdr.len; 723181627Svanhu 724174054Sbz /* 725174054Sbz * Pass the mbuf to enc0 for bpf and pfil. We will filter the IPIP 726174054Sbz * packet later after it has been decapsulated. 727174054Sbz */ 728174054Sbz ipsec_bpf(m, sav, AF_INET6, ENC_IN|ENC_BEFORE); 729174054Sbz 730174054Sbz /* XXX-BZ does not make sense. */ 731174054Sbz if (prot != IPPROTO_IPIP) 732174054Sbz if ((error = ipsec_filter(&m, PFIL_IN, ENC_IN|ENC_BEFORE)) != 0) 733174054Sbz return (error); 734174054Sbz#endif 735174054Sbz 736105197Ssam /* Retrieve new protocol */ 737105197Ssam m_copydata(m, protoff, sizeof(u_int8_t), (caddr_t) &nxt8); 738105197Ssam 739105197Ssam /* 740105197Ssam * See the end of ip6_input for this logic. 741105197Ssam * IPPROTO_IPV[46] case will be processed just like other ones 742105197Ssam */ 743105197Ssam nest = 0; 744105197Ssam nxt = nxt8; 745105197Ssam while (nxt != IPPROTO_DONE) { 746181803Sbz if (V_ip6_hdrnestlimit && (++nest > V_ip6_hdrnestlimit)) { 747249294Sae IP6STAT_INC(ip6s_toomanyhdr); 748105197Ssam error = EINVAL; 749105197Ssam goto bad; 750105197Ssam } 751105197Ssam 752105197Ssam /* 753105197Ssam * Protection against faulty packet - there should be 754105197Ssam * more sanity checks in header chain processing. 755105197Ssam */ 756105197Ssam if (m->m_pkthdr.len < skip) { 757249294Sae IP6STAT_INC(ip6s_tooshort); 758105197Ssam in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated); 759105197Ssam error = EINVAL; 760105197Ssam goto bad; 761105197Ssam } 762105197Ssam /* 763105197Ssam * Enforce IPsec policy checking if we are seeing last header. 764105197Ssam * note that we do not visit this with protocols with pcb layer 765105197Ssam * code - like udp/tcp/raw ip. 766105197Ssam */ 767105197Ssam if ((inet6sw[ip6_protox[nxt]].pr_flags & PR_LASTHDR) != 0 && 768105197Ssam ipsec6_in_reject(m, NULL)) { 769105197Ssam error = EINVAL; 770105197Ssam goto bad; 771105197Ssam } 772105197Ssam nxt = (*inet6sw[ip6_protox[nxt]].pr_input)(&m, &skip, nxt); 773105197Ssam } 774105197Ssam return 0; 775105197Ssambad: 776105197Ssam if (m) 777105197Ssam m_freem(m); 778105197Ssam return error; 779105197Ssam} 780120585Ssam 781120585Ssamvoid 782120585Ssamesp6_ctlinput(int cmd, struct sockaddr *sa, void *d) 783120585Ssam{ 784172149Sgnn struct ip6ctlparam *ip6cp = NULL; 785172149Sgnn struct mbuf *m = NULL; 786172149Sgnn struct ip6_hdr *ip6; 787172149Sgnn int off; 788172149Sgnn 789120585Ssam if (sa->sa_family != AF_INET6 || 790120585Ssam sa->sa_len != sizeof(struct sockaddr_in6)) 791120585Ssam return; 792120585Ssam if ((unsigned)cmd >= PRC_NCMDS) 793120585Ssam return; 794120585Ssam 795120585Ssam /* if the parameter is from icmp6, decode it. */ 796172149Sgnn if (d != NULL) { 797172149Sgnn ip6cp = (struct ip6ctlparam *)d; 798172149Sgnn m = ip6cp->ip6c_m; 799172149Sgnn ip6 = ip6cp->ip6c_ip6; 800172149Sgnn off = ip6cp->ip6c_off; 801172149Sgnn } else { 802172149Sgnn m = NULL; 803172149Sgnn ip6 = NULL; 804172149Sgnn off = 0; /* calm gcc */ 805172149Sgnn } 806120585Ssam 807172149Sgnn if (ip6 != NULL) { 808172149Sgnn 809120585Ssam struct ip6ctlparam ip6cp1; 810120585Ssam 811120585Ssam /* 812120585Ssam * Notify the error to all possible sockets via pfctlinput2. 813120585Ssam * Since the upper layer information (such as protocol type, 814120585Ssam * source and destination ports) is embedded in the encrypted 815120585Ssam * data and might have been cut, we can't directly call 816120585Ssam * an upper layer ctlinput function. However, the pcbnotify 817120585Ssam * function will consider source and destination addresses 818120585Ssam * as well as the flow info value, and may be able to find 819120585Ssam * some PCB that should be notified. 820120585Ssam * Although pfctlinput2 will call esp6_ctlinput(), there is 821120585Ssam * no possibility of an infinite loop of function calls, 822120585Ssam * because we don't pass the inner IPv6 header. 823120585Ssam */ 824120585Ssam bzero(&ip6cp1, sizeof(ip6cp1)); 825120585Ssam ip6cp1.ip6c_src = ip6cp->ip6c_src; 826120585Ssam pfctlinput2(cmd, sa, (void *)&ip6cp1); 827120585Ssam 828120585Ssam /* 829120585Ssam * Then go to special cases that need ESP header information. 830120585Ssam * XXX: We assume that when ip6 is non NULL, 831120585Ssam * M and OFF are valid. 832120585Ssam */ 833120585Ssam 834120585Ssam if (cmd == PRC_MSGSIZE) { 835120585Ssam struct secasvar *sav; 836120585Ssam u_int32_t spi; 837120585Ssam int valid; 838120585Ssam 839120585Ssam /* check header length before using m_copydata */ 840120585Ssam if (m->m_pkthdr.len < off + sizeof (struct esp)) 841120585Ssam return; 842120585Ssam m_copydata(m, off + offsetof(struct esp, esp_spi), 843120585Ssam sizeof(u_int32_t), (caddr_t) &spi); 844120585Ssam /* 845120585Ssam * Check to see if we have a valid SA corresponding to 846120585Ssam * the address in the ICMP message payload. 847120585Ssam */ 848120585Ssam sav = KEY_ALLOCSA((union sockaddr_union *)sa, 849120585Ssam IPPROTO_ESP, spi); 850120585Ssam valid = (sav != NULL); 851120585Ssam if (sav) 852120585Ssam KEY_FREESAV(&sav); 853120585Ssam 854120585Ssam /* XXX Further validation? */ 855120585Ssam 856120585Ssam /* 857120585Ssam * Depending on whether the SA is "valid" and 858120585Ssam * routing table size (mtudisc_{hi,lo}wat), we will: 859120585Ssam * - recalcurate the new MTU and create the 860120585Ssam * corresponding routing entry, or 861120585Ssam * - ignore the MTU change notification. 862120585Ssam */ 863120585Ssam icmp6_mtudisc_update(ip6cp, valid); 864120585Ssam } 865120585Ssam } else { 866120585Ssam /* we normally notify any pcb here */ 867120585Ssam } 868120585Ssam} 869105197Ssam#endif /* INET6 */ 870