child-cfg: Use traffic selector list

This commit is contained in:
Tobias Brunner
2025-05-28 11:06:19 +02:00
parent 4b468126ca
commit ad1ad2159f
2 changed files with 70 additions and 178 deletions
+45 -174
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2008-2019 Tobias Brunner
* Copyright (C) 2008-2025 Tobias Brunner
* Copyright (C) 2016 Andreas Steffen
* Copyright (C) 2005-2007 Martin Willi
* Copyright (C) 2005 Jan Hutter
@@ -67,12 +67,12 @@ struct private_child_cfg_t {
/**
* list for traffic selectors for my site
*/
linked_list_t *my_ts;
traffic_selector_list_t *my_ts;
/**
* list for traffic selectors for others site
*/
linked_list_t *other_ts;
traffic_selector_list_t *other_ts;
/**
* updown script
@@ -258,115 +258,56 @@ METHOD(child_cfg_t, add_traffic_selector, void,
{
if (local)
{
this->my_ts->insert_last(this->my_ts, ts);
this->my_ts->add(this->my_ts, ts);
}
else
{
this->other_ts->insert_last(this->other_ts, ts);
this->other_ts->add(this->other_ts, ts);
}
}
/**
* Create a copy of the traffic selectors in the given list, while resolving
* "dynamic" traffic selectors using the given hosts, if any. When not narrowing
* as initiator, we also replace TS in transport mode.
* Check whether the config is for regular transport mode.
*/
static linked_list_t *resolve_dynamic_ts(private_child_cfg_t *this,
linked_list_t *list,
linked_list_t *hosts,
bool narrowing)
static bool is_transport_mode(private_child_cfg_t *this)
{
enumerator_t *e1, *e2;
traffic_selector_t *ts1, *ts2;
linked_list_t *result;
host_t *host;
bool transport_mode;
if (!hosts || !hosts->get_count(hosts))
{
return list->clone_offset(list, offsetof(traffic_selector_t, clone));
}
transport_mode = !narrowing && this->mode == MODE_TRANSPORT &&
!has_option(this, OPT_PROXY_MODE);
result = linked_list_create();
e1 = list->create_enumerator(list);
while (e1->enumerate(e1, &ts1))
{
/* set hosts if TS is dynamic or as initiator in transport mode */
bool dynamic = ts1->is_dynamic(ts1);
if (!dynamic && !transport_mode)
{
result->insert_last(result, ts1->clone(ts1));
continue;
}
e2 = hosts->create_enumerator(hosts);
while (e2->enumerate(e2, &host))
{
if (!dynamic && !host->is_anyaddr(host) &&
!ts1->includes(ts1, host))
{ /* for transport mode, we skip TS that don't match
* specific IPs */
continue;
}
ts2 = ts1->clone(ts1);
if (dynamic || !host->is_anyaddr(host))
{ /* don't make regular TS larger than they were */
ts2->set_address(ts2, host);
}
result->insert_last(result, ts2);
}
e2->destroy(e2);
}
e1->destroy(e1);
return result;
}
/**
* Remove duplicate traffic selectors in the given list.
*/
static void remove_duplicate_ts(linked_list_t *list)
{
enumerator_t *e1, *e2;
traffic_selector_t *ts1, *ts2;
e1 = list->create_enumerator(list);
e2 = list->create_enumerator(list);
while (e1->enumerate(e1, &ts1))
{
while (e2->enumerate(e2, &ts2))
{
if (ts1 != ts2)
{
if (ts2->is_contained_in(ts2, ts1))
{
list->remove_at(list, e2);
ts2->destroy(ts2);
list->reset_enumerator(list, e1);
break;
}
if (ts1->is_contained_in(ts1, ts2))
{
list->remove_at(list, e1);
ts1->destroy(ts1);
break;
}
}
}
list->reset_enumerator(list, e2);
}
e1->destroy(e1);
e2->destroy(e2);
return this->mode == MODE_TRANSPORT && !has_option(this, OPT_PROXY_MODE);
}
METHOD(child_cfg_t, get_traffic_selectors, linked_list_t*,
private_child_cfg_t *this, bool local, linked_list_t *hosts)
{
linked_list_t *result;
traffic_selector_list_t *ts = local ? this->my_ts : this->other_ts;
result = resolve_dynamic_ts(this, local ? this->my_ts : this->other_ts,
hosts, FALSE);
remove_duplicate_ts(result);
/* force replacing non-dynamic TS to the IPs in transport mode */
return ts->get(ts, hosts, is_transport_mode(this));
}
/*
* Described in header
*/
linked_list_t *child_cfg_select_ts(child_cfg_t *cfg, bool local,
traffic_selector_list_t *list,
linked_list_t *supplied, linked_list_t *hosts)
{
private_child_cfg_t *this = (private_child_cfg_t*)cfg;
traffic_selector_list_t *ts = list ?: (local ? this->my_ts : this->other_ts);
linked_list_t *result;
bool force, narrowed = FALSE;
DBG2(DBG_CFG, "%s traffic selectors for %s:",
supplied ? "selecting" : "proposing", local ? "us" : "other");
/* force replacing non-dynamic TS to the IPs in transport mode, but only
* when proposing as initiator */
force = supplied && is_transport_mode(this);
result = ts->select(ts, supplied, hosts, force, &narrowed);
if (narrowed)
{
charon->bus->alert(charon->bus, ALERT_TS_NARROWED,
local, result, this);
}
return result;
}
@@ -374,72 +315,7 @@ METHOD(child_cfg_t, select_traffic_selectors, linked_list_t*,
private_child_cfg_t *this, bool local, linked_list_t *supplied,
linked_list_t *hosts)
{
enumerator_t *e1, *e2;
traffic_selector_t *ts1, *ts2, *selected;
linked_list_t *resolved, *result;
result = linked_list_create();
resolved = resolve_dynamic_ts(this, local ? this->my_ts : this->other_ts,
hosts, supplied);
DBG2(DBG_CFG, "%s traffic selectors for %s:",
supplied ? "selecting" : "proposing", local ? "us" : "other");
if (!supplied)
{
while (resolved->remove_first(resolved, (void**)&ts1) == SUCCESS)
{
DBG2(DBG_CFG, " %R", ts1);
result->insert_last(result, ts1);
}
}
else
{
e1 = resolved->create_enumerator(resolved);
e2 = supplied->create_enumerator(supplied);
/* enumerate all configured/resolved selectors */
while (e1->enumerate(e1, &ts1))
{
/* enumerate all supplied traffic selectors */
while (e2->enumerate(e2, &ts2))
{
selected = ts1->get_subset(ts1, ts2);
if (selected)
{
DBG2(DBG_CFG, " config: %R, received: %R => match: %R",
ts1, ts2, selected);
result->insert_last(result, selected);
}
else
{
DBG2(DBG_CFG, " config: %R, received: %R => no match",
ts1, ts2);
}
}
supplied->reset_enumerator(supplied, e2);
}
e1->destroy(e1);
e2->destroy(e2);
/* check if we/peer did any narrowing, raise alert */
e1 = resolved->create_enumerator(resolved);
e2 = result->create_enumerator(result);
while (e1->enumerate(e1, &ts1))
{
if (!e2->enumerate(e2, &ts2) || !ts1->equals(ts1, ts2))
{
charon->bus->alert(charon->bus, ALERT_TS_NARROWED,
local, result, this);
break;
}
}
e1->destroy(e1);
e2->destroy(e2);
}
resolved->destroy_offset(resolved, offsetof(traffic_selector_t, destroy));
remove_duplicate_ts(result);
return result;
return child_cfg_select_ts(&this->public, local, NULL, supplied, hosts);
}
METHOD(child_cfg_t, get_updown, char*,
@@ -706,13 +582,8 @@ METHOD(child_cfg_t, equals, bool,
{
return FALSE;
}
if (!this->my_ts->equals_offset(this->my_ts, other->my_ts,
offsetof(traffic_selector_t, equals)))
{
return FALSE;
}
if (!this->other_ts->equals_offset(this->other_ts, other->other_ts,
offsetof(traffic_selector_t, equals)))
if (!this->my_ts->equals(this->my_ts, other->my_ts) ||
!this->other_ts->equals(this->other_ts, other->other_ts))
{
return FALSE;
}
@@ -758,8 +629,8 @@ METHOD(child_cfg_t, destroy, void,
if (ref_put(&this->refcount))
{
this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
this->my_ts->destroy_offset(this->my_ts, offsetof(traffic_selector_t, destroy));
this->other_ts->destroy_offset(this->other_ts, offsetof(traffic_selector_t, destroy));
this->my_ts->destroy(this->my_ts);
this->other_ts->destroy(this->other_ts);
DESTROY_IF(this->label);
free(this->updown);
free(this->interface);
@@ -835,8 +706,8 @@ child_cfg_t *child_cfg_create(char *name, child_cfg_create_t *data)
.interface = strdupnull(data->interface),
.refcount = 1,
.proposals = linked_list_create(),
.my_ts = linked_list_create(),
.other_ts = linked_list_create(),
.my_ts = traffic_selector_list_create(),
.other_ts = traffic_selector_list_create(),
.replay_window = lib->settings->get_int(lib->settings,
"%s.replay_window", DEFAULT_REPLAY_WINDOW, lib->ns),
.hw_offload = data->hw_offload,
+25 -4
View File
@@ -32,6 +32,7 @@ typedef struct child_cfg_create_t child_cfg_create_t;
#include <library.h>
#include <selectors/traffic_selector.h>
#include <selectors/traffic_selector_list.h>
#include <crypto/proposal/proposal.h>
#include <kernel/kernel_ipsec.h>
@@ -121,12 +122,12 @@ struct child_cfg_t {
/**
* Get a list of configured traffic selectors to use for the CHILD_SA.
*
* The config contains two set of traffic selectors, one for the local
* The config contains two sets of traffic selectors, one for the local
* side, one for the remote side.
*
* Some traffic selectors may be "dynamic", meaning they are narrowed down
* to a specific address (host-to-host or virtual-IP setups). Use the
* "hosts" parameter to narrow such traffic selectors to an address.
* \p hosts parameter to narrow such traffic selectors to an address.
*
* Returned list and its traffic selectors must be destroyed after use.
*
@@ -143,7 +144,7 @@ struct child_cfg_t {
/**
* Select a list of traffic selectors to use for the CHILD_SA.
*
* The config contains two set of traffic selectors, one for the local
* The config contains two sets of traffic selectors, one for the local
* side, one for the remote side.
*
* If a list with traffic selectors is supplied, these are used to narrow
@@ -151,10 +152,13 @@ struct child_cfg_t {
*
* Some traffic selectors may be "dynamic", meaning they are narrowed down
* to a specific address (host-to-host or virtual-IP setups). Use the
* "hosts" parameter to narrow such traffic selectors to an address.
* \p hosts parameter to narrow such traffic selectors to an address.
*
* Returned list and its traffic selectors must be destroyed after use.
*
* Details about the selection process are logged and an alert is triggered
* if narrowing occurred.
*
* @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
@@ -473,4 +477,21 @@ struct child_cfg_create_t {
*/
child_cfg_t *child_cfg_create(char *name, child_cfg_create_t *data);
/**
* Select and narrow traffic selectors in the given traffic selector list.
* Refer to child_cfg_t::select_traffic_selectors() for details, the difference
* is that this can work with external traffic selector lists.
*
* @param this config to use
* @param local TRUE for TS on local side, FALSE for remote (also
* used for logging)
* @param list traffic selectors to use instead of those in config
* @param supplied list with TS to select from, or NULL
* @param hosts addresses to use for narrowing "dynamic" TS', host_t
* @return list containing the traffic selectors
*/
linked_list_t *child_cfg_select_ts(child_cfg_t *this, bool local,
traffic_selector_list_t *list,
linked_list_t *supplied, linked_list_t *hosts);
#endif /** CHILD_CFG_H_ @}*/