implemented IKEv2 force_encap connection parameter
authorMartin Willi <martin@strongswan.org>
Mon, 1 Oct 2007 12:19:39 +0000 (12:19 -0000)
committerMartin Willi <martin@strongswan.org>
Mon, 1 Oct 2007 12:19:39 +0000 (12:19 -0000)
  enforces UDP encapsulation by faking NAT detection payloads
  to hurdle restrictive firewalls

16 files changed:
src/charon/config/backends/sqlite_backend.c
src/charon/config/peer_cfg.c
src/charon/config/peer_cfg.h
src/charon/control/interfaces/stroke_interface.c
src/charon/sa/child_sa.c
src/charon/sa/ike_sa.c
src/charon/sa/ike_sa.h
src/charon/sa/tasks/ike_natd.c
src/pluto/constants.h
src/starter/args.c
src/starter/confread.c
src/starter/ipsec.conf.5
src/starter/keywords.h
src/starter/keywords.txt
src/stroke/stroke.c
src/stroke/stroke.h

index 2db90f9..be94f9b 100644 (file)
@@ -192,6 +192,7 @@ static peer_cfg_t *process_peer_cfg_row(private_sqlite_backend_t *this,
                        sqlite3_column_int(stmt, 10),                           /* jitter */
                        sqlite3_column_int(stmt, 13),                           /* reauth */
                        sqlite3_column_int(stmt, 14),                           /* mobike */
+                       FALSE,                                                                          /* force_encap */
                        sqlite3_column_int(stmt, 11),                           /* dpd_delay */
                        sqlite3_column_int(stmt, 12),                           /* dpd_action */
                        local_vip, remote_vip);
