summaryrefslogtreecommitdiff
path: root/src/charon/config/connections
diff options
context:
space:
mode:
Diffstat (limited to 'src/charon/config/connections')
-rw-r--r--src/charon/config/connections/connection.c404
-rw-r--r--src/charon/config/connections/connection.h292
-rwxr-xr-xsrc/charon/config/connections/connection_store.h118
-rw-r--r--src/charon/config/connections/local_connection_store.c237
-rw-r--r--src/charon/config/connections/local_connection_store.h62
5 files changed, 1113 insertions, 0 deletions
diff --git a/src/charon/config/connections/connection.c b/src/charon/config/connections/connection.c
new file mode 100644
index 000000000..ffe508992
--- /dev/null
+++ b/src/charon/config/connections/connection.c
@@ -0,0 +1,404 @@
+/**
+ * @file connection.c
+ *
+ * @brief Implementation of connection_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <string.h>
+
+#include <config/connections/connection.h>
+#include <utils/linked_list.h>
+
+ENUM(cert_policy_names, CERT_ALWAYS_SEND, CERT_NEVER_SEND,
+ "CERT_ALWAYS_SEND",
+ "CERT_SEND_IF_ASKED",
+ "CERT_NEVER_SEND"
+);
+
+typedef struct private_connection_t private_connection_t;
+
+/**
+ * Private data of an connection_t object
+ */
+struct private_connection_t {
+
+ /**
+ * Public part
+ */
+ connection_t public;
+
+ /**
+ * Number of references hold by others to this connection
+ */
+ refcount_t refcount;
+
+ /**
+ * Name of the connection
+ */
+ char *name;
+
+ /**
+ * Does charon handle this connection? Or can he ignore it?
+ */
+ bool ikev2;
+
+ /**
+ * should we send a certificate request?
+ */
+ cert_policy_t certreq_policy;
+
+ /**
+ * should we send a certificates?
+ */
+ cert_policy_t cert_policy;
+
+ /**
+ * ID of us
+ */
+ identification_t *my_id;
+
+ /**
+ * Host information of my host.
+ */
+ host_t *my_host;
+
+ /**
+ * Host information of other host.
+ */
+ host_t *other_host;
+
+ /**
+ * Interval to send DPD liveness checks on inactivity
+ */
+ u_int32_t dpd_delay;
+
+ /**
+ * Number of retransmission sequences to send bevore giving up
+ */
+ u_int32_t keyingtries;
+
+ /**
+ * Supported proposals
+ */
+ linked_list_t *proposals;
+
+ /**
+ * Time before an SA gets invalid
+ */
+ u_int32_t soft_lifetime;
+
+ /**
+ * Time before an SA gets rekeyed
+ */
+ u_int32_t hard_lifetime;
+
+ /**
+ * Use full reauthentication instead of rekeying
+ */
+ bool reauth;
+
+ /**
+ * Time, which specifies the range of a random value
+ * substracted from soft_lifetime.
+ */
+ u_int32_t jitter;
+};
+
+/**
+ * Implementation of connection_t.get_name.
+ */
+static char *get_name (private_connection_t *this)
+{
+ return this->name;
+}
+
+/**
+ * Implementation of connection_t.is_ikev2.
+ */
+static bool is_ikev2 (private_connection_t *this)
+{
+ return this->ikev2;
+}
+
+/**
+ * Implementation of connection_t.get_certreq_policy.
+ */
+static cert_policy_t get_certreq_policy (private_connection_t *this)
+{
+ return this->certreq_policy;
+}
+
+/**
+ * Implementation of connection_t.get_cert_policy.
+ */
+static cert_policy_t get_cert_policy (private_connection_t *this)
+{
+ return this->cert_policy;
+}
+
+/**
+ * Implementation of connection_t.get_my_host.
+ */
+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.get_proposals.
+ */
+static linked_list_t* get_proposals(private_connection_t *this)
+{
+ iterator_t *iterator;
+ proposal_t *current;
+ linked_list_t *proposals = linked_list_create();
+
+ iterator = this->proposals->create_iterator(this->proposals, TRUE);
+ while (iterator->iterate(iterator, (void**)&current))
+ {
+ current = current->clone(current);
+ proposals->insert_last(proposals, (void*)current);
+ }
+ iterator->destroy(iterator);
+
+ return proposals;
+}
+
+/**
+ * Implementation of connection_t.select_proposal.
+ */
+static proposal_t *select_proposal(private_connection_t *this, linked_list_t *proposals)
+{
+ iterator_t *stored_iter, *supplied_iter;
+ proposal_t *stored, *supplied, *selected;
+
+ stored_iter = this->proposals->create_iterator(this->proposals, TRUE);
+ supplied_iter = proposals->create_iterator(proposals, TRUE);
+
+ /* compare all stored proposals with all supplied. Stored ones are preferred. */
+ while (stored_iter->iterate(stored_iter, (void**)&stored))
+ {
+ supplied_iter->reset(supplied_iter);
+
+ while (supplied_iter->iterate(supplied_iter, (void**)&supplied))
+ {
+ selected = stored->select(stored, supplied);
+ if (selected)
+ {
+ /* they match, return */
+ stored_iter->destroy(stored_iter);
+ supplied_iter->destroy(supplied_iter);
+ return selected;
+ }
+ }
+ }
+ /* no proposal match :-(, will result in a NO_PROPOSAL_CHOSEN... */
+ stored_iter->destroy(stored_iter);
+ supplied_iter->destroy(supplied_iter);
+
+ return NULL;
+}
+
+/**
+ * Implementation of connection_t.add_proposal.
+ */
+static void add_proposal(private_connection_t *this, proposal_t *proposal)
+{
+ this->proposals->insert_last(this->proposals, proposal);
+}
+
+/**
+ * Implementation of connection_t.get_dpd_delay.
+ */
+static u_int32_t get_dpd_delay(private_connection_t *this)
+{
+ return this->dpd_delay;
+}
+
+/**
+ * Implementation of connection_t.get_keyingtries.
+ */
+static u_int32_t get_keyingtries(private_connection_t *this)
+{
+ return this->keyingtries;
+}
+
+/**
+ * Implementation of connection_t.get_dh_group.
+ */
+static diffie_hellman_group_t get_dh_group(private_connection_t *this)
+{
+ iterator_t *iterator;
+ proposal_t *proposal;
+ algorithm_t *algo;
+ diffie_hellman_group_t dh_group = MODP_NONE;
+
+ iterator = this->proposals->create_iterator(this->proposals, TRUE);
+ while (iterator->iterate(iterator, (void**)&proposal))
+ {
+ if (proposal->get_algorithm(proposal, DIFFIE_HELLMAN_GROUP, &algo))
+ {
+ dh_group = algo->algorithm;
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+ return dh_group;
+}
+
+/**
+ * Implementation of connection_t.check_dh_group.
+ */
+static bool check_dh_group(private_connection_t *this, diffie_hellman_group_t dh_group)
+{
+ iterator_t *prop_iter, *alg_iter;
+ proposal_t *proposal;
+ algorithm_t *algo;
+
+ prop_iter = this->proposals->create_iterator(this->proposals, TRUE);
+ while (prop_iter->iterate(prop_iter, (void**)&proposal))
+ {
+ alg_iter = proposal->create_algorithm_iterator(proposal, DIFFIE_HELLMAN_GROUP);
+ while (alg_iter->iterate(alg_iter, (void**)&algo))
+ {
+ if (algo->algorithm == dh_group)
+ {
+ prop_iter->destroy(prop_iter);
+ alg_iter->destroy(alg_iter);
+ return TRUE;
+ }
+ }
+ alg_iter->destroy(alg_iter);
+ }
+ prop_iter->destroy(prop_iter);
+ return FALSE;
+}
+/**
+ * Implementation of connection_t.get_soft_lifetime
+ */
+static u_int32_t get_soft_lifetime(private_connection_t *this)
+{
+ if (this->jitter == 0)
+ {
+ return this->soft_lifetime ;
+ }
+ return this->soft_lifetime - (random() % this->jitter);
+}
+
+/**
+ * Implementation of connection_t.get_hard_lifetime.
+ */
+static u_int32_t get_hard_lifetime(private_connection_t *this)
+{
+ return this->hard_lifetime;
+}
+
+/**
+ * Implementation of connection_t.get_reauth.
+ */
+static bool get_reauth(private_connection_t *this)
+{
+ return this->reauth;
+}
+
+/**
+ * Implementation of connection_t.get_ref.
+ */
+static void get_ref(private_connection_t *this)
+{
+ ref_get(&this->refcount);
+}
+
+/**
+ * Implementation of connection_t.destroy.
+ */
+static void destroy(private_connection_t *this)
+{
+ if (ref_put(&this->refcount))
+ {
+ this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
+ this->my_host->destroy(this->my_host);
+ this->other_host->destroy(this->other_host);
+ free(this->name);
+ free(this);
+ }
+}
+
+/**
+ * Described in header.
+ */
+connection_t * connection_create(char *name, bool ikev2,
+ cert_policy_t cert_policy,
+ cert_policy_t certreq_policy,
+ host_t *my_host, host_t *other_host,
+ u_int32_t dpd_delay, bool reauth,
+ u_int32_t keyingtries,
+ u_int32_t hard_lifetime,
+ u_int32_t soft_lifetime, u_int32_t jitter)
+{
+ 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.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;
+ this->public.add_proposal = (void(*)(connection_t*, proposal_t*)) add_proposal;
+ this->public.get_dpd_delay = (u_int32_t(*)(connection_t*)) get_dpd_delay;
+ this->public.get_reauth = (bool(*)(connection_t*)) get_reauth;
+ this->public.get_keyingtries = (u_int32_t(*)(connection_t*)) get_keyingtries;
+ 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.get_soft_lifetime = (u_int32_t (*) (connection_t *))get_soft_lifetime;
+ this->public.get_hard_lifetime = (u_int32_t (*) (connection_t *))get_hard_lifetime;
+ 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;
+ this->certreq_policy = certreq_policy;
+ this->my_host = my_host;
+ this->other_host = other_host;
+ this->dpd_delay = dpd_delay;
+ this->reauth = reauth;
+ this->keyingtries = keyingtries;
+ this->hard_lifetime = hard_lifetime;
+ this->soft_lifetime = soft_lifetime;
+ this->jitter = jitter;
+
+ this->proposals = linked_list_create();
+
+ return &this->public;
+}
diff --git a/src/charon/config/connections/connection.h b/src/charon/config/connections/connection.h
new file mode 100644
index 000000000..d0788876f
--- /dev/null
+++ b/src/charon/config/connections/connection.h
@@ -0,0 +1,292 @@
+/**
+ * @file connection.h
+ *
+ * @brief Interface of connection_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef CONNECTION_H_
+#define CONNECTION_H_
+
+typedef enum cert_policy_t cert_policy_t;
+typedef struct connection_t connection_t;
+
+#include <library.h>
+#include <utils/host.h>
+#include <utils/linked_list.h>
+#include <utils/identification.h>
+#include <config/proposal.h>
+#include <crypto/diffie_hellman.h>
+
+
+/**
+ * Certificate sending policy. This is also used for certificate
+ * requests when using this definition for the other peer. If
+ * it is CERT_NEVER_SEND, a certreq is omitted, otherwise its
+ * included.
+ *
+ * @ingroup config
+ *
+ * @warning These definitions must be the same as in pluto/starter,
+ * as they are sent over the stroke socket.
+ */
+enum cert_policy_t {
+ /** always send certificates, even when not requested */
+ CERT_ALWAYS_SEND = 0,
+ /** send certificate upon cert request */
+ CERT_SEND_IF_ASKED = 1,
+ /** never send a certificate, even when requested */
+ CERT_NEVER_SEND = 2,
+};
+
+/**
+ * enum strings for cert_policy_t
+ *
+ * @ingroup config
+ */
+extern enum_name_t *cert_policy_names;
+
+/**
+ * @brief A connection_t defines the rules to set up an IKE_SA.
+ *
+ * @b Constructors:
+ * - connection_create()
+ *
+ * @ingroup config
+ */
+struct connection_t {
+
+ /**
+ * @brief Get my address as host_t object.
+ *
+ * Object is NOT getting cloned.
+ *
+ * @param this calling object
+ * @return host information as host_t object
+ */
+ host_t *(*get_my_host) (connection_t *this);
+
+ /**
+ * @brief Get others address as host_t object.
+ *
+ * Object is NOT getting cloned.
+ *
+ * @param this calling object
+ * @return host information as host_t object
+ */
+ host_t *(*get_other_host) (connection_t *this);
+
+ /**
+ * @brief Returns a list of all supported proposals.
+ *
+ * Returned list and its proposals must be destroyed after usage.
+ *
+ * @param this calling object
+ * @return list containing all the proposals
+ */
+ linked_list_t *(*get_proposals) (connection_t *this);
+
+ /**
+ * @brief Adds a proposal to the list.
+ *
+ * The first added proposal has the highest priority, the last
+ * added the lowest.
+ *
+ * @param this calling object
+ * @param proposal proposal to add
+ */
+ void (*add_proposal) (connection_t *this, proposal_t *proposal);
+
+ /**
+ * @brief Select a proposed from suggested proposals.
+ *
+ * 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.
+ */
+ proposal_t *(*select_proposal) (connection_t *this, linked_list_t *proposals);
+
+ /**
+ * @brief Get the DPD check interval.
+ *
+ * @param this calling object
+ * @return dpd_delay in seconds
+ */
+ u_int32_t (*get_dpd_delay) (connection_t *this);
+
+ /**
+ * @brief Should a full reauthentication be done instead of rekeying?
+ *
+ * @param this calling object
+ * @return TRUE to use full reauthentication
+ */
+ bool (*get_reauth) (connection_t *this);
+
+ /**
+ * @brief Get the max number of retransmission sequences.
+ *
+ * @param this calling object
+ * @return max number of retransmission sequences
+ */
+ u_int32_t (*get_keyingtries) (connection_t *this);
+
+ /**
+ * @brief Get the connection name.
+ *
+ * Name must not be freed, since it points to
+ * internal data.
+ *
+ * @param this calling object
+ * @return name of the connection
+ */
+ char* (*get_name) (connection_t *this);
+
+ /**
+ * @brief Check if the connection is marked as an IKEv2 connection.
+ *
+ * Since all connections (IKEv1+2) are loaded, but charon handles
+ * 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
+ */
+ bool (*is_ikev2) (connection_t *this);
+
+ /**
+ * @brief Should be sent a certificate request for this connection?
+ *
+ * A certificate request contains serials of our trusted CA certificates.
+ * This flag says if such a request is sent on connection setup to
+ * the peer. It should be omitted when CERT_SEND_NEVER, sended otherwise.
+ *
+ * @param this calling object
+ * @return certificate request sending policy
+ */
+ cert_policy_t (*get_certreq_policy) (connection_t *this);
+
+ /**
+ * @brief Should be sent a certificate for this connection?
+ *
+ * Return the policy used to send the certificate.
+ *
+ * @param this calling object
+ * @return certificate sending policy
+ */
+ cert_policy_t (*get_cert_policy) (connection_t *this);
+
+ /**
+ * @brief Get the DH group to use for connection initialization.
+ *
+ * @param this calling object
+ * @return dh group to use for initialization
+ */
+ diffie_hellman_group_t (*get_dh_group) (connection_t *this);
+
+ /**
+ * @brief Check if a suggested dh group is acceptable.
+ *
+ * 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
+ */
+ bool (*check_dh_group) (connection_t *this, diffie_hellman_group_t dh_group);
+
+ /**
+ * @brief Get the lifetime of a connection, before IKE_SA rekeying starts.
+ *
+ * A call to this function automatically adds a jitter to
+ * avoid simultanous rekeying.
+ *
+ * @param this calling object
+ * @return lifetime in seconds
+ */
+ u_int32_t (*get_soft_lifetime) (connection_t *this);
+
+ /**
+ * @brief Get the lifetime of a connection, before IKE_SA gets deleted.
+ *
+ * @param this calling object
+ * @return lifetime in seconds
+ */
+ u_int32_t (*get_hard_lifetime) (connection_t *this);
+
+ /**
+ * @brief Get a new reference to this connection.
+ *
+ * Get a new reference to this connection by increasing
+ * it's internal reference counter.
+ * Do not call get_ref or any other function until you
+ * already have a reference. Otherwise the object may get
+ * destroyed while calling get_ref(),
+ *
+ * @param this calling object
+ */
+ 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);
+};
+
+/**
+ * @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.
+ * The retrasmit sequence number says how fast we give up when the peer
+ * does not respond. A high value may bridge-over temporary connection
+ * problems, a small value can detect dead peers faster.
+ *
+ * @param name connection identifier
+ * @param ikev2 TRUE if this is an IKEv2 connection
+ * @param cert_policy certificate send policy
+ * @param cert_req_policy certificate request send policy
+ * @param my_host host_t representing local address
+ * @param other_host host_t representing remote address
+ * @param dpd_delay interval of DPD liveness checks
+ * @param reauth use full reauthentication instead of rekeying
+ * @param keyingtries number of retransmit sequences to use
+ * @param hard_lifetime lifetime before deleting an IKE_SA
+ * @param soft_lifetime lifetime before rekeying an IKE_SA
+ * @param jitter range of randomization time
+ * @return connection_t object.
+ *
+ * @ingroup config
+ */
+connection_t * connection_create(char *name, bool ikev2,
+ cert_policy_t cert_pol, cert_policy_t req_pol,
+ host_t *my_host, host_t *other_host,
+ u_int32_t dpd_delay, bool reauth,
+ u_int32_t keyingtries,
+ u_int32_t hard_lifetime, u_int32_t soft_lifetime,
+ u_int32_t jitter);
+
+#endif /* CONNECTION_H_ */
diff --git a/src/charon/config/connections/connection_store.h b/src/charon/config/connections/connection_store.h
new file mode 100755
index 000000000..70f209d3b
--- /dev/null
+++ b/src/charon/config/connections/connection_store.h
@@ -0,0 +1,118 @@
+/**
+ * @file connection_store.h
+ *
+ * @brief Interface connection_store_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef CONNECTION_STORE_H_
+#define CONNECTION_STORE_H_
+
+typedef struct connection_store_t connection_store_t;
+
+#include <library.h>
+#include <config/connections/connection.h>
+#include <utils/iterator.h>
+
+/**
+ * @brief The interface for a store of connection_t's.
+ *
+ * @b Constructors:
+ * - stroke_create()
+ *
+ * @ingroup config
+ */
+struct connection_store_t {
+
+ /**
+ * @brief Returns a connection definition identified by two hosts.
+ *
+ * This call is usefull to get a connection identified by addresses.
+ * It may be used after kernel request for traffic protection.
+ * The returned connection gets created/cloned and therefore must
+ * be destroyed after usage.
+ *
+ * @param this calling object
+ * @param my_id own address of connection
+ * @param other_id others address of connection
+ * @return
+ * - connection_t, if found
+ * - NULL otherwise
+ */
+ connection_t *(*get_connection_by_hosts)(connection_store_t *this,
+ host_t *my_host, host_t *other_host);
+
+ /**
+ * @brief Returns a connection identified by its name.
+ *
+ * This call is usefull to get a connection identified its
+ * name, as on an connection setup.
+ *
+ * @param this calling object
+ * @param name name of the connection to get
+ * @return
+ * - connection_t, if found
+ * - NULL otherwise
+ */
+ connection_t *(*get_connection_by_name) (connection_store_t *this, char *name);
+
+ /**
+ * @brief Add a connection to the store.
+ *
+ * After a successful call, the connection is owned by the store and may
+ * not be manipulated nor destroyed.
+ *
+ * @param this calling object
+ * @param connection connection to add
+ * @return
+ * - SUCCESS, or
+ * - FAILED
+ */
+ 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 Get an iterator for the stored connections.
+ *
+ * @param this calling object
+ * @return iterator over all stored connections
+ */
+ iterator_t* (*create_iterator) (connection_store_t *this);
+
+ /**
+ * @brief Destroys a connection_store_t object.
+ *
+ * @param this calling object
+ */
+ void (*destroy) (connection_store_t *this);
+};
+
+#endif /* CONNECTION_STORE_H_ */
diff --git a/src/charon/config/connections/local_connection_store.c b/src/charon/config/connections/local_connection_store.c
new file mode 100644
index 000000000..df4ec230a
--- /dev/null
+++ b/src/charon/config/connections/local_connection_store.c
@@ -0,0 +1,237 @@
+/**
+ * @file local_connection_store.c
+ *
+ * @brief Implementation of local_connection_store_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <string.h>
+
+#include "local_connection_store.h"
+
+#include <daemon.h>
+#include <utils/linked_list.h>
+
+
+typedef struct private_local_connection_store_t private_local_connection_store_t;
+
+/**
+ * Private data of an local_connection_store_t object
+ */
+struct private_local_connection_store_t {
+
+ /**
+ * Public part
+ */
+ local_connection_store_t public;
+
+ /**
+ * stored connection
+ */
+ linked_list_t *connections;
+
+ /**
+ * Mutex to exclusivly access connection list
+ */
+ pthread_mutex_t mutex;
+};
+
+
+/**
+ * Implementation of connection_store_t.get_connection_by_hosts.
+ */
+static connection_t *get_connection_by_hosts(private_local_connection_store_t *this, host_t *my_host, host_t *other_host)
+{
+ typedef enum {
+ PRIO_UNDEFINED= 0x00,
+ PRIO_ADDR_ANY= 0x01,
+ PRIO_ADDR_MATCH= 0x02
+ } prio_t;
+
+ prio_t best_prio = PRIO_UNDEFINED;
+
+ iterator_t *iterator;
+ connection_t *candidate;
+ connection_t *found = NULL;
+
+ DBG2(DBG_CFG, "looking for connection for host pair %H...%H",
+ my_host, other_host);
+
+ pthread_mutex_lock(&(this->mutex));
+ iterator = this->connections->create_iterator(this->connections, TRUE);
+ /* determine closest matching connection */
+ while (iterator->iterate(iterator, (void**)&candidate))
+ {
+ host_t *candidate_my_host;
+ host_t *candidate_other_host;
+
+ candidate_my_host = candidate->get_my_host(candidate);
+ candidate_other_host = candidate->get_other_host(candidate);
+
+ /* my_host addresses must match*/
+ if (my_host->ip_equals(my_host, candidate_my_host))
+ {
+ prio_t prio = PRIO_UNDEFINED;
+
+ /* exact match of peer host address or wildcard address? */
+ if (other_host->ip_equals(other_host, candidate_other_host))
+ {
+ prio |= PRIO_ADDR_MATCH;
+ }
+ else if (candidate_other_host->is_anyaddr(candidate_other_host))
+ {
+ prio |= PRIO_ADDR_ANY;
+ }
+
+ DBG2(DBG_CFG, "candidate connection \"%s\": %H...%H (prio=%d)",
+ candidate->get_name(candidate),
+ candidate_my_host, candidate_other_host, prio);
+
+ if (prio > best_prio)
+ {
+ found = candidate;
+ best_prio = prio;
+ }
+ }
+ }
+ iterator->destroy(iterator);
+
+ if (found)
+ {
+ DBG2(DBG_CFG, "found matching connection \"%s\": %H...%H (prio=%d)",
+ found->get_name(found), found->get_my_host(found),
+ found->get_other_host(found), best_prio);
+
+ /* give out a new reference to it */
+ found->get_ref(found);
+ }
+ pthread_mutex_unlock(&(this->mutex));
+ return found;
+}
+
+/**
+ * Implementation of connection_store_t.get_connection_by_name.
+ */
+static connection_t *get_connection_by_name(private_local_connection_store_t *this, char *name)
+{
+ iterator_t *iterator;
+ connection_t *current, *found = NULL;
+
+ pthread_mutex_lock(&(this->mutex));
+ iterator = this->connections->create_iterator(this->connections, TRUE);
+ while (iterator->iterate(iterator, (void**)&current))
+ {
+ if (strcmp(name, current->get_name(current)) == 0)
+ {
+ found = current;
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+ pthread_mutex_unlock(&(this->mutex));
+
+ if (found)
+ {
+ /* get a new reference for it */
+ found->get_ref(found);
+ }
+ 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->iterate(iterator, (void **)&current))
+ {
+ 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;
+}
+
+/**
+ * Implementation of connection_store_t.create_iterator.
+ */
+static iterator_t* create_iterator(private_local_connection_store_t *this)
+{
+ return this->connections->create_iterator_locked(this->connections,
+ &this->mutex);
+}
+
+/**
+ * Implementation of connection_store_t.destroy.
+ */
+static void destroy (private_local_connection_store_t *this)
+{
+ pthread_mutex_lock(&(this->mutex));
+ this->connections->destroy_offset(this->connections, offsetof(connection_t, destroy));
+ pthread_mutex_unlock(&(this->mutex));
+ free(this);
+}
+
+/**
+ * Described in header.
+ */
+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_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.create_iterator = (iterator_t*(*)(connection_store_t*))create_iterator;
+ this->public.connection_store.destroy = (void(*)(connection_store_t*))destroy;
+
+ /* private variables */
+ this->connections = linked_list_create();
+ pthread_mutex_init(&(this->mutex), NULL);
+
+ return (&this->public);
+}
diff --git a/src/charon/config/connections/local_connection_store.h b/src/charon/config/connections/local_connection_store.h
new file mode 100644
index 000000000..e78ed809a
--- /dev/null
+++ b/src/charon/config/connections/local_connection_store.h
@@ -0,0 +1,62 @@
+/**
+ * @file local_connection_store.h
+ *
+ * @brief Interface of local_connection_store_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef LOCAL_CONNECTION_H_
+#define LOCAL_CONNECTION_H_
+
+typedef struct local_connection_store_t local_connection_store_t;
+
+#include <library.h>
+#include <config/connections/connection_store.h>
+
+/**
+ * @brief A connection_store_t implementation using a simple connection list.
+ *
+ * The local_connection_store_t class implements the connection_store_t interface
+ * as simple as possible. connection_t's are stored in an in-memory list.
+ *
+ * @b Constructors:
+ * - local_connection_store_create()
+ *
+ * @todo Make thread-save first
+ * @todo Add remove_connection method
+ *
+ * @ingroup config
+ */
+struct local_connection_store_t {
+
+ /**
+ * Implements connection_store_t interface
+ */
+ connection_store_t connection_store;
+};
+
+/**
+ * @brief Creates a local_connection_store_t instance.
+ *
+ * @return connection store instance.
+ *
+ * @ingroup config
+ */
+local_connection_store_t * local_connection_store_create(void);
+
+#endif /* LOCAL_CONNECTION_H_ */