eap-radius: Forward UNITY_SPLIT_INCLUDE or UNITY_LOCAL_LAN attributes

Depending on the value of the CVPN3000-IPSec-Split-Tunneling-Policy(55)
radius attribute, the subnets in the CVPN3000-IPSec-Split-Tunnel-List(27)
attribute are sent in either a UNITY_SPLIT_INCLUDE (if the value is 1)
or a UNITY_LOCAL_LAN (if the value is 2).

So if the following attributes would be configured for a RADIUS user

  CVPN3000-IPSec-Split-Tunnel-List := "10.0.1.0/255.255.255.0,10.0.2.0/255.255.255.0"
  CVPN3000-IPSec-Split-Tunneling-Policy := 1

A UNITY_SPLIT_INCLUDE configuration payload containing these two subnets
would be sent to the client during the ModeCfg exchange.
This commit is contained in:
Tobias Brunner 2013-08-16 15:25:33 +02:00
parent 66229619cf
commit 1a809e46f8
1 changed files with 93 additions and 0 deletions

View File

@ -21,6 +21,7 @@
#include <radius_message.h>
#include <radius_client.h>
#include <bio/bio_writer.h>
#include <daemon.h>
@ -412,6 +413,64 @@ static void add_unity_attribute(eap_radius_provider_t *provider, u_int32_t id,
}
}
/**
* Add a UNITY_LOCAL_LAN or UNITY_SPLIT_INCLUDE attribute
*/
static void add_unity_split_attribute(eap_radius_provider_t *provider,
u_int32_t id, configuration_attribute_type_t type,
chunk_t data)
{
enumerator_t *enumerator;
bio_writer_t *writer;
char buffer[256], *token, *slash;
if (snprintf(buffer, sizeof(buffer), "%.*s", (int)data.len,
data.ptr) >= sizeof(buffer))
{
return;
}
writer = bio_writer_create(16); /* two IPv4 addresses and 6 bytes padding */
enumerator = enumerator_create_token(buffer, ",", " ");
while (enumerator->enumerate(enumerator, &token))
{
host_t *net, *mask = NULL;
chunk_t padding;
slash = strchr(token, '/');
if (slash)
{
*slash++ = '\0';
mask = host_create_from_string(slash, 0);
}
if (!mask)
{ /* default to /32 */
mask = host_create_from_string("255.255.255.255", 0);
}
net = host_create_from_string(token, 0);
if (!net || net->get_family(net) != AF_INET ||
mask->get_family(mask) != AF_INET)
{
mask->destroy(mask);
DESTROY_IF(net);
continue;
}
writer->write_data(writer, net->get_address(net));
writer->write_data(writer, mask->get_address(mask));
padding = writer->skip(writer, 6); /* 6 bytes pdding */
memset(padding.ptr, 0, padding.len);
mask->destroy(mask);
net->destroy(net);
}
enumerator->destroy(enumerator);
data = writer->get_buf(writer);
if (data.len)
{
provider->add_attribute(provider, id, type, data);
}
writer->destroy(writer);
}
/**
* Handle Framed-IP-Address and other IKE configuration attributes
*/
@ -422,6 +481,7 @@ static void process_cfg_attributes(radius_message_t *msg)
ike_sa_t *ike_sa;
host_t *host;
chunk_t data;
configuration_attribute_type_t split_type = 0;
int type, vendor;
ike_sa = charon->bus->get_sa(charon->bus);
@ -460,12 +520,45 @@ static void process_cfg_attributes(radius_message_t *msg)
ike_sa->get_unique_id(ike_sa), type, data);
}
break;
case 55: /* CVPN3000-IPSec-Split-Tunneling-Policy */
if (data.len)
{
switch (data.ptr[data.len - 1])
{
case 0: /* tunnelall */
default:
break;
case 1: /* tunnelspecified */
split_type = UNITY_SPLIT_INCLUDE;
break;
case 2: /* excludespecified */
split_type = UNITY_LOCAL_LAN;
break;
}
}
break;
default:
break;
}
}
}
enumerator->destroy(enumerator);
if (split_type != 0 &&
ike_sa->supports_extension(ike_sa, EXT_CISCO_UNITY))
{
enumerator = msg->create_vendor_enumerator(msg);
while (enumerator->enumerate(enumerator, &vendor, &type, &data))
{
if (vendor == PEN_ALTIGA /* aka Cisco VPN3000 */ &&
type == 27 /* CVPN3000-IPSec-Split-Tunnel-List */)
{
add_unity_split_attribute(provider,
ike_sa->get_unique_id(ike_sa), split_type, data);
}
}
enumerator->destroy(enumerator);
}
}
}