[Openswan dev] Re: [PATCH] Openswan and OS X with NAT-T

Peter Van der Beken peterv at propagandism.org
Thu Sep 29 01:19:04 CEST 2005


Michael Richardson wrote:
>     Paul>   	NAT-Traversal: Result using RFC 3947 (NAT-Traversal):
>     Paul> both are NATed
> 
>   It means that the hash on the server side ports/data is wrong.
>   Apple probably screwed that up too.  I'm disinclined to ship the patch
> based upon that knowledge.

Bah! Looking at the debugging info on both ends confirms that they 
inverted the messages for the hashes, they send the hash for the local 
side first and then the hash for the remote side, whereas the RFC 
specifies that the receiver should get the local side first and then the 
remote side. I attached an updated patch that handles this bug too 
(still 2.3.1, sorry!). It's getting uglier with every iteration :-(.

I do think that http://bugs.xelerance.com/view.php?id=442 is right, in 
nat_traversal_add_natd the hash for the second packet is computed using 
&(md->iface->ip_addr) and ntohs(st->st_remoteport), I think that last 
one should be ntohs(st->st_localport).

Peter
-------------- next part --------------
diff -ru openswan-2.3.1.orig/include/ietf_constants.h openswan-2.3.1/include/ietf_constants.h
--- openswan-2.3.1.orig/include/ietf_constants.h	2005-03-21 04:54:42.000000000 +0100
+++ openswan-2.3.1/include/ietf_constants.h	2005-09-27 00:50:20.000000000 +0200
@@ -270,6 +270,8 @@
 #define ISAKMP_NEXT_D          12	/* Delete */
 #define ISAKMP_NEXT_VID        13	/* Vendor ID */
 #define ISAKMP_NEXT_ATTR       14       /* Mode config Attribute */
+#define ISAKMP_NEXT_NATD_BADDRAFTS   15 /* NAT-Traversal: NAT-D (bad drafts) */
+                                        /* !!! Conflicts with RFC 3547 */
 #define ISAKMP_NEXT_NATD_RFC   20       /* NAT-Traversal: NAT-D (rfc) */
 #define ISAKMP_NEXT_NATOA_RFC  21       /* NAT-Traversal: NAT-OA (rfc) */
 #define ISAKMP_NEXT_ROOF       22	/* roof on payload types */
diff -ru openswan-2.3.1.orig/lib/libopenswan/constants.c openswan-2.3.1/lib/libopenswan/constants.c
--- openswan-2.3.1.orig/lib/libopenswan/constants.c	2005-01-23 19:53:35.000000000 +0100
+++ openswan-2.3.1/lib/libopenswan/constants.c	2005-09-27 00:50:20.000000000 +0200
@@ -123,7 +123,7 @@
 	"ISAKMP_NEXT_D",
 	"ISAKMP_NEXT_VID",
 	"ISAKMP_NEXT_MODECFG",  /* 14 */
-	"ISAKMP_NEXT_15",
+	"ISAKMP_NEXT_NAT-D",
 	"ISAKMP_NEXT_16",
 	"ISAKMP_NEXT_17",
 	"ISAKMP_NEXT_18",
