unity: Handle multi-valued UNITY_SPLIT_INCLUDE/UNITY_LOCAL_LAN attributes
Cisco devices seem to add 6 bytes of padding between each address/mask pair. Fixes #366.
This commit is contained in:
@@ -1,4 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
|
* Copyright (C) 2013 Tobias Brunner
|
||||||
|
* Hochschule fuer Technik Rapperswil
|
||||||
|
*
|
||||||
* Copyright (C) 2012 Martin Willi
|
* Copyright (C) 2012 Martin Willi
|
||||||
* Copyright (C) 2012 revosec AG
|
* Copyright (C) 2012 revosec AG
|
||||||
*
|
*
|
||||||
@@ -70,12 +73,8 @@ static traffic_selector_t *create_ts(chunk_t subnet)
|
|||||||
chunk_t net, mask;
|
chunk_t net, mask;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (subnet.len < 8)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
net = chunk_create(subnet.ptr, 4);
|
net = chunk_create(subnet.ptr, 4);
|
||||||
mask = chunk_clonea(chunk_skip(subnet, 4));
|
mask = chunk_clonea(chunk_create(subnet.ptr + 4, 4));
|
||||||
for (i = 0; i < net.len; i++)
|
for (i = 0; i < net.len; i++)
|
||||||
{
|
{
|
||||||
mask.ptr[i] = (mask.ptr[i] ^ 0xFF) | net.ptr[i];
|
mask.ptr[i] = (mask.ptr[i] ^ 0xFF) | net.ptr[i];
|
||||||
@@ -85,11 +84,37 @@ static traffic_selector_t *create_ts(chunk_t subnet)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Store a subnet to include in tunnels under this IKE_SA
|
* Parse a unity attribute and extract all subnets as traffic selectors
|
||||||
*/
|
*/
|
||||||
static bool add_include(private_unity_handler_t *this, chunk_t subnet)
|
static linked_list_t *parse_subnets(chunk_t data)
|
||||||
|
{
|
||||||
|
linked_list_t *list = NULL;
|
||||||
|
traffic_selector_t *ts;
|
||||||
|
|
||||||
|
while (data.len >= 8)
|
||||||
|
{ /* the padding is optional */
|
||||||
|
ts = create_ts(data);
|
||||||
|
if (ts)
|
||||||
|
{
|
||||||
|
if (!list)
|
||||||
|
{
|
||||||
|
list = linked_list_create();
|
||||||
|
}
|
||||||
|
list->insert_last(list, ts);
|
||||||
|
}
|
||||||
|
/* skip address, mask and 6 bytes of padding */
|
||||||
|
data = chunk_skip(data, 14);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store a list of subnets to include in tunnels under this IKE_SA
|
||||||
|
*/
|
||||||
|
static bool add_include(private_unity_handler_t *this, chunk_t data)
|
||||||
{
|
{
|
||||||
traffic_selector_t *ts;
|
traffic_selector_t *ts;
|
||||||
|
linked_list_t *list;
|
||||||
ike_sa_t *ike_sa;
|
ike_sa_t *ike_sa;
|
||||||
entry_t *entry;
|
entry_t *entry;
|
||||||
|
|
||||||
@@ -98,29 +123,34 @@ static bool add_include(private_unity_handler_t *this, chunk_t subnet)
|
|||||||
{
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
ts = create_ts(subnet);
|
list = parse_subnets(data);
|
||||||
if (!ts)
|
if (!list)
|
||||||
{
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
INIT(entry,
|
while (list->remove_first(list, (void**)&ts) == SUCCESS)
|
||||||
.sa = ike_sa->get_unique_id(ike_sa),
|
{
|
||||||
.ts = ts,
|
INIT(entry,
|
||||||
);
|
.sa = ike_sa->get_unique_id(ike_sa),
|
||||||
|
.ts = ts,
|
||||||
|
);
|
||||||
|
|
||||||
this->mutex->lock(this->mutex);
|
this->mutex->lock(this->mutex);
|
||||||
this->include->insert_last(this->include, entry);
|
this->include->insert_last(this->include, entry);
|
||||||
this->mutex->unlock(this->mutex);
|
this->mutex->unlock(this->mutex);
|
||||||
|
}
|
||||||
|
list->destroy(list);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove a subnet from the inclusion list for this IKE_SA
|
* Remove a list of subnets from the inclusion list for this IKE_SA
|
||||||
*/
|
*/
|
||||||
static bool remove_include(private_unity_handler_t *this, chunk_t subnet)
|
static bool remove_include(private_unity_handler_t *this, chunk_t data)
|
||||||
{
|
{
|
||||||
enumerator_t *enumerator;
|
enumerator_t *enumerator;
|
||||||
traffic_selector_t *ts;
|
traffic_selector_t *ts;
|
||||||
|
linked_list_t *list;
|
||||||
ike_sa_t *ike_sa;
|
ike_sa_t *ike_sa;
|
||||||
entry_t *entry;
|
entry_t *entry;
|
||||||
|
|
||||||
@@ -129,27 +159,31 @@ static bool remove_include(private_unity_handler_t *this, chunk_t subnet)
|
|||||||
{
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
ts = create_ts(subnet);
|
list = parse_subnets(data);
|
||||||
if (!ts)
|
if (!list)
|
||||||
{
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->mutex->lock(this->mutex);
|
this->mutex->lock(this->mutex);
|
||||||
enumerator = this->include->create_enumerator(this->include);
|
while (list->remove_first(list, (void**)&ts) == SUCCESS)
|
||||||
while (enumerator->enumerate(enumerator, &entry))
|
|
||||||
{
|
{
|
||||||
if (entry->sa == ike_sa->get_unique_id(ike_sa) &&
|
enumerator = this->include->create_enumerator(this->include);
|
||||||
ts->equals(ts, entry->ts))
|
while (enumerator->enumerate(enumerator, &entry))
|
||||||
{
|
{
|
||||||
this->include->remove_at(this->include, enumerator);
|
if (entry->sa == ike_sa->get_unique_id(ike_sa) &&
|
||||||
entry_destroy(entry);
|
ts->equals(ts, entry->ts))
|
||||||
break;
|
{
|
||||||
|
this->include->remove_at(this->include, enumerator);
|
||||||
|
entry_destroy(entry);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
enumerator->destroy(enumerator);
|
||||||
|
ts->destroy(ts);
|
||||||
}
|
}
|
||||||
enumerator->destroy(enumerator);
|
|
||||||
this->mutex->unlock(this->mutex);
|
this->mutex->unlock(this->mutex);
|
||||||
ts->destroy(ts);
|
list->destroy(list);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,9 +246,10 @@ static job_requeue_t add_exclude_async(entry_t *entry)
|
|||||||
/**
|
/**
|
||||||
* Add a bypass policy for a given subnet
|
* Add a bypass policy for a given subnet
|
||||||
*/
|
*/
|
||||||
static bool add_exclude(private_unity_handler_t *this, chunk_t subnet)
|
static bool add_exclude(private_unity_handler_t *this, chunk_t data)
|
||||||
{
|
{
|
||||||
traffic_selector_t *ts;
|
traffic_selector_t *ts;
|
||||||
|
linked_list_t *list;
|
||||||
ike_sa_t *ike_sa;
|
ike_sa_t *ike_sa;
|
||||||
entry_t *entry;
|
entry_t *entry;
|
||||||
|
|
||||||
@@ -223,48 +258,60 @@ static bool add_exclude(private_unity_handler_t *this, chunk_t subnet)
|
|||||||
{
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
ts = create_ts(subnet);
|
list = parse_subnets(data);
|
||||||
if (!ts)
|
if (!list)
|
||||||
{
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
INIT(entry,
|
|
||||||
.sa = ike_sa->get_unique_id(ike_sa),
|
|
||||||
.ts = ts,
|
|
||||||
);
|
|
||||||
|
|
||||||
/* we can't install the shunt policy yet, as we don't know the virtual IP.
|
while (list->remove_first(list, (void**)&ts) == SUCCESS)
|
||||||
* Defer installation using an async callback. */
|
{
|
||||||
lib->processor->queue_job(lib->processor, (job_t*)
|
INIT(entry,
|
||||||
callback_job_create((void*)add_exclude_async, entry,
|
.sa = ike_sa->get_unique_id(ike_sa),
|
||||||
(void*)entry_destroy, NULL));
|
.ts = ts,
|
||||||
|
);
|
||||||
|
|
||||||
|
/* we can't install the shunt policy yet, as we don't know the virtual IP.
|
||||||
|
* Defer installation using an async callback. */
|
||||||
|
lib->processor->queue_job(lib->processor, (job_t*)
|
||||||
|
callback_job_create((void*)add_exclude_async, entry,
|
||||||
|
(void*)entry_destroy, NULL));
|
||||||
|
}
|
||||||
|
list->destroy(list);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove a bypass policy for a given subnet
|
* Remove a bypass policy for a given subnet
|
||||||
*/
|
*/
|
||||||
static bool remove_exclude(private_unity_handler_t *this, chunk_t subnet)
|
static bool remove_exclude(private_unity_handler_t *this, chunk_t data)
|
||||||
{
|
{
|
||||||
traffic_selector_t *ts;
|
traffic_selector_t *ts;
|
||||||
|
linked_list_t *list;
|
||||||
ike_sa_t *ike_sa;
|
ike_sa_t *ike_sa;
|
||||||
char name[128];
|
char name[128];
|
||||||
|
bool success = TRUE;
|
||||||
|
|
||||||
ike_sa = charon->bus->get_sa(charon->bus);
|
ike_sa = charon->bus->get_sa(charon->bus);
|
||||||
if (!ike_sa)
|
if (!ike_sa)
|
||||||
{
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
ts = create_ts(subnet);
|
list = parse_subnets(data);
|
||||||
if (!ts)
|
if (!list)
|
||||||
{
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
create_shunt_name(ike_sa, ts, name, sizeof(name));
|
while (list->remove_first(list, (void**)&ts) == SUCCESS)
|
||||||
DBG1(DBG_IKE, "uninstalling %N bypass policy for %R",
|
{
|
||||||
configuration_attribute_type_names, UNITY_LOCAL_LAN, ts);
|
create_shunt_name(ike_sa, ts, name, sizeof(name));
|
||||||
ts->destroy(ts);
|
DBG1(DBG_IKE, "uninstalling %N bypass policy for %R",
|
||||||
return charon->shunts->uninstall(charon->shunts, name);
|
configuration_attribute_type_names, UNITY_LOCAL_LAN, ts);
|
||||||
|
ts->destroy(ts);
|
||||||
|
success = charon->shunts->uninstall(charon->shunts, name) && success;
|
||||||
|
}
|
||||||
|
list->destroy(list);
|
||||||
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
METHOD(attribute_handler_t, handle, bool,
|
METHOD(attribute_handler_t, handle, bool,
|
||||||
|
|||||||
Reference in New Issue
Block a user