mobike: try to keep existing source address before switching to another
authorMartin Willi <martin@strongswan.org>
Wed, 8 Oct 2008 08:23:46 +0000 (08:23 -0000)
committerMartin Willi <martin@strongswan.org>
Wed, 8 Oct 2008 08:23:46 +0000 (08:23 -0000)
src/charon/kernel/kernel_interface.c
src/charon/kernel/kernel_interface.h
src/charon/kernel/kernel_net.h
src/charon/plugins/kernel_netlink/kernel_netlink_net.c
src/charon/sa/ike_sa.c
src/charon/sa/tasks/ike_mobike.c
src/charon/sa/tasks/ike_natd.c

index 4e56a07..7a0ffa1 100644 (file)
@@ -160,9 +160,10 @@ static status_t del_policy(private_kernel_interface_t *this,
 /**
  * Implementation of kernel_interface_t.get_source_addr
  */
-static host_t *get_source_addr(private_kernel_interface_t *this, host_t *dest)
+static host_t *get_source_addr(private_kernel_interface_t *this,
+                                                          host_t *dest, host_t *src)
 {
-       return this->net->get_source_addr(this->net, dest);
+       return this->net->get_source_addr(this->net, dest, src);
 }
 
 /**
@@ -329,7 +330,7 @@ kernel_interface_t *kernel_interface_create()
        this->public.query_policy = (status_t(*)(kernel_interface_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t,u_int32_t*))query_policy;
        this->public.del_policy = (status_t(*)(kernel_interface_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t))del_policy;
        
-       this->public.get_source_addr = (host_t*(*)(kernel_interface_t*, host_t *dest))get_source_addr;
+       this->public.get_source_addr = (host_t*(*)(kernel_interface_t*, host_t *dest, host_t *src))get_source_addr;
        this->public.get_nexthop = (host_t*(*)(kernel_interface_t*, host_t *dest))get_nexthop;
        this->public.get_interface = (char*(*)(kernel_interface_t*,host_t*))get_interface;
        this->public.create_address_enumerator = (enumerator_t*(*)(kernel_interface_t*,bool,bool))create_address_enumerator;
index 49faf7c..c87e825 100644 (file)
@@ -235,11 +235,15 @@ struct kernel_interface_t {
         *
         * Does a route lookup to get the source address used to reach dest.
         * The returned host is allocated and must be destroyed.
+        * An optional src address can be used to check if a route is available
+        * for given source to dest.
         *
         * @param dest                  target destination address
+        * @param src                   source address to check, or NULL
         * @return                              outgoing source address, NULL if unreachable
         */
-       host_t* (*get_source_addr)(kernel_interface_t *this, host_t *dest);
+       host_t* (*get_source_addr)(kernel_interface_t *this,
+                                                          host_t *dest, host_t *src);
        
        /**
         * Get the next hop for a destination.
index 998fef0..525a9de 100644 (file)
@@ -42,11 +42,14 @@ struct kernel_net_t {
         *
         * Does a route lookup to get the source address used to reach dest.
         * The returned host is allocated and must be destroyed.
+        * An optional src address can be used to check if a route is available
+        * for given source to dest.
         *
         * @param dest                  target destination address
+        * @param src                   source address to check, or NULL
         * @return                              outgoing source address, NULL if unreachable
         */
-       host_t* (*get_source_addr)(kernel_net_t *this, host_t *dest);
+       host_t* (*get_source_addr)(kernel_net_t *this, host_t *dest, host_t *src);
        
        /**
         * Get the next hop for a destination.
index ea59541..bef1362 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2008 Tobias Brunner
+ * Copyright (C) 2005-2008 Martin Willi
  * Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -720,7 +721,7 @@ static bool addr_in_subnet(chunk_t addr, chunk_t net, int net_len)
  * Get a route: If "nexthop", the nexthop is returned. source addr otherwise.
  */
 static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest,
-                                                bool nexthop)
+                                                bool nexthop, host_t *candidate)
 {
        unsigned char request[NETLINK_BUFFER_SIZE];
        struct nlmsghdr *hdr, *out, *current;
@@ -744,7 +745,12 @@ static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest,
        
        chunk = dest->get_address(dest);
        netlink_add_attribute(hdr, RTA_DST, chunk, sizeof(request));
-                       
+       if (candidate)
+       {
+               chunk = candidate->get_address(candidate);
+               netlink_add_attribute(hdr, RTA_PREFSRC, chunk, sizeof(request));
+       }
+       
        if (this->socket->send(this->socket, hdr, &out, &len) != SUCCESS)
        {
                DBG1(DBG_KNL, "getting address to %H failed", dest);
@@ -878,9 +884,10 @@ static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest,
 /**
  * Implementation of kernel_net_t.get_source_addr.
  */
-static host_t* get_source_addr(private_kernel_netlink_net_t *this, host_t *dest)
+static host_t* get_source_addr(private_kernel_netlink_net_t *this,
+                                                          host_t *dest, host_t *src)
 {
-       return get_route(this, dest, FALSE);
+       return get_route(this, dest, FALSE, src);
 }
 
 /**
@@ -888,7 +895,7 @@ static host_t* get_source_addr(private_kernel_netlink_net_t *this, host_t *dest)
  */
 static host_t* get_nexthop(private_kernel_netlink_net_t *this, host_t *dest)
 {
-       return get_route(this, dest, TRUE);
+       return get_route(this, dest, TRUE, NULL);
 }
 
 /**
@@ -1284,7 +1291,7 @@ kernel_netlink_net_t *kernel_netlink_net_create()
        /* public functions */
        this->public.interface.get_interface = (char*(*)(kernel_net_t*,host_t*))get_interface_name;
        this->public.interface.create_address_enumerator = (enumerator_t*(*)(kernel_net_t*,bool,bool))create_address_enumerator;
-       this->public.interface.get_source_addr = (host_t*(*)(kernel_net_t*, host_t *dest))get_source_addr;
+       this->public.interface.get_source_addr = (host_t*(*)(kernel_net_t*, host_t *dest, host_t *src))get_source_addr;
        this->public.interface.get_nexthop = (host_t*(*)(kernel_net_t*, host_t *dest))get_nexthop;
        this->public.interface.add_ip = (status_t(*)(kernel_net_t*,host_t*,host_t*)) add_ip;
        this->public.interface.del_ip = (status_t(*)(kernel_net_t*,host_t*)) del_ip;
index 575ae4d..12f4ebe 100644 (file)
@@ -1098,7 +1098,7 @@ static void resolve_hosts(private_ike_sa_t *this)
        {
                host->destroy(host);
                host = charon->kernel_interface->get_source_addr(
-                                                               charon->kernel_interface, this->other_host);
+                                                       charon->kernel_interface, this->other_host, NULL);
                if (host)
                {
                        host->set_port(host, IKEV2_UDP_PORT);
@@ -2206,7 +2206,7 @@ static void set_auth_lifetime(private_ike_sa_t *this, u_int32_t lifetime)
  */
 static status_t roam(private_ike_sa_t *this, bool address)
 {
-       host_t *me, *other;
+       host_t *src;
        ike_mobike_t *mobike;
        
        switch (this->state)
@@ -2230,21 +2230,21 @@ static status_t roam(private_ike_sa_t *this, bool address)
                return SUCCESS;
        }
        
-       /* get best address pair to use */
-       other = this->other_host;
-       me = charon->kernel_interface->get_source_addr(charon->kernel_interface,
-                                                                                                  other);
-       
-       if (me)
+       /* keep existing path if possible */
+       src = charon->kernel_interface->get_source_addr(charon->kernel_interface,
+                                                                                       this->other_host, this->my_host);
+       if (src)
        {
-               if (me->ip_equals(me, this->my_host) &&
-                       other->ip_equals(other, this->other_host))
+               if (src->ip_equals(src, this->my_host))
                {
-                       DBG2(DBG_IKE, "keeping connection path %H - %H", this->other_host, me);
-                       me->destroy(me);
+                       DBG2(DBG_IKE, "keeping connection path %H - %H",
+                                src, this->other_host);
+                       src->destroy(src);
                        return SUCCESS;
                }
-               me->destroy(me);
+               /* old address is not valid anymore, try with new one */
+               src->set_port(src, this->my_host->get_port(this->my_host));
+               set_my_host(this, src);
        }
        
        /* update addresses with mobike, if supported ... */
index 450149f..a5fe74a 100644 (file)
@@ -277,7 +277,7 @@ static void transmit(private_ike_mobike_t *this, packet_t *packet)
        other_old = this->ike_sa->get_other_host(this->ike_sa);
        
        me = charon->kernel_interface->get_source_addr(
-                                                                               charon->kernel_interface, other_old);
+                                                                       charon->kernel_interface, other_old, NULL);
        if (me)
        {
                me->set_port(me, me->ip_equals(me, me_old) ?
@@ -289,7 +289,7 @@ static void transmit(private_ike_mobike_t *this, packet_t *packet)
        while (iterator->iterate(iterator, (void**)&other))
        {
                me = charon->kernel_interface->get_source_addr(
-                                                                                       charon->kernel_interface, other);
+                                                                               charon->kernel_interface, other, NULL);
                if (me)
                {
                        if (me->get_family(me) != other->get_family(other))
index de0cfce..b35ddf4 100644 (file)
@@ -341,9 +341,8 @@ static status_t build_i(private_ike_natd_t *this, message_t *message)
        }
        else
        {
-               host = charon->kernel_interface->get_source_addr(
-                                                                       charon->kernel_interface,
-                                                                       this->ike_sa->get_other_host(this->ike_sa));
+               host = charon->kernel_interface->get_source_addr(charon->kernel_interface,
+                                                       this->ike_sa->get_other_host(this->ike_sa), NULL);
                if (host)
                {       /* 2. */
                        host->set_port(host, IKEV2_UDP_PORT);