diff options
Diffstat (limited to 'src/charon')
-rw-r--r-- | src/charon/Makefile.am | 1 | ||||
-rw-r--r-- | src/charon/encoding/message.c | 17 | ||||
-rw-r--r-- | src/charon/encoding/payloads/encryption_payload.c | 7 | ||||
-rw-r--r-- | src/charon/sa/ike_sa.c | 246 | ||||
-rw-r--r-- | src/charon/sa/ike_sa.h | 29 | ||||
-rw-r--r-- | src/charon/sa/ike_sa_manager.c | 97 | ||||
-rw-r--r-- | src/charon/sa/ike_sa_manager.h | 19 | ||||
-rw-r--r-- | src/charon/sa/states/delete_requested.c | 163 | ||||
-rw-r--r-- | src/charon/sa/states/delete_requested.h | 57 | ||||
-rw-r--r-- | src/charon/sa/states/ike_auth_requested.c | 32 | ||||
-rw-r--r-- | src/charon/sa/states/ike_sa_established.c | 185 | ||||
-rw-r--r-- | src/charon/sa/states/ike_sa_init_requested.c | 24 | ||||
-rw-r--r-- | src/charon/sa/states/ike_sa_init_responded.c | 23 | ||||
-rw-r--r-- | src/charon/sa/states/initiator_init.c | 8 | ||||
-rw-r--r-- | src/charon/sa/states/initiator_init.h | 4 | ||||
-rw-r--r-- | src/charon/sa/states/responder_init.c | 28 | ||||
-rw-r--r-- | src/charon/sa/states/state.c | 1 | ||||
-rw-r--r-- | src/charon/sa/states/state.h | 19 | ||||
-rw-r--r-- | src/charon/threads/thread_pool.c | 116 |
19 files changed, 633 insertions, 443 deletions
diff --git a/src/charon/Makefile.am b/src/charon/Makefile.am index fa8b322e5..3db6ae48a 100644 --- a/src/charon/Makefile.am +++ b/src/charon/Makefile.am @@ -11,6 +11,7 @@ sa/states/state.c sa/states/state.h sa/states/ike_sa_init_requested.c sa/states/ sa/states/ike_sa_init_responded.c sa/states/ike_sa_established.c sa/states/ike_sa_established.h \ sa/states/responder_init.c sa/states/responder_init.h sa/states/initiator_init.c sa/states/initiator_init.h \ sa/states/ike_sa_init_responded.h sa/states/ike_auth_requested.c sa/states/ike_auth_requested.h \ +sa/states/delete_requested.h sa/states/delete_requested.c \ sa/child_sa.c sa/child_sa.h sa/ike_sa.c sa/ike_sa.h sa/ike_sa_manager.c sa/ike_sa_manager.h \ sa/ike_sa_id.c sa/ike_sa_id.h sa/authenticator.c sa/authenticator.h encoding/payloads/encryption_payload.c \ encoding/payloads/cert_payload.c encoding/payloads/payload.h encoding/payloads/traffic_selector_substructure.c \ diff --git a/src/charon/encoding/message.c b/src/charon/encoding/message.c index a57315272..9875a3df9 100644 --- a/src/charon/encoding/message.c +++ b/src/charon/encoding/message.c @@ -941,7 +941,7 @@ static status_t decrypt_payloads(private_message_t *this,crypter_t *crypter, sig iterator->destroy(iterator); return FAILED; } - /* decrypt */ + /* decrypt */ encryption_payload->set_transforms(encryption_payload, crypter, signer); this->logger->log(this->logger, CONTROL | LEVEL1, "Verify signature of encryption payload"); status = encryption_payload->verify_signature(encryption_payload, this->packet->get_data(this->packet)); @@ -955,8 +955,9 @@ static status_t decrypt_payloads(private_message_t *this,crypter_t *crypter, sig status = encryption_payload->decrypt(encryption_payload); if (status != SUCCESS) { - this->logger->log(this->logger, ERROR | LEVEL1, "Encrypted payload could not be decrypted and parsed: %s", - mapping_find(status_m, status)); + this->logger->log(this->logger, ERROR | LEVEL1, + "Encrypted payload could not be decrypted and parsed: %s", + mapping_find(status_m, status)); iterator->destroy(iterator); return status; } @@ -997,8 +998,9 @@ static status_t decrypt_payloads(private_message_t *this,crypter_t *crypter, sig while (encryption_payload->get_payload_count(encryption_payload) > 0) { encryption_payload->remove_first_payload(encryption_payload, ¤t_encrypted_payload); - this->logger->log(this->logger, CONTROL | LEVEL1, "Insert unencrypted payload of type %s at end of list.", - mapping_find(payload_type_m,current_encrypted_payload->get_type(current_encrypted_payload))); + this->logger->log(this->logger, CONTROL | LEVEL1, + "Insert unencrypted payload of type %s at end of list.", + mapping_find(payload_type_m, current_encrypted_payload->get_type(current_encrypted_payload))); this->payloads->insert_last(this->payloads,current_encrypted_payload); } @@ -1007,14 +1009,15 @@ static status_t decrypt_payloads(private_message_t *this,crypter_t *crypter, sig } /* we allow unknown payloads of any type and don't bother if it was encrypted. Not our problem. */ - if (current_payload_type != UNKNOWN_PAYLOAD) + if (current_payload_type != UNKNOWN_PAYLOAD && current_payload_type != NO_PAYLOAD) { /* get the ruleset for found payload */ status = this->get_payload_rule(this, current_payload_type, &payload_rule); if (status != SUCCESS) { /* payload is not allowed */ - this->logger->log(this->logger, ERROR | LEVEL1, "Payload type %s not allowed",mapping_find(payload_type_m,current_payload_type)); + this->logger->log(this->logger, ERROR | LEVEL1, "Payload type %s not allowed", + mapping_find(payload_type_m,current_payload_type)); iterator->destroy(iterator); return status; } diff --git a/src/charon/encoding/payloads/encryption_payload.c b/src/charon/encoding/payloads/encryption_payload.c index e0ca74ff4..358f371e9 100644 --- a/src/charon/encoding/payloads/encryption_payload.c +++ b/src/charon/encoding/payloads/encryption_payload.c @@ -556,13 +556,6 @@ static status_t parse(private_encryption_payload_t *this) status_t status; payload_type_t current_payload_type; - /* check if there is decrypted data */ - if (this->decrypted.ptr == NULL) - { - this->logger->log(this->logger, ERROR, "unable to parse, no input!"); - return INVALID_STATE; - } - /* build a parser on the decrypted data */ parser = parser_create(this->decrypted); diff --git a/src/charon/sa/ike_sa.c b/src/charon/sa/ike_sa.c index 5290bde64..c012ce82b 100644 --- a/src/charon/sa/ike_sa.c +++ b/src/charon/sa/ike_sa.c @@ -42,6 +42,7 @@ #include <sa/states/responder_init.h> #include <queues/jobs/retransmit_request_job.h> #include <queues/jobs/delete_established_ike_sa_job.h> +#include <queues/jobs/delete_half_open_ike_sa_job.h> @@ -186,43 +187,45 @@ struct private_ike_sa_t { * A logger for this IKE_SA. */ logger_t *logger; - - /** - * Resends the last sent reply. - * - * @param this calling object - */ - status_t (*resend_last_reply) (private_ike_sa_t *this); }; /** * Implementation of ike_sa_t.process_message. */ -static status_t process_message (private_ike_sa_t *this, message_t *message) +static status_t process_message(private_ike_sa_t *this, message_t *message) { u_int32_t message_id; exchange_type_t exchange_type; bool is_request; - /* We must process each request or response from remote host */ - + /* Find out type of message (request or response) */ is_request = message->get_request(message); exchange_type = message->get_exchange_type(message); - + this->logger->log(this->logger, CONTROL|LEVEL1, "Process %s of exchange type %s", (is_request) ? "request" : "response",mapping_find(exchange_type_m,exchange_type)); - + message_id = message->get_message_id(message); - + /* * It has to be checked, if the message has to be resent cause of lost packets! */ if (is_request && (message_id == (this->message_id_in - 1))) { - /* Message can be resent ! */ - this->logger->log(this->logger, CONTROL|LEVEL1, "Resent request detected. Send stored reply."); - return (this->resend_last_reply(this)); + /* resend last message, if any */ + if (this->last_responded_message) + { + packet_t *packet = this->last_responded_message->get_packet(this->last_responded_message); + this->logger->log(this->logger, CONTROL|LEVEL1, "Resent request detected. Send stored reply."); + charon->send_queue->add(charon->send_queue, packet); + return SUCCESS; + } + else + { + /* somebody does something nasty here... */ + return FAILED; + } } /* Now, the message id is checked for request AND reply */ @@ -253,7 +256,7 @@ static status_t process_message (private_ike_sa_t *this, message_t *message) * The specific state object is responsible to check if a message can be received in * the state it represents. * The current state is also responsible to change the state object to the next state - * by calling protected_ike_sa_t.set_new_state*/ + * by calling protected_ike_sa_t.set_new_state*/ return this->current_state->process_message(this->current_state,message); } @@ -269,7 +272,7 @@ static void build_message(private_ike_sa_t *this, exchange_type_t type, bool req other = this->connection->get_other_host(this->connection); this->logger->log(this->logger, CONTROL|LEVEL2, "Build empty message"); - new_message = message_create(); + new_message = message_create(); new_message->set_source(new_message, me->clone(me)); new_message->set_destination(new_message, other->clone(other)); new_message->set_exchange_type(new_message, type); @@ -301,55 +304,6 @@ static status_t initiate_connection(private_ike_sa_t *this, connection_t *connec } /** - * Implementation of ike_sa_t.send_delete_ike_sa_request. - */ -static void send_delete_ike_sa_request (private_ike_sa_t *this) -{ - message_t *informational_request; - delete_payload_t *delete_payload; - crypter_t *crypter; - signer_t *signer; - packet_t *packet; - status_t status; - - if (this->current_state->get_state(this->current_state) != IKE_SA_ESTABLISHED) - { - return; - } - - /* build empty INFORMATIONAL message */ - this->protected.build_message(&(this->protected), INFORMATIONAL, TRUE, &informational_request); - - delete_payload = delete_payload_create(); - delete_payload->set_protocol_id(delete_payload, PROTO_IKE); - - informational_request->add_payload(informational_request,(payload_t *)delete_payload); - - if (this->ike_sa_id->is_initiator(this->ike_sa_id)) - { - crypter = this->crypter_initiator; - signer = this->signer_initiator; - } - else - { - crypter = this->crypter_responder; - signer = this->signer_responder; - } - - status = informational_request->generate(informational_request, - crypter, - signer, &packet); - informational_request->destroy(informational_request); - if (status != SUCCESS) - { - this->logger->log(this->logger, ERROR, "Could not generate packet from message"); - return ; - } - - charon->send_queue->add(charon->send_queue,packet); -} - -/** * Implementation of ike_sa_t.get_id. */ static ike_sa_id_t* get_id(private_ike_sa_t *this) @@ -390,20 +344,6 @@ static identification_t* get_other_id(private_ike_sa_t *this) } /** - * Implementation of private_ike_sa_t.resend_last_reply. - */ -static status_t resend_last_reply(private_ike_sa_t *this) -{ - packet_t *packet; - - this->logger->log(this->logger, CONTROL | LEVEL1, "Going to retransmit last reply"); - packet = this->last_responded_message->get_packet(this->last_responded_message); - charon->send_queue->add(charon->send_queue, packet); - - return SUCCESS; -} - -/** * Implementation of ike_sa_t.retransmit_request. */ status_t retransmit_request (private_ike_sa_t *this, u_int32_t message_id) @@ -431,22 +371,30 @@ status_t retransmit_request (private_ike_sa_t *this, u_int32_t message_id) return SUCCESS; } + +/** + * Implementation of ike_sa_t.get_state. + */ +static ike_sa_state_t get_state(private_ike_sa_t *this) +{ + return this->current_state->get_state(this->current_state); +} /** * Implementation of protected_ike_sa_t.set_new_state. */ -static void set_new_state (private_ike_sa_t *this, state_t *state) +static void set_new_state(private_ike_sa_t *this, state_t *state) { this->logger->log(this->logger, CONTROL, "statechange: %s => %s", - mapping_find(ike_sa_state_m,this->current_state->get_state(this->current_state)), - mapping_find(ike_sa_state_m,state->get_state(state))); + mapping_find(ike_sa_state_m, get_state(this)), + mapping_find(ike_sa_state_m, state->get_state(state))); this->current_state = state; } /** * Implementation of protected_ike_sa_t.get_connection. */ -static connection_t *get_connection (private_ike_sa_t *this) +static connection_t *get_connection(private_ike_sa_t *this) { return this->connection; } @@ -454,7 +402,7 @@ static connection_t *get_connection (private_ike_sa_t *this) /** * Implementation of protected_ike_sa_t.set_connection. */ -static void set_connection (private_ike_sa_t *this,connection_t * connection) +static void set_connection(private_ike_sa_t *this,connection_t * connection) { this->connection = connection; } @@ -462,7 +410,7 @@ static void set_connection (private_ike_sa_t *this,connection_t * connection) /** * Implementation of protected_ike_sa_t.get_policy. */ -static policy_t *get_policy (private_ike_sa_t *this) +static policy_t *get_policy(private_ike_sa_t *this) { return this->policy; } @@ -470,7 +418,7 @@ static policy_t *get_policy (private_ike_sa_t *this) /** * Implementation of protected_ike_sa_t.set_policy. */ -static void set_policy (private_ike_sa_t *this,policy_t * policy) +static void set_policy(private_ike_sa_t *this,policy_t * policy) { this->policy = policy; } @@ -478,7 +426,7 @@ static void set_policy (private_ike_sa_t *this,policy_t * policy) /** * Implementation of protected_ike_sa_t.get_prf. */ -static prf_t *get_prf (private_ike_sa_t *this) +static prf_t *get_prf(private_ike_sa_t *this) { return this->prf; } @@ -486,7 +434,7 @@ static prf_t *get_prf (private_ike_sa_t *this) /** * Implementation of protected_ike_sa_t.get_prf. */ -static prf_t *get_child_prf (private_ike_sa_t *this) +static prf_t *get_child_prf(private_ike_sa_t *this) { return this->child_prf; } @@ -494,7 +442,7 @@ static prf_t *get_child_prf (private_ike_sa_t *this) /** * Implementation of protected_ike_sa_t.get_prf_auth_i. */ -static prf_t *get_prf_auth_i (private_ike_sa_t *this) +static prf_t *get_prf_auth_i(private_ike_sa_t *this) { return this->prf_auth_i; } @@ -502,7 +450,7 @@ static prf_t *get_prf_auth_i (private_ike_sa_t *this) /** * Implementation of protected_ike_sa_t.get_prf_auth_r. */ -static prf_t *get_prf_auth_r (private_ike_sa_t *this) +static prf_t *get_prf_auth_r(private_ike_sa_t *this) { return this->prf_auth_r; } @@ -701,7 +649,7 @@ static status_t build_transforms(private_ike_sa_t *this, proposal_t *proposal, d /** * Implementation of protected_ike_sa_t.get_randomizer. */ -static randomizer_t *get_randomizer (private_ike_sa_t *this) +static randomizer_t *get_randomizer(private_ike_sa_t *this) { return this->randomizer; } @@ -709,7 +657,7 @@ static randomizer_t *get_randomizer (private_ike_sa_t *this) /** * Implementation of protected_ike_sa_t.get_crypter_initiator. */ -static crypter_t *get_crypter_initiator (private_ike_sa_t *this) +static crypter_t *get_crypter_initiator(private_ike_sa_t *this) { return this->crypter_initiator; } @@ -717,7 +665,7 @@ static crypter_t *get_crypter_initiator (private_ike_sa_t *this) /** * Implementation of protected_ike_sa_t.get_signer_initiator. */ -static signer_t *get_signer_initiator (private_ike_sa_t *this) +static signer_t *get_signer_initiator(private_ike_sa_t *this) { return this->signer_initiator; } @@ -733,7 +681,7 @@ static crypter_t *get_crypter_responder(private_ike_sa_t *this) /** * Implementation of protected_ike_sa_t.get_signer_responder. */ -static signer_t *get_signer_responder (private_ike_sa_t *this) +static signer_t *get_signer_responder(private_ike_sa_t *this) { return this->signer_responder; } @@ -741,7 +689,7 @@ static signer_t *get_signer_responder (private_ike_sa_t *this) /** * Implementation of protected_ike_sa_t.send_request. */ -static status_t send_request (private_ike_sa_t *this,message_t * message) +static status_t send_request(private_ike_sa_t *this, message_t *message) { retransmit_request_job_t *retransmit_job; u_int32_t timeout; @@ -783,29 +731,25 @@ static status_t send_request (private_ike_sa_t *this,message_t * message) this->message_id_out); charon->send_queue->add(charon->send_queue, packet); + /* replace last message for retransmit with current */ if (this->last_requested_message != NULL) { - /* destroy message */ this->last_requested_message->destroy(this->last_requested_message); - } - + } this->logger->log(this->logger, CONTROL|LEVEL3, "Replace last requested message with new one"); this->last_requested_message = message; - retransmit_job = retransmit_request_job_create(this->message_id_out,this->ike_sa_id); - - status = charon->configuration->get_retransmit_timeout (charon->configuration, - retransmit_job->get_retransmit_count(retransmit_job),&timeout); - + /* schedule a job for retransmission */ + status = charon->configuration->get_retransmit_timeout(charon->configuration, 0, &timeout); if (status != SUCCESS) { this->logger->log(this->logger, CONTROL|LEVEL2, "No retransmit job for message created!"); - retransmit_job->destroy(retransmit_job); } else { - this->logger->log(this->logger, CONTROL|LEVEL2, "Request will be retransmitted in %d ms.",timeout); - charon->event_queue->add_relative(charon->event_queue,(job_t *) retransmit_job,timeout); + this->logger->log(this->logger, CONTROL|LEVEL2, "Request will be retransmitted in %d ms.", timeout); + retransmit_job = retransmit_request_job_create(this->message_id_out, this->ike_sa_id); + charon->event_queue->add_relative(charon->event_queue, (job_t *)retransmit_job, timeout); } /* message counter can now be increased */ @@ -819,7 +763,7 @@ static status_t send_request (private_ike_sa_t *this,message_t * message) /** * Implementation of protected_ike_sa_t.send_response. */ -static status_t send_response (private_ike_sa_t *this,message_t * message) +static status_t send_response(private_ike_sa_t *this, message_t *message) { crypter_t *crypter; signer_t *signer; @@ -832,7 +776,6 @@ static status_t send_response (private_ike_sa_t *this,message_t * message) return FAILED; } - if (this->ike_sa_id->is_initiator(this->ike_sa_id)) { crypter = this->crypter_initiator; @@ -922,7 +865,7 @@ static void set_last_replied_message_id (private_ike_sa_t *this,u_int32_t messag /** * Implementation of protected_ike_sa_t.get_last_responded_message. */ -static message_t * get_last_responded_message (private_ike_sa_t *this) +static message_t *get_last_responded_message (private_ike_sa_t *this) { return this->last_responded_message; } @@ -930,23 +873,15 @@ static message_t * get_last_responded_message (private_ike_sa_t *this) /** * Implementation of protected_ike_sa_t.get_last_requested_message. */ -static message_t * get_last_requested_message (private_ike_sa_t *this) +static message_t *get_last_requested_message(private_ike_sa_t *this) { return this->last_requested_message; } /** - * Implementation of ike_sa_t.get_state. - */ -static ike_sa_state_t get_state (private_ike_sa_t *this) -{ - return this->current_state->get_state(this->current_state); -} - -/** * Implementation of protected_ike_sa_t.add_child_sa. */ -static void add_child_sa (private_ike_sa_t *this, child_sa_t *child_sa) +static void add_child_sa(private_ike_sa_t *this, child_sa_t *child_sa) { this->child_sas->insert_last(this->child_sas, child_sa); } @@ -954,7 +889,7 @@ static void add_child_sa (private_ike_sa_t *this, child_sa_t *child_sa) /** * Implementation of protected_ike_sa_t.reset_message_buffers. */ -static void reset_message_buffers (private_ike_sa_t *this) +static void reset_message_buffers(private_ike_sa_t *this) { this->logger->log(this->logger, CONTROL|LEVEL2, "Reset message counters and destroy stored messages"); /* destroy stored requested message */ @@ -983,6 +918,8 @@ static void log_status(private_ike_sa_t *this, logger_t *logger, char *name) { iterator_t *iterator; child_sa_t *child_sa; + host_t *my_host, *other_host; + identification_t *my_id, *other_id; /* only log if name == NULL or name == connection_name */ if (name) @@ -997,11 +934,11 @@ static void log_status(private_ike_sa_t *this, logger_t *logger, char *name) name = this->connection->get_name(this->connection); } - host_t *my_host = this->connection->get_my_host(this->connection); - host_t *other_host = this->connection->get_other_host(this->connection); + my_host = this->connection->get_my_host(this->connection); + other_host = this->connection->get_other_host(this->connection); - identification_t *my_id = this->connection->get_my_id(this->connection); - identification_t *other_id = this->connection->get_other_id(this->connection); + my_id = this->connection->get_my_id(this->connection); + other_id = this->connection->get_other_id(this->connection); if (logger == NULL) { @@ -1029,9 +966,52 @@ static void log_status(private_ike_sa_t *this, logger_t *logger, char *name) } /** + * Implementation of public_ike_sa_t.delete. + */ +static status_t delete_(private_ike_sa_t *this) +{ + message_t *informational_request; + delete_payload_t *delete_payload; + u_int32_t timeout; + delete_half_open_ike_sa_job_t *job; + + if (get_state(this) != IKE_SA_ESTABLISHED) + { + this->logger->log(this->logger, ERROR, "Closing a not established IKE SA not allowed, aborting!"); + return INVALID_STATE; + } + + build_message(this, INFORMATIONAL, TRUE, &informational_request); + /* delete for the full IKE_SA, this deletes all child_sa's implicit */ + delete_payload = delete_payload_create(); + delete_payload->set_protocol_id(delete_payload, PROTO_IKE); + + informational_request->add_payload(informational_request, (payload_t*)delete_payload); + + if (send_request(this, informational_request) != SUCCESS) + { + /* send failed, but we ignore this, SA will get deleted anyway later */ + informational_request->destroy(informational_request); + } + + /* transit to state delete_requested */ + this->current_state->destroy(this->current_state); + set_new_state(this, (state_t*)delete_requested_create(this)); + + /* there is no guarantee that the other peer will acknowledge the delete, + * so we have to set a timeout where we destroy the SA... This is done with + * the delete_half_open_ike_sa_job as used in IKE SA setup. + */ + timeout = charon->configuration->get_half_open_ike_sa_timeout(charon->configuration); + job = delete_half_open_ike_sa_job_create(this->ike_sa_id); + charon->event_queue->add_relative(charon->event_queue, (job_t*)job, timeout); + return SUCCESS; +} + +/** * Implementation of protected_ike_sa_t.destroy. */ -static void destroy (private_ike_sa_t *this) +static void destroy(private_ike_sa_t *this) { child_sa_t *child_sa; @@ -1039,9 +1019,12 @@ static void destroy (private_ike_sa_t *this) this->ike_sa_id->get_initiator_spi(this->ike_sa_id), this->ike_sa_id->get_responder_spi(this->ike_sa_id), this->ike_sa_id->is_initiator(this->ike_sa_id) ? "initiator" : "responder"); + + if (get_state(this) == IKE_SA_ESTABLISHED) + { + this->logger->log(this->logger, ERROR, "Destroying an established IKE SA without knowledge from remote peer!"); + } - /* inform other peer of delete */ - send_delete_ike_sa_request(this); while (this->child_sas->remove_last(this->child_sas, (void**)&child_sa) == SUCCESS) { child_sa->destroy(child_sa); @@ -1127,8 +1110,8 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->protected.public.get_connection = (connection_t*(*)(ike_sa_t*)) get_connection; this->protected.public.retransmit_request = (status_t (*) (ike_sa_t *, u_int32_t)) retransmit_request; this->protected.public.get_state = (ike_sa_state_t (*) (ike_sa_t *this)) get_state; - this->protected.public.send_delete_ike_sa_request = (void (*)(ike_sa_t*)) send_delete_ike_sa_request; this->protected.public.log_status = (void (*) (ike_sa_t*,logger_t*,char*))log_status; + this->protected.public.delete = (status_t(*)(ike_sa_t*))delete_; this->protected.public.destroy = (void(*)(ike_sa_t*))destroy; /* protected functions */ @@ -1158,9 +1141,6 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->protected.set_last_replied_message_id = (void (*) (protected_ike_sa_t *,u_int32_t)) set_last_replied_message_id; - /* private functions */ - this->resend_last_reply = resend_last_reply; - /* initialize private fields */ this->logger = logger_manager->get_logger(logger_manager, IKE_SA); diff --git a/src/charon/sa/ike_sa.h b/src/charon/sa/ike_sa.h index a4ab82cef..31a5ba8a1 100644 --- a/src/charon/sa/ike_sa.h +++ b/src/charon/sa/ike_sa.h @@ -73,7 +73,7 @@ struct ike_sa_t { * @return * - SUCCESS * - FAILED - * - DELETE_ME if this IKE_SA MUST be deleted + * - DESTROY_ME if this IKE_SA MUST be deleted */ status_t (*process_message) (ike_sa_t *this,message_t *message); @@ -88,7 +88,7 @@ struct ike_sa_t { * @return * - SUCCESS if initialization started * - FAILED if in wrong state - * - DELETE_ME if initialization failed and IKE_SA MUST be deleted + * - DESTROY_ME if initialization failed and IKE_SA MUST be deleted */ status_t (*initiate_connection) (ike_sa_t *this, connection_t *connection); @@ -102,15 +102,6 @@ struct ike_sa_t { * - NOT_FOUND if request doesn't have to be retransmited */ status_t (*retransmit_request) (ike_sa_t *this, u_int32_t message_id); - - /** - * @brief Sends a request to delete IKE_SA. - * - * Only supported in state IKE_SA_ESTABLISHED - * - * @param this calling object - */ - void (*send_delete_ike_sa_request) (ike_sa_t *this); /** * @brief Get the id of the SA. @@ -188,6 +179,22 @@ struct ike_sa_t { * @param name name of the connection */ void (*log_status) (ike_sa_t *this, logger_t *logger, char *name); + + /** + * @brief Initiates the deletion of an IKE_SA. + * + * Sends a delete message to the remote peer and waits for + * its response. If the response comes in, or a timeout occur, + * the IKE SA gets deleted. + * + * @param this calling object + * @return + * - SUCCESS if deletion is initialized + * - INVALID_STATE, if the IKE_SA is not in + * an established state and can not be + * delete (but destroyed). + */ + status_t (*delete) (ike_sa_t *this); /** * @brief Destroys a ike_sa_t object. diff --git a/src/charon/sa/ike_sa_manager.c b/src/charon/sa/ike_sa_manager.c index e6c8e4982..475898e26 100644 --- a/src/charon/sa/ike_sa_manager.c +++ b/src/charon/sa/ike_sa_manager.c @@ -137,7 +137,7 @@ struct private_ike_sa_manager_t { /** * @brief Get next spi. * - * We give out SPIs incremental starting at 1. + * We give out SPIs from a pseudo random source * * @param this the ike_sa_manager * @return the next spi @@ -232,7 +232,8 @@ static status_t get_entry_by_id(private_ike_sa_manager_t *this, ike_sa_id_t *ike if ((current->ike_sa_id->get_initiator_spi(current->ike_sa_id) == ike_sa_id->get_initiator_spi(ike_sa_id)) && (ike_sa_id->is_initiator(ike_sa_id) == current->ike_sa_id->is_initiator(current->ike_sa_id))) { - this->logger->log(this->logger,CONTROL | LEVEL2,"Found entry by initiator spi %d",ike_sa_id->get_initiator_spi(ike_sa_id)); + this->logger->log(this->logger, CONTROL|LEVEL2, "Found entry by initiator spi %d", + ike_sa_id->get_initiator_spi(ike_sa_id)); *entry = current; status = SUCCESS; break; @@ -243,7 +244,8 @@ static status_t get_entry_by_id(private_ike_sa_manager_t *this, ike_sa_id_t *ike if ((current->ike_sa_id->get_initiator_spi(current->ike_sa_id) == ike_sa_id->get_initiator_spi(ike_sa_id)) && (ike_sa_id->is_initiator(ike_sa_id) == current->ike_sa_id->is_initiator(current->ike_sa_id))) { - this->logger->log(this->logger,CONTROL | LEVEL2,"Found entry by initiator spi %d",ike_sa_id->get_initiator_spi(ike_sa_id)); + this->logger->log(this->logger, CONTROL|LEVEL2, "Found entry by initiator spi %d", + ike_sa_id->get_initiator_spi(ike_sa_id)); *entry = current; status = SUCCESS; break; @@ -251,7 +253,7 @@ static status_t get_entry_by_id(private_ike_sa_manager_t *this, ike_sa_id_t *ike } if (current->ike_sa_id->equals(current->ike_sa_id, ike_sa_id)) { - this->logger->log(this->logger,CONTROL | LEVEL2,"Found entry by full ID"); + this->logger->log(this->logger, CONTROL|LEVEL2, "Found entry by full ID"); *entry = current; status = SUCCESS; break; @@ -283,7 +285,7 @@ static status_t get_entry_by_sa(private_ike_sa_manager_t *this, ike_sa_t *ike_sa /* only pointers are compared */ if (current->ike_sa == ike_sa) { - this->logger->log(this->logger,CONTROL | LEVEL2,"Found entry by pointer"); + this->logger->log(this->logger, CONTROL|LEVEL2, "Found entry by pointer"); *entry = current; status = SUCCESS; break; @@ -305,7 +307,7 @@ static status_t delete_entry(private_ike_sa_manager_t *this, ike_sa_entry_t *ent iterator = list->create_iterator(list, TRUE); - status = NOT_FOUND; + status = NOT_FOUND; while (iterator->has_next(iterator)) { @@ -313,7 +315,7 @@ static status_t delete_entry(private_ike_sa_manager_t *this, ike_sa_entry_t *ent iterator->current(iterator, (void**)¤t); if (current == entry) { - this->logger->log(this->logger,CONTROL | LEVEL2,"Found entry by pointer. Going to delete it."); + this->logger->log(this->logger, CONTROL|LEVEL2, "Found entry by pointer. Going to delete it."); iterator->remove(iterator); entry->destroy(entry); status = SUCCESS; @@ -360,7 +362,7 @@ static void create_and_checkout(private_ike_sa_manager_t *this,ike_sa_t **ike_sa this->ike_sa_list->insert_last(this->ike_sa_list, new_ike_sa_entry); /* check ike_sa out */ - this->logger->log(this->logger,CONTROL | LEVEL1 ,"New IKE_SA created and added to list of known IKE_SA's"); + this->logger->log(this->logger, CONTROL|LEVEL1, "New IKE_SA created and added to list of known IKE_SA's"); new_ike_sa_entry->checked_out = TRUE; *ike_sa = new_ike_sa_entry->ike_sa; @@ -397,7 +399,7 @@ static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id, /* can we give this ike_sa out to new requesters?*/ if (entry->driveout_new_threads) { - this->logger->log(this->logger,CONTROL|LEVEL1,"Drive out new thread for existing IKE_SA"); + this->logger->log(this->logger, CONTROL|LEVEL1, "Drive out new thread for existing IKE_SA"); /* no we can't */ retval = NOT_FOUND; } @@ -420,12 +422,12 @@ static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id, { /* we must signal here, others are interested that we leave */ pthread_cond_signal(&(entry->condvar)); - this->logger->log(this->logger,CONTROL|LEVEL1,"Drive out waiting thread for existing IKE_SA"); + this->logger->log(this->logger, CONTROL|LEVEL1, "Drive out waiting thread for existing IKE_SA"); retval = NOT_FOUND; } else { - this->logger->log(this->logger,CONTROL|LEVEL2,"IKE SA successfully checked out"); + this->logger->log(this->logger, CONTROL|LEVEL2, "IKE SA successfully checked out"); /* ok, this IKE_SA is finally ours */ entry->checked_out = TRUE; *ike_sa = entry->ike_sa; @@ -436,7 +438,7 @@ static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id, } else { - this->logger->log(this->logger,ERROR | LEVEL1,"IKE SA not stored in known IKE_SA list"); + this->logger->log(this->logger, ERROR|LEVEL1, "IKE SA not stored in known IKE_SA list"); /* looks like there is no such IKE_SA, better luck next time... */ /* DON'T use return, we must unlock the mutex! */ retval = NOT_FOUND; @@ -467,7 +469,7 @@ static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id, this->ike_sa_list->insert_last(this->ike_sa_list, new_ike_sa_entry); /* check ike_sa out */ - this->logger->log(this->logger,CONTROL | LEVEL1 ,"IKE_SA added to list of known IKE_SA's"); + this->logger->log(this->logger, CONTROL|LEVEL1 ,"IKE_SA added to list of known IKE_SA's"); new_ike_sa_entry->checked_out = TRUE; *ike_sa = new_ike_sa_entry->ike_sa; @@ -476,7 +478,7 @@ static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id, else { /* responder set, initiator not: here is something seriously wrong! */ - this->logger->log(this->logger,ERROR | LEVEL1, "Invalid IKE_SA SPI's"); + this->logger->log(this->logger, ERROR|LEVEL1, "Invalid IKE_SA SPI's"); /* DON'T use return, we must unlock the mutex! */ retval = INVALID_ARG; } @@ -644,13 +646,13 @@ static status_t checkin(private_ike_sa_manager_t *this, ike_sa_t *ike_sa) entry->ike_sa_id->replace_values(entry->ike_sa_id, ike_sa->get_id(ike_sa)); /* signal waiting threads */ entry->checked_out = FALSE; - this->logger->log(this->logger,CONTROL | LEVEL1,"Checkin of IKE_SA successful."); + this->logger->log(this->logger, CONTROL|LEVEL1, "Checkin of IKE_SA successful."); pthread_cond_signal(&(entry->condvar)); retval = SUCCESS; } else { - this->logger->log(this->logger,ERROR,"Fatal Error: Tried to checkin nonexisting IKE_SA"); + this->logger->log(this->logger, ERROR, "Tried to checkin nonexisting IKE_SA"); /* this SA is no more, this REALLY should not happen */ retval = NOT_FOUND; } @@ -660,9 +662,9 @@ static status_t checkin(private_ike_sa_manager_t *this, ike_sa_t *ike_sa) /** - * Implementation of ike_sa_manager_t.checkin_and_delete. + * Implementation of ike_sa_manager_t.checkin_and_destroy. */ -static status_t checkin_and_delete(private_ike_sa_manager_t *this, ike_sa_t *ike_sa) +static status_t checkin_and_destroy(private_ike_sa_manager_t *this, ike_sa_t *ike_sa) { /* deletion is a bit complex, we must garant that no thread is waiting for * this SA. @@ -682,21 +684,21 @@ static status_t checkin_and_delete(private_ike_sa_manager_t *this, ike_sa_t *ike entry->driveout_waiting_threads = TRUE; /* wait until all workers have done their work */ - while (entry->waiting_threads > 0) + while (entry->waiting_threads) { - /* let the other threads do some work*/ - pthread_cond_signal(&(entry->condvar)); + /* let the other threads leave the manager */ + pthread_cond_broadcast(&(entry->condvar)); /* and the nice thing, they will wake us again when their work is done */ pthread_cond_wait(&(entry->condvar), &(this->mutex)); } /* ok, we are alone now, no threads waiting in the entry's condvar */ this->delete_entry(this, entry); - this->logger->log(this->logger,CONTROL | LEVEL1,"Checkin and delete of IKE_SA successful"); + this->logger->log(this->logger, CONTROL|LEVEL1, "Checkin and destroy of IKE_SA successful"); retval = SUCCESS; } else { - this->logger->log(this->logger,ERROR,"Fatal Error: Tried to checkin and delete nonexisting IKE_SA"); + this->logger->log(this->logger,ERROR, "Tried to checkin and delete nonexisting IKE_SA"); retval = NOT_FOUND; } @@ -707,7 +709,7 @@ static status_t checkin_and_delete(private_ike_sa_manager_t *this, ike_sa_t *ike /** * Implementation of ike_sa_manager_t.delete. */ -static status_t delete(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id) +static status_t delete_(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id) { /* deletion is a bit complex, we must garant that no thread is waiting for * this SA. @@ -721,25 +723,38 @@ static status_t delete(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id) if (this->get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS) { - /* mark it, so now new threads can acquire this SA */ - entry->driveout_new_threads = TRUE; - - /* wait until all workers have done their work */ - while (entry->waiting_threads) + /* we try a delete. If it succeeds, our job is done here. The + * other peer will reply, and the IKE SA gets the finally deleted... + */ + if (entry->ike_sa->delete(entry->ike_sa) == SUCCESS) { - /* wake up all */ - pthread_cond_signal(&(entry->condvar)); - /* and the nice thing, they will wake us again when their work is done */ - pthread_cond_wait(&(entry->condvar), &(this->mutex)); + this->logger->log(this->logger, CONTROL|LEVEL1, "Initiated delete for IKE_SA"); + } + /* but if the IKE SA is not in a state where the deletion is negotiated with + * the other peer, we can destroy the IKE SA on our own. For this, we must + * be sure that really NO other threads are waiting for this SA... + */ + else + { + /* mark it, so now new threads can acquire this SA */ + entry->driveout_new_threads = TRUE; + /* wait until all workers have done their work */ + while (entry->waiting_threads) + { + /* wake up all */ + pthread_cond_broadcast(&(entry->condvar)); + /* and the nice thing, they will wake us again when their work is done */ + pthread_cond_wait(&(entry->condvar), &(this->mutex)); + } + /* ok, we are alone now, no threads waiting in the entry's condvar */ + this->delete_entry(this, entry); + this->logger->log(this->logger, CONTROL|LEVEL1, "Destroyed IKE_SA"); } - /* ok, we are alone now, no threads waiting in the entry's condvar */ - this->delete_entry(this, entry); - this->logger->log(this->logger,CONTROL | LEVEL1,"Delete of IKE_SA successful"); retval = SUCCESS; } else { - this->logger->log(this->logger,ERROR,"Fatal Error: Tried to delete nonexisting IKE_SA"); + this->logger->log(this->logger,ERROR, "Tried to delete nonexisting IKE_SA"); retval = NOT_FOUND; } @@ -782,9 +797,9 @@ static void destroy(private_ike_sa_manager_t *this) while (entry->waiting_threads) { /* wake up all */ - pthread_cond_signal(&(entry->condvar)); + pthread_cond_broadcast(&(entry->condvar)); /* go sleeping until they are gone */ - pthread_cond_wait(&(entry->condvar), &(this->mutex)); + pthread_cond_wait(&(entry->condvar), &(this->mutex)); } } this->logger->log(this->logger,CONTROL | LEVEL2,"Delete all IKE_SA's"); @@ -821,8 +836,8 @@ ike_sa_manager_t *ike_sa_manager_create() this->public.get_ike_sa_list_by_name = (linked_list_t*(*)(ike_sa_manager_t*,const char*))get_ike_sa_list_by_name; this->public.log_status = (void(*)(ike_sa_manager_t*,logger_t*,char*))log_status; this->public.checkin = (status_t(*)(ike_sa_manager_t*,ike_sa_t*))checkin; - this->public.delete = (status_t(*)(ike_sa_manager_t*,ike_sa_id_t*))delete; - this->public.checkin_and_delete = (status_t(*)(ike_sa_manager_t*,ike_sa_t*))checkin_and_delete; + this->public.delete = (status_t(*)(ike_sa_manager_t*,ike_sa_id_t*))delete_; + this->public.checkin_and_destroy = (status_t(*)(ike_sa_manager_t*,ike_sa_t*))checkin_and_destroy; /* initialize private functions */ this->get_next_spi = get_next_spi; diff --git a/src/charon/sa/ike_sa_manager.h b/src/charon/sa/ike_sa_manager.h index d4cd749dc..a608052bd 100644 --- a/src/charon/sa/ike_sa_manager.h +++ b/src/charon/sa/ike_sa_manager.h @@ -149,10 +149,14 @@ struct ike_sa_manager_t { /** * @brief Delete a SA, which was not checked out. - * + * + * If the state allows it, the IKE SA is destroyed immediately. If it is + * in the state ike_sa_established or further, a delete message + * is sent to the remote peer, which has to be acknowledged. + * * @warning do not use this when the SA is already checked out, this will * deadlock! - * + * * @param this the manager object * @param ike_sa_id[in/out] the SA identifier * @returns @@ -162,7 +166,14 @@ struct ike_sa_manager_t { status_t (*delete) (ike_sa_manager_t* this, ike_sa_id_t *ike_sa_id); /** - * @brief Delete a checked out SA. + * @brief Destroy a checked out SA. + * + * The IKE SA is destroyed without notification of the remote peer. + * Use this only if the other peer doesn't respond or behaves not + * as predicted. + * Checking in and destruction is an atomic operation (for the IKE_SA), + * so this can be called if the SA is in a "unclean" state, without the + * risk that another thread can get the SA. * * @param this the manager object * @param ike_sa SA to delete @@ -170,7 +181,7 @@ struct ike_sa_manager_t { * - SUCCESS if found * - NOT_FOUND when no such SA is available */ - status_t (*checkin_and_delete) (ike_sa_manager_t* this, ike_sa_t *ike_sa); + status_t (*checkin_and_destroy) (ike_sa_manager_t* this, ike_sa_t *ike_sa); /** * @brief Destroys the manager with all associated SAs. diff --git a/src/charon/sa/states/delete_requested.c b/src/charon/sa/states/delete_requested.c new file mode 100644 index 000000000..ff6ec1d48 --- /dev/null +++ b/src/charon/sa/states/delete_requested.c @@ -0,0 +1,163 @@ +/** + * @file delete_requested.c + * + * @brief Implementation of delete_requested_t. + * + */ + +/* + * Copyright (C) 2006 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * 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. + */ + +#include "delete_requested.h" + +#include <daemon.h> + + +typedef struct private_delete_requested_t private_delete_requested_t; + +/** + * Private data of a delete_requested_t object. + */ +struct private_delete_requested_t { + + /** + * methods of the state_t interface + */ + delete_requested_t public; + + /** + * Assigned IKE_SA. + */ + protected_ike_sa_t *ike_sa; + + /** + * Assigned logger. Use logger of IKE_SA. + */ + logger_t *logger; +}; + +/** + * Implements state_t.get_state + */ +static status_t process_message(private_delete_requested_t *this, message_t *message) +{ + ike_sa_id_t *ike_sa_id; + crypter_t *crypter; + signer_t *signer; + status_t status; + + /* Notation as follows: + * Mx{D} means: Message, with message ID "x", containing a Delete payload + * + * The clarifcation Document says in 5.8, that a IKE_SA delete should not + * be acknowledged with the same delete. This only makes sense for CHILD_SAs, + * as they are paired. IKE_SAs are not, there is only one for both ends. + * + * Normal case: + * ---------------- + * Mx{D} --> + * <-- Mx{} + * Delete request is sent, and we wait for the acknowledge. + * + * Special case 1: + * --------------- + * Mx{D} --> + * <-- My{D} + * My{} --> + * <-- Mx{} + * Both initate a delete at the same time. We ack the delete, but wait for + * our delete to be acknowledged. + */ + + if (message->get_exchange_type(message) != INFORMATIONAL) + { + /* anything other than information is ignored. We can an will not handle + * messages such as CREATE_CHILD_SA */ + this->logger->log(this->logger, ERROR | LEVEL1, + "%s messages not supported in state delete_requested. Ignored", + mapping_find(exchange_type_m, message->get_exchange_type(message))); + return FAILED; + } + + if (message->get_request(message)) + { + /* if it is a request, not a reply to our delete request, we + * just acknowledge this. We stay in our state, as the other peer + * has to ACK our request. + */ + message_t *acknowledge; + this->ike_sa->build_message(this->ike_sa, INFORMATIONAL, FALSE, &acknowledge); + return this->ike_sa->send_response(this->ike_sa, acknowledge); + } + + /* get signer for verification and crypter for decryption */ + ike_sa_id = this->ike_sa->public.get_id(&(this->ike_sa->public)); + if (!ike_sa_id->is_initiator(ike_sa_id)) + { + crypter = this->ike_sa->get_crypter_initiator(this->ike_sa); + signer = this->ike_sa->get_signer_initiator(this->ike_sa); + } + else + { + crypter = this->ike_sa->get_crypter_responder(this->ike_sa); + signer = this->ike_sa->get_signer_responder(this->ike_sa); + } + + /* parse incoming message, check if it's proper signed */ + status = message->parse_body(message, crypter, signer); + if (status != SUCCESS) + { + this->logger->log(this->logger, AUDIT, "INFORMATIONAL message decryption failed. Ignoring message"); + return status; + } + + /* ok, he knows about the deletion, destroy this IKE SA */ + return DESTROY_ME; +} + +/** + * Implementation of state_t.get_state. + */ +static ike_sa_state_t get_state(private_delete_requested_t *this) +{ + return DELETE_REQUESTED; +} + +/** + * Implementation of state_t.get_state + */ +static void destroy(private_delete_requested_t *this) +{ + free(this); +} + +/* + * Described in header. + */ +delete_requested_t *delete_requested_create(protected_ike_sa_t *ike_sa) +{ + private_delete_requested_t *this = malloc_thing(private_delete_requested_t); + + /* interface functions */ + this->public.state_interface.process_message = (status_t (*) (state_t *,message_t *)) process_message; + this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state; + this->public.state_interface.destroy = (void (*) (state_t *)) destroy; + + /* private data */ + this->ike_sa = ike_sa; + this->logger = logger_manager->get_logger(logger_manager, IKE_SA); + + return &(this->public); +} diff --git a/src/charon/sa/states/delete_requested.h b/src/charon/sa/states/delete_requested.h new file mode 100644 index 000000000..a4c6daba0 --- /dev/null +++ b/src/charon/sa/states/delete_requested.h @@ -0,0 +1,57 @@ +/** + * @file delete_requested.h + * + * @brief Interface of delete_requested_t. + * + */ + +/* + * Copyright (C) 2006 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * 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. + */ + +#ifndef DELETE_REQUESTED_H_ +#define DELETE_REQUESTED_H_ + +#include <sa/states/state.h> +#include <sa/ike_sa.h> + +typedef struct delete_requested_t delete_requested_t; + +/** + * @brief This class represents an the state of a half closed IKE_SA. + * + * @b Constructors: + * - delete_requested_create() + * + * @ingroup states + */ +struct delete_requested_t { + /** + * methods of the state_t interface + */ + state_t state_interface; + +}; + +/** + * @brief Constructor of class delete_requested_t + * + * @param ike_sa assigned ike_sa + * @return created delete_requested_t object + * + * @ingroup states + */ +delete_requested_t *delete_requested_create(protected_ike_sa_t *ike_sa); + +#endif /*DELETE_REQUESTED_H_*/ diff --git a/src/charon/sa/states/ike_auth_requested.c b/src/charon/sa/states/ike_auth_requested.c index 3d49f440f..069f16506 100644 --- a/src/charon/sa/states/ike_auth_requested.c +++ b/src/charon/sa/states/ike_auth_requested.c @@ -107,7 +107,7 @@ struct private_ike_auth_requested_t { * @param idr_payload ID payload of responder * @return * - SUCCESS - * - DELETE_ME + * - DESTROY_ME */ status_t (*process_idr_payload) (private_ike_auth_requested_t *this, id_payload_t *idr_payload); @@ -118,7 +118,7 @@ struct private_ike_auth_requested_t { * @param sa_payload SA payload of responder * * - SUCCESS - * - DELETE_ME + * - DESTROY_ME */ status_t (*process_sa_payload) (private_ike_auth_requested_t *this, sa_payload_t *sa_payload); @@ -130,7 +130,7 @@ struct private_ike_auth_requested_t { * @param other_id_payload ID payload of responder * * - SUCCESS - * - DELETE_ME + * - DESTROY_ME */ status_t (*process_auth_payload) (private_ike_auth_requested_t *this, auth_payload_t *auth_payload, id_payload_t *other_id_payload); @@ -142,7 +142,7 @@ struct private_ike_auth_requested_t { * @param ts_payload TS payload of responder * * - SUCCESS - * - DELETE_ME + * - DESTROY_ME */ status_t (*process_ts_payload) (private_ike_auth_requested_t *this, bool ts_initiator, ts_payload_t *ts_payload); @@ -154,7 +154,7 @@ struct private_ike_auth_requested_t { * * - SUCCESS * - FAILED - * - DELETE_ME + * - DESTROY_ME */ status_t (*process_notify_payload) (private_ike_auth_requested_t *this, notify_payload_t *notify_payload); @@ -281,7 +281,7 @@ static status_t process_message(private_ike_auth_requested_t *this, message_t *i if (!(idr_payload && sa_payload && auth_payload && tsi_payload && tsr_payload)) { this->logger->log(this->logger, AUDIT, "IKE_AUTH reply did not contain all required payloads. Deleting IKE_SA"); - return DELETE_ME; + return DESTROY_ME; } /* process all payloads */ @@ -341,13 +341,13 @@ static status_t process_message(private_ike_auth_requested_t *this, message_t *i if (status != SUCCESS) { this->logger->log(this->logger, AUDIT, "Could not install CHILD_SA! Deleting IKE_SA"); - return DELETE_ME; + return DESTROY_ME; } status = this->child_sa->add_policies(this->child_sa, this->my_ts, this->other_ts); if (status != SUCCESS) { this->logger->log(this->logger, AUDIT, "Could not install CHILD_SA policy! Deleting IKE_SA"); - return DELETE_ME; + return DESTROY_ME; } this->ike_sa->add_child_sa(this->ike_sa, this->child_sa); } @@ -386,7 +386,7 @@ static status_t process_idr_payload(private_ike_auth_requested_t *this, id_paylo { other_id->destroy(other_id); this->logger->log(this->logger, AUDIT, "IKE_AUTH reply contained a not acceptable ID. Deleting IKE_SA"); - return DELETE_ME; + return DESTROY_ME; } connection = this->ike_sa->get_connection(this->ike_sa); @@ -424,7 +424,7 @@ static status_t process_sa_payload(private_ike_auth_requested_t *this, sa_payloa proposal->destroy(proposal); } proposal_list->destroy(proposal_list); - return DELETE_ME; + return DESTROY_ME; } /* we have to re-check here if other's selection is valid */ @@ -439,7 +439,7 @@ static status_t process_sa_payload(private_ike_auth_requested_t *this, sa_payloa if (proposal == NULL) { this->logger->log(this->logger, AUDIT, "IKE_AUTH reply contained a not offered proposal. Deleting IKE_SA"); - return DELETE_ME; + return DESTROY_ME; } /* apply proposal */ @@ -462,7 +462,7 @@ static status_t process_auth_payload(private_ike_auth_requested_t *this, auth_pa if (status != SUCCESS) { this->logger->log(this->logger, AUDIT, "Verification of IKE_AUTH reply failed. Deleting IKE_SA"); - return DELETE_ME; + return DESTROY_ME; } this->logger->log(this->logger, CONTROL|LEVEL1, "AUTH data verified successfully"); @@ -521,19 +521,19 @@ static status_t process_notify_payload(private_ike_auth_requested_t *this, notif case INVALID_SYNTAX: { this->logger->log(this->logger, AUDIT, "IKE_AUTH reply contained an INVALID_SYNTAX notify. Deleting IKE_SA"); - return DELETE_ME; + return DESTROY_ME; } case AUTHENTICATION_FAILED: { this->logger->log(this->logger, AUDIT, "IKE_AUTH reply contained an AUTHENTICATION_FAILED notify. Deleting IKE_SA"); - return DELETE_ME; + return DESTROY_ME; } case SINGLE_PAIR_REQUIRED: { this->logger->log(this->logger, AUDIT, "IKE_AUTH reply contained a SINGLE_PAIR_REQUIRED notify. Deleting IKE_SA"); - return DELETE_ME; + return DESTROY_ME; } default: { @@ -546,7 +546,7 @@ static status_t process_notify_payload(private_ike_auth_requested_t *this, notif { this->logger->log(this->logger, AUDIT, "IKE_AUTH reply contained an unknown notify error (%d). Deleting IKE_SA", notify_message_type); - return DELETE_ME; + return DESTROY_ME; } else diff --git a/src/charon/sa/states/ike_sa_established.c b/src/charon/sa/states/ike_sa_established.c index e91409f6a..782b608dc 100644 --- a/src/charon/sa/states/ike_sa_established.c +++ b/src/charon/sa/states/ike_sa_established.c @@ -46,22 +46,59 @@ struct private_ike_sa_established_t { * Assigned logger. Use logger of IKE_SA. */ logger_t *logger; - - /** - * Process a notify payload - * - * @param this calling object - * @param notify_payload notify payload - * @param response response message of type INFORMATIONAL - * - * - SUCCESS - * - FAILED - * - DELETE_ME - */ - status_t (*process_notify_payload) (private_ike_sa_established_t *this, notify_payload_t *notify_payload,message_t *response); }; /** + * Process an informational request + */ +static status_t process_informational(private_ike_sa_established_t *this, message_t *request, message_t *response) +{ + delete_payload_t *delete_request = NULL; + iterator_t *payloads = request->get_payload_iterator(request); + + while (payloads->has_next(payloads)) + { + payload_t *payload; + payloads->current(payloads, (void**)&payload); + + switch (payload->get_type(payload)) + { + case DELETE: + { + delete_request = (delete_payload_t *) payload; + break; + } + default: + { + this->logger->log(this->logger, ERROR|LEVEL1, "Ignoring Payload %s (%d)", + mapping_find(payload_type_m, payload->get_type(payload)), + payload->get_type(payload)); + break; + } + } + } + /* iterator can be destroyed */ + payloads->destroy(payloads); + + if (delete_request) + { + if (delete_request->get_protocol_id(delete_request) == PROTO_IKE) + { + this->logger->log(this->logger, CONTROL, "DELETE request for IKE_SA received"); + /* we reply with an empty informational message */ + return DESTROY_ME; + } + else + { + this->logger->log(this->logger, CONTROL, "DELETE request for CHILD_SA received. Ignored"); + response->destroy(response); + return SUCCESS; + } + } + return SUCCESS; +} + +/** * Implements state_t.get_state */ static status_t process_message(private_ike_sa_established_t *this, message_t *message) @@ -74,22 +111,16 @@ static status_t process_message(private_ike_sa_established_t *this, message_t *m signer_t *signer; status_t status; - if (message->get_exchange_type(message) != INFORMATIONAL) - { - this->logger->log(this->logger, ERROR | LEVEL1, "Message of type %s not supported in state ike_sa_established", - mapping_find(exchange_type_m,message->get_exchange_type(message))); - return FAILED; - } - + /* only requests are allowed, responses are handled in sub-states */ if (!message->get_request(message)) { - this->logger->log(this->logger, ERROR | LEVEL1, "INFORMATIONAL responses not handled in state ike_sa_established"); + this->logger->log(this->logger, ERROR | LEVEL1, + "INFORMATIONAL responses not handled in state ike_sa_established"); return FAILED; } - ike_sa_id = this->ike_sa->public.get_id(&(this->ike_sa->public)); - /* get signer for verification and crypter for decryption */ + ike_sa_id = this->ike_sa->public.get_id(&(this->ike_sa->public)); if (!ike_sa_id->is_initiator(ike_sa_id)) { crypter = this->ike_sa->get_crypter_initiator(this->ike_sa); @@ -105,99 +136,50 @@ static status_t process_message(private_ike_sa_established_t *this, message_t *m status = message->parse_body(message, crypter, signer); if (status != SUCCESS) { - this->logger->log(this->logger, AUDIT, "INFORMATIONAL request decryption failed. Ignoring message"); + this->logger->log(this->logger, AUDIT, "%s request decryption failed. Ignoring message", + mapping_find(exchange_type_m, message->get_exchange_type(message))); return status; } - /* build empty INFORMATIONAL message */ - this->ike_sa->build_message(this->ike_sa, INFORMATIONAL, FALSE, &response); - - payloads = message->get_payload_iterator(message); + /* prepare a reply of the same type */ + this->ike_sa->build_message(this->ike_sa, message->get_exchange_type(message), FALSE, &response); - while (payloads->has_next(payloads)) + /* handle the different message types in their functions */ + switch (message->get_exchange_type(message)) { - payload_t *payload; - payloads->current(payloads, (void**)&payload); - - switch (payload->get_type(payload)) - { - case NOTIFY: - { - notify_payload_t *notify_payload = (notify_payload_t *) payload; - /* handle the notify directly, abort if no further processing required */ - status = this->process_notify_payload(this, notify_payload,response); - if (status != SUCCESS) - { - payloads->destroy(payloads); - response->destroy(response); - return status; - } - } - case DELETE: - { - delete_request = (delete_payload_t *) payload; - break; - } - default: - { - this->logger->log(this->logger, ERROR|LEVEL1, "Ignoring Payload %s (%d)", - mapping_find(payload_type_m, payload->get_type(payload)), payload->get_type(payload)); - break; - } - } + case INFORMATIONAL: + status = process_informational(this, message, response); + break; + default: + this->logger->log(this->logger, ERROR | LEVEL1, + "Message of type %s currently not supported in state ike_sa_established", + mapping_find(exchange_type_m, message->get_exchange_type(message))); + status = NOT_SUPPORTED; } - /* iterator can be destroyed */ - payloads->destroy(payloads); - if (delete_request) - { - if (delete_request->get_protocol_id(delete_request) == PROTO_IKE) + /* if we get a DESTROY_ME, we respond to follow strict request/reply scheme */ + if (status == SUCCESS || status == DESTROY_ME) + { + if (this->ike_sa->send_response(this->ike_sa, response) != SUCCESS) { - this->logger->log(this->logger, AUDIT, "DELETE request for IKE_SA received"); + /* something is seriously wrong, kill connection */ + this->logger->log(this->logger, AUDIT, "Unable to send reply. Deleting IKE_SA"); response->destroy(response); - return DELETE_ME; + status = DESTROY_ME; } - else + else if (status == DESTROY_ME) { - this->logger->log(this->logger, AUDIT, "DELETE request for CHILD_SA received. Ignored"); - response->destroy(response); - return SUCCESS; + /* switch to delete_requested. This is not absolutly correct, but we + * allow the clean destruction of an SA only in this state. */ + this->ike_sa->set_new_state(this->ike_sa, (state_t*)delete_requested_create(this)); + this->public.state_interface.destroy(&(this->public.state_interface)); } } - - status = this->ike_sa->send_response(this->ike_sa, response); - /* message can now be sent (must not be destroyed) */ - if (status != SUCCESS) + else { - this->logger->log(this->logger, AUDIT, "Unable to send INFORMATIONAL reply"); response->destroy(response); - return FAILED; } - - return SUCCESS; -} - -/** - * Implementation of private_ike_sa_established_t.process_notify_payload; - */ -static status_t process_notify_payload (private_ike_sa_established_t *this, notify_payload_t *notify_payload, message_t *response) -{ - notify_message_type_t notify_message_type = notify_payload->get_notify_message_type(notify_payload); - - this->logger->log(this->logger, CONTROL|LEVEL1, "Process notify type %s for protocol %s", - mapping_find(notify_message_type_m, notify_message_type), - mapping_find(protocol_id_m, notify_payload->get_protocol_id(notify_payload))); - - switch (notify_message_type) - { - default: - { - this->logger->log(this->logger, AUDIT, "INFORMATIONAL request contained an unknown notify (%d), ignored.", notify_message_type); - } - } - - - return SUCCESS; + return status; } /** @@ -228,9 +210,6 @@ ike_sa_established_t *ike_sa_established_create(protected_ike_sa_t *ike_sa) this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state; this->public.state_interface.destroy = (void (*) (state_t *)) destroy; - /* private functions */ - this->process_notify_payload = process_notify_payload; - /* private data */ this->ike_sa = ike_sa; this->logger = logger_manager->get_logger(logger_manager, IKE_SA); diff --git a/src/charon/sa/states/ike_sa_init_requested.c b/src/charon/sa/states/ike_sa_init_requested.c index 04fef3d94..6befa96e6 100644 --- a/src/charon/sa/states/ike_sa_init_requested.c +++ b/src/charon/sa/states/ike_sa_init_requested.c @@ -325,7 +325,7 @@ static status_t process_message(private_ike_sa_init_requested_t *this, message_t if (!(nonce_payload && sa_payload && ke_payload)) { this->logger->log(this->logger, AUDIT, "IKE_SA_INIT reply did not contain all required payloads. Deleting IKE_SA"); - return DELETE_ME; + return DESTROY_ME; } status = this->process_nonce_payload (this,nonce_payload); @@ -351,7 +351,7 @@ static status_t process_message(private_ike_sa_init_requested_t *this, message_t if (status != SUCCESS) { this->logger->log(this->logger, AUDIT, "Transform objects could not be created from selected proposal. Deleting IKE_SA"); - return DELETE_ME; + return DESTROY_ME; } /* apply the address on wich we really received the packet */ @@ -407,7 +407,7 @@ static status_t process_message(private_ike_sa_init_requested_t *this, message_t { this->logger->log(this->logger, AUDIT, "Unable to send IKE_AUTH request. Deleting IKE_SA"); request->destroy(request); - return DELETE_ME; + return DESTROY_ME; } this->ike_sa->set_last_replied_message_id(this->ike_sa,ike_sa_init_reply->get_message_id(ike_sa_init_reply)); @@ -456,7 +456,7 @@ status_t process_sa_payload (private_ike_sa_init_requested_t *this, sa_payload_t proposal->destroy(proposal); } proposal_list->destroy(proposal_list); - return DELETE_ME; + return DESTROY_ME; } /* we have to re-check if the others selection is valid */ @@ -470,7 +470,7 @@ status_t process_sa_payload (private_ike_sa_init_requested_t *this, sa_payload_t if (this->proposal == NULL) { this->logger->log(this->logger, AUDIT, "IKE_SA_INIT response contained selected proposal we did not offer. Deleting IKE_SA"); - return DELETE_ME; + return DESTROY_ME; } return SUCCESS; @@ -544,7 +544,7 @@ static status_t build_auth_payload (private_ike_sa_init_requested_t *this, id_pa if (status != SUCCESS) { this->logger->log(this->logger, AUDIT, "Could not generate AUTH data for IKE_AUTH request. Deleting IKE_SA"); - return DELETE_ME; + return DESTROY_ME; } this->logger->log(this->logger, CONTROL|LEVEL2, "Add AUTH payload to message"); @@ -573,7 +573,7 @@ static status_t build_sa_payload (private_ike_sa_init_requested_t *this, message if (this->child_sa->alloc(this->child_sa, proposal_list) != SUCCESS) { this->logger->log(this->logger, AUDIT, "Could not install CHILD_SA! Deleting IKE_SA"); - return DELETE_ME; + return DESTROY_ME; } sa_payload = sa_payload_create_from_proposal_list(proposal_list); @@ -637,12 +637,12 @@ static status_t process_notify_payload(private_ike_sa_init_requested_t *this, no case NO_PROPOSAL_CHOSEN: { this->logger->log(this->logger, AUDIT, "IKE_SA_INIT response contained a NO_PROPOSAL_CHOSEN notify. Deleting IKE_SA"); - return DELETE_ME; + return DESTROY_ME; } case INVALID_MAJOR_VERSION: { this->logger->log(this->logger, AUDIT, "IKE_SA_INIT response contained a INVALID_MAJOR_VERSION notify. Deleting IKE_SA"); - return DELETE_ME; + return DESTROY_ME; } case INVALID_KE_PAYLOAD: { @@ -671,7 +671,7 @@ static status_t process_notify_payload(private_ike_sa_init_requested_t *this, no this->logger->log(this->logger, AUDIT, "Peer does only accept DH group %s, which we do not accept! Aborting", mapping_find(diffie_hellman_group_m, dh_group)); - return DELETE_ME; + return DESTROY_ME; } /* Going to change state back to initiator_init_t */ @@ -691,7 +691,7 @@ static status_t process_notify_payload(private_ike_sa_init_requested_t *this, no this->public.state_interface.destroy(&(this->public.state_interface)); if (initiator_init_state->retry_initiate_connection (initiator_init_state, dh_group) != SUCCESS) { - return DELETE_ME; + return DESTROY_ME; } return FAILED; } @@ -705,7 +705,7 @@ static status_t process_notify_payload(private_ike_sa_init_requested_t *this, no { this->logger->log(this->logger, AUDIT, "IKE_SA_INIT reply contained an unknown notify error (%d). Deleting IKE_SA", notify_message_type); - return DELETE_ME; + return DESTROY_ME; } else { diff --git a/src/charon/sa/states/ike_sa_init_responded.c b/src/charon/sa/states/ike_sa_init_responded.c index 84187f027..3a379247c 100644 --- a/src/charon/sa/states/ike_sa_init_responded.c +++ b/src/charon/sa/states/ike_sa_init_responded.c @@ -152,7 +152,7 @@ struct private_ike_sa_init_responded_t { * @param this calling object * @param notify_payload payload to process * @return - * - DELETE_ME if IKE_SA should be deleted + * - DESTROY_ME if IKE_SA should be deleted * - SUCCSS if processed successfull */ status_t (*process_notify_payload) (private_ike_sa_init_responded_t *this, notify_payload_t* notify_payload); @@ -210,7 +210,7 @@ static status_t process_message(private_ike_sa_init_responded_t *this, message_t this->logger->log(this->logger, ERROR | LEVEL1, "IKE_AUTH request contains unsupported payload with critical flag set. " "Deleting IKE_SA"); this->ike_sa->send_notify(this->ike_sa, IKE_AUTH, UNSUPPORTED_CRITICAL_PAYLOAD, CHUNK_INITIALIZER); - return DELETE_ME; + return DESTROY_ME; } else { @@ -291,7 +291,7 @@ static status_t process_message(private_ike_sa_init_responded_t *this, message_t if (!(idi_request && sa_request && auth_request && tsi_request && tsr_request)) { this->logger->log(this->logger, AUDIT, "IKE_AUTH reply did not contain all required payloads. Deleting IKE_SA"); - return DELETE_ME; + return DESTROY_ME; } /* build response */ @@ -335,7 +335,7 @@ static status_t process_message(private_ike_sa_init_responded_t *this, message_t { this->logger->log(this->logger, AUDIT, "Unable to send IKE_AUTH reply. Deleting IKE_SA"); response->destroy(response); - return DELETE_ME; + return DESTROY_ME; } /* install child SA policies */ @@ -355,12 +355,12 @@ static status_t process_message(private_ike_sa_init_responded_t *this, message_t if (status != SUCCESS) { this->logger->log(this->logger, AUDIT, "Could not install CHILD_SA policy! Deleting IKE_SA"); - return DELETE_ME; + return DESTROY_ME; } this->ike_sa->add_child_sa(this->ike_sa, this->child_sa); } - /* create new state */ + /* create new state */ this->ike_sa->set_new_state(this->ike_sa, (state_t*)ike_sa_established_create(this->ike_sa)); this->destroy_after_state_change(this); @@ -403,7 +403,7 @@ static status_t build_idr_payload(private_ike_sa_init_responded_t *this, id_payl { this->logger->log(this->logger, AUDIT, "We don't have a policy for IDs %s - %s. Deleting IKE_SA", my_id->get_string(my_id), other_id->get_string(other_id)); - return DELETE_ME; + return DESTROY_ME; } /* get my id from policy, which must contain a fully qualified valid id */ @@ -462,7 +462,7 @@ static status_t build_sa_payload(private_ike_sa_init_responded_t *this, sa_paylo { this->logger->log(this->logger, AUDIT, "IKE_AUTH request did not contain any proposals we accept. Deleting IKE_SA"); this->ike_sa->send_notify(this->ike_sa, IKE_AUTH, NO_PROPOSAL_CHOSEN, CHUNK_INITIALIZER); - return DELETE_ME; + return DESTROY_ME; } /* set up child sa */ @@ -481,7 +481,7 @@ static status_t build_sa_payload(private_ike_sa_init_responded_t *this, sa_paylo if (status != SUCCESS) { this->logger->log(this->logger, AUDIT, "Could not install CHILD_SA! Deleting IKE_SA"); - return DELETE_ME; + return DESTROY_ME; } /* create payload with selected propsal */ @@ -508,7 +508,7 @@ static status_t build_auth_payload(private_ike_sa_init_responded_t *this, auth_p this->logger->log(this->logger, AUDIT, "IKE_AUTH request verification failed. Deleting IKE_SA"); this->ike_sa->send_notify(this->ike_sa, IKE_AUTH, AUTHENTICATION_FAILED, CHUNK_INITIALIZER); authenticator->destroy(authenticator); - return DELETE_ME; + return DESTROY_ME; } status = authenticator->compute_auth_data(authenticator,&auth_reply, this->ike_sa_init_response_data,this->received_nonce,my_id_payload,FALSE); @@ -516,8 +516,7 @@ static status_t build_auth_payload(private_ike_sa_init_responded_t *this, auth_p if (status != SUCCESS) { this->logger->log(this->logger, AUDIT, "Unable to build authentication data for IKE_AUTH reply. Deleting IKE_SA"); - return DELETE_ME; - + return DESTROY_ME; } response->add_payload(response, (payload_t *)auth_reply); diff --git a/src/charon/sa/states/initiator_init.c b/src/charon/sa/states/initiator_init.c index 35d15235d..9636d8f66 100644 --- a/src/charon/sa/states/initiator_init.c +++ b/src/charon/sa/states/initiator_init.c @@ -131,7 +131,7 @@ static status_t initiate_connection (private_initiator_init_t *this, connection_ { this->logger->log(this->logger, ERROR | LEVEL1, "Could not get a policy for '%s - %s', aborting", my_id->get_string(my_id), other_id->get_string(other_id)); - return DELETE_ME; + return DESTROY_ME; } this->ike_sa->set_policy(this->ike_sa,policy); @@ -157,7 +157,7 @@ status_t retry_initiate_connection (private_initiator_init_t *this, diffie_hellm if (dh_group == MODP_UNDEFINED) { this->logger->log(this->logger, AUDIT, "No DH group acceptable for initialization, Aborting"); - return DELETE_ME; + return DESTROY_ME; } connection = this->ike_sa->get_connection(this->ike_sa); @@ -181,7 +181,7 @@ status_t retry_initiate_connection (private_initiator_init_t *this, diffie_hellm { this->logger->log(this->logger, ERROR, "Building nonce payload failed. Aborting"); message->destroy(message); - return DELETE_ME; + return DESTROY_ME; } /* message can now be sent (must not be destroyed) */ @@ -190,7 +190,7 @@ status_t retry_initiate_connection (private_initiator_init_t *this, diffie_hellm { this->logger->log(this->logger, AUDIT, "Unable to initiate connection, could not send message. Aborting"); message->destroy(message); - return DELETE_ME; + return DESTROY_ME; } message = this->ike_sa->get_last_requested_message(this->ike_sa); diff --git a/src/charon/sa/states/initiator_init.h b/src/charon/sa/states/initiator_init.h index 6b4940a73..903c58038 100644 --- a/src/charon/sa/states/initiator_init.h +++ b/src/charon/sa/states/initiator_init.h @@ -52,7 +52,7 @@ struct initiator_init_t { * @param connection connection to initiate * @return * - SUCCESS - * - DELETE_ME if something failed + * - DESTROY_ME if something failed */ status_t (*initiate_connection) (initiator_init_t *this, connection_t *connection); @@ -65,7 +65,7 @@ struct initiator_init_t { * @param dh_group_priority dh group priority to try with * @return * - SUCCESS - * - DELETE_ME if something failed (see log for error) + * - DESTROY_ME if something failed (see log for error) */ status_t (*retry_initiate_connection) (initiator_init_t *this, int dh_group_priority); }; diff --git a/src/charon/sa/states/responder_init.c b/src/charon/sa/states/responder_init.c index 10acf645c..8ee77269d 100644 --- a/src/charon/sa/states/responder_init.c +++ b/src/charon/sa/states/responder_init.c @@ -97,7 +97,7 @@ struct private_responder_init_t { * @param sa_request The received SA payload * @param response the SA payload is added to this response message_t object. * @return - * - DELETE_ME + * - DESTROY_ME * - SUCCESS */ status_t (*build_sa_payload) (private_responder_init_t *this,sa_payload_t *sa_request, message_t *response); @@ -108,7 +108,7 @@ struct private_responder_init_t { * @param this calling object * @param ke_request The received KE payload * @param response the KE payload is added to this response message_t object. - * - DELETE_ME + * - DESTROY_ME * - SUCCESS */ status_t (*build_ke_payload) (private_responder_init_t *this,ke_payload_t *ke_request, message_t *response); @@ -119,7 +119,7 @@ struct private_responder_init_t { * @param this calling object * @param nonce_request The received NONCE payload * @param response the NONCE payload is added to this response message_t object. - * - DELETE_ME + * - DESTROY_ME * - SUCCESS */ status_t (*build_nonce_payload) (private_responder_init_t *this,nonce_payload_t *nonce_request, message_t *response); @@ -164,12 +164,12 @@ static status_t process_message(private_responder_init_t *this, message_t *messa if (message->get_exchange_type(message) != IKE_SA_INIT) { this->logger->log(this->logger, ERROR | LEVEL1, "Message of type %s not supported in state responder_init",mapping_find(exchange_type_m,message->get_exchange_type(message))); - return DELETE_ME; + return DESTROY_ME; } if (!message->get_request(message)) { this->logger->log(this->logger, ERROR | LEVEL1, "IKE_SA_INIT responses not allowed state ike_sa_init_responded"); - return DELETE_ME; + return DESTROY_ME; } /* this is the first message to process, so get host infos */ @@ -182,7 +182,7 @@ static status_t process_message(private_responder_init_t *this, message_t *messa /* no configuration matches given hosts */ this->logger->log(this->logger, AUDIT, "IKE_SA_INIT request does not match any available connection. Deleting IKE_SA"); /* TODO: inform requestor */ - return DELETE_ME; + return DESTROY_ME; } this->ike_sa->set_connection(this->ike_sa,connection); @@ -200,7 +200,7 @@ static status_t process_message(private_responder_init_t *this, message_t *messa { this->logger->log(this->logger, AUDIT, "Unable to parse IKE_SA_INIT request. Deleting IKE_SA"); } - return DELETE_ME; + return DESTROY_ME; } payloads = message->get_payload_iterator(message); @@ -251,7 +251,7 @@ static status_t process_message(private_responder_init_t *this, message_t *messa if (!(sa_request && ke_request && nonce_request)) { this->logger->log(this->logger, AUDIT, "IKE_SA_INIT request did not contain all required payloads. Deleting IKE_SA"); - return DELETE_ME; + return DESTROY_ME; } this->ike_sa->build_message(this->ike_sa, IKE_SA_INIT, FALSE, &response); @@ -282,7 +282,7 @@ static status_t process_message(private_responder_init_t *this, message_t *messa if (status != SUCCESS) { this->logger->log(this->logger, AUDIT, "Transform objects could not be created from selected proposal. Deleting IKE_SA"); - return DELETE_ME; + return DESTROY_ME; } /* message can now be sent (must not be destroyed) */ @@ -291,7 +291,7 @@ static status_t process_message(private_responder_init_t *this, message_t *messa { this->logger->log(this->logger, AUDIT, "Unable to send IKE_SA_INIT response. Deleting IKE_SA"); response->destroy(response); - return DELETE_ME; + return DESTROY_ME; } /* state can now be changed */ @@ -340,7 +340,7 @@ static status_t build_sa_payload(private_responder_init_t *this,sa_payload_t *sa { this->logger->log(this->logger, AUDIT, "IKE_SA_INIT request did not contain any acceptable proposals. Deleting IKE_SA"); this->ike_sa->send_notify(this->ike_sa, IKE_SA_INIT, NO_PROPOSAL_CHOSEN, CHUNK_INITIALIZER); - return DELETE_ME; + return DESTROY_ME; } /* get selected DH group to force policy, this is very restrictive!? */ this->proposal->get_algorithm(this->proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, &algo); @@ -372,7 +372,7 @@ static status_t build_ke_payload(private_responder_init_t *this,ke_payload_t *ke if (group == MODP_UNDEFINED) { this->logger->log(this->logger, AUDIT, "No diffie hellman group to select. Deleting IKE_SA"); - return DELETE_ME; + return DESTROY_ME; } if (this->dh_group_number != group) @@ -387,7 +387,7 @@ static status_t build_ke_payload(private_responder_init_t *this,ke_payload_t *ke accepted_group_chunk.ptr = (u_int8_t*) &(accepted_group); accepted_group_chunk.len = 2; this->ike_sa->send_notify(this->ike_sa,IKE_SA_INIT,INVALID_KE_PAYLOAD,accepted_group_chunk); - return DELETE_ME; + return DESTROY_ME; } /* create diffie hellman object to handle DH exchange */ @@ -396,7 +396,7 @@ static status_t build_ke_payload(private_responder_init_t *this,ke_payload_t *ke { this->logger->log(this->logger, AUDIT, "Could not generate DH object with group %d. Deleting IKE_SA", mapping_find(diffie_hellman_group_m,group) ); - return DELETE_ME; + return DESTROY_ME; } this->logger->log(this->logger, CONTROL | LEVEL2, "Set other DH public value"); diff --git a/src/charon/sa/states/state.c b/src/charon/sa/states/state.c index 595f5abbb..eda29870b 100644 --- a/src/charon/sa/states/state.c +++ b/src/charon/sa/states/state.c @@ -33,5 +33,6 @@ mapping_t ike_sa_state_m[] = { {IKE_SA_INIT_RESPONDED, "IKE_SA_INIT_RESPONDED"}, {IKE_AUTH_REQUESTED, "IKE_AUTH_REQUESTED"}, {IKE_SA_ESTABLISHED, "IKE_SA_ESTABLISHED"}, + {DELETE_REQUESTED, "DELETE_REQUESTED"}, {MAPPING_END, NULL} }; diff --git a/src/charon/sa/states/state.h b/src/charon/sa/states/state.h index c93068d35..0f39aec01 100644 --- a/src/charon/sa/states/state.h +++ b/src/charon/sa/states/state.h @@ -90,9 +90,20 @@ enum ike_sa_state_t { * * In this state, all the informations for an IKE_SA and one CHILD_SA are known. * - * Implemented in class ike_sa_established_t. + * Implemented in class ike_sa_established_t. */ - IKE_SA_ESTABLISHED = 6 + IKE_SA_ESTABLISHED = 6, + + /** + * @brief An IKE SA has sent a DELETE IKE_SA to the other peer. + * + * After a call to ike_sa.close(), the IKE_SA sends a delete message + * to the remote peer and switches to this state. It waits until the + * message is aknowledged, or a certain timout occurs. + * + * Implemented in class delete_requested. + */ + DELETE_REQUESTED = 7 }; @@ -122,6 +133,7 @@ typedef struct state_t state_t; * - IKE_SA_INIT_RESPONDED: implemented in ike_sa_init_responded_t * - IKE_AUTH_REQUESTED: implemented in ike_auth_requested_t * - IKE_SA_ESTABLISHED: implemented in ike_sa_established_t + * - DELETE_REQUESTED: implemented in delete_requested_t * * @b Constructors: * - initiator_init_create() @@ -130,6 +142,7 @@ typedef struct state_t state_t; * - ike_sa_init_responded_create() * - ike_auth_requested_create() * - ike_sa_established_create() + * - delete_requested_create() * * @ingroup states */ @@ -143,7 +156,7 @@ struct state_t { * @return * - SUCCESSFUL * - FAILED - * - DELETE_ME if belonging IKE_SA should be deleted + * - DESTROY_ME if belonging IKE_SA should be deleted */ status_t (*process_message) (state_t *this,message_t *message); diff --git a/src/charon/threads/thread_pool.c b/src/charon/threads/thread_pool.c index 57b2539cb..51d29c222 100644 --- a/src/charon/threads/thread_pool.c +++ b/src/charon/threads/thread_pool.c @@ -146,8 +146,8 @@ static void process_jobs(private_thread_pool_t *this) this->worker_logger->log(this->worker_logger, CONTROL, "worker thread running, thread_ID: %06d", (int)pthread_self()); - for (;;) { - + for (;;) + { job = charon->job_queue->get(charon->job_queue); job_type = job->get_type(job); this->worker_logger->log(this->worker_logger, CONTROL|LEVEL2, "Process job of type %s", @@ -207,47 +207,43 @@ static void process_jobs(private_thread_pool_t *this) */ static void process_incoming_packet_job(private_thread_pool_t *this, incoming_packet_job_t *job) { - packet_t *packet; - message_t *message; - ike_sa_t *ike_sa; + packet_t *packet; + message_t *message; + ike_sa_t *ike_sa; ike_sa_id_t *ike_sa_id; - status_t status; - + status_t status; packet = job->get_packet(job); - + message = message_create_from_packet(packet); - status = message->parse_header(message); if (status != SUCCESS) { this->worker_logger->log(this->worker_logger, ERROR, "Message header could not be verified!"); message->destroy(message); - return; + return; } - + this->worker_logger->log(this->worker_logger, CONTROL|LEVEL2, "Message is a %s %s", mapping_find(exchange_type_m, message->get_exchange_type(message)), message->get_request(message) ? "request" : "reply"); - - if ((message->get_major_version(message) != IKE_MAJOR_VERSION) || - (message->get_minor_version(message) != IKE_MINOR_VERSION)) + + if ((message->get_major_version(message) != IKE_MAJOR_VERSION) || + (message->get_minor_version(message) != IKE_MINOR_VERSION)) { - this->worker_logger->log(this->worker_logger, ERROR | LEVEL2, "IKE version %d.%d not supported", - message->get_major_version(message), - message->get_minor_version(message)); - /* - * This check is not handled in state_t object of IKE_SA to increase speed. - */ + this->worker_logger->log(this->worker_logger, ERROR | LEVEL2, + "IKE version %d.%d not supported", + message->get_major_version(message), + message->get_minor_version(message)); if ((message->get_exchange_type(message) == IKE_SA_INIT) && (message->get_request(message))) - { + { message_t *response; message->get_ike_sa_id(message, &ike_sa_id); ike_sa_id->switch_initiator(ike_sa_id); response = message_create_notify_reply(message->get_destination(message), - message->get_source(message), - IKE_SA_INIT, - FALSE,ike_sa_id,INVALID_MAJOR_VERSION); + message->get_source(message), + IKE_SA_INIT, FALSE, ike_sa_id, + INVALID_MAJOR_VERSION); message->destroy(message); ike_sa_id->destroy(ike_sa_id); status = response->generate(response, NULL, NULL, &packet); @@ -265,27 +261,24 @@ static void process_incoming_packet_job(private_thread_pool_t *this, incoming_pa message->destroy(message); return; } - + message->get_ike_sa_id(message, &ike_sa_id); - + ike_sa_id->switch_initiator(ike_sa_id); - + this->worker_logger->log(this->worker_logger, CONTROL|LEVEL3, "Checking out IKE SA %lld:%lld, role %s", ike_sa_id->get_initiator_spi(ike_sa_id), ike_sa_id->get_responder_spi(ike_sa_id), ike_sa_id->is_initiator(ike_sa_id) ? "initiator" : "responder"); - + status = charon->ike_sa_manager->checkout(charon->ike_sa_manager,ike_sa_id, &ike_sa); if ((status != SUCCESS) && (status != CREATED)) { this->worker_logger->log(this->worker_logger, ERROR, "IKE SA could not be checked out"); ike_sa_id->destroy(ike_sa_id); message->destroy(message); - - /* - * TODO send notify reply of type INVALID_IKE_SPI if SPI could not be found ? - */ - + + /* TODO: send notify reply of type INVALID_IKE_SPI if SPI could not be found ? */ return; } @@ -296,25 +289,25 @@ static void process_incoming_packet_job(private_thread_pool_t *this, incoming_pa this->create_delete_half_open_ike_sa_job(this,ike_sa_id, charon->configuration->get_half_open_ike_sa_timeout(charon->configuration)); } - + status = ike_sa->process_message(ike_sa, message); - + this->worker_logger->log(this->worker_logger, CONTROL|LEVEL3, "%s IKE SA %lld:%lld, role %s", - (status == DELETE_ME) ? "Checkin and delete" : "Checkin", + (status == DESTROY_ME) ? "Checkin and delete" : "Checkin", ike_sa_id->get_initiator_spi(ike_sa_id), ike_sa_id->get_responder_spi(ike_sa_id), ike_sa_id->is_initiator(ike_sa_id) ? "initiator" : "responder"); ike_sa_id->destroy(ike_sa_id); - - if (status == DELETE_ME) + + if (status == DESTROY_ME) { - status = charon->ike_sa_manager->checkin_and_delete(charon->ike_sa_manager, ike_sa); + status = charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa); } else { status = charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); } - + if (status != SUCCESS) { this->worker_logger->log(this->worker_logger, ERROR, "Checkin of IKE SA failed!"); @@ -345,7 +338,7 @@ static void process_initiate_ike_sa_job(private_thread_pool_t *this, initiate_ik { this->worker_logger->log(this->worker_logger, ERROR, "Initiation returned %s, going to delete IKE_SA.", mapping_find(status_m, status)); - charon->ike_sa_manager->checkin_and_delete(charon->ike_sa_manager, ike_sa); + charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa); return; } @@ -373,11 +366,10 @@ static void process_delete_half_open_ike_sa_job(private_thread_pool_t *this, del status = charon->ike_sa_manager->checkout(charon->ike_sa_manager,ike_sa_id, &ike_sa); if ((status != SUCCESS) && (status != CREATED)) { - this->worker_logger->log(this->worker_logger, CONTROL | LEVEL3, "IKE SA seems to be already deleted and so doesn't have to be deleted"); + this->worker_logger->log(this->worker_logger, CONTROL | LEVEL3, "IKE SA seems to be already deleted"); return; } - switch (ike_sa->get_state(ike_sa)) { case INITIATOR_INIT: @@ -385,9 +377,10 @@ static void process_delete_half_open_ike_sa_job(private_thread_pool_t *this, del case IKE_SA_INIT_REQUESTED: case IKE_SA_INIT_RESPONDED: case IKE_AUTH_REQUESTED: + case DELETE_REQUESTED: { /* IKE_SA is half open and gets deleted! */ - status = charon->ike_sa_manager->checkin_and_delete(charon->ike_sa_manager, ike_sa); + status = charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa); if (status != SUCCESS) { this->worker_logger->log(this->worker_logger, ERROR, "Could not checkin and delete checked out IKE_SA!"); @@ -415,39 +408,14 @@ static void process_delete_established_ike_sa_job(private_thread_pool_t *this, d ike_sa_id_t *ike_sa_id = job->get_ike_sa_id(job); ike_sa_t *ike_sa; status_t status; - status = charon->ike_sa_manager->checkout(charon->ike_sa_manager,ike_sa_id, &ike_sa); - if ((status != SUCCESS) && (status != CREATED)) - { - this->worker_logger->log(this->worker_logger, CONTROL | LEVEL3, "IKE SA seems to be already deleted and so doesn't have to be deleted"); - return; - } - - switch (ike_sa->get_state(ike_sa)) - { - case INITIATOR_INIT: - case RESPONDER_INIT: - case IKE_SA_INIT_REQUESTED: - case IKE_SA_INIT_RESPONDED: - case IKE_AUTH_REQUESTED: - { - break; - } - default: - { - this->worker_logger->log(this->worker_logger, CONTROL, "Send delete request for IKE_SA."); - ike_sa->send_delete_ike_sa_request(ike_sa); - break; - } - } - this->worker_logger->log(this->worker_logger, CONTROL, "Delete established IKE_SA."); - status = charon->ike_sa_manager->checkin_and_delete(charon->ike_sa_manager, ike_sa); + status = charon->ike_sa_manager->delete(charon->ike_sa_manager, ike_sa_id); if (status != SUCCESS) { - this->worker_logger->log(this->worker_logger, ERROR, "Could not checkin and delete checked out IKE_SA!"); + this->worker_logger->log(this->worker_logger, CONTROL, "IKE SA didn't exist anymore"); + return; } } - /** * Implementation of private_thread_pool_t.process_retransmit_request_job. */ @@ -470,7 +438,7 @@ static void process_retransmit_request_job(private_thread_pool_t *this, retransm if ((status != SUCCESS) && (status != CREATED)) { job->destroy(job); - this->worker_logger->log(this->worker_logger, ERROR, "IKE SA could not be checked out. Already deleted?"); + this->worker_logger->log(this->worker_logger, ERROR|LEVEL1, "IKE SA could not be checked out. Already deleted?"); return; } @@ -478,7 +446,7 @@ static void process_retransmit_request_job(private_thread_pool_t *this, retransm if (status != SUCCESS) { - this->worker_logger->log(this->worker_logger, CONTROL | LEVEL3, "Message doesn't have to be retransmitted"); + this->worker_logger->log(this->worker_logger, CONTROL|LEVEL3, "Message doesn't have to be retransmitted"); stop_retransmitting = TRUE; } |