diff options
Diffstat (limited to 'src/charon/sa/tasks/child_create.c')
-rw-r--r-- | src/charon/sa/tasks/child_create.c | 242 |
1 files changed, 155 insertions, 87 deletions
diff --git a/src/charon/sa/tasks/child_create.c b/src/charon/sa/tasks/child_create.c index 767ceef55..f6043979f 100644 --- a/src/charon/sa/tasks/child_create.c +++ b/src/charon/sa/tasks/child_create.c @@ -14,7 +14,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: child_create.c 4618 2008-11-11 09:22:00Z tobias $ + * $Id: child_create.c 4860 2009-02-11 13:09:52Z martin $ */ #include "child_create.h" @@ -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; @@ -189,6 +204,36 @@ static bool ts_list_is_host(linked_list_t *list, host_t *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 * - INVALID_ARG: diffie hellman group inacceptable @@ -197,7 +242,9 @@ static bool ts_list_is_host(linked_list_t *list, host_t *host) static status_t select_and_install(private_child_create_t *this, bool no_dh) { status_t status; - chunk_t nonce_i, nonce_r, encr_i, integ_i, encr_r, integ_r; + chunk_t nonce_i, nonce_r; + chunk_t encr_i = chunk_empty, encr_r = chunk_empty; + chunk_t integ_i = chunk_empty, integ_r = chunk_empty; linked_list_t *my_ts, *other_ts; host_t *me, *other, *other_vip, *my_vip; @@ -216,7 +263,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 +271,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 +383,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 +423,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 +497,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 +575,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 +610,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; @@ -557,9 +625,8 @@ static void process_payloads(private_child_create_t *this, message_t *message) 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: @@ -610,23 +677,18 @@ static status_t build_i(private_child_create_t *this, message_t *message) } /* check if we want a virtual IP, but don't have one */ - if (!this->reqid) + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + vip = peer_cfg->get_virtual_ip(peer_cfg); + if (!this->reqid && vip) { - peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); - vip = peer_cfg->get_virtual_ip(peer_cfg); - if (vip) - { - propose_all = TRUE; - } - } - - if (propose_all) - { /* propose a 0.0.0.0/0 subnet when we use virtual ip */ + /* propose a 0.0.0.0/0 or ::/0 subnet when we use virtual ip */ + vip = host_create_any(vip->get_family(vip)); this->tsi = this->config->get_traffic_selectors(this->config, TRUE, - NULL, NULL); + NULL, vip); + vip->destroy(vip); } else - { /* but shorten a 0.0.0.0/0 subnet for host2host/we already have a vip */ + { /* but narrow it for host2host / if we already have a vip */ this->tsi = this->config->get_traffic_selectors(this->config, TRUE, NULL, me); } @@ -641,7 +703,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 +714,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 +883,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) + if (this->ipcomp_received != IPCOMP_NONE) { - this->ipcomp = this->ipcomp_received; - build_ipcomp_supported_notify(this, message); - } - else 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)) @@ -1052,6 +1115,8 @@ static void migrate(private_child_create_t *this, ike_sa_t *ike_sa) } this->ike_sa = ike_sa; + this->keymat = ike_sa->get_keymat(ike_sa); + this->proposal = NULL; this->proposals = NULL; this->tsi = NULL; this->tsr = NULL; @@ -1137,6 +1202,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; |