@@ -916,9 +916,9 @@
 const char *const natt_type_bitnames[] = {
   "draft-ietf-ipsec-nat-t-ike-00/01",    /* 0 */
   "draft-ietf-ipsec-nat-t-ike-02/03",
+  "draft-ietf-ipsec-nat-t-ike (OS X)",
   "RFC 3947 (NAT-Traversal)",
-  "3",                                   /* 3 */
-  "4",   "5",   "6",   "7", 
+  "4",   "5",   "6",   "7",              /* 4 */ 
   "8",   "9",   "10",  "11",
   "12",  "13",  "14",  "15",
   "16",  "17",  "18",  "19", 
diff -ru openswan-2.3.1.orig/programs/pluto/demux.c openswan-2.3.1/programs/pluto/demux.c
--- openswan-2.3.1.orig/programs/pluto/demux.c	2005-03-21 05:01:52.000000000 +0100
+++ openswan-2.3.1/programs/pluto/demux.c	2005-09-27 00:50:20.000000000 +0200
@@ -2029,6 +2029,16 @@
 		    np = ISAKMP_NEXT_NATOA_RFC;  /* NAT-OA relocated */
 		    sd = payload_descs[np];
 		    break;
+		case ISAKMP_NEXT_NATD_BADDRAFTS:
+			if (st && (st->hidden_variables.st_nat_traversal & NAT_T_WITH_NATD_BADDRAFT_VALUES)) {
+			    /*
+			     * Only accept this value if we're in compatibility mode with
+			     * the bad drafts of the RFC
+			     */
+		        np = ISAKMP_NEXT_NATD_RFC;  /* NAT-D relocated */
+		        sd = payload_descs[np];
+		        break;
+		    }
 #endif
 		default:
 		    loglog(RC_LOG_SERIOUS, "%smessage ignored because it contains an unknown or"
diff -ru openswan-2.3.1.orig/programs/pluto/nat_traversal.c openswan-2.3.1/programs/pluto/nat_traversal.c
--- openswan-2.3.1.orig/programs/pluto/nat_traversal.c	2005-03-21 00:16:16.000000000 +0100
+++ openswan-2.3.1/programs/pluto/nat_traversal.c	2005-09-28 22:06:42.000000000 +0200
@@ -211,6 +211,9 @@
 		case VID_NATT_IETF_03:
 			return LELEM(NAT_TRAVERSAL_IETF_02_03);
 			break;
+		case VID_NATT_DRAFT_IETF_IPSEC_NAT_T_IKE:
+			return LELEM(NAT_TRAVERSAL_OSX);
+			break;
 		case VID_NATT_RFC:
 			return LELEM(NAT_TRAVERSAL_RFC);
 			break;
@@ -224,6 +227,10 @@
 	struct payload_digest *p;
 	struct state *st = md->st;
 	int i;
+	u_int32_t first_type, other_type;
+	const ip_address *first_ip, *other_ip;
+	u_int16_t first_port, other_port;
+	bool invert = (st->hidden_variables.st_nat_traversal & LELEM(NAT_TRAVERSAL_OSX));
 
 	if (!st || !md->iface || !st->st_oakley.hasher) {
 		loglog(RC_LOG_SERIOUS, "NAT-Traversal: assert failed %s:%d",
@@ -247,34 +254,59 @@
 	}
 
 	/**
-	 * First one with my IP & port
+	 * First one with my IP & port to detect NAT behind me
+	 */
+	first_type = LELEM(NAT_TRAVERSAL_NAT_BHND_ME);
+	first_ip = &(md->iface->addr);
+	first_port = ntohs(st->st_localport);
+
+	/**
+	 * Others with sender IP & port to detect NAT behind peer
 	 */
+	other_type = LELEM(NAT_TRAVERSAL_NAT_BHND_PEER);
+	other_ip = &(md->sender);
+	other_port = ntohs(md->sender_port);
+
+	if (invert) {
+		/**
+		 * Apple's OS X implementation is broken, they inverted the messages.
+		 */
+		u_int32_t type = other_type;
+		const ip_address *ip = other_ip;
+		u_int16_t port = other_port;
+
+		other_type = first_type;
+		other_ip = first_ip;
+		other_port = first_port;
+		first_type = type;
+		first_ip = ip;
+		first_port = port;
+	}
+
 	p = md->chain[ISAKMP_NEXT_NATD_RFC];
 	_natd_hash(st->st_oakley.hasher, hash
 		   , st->st_icookie, st->st_rcookie
-		   , &(md->iface->addr)
-		   , ntohs(st->st_localport));
+		   , first_ip
+		   , first_port);
 
 	if (!( (pbs_left(&p->pbs) == st->st_oakley.hasher->hash_digest_len)
 	       && (memcmp(p->pbs.cur, hash, st->st_oakley.hasher->hash_digest_len)==0)))
 	{
 #ifdef NAT_D_DEBUG
 	    DBG(DBG_NATT,
-		DBG_log("NAT_TRAVERSAL_NAT_BHND_ME");
+		DBG_log(invert ? "NAT_TRAVERSAL_NAT_BHND_PEER" : "NAT_TRAVERSAL_NAT_BHND_ME");
 		DBG_dump("expected NAT-D:", hash,
 			 st->st_oakley.hasher->hash_digest_len);
 		DBG_dump("received NAT-D:", p->pbs.cur, pbs_left(&p->pbs));
 		);
 #endif
-	    st->hidden_variables.st_nat_traversal |= LELEM(NAT_TRAVERSAL_NAT_BHND_ME);
+	    st->hidden_variables.st_nat_traversal |= first_type;
 	}
 
-	/**
-	 * The others with sender IP & port
-	 */
 	_natd_hash(st->st_oakley.hasher, hash
 		   , st->st_icookie, st->st_rcookie
-		   , &(md->sender), ntohs(md->sender_port));
+		   , other_ip
+		   , other_port);
 
 	for (p = p->next, i=0 ; p != NULL; p = p->next) {
 	    if ( (pbs_left(&p->pbs) == st->st_oakley.hasher->hash_digest_len)
@@ -288,7 +320,7 @@
 	if (!i) {
 #ifdef NAT_D_DEBUG
 	    DBG(DBG_NATT,
-		DBG_log("NAT_TRAVERSAL_NAT_BHND_PEER");
+		DBG_log(invert ? "NAT_TRAVERSAL_NAT_BHND_ME" : "NAT_TRAVERSAL_NAT_BHND_PEER");
 		DBG_dump("expected NAT-D:", hash,
 			 st->st_oakley.hasher->hash_digest_len);
 		p = md->chain[ISAKMP_NEXT_NATD_RFC];
@@ -297,7 +329,7 @@
 		}
 		);
 #endif
-	    st->hidden_variables.st_nat_traversal |= LELEM(NAT_TRAVERSAL_NAT_BHND_PEER);
+	    st->hidden_variables.st_nat_traversal |= other_type;
 	}
 	
 	st->hidden_variables.st_natd = md->sender;
@@ -314,6 +346,8 @@
 	char hash[MAX_DIGEST_LEN];
 	struct state *st = md->st;
 	unsigned int nat_np;
+	const ip_address *first_ip, *second_ip;
+	u_int16_t first_port, second_port;
 
 	if (!st || !st->st_oakley.hasher) {
 		loglog(RC_LOG_SERIOUS, "NAT-Traversal: assert failed %s:%d",
@@ -324,7 +358,9 @@
 	DBG(DBG_EMITTING, DBG_log("sending NATD payloads"));
 
 	nat_np = (st->hidden_variables.st_nat_traversal & NAT_T_WITH_RFC_VALUES
-	      ? ISAKMP_NEXT_NATD_RFC : ISAKMP_NEXT_NATD_DRAFTS);
+	      ? ISAKMP_NEXT_NATD_RFC
+	      : (st->hidden_variables.st_nat_traversal & NAT_T_WITH_NATD_BADDRAFT_VALUES
+	      ? ISAKMP_NEXT_NATD_BADDRAFTS : ISAKMP_NEXT_NATD_DRAFTS));
 	if (!out_modify_previous_np(nat_np, outs)) {
 		return FALSE;
 	}
@@ -332,17 +368,36 @@
 	/**
 	 * First one with sender IP & port
 	 */
+	first_ip = &(md->sender);
+	first_port = ntohs(md->sender_port);
+
+	/**
+	 * Second one with my IP & port
+	 */
+	second_ip = &(md->iface->addr);
+	second_port = ntohs(st->st_localport);
+
+	if (st->hidden_variables.st_nat_traversal & LELEM(NAT_TRAVERSAL_OSX)) {
+		const ip_address *ip = second_ip;
+		u_int16_t port = second_port;
+
+		second_ip = first_ip;
+		second_port = first_port;
+		first_ip = ip;
+		first_port = port;
+	}
+
 	if(st->st_connection->forceencaps) {
 	    _natd_hash(st->st_oakley.hasher
 		       , hash, st->st_icookie
 		       , is_zero_cookie(st->st_rcookie) ? md->hdr.isa_rcookie : st->st_rcookie
-		       , &(md->sender)
+		       , first_ip
 		       , 0);
 	} else {
 	    _natd_hash(st->st_oakley.hasher, hash, st->st_icookie
 		       , is_zero_cookie(st->st_rcookie) ? md->hdr.isa_rcookie : st->st_rcookie
-		       , &(md->sender)
-		       , ntohs(md->sender_port));
+		       , first_ip
+		       , first_port);
 	}
 
 	if (!out_generic_raw(nat_np, &isakmp_nat_d, outs
@@ -352,20 +407,18 @@
 	    return FALSE;
 	}
 
-	/**
-	 * Second one with my IP & port
-	 */
 	if(st->st_connection->forceencaps) {
 	    _natd_hash(st->st_oakley.hasher, hash
 		       , st->st_icookie
 		       , is_zero_cookie(st->st_rcookie) ? md->hdr.isa_rcookie : st->st_rcookie
-		       , &(md->iface->addr),0);
+		       , second_ip
+		       , 0);
 	} else {
 	    _natd_hash(st->st_oakley.hasher, hash
 		       , st->st_icookie
 		       , is_zero_cookie(st->st_rcookie) ? md->hdr.isa_rcookie : st->st_rcookie
-		       , &(md->iface->addr)
-		       , ntohs(st->st_remoteport));
+		       , second_ip
+		       , second_port);
 	}
 	return (out_generic_raw(np, &isakmp_nat_d, outs,
 		hash, st->st_oakley.hasher->hash_digest_len, "NAT-D"));
@@ -541,9 +594,12 @@
 	case LELEM(NAT_TRAVERSAL_IETF_02_03):
 	    mth = natt_type_bitnames[1];
 	    break;
-	case LELEM(NAT_TRAVERSAL_RFC):
+	case LELEM(NAT_TRAVERSAL_OSX):
 	    mth = natt_type_bitnames[2];
 	    break;
+	case LELEM(NAT_TRAVERSAL_RFC):
+	    mth = natt_type_bitnames[3];
+	    break;
 	}
 	switch (nt & NAT_T_DETECTED) {
 		case 0:
diff -ru openswan-2.3.1.orig/programs/pluto/nat_traversal.h openswan-2.3.1/programs/pluto/nat_traversal.h
--- openswan-2.3.1.orig/programs/pluto/nat_traversal.h	2005-01-23 20:17:25.000000000 +0100
+++ openswan-2.3.1/programs/pluto/nat_traversal.h	2005-09-27 00:50:20.000000000 +0200
@@ -21,7 +21,8 @@
 
 #define NAT_TRAVERSAL_IETF_00_01     1
 #define NAT_TRAVERSAL_IETF_02_03     2
-#define NAT_TRAVERSAL_RFC            3
+#define NAT_TRAVERSAL_OSX            3
+#define NAT_TRAVERSAL_RFC            4
 
 #define NAT_TRAVERSAL_NAT_BHND_ME    30
 #define NAT_TRAVERSAL_NAT_BHND_PEER  31
@@ -33,7 +34,7 @@
  */
 #define NAT_T_WITH_NATD \
 	( LELEM(NAT_TRAVERSAL_IETF_00_01) | LELEM(NAT_TRAVERSAL_IETF_02_03) | \
-	LELEM(NAT_TRAVERSAL_RFC) )
+	LELEM(NAT_TRAVERSAL_OSX) | LELEM(NAT_TRAVERSAL_RFC) )
 /**
  * NAT-Traversal methods which need NAT-OA
  */
