further fixed for mobike roaming
authorMartin Willi <martin@strongswan.org>
Mon, 25 Jun 2007 13:26:02 +0000 (13:26 -0000)
committerMartin Willi <martin@strongswan.org>
Mon, 25 Jun 2007 13:26:02 +0000 (13:26 -0000)
src/charon/daemon.c
src/charon/encoding/payloads/notify_payload.c
src/charon/encoding/payloads/notify_payload.h
src/charon/kernel/kernel_interface.c
src/charon/sa/ike_sa.c
src/charon/sa/ike_sa_manager.c
src/charon/sa/task_manager.c
src/charon/sa/tasks/ike_mobike.c

index 088bbf6..37699f8 100644 (file)
@@ -381,6 +381,9 @@ private_daemon_t *daemon_create(void)
        sigaddset(&action.sa_mask, SIGHUP);
        sigaction(SIGSEGV, &action, NULL);
        sigaction(SIGILL, &action, NULL);
+       action.sa_handler = SIG_IGN;
+       sigaction(SIGPIPE, &action, NULL);
+       
        pthread_sigmask(SIG_SETMASK, &action.sa_mask, 0);
        
        return this;
index ca92fc1..d700965 100644 (file)
@@ -47,14 +47,16 @@ ENUM_NEXT(notify_type_names, INVALID_KE_PAYLOAD, INVALID_KE_PAYLOAD, NO_PROPOSAL
        "INVALID_KE_PAYLOAD");
 ENUM_NEXT(notify_type_names, AUTHENTICATION_FAILED, AUTHENTICATION_FAILED, INVALID_KE_PAYLOAD,
        "AUTHENTICATION_FAILED");
