kernel-pfkey: Install routes with OUT policies

This commit is contained in:
Tobias Brunner
2016-06-10 15:25:46 +02:00
parent aea3c1052e
commit b98afc0a37
@@ -400,7 +400,7 @@ static void ipsec_sa_destroy(private_kernel_pfkey_ipsec_t *this,
} }
typedef struct policy_sa_t policy_sa_t; typedef struct policy_sa_t policy_sa_t;
typedef struct policy_sa_in_t policy_sa_in_t; typedef struct policy_sa_out_t policy_sa_out_t;
/** /**
* Mapping between a policy and an IPsec SA. * Mapping between a policy and an IPsec SA.
@@ -420,10 +420,10 @@ struct policy_sa_t {
}; };
/** /**
* For input policies we also cache the traffic selectors in order to install * For outbound policies we also cache the traffic selectors in order to install
* the route. * the route.
*/ */
struct policy_sa_in_t { struct policy_sa_out_t {
/** Generic interface */ /** Generic interface */
policy_sa_t generic; policy_sa_t generic;
@@ -443,14 +443,14 @@ static policy_sa_t *policy_sa_create(private_kernel_pfkey_ipsec_t *this,
{ {
policy_sa_t *policy; policy_sa_t *policy;
if (dir == POLICY_IN) if (dir == POLICY_OUT)
{ {
policy_sa_in_t *in; policy_sa_out_t *out;
INIT(in, INIT(out,
.src_ts = src_ts->clone(src_ts), .src_ts = src_ts->clone(src_ts),
.dst_ts = dst_ts->clone(dst_ts), .dst_ts = dst_ts->clone(dst_ts),
); );
policy = &in->generic; policy = &out->generic;
} }
else else
{ {
@@ -467,11 +467,11 @@ static policy_sa_t *policy_sa_create(private_kernel_pfkey_ipsec_t *this,
static void policy_sa_destroy(policy_sa_t *policy, policy_dir_t *dir, static void policy_sa_destroy(policy_sa_t *policy, policy_dir_t *dir,
private_kernel_pfkey_ipsec_t *this) private_kernel_pfkey_ipsec_t *this)
{ {
if (*dir == POLICY_IN) if (*dir == POLICY_OUT)
{ {
policy_sa_in_t *in = (policy_sa_in_t*)policy; policy_sa_out_t *out = (policy_sa_out_t*)policy;
in->src_ts->destroy(in->src_ts); out->src_ts->destroy(out->src_ts);
in->dst_ts->destroy(in->dst_ts); out->dst_ts->destroy(out->dst_ts);
} }
ipsec_sa_destroy(this, policy->sa); ipsec_sa_destroy(this, policy->sa);
free(policy); free(policy);
@@ -2287,31 +2287,30 @@ static void remove_exclude_route(private_kernel_pfkey_ipsec_t *this,
} }
/** /**
* Try to install a route to the given inbound policy * Try to install a route to the given outbound policy
*/ */
static bool install_route(private_kernel_pfkey_ipsec_t *this, static bool install_route(private_kernel_pfkey_ipsec_t *this,
policy_entry_t *policy, policy_sa_in_t *in) policy_entry_t *policy, policy_sa_out_t *out)
{ {
route_entry_t *route, *old; route_entry_t *route, *old;
host_t *host, *src, *dst; host_t *host, *src, *dst;
bool is_virtual; bool is_virtual;
if (charon->kernel->get_address_by_ts(charon->kernel, in->dst_ts, &host, if (charon->kernel->get_address_by_ts(charon->kernel, out->src_ts, &host,
&is_virtual) != SUCCESS) &is_virtual) != SUCCESS)
{ {
return FALSE; return FALSE;
} }
/* switch src/dst, as we handle an IN policy */
src = in->generic.sa->dst;
dst = in->generic.sa->src;
INIT(route, INIT(route,
.prefixlen = policy->src.mask, .prefixlen = policy->dst.mask,
.src_ip = host, .src_ip = host,
.dst_net = chunk_clone(policy->src.net->get_address(policy->src.net)), .dst_net = chunk_clone(policy->dst.net->get_address(policy->dst.net)),
); );
src = out->generic.sa->src;
dst = out->generic.sa->dst;
if (!dst->is_anyaddr(dst)) if (!dst->is_anyaddr(dst))
{ {
route->gateway = charon->kernel->get_nexthop(charon->kernel, dst, -1, route->gateway = charon->kernel->get_nexthop(charon->kernel, dst, -1,
@@ -2330,7 +2329,7 @@ static bool install_route(private_kernel_pfkey_ipsec_t *this,
else else
{ /* for shunt policies */ { /* for shunt policies */
route->gateway = charon->kernel->get_nexthop(charon->kernel, route->gateway = charon->kernel->get_nexthop(charon->kernel,
policy->src.net, policy->src.mask, policy->dst.net, policy->dst.mask,
route->src_ip, &route->if_name); route->src_ip, &route->if_name);
/* we don't have a source address, use the address we found */ /* we don't have a source address, use the address we found */
@@ -2360,7 +2359,7 @@ static bool install_route(private_kernel_pfkey_ipsec_t *this,
old->src_ip, old->if_name) != SUCCESS) old->src_ip, old->if_name) != SUCCESS)
{ {
DBG1(DBG_KNL, "error uninstalling route installed with policy " DBG1(DBG_KNL, "error uninstalling route installed with policy "
"%R === %R %N", in->src_ts, in->dst_ts, "%R === %R %N", out->src_ts, out->dst_ts,
policy_dir_names, policy->direction); policy_dir_names, policy->direction);
} }
route_entry_destroy(old); route_entry_destroy(old);
@@ -2370,22 +2369,22 @@ static bool install_route(private_kernel_pfkey_ipsec_t *this,
/* if remote traffic selector covers the IKE peer, add an exclude route */ /* if remote traffic selector covers the IKE peer, add an exclude route */
if (charon->kernel->get_features(charon->kernel) & KERNEL_REQUIRE_EXCLUDE_ROUTE) if (charon->kernel->get_features(charon->kernel) & KERNEL_REQUIRE_EXCLUDE_ROUTE)
{ {
if (in->src_ts->is_host(in->src_ts, dst)) if (out->dst_ts->is_host(out->dst_ts, dst))
{ {
DBG1(DBG_KNL, "can't install route for %R === %R %N, conflicts " DBG1(DBG_KNL, "can't install route for %R === %R %N, conflicts "
"with IKE traffic", in->src_ts, in->dst_ts, policy_dir_names, "with IKE traffic", out->src_ts, out->dst_ts, policy_dir_names,
policy->direction); policy->direction);
route_entry_destroy(route); route_entry_destroy(route);
return FALSE; return FALSE;
} }
if (in->src_ts->includes(in->src_ts, dst)) if (out->dst_ts->includes(out->dst_ts, dst))
{ {
add_exclude_route(this, route, in->generic.sa->dst, dst); add_exclude_route(this, route, out->generic.sa->src, dst);
} }
} }
DBG2(DBG_KNL, "installing route: %R via %H src %H dev %s", DBG2(DBG_KNL, "installing route: %R via %H src %H dev %s",
in->src_ts, route->gateway, route->src_ip, route->if_name); out->dst_ts, route->gateway, route->src_ip, route->if_name);
switch (charon->kernel->add_route(charon->kernel, route->dst_net, switch (charon->kernel->add_route(charon->kernel, route->dst_net,
route->prefixlen, route->gateway, route->prefixlen, route->gateway,
@@ -2402,7 +2401,7 @@ static bool install_route(private_kernel_pfkey_ipsec_t *this,
return TRUE; return TRUE;
default: default:
DBG1(DBG_KNL, "installing route failed: %R via %H src %H dev %s", DBG1(DBG_KNL, "installing route failed: %R via %H src %H dev %s",
in->src_ts, route->gateway, route->src_ip, route->if_name); out->dst_ts, route->gateway, route->src_ip, route->if_name);
remove_exclude_route(this, route); remove_exclude_route(this, route);
route_entry_destroy(route); route_entry_destroy(route);
return FALSE; return FALSE;
@@ -2559,12 +2558,12 @@ static status_t add_policy_internal(private_kernel_pfkey_ipsec_t *this,
free(out); free(out);
/* install a route, if: /* install a route, if:
* - this is an inbound policy (to just get one for each child) * - this is an outbound policy (to just get one for each child)
* - routing is not disabled via strongswan.conf * - routing is not disabled via strongswan.conf
* - the selector is not for a specific protocol/port * - the selector is not for a specific protocol/port
* - we are in tunnel mode or install a bypass policy * - we are in tunnel mode or install a bypass policy
*/ */
if (policy->direction == POLICY_IN && this->install_routes && if (policy->direction == POLICY_OUT && this->install_routes &&
policy->src.proto == IPSEC_PROTO_ANY && policy->src.proto == IPSEC_PROTO_ANY &&
!policy->src.net->get_port(policy->src.net) && !policy->src.net->get_port(policy->src.net) &&
!policy->dst.net->get_port(policy->dst.net)) !policy->dst.net->get_port(policy->dst.net))
@@ -2572,7 +2571,7 @@ static status_t add_policy_internal(private_kernel_pfkey_ipsec_t *this,
if (mapping->type == POLICY_PASS || if (mapping->type == POLICY_PASS ||
(mapping->type == POLICY_IPSEC && ipsec->cfg.mode != MODE_TRANSPORT)) (mapping->type == POLICY_IPSEC && ipsec->cfg.mode != MODE_TRANSPORT))
{ {
install_route(this, policy, (policy_sa_in_t*)mapping); install_route(this, policy, (policy_sa_out_t*)mapping);
} }
} }
this->mutex->unlock(this->mutex); this->mutex->unlock(this->mutex);