Where is IPSec NAT-T support?

Norikatsu Shigemura nork at FreeBSD.org
Sat Sep 9 04:32:03 PDT 2006


On Wed, 6 Sep 2006 09:01:35 +0200
VANHULLEBUS Yvan <vanhu_bsd at zeninc.net> wrote:
> > Yes it was a clean RELENG_6_1.
> > >I compiled this on i386 and am64 just a few days ago and everything
> > >was fine.
> > >Perhaps contact me off-list and we'll post a summary once we found the
> > >problem?
> > Maybe it is because I am including FAST_IPSEC?   I have attempted to
> > build and use a NAT-T kernel on atleast 7 attempts now.  Last of which
> > was a couple months ago.
> Actually, I did NOT make the FAST_IPSEC part of the patch.

	Hummmm.... :-)

> Here is probably the good location and the good time for a small
> summary of the patch's state:

	Oh!

> - The public patch (A) works for IPSEC, and should apply on both
>   RELENG_6 and RELENG_6_1 (some minor patching issues may need to be
>   solved by hand, but it's just some indentation changes in the source
>   code between the two versions).
> - This public patch does NOT provide support for multiple peers behind
>   the same NAT device.
> - I have a newer version of the patch (B), against RELENG_6_1, which
>   provides such support for multiples peers behind the same NAT
>   device. I was about to put it in public place when someone raised a
>   discutable implementation choice in the way ipsec-tools and kernel
>   exchange some datas specific to that NAT-T support (I ported it from
>   Manu's work on NetBSD).

	How to get the patch(B)?  I'm interesting new version of the patch.

> - I guessed I would have quickly the time to look at it and to clean
>   it up for both FreeBSD and NetBSD (and perhaps Linux), but I
>   drastically lacked free time those last months.
> - Some FreeBSD developpers already had a look at the patch, and are in
>   contact with me to include it in the kernel, but it has been
>   reported several times for various reasons.
> - FAST_IPSEC support will be quite easy to do when all the other
>   problems will be solved, and I guess Larry Baird will do it if I
>   don't have free time for that quickly.
> As I reported that work several time on the last months, I guess I'll
> publish the actual version of the patch (B) those days, which will
> already solve some problems for most people, then I'll start to do the
> rest of the stuff (FAST_IPSEC and solve kernel/ipsec-tools
> commnication design).

	I'm interesting FAST_IPSEC support:-).

> > The Kernel configuration file that I am trying to build is
> > http://pfsense.com/cgi-bin/cvsweb.cgi/tools/builder_scripts/conf/pfSense.6?rev=1.32
> > with the added options         IPSEC_NAT_T
> > option.
> > Maybe I am overlooking something simple?
> FAST_IPSEC....

	.....

	I made a patch for 6-stable, based on MD5 (freebsd6-natt.diff) =
	5e7bb5a3203c8959928bf910d5498140.  But I didn't compile, yet:-).
-------------- next part --------------
--- sys/conf/options.orig	Sat Sep  2 22:12:08 2006
+++ sys/conf/options	Sat Sep  9 19:44:12 2006
@@ -352,6 +352,7 @@
 INET6			opt_inet6.h
 IPSEC			opt_ipsec.h
 IPSEC_ESP		opt_ipsec.h
+IPSEC_NAT_T		opt_ipsec.h
 IPSEC_DEBUG		opt_ipsec.h
 IPSEC_FILTERGIF		opt_ipsec.h
 FAST_IPSEC		opt_ipsec.h
--- sys/net/pfkeyv2.h.orig	Fri Jan  7 10:45:35 2005
+++ sys/net/pfkeyv2.h	Sat Sep  9 19:46:21 2006
@@ -75,7 +75,8 @@
 #define SADB_X_SPDSETIDX  20
 #define SADB_X_SPDEXPIRE  21
 #define SADB_X_SPDDELETE2 22	/* by policy id */
-#define SADB_MAX          22
+#define SADB_X_NAT_T_NEW_MAPPING 23
+#define SADB_MAX          23
 
 struct sadb_msg {
   u_int8_t sadb_msg_version;
@@ -255,6 +256,25 @@
    */
 };
 
+/* NAT traversal type, see RFC 3948 */
+/* sizeof(struct sadb_x_nat_t_type) == 8 */
+struct sadb_x_nat_t_type {
+  u_int16_t sadb_x_nat_t_type_len;
+  u_int16_t sadb_x_nat_t_type_exttype;
+  u_int8_t sadb_x_nat_t_type_type;
+  u_int8_t sadb_x_nat_t_type_reserved[3];
+};
+
+/* NAT traversal source or destination port */
+/* sizeof(struct sadb_x_nat_t_port) == 8 */
+struct sadb_x_nat_t_port { 
+  u_int16_t sadb_x_nat_t_port_len;
+  u_int16_t sadb_x_nat_t_port_exttype;
+  u_int16_t sadb_x_nat_t_port_port;
+  u_int16_t sadb_x_nat_t_port_reserved;
+};
+
+
 #define SADB_EXT_RESERVED             0
 #define SADB_EXT_SA                   1
 #define SADB_EXT_LIFETIME_CURRENT     2
@@ -275,7 +295,11 @@
 #define SADB_X_EXT_KMPRIVATE          17
 #define SADB_X_EXT_POLICY             18
 #define SADB_X_EXT_SA2                19
-#define SADB_EXT_MAX                  19
+#define SADB_X_EXT_NAT_T_TYPE         20
+#define SADB_X_EXT_NAT_T_SPORT        21
+#define SADB_X_EXT_NAT_T_DPORT        22
+#define SADB_X_EXT_NAT_T_OA           23
+#define SADB_EXT_MAX                  23
 
 #define SADB_SATYPE_UNSPEC	0
 #define SADB_SATYPE_AH		2
--- sys/netinet/in_pcb.h.orig	Mon Aug 21 04:28:43 2006
+++ sys/netinet/in_pcb.h	Sat Sep  9 19:48:02 2006
@@ -298,6 +298,11 @@
 #define	IN6P_RFC2292		0x40000000 /* used RFC2292 API on the socket */
 #define	IN6P_MTU		0x80000000 /* receive path MTU */
 
+/* XXX should move to an UDP control block */
+#define INP_ESPINUDP		0x100	/* ESP over UDP for NAT-T */
+#define INP_ESPINUDP_NON_IKE	0x200	/* ESP over UDP for NAT-T */
+#define INP_ESPINUDP_ALL	(INP_ESPINUDP|INP_ESPINUDP_NON_IKE)
+
 #define	INP_CONTROLOPTS		(INP_RECVOPTS|INP_RECVRETOPTS|INP_RECVDSTADDR|\
 				 INP_RECVIF|INP_RECVTTL|\
 				 IN6P_PKTINFO|IN6P_HOPLIMIT|IN6P_HOPOPTS|\
--- sys/netinet/in_proto.c.orig	Tue Jan  3 17:15:32 2006
+++ sys/netinet/in_proto.c	Sat Sep  9 19:50:09 2006
@@ -122,7 +122,7 @@
 	.pr_flags =		PR_ATOMIC|PR_ADDR,
 	.pr_input =		udp_input,
 	.pr_ctlinput =		udp_ctlinput,
-	.pr_ctloutput =		ip_ctloutput,
+	.pr_ctloutput =		udp_ctloutput,
 	.pr_init =		udp_init,
 	.pr_usrreqs =		&udp_usrreqs
 },
