diff options
Diffstat (limited to 'src/charon/sa/child_sa.c')
-rw-r--r-- | src/charon/sa/child_sa.c | 411 |
1 files changed, 147 insertions, 264 deletions
diff --git a/src/charon/sa/child_sa.c b/src/charon/sa/child_sa.c index d7a63d5e8..022b9149a 100644 --- a/src/charon/sa/child_sa.c +++ b/src/charon/sa/child_sa.c @@ -15,7 +15,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: child_sa.c 4665 2008-11-17 00:01:34Z andreas $ + * $Id: child_sa.c 4677 2008-11-19 15:31:27Z martin $ */ #define _GNU_SOURCE @@ -90,16 +90,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 */ protocol_id_t protocol; @@ -135,11 +125,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 */ ipsec_mode_t mode; @@ -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 */ @@ -196,6 +206,14 @@ protocol_id_t get_protocol(private_child_sa_t *this) } /** + * 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 */ static ipsec_mode_t get_mode(private_child_sa_t *this) @@ -204,6 +222,14 @@ static ipsec_mode_t get_mode(private_child_sa_t *this) } /** + * 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 */ static bool has_encap(private_child_sa_t *this) @@ -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; @@ -511,83 +510,16 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal, } /** - * 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; @@ -792,30 +710,6 @@ static status_t update_hosts(private_child_sa_t *this, } /** - * 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. */ static void destroy(private_child_sa_t *this) @@ -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)) |