From: Tobias Brunner Date: Tue, 25 Feb 2020 15:39:35 +0000 (+0100) Subject: kernel-netlink: Allow blank source address in routes for passthrough policies X-Git-Tag: 5.8.3rc1~4^2~2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=b0b6bd24701edf2998015b79e561641dab2b00b3;p=thirdparty%2Fstrongswan.git kernel-netlink: Allow blank source address in routes for passthrough policies --- diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c index 9a91549cf1..da22c0bbba 100644 --- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c +++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c @@ -2622,88 +2622,92 @@ static void install_route(private_kernel_netlink_ipsec_t *this, ); if (charon->kernel->get_address_by_ts(charon->kernel, out->src_ts, - &route->src_ip, NULL) == SUCCESS) + &route->src_ip, NULL) != SUCCESS) { - if (!ipsec->dst->is_anyaddr(ipsec->dst)) + if (!route->pass) { - route->gateway = charon->kernel->get_nexthop(charon->kernel, - ipsec->dst, -1, ipsec->src, - &route->if_name); + free(route); + return; } - else - { /* for shunt policies */ - iface = xfrm2host(policy->sel.family, &policy->sel.daddr, 0); - route->gateway = charon->kernel->get_nexthop(charon->kernel, - iface, policy->sel.prefixlen_d, - route->src_ip, &route->if_name); - iface->destroy(iface); - } - route->dst_net = chunk_alloc(policy->sel.family == AF_INET ? 4 : 16); - memcpy(route->dst_net.ptr, &policy->sel.daddr, route->dst_net.len); - - /* get the interface to install the route for, if we haven't one yet. - * If we have a local address, use it. Otherwise (for shunt policies) - * use the route's source address. */ - if (!route->if_name) - { - iface = ipsec->src; - if (iface->is_anyaddr(iface)) - { - iface = route->src_ip; - } - if (!charon->kernel->get_interface(charon->kernel, iface, - &route->if_name)) - { - route_entry_destroy(route); - return; - } + /* allow blank source IP for passthrough policies */ + route->src_ip = host_create_any(policy->sel.family); + } + + if (!ipsec->dst->is_anyaddr(ipsec->dst)) + { + route->gateway = charon->kernel->get_nexthop(charon->kernel, + ipsec->dst, -1, ipsec->src, + &route->if_name); + } + else + { /* for shunt policies */ + iface = xfrm2host(policy->sel.family, &policy->sel.daddr, 0); + route->gateway = charon->kernel->get_nexthop(charon->kernel, + iface, policy->sel.prefixlen_d, + route->src_ip, &route->if_name); + iface->destroy(iface); + } + route->dst_net = chunk_alloc(policy->sel.family == AF_INET ? 4 : 16); + memcpy(route->dst_net.ptr, &policy->sel.daddr, route->dst_net.len); + + /* get the interface to install the route for, if we haven't one yet. + * If we have a local address, use it. Otherwise (for shunt policies) + * use the route's source address. */ + if (!route->if_name) + { + iface = ipsec->src; + if (iface->is_anyaddr(iface)) + { + iface = route->src_ip; } - if (policy->route) + if (!charon->kernel->get_interface(charon->kernel, iface, + &route->if_name)) { - route_entry_t *old = policy->route; - if (route_entry_equals(old, route)) - { - route_entry_destroy(route); - return; - } - /* uninstall previously installed route */ - if (charon->kernel->del_route(charon->kernel, old->dst_net, - old->prefixlen, old->gateway, - old->src_ip, old->if_name, - old->pass) != SUCCESS) - { - DBG1(DBG_KNL, "error uninstalling route installed with policy " - "%R === %R %N", out->src_ts, out->dst_ts, policy_dir_names, - policy->direction); - } - route_entry_destroy(old); - policy->route = NULL; + route_entry_destroy(route); + return; } - - DBG2(DBG_KNL, "installing route: %R via %H src %H dev %s", out->dst_ts, - route->gateway, route->src_ip, route->if_name); - switch (charon->kernel->add_route(charon->kernel, route->dst_net, - route->prefixlen, route->gateway, - route->src_ip, route->if_name, - route->pass)) + } + if (policy->route) + { + route_entry_t *old = policy->route; + if (route_entry_equals(old, route)) { - default: - DBG1(DBG_KNL, "unable to install source route for %H", - route->src_ip); - /* FALL */ - case ALREADY_DONE: - /* route exists, do not uninstall */ - route_entry_destroy(route); - break; - case SUCCESS: - /* cache the installed route */ - policy->route = route; - break; + route_entry_destroy(route); + return; } + /* uninstall previously installed route */ + if (charon->kernel->del_route(charon->kernel, old->dst_net, + old->prefixlen, old->gateway, + old->src_ip, old->if_name, + old->pass) != SUCCESS) + { + DBG1(DBG_KNL, "error uninstalling route installed with policy " + "%R === %R %N", out->src_ts, out->dst_ts, policy_dir_names, + policy->direction); + } + route_entry_destroy(old); + policy->route = NULL; } - else + + DBG2(DBG_KNL, "installing route: %R via %H src %H dev %s", out->dst_ts, + route->gateway, route->src_ip, route->if_name); + switch (charon->kernel->add_route(charon->kernel, route->dst_net, + route->prefixlen, route->gateway, + route->src_ip, route->if_name, + route->pass)) { - free(route); + default: + DBG1(DBG_KNL, "unable to install source route for %H", + route->src_ip); + /* FALL */ + case ALREADY_DONE: + /* route exists, do not uninstall */ + route_entry_destroy(route); + break; + case SUCCESS: + /* cache the installed route */ + policy->route = route; + break; } }