@@ -45,12 +46,20 @@
  */
 #define NAT_T_WITH_KA \
 	( LELEM(NAT_TRAVERSAL_IETF_00_01) | LELEM(NAT_TRAVERSAL_IETF_02_03) | \
-	LELEM(NAT_TRAVERSAL_RFC) )
+	LELEM(NAT_TRAVERSAL_OSX) | LELEM(NAT_TRAVERSAL_RFC) )
 /**
  * NAT-Traversal methods which use floating port
  */
 #define NAT_T_WITH_PORT_FLOATING \
-	( LELEM(NAT_TRAVERSAL_IETF_02_03) | LELEM(NAT_TRAVERSAL_RFC) )
+	( LELEM(NAT_TRAVERSAL_IETF_02_03) | LELEM(NAT_TRAVERSAL_OSX) | \
+	LELEM(NAT_TRAVERSAL_RFC) )
+
+/**
+ * NAT-Traversal methods which use a value for NAT-D from draft versions of the
+ * RFC which conflict with values from RFC 3547
+ */
+#define NAT_T_WITH_NATD_BADDRAFT_VALUES \
+	( LELEM(NAT_TRAVERSAL_OSX) )
 
 /**
  * NAT-Traversal methods which use officials values (RFC)
@@ -59,6 +68,12 @@
 	( LELEM(NAT_TRAVERSAL_RFC) )
 
 /**
+ * NAT-Traversal methods which use officials values (RFC) for encapsulation
+ */
+#define NAT_T_WITH_ENCAPSULATION_RFC_VALUES \
+	( LELEM(NAT_TRAVERSAL_OSX) | LELEM(NAT_TRAVERSAL_RFC) )
+
+/**
  * NAT-Traversal detected
  */
 #define NAT_T_DETECTED \
