Added support for IPv6 source route installation
authorMartin Willi <martin@strongswan.org>
Tue, 24 Nov 2009 13:10:18 +0000 (14:10 +0100)
committerMartin Willi <martin@strongswan.org>
Thu, 26 Nov 2009 09:31:00 +0000 (10:31 +0100)
src/charon/plugins/kernel_netlink/kernel_netlink_ipsec.c
src/charon/plugins/kernel_netlink/kernel_netlink_net.c

index 51a9ea3..12e20eb 100644 (file)
@@ -260,7 +260,7 @@ static void route_entry_destroy(route_entry_t *this)
 {
        free(this->if_name);
        this->src_ip->destroy(this->src_ip);
-       this->gateway->destroy(this->gateway);
+       DESTROY_IF(this->gateway);
        chunk_free(&this->dst_net);
        free(this);
 }
@@ -1661,24 +1661,34 @@ static status_t add_policy(private_kernel_netlink_ipsec_t *this,
         * - we are NOT updating a policy
         * - this is a forward policy (to just get one for each child)
         * - we are in tunnel mode
-        * - we are not using IPv6 (does not work correctly yet!)
         * - routing is not disabled via strongswan.conf
         */
        if (policy->route == NULL && direction == POLICY_FWD &&
-               mode != MODE_TRANSPORT && src->get_family(src) != AF_INET6 &&
-               this->install_routes)
+               mode != MODE_TRANSPORT && this->install_routes)
        {
                route_entry_t *route = malloc_thing(route_entry_t);
 
                if (charon->kernel_interface->get_address_by_ts(charon->kernel_interface,
                                dst_ts, &route->src_ip) == SUCCESS)
                {
-                       /* get the nexthop to src (src as we are in POLICY_FWD).*/
-                       route->gateway = charon->kernel_interface->get_nexthop(
+                       if (policy->sel.family == AF_INET)
+                       {
+                               /* get the nexthop to src (src as we are in POLICY_FWD).*/
+                               route->gateway = charon->kernel_interface->get_nexthop(
                                                                        charon->kernel_interface, src);
-                       route->if_name = charon->kernel_interface->get_interface(
-                                                                       charon->kernel_interface, dst);
-                       route->dst_net = chunk_alloc(policy->sel.family == AF_INET ? 4 : 16);
+                               /* for IPv4, the route is installed on the outgoing interface */
+                               route->if_name = charon->kernel_interface->get_interface(
+                                                                                               charon->kernel_interface, dst);
+                               route->dst_net = chunk_alloc(4);
+                       }
+                       else
+                       {
+                               route->gateway = NULL;
+                               /* for IPv6, it is on the interface with our source address */
+                               route->if_name = charon->kernel_interface->get_interface(
+                                                                               charon->kernel_interface, route->src_ip);
+                               route->dst_net = chunk_alloc(16);
+                       }
                        memcpy(route->dst_net.ptr, &policy->sel.saddr, route->dst_net.len);
                        route->prefixlen = policy->sel.prefixlen_s;
 
index ab2ca7d..609a5c3 100644 (file)
@@ -769,7 +769,14 @@ static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest,
        memset(&request, 0, sizeof(request));
 
        hdr = (struct nlmsghdr*)request;
-       hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP | NLM_F_ROOT;
+       hdr->nlmsg_flags = NLM_F_REQUEST;
+       if (dest->get_family(dest) == AF_INET)
+       {
+               /* We dump all addresses for IPv4, as we want to ignore IPsec specific
+                * routes installed by us. But the kernel does not return source
+                * addresses in a IPv6 dump, so fall back to get() for v6 routes. */
+               hdr->nlmsg_flags |= NLM_F_ROOT | NLM_F_DUMP;
+       }
        hdr->nlmsg_type = RTM_GETROUTE;
        hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
 
@@ -1157,8 +1164,11 @@ static status_t manage_srcroute(private_kernel_netlink_net_t *this, int nlmsg_ty
        netlink_add_attribute(hdr, RTA_DST, dst_net, sizeof(request));
        chunk = src_ip->get_address(src_ip);
        netlink_add_attribute(hdr, RTA_PREFSRC, chunk, sizeof(request));
-       chunk = gateway->get_address(gateway);
-       netlink_add_attribute(hdr, RTA_GATEWAY, chunk, sizeof(request));
+       if (gateway && gateway->get_family(gateway) == src_ip->get_family(src_ip))
+       {
+               chunk = gateway->get_address(gateway);
+               netlink_add_attribute(hdr, RTA_GATEWAY, chunk, sizeof(request));
+       }
        ifindex = get_interface_index(this, if_name);
        chunk.ptr = (char*)&ifindex;
        chunk.len = sizeof(ifindex);
@@ -1282,7 +1292,7 @@ static status_t init_address_list(private_kernel_netlink_net_t *this)
  * create or delete a rule to use our routing table
  */
 static status_t manage_rule(private_kernel_netlink_net_t *this, int nlmsg_type,
-                                                       u_int32_t table, u_int32_t prio)
+                                                       int family, u_int32_t table, u_int32_t prio)
 {
        netlink_buf_t request;
        struct nlmsghdr *hdr;
@@ -1301,7 +1311,7 @@ static status_t manage_rule(private_kernel_netlink_net_t *this, int nlmsg_type,
 
        msg = (struct rtmsg*)NLMSG_DATA(hdr);
        msg->rtm_table = table;
-       msg->rtm_family = AF_INET;
+       msg->rtm_family = family;
        msg->rtm_protocol = RTPROT_BOOT;
        msg->rtm_scope = RT_SCOPE_UNIVERSE;
        msg->rtm_type = RTN_UNICAST;
@@ -1319,7 +1329,9 @@ static void destroy(private_kernel_netlink_net_t *this)
 {
        if (this->routing_table)
        {
-               manage_rule(this, RTM_DELRULE, this->routing_table,
+               manage_rule(this, RTM_DELRULE, AF_INET, this->routing_table,
+                                       this->routing_table_prio);
+               manage_rule(this, RTM_DELRULE, AF_INET6, this->routing_table,
                                        this->routing_table_prio);
        }
 
@@ -1394,10 +1406,15 @@ kernel_netlink_net_t *kernel_netlink_net_create()
 
        if (this->routing_table)
        {
-               if (manage_rule(this, RTM_NEWRULE, this->routing_table,
+               if (manage_rule(this, RTM_NEWRULE, AF_INET, this->routing_table,
+                                               this->routing_table_prio) != SUCCESS)
+               {
+                       DBG1(DBG_KNL, "unable to create IPv4 routing table rule");
+               }
+               if (manage_rule(this, RTM_NEWRULE, AF_INET6, this->routing_table,
                                                this->routing_table_prio) != SUCCESS)
                {
-                       DBG1(DBG_KNL, "unable to create routing table rule");
+                       DBG1(DBG_KNL, "unable to create IPv6 routing table rule");
                }
        }