-ENUM_NEXT(notify_type_names, SINGLE_PAIR_REQUIRED, INVALID_SELECTORS, AUTHENTICATION_FAILED,
+ENUM_NEXT(notify_type_names, SINGLE_PAIR_REQUIRED, UNEXPECTED_NAT_DETECTED, AUTHENTICATION_FAILED,
        "SINGLE_PAIR_REQUIRED",
        "NO_ADDITIONAL_SAS",
        "INTERNAL_ADDRESS_FAILURE",
        "FAILED_CP_REQUIRED",
        "TS_UNACCEPTABLE",
-       "INVALID_SELECTORS");
-ENUM_NEXT(notify_type_names, INITIAL_CONTACT, AUTH_LIFETIME, INVALID_SELECTORS,
+       "INVALID_SELECTORS",
+       "UNACCEPTABLE_ADDRESSES",
+       "UNEXPECTED_NAT_DETECTED");
+ENUM_NEXT(notify_type_names, INITIAL_CONTACT, AUTH_LIFETIME, UNEXPECTED_NAT_DETECTED,
        "INITIAL_CONTACT",
        "SET_WINDOW_SIZE",
        "ADDITIONAL_TS_POSSIBLE",
index 4319326..ca1fe3a 100644 (file)
@@ -65,6 +65,8 @@ enum notify_type_t {
        FAILED_CP_REQUIRED = 37,
        TS_UNACCEPTABLE = 38,
        INVALID_SELECTORS = 39,
+       UNACCEPTABLE_ADDRESSES = 40,
+       UNEXPECTED_NAT_DETECTED = 41,
        /* notify status messages */
        INITIAL_CONTACT = 16384,
        SET_WINDOW_SIZE = 16385,
index 9847f30..bf5479b 100644 (file)
@@ -228,6 +228,9 @@ struct addr_entry_t {
        /** The ip address */
        host_t *ip;
        
+       /** virtual IP managed by us */
+       bool virtual;
+       
        /** Number of times this IP is used, if virtual */
        u_int refcount;
 };
@@ -690,6 +693,7 @@ static void process_addr(private_kernel_interface_t *this,
                                        found = TRUE;
                                        addr = malloc_thing(addr_entry_t);
                                        addr->ip = host->clone(host);
+                                       addr->virtual = FALSE;
                                        addr->refcount = 1;
                                        
                                        iface->addrs->insert_last(iface->addrs, addr);
@@ -1070,6 +1074,10 @@ static status_t init_address_list(private_kernel_interface_t *this)
 static hook_result_t addr_hook(private_kernel_interface_t *this,
                                                           addr_entry_t *in, host_t **out)
 {
+       if (in->virtual)
+       {       /* skip virtual interfaces added by us */
+               return HOOK_SKIP;
+       }
        *out = in->ip;
        return HOOK_NEXT;
 }
@@ -1107,6 +1115,11 @@ static iterator_t *create_address_iterator(private_kernel_interface_t *this)
 {
        iterator_t *iterator;
        
+       /* This iterator is not only hooked, is is double-hooked. As we have stored
+        * our addresses in iface_entry->addr_entry->ip, we need to iterate the
+        * entries in each interface we iterate. This does the iface_hook. The
+        * addr_hook returns the ip instead of the addr_entry. */
+       
        iterator = this->ifaces->create_iterator_locked(this->ifaces, &this->mutex);
        iterator->set_iterator_hook(iterator, (iterator_hook_t*)iface_hook, this);
        return iterator;
@@ -1368,6 +1381,8 @@ static host_t* get_source_addr(private_kernel_interface_t *this, host_t *dest)
        size_t len;
        host_t *source = NULL;
        
+       DBG2(DBG_KNL, "getting source address to reach %H", dest);
+       
        memset(&request, 0, sizeof(request));
 
        hdr = (struct nlmsghdr*)request;
@@ -1378,10 +1393,10 @@ static host_t* get_source_addr(private_kernel_interface_t *this, host_t *dest)
        msg = (struct rtmsg*)NLMSG_DATA(hdr);
        msg->rtm_family = dest->get_family(dest);
        msg->rtm_dst_len = msg->rtm_family == AF_INET ? 32 : 128;
-       msg->rtm_table = RT_TABLE_MAIN;
-       msg->rtm_protocol = RTPROT_STATIC;
+       msg->rtm_table = RT_TABLE_UNSPEC;
+       msg->rtm_protocol = RTPROT_UNSPEC;
        msg->rtm_type = RTN_UNICAST;
-       msg->rtm_scope = RT_SCOPE_UNIVERSE;
+       msg->rtm_scope = RT_SCOPE_HOST;
        
        chunk = dest->get_address(dest);
        add_attribute(hdr, RTA_DST, chunk, sizeof(request));
@@ -1427,12 +1442,13 @@ static host_t* get_source_addr(private_kernel_interface_t *this, host_t *dest)
                }
                break;
        }
-       if (source == NULL)
+       free(out);
+       if (source)
        {
-               DBG2(DBG_KNL, "no route found to %H", dest);
+               return source;
        }
-       free(out);
-       return source;
+       DBG2(DBG_KNL, "no route found to %H", dest);
+       return NULL;
 }
 
 /**
@@ -1481,6 +1497,7 @@ static status_t add_ip(private_kernel_interface_t *this,
                                addr = malloc_thing(addr_entry_t);
                                addr->ip = virtual_ip->clone(virtual_ip);
                                addr->refcount = 1;
+                               addr->virtual = TRUE;
                                pthread_mutex_lock(&this->mutex);
                                iface->addrs->insert_last(iface->addrs, addr);
                                pthread_mutex_unlock(&this->mutex);
@@ -2298,7 +2315,6 @@ kernel_interface_t *kernel_interface_create()
        private_kernel_interface_t *this = malloc_thing(private_kernel_interface_t);
        struct sockaddr_nl addr;
        
-       
        /* public functions */
        this->public.get_spi = (status_t(*)(kernel_interface_t*,host_t*,host_t*,protocol_id_t,u_int32_t,u_int32_t*))get_spi;
        this->public.add_sa  = (status_t(*)(kernel_interface_t *,host_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t,u_int64_t,u_int64_t,algorithm_t*,algorithm_t*,prf_plus_t*,natt_conf_t*,mode_t,bool))add_sa;
index 00f9596..5406cb7 100644 (file)
@@ -1681,7 +1681,13 @@ static status_t roam(private_ike_sa_t *this)
        }
        
        me = charon->kernel_interface->get_source_addr(charon->kernel_interface,
-                                                                                                  this->other_host);
+                                                                                                  this->other_host);   
+       if (me && me->ip_equals(me, this->my_virtual_ip))
+       {       /* do not roam to the virtual IP of this IKE_SA */
+               me->destroy(me);
+               me = NULL;
+       }
+       
        if (me)
        {
                set_condition(this, COND_STALE, FALSE);
@@ -1695,12 +1701,8 @@ static status_t roam(private_ike_sa_t *this)
                }
                me->set_port(me, this->my_host->get_port(this->my_host));
                
-#ifndef MOBIKE
-               set_my_host(this, me);
-               return reestablish(this);
-#endif 
                /* our attachement changed, update if we have mobike */
-               if (this->extensions & EXT_MOBIKE)
+               if (supports_extension(this, EXT_MOBIKE))
                {
                        mobike = ike_mobike_create(&this->public, TRUE);
                        mobike->roam(mobike, me, NULL);
@@ -1713,15 +1715,11 @@ static status_t roam(private_ike_sa_t *this)
        }
        
        /* there is nothing we can do without mobike */
