diff options
Diffstat (limited to 'src/charon/sa/child_sa.c')
-rw-r--r-- | src/charon/sa/child_sa.c | 169 |
1 files changed, 117 insertions, 52 deletions
diff --git a/src/charon/sa/child_sa.c b/src/charon/sa/child_sa.c index b6c71a8b5..2a6b6f67c 100644 --- a/src/charon/sa/child_sa.c +++ b/src/charon/sa/child_sa.c @@ -1,13 +1,7 @@ -/** - * @file child_sa.c - * - * @brief Implementation of child_sa_t. - * - */ - /* + * Copyright (C) 2006-2008 Tobias Brunner * Copyright (C) 2005-2007 Martin Willi - * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger + * Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * @@ -20,6 +14,8 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. + * + * $Id: child_sa.c 3920 2008-05-08 16:19:11Z tobias $ */ #define _GNU_SOURCE @@ -75,6 +71,8 @@ struct private_child_sa_t { identification_t *id; /** actual used SPI, 0 if unused */ u_int32_t spi; + /** Compression Parameter Index (CPI) used, 0 if unused */ + u_int16_t cpi; } me, other; /** @@ -115,12 +113,22 @@ struct private_child_sa_t { /** * encryption algorithm used for this SA */ - algorithm_t encryption; + u_int16_t enc_alg; + + /** + * key size of enc_alg + */ + u_int16_t enc_size; /** * integrity protection algorithm used for this SA */ - algorithm_t integrity; + u_int16_t int_alg; + + /** + * key size of int_alg + */ + u_int16_t int_size; /** * time, on which SA was installed @@ -143,6 +151,16 @@ struct private_child_sa_t { bool encap; /** + * Specifies the IPComp transform used (IPCOMP_NONE if disabled) + */ + ipcomp_transform_t ipcomp; + + /** + * TRUE if we allocated (or tried to allocate) a CPI + */ + bool cpi_allocated; + + /** * mode this SA uses, tunnel/transport */ mode_t mode; @@ -251,10 +269,10 @@ static void get_stats(private_child_sa_t *this, mode_t *mode, iterator->destroy(iterator); *mode = this->mode; - *encr_algo = this->encryption.algorithm; - *encr_len = this->encryption.key_size; - *int_algo = this->integrity.algorithm; - *int_len = this->integrity.key_size; + *encr_algo = this->enc_alg; + *encr_len = this->enc_size; + *int_algo = this->int_alg; + *int_len = this->int_size; *rekey = this->rekey_time; *use_in = in; *use_out = out; @@ -498,10 +516,7 @@ static status_t alloc(private_child_sa_t *this, linked_list_t *proposals) static status_t install(private_child_sa_t *this, proposal_t *proposal, mode_t mode, prf_plus_t *prf_plus, bool mine) { - u_int32_t spi, soft, hard;; - algorithm_t *enc_algo, *int_algo; - algorithm_t enc_algo_none = {ENCR_UNDEFINED, 0}; - algorithm_t int_algo_none = {AUTH_UNDEFINED, 0}; + u_int32_t spi, soft, hard; host_t *src; host_t *dst; status_t status; @@ -549,43 +564,43 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal, protocol_id_names, this->protocol); /* select encryption algo */ - if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &enc_algo)) + if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, + &this->enc_alg, &this->enc_size)) { - DBG2(DBG_CHD, " using %N for encryption", - encryption_algorithm_names, enc_algo->algorithm); - } - else - { - enc_algo = &enc_algo_none; + DBG2(DBG_CHD, " using %N for encryption", + encryption_algorithm_names, this->enc_alg); } /* select integrity algo */ - if (proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &int_algo)) + if (proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, + &this->int_alg, &this->int_size)) { DBG2(DBG_CHD, " using %N for integrity", - integrity_algorithm_names, int_algo->algorithm); - } - else - { - int_algo = &int_algo_none; + integrity_algorithm_names, this->int_alg); } - soft = this->config->get_lifetime(this->config, TRUE); hard = this->config->get_lifetime(this->config, FALSE); /* send SA down to the kernel */ DBG2(DBG_CHD, " SPI 0x%.8x, src %H dst %H", ntohl(spi), src, dst); - status = charon->kernel_interface->add_sa(charon->kernel_interface, - src, dst, spi, this->protocol, - this->reqid, mine ? soft : 0, - hard, enc_algo, int_algo, - prf_plus, mode, this->encap, mine); - this->encryption = *enc_algo; - this->integrity = *int_algo; + if (this->ipcomp != IPCOMP_NONE) + { + /* we install an additional IPComp SA */ + u_int32_t cpi = htonl(ntohs(mine ? this->me.cpi : this->other.cpi)); + status = charon->kernel_interface->add_sa(charon->kernel_interface, + src, dst, cpi, IPPROTO_COMP, this->reqid, 0, 0, + ENCR_UNDEFINED, 0, AUTH_UNDEFINED, 0, NULL, mode, + this->ipcomp, FALSE, mine); + } + + status = charon->kernel_interface->add_sa(charon->kernel_interface, + src, dst, spi, this->protocol, this->reqid, mine ? soft : 0, hard, + this->enc_alg, this->enc_size, this->int_alg, this->int_size, + prf_plus, mode, IPCOMP_NONE, this->encap, mine); + this->install_time = time(NULL); this->rekey_time = this->install_time + soft; - return status; } @@ -686,15 +701,15 @@ 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->me.addr, this->other.addr, my_ts, other_ts, POLICY_OUT, - this->protocol, this->reqid, high_prio, mode); + this->protocol, this->reqid, high_prio, mode, this->ipcomp); status |= charon->kernel_interface->add_policy(charon->kernel_interface, this->other.addr, this->me.addr, other_ts, my_ts, POLICY_IN, - this->protocol, this->reqid, high_prio, mode); + this->protocol, this->reqid, high_prio, mode, this->ipcomp); status |= charon->kernel_interface->add_policy(charon->kernel_interface, this->other.addr, this->me.addr, other_ts, my_ts, POLICY_FWD, - this->protocol, this->reqid, high_prio, mode); + this->protocol, this->reqid, high_prio, mode, this->ipcomp); if (status != SUCCESS) { @@ -795,10 +810,20 @@ static status_t update_hosts(private_child_sa_t *this, this->encap = encap; - /* update our (initator) SAs */ + if (this->ipcomp != IPCOMP_NONE) + { + /* update our (initator) IPComp SA */ + charon->kernel_interface->update_sa(charon->kernel_interface, htonl(ntohs(this->me.cpi)), + IPPROTO_COMP, this->other.addr, this->me.addr, other, me, FALSE); + /* update his (responder) IPComp SA */ + charon->kernel_interface->update_sa(charon->kernel_interface, htonl(ntohs(this->other.cpi)), + IPPROTO_COMP, this->me.addr, this->other.addr, me, other, FALSE); + } + + /* update our (initator) SA */ charon->kernel_interface->update_sa(charon->kernel_interface, this->me.spi, this->protocol, this->other.addr, this->me.addr, other, me, encap); - /* update his (responder) SAs */ + /* update his (responder) SA */ charon->kernel_interface->update_sa(charon->kernel_interface, this->other.spi, this->protocol, this->me.addr, this->other.addr, me, other, encap); @@ -846,13 +871,13 @@ static status_t update_hosts(private_child_sa_t *this, /* reinstall updated policies */ charon->kernel_interface->add_policy(charon->kernel_interface, me, other, policy->my_ts, policy->other_ts, POLICY_OUT, - this->protocol, this->reqid, TRUE, this->mode); + this->protocol, this->reqid, TRUE, this->mode, this->ipcomp); charon->kernel_interface->add_policy(charon->kernel_interface, other, me, policy->other_ts, policy->my_ts, POLICY_IN, - this->protocol, this->reqid, TRUE, this->mode); + this->protocol, this->reqid, TRUE, this->mode, this->ipcomp); charon->kernel_interface->add_policy(charon->kernel_interface, other, me, policy->other_ts, policy->my_ts, POLICY_FWD, - this->protocol, this->reqid, TRUE, this->mode); + this->protocol, this->reqid, TRUE, this->mode, this->ipcomp); } iterator->destroy(iterator); } @@ -884,6 +909,30 @@ static void set_virtual_ip(private_child_sa_t *this, host_t *ip) } /** + * 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.get_my_cpi. + */ +static u_int16_t get_my_cpi(private_child_sa_t *this) +{ + if (!this->cpi_allocated) + { + charon->kernel_interface->get_cpi(charon->kernel_interface, + this->other.addr, this->me.addr, this->reqid, &this->me.cpi); + this->cpi_allocated = TRUE; + } + return this->me.cpi; +} + +/** * Implementation of child_sa_t.destroy. */ static void destroy(private_child_sa_t *this) @@ -916,6 +965,16 @@ static void destroy(private_child_sa_t *this) charon->kernel_interface->del_sa(charon->kernel_interface, this->other.addr, this->other.spi, this->protocol); } + if (this->me.cpi) + { + charon->kernel_interface->del_sa(charon->kernel_interface, + this->other.addr, htonl(ntohs(this->me.cpi)), IPPROTO_COMP); + } + if (this->other.cpi) + { + charon->kernel_interface->del_sa(charon->kernel_interface, + this->other.addr, htonl(ntohs(this->other.cpi)), IPPROTO_COMP); + } /* delete all policies in the kernel */ while (this->policies->remove_last(this->policies, (void**)&policy) == SUCCESS) @@ -976,6 +1035,8 @@ child_sa_t * child_sa_create(host_t *me, host_t* other, 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.get_my_cpi = (u_int16_t(*)(child_sa_t*))get_my_cpi; this->public.set_virtual_ip = (void(*)(child_sa_t*,host_t*))set_virtual_ip; this->public.destroy = (void(*)(child_sa_t*))destroy; @@ -985,17 +1046,21 @@ child_sa_t * child_sa_create(host_t *me, host_t* other, this->me.id = my_id->clone(my_id); this->other.id = other_id->clone(other_id); this->me.spi = 0; + this->me.cpi = 0; this->other.spi = 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 */ this->reqid = rekey ? rekey : ++reqid; - this->encryption.algorithm = ENCR_UNDEFINED; - this->encryption.key_size = 0; - this->integrity.algorithm = AUTH_UNDEFINED; - this->encryption.key_size = 0; + this->enc_alg = ENCR_UNDEFINED; + this->enc_size = 0; + this->int_alg = AUTH_UNDEFINED; + this->int_size = 0; this->policies = linked_list_create(); this->my_ts = linked_list_create(); this->other_ts = linked_list_create(); |