--- sys/netinet/udp.h.orig	Fri Jan  7 10:45:45 2005
+++ sys/netinet/udp.h	Sat Sep  9 19:56:15 2006
@@ -44,4 +44,17 @@
 	u_short	uh_sum;			/* udp checksum */
 };
 
+/* socket options for UDP */
+#define UDP_ENCAP	100
+
+/* 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+ */
+
+/* Default encapsulation port */
+#define UDP_ENCAP_ESPINUDP_PORT		500
+
+/* Maximum UDP fragment size for ESP over UDP */
+#define UDP_ENCAP_ESPINUDP_MAXFRAGLEN	552
+
 #endif
--- sys/netinet/udp_usrreq.c.orig	Tue May 16 16:27:48 2006
+++ sys/netinet/udp_usrreq.c	Sat Sep  9 19:52:13 2006
@@ -86,6 +86,9 @@
 
 #include <machine/in_cksum.h>
 
+#include <netinet6/ipsec.h>
+#include <netinet6/esp.h>
+
 /*
  * UDP protocol implementation.
  * Per RFC 768, August, 1980.
@@ -128,6 +131,11 @@
 static int udp_detach(struct socket *so);
 static	int udp_output(struct inpcb *, struct mbuf *, struct sockaddr *,
 		struct mbuf *, struct thread *);
+#ifdef IPSEC
+#ifdef INET
+static int udp4_espinudp (struct mbuf *, int, struct sockaddr *, struct socket *);
+#endif
+#endif
 
 static void
 udp_zone_change(void *tag)
@@ -464,6 +472,41 @@
 		return;
 	}
 #endif /*IPSEC || FAST_IPSEC*/
