-SUBDIRS = . testing
ipsec_PROGRAMS = charon
charon_SOURCES = \
config/credentials/local_credential_store.c config/credentials/local_credential_store.h \
config/credentials/credential_store.h config/traffic_selector.c config/traffic_selector.h \
config/proposal.c config/proposal.h config/configuration.c config/configuration.h \
-sa/states/state.c sa/states/state.h sa/states/ike_sa_init_requested.c sa/states/ike_sa_init_requested.h \
-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_ike_sa_requested.h sa/states/delete_ike_sa_requested.c \
-sa/states/delete_child_sa_requested.h sa/states/delete_child_sa_requested.c \
-sa/states/create_child_sa_requested.c sa/states/create_child_sa_requested.h \
+sa/transactions/transaction.h sa/transactions/transaction.c \
+sa/transactions/ike_sa_init.h sa/transactions/ike_sa_init.c \
+sa/transactions/ike_auth.h sa/transactions/ike_auth.c \
+sa/transactions/dead_peer_detection.h sa/transactions/dead_peer_detection.c \
+sa/transactions/delete_ike_sa.h sa/transactions/delete_ike_sa.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 \
/**
* Timeout in milliseconds after that a half open IKE_SA gets deleted.
+ * Set to zero to disable
*/
#define HALF_OPEN_IKE_SA_TIMEOUT 30000
#define MAX_RETRANSMIT_COUNT 6
/**
- * Keepalive interval in milliseconds.
+ * Keepalive interval in seconds.
*/
-#define KEEPALIVE_INTERVAL 2000000
+#define KEEPALIVE_INTERVAL 20
/**
- * DPD interval in milliseconds.
+ * DPD interval in seconds.
*/
-#define DPD_INTERVAL 6000000
+#define DPD_INTERVAL 60
typedef struct private_configuration_t private_configuration_t;
/**
* Implementation of configuration_t.get_retransmit_timeout.
*/
-static status_t get_retransmit_timeout (private_configuration_t *this, u_int32_t retransmit_count, u_int32_t *timeout)
+static u_int32_t get_retransmit_timeout (private_configuration_t *this, u_int32_t retransmit_count)
{
if (retransmit_count > MAX_RETRANSMIT_COUNT && MAX_RETRANSMIT_COUNT != 0)
{
- return FAILED;
+ return 0;
}
-
- *timeout = (u_int32_t)(RETRANSMIT_TIMEOUT * pow(RETRANSMIT_BASE, retransmit_count));
-
- return SUCCESS;
+ return (u_int32_t)(RETRANSMIT_TIMEOUT * pow(RETRANSMIT_BASE, retransmit_count));
}
/**
/* public functions */
this->public.destroy = (void(*)(configuration_t*))destroy;
- this->public.get_retransmit_timeout = (status_t (*) (configuration_t *, u_int32_t retransmit_count, u_int32_t *timeout))get_retransmit_timeout;
+ this->public.get_retransmit_timeout = (u_int32_t (*) (configuration_t *, u_int32_t retransmit_count))get_retransmit_timeout;
this->public.get_half_open_ike_sa_timeout = (u_int32_t (*) (configuration_t *)) get_half_open_ike_sa_timeout;
this->public.get_keepalive_interval = (u_int32_t (*) (configuration_t *)) get_keepalive_interval;
this->public.get_dpd_interval = (u_int32_t (*) (configuration_t *)) get_dpd_interval;
/**
* @brief Returns the retransmit timeout.
*
+ * A return value of zero means the request should not retransmitted again.
* The timeout values are managed by the configuration, so
* another backoff algorithm may be implemented here.
*
* @param this calling object
* @param retransmit_count number of times a message was retransmitted so far
- * @param[out] timeout the new retransmit timeout in milliseconds
- *
- * @return
- * - FAILED, if the message should not be retransmitted
- * - SUCCESS
+ * @return time in milliseconds, when to schedule next retransmit
*/
- status_t (*get_retransmit_timeout) (configuration_t *this, u_int32_t retransmit_count, u_int32_t *timeout);
+ u_int32_t (*get_retransmit_timeout) (configuration_t *this, u_int32_t retransmit_count);
/**
* @brief Returns the timeout for an half open IKE_SA in ms.
* NAT keepalive packet should be sent.
*
* @param this calling object
- * @return interval in milliseconds (ms)
+ * @return interval in seconds
*/
u_int32_t (*get_keepalive_interval) (configuration_t *this);
* DPD request packet should be sent.
*
* @param this calling object
- * @return interval in milliseconds (ms)
+ * @return interval in seconds
*/
u_int32_t (*get_dpd_interval) (configuration_t *this);
return TRUE;
}
}
+ alg_iter->destroy(alg_iter);
}
prop_iter->destroy(prop_iter);
- alg_iter->destroy(alg_iter);
return FALSE;
}
this->public.add_other_traffic_selector = (void(*)(policy_t*,traffic_selector_t*))add_other_traffic_selector;
this->public.add_proposal = (void(*)(policy_t*,proposal_t*))add_proposal;
this->public.add_authorities = (void(*)(policy_t*,identification_t*, identification_t*))add_authorities;
- this->public.add_updown = (void(*)(policy_t*,identification_t*,char*))add_updown;
+ this->public.add_updown = (void(*)(policy_t*,char*))add_updown;
this->public.get_soft_lifetime = (u_int32_t (*) (policy_t *))get_soft_lifetime;
this->public.get_hard_lifetime = (u_int32_t (*) (policy_t *))get_hard_lifetime;
this->public.clone = (policy_t*(*)(policy_t*))clone;
add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0);
add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0);
break;
+ default:
+ break;
}
return &this->public;
#include "daemon.h"
#include <types.h>
-#include <config/credentials/credential_store.h>
+#include <config/credentials/local_credential_store.h>
#include <config/connections/local_connection_store.h>
#include <config/policies/local_policy_store.h>
/ useable certificate support
+ more id types (use atodn from pluto)
+ rewrite certificate storage the clean way
- - further subjectAltName support
- - certificate validation/chaining
- - certificate exchange
+ + further subjectAltName support
+ + certificate validation/chaining
+ + certificate exchange
+ Apply -W's from Makefile.program to charon
+ do ipsec status via starter
+ stroke status should show configured connections
+ stroke loglevel update
-- stroke argument parsing via getopts/gperf?
++ stroke argument parsing via getopts/gperf?
- implement 3DES to load encrypted pem files
+ ipsec.secrets parsing
- add a crl fetch mechanism which synchronizes equal fetches
- replace state machine with something more transaction oriented
+- find existing IKE_SA on CHILD_SA initiation
*/
#include <stdlib.h>
+#include <string.h>
#include "message.h"
/**
* Implementation of message_t.get_ike_sa_id.
*/
-static status_t get_ike_sa_id (private_message_t *this,ike_sa_id_t **ike_sa_id)
+static ike_sa_id_t* get_ike_sa_id (private_message_t *this)
{
- if (this->ike_sa_id == NULL)
- {
- return FAILED;
- }
- *ike_sa_id = this->ike_sa_id->clone(this->ike_sa_id);
- return SUCCESS;
+ return this->ike_sa_id;
}
/**
}
/**
+ * Is this message in an encoded form?
+ */
+static bool is_encoded(private_message_t *this)
+{
+ chunk_t data = this->packet->get_data(this->packet);
+
+ if (data.ptr == NULL)
+ {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
* Implementation of message_t.add_payload.
*/
static void add_payload(private_message_t *this, payload_t *payload)
return this->payloads->create_iterator(this->payloads, TRUE);
}
+/**
+ * Build a string containing short names for all payload in this message
+ */
+static void build_payload_string(private_message_t *this, char* buffer, size_t size)
+{
+ iterator_t *iterator;
+ payload_t *payload;
+ bool first = TRUE;
+
+ *buffer = '\0';
+ size--;
+
+ iterator = this->payloads->create_iterator(this->payloads, TRUE);
+ while (iterator->iterate(iterator, (void**)&payload))
+ {
+ payload_type_t type = payload->get_type(payload);
+ char *name = mapping_find(payload_type_short_m, type);
+ size_t name_len = strlen(name);
+ if (!first)
+ {
+ strncat(buffer, " ", size);
+ if (size)
+ {
+ size--;
+ }
+ }
+ else
+ {
+ first = FALSE;
+ }
+ strncat(buffer, name, size);
+ if (name_len > size)
+ {
+ size = 0;
+ }
+ else
+ {
+ size -= name_len;
+ }
+ }
+ iterator->destroy(iterator);
+}
/**
* Implementation of message_t.generate.
iterator_t *iterator;
status_t status;
chunk_t packet_data;
+ char payload_names[128];
+
+ if (is_encoded(this))
+ {
+ /* already generated, return a new packet clone */
+ *packet = this->packet->clone(this->packet);
+ return SUCCESS;
+ }
- this->logger->log(this->logger, CONTROL, "generating %s %s, contains %d payloads",
+ build_payload_string(this, payload_names, sizeof(payload_names));
+ this->logger->log(this->logger, CONTROL, "generating %s %s [%s]",
mapping_find(exchange_type_m,this->exchange_type),
this->is_request ? "request" : "response",
- this->payloads->get_count(this->payloads));
+ payload_names);
if (this->exchange_type == EXCHANGE_TYPE_UNDEFINED)
{
}
/**
- * Implementation of message_t.is_encoded.
- */
-static bool is_encoded(private_message_t *this)
-{
- chunk_t data = this->packet->get_data(this->packet);
-
- if (data.ptr == NULL)
- {
- return FALSE;
- }
- return TRUE;
-}
-
-/**
* Implementation of message_t.parse_header.
*/
static status_t parse_header(private_message_t *this)
{
status_t status = SUCCESS;
payload_type_t current_payload_type;
+ char payload_names[128];
current_payload_type = this->first_payload;
{
this->logger->log(this->logger, ERROR, "payload type %s could not be parsed",
mapping_find(payload_type_m,current_payload_type));
- return status;
+ return PARSE_ERROR;
}
this->logger->log(this->logger, CONTROL|LEVEL2, "verify payload of type %s",
this->logger->log(this->logger, ERROR, "%s payload verification failed",
mapping_find(payload_type_m,current_payload_type));
current_payload->destroy(current_payload);
- status = VERIFY_ERROR;
- return status;
+ return VERIFY_ERROR;
}
this->logger->log(this->logger, CONTROL|LEVEL2, "%s payload verified. Adding to payload list",
if (status != SUCCESS)
{
this->logger->log(this->logger, ERROR, "verification of message failed");
+ return status;
}
- this->logger->log(this->logger, CONTROL, "parsed %s %s, contains %d payloads",
+ build_payload_string(this, payload_names, sizeof(payload_names));
+ this->logger->log(this->logger, CONTROL, "parsed %s %s [%s]",
mapping_find(exchange_type_m, this->exchange_type),
this->is_request ? "request" : "response",
- this->payloads->get_count(this->payloads));
+ payload_names);
- return status;
+ return SUCCESS;
}
/**
mapping_find(payload_type_m, current_payload_type),
this->message_rule->payload_rules[i].max_occurence, found_payloads);
iterator->destroy(iterator);
- return FAILED;
+ return VERIFY_ERROR;
}
}
}
mapping_find(payload_type_m, this->message_rule->payload_rules[i].payload_type),
this->message_rule->payload_rules[i].min_occurence, found_payloads);
iterator->destroy(iterator);
- return FAILED;
+ return VERIFY_ERROR;
}
if ((this->message_rule->payload_rules[i].sufficient) && (this->payloads->get_count(this->payloads) == total_found_payloads))
{
/* encrypted payload is not last one */
this->logger->log(this->logger, ERROR, "encrypted payload is not last payload");
iterator->destroy(iterator);
- return FAILED;
+ return VERIFY_ERROR;
}
/* decrypt */
encryption_payload->set_transforms(encryption_payload, crypter, signer);
{
this->logger->log(this->logger, ERROR, "encryption payload signature invalid");
iterator->destroy(iterator);
- return status;
+ return FAILED;
}
this->logger->log(this->logger, CONTROL | LEVEL2, "decrypt content of encryption payload");
status = encryption_payload->decrypt(encryption_payload);
"encrypted payload could not be decrypted and parsed: %s",
mapping_find(status_m, status));
iterator->destroy(iterator);
- return status;
+ return PARSE_ERROR;
}
/* needed later to find out if a payload was encrypted */
this->logger->log(this->logger, ERROR, "payload type %s not allowed",
mapping_find(payload_type_m,current_payload_type));
iterator->destroy(iterator);
- return status;
+ return VERIFY_ERROR;
}
/* check if the payload was encrypted, and if it should been have encrypted */
mapping_find(payload_type_m,current_payload_type),
(payload_rule->encrypted) ? "encrypted" : "not encrypted");
iterator->destroy(iterator);
- return FAILED;
+ return VERIFY_ERROR;
}
}
/* advance to the next payload */
{
iterator_t *iterator;
- this->logger->log(this->logger, CONTROL|LEVEL3, "going to destroy message_t object");
-
this->packet->destroy(this->packet);
if (this->ike_sa_id != NULL)
{
payload_t *payload;
iterator->current(iterator, (void**)&payload);
- this->logger->log(this->logger, CONTROL|LEVEL3, "destroying payload of type %s",
- mapping_find(payload_type_m, payload->get_type(payload)));
payload->destroy(payload);
}
iterator->destroy(iterator);
this->public.get_initiator_spi = (u_int64_t(*)(message_t*))get_initiator_spi;
this->public.get_responder_spi = (u_int64_t(*)(message_t*))get_responder_spi;
this->public.set_ike_sa_id = (void(*)(message_t*, ike_sa_id_t *))set_ike_sa_id;
- this->public.get_ike_sa_id = (status_t(*)(message_t*, ike_sa_id_t **))get_ike_sa_id;
+ this->public.get_ike_sa_id = (ike_sa_id_t*(*)(message_t*))get_ike_sa_id;
this->public.set_exchange_type = (void(*)(message_t*, exchange_type_t))set_exchange_type;
this->public.get_exchange_type = (exchange_type_t(*)(message_t*))get_exchange_type;
this->public.set_request = (void(*)(message_t*, bool))set_request;
this->public.parse_body = (status_t (*) (message_t *,crypter_t*,signer_t*)) parse_body;
this->public.get_packet = (packet_t * (*) (message_t*)) get_packet;
this->public.get_packet_data = (chunk_t (*) (message_t *this)) get_packet_data;
- this->public.is_encoded = (bool (*) (message_t *this)) is_encoded;
this->public.destroy = (void(*)(message_t*))destroy;
/* private values */
/**
* @brief Sets the IKE_SA ID of the message.
*
- * @warning ike_sa_id gets cloned internaly and
- * so can be destroyed afterwards.
+ * ike_sa_id gets cloned.
*
* @param this message_t object
* @param ike_sa_id ike_sa_id to set
*/
- void (*set_ike_sa_id) (message_t *this,ike_sa_id_t * ike_sa_id);
+ void (*set_ike_sa_id) (message_t *this, ike_sa_id_t * ike_sa_id);
/**
* @brief Gets the IKE_SA ID of the message.
- *
- * @warning The returned ike_sa_id is a clone of the internal one.
- * So it has to be destroyed by the caller.
+ *
+ * The ike_sa_id points to the message internal id, do not modify.
*
* @param this message_t object
- * @param ike_sa_id pointer to ike_sa_id pointer which will be set
- * @return
- * - SUCCESS
- * - FAILED if no ike_sa_id is set
+ * @return ike_sa_id of message
*/
- status_t (*get_ike_sa_id) (message_t *this,ike_sa_id_t **ike_sa_id);
+ ike_sa_id_t *(*get_ike_sa_id) (message_t *this);
/**
* @brief Sets the exchange type of the message.
* @param crypter crypter to decrypt encryption payloads
* @param signer signer to verifiy a message with an encryption payload
* @return
- * - SUCCESS if header could be parsed
+ * - SUCCESS if parsing successful
* - NOT_SUPPORTED if ciritcal unknown payloads found
- * - FAILED if message type is not suppported!
- * - PARSE_ERROR if corrupted/invalid data found
- * - VERIFY_ERROR if verification of some payload failed
+ * - NOT_SUPPORTED if message type is not supported!
+ * - PARSE_ERROR if message parsing failed
+ * - VERIFY_ERROR if message verification failed (bad syntax)
+ * - FAILED if integrity check failed
* - INVALID_STATE if crypter/signer not supplied, but needed
*/
status_t (*parse_body) (message_t *this, crypter_t *crypter, signer_t *signer);
* message.
* Crypter/signer can be omitted (by passing NULL) when no encryption
* payload is expected.
+ * Generation is only done once, multiple calls will just return a packet copy.
*
* @param this message_t object
* @param crypter crypter to use when a payload must be encrypted
* @param signer signer to build a mac
+ * @param packet copy of generated packet
* @return
* - SUCCESS if packet could be generated
* - INVALID_STATE if exchange type is currently not set
chunk_t (*get_packet_data) (message_t *this);
/**
- * @brief Check if a message is encoded.
- *
- * Check if the packet is in a generated (and encrypted) form available
- * and can be passed down to the socket. If not, it has to be generated
- * first.
- *
- * @param this message_t object
- * @return TRUE if encoded, FALSE if not
- */
- bool (*is_encoded) (message_t *this);
-
-
- /**
* @brief Destroys a message and all including objects.
*
* @param this message_t object
this->set_cert_encoding(this, CERT_X509_SIGNATURE);
this->set_data(this, cert->get_certificate(cert));
return this;
-}
\ No newline at end of file
+}
}
- this->key_exchange_data.ptr = clalloc(key_exchange_data.ptr,key_exchange_data.len);
-
- this->key_exchange_data.len = key_exchange_data.len;
+ this->key_exchange_data = chunk_clone(key_exchange_data);
this->compute_length(this);
}
this->critical = FALSE;
this->next_payload = NO_PAYLOAD;
this->payload_length = KE_PAYLOAD_HEADER_LENGTH;
- this->key_exchange_data.ptr = NULL;
- this->key_exchange_data.len = 0;
- this->dh_group_number = 0;
+ this->key_exchange_data = CHUNK_INITIALIZER;
+ this->dh_group_number = MODP_NONE;
+
+ return &this->public;
+}
- return (&(this->public));
+/*
+ * Described in header
+ */
+ke_payload_t *ke_payload_create_from_diffie_hellman(diffie_hellman_t *dh)
+{
+ private_ke_payload_t *this = (private_ke_payload_t*)ke_payload_create();
+
+ dh->get_my_public_value(dh, &this->key_exchange_data);
+ this->dh_group_number = dh->get_dh_group(dh);
+ this->compute_length(this);
+
+ return &this->public;
}
#include <encoding/payloads/payload.h>
#include <encoding/payloads/transform_substructure.h>
#include <utils/linked_list.h>
+#include <crypto/diffie_hellman.h>
+
/**
* KE payload length in bytes without any key exchange data.
*
*/
ke_payload_t *ke_payload_create(void);
+/**
+ * @brief Creates a ke_payload_t from a diffie_hellman_t
+ *
+ * @param diffie_hellman diffie hellman object containing group and key
+ * @return ke_payload_t object
+ *
+ * @ingroup payloads
+ */
+ke_payload_t *ke_payload_create_from_diffie_hellman(diffie_hellman_t *diffie_hellman);
-#endif /*KE_PAYLOAD_H_*/
+#endif /* KE_PAYLOAD_H_ */
#include <encoding/payloads/payload.h>
/**
+ * Nonce size in bytes for nonces sending to other peer.
+ *
+ * @warning Nonce size MUST be between 16 and 256 bytes.
+ *
+ * @ingroup payloads
+ */
+#define NONCE_SIZE 16
+
+/**
* Length of a nonce payload without a nonce in bytes.
*
* @ingroup payloads
#include <daemon.h>
#include <encoding/payloads/encodings.h>
+#define SHA1_HASH_SIZE 20
+
/**
- * String mappings for notify_message_type_t.
+ * String mappings for notify_type_t.
*/
-mapping_t notify_message_type_m[] = {
+mapping_t notify_type_m[] = {
{UNSUPPORTED_CRITICAL_PAYLOAD, "UNSUPPORTED_CRITICAL_PAYLOAD"},
{INVALID_IKE_SPI, "INVALID_IKE_SPI"},
{INVALID_MAJOR_VERSION, "INVALID_MAJOR_VERSION"},
/**
* Notify message type.
*/
- u_int16_t notify_message_type;
+ u_int16_t notify_type;
/**
* Security parameter index (spi).
/* SPI Size as 8 bit field*/
{ SPI_SIZE, offsetof(private_notify_payload_t, spi_size) },
/* Notify message type as 16 bit field*/
- { U_INT_16, offsetof(private_notify_payload_t, notify_message_type) },
+ { U_INT_16, offsetof(private_notify_payload_t, notify_type) },
/* SPI as variable length field*/
{ SPI, offsetof(private_notify_payload_t, spi) },
/* Key Exchange Data is from variable size */
return FAILED;
}
- /* TODO: Check all kinds of notify */
- if (this->notify_message_type == INVALID_KE_PAYLOAD)
+ switch (this->notify_type)
{
- /* check notification data */
- diffie_hellman_group_t dh_group;
- if (this->notification_data.len != 2)
+ case INVALID_KE_PAYLOAD:
{
- return FAILED;
+ /* check notification data */
+ diffie_hellman_group_t dh_group;
+ if (this->notification_data.len != 2)
+ {
+ return FAILED;
+ }
+ dh_group = ntohs(*((u_int16_t*)this->notification_data.ptr));
+ switch (dh_group)
+ {
+ case MODP_768_BIT:
+ case MODP_1024_BIT:
+ case MODP_1536_BIT:
+ case MODP_2048_BIT:
+ case MODP_3072_BIT:
+ case MODP_4096_BIT:
+ case MODP_6144_BIT:
+ case MODP_8192_BIT:
+ break;
+ default:
+ this->logger->log(this->logger, ERROR, "Bad DH group (%d)", dh_group);
+ return FAILED;
+ }
+ break;
}
- dh_group = ntohs(*((u_int16_t*)this->notification_data.ptr));
- switch (dh_group)
+ case NAT_DETECTION_SOURCE_IP:
+ case NAT_DETECTION_DESTINATION_IP:
{
- case MODP_768_BIT:
- case MODP_1024_BIT:
- case MODP_1536_BIT:
- case MODP_2048_BIT:
- case MODP_3072_BIT:
- case MODP_4096_BIT:
- case MODP_6144_BIT:
- case MODP_8192_BIT:
- break;
- default:
- this->logger->log(this->logger, ERROR, "Bad DH group (%d)", dh_group);
+ if (this->notification_data.len != SHA1_HASH_SIZE)
+ {
+ this->logger->log(this->logger, ERROR, "invalid %s notify length",
+ mapping_find(notify_type_m, this->notify_type));
+ return FAILED;
+ }
+ break;
+ }
+ case INVALID_SYNTAX:
+ case INVALID_MAJOR_VERSION:
+ case NO_PROPOSAL_CHOSEN:
+ {
+ if (this->notification_data.len != 0)
+ {
+ this->logger->log(this->logger, ERROR, "invalid %s notify",
+ mapping_find(notify_type_m, this->notify_type));
return FAILED;
+ }
+ break;
}
+ default:
+ /* TODO: verify */
+ break;
}
return SUCCESS;
}
}
/**
- * Implementation of notify_payload_t.get_notify_message_type.
+ * Implementation of notify_payload_t.get_notify_type.
*/
-static notify_message_type_t get_notify_message_type(private_notify_payload_t *this)
+static notify_type_t get_notify_type(private_notify_payload_t *this)
{
- return this->notify_message_type;
+ return this->notify_type;
}
/**
- * Implementation of notify_payload_t.set_notify_message_type.
+ * Implementation of notify_payload_t.set_notify_type.
*/
-static void set_notify_message_type(private_notify_payload_t *this, u_int16_t notify_message_type)
+static void set_notify_type(private_notify_payload_t *this, u_int16_t notify_type)
{
- this->notify_message_type = notify_message_type;
+ this->notify_type = notify_type;
}
/**
*/
static status_t set_notification_data(private_notify_payload_t *this, chunk_t notification_data)
{
- /* destroy existing data first */
- if (this->notification_data.ptr != NULL)
- {
- /* free existing value */
- free(this->notification_data.ptr);
- this->notification_data.ptr = NULL;
- this->notification_data.len = 0;
-
- }
-
- this->notification_data.ptr = clalloc(notification_data.ptr,notification_data.len);
- this->notification_data.len = notification_data.len;
+ chunk_free(&this->notification_data);
+ this->notification_data = chunk_clone(notification_data);
this->compute_length(this);
-
return SUCCESS;
}
*/
static status_t destroy(private_notify_payload_t *this)
{
- if (this->notification_data.ptr != NULL)
- {
- free(this->notification_data.ptr);
- }
- if (this->spi.ptr != NULL)
- {
- free(this->spi.ptr);
- }
+ chunk_free(&this->notification_data);
+ chunk_free(&this->spi);
free(this);
return SUCCESS;
}
/* public functions */
this->public.get_protocol_id = (u_int8_t (*) (notify_payload_t *)) get_protocol_id;
this->public.set_protocol_id = (void (*) (notify_payload_t *,u_int8_t)) set_protocol_id;
- this->public.get_notify_message_type = (notify_message_type_t (*) (notify_payload_t *)) get_notify_message_type;
- this->public.set_notify_message_type = (void (*) (notify_payload_t *,notify_message_type_t)) set_notify_message_type;
+ this->public.get_notify_type = (notify_type_t (*) (notify_payload_t *)) get_notify_type;
+ this->public.set_notify_type = (void (*) (notify_payload_t *,notify_type_t)) set_notify_type;
this->public.get_spi = (u_int32_t (*) (notify_payload_t *)) get_spi;
this->public.set_spi = (void (*) (notify_payload_t *,u_int32_t)) set_spi;
this->public.get_notification_data = (chunk_t (*) (notify_payload_t *)) get_notification_data;
this->next_payload = NO_PAYLOAD;
this->payload_length = NOTIFY_PAYLOAD_HEADER_LENGTH;
this->protocol_id = 0;
- this->notify_message_type = 0;
+ this->notify_type = 0;
this->spi.ptr = NULL;
this->spi.len = 0;
this->spi_size = 0;
this->notification_data.len = 0;
this->logger = logger_manager->get_logger(logger_manager, PAYLOAD);
- return (&(this->public));
+ return &this->public;
}
/*
* Described in header.
*/
-notify_payload_t *notify_payload_create_from_protocol_and_type(protocol_id_t protocol_id, notify_message_type_t notify_message_type)
+notify_payload_t *notify_payload_create_from_protocol_and_type(protocol_id_t protocol_id, notify_type_t notify_type)
{
notify_payload_t *notify = notify_payload_create();
- notify->set_notify_message_type(notify,notify_message_type);
+ notify->set_notify_type(notify,notify_type);
notify->set_protocol_id(notify,protocol_id);
return notify;
*/
#define NOTIFY_PAYLOAD_HEADER_LENGTH 8
-typedef enum notify_message_type_t notify_message_type_t;
+typedef enum notify_type_t notify_type_t;
/**
*
* @ingroup payloads
*/
-enum notify_message_type_t {
+enum notify_type_t {
UNSUPPORTED_CRITICAL_PAYLOAD = 1,
INVALID_IKE_SPI = 4,
INVALID_MAJOR_VERSION = 5,
};
/**
- * String mappings for notify_message_type_t.
+ * String mappings for notify_type_t.
*
* @ingroup payloads
*/
-extern mapping_t notify_message_type_m[];
+extern mapping_t notify_type_m[];
typedef struct notify_payload_t notify_payload_t;
* @param this calling notify_payload_t object
* @return notify message type of this payload
*/
- notify_message_type_t (*get_notify_message_type) (notify_payload_t *this);
+ notify_type_t (*get_notify_type) (notify_payload_t *this);
/**
* @brief Sets notify message type of this payload.
* @param this calling notify_payload_t object
* @param type notify message type to set
*/
- void (*set_notify_message_type) (notify_payload_t *this, notify_message_type_t type);
+ void (*set_notify_type) (notify_payload_t *this, notify_type_t type);
/**
* @brief Returns the currently set spi of this payload.
* @brief Creates an notify_payload_t object of specific type for specific protocol id.
*
* @param protocol_id protocol id (IKE, AH or ESP)
- * @param notify_message_type notify type (see notify_message_type_t)
+ * @param type notify type (see notify_type_t)
* @return notify_payload_t object
*
* @ingroup payloads
*/
-notify_payload_t *notify_payload_create_from_protocol_and_type(protocol_id_t protocol_id, notify_message_type_t notify_message_type);
+notify_payload_t *notify_payload_create_from_protocol_and_type(protocol_id_t protocol_id, notify_type_t type);
#endif /*NOTIFY_PAYLOAD_H_*/
};
/*
+ * build the short mappings for payload_type_t
+ */
+mapping_t payload_type_short_m[] = {
+ {NO_PAYLOAD, "--"},
+ {SECURITY_ASSOCIATION, "SA"},
+ {KEY_EXCHANGE, "KE"},
+ {ID_INITIATOR, "IDi"},
+ {ID_RESPONDER, "IDr"},
+ {CERTIFICATE, "CERT"},
+ {CERTIFICATE_REQUEST, "CERTREQ"},
+ {AUTHENTICATION, "AUTH"},
+ {NONCE, "No"},
+ {NOTIFY, "N"},
+ {DELETE, "D"},
+ {VENDOR_ID, "V"},
+ {TRAFFIC_SELECTOR_INITIATOR, "TSi"},
+ {TRAFFIC_SELECTOR_RESPONDER, "TSr"},
+ {ENCRYPTED, "E"},
+ {CONFIGURATION, "CP"},
+ {EXTENSIBLE_AUTHENTICATION, "EAP"},
+ {HEADER, "HDR"},
+ {PROPOSAL_SUBSTRUCTURE, "PROP"},
+ {TRANSFORM_SUBSTRUCTURE, "TRANS"},
+ {TRANSFORM_ATTRIBUTE, "TRANSATTR"},
+ {TRAFFIC_SELECTOR_SUBSTRUCTURE, "TSSUB"},
+ {CONFIGURATION_ATTRIBUTE, "CPATTR"},
+ {UNKNOWN_PAYLOAD, "??"},
+ {MAPPING_END, NULL}
+};
+
+/*
* see header
*/
payload_t *payload_create(payload_type_t type)
*/
extern mapping_t payload_type_m[];
+/**
+ * Special string mappings for payload_type_t in a short form.
+ */
+extern mapping_t payload_type_short_m[];
+
typedef struct payload_t payload_t;
iterator->destroy(iterator);
/* take over general infos */
- this->spi_size = proposal->get_protocol(proposal) == PROTO_IKE ? 8 : 4;
+ this->spi_size = proposal->get_protocol(proposal) == PROTO_IKE ? 0 : 4;
this->spi.len = this->spi_size;
- this->spi.ptr = malloc(this->spi_size);
- if (this->spi_size == 8)
- {
- *((u_int64_t*)this->spi.ptr) = proposal->get_spi(proposal);
- }
- else
+ if (this->spi_size == 4)
{
+ this->spi.ptr = malloc(this->spi_size);
*((u_int32_t*)this->spi.ptr) = proposal->get_spi(proposal);
}
this->proposal_number = 0;
if (ignore_struct_number < struct_number)
{
/* remova an already added, if first of series */
- proposal_list->remove_last(proposal_list, (void**)proposal);
+ proposal_list->remove_last(proposal_list, (void**)&proposal);
proposal->destroy(proposal);
ignore_struct_number = struct_number;
}
};
/**
- * Implements interfaces_t.get_addresses
+ * Implements interfaces_t.create_address_iterator
*/
-static linked_list_t* get_addresses(private_interfaces_t *this)
+static iterator_t* create_address_iterator(private_interfaces_t *this)
{
- return this->addresses;
+ return this->addresses->create_iterator(this->addresses, TRUE);
}
/**
this->port = port;
- this->public.get_addresses = (linked_list_t* (*) (interfaces_t*)) get_addresses;
+ this->public.create_address_iterator = (iterator_t* (*) (interfaces_t*)) create_address_iterator;
this->public.is_local_address = (bool (*) (interfaces_t*, host_t*)) is_local_address;
this->public.destroy = (void (*) (interfaces_t*)) destroy;
struct interfaces_t {
/**
- * @brief Get addresses of local interfaces
+ * @brief Get an iterator over addresses of local interfaces
*
* @param this calling object
- * @return linked_list_t of host_t objects
+ * @return iterator over host_t objects
*/
- linked_list_t* (*get_addresses) (interfaces_t *ifaces);
+ iterator_t* (*create_address_iterator) (interfaces_t *this);
/**
* @brief Check if address is associated with a local interface
* @param host address to set as destination
* @return TRUE if address is associated with a local interface, FALSE otherwise
*/
- bool (*is_local_address) (interfaces_t *ifaces, host_t *host);
+ bool (*is_local_address) (interfaces_t *this, host_t *host);
/**
* @brief Destroy the object, freeing contained data.
interfaces_t *interfaces_create(u_int16_t port);
-#endif /*INTERFACES_H_*/
+#endif /* INTERFACES_H_ */
pkt->set_source(pkt, source);
pkt->set_destination(pkt, dest);
- this->logger->log(this->logger, CONTROL, "received packet: from %s:%d to %s:%d",
+ this->logger->log(this->logger, CONTROL|LEVEL1, "received packet: from %s:%d to %s:%d",
source->get_address(source), source->get_port(source),
dest->get_address(dest), dest->get_port(dest));
dst = packet->get_destination(packet);
data = packet->get_data(packet);
- this->logger->log(this->logger, CONTROL, "sending packet: from %s:%d to %s:%d",
+ this->logger->log(this->logger, CONTROL|LEVEL1, "sending packet: from %s:%d to %s:%d",
src->get_address(src), src->get_port(src),
dst->get_address(dst), dst->get_port(dst));
static status_t execute(private_delete_half_open_ike_sa_job_t *this)
{
ike_sa_t *ike_sa;
- status_t status;
- status = charon->ike_sa_manager->checkout(charon->ike_sa_manager, this->ike_sa_id, &ike_sa);
- if ((status != SUCCESS) && (status != CREATED))
+ if (charon->ike_sa_manager->checkout(charon->ike_sa_manager, this->ike_sa_id,
+ &ike_sa) != SUCCESS)
{
- this->logger->log(this->logger, CONTROL | LEVEL3, "IKE SA seems to be already deleted");
return DESTROY_ME;
}
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:
- case DELETE_IKE_SA_REQUESTED:
+ case SA_ESTABLISHED:
{
- /* IKE_SA is half open and gets deleted! */
- status = charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, ERROR, "Could not checkin and delete checked out IKE_SA!");
- }
+ /* IKE_SA is established and so is not getting destroyed */
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
return DESTROY_ME;
}
default:
{
- /* IKE_SA is established and so is not getting deleted! */
- status = charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, ERROR, "Could not checkin a checked out IKE_SA!");
- }
+ /* IKE_SA is half open and gets destroyed */
+ this->logger->log(this->logger, AUDIT,
+ "deleting half open IKE_SA after timeout");
+ charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
return DESTROY_ME;
}
}
* @brief Class representing an DELETE_HALF_OPEN_IKE_SA Job.
*
* This job is responsible for deleting of half open IKE_SAs. A half
- * open IKE_SA is every IKE_SA which hasn't reache the ike_sa_established
+ * open IKE_SA is every IKE_SA which hasn't reache the SA_ESTABLISHED
* state.
*
* @b Constructors:
* @ingroup jobs
*/
struct delete_half_open_ike_sa_job_t {
+
/**
* The job_t interface.
*/
*/
delete_half_open_ike_sa_job_t *delete_half_open_ike_sa_job_create(ike_sa_id_t *ike_sa_id);
-#endif /*DELETE_HALF_OPEN_IKE_SA_JOB_H_*/
+#endif /* DELETE_HALF_OPEN_IKE_SA_JOB_H_ */
}
/**
+ * send a notify back to the sender
+ */
+static void send_notify_response(private_incoming_packet_job_t *this,
+ message_t *request,
+ notify_type_t type)
+{
+ notify_payload_t *notify;
+ message_t *response;
+ host_t *src, *dst;
+ packet_t *packet;
+ ike_sa_id_t *ike_sa_id;
+
+ ike_sa_id = request->get_ike_sa_id(request);
+ ike_sa_id = ike_sa_id->clone(ike_sa_id);
+ ike_sa_id->switch_initiator(ike_sa_id);
+
+ response = message_create();
+ dst = request->get_source(request);
+ src = request->get_destination(request);
+ response->set_source(response, src->clone(src));
+ response->set_destination(response, dst->clone(dst));
+ response->set_exchange_type(response, IKE_SA_INIT);
+ response->set_request(response, FALSE);
+ response->set_message_id(response, 0);
+ response->set_ike_sa_id(response, ike_sa_id);
+ notify = notify_payload_create_from_protocol_and_type(PROTO_NONE, type);
+ response->add_payload(response, (payload_t *)notify);
+ if (response->generate(response, NULL, NULL, &packet) != SUCCESS)
+ {
+ response->destroy(response);
+ return;
+ }
+ this->logger->log(this->logger, CONTROL, "sending %s notify",
+ mapping_find(notify_type_m, type));
+ charon->send_queue->add(charon->send_queue, packet);
+ response->destroy(response);
+ ike_sa_id->destroy(ike_sa_id);
+ return;
+}
+
+/**
* Implementation of job_t.execute.
*/
static status_t execute(private_incoming_packet_job_t *this)
ike_sa_t *ike_sa;
ike_sa_id_t *ike_sa_id;
status_t status;
- packet_t *packet;
+ host_t *src, *dst;
message = message_create_from_packet(this->packet->clone(this->packet));
+ src = message->get_source(message);
+ dst = message->get_destination(message);
+ this->logger->log(this->logger, CONTROL, "received packet: from %s:%d to %s:%d",
+ src->get_address(src), src->get_port(src),
+ dst->get_address(dst), dst->get_port(dst));
+
status = message->parse_header(message);
if (status != SUCCESS)
{
- this->logger->log(this->logger, ERROR, "Message header could not be verified!");
+ this->logger->log(this->logger, ERROR, "received message with invalid IKE header, ignored");
message->destroy(message);
return DESTROY_ME;
}
- this->logger->log(this->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))
{
- this->logger->log(this->logger, ERROR | LEVEL2,
- "IKE version %d.%d not supported",
+ this->logger->log(this->logger, ERROR,
+ "received a packet with 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)))
{
- notify_payload_t *notify;
- message_t *response;
- host_t *src, *dst;
-
- message->get_ike_sa_id(message, &ike_sa_id);
- ike_sa_id->switch_initiator(ike_sa_id);
-
- response = message_create();
- src = message->get_source(message);
- dst = message->get_destination(message);
- response->set_source(response, src->clone(src));
- response->set_destination(response, dst->clone(dst));
- response->set_exchange_type(response, IKE_SA_INIT);
- response->set_request(response, FALSE);
- response->set_message_id(response, 0);
- response->set_ike_sa_id(response, ike_sa_id);
-
- notify = notify_payload_create_from_protocol_and_type(PROTO_NONE, INVALID_MAJOR_VERSION);
- response->add_payload(response, (payload_t *)notify);
-
- status = response->generate(response, NULL, NULL, &packet);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, ERROR, "Could not generate packet from message");
- response->destroy(response);
- return DESTROY_ME;
- }
- this->logger->log(this->logger, ERROR, "Send notify reply of type INVALID_MAJOR_VERSION");
- charon->send_queue->add(charon->send_queue, packet);
- response->destroy(response);
- return DESTROY_ME;
+ send_notify_response(this, message, INVALID_MAJOR_VERSION);
}
message->destroy(message);
return DESTROY_ME;
}
- message->get_ike_sa_id(message, &ike_sa_id);
+ ike_sa_id = message->get_ike_sa_id(message);
+ ike_sa_id = ike_sa_id->clone(ike_sa_id);
ike_sa_id->switch_initiator(ike_sa_id);
- this->logger->log(this->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))
+ if (status != SUCCESS)
{
- this->logger->log(this->logger, ERROR, "IKE SA could not be checked out");
+ this->logger->log(this->logger, ERROR,
+ "received packet with SPIs %llx:%llx, but no such IKE_SA",
+ ike_sa_id->get_initiator_spi(ike_sa_id),
+ ike_sa_id->get_responder_spi(ike_sa_id));
+ send_notify_response(this, message, INVALID_IKE_SPI);
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 ? */
return DESTROY_ME;
}
-
- if (status == CREATED)
- {
- job_t *delete_job;
- this->logger->log(this->logger, CONTROL|LEVEL3,
- "Create Job to delete half open IKE_SA.");
-
- delete_job = (job_t *) delete_half_open_ike_sa_job_create(ike_sa_id);
- charon->event_queue->add_relative(charon->event_queue, delete_job,
- charon->configuration->get_half_open_ike_sa_timeout(charon->configuration));
- }
status = ike_sa->process_message(ike_sa, message);
-
- this->logger->log(this->logger, CONTROL|LEVEL3, "%s IKE SA %lld:%lld, role %s",
- 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 == DESTROY_ME)
{
status = charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
{
status = charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
}
-
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, ERROR, "Checkin of IKE SA failed!");
- }
+ ike_sa_id->destroy(ike_sa_id);
message->destroy(message);
return DESTROY_ME;
}
*/
static status_t execute(private_initiate_ike_sa_job_t *this)
{
- /*
- * Initiatie an IKE_SA:
- * - is defined by a name of a configuration
- * - create an empty IKE_SA via manager
- * - call initiate_connection on this sa
- */
+ /* Initiatie an IKE_SA:
+ * - is defined by a connection
+ * - create an empty IKE_SA via manager
+ * - call initiate() on this IKE_SA
+ */
ike_sa_t *ike_sa;
status_t status;
- job_t *delete_job;
this->logger->log(this->logger, CONTROL|LEVEL2, "Creating and checking out IKE SA");
charon->ike_sa_manager->create_and_checkout(charon->ike_sa_manager, &ike_sa);
- status = ike_sa->initiate_connection(ike_sa, this->connection->clone(this->connection));
+ status = ike_sa->initiate(ike_sa, this->connection->clone(this->connection));
if (status != SUCCESS)
{
- this->logger->log(this->logger, ERROR, "Initiation returned %s, going to delete IKE_SA.",
- mapping_find(status_m, status));
+ this->logger->log(this->logger, ERROR,
+ "initiation returned %s, going to delete IKE_SA.",
+ mapping_find(status_m, status));
charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
return DESTROY_ME;
}
- this->logger->log(this->logger, CONTROL|LEVEL3, "Create Job to delete half open IKE_SA.");
-
- delete_job = (job_t *) delete_half_open_ike_sa_job_create(ike_sa->get_id(ike_sa));
- charon->event_queue->add_relative(charon->event_queue, delete_job,
- charon->configuration->get_half_open_ike_sa_timeout(charon->configuration));
-
- this->logger->log(this->logger, CONTROL|LEVEL2, "Checking in IKE SA");
- status = charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, ERROR, "Could not checkin IKE_SA (%s)",
- mapping_find(status_m, status));
- }
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
return DESTROY_ME;
}
ike_sa_id_t *ike_sa_id;
/**
- * Number of times a request was retransmitted
- */
- u_int32_t retransmit_count;
-
- /**
* Logger reference
*/
logger_t *logger;
*/
static status_t execute(private_retransmit_request_job_t *this)
{
- bool stop_retransmitting = FALSE, timed_out = FALSE;
- u_int32_t timeout;
ike_sa_t *ike_sa;
status_t status;
-
- this->logger->log(this->logger, CONTROL|LEVEL2, "Checking out IKE SA %lld:%lld, role %s",
- 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");
status = charon->ike_sa_manager->checkout(charon->ike_sa_manager, this->ike_sa_id, &ike_sa);
- if ((status != SUCCESS) && (status != CREATED))
+ if (status != SUCCESS)
{
this->logger->log(this->logger, ERROR|LEVEL1,
"IKE SA could not be checked out. Already deleted?");
return DESTROY_ME;
}
- this->retransmit_count++;
- status = charon->configuration->get_retransmit_timeout(charon->configuration,
- this->retransmit_count, &timeout);
- timed_out = (status != SUCCESS);
-
- if (ike_sa->retransmit_possible(ike_sa, this->message_id))
+ if (ike_sa->retransmit_request(ike_sa, this->message_id) == DESTROY_ME)
{
- if (!timed_out)
- {
- status = ike_sa->retransmit_request(ike_sa, this->message_id);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, CONTROL|LEVEL3,
- "Message doesn't have to be retransmitted");
- stop_retransmitting = TRUE;
- }
- }
+ /* retransmission hopeless, kill SA */
+ charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
}
else
{
- stop_retransmitting = TRUE;
- }
-
- this->logger->log(this->logger, CONTROL|LEVEL2, "Checkin IKE SA %lld:%lld, role %s",
- 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");
-
- status = charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, ERROR, "Checkin of IKE SA failed!");
- }
-
- if (timed_out)
- {
- /*
- * XXX: We should act depending on DPD policy here, or not act at all.
- */
- this->logger->log(this->logger, CONTROL|LEVEL2, "Timeout: Deleting SA!");
- status = charon->ike_sa_manager->delete(charon->ike_sa_manager, this->ike_sa_id);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, ERROR|LEVEL1, "Cannot delete SA!");
- }
- return DESTROY_ME;
- }
-
- if (stop_retransmitting)
- {
- return DESTROY_ME;
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
}
-
- charon->event_queue->add_relative(charon->event_queue, (job_t *)this, timeout);
- return SUCCESS;
+ return DESTROY_ME;
}
/**
/* private variables */
this->message_id = message_id;
- this->retransmit_count = 0;
this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
this->logger = logger_manager->get_logger(logger_manager, WORKER);
{
ike_sa_t *ike_sa;
status_t status;
- u_int32_t dt;
- u_int32_t interval = charon->configuration->get_dpd_interval(charon->configuration);
- struct timeval last_msg_tv, current_tv;
-
- this->logger->log(this->logger, CONTROL|LEVEL2, "Checking out IKE SA %lld:%lld, role %s",
- 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");
status = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
- this->ike_sa_id, &ike_sa);
+ this->ike_sa_id, &ike_sa);
if (status != SUCCESS)
{
- this->logger->log(this->logger, ERROR|LEVEL1,
- "IKE SA could not be checked out. Already deleted?");
return DESTROY_ME;
}
-
- last_msg_tv = ike_sa->get_last_traffic_in_tv(ike_sa);
- if (0 > gettimeofday(¤t_tv, NULL) )
- {
- this->logger->log(this->logger, ERROR|LEVEL1,
- "Warning: Failed to get time of day.");
- }
- dt = (current_tv.tv_sec - last_msg_tv.tv_sec) * 1000
- + (current_tv.tv_usec - last_msg_tv.tv_usec) / 1000;
-
- if (dt >= interval)
+ status = ike_sa->send_dpd(ike_sa);
+ if (status == DESTROY_ME)
{
- ike_sa->send_dpd_request(ike_sa);
- this->logger->log(this->logger, CONTROL|LEVEL1,
- "DPD request packet scheduled");
-
+ charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
}
else
{
- charon->event_queue->add_relative(charon->event_queue, (job_t*) this, interval - dt);
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
}
-
- this->logger->log(this->logger, CONTROL|LEVEL2,
- "Checkin IKE SA %lld:%lld, role %s",
- 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");
-
- status = charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, ERROR, "Checkin of IKE SA failed!");
- }
-
- return SUCCESS;
+ return DESTROY_ME;
}
/**
}
/**
- * Implementation of job_t.execute.
+ * Implementation of job_t.execute.
*/
static status_t execute(private_send_keepalive_job_t *this)
{
ike_sa_t *ike_sa;
status_t status;
- u_int32_t dt;
- u_int32_t interval = charon->configuration->get_keepalive_interval(charon->configuration);
- struct timeval last_msg_tv, current_tv;
- packet_t *packet;
- host_t *host;
- connection_t *connection;
- chunk_t data;
-
- this->logger->log(this->logger, CONTROL|LEVEL2, "Checking out IKE SA %lld:%lld, role %s",
- 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");
status = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
- this->ike_sa_id, &ike_sa);
+ this->ike_sa_id, &ike_sa);
if (status != SUCCESS)
{
- this->logger->log(this->logger, ERROR|LEVEL1,
- "IKE SA could not be checked out. Already deleted?");
return DESTROY_ME;
}
-
- last_msg_tv = ike_sa->get_last_traffic_out_tv(ike_sa);
- if (0 > gettimeofday(¤t_tv, NULL) )
- {
- this->logger->log(this->logger, ERROR|LEVEL1,
- "Warning: Failed to get time of day.");
- }
- dt = (current_tv.tv_sec - last_msg_tv.tv_sec) * 1000
- + (current_tv.tv_usec - last_msg_tv.tv_usec) / 1000;
-
- if (dt >= interval)
- {
- packet = packet_create();
- connection = ike_sa->get_connection(ike_sa);
- host = connection->get_my_host(connection);
- packet->set_source(packet, host->clone(host));
- host = connection->get_other_host(connection);
- packet->set_destination(packet, host->clone(host));
- data = chunk_alloc(1);
- data.ptr[0] = 0xFF;
- packet->set_data(packet, data);
- charon->send_queue->add(charon->send_queue, packet);
- dt = 0;
- this->logger->log(this->logger, CONTROL|LEVEL1,
- "NAT keepalive packet scheduled");
- }
- charon->event_queue->add_relative(charon->event_queue, (job_t*) this, interval - dt);
-
- this->logger->log(this->logger, CONTROL|LEVEL2,
- "Checkin IKE SA %lld:%lld, role %s",
- 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");
-
- status = charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, ERROR, "Checkin of IKE SA failed!");
- }
-
- return SUCCESS;
+ ike_sa->send_keepalive(ike_sa);
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+ return DESTROY_ME;
}
/**
#include "send_queue.h"
#include <utils/linked_list.h>
+#include <utils/logger_manager.h>
typedef struct private_send_queue_t private_send_queue_t;
* This condvar is used to wake up such a thread
*/
pthread_cond_t condvar;
-};
+ /**
+ * Logger reference
+ */
+ logger_t *logger;
+};
/**
* implements send_queue_t.get_count
*/
static void add(private_send_queue_t *this, packet_t *packet)
{
+ host_t *src, *dst;
+
+ src = packet->get_source(packet);
+ dst = packet->get_destination(packet);
+ this->logger->log(this->logger, CONTROL, "sending packet: from %s:%d to %s:%d",
+ src->get_address(src), src->get_port(src),
+ dst->get_address(dst), dst->get_port(dst));
+
pthread_mutex_lock(&(this->mutex));
this->list->insert_last(this->list,packet);
pthread_cond_signal( &(this->condvar));
this->list = linked_list_create();
pthread_mutex_init(&(this->mutex), NULL);
pthread_cond_init(&(this->condvar), NULL);
+ this->logger = logger_manager->get_logger(logger_manager, SOCKET);
return (&this->public);
}
/**
* Assigned IKE_SA. Needed to get objects of type prf_t and logger_t.
*/
- protected_ike_sa_t *ike_sa;
+ ike_sa_t *ike_sa;
/**
* PRF taken from the IKE_SA.
/*
* Described in header.
*/
-authenticator_t *authenticator_create(protected_ike_sa_t *ike_sa)
+authenticator_t *authenticator_create(ike_sa_t *ike_sa)
{
private_authenticator_t *this = malloc_thing(private_authenticator_t);
/**
* @brief Creates an authenticator object.
*
- * @warning: The following functions of the assigned protected_ike_sa_t object
- * must return a valid value:
- * - protected_ike_sa_t.get_policy
- * - protected_ike_sa_t.get_prf
- * - protected_ike_sa_t.get_logger
- * This preconditions are not given in IKE_SA states INITIATOR_INIT or RESPONDER_INIT!
- *
- * @param ike_sa object of type protected_ike_sa_t
+ * @param ike_sa associated ike_sa
*
* @return authenticator_t object
*
* @ingroup sa
*/
-authenticator_t *authenticator_create(protected_ike_sa_t *ike_sa);
+authenticator_t *authenticator_create(ike_sa_t *ike_sa);
#endif /* AUTHENTICATOR_H_ */
this->public.alloc = (status_t(*)(child_sa_t*,linked_list_t*))alloc;
this->public.add = (status_t(*)(child_sa_t*,proposal_t*,prf_plus_t*))add;
this->public.update = (status_t(*)(child_sa_t*,proposal_t*,prf_plus_t*))update;
+ this->public.update_hosts = (status_t (*)(child_sa_t*,host_t*,host_t*,int,int))update_hosts;
this->public.add_policies = (status_t (*)(child_sa_t*, linked_list_t*,linked_list_t*))add_policies;
this->public.get_use_time = (status_t (*)(child_sa_t*,bool,time_t*))get_use_time;
this->public.set_rekeyed = (void (*)(child_sa_t*))set_rekeyed;
#include <definitions.h>
#include <utils/linked_list.h>
#include <utils/logger_manager.h>
-#include <utils/randomizer.h>
#include <crypto/diffie_hellman.h>
#include <crypto/prf_plus.h>
#include <crypto/crypters/crypter.h>
#include <encoding/payloads/transform_substructure.h>
#include <encoding/payloads/transform_attribute.h>
#include <encoding/payloads/ts_payload.h>
-#include <sa/states/initiator_init.h>
-#include <sa/states/responder_init.h>
-#include <sa/states/create_child_sa_requested.h>
-#include <sa/states/delete_child_sa_requested.h>
-#include <sa/states/delete_ike_sa_requested.h>
+#include <sa/transactions/transaction.h>
+#include <sa/transactions/ike_sa_init.h>
+#include <sa/transactions/delete_ike_sa.h>
+#include <sa/transactions/dead_peer_detection.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>
+#include <queues/jobs/send_dpd_job.h>
+#include <queues/jobs/send_keepalive_job.h>
+/**
+ * String mappings for ike_sa_state_t.
+ */
+mapping_t ike_sa_state_m[] = {
+ {SA_CREATED, "CREATED"},
+ {SA_CONNECTING, "CONNECTING"},
+ {SA_ESTABLISHED, "ESTABLISHED"},
+ {SA_DELETING, "DELETING"},
+ {MAPPING_END, NULL}
+};
typedef struct private_ike_sa_t private_ike_sa_t;
struct private_ike_sa_t {
/**
- * Protected part of a ike_sa_t object.
- */
- protected_ike_sa_t protected;
-
- /**
- * Update a timestamp on ike traffic
- */
- void (*update_timestamp)(private_ike_sa_t *this, bool in);
-
- /**
- * Returns the time since last traffic on kernel policies
+ * Public members
*/
- struct timeval (*get_last_esp_traffic_tv)(private_ike_sa_t * this, bool inbound);
+ ike_sa_t public;
/**
* Identifier for the current IKE_SA.
linked_list_t *child_sas;
/**
- * Current state of the IKE_SA represented as state_t object.
- *
- * A state object representates one of the following states and is processing
- * messages in the specific state:
- * - INITIATOR_INIT
- * - RESPONDER_INIT
- * - IKE_SA_INIT_REQUESTED
- * - IKE_SA_INIT_RESPONDED
- * - IKE_AUTH_REQUESTED
- * -IKE_SA_ESTABLISHED
+ * Current state of the IKE_SA
*/
- state_t *current_state;
+ ike_sa_state_t state;
/**
* Connection definition used for this IKE_SA
policy_t *policy;
/**
- * This SA's source for random data.
- *
- * Is available in every state.
- */
- randomizer_t *randomizer;
-
- /**
- * The last responded message.
- */
- message_t *last_responded_message;
-
- /**
- * The ast requested message.
- */
- message_t *last_requested_message;
-
- /**
- * Crypter object for initiator.
+ * crypter for inbound traffic
*/
- crypter_t *crypter_initiator;
+ crypter_t *crypter_in;
/**
- * Crypter object for responder.
+ * crypter for outbound traffic
*/
- crypter_t *crypter_responder;
+ crypter_t *crypter_out;
/**
- * Signer object for initiator.
+ * Signer for inbound traffic
*/
- signer_t *signer_initiator;
+ signer_t *signer_in;
/**
- * Signer object for responder.
+ * Signer for outbound traffic
*/
- signer_t *signer_responder;
+ signer_t *signer_out;
/**
* Multi purpose prf, set key, use it, forget it
* PRF, with key set to pr_key, used for authentication
*/
prf_t *prf_auth_r;
-
- /**
- * Next message id to receive.
- */
- u_int32_t message_id_in;
-
- /**
- * Next message id to send.
- */
- u_int32_t message_id_out;
-
- /**
- * Last reply id which was successfully received.
- */
- int32_t last_replied_message_id;
/**
* A logger for this IKE_SA.
* NAT status of remote host.
*/
bool nat_there;
+
+ /**
+ * message ID for next outgoung request
+ */
+ u_int32_t message_id_out;
/**
* Timestamp of last IKE message received on this SA
*/
- struct timeval last_msg_in_tv;
+ time_t time_inbound;
/**
* Timestamp of last IKE message sent on this SA
*/
- struct timeval last_msg_out_tv;
-
- /*
- * Message ID of last DPD message
+ time_t time_outbound;
+
+ /**
+ * List of queued transactions to process
+ */
+ linked_list_t *transaction_queue;
+
+ /**
+ * Transaction currently initiated
+ * (only one supported yet, window size = 1)
+ */
+ transaction_t *transaction_out;
+
+ /**
+ * last transaction initiated by peer processed.
+ * (only one supported yet, window size = 1)
+ * Stored for retransmission.
*/
- u_int32_t last_dpd_message_id;
+ transaction_t *transaction_in;
+
+ /**
+ * Next incoming transaction expected. Used to
+ * do multi transaction operations.
+ */
+ transaction_t *transaction_in_next;
};
/**
- * Implementation of protected_ike_sa_t.build_message.
+ * get the time of the latest traffic processed by the kernel
*/
-static void build_message(private_ike_sa_t *this, exchange_type_t type, bool request, message_t **message)
+static time_t get_esp_time(private_ike_sa_t* this, bool inbound)
{
- message_t *new_message;
- host_t *me, *other;
+ iterator_t *iterator;
+ child_sa_t *child_sa;
+ time_t latest = 0, use_time;
- me = this->connection->get_my_host(this->connection);
- other = this->connection->get_other_host(this->connection);
-
- this->logger->log(this->logger, CONTROL|LEVEL2, "build empty message");
- 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);
- new_message->set_request(new_message, request);
- new_message->set_message_id(new_message, (request) ? this->message_id_out : this->message_id_in);
- new_message->set_ike_sa_id(new_message, this->ike_sa_id);
-
- *message = new_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);
-}
+ iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
+ while (iterator->iterate(iterator, (void**)&child_sa))
+ {
+ if (child_sa->get_use_time(child_sa, inbound, &use_time) == SUCCESS)
+ {
+ latest = max(latest, use_time);
+ }
+ }
+ iterator->destroy(iterator);
-/**
- * Implementation of protected_ike_sa_t.set_new_state.
- */
-static void set_new_state(private_ike_sa_t *this, state_t *state)
-{
- this->logger->log(this->logger, CONTROL, "state change: %s => %s",
- 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)
-{
- return this->connection;
-}
-
-/**
- * Implementation of protected_ike_sa_t.set_connection.
- */
-static void set_connection(private_ike_sa_t *this,connection_t * connection)
-{
- this->connection = connection;
-}
-
-/**
- * Implementation of protected_ike_sa_t.get_policy.
- */
-static policy_t *get_policy(private_ike_sa_t *this)
-{
- return this->policy;
+ return latest;
}
/**
- * Implementation of protected_ike_sa_t.set_policy.
+ * get the time of the latest received traffice
*/
-static void set_policy(private_ike_sa_t *this,policy_t * policy)
+static time_t get_time_inbound(private_ike_sa_t *this)
{
- this->policy = policy;
+ return max(this->time_inbound, get_esp_time(this, TRUE));
}
/**
- * Implementation of protected_ike_sa_t.get_prf.
+ * get the time of the latest sent traffic
*/
-static prf_t *get_prf(private_ike_sa_t *this)
+static time_t get_time_outbound(private_ike_sa_t *this)
{
- return this->prf;
+ return max(this->time_outbound, get_esp_time(this, FALSE));
}
-/**
- * Implementation of protected_ike_sa_t.get_prf.
- */
-static prf_t *get_child_prf(private_ike_sa_t *this)
-{
- return this->child_prf;
-}
/**
- * Implementation of protected_ike_sa_t.get_prf_auth_i.
+ * Update connection host, as addresses may change (NAT)
*/
-static prf_t *get_prf_auth_i(private_ike_sa_t *this)
+static void update_hosts(private_ike_sa_t *this, host_t *me, host_t *other)
{
- return this->prf_auth_i;
-}
+ /*
+ * Quoting RFC 4306:
+ *
+ * 2.11. Address and Port Agility
+ *
+ * IKE runs over UDP ports 500 and 4500, and implicitly sets up ESP and
+ * AH associations for the same IP addresses it runs over. The IP
+ * addresses and ports in the outer header are, however, not themselves
+ * cryptographically protected, and IKE is designed to work even through
+ * Network Address Translation (NAT) boxes. An implementation MUST
+ * accept incoming requests even if the source port is not 500 or 4500,
+ * and MUST respond to the address and port from which the request was
+ * received. It MUST specify the address and port at which the request
+ * was received as the source address and port in the response. IKE
+ * functions identically over IPv4 or IPv6.
+ *
+ * [...]
+ *
+ * There are cases where a NAT box decides to remove mappings that
+ * are still alive (for example, the keepalive interval is too long,
+ * or the NAT box is rebooted). To recover in these cases, hosts
+ * that are not behind a NAT SHOULD send all packets (including
+ * retransmission packets) to the IP address and port from the last
+ * valid authenticated packet from the other end (i.e., dynamically
+ * update the address). A host behind a NAT SHOULD NOT do this
+ * because it opens a DoS attack possibility. Any authenticated IKE
+ * packet or any authenticated UDP-encapsulated ESP packet can be
+ * used to detect that the IP address or the port has changed.
+ */
+ host_t *old_other = NULL;
+ iterator_t *iterator = NULL;
+ child_sa_t *child_sa = NULL;
+ int my_changes, other_changes;
-/**
- * Implementation of protected_ike_sa_t.get_prf_auth_r.
- */
-static prf_t *get_prf_auth_r(private_ike_sa_t *this)
-{
- return this->prf_auth_r;
-}
-/**
- * Implementation of ike_sa_t.get_id.
- */
-static ike_sa_id_t* get_id(private_ike_sa_t *this)
-{
- return this->ike_sa_id;
-}
+ my_changes = me->get_differences(me, this->connection->get_my_host(this->connection));
-/**
- * Implementation of ike_sa_t.get_my_host.
- */
-static host_t* get_my_host(private_ike_sa_t *this)
-{
- return this->connection->get_my_host(this->connection);;
-}
+ old_other = this->connection->get_other_host(this->connection);
+ other_changes = other->get_differences(other, old_other);
-/**
- * Implementation of ike_sa_t.get_other_host.
- */
-static host_t* get_other_host(private_ike_sa_t *this)
-{
- return this->connection->get_other_host(this->connection);
+ if (!my_changes && !other_changes)
+ {
+ return;
+ }
+
+ if (my_changes)
+ {
+ this->connection->update_my_host(this->connection, me->clone(me));
+ }
+
+ if (!this->nat_here)
+ {
+ /* update without restrictions if we are not NATted */
+ if (other_changes)
+ {
+ this->connection->update_other_host(this->connection, other->clone(other));
+ }
+ }
+ else
+ {
+ /* if we are natted, only port may change */
+ if (other_changes & HOST_DIFF_ADDR)
+ {
+ return;
+ }
+ else if (other_changes & HOST_DIFF_PORT)
+ {
+ old_other->set_port(old_other, other->get_port(other));
+ }
+ }
+ iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
+ while (iterator->iterate(iterator, (void**)&child_sa))
+ {
+ child_sa->update_hosts(child_sa,
+ this->connection->get_my_host(this->connection),
+ this->connection->get_other_host(this->connection),
+ my_changes, other_changes);
+ /* TODO: what to do if update fails? Delete CHILD_SA? */
+ }
+ iterator->destroy(iterator);
}
/**
- * Implementation of ike_sa_t.get_my_id.
+ * send a request and schedule retransmission
*/
-static identification_t* get_my_id(private_ike_sa_t *this)
+static status_t transmit_request(private_ike_sa_t *this)
{
- return this->policy->get_my_id(this->policy);
+ message_t *request;
+ packet_t *packet;
+ status_t status;
+ retransmit_request_job_t *job;
+ u_int32_t transmitted;
+ u_int32_t timeout;
+ transaction_t *transaction = this->transaction_out;
+ u_int32_t message_id = transaction->get_message_id(transaction);
+
+ transmitted = transaction->requested(transaction);
+ timeout = charon->configuration->get_retransmit_timeout(charon->configuration,
+ transmitted);
+ if (timeout == 0)
+ {
+ this->logger->log(this->logger, ERROR,
+ "giving up after %d retransmits, deleting IKE_SA",
+ transmitted - 1);
+ return DESTROY_ME;
+ }
+
+ status = transaction->get_request(transaction, &request);
+ if (status != SUCCESS)
+ {
+ return status;
+ }
+ /* if we retransmit, the request is already generated */
+ if (transmitted == 0)
+ {
+ status = request->generate(request, this->crypter_out, this->signer_out, &packet);
+ if (status != SUCCESS)
+ {
+ return FAILED;
+ }
+ }
+ else
+ {
+ this->logger->log(this->logger, CONTROL,
+ "sending retransmit %d for %s request with message ID %d",
+ transmitted,
+ mapping_find(exchange_type_m, request->get_exchange_type(request)),
+ message_id);
+ packet = request->get_packet(request);
+ }
+ /* finally send */
+ charon->send_queue->add(charon->send_queue, packet);
+ this->time_outbound = time(NULL);
+
+ /* schedule retransmission job */
+ job = retransmit_request_job_create(message_id, this->ike_sa_id);
+ charon->event_queue->add_relative(charon->event_queue, (job_t*)job, timeout);
+ return SUCCESS;
}
/**
- * Implementation of ike_sa_t.get_other_id.
+ * Implementation of ike_sa.retransmit_request.
*/
-static identification_t* get_other_id(private_ike_sa_t *this)
+static status_t retransmit_request(private_ike_sa_t *this, u_int32_t message_id)
{
- return this->policy->get_other_id(this->policy);
+ if (this->transaction_out == NULL ||
+ this->transaction_out->get_message_id(this->transaction_out) != message_id)
+ {
+ /* no retransmit necessary, transaction did already complete */
+ return SUCCESS;
+ }
+ return transmit_request(this);
}
/**
- * Implementation of ike_sa_t.retransmit_possible.
+ * Check for transactions in the queue and initiate the first transaction found.
*/
-static bool retransmit_possible(private_ike_sa_t *this, u_int32_t message_id)
+static status_t process_transaction_queue(private_ike_sa_t *this)
{
- return ((this->last_requested_message)
- && (message_id != this->last_replied_message_id)
- && (message_id == this->last_requested_message->get_message_id(
- this->last_requested_message)));
+ if (this->transaction_out)
+ {
+ /* already a transaction in progress */
+ return SUCCESS;
+ }
+
+ while (TRUE)
+ {
+ if (this->transaction_queue->remove_first(this->transaction_queue,
+ (void**)&this->transaction_out) != SUCCESS)
+ {
+ /* transaction queue empty */
+ return SUCCESS;
+ }
+ switch (transmit_request(this))
+ {
+ case SUCCESS:
+ return SUCCESS;
+ case DESTROY_ME:
+ /* critical, IKE_SA unusable, destroy immediately */
+ this->logger->log(this->logger, ERROR,
+ "transaction initiaton failed, deleting IKE_SA");
+ return DESTROY_ME;
+ default:
+ /* discard transaction, process next one */
+ this->logger->log(this->logger, ERROR,
+ "transaction initiation failed, discarded");
+ this->transaction_out->destroy(this->transaction_out);
+ this->transaction_out = NULL;
+ /* handle next transaction */
+ continue;
+ }
+ }
}
/**
- * Implementation of ike_sa_t.retransmit_request.
+ * Queue a new transaction and execute the next outstanding transaction
*/
-static status_t retransmit_request(private_ike_sa_t *this, u_int32_t message_id)
+static status_t queue_transaction(private_ike_sa_t *this, transaction_t *transaction, bool prefer)
{
- packet_t *packet;
-
- if (!this->protected.public.retransmit_possible(&this->protected.public, message_id))
+ /* inject next transaction */
+ if (transaction)
{
- return NOT_FOUND;
+ if (prefer)
+ {
+ this->transaction_queue->insert_first(this->transaction_queue, transaction);
+ }
+ else
+ {
+ this->transaction_queue->insert_last(this->transaction_queue, transaction);
+ }
}
-
- this->logger->log(this->logger, CONTROL | LEVEL1, "going to retransmit message with id %d",message_id);
- packet = this->last_requested_message->get_packet(this->last_requested_message);
- charon->send_queue->add(charon->send_queue, packet);
- this->update_timestamp(this, FALSE);
- return SUCCESS;
+ /* process a transaction */
+ return process_transaction_queue(this);
}
/**
- * Implementation of protected_ike_sa_t.build_transforms.
+ * process an incoming request.
*/
-static status_t build_transforms(private_ike_sa_t *this, proposal_t *proposal, diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r)
+static status_t process_request(private_ike_sa_t *this, message_t *request)
{
- chunk_t nonces, nonces_spis, skeyseed, key, secret;
- u_int64_t spi_i, spi_r;
- prf_plus_t *prf_plus;
- algorithm_t *algo;
- size_t key_size;
+ transaction_t *last, *current = NULL;
+ message_t *response;
+ packet_t *packet;
+ u_int32_t request_mid;
+ status_t status;
- /*
- * Build the PRF+ instance for deriving keys
- */
- if (this->prf != NULL)
+ request_mid = request->get_message_id(request);
+ last = this->transaction_in;
+
+ /* check if message ID is correct */
+ if (last)
{
- this->prf->destroy(this->prf);
+ u_int32_t last_mid = last->get_message_id(last);
+
+ if (last_mid == request_mid)
+ {
+ /* retransmit detected */
+ this->logger->log(this->logger, ERROR,
+ "received retransmitted request for message ID %d, retransmitting response",
+ request_mid);
+ last->get_response(last, request, &response, &this->transaction_in_next);
+ packet = response->get_packet(response);
+ charon->send_queue->add(charon->send_queue, packet);
+ this->time_outbound = time(NULL);
+ return SUCCESS;
+ }
+
+ if (last_mid > request_mid)
+ {
+ /* something seriously wrong here, message id may not decrease */
+ this->logger->log(this->logger, ERROR,
+ "received request with message ID %d, excepted %d, ingored",
+ request_mid, last_mid + 1);
+ return FAILED;
+ }
+ /* we allow jumps in message IDs, as long as they are incremental */
+ if (last_mid + 1 < request_mid)
+ {
+ this->logger->log(this->logger, ERROR,
+ "received request with message ID %d, excepted %d",
+ request_mid, last_mid + 1);
+ }
}
- if (!proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &algo))
+ else
{
- this->logger->log(this->logger, ERROR|LEVEL2, "no PRF algoithm selected!?");
- return FAILED;
+ if (request_mid != 0)
+ {
+ /* warn, but allow it */
+ this->logger->log(this->logger, CONTROL,
+ "first received request has message ID %d, excepted 0",
+ request_mid);
+ }
}
- this->prf = prf_create(algo->algorithm);
- if (this->prf == NULL)
- {
- this->logger->log(this->logger, ERROR|LEVEL1,
- "PSEUDO_RANDOM_FUNCTION %s not supported!",
- mapping_find(pseudo_random_function_m, algo->algorithm));
- return FAILED;
- }
-
- /* concatenate nonces = nonce_i | nonce_r */
- nonces = chunk_alloc(nonce_i.len + nonce_r.len);
- memcpy(nonces.ptr, nonce_i.ptr, nonce_i.len);
- memcpy(nonces.ptr + nonce_i.len, nonce_r.ptr, nonce_r.len);
-
- /* concatenate prf_seed = nonce_i | nonce_r | spi_i | spi_r */
- nonces_spis = chunk_alloc(nonces.len + 16);
- memcpy(nonces_spis.ptr, nonces.ptr, nonces.len);
- spi_i = this->ike_sa_id->get_initiator_spi(this->ike_sa_id);
- spi_r = this->ike_sa_id->get_responder_spi(this->ike_sa_id);
- memcpy(nonces_spis.ptr + nonces.len, &spi_i, 8);
- memcpy(nonces_spis.ptr + nonces.len + 8, &spi_r, 8);
- /* SKEYSEED = prf(Ni | Nr, g^ir) */
- dh->get_shared_secret(dh, &secret);
- this->logger->log_chunk(this->logger, PRIVATE, "shared Diffie-Hellman secret", secret);
- this->prf->set_key(this->prf, nonces);
- this->prf->allocate_bytes(this->prf, secret, &skeyseed);
- this->logger->log_chunk(this->logger, PRIVATE | LEVEL1, "SKEYSEED", skeyseed);
- chunk_free(&secret);
-
- /* prf+ (SKEYSEED, Ni | Nr | SPIi | SPIr )
- * = SK_d | SK_ai | SK_ar | SK_ei | SK_er | SK_pi | SK_pr
- *
- * we use the prf directly for prf+
- */
- this->prf->set_key(this->prf, skeyseed);
- prf_plus = prf_plus_create(this->prf, nonces_spis);
-
- /* clean up unused stuff */
- chunk_free(&nonces);
- chunk_free(&nonces_spis);
- chunk_free(&skeyseed);
-
-
- /*
- * We now can derive all of our key. We build the transforms
- * directly.
- */
-
-
- /* SK_d used for prf+ to derive keys for child SAs */
- this->child_prf = prf_create(algo->algorithm);
- key_size = this->child_prf->get_key_size(this->child_prf);
- prf_plus->allocate_bytes(prf_plus, key_size, &key);
- this->logger->log_chunk(this->logger, PRIVATE, "Sk_d secret", key);
- this->child_prf->set_key(this->child_prf, key);
- chunk_free(&key);
-
-
- /* SK_ai/SK_ar used for integrity protection */
- if (!proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &algo))
- {
- this->logger->log(this->logger, ERROR, "no integrity algoithm selected?!");
- return FAILED;
- }
- if (this->signer_initiator != NULL)
+ /* check if we already have a pre-created transaction for this request */
+ if (this->transaction_in_next)
{
- this->signer_initiator->destroy(this->signer_initiator);
+ u_int32_t trans_mid = this->transaction_in_next->get_message_id(this->transaction_in_next);
+
+ /* check message id consistency */
+ if (trans_mid == request_mid)
+ {
+ /* use it */
+ current = this->transaction_in_next;
+ }
+ else
+ {
+ /* discard queued transaction */
+ this->transaction_in_next->destroy(this->transaction_in_next);
+ }
+ this->transaction_in_next = NULL;
}
- if (this->signer_responder != NULL)
+ /* create new transaction if "next" unusable */
+ if (current == NULL)
{
- this->signer_responder->destroy(this->signer_responder);
+ current = transaction_create(&this->public, request);
+ if (current == NULL)
+ {
+ this->logger->log(this->logger, ERROR,
+ "no idea how to handle received message (%d), ignored",
+ request->get_exchange_type(request));
+ return FAILED;
+ }
}
- this->signer_initiator = signer_create(algo->algorithm);
- this->signer_responder = signer_create(algo->algorithm);
- if (this->signer_initiator == NULL || this->signer_responder == NULL)
+ /* send message. get_request() always gives a valid response */
+ status = current->get_response(current, request, &response, &this->transaction_in_next);
+ if (response->generate(response, this->crypter_out, this->signer_out, &packet) != SUCCESS)
{
this->logger->log(this->logger, ERROR,
- "INTEGRITY_ALGORITHM %s not supported!",
- mapping_find(integrity_algorithm_m,algo->algorithm));
+ "response generation failed, discarding transaction");
+ current->destroy(current);
return FAILED;
}
- key_size = this->signer_initiator->get_key_size(this->signer_initiator);
- prf_plus->allocate_bytes(prf_plus, key_size, &key);
- this->logger->log_chunk(this->logger, CONTROL|LEVEL1, "Sk_ai secret", key);
- this->signer_initiator->set_key(this->signer_initiator, key);
- chunk_free(&key);
+ charon->send_queue->add(charon->send_queue, packet);
+ this->time_outbound = time(NULL);
+ /* act depending on transaction result */
+ switch (status)
+ {
+ case DESTROY_ME:
+ /* transactions says we should destroy the IKE_SA, so do it */
+ current->destroy(current);
+ return DESTROY_ME;
+ default:
+ /* store for retransmission, destroy old transaction */
+ this->transaction_in = current;
+ if (last)
+ {
+ last->destroy(last);
+ }
+ return SUCCESS;
+ }
+}
- prf_plus->allocate_bytes(prf_plus, key_size, &key);
- this->logger->log_chunk(this->logger, CONTROL|LEVEL1, "Sk_ar secret", key);
- this->signer_responder->set_key(this->signer_responder, key);
- chunk_free(&key);
-
+/**
+ * process an incoming response
+ */
+static status_t process_response(private_ike_sa_t *this, message_t *response)
+{
+ transaction_t *current, *new = NULL;
- /* SK_ei/SK_er used for encryption */
- if (!proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &algo))
+ current = this->transaction_out;
+ /* check if message ID is that of our currently active transaction */
+ if (current == NULL ||
+ current->get_message_id(current) !=
+ response->get_message_id(response))
{
- this->logger->log(this->logger, ERROR, "no encryption algoithm selected!?");
+ this->logger->log(this->logger, ERROR,
+ "received response with message ID %d not requested, ignored");
return FAILED;
}
- if (this->crypter_initiator != NULL)
- {
- this->crypter_initiator->destroy(this->crypter_initiator);
- }
- if (this->crypter_responder != NULL)
+
+ switch (current->conclude(current, response, &new))
{
- this->crypter_responder->destroy(this->crypter_responder);
+ case DESTROY_ME:
+ /* state requested to destroy IKE_SA */
+ return DESTROY_ME;
+ default:
+ /* discard transaction, process next one */
+ break;
}
+ /* transaction comleted, remove */
+ current->destroy(current);
+ this->transaction_out = NULL;
- this->crypter_initiator = crypter_create(algo->algorithm, algo->key_size / 8);
- this->crypter_responder = crypter_create(algo->algorithm, algo->key_size / 8);
- if (this->crypter_initiator == NULL || this->crypter_responder == NULL)
+ /* queue new transaction */
+ return queue_transaction(this, new, TRUE);
+}
+
+/**
+ * send a notify back to the sender
+ */
+static void send_notify_response(private_ike_sa_t *this,
+ message_t *request,
+ notify_type_t type)
+{
+ notify_payload_t *notify;
+ message_t *response;
+ host_t *src, *dst;
+ packet_t *packet;
+
+ response = message_create();
+ dst = request->get_source(request);
+ src = request->get_destination(request);
+ response->set_source(response, src->clone(src));
+ response->set_destination(response, dst->clone(dst));
+ response->set_exchange_type(response, request->get_exchange_type(request));
+ response->set_request(response, FALSE);
+ response->set_message_id(response, request->get_message_id(request));
+ response->set_ike_sa_id(response, this->ike_sa_id);
+ notify = notify_payload_create_from_protocol_and_type(PROTO_NONE, type);
+ response->add_payload(response, (payload_t *)notify);
+ if (response->generate(response, this->crypter_out, this->signer_out, &packet) != SUCCESS)
{
- this->logger->log(this->logger, ERROR,
- "ENCRYPTION_ALGORITHM %s (key size %d) not supported!",
- mapping_find(encryption_algorithm_m, algo->algorithm),
- algo->key_size);
- return FAILED;
+ response->destroy(response);
+ return;
}
- key_size = this->crypter_initiator->get_key_size(this->crypter_initiator);
-
- prf_plus->allocate_bytes(prf_plus, key_size, &key);
- this->logger->log_chunk(this->logger, PRIVATE, "Sk_ei secret", key);
- this->crypter_initiator->set_key(this->crypter_initiator, key);
- chunk_free(&key);
+ charon->send_queue->add(charon->send_queue, packet);
+ this->time_outbound = time(NULL);
+ response->destroy(response);
+ return;
+}
+
+
+/**
+ * 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;
- prf_plus->allocate_bytes(prf_plus, key_size, &key);
- this->logger->log_chunk(this->logger, PRIVATE, "Sk_er secret", key);
- this->crypter_responder->set_key(this->crypter_responder, key);
- chunk_free(&key);
+ is_request = message->get_request(message);
- /* SK_pi/SK_pr used for authentication */
- if (this->prf_auth_i != NULL)
+ status = message->parse_body(message, this->crypter_in, this->signer_in);
+ if (status != SUCCESS)
{
- this->prf_auth_i->destroy(this->prf_auth_i);
+ switch (status)
+ {
+ case NOT_SUPPORTED:
+ this->logger->log(this->logger, ERROR,
+ "ciritcal unknown payloads found");
+ if (is_request)
+ {
+ send_notify_response(this, message, UNSUPPORTED_CRITICAL_PAYLOAD);
+ }
+ break;
+ case PARSE_ERROR:
+ this->logger->log(this->logger, ERROR,
+ "message parsing failed");
+ if (is_request)
+ {
+ send_notify_response(this, message, INVALID_SYNTAX);
+ }
+ break;
+ case VERIFY_ERROR:
+ this->logger->log(this->logger, ERROR,
+ "message verification failed");
+ if (is_request)
+ {
+ send_notify_response(this, message, INVALID_SYNTAX);
+ }
+ break;
+ case FAILED:
+ this->logger->log(this->logger, ERROR,
+ "integrity check failed");
+ /* ignored */
+ break;
+ case INVALID_STATE:
+ this->logger->log(this->logger, ERROR,
+ "found encrypted message, but no keys available");
+ if (is_request)
+ {
+ send_notify_response(this, message, INVALID_SYNTAX);
+ }
+ default:
+ break;
+ }
+ this->logger->log(this->logger, ERROR,
+ "%s %s with message ID %d processing failed",
+ mapping_find(exchange_type_m, message->get_exchange_type(message)),
+ message->get_request(message) ? "request" : "response",
+ message->get_message_id(message));
}
- if (this->prf_auth_r != NULL)
+ else
{
- this->prf_auth_r->destroy(this->prf_auth_r);
+ /* check if message is trustworthy, and update connection information */
+ if ((this->state == SA_CREATED && this->connection) ||
+ message->get_exchange_type(message) != IKE_SA_INIT)
+ {
+ update_hosts(this, message->get_destination(message),
+ message->get_source(message));
+ this->time_inbound = time(NULL);
+ }
+ if (is_request)
+ {
+ status = process_request(this, message);
+ }
+ else
+ {
+ status = process_response(this, message);
+ }
}
-
- proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &algo);
- this->prf_auth_i = prf_create(algo->algorithm);
- this->prf_auth_r = prf_create(algo->algorithm);
-
- key_size = this->prf_auth_i->get_key_size(this->prf_auth_i);
- prf_plus->allocate_bytes(prf_plus, key_size, &key);
- this->logger->log_chunk(this->logger, PRIVATE, "Sk_pi secret", key);
- this->prf_auth_i->set_key(this->prf_auth_i, key);
- chunk_free(&key);
-
- prf_plus->allocate_bytes(prf_plus, key_size, &key);
- this->logger->log_chunk(this->logger, PRIVATE, "Sk_pr secret", key);
- this->prf_auth_r->set_key(this->prf_auth_r, key);
- chunk_free(&key);
-
- /* all done, prf_plus not needed anymore */
- prf_plus->destroy(prf_plus);
-
- return SUCCESS;
+ return status;
}
/**
- * Implementation of protected_ike_sa_t.get_randomizer.
+ * Implementation of ike_sa_t.initiate.
*/
-static randomizer_t *get_randomizer(private_ike_sa_t *this)
+static status_t initiate(private_ike_sa_t *this, connection_t *connection)
{
- return this->randomizer;
+ ike_sa_init_t *ike_sa_init;
+
+ /* set connection and policy */
+ this->connection = connection;
+ this->policy = charon->policies->get_policy_by_name(charon->policies,
+ this->connection->get_name(this->connection));
+ if (this->policy == NULL)
+ {
+ this->logger->log(this->logger, ERROR,
+ "no policy found for connection %s, aborting",
+ connection->get_name(connection));
+ return DESTROY_ME;
+ }
+ ike_sa_init = ike_sa_init_create(&this->public, 0);
+ this->message_id_out = 2;
+ return queue_transaction(this, (transaction_t*)ike_sa_init, TRUE);
}
/**
- * Implementation of protected_ike_sa_t.get_crypter_initiator.
+ * Implementation of ike_sa_t.send_dpd
*/
-static crypter_t *get_crypter_initiator(private_ike_sa_t *this)
+static status_t send_dpd(private_ike_sa_t *this)
{
- return this->crypter_initiator;
+ send_dpd_job_t *job;
+ time_t diff, interval;
+ status_t status = SUCCESS;
+
+ interval = charon->configuration->get_dpd_interval(charon->configuration);
+
+ if (this->transaction_out)
+ {
+ /* there is a transaction in progress. Come back later */
+ diff = 0;
+ }
+ else
+ {
+ /* check if there was any inbound traffic */
+ time_t last_in, now;
+ last_in = get_time_inbound(this);
+ now = time(NULL);
+ diff = now - last_in;
+ if (diff >= interval)
+ {
+ /* to long ago, initiate dead peer detection */
+ dead_peer_detection_t *dpd;
+ this->logger->log(this->logger, CONTROL, "sending DPD request");
+ dpd = dead_peer_detection_create(&this->public, this->message_id_out++);
+ status = queue_transaction(this, (transaction_t*)dpd, FALSE);
+ diff = 0;
+ }
+ }
+ /* recheck in "interval" seconds */
+ job = send_dpd_job_create(this->ike_sa_id);
+ charon->event_queue->add_relative(charon->event_queue, (job_t*)job,
+ (interval - diff) * 1000);
+ return SUCCESS;
}
/**
- * Implementation of protected_ike_sa_t.get_signer_initiator.
+ * Implementation of ike_sa_t.send_keepalive
*/
-static signer_t *get_signer_initiator(private_ike_sa_t *this)
+static void send_keepalive(private_ike_sa_t *this)
{
- return this->signer_initiator;
+ send_keepalive_job_t *job;
+ time_t last_out, now, diff, interval;
+
+ last_out = get_time_outbound(this);
+ now = time(NULL);
+
+ diff = now - last_out;
+ interval = charon->configuration->get_keepalive_interval(charon->configuration);
+
+ if (diff >= interval)
+ {
+ host_t *me, *other;
+ packet_t *packet;
+ chunk_t data;
+
+ packet = packet_create();
+ me = this->connection->get_my_host(this->connection);
+ other = this->connection->get_other_host(this->connection);
+ packet->set_source(packet, me->clone(me));
+ packet->set_destination(packet, other->clone(other));
+ data.ptr = malloc(1);
+ data.ptr[0] = 0xFF;
+ data.len = 1;
+ packet->set_data(packet, data);
+ charon->send_queue->add(charon->send_queue, packet);
+ this->logger->log(this->logger, CONTROL, "sending keep alive");
+ diff = 0;
+ }
+ job = send_keepalive_job_create(this->ike_sa_id);
+ charon->event_queue->add_relative(charon->event_queue, (job_t*)job,
+ (interval - diff) * 1000);
}
/**
- * Implementation of protected_ike_sa_t.get_crypter_responder.
+ * Implementation of ike_sa_t.get_state.
*/
-static crypter_t *get_crypter_responder(private_ike_sa_t *this)
+static ike_sa_state_t get_state(private_ike_sa_t *this)
{
- return this->crypter_responder;
+ return this->state;
}
/**
- * Implementation of protected_ike_sa_t.get_signer_responder.
+ * Implementation of ike_sa_t.set_state.
*/
-static signer_t *get_signer_responder(private_ike_sa_t *this)
+static void set_state(private_ike_sa_t *this, ike_sa_state_t state)
{
- return this->signer_responder;
+ this->logger->log(this->logger, CONTROL, "state change: %s => %s",
+ mapping_find(ike_sa_state_m, this->state),
+ mapping_find(ike_sa_state_m, state));
+ if (state == SA_ESTABLISHED)
+ {
+ host_t *my_host, *other_host;
+ identification_t *my_id, *other_id;
+ my_host = this->connection->get_my_host(this->connection);
+ other_host = this->connection->get_other_host(this->connection);
+ my_id = this->policy->get_my_id(this->policy);
+ other_id = this->policy->get_other_id(this->policy);
+ this->logger->log(this->logger, AUDIT, "IKE_SA established: %s[%s]...%s[%s]",
+ my_host->get_address(my_host),
+ my_id->get_string(my_id),
+ other_host->get_address(other_host),
+ other_id->get_string(other_id));
+
+ send_dpd(this);
+ }
+ this->state = state;
}
/**
- * Implementation of protected_ike_sa_t.update_timestamp
+ * Implementation of protected_ike_sa_t.get_connection.
*/
-static void update_timestamp(private_ike_sa_t *this, bool in)
+static connection_t *get_connection(private_ike_sa_t *this)
{
- /* bump last message sent timestamp */
- struct timeval *tv = in ? &this->last_msg_in_tv : &this->last_msg_out_tv;
- if (0 > gettimeofday(tv, NULL))
- {
- this->logger->log(this->logger, ERROR|LEVEL1,
- "warning: failed to get time of day.");
- }
+ return this->connection;
}
/**
- * Implementation of protected_ike_sa_t.send_request.
+ * Implementation of protected_ike_sa_t.set_connection.
*/
-static status_t send_request(private_ike_sa_t *this, message_t *message)
+static void set_connection(private_ike_sa_t *this,connection_t * connection)
{
- retransmit_request_job_t *retransmit_job;
- u_int32_t timeout;
- crypter_t *crypter;
- signer_t *signer;
- packet_t *packet;
- status_t status;
-
- if (message->get_message_id(message) != this->message_id_out)
- {
- this->logger->log(this->logger, ERROR, "message could not be sent cause id (%d) was not as expected (%d)",
- message->get_message_id(message),this->message_id_out);
- return FAILED;
- }
-
- /* generate packet */
- this->logger->log(this->logger, CONTROL|LEVEL2, "generate packet from message");
-
- 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 = message->generate(message, crypter,signer, &packet);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, ERROR, "could not generate packet from message");
- return FAILED;
- }
-
- this->logger->log(this->logger, CONTROL|LEVEL3,
- "add request packet with message id %d to global send queue",
- 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)
- {
- 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;
-
- /* 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!");
- }
- else
- {
- 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 */
- this->logger->log(this->logger, CONTROL|LEVEL3,
- "increase message counter for outgoing messages from %d",
- this->message_id_out);
- this->message_id_out++;
-
- this->update_timestamp(this, FALSE);
- return SUCCESS;
+ this->connection = connection;
}
/**
- * Implementation of protected_ike_sa_t.send_response.
+ * Implementation of protected_ike_sa_t.get_policy.
*/
-static status_t send_response(private_ike_sa_t *this, message_t *message)
+static policy_t *get_policy(private_ike_sa_t *this)
{
- crypter_t *crypter;
- signer_t *signer;
- packet_t *packet;
- status_t status;
-
- if (message->get_message_id(message) != this->message_id_in)
- {
-
- this->logger->log(this->logger, ERROR, "message could not be sent cause id (%d) was not as expected (%d)",
- message->get_message_id(message),this->message_id_in);
- return FAILED;
- }
-
- 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 = message->generate(message, crypter,signer, &packet);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, ERROR, "could not generate packet from message");
- return FAILED;
- }
-
- this->logger->log(this->logger, CONTROL|LEVEL3,
- "add response packet with message id %d to global send queue",
- this->message_id_in);
- charon->send_queue->add(charon->send_queue, packet);
-
- if (this->last_responded_message != NULL)
- {
- /* destroy message */
- this->last_responded_message->destroy(this->last_responded_message);
- }
-
- this->logger->log(this->logger, CONTROL|LEVEL3, "replace last responded message with new one");
- this->last_responded_message = message;
-
- /* message counter can now be increased */
- this->logger->log(this->logger, CONTROL|LEVEL3, "increase message counter for incoming messages");
- this->message_id_in++;
-
- this->update_timestamp(this, FALSE);
-
- return SUCCESS;
+ return this->policy;
}
/**
- * Implementation of of private_responder_init_t.send_notify_reply.
+ * Implementation of protected_ike_sa_t.set_policy.
*/
-static void send_notify(private_ike_sa_t *this, exchange_type_t exchange_type, notify_message_type_t type, chunk_t data)
+static void set_policy(private_ike_sa_t *this,policy_t * policy)
{
- notify_payload_t *payload;
- message_t *response;
- packet_t *packet;
- status_t status;
-
- this->logger->log(this->logger, CONTROL|LEVEL2, "going to build message with notify payload");
- /* set up the reply */
- build_message(this, exchange_type, FALSE, &response);
- payload = notify_payload_create_from_protocol_and_type(PROTO_NONE, type);
- if ((data.ptr != NULL) && (data.len > 0))
- {
- this->logger->log(this->logger, CONTROL|LEVEL2, "add Data to notify payload");
- payload->set_notification_data(payload,data);
- }
-
- this->logger->log(this->logger, CONTROL|LEVEL2, "add Notify payload to message");
- response->add_payload(response,(payload_t *) payload);
-
- /* generate packet */
- this->logger->log(this->logger, CONTROL|LEVEL2, "generate packet from message");
- status = response->generate(response, this->crypter_responder, this->signer_responder, &packet);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, ERROR|LEVEL1, "could not generate notify message");
- response->destroy(response);
- return;
- }
-
- this->logger->log(this->logger, CONTROL|LEVEL2, "add packet to global send queue");
- charon->send_queue->add(charon->send_queue, packet);
- this->logger->log(this->logger, CONTROL|LEVEL2, "destroy message");
- response->destroy(response);
-
- this->update_timestamp(this, FALSE);
+ this->policy = policy;
}
/**
- * Implementation of protected_ike_sa_t.set_last_replied_message_id.
+ * Implementation of protected_ike_sa_t.get_prf.
*/
-static void set_last_replied_message_id (private_ike_sa_t *this,u_int32_t message_id)
+static prf_t *get_prf(private_ike_sa_t *this)
{
- this->last_replied_message_id = message_id;
+ return this->prf;
}
/**
- * Implementation of protected_ike_sa_t.get_last_responded_message.
+ * Implementation of protected_ike_sa_t.get_prf.
*/
-static message_t *get_last_responded_message (private_ike_sa_t *this)
+static prf_t *get_child_prf(private_ike_sa_t *this)
{
- return this->last_responded_message;
+ return this->child_prf;
}
/**
- * Implementation of protected_ike_sa_t.get_last_requested_message.
+ * Implementation of protected_ike_sa_t.get_prf_auth_i.
*/
-static message_t *get_last_requested_message(private_ike_sa_t *this)
+static prf_t *get_prf_auth_i(private_ike_sa_t *this)
{
- return this->last_requested_message;
+ return this->prf_auth_i;
}
/**
- * Implementation of protected_ike_sa_t.add_child_sa.
+ * Implementation of protected_ike_sa_t.get_prf_auth_r.
*/
-static void add_child_sa(private_ike_sa_t *this, child_sa_t *child_sa)
+static prf_t *get_prf_auth_r(private_ike_sa_t *this)
{
- this->child_sas->insert_last(this->child_sas, child_sa);
+ return this->prf_auth_r;
+}
+/**
+ * Implementation of ike_sa_t.get_id.
+ */
+static ike_sa_id_t* get_id(private_ike_sa_t *this)
+{
+ return this->ike_sa_id;
}
/**
- * Implementation of ike_sa_t.process_message.
+ * Implementation of protected_ike_sa_t.build_transforms.
*/
-static status_t process_message(private_ike_sa_t *this, message_t *message)
+static status_t build_transforms(private_ike_sa_t *this, proposal_t *proposal,
+ diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r,
+ bool initiator)
{
- u_int32_t message_id;
- exchange_type_t exchange_type;
- bool is_request;
-
- /* 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);
-
- /* check if message already received, and retransmit its reply */
- if (is_request && (message_id == (this->message_id_in - 1)))
- {
- /* 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);
- this->update_timestamp(this, FALSE);
- return SUCCESS;
- }
- else
- {
- /* somebody does something nasty here... */
- return FAILED;
- }
- }
+ chunk_t nonces, nonces_spis, skeyseed, key, secret;
+ u_int64_t spi_i, spi_r;
+ prf_plus_t *prf_plus;
+ algorithm_t *algo;
+ size_t key_size;
+ crypter_t *crypter_i, *crypter_r;
+ signer_t *signer_i, *signer_r;
- /* Now, the message id is checked for request AND reply */
- if (is_request)
+ /* Build the PRF+ instance for deriving keys */
+ if (!proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &algo))
{
- /* In a request, the message has to be this->message_id_in (other case is already handled) */
- if (message_id != this->message_id_in)
- {
- this->logger->log(this->logger, ERROR | LEVEL1,
- "message request with message id %d received, but %d expected",
- message_id,this->message_id_in);
- return FAILED;
- }
+ this->logger->log(this->logger, ERROR, "no PSEUDO_RANDOM_FUNCTION selected!");
+ return FAILED;
}
- else
+ this->prf = prf_create(algo->algorithm);
+ if (this->prf == NULL)
{
- /* In a reply, the message has to be this->message_id_out -1 cause it is the reply to the last sent message*/
- if (message_id != (this->message_id_out - 1))
- {
- this->logger->log(this->logger, ERROR | LEVEL1,
- "message reply with message id %d received, but %d expected",
- message_id,this->message_id_in);
- return FAILED;
- }
+ this->logger->log(this->logger, ERROR, "PSEUDO_RANDOM_FUNCTION %s not supported!",
+ mapping_find(pseudo_random_function_m, algo->algorithm));
+ return FAILED;
}
- this->update_timestamp(this, TRUE);
-
- /* now the message is processed by the current state object.
- * 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
- */
- return this->current_state->process_message(this->current_state, message);
-}
+ /* nonces = nonce_i | nonce_r */
+ nonces = chunk_alloc(nonce_i.len + nonce_r.len);
+ memcpy(nonces.ptr, nonce_i.ptr, nonce_i.len);
+ memcpy(nonces.ptr + nonce_i.len, nonce_r.ptr, nonce_r.len);
-/**
- * Implementation of protected_ike_sa_t.initiate_connection.
- */
-static status_t initiate_connection(private_ike_sa_t *this, connection_t *connection)
-{
- initiator_init_t *current_state;
+ /* prf_seed = nonce_i | nonce_r | spi_i | spi_r */
+ nonces_spis = chunk_alloc(nonces.len + 16);
+ memcpy(nonces_spis.ptr, nonces.ptr, nonces.len);
+ spi_i = this->ike_sa_id->get_initiator_spi(this->ike_sa_id);
+ spi_r = this->ike_sa_id->get_responder_spi(this->ike_sa_id);
+ memcpy(nonces_spis.ptr + nonces.len, &spi_i, 8);
+ memcpy(nonces_spis.ptr + nonces.len + 8, &spi_r, 8);
+
+ /* SKEYSEED = prf(Ni | Nr, g^ir) */
+ dh->get_shared_secret(dh, &secret);
+ this->logger->log_chunk(this->logger, PRIVATE, "shared Diffie Hellman secret", secret);
+ this->prf->set_key(this->prf, nonces);
+ this->prf->allocate_bytes(this->prf, secret, &skeyseed);
+ this->logger->log_chunk(this->logger, PRIVATE|LEVEL1, "SKEYSEED", skeyseed);
+ chunk_free(&secret);
- /* Work is done in state object of type INITIATOR_INIT. All other states are not
- * initial states and so don't have a initiate_connection function */
+ /* prf+ (SKEYSEED, Ni | Nr | SPIi | SPIr )
+ * = SK_d | SK_ai | SK_ar | SK_ei | SK_er | SK_pi | SK_pr
+ */
+ this->prf->set_key(this->prf, skeyseed);
+ prf_plus = prf_plus_create(this->prf, nonces_spis);
- if (this->current_state->get_state(this->current_state) != INITIATOR_INIT)
+ /* clean up unused stuff */
+ chunk_free(&nonces);
+ chunk_free(&nonces_spis);
+ chunk_free(&skeyseed);
+
+ /* SK_d used for prf+ to derive keys for child SAs */
+ this->child_prf = prf_create(algo->algorithm);
+ key_size = this->child_prf->get_key_size(this->child_prf);
+ prf_plus->allocate_bytes(prf_plus, key_size, &key);
+ this->logger->log_chunk(this->logger, PRIVATE, "Sk_d secret", key);
+ this->child_prf->set_key(this->child_prf, key);
+ chunk_free(&key);
+
+ /* SK_ai/SK_ar used for integrity protection */
+ if (!proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &algo))
{
+ this->logger->log(this->logger, ERROR, "no INTEGRITY_ALGORITHM selected?!");
return FAILED;
}
- current_state = (initiator_init_t *) this->current_state;
-
- return current_state->initiate_connection(current_state, connection);
-}
-
-/**
- * Implementation of protected_ike_sa_t.update_connection_hosts.
- *
- * Quoting RFC 4306:
- *
- * 2.11. Address and Port Agility
- *
- * IKE runs over UDP ports 500 and 4500, and implicitly sets up ESP and
- * AH associations for the same IP addresses it runs over. The IP
- * addresses and ports in the outer header are, however, not themselves
- * cryptographically protected, and IKE is designed to work even through
- * Network Address Translation (NAT) boxes. An implementation MUST
- * accept incoming requests even if the source port is not 500 or 4500,
- * and MUST respond to the address and port from which the request was
- * received. It MUST specify the address and port at which the request
- * was received as the source address and port in the response. IKE
- * functions identically over IPv4 or IPv6.
- *
- * [...]
- *
- * There are cases where a NAT box decides to remove mappings that
- * are still alive (for example, the keepalive interval is too long,
- * or the NAT box is rebooted). To recover in these cases, hosts
- * that are not behind a NAT SHOULD send all packets (including
- * retransmission packets) to the IP address and port from the last
- * valid authenticated packet from the other end (i.e., dynamically
- * update the address). A host behind a NAT SHOULD NOT do this
- * because it opens a DoS attack possibility. Any authenticated IKE
- * packet or any authenticated UDP-encapsulated ESP packet can be
- * used to detect that the IP address or the port has changed.
- */
-static status_t update_connection_hosts(private_ike_sa_t *this, host_t *me, host_t *other)
-{
- host_t *old_other = NULL;
- iterator_t *iterator = NULL;
- child_sa_t *child_sa = NULL;
- int my_changes, other_changes;
- ike_sa_state_t s;
-
- my_changes = me->get_differences(me, this->connection->get_my_host(this->connection));
-
- old_other = this->connection->get_other_host(this->connection);
- other_changes = other->get_differences(other, old_other);
-
- if (!my_changes && !other_changes) {
- return SUCCESS;
- }
-
- if (my_changes)
+ signer_i = signer_create(algo->algorithm);
+ signer_r = signer_create(algo->algorithm);
+ if (signer_i == NULL || signer_r == NULL)
{
- this->connection->update_my_host(this->connection, me->clone(me));
+ this->logger->log(this->logger, ERROR, "INTEGRITY_ALGORITHM %s not supported!",
+ mapping_find(integrity_algorithm_m,algo->algorithm));
+ return FAILED;
}
+ key_size = signer_i->get_key_size(signer_i);
+
+ prf_plus->allocate_bytes(prf_plus, key_size, &key);
+ this->logger->log_chunk(this->logger, CONTROL|LEVEL1, "Sk_ai secret", key);
+ signer_i->set_key(signer_i, key);
+ chunk_free(&key);
- s = this->protected.public.get_state(&this->protected.public);
+ prf_plus->allocate_bytes(prf_plus, key_size, &key);
+ this->logger->log_chunk(this->logger, CONTROL|LEVEL1, "Sk_ar secret", key);
+ signer_r->set_key(signer_r, key);
+ chunk_free(&key);
- if (s == RESPONDER_INIT || s == IKE_SA_INIT_REQUESTED || !this->nat_here)
+ if (initiator)
{
- if (other_changes)
- {
- this->connection->update_other_host(this->connection, other->clone(other));
- }
+ this->signer_in = signer_i;
+ this->signer_out = signer_r;
}
else
{
- if (other_changes & HOST_DIFF_ADDR)
- {
- this->logger->log(this->logger, ERROR|LEVEL1,
- "destination ip changed from %s to %s. As we are NATed this is not allowed!",
- old_other->get_address(old_other), other->get_address(other));
- return DESTROY_ME;
- }
- else if (other_changes & HOST_DIFF_PORT)
- {
- old_other->set_port(old_other, other->get_port(other));
- }
+ this->signer_in = signer_r;
+ this->signer_out = signer_i;
}
-
- iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
- while (iterator->iterate(iterator, (void**)&child_sa))
+
+ /* SK_ei/SK_er used for encryption */
+ if (!proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &algo))
{
- child_sa->update_hosts(child_sa,
- this->connection->get_my_host(this->connection),
- this->connection->get_other_host(this->connection),
- my_changes, other_changes);
- /* XXX error handling */
+ this->logger->log(this->logger, ERROR, "no ENCRYPTION_ALGORITHM selected!");
+ return FAILED;
+ }
+ crypter_i = crypter_create(algo->algorithm, algo->key_size / 8);
+ crypter_r = crypter_create(algo->algorithm, algo->key_size / 8);
+ if (crypter_i == NULL || crypter_r == NULL)
+ {
+ this->logger->log(this->logger, ERROR,
+ "ENCRYPTION_ALGORITHM %s (key size %d) not supported!",
+ mapping_find(encryption_algorithm_m, algo->algorithm),
+ algo->key_size);
+ return FAILED;
}
- iterator->destroy(iterator);
+ key_size = crypter_i->get_key_size(crypter_i);
- return SUCCESS;
-}
-
-/**
- * Implementation of protected_ike_sa_t.build_transforms.
- * TODO: IPv6 support.
- */
-static chunk_t generate_natd_hash(private_ike_sa_t *this, u_int64_t spi_i, u_int64_t spi_r, host_t *host)
-{
- chunk_t natd_string;
- chunk_t natd_hash;
- void *p;
- struct sockaddr_in* sai;
- char buf[512];
-
- natd_hash = chunk_alloc(this->nat_hasher->get_hash_size(this->nat_hasher));
- natd_string = chunk_alloc(8 + 8 + 4 + 2);
-
- sai = (struct sockaddr_in*)host->get_sockaddr(host);
- p = natd_string.ptr;
- *(u_int64_t*)p = spi_i; p += sizeof(spi_i);
- *(u_int64_t*)p = spi_r; p += sizeof(spi_r);
- *(u_int32_t*)p = sai->sin_addr.s_addr; p += sizeof(sai->sin_addr.s_addr);
- *(u_int16_t*)p = sai->sin_port; p += sizeof(sai->sin_port);
-
- this->nat_hasher->get_hash(this->nat_hasher, natd_string, natd_hash.ptr);
- this->nat_hasher->reset(this->nat_hasher);
-
- sprintf(buf, "natd_hash(%016llx %016llx %s:%d)\n == SHA1(", spi_i, spi_r,
- host->get_address(host), host->get_port(host));
- chunk_to_hex(buf + strlen(buf), sizeof(buf) - strlen(buf), natd_string);
- strcat(buf, ") == ");
- chunk_to_hex(buf + strlen(buf), sizeof(buf) - strlen(buf), natd_hash);
- this->logger->log(this->logger, CONTROL|LEVEL3, buf);
-
- chunk_free(&natd_string);
- return natd_hash;
-}
-
-/**
- * Implementation of ike_sa_t.send_dpd_request.
- */
-static status_t send_dpd_request(private_ike_sa_t *this)
-{
- message_t *dpd_msg;
- status_t status;
- this->protected.build_message(&this->protected, INFORMATIONAL, TRUE, &dpd_msg);
- status = this->protected.send_request(&this->protected, dpd_msg);
- if (status != SUCCESS)
+ prf_plus->allocate_bytes(prf_plus, key_size, &key);
+ this->logger->log_chunk(this->logger, PRIVATE, "Sk_ei secret", key);
+ crypter_i->set_key(crypter_i, key);
+ chunk_free(&key);
+
+ prf_plus->allocate_bytes(prf_plus, key_size, &key);
+ this->logger->log_chunk(this->logger, PRIVATE, "Sk_er secret", key);
+ crypter_r->set_key(crypter_r, key);
+ chunk_free(&key);
+
+ if (initiator)
{
- dpd_msg->destroy(dpd_msg);
+ this->crypter_in = crypter_i;
+ this->crypter_out = crypter_r;
}
- this->last_dpd_message_id = dpd_msg->get_message_id(dpd_msg);
- return status;
-}
-
-/**
- * Implementation of ike_sa_t.get_last_dpd_message_id
- */
-static u_int32_t get_last_dpd_message_id(private_ike_sa_t *this)
-{
- return this->last_dpd_message_id;
+ else
+ {
+ this->crypter_in = crypter_r;
+ this->crypter_out = crypter_i;
+ }
+
+ /* SK_pi/SK_pr used for authentication */
+ proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &algo);
+ this->prf_auth_i = prf_create(algo->algorithm);
+ this->prf_auth_r = prf_create(algo->algorithm);
+
+ key_size = this->prf_auth_i->get_key_size(this->prf_auth_i);
+ prf_plus->allocate_bytes(prf_plus, key_size, &key);
+ this->logger->log_chunk(this->logger, PRIVATE, "Sk_pi secret", key);
+ this->prf_auth_i->set_key(this->prf_auth_i, key);
+ chunk_free(&key);
+
+ prf_plus->allocate_bytes(prf_plus, key_size, &key);
+ this->logger->log_chunk(this->logger, PRIVATE, "Sk_pr secret", key);
+ this->prf_auth_r->set_key(this->prf_auth_r, key);
+ chunk_free(&key);
+
+ /* all done, prf_plus not needed anymore */
+ prf_plus->destroy(prf_plus);
+
+ return SUCCESS;
}
/**
- * Implementation of ike_sa_t.get_child_sa.
+ * Implementation of protected_ike_sa_t.add_child_sa.
*/
-static child_sa_t *get_child_sa(private_ike_sa_t *this, u_int32_t reqid)
+static void add_child_sa(private_ike_sa_t *this, child_sa_t *child_sa)
{
- iterator_t *iterator;
- child_sa_t *current, *found = NULL;
-
- iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
- while (iterator->has_next(iterator))
- {
- iterator->current(iterator, (void**)¤t);
- if (current->get_reqid(current) == reqid)
- {
- found = current;
- break;
- }
- }
- iterator->destroy(iterator);
- return found;
+ this->child_sas->insert_last(this->child_sas, child_sa);
}
/**
* Implementation of ike_sa_t.delete_child_sa.
*/
-static status_t delete_child_sa(private_ike_sa_t *this, u_int32_t reqid)
+static status_t delete_child_sa(private_ike_sa_t *this, u_int32_t spi)
{
- message_t *request;
- child_sa_t *child_sa;
- delete_payload_t *delete_payload;
- state_t *old_state;
-
- if (this->current_state->get_state(this->current_state) != IKE_SA_ESTABLISHED)
- {
- this->logger->log(this->logger, ERROR|LEVEL1,
- "delete of a CHILD_SA whose IKE_SA not in state IKE_SA_ESTABLISHED, aborting");
- return FAILED;
- }
-
- child_sa = get_child_sa(this, reqid);
- if (child_sa == NULL)
- {
- this->logger->log(this->logger, ERROR|LEVEL1,
- "IKE_SA does not contain a CHILD_SA with reqid %d", reqid);
- return FAILED;
- }
- build_message(this, INFORMATIONAL, TRUE, &request);
- delete_payload = delete_payload_create(child_sa->get_protocol(child_sa));
- delete_payload->add_spi(delete_payload, child_sa->get_spi(child_sa, TRUE));
- request->add_payload(request, (payload_t*)delete_payload);
-
- send_request(this, request);
-
- old_state = this->current_state;
- set_new_state(this, (state_t*)delete_child_sa_requested_create(&this->protected));
- old_state->destroy(old_state);
+ /* TODO: Reimplement */
+// message_t *request;
+// child_sa_t *child_sa;
+// delete_payload_t *delete_payload;
+//
+// if (this->current_state->get_state(this->current_state) != IKE_SA_ESTABLISHED)
+// {
+// this->logger->log(this->logger, ERROR|LEVEL1,
+// "Delete of a CHILD_SA whose IKE_SA not in state IKE_SA_ESTABLISHED, aborting");
+// return FAILED;
+// }
+//
+// child_sa = get_child_sa(this, reqid);
+// if (child_sa == NULL)
+// {
+// this->logger->log(this->logger, ERROR|LEVEL1,
+// "IKE_SA does not contain a CHILD_SA with reqid %d", reqid);
+// return FAILED;
+// }
+// build_message(this, INFORMATIONAL, TRUE, &request);
+// delete_payload = delete_payload_create(child_sa->get_protocol(child_sa));
+// delete_payload->add_spi(delete_payload, child_sa->get_spi(child_sa, TRUE));
+// request->add_payload(request, (payload_t*)delete_payload);
+//
+// send_request(this, request);
+//
+// old_state = this->current_state;
+// set_new_state(this, (state_t*)delete_child_sa_requested_create(&this->protected));
+// old_state->destroy(old_state);
return SUCCESS;
}
/**
* Implementation of protected_ike_sa_t.get_child_sa.
*/
-static child_sa_t* get_child_sa_by_spi(private_ike_sa_t *this, u_int32_t spi)
+static child_sa_t* get_child_sa(private_ike_sa_t *this, u_int32_t spi)
{
iterator_t *iterator;
child_sa_t *current, *found = NULL;
/**
* Implementation of ike_sa_t.rekey_child_sa.
*/
-static status_t rekey_child_sa(private_ike_sa_t *this, u_int32_t reqid)
+static status_t rekey_child_sa(private_ike_sa_t *this, u_int32_t spi)
{
+/* TODO reimplement
message_t *request;
child_sa_t *child_sa;
notify_payload_t *notify;
linked_list_t *proposals;
chunk_t nonce;
linked_list_t *my_ts, *other_ts;
- state_t *old_state;
if (this->current_state->get_state(this->current_state) != IKE_SA_ESTABLISHED)
{
old_state = this->current_state;
set_new_state(this, (state_t*)create_child_sa_requested_create(&this->protected, child_sa, nonce, reqid));
- old_state->destroy(old_state);
+ old_state->destroy(old_state);*/
return SUCCESS;
}
-/**
- * Implementation of protected_ike_sa_t.establish.
- */
-static void establish(private_ike_sa_t *this)
-{
- protected_ike_sa_t *ike_sa = (protected_ike_sa_t *)this;
-
- connection_t *connection = ike_sa->get_connection(ike_sa);
- host_t *my_host = connection->get_my_host(connection);
- host_t *other_host = connection->get_other_host(connection);
- policy_t *policy = ike_sa->get_policy(ike_sa);
- identification_t *my_id = policy->get_my_id(policy);
- identification_t *other_id = policy->get_other_id(policy);
-
- ike_sa->set_new_state(ike_sa, (state_t*)ike_sa_established_create(ike_sa));
-
- this->logger->log(this->logger, AUDIT, "IKE_SA established %s[%s]...%s[%s]",
- my_host->get_address(my_host),
- my_id->get_string(my_id),
- other_host->get_address(other_host),
- other_id->get_string(other_id));
-}
-
-/**
- * Implementation of protected_ike_sa_t.reset_message_buffers.
- */
-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 */
- if (this->last_requested_message != NULL)
- {
- this->last_requested_message->destroy(this->last_requested_message);
- this->last_requested_message = NULL;
- }
-
- /* destroy stored responded messages */
- if (this->last_responded_message != NULL)
- {
- this->last_responded_message->destroy(this->last_responded_message);
- this->last_responded_message = NULL;
- }
-
- this->message_id_out = 0;
- this->message_id_in = 0;
- this->last_replied_message_id = -1;
-}
/**
* Implementation of protected_ike_sa_t.log_status.
}
logger->log(logger, CONTROL|LEVEL1, " \"%s\": IKE_SA in state %s, SPIs: 0x%.16llx 0x%.16llx",
name,
- mapping_find(ike_sa_state_m, this->current_state->get_state(this->current_state)),
+ mapping_find(ike_sa_state_m, this->state),
this->ike_sa_id->get_initiator_spi(this->ike_sa_id),
this->ike_sa_id->get_responder_spi(this->ike_sa_id));
logger->log(logger, CONTROL, " \"%s\": %s[%s]...%s[%s]",
*/
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;
- state_t *old_state;
-
- if (get_state(this) != IKE_SA_ESTABLISHED)
- {
- 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(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_ike_sa_requested */
- old_state = this->current_state;
- set_new_state(this, (state_t*)delete_ike_sa_requested_create(&this->protected));
- old_state->destroy(old_state);
+ delete_ike_sa_t *delete_ike_sa;
+ delete_ike_sa = delete_ike_sa_create(&this->public, this->message_id_out++);
- /* 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 ike_sa_t.is_my_host_behind_nat.
- */
-static bool is_my_host_behind_nat (private_ike_sa_t *this)
-{
- return this->nat_here;
-}
-
-/**
- * Implementation of ike_sa_t.is_other_host_behind_nat.
- */
-static bool is_other_host_behind_nat (private_ike_sa_t *this)
-{
- return this->nat_there;
+ return queue_transaction(this, (transaction_t*)delete_ike_sa, FALSE);
}
/**
- * Implementation of ike_sa_t.is_any_host_behind_nat.
+ * Implementation of ike_sa_t.is_natt_enabled.
*/
-static bool is_any_host_behind_nat (private_ike_sa_t *this)
+static bool is_natt_enabled (private_ike_sa_t *this)
{
return this->nat_here || this->nat_there;
}
/**
- * Implementation of protected_ike_sa_t.set_my_host_behind_nat.
- */
-static void set_my_host_behind_nat (private_ike_sa_t *this, bool nat)
-{
- this->nat_here = nat;
-}
-
-/**
- * Implementation of protected_ike_sa_t.set_other_host_behind_nat.
- */
-static void set_other_host_behind_nat (private_ike_sa_t *this, bool nat)
-{
- this->nat_there = nat;
-}
-
-/**
- * Implementation of private_ike_sa_t.get_last_esp_traffic_tv
+ * Implementation of protected_ike_sa_t.enable_natt.
*/
-static struct timeval get_last_esp_traffic_tv(private_ike_sa_t * this, bool inbound)
+static void enable_natt (private_ike_sa_t *this, bool local)
{
- iterator_t *iterator;
- child_sa_t *child_sa;
- bool ret = TRUE;
- time_t use_time = 0;
- struct timeval tv = {0, 0};
-
- iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
- while (iterator->iterate(iterator, (void**)&child_sa))
+ if (local)
{
- if (child_sa->get_use_time(child_sa, inbound, &use_time) == SUCCESS
- && use_time != 0)
- {
- tv.tv_sec = max(tv.tv_sec, use_time);
- }
+ this->logger->log(this->logger, CONTROL,
+ "local host is behind NAT, using NAT-T, scheduled keep alives");
+ this->nat_here = TRUE;
+ send_keepalive(this);
+ }
+ else
+ {
+ this->logger->log(this->logger, CONTROL,
+ "remote host is behind NAT, using NAT-T");
+ this->nat_there = TRUE;
}
- iterator->destroy(iterator);
-
- return tv;
-}
-
-/**
- * Implementation of ike_sa_t.get_last_traffic_in_tv.
- */
-static struct timeval get_last_traffic_in_tv (private_ike_sa_t *this)
-{
- struct timeval esp_tv = this->get_last_esp_traffic_tv(this, TRUE);
- return this->last_msg_in_tv.tv_sec > esp_tv.tv_sec ? this->last_msg_in_tv
- : this->last_msg_in_tv.tv_sec < esp_tv.tv_sec ? esp_tv
- : this->last_msg_in_tv.tv_usec > esp_tv.tv_usec ? this->last_msg_in_tv : esp_tv;
-}
-
-/**
- * Implementation of ike_sa_t.get_last_traffic_out_tv.
- */
-static struct timeval get_last_traffic_out_tv (private_ike_sa_t *this)
-{
- struct timeval esp_tv = this->get_last_esp_traffic_tv(this, FALSE);
- return this->last_msg_out_tv.tv_sec > esp_tv.tv_sec ? this->last_msg_out_tv
- : this->last_msg_out_tv.tv_sec < esp_tv.tv_sec ? esp_tv
- : this->last_msg_out_tv.tv_usec > esp_tv.tv_usec ? this->last_msg_out_tv : esp_tv;
}
/**
static void destroy(private_ike_sa_t *this)
{
child_sa_t *child_sa;
+ transaction_t *transaction;
this->logger->log(this->logger, CONTROL|LEVEL2, "going to destroy IKE SA %llu:%llu, role %s",
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)
+ if (this->state == SA_ESTABLISHED)
{
- this->logger->log(this->logger, ERROR, "destroying an established IKE SA without knowledge from remote peer!");
+ this->logger->log(this->logger, ERROR,
+ "destroying an established IKE SA without knowledge from remote peer!");
}
while (this->child_sas->remove_last(this->child_sas, (void**)&child_sa) == SUCCESS)
}
this->child_sas->destroy(this->child_sas);
- if (this->crypter_initiator)
+ while (this->transaction_queue->remove_last(this->transaction_queue, (void**)&transaction) == SUCCESS)
+ {
+ transaction->destroy(transaction);
+ }
+ this->transaction_queue->destroy(this->transaction_queue);
+ if (this->transaction_in)
+ {
+ this->transaction_in->destroy(this->transaction_in);
+ }
+ if (this->transaction_in_next)
+ {
+ this->transaction_in_next->destroy(this->transaction_in_next);
+ }
+ if (this->transaction_out)
+ {
+ this->transaction_out->destroy(this->transaction_out);
+ }
+ if (this->crypter_in)
{
- this->crypter_initiator->destroy(this->crypter_initiator);
+ this->crypter_in->destroy(this->crypter_in);
}
- if (this->crypter_responder)
+ if (this->crypter_out)
{
- this->crypter_responder->destroy(this->crypter_responder);
+ this->crypter_out->destroy(this->crypter_out);
}
- if (this->signer_initiator)
+ if (this->signer_in)
{
- this->signer_initiator->destroy(this->signer_initiator);
+ this->signer_in->destroy(this->signer_in);
}
- if (this->signer_responder)
+ if (this->signer_out)
{
- this->signer_responder->destroy(this->signer_responder);
+ this->signer_out->destroy(this->signer_out);
}
if (this->prf)
{
{
this->policy->destroy(this->policy);
}
- if (this->last_requested_message)
- {
- this->last_requested_message->destroy(this->last_requested_message);
- }
- if (this->last_responded_message)
- {
- this->last_responded_message->destroy(this->last_responded_message);
- }
- this->nat_hasher->destroy(this->nat_hasher);
this->ike_sa_id->destroy(this->ike_sa_id);
- this->randomizer->destroy(this->randomizer);
- this->current_state->destroy(this->current_state);
free(this);
}
private_ike_sa_t *this = malloc_thing(private_ike_sa_t);
/* Public functions */
- this->protected.public.process_message = (status_t (*) (ike_sa_t*,message_t*)) process_message;
- this->protected.public.initiate_connection = (status_t (*) (ike_sa_t*,connection_t*)) initiate_connection;
- this->protected.public.delete_child_sa = (status_t (*) (ike_sa_t*,u_int32_t)) delete_child_sa;
- this->protected.public.rekey_child_sa = (status_t (*) (ike_sa_t*,u_int32_t)) rekey_child_sa;
- this->protected.public.get_child_sa = (child_sa_t* (*) (ike_sa_t*,u_int32_t))get_child_sa;
- this->protected.public.get_id = (ike_sa_id_t* (*) (ike_sa_t*)) get_id;
- this->protected.public.get_my_host = (host_t* (*) (ike_sa_t*)) get_my_host;
- this->protected.public.get_other_host = (host_t* (*) (ike_sa_t*)) get_other_host;
- this->protected.public.get_my_id = (identification_t* (*) (ike_sa_t*)) get_my_id;
- this->protected.public.get_other_id = (identification_t* (*) (ike_sa_t*)) get_other_id;
- this->protected.public.get_connection = (connection_t* (*) (ike_sa_t*)) get_connection;
- this->protected.public.retransmit_possible = (bool (*) (ike_sa_t*,u_int32_t)) retransmit_possible;
- 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*)) get_state;
- 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;
- this->protected.public.is_my_host_behind_nat = (bool (*) (ike_sa_t*)) is_my_host_behind_nat;
- this->protected.public.is_other_host_behind_nat = (bool (*) (ike_sa_t*)) is_other_host_behind_nat;
- this->protected.public.is_any_host_behind_nat = (bool (*) (ike_sa_t*)) is_any_host_behind_nat;
- this->protected.public.get_last_traffic_in_tv = (struct timeval (*) (ike_sa_t*)) get_last_traffic_in_tv;
- this->protected.public.get_last_traffic_out_tv = (struct timeval (*) (ike_sa_t*)) get_last_traffic_out_tv;
- this->protected.public.send_dpd_request = (status_t (*) (ike_sa_t*)) send_dpd_request;
-
- /* protected functions */
- this->protected.build_message = (void (*) (protected_ike_sa_t*,exchange_type_t,bool,message_t**)) build_message;
- this->protected.get_prf = (prf_t *(*) (protected_ike_sa_t*)) get_prf;
- this->protected.get_child_prf = (prf_t* (*) (protected_ike_sa_t*)) get_child_prf;
- this->protected.get_prf_auth_i = (prf_t* (*) (protected_ike_sa_t*)) get_prf_auth_i;
- this->protected.get_prf_auth_r = (prf_t* (*) (protected_ike_sa_t*)) get_prf_auth_r;
- this->protected.add_child_sa = (void (*) (protected_ike_sa_t*,child_sa_t*)) add_child_sa;
- this->protected.establish = (void (*) (protected_ike_sa_t*)) establish;
- this->protected.set_connection = (void (*) (protected_ike_sa_t*,connection_t*)) set_connection;
- this->protected.get_connection = (connection_t* (*) (protected_ike_sa_t*)) get_connection;
- this->protected.set_policy = (void (*) (protected_ike_sa_t *,policy_t*)) set_policy;
- this->protected.get_policy = (policy_t* (*) (protected_ike_sa_t*)) get_policy;
- this->protected.get_randomizer = (randomizer_t* (*) (protected_ike_sa_t*)) get_randomizer;
- this->protected.send_request = (status_t (*) (protected_ike_sa_t*,message_t*)) send_request;
- this->protected.send_response = (status_t (*) (protected_ike_sa_t*,message_t*)) send_response;
- this->protected.send_notify = (void (*) (protected_ike_sa_t*,exchange_type_t,notify_message_type_t,chunk_t)) send_notify;
- this->protected.build_transforms = (status_t (*) (protected_ike_sa_t*,proposal_t*,diffie_hellman_t*,chunk_t,chunk_t)) build_transforms;
- this->protected.set_new_state = (void (*) (protected_ike_sa_t*,state_t*)) set_new_state;
- this->protected.get_crypter_initiator = (crypter_t* (*) (protected_ike_sa_t*)) get_crypter_initiator;
- this->protected.get_signer_initiator = (signer_t* (*) (protected_ike_sa_t*)) get_signer_initiator;
- this->protected.get_crypter_responder = (crypter_t* (*) (protected_ike_sa_t*)) get_crypter_responder;
- this->protected.get_signer_responder = (signer_t* (*) (protected_ike_sa_t*)) get_signer_responder;
- this->protected.reset_message_buffers = (void (*) (protected_ike_sa_t*)) reset_message_buffers;
- this->protected.get_last_responded_message = (message_t* (*) (protected_ike_sa_t*)) get_last_responded_message;
- this->protected.get_last_requested_message = (message_t* (*) (protected_ike_sa_t*)) get_last_requested_message;
- this->protected.set_last_replied_message_id = (void (*) (protected_ike_sa_t*,u_int32_t)) set_last_replied_message_id;
- this->protected.destroy_child_sa = (u_int32_t (*) (protected_ike_sa_t*,u_int32_t))destroy_child_sa;
- this->protected.get_child_sa = (child_sa_t* (*) (protected_ike_sa_t*,u_int32_t))get_child_sa_by_spi;
- this->protected.set_my_host_behind_nat = (void (*) (protected_ike_sa_t*,bool)) set_my_host_behind_nat;
- this->protected.set_other_host_behind_nat = (void (*) (protected_ike_sa_t*,bool)) set_other_host_behind_nat;
- this->protected.generate_natd_hash = (chunk_t (*) (protected_ike_sa_t*,u_int64_t, u_int64_t, host_t*)) generate_natd_hash;
- this->protected.get_last_dpd_message_id = (u_int32_t (*) (protected_ike_sa_t*)) get_last_dpd_message_id;
- this->protected.update_connection_hosts = (status_t (*) (protected_ike_sa_t*,host_t*,host_t*)) update_connection_hosts;
-
- /* private functions */
- this->update_timestamp = (void (*) (private_ike_sa_t*,bool))update_timestamp;
- this->get_last_esp_traffic_tv = (struct timeval (*) (private_ike_sa_t*,bool))get_last_esp_traffic_tv;
-
+ this->public.get_state = (ike_sa_state_t(*)(ike_sa_t*)) get_state;
+ this->public.set_state = (void(*)(ike_sa_t*,ike_sa_state_t)) set_state;
+ this->public.process_message = (status_t(*)(ike_sa_t*, message_t*)) process_message;
+ this->public.initiate = (status_t(*)(ike_sa_t*,connection_t*)) initiate;
+ this->public.get_id = (ike_sa_id_t*(*)(ike_sa_t*)) get_id;
+ this->public.get_connection = (connection_t*(*)(ike_sa_t*)) get_connection;
+ this->public.retransmit_request = (status_t (*) (ike_sa_t *, u_int32_t)) retransmit_request;
+ this->public.log_status = (void (*) (ike_sa_t*,logger_t*,char*))log_status;
+ this->public.delete = (status_t(*)(ike_sa_t*))delete_;
+ this->public.destroy = (void(*)(ike_sa_t*))destroy;
+ this->public.send_dpd = (status_t (*)(ike_sa_t*)) send_dpd;
+ this->public.send_keepalive = (void (*)(ike_sa_t*)) send_keepalive;
+ this->public.get_prf = (prf_t *(*) (ike_sa_t *)) get_prf;
+ this->public.get_child_prf = (prf_t *(*) (ike_sa_t *)) get_child_prf;
+ this->public.get_prf_auth_i = (prf_t *(*) (ike_sa_t *)) get_prf_auth_i;
+ this->public.get_prf_auth_r = (prf_t *(*) (ike_sa_t *)) get_prf_auth_r;
+ this->public.add_child_sa = (void (*) (ike_sa_t*,child_sa_t*)) add_child_sa;
+ this->public.set_connection = (void (*) (ike_sa_t *,connection_t *)) set_connection;
+ this->public.get_connection = (connection_t *(*) (ike_sa_t *)) get_connection;
+ this->public.set_policy = (void (*) (ike_sa_t *,policy_t *)) set_policy;
+ this->public.get_policy = (policy_t *(*) (ike_sa_t *)) get_policy;
+ this->public.build_transforms = (status_t (*) (ike_sa_t *,proposal_t*,diffie_hellman_t*,chunk_t,chunk_t,bool)) build_transforms;
+ this->public.destroy_child_sa = (u_int32_t (*)(ike_sa_t*,u_int32_t))destroy_child_sa;
+ this->public.get_child_sa = (child_sa_t* (*)(ike_sa_t*,u_int32_t)) get_child_sa;
+ this->public.delete_child_sa = (status_t(*)(ike_sa_t*,u_int32_t)) delete_child_sa;
+ this->public.rekey_child_sa = (status_t(*)(ike_sa_t*,u_int32_t)) rekey_child_sa;
+ this->public.enable_natt = (void(*)(ike_sa_t*, bool)) enable_natt;
+ this->public.is_natt_enabled = (bool(*)(ike_sa_t*)) is_natt_enabled;
+
/* initialize private fields */
this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
-
this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
this->child_sas = linked_list_create();
- this->randomizer = randomizer_create();
-
- this->last_requested_message = NULL;
- this->last_responded_message = NULL;
- this->message_id_out = 0;
- this->message_id_in = 0;
- this->last_replied_message_id = -1;
- this->crypter_initiator = NULL;
- this->crypter_responder = NULL;
- this->signer_initiator = NULL;
- this->signer_responder = NULL;
+ this->crypter_in = NULL;
+ this->crypter_out = NULL;
+ this->signer_in = NULL;
+ this->signer_out = NULL;
this->prf = NULL;
this->prf_auth_i = NULL;
this->prf_auth_r = NULL;
this->child_prf = NULL;
this->connection = NULL;
this->policy = NULL;
- this->nat_hasher = hasher_create(HASH_SHA1);
this->nat_here = FALSE;
this->nat_there = FALSE;
- this->last_msg_in_tv.tv_sec = 0;
- this->last_msg_in_tv.tv_usec = 0;
- this->last_msg_out_tv.tv_sec = 0;
- this->last_msg_out_tv.tv_usec = 0;
- this->last_dpd_message_id = 0;
-
- /* at creation time, IKE_SA is in a initiator state */
- if (ike_sa_id->is_initiator(ike_sa_id))
- {
- this->logger->log(this->logger, CONTROL | LEVEL2, "create first state_t object of type INITIATOR_INIT");
- this->current_state = (state_t *) initiator_init_create(&(this->protected));
- }
- else
- {
- this->logger->log(this->logger, CONTROL | LEVEL2, "create first state_t object of type RESPONDER_INIT");
- this->current_state = (state_t *) responder_init_create(&(this->protected));
- }
- return &(this->protected.public);
+ this->transaction_queue = linked_list_create();
+ this->transaction_in = NULL;
+ this->transaction_in_next = NULL;
+ this->transaction_out = NULL;
+ this->state = SA_CREATED;
+ this->message_id_out = 0;
+ this->time_inbound = 0;
+ this->time_outbound = 0;
+
+ return &this->public;
}
#include <encoding/payloads/proposal_substructure.h>
#include <sa/ike_sa_id.h>
#include <sa/child_sa.h>
-#include <sa/states/state.h>
#include <config/configuration.h>
#include <utils/logger.h>
#include <utils/randomizer.h>
#include <config/policies/policy.h>
#include <utils/logger.h>
+
+typedef enum ike_sa_state_t ike_sa_state_t;
+
/**
- * Nonce size in bytes for nonces sending to other peer.
- *
- * @warning Nonce size MUST be between 16 and 256 bytes.
+ * @brief State of an IKE_SA.
*
* @ingroup sa
*/
-#define NONCE_SIZE 16
+enum ike_sa_state_t {
+
+ /**
+ * IKE_SA just got created, but is not initiating nor responding yet.
+ */
+ SA_CREATED,
+
+ /**
+ * IKE_SA gets initiated actively or passively
+ */
+ SA_CONNECTING,
+
+ /**
+ * IKE_SA is fully established
+ */
+ SA_ESTABLISHED,
+
+ /**
+ * IKE_SA is in progress of deletion
+ */
+ SA_DELETING,
+};
+
+/**
+ * String mappings for ike_sa_state_t.
+ */
+extern mapping_t ike_sa_state_m[];
typedef struct ike_sa_t ike_sa_t;
/**
- * @brief Class ike_sa_t representing an IKE_SA.
- *
- * An object of this type is managed by an ike_sa_manager_t object
- * and represents an IKE_SA. Message processing is split up in different states.
- * They will handle all related things for the state they represent.
- *
+ * @brief Class ike_sa_t representing an IKE_SA.
+ *
+ * An IKE_SA contains crypto information related to a connection
+ * with a peer. It contains multiple IPsec CHILD_SA, for which
+ * it is responsible. All traffic is handled by an IKE_SA, using
+ * transactions.
+ *
* @b Constructors:
* - ike_sa_create()
*
struct ike_sa_t {
/**
- * @brief Processes a incoming IKEv2-Message of type message_t.
+ * @brief Get the id of the SA.
+ *
+ * Returned ike_sa_id_t object is not getting cloned!
*
- * @param this ike_sa_t object object
- * @param[in] message message_t object to process
- * @return
- * - SUCCESS
- * - FAILED
- * - DESTROY_ME if this IKE_SA MUST be deleted
+ * @param this calling object
+ * @return ike_sa's ike_sa_id_t
*/
- status_t (*process_message) (ike_sa_t *this,message_t *message);
+ ike_sa_id_t* (*get_id) (ike_sa_t *this);
+
+ /**
+ * @brief Get the state of the IKE_SA.
+ *
+ * @param this calling object
+ * @return state of the IKE_SA
+ */
+ ike_sa_state_t (*get_state) (ike_sa_t *this);
+
+ /**
+ * @brief Set the state of the IKE_SA.
+ *
+ * @param this calling object
+ * @param state state to set for the IKE_SA
+ */
+ void (*set_state) (ike_sa_t *this, ike_sa_state_t ike_sa);
/**
- * @brief Initiate a new connection with given connection_t object.
- *
+ * @brief Initiate a new connection.
+ *
* The connection_t object is owned by the IKE_SA after the call, so
* do not modify or destroy it.
*
* - FAILED if in wrong state
* - DESTROY_ME if initialization failed and IKE_SA MUST be deleted
*/
- status_t (*initiate_connection) (ike_sa_t *this, connection_t *connection);
+ status_t (*initiate) (ike_sa_t *this, connection_t *connection);
/**
- * @brief Checks whether retransmission is possible.
+ * @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 occurs,
+ * the IKE SA gets deleted.
*
* @param this calling object
- * @param message_id ID of the request to retransmit
* @return
- * - TRUE if retransmit is possible
- * - FALSE if not
+ * - SUCCESS if deletion is initialized
+ * - INVALID_STATE, if the IKE_SA is not in
+ * an established state and can not be
+ * delete (but destroyed).
*/
- bool (*retransmit_possible) (ike_sa_t *this, u_int32_t message_id);
-
+ status_t (*delete) (ike_sa_t *this);
+
/**
* @brief Retransmits a request.
*
* - NOT_FOUND if request doesn't have to be retransmited
*/
status_t (*retransmit_request) (ike_sa_t *this, u_int32_t message_id);
-
- /**
- * @brief Get the id of the SA.
- *
- * Returned ike_sa_id_t object is not getting cloned!
- *
- * @param this calling object
- * @return ike_sa's ike_sa_id_t
- */
- ike_sa_id_t* (*get_id) (ike_sa_t *this);
-
- /**
- * @brief Get the CHILD_SA with the specified reqid.
- *
- * The reqid is a unique ID for a child SA, which is
- * generated on child SA creation.
- * Returned child_sa_t object is not cloned!
- *
- * @param this calling object
- * @param reqid reqid of the child SA, as used in the kernel
- * @return child_sa, or NULL if not found
- */
- child_sa_t* (*get_child_sa) (ike_sa_t *this, u_int32_t reqid);
-
- /**
- * @brief Close the CHILD SA with the specified reqid.
- *
- * Looks for a CHILD SA owned by this IKE_SA, deletes it and
- * notify's the remote peer about the delete. The associated
- * states and policies in the kernel get deleted, if they exist.
- *
- * @param this calling object
- * @param reqid reqid of the child SA, as used in the kernel
- * @return
- * - NOT_FOUND, if IKE_SA has no such CHILD_SA
- * - SUCCESS, if deleted and delete message sent
- */
- status_t (*delete_child_sa) (ike_sa_t *this, u_int32_t reqid);
-
- /**
- * @brief Rekey the CHILD SA with the specified reqid.
- *
- * Looks for a CHILD SA owned by this IKE_SA, and start the rekeing.
- *
- * @param this calling object
- * @param spi security parameter index identifying the SA to rekey
- * @return
- * - NOT_FOUND, if IKE_SA has no such CHILD_SA
- * - SUCCESS, if rekeying initiated
- */
- status_t (*rekey_child_sa) (ike_sa_t *this, u_int32_t reqid);
-
- /**
- * @brief Get local peer address of the IKE_SA.
- *
- * @param this calling object
- * @return local host_t
- */
- host_t* (*get_my_host) (ike_sa_t *this);
-
- /**
- * @brief Get remote peer address of the IKE_SA.
- *
- * @param this calling object
- * @return remote host_t
- */
- host_t* (*get_other_host) (ike_sa_t *this);
-
- /**
- * @brief Get own ID of the IKE_SA.
- *
- * @param this calling object
- * @return local identification_t
- */
- identification_t* (*get_my_id) (ike_sa_t *this);
-
+
/**
- * @brief Get remote ID the IKE_SA.
+ * @brief Processes a incoming IKEv2-Message.
*
- * @param this calling object
- * @return remote identification_t
- */
- identification_t* (*get_other_id) (ike_sa_t *this);
-
- /**
- * @brief Get the connection of the IKE_SA.
+ * Message processing may fail. If a critical failure occurs,
+ * process_message() return DESTROY_ME. Then the caller must
+ * destroy the IKE_SA immediatly, as it is unusable.
*
- * The internal used connection specification
- * can be queried to get some data of an IKE_SA.
- * The connection is still owned to the IKE_SA
- * and must not be manipulated.
- *
* @param this calling object
- * @return connection_t
+ * @param[in] message message to process
+ * @return
+ * - SUCCESS
+ * - FAILED
+ * - DESTROY_ME if this IKE_SA MUST be deleted
*/
- connection_t* (*get_connection) (ike_sa_t *this);
+ status_t (*process_message) (ike_sa_t *this,message_t *message);
/**
- * @brief Query NAT detection status for local host.
+ * @brief Check if NAT traversal is enabled for this IKE_SA.
*
* @param this calling object
- * @return TRUE if this host is behind NAT
+ * @return TRUE if NAT traversal enabled
*/
- bool (*is_my_host_behind_nat) (ike_sa_t *this);
+ bool (*is_natt_enabled) (ike_sa_t *this);
/**
- * @brief Query NAT detection status for remote host.
+ * @brief Enable NAT detection for this IKE_SA.
*
- * @param this calling object
- * @return TRUE if other host is behind NAT
- */
- bool (*is_other_host_behind_nat) (ike_sa_t *this);
-
- /**
- * @brief Query NAT detection status for any host.
+ * If a Network address translation is detected with
+ * NAT_DETECTION notifys, a SA must switch to ports
+ * 4500. To enable this behavior, call enable_natt().
+ * It is relevant which peer is NATted, this is specified
+ * with the "local" parameter. Call it twice when both
+ * are NATted.
*
* @param this calling object
- * @return TRUE if this or other host is behind NAT
+ * @param local TRUE, if we are NATted, FALSE if other
*/
- bool (*is_any_host_behind_nat) (ike_sa_t *this);
+ void (*enable_natt) (ike_sa_t *this, bool local);
/**
- * @brief Query timeval of last inbound IKE or ESP traffic.
+ * @brief Sends a DPD request to the peer.
*
+ * To check if a peer is still alive, periodic
+ * empty INFORMATIONAL messages are sent if no
+ * other traffic was received.
+ *
* @param this calling object
- * @return time when the last traffic was seen
+ * @return
+ * - SUCCESS
+ * - DESTROY_ME, if peer did not respond
*/
- struct timeval (*get_last_traffic_in_tv) (ike_sa_t *this);
-
+ status_t (*send_dpd) (ike_sa_t *this);
+
/**
- * @brief Query timeval of last outbound IKE or ESP traffic.
+ * @brief Sends a keep alive packet.
*
- * @param this calling object
- * @return time when the last traffic was seen
- */
- struct timeval (*get_last_traffic_out_tv) (ike_sa_t *this);
-
- /**
- * @brief Get the state of type of associated state object.
+ * To refresh NAT tables in a NAT router
+ * between the peers, periodic empty
+ * UDP packets are sent if no other traffic
+ * was sent.
*
- * @param this calling object
- * @return state of IKE_SA
- */
- ike_sa_state_t (*get_state) (ike_sa_t *this);
-
- /**
- * @brief Sends a DPD request to the peer.
- *
* @param this calling object
*/
- status_t (*send_dpd_request) (ike_sa_t *this);
+ void (*send_keepalive) (ike_sa_t *this);
/**
* @brief Log the status of a the ike sa to a logger.
* @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 occurs,
- * 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.
- *
- * @param this calling object
- */
- void (*destroy) (ike_sa_t *this);
-};
-
-
-typedef struct protected_ike_sa_t protected_ike_sa_t;
-
-/**
- * @brief Protected functions of an ike_sa_t object.
- *
- * This members are only accessed out from
- * the various state_t implementations.
- *
- * @ingroup sa
- */
-struct protected_ike_sa_t {
-
- /**
- * Public interface of an ike_sa_t object.
- */
- ike_sa_t public;
-
- /**
- * @brief Build an empty IKEv2-Message and fills in default informations.
- *
- * Depending on the type of message (request or response), the message id is
- * either message_id_out or message_id_in.
- *
- * Used in state_t Implementation to build an empty IKEv2-Message.
- *
- * @param this calling object
- * @param type exchange type of new message
- * @param request TRUE, if message has to be a request
- * @param message new message is stored at this location
- */
- void (*build_message) (protected_ike_sa_t *this, exchange_type_t type, bool request, message_t **message);
-
+
/**
* @brief Get the internal stored connection_t object.
*
* @param this calling object
* @return pointer to the internal stored connection_t object
*/
- connection_t *(*get_connection) (protected_ike_sa_t *this);
+ connection_t *(*get_connection) (ike_sa_t *this);
/**
* @brief Set the internal connection object.
* @param this calling object
* @param connection object of type connection_t
*/
- void (*set_connection) (protected_ike_sa_t *this, connection_t *connection);
+ void (*set_connection) (ike_sa_t *this, connection_t *connection);
/**
* @brief Get the internal stored policy object.
* @param this calling object
* @return pointer to the internal stored policy_t object
*/
- policy_t *(*get_policy) (protected_ike_sa_t *this);
+ policy_t *(*get_policy) (ike_sa_t *this);
/**
* @brief Set the internal policy_t object.
* @param this calling object
* @param policy object of type policy_t
*/
- void (*set_policy) (protected_ike_sa_t *this,policy_t *policy);
-
+ void (*set_policy) (ike_sa_t *this, policy_t *policy);
+
/**
* @brief Derive all keys and create the transforms for IKE communication.
*
* Keys are derived using the diffie hellman secret, nonces and internal
- * stored SPIs.
+ * stored SPIs.
* Already existing objects get destroyed.
*
- * @param this calling object
- * @param proposal proposal which contains algorithms to use
- * @param dh diffie hellman object with shared secret
- * @param nonce_i initiators nonce
- * @param nonce_r responders nonce
- */
- status_t (*build_transforms) (protected_ike_sa_t *this, proposal_t* proposal,
- diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r);
-
- /**
- * @brief Send the next request message.
- *
- * Also the first retransmit job is created.
- *
- * Last stored requested message gets destroyed. Object gets not cloned!
- *
- * @param this calling object
- * @param message pointer to the message which should be sent
- * @return
- * - SUCCESS
- * - FAILED if message id is not next expected one
- */
- status_t (*send_request) (protected_ike_sa_t *this,message_t * message);
-
- /**
- * @brief Send the next response message.
- *
- * Last stored responded message gets destroyed. Object gets not cloned!
- *
- * @param this calling object
- * @param message pointer to the message which should be sent
- * return
- * - SUCCESS
- * - FAILED if message id is not next expected one
- */
- status_t (*send_response) (protected_ike_sa_t *this,message_t * message);
-
- /**
- * @brief Send a notify reply message.
- *
- * @param this calling object
- * @param exchange_type type of exchange in which the notify should be wrapped
- * @param type type of the notify message to send
- * @param data notification data
- */
- void (*send_notify) (protected_ike_sa_t *this, exchange_type_t exchange_type, notify_message_type_t type, chunk_t data);
-
- /**
- * @brief Get the internal stored randomizer_t object.
- *
- * @param this calling object
- * @return pointer to the internal randomizer_t object
- */
- randomizer_t *(*get_randomizer) (protected_ike_sa_t *this);
-
- /**
- * @brief Set the new state_t object of the IKE_SA object.
- *
- * The old state_t object gets not destroyed. It's the callers duty to
- * make sure old state is destroyed (Normally the old state is the caller).
- *
- * @param this calling object
- * @param state pointer to the new state_t object
- */
- void (*set_new_state) (protected_ike_sa_t *this,state_t *state);
-
- /**
- * @brief Set the last replied message id.
- *
- * @param this calling object
- * @param message_id message id
- */
- void (*set_last_replied_message_id) (protected_ike_sa_t *this,u_int32_t message_id);
-
- /**
- * @brief Get the internal stored initiator crypter_t object.
- *
- * @param this calling object
- * @return pointer to crypter_t object
- */
- crypter_t *(*get_crypter_initiator) (protected_ike_sa_t *this);
-
- /**
- * @brief Get the internal stored initiator signer_t object.
- *
- * @param this calling object
- * @return pointer to signer_t object
- */
- signer_t *(*get_signer_initiator) (protected_ike_sa_t *this);
-
- /**
- * @brief Get the internal stored responder crypter_t object.
- *
- * @param this calling object
- * @return pointer to crypter_t object
- */
- crypter_t *(*get_crypter_responder) (protected_ike_sa_t *this);
-
- /**
- * @brief Get the internal stored responder signer object.
- *
- * @param this calling object
- * @return pointer to signer_t object
- */
- signer_t *(*get_signer_responder) (protected_ike_sa_t *this);
+ * @param this calling object
+ * @param proposal proposal which contains algorithms to use
+ * @param dh diffie hellman object with shared secret
+ * @param nonce_i initiators nonce
+ * @param nonce_r responders nonce
+ * @param initiator role of this IKE SA (TRUE = originial initiator)
+ */
+ status_t (*build_transforms) (ike_sa_t *this, proposal_t* proposal,
+ diffie_hellman_t *dh,
+ chunk_t nonce_i, chunk_t nonce_r,
+ bool initiator);
/**
* @brief Get the multi purpose prf.
*
- * @param this calling object
- * @return pointer to prf_t object
+ * @param this calling object
+ * @return pointer to prf_t object
*/
- prf_t *(*get_prf) (protected_ike_sa_t *this);
+ prf_t *(*get_prf) (ike_sa_t *this);
/**
* @brief Get the prf-object, which is used to derive keys for child SAs.
*
- * @param this calling object
- * @return pointer to prf_t object
+ * @param this calling object
+ * @return pointer to prf_t object
*/
- prf_t *(*get_child_prf) (protected_ike_sa_t *this);
+ prf_t *(*get_child_prf) (ike_sa_t *this);
/**
* @brief Get the prf used for authentication of initiator.
*
- * @param this calling object
- * @return pointer to prf_t object
+ * @param this calling object
+ * @return pointer to prf_t object
*/
- prf_t *(*get_prf_auth_i) (protected_ike_sa_t *this);
+ prf_t *(*get_prf_auth_i) (ike_sa_t *this);
/**
* @brief Get the prf used for authentication of responder.
*
- * @param this calling object
- * @return pointer to prf_t object
- */
- prf_t *(*get_prf_auth_r) (protected_ike_sa_t *this);
-
- /**
- * @brief Associates a child SA to this IKE SA
- *
- * @param this calling object
- * @param child_sa child_sa to add
- */
- void (*add_child_sa) (protected_ike_sa_t *this, child_sa_t *child_sa);
-
- /**
- * @brief Destroys a CHILD_SA upon request from the other peer.
- *
- * @param this calling object
- * @param spi inbound spi of the CHILD_SA to destroy
- * @return outbound spi of the destroyed CHILD_SA
+ * @param this calling object
+ * @return pointer to prf_t object
*/
- u_int32_t (*destroy_child_sa) (protected_ike_sa_t *this, u_int32_t spi);
+ prf_t *(*get_prf_auth_r) (ike_sa_t *this);
/**
* @brief Get a CHILD_SA upon request from the other peer.
*
- * @param this calling object
- * @param spi spi of the CHILD_SA
- * @return child_sa, or NULL if none found
+ * @param this calling object
+ * @param spi spi of the CHILD_SA
+ * @return child_sa, or NULL if none found
*/
- child_sa_t* (*get_child_sa) (protected_ike_sa_t *this, u_int32_t spi);
+ child_sa_t* (*get_child_sa) (ike_sa_t *this, u_int32_t spi);
/**
- * @brief establish the IKE SA
+ * @brief Close the CHILD SA with the specified reqid.
+ *
+ * Looks for a CHILD SA owned by this IKE_SA, deletes it and
+ * notify's the remote peer about the delete. The associated
+ * states and policies in the kernel get deleted, if they exist.
*
* @param this calling object
- */
- void (*establish) (protected_ike_sa_t *this);
-
- /**
- * @brief Get the last responded message.
- *
- * @param this calling object
- * @return
- * - last received as message_t object
- * - NULL if no last request available
- */
- message_t *(*get_last_responded_message) (protected_ike_sa_t *this);
-
- /**
- * @brief Get the last requested message.
- *
- * @param this calling object
- * @return
- * - last sent as message_t object
- * - NULL if no last request available
- */
- message_t *(*get_last_requested_message) (protected_ike_sa_t *this);
-
- /**
- * @brief Resets message counters and does destroy stored received and sent messages.
+ * @param reqid reqid of the child SA, as used in the kernel
+ * @return
+ * - NOT_FOUND, if IKE_SA has no such CHILD_SA
+ * - SUCCESS, if deleted and delete message sent
*
- * @param this calling object
- */
- void (*reset_message_buffers) (protected_ike_sa_t *this);
+ * @TODO use spi, not reqid
+ */
+ status_t (*delete_child_sa) (ike_sa_t *this, u_int32_t reqid);
/**
- * @brief Set NAT detection status for local host.
+ * @brief Rekey the CHILD SA with the specified reqid.
*
- * @param this calling object
- * @param nat if TRUE, local host is behing NAT
- */
- void (*set_my_host_behind_nat) (protected_ike_sa_t *this, bool nat);
-
- /**
- * @brief Set NAT detection status for remote host.
+ * Looks for a CHILD SA owned by this IKE_SA, and start the rekeing.
*
- * @param this calling object
- * @param nat if TRUE, remote host is behing NAT
+ * @param this calling object
+ * @param spi security parameter index identifying the SA to rekey
+ * @return
+ * - NOT_FOUND, if IKE_SA has no such CHILD_SA
+ * - SUCCESS, if rekeying initiated
+ *
+ * @TODO use spi, not reqid
*/
- void (*set_other_host_behind_nat) (protected_ike_sa_t *this, bool nat);
-
+ status_t (*rekey_child_sa) (ike_sa_t *this, u_int32_t reqid);
+
/**
- * @brief Generate NAT-D payload hash.
- *
- * @param this calling object
- * @param spi_i IKE SPI of initiator
- * @param spi_r IKE SPI of responder
- * @param host address and port of the host/interface
- * @return chunk containing calculated NAT-D hash
+ * @brief Associates a child SA to this IKE SA
+ *
+ * @param this calling object
+ * @param child_sa child_sa to add
*/
- chunk_t (*generate_natd_hash) (protected_ike_sa_t *this, u_int64_t spi_i, u_int64_t spi_r, host_t *host);
-
+ void (*add_child_sa) (ike_sa_t *this, child_sa_t *child_sa);
+
/**
- * @brief Dynamically update hosts on the associated connection.
- *
- * Warning: me and other host are cloned.
- *
- * @param this calling object
- * @param me local address and port
- * @param other remote address and port
+ * @brief Destroys a CHILD_SA upon request from the other peer.
+ *
+ * @param this calling object
+ * @param spi inbound spi of the CHILD_SA to destroy
+ * @return outbound spi of the destroyed CHILD_SA
*/
- status_t (*update_connection_hosts) (protected_ike_sa_t *this, host_t *me, host_t *other);
-
+ u_int32_t (*destroy_child_sa) (ike_sa_t *this, u_int32_t spi);
+
/**
- * @brief Return the message id of the last DPD message
+ * @brief Destroys a ike_sa_t object.
*
- * @param this calling object
- * @return the messages id
+ * @param this calling object
*/
- u_int32_t (*get_last_dpd_message_id) (protected_ike_sa_t *this);
+ void (*destroy) (ike_sa_t *this);
};
-
/**
* @brief Creates an ike_sa_t object with a specific ID.
- *
- * @warning the Content of internal ike_sa_id_t object can change over time
- * e.g. when a IKE_SA_INIT has been finished.
*
- * @param[in] ike_sa_id ike_sa_id_t object to associate with new IKE_SA.
- * The object is internal getting cloned
- * and so has to be destroyed by the caller.
+ * The ID gets cloned internally.
+ *
+ * @param[in] ike_sa_id ike_sa_id_t object to associate with new IKE_SA
* @return ike_sa_t object
*
* @ingroup sa
*/
-ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id);
+ike_sa_t *ike_sa_create(ike_sa_id_t *ike_sa_id);
#endif /*IKE_SA_H_*/
this->responder_spi = responder_spi;
this->is_initiator_flag = is_initiator_flag;
- return (&this->public);
+ return &this->public;
}
status_t (*get_entry_by_sa) (private_ike_sa_manager_t *this, ike_sa_t *ike_sa, ike_sa_entry_t **entry);
/**
- * @brief Felete an entry from the linked list.
+ * @brief Delete an entry from the linked list.
*
* @param this calling object
* @param entry entry to delete
if (current->ike_sa_id->get_responder_spi(current->ike_sa_id) == 0)
{
/* seems to be a half ready ike_sa */
- 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)))
+ 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",
+ 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;
}
else if (ike_sa_id->get_responder_spi(ike_sa_id) == 0)
{
- 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)))
+ 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));
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;
/* create entry */
new_ike_sa_entry = ike_sa_entry_create(new_ike_sa_id);
new_ike_sa_id->destroy(new_ike_sa_id);
+ this->logger->log(this->logger, CONTROL|LEVEL2,
+ "created IKE_SA %llx:%llx, role %s",
+ new_ike_sa_id->get_initiator_spi(new_ike_sa_id),
+ new_ike_sa_id->get_responder_spi(new_ike_sa_id),
+ new_ike_sa_id->is_initiator(new_ike_sa_id) ? "initiator" : "responder");
/* each access is locked */
pthread_mutex_lock(&(this->mutex));
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;
bool original_initiator;
status_t retval;
+ this->logger->log(this->logger, CONTROL|LEVEL2,
+ "checkout IKE_SA %llx:%llx, 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");
+
+ this->logger->log(this->logger, CONTROL|LEVEL2, "%d IKE_SAs in manager",
+ this->ike_sa_list->get_count(this->ike_sa_list));
+
/* each access is locked */
pthread_mutex_lock(&(this->mutex));
/* 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;
}
{
/* 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;
}
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;
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;
- retval = CREATED;
+ retval = SUCCESS;
}
else
{
/* DON'T use return, we must unlock the mutex! */
retval = INVALID_ARG;
}
-
+
pthread_mutex_unlock(&(this->mutex));
/* OK, unlocked... */
return retval;
/**
* Implementation of of ike_sa_manager.checkout_by_reqid.
*/
-static status_t checkout_by_reqid(private_ike_sa_manager_t *this, u_int32_t reqid, ike_sa_t **ike_sa)
+static status_t checkout_by_reqid(private_ike_sa_manager_t *this,
+ u_int32_t reqid, ike_sa_t **ike_sa)
{
iterator_t *iterator;
status_t status = NOT_FOUND;
static void log_status(private_ike_sa_manager_t* this, logger_t* logger, char* name)
{
iterator_t *iterator;
+ u_int instances;
pthread_mutex_lock(&(this->mutex));
- iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
-
- if (iterator->get_count(iterator))
+ instances = this->ike_sa_list->get_count(this->ike_sa_list);
+ if (instances)
{
- logger->log(logger, CONTROL, "Instances:");
+ logger->log(logger, CONTROL, "Instances (%d):", instances);
}
+ iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
while (iterator->has_next(iterator))
{
ike_sa_entry_t *entry;
*/
status_t retval;
ike_sa_entry_t *entry;
+ ike_sa_id_t *ike_sa_id;
+
+ ike_sa_id = ike_sa->get_id(ike_sa);
+
+ this->logger->log(this->logger, CONTROL|LEVEL2,
+ "checkin IKE_SA %llx:%llx, 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");
pthread_mutex_lock(&(this->mutex));
}
else
{
- this->logger->log(this->logger, ERROR, "tried to check in nonexisting IKE_SA");
+ this->logger->log(this->logger, ERROR,
+ "tried to check in nonexisting IKE_SA");
/* this SA is no more, this REALLY should not happen */
retval = NOT_FOUND;
}
+
+ this->logger->log(this->logger, CONTROL|LEVEL2, "%d IKE_SAs in manager now",
+ this->ike_sa_list->get_count(this->ike_sa_list));
pthread_mutex_unlock(&(this->mutex));
return retval;
}
*/
ike_sa_entry_t *entry;
status_t retval;
+ ike_sa_id_t *ike_sa_id;
+
+ ike_sa_id = ike_sa->get_id(ike_sa);
+ this->logger->log(this->logger, CONTROL|LEVEL2,
+ "checkin and destroy IKE_SA %llx:%llx, 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");
pthread_mutex_lock(&(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, "check-in and destroy of IKE_SA successful");
+ this->logger->log(this->logger, CONTROL|LEVEL1,
+ "check-in and destroy of IKE_SA successful");
retval = SUCCESS;
}
else
{
- this->logger->log(this->logger,ERROR, "tried to check-in and delete nonexisting IKE_SA");
+ this->logger->log(this->logger,ERROR,
+ "tried to check-in and delete nonexisting IKE_SA");
retval = NOT_FOUND;
}
*/
ike_sa_entry_t *entry;
status_t retval;
-
+
+ this->logger->log(this->logger, CONTROL|LEVEL2,
+ "delete IKE_SA %llx:%llx, 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");
+
pthread_mutex_lock(&(this->mutex));
-
+
if (this->get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS)
{
/* we try a delete. If it succeeds, our job is done here. The
*/
if (entry->ike_sa->delete(entry->ike_sa) == SUCCESS)
{
- this->logger->log(this->logger, CONTROL|LEVEL1, "initiated delete for IKE_SA");
+ 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...
+ /* 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
{
{
/* wake up all */
pthread_cond_broadcast(&(entry->condvar));
- /* and the nice thing, they will wake us again when their work is done */
+ /* 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 */
}
else
{
- this->logger->log(this->logger,ERROR, "tried to delete nonexisting IKE_SA");
+ this->logger->log(this->logger,ERROR,
+ "tried to delete nonexisting IKE_SA");
retval = NOT_FOUND;
}
ike_sa_entry_t *entry;
pthread_mutex_lock(&(this->mutex));
-
- this->logger->log(this->logger, CONTROL|LEVEL1, "going to destroy IKE_SA manager and all managed IKE_SA's");
-
+ this->logger->log(this->logger, CONTROL|LEVEL1,
+ "going to destroy IKE_SA manager and all managed IKE_SA's");
/* Step 1: drive out all waiting threads */
+ this->logger->log(this->logger, CONTROL|LEVEL2,
+ "set driveout flags for all stored IKE_SA's");
iterator = list->create_iterator(list, TRUE);
-
- this->logger->log(this->logger, CONTROL|LEVEL2, "set driveout flags for all stored IKE_SA's");
while (iterator->has_next(iterator))
{
iterator->current(iterator, (void**)&entry);
entry->driveout_new_threads = TRUE;
entry->driveout_waiting_threads = TRUE;
}
-
- this->logger->log(this->logger, CONTROL|LEVEL2, "wait for all threads to leave IKE_SA's");
+ this->logger->log(this->logger, CONTROL|LEVEL2,
+ "wait for all threads to leave IKE_SA's");
/* Step 2: wait until all are gone */
iterator->reset(iterator);
while (iterator->has_next(iterator))
+++ /dev/null
-/**
- * @file create_child_sa_requested.c
- *
- * @brief State after a CREATE_CHILD_SA request was sent.
- *
- */
-
-/*
- * 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 <string.h>
-
-#include "create_child_sa_requested.h"
-
-#include <sa/child_sa.h>
-#include <sa/states/delete_ike_sa_requested.h>
-#include <sa/states/ike_sa_established.h>
-#include <encoding/payloads/ts_payload.h>
-#include <encoding/payloads/sa_payload.h>
-#include <encoding/payloads/nonce_payload.h>
-#include <encoding/payloads/notify_payload.h>
-#include <utils/logger_manager.h>
-
-
-typedef struct private_create_child_sa_requested_t private_create_child_sa_requested_t;
-
-/**
- * Private data of a create_child_sa_requested_t object.
- */
-struct private_create_child_sa_requested_t {
- /**
- * Public interface of create_child_sa_requested_t.
- */
- create_child_sa_requested_t public;
-
- /**
- * Assigned IKE_SA.
- */
- protected_ike_sa_t *ike_sa;
-
- /**
- * nonce chosen by initiator
- */
- chunk_t nonce_i;
-
- /**
- * nonce chosen by the responder
- */
- chunk_t nonce_r;
-
- /**
- * Policy to use for new child_sa
- */
- policy_t *policy;
-
- /**
- * Proposal negotiated
- */
- proposal_t *proposal;
-
- /**
- * Negotiated list of traffic selectors for local site
- */
- linked_list_t *my_ts;
-
- /**
- * Negotiated list of traffic selectors for remote site
- */
- linked_list_t *other_ts;
-
- /**
- * Child SA to create
- */
- child_sa_t *child_sa;
-
- /**
- * Reqid of the old CHILD_SA, when rekeying
- */
- u_int32_t reqid;
-
- /**
- * Assigned logger.
- *
- * Is logger of ike_sa!
- */
- logger_t *logger;
-};
-
-/**
- * Implementation of private_create_child_sa_requested_t.process_sa_payload.
- */
-static status_t process_sa_payload(private_create_child_sa_requested_t *this, sa_payload_t *sa_payload)
-{
- proposal_t *proposal, *proposal_tmp;
- linked_list_t *proposal_list;
-
- /* get his selected proposal */
- proposal_list = sa_payload->get_proposals(sa_payload);
- /* check count of proposals */
- if (proposal_list->get_count(proposal_list) == 0)
- {
- /* no proposal? we accept this, but no child sa is built */
- this->logger->log(this->logger, AUDIT, "CREATE_CHILD_SA reply contained no proposals. CHILD_SA not created");
- proposal_list->destroy(proposal_list);
- return FAILED;
- }
- if (proposal_list->get_count(proposal_list) > 1)
- {
- this->logger->log(this->logger, AUDIT, "CREATE_CHILD_SA reply contained %d proposals. Aborting",
- proposal_list->get_count(proposal_list));
- while (proposal_list->remove_last(proposal_list, (void**)&proposal) == SUCCESS)
- {
- proposal->destroy(proposal);
- }
- proposal_list->destroy(proposal_list);
- return FAILED;
- }
-
- /* we have to re-check here if other's selection is valid */
- proposal = this->policy->select_proposal(this->policy, proposal_list);
- /* list not needed anymore */
- while (proposal_list->remove_last(proposal_list, (void**)&proposal_tmp) == SUCCESS)
- {
- proposal_tmp->destroy(proposal_tmp);
- }
- proposal_list->destroy(proposal_list);
- /* got a match? */
- if (proposal == NULL)
- {
- this->logger->log(this->logger, AUDIT, "CREATE_CHILD_SA reply contained a not offered proposal. Aborting");
- return FAILED;
- }
-
- /* apply proposal */
- this->proposal = proposal;
-
- return SUCCESS;
-}
-
-/**
- * Implementation of private_create_child_sa_requested_t.process_ts_payload.
- */
-static status_t process_ts_payload(private_create_child_sa_requested_t *this, bool ts_initiator, ts_payload_t *ts_payload)
-{
- linked_list_t *ts_received, *ts_selected;
- traffic_selector_t *ts;
-
- /* get ts form payload */
- ts_received = ts_payload->get_traffic_selectors(ts_payload);
- /* select ts depending on payload type */
- if (ts_initiator)
- {
- ts_selected = this->policy->select_my_traffic_selectors(this->policy, ts_received);
- this->my_ts = ts_selected;
- }
- else
- {
- ts_selected = this->policy->select_other_traffic_selectors(this->policy, ts_received);
- this->other_ts = ts_selected;
- }
- /* check if the responder selected valid proposals */
- if (ts_selected->get_count(ts_selected) != ts_received->get_count(ts_received))
- {
- this->logger->log(this->logger, AUDIT, "IKE_AUTH reply contained not offered traffic selectors.");
- }
-
- /* cleanup */
- while (ts_received->remove_last(ts_received, (void**)&ts) == SUCCESS)
- {
- ts->destroy(ts);
- }
- ts_received->destroy(ts_received);
-
- return SUCCESS;
-}
-
-/**
- * Implementation of private_create_child_sa_requested_t.process_nonce_payload.
- */
-static status_t process_nonce_payload(private_create_child_sa_requested_t *this, nonce_payload_t *nonce_request)
-{
- this->nonce_r = nonce_request->get_nonce(nonce_request);
- return SUCCESS;
-}
-
-/**
- * Process a CREATE_CHILD_SA response
- */
-static status_t process_message(private_create_child_sa_requested_t *this, message_t *response)
-{
- ts_payload_t *tsi_request = NULL, *tsr_request = NULL;
- sa_payload_t *sa_request = NULL;
- nonce_payload_t *nonce_request = NULL;
- ike_sa_id_t *ike_sa_id;
- iterator_t *payloads;
- crypter_t *crypter;
- signer_t *signer;
- status_t status;
- chunk_t seed;
- prf_plus_t *prf_plus;
- child_sa_t *old_child_sa;
-
- this->policy = this->ike_sa->get_policy(this->ike_sa);
- if (response->get_exchange_type(response) != CREATE_CHILD_SA)
- {
- this->logger->log(this->logger, ERROR | LEVEL1, "Message of type %s not supported in state create_child_sa_requested",
- mapping_find(exchange_type_m, response->get_exchange_type(response)));
- return FAILED;
- }
-
- if (response->get_request(response))
- {
- this->logger->log(this->logger, ERROR | LEVEL1, "CREATE_CHILD_SA requests not allowed state create_child_sa_requested");
- /* TODO: our state implementation currently can not handle incoming requests cleanly here.
- * If a request comes in before an outstanding reply, we can not handle it the correct way.
- * Currently, we create a ESTABLISHED state and let it process the message... But we
- * need changes in the whole state mechanism.
- */
- state_t *state = (state_t*)ike_sa_established_create(this->ike_sa);
- state->process_message(state, response);
- state->destroy(state);
- return SUCCESS;
- }
-
- /* 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 */
- status = response->parse_body(response, crypter, signer);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, AUDIT, "CREATE_CHILD_SA r decryption failed. Ignoring message");
- return status;
- }
-
- /* iterate over incoming payloads. Message is verified, we can be sure there are the required payloads */
- payloads = response->get_payload_iterator(response);
- while (payloads->has_next(payloads))
- {
- payload_t *payload;
- payloads->current(payloads, (void**)&payload);
-
- switch (payload->get_type(payload))
- {
- case SECURITY_ASSOCIATION:
- {
- sa_request = (sa_payload_t*)payload;
- break;
- }
- case TRAFFIC_SELECTOR_INITIATOR:
- {
- tsi_request = (ts_payload_t*)payload;
- break;
- }
- case TRAFFIC_SELECTOR_RESPONDER:
- {
- tsr_request = (ts_payload_t*)payload;
- break;
- }
- case NONCE:
- {
- nonce_request = (nonce_payload_t*)payload;
- break;
- }
- case NOTIFY:
- {
- /* TODO: handle notifys */
- 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);
-
- /* check if we have all payloads */
- if (!(sa_request && nonce_request && tsi_request && tsr_request))
- {
- this->logger->log(this->logger, AUDIT, "CREATE_CHILD_SA request did not contain all required payloads. Ignored");
- return FAILED;
- }
-
- /* add payloads to it */
- status = process_nonce_payload(this, nonce_request);
- if (status != SUCCESS)
- {
- response->destroy(response);
- return status;
- }
- status = process_sa_payload(this, sa_request);
- if (status != SUCCESS)
- {
- response->destroy(response);
- return status;
- }
- status = process_ts_payload(this, TRUE, tsi_request);
- if (status != SUCCESS)
- {
- response->destroy(response);
- return status;
- }
- status = process_ts_payload(this, FALSE, tsr_request);
- if (status != SUCCESS)
- {
- response->destroy(response);
- return status;
- }
-
- /* install child SAs for AH and esp */
- if (!this->proposal)
- {
- this->logger->log(this->logger, CONTROL, "Proposal negotiation failed, no CHILD_SA built");
- this->child_sa->destroy(this->child_sa);
- this->child_sa = NULL;
- }
- else if (this->my_ts->get_count(this->my_ts) == 0 || this->other_ts->get_count(this->other_ts) == 0)
- {
- this->logger->log(this->logger, CONTROL, "Traffic selector negotiation failed, no CHILD_SA built");
- this->child_sa->destroy(this->child_sa);
- this->child_sa = NULL;
- }
- else
- {
- seed = chunk_alloc(this->nonce_i.len + this->nonce_r.len);
- memcpy(seed.ptr, this->nonce_i.ptr, this->nonce_i.len);
- memcpy(seed.ptr + this->nonce_i.len, this->nonce_r.ptr, this->nonce_r.len);
- prf_plus = prf_plus_create(this->ike_sa->get_child_prf(this->ike_sa), seed);
-
- this->logger->log_chunk(this->logger, RAW|LEVEL2, "Rekey seed", seed);
- chunk_free(&seed);
-
- status = this->child_sa->update(this->child_sa, this->proposal, prf_plus);
- prf_plus->destroy(prf_plus);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, AUDIT, "Could not install CHILD_SA! Deleting IKE_SA");
- 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 DESTROY_ME;
- }
- this->ike_sa->add_child_sa(this->ike_sa, this->child_sa);
- }
-
- this->ike_sa->set_last_replied_message_id(this->ike_sa, response->get_message_id(response));
-
- /* create new state */
- this->ike_sa->set_new_state(this->ike_sa, (state_t*)ike_sa_established_create(this->ike_sa));
-
- /* if we are rekeying, inform the old child SA that it has been superseeded and
- * start its delete */
- if (this->reqid)
- {
- old_child_sa = this->ike_sa->public.get_child_sa(&this->ike_sa->public, this->reqid);
- if (old_child_sa)
- {
- old_child_sa->set_rekeyed(old_child_sa);
- }
-
- this->ike_sa->public.delete_child_sa(&this->ike_sa->public, this->reqid);
- }
- this->public.state_interface.destroy(&this->public.state_interface);
- return SUCCESS;
-}
-
-/**
- * Implements state_t.get_state
- */
-static ike_sa_state_t get_state(private_create_child_sa_requested_t *this)
-{
- return CREATE_CHILD_SA_REQUESTED;
-}
-
-/**
- * Implementation of state_t.destroy.
- */
-static void destroy(private_create_child_sa_requested_t *this)
-{
- chunk_free(&this->nonce_i);
- chunk_free(&this->nonce_r);
- free(this);
-}
-
-/*
- * Described in header.
- */
-create_child_sa_requested_t *create_child_sa_requested_create(protected_ike_sa_t *ike_sa, child_sa_t *child_sa, chunk_t nonce_i, u_int32_t reqid)
-{
- private_create_child_sa_requested_t *this = malloc_thing(private_create_child_sa_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->child_sa = child_sa;
- this->nonce_i = nonce_i;
- this->nonce_r = CHUNK_INITIALIZER;
- this->reqid = reqid;
- this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
-
- return &(this->public);
-}
+++ /dev/null
-/**
- * @file create_child_sa_requested.h
- *
- * @brief Interface of create_child_sa_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 CREATE_CHILD_SA_REQEUSTED_H_
-#define CREATE_CHILD_SA_REQEUSTED_H_
-
-#include <sa/states/state.h>
-#include <sa/ike_sa.h>
-#include <sa/child_sa.h>
-
-typedef struct create_child_sa_requested_t create_child_sa_requested_t;
-
-/**
- * @brief State after a CREATE_CHILD_SA request was sent.
- *
- * @b Constructors:
- * - create_child_sa_requested_create()
- *
- * @ingroup states
- */
-struct create_child_sa_requested_t {
- /**
- * methods of the state_t interface
- */
- state_t state_interface;
-};
-
-/**
- * @brief Constructor of class create_child_sa_requested_t
- *
- * If this CREATE_CHILD_SA message is to rekey a CHILD_SA,
- * the child_sa with the specified reqid gets deleted after a new
- * one is set up.
- *
- * @param ike_sa assigned ike_sa
- * @param child_sa newly created child sa to complete
- * @param nonce nonce sent at initialization
- * @param reqid reqid, when rekeying a child SA.
- * @return created create_child_sa_requested_t object
- *
- * @ingroup states
- */
-create_child_sa_requested_t *create_child_sa_requested_create(protected_ike_sa_t *ike_sa, child_sa_t *child_sa, chunk_t nonce_i, u_int32_t reqid);
-
-#endif /*CREATE_CHILD_SA_REQEUSTED_H_*/
+++ /dev/null
-/**
- * @file delete_child_sa_requested.c
- *
- * @brief State after a CREATE_CHILD_SA request was sent.
- *
- */
-
-/*
- * 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 <string.h>
-
-#include "delete_child_sa_requested.h"
-
-#include <sa/child_sa.h>
-#include <sa/states/delete_ike_sa_requested.h>
-#include <sa/states/ike_sa_established.h>
-#include <encoding/payloads/notify_payload.h>
-#include <encoding/payloads/delete_payload.h>
-#include <utils/logger_manager.h>
-
-
-typedef struct private_delete_child_sa_requested_t private_delete_child_sa_requested_t;
-
-/**
- * Private data of a delete_child_sa_requested_t object.
- */
-struct private_delete_child_sa_requested_t {
- /**
- * Public interface of delete_child_sa_requested_t.
- */
- delete_child_sa_requested_t public;
-
- /**
- * Assigned IKE_SA.
- */
- protected_ike_sa_t *ike_sa;
-
- /**
- * Assigned logger.
- *
- * Is logger of ike_sa!
- */
- logger_t *logger;
-};
-
-
-/**
- * Process the response
- */
-static status_t process_message(private_delete_child_sa_requested_t *this, message_t *response)
-{
- ike_sa_id_t *ike_sa_id;
- crypter_t *crypter;
- signer_t *signer;
- status_t status;
- iterator_t *iterator;
- payload_t *payload;
- delete_payload_t *delete_response;
-
- if (response->get_exchange_type(response) != INFORMATIONAL)
- {
- this->logger->log(this->logger, ERROR | LEVEL1, "Message of type %s not supported in state delete_child_sa_requested",
- mapping_find(exchange_type_m, response->get_exchange_type(response)));
- return FAILED;
- }
-
- if (response->get_request(response))
- {
- this->logger->log(this->logger, ERROR | LEVEL1, "INFORMATIONAL requests not allowed state delete_child_sa_requested");
- /* TODO: our state implementation currently can not handle incoming requests cleanly here.
- * If a request comes in before an outstanding reply, we can not handle it cleanly.
- * Currently, we create a ESTABLISHED state and let it process the message... But we
- * need changes in the whole state mechanism.
- */
- state_t *state = (state_t*)ike_sa_established_create(this->ike_sa);
- state->process_message(state, response);
- state->destroy(state);
- return SUCCESS;
- }
-
- /* 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 */
- status = response->parse_body(response, crypter, signer);
- if (status != SUCCESS)
- {
- this->logger->log(this->logger, AUDIT, "INFORMATIONAL response decryption failed. Ignoring message");
- return status;
- }
-
- iterator = response->get_payload_iterator(response);
- while (iterator->has_next(iterator)) {
- iterator->current(iterator, (void**)&payload);
- switch (payload->get_type(payload))
- {
- case DELETE:
- delete_response = (delete_payload_t*)payload;
- break;
- default:
- break;
- }
-
- }
- iterator->destroy(iterator);
-
- if (delete_response)
- {
- iterator = delete_response->create_spi_iterator(delete_response);
- while (iterator->has_next(iterator))
- {
- u_int32_t spi;
- iterator->current(iterator, (void**)&spi);
- this->logger->log(this->logger, CONTROL, "DELETE request for CHILD_SA with SPI 0x%x received", spi);
- this->ike_sa->destroy_child_sa(this->ike_sa, spi);
- }
- iterator->destroy(iterator);
- }
-
- this->ike_sa->set_last_replied_message_id(this->ike_sa, response->get_message_id(response));
-
- /* create new state */
- this->ike_sa->set_new_state(this->ike_sa, (state_t*)ike_sa_established_create(this->ike_sa));
- this->public.state_interface.destroy(&this->public.state_interface);
-
- return SUCCESS;
-}
-
-/**
- * Implements state_t.get_state
- */
-static ike_sa_state_t get_state(private_delete_child_sa_requested_t *this)
-{
- return DELETE_CHILD_SA_REQUESTED;
-}
-
-/**
- * Implementation of state_t.destroy.
- */
-static void destroy(private_delete_child_sa_requested_t *this)
-{
- free(this);
-}
-
-/*
- * Described in header.
- */
-delete_child_sa_requested_t *delete_child_sa_requested_create(protected_ike_sa_t *ike_sa)
-{
- private_delete_child_sa_requested_t *this = malloc_thing(private_delete_child_sa_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);
-}
+++ /dev/null
-/**
- * @file delete_child_sa_requested.h
- *
- * @brief Interface of delete_child_sa_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_CHILD_SA_REQEUSTED_H_
-#define DELETE_CHILD_SA_REQEUSTED_H_
-
-#include <sa/states/state.h>
-#include <sa/ike_sa.h>
-#include <sa/child_sa.h>
-
-typedef struct delete_child_sa_requested_t delete_child_sa_requested_t;
-
-/**
- * @brief State after a CREATE_CHILD_SA request was sent.
- *
- * @b Constructors:
- * - delete_child_sa_requested_create()
- *
- * @ingroup states
- */
-struct delete_child_sa_requested_t {
- /**
- * methods of the state_t interface
- */
- state_t state_interface;
-};
-
-/**
- * @brief Constructor of class delete_child_sa_requested_t
- *
- * @param ike_sa assigned ike_sa
- * @return created delete_child_sa_requested_t object
- *
- * @ingroup states
- */
-delete_child_sa_requested_t *delete_child_sa_requested_create(protected_ike_sa_t *ike_sa);
-
-#endif /*DELETE_CHILD_SA_REQEUSTED_H_*/
+++ /dev/null
-/**
- * @file delete_ike_sa_requested.c
- *
- * @brief Implementation of delete_ike_sa_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_ike_sa_requested.h"
-
-#include <daemon.h>
-
-
-typedef struct private_delete_ike_sa_requested_t private_delete_ike_sa_requested_t;
-
-/**
- * Private data of a delete_ike_sa_requested_t object.
- */
-struct private_delete_ike_sa_requested_t {
-
- /**
- * methods of the state_t interface
- */
- delete_ike_sa_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_ike_sa_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_ike_sa_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_ike_sa_requested_t *this)
-{
- return DELETE_IKE_SA_REQUESTED;
-}
-
-/**
- * Implementation of state_t.get_state
- */
-static void destroy(private_delete_ike_sa_requested_t *this)
-{
- free(this);
-}
-
-/*
- * Described in header.
- */
-delete_ike_sa_requested_t *delete_ike_sa_requested_create(protected_ike_sa_t *ike_sa)
-{
- private_delete_ike_sa_requested_t *this = malloc_thing(private_delete_ike_sa_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);
-}
+++ /dev/null
-/**
- * @file delete_ike_sa_requested.h
- *
- * @brief Interface of delete_ike_sa_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_IKE_SA_REQUESTED_H_
-#define DELETE_IKE_SA_REQUESTED_H_
-
-#include <sa/states/state.h>
-#include <sa/ike_sa.h>
-
-typedef struct delete_ike_sa_requested_t delete_ike_sa_requested_t;
-
-/**
- * @brief This class represents an the state of a half closed IKE_SA.
- *
- * @b Constructors:
- * - delete_ike_sa_requested_create()
- *
- * @ingroup states
- */
-struct delete_ike_sa_requested_t {
- /**
- * methods of the state_t interface
- */
- state_t state_interface;
-
-};
-
-/**
- * @brief Constructor of class delete_ike_sa_requested_t
- *
- * @param ike_sa assigned ike_sa
- * @return created delete_ike_sa_requested_t object
- *
- * @ingroup states
- */
-delete_ike_sa_requested_t *delete_ike_sa_requested_create(protected_ike_sa_t *ike_sa);
-
-#endif /*DELETE_IKE_SA_REQUESTED_H_*/
+++ /dev/null
-/**
- * @file ike_auth_requested.c
- *
- * @brief Implementation of ike_auth_requested_t.
- *
- */
-
-/*
- * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
- * Copyright (C) 2005 Jan Hutter, 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 <string.h>
-
-#include "ike_auth_requested.h"
-
-#include <daemon.h>
-#include <encoding/payloads/ts_payload.h>
-#include <encoding/payloads/sa_payload.h>
-#include <encoding/payloads/id_payload.h>
-#include <encoding/payloads/cert_payload.h>
-#include <encoding/payloads/auth_payload.h>
-#include <encoding/payloads/notify_payload.h>
-#include <crypto/signers/signer.h>
-#include <crypto/crypters/crypter.h>
-#include <sa/states/ike_sa_established.h>
-#include <sa/authenticator.h>
-#include <sa/child_sa.h>
-
-typedef struct private_ike_auth_requested_t private_ike_auth_requested_t;
-
-/**
- * Private data of a ike_auth_requested_t object.
- *
- */
-struct private_ike_auth_requested_t {
- /**
- * Public interface of ike_auth_requested_t.
- */
- ike_auth_requested_t public;
-
- /**
- * Assigned IKE_SA.
- */
- protected_ike_sa_t *ike_sa;
-
- /**
- * SA config, just a copy of the one stored in the ike_sa.
- */
- policy_t *policy;
-
- /**
- * Received nonce from responder.
- */
- chunk_t received_nonce;
-
- /**
- * Sent nonce in IKE_SA_INIT request.
- */
- chunk_t sent_nonce;
-
- /**
- * IKE_SA_INIT-Request in binary form.
- */
- chunk_t ike_sa_init_reply_data;
-
- /**
- * Proposal to setup CHILD_SA
- */
- proposal_t *proposal;
-
- /**
- * Traffic selectors applicable at our site
- */
- linked_list_t *my_ts;
-
- /**
- * Traffic selectors applicable at remote site
- */
- linked_list_t *other_ts;
-
- /**
- * Child sa created in ike_sa_init_requested
- */
- child_sa_t *child_sa;
-
- /**
- * Assigned Logger.
- *
- * Is logger of ike_sa!
- */
- logger_t *logger;
-
- /**
- * Process the IDr payload (check if other id is valid)
- *
- * @param this calling object
- * @param idr_payload ID payload of responder
- * @return
- * - SUCCESS
- * - DESTROY_ME
- */
- status_t (*process_idr_payload) (private_ike_auth_requested_t *this, id_payload_t *idr_payload);
-
- /**
- * Process received CERT payload
- *
- * @param this calling object
- * @param cert_payload payload to process
- * @return
- * - DESTROY_ME if IKE_SA should be deleted
- * - SUCCSS if processed successful
- */
- status_t (*process_cert_payload) (private_ike_auth_requested_t *this, cert_payload_t *cert_payload);
-
- /**
- * Process the SA payload (check if selected proposals are valid, setup child sa)
- *
- * @param this calling object
- * @param sa_payload SA payload of responder
- *
- * - SUCCESS
- * - DESTROY_ME
- */
- status_t (*process_sa_payload) (private_ike_auth_requested_t *this, sa_payload_t *sa_payload);
-
- /**
- * Process the AUTH payload (check authenticity of message)
- *
- * @param this calling object
- * @param auth_payload AUTH payload of responder
- * @param other_id_payload ID payload of responder
- *
- * - SUCCESS
- * - DESTROY_ME
- */
- status_t (*process_auth_payload) (private_ike_auth_requested_t *this, auth_payload_t *auth_payload, id_payload_t *other_id_payload);
-
- /**
- * Process the TS payload (check if selected traffic selectors are valid)
- *
- * @param this calling object
- * @param ts_initiator TRUE if TS payload is TSi, FALSE for TSr
- * @param ts_payload TS payload of responder
- *
- * - SUCCESS
- * - DESTROY_ME
- */
- status_t (*process_ts_payload) (private_ike_auth_requested_t *this, bool ts_initiator, ts_payload_t *ts_payload);
-
- /**
- * Process a notify payload
- *
- * @param this calling object
- * @param notify_payload notify payload
- *
- * &n