From: Martin Willi Date: Wed, 19 Nov 2008 15:31:27 +0000 (-0000) Subject: refactored and cleaned up child_sa interface X-Git-Tag: 4.2.10~107 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3aaf7908d1dd0cadf2a85585ce21c7f42df830f5;p=thirdparty%2Fstrongswan.git refactored and cleaned up child_sa interface replaced add/update calls by a install() call allocating SPIs always externally support installation of non-allocated CHILD_SAs some other cleanups --- diff --git a/src/charon/processing/jobs/migrate_job.c b/src/charon/processing/jobs/migrate_job.c index 92bdac04fd..e52b91cfe2 100644 --- a/src/charon/processing/jobs/migrate_job.c +++ b/src/charon/processing/jobs/migrate_job.c @@ -110,7 +110,7 @@ static void execute(private_migrate_job_t *this) host->set_port(host, IKEV2_UDP_PORT); ike_sa->set_other_host(ike_sa, host); - if (child_sa->update_hosts(child_sa, this->local, this->remote, + if (child_sa->update(child_sa, this->local, this->remote, ike_sa->get_virtual_ip(ike_sa, TRUE), ike_sa->has_condition(ike_sa, COND_NAT_ANY)) == NOT_SUPPORTED) { diff --git a/src/charon/sa/child_sa.c b/src/charon/sa/child_sa.c index e7ab356c9c..092210bb24 100644 --- a/src/charon/sa/child_sa.c +++ b/src/charon/sa/child_sa.c @@ -89,16 +89,6 @@ struct private_child_sa_t { */ linked_list_t *other_ts; - /** - * Allocated SPI for a ESP proposal candidates - */ - u_int32_t alloc_esp_spi; - - /** - * Allocated SPI for a AH proposal candidates - */ - u_int32_t alloc_ah_spi; - /** * Protocol used to protect this SA, ESP|AH */ @@ -134,11 +124,6 @@ struct private_child_sa_t { */ ipcomp_transform_t ipcomp; - /** - * TRUE if we allocated (or tried to allocate) a CPI - */ - bool cpi_allocated; - /** * mode this SA uses, tunnel/transport */ @@ -170,7 +155,32 @@ static u_int32_t get_reqid(private_child_sa_t *this) { return this->reqid; } - + +/** + * Implements child_sa_t.get_config + */ +static child_cfg_t* get_config(private_child_sa_t *this) +{ + return this->config; +} + +/** + * Implements child_sa_t.set_state + */ +static void set_state(private_child_sa_t *this, child_sa_state_t state) +{ + charon->bus->child_state_change(charon->bus, &this->public, state); + this->state = state; +} + +/** + * Implements child_sa_t.get_state + */ +static child_sa_state_t get_state(private_child_sa_t *this) +{ + return this->state; +} + /** * Implements child_sa_t.get_spi */ @@ -195,6 +205,14 @@ protocol_id_t get_protocol(private_child_sa_t *this) return this->protocol; } +/** + * Implementation of child_sa_t.set_protocol + */ +static void set_protocol(private_child_sa_t *this, protocol_id_t protocol) +{ + this->protocol = protocol; +} + /** * Implementation of child_sa_t.get_mode */ @@ -203,6 +221,14 @@ static ipsec_mode_t get_mode(private_child_sa_t *this) return this->mode; } +/** + * Implementation of child_sa_t.set_mode + */ +static void set_mode(private_child_sa_t *this, ipsec_mode_t mode) +{ + this->mode = mode; +} + /** * Implementation of child_sa_t.has_encap */ @@ -220,19 +246,35 @@ static ipcomp_transform_t get_ipcomp(private_child_sa_t *this) } /** - * Implements child_sa_t.get_state + * Implementation of child_sa_t.set_ipcomp. */ -static child_sa_state_t get_state(private_child_sa_t *this) +static void set_ipcomp(private_child_sa_t *this, ipcomp_transform_t ipcomp) { - return this->state; + this->ipcomp = ipcomp; } /** - * Implements child_sa_t.get_config + * Implementation of child_sa_t.get_proposal */ -static child_cfg_t* get_config(private_child_sa_t *this) +static proposal_t* get_proposal(private_child_sa_t *this) { - return this->config; + return this->proposal; +} + +/** + * Implementation of child_sa_t.set_proposal + */ +static void set_proposal(private_child_sa_t *this, proposal_t *proposal) +{ + this->proposal = proposal->clone(proposal); +} + +/** + * Implementation of child_sa_t.get_traffic_selectors. + */ +static linked_list_t *get_traffic_selectors(private_child_sa_t *this, bool local) +{ + return local ? this->my_ts : this->other_ts; } typedef struct policy_enumerator_t policy_enumerator_t; @@ -366,143 +408,100 @@ static u_int32_t get_lifetime(private_child_sa_t *this, bool hard) } /** - * Implements child_sa_t.set_state - */ -static void set_state(private_child_sa_t *this, child_sa_state_t state) -{ - charon->bus->child_state_change(charon->bus, &this->public, state); - this->state = state; -} - -/** - * Allocate SPI for a single proposal + * Implementation of child_sa_t.alloc_spi */ -static status_t alloc_proposal(private_child_sa_t *this, proposal_t *proposal) +static u_int32_t alloc_spi(private_child_sa_t *this, protocol_id_t protocol) { - protocol_id_t protocol = proposal->get_protocol(proposal); - - if (protocol == PROTO_AH) + switch (protocol) { - /* get a new spi for AH, if not already done */ - if (this->alloc_ah_spi == 0) - { - if (charon->kernel_interface->get_spi( - charon->kernel_interface, - this->other_addr, this->my_addr, - PROTO_AH, this->reqid, - &this->alloc_ah_spi) != SUCCESS) + case PROTO_AH: + if (charon->kernel_interface->get_spi(charon->kernel_interface, + this->other_addr, this->my_addr, PROTO_AH, + this->reqid, &this->my_spi) == SUCCESS) { - return FAILED; + return this->my_spi; } - } - proposal->set_spi(proposal, this->alloc_ah_spi); - } - if (protocol == PROTO_ESP) - { - /* get a new spi for ESP, if not already done */ - if (this->alloc_esp_spi == 0) - { - if (charon->kernel_interface->get_spi( - charon->kernel_interface, - this->other_addr, this->my_addr, - PROTO_ESP, this->reqid, - &this->alloc_esp_spi) != SUCCESS) + break; + case PROTO_ESP: + if (charon->kernel_interface->get_spi(charon->kernel_interface, + this->other_addr, this->my_addr, PROTO_ESP, + this->reqid, &this->my_spi) == SUCCESS) { - return FAILED; + return this->my_spi; } - } - proposal->set_spi(proposal, this->alloc_esp_spi); + break; + default: + break; } - return SUCCESS; + return 0; } /** - * Implements child_sa_t.alloc + * Implementation of child_sa_t.alloc_cpi */ -static status_t alloc(private_child_sa_t *this, linked_list_t *proposals) +static u_int16_t alloc_cpi(private_child_sa_t *this) { - iterator_t *iterator; - proposal_t *proposal; - - /* iterator through proposals to update spis */ - iterator = proposals->create_iterator(proposals, TRUE); - while(iterator->iterate(iterator, (void**)&proposal)) + if (charon->kernel_interface->get_cpi(charon->kernel_interface, + this->other_addr, this->my_addr, this->reqid, + &this->my_cpi) == SUCCESS) { - if (alloc_proposal(this, proposal) != SUCCESS) - { - iterator->destroy(iterator); - return FAILED; - } + return this->my_cpi; } - iterator->destroy(iterator); - return SUCCESS; + return 0; } /** - * Install an SA for one direction + * Implementation of child_sa_t.install */ -static status_t install(private_child_sa_t *this, proposal_t *proposal, - ipsec_mode_t mode, chunk_t integ, chunk_t encr, bool in) +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_int16_t enc_alg = ENCR_UNDEFINED, int_alg = AUTH_UNDEFINED, size; - u_int32_t spi, soft, hard, now; + u_int32_t soft, hard, now; 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 */ - if (in) + if (inbound) { - /* if we have allocated SPIs for AH and ESP, we must delete the unused - * one. */ - if (this->protocol == PROTO_ESP) - { - this->my_spi = this->alloc_esp_spi; - if (this->alloc_ah_spi) - { - charon->kernel_interface->del_sa(charon->kernel_interface, - this->my_addr, this->alloc_ah_spi, 0, PROTO_AH); - } - } - else - { - this->my_spi = this->alloc_ah_spi; - if (this->alloc_esp_spi) - { - charon->kernel_interface->del_sa(charon->kernel_interface, - this->my_addr, this->alloc_esp_spi, 0, PROTO_ESP); - } - } - spi = this->my_spi; dst = this->my_addr; src = this->other_addr; + if (this->my_spi == spi) + { /* alloc_spi has been called, do an SA update */ + update = TRUE; + } + this->my_spi = spi; + this->my_cpi = cpi; } else { - this->other_spi = proposal->get_spi(proposal); - spi = this->other_spi; src = this->my_addr; dst = this->other_addr; + this->other_spi = spi; + this->other_cpi = cpi; } - DBG2(DBG_CHD, "adding %s %N SA", in ? "inbound" : "outbound", + 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); - proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &enc_alg, &size); - proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &int_alg, &size); + 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, - in ? soft : 0, hard, enc_alg, encr, int_alg, integ, - mode, this->ipcomp, in ? this->my_cpi : this->other_cpi, - this->encap, in); + inbound ? soft : 0, hard, enc_alg, encr, int_alg, integ, + this->mode, this->ipcomp, cpi, this->encap, update); now = time(NULL); this->rekey_time = now + soft; @@ -510,84 +509,17 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal, return status; } -/** - * Implementation of child_sa_t.add - */ -static status_t add(private_child_sa_t *this, - proposal_t *proposal, ipsec_mode_t mode, - chunk_t integ_in, chunk_t integ_out, - chunk_t encr_in, chunk_t encr_out) -{ - this->proposal = proposal->clone(proposal); - this->protocol = proposal->get_protocol(proposal); - - /* get SPIs for inbound SAs, write to proposal */ - if (alloc_proposal(this, proposal) != SUCCESS) - { - return FAILED; - } - /* install inbound SAs using allocated SPI */ - if (install(this, proposal, mode, integ_in, encr_in, TRUE) != SUCCESS) - { - return FAILED; - } - /* install outbound SAs using received SPI*/ - if (install(this, this->proposal, mode, integ_out, encr_out, FALSE) != SUCCESS) - { - return FAILED; - } - return SUCCESS; -} - -/** - * Implementation of child_sa_t.update - */ -static status_t update(private_child_sa_t *this, - proposal_t *proposal, ipsec_mode_t mode, - chunk_t integ_in, chunk_t integ_out, - chunk_t encr_in, chunk_t encr_out) -{ - this->proposal = proposal->clone(proposal); - this->protocol = proposal->get_protocol(proposal); - - /* install outbound SAs */ - if (install(this, proposal, mode, integ_out, encr_out, FALSE) != SUCCESS) - { - return FAILED; - } - /* install inbound SAs */ - if (install(this, proposal, mode, integ_in, encr_in, TRUE) != SUCCESS) - { - return FAILED; - } - return SUCCESS; -} - -/** - * Implementation of child_sa_t.get_proposal - */ -static proposal_t* get_proposal(private_child_sa_t *this) -{ - return this->proposal; -} - /** * Implementation of child_sa_t.add_policies */ static status_t add_policies(private_child_sa_t *this, - linked_list_t *my_ts_list, linked_list_t *other_ts_list, - ipsec_mode_t mode, protocol_id_t proto) + linked_list_t *my_ts_list, linked_list_t *other_ts_list) { enumerator_t *enumerator; traffic_selector_t *my_ts, *other_ts; status_t status = SUCCESS; bool routed = (this->state == CHILD_CREATED); - if (this->protocol == PROTO_NONE) - { /* update if not set yet */ - this->protocol = proto; - } - /* apply traffic selectors */ enumerator = my_ts_list->create_enumerator(my_ts_list); while (enumerator->enumerate(enumerator, &my_ts)) @@ -611,19 +543,19 @@ static status_t add_policies(private_child_sa_t *this, /* install 3 policies: out, in and forward */ status |= charon->kernel_interface->add_policy(charon->kernel_interface, this->my_addr, this->other_addr, my_ts, other_ts, POLICY_OUT, - this->other_spi, this->protocol, this->reqid, mode, this->ipcomp, - this->other_cpi, routed); + 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, mode, this->ipcomp, - this->my_cpi, routed); - if (mode != MODE_TRANSPORT) + this->my_spi, this->protocol, this->reqid, this->mode, + this->ipcomp, this->my_cpi, routed); + if (this->mode != MODE_TRANSPORT) { status |= charon->kernel_interface->add_policy(charon->kernel_interface, this->other_addr, this->my_addr, other_ts, my_ts, POLICY_FWD, - this->my_spi, this->protocol, this->reqid, mode, this->ipcomp, - this->my_cpi, routed); + this->my_spi, this->protocol, this->reqid, this->mode, + this->ipcomp, this->my_cpi, routed); } if (status != SUCCESS) @@ -634,32 +566,18 @@ static status_t add_policies(private_child_sa_t *this, enumerator->destroy(enumerator); } - if (status == SUCCESS) - { - /* switch to routed state if no SAD entry set up */ - if (this->state == CHILD_CREATED) - { - set_state(this, CHILD_ROUTED); - } - /* needed to update hosts */ - this->mode = mode; + if (status == SUCCESS && this->state == CHILD_CREATED) + { /* switch to routed state if no SAD entry set up */ + set_state(this, CHILD_ROUTED); } return status; } /** - * Implementation of child_sa_t.get_traffic_selectors. + * Implementation of child_sa_t.update. */ -static linked_list_t *get_traffic_selectors(private_child_sa_t *this, bool local) -{ - return local ? this->my_ts : this->other_ts; -} - -/** - * Implementation of child_sa_t.update_hosts. - */ -static status_t update_hosts(private_child_sa_t *this, - host_t *me, host_t *other, host_t *vip, bool encap) +static status_t update(private_child_sa_t *this, host_t *me, host_t *other, + host_t *vip, bool encap) { child_sa_state_t old; bool transport_proxy_mode; @@ -791,30 +709,6 @@ static status_t update_hosts(private_child_sa_t *this, return SUCCESS; } -/** - * Implementation of child_sa_t.activate_ipcomp. - */ -static void activate_ipcomp(private_child_sa_t *this, ipcomp_transform_t ipcomp, - u_int16_t other_cpi) -{ - this->ipcomp = ipcomp; - this->other_cpi = other_cpi; -} - -/** - * Implementation of child_sa_t.allocate_cpi. - */ -static u_int16_t allocate_cpi(private_child_sa_t *this) -{ - if (!this->cpi_allocated) - { - charon->kernel_interface->get_cpi(charon->kernel_interface, - this->other_addr, this->my_addr, this->reqid, &this->my_cpi); - this->cpi_allocated = TRUE; - } - return this->my_cpi; -} - /** * Implementation of child_sa_t.destroy. */ @@ -833,16 +727,6 @@ static void destroy(private_child_sa_t *this) this->my_addr, this->my_spi, this->protocol, this->my_cpi); } - if (this->alloc_esp_spi && this->alloc_esp_spi != this->my_spi) - { - charon->kernel_interface->del_sa(charon->kernel_interface, - this->my_addr, this->alloc_esp_spi, PROTO_ESP, 0); - } - if (this->alloc_ah_spi && this->alloc_ah_spi != this->my_spi) - { - charon->kernel_interface->del_sa(charon->kernel_interface, - this->my_addr, this->alloc_ah_spi, PROTO_AH, 0); - } if (this->other_spi) { charon->kernel_interface->del_sa(charon->kernel_interface, @@ -890,40 +774,39 @@ child_sa_t * child_sa_create(host_t *me, host_t* other, /* public functions */ this->public.get_name = (char*(*)(child_sa_t*))get_name; this->public.get_reqid = (u_int32_t(*)(child_sa_t*))get_reqid; + this->public.get_config = (child_cfg_t*(*)(child_sa_t*))get_config; + this->public.get_state = (child_sa_state_t(*)(child_sa_t*))get_state; + this->public.set_state = (void(*)(child_sa_t*,child_sa_state_t))set_state; this->public.get_spi = (u_int32_t(*)(child_sa_t*, bool))get_spi; this->public.get_cpi = (u_int16_t(*)(child_sa_t*, bool))get_cpi; this->public.get_protocol = (protocol_id_t(*)(child_sa_t*))get_protocol; + this->public.set_protocol = (void(*)(child_sa_t*, protocol_id_t protocol))set_protocol; this->public.get_mode = (ipsec_mode_t(*)(child_sa_t*))get_mode; - this->public.get_ipcomp = (ipcomp_transform_t(*)(child_sa_t*))get_ipcomp; - this->public.has_encap = (bool(*)(child_sa_t*))has_encap; + 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_usetime = (u_int32_t(*)(child_sa_t*, bool))get_usetime; - this->public.alloc = (status_t(*)(child_sa_t*,linked_list_t*))alloc; - this->public.add = (status_t(*)(child_sa_t*,proposal_t*,ipsec_mode_t,chunk_t,chunk_t,chunk_t,chunk_t))add; - this->public.update = (status_t(*)(child_sa_t*,proposal_t*,ipsec_mode_t,chunk_t,chunk_t,chunk_t,chunk_t))update; - this->public.get_proposal = (proposal_t*(*)(child_sa_t*))get_proposal; - this->public.update_hosts = (status_t (*)(child_sa_t*,host_t*,host_t*,host_t*,bool))update_hosts; - this->public.add_policies = (status_t (*)(child_sa_t*, linked_list_t*,linked_list_t*,ipsec_mode_t,protocol_id_t))add_policies; + 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.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.set_state = (void(*)(child_sa_t*,child_sa_state_t))set_state; - this->public.get_state = (child_sa_state_t(*)(child_sa_t*))get_state; - this->public.get_config = (child_cfg_t*(*)(child_sa_t*))get_config; - this->public.activate_ipcomp = (void(*)(child_sa_t*,ipcomp_transform_t,u_int16_t))activate_ipcomp; - this->public.allocate_cpi = (u_int16_t(*)(child_sa_t*))allocate_cpi; this->public.destroy = (void(*)(child_sa_t*))destroy; - + /* private data */ this->my_addr = me->clone(me); this->other_addr = other->clone(other); this->my_spi = 0; - this->my_cpi = 0; this->other_spi = 0; + this->my_cpi = 0; this->other_cpi = 0; - this->alloc_ah_spi = 0; - this->alloc_esp_spi = 0; this->encap = encap; - this->cpi_allocated = FALSE; this->ipcomp = IPCOMP_NONE; this->state = CHILD_CREATED; /* reuse old reqid if we are rekeying an existing CHILD_SA */ @@ -935,7 +818,7 @@ child_sa_t * child_sa_create(host_t *me, host_t* other, this->proposal = NULL; 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)) @@ -947,9 +830,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)) @@ -970,7 +853,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)) diff --git a/src/charon/sa/child_sa.h b/src/charon/sa/child_sa.h index 202573a235..7e180b7eee 100644 --- a/src/charon/sa/child_sa.h +++ b/src/charon/sa/child_sa.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2006-2008 Tobias Brunner - * Copyright (C) 2006-2007 Martin Willi + * Copyright (C) 2006-2008 Martin Willi * Copyright (C) 2006 Daniel Roethlisberger * Hochschule fuer Technik Rapperswil * @@ -93,12 +93,13 @@ extern enum_name_t *child_sa_state_names; * SAs and the policies have the same reqid. * * The procedure for child sa setup is as follows: - * - A gets SPIs for a proposal via child_sa_t.alloc - * - A send the updated proposal to B + * - A gets SPIs for a all protocols in its proposals via child_sa_t.alloc + * - A send the proposals with the allocated SPIs to B * - B selects a suitable proposal - * - B calls child_sa_t.add to add and update the selected proposal - * - B sends the updated proposal to A - * - A calls child_sa_t.update to update the already allocated SPIs with the chosen proposal + * - B allocates an SPI for the selected protocol + * - B calls child_sa_t.install for both, the allocated and received SPI + * - B sends the proposal with the allocated SPI to A + * - A calls child_sa_t.install for both, the allocated and recevied SPI * * Once SAs are set up, policies can be added using add_policies. */ @@ -121,6 +122,27 @@ struct child_sa_t { */ u_int32_t (*get_reqid)(child_sa_t *this); + /** + * Get the config used to set up this child sa. + * + * @return child_cfg + */ + child_cfg_t* (*get_config) (child_sa_t *this); + + /** + * Get the state of the CHILD_SA. + * + * @return CHILD_SA state + */ + child_sa_state_t (*get_state) (child_sa_t *this); + + /** + * Set the state of the CHILD_SA. + * + * @param state state to set on CHILD_SA + */ + void (*set_state) (child_sa_t *this, child_sa_state_t state); + /** * Get the SPI of this CHILD_SA. * @@ -152,6 +174,13 @@ struct child_sa_t { */ protocol_id_t (*get_protocol) (child_sa_t *this); + /** + * Set the negotiated protocol to use for this CHILD_SA. + * + * @param protocol AH | ESP + */ + void (*set_protocol)(child_sa_t *this, protocol_id_t protocol); + /** * Get the IPsec mode of this CHILD_SA. * @@ -159,6 +188,13 @@ struct child_sa_t { */ ipsec_mode_t (*get_mode)(child_sa_t *this); + /** + * Set the negotiated IPsec mode to use. + * + * @param mode TUNNEL | TRANPORT | BEET + */ + void (*set_mode)(child_sa_t *this, ipsec_mode_t mode); + /** * Get the used IPComp algorithm. * @@ -166,6 +202,27 @@ struct child_sa_t { */ ipcomp_transform_t (*get_ipcomp)(child_sa_t *this); + /** + * Set the IPComp algorithm to use. + * + * @param ipcomp the IPComp transform to use + */ + void (*set_ipcomp)(child_sa_t *this, ipcomp_transform_t ipcomp); + + /** + * Get the selected proposal. + * + * @return selected proposal + */ + proposal_t* (*get_proposal)(child_sa_t *this); + + /** + * Set the negotiated proposal. + * + * @param proposal selected proposal + */ + void (*set_proposal)(child_sa_t *this, proposal_t *proposal); + /** * Check if this CHILD_SA uses UDP encapsulation. * @@ -190,69 +247,48 @@ struct child_sa_t { u_int32_t (*get_usetime)(child_sa_t *this, bool inbound); /** - * Allocate SPIs for given proposals. - * - * Since the kernel manages SPIs for us, we need - * to allocate them. If a proposal contains more - * than one protocol, for each protocol an SPI is - * allocated. SPIs are stored internally and written - * back to the proposal. + * Get the traffic selectors list added for one side. * - * @param proposals list of proposals for which SPIs are allocated - */ - status_t (*alloc)(child_sa_t *this, linked_list_t* proposals); + * @param local TRUE for own traffic selectors, FALSE for remote + * @return list of traffic selectors + */ + linked_list_t* (*get_traffic_selectors) (child_sa_t *this, bool local); /** - * Install the kernel SAs for a proposal, without previous SPI allocation. + * Create an enumerator over installed policies. * - * @param proposal proposal for which SPIs are allocated - * @param mode mode for the CHILD_SA - * @param integ_in integrity key for inbound traffic - * @param integ_out integrity key for outbound traffic - * @param encr_in encryption key for inbound traffic - * @param enc_out encryption key for outbound traffic - * @return SUCCESS or FAILED + * @return enumerator over pairs of traffic selectors. */ - status_t (*add)(child_sa_t *this, proposal_t *proposal, ipsec_mode_t mode, - chunk_t integ_in, chunk_t integ_out, - chunk_t encr_in, chunk_t encr_out); + enumerator_t* (*create_policy_enumerator)(child_sa_t *this); + /** - * Install the kernel SAs for a proposal, after SPIs have been allocated. - * - * Updates an SA, for which SPIs are already allocated via alloc(). + * Allocate an SPI to include in a proposal. * - * @param proposal proposal for which SPIs are allocated - * @param mode mode for the CHILD_SA - * @param integ_in integrity key for inbound traffic - * @param integ_out integrity key for outbound traffic - * @param encr_in encryption key for inbound traffic - * @param enc_out encryption key for outbound traffic - * @return SUCCESS or FAILED + * @param protocol protocol to allocate SPI for (ESP|AH) + * @param spi SPI output pointer + * @return SPI, 0 on failure */ - status_t (*update)(child_sa_t *this, proposal_t *proposal, ipsec_mode_t mode, - chunk_t integ_in, chunk_t integ_out, - chunk_t encr_in, chunk_t encr_out); + u_int32_t (*alloc_spi)(child_sa_t *this, protocol_id_t protocol); + /** - * Get the selected proposal passed to add()/update(). + * Allocate a CPI to use for IPComp. * - * @return selected proposal + * @return CPI, 0 on failure */ - proposal_t* (*get_proposal)(child_sa_t *this); + u_int16_t (*alloc_cpi)(child_sa_t *this); /** - * Update the hosts in the kernel SAs and policies. + * Install an IPsec SA for one direction. * - * The CHILD must be INSTALLED to do this update. - * - * @param me the new local host - * @param other the new remote host - * @param vip virtual IP, if any - * @param TRUE to use UDP encapsulation for NAT traversal + * @param encr encryption key, if any + * @param integ integrity key + * @param spi SPI to use, allocated for inbound + * @param cpi CPI to use, allocated for outbound + * @param inbound TRUE to install an inbound SA, FALSE for outbound * @return SUCCESS or FAILED */ - status_t (*update_hosts)(child_sa_t *this, host_t *me, host_t *other, - host_t *vip, bool encap); - + status_t (*install)(child_sa_t *this, chunk_t encr, chunk_t integ, + u_int32_t spi, u_int16_t cpi, bool inbound); /** * Install the policies using some traffic selectors. * @@ -261,64 +297,21 @@ struct child_sa_t { * * @param my_ts traffic selectors for local site * @param other_ts traffic selectors for remote site - * @param mode mode for the SA: tunnel/transport - * @param proto protocol for policy, ESP/AH * @return SUCCESS or FAILED */ status_t (*add_policies)(child_sa_t *this, linked_list_t *my_ts_list, - linked_list_t *other_ts_list, ipsec_mode_t mode, - protocol_id_t proto); - - /** - * Get the traffic selectors of added policies of local host. - * - * @param local TRUE for own traffic selectors, FALSE for remote - * @return list of traffic selectors - */ - linked_list_t* (*get_traffic_selectors) (child_sa_t *this, bool local); - + linked_list_t *other_ts_list); /** - * Create an enumerator over installed policies. + * Update hosts and ecapulation mode in the kernel SAs and policies. * - * @return enumerator over pairs of traffic selectors. - */ - enumerator_t* (*create_policy_enumerator)(child_sa_t *this); - - /** - * Get the state of the CHILD_SA. - */ - child_sa_state_t (*get_state) (child_sa_t *this); - - /** - * Set the state of the CHILD_SA. - * - * @param state state to set on CHILD_SA - */ - void (*set_state) (child_sa_t *this, child_sa_state_t state); - - /** - * Get the config used to set up this child sa. - * - * @return child_cfg - */ - child_cfg_t* (*get_config) (child_sa_t *this); - - /** - * Activate IPComp by setting the transform ID and CPI values. - * - * @param ipcomp the IPComp transform to use - * @param other_cpi other Compression Parameter Index - */ - void (*activate_ipcomp) (child_sa_t *this, ipcomp_transform_t ipcomp, - u_int16_t other_cpi); - - /** - * Returns the Compression Parameter Index (CPI) allocated from the kernel. - * - * @return allocated CPI + * @param me the new local host + * @param other the new remote host + * @param vip virtual IP, if any + * @param TRUE to use UDP encapsulation for NAT traversal + * @return SUCCESS or FAILED */ - u_int16_t (*allocate_cpi) (child_sa_t *this); - + status_t (*update)(child_sa_t *this, host_t *me, host_t *other, + host_t *vip, bool encap); /** * Destroys a child_sa. */ diff --git a/src/charon/sa/ike_sa.c b/src/charon/sa/ike_sa.c index f6fa35130b..d8932dd030 100644 --- a/src/charon/sa/ike_sa.c +++ b/src/charon/sa/ike_sa.c @@ -874,7 +874,7 @@ static void update_hosts(private_ike_sa_t *this, host_t *me, host_t *other) iterator = this->child_sas->create_iterator(this->child_sas, TRUE); while (iterator->iterate(iterator, (void**)&child_sa)) { - if (child_sa->update_hosts(child_sa, this->my_host, + if (child_sa->update(child_sa, this->my_host, this->other_host, this->my_virtual_ip, has_condition(this, COND_NAT_ANY)) == NOT_SUPPORTED) { @@ -1288,8 +1288,8 @@ static status_t route(private_ike_sa_t *this, child_cfg_t *child_cfg) my_ts = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, me); other_ts = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, other); - status = child_sa->add_policies(child_sa, my_ts, other_ts, - child_cfg->get_mode(child_cfg), PROTO_NONE); + child_sa->set_mode(child_sa, child_cfg->get_mode(child_cfg)); + status = child_sa->add_policies(child_sa, my_ts, other_ts); my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy)); other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy)); diff --git a/src/charon/sa/tasks/child_create.c b/src/charon/sa/tasks/child_create.c index 02664338a0..f1453f0c5a 100644 --- a/src/charon/sa/tasks/child_create.c +++ b/src/charon/sa/tasks/child_create.c @@ -117,7 +117,22 @@ struct private_child_create_t { ipcomp_transform_t ipcomp_received; /** - * Other Compression Parameter Index (CPI) + * Own allocated SPI + */ + u_int32_t my_spi; + + /** + * SPI received in proposal + */ + u_int32_t other_spi; + + /** + * Own allocated Compression Parameter Index (CPI) + */ + u_int16_t my_cpi; + + /** + * Other Compression Parameter Index (CPI), received via IPCOMP_SUPPORTED */ u_int16_t other_cpi; @@ -188,6 +203,36 @@ static bool ts_list_is_host(linked_list_t *list, host_t *host) return is_host; } +/** + * Allocate SPIs and update proposals + */ +static bool allocate_spi(private_child_create_t *this) +{ + enumerator_t *enumerator; + proposal_t *proposal; + + /* TODO: allocate additional SPI for AH if we have such proposals */ + this->my_spi = this->child_sa->alloc_spi(this->child_sa, PROTO_ESP); + if (this->my_spi) + { + if (this->initiator) + { + enumerator = this->proposals->create_enumerator(this->proposals); + while (enumerator->enumerate(enumerator, &proposal)) + { + proposal->set_spi(proposal, this->my_spi); + } + enumerator->destroy(enumerator); + } + else + { + this->proposal->set_spi(this->proposal, this->my_spi); + } + return TRUE; + } + return FALSE; +} + /** * Install a CHILD_SA for usage, return value: * - FAILED: no acceptable proposal @@ -216,7 +261,7 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh) other = this->ike_sa->get_other_host(this->ike_sa); my_vip = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE); other_vip = this->ike_sa->get_virtual_ip(this->ike_sa, FALSE); - + this->proposal = this->config->select_proposal(this->config, this->proposals, no_dh); if (this->proposal == NULL) @@ -224,6 +269,14 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh) DBG1(DBG_IKE, "no acceptable proposal found"); return FAILED; } + this->other_spi = this->proposal->get_spi(this->proposal); + + if (!this->initiator && !allocate_spi(this)) + { /* responder has no SPI allocated yet */ + DBG1(DBG_IKE, "allocating SPI failed"); + return FAILED; + } + this->child_sa->set_proposal(this->child_sa, this->proposal); if (!this->proposal->has_dh_group(this->proposal, this->dh_group)) { @@ -328,26 +381,33 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh) } this->child_sa->set_state(this->child_sa, CHILD_INSTALLING); + this->child_sa->set_ipcomp(this->child_sa, this->ipcomp); + this->child_sa->set_mode(this->child_sa, this->mode); + this->child_sa->set_protocol(this->child_sa, + this->proposal->get_protocol(this->proposal)); - if (this->ipcomp != IPCOMP_NONE) + if (this->my_cpi == 0 || this->other_cpi == 0 || this->ipcomp == IPCOMP_NONE) { - this->child_sa->activate_ipcomp(this->child_sa, this->ipcomp, - this->other_cpi); + this->my_cpi = this->other_cpi = 0; + this->ipcomp = IPCOMP_NONE; } - status = FAILED; if (this->keymat->derive_child_keys(this->keymat, this->proposal, this->dh, nonce_i, nonce_r, &encr_i, &integ_i, &encr_r, &integ_r)) { if (this->initiator) { - status = this->child_sa->update(this->child_sa, this->proposal, - this->mode, integ_r, integ_i, encr_r, encr_i); + status = this->child_sa->install(this->child_sa, encr_r, integ_r, + this->my_spi, this->my_cpi, TRUE); + status = this->child_sa->install(this->child_sa, encr_i, integ_i, + this->other_spi, this->other_cpi, FALSE); } else { - status = this->child_sa->add(this->child_sa, this->proposal, - this->mode, integ_i, integ_r, encr_i, encr_r); + status = this->child_sa->install(this->child_sa, encr_i, integ_i, + this->my_spi, this->my_cpi, TRUE); + status = this->child_sa->install(this->child_sa, encr_r, integ_r, + this->other_spi, this->other_cpi, FALSE); } } chunk_clear(&integ_i); @@ -361,8 +421,7 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh) return FAILED; } - status = this->child_sa->add_policies(this->child_sa, my_ts, other_ts, - this->mode, this->proposal->get_protocol(this->proposal)); + status = this->child_sa->add_policies(this->child_sa, my_ts, other_ts); if (status != SUCCESS) { DBG1(DBG_IKE, "unable to install IPsec policies (SPD) in kernel"); @@ -436,33 +495,71 @@ static void build_payloads(private_child_create_t *this, message_t *message) } /** - * Adds an IPCOMP_SUPPORTED notify to the message, if possible + * Adds an IPCOMP_SUPPORTED notify to the message, allocating a CPI */ -static void build_ipcomp_supported_notify(private_child_create_t *this, - message_t *message) +static void add_ipcomp_notify(private_child_create_t *this, + message_t *message, u_int8_t ipcomp) { - u_int16_t cpi; - u_int8_t tid; - if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY)) { DBG1(DBG_IKE, "IPComp is not supported if either peer is natted, " "IPComp disabled"); - this->ipcomp = IPCOMP_NONE; return; } - cpi = this->child_sa->allocate_cpi(this->child_sa); - tid = this->ipcomp; - if (cpi) + this->my_cpi = this->child_sa->alloc_cpi(this->child_sa); + if (this->my_cpi) { - message->add_notify(message, FALSE, IPCOMP_SUPPORTED, - chunk_cata("cc", chunk_from_thing(cpi), chunk_from_thing(tid))); + this->ipcomp = ipcomp; + message->add_notify(message, FALSE, IPCOMP_SUPPORTED, + chunk_cata("cc", chunk_from_thing(this->my_cpi), + chunk_from_thing(ipcomp))); } else { DBG1(DBG_IKE, "unable to allocate a CPI from kernel, IPComp disabled"); - this->ipcomp = IPCOMP_NONE; + } +} + +/** + * handle a received notify payload + */ +static void handle_notify(private_child_create_t *this, notify_payload_t *notify) +{ + switch (notify->get_notify_type(notify)) + { + case USE_TRANSPORT_MODE: + this->mode = MODE_TRANSPORT; + break; + case USE_BEET_MODE: + this->mode = MODE_BEET; + break; + case IPCOMP_SUPPORTED: + { + ipcomp_transform_t ipcomp; + u_int16_t cpi; + chunk_t data; + + data = notify->get_notification_data(notify); + cpi = *(u_int16_t*)data.ptr; + ipcomp = (ipcomp_transform_t)(*(data.ptr + 2)); + switch (ipcomp) + { + case IPCOMP_DEFLATE: + this->other_cpi = cpi; + this->ipcomp_received = ipcomp; + break; + case IPCOMP_LZS: + case IPCOMP_LZJH: + default: + DBG1(DBG_IKE, "received IPCOMP_SUPPORTED notify with a " + "transform ID we don't support %N", + ipcomp_transform_names, ipcomp); + break; + } + } + default: + break; } } @@ -476,7 +573,6 @@ static void process_payloads(private_child_create_t *this, message_t *message) sa_payload_t *sa_payload; ke_payload_t *ke_payload; ts_payload_t *ts_payload; - notify_payload_t *notify_payload; /* defaults to TUNNEL mode */ this->mode = MODE_TUNNEL; @@ -512,37 +608,7 @@ static void process_payloads(private_child_create_t *this, message_t *message) this->tsr = ts_payload->get_traffic_selectors(ts_payload); break; case NOTIFY: - notify_payload = (notify_payload_t*)payload; - switch (notify_payload ->get_notify_type(notify_payload )) - { - case USE_TRANSPORT_MODE: - this->mode = MODE_TRANSPORT; - break; - case USE_BEET_MODE: - this->mode = MODE_BEET; - break; - case IPCOMP_SUPPORTED: - { - chunk_t data = notify_payload->get_notification_data(notify_payload); - u_int16_t cpi = *(u_int16_t*)data.ptr; - ipcomp_transform_t ipcomp = (ipcomp_transform_t)(*(data.ptr + 2)); - switch(ipcomp) - { - case IPCOMP_DEFLATE: - this->other_cpi = cpi; - this->ipcomp_received = ipcomp; - break; - case IPCOMP_LZS: - case IPCOMP_LZJH: - default: - DBG1(DBG_IKE, "received IPCOMP_SUPPORTED notify with a transform" - " ID we don't support %N", ipcomp_transform_names, ipcomp); - break; - } - } - default: - break; - } + handle_notify(this, (notify_payload_t*)payload); break; default: break; @@ -559,7 +625,7 @@ static status_t build_i(private_child_create_t *this, message_t *message) host_t *me, *other, *vip; bool propose_all = FALSE; peer_cfg_t *peer_cfg; - + switch (message->get_exchange_type(message)) { case IKE_SA_INIT: @@ -641,7 +707,7 @@ static status_t build_i(private_child_create_t *this, message_t *message) this->ike_sa->get_other_host(this->ike_sa), this->config, this->reqid, this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY)); - if (this->child_sa->alloc(this->child_sa, this->proposals) != SUCCESS) + if (!allocate_spi(this)) { DBG1(DBG_IKE, "unable to allocate SPIs from kernel"); return FAILED; @@ -652,10 +718,10 @@ static status_t build_i(private_child_create_t *this, message_t *message) this->dh = this->keymat->create_dh(this->keymat, this->dh_group); } - if (this->config->use_ipcomp(this->config)) { + if (this->config->use_ipcomp(this->config)) + { /* IPCOMP_DEFLATE is the only transform we support at the moment */ - this->ipcomp = IPCOMP_DEFLATE; - build_ipcomp_supported_notify(this, message); + add_ipcomp_notify(this, message, IPCOMP_DEFLATE); } build_payloads(this, message); @@ -821,16 +887,17 @@ static status_t build_r(private_child_create_t *this, message_t *message) this->ike_sa->get_other_host(this->ike_sa), this->config, this->reqid, this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY)); - if (this->config->use_ipcomp(this->config) && - this->ipcomp_received != IPCOMP_NONE) - { - this->ipcomp = this->ipcomp_received; - build_ipcomp_supported_notify(this, message); - } - else if (this->ipcomp_received != IPCOMP_NONE) + if (this->ipcomp_received != IPCOMP_NONE) { - DBG1(DBG_IKE, "received %N notify but IPComp is disabled, ignoring", - notify_type_names, IPCOMP_SUPPORTED); + if (this->config->use_ipcomp(this->config)) + { + add_ipcomp_notify(this, message, this->ipcomp_received); + } + else + { + DBG1(DBG_IKE, "received %N notify but IPComp is disabled, ignoring", + notify_type_names, IPCOMP_SUPPORTED); + } } switch (select_and_install(this, no_dh)) @@ -1137,6 +1204,9 @@ child_create_t *child_create_create(ike_sa_t *ike_sa, child_cfg_t *config) this->mode = MODE_TUNNEL; this->ipcomp = IPCOMP_NONE; this->ipcomp_received = IPCOMP_NONE; + this->my_spi = 0; + this->other_spi = 0; + this->my_cpi = 0; this->other_cpi = 0; this->reqid = 0; this->established = FALSE; diff --git a/src/charon/sa/tasks/ike_mobike.c b/src/charon/sa/tasks/ike_mobike.c index 026190b808..38650cb917 100644 --- a/src/charon/sa/tasks/ike_mobike.c +++ b/src/charon/sa/tasks/ike_mobike.c @@ -251,7 +251,7 @@ static void update_children(private_ike_mobike_t *this) iterator = this->ike_sa->create_child_sa_iterator(this->ike_sa); while (iterator->iterate(iterator, (void**)&child_sa)) { - if (child_sa->update_hosts(child_sa, + if (child_sa->update(child_sa, this->ike_sa->get_my_host(this->ike_sa), this->ike_sa->get_other_host(this->ike_sa), this->ike_sa->get_virtual_ip(this->ike_sa, TRUE),