+#ifdef IPSEC_NAT_T
+	/* Handle ESP over UDP */
+	if (last->inp_flags & INP_ESPINUDP_ALL) {
+		struct sockaddr_in src;
+		struct sockaddr *sa = (struct sockaddr *)(&src);
+		size_t minlen;
+
+		bzero(&src, sizeof(src));
+		src.sin_family = AF_INET;
+		src.sin_len = sizeof(struct sockaddr_in);
+		bcopy(&ip->ip_src, &src.sin_addr, sizeof(src.sin_addr));
+		src.sin_port = udp_in->sin_port;
+
+		/* 
+		 * Collapse the mbuf chain if the first mbuf is too short
+		 * The longest case is: UDP + non ESP marker + ESP
+		 */
+		minlen = off + sizeof(struct udphdr) + sizeof(u_int64_t) + sizeof(struct esp);
+		if (minlen > n->m_pkthdr.len)
+			minlen = n->m_pkthdr.len;
+
+		if ((n = m_pullup(n, minlen)) == NULL) {
+			printf("udp_append: m_pullup failed\n");
+			m_freem(n);
+			return;
+		}
+
+		if (udp4_espinudp(n, off, sa, last->inp_socket) != 0) {
+			m_freem(n);
+			return;
+		}
+		
+		/* Normal UDP processing will take place */
+	}
+#endif
 #ifdef MAC
 	if (mac_check_inpcb_deliver(last, n) != 0) {
 		m_freem(n);
@@ -702,6 +745,80 @@
     CTLTYPE_OPAQUE|CTLFLAG_RW|CTLFLAG_PRISON, 0, 0,
     udp_getcred, "S,xucred", "Get the xucred of a UDP connection");
 
