Deleted Added
full compact
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 ---