use MOBIKE enabled DPD if we are NATed
authorMartin Willi <martin@strongswan.org>
Mon, 6 Oct 2008 13:37:04 +0000 (13:37 -0000)
committerMartin Willi <martin@strongswan.org>
Mon, 6 Oct 2008 13:37:04 +0000 (13:37 -0000)
update SAs if we detect changes in NAT mappings

src/charon/sa/ike_sa.c
src/charon/sa/ike_sa.h
src/charon/sa/tasks/ike_mobike.c
src/charon/sa/tasks/ike_mobike.h
src/charon/sa/tasks/ike_natd.c
src/charon/sa/tasks/ike_natd.h

index 4151127..351e282 100644 (file)
@@ -255,6 +255,11 @@ struct private_ike_sa_t {
        linked_list_t *additional_addresses;
        
        /**
+        * previously value of received DESTINATION_IP hash
+        */
+       chunk_t nat_detection_dest;
+       
+       /**
         * number pending UPDATE_SA_ADDRESS (MOBIKE)
         */
        u_int32_t pending_updates;
@@ -626,8 +631,20 @@ static status_t send_dpd(private_ike_sa_t *this)
                {
                        /* to long ago, initiate dead peer detection */
                        task_t *task;
+                       ike_mobike_t *mobike;
                        
-                       task = (task_t*)ike_dpd_create(TRUE);
+                       if (supports_extension(this, EXT_MOBIKE) &&
+                               has_condition(this, COND_NAT_HERE))
+                       {
+                               /* use mobike enabled DPD to detect NAT mapping changes */
+                               mobike = ike_mobike_create(&this->public, TRUE);
+                               mobike->dpd(mobike);
+                               task = &mobike->task;
+                       }
+                       else
+                       {
+                               task = (task_t*)ike_dpd_create(TRUE);
+                       }
                        diff = 0;
                        DBG1(DBG_IKE, "sending DPD request");
                        
@@ -817,7 +834,26 @@ static iterator_t* create_additional_address_iterator(private_ike_sa_t *this)
        return this->additional_addresses->create_iterator(
                                                                                        this->additional_addresses, TRUE);
 }
-       
+
+/**
+ * Implementation of ike_sa_t.has_mapping_changed
+ */
+static bool has_mapping_changed(private_ike_sa_t *this, chunk_t hash)
+{
+       if (this->nat_detection_dest.ptr == NULL)
+       {
+               this->nat_detection_dest = chunk_clone(hash);
+               return FALSE;
+       }
+       if (chunk_equals(hash, this->nat_detection_dest))
+       {
+               return FALSE;
+       }
+       free(this->nat_detection_dest.ptr);
+       this->nat_detection_dest = chunk_clone(hash);
+       return TRUE;
+}
+
 /**
  * Implementation of ike_sa_t.set_pending_updates.
  */
@@ -2498,6 +2534,7 @@ static void destroy(private_ike_sa_t *this)
        DESTROY_IF(this->server_reflexive_host);
        chunk_free(&this->connect_id);
 #endif /* ME */
+       free(this->nat_detection_dest.ptr);
        
        DESTROY_IF(this->my_host);
        DESTROY_IF(this->other_host);
@@ -2559,6 +2596,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
        this->public.is_ike_initiator = (bool (*)(ike_sa_t*))is_ike_initiator;
        this->public.create_additional_address_iterator = (iterator_t*(*)(ike_sa_t*))create_additional_address_iterator;
        this->public.add_additional_address = (void(*)(ike_sa_t*, host_t *host))add_additional_address;
+       this->public.has_mapping_changed = (bool(*)(ike_sa_t*, chunk_t hash))has_mapping_changed;
        this->public.retransmit = (status_t (*)(ike_sa_t *, u_int32_t)) retransmit;
        this->public.delete = (status_t (*)(ike_sa_t*))delete_;
        this->public.destroy = (void (*)(ike_sa_t*))destroy;
@@ -2638,6 +2676,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
        this->other_virtual_ip = NULL;
        this->dns_servers = linked_list_create();
        this->additional_addresses = linked_list_create();
+       this->nat_detection_dest = chunk_empty;
        this->pending_updates = 0;
        this->keyingtry = 0;
        this->ike_initiator = FALSE;
index e45d18c..3cd9e00 100644 (file)
@@ -407,6 +407,14 @@ struct ike_sa_t {
        iterator_t* (*create_additional_address_iterator)(ike_sa_t *this);
        
        /**
+        * Check if mappings have changed on a NAT for our source address.
+        *
+        * @param hash                  received DESTINATION_IP hash
+        * @return                              TRUE if mappings have changed
+        */
+       bool (*has_mapping_changed)(ike_sa_t *this, chunk_t hash);
+       
+       /**
         * Enable an extension the peer supports.
         *
         * If support for an IKE extension is detected, this method is called
index 4b8e8ce..450149f 100644 (file)
@@ -434,7 +434,7 @@ static status_t process_i(private_ike_mobike_t *this, message_t *message)
                        return SUCCESS;
                }
                if (this->cookie2.ptr)
-               {       /* check cookie if we included none */
+               {       /* check cookie if we included one */
                        chunk_t cookie2;
                        
                        cookie2 = this->cookie2;
@@ -455,6 +455,13 @@ static status_t process_i(private_ike_mobike_t *this, message_t *message)
                if (this->natd)
                {
                        this->natd->task.process(&this->natd->task, message);
+                       if (this->natd->has_mapping_changed(this->natd))
+                       {
+                               /* force an update if mappings have changed */
+                               this->update = this->check = TRUE;
+                               DBG1(DBG_IKE, "detected changes in NAT mappings, "
+                                        "initiating MOBIKE update");
+                       }
                }
                if (this->update)
                {
@@ -507,6 +514,20 @@ static void roam(private_ike_mobike_t *this, bool address)
 }
 
 /**
+ * Implementation of ike_mobike_t.dpd
+ */
+static void dpd(private_ike_mobike_t *this)
+{
+       if (!this->natd)
+       {
+               this->natd = ike_natd_create(this->ike_sa, this->initiator);
+       }
+       this->address = FALSE;
+       this->ike_sa->set_pending_updates(this->ike_sa, 
+                                                       this->ike_sa->get_pending_updates(this->ike_sa) + 1);
+}
+
+/**
  * Implementation of ike_mobike_t.is_probing.
  */
 static bool is_probing(private_ike_mobike_t *this)
@@ -556,6 +577,7 @@ ike_mobike_t *ike_mobike_create(ike_sa_t *ike_sa, bool initiator)
        private_ike_mobike_t *this = malloc_thing(private_ike_mobike_t);
 
        this->public.roam = (void(*)(ike_mobike_t*,bool))roam;
+       this->public.dpd = (void(*)(ike_mobike_t*))dpd;
        this->public.transmit = (void(*)(ike_mobike_t*,packet_t*))transmit;
        this->public.is_probing = (bool(*)(ike_mobike_t*))is_probing;
        this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
index 7325f5a..81bdd0f 100644 (file)
@@ -55,6 +55,11 @@ struct ike_mobike_t {
        void (*roam)(ike_mobike_t *this, bool address);
        
        /**
+        * Use the task for a DPD check which detects changes in NAT mappings.
+        */
+       void (*dpd)(ike_mobike_t *this);
+       
+       /**
         * Transmision hook, called by task manager.
         *
         * The task manager calls this hook whenever it transmits a packet. It 
index 34c040c..de0cfce 100644 (file)
@@ -72,6 +72,11 @@ struct private_ike_natd_t {
         * Have we found a matching destination address NAT hash?
         */
        bool dst_matched;
+       
+       /**
+        * whether NAT mappings for our NATed address has changed
+        */
+       bool mapping_changed;
 };
 
 
@@ -192,15 +197,24 @@ static void process_payloads(private_ike_natd_t *this, message_t *message)
                        case NAT_DETECTION_DESTINATION_IP:
                        {
                                this->dst_seen = TRUE;
+                               hash = notify->get_notification_data(notify);
                                if (!this->dst_matched)
                                {
-                                       hash = notify->get_notification_data(notify);
                                        DBG3(DBG_IKE, "received dst_hash %B", &hash);
                                        if (chunk_equals(hash, dst_hash))
                                        {
                                                this->dst_matched = TRUE;
                                        }
                                }
+                               /* RFC4555 says we should also compare against IKE_SA_INIT
+                                * NATD payloads, but this does not work: We are running
+                                * there at port 500, but use 4500 afterwards... */
+                               if (message->get_exchange_type(message) == INFORMATIONAL &&
+                                       this->initiator && !this->dst_matched)
+                               {
+                                       this->mapping_changed = this->ike_sa->has_mapping_changed(
+                                                                                                                       this->ike_sa, hash);
+                               }
                                break;
                        }
                        case NAT_DETECTION_SOURCE_IP:
@@ -415,6 +429,15 @@ static void migrate(private_ike_natd_t *this, ike_sa_t *ike_sa)
        this->dst_seen = FALSE;
        this->src_matched = FALSE;
        this->dst_matched = FALSE;
+       this->mapping_changed = FALSE;
+}
+
+/**
+ * Implementation of ike_natd_t.has_mapping_changed
+ */
+static bool has_mapping_changed(private_ike_natd_t *this)
+{
+       return this->mapping_changed;
 }
 
 /**
@@ -448,6 +471,8 @@ ike_natd_t *ike_natd_create(ike_sa_t *ike_sa, bool initiator)
                this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
        }
        
+       this->public.has_mapping_changed = (bool(*)(ike_natd_t*))has_mapping_changed;
+       
        this->ike_sa = ike_sa;
        this->initiator = initiator;
        this->hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
@@ -455,6 +480,7 @@ ike_natd_t *ike_natd_create(ike_sa_t *ike_sa, bool initiator)
        this->dst_seen = FALSE;
        this->src_matched = FALSE;
        this->dst_matched = FALSE;
+       this->mapping_changed = FALSE;
        
        return &this->public;
 }
index 7934087..cb132d0 100644 (file)
@@ -38,6 +38,15 @@ struct ike_natd_t {
         * Implements the task_t interface
         */
        task_t task;
+       
+       /**
+        * Check if the NAT mapping has changed for our address.
+        *
+        * MOBIKE uses NAT payloads in DPD to detect changes in the NAT mappings.
+        *
+        * @return      TRUE if mappings have changed
+        */
+       bool (*has_mapping_changed)(ike_natd_t *this);
 };
 
 /**