Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 10 Dec 2016 14:20:51 +0000 (UTC)
From:      "Andrey V. Elsukov" <ae@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r309808 - in projects/ipsec/sys: conf netinet netipsec
Message-ID:  <201612101420.uBAEKpC3084749@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: ae
Date: Sat Dec 10 14:20:51 2016
New Revision: 309808
URL: https://svnweb.freebsd.org/changeset/base/309808

Log:
  Rework NAT-T support.
  
  Remove UDP_ENCAP_ESPINUDP_NON_IKE UDP encapsulation support. This type
  was introduced in draft-ietf-ipsec-udp-encaps-00 and then was removed in
  draft-ietf-ipsec-udp-encaps-02. All these drafts were already expired
  almost 15 years ago.
  
  Now we support only one encapsulation type described in the RFC3948.
  NAT-T support is enabled by default in IPSEC kernel, IPSEC_NAT_T option
  is removed.
  
  Move UDP encapsulation releated code into netipsec/udpencap.c.
  
  Add udp_ipsec_input() function. Use it from UDP input path to check that
  datagram needs decapsulation.
  
  Add udp_ipsec_output() function to encapsulate outbound IP+ESP datagram
  into UDP.
  
  Add udp_ipsec_adjust_cksum() function to update TCP/UDP checksum for
  decapsulated and decrypted inbound packet for transport mode SA.
  
  Introduce net.inet.ipsec.natt_cksum_policy sysctl variable. It controls
  how udp_ipsec_adjust_cksum() updates TCP/UDP checksum:
   0: use incremental checksum update using information about original
      addresses from IKE.
   1: fully recalculate checksum;
   2: for UDP reset checksum to zero, for TCP set mbuf's csum_flags to
      mark checksum as valid.
  
  Due to changes in SADB now each SA has unique SPI. Thus even when several
  peers are behind the same NAT, they all will have different SPI and we
  don't need to keep ports in the SAIDX. Remove all such ports checks and
  all XXX comments related to NAT-T from key.c. Instead add big comment
  that describes how NAT-T support implemented and where the kernel expects
  NAT-T extension headers.
  
  Introduce "struct secnatt {}" that contains all information related to
  NAT-T, allocate it by demand if IKEd has determined presence of NAT.
  Add support for SADB_X_EXT_NAT_T_OAI and SADB_X_EXT_NAT_T_OAR PF_KEY
  messages.

Added:
  projects/ipsec/sys/netipsec/udpencap.c   (contents, props changed)
Modified:
  projects/ipsec/sys/conf/NOTES
  projects/ipsec/sys/conf/files
  projects/ipsec/sys/conf/options
  projects/ipsec/sys/netinet/udp.h
  projects/ipsec/sys/netinet/udp_usrreq.c
  projects/ipsec/sys/netipsec/ipsec.c
  projects/ipsec/sys/netipsec/ipsec.h
  projects/ipsec/sys/netipsec/ipsec_input.c
  projects/ipsec/sys/netipsec/ipsec_output.c
  projects/ipsec/sys/netipsec/key.c
  projects/ipsec/sys/netipsec/keydb.h

Modified: projects/ipsec/sys/conf/NOTES
==============================================================================
--- projects/ipsec/sys/conf/NOTES	Sat Dec 10 13:30:18 2016	(r309807)
+++ projects/ipsec/sys/conf/NOTES	Sat Dec 10 14:20:51 2016	(r309808)
@@ -625,11 +625,6 @@ options 	TCP_OFFLOAD		# TCP offload supp
 # your kernel configuration
 options 	IPSEC			#IP security (requires device crypto)
 #options 	IPSEC_DEBUG		#debug for IP security
-#
-# Set IPSEC_NAT_T to enable NAT-Traversal support.  This enables
-# optional UDP encapsulation of ESP packets.
-#
-options		IPSEC_NAT_T		#NAT-T support, UDP encap of ESP
 
 #
 # SMB/CIFS requester

Modified: projects/ipsec/sys/conf/files
==============================================================================
--- projects/ipsec/sys/conf/files	Sat Dec 10 13:30:18 2016	(r309807)
+++ projects/ipsec/sys/conf/files	Sat Dec 10 14:20:51 2016	(r309808)
@@ -4111,6 +4111,7 @@ netipsec/ipsec_output.c		optional ipsec 
 netipsec/key.c			optional ipsec inet | ipsec inet6
 netipsec/key_debug.c		optional ipsec inet | ipsec inet6
 netipsec/keysock.c		optional ipsec inet | ipsec inet6
+netipsec/udpencap.c		optional ipsec inet
 netipsec/xform_ah.c		optional ipsec inet | ipsec inet6
 netipsec/xform_esp.c		optional ipsec inet | ipsec inet6
 netipsec/xform_ipcomp.c		optional ipsec inet | ipsec inet6

Modified: projects/ipsec/sys/conf/options
==============================================================================
--- projects/ipsec/sys/conf/options	Sat Dec 10 13:30:18 2016	(r309807)
+++ projects/ipsec/sys/conf/options	Sat Dec 10 14:20:51 2016	(r309808)
@@ -427,7 +427,6 @@ IPFIREWALL_VERBOSE	opt_ipfw.h
 IPFIREWALL_VERBOSE_LIMIT	opt_ipfw.h
 IPSEC			opt_ipsec.h
 IPSEC_DEBUG		opt_ipsec.h
-IPSEC_NAT_T		opt_ipsec.h
 IPSTEALTH
 KRPC
 LIBALIAS