+
+int
+udp_ctloutput(so, sopt)
+	struct socket *so;
+	struct sockopt *sopt;
+{
+	int error, optval, s;
+	struct inpcb *inp;
+	int family;
+
+	error = 0;
+	family = so->so_proto->pr_domain->dom_family;
+
+	s = splnet();
+	if (sopt->sopt_level != IPPROTO_UDP) {
+#ifdef INET6
+		if (INP_CHECK_SOCKAF(so, AF_INET6))
+			error = ip6_ctloutput(so, sopt);
+		else
+#endif /* INET6 */
+		error = ip_ctloutput(so, sopt);
+		splx(s);
+		return (error);
+	}
+	inp = sotoinpcb(so);
+
+	switch (sopt->sopt_dir) {
+	case SOPT_SET:
+		switch (sopt->sopt_name) {
+			case UDP_ENCAP:
+			error = sooptcopyin(sopt, &optval, sizeof optval,
+					    sizeof optval);
+			if (error)
+				break;
+
+			switch(optval){
+			case 0:
+				inp->inp_flags &= ~INP_ESPINUDP_ALL;
+				break;
+
+			case UDP_ENCAP_ESPINUDP:
+				inp->inp_flags |= INP_ESPINUDP;
+				break;
+				
+			case UDP_ENCAP_ESPINUDP_NON_IKE:
+				inp->inp_flags |= INP_ESPINUDP_NON_IKE;
+				break;
+
+			default:
+				error = EINVAL;
+				goto end;
+				break;
+			}
+			break;
+
+			default:
+			error = ENOPROTOOPT;
+			goto end;
+			break;
+		}
+		break;
+
+	default:
+		error = EINVAL;
+		goto end;
+		break;
+	}	
+	
+end:
+	splx(s);
+	return error;
+}
+
+
 static int
 udp_output(inp, m, addr, control, td)
 	register struct inpcb *inp;
@@ -922,6 +1039,115 @@
 	m_freem(m);
 	return (error);
 }
+
+#ifdef IPSEC
+#ifdef INET
+/*
+ * Returns:
+ * 1 if the packet was processed
+ * 0 if normal UDP processing should take place
+ */
+static int
+udp4_espinudp(m, off, src, so)
+	struct mbuf *m;
+	int off;
+	struct sockaddr *src;
+	struct socket *so;
+{
+	size_t len;
+	caddr_t data;
+	struct inpcb *inp;
+	size_t skip = 0;
+	size_t minlen;
+	size_t iphdrlen;
+	struct ip *ip;
+	struct mbuf *n;
+
+	/* 
+	 * Cannot collapse the mbuf chain here, must have been done in
+	 * calling function
+	 * The longest case is: UDP + non ESP marker + ESP
+	 */
+	minlen = off + sizeof(u_int64_t) + sizeof(struct esp);
+	if (minlen > m->m_pkthdr.len)
+		minlen = m->m_pkthdr.len;
+
+	if (m->m_len < minlen)
+		return 0;
+
+	len = m->m_len - off;	
+	data = mtod(m, caddr_t) + off;
+	inp = sotoinpcb(so);
+
+	/* Ignore keepalive packets */
+	if ((len == 1) && (data[0] == '\xff')) {
+		return 1;
+	}
+
+	/* 
+	 * Check that the payload is long enough to hold 
+	 * an ESP header and compute the length of encapsulation
+	 * header to remove 
+	 */
+	if (inp->inp_flags & INP_ESPINUDP) {
+		u_int32_t *st = (u_int32_t *)data;
+
+		if ((len <= sizeof(struct esp)) || (*st == 0))
+			return 0; /* Normal UDP processing */
+
+		skip = sizeof(struct udphdr);
+	}
+
+	if (inp->inp_flags & INP_ESPINUDP_NON_IKE) {
+		u_int64_t *st = (u_int64_t *)data;
+
+		if ((len <= sizeof(u_int64_t) + sizeof(struct esp))
+		    || (*st != 0))
+			return 0; /* Normal UDP processing */
+		
+		skip = sizeof(struct udphdr) + sizeof(u_int64_t);
+	}
+
+	/*
+	 * Remove the UDP header (and possibly the non ESP marker)
+	 * IP header lendth is iphdrlen
+	 * Before:   
+	 *   <--- off --->
+	 *   +----+------+-----+
+	 *   | IP |  UDP | ESP |
+	 *   +----+------+-----+
+	 *        <-skip->
+	 * After:
+	 *          +----+-----+
+	 *          | IP | ESP |
+	 *          +----+-----+
+	 *   <-skip->
+	 */
+	iphdrlen = off - sizeof(struct udphdr);
+	ovbcopy(mtod(m, caddr_t), mtod(m, caddr_t) + skip, iphdrlen);
+	m_adj(m, skip);
+
+	ip = mtod(m, struct ip *);
+	ip->ip_len = htons(ntohs(ip->ip_len) - skip);
+	ip->ip_p = IPPROTO_ESP;
+
+	/*
+	 * Copy the mbuf to avoid multiple free, as both 
+	 * esp4_input (which we call) and udp_input (which 
+	 * called us) free the mbuf.
+	 */
+	if ((n = m_dup(m, M_DONTWAIT)) == NULL) {
+		printf("udp4_espinudp: m_dup failed\n");
+		return 0;
+	}
+
+	esp4_input(n, iphdrlen);
+
+	/* We handled it, it shoudln't be handled by UDP */
+	return 1;
+}
+#endif
+#endif
 
 u_long	udp_sendspace = 9216;		/* really max datagram size */
 					/* 40 1K datagrams */
