diff options
Diffstat (limited to 'src/libcharon/config')
-rw-r--r-- | src/libcharon/config/backend_manager.c | 64 | ||||
-rw-r--r-- | src/libcharon/config/ike_cfg.c | 252 | ||||
-rw-r--r-- | src/libcharon/config/ike_cfg.h | 51 | ||||
-rw-r--r-- | src/libcharon/config/peer_cfg.c | 18 | ||||
-rw-r--r-- | src/libcharon/config/peer_cfg.h | 12 | ||||
-rw-r--r-- | src/libcharon/config/proposal.c | 39 |
6 files changed, 339 insertions, 97 deletions
diff --git a/src/libcharon/config/backend_manager.c b/src/libcharon/config/backend_manager.c index f47d5715a..79f1d9fee 100644 --- a/src/libcharon/config/backend_manager.c +++ b/src/libcharon/config/backend_manager.c @@ -84,10 +84,8 @@ static enumerator_t *ike_enum_create(backend_t *backend, ike_data_t *data) static ike_cfg_match_t get_ike_match(ike_cfg_t *cand, host_t *me, host_t *other, ike_version_t version) { - host_t *me_cand, *other_cand; - char *my_addr, *other_addr; - bool my_allow_any, other_allow_any; ike_cfg_match_t match = MATCH_NONE; + int quality; if (cand->get_version(cand) != IKE_ANY && version != cand->get_version(cand)) @@ -97,26 +95,12 @@ static ike_cfg_match_t get_ike_match(ike_cfg_t *cand, host_t *me, host_t *other, if (me) { - my_addr = cand->get_my_addr(cand, &my_allow_any); - me_cand = host_create_from_dns(my_addr, me->get_family(me), 0); - if (!me_cand) - { - return MATCH_NONE; - } - if (me_cand->ip_equals(me_cand, me)) - { - match += MATCH_ME; - } - else if (my_allow_any || me_cand->is_anyaddr(me_cand)) - { - match += MATCH_ANY; - } - else + quality = cand->match_me(cand, me); + if (!quality) { - me_cand->destroy(me_cand); return MATCH_NONE; } - me_cand->destroy(me_cand); + match += quality * MATCH_ME; } else { @@ -125,26 +109,12 @@ static ike_cfg_match_t get_ike_match(ike_cfg_t *cand, host_t *me, host_t *other, if (other) { - other_addr = cand->get_other_addr(cand, &other_allow_any); - other_cand = host_create_from_dns(other_addr, other->get_family(other), 0); - if (!other_cand) + quality = cand->match_other(cand, other); + if (!quality) { return MATCH_NONE; } - if (other_cand->ip_equals(other_cand, other)) - { - match += MATCH_OTHER; - } - else if (other_allow_any || other_cand->is_anyaddr(other_cand)) - { - match += MATCH_ANY; - } - else - { - other_cand->destroy(other_cand); - return MATCH_NONE; - } - other_cand->destroy(other_cand); + match += quality * MATCH_OTHER; } else { @@ -165,7 +135,6 @@ METHOD(backend_manager_t, get_ike_cfg, ike_cfg_t*, { ike_cfg_t *current, *found = NULL; char *my_addr, *other_addr; - bool my_allow_any, other_allow_any; enumerator_t *enumerator; ike_cfg_match_t match, best = MATCH_ANY; ike_data_t *data; @@ -189,11 +158,10 @@ METHOD(backend_manager_t, get_ike_cfg, ike_cfg_t*, match, me, other, ike_version_names, version); if (match) { - my_addr = current->get_my_addr(current, &my_allow_any); - other_addr = current->get_other_addr(current, &other_allow_any); - DBG2(DBG_CFG, " candidate: %s%s...%s%s, prio %d", - my_allow_any ? "%":"", my_addr, - other_allow_any ? "%":"", other_addr, match); + my_addr = current->get_my_addr(current); + other_addr = current->get_other_addr(current); + DBG2(DBG_CFG, " candidate: %s...%s, prio %d", + my_addr, other_addr, match); if (match > best) { DESTROY_IF(found); @@ -207,11 +175,10 @@ METHOD(backend_manager_t, get_ike_cfg, ike_cfg_t*, this->lock->unlock(this->lock); if (found) { - my_addr = found->get_my_addr(found, &my_allow_any); - other_addr = found->get_other_addr(found, &other_allow_any); - DBG2(DBG_CFG, "found matching ike config: %s%s...%s%s with prio %d", - my_allow_any ? "%":"", my_addr, - other_allow_any ? "%":"", other_addr, best); + my_addr = found->get_my_addr(found); + other_addr = found->get_other_addr(found); + DBG2(DBG_CFG, "found matching ike config: %s...%s with prio %d", + my_addr, other_addr, best); } return found; } @@ -481,4 +448,3 @@ backend_manager_t *backend_manager_create() return &this->public; } - diff --git a/src/libcharon/config/ike_cfg.c b/src/libcharon/config/ike_cfg.c index 54a054e40..cb6f6ca0e 100644 --- a/src/libcharon/config/ike_cfg.c +++ b/src/libcharon/config/ike_cfg.c @@ -50,24 +50,34 @@ struct private_ike_cfg_t { ike_version_t version; /** - * Address of local host + * Address list string for local host */ char *me; /** - * Address of remote host + * Address list string for remote host */ char *other; /** - * Allow override of local address + * Local single host or DNS names, as allocated char* */ - bool my_allow_any; + linked_list_t *my_hosts; /** - * Allow override of remote address + * Remote single host or DNS names, as allocated char* */ - bool other_allow_any; + linked_list_t *other_hosts; + + /** + * Local ranges/subnets this config matches to, as traffic_selector_t* + */ + linked_list_t *my_ranges; + + /** + * Remote ranges/subnets this config matches to, as traffic_selector_t* + */ + linked_list_t *other_ranges; /** * our source port @@ -129,23 +139,124 @@ METHOD(ike_cfg_t, fragmentation, fragmentation_t, return this->fragmentation; } -METHOD(ike_cfg_t, get_my_addr, char*, - private_ike_cfg_t *this, bool *allow_any) +/** + * Common function for resolve_me/other + */ +static host_t* resolve(linked_list_t *hosts, int family, u_int16_t port) { - if (allow_any) + enumerator_t *enumerator; + host_t *host = NULL; + bool tried = FALSE; + char *str; + + enumerator = hosts->create_enumerator(hosts); + while (enumerator->enumerate(enumerator, &str)) + { + host = host_create_from_dns(str, family, port); + if (host) + { + break; + } + tried = TRUE; + } + enumerator->destroy(enumerator); + + if (!host && !tried) { - *allow_any = this->my_allow_any; + /* we have no single host configured, return %any */ + host = host_create_any(family ?: AF_INET); + host->set_port(host, port); } - return this->me; + return host; } -METHOD(ike_cfg_t, get_other_addr, char*, - private_ike_cfg_t *this, bool *allow_any) +METHOD(ike_cfg_t, resolve_me, host_t*, + private_ike_cfg_t *this, int family) +{ + return resolve(this->my_hosts, family, this->my_port); +} + +METHOD(ike_cfg_t, resolve_other, host_t*, + private_ike_cfg_t *this, int family) +{ + return resolve(this->other_hosts, family, this->other_port); +} + +/** + * Common function for match_me/other + */ +static u_int match(linked_list_t *hosts, linked_list_t *ranges, host_t *cand) { - if (allow_any) + enumerator_t *enumerator; + traffic_selector_t *ts; + char *str; + host_t *host; + u_int8_t mask; + u_int quality = 0; + + /* try single hosts first */ + enumerator = hosts->create_enumerator(hosts); + while (enumerator->enumerate(enumerator, &str)) + { + host = host_create_from_dns(str, cand->get_family(cand), 0); + if (host) + { + if (host->ip_equals(host, cand)) + { + quality = max(quality, 128 + 1); + } + if (host->is_anyaddr(host)) + { + quality = max(quality, 1); + } + host->destroy(host); + } + } + enumerator->destroy(enumerator); + + /* then ranges/subnets */ + enumerator = ranges->create_enumerator(ranges); + while (enumerator->enumerate(enumerator, &ts)) { - *allow_any = this->other_allow_any; + if (ts->includes(ts, cand)) + { + if (ts->to_subnet(ts, &host, &mask)) + { + quality = max(quality, mask + 1); + host->destroy(host); + } + else + { + quality = max(quality, 1); + } + } } + enumerator->destroy(enumerator); + + return quality; +} + +METHOD(ike_cfg_t, match_me, u_int, + private_ike_cfg_t *this, host_t *host) +{ + return match(this->my_hosts, this->my_ranges, host); +} + +METHOD(ike_cfg_t, match_other, u_int, + private_ike_cfg_t *this, host_t *host) +{ + return match(this->other_hosts, this->other_ranges, host); +} + +METHOD(ike_cfg_t, get_my_addr, char*, + private_ike_cfg_t *this) +{ + return this->me; +} + +METHOD(ike_cfg_t, get_other_addr, char*, + private_ike_cfg_t *this) +{ return this->other; } @@ -313,16 +424,110 @@ METHOD(ike_cfg_t, destroy, void, offsetof(proposal_t, destroy)); free(this->me); free(this->other); + this->my_hosts->destroy_function(this->my_hosts, free); + this->other_hosts->destroy_function(this->other_hosts, free); + this->my_ranges->destroy_offset(this->my_ranges, + offsetof(traffic_selector_t, destroy)); + this->other_ranges->destroy_offset(this->other_ranges, + offsetof(traffic_selector_t, destroy)); free(this); } } /** + * Try to parse a string as subnet + */ +static traffic_selector_t* make_subnet(char *str) +{ + char *pos; + + pos = strchr(str, '/'); + if (!pos) + { + return NULL; + } + return traffic_selector_create_from_cidr(str, 0, 0, 0); +} + +/** + * Try to parse a string as an IP range + */ +static traffic_selector_t* make_range(char *str) +{ + traffic_selector_t *ts; + ts_type_t type; + char *pos; + host_t *from, *to; + + pos = strchr(str, '-'); + if (!pos) + { + return NULL; + } + to = host_create_from_string(pos + 1, 0); + if (!to) + { + return NULL; + } + str = strndup(str, pos - str); + from = host_create_from_string_and_family(str, to->get_family(to), 0); + free(str); + if (!from) + { + to->destroy(to); + return NULL; + } + if (to->get_family(to) == AF_INET) + { + type = TS_IPV4_ADDR_RANGE; + } + else + { + type = TS_IPV6_ADDR_RANGE; + } + ts = traffic_selector_create_from_bytes(0, type, + from->get_address(from), 0, + to->get_address(to), 0); + from->destroy(from); + to->destroy(to); + return ts; +} + +/** + * Parse address string into lists of single hosts and ranges/subnets + */ +static void parse_addresses(char *str, linked_list_t *hosts, + linked_list_t *ranges) +{ + enumerator_t *enumerator; + traffic_selector_t *ts; + + enumerator = enumerator_create_token(str, ",", " "); + while (enumerator->enumerate(enumerator, &str)) + { + ts = make_subnet(str); + if (ts) + { + ranges->insert_last(ranges, ts); + continue; + } + ts = make_range(str); + if (ts) + { + ranges->insert_last(ranges, ts); + continue; + } + hosts->insert_last(hosts, strdup(str)); + } + enumerator->destroy(enumerator); +} + +/** * Described in header. */ ike_cfg_t *ike_cfg_create(ike_version_t version, bool certreq, bool force_encap, - char *me, bool my_allow_any, u_int16_t my_port, - char *other, bool other_allow_any, u_int16_t other_port, + char *me, u_int16_t my_port, + char *other, u_int16_t other_port, fragmentation_t fragmentation, u_int8_t dscp) { private_ike_cfg_t *this; @@ -333,6 +538,10 @@ ike_cfg_t *ike_cfg_create(ike_version_t version, bool certreq, bool force_encap, .send_certreq = _send_certreq, .force_encap = _force_encap_, .fragmentation = _fragmentation, + .resolve_me = _resolve_me, + .resolve_other = _resolve_other, + .match_me = _match_me, + .match_other = _match_other, .get_my_addr = _get_my_addr, .get_other_addr = _get_other_addr, .get_my_port = _get_my_port, @@ -352,14 +561,19 @@ ike_cfg_t *ike_cfg_create(ike_version_t version, bool certreq, bool force_encap, .force_encap = force_encap, .fragmentation = fragmentation, .me = strdup(me), + .my_ranges = linked_list_create(), + .my_hosts = linked_list_create(), .other = strdup(other), - .my_allow_any = my_allow_any, - .other_allow_any = other_allow_any, + .other_ranges = linked_list_create(), + .other_hosts = linked_list_create(), .my_port = my_port, .other_port = other_port, .dscp = dscp, .proposals = linked_list_create(), ); + parse_addresses(me, this->my_hosts, this->my_ranges); + parse_addresses(other, this->other_hosts, this->other_ranges); + return &this->public; } diff --git a/src/libcharon/config/ike_cfg.h b/src/libcharon/config/ike_cfg.h index 719ceb9dd..f9e4fbebc 100644 --- a/src/libcharon/config/ike_cfg.h +++ b/src/libcharon/config/ike_cfg.h @@ -78,20 +78,50 @@ struct ike_cfg_t { ike_version_t (*get_version)(ike_cfg_t *this); /** + * Resolve the local address to use for initiation. + * + * @param family address family to prefer, or AF_UNSPEC + * @return resolved host, NULL on error + */ + host_t* (*resolve_me)(ike_cfg_t *this, int family); + + /** + * Resolve the remote address to use for initiation. + * + * @param family address family to prefer, or AF_UNSPEC + * @return resolved host, NULL on error + */ + host_t* (*resolve_other)(ike_cfg_t *this, int family); + + /** + * Check how good a host matches to the configured local address. + * + * @param host host to check match quality + * @return quality of the match, 0 if not matching at all + */ + u_int (*match_me)(ike_cfg_t *this, host_t *host); + + /** + * Check how good a host matches to the configured remote address. + * + * @param host host to check match quality + * @return quality of the match, 0 if not matching at all + */ + u_int (*match_other)(ike_cfg_t *this, host_t *host); + + /** * Get own address. * - * @param allow_any allow any address to match * @return string of address/DNS name */ - char* (*get_my_addr) (ike_cfg_t *this, bool *allow_any); + char* (*get_my_addr) (ike_cfg_t *this); /** * Get peer's address. * - * @param allow_any allow any address to match * @return string of address/DNS name */ - char* (*get_other_addr) (ike_cfg_t *this, bool *allow_any); + char* (*get_other_addr) (ike_cfg_t *this); /** * Get the port to use as our source port. @@ -200,24 +230,27 @@ struct ike_cfg_t { /** * Creates a ike_cfg_t object. * - * Supplied hosts become owned by ike_cfg, the name gets cloned. + * Supplied hosts become owned by ike_cfg, strings get cloned. + * + * me and other are comma separated lists of IP addresses, DNS names, IP ranges + * or subnets. When initiating, the first non-range/subnet address is used + * as address. When responding, a match is performed against all items in the + * list. * * @param version IKE major version to use for this config * @param certreq TRUE to send a certificate request * @param force_encap enforce UDP encapsulation by faking NATD notify * @param me address/DNS name of local peer - * @param my_allow_any allow override of local address by any address * @param my_port IKE port to use as source, 500 uses IKEv2 port floating * @param other address/DNS name of remote peer - * @param other_allow_any allow override of remote address by any address * @param other_port IKE port to use as dest, 500 uses IKEv2 port floating * @param fragmentation use IKEv1 fragmentation * @param dscp DSCP value to send IKE packets with * @return ike_cfg_t object. */ ike_cfg_t *ike_cfg_create(ike_version_t version, bool certreq, bool force_encap, - char *me, bool my_allow_any, u_int16_t my_port, - char *other, bool other_allow_any, u_int16_t other_port, + char *me, u_int16_t my_port, + char *other, u_int16_t other_port, fragmentation_t fragmentation, u_int8_t dscp); #endif /** IKE_CFG_H_ @}*/ diff --git a/src/libcharon/config/peer_cfg.c b/src/libcharon/config/peer_cfg.c index eb983199b..d198503d0 100644 --- a/src/libcharon/config/peer_cfg.c +++ b/src/libcharon/config/peer_cfg.c @@ -100,6 +100,11 @@ struct private_peer_cfg_t { bool aggressive; /** + * Use pull or push in mode config? + */ + bool pull_mode; + + /** * Time before starting rekeying */ u_int32_t rekey_time; @@ -390,6 +395,12 @@ METHOD(peer_cfg_t, use_aggressive, bool, return this->aggressive; } +METHOD(peer_cfg_t, use_pull_mode, bool, + private_peer_cfg_t *this) +{ + return this->pull_mode; +} + METHOD(peer_cfg_t, get_dpd, u_int32_t, private_peer_cfg_t *this) { @@ -588,6 +599,7 @@ METHOD(peer_cfg_t, equals, bool, this->over_time == other->over_time && this->dpd == other->dpd && this->aggressive == other->aggressive && + this->pull_mode == other->pull_mode && auth_cfg_equal(this, other) #ifdef ME && this->mediation == other->mediation && @@ -638,8 +650,8 @@ peer_cfg_t *peer_cfg_create(char *name, unique_policy_t unique, u_int32_t keyingtries, u_int32_t rekey_time, u_int32_t reauth_time, u_int32_t jitter_time, u_int32_t over_time, - bool mobike, bool aggressive, u_int32_t dpd, - u_int32_t dpd_timeout, + bool mobike, bool aggressive, bool pull_mode, + u_int32_t dpd, u_int32_t dpd_timeout, bool mediation, peer_cfg_t *mediated_by, identification_t *peer_id) { @@ -671,6 +683,7 @@ peer_cfg_t *peer_cfg_create(char *name, .get_over_time = _get_over_time, .use_mobike = _use_mobike, .use_aggressive = _use_aggressive, + .use_pull_mode = _use_pull_mode, .get_dpd = _get_dpd, .get_dpd_timeout = _get_dpd_timeout, .add_virtual_ip = _add_virtual_ip, @@ -701,6 +714,7 @@ peer_cfg_t *peer_cfg_create(char *name, .over_time = over_time, .use_mobike = mobike, .aggressive = aggressive, + .pull_mode = pull_mode, .dpd = dpd, .dpd_timeout = dpd_timeout, .vips = linked_list_create(), diff --git a/src/libcharon/config/peer_cfg.h b/src/libcharon/config/peer_cfg.h index e62e03ec5..3e780394a 100644 --- a/src/libcharon/config/peer_cfg.h +++ b/src/libcharon/config/peer_cfg.h @@ -248,6 +248,13 @@ struct peer_cfg_t { bool (*use_aggressive)(peer_cfg_t *this); /** + * Use pull or push mode for mode config? + * + * @return TRUE to use pull, FALSE to use push mode + */ + bool (*use_pull_mode)(peer_cfg_t *this); + + /** * Get the DPD check interval. * * @return dpd_delay in seconds @@ -366,6 +373,7 @@ struct peer_cfg_t { * @param over_time maximum overtime before closing a rekeying/reauth SA * @param mobike use MOBIKE (RFC4555) if peer supports it * @param aggressive use/accept aggressive mode with IKEv1 + * @param pull_mode TRUE to use modeconfig pull, FALSE for push * @param dpd DPD check interval, 0 to disable * @param dpd_timeout DPD timeout interval (IKEv1 only), if 0 default applies * @param mediation TRUE if this is a mediation connection @@ -378,8 +386,8 @@ peer_cfg_t *peer_cfg_create(char *name, unique_policy_t unique, u_int32_t keyingtries, u_int32_t rekey_time, u_int32_t reauth_time, u_int32_t jitter_time, u_int32_t over_time, - bool mobike, bool aggressive, u_int32_t dpd, - u_int32_t dpd_timeout, + bool mobike, bool aggressive, bool pull_mode, + u_int32_t dpd, u_int32_t dpd_timeout, bool mediation, peer_cfg_t *mediated_by, identification_t *peer_id); diff --git a/src/libcharon/config/proposal.c b/src/libcharon/config/proposal.c index 0b702e014..1f3f2ba8b 100644 --- a/src/libcharon/config/proposal.c +++ b/src/libcharon/config/proposal.c @@ -429,30 +429,33 @@ static void check_proposal(private_proposal_t *this) e->destroy(e); } - e = create_enumerator(this, ENCRYPTION_ALGORITHM); - while (e->enumerate(e, &alg, &ks)) + if (this->protocol == PROTO_ESP) { - if (!encryption_algorithm_is_aead(alg)) + e = create_enumerator(this, ENCRYPTION_ALGORITHM); + while (e->enumerate(e, &alg, &ks)) { - all_aead = FALSE; - break; + if (!encryption_algorithm_is_aead(alg)) + { + all_aead = FALSE; + break; + } } - } - e->destroy(e); + e->destroy(e); - if (all_aead) - { - /* if all encryption algorithms in the proposal are AEADs, - * we MUST NOT propose any integrity algorithms */ - e = array_create_enumerator(this->transforms); - while (e->enumerate(e, &entry)) + if (all_aead) { - if (entry->type == INTEGRITY_ALGORITHM) + /* if all encryption algorithms in the proposal are AEADs, + * we MUST NOT propose any integrity algorithms */ + e = array_create_enumerator(this->transforms); + while (e->enumerate(e, &entry)) { - array_remove_at(this->transforms, e); + if (entry->type == INTEGRITY_ALGORITHM) + { + array_remove_at(this->transforms, e); + } } + e->destroy(e); } - e->destroy(e); } if (this->protocol == PROTO_AH || this->protocol == PROTO_ESP) @@ -734,6 +737,10 @@ static void proposal_add_supported_ike(private_proposal_t *this) case MODP_2048_256: case ECP_192_BIT: case ECP_224_BIT: + case ECP_224_BP: + case ECP_256_BP: + case ECP_384_BP: + case ECP_512_BP: add_algorithm(this, DIFFIE_HELLMAN_GROUP, group, 0); break; default: |