diff options
Diffstat (limited to 'src/libcharon/sa')
27 files changed, 944 insertions, 938 deletions
diff --git a/src/libcharon/sa/authenticators/eap/eap_manager.c b/src/libcharon/sa/authenticators/eap/eap_manager.c index f795183f0..bc2c4a617 100644 --- a/src/libcharon/sa/authenticators/eap/eap_manager.c +++ b/src/libcharon/sa/authenticators/eap/eap_manager.c @@ -68,12 +68,9 @@ struct private_eap_manager_t { rwlock_t *lock; }; -/** - * Implementation of eap_manager_t.add_method. - */ -static void add_method(private_eap_manager_t *this, eap_type_t type, - u_int32_t vendor, eap_role_t role, - eap_constructor_t constructor) +METHOD(eap_manager_t, add_method, void, + private_eap_manager_t *this, eap_type_t type, u_int32_t vendor, + eap_role_t role, eap_constructor_t constructor) { eap_entry_t *entry = malloc_thing(eap_entry_t); @@ -87,10 +84,8 @@ static void add_method(private_eap_manager_t *this, eap_type_t type, this->lock->unlock(this->lock); } -/** - * Implementation of eap_manager_t.remove_method. - */ -static void remove_method(private_eap_manager_t *this, eap_constructor_t constructor) +METHOD(eap_manager_t, remove_method, void, + private_eap_manager_t *this, eap_constructor_t constructor) { enumerator_t *enumerator; eap_entry_t *entry; @@ -109,13 +104,9 @@ static void remove_method(private_eap_manager_t *this, eap_constructor_t constru this->lock->unlock(this->lock); } -/** - * Implementation of eap_manager_t.create_instance. - */ -static eap_method_t* create_instance(private_eap_manager_t *this, - eap_type_t type, u_int32_t vendor, - eap_role_t role, identification_t *server, - identification_t *peer) +METHOD(eap_manager_t, create_instance, eap_method_t*, + private_eap_manager_t *this, eap_type_t type, u_int32_t vendor, + eap_role_t role, identification_t *server, identification_t *peer) { enumerator_t *enumerator; eap_entry_t *entry; @@ -140,10 +131,8 @@ static eap_method_t* create_instance(private_eap_manager_t *this, return method; } -/** - * Implementation of 2008_t.destroy - */ -static void destroy(private_eap_manager_t *this) +METHOD(eap_manager_t, destroy, void, + private_eap_manager_t *this) { this->methods->destroy_function(this->methods, free); this->lock->destroy(this->lock); @@ -151,19 +140,22 @@ static void destroy(private_eap_manager_t *this) } /* - * see header file + * See header */ eap_manager_t *eap_manager_create() { - private_eap_manager_t *this = malloc_thing(private_eap_manager_t); - - this->public.add_method = (void(*)(eap_manager_t*, eap_type_t type, u_int32_t vendor, eap_role_t role, eap_constructor_t constructor))add_method; - this->public.remove_method = (void(*)(eap_manager_t*, eap_constructor_t constructor))remove_method; - this->public.create_instance = (eap_method_t*(*)(eap_manager_t*, eap_type_t type, u_int32_t vendor, eap_role_t role, identification_t*,identification_t*))create_instance; - this->public.destroy = (void(*)(eap_manager_t*))destroy; - - this->methods = linked_list_create(); - this->lock = rwlock_create(RWLOCK_TYPE_DEFAULT); + private_eap_manager_t *this; + + INIT(this, + .public = { + .add_method = _add_method, + .remove_method = _remove_method, + .create_instance = _create_instance, + .destroy = _destroy, + }, + .methods = linked_list_create(), + .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), + ); return &this->public; } diff --git a/src/libcharon/sa/authenticators/eap/eap_method.c b/src/libcharon/sa/authenticators/eap/eap_method.c index ad7b92cfa..0fa4a00c5 100644 --- a/src/libcharon/sa/authenticators/eap/eap_method.c +++ b/src/libcharon/sa/authenticators/eap/eap_method.c @@ -15,55 +15,8 @@ #include "eap_method.h" -/* - * See header - */ -eap_type_t eap_type_from_string(char *name) -{ - int i; - static struct { - char *name; - eap_type_t type; - } types[] = { - {"identity", EAP_IDENTITY}, - {"md5", EAP_MD5}, - {"otp", EAP_OTP}, - {"gtc", EAP_GTC}, - {"sim", EAP_SIM}, - {"aka", EAP_AKA}, - {"mschapv2", EAP_MSCHAPV2}, - {"radius", EAP_RADIUS}, - }; - - for (i = 0; i < countof(types); i++) - { - if (strcaseeq(name, types[i].name)) - { - return types[i].type; - } - } - return 0; -} - -ENUM(eap_code_names, EAP_REQUEST, EAP_FAILURE, - "EAP_REQUEST", - "EAP_RESPONSE", - "EAP_SUCCESS", - "EAP_FAILURE", -); - -ENUM(eap_code_short_names, EAP_REQUEST, EAP_FAILURE, - "REQ", - "RES", - "SUCC", - "FAIL", -); - ENUM(eap_role_names, EAP_SERVER, EAP_PEER, "EAP_SERVER", "EAP_PEER", ); - - - diff --git a/src/libcharon/sa/authenticators/eap/eap_method.h b/src/libcharon/sa/authenticators/eap/eap_method.h index df354edb4..9961039ff 100644 --- a/src/libcharon/sa/authenticators/eap/eap_method.h +++ b/src/libcharon/sa/authenticators/eap/eap_method.h @@ -23,10 +23,10 @@ typedef struct eap_method_t eap_method_t; typedef enum eap_role_t eap_role_t; -typedef enum eap_code_t eap_code_t; #include <library.h> #include <utils/identification.h> +#include <eap/eap.h> #include <encoding/payloads/eap_payload.h> /** @@ -42,34 +42,6 @@ enum eap_role_t { extern enum_name_t *eap_role_names; /** - * Lookup the EAP method type from a string. - * - * @param name EAP method name (such as "md5", "aka") - * @return method type, 0 if unkown - */ -eap_type_t eap_type_from_string(char *name); - -/** - * EAP code, type of an EAP message - */ -enum eap_code_t { - EAP_REQUEST = 1, - EAP_RESPONSE = 2, - EAP_SUCCESS = 3, - EAP_FAILURE = 4, -}; - -/** - * enum names for eap_code_t. - */ -extern enum_name_t *eap_code_names; - -/** - * short string enum names for eap_code_t. - */ -extern enum_name_t *eap_code_short_names; - -/** * Interface of an EAP method for server and client side. * * An EAP method initiates an EAP exchange and processes requests and diff --git a/src/libcharon/sa/authenticators/eap_authenticator.c b/src/libcharon/sa/authenticators/eap_authenticator.c index 3c0f3c358..8b22fd1d7 100644 --- a/src/libcharon/sa/authenticators/eap_authenticator.c +++ b/src/libcharon/sa/authenticators/eap_authenticator.c @@ -99,22 +99,30 @@ struct private_eap_authenticator_t { static eap_method_t *load_method(private_eap_authenticator_t *this, eap_type_t type, u_int32_t vendor, eap_role_t role) { - identification_t *server, *peer; + identification_t *server, *peer, *aaa; + auth_cfg_t *auth; if (role == EAP_SERVER) { server = this->ike_sa->get_my_id(this->ike_sa); peer = this->ike_sa->get_other_id(this->ike_sa); + auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); } else { server = this->ike_sa->get_other_id(this->ike_sa); peer = this->ike_sa->get_my_id(this->ike_sa); + auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); } if (this->eap_identity) { peer = this->eap_identity; } + aaa = auth->get(auth, AUTH_RULE_AAA_IDENTITY); + if (aaa) + { + server = aaa; + } return charon->eap->create_instance(charon->eap, type, vendor, role, server, peer); } @@ -458,11 +466,8 @@ static void build_auth(private_eap_authenticator_t *this, message_t *message, chunk_free(&auth_data); } -/** - * Implementation of authenticator_t.process for a server - */ -static status_t process_server(private_eap_authenticator_t *this, - message_t *message) +METHOD(authenticator_t, process_server, status_t, + private_eap_authenticator_t *this, message_t *message) { eap_payload_t *eap_payload; @@ -492,11 +497,8 @@ static status_t process_server(private_eap_authenticator_t *this, return NEED_MORE; } -/** - * Implementation of authenticator_t.build for a server - */ -static status_t build_server(private_eap_authenticator_t *this, - message_t *message) +METHOD(authenticator_t, build_server, status_t, + private_eap_authenticator_t *this, message_t *message) { if (this->eap_payload) { @@ -519,11 +521,8 @@ static status_t build_server(private_eap_authenticator_t *this, return FAILED; } -/** - * Implementation of authenticator_t.process for a client - */ -static status_t process_client(private_eap_authenticator_t *this, - message_t *message) +METHOD(authenticator_t, process_client, status_t, + private_eap_authenticator_t *this, message_t *message) { eap_payload_t *eap_payload; @@ -603,11 +602,8 @@ static status_t process_client(private_eap_authenticator_t *this, return FAILED; } -/** - * Implementation of authenticator_t.build for a client - */ -static status_t build_client(private_eap_authenticator_t *this, - message_t *message) +METHOD(authenticator_t, build_client, status_t, + private_eap_authenticator_t *this, message_t *message) { if (this->eap_payload) { @@ -623,20 +619,16 @@ static status_t build_client(private_eap_authenticator_t *this, return NEED_MORE; } -/** - * Implementation of authenticator_t.is_mutual. - */ -static bool is_mutual(private_eap_authenticator_t *this) +METHOD(authenticator_t, is_mutual, bool, + private_eap_authenticator_t *this) { /* we don't know yet, but insist on it after EAP is complete */ this->require_mutual = TRUE; return TRUE; } -/** - * Implementation of authenticator_t.destroy. - */ -static void destroy(private_eap_authenticator_t *this) +METHOD(authenticator_t, destroy, void, + private_eap_authenticator_t *this) { DESTROY_IF(this->method); DESTROY_IF(this->eap_payload); @@ -652,25 +644,23 @@ eap_authenticator_t *eap_authenticator_create_builder(ike_sa_t *ike_sa, chunk_t received_nonce, chunk_t sent_nonce, chunk_t received_init, chunk_t sent_init) { - private_eap_authenticator_t *this = malloc_thing(private_eap_authenticator_t); - - this->public.authenticator.build = (status_t(*)(authenticator_t*, message_t *message))build_client; - this->public.authenticator.process = (status_t(*)(authenticator_t*, message_t *message))process_client; - this->public.authenticator.is_mutual = (bool(*)(authenticator_t*))is_mutual; - this->public.authenticator.destroy = (void(*)(authenticator_t*))destroy; - - this->ike_sa = ike_sa; - this->received_init = received_init; - this->received_nonce = received_nonce; - this->sent_init = sent_init; - this->sent_nonce = sent_nonce; - this->msk = chunk_empty; - this->method = NULL; - this->eap_payload = NULL; - this->eap_complete = FALSE; - this->auth_complete = FALSE; - this->eap_identity = NULL; - this->require_mutual = FALSE; + private_eap_authenticator_t *this; + + INIT(this, + .public = { + .authenticator = { + .build = _build_client, + .process = _process_client, + .is_mutual = _is_mutual, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .received_init = received_init, + .received_nonce = received_nonce, + .sent_init = sent_init, + .sent_nonce = sent_nonce, + ); return &this->public; } @@ -682,25 +672,23 @@ eap_authenticator_t *eap_authenticator_create_verifier(ike_sa_t *ike_sa, chunk_t received_nonce, chunk_t sent_nonce, chunk_t received_init, chunk_t sent_init) { - private_eap_authenticator_t *this = malloc_thing(private_eap_authenticator_t); - - this->public.authenticator.build = (status_t(*)(authenticator_t*, message_t *messageh))build_server; - this->public.authenticator.process = (status_t(*)(authenticator_t*, message_t *message))process_server; - this->public.authenticator.is_mutual = (bool(*)(authenticator_t*))is_mutual; - this->public.authenticator.destroy = (void(*)(authenticator_t*))destroy; - - this->ike_sa = ike_sa; - this->received_init = received_init; - this->received_nonce = received_nonce; - this->sent_init = sent_init; - this->sent_nonce = sent_nonce; - this->msk = chunk_empty; - this->method = NULL; - this->eap_payload = NULL; - this->eap_complete = FALSE; - this->auth_complete = FALSE; - this->eap_identity = NULL; - this->require_mutual = FALSE; + private_eap_authenticator_t *this; + + INIT(this, + .public = { + .authenticator = { + .build = _build_server, + .process = _process_server, + .is_mutual = _is_mutual, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .received_init = received_init, + .received_nonce = received_nonce, + .sent_init = sent_init, + .sent_nonce = sent_nonce, + ); return &this->public; } diff --git a/src/libcharon/sa/authenticators/pubkey_authenticator.c b/src/libcharon/sa/authenticators/pubkey_authenticator.c index 3c67f6db6..54b4338bb 100644 --- a/src/libcharon/sa/authenticators/pubkey_authenticator.c +++ b/src/libcharon/sa/authenticators/pubkey_authenticator.c @@ -84,15 +84,15 @@ static status_t build(private_pubkey_authenticator_t *this, message_t *message) /* we try to deduct the signature scheme from the keysize */ switch (private->get_keysize(private)) { - case 32: + case 256: scheme = SIGN_ECDSA_256; auth_method = AUTH_ECDSA_256; break; - case 48: + case 384: scheme = SIGN_ECDSA_384; auth_method = AUTH_ECDSA_384; break; - case 66: + case 521: scheme = SIGN_ECDSA_521; auth_method = AUTH_ECDSA_521; break; diff --git a/src/libcharon/sa/child_sa.c b/src/libcharon/sa/child_sa.c index bd41cba56..b6ef31da0 100644 --- a/src/libcharon/sa/child_sa.c +++ b/src/libcharon/sa/child_sa.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2009 Tobias Brunner + * Copyright (C) 2006-2010 Tobias Brunner * Copyright (C) 2005-2008 Martin Willi * Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2005 Jan Hutter @@ -23,6 +23,7 @@ #include <string.h> #include <time.h> +#include <hydra.h> #include <daemon.h> ENUM(child_sa_state_names, CHILD_CREATED, CHILD_DESTROYING, @@ -179,170 +180,144 @@ struct private_child_sa_t { }; /** - * Implementation of child_sa_t.get_name + * convert an IKEv2 specific protocol identifier to the IP protocol identifier. */ -static char *get_name(private_child_sa_t *this) +static inline u_int8_t proto_ike2ip(protocol_id_t protocol) +{ + switch (protocol) + { + case PROTO_ESP: + return IPPROTO_ESP; + case PROTO_AH: + return IPPROTO_AH; + default: + return protocol; + } +} + +METHOD(child_sa_t, get_name, char*, + private_child_sa_t *this) { return this->config->get_name(this->config); } -/** - * Implements child_sa_t.get_reqid - */ -static u_int32_t get_reqid(private_child_sa_t *this) +METHOD(child_sa_t, get_reqid, u_int32_t, + private_child_sa_t *this) { return this->reqid; } -/** - * Implements child_sa_t.get_config - */ -static child_cfg_t* get_config(private_child_sa_t *this) +METHOD(child_sa_t, get_config, child_cfg_t*, + private_child_sa_t *this) { return this->config; } -/** - * Implements child_sa_t.set_state - */ -static void set_state(private_child_sa_t *this, child_sa_state_t state) +METHOD(child_sa_t, set_state, void, + private_child_sa_t *this, child_sa_state_t state) { charon->bus->child_state_change(charon->bus, &this->public, state); this->state = state; } -/** - * Implements child_sa_t.get_state - */ -static child_sa_state_t get_state(private_child_sa_t *this) +METHOD(child_sa_t, get_state, child_sa_state_t, + private_child_sa_t *this) { return this->state; } -/** - * Implements child_sa_t.get_spi - */ -u_int32_t get_spi(private_child_sa_t *this, bool inbound) +METHOD(child_sa_t, get_spi, u_int32_t, + private_child_sa_t *this, bool inbound) { return inbound ? this->my_spi : this->other_spi; } -/** - * Implements child_sa_t.get_cpi - */ -u_int16_t get_cpi(private_child_sa_t *this, bool inbound) +METHOD(child_sa_t, get_cpi, u_int16_t, + private_child_sa_t *this, bool inbound) { return inbound ? this->my_cpi : this->other_cpi; } -/** - * Implements child_sa_t.get_protocol - */ -protocol_id_t get_protocol(private_child_sa_t *this) +METHOD(child_sa_t, get_protocol, protocol_id_t, + private_child_sa_t *this) { return this->protocol; } -/** - * Implementation of child_sa_t.set_protocol - */ -static void set_protocol(private_child_sa_t *this, protocol_id_t protocol) +METHOD(child_sa_t, set_protocol, void, + private_child_sa_t *this, protocol_id_t protocol) { this->protocol = protocol; } -/** - * Implementation of child_sa_t.get_mode - */ -static ipsec_mode_t get_mode(private_child_sa_t *this) +METHOD(child_sa_t, get_mode, ipsec_mode_t, + private_child_sa_t *this) { return this->mode; } -/** - * Implementation of child_sa_t.set_mode - */ -static void set_mode(private_child_sa_t *this, ipsec_mode_t mode) +METHOD(child_sa_t, set_mode, void, + private_child_sa_t *this, ipsec_mode_t mode) { this->mode = mode; } -/** - * Implementation of child_sa_t.has_encap - */ -static bool has_encap(private_child_sa_t *this) +METHOD(child_sa_t, has_encap, bool, + private_child_sa_t *this) { return this->encap; } -/** - * Implementation of child_sa_t.get_ipcomp - */ -static ipcomp_transform_t get_ipcomp(private_child_sa_t *this) +METHOD(child_sa_t, get_ipcomp, ipcomp_transform_t, + private_child_sa_t *this) { return this->ipcomp; } -/** - * Implementation of child_sa_t.set_ipcomp. - */ -static void set_ipcomp(private_child_sa_t *this, ipcomp_transform_t ipcomp) +METHOD(child_sa_t, set_ipcomp, void, + private_child_sa_t *this, ipcomp_transform_t ipcomp) { this->ipcomp = ipcomp; } -/** - * Implementation of child_sa_t.set_close_action. - */ -static void set_close_action(private_child_sa_t *this, action_t action) +METHOD(child_sa_t, set_close_action, void, + private_child_sa_t *this, action_t action) { this->close_action = action; } -/** - * Implementation of child_sa_t.get_close_action. - */ -static action_t get_close_action(private_child_sa_t *this) +METHOD(child_sa_t, get_close_action, action_t, + private_child_sa_t *this) { return this->close_action; } -/** - * Implementation of child_sa_t.set_dpd_action. - */ -static void set_dpd_action(private_child_sa_t *this, action_t action) +METHOD(child_sa_t, set_dpd_action, void, + private_child_sa_t *this, action_t action) { this->dpd_action = action; } -/** - * Implementation of child_sa_t.get_dpd_action. - */ -static action_t get_dpd_action(private_child_sa_t *this) +METHOD(child_sa_t, get_dpd_action, action_t, + private_child_sa_t *this) { return this->dpd_action; } -/** - * Implementation of child_sa_t.get_proposal - */ -static proposal_t* get_proposal(private_child_sa_t *this) +METHOD(child_sa_t, get_proposal, proposal_t*, + private_child_sa_t *this) { return this->proposal; } -/** - * Implementation of child_sa_t.set_proposal - */ -static void set_proposal(private_child_sa_t *this, proposal_t *proposal) +METHOD(child_sa_t, set_proposal, void, + private_child_sa_t *this, proposal_t *proposal) { this->proposal = proposal->clone(proposal); } -/** - * Implementation of child_sa_t.get_traffic_selectors. - */ -static linked_list_t *get_traffic_selectors(private_child_sa_t *this, bool local) +METHOD(child_sa_t, get_traffic_selectors, linked_list_t*, + private_child_sa_t *this, bool local) { return local ? this->my_ts : this->other_ts; } @@ -365,11 +340,9 @@ struct policy_enumerator_t { traffic_selector_t *ts; }; -/** - * enumerator function of create_policy_enumerator() - */ -static bool policy_enumerate(policy_enumerator_t *this, - traffic_selector_t **my_out, traffic_selector_t **other_out) +METHOD(enumerator_t, policy_enumerate, bool, + policy_enumerator_t *this, traffic_selector_t **my_out, + traffic_selector_t **other_out) { traffic_selector_t *other_ts; @@ -399,29 +372,29 @@ static bool policy_enumerate(policy_enumerator_t *this, return FALSE; } -/** - * destroy function of create_policy_enumerator() - */ -static void policy_destroy(policy_enumerator_t *this) +METHOD(enumerator_t, policy_destroy, void, + policy_enumerator_t *this) { this->mine->destroy(this->mine); this->other->destroy(this->other); free(this); } -/** - * Implementation of child_sa_t.create_policy_enumerator - */ -static enumerator_t* create_policy_enumerator(private_child_sa_t *this) +METHOD(child_sa_t, create_policy_enumerator, enumerator_t*, + private_child_sa_t *this) { - policy_enumerator_t *e = malloc_thing(policy_enumerator_t); - - e->public.enumerate = (void*)policy_enumerate; - e->public.destroy = (void*)policy_destroy; - e->mine = this->my_ts->create_enumerator(this->my_ts); - e->other = this->other_ts->create_enumerator(this->other_ts); - e->list = this->other_ts; - e->ts = NULL; + policy_enumerator_t *e; + + INIT(e, + .public = { + .enumerate = (void*)_policy_enumerate, + .destroy = _policy_destroy, + }, + .mine = this->my_ts->create_enumerator(this->my_ts), + .other = this->other_ts->create_enumerator(this->other_ts), + .list = this->other_ts, + .ts = NULL, + ); return &e->public; } @@ -441,10 +414,10 @@ static status_t update_usebytes(private_child_sa_t *this, bool inbound) { if (this->my_spi) { - status = charon->kernel_interface->query_sa(charon->kernel_interface, - this->other_addr, this->my_addr, - this->my_spi, this->protocol, - this->mark_in, &bytes); + status = hydra->kernel_interface->query_sa(hydra->kernel_interface, + this->other_addr, this->my_addr, this->my_spi, + proto_ike2ip(this->protocol), this->mark_in, + &bytes); if (status == SUCCESS) { if (bytes > this->my_usebytes) @@ -460,10 +433,10 @@ static status_t update_usebytes(private_child_sa_t *this, bool inbound) { if (this->other_spi) { - status = charon->kernel_interface->query_sa(charon->kernel_interface, - this->my_addr, this->other_addr, - this->other_spi, this->protocol, - this->mark_out, &bytes); + status = hydra->kernel_interface->query_sa(hydra->kernel_interface, + this->my_addr, this->other_addr, this->other_spi, + proto_ike2ip(this->protocol), this->mark_out, + &bytes); if (status == SUCCESS) { if (bytes > this->other_usebytes) @@ -494,14 +467,14 @@ static void update_usetime(private_child_sa_t *this, bool inbound) if (inbound) { - if (charon->kernel_interface->query_policy(charon->kernel_interface, + if (hydra->kernel_interface->query_policy(hydra->kernel_interface, other_ts, my_ts, POLICY_IN, this->mark_in, &in) == SUCCESS) { last_use = max(last_use, in); } if (this->mode != MODE_TRANSPORT) { - if (charon->kernel_interface->query_policy(charon->kernel_interface, + if (hydra->kernel_interface->query_policy(hydra->kernel_interface, other_ts, my_ts, POLICY_FWD, this->mark_in, &fwd) == SUCCESS) { last_use = max(last_use, fwd); @@ -510,7 +483,7 @@ static void update_usetime(private_child_sa_t *this, bool inbound) } else { - if (charon->kernel_interface->query_policy(charon->kernel_interface, + if (hydra->kernel_interface->query_policy(hydra->kernel_interface, my_ts, other_ts, POLICY_OUT, this->mark_out, &out) == SUCCESS) { last_use = max(last_use, out); @@ -533,11 +506,8 @@ static void update_usetime(private_child_sa_t *this, bool inbound) } } -/** - * Implementation of child_sa_t.get_usestats - */ -static void get_usestats(private_child_sa_t *this, bool inbound, - time_t *time, u_int64_t *bytes) +METHOD(child_sa_t, get_usestats, void, + private_child_sa_t *this, bool inbound, time_t *time, u_int64_t *bytes) { if (update_usebytes(this, inbound) != FAILED) { @@ -556,48 +526,41 @@ static void get_usestats(private_child_sa_t *this, bool inbound, } } -/** - * Implementation of child_sa_t.get_lifetime - */ -static time_t get_lifetime(private_child_sa_t *this, bool hard) +METHOD(child_sa_t, get_lifetime, time_t, + private_child_sa_t *this, bool hard) { return hard ? this->expire_time : this->rekey_time; } -/** - * Implementation of child_sa_t.alloc_spi - */ -static u_int32_t alloc_spi(private_child_sa_t *this, protocol_id_t protocol) +METHOD(child_sa_t, alloc_spi, u_int32_t, + private_child_sa_t *this, protocol_id_t protocol) { - if (charon->kernel_interface->get_spi(charon->kernel_interface, - this->other_addr, this->my_addr, protocol, - this->reqid, &this->my_spi) == SUCCESS) + if (hydra->kernel_interface->get_spi(hydra->kernel_interface, + this->other_addr, this->my_addr, + proto_ike2ip(protocol), this->reqid, + &this->my_spi) == SUCCESS) { return this->my_spi; } return 0; } -/** - * Implementation of child_sa_t.alloc_cpi - */ -static u_int16_t alloc_cpi(private_child_sa_t *this) +METHOD(child_sa_t, alloc_cpi, u_int16_t, + private_child_sa_t *this) { - if (charon->kernel_interface->get_cpi(charon->kernel_interface, - this->other_addr, this->my_addr, this->reqid, - &this->my_cpi) == SUCCESS) + if (hydra->kernel_interface->get_cpi(hydra->kernel_interface, + this->other_addr, this->my_addr, + this->reqid, &this->my_cpi) == SUCCESS) { return this->my_cpi; } return 0; } -/** - * Implementation of child_sa_t.install - */ -static status_t install(private_child_sa_t *this, chunk_t encr, chunk_t integ, - u_int32_t spi, u_int16_t cpi, bool inbound, - linked_list_t *my_ts, linked_list_t *other_ts) +METHOD(child_sa_t, install, status_t, + private_child_sa_t *this, chunk_t encr, chunk_t integ, u_int32_t spi, + u_int16_t cpi, bool inbound, linked_list_t *my_ts, + linked_list_t *other_ts) { u_int16_t enc_alg = ENCR_UNDEFINED, int_alg = AUTH_UNDEFINED, size; traffic_selector_t *src_ts = NULL, *dst_ts = NULL; @@ -674,8 +637,8 @@ static status_t install(private_child_sa_t *this, chunk_t encr, chunk_t integ, } } - status = charon->kernel_interface->add_sa(charon->kernel_interface, - src, dst, spi, this->protocol, this->reqid, + status = hydra->kernel_interface->add_sa(hydra->kernel_interface, + src, dst, spi, proto_ike2ip(this->protocol), this->reqid, inbound ? this->mark_in : this->mark_out, lifetime, enc_alg, encr, int_alg, integ, this->mode, this->ipcomp, cpi, this->encap, update, src_ts, dst_ts); @@ -685,11 +648,9 @@ static status_t install(private_child_sa_t *this, chunk_t encr, chunk_t integ, return status; } -/** - * Implementation of child_sa_t.add_policies - */ -static status_t add_policies(private_child_sa_t *this, - linked_list_t *my_ts_list, linked_list_t *other_ts_list) +METHOD(child_sa_t, add_policies, status_t, + private_child_sa_t *this, linked_list_t *my_ts_list, + linked_list_t *other_ts_list) { enumerator_t *enumerator; traffic_selector_t *my_ts, *other_ts; @@ -712,26 +673,55 @@ static status_t add_policies(private_child_sa_t *this, if (this->config->install_policy(this->config)) { + ipsec_sa_cfg_t my_sa = { + .mode = this->mode, + .reqid = this->reqid, + .ipcomp = { + .transform = this->ipcomp, + }, + }, other_sa = my_sa; + + my_sa.ipcomp.cpi = this->my_cpi; + other_sa.ipcomp.cpi = this->other_cpi; + + if (this->protocol == PROTO_ESP) + { + my_sa.esp.use = TRUE; + my_sa.esp.spi = this->my_spi; + other_sa.esp.use = TRUE; + other_sa.esp.spi = this->other_spi; + } + else + { + my_sa.ah.use = TRUE; + my_sa.ah.spi = this->my_spi; + other_sa.ah.use = TRUE; + other_sa.ah.spi = this->other_spi; + } + /* enumerate pairs of traffic selectors */ enumerator = create_policy_enumerator(this); while (enumerator->enumerate(enumerator, &my_ts, &other_ts)) { /* install 3 policies: out, in and forward */ - status |= charon->kernel_interface->add_policy(charon->kernel_interface, - this->my_addr, this->other_addr, my_ts, other_ts, POLICY_OUT, - this->other_spi, this->protocol, this->reqid, this->mark_out, - this->mode, this->ipcomp, this->other_cpi, routed); - - status |= charon->kernel_interface->add_policy(charon->kernel_interface, - this->other_addr, this->my_addr, other_ts, my_ts, POLICY_IN, - this->my_spi, this->protocol, this->reqid, this->mark_in, - this->mode, this->ipcomp, this->my_cpi, routed); + status |= hydra->kernel_interface->add_policy( + hydra->kernel_interface, + this->my_addr, this->other_addr, my_ts, other_ts, + POLICY_OUT, POLICY_IPSEC, &other_sa, + this->mark_out, routed); + + status |= hydra->kernel_interface->add_policy( + hydra->kernel_interface, + this->other_addr, this->my_addr, other_ts, my_ts, + POLICY_IN, POLICY_IPSEC, &my_sa, + this->mark_in, routed); if (this->mode != MODE_TRANSPORT) { - status |= charon->kernel_interface->add_policy(charon->kernel_interface, - this->other_addr, this->my_addr, other_ts, my_ts, POLICY_FWD, - this->my_spi, this->protocol, this->reqid, this->mark_in, - this->mode, this->ipcomp, this->my_cpi, routed); + status |= hydra->kernel_interface->add_policy( + hydra->kernel_interface, + this->other_addr, this->my_addr, other_ts, my_ts, + POLICY_FWD, POLICY_IPSEC, &my_sa, + this->mark_in, routed); } if (status != SUCCESS) @@ -749,11 +739,9 @@ static status_t add_policies(private_child_sa_t *this, return status; } -/** - * Implementation of child_sa_t.update. - */ -static status_t update(private_child_sa_t *this, host_t *me, host_t *other, - host_t *vip, bool encap) +METHOD(child_sa_t, update, status_t, + private_child_sa_t *this, host_t *me, host_t *other, host_t *vip, + bool encap) { child_sa_state_t old; bool transport_proxy_mode; @@ -775,8 +763,8 @@ static status_t update(private_child_sa_t *this, host_t *me, host_t *other, /* update our (initator) SA */ if (this->my_spi) { - if (charon->kernel_interface->update_sa(charon->kernel_interface, - this->my_spi, this->protocol, + if (hydra->kernel_interface->update_sa(hydra->kernel_interface, + this->my_spi, proto_ike2ip(this->protocol), this->ipcomp != IPCOMP_NONE ? this->my_cpi : 0, this->other_addr, this->my_addr, other, me, this->encap, encap, this->mark_in) == NOT_SUPPORTED) @@ -788,8 +776,8 @@ static status_t update(private_child_sa_t *this, host_t *me, host_t *other, /* update his (responder) SA */ if (this->other_spi) { - if (charon->kernel_interface->update_sa(charon->kernel_interface, - this->other_spi, this->protocol, + if (hydra->kernel_interface->update_sa(hydra->kernel_interface, + this->other_spi, proto_ike2ip(this->protocol), this->ipcomp != IPCOMP_NONE ? this->other_cpi : 0, this->my_addr, this->other_addr, me, other, this->encap, encap, this->mark_out) == NOT_SUPPORTED) @@ -801,6 +789,32 @@ static status_t update(private_child_sa_t *this, host_t *me, host_t *other, if (this->config->install_policy(this->config)) { + ipsec_sa_cfg_t my_sa = { + .mode = this->mode, + .reqid = this->reqid, + .ipcomp = { + .transform = this->ipcomp, + }, + }, other_sa = my_sa; + + my_sa.ipcomp.cpi = this->my_cpi; + other_sa.ipcomp.cpi = this->other_cpi; + + if (this->protocol == PROTO_ESP) + { + my_sa.esp.use = TRUE; + my_sa.esp.spi = this->my_spi; + other_sa.esp.use = TRUE; + other_sa.esp.spi = this->other_spi; + } + else + { + my_sa.ah.use = TRUE; + my_sa.ah.spi = this->my_spi; + other_sa.ah.use = TRUE; + other_sa.ah.spi = this->other_spi; + } + /* update policies */ if (!me->ip_equals(me, this->my_addr) || !other->ip_equals(other, this->other_addr)) @@ -813,13 +827,13 @@ static status_t update(private_child_sa_t *this, host_t *me, host_t *other, while (enumerator->enumerate(enumerator, &my_ts, &other_ts)) { /* remove old policies first */ - charon->kernel_interface->del_policy(charon->kernel_interface, + hydra->kernel_interface->del_policy(hydra->kernel_interface, my_ts, other_ts, POLICY_OUT, this->mark_out, FALSE); - charon->kernel_interface->del_policy(charon->kernel_interface, + hydra->kernel_interface->del_policy(hydra->kernel_interface, other_ts, my_ts, POLICY_IN, this->mark_in, FALSE); if (this->mode != MODE_TRANSPORT) { - charon->kernel_interface->del_policy(charon->kernel_interface, + hydra->kernel_interface->del_policy(hydra->kernel_interface, other_ts, my_ts, POLICY_FWD, this->mark_in, FALSE); } @@ -839,25 +853,22 @@ static status_t update(private_child_sa_t *this, host_t *me, host_t *other, * correctly */ if (vip) { - charon->kernel_interface->del_ip(charon->kernel_interface, vip); - charon->kernel_interface->add_ip(charon->kernel_interface, vip, me); + hydra->kernel_interface->del_ip(hydra->kernel_interface, vip); + hydra->kernel_interface->add_ip(hydra->kernel_interface, vip, me); } /* reinstall updated policies */ - charon->kernel_interface->add_policy(charon->kernel_interface, - me, other, my_ts, other_ts, POLICY_OUT, this->other_spi, - this->protocol, this->reqid, this->mark_out, this->mode, - this->ipcomp, this->other_cpi, FALSE); - charon->kernel_interface->add_policy(charon->kernel_interface, - other, me, other_ts, my_ts, POLICY_IN, this->my_spi, - this->protocol, this->reqid, this->mark_in, this->mode, - this->ipcomp, this->my_cpi, FALSE); + hydra->kernel_interface->add_policy(hydra->kernel_interface, + me, other, my_ts, other_ts, POLICY_OUT, POLICY_IPSEC, + &other_sa, this->mark_out, FALSE); + hydra->kernel_interface->add_policy(hydra->kernel_interface, + other, me, other_ts, my_ts, POLICY_IN, POLICY_IPSEC, + &my_sa, this->mark_in, FALSE); if (this->mode != MODE_TRANSPORT) { - charon->kernel_interface->add_policy(charon->kernel_interface, - other, me, other_ts, my_ts, POLICY_FWD, this->my_spi, - this->protocol, this->reqid, this->mark_in, this->mode, - this->ipcomp, this->my_cpi, FALSE); + hydra->kernel_interface->add_policy(hydra->kernel_interface, + other, me, other_ts, my_ts, POLICY_FWD, POLICY_IPSEC, + &my_sa, this->mark_in, FALSE); } } enumerator->destroy(enumerator); @@ -885,10 +896,8 @@ static status_t update(private_child_sa_t *this, host_t *me, host_t *other, return SUCCESS; } -/** - * Implementation of child_sa_t.destroy. - */ -static void destroy(private_child_sa_t *this) +METHOD(child_sa_t, destroy, void, + private_child_sa_t *this) { enumerator_t *enumerator; traffic_selector_t *my_ts, *other_ts; @@ -905,15 +914,17 @@ static void destroy(private_child_sa_t *this) { this->protocol = PROTO_ESP; } - charon->kernel_interface->del_sa(charon->kernel_interface, + hydra->kernel_interface->del_sa(hydra->kernel_interface, this->other_addr, this->my_addr, this->my_spi, - this->protocol, this->my_cpi, this->mark_in); + proto_ike2ip(this->protocol), this->my_cpi, + this->mark_in); } if (this->other_spi) { - charon->kernel_interface->del_sa(charon->kernel_interface, + hydra->kernel_interface->del_sa(hydra->kernel_interface, this->my_addr, this->other_addr, this->other_spi, - this->protocol, this->other_cpi, this->mark_out); + proto_ike2ip(this->protocol), this->other_cpi, + this->mark_out); } if (this->config->install_policy(this->config)) @@ -922,14 +933,14 @@ static void destroy(private_child_sa_t *this) enumerator = create_policy_enumerator(this); while (enumerator->enumerate(enumerator, &my_ts, &other_ts)) { - charon->kernel_interface->del_policy(charon->kernel_interface, - my_ts, other_ts, POLICY_OUT, this->mark_out, unrouted); - charon->kernel_interface->del_policy(charon->kernel_interface, - other_ts, my_ts, POLICY_IN, this->mark_in, unrouted); + hydra->kernel_interface->del_policy(hydra->kernel_interface, + my_ts, other_ts, POLICY_OUT, this->mark_out, unrouted); + hydra->kernel_interface->del_policy(hydra->kernel_interface, + other_ts, my_ts, POLICY_IN, this->mark_in, unrouted); if (this->mode != MODE_TRANSPORT) { - charon->kernel_interface->del_policy(charon->kernel_interface, - other_ts, my_ts, POLICY_FWD, this->mark_in, unrouted); + hydra->kernel_interface->del_policy(hydra->kernel_interface, + other_ts, my_ts, POLICY_FWD, this->mark_in, unrouted); } } enumerator->destroy(enumerator); @@ -944,75 +955,66 @@ static void destroy(private_child_sa_t *this) free(this); } -/* +/** * Described in header. */ child_sa_t * child_sa_create(host_t *me, host_t* other, child_cfg_t *config, u_int32_t rekey, bool encap) { static u_int32_t reqid = 0; - private_child_sa_t *this = malloc_thing(private_child_sa_t); - - /* public functions */ - this->public.get_name = (char*(*)(child_sa_t*))get_name; - this->public.get_reqid = (u_int32_t(*)(child_sa_t*))get_reqid; - this->public.get_config = (child_cfg_t*(*)(child_sa_t*))get_config; - this->public.get_state = (child_sa_state_t(*)(child_sa_t*))get_state; - this->public.set_state = (void(*)(child_sa_t*,child_sa_state_t))set_state; - this->public.get_spi = (u_int32_t(*)(child_sa_t*, bool))get_spi; - this->public.get_cpi = (u_int16_t(*)(child_sa_t*, bool))get_cpi; - this->public.get_protocol = (protocol_id_t(*)(child_sa_t*))get_protocol; - this->public.set_protocol = (void(*)(child_sa_t*, protocol_id_t protocol))set_protocol; - this->public.get_mode = (ipsec_mode_t(*)(child_sa_t*))get_mode; - this->public.set_mode = (void(*)(child_sa_t*, ipsec_mode_t mode))set_mode; - this->public.get_proposal = (proposal_t*(*)(child_sa_t*))get_proposal; - this->public.set_proposal = (void(*)(child_sa_t*, proposal_t *proposal))set_proposal; - this->public.get_lifetime = (time_t(*)(child_sa_t*, bool))get_lifetime; - this->public.get_usestats = (void(*)(child_sa_t*,bool,time_t*,u_int64_t*))get_usestats; - this->public.has_encap = (bool(*)(child_sa_t*))has_encap; - this->public.get_ipcomp = (ipcomp_transform_t(*)(child_sa_t*))get_ipcomp; - this->public.set_ipcomp = (void(*)(child_sa_t*,ipcomp_transform_t))set_ipcomp; - this->public.get_close_action = (action_t(*)(child_sa_t*))get_close_action; - this->public.set_close_action = (void(*)(child_sa_t*,action_t))set_close_action; - this->public.get_dpd_action = (action_t(*)(child_sa_t*))get_dpd_action; - this->public.set_dpd_action = (void(*)(child_sa_t*,action_t))set_dpd_action; - this->public.alloc_spi = (u_int32_t(*)(child_sa_t*, protocol_id_t protocol))alloc_spi; - this->public.alloc_cpi = (u_int16_t(*)(child_sa_t*))alloc_cpi; - this->public.install = (status_t(*)(child_sa_t*, chunk_t encr, chunk_t integ, u_int32_t spi, u_int16_t cpi, bool inbound, linked_list_t *my_ts_list, linked_list_t *other_ts_list))install; - this->public.update = (status_t (*)(child_sa_t*,host_t*,host_t*,host_t*,bool))update; - this->public.add_policies = (status_t (*)(child_sa_t*, linked_list_t*,linked_list_t*))add_policies; - this->public.get_traffic_selectors = (linked_list_t*(*)(child_sa_t*,bool))get_traffic_selectors; - this->public.create_policy_enumerator = (enumerator_t*(*)(child_sa_t*))create_policy_enumerator; - this->public.destroy = (void(*)(child_sa_t*))destroy; - - /* private data */ - this->my_addr = me->clone(me); - this->other_addr = other->clone(other); - this->my_spi = 0; - this->other_spi = 0; - this->my_cpi = 0; - this->other_cpi = 0; - this->encap = encap; - this->ipcomp = IPCOMP_NONE; - this->state = CHILD_CREATED; - this->my_usetime = 0; - this->other_usetime = 0; - this->my_usebytes = 0; - this->other_usebytes = 0; - this->my_ts = linked_list_create(); - this->other_ts = linked_list_create(); - this->protocol = PROTO_NONE; - this->mode = MODE_TUNNEL; - this->close_action = config->get_close_action(config); - this->dpd_action = config->get_dpd_action(config); - this->proposal = NULL; - this->rekey_time = 0; - this->expire_time = 0; + private_child_sa_t *this; + + INIT(this, + .public = { + .get_name = _get_name, + .get_reqid = _get_reqid, + .get_config = _get_config, + .get_state = _get_state, + .set_state = _set_state, + .get_spi = _get_spi, + .get_cpi = _get_cpi, + .get_protocol = _get_protocol, + .set_protocol = _set_protocol, + .get_mode = _get_mode, + .set_mode = _set_mode, + .get_proposal = _get_proposal, + .set_proposal = _set_proposal, + .get_lifetime = _get_lifetime, + .get_usestats = _get_usestats, + .has_encap = _has_encap, + .get_ipcomp = _get_ipcomp, + .set_ipcomp = _set_ipcomp, + .get_close_action = _get_close_action, + .set_close_action = _set_close_action, + .get_dpd_action = _get_dpd_action, + .set_dpd_action = _set_dpd_action, + .alloc_spi = _alloc_spi, + .alloc_cpi = _alloc_cpi, + .install = _install, + .update = _update, + .add_policies = _add_policies, + .get_traffic_selectors = _get_traffic_selectors, + .create_policy_enumerator = _create_policy_enumerator, + .destroy = _destroy, + }, + .my_addr = me->clone(me), + .other_addr = other->clone(other), + .encap = encap, + .ipcomp = IPCOMP_NONE, + .state = CHILD_CREATED, + .my_ts = linked_list_create(), + .other_ts = linked_list_create(), + .protocol = PROTO_NONE, + .mode = MODE_TUNNEL, + .close_action = config->get_close_action(config), + .dpd_action = config->get_dpd_action(config), + .reqid = config->get_reqid(config), + .mark_in = config->get_mark(config, TRUE), + .mark_out = config->get_mark(config, FALSE), + ); + this->config = config; config->get_ref(config); - this->reqid = config->get_reqid(config); - this->mark_in = config->get_mark(config, TRUE); - this->mark_out = config->get_mark(config, FALSE); if (!this->reqid) { diff --git a/src/libcharon/sa/connect_manager.c b/src/libcharon/sa/connect_manager.c index b78ba070d..1fb286863 100644 --- a/src/libcharon/sa/connect_manager.c +++ b/src/libcharon/sa/connect_manager.c @@ -932,7 +932,7 @@ static void update_checklist_state(private_connect_manager_t *this, callback_data_t *data = callback_data_create(this, checklist->connect_id); job_t *job = (job_t*)callback_job_create((callback_job_cb_t)initiator_finish, data, (callback_job_cleanup_t)callback_data_destroy, NULL); - charon->scheduler->schedule_job_ms(charon->scheduler, job, ME_WAIT_TO_FINISH); + lib->scheduler->schedule_job_ms(lib->scheduler, job, ME_WAIT_TO_FINISH); checklist->is_finishing = TRUE; } @@ -1031,7 +1031,7 @@ static void queue_retransmission(private_connect_manager_t *this, check_list_t * DBG2(DBG_IKE, "scheduling retransmission %d of pair '%d' in %dms", retransmission, pair->id, rto); - charon->scheduler->schedule_job_ms(charon->scheduler, (job_t*)job, rto); + lib->scheduler->schedule_job_ms(lib->scheduler, (job_t*)job, rto); } /** @@ -1064,7 +1064,7 @@ static void send_check(private_connect_manager_t *this, check_list_t *checklist, DBG2(DBG_IKE, "send ME_CONNECTAUTH %#B", &check->auth); packet_t *packet; - if (message->generate(message, NULL, NULL, &packet) == SUCCESS) + if (message->generate(message, NULL, &packet) == SUCCESS) { charon->sender->send(charon->sender, packet->clone(packet)); @@ -1170,7 +1170,7 @@ static void schedule_checks(private_connect_manager_t *this, check_list_t *check { callback_data_t *data = callback_data_create(this, checklist->connect_id); checklist->sender = (job_t*)callback_job_create((callback_job_cb_t)sender, data, (callback_job_cleanup_t)callback_data_destroy, NULL); - charon->scheduler->schedule_job_ms(charon->scheduler, checklist->sender, time); + lib->scheduler->schedule_job_ms(lib->scheduler, checklist->sender, time); } /** @@ -1222,7 +1222,7 @@ static void finish_checks(private_connect_manager_t *this, check_list_t *checkli initiate_data_t *data = initiate_data_create(checklist, initiated); job_t *job = (job_t*)callback_job_create((callback_job_cb_t)initiate_mediated, data, (callback_job_cleanup_t)initiate_data_destroy, NULL); - charon->processor->queue_job(charon->processor, job); + lib->processor->queue_job(lib->processor, job); return; } else @@ -1357,7 +1357,7 @@ static void process_request(private_connect_manager_t *this, check_t *check, */ static void process_check(private_connect_manager_t *this, message_t *message) { - if (message->parse_body(message, NULL, NULL) != SUCCESS) + if (message->parse_body(message, NULL) != SUCCESS) { DBG1(DBG_IKE, "%N %s with message ID %d processing failed", exchange_type_names, message->get_exchange_type(message), @@ -1477,7 +1477,7 @@ static void check_and_initiate(private_connect_manager_t *this, { job_t *job = (job_t*)reinitiate_mediation_job_create(mediation_sa, waiting_sa); - charon->processor->queue_job(charon->processor, job); + lib->processor->queue_job(lib->processor, job); } iterator->destroy(iterator); diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 7536662ca..a4e4028ab 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -24,8 +24,8 @@ #include "ike_sa.h" #include <library.h> -#include <daemon.h> #include <hydra.h> +#include <daemon.h> #include <utils/linked_list.h> #include <utils/lexparser.h> #include <sa/task_manager.h> @@ -470,8 +470,8 @@ METHOD(ike_sa_t, send_keepalive, void, diff = 0; } job = send_keepalive_job_create(this->ike_sa_id); - charon->scheduler->schedule_job(charon->scheduler, (job_t*)job, - this->keepalive_interval - diff); + lib->scheduler->schedule_job(lib->scheduler, (job_t*)job, + this->keepalive_interval - diff); } METHOD(ike_sa_t, get_ike_cfg, ike_cfg_t*, @@ -605,7 +605,7 @@ METHOD(ike_sa_t, send_dpd, status_t, } /* recheck in "interval" seconds */ job = (job_t*)send_dpd_job_create(this->ike_sa_id); - charon->scheduler->schedule_job(charon->scheduler, job, delay - diff); + lib->scheduler->schedule_job(lib->scheduler, job, delay - diff); return SUCCESS; } @@ -644,7 +644,7 @@ METHOD(ike_sa_t, set_state, void, { this->stats[STAT_REKEY] = t + this->stats[STAT_ESTABLISHED]; job = (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, FALSE); - charon->scheduler->schedule_job(charon->scheduler, job, t); + lib->scheduler->schedule_job(lib->scheduler, job, t); DBG1(DBG_IKE, "scheduling rekeying in %ds", t); } t = this->peer_cfg->get_reauth_time(this->peer_cfg); @@ -653,7 +653,7 @@ METHOD(ike_sa_t, set_state, void, { this->stats[STAT_REAUTH] = t + this->stats[STAT_ESTABLISHED]; job = (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, TRUE); - charon->scheduler->schedule_job(charon->scheduler, job, t); + lib->scheduler->schedule_job(lib->scheduler, job, t); DBG1(DBG_IKE, "scheduling reauthentication in %ds", t); } t = this->peer_cfg->get_over_time(this->peer_cfg); @@ -675,7 +675,7 @@ METHOD(ike_sa_t, set_state, void, this->stats[STAT_DELETE] += t; t = this->stats[STAT_DELETE] - this->stats[STAT_ESTABLISHED]; job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, TRUE); - charon->scheduler->schedule_job(charon->scheduler, job, t); + lib->scheduler->schedule_job(lib->scheduler, job, t); DBG1(DBG_IKE, "maximum IKE_SA lifetime %ds", t); } @@ -688,8 +688,8 @@ METHOD(ike_sa_t, set_state, void, { /* delete may fail if a packet gets lost, so set a timeout */ job_t *job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, TRUE); - charon->scheduler->schedule_job(charon->scheduler, job, - HALF_OPEN_IKE_SA_TIMEOUT); + lib->scheduler->schedule_job(lib->scheduler, job, + HALF_OPEN_IKE_SA_TIMEOUT); break; } default: @@ -730,14 +730,14 @@ METHOD(ike_sa_t, set_virtual_ip, void, if (local) { DBG1(DBG_IKE, "installing new virtual IP %H", ip); - if (charon->kernel_interface->add_ip(charon->kernel_interface, ip, - this->my_host) == SUCCESS) + if (hydra->kernel_interface->add_ip(hydra->kernel_interface, ip, + this->my_host) == SUCCESS) { if (this->my_virtual_ip) { DBG1(DBG_IKE, "removing old virtual IP %H", this->my_virtual_ip); - charon->kernel_interface->del_ip(charon->kernel_interface, - this->my_virtual_ip); + hydra->kernel_interface->del_ip(hydra->kernel_interface, + this->my_virtual_ip); } DESTROY_IF(this->my_virtual_ip); this->my_virtual_ip = ip->clone(ip); @@ -810,6 +810,20 @@ METHOD(ike_sa_t, get_pending_updates, u_int32_t, return this->pending_updates; } +METHOD(ike_sa_t, float_ports, void, + private_ike_sa_t *this) +{ + /* do not switch if we have a custom port from MOBIKE/NAT */ + if (this->my_host->get_port(this->my_host) == IKEV2_UDP_PORT) + { + this->my_host->set_port(this->my_host, IKEV2_NATT_PORT); + } + if (this->other_host->get_port(this->other_host) == IKEV2_UDP_PORT) + { + this->other_host->set_port(this->other_host, IKEV2_NATT_PORT); + } +} + METHOD(ike_sa_t, update_hosts, void, private_ike_sa_t *this, host_t *me, host_t *other) { @@ -843,10 +857,8 @@ METHOD(ike_sa_t, update_hosts, void, if (!other->equals(other, this->other_host)) { - /* update others adress if we are NOT NATed, - * and allow port changes if we are NATed */ - if (!has_condition(this, COND_NAT_HERE) || - other->ip_equals(other, this->other_host)) + /* update others adress if we are NOT NATed */ + if (!has_condition(this, COND_NAT_HERE)) { set_other_host(this, other->clone(other)); update = TRUE; @@ -882,8 +894,7 @@ METHOD(ike_sa_t, generate_message, status_t, this->stats[STAT_OUTBOUND] = time_monotonic(NULL); message->set_ike_sa_id(message, this->ike_sa_id); return message->generate(message, - this->keymat->get_crypter(this->keymat, FALSE), - this->keymat->get_signer(this->keymat, FALSE), packet); + this->keymat->get_aead(this->keymat, FALSE), packet); } /** @@ -1049,8 +1060,8 @@ static void resolve_hosts(private_ike_sa_t *this) !this->other_host->is_anyaddr(this->other_host)) { host->destroy(host); - host = charon->kernel_interface->get_source_addr( - charon->kernel_interface, this->other_host, NULL); + host = hydra->kernel_interface->get_source_addr( + hydra->kernel_interface, this->other_host, NULL); if (host) { host->set_port(host, this->ike_cfg->get_my_port(this->ike_cfg)); @@ -1150,7 +1161,7 @@ METHOD(ike_sa_t, initiate, status_t, { /* mediated connection, initiate mediation process */ job_t *job = (job_t*)initiate_mediation_job_create(this->ike_sa_id); - charon->processor->queue_job(charon->processor, job); + lib->processor->queue_job(lib->processor, job); return SUCCESS; } #endif /* ME */ @@ -1173,8 +1184,7 @@ METHOD(ike_sa_t, process_message, status_t, is_request = message->get_request(message); status = message->parse_body(message, - this->keymat->get_crypter(this->keymat, TRUE), - this->keymat->get_signer(this->keymat, TRUE)); + this->keymat->get_aead(this->keymat, TRUE)); if (status != SUCCESS) { @@ -1229,15 +1239,12 @@ METHOD(ike_sa_t, process_message, status_t, } else { - host_t *me, *other; - - me = message->get_destination(message); - other = message->get_source(message); - /* if this IKE_SA is virgin, we check for a config */ if (this->ike_cfg == NULL) { job_t *job; + host_t *me = message->get_destination(message), + *other = message->get_source(message); this->ike_cfg = charon->backends->get_ike_cfg(charon->backends, me, other); if (this->ike_cfg == NULL) @@ -1250,20 +1257,12 @@ METHOD(ike_sa_t, process_message, status_t, } /* add a timeout if peer does not establish it completely */ job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, FALSE); - charon->scheduler->schedule_job(charon->scheduler, job, - HALF_OPEN_IKE_SA_TIMEOUT); + lib->scheduler->schedule_job(lib->scheduler, job, + HALF_OPEN_IKE_SA_TIMEOUT); } this->stats[STAT_INBOUND] = time_monotonic(NULL); - /* check if message is trustworthy, and update host information */ - if (this->state == IKE_CREATED || this->state == IKE_CONNECTING || - message->get_exchange_type(message) != IKE_SA_INIT) - { - if (!supports_extension(this, EXT_MOBIKE)) - { /* with MOBIKE, we do no implicit updates */ - update_hosts(this, me, other); - } - } - status = this->task_manager->process_message(this->task_manager, message); + status = this->task_manager->process_message(this->task_manager, + message); if (message->get_exchange_type(message) == IKE_AUTH && this->state == IKE_ESTABLISHED && lib->settings->get_bool(lib->settings, @@ -1697,7 +1696,7 @@ METHOD(ike_sa_t, set_auth_lifetime, void, { DBG1(DBG_IKE, "received AUTH_LIFETIME of %ds, starting reauthentication", lifetime); - charon->processor->queue_job(charon->processor, + lib->processor->queue_job(lib->processor, (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, TRUE)); } else if (this->stats[STAT_REAUTH] == 0 || @@ -1706,7 +1705,7 @@ METHOD(ike_sa_t, set_auth_lifetime, void, this->stats[STAT_REAUTH] = reauth_time; DBG1(DBG_IKE, "received AUTH_LIFETIME of %ds, scheduling reauthentication" " in %ds", lifetime, lifetime - reduction); - charon->scheduler->schedule_job(charon->scheduler, + lib->scheduler->schedule_job(lib->scheduler, (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, TRUE), lifetime - reduction); } @@ -1718,10 +1717,65 @@ METHOD(ike_sa_t, set_auth_lifetime, void, } } +/** + * Check if the current combination of source and destination address is still + * valid. + */ +static bool is_current_path_valid(private_ike_sa_t *this) +{ + bool valid = FALSE; + host_t *src; + src = hydra->kernel_interface->get_source_addr(hydra->kernel_interface, + this->other_host, this->my_host); + if (src) + { + if (src->ip_equals(src, this->my_host)) + { + valid = TRUE; + } + src->destroy(src); + } + return valid; +} + +/** + * Check if we have any path avialable for this IKE SA. + */ +static bool is_any_path_valid(private_ike_sa_t *this) +{ + bool valid = FALSE; + enumerator_t *enumerator; + host_t *src, *addr; + DBG1(DBG_IKE, "old path is not available anymore, try to find another"); + src = hydra->kernel_interface->get_source_addr(hydra->kernel_interface, + this->other_host, NULL); + if (!src) + { + enumerator = this->additional_addresses->create_enumerator( + this->additional_addresses); + while (enumerator->enumerate(enumerator, &addr)) + { + DBG1(DBG_IKE, "looking for a route to %H ...", addr); + src = hydra->kernel_interface->get_source_addr( + hydra->kernel_interface, addr, NULL); + if (src) + { + break; + } + } + enumerator->destroy(enumerator); + } + if (src) + { + valid = TRUE; + src->destroy(src); + } + return valid; +} + METHOD(ike_sa_t, roam, status_t, private_ike_sa_t *this, bool address) { - host_t *src; ike_mobike_t *mobike; switch (this->state) @@ -1734,81 +1788,61 @@ METHOD(ike_sa_t, roam, status_t, default: break; } - /* responder just updates the peer about changed address config */ - if (!this->ike_sa_id->is_initiator(this->ike_sa_id)) + + /* keep existing path if possible */ + if (is_current_path_valid(this)) { + DBG2(DBG_IKE, "keeping connection path %H - %H", + this->my_host, this->other_host); + set_condition(this, COND_STALE, FALSE); + if (supports_extension(this, EXT_MOBIKE) && address) - { + { /* if any addresses changed, send an updated list */ DBG1(DBG_IKE, "sending address list update using MOBIKE"); mobike = ike_mobike_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, (task_t*)mobike); + mobike->addresses(mobike); + this->task_manager->queue_task(this->task_manager, + (task_t*)mobike); return this->task_manager->initiate(this->task_manager); } return SUCCESS; } - /* keep existing path if possible */ - src = charon->kernel_interface->get_source_addr(charon->kernel_interface, - this->other_host, this->my_host); - if (src) + if (!is_any_path_valid(this)) { - if (src->ip_equals(src, this->my_host)) - { - DBG2(DBG_IKE, "keeping connection path %H - %H", - src, this->other_host); - src->destroy(src); - set_condition(this, COND_STALE, FALSE); - return SUCCESS; - } - src->destroy(src); - - } - else - { - /* check if we find a route at all */ - enumerator_t *enumerator; - host_t *addr; - - src = charon->kernel_interface->get_source_addr(charon->kernel_interface, - this->other_host, NULL); - if (!src) - { - enumerator = this->additional_addresses->create_enumerator( - this->additional_addresses); - while (enumerator->enumerate(enumerator, &addr)) - { - DBG1(DBG_IKE, "looking for a route to %H ...", addr); - src = charon->kernel_interface->get_source_addr( - charon->kernel_interface, addr, NULL); - if (src) - { - break; - } - } - enumerator->destroy(enumerator); - } - if (!src) - { - DBG1(DBG_IKE, "no route found to reach %H, MOBIKE update deferred", - this->other_host); - set_condition(this, COND_STALE, TRUE); - return SUCCESS; - } - src->destroy(src); + DBG1(DBG_IKE, "no route found to reach %H, MOBIKE update deferred", + this->other_host); + set_condition(this, COND_STALE, TRUE); + return SUCCESS; } set_condition(this, COND_STALE, FALSE); /* update addresses with mobike, if supported ... */ if (supports_extension(this, EXT_MOBIKE)) { - DBG1(DBG_IKE, "requesting address change using MOBIKE"); + if (!has_condition(this, COND_ORIGINAL_INITIATOR)) + { /* responder updates the peer about changed address config */ + DBG1(DBG_IKE, "sending address list update using MOBIKE, " + "implicitly requesting an address change"); + address = TRUE; + } + else + { + DBG1(DBG_IKE, "requesting address change using MOBIKE"); + } mobike = ike_mobike_create(&this->public, TRUE); mobike->roam(mobike, address); this->task_manager->queue_task(this->task_manager, (task_t*)mobike); return this->task_manager->initiate(this->task_manager); } - DBG1(DBG_IKE, "reauthenticating IKE_SA due to address change"); + /* ... reauth if not */ + if (!has_condition(this, COND_ORIGINAL_INITIATOR)) + { /* responder does not reauthenticate */ + set_condition(this, COND_STALE, TRUE); + return SUCCESS; + } + DBG1(DBG_IKE, "reauthenticating IKE_SA due to address change"); return reauth(this); } @@ -1907,9 +1941,9 @@ METHOD(ike_sa_t, inherit, status_t, this->stats[STAT_DELETE] = this->stats[STAT_REAUTH] + delete; DBG1(DBG_IKE, "rescheduling reauthentication in %ds after rekeying, " "lifetime reduced to %ds", reauth, delete); - charon->scheduler->schedule_job(charon->scheduler, + lib->scheduler->schedule_job(lib->scheduler, (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, TRUE), reauth); - charon->scheduler->schedule_job(charon->scheduler, + lib->scheduler->schedule_job(lib->scheduler, (job_t*)delete_ike_sa_job_create(this->ike_sa_id, TRUE), delete); } /* we have to initate here, there may be new tasks to handle */ @@ -1946,8 +1980,8 @@ METHOD(ike_sa_t, destroy, void, if (this->my_virtual_ip) { - charon->kernel_interface->del_ip(charon->kernel_interface, - this->my_virtual_ip); + hydra->kernel_interface->del_ip(hydra->kernel_interface, + this->my_virtual_ip); this->my_virtual_ip->destroy(this->my_virtual_ip); } if (this->other_virtual_ip) @@ -2025,6 +2059,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) .get_other_host = _get_other_host, .set_other_host = _set_other_host, .set_message_id = _set_message_id, + .float_ports = _float_ports, .update_hosts = _update_hosts, .get_my_id = _get_my_id, .set_my_id = _set_my_id, diff --git a/src/libcharon/sa/ike_sa.h b/src/libcharon/sa/ike_sa.h index 34842a573..c0007e27d 100644 --- a/src/libcharon/sa/ike_sa.h +++ b/src/libcharon/sa/ike_sa.h @@ -329,6 +329,14 @@ struct ike_sa_t { void (*set_other_host) (ike_sa_t *this, host_t *other); /** + * Float to port 4500 (e.g. if a NAT is detected). + * + * The port of either endpoint is changed only if it is currently + * set to the default value of 500. + */ + void (*float_ports)(ike_sa_t *this); + + /** * Update the IKE_SAs host. * * Hosts may be NULL to use current host. diff --git a/src/libcharon/sa/ike_sa_manager.c b/src/libcharon/sa/ike_sa_manager.c index c71c3b297..fa94bb86d 100644 --- a/src/libcharon/sa/ike_sa_manager.c +++ b/src/libcharon/sa/ike_sa_manager.c @@ -1613,6 +1613,9 @@ static void flush(private_ike_sa_manager_t *this) enumerator->destroy(enumerator); charon->bus->set_sa(charon->bus, NULL); unlock_all_segments(this); + + this->rng->destroy(this->rng); + this->hasher->destroy(this->hasher); } /** @@ -1652,8 +1655,6 @@ static void destroy(private_ike_sa_manager_t *this) free(this->half_open_segments); free(this->connected_peers_segments); - this->rng->destroy(this->rng); - this->hasher->destroy(this->hasher); free(this); } diff --git a/src/libcharon/sa/ike_sa_manager.h b/src/libcharon/sa/ike_sa_manager.h index 38f5454e1..f4eabf808 100644 --- a/src/libcharon/sa/ike_sa_manager.h +++ b/src/libcharon/sa/ike_sa_manager.h @@ -199,6 +199,8 @@ struct ike_sa_manager_t { * Delete all existing IKE_SAs and destroy them immediately. * * Threads will be driven out, so all SAs can be deleted cleanly. + * To a flush(), an immediate call to destroy() is mandatory; no other + * method may be used. */ void (*flush)(ike_sa_manager_t *this); diff --git a/src/libcharon/sa/keymat.c b/src/libcharon/sa/keymat.c index 837cbe428..878ad124f 100644 --- a/src/libcharon/sa/keymat.c +++ b/src/libcharon/sa/keymat.c @@ -36,24 +36,14 @@ struct private_keymat_t { bool initiator; /** - * inbound signer (verify) + * inbound AEAD */ - signer_t *signer_in; + aead_t *aead_in; /** - * outbound signer (sign) + * outbound AEAD */ - signer_t *signer_out; - - /** - * inbound crypter (decrypt) - */ - crypter_t *crypter_in; - - /** - * outbound crypter (encrypt) - */ - crypter_t *crypter_out; + aead_t *aead_out; /** * General purpose PRF @@ -134,30 +124,135 @@ static int lookup_keylen(keylen_entry_t *list, int algo) return 0; } +METHOD(keymat_t, create_dh, diffie_hellman_t*, + private_keymat_t *this, diffie_hellman_group_t group) +{ + return lib->crypto->create_dh(lib->crypto, group);; +} + /** - * Implementation of keymat_t.create_dh + * Derive IKE keys for a combined AEAD algorithm */ -static diffie_hellman_t* create_dh(private_keymat_t *this, - diffie_hellman_group_t group) +static bool derive_ike_aead(private_keymat_t *this, u_int16_t alg, + u_int16_t key_size, prf_plus_t *prf_plus) { - return lib->crypto->create_dh(lib->crypto, group);; + aead_t *aead_i, *aead_r; + chunk_t key; + + /* SK_ei/SK_er used for encryption */ + aead_i = lib->crypto->create_aead(lib->crypto, alg, key_size / 8); + aead_r = lib->crypto->create_aead(lib->crypto, alg, key_size / 8); + if (aead_i == NULL || aead_r == NULL) + { + DBG1(DBG_IKE, "%N %N (key size %d) not supported!", + transform_type_names, ENCRYPTION_ALGORITHM, + encryption_algorithm_names, alg, key_size); + return FALSE; + } + key_size = aead_i->get_key_size(aead_i); + + prf_plus->allocate_bytes(prf_plus, key_size, &key); + DBG4(DBG_IKE, "Sk_ei secret %B", &key); + aead_i->set_key(aead_i, key); + chunk_clear(&key); + + prf_plus->allocate_bytes(prf_plus, key_size, &key); + DBG4(DBG_IKE, "Sk_er secret %B", &key); + aead_r->set_key(aead_r, key); + chunk_clear(&key); + + if (this->initiator) + { + this->aead_in = aead_r; + this->aead_out = aead_i; + } + else + { + this->aead_in = aead_i; + this->aead_out = aead_r; + } + return TRUE; } /** - * Implementation of keymat_t.derive_keys + * Derive IKE keys for traditional encryption and MAC algorithms */ -static bool derive_ike_keys(private_keymat_t *this, proposal_t *proposal, - diffie_hellman_t *dh, chunk_t nonce_i, - chunk_t nonce_r, ike_sa_id_t *id, - pseudo_random_function_t rekey_function, - chunk_t rekey_skd) +static bool derive_ike_traditional(private_keymat_t *this, u_int16_t enc_alg, + u_int16_t enc_size, u_int16_t int_alg, prf_plus_t *prf_plus) { - chunk_t skeyseed, key, secret, full_nonce, fixed_nonce, prf_plus_seed; - chunk_t spi_i, spi_r; crypter_t *crypter_i, *crypter_r; signer_t *signer_i, *signer_r; + size_t key_size; + chunk_t key; + + /* SK_ai/SK_ar used for integrity protection */ + signer_i = lib->crypto->create_signer(lib->crypto, int_alg); + signer_r = lib->crypto->create_signer(lib->crypto, int_alg); + if (signer_i == NULL || signer_r == NULL) + { + DBG1(DBG_IKE, "%N %N not supported!", + transform_type_names, INTEGRITY_ALGORITHM, + integrity_algorithm_names, int_alg); + return FALSE; + } + key_size = signer_i->get_key_size(signer_i); + + prf_plus->allocate_bytes(prf_plus, key_size, &key); + DBG4(DBG_IKE, "Sk_ai secret %B", &key); + signer_i->set_key(signer_i, key); + chunk_clear(&key); + + prf_plus->allocate_bytes(prf_plus, key_size, &key); + DBG4(DBG_IKE, "Sk_ar secret %B", &key); + signer_r->set_key(signer_r, key); + chunk_clear(&key); + + /* SK_ei/SK_er used for encryption */ + crypter_i = lib->crypto->create_crypter(lib->crypto, enc_alg, enc_size / 8); + crypter_r = lib->crypto->create_crypter(lib->crypto, enc_alg, enc_size / 8); + if (crypter_i == NULL || crypter_r == NULL) + { + DBG1(DBG_IKE, "%N %N (key size %d) not supported!", + transform_type_names, ENCRYPTION_ALGORITHM, + encryption_algorithm_names, enc_alg, key_size); + signer_i->destroy(signer_i); + signer_r->destroy(signer_r); + return FALSE; + } + key_size = crypter_i->get_key_size(crypter_i); + + prf_plus->allocate_bytes(prf_plus, key_size, &key); + DBG4(DBG_IKE, "Sk_ei secret %B", &key); + crypter_i->set_key(crypter_i, key); + chunk_clear(&key); + + prf_plus->allocate_bytes(prf_plus, key_size, &key); + DBG4(DBG_IKE, "Sk_er secret %B", &key); + crypter_r->set_key(crypter_r, key); + chunk_clear(&key); + + if (this->initiator) + { + this->aead_in = aead_create(crypter_r, signer_r); + this->aead_out = aead_create(crypter_i, signer_i); + } + else + { + this->aead_in = aead_create(crypter_i, signer_i); + this->aead_out = aead_create(crypter_r, signer_r); + } + return TRUE; +} + +METHOD(keymat_t, derive_ike_keys, bool, + private_keymat_t *this, proposal_t *proposal, diffie_hellman_t *dh, + chunk_t nonce_i, chunk_t nonce_r, ike_sa_id_t *id, + pseudo_random_function_t rekey_function, chunk_t rekey_skd) +{ + chunk_t skeyseed, key, secret, full_nonce, fixed_nonce, prf_plus_seed; + chunk_t spi_i, spi_r; prf_plus_t *prf_plus; - u_int16_t alg, key_size; + u_int16_t alg, key_size, int_alg; prf_t *rekey_prf = NULL; spi_i = chunk_alloca(sizeof(u_int64_t)); @@ -195,6 +290,9 @@ static bool derive_ike_keys(private_keymat_t *this, proposal_t *proposal, /* while rfc4434 defines variable keys for AES-XCBC, rfc3664 does * not and therefore fixed key semantics apply to XCBC for key * derivation. */ + case PRF_CAMELLIA128_XCBC: + /* draft-kanno-ipsecme-camellia-xcbc refers to rfc 4434, we + * assume fixed key length. */ key_size = this->prf->get_key_size(this->prf)/2; nonce_i.len = min(nonce_i.len, key_size); nonce_r.len = min(nonce_r.len, key_size); @@ -255,50 +353,6 @@ static bool derive_ike_keys(private_keymat_t *this, proposal_t *proposal, prf_plus->allocate_bytes(prf_plus, key_size, &this->skd); DBG4(DBG_IKE, "Sk_d secret %B", &this->skd); - /* SK_ai/SK_ar used for integrity protection => signer_in/signer_out */ - if (!proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &alg, NULL)) - { - DBG1(DBG_IKE, "no %N selected", - transform_type_names, INTEGRITY_ALGORITHM); - prf_plus->destroy(prf_plus); - DESTROY_IF(rekey_prf); - return FALSE; - } - signer_i = lib->crypto->create_signer(lib->crypto, alg); - signer_r = lib->crypto->create_signer(lib->crypto, alg); - if (signer_i == NULL || signer_r == NULL) - { - DBG1(DBG_IKE, "%N %N not supported!", - transform_type_names, INTEGRITY_ALGORITHM, - integrity_algorithm_names ,alg); - prf_plus->destroy(prf_plus); - DESTROY_IF(rekey_prf); - return FALSE; - } - key_size = signer_i->get_key_size(signer_i); - - prf_plus->allocate_bytes(prf_plus, key_size, &key); - DBG4(DBG_IKE, "Sk_ai secret %B", &key); - signer_i->set_key(signer_i, key); - chunk_clear(&key); - - prf_plus->allocate_bytes(prf_plus, key_size, &key); - DBG4(DBG_IKE, "Sk_ar secret %B", &key); - signer_r->set_key(signer_r, key); - chunk_clear(&key); - - if (this->initiator) - { - this->signer_in = signer_r; - this->signer_out = signer_i; - } - else - { - this->signer_in = signer_i; - this->signer_out = signer_r; - } - - /* SK_ei/SK_er used for encryption => crypter_in/crypter_out */ if (!proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &alg, &key_size)) { DBG1(DBG_IKE, "no %N selected", @@ -307,38 +361,33 @@ static bool derive_ike_keys(private_keymat_t *this, proposal_t *proposal, DESTROY_IF(rekey_prf); return FALSE; } - crypter_i = lib->crypto->create_crypter(lib->crypto, alg, key_size / 8); - crypter_r = lib->crypto->create_crypter(lib->crypto, alg, key_size / 8); - if (crypter_i == NULL || crypter_r == NULL) - { - DBG1(DBG_IKE, "%N %N (key size %d) not supported!", - transform_type_names, ENCRYPTION_ALGORITHM, - encryption_algorithm_names, alg, key_size); - prf_plus->destroy(prf_plus); - DESTROY_IF(rekey_prf); - return FALSE; - } - key_size = crypter_i->get_key_size(crypter_i); - prf_plus->allocate_bytes(prf_plus, key_size, &key); - DBG4(DBG_IKE, "Sk_ei secret %B", &key); - crypter_i->set_key(crypter_i, key); - chunk_clear(&key); - - prf_plus->allocate_bytes(prf_plus, key_size, &key); - DBG4(DBG_IKE, "Sk_er secret %B", &key); - crypter_r->set_key(crypter_r, key); - chunk_clear(&key); - - if (this->initiator) + if (encryption_algorithm_is_aead(alg)) { - this->crypter_in = crypter_r; - this->crypter_out = crypter_i; + if (!derive_ike_aead(this, alg, key_size, prf_plus)) + { + prf_plus->destroy(prf_plus); + DESTROY_IF(rekey_prf); + return FALSE; + } } else { - this->crypter_in = crypter_i; - this->crypter_out = crypter_r; + if (!proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, + &int_alg, NULL)) + { + DBG1(DBG_IKE, "no %N selected", + transform_type_names, INTEGRITY_ALGORITHM); + prf_plus->destroy(prf_plus); + DESTROY_IF(rekey_prf); + return FALSE; + } + if (!derive_ike_traditional(this, alg, key_size, int_alg, prf_plus)) + { + prf_plus->destroy(prf_plus); + DESTROY_IF(rekey_prf); + return FALSE; + } } /* SK_pi/SK_pr used for authentication => stored for later */ @@ -371,14 +420,10 @@ static bool derive_ike_keys(private_keymat_t *this, proposal_t *proposal, return TRUE; } -/** - * Implementation of keymat_t.derive_child_keys - */ -static bool derive_child_keys(private_keymat_t *this, - proposal_t *proposal, diffie_hellman_t *dh, - chunk_t nonce_i, chunk_t nonce_r, - chunk_t *encr_i, chunk_t *integ_i, - chunk_t *encr_r, chunk_t *integ_r) +METHOD(keymat_t, derive_child_keys, bool, + private_keymat_t *this, proposal_t *proposal, diffie_hellman_t *dh, + chunk_t nonce_i, chunk_t nonce_r, chunk_t *encr_i, chunk_t *integ_i, + chunk_t *encr_r, chunk_t *integ_r) { u_int16_t enc_alg, int_alg, enc_size = 0, int_size = 0; chunk_t seed, secret = chunk_empty; @@ -480,37 +525,22 @@ static bool derive_child_keys(private_keymat_t *this, return TRUE; } -/** - * Implementation of keymat_t.get_skd - */ -static pseudo_random_function_t get_skd(private_keymat_t *this, chunk_t *skd) +METHOD(keymat_t, get_skd, pseudo_random_function_t, + private_keymat_t *this, chunk_t *skd) { *skd = this->skd; return this->prf_alg; } -/** - * Implementation of keymat_t.get_signer - */ -static signer_t* get_signer(private_keymat_t *this, bool in) -{ - return in ? this->signer_in : this->signer_out; -} - -/** - * Implementation of keymat_t.get_crypter - */ -static crypter_t* get_crypter(private_keymat_t *this, bool in) +METHOD(keymat_t, get_aead, aead_t*, + private_keymat_t *this, bool in) { - return in ? this->crypter_in : this->crypter_out; + return in ? this->aead_in : this->aead_out; } -/** - * Implementation of keymat_t.get_auth_octets - */ -static chunk_t get_auth_octets(private_keymat_t *this, bool verify, - chunk_t ike_sa_init, chunk_t nonce, - identification_t *id) +METHOD(keymat_t, get_auth_octets, chunk_t, + private_keymat_t *this, bool verify, chunk_t ike_sa_init, + chunk_t nonce, identification_t *id) { chunk_t chunk, idx, octets; chunk_t skp; @@ -538,12 +568,9 @@ static chunk_t get_auth_octets(private_keymat_t *this, bool verify, #define IKEV2_KEY_PAD "Key Pad for IKEv2" #define IKEV2_KEY_PAD_LENGTH 17 -/** - * Implementation of keymat_t.get_psk_sig - */ -static chunk_t get_psk_sig(private_keymat_t *this, bool verify, - chunk_t ike_sa_init, chunk_t nonce, chunk_t secret, - identification_t *id) +METHOD(keymat_t, get_psk_sig, chunk_t, + private_keymat_t *this, bool verify, chunk_t ike_sa_init, + chunk_t nonce, chunk_t secret, identification_t *id) { chunk_t key_pad, key, sig, octets; @@ -567,15 +594,11 @@ static chunk_t get_psk_sig(private_keymat_t *this, bool verify, return sig; } -/** - * Implementation of keymat_t.destroy. - */ -static void destroy(private_keymat_t *this) +METHOD(keymat_t, destroy, void, + private_keymat_t *this) { - DESTROY_IF(this->signer_in); - DESTROY_IF(this->signer_out); - DESTROY_IF(this->crypter_in); - DESTROY_IF(this->crypter_out); + DESTROY_IF(this->aead_in); + DESTROY_IF(this->aead_out); DESTROY_IF(this->prf); chunk_clear(&this->skd); chunk_clear(&this->skp_verify); @@ -588,29 +611,22 @@ static void destroy(private_keymat_t *this) */ keymat_t *keymat_create(bool initiator) { - private_keymat_t *this = malloc_thing(private_keymat_t); - - this->public.create_dh = (diffie_hellman_t*(*)(keymat_t*, diffie_hellman_group_t group))create_dh; - this->public.derive_ike_keys = (bool(*)(keymat_t*, proposal_t *proposal, diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r, ike_sa_id_t *id, pseudo_random_function_t,chunk_t))derive_ike_keys; - this->public.derive_child_keys = (bool(*)(keymat_t*, proposal_t *proposal, diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r, chunk_t *encr_i, chunk_t *integ_i, chunk_t *encr_r, chunk_t *integ_r))derive_child_keys; - this->public.get_skd = (pseudo_random_function_t(*)(keymat_t*, chunk_t *skd))get_skd; - this->public.get_signer = (signer_t*(*)(keymat_t*, bool in))get_signer; - this->public.get_crypter = (crypter_t*(*)(keymat_t*, bool in))get_crypter; - this->public.get_auth_octets = (chunk_t(*)(keymat_t *, bool verify, chunk_t ike_sa_init, chunk_t nonce, identification_t *id))get_auth_octets; - this->public.get_psk_sig = (chunk_t(*)(keymat_t*, bool verify, chunk_t ike_sa_init, chunk_t nonce, chunk_t secret, identification_t *id))get_psk_sig; - this->public.destroy = (void(*)(keymat_t*))destroy; - - this->initiator = initiator; - - this->signer_in = NULL; - this->signer_out = NULL; - this->crypter_in = NULL; - this->crypter_out = NULL; - this->prf = NULL; - this->prf_alg = PRF_UNDEFINED; - this->skd = chunk_empty; - this->skp_verify = chunk_empty; - this->skp_build = chunk_empty; + private_keymat_t *this; + + INIT(this, + .public = { + .create_dh = _create_dh, + .derive_ike_keys = _derive_ike_keys, + .derive_child_keys = _derive_child_keys, + .get_skd = _get_skd, + .get_aead = _get_aead, + .get_auth_octets = _get_auth_octets, + .get_psk_sig = _get_psk_sig, + .destroy = _destroy, + }, + .initiator = initiator, + .prf_alg = PRF_UNDEFINED, + ); return &this->public; } diff --git a/src/libcharon/sa/keymat.h b/src/libcharon/sa/keymat.h index e51709e8d..4f01aa411 100644 --- a/src/libcharon/sa/keymat.h +++ b/src/libcharon/sa/keymat.h @@ -24,8 +24,7 @@ #include <library.h> #include <utils/identification.h> #include <crypto/prfs/prf.h> -#include <crypto/crypters/crypter.h> -#include <crypto/signers/signer.h> +#include <crypto/aead.h> #include <config/proposal.h> #include <sa/ike_sa_id.h> @@ -99,21 +98,13 @@ struct keymat_t { */ pseudo_random_function_t (*get_skd)(keymat_t *this, chunk_t *skd); - /** - * Get a signer to sign/verify IKE messages. - * - * @param in TRUE for inbound (verify), FALSE for outbound (sign) - * @return signer - */ - signer_t* (*get_signer)(keymat_t *this, bool in); - /* - * Get a crypter to en-/decrypt IKE messages. + * Get a AEAD transform to en-/decrypt and sign/verify IKE messages. * * @param in TRUE for inbound (decrypt), FALSE for outbound (encrypt) * @return crypter */ - crypter_t* (*get_crypter)(keymat_t *this, bool in); + aead_t* (*get_aead)(keymat_t *this, bool in); /** * Generate octets to use for authentication procedure (RFC4306 2.15). diff --git a/src/libcharon/sa/mediation_manager.c b/src/libcharon/sa/mediation_manager.c index 035f49053..2fbab7c7c 100644 --- a/src/libcharon/sa/mediation_manager.c +++ b/src/libcharon/sa/mediation_manager.c @@ -241,7 +241,7 @@ static void update_sa_id(private_mediation_manager_t *this, identification_t *pe (void**)&requester) == SUCCESS) { job_t *job = (job_t*)mediation_callback_job_create(requester, peer_id); - charon->processor->queue_job(charon->processor, job); + lib->processor->queue_job(lib->processor, job); requester->destroy(requester); } diff --git a/src/libcharon/sa/task_manager.c b/src/libcharon/sa/task_manager.c index a68826440..18703ce36 100644 --- a/src/libcharon/sa/task_manager.c +++ b/src/libcharon/sa/task_manager.c @@ -274,7 +274,7 @@ METHOD(task_manager_t, retransmit, status_t, this->initiating.retransmitted++; job = (job_t*)retransmit_job_create(this->initiating.mid, this->ike_sa->get_id(this->ike_sa)); - charon->scheduler->schedule_job_ms(charon->scheduler, job, timeout); + lib->scheduler->schedule_job_ms(lib->scheduler, job, timeout); } return SUCCESS; } @@ -883,11 +883,21 @@ METHOD(task_manager_t, process_message, status_t, private_task_manager_t *this, message_t *msg) { u_int32_t mid = msg->get_message_id(msg); + host_t *me = msg->get_destination(msg), *other = msg->get_source(msg); if (msg->get_request(msg)) { if (mid == this->responding.mid) { + if (this->ike_sa->get_state(this->ike_sa) == IKE_CREATED || + this->ike_sa->get_state(this->ike_sa) == IKE_CONNECTING || + msg->get_exchange_type(msg) != IKE_SA_INIT) + { /* only do host updates based on verified messages */ + if (!this->ike_sa->supports_extension(this->ike_sa, EXT_MOBIKE)) + { /* with MOBIKE, we do no implicit updates */ + this->ike_sa->update_hosts(this->ike_sa, me, other); + } + } charon->bus->message(charon->bus, msg, TRUE); if (process_request(this, msg) != SUCCESS) { @@ -920,6 +930,15 @@ METHOD(task_manager_t, process_message, status_t, { if (mid == this->initiating.mid) { + if (this->ike_sa->get_state(this->ike_sa) == IKE_CREATED || + this->ike_sa->get_state(this->ike_sa) == IKE_CONNECTING || + msg->get_exchange_type(msg) != IKE_SA_INIT) + { /* only do host updates based on verified messages */ + if (!this->ike_sa->supports_extension(this->ike_sa, EXT_MOBIKE)) + { /* with MOBIKE, we do no implicit updates */ + this->ike_sa->update_hosts(this->ike_sa, me, other); + } + } charon->bus->message(charon->bus, msg, TRUE); if (process_response(this, msg) != SUCCESS) { diff --git a/src/libcharon/sa/tasks/child_create.c b/src/libcharon/sa/tasks/child_create.c index 3de27ee3f..57beedba9 100644 --- a/src/libcharon/sa/tasks/child_create.c +++ b/src/libcharon/sa/tasks/child_create.c @@ -261,7 +261,7 @@ static void schedule_inactivity_timeout(private_child_create_t *this) { close_ike = lib->settings->get_bool(lib->settings, "charon.inactivity_close_ike", FALSE); - charon->scheduler->schedule_job(charon->scheduler, (job_t*) + lib->scheduler->schedule_job(lib->scheduler, (job_t*) inactivity_job_create(this->child_sa->get_reqid(this->child_sa), timeout, close_ike), timeout); } @@ -871,7 +871,7 @@ static void handle_child_sa_failure(private_child_create_t *this, /* we delay the delete for 100ms, as the IKE_AUTH response must arrive * first */ DBG1(DBG_IKE, "closing IKE_SA due CHILD_SA setup failure"); - charon->scheduler->schedule_job_ms(charon->scheduler, (job_t*) + lib->scheduler->schedule_job_ms(lib->scheduler, (job_t*) delete_ike_sa_job_create(this->ike_sa->get_id(this->ike_sa), TRUE), 100); } diff --git a/src/libcharon/sa/tasks/child_delete.c b/src/libcharon/sa/tasks/child_delete.c index b0cd30e1e..45e97e4cd 100644 --- a/src/libcharon/sa/tasks/child_delete.c +++ b/src/libcharon/sa/tasks/child_delete.c @@ -117,11 +117,10 @@ static void build_payloads(private_child_delete_t *this, message_t *message) */ static void process_payloads(private_child_delete_t *this, message_t *message) { - enumerator_t *payloads; - iterator_t *spis; + enumerator_t *payloads, *spis; payload_t *payload; delete_payload_t *delete_payload; - u_int32_t *spi; + u_int32_t spi; protocol_id_t protocol; child_sa_t *child_sa; @@ -136,19 +135,19 @@ static void process_payloads(private_child_delete_t *this, message_t *message) { continue; } - spis = delete_payload->create_spi_iterator(delete_payload); - while (spis->iterate(spis, (void**)&spi)) + spis = delete_payload->create_spi_enumerator(delete_payload); + while (spis->enumerate(spis, &spi)) { child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol, - *spi, FALSE); + spi, FALSE); if (child_sa == NULL) { DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI %.8x, " - "but no such SA", protocol_id_names, protocol, ntohl(*spi)); + "but no such SA", protocol_id_names, protocol, ntohl(spi)); continue; } DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI %.8x", - protocol_id_names, protocol, ntohl(*spi)); + protocol_id_names, protocol, ntohl(spi)); switch (child_sa->get_state(child_sa)) { @@ -161,7 +160,7 @@ static void process_payloads(private_child_delete_t *this, message_t *message) if (!this->initiator) { this->ike_sa->destroy_child_sa(this->ike_sa, - protocol, *spi); + protocol, spi); continue; } case CHILD_INSTALLED: diff --git a/src/libcharon/sa/tasks/child_rekey.c b/src/libcharon/sa/tasks/child_rekey.c index fb3452efd..fdaaea4b8 100644 --- a/src/libcharon/sa/tasks/child_rekey.c +++ b/src/libcharon/sa/tasks/child_rekey.c @@ -75,6 +75,15 @@ struct private_child_rekey_t { * colliding task, may be delete or rekey */ task_t *collision; + + /** + * Indicate that peer destroyed the redundant child from collision. + * This happens if a peer's delete notification for the redundant + * child gets processed before the rekey job. If so, we must not + * touch the child created in the collision since it points to + * memory already freed. + */ + bool other_child_destroyed; }; /** @@ -239,9 +248,13 @@ static child_sa_t *handle_collision(private_child_rekey_t *this) DBG1(DBG_IKE, "CHILD_SA rekey collision won, " "deleting rekeyed child"); to_delete = this->child_sa; - /* disable close action for the redundand child */ - child_sa = other->child_create->get_child(other->child_create); - child_sa->set_close_action(child_sa, ACTION_NONE); + /* don't touch child other created, it has already been deleted */ + if (!this->other_child_destroyed) + { + /* disable close action for the redundand child */ + child_sa = other->child_create->get_child(other->child_create); + child_sa->set_close_action(child_sa, ACTION_NONE); + } } else { @@ -286,7 +299,7 @@ static status_t process_i(private_child_rekey_t *this, message_t *message) DBG1(DBG_IKE, "peer seems to not support CHILD_SA rekeying, " "starting reauthentication"); this->child_sa->set_state(this->child_sa, CHILD_INSTALLED); - charon->processor->queue_job(charon->processor, + lib->processor->queue_job(lib->processor, (job_t*)rekey_ike_sa_job_create( this->ike_sa->get_id(this->ike_sa), TRUE)); return SUCCESS; @@ -316,7 +329,7 @@ static status_t process_i(private_child_rekey_t *this, message_t *message) DBG1(DBG_IKE, "CHILD_SA rekeying failed, " "trying again in %d seconds", retry); this->child_sa->set_state(this->child_sa, CHILD_INSTALLED); - charon->scheduler->schedule_job(charon->scheduler, job, retry); + lib->scheduler->schedule_job(lib->scheduler, job, retry); } return SUCCESS; } @@ -380,6 +393,13 @@ static void collide(private_child_rekey_t *this, task_t *other) else if (other->get_type(other) == CHILD_DELETE) { child_delete_t *del = (child_delete_t*)other; + if (del->get_child(del) == this->child_create->get_child(this->child_create)) + { + /* peer deletes redundant child created in collision */ + this->other_child_destroyed = TRUE; + other->destroy(other); + return; + } if (del == NULL || del->get_child(del) != this->child_sa) { /* not the same child => no collision */ @@ -466,6 +486,7 @@ child_rekey_t *child_rekey_create(ike_sa_t *ike_sa, protocol_id_t protocol, this->spi = spi; this->collision = NULL; this->child_delete = NULL; + this->other_child_destroyed = FALSE; return &this->public; } diff --git a/src/libcharon/sa/tasks/ike_auth.c b/src/libcharon/sa/tasks/ike_auth.c index a954782f2..b440ec811 100644 --- a/src/libcharon/sa/tasks/ike_auth.c +++ b/src/libcharon/sa/tasks/ike_auth.c @@ -481,9 +481,8 @@ static status_t process_r(private_ike_auth_t *this, message_t *message) { this->ike_sa->enable_extension(this->ike_sa, EXT_MULTIPLE_AUTH); } - if (this->ike_sa->supports_extension(this->ike_sa, EXT_STRONGSWAN) && - message->get_notify(message, EAP_ONLY_AUTHENTICATION)) - { /* EAP-only has no official notify, accept only from strongSwan */ + if (message->get_notify(message, EAP_ONLY_AUTHENTICATION)) + { this->ike_sa->enable_extension(this->ike_sa, EXT_EAP_ONLY_AUTHENTICATION); } @@ -538,6 +537,11 @@ static status_t process_r(private_ike_auth_t *this, message_t *message) { cfg->add(cfg, AUTH_RULE_EAP_IDENTITY, id->clone(id)); } + id = (identification_t*)cand->get(cand, AUTH_RULE_AAA_IDENTITY); + if (id) + { + cfg->add(cfg, AUTH_RULE_AAA_IDENTITY, id->clone(id)); + } } /* verify authentication data */ @@ -821,7 +825,7 @@ static status_t process_i(private_ike_auth_t *this, message_t *message) break; default: { - if (type < 16383) + if (type <= 16383) { DBG1(DBG_IKE, "received %N notify error", notify_type_names, type); diff --git a/src/libcharon/sa/tasks/ike_init.c b/src/libcharon/sa/tasks/ike_init.c index 38fb572f4..dd4a5f5c0 100644 --- a/src/libcharon/sa/tasks/ike_init.c +++ b/src/libcharon/sa/tasks/ike_init.c @@ -468,7 +468,7 @@ static status_t process_i(private_ike_init_t *this, message_t *message) } default: { - if (type < 16383) + if (type <= 16383) { DBG1(DBG_IKE, "received %N notify error", notify_type_names, type); diff --git a/src/libcharon/sa/tasks/ike_me.c b/src/libcharon/sa/tasks/ike_me.c index 2d2847ae0..1de6ae8fc 100644 --- a/src/libcharon/sa/tasks/ike_me.c +++ b/src/libcharon/sa/tasks/ike_me.c @@ -17,6 +17,7 @@ #include <string.h> +#include <hydra.h> #include <daemon.h> #include <config/peer_cfg.h> #include <encoding/payloads/id_payload.h> @@ -134,8 +135,8 @@ static void gather_and_add_endpoints(private_ike_me_t *this, message_t *message) host = this->ike_sa->get_my_host(this->ike_sa); port = host->get_port(host); - enumerator = charon->kernel_interface->create_address_enumerator( - charon->kernel_interface, FALSE, FALSE); + enumerator = hydra->kernel_interface->create_address_enumerator( + hydra->kernel_interface, FALSE, FALSE); while (enumerator->enumerate(enumerator, (void**)&addr)) { host = addr->clone(addr); @@ -454,6 +455,9 @@ static status_t process_i(private_ike_me_t *this, message_t *message) DBG1(DBG_IKE, "server did not return a ME_MEDIATION, aborting"); return FAILED; } + /* if we are on a mediation connection we switch to port 4500 even + * if no NAT is detected. */ + this->ike_sa->float_ports(this->ike_sa); return NEED_MORE; } case IKE_AUTH: @@ -689,7 +693,7 @@ static status_t build_r_ms(private_ike_me_t *this, message_t *message) job_t *job = (job_t*)mediation_job_create(this->peer_id, this->ike_sa->get_other_id(this->ike_sa), this->connect_id, this->connect_key, this->remote_endpoints, this->response); - charon->processor->queue_job(charon->processor, job); + lib->processor->queue_job(lib->processor, job); break; } default: diff --git a/src/libcharon/sa/tasks/ike_mobike.c b/src/libcharon/sa/tasks/ike_mobike.c index a62886f02..5b12eaaac 100644 --- a/src/libcharon/sa/tasks/ike_mobike.c +++ b/src/libcharon/sa/tasks/ike_mobike.c @@ -17,6 +17,7 @@ #include <string.h> +#include <hydra.h> #include <daemon.h> #include <sa/tasks/ike_natd.h> #include <encoding/payloads/notify_payload.h> @@ -70,6 +71,11 @@ struct private_ike_mobike_t { * include address list update */ bool address; + + /** + * additional addresses got updated + */ + bool addresses_updated; }; /** @@ -153,6 +159,7 @@ static void process_payloads(private_ike_mobike_t *this, message_t *message) host = host_create_from_chunk(family, data, 0); DBG2(DBG_IKE, "got additional MOBIKE peer address: %H", host); this->ike_sa->add_additional_address(this->ike_sa, host); + this->addresses_updated = TRUE; break; } case UPDATE_SA_ADDRESSES: @@ -163,6 +170,7 @@ static void process_payloads(private_ike_mobike_t *this, message_t *message) case NO_ADDITIONAL_ADDRESSES: { flush_additional_addresses(this); + this->addresses_updated = TRUE; break; } case NAT_DETECTION_SOURCE_IP: @@ -193,8 +201,8 @@ static void build_address_list(private_ike_mobike_t *this, message_t *message) int added = 0; me = this->ike_sa->get_my_host(this->ike_sa); - enumerator = charon->kernel_interface->create_address_enumerator( - charon->kernel_interface, FALSE, FALSE); + enumerator = hydra->kernel_interface->create_address_enumerator( + hydra->kernel_interface, FALSE, FALSE); while (enumerator->enumerate(enumerator, (void**)&host)) { if (me->ip_equals(me, host)) @@ -269,32 +277,23 @@ static void update_children(private_ike_mobike_t *this) } /** - * Apply port of old address if it equals new, port otherwise + * Apply the port of the old host, if its ip equals the new, use port otherwise. */ -static void apply_port(private_ike_mobike_t *this, host_t *host, host_t *old, - u_int16_t port) +static void apply_port(host_t *host, host_t *old, u_int16_t port) { if (host->ip_equals(host, old)) { - host->set_port(host, old->get_port(old)); + port = old->get_port(old); } - else + else if (port == IKEV2_UDP_PORT) { - if (port == IKEV2_UDP_PORT) - { - host->set_port(host, IKEV2_NATT_PORT); - } - else - { - host->set_port(host, port); - } + port = IKEV2_NATT_PORT; } + host->set_port(host, port); } -/** - * Implementation of ike_mobike_t.transmit - */ -static void transmit(private_ike_mobike_t *this, packet_t *packet) +METHOD(ike_mobike_t, transmit, void, + private_ike_mobike_t *this, packet_t *packet) { host_t *me, *other, *me_old, *other_old; iterator_t *iterator; @@ -310,11 +309,11 @@ static void transmit(private_ike_mobike_t *this, packet_t *packet) other_old = this->ike_sa->get_other_host(this->ike_sa); ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa); - me = charon->kernel_interface->get_source_addr( - charon->kernel_interface, other_old, NULL); + me = hydra->kernel_interface->get_source_addr( + hydra->kernel_interface, other_old, NULL); if (me) { - apply_port(this, me, me_old, ike_cfg->get_my_port(ike_cfg)); + apply_port(me, me_old, ike_cfg->get_my_port(ike_cfg)); DBG1(DBG_IKE, "checking original path %#H - %#H", me, other_old); copy = packet->clone(packet); copy->set_source(copy, me); @@ -324,8 +323,8 @@ static void transmit(private_ike_mobike_t *this, packet_t *packet) iterator = this->ike_sa->create_additional_address_iterator(this->ike_sa); while (iterator->iterate(iterator, (void**)&other)) { - me = charon->kernel_interface->get_source_addr( - charon->kernel_interface, other, NULL); + me = hydra->kernel_interface->get_source_addr( + hydra->kernel_interface, other, NULL); if (me) { if (me->get_family(me) != other->get_family(other)) @@ -334,9 +333,9 @@ static void transmit(private_ike_mobike_t *this, packet_t *packet) continue; } /* reuse port for an active address, 4500 otherwise */ - apply_port(this, me, me_old, ike_cfg->get_my_port(ike_cfg)); + apply_port(me, me_old, ike_cfg->get_my_port(ike_cfg)); other = other->clone(other); - apply_port(this, other, other_old, ike_cfg->get_other_port(ike_cfg)); + apply_port(other, other_old, ike_cfg->get_other_port(ike_cfg)); DBG1(DBG_IKE, "checking path %#H - %#H", me, other); copy = packet->clone(packet); copy->set_source(copy, me); @@ -347,12 +346,11 @@ static void transmit(private_ike_mobike_t *this, packet_t *packet) iterator->destroy(iterator); } -/** - * Implementation of task_t.process for initiator - */ -static status_t build_i(private_ike_mobike_t *this, message_t *message) +METHOD(task_t, build_i, status_t, + private_ike_mobike_t *this, message_t *message) { - if (message->get_message_id(message) == 1) + if (message->get_exchange_type(message) == IKE_AUTH && + message->get_message_id(message) == 1) { /* only in first IKE_AUTH */ message->add_notify(message, FALSE, MOBIKE_SUPPORTED, chunk_empty); build_address_list(this, message); @@ -363,7 +361,7 @@ static status_t build_i(private_ike_mobike_t *this, message_t *message) /* we check if the existing address is still valid */ old = message->get_source(message); - new = charon->kernel_interface->get_source_addr(charon->kernel_interface, + new = hydra->kernel_interface->get_source_addr(hydra->kernel_interface, message->get_destination(message), old); if (new) { @@ -379,11 +377,12 @@ static status_t build_i(private_ike_mobike_t *this, message_t *message) } if (this->update) { - message->add_notify(message, FALSE, UPDATE_SA_ADDRESSES, chunk_empty); + message->add_notify(message, FALSE, UPDATE_SA_ADDRESSES, + chunk_empty); build_cookie(this, message); update_children(this); } - if (this->address) + if (this->address && !this->check) { build_address_list(this, message); } @@ -395,12 +394,11 @@ static status_t build_i(private_ike_mobike_t *this, message_t *message) return NEED_MORE; } -/** - * Implementation of task_t.process for responder - */ -static status_t process_r(private_ike_mobike_t *this, message_t *message) +METHOD(task_t, process_r, status_t, + private_ike_mobike_t *this, message_t *message) { - if (message->get_message_id(message) == 1) + if (message->get_exchange_type(message) == IKE_AUTH && + message->get_message_id(message) == 1) { /* only first IKE_AUTH */ process_payloads(this, message); } @@ -421,14 +419,25 @@ static status_t process_r(private_ike_mobike_t *this, message_t *message) { this->natd->task.process(&this->natd->task, message); } + if (this->addresses_updated && this->ike_sa->has_condition(this->ike_sa, + COND_ORIGINAL_INITIATOR)) + { + host_t *other = message->get_source(message); + host_t *other_old = this->ike_sa->get_other_host(this->ike_sa); + if (!other->equals(other, other_old)) + { + DBG1(DBG_IKE, "remote address changed from %H to %H", other_old, + other); + this->ike_sa->set_other_host(this->ike_sa, other->clone(other)); + this->update = TRUE; + } + } } return NEED_MORE; } -/** - * Implementation of task_t.build for responder - */ -static status_t build_r(private_ike_mobike_t *this, message_t *message) +METHOD(task_t, build_r, status_t, + private_ike_mobike_t *this, message_t *message) { if (message->get_exchange_type(message) == IKE_AUTH && this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED) @@ -460,10 +469,8 @@ static status_t build_r(private_ike_mobike_t *this, message_t *message) return NEED_MORE; } -/** - * Implementation of task_t.process for initiator - */ -static status_t process_i(private_ike_mobike_t *this, message_t *message) +METHOD(task_t, process_i, status_t, + private_ike_mobike_t *this, message_t *message) { if (message->get_exchange_type(message) == IKE_AUTH && this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED) @@ -536,14 +543,22 @@ static status_t process_i(private_ike_mobike_t *this, message_t *message) } if (this->update) { - /* start the update with the same task */ - this->check = FALSE; - this->address = FALSE; - if (this->natd) - { - this->natd->task.destroy(&this->natd->task); + /* use the same task to ... */ + if (!this->ike_sa->has_condition(this->ike_sa, + COND_ORIGINAL_INITIATOR)) + { /*... send an updated list of addresses as responder */ + update_children(this); + this->update = FALSE; + } + else + { /* ... send the update as original initiator */ + if (this->natd) + { + this->natd->task.destroy(&this->natd->task); + } + this->natd = ike_natd_create(this->ike_sa, this->initiator); } - this->natd = ike_natd_create(this->ike_sa, this->initiator); + this->check = FALSE; this->ike_sa->set_pending_updates(this->ike_sa, 1); return NEED_MORE; } @@ -553,51 +568,48 @@ static status_t process_i(private_ike_mobike_t *this, message_t *message) return NEED_MORE; } -/** - * Implementation of ike_mobike_t.roam. - */ -static void roam(private_ike_mobike_t *this, bool address) +METHOD(ike_mobike_t, addresses, void, + private_ike_mobike_t *this) +{ + this->address = TRUE; + this->ike_sa->set_pending_updates(this->ike_sa, + this->ike_sa->get_pending_updates(this->ike_sa) + 1); +} + +METHOD(ike_mobike_t, roam, void, + private_ike_mobike_t *this, bool address) { this->check = TRUE; this->address = address; this->ike_sa->set_pending_updates(this->ike_sa, - this->ike_sa->get_pending_updates(this->ike_sa) + 1); + this->ike_sa->get_pending_updates(this->ike_sa) + 1); } -/** - * Implementation of ike_mobike_t.dpd - */ -static void dpd(private_ike_mobike_t *this) +METHOD(ike_mobike_t, dpd, void, + private_ike_mobike_t *this) { if (!this->natd) { this->natd = ike_natd_create(this->ike_sa, this->initiator); } - this->address = FALSE; this->ike_sa->set_pending_updates(this->ike_sa, - this->ike_sa->get_pending_updates(this->ike_sa) + 1); + this->ike_sa->get_pending_updates(this->ike_sa) + 1); } -/** - * Implementation of ike_mobike_t.is_probing. - */ -static bool is_probing(private_ike_mobike_t *this) +METHOD(ike_mobike_t, is_probing, bool, + private_ike_mobike_t *this) { return this->check; } -/** - * Implementation of task_t.get_type - */ -static task_type_t get_type(private_ike_mobike_t *this) +METHOD(task_t, get_type, task_type_t, + private_ike_mobike_t *this) { return IKE_MOBIKE; } -/** - * Implementation of task_t.migrate - */ -static void migrate(private_ike_mobike_t *this, ike_sa_t *ike_sa) +METHOD(task_t, migrate, void, + private_ike_mobike_t *this, ike_sa_t *ike_sa) { chunk_free(&this->cookie2); this->ike_sa = ike_sa; @@ -607,10 +619,8 @@ static void migrate(private_ike_mobike_t *this, ike_sa_t *ike_sa) } } -/** - * Implementation of task_t.destroy - */ -static void destroy(private_ike_mobike_t *this) +METHOD(task_t, destroy, void, + private_ike_mobike_t *this) { chunk_free(&this->cookie2); if (this->natd) @@ -625,35 +635,36 @@ static void destroy(private_ike_mobike_t *this) */ ike_mobike_t *ike_mobike_create(ike_sa_t *ike_sa, bool initiator) { - private_ike_mobike_t *this = malloc_thing(private_ike_mobike_t); - - this->public.roam = (void(*)(ike_mobike_t*,bool))roam; - this->public.dpd = (void(*)(ike_mobike_t*))dpd; - this->public.transmit = (void(*)(ike_mobike_t*,packet_t*))transmit; - this->public.is_probing = (bool(*)(ike_mobike_t*))is_probing; - this->public.task.get_type = (task_type_t(*)(task_t*))get_type; - this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate; - this->public.task.destroy = (void(*)(task_t*))destroy; + private_ike_mobike_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + .addresses = _addresses, + .roam = _roam, + .dpd = _dpd, + .transmit = _transmit, + .is_probing = _is_probing, + }, + .ike_sa = ike_sa, + .initiator = initiator, + ); if (initiator) { - this->public.task.build = (status_t(*)(task_t*,message_t*))build_i; - this->public.task.process = (status_t(*)(task_t*,message_t*))process_i; + this->public.task.build = _build_i; + this->public.task.process = _process_i; } else { - this->public.task.build = (status_t(*)(task_t*,message_t*))build_r; - this->public.task.process = (status_t(*)(task_t*,message_t*))process_r; + this->public.task.build = _build_r; + this->public.task.process = _process_r; } - this->ike_sa = ike_sa; - this->initiator = initiator; - this->update = FALSE; - this->check = FALSE; - this->address = TRUE; - this->cookie2 = chunk_empty; - this->natd = NULL; - return &this->public; } diff --git a/src/libcharon/sa/tasks/ike_mobike.h b/src/libcharon/sa/tasks/ike_mobike.h index 05b2224d1..16611939e 100644 --- a/src/libcharon/sa/tasks/ike_mobike.h +++ b/src/libcharon/sa/tasks/ike_mobike.h @@ -46,6 +46,11 @@ struct ike_mobike_t { task_t task; /** + * Use the task to update the list of additional addresses. + */ + void (*addresses)(ike_mobike_t *this); + + /** * Use the task to roam to other addresses. * * @param address TRUE to include address list update diff --git a/src/libcharon/sa/tasks/ike_natd.c b/src/libcharon/sa/tasks/ike_natd.c index 9ea20ba36..7839b52eb 100644 --- a/src/libcharon/sa/tasks/ike_natd.c +++ b/src/libcharon/sa/tasks/ike_natd.c @@ -18,6 +18,7 @@ #include <string.h> +#include <hydra.h> #include <daemon.h> #include <config/peer_cfg.h> #include <crypto/hashers/hasher.h> @@ -265,41 +266,15 @@ static status_t process_i(private_ike_natd_t *this, message_t *message) if (message->get_exchange_type(message) == IKE_SA_INIT) { peer_cfg_t *peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); - -#ifdef ME - /* if we are on a mediated connection we have already switched to - * port 4500 and the correct destination port is already configured, - * therefore we must not switch again */ - if (peer_cfg->get_mediated_by(peer_cfg)) - { - return SUCCESS; - } -#endif /* ME */ - if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY) || -#ifdef ME - /* if we are on a mediation connection we switch to port 4500 even - * if no NAT is detected. */ - peer_cfg->is_mediation(peer_cfg) || -#endif /* ME */ /* if peer supports NAT-T, we switch to port 4500 even - * if no NAT is detected. MOBIKE requires this. */ + * if no NAT is detected. can't be done later (when we would know + * whether the peer supports MOBIKE) because there would be no + * exchange to actually do the switch (other than a forced DPD). */ (peer_cfg->use_mobike(peer_cfg) && this->ike_sa->supports_extension(this->ike_sa, EXT_NATT))) { - host_t *me, *other; - - /* do not switch if we have a custom port from mobike/NAT */ - me = this->ike_sa->get_my_host(this->ike_sa); - if (me->get_port(me) == IKEV2_UDP_PORT) - { - me->set_port(me, IKEV2_NATT_PORT); - } - other = this->ike_sa->get_other_host(this->ike_sa); - if (other->get_port(other) == IKEV2_UDP_PORT) - { - other->set_port(other, IKEV2_NATT_PORT); - } + this->ike_sa->float_ports(this->ike_sa); } } @@ -342,7 +317,7 @@ static status_t build_i(private_ike_natd_t *this, message_t *message) } else { - host = charon->kernel_interface->get_source_addr(charon->kernel_interface, + host = hydra->kernel_interface->get_source_addr(hydra->kernel_interface, this->ike_sa->get_other_host(this->ike_sa), NULL); if (host) { /* 2. */ @@ -353,8 +328,8 @@ static status_t build_i(private_ike_natd_t *this, message_t *message) } else { /* 3. */ - enumerator = charon->kernel_interface->create_address_enumerator( - charon->kernel_interface, FALSE, FALSE); + enumerator = hydra->kernel_interface->create_address_enumerator( + hydra->kernel_interface, FALSE, FALSE); while (enumerator->enumerate(enumerator, (void**)&host)) { /* apply port 500 to host, but work on a copy */ diff --git a/src/libcharon/sa/tasks/ike_rekey.c b/src/libcharon/sa/tasks/ike_rekey.c index a2275e796..1a6c140c4 100644 --- a/src/libcharon/sa/tasks/ike_rekey.c +++ b/src/libcharon/sa/tasks/ike_rekey.c @@ -196,7 +196,7 @@ static status_t process_i(private_ike_rekey_t *this, message_t *message) DBG1(DBG_IKE, "peer seems to not support IKE rekeying, " "starting reauthentication"); this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); - charon->processor->queue_job(charon->processor, + lib->processor->queue_job(lib->processor, (job_t*)rekey_ike_sa_job_create( this->ike_sa->get_id(this->ike_sa), TRUE)); return SUCCESS; @@ -217,7 +217,7 @@ static status_t process_i(private_ike_rekey_t *this, message_t *message) DBG1(DBG_IKE, "IKE_SA rekeying failed, " "trying again in %d seconds", retry); this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); - charon->scheduler->schedule_job(charon->scheduler, job, retry); + lib->scheduler->schedule_job(lib->scheduler, job, retry); } return SUCCESS; case NEED_MORE: @@ -241,51 +241,56 @@ static status_t process_i(private_ike_rekey_t *this, message_t *message) if (this->collision && this->collision->get_type(this->collision) == IKE_REKEY) { - chunk_t this_nonce, other_nonce; - host_t *host; private_ike_rekey_t *other = (private_ike_rekey_t*)this->collision; - this_nonce = this->ike_init->get_lower_nonce(this->ike_init); - other_nonce = other->ike_init->get_lower_nonce(other->ike_init); - - /* if we have the lower nonce, delete rekeyed SA. If not, delete - * the redundant. */ - if (memcmp(this_nonce.ptr, other_nonce.ptr, - min(this_nonce.len, other_nonce.len)) < 0) - { - /* peer should delete this SA. Add a timeout just in case. */ - job_t *job = (job_t*)delete_ike_sa_job_create( - other->new_sa->get_id(other->new_sa), TRUE); - charon->scheduler->schedule_job(charon->scheduler, job, 10); - DBG1(DBG_IKE, "IKE_SA rekey collision won, deleting rekeyed IKE_SA"); - charon->ike_sa_manager->checkin(charon->ike_sa_manager, other->new_sa); - other->new_sa = NULL; - } - else + /* ike_init can be NULL, if child_sa is half-open */ + if (other->ike_init) { - DBG1(DBG_IKE, "IKE_SA rekey collision lost, deleting redundant IKE_SA"); - /* apply host for a proper delete */ - host = this->ike_sa->get_my_host(this->ike_sa); - this->new_sa->set_my_host(this->new_sa, host->clone(host)); - host = this->ike_sa->get_other_host(this->ike_sa); - this->new_sa->set_other_host(this->new_sa, host->clone(host)); - this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); - if (this->new_sa->delete(this->new_sa) == DESTROY_ME) + host_t *host; + chunk_t this_nonce, other_nonce; + + this_nonce = this->ike_init->get_lower_nonce(this->ike_init); + other_nonce = other->ike_init->get_lower_nonce(other->ike_init); + + /* if we have the lower nonce, delete rekeyed SA. If not, delete + * the redundant. */ + if (memcmp(this_nonce.ptr, other_nonce.ptr, + min(this_nonce.len, other_nonce.len)) < 0) { - charon->ike_sa_manager->checkin_and_destroy( - charon->ike_sa_manager, this->new_sa); + /* peer should delete this SA. Add a timeout just in case. */ + job_t *job = (job_t*)delete_ike_sa_job_create( + other->new_sa->get_id(other->new_sa), TRUE); + lib->scheduler->schedule_job(lib->scheduler, job, 10); + DBG1(DBG_IKE, "IKE_SA rekey collision won, deleting rekeyed IKE_SA"); + charon->ike_sa_manager->checkin(charon->ike_sa_manager, other->new_sa); + other->new_sa = NULL; } else { - charon->ike_sa_manager->checkin( - charon->ike_sa_manager, this->new_sa); + DBG1(DBG_IKE, "IKE_SA rekey collision lost, deleting redundant IKE_SA"); + /* apply host for a proper delete */ + host = this->ike_sa->get_my_host(this->ike_sa); + this->new_sa->set_my_host(this->new_sa, host->clone(host)); + host = this->ike_sa->get_other_host(this->ike_sa); + this->new_sa->set_other_host(this->new_sa, host->clone(host)); + this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); + if (this->new_sa->delete(this->new_sa) == DESTROY_ME) + { + charon->ike_sa_manager->checkin_and_destroy( + charon->ike_sa_manager, this->new_sa); + } + else + { + charon->ike_sa_manager->checkin( + charon->ike_sa_manager, this->new_sa); + } + /* set threads active IKE_SA after checkin */ + charon->bus->set_sa(charon->bus, this->ike_sa); + /* inherit to other->new_sa in destroy() */ + this->new_sa = other->new_sa; + other->new_sa = NULL; + return SUCCESS; } - /* set threads active IKE_SA after checkin */ - charon->bus->set_sa(charon->bus, this->ike_sa); - /* inherit to other->new_sa in destroy() */ - this->new_sa = other->new_sa; - other->new_sa = NULL; - return SUCCESS; } /* set threads active IKE_SA after checkin */ charon->bus->set_sa(charon->bus, this->ike_sa); diff --git a/src/libcharon/sa/tasks/ike_vendor.c b/src/libcharon/sa/tasks/ike_vendor.c index 7c435b6d1..1c14ee06b 100644 --- a/src/libcharon/sa/tasks/ike_vendor.c +++ b/src/libcharon/sa/tasks/ike_vendor.c @@ -123,12 +123,14 @@ ike_vendor_t *ike_vendor_create(ike_sa_t *ike_sa, bool initiator) private_ike_vendor_t *this; INIT(this, - .public.task = { - .build = _build, - .process = _process, - .migrate = _migrate, - .get_type = _get_type, - .destroy = _destroy, + .public = { + .task = { + .build = _build, + .process = _process, + .migrate = _migrate, + .get_type = _get_type, + .destroy = _destroy, + }, }, .initiator = initiator, .ike_sa = ike_sa, diff --git a/src/libcharon/sa/trap_manager.c b/src/libcharon/sa/trap_manager.c index 80bf647cd..f91eff077 100644 --- a/src/libcharon/sa/trap_manager.c +++ b/src/libcharon/sa/trap_manager.c @@ -15,6 +15,7 @@ #include "trap_manager.h" +#include <hydra.h> #include <daemon.h> #include <threading/rwlock.h> #include <utils/linked_list.h> @@ -138,8 +139,8 @@ static u_int32_t install(private_trap_manager_t *this, peer_cfg_t *peer, if (!me || me->is_anyaddr(me)) { DESTROY_IF(me); - me = charon->kernel_interface->get_source_addr( - charon->kernel_interface, other, NULL); + me = hydra->kernel_interface->get_source_addr( + hydra->kernel_interface, other, NULL); if (!me) { DBG1(DBG_CFG, "installing trap failed, local address unknown"); |