--- sys/netinet/udp_var.h.orig	Fri Jan  7 10:45:45 2005
+++ sys/netinet/udp_var.h	Sat Sep  9 19:54:50 2006
@@ -100,6 +100,7 @@
 extern int	log_in_vain;
 
 void	udp_ctlinput(int, struct sockaddr *, void *);
+int		udp_ctloutput(struct socket *, struct sockopt *sopt);
 void	udp_init(void);
 void	udp_input(struct mbuf *, int);
 
--- sys/netinet6/esp_output.c.orig	Fri Jan  7 11:30:34 2005
+++ sys/netinet6/esp_output.c	Sat Sep  9 19:57:55 2006
@@ -56,6 +56,8 @@
 #include <netinet/ip.h>
 #include <netinet/in_var.h>
 
+#include <netinet/udp.h>
+
 #ifdef INET6
 #include <netinet/ip6.h>
 #include <netinet6/ip6_var.h>
@@ -139,6 +141,17 @@
 		hdrsiz = sizeof(struct newesp) + ivlen + 9 + authlen;
 	}
 
+#ifdef IPSEC_NAT_T
+	/*
+	 * If NAT-T is enabled, add the space for UDP encapsulation
+	 */
+	if (sav->natt_type != 0) {
+		hdrsiz += sizeof(struct udphdr);
+		if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE)
+			hdrsiz += sizeof(u_int64_t);
+	}
+#endif
+
 	return hdrsiz;
 
    estimate:
@@ -149,8 +162,14 @@
 	 *	9 = (maximum padding length without random padding length)
 	 *	   + (Pad Length field) + (Next Header field).
 	 *	16 = maximum ICV we support.
+	 *  sizeof(struct udphdr) in case NAT traversal is used
 	 */
+#if defined (IPSEC_NAT_T)
+ 	return sizeof(struct newesp) + esp_max_ivlen() + 9 + 16 +
+	    sizeof(u_int64_t) + sizeof(struct udphdr);
+#else
 	return sizeof(struct newesp) + esp_max_ivlen() + 9 + 16;
+#endif
 }
 
 /*
@@ -196,6 +215,9 @@
 	size_t extendsiz;
 	int error = 0;
 	struct ipsecstat *stat;
+#ifdef IPSEC_NAT_T
+	struct udphdr *udp = NULL;
+#endif
 
 	switch (af) {
 #ifdef INET
@@ -334,10 +356,25 @@
 
 	espoff = m->m_pkthdr.len - plen;
 
+#ifdef IPSEC_NAT_T
+	if (sav->natt_type != 0) {
+		esphlen += sizeof(struct udphdr);
+		espoff += sizeof(struct udphdr);
+		
+		if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE) {
+			/* NON-IKE marker */
+			esphlen += sizeof(u_int64_t);
+			espoff += sizeof(u_int64_t);
+		}
+	}
+#endif
+
 	/*
 	 * grow the mbuf to accomodate ESP header.
 	 * before: IP ... payload
-	 * after:  IP ... ESP IV payload
+	 * after (without NAT-T):  IP ... ESP IV payload
+	 * after (with older NAT-T):  IP ... UDP non-IKE-marker ESP IV payload
+	 * after (with newer NAT-T):  IP ... UDP ESP IV payload
 	 */
 	if (M_LEADINGSPACE(md) < esphlen || (md->m_flags & M_EXT) != 0) {
 		MGET(n, M_DONTWAIT, MT_DATA);
@@ -358,6 +395,21 @@
 		esp = mtod(md, struct esp *);
 	}
 
