kernel-netlink: Respect kernel routing priorities for IKE routes
authorMartin Willi <martin@revosec.ch>
Thu, 15 Jan 2015 14:05:42 +0000 (15:05 +0100)
committerMartin Willi <martin@revosec.ch>
Tue, 3 Mar 2015 12:42:41 +0000 (13:42 +0100)
If a system uses routing metrics, we should honor them when doing (manual)
routing lookups for IKE. When enumerating routes, the kernel reports priorities
with the RTA_PRIORITY attribute, not RTA_METRICS. We prefer routes with a
lower priority value, and fall back to longest prefix match priorities if
the priority value is equal.

src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c

index b8cd397..a431e49 100644 (file)
@@ -1538,6 +1538,7 @@ typedef struct {
        u_int8_t dst_len;
        u_int32_t table;
        u_int32_t oif;
+       u_int32_t priority;
 } rt_entry_t;
 
 /**
@@ -1573,6 +1574,7 @@ static rt_entry_t *parse_route(struct nlmsghdr *hdr, rt_entry_t *route)
                route->dst_len = msg->rtm_dst_len;
                route->table = msg->rtm_table;
                route->oif = 0;
+               route->priority = 0;
        }
        else
        {
@@ -1601,6 +1603,12 @@ static rt_entry_t *parse_route(struct nlmsghdr *hdr, rt_entry_t *route)
                                        route->oif = *(u_int32_t*)RTA_DATA(rta);
                                }
                                break;
+                       case RTA_PRIORITY:
+                               if (RTA_PAYLOAD(rta) == sizeof(route->priority))
+                               {
+                                       route->priority = *(u_int32_t*)RTA_DATA(rta);
+                               }
+                               break;
 #ifdef HAVE_RTA_TABLE
                        case RTA_TABLE:
                                if (RTA_PAYLOAD(rta) == sizeof(route->table))
@@ -1724,11 +1732,16 @@ static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest,
                                        }
                                        route->src_host = src;
                                }
-                               /* insert route, sorted by decreasing network prefix */
+                               /* insert route, sorted by priority and network prefix */
                                enumerator = routes->create_enumerator(routes);
                                while (enumerator->enumerate(enumerator, &other))
                                {
-                                       if (route->dst_len > other->dst_len)
+                                       if (route->priority < other->priority)
+                                       {
+                                               break;
+                                       }
+                                       if (route->priority == other->priority &&
+                                               route->dst_len > other->dst_len)
                                        {
                                                break;
                                        }