diff options
Diffstat (limited to 'src/charon/sa/child_sa.c')
-rw-r--r-- | src/charon/sa/child_sa.c | 185 |
1 files changed, 109 insertions, 76 deletions
diff --git a/src/charon/sa/child_sa.c b/src/charon/sa/child_sa.c index 14d174ab5..3fdfb51ad 100644 --- a/src/charon/sa/child_sa.c +++ b/src/charon/sa/child_sa.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2008 Tobias Brunner + * Copyright (C) 2006-2009 Tobias Brunner * Copyright (C) 2005-2008 Martin Willi * Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2005 Jan Hutter @@ -46,67 +46,67 @@ struct private_child_sa_t { * Public interface of child_sa_t. */ child_sa_t public; - + /** * address of us */ host_t *my_addr; - + /** * address of remote */ host_t *other_addr; - + /** * our actually used SPI, 0 if unused */ u_int32_t my_spi; - + /** * others used SPI, 0 if unused */ u_int32_t other_spi; - + /** * our Compression Parameter Index (CPI) used, 0 if unused */ u_int16_t my_cpi; - + /** * others Compression Parameter Index (CPI) used, 0 if unused */ u_int16_t other_cpi; - + /** * List for local traffic selectors */ linked_list_t *my_ts; - + /** * List for remote traffic selectors */ linked_list_t *other_ts; - + /** * Protocol used to protect this SA, ESP|AH */ protocol_id_t protocol; - + /** * reqid used for this child_sa */ u_int32_t reqid; - + /** * absolute time when rekeying is scheduled */ time_t rekey_time; - + /** * absolute time when the SA expires */ time_t expire_time; - + /** * state of the CHILD_SA */ @@ -116,22 +116,22 @@ struct private_child_sa_t { * Specifies if UDP encapsulation is enabled (NAT traversal) */ bool encap; - + /** * Specifies the IPComp transform used (IPCOMP_NONE if disabled) */ ipcomp_transform_t ipcomp; - + /** * mode this SA uses, tunnel/transport */ ipsec_mode_t mode; - + /** - * selected proposal - */ - proposal_t *proposal; - + * selected proposal + */ + proposal_t *proposal; + /** * config used to create this child */ @@ -320,7 +320,7 @@ static bool policy_enumerate(policy_enumerator_t *this, traffic_selector_t **my_out, traffic_selector_t **other_out) { traffic_selector_t *other_ts; - + while (this->ts || this->mine->enumerate(this->mine, &this->ts)) { if (!this->other->enumerate(this->other, &other_ts)) @@ -363,14 +363,14 @@ static void policy_destroy(policy_enumerator_t *this) static enumerator_t* create_policy_enumerator(private_child_sa_t *this) { policy_enumerator_t *e = malloc_thing(policy_enumerator_t); - + e->public.enumerate = (void*)policy_enumerate; e->public.destroy = (void*)policy_destroy; e->mine = this->my_ts->create_enumerator(this->my_ts); e->other = this->other_ts->create_enumerator(this->other_ts); e->list = this->other_ts; e->ts = NULL; - + return &e->public; } @@ -384,7 +384,7 @@ static status_t update_usebytes(private_child_sa_t *this, bool inbound) { status_t status = FAILED; u_int64_t bytes; - + if (inbound) { if (this->my_spi) @@ -434,12 +434,12 @@ static void update_usetime(private_child_sa_t *this, bool inbound) enumerator_t *enumerator; traffic_selector_t *my_ts, *other_ts; u_int32_t last_use = 0; - + enumerator = create_policy_enumerator(this); while (enumerator->enumerate(enumerator, &my_ts, &other_ts)) { u_int32_t in, out, fwd; - + if (inbound) { if (charon->kernel_interface->query_policy(charon->kernel_interface, @@ -507,7 +507,7 @@ static void get_usestats(private_child_sa_t *this, bool inbound, /** * Implementation of child_sa_t.get_lifetime */ -static u_int32_t get_lifetime(private_child_sa_t *this, bool hard) +static time_t get_lifetime(private_child_sa_t *this, bool hard) { return hard ? this->expire_time : this->rekey_time; } @@ -544,14 +544,17 @@ static u_int16_t alloc_cpi(private_child_sa_t *this) * Implementation of child_sa_t.install */ static status_t install(private_child_sa_t *this, chunk_t encr, chunk_t integ, - u_int32_t spi, u_int16_t cpi, bool inbound) + u_int32_t spi, u_int16_t cpi, bool inbound, + linked_list_t *my_ts, linked_list_t *other_ts) { u_int16_t enc_alg = ENCR_UNDEFINED, int_alg = AUTH_UNDEFINED, size; - u_int32_t soft, hard, now; + traffic_selector_t *src_ts = NULL, *dst_ts = NULL; + time_t now; + lifetime_cfg_t *lifetime; host_t *src, *dst; status_t status; bool update = FALSE; - + /* now we have to decide which spi to use. Use self allocated, if "in", * or the one in the proposal, if not "in" (others). Additionally, * source and dest host switch depending on the role */ @@ -573,35 +576,59 @@ static status_t install(private_child_sa_t *this, chunk_t encr, chunk_t integ, this->other_spi = spi; this->other_cpi = cpi; } - + DBG2(DBG_CHD, "adding %s %N SA", inbound ? "inbound" : "outbound", protocol_id_names, this->protocol); - + /* send SA down to the kernel */ DBG2(DBG_CHD, " SPI 0x%.8x, src %H dst %H", ntohl(spi), src, dst); - + this->proposal->get_algorithm(this->proposal, ENCRYPTION_ALGORITHM, &enc_alg, &size); this->proposal->get_algorithm(this->proposal, INTEGRITY_ALGORITHM, &int_alg, &size); - - soft = this->config->get_lifetime(this->config, TRUE); - hard = this->config->get_lifetime(this->config, FALSE); - - status = charon->kernel_interface->add_sa(charon->kernel_interface, - src, dst, spi, this->protocol, this->reqid, - inbound ? soft : 0, hard, enc_alg, encr, int_alg, integ, - this->mode, this->ipcomp, cpi, this->encap, update); - - now = time(NULL); - if (soft) + + lifetime = this->config->get_lifetime(this->config); + + now = time_monotonic(NULL); + if (lifetime->time.rekey) { - this->rekey_time = now + soft; + this->rekey_time = now + lifetime->time.rekey; } - if (hard) + if (lifetime->time.life) + { + this->expire_time = now + lifetime->time.life; + } + + if (!lifetime->time.jitter && !inbound) + { /* avoid triggering multiple rekey events */ + lifetime->time.rekey = 0; + } + + if (this->mode == MODE_BEET) { - this->expire_time = now + hard; + /* 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); + } } + + status = charon->kernel_interface->add_sa(charon->kernel_interface, + src, dst, spi, this->protocol, this->reqid, lifetime, + enc_alg, encr, int_alg, integ, this->mode, this->ipcomp, cpi, + this->encap, update, src_ts, dst_ts); + + free(lifetime); + return status; } @@ -615,7 +642,7 @@ static status_t add_policies(private_child_sa_t *this, traffic_selector_t *my_ts, *other_ts; status_t status = SUCCESS; bool routed = (this->state == CHILD_CREATED); - + /* apply traffic selectors */ enumerator = my_ts_list->create_enumerator(my_ts_list); while (enumerator->enumerate(enumerator, &my_ts)) @@ -629,7 +656,7 @@ static status_t add_policies(private_child_sa_t *this, this->other_ts->insert_last(this->other_ts, other_ts->clone(other_ts)); } enumerator->destroy(enumerator); - + if (this->config->install_policy(this->config)) { /* enumerate pairs of traffic selectors */ @@ -641,7 +668,7 @@ static status_t add_policies(private_child_sa_t *this, this->my_addr, this->other_addr, my_ts, other_ts, POLICY_OUT, this->other_spi, this->protocol, this->reqid, this->mode, this->ipcomp, this->other_cpi, routed); - + status |= charon->kernel_interface->add_policy(charon->kernel_interface, this->other_addr, this->my_addr, other_ts, my_ts, POLICY_IN, this->my_spi, this->protocol, this->reqid, this->mode, @@ -653,7 +680,7 @@ static status_t add_policies(private_child_sa_t *this, this->my_spi, this->protocol, this->reqid, this->mode, this->ipcomp, this->my_cpi, routed); } - + if (status != SUCCESS) { break; @@ -661,7 +688,7 @@ static status_t add_policies(private_child_sa_t *this, } enumerator->destroy(enumerator); } - + if (status == SUCCESS && this->state == CHILD_CREATED) { /* switch to routed state if no SAD entry set up */ set_state(this, CHILD_ROUTED); @@ -677,19 +704,19 @@ static status_t update(private_child_sa_t *this, host_t *me, host_t *other, { child_sa_state_t old; bool transport_proxy_mode; - + /* anything changed at all? */ if (me->equals(me, this->my_addr) && other->equals(other, this->other_addr) && this->encap == encap) { return SUCCESS; } - + old = this->state; set_state(this, CHILD_UPDATING); transport_proxy_mode = this->config->use_proxy_mode(this->config) && this->mode == MODE_TRANSPORT; - + if (!transport_proxy_mode) { /* update our (initator) SA */ @@ -704,13 +731,13 @@ static status_t update(private_child_sa_t *this, host_t *me, host_t *other, return NOT_SUPPORTED; } } - + /* update his (responder) SA */ if (this->other_spi) { if (charon->kernel_interface->update_sa(charon->kernel_interface, this->other_spi, this->protocol, - this->ipcomp != IPCOMP_NONE ? this->other_cpi : 0, + this->ipcomp != IPCOMP_NONE ? this->other_cpi : 0, this->my_addr, this->other_addr, me, other, this->encap, encap) == NOT_SUPPORTED) { @@ -718,7 +745,7 @@ static status_t update(private_child_sa_t *this, host_t *me, host_t *other, } } } - + if (this->config->install_policy(this->config)) { /* update policies */ @@ -727,7 +754,7 @@ static status_t update(private_child_sa_t *this, host_t *me, host_t *other, { enumerator_t *enumerator; traffic_selector_t *my_ts, *other_ts; - + /* always use high priorities, as hosts getting updated are INSTALLED */ enumerator = create_policy_enumerator(this); while (enumerator->enumerate(enumerator, &my_ts, &other_ts)) @@ -742,7 +769,7 @@ static status_t update(private_child_sa_t *this, host_t *me, host_t *other, charon->kernel_interface->del_policy(charon->kernel_interface, other_ts, my_ts, POLICY_FWD, FALSE); } - + /* check whether we have to update a "dynamic" traffic selector */ if (!me->ip_equals(me, this->my_addr) && my_ts->is_host(my_ts, this->my_addr)) @@ -754,7 +781,7 @@ static status_t update(private_child_sa_t *this, host_t *me, host_t *other, { other_ts->set_address(other_ts, other); } - + /* we reinstall the virtual IP to handle interface roaming * correctly */ if (vip) @@ -762,7 +789,7 @@ static status_t update(private_child_sa_t *this, host_t *me, host_t *other, charon->kernel_interface->del_ip(charon->kernel_interface, vip); charon->kernel_interface->add_ip(charon->kernel_interface, vip, me); } - + /* reinstall updated policies */ charon->kernel_interface->add_policy(charon->kernel_interface, me, other, my_ts, other_ts, POLICY_OUT, this->other_spi, @@ -813,12 +840,18 @@ static void destroy(private_child_sa_t *this) enumerator_t *enumerator; traffic_selector_t *my_ts, *other_ts; bool unrouted = (this->state == CHILD_ROUTED); - + set_state(this, CHILD_DESTROYING); - + /* delete SAs in the kernel, if they are set up */ if (this->my_spi) { + /* if CHILD was not established, use PROTO_ESP used during alloc_spi(). + * TODO: For AH support, we have to store protocol specific SPI.s */ + if (this->protocol == PROTO_NONE) + { + this->protocol = PROTO_ESP; + } charon->kernel_interface->del_sa(charon->kernel_interface, this->other_addr, this->my_addr, this->my_spi, this->protocol, this->my_cpi); @@ -829,7 +862,7 @@ static void destroy(private_child_sa_t *this) this->my_addr, this->other_addr, this->other_spi, this->protocol, this->other_cpi); } - + if (this->config->install_policy(this->config)) { /* delete all policies in the kernel */ @@ -848,7 +881,7 @@ static void destroy(private_child_sa_t *this) } 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)); this->my_addr->destroy(this->my_addr); @@ -881,20 +914,20 @@ child_sa_t * child_sa_create(host_t *me, host_t* other, this->public.set_mode = (void(*)(child_sa_t*, ipsec_mode_t mode))set_mode; this->public.get_proposal = (proposal_t*(*)(child_sa_t*))get_proposal; this->public.set_proposal = (void(*)(child_sa_t*, proposal_t *proposal))set_proposal; - this->public.get_lifetime = (u_int32_t(*)(child_sa_t*, bool))get_lifetime; + this->public.get_lifetime = (time_t(*)(child_sa_t*, bool))get_lifetime; this->public.get_usestats = (void(*)(child_sa_t*,bool,time_t*,u_int64_t*))get_usestats; this->public.has_encap = (bool(*)(child_sa_t*))has_encap; this->public.get_ipcomp = (ipcomp_transform_t(*)(child_sa_t*))get_ipcomp; this->public.set_ipcomp = (void(*)(child_sa_t*,ipcomp_transform_t))set_ipcomp; this->public.alloc_spi = (u_int32_t(*)(child_sa_t*, protocol_id_t protocol))alloc_spi; this->public.alloc_cpi = (u_int16_t(*)(child_sa_t*))alloc_cpi; - this->public.install = (status_t(*)(child_sa_t*, chunk_t encr, chunk_t integ, u_int32_t spi, u_int16_t cpi, bool inbound))install; + this->public.install = (status_t(*)(child_sa_t*, chunk_t encr, chunk_t integ, u_int32_t spi, u_int16_t cpi, bool inbound, linked_list_t *my_ts_list, linked_list_t *other_ts_list))install; this->public.update = (status_t (*)(child_sa_t*,host_t*,host_t*,host_t*,bool))update; this->public.add_policies = (status_t (*)(child_sa_t*, linked_list_t*,linked_list_t*))add_policies; this->public.get_traffic_selectors = (linked_list_t*(*)(child_sa_t*,bool))get_traffic_selectors; this->public.create_policy_enumerator = (enumerator_t*(*)(child_sa_t*))create_policy_enumerator; this->public.destroy = (void(*)(child_sa_t*))destroy; - + /* private data */ this->my_addr = me->clone(me); this->other_addr = other->clone(other); @@ -920,10 +953,10 @@ child_sa_t * child_sa_create(host_t *me, host_t* other, this->expire_time = 0; this->config = config; config->get_ref(config); - + /* MIPv6 proxy transport mode sets SA endpoints to TS hosts */ if (config->get_mode(config) == MODE_TRANSPORT && - config->use_proxy_mode(config)) + config->use_proxy_mode(config)) { ts_type_t type; int family; @@ -932,9 +965,9 @@ child_sa_t * child_sa_create(host_t *me, host_t* other, enumerator_t *enumerator; linked_list_t *my_ts_list, *other_ts_list; traffic_selector_t *my_ts, *other_ts; - + this->mode = MODE_TRANSPORT; - + my_ts_list = config->get_traffic_selectors(config, TRUE, NULL, me); enumerator = my_ts_list->create_enumerator(my_ts_list); if (enumerator->enumerate(enumerator, &my_ts)) @@ -955,7 +988,7 @@ child_sa_t * child_sa_create(host_t *me, host_t* other, } enumerator->destroy(enumerator); my_ts_list->destroy_offset(my_ts_list, offsetof(traffic_selector_t, destroy)); - + other_ts_list = config->get_traffic_selectors(config, FALSE, NULL, other); enumerator = other_ts_list->create_enumerator(other_ts_list); if (enumerator->enumerate(enumerator, &other_ts)) @@ -977,6 +1010,6 @@ child_sa_t * child_sa_create(host_t *me, host_t* other, enumerator->destroy(enumerator); other_ts_list->destroy_offset(other_ts_list, offsetof(traffic_selector_t, destroy)); } - + return &this->public; } |