diff options
author | Martin Willi <martin@strongswan.org> | 2007-08-27 09:10:12 +0000 |
---|---|---|
committer | Martin Willi <martin@strongswan.org> | 2007-08-27 09:10:12 +0000 |
commit | 98f97433af9166217389be93cc9d833b07f6ca46 (patch) | |
tree | 75b24fb5d9ac0635737cc779f004ce4f7bbfa412 /src/charon | |
parent | 9a63ddd84defbad48bfc1870fcef2816de2380f0 (diff) | |
download | strongswan-98f97433af9166217389be93cc9d833b07f6ca46.tar.bz2 strongswan-98f97433af9166217389be93cc9d833b07f6ca46.tar.xz |
rerouting CHILD_SA if its IKE_SA gets deleted
Diffstat (limited to 'src/charon')
-rw-r--r-- | src/charon/sa/ike_sa.c | 248 |
1 files changed, 149 insertions, 99 deletions
diff --git a/src/charon/sa/ike_sa.c b/src/charon/sa/ike_sa.c index 0a996329d..d50aec6e5 100644 --- a/src/charon/sa/ike_sa.c +++ b/src/charon/sa/ike_sa.c @@ -851,103 +851,6 @@ static void send_notify_response(private_ike_sa_t *this, message_t *request, } /** - * Implementation of ike_sa_t.process_message. - */ -static status_t process_message(private_ike_sa_t *this, message_t *message) -{ - status_t status; - bool is_request; - - is_request = message->get_request(message); - - status = message->parse_body(message, this->crypter_in, this->signer_in); - if (status != SUCCESS) - { - - if (is_request) - { - switch (status) - { - case NOT_SUPPORTED: - DBG1(DBG_IKE, "ciritcal unknown payloads found"); - if (is_request) - { - send_notify_response(this, message, UNSUPPORTED_CRITICAL_PAYLOAD); - } - break; - case PARSE_ERROR: - DBG1(DBG_IKE, "message parsing failed"); - if (is_request) - { - send_notify_response(this, message, INVALID_SYNTAX); - } - break; - case VERIFY_ERROR: - DBG1(DBG_IKE, "message verification failed"); - if (is_request) - { - send_notify_response(this, message, INVALID_SYNTAX); - } - break; - case FAILED: - DBG1(DBG_IKE, "integrity check failed"); - /* ignored */ - break; - case INVALID_STATE: - DBG1(DBG_IKE, "found encrypted message, but no keys available"); - if (is_request) - { - send_notify_response(this, message, INVALID_SYNTAX); - } - default: - break; - } - } - DBG1(DBG_IKE, "%N %s with message ID %d processing failed", - exchange_type_names, message->get_exchange_type(message), - message->get_request(message) ? "request" : "response", - message->get_message_id(message)); - return status; - } - else - { - host_t *me, *other; - - me = message->get_destination(message); - other = message->get_source(message); - - /* if this IKE_SA is virgin, we check for a config */ - if (this->ike_cfg == NULL) - { - job_t *job; - this->ike_cfg = charon->backends->get_ike_cfg(charon->backends, - me, other); - if (this->ike_cfg == NULL) - { - /* no config found for these hosts, destroy */ - DBG1(DBG_IKE, "no IKE config found for %H...%H, sending %N", - me, other, notify_type_names, NO_PROPOSAL_CHOSEN); - send_notify_response(this, message, NO_PROPOSAL_CHOSEN); - return DESTROY_ME; - } - /* add a timeout if peer does not establish it completely */ - job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, FALSE); - charon->scheduler->schedule_job(charon->scheduler, job, - HALF_OPEN_IKE_SA_TIMEOUT); - } - - /* check if message is trustworthy, and update host information */ - if (this->state == IKE_CREATED || this->state == IKE_CONNECTING || - message->get_exchange_type(message) != IKE_SA_INIT) - { - update_hosts(this, me, other); - this->time.inbound = time(NULL); - } - return this->task_manager->process_message(this->task_manager, message); - } -} - -/** * Implementation of ike_sa_t.initiate. */ static status_t initiate(private_ike_sa_t *this, child_cfg_t *child_cfg) @@ -1162,6 +1065,150 @@ static status_t unroute(private_ike_sa_t *this, u_int32_t reqid) } return SUCCESS; } +/** + * Implementation of ike_sa_t.process_message. + */ +static status_t process_message(private_ike_sa_t *this, message_t *message) +{ + status_t status; + bool is_request; + + is_request = message->get_request(message); + + status = message->parse_body(message, this->crypter_in, this->signer_in); + if (status != SUCCESS) + { + + if (is_request) + { + switch (status) + { + case NOT_SUPPORTED: + DBG1(DBG_IKE, "ciritcal unknown payloads found"); + if (is_request) + { + send_notify_response(this, message, UNSUPPORTED_CRITICAL_PAYLOAD); + } + break; + case PARSE_ERROR: + DBG1(DBG_IKE, "message parsing failed"); + if (is_request) + { + send_notify_response(this, message, INVALID_SYNTAX); + } + break; + case VERIFY_ERROR: + DBG1(DBG_IKE, "message verification failed"); + if (is_request) + { + send_notify_response(this, message, INVALID_SYNTAX); + } + break; + case FAILED: + DBG1(DBG_IKE, "integrity check failed"); + /* ignored */ + break; + case INVALID_STATE: + DBG1(DBG_IKE, "found encrypted message, but no keys available"); + if (is_request) + { + send_notify_response(this, message, INVALID_SYNTAX); + } + default: + break; + } + } + DBG1(DBG_IKE, "%N %s with message ID %d processing failed", + exchange_type_names, message->get_exchange_type(message), + message->get_request(message) ? "request" : "response", + message->get_message_id(message)); + return status; + } + else + { + host_t *me, *other; + private_ike_sa_t *new; + iterator_t *iterator; + child_sa_t *child; + bool has_routed = FALSE; + + me = message->get_destination(message); + other = message->get_source(message); + + /* if this IKE_SA is virgin, we check for a config */ + if (this->ike_cfg == NULL) + { + job_t *job; + this->ike_cfg = charon->backends->get_ike_cfg(charon->backends, + me, other); + if (this->ike_cfg == NULL) + { + /* no config found for these hosts, destroy */ + DBG1(DBG_IKE, "no IKE config found for %H...%H, sending %N", + me, other, notify_type_names, NO_PROPOSAL_CHOSEN); + send_notify_response(this, message, NO_PROPOSAL_CHOSEN); + return DESTROY_ME; + } + /* add a timeout if peer does not establish it completely */ + job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, FALSE); + charon->scheduler->schedule_job(charon->scheduler, job, + HALF_OPEN_IKE_SA_TIMEOUT); + } + + /* check if message is trustworthy, and update host information */ + if (this->state == IKE_CREATED || this->state == IKE_CONNECTING || + message->get_exchange_type(message) != IKE_SA_INIT) + { + update_hosts(this, me, other); + this->time.inbound = time(NULL); + } + status = this->task_manager->process_message(this->task_manager, message); + if (status != DESTROY_ME) + { + return status; + } + /* if IKE_SA gets closed for any reasons, reroute routed children */ + iterator = this->child_sas->create_iterator(this->child_sas, TRUE); + while (iterator->iterate(iterator, (void**)&child)) + { + if (child->get_state(child) == CHILD_ROUTED) + { + has_routed = TRUE; + break; + } + } + iterator->destroy(iterator); + if (!has_routed) + { + return status; + } + /* move routed children to a new IKE_SA, apply connection info */ + new = (private_ike_sa_t*)charon->ike_sa_manager->checkout_new( + charon->ike_sa_manager, TRUE); + set_peer_cfg(new, this->peer_cfg); + new->other_host->destroy(new->other_host); + new->other_host = this->other_host->clone(this->other_host); + if (!has_condition(this, COND_NAT_THERE)) + { + new->other_host->set_port(new->other_host, IKEV2_UDP_PORT); + } + if (this->my_virtual_ip) + { + set_virtual_ip(new, TRUE, this->my_virtual_ip); + } + iterator = this->child_sas->create_iterator(this->child_sas, TRUE); + while (iterator->iterate(iterator, (void**)&child)) + { + if (child->get_state(child) == CHILD_ROUTED) + { + route(new, child->get_config(child)); + } + } + iterator->destroy(iterator); + charon->ike_sa_manager->checkin(charon->ike_sa_manager, &new->public); + return status; + } +} /** * Implementation of ike_sa_t.retransmit. @@ -1684,9 +1731,12 @@ static status_t delete_(private_ike_sa_t *this) ike_delete = ike_delete_create(&this->public, TRUE); this->task_manager->queue_task(this->task_manager, &ike_delete->task); return this->task_manager->initiate(this->task_manager); + case IKE_CREATED: + SIG(IKE_DOWN_SUCCESS, "deleting unestablished IKE_SA"); + break; default: - DBG1(DBG_IKE, "destroying IKE_SA in state %N without notification", - ike_sa_state_names, this->state); + SIG(IKE_DOWN_SUCCESS, "destroying IKE_SA in state %N " + "without notification", ike_sa_state_names, this->state); break; } return DESTROY_ME; |