kernel-netlink: Don't install routes for drop policies and if protocol/ports are in the selector
We don't need them for drop policies and they might even mess with other routes we install. Routes for policies with protocol/ports in the selector will always be too broad and might conflict with other routes we install.
This commit is contained in:
@@ -2174,6 +2174,105 @@ static void policy_change_done(private_kernel_netlink_ipsec_t *this,
|
|||||||
this->mutex->unlock(this->mutex);
|
this->mutex->unlock(this->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Install a route for the given policy if enabled and required
|
||||||
|
*/
|
||||||
|
static void install_route(private_kernel_netlink_ipsec_t *this,
|
||||||
|
policy_entry_t *policy, policy_sa_t *mapping, ipsec_sa_t *ipsec)
|
||||||
|
{
|
||||||
|
policy_sa_in_t *in = (policy_sa_in_t*)mapping;
|
||||||
|
route_entry_t *route;
|
||||||
|
host_t *iface;
|
||||||
|
|
||||||
|
INIT(route,
|
||||||
|
.prefixlen = policy->sel.prefixlen_s,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (charon->kernel->get_address_by_ts(charon->kernel, in->dst_ts,
|
||||||
|
&route->src_ip, NULL) == SUCCESS)
|
||||||
|
{
|
||||||
|
/* get the nexthop to src (src as we are in POLICY_IN) */
|
||||||
|
if (!ipsec->src->is_anyaddr(ipsec->src))
|
||||||
|
{
|
||||||
|
route->gateway = charon->kernel->get_nexthop(charon->kernel,
|
||||||
|
ipsec->src, -1, ipsec->dst,
|
||||||
|
&route->if_name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ /* for shunt policies */
|
||||||
|
iface = xfrm2host(policy->sel.family, &policy->sel.saddr, 0);
|
||||||
|
route->gateway = charon->kernel->get_nexthop(charon->kernel,
|
||||||
|
iface, policy->sel.prefixlen_s,
|
||||||
|
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.saddr, 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->dst;
|
||||||
|
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) != SUCCESS)
|
||||||
|
{
|
||||||
|
DBG1(DBG_KNL, "error uninstalling route installed with policy "
|
||||||
|
"%R === %R %N", in->src_ts, in->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", in->src_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))
|
||||||
|
{
|
||||||
|
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
|
||||||
|
{
|
||||||
|
free(route);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add or update a policy in the kernel.
|
* Add or update a policy in the kernel.
|
||||||
*
|
*
|
||||||
@@ -2298,107 +2397,18 @@ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this,
|
|||||||
return FAILED;
|
return FAILED;
|
||||||
}
|
}
|
||||||
/* install a route, if:
|
/* install a route, if:
|
||||||
* - this is a inbound policy (to just get one for each child)
|
* - this is an inbound policy (to just get one for each child)
|
||||||
* - we are in tunnel/BEET mode or install a bypass policy
|
|
||||||
* - routing is not disabled via strongswan.conf
|
* - routing is not disabled via strongswan.conf
|
||||||
|
* - the selector is not for a specific protocol/port
|
||||||
|
* - we are in tunnel/BEET mode or install a bypass policy
|
||||||
*/
|
*/
|
||||||
if (policy->direction == POLICY_IN && this->install_routes &&
|
if (policy->direction == POLICY_IN && this->install_routes &&
|
||||||
(mapping->type != POLICY_IPSEC || ipsec->cfg.mode != MODE_TRANSPORT))
|
!policy->sel.proto && !policy->sel.dport && !policy->sel.sport)
|
||||||
{
|
{
|
||||||
policy_sa_in_t *in = (policy_sa_in_t*)mapping;
|
if (mapping->type == POLICY_PASS ||
|
||||||
route_entry_t *route;
|
(mapping->type == POLICY_IPSEC && ipsec->cfg.mode != MODE_TRANSPORT))
|
||||||
host_t *iface;
|
|
||||||
|
|
||||||
INIT(route,
|
|
||||||
.prefixlen = policy->sel.prefixlen_s,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (charon->kernel->get_address_by_ts(charon->kernel, in->dst_ts,
|
|
||||||
&route->src_ip, NULL) == SUCCESS)
|
|
||||||
{
|
{
|
||||||
/* get the nexthop to src (src as we are in POLICY_IN) */
|
install_route(this, policy, mapping, ipsec);
|
||||||
if (!ipsec->src->is_anyaddr(ipsec->src))
|
|
||||||
{
|
|
||||||
route->gateway = charon->kernel->get_nexthop(charon->kernel,
|
|
||||||
ipsec->src, -1, ipsec->dst,
|
|
||||||
&route->if_name);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{ /* for shunt policies */
|
|
||||||
iface = xfrm2host(policy->sel.family, &policy->sel.saddr, 0);
|
|
||||||
route->gateway = charon->kernel->get_nexthop(charon->kernel,
|
|
||||||
iface, policy->sel.prefixlen_s,
|
|
||||||
route->src_ip, NULL);
|
|
||||||
iface->destroy(iface);
|
|
||||||
}
|
|
||||||
route->dst_net = chunk_alloc(policy->sel.family == AF_INET ? 4 : 16);
|
|
||||||
memcpy(route->dst_net.ptr, &policy->sel.saddr, route->dst_net.len);
|
|
||||||
|
|
||||||
/* get the interface to install the route for. If we have a local
|
|
||||||
* address, use it. Otherwise (for shunt policies) use the
|
|
||||||
* route's source address. */
|
|
||||||
iface = ipsec->dst;
|
|
||||||
if (iface->is_anyaddr(iface))
|
|
||||||
{
|
|
||||||
iface = ipsec->dst;
|
|
||||||
if (iface->is_anyaddr(iface))
|
|
||||||
{
|
|
||||||
iface = route->src_ip;
|
|
||||||
}
|
|
||||||
if (!charon->kernel->get_interface(charon->kernel, iface,
|
|
||||||
&route->if_name))
|
|
||||||
{
|
|
||||||
policy_change_done(this, policy);
|
|
||||||
route_entry_destroy(route);
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (policy->route)
|
|
||||||
{
|
|
||||||
route_entry_t *old = policy->route;
|
|
||||||
if (route_entry_equals(old, route))
|
|
||||||
{
|
|
||||||
policy_change_done(this, policy);
|
|
||||||
route_entry_destroy(route);
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
|
||||||
/* uninstall previously installed route */
|
|
||||||
if (charon->kernel->del_route(charon->kernel, old->dst_net,
|
|
||||||
old->prefixlen, old->gateway,
|
|
||||||
old->src_ip, old->if_name) != SUCCESS)
|
|
||||||
{
|
|
||||||
DBG1(DBG_KNL, "error uninstalling route installed with "
|
|
||||||
"policy %R === %R %N", in->src_ts, in->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",
|
|
||||||
in->src_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))
|
|
||||||
{
|
|
||||||
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
|
|
||||||
{
|
|
||||||
free(route);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
policy_change_done(this, policy);
|
policy_change_done(this, policy);
|
||||||
|
|||||||
Reference in New Issue
Block a user