kernel-netlink: Allow blank source address in routes for passthrough policies

This commit is contained in:
Tobias Brunner
2020-03-10 10:25:19 +01:00
parent 09f4bccfea
commit b0b6bd2470
@@ -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, 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, free(route);
ipsec->dst, -1, ipsec->src, return;
&route->if_name);
} }
else /* allow blank source IP for passthrough policies */
{ /* for shunt policies */ route->src_ip = host_create_any(policy->sel.family);
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 (!ipsec->dst->is_anyaddr(ipsec->dst))
* If we have a local address, use it. Otherwise (for shunt policies) {
* use the route's source address. */ route->gateway = charon->kernel->get_nexthop(charon->kernel,
if (!route->if_name) ipsec->dst, -1, ipsec->src,
{ &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;
}
}
if (policy->route)
{
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;
}
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))
{
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;
}
} }
else 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)
{ {
free(route); 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;
}
}
if (policy->route)
{
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;
}
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))
{
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;
} }
} }