@@ -137,11 +152,11 @@
 #define NAT_T_ENCAPSULATION_MODE(st,nat_t_policy) ( \
 	((st)->hidden_variables.st_nat_traversal & NAT_T_DETECTED) \
 		? ( ((nat_t_policy) & POLICY_TUNNEL) \
-			? ( ((st)->hidden_variables.st_nat_traversal & NAT_T_WITH_RFC_VALUES) \
+			? ( ((st)->hidden_variables.st_nat_traversal & NAT_T_WITH_ENCAPSULATION_RFC_VALUES) \
 				? (ENCAPSULATION_MODE_UDP_TUNNEL_RFC) \
 				: (ENCAPSULATION_MODE_UDP_TUNNEL_DRAFTS) \
 			  ) \
-			: ( ((st)->hidden_variables.st_nat_traversal & NAT_T_WITH_RFC_VALUES) \
+			: ( ((st)->hidden_variables.st_nat_traversal & NAT_T_WITH_ENCAPSULATION_RFC_VALUES) \
 				? (ENCAPSULATION_MODE_UDP_TRANSPORT_RFC) \
 				: (ENCAPSULATION_MODE_UDP_TRANSPORT_DRAFTS) \
 			  ) \
diff -ru openswan-2.3.1.orig/programs/pluto/spdb_struct.c openswan-2.3.1/programs/pluto/spdb_struct.c
--- openswan-2.3.1.orig/programs/pluto/spdb_struct.c	2005-02-15 02:54:20.000000000 +0100
+++ openswan-2.3.1/programs/pluto/spdb_struct.c	2005-09-27 00:50:20.000000000 +0200
@@ -1458,7 +1458,7 @@
 #endif
 
 			case ENCAPSULATION_MODE_UDP_TUNNEL_DRAFTS:
-				if (st->hidden_variables.st_nat_traversal & NAT_T_WITH_RFC_VALUES) {
+				if (st->hidden_variables.st_nat_traversal & NAT_T_WITH_ENCAPSULATION_RFC_VALUES) {
 					loglog(RC_LOG_SERIOUS,
 						"%s must only be used with old IETF drafts",
 						enum_name(&enc_mode_names, val));
@@ -1487,7 +1487,7 @@
 
 			case ENCAPSULATION_MODE_UDP_TUNNEL_RFC:
 				if ((st->hidden_variables.st_nat_traversal & NAT_T_DETECTED) &&
-					(st->hidden_variables.st_nat_traversal & NAT_T_WITH_RFC_VALUES)) {
+					(st->hidden_variables.st_nat_traversal & NAT_T_WITH_ENCAPSULATION_RFC_VALUES)) {
 					attrs->encapsulation = val - ENCAPSULATION_MODE_UDP_TUNNEL_RFC + ENCAPSULATION_MODE_TUNNEL;
 				}
 				else if (st->hidden_variables.st_nat_traversal & NAT_T_DETECTED) {
diff -ru openswan-2.3.1.orig/programs/pluto/vendor.c openswan-2.3.1/programs/pluto/vendor.c
--- openswan-2.3.1.orig/programs/pluto/vendor.c	2005-09-26 01:13:27.000000000 +0200
+++ openswan-2.3.1/programs/pluto/vendor.c	2005-09-27 00:50:20.000000000 +0200
@@ -378,6 +378,7 @@
 		case VID_NATT_IETF_02:
 		case VID_NATT_IETF_02_N:
 		case VID_NATT_IETF_03:
+		case VID_NATT_DRAFT_IETF_IPSEC_NAT_T_IKE:
 		case VID_NATT_RFC:
  		        vid_usefull = 1;
 			if(!nat_traversal_support_port_floating) {


More information about the Dev mailing list