further MOBIKE stuff:
authorMartin Willi <martin@strongswan.org>
Thu, 21 Jun 2007 15:25:28 +0000 (15:25 -0000)
committerMartin Willi <martin@strongswan.org>
Thu, 21 Jun 2007 15:25:28 +0000 (15:25 -0000)
  kernel properly reports network reconfiguration and informs all IKE_SAs
  MOBIKE in IKE_AUTH: MOBIKE_SUPPORTED notify and address exchange
  reestablishment of IKE_SAs on network reconfiguration kinda works
  not stable yet!

22 files changed:
src/charon/Makefile.am
src/charon/encoding/payloads/notify_payload.c
src/charon/kernel/kernel_interface.c
src/charon/kernel/kernel_interface.h
src/charon/processing/jobs/roam_job.c [new file with mode: 0644]
src/charon/processing/jobs/roam_job.h [new file with mode: 0644]
src/charon/processing/jobs/send_dpd_job.c
src/charon/processing/jobs/send_dpd_job.h
src/charon/processing/jobs/send_keepalive_job.c
src/charon/processing/jobs/send_keepalive_job.h
src/charon/sa/ike_sa.c
src/charon/sa/ike_sa.h
src/charon/sa/task_manager.c
src/charon/sa/tasks/child_create.c
src/charon/sa/tasks/ike_auth.c
src/charon/sa/tasks/ike_dpd.c
src/charon/sa/tasks/ike_mobike.c [new file with mode: 0644]
src/charon/sa/tasks/ike_mobike.h [new file with mode: 0644]
src/charon/sa/tasks/ike_natd.c
src/charon/sa/tasks/ike_reauth.c
src/charon/sa/tasks/task.c
src/charon/sa/tasks/task.h

index b0a3c56..9812a32 100644 (file)
@@ -59,6 +59,7 @@ processing/jobs/rekey_ike_sa_job.c processing/jobs/rekey_ike_sa_job.h \
 processing/jobs/retransmit_job.c processing/jobs/retransmit_job.h \
 processing/jobs/send_dpd_job.c processing/jobs/send_dpd_job.h \
 processing/jobs/send_keepalive_job.c processing/jobs/send_keepalive_job.h \
+processing/jobs/roam_job.c processing/jobs/roam_job.h \
 processing/scheduler.c processing/scheduler.h \
 processing/processor.c processing/processor.h  \
 sa/authenticators/authenticator.c sa/authenticators/authenticator.h \
@@ -81,6 +82,7 @@ sa/tasks/ike_delete.c sa/tasks/ike_delete.h \
 sa/tasks/ike_dpd.c sa/tasks/ike_dpd.h \
 sa/tasks/ike_init.c sa/tasks/ike_init.h \
 sa/tasks/ike_natd.c sa/tasks/ike_natd.h \
+sa/tasks/ike_mobike.c sa/tasks/ike_mobike.h \
 sa/tasks/ike_rekey.c sa/tasks/ike_rekey.h \
 sa/tasks/ike_reauth.c sa/tasks/ike_reauth.h \
 sa/tasks/task.c sa/tasks/task.h
