kernel-wfp: Install appropriate routes for tunnel mode policies
This commit is contained in:
@@ -56,6 +56,11 @@ struct private_kernel_wfp_ipsec_t {
|
|||||||
*/
|
*/
|
||||||
hashtable_t *osas;
|
hashtable_t *osas;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Installed routes, as route_t => route_t
|
||||||
|
*/
|
||||||
|
hashtable_t *routes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mutex for accessing entries
|
* Mutex for accessing entries
|
||||||
*/
|
*/
|
||||||
@@ -157,6 +162,56 @@ typedef struct {
|
|||||||
u_int64_t sa_id;
|
u_int64_t sa_id;
|
||||||
} entry_t;
|
} entry_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Installed route
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/** destination net of route */
|
||||||
|
host_t *dst;
|
||||||
|
/** prefix length of dst */
|
||||||
|
u_int8_t mask;
|
||||||
|
/** source address for route */
|
||||||
|
host_t *src;
|
||||||
|
/** gateway of route, NULL if directly attached */
|
||||||
|
host_t *gtw;
|
||||||
|
/** references for route */
|
||||||
|
u_int refs;
|
||||||
|
} route_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy a route_t
|
||||||
|
*/
|
||||||
|
static void destroy_route(route_t *this)
|
||||||
|
{
|
||||||
|
this->dst->destroy(this->dst);
|
||||||
|
this->src->destroy(this->src);
|
||||||
|
DESTROY_IF(this->gtw);
|
||||||
|
free(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hashtable equals function for routes
|
||||||
|
*/
|
||||||
|
static bool equals_route(route_t *a, route_t *b)
|
||||||
|
{
|
||||||
|
return a->mask == b->mask &&
|
||||||
|
a->dst->ip_equals(a->dst, b->dst) &&
|
||||||
|
a->src->ip_equals(a->src, b->src);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hashtable hash function for routes
|
||||||
|
*/
|
||||||
|
static u_int hash_route(route_t *route)
|
||||||
|
{
|
||||||
|
return chunk_hash_inc(route->src->get_address(route->src),
|
||||||
|
chunk_hash_inc(route->dst->get_address(route->dst), route->mask));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** forward declaration */
|
||||||
|
static bool manage_routes(private_kernel_wfp_ipsec_t *this, entry_t *entry,
|
||||||
|
bool add);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove a transport or tunnel policy from kernel
|
* Remove a transport or tunnel policy from kernel
|
||||||
*/
|
*/
|
||||||
@@ -195,6 +250,10 @@ static void cleanup_policies(private_kernel_wfp_ipsec_t *this, entry_t *entry)
|
|||||||
cleanup_policy(this, entry->mode == MODE_TRANSPORT, entry->policy_out);
|
cleanup_policy(this, entry->mode == MODE_TRANSPORT, entry->policy_out);
|
||||||
entry->policy_out = 0;
|
entry->policy_out = 0;
|
||||||
}
|
}
|
||||||
|
if (entry->mode == MODE_TUNNEL)
|
||||||
|
{
|
||||||
|
manage_routes(this, entry, FALSE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -962,12 +1021,158 @@ static bool install_tunnel_sps(private_kernel_wfp_ipsec_t *this, entry_t *entry)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reduce refcount, or uninstall a route if all refs gone
|
||||||
|
*/
|
||||||
|
static bool uninstall_route(private_kernel_wfp_ipsec_t *this,
|
||||||
|
host_t *dst, u_int8_t mask, host_t *src, host_t *gtw)
|
||||||
|
{
|
||||||
|
route_t *route, key = {
|
||||||
|
.dst = dst,
|
||||||
|
.mask = mask,
|
||||||
|
.src = src,
|
||||||
|
};
|
||||||
|
char *name;
|
||||||
|
bool res = FALSE;
|
||||||
|
|
||||||
|
this->mutex->lock(this->mutex);
|
||||||
|
route = this->routes->get(this->routes, &key);
|
||||||
|
if (route)
|
||||||
|
{
|
||||||
|
if (--route->refs == 0)
|
||||||
|
{
|
||||||
|
if (hydra->kernel_interface->get_interface(hydra->kernel_interface,
|
||||||
|
src, &name))
|
||||||
|
{
|
||||||
|
res = hydra->kernel_interface->del_route(hydra->kernel_interface,
|
||||||
|
dst->get_address(dst), mask, gtw, src, name) == SUCCESS;
|
||||||
|
free(name);
|
||||||
|
}
|
||||||
|
route = this->routes->remove(this->routes, route);
|
||||||
|
if (route)
|
||||||
|
{
|
||||||
|
destroy_route(route);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
res = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this->mutex->unlock(this->mutex);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Install a single route, or refcount if exists
|
||||||
|
*/
|
||||||
|
static bool install_route(private_kernel_wfp_ipsec_t *this,
|
||||||
|
host_t *dst, u_int8_t mask, host_t *src, host_t *gtw)
|
||||||
|
{
|
||||||
|
route_t *route, key = {
|
||||||
|
.dst = dst,
|
||||||
|
.mask = mask,
|
||||||
|
.src = src,
|
||||||
|
};
|
||||||
|
char *name;
|
||||||
|
bool res = FALSE;
|
||||||
|
|
||||||
|
this->mutex->lock(this->mutex);
|
||||||
|
route = this->routes->get(this->routes, &key);
|
||||||
|
if (route)
|
||||||
|
{
|
||||||
|
route->refs++;
|
||||||
|
res = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (hydra->kernel_interface->get_interface(hydra->kernel_interface,
|
||||||
|
src, &name))
|
||||||
|
{
|
||||||
|
if (hydra->kernel_interface->add_route(hydra->kernel_interface,
|
||||||
|
dst->get_address(dst), mask, gtw, src, name) == SUCCESS)
|
||||||
|
{
|
||||||
|
INIT(route,
|
||||||
|
.dst = dst->clone(dst),
|
||||||
|
.mask = mask,
|
||||||
|
.src = src->clone(src),
|
||||||
|
.gtw = gtw ? gtw->clone(gtw) : NULL,
|
||||||
|
.refs = 1,
|
||||||
|
);
|
||||||
|
route = this->routes->put(this->routes, route, route);
|
||||||
|
if (route)
|
||||||
|
{
|
||||||
|
destroy_route(route);
|
||||||
|
}
|
||||||
|
res = TRUE;
|
||||||
|
}
|
||||||
|
free(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this->mutex->unlock(this->mutex);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (Un)-install routes for IPsec policies
|
||||||
|
*/
|
||||||
|
static bool manage_routes(private_kernel_wfp_ipsec_t *this, entry_t *entry,
|
||||||
|
bool add)
|
||||||
|
{
|
||||||
|
enumerator_t *enumerator;
|
||||||
|
host_t *src, *dst, *gtw;
|
||||||
|
sp_entry_t *sp;
|
||||||
|
u_int8_t mask;
|
||||||
|
|
||||||
|
enumerator = array_create_enumerator(entry->sps);
|
||||||
|
while (enumerator->enumerate(enumerator, &sp))
|
||||||
|
{
|
||||||
|
if (!sp->dst->to_subnet(sp->dst, &dst, &mask))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (hydra->kernel_interface->get_address_by_ts( hydra->kernel_interface,
|
||||||
|
sp->src, &src, NULL) != SUCCESS)
|
||||||
|
{
|
||||||
|
dst->destroy(dst);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
gtw = hydra->kernel_interface->get_nexthop(hydra->kernel_interface,
|
||||||
|
entry->remote, entry->local);
|
||||||
|
if (add)
|
||||||
|
{
|
||||||
|
if (!install_route(this, dst, mask, src, gtw))
|
||||||
|
{
|
||||||
|
DBG1(DBG_KNL, "installing route for policy %R === %R failed",
|
||||||
|
sp->src, sp->dst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!uninstall_route(this, dst, mask, src, gtw))
|
||||||
|
{
|
||||||
|
DBG1(DBG_KNL, "uninstalling route for policy %R === %R failed",
|
||||||
|
sp->src, sp->dst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dst->destroy(dst);
|
||||||
|
src->destroy(src);
|
||||||
|
DESTROY_IF(gtw);
|
||||||
|
}
|
||||||
|
enumerator->destroy(enumerator);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Install a tunnel mode SA/SP set to the kernel
|
* Install a tunnel mode SA/SP set to the kernel
|
||||||
*/
|
*/
|
||||||
static bool install_tunnel(private_kernel_wfp_ipsec_t *this, entry_t *entry)
|
static bool install_tunnel(private_kernel_wfp_ipsec_t *this, entry_t *entry)
|
||||||
{
|
{
|
||||||
if (install_tunnel_sps(this, entry) &&
|
if (install_tunnel_sps(this, entry) &&
|
||||||
|
manage_routes(this, entry, TRUE) &&
|
||||||
install_sas(this, entry, IPSEC_TRAFFIC_TYPE_TUNNEL))
|
install_sas(this, entry, IPSEC_TRAFFIC_TYPE_TUNNEL))
|
||||||
{
|
{
|
||||||
return TRUE;
|
return TRUE;
|
||||||
@@ -1394,6 +1599,7 @@ METHOD(kernel_ipsec_t, destroy, void,
|
|||||||
this->tsas->destroy(this->tsas);
|
this->tsas->destroy(this->tsas);
|
||||||
this->isas->destroy(this->isas);
|
this->isas->destroy(this->isas);
|
||||||
this->osas->destroy(this->osas);
|
this->osas->destroy(this->osas);
|
||||||
|
this->routes->destroy(this->routes);
|
||||||
this->mutex->destroy(this->mutex);
|
this->mutex->destroy(this->mutex);
|
||||||
free(this);
|
free(this);
|
||||||
}
|
}
|
||||||
@@ -1441,10 +1647,11 @@ kernel_wfp_ipsec_t *kernel_wfp_ipsec_create()
|
|||||||
{ 0xa9,0x59,0x9d,0x91,0xac,0xaf,0xf9,0x19 }},
|
{ 0xa9,0x59,0x9d,0x91,0xac,0xaf,0xf9,0x19 }},
|
||||||
},
|
},
|
||||||
.nextspi = 0xc0000001,
|
.nextspi = 0xc0000001,
|
||||||
.mutex = mutex_create(MUTEX_TYPE_DEFAULT),
|
.mutex = mutex_create(MUTEX_TYPE_RECURSIVE),
|
||||||
.tsas = hashtable_create(hashtable_hash_ptr, hashtable_equals_ptr, 4),
|
.tsas = hashtable_create(hashtable_hash_ptr, hashtable_equals_ptr, 4),
|
||||||
.isas = hashtable_create((void*)hash_sa, (void*)equals_sa, 4),
|
.isas = hashtable_create((void*)hash_sa, (void*)equals_sa, 4),
|
||||||
.osas = hashtable_create((void*)hash_sa, (void*)equals_sa, 4),
|
.osas = hashtable_create((void*)hash_sa, (void*)equals_sa, 4),
|
||||||
|
.routes = hashtable_create((void*)hash_route, (void*)equals_route, 4),
|
||||||
);
|
);
|
||||||
|
|
||||||
res = FwpmEngineOpen0(NULL, RPC_C_AUTHN_WINNT, NULL, &session,
|
res = FwpmEngineOpen0(NULL, RPC_C_AUTHN_WINNT, NULL, &session,
|
||||||
|
|||||||
Reference in New Issue
Block a user