+#ifdef IPSEC_NAT_T
+	if (sav->natt_type != 0) {
+		udp = (struct udphdr *)esp;
+		esp = (struct esp *)(udp + 1);
+
+		if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE) {
+			u_int64_t *data = (u_int64_t *)esp;
+
+			*data = 0; /* NON-IKE marker */
+			esp = (struct esp *)(data + 1);
+		}
+	}
+#endif
+
+
 	nxt = *nexthdrp;
 	*nexthdrp = IPPROTO_ESP;
 	switch (af) {
@@ -523,6 +575,26 @@
 		break;
 	}
 
+#ifdef IPSEC_NAT_T
+	if (sav->natt_type != 0) {
+		*nexthdrp = IPPROTO_UDP;
+
+		/* 
+		 * Create the UDP encapsulation header for NAT-T
+		 * uh_len is set later, when the size is known.
+		 */
+		if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE)
+			udp->uh_sport = htons(UDP_ENCAP_ESPINUDP_PORT);
+		else
+			udp->uh_sport = htons(sav->local_ike_port);
+
+		udp->uh_dport = htons(sav->remote_ike_port);
+		udp->uh_sum = 0;
+	} else {
+		*nexthdrp = IPPROTO_ESP;
+	}
+#endif
+
 	/* initialize esp trailer. */
 	esptail = (struct esptail *)
 		(mtod(n, u_int8_t *) + n->m_len - sizeof(struct esptail));
@@ -665,6 +737,18 @@
 #endif
 	}
     }
+
+#ifdef IPSEC_NAT_T
+	if (sav->natt_type != 0) {
+		struct ip *ip;
+		ip = mtod(m, struct ip *);
+#ifdef _IP_VHL
+		udp->uh_ulen = htons(ntohs(ip->ip_len) - (IP_VHL_HL(ip->ip_vhl) << 2));
+#else
+		udp->uh_ulen = htons(ntohs(ip->ip_len) - (ip->ip_hl << 2));
+#endif
+	}
+#endif
 
 noantireplay:
 	if (!m) {
--- sys/netkey/key.c.orig	Sat Nov  5 05:26:16 2005
+++ sys/netkey/key.c	Sat Sep  9 20:01:27 2006
@@ -194,6 +194,10 @@
 	0,				/* SADB_X_EXT_KMPRIVATE */
 	sizeof(struct sadb_x_policy),	/* SADB_X_EXT_POLICY */
 	sizeof(struct sadb_x_sa2),	/* SADB_X_SA2 */
+	sizeof(struct sadb_x_nat_t_type), /* SADB_X_EXT_NAT_T_TYPE */
+	sizeof(struct sadb_x_nat_t_port), /* SADB_X_EXT_NAT_T_SPORT */
+	sizeof(struct sadb_x_nat_t_port), /* SADB_X_EXT_NAT_T_DPORT */
+	sizeof(struct sadb_address),	/* SADB_X_EXT_NAT_T_OA */
 };
 static const int maxsize[] = {
 	sizeof(struct sadb_msg),	/* SADB_EXT_RESERVED */
@@ -216,6 +220,10 @@
 	0,				/* SADB_X_EXT_KMPRIVATE */
 	0,				/* SADB_X_EXT_POLICY */
 	sizeof(struct sadb_x_sa2),	/* SADB_X_SA2 */
+	sizeof(struct sadb_x_nat_t_type), /* SADB_X_EXT_NAT_T_TYPE */
+	sizeof(struct sadb_x_nat_t_port), /* SADB_X_EXT_NAT_T_SPORT */
+	sizeof(struct sadb_x_nat_t_port), /* SADB_X_EXT_NAT_T_DPORT */
+	0,				/* SADB_X_EXT_NAT_T_OA */
 };
 
 static int ipsec_esp_keymin = 256;
