diff options
Diffstat (limited to 'src/libcharon/config/backend_manager.c')
-rw-r--r-- | src/libcharon/config/backend_manager.c | 214 |
1 files changed, 159 insertions, 55 deletions
diff --git a/src/libcharon/config/backend_manager.c b/src/libcharon/config/backend_manager.c index 02a41a5b3..47f62d59a 100644 --- a/src/libcharon/config/backend_manager.c +++ b/src/libcharon/config/backend_manager.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2018 Tobias Brunner * Copyright (C) 2007-2009 Martin Willi * HSR Hochschule fuer Technik Rapperswil * @@ -129,15 +130,77 @@ static ike_cfg_match_t get_ike_match(ike_cfg_t *cand, host_t *me, host_t *other, return match; } -METHOD(backend_manager_t, get_ike_cfg, ike_cfg_t*, - private_backend_manager_t *this, host_t *me, host_t *other, - ike_version_t version) +/** + * list element to help sorting + */ +typedef struct { + ike_cfg_match_t match; + ike_cfg_t *cfg; +} ike_match_entry_t; + +CALLBACK(ike_enum_filter, bool, + linked_list_t *configs, enumerator_t *orig, va_list args) +{ + ike_match_entry_t *entry; + ike_cfg_t **out; + + VA_ARGS_VGET(args, out); + + if (orig->enumerate(orig, &entry)) + { + *out = entry->cfg; + return TRUE; + } + return FALSE; +} + +CALLBACK(ike_match_entry_list_destroy, void, + linked_list_t *configs) +{ + ike_match_entry_t *entry; + + while (configs->remove_last(configs, (void**)&entry) == SUCCESS) + { + entry->cfg->destroy(entry->cfg); + free(entry); + } + configs->destroy(configs); +} + +/** + * Insert entry into match-sorted list + */ +static void insert_sorted_ike(ike_match_entry_t *entry, linked_list_t *list) +{ + enumerator_t *enumerator; + ike_match_entry_t *current; + + enumerator = list->create_enumerator(list); + while (enumerator->enumerate(enumerator, ¤t)) + { + if (entry->match > current->match) + { + break; + } + } + list->insert_before(list, enumerator, entry); + enumerator->destroy(enumerator); +} + +/** + * Create a sorted list of all matching IKE configs + */ +static linked_list_t *get_matching_ike_cfgs(private_backend_manager_t *this, + host_t *me, host_t *other, + ike_version_t version) { - ike_cfg_t *current, *found = NULL; + ike_cfg_t *current; char *my_addr, *other_addr; enumerator_t *enumerator; - ike_cfg_match_t match, best = MATCH_ANY; ike_data_t *data; + linked_list_t *configs; + ike_cfg_match_t match; + ike_match_entry_t *entry; INIT(data, .this = this, @@ -145,44 +208,82 @@ METHOD(backend_manager_t, get_ike_cfg, ike_cfg_t*, .other = other, ); - DBG2(DBG_CFG, "looking for an ike config for %H...%H", me, other); + configs = linked_list_create(); this->lock->read_lock(this->lock); enumerator = enumerator_create_nested( this->backends->create_enumerator(this->backends), (void*)ike_enum_create, data, (void*)free); - while (enumerator->enumerate(enumerator, (void**)¤t)) + + while (enumerator->enumerate(enumerator, ¤t)) { + my_addr = current->get_my_addr(current); + other_addr = current->get_other_addr(current); match = get_ike_match(current, me, other, version); - DBG3(DBG_CFG, "ike config match: %d (%H %H %N)", - match, me, other, ike_version_names, version); + DBG3(DBG_CFG, "ike config match: %d (%s...%s %N)", match, my_addr, + other_addr, ike_version_names, current->get_version(current)); + if (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); - found = current; - found->get_ref(found); - best = match; - } + + INIT(entry, + .match = match, + .cfg = current->get_ref(current), + ); + insert_sorted_ike(entry, configs); } } enumerator->destroy(enumerator); this->lock->unlock(this->lock); - if (found) + + return configs; +} + +METHOD(backend_manager_t, get_ike_cfg, ike_cfg_t*, + private_backend_manager_t *this, host_t *me, host_t *other, + ike_version_t version) +{ + linked_list_t *configs; + ike_match_entry_t *entry; + ike_cfg_t *found = NULL; + char *my_addr, *other_addr; + + DBG2(DBG_CFG, "looking for an %N config for %H...%H", ike_version_names, + version, me, other); + + configs = get_matching_ike_cfgs(this, me, other, version); + if (configs->get_first(configs, (void**)&entry) == SUCCESS) { + found = entry->cfg->get_ref(entry->cfg); + 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); + my_addr, other_addr, entry->match); } + ike_match_entry_list_destroy(configs); + return found; } +METHOD(backend_manager_t, create_ike_cfg_enumerator, enumerator_t*, + private_backend_manager_t *this, host_t *me, host_t *other, + ike_version_t version) +{ + linked_list_t *configs; + + DBG2(DBG_CFG, "looking for %N configs for %H...%H", ike_version_names, + version, me, other); + + configs = get_matching_ike_cfgs(this, me, other, version); + + return enumerator_create_filter(configs->create_enumerator(configs), + ike_enum_filter, configs, + ike_match_entry_list_destroy); +} + /** * Get the best ID match in one of the configs auth_cfg */ @@ -198,7 +299,7 @@ static id_match_t get_peer_match(identification_t *id, if (!id) { - DBG3(DBG_CFG, "peer config match %s: %d (%N)", + DBG3(DBG_CFG, " %s id match: %d (%N)", where, ID_MATCH_ANY, id_type_names, ID_ANY); return ID_MATCH_ANY; } @@ -225,7 +326,7 @@ static id_match_t get_peer_match(identification_t *id, enumerator->destroy(enumerator); data = id->get_encoding(id); - DBG3(DBG_CFG, "peer config match %s: %d (%N -> %#B)", + DBG3(DBG_CFG, " %s id match: %d (%N: %#B)", where, match, id_type_names, id->get_type(id), &data); return match; } @@ -295,34 +396,26 @@ CALLBACK(peer_enum_filter_destroy, void, } /** - * Insert entry into match-sorted list, using helper + * Insert entry into match-sorted list */ -static void insert_sorted(match_entry_t *entry, linked_list_t *list, - linked_list_t *helper) +static void insert_sorted(match_entry_t *entry, linked_list_t *list) { + enumerator_t *enumerator; match_entry_t *current; - while (list->remove_first(list, (void**)¤t) == SUCCESS) - { - helper->insert_last(helper, current); - } - while (helper->remove_first(helper, (void**)¤t) == SUCCESS) + enumerator = list->create_enumerator(list); + while (enumerator->enumerate(enumerator, ¤t)) { - if (entry && ( - (entry->match_ike > current->match_ike && - entry->match_peer >= current->match_peer) || - (entry->match_ike >= current->match_ike && - entry->match_peer > current->match_peer))) + if ((entry->match_ike > current->match_ike && + entry->match_peer >= current->match_peer) || + (entry->match_ike >= current->match_ike && + entry->match_peer > current->match_peer)) { - list->insert_last(list, entry); - entry = NULL; + break; } - list->insert_last(list, current); - } - if (entry) - { - list->insert_last(list, entry); } + list->insert_before(list, enumerator, entry); + enumerator->destroy(enumerator); } METHOD(backend_manager_t, create_peer_cfg_enumerator, enumerator_t*, @@ -332,7 +425,7 @@ METHOD(backend_manager_t, create_peer_cfg_enumerator, enumerator_t*, enumerator_t *enumerator; peer_data_t *data; peer_cfg_t *cfg; - linked_list_t *configs, *helper; + linked_list_t *configs; INIT(data, .lock = this->lock, @@ -352,35 +445,46 @@ METHOD(backend_manager_t, create_peer_cfg_enumerator, enumerator_t*, } configs = linked_list_create(); - /* only once allocated helper list for sorting */ - helper = linked_list_create(); while (enumerator->enumerate(enumerator, &cfg)) { - id_match_t match_peer_me, match_peer_other; + ike_cfg_t *ike_cfg = cfg->get_ike_cfg(cfg); ike_cfg_match_t match_ike; + id_match_t match_peer_me, match_peer_other; match_entry_t *entry; + char *my_addr, *other_addr; + + match_ike = get_ike_match(ike_cfg, me, other, version); + my_addr = ike_cfg->get_my_addr(ike_cfg); + other_addr = ike_cfg->get_other_addr(ike_cfg); + DBG3(DBG_CFG, "peer config \"%s\", ike match: %d (%s...%s %N)", + cfg->get_name(cfg), match_ike, my_addr, other_addr, + ike_version_names, ike_cfg->get_version(ike_cfg)); + + if (!match_ike) + { + continue; + } match_peer_me = get_peer_match(my_id, cfg, TRUE); + if (!match_peer_me) + { + continue; + } match_peer_other = get_peer_match(other_id, cfg, FALSE); - match_ike = get_ike_match(cfg->get_ike_cfg(cfg), me, other, version); - DBG3(DBG_CFG, "ike config match: %d (%H %H %N)", - match_ike, me, other, ike_version_names, version); - if (match_peer_me && match_peer_other && match_ike) + if (match_peer_other) { DBG2(DBG_CFG, " candidate \"%s\", match: %d/%d/%d (me/other/ike)", cfg->get_name(cfg), match_peer_me, match_peer_other, match_ike); - INIT(entry, .match_peer = match_peer_me + match_peer_other, .match_ike = match_ike, .cfg = cfg->get_ref(cfg), ); - insert_sorted(entry, configs, helper); + insert_sorted(entry, configs); } } enumerator->destroy(enumerator); - helper->destroy(helper); return enumerator_create_filter(configs->create_enumerator(configs), peer_enum_filter, configs, @@ -430,8 +534,7 @@ METHOD(backend_manager_t, destroy, void, } /* - * Described in header-file - + * Described in header */ backend_manager_t *backend_manager_create() { @@ -440,6 +543,7 @@ backend_manager_t *backend_manager_create() INIT(this, .public = { .get_ike_cfg = _get_ike_cfg, + .create_ike_cfg_enumerator = _create_ike_cfg_enumerator, .get_peer_cfg_by_name = _get_peer_cfg_by_name, .create_peer_cfg_enumerator = _create_peer_cfg_enumerator, .add_backend = _add_backend, |