-       if (!(this->extensions & EXT_MOBIKE))
+       if (!supports_extension(this, EXT_MOBIKE))
        {
                set_condition(this, COND_STALE, TRUE);
                return FAILED;
        }
-#ifndef MOBIKE
-       set_condition(this, COND_STALE, TRUE);
-       return FAILED;
-#endif 
 
        /* we are unable to reach the peer. Try an alternative address */
        iterator = create_additional_address_iterator(this);
@@ -1729,10 +1727,18 @@ static status_t roam(private_ike_sa_t *this)
        {
                me = charon->kernel_interface->get_source_addr(charon->kernel_interface,
                                                                                                           other);
+               if (me && me->ip_equals(me, this->my_virtual_ip))
+               {       /* do not roam to the virtual IP of this IKE_SA */
+                       me->destroy(me);
+                       me = NULL;
+               }
+               
                if (me)
                {
                        /* good, we have a new route. Use MOBIKE to update */
                        iterator->destroy(iterator);
+                       me->set_port(me, this->my_host->get_port(this->my_host));
+                       other->set_port(other, this->other_host->get_port(this->other_host));
                        mobike = ike_mobike_create(&this->public, TRUE);
                        mobike->roam(mobike, me, other);
                        this->task_manager->queue_task(this->task_manager, (task_t*)mobike);
@@ -1740,7 +1746,10 @@ static status_t roam(private_ike_sa_t *this)
                }
        }
        iterator->destroy(iterator);
-       return SUCCESS;
+
+       /* no route found to host, give up (temporary) */
+       set_condition(this, COND_STALE, TRUE);
+       return FAILED;
 }
 
 /**
index bc90940..0a0d5e5 100644 (file)
@@ -701,6 +701,7 @@ static iterator_t *create_iterator(private_ike_sa_manager_t* this)
 {
        iterator_t *iterator = this->ike_sa_list->create_iterator_locked(
                                                                                        this->ike_sa_list, &this->mutex);
+       
        /* register hook to iterator over ike_sas, not entries */
        iterator->set_iterator_hook(iterator, (iterator_hook_t*)iterator_hook, this);
        return iterator;
index 84ce1fb..fc2a130 100644 (file)
@@ -314,6 +314,11 @@ static status_t build_request(private_task_manager_t *this)
                                        exchange = INFORMATIONAL;
                                        break;
                                }
