Get source address from interface if the route does not provide one.
authorTobias Brunner <tobias@strongswan.org>
Tue, 5 Oct 2010 07:36:31 +0000 (09:36 +0200)
committerTobias Brunner <tobias@strongswan.org>
Tue, 12 Oct 2010 09:11:04 +0000 (11:11 +0200)
src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c

index 90e9789..4956ddb 100644 (file)
@@ -735,6 +735,42 @@ static int get_interface_index(private_kernel_netlink_net_t *this, char* name)
 }
 
 /**
+ * get the first non-virtual ip address on the given interface.
+ * returned host is a clone, has to be freed by caller.
+ */
+static host_t *get_interface_address(private_kernel_netlink_net_t *this,
+                                                                        int ifindex, int family)
+{
+       enumerator_t *ifaces, *addrs;
+       iface_entry_t *iface;
+       addr_entry_t *addr;
+       host_t *ip = NULL;
+
+       this->mutex->lock(this->mutex);
+       ifaces = this->ifaces->create_enumerator(this->ifaces);
+       while (ifaces->enumerate(ifaces, &iface))
+       {
+               if (iface->ifindex == ifindex)
+               {
+                       addrs = iface->addrs->create_enumerator(iface->addrs);
+                       while (addrs->enumerate(addrs, &addr))
+                       {
+                               if (!addr->virtual && addr->ip->get_family(addr->ip) == family)
+                               {
+                                       ip = addr->ip->clone(addr->ip);
+                                       break;
+                               }
+                       }
+                       addrs->destroy(addrs);
+                       break;
+               }
+       }
+       ifaces->destroy(ifaces);
+       this->mutex->unlock(this->mutex);
+       return ip;
+}
+
+/**
  * Check if an interface with a given index is up
  */
 static bool is_interface_up(private_kernel_netlink_net_t *this, int index)
@@ -925,8 +961,7 @@ static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest,
                                        continue;
                                }
                                if (rta_src.ptr)
-                               {
-                                       /* got a source address */
+                               {       /* got a source address */
                                        new_src = host_create_from_chunk(msg->rtm_family, rta_src, 0);
                                        if (new_src)
                                        {
@@ -943,6 +978,18 @@ static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest,
                                        }
                                        continue;
                                }
+                               if (rta_oif)
+                               {       /* no source, but an interface. Get address from it. */
+                                       new_src = get_interface_address(this, rta_oif,
+                                                                                                       msg->rtm_family);
+                                       if (new_src)
+                                       {
+                                               DESTROY_IF(src);
+                                               src = new_src;
+                                               best = msg->rtm_dst_len;
+                                       }
+                                       continue;
+                               }
                                if (rta_gtw.ptr)
                                {       /* no source, but a gateway. Lookup source to reach gtw. */
                                        new_gtw = host_create_from_chunk(msg->rtm_family, rta_gtw, 0);