@@ -384,6 +392,8 @@
 	const struct sadb_msghdr *);
 static int key_spddump(struct socket *, struct mbuf *,
 	const struct sadb_msghdr *);
+static int key_nat_map(struct socket *, struct mbuf *,
+	const struct sadb_msghdr *);
 static struct mbuf *key_setdumpsp(struct secpolicy *,
 	u_int8_t, u_int32_t, u_int32_t);
 static u_int key_getspreqmsglen(struct secpolicy *);
@@ -2475,6 +2485,62 @@
 	return 0;
 }
 
+/* 
+ * SADB_X_NAT_T_NEW_MAPPING 
+ */
+static int
+key_nat_map(so, m, mhp)
+	struct socket *so;
+	struct mbuf *m;
+	const struct sadb_msghdr *mhp;
+{
+	struct sadb_x_nat_t_type *type;
+	struct sadb_x_nat_t_port *sport;
+	struct sadb_x_nat_t_port *dport;
+	struct sadb_address *addr;
+
+	/* sanity check */
+	if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
+		panic("key_nat_map: NULL pointer is passed.");
+
+	if (mhp->ext[SADB_X_EXT_NAT_T_TYPE] == NULL ||
+	    mhp->ext[SADB_X_EXT_NAT_T_SPORT] == NULL ||
+	    mhp->ext[SADB_X_EXT_NAT_T_DPORT] == NULL) {
+		ipseclog((LOG_DEBUG, "key_nat_map: invalid message.\n"));
+		return key_senderror(so, m, EINVAL);
+	}
+	if ((mhp->extlen[SADB_X_EXT_NAT_T_TYPE] < sizeof(*type)) ||
+	    (mhp->extlen[SADB_X_EXT_NAT_T_SPORT] < sizeof(*sport)) ||
+	    (mhp->extlen[SADB_X_EXT_NAT_T_DPORT] < sizeof(*dport))) {
+		ipseclog((LOG_DEBUG, "key_nat_map: invalid message.\n"));
+		return key_senderror(so, m, EINVAL);
+	}
+
+	if ((mhp->ext[SADB_X_EXT_NAT_T_OA] != NULL) && 
+	    (mhp->extlen[SADB_X_EXT_NAT_T_OA] < sizeof(*addr))) {
+		ipseclog((LOG_DEBUG, "key_nat_map: invalid message\n"));
+		return key_senderror(so, m, 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];
+	addr = (struct sadb_address *)mhp->ext[SADB_X_EXT_NAT_T_OA];
+
+	printf("sadb_nat_map: type %d, sport = %d, dport = %d\n", 
+		type->sadb_x_nat_t_type_type,
+		sport->sadb_x_nat_t_port_port,
+		dport->sadb_x_nat_t_port_port);
+
+	/* 
+	 * XXX handle that, it should also contain a SA, or anything 
+	 * that enable to update the SA information.
+	 */
+
+	return 0;
+}
+
+
 static struct mbuf *
 key_setdumpsp(sp, type, seq, pid)
 	struct secpolicy *sp;
@@ -3025,6 +3091,9 @@
 	sav->lft_c = NULL;
 	sav->lft_h = NULL;
 	sav->lft_s = NULL;
+	sav->natt_type = 0;
+	sav->remote_ike_port = 0;
+	sav->local_ike_port = 0;
 
 	/* SA */
 	if (mhp->ext[SADB_EXT_SA] != NULL) {
@@ -5223,6 +5292,50 @@
 	}
 
 	/*
+	 * Handle NAT-T info if present
+	 */
+	if (mhp->ext[SADB_X_EXT_NAT_T_OA] != NULL) {
+		printf("add: NAT-T OA present\n");
+	}
+	if ((mhp->ext[SADB_X_EXT_NAT_T_TYPE] != NULL) &&
+	    (mhp->ext[SADB_X_EXT_NAT_T_SPORT] != NULL) &&
+	    (mhp->ext[SADB_X_EXT_NAT_T_DPORT] != NULL)) { 
+		struct sadb_x_nat_t_type *type;
+		struct sadb_x_nat_t_port *sport;
+		struct sadb_x_nat_t_port *dport;
+		struct sadb_address *addr;
+
+		if ((mhp->extlen[SADB_X_EXT_NAT_T_TYPE] < sizeof(*type)) ||
+		    (mhp->extlen[SADB_X_EXT_NAT_T_SPORT] < sizeof(*sport)) ||
+		    (mhp->extlen[SADB_X_EXT_NAT_T_DPORT] < sizeof(*dport))) {
+			ipseclog((LOG_DEBUG, "key_add: "
+			    "invalid message.\n"));
+			return key_senderror(so, m, EINVAL);
+		}
+
+		if ((mhp->ext[SADB_X_EXT_NAT_T_OA] != NULL) && 
+		    (mhp->extlen[SADB_X_EXT_NAT_T_OA] < sizeof(*addr))) {
+			ipseclog((LOG_DEBUG, "key_add: invalid message\n"));
+			return key_senderror(so, m, 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];
+		addr = (struct sadb_address *)
+		    mhp->ext[SADB_X_EXT_NAT_T_OA];
+	
+		newsav->natt_type = type->sadb_x_nat_t_type_type;
+		newsav->local_ike_port = ntohs(sport->sadb_x_nat_t_port_port);
+		newsav->remote_ike_port = ntohs(dport->sadb_x_nat_t_port_port);
+	}
+
+
+
+	/*
 	 * don't call key_freesav() here, as we would like to keep the SA
 	 * in the database on success.
 	 */
@@ -6875,6 +6988,7 @@
 	key_spdadd,	/* SADB_X_SPDSETIDX */
 	NULL,		/* SADB_X_SPDEXPIRE */
 	key_spddelete2,	/* SADB_X_SPDDELETE2 */
+	key_nat_map, /* SADB_X_NAT_T_NEW_MAPPING */
 };
 
 /*
@@ -7227,6 +7341,12 @@
 		case SADB_EXT_SPIRANGE:
 		case SADB_X_EXT_POLICY:
 		case SADB_X_EXT_SA2:
+#ifdef IPSEC_NAT_T
+		case SADB_X_EXT_NAT_T_TYPE:
+		case SADB_X_EXT_NAT_T_SPORT:
+		case SADB_X_EXT_NAT_T_DPORT:
+		case SADB_X_EXT_NAT_T_OA:
+#endif
 			/* duplicate check */
 			/*
 			 * XXX Are there duplication payloads of either
--- sys/netkey/keydb.h.orig	Fri Jan  7 10:45:48 2005
+++ sys/netkey/keydb.h	Sat Sep  9 20:05:00 2006
@@ -114,6 +114,11 @@
 	pid_t pid;			/* message's pid */
 
 	struct secashead *sah;		/* back pointer to the secashead */
+  /* For NAT-Traversal 
+   */
+	u_int16_t	natt_type;
+	u_int16_t	remote_ike_port;
+	u_int16_t	local_ike_port; /* ??? */
 
 	u_int32_t id;			/* SA id */
 };



More information about the freebsd-net mailing list