+                               if (activate_task(this, IKE_MOBIKE))
+                               {
+                                       exchange = INFORMATIONAL;
+                                       break;
+                               }
                                if (activate_task(this, IKE_DPD))
                                {
                                        exchange = INFORMATIONAL;
@@ -592,6 +597,7 @@ static status_t process_request(private_task_manager_t *this,
        exchange_type_t exchange;
        payload_t *payload;
        notify_payload_t *notify;
+       delete_payload_t *delete;
 
        exchange = message->get_exchange_type(message);
 
@@ -669,27 +675,56 @@ static status_t process_request(private_task_manager_t *this,
                }
                case INFORMATIONAL:
                {
-                       delete_payload_t *delete;
-                       
-                       delete = (delete_payload_t*)message->get_payload(message, DELETE);
-                       if (delete)
+                       iterator = message->get_payload_iterator(message);
+                       while (iterator->iterate(iterator, (void**)&payload))
                        {
-                               if (delete->get_protocol_id(delete) == PROTO_IKE)
-                               {
-                                       task = (task_t*)ike_delete_create(this->ike_sa, FALSE);
-                                       this->passive_tasks->insert_last(this->passive_tasks, task);
-                               }
-                               else
+                               switch (payload->get_type(payload))
                                {
-                                       task = (task_t*)child_delete_create(this->ike_sa, NULL);
-                                       this->passive_tasks->insert_last(this->passive_tasks, task);
+                                       case NOTIFY:
+                                       {
+                                               notify = (notify_payload_t*)payload;
+                                               switch (notify->get_notify_type(notify))
+                                               {
+                                                       case ADDITIONAL_IP4_ADDRESS:
+                                                       case ADDITIONAL_IP6_ADDRESS:
+                                                       case NO_ADDITIONAL_ADDRESSES:
+                                                       case UPDATE_SA_ADDRESSES:
+                                                       case NO_NATS_ALLOWED:
+                                                       case UNACCEPTABLE_ADDRESSES:
+                                                       case UNEXPECTED_NAT_DETECTED:
+                                                       case COOKIE2:
+                                                               task = (task_t*)ike_mobike_create(this->ike_sa,
+                                                                                                                                 FALSE);
+                                                               break;
+                                                       default:
+                                                               break;
+                                               }
+                                               break;
+                                       }
+                                       case DELETE:
+                                       {
+                                               delete = (delete_payload_t*)payload;
+                                               if (delete->get_protocol_id(delete) == PROTO_IKE)
+                                               {
+                                                       task = (task_t*)ike_delete_create(this->ike_sa, FALSE);
+                                               }
+                                               else
+                                               {
+                                                       task = (task_t*)child_delete_create(this->ike_sa, NULL);
+                                               }
+                                               break;
+                                       }
+                                       default:
+                                               break;
                                }
                        }
-                       else
+                       iterator->destroy(iterator);
+                       
+                       if (task == NULL)
                        {
                                task = (task_t*)ike_dpd_create(FALSE);
-                               this->passive_tasks->insert_last(this->passive_tasks, task);
                        }
+                       this->passive_tasks->insert_last(this->passive_tasks, task);
                        break;
                }
                default:
index 0b3bd07..a7f5fb6 100644 (file)
@@ -25,6 +25,7 @@
 #include <string.h>
 
 #include <daemon.h>
+#include <sa/tasks/ike_natd.h>
 #include <encoding/payloads/notify_payload.h>
 
 
@@ -59,6 +60,16 @@ struct private_ike_mobike_t {
         * remote host to roam to
         */
        host_t *other;
+       
+       /**
+        * cookie2 value to verify new addresses
+        */
+       chunk_t cookie2;
+       
+       /**
+        * NAT discovery reusing the IKE_NATD task
+        */
+       ike_natd_t *natd;
 };
 
 /**
@@ -119,6 +130,7 @@ static void process_payloads(private_ike_mobike_t *this, message_t *message)
                                if (first)
                                {       /* an ADDITIONAL_*_ADDRESS means replace, so flush once */
                                        flush_additional_addresses(this);
+                                       first = FALSE;
                                }
                                data = notify->get_notification_data(notify);
                                host = host_create_from_chunk(family, data, 0);
@@ -185,10 +197,26 @@ static status_t build_i(private_ike_mobike_t *this, message_t *message)
 {
        if (message->get_exchange_type(message) == IKE_AUTH &&
                message->get_payload(message, SECURITY_ASSOCIATION))
-       {               
+       {
                message->add_notify(message, FALSE, MOBIKE_SUPPORTED, chunk_empty);
                build_address_list(this, message);
        }
+       else if (this->me || this->other)
+       {       /* address change */
+               message->add_notify(message, FALSE, UPDATE_SA_ADDRESSES, chunk_empty);
+               build_address_list(this, message);
+               /* TODO: NAT discovery */
+               
+               /* set new addresses */
+               if (this->me)
+               {
+                       this->ike_sa->set_my_host(this->ike_sa, this->me->clone(this->me));
+               }
+               if (this->other)
+               {
+                       this->ike_sa->set_other_host(this->ike_sa, this->other->clone(this->other));
+               }
+       }
        
        return NEED_MORE;
 }
@@ -197,8 +225,13 @@ static status_t build_i(private_ike_mobike_t *this, message_t *message)
  * Implementation of task_t.process for responder
  */
 static status_t process_r(private_ike_mobike_t *this, message_t *message)
-{      
-       process_payloads(this, message);
+{
+       if ((message->get_exchange_type(message) == IKE_AUTH &&
+                message->get_payload(message, SECURITY_ASSOCIATION)) ||
+               message->get_exchange_type(message) == INFORMATIONAL)
+       {
+               process_payloads(this, message);
+       }
        
        return NEED_MORE;
 }
@@ -259,9 +292,14 @@ static void migrate(private_ike_mobike_t *this, ike_sa_t *ike_sa)
 {
        DESTROY_IF(this->me);
        DESTROY_IF(this->other);
+       chunk_free(&this->cookie2);
        this->ike_sa = ike_sa;
        this->me = NULL;
        this->other = NULL;
+       if (this->natd)
+       {
+               this->natd->task.migrate(&this->natd->task, ike_sa);
+       }
 }
 
 /**
@@ -271,6 +309,11 @@ static void destroy(private_ike_mobike_t *this)
 {
        DESTROY_IF(this->me);
        DESTROY_IF(this->other);
+       chunk_free(&this->cookie2);
+       if (this->natd)
+       {
+               this->natd->task.destroy(&this->natd->task);
+       }
        free(this);
 }
 
@@ -301,6 +344,8 @@ ike_mobike_t *ike_mobike_create(ike_sa_t *ike_sa, bool initiator)
        this->initiator = initiator;
        this->me = NULL;
        this->other = NULL;
+       this->cookie2 = chunk_empty;
+       this->natd = NULL;
        
        return &this->public;
 }