summaryrefslogtreecommitdiff
path: root/src/libcharon/sa/child_sa.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcharon/sa/child_sa.c')
-rw-r--r--src/libcharon/sa/child_sa.c221
1 files changed, 119 insertions, 102 deletions
diff --git a/src/libcharon/sa/child_sa.c b/src/libcharon/sa/child_sa.c
index 463ad2e22..46e4b6f7b 100644
--- a/src/libcharon/sa/child_sa.c
+++ b/src/libcharon/sa/child_sa.c
@@ -25,6 +25,7 @@
#include <hydra.h>
#include <daemon.h>
+#include <collections/array.h>
ENUM(child_sa_state_names, CHILD_CREATED, CHILD_DESTROYING,
"CREATED",
@@ -79,14 +80,14 @@ struct private_child_sa_t {
u_int16_t other_cpi;
/**
- * List for local traffic selectors
+ * Array for local traffic selectors
*/
- linked_list_t *my_ts;
+ array_t *my_ts;
/**
- * List for remote traffic selectors
+ * Array for remote traffic selectors
*/
- linked_list_t *other_ts;
+ array_t *other_ts;
/**
* Protocol used to protect this SA, ESP|AH
@@ -331,10 +332,14 @@ METHOD(child_sa_t, set_proposal, void,
this->proposal = proposal->clone(proposal);
}
-METHOD(child_sa_t, get_traffic_selectors, linked_list_t*,
- private_child_sa_t *this, bool local)
+METHOD(child_sa_t, create_ts_enumerator, enumerator_t*,
+ private_child_sa_t *this, bool local)
{
- return local ? this->my_ts : this->other_ts;
+ if (local)
+ {
+ return array_create_enumerator(this->my_ts);
+ }
+ return array_create_enumerator(this->other_ts);
}
typedef struct policy_enumerator_t policy_enumerator_t;
@@ -349,8 +354,8 @@ struct policy_enumerator_t {
enumerator_t *mine;
/** enumerator over others TS */
enumerator_t *other;
- /** list of others TS, to recreate enumerator */
- linked_list_t *list;
+ /** array of others TS, to recreate enumerator */
+ array_t *array;
/** currently enumerating TS for "me" side */
traffic_selector_t *ts;
};
@@ -366,7 +371,7 @@ METHOD(enumerator_t, policy_enumerate, bool,
if (!this->other->enumerate(this->other, &other_ts))
{ /* end of others list, restart with new of mine */
this->other->destroy(this->other);
- this->other = this->list->create_enumerator(this->list);
+ this->other = array_create_enumerator(this->array);
this->ts = NULL;
continue;
}
@@ -405,9 +410,9 @@ METHOD(child_sa_t, create_policy_enumerator, enumerator_t*,
.enumerate = (void*)_policy_enumerate,
.destroy = _policy_destroy,
},
- .mine = this->my_ts->create_enumerator(this->my_ts),
- .other = this->other_ts->create_enumerator(this->other_ts),
- .list = this->other_ts,
+ .mine = array_create_enumerator(this->my_ts),
+ .other = array_create_enumerator(this->other_ts),
+ .array = this->other_ts,
.ts = NULL,
);
@@ -424,6 +429,7 @@ static status_t update_usebytes(private_child_sa_t *this, bool inbound)
{
status_t status = FAILED;
u_int64_t bytes, packets;
+ u_int32_t time;
if (inbound)
{
@@ -432,13 +438,17 @@ static status_t update_usebytes(private_child_sa_t *this, bool inbound)
status = hydra->kernel_interface->query_sa(hydra->kernel_interface,
this->other_addr, this->my_addr, this->my_spi,
proto_ike2ip(this->protocol), this->mark_in,
- &bytes, &packets);
+ &bytes, &packets, &time);
if (status == SUCCESS)
{
if (bytes > this->my_usebytes)
{
this->my_usebytes = bytes;
this->my_usepackets = packets;
+ if (time)
+ {
+ this->my_usetime = time;
+ }
return SUCCESS;
}
return FAILED;
@@ -452,13 +462,17 @@ static status_t update_usebytes(private_child_sa_t *this, bool inbound)
status = hydra->kernel_interface->query_sa(hydra->kernel_interface,
this->my_addr, this->other_addr, this->other_spi,
proto_ike2ip(this->protocol), this->mark_out,
- &bytes, &packets);
+ &bytes, &packets, &time);
if (status == SUCCESS)
{
if (bytes > this->other_usebytes)
{
this->other_usebytes = bytes;
this->other_usepackets = packets;
+ if (time)
+ {
+ this->other_usetime = time;
+ }
return SUCCESS;
}
return FAILED;
@@ -471,7 +485,7 @@ static status_t update_usebytes(private_child_sa_t *this, bool inbound)
/**
* updates the cached usetime
*/
-static void update_usetime(private_child_sa_t *this, bool inbound)
+static bool update_usetime(private_child_sa_t *this, bool inbound)
{
enumerator_t *enumerator;
traffic_selector_t *my_ts, *other_ts;
@@ -511,7 +525,7 @@ static void update_usetime(private_child_sa_t *this, bool inbound)
if (last_use == 0)
{
- return;
+ return FALSE;
}
if (inbound)
{
@@ -521,18 +535,26 @@ static void update_usetime(private_child_sa_t *this, bool inbound)
{
this->other_usetime = last_use;
}
+ return TRUE;
}
METHOD(child_sa_t, get_usestats, void,
private_child_sa_t *this, bool inbound,
time_t *time, u_int64_t *bytes, u_int64_t *packets)
{
- if (update_usebytes(this, inbound) != FAILED)
+ if ((!bytes && !packets) || update_usebytes(this, inbound) != FAILED)
{
/* there was traffic since last update or the kernel interface
* does not support querying the number of usebytes.
*/
- update_usetime(this, inbound);
+ if (time)
+ {
+ if (!update_usetime(this, inbound) && !bytes && !packets)
+ {
+ /* if policy query did not yield a usetime, query SAs instead */
+ update_usebytes(this, inbound);
+ }
+ }
}
if (time)
{
@@ -590,9 +612,9 @@ METHOD(child_sa_t, alloc_cpi, u_int16_t,
}
METHOD(child_sa_t, install, status_t,
- private_child_sa_t *this, chunk_t encr, chunk_t integ, u_int32_t spi,
- u_int16_t cpi, bool inbound, bool tfcv3, linked_list_t *my_ts,
- linked_list_t *other_ts)
+ private_child_sa_t *this, chunk_t encr, chunk_t integ, u_int32_t spi,
+ u_int16_t cpi, bool initiator, bool inbound, bool tfcv3,
+ linked_list_t *my_ts, linked_list_t *other_ts)
{
u_int16_t enc_alg = ENCR_UNDEFINED, int_alg = AUTH_UNDEFINED, size;
u_int16_t esn = NO_EXT_SEQ_NUMBERS;
@@ -668,28 +690,26 @@ METHOD(child_sa_t, install, status_t,
lifetime->time.rekey = 0;
}
- if (this->mode == MODE_BEET || this->mode == MODE_TRANSPORT)
+ /* BEET requires the bound address from the traffic selectors.
+ * TODO: We add just the first traffic selector for now, as the
+ * kernel accepts a single TS per SA only */
+ if (inbound)
{
- /* BEET requires the bound address from the traffic selectors.
- * TODO: We add just the first traffic selector for now, as the
- * kernel accepts a single TS per SA only */
- if (inbound)
- {
- my_ts->get_first(my_ts, (void**)&dst_ts);
- other_ts->get_first(other_ts, (void**)&src_ts);
- }
- else
- {
- my_ts->get_first(my_ts, (void**)&src_ts);
- other_ts->get_first(other_ts, (void**)&dst_ts);
- }
+ my_ts->get_first(my_ts, (void**)&dst_ts);
+ other_ts->get_first(other_ts, (void**)&src_ts);
+ }
+ else
+ {
+ my_ts->get_first(my_ts, (void**)&src_ts);
+ other_ts->get_first(other_ts, (void**)&dst_ts);
}
status = hydra->kernel_interface->add_sa(hydra->kernel_interface,
src, dst, spi, proto_ike2ip(this->protocol), this->reqid,
inbound ? this->mark_in : this->mark_out, tfc,
lifetime, enc_alg, encr, int_alg, integ, this->mode,
- this->ipcomp, cpi, this->encap, esn, update, src_ts, dst_ts);
+ this->ipcomp, cpi, initiator, this->encap, esn, update,
+ src_ts, dst_ts);
free(lifetime);
@@ -757,13 +777,13 @@ METHOD(child_sa_t, add_policies, status_t,
enumerator = my_ts_list->create_enumerator(my_ts_list);
while (enumerator->enumerate(enumerator, &my_ts))
{
- this->my_ts->insert_last(this->my_ts, my_ts->clone(my_ts));
+ array_insert(this->my_ts, ARRAY_TAIL, my_ts->clone(my_ts));
}
enumerator->destroy(enumerator);
enumerator = other_ts_list->create_enumerator(other_ts_list);
while (enumerator->enumerate(enumerator, &other_ts))
{
- this->other_ts->insert_last(this->other_ts, other_ts->clone(other_ts));
+ array_insert(this->other_ts, ARRAY_TAIL, other_ts->clone(other_ts));
}
enumerator->destroy(enumerator);
@@ -1054,8 +1074,8 @@ METHOD(child_sa_t, destroy, void,
enumerator->destroy(enumerator);
}
- 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));
+ array_destroy_offset(this->my_ts, offsetof(traffic_selector_t, destroy));
+ array_destroy_offset(this->other_ts, offsetof(traffic_selector_t, destroy));
this->my_addr->destroy(this->my_addr);
this->other_addr->destroy(this->other_addr);
DESTROY_IF(this->proposal);
@@ -1064,12 +1084,47 @@ METHOD(child_sa_t, destroy, void,
}
/**
+ * Get proxy address for one side, if any
+ */
+static host_t* get_proxy_addr(child_cfg_t *config, host_t *ike, bool local)
+{
+ host_t *host = NULL;
+ u_int8_t mask;
+ enumerator_t *enumerator;
+ linked_list_t *ts_list, *list;
+ traffic_selector_t *ts;
+
+ list = linked_list_create_with_items(ike, NULL);
+ ts_list = config->get_traffic_selectors(config, local, NULL, list);
+ list->destroy(list);
+
+ enumerator = ts_list->create_enumerator(ts_list);
+ while (enumerator->enumerate(enumerator, &ts))
+ {
+ if (ts->is_host(ts, NULL) && ts->to_subnet(ts, &host, &mask))
+ {
+ DBG1(DBG_CHD, "%s address: %H is a transport mode proxy for %H",
+ local ? "my" : "other", ike, host);
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ ts_list->destroy_offset(ts_list, offsetof(traffic_selector_t, destroy));
+
+ if (!host)
+ {
+ host = ike->clone(ike);
+ }
+ return host;
+}
+
+/**
* Described in header.
*/
child_sa_t * child_sa_create(host_t *me, host_t* other,
child_cfg_t *config, u_int32_t rekey, bool encap)
{
- static u_int32_t reqid = 0;
+ static refcount_t reqid = 0;
private_child_sa_t *this;
INIT(this,
@@ -1102,17 +1157,15 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
.install = _install,
.update = _update,
.add_policies = _add_policies,
- .get_traffic_selectors = _get_traffic_selectors,
+ .create_ts_enumerator = _create_ts_enumerator,
.create_policy_enumerator = _create_policy_enumerator,
.destroy = _destroy,
},
- .my_addr = me->clone(me),
- .other_addr = other->clone(other),
.encap = encap,
.ipcomp = IPCOMP_NONE,
.state = CHILD_CREATED,
- .my_ts = linked_list_create(),
- .other_ts = linked_list_create(),
+ .my_ts = array_create(0, 0),
+ .other_ts = array_create(0, 0),
.protocol = PROTO_NONE,
.mode = MODE_TUNNEL,
.close_action = config->get_close_action(config),
@@ -1128,7 +1181,18 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
if (!this->reqid)
{
/* reuse old reqid if we are rekeying an existing CHILD_SA */
- this->reqid = rekey ? rekey : ++reqid;
+ if (rekey)
+ {
+ this->reqid = rekey;
+ }
+ else
+ {
+ this->reqid = charon->traps->find_reqid(charon->traps, config);
+ if (!this->reqid)
+ {
+ this->reqid = ref_get(&reqid);
+ }
+ }
}
if (this->mark_in.value == MARK_REQID)
@@ -1144,62 +1208,15 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
if (config->get_mode(config) == MODE_TRANSPORT &&
config->use_proxy_mode(config))
{
- ts_type_t type;
- int family;
- chunk_t addr;
- host_t *host;
- enumerator_t *enumerator;
- linked_list_t *my_ts_list, *other_ts_list, *list;
- traffic_selector_t *my_ts, *other_ts;
-
this->mode = MODE_TRANSPORT;
- list = linked_list_create_with_items(me, NULL);
- my_ts_list = config->get_traffic_selectors(config, TRUE, NULL, list);
- list->destroy(list);
- enumerator = my_ts_list->create_enumerator(my_ts_list);
- if (enumerator->enumerate(enumerator, &my_ts))
- {
- if (my_ts->is_host(my_ts, NULL) &&
- !my_ts->is_host(my_ts, this->my_addr))
- {
- type = my_ts->get_type(my_ts);
- family = (type == TS_IPV4_ADDR_RANGE) ? AF_INET : AF_INET6;
- addr = my_ts->get_from_address(my_ts);
- host = host_create_from_chunk(family, addr, 0);
- free(addr.ptr);
- DBG1(DBG_CHD, "my address: %H is a transport mode proxy for %H",
- this->my_addr, host);
- this->my_addr->destroy(this->my_addr);
- this->my_addr = host;
- }
- }
- enumerator->destroy(enumerator);
- my_ts_list->destroy_offset(my_ts_list, offsetof(traffic_selector_t, destroy));
-
- list = linked_list_create_with_items(other, NULL);
- other_ts_list = config->get_traffic_selectors(config, FALSE, NULL, list);
- list->destroy(list);
- enumerator = other_ts_list->create_enumerator(other_ts_list);
- if (enumerator->enumerate(enumerator, &other_ts))
- {
- if (other_ts->is_host(other_ts, NULL) &&
- !other_ts->is_host(other_ts, this->other_addr))
- {
- type = other_ts->get_type(other_ts);
- family = (type == TS_IPV4_ADDR_RANGE) ? AF_INET : AF_INET6;
- addr = other_ts->get_from_address(other_ts);
- host = host_create_from_chunk(family, addr, 0);
- free(addr.ptr);
- DBG1(DBG_CHD, "other address: %H is a transport mode proxy for %H",
- this->other_addr, host);
- this->other_addr->destroy(this->other_addr);
- this->other_addr = host;
- }
- }
- enumerator->destroy(enumerator);
- other_ts_list->destroy_offset(other_ts_list, offsetof(traffic_selector_t, destroy));
+ this->my_addr = get_proxy_addr(config, me, TRUE);
+ this->other_addr = get_proxy_addr(config, other, FALSE);
+ }
+ else
+ {
+ this->my_addr = me->clone(me);
+ this->other_addr = other->clone(other);
}
-
return &this->public;
}