Deleted Added
sdiff udiff text old ( 275708 ) new ( 281692 )
full compact
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 $
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#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
422#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;
433 int error, i, off, setdf;
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 */
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)) {
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);
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);
495 if (error != 0) {
496 m = NULL; /* ipip_output() already freed it */
497 goto bad;
498 }
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 }
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
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).
529 *
530 * NB: m & sav are ``passed to caller'' who's reponsible for
531 * for reclaiming their resources.
532 */
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;
541#ifdef INET6
542 case AF_INET6:
543 i = sizeof(struct ip6_hdr);
544 off = offsetof(struct ip6_hdr, ip6_nxt);
545 break;
546#endif /* INET6 */
547 default:
548 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);
557 }
558 IPSECREQUEST_UNLOCK(isr);
559 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 }
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)))) {
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 }
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;
655 goto bad;
656 }
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 ---