[strongSwan-dev] strongSwan 5 draft-ietf-ipsec-nat-t-ike-02 support

Volker Rümelin vr_strongswan at t-online.de
Mon Dec 10 21:22:10 CET 2012


Hello strongSwan team,

this is a patch to support nat traversal draft-ietf-ipsec-nat-t-ike-02 in
strongSwan 5. Comments or suggestions are welcome.

Signed-off-by: Volker Rümelin <vr_strongswan at t-online.de>
---
 src/libcharon/encoding/message.c                   |   12 +++
 src/libcharon/encoding/payloads/id_payload.c       |    5 +-
 src/libcharon/encoding/payloads/payload.c          |   53 +++++------
 src/libcharon/encoding/payloads/payload.h          |   10 ++
 .../encoding/payloads/proposal_substructure.c      |   34 ++++++--
 .../encoding/payloads/proposal_substructure.h      |   22 ++++--
 src/libcharon/encoding/payloads/sa_payload.c       |    8 +-
 src/libcharon/encoding/payloads/sa_payload.h       |    8 +-
 src/libcharon/sa/ike_sa.h                          |   24 +++++
 src/libcharon/sa/ikev1/tasks/aggressive_mode.c     |    6 +-
 src/libcharon/sa/ikev1/tasks/isakmp_natd.c         |   17 +++-
 src/libcharon/sa/ikev1/tasks/isakmp_vendor.c       |   96 ++++++++++++++------
 src/libcharon/sa/ikev1/tasks/main_mode.c           |    6 +-
 src/libcharon/sa/ikev1/tasks/quick_mode.c          |   43 ++++++++-
 14 files changed, 253 insertions(+), 91 deletions(-)

diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c
index d3b72ea..c450f39 100644
--- a/src/libcharon/encoding/message.c
+++ b/src/libcharon/encoding/message.c
@@ -437,6 +437,7 @@ static payload_rule_t id_prot_i_rules[] = {
 	{VENDOR_ID_V1,				0,	MAX_VID_PAYLOADS,		FALSE,	FALSE},
 	{CERTIFICATE_REQUEST_V1,	0,	MAX_CERTREQ_PAYLOADS,	FALSE,	FALSE},
 	{NAT_D_V1,					0,	MAX_NAT_D_PAYLOADS,		FALSE,	FALSE},
+	{NAT_D_DRAFT_00_03_V1,		0,	MAX_NAT_D_PAYLOADS,		FALSE,	FALSE},
 	{ID_V1,						0,	1,						TRUE,	FALSE},
 	{CERTIFICATE_V1,			0,	2,						TRUE,	FALSE},
 	{SIGNATURE_V1,				0,	1,						TRUE,	FALSE},
@@ -459,6 +460,7 @@ static payload_order_t id_prot_i_order[] = {
 	{NOTIFY_V1,					0},
 	{VENDOR_ID_V1,				0},
 	{NAT_D_V1,					0},
+	{NAT_D_DRAFT_00_03_V1,		0},
 };
 
 /**
@@ -473,6 +475,7 @@ static payload_rule_t id_prot_r_rules[] = {
 	{VENDOR_ID_V1,				0,	MAX_VID_PAYLOADS,		FALSE,	FALSE},
 	{CERTIFICATE_REQUEST_V1,	0,	MAX_CERTREQ_PAYLOADS,	FALSE,	FALSE},
 	{NAT_D_V1,					0,	MAX_NAT_D_PAYLOADS,		FALSE,	FALSE},
+	{NAT_D_DRAFT_00_03_V1,		0,	MAX_NAT_D_PAYLOADS,		FALSE,	FALSE},
 	{ID_V1,						0,	1,						TRUE,	FALSE},
 	{CERTIFICATE_V1,			0,	2,						TRUE,	FALSE},
 	{SIGNATURE_V1,				0,	1,						TRUE,	FALSE},
@@ -495,6 +498,7 @@ static payload_order_t id_prot_r_order[] = {
 	{NOTIFY_V1,					0},
 	{VENDOR_ID_V1,				0},
 	{NAT_D_V1,					0},
+	{NAT_D_DRAFT_00_03_V1,		0},
 };
 
 /**
@@ -509,6 +513,7 @@ static payload_rule_t aggressive_i_rules[] = {
 	{VENDOR_ID_V1,				0,	MAX_VID_PAYLOADS,		FALSE,	FALSE},
 	{CERTIFICATE_REQUEST_V1,	0,	MAX_CERTREQ_PAYLOADS,	FALSE,	FALSE},
 	{NAT_D_V1,					0,	MAX_NAT_D_PAYLOADS,		FALSE,	FALSE},
+	{NAT_D_DRAFT_00_03_V1,		0,	MAX_NAT_D_PAYLOADS,		FALSE,	FALSE},
 	{ID_V1,						0,	1,						FALSE,	FALSE},
 	{CERTIFICATE_V1,			0,	1,						TRUE,	FALSE},
 	{SIGNATURE_V1,				0,	1,						TRUE,	FALSE},
@@ -526,6 +531,7 @@ static payload_order_t aggressive_i_order[] = {
 	{ID_V1,						0},
 	{CERTIFICATE_V1,			0},
 	{NAT_D_V1,					0},
+	{NAT_D_DRAFT_00_03_V1,		0},
 	{SIGNATURE_V1,				0},
 	{HASH_V1,					0},
 	{CERTIFICATE_REQUEST_V1,	0},
@@ -545,6 +551,7 @@ static payload_rule_t aggressive_r_rules[] = {
 	{VENDOR_ID_V1,				0,	MAX_VID_PAYLOADS,		FALSE,	FALSE},
 	{CERTIFICATE_REQUEST_V1,	0,	MAX_CERTREQ_PAYLOADS,	FALSE,	FALSE},
 	{NAT_D_V1,					0,	MAX_NAT_D_PAYLOADS,		FALSE,	FALSE},
+	{NAT_D_DRAFT_00_03_V1,		0,	MAX_NAT_D_PAYLOADS,		FALSE,	FALSE},
 	{ID_V1,						0,	1,						FALSE,	FALSE},
 	{CERTIFICATE_V1,			0,	1,						FALSE,	FALSE},
 	{SIGNATURE_V1,				0,	1,						FALSE,	FALSE},
@@ -562,6 +569,7 @@ static payload_order_t aggressive_r_order[] = {
 	{ID_V1,						0},
 	{CERTIFICATE_V1,			0},
 	{NAT_D_V1,					0},
+	{NAT_D_DRAFT_00_03_V1,		0},
 	{SIGNATURE_V1,				0},
 	{HASH_V1,					0},
 	{CERTIFICATE_REQUEST_V1,	0},
@@ -624,6 +632,7 @@ static payload_rule_t quick_mode_i_rules[] = {
 	{KEY_EXCHANGE_V1,			0,	1,						TRUE,	FALSE},
 	{ID_V1,						0,	2,						TRUE,	FALSE},
 	{NAT_OA_V1,					0,	2,						TRUE,	FALSE},
+	{NAT_OA_DRAFT_00_03_V1,		0,	2,						TRUE,	FALSE},
 };
 
 /**
@@ -639,6 +648,7 @@ static payload_order_t quick_mode_i_order[] = {
 	{KEY_EXCHANGE_V1,			0},
 	{ID_V1,						0},
 	{NAT_OA_V1,					0},
+	{NAT_OA_DRAFT_00_03_V1,		0},
 };
 
 /**
@@ -654,6 +664,7 @@ static payload_rule_t quick_mode_r_rules[] = {
 	{KEY_EXCHANGE_V1,			0,	1,						TRUE,	FALSE},
 	{ID_V1,						0,	2,						TRUE,	FALSE},
 	{NAT_OA_V1,					0,	2,						TRUE,	FALSE},
+	{NAT_OA_DRAFT_00_03_V1,		0,	2,						TRUE,	FALSE},
 };
 
 /**
@@ -669,6 +680,7 @@ static payload_order_t quick_mode_r_order[] = {
 	{KEY_EXCHANGE_V1,			0},
 	{ID_V1,						0},
 	{NAT_OA_V1,					0},
+	{NAT_OA_DRAFT_00_03_V1,		0},
 };
 
 /**
diff --git a/src/libcharon/encoding/payloads/id_payload.c b/src/libcharon/encoding/payloads/id_payload.c
index 02b07d6..8c4591c 100644
--- a/src/libcharon/encoding/payloads/id_payload.c
+++ b/src/libcharon/encoding/payloads/id_payload.c
@@ -165,7 +165,7 @@ METHOD(payload_t, verify, status_t,
 {
 	bool bad_length = FALSE;
 
-	if (this->type == NAT_OA_V1 &&
+	if ((this->type == NAT_OA_V1 || this->type == NAT_OA_DRAFT_00_03_V1 ) &&
 		this->id_type != ID_IPV4_ADDR && this->id_type != ID_IPV6_ADDR)
 	{
 		DBG1(DBG_ENC, "invalid ID type %N for %N payload", id_type_names,
@@ -195,7 +195,8 @@ METHOD(payload_t, verify, status_t,
 METHOD(payload_t, get_encoding_rules, int,
 	private_id_payload_t *this, encoding_rule_t **rules)
 {
-	if (this->type == ID_V1 || this->type == NAT_OA_V1)
+	if (this->type == ID_V1 ||
+		this->type == NAT_OA_V1 || this->type == NAT_OA_DRAFT_00_03_V1)
 	{
 		*rules = encodings_v1;
 		return countof(encodings_v1);
diff --git a/src/libcharon/encoding/payloads/payload.c b/src/libcharon/encoding/payloads/payload.c
index dc15847..467851a 100644
--- a/src/libcharon/encoding/payloads/payload.c
+++ b/src/libcharon/encoding/payloads/payload.c
@@ -79,20 +79,15 @@ ENUM_NEXT(payload_type_names, SECURITY_ASSOCIATION, GENERIC_SECURE_PASSWORD_METH
 #ifdef ME
 ENUM_NEXT(payload_type_names, ID_PEER, ID_PEER, GENERIC_SECURE_PASSWORD_METHOD,
 	"ID_PEER");
-ENUM_NEXT(payload_type_names, HEADER, ENCRYPTED_V1, ID_PEER,
-	"HEADER",
-	"PROPOSAL_SUBSTRUCTURE",
-	"PROPOSAL_SUBSTRUCTURE_V1",
-	"TRANSFORM_SUBSTRUCTURE",
-	"TRANSFORM_SUBSTRUCTURE_V1",
-	"TRANSFORM_ATTRIBUTE",
-	"TRANSFORM_ATTRIBUTE_V1",
-	"TRAFFIC_SELECTOR_SUBSTRUCTURE",
-	"CONFIGURATION_ATTRIBUTE",
-	"CONFIGURATION_ATTRIBUTE_V1",
-	"ENCRYPTED_V1");
+ENUM_NEXT(payload_type_names, NAT_D_DRAFT_00_03_V1, NAT_OA_DRAFT_00_03_V1, ID_PEER,
+	"NAT_D_DRAFT_V1",
+	"NAT_OA_DRAFT_V1");
 #else
-ENUM_NEXT(payload_type_names, HEADER, ENCRYPTED_V1, GENERIC_SECURE_PASSWORD_METHOD,
+ENUM_NEXT(payload_type_names, NAT_D_DRAFT_00_03_V1, NAT_OA_DRAFT_00_03_V1, GENERIC_SECURE_PASSWORD_METHOD,
+	"NAT_D_DRAFT_V1",
+	"NAT_OA_DRAFT_V1");
+#endif /* ME */
+ENUM_NEXT(payload_type_names, HEADER, ENCRYPTED_V1, NAT_OA_DRAFT_00_03_V1,
 	"HEADER",
 	"PROPOSAL_SUBSTRUCTURE",
 	"PROPOSAL_SUBSTRUCTURE_V1",
@@ -104,7 +99,6 @@ ENUM_NEXT(payload_type_names, HEADER, ENCRYPTED_V1, GENERIC_SECURE_PASSWORD_METH
 	"CONFIGURATION_ATTRIBUTE",
 	"CONFIGURATION_ATTRIBUTE_V1",
 	"ENCRYPTED_V1");
-#endif /* ME */
 ENUM_END(payload_type_names, ENCRYPTED_V1);
 
 /* short forms of payload names */
@@ -147,23 +141,17 @@ ENUM_NEXT(payload_type_short_names, SECURITY_ASSOCIATION, GENERIC_SECURE_PASSWOR
 	"EAP",
 	"GSPM");
 #ifdef ME
-ENUM_NEXT(payload_type_short_names, ID_PEER, ID_PEER,
-									GENERIC_SECURE_PASSWORD_METHOD,
+ENUM_NEXT(payload_type_short_names, ID_PEER, ID_PEER, GENERIC_SECURE_PASSWORD_METHOD,
 	"IDp");
-ENUM_NEXT(payload_type_short_names, HEADER, ENCRYPTED_V1, ID_PEER,
-	"HDR",
-	"PROP",
-	"PROP",
-	"TRANS",
-	"TRANS",
-	"TRANSATTR",
-	"TRANSATTR",
-	"TSSUB",
-	"CATTR",
-	"CATTR",
-	"E");
+ENUM_NEXT(payload_type_short_names, NAT_D_DRAFT_00_03_V1, NAT_OA_DRAFT_00_03_V1, ID_PEER,
+	"NAT-D",
+	"NAT-OA");
 #else
-ENUM_NEXT(payload_type_short_names, HEADER, ENCRYPTED_V1, GENERIC_SECURE_PASSWORD_METHOD,
+ENUM_NEXT(payload_type_short_names, NAT_D_DRAFT_00_03_V1, NAT_OA_DRAFT_00_03_V1, GENERIC_SECURE_PASSWORD_METHOD,
+	"NAT-D",
+	"NAT-OA");
+#endif /* ME */
+ENUM_NEXT(payload_type_short_names, HEADER, ENCRYPTED_V1, NAT_OA_DRAFT_00_03_V1,
 	"HDR",
 	"PROP",
 	"PROP",
@@ -175,7 +163,6 @@ ENUM_NEXT(payload_type_short_names, HEADER, ENCRYPTED_V1, GENERIC_SECURE_PASSWOR
 	"CATTR",
 	"CATTR",
 	"E");
-#endif /* ME */
 ENUM_END(payload_type_short_names, ENCRYPTED_V1);
 
 /*
@@ -209,6 +196,7 @@ payload_t *payload_create(payload_type_t type)
 #ifdef ME
 		case ID_PEER:
 #endif /* ME */
+		case NAT_OA_DRAFT_00_03_V1:
 			return (payload_t*)id_payload_create(type);
 		case AUTHENTICATION:
 			return (payload_t*)auth_payload_create();
@@ -239,6 +227,7 @@ payload_t *payload_create(payload_type_t type)
 		case HASH_V1:
 		case SIGNATURE_V1:
 		case NAT_D_V1:
+		case NAT_D_DRAFT_00_03_V1:
 			return (payload_t*)hash_payload_create(type);
 		case CONFIGURATION:
 		case CONFIGURATION_V1:
@@ -283,6 +272,10 @@ bool payload_is_known(payload_type_t type)
 		return TRUE;
 	}
 #endif
+	if (type >= NAT_D_DRAFT_00_03_V1 && type <= NAT_OA_DRAFT_00_03_V1)
+	{
+		return TRUE;
+	}
 	return FALSE;
 }
 
diff --git a/src/libcharon/encoding/payloads/payload.h b/src/libcharon/encoding/payloads/payload.h
index d5e8626..6b20862 100644
--- a/src/libcharon/encoding/payloads/payload.h
+++ b/src/libcharon/encoding/payloads/payload.h
@@ -221,6 +221,16 @@ enum payload_type_t {
 #endif /* ME */
 
 	/**
+	 * NAT discovery payload (NAT-D) (drafts).
+	 */
+	NAT_D_DRAFT_00_03_V1 = 130,
+
+	/**
+	 * NAT original address payload (NAT-OA) (drafts)
+	 */
+	NAT_OA_DRAFT_00_03_V1 = 131,
+
+	/**
 	 * Header has a value of PRIVATE USE space.
 	 *
 	 * This type and all the following are never sent over wire and are
diff --git a/src/libcharon/encoding/payloads/proposal_substructure.c b/src/libcharon/encoding/payloads/proposal_substructure.c
index 653f51a..51ecb7e 100644
--- a/src/libcharon/encoding/payloads/proposal_substructure.c
+++ b/src/libcharon/encoding/payloads/proposal_substructure.c
@@ -253,6 +253,8 @@ typedef enum {
   IKEV1_ENCAP_TRANSPORT = 2,
   IKEV1_ENCAP_UDP_TUNNEL = 3,
   IKEV1_ENCAP_UDP_TRANSPORT = 4,
+  IKEV1_ENCAP_UDP_TUNNEL_DRAFT_00_03 = 61443,
+  IKEV1_ENCAP_UDP_TRANSPORT_DRAFT_00_03 = 61444,
 } ikev1_esp_encap_t;
 
 /**
@@ -810,14 +812,30 @@ static u_int16_t get_ikev1_auth(auth_method_t method)
 /**
  * Get IKEv1 encapsulation mode
  */
-static u_int16_t get_ikev1_mode(ipsec_mode_t mode, bool udp)
+static u_int16_t get_ikev1_mode(ipsec_mode_t mode, encap_t udp)
 {
 	switch (mode)
 	{
 		case MODE_TUNNEL:
-			return udp ? IKEV1_ENCAP_UDP_TUNNEL : IKEV1_ENCAP_TUNNEL;
+			switch (udp)
+			{
+				case ENCAP_UDP:
+					return IKEV1_ENCAP_UDP_TUNNEL;
+				case ENCAP_UDP_DRAFT_00_03:
+					return IKEV1_ENCAP_UDP_TUNNEL_DRAFT_00_03;
+				default:
+					return IKEV1_ENCAP_TUNNEL;
+			}
 		case MODE_TRANSPORT:
-			return udp ? IKEV1_ENCAP_UDP_TRANSPORT : IKEV1_ENCAP_TRANSPORT;
+			switch (udp)
+			{
+				case ENCAP_UDP:
+					return IKEV1_ENCAP_UDP_TRANSPORT;
+				case ENCAP_UDP_DRAFT_00_03:
+					return IKEV1_ENCAP_UDP_TRANSPORT_DRAFT_00_03;
+				default:
+					return IKEV1_ENCAP_TRANSPORT;
+			}
 		default:
 			return IKEV1_ENCAP_TUNNEL;
 	}
@@ -1125,9 +1143,11 @@ METHOD(proposal_substructure_t, get_encap_mode, ipsec_mode_t,
 		case IKEV1_ENCAP_TUNNEL:
 			return MODE_TUNNEL;
 		case IKEV1_ENCAP_UDP_TRANSPORT:
+		case IKEV1_ENCAP_UDP_TRANSPORT_DRAFT_00_03:
 			*udp = TRUE;
 			return MODE_TRANSPORT;
 		case IKEV1_ENCAP_UDP_TUNNEL:
+		case IKEV1_ENCAP_UDP_TUNNEL_DRAFT_00_03:
 			*udp = TRUE;
 			return MODE_TUNNEL;
 		default:
@@ -1263,7 +1283,7 @@ static void set_from_proposal_v1_ike(private_proposal_substructure_t *this,
  */
 static void set_from_proposal_v1_esp(private_proposal_substructure_t *this,
 				proposal_t *proposal, u_int32_t lifetime, u_int64_t lifebytes,
-				ipsec_mode_t mode, bool udp, int number)
+				ipsec_mode_t mode, encap_t udp, int number)
 {
 	transform_substructure_t *transform = NULL;
 	u_int16_t alg, key_size;
@@ -1459,7 +1479,7 @@ proposal_substructure_t *proposal_substructure_create_from_proposal_v2(
  */
 proposal_substructure_t *proposal_substructure_create_from_proposal_v1(
 			proposal_t *proposal, u_int32_t lifetime, u_int64_t lifebytes,
-			auth_method_t auth, ipsec_mode_t mode, bool udp)
+			auth_method_t auth, ipsec_mode_t mode, encap_t udp)
 {
 	private_proposal_substructure_t *this;
 
@@ -1487,7 +1507,7 @@ proposal_substructure_t *proposal_substructure_create_from_proposal_v1(
  */
 proposal_substructure_t *proposal_substructure_create_from_proposals_v1(
 			linked_list_t *proposals, u_int32_t lifetime, u_int64_t lifebytes,
-			auth_method_t auth, ipsec_mode_t mode, bool udp)
+			auth_method_t auth, ipsec_mode_t mode, encap_t udp)
 {
 	private_proposal_substructure_t *this = NULL;
 	enumerator_t *enumerator;
@@ -1531,7 +1551,7 @@ proposal_substructure_t *proposal_substructure_create_from_proposals_v1(
  */
 proposal_substructure_t *proposal_substructure_create_for_ipcomp_v1(
 			u_int32_t lifetime, u_int64_t lifebytes, u_int16_t cpi,
-			ipsec_mode_t mode, bool udp, u_int8_t proposal_number)
+			ipsec_mode_t mode, encap_t udp, u_int8_t proposal_number)
 {
 	private_proposal_substructure_t *this;
 	transform_substructure_t *transform;
diff --git a/src/libcharon/encoding/payloads/proposal_substructure.h b/src/libcharon/encoding/payloads/proposal_substructure.h
index 5d42a61..23a6dc0 100644
--- a/src/libcharon/encoding/payloads/proposal_substructure.h
+++ b/src/libcharon/encoding/payloads/proposal_substructure.h
@@ -23,6 +23,7 @@
 #ifndef PROPOSAL_SUBSTRUCTURE_H_
 #define PROPOSAL_SUBSTRUCTURE_H_
 
+typedef enum encap_t encap_t;
 typedef struct proposal_substructure_t proposal_substructure_t;
 
 #include <library.h>
@@ -34,6 +35,15 @@ typedef struct proposal_substructure_t proposal_substructure_t;
 #include <sa/authenticator.h>
 
 /**
+ * Encap type for proposal substructure
+ */
+enum encap_t {
+	ENCAP_NONE = 0,
+	ENCAP_UDP,
+	ENCAP_UDP_DRAFT_00_03,
+};
+
+/**
  * Class representing an IKEv1/IKEv2 proposal substructure.
  */
 struct proposal_substructure_t {
@@ -179,12 +189,12 @@ proposal_substructure_t *proposal_substructure_create_from_proposal_v2(
  * @param lifebytes	lifebytes, in bytes
  * @param auth		authentication method to use, or AUTH_NONE
  * @param mode		IPsec encapsulation mode, TRANSPORT or TUNNEL
- * @param udp		TRUE to use UDP encapsulation
+ * @param udp		ENCAP_UDP to use UDP encapsulation
  * @return			proposal_substructure_t object PROPOSAL_SUBSTRUCTURE_V1
  */
 proposal_substructure_t *proposal_substructure_create_from_proposal_v1(
 			proposal_t *proposal,  u_int32_t lifetime, u_int64_t lifebytes,
-			auth_method_t auth, ipsec_mode_t mode, bool udp);
+			auth_method_t auth, ipsec_mode_t mode, encap_t udp);
 
 /**
  * Creates an IKEv1 proposal_substructure_t from a list of proposal_t.
@@ -194,12 +204,12 @@ proposal_substructure_t *proposal_substructure_create_from_proposal_v1(
  * @param lifebytes	lifebytes, in bytes
  * @param auth		authentication method to use, or AUTH_NONE
  * @param mode		IPsec encapsulation mode, TRANSPORT or TUNNEL
- * @param udp		TRUE to use UDP encapsulation
+ * @param udp		ENCAP_UDP to use UDP encapsulation
  * @return			IKEv1 proposal_substructure_t PROPOSAL_SUBSTRUCTURE_V1
  */
 proposal_substructure_t *proposal_substructure_create_from_proposals_v1(
 			linked_list_t *proposals, u_int32_t lifetime, u_int64_t lifebytes,
-			auth_method_t auth, ipsec_mode_t mode, bool udp);
+			auth_method_t auth, ipsec_mode_t mode, encap_t udp);
 
 /**
  * Creates an IKEv1 proposal_substructure_t for IPComp with the given
@@ -209,12 +219,12 @@ proposal_substructure_t *proposal_substructure_create_from_proposals_v1(
  * @param lifebytes			lifebytes, in bytes
  * @param cpi				the CPI to be used
  * @param mode				IPsec encapsulation mode, TRANSPORT or TUNNEL
- * @param udp				TRUE to use UDP encapsulation
+ * @param udp				ENCAP_UDP to use UDP encapsulation
  * @param proposal_number	the proposal number of the proposal to be linked
  * @return					IKEv1 proposal_substructure_t PROPOSAL_SUBSTRUCTURE_V1
  */
 proposal_substructure_t *proposal_substructure_create_for_ipcomp_v1(
 			u_int32_t lifetime, u_int64_t lifebytes, u_int16_t cpi,
-			ipsec_mode_t mode, bool udp, u_int8_t proposal_number);
+			ipsec_mode_t mode, encap_t udp, u_int8_t proposal_number);
 
 #endif /** PROPOSAL_SUBSTRUCTURE_H_ @}*/
diff --git a/src/libcharon/encoding/payloads/sa_payload.c b/src/libcharon/encoding/payloads/sa_payload.c
index adf19aa..e37a94d 100644
--- a/src/libcharon/encoding/payloads/sa_payload.c
+++ b/src/libcharon/encoding/payloads/sa_payload.c
@@ -552,8 +552,8 @@ sa_payload_t *sa_payload_create_from_proposal_v2(proposal_t *proposal)
  */
 sa_payload_t *sa_payload_create_from_proposals_v1(linked_list_t *proposals,
 								u_int32_t lifetime, u_int64_t lifebytes,
-								auth_method_t auth, ipsec_mode_t mode, bool udp,
-								u_int16_t cpi)
+								auth_method_t auth, ipsec_mode_t mode,
+								encap_t udp, u_int16_t cpi)
 {
 	proposal_substructure_t *substruct;
 	private_sa_payload_t *this;
@@ -591,8 +591,8 @@ sa_payload_t *sa_payload_create_from_proposals_v1(linked_list_t *proposals,
  */
 sa_payload_t *sa_payload_create_from_proposal_v1(proposal_t *proposal,
 								u_int32_t lifetime, u_int64_t lifebytes,
-								auth_method_t auth, ipsec_mode_t mode, bool udp,
-								u_int16_t cpi)
+								auth_method_t auth, ipsec_mode_t mode,
+								encap_t udp, u_int16_t cpi)
 {
 	private_sa_payload_t *this;
 	linked_list_t *proposals;
diff --git a/src/libcharon/encoding/payloads/sa_payload.h b/src/libcharon/encoding/payloads/sa_payload.h
index 9a88ccc..466ec8b 100644
--- a/src/libcharon/encoding/payloads/sa_payload.h
+++ b/src/libcharon/encoding/payloads/sa_payload.h
@@ -133,13 +133,13 @@ sa_payload_t *sa_payload_create_from_proposal_v2(proposal_t *proposal);
  * @param lifebytes			lifebytes, in bytes
  * @param auth				authentication method to use, or AUTH_NONE
  * @param mode				IPsec encapsulation mode, TRANSPORT or TUNNEL
- * @param udp				TRUE to use UDP encapsulation
+ * @param udp				ENCAP_UDP to use UDP encapsulation
  * @param cpi				CPI in case IPComp should be used
  * @return					sa_payload_t object
  */
 sa_payload_t *sa_payload_create_from_proposals_v1(linked_list_t *proposals,
 							u_int32_t lifetime, u_int64_t lifebytes,
-							auth_method_t auth, ipsec_mode_t mode, bool udp,
+							auth_method_t auth, ipsec_mode_t mode, encap_t udp,
 							u_int16_t cpi);
 
 /**
@@ -150,13 +150,13 @@ sa_payload_t *sa_payload_create_from_proposals_v1(linked_list_t *proposals,
  * @param lifebytes			lifebytes, in bytes
  * @param auth				authentication method to use, or AUTH_NONE
  * @param mode				IPsec encapsulation mode, TRANSPORT or TUNNEL
- * @param udp				TRUE to use UDP encapsulation
+ * @param udp				ENCAP_UDP to use UDP encapsulation
  * @param cpi				CPI in case IPComp should be used
  * @return					sa_payload_t object
  */
 sa_payload_t *sa_payload_create_from_proposal_v1(proposal_t *proposal,
 							u_int32_t lifetime, u_int64_t lifebytes,
-							auth_method_t auth, ipsec_mode_t mode, bool udp,
+							auth_method_t auth, ipsec_mode_t mode, encap_t udp,
 							u_int16_t cpi);
 
 #endif /** SA_PAYLOAD_H_ @}*/
diff --git a/src/libcharon/sa/ike_sa.h b/src/libcharon/sa/ike_sa.h
index af741c7..12ca76f 100644
--- a/src/libcharon/sa/ike_sa.h
+++ b/src/libcharon/sa/ike_sa.h
@@ -72,6 +72,7 @@ enum ike_extension_t {
 
 	/**
 	 * peer supports NAT traversal as specified in RFC4306 or RFC3947
+	 * including some RFC3947 drafts
 	 */
 	EXT_NATT = (1<<0),
 
@@ -119,6 +120,29 @@ enum ike_extension_t {
 	 * peer supports Cisco Unity configuration attributes
 	 */
 	EXT_CISCO_UNITY = (1<<9),
+
+	/**
+	 * peer supports NAT traversal as specified in RFC3947
+	 */
+	EXT_NATT_RFC = (1<<10),
+
+	/**
+	 * peer supports NAT traversal as specified in
+	 * draft-ietf-ipsec-nat-t-ike-03
+	 */
+	EXT_NATT_DRAFT_03 = (1<<11),
+
+	/**
+	 * peer supports NAT traversal as specified in
+	 * draft-ietf-ipsec-nat-t-ike-02
+	 */
+	EXT_NATT_DRAFT_02 = (1<<12),
+
+	/**
+	 * peer supports NAT traversal as specified in
+	 * draft-ietf-ipsec-nat-t-ike-02 with wrong vendor id
+	 */
+	EXT_NATT_DRAFT_02N = (1<<13),
 };
 
 /**
diff --git a/src/libcharon/sa/ikev1/tasks/aggressive_mode.c b/src/libcharon/sa/ikev1/tasks/aggressive_mode.c
index 954dea8..e901cd9 100644
--- a/src/libcharon/sa/ikev1/tasks/aggressive_mode.c
+++ b/src/libcharon/sa/ikev1/tasks/aggressive_mode.c
@@ -235,7 +235,8 @@ METHOD(task_t, build_i, status_t,
 			this->lifetime += this->peer_cfg->get_over_time(this->peer_cfg);
 			proposals = this->ike_cfg->get_proposals(this->ike_cfg);
 			sa_payload = sa_payload_create_from_proposals_v1(proposals,
-						this->lifetime, 0, this->method, MODE_NONE, FALSE, 0);
+						this->lifetime, 0, this->method, MODE_NONE, ENCAP_NONE,
+						0);
 			proposals->destroy_offset(proposals, offsetof(proposal_t, destroy));
 
 			message->add_payload(message, &sa_payload->payload_interface);
@@ -520,7 +521,8 @@ METHOD(task_t, build_r, status_t,
 		identification_t *id;
 
 		sa_payload = sa_payload_create_from_proposal_v1(this->proposal,
-						this->lifetime, 0, this->method, MODE_NONE, FALSE, 0);
+						this->lifetime, 0, this->method, MODE_NONE, ENCAP_NONE,
+						0);
 		message->add_payload(message, &sa_payload->payload_interface);
 
 		if (!this->ph1->add_nonce_ke(this->ph1, message))
diff --git a/src/libcharon/sa/ikev1/tasks/isakmp_natd.c b/src/libcharon/sa/ikev1/tasks/isakmp_natd.c
index 50bf161..48b933e 100644
--- a/src/libcharon/sa/ikev1/tasks/isakmp_natd.c
+++ b/src/libcharon/sa/ikev1/tasks/isakmp_natd.c
@@ -75,6 +75,18 @@ struct private_isakmp_natd_t {
 };
 
 /**
+ * Get NAT-D payload type (RFC 3947 or RFC 3947 drafts).
+ */
+static payload_type_t get_nat_d_payload_type(ike_sa_t *ike_sa)
+{
+	if (ike_sa->supports_extension(ike_sa, EXT_NATT_RFC))
+	{
+		return NAT_D_V1;
+	}
+	return NAT_D_DRAFT_00_03_V1;
+}
+
+/**
  * Build NAT detection hash for a host.
  */
 static chunk_t generate_natd_hash(private_isakmp_natd_t *this,
@@ -162,7 +174,7 @@ static hash_payload_t *build_natd_payload(private_isakmp_natd_t *this, bool src,
 	{
 		return NULL;
 	}
-	payload = hash_payload_create(NAT_D_V1);
+	payload = hash_payload_create(get_nat_d_payload_type(this->ike_sa));
 	payload->set_hash(payload, hash);
 	chunk_free(&hash);
 	return payload;
@@ -221,7 +233,8 @@ static void process_payloads(private_isakmp_natd_t *this, message_t *message)
 	enumerator = message->create_payload_enumerator(message);
 	while (enumerator->enumerate(enumerator, &payload))
 	{
-		if (payload->get_type(payload) != NAT_D_V1)
+		if (payload->get_type(payload) != NAT_D_V1 &&
+			payload->get_type(payload) != NAT_D_DRAFT_00_03_V1)
 		{
 			continue;
 		}
diff --git a/src/libcharon/sa/ikev1/tasks/isakmp_vendor.c b/src/libcharon/sa/ikev1/tasks/isakmp_vendor.c
index 4fd0ef3..4c87f54 100644
--- a/src/libcharon/sa/ikev1/tasks/isakmp_vendor.c
+++ b/src/libcharon/sa/ikev1/tasks/isakmp_vendor.c
@@ -65,52 +65,53 @@ static struct {
 	{ "XAuth", EXT_XAUTH, TRUE, 8,
 	  "\x09\x00\x26\x89\xdf\xd6\xb7\x12"},
 
-	/* NAT-Traversal, MD5("RFC 3947") */
-	{ "NAT-T (RFC 3947)", EXT_NATT, TRUE, 16,
-	  "\x4a\x13\x1c\x81\x07\x03\x58\x45\x5c\x57\x28\xf2\x0e\x95\x45\x2f"},
-
 	/* Dead peer detection, RFC 3706 */
 	{ "DPD", EXT_DPD, TRUE, 16,
 	  "\xaf\xca\xd7\x13\x68\xa1\xf1\xc9\x6b\x86\x96\xfc\x77\x57\x01\x00"},
 
-	{ "draft-stenberg-ipsec-nat-traversal-01", 0, FALSE, 16,
-	  "\x27\xba\xb5\xdc\x01\xea\x07\x60\xea\x4e\x31\x90\xac\x27\xc0\xd0"},
-
-	{ "draft-stenberg-ipsec-nat-traversal-02", 0, FALSE, 16,
-	  "\x61\x05\xc4\x22\xe7\x68\x47\xe4\x3f\x96\x84\x80\x12\x92\xae\xcd"},
+	{ "Cisco Unity", EXT_CISCO_UNITY, FALSE, 16,
+	  "\x12\xf5\xf2\x8c\x45\x71\x68\xa9\x70\x2d\x9f\xe2\x74\xcc\x01\x00"},
+}, vendor_natt_ids[] = {
 
-	{ "draft-ietf-ipsec-nat-t-ike", 0, FALSE, 16,
-	  "\x4d\xf3\x79\x28\xe9\xfc\x4f\xd1\xb3\x26\x21\x70\xd5\x15\xc6\x62"},
+	/* NAT-Traversal, MD5("RFC 3947") */
+	{ "NAT-T (RFC 3947)", EXT_NATT_RFC, TRUE, 16,
+	  "\x4a\x13\x1c\x81\x07\x03\x58\x45\x5c\x57\x28\xf2\x0e\x95\x45\x2f"},
 
-	{ "draft-ietf-ipsec-nat-t-ike-00", 0, FALSE, 16,
-	  "\x44\x85\x15\x2d\x18\xb6\xbb\xcd\x0b\xe8\xa8\x46\x95\x79\xdd\xcc"},
+	{ "draft-ietf-ipsec-nat-t-ike-03", EXT_NATT_DRAFT_03, FALSE, 16,
+	  "\x7d\x94\x19\xa6\x53\x10\xca\x6f\x2c\x17\x9d\x92\x15\x52\x9d\x56"},
 
-	{ "draft-ietf-ipsec-nat-t-ike-02", 0, FALSE, 16,
+	{ "draft-ietf-ipsec-nat-t-ike-02", EXT_NATT_DRAFT_02, FALSE, 16,
 	  "\xcd\x60\x46\x43\x35\xdf\x21\xf8\x7c\xfd\xb2\xfc\x68\xb6\xa4\x48"},
 
-	{ "draft-ietf-ipsec-nat-t-ike-02\\n", 0, FALSE, 16,
+	{ "draft-ietf-ipsec-nat-t-ike-02\\n", EXT_NATT_DRAFT_02N, TRUE, 16,
 	  "\x90\xcb\x80\x91\x3e\xbb\x69\x6e\x08\x63\x81\xb5\xec\x42\x7b\x1f"},
 
-	{ "draft-ietf-ipsec-nat-t-ike-03", 0, FALSE, 16,
-	  "\x7d\x94\x19\xa6\x53\x10\xca\x6f\x2c\x17\x9d\x92\x15\x52\x9d\x56"},
+	{ "draft-ietf-ipsec-nat-t-ike-08", 0, FALSE, 16,
+	  "\x8f\x8d\x83\x82\x6d\x24\x6b\x6f\xc7\xa8\xa6\xa4\x28\xc1\x1d\xe8"},
 
-	{ "draft-ietf-ipsec-nat-t-ike-04", 0, FALSE, 16,
-	  "\x99\x09\xb6\x4e\xed\x93\x7c\x65\x73\xde\x52\xac\xe9\x52\xfa\x6b"},
+	{ "draft-ietf-ipsec-nat-t-ike-07", 0, FALSE, 16,
+	  "\x43\x9b\x59\xf8\xba\x67\x6c\x4c\x77\x37\xae\x22\xea\xb8\xf5\x82"},
+
+	{ "draft-ietf-ipsec-nat-t-ike-06", 0, FALSE, 16,
+	  "\x4d\x1e\x0e\x13\x6d\xea\xfa\x34\xc4\xf3\xea\x9f\x02\xec\x72\x85"},
 
 	{ "draft-ietf-ipsec-nat-t-ike-05", 0, FALSE, 16,
 	  "\x80\xd0\xbb\x3d\xef\x54\x56\x5e\xe8\x46\x45\xd4\xc8\x5c\xe3\xee"},
 
-	{ "draft-ietf-ipsec-nat-t-ike-06", 0, FALSE, 16,
-	  "\x4d\x1e\x0e\x13\x6d\xea\xfa\x34\xc4\xf3\xea\x9f\x02\xec\x72\x85"},
+	{ "draft-ietf-ipsec-nat-t-ike-04", 0, FALSE, 16,
+	  "\x99\x09\xb6\x4e\xed\x93\x7c\x65\x73\xde\x52\xac\xe9\x52\xfa\x6b"},
 
-	{ "draft-ietf-ipsec-nat-t-ike-07", 0, FALSE, 16,
-	  "\x43\x9b\x59\xf8\xba\x67\x6c\x4c\x77\x37\xae\x22\xea\xb8\xf5\x82"},
+	{ "draft-ietf-ipsec-nat-t-ike-00", 0, FALSE, 16,
+	  "\x44\x85\x15\x2d\x18\xb6\xbb\xcd\x0b\xe8\xa8\x46\x95\x79\xdd\xcc"},
 
-	{ "draft-ietf-ipsec-nat-t-ike-08", 0, FALSE, 16,
-	  "\x8f\x8d\x83\x82\x6d\x24\x6b\x6f\xc7\xa8\xa6\xa4\x28\xc1\x1d\xe8"},
+	{ "draft-ietf-ipsec-nat-t-ike", 0, FALSE, 16,
+	  "\x4d\xf3\x79\x28\xe9\xfc\x4f\xd1\xb3\x26\x21\x70\xd5\x15\xc6\x62"},
 
-	{ "Cisco Unity", EXT_CISCO_UNITY, FALSE, 16,
-	  "\x12\xf5\xf2\x8c\x45\x71\x68\xa9\x70\x2d\x9f\xe2\x74\xcc\x01\x00"},
+	{ "draft-stenberg-ipsec-nat-traversal-02", 0, FALSE, 16,
+	  "\x61\x05\xc4\x22\xe7\x68\x47\xe4\x3f\x96\x84\x80\x12\x92\xae\xcd"},
+
+	{ "draft-stenberg-ipsec-nat-traversal-01", 0, FALSE, 16,
+	  "\x27\xba\xb5\xdc\x01\xea\x07\x60\xea\x4e\x31\x90\xac\x27\xc0\xd0"},
 };
 
 METHOD(task_t, build, status_t,
@@ -135,6 +136,18 @@ METHOD(task_t, build, status_t,
 			message->add_payload(message, &vid_payload->payload_interface);
 		}
 	}
+	for (i = 0; i < countof(vendor_natt_ids); i++)
+	{
+		if (this->initiator && vendor_natt_ids[i].send ||
+			this->ike_sa->supports_extension(this->ike_sa,
+			vendor_natt_ids[i].extension))
+		{
+			vid_payload = vendor_id_payload_create_data(VENDOR_ID_V1,
+				chunk_clone(
+				chunk_create(vendor_natt_ids[i].id, vendor_natt_ids[i].len)));
+			message->add_payload(message, &vid_payload->payload_interface);
+		}
+	}
 	return this->initiator ? NEED_MORE : SUCCESS;
 }
 
@@ -143,7 +156,7 @@ METHOD(task_t, process, status_t,
 {
 	enumerator_t *enumerator;
 	payload_t *payload;
-	int i;
+	int i, best_natt_ext = -1;
 
 	enumerator = message->create_payload_enumerator(message);
 	while (enumerator->enumerate(enumerator, &payload))
@@ -169,6 +182,26 @@ METHOD(task_t, process, status_t,
 													   vendor_ids[i].extension);
 					}
 					found = TRUE;
+					break;
+				}
+			}
+			if (!found)
+			{
+				for (i = 0; i < countof(vendor_natt_ids); i++)
+				{
+					if (chunk_equals(data, chunk_create(vendor_natt_ids[i].id,
+											vendor_natt_ids[i].len)))
+					{
+						DBG1(DBG_IKE, "received %s vendor ID",
+							 vendor_natt_ids[i].desc);
+						if (vendor_natt_ids[i].extension &&
+						   (i < best_natt_ext || best_natt_ext < 0))
+						{
+							best_natt_ext = i;
+						}
+						found = TRUE;
+						break;
+					}
 				}
 			}
 			if (!found)
@@ -179,6 +212,13 @@ METHOD(task_t, process, status_t,
 	}
 	enumerator->destroy(enumerator);
 
+	if (best_natt_ext >= 0)
+	{
+		this->ike_sa->enable_extension(this->ike_sa, EXT_NATT);
+		this->ike_sa->enable_extension(this->ike_sa,
+			vendor_natt_ids[best_natt_ext].extension);
+	}
+
 	return this->initiator ? SUCCESS : NEED_MORE;
 }
 
diff --git a/src/libcharon/sa/ikev1/tasks/main_mode.c b/src/libcharon/sa/ikev1/tasks/main_mode.c
index 9ccf9ab..1b6387b 100644
--- a/src/libcharon/sa/ikev1/tasks/main_mode.c
+++ b/src/libcharon/sa/ikev1/tasks/main_mode.c
@@ -241,7 +241,8 @@ METHOD(task_t, build_i, status_t,
 			this->lifetime += this->peer_cfg->get_over_time(this->peer_cfg);
 			proposals = this->ike_cfg->get_proposals(this->ike_cfg);
 			sa_payload = sa_payload_create_from_proposals_v1(proposals,
-						this->lifetime, 0, this->method, MODE_NONE, FALSE, 0);
+						this->lifetime, 0, this->method, MODE_NONE, ENCAP_NONE,
+						0);
 			proposals->destroy_offset(proposals, offsetof(proposal_t, destroy));
 
 			message->add_payload(message, &sa_payload->payload_interface);
@@ -455,7 +456,8 @@ METHOD(task_t, build_r, status_t,
 			sa_payload_t *sa_payload;
 
 			sa_payload = sa_payload_create_from_proposal_v1(this->proposal,
-						this->lifetime, 0, this->method, MODE_NONE, FALSE, 0);
+						this->lifetime, 0, this->method, MODE_NONE, ENCAP_NONE,
+						0);
 			message->add_payload(message, &sa_payload->payload_interface);
 
 			return NEED_MORE;
diff --git a/src/libcharon/sa/ikev1/tasks/quick_mode.c b/src/libcharon/sa/ikev1/tasks/quick_mode.c
index 82a7238..561be14 100644
--- a/src/libcharon/sa/ikev1/tasks/quick_mode.c
+++ b/src/libcharon/sa/ikev1/tasks/quick_mode.c
@@ -596,6 +596,34 @@ static bool get_ts(private_quick_mode_t *this, message_t *message)
 }
 
 /**
+ * Get encap
+ */
+static encap_t get_encap(ike_sa_t* ike_sa, bool udp)
+{
+	if (!udp)
+	{
+		return ENCAP_NONE;
+	}
+	if (ike_sa->supports_extension(ike_sa, EXT_NATT_RFC))
+	{
+		return ENCAP_UDP;
+	}
+	return ENCAP_UDP_DRAFT_00_03;
+}
+
+/**
+ * Get NAT-OA payload type (RFC 3947 or RFC 3947 drafts).
+ */
+static payload_type_t get_nat_oa_payload_type(ike_sa_t *ike_sa)
+{
+	if (ike_sa->supports_extension(ike_sa, EXT_NATT_RFC))
+	{
+		return NAT_OA_V1;
+	}
+	return NAT_OA_DRAFT_00_03_V1;
+}
+
+/**
  * Add NAT-OA payloads
  */
 static void add_nat_oa_payloads(private_quick_mode_t *this, message_t *message)
@@ -603,6 +631,7 @@ static void add_nat_oa_payloads(private_quick_mode_t *this, message_t *message)
 	identification_t *id;
 	id_payload_t *nat_oa;
 	host_t *src, *dst;
+	payload_type_t nat_oa_payload_type;
 
 	src = message->get_source(message);
 	dst = message->get_destination(message);
@@ -610,15 +639,17 @@ static void add_nat_oa_payloads(private_quick_mode_t *this, message_t *message)
 	src = this->initiator ? src : dst;
 	dst = this->initiator ? dst : src;
 
+	nat_oa_payload_type = get_nat_oa_payload_type(this->ike_sa);
+
 	/* first NAT-OA is the initiator's address */
 	id = identification_create_from_sockaddr(src->get_sockaddr(src));
-	nat_oa = id_payload_create_from_identification(NAT_OA_V1, id);
+	nat_oa = id_payload_create_from_identification(nat_oa_payload_type, id);
 	message->add_payload(message, (payload_t*)nat_oa);
 	id->destroy(id);
 
 	/* second NAT-OA is that of the responder */
 	id = identification_create_from_sockaddr(dst->get_sockaddr(dst));
-	nat_oa = id_payload_create_from_identification(NAT_OA_V1, id);
+	nat_oa = id_payload_create_from_identification(nat_oa_payload_type, id);
 	message->add_payload(message, (payload_t*)nat_oa);
 	id->destroy(id);
 }
@@ -697,6 +728,7 @@ METHOD(task_t, build_i, status_t,
 			linked_list_t *list, *tsi, *tsr;
 			proposal_t *proposal;
 			diffie_hellman_group_t group;
+			encap_t encap;
 
 			this->udp = this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY);
 			this->mode = this->config->get_mode(this->config);
@@ -745,9 +777,10 @@ METHOD(task_t, build_i, status_t,
 			enumerator->destroy(enumerator);
 
 			get_lifetimes(this);
+			encap = get_encap(this->ike_sa, this->udp);
 			sa_payload = sa_payload_create_from_proposals_v1(list,
 								this->lifetime, this->lifebytes, AUTH_NONE,
-								this->mode, this->udp, this->cpi_i);
+								this->mode, encap, this->cpi_i);
 			list->destroy_offset(list, offsetof(proposal_t, destroy));
 			message->add_payload(message, &sa_payload->payload_interface);
 
@@ -1048,6 +1081,7 @@ METHOD(task_t, build_r, status_t,
 		case QM_INIT:
 		{
 			sa_payload_t *sa_payload;
+			encap_t encap;
 
 			this->spi_r = this->child_sa->alloc_spi(this->child_sa, PROTO_ESP);
 			if (!this->spi_r)
@@ -1074,9 +1108,10 @@ METHOD(task_t, build_r, status_t,
 				add_nat_oa_payloads(this, message);
 			}
 
+			encap = get_encap(this->ike_sa, this->udp);
 			sa_payload = sa_payload_create_from_proposal_v1(this->proposal,
 								this->lifetime, this->lifebytes, AUTH_NONE,
-								this->mode, this->udp, this->cpi_r);
+								this->mode, encap, this->cpi_r);
 			message->add_payload(message, &sa_payload->payload_interface);
 
 			if (!add_nonce(this, &this->nonce_r, message))
-- 
1.7.3.4





More information about the Dev mailing list