ipsec_output.c (275708) | ipsec_output.c (281692) |
---|---|
1/*- 2 * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 9 unchanged lines hidden (view full) --- 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * | 1/*- 2 * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 9 unchanged lines hidden (view full) --- 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * |
26 * $FreeBSD: head/sys/netipsec/ipsec_output.c 275708 2014-12-11 17:34:49Z ae $ | 26 * $FreeBSD: head/sys/netipsec/ipsec_output.c 281692 2015-04-18 16:38:45Z ae $ |
27 */ 28 29/* 30 * IPsec output processing. 31 */ 32#include "opt_inet.h" 33#include "opt_inet6.h" 34#include "opt_ipsec.h" --- 21 unchanged lines hidden (view full) --- 56#include <netinet/ip_ecn.h> 57#ifdef INET6 58#include <netinet6/ip6_ecn.h> 59#endif 60 61#include <netinet/ip6.h> 62#ifdef INET6 63#include <netinet6/ip6_var.h> | 27 */ 28 29/* 30 * IPsec output processing. 31 */ 32#include "opt_inet.h" 33#include "opt_inet6.h" 34#include "opt_ipsec.h" --- 21 unchanged lines hidden (view full) --- 56#include <netinet/ip_ecn.h> 57#ifdef INET6 58#include <netinet6/ip6_ecn.h> 59#endif 60 61#include <netinet/ip6.h> 62#ifdef INET6 63#include <netinet6/ip6_var.h> |
64#include <netinet6/scope6_var.h> |
|
64#endif 65#include <netinet/in_pcb.h> 66#ifdef INET6 67#include <netinet/icmp6.h> 68#endif 69 70#include <netipsec/ipsec.h> 71#ifdef INET6 --- 342 unchanged lines hidden (view full) --- 414 return isr; 415bad: 416 IPSEC_ASSERT(*error != 0, ("error return w/ no error code")); 417 IPSECREQUEST_UNLOCK(isr); 418 return NULL; 419#undef IPSEC_OSTAT 420} 421 | 65#endif 66#include <netinet/in_pcb.h> 67#ifdef INET6 68#include <netinet/icmp6.h> 69#endif 70 71#include <netipsec/ipsec.h> 72#ifdef INET6 --- 342 unchanged lines hidden (view full) --- 415 return isr; 416bad: 417 IPSEC_ASSERT(*error != 0, ("error return w/ no error code")); 418 IPSECREQUEST_UNLOCK(isr); 419 return NULL; 420#undef IPSEC_OSTAT 421} 422 |
423static int 424ipsec_encap(struct mbuf **mp, struct secasindex *saidx) 425{ 426#ifdef INET6 427 struct ip6_hdr *ip6; 428#endif 429 struct ip *ip; 430 int setdf; 431 uint8_t itos, proto; 432 433 ip = mtod(*mp, struct ip *); 434 switch (ip->ip_v) { |
|
422#ifdef INET | 435#ifdef INET |
436 case IPVERSION: 437 proto = IPPROTO_IPIP; 438 /* 439 * Collect IP_DF state from the inner header 440 * and honor system-wide control of how to handle it. 441 */ 442 switch (V_ip4_ipsec_dfbit) { 443 case 0: /* clear in outer header */ 444 case 1: /* set in outer header */ 445 setdf = V_ip4_ipsec_dfbit; 446 break; 447 default:/* propagate to outer header */ 448 setdf = (ip->ip_off & ntohs(IP_DF)) != 0; 449 } 450 itos = ip->ip_tos; 451 break; 452#endif 453#ifdef INET6 454 case (IPV6_VERSION >> 4): 455 proto = IPPROTO_IPV6; 456 ip6 = mtod(*mp, struct ip6_hdr *); 457 itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; 458 setdf = V_ip4_ipsec_dfbit ? 1: 0; 459 /* scoped address handling */ 460 in6_clearscope(&ip6->ip6_src); 461 in6_clearscope(&ip6->ip6_dst); 462 break; 463#endif 464 default: 465 return (EAFNOSUPPORT); 466 } 467 switch (saidx->dst.sa.sa_family) { 468#ifdef INET 469 case AF_INET: 470 if (saidx->src.sa.sa_family != AF_INET || 471 saidx->src.sin.sin_addr.s_addr == INADDR_ANY || 472 saidx->dst.sin.sin_addr.s_addr == INADDR_ANY) 473 return (EINVAL); 474 M_PREPEND(*mp, sizeof(struct ip), M_NOWAIT); 475 if (*mp == NULL) 476 return (ENOBUFS); 477 ip = mtod(*mp, struct ip *); 478 ip->ip_v = IPVERSION; 479 ip->ip_hl = sizeof(struct ip) >> 2; 480 ip->ip_p = proto; 481 ip->ip_len = htons((*mp)->m_pkthdr.len); 482 ip->ip_ttl = V_ip_defttl; 483 ip->ip_sum = 0; 484 ip->ip_off = setdf ? htons(IP_DF): 0; 485 ip->ip_src = saidx->src.sin.sin_addr; 486 ip->ip_dst = saidx->dst.sin.sin_addr; 487 ip_ecn_ingress(V_ip4_ipsec_ecn, &ip->ip_tos, &itos); 488 ip_fillid(ip); 489 break; 490#endif /* INET */ 491#ifdef INET6 492 case AF_INET6: 493 if (saidx->src.sa.sa_family != AF_INET6 || 494 IN6_IS_ADDR_UNSPECIFIED(&saidx->src.sin6.sin6_addr) || 495 IN6_IS_ADDR_UNSPECIFIED(&saidx->dst.sin6.sin6_addr)) 496 return (EINVAL); 497 M_PREPEND(*mp, sizeof(struct ip6_hdr), M_NOWAIT); 498 if (*mp == NULL) 499 return (ENOBUFS); 500 ip6 = mtod(*mp, struct ip6_hdr *); 501 ip6->ip6_flow = 0; 502 ip6->ip6_vfc = IPV6_VERSION; 503 ip6->ip6_hlim = V_ip6_defhlim; 504 ip6->ip6_nxt = proto; 505 ip6->ip6_dst = saidx->dst.sin6.sin6_addr; 506 ip6->ip6_src = saidx->src.sin6.sin6_addr; 507 ip6->ip6_plen = htons((*mp)->m_pkthdr.len - sizeof(*ip6)); 508 ip_ecn_ingress(V_ip6_ipsec_ecn, &proto, &itos); 509 ip6->ip6_flow |= htonl((uint32_t)proto << 20); 510 break; 511#endif /* INET6 */ 512 default: 513 return (EAFNOSUPPORT); 514 } 515 return (0); 516} 517 518#ifdef INET |
|
423/* 424 * IPsec output logic for IPv4. 425 */ 426int 427ipsec4_process_packet(struct mbuf *m, struct ipsecrequest *isr) 428{ 429 union sockaddr_union *dst; 430 struct secasindex saidx; 431 struct secasvar *sav; 432 struct ip *ip; | 519/* 520 * IPsec output logic for IPv4. 521 */ 522int 523ipsec4_process_packet(struct mbuf *m, struct ipsecrequest *isr) 524{ 525 union sockaddr_union *dst; 526 struct secasindex saidx; 527 struct secasvar *sav; 528 struct ip *ip; |
433 int error, i, off, setdf; | 529 int error, i, off; |
434 435 IPSEC_ASSERT(m != NULL, ("null mbuf")); 436 IPSEC_ASSERT(isr != NULL, ("null isr")); 437 438 IPSECREQUEST_LOCK(isr); /* insure SA contents don't change */ 439 440 isr = ipsec_nextisr(m, isr, AF_INET, &saidx, &error); 441 if (isr == NULL) { --- 18 unchanged lines hidden (view full) --- 460 ipsec_bpf(m, sav, AF_INET, ENC_OUT|ENC_BEFORE); 461 /* pass the mbuf to enc0 for packet filtering */ 462 if ((error = ipsec_filter(&m, PFIL_OUT, ENC_OUT|ENC_BEFORE)) != 0) 463 goto bad; 464#endif 465 /* Do the appropriate encapsulation, if necessary */ 466 if (isr->saidx.mode == IPSEC_MODE_TUNNEL || /* Tunnel requ'd */ 467 dst->sa.sa_family != AF_INET || /* PF mismatch */ | 530 531 IPSEC_ASSERT(m != NULL, ("null mbuf")); 532 IPSEC_ASSERT(isr != NULL, ("null isr")); 533 534 IPSECREQUEST_LOCK(isr); /* insure SA contents don't change */ 535 536 isr = ipsec_nextisr(m, isr, AF_INET, &saidx, &error); 537 if (isr == NULL) { --- 18 unchanged lines hidden (view full) --- 556 ipsec_bpf(m, sav, AF_INET, ENC_OUT|ENC_BEFORE); 557 /* pass the mbuf to enc0 for packet filtering */ 558 if ((error = ipsec_filter(&m, PFIL_OUT, ENC_OUT|ENC_BEFORE)) != 0) 559 goto bad; 560#endif 561 /* Do the appropriate encapsulation, if necessary */ 562 if (isr->saidx.mode == IPSEC_MODE_TUNNEL || /* Tunnel requ'd */ 563 dst->sa.sa_family != AF_INET || /* PF mismatch */ |
468#if 0 469 (sav->flags & SADB_X_SAFLAGS_TUNNEL) || /* Tunnel requ'd */ 470 sav->tdb_xform->xf_type == XF_IP4 || /* ditto */ 471#endif | |
472 (dst->sa.sa_family == AF_INET && /* Proxy */ 473 dst->sin.sin_addr.s_addr != INADDR_ANY && 474 dst->sin.sin_addr.s_addr != ip->ip_dst.s_addr)) { | 564 (dst->sa.sa_family == AF_INET && /* Proxy */ 565 dst->sin.sin_addr.s_addr != INADDR_ANY && 566 dst->sin.sin_addr.s_addr != ip->ip_dst.s_addr)) { |
475 struct mbuf *mp; 476 | |
477 /* Fix IPv4 header checksum and length */ 478 ip->ip_len = htons(m->m_pkthdr.len); 479 ip->ip_sum = 0; 480 ip->ip_sum = in_cksum(m, ip->ip_hl << 2); | 567 /* Fix IPv4 header checksum and length */ 568 ip->ip_len = htons(m->m_pkthdr.len); 569 ip->ip_sum = 0; 570 ip->ip_sum = in_cksum(m, ip->ip_hl << 2); |
481 /* 482 * Collect IP_DF state from the outer header 483 * and honor system-wide control of how to handle it. 484 */ 485 switch (V_ip4_ipsec_dfbit) { 486 case 0: /* clear in outer header */ 487 case 1: /* set in outer header */ 488 setdf = V_ip4_ipsec_dfbit; 489 break; 490 default: /* propagate to outer header */ 491 setdf = ntohs(ip->ip_off & IP_DF); 492 } 493 /* Encapsulate the packet */ 494 error = ipip_output(m, isr, &mp, 0, 0); | 571 error = ipsec_encap(&m, &sav->sah->saidx); |
495 if (error != 0) { | 572 if (error != 0) { |
496 m = NULL; /* ipip_output() already freed it */ | 573 DPRINTF(("%s: encapsulation for SA %s->%s " 574 "SPI 0x%08x failed with error %d\n", __func__, 575 ipsec_address(&sav->sah->saidx.src), 576 ipsec_address(&sav->sah->saidx.dst), 577 ntohl(sav->spi), error)); |
497 goto bad; 498 } | 578 goto bad; 579 } |
499 m = mp; 500 /* 501 * ipip_output clears IP_DF in the new header. If 502 * we need to propagate IP_DF from the outer header, 503 * then we have to do it here. 504 * 505 * XXX shouldn't assume what ipip_output does. 506 */ 507 if (dst->sa.sa_family == AF_INET && setdf) { 508 ip = mtod(m, struct ip *); 509 ip->ip_off = ntohs(ip->ip_off); 510 ip->ip_off |= IP_DF; 511 ip->ip_off = htons(ip->ip_off); 512 } | |
513 } | 580 } |
514 | |
515#ifdef DEV_ENC 516 /* pass the mbuf to enc0 for bpf processing */ 517 ipsec_bpf(m, sav, sav->sah->saidx.dst.sa.sa_family, ENC_OUT|ENC_AFTER); 518 /* pass the mbuf to enc0 for packet filtering */ 519 if ((error = ipsec_filter(&m, PFIL_OUT, ENC_OUT|ENC_AFTER)) != 0) 520 goto bad; 521#endif 522 523 /* 524 * Dispatch to the appropriate IPsec transform logic. The 525 * packet will be returned for transmission after crypto | 581#ifdef DEV_ENC 582 /* pass the mbuf to enc0 for bpf processing */ 583 ipsec_bpf(m, sav, sav->sah->saidx.dst.sa.sa_family, ENC_OUT|ENC_AFTER); 584 /* pass the mbuf to enc0 for packet filtering */ 585 if ((error = ipsec_filter(&m, PFIL_OUT, ENC_OUT|ENC_AFTER)) != 0) 586 goto bad; 587#endif 588 589 /* 590 * Dispatch to the appropriate IPsec transform logic. The 591 * packet will be returned for transmission after crypto |
526 * processing, etc. are completed. For encapsulation we 527 * bypass this call because of the explicit call done above 528 * (necessary to deal with IP_DF handling for IPv4). | 592 * processing, etc. are completed. |
529 * 530 * NB: m & sav are ``passed to caller'' who's reponsible for 531 * for reclaiming their resources. 532 */ | 593 * 594 * NB: m & sav are ``passed to caller'' who's reponsible for 595 * for reclaiming their resources. 596 */ |
533 if (sav->tdb_xform->xf_type != XF_IP4) { 534 union sockaddr_union *dst = &sav->sah->saidx.dst; 535 switch(dst->sa.sa_family) { 536 case AF_INET: 537 ip = mtod(m, struct ip *); 538 i = ip->ip_hl << 2; 539 off = offsetof(struct ip, ip_p); 540 break; | 597 switch(dst->sa.sa_family) { 598 case AF_INET: 599 ip = mtod(m, struct ip *); 600 i = ip->ip_hl << 2; 601 off = offsetof(struct ip, ip_p); 602 break; |
541#ifdef INET6 | 603#ifdef INET6 |
542 case AF_INET6: 543 i = sizeof(struct ip6_hdr); 544 off = offsetof(struct ip6_hdr, ip6_nxt); 545 break; | 604 case AF_INET6: 605 i = sizeof(struct ip6_hdr); 606 off = offsetof(struct ip6_hdr, ip6_nxt); 607 break; |
546#endif /* INET6 */ | 608#endif /* INET6 */ |
547 default: | 609 default: |
548 DPRINTF(("%s: unsupported protocol family %u\n", | 610 DPRINTF(("%s: unsupported protocol family %u\n", |
549 __func__, dst->sa.sa_family)); 550 error = EPFNOSUPPORT; 551 IPSECSTAT_INC(ips_out_inval); 552 goto bad; 553 } 554 error = (*sav->tdb_xform->xf_output)(m, isr, NULL, i, off); 555 } else { 556 error = ipsec_process_done(m, isr); | 611 __func__, dst->sa.sa_family)); 612 error = EPFNOSUPPORT; 613 IPSECSTAT_INC(ips_out_inval); 614 goto bad; |
557 } | 615 } |
616 error = (*sav->tdb_xform->xf_output)(m, isr, NULL, i, off); |
|
558 IPSECREQUEST_UNLOCK(isr); | 617 IPSECREQUEST_UNLOCK(isr); |
559 return error; | 618 return (error); |
560bad: 561 if (isr) 562 IPSECREQUEST_UNLOCK(isr); 563 if (m) 564 m_freem(m); 565 return error; 566} 567#endif --- 33 unchanged lines hidden (view full) --- 601 IPSECREQUEST_LOCK(isr); /* insure SA contents don't change */ 602 603 isr = ipsec_nextisr(m, isr, AF_INET6, &saidx, &error); 604 if (isr == NULL) { 605 if (error != 0) 606 goto bad; 607 return EJUSTRETURN; 608 } | 619bad: 620 if (isr) 621 IPSECREQUEST_UNLOCK(isr); 622 if (m) 623 m_freem(m); 624 return error; 625} 626#endif --- 33 unchanged lines hidden (view full) --- 660 IPSECREQUEST_LOCK(isr); /* insure SA contents don't change */ 661 662 isr = ipsec_nextisr(m, isr, AF_INET6, &saidx, &error); 663 if (isr == NULL) { 664 if (error != 0) 665 goto bad; 666 return EJUSTRETURN; 667 } |
609 | |
610 sav = isr->sav; 611 dst = &sav->sah->saidx.dst; 612 613 ip6 = mtod(m, struct ip6_hdr *); 614 ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6)); 615#ifdef DEV_ENC 616 if_inc_counter(encif, IFCOUNTER_OPACKETS, 1); 617 if_inc_counter(encif, IFCOUNTER_OBYTES, m->m_pkthdr.len); --- 7 unchanged lines hidden (view full) --- 625 626 /* Do the appropriate encapsulation, if necessary */ 627 if (isr->saidx.mode == IPSEC_MODE_TUNNEL || /* Tunnel requ'd */ 628 dst->sa.sa_family != AF_INET6 || /* PF mismatch */ 629 ((dst->sa.sa_family == AF_INET6) && 630 (!IN6_IS_ADDR_UNSPECIFIED(&dst->sin6.sin6_addr)) && 631 (!in6_sa_equal_addrwithscope(&dst->sin6, 632 &ip6->ip6_dst)))) { | 668 sav = isr->sav; 669 dst = &sav->sah->saidx.dst; 670 671 ip6 = mtod(m, struct ip6_hdr *); 672 ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6)); 673#ifdef DEV_ENC 674 if_inc_counter(encif, IFCOUNTER_OPACKETS, 1); 675 if_inc_counter(encif, IFCOUNTER_OBYTES, m->m_pkthdr.len); --- 7 unchanged lines hidden (view full) --- 683 684 /* Do the appropriate encapsulation, if necessary */ 685 if (isr->saidx.mode == IPSEC_MODE_TUNNEL || /* Tunnel requ'd */ 686 dst->sa.sa_family != AF_INET6 || /* PF mismatch */ 687 ((dst->sa.sa_family == AF_INET6) && 688 (!IN6_IS_ADDR_UNSPECIFIED(&dst->sin6.sin6_addr)) && 689 (!in6_sa_equal_addrwithscope(&dst->sin6, 690 &ip6->ip6_dst)))) { |
633 struct mbuf *mp; 634 635 /* Fix IPv6 header payload length. */ 636 if (m->m_len < sizeof(struct ip6_hdr)) 637 if ((m = m_pullup(m,sizeof(struct ip6_hdr))) == NULL) { 638 error = ENOBUFS; 639 goto bad; 640 } 641 | |
642 if (m->m_pkthdr.len - sizeof(*ip6) > IPV6_MAXPACKET) { 643 /* No jumbogram support. */ 644 error = ENXIO; /*XXX*/ 645 goto bad; 646 } | 691 if (m->m_pkthdr.len - sizeof(*ip6) > IPV6_MAXPACKET) { 692 /* No jumbogram support. */ 693 error = ENXIO; /*XXX*/ 694 goto bad; 695 } |
647 648 /* Encapsulate the packet */ 649 error = ipip_output(m, isr, &mp, 0, 0); 650 if (mp == NULL && !error) { 651 /* Should never happen. */ 652 DPRINTF(("ipsec6_process_packet: ipip_output " 653 "returns no mbuf and no error!")); 654 error = EFAULT; | 696 error = ipsec_encap(&m, &sav->sah->saidx); 697 if (error != 0) { 698 DPRINTF(("%s: encapsulation for SA %s->%s " 699 "SPI 0x%08x failed with error %d\n", __func__, 700 ipsec_address(&sav->sah->saidx.src), 701 ipsec_address(&sav->sah->saidx.dst), 702 ntohl(sav->spi), error)); |
655 goto bad; 656 } | 703 goto bad; 704 } |
657 658 if (error) { 659 if (mp) { 660 /* XXX: Should never happen! */ 661 m_freem(mp); 662 } 663 m = NULL; /* ipip_output() already freed it */ 664 goto bad; 665 } 666 667 m = mp; 668 mp = NULL; | |
669 } 670 671#ifdef DEV_ENC 672 ipsec_bpf(m, isr->sav, dst->sa.sa_family, ENC_OUT|ENC_AFTER); 673 /* pass the mbuf to enc0 for packet filtering */ 674 if ((error = ipsec_filter(&m, PFIL_OUT, ENC_OUT|ENC_AFTER)) != 0) 675 goto bad; 676#endif /* DEV_ENC */ --- 35 unchanged lines hidden --- | 705 } 706 707#ifdef DEV_ENC 708 ipsec_bpf(m, isr->sav, dst->sa.sa_family, ENC_OUT|ENC_AFTER); 709 /* pass the mbuf to enc0 for packet filtering */ 710 if ((error = ipsec_filter(&m, PFIL_OUT, ENC_OUT|ENC_AFTER)) != 0) 711 goto bad; 712#endif /* DEV_ENC */ --- 35 unchanged lines hidden --- |