ipsec_input.c revision 159215
1249259Sdim/* $FreeBSD: head/sys/netipsec/ipsec_input.c 159215 2006-06-04 03:11:09Z gnn $ */ 2249259Sdim/* $OpenBSD: ipsec_input.c,v 1.63 2003/02/20 18:35:43 deraadt Exp $ */ 3249259Sdim/*- 4249259Sdim * The authors of this code are John Ioannidis (ji@tla.org), 5249259Sdim * Angelos D. Keromytis (kermit@csd.uch.gr) and 6249259Sdim * Niels Provos (provos@physnet.uni-hamburg.de). 7249259Sdim * 8249259Sdim * This code was written by John Ioannidis for BSD/OS in Athens, Greece, 9249259Sdim * in November 1995. 10249259Sdim * 11249259Sdim * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996, 12249259Sdim * by Angelos D. Keromytis. 13249259Sdim * 14249259Sdim * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis 15249259Sdim * and Niels Provos. 16249259Sdim * 17249259Sdim * Additional features in 1999 by Angelos D. Keromytis. 18249259Sdim * 19249259Sdim * Copyright (C) 1995, 1996, 1997, 1998, 1999 by John Ioannidis, 20249259Sdim * Angelos D. Keromytis and Niels Provos. 21249259Sdim * Copyright (c) 2001, Angelos D. Keromytis. 22249259Sdim * 23249259Sdim * Permission to use, copy, and modify this software with or without fee 24249259Sdim * is hereby granted, provided that this entire notice is included in 25249259Sdim * all copies of any software which is or includes a copy or 26249259Sdim * modification of this software. 27249259Sdim * You may use this code under the GNU public license if you so wish. Please 28249259Sdim * contribute changes back to the authors under this freer than GPL license 29249259Sdim * so that we may further the use of strong encryption without limitations to 30249259Sdim * all. 31249259Sdim * 32249259Sdim * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR 33249259Sdim * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY 34266759Sdim * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE 35266759Sdim * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR 36249259Sdim * PURPOSE. 37249259Sdim */ 38249259Sdim 39263509Sdim/* 40249259Sdim * IPsec input processing. 41263509Sdim */ 42263509Sdim 43249259Sdim#include "opt_inet.h" 44249259Sdim#include "opt_inet6.h" 45249259Sdim#include "opt_ipsec.h" 46249259Sdim 47249259Sdim#include <sys/param.h> 48249259Sdim#include <sys/systm.h> 49249259Sdim#include <sys/malloc.h> 50263509Sdim#include <sys/mbuf.h> 51263509Sdim#include <sys/domain.h> 52263509Sdim#include <sys/protosw.h> 53263509Sdim#include <sys/socket.h> 54263509Sdim#include <sys/errno.h> 55263509Sdim#include <sys/syslog.h> 56263509Sdim 57263509Sdim#include <net/if.h> 58263509Sdim#include <net/route.h> 59263509Sdim#include <net/netisr.h> 60263509Sdim 61263509Sdim#include <netinet/in.h> 62263509Sdim#include <netinet/in_systm.h> 63263509Sdim#include <netinet/ip.h> 64263509Sdim#include <netinet/ip_var.h> 65263509Sdim#include <netinet/in_var.h> 66263509Sdim 67263509Sdim#include <netinet/ip6.h> 68263509Sdim#ifdef INET6 69263509Sdim#include <netinet6/ip6_var.h> 70263509Sdim#endif 71263509Sdim#include <netinet/in_pcb.h> 72263509Sdim#ifdef INET6 73263509Sdim#include <netinet/icmp6.h> 74263509Sdim#endif 75263509Sdim 76263509Sdim#include <netipsec/ipsec.h> 77263509Sdim#ifdef INET6 78249259Sdim#include <netipsec/ipsec6.h> 79249259Sdim#endif 80249259Sdim#include <netipsec/ah_var.h> 81249259Sdim#include <netipsec/esp.h> 82249259Sdim#include <netipsec/esp_var.h> 83249259Sdim#include <netipsec/ipcomp_var.h> 84249259Sdim 85263509Sdim#include <netipsec/key.h> 86263509Sdim#include <netipsec/keydb.h> 87249259Sdim 88263509Sdim#include <netipsec/xform.h> 89263509Sdim#include <netinet6/ip6protosw.h> 90263509Sdim 91263509Sdim#include <machine/in_cksum.h> 92249259Sdim#include <machine/stdarg.h> 93249259Sdim 94249259Sdim#define IPSEC_ISTAT(p,x,y,z) ((p) == IPPROTO_ESP ? (x)++ : \ 95249259Sdim (p) == IPPROTO_AH ? (y)++ : (z)++) 96249259Sdim 97249259Sdimstatic void ipsec4_common_ctlinput(int, struct sockaddr *, void *, int); 98249259Sdim 99249259Sdim/* 100249259Sdim * ipsec_common_input gets called when an IPsec-protected packet 101249259Sdim * is received by IPv4 or IPv6. It's job is to find the right SA 102249259Sdim # and call the appropriate transform. The transform callback 103249259Sdim * takes care of further processing (like ingress filtering). 104249259Sdim */ 105249259Sdimstatic int 106249259Sdimipsec_common_input(struct mbuf *m, int skip, int protoff, int af, int sproto) 107249259Sdim{ 108249259Sdim union sockaddr_union dst_address; 109249259Sdim struct secasvar *sav; 110249259Sdim u_int32_t spi; 111249259Sdim int error; 112249259Sdim 113249259Sdim IPSEC_ISTAT(sproto, espstat.esps_input, ahstat.ahs_input, 114249259Sdim ipcompstat.ipcomps_input); 115249259Sdim 116249259Sdim IPSEC_ASSERT(m != NULL, ("null packet")); 117249259Sdim 118249259Sdim if ((sproto == IPPROTO_ESP && !esp_enable) || 119249259Sdim (sproto == IPPROTO_AH && !ah_enable) || 120249259Sdim (sproto == IPPROTO_IPCOMP && !ipcomp_enable)) { 121249259Sdim m_freem(m); 122249259Sdim IPSEC_ISTAT(sproto, espstat.esps_pdrops, ahstat.ahs_pdrops, 123249259Sdim ipcompstat.ipcomps_pdrops); 124249259Sdim return EOPNOTSUPP; 125249259Sdim } 126249259Sdim 127249259Sdim if (m->m_pkthdr.len - skip < 2 * sizeof (u_int32_t)) { 128249259Sdim m_freem(m); 129249259Sdim IPSEC_ISTAT(sproto, espstat.esps_hdrops, ahstat.ahs_hdrops, 130249259Sdim ipcompstat.ipcomps_hdrops); 131249259Sdim DPRINTF(("%s: packet too small\n", __func__)); 132249259Sdim return EINVAL; 133249259Sdim } 134249259Sdim 135249259Sdim /* Retrieve the SPI from the relevant IPsec header */ 136249259Sdim if (sproto == IPPROTO_ESP) 137249259Sdim m_copydata(m, skip, sizeof(u_int32_t), (caddr_t) &spi); 138249259Sdim else if (sproto == IPPROTO_AH) 139249259Sdim m_copydata(m, skip + sizeof(u_int32_t), sizeof(u_int32_t), 140249259Sdim (caddr_t) &spi); 141249259Sdim else if (sproto == IPPROTO_IPCOMP) { 142249259Sdim u_int16_t cpi; 143249259Sdim m_copydata(m, skip + sizeof(u_int16_t), sizeof(u_int16_t), 144249259Sdim (caddr_t) &cpi); 145249259Sdim spi = ntohl(htons(cpi)); 146249259Sdim } 147249259Sdim 148249259Sdim /* 149249259Sdim * Find the SA and (indirectly) call the appropriate 150249259Sdim * kernel crypto routine. The resulting mbuf chain is a valid 151249259Sdim * IP packet ready to go through input processing. 152249259Sdim */ 153249259Sdim bzero(&dst_address, sizeof (dst_address)); 154249259Sdim dst_address.sa.sa_family = af; 155249259Sdim switch (af) { 156249259Sdim#ifdef INET 157249259Sdim case AF_INET: 158249259Sdim dst_address.sin.sin_len = sizeof(struct sockaddr_in); 159249259Sdim m_copydata(m, offsetof(struct ip, ip_dst), 160249259Sdim sizeof(struct in_addr), 161249259Sdim (caddr_t) &dst_address.sin.sin_addr); 162249259Sdim break; 163249259Sdim#endif /* INET */ 164249259Sdim#ifdef INET6 165249259Sdim case AF_INET6: 166249259Sdim dst_address.sin6.sin6_len = sizeof(struct sockaddr_in6); 167249259Sdim m_copydata(m, offsetof(struct ip6_hdr, ip6_dst), 168249259Sdim sizeof(struct in6_addr), 169249259Sdim (caddr_t) &dst_address.sin6.sin6_addr); 170249259Sdim break; 171249259Sdim#endif /* INET6 */ 172249259Sdim default: 173249259Sdim DPRINTF(("%s: unsupported protocol family %u\n", __func__, af)); 174249259Sdim m_freem(m); 175249259Sdim IPSEC_ISTAT(sproto, espstat.esps_nopf, ahstat.ahs_nopf, 176249259Sdim ipcompstat.ipcomps_nopf); 177249259Sdim return EPFNOSUPPORT; 178249259Sdim } 179249259Sdim 180249259Sdim /* NB: only pass dst since key_allocsa follows RFC2401 */ 181249259Sdim sav = KEY_ALLOCSA(&dst_address, sproto, spi); 182249259Sdim if (sav == NULL) { 183249259Sdim DPRINTF(("%s: no key association found for SA %s/%08lx/%u\n", 184249259Sdim __func__, ipsec_address(&dst_address), 185249259Sdim (u_long) ntohl(spi), sproto)); 186249259Sdim IPSEC_ISTAT(sproto, espstat.esps_notdb, ahstat.ahs_notdb, 187249259Sdim ipcompstat.ipcomps_notdb); 188249259Sdim m_freem(m); 189249259Sdim return ENOENT; 190249259Sdim } 191249259Sdim 192249259Sdim if (sav->tdb_xform == NULL) { 193249259Sdim DPRINTF(("%s: attempted to use uninitialized SA %s/%08lx/%u\n", 194249259Sdim __func__, ipsec_address(&dst_address), 195249259Sdim (u_long) ntohl(spi), sproto)); 196249259Sdim IPSEC_ISTAT(sproto, espstat.esps_noxform, ahstat.ahs_noxform, 197249259Sdim ipcompstat.ipcomps_noxform); 198249259Sdim KEY_FREESAV(&sav); 199249259Sdim m_freem(m); 200249259Sdim return ENXIO; 201249259Sdim } 202249259Sdim 203249259Sdim /* 204249259Sdim * Call appropriate transform and return -- callback takes care of 205249259Sdim * everything else. 206249259Sdim */ 207249259Sdim error = (*sav->tdb_xform->xf_input)(m, sav, skip, protoff); 208249259Sdim KEY_FREESAV(&sav); 209249259Sdim return error; 210249259Sdim} 211249259Sdim 212249259Sdim#ifdef INET 213249259Sdim/* 214249259Sdim * Common input handler for IPv4 AH, ESP, and IPCOMP. 215249259Sdim */ 216249259Sdimint 217249259Sdimipsec4_common_input(struct mbuf *m, ...) 218249259Sdim{ 219249259Sdim va_list ap; 220249259Sdim int off, nxt; 221249259Sdim 222249259Sdim va_start(ap, m); 223249259Sdim off = va_arg(ap, int); 224249259Sdim nxt = va_arg(ap, int); 225249259Sdim va_end(ap); 226249259Sdim 227249259Sdim return ipsec_common_input(m, off, offsetof(struct ip, ip_p), 228249259Sdim AF_INET, nxt); 229249259Sdim} 230249259Sdim 231249259Sdimvoid 232249259Sdimah4_input(struct mbuf *m, int off) 233249259Sdim{ 234249259Sdim ipsec4_common_input(m, off, IPPROTO_AH); 235249259Sdim} 236249259Sdimvoid 237249259Sdimah4_ctlinput(int cmd, struct sockaddr *sa, void *v) 238249259Sdim{ 239249259Sdim if (sa->sa_family == AF_INET && 240249259Sdim sa->sa_len == sizeof(struct sockaddr_in)) 241249259Sdim ipsec4_common_ctlinput(cmd, sa, v, IPPROTO_AH); 242249259Sdim} 243249259Sdim 244249259Sdimvoid 245249259Sdimesp4_input(struct mbuf *m, int off) 246249259Sdim{ 247249259Sdim ipsec4_common_input(m, off, IPPROTO_ESP); 248249259Sdim} 249249259Sdimvoid 250249259Sdimesp4_ctlinput(int cmd, struct sockaddr *sa, void *v) 251249259Sdim{ 252249259Sdim if (sa->sa_family == AF_INET && 253249259Sdim sa->sa_len == sizeof(struct sockaddr_in)) 254249259Sdim ipsec4_common_ctlinput(cmd, sa, v, IPPROTO_ESP); 255249259Sdim} 256249259Sdim 257249259Sdimvoid 258249259Sdimipcomp4_input(struct mbuf *m, int off) 259249259Sdim{ 260249259Sdim ipsec4_common_input(m, off, IPPROTO_IPCOMP); 261249259Sdim} 262249259Sdim 263249259Sdim/* 264249259Sdim * IPsec input callback for INET protocols. 265249259Sdim * This routine is called as the transform callback. 266249259Sdim * Takes care of filtering and other sanity checks on 267249259Sdim * the processed packet. 268249259Sdim */ 269249259Sdimint 270249259Sdimipsec4_common_input_cb(struct mbuf *m, struct secasvar *sav, 271249259Sdim int skip, int protoff, struct m_tag *mt) 272249259Sdim{ 273249259Sdim int prot, af, sproto; 274249259Sdim struct ip *ip; 275249259Sdim struct m_tag *mtag; 276249259Sdim struct tdb_ident *tdbi; 277249259Sdim struct secasindex *saidx; 278249259Sdim int error; 279249259Sdim 280249259Sdim IPSEC_SPLASSERT_SOFTNET(__func__); 281249259Sdim 282263509Sdim IPSEC_ASSERT(m != NULL, ("null mbuf")); 283263509Sdim IPSEC_ASSERT(sav != NULL, ("null SA")); 284263509Sdim IPSEC_ASSERT(sav->sah != NULL, ("null SAH")); 285263509Sdim saidx = &sav->sah->saidx; 286263509Sdim af = saidx->dst.sa.sa_family; 287263509Sdim IPSEC_ASSERT(af == AF_INET, ("unexpected af %u", af)); 288263509Sdim sproto = saidx->proto; 289263509Sdim IPSEC_ASSERT(sproto == IPPROTO_ESP || sproto == IPPROTO_AH || 290263509Sdim sproto == IPPROTO_IPCOMP, 291263509Sdim ("unexpected security protocol %u", sproto)); 292263509Sdim 293263509Sdim /* Sanity check */ 294263509Sdim if (m == NULL) { 295263509Sdim DPRINTF(("%s: null mbuf", __func__)); 296263509Sdim IPSEC_ISTAT(sproto, espstat.esps_badkcr, ahstat.ahs_badkcr, 297263509Sdim ipcompstat.ipcomps_badkcr); 298263509Sdim KEY_FREESAV(&sav); 299263509Sdim return EINVAL; 300263509Sdim } 301263509Sdim 302263509Sdim if (skip != 0) { 303263509Sdim /* Fix IPv4 header */ 304263509Sdim if (m->m_len < skip && (m = m_pullup(m, skip)) == NULL) { 305263509Sdim DPRINTF(("%s: processing failed for SA %s/%08lx\n", 306263509Sdim __func__, ipsec_address(&sav->sah->saidx.dst), 307263509Sdim (u_long) ntohl(sav->spi))); 308263509Sdim IPSEC_ISTAT(sproto, espstat.esps_hdrops, ahstat.ahs_hdrops, 309263509Sdim ipcompstat.ipcomps_hdrops); 310263509Sdim error = ENOBUFS; 311263509Sdim goto bad; 312263509Sdim } 313263509Sdim 314263509Sdim ip = mtod(m, struct ip *); 315263509Sdim ip->ip_len = htons(m->m_pkthdr.len); 316263509Sdim ip->ip_off = htons(ip->ip_off); 317263509Sdim ip->ip_sum = 0; 318263509Sdim ip->ip_sum = in_cksum(m, ip->ip_hl << 2); 319263509Sdim } else { 320263509Sdim ip = mtod(m, struct ip *); 321263509Sdim } 322263509Sdim prot = ip->ip_p; 323263509Sdim 324263509Sdim#ifdef notyet 325263509Sdim /* IP-in-IP encapsulation */ 326263509Sdim if (prot == IPPROTO_IPIP) { 327263509Sdim struct ip ipn; 328263509Sdim 329263509Sdim if (m->m_pkthdr.len - skip < sizeof(struct ip)) { 330263509Sdim IPSEC_ISTAT(sproto, espstat.esps_hdrops, 331263509Sdim ahstat.ahs_hdrops, 332263509Sdim ipcompstat.ipcomps_hdrops); 333263509Sdim error = EINVAL; 334263509Sdim goto bad; 335263509Sdim } 336263509Sdim /* ipn will now contain the inner IPv4 header */ 337263509Sdim m_copydata(m, ip->ip_hl << 2, sizeof(struct ip), 338263509Sdim (caddr_t) &ipn); 339263509Sdim 340263509Sdim /* XXX PROXY address isn't recorded in SAH */ 341263509Sdim /* 342263509Sdim * Check that the inner source address is the same as 343263509Sdim * the proxy address, if available. 344263509Sdim */ 345263509Sdim if ((saidx->proxy.sa.sa_family == AF_INET && 346263509Sdim saidx->proxy.sin.sin_addr.s_addr != 347263509Sdim INADDR_ANY && 348263509Sdim ipn.ip_src.s_addr != 349263509Sdim saidx->proxy.sin.sin_addr.s_addr) || 350263509Sdim (saidx->proxy.sa.sa_family != AF_INET && 351263509Sdim saidx->proxy.sa.sa_family != 0)) { 352263509Sdim 353263509Sdim DPRINTF(("%s: inner source address %s doesn't " 354263509Sdim "correspond to expected proxy source %s, " 355263509Sdim "SA %s/%08lx\n", __func__, 356263509Sdim inet_ntoa4(ipn.ip_src), 357263509Sdim ipsp_address(saidx->proxy), 358263509Sdim ipsp_address(saidx->dst), 359263509Sdim (u_long) ntohl(sav->spi))); 360263509Sdim 361263509Sdim IPSEC_ISTAT(sproto, espstat.esps_pdrops, 362263509Sdim ahstat.ahs_pdrops, 363263509Sdim ipcompstat.ipcomps_pdrops); 364263509Sdim error = EACCES; 365263509Sdim goto bad; 366263509Sdim } 367263509Sdim } 368249259Sdim#if INET6 369249259Sdim /* IPv6-in-IP encapsulation. */ 370263509Sdim if (prot == IPPROTO_IPV6) { 371249259Sdim struct ip6_hdr ip6n; 372249259Sdim 373249259Sdim if (m->m_pkthdr.len - skip < sizeof(struct ip6_hdr)) { 374249259Sdim IPSEC_ISTAT(sproto, espstat.esps_hdrops, 375249259Sdim ahstat.ahs_hdrops, 376249259Sdim ipcompstat.ipcomps_hdrops); 377249259Sdim error = EINVAL; 378252723Sdim goto bad; 379252723Sdim } 380252723Sdim /* ip6n will now contain the inner IPv6 header. */ 381263509Sdim m_copydata(m, ip->ip_hl << 2, sizeof(struct ip6_hdr), 382263509Sdim (caddr_t) &ip6n); 383263509Sdim 384263509Sdim /* 385263509Sdim * Check that the inner source address is the same as 386263509Sdim * the proxy address, if available. 387263509Sdim */ 388263509Sdim if ((saidx->proxy.sa.sa_family == AF_INET6 && 389252723Sdim !IN6_IS_ADDR_UNSPECIFIED(&saidx->proxy.sin6.sin6_addr) && 390263509Sdim !IN6_ARE_ADDR_EQUAL(&ip6n.ip6_src, 391252723Sdim &saidx->proxy.sin6.sin6_addr)) || 392252723Sdim (saidx->proxy.sa.sa_family != AF_INET6 && 393252723Sdim saidx->proxy.sa.sa_family != 0)) { 394252723Sdim 395252723Sdim DPRINTF(("%s: inner source address %s doesn't " 396252723Sdim "correspond to expected proxy source %s, " 397252723Sdim "SA %s/%08lx\n", __func__, 398252723Sdim ip6_sprintf(&ip6n.ip6_src), 399252723Sdim ipsec_address(&saidx->proxy), 400252723Sdim ipsec_address(&saidx->dst), 401252723Sdim (u_long) ntohl(sav->spi))); 402252723Sdim 403252723Sdim IPSEC_ISTAT(sproto, espstat.esps_pdrops, 404252723Sdim ahstat.ahs_pdrops, 405252723Sdim ipcompstat.ipcomps_pdrops); 406249259Sdim error = EACCES; 407249259Sdim goto bad; 408263509Sdim } 409263509Sdim } 410263509Sdim#endif /* INET6 */ 411263509Sdim#endif /*XXX*/ 412263509Sdim 413263509Sdim /* 414263509Sdim * Record what we've done to the packet (under what SA it was 415263509Sdim * processed). If we've been passed an mtag, it means the packet 416263509Sdim * was already processed by an ethernet/crypto combo card and 417263509Sdim * thus has a tag attached with all the right information, but 418263509Sdim * with a PACKET_TAG_IPSEC_IN_CRYPTO_DONE as opposed to 419263509Sdim * PACKET_TAG_IPSEC_IN_DONE type; in that case, just change the type. 420263509Sdim */ 421263509Sdim if (mt == NULL && sproto != IPPROTO_IPCOMP) { 422263509Sdim mtag = m_tag_get(PACKET_TAG_IPSEC_IN_DONE, 423263509Sdim sizeof(struct tdb_ident), M_NOWAIT); 424263509Sdim if (mtag == NULL) { 425263509Sdim DPRINTF(("%s: failed to get tag\n", __func__)); 426263509Sdim IPSEC_ISTAT(sproto, espstat.esps_hdrops, 427263509Sdim ahstat.ahs_hdrops, ipcompstat.ipcomps_hdrops); 428263509Sdim error = ENOMEM; 429263509Sdim goto bad; 430263509Sdim } 431249259Sdim 432249259Sdim tdbi = (struct tdb_ident *)(mtag + 1); 433249259Sdim bcopy(&saidx->dst, &tdbi->dst, saidx->dst.sa.sa_len); 434249259Sdim tdbi->proto = sproto; 435249259Sdim tdbi->spi = sav->spi; 436249259Sdim 437249259Sdim m_tag_prepend(m, mtag); 438249259Sdim } else { 439249259Sdim mt->m_tag_id = PACKET_TAG_IPSEC_IN_DONE; 440249259Sdim /* XXX do we need to mark m_flags??? */ 441249259Sdim } 442249259Sdim 443249259Sdim key_sa_recordxfer(sav, m); /* record data transfer */ 444249259Sdim 445249259Sdim /* 446252723Sdim * Re-dispatch via software interrupt. 447249259Sdim */ 448249259Sdim if ((error = netisr_queue(NETISR_IP, m))) { 449249259Sdim IPSEC_ISTAT(sproto, espstat.esps_qfull, ahstat.ahs_qfull, 450249259Sdim ipcompstat.ipcomps_qfull); 451249259Sdim 452252723Sdim DPRINTF(("%s: queue full; proto %u packet dropped\n", 453249259Sdim __func__, sproto)); 454249259Sdim return error; 455249259Sdim } 456249259Sdim return 0; 457249259Sdimbad: 458249259Sdim m_freem(m); 459249259Sdim return error; 460249259Sdim} 461249259Sdim 462249259Sdimvoid 463249259Sdimipsec4_common_ctlinput(int cmd, struct sockaddr *sa, void *v, int proto) 464249259Sdim{ 465249259Sdim /* XXX nothing just yet */ 466249259Sdim} 467249259Sdim#endif /* INET */ 468249259Sdim 469249259Sdim#ifdef INET6 470249259Sdim/* IPv6 AH wrapper. */ 471249259Sdimint 472249259Sdimipsec6_common_input(struct mbuf **mp, int *offp, int proto) 473249259Sdim{ 474249259Sdim int l = 0; 475249259Sdim int protoff; 476249259Sdim struct ip6_ext ip6e; 477249259Sdim 478249259Sdim if (*offp < sizeof(struct ip6_hdr)) { 479249259Sdim DPRINTF(("%s: bad offset %u\n", __func__, *offp)); 480249259Sdim return IPPROTO_DONE; 481249259Sdim } else if (*offp == sizeof(struct ip6_hdr)) { 482249259Sdim protoff = offsetof(struct ip6_hdr, ip6_nxt); 483249259Sdim } else { 484249259Sdim /* Chase down the header chain... */ 485249259Sdim protoff = sizeof(struct ip6_hdr); 486249259Sdim 487249259Sdim do { 488249259Sdim protoff += l; 489249259Sdim m_copydata(*mp, protoff, sizeof(ip6e), 490249259Sdim (caddr_t) &ip6e); 491249259Sdim 492249259Sdim if (ip6e.ip6e_nxt == IPPROTO_AH) 493249259Sdim l = (ip6e.ip6e_len + 2) << 2; 494249259Sdim else 495249259Sdim l = (ip6e.ip6e_len + 1) << 3; 496249259Sdim IPSEC_ASSERT(l > 0, ("l went zero or negative")); 497249259Sdim } while (protoff + l < *offp); 498249259Sdim 499249259Sdim /* Malformed packet check */ 500249259Sdim if (protoff + l != *offp) { 501249259Sdim DPRINTF(("%s: bad packet header chain, protoff %u, " 502249259Sdim "l %u, off %u\n", __func__, protoff, l, *offp)); 503249259Sdim IPSEC_ISTAT(proto, espstat.esps_hdrops, 504249259Sdim ahstat.ahs_hdrops, 505249259Sdim ipcompstat.ipcomps_hdrops); 506249259Sdim m_freem(*mp); 507249259Sdim *mp = NULL; 508249259Sdim return IPPROTO_DONE; 509249259Sdim } 510249259Sdim protoff += offsetof(struct ip6_ext, ip6e_nxt); 511249259Sdim } 512249259Sdim (void) ipsec_common_input(*mp, *offp, protoff, AF_INET6, proto); 513249259Sdim return IPPROTO_DONE; 514249259Sdim} 515249259Sdim 516249259Sdim/* 517249259Sdim * IPsec input callback, called by the transform callback. Takes care of 518249259Sdim * filtering and other sanity checks on the processed packet. 519249259Sdim */ 520249259Sdimint 521249259Sdimipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip, int protoff, 522249259Sdim struct m_tag *mt) 523249259Sdim{ 524249259Sdim int prot, af, sproto; 525249259Sdim struct ip6_hdr *ip6; 526249259Sdim struct m_tag *mtag; 527249259Sdim struct tdb_ident *tdbi; 528249259Sdim struct secasindex *saidx; 529249259Sdim int nxt; 530249259Sdim u_int8_t nxt8; 531252723Sdim int error, nest; 532252723Sdim 533249259Sdim IPSEC_ASSERT(m != NULL, ("null mbuf")); 534249259Sdim IPSEC_ASSERT(sav != NULL, ("null SA")); 535249259Sdim IPSEC_ASSERT(sav->sah != NULL, ("null SAH")); 536249259Sdim saidx = &sav->sah->saidx; 537249259Sdim af = saidx->dst.sa.sa_family; 538249259Sdim IPSEC_ASSERT(af == AF_INET6, ("unexpected af %u", af)); 539249259Sdim sproto = saidx->proto; 540249259Sdim IPSEC_ASSERT(sproto == IPPROTO_ESP || sproto == IPPROTO_AH || 541249259Sdim sproto == IPPROTO_IPCOMP, 542249259Sdim ("unexpected security protocol %u", sproto)); 543249259Sdim 544249259Sdim /* Sanity check */ 545249259Sdim if (m == NULL) { 546249259Sdim DPRINTF(("%s: null mbuf", __func__)); 547252723Sdim IPSEC_ISTAT(sproto, espstat.esps_badkcr, ahstat.ahs_badkcr, 548249259Sdim ipcompstat.ipcomps_badkcr); 549249259Sdim error = EINVAL; 550249259Sdim goto bad; 551249259Sdim } 552249259Sdim 553249259Sdim /* Fix IPv6 header */ 554249259Sdim if (m->m_len < sizeof(struct ip6_hdr) && 555249259Sdim (m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) { 556249259Sdim 557249259Sdim DPRINTF(("%s: processing failed for SA %s/%08lx\n", 558249259Sdim __func__, ipsec_address(&sav->sah->saidx.dst), 559249259Sdim (u_long) ntohl(sav->spi))); 560249259Sdim 561249259Sdim IPSEC_ISTAT(sproto, espstat.esps_hdrops, ahstat.ahs_hdrops, 562249259Sdim ipcompstat.ipcomps_hdrops); 563249259Sdim error = EACCES; 564249259Sdim goto bad; 565249259Sdim } 566249259Sdim 567249259Sdim ip6 = mtod(m, struct ip6_hdr *); 568249259Sdim ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr)); 569249259Sdim 570249259Sdim /* Save protocol */ 571249259Sdim m_copydata(m, protoff, 1, (unsigned char *) &prot); 572249259Sdim 573249259Sdim#ifdef notyet 574249259Sdim#ifdef INET 575249259Sdim /* IP-in-IP encapsulation */ 576249259Sdim if (prot == IPPROTO_IPIP) { 577249259Sdim struct ip ipn; 578249259Sdim 579249259Sdim if (m->m_pkthdr.len - skip < sizeof(struct ip)) { 580249259Sdim IPSEC_ISTAT(sproto, espstat.esps_hdrops, 581249259Sdim ahstat.ahs_hdrops, 582249259Sdim ipcompstat.ipcomps_hdrops); 583249259Sdim error = EINVAL; 584249259Sdim goto bad; 585249259Sdim } 586249259Sdim /* ipn will now contain the inner IPv4 header */ 587249259Sdim m_copydata(m, skip, sizeof(struct ip), (caddr_t) &ipn); 588249259Sdim 589249259Sdim /* 590249259Sdim * Check that the inner source address is the same as 591249259Sdim * the proxy address, if available. 592249259Sdim */ 593249259Sdim if ((saidx->proxy.sa.sa_family == AF_INET && 594249259Sdim saidx->proxy.sin.sin_addr.s_addr != INADDR_ANY && 595249259Sdim ipn.ip_src.s_addr != saidx->proxy.sin.sin_addr.s_addr) || 596249259Sdim (saidx->proxy.sa.sa_family != AF_INET && 597249259Sdim saidx->proxy.sa.sa_family != 0)) { 598249259Sdim 599249259Sdim DPRINTF(("%s: inner source address %s doesn't " 600249259Sdim "correspond to expected proxy source %s, " 601249259Sdim "SA %s/%08lx\n", __func__, 602249259Sdim inet_ntoa4(ipn.ip_src), 603249259Sdim ipsec_address(&saidx->proxy), 604249259Sdim ipsec_address(&saidx->dst), 605249259Sdim (u_long) ntohl(sav->spi))); 606249259Sdim 607249259Sdim IPSEC_ISTATsproto, (espstat.esps_pdrops, 608249259Sdim ahstat.ahs_pdrops, ipcompstat.ipcomps_pdrops); 609249259Sdim error = EACCES; 610249259Sdim goto bad; 611249259Sdim } 612249259Sdim } 613249259Sdim#endif /* INET */ 614249259Sdim 615252723Sdim /* IPv6-in-IP encapsulation */ 616249259Sdim if (prot == IPPROTO_IPV6) { 617249259Sdim struct ip6_hdr ip6n; 618249259Sdim 619249259Sdim if (m->m_pkthdr.len - skip < sizeof(struct ip6_hdr)) { 620249259Sdim IPSEC_ISTAT(sproto, espstat.esps_hdrops, 621249259Sdim ahstat.ahs_hdrops, 622249259Sdim ipcompstat.ipcomps_hdrops); 623249259Sdim error = EINVAL; 624252723Sdim goto bad; 625249259Sdim } 626249259Sdim /* ip6n will now contain the inner IPv6 header. */ 627249259Sdim m_copydata(m, skip, sizeof(struct ip6_hdr), 628249259Sdim (caddr_t) &ip6n); 629249259Sdim 630249259Sdim /* 631249259Sdim * Check that the inner source address is the same as 632249259Sdim * the proxy address, if available. 633249259Sdim */ 634249259Sdim if ((saidx->proxy.sa.sa_family == AF_INET6 && 635249259Sdim !IN6_IS_ADDR_UNSPECIFIED(&saidx->proxy.sin6.sin6_addr) && 636249259Sdim !IN6_ARE_ADDR_EQUAL(&ip6n.ip6_src, 637249259Sdim &saidx->proxy.sin6.sin6_addr)) || 638249259Sdim (saidx->proxy.sa.sa_family != AF_INET6 && 639249259Sdim saidx->proxy.sa.sa_family != 0)) { 640249259Sdim 641249259Sdim DPRINTF(("%s: inner source address %s doesn't " 642249259Sdim "correspond to expected proxy source %s, " 643249259Sdim "SA %s/%08lx\n", __func__, 644249259Sdim ip6_sprintf(&ip6n.ip6_src), 645249259Sdim ipsec_address(&saidx->proxy), 646249259Sdim ipsec_address(&saidx->dst), 647249259Sdim (u_long) ntohl(sav->spi))); 648249259Sdim 649249259Sdim IPSEC_ISTAT(sproto, espstat.esps_pdrops, 650249259Sdim ahstat.ahs_pdrops, ipcompstat.ipcomps_pdrops); 651249259Sdim error = EACCES; 652249259Sdim goto bad; 653249259Sdim } 654249259Sdim } 655249259Sdim#endif /*XXX*/ 656249259Sdim 657249259Sdim /* 658249259Sdim * Record what we've done to the packet (under what SA it was 659249259Sdim * processed). If we've been passed an mtag, it means the packet 660249259Sdim * was already processed by an ethernet/crypto combo card and 661249259Sdim * thus has a tag attached with all the right information, but 662249259Sdim * with a PACKET_TAG_IPSEC_IN_CRYPTO_DONE as opposed to 663249259Sdim * PACKET_TAG_IPSEC_IN_DONE type; in that case, just change the type. 664249259Sdim */ 665249259Sdim if (mt == NULL && sproto != IPPROTO_IPCOMP) { 666249259Sdim mtag = m_tag_get(PACKET_TAG_IPSEC_IN_DONE, 667249259Sdim sizeof(struct tdb_ident), M_NOWAIT); 668249259Sdim if (mtag == NULL) { 669249259Sdim DPRINTF(("%s: failed to get tag\n", __func__)); 670249259Sdim IPSEC_ISTAT(sproto, espstat.esps_hdrops, 671249259Sdim ahstat.ahs_hdrops, ipcompstat.ipcomps_hdrops); 672249259Sdim error = ENOMEM; 673249259Sdim goto bad; 674249259Sdim } 675249259Sdim 676249259Sdim tdbi = (struct tdb_ident *)(mtag + 1); 677249259Sdim bcopy(&saidx->dst, &tdbi->dst, sizeof(union sockaddr_union)); 678249259Sdim tdbi->proto = sproto; 679249259Sdim tdbi->spi = sav->spi; 680249259Sdim 681249259Sdim m_tag_prepend(m, mtag); 682249259Sdim } else { 683249259Sdim if (mt != NULL) 684249259Sdim mt->m_tag_id = PACKET_TAG_IPSEC_IN_DONE; 685249259Sdim /* XXX do we need to mark m_flags??? */ 686249259Sdim } 687249259Sdim 688249259Sdim key_sa_recordxfer(sav, m); 689249259Sdim 690249259Sdim /* Retrieve new protocol */ 691249259Sdim m_copydata(m, protoff, sizeof(u_int8_t), (caddr_t) &nxt8); 692249259Sdim 693249259Sdim /* 694249259Sdim * See the end of ip6_input for this logic. 695249259Sdim * IPPROTO_IPV[46] case will be processed just like other ones 696249259Sdim */ 697249259Sdim nest = 0; 698249259Sdim nxt = nxt8; 699249259Sdim while (nxt != IPPROTO_DONE) { 700249259Sdim if (ip6_hdrnestlimit && (++nest > ip6_hdrnestlimit)) { 701249259Sdim ip6stat.ip6s_toomanyhdr++; 702249259Sdim error = EINVAL; 703249259Sdim goto bad; 704249259Sdim } 705249259Sdim 706249259Sdim /* 707249259Sdim * Protection against faulty packet - there should be 708249259Sdim * more sanity checks in header chain processing. 709249259Sdim */ 710249259Sdim if (m->m_pkthdr.len < skip) { 711249259Sdim ip6stat.ip6s_tooshort++; 712249259Sdim in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated); 713249259Sdim error = EINVAL; 714249259Sdim goto bad; 715249259Sdim } 716249259Sdim /* 717249259Sdim * Enforce IPsec policy checking if we are seeing last header. 718249259Sdim * note that we do not visit this with protocols with pcb layer 719249259Sdim * code - like udp/tcp/raw ip. 720249259Sdim */ 721249259Sdim if ((inet6sw[ip6_protox[nxt]].pr_flags & PR_LASTHDR) != 0 && 722249259Sdim ipsec6_in_reject(m, NULL)) { 723249259Sdim error = EINVAL; 724249259Sdim goto bad; 725249259Sdim } 726249259Sdim nxt = (*inet6sw[ip6_protox[nxt]].pr_input)(&m, &skip, nxt); 727249259Sdim } 728249259Sdim return 0; 729249259Sdimbad: 730249259Sdim if (m) 731249259Sdim m_freem(m); 732249259Sdim return error; 733249259Sdim} 734249259Sdim 735249259Sdimvoid 736249259Sdimesp6_ctlinput(int cmd, struct sockaddr *sa, void *d) 737249259Sdim{ 738249259Sdim if (sa->sa_family != AF_INET6 || 739249259Sdim sa->sa_len != sizeof(struct sockaddr_in6)) 740249259Sdim return; 741249259Sdim if ((unsigned)cmd >= PRC_NCMDS) 742249259Sdim return; 743249259Sdim 744249259Sdim /* if the parameter is from icmp6, decode it. */ 745249259Sdim if (d != NULL) { 746249259Sdim struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d; 747249259Sdim struct mbuf *m = ip6cp->ip6c_m; 748249259Sdim int off = ip6cp->ip6c_off; 749249259Sdim 750249259Sdim struct ip6ctlparam ip6cp1; 751249259Sdim 752249259Sdim /* 753249259Sdim * Notify the error to all possible sockets via pfctlinput2. 754249259Sdim * Since the upper layer information (such as protocol type, 755249259Sdim * source and destination ports) is embedded in the encrypted 756263509Sdim * data and might have been cut, we can't directly call 757263509Sdim * an upper layer ctlinput function. However, the pcbnotify 758263509Sdim * function will consider source and destination addresses 759263509Sdim * as well as the flow info value, and may be able to find 760263509Sdim * some PCB that should be notified. 761263509Sdim * Although pfctlinput2 will call esp6_ctlinput(), there is 762249259Sdim * no possibility of an infinite loop of function calls, 763249259Sdim * because we don't pass the inner IPv6 header. 764249259Sdim */ 765249259Sdim bzero(&ip6cp1, sizeof(ip6cp1)); 766249259Sdim ip6cp1.ip6c_src = ip6cp->ip6c_src; 767249259Sdim pfctlinput2(cmd, sa, (void *)&ip6cp1); 768249259Sdim 769249259Sdim /* 770249259Sdim * Then go to special cases that need ESP header information. 771249259Sdim * XXX: We assume that when ip6 is non NULL, 772249259Sdim * M and OFF are valid. 773249259Sdim */ 774249259Sdim 775249259Sdim if (cmd == PRC_MSGSIZE) { 776249259Sdim struct secasvar *sav; 777249259Sdim u_int32_t spi; 778249259Sdim int valid; 779249259Sdim 780249259Sdim /* check header length before using m_copydata */ 781249259Sdim if (m->m_pkthdr.len < off + sizeof (struct esp)) 782249259Sdim return; 783249259Sdim m_copydata(m, off + offsetof(struct esp, esp_spi), 784249259Sdim sizeof(u_int32_t), (caddr_t) &spi); 785249259Sdim /* 786249259Sdim * Check to see if we have a valid SA corresponding to 787249259Sdim * the address in the ICMP message payload. 788249259Sdim */ 789249259Sdim sav = KEY_ALLOCSA((union sockaddr_union *)sa, 790249259Sdim IPPROTO_ESP, spi); 791249259Sdim valid = (sav != NULL); 792249259Sdim if (sav) 793249259Sdim KEY_FREESAV(&sav); 794249259Sdim 795249259Sdim /* XXX Further validation? */ 796249259Sdim 797249259Sdim /* 798249259Sdim * Depending on whether the SA is "valid" and 799249259Sdim * routing table size (mtudisc_{hi,lo}wat), we will: 800249259Sdim * - recalcurate the new MTU and create the 801249259Sdim * corresponding routing entry, or 802249259Sdim * - ignore the MTU change notification. 803249259Sdim */ 804249259Sdim icmp6_mtudisc_update(ip6cp, valid); 805249259Sdim } 806249259Sdim } else { 807249259Sdim /* we normally notify any pcb here */ 808249259Sdim } 809249259Sdim} 810249259Sdim#endif /* INET6 */ 811249259Sdim