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:
Tobias Brunner
2013-07-29 21:44:27 +02:00
parent e8b8a6d958
commit 1cf8022839
+96 -49
View File
@@ -1,4 +1,7 @@
/*
* Copyright (C) 2013 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* Copyright (C) 2012 Martin Willi
* Copyright (C) 2012 revosec AG
*
@@ -70,12 +73,8 @@ static traffic_selector_t *create_ts(chunk_t subnet)
chunk_t net, mask;
int i;
if (subnet.len < 8)
{
return NULL;
}
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++)
{
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;
linked_list_t *list;
ike_sa_t *ike_sa;
entry_t *entry;
@@ -98,29 +123,34 @@ static bool add_include(private_unity_handler_t *this, chunk_t subnet)
{
return FALSE;
}
ts = create_ts(subnet);
if (!ts)
list = parse_subnets(data);
if (!list)
{
return FALSE;
}
INIT(entry,
.sa = ike_sa->get_unique_id(ike_sa),
.ts = ts,
);
while (list->remove_first(list, (void**)&ts) == SUCCESS)
{
INIT(entry,
.sa = ike_sa->get_unique_id(ike_sa),
.ts = ts,
);
this->mutex->lock(this->mutex);
this->include->insert_last(this->include, entry);
this->mutex->unlock(this->mutex);
this->mutex->lock(this->mutex);
this->include->insert_last(this->include, entry);
this->mutex->unlock(this->mutex);
}
list->destroy(list);
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;
traffic_selector_t *ts;
linked_list_t *list;
ike_sa_t *ike_sa;
entry_t *entry;
@@ -129,27 +159,31 @@ static bool remove_include(private_unity_handler_t *this, chunk_t subnet)
{
return FALSE;
}
ts = create_ts(subnet);
if (!ts)
list = parse_subnets(data);
if (!list)
{
return FALSE;
}
this->mutex->lock(this->mutex);
enumerator = this->include->create_enumerator(this->include);
while (enumerator->enumerate(enumerator, &entry))
while (list->remove_first(list, (void**)&ts) == SUCCESS)
{
if (entry->sa == ike_sa->get_unique_id(ike_sa) &&
ts->equals(ts, entry->ts))
enumerator = this->include->create_enumerator(this->include);
while (enumerator->enumerate(enumerator, &entry))
{
this->include->remove_at(this->include, enumerator);
entry_destroy(entry);
break;
if (entry->sa == ike_sa->get_unique_id(ike_sa) &&
ts->equals(ts, entry->ts))
{
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);
ts->destroy(ts);
list->destroy(list);
return TRUE;
}
@@ -212,9 +246,10 @@ static job_requeue_t add_exclude_async(entry_t *entry)
/**
* 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;
linked_list_t *list;
ike_sa_t *ike_sa;
entry_t *entry;
@@ -223,48 +258,60 @@ static bool add_exclude(private_unity_handler_t *this, chunk_t subnet)
{
return FALSE;
}
ts = create_ts(subnet);
if (!ts)
list = parse_subnets(data);
if (!list)
{
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.
* 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));
while (list->remove_first(list, (void**)&ts) == SUCCESS)
{
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.
* 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;
}
/**
* 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;
linked_list_t *list;
ike_sa_t *ike_sa;
char name[128];
bool success = TRUE;
ike_sa = charon->bus->get_sa(charon->bus);
if (!ike_sa)
{
return FALSE;
}
ts = create_ts(subnet);
if (!ts)
list = parse_subnets(data);
if (!list)
{
return FALSE;
}
create_shunt_name(ike_sa, ts, name, sizeof(name));
DBG1(DBG_IKE, "uninstalling %N bypass policy for %R",
configuration_attribute_type_names, UNITY_LOCAL_LAN, ts);
ts->destroy(ts);
return charon->shunts->uninstall(charon->shunts, name);
while (list->remove_first(list, (void**)&ts) == SUCCESS)
{
create_shunt_name(ike_sa, ts, name, sizeof(name));
DBG1(DBG_IKE, "uninstalling %N bypass policy for %R",
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,