index 6733df0..7935b97 100644 (file)
@@ -141,6 +141,11 @@ struct private_peer_cfg_t {
        bool use_mobike;
        
        /**
+        * enforce UDP encapsulation
+        */
+       bool force_encap;
+       
+       /**
         * Time before an SA gets invalid
         */
        u_int32_t lifetime;
@@ -364,6 +369,14 @@ static bool use_mobike(private_peer_cfg_t *this)
 {
        return this->use_mobike;
 }
+       
+/**
+ * Implementation of peer_cfg_t.force_encap.
+ */
+static bool force_encap_meth(private_peer_cfg_t *this)
+{
+       return this->force_encap;
+}
 
 /**
  * Implements peer_cfg_t.get_dpd_delay
@@ -452,7 +465,7 @@ peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg,
                                                        auth_method_t auth_method, eap_type_t eap_type,
                                                        u_int32_t keyingtries, u_int32_t lifetime,
                                                        u_int32_t rekeytime, u_int32_t jitter,
-                                                       bool reauth, bool mobike,
+                                                       bool reauth, bool mobike, bool force_encap,
                                                        u_int32_t dpd_delay, dpd_action_t dpd_action,
                                                        host_t *my_virtual_ip, host_t *other_virtual_ip)
 {
@@ -477,6 +490,7 @@ peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg,
        this->public.get_lifetime = (u_int32_t (*) (peer_cfg_t *, bool rekey))get_lifetime;
        this->public.use_reauth = (bool (*) (peer_cfg_t *))use_reauth;
        this->public.use_mobike = (bool (*) (peer_cfg_t *))use_mobike;
+       this->public.force_encap = (bool (*) (peer_cfg_t *))force_encap_meth;
        this->public.get_dpd_delay = (u_int32_t (*) (peer_cfg_t *))get_dpd_delay;
        this->public.get_dpd_action = (dpd_action_t (*) (peer_cfg_t *))get_dpd_action;
        this->public.get_my_virtual_ip = (host_t* (*) (peer_cfg_t *))get_my_virtual_ip;
@@ -504,6 +518,7 @@ peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg,
        this->jitter = jitter;
        this->use_reauth = reauth;
        this->use_mobike = mobike;
+       this->force_encap = force_encap;
        this->dpd_delay = dpd_delay;
        this->dpd_action = dpd_action;
        this->my_virtual_ip = my_virtual_ip;
index 1c6051f..ecd6bcf 100644 (file)
@@ -274,6 +274,14 @@ struct peer_cfg_t {
        bool (*use_mobike) (peer_cfg_t *this);
        
        /**
+        * @brief Enforce UDP encapsulation by faking NATD notifies?
+        * 
+        * @param this          calling object
+        * @return                      TRUE to enfoce UDP encapsulation
+        */
+       bool (*force_encap) (peer_cfg_t *this);
+       
+       /**
         * @brief Get the DPD check interval.
         * 
         * @param this          calling object
@@ -364,8 +372,9 @@ struct peer_cfg_t {
  * @param lifetime                     lifetime before deleting an SA
  * @param rekeytime                    lifetime before rekeying an SA
  * @param jitter                       range of random to substract from rekeytime
- * @param use_reauth           sould be done reauthentication instead of rekeying?
- * @param use_mobike           use MOBIKE (RFC4555) if peer supports it
+ * @param reauth                       sould be done reauthentication instead of rekeying?
+ * @param mobike                       use MOBIKE (RFC4555) if peer supports it
+ * @param force_encap          enforce UDP encapsulation by faking NATD notify
  * @param dpd_delay                    after how many seconds of inactivity to check DPD
  * @param dpd_action           what to do with CHILD_SAs when detected a dead peer
  * @param my_virtual_ip                virtual IP for local host, or NULL
@@ -381,7 +390,7 @@ peer_cfg_t *peer_cfg_create(char *name, u_int ikev_version, ike_cfg_t *ike_cfg,
                                                        auth_method_t auth_method, eap_type_t eap_type,
                                                        u_int32_t keyingtries, u_int32_t lifetime,
                                                        u_int32_t rekeytime, u_int32_t jitter,
-                                                       bool reauth, bool mobike,
+                                                       bool reauth, bool mobike, bool force_encap,
                                                        u_int32_t dpd_delay, dpd_action_t dpd_action,
                                                        host_t *my_virtual_ip, host_t *other_virtual_ip);
 
index 3ab6b57..13d4b96 100755 (executable)
@@ -571,8 +571,9 @@ static void stroke_add_conn(stroke_msg_t *msg, FILE *out)
                                        msg->add_conn.rekey.tries, msg->add_conn.rekey.ike_lifetime,
                                        msg->add_conn.rekey.ike_lifetime - msg->add_conn.rekey.margin,
                                        msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100, 
-                                       msg->add_conn.rekey.reauth, msg->add_conn.mobike,
-                                       msg->add_conn.dpd.delay, msg->add_conn.dpd.action, my_vip, other_vip);
+                                       msg->add_conn.rekey.reauth, msg->add_conn.mobike, 
+                                       msg->add_conn.force_encap, msg->add_conn.dpd.delay,
+                                       msg->add_conn.dpd.action, my_vip, other_vip);
        }
        
        child_cfg = child_cfg_create(
index 44f0298..9ccf297 100644 (file)
@@ -822,6 +822,8 @@ static status_t update_hosts(private_child_sa_t *this,
                                                                policy->other_ts, policy->my_ts, POLICY_FWD);
                
                        /* check wether we have to update a "dynamic" traffic selector */
+                       DBG1(DBG_IKE, "--- my: %H, %H, %R", me, this->me.addr, policy->my_ts);
+                       DBG1(DBG_IKE, "--- ot: %H, %H, %R", other, this->other.addr, policy->other_ts);
                        if (!me->ip_equals(me, this->me.addr) &&
                                policy->my_ts->is_host(policy->my_ts, this->me.addr))
                        {
@@ -832,6 +834,8 @@ static status_t update_hosts(private_child_sa_t *this,
                        {
                                policy->other_ts->set_address(policy->other_ts, other);
                        }
+                       DBG1(DBG_IKE, "--- my: %H, %H, %R", me, this->me.addr, policy->my_ts);
+                       DBG1(DBG_IKE, "--- ot: %H, %H, %R", other, this->other.addr, policy->other_ts);
                        
                        /* we reinstall the virtual IP to handle interface romaing
                         * correctly */
index 0c0e179..27ba126 100644 (file)
@@ -495,6 +495,10 @@ static void set_condition(private_ike_sa_t *this, ike_condition_t condition,
                                        DBG1(DBG_IKE, "remote host is behind NAT");
                                        this->conditions |= COND_NAT_ANY;
                                        break;
+                               case COND_NAT_FAKE:
+                                       DBG1(DBG_IKE, "faked NAT situation to enforce UDP encapsulation");
+                                       this->conditions |= COND_NAT_ANY;
+                                       break;
                                default:
                                        break;
                        }
@@ -508,10 +512,12 @@ static void set_condition(private_ike_sa_t *this, ike_condition_t condition,
                                        DBG1(DBG_IKE, "new route to %H found", this->other_host);
                                        break;
                                case COND_NAT_HERE:
+                               case COND_NAT_FAKE:
                                case COND_NAT_THERE:
                                        set_condition(this, COND_NAT_ANY,
                                                                  has_condition(this, COND_NAT_HERE) ||
-                                                                 has_condition(this, COND_NAT_THERE));
+                                                                 has_condition(this, COND_NAT_THERE) ||
+                                                                 has_condition(this, COND_NAT_FAKE));
                                        break;
                                default:
                                        break;
index ba18957..67d6a88 100644 (file)
@@ -94,7 +94,7 @@ enum ike_extension_t {
 enum ike_condition_t {
        
        /**
-        * Connection is natted somewhere
+        * Connection is natted (or faked) somewhere
         */
        COND_NAT_ANY = (1<<0),
        
@@ -107,11 +107,16 @@ enum ike_condition_t {
         * other is behind NAT
         */
        COND_NAT_THERE = (1<<2),
+       
+       /**
+        * Faking NAT to enforce UDP encapsulation
+        */
+       COND_NAT_FAKE = (1<<3),
 
        /**
         * peer is currently not reachable (due missing route, ...)
         */
-       COND_STALE = (1<<3),
+       COND_STALE = (1<<4),
 };
 
 /**
index eea7691..ff3fbb7 100644 (file)
@@ -114,6 +114,25 @@ static chunk_t generate_natd_hash(private_ike_natd_t *this,
 }
 
 /**
+ * build a faked NATD payload to enforce UDP encap
+ */
+static chunk_t generate_natd_hash_faked(private_ike_natd_t *this)
+{
+       randomizer_t *randomizer;
+       chunk_t chunk;
+       
+       randomizer = randomizer_create();
+       if (randomizer->allocate_pseudo_random_bytes(randomizer, HASH_SIZE_SHA1,
+                                                                                                &chunk) != SUCCESS)
+       {
+               DBG1(DBG_IKE, "unable to get random bytes for NATD fake");
+               chunk = chunk_empty;
+       }
+       randomizer->destroy(randomizer);
+       return chunk;
+}
+
+/**
  * Build a NAT detection notify payload.
  */
 static notify_payload_t *build_natd_payload(private_ike_natd_t *this,
@@ -121,12 +140,21 @@ static notify_payload_t *build_natd_payload(private_ike_natd_t *this,
 {
        chunk_t hash;
        notify_payload_t *notify;       
-       ike_sa_id_t *ike_sa_id; 
+       ike_sa_id_t *ike_sa_id;
+       peer_cfg_t *config;
        
        ike_sa_id = this->ike_sa->get_id(this->ike_sa);
+       config = this->ike_sa->get_peer_cfg(this->ike_sa);
        notify = notify_payload_create();
        notify->set_notify_type(notify, type);
-       hash = generate_natd_hash(this, ike_sa_id, host);
+       if (config->force_encap(config) && type == NAT_DETECTION_SOURCE_IP)
+       {
+               hash = generate_natd_hash_faked(this);
+       }
+       else
+       {
+               hash = generate_natd_hash(this, ike_sa_id, host);
+       }
        notify->set_notification_data(notify, hash);
        chunk_free(&hash);
        
@@ -144,6 +172,7 @@ static void process_payloads(private_ike_natd_t *this, message_t *message)
        chunk_t hash, src_hash, dst_hash;
        ike_sa_id_t *ike_sa_id;
        host_t *me, *other;
+       peer_cfg_t *config;
        
        /* Precompute NAT-D hashes for incoming NAT notify comparison */
        ike_sa_id = message->get_ike_sa_id(message);
@@ -209,7 +238,12 @@ static void process_payloads(private_ike_natd_t *this, message_t *message)
                this->ike_sa->set_condition(this->ike_sa, COND_NAT_HERE,
                                                                        !this->dst_matched);
                this->ike_sa->set_condition(this->ike_sa, COND_NAT_THERE,
-                                                                       !this->src_matched);
+                                                                       !this->src_matched);            
+               config = this->ike_sa->get_peer_cfg(this->ike_sa);
+               if (config->force_encap(config))
+               {
+                       this->ike_sa->set_condition(this->ike_sa, COND_NAT_FAKE, TRUE); 
+               }
        }
 }
 
index b869992..a4f5ba1 100644 (file)
@@ -876,6 +876,7 @@ extern const char *prettypolicy(lset_t policy);
 #define POLICY_DONT_REAUTH     LELEM(21)       /* don't reauthenticate on rekeying, IKEv2 only */
 #define POLICY_BEET            LELEM(22)       /* bound end2end tunnel, IKEv2 */
 #define POLICY_MOBIKE          LELEM(23)       /* enable MOBIKE for IKEv2  */
+#define POLICY_FORCE_ENCAP     LELEM(24)       /* force UDP encapsulation (IKEv2)  */
 
 /* Any IPsec policy?  If not, a connection description
  * is only for ISAKMP SA, not IPSEC SA.  (A pun, I admit.)
index bfb7147..6ddc721 100644 (file)
@@ -194,6 +194,7 @@ static const token_info_t token_info[] =
     { ARG_MISC, 0, NULL  /* KW_AUTHBY */                                           },
     { ARG_MISC, 0, NULL  /* KW_EAP */                                              },
     { ARG_MISC, 0, NULL  /* KW_MOBIKE */                                           },
+    { ARG_MISC, 0, NULL  /* KW_FORCE_ENCAP */                                      },
     { ARG_TIME, offsetof(starter_conn_t, sa_ike_life_seconds), NULL                },
     { ARG_TIME, offsetof(starter_conn_t, sa_ipsec_life_seconds), NULL              },
     { ARG_TIME, offsetof(starter_conn_t, sa_rekey_margin), NULL                    },
index 8ef115f..cd1e213 100644 (file)
@@ -554,6 +554,9 @@ load_conn(starter_conn_t *conn, kw_list_t *kw, starter_config_t *cfg)
                case KW_MOBIKE:
                        KW_POLICY_FLAG("yes", "no", POLICY_MOBIKE)
                        break;
+               case KW_FORCE_ENCAP:
+                       KW_POLICY_FLAG("yes", "no", POLICY_FORCE_ENCAP)
+                       break;
                case KW_MODECONFIG:
                        KW_POLICY_FLAG("push", "pull", POLICY_MODECFG_PUSH)
                        break;
index a1f6cb8..a54a6cc 100644 (file)
@@ -365,6 +365,11 @@ for the connection, e.g.
 (encryption-integrity-[dh-group]). If dh-group is specified, CHILD_SA setup
 and rekeying include a separate diffe hellman exchange (IKEv2 only).
 .TP
+.B force_encap
+Force UDP encapsulation for ESP packets even if no NAT situation is detected.
+This may help to hurdle restrictive firewalls. To enforce the peer to 
+encapsulate packets, NAT detection payloads are faked (IKEv2 only).
+.TP
 .B ike
 IKE/ISAKMP SA encryption/authentication algorithm to be used, e.g.
 .B aes128-sha1-modp2048
index 69a4b6d..d25e08b 100644 (file)
@@ -71,6 +71,7 @@ typedef enum {
     KW_AUTHBY,
     KW_EAP,
     KW_MOBIKE,
+    KW_FORCE_ENCAP,
     KW_IKELIFETIME,
     KW_KEYLIFE,
     KW_REKEYMARGIN,
index 5deecff..c0990c5 100644 (file)
@@ -50,6 +50,7 @@ virtual_private,   KW_VIRTUAL_PRIVATE
 eap,               KW_EAP
 eapdir,            KW_EAPDIR
 mobike,                   KW_MOBIKE
+force_encap,       KW_FORCE_ENCAP
 pkcs11module,      KW_PKCS11MODULE
 pkcs11initargs,    KW_PKCS11INITARGS
 pkcs11keepstate,   KW_PKCS11KEEPSTATE
index 14f2e54..d984f66 100644 (file)
@@ -110,6 +110,7 @@ static int add_connection(char *name,
        msg.add_conn.eap_type = 0;
        msg.add_conn.mode = 1;
        msg.add_conn.mobike = 1;
+       msg.add_conn.force_encap = 0;
        
        msg.add_conn.rekey.reauth = 0;
        msg.add_conn.rekey.ipsec_lifetime = 0;
index f903379..46bd129 100644 (file)
@@ -183,6 +183,7 @@ struct stroke_msg_t {
                        int eap_type;
                        int mode;
                        int mobike;
+                       int force_encap;
                        struct {
                                char *ike;
                                char *esp;