1/* 2 * Copyright (c) 2008-2011 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28 29/* $FreeBSD: src/sys/netinet6/esp_input.c,v 1.1.2.3 2001/07/03 11:01:50 ume Exp $ */ 30/* $KAME: esp_input.c,v 1.55 2001/03/23 08:08:47 itojun Exp $ */ 31 32/* 33 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 34 * All rights reserved. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in the 43 * documentation and/or other materials provided with the distribution. 44 * 3. Neither the name of the project nor the names of its contributors 45 * may be used to endorse or promote products derived from this software 46 * without specific prior written permission. 47 * 48 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 51 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 58 * SUCH DAMAGE. 59 */ 60 61/* 62 * RFC1827/2406 Encapsulated Security Payload. 63 */ 64 65#include <sys/param.h> 66#include <sys/systm.h> 67#include <sys/malloc.h> 68#include <sys/mbuf.h> 69#include <sys/mcache.h> 70#include <sys/domain.h> 71#include <sys/protosw.h> 72#include <sys/socket.h> 73#include <sys/errno.h> 74#include <sys/time.h> 75#include <sys/kernel.h> 76#include <sys/syslog.h> 77 78#include <net/if.h> 79#include <net/route.h> 80#include <kern/cpu_number.h> 81#include <kern/locks.h> 82 83#include <netinet/in.h> 84#include <netinet/in_systm.h> 85#include <netinet/ip.h> 86#include <netinet/ip_var.h> 87#include <netinet/in_var.h> 88#include <netinet/ip_ecn.h> 89#include <netinet/in_pcb.h> 90#include <netinet/udp.h> 91#if INET6 92#include <netinet6/ip6_ecn.h> 93#endif 94 95#if INET6 96#include <netinet/ip6.h> 97#include <netinet6/in6_pcb.h> 98#include <netinet6/ip6_var.h> 99#include <netinet/icmp6.h> 100#include <netinet6/ip6protosw.h> 101#endif 102 103#include <netinet6/ipsec.h> 104#if INET6 105#include <netinet6/ipsec6.h> 106#endif 107#include <netinet6/ah.h> 108#if INET6 109#include <netinet6/ah6.h> 110#endif 111#include <netinet6/esp.h> 112#if INET6 113#include <netinet6/esp6.h> 114#endif 115#include <netkey/key.h> 116#include <netkey/keydb.h> 117#include <netkey/key_debug.h> 118 119#include <net/kpi_protocol.h> 120#include <netinet/kpi_ipfilter_var.h> 121 122#include <net/net_osdep.h> 123#include <mach/sdt.h> 124 125#include <sys/kdebug.h> 126#define DBG_LAYER_BEG NETDBG_CODE(DBG_NETIPSEC, 1) 127#define DBG_LAYER_END NETDBG_CODE(DBG_NETIPSEC, 3) 128#define DBG_FNC_ESPIN NETDBG_CODE(DBG_NETIPSEC, (6 << 8)) 129#define DBG_FNC_DECRYPT NETDBG_CODE(DBG_NETIPSEC, (7 << 8)) 130#define IPLEN_FLIPPED 131 132extern lck_mtx_t *sadb_mutex; 133 134#if INET 135extern struct protosw inetsw[]; 136 137#define ESPMAXLEN \ 138 (sizeof(struct esp) < sizeof(struct newesp) \ 139 ? sizeof(struct newesp) : sizeof(struct esp)) 140 141static struct ip * 142esp4_input_strip_UDP_encap (struct mbuf *m, int iphlen) 143{ 144 // strip the udp header that's encapsulating ESP 145 struct ip *ip; 146 size_t stripsiz = sizeof(struct udphdr); 147 148 ip = mtod(m, __typeof__(ip)); 149 ovbcopy((caddr_t)ip, (caddr_t)(((u_char *)ip) + stripsiz), iphlen); 150 m->m_data += stripsiz; 151 m->m_len -= stripsiz; 152 m->m_pkthdr.len -= stripsiz; 153 ip = mtod(m, __typeof__(ip)); 154 ip->ip_len = ip->ip_len - stripsiz; 155 ip->ip_p = IPPROTO_ESP; 156 return ip; 157} 158 159void 160esp4_input(m, off) 161 struct mbuf *m; 162 int off; 163{ 164 struct ip *ip; 165#if INET6 166 struct ip6_hdr *ip6; 167#endif /* INET6 */ 168 struct esp *esp; 169 struct esptail esptail; 170 u_int32_t spi; 171 u_int32_t seq; 172 struct secasvar *sav = NULL; 173 size_t taillen; 174 u_int16_t nxt; 175 const struct esp_algorithm *algo; 176 int ivlen; 177 size_t hlen; 178 size_t esplen; 179 sa_family_t ifamily; 180 181 KERNEL_DEBUG(DBG_FNC_ESPIN | DBG_FUNC_START, 0,0,0,0,0); 182 /* sanity check for alignment. */ 183 if (off % 4 != 0 || m->m_pkthdr.len % 4 != 0) { 184 ipseclog((LOG_ERR, "IPv4 ESP input: packet alignment problem " 185 "(off=%d, pktlen=%d)\n", off, m->m_pkthdr.len)); 186 IPSEC_STAT_INCREMENT(ipsecstat.in_inval); 187 goto bad; 188 } 189 190 if (m->m_len < off + ESPMAXLEN) { 191 m = m_pullup(m, off + ESPMAXLEN); 192 if (!m) { 193 ipseclog((LOG_DEBUG, 194 "IPv4 ESP input: can't pullup in esp4_input\n")); 195 IPSEC_STAT_INCREMENT(ipsecstat.in_inval); 196 goto bad; 197 } 198 } 199 200 /* Expect 32-bit aligned data pointer on strict-align platforms */ 201 MBUF_STRICT_DATA_ALIGNMENT_CHECK_32(m); 202 203 ip = mtod(m, struct ip *); 204 // expect udp-encap and esp packets only 205 if (ip->ip_p != IPPROTO_ESP && 206 !(ip->ip_p == IPPROTO_UDP && off >= sizeof(struct udphdr))) { 207 ipseclog((LOG_DEBUG, 208 "IPv4 ESP input: invalid protocol type\n")); 209 IPSEC_STAT_INCREMENT(ipsecstat.in_inval); 210 goto bad; 211 } 212 esp = (struct esp *)(void *)(((u_int8_t *)ip) + off); 213#ifdef _IP_VHL 214 hlen = IP_VHL_HL(ip->ip_vhl) << 2; 215#else 216 hlen = ip->ip_hl << 2; 217#endif 218 219 /* find the sassoc. */ 220 spi = esp->esp_spi; 221 222 if ((sav = key_allocsa(AF_INET, 223 (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst, 224 IPPROTO_ESP, spi)) == 0) { 225 ipseclog((LOG_WARNING, 226 "IPv4 ESP input: no key association found for spi %u\n", 227 (u_int32_t)ntohl(spi))); 228 IPSEC_STAT_INCREMENT(ipsecstat.in_nosa); 229 goto bad; 230 } 231 KEYDEBUG(KEYDEBUG_IPSEC_STAMP, 232 printf("DP esp4_input called to allocate SA:%p\n", sav)); 233 if (sav->state != SADB_SASTATE_MATURE 234 && sav->state != SADB_SASTATE_DYING) { 235 ipseclog((LOG_DEBUG, 236 "IPv4 ESP input: non-mature/dying SA found for spi %u\n", 237 (u_int32_t)ntohl(spi))); 238 IPSEC_STAT_INCREMENT(ipsecstat.in_badspi); 239 goto bad; 240 } 241 algo = esp_algorithm_lookup(sav->alg_enc); 242 if (!algo) { 243 ipseclog((LOG_DEBUG, "IPv4 ESP input: " 244 "unsupported encryption algorithm for spi %u\n", 245 (u_int32_t)ntohl(spi))); 246 IPSEC_STAT_INCREMENT(ipsecstat.in_badspi); 247 goto bad; 248 } 249 250 /* check if we have proper ivlen information */ 251 ivlen = sav->ivlen; 252 if (ivlen < 0) { 253 ipseclog((LOG_ERR, "inproper ivlen in IPv4 ESP input: %s %s\n", 254 ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav))); 255 IPSEC_STAT_INCREMENT(ipsecstat.in_inval); 256 goto bad; 257 } 258 259 seq = ntohl(((struct newesp *)esp)->esp_seq); 260 if (!((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay 261 && (sav->alg_auth && sav->key_auth))) 262 goto noreplaycheck; 263 264 if (sav->alg_auth == SADB_X_AALG_NULL || 265 sav->alg_auth == SADB_AALG_NONE) 266 goto noreplaycheck; 267 268 /* 269 * check for sequence number. 270 */ 271 if (ipsec_chkreplay(seq, sav)) 272 ; /*okey*/ 273 else { 274 IPSEC_STAT_INCREMENT(ipsecstat.in_espreplay); 275 ipseclog((LOG_WARNING, 276 "replay packet in IPv4 ESP input: %s %s\n", 277 ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav))); 278 goto bad; 279 } 280 281 /* check ICV */ 282 { 283 u_char sum0[AH_MAXSUMSIZE] __attribute__((aligned(4))); 284 u_char sum[AH_MAXSUMSIZE] __attribute__((aligned(4))); 285 const struct ah_algorithm *sumalgo; 286 size_t siz; 287 288 sumalgo = ah_algorithm_lookup(sav->alg_auth); 289 if (!sumalgo) 290 goto noreplaycheck; 291 siz = (((*sumalgo->sumsiz)(sav) + 3) & ~(4 - 1)); 292 if (m->m_pkthdr.len < off + ESPMAXLEN + siz) { 293 IPSEC_STAT_INCREMENT(ipsecstat.in_inval); 294 goto bad; 295 } 296 if (AH_MAXSUMSIZE < siz) { 297 ipseclog((LOG_DEBUG, 298 "internal error: AH_MAXSUMSIZE must be larger than %lu\n", 299 (u_int32_t)siz)); 300 IPSEC_STAT_INCREMENT(ipsecstat.in_inval); 301 goto bad; 302 } 303 304 m_copydata(m, m->m_pkthdr.len - siz, siz, (caddr_t) &sum0[0]); 305 306 if (esp_auth(m, off, m->m_pkthdr.len - off - siz, sav, sum)) { 307 ipseclog((LOG_WARNING, "auth fail in IPv4 ESP input: %s %s\n", 308 ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav))); 309 IPSEC_STAT_INCREMENT(ipsecstat.in_espauthfail); 310 goto bad; 311 } 312 313 if (bcmp(sum0, sum, siz) != 0) { 314 ipseclog((LOG_WARNING, "auth fail in IPv4 ESP input: %s %s\n", 315 ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav))); 316 IPSEC_STAT_INCREMENT(ipsecstat.in_espauthfail); 317 goto bad; 318 } 319 320 /* strip off the authentication data */ 321 m_adj(m, -siz); 322 ip = mtod(m, struct ip *); 323#ifdef IPLEN_FLIPPED 324 ip->ip_len = ip->ip_len - siz; 325#else 326 ip->ip_len = htons(ntohs(ip->ip_len) - siz); 327#endif 328 m->m_flags |= M_AUTHIPDGM; 329 IPSEC_STAT_INCREMENT(ipsecstat.in_espauthsucc); 330 } 331 332 /* 333 * update sequence number. 334 */ 335 if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) { 336 if (ipsec_updatereplay(seq, sav)) { 337 IPSEC_STAT_INCREMENT(ipsecstat.in_espreplay); 338 goto bad; 339 } 340 } 341 342noreplaycheck: 343 344 /* process main esp header. */ 345 if (sav->flags & SADB_X_EXT_OLD) { 346 /* RFC 1827 */ 347 esplen = sizeof(struct esp); 348 } else { 349 /* RFC 2406 */ 350 if (sav->flags & SADB_X_EXT_DERIV) 351 esplen = sizeof(struct esp); 352 else 353 esplen = sizeof(struct newesp); 354 } 355 356 if (m->m_pkthdr.len < off + esplen + ivlen + sizeof(esptail)) { 357 ipseclog((LOG_WARNING, 358 "IPv4 ESP input: packet too short\n")); 359 IPSEC_STAT_INCREMENT(ipsecstat.in_inval); 360 goto bad; 361 } 362 363 if (m->m_len < off + esplen + ivlen) { 364 m = m_pullup(m, off + esplen + ivlen); 365 if (!m) { 366 ipseclog((LOG_DEBUG, 367 "IPv4 ESP input: can't pullup in esp4_input\n")); 368 IPSEC_STAT_INCREMENT(ipsecstat.in_inval); 369 goto bad; 370 } 371 } 372 373 /* 374 * pre-compute and cache intermediate key 375 */ 376 if (esp_schedule(algo, sav) != 0) { 377 IPSEC_STAT_INCREMENT(ipsecstat.in_inval); 378 goto bad; 379 } 380 381 /* 382 * decrypt the packet. 383 */ 384 if (!algo->decrypt) 385 panic("internal error: no decrypt function"); 386 KERNEL_DEBUG(DBG_FNC_DECRYPT | DBG_FUNC_START, 0,0,0,0,0); 387 if ((*algo->decrypt)(m, off, sav, algo, ivlen)) { 388 /* m is already freed */ 389 m = NULL; 390 ipseclog((LOG_ERR, "decrypt fail in IPv4 ESP input: %s\n", 391 ipsec_logsastr(sav))); 392 IPSEC_STAT_INCREMENT(ipsecstat.in_inval); 393 KERNEL_DEBUG(DBG_FNC_DECRYPT | DBG_FUNC_END, 1,0,0,0,0); 394 goto bad; 395 } 396 KERNEL_DEBUG(DBG_FNC_DECRYPT | DBG_FUNC_END, 2,0,0,0,0); 397 IPSEC_STAT_INCREMENT(ipsecstat.in_esphist[sav->alg_enc]); 398 399 m->m_flags |= M_DECRYPTED; 400 401 /* 402 * find the trailer of the ESP. 403 */ 404 m_copydata(m, m->m_pkthdr.len - sizeof(esptail), sizeof(esptail), 405 (caddr_t)&esptail); 406 nxt = esptail.esp_nxt; 407 taillen = esptail.esp_padlen + sizeof(esptail); 408 409 if (m->m_pkthdr.len < taillen 410 || m->m_pkthdr.len - taillen < hlen) { /*?*/ 411 ipseclog((LOG_WARNING, 412 "bad pad length in IPv4 ESP input: %s %s\n", 413 ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav))); 414 IPSEC_STAT_INCREMENT(ipsecstat.in_inval); 415 goto bad; 416 } 417 418 /* strip off the trailing pad area. */ 419 m_adj(m, -taillen); 420 ip = mtod(m, struct ip *); 421#ifdef IPLEN_FLIPPED 422 ip->ip_len = ip->ip_len - taillen; 423#else 424 ip->ip_len = htons(ntohs(ip->ip_len) - taillen); 425#endif 426 if (ip->ip_p == IPPROTO_UDP) { 427 // offset includes the outer ip and udp header lengths. 428 if (m->m_len < off) { 429 m = m_pullup(m, off); 430 if (!m) { 431 ipseclog((LOG_DEBUG, 432 "IPv4 ESP input: invalid udp encapsulated ESP packet length \n")); 433 IPSEC_STAT_INCREMENT(ipsecstat.in_inval); 434 goto bad; 435 } 436 } 437 438 // check the UDP encap header to detect changes in the source port, and then strip the header 439 off -= sizeof(struct udphdr); // off no longer includes the udphdr's size 440 // if peer is behind nat and this is the latest esp packet 441 if ((sav->flags & SADB_X_EXT_NATT_DETECTED_PEER) != 0 && 442 (sav->flags & SADB_X_EXT_OLD) == 0 && 443 seq && sav->replay && 444 seq >= sav->replay->lastseq) { 445 struct udphdr *encap_uh = (__typeof__(encap_uh))(void *)((caddr_t)ip + off); 446 if (encap_uh->uh_sport && 447 ntohs(encap_uh->uh_sport) != sav->remote_ike_port) { 448 sav->remote_ike_port = ntohs(encap_uh->uh_sport); 449 } 450 } 451 ip = esp4_input_strip_UDP_encap(m, off); 452 esp = (struct esp *)(void *)(((u_int8_t *)ip) + off); 453 } 454 455 if (sav->utun_is_keepalive_fn) { 456 if (sav->utun_is_keepalive_fn(sav->utun_pcb, &m, nxt, sav->flags, (off + esplen + ivlen))) { 457 if (m) { 458 // not really bad, we just wanna exit 459 IPSEC_STAT_INCREMENT(ipsecstat.in_success); 460 m = NULL; 461 } 462 goto bad; 463 } 464 } 465 466 /* was it transmitted over the IPsec tunnel SA? */ 467 if (ipsec4_tunnel_validate(m, off + esplen + ivlen, nxt, sav, &ifamily)) { 468 ifaddr_t ifa; 469 struct sockaddr_storage addr; 470 471 /* 472 * strip off all the headers that precedes ESP header. 473 * IP4 xx ESP IP4' payload -> IP4' payload 474 * 475 * XXX more sanity checks 476 * XXX relationship with gif? 477 */ 478 u_int8_t tos; 479 480 tos = ip->ip_tos; 481 m_adj(m, off + esplen + ivlen); 482 if (ifamily == AF_INET) { 483 struct sockaddr_in *ipaddr; 484 485 if (m->m_len < sizeof(*ip)) { 486 m = m_pullup(m, sizeof(*ip)); 487 if (!m) { 488 IPSEC_STAT_INCREMENT(ipsecstat.in_inval); 489 goto bad; 490 } 491 } 492 ip = mtod(m, struct ip *); 493 /* ECN consideration. */ 494 ip_ecn_egress(ip4_ipsec_ecn, &tos, &ip->ip_tos); 495 if (!key_checktunnelsanity(sav, AF_INET, 496 (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst)) { 497 ipseclog((LOG_ERR, "ipsec tunnel address mismatch " 498 "in ESP input: %s %s\n", 499 ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav))); 500 IPSEC_STAT_INCREMENT(ipsecstat.in_inval); 501 goto bad; 502 } 503 504 if (ip_doscopedroute) { 505 bzero(&addr, sizeof(addr)); 506 ipaddr = (__typeof__(ipaddr))&addr; 507 ipaddr->sin_family = AF_INET; 508 ipaddr->sin_len = sizeof(*ipaddr); 509 ipaddr->sin_addr = ip->ip_dst; 510 } 511#if INET6 512 } else if (ifamily == AF_INET6) { 513 struct sockaddr_in6 *ip6addr; 514 515#ifndef PULLDOWN_TEST 516 /* 517 * m_pullup is prohibited in KAME IPv6 input processing 518 * but there's no other way! 519 */ 520#else 521 /* okay to pullup in m_pulldown style */ 522#endif 523 if (m->m_len < sizeof(*ip6)) { 524 m = m_pullup(m, sizeof(*ip6)); 525 if (!m) { 526 IPSEC_STAT_INCREMENT(ipsecstat.in_inval); 527 goto bad; 528 } 529 } 530 531 /* 532 * Expect 32-bit aligned data pointer on strict-align 533 * platforms. 534 */ 535 MBUF_STRICT_DATA_ALIGNMENT_CHECK_32(m); 536 537 ip6 = mtod(m, struct ip6_hdr *); 538 539 /* ECN consideration. */ 540 /* XXX To be fixed later if needed */ 541 // ip_ecn_egress(ip4_ipsec_ecn, &tos, &ip->ip_tos); 542 543 if (!key_checktunnelsanity(sav, AF_INET6, 544 (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst)) { 545 ipseclog((LOG_ERR, "ipsec tunnel address mismatch " 546 "in ESP input: %s %s\n", 547 ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav))); 548 IPSEC_STAT_INCREMENT(ipsecstat.in_inval); 549 goto bad; 550 } 551 552 if (ip6_doscopedroute) { 553 bzero(&addr, sizeof(addr)); 554 ip6addr = (__typeof__(ip6addr))&addr; 555 ip6addr->sin6_family = AF_INET6; 556 ip6addr->sin6_len = sizeof(*ip6addr); 557 ip6addr->sin6_addr = ip6->ip6_dst; 558 } 559#endif /* INET6 */ 560 } else { 561 ipseclog((LOG_ERR, "ipsec tunnel unsupported address family " 562 "in ESP input\n")); 563 goto bad; 564 } 565 566 key_sa_recordxfer(sav, m); 567 if (ipsec_addhist(m, IPPROTO_ESP, spi) != 0 || 568 ipsec_addhist(m, IPPROTO_IPV4, 0) != 0) { 569 IPSEC_STAT_INCREMENT(ipsecstat.in_nomem); 570 goto bad; 571 } 572 573 if (ip_doscopedroute || ip6_doscopedroute) { 574 // update the receiving interface address based on the inner address 575 ifa = ifa_ifwithaddr((struct sockaddr *)&addr); 576 if (ifa) { 577 m->m_pkthdr.rcvif = ifa->ifa_ifp; 578 IFA_REMREF(ifa); 579 } 580 } 581 582 /* Clear the csum flags, they can't be valid for the inner headers */ 583 m->m_pkthdr.csum_flags = 0; 584 585 if (sav->utun_in_fn) { 586 if (!(sav->utun_in_fn(sav->utun_pcb, &m, ifamily == AF_INET ? PF_INET : PF_INET6))) { 587 m = NULL; 588 // we just wanna exit since packet has been completely processed 589 goto bad; 590 } 591 } 592 593 if (proto_input(ifamily == AF_INET ? PF_INET : PF_INET6, m) != 0) 594 goto bad; 595 596 nxt = IPPROTO_DONE; 597 KERNEL_DEBUG(DBG_FNC_ESPIN | DBG_FUNC_END, 2,0,0,0,0); 598 } else { 599 /* 600 * strip off ESP header and IV. 601 * even in m_pulldown case, we need to strip off ESP so that 602 * we can always compute checksum for AH correctly. 603 */ 604 size_t stripsiz; 605 606 stripsiz = esplen + ivlen; 607 608 ip = mtod(m, struct ip *); 609 ovbcopy((caddr_t)ip, (caddr_t)(((u_char *)ip) + stripsiz), off); 610 m->m_data += stripsiz; 611 m->m_len -= stripsiz; 612 m->m_pkthdr.len -= stripsiz; 613 614 ip = mtod(m, struct ip *); 615#ifdef IPLEN_FLIPPED 616 ip->ip_len = ip->ip_len - stripsiz; 617#else 618 ip->ip_len = htons(ntohs(ip->ip_len) - stripsiz); 619#endif 620 ip->ip_p = nxt; 621 622 key_sa_recordxfer(sav, m); 623 if (ipsec_addhist(m, IPPROTO_ESP, spi) != 0) { 624 IPSEC_STAT_INCREMENT(ipsecstat.in_nomem); 625 goto bad; 626 } 627 628 /* 629 * Set the csum valid flag, if we authenticated the 630 * packet, the payload shouldn't be corrupt unless 631 * it was corrupted before being signed on the other 632 * side. 633 */ 634 if (nxt == IPPROTO_TCP || nxt == IPPROTO_UDP) { 635 m->m_pkthdr.csum_flags = CSUM_DATA_VALID | CSUM_PSEUDO_HDR; 636 m->m_pkthdr.csum_data = 0xFFFF; 637 } 638 639 if (nxt != IPPROTO_DONE) { 640 if ((ip_protox[nxt]->pr_flags & PR_LASTHDR) != 0 && 641 ipsec4_in_reject(m, NULL)) { 642 IPSEC_STAT_INCREMENT(ipsecstat.in_polvio); 643 goto bad; 644 } 645 KERNEL_DEBUG(DBG_FNC_ESPIN | DBG_FUNC_END, 3,0,0,0,0); 646 647 /* translate encapsulated UDP port ? */ 648 if ((sav->flags & SADB_X_EXT_NATT_MULTIPLEUSERS) != 0) { 649 struct udphdr *udp; 650 651 if (nxt != IPPROTO_UDP) { /* not UPD packet - drop it */ 652 IPSEC_STAT_INCREMENT(ipsecstat.in_inval); 653 goto bad; 654 } 655 656 if (m->m_len < off + sizeof(struct udphdr)) { 657 m = m_pullup(m, off + sizeof(struct udphdr)); 658 if (!m) { 659 ipseclog((LOG_DEBUG, 660 "IPv4 ESP input: can't pullup UDP header in esp4_input\n")); 661 IPSEC_STAT_INCREMENT(ipsecstat.in_inval); 662 goto bad; 663 } 664 ip = mtod(m, struct ip *); 665 } 666 udp = (struct udphdr *)(void *)(((u_int8_t *)ip) + off); 667 668 lck_mtx_lock(sadb_mutex); 669 if (sav->natt_encapsulated_src_port == 0) { 670 sav->natt_encapsulated_src_port = udp->uh_sport; 671 } else if (sav->natt_encapsulated_src_port != udp->uh_sport) { /* something wrong */ 672 IPSEC_STAT_INCREMENT(ipsecstat.in_inval); 673 lck_mtx_unlock(sadb_mutex); 674 goto bad; 675 } 676 lck_mtx_unlock(sadb_mutex); 677 udp->uh_sport = htons(sav->remote_ike_port); 678 udp->uh_sum = 0; 679 } 680 681 DTRACE_IP6(receive, struct mbuf *, m, struct inpcb *, NULL, 682 struct ip *, ip, struct ifnet *, m->m_pkthdr.rcvif, 683 struct ip *, ip, struct ip6_hdr *, NULL); 684 685 if (sav->utun_in_fn) { 686 if (!(sav->utun_in_fn(sav->utun_pcb, &m, PF_INET))) { 687 m = NULL; 688 // we just wanna exit since packet has been completely processed 689 goto bad; 690 } 691 } 692 693 ip_proto_dispatch_in(m, off, nxt, 0); 694 } else 695 m_freem(m); 696 m = NULL; 697 } 698 699 if (sav) { 700 KEYDEBUG(KEYDEBUG_IPSEC_STAMP, 701 printf("DP esp4_input call free SA:%p\n", sav)); 702 key_freesav(sav, KEY_SADB_UNLOCKED); 703 } 704 IPSEC_STAT_INCREMENT(ipsecstat.in_success); 705 return; 706 707bad: 708 if (sav) { 709 KEYDEBUG(KEYDEBUG_IPSEC_STAMP, 710 printf("DP esp4_input call free SA:%p\n", sav)); 711 key_freesav(sav, KEY_SADB_UNLOCKED); 712 } 713 if (m) 714 m_freem(m); 715 KERNEL_DEBUG(DBG_FNC_ESPIN | DBG_FUNC_END, 4,0,0,0,0); 716 return; 717} 718#endif /* INET */ 719 720#if INET6 721int 722esp6_input(struct mbuf **mp, int *offp, int proto) 723{ 724#pragma unused(proto) 725 struct mbuf *m = *mp; 726 int off = *offp; 727 struct ip6_hdr *ip6; 728 struct esp *esp; 729 struct esptail esptail; 730 u_int32_t spi; 731 u_int32_t seq; 732 struct secasvar *sav = NULL; 733 size_t taillen; 734 u_int16_t nxt; 735 const struct esp_algorithm *algo; 736 int ivlen; 737 size_t esplen; 738 739 /* sanity check for alignment. */ 740 if (off % 4 != 0 || m->m_pkthdr.len % 4 != 0) { 741 ipseclog((LOG_ERR, "IPv6 ESP input: packet alignment problem " 742 "(off=%d, pktlen=%d)\n", off, m->m_pkthdr.len)); 743 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval); 744 goto bad; 745 } 746 747#ifndef PULLDOWN_TEST 748 IP6_EXTHDR_CHECK(m, off, ESPMAXLEN, {return IPPROTO_DONE;}); 749 esp = (struct esp *)(void *)(mtod(m, caddr_t) + off); 750#else 751 IP6_EXTHDR_GET(esp, struct esp *, m, off, ESPMAXLEN); 752 if (esp == NULL) { 753 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval); 754 return IPPROTO_DONE; 755 } 756#endif 757 /* Expect 32-bit data aligned pointer on strict-align platforms */ 758 MBUF_STRICT_DATA_ALIGNMENT_CHECK_32(m); 759 760 ip6 = mtod(m, struct ip6_hdr *); 761 762 if (ntohs(ip6->ip6_plen) == 0) { 763 ipseclog((LOG_ERR, "IPv6 ESP input: " 764 "ESP with IPv6 jumbogram is not supported.\n")); 765 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval); 766 goto bad; 767 } 768 769 /* find the sassoc. */ 770 spi = esp->esp_spi; 771 772 if ((sav = key_allocsa(AF_INET6, 773 (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst, 774 IPPROTO_ESP, spi)) == 0) { 775 ipseclog((LOG_WARNING, 776 "IPv6 ESP input: no key association found for spi %u\n", 777 (u_int32_t)ntohl(spi))); 778 IPSEC_STAT_INCREMENT(ipsec6stat.in_nosa); 779 goto bad; 780 } 781 KEYDEBUG(KEYDEBUG_IPSEC_STAMP, 782 printf("DP esp6_input called to allocate SA:%p\n", sav)); 783 if (sav->state != SADB_SASTATE_MATURE 784 && sav->state != SADB_SASTATE_DYING) { 785 ipseclog((LOG_DEBUG, 786 "IPv6 ESP input: non-mature/dying SA found for spi %u\n", 787 (u_int32_t)ntohl(spi))); 788 IPSEC_STAT_INCREMENT(ipsec6stat.in_badspi); 789 goto bad; 790 } 791 algo = esp_algorithm_lookup(sav->alg_enc); 792 if (!algo) { 793 ipseclog((LOG_DEBUG, "IPv6 ESP input: " 794 "unsupported encryption algorithm for spi %u\n", 795 (u_int32_t)ntohl(spi))); 796 IPSEC_STAT_INCREMENT(ipsec6stat.in_badspi); 797 goto bad; 798 } 799 800 /* check if we have proper ivlen information */ 801 ivlen = sav->ivlen; 802 if (ivlen < 0) { 803 ipseclog((LOG_ERR, "inproper ivlen in IPv6 ESP input: %s %s\n", 804 ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav))); 805 IPSEC_STAT_INCREMENT(ipsec6stat.in_badspi); 806 goto bad; 807 } 808 809 seq = ntohl(((struct newesp *)esp)->esp_seq); 810 811 if (!((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay 812 && (sav->alg_auth && sav->key_auth))) 813 goto noreplaycheck; 814 815 if (sav->alg_auth == SADB_X_AALG_NULL || 816 sav->alg_auth == SADB_AALG_NONE) 817 goto noreplaycheck; 818 819 /* 820 * check for sequence number. 821 */ 822 if (ipsec_chkreplay(seq, sav)) 823 ; /*okey*/ 824 else { 825 IPSEC_STAT_INCREMENT(ipsec6stat.in_espreplay); 826 ipseclog((LOG_WARNING, 827 "replay packet in IPv6 ESP input: %s %s\n", 828 ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav))); 829 goto bad; 830 } 831 832 /* check ICV */ 833 { 834 u_char sum0[AH_MAXSUMSIZE] __attribute__((aligned(4))); 835 u_char sum[AH_MAXSUMSIZE] __attribute__((aligned(4))); 836 const struct ah_algorithm *sumalgo; 837 size_t siz; 838 839 sumalgo = ah_algorithm_lookup(sav->alg_auth); 840 if (!sumalgo) 841 goto noreplaycheck; 842 siz = (((*sumalgo->sumsiz)(sav) + 3) & ~(4 - 1)); 843 if (m->m_pkthdr.len < off + ESPMAXLEN + siz) { 844 IPSEC_STAT_INCREMENT(ipsecstat.in_inval); 845 goto bad; 846 } 847 if (AH_MAXSUMSIZE < siz) { 848 ipseclog((LOG_DEBUG, 849 "internal error: AH_MAXSUMSIZE must be larger than %lu\n", 850 (u_int32_t)siz)); 851 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval); 852 goto bad; 853 } 854 855 m_copydata(m, m->m_pkthdr.len - siz, siz, (caddr_t) &sum0[0]); 856 857 if (esp_auth(m, off, m->m_pkthdr.len - off - siz, sav, sum)) { 858 ipseclog((LOG_WARNING, "auth fail in IPv6 ESP input: %s %s\n", 859 ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav))); 860 IPSEC_STAT_INCREMENT(ipsec6stat.in_espauthfail); 861 goto bad; 862 } 863 864 if (bcmp(sum0, sum, siz) != 0) { 865 ipseclog((LOG_WARNING, "auth fail in IPv6 ESP input: %s %s\n", 866 ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav))); 867 IPSEC_STAT_INCREMENT(ipsec6stat.in_espauthfail); 868 goto bad; 869 } 870 871 /* strip off the authentication data */ 872 m_adj(m, -siz); 873 ip6 = mtod(m, struct ip6_hdr *); 874 ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - siz); 875 876 m->m_flags |= M_AUTHIPDGM; 877 IPSEC_STAT_INCREMENT(ipsec6stat.in_espauthsucc); 878 } 879 880 /* 881 * update sequence number. 882 */ 883 if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) { 884 if (ipsec_updatereplay(seq, sav)) { 885 IPSEC_STAT_INCREMENT(ipsec6stat.in_espreplay); 886 goto bad; 887 } 888 } 889 890noreplaycheck: 891 892 /* process main esp header. */ 893 if (sav->flags & SADB_X_EXT_OLD) { 894 /* RFC 1827 */ 895 esplen = sizeof(struct esp); 896 } else { 897 /* RFC 2406 */ 898 if (sav->flags & SADB_X_EXT_DERIV) 899 esplen = sizeof(struct esp); 900 else 901 esplen = sizeof(struct newesp); 902 } 903 904 if (m->m_pkthdr.len < off + esplen + ivlen + sizeof(esptail)) { 905 ipseclog((LOG_WARNING, 906 "IPv6 ESP input: packet too short\n")); 907 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval); 908 goto bad; 909 } 910 911#ifndef PULLDOWN_TEST 912 IP6_EXTHDR_CHECK(m, off, esplen + ivlen, return IPPROTO_DONE); /*XXX*/ 913#else 914 IP6_EXTHDR_GET(esp, struct esp *, m, off, esplen + ivlen); 915 if (esp == NULL) { 916 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval); 917 m = NULL; 918 goto bad; 919 } 920#endif 921 ip6 = mtod(m, struct ip6_hdr *); /*set it again just in case*/ 922 923 /* 924 * pre-compute and cache intermediate key 925 */ 926 if (esp_schedule(algo, sav) != 0) { 927 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval); 928 goto bad; 929 } 930 931 /* 932 * decrypt the packet. 933 */ 934 if (!algo->decrypt) 935 panic("internal error: no decrypt function"); 936 if ((*algo->decrypt)(m, off, sav, algo, ivlen)) { 937 /* m is already freed */ 938 m = NULL; 939 ipseclog((LOG_ERR, "decrypt fail in IPv6 ESP input: %s\n", 940 ipsec_logsastr(sav))); 941 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval); 942 goto bad; 943 } 944 IPSEC_STAT_INCREMENT(ipsec6stat.in_esphist[sav->alg_enc]); 945 946 m->m_flags |= M_DECRYPTED; 947 948 /* 949 * find the trailer of the ESP. 950 */ 951 m_copydata(m, m->m_pkthdr.len - sizeof(esptail), sizeof(esptail), 952 (caddr_t)&esptail); 953 nxt = esptail.esp_nxt; 954 taillen = esptail.esp_padlen + sizeof(esptail); 955 956 if (m->m_pkthdr.len < taillen 957 || m->m_pkthdr.len - taillen < sizeof(struct ip6_hdr)) { /*?*/ 958 ipseclog((LOG_WARNING, 959 "bad pad length in IPv6 ESP input: %s %s\n", 960 ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav))); 961 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval); 962 goto bad; 963 } 964 965 /* strip off the trailing pad area. */ 966 m_adj(m, -taillen); 967 ip6 = mtod(m, struct ip6_hdr *); 968 ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - taillen); 969 970 if (sav->utun_is_keepalive_fn) { 971 if (sav->utun_is_keepalive_fn(sav->utun_pcb, &m, nxt, sav->flags, (off + esplen + ivlen))) { 972 if (m) { 973 // not really bad, we just wanna exit 974 IPSEC_STAT_INCREMENT(ipsec6stat.in_success); 975 m = NULL; 976 } 977 goto bad; 978 } 979 } 980 981 /* was it transmitted over the IPsec tunnel SA? */ 982 if (ipsec6_tunnel_validate(m, off + esplen + ivlen, nxt, sav)) { 983 ifaddr_t ifa; 984 struct sockaddr_storage addr; 985 986 /* 987 * strip off all the headers that precedes ESP header. 988 * IP6 xx ESP IP6' payload -> IP6' payload 989 * 990 * XXX more sanity checks 991 * XXX relationship with gif? 992 */ 993 u_int32_t flowinfo; /*net endian*/ 994 flowinfo = ip6->ip6_flow; 995 m_adj(m, off + esplen + ivlen); 996 if (m->m_len < sizeof(*ip6)) { 997#ifndef PULLDOWN_TEST 998 /* 999 * m_pullup is prohibited in KAME IPv6 input processing 1000 * but there's no other way! 1001 */ 1002#else 1003 /* okay to pullup in m_pulldown style */ 1004#endif 1005 m = m_pullup(m, sizeof(*ip6)); 1006 if (!m) { 1007 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval); 1008 goto bad; 1009 } 1010 } 1011 ip6 = mtod(m, struct ip6_hdr *); 1012 /* ECN consideration. */ 1013 ip6_ecn_egress(ip6_ipsec_ecn, &flowinfo, &ip6->ip6_flow); 1014 if (!key_checktunnelsanity(sav, AF_INET6, 1015 (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst)) { 1016 ipseclog((LOG_ERR, "ipsec tunnel address mismatch " 1017 "in IPv6 ESP input: %s %s\n", 1018 ipsec6_logpacketstr(ip6, spi), 1019 ipsec_logsastr(sav))); 1020 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval); 1021 goto bad; 1022 } 1023 1024 key_sa_recordxfer(sav, m); 1025 if (ipsec_addhist(m, IPPROTO_ESP, spi) != 0 || 1026 ipsec_addhist(m, IPPROTO_IPV6, 0) != 0) { 1027 IPSEC_STAT_INCREMENT(ipsec6stat.in_nomem); 1028 goto bad; 1029 } 1030 1031 if (ip6_doscopedroute) { 1032 struct sockaddr_in6 *ip6addr; 1033 1034 bzero(&addr, sizeof(addr)); 1035 ip6addr = (__typeof__(ip6addr))&addr; 1036 ip6addr->sin6_family = AF_INET6; 1037 ip6addr->sin6_len = sizeof(*ip6addr); 1038 ip6addr->sin6_addr = ip6->ip6_dst; 1039 1040 // update the receiving interface address based on the inner address 1041 ifa = ifa_ifwithaddr((struct sockaddr *)&addr); 1042 if (ifa) { 1043 m->m_pkthdr.rcvif = ifa->ifa_ifp; 1044 IFA_REMREF(ifa); 1045 } 1046 } 1047 1048 if (sav->utun_in_fn) { 1049 if (!(sav->utun_in_fn(sav->utun_pcb, &m, PF_INET6))) { 1050 m = NULL; 1051 // we just wanna exit since packet has been completely processed 1052 goto bad; 1053 } 1054 } 1055 1056 if (proto_input(PF_INET6, m) != 0) 1057 goto bad; 1058 nxt = IPPROTO_DONE; 1059 } else { 1060 /* 1061 * strip off ESP header and IV. 1062 * even in m_pulldown case, we need to strip off ESP so that 1063 * we can always compute checksum for AH correctly. 1064 */ 1065 size_t stripsiz; 1066 char *prvnxtp; 1067 1068 /* 1069 * Set the next header field of the previous header correctly. 1070 */ 1071 prvnxtp = ip6_get_prevhdr(m, off); /* XXX */ 1072 *prvnxtp = nxt; 1073 1074 stripsiz = esplen + ivlen; 1075 1076 ip6 = mtod(m, struct ip6_hdr *); 1077 if (m->m_len >= stripsiz + off) { 1078 ovbcopy((caddr_t)ip6, ((caddr_t)ip6) + stripsiz, off); 1079 m->m_data += stripsiz; 1080 m->m_len -= stripsiz; 1081 m->m_pkthdr.len -= stripsiz; 1082 } else { 1083 /* 1084 * this comes with no copy if the boundary is on 1085 * cluster 1086 */ 1087 struct mbuf *n; 1088 1089 n = m_split(m, off, M_DONTWAIT); 1090 if (n == NULL) { 1091 /* m is retained by m_split */ 1092 goto bad; 1093 } 1094 m_adj(n, stripsiz); 1095 /* m_cat does not update m_pkthdr.len */ 1096 m->m_pkthdr.len += n->m_pkthdr.len; 1097 m_cat(m, n); 1098 } 1099 1100#ifndef PULLDOWN_TEST 1101 /* 1102 * KAME requires that the packet to be contiguous on the 1103 * mbuf. We need to make that sure. 1104 * this kind of code should be avoided. 1105 * XXX other conditions to avoid running this part? 1106 */ 1107 if (m->m_len != m->m_pkthdr.len) { 1108 struct mbuf *n = NULL; 1109 int maxlen; 1110 1111 MGETHDR(n, M_DONTWAIT, MT_HEADER); /* MAC-OK */ 1112 maxlen = MHLEN; 1113 if (n) 1114 M_COPY_PKTHDR(n, m); 1115 if (n && m->m_pkthdr.len > maxlen) { 1116 MCLGET(n, M_DONTWAIT); 1117 maxlen = MCLBYTES; 1118 if ((n->m_flags & M_EXT) == 0) { 1119 m_free(n); 1120 n = NULL; 1121 } 1122 } 1123 if (!n) { 1124 printf("esp6_input: mbuf allocation failed\n"); 1125 goto bad; 1126 } 1127 1128 if (m->m_pkthdr.len <= maxlen) { 1129 m_copydata(m, 0, m->m_pkthdr.len, mtod(n, caddr_t)); 1130 n->m_len = m->m_pkthdr.len; 1131 n->m_pkthdr.len = m->m_pkthdr.len; 1132 n->m_next = NULL; 1133 m_freem(m); 1134 } else { 1135 m_copydata(m, 0, maxlen, mtod(n, caddr_t)); 1136 n->m_len = maxlen; 1137 n->m_pkthdr.len = m->m_pkthdr.len; 1138 n->m_next = m; 1139 m_adj(m, maxlen); 1140 m->m_flags &= ~M_PKTHDR; 1141 } 1142 m = n; 1143 } 1144#endif 1145 1146 ip6 = mtod(m, struct ip6_hdr *); 1147 ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - stripsiz); 1148 1149 key_sa_recordxfer(sav, m); 1150 if (ipsec_addhist(m, IPPROTO_ESP, spi) != 0) { 1151 IPSEC_STAT_INCREMENT(ipsec6stat.in_nomem); 1152 goto bad; 1153 } 1154 1155 if (sav->utun_in_fn) { 1156 if (!(sav->utun_in_fn(sav->utun_pcb, &m, PF_INET6))) { 1157 m = NULL; 1158 // we just wanna exit since packet has been completely processed 1159 goto bad; 1160 } 1161 } 1162 } 1163 1164 *offp = off; 1165 *mp = m; 1166 1167 if (sav) { 1168 KEYDEBUG(KEYDEBUG_IPSEC_STAMP, 1169 printf("DP esp6_input call free SA:%p\n", sav)); 1170 key_freesav(sav, KEY_SADB_UNLOCKED); 1171 } 1172 IPSEC_STAT_INCREMENT(ipsec6stat.in_success); 1173 return nxt; 1174 1175bad: 1176 if (sav) { 1177 KEYDEBUG(KEYDEBUG_IPSEC_STAMP, 1178 printf("DP esp6_input call free SA:%p\n", sav)); 1179 key_freesav(sav, KEY_SADB_UNLOCKED); 1180 } 1181 if (m) 1182 m_freem(m); 1183 return IPPROTO_DONE; 1184} 1185 1186void 1187esp6_ctlinput(cmd, sa, d) 1188 int cmd; 1189 struct sockaddr *sa; 1190 void *d; 1191{ 1192 const struct newesp *espp; 1193 struct newesp esp; 1194 struct ip6ctlparam *ip6cp = NULL, ip6cp1; 1195 struct secasvar *sav; 1196 struct ip6_hdr *ip6; 1197 struct mbuf *m; 1198 int off; 1199 struct sockaddr_in6 *sa6_src, *sa6_dst; 1200 1201 if (sa->sa_family != AF_INET6 || 1202 sa->sa_len != sizeof(struct sockaddr_in6)) 1203 return; 1204 if ((unsigned)cmd >= PRC_NCMDS) 1205 return; 1206 1207 /* if the parameter is from icmp6, decode it. */ 1208 if (d != NULL) { 1209 ip6cp = (struct ip6ctlparam *)d; 1210 m = ip6cp->ip6c_m; 1211 ip6 = ip6cp->ip6c_ip6; 1212 off = ip6cp->ip6c_off; 1213 } else { 1214 m = NULL; 1215 ip6 = NULL; 1216 } 1217 1218 if (ip6) { 1219 /* 1220 * Notify the error to all possible sockets via pfctlinput2. 1221 * Since the upper layer information (such as protocol type, 1222 * source and destination ports) is embedded in the encrypted 1223 * data and might have been cut, we can't directly call 1224 * an upper layer ctlinput function. However, the pcbnotify 1225 * function will consider source and destination addresses 1226 * as well as the flow info value, and may be able to find 1227 * some PCB that should be notified. 1228 * Although pfctlinput2 will call esp6_ctlinput(), there is 1229 * no possibility of an infinite loop of function calls, 1230 * because we don't pass the inner IPv6 header. 1231 */ 1232 bzero(&ip6cp1, sizeof(ip6cp1)); 1233 ip6cp1.ip6c_src = ip6cp->ip6c_src; 1234 pfctlinput2(cmd, sa, (void *)&ip6cp1); 1235 1236 /* 1237 * Then go to special cases that need ESP header information. 1238 * XXX: We assume that when ip6 is non NULL, 1239 * M and OFF are valid. 1240 */ 1241 1242 /* check if we can safely examine src and dst ports */ 1243 if (m->m_pkthdr.len < off + sizeof(esp)) 1244 return; 1245 1246 if (m->m_len < off + sizeof(esp)) { 1247 /* 1248 * this should be rare case, 1249 * so we compromise on this copy... 1250 */ 1251 m_copydata(m, off, sizeof(esp), (caddr_t)&esp); 1252 espp = &esp; 1253 } else 1254 espp = (struct newesp*)(void *)(mtod(m, caddr_t) + off); 1255 1256 if (cmd == PRC_MSGSIZE) { 1257 int valid = 0; 1258 1259 /* 1260 * Check to see if we have a valid SA corresponding to 1261 * the address in the ICMP message payload. 1262 */ 1263 sa6_src = ip6cp->ip6c_src; 1264 sa6_dst = (struct sockaddr_in6 *)(void *)sa; 1265 sav = key_allocsa(AF_INET6, 1266 (caddr_t)&sa6_src->sin6_addr, 1267 (caddr_t)&sa6_dst->sin6_addr, 1268 IPPROTO_ESP, espp->esp_spi); 1269 if (sav) { 1270 if (sav->state == SADB_SASTATE_MATURE || 1271 sav->state == SADB_SASTATE_DYING) 1272 valid++; 1273 key_freesav(sav, KEY_SADB_LOCKED); 1274 } 1275 1276 /* XXX Further validation? */ 1277 1278 /* 1279 * Depending on the value of "valid" and routing table 1280 * size (mtudisc_{hi,lo}wat), we will: 1281 * - recalcurate the new MTU and create the 1282 * corresponding routing entry, or 1283 * - ignore the MTU change notification. 1284 */ 1285 icmp6_mtudisc_update((struct ip6ctlparam *)d, valid); 1286 } 1287 } else { 1288 /* we normally notify any pcb here */ 1289 } 1290} 1291#endif /* INET6 */ 1292