Modified: projects/ipsec/sys/netinet/udp.h
==============================================================================
--- projects/ipsec/sys/netinet/udp.h	Sat Dec 10 13:30:18 2016	(r309807)
+++ projects/ipsec/sys/netinet/udp.h	Sat Dec 10 14:20:51 2016	(r309808)
@@ -58,7 +58,7 @@ struct udphdr {
  */
 /* Encapsulation types. */
 #define	UDP_ENCAP_ESPINUDP_NON_IKE	1 /* draft-ietf-ipsec-nat-t-ike-00/01 */
-#define	UDP_ENCAP_ESPINUDP		2 /* draft-ietf-ipsec-udp-encaps-02+ */
+#define	UDP_ENCAP_ESPINUDP		2 /* RFC3948 */
 
 /* Default ESP in UDP encapsulation port. */
 #define	UDP_ENCAP_ESPINUDP_PORT		500

Modified: projects/ipsec/sys/netinet/udp_usrreq.c
==============================================================================
--- projects/ipsec/sys/netinet/udp_usrreq.c	Sat Dec 10 13:30:18 2016	(r309807)
+++ projects/ipsec/sys/netinet/udp_usrreq.c	Sat Dec 10 14:20:51 2016	(r309808)
@@ -172,15 +172,6 @@ static int	udp_output(struct inpcb *, st
 		    struct mbuf *, struct thread *);
 #endif
 
-#ifdef IPSEC
-#ifdef IPSEC_NAT_T
-#define	UF_ESPINUDP_ALL	(UF_ESPINUDP_NON_IKE|UF_ESPINUDP)
-#ifdef INET
-static struct mbuf *udp4_espdecap(struct inpcb *, struct mbuf *, int);
-#endif
-#endif /* IPSEC_NAT_T */
-#endif /* IPSEC */
-
 static void
 udp_zone_change(void *tag)
 {
@@ -345,15 +336,11 @@ udp_append(struct inpcb *inp, struct ip 
 		m_freem(n);
 		return (0);
 	}
-#ifdef IPSEC_NAT_T
-	up = intoudpcb(inp);
 	KASSERT(up != NULL, ("%s: udpcb NULL", __func__));
-	if (up->u_flags & UF_ESPINUDP_ALL) {	/* IPSec UDP encaps. */
-		n = udp4_espdecap(inp, n, off);
-		if (n == NULL)				/* Consumed. */
-			return (0);
+	if (up->u_flags & UF_ESPINUDP) {/* IPSec UDP encaps. */
+		if (udp_ipsec_input(n, off, AF_INET) != 0)
+			return (0);	/* Consumed. */
 	}
-#endif /* IPSEC_NAT_T */
 #endif /* IPSEC */
 #ifdef MAC
 	if (mac_inpcb_check_deliver(inp, n) != 0) {
@@ -1021,42 +1008,11 @@ udp_ctloutput(struct socket *so, struct 
 	switch (sopt->sopt_dir) {
 	case SOPT_SET:
 		switch (sopt->sopt_name) {
+#ifdef IPSEC
 		case UDP_ENCAP:
-			INP_WUNLOCK(inp);
-			error = sooptcopyin(sopt, &optval, sizeof optval,
-					    sizeof optval);
-			if (error)
-				break;
-			inp = sotoinpcb(so);
-			KASSERT(inp != NULL, ("%s: inp == NULL", __func__));
-			INP_WLOCK(inp);
-#ifdef IPSEC_NAT_T
-			up = intoudpcb(inp);
-			KASSERT(up != NULL, ("%s: up == NULL", __func__));
-#endif
-			switch (optval) {
-			case 0:
-				/* Clear all UDP encap. */
-#ifdef IPSEC_NAT_T
-				up->u_flags &= ~UF_ESPINUDP_ALL;
-#endif
-				break;
-#ifdef IPSEC_NAT_T
-			case UDP_ENCAP_ESPINUDP:
-			case UDP_ENCAP_ESPINUDP_NON_IKE:
-				up->u_flags &= ~UF_ESPINUDP_ALL;
-				if (optval == UDP_ENCAP_ESPINUDP)
-					up->u_flags |= UF_ESPINUDP;
-				else if (optval == UDP_ENCAP_ESPINUDP_NON_IKE)
-					up->u_flags |= UF_ESPINUDP_NON_IKE;
-				break;
-#endif
-			default:
-				error = EINVAL;
-				break;
-			}
-			INP_WUNLOCK(inp);
+			error = udp_ipsec_pcbctl(inp, sopt);
 			break;
+#endif
 		case UDPLITE_SEND_CSCOV:
 		case UDPLITE_RECV_CSCOV:
 			if (!isudplite) {
@@ -1093,13 +1049,9 @@ udp_ctloutput(struct socket *so, struct 
 		break;
 	case SOPT_GET:
 		switch (sopt->sopt_name) {
-#ifdef IPSEC_NAT_T
+#ifdef IPSEC
 		case UDP_ENCAP:
-			up = intoudpcb(inp);
-			KASSERT(up != NULL, ("%s: up == NULL", __func__));
-			optval = up->u_flags & UF_ESPINUDP_ALL;
-			INP_WUNLOCK(inp);
-			error = sooptcopyout(sopt, &optval, sizeof optval);
+			error = udp_ipsec_pcbctl(inp, sopt);
 			break;
 #endif
 		case UDPLITE_SEND_CSCOV:
@@ -1584,142 +1536,6 @@ release:
 	return (error);
 }
 
-
-#if defined(IPSEC) && defined(IPSEC_NAT_T)
-/*
- * Potentially decap ESP in UDP frame.  Check for an ESP header
- * and optional marker; if present, strip the UDP header and
- * push the result through IPSec.
- *
- * Returns mbuf to be processed (potentially re-allocated) or
- * NULL if consumed and/or processed.
- */
-static struct mbuf *
-udp4_espdecap(struct inpcb *inp, struct mbuf *m, int off)
-{
-	size_t minlen, payload, skip, iphlen;
-	caddr_t data;
-	struct udpcb *up;
-	struct m_tag *tag;
-	struct udphdr *udphdr;
-	struct ip *ip;
-
-	INP_RLOCK_ASSERT(inp);
-
-	/* 
-	 * Pull up data so the longest case is contiguous:
-	 *    IP/UDP hdr + non ESP marker + ESP hdr.
-	 */
-	minlen = off + sizeof(uint64_t) + sizeof(struct esp);
-	if (minlen > m->m_pkthdr.len)
-		minlen = m->m_pkthdr.len;
-	if ((m = m_pullup(m, minlen)) == NULL) {
-		IPSECSTAT_INC(ips_in_inval);
-		return (NULL);		/* Bypass caller processing. */
-	}
-	data = mtod(m, caddr_t);	/* Points to ip header. */
-	payload = m->m_len - off;	/* Size of payload. */
-
-	if (payload == 1 && data[off] == '\xff')
-		return (m);		/* NB: keepalive packet, no decap. */
-
-	up = intoudpcb(inp);
-	KASSERT(up != NULL, ("%s: udpcb NULL", __func__));
-	KASSERT((up->u_flags & UF_ESPINUDP_ALL) != 0,
-	    ("u_flags 0x%x", up->u_flags));
-
-	/* 
-	 * Check that the payload is large enough to hold an
-	 * ESP header and compute the amount of data to remove.
-	 *
-	 * NB: the caller has already done a pullup for us.
-	 * XXX can we assume alignment and eliminate bcopys?
-	 */
-	if (up->u_flags & UF_ESPINUDP_NON_IKE) {
-		/*
-		 * draft-ietf-ipsec-nat-t-ike-0[01].txt and
-		 * draft-ietf-ipsec-udp-encaps-(00/)01.txt, ignoring
-		 * possible AH mode non-IKE marker+non-ESP marker
-		 * from draft-ietf-ipsec-udp-encaps-00.txt.
-		 */
-		uint64_t marker;
-
-		if (payload <= sizeof(uint64_t) + sizeof(struct esp))
-			return (m);	/* NB: no decap. */
-		bcopy(data + off, &marker, sizeof(uint64_t));
-		if (marker != 0)	/* Non-IKE marker. */
-			return (m);	/* NB: no decap. */
-		skip = sizeof(uint64_t) + sizeof(struct udphdr);
-	} else {
-		uint32_t spi;
-
-		if (payload <= sizeof(struct esp)) {
-			IPSECSTAT_INC(ips_in_inval);
-			m_freem(m);
-			return (NULL);	/* Discard. */
-		}
-		bcopy(data + off, &spi, sizeof(uint32_t));
-		if (spi == 0)		/* Non-ESP marker. */
-			return (m);	/* NB: no decap. */
-		skip = sizeof(struct udphdr);
-	}
-
-	/*
-	 * Setup a PACKET_TAG_IPSEC_NAT_T_PORT tag to remember
-	 * the UDP ports. This is required if we want to select
-	 * the right SPD for multiple hosts behind same NAT.
-	 *
-	 * NB: ports are maintained in network byte order everywhere
-	 *     in the NAT-T code.
-	 */
-	tag = m_tag_get(PACKET_TAG_IPSEC_NAT_T_PORTS,
-		2 * sizeof(uint16_t), M_NOWAIT);
-	if (tag == NULL) {
-		IPSECSTAT_INC(ips_in_nomem);
-		m_freem(m);
-		return (NULL);		/* Discard. */
-	}
-	iphlen = off - sizeof(struct udphdr);
-	udphdr = (struct udphdr *)(data + iphlen);
-	((uint16_t *)(tag + 1))[0] = udphdr->uh_sport;
-	((uint16_t *)(tag + 1))[1] = udphdr->uh_dport;
-	m_tag_prepend(m, tag);
-
-	/*
-	 * Remove the UDP header (and possibly the non ESP marker)
-	 * IP header length is iphlen
-	 * Before:
-	 *   <--- off --->
-	 *   +----+------+-----+
-	 *   | IP |  UDP | ESP |
-	 *   +----+------+-----+
-	 *        <-skip->
-	 * After:
-	 *          +----+-----+
-	 *          | IP | ESP |
-	 *          +----+-----+
-	 *   <-skip->
-	 */
-	ovbcopy(data, data + skip, iphlen);
-	m_adj(m, skip);
-
-	ip = mtod(m, struct ip *);
-	ip->ip_len = htons(ntohs(ip->ip_len) - skip);
-	ip->ip_p = IPPROTO_ESP;
-
-	/*
-	 * We cannot yet update the cksums so clear any
-	 * h/w cksum flags as they are no longer valid.
-	 */
-	if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID)
-		m->m_pkthdr.csum_flags &= ~(CSUM_DATA_VALID|CSUM_PSEUDO_HDR);
-
-	(void) ipsec_common_input(m, iphlen, offsetof(struct ip, ip_p),
-				AF_INET, ip->ip_p);
-	return (NULL);			/* NB: consumed, bypass processing. */
-}
-#endif /* defined(IPSEC) && defined(IPSEC_NAT_T) */
-
 static void
 udp_abort(struct socket *so)
 {

Modified: projects/ipsec/sys/netipsec/ipsec.c
==============================================================================
--- projects/ipsec/sys/netipsec/ipsec.c	Sat Dec 10 13:30:18 2016	(r309807)
+++ projects/ipsec/sys/netipsec/ipsec.c	Sat Dec 10 14:20:51 2016	(r309808)
@@ -136,11 +136,17 @@ static VNET_DEFINE(struct secpolicy, def
  *  0	take anything
  */
 VNET_DEFINE(int, crypto_support) = CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE;
+/*
+ * TCP/UDP checksum handling policy for transport mode NAT-T (RFC3948)
+ *
+ * 0 - incrementally recompute.
+ * 1 - fully recompute TCP/UDP checksum.
+ * 2 - for UDP reset checksum to zero; for TCP mark csum_flags as valid.
+ */
+VNET_DEFINE(int, natt_cksum_policy) = 0;
 
 FEATURE(ipsec, "Internet Protocol Security (IPsec)");
-#ifdef IPSEC_NAT_T
 FEATURE(ipsec_natt, "UDP Encapsulation of IPsec ESP Packets ('NAT-T')");
-#endif
 
 SYSCTL_DECL(_net_inet_ipsec);
 
@@ -180,7 +186,10 @@ SYSCTL_INT(_net_inet_ipsec, OID_AUTO, cr
 	"Crypto driver selection.");
 SYSCTL_INT(_net_inet_ipsec, OID_AUTO, check_policy_history,
 	CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(check_policy_history), 0,
-	"Use strict check of inbound packets to security policy compliance");
+	"Use strict check of inbound packets to security policy compliance.");
+SYSCTL_INT(_net_inet_ipsec, OID_AUTO, natt_cksum_policy,
+	CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(natt_cksum_policy), 0,
+	"Method to fix TCP/UDP checksum for transport mode IPsec after NAT.");
 SYSCTL_VNET_PCPUSTAT(_net_inet_ipsec, OID_AUTO, ipsecstats, struct ipsecstat,
     ipsec4stat, "IPsec IPv4 statistics.");
 

Modified: projects/ipsec/sys/netipsec/ipsec.h
==============================================================================
--- projects/ipsec/sys/netipsec/ipsec.h	Sat Dec 10 13:30:18 2016	(r309807)
+++ projects/ipsec/sys/netipsec/ipsec.h	Sat Dec 10 14:20:51 2016	(r309808)
@@ -276,6 +276,7 @@ VNET_DECLARE(int, ip4_ipsec_dfbit);
 VNET_DECLARE(int, ip4_ipsec_ecn);
 VNET_DECLARE(int, ip4_esp_randpad);
 VNET_DECLARE(int, crypto_support);
+VNET_DECLARE(int, natt_cksum_policy);
 
 #define	IPSECSTAT_INC(name)	\
     VNET_PCPUSTAT_ADD(struct ipsecstat, ipsec4stat, name, 1)
@@ -288,6 +289,7 @@ VNET_DECLARE(int, crypto_support);
 #define	V_ip4_ipsec_ecn		VNET(ip4_ipsec_ecn)
 #define	V_ip4_esp_randpad	VNET(ip4_esp_randpad)
 #define	V_crypto_support	VNET(crypto_support)
+#define	V_natt_cksum_policy	VNET(natt_cksum_policy)
 
 #define ipseclog(x)	do { if (V_ipsec_debug) log x; } while (0)
 /* for openbsd compatibility */
@@ -320,6 +322,11 @@ int tcp_ipsec_pcbctl(struct inpcb *, str
 int tcp_ipsec_input(struct mbuf *, struct tcphdr *, u_char *);
 int tcp_ipsec_output(struct mbuf *, struct tcphdr *, u_char *);
 
+int udp_ipsec_pcbctl(struct inpcb *, struct sockopt *);
+int udp_ipsec_input(struct mbuf *, int, int);
+void udp_ipsec_adjust_cksum(struct mbuf *, struct secasvar *, int, int);
+int udp_ipsec_output(struct mbuf **, struct secasvar *);
+
 int ipsec_chkreplay(uint32_t, struct secasvar *);
 int ipsec_updatereplay(uint32_t, struct secasvar *);
 int ipsec_updateid(struct secasvar *, uint64_t *, uint64_t *);

Modified: projects/ipsec/sys/netipsec/ipsec_input.c
==============================================================================
--- projects/ipsec/sys/netipsec/ipsec_input.c	Sat Dec 10 13:30:18 2016	(r309807)
+++ projects/ipsec/sys/netipsec/ipsec_input.c	Sat Dec 10 14:20:51 2016	(r309808)
@@ -122,11 +122,6 @@ ipsec_common_input(struct mbuf *m, int s
 	struct secasvar *sav;
 	uint32_t spi;
 	int error;
-#ifdef INET
-#ifdef IPSEC_NAT_T
-	struct m_tag *tag;
-#endif
-#endif
 
 	IPSEC_ISTAT(sproto, input);
 
@@ -178,12 +173,6 @@ ipsec_common_input(struct mbuf *m, int s
 		m_copydata(m, offsetof(struct ip, ip_dst),
 		    sizeof(struct in_addr),
 		    (caddr_t) &dst_address.sin.sin_addr);
-#ifdef IPSEC_NAT_T
-		/* Find the source port for NAT-T; see udp*_espdecap. */
-		tag = m_tag_find(m, PACKET_TAG_IPSEC_NAT_T_PORTS, NULL);
-		if (tag != NULL)
-			dst_address.sin.sin_port = ((u_int16_t *)(tag + 1))[1];
-#endif /* IPSEC_NAT_T */
 		break;
 #endif /* INET */
 #ifdef INET6
@@ -336,7 +325,6 @@ ipsec4_common_input_cb(struct mbuf *m, s
 	if (skip != 0) {
 		/*
 		 * Fix IPv4 header
-		 * XXXGL: do we need this entire block?
 		 */
 		if (m->m_len < skip && (m = m_pullup(m, skip)) == NULL) {
 			DPRINTF(("%s: processing failed for SA %s/%08lx\n",
@@ -355,6 +343,14 @@ ipsec4_common_input_cb(struct mbuf *m, s
 		ip = mtod(m, struct ip *);
 	}
 	prot = ip->ip_p;
+	/*
+	 * Check that we have NAT-T enabled and apply transport mode
+	 * decapsulation NAT procedure (RFC3948).
+	 * Do this before invoking into the PFIL.
+	 */
+	if (sav->natt != NULL &&
+	    (prot == IPPROTO_UDP || prot == IPPROTO_TCP))
+		udp_ipsec_adjust_cksum(m, sav, prot, skip);
 
 	IPSEC_INIT_CTX(&ctx, &m, sav, AF_INET, IPSEC_ENC_BEFORE);
 	if ((error = ipsec_run_hhooks(&ctx, HHOOK_TYPE_IPSEC_IN)) != 0)

Modified: projects/ipsec/sys/netipsec/ipsec_output.c
==============================================================================
--- projects/ipsec/sys/netipsec/ipsec_output.c	Sat Dec 10 13:30:18 2016	(r309807)
+++ projects/ipsec/sys/netipsec/ipsec_output.c	Sat Dec 10 14:20:51 2016	(r309808)
@@ -217,7 +217,9 @@ ipsec4_perform_request(struct mbuf *m, s
 		}
 		goto bad;
 	}
-
+	/*
+	 * XXXAE: most likely ip_sum at this point is wrong.
+	 */
 	IPSEC_INIT_CTX(&ctx, &m, sav, AF_INET, IPSEC_ENC_BEFORE);
 	if ((error = ipsec_run_hhooks(&ctx, HHOOK_TYPE_IPSEC_OUT)) != 0)
 		goto bad;
@@ -614,69 +616,25 @@ ipsec_process_done(struct mbuf *m, struc
 
 	key_freesp(&sp), sp = NULL;	/* Release reference to SP */
 	/*
+	 * Do UDP encapsulation if SA requires it.
+	 */
+	if (sav->natt != NULL) {
+		error = udp_ipsec_output(&m, sav);
+		if (error != 0)
+			goto bad;
+	}
+	/*
 	 * We're done with IPsec processing, transmit the packet using the
 	 * appropriate network protocol (IP or IPv6).
 	 */
 	switch (saidx->dst.sa.sa_family) {
 #ifdef INET
 	case AF_INET:
-#ifdef IPSEC_NAT_T
-		/*
-		 * If NAT-T is enabled, now that all IPsec processing is done
-		 * insert UDP encapsulation header after IP header.
-		 */
-		if (sav->natt_type) {
-			struct ip *ip = mtod(m, struct ip *);
-			const int hlen = (ip->ip_hl << 2);
-			int size, off;
-			struct mbuf *mi;
-			struct udphdr *udp;
-
-			size = sizeof(struct udphdr);
-			if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE) {
-				/*
-				 * draft-ietf-ipsec-nat-t-ike-0[01].txt and
-				 * draft-ietf-ipsec-udp-encaps-(00/)01.txt,
-				 * ignoring possible AH mode
-				 * non-IKE marker + non-ESP marker
-				 * from draft-ietf-ipsec-udp-encaps-00.txt.
-				 */
-				size += sizeof(u_int64_t);
-			}
-			mi = m_makespace(m, hlen, size, &off);
-			if (mi == NULL) {
-				DPRINTF(("%s: m_makespace for udphdr failed\n",
-				    __func__));
-				error = ENOBUFS;
-				goto bad;
-			}
-
-			udp = (struct udphdr *)(mtod(mi, caddr_t) + off);
-			if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE)
-				udp->uh_sport = htons(UDP_ENCAP_ESPINUDP_PORT);
-			else
-				udp->uh_sport = key_portfromsaddr(
-				    &sav->sah->saidx.src.sa);
-			udp->uh_dport = key_portfromsaddr(
-			    &sav->sah->saidx.dst.sa);
-			udp->uh_sum = 0;
-			udp->uh_ulen = htons(m->m_pkthdr.len - hlen);
-			ip->ip_len = htons(m->m_pkthdr.len);
-			ip->ip_p = IPPROTO_UDP;
-
-			if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE)
-				*(u_int64_t *)(udp + 1) = 0;
-		}
-#endif /* IPSEC_NAT_T */
 		key_freesav(&sav);
 		return ip_output(m, NULL, NULL, IP_RAWOUTPUT, NULL, NULL);
 #endif /* INET */
 #ifdef INET6
 	case AF_INET6:
-		/*
-		 * We don't need massage, IPv6 header fields are always in
-		 * net endian.
-		 */
 		key_freesav(&sav);
 		return ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
 #endif /* INET6 */

Modified: projects/ipsec/sys/netipsec/key.c
==============================================================================
--- projects/ipsec/sys/netipsec/key.c	Sat Dec 10 13:30:18 2016	(r309807)
+++ projects/ipsec/sys/netipsec/key.c	Sat Dec 10 14:20:51 2016	(r309808)
@@ -70,6 +70,7 @@
 #include <netinet/in_systm.h>
 #include <netinet/ip.h>
 #include <netinet/in_var.h>
+#include <netinet/udp.h>
 
 #ifdef INET6
 #include <netinet/ip6.h>
@@ -89,6 +90,7 @@
 #endif
 
 #include <netipsec/xform.h>
+#include <machine/in_cksum.h>
 #include <machine/stdarg.h>
 
 /* randomness */
@@ -468,6 +470,8 @@ do { \
 	(idx)->reqid = (r);                                                  \
 	bcopy((s), &(idx)->src, ((const struct sockaddr *)(s))->sa_len);     \
 	bcopy((d), &(idx)->dst, ((const struct sockaddr *)(d))->sa_len);     \
+	key_porttosaddr(&(idx)->src.sa, 0);				     \
+	key_porttosaddr(&(idx)->dst.sa, 0);				     \
 } while (0)
 
 /* key statistics */
@@ -529,10 +533,8 @@ static struct mbuf *key_setsadbmsg(u_int
 static struct mbuf *key_setsadbsa(struct secasvar *);
 static struct mbuf *key_setsadbaddr(u_int16_t,
 	const struct sockaddr *, u_int8_t, u_int16_t);
-#ifdef IPSEC_NAT_T
 static struct mbuf *key_setsadbxport(u_int16_t, u_int16_t);
 static struct mbuf *key_setsadbxtype(u_int16_t);
-#endif
 static struct mbuf *key_setsadbxsa2(u_int8_t, u_int32_t, u_int32_t);
 static struct mbuf *key_setsadbxpolicy(u_int16_t, u_int8_t,
 	u_int32_t, u_int32_t);
@@ -894,13 +896,11 @@ key_allocsa(union sockaddr_union *dst, u
 {
 	SAHTREE_RLOCK_TRACKER;
 	struct secasvar *sav;
-	int chkport;
 
 	IPSEC_ASSERT(proto == IPPROTO_ESP || proto == IPPROTO_AH ||
 	    proto == IPPROTO_IPCOMP, ("unexpected security protocol %u",
 	    proto));
 
-	chkport = 0;
 	SAHTREE_RLOCK();
 	LIST_FOREACH(sav, SAVHASH_HASH(spi), spihash) {
 		if (sav->spi == spi)
@@ -911,21 +911,10 @@ key_allocsa(union sockaddr_union *dst, u
 	 * impossible to have SPI duplicates in the SAVHASH.
 	 */
 	if (sav != NULL) {
-#ifdef IPSEC_NAT_T
-		/*
-		 * Really only check ports when this is a NAT-T
-		 * SA.  Otherwise other lookups providing ports
-		 * might suffer.
-		 */
-		chkport = (sav->natt_type != 0 &&
-		    dst->sa.sa_family == AF_INET &&
-		    dst->sa.sa_len == sizeof(struct sockaddr_in) &&
-		    dst->sin.sin_port != 0);
-#endif
 		if (sav->state != SADB_SASTATE_LARVAL &&
 		    sav->sah->saidx.proto == proto &&
-		    key_sockaddrcmp(&dst->sa, &sav->sah->saidx.dst.sa,
-			chkport) == 0)
+		    key_sockaddrcmp(&dst->sa,
+			&sav->sah->saidx.dst.sa, 0) == 0)
 			SAV_ADDREF(sav);
 		else
 			sav = NULL;
@@ -1718,11 +1707,6 @@ key_spdadd(struct socket *so, struct mbu
 	dst0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_DST];
 	xpl0 = (struct sadb_x_policy *)mhp->ext[SADB_X_EXT_POLICY];
 
-	/*
-	 * Note: do not parse SADB_X_EXT_NAT_T_* here:
-	 * we are processing traffic endpoints.
-	 */
-
 	/* check the direciton */
 	switch (xpl0->sadb_x_policy_dir) {
 	case IPSEC_DIR_INBOUND:
@@ -1810,11 +1794,6 @@ key_spdadd(struct socket *so, struct mbu
 	struct sadb_msg *newmsg;
 	int off;
 
-	/*
-	 * Note: do not send SADB_X_EXT_NAT_T_* here:
-	 * we are sending traffic endpoints.
-	 */
-
 	/* create new sadb_msg to reply. */
 	if (lft) {
 		n = key_gather_mbuf(m, mhp, 2, 5, SADB_EXT_RESERVED,
@@ -1952,12 +1931,6 @@ key_spddelete(struct socket *so, struct 
 		ipseclog((LOG_DEBUG, "%s: invalid policy type.\n", __func__));
 		return key_senderror(so, m, EINVAL);
 	}
-
-	/*
-	 * Note: do not parse SADB_X_EXT_NAT_T_* here:
-	 * we are processing traffic endpoints.
-	 */
-
 	if (key_checksockaddrs((struct sockaddr *)(src0 + 1),
 	    (struct sockaddr *)(dst0 + 1)) != 0 ||
 	    src0->sadb_address_proto != dst0->sadb_address_proto) {
@@ -1992,11 +1965,6 @@ key_spddelete(struct socket *so, struct 
 	struct mbuf *n;
 	struct sadb_msg *newmsg;
 
-	/*
-	 * Note: do not send SADB_X_EXT_NAT_T_* here:
-	 * we are sending traffic endpoints.
-	 */
-
 	/* create new sadb_msg to reply. */
 	n = key_gather_mbuf(m, mhp, 1, 4, SADB_EXT_RESERVED,
 	    SADB_X_EXT_POLICY, SADB_EXT_ADDRESS_SRC, SADB_EXT_ADDRESS_DST);
@@ -2372,10 +2340,6 @@ key_setdumpsp(struct secpolicy *sp, u_in
 		goto fail;
 	result = m;
 
-	/*
-	 * Note: do not send SADB_X_EXT_NAT_T_* here:
-	 * we are sending traffic endpoints.
-	 */
 	m = key_setsadbaddr(SADB_EXT_ADDRESS_SRC,
 	    &sp->spidx.src.sa, sp->spidx.prefs,
 	    sp->spidx.ul_proto);
@@ -2514,11 +2478,6 @@ key_spdexpire(struct secpolicy *sp)
 	lt->sadb_lifetime_usetime = sp->validtime;
 	m_cat(result, m);
 
-	/*
-	 * Note: do not send SADB_X_EXT_NAT_T_* here:
-	 * we are sending traffic endpoints.
-	 */
-
 	/* set sadb_address for source */
 	m = key_setsadbaddr(SADB_EXT_ADDRESS_SRC,
 	    &sp->spidx.src.sa,
@@ -2811,6 +2770,10 @@ key_cleansav(struct secasvar *sav)
 		free(sav->key_enc, M_IPSEC_MISC);
 		sav->key_enc = NULL;
 	}
+	if (sav->natt != NULL) {
+		free(sav->natt, M_IPSEC_MISC);
+		sav->natt = NULL;
+	}
 	if (sav->replay != NULL) {
 		free(sav->replay, M_IPSEC_MISC);
 		sav->replay = NULL;
@@ -3016,10 +2979,6 @@ key_setsaval(struct secasvar *sav, const
 	if (error != 0)
 		goto fail;
 
-	error = key_setnatt(sav, mhp);
-	if (error != 0)
-		goto fail;
-
 	/* SA */
 	if (!SADB_CHECKHDR(mhp, SADB_EXT_SA)) {
 		if (SADB_CHECKLEN(mhp, SADB_EXT_SA)) {
@@ -3194,6 +3153,11 @@ key_setsaval(struct secasvar *sav, const
 		goto fail;
 	}
 
+	/* Handle NAT-T headers */
+	error = key_setnatt(sav, mhp);
+	if (error != 0)
+		goto fail;
+
 	/* Initialize lifetime for CURRENT */
 	sav->firstused = 0;
 	sav->created = time_second;
@@ -3224,12 +3188,10 @@ key_setdumpsa(struct secasvar *sav, uint
 		SADB_EXT_KEY_AUTH, SADB_EXT_KEY_ENCRYPT,
 		SADB_EXT_IDENTITY_SRC, SADB_EXT_IDENTITY_DST,
 		SADB_EXT_SENSITIVITY,
-#ifdef IPSEC_NAT_T
 		SADB_X_EXT_NAT_T_TYPE,
 		SADB_X_EXT_NAT_T_SPORT, SADB_X_EXT_NAT_T_DPORT,
 		SADB_X_EXT_NAT_T_OAI, SADB_X_EXT_NAT_T_OAR,
 		SADB_X_EXT_NAT_T_FRAG,
-#endif
 	};
 
 	m = key_setsadbmsg(type, 0, satype, seq, pid, sav->refcnt);
@@ -3316,35 +3278,53 @@ key_setdumpsa(struct secasvar *sav, uint
 				goto fail;
 			break;
 
-#ifdef IPSEC_NAT_T
 		case SADB_X_EXT_NAT_T_TYPE:
-			m = key_setsadbxtype(sav->natt_type);
+			if (sav->natt == NULL)
+				continue;
+			m = key_setsadbxtype(UDP_ENCAP_ESPINUDP);
 			if (!m)
 				goto fail;
 			break;
 
 		case SADB_X_EXT_NAT_T_DPORT:
-			m = key_setsadbxport(
-			    key_portfromsaddr(&sav->sah->saidx.dst.sa),
+			if (sav->natt == NULL)
+				continue;
+			m = key_setsadbxport(sav->natt->dport,
 			    SADB_X_EXT_NAT_T_DPORT);
 			if (!m)
 				goto fail;
 			break;
 
 		case SADB_X_EXT_NAT_T_SPORT:
-			m = key_setsadbxport(
-			    key_portfromsaddr(&sav->sah->saidx.src.sa),
+			if (sav->natt == NULL)
+				continue;
+			m = key_setsadbxport(sav->natt->sport,
 			    SADB_X_EXT_NAT_T_SPORT);
 			if (!m)
 				goto fail;
 			break;
 
 		case SADB_X_EXT_NAT_T_OAI:
+			if (sav->natt == NULL ||
+			    (sav->natt->flags & IPSEC_NATT_F_OAI) == 0)
+				continue;
+			m = key_setsadbaddr(SADB_X_EXT_NAT_T_OAI,
+			    &sav->natt->oai.sa, FULLMASK, IPSEC_ULPROTO_ANY);
+			if (!m)
+				goto fail;
+			break;
 		case SADB_X_EXT_NAT_T_OAR:
+			if (sav->natt == NULL ||
+			    (sav->natt->flags & IPSEC_NATT_F_OAR) == 0)
+				continue;
+			m = key_setsadbaddr(SADB_X_EXT_NAT_T_OAR,
+			    &sav->natt->oar.sa, FULLMASK, IPSEC_ULPROTO_ANY);
+			if (!m)
+				goto fail;
+			break;
 		case SADB_X_EXT_NAT_T_FRAG:
 			/* We do not (yet) support those. */
 			continue;
-#endif
 
 		case SADB_EXT_ADDRESS_PROXY:
 		case SADB_EXT_IDENTITY_SRC:
@@ -3532,7 +3512,6 @@ key_setsadbxsa2(u_int8_t mode, u_int32_t
 	return m;
 }
 
-#ifdef IPSEC_NAT_T
 /*
  * Set a type in sadb_x_nat_t_type.
  */
@@ -3586,7 +3565,6 @@ key_setsadbxport(u_int16_t port, u_int16
 
 	return (m);
 }
-#endif /* IPSEC_NAT_T */
 
 /*
  * Get port from sockaddr. Port is in network byte order.
@@ -3735,7 +3713,6 @@ static int
 key_cmpsaidx(const struct secasindex *saidx0, const struct secasindex *saidx1,
     int flag)
 {
-	int chkport = 0;
 
 	/* sanity */
 	if (saidx0 == NULL && saidx1 == NULL)
@@ -3752,19 +3729,21 @@ key_cmpsaidx(const struct secasindex *sa
 			return 0;
 		if (saidx0->reqid != saidx1->reqid)
 			return 0;
-		if (bcmp(&saidx0->src, &saidx1->src, saidx0->src.sa.sa_len) != 0 ||
-		    bcmp(&saidx0->dst, &saidx1->dst, saidx0->dst.sa.sa_len) != 0)
+		if (bcmp(&saidx0->src, &saidx1->src,
+		    saidx0->src.sa.sa_len) != 0 ||
+		    bcmp(&saidx0->dst, &saidx1->dst,
+		    saidx0->dst.sa.sa_len) != 0)
 			return 0;
 	} else {
 
 		/* CMP_MODE_REQID, CMP_REQID, CMP_HEAD */
-		if (flag == CMP_MODE_REQID
-		  ||flag == CMP_REQID) {
+		if (flag == CMP_MODE_REQID || flag == CMP_REQID) {
 			/*
 			 * If reqid of SPD is non-zero, unique SA is required.
 			 * The result must be of same reqid in this case.
 			 */
-			if (saidx1->reqid != 0 && saidx0->reqid != saidx1->reqid)
+			if (saidx1->reqid != 0 &&
+			    saidx0->reqid != saidx1->reqid)
 				return 0;
 		}
 
@@ -3774,29 +3753,10 @@ key_cmpsaidx(const struct secasindex *sa
 				return 0;
 		}
 
-#ifdef IPSEC_NAT_T
-		/*
-		 * If NAT-T is enabled, check ports for tunnel mode.
-		 * Do not check ports if they are set to zero in the SPD.
-		 * Also do not do it for native transport mode, as there
-		 * is no port information available in the SP.
-		 */
-		if ((saidx1->mode == IPSEC_MODE_TUNNEL ||
-		     (saidx1->mode == IPSEC_MODE_TRANSPORT &&
-		      saidx1->proto == IPPROTO_ESP)) &&
-		    saidx1->src.sa.sa_family == AF_INET &&
-		    saidx1->dst.sa.sa_family == AF_INET &&
-		    ((const struct sockaddr_in *)(&saidx1->src))->sin_port &&
-		    ((const struct sockaddr_in *)(&saidx1->dst))->sin_port)
-			chkport = 1;
-#endif /* IPSEC_NAT_T */
-
-		if (key_sockaddrcmp(&saidx0->src.sa, &saidx1->src.sa, chkport) != 0) {
+		if (key_sockaddrcmp(&saidx0->src.sa, &saidx1->src.sa, 0) != 0)
 			return 0;
-		}
-		if (key_sockaddrcmp(&saidx0->dst.sa, &saidx1->dst.sa, chkport) != 0) {
+		if (key_sockaddrcmp(&saidx0->dst.sa, &saidx1->dst.sa, 0) != 0)
 			return 0;
-		}
 	}
 
 	return 1;
@@ -4543,12 +4503,6 @@ key_getspi(struct socket *so, struct mbu
 		goto fail;
 	}
 	KEY_SETSECASIDX(proto, mode, reqid, src0 + 1, dst0 + 1, &saidx);
-	/*
-	 * Make sure the port numbers are zero.
-	 * In case of NAT-T we will update them later if needed.
-	 */
-	key_porttosaddr(&saidx.src.sa, 0);
-	key_porttosaddr(&saidx.dst.sa, 0);
 
 	/* SPI allocation */
 	spi = key_do_getnewspi(
@@ -4874,13 +4828,6 @@ key_update(struct socket *so, struct mbu
 		return key_senderror(so, m, error);
 	}
 	KEY_SETSECASIDX(proto, mode, reqid, src0 + 1, dst0 + 1, &saidx);
-	/*
-	 * Make sure the port numbers are zero.
-	 * In case of NAT-T we will update them later if needed.
-	 */
-	key_porttosaddr(&saidx.src.sa, 0);
-	key_porttosaddr(&saidx.dst.sa, 0);
-
 	sav = key_getsavbyspi(sa0->sadb_sa_spi);
 	if (sav == NULL) {
 		ipseclog((LOG_DEBUG, "%s: no SA found for SPI %u\n",
@@ -4898,10 +4845,7 @@ key_update(struct socket *so, struct mbu
 		key_freesav(&sav);
 		return key_senderror(so, m, EINVAL);
 	}
-	/*
-	 * XXXAE: saidx should match with SA. Use CMP_MODE_REQID since we
-	 * didn't set ports for NAT-T yet and exactly match may fail.
-	 */
+	/* saidx should match with SA. */
 	if (key_cmpsaidx(&sav->sah->saidx, &saidx, CMP_MODE_REQID) == 0) {
 		ipseclog((LOG_DEBUG, "%s: saidx mismatched for SPI %u",
 		    __func__, ntohl(sav->spi)));
@@ -5088,17 +5032,11 @@ key_add(struct socket *so, struct mbuf *
 		return key_senderror(so, m, error);
 	}
 	KEY_SETSECASIDX(proto, mode, reqid, src0 + 1, dst0 + 1, &saidx);
-	/*
-	 * Make sure the port numbers are zero.
-	 * In case of NAT-T we will update them later if needed.
-	 */
-	key_porttosaddr(&saidx.src.sa, 0);
-	key_porttosaddr(&saidx.dst.sa, 0);
-
 	spi = sa0->sadb_sa_spi;
 	/*
-	 * XXX: For TCP-MD5 SAs we don't use SPI.
-	 * Check the uniqueness using secasindex.
+	 * For TCP-MD5 SAs we don't use SPI. Check the uniqueness using
+	 * secasindex.
+	 * XXXAE: IPComp seems also doesn't use SPI.
 	 */
 	if (proto == IPPROTO_TCP) {
 		sav = key_getsav_tcpmd5(&saidx, &spi);
@@ -5151,12 +5089,46 @@ key_add(struct socket *so, struct mbuf *
     }
 }
 
+/*
+ * NAT-T support.
+ * IKEd may request the use ESP in UDP encapsulation when it detects the
+ * presence of NAT. It uses NAT-T extension headers for such SAs to specify
+ * parameters needed for encapsulation and decapsulation. These PF_KEY
+ * extension headers are not standardized, so this comment addresses our
+ * implementation.
+ * SADB_X_EXT_NAT_T_TYPE specifies type of encapsulation, we support only
+ * UDP_ENCAP_ESPINUDP as described in RFC3948.
+ * SADB_X_EXT_NAT_T_SPORT/DPORT specifies source and destination ports for
+ * UDP header. We use these ports in UDP encapsulation procedure, also we
+ * can check them in UDP decapsulation procedure.
+ * SADB_X_EXT_NAT_T_OA[IR] specifies original address of initiator or
+ * responder. These addresses can be used for transport mode to adjust
+ * checksum after decapsulation and decryption. Since original IP addresses
+ * used by peer usually different (we detected presence of NAT), TCP/UDP
+ * pseudo header checksum and IP header checksum was calculated using original
+ * addresses. After decapsulation and decryption we need to adjust checksum
+ * to have correct datagram.
+ *
+ * We expect presence of NAT-T extension headers only in SADB_ADD and
+ * SADB_UPDATE messages. We report NAT-T extension headers in replies
+ * to SADB_ADD, SADB_UPDATE, SADB_GET, and SADB_DUMP messages.
+ */
 static int
 key_setnatt(struct secasvar *sav, const struct sadb_msghdr *mhp)
 {
-#ifdef IPSEC_NAT_T
-	struct sadb_x_nat_t_port *sport, *dport;
+	struct sadb_x_nat_t_port *port;
 	struct sadb_x_nat_t_type *type;
+	struct sadb_address *oai, *oar;
+	struct sockaddr *sa;
+	uint32_t addr;
+	uint16_t cksum;
+
+	IPSEC_ASSERT(sav->natt == NULL, ("natt is already initialized"));
+	/*
+	 * Ignore NAT-T headers if sproto isn't ESP.
+	 */
+	if (sav->sah->saidx.proto != IPPROTO_ESP)
+		return (0);
 
 	if (!SADB_CHECKHDR(mhp, SADB_X_EXT_NAT_T_TYPE) &&
 	    !SADB_CHECKHDR(mhp, SADB_X_EXT_NAT_T_SPORT) &&
@@ -5169,53 +5141,122 @@ key_setnatt(struct secasvar *sav, const 
 			    __func__));
 			return (EINVAL);
 		}
-
-		type = (struct sadb_x_nat_t_type *)
-		    mhp->ext[SADB_X_EXT_NAT_T_TYPE];
-		sport = (struct sadb_x_nat_t_port *)
-		    mhp->ext[SADB_X_EXT_NAT_T_SPORT];
-		dport = (struct sadb_x_nat_t_port *)
-		    mhp->ext[SADB_X_EXT_NAT_T_DPORT];
-
-		sav->natt_type = type->sadb_x_nat_t_type_type;
-		key_porttosaddr(&sav->sah->saidx.src.sa,
-		    sport->sadb_x_nat_t_port_port);
-		key_porttosaddr(&sav->sah->saidx.dst.sa,
-		    dport->sadb_x_nat_t_port_port);
 	} else
 		return (0);
-	if (!SADB_CHECKHDR(mhp, SADB_X_EXT_NAT_T_OAI) &&
-	    !SADB_CHECKHDR(mhp, SADB_X_EXT_NAT_T_OAR)) {
-		if (SADB_CHECKLEN(mhp, SADB_X_EXT_NAT_T_OAI) ||
-		    SADB_CHECKLEN(mhp, SADB_X_EXT_NAT_T_OAR)) {
+
+	type = (struct sadb_x_nat_t_type *)mhp->ext[SADB_X_EXT_NAT_T_TYPE];
+	if (type->sadb_x_nat_t_type_type != UDP_ENCAP_ESPINUDP) {
+		ipseclog((LOG_DEBUG, "%s: unsupported NAT-T type %u.\n",
+		    __func__, type->sadb_x_nat_t_type_type));
+		return (EINVAL);
+	}
+	/*
+	 * Allocate storage for NAT-T config.
+	 * On error it will be released by key_cleansav().
+	 */
+	sav->natt = malloc(sizeof(struct secnatt), M_IPSEC_MISC,
+	    M_NOWAIT | M_ZERO);
+	if (sav->natt == NULL) {
+		PFKEYSTAT_INC(in_nomem);
+		ipseclog((LOG_DEBUG, "%s: No more memory.\n", __func__));
+		return (ENOBUFS);
+	}
+	port = (struct sadb_x_nat_t_port *)mhp->ext[SADB_X_EXT_NAT_T_SPORT];
+	if (port->sadb_x_nat_t_port_port == 0) {
+		ipseclog((LOG_DEBUG, "%s: invalid NAT-T sport specified.\n",
+		    __func__));
+		return (EINVAL);
+	}
+	sav->natt->sport = port->sadb_x_nat_t_port_port;
+	port = (struct sadb_x_nat_t_port *)mhp->ext[SADB_X_EXT_NAT_T_DPORT];
+	if (port->sadb_x_nat_t_port_port == 0) {
+		ipseclog((LOG_DEBUG, "%s: invalid NAT-T dport specified.\n",
+		    __func__));
+		return (EINVAL);
+	}
+	sav->natt->dport = port->sadb_x_nat_t_port_port;
+
+	/*
+	 * SADB_X_EXT_NAT_T_OAI and SADB_X_EXT_NAT_T_OAR are optional
+	 * and needed only for transport mode IPsec.
+	 * Usually NAT translates only one address, but it is possible,

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201612101420.uBAEKpC3084749>