diff options
author | Martin Willi <martin@strongswan.org> | 2006-07-20 10:09:32 +0000 |
---|---|---|
committer | Martin Willi <martin@strongswan.org> | 2006-07-20 10:09:32 +0000 |
commit | 8dfbe71b34badd4a277b46e4bfd9a70cfa9db06b (patch) | |
tree | c85c7059d723cb76a0db9dd51f9cb984c3ad7f8f | |
parent | 92ee45a0eedfa4b58d5814d7ffad0671165f3f06 (diff) | |
download | strongswan-8dfbe71b34badd4a277b46e4bfd9a70cfa9db06b.tar.bz2 strongswan-8dfbe71b34badd4a277b46e4bfd9a70cfa9db06b.tar.xz |
introduced refcounting on policy and connections
aren't stored in the IKE_SA anymore, they are queried on the fly
are immutable now, allows it to share them
policy selection based on traffic selectors, leads to valid lookup results
rekeying queries the policy based on its traffic selectors
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__) |