diff options
Diffstat (limited to 'src/charon/plugins/kernel_netlink')
-rw-r--r-- | src/charon/plugins/kernel_netlink/kernel_netlink_ipsec.c | 28 | ||||
-rw-r--r-- | src/charon/plugins/kernel_netlink/kernel_netlink_net.c | 33 |
2 files changed, 44 insertions, 17 deletions
diff --git a/src/charon/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/charon/plugins/kernel_netlink/kernel_netlink_ipsec.c index 51a9ea31d..12e20ebec 100644 --- a/src/charon/plugins/kernel_netlink/kernel_netlink_ipsec.c +++ b/src/charon/plugins/kernel_netlink/kernel_netlink_ipsec.c @@ -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; diff --git a/src/charon/plugins/kernel_netlink/kernel_netlink_net.c b/src/charon/plugins/kernel_netlink/kernel_netlink_net.c index ab2ca7d13..609a5c3b6 100644 --- a/src/charon/plugins/kernel_netlink/kernel_netlink_net.c +++ b/src/charon/plugins/kernel_netlink/kernel_netlink_net.c @@ -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"); } } |