diff options
author | Andreas Steffen <andreas.steffen@strongswan.org> | 2009-12-21 21:28:45 +0100 |
---|---|---|
committer | Andreas Steffen <andreas.steffen@strongswan.org> | 2009-12-21 21:29:01 +0100 |
commit | 157125e4c935b6f477fb78091d623d85700fc319 (patch) | |
tree | 8309f1412ecfd18d40bba4c6d4f9c91ea360997d /src | |
parent | 2fcb2cc65348f90353dca1ef0e7695e78801c2f1 (diff) | |
download | strongswan-157125e4c935b6f477fb78091d623d85700fc319.tar.bz2 strongswan-157125e4c935b6f477fb78091d623d85700fc319.tar.xz |
traffic_selector supports RFC 3779 address range format
Diffstat (limited to 'src')
-rw-r--r-- | src/libstrongswan/plugins/x509/x509_cert.c | 82 | ||||
-rw-r--r-- | src/libstrongswan/selectors/traffic_selector.c | 139 | ||||
-rw-r--r-- | src/libstrongswan/selectors/traffic_selector.h | 15 |
3 files changed, 190 insertions, 46 deletions
diff --git a/src/libstrongswan/plugins/x509/x509_cert.c b/src/libstrongswan/plugins/x509/x509_cert.c index f2f7db4dc..74a2967f0 100644 --- a/src/libstrongswan/plugins/x509/x509_cert.c +++ b/src/libstrongswan/plugins/x509/x509_cert.c @@ -688,19 +688,60 @@ static const asn1Object_t ipAddrBlocksObjects[] = { { 0, "end loop", ASN1_EOC, ASN1_END }, /* 13 */ { 0, "exit", ASN1_EOC, ASN1_EXIT } }; -#define IP_ADDR_BLOCKS_FAMILY 2 -#define IP_ADDR_BLOCKS_INHERIT 3 -#define IP_ADDR_BLOCKS_PREFIX 6 -#define IP_ADDR_BLOCKS_MIN 9 -#define IP_ADDR_BLOCKS_MAX 10 +#define IP_ADDR_BLOCKS_FAMILY 2 +#define IP_ADDR_BLOCKS_INHERIT 3 +#define IP_ADDR_BLOCKS_PREFIX 6 +#define IP_ADDR_BLOCKS_MIN 9 +#define IP_ADDR_BLOCKS_MAX 10 + +static bool check_address_object(ts_type_t ts_type, chunk_t object) +{ + switch (ts_type) + { + case TS_IPV4_ADDR_RANGE: + if (object.len > 5) + { + DBG1("IPv4 address object is larger than 5 octets"); + return FALSE; + } + break; + case TS_IPV6_ADDR_RANGE: + if (object.len > 17) + { + DBG1("IPv6 address object is larger than 17 octets"); + return FALSE; + } + break; + default: + DBG1("unknown address family"); + return FALSE; + } + if (object.len == 0) + { + DBG1("An ASN.1 bit string must contain at least the initial octet"); + return FALSE; + } + if (object.len == 1 && object.ptr[0] != 0) + { + DBG1("An empty ASN.1 bit string must contain a zero initial octet"); + return FALSE; + } + if (object.ptr[0] > 7) + { + DBG1("number of unused bits is too large"); + return FALSE; + } + return TRUE; +} static void parse_ipAddrBlocks(chunk_t blob, int level0, private_x509_cert_t *this) { asn1_parser_t *parser; - chunk_t object; - int objectID; + chunk_t object, min_object; ts_type_t ts_type; + traffic_selector_t *ts; + int objectID; parser = asn1_parser_create(ipAddrBlocksObjects, blob); parser->set_top_level(parser, level0); @@ -721,6 +762,10 @@ static void parse_ipAddrBlocks(chunk_t blob, int level0, { ts_type = TS_IPV6_ADDR_RANGE; } + else + { + break; + } DBG2(" %N", ts_type_name, ts_type); } break; @@ -728,15 +773,38 @@ static void parse_ipAddrBlocks(chunk_t blob, int level0, DBG1("inherit choice is not supported"); break; case IP_ADDR_BLOCKS_PREFIX: + if (!check_address_object(ts_type, object)) + { + goto end; + } + ts = traffic_selector_create_from_rfc3779_format(ts_type, + object, object); + DBG2(" %R", ts); + this->ipAddrBlocks->insert_last(this->ipAddrBlocks, ts); break; case IP_ADDR_BLOCKS_MIN: + if (!check_address_object(ts_type, object)) + { + goto end; + } + min_object = object; break; case IP_ADDR_BLOCKS_MAX: + if (!check_address_object(ts_type, object)) + { + goto end; + } + ts = traffic_selector_create_from_rfc3779_format(ts_type, + min_object, object); + DBG2(" %R", ts); + this->ipAddrBlocks->insert_last(this->ipAddrBlocks, ts); break; default: break; } } + +end: parser->destroy(parser); } diff --git a/src/libstrongswan/selectors/traffic_selector.c b/src/libstrongswan/selectors/traffic_selector.c index ef463e2a0..aa762e985 100644 --- a/src/libstrongswan/selectors/traffic_selector.c +++ b/src/libstrongswan/selectors/traffic_selector.c @@ -25,6 +25,8 @@ #include <utils/linked_list.h> #include <utils/identification.h> +#define NON_SUBNET_ADDRESS_RANGE 255 + ENUM(ts_type_name, TS_IPV4_ADDR_RANGE, TS_IPV6_ADDR_RANGE, "TS_IPV4_ADDR_RANGE", "TS_IPV6_ADDR_RANGE", @@ -59,6 +61,11 @@ struct private_traffic_selector_t { bool dynamic; /** + * subnet size in CIDR notation, 255 means a non-subnet address range + */ + u_int8_t netbits; + + /** * begin of address range, network order */ union { @@ -94,17 +101,19 @@ struct private_traffic_selector_t { }; /** - * calculate to "to"-address for the "from" address and a subnet size + * calculate the "to"-address for the "from" address and a subnet size */ static void calc_range(private_traffic_selector_t *this, u_int8_t netbits) { int byte; size_t size = (this->type == TS_IPV4_ADDR_RANGE) ? 4 : 16; + this->netbits = netbits; + /* go through the from address, starting at the tail. While we * have not processed the bits belonging to the host, set them to 1 on * the to address. If we reach the bits for the net, copy them from "from". */ - for (byte = size - 1; byte >=0; byte--) + for (byte = size - 1; byte >= 0; byte--) { u_char mask = 0x00; int shift; @@ -124,28 +133,50 @@ static void calc_range(private_traffic_selector_t *this, u_int8_t netbits) } /** - * calculate to subnet size from "to"- and "from"-address + * calculate the subnet size from the "to" and "from" addresses */ static u_int8_t calc_netbits(private_traffic_selector_t *this) { int byte, bit; + u_int8_t netbits; size_t size = (this->type == TS_IPV4_ADDR_RANGE) ? 4 : 16; + bool prefix = TRUE; + + /* a perfect match results in a single address with a /32 or /128 netmask */ + netbits = (size * 8); + this->netbits = netbits; - /* go trough all bits of the addresses, beginning in the front. + /* go through all bits of the addresses, beginning in the front. * as long as they are equal, the subnet gets larger */ for (byte = 0; byte < size; byte++) { for (bit = 7; bit >= 0; bit--) { - if ((1<<bit & this->from[byte]) != (1<<bit & this->to[byte])) + u_int8_t bitmask = 1 << bit; + + if (prefix) { - return ((7 - bit) + (byte * 8)); + if ((bitmask & this->from[byte]) != (bitmask & this->to[byte])) + { + /* store the common prefix which might be a true subnet */ + netbits = (7 - bit) + (byte * 8); + this->netbits = netbits; + prefix = FALSE; + } } + else + { + if ((bitmask & this->from[byte]) || !(bitmask & this->to[byte])) + { + this->netbits = NON_SUBNET_ADDRESS_RANGE; + return netbits; /* return a pseudo subnet */ + + } + } } } - /* single host, netmask is 32/128 */ - return (size * 8); + return netbits; /* return a true subnet */ } /** @@ -162,9 +193,9 @@ int traffic_selector_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec private_traffic_selector_t *this = *((private_traffic_selector_t**)(args[0])); linked_list_t *list = *((linked_list_t**)(args[0])); iterator_t *iterator; - char addr_str[INET6_ADDRSTRLEN] = ""; + char from_str[INET6_ADDRSTRLEN] = ""; + char to_str[INET6_ADDRSTRLEN] = ""; char *serv_proto = NULL; - u_int8_t mask; bool has_proto; bool has_ports; size_t written = 0; @@ -199,14 +230,28 @@ int traffic_selector_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec { if (this->type == TS_IPV4_ADDR_RANGE) { - inet_ntop(AF_INET, &this->from4, addr_str, sizeof(addr_str)); + inet_ntop(AF_INET, &this->from4, from_str, sizeof(from_str)); + } + else + { + inet_ntop(AF_INET6, &this->from6, from_str, sizeof(from_str)); + } + if (this->netbits == NON_SUBNET_ADDRESS_RANGE) + { + if (this->type == TS_IPV4_ADDR_RANGE) + { + inet_ntop(AF_INET, &this->to4, to_str, sizeof(to_str)); + } + else + { + inet_ntop(AF_INET6, &this->to6, to_str, sizeof(to_str)); + } + written += print_in_hook(dst, len, "%s..%s", from_str, to_str); } else { - inet_ntop(AF_INET6, &this->from6, addr_str, sizeof(addr_str)); + written += print_in_hook(dst, len, "%s/%d", from_str, this->netbits); } - mask = calc_netbits(this); - written += print_in_hook(dst, len, "%s/%d", addr_str, mask); } /* check if we have protocol and/or port selectors */ @@ -333,7 +378,7 @@ static traffic_selector_t *get_subset(private_traffic_selector_t *this, private_ new_ts->dynamic = this->dynamic || other->dynamic; memcpy(new_ts->from, from, size); memcpy(new_ts->to, to, size); - + calc_netbits(new_ts); return &new_ts->public; } return NULL; @@ -568,22 +613,16 @@ static void to_subnet(private_traffic_selector_t *this, host_t **net, u_int8_t * switch (this->type) { case TS_IPV4_ADDR_RANGE: - { family = AF_INET; net_chunk.len = sizeof(this->from4); break; - } case TS_IPV6_ADDR_RANGE: - { family = AF_INET6; net_chunk.len = sizeof(this->from6); break; - } default: - { /* unreachable */ return; - } } net_chunk.ptr = malloc(net_chunk.len); @@ -618,22 +657,16 @@ static traffic_selector_t *clone_(private_traffic_selector_t *this) switch (clone->type) { case TS_IPV4_ADDR_RANGE: - { memcpy(clone->from4, this->from4, sizeof(this->from4)); memcpy(clone->to4, this->to4, sizeof(this->to4)); return &clone->public; - } case TS_IPV6_ADDR_RANGE: - { memcpy(clone->from6, this->from6, sizeof(this->from6)); memcpy(clone->to6, this->to6, sizeof(this->to6)); return &clone->public; - } default: - { /* unreachable */ return &clone->public; - } } } @@ -659,7 +692,6 @@ traffic_selector_t *traffic_selector_create_from_bytes(u_int8_t protocol, switch (type) { case TS_IPV4_ADDR_RANGE: - { if (from.len != 4 || to.len != 4) { free(this); @@ -668,9 +700,7 @@ traffic_selector_t *traffic_selector_create_from_bytes(u_int8_t protocol, memcpy(this->from4, from.ptr, from.len); memcpy(this->to4, to.ptr, to.len); break; - } case TS_IPV6_ADDR_RANGE: - { if (from.len != 16 || to.len != 16) { free(this); @@ -679,13 +709,49 @@ traffic_selector_t *traffic_selector_create_from_bytes(u_int8_t protocol, memcpy(this->from6, from.ptr, from.len); memcpy(this->to6, to.ptr, to.len); break; - } default: - { free(this); return NULL; - } } + calc_netbits(this); + return (&this->public); +} + +/* + * see header + */ +traffic_selector_t *traffic_selector_create_from_rfc3779_format(ts_type_t type, + chunk_t from, chunk_t to) +{ + size_t len; + private_traffic_selector_t *this = traffic_selector_create(0, type, 0, 65535); + + switch (type) + { + case TS_IPV4_ADDR_RANGE: + len = 4; + break; + case TS_IPV6_ADDR_RANGE: + len = 16; + break; + default: + free(this); + return NULL; + } + memset(this->from, 0x00, len); + memset(this->to , 0xff, len); + + if (from.len > 1) + { + memcpy(this->from, from.ptr+1, from.len-1); + } + if (to.len > 1) + { + memcpy(this->to, to.ptr+1, to.len-1); + this->to[to.len-2] |= to.ptr[0] ? (1 << to.ptr[0]) - 1 : 0; + } + this->netbits = chunk_equals(from, to) ? (from.len-1)*8 - from.ptr[0] + : NON_SUBNET_ADDRESS_RANGE; return (&this->public); } @@ -710,6 +776,7 @@ traffic_selector_t *traffic_selector_create_from_subnet(host_t *net, { /* use /0 for 0.0.0.0 */ this->to4[0] = ~0; + this->netbits = 0; } else { @@ -732,6 +799,7 @@ traffic_selector_t *traffic_selector_create_from_subnet(host_t *net, this->to6[1] = ~0; this->to6[2] = ~0; this->to6[3] = ~0; + this->netbits = 0; } else { @@ -769,7 +837,6 @@ traffic_selector_t *traffic_selector_create_from_string( switch (type) { case TS_IPV4_ADDR_RANGE: - { if (inet_pton(AF_INET, from_addr, (struct in_addr*)this->from4) < 0) { free(this); @@ -781,9 +848,7 @@ traffic_selector_t *traffic_selector_create_from_string( return NULL; } break; - } case TS_IPV6_ADDR_RANGE: - { if (inet_pton(AF_INET6, from_addr, (struct in6_addr*)this->from6) < 0) { free(this); @@ -795,8 +860,8 @@ traffic_selector_t *traffic_selector_create_from_string( return NULL; } break; - } } + calc_netbits(this); return (&this->public); } diff --git a/src/libstrongswan/selectors/traffic_selector.h b/src/libstrongswan/selectors/traffic_selector.h index 900212ddf..b5964b541 100644 --- a/src/libstrongswan/selectors/traffic_selector.h +++ b/src/libstrongswan/selectors/traffic_selector.h @@ -239,9 +239,9 @@ traffic_selector_t *traffic_selector_create_from_string( * * @param protocol protocol for this ts, such as TCP or UDP * @param type type of following addresses, such as TS_IPV4_ADDR_RANGE - * @param from_address start of address range, network order + * @param from_addr start of address range, network order * @param from_port port number, host order - * @param to_address end of address range, network order + * @param to_addr end of address range, network order * @param to_port port number, host order * @return traffic_selector_t object */ @@ -251,6 +251,17 @@ traffic_selector_t *traffic_selector_create_from_bytes( chunk_t to_address, u_int16_t to_port); /** + * Create a new traffic selector using the RFC 3779 ASN.1 min/max address format + * + * @param type type of following addresses, such as TS_IPV4_ADDR_RANGE + * @param from_addr start of address range in RFC 3779 ASN.1 BIT STRING format + * @param to_addr end of address range in RFC 3779 ASN.1 BIT STRING format + * @return traffic_selector_t object + */ +traffic_selector_t *traffic_selector_create_from_rfc3779_format(ts_type_t type, + chunk_t from_addr, chunk_t to_addr); + +/** * Create a new traffic selector defining a whole subnet. * * In most cases, definition of a traffic selector for full subnets |