diff options
28 files changed, 1060 insertions, 894 deletions
diff --git a/src/charon/config/connections/connection.c b/src/charon/config/connections/connection.c index 3de57ca80..e1ab0392d 100644 --- a/src/charon/config/connections/connection.c +++ b/src/charon/config/connections/connection.c @@ -59,6 +59,11 @@ struct private_connection_t { * Public part */ connection_t public; + + /** + * Number of references hold by others to this connection + */ + u_int refcount; /** * Name of the connection @@ -155,24 +160,6 @@ static host_t *get_other_host (private_connection_t *this) } /** - * Implementation of connection_t.update_my_host. - */ -static void update_my_host(private_connection_t *this, host_t *my_host) -{ - this->my_host->destroy(this->my_host); - this->my_host = my_host; -} - -/** - * Implementation of connection_t.update_other_host. - */ -static void update_other_host(private_connection_t *this, host_t *other_host) -{ - this->other_host->destroy(this->other_host); - this->other_host = other_host; -} - -/** * Implementation of connection_t.get_proposals. */ static linked_list_t* get_proposals(private_connection_t *this) @@ -288,31 +275,11 @@ static bool check_dh_group(private_connection_t *this, diffie_hellman_group_t dh } /** - * Implementation of connection_t.clone. + * Implementation of connection_t.get_ref. */ -static connection_t *clone(private_connection_t *this) +static void get_ref(private_connection_t *this) { - iterator_t *iterator; - proposal_t *proposal; - private_connection_t *clone = (private_connection_t*)connection_create( - this->name, this->ikev2, - this->cert_policy, - this->certreq_policy, - this->my_host->clone(this->my_host), - this->other_host->clone(this->other_host), - this->auth_method); - - /* clone all proposals */ - iterator = this->proposals->create_iterator(this->proposals, TRUE); - while (iterator->has_next(iterator)) - { - iterator->current(iterator, (void**)&proposal); - proposal = proposal->clone(proposal); - clone->proposals->insert_last(clone->proposals, (void*)proposal); - } - iterator->destroy(iterator); - - return &clone->public; + this->refcount++; } /** @@ -320,18 +287,21 @@ static connection_t *clone(private_connection_t *this) */ static void destroy(private_connection_t *this) { - proposal_t *proposal; - - while (this->proposals->remove_last(this->proposals, (void**)&proposal) == SUCCESS) + if (--this->refcount == 0) { - proposal->destroy(proposal); + proposal_t *proposal; + + while (this->proposals->remove_last(this->proposals, (void**)&proposal) == SUCCESS) + { + proposal->destroy(proposal); + } + this->proposals->destroy(this->proposals); + + this->my_host->destroy(this->my_host); + this->other_host->destroy(this->other_host); + free(this->name); + free(this); } - this->proposals->destroy(this->proposals); - - this->my_host->destroy(this->my_host); - this->other_host->destroy(this->other_host); - free(this->name); - free(this); } /** @@ -344,15 +314,13 @@ connection_t * connection_create(char *name, bool ikev2, auth_method_t auth_method) { private_connection_t *this = malloc_thing(private_connection_t); - + /* public functions */ this->public.get_name = (char*(*)(connection_t*))get_name; this->public.is_ikev2 = (bool(*)(connection_t*))is_ikev2; this->public.get_cert_policy = (cert_policy_t(*)(connection_t*))get_cert_policy; this->public.get_certreq_policy = (cert_policy_t(*)(connection_t*))get_certreq_policy; this->public.get_my_host = (host_t*(*)(connection_t*))get_my_host; - this->public.update_my_host = (void(*)(connection_t*,host_t*))update_my_host; - this->public.update_other_host = (void(*)(connection_t*,host_t*))update_other_host; this->public.get_other_host = (host_t*(*)(connection_t*))get_other_host; this->public.get_proposals = (linked_list_t*(*)(connection_t*))get_proposals; this->public.select_proposal = (proposal_t*(*)(connection_t*,linked_list_t*))select_proposal; @@ -360,10 +328,11 @@ connection_t * connection_create(char *name, bool ikev2, this->public.get_auth_method = (auth_method_t(*)(connection_t*)) get_auth_method; this->public.get_dh_group = (diffie_hellman_group_t(*)(connection_t*)) get_dh_group; this->public.check_dh_group = (bool(*)(connection_t*,diffie_hellman_group_t)) check_dh_group; - this->public.clone = (connection_t*(*)(connection_t*))clone; + this->public.get_ref = (void(*)(connection_t*))get_ref; this->public.destroy = (void(*)(connection_t*))destroy; /* private variables */ + this->refcount = 1; this->name = strdup(name); this->ikev2 = ikev2; this->cert_policy = cert_policy; @@ -373,6 +342,6 @@ connection_t * connection_create(char *name, bool ikev2, this->auth_method = auth_method; this->proposals = linked_list_create(); - - return (&this->public); + + return &this->public; } diff --git a/src/charon/config/connections/connection.h b/src/charon/config/connections/connection.h index dca570e05..111acd5e1 100644 --- a/src/charon/config/connections/connection.h +++ b/src/charon/config/connections/connection.h @@ -130,30 +130,6 @@ struct connection_t { * @return host information as host_t object */ host_t *(*get_other_host) (connection_t *this); - - /** - * @brief Update address of my host. - * - * It may be necessary to uptdate own address, as it - * is set to the default route (0.0.0.0) in some cases. - * Old host is destroyed, new one NOT cloned. - * - * @param this calling object - * @param my_host new host to set as my_host - */ - void (*update_my_host) (connection_t *this, host_t *my_host); - - /** - * @brief Update address of remote host. - * - * It may be necessary to uptdate remote address, as a - * connection may define %any (0.0.0.0) or a subnet. - * Old host is destroyed, new one NOT cloned. - * - * @param this calling object - * @param my_host new host to set as other_host - */ - void (*update_other_host) (connection_t *this, host_t *other_host); /** * @brief Returns a list of all supported proposals. @@ -227,7 +203,7 @@ struct connection_t { * the peer. It should be ommited when CERT_SEND_NEVER, sended otherwise. * * @param this calling object - * @return - TRUE, if certificate request should be sent + * @return certificate request sending policy */ cert_policy_t (*get_certreq_policy) (connection_t *this); @@ -261,16 +237,21 @@ struct connection_t { bool (*check_dh_group) (connection_t *this, diffie_hellman_group_t dh_group); /** - * @brief Clone a connection_t object. - * - * @param this connection to clone - * @return clone of it + * @brief Get a new reference to this connection. + * + * Get a new reference to this connection by increasing + * it's internal reference counter. + * + * @param this calling object */ - connection_t *(*clone) (connection_t *this); + void (*get_ref) (connection_t *this); /** * @brief Destroys a connection_t object. * + * Decrements the internal reference counter and + * destroys the connection when it reaches zero. + * * @param this calling object */ void (*destroy) (connection_t *this); @@ -278,7 +259,7 @@ struct connection_t { /** * @brief Creates a connection_t object. - * + * * Supplied hosts become owned by connection, so * do not modify or destroy them after a call to * connection_create(). Name gets cloned internally. diff --git a/src/charon/config/connections/local_connection_store.c b/src/charon/config/connections/local_connection_store.c index c6e982e23..1f961cbcc 100644 --- a/src/charon/config/connections/local_connection_store.c +++ b/src/charon/config/connections/local_connection_store.c @@ -116,7 +116,7 @@ static connection_t *get_connection_by_hosts(private_local_connection_store_t *t { found = candidate; best_prio = prio; - } + } } } iterator->destroy(iterator); @@ -132,13 +132,9 @@ static connection_t *get_connection_by_hosts(private_local_connection_store_t *t found_my_host->get_string(found_my_host), found_other_host->get_string(found_other_host), best_prio); - - found = found->clone(found); - if (best_prio & PRIO_ADDR_ANY) - { - /* replace %any by the peer's address */ - found->update_other_host(found, other_host->clone(other_host)); - } + + /* give out a new reference to it */ + found->get_ref(found); } pthread_mutex_unlock(&(this->mutex)); return found; @@ -159,13 +155,15 @@ static connection_t *get_connection_by_name(private_local_connection_store_t *th iterator->current(iterator, (void**)¤t); if (strcmp(name, current->get_name(current)) == 0) { - found = current->clone(current); + found = current; break; } } iterator->destroy(iterator); pthread_mutex_unlock(&(this->mutex)); + /* get a new reference for it */ + found->get_ref(found); return found; } diff --git a/src/charon/config/policies/local_policy_store.c b/src/charon/config/policies/local_policy_store.c index 2054b9df5..0c3e0ee04 100644 --- a/src/charon/config/policies/local_policy_store.c +++ b/src/charon/config/policies/local_policy_store.c @@ -67,9 +67,42 @@ static void add_policy(private_local_policy_store_t *this, policy_t *policy) } /** - * Implementation of policy_store_t.get_policy_by_ids. + * Check if a policy contains traffic selectors */ -static policy_t *get_policy_by_ids(private_local_policy_store_t *this, identification_t *my_id, identification_t *other_id) +static bool contains_traffic_selectors(policy_t *policy, bool mine, + linked_list_t *ts, host_t *host) +{ + linked_list_t *selected; + bool contains = FALSE; + traffic_selector_t *to; + + if (mine) + { + selected = policy->select_my_traffic_selectors(policy, ts, host); + } + else + { + selected = policy->select_other_traffic_selectors(policy, ts, host); + } + if (selected->get_count(selected)) + { + contains = TRUE; + } + while (selected->remove_last(selected, (void**)&to) == SUCCESS) + { + to->destroy(to); + } + selected->destroy(selected); + return contains; +} + +/** + * Implementation of policy_store_t.get_policy. + */ +static policy_t *get_policy(private_local_policy_store_t *this, + identification_t *my_id, identification_t *other_id, + linked_list_t *my_ts, linked_list_t *other_ts, + host_t *my_host, host_t *other_host) { typedef enum { PRIO_UNDEFINED = 0x00, @@ -111,9 +144,22 @@ static policy_t *get_policy_by_ids(private_local_policy_store_t *this, identific { prio = PRIO_ID_MATCH - wildcards; } + + /* only accept if traffic selectors match */ + if (!contains_traffic_selectors(candidate, TRUE, my_ts, my_host) || + !contains_traffic_selectors(candidate, FALSE, other_ts, other_host)) + { + this->logger->log(this->logger, CONTROL|LEVEL2, + "candidate '%s' inacceptable due traffic selector mismatch", + candidate->get_name(candidate), + candidate_my_id->get_string(candidate_my_id), + candidate_other_id->get_string(candidate_other_id), + prio); + continue; + } this->logger->log(this->logger, CONTROL|LEVEL2, - "candidate policy \"%s\": %s...%s (prio=%d)", + "candidate policy '%s': %s...%s (prio=%d)", candidate->get_name(candidate), candidate_my_id->get_string(candidate_my_id), candidate_other_id->get_string(candidate_other_id), @@ -134,18 +180,13 @@ static policy_t *get_policy_by_ids(private_local_policy_store_t *this, identific identification_t *found_other_id = found->get_other_id(found); this->logger->log(this->logger, CONTROL|LEVEL1, - "found matching policy \"%s\": %s...%s (prio=%d)", + "found matching policy '%s': %s...%s (prio=%d)", found->get_name(found), found_my_id->get_string(found_my_id), found_other_id->get_string(found_other_id), best_prio); - - found = found->clone(found); - if (best_prio != PRIO_ID_MATCH) - { - /* replace %any/wildcards by the peer's address */ - found->update_other_id(found, other_id->clone(other_id)); - } + /* give out a new reference to it */ + found->get_ref(found); } pthread_mutex_unlock(&(this->mutex)); return found; @@ -168,12 +209,14 @@ static policy_t *get_policy_by_name(private_local_policy_store_t *this, char *na iterator->current(iterator, (void **)¤t); if (strcmp(current->get_name(current), name) == 0) { - found = current->clone(current); + found = current; } } iterator->destroy(iterator); pthread_mutex_unlock(&(this->mutex)); + /* give out a new reference */ + found->get_ref(found); return found; } @@ -234,7 +277,7 @@ local_policy_store_t *local_policy_store_create(void) private_local_policy_store_t *this = malloc_thing(private_local_policy_store_t); this->public.policy_store.add_policy = (void(*)(policy_store_t*,policy_t*))add_policy; - this->public.policy_store.get_policy_by_ids = (policy_t*(*)(policy_store_t*,identification_t*,identification_t*))get_policy_by_ids; + this->public.policy_store.get_policy = (policy_t*(*)(policy_store_t*,identification_t*,identification_t*,linked_list_t*,linked_list_t*,host_t*,host_t*))get_policy; this->public.policy_store.get_policy_by_name = (policy_t*(*)(policy_store_t*,char*))get_policy_by_name; this->public.policy_store.delete_policy = (status_t(*)(policy_store_t*,char*))delete_policy; this->public.policy_store.destroy = (void(*)(policy_store_t*))destroy; diff --git a/src/charon/config/policies/policy.c b/src/charon/config/policies/policy.c index 152c157a8..a64af3271 100644 --- a/src/charon/config/policies/policy.c +++ b/src/charon/config/policies/policy.c @@ -44,6 +44,11 @@ struct private_policy_t { policy_t public; /** + * Number of references hold by others to this policy + */ + u_int refcount; + + /** * Name of the policy, used to query it */ char *name; @@ -135,76 +140,52 @@ static identification_t *get_other_id(private_policy_t *this) } /** - * Implementation of policy_t.update_my_id - */ -static void update_my_id(private_policy_t *this, identification_t *my_id) -{ - this->my_id->destroy(this->my_id); - this->my_id = my_id; -} - -/** - * Implementation of policy_t.update_other_id - */ -static void update_other_id(private_policy_t *this, identification_t *other_id) -{ - this->other_id->destroy(this->other_id); - this->other_id = other_id; -} - -/** - * Helper function which does the work for policy_t.update_my_ts and update_other_ts + * Get traffic selectors, with wildcard-address update */ -static void update_ts(linked_list_t* list, host_t *new_host) +static linked_list_t *get_traffic_selectors(private_policy_t *this, linked_list_t *list, host_t *host) { - traffic_selector_t *ts; iterator_t *iterator; - + traffic_selector_t *current; + linked_list_t *result = linked_list_create(); + iterator = list->create_iterator(list, TRUE); - while (iterator->has_next(iterator)) + + while (iterator->iterate(iterator, (void**)¤t)) { - iterator->current(iterator, (void**)&ts); - ts->update_address_range(ts, new_host); + /* we make a copy of the TS, this allows us to update wildcard + * addresses in it. We won't pollute the shared policy. */ + current = current->clone(current); + current->update_address_range(current, host); + + result->insert_last(result, (void*)current); } iterator->destroy(iterator); -} - -/** - * Implementation of policy_t.update_my_id - */ -static void update_my_ts(private_policy_t *this, host_t *my_host) -{ - update_ts(this->my_ts, my_host); -} - -/** - * Implementation of policy_t.update_other_ts - */ -static void update_other_ts(private_policy_t *this, host_t *my_host) -{ - update_ts(this->other_ts, my_host); + return result; } /** * Implementation of policy_t.get_my_traffic_selectors */ -static linked_list_t *get_my_traffic_selectors(private_policy_t *this) +static linked_list_t *get_my_traffic_selectors(private_policy_t *this, host_t *me) { - return this->my_ts; + return get_traffic_selectors(this, this->my_ts, me); } /** * Implementation of policy_t.get_other_traffic_selectors */ -static linked_list_t *get_other_traffic_selectors(private_policy_t *this, traffic_selector_t **traffic_selectors[]) +static linked_list_t *get_other_traffic_selectors(private_policy_t *this, host_t *other) { - return this->other_ts; + return get_traffic_selectors(this, this->other_ts, other); } /** - * Implementation of private_policy_t.select_traffic_selectors + * Narrow traffic selectors, with wildcard-address update in "stored". */ -static linked_list_t *select_traffic_selectors(private_policy_t *this, linked_list_t *stored, linked_list_t *supplied) +static linked_list_t *select_traffic_selectors(private_policy_t *this, + linked_list_t *stored, + linked_list_t *supplied, + host_t *host) { iterator_t *supplied_iter, *stored_iter; traffic_selector_t *supplied_ts, *stored_ts, *selected_ts; @@ -218,16 +199,17 @@ static linked_list_t *select_traffic_selectors(private_policy_t *this, linked_li supplied_iter = supplied->create_iterator(supplied, TRUE); /* iterate over all stored selectors */ - while (stored_iter->has_next(stored_iter)) + while (stored_iter->iterate(stored_iter, (void**)&stored_ts)) { - stored_iter->current(stored_iter, (void**)&stored_ts); + /* we make a copy of the TS, this allows us to update wildcard + * addresses in it. We won't pollute the shared policy. */ + stored_ts = stored_ts->clone(stored_ts); + stored_ts->update_address_range(stored_ts, host); supplied_iter->reset(supplied_iter); /* iterate over all supplied traffic selectors */ - while (supplied_iter->has_next(supplied_iter)) + while (supplied_iter->iterate(supplied_iter, (void**)&supplied_ts)) { - supplied_iter->current(supplied_iter, (void**)&supplied_ts); - this->logger->log(this->logger, CONTROL|LEVEL2, " stored %s <=> %s received", stored_ts->get_string(stored_ts), @@ -243,6 +225,7 @@ static linked_list_t *select_traffic_selectors(private_policy_t *this, linked_li selected_ts->get_string(selected_ts)); } } + stored_ts->destroy(stored_ts); } stored_iter->destroy(stored_iter); supplied_iter->destroy(supplied_iter); @@ -253,17 +236,21 @@ static linked_list_t *select_traffic_selectors(private_policy_t *this, linked_li /** * Implementation of private_policy_t.select_my_traffic_selectors */ -static linked_list_t *select_my_traffic_selectors(private_policy_t *this, linked_list_t *supplied) +static linked_list_t *select_my_traffic_selectors(private_policy_t *this, + linked_list_t *supplied, + host_t *me) { - return select_traffic_selectors(this, this->my_ts, supplied); + return select_traffic_selectors(this, this->my_ts, supplied, me); } /** * Implementation of private_policy_t.select_other_traffic_selectors */ -static linked_list_t *select_other_traffic_selectors(private_policy_t *this, linked_list_t *supplied) +static linked_list_t *select_other_traffic_selectors(private_policy_t *this, + linked_list_t *supplied, + host_t* other) { - return select_traffic_selectors(this, this->other_ts, supplied); + return select_traffic_selectors(this, this->other_ts, supplied, other); } /** @@ -322,11 +309,11 @@ static void add_authorities(private_policy_t *this, identification_t *my_ca, ide } /** - * Implementation of policy_t.add_updown + * Implementation of policy_t.get_updown */ -static void add_updown(private_policy_t *this, char *updown) +static char* get_updown(private_policy_t *this) { - this->updown = (updown == NULL)? NULL:strdup(updown); + return this->updown; } /** @@ -375,118 +362,67 @@ static u_int32_t get_hard_lifetime(private_policy_t *this) } /** - * Implements policy_t.clone. + * Implements policy_t.get_ref. */ -static policy_t *clone_(private_policy_t *this) +static void get_ref(private_policy_t *this) { - private_policy_t *clone = (private_policy_t*)policy_create(this->name, - this->my_id->clone(this->my_id), - this->other_id->clone(this->other_id), - this->hard_lifetime, this->soft_lifetime, - this->jitter); - iterator_t *iterator; - proposal_t *proposal; - traffic_selector_t *ts; - - /* clone the certification authorities */ - if (this->my_ca) - { - clone->my_ca = this->my_ca->clone(this->my_ca); - } - if (this->other_ca) - { - clone->other_ca = this->other_ca->clone(this->other_ca); - } - - /* clone updown script */ - clone->updown = (this->updown == NULL)? NULL:strdup(this->updown); - - /* clone all proposals */ - iterator = this->proposals->create_iterator(this->proposals, TRUE); - while (iterator->has_next(iterator)) - { - iterator->current(iterator, (void**)&proposal); - proposal = proposal->clone(proposal); - clone->proposals->insert_last(clone->proposals, (void*)proposal); - } - iterator->destroy(iterator); - - /* clone all local traffic selectors */ - iterator = this->my_ts->create_iterator(this->my_ts, TRUE); - while (iterator->has_next(iterator)) - { - iterator->current(iterator, (void**)&ts); - ts = ts->clone(ts); - clone->my_ts->insert_last(clone->my_ts, (void*)ts); - } - iterator->destroy(iterator); - - /* clone all remote traffic selectors */ - iterator = this->other_ts->create_iterator(this->other_ts, TRUE); - while (iterator->has_next(iterator)) - { - iterator->current(iterator, (void**)&ts); - ts = ts->clone(ts); - clone->other_ts->insert_last(clone->other_ts, (void*)ts); - } - iterator->destroy(iterator); - - return &clone->public; + this->refcount++; } /** * Implements policy_t.destroy. */ -static status_t destroy(private_policy_t *this) -{ - proposal_t *proposal; - traffic_selector_t *traffic_selector; - - - /* delete proposals */ - while(this->proposals->remove_last(this->proposals, (void**)&proposal) == SUCCESS) - { - proposal->destroy(proposal); - } - this->proposals->destroy(this->proposals); - - /* delete traffic selectors */ - while(this->my_ts->remove_last(this->my_ts, (void**)&traffic_selector) == SUCCESS) - { - traffic_selector->destroy(traffic_selector); - } - this->my_ts->destroy(this->my_ts); - - /* delete traffic selectors */ - while(this->other_ts->remove_last(this->other_ts, (void**)&traffic_selector) == SUCCESS) - { - traffic_selector->destroy(traffic_selector); - } - this->other_ts->destroy(this->other_ts); - - /* delete certification authorities */ - if (this->my_ca) - { - this->my_ca->destroy(this->my_ca); - } - if (this->other_ca) - { - this->other_ca->destroy(this->other_ca); - } - - /* delete updown script */ - if (this->updown) +static void destroy(private_policy_t *this) +{ + if (--this->refcount == 0) { - free(this->updown); + proposal_t *proposal; + traffic_selector_t *traffic_selector; + + /* delete proposals */ + while(this->proposals->remove_last(this->proposals, (void**)&proposal) == SUCCESS) + { + proposal->destroy(proposal); + } + this->proposals->destroy(this->proposals); + + /* delete traffic selectors */ + while(this->my_ts->remove_last(this->my_ts, (void**)&traffic_selector) == SUCCESS) + { + traffic_selector->destroy(traffic_selector); + } + this->my_ts->destroy(this->my_ts); + + /* delete traffic selectors */ + while(this->other_ts->remove_last(this->other_ts, (void**)&traffic_selector) == SUCCESS) + { + traffic_selector->destroy(traffic_selector); + } + this->other_ts->destroy(this->other_ts); + + /* delete certification authorities */ + if (this->my_ca) + { + this->my_ca->destroy(this->my_ca); + } + if (this->other_ca) + { + this->other_ca->destroy(this->other_ca); + } + + /* delete updown script */ + if (this->updown) + { + free(this->updown); + } + + /* delete ids */ + this->my_id->destroy(this->my_id); + this->other_id->destroy(this->other_id); + + free(this->name); + free(this); } - - /* delete ids */ - this->my_id->destroy(this->my_id); - this->other_id->destroy(this->other_id); - - free(this->name); - free(this); - return SUCCESS; } /* @@ -494,7 +430,7 @@ static status_t destroy(private_policy_t *this) */ policy_t *policy_create(char *name, identification_t *my_id, identification_t *other_id, u_int32_t hard_lifetime, u_int32_t soft_lifetime, - u_int32_t jitter) + u_int32_t jitter, char *updown) { private_policy_t *this = malloc_thing(private_policy_t); @@ -502,24 +438,20 @@ policy_t *policy_create(char *name, identification_t *my_id, identification_t *o this->public.get_name = (char *(*)(policy_t*))get_name; this->public.get_my_id = (identification_t*(*)(policy_t*))get_my_id; this->public.get_other_id = (identification_t*(*)(policy_t*))get_other_id; - this->public.update_my_id = (void(*)(policy_t*,identification_t*))update_my_id; - this->public.update_other_id = (void(*)(policy_t*,identification_t*))update_other_id; - this->public.update_my_ts = (void(*)(policy_t*,host_t*))update_my_ts; - this->public.update_other_ts = (void(*)(policy_t*,host_t*))update_other_ts; - this->public.get_my_traffic_selectors = (linked_list_t*(*)(policy_t*))get_my_traffic_selectors; - this->public.select_my_traffic_selectors = (linked_list_t*(*)(policy_t*,linked_list_t*))select_my_traffic_selectors; - this->public.get_other_traffic_selectors = (linked_list_t*(*)(policy_t*))get_other_traffic_selectors; - this->public.select_other_traffic_selectors = (linked_list_t*(*)(policy_t*,linked_list_t*))select_other_traffic_selectors; + this->public.get_my_traffic_selectors = (linked_list_t*(*)(policy_t*,host_t*))get_my_traffic_selectors; + this->public.get_other_traffic_selectors = (linked_list_t*(*)(policy_t*,host_t*))get_other_traffic_selectors; + this->public.select_my_traffic_selectors = (linked_list_t*(*)(policy_t*,linked_list_t*,host_t*))select_my_traffic_selectors; + this->public.select_other_traffic_selectors = (linked_list_t*(*)(policy_t*,linked_list_t*,host_t*))select_other_traffic_selectors; this->public.get_proposals = (linked_list_t*(*)(policy_t*))get_proposals; this->public.select_proposal = (proposal_t*(*)(policy_t*,linked_list_t*))select_proposal; this->public.add_my_traffic_selector = (void(*)(policy_t*,traffic_selector_t*))add_my_traffic_selector; this->public.add_other_traffic_selector = (void(*)(policy_t*,traffic_selector_t*))add_other_traffic_selector; this->public.add_proposal = (void(*)(policy_t*,proposal_t*))add_proposal; this->public.add_authorities = (void(*)(policy_t*,identification_t*, identification_t*))add_authorities; - this->public.add_updown = (void(*)(policy_t*,char*))add_updown; + this->public.get_updown = (char*(*)(policy_t*))get_updown; this->public.get_soft_lifetime = (u_int32_t (*) (policy_t *))get_soft_lifetime; this->public.get_hard_lifetime = (u_int32_t (*) (policy_t *))get_hard_lifetime; - this->public.clone = (policy_t*(*)(policy_t*))clone_; + this->public.get_ref = (void(*)(policy_t*))get_ref; this->public.destroy = (void(*)(policy_t*))destroy; /* apply init values */ @@ -529,8 +461,10 @@ policy_t *policy_create(char *name, identification_t *my_id, identification_t *o this->hard_lifetime = hard_lifetime; this->soft_lifetime = soft_lifetime; this->jitter = jitter; + this->updown = (updown == NULL) ? NULL : strdup(updown); /* initialize private members*/ + this->refcount = 1; this->my_ca = NULL; this->other_ca = NULL; this->proposals = linked_list_create(); @@ -538,5 +472,5 @@ policy_t *policy_create(char *name, identification_t *my_id, identification_t *o this->other_ts = linked_list_create(); this->logger = logger_manager->get_logger(logger_manager, CONFIG); - return (&this->public); + return &this->public; } diff --git a/src/charon/config/policies/policy.h b/src/charon/config/policies/policy.h index 329a48ff3..1a539f5bc 100644 --- a/src/charon/config/policies/policy.h +++ b/src/charon/config/policies/policy.h @@ -75,145 +75,103 @@ struct policy_t { * @return other id */ identification_t *(*get_other_id) (policy_t *this); - - /** - * @brief Update own ID. - * - * It may be necessary to uptdate own ID, as it - * is set to %any or to e.g. *@strongswan.org in - * some cases. - * Old ID is destroyed, new one NOT cloned. - * - * @param this calling object - * @param my_id new ID to set as my_id - */ - void (*update_my_id) (policy_t *this, identification_t *my_id); - - /** - * @brief Update others ID. - * - * It may be necessary to uptdate others ID, as it - * is set to %any or to e.g. *@strongswan.org in - * some cases. - * Old ID is destroyed, new one NOT cloned. - * - * @param this calling object - * @param other_id new ID to set as other_id - */ - void (*update_other_id) (policy_t *this, identification_t *other_id); - - /** - * @brief Update own address in traffic selectors. - * - * Update own 0.0.0.0 address in traffic selectors - * with supplied one. The size of the subnet will be - * set to /32. - * - * @param this calling object - * @param my_host new address to set in traffic selectors - */ - void (*update_my_ts) (policy_t *this, host_t *my_host); - - /** - * @brief Update others address in traffic selectors. - * - * Update remote 0.0.0.0 address in traffic selectors - * with supplied one. The size of the subnet will be - * set to /32. - * - * @param this calling object - * @param other_host new address to set in traffic selectors - */ - void (*update_other_ts) (policy_t *this, host_t *other_host); /** * @brief Get configured traffic selectors for our site. * * Returns a list with all traffic selectors for the local - * site. List and items MUST NOT be freed nor modified. + * site. List and items must be destroyed after usage. * - * @param this calling object - * @return list with traffic selectors + * @param this calling object + * @return list with traffic selectors */ - linked_list_t *(*get_my_traffic_selectors) (policy_t *this); + linked_list_t *(*get_my_traffic_selectors) (policy_t *this, host_t *me); /** * @brief Get configured traffic selectors for others site. * * Returns a list with all traffic selectors for the remote - * site. List and items MUST NOT be freed nor modified. + * site. List and items must be destroyed after usage. * - * @param this calling object - * @return list with traffic selectors + * @param this calling object + * @return list with traffic selectors */ - linked_list_t *(*get_other_traffic_selectors) (policy_t *this); + linked_list_t *(*get_other_traffic_selectors) (policy_t *this, host_t* other); /** * @brief Select traffic selectors from a supplied list for local site. * * Resulted list and traffic selectors must be destroyed after usage. + * As the traffic selectors may contain a wildcard address (0.0.0.0) for + * addresses we don't know in previous, an address may be supplied to + * replace these 0.0.0.0 addresses on-the-fly. * - * @param this calling object - * @param supplied linked list with traffic selectors - * @return list containing the selected traffic selectors + * @param this calling object + * @param supplied linked list with traffic selectors + * @param me host address used by us + * @return list containing the selected traffic selectors */ - linked_list_t *(*select_my_traffic_selectors) (policy_t *this, linked_list_t *supplied); + linked_list_t *(*select_my_traffic_selectors) (policy_t *this, + linked_list_t *supplied, + host_t *me); /** * @brief Select traffic selectors from a supplied list for remote site. * * Resulted list and traffic selectors must be destroyed after usage. - * - * @param this calling object - * @param supplied linked list with traffic selectors - * @return list containing the selected traffic selectors + * As the traffic selectors may contain a wildcard address (0.0.0.0) for + * addresses we don't know in previous, an address may be supplied to + * replace these 0.0.0.0 addresses on-the-fly. + * + * @param this calling object + * @param supplied linked list with traffic selectors + * @return list containing the selected traffic selectors */ - linked_list_t *(*select_other_traffic_selectors) (policy_t *this, linked_list_t *supplied); + linked_list_t *(*select_other_traffic_selectors) (policy_t *this, + linked_list_t *supplied, + host_t *other); /** * @brief Get the list of internally stored proposals. * - * Rembember: policy_t does store proposals for AH/ESP, - * IKE proposals are in the connection_t - * - * @warning List and Items are still owned by policy and MUST NOT - * be manipulated or freed! - * - * @param this calling object - * @return lists with proposals + * policy_t does store proposals for AH/ESP, IKE proposals are in + * the connection_t. + * List and Items are still owned by policy and MUST NOT + * be manipulated or freed! + * + * @param this calling object + * @return lists with proposals */ linked_list_t *(*get_proposals) (policy_t *this); /** * @brief Select a proposal from a supplied list. + * + * Returned propsal is newly created and must be destroyed after usage. * - * @param this calling object - * @param proposals list from from wich proposals are selected - * @return selected proposal, or NULL if nothing matches + * @param this calling object + * @param proposals list from from wich proposals are selected + * @return selected proposal, or NULL if nothing matches */ proposal_t *(*select_proposal) (policy_t *this, linked_list_t *proposals); /** * @brief Add a traffic selector to the list for local site. * - * After add, proposal is owned by policy. - * - * @warning Do not add while other threads are reading. + * After add, traffic selector is owned by policy. * - * @param this calling object - * @param traffic_selector traffic_selector to add + * @param this calling object + * @param traffic_selector traffic_selector to add */ void (*add_my_traffic_selector) (policy_t *this, traffic_selector_t *traffic_selector); /** * @brief Add a traffic selector to the list for remote site. * - * After add, proposal is owned by policy. - * - * @warning Do not add while other threads are reading. + * After add, traffic selector is owned by policy. * - * @param this calling object - * @param traffic_selector traffic_selector to add + * @param this calling object + * @param traffic_selector traffic_selector to add */ void (*add_other_traffic_selector) (policy_t *this, traffic_selector_t *traffic_selector); @@ -222,30 +180,29 @@ struct policy_t { * * The proposals are stored by priority, first added * is the most prefered. + * After add, proposal is owned by policy. * - * @warning Do not add while other threads are reading. - * - * @param this calling object - * @param proposal proposal to add + * @param this calling object + * @param proposal proposal to add */ void (*add_proposal) (policy_t *this, proposal_t *proposal); /** - * @brief Add certification authorities + * @brief Add certification authorities. * - * @param this calling object - * @param my_ca issuer of my certificate - * @param other_ca required issuer of the peer's certificate + * @param this calling object + * @param my_ca issuer of my certificate + * @param other_ca required issuer of the peer's certificate */ void (*add_authorities) (policy_t *this, identification_t *my_ca, identification_t *other_ca); /** - * @brief Add updown script + * @brief Get updown script * - * @param this calling object - * @param updown updown script + * @param this calling object + * @return path to updown script */ - void (*add_updown) (policy_t *this, char *updown); + char* (*get_updown) (policy_t *this); /** * @brief Get the lifetime of a policy, before rekeying starts. @@ -253,29 +210,34 @@ struct policy_t { * A call to this function automatically adds a jitter to * avoid simultanous rekeying. * - * @param this policy - * @return lifetime in seconds + * @param this policy + * @return lifetime in seconds */ u_int32_t (*get_soft_lifetime) (policy_t *this); /** * @brief Get the lifetime of a policy, before SA gets deleted. * - * @param this policy - * @return lifetime in seconds + * @param this policy + * @return lifetime in seconds */ u_int32_t (*get_hard_lifetime) (policy_t *this); /** - * @brief Clone a policy. + * @brief Get a new reference. + * + * Get a new reference to this policy by increasing + * it's internal reference counter. * - * @param this policy to clone - * @return clone of it + * @param this calling object */ - policy_t *(*clone) (policy_t *this); + void (*get_ref) (policy_t *this); /** - * @brief Destroys the policy object + * @brief Destroys the policy object. + * + * Decrements the internal reference counter and + * destroys the policy when it reaches zero. * * @param this calling object */ @@ -291,6 +253,7 @@ struct policy_t { * (soft_lifetime - random(0, jitter)). After a successful rekeying, * the hard_lifetime limit counter is reset. You should specify * hard_lifetime > soft_lifetime > jitter. + * After a call to create, a reference is obtained (refcount = 1). * * @param name name of the policy * @param my_id identification_t for ourselves @@ -298,11 +261,14 @@ struct policy_t { * @param hard_lifetime lifetime before deleting an SA * @param soft_lifetime lifetime before rekeying an SA * @param jitter range of randomization time + * @param updown updown script to execute on up/down event * @return policy_t object * * @ingroup config */ -policy_t *policy_create(char *name, identification_t *my_id, identification_t *other_id, - u_int32_t hard_lifetime, u_int32_t soft_lifetime, u_int32_t jitter); +policy_t *policy_create(char *name, + identification_t *my_id, identification_t *other_id, + u_int32_t hard_lifetime, u_int32_t soft_lifetime, + u_int32_t jitter, char *updown); #endif /* POLICY_H_ */ diff --git a/src/charon/config/policies/policy_store.h b/src/charon/config/policies/policy_store.h index 40cc87e2f..2ea57b8b4 100755 --- a/src/charon/config/policies/policy_store.h +++ b/src/charon/config/policies/policy_store.h @@ -25,13 +25,17 @@ #include <types.h> #include <config/policies/policy.h> +#include <utils/linked_list.h> typedef struct policy_store_t policy_store_t; /** * @brief The interface for a store of policy_t's. - * + * + * The store uses reference counting to manage their lifetime. Call + * destroy() for a policy which is returned from the store after usage. + * * @b Constructors: * - stroke_create() * @@ -40,28 +44,30 @@ typedef struct policy_store_t policy_store_t; struct policy_store_t { /** - * @brief Returns a policy identified by two IDs. + * @brief Returns a policy identified by two IDs and a set of traffic selectors. * - * The returned policy gets created/cloned and therefore must be - * destroyed by the caller. * other_id must be fully qualified. my_id may be %any, as the * other peer may not include an IDr Request. * - * @param this calling object - * @param my_id own ID of the policy - * @param other_id others ID of the policy + * @param this calling object + * @param my_id own ID of the policy + * @param other_id others ID of the policy + * @param my_ts traffic selectors requested for local host + * @param other_ts traffic selectors requested for remote host + * @param my_host host to use for wilcards in TS compare + * @param other_host host to use for wildcards in TS compare * @return - * - matching policy_t, if found - * - NULL otherwise + * - matching policy_t, if found + * - NULL otherwise */ - policy_t *(*get_policy_by_ids) (policy_store_t *this, identification_t *my_id, identification_t *other_id); + policy_t *(*get_policy) (policy_store_t *this, + identification_t *my_id, identification_t *other_id, + linked_list_t *my_ts, linked_list_t *other_ts, + host_t *my_host, host_t* other_host); /** * @brief Returns a policy identified by a connection name. * - * The returned policy gets created/cloned and therefore must be - * destroyed by the caller. - * * @param this calling object * @param name name of the policy * @return diff --git a/src/charon/config/traffic_selector.c b/src/charon/config/traffic_selector.c index b0b0a13ce..3a9480f77 100644 --- a/src/charon/config/traffic_selector.c +++ b/src/charon/config/traffic_selector.c @@ -356,16 +356,18 @@ static void update_address_range(private_traffic_selector_t *this, host_t *host) */ static traffic_selector_t *clone_(private_traffic_selector_t *this) { - private_traffic_selector_t *clone = traffic_selector_create(this->protocol, this->type, this->from_port, this->to_port); - clone->type = this->type; - clone->string = strdup(this->string); + private_traffic_selector_t *clone; + + clone = traffic_selector_create(this->protocol, this->type, + this->from_port, this->to_port); switch (clone->type) { case TS_IPV4_ADDR_RANGE: { clone->from_addr_ipv4 = this->from_addr_ipv4; clone->to_addr_ipv4 = this->to_addr_ipv4; - return &(clone->public); + update_string(clone); + return &clone->public; } case TS_IPV6_ADDR_RANGE: default: @@ -391,8 +393,7 @@ static void destroy(private_traffic_selector_t *this) traffic_selector_t *traffic_selector_create_from_bytes(u_int8_t protocol, ts_type_t type, chunk_t from_addr, u_int16_t from_port, chunk_t to_addr, u_int16_t to_port) { private_traffic_selector_t *this = traffic_selector_create(protocol, type, from_port, to_port); - - this->type = type; + switch (type) { case TS_IPV4_ADDR_RANGE: @@ -400,12 +401,12 @@ traffic_selector_t *traffic_selector_create_from_bytes(u_int8_t protocol, ts_typ if (from_addr.len != 4 || to_addr.len != 4) { free(this); - return NULL; + return NULL; } /* chunk contains network order, convert! */ this->from_addr_ipv4 = ntohl(*((u_int32_t*)from_addr.ptr)); this->to_addr_ipv4 = ntohl(*((u_int32_t*)to_addr.ptr)); - break; + break; } case TS_IPV6_ADDR_RANGE: default: diff --git a/src/charon/queues/jobs/initiate_ike_sa_job.c b/src/charon/queues/jobs/initiate_ike_sa_job.c index 6c753fd68..38108cab8 100644 --- a/src/charon/queues/jobs/initiate_ike_sa_job.c +++ b/src/charon/queues/jobs/initiate_ike_sa_job.c @@ -41,11 +41,16 @@ struct private_initiate_ike_sa_job_t { initiate_ike_sa_job_t public; /** - * associated connection object to initiate + * associated connection to initiate */ connection_t *connection; /** + * associated policy to initiate + */ + policy_t *policy; + + /** * logger */ logger_t *logger; @@ -75,7 +80,9 @@ static status_t execute(private_initiate_ike_sa_job_t *this) this->logger->log(this->logger, CONTROL|LEVEL2, "Creating and checking out IKE SA"); charon->ike_sa_manager->create_and_checkout(charon->ike_sa_manager, &ike_sa); - status = ike_sa->initiate(ike_sa, this->connection->clone(this->connection)); + this->connection->get_ref(this->connection); + this->policy->get_ref(this->policy); + status = ike_sa->initiate(ike_sa, this->connection, this->policy); if (status != SUCCESS) { this->logger->log(this->logger, ERROR, @@ -95,13 +102,14 @@ static status_t execute(private_initiate_ike_sa_job_t *this) static void destroy(private_initiate_ike_sa_job_t *this) { this->connection->destroy(this->connection); + this->policy->destroy(this->policy); free(this); } /* * Described in header */ -initiate_ike_sa_job_t *initiate_ike_sa_job_create(connection_t *connection) +initiate_ike_sa_job_t *initiate_ike_sa_job_create(connection_t *connection, policy_t *policy) { private_initiate_ike_sa_job_t *this = malloc_thing(private_initiate_ike_sa_job_t); @@ -112,7 +120,8 @@ initiate_ike_sa_job_t *initiate_ike_sa_job_create(connection_t *connection) /* private variables */ this->connection = connection; + this->policy = policy; this->logger = logger_manager->get_logger(logger_manager, WORKER); - return &(this->public); + return &this->public; } diff --git a/src/charon/queues/jobs/initiate_ike_sa_job.h b/src/charon/queues/jobs/initiate_ike_sa_job.h index fe81d31d6..c119cf3fc 100644 --- a/src/charon/queues/jobs/initiate_ike_sa_job.h +++ b/src/charon/queues/jobs/initiate_ike_sa_job.h @@ -26,6 +26,7 @@ #include <types.h> #include <queues/jobs/job.h> #include <config/connections/connection.h> +#include <config/policies/policy.h> typedef struct initiate_ike_sa_job_t initiate_ike_sa_job_t; @@ -33,8 +34,7 @@ typedef struct initiate_ike_sa_job_t initiate_ike_sa_job_t; /** * @brief Class representing an INITIATE_IKE_SA Job. * - * This job is created if an IKE_SA should be iniated. This - * happens via a user request, or via the kernel interface. + * This job is created if an IKE_SA should be iniated. * * @b Constructors: * - initiate_ike_sa_job_create() @@ -52,10 +52,12 @@ struct initiate_ike_sa_job_t { * @brief Creates a job of type INITIATE_IKE_SA. * * @param connection connection_t to initializes + * @param policy policy to set up * @return initiate_ike_sa_job_t object * * @ingroup jobs */ -initiate_ike_sa_job_t *initiate_ike_sa_job_create(connection_t *connection); +initiate_ike_sa_job_t *initiate_ike_sa_job_create(connection_t *connection, + policy_t *policy); #endif /*INITIATE_IKE_SA_JOB_H_*/ diff --git a/src/charon/sa/authenticator.c b/src/charon/sa/authenticator.c index fb4bdde4e..8dcfc049f 100644 --- a/src/charon/sa/authenticator.c +++ b/src/charon/sa/authenticator.c @@ -51,6 +51,11 @@ struct private_authenticator_t { ike_sa_t *ike_sa; /** + * auth_method to create own signature/mac/whatever.. + */ + auth_method_t auth_method; + + /** * PRF taken from the IKE_SA. */ prf_t *prf; @@ -294,10 +299,8 @@ static status_t compute_auth_data (private_authenticator_t *this, chunk_t other_nonce, id_payload_t *my_id_payload, bool initiator) -{ - connection_t *connection = this->ike_sa->get_connection(this->ike_sa); - - switch(connection->get_auth_method(connection)) +{ + switch(this->auth_method) { case SHARED_KEY_MESSAGE_INTEGRITY_CODE: { @@ -405,7 +408,7 @@ static void destroy (private_authenticator_t *this) /* * Described in header. */ -authenticator_t *authenticator_create(ike_sa_t *ike_sa) +authenticator_t *authenticator_create(ike_sa_t *ike_sa, auth_method_t auth_method) { private_authenticator_t *this = malloc_thing(private_authenticator_t); @@ -420,6 +423,7 @@ authenticator_t *authenticator_create(ike_sa_t *ike_sa) /* private data */ this->ike_sa = ike_sa; + this->auth_method = auth_method; this->prf = this->ike_sa->get_prf(this->ike_sa); this->logger = logger_manager->get_logger(logger_manager, IKE_SA); diff --git a/src/charon/sa/authenticator.h b/src/charon/sa/authenticator.h index 99a56e2e4..645e39b81 100644 --- a/src/charon/sa/authenticator.h +++ b/src/charon/sa/authenticator.h @@ -122,11 +122,12 @@ struct authenticator_t { * @brief Creates an authenticator object. * * @param ike_sa associated ike_sa + * @param auth_method authentication method to use for own signature/mac * * @return authenticator_t object * * @ingroup sa */ -authenticator_t *authenticator_create(ike_sa_t *ike_sa); +authenticator_t *authenticator_create(ike_sa_t *ike_sa, auth_method_t auth_method); #endif /* AUTHENTICATOR_H_ */ diff --git a/src/charon/sa/child_sa.c b/src/charon/sa/child_sa.c index c9c6794b2..38b4fa87a 100644 --- a/src/charon/sa/child_sa.c +++ b/src/charon/sa/child_sa.c @@ -96,6 +96,16 @@ struct private_child_sa_t { linked_list_t *policies; /** + * Seperate list for local traffic selectors + */ + linked_list_t *my_ts; + + /** + * Seperate list for remote traffic selectors + */ + linked_list_t *other_ts; + + /** * reqid used for this child_sa */ u_int32_t reqid; @@ -473,6 +483,9 @@ static status_t add_policies(private_child_sa_t *this, linked_list_t *my_ts_list policy->my_ts = my_ts->clone(my_ts); policy->other_ts = other_ts->clone(other_ts); this->policies->insert_last(this->policies, (void*)policy); + /* add to separate list to query them via get_*_traffic_selectors() */ + this->my_ts->insert_last(this->my_ts, (void*)policy->my_ts); + this->other_ts->insert_last(this->other_ts, (void*)policy->other_ts); } } my_iter->destroy(my_iter); @@ -481,6 +494,22 @@ static status_t add_policies(private_child_sa_t *this, linked_list_t *my_ts_list } /** + * Implementation of child_sa_t.get_my_traffic_selectors. + */ +static linked_list_t *get_my_traffic_selectors(private_child_sa_t *this) +{ + return this->my_ts; +} + +/** + * Implementation of child_sa_t.get_my_traffic_selectors. + */ +static linked_list_t *get_other_traffic_selectors(private_child_sa_t *this) +{ + return this->other_ts; +} + +/** * Implementation of child_sa_t.set_rekeying_transaction. */ static void set_rekeying_transaction(private_child_sa_t *this, void *transaction) @@ -819,6 +848,8 @@ static void destroy(private_child_sa_t *this) } this->policies->destroy(this->policies); + this->my_ts->destroy(this->my_ts); + this->other_ts->destroy(this->other_ts); this->me.addr->destroy(this->me.addr); this->other.addr->destroy(this->other.addr); free(this); @@ -843,6 +874,8 @@ child_sa_t * child_sa_create(u_int32_t rekey, host_t *me, host_t* other, this->public.update = (status_t(*)(child_sa_t*,proposal_t*,prf_plus_t*))update; this->public.update_hosts = (status_t (*)(child_sa_t*,host_t*,host_t*,host_diff_t,host_diff_t))update_hosts; this->public.add_policies = (status_t (*)(child_sa_t*, linked_list_t*,linked_list_t*))add_policies; + this->public.get_my_traffic_selectors = (linked_list_t*(*)(child_sa_t*))get_my_traffic_selectors; + this->public.get_other_traffic_selectors = (linked_list_t*(*)(child_sa_t*))get_other_traffic_selectors; this->public.get_use_time = (status_t (*)(child_sa_t*,bool,time_t*))get_use_time; this->public.set_rekeying_transaction = (void (*)(child_sa_t*,void*))set_rekeying_transaction; this->public.get_rekeying_transaction = (void* (*)(child_sa_t*))get_rekeying_transaction; @@ -866,6 +899,8 @@ child_sa_t * child_sa_create(u_int32_t rekey, host_t *me, host_t* other, /* reuse old reqid if we are rekeying an existing CHILD_SA */ this->reqid = rekey ? rekey : ++reqid; this->policies = linked_list_create(); + this->my_ts = linked_list_create(); + this->other_ts = linked_list_create(); this->protocol = PROTO_NONE; this->rekeying_transaction = NULL; diff --git a/src/charon/sa/child_sa.h b/src/charon/sa/child_sa.h index 33d06a70b..2a74a2a44 100644 --- a/src/charon/sa/child_sa.h +++ b/src/charon/sa/child_sa.h @@ -177,7 +177,7 @@ struct child_sa_t { * @return SUCCESS or FAILED */ status_t (*update_hosts) (child_sa_t *this, host_t *new_me, host_t *new_other, - host_diff_t my_diff, host_diff_t other_diff); + host_diff_t my_diff, host_diff_t other_diff); /** * @brief Install the policies using some traffic selectors. @@ -193,6 +193,22 @@ struct child_sa_t { status_t (*add_policies) (child_sa_t *this, linked_list_t *my_ts_list, linked_list_t *other_ts_list); /** + * @brief Get the traffic selectors of added policies of local host. + * + * @param this calling object + * @return list of traffic selectors + */ + linked_list_t* (*get_my_traffic_selectors) (child_sa_t *this); + + /** + * @brief Get the traffic selectors of added policies of remote host. + * + * @param this calling object + * @return list of traffic selectors + */ + linked_list_t* (*get_other_traffic_selectors) (child_sa_t *this); + + /** * @brief Get the time of this child_sa_t's last use (i.e. last use of any of its policies) * * @param this calling object diff --git a/src/charon/sa/ike_sa.c b/src/charon/sa/ike_sa.c index c233afc37..569d8795e 100644 --- a/src/charon/sa/ike_sa.c +++ b/src/charon/sa/ike_sa.c @@ -86,24 +86,39 @@ struct private_ike_sa_t { ike_sa_id_t *ike_sa_id; /** - * Linked List containing the child sa's of the current IKE_SA. + * Current state of the IKE_SA */ - linked_list_t *child_sas; + ike_sa_state_t state; /** - * Current state of the IKE_SA + * Name of the connection used by this IKE_SA */ - ike_sa_state_t state; + char *name; + + /** + * Address of local host + */ + host_t *my_host; + + /** + * Address of remote host + */ + host_t *other_host; + + /** + * Identification used for us + */ + identification_t *my_id; /** - * Connection definition used for this IKE_SA + * Identification used for other */ - connection_t *connection; + identification_t *other_id; /** - * Policy definition used for this IKE_SA + * Linked List containing the child sa's of the current IKE_SA. */ - policy_t *policy; + linked_list_t *child_sas; /** * crypter for inbound traffic @@ -208,7 +223,7 @@ struct private_ike_sa_t { /** * get the time of the latest traffic processed by the kernel */ -static time_t get_esp_time(private_ike_sa_t* this, bool inbound) +static time_t get_kernel_time(private_ike_sa_t* this, bool inbound) { iterator_t *iterator; child_sa_t *child_sa; @@ -232,7 +247,7 @@ static time_t get_esp_time(private_ike_sa_t* this, bool inbound) */ static time_t get_time_inbound(private_ike_sa_t *this) { - return max(this->time_inbound, get_esp_time(this, TRUE)); + return max(this->time_inbound, get_kernel_time(this, TRUE)); } /** @@ -240,9 +255,41 @@ static time_t get_time_inbound(private_ike_sa_t *this) */ static time_t get_time_outbound(private_ike_sa_t *this) { - return max(this->time_outbound, get_esp_time(this, FALSE)); + return max(this->time_outbound, get_kernel_time(this, FALSE)); } +/** + * Implementation of ike_sa_t.get_name. + */ +static char *get_name(private_ike_sa_t *this) +{ + return this->name; +} + +/** + * Implementation of ike_sa_t.set_name. + */ +static void set_name(private_ike_sa_t *this, char* name) +{ + free(this->name); + this->name = strdup(name); +} + +/** + * Implementation of ike_sa_t.get_my_host. + */ +static host_t *get_my_host(private_ike_sa_t *this) +{ + return this->my_host; +} + +/** + * Implementation of ike_sa_t.get_other_host. + */ +static host_t *get_other_host(private_ike_sa_t *this) +{ + return this->other_host; +} /** * Update connection host, as addresses may change (NAT) @@ -278,53 +325,58 @@ static void update_hosts(private_ike_sa_t *this, host_t *me, host_t *other) * packet or any authenticated UDP-encapsulated ESP packet can be * used to detect that the IP address or the port has changed. */ - host_t *old_other = NULL; iterator_t *iterator = NULL; child_sa_t *child_sa = NULL; - int my_changes, other_changes; - - my_changes = me->get_differences(me, this->connection->get_my_host(this->connection)); - - old_other = this->connection->get_other_host(this->connection); - other_changes = other->get_differences(other, old_other); - - if (!my_changes && !other_changes) + host_diff_t my_diff, other_diff; + + if (this->my_host == NULL || this->other_host == NULL) + { + /* on first received message */ + this->my_host = me->clone(me); + this->other_host = other->clone(other); + return; + } + + my_diff = me->get_differences(me, this->my_host); + other_diff = other->get_differences(other, this->other_host); + + if (!my_diff && !other_diff) { return; } - if (my_changes) + if (my_diff) { - this->connection->update_my_host(this->connection, me->clone(me)); + this->my_host->destroy(this->my_host); + this->my_host = me->clone(me); } if (!this->nat_here) { /* update without restrictions if we are not NATted */ - if (other_changes) + if (other_diff) { - this->connection->update_other_host(this->connection, other->clone(other)); + this->other_host->destroy(this->other_host); + this->other_host = other->clone(other); } } else { /* if we are natted, only port may change */ - if (other_changes & HOST_DIFF_ADDR) + if (other_diff & HOST_DIFF_ADDR) { return; } - else if (other_changes & HOST_DIFF_PORT) + else if (other_diff & HOST_DIFF_PORT) { - old_other->set_port(old_other, other->get_port(other)); + this->other_host->set_port(this->other_host, other->get_port(other)); } } iterator = this->child_sas->create_iterator(this->child_sas, TRUE); while (iterator->iterate(iterator, (void**)&child_sa)) { - child_sa->update_hosts(child_sa, - this->connection->get_my_host(this->connection), - this->connection->get_other_host(this->connection), - my_changes, other_changes); + child_sa->update_hosts(child_sa, this->my_host, this->other_host, + my_diff, other_diff); /* TODO: what to do if update fails? Delete CHILD_SA? */ } iterator->destroy(iterator); @@ -705,7 +757,7 @@ static status_t process_message(private_ike_sa_t *this, message_t *message) else { /* check if message is trustworthy, and update connection information */ - if ((this->state == IKE_CREATED && this->connection) || + if (this->state == IKE_CREATED || message->get_exchange_type(message) != IKE_SA_INIT) { update_hosts(this, message->get_destination(message), @@ -727,26 +779,60 @@ static status_t process_message(private_ike_sa_t *this, message_t *message) /** * Implementation of ike_sa_t.initiate. */ -static status_t initiate(private_ike_sa_t *this, connection_t *connection) +static status_t initiate(private_ike_sa_t *this, + connection_t *connection, policy_t *policy) { ike_sa_init_t *ike_sa_init; - /* set connection and policy */ - this->connection = connection; - this->policy = charon->policies->get_policy_by_name(charon->policies, - this->connection->get_name(this->connection)); - if (this->policy == NULL) - { - this->logger->log(this->logger, ERROR, - "no policy found for connection %s, aborting", - connection->get_name(connection)); - return DESTROY_ME; - } + set_name(this, connection->get_name(connection)); + + /* apply hosts from connection */ + this->my_host = connection->get_my_host(connection); + this->my_host = this->my_host->clone(this->my_host); + this->other_host = connection->get_other_host(connection); + this->other_host = this->other_host->clone(this->other_host); + this->message_id_out = 1; ike_sa_init = ike_sa_init_create(&this->public); + ike_sa_init->set_config(ike_sa_init, connection, policy); return queue_transaction(this, (transaction_t*)ike_sa_init, TRUE); } + +/** + * Implementation of ike_sa_t.acquire. + */ +static status_t acquire(private_ike_sa_t *this, u_int32_t reqid) +{ + /* - get TS from child with reqid + * - get a policy from TS + * - get connection from policy + */ + switch (this->state) + { + case IKE_CREATED: + /* ike_sa_init */ + break; + case IKE_CONNECTING: + case IKE_ESTABLISHED: + /* queue create_child_sa */ + break; + case IKE_DELETING: + /* deny */ + break; + } + return FAILED; +} + +/** + * Implementation of ike_sa_t.route. + */ +static status_t route(private_ike_sa_t *this, policy_t *policy) +{ + /* TODO: create CHILD_SA, add policy */ + return FAILED; +} + /** * Implementation of ike_sa_t.send_dpd */ @@ -803,15 +889,12 @@ static void send_keepalive(private_ike_sa_t *this) if (diff >= interval) { - host_t *me, *other; packet_t *packet; chunk_t data; packet = packet_create(); - me = this->connection->get_my_host(this->connection); - other = this->connection->get_other_host(this->connection); - packet->set_source(packet, me->clone(me)); - packet->set_destination(packet, other->clone(other)); + packet->set_source(packet, this->my_host->clone(this->my_host)); + packet->set_destination(packet, this->other_host->clone(this->other_host)); data.ptr = malloc(1); data.ptr[0] = 0xFF; data.len = 1; @@ -843,17 +926,11 @@ static void set_state(private_ike_sa_t *this, ike_sa_state_t state) mapping_find(ike_sa_state_m, state)); if (state == IKE_ESTABLISHED) { - host_t *my_host, *other_host; - identification_t *my_id, *other_id; - my_host = this->connection->get_my_host(this->connection); - other_host = this->connection->get_other_host(this->connection); - my_id = this->policy->get_my_id(this->policy); - other_id = this->policy->get_other_id(this->policy); this->logger->log(this->logger, AUDIT, "IKE_SA established: %s[%s]...%s[%s]", - my_host->get_string(my_host), - my_id->get_string(my_id), - other_host->get_string(other_host), - other_id->get_string(other_id)); + this->my_host->get_string(this->my_host), + this->my_id->get_string(this->my_id), + this->other_host->get_string(this->other_host), + this->other_id->get_string(this->other_id)); send_dpd(this); } @@ -861,74 +938,75 @@ static void set_state(private_ike_sa_t *this, ike_sa_state_t state) } /** - * Implementation of protected_ike_sa_t.get_connection. + * Implementation of protected_ike_sa_t.get_prf. */ -static connection_t *get_connection(private_ike_sa_t *this) +static prf_t *get_prf(private_ike_sa_t *this) { - return this->connection; + return this->prf; } /** - * Implementation of protected_ike_sa_t.set_connection. + * Implementation of protected_ike_sa_t.get_prf. */ -static void set_connection(private_ike_sa_t *this,connection_t * connection) +static prf_t *get_child_prf(private_ike_sa_t *this) { - this->connection = connection; + return this->child_prf; } /** - * Implementation of protected_ike_sa_t.get_policy. + * Implementation of protected_ike_sa_t.get_prf_auth_i. */ -static policy_t *get_policy(private_ike_sa_t *this) +static prf_t *get_prf_auth_i(private_ike_sa_t *this) { - return this->policy; + return this->prf_auth_i; } /** - * Implementation of protected_ike_sa_t.set_policy. + * Implementation of protected_ike_sa_t.get_prf_auth_r. */ -static void set_policy(private_ike_sa_t *this,policy_t * policy) +static prf_t *get_prf_auth_r(private_ike_sa_t *this) { - this->policy = policy; + return this->prf_auth_r; } /** - * Implementation of protected_ike_sa_t.get_prf. + * Implementation of ike_sa_t.get_id. */ -static prf_t *get_prf(private_ike_sa_t *this) +static ike_sa_id_t* get_id(private_ike_sa_t *this) { - return this->prf; + return this->ike_sa_id; } /** - * Implementation of protected_ike_sa_t.get_prf. + * Implementation of ike_sa_t.get_my_id. */ -static prf_t *get_child_prf(private_ike_sa_t *this) +static identification_t* get_my_id(private_ike_sa_t *this) { - return this->child_prf; + return this->my_id; } /** - * Implementation of protected_ike_sa_t.get_prf_auth_i. + * Implementation of ike_sa_t.set_my_id. */ -static prf_t *get_prf_auth_i(private_ike_sa_t *this) +static void set_my_id(private_ike_sa_t *this, identification_t *me) { - return this->prf_auth_i; + this->my_id = me; } /** - * Implementation of protected_ike_sa_t.get_prf_auth_r. + * Implementation of ike_sa_t.get_other_id. */ -static prf_t *get_prf_auth_r(private_ike_sa_t *this) +static identification_t* get_other_id(private_ike_sa_t *this) { - return this->prf_auth_r; + return this->other_id; } + /** - * Implementation of ike_sa_t.get_id. + * Implementation of ike_sa_t.set_other_id. */ -static ike_sa_id_t* get_id(private_ike_sa_t *this) +static void set_other_id(private_ike_sa_t *this, identification_t *other) { - return this->ike_sa_id; + this->other_id = other; } /** @@ -1201,55 +1279,41 @@ static void log_status(private_ike_sa_t *this, logger_t *logger, char *name) { iterator_t *iterator; child_sa_t *child_sa; - host_t *my_host, *other_host; - identification_t *my_id = NULL, *other_id = NULL; + char *my_host, *other_host, *my_id, *other_id; - /* only log if name == NULL or name == connection_name */ - if (name) + if (name == NULL || streq(name, this->name)) { - if (streq(this->connection->get_name(this->connection), name)) + if (logger == NULL) { - return; + logger = this->logger; } + + my_host = this->my_host ? + this->my_host->get_string(this->my_host) : "(unknown)"; + other_host = this->other_host ? + this->other_host->get_string(this->other_host) : "(unknown)"; + my_id = this->my_id ? + this->my_id->get_string(this->my_id) : "(unknown)"; + other_id = this->other_id ? + this->other_id->get_string(this->other_id) : "(unknown)"; + + logger->log(logger, CONTROL|LEVEL1, + " \"%s\": IKE_SA in state %s, SPIs: 0x%.16llx 0x%.16llx", + this->name, + mapping_find(ike_sa_state_m, this->state), + this->ike_sa_id->get_initiator_spi(this->ike_sa_id), + this->ike_sa_id->get_responder_spi(this->ike_sa_id)); + logger->log(logger, CONTROL, " \"%s\": %s[%s]...%s[%s]", + this->name, my_host, my_id, other_host, other_id); + + iterator = this->child_sas->create_iterator(this->child_sas, TRUE); + while (iterator->has_next(iterator)) + { + iterator->current(iterator, (void**)&child_sa); + child_sa->log_status(child_sa, logger, this->name); + } + iterator->destroy(iterator); } - my_host = this->connection->get_my_host(this->connection); - other_host = this->connection->get_other_host(this->connection); - - /* use policy information, if available */ - if (this->policy) - { - my_id = this->policy->get_my_id(this->policy); - other_id = this->policy->get_other_id(this->policy); - name = this->policy->get_name(this->policy); - } - else - { - name = this->connection->get_name(this->connection); - } - - if (logger == NULL) - { - logger = this->logger; - } - logger->log(logger, CONTROL|LEVEL1, " \"%s\": IKE_SA in state %s, SPIs: 0x%.16llx 0x%.16llx", - name, - mapping_find(ike_sa_state_m, this->state), - this->ike_sa_id->get_initiator_spi(this->ike_sa_id), - this->ike_sa_id->get_responder_spi(this->ike_sa_id)); - logger->log(logger, CONTROL, " \"%s\": %s[%s]...%s[%s]", - name, - my_host->get_string(my_host), - my_id ? my_id->get_string(my_id) : "(unknown)", - other_host->get_string(other_host), - other_id ? other_id->get_string(other_id) : "(unknown)"); - - iterator = this->child_sas->create_iterator(this->child_sas, TRUE); - while (iterator->has_next(iterator)) - { - iterator->current(iterator, (void**)&child_sa); - child_sa->log_status(child_sa, logger, name); - } - iterator->destroy(iterator); } /** @@ -1313,6 +1377,7 @@ static void destroy(private_ike_sa_t *this) { child_sa_t *child_sa; transaction_t *transaction; + char *my_host, *other_host, *my_id, *other_id; this->logger->log(this->logger, CONTROL|LEVEL2, "going to destroy IKE SA %llu:%llu, role %s", this->ike_sa_id->get_initiator_spi(this->ike_sa_id), @@ -1336,73 +1401,38 @@ static void destroy(private_ike_sa_t *this) transaction->destroy(transaction); } this->transaction_queue->destroy(this->transaction_queue); - if (this->transaction_in) - { - this->transaction_in->destroy(this->transaction_in); - } - if (this->transaction_in_next) - { - this->transaction_in_next->destroy(this->transaction_in_next); - } - if (this->transaction_out) - { - this->transaction_out->destroy(this->transaction_out); - } - if (this->crypter_in) - { - this->crypter_in->destroy(this->crypter_in); - } - if (this->crypter_out) - { - this->crypter_out->destroy(this->crypter_out); - } - if (this->signer_in) - { - this->signer_in->destroy(this->signer_in); - } - if (this->signer_out) - { - this->signer_out->destroy(this->signer_out); - } - if (this->prf) - { - this->prf->destroy(this->prf); - } - if (this->child_prf) - { - this->child_prf->destroy(this->child_prf); - } - if (this->prf_auth_i) - { - this->prf_auth_i->destroy(this->prf_auth_i); - } - if (this->prf_auth_r) - { - this->prf_auth_r->destroy(this->prf_auth_r); - } - if (this->connection) - { - host_t *my_host, *other_host; - identification_t *my_id = NULL, *other_id = NULL; - my_host = this->connection->get_my_host(this->connection); - other_host = this->connection->get_other_host(this->connection); - if (this->policy) - { - my_id = this->policy->get_my_id(this->policy); - other_id = this->policy->get_other_id(this->policy); - } - - this->logger->log(this->logger, AUDIT, "IKE_SA deleted between %s[%s]...%s[%s]", - my_host->get_string(my_host), - my_id ? my_id->get_string(my_id) : "(unknown)", - other_host->get_string(other_host), - other_id ? other_id->get_string(other_id) : "(unknown)"); - this->connection->destroy(this->connection); - } - if (this->policy) - { - this->policy->destroy(this->policy); - } + + DESTROY_IF(this->transaction_in); + DESTROY_IF(this->transaction_in_next); + DESTROY_IF(this->transaction_out); + DESTROY_IF(this->crypter_in); + DESTROY_IF(this->crypter_out); + DESTROY_IF(this->signer_in); + DESTROY_IF(this->signer_out); + DESTROY_IF(this->prf); + DESTROY_IF(this->child_prf); + DESTROY_IF(this->prf_auth_i); + DESTROY_IF(this->prf_auth_r); + + my_host = this->my_host ? + this->my_host->get_string(this->my_host) : "(unknown)"; + other_host = this->other_host ? + this->other_host->get_string(this->other_host) : "(unknown)"; + my_id = this->my_id ? + this->my_id->get_string(this->my_id) : "(unknown)"; + other_id = this->other_id ? + this->other_id->get_string(this->other_id) : "(unknown)"; + + this->logger->log(this->logger, AUDIT, + "IKE_SA deleted between %s[%s]...%s[%s]", + my_host, my_id, other_host, other_id); + + DESTROY_IF(this->my_host); + DESTROY_IF(this->other_host); + DESTROY_IF(this->my_id); + DESTROY_IF(this->other_id); + + free(this->name); this->ike_sa_id->destroy(this->ike_sa_id); free(this); } @@ -1417,11 +1447,20 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) /* Public functions */ this->public.get_state = (ike_sa_state_t(*)(ike_sa_t*)) get_state; this->public.set_state = (void(*)(ike_sa_t*,ike_sa_state_t)) set_state; + this->public.get_name = (char*(*)(ike_sa_t*))get_name; + this->public.set_name = (void(*)(ike_sa_t*,char*))set_name; this->public.process_message = (status_t(*)(ike_sa_t*, message_t*)) process_message; - this->public.initiate = (status_t(*)(ike_sa_t*,connection_t*)) initiate; + this->public.initiate = (status_t(*)(ike_sa_t*,connection_t*,policy_t*)) initiate; + this->public.route = (status_t(*)(ike_sa_t*,policy_t*)) route; + this->public.acquire = (status_t(*)(ike_sa_t*,u_int32_t)) acquire; this->public.get_id = (ike_sa_id_t*(*)(ike_sa_t*)) get_id; + this->public.get_my_host = (host_t*(*)(ike_sa_t*)) get_my_host; + this->public.get_other_host = (host_t*(*)(ike_sa_t*)) get_other_host; + this->public.get_my_id = (identification_t*(*)(ike_sa_t*)) get_my_id; + this->public.set_my_id = (void(*)(ike_sa_t*,identification_t*)) set_my_id; + this->public.get_other_id = (identification_t*(*)(ike_sa_t*)) get_other_id; + this->public.set_other_id = (void(*)(ike_sa_t*,identification_t*)) set_other_id; this->public.get_next_message_id = (u_int32_t(*)(ike_sa_t*)) get_next_message_id; - this->public.get_connection = (connection_t*(*)(ike_sa_t*)) get_connection; this->public.retransmit_request = (status_t (*) (ike_sa_t *, u_int32_t)) retransmit_request; this->public.log_status = (void (*) (ike_sa_t*,logger_t*,char*))log_status; this->public.delete = (status_t(*)(ike_sa_t*))delete_; @@ -1432,10 +1471,6 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->public.get_child_prf = (prf_t *(*) (ike_sa_t *)) get_child_prf; this->public.get_prf_auth_i = (prf_t *(*) (ike_sa_t *)) get_prf_auth_i; this->public.get_prf_auth_r = (prf_t *(*) (ike_sa_t *)) get_prf_auth_r; - this->public.set_connection = (void (*) (ike_sa_t *,connection_t *)) set_connection; - this->public.get_connection = (connection_t *(*) (ike_sa_t *)) get_connection; - this->public.set_policy = (void (*) (ike_sa_t *,policy_t *)) set_policy; - this->public.get_policy = (policy_t *(*) (ike_sa_t *)) get_policy; this->public.build_transforms = (status_t (*) (ike_sa_t *,proposal_t*,diffie_hellman_t*,chunk_t,chunk_t,bool)) build_transforms; this->public.add_child_sa = (void (*) (ike_sa_t*,child_sa_t*)) add_child_sa; this->public.get_child_sa = (child_sa_t* (*)(ike_sa_t*,protocol_id_t,u_int32_t,bool)) get_child_sa; @@ -1448,7 +1483,12 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) /* initialize private fields */ this->logger = logger_manager->get_logger(logger_manager, IKE_SA); this->ike_sa_id = ike_sa_id->clone(ike_sa_id); + this->name = strdup("(uninitialized)"); this->child_sas = linked_list_create(); + this->my_host = NULL; + this->other_host = NULL; + this->my_id = NULL; + this->other_id = NULL; this->crypter_in = NULL; this->crypter_out = NULL; this->signer_in = NULL; @@ -1457,8 +1497,6 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->prf_auth_i = NULL; this->prf_auth_r = NULL; this->child_prf = NULL; - this->connection = NULL; - this->policy = NULL; this->nat_here = FALSE; this->nat_there = FALSE; this->transaction_queue = linked_list_create(); diff --git a/src/charon/sa/ike_sa.h b/src/charon/sa/ike_sa.h index ab94505fd..f593e382a 100644 --- a/src/charon/sa/ike_sa.h +++ b/src/charon/sa/ike_sa.h @@ -152,20 +152,115 @@ struct ike_sa_t { * @param state state to set for the IKE_SA */ void (*set_state) (ike_sa_t *this, ike_sa_state_t ike_sa); + + /** + * @brief Get the name of the connection this IKE_SA uses. + * + * @param this calling object + * @return name + */ + char* (*get_name) (ike_sa_t *this); + + /** + * @brief Set the name of the connection this IKE_SA uses. + * + * @param this calling object + * @param name name, gets cloned + */ + void (*set_name) (ike_sa_t *this, char* name); + + /** + * @brief Get the own host address. + * + * @param this calling object + * @return host address + */ + host_t* (*get_my_host) (ike_sa_t *this); + + /** + * @brief Get the other peers host address. + * + * @param this calling object + * @return host address + */ + host_t* (*get_other_host) (ike_sa_t *this); + + /** + * @brief Get the own identification. + * + * @param this calling object + * @return identification + */ + identification_t* (*get_my_id) (ike_sa_t *this); + + /** + * @brief Set the own identification. + * + * @param this calling object + * @param me identification + */ + void (*set_my_id) (ike_sa_t *this, identification_t *me); + + /** + * @brief Get the other peers identification. + * + * @param this calling object + * @return identification + */ + identification_t* (*get_other_id) (ike_sa_t *this); + + /** + * @brief Set the other peers identification. + * + * @param this calling object + * @param other identification + */ + void (*set_other_id) (ike_sa_t *this, identification_t *other); /** * @brief Initiate a new connection. * - * The connection_t object is owned by the IKE_SA after the call, so + * The policy/connection is owned by the IKE_SA after the call, so * do not modify or destroy it. * * @param this calling object * @param connection connection to initiate + * @param policy policy to set up + * @return + * - SUCCESS if initialization started + * - DESTROY_ME if initialization failed and IKE_SA MUST be deleted + */ + status_t (*initiate) (ike_sa_t *this, connection_t *connection, policy_t *policy); + + /** + * @brief Route a policy in the kernel. + * + * Installs the policies in the kernel. If traffic matches, + * the kernel requests connection setup from the IKE_SA via acquire(). + * The policy is owned by the IKE_SA after the call, so + * do not modify or destroy it. + * + * @param this calling object + * @param policy policy to route + * @return + * - SUCCESS if initialization started + * - DESTROY_ME if initialization failed and IKE_SA MUST be deleted + */ + status_t (*route) (ike_sa_t *this, policy_t *policy); + + /** + * @brief Acquire connection setup for a policy. + * + * If an installed policy raises an acquire, the kernel calls + * this function to establsh the CHILD_SA (and maybe the IKE_SA). + * + * @param this calling object + * @param reqid reqid of the CHILD_SA the policy belongs to. * @return * - SUCCESS if initialization started * - DESTROY_ME if initialization failed and IKE_SA MUST be deleted */ - status_t (*initiate) (ike_sa_t *this, connection_t *connection); + status_t (*acquire) (ike_sa_t *this, u_int32_t reqid); /** * @brief Initiates the deletion of an IKE_SA. @@ -280,38 +375,6 @@ struct ike_sa_t { * @param name name of the connection */ void (*log_status) (ike_sa_t *this, logger_t *logger, char *name); - - /** - * @brief Get the internal stored connection_t object. - * - * @param this calling object - * @return pointer to the internal stored connection_t object - */ - connection_t *(*get_connection) (ike_sa_t *this); - - /** - * @brief Set the internal connection object. - * - * @param this calling object - * @param connection object of type connection_t - */ - void (*set_connection) (ike_sa_t *this, connection_t *connection); - - /** - * @brief Get the internal stored policy object. - * - * @param this calling object - * @return pointer to the internal stored policy_t object - */ - policy_t *(*get_policy) (ike_sa_t *this); - - /** - * @brief Set the internal policy_t object. - * - * @param this calling object - * @param policy object of type policy_t - */ - void (*set_policy) (ike_sa_t *this, policy_t *policy); /** * @brief Derive all keys and create the transforms for IKE communication. diff --git a/src/charon/sa/ike_sa_manager.c b/src/charon/sa/ike_sa_manager.c index e6a738d50..b0822acb7 100644 --- a/src/charon/sa/ike_sa_manager.c +++ b/src/charon/sa/ike_sa_manager.c @@ -600,19 +600,15 @@ linked_list_t *get_ike_sa_list_by_name(private_ike_sa_manager_t* this, const cha { linked_list_t *list; iterator_t *iterator; + ike_sa_entry_t *entry; pthread_mutex_lock(&(this->mutex)); list = linked_list_create(); iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE); - while (iterator->has_next(iterator)) + while (iterator->iterate(iterator, (void**)&entry)) { - ike_sa_entry_t *entry; - connection_t *connection; - - iterator->current(iterator, (void**)&entry); - connection = entry->ike_sa->get_connection(entry->ike_sa); - if (strcmp(name, connection->get_name(connection)) == 0) + if (strcmp(name, entry->ike_sa->get_name(entry->ike_sa)) == 0) { list->insert_last(list, (void*)entry->ike_sa_id->clone(entry->ike_sa_id)); } diff --git a/src/charon/sa/transactions/create_child_sa.c b/src/charon/sa/transactions/create_child_sa.c index 14d1dab70..4c29cabd1 100644 --- a/src/charon/sa/transactions/create_child_sa.c +++ b/src/charon/sa/transactions/create_child_sa.c @@ -70,11 +70,6 @@ struct private_create_child_sa_t { u_int32_t rekey_spi; /** - * connection of IKE_SA - */ - connection_t *connection; - - /** * policy definition used */ policy_t *policy; @@ -152,6 +147,14 @@ static u_int32_t requested(private_create_child_sa_t *this) } /** + * Implementation of create_child_sa_t.set_policy. + */ +static void set_policy(private_create_child_sa_t *this, policy_t *policy) +{ + this->policy = policy; +} + +/** * Implementation of create_child_sa_t.rekeys_child. */ static void rekeys_child(private_create_child_sa_t *this, child_sa_t *child_sa) @@ -169,6 +172,22 @@ static void cancel(private_create_child_sa_t *this) } /** + * destroy a list of traffic selectors + */ +static void destroy_ts_list(linked_list_t *list) +{ + if (list) + { + traffic_selector_t *ts; + while (list->remove_last(list, (void**)&ts) == SUCCESS) + { + ts->destroy(ts); + } + list->destroy(list); + } +} + +/** * Implementation of transaction_t.get_request. */ static status_t get_request(private_create_child_sa_t *this, message_t **result) @@ -176,6 +195,13 @@ static status_t get_request(private_create_child_sa_t *this, message_t **result) message_t *request; host_t *me, *other; + /* check if we already have built a message (retransmission) */ + if (this->message) + { + *result = this->message; + return SUCCESS; + } + /* check if we are not already rekeying */ if (this->rekeyed_sa) { @@ -195,17 +221,8 @@ static status_t get_request(private_create_child_sa_t *this, message_t **result) this->rekeyed_sa->set_state(this->rekeyed_sa, CHILD_REKEYING); } - /* check if we already have built a message (retransmission) */ - if (this->message) - { - *result = this->message; - return SUCCESS; - } - - this->connection = this->ike_sa->get_connection(this->ike_sa); - me = this->connection->get_my_host(this->connection); - other = this->connection->get_other_host(this->connection); - this->policy = this->ike_sa->get_policy(this->ike_sa); + me = this->ike_sa->get_my_host(this->ike_sa); + other = this->ike_sa->get_other_host(this->ike_sa); /* build the request */ request = message_create(); @@ -223,9 +240,31 @@ static status_t get_request(private_create_child_sa_t *this, message_t **result) bool use_natt; u_int32_t reqid = 0; + /* get a policy, if we are rekeying */ if (this->rekeyed_sa) { + linked_list_t *my_ts, *other_ts; + identification_t *my_id, *other_id; + + my_ts = this->rekeyed_sa->get_my_traffic_selectors(this->rekeyed_sa); + other_ts = this->rekeyed_sa->get_other_traffic_selectors(this->rekeyed_sa); + my_id = this->ike_sa->get_my_id(this->ike_sa); + other_id = this->ike_sa->get_other_id(this->ike_sa); + + this->policy = charon->policies->get_policy(charon->policies, + my_id, other_id, + my_ts, other_ts, + me, other); + reqid = this->rekeyed_sa->get_reqid(this->rekeyed_sa); + + if (this->policy == NULL) + { + this->logger->log(this->logger, ERROR, + "no policy found to rekey CHILD_SA with reqid %d", + reqid); + return FAILED; + } } proposals = this->policy->get_proposals(this->policy); @@ -261,8 +300,9 @@ static status_t get_request(private_create_child_sa_t *this, message_t **result) linked_list_t *ts_list; ts_payload_t *ts_payload; - ts_list = this->policy->get_my_traffic_selectors(this->policy); + ts_list = this->policy->get_my_traffic_selectors(this->policy, me); ts_payload = ts_payload_create_from_traffic_selectors(TRUE, ts_list); + destroy_ts_list(ts_list); request->add_payload(request, (payload_t*)ts_payload); } @@ -270,8 +310,9 @@ static status_t get_request(private_create_child_sa_t *this, message_t **result) linked_list_t *ts_list; ts_payload_t *ts_payload; - ts_list = this->policy->get_other_traffic_selectors(this->policy); + ts_list = this->policy->get_other_traffic_selectors(this->policy, other); ts_payload = ts_payload_create_from_traffic_selectors(FALSE, ts_list); + destroy_ts_list(ts_list); request->add_payload(request, (payload_t*)ts_payload); } @@ -439,22 +480,6 @@ static status_t install_child_sa(private_create_child_sa_t *this, bool initiator } /** - * destroy a list of traffic selectors - */ -static void destroy_ts_list(linked_list_t *list) -{ - if (list) - { - traffic_selector_t *ts; - while (list->remove_last(list, (void**)&ts) == SUCCESS) - { - ts->destroy(ts); - } - list->destroy(list); - } -} - -/** * Implementation of transaction_t.get_response. */ static status_t get_response(private_create_child_sa_t *this, message_t *request, @@ -477,10 +502,8 @@ static status_t get_response(private_create_child_sa_t *this, message_t *request return SUCCESS; } - this->connection = this->ike_sa->get_connection(this->ike_sa); - me = this->connection->get_my_host(this->connection); - other = this->connection->get_other_host(this->connection); - this->policy = this->ike_sa->get_policy(this->ike_sa); + me = this->ike_sa->get_my_host(this->ike_sa); + other = this->ike_sa->get_other_host(this->ike_sa); this->message_id = request->get_message_id(request); /* set up response */ @@ -573,16 +596,35 @@ static status_t get_response(private_create_child_sa_t *this, message_t *request nonce_response->set_nonce(nonce_response, this->nonce_r); } - { /* process traffic selectors for other */ - linked_list_t *ts_received = tsi_request->get_traffic_selectors(tsi_request); - this->tsi = this->policy->select_other_traffic_selectors(this->policy, ts_received); - destroy_ts_list(ts_received); - } - - { /* process traffic selectors for us */ - linked_list_t *ts_received = ts_received = tsr_request->get_traffic_selectors(tsr_request); - this->tsr = this->policy->select_my_traffic_selectors(this->policy, ts_received); - destroy_ts_list(ts_received); + { /* get a policy and process traffic selectors */ + identification_t *my_id, *other_id; + linked_list_t *my_ts, *other_ts; + + my_id = this->ike_sa->get_my_id(this->ike_sa); + other_id = this->ike_sa->get_other_id(this->ike_sa); + + my_ts = tsr_request->get_traffic_selectors(tsr_request); + other_ts = tsi_request->get_traffic_selectors(tsi_request); + + this->policy = charon->policies->get_policy(charon->policies, + my_id, other_id, + my_ts, other_ts, + me, other); + if (this->policy) + { + this->tsr = this->policy->select_my_traffic_selectors(this->policy, my_ts, me); + this->tsi = this->policy->select_other_traffic_selectors(this->policy, other_ts, other); + } + destroy_ts_list(my_ts); + destroy_ts_list(other_ts); + + if (this->policy == NULL) + { + this->logger->log(this->logger, AUDIT, + "no acceptable policy found, adding TS_UNACCEPTABLE notify"); + build_notify(TS_UNACCEPTABLE, CHUNK_INITIALIZER, response, TRUE); + return FAILED; + } } { /* process SA payload */ @@ -705,8 +747,8 @@ static status_t conclude(private_create_child_sa_t *this, message_t *response, return FAILED; } - me = this->connection->get_my_host(this->connection); - other = this->connection->get_other_host(this->connection); + me = this->ike_sa->get_my_host(this->ike_sa); + other = this->ike_sa->get_other_host(this->ike_sa); /* Iterate over all payloads to collect them */ payloads = response->get_payload_iterator(response); @@ -761,13 +803,13 @@ static status_t conclude(private_create_child_sa_t *this, message_t *response, { /* process traffic selectors for us */ linked_list_t *ts_received = tsi_payload->get_traffic_selectors(tsi_payload); - this->tsi = this->policy->select_my_traffic_selectors(this->policy, ts_received); + this->tsi = this->policy->select_my_traffic_selectors(this->policy, ts_received, me); destroy_ts_list(ts_received); } { /* process traffic selectors for other */ linked_list_t *ts_received = tsr_payload->get_traffic_selectors(tsr_payload); - this->tsr = this->policy->select_other_traffic_selectors(this->policy, ts_received); + this->tsr = this->policy->select_other_traffic_selectors(this->policy, ts_received, other); destroy_ts_list(ts_received); } @@ -790,8 +832,7 @@ static status_t conclude(private_create_child_sa_t *this, message_t *response, this->tsi->get_count(this->tsi) == 0 || this->tsr->get_count(this->tsr) == 0) { - this->logger->log(this->logger, AUDIT, - "CHILD_SA creation failed"); + this->logger->log(this->logger, AUDIT, "CHILD_SA creation failed"); return FAILED; } new_child = this->child_sa; @@ -863,18 +904,10 @@ static status_t conclude(private_create_child_sa_t *this, message_t *response, */ static void destroy(private_create_child_sa_t *this) { - if (this->message) - { - this->message->destroy(this->message); - } - if (this->proposal) - { - this->proposal->destroy(this->proposal); - } - if (this->child_sa) - { - this->child_sa->destroy(this->child_sa); - } + DESTROY_IF(this->message); + DESTROY_IF(this->proposal); + DESTROY_IF(this->child_sa); + DESTROY_IF(this->policy); destroy_ts_list(this->tsi); destroy_ts_list(this->tsr); chunk_free(&this->nonce_i); @@ -900,6 +933,7 @@ create_child_sa_t *create_child_sa_create(ike_sa_t *ike_sa) this->public.transaction.destroy = (void(*)(transaction_t*))destroy; /* public functions */ + this->public.set_policy = (void(*)(create_child_sa_t*,policy_t*))set_policy; this->public.rekeys_child = (void(*)(create_child_sa_t*,child_sa_t*))rekeys_child; this->public.cancel = (void(*)(create_child_sa_t*))cancel; @@ -916,6 +950,7 @@ create_child_sa_t *create_child_sa_create(ike_sa_t *ike_sa) this->rekeyed_sa = NULL; this->lost = FALSE; this->proposal = NULL; + this->policy = NULL; this->tsi = NULL; this->tsr = NULL; this->randomizer = randomizer_create(); diff --git a/src/charon/sa/transactions/create_child_sa.h b/src/charon/sa/transactions/create_child_sa.h index df7a64fde..d45bfcc6b 100644 --- a/src/charon/sa/transactions/create_child_sa.h +++ b/src/charon/sa/transactions/create_child_sa.h @@ -33,6 +33,10 @@ typedef struct create_child_sa_t create_child_sa_t; /** * @brief A transaction to create a new or rekey an existing CHILD_SA. * + * If the CHILD_SA is intended to create a new CHILD_SA, set the policy + * with set_policy(). If it is intended to rekey an existing CHILD_SA, + * set the appropriate CHILD_SA with rekeys_child(). + * * Rekeying of an CHILD_SA works the same way as creating a new one, * but includes an additional REKEY_SA notify and deletes the old * one (in a separate transaction). @@ -68,10 +72,15 @@ struct create_child_sa_t { transaction_t transaction; /** - * @brief Set the CHILD_SA which gets rekeyed by the new one. + * @brief Set the policy to use for creating a new CHILD_SA. * - * If this transaction is used for rekeying, set the inbound - * SPI of the CHILD_SA which the new CHILD_SA rekeys. + * @param this calling object + * @param policy policy for CHILD_SA + */ + void (*set_policy) (create_child_sa_t* this, policy_t *policy); + + /** + * @brief Set the CHILD_SA which gets rekeyed by the new one. * * @param this calling object * @param child_sa CHILD_SA to rekey @@ -79,9 +88,9 @@ struct create_child_sa_t { void (*rekeys_child) (create_child_sa_t* this, child_sa_t *child_sa); /** - * @brief Cancel a rekeying request. + * @brief Cancel the request. * - * Cancelling a rekeying request will set a flag in the transaction. When + * Cancelling the request will set a flag in the transaction. When * the response for the transaction is received, the created CHILD_SA * gets deleted afterwards. * diff --git a/src/charon/sa/transactions/dead_peer_detection.c b/src/charon/sa/transactions/dead_peer_detection.c index c7f5db604..a0e687c32 100644 --- a/src/charon/sa/transactions/dead_peer_detection.c +++ b/src/charon/sa/transactions/dead_peer_detection.c @@ -85,7 +85,6 @@ static u_int32_t requested(private_dead_peer_detection_t *this) static status_t get_request(private_dead_peer_detection_t *this, message_t **result) { message_t *request; - connection_t *connection; host_t *me, *other; /* check if we already have built a message (retransmission) */ @@ -95,9 +94,8 @@ static status_t get_request(private_dead_peer_detection_t *this, message_t **res return SUCCESS; } - connection = this->ike_sa->get_connection(this->ike_sa); - me = connection->get_my_host(connection); - other = connection->get_other_host(connection); + me = this->ike_sa->get_my_host(this->ike_sa); + other = this->ike_sa->get_other_host(this->ike_sa); /* build the request */ request = message_create(); @@ -124,7 +122,6 @@ static status_t get_response(private_dead_peer_detection_t *this, message_t *req { host_t *me, *other; message_t *response; - connection_t *connection; /* check if we already have built a response (retransmission) */ if (this->message) @@ -133,9 +130,8 @@ static status_t get_response(private_dead_peer_detection_t *this, message_t *req return SUCCESS; } - connection = this->ike_sa->get_connection(this->ike_sa); - me = connection->get_my_host(connection); - other = connection->get_other_host(connection); + me = this->ike_sa->get_my_host(this->ike_sa); + other = this->ike_sa->get_other_host(this->ike_sa); this->message_id = request->get_message_id(request); /* set up response */ @@ -167,10 +163,7 @@ static status_t conclude(private_dead_peer_detection_t *this, message_t *respons */ static void destroy(private_dead_peer_detection_t *this) { - if (this->message) - { - this->message->destroy(this->message); - } + DESTROY_IF(this->message); free(this); } diff --git a/src/charon/sa/transactions/delete_child_sa.c b/src/charon/sa/transactions/delete_child_sa.c index e8ca4bbae..f8399628b 100644 --- a/src/charon/sa/transactions/delete_child_sa.c +++ b/src/charon/sa/transactions/delete_child_sa.c @@ -100,7 +100,6 @@ static void set_child_sa(private_delete_child_sa_t *this, child_sa_t *child_sa) static status_t get_request(private_delete_child_sa_t *this, message_t **result) { message_t *request; - connection_t *connection; host_t *me, *other; /* check if we already have built a message (retransmission) */ @@ -110,9 +109,8 @@ static status_t get_request(private_delete_child_sa_t *this, message_t **result) return SUCCESS; } - connection = this->ike_sa->get_connection(this->ike_sa); - me = connection->get_my_host(connection); - other = connection->get_other_host(connection); + me = this->ike_sa->get_my_host(this->ike_sa); + other = this->ike_sa->get_other_host(this->ike_sa); /* build the request */ request = message_create(); @@ -228,7 +226,6 @@ static status_t get_response(private_delete_child_sa_t *this, message_t *request host_t *me, *other; message_t *response; iterator_t *payloads; - connection_t *connection; /* check if we already have built a response (retransmission) */ if (this->message) @@ -237,9 +234,8 @@ static status_t get_response(private_delete_child_sa_t *this, message_t *request return SUCCESS; } - connection = this->ike_sa->get_connection(this->ike_sa); - me = connection->get_my_host(connection); - other = connection->get_other_host(connection); + me = this->ike_sa->get_my_host(this->ike_sa); + other = this->ike_sa->get_other_host(this->ike_sa); this->message_id = request->get_message_id(request); /* set up response */ @@ -335,10 +331,7 @@ static status_t conclude(private_delete_child_sa_t *this, message_t *response, */ static void destroy(private_delete_child_sa_t *this) { - if (this->message) - { - this->message->destroy(this->message); - } + DESTROY_IF(this->message); free(this); } diff --git a/src/charon/sa/transactions/delete_ike_sa.c b/src/charon/sa/transactions/delete_ike_sa.c index 95f9fc654..3ab89a45c 100644 --- a/src/charon/sa/transactions/delete_ike_sa.c +++ b/src/charon/sa/transactions/delete_ike_sa.c @@ -86,7 +86,6 @@ static u_int32_t requested(private_delete_ike_sa_t *this) static status_t get_request(private_delete_ike_sa_t *this, message_t **result) { message_t *request; - connection_t *connection; host_t *me, *other; delete_payload_t *delete_payload; @@ -97,9 +96,8 @@ static status_t get_request(private_delete_ike_sa_t *this, message_t **result) return SUCCESS; } - connection = this->ike_sa->get_connection(this->ike_sa); - me = connection->get_my_host(connection); - other = connection->get_other_host(connection); + me = this->ike_sa->get_my_host(this->ike_sa); + other = this->ike_sa->get_other_host(this->ike_sa); /* build the request */ request = message_create(); @@ -134,7 +132,6 @@ static status_t get_response(private_delete_ike_sa_t *this, message_t *request, message_t *response; iterator_t *payloads; delete_payload_t *delete_request = NULL; - connection_t *connection; /* check if we already have built a response (retransmission) * this only happens in special simultanous transaction cases, @@ -145,9 +142,8 @@ static status_t get_response(private_delete_ike_sa_t *this, message_t *request, return SUCCESS; } - connection = this->ike_sa->get_connection(this->ike_sa); - me = connection->get_my_host(connection); - other = connection->get_other_host(connection); + me = this->ike_sa->get_my_host(this->ike_sa); + other = this->ike_sa->get_other_host(this->ike_sa); this->message_id = request->get_message_id(request); /* set up response */ @@ -240,10 +236,7 @@ static status_t conclude(private_delete_ike_sa_t *this, message_t *response, */ static void destroy(private_delete_ike_sa_t *this) { - if (this->message) - { - this->message->destroy(this->message); - } + DESTROY_IF(this->message); free(this); } diff --git a/src/charon/sa/transactions/ike_auth.c b/src/charon/sa/transactions/ike_auth.c index 53ba6205c..2bf12f754 100644 --- a/src/charon/sa/transactions/ike_auth.c +++ b/src/charon/sa/transactions/ike_auth.c @@ -90,12 +90,12 @@ struct private_ike_auth_t { chunk_t init_response; /** - * connection definition used + * connection definition used for IKE_SA setup */ connection_t *connection; /** - * policy definition used + * policy definition used CHILD_SA creation */ policy_t *policy; @@ -147,6 +147,16 @@ static u_int32_t requested(private_ike_auth_t *this) } /** + * Implementation of transaction_t.set_config. + */ +static void set_config(private_ike_auth_t *this, + connection_t *connection, policy_t *policy) +{ + this->connection = connection; + this->policy = policy; +} + +/** * Implementation of transaction_t.set_nonces. */ static void set_nonces(private_ike_auth_t *this, chunk_t nonce_i, chunk_t nonce_r) @@ -165,6 +175,23 @@ static void set_init_messages(private_ike_auth_t *this, chunk_t init_request, ch } /** + * destroy a list of traffic selectors + */ +static void destroy_ts_list(linked_list_t *list) +{ + if (list) + { + traffic_selector_t *ts; + + while (list->remove_last(list, (void**)&ts) == SUCCESS) + { + ts->destroy(ts); + } + list->destroy(list); + } +} + +/** * Implementation of transaction_t.get_request. */ static status_t get_request(private_ike_auth_t *this, message_t **result) @@ -181,10 +208,8 @@ static status_t get_request(private_ike_auth_t *this, message_t **result) return SUCCESS; } - this->connection = this->ike_sa->get_connection(this->ike_sa); - me = this->connection->get_my_host(this->connection); - other = this->connection->get_other_host(this->connection); - this->policy = this->ike_sa->get_policy(this->ike_sa); + me = this->ike_sa->get_my_host(this->ike_sa); + other = this->ike_sa->get_other_host(this->ike_sa); my_id = this->policy->get_my_id(this->policy); other_id = this->policy->get_other_id(this->policy); @@ -203,6 +228,7 @@ static status_t get_request(private_ike_auth_t *this, message_t **result) { /* build ID payload */ my_id_payload = id_payload_create_from_identification(TRUE, my_id); request->add_payload(request, (payload_t*)my_id_payload); + this->ike_sa->set_my_id(this->ike_sa, my_id->clone(my_id)); } { /* TODO: build certreq payload */ @@ -239,9 +265,11 @@ static status_t get_request(private_ike_auth_t *this, message_t **result) { /* build auth payload */ authenticator_t *authenticator; auth_payload_t *auth_payload; + auth_method_t auth_method; status_t status; - - authenticator = authenticator_create(this->ike_sa); + + auth_method = this->connection->get_auth_method(this->connection); + authenticator = authenticator_create(this->ike_sa, auth_method); status = authenticator->compute_auth_data(authenticator, &auth_payload, this->init_request, this->nonce_r, my_id_payload, TRUE); authenticator->destroy(authenticator); @@ -278,8 +306,9 @@ static status_t get_request(private_ike_auth_t *this, message_t **result) linked_list_t *ts_list; ts_payload_t *ts_payload; - ts_list = this->policy->get_my_traffic_selectors(this->policy); + ts_list = this->policy->get_my_traffic_selectors(this->policy, me); ts_payload = ts_payload_create_from_traffic_selectors(TRUE, ts_list); + destroy_ts_list(ts_list); request->add_payload(request, (payload_t*)ts_payload); } @@ -288,8 +317,9 @@ static status_t get_request(private_ike_auth_t *this, message_t **result) linked_list_t *ts_list; ts_payload_t *ts_payload; - ts_list = this->policy->get_other_traffic_selectors(this->policy); + ts_list = this->policy->get_other_traffic_selectors(this->policy, other); ts_payload = ts_payload_create_from_traffic_selectors(FALSE, ts_list); + destroy_ts_list(ts_list); request->add_payload(request, (payload_t*)ts_payload); } @@ -465,23 +495,6 @@ static status_t install_child_sa(private_ike_auth_t *this, bool initiator) } /** - * destroy a list of traffic selectors - */ -static void destroy_ts_list(linked_list_t *list) -{ - if (list) - { - traffic_selector_t *ts; - - while (list->remove_last(list, (void**)&ts) == SUCCESS) - { - ts->destroy(ts); - } - list->destroy(list); - } -} - -/** * Implementation of transaction_t.get_response. */ static status_t get_response(private_ike_auth_t *this, message_t *request, @@ -508,9 +521,8 @@ static status_t get_response(private_ike_auth_t *this, message_t *request, return SUCCESS; } - this->connection = this->ike_sa->get_connection(this->ike_sa); - me = this->connection->get_my_host(this->connection); - other = this->connection->get_other_host(this->connection); + me = this->ike_sa->get_my_host(this->ike_sa); + other = this->ike_sa->get_other_host(this->ike_sa); this->message_id = request->get_message_id(request); /* set up response */ @@ -607,13 +619,32 @@ static status_t get_response(private_ike_auth_t *this, message_t *request, { my_id = identification_create_from_encoding(ID_ANY, CHUNK_INITIALIZER); } + } + + { /* get a policy and process traffic selectors */ + linked_list_t *my_ts, *other_ts; + + my_ts = tsr_request->get_traffic_selectors(tsr_request); + other_ts = tsi_request->get_traffic_selectors(tsi_request); + + this->policy = charon->policies->get_policy(charon->policies, + my_id, other_id, + my_ts, other_ts, + me, other); + if (this->policy) + { + this->tsr = this->policy->select_my_traffic_selectors(this->policy, my_ts, me); + this->tsi = this->policy->select_other_traffic_selectors(this->policy, other_ts, other); + } + destroy_ts_list(my_ts); + destroy_ts_list(other_ts); - /* get policy from store */ - this->policy = charon->policies->get_policy_by_ids(charon->policies, my_id, other_id); + /* TODO: We should check somehow if we have a policy, but with other + * traffic selectors. Then we would create a IKE_SA without a CHILD_SA. */ if (this->policy == NULL) { this->logger->log(this->logger, AUDIT, - "we don't have a policy for IDs %s - %s, deleting IKE_SA", + "no acceptable policy for IDs %s - %s found, deleting IKE_SA", my_id->get_string(my_id), other_id->get_string(other_id)); my_id->destroy(my_id); other_id->destroy(other_id); @@ -621,16 +652,12 @@ static status_t get_response(private_ike_auth_t *this, message_t *request, return DESTROY_ME; } my_id->destroy(my_id); - other_id->destroy(other_id); /* get my id from policy, which must contain a fully qualified valid id */ my_id = this->policy->get_my_id(this->policy); + this->ike_sa->set_my_id(this->ike_sa, my_id->clone(my_id)); + this->ike_sa->set_other_id(this->ike_sa, other_id); - /* update others traffic selectors with actually used address */ - this->policy->update_my_ts(this->policy, me); - this->policy->update_other_ts(this->policy, other); - - this->ike_sa->set_policy(this->ike_sa, this->policy); idr_response = id_payload_create_from_identification(FALSE, my_id); response->add_payload(response, (payload_t*)idr_response); } @@ -658,9 +685,11 @@ static status_t get_response(private_ike_auth_t *this, message_t *request, { /* process auth payload */ authenticator_t *authenticator; auth_payload_t *auth_response; + auth_method_t auth_method; status_t status; - - authenticator = authenticator_create(this->ike_sa); + + auth_method = this->connection->get_auth_method(this->connection); + authenticator = authenticator_create(this->ike_sa, auth_method); status = authenticator->verify_auth_data(authenticator, auth_request, this->init_request, this->nonce_r, idi_request, @@ -688,18 +717,6 @@ static status_t get_response(private_ike_auth_t *this, message_t *request, response->add_payload(response, (payload_t*)auth_response); } - { /* process traffic selectors for other */ - linked_list_t *ts_received = tsi_request->get_traffic_selectors(tsi_request); - this->tsi = this->policy->select_other_traffic_selectors(this->policy, ts_received); - destroy_ts_list(ts_received); - } - - { /* process traffic selectors for us */ - linked_list_t *ts_received = ts_received = tsr_request->get_traffic_selectors(tsr_request); - this->tsr = this->policy->select_my_traffic_selectors(this->policy, ts_received); - destroy_ts_list(ts_received); - } - { /* process SA payload */ proposal_t *proposal; linked_list_t *proposal_list; @@ -793,8 +810,8 @@ static status_t conclude(private_ike_auth_t *this, message_t *response, return DESTROY_ME; } - me = this->connection->get_my_host(this->connection); - other = this->connection->get_other_host(this->connection); + me = this->ike_sa->get_my_host(this->ike_sa); + other = this->ike_sa->get_other_host(this->ike_sa); /* Iterate over all payloads to collect them */ payloads = response->get_payload_iterator(response); @@ -872,8 +889,7 @@ static status_t conclude(private_ike_auth_t *this, message_t *response, configured_other_id->get_string(configured_other_id)); return DESTROY_ME; } - - this->policy->update_other_id(this->policy, other_id); + this->ike_sa->set_other_id(this->ike_sa, other_id); } if (cert_payload) @@ -883,9 +899,11 @@ static status_t conclude(private_ike_auth_t *this, message_t *response, { /* authenticate peer */ authenticator_t *authenticator; + auth_method_t auth_method; status_t status; - authenticator = authenticator_create(this->ike_sa); + auth_method = this->connection->get_auth_method(this->connection); + authenticator = authenticator_create(this->ike_sa, auth_method); status = authenticator->verify_auth_data(authenticator, auth_payload, this->init_response, this->nonce_i, idr_payload, @@ -900,13 +918,13 @@ static status_t conclude(private_ike_auth_t *this, message_t *response, { /* process traffic selectors for us */ linked_list_t *ts_received = tsi_payload->get_traffic_selectors(tsi_payload); - this->tsi = this->policy->select_my_traffic_selectors(this->policy, ts_received); + this->tsi = this->policy->select_my_traffic_selectors(this->policy, ts_received, me); destroy_ts_list(ts_received); } { /* process traffic selectors for other */ linked_list_t *ts_received = tsr_payload->get_traffic_selectors(tsr_payload); - this->tsr = this->policy->select_other_traffic_selectors(this->policy, ts_received); + this->tsr = this->policy->select_other_traffic_selectors(this->policy, ts_received, other); destroy_ts_list(ts_received); } @@ -952,18 +970,11 @@ static status_t conclude(private_ike_auth_t *this, message_t *response, */ static void destroy(private_ike_auth_t *this) { - if (this->message) - { - this->message->destroy(this->message); - } - if (this->proposal) - { - this->proposal->destroy(this->proposal); - } - if (this->child_sa) - { - this->child_sa->destroy(this->child_sa); - } + DESTROY_IF(this->message); + DESTROY_IF(this->proposal); + DESTROY_IF(this->child_sa); + DESTROY_IF(this->policy); + DESTROY_IF(this->connection); destroy_ts_list(this->tsi); destroy_ts_list(this->tsr); chunk_free(&this->nonce_i); @@ -989,6 +1000,7 @@ ike_auth_t *ike_auth_create(ike_sa_t *ike_sa) this->public.transaction.destroy = (void(*)(transaction_t*))destroy; /* public functions */ + this->public.set_config = (void(*)(ike_auth_t*,connection_t*,policy_t*))set_config; this->public.set_nonces = (void(*)(ike_auth_t*,chunk_t,chunk_t))set_nonces; this->public.set_init_messages = (void(*)(ike_auth_t*,chunk_t,chunk_t))set_init_messages; diff --git a/src/charon/sa/transactions/ike_auth.h b/src/charon/sa/transactions/ike_auth.h index 5c2b14c79..89263d47c 100644 --- a/src/charon/sa/transactions/ike_auth.h +++ b/src/charon/sa/transactions/ike_auth.h @@ -50,6 +50,20 @@ struct ike_auth_t { transaction_t transaction; /** + * @brief Set the config used for the ike_auth exchange. + * + * The connection definition is used to complete IKE_SA setup, the + * policy defines the CHILD_SA which is created along with the ike_auth + * exchange. + * + * @param this calling object + * @param connection connection definition + * @param policy policy definition + */ + void (*set_config) (ike_auth_t* this, + connection_t *connection, policy_t *policy); + + /** * @brief Set the nonces used in the previous ike_sa_init transaction. * * The nonces are used to create the authentication data. diff --git a/src/charon/sa/transactions/ike_sa_init.c b/src/charon/sa/transactions/ike_sa_init.c index d66ba8474..29cdcaf02 100644 --- a/src/charon/sa/transactions/ike_sa_init.c +++ b/src/charon/sa/transactions/ike_sa_init.c @@ -90,11 +90,16 @@ struct private_ike_sa_init_t { chunk_t nonce_r; /** - * connection definition used + * connection definition used for initiation */ connection_t *connection; /** + * policy definition forwarded to ike_auth transaction + */ + policy_t *policy; + + /** * Negotiated proposal used for IKE_SA */ proposal_t *proposal; @@ -150,8 +155,6 @@ struct private_ike_sa_init_t { */ static bool use_dh_group(private_ike_sa_init_t *this, diffie_hellman_group_t dh_group) { - this->connection = this->ike_sa->get_connection(this->ike_sa); - if (this->connection->check_dh_group(this->connection, dh_group)) { this->diffie_hellman = diffie_hellman_create(dh_group); @@ -164,6 +167,16 @@ static bool use_dh_group(private_ike_sa_init_t *this, diffie_hellman_group_t dh_ } /** + * Implementation of ike_sa_init_t.set_config. + */ +static void set_config(private_ike_sa_init_t *this, + connection_t *connection, policy_t *policy) +{ + this->connection = connection; + this->policy = policy; +} + +/** * Implementation of transaction_t.get_message_id. */ static u_int32_t get_message_id(private_ike_sa_init_t *this) @@ -264,7 +277,6 @@ static status_t get_request(private_ike_sa_init_t *this, message_t **result) return SUCCESS; } - this->connection = this->ike_sa->get_connection(this->ike_sa); me = this->connection->get_my_host(this->connection); other = this->connection->get_other_host(this->connection); @@ -398,6 +410,9 @@ static status_t process_notifys(private_ike_sa_init_t *this, notify_payload_t *n return DESTROY_ME; } retry = ike_sa_init_create(this->ike_sa); + retry->set_config(retry, this->connection, this->policy); + this->connection = NULL; + this->policy = NULL; retry->use_dh_group(retry, dh_group); *this->next = (transaction_t*)retry; return FAILED; @@ -523,7 +538,8 @@ static status_t get_response(private_ike_sa_init_t *this, me->get_string(me), other->get_string(other)); return DESTROY_ME; } - this->ike_sa->set_connection(this->ike_sa, this->connection); + this->ike_sa->set_name(this->ike_sa, + this->connection->get_name(this->connection)); /* Precompute NAT-D hashes for incoming NAT notify comparison */ ike_sa_id = request->get_ike_sa_id(request); @@ -769,6 +785,9 @@ static status_t get_response(private_ike_sa_init_t *this, /* create next transaction, for which we except a message */ ike_auth = ike_auth_create(this->ike_sa); + ike_auth->set_config(ike_auth, this->connection, this->policy); + this->connection = NULL; + this->policy = NULL; ike_auth->set_nonces(ike_auth, chunk_clone(this->nonce_i), chunk_clone(this->nonce_r)); @@ -802,7 +821,6 @@ static status_t conclude(private_ike_sa_init_t *this, message_t *response, sa_payload_t *sa_payload = NULL; ke_payload_t *ke_payload = NULL; nonce_payload_t *nonce_payload = NULL; - policy_t *policy; status_t status; /* check message type */ @@ -816,7 +834,6 @@ static status_t conclude(private_ike_sa_init_t *this, message_t *response, /* allow setting of next transaction in other functions */ this->next = next; - this->connection = this->ike_sa->get_connection(this->ike_sa); me = this->connection->get_my_host(this->connection); other = this->connection->get_other_host(this->connection); @@ -971,9 +988,6 @@ static status_t conclude(private_ike_sa_init_t *this, message_t *response, other->set_port(other, IKEV2_NATT_PORT); this->logger->log(this->logger, CONTROL|LEVEL1, "switching to port %d", IKEV2_NATT_PORT); } - policy = this->ike_sa->get_policy(this->ike_sa); - policy->update_my_ts(policy, me); - policy->update_other_ts(policy, other); } /* because we are original initiator we have to update the responder SPI to the new one */ @@ -1000,6 +1014,9 @@ static status_t conclude(private_ike_sa_init_t *this, message_t *response, /* create next transaction, for which we except a message */ ike_auth = ike_auth_create(this->ike_sa); + ike_auth->set_config(ike_auth, this->connection, this->policy); + this->connection = NULL; + this->policy = NULL; ike_auth->set_nonces(ike_auth, chunk_clone(this->nonce_i), chunk_clone(this->nonce_r)); @@ -1012,18 +1029,11 @@ static status_t conclude(private_ike_sa_init_t *this, message_t *response, static void destroy(private_ike_sa_init_t *this) { - if (this->message) - { - this->message->destroy(this->message); - } - if (this->diffie_hellman) - { - this->diffie_hellman->destroy(this->diffie_hellman); - } - if (this->proposal) - { - this->proposal->destroy(this->proposal); - } + DESTROY_IF(this->message); + DESTROY_IF(this->diffie_hellman); + DESTROY_IF(this->proposal); + DESTROY_IF(this->connection); + DESTROY_IF(this->policy); chunk_free(&this->nonce_i); chunk_free(&this->nonce_r); this->randomizer->destroy(this->randomizer); @@ -1049,6 +1059,7 @@ ike_sa_init_t *ike_sa_init_create(ike_sa_t *ike_sa) this->public.transaction.destroy = (void(*)(transaction_t*))destroy; /* public functions */ + this->public.set_config = (void(*)(ike_sa_init_t*,connection_t*,policy_t*))set_config; this->public.use_dh_group = (bool(*)(ike_sa_init_t*,diffie_hellman_group_t))use_dh_group; /* private data */ @@ -1060,6 +1071,7 @@ ike_sa_init_t *ike_sa_init_create(ike_sa_t *ike_sa) this->nonce_i = CHUNK_INITIALIZER; this->nonce_r = CHUNK_INITIALIZER; this->connection = NULL; + this->policy = NULL; this->proposal = NULL; this->randomizer = randomizer_create(); this->nat_hasher = hasher_create(HASH_SHA1); @@ -1070,6 +1082,6 @@ ike_sa_init_t *ike_sa_init_create(ike_sa_t *ike_sa) this->natd_src_matched = FALSE; this->natd_dst_matched = FALSE; this->logger = logger_manager->get_logger(logger_manager, IKE_SA); - + return &this->public; } diff --git a/src/charon/sa/transactions/ike_sa_init.h b/src/charon/sa/transactions/ike_sa_init.h index b268fac11..3bc049db3 100644 --- a/src/charon/sa/transactions/ike_sa_init.h +++ b/src/charon/sa/transactions/ike_sa_init.h @@ -47,6 +47,19 @@ struct ike_sa_init_t { transaction_t transaction; /** + * @brief Set connection & policy to use for initiation. + * + * The policy is not used directly, but forwarded to the + * ike_auth transaction. + * + * @param this calling object + * @param connection connection to use for initiation + * @param policy policy used in ike_auth transaction + */ + void (*set_config) (ike_sa_init_t* this, + connection_t *connection, policy_t *policy); + + /** * @brief Set the Diffie Hellman group to use for initiating. * * If a first exchange fails with a INVALID_KE_PAYLOAD, the second diff --git a/src/charon/threads/stroke_interface.c b/src/charon/threads/stroke_interface.c index f4d7accfb..2242ea24a 100755 --- a/src/charon/threads/stroke_interface.c +++ b/src/charon/threads/stroke_interface.c @@ -260,12 +260,12 @@ static void stroke_add_conn(private_stroke_t *this, stroke_msg_t *msg) } my_ts = traffic_selector_create_from_subnet(my_subnet, - msg->add_conn.me.subnet ? msg->add_conn.me.subnet_mask : 32, + msg->add_conn.me.subnet ? msg->add_conn.me.subnet_mask : 0, msg->add_conn.me.protocol, msg->add_conn.me.port); my_subnet->destroy(my_subnet); other_ts = traffic_selector_create_from_subnet(other_subnet, - msg->add_conn.other.subnet ? msg->add_conn.other.subnet_mask : 32, + msg->add_conn.other.subnet ? msg->add_conn.other.subnet_mask : 0, msg->add_conn.other.protocol, msg->add_conn.other.port); other_subnet->destroy(other_subnet); @@ -383,11 +383,11 @@ static void stroke_add_conn(private_stroke_t *this, stroke_msg_t *msg) policy = policy_create(msg->add_conn.name, my_id, other_id, msg->add_conn.rekey.ipsec_lifetime, msg->add_conn.rekey.ipsec_lifetime - msg->add_conn.rekey.margin, - msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100); + msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100, + msg->add_conn.me.updown); policy->add_my_traffic_selector(policy, my_ts); policy->add_other_traffic_selector(policy, other_ts); policy->add_authorities(policy, my_ca, other_ca); - policy->add_updown(policy, msg->add_conn.me.updown); if (msg->add_conn.algorithms.esp) { @@ -479,40 +479,65 @@ static void stroke_initiate(private_stroke_t *this, stroke_msg_t *msg) { initiate_ike_sa_job_t *job; connection_t *connection; + policy_t *policy; linked_list_t *ike_sas; ike_sa_id_t *ike_sa_id; pop_string(msg, &(msg->initiate.name)); - this->logger->log(this->logger, CONTROL, "received stroke: initiate \"%s\"", msg->initiate.name); - connection = charon->connections->get_connection_by_name(charon->connections, msg->initiate.name); + this->logger->log(this->logger, CONTROL, + "received stroke: initiate \"%s\"", + msg->initiate.name); + + connection = charon->connections->get_connection_by_name(charon->connections, + msg->initiate.name); if (connection == NULL) { - this->stroke_logger->log(this->stroke_logger, ERROR, "no connection named \"%s\"", msg->initiate.name); + this->stroke_logger->log(this->stroke_logger, ERROR, + "no connection named \"%s\"", + msg->initiate.name); } /* only initiate if it is an IKEv2 connection, ignore IKEv1 */ else if (connection->is_ikev2(connection)) { - /* check for already set up IKE_SAs befor initiating */ - ike_sas = charon->ike_sa_manager->get_ike_sa_list_by_name(charon->ike_sa_manager, msg->initiate.name); - if (ike_sas->get_count(ike_sas) == 0) + + policy = charon->policies->get_policy_by_name(charon->policies, + msg->initiate.name); + if (policy == NULL) { - this->stroke_logger->log(this->stroke_logger, CONTROL, - "initiating connection \"%s\" (see log)...", msg->initiate.name); - job = initiate_ike_sa_job_create(connection); - charon->job_queue->add(charon->job_queue, (job_t*)job); + this->stroke_logger->log(this->stroke_logger, ERROR, + "no policy named \"%s\"", + msg->initiate.name); + connection->destroy(connection); + return; } - else + /* check for already set up IKE_SAs befor initiating */ + ike_sas = charon->ike_sa_manager->get_ike_sa_list_by_name(charon->ike_sa_manager, + msg->initiate.name); + if (ike_sas->get_count(ike_sas) > 0) { this->stroke_logger->log(this->stroke_logger, CONTROL, - "connection \"%s\" already up", msg->initiate.name); + "connection \"%s\" already up", + msg->initiate.name); + /* TODO: setup CHILD_SA with policy */ connection->destroy(connection); + ike_sas->destroy(ike_sas); + return; } + this->stroke_logger->log(this->stroke_logger, CONTROL, + "initiating connection \"%s\" (see log)...", + msg->initiate.name); + job = initiate_ike_sa_job_create(connection, policy); + charon->job_queue->add(charon->job_queue, (job_t*)job); while (ike_sas->remove_last(ike_sas, (void**)&ike_sa_id) == SUCCESS) { ike_sa_id->destroy(ike_sa_id); } ike_sas->destroy(ike_sas); } + else + { + connection->destroy(connection); + } } /** diff --git a/src/libstrongswan/definitions.h b/src/libstrongswan/definitions.h index c8839ef70..db920e3e6 100644 --- a/src/libstrongswan/definitions.h +++ b/src/libstrongswan/definitions.h @@ -90,6 +90,11 @@ #define min(x,y) ((x) < (y) ? (x):(y)) /** + * Call destructor of a object if object != NULL + */ +#define DESTROY_IF(obj) if (obj) obj->destroy(obj) + +/** * Debug macro to follow control flow */ #define POS printf("%s, line %d\n", __FILE__, __LINE__) |