Merge branch 'ike-proposal-switch'
This allows switching the originally selected IKE config (based on the IPs and IKE version) to a different one if no matching proposal is found. This way we don't rely that much on the order of configs anymore and it's possible to configure separate configs for clients that require weak algorithms.
This commit is contained in:
@@ -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_cfg_t *current, *found = NULL;
|
||||
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;
|
||||
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)
|
||||
enumerator = list->create_enumerator(list);
|
||||
while (enumerator->enumerate(enumerator, ¤t))
|
||||
{
|
||||
helper->insert_last(helper, current);
|
||||
}
|
||||
while (helper->remove_first(helper, (void**)¤t) == SUCCESS)
|
||||
{
|
||||
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,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Tobias Brunner
|
||||
* Copyright (C) 2007 Martin Willi
|
||||
* HSR Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
@@ -63,6 +64,20 @@ struct backend_manager_t {
|
||||
host_t *my_host, host_t *other_host,
|
||||
ike_version_t version);
|
||||
|
||||
/**
|
||||
* Create an enumerator over all matching IKE configs.
|
||||
*
|
||||
* Pass NULL as parameters to match any. The enumerator enumerates over
|
||||
* ike_cfgs, ordered by priority (best match first).
|
||||
*
|
||||
* @param me local address
|
||||
* @param other remote address
|
||||
* @param version IKE version to get a config for
|
||||
* @return enumerator over ike_cfg
|
||||
*/
|
||||
enumerator_t* (*create_ike_cfg_enumerator)(backend_manager_t *this,
|
||||
host_t *me, host_t *other, ike_version_t version);
|
||||
|
||||
/**
|
||||
* Get a peer_config identified by it's name.
|
||||
*
|
||||
|
||||
@@ -254,7 +254,7 @@ METHOD(child_cfg_t, select_proposal, proposal_t*,
|
||||
{
|
||||
DBG2(DBG_CFG, "received proposals: %#P", proposals);
|
||||
DBG2(DBG_CFG, "configured proposals: %#P", this->proposals);
|
||||
DBG2(DBG_CFG, "selected proposal: %P", selected);
|
||||
DBG1(DBG_CFG, "selected proposal: %P", selected);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -289,7 +289,7 @@ METHOD(child_cfg_t, add_traffic_selector, void,
|
||||
|
||||
METHOD(child_cfg_t, get_traffic_selectors, linked_list_t*,
|
||||
private_child_cfg_t *this, bool local, linked_list_t *supplied,
|
||||
linked_list_t *hosts)
|
||||
linked_list_t *hosts, bool log)
|
||||
{
|
||||
enumerator_t *e1, *e2;
|
||||
traffic_selector_t *ts1, *ts2, *selected;
|
||||
@@ -334,13 +334,19 @@ METHOD(child_cfg_t, get_traffic_selectors, linked_list_t*,
|
||||
}
|
||||
e1->destroy(e1);
|
||||
|
||||
DBG2(DBG_CFG, "%s traffic selectors for %s:",
|
||||
supplied ? "selecting" : "proposing", local ? "us" : "other");
|
||||
if (supplied == NULL)
|
||||
if (log)
|
||||
{
|
||||
DBG2(DBG_CFG, "%s traffic selectors for %s:",
|
||||
supplied ? "selecting" : "proposing", local ? "us" : "other");
|
||||
}
|
||||
if (!supplied)
|
||||
{
|
||||
while (derived->remove_first(derived, (void**)&ts1) == SUCCESS)
|
||||
{
|
||||
DBG2(DBG_CFG, " %R", ts1);
|
||||
if (log)
|
||||
{
|
||||
DBG2(DBG_CFG, " %R", ts1);
|
||||
}
|
||||
result->insert_last(result, ts1);
|
||||
}
|
||||
derived->destroy(derived);
|
||||
@@ -358,11 +364,14 @@ METHOD(child_cfg_t, get_traffic_selectors, linked_list_t*,
|
||||
selected = ts1->get_subset(ts1, ts2);
|
||||
if (selected)
|
||||
{
|
||||
DBG2(DBG_CFG, " config: %R, received: %R => match: %R",
|
||||
ts1, ts2, selected);
|
||||
if (log)
|
||||
{
|
||||
DBG2(DBG_CFG, " config: %R, received: %R => match: %R",
|
||||
ts1, ts2, selected);
|
||||
}
|
||||
result->insert_last(result, selected);
|
||||
}
|
||||
else
|
||||
else if (log)
|
||||
{
|
||||
DBG2(DBG_CFG, " config: %R, received: %R => no match",
|
||||
ts1, ts2);
|
||||
|
||||
@@ -135,11 +135,13 @@ struct child_cfg_t {
|
||||
* @param local TRUE for TS on local side, FALSE for remote
|
||||
* @param supplied list with TS to select from, or NULL
|
||||
* @param hosts addresses to use for narrowing "dynamic" TS', host_t
|
||||
* @param log FALSE to avoid logging details about the selection
|
||||
* @return list containing the traffic selectors
|
||||
*/
|
||||
linked_list_t *(*get_traffic_selectors)(child_cfg_t *this, bool local,
|
||||
linked_list_t *supplied,
|
||||
linked_list_t *hosts);
|
||||
linked_list_t *hosts, bool log);
|
||||
|
||||
/**
|
||||
* Get the updown script to run for the CHILD_SA.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 Tobias Brunner
|
||||
* Copyright (C) 2012-2018 Tobias Brunner
|
||||
* Copyright (C) 2005-2007 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
* HSR Hochschule fuer Technik Rapperswil
|
||||
@@ -309,6 +309,25 @@ METHOD(ike_cfg_t, get_proposals, linked_list_t*,
|
||||
return proposals;
|
||||
}
|
||||
|
||||
METHOD(ike_cfg_t, has_proposal, bool,
|
||||
private_ike_cfg_t *this, proposal_t *match, bool private)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
proposal_t *proposal;
|
||||
|
||||
enumerator = this->proposals->create_enumerator(this->proposals);
|
||||
while (enumerator->enumerate(enumerator, &proposal))
|
||||
{
|
||||
if (proposal->matches(proposal, match, private))
|
||||
{
|
||||
enumerator->destroy(enumerator);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
METHOD(ike_cfg_t, select_proposal, proposal_t*,
|
||||
private_ike_cfg_t *this, linked_list_t *proposals, bool private,
|
||||
bool prefer_self)
|
||||
@@ -344,7 +363,7 @@ METHOD(ike_cfg_t, select_proposal, proposal_t*,
|
||||
{
|
||||
DBG2(DBG_CFG, "received proposals: %#P", proposals);
|
||||
DBG2(DBG_CFG, "configured proposals: %#P", this->proposals);
|
||||
DBG2(DBG_CFG, "selected proposal: %P", selected);
|
||||
DBG1(DBG_CFG, "selected proposal: %P", selected);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -618,6 +637,7 @@ ike_cfg_t *ike_cfg_create(ike_version_t version, bool certreq, bool force_encap,
|
||||
.add_proposal = _add_proposal,
|
||||
.get_proposals = _get_proposals,
|
||||
.select_proposal = _select_proposal,
|
||||
.has_proposal = _has_proposal,
|
||||
.get_dh_group = _get_dh_group,
|
||||
.equals = _equals,
|
||||
.get_ref = _get_ref,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 Tobias Brunner
|
||||
* Copyright (C) 2012-2018 Tobias Brunner
|
||||
* Copyright (C) 2005-2007 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
* HSR Hochschule fuer Technik Rapperswil
|
||||
@@ -179,6 +179,15 @@ struct ike_cfg_t {
|
||||
proposal_t *(*select_proposal) (ike_cfg_t *this, linked_list_t *proposals,
|
||||
bool private, bool prefer_self);
|
||||
|
||||
/**
|
||||
* Check if the config has a matching proposal.
|
||||
*
|
||||
* @param match proposal to check
|
||||
* @param private accept algorithms from a private range
|
||||
* @return TRUE if a matching proposal is contained
|
||||
*/
|
||||
bool(*has_proposal)(ike_cfg_t *this, proposal_t *match, bool private);
|
||||
|
||||
/**
|
||||
* Should we send a certificate request in IKE_SA_INIT?
|
||||
*
|
||||
|
||||
@@ -379,7 +379,7 @@ static int get_ts_match(child_cfg_t *cfg, bool local,
|
||||
int match = 0, round;
|
||||
|
||||
/* fetch configured TS list, narrowing dynamic TS */
|
||||
cfg_list = cfg->get_traffic_selectors(cfg, local, NULL, hosts);
|
||||
cfg_list = cfg->get_traffic_selectors(cfg, local, NULL, hosts, TRUE);
|
||||
|
||||
/* use a round counter to rate leading TS with higher priority */
|
||||
round = sup_list->get_count(sup_list);
|
||||
|
||||
@@ -324,10 +324,12 @@ static void request_query_config(xmlTextReaderPtr reader, xmlTextWriterPtr write
|
||||
xmlTextWriterStartElement(writer, "childconfig");
|
||||
xmlTextWriterWriteElement(writer, "name",
|
||||
child_cfg->get_name(child_cfg));
|
||||
list = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, NULL);
|
||||
list = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL,
|
||||
NULL, FALSE);
|
||||
write_networks(writer, "local", list);
|
||||
list->destroy_offset(list, offsetof(traffic_selector_t, destroy));
|
||||
list = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, NULL);
|
||||
list = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL,
|
||||
NULL, FALSE);
|
||||
write_networks(writer, "remote", list);
|
||||
list->destroy_offset(list, offsetof(traffic_selector_t, destroy));
|
||||
xmlTextWriterEndElement(writer);
|
||||
|
||||
@@ -580,8 +580,10 @@ METHOD(stroke_list_t, status, void,
|
||||
children = peer_cfg->create_child_cfg_enumerator(peer_cfg);
|
||||
while (children->enumerate(children, &child_cfg))
|
||||
{
|
||||
my_ts = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, NULL);
|
||||
other_ts = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, NULL);
|
||||
my_ts = child_cfg->get_traffic_selectors(child_cfg, TRUE,
|
||||
NULL, NULL, FALSE);
|
||||
other_ts = child_cfg->get_traffic_selectors(child_cfg, FALSE,
|
||||
NULL, NULL, FALSE);
|
||||
fprintf(out, "%12s: child: %#R === %#R %N",
|
||||
child_cfg->get_name(child_cfg), my_ts, other_ts,
|
||||
ipsec_mode_names, child_cfg->get_mode(child_cfg));
|
||||
@@ -614,8 +616,10 @@ METHOD(stroke_list_t, status, void,
|
||||
fprintf(out, "Shunted Connections:\n");
|
||||
first = FALSE;
|
||||
}
|
||||
my_ts = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, NULL);
|
||||
other_ts = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, NULL);
|
||||
my_ts = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL,
|
||||
NULL, FALSE);
|
||||
other_ts = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL,
|
||||
NULL, FALSE);
|
||||
fprintf(out, "%12s: %#R === %#R %N\n",
|
||||
child_cfg->get_name(child_cfg), my_ts, other_ts,
|
||||
ipsec_mode_names, child_cfg->get_mode(child_cfg));
|
||||
|
||||
@@ -56,7 +56,7 @@ static void narrow_ts(child_cfg_t *cfg, traffic_selector_t *ts,
|
||||
|
||||
received = linked_list_create();
|
||||
received->insert_last(received, ts);
|
||||
selected = cfg->get_traffic_selectors(cfg, FALSE, received, NULL);
|
||||
selected = cfg->get_traffic_selectors(cfg, FALSE, received, NULL, FALSE);
|
||||
while (selected->remove_first(selected, (void**)&ts) == SUCCESS)
|
||||
{
|
||||
list->insert_last(list, ts);
|
||||
@@ -140,7 +140,8 @@ static void narrow_responder_post(child_cfg_t *child_cfg, linked_list_t *local)
|
||||
{
|
||||
ts->destroy(ts);
|
||||
}
|
||||
configured = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, NULL);
|
||||
configured = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, NULL,
|
||||
FALSE);
|
||||
|
||||
while (configured->remove_first(configured, (void**)&ts) == SUCCESS)
|
||||
{
|
||||
|
||||
@@ -160,7 +160,8 @@ METHOD(attribute_provider_t, create_attribute_enumerator, enumerator_t*,
|
||||
enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg);
|
||||
while (enumerator->enumerate(enumerator, &child_cfg))
|
||||
{
|
||||
current = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, NULL);
|
||||
current = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, NULL,
|
||||
FALSE);
|
||||
while (current->remove_first(current, (void**)&ts) == SUCCESS)
|
||||
{
|
||||
if (use_ts(ts))
|
||||
|
||||
@@ -570,7 +570,7 @@ static void raise_policy_cfg(private_vici_query_t *this, u_int id, char *ike,
|
||||
list_mode(b, NULL, cfg);
|
||||
|
||||
b->begin_list(b, "local-ts");
|
||||
list = cfg->get_traffic_selectors(cfg, TRUE, NULL, NULL);
|
||||
list = cfg->get_traffic_selectors(cfg, TRUE, NULL, NULL, FALSE);
|
||||
enumerator = list->create_enumerator(list);
|
||||
while (enumerator->enumerate(enumerator, &ts))
|
||||
{
|
||||
@@ -581,7 +581,7 @@ static void raise_policy_cfg(private_vici_query_t *this, u_int id, char *ike,
|
||||
b->end_list(b /* local-ts */);
|
||||
|
||||
b->begin_list(b, "remote-ts");
|
||||
list = cfg->get_traffic_selectors(cfg, FALSE, NULL, NULL);
|
||||
list = cfg->get_traffic_selectors(cfg, FALSE, NULL, NULL, FALSE);
|
||||
enumerator = list->create_enumerator(list);
|
||||
while (enumerator->enumerate(enumerator, &ts))
|
||||
{
|
||||
@@ -873,7 +873,8 @@ CALLBACK(list_conns, vici_message_t*,
|
||||
child_cfg->get_close_action(child_cfg));
|
||||
|
||||
b->begin_list(b, "local-ts");
|
||||
list = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, NULL);
|
||||
list = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL,
|
||||
NULL, FALSE);
|
||||
selectors = list->create_enumerator(list);
|
||||
while (selectors->enumerate(selectors, &ts))
|
||||
{
|
||||
@@ -884,7 +885,8 @@ CALLBACK(list_conns, vici_message_t*,
|
||||
b->end_list(b /* local-ts */);
|
||||
|
||||
b->begin_list(b, "remote-ts");
|
||||
list = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, NULL);
|
||||
list = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL,
|
||||
NULL, FALSE);
|
||||
selectors = list->create_enumerator(list);
|
||||
while (selectors->enumerate(selectors, &ts))
|
||||
{
|
||||
|
||||
@@ -1723,7 +1723,7 @@ static host_t* get_proxy_addr(child_cfg_t *config, host_t *ike, bool local)
|
||||
traffic_selector_t *ts;
|
||||
|
||||
list = linked_list_create_with_items(ike, NULL);
|
||||
ts_list = config->get_traffic_selectors(config, local, NULL, list);
|
||||
ts_list = config->get_traffic_selectors(config, local, NULL, list, FALSE);
|
||||
list->destroy(list);
|
||||
|
||||
enumerator = ts_list->create_enumerator(ts_list);
|
||||
|
||||
@@ -674,6 +674,7 @@ METHOD(ike_sa_t, get_ike_cfg, ike_cfg_t*,
|
||||
METHOD(ike_sa_t, set_ike_cfg, void,
|
||||
private_ike_sa_t *this, ike_cfg_t *ike_cfg)
|
||||
{
|
||||
DESTROY_IF(this->ike_cfg);
|
||||
ike_cfg->get_ref(ike_cfg);
|
||||
this->ike_cfg = ike_cfg;
|
||||
}
|
||||
|
||||
@@ -544,7 +544,7 @@ static traffic_selector_t* select_ts(private_quick_mode_t *this, bool local,
|
||||
|
||||
hosts = get_dynamic_hosts(this->ike_sa, local);
|
||||
list = this->config->get_traffic_selectors(this->config,
|
||||
local, supplied, hosts);
|
||||
local, supplied, hosts, TRUE);
|
||||
hosts->destroy(hosts);
|
||||
if (list->get_first(list, (void**)&ts) == SUCCESS)
|
||||
{
|
||||
|
||||
@@ -226,7 +226,7 @@ static bool select_compliant_config(private_xauth_t *this)
|
||||
{ /* current config is fine */
|
||||
return TRUE;
|
||||
}
|
||||
DBG1(DBG_CFG, "selected peer config '%s' inacceptable",
|
||||
DBG1(DBG_CFG, "selected peer config '%s' unacceptable",
|
||||
old->get_name(old));
|
||||
aggressive = old->use_aggressive(old);
|
||||
|
||||
|
||||
@@ -481,12 +481,14 @@ static linked_list_t* narrow_ts(private_child_create_t *this, bool local,
|
||||
this->ike_sa->has_condition(this->ike_sa, cond))
|
||||
{
|
||||
nat = get_transport_nat_ts(this, local, in);
|
||||
ts = this->config->get_traffic_selectors(this->config, local, nat, hosts);
|
||||
ts = this->config->get_traffic_selectors(this->config, local, nat,
|
||||
hosts, TRUE);
|
||||
nat->destroy_offset(nat, offsetof(traffic_selector_t, destroy));
|
||||
}
|
||||
else
|
||||
{
|
||||
ts = this->config->get_traffic_selectors(this->config, local, in, hosts);
|
||||
ts = this->config->get_traffic_selectors(this->config, local, in,
|
||||
hosts, TRUE);
|
||||
}
|
||||
|
||||
hosts->destroy(hosts);
|
||||
@@ -497,8 +499,8 @@ static linked_list_t* narrow_ts(private_child_create_t *this, bool local,
|
||||
/**
|
||||
* Install a CHILD_SA for usage, return value:
|
||||
* - FAILED: no acceptable proposal
|
||||
* - INVALID_ARG: diffie hellman group inacceptable
|
||||
* - NOT_FOUND: TS inacceptable
|
||||
* - INVALID_ARG: diffie hellman group unacceptable
|
||||
* - NOT_FOUND: TS unacceptable
|
||||
*/
|
||||
static status_t select_and_install(private_child_create_t *this,
|
||||
bool no_dh, bool ike_auth)
|
||||
@@ -559,7 +561,7 @@ static status_t select_and_install(private_child_create_t *this,
|
||||
if (this->proposal->get_algorithm(this->proposal, DIFFIE_HELLMAN_GROUP,
|
||||
&group, NULL))
|
||||
{
|
||||
DBG1(DBG_IKE, "DH group %N inacceptable, requesting %N",
|
||||
DBG1(DBG_IKE, "DH group %N unacceptable, requesting %N",
|
||||
diffie_hellman_group_names, this->dh_group,
|
||||
diffie_hellman_group_names, group);
|
||||
this->dh_group = group;
|
||||
@@ -1075,7 +1077,7 @@ METHOD(task_t, build_i, status_t,
|
||||
if (list->get_count(list))
|
||||
{
|
||||
this->tsi = this->config->get_traffic_selectors(this->config,
|
||||
TRUE, NULL, list);
|
||||
TRUE, NULL, list, TRUE);
|
||||
list->destroy_offset(list, offsetof(host_t, destroy));
|
||||
}
|
||||
else
|
||||
@@ -1083,12 +1085,12 @@ METHOD(task_t, build_i, status_t,
|
||||
list->destroy(list);
|
||||
list = get_dynamic_hosts(this->ike_sa, TRUE);
|
||||
this->tsi = this->config->get_traffic_selectors(this->config,
|
||||
TRUE, NULL, list);
|
||||
TRUE, NULL, list, TRUE);
|
||||
list->destroy(list);
|
||||
}
|
||||
list = get_dynamic_hosts(this->ike_sa, FALSE);
|
||||
this->tsr = this->config->get_traffic_selectors(this->config,
|
||||
FALSE, NULL, list);
|
||||
FALSE, NULL, list, TRUE);
|
||||
list->destroy(list);
|
||||
|
||||
if (this->packet_tsi)
|
||||
@@ -1356,7 +1358,7 @@ METHOD(task_t, build_r, status_t,
|
||||
}
|
||||
if (this->config == NULL)
|
||||
{
|
||||
DBG1(DBG_IKE, "traffic selectors %#R === %#R inacceptable",
|
||||
DBG1(DBG_IKE, "traffic selectors %#R === %#R unacceptable",
|
||||
this->tsr, this->tsi);
|
||||
charon->bus->alert(charon->bus, ALERT_TS_MISMATCH, this->tsi, this->tsr);
|
||||
message->add_notify(message, FALSE, TS_UNACCEPTABLE, chunk_empty);
|
||||
|
||||
@@ -285,13 +285,18 @@ static bool load_cfg_candidates(private_ike_auth_t *this)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
peer_cfg_t *peer_cfg;
|
||||
ike_cfg_t *ike_cfg;
|
||||
host_t *me, *other;
|
||||
identification_t *my_id, *other_id;
|
||||
proposal_t *ike_proposal;
|
||||
bool private;
|
||||
|
||||
me = this->ike_sa->get_my_host(this->ike_sa);
|
||||
other = this->ike_sa->get_other_host(this->ike_sa);
|
||||
my_id = this->ike_sa->get_my_id(this->ike_sa);
|
||||
other_id = this->ike_sa->get_other_id(this->ike_sa);
|
||||
ike_proposal = this->ike_sa->get_proposal(this->ike_sa);
|
||||
private = this->ike_sa->supports_extension(this->ike_sa, EXT_STRONGSWAN);
|
||||
|
||||
DBG1(DBG_CFG, "looking for peer configs matching %H[%Y]...%H[%Y]",
|
||||
me, my_id, other, other_id);
|
||||
@@ -299,11 +304,18 @@ static bool load_cfg_candidates(private_ike_auth_t *this)
|
||||
me, other, my_id, other_id, IKEV2);
|
||||
while (enumerator->enumerate(enumerator, &peer_cfg))
|
||||
{
|
||||
/* ignore all configs that have no matching IKE proposal */
|
||||
ike_cfg = peer_cfg->get_ike_cfg(peer_cfg);
|
||||
if (!ike_cfg->has_proposal(ike_cfg, ike_proposal, private))
|
||||
{
|
||||
DBG2(DBG_CFG, "ignore candidate '%s' without matching IKE proposal",
|
||||
peer_cfg->get_name(peer_cfg));
|
||||
continue;
|
||||
}
|
||||
peer_cfg->get_ref(peer_cfg);
|
||||
if (this->peer_cfg == NULL)
|
||||
{ /* best match */
|
||||
this->peer_cfg = peer_cfg;
|
||||
this->ike_sa->set_peer_cfg(this->ike_sa, peer_cfg);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -313,6 +325,7 @@ static bool load_cfg_candidates(private_ike_auth_t *this)
|
||||
enumerator->destroy(enumerator);
|
||||
if (this->peer_cfg)
|
||||
{
|
||||
this->ike_sa->set_peer_cfg(this->ike_sa, this->peer_cfg);
|
||||
DBG1(DBG_CFG, "selected peer config '%s'",
|
||||
this->peer_cfg->get_name(this->peer_cfg));
|
||||
return TRUE;
|
||||
@@ -369,7 +382,7 @@ static bool update_cfg_candidates(private_ike_auth_t *this, bool strict)
|
||||
{
|
||||
break;
|
||||
}
|
||||
DBG1(DBG_CFG, "selected peer config '%s' inacceptable: %s",
|
||||
DBG1(DBG_CFG, "selected peer config '%s' unacceptable: %s",
|
||||
this->peer_cfg->get_name(this->peer_cfg), comply_error);
|
||||
this->peer_cfg->destroy(this->peer_cfg);
|
||||
}
|
||||
@@ -603,7 +616,7 @@ METHOD(task_t, process_r, status_t,
|
||||
(uintptr_t)cand->get(cand, AUTH_RULE_EAP_TYPE) == EAP_NAK &&
|
||||
(uintptr_t)cand->get(cand, AUTH_RULE_EAP_VENDOR) == 0))
|
||||
{ /* peer requested EAP, but current config does not match */
|
||||
DBG1(DBG_IKE, "peer requested EAP, config inacceptable");
|
||||
DBG1(DBG_IKE, "peer requested EAP, config unacceptable");
|
||||
this->peer_cfg->destroy(this->peer_cfg);
|
||||
this->peer_cfg = NULL;
|
||||
if (!update_cfg_candidates(this, FALSE))
|
||||
|
||||
@@ -54,11 +54,6 @@ struct private_ike_init_t {
|
||||
*/
|
||||
bool initiator;
|
||||
|
||||
/**
|
||||
* IKE config to establish
|
||||
*/
|
||||
ike_cfg_t *config;
|
||||
|
||||
/**
|
||||
* diffie hellman group to use
|
||||
*/
|
||||
@@ -286,14 +281,15 @@ static bool build_payloads(private_ike_init_t *this, message_t *message)
|
||||
ike_sa_id_t *id;
|
||||
proposal_t *proposal;
|
||||
enumerator_t *enumerator;
|
||||
ike_cfg_t *ike_cfg;
|
||||
|
||||
id = this->ike_sa->get_id(this->ike_sa);
|
||||
|
||||
this->config = this->ike_sa->get_ike_cfg(this->ike_sa);
|
||||
ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa);
|
||||
|
||||
if (this->initiator)
|
||||
{
|
||||
proposal_list = this->config->get_proposals(this->config);
|
||||
proposal_list = ike_cfg->get_proposals(ike_cfg);
|
||||
other_dh_groups = linked_list_create();
|
||||
enumerator = proposal_list->create_enumerator(proposal_list);
|
||||
while (enumerator->enumerate(enumerator, (void**)&proposal))
|
||||
@@ -357,7 +353,7 @@ static bool build_payloads(private_ike_init_t *this, message_t *message)
|
||||
|
||||
/* negotiate fragmentation if we are not rekeying */
|
||||
if (!this->old_sa &&
|
||||
this->config->fragmentation(this->config) != FRAGMENTATION_NO)
|
||||
ike_cfg->fragmentation(ike_cfg) != FRAGMENTATION_NO)
|
||||
{
|
||||
if (this->initiator ||
|
||||
this->ike_sa->supports_extension(this->ike_sa,
|
||||
@@ -403,6 +399,68 @@ static bool build_payloads(private_ike_init_t *this, message_t *message)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the SA payload and select a proposal
|
||||
*/
|
||||
static void process_sa_payload(private_ike_init_t *this, message_t *message,
|
||||
sa_payload_t *sa_payload)
|
||||
{
|
||||
ike_cfg_t *ike_cfg, *cfg, *alt_cfg = NULL;
|
||||
enumerator_t *enumerator;
|
||||
linked_list_t *proposal_list;
|
||||
host_t *me, *other;
|
||||
bool private, prefer_configured;
|
||||
|
||||
ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa);
|
||||
|
||||
proposal_list = sa_payload->get_proposals(sa_payload);
|
||||
private = this->ike_sa->supports_extension(this->ike_sa, EXT_STRONGSWAN);
|
||||
prefer_configured = lib->settings->get_bool(lib->settings,
|
||||
"%s.prefer_configured_proposals", TRUE, lib->ns);
|
||||
|
||||
this->proposal = ike_cfg->select_proposal(ike_cfg, proposal_list, private,
|
||||
prefer_configured);
|
||||
if (!this->proposal)
|
||||
{
|
||||
if (!this->initiator && !this->old_sa)
|
||||
{
|
||||
me = message->get_destination(message);
|
||||
other = message->get_source(message);
|
||||
enumerator = charon->backends->create_ike_cfg_enumerator(
|
||||
charon->backends, me, other, IKEV2);
|
||||
while (enumerator->enumerate(enumerator, &cfg))
|
||||
{
|
||||
if (ike_cfg == cfg)
|
||||
{ /* already tried and failed */
|
||||
continue;
|
||||
}
|
||||
DBG1(DBG_IKE, "no matching proposal found, trying alternative "
|
||||
"config");
|
||||
this->proposal = cfg->select_proposal(cfg, proposal_list,
|
||||
private, prefer_configured);
|
||||
if (this->proposal)
|
||||
{
|
||||
alt_cfg = cfg->get_ref(cfg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
if (alt_cfg)
|
||||
{
|
||||
this->ike_sa->set_ike_cfg(this->ike_sa, alt_cfg);
|
||||
alt_cfg->destroy(alt_cfg);
|
||||
}
|
||||
else
|
||||
{
|
||||
charon->bus->alert(charon->bus, ALERT_PROPOSAL_MISMATCH_IKE,
|
||||
proposal_list);
|
||||
}
|
||||
}
|
||||
proposal_list->destroy_offset(proposal_list,
|
||||
offsetof(proposal_t, destroy));
|
||||
}
|
||||
|
||||
/**
|
||||
* Read payloads from message
|
||||
*/
|
||||
@@ -419,24 +477,7 @@ static void process_payloads(private_ike_init_t *this, message_t *message)
|
||||
{
|
||||
case PLV2_SECURITY_ASSOCIATION:
|
||||
{
|
||||
sa_payload_t *sa_payload = (sa_payload_t*)payload;
|
||||
linked_list_t *proposal_list;
|
||||
bool private, prefer_configured;
|
||||
|
||||
proposal_list = sa_payload->get_proposals(sa_payload);
|
||||
private = this->ike_sa->supports_extension(this->ike_sa,
|
||||
EXT_STRONGSWAN);
|
||||
prefer_configured = lib->settings->get_bool(lib->settings,
|
||||
"%s.prefer_configured_proposals", TRUE, lib->ns);
|
||||
this->proposal = this->config->select_proposal(this->config,
|
||||
proposal_list, private, prefer_configured);
|
||||
if (!this->proposal)
|
||||
{
|
||||
charon->bus->alert(charon->bus, ALERT_PROPOSAL_MISMATCH_IKE,
|
||||
proposal_list);
|
||||
}
|
||||
proposal_list->destroy_offset(proposal_list,
|
||||
offsetof(proposal_t, destroy));
|
||||
process_sa_payload(this, message, (sa_payload_t*)payload);
|
||||
break;
|
||||
}
|
||||
case PLV2_KEY_EXCHANGE:
|
||||
@@ -533,7 +574,10 @@ static void process_payloads(private_ike_init_t *this, message_t *message)
|
||||
METHOD(task_t, build_i, status_t,
|
||||
private_ike_init_t *this, message_t *message)
|
||||
{
|
||||
this->config = this->ike_sa->get_ike_cfg(this->ike_sa);
|
||||
ike_cfg_t *ike_cfg;
|
||||
|
||||
ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa);
|
||||
|
||||
DBG0(DBG_IKE, "initiating IKE_SA %s[%d] to %H",
|
||||
this->ike_sa->get_name(this->ike_sa),
|
||||
this->ike_sa->get_unique_id(this->ike_sa),
|
||||
@@ -563,12 +607,12 @@ METHOD(task_t, build_i, status_t,
|
||||
}
|
||||
else
|
||||
{ /* this shouldn't happen, but let's be safe */
|
||||
this->dh_group = this->config->get_dh_group(this->config);
|
||||
this->dh_group = ike_cfg->get_dh_group(ike_cfg);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this->dh_group = this->config->get_dh_group(this->config);
|
||||
this->dh_group = ike_cfg->get_dh_group(ike_cfg);
|
||||
}
|
||||
this->dh = this->keymat->keymat.create_dh(&this->keymat->keymat,
|
||||
this->dh_group);
|
||||
@@ -627,7 +671,6 @@ METHOD(task_t, build_i, status_t,
|
||||
METHOD(task_t, process_r, status_t,
|
||||
private_ike_init_t *this, message_t *message)
|
||||
{
|
||||
this->config = this->ike_sa->get_ike_cfg(this->ike_sa);
|
||||
DBG0(DBG_IKE, "%H is initiating an IKE_SA", message->get_source(message));
|
||||
this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING);
|
||||
|
||||
@@ -699,7 +742,7 @@ METHOD(task_t, build_r, status_t,
|
||||
if (this->proposal == NULL ||
|
||||
this->other_nonce.len == 0 || this->my_nonce.len == 0)
|
||||
{
|
||||
DBG1(DBG_IKE, "received proposals inacceptable");
|
||||
DBG1(DBG_IKE, "received proposals unacceptable");
|
||||
message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty);
|
||||
return FAILED;
|
||||
}
|
||||
@@ -728,7 +771,7 @@ METHOD(task_t, build_r, status_t,
|
||||
if (this->proposal->get_algorithm(this->proposal, DIFFIE_HELLMAN_GROUP,
|
||||
&group, NULL))
|
||||
{
|
||||
DBG1(DBG_IKE, "DH group %N inacceptable, requesting %N",
|
||||
DBG1(DBG_IKE, "DH group %N unacceptable, requesting %N",
|
||||
diffie_hellman_group_names, this->dh_group,
|
||||
diffie_hellman_group_names, group);
|
||||
this->dh_group = group;
|
||||
@@ -770,12 +813,14 @@ METHOD(task_t, build_r, status_t,
|
||||
*/
|
||||
static void raise_alerts(private_ike_init_t *this, notify_type_t type)
|
||||
{
|
||||
ike_cfg_t *ike_cfg;
|
||||
linked_list_t *list;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case NO_PROPOSAL_CHOSEN:
|
||||
list = this->config->get_proposals(this->config);
|
||||
ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa);
|
||||
list = ike_cfg->get_proposals(ike_cfg);
|
||||
charon->bus->alert(charon->bus, ALERT_PROPOSAL_MISMATCH_IKE, list);
|
||||
list->destroy_offset(list, offsetof(proposal_t, destroy));
|
||||
break;
|
||||
|
||||
@@ -259,7 +259,7 @@ METHOD(task_t, build_r, status_t,
|
||||
}
|
||||
if (this->new_sa == NULL)
|
||||
{
|
||||
/* IKE_SA/a CHILD_SA is in an inacceptable state, deny rekeying */
|
||||
/* IKE_SA/a CHILD_SA is in an unacceptable state, deny rekeying */
|
||||
message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
@@ -117,8 +117,10 @@ static bool install_shunt_policy(child_cfg_t *child)
|
||||
host_any6 = host_create_any(AF_INET6);
|
||||
|
||||
hosts = linked_list_create_with_items(host_any, host_any6, NULL);
|
||||
my_ts_list = child->get_traffic_selectors(child, TRUE, NULL, hosts);
|
||||
other_ts_list = child->get_traffic_selectors(child, FALSE, NULL, hosts);
|
||||
my_ts_list = child->get_traffic_selectors(child, TRUE, NULL, hosts,
|
||||
FALSE);
|
||||
other_ts_list = child->get_traffic_selectors(child, FALSE, NULL, hosts,
|
||||
FALSE);
|
||||
hosts->destroy(hosts);
|
||||
|
||||
manual_prio = child->get_manual_prio(child);
|
||||
@@ -287,8 +289,10 @@ static void uninstall_shunt_policy(child_cfg_t *child)
|
||||
host_any6 = host_create_any(AF_INET6);
|
||||
|
||||
hosts = linked_list_create_with_items(host_any, host_any6, NULL);
|
||||
my_ts_list = child->get_traffic_selectors(child, TRUE, NULL, hosts);
|
||||
other_ts_list = child->get_traffic_selectors(child, FALSE, NULL, hosts);
|
||||
my_ts_list = child->get_traffic_selectors(child, TRUE, NULL, hosts,
|
||||
FALSE);
|
||||
other_ts_list = child->get_traffic_selectors(child, FALSE, NULL, hosts,
|
||||
FALSE);
|
||||
hosts->destroy(hosts);
|
||||
|
||||
manual_prio = child->get_manual_prio(child);
|
||||
|
||||
@@ -168,7 +168,7 @@ static bool dynamic_remote_ts(child_cfg_t *child)
|
||||
traffic_selector_t *ts;
|
||||
bool found = FALSE;
|
||||
|
||||
other_ts = child->get_traffic_selectors(child, FALSE, NULL, NULL);
|
||||
other_ts = child->get_traffic_selectors(child, FALSE, NULL, NULL, FALSE);
|
||||
enumerator = other_ts->create_enumerator(other_ts);
|
||||
while (enumerator->enumerate(enumerator, &ts))
|
||||
{
|
||||
@@ -296,11 +296,11 @@ METHOD(trap_manager_t, install, bool,
|
||||
child_sa = child_sa_create(me, other, child, 0, FALSE, 0, 0);
|
||||
|
||||
list = linked_list_create_with_items(me, NULL);
|
||||
my_ts = child->get_traffic_selectors(child, TRUE, NULL, list);
|
||||
my_ts = child->get_traffic_selectors(child, TRUE, NULL, list, FALSE);
|
||||
list->destroy_offset(list, offsetof(host_t, destroy));
|
||||
|
||||
list = linked_list_create_with_items(other, NULL);
|
||||
other_ts = child->get_traffic_selectors(child, FALSE, NULL, list);
|
||||
other_ts = child->get_traffic_selectors(child, FALSE, NULL, list, FALSE);
|
||||
list->destroy_offset(list, offsetof(host_t, destroy));
|
||||
|
||||
/* We don't know the finally negotiated protocol (ESP|AH), we install
|
||||
|
||||
@@ -225,7 +225,7 @@ static status_t do_sasl(private_pt_tls_client_t *this, sasl_mechanism_t *sasl)
|
||||
reader->destroy(reader);
|
||||
return SUCCESS;
|
||||
case NEED_MORE:
|
||||
/* inacceptable, it won't get more. FALL */
|
||||
/* unacceptable, it won't get more. FALL */
|
||||
case FAILED:
|
||||
default:
|
||||
reader->destroy(reader);
|
||||
|
||||
@@ -335,22 +335,16 @@ METHOD(proposal_t, strip_dh, void,
|
||||
}
|
||||
|
||||
/**
|
||||
* Select a matching proposal from this and other, insert into selected.
|
||||
* Select a matching proposal from this and other.
|
||||
*/
|
||||
static bool select_algo(private_proposal_t *this, proposal_t *other,
|
||||
proposal_t *selected, transform_type_t type, bool priv)
|
||||
transform_type_t type, bool priv, bool log,
|
||||
uint16_t *alg, uint16_t *ks)
|
||||
{
|
||||
enumerator_t *e1, *e2;
|
||||
uint16_t alg1, alg2, ks1, ks2;
|
||||
bool found = FALSE, optional = FALSE;
|
||||
|
||||
if (type == INTEGRITY_ALGORITHM &&
|
||||
selected->get_algorithm(selected, ENCRYPTION_ALGORITHM, &alg1, NULL) &&
|
||||
encryption_algorithm_is_aead(alg1))
|
||||
{
|
||||
/* no integrity algorithm required, we have an AEAD */
|
||||
return TRUE;
|
||||
}
|
||||
if (type == DIFFIE_HELLMAN_GROUP)
|
||||
{
|
||||
optional = this->protocol == PROTO_ESP || this->protocol == PROTO_AH;
|
||||
@@ -398,36 +392,86 @@ static bool select_algo(private_proposal_t *this, proposal_t *other,
|
||||
{
|
||||
if (!priv && alg1 >= 1024)
|
||||
{
|
||||
/* accept private use algorithms only if requested */
|
||||
DBG1(DBG_CFG, "an algorithm from private space would match, "
|
||||
"but peer implementation is unknown, skipped");
|
||||
if (log)
|
||||
{
|
||||
DBG1(DBG_CFG, "an algorithm from private space would "
|
||||
"match, but peer implementation is unknown, "
|
||||
"skipped");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
selected->add_algorithm(selected, type, alg1, ks1);
|
||||
*alg = alg1;
|
||||
*ks = ks1;
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* no match in all comparisons */
|
||||
e1->destroy(e1);
|
||||
e2->destroy(e2);
|
||||
|
||||
if (!found)
|
||||
{
|
||||
DBG2(DBG_CFG, " no acceptable %N found", transform_type_names, type);
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
/**
|
||||
* Select algorithms from the given proposals, if selected is given, the result
|
||||
* is stored there and errors are logged.
|
||||
*/
|
||||
static bool select_algos(private_proposal_t *this, proposal_t *other,
|
||||
proposal_t *selected, bool private)
|
||||
{
|
||||
transform_type_t type;
|
||||
array_t *types;
|
||||
bool skip_integrity = FALSE;
|
||||
int i;
|
||||
|
||||
types = merge_types(this, (private_proposal_t*)other);
|
||||
for (i = 0; i < array_count(types); i++)
|
||||
{
|
||||
uint16_t alg = 0, ks = 0;
|
||||
|
||||
array_get(types, i, &type);
|
||||
if (type == INTEGRITY_ALGORITHM && skip_integrity)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (select_algo(this, other, type, private, selected != NULL, &alg, &ks))
|
||||
{
|
||||
if (alg == 0 && type != EXTENDED_SEQUENCE_NUMBERS)
|
||||
{ /* 0 is "valid" for extended sequence numbers, for other
|
||||
* transforms it either means NONE or is reserved */
|
||||
continue;
|
||||
}
|
||||
if (selected)
|
||||
{
|
||||
selected->add_algorithm(selected, type, alg, ks);
|
||||
}
|
||||
if (type == ENCRYPTION_ALGORITHM &&
|
||||
encryption_algorithm_is_aead(alg))
|
||||
{
|
||||
/* no integrity algorithm required, we have an AEAD */
|
||||
skip_integrity = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (selected)
|
||||
{
|
||||
DBG2(DBG_CFG, " no acceptable %N found", transform_type_names,
|
||||
type);
|
||||
}
|
||||
array_destroy(types);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
array_destroy(types);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
METHOD(proposal_t, select_proposal, proposal_t*,
|
||||
private_proposal_t *this, proposal_t *other, bool other_remote,
|
||||
bool private)
|
||||
{
|
||||
proposal_t *selected;
|
||||
transform_type_t type;
|
||||
array_t *types;
|
||||
int i;
|
||||
|
||||
DBG2(DBG_CFG, "selecting proposal:");
|
||||
|
||||
@@ -448,23 +492,25 @@ METHOD(proposal_t, select_proposal, proposal_t*,
|
||||
selected->set_spi(selected, this->spi);
|
||||
}
|
||||
|
||||
types = merge_types(this, (private_proposal_t*)other);
|
||||
for (i = 0; i < array_count(types); i++)
|
||||
if (!select_algos(this, other, selected, private))
|
||||
{
|
||||
array_get(types, i, &type);
|
||||
if (!select_algo(this, other, selected, type, private))
|
||||
{
|
||||
selected->destroy(selected);
|
||||
array_destroy(types);
|
||||
return NULL;
|
||||
}
|
||||
selected->destroy(selected);
|
||||
return NULL;
|
||||
}
|
||||
array_destroy(types);
|
||||
|
||||
DBG2(DBG_CFG, " proposal matches");
|
||||
return selected;
|
||||
}
|
||||
|
||||
METHOD(proposal_t, matches, bool,
|
||||
private_proposal_t *this, proposal_t *other, bool private)
|
||||
{
|
||||
if (this->protocol != other->get_protocol(other))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
return select_algos(this, other, NULL, private);
|
||||
}
|
||||
|
||||
METHOD(proposal_t, get_protocol, protocol_id_t,
|
||||
private_proposal_t *this)
|
||||
{
|
||||
@@ -910,6 +956,7 @@ proposal_t *proposal_create(protocol_id_t protocol, u_int number)
|
||||
.promote_dh_group = _promote_dh_group,
|
||||
.strip_dh = _strip_dh,
|
||||
.select = _select_proposal,
|
||||
.matches = _matches,
|
||||
.get_protocol = _get_protocol,
|
||||
.set_spi = _set_spi,
|
||||
.get_spi = _get_spi,
|
||||
|
||||
@@ -34,7 +34,6 @@ typedef struct proposal_t proposal_t;
|
||||
#include <crypto/crypters/crypter.h>
|
||||
#include <crypto/signers/signer.h>
|
||||
#include <crypto/diffie_hellman.h>
|
||||
#include <selectors/traffic_selector.h>
|
||||
|
||||
/**
|
||||
* Protocol ID of a proposal.
|
||||
@@ -143,6 +142,17 @@ struct proposal_t {
|
||||
proposal_t *(*select)(proposal_t *this, proposal_t *other,
|
||||
bool other_remote, bool private);
|
||||
|
||||
/**
|
||||
* Check if the given proposal matches this proposal.
|
||||
*
|
||||
* This is similar to select, but no resulting proposal is selected.
|
||||
*
|
||||
* @param other proposal to compare against
|
||||
* @param private accepts algorithms allocated in a private range
|
||||
* @return TRUE if the proposals match
|
||||
*/
|
||||
bool (*matches)(proposal_t *this, proposal_t *other, bool private);
|
||||
|
||||
/**
|
||||
* Get the protocol ID of the proposal.
|
||||
*
|
||||
|
||||
@@ -102,7 +102,12 @@ static struct {
|
||||
{ PROTO_ESP, "aes128-sha256-modp3072-modpnone", "aes128-sha256", "aes128-sha256" },
|
||||
{ PROTO_ESP, "aes128-sha256", "aes128-sha256-modp3072-modpnone", "aes128-sha256" },
|
||||
{ PROTO_ESP, "aes128-sha256-modp3072-modpnone", "aes128-sha256-modpnone-modp3072", "aes128-sha256-modp3072" },
|
||||
{ PROTO_ESP, "aes128-sha256-modpnone-modp3072", "aes128-sha256-modp3072-modpnone", "aes128-sha256-modpnone" },
|
||||
{ PROTO_ESP, "aes128-sha256-modpnone-modp3072", "aes128-sha256-modp3072-modpnone", "aes128-sha256" },
|
||||
{ PROTO_ESP, "aes128-sha256-esn", "aes128-sha256-esn", "aes128-sha256-esn" },
|
||||
{ PROTO_ESP, "aes128-sha256-noesn", "aes128-sha256-esn", NULL },
|
||||
{ PROTO_ESP, "aes128-sha256-noesn-esn", "aes128-sha256-esn", "aes128-sha256-esn" },
|
||||
{ PROTO_ESP, "aes128-sha256-noesn-esn", "aes128-sha256", "aes128-sha256" },
|
||||
{ PROTO_ESP, "aes128-sha256-esn-noesn", "aes128-sha256-noesn-esn", "aes128-sha256-esn" },
|
||||
{ PROTO_IKE, "aes128-sha256-modp3072", "aes128-sha256-modp3072", "aes128-sha256-modp3072" },
|
||||
{ PROTO_IKE, "aes128-sha256-modp3072", "aes128-sha256-modp3072-modpnone", "aes128-sha256-modp3072" },
|
||||
{ PROTO_IKE, "aes128-sha256-modp3072-modpnone", "aes128-sha256-modp3072", "aes128-sha256-modp3072" },
|
||||
@@ -159,6 +164,29 @@ START_TEST(test_select_spi)
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_matches)
|
||||
{
|
||||
proposal_t *self, *other;
|
||||
|
||||
self = proposal_create_from_string(select_data[_i].proto,
|
||||
select_data[_i].self);
|
||||
other = proposal_create_from_string(select_data[_i].proto,
|
||||
select_data[_i].other);
|
||||
if (select_data[_i].expected)
|
||||
{
|
||||
ck_assert(self->matches(self, other, FALSE));
|
||||
ck_assert(other->matches(other, self, FALSE));
|
||||
}
|
||||
else
|
||||
{
|
||||
ck_assert(!self->matches(self, other, FALSE));
|
||||
ck_assert(!other->matches(other, self, FALSE));
|
||||
}
|
||||
other->destroy(other);
|
||||
self->destroy(self);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_promote_dh_group)
|
||||
{
|
||||
proposal_t *proposal;
|
||||
@@ -312,6 +340,10 @@ Suite *proposal_suite_create()
|
||||
tcase_add_test(tc, test_select_spi);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("matches");
|
||||
tcase_add_loop_test(tc, test_matches, 0, countof(select_data));
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("promote_dh_group");
|
||||
tcase_add_test(tc, test_promote_dh_group);
|
||||
tcase_add_test(tc, test_promote_dh_group_already_front);
|
||||
|
||||
@@ -188,7 +188,7 @@ static status_t process_server_hello(private_tls_peer_t *this,
|
||||
suite = cipher;
|
||||
if (!this->crypto->select_cipher_suite(this->crypto, &suite, 1, KEY_ANY))
|
||||
{
|
||||
DBG1(DBG_TLS, "received TLS cipher suite %N inacceptable",
|
||||
DBG1(DBG_TLS, "received TLS cipher suite %N unacceptable",
|
||||
tls_cipher_suite_names, suite);
|
||||
this->alert->add(this->alert, TLS_FATAL, TLS_HANDSHAKE_FAILURE);
|
||||
return NEED_MORE;
|
||||
|
||||
@@ -190,7 +190,7 @@ static bool select_suite_and_key(private_tls_server_t *this,
|
||||
suites, count, type);
|
||||
if (!this->suite)
|
||||
{
|
||||
DBG1(DBG_TLS, "received cipher suites inacceptable");
|
||||
DBG1(DBG_TLS, "received cipher suites unacceptable");
|
||||
return FALSE;
|
||||
}
|
||||
this->server_auth->destroy(this->server_auth);
|
||||
@@ -199,7 +199,7 @@ static bool select_suite_and_key(private_tls_server_t *this,
|
||||
this->server_auth);
|
||||
if (!key)
|
||||
{
|
||||
DBG1(DBG_TLS, "received cipher suites inacceptable");
|
||||
DBG1(DBG_TLS, "received cipher suites unacceptable");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ carol::cat /var/log/daemon.log::received TS_UNACCEPTABLE notify, no CHILD_SA bui
|
||||
carol::ipsec status 2> /dev/null::venus.*INSTALLED::NO
|
||||
moon:: ipsec status 2> /dev/null::venus.*ESTABLISHED.*moon.strongswan.org.*[email protected]::NO
|
||||
moon:: cat /var/log/daemon.log::constraint check failed: peer not authenticated by.*Research CA::YES
|
||||
moon:: cat /var/log/daemon.log::selected peer config.*alice.*inacceptable::YES
|
||||
moon:: cat /var/log/daemon.log::selected peer config.*alice.*unacceptable::YES
|
||||
moon:: cat /var/log/daemon.log::switching to peer config.*venus::YES
|
||||
dave:: ipsec status 2> /dev/null::venus.*INSTALLED, TUNNEL::YES
|
||||
moon:: ipsec status 2> /dev/null::venus.*ESTABLISHED.*moon.strongswan.org.*[email protected]::YES
|
||||
|
||||
@@ -10,7 +10,7 @@ carol::cat /var/log/daemon.log::received TS_UNACCEPTABLE notify, no CHILD_SA bui
|
||||
carol::ipsec status 2> /dev/null::venus.*INSTALLED::NO
|
||||
moon:: ipsec status 2> /dev/null::venus.*ESTABLISHED.*[email protected]::NO
|
||||
moon:: cat /var/log/daemon.log::constraint check failed: peer not authenticated by.*Research CA::YES
|
||||
moon:: cat /var/log/daemon.log::selected peer config.*alice.*inacceptable::YES
|
||||
moon:: cat /var/log/daemon.log::selected peer config.*alice.*unacceptable::YES
|
||||
moon:: cat /var/log/daemon.log::switching to peer config.*venus::YES
|
||||
dave:: ipsec status 2> /dev/null::venus.*INSTALLED, TUNNEL::YES
|
||||
moon:: ipsec status 2> /dev/null::venus.*ESTABLISHED.*[email protected]::YES
|
||||
|
||||
@@ -11,7 +11,7 @@ carol::swanctl --list-sas --raw 2> /dev/null::home.*version=2 state=ESTABLISHED.
|
||||
moon:: swanctl --list-sas --raw 2> /dev/null::sales.*version=2 state=ESTABLISHED.*remote-host=192.168.0.100 remote-port=4500 [email protected].*child-sas.*venus.*state=INSTALLED::NO
|
||||
dave:: cat /var/log/daemon.log::received TS_UNACCEPTABLE notify, no CHILD_SA built::YES
|
||||
moon:: cat /var/log/daemon.log::constraint check failed: peer not authenticated by.*Research CA::YES
|
||||
moon:: cat /var/log/daemon.log::selected peer config.*research.*inacceptable::YES
|
||||
moon:: cat /var/log/daemon.log::selected peer config.*research.*unacceptable::YES
|
||||
moon:: cat /var/log/daemon.log::switching to peer config.*sales::YES
|
||||
dave:: swanctl --list-sas --raw 2> /dev/null::home.*version=2 state=ESTABLISHED.*child-sas.*alice.*state=INSTALLED::NO
|
||||
moon:: swanctl --list-sas --raw 2> /dev/null::research.*version=2 state=ESTABLISHED.*remote-host=192.168.0.100 remote-port=4500 [email protected].*child-sas.*alice.*state=INSTALLED::NO
|
||||
|
||||
@@ -11,7 +11,7 @@ connections {
|
||||
id = moon.strongswan.org
|
||||
}
|
||||
children {
|
||||
net-moon {
|
||||
net {
|
||||
local_ts = 10.2.0.0/16
|
||||
remote_ts = 10.1.0.0/16
|
||||
|
||||
@@ -23,27 +23,16 @@ connections {
|
||||
mobike = no
|
||||
proposals = aes128-sha256-x25519
|
||||
}
|
||||
gw-sun {
|
||||
local {
|
||||
auth = pubkey
|
||||
certs = carolCert.pem
|
||||
id = [email protected]
|
||||
}
|
||||
|
||||
gw-sun : connections.gw-moon {
|
||||
remote {
|
||||
auth = pubkey
|
||||
id = sun.strongswan.org
|
||||
}
|
||||
children {
|
||||
net-sun {
|
||||
net {
|
||||
local_ts = 10.1.0.0/16
|
||||
remote_ts = 10.2.0.0/16
|
||||
|
||||
updown = /usr/local/libexec/ipsec/_updown iptables
|
||||
esp_proposals = aes128gcm128-modp3072
|
||||
}
|
||||
}
|
||||
version = 2
|
||||
mobike = no
|
||||
proposals = aes128-sha256-modp3072
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ carol::swanctl --list-sas --raw 2> /dev/null::home.*version=2 state=ESTABLISHED.
|
||||
moon:: swanctl --list-sas --raw 2> /dev/null::sales.*version=2 state=ESTABLISHED.*remote-host=192.168.0.100 remote-port=4500 [email protected].*child-sas.*venus.*state=INSTALLED::NO
|
||||
dave:: cat /var/log/daemon.log::received TS_UNACCEPTABLE notify, no CHILD_SA built::YES
|
||||
moon:: cat /var/log/daemon.log::constraint check failed: peer not authenticated by.*Research CA::YES
|
||||
moon:: cat /var/log/daemon.log::selected peer config.*research.*inacceptable::YES
|
||||
moon:: cat /var/log/daemon.log::selected peer config.*research.*unacceptable::YES
|
||||
moon:: cat /var/log/daemon.log::switching to peer config.*sales::YES
|
||||
dave:: swanctl --list-sas --raw 2> /dev/null::home.*version=2 state=ESTABLISHED.*child-sas.*alice.*state=INSTALLED::NO
|
||||
moon:: swanctl --list-sas --raw 2> /dev/null::research.*version=2 state=ESTABLISHED.*remote-host=192.168.0.100 remote-port=4500 [email protected].*child-sas.*alice.*state=INSTALLED::NO
|
||||
|
||||
Reference in New Issue
Block a user