From 9fe14f4b8a3ae487134854eb8ebdfcb49cea4027 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 29 May 2006 11:09:45 +0000 Subject: [PATCH] - policies contain a connections name now - used for initiate and delete - connections won't get initiated twice anymore - deleting of connections is now possible, which allows us to use ipsec update and ipsec reload --- src/charon/config/connections/connection.c | 78 ++------ src/charon/config/connections/connection.h | 92 +++------- .../config/connections/connection_store.h | 31 ++-- .../connections/local_connection_store.c | 98 +++++----- .../config/policies/local_policy_store.c | 170 +++++++++++++++--- src/charon/config/policies/policy.c | 98 +++++----- src/charon/config/policies/policy.h | 15 +- src/charon/config/policies/policy_store.h | 45 ++++- src/charon/sa/ike_sa.c | 36 ++-- src/charon/sa/states/ike_auth_requested.c | 9 +- src/charon/sa/states/ike_sa_init_responded.c | 19 +- src/charon/sa/states/initiator_init.c | 34 ++-- src/charon/threads/stroke_interface.c | 50 +++++- src/starter/starter.c | 2 +- src/starter/starterstroke.c | 7 +- src/stroke/stroke.c | 21 +++ src/stroke/stroke.h | 4 +- 17 files changed, 483 insertions(+), 326 deletions(-) diff --git a/src/charon/config/connections/connection.c b/src/charon/config/connections/connection.c index a33026acd..16dc75baf 100644 --- a/src/charon/config/connections/connection.c +++ b/src/charon/config/connections/connection.c @@ -59,16 +59,6 @@ struct private_connection_t { * Does charon handle this connection? Or can he ignore it? */ bool ikev2; - - /** - * ID of us - */ - identification_t *my_id; - - /** - * ID of remote peer - */ - identification_t *other_id; /** * Host information of my host. @@ -107,48 +97,22 @@ static bool is_ikev2 (private_connection_t *this) return this->ikev2; } -/** - * Implementation of connection_t.get_my_id. - */ -static identification_t *get_my_id (private_connection_t *this) -{ - return this->my_id; -} - -/** - * Implementation of connection_t.get_other_id. - */ -static identification_t *get_other_id(private_connection_t *this) -{ - return this->other_id; -} - -/** - * Implementation of connection_t.update_my_id - */ -static void update_my_id(private_connection_t *this, identification_t *my_id) -{ - this->my_id->destroy(this->my_id); - this->my_id = my_id; -} - -/** - * Implementation of connection_t.update_other_id - */ -static void update_other_id(private_connection_t *this, identification_t *other_id) -{ - this->other_id->destroy(this->other_id); - this->other_id = other_id; -} - /** * Implementation of connection_t.get_my_host. */ -static host_t * get_my_host (private_connection_t *this) +static host_t *get_my_host (private_connection_t *this) { return this->my_host; } +/** + * Implementation of connection_t.get_other_host. + */ +static host_t *get_other_host (private_connection_t *this) +{ + return this->other_host; +} + /** * Implementation of connection_t.update_my_host. */ @@ -167,18 +131,10 @@ static void update_other_host(private_connection_t *this, host_t *other_host) this->other_host = other_host; } -/** - * Implementation of connection_t.get_other_host. - */ -static host_t * get_other_host (private_connection_t *this) -{ - return this->other_host; -} - /** * Implementation of connection_t.get_proposals. */ -static linked_list_t* get_proposals (private_connection_t *this) +static linked_list_t* get_proposals(private_connection_t *this) { return this->proposals; } @@ -224,7 +180,7 @@ static proposal_t *select_proposal(private_connection_t *this, linked_list_t *pr /** * Implementation of connection_t.add_proposal. */ -static void add_proposal (private_connection_t *this, proposal_t *proposal) +static void add_proposal(private_connection_t *this, proposal_t *proposal) { this->proposals->insert_last(this->proposals, proposal); } @@ -303,8 +259,6 @@ static connection_t *clone(private_connection_t *this) this->ikev2, this->my_host->clone(this->my_host), this->other_host->clone(this->other_host), - this->my_id->clone(this->my_id), - this->other_id->clone(this->other_id), this->auth_method); /* clone all proposals */ @@ -335,8 +289,6 @@ static void destroy(private_connection_t *this) this->my_host->destroy(this->my_host); this->other_host->destroy(this->other_host); - this->my_id->destroy(this->my_id); - this->other_id->destroy(this->other_id); free(this->name); free(this); } @@ -344,20 +296,16 @@ static void destroy(private_connection_t *this) /** * Described in header. */ -connection_t * connection_create(char *name, bool ikev2, host_t *my_host, host_t *other_host, identification_t *my_id, identification_t *other_id, auth_method_t auth_method) +connection_t * connection_create(char *name, bool ikev2, host_t *my_host, host_t *other_host, 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_my_id = (identification_t*(*)(connection_t*))get_my_id; - this->public.get_other_id = (identification_t*(*)(connection_t*))get_other_id; 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.update_my_id = (void(*)(connection_t*,identification_t*))update_my_id; - this->public.update_other_id = (void(*)(connection_t*,identification_t*))update_other_id; 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; @@ -373,8 +321,6 @@ connection_t * connection_create(char *name, bool ikev2, host_t *my_host, host_t this->ikev2 = ikev2; this->my_host = my_host; this->other_host = other_host; - this->my_id = my_id; - this->other_id = other_id; this->auth_method = auth_method; this->proposals = linked_list_create(); diff --git a/src/charon/config/connections/connection.h b/src/charon/config/connections/connection.h index 2b21227ce..523574632 100644 --- a/src/charon/config/connections/connection.h +++ b/src/charon/config/connections/connection.h @@ -80,26 +80,6 @@ typedef struct connection_t connection_t; */ struct connection_t { - /** - * @brief Get my ID for this connection. - * - * Object is NOT getting cloned. - * - * @param this calling object - * @return host information as identification_t object - */ - identification_t *(*get_my_id) (connection_t *this); - - /** - * @brief Get others ID for this connection. - * - * Object is NOT getting cloned. - * - * @param this calling object - * @return host information as identification_t object - */ - identification_t *(*get_other_id) (connection_t *this); - /** * @brief Get my address as host_t object. * @@ -143,32 +123,6 @@ struct connection_t { * @param my_host new host to set as other_host */ void (*update_other_host) (connection_t *this, host_t *other_host); - - /** - * @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) (connection_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) (connection_t *this, identification_t *other_id); /** * @brief Returns a list of all supported proposals. @@ -176,8 +130,8 @@ struct connection_t { * Returned list is still owned by connection and MUST NOT * modified or destroyed. * - * @param this calling object - * @return list containing all the proposals + * @param this calling object + * @return list containing all the proposals */ linked_list_t *(*get_proposals) (connection_t *this); @@ -187,8 +141,8 @@ struct connection_t { * The first added proposal has the highest priority, the last * added the lowest. * - * @param this calling object - * @param proposal proposal to add + * @param this calling object + * @param proposal proposal to add */ void (*add_proposal) (connection_t *this, proposal_t *proposal); @@ -197,17 +151,17 @@ struct connection_t { * * Returned proposal must be destroyed after usage. * - * @param this calling object - * @param proposals list of proposals to select from - * @return selected proposal, or NULL if none matches. + * @param this calling object + * @param proposals list of proposals to select from + * @return selected proposal, or NULL if none matches. */ proposal_t *(*select_proposal) (connection_t *this, linked_list_t *proposals); /** * @brief Get the authentication method to use * - * @param this calling object - * @return authentication method + * @param this calling object + * @return authentication method */ auth_method_t (*get_auth_method) (connection_t *this); @@ -217,8 +171,8 @@ struct connection_t { * Name must not be freed, since it points to * internal data. * - * @param this calling object - * @return name of the connection + * @param this calling object + * @return name of the connection */ char* (*get_name) (connection_t *this); @@ -229,16 +183,16 @@ struct connection_t { * only those marked with IKEv2, this flag can tell us if we must * ignore a connection on initiaton. Then pluto will do it for us. * - * @param this calling object - * @return - TRUE, if this is an IKEv2 connection + * @param this calling object + * @return - TRUE, if this is an IKEv2 connection */ bool (*is_ikev2) (connection_t *this); /** * @brief Get the DH group to use for connection initialization. * - * @param this calling object - * @return dh group to use for initialization + * @param this calling object + * @return dh group to use for initialization */ diffie_hellman_group_t (*get_dh_group) (connection_t *this); @@ -248,23 +202,23 @@ struct connection_t { * If we guess a wrong DH group for IKE_SA_INIT, the other * peer will send us a offer. But is this acceptable for us? * - * @param this calling object - * @return TRUE if group acceptable + * @param this calling object + * @return TRUE if group acceptable */ 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 + * @param this connection to clone + * @return clone of it */ connection_t *(*clone) (connection_t *this); /** * @brief Destroys a connection_t object. * - * @param this calling object + * @param this calling object */ void (*destroy) (connection_t *this); }; @@ -272,7 +226,7 @@ struct connection_t { /** * @brief Creates a connection_t object. * - * Supplied hosts/IDs become owned by connection, so + * Supplied hosts become owned by connection, so * do not modify or destroy them after a call to * connection_create(). Name gets cloned internally. * @@ -280,8 +234,6 @@ struct connection_t { * @param ikev2 TRUE if this is an IKEv2 connection * @param my_host host_t representing local address * @param other_host host_t representing remote address - * @param my_id identification_t for me - * @param other_id identification_t for other * @param auth_method Authentication method to use for our(!) auth data * @return connection_t object. * @@ -290,8 +242,6 @@ struct connection_t { connection_t * connection_create(char *name, bool ikev2, host_t *my_host, host_t *other_host, - identification_t *my_id, - identification_t *other_id, auth_method_t auth_method); #endif /* CONNECTION_H_ */ diff --git a/src/charon/config/connections/connection_store.h b/src/charon/config/connections/connection_store.h index acdfa5430..7d42dd26f 100755 --- a/src/charon/config/connections/connection_store.h +++ b/src/charon/config/connections/connection_store.h @@ -40,23 +40,6 @@ typedef struct connection_store_t connection_store_t; */ struct connection_store_t { - /** - * @brief Returns a connection definition identified by two IDs. - * - * This call is useful to get a connection which is identified by IDs - * rather than addresses, e.g. for connection setup on user request. - * The returned connection gets created/cloned and therefore must - * be destroyed after usage. - * - * @param this calling object - * @param my_id own ID of connection - * @param other_id others ID of connection - * @return - * - connection_t, if found - * - NULL otherwise - */ - connection_t *(*get_connection_by_ids) (connection_store_t *this, identification_t *my_id, identification_t *other_id); - /** * @brief Returns a connection definition identified by two hosts. * @@ -102,6 +85,20 @@ struct connection_store_t { */ status_t (*add_connection) (connection_store_t *this, connection_t *connection); + /** + * @brief Delete a connection from the store. + * + * Remove a connection from the connection store, identified + * by the connections name. + * + * @param this calling object + * @param name name of the connection to delete + * @return + * - SUCCESS, or + * - NOT_FOUND + */ + status_t (*delete_connection) (connection_store_t *this, char *name); + /** * @brief Log the connections stored in the store. * diff --git a/src/charon/config/connections/local_connection_store.c b/src/charon/config/connections/local_connection_store.c index e7a93414c..180205a9d 100644 --- a/src/charon/config/connections/local_connection_store.c +++ b/src/charon/config/connections/local_connection_store.c @@ -45,6 +45,11 @@ struct private_local_connection_store_t { */ linked_list_t *connections; + /** + * Mutex to exclusivly access connection list + */ + pthread_mutex_t mutex; + /** * Assigned logger */ @@ -71,9 +76,9 @@ static connection_t *get_connection_by_hosts(private_local_connection_store_t *t this->logger->log(this->logger, CONTROL|LEVEL1, "searching connection for host pair %s...%s", my_host->get_address(my_host), other_host->get_address(other_host)); - + + pthread_mutex_lock(&(this->mutex)); iterator = this->connections->create_iterator(this->connections, TRUE); - /* determine closest matching connection */ while (iterator->has_next(iterator)) { @@ -135,43 +140,7 @@ static connection_t *get_connection_by_hosts(private_local_connection_store_t *t found->update_other_host(found, other_host->clone(other_host)); } } - return found; -} - -/** - * Implementation of connection_store_t.get_connection_by_ids. - */ -static connection_t *get_connection_by_ids(private_local_connection_store_t *this, identification_t *my_id, identification_t *other_id) -{ - iterator_t *iterator; - connection_t *current, *found = NULL; - - this->logger->log(this->logger, CONTROL|LEVEL1, "getting config for ids %s - %s", - my_id->get_string(my_id), other_id->get_string(other_id)); - - iterator = this->connections->create_iterator(this->connections, TRUE); - while (iterator->has_next(iterator)) - { - identification_t *config_my_id, *config_other_id; - - iterator->current(iterator, (void**)¤t); - - config_my_id = current->get_my_id(current); - config_other_id = current->get_other_id(current); - - /* first check if ids are equal - * TODO: Add wildcard checks */ - if (config_other_id->equals(config_other_id, other_id) && - config_my_id->equals(config_my_id, my_id)) - { - this->logger->log(this->logger, CONTROL|LEVEL2, "config entry with remote id %s", - config_other_id->get_string(config_other_id)); - found = current->clone(current); - break; - } - } - iterator->destroy(iterator); - + pthread_mutex_unlock(&(this->mutex)); return found; } @@ -183,6 +152,7 @@ static connection_t *get_connection_by_name(private_local_connection_store_t *th iterator_t *iterator; connection_t *current, *found = NULL; + pthread_mutex_lock(&(this->mutex)); iterator = this->connections->create_iterator(this->connections, TRUE); while (iterator->has_next(iterator)) { @@ -194,16 +164,51 @@ static connection_t *get_connection_by_name(private_local_connection_store_t *th } } iterator->destroy(iterator); + pthread_mutex_unlock(&(this->mutex)); return found; } +/** + * Implementation of connection_store_t.delete_connection. + */ +static status_t delete_connection(private_local_connection_store_t *this, char *name) +{ + iterator_t *iterator; + connection_t *current; + bool found = FALSE; + + pthread_mutex_lock(&(this->mutex)); + iterator = this->connections->create_iterator(this->connections, TRUE); + while (iterator->has_next(iterator)) + { + iterator->current(iterator, (void **)¤t); + if (strcmp(current->get_name(current), name) == 0) + { + /* remove connection from list, and destroy it */ + iterator->remove(iterator); + current->destroy(current); + found = TRUE; + break; + } + } + iterator->destroy(iterator); + pthread_mutex_unlock(&(this->mutex)); + if (found) + { + return SUCCESS; + } + return NOT_FOUND; +} + /** * Implementation of connection_store_t.add_connection. */ static status_t add_connection(private_local_connection_store_t *this, connection_t *connection) { + pthread_mutex_lock(&(this->mutex)); this->connections->insert_last(this->connections, connection); + pthread_mutex_unlock(&(this->mutex)); return SUCCESS; } @@ -222,25 +227,23 @@ void log_connections(private_local_connection_store_t *this, logger_t *logger, c logger->log(logger, CONTROL, "templates:"); + pthread_mutex_lock(&(this->mutex)); iterator = this->connections->create_iterator(this->connections, TRUE); while (iterator->has_next(iterator)) { iterator->current(iterator, (void**)¤t); if (!name || strcmp(name, current->get_name(current)) == 0) { - identification_t *my_id, *other_id; host_t *my_host, *other_host; - my_id = current->get_my_id(current); - other_id = current->get_other_id(current); my_host = current->get_my_host(current); other_host = current->get_other_host(current); - logger->log(logger, CONTROL, " \"%s\": %s[%s]...%s[%s]", + logger->log(logger, CONTROL, " \"%s\": %s...%s", current->get_name(current), - my_host->get_address(my_host), my_id->get_string(my_id), - other_host->get_address(other_host), other_id->get_string(other_id)); + my_host->get_address(my_host), other_host->get_address(other_host)); } } iterator->destroy(iterator); + pthread_mutex_unlock(&(this->mutex)); } /** @@ -250,11 +253,13 @@ static void destroy (private_local_connection_store_t *this) { connection_t *connection; + pthread_mutex_lock(&(this->mutex)); while (this->connections->remove_last(this->connections, (void**)&connection) == SUCCESS) { connection->destroy(connection); } this->connections->destroy(this->connections); + pthread_mutex_unlock(&(this->mutex)); free(this); } @@ -266,8 +271,8 @@ local_connection_store_t * local_connection_store_create(void) private_local_connection_store_t *this = malloc_thing(private_local_connection_store_t); this->public.connection_store.get_connection_by_hosts = (connection_t*(*)(connection_store_t*,host_t*,host_t*))get_connection_by_hosts; - this->public.connection_store.get_connection_by_ids = (connection_t*(*)(connection_store_t*,identification_t*,identification_t*))get_connection_by_ids; this->public.connection_store.get_connection_by_name = (connection_t*(*)(connection_store_t*,char*))get_connection_by_name; + this->public.connection_store.delete_connection = (status_t(*)(connection_store_t*,char*))delete_connection; this->public.connection_store.add_connection = (status_t(*)(connection_store_t*,connection_t*))add_connection; this->public.connection_store.log_connections = (void(*)(connection_store_t*,logger_t*,char*))log_connections; this->public.connection_store.destroy = (void(*)(connection_store_t*))destroy; @@ -275,6 +280,7 @@ local_connection_store_t * local_connection_store_create(void) /* private variables */ this->connections = linked_list_create(); this->logger = logger_manager->get_logger(logger_manager, CONFIG); + pthread_mutex_init(&(this->mutex), NULL); return (&this->public); } diff --git a/src/charon/config/policies/local_policy_store.c b/src/charon/config/policies/local_policy_store.c index 24d22f485..764843526 100644 --- a/src/charon/config/policies/local_policy_store.c +++ b/src/charon/config/policies/local_policy_store.c @@ -43,6 +43,11 @@ struct private_local_policy_store_t { */ linked_list_t *policies; + /** + * Mutex to exclusivly access list + */ + pthread_mutex_t mutex; + /** * Assigned logger */ @@ -54,54 +59,168 @@ struct private_local_policy_store_t { */ static void add_policy(private_local_policy_store_t *this, policy_t *policy) { + pthread_mutex_lock(&(this->mutex)); this->policies->insert_last(this->policies, (void*)policy); + pthread_mutex_unlock(&(this->mutex)); } - /** - * Implementation of policy_store_t.get_policy. + * Implementation of policy_store_t.get_policy_by_ids. */ -static policy_t *get_policy(private_local_policy_store_t *this, identification_t *my_id, identification_t *other_id) +static policy_t *get_policy_by_ids(private_local_policy_store_t *this, identification_t *my_id, identification_t *other_id) { + typedef enum { + PRIO_UNDEFINED = 0x00, + PRIO_ID_ANY = 0x01, + PRIO_ID_WILDCARD = 0x02, + PRIO_ID_MATCH = 0x04, + } prio_t; + + prio_t best_prio = PRIO_UNDEFINED; + iterator_t *iterator; - policy_t *current, *found = NULL; + policy_t *candidate; + policy_t *found = NULL; - this->logger->log(this->logger, CONTROL|LEVEL1, "Looking for policy for IDs %s - %s", - my_id ? my_id->get_string(my_id) : "%any", - other_id->get_string(other_id)); + this->logger->log(this->logger, CONTROL|LEVEL1, "searching policy for ID pair %s...%s", + my_id->get_string(my_id), other_id->get_string(other_id)); + + pthread_mutex_lock(&(this->mutex)); iterator = this->policies->create_iterator(this->policies, TRUE); + /* determine closest matching policy */ while (iterator->has_next(iterator)) { - iterator->current(iterator, (void **)¤t); - identification_t *config_my_id = current->get_my_id(current); - identification_t *config_other_id = current->get_other_id(current); + identification_t *candidate_my_id; + identification_t *candidate_other_id; - this->logger->log(this->logger, CONTROL|LEVEL2, "Found one for %s - %s", - config_my_id->get_string(config_my_id), - config_other_id->get_string(config_other_id)); - - /* check other host first */ - if (other_id->belongs_to(other_id, config_other_id)) + iterator->current(iterator, (void**)&candidate); + + candidate_my_id = candidate->get_my_id(candidate); + candidate_other_id = candidate->get_other_id(candidate); + + /* my_id must match, or may be %any */ + if (candidate_my_id->belongs_to(candidate_my_id, my_id)) { - /* get it if my_id not specified */ - if (my_id->belongs_to(my_id, config_my_id)) + prio_t prio = PRIO_UNDEFINED; + + /* exact match of id? */ + if (other_id->equals(other_id, candidate_other_id)) { - found = current->clone(current); + prio = PRIO_ID_MATCH; + } + /* match against any? */ + else if (candidate_other_id->get_type(candidate_other_id) == ID_ANY) + { + prio = PRIO_ID_ANY; + } + /* wildcard match? */ + else if (other_id->belongs_to(other_id, candidate_other_id)) + { + prio = PRIO_ID_WILDCARD; + } + + this->logger->log(this->logger, CONTROL|LEVEL2, + "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), + prio); + + if (prio > best_prio) + { + found = candidate; + best_prio = prio; + } + if (prio == PRIO_ID_MATCH) + { + /* won't get better, stop searching */ break; } } } iterator->destroy(iterator); - /* apply IDs as they are requsted, since they may be configured as %any or such */ if (found) { - found->update_my_id(found, my_id->clone(my_id)); - found->update_other_id(found, other_id->clone(other_id)); + identification_t *found_my_id = found->get_my_id(found); + 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->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)); + } } + pthread_mutex_unlock(&(this->mutex)); return found; } +/** + * Implementation of policy_store_t.get_policy_by_name. + */ +static policy_t *get_policy_by_name(private_local_policy_store_t *this, char *name) +{ + iterator_t *iterator; + policy_t *current, *found = NULL; + + this->logger->log(this->logger, CONTROL|LEVEL1, "Looking for policy \"%s\"", name); + + pthread_mutex_lock(&(this->mutex)); + iterator = this->policies->create_iterator(this->policies, TRUE); + while (iterator->has_next(iterator)) + { + iterator->current(iterator, (void **)¤t); + if (strcmp(current->get_name(current), name) == 0) + { + found = current->clone(current); + } + } + iterator->destroy(iterator); + pthread_mutex_unlock(&(this->mutex)); + + return found; +} + +/** + * Implementation of policy_store_t.delete_policy. + */ +static status_t delete_policy(private_local_policy_store_t *this, char *name) +{ + iterator_t *iterator; + policy_t *current; + bool found = FALSE; + + pthread_mutex_lock(&(this->mutex)); + iterator = this->policies->create_iterator(this->policies, TRUE); + while (iterator->has_next(iterator)) + { + iterator->current(iterator, (void **)¤t); + if (strcmp(current->get_name(current), name) == 0) + { + /* remove policy from list, and destroy it */ + iterator->remove(iterator); + current->destroy(current); + found = TRUE; + /* we do not break here, as there may be multipe policies */ + } + } + iterator->destroy(iterator); + pthread_mutex_unlock(&(this->mutex)); + if (found) + { + return SUCCESS; + } + return NOT_FOUND; +} + /** * Implementation of policy_store_t.destroy. */ @@ -109,11 +228,13 @@ static void destroy(private_local_policy_store_t *this) { policy_t *policy; + pthread_mutex_lock(&(this->mutex)); while (this->policies->remove_last(this->policies, (void**)&policy) == SUCCESS) { policy->destroy(policy); } this->policies->destroy(this->policies); + pthread_mutex_unlock(&(this->mutex)); free(this); } @@ -125,12 +246,15 @@ 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 = (policy_t*(*)(policy_store_t*,identification_t*,identification_t*))get_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_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; /* private variables */ this->policies = linked_list_create(); this->logger = logger_manager->get_logger(logger_manager, CONFIG); + pthread_mutex_init(&(this->mutex), NULL); return (&this->public); } diff --git a/src/charon/config/policies/policy.c b/src/charon/config/policies/policy.c index cff87fc6b..14ca50365 100644 --- a/src/charon/config/policies/policy.c +++ b/src/charon/config/policies/policy.c @@ -38,6 +38,11 @@ struct private_policy_t { */ policy_t public; + /** + * Name of the policy, used to query it + */ + char *name; + /** * id to use to identify us */ @@ -69,6 +74,14 @@ struct private_policy_t { linked_list_t *(*select_traffic_selectors) (private_policy_t *,linked_list_t*,linked_list_t*); }; +/** + * Implementation of policy_t.get_name + */ +static char *get_name(private_policy_t *this) +{ + return this->name; +} + /** * Implementation of policy_t.get_my_id */ @@ -275,50 +288,13 @@ static void add_proposal(private_policy_t *this, proposal_t *proposal) this->proposals->insert_last(this->proposals, (void*)proposal); } -/** - * 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 ids */ - this->my_id->destroy(this->my_id); - this->other_id->destroy(this->other_id); - - free(this); - return SUCCESS; -} - /** * Implements policy_t.clone. */ static policy_t *clone(private_policy_t *this) { - private_policy_t *clone = (private_policy_t*)policy_create(this->my_id->clone(this->my_id), + 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)); iterator_t *iterator; proposal_t *proposal; @@ -354,17 +330,58 @@ static policy_t *clone(private_policy_t *this) } iterator->destroy(iterator); + clone->name = strdup(this->name); return &clone->public; } +/** + * 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 ids */ + this->my_id->destroy(this->my_id); + this->other_id->destroy(this->other_id); + + free(this->name); + free(this); + return SUCCESS; +} + /* * Described in header-file */ -policy_t *policy_create(identification_t *my_id, identification_t *other_id) +policy_t *policy_create(char *name, identification_t *my_id, identification_t *other_id) { private_policy_t *this = malloc_thing(private_policy_t); /* public functions */ + 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; @@ -386,6 +403,7 @@ policy_t *policy_create(identification_t *my_id, identification_t *other_id) /* apply init values */ this->my_id = my_id; this->other_id = other_id; + this->name = strdup(name); /* init private members*/ this->select_traffic_selectors = select_traffic_selectors; diff --git a/src/charon/config/policies/policy.h b/src/charon/config/policies/policy.h index 78cda1e8b..5956d9864 100644 --- a/src/charon/config/policies/policy.h +++ b/src/charon/config/policies/policy.h @@ -45,6 +45,16 @@ typedef struct policy_t policy_t; */ struct policy_t { + /** + * @brief Get the name of the policy. + * + * Returned object is not getting cloned. + * + * @param this calling object + * @return policy's name + */ + char *(*get_name) (policy_t *this); + /** * @brief Get own id to use for identification. * @@ -238,12 +248,15 @@ struct policy_t { /** * @brief Create a configuration object for IKE_AUTH and later. * + * name-string gets cloned, ID's not. + * + * @param name name of the policy * @param my_id identification_t for ourselves * @param other_id identification_t for the remote guy * @return policy_t object * * @ingroup config */ -policy_t *policy_create(identification_t *my_id, identification_t *other_id); +policy_t *policy_create(char *name, identification_t *my_id, identification_t *other_id); #endif /* POLICY_H_ */ diff --git a/src/charon/config/policies/policy_store.h b/src/charon/config/policies/policy_store.h index 651dea634..40cc87e2f 100755 --- a/src/charon/config/policies/policy_store.h +++ b/src/charon/config/policies/policy_store.h @@ -37,37 +37,66 @@ typedef struct policy_store_t policy_store_t; * * @ingroup config */ -struct policy_store_t { +struct policy_store_t { /** * @brief Returns a policy identified by two IDs. - * + * * 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 * @return * - matching policy_t, if found - * - NULL otherwise + * - NULL otherwise */ - policy_t *(*get_policy) (policy_store_t *this, identification_t *my_id, identification_t *other_id); + policy_t *(*get_policy_by_ids) (policy_store_t *this, identification_t *my_id, identification_t *other_id); + + /** + * @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 + * - matching policy_t, if found + * - NULL otherwise + */ + policy_t *(*get_policy_by_name) (policy_store_t *this, char *name); /** * @brief Add a policy to the list. - * + * * The policy is owned by the store after the call. Do * not modify nor free. - * + * * @param this calling object * @param policy policy to add */ void (*add_policy) (policy_store_t *this, policy_t *policy); + + /** + * @brief Delete a policy from the store. + * + * Remove a policy from the store identified by its name. + * + * @param this calling object + * @param policy policy to add + * @return + * - SUCCESS, or + * - NOT_FOUND + */ + status_t (*delete_policy) (policy_store_t *this, char *name); /** * @brief Destroys a policy_store_t object. - * + * * @param this calling object */ void (*destroy) (policy_store_t *this); diff --git a/src/charon/sa/ike_sa.c b/src/charon/sa/ike_sa.c index 91f839a5b..1dbcac429 100644 --- a/src/charon/sa/ike_sa.c +++ b/src/charon/sa/ike_sa.c @@ -332,7 +332,7 @@ static host_t* get_other_host(private_ike_sa_t *this) */ static identification_t* get_my_id(private_ike_sa_t *this) { - return this->connection->get_my_id(this->connection);; + return this->policy->get_my_id(this->policy);; } /** @@ -340,7 +340,7 @@ static identification_t* get_my_id(private_ike_sa_t *this) */ static identification_t* get_other_id(private_ike_sa_t *this) { - return this->connection->get_other_id(this->connection);; + return this->policy->get_other_id(this->policy);; } /** @@ -919,7 +919,7 @@ static void log_status(private_ike_sa_t *this, logger_t *logger, char *name) iterator_t *iterator; child_sa_t *child_sa; host_t *my_host, *other_host; - identification_t *my_id, *other_id; + identification_t *my_id = NULL, *other_id = NULL; /* only log if name == NULL or name == connection_name */ if (name) @@ -937,8 +937,11 @@ static void log_status(private_ike_sa_t *this, logger_t *logger, char *name) my_host = this->connection->get_my_host(this->connection); other_host = this->connection->get_other_host(this->connection); - my_id = this->connection->get_my_id(this->connection); - other_id = this->connection->get_other_id(this->connection); + if (this->policy) + { + my_id = this->policy->get_my_id(this->policy); + other_id = this->policy->get_other_id(this->policy); + } if (logger == NULL) { @@ -952,9 +955,9 @@ static void log_status(private_ike_sa_t *this, logger_t *logger, char *name) logger->log(logger, CONTROL, " \"%s\": %s[%s]...%s[%s]", name, my_host->get_address(my_host), - my_id->get_string(my_id), + my_id ? my_id->get_string(my_id) : "(unknown)", other_host->get_address(other_host), - other_id->get_string(other_id)); + other_id ? other_id->get_string(other_id) : "(unknown)"); iterator = this->child_sas->create_iterator(this->child_sas, TRUE); while (iterator->has_next(iterator)) @@ -1067,12 +1070,21 @@ static void destroy(private_ike_sa_t *this) } if (this->connection) { - host_t *me, *other; - me = this->connection->get_my_host(this->connection); - other = this->connection->get_other_host(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", - me->get_address(me), other->get_address(other)); + this->logger->log(this->logger, AUDIT, "IKE_SA deleted between %s[%s]...%s[%s]", + my_host->get_address(my_host), + my_id ? my_id->get_string(my_id) : "(unknown)", + other_host->get_address(other_host), + other_id ? other_id->get_string(other_id) : "(unknown)"); this->connection->destroy(this->connection); } if (this->policy) diff --git a/src/charon/sa/states/ike_auth_requested.c b/src/charon/sa/states/ike_auth_requested.c index 47cc16f81..0ceecf14a 100644 --- a/src/charon/sa/states/ike_auth_requested.c +++ b/src/charon/sa/states/ike_auth_requested.c @@ -188,6 +188,7 @@ static status_t process_message(private_ike_auth_requested_t *this, message_t *i chunk_t seed; prf_plus_t *prf_plus; connection_t *connection; + policy_t *policy; if (ike_auth_reply->get_exchange_type(ike_auth_reply) != IKE_AUTH) { @@ -362,8 +363,9 @@ static status_t process_message(private_ike_auth_requested_t *this, message_t *i connection = this->ike_sa->get_connection(this->ike_sa); my_host = connection->get_my_host(connection); other_host = connection->get_other_host(connection); - my_id = connection->get_my_id(connection); - other_id = connection->get_other_id(connection); + policy = this->ike_sa->get_policy(this->ike_sa); + my_id = policy->get_my_id(policy); + other_id = policy->get_other_id(policy); this->logger->log(this->logger, AUDIT, "IKE_SA established %s[%s]...%s[%s]", my_host->get_address(my_host), my_id->get_string(my_id), other_host->get_address(other_host), other_id->get_string(other_id)); @@ -393,9 +395,6 @@ static status_t process_idr_payload(private_ike_auth_requested_t *this, id_paylo return DESTROY_ME; } - connection = this->ike_sa->get_connection(this->ike_sa); - connection->update_other_id(connection, other_id->clone(other_id)); - this->policy->update_other_id(this->policy, other_id); return SUCCESS; } diff --git a/src/charon/sa/states/ike_sa_init_responded.c b/src/charon/sa/states/ike_sa_init_responded.c index 17d9e9db0..ab63a86d0 100644 --- a/src/charon/sa/states/ike_sa_init_responded.c +++ b/src/charon/sa/states/ike_sa_init_responded.c @@ -185,6 +185,7 @@ static status_t process_message(private_ike_sa_init_responded_t *this, message_t host_t *my_host, *other_host; identification_t *my_id, *other_id; connection_t *connection; + policy_t *policy; if (request->get_exchange_type(request) != IKE_AUTH) { @@ -368,8 +369,9 @@ static status_t process_message(private_ike_sa_init_responded_t *this, message_t connection = this->ike_sa->get_connection(this->ike_sa); my_host = connection->get_my_host(connection); other_host = connection->get_other_host(connection); - my_id = connection->get_my_id(connection); - other_id = connection->get_other_id(connection); + policy = this->ike_sa->get_policy(this->ike_sa); + my_id = policy->get_my_id(policy); + other_id = policy->get_other_id(policy); this->logger->log(this->logger, AUDIT, "IKE_SA established %s[%s]...%s[%s]", my_host->get_address(my_host), my_id->get_string(my_id), other_host->get_address(other_host), other_id->get_string(other_id)); @@ -382,27 +384,22 @@ static status_t process_message(private_ike_sa_init_responded_t *this, message_t */ static status_t build_idr_payload(private_ike_sa_init_responded_t *this, id_payload_t *request_idi, id_payload_t *request_idr, message_t *response,id_payload_t **response_idr) { - identification_t *other_id, *my_id = NULL; - connection_t *connection; + identification_t *other_id, *my_id; id_payload_t *idr_response; - connection = this->ike_sa->get_connection(this->ike_sa); - - /* update adresses, as connection may contain wildcards, or wrong IDs */ + /* use others ID, an ours if peer requested one */ other_id = request_idi->get_identification(request_idi); if (request_idr) { my_id = request_idr->get_identification(request_idr); - connection->update_my_id(connection, my_id); } else { - my_id = connection->get_my_id(connection); + my_id = identification_create_from_encoding(ID_ANY, CHUNK_INITIALIZER);; } - connection->update_other_id(connection, other_id); /* build new sa config */ - this->policy = charon->policies->get_policy(charon->policies, my_id, other_id); + this->policy = charon->policies->get_policy_by_ids(charon->policies, my_id, other_id); if (this->policy == NULL) { this->logger->log(this->logger, AUDIT, "We don't have a policy for IDs %s - %s. Deleting IKE_SA", diff --git a/src/charon/sa/states/initiator_init.c b/src/charon/sa/states/initiator_init.c index 4837ad1a1..8aa5bad98 100644 --- a/src/charon/sa/states/initiator_init.c +++ b/src/charon/sa/states/initiator_init.c @@ -113,30 +113,32 @@ static status_t initiate_connection (private_initiator_init_t *this, connection_ diffie_hellman_group_t dh_group; host_t *my_host, *other_host; identification_t *my_id, *other_id; + char *name; - my_host = connection->get_my_host(connection); - other_host = connection->get_other_host(connection); - my_id = connection->get_my_id(connection); - other_id = connection->get_other_id(connection); - - this->logger->log(this->logger, CONTROL, "initiating connection \"%s\": %s[%s]...%s[%s]", - connection->get_name(connection), - my_host->get_address(my_host), - my_id->get_string(my_id), - other_host->get_address(other_host), - other_id->get_string(other_id)); - + name = connection->get_name(connection); this->ike_sa->set_connection(this->ike_sa, connection); /* get policy */ - policy = charon->policies->get_policy(charon->policies, my_id, other_id); + policy = charon->policies->get_policy_by_name(charon->policies, name); if (policy == NULL) { - this->logger->log(this->logger, ERROR | LEVEL1, "could not get a policy for '%s...%s', aborting", - my_id->get_string(my_id), other_id->get_string(other_id)); + this->logger->log(this->logger, ERROR | LEVEL1, + "could not get a policy named '%s', aborting", name); return DESTROY_ME; } - this->ike_sa->set_policy(this->ike_sa,policy); + this->ike_sa->set_policy(this->ike_sa, policy); + + my_host = connection->get_my_host(connection); + other_host = connection->get_other_host(connection); + my_id = policy->get_my_id(policy); + other_id = policy->get_other_id(policy); + + this->logger->log(this->logger, CONTROL, "initiating connection \"%s\": %s[%s]...%s[%s]", + name, + my_host->get_address(my_host), + my_id->get_string(my_id), + other_host->get_address(other_host), + other_id->get_string(other_id)); /* we must guess now a DH group. For that we choose our most preferred group */ dh_group = connection->get_dh_group(connection); diff --git a/src/charon/threads/stroke_interface.c b/src/charon/threads/stroke_interface.c index 9110f5c24..9c41701d7 100755 --- a/src/charon/threads/stroke_interface.c +++ b/src/charon/threads/stroke_interface.c @@ -293,7 +293,6 @@ static void stroke_add_conn(private_stroke_t *this, stroke_msg_t *msg) connection = connection_create(msg->add_conn.name, msg->add_conn.ikev2, my_host, other_host, - my_id->clone(my_id), other_id->clone(other_id), RSA_DIGITAL_SIGNATURE); proposal = proposal_create(1); proposal->add_algorithm(proposal, PROTO_IKE, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 16); @@ -317,7 +316,7 @@ static void stroke_add_conn(private_stroke_t *this, stroke_msg_t *msg) other_host->get_address(other_host), other_id->get_string(other_id)); - policy = policy_create(my_id, other_id); + policy = policy_create(msg->add_conn.name, my_id, other_id); proposal = proposal_create(1); proposal->add_algorithm(proposal, PROTO_ESP, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 16); proposal->add_algorithm(proposal, PROTO_ESP, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0); @@ -330,6 +329,31 @@ static void stroke_add_conn(private_stroke_t *this, stroke_msg_t *msg) charon->policies->add_policy(charon->policies, policy); } +/** + * Delete a connection from the list + */ +static void stroke_del_conn(private_stroke_t *this, stroke_msg_t *msg) +{ + status_t status; + + pop_string(msg, &(msg->del_conn.name)); + this->logger->log(this->logger, CONTROL, "received stroke: delete \"%s\"", msg->del_conn.name); + + status = charon->connections->delete_connection(charon->connections, + msg->del_conn.name); + charon->policies->delete_policy(charon->policies, msg->del_conn.name); + if (status == SUCCESS) + { + this->stroke_logger->log(this->stroke_logger, CONTROL, + "Deleted connection '%s'", msg->del_conn.name); + } + else + { + this->stroke_logger->log(this->stroke_logger, ERROR, + "No connection named '%s'", msg->del_conn.name); + } +} + /** * initiate a connection by name */ @@ -337,6 +361,7 @@ static void stroke_initiate(private_stroke_t *this, stroke_msg_t *msg) { initiate_ike_sa_job_t *job; connection_t *connection; + linked_list_t *ike_sas; pop_string(msg, &(msg->initiate.name)); this->logger->log(this->logger, CONTROL, "received stroke: initiate \"%s\"", msg->initiate.name); @@ -348,10 +373,20 @@ static void stroke_initiate(private_stroke_t *this, stroke_msg_t *msg) /* only initiate if it is an IKEv2 connection, ignore IKEv1 */ else if (connection->is_ikev2(connection)) { - 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); + /* 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, "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); + } + else + { + + this->stroke_logger->log(this->stroke_logger, CONTROL, "connection \"%s\" already up", msg->initiate.name); + } + ike_sas->destroy(ike_sas); } } @@ -621,6 +656,9 @@ static void stroke_receive(private_stroke_t *this) case STR_ADD_CONN: stroke_add_conn(this, msg); break; + case STR_DEL_CONN: + stroke_del_conn(this, msg); + break; case STR_LOGTYPE: stroke_logtype(this, msg); break; diff --git a/src/starter/starter.c b/src/starter/starter.c index c70fadc3d..4b49d15b9 100644 --- a/src/starter/starter.c +++ b/src/starter/starter.c @@ -338,8 +338,8 @@ int main (int argc, char **argv) if (starter_pluto_pid()) { starter_whack_del_conn(conn); - conn->state = STATE_TO_ADD; } + conn->state = STATE_TO_ADD; } } for (ca = cfg->ca_first; ca; ca = ca->next) diff --git a/src/starter/starterstroke.c b/src/starter/starterstroke.c index c20e7f6e3..d271d4018 100644 --- a/src/starter/starterstroke.c +++ b/src/starter/starterstroke.c @@ -132,7 +132,12 @@ int starter_stroke_add_conn(starter_conn_t *conn) int starter_stroke_del_conn(starter_conn_t *conn) { - return 0; + stroke_msg_t msg; + + msg.type = STR_DEL_CONN; + msg.length = offsetof(stroke_msg_t, buffer); + msg.install.name = push_string(&msg, connection_name(conn)); + return send_stroke_msg(&msg); } int starter_stroke_route_conn(starter_conn_t *conn) diff --git a/src/stroke/stroke.c b/src/stroke/stroke.c index d104f8dd6..9bcc39ad4 100644 --- a/src/stroke/stroke.c +++ b/src/stroke/stroke.c @@ -116,6 +116,16 @@ static int add_connection(char *name, return send_stroke_msg(&msg); } +static int del_connection(char *name) +{ + stroke_msg_t msg; + + msg.length = offsetof(stroke_msg_t, buffer); + msg.type = STR_DEL_CONN; + msg.initiate.name = push_string(&msg, name); + return send_stroke_msg(&msg); +} + static int initiate_connection(char *name) { stroke_msg_t msg; @@ -201,6 +211,9 @@ static void exit_usage(char *error) printf(" ADDR is a IPv4 address\n"); printf(" NET is a IPv4 address of the subnet to tunnel\n"); printf(" NETBITS is the size of the subnet, as the \"24\" in 192.168.0.0/24\n"); + printf(" Delete a connection:\n"); + printf(" stroke delete NAME\n"); + printf(" where: NAME is a connection name added with \"stroke add\"\n"); printf(" Initiate a connection:\n"); printf(" stroke up NAME\n"); printf(" where: NAME is a connection name added with \"stroke add\"\n"); @@ -273,6 +286,14 @@ int main(int argc, char *argv[]) argv[7], argv[8], atoi(argv[9]), atoi(argv[10])); } + else if (streq(op, "delete")) + { + if (argc < 3) + { + exit_usage("\"delete\" needs a connection name"); + } + res = del_connection(argv[2]); + } else if (streq(op, "logtype")) { if (argc < 5) diff --git a/src/stroke/stroke.h b/src/stroke/stroke.h index f860b3690..a5e26af4a 100644 --- a/src/stroke/stroke.h +++ b/src/stroke/stroke.h @@ -65,10 +65,10 @@ struct stroke_msg_t { } type; union { - /* data for STR_INITIATE, STR_INSTALL, STR_UP, STR_DOWN */ + /* data for STR_INITIATE, STR_INSTALL, STR_UP, STR_DOWN, ... */ struct { char *name; - } initiate, install, terminate, status; + } initiate, install, terminate, status, del_conn; /* data for STR_ADD_CONN */ struct {