index a04901a..ca92fc1 100644 (file)
@@ -189,6 +189,8 @@ encoding_rule_t notify_payload_encodings[] = {
  */
 static status_t verify(private_notify_payload_t *this)
 {
+       bool bad_length = FALSE;
+
        switch (this->protocol_id)
        {
                case PROTO_NONE:
@@ -205,30 +207,9 @@ static status_t verify(private_notify_payload_t *this)
        {
                case INVALID_KE_PAYLOAD:
                {
-                       /* check notification data */
-                       diffie_hellman_group_t dh_group;
                        if (this->notification_data.len != 2)
                        {
-                               DBG1(DBG_ENC, "invalid notify data length for %N (%d)",
-                                        notify_type_names, this->notify_type,
-                                        this->notification_data.len);
-                               return FAILED;
-                       }
-                       dh_group = ntohs(*((u_int16_t*)this->notification_data.ptr));
-                       switch (dh_group)
-                       {
-                               case MODP_768_BIT:
-                               case MODP_1024_BIT:
-                               case MODP_1536_BIT:
-                               case MODP_2048_BIT:
-                               case MODP_3072_BIT:
-                               case MODP_4096_BIT:
-                               case MODP_6144_BIT:
-                               case MODP_8192_BIT:
-                                       break;
-                               default:
-                                       DBG1(DBG_ENC, "Bad DH group (%d)", dh_group);
-                                       return FAILED;
+                               bad_length = TRUE;
                        }
                        break;
                }
@@ -237,9 +218,7 @@ static status_t verify(private_notify_payload_t *this)
                {
                        if (this->notification_data.len != HASH_SIZE_SHA1)
                        {
-                               DBG1(DBG_ENC, "invalid %N notify length",
-                                        notify_type_names, this->notify_type);
-                               return FAILED;
+                               bad_length = TRUE;
                        }
                        break;
                }
@@ -249,9 +228,23 @@ static status_t verify(private_notify_payload_t *this)
                {
                        if (this->notification_data.len != 0)
                        {
-                               DBG1(DBG_ENC, "invalid %N notify",
-                                        notify_type_names, this->notify_type);
-                               return FAILED;
+                               bad_length = TRUE;
+                       }
+                       break;
+               }
+               case ADDITIONAL_IP4_ADDRESS:
+               {
+                       if (this->notification_data.len != 4)
+                       {
+                               bad_length = TRUE;
+                       }
+                       break;
+               }
+               case ADDITIONAL_IP6_ADDRESS:
+               {
+                       if (this->notification_data.len != 16)
+                       {
+                               bad_length = TRUE;
                        }
                        break;
                }
@@ -259,6 +252,13 @@ static status_t verify(private_notify_payload_t *this)
                        /* TODO: verify */
                        break;
        }
+       if (bad_length)
+       {
+               DBG1(DBG_ENC, "invalid notify data length for %N (%d)",
+                        notify_type_names, this->notify_type,
+                        this->notification_data.len);
+               return FAILED;
+       }
        return SUCCESS;
 }
 
index 73fd513..9847f30 100644 (file)
@@ -49,6 +49,7 @@
 #include <processing/jobs/rekey_child_sa_job.h>
 #include <processing/jobs/acquire_job.h>
 #include <processing/jobs/callback_job.h>
+#include <processing/jobs/roam_job.h>
 
 /** kernel level protocol identifiers */
 #define KERNEL_ESP 50
@@ -217,37 +218,35 @@ struct policy_entry_t {
        u_int refcount;
 };
 
-typedef struct vip_entry_t vip_entry_t;
+typedef struct addr_entry_t addr_entry_t;
 
 /**
- * Installed virtual ip
+ * IP address in an inface_entry_t
  */
-struct vip_entry_t {
-       /** Index of the interface the ip is bound to */
-       u_int8_t if_index;
+struct addr_entry_t {
        
        /** The ip address */
        host_t *ip;
        
-       /** Number of times this IP is used */
+       /** Number of times this IP is used, if virtual */
        u_int refcount;
 };
 
 /**
- * destroy a vip_entry_t object
+ * destroy a addr_entry_t object
  */
-static void vip_entry_destroy(vip_entry_t *this)
+static void addr_entry_destroy(addr_entry_t *this)
 {
        this->ip->destroy(this->ip);
        free(this);
 }
 
-typedef struct interface_entry_t interface_entry_t;
+typedef struct iface_entry_t iface_entry_t;
 
 /**
- * A network interface on this system, containing addresses
+ * A network interface on this system, containing addr_entry_t's
  */
-struct interface_entry_t {
+struct iface_entry_t {
        
        /** interface index */
        int ifindex;
@@ -259,15 +258,15 @@ struct interface_entry_t {
        u_int flags;
        
        /** list of addresses as host_t */
-       linked_list_t *addresses;
+       linked_list_t *addrs;
 };
 
 /**
  * destroy an interface entry
  */
-static void interface_entry_destroy(interface_entry_t *this)
+static void iface_entry_destroy(iface_entry_t *this)
 {
-       this->addresses->destroy_offset(this->addresses, offsetof(host_t, destroy));
+       this->addrs->destroy_function(this->addrs, (void*)addr_entry_destroy);
        free(this);
 }
 
@@ -288,19 +287,14 @@ struct private_kernel_interface_t {
        pthread_mutex_t mutex;
        
        /**
-        * List of installed policies (kernel_entry_t)
+        * List of installed policies (policy_entry_t)
         */
        linked_list_t *policies;
        
        /**
-        * List of installed virtual IPs. (vip_entry_t)
+        * Cached list of interfaces and its adresses (iface_entry_t)
         */
-       linked_list_t *vips;
-       
-       /**
-        * Cached list of interfaces and its adresses (interface_entry_t)
-        */
-       linked_list_t *interfaces;
+       linked_list_t *ifaces;
        
        /**
         * iterator used in hook()
@@ -529,8 +523,9 @@ static void process_link(private_kernel_interface_t *this,
        struct rtattr *rta = IFLA_RTA(msg);
        size_t rtasize = IFLA_PAYLOAD (hdr);
        iterator_t *iterator;
-       interface_entry_t *current, *entry = NULL;
+       iface_entry_t *current, *entry = NULL;
        char *name = NULL;
+       bool update = FALSE;
        
        while(RTA_OK(rta, rtasize))
        {
@@ -555,8 +550,8 @@ static void process_link(private_kernel_interface_t *this,
                        {       /* ignore loopback interfaces */
                                break;
                        }
-                       iterator = this->interfaces->create_iterator_locked(this->interfaces,
-                                                                                                                               &this->mutex);
+                       iterator = this->ifaces->create_iterator_locked(this->ifaces,
+                                                                                                                       &this->mutex);
                        while (iterator->iterate(iterator, (void**)&current))
                        {
                                if (current->ifindex == msg->ifi_index)
@@ -567,11 +562,11 @@ static void process_link(private_kernel_interface_t *this,
                        }
                        if (!entry)
                        {
-                               entry = malloc_thing(interface_entry_t);
+                               entry = malloc_thing(iface_entry_t);
                                entry->ifindex = msg->ifi_index;
                                entry->flags = 0;
-                               entry->addresses = linked_list_create();
-                               this->interfaces->insert_last(this->interfaces, entry);
+                               entry->addrs = linked_list_create();
+                               this->ifaces->insert_last(this->ifaces, entry);
                        }
                        memcpy(entry->ifname, name, IFNAMSIZ);
                        entry->ifname[IFNAMSIZ-1] = '\0';
@@ -579,10 +574,12 @@ static void process_link(private_kernel_interface_t *this,
                        {
                                if (!(entry->flags & IFF_UP) && (msg->ifi_flags & IFF_UP))
                                {
+                                       update = TRUE;
                                        DBG1(DBG_KNL, "interface %s activated", name);
                                }
                                if ((entry->flags & IFF_UP) && !(msg->ifi_flags & IFF_UP))
                                {
+                                       update = TRUE;
                                        DBG1(DBG_KNL, "interface %s deactivated", name);
                                }
                        }
@@ -592,8 +589,8 @@ static void process_link(private_kernel_interface_t *this,
                }
                case RTM_DELLINK:
                {
-                       iterator = this->interfaces->create_iterator_locked(this->interfaces,
-                                                                                                                               &this->mutex);
+                       iterator = this->ifaces->create_iterator_locked(this->ifaces,
+                                                                                                                       &this->mutex);
                        while (iterator->iterate(iterator, (void**)&current))
                        {
                                if (current->ifindex == msg->ifi_index)
@@ -608,6 +605,12 @@ static void process_link(private_kernel_interface_t *this,
                        break;
                }
        }
+       
+       /* send an update to all IKE_SAs */
+       if (update && event)
+       {
+               charon->processor->queue_job(charon->processor, (job_t*)roam_job_create());
+       }
 }
 
 /**
@@ -620,9 +623,11 @@ static void process_addr(private_kernel_interface_t *this,
        struct rtattr *rta = IFA_RTA(msg);
        size_t rtasize = IFA_PAYLOAD (hdr);
        host_t *host = NULL;
-       iterator_t *iterator;
-       interface_entry_t *entry;
+       iterator_t *ifaces, *addrs;
+       iface_entry_t *iface;
+       addr_entry_t *addr;
        chunk_t local = chunk_empty, address = chunk_empty;
+       bool update = FALSE, found = FALSE;
        
        while(RTA_OK(rta, rtasize))
        {
@@ -642,7 +647,7 @@ static void process_addr(private_kernel_interface_t *this,
        
        /* For PPP interfaces, we need the IFA_LOCAL address,
         * IFA_ADDRESS is the peers address. But IFA_LOCAL is
-        * not included in all cases, so fallback to IFA_ADDRESS. */
+        * not included in all cases (IPv6?), so fallback to IFA_ADDRESS. */
        if (local.ptr)
        {
                host = host_create_from_chunk(msg->ifa_family, local, 0);
@@ -657,61 +662,58 @@ static void process_addr(private_kernel_interface_t *this,
                return;
        }
        
-       switch (hdr->nlmsg_type)
+       ifaces = this->ifaces->create_iterator_locked(this->ifaces, &this->mutex);
+       while (ifaces->iterate(ifaces, (void**)&iface))
        {
-               case RTM_NEWADDR:
+               if (iface->ifindex == msg->ifa_index)
                {
-                       iterator = this->interfaces->create_iterator_locked(this->interfaces,
-                                                                                                                               &this->mutex);
-                       while (iterator->iterate(iterator, (void**)&entry))
+                       addrs = iface->addrs->create_iterator(iface->addrs, TRUE);
+                       while (addrs->iterate(addrs, (void**)&addr))
                        {
-                               if (entry->ifindex == msg->ifa_index)
+                               if (host->ip_equals(host, addr->ip))
                                {
-                                       entry->addresses->insert_last(entry->addresses,
-                                                                                                 host->clone(host));
-                                       if (event)
+                                       found = TRUE;
+                                       if (hdr->nlmsg_type == RTM_DELADDR)
                                        {
-                                               DBG1(DBG_KNL, "%H appeared on %s", host, entry->ifname);
+                                               addrs->remove(addrs);
+                                               addr_entry_destroy(addr);
+                                               DBG1(DBG_KNL, "%H disappeared from %s", host, iface->ifname);
                                        }
-                                       break;
                                }
                        }
-                       iterator->destroy(iterator);
-                       break;
-               }
-               case RTM_DELADDR:
-               {
-                       iterator = this->interfaces->create_iterator_locked(this->interfaces,
-                                                                                                               &this->mutex);
-                       while (iterator->iterate(iterator, (void**)&entry))
+                       addrs->destroy(addrs);
+               
+                       if (hdr->nlmsg_type == RTM_NEWADDR)
                        {
-                               if (entry->ifindex == msg->ifa_index)
+                               if (!found)
                                {
-                                       iterator_t *addresses;
-                                       host_t *current;
+                                       found = TRUE;
+                                       addr = malloc_thing(addr_entry_t);
+                                       addr->ip = host->clone(host);
+                                       addr->refcount = 1;
                                        
-                                       addresses = entry->addresses->create_iterator(
-                                                                                                       entry->addresses, TRUE);
-                                       while (addresses->iterate(addresses, (void**)&current))
+                                       iface->addrs->insert_last(iface->addrs, addr);
+                                       if (event)
                                        {
-                                               if (current->equals(current, host))
-                                               {
-                                                       addresses->remove(addresses);
-                                                       current->destroy(current);
-                                                       DBG1(DBG_KNL, "%H disappeared from %s", 
-                                                                host, entry->ifname);
-                                               }
+                                               DBG1(DBG_KNL, "%H appeared on %s", host, iface->ifname);
                                        }
-                                       addresses->destroy(addresses);
                                }
                        }
-                       iterator->destroy(iterator);
+                       if (found && (iface->flags & IFF_UP))
+                       {
+                               update = TRUE;
+                       }
                        break;
                }
-               default:
-                       break;
        }
+       ifaces->destroy(ifaces);
        host->destroy(host);
+       
+       /* send an update to all IKE_SAs */
+       if (update && event)
+       {
+               charon->processor->queue_job(charon->processor, (job_t*)roam_job_create());
+       }
 }
 
 /**
@@ -804,6 +806,11 @@ static job_requeue_t receive_events(private_kernel_interface_t *this)
                                case RTM_DELLINK:
                                        process_link(this, hdr, TRUE);
                                        break;
+                               case RTM_NEWROUTE:
+                               case RTM_DELROUTE:
+                                       charon->processor->queue_job(charon->processor,
+                                                                                                (job_t*)roam_job_create());
+                                       break;
                                default:
                                        break;
                        }
@@ -977,9 +984,9 @@ static status_t init_address_list(private_kernel_interface_t *this)
        struct nlmsghdr *out, *current, *in;
        struct rtgenmsg *msg;
        size_t len;
-       iterator_t *i_iface, *i_addr;
-       host_t *address;
-       interface_entry_t *entry;
+       iterator_t *ifaces, *addrs;
+       iface_entry_t *iface;
+       addr_entry_t *addr;
        
        DBG1(DBG_KNL, "listening on interfaces:");
        
@@ -1039,31 +1046,39 @@ static status_t init_address_list(private_kernel_interface_t *this)
        }
        free(out);
        
-       i_iface = this->interfaces->create_iterator_locked(this->interfaces,
-                                                                                                          &this->mutex);
-       while (i_iface->iterate(i_iface, (void**)&entry))
+       ifaces = this->ifaces->create_iterator_locked(this->ifaces, &this->mutex);
+       while (ifaces->iterate(ifaces, (void**)&iface))
        {
-               if (entry->flags & IFF_UP)
+               if (iface->flags & IFF_UP)
                {
-                       DBG1(DBG_KNL, "  %s", entry->ifname);
-                       i_addr = entry->addresses->create_iterator(entry->addresses, TRUE);
-                       while (i_addr->iterate(i_addr, (void**)&address))
+                       DBG1(DBG_KNL, "  %s", iface->ifname);
+                       addrs = iface->addrs->create_iterator(iface->addrs, TRUE);
+                       while (addrs->iterate(addrs, (void**)&addr))
                        {
-                               DBG1(DBG_KNL, "    %H", address);
+                               DBG1(DBG_KNL, "    %H", addr->ip);
                        }
-                       i_addr->destroy(i_addr);
+                       addrs->destroy(addrs);
                }
        }
-       i_iface->destroy(i_iface);
-       
+       ifaces->destroy(ifaces);
        return SUCCESS;
 }
 
 /**
- * iterator hook to return address, not address_entry_t
+ * iterator hook to iterate over addrs
  */
-static hook_result_t hook(private_kernel_interface_t *this,
-                                                 interface_entry_t *in, host_t **out)
+static hook_result_t addr_hook(private_kernel_interface_t *this,
+                                                          addr_entry_t *in, host_t **out)
+{
+       *out = in->ip;
+       return HOOK_NEXT;
+}
+                                                               
+/**
+ * iterator hook to iterate over ifaces
+ */
+static hook_result_t iface_hook(private_kernel_interface_t *this,
+                                                               iface_entry_t *in, host_t **out)
 {
        if (!(in->flags & IFF_UP))
        {       /* skip interfaces not up */
@@ -1072,7 +1087,9 @@ static hook_result_t hook(private_kernel_interface_t *this,
 
        if (this->hiter == NULL)
        {
-               this->hiter = in->addresses->create_iterator(in->addresses, TRUE);
+               this->hiter = in->addrs->create_iterator(in->addrs, TRUE);
+               this->hiter->set_iterator_hook(this->hiter,
+                                                                          (iterator_hook_t*)addr_hook, this);
        }
        while (this->hiter->iterate(this->hiter, (void**)out))
        {
@@ -1090,9 +1107,8 @@ static iterator_t *create_address_iterator(private_kernel_interface_t *this)
 {
        iterator_t *iterator;
        
-       iterator = this->interfaces->create_iterator_locked(this->interfaces,
-                                                                                                               &this->mutex);
-       iterator->set_iterator_hook(iterator, (iterator_hook_t*)hook, this);
+       iterator = this->ifaces->create_iterator_locked(this->ifaces, &this->mutex);
+       iterator->set_iterator_hook(iterator, (iterator_hook_t*)iface_hook, this);
        return iterator;
 }
 
@@ -1101,33 +1117,32 @@ static iterator_t *create_address_iterator(private_kernel_interface_t *this)
  */
 static char *get_interface_name(private_kernel_interface_t *this, host_t* ip)
 {
-       iterator_t *iterator, *addresses;
-       interface_entry_t *entry;
-       host_t *host;
+       iterator_t *ifaces, *addrs;
+       iface_entry_t *iface;
+       addr_entry_t *addr;
        char *name = NULL;
        
        DBG2(DBG_KNL, "getting interface name for %H", ip);
        
-       iterator = this->interfaces->create_iterator_locked(this->interfaces,   
-                                                                                                               &this->mutex);
-       while (iterator->iterate(iterator, (void**)&entry))
+       ifaces = this->ifaces->create_iterator_locked(this->ifaces, &this->mutex);
+       while (ifaces->iterate(ifaces, (void**)&iface))
        {
-               addresses = entry->addresses->create_iterator(entry->addresses, TRUE);
-               while (addresses->iterate(addresses, (void**)&host))
+               addrs = iface->addrs->create_iterator(iface->addrs, TRUE);
+               while (addrs->iterate(addrs, (void**)&addr))
                {
-                       if (ip->ip_equals(ip, host))
+                       if (ip->ip_equals(ip, addr->ip))
                        {
-                               name = strdup(entry->ifname);
+                               name = strdup(iface->ifname);
                                break;
                        }
                }
-               addresses->destroy(addresses);
+               addrs->destroy(addrs);
                if (name)
                {
                        break;
                }
        }
-       iterator->destroy(iterator);
+       ifaces->destroy(ifaces);
        
        if (name)
        {
@@ -1147,8 +1162,9 @@ static char *get_interface_name(private_kernel_interface_t *this, host_t* ip)
 static status_t get_address_by_ts(private_kernel_interface_t *this,
                                                                  traffic_selector_t *ts, host_t **ip)
 {
-       iterator_t *iterator, *addresses;
-       interface_entry_t *entry;
+       iterator_t *ifaces, *addrs;
+       iface_entry_t *iface;
+       addr_entry_t *addr;
        host_t *host;
        int family;
        bool found = FALSE;
@@ -1177,27 +1193,26 @@ static status_t get_address_by_ts(private_kernel_interface_t *this,
        }
        host->destroy(host);
        
-       iterator = this->interfaces->create_iterator_locked(this->interfaces,   
-                                                                                                               &this->mutex);
-       while (iterator->iterate(iterator, (void**)&entry))
+       ifaces = this->ifaces->create_iterator_locked(this->ifaces,     &this->mutex);
+       while (ifaces->iterate(ifaces, (void**)&iface))
        {
-               addresses = entry->addresses->create_iterator(entry->addresses, TRUE);
-               while (addresses->iterate(addresses, (void**)&host))
+               addrs = iface->addrs->create_iterator(iface->addrs, TRUE);
+               while (addrs->iterate(addrs, (void**)&addr))
                {
-                       if (ts->includes(ts, host))
+                       if (ts->includes(ts, addr->ip))
                        {
                                found = TRUE;
-                               *ip = host->clone(host);
+                               *ip = addr->ip->clone(addr->ip);
                                break;
                        }
                }
-               addresses->destroy(addresses);
+               addrs->destroy(addrs);
                if (found)
                {
                        break;
                }
        }
-       iterator->destroy(iterator);
+       ifaces->destroy(ifaces);
        
        if (!found)
        {
@@ -1213,33 +1228,32 @@ static status_t get_address_by_ts(private_kernel_interface_t *this,
  */
 static int get_interface_index(private_kernel_interface_t *this, host_t* ip)
 {
-       iterator_t *iterator, *addresses;
-       interface_entry_t *entry;
-       host_t *host;
+       iterator_t *ifaces, *addrs;
+       iface_entry_t *iface;
+       addr_entry_t *addr;
        int ifindex = 0;
        
        DBG2(DBG_KNL, "getting iface for %H", ip);
        
-       iterator = this->interfaces->create_iterator_locked(this->interfaces,   
-                                                                                                               &this->mutex);
-       while (iterator->iterate(iterator, (void**)&entry))
+       ifaces = this->ifaces->create_iterator_locked(this->ifaces,     &this->mutex);
+       while (ifaces->iterate(ifaces, (void**)&iface))
        {
-               addresses = entry->addresses->create_iterator(entry->addresses, TRUE);
-               while (addresses->iterate(addresses, (void**)&host))
+               addrs = iface->addrs->create_iterator(iface->addrs, TRUE);
+               while (addrs->iterate(addrs, (void**)&addr))
                {
-                       if (ip->ip_equals(ip, host))
+                       if (ip->ip_equals(ip, addr->ip))
                        {
-                               ifindex = entry->ifindex;
+                               ifindex = iface->ifindex;
                                break;
                        }
                }
-               addresses->destroy(addresses);
+               addrs->destroy(addrs);
                if (ifindex)
                {
                        break;
                }
        }
-       iterator->destroy(iterator);
+       ifaces->destroy(ifaces);
 
        if (ifindex == 0)
        {
@@ -1415,7 +1429,7 @@ static host_t* get_source_addr(private_kernel_interface_t *this, host_t *dest)
        }
        if (source == NULL)
        {
-               DBG1(DBG_KNL, "no route found to %H", dest);
+               DBG2(DBG_KNL, "no route found to %H", dest);
        }
        free(out);
        return source;
@@ -1427,111 +1441,105 @@ static host_t* get_source_addr(private_kernel_interface_t *this, host_t *dest)
 static status_t add_ip(private_kernel_interface_t *this, 
                                                host_t *virtual_ip, host_t *iface_ip)
 {
-       int targetif;
-       vip_entry_t *listed;
-       interface_entry_t *entry;
-       iterator_t *iterator;
+       iface_entry_t *iface;
+       addr_entry_t *addr;
+       iterator_t *addrs, *ifaces;
 
        DBG2(DBG_KNL, "adding virtual IP %H", virtual_ip);
-
-       targetif = get_interface_index(this, iface_ip);
-       if (targetif == 0)
-       {
-               DBG1(DBG_KNL, "unable to add virtual IP %H, no iface found for %H",
-                        virtual_ip, iface_ip);
-               return FAILED;
-       }
-
-       /* beware of deadlocks (e.g. send/receive packets while holding the lock) */
-       iterator = this->vips->create_iterator_locked(this->vips, &this->mutex);
-       while (iterator->iterate(iterator, (void**)&listed))
+       
+       ifaces = this->ifaces->create_iterator_locked(this->ifaces, &this->mutex);
+       while (ifaces->iterate(ifaces, (void**)&iface))
        {
-               if (listed->if_index == targetif &&
-                       virtual_ip->ip_equals(virtual_ip, listed->ip))
+               bool iface_found = FALSE;
+       
+               addrs = iface->addrs->create_iterator(iface->addrs, TRUE);
+               while (addrs->iterate(addrs, (void**)&addr))
                {
-                       listed->refcount++;
-                       iterator->destroy(iterator);
-                       DBG2(DBG_KNL, "virtual IP %H already added to iface %d reusing it",
-                                virtual_ip, targetif);
-                       return SUCCESS;
+                       if (iface_ip->ip_equals(iface_ip, addr->ip))
+                       {
+                               iface_found = TRUE;
+                       }
+                       else if (virtual_ip->ip_equals(virtual_ip, addr->ip))
+                       {
+                               addr->refcount++;
+                               DBG2(DBG_KNL, "virtual IP %H already installed on %s",
+                                        virtual_ip, iface->ifname);
+                               addrs->destroy(addrs);
+                               ifaces->destroy(ifaces);
+                               return SUCCESS;
+                       }
                }
-       }
-       iterator->destroy(iterator);
-
-       if (manage_ipaddr(this, RTM_NEWADDR, NLM_F_CREATE | NLM_F_EXCL,
-                                         targetif, virtual_ip) == SUCCESS)
-       {
-               listed = malloc_thing(vip_entry_t);
-               listed->ip = virtual_ip->clone(virtual_ip);
-               listed->if_index = targetif;
-               listed->refcount = 1;
-               DBG2(DBG_KNL, "virtual IP %H added to iface %d", virtual_ip, targetif);
-               iterator = this->interfaces->create_iterator_locked(this->interfaces,
-                                                                                                                       &this->mutex);
-               this->vips->insert_last(this->vips, listed);
-               /* we add the VIP also to the cached interface list; the netlink
-                * event comes in asynchronous and may be to late */
-               while (iterator->iterate(iterator, (void**)&entry))
+               addrs->destroy(addrs);
+               
+               if (iface_found)
                {
-                       if (entry->ifindex == targetif)
+                       int ifindex = iface->ifindex;
+                       ifaces->destroy(ifaces);
+                       if (manage_ipaddr(this, RTM_NEWADDR, NLM_F_CREATE | NLM_F_EXCL,
+                                                         ifindex, virtual_ip) == SUCCESS)
                        {
-                               entry->addresses->insert_last(entry->addresses,
-                                                                                         virtual_ip->clone(virtual_ip));
-                               break;
+                               addr = malloc_thing(addr_entry_t);
+                               addr->ip = virtual_ip->clone(virtual_ip);
+                               addr->refcount = 1;
+                               pthread_mutex_lock(&this->mutex);
+                               iface->addrs->insert_last(iface->addrs, addr);
+                               pthread_mutex_unlock(&this->mutex);
+                               return SUCCESS;
                        }
+                       DBG2(DBG_KNL, "adding virtual IP %H failed", virtual_ip);
+                       return FAILED;
+                       
                }
-               iterator->destroy(iterator);
-               return SUCCESS;
+               
        }
+       ifaces->destroy(ifaces);
        
-       DBG2(DBG_KNL, "unable to add virtual IP %H to iface %d",
-                virtual_ip, targetif);
+       DBG2(DBG_KNL, "interface address %H not found, unable to install"
+                "virtual IP %H", iface_ip, virtual_ip);
        return FAILED;
 }
 
 /**
  * Implementation of kernel_interface_t.del_ip.
  */
-static status_t del_ip(private_kernel_interface_t *this,
-                                               host_t *virtual_ip, host_t *iface_ip)
+static status_t del_ip(private_kernel_interface_t *this, host_t *virtual_ip)
 {
-       int targetif;
-       vip_entry_t *listed;
-       iterator_t *iterator;
+       iface_entry_t *iface;
+       addr_entry_t *addr;
+       iterator_t *addrs, *ifaces;
 
        DBG2(DBG_KNL, "deleting virtual IP %H", virtual_ip);
-
-       targetif = get_interface_index(this, iface_ip);
-       if (targetif == 0)
-       {
-               DBG1(DBG_KNL, "unable to delete virtual IP %H, no iface found for %H",
-                        virtual_ip, iface_ip);
-               return FAILED;
-       }
-
-       /* beware of deadlocks (e.g. send/receive packets while holding the lock) */
-       iterator = this->vips->create_iterator_locked(this->vips, &this->mutex);
-       while (iterator->iterate(iterator, (void**)&listed))
+       
+       ifaces = this->ifaces->create_iterator_locked(this->ifaces, &this->mutex);
+       while (ifaces->iterate(ifaces, (void**)&iface))
        {
-               if (listed->if_index == targetif &&
-                       virtual_ip->ip_equals(virtual_ip, listed->ip))
+               addrs = iface->addrs->create_iterator(iface->addrs, TRUE);
+               while (addrs->iterate(addrs, (void**)&addr))
                {
-                       listed->refcount--;
-                       if (listed->refcount == 0)
+                       if (virtual_ip->ip_equals(virtual_ip, addr->ip))
                        {
-                               iterator->remove(iterator);
-                               vip_entry_destroy(listed);
-                               iterator->destroy(iterator);
-                               return manage_ipaddr(this, RTM_DELADDR, 0, targetif, virtual_ip);
+                               int ifindex = iface->ifindex;
+                               addr->refcount--;
+                               if (addr->refcount == 0)
+                               {
+                                       addrs->remove(addrs);
+                                       addrs->destroy(addrs);
+                                       ifaces->destroy(ifaces);
+                                       addr_entry_destroy(addr);
+                                       return manage_ipaddr(this, RTM_DELADDR, 0,
+                                                                                ifindex, virtual_ip);
+                               }
+                               DBG2(DBG_KNL, "virtual IP %H used by other SAs, not deleting",
+                                        virtual_ip);
+                               addrs->destroy(addrs);
+                               ifaces->destroy(ifaces);
+                               return SUCCESS;
                        }
-                       iterator->destroy(iterator);
-                       DBG2(DBG_KNL, "virtual IP %H used by other SAs, not deleting",
-                                virtual_ip);
-                       return SUCCESS;
                }
+               addrs->destroy(addrs);
        }
-       iterator->destroy(iterator);
+       ifaces->destroy(ifaces);
+       
        DBG2(DBG_KNL, "virtual IP %H not cached, unable to delete", virtual_ip);
        return FAILED;
 }
@@ -1759,10 +1767,10 @@ static status_t add_sa(private_kernel_interface_t *this,
  * Implementation of kernel_interface_t.update_sa.
  */
 static status_t update_sa(private_kernel_interface_t *this,
-                                                 host_t *src, host_t *dst, 
-                                                 host_t *new_src, host_t *new_dst, 
-                                                 host_diff_t src_changes, host_diff_t dst_changes,
-                                                 u_int32_t spi, protocol_id_t protocol)
+                                                 host_t *dst, u_int32_t spi,
+                                                 protocol_id_t protocol,
+                                                 host_t *new_src, host_t *new_dst,
+                                                 host_diff_t src_changes, host_diff_t dst_changes)
 {
        unsigned char request[BUFFER_SIZE];
        struct nlmsghdr *hdr, *out = NULL;
@@ -2277,9 +2285,8 @@ static void destroy(private_kernel_interface_t *this)
        close(this->socket_xfrm);
        close(this->socket_rt_events);
        close(this->socket_rt);
-       this->vips->destroy(this->vips);
        this->policies->destroy(this->policies);
-       this->interfaces->destroy_function(this->interfaces, (void*)interface_entry_destroy);
+       this->ifaces->destroy_function(this->ifaces, (void*)iface_entry_destroy);
        free(this);
 }
 
@@ -2305,13 +2312,12 @@ kernel_interface_t *kernel_interface_create()
        this->public.create_address_iterator = (iterator_t*(*)(kernel_interface_t*))create_address_iterator;
        this->public.get_source_addr = (host_t*(*)(kernel_interface_t*, host_t *dest))get_source_addr;
        this->public.add_ip = (status_t(*)(kernel_interface_t*,host_t*,host_t*)) add_ip;
-       this->public.del_ip = (status_t(*)(kernel_interface_t*,host_t*,host_t*)) del_ip;
+       this->public.del_ip = (status_t(*)(kernel_interface_t*,host_t*)) del_ip;
        this->public.destroy = (void(*)(kernel_interface_t*)) destroy;
 
        /* private members */
-       this->vips = linked_list_create();
        this->policies = linked_list_create();
-       this->interfaces = linked_list_create();
+       this->ifaces = linked_list_create();
        this->hiter = NULL;
        this->seq = 200;
        pthread_mutex_init(&this->mutex,NULL);
@@ -2331,13 +2337,14 @@ kernel_interface_t *kernel_interface_create()
                charon->kill(charon, "unable to bind RT netlink socket");
        }
        
-       /* create and bind RT socket for events (address/interface changes) */
+       /* create and bind RT socket for events (address/interface/route changes) */
        this->socket_rt_events = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
        if (this->socket_rt_events <= 0)
        {
                charon->kill(charon, "unable to create RT event socket");
        }
-       addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | RTMGRP_LINK;
+       addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | 
+                                        RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_ROUTE | RTMGRP_LINK;
        if (bind(this->socket_rt_events, (struct sockaddr*)&addr, sizeof(addr)))
        {
                charon->kill(charon, "unable to bind RT event socket");
index 39eb6d4..62acb45 100644 (file)
@@ -325,13 +325,11 @@ struct kernel_interface_t {
         *
         * @param this                  calling object
         * @param virtual_ip    virtual ip address to assign
-        * @param iface_ip              IP of an interface to remove virtual IP from
         * @return
         *                                              - SUCCESS
         *                                              - FAILED if kernel comm failed
         */
-       status_t (*del_ip) (kernel_interface_t *this, host_t *virtual_ip,
-                                               host_t *iface_ip);
+       status_t (*del_ip) (kernel_interface_t *this, host_t *virtual_ip);
        
        /**
         * @brief Destroys a kernel_interface object.
diff --git a/src/charon/processing/jobs/roam_job.c b/src/charon/processing/jobs/roam_job.c
new file mode 100644 (file)
index 0000000..c5acad6
--- /dev/null
@@ -0,0 +1,108 @@
+/**
+ * @file roam_job.c
+ * 
+ * @brief Implementation of roam_job_t.
+ * 
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+
+#include <stdlib.h>
+
+#include "roam_job.h"
+
+#include <sa/ike_sa.h>
+#include <daemon.h>
+
+
+typedef struct private_roam_job_t private_roam_job_t;
+
+/**
+ * Private data of an roam_job_t Object
+ */
+struct private_roam_job_t {
+       /**
+        * public roam_job_t interface
+        */
+       roam_job_t public;
+};
+
+/**
+ * Implements job_t.destroy.
+ */
+static void destroy(private_roam_job_t *this)
+{
+       free(this);
+}
+
+/**
+ * Implementation of job_t.execute. 
+ */ 
+static void execute(private_roam_job_t *this)
+{
+       ike_sa_t *ike_sa;
+       linked_list_t *list;
+       ike_sa_id_t *id;
+       iterator_t *iterator;
+       
+       /* iterating over all IKE_SAs gives us no way to checkin_and_destroy 
+        * after a DESTROY_ME, so we check out each available IKE_SA by hand. */
+       list = linked_list_create();
+       iterator = charon->ike_sa_manager->create_iterator(charon->ike_sa_manager);
+       while (iterator->iterate(iterator, (void**)&ike_sa))
+       {
+               id = ike_sa->get_id(ike_sa);
+               list->insert_last(list, id->clone(id));
+       }
+       iterator->destroy(iterator);
+       
+       while (list->remove_last(list, (void**)&id) == SUCCESS)
+       {
+               ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, id);
+               if (ike_sa)
+               {
+                       if (ike_sa->roam(ike_sa) == DESTROY_ME)
+                       {
+                               charon->ike_sa_manager->checkin_and_destroy(
+                                                                                       charon->ike_sa_manager, ike_sa);
+                       }
+                       else
+                       {
+                               charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+                       }
+               }
+               id->destroy(id);
+       }
+       list->destroy(list);
+
+       destroy(this);
+}
+
+/*
+ * Described in header
+ */
+roam_job_t *roam_job_create()
+{
+       private_roam_job_t *this = malloc_thing(private_roam_job_t);
+       
+       this->public.job_interface.destroy = (void (*) (job_t *)) destroy;
+       this->public.job_interface.execute = (void (*) (job_t *)) execute;
+       this->public.job_interface.destroy = (void (*) (job_t *)) destroy;
+
+       return &this->public;
+}
+
diff --git a/src/charon/processing/jobs/roam_job.h b/src/charon/processing/jobs/roam_job.h
new file mode 100644 (file)
index 0000000..23d374c
--- /dev/null
@@ -0,0 +1,60 @@
+/**
+ * @file roam_job.h
+ * 
+ * @brief Interface of roam_job_t.
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef ROAM_JOB_H_
+#define ROAM_JOB_H_
+
+typedef struct roam_job_t roam_job_t;
+
+#include <library.h>
+#include <sa/ike_sa_id.h>
+#include <processing/jobs/job.h>
+
+/**
+ * @brief A job to inform IKE_SAs about changed local address setup.
+ * 
+ * If a local address appears or disappears, the kernel fires this job to
+ * update all IKE_SAs.
+ * 
+ * @b Constructors:
+ * - roam_job_create()
+ * 
+ * @ingroup jobs
+ */
+struct roam_job_t {
+
+       /**
+        * implements job_t interface
+        */
+       job_t job_interface;
+};
+
+/**
+ * @brief Creates a job to inform IKE_SAs about an updated address list.
+ * 
+ * @return                             initiate_ike_sa_job_t object
+ * 
+ * @ingroup jobs
+ */
+roam_job_t *roam_job_create();
+
+#endif /*ROAM_JOB_H_*/
+
index cb259d9..f6786bf 100644 (file)
@@ -88,9 +88,7 @@ send_dpd_job_t *send_dpd_job_create(ike_sa_id_t *ike_sa_id)
        /* interface functions */
        this->public.job_interface.destroy = (void (*) (job_t *)) destroy;
        this->public.job_interface.execute = (void (*) (job_t *)) execute;
-       
-       /* public functions */
-       this->public.destroy = (void (*)(send_dpd_job_t *)) destroy;
+       this->public.job_interface.destroy = (void (*) (job_t *)) destroy;
        
        /* private variables */
        this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
index 26c9e2e..0e40591 100644 (file)
@@ -45,13 +45,6 @@ struct send_dpd_job_t {
         * implements job_t interface
         */
        job_t job_interface;
-       
-       /**
-        * @brief Destroys an send_dpd_job_t object.
-        *
-        * @param this  send_dpd_job_t object to destroy
-        */
-       void (*destroy) (send_dpd_job_t *this);
 };
 
 /**
index 6d529e1..8cb51e5 100644 (file)
@@ -82,9 +82,7 @@ send_keepalive_job_t *send_keepalive_job_create(ike_sa_id_t *ike_sa_id)
        /* interface functions */
        this->public.job_interface.destroy = (void (*) (job_t *)) destroy;
        this->public.job_interface.execute = (void (*) (job_t *)) execute;
-       
-       /* public functions */
-       this->public.destroy = (void (*)(send_keepalive_job_t *)) destroy;
+       this->public.job_interface.destroy = (void (*) (job_t *)) destroy;
        
        /* private variables */
        this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
index f7b3833..e8d214a 100644 (file)
@@ -44,13 +44,6 @@ struct send_keepalive_job_t {
         * implements job_t interface
         */
        job_t job_interface;
-       
-       /**
-        * @brief Destroys an send_keepalive_job_t object.
-        *
-        * @param this  send_keepalive_job_t object to destroy
-        */
-       void (*destroy) (send_keepalive_job_t *this);
 };
 
 /**
index a23bb4a..00f9596 100644 (file)
@@ -48,6 +48,7 @@
 #include <sa/task_manager.h>
 #include <sa/tasks/ike_init.h>
 #include <sa/tasks/ike_natd.h>
+#include <sa/tasks/ike_mobike.h>
 #include <sa/tasks/ike_auth.h>
 #include <sa/tasks/ike_config.h>
 #include <sa/tasks/ike_cert.h>
@@ -148,6 +149,11 @@ struct private_ike_sa_t {
         * set of extensions the peer supports
         */
        ike_extension_t extensions;
+       
+       /**
+        * set of condition flags currently enabled for this IKE_SA
+        */
+       ike_condition_t conditions;
 
        /**
         * Linked List containing the child sa's of the current IKE_SA.
@@ -195,16 +201,6 @@ struct private_ike_sa_t {
        chunk_t skp_verify;
        
        /**
-        * NAT status of local host.
-        */
-       bool nat_here;
-       
-       /**
-        * NAT status of remote host.
-        */
-       bool nat_there;
-       
-       /**
         * Virtual IP on local host, if any
         */
        host_t *my_virtual_ip;
@@ -218,6 +214,11 @@ struct private_ike_sa_t {
         * List of DNS servers installed by us
         */
        linked_list_t *dns_servers;
+       
+       /**
+        * list of peers additional addresses, transmitted via MOBIKE
+        */
+       linked_list_t *additional_addresses;
 
        /**
         * Timestamps for this IKE_SA
@@ -605,7 +606,7 @@ static void update_hosts(private_ike_sa_t *this, host_t *me, host_t *other)
                this->my_host = me->clone(me);
        }
        
-       if (!this->nat_here)
+       if (!(this->conditions & COND_NAT_THERE))
        {
                /* update without restrictions if we are not NATted */
                if (other_diff)
@@ -806,6 +807,8 @@ static status_t initiate(private_ike_sa_t *this, child_cfg_t *child_cfg)
                this->task_manager->queue_task(this->task_manager, task);
                task = (task_t*)ike_config_create(&this->public, TRUE);
                this->task_manager->queue_task(this->task_manager, task);
+               task = (task_t*)ike_mobike_create(&this->public, TRUE);
+               this->task_manager->queue_task(this->task_manager, task);
        }
        
        task = (task_t*)child_create_create(&this->public, child_cfg);
@@ -866,6 +869,8 @@ static status_t acquire(private_ike_sa_t *this, u_int32_t reqid)
                this->task_manager->queue_task(this->task_manager, task);
                task = (task_t*)ike_config_create(&this->public, TRUE);
                this->task_manager->queue_task(this->task_manager, task);
+               task = (task_t*)ike_mobike_create(&this->public, TRUE);
+               this->task_manager->queue_task(this->task_manager, task);
        }
        
        child_cfg = child_sa->get_config(child_sa);
@@ -1092,6 +1097,8 @@ static status_t retransmit(private_ike_sa_t *this, u_int32_t message_id)
                                        task = (task_t*)child_create_create(&new->public, child_cfg);
                                        new->task_manager->queue_task(new->task_manager, task);
                                }
+                               task = (task_t*)ike_mobike_create(&new->public, TRUE);
+                               new->task_manager->queue_task(new->task_manager, task);
                                new->task_manager->initiate(new->task_manager);
                        }
                        charon->ike_sa_manager->checkin(charon->ike_sa_manager, &new->public);
@@ -1205,8 +1212,7 @@ static void set_virtual_ip(private_ike_sa_t *this, bool local, host_t *ip)
                {
                        DBG1(DBG_IKE, "removing old virtual IP %H", this->my_virtual_ip);
                        charon->kernel_interface->del_ip(charon->kernel_interface,
-                                                                                        this->my_virtual_ip,
-                                                                                        this->my_host);
+                                                                                        this->my_virtual_ip);
                        this->my_virtual_ip->destroy(this->my_virtual_ip);
                }
                if (charon->kernel_interface->add_ip(charon->kernel_interface, ip,
@@ -1255,7 +1261,77 @@ static void enable_extension(private_ike_sa_t *this, ike_extension_t extension)
  */
 static bool supports_extension(private_ike_sa_t *this, ike_extension_t extension)
 {
-       return this->extensions & extension;
+       return (this->extensions & extension) != FALSE;
+}
+
+/**
+ * Implementation of ike_sa_t.has_condition.
+ */
+static bool has_condition(private_ike_sa_t *this, ike_condition_t condition)
+{
+       return (this->conditions & condition) != FALSE;
+}
+
+/**
+ * Implementation of ike_sa_t.enable_condition.
+ */
+static void set_condition(private_ike_sa_t *this, ike_condition_t condition,
+                                                 bool enable)
+{
+       if (has_condition(this, condition) != enable)
+       {
+               if (enable)
+               {
+                       switch (condition)
+                       {
+                               case COND_STALE:
+                                       DBG1(DBG_IKE, "no route to %H, setting IKE_SA to stale",
+                                                this->other_host);
+                                       break;
+                               case COND_NAT_HERE:
+                                       DBG1(DBG_IKE, "local host is behind NAT, sending keep alives");
+                                       this->conditions |= COND_NAT_ANY;
+                                       send_keepalive(this);
+                                       break;
+                               case COND_NAT_THERE:
+                                       DBG1(DBG_IKE, "remote host is behind NAT");
+                                       this->conditions |= COND_NAT_ANY;
+                                       break;
+                               default:
+                                       break;
+                       }
+                       this->conditions |= condition;
+               }
+               else
+               {
+                       switch (condition)
+                       {
+                               case COND_STALE:
+                                       DBG1(DBG_IKE, "new route to %H found", this->other_host);
+                                       break;
+                               default:
+                                       break;
+                       }
+                       this->conditions &= ~condition;
+               }
+       }
+}
+
+/**
+ * Implementation of ike_sa_t.add_additional_address.
+ */
+static void add_additional_address(private_ike_sa_t *this, host_t *host)
+{
+       this->additional_addresses->insert_last(this->additional_addresses, host);
+}
+       
+/**
+ * Implementation of ike_sa_t.create_additional_address_iterator.
+ */
+static iterator_t* create_additional_address_iterator(private_ike_sa_t *this)
+{
+       return this->additional_addresses->create_iterator(
+                                                                                       this->additional_addresses, TRUE);
 }
 
 /**
@@ -1588,6 +1664,84 @@ static status_t reestablish(private_ike_sa_t *this)
        
        return this->task_manager->initiate(this->task_manager);
 }
+       
+/**
+ * Implementation of ike_sa_t.roam.
+ */
+static status_t roam(private_ike_sa_t *this)
+{
+       iterator_t *iterator;
+       host_t *me, *other;
+       ike_mobike_t *mobike;
+       
+       /* only initiator handles address updated actively */
+       if (!this->ike_sa_id->is_initiator(this->ike_sa_id))
+       {
+               return SUCCESS;
+       }
+       
+       me = charon->kernel_interface->get_source_addr(charon->kernel_interface,
+                                                                                                  this->other_host);
+       if (me)
+       {
+               set_condition(this, COND_STALE, FALSE);
+               /* attachment still the same? */
+               if (me->ip_equals(me, this->my_host))
+               {
+                       DBG2(DBG_IKE, "%H still reached through %H, no update needed",
+                                this->other_host, me);
+                       me->destroy(me);
+                       return SUCCESS;
+               }
+               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)
+               {
+                       mobike = ike_mobike_create(&this->public, TRUE);
+                       mobike->roam(mobike, me, NULL);
+                       this->task_manager->queue_task(this->task_manager, (task_t*)mobike);
+                       return this->task_manager->initiate(this->task_manager);
+               }
+               /* reestablish if not */
+               set_my_host(this, me);
+               return reestablish(this);
+       }
+       
+       /* there is nothing we can do without mobike */
+       if (!(this->extensions & 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);
+       while (iterator->iterate(iterator, (void**)&other))
+       {
+               me = charon->kernel_interface->get_source_addr(charon->kernel_interface,
+                                                                                                          other);
+               if (me)
+               {
+                       /* good, we have a new route. Use MOBIKE to update */
+                       iterator->destroy(iterator);
+                       mobike = ike_mobike_create(&this->public, TRUE);
+                       mobike->roam(mobike, me, other);
+                       this->task_manager->queue_task(this->task_manager, (task_t*)mobike);
+                       return this->task_manager->initiate(this->task_manager);
+               }
+       }
+       iterator->destroy(iterator);
+       return SUCCESS;
+}
 
 /**
  * Implementation of ike_sa_t.inherit.
@@ -1641,32 +1795,6 @@ static status_t inherit(private_ike_sa_t *this, private_ike_sa_t *other)
 }
 
 /**
- * Implementation of ike_sa_t.is_natt_enabled.
- */
-static bool is_natt_enabled(private_ike_sa_t *this)
-{
-       return this->nat_here || this->nat_there;
-}
-
-/**
- * Implementation of ike_sa_t.enable_natt.
- */
-static void enable_natt(private_ike_sa_t *this, bool local)
-{
-       if (local)
-       {
-               DBG1(DBG_IKE, "local host is behind NAT, scheduling keep alives");
-               this->nat_here = TRUE;
-               send_keepalive(this);
-       }
-       else
-       {
-               DBG1(DBG_IKE, "remote host is behind NAT");
-               this->nat_there = TRUE;
-       }
-}
-
-/**
  * Implementation of ike_sa_t.remove_dns_server
  */
 static void remove_dns_servers(private_ike_sa_t *this)
@@ -1818,13 +1946,16 @@ static void destroy(private_ike_sa_t *this)
        if (this->my_virtual_ip)
        {
                charon->kernel_interface->del_ip(charon->kernel_interface,
-                                                                                this->my_virtual_ip, this->my_host);
+                                                                                this->my_virtual_ip);
                this->my_virtual_ip->destroy(this->my_virtual_ip);
        }
        DESTROY_IF(this->other_virtual_ip);
        
        remove_dns_servers(this);
-       this->dns_servers->destroy_offset(this->dns_servers, offsetof(host_t, destroy));
+       this->dns_servers->destroy_offset(this->dns_servers,
+                                                                                                       offsetof(host_t, destroy));
+       this->additional_addresses->destroy_offset(this->additional_addresses,
+                                                                                                       offsetof(host_t, destroy));
        
        DESTROY_IF(this->my_host);
        DESTROY_IF(this->other_host);
@@ -1874,6 +2005,10 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
        this->public.set_other_ca = (void (*)(ike_sa_t*,ca_info_t*)) set_other_ca;
        this->public.enable_extension = (void(*)(ike_sa_t*, ike_extension_t extension))enable_extension;
        this->public.supports_extension = (bool(*)(ike_sa_t*, ike_extension_t extension))supports_extension;
+       this->public.set_condition = (void (*)(ike_sa_t*, ike_condition_t,bool)) set_condition;
+       this->public.has_condition = (bool (*)(ike_sa_t*,ike_condition_t)) has_condition;
+       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.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;
@@ -1890,10 +2025,9 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
        this->public.rekey_child_sa = (status_t (*)(ike_sa_t*,protocol_id_t,u_int32_t)) rekey_child_sa;
        this->public.delete_child_sa = (status_t (*)(ike_sa_t*,protocol_id_t,u_int32_t)) delete_child_sa;
        this->public.destroy_child_sa = (status_t (*)(ike_sa_t*,protocol_id_t,u_int32_t))destroy_child_sa;
-       this->public.enable_natt = (void (*)(ike_sa_t*, bool)) enable_natt;
-       this->public.is_natt_enabled = (bool (*)(ike_sa_t*)) is_natt_enabled;
        this->public.rekey = (status_t (*)(ike_sa_t*))rekey;
        this->public.reestablish = (status_t (*)(ike_sa_t*))reestablish;
+       this->public.roam = (status_t(*)(ike_sa_t*))roam;
        this->public.inherit = (status_t (*)(ike_sa_t*,ike_sa_t*))inherit;
        this->public.generate_message = (status_t (*)(ike_sa_t*,message_t*,packet_t**))generate_message;
        this->public.reset = (void (*)(ike_sa_t*))reset;
@@ -1911,6 +2045,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
        this->other_id = identification_create_from_encoding(ID_ANY, chunk_empty);
        this->other_ca = NULL;
        this->extensions = 0;
+       this->conditions = 0;
        this->crypter_in = NULL;
        this->crypter_out = NULL;
        this->signer_in = NULL;
@@ -1919,8 +2054,6 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
        this->skp_verify = chunk_empty;
        this->skp_build = chunk_empty;
        this->child_prf = NULL;
-       this->nat_here = FALSE;
-       this->nat_there = FALSE;
        this->state = IKE_CREATED;
        this->time.inbound = this->time.outbound = time(NULL);
        this->time.established = 0;
@@ -1933,6 +2066,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
        this->my_virtual_ip = NULL;
        this->other_virtual_ip = NULL;
        this->dns_servers = linked_list_create();
+       this->additional_addresses = linked_list_create();
        this->keyingtry = 0;
        
        return &this->public;
index 3905a89..f4ca5ae 100644 (file)
@@ -26,6 +26,7 @@
 #define IKE_SA_H_
 
 typedef enum ike_extension_t ike_extension_t;
+typedef enum ike_condition_t ike_condition_t;
 typedef enum ike_sa_state_t ike_sa_state_t;
 typedef struct ike_sa_t ike_sa_t;
 
@@ -79,12 +80,38 @@ enum ike_extension_t {
        /**
         * peer supports NAT traversal as specified in RFC4306
         */
-       EXT_NATT,
+       EXT_NATT = (1<<0),
 
        /**
         * peer supports MOBIKE (RFC4555)
         */
-       EXT_MOBIKE,
+       EXT_MOBIKE = (1<<1),
+};
+
+/**
+ * @brief Conditions of an IKE_SA, change during its lifetime
+ */
+enum ike_condition_t {
+       
+       /**
+        * Connection is natted somewhere
+        */
+       COND_NAT_ANY = (1<<0),
+       
+       /**
+        * we are behind NAT
+        */
+       COND_NAT_HERE = (1<<1),
+       
+       /**
+        * other is behind NAT
+        */
+       COND_NAT_THERE = (1<<2),
+
+       /**
+        * peer is currently not reachable (due missing route, ...)
+        */
+       COND_STALE = (1<<3),
 };
 
 /**
@@ -336,13 +363,25 @@ struct ike_sa_t {
        void (*set_peer_cfg) (ike_sa_t *this, peer_cfg_t *config);
        
        /**
-        * @brief Check if the peer supports an extension.
+        * @brief Add an additional address for the peer.
+        *
+        * In MOBIKE, a peer may transmit additional addresses where it is
+        * reachable. These are stored in the IKE_SA.
+        * The own list of addresses is not stored, they are queried from
+        * the kernel when required.
         *
         * @param this                  calling object
-        * @param extension             extension to check for support
-        * @return                              TRUE if peer supports it, FALSE otherwise
+        * @param host                  host to add to list
         */
-       bool (*supports_extension)(ike_sa_t *this, ike_extension_t extension);
+       void (*add_additional_address)(ike_sa_t *this, host_t *host);
+       
+       /**
+        * @brief Create an iterator over all additional addresses of the peer.
+        *
+        * @param this                  calling object
+        * @return                              iterator over addresses
+        */
+       iterator_t* (*create_additional_address_iterator)(ike_sa_t *this);
        
        /**
         * @brief Enable an extension the peer supports.
@@ -356,6 +395,33 @@ struct ike_sa_t {
        void (*enable_extension)(ike_sa_t *this, ike_extension_t extension);
        
        /**
+        * @brief Check if the peer supports an extension.
+        *
+        * @param this                  calling object
+        * @param extension             extension to check for support
+        * @return                              TRUE if peer supports it, FALSE otherwise
+        */
+       bool (*supports_extension)(ike_sa_t *this, ike_extension_t extension);
+       
+       /**
+        * @brief Enable/disable a condition flag for this IKE_SA.
+        *
+        * @param this                  calling object
+        * @param condition             condition to enable/disable
+        * @param enable                TRUE to enable condition, FALSE to disable
+        */
+       void (*set_condition) (ike_sa_t *this, ike_condition_t condition, bool enable);
+
+       /**
+        * @brief Check if a condition flag is set.
+        *
+        * @param this                  calling object
+        * @param condition             condition to check
+        * @return                              TRUE if condition flag set, FALSE otherwise
+        */
+       bool (*has_condition) (ike_sa_t *this, ike_condition_t condition);
+       
+       /**
         * @brief Initiate a new connection.
         *
         * The configs are owned by the IKE_SA after the call.
@@ -425,6 +491,20 @@ struct ike_sa_t {
        status_t (*delete) (ike_sa_t *this);
        
        /**
+        * @brief Update IKE_SAs after network interfaces have changed.
+        *
+        * Whenever the network interface configuration changes, the kernel
+        * interface calls roam() on each IKE_SA. The IKE_SA then checks if
+        * the new network config requires changes, and handles appropriate.
+        * If MOBIKE is supported, addresses are updated; If not, the tunnel is
+        * restarted.
+        *
+        * @param 
+        * @return
+        */
+       status_t (*roam)(ike_sa_t *this);
+       
+       /**
         * @brief Processes a incoming IKEv2-Message.
         *
         * Message processing may fail. If a critical failure occurs, 
@@ -493,29 +573,6 @@ struct ike_sa_t {
         * @param this                  calling object
         */
        void (*send_keepalive) (ike_sa_t *this);
-       
-       /**
-        * @brief Check if NAT traversal is enabled for this IKE_SA.
-        *
-        * @param this                  calling object
-        * @return                              TRUE if NAT traversal enabled
-        */
-       bool (*is_natt_enabled) (ike_sa_t *this);
-
-       /**
-        * @brief Enable NAT detection for this IKE_SA.
-        *
-        * If a Network address translation is detected with
-        * NAT_DETECTION notifys, a SA must switch to ports
-        * 4500. To enable this behavior, call enable_natt().
-        * It is relevant which peer is NATted, this is specified
-        * with the "local" parameter. Call it twice when both
-        * are NATted.
-        *
-        * @param this                  calling object
-        * @param local                 TRUE, if we are NATted, FALSE if other
-        */
-       void (*enable_natt) (ike_sa_t *this, bool local);
 
        /**
         * @brief Derive all keys and create the transforms for IKE communication.
index 11c2592..84ce1fb 100644 (file)
@@ -27,6 +27,7 @@
 #include <daemon.h>
 #include <sa/tasks/ike_init.h>
 #include <sa/tasks/ike_natd.h>
+#include <sa/tasks/ike_mobike.h>
 #include <sa/tasks/ike_auth.h>
 #include <sa/tasks/ike_cert.h>
 #include <sa/tasks/ike_rekey.h>
@@ -130,6 +131,11 @@ struct private_task_manager_t {
         * List of tasks initiated by peer
         */
        linked_list_t *passive_tasks;
+       
+       /**
+        * the task manager has been reset 
+        */
+       bool reset;
 };
 
 /**
@@ -140,7 +146,7 @@ static void flush(private_task_manager_t *this)
        task_t *task;
        
        this->queued_tasks->destroy_offset(this->queued_tasks, 
-                                                                          offsetof(task_t, destroy));
+                                                                               offsetof(task_t, destroy));
        this->passive_tasks->destroy_offset(this->passive_tasks,
                                                                                offsetof(task_t, destroy));
        
@@ -274,6 +280,7 @@ static status_t build_request(private_task_manager_t *this)
                                        activate_task(this, IKE_AUTHENTICATE);
                                        activate_task(this, IKE_CONFIG);
                                        activate_task(this, CHILD_CREATE);
+                                       activate_task(this, IKE_MOBIKE);
                                }
                                break;
                        case IKE_ESTABLISHED:
@@ -307,7 +314,7 @@ static status_t build_request(private_task_manager_t *this)
                                        exchange = INFORMATIONAL;
                                        break;
                                }
-                               if (activate_task(this, IKE_DEADPEER))
+                               if (activate_task(this, IKE_DPD))
                                {
                                        exchange = INFORMATIONAL;
                                        break;
@@ -420,6 +427,8 @@ static status_t process_response(private_task_manager_t *this,
                return DESTROY_ME;
        }
 
+       /* catch if we get resetted while processing */
+       this->reset = FALSE;
        iterator = this->active_tasks->create_iterator(this->active_tasks, TRUE);
        while (iterator->iterate(iterator, (void*)&task))
        {
@@ -439,6 +448,12 @@ static status_t process_response(private_task_manager_t *this,
                    iterator->destroy(iterator);
                    return DESTROY_ME;
            }
+           if (this->reset)
+           {   /* start all over again if we were reset */
+               this->reset = FALSE;
+               iterator->destroy(iterator);
+                       return build_request(this);
+               }       
        }
        iterator->destroy(iterator);
        
@@ -597,6 +612,8 @@ static status_t process_request(private_task_manager_t *this,
                        this->passive_tasks->insert_last(this->passive_tasks, task);
                        task = (task_t*)child_create_create(this->ike_sa, NULL);
                        this->passive_tasks->insert_last(this->passive_tasks, task);
+                       task = (task_t*)ike_mobike_create(this->ike_sa, FALSE);
+                       this->passive_tasks->insert_last(this->passive_tasks, task);
                        break;
                }
                case CREATE_CHILD_SA:
@@ -812,7 +829,7 @@ static void reset(private_task_manager_t *this)
        this->responding.packet = NULL;
        this->initiating.packet = NULL;
        this->responding.mid = 0;
-       this->initiating.mid = -1;
+       this->initiating.mid = 0;
        this->initiating.type = EXCHANGE_TYPE_UNDEFINED;
        
        /* reset active tasks */
@@ -822,6 +839,8 @@ static void reset(private_task_manager_t *this)
                task->migrate(task, this->ike_sa);
                this->queued_tasks->insert_first(this->queued_tasks, task);
        }
+       
+       this->reset = TRUE;
 }
 
 /**
@@ -865,6 +884,7 @@ task_manager_t *task_manager_create(ike_sa_t *ike_sa)
        this->queued_tasks = linked_list_create();
        this->active_tasks = linked_list_create();
        this->passive_tasks = linked_list_create();
+       this->reset = FALSE;
 
        return &this->public;
 }
index f70730b..7bf2213 100644 (file)
@@ -297,7 +297,7 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh)
                                        this->mode = MODE_TUNNEL;
                                        DBG1(DBG_IKE, "not using tranport mode, not host-to-host");
                                }
-                               else if (this->ike_sa->is_natt_enabled(this->ike_sa))
+                               else if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY))
                                {
                                        this->mode = MODE_TUNNEL;
                                        DBG1(DBG_IKE, "not using tranport mode, connection NATed");
@@ -545,11 +545,10 @@ static status_t build_i(private_child_create_t *this, message_t *message)
                                                                                                  this->dh_group == MODP_NONE);
        this->mode = this->config->get_mode(this->config);
        
-       this->child_sa = child_sa_create(me, other,
-                                                                        this->ike_sa->get_my_id(this->ike_sa),
-                                                                        this->ike_sa->get_other_id(this->ike_sa),
-                                                                        this->config, this->reqid,
-                                                                        this->ike_sa->is_natt_enabled(this->ike_sa));
+       this->child_sa = child_sa_create(
+                       me, other, this->ike_sa->get_my_id(this->ike_sa), 
+                       this->ike_sa->get_other_id(this->ike_sa), this->config, this->reqid,
+                       this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY));
        
        if (this->child_sa->alloc(this->child_sa, this->proposals) != SUCCESS)
        {
@@ -660,12 +659,12 @@ static status_t build_r(private_child_create_t *this, message_t *message)
                return SUCCESS;
        }
        
-       this->child_sa = child_sa_create(this->ike_sa->get_my_host(this->ike_sa),
-                                                                        this->ike_sa->get_other_host(this->ike_sa),
-                                                                        this->ike_sa->get_my_id(this->ike_sa),
-                                                                        this->ike_sa->get_other_id(this->ike_sa),
-                                                                        this->config, this->reqid,
-                                                                        this->ike_sa->is_natt_enabled(this->ike_sa));
+       this->child_sa = child_sa_create(
+                       this->ike_sa->get_my_host(this->ike_sa),
+                       this->ike_sa->get_other_host(this->ike_sa),
+                       this->ike_sa->get_my_id(this->ike_sa),
+                       this->ike_sa->get_other_id(this->ike_sa), this->config, this->reqid,
+                       this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY));
        
        switch (select_and_install(this, no_dh))
        {
index d0dd49a..c1c0cd5 100644 (file)
@@ -636,7 +636,12 @@ static status_t process_i(private_ike_auth_t *this, message_t *message)
                                case INVALID_SELECTORS:
                                        /* these are errors, but are not critical as only the
                                         * CHILD_SA won't get build, but IKE_SA establishes anyway */
-                                        break;
+                                       break;
+                               case MOBIKE_SUPPORTED:
+                               case ADDITIONAL_IP4_ADDRESS:
+                               case ADDITIONAL_IP6_ADDRESS:
+                                       /* handled in ike_mobike task */
+                                       break;
                                default:
                                {
                                        if (type < 16383)
index 1cb05c4..be75176 100644 (file)
@@ -61,7 +61,7 @@ static status_t return_success(private_ike_dpd_t *this, message_t *message)
  */
 static task_type_t get_type(private_ike_dpd_t *this)
 {
-       return IKE_DEADPEER;
+       return IKE_DPD;
 }
 
 /**
diff --git a/src/charon/sa/tasks/ike_mobike.c b/src/charon/sa/tasks/ike_mobike.c
new file mode 100644 (file)
index 0000000..0b3bd07
--- /dev/null
@@ -0,0 +1,307 @@
+/**
+ * @file ike_mobike.c
+ *
+ * @brief Implementation of the ike_mobike task.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include "ike_mobike.h"
+
+#include <string.h>
+
+#include <daemon.h>
+#include <encoding/payloads/notify_payload.h>
+
+
+typedef struct private_ike_mobike_t private_ike_mobike_t;
+
+/**
+ * Private members of a ike_mobike_t task.
+ */
+struct private_ike_mobike_t {
+       
+       /**
+        * Public methods and task_t interface.
+        */
+       ike_mobike_t public;
+       
+       /**
+        * Assigned IKE_SA.
+        */
+       ike_sa_t *ike_sa;
+       
+       /**
+        * Are we the initiator?
+        */
+       bool initiator;
+       
+       /**
+        * local host to roam to
+        */
+       host_t *me;
+       
+       /**
+        * remote host to roam to
+        */
+       host_t *other;
+};
+
+/**
+ * flush the IKE_SAs list of additional addresses
+ */
+static void flush_additional_addresses(private_ike_mobike_t *this)
+{
+       iterator_t *iterator;
+       host_t *host;
+       
+       iterator = this->ike_sa->create_additional_address_iterator(this->ike_sa);
+       while (iterator->iterate(iterator, (void**)&host))
+       {
+               iterator->remove(iterator);
+               host->destroy(host);
+       }
+       iterator->destroy(iterator);
+}
+
+
+/**
+ * read notifys from message and evaluate them
+ */
+static void process_payloads(private_ike_mobike_t *this, message_t *message)
+{
+       iterator_t *iterator;
+       payload_t *payload;
+       bool first = TRUE;
+       
+       iterator = message->get_payload_iterator(message);
+       while (iterator->iterate(iterator, (void**)&payload))
+       {
+               int family = AF_INET;
+               notify_payload_t *notify;
+               chunk_t data;
+               host_t *host;
+               
+               if (payload->get_type(payload) != NOTIFY)
+               {
+                       continue;
+               }
+               notify = (notify_payload_t*)payload;
+               switch (notify->get_notify_type(notify))
+               {
+                       case MOBIKE_SUPPORTED:
+                       {
+                               DBG2(DBG_IKE, "peer supports MOBIKE");
+                               this->ike_sa->enable_extension(this->ike_sa, EXT_MOBIKE);
+                               break;
+                       }
+                       case ADDITIONAL_IP6_ADDRESS:
+                       {
+                               family = AF_INET6;
+                               /* fall through */
+                       }
+                       case ADDITIONAL_IP4_ADDRESS:
+                       {
+                               if (first)
+                               {       /* an ADDITIONAL_*_ADDRESS means replace, so flush once */
+                                       flush_additional_addresses(this);
+                               }
+                               data = notify->get_notification_data(notify);
+                               host = host_create_from_chunk(family, data, 0);
+                               DBG2(DBG_IKE, "got additional MOBIKE peer address: %H", host);
+                               this->ike_sa->add_additional_address(this->ike_sa, host);
+                               break;
+                       }
+                       case NO_ADDITIONAL_ADDRESSES:
+                       {
+                               flush_additional_addresses(this);
+                               break;
+                       }
+                       default:
+                               break;
+               }
+       }
+       iterator->destroy(iterator);
+}
+
+/**
+ * Add ADDITIONAL_*_ADDRESS notifys depending on our address list
+ */
+static void build_address_list(private_ike_mobike_t *this, message_t *message)
+{
+       iterator_t *iterator;
+       host_t *host, *me;
+       notify_type_t type;
+       bool additional = FALSE;
+
+       me = this->ike_sa->get_my_host(this->ike_sa);
+       iterator = charon->kernel_interface->create_address_iterator(
+                                                                                               charon->kernel_interface);
+       while (iterator->iterate(iterator, (void**)&host))
+       {
+               if (me->ip_equals(me, host))
+               {       /* "ADDITIONAL" means do not include IKE_SAs host */
+                       continue;
+               }
+               switch (host->get_family(host))
+               {
+                       case AF_INET:
+                               type = ADDITIONAL_IP4_ADDRESS;
+                               break;
+                       case AF_INET6:
+                               type = ADDITIONAL_IP6_ADDRESS;
+                               break;
+                       default:
+                               continue;
+               }
+               message->add_notify(message, FALSE, type, host->get_address(host));
+               additional = TRUE;
+       }
+       if (!additional)
+       {
+               message->add_notify(message, FALSE, NO_ADDITIONAL_ADDRESSES, chunk_empty);
+       }
+       iterator->destroy(iterator);
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+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);
+       }
+       
+       return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.process for responder
+ */
+static status_t process_r(private_ike_mobike_t *this, message_t *message)
+{      
+       process_payloads(this, message);
+       
+       return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.build for responder
+ */
+static status_t build_r(private_ike_mobike_t *this, message_t *message)
+{
+       if (message->get_exchange_type(message) == IKE_AUTH &&
+               message->get_payload(message, SECURITY_ASSOCIATION))
+       {
+               if (this->ike_sa->supports_extension(this->ike_sa, EXT_MOBIKE))
+               {
+                       message->add_notify(message, FALSE, MOBIKE_SUPPORTED, chunk_empty);
+                       build_address_list(this, message);
+               }
+               return SUCCESS;
+       }
+       return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t process_i(private_ike_mobike_t *this, message_t *message)
+{
+       if (message->get_exchange_type(message) == IKE_AUTH &&
+               message->get_payload(message, SECURITY_ASSOCIATION))
+       {
+               process_payloads(this, message);
+               return SUCCESS;
+       }
+       return NEED_MORE;
+}
+
+/**
+ * Implementation of ike_mobike_t.roam.
+ */
+static void roam(private_ike_mobike_t *this, host_t *me, host_t *other)
+{
+       this->me = me;
+       this->other = other;
+}
+
+/**
+ * Implementation of task_t.get_type
+ */
+static task_type_t get_type(private_ike_mobike_t *this)
+{
+       return IKE_MOBIKE;
+}
+
+/**
+ * Implementation of task_t.migrate
+ */
+static void migrate(private_ike_mobike_t *this, ike_sa_t *ike_sa)
+{
+       DESTROY_IF(this->me);
+       DESTROY_IF(this->other);
+       this->ike_sa = ike_sa;
+       this->me = NULL;
+       this->other = NULL;
+}
+
+/**
+ * Implementation of task_t.destroy
+ */
+static void destroy(private_ike_mobike_t *this)
+{
+       DESTROY_IF(this->me);
+       DESTROY_IF(this->other);
+       free(this);
+}
+
+/*
+ * Described in header.
+ */
+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*, host_t *, host_t *))roam;
+       this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
+       this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
+       this->public.task.destroy = (void(*)(task_t*))destroy;
+       
+       if (initiator)
+       {
+               this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
+               this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
+       }
+       else
+       {
+               this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
+               this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
+       }
+       
+       this->ike_sa = ike_sa;
+       this->initiator = initiator;
+       this->me = NULL;
+       this->other = NULL;
+       
+       return &this->public;
+}
+
diff --git a/src/charon/sa/tasks/ike_mobike.h b/src/charon/sa/tasks/ike_mobike.h
new file mode 100644 (file)
index 0000000..f815e49
--- /dev/null
@@ -0,0 +1,76 @@
+/**
+ * @file ike_mobike.h
+ * 
+ * @brief Interface ike_mobike_t.
+ * 
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef IKE_MOBIKE_H_
+#define IKE_MOBIKE_H_
+
+typedef struct ike_mobike_t ike_mobike_t;
+
+#include <library.h>
+#include <sa/ike_sa.h>
+#include <sa/tasks/task.h>
+
+/**
+ * @brief Task of type ike_mobike, detects and handles MOBIKE extension.
+ *
+ * The MOBIKE extension is defined in RFC4555. It allows to update IKE
+ * and IPsec tunnel addresses.
+ * This tasks handles the MOBIKE_SUPPORTED notify exchange to detect MOBIKE
+ * support, allows the exchange of ADDITIONAL_*_ADDRESS to exchange additional
+ * endpoints and handles the UPDATE_SA_ADDRESS notify to finally update 
+ * endpoints.
+ *
+ * @b Constructors:
+ *  - ike_mobike_create()
+ * 
+ * @ingroup tasks
+ */
+struct ike_mobike_t {
+
+       /**
+        * Implements the task_t interface
+        */
+       task_t task;
+       
+       /**
+        * @brief Use the task to roam to other addresses.
+        *
+        * Supplied hosts may be NULL to reuse existing IKE_SA hosts.
+        *
+        * @param this                  calling object
+        * @param me                    local host to roam to, or NULL
+        * @param other                 remote host to roam to, or NULL
+        */
+       void (*roam)(ike_mobike_t *this, host_t *me, host_t *other);
+};
+
+/**
+ * @brief Create a new ike_mobike task.
+ *
+ * @param ike_sa               IKE_SA this task works for
+ * @param initiator            TRUE if taks is initiated by us
+ * @return                             ike_mobike task to handle by the task_manager
+ */
+ike_mobike_t *ike_mobike_create(ike_sa_t *ike_sa, bool initiator);
+
+#endif /* IKE_MOBIKE_H_ */
+
index 15c516c..db8a400 100644 (file)
@@ -207,11 +207,11 @@ static void process_payloads(private_ike_natd_t *this, message_t *message)
        
                if (!this->dst_matched)
                {
-                       this->ike_sa->enable_natt(this->ike_sa, TRUE);
+                       this->ike_sa->set_condition(this->ike_sa, COND_NAT_HERE, TRUE);
                }
                if (!this->src_matched)
                {
-                       this->ike_sa->enable_natt(this->ike_sa, FALSE);
+                       this->ike_sa->set_condition(this->ike_sa, COND_NAT_THERE, TRUE);
                }
        }
 }
@@ -223,7 +223,7 @@ static status_t process_i(private_ike_natd_t *this, message_t *message)
 {
        process_payloads(this, message);
 
-       if (this->ike_sa->is_natt_enabled(this->ike_sa))
+       if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY))
        {
                host_t *me, *other;
        
index 93be23d..0e98382 100644 (file)
@@ -84,6 +84,8 @@ static status_t process_i(private_ike_reauth_t *this, message_t *message)
        new->set_peer_cfg(new, this->ike_sa->get_peer_cfg(this->ike_sa));
        host = this->ike_sa->get_other_host(this->ike_sa);
        new->set_other_host(new, host->clone(host));
+       host = this->ike_sa->get_my_host(this->ike_sa);
+       new->set_my_host(new, host->clone(host));
        /* if we already have a virtual IP, we reuse it */
        host = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE);
        if (host)
index 68d8ebf..713403d 100644 (file)
 ENUM(task_type_names, IKE_INIT, CHILD_REKEY,
        "IKE_INIT",
        "IKE_NATD",
+       "IKE_MOBIKE",
        "IKE_AUTHENTICATE",
        "IKE_CERT",
        "IKE_CONFIG",
-       "IKE_DPD",
        "IKE_REKEY",
+       "IKE_REAUTH",
        "IKE_DELETE",
-       "IKE_DEADPEER",
+       "IKE_DPD",
        "CHILD_CREATE",
        "CHILD_DELETE",
        "CHILD_REKEY",
 );
+
index 2b45d26..ff60ea8 100644 (file)
@@ -40,14 +40,14 @@ enum task_type_t {
        IKE_INIT,
        /** detect NAT situation */
        IKE_NATD,
+       /** handle MOBIKE stuff */
+       IKE_MOBIKE,
        /** authenticate the initiated IKE_SA */
        IKE_AUTHENTICATE,
        /** exchange certificates and requests */
        IKE_CERT,
        /** Configuration payloads, virtual IP and such */
        IKE_CONFIG,
-       /** DPD detection */
-       IKE_DEADPEER,
        /** rekey an IKE_SA */
        IKE_REKEY,
        /** reestablish a complete IKE_SA */