#include <sa/tasks/child_create.h>
#include <sa/tasks/child_delete.h>
#include <sa/tasks/child_rekey.h>
-#include <queues/jobs/retransmit_job.h>
-#include <queues/jobs/delete_ike_sa_job.h>
-#include <queues/jobs/send_dpd_job.h>
-#include <queues/jobs/send_keepalive_job.h>
-#include <queues/jobs/rekey_ike_sa_job.h>
-#include <queues/jobs/route_job.h>
-#include <queues/jobs/initiate_job.h>
+#include <processing/jobs/retransmit_job.h>
+#include <processing/jobs/delete_ike_sa_job.h>
+#include <processing/jobs/send_dpd_job.h>
+#include <processing/jobs/send_keepalive_job.h>
+#include <processing/jobs/rekey_ike_sa_job.h>
+#include <processing/jobs/route_job.h>
+#include <processing/jobs/initiate_job.h>
#ifndef RESOLV_CONF
ike_sa_state_t state;
/**
- * connection used to establish this IKE_SA.
+ * IKE configuration used to set up this IKE_SA
*/
- connection_t *connection;
+ ike_cfg_t *ike_cfg;
/**
* Peer and authentication information to establish IKE_SA.
*/
- policy_t *policy;
+ peer_cfg_t *peer_cfg;
/**
* Juggles tasks to process messages
/** when IKE_SA gets deleted */
u_int32_t delete;
} time;
+
+ /**
+ * how many times we have retried so far (keyingtries)
+ */
+ u_int32_t keyingtry;
};
/**
*/
static char *get_name(private_ike_sa_t *this)
{
- if (this->connection)
+ if (this->peer_cfg)
{
- return this->connection->get_name(this->connection);
+ return this->peer_cfg->get_name(this->peer_cfg);
}
return "(unnamed)";
}
/**
- * Implementation of ike_sa_t.get_connection
+ * Implementation of ike_sa_t.get_my_host.
*/
-static connection_t* get_connection(private_ike_sa_t *this)
+static host_t *get_my_host(private_ike_sa_t *this)
{
- return this->connection;
+ return this->my_host;
}
/**
- * Implementation of ike_sa_t.set_connection
+ * Implementation of ike_sa_t.set_my_host.
*/
-static void set_connection(private_ike_sa_t *this, connection_t *connection)
+static void set_my_host(private_ike_sa_t *this, host_t *me)
{
- this->connection = connection;
- connection->get_ref(connection);
+ DESTROY_IF(this->my_host);
+ this->my_host = me;
}
/**
- * Implementation of ike_sa_t.get_policy
+ * Implementation of ike_sa_t.get_other_host.
*/
-static policy_t *get_policy(private_ike_sa_t *this)
+static host_t *get_other_host(private_ike_sa_t *this)
{
- return this->policy;
+ return this->other_host;
}
/**
- * Implementation of ike_sa_t.set_policy
+ * Implementation of ike_sa_t.set_other_host.
*/
-static void set_policy(private_ike_sa_t *this, policy_t *policy)
+static void set_other_host(private_ike_sa_t *this, host_t *other)
{
- policy->get_ref(policy);
- this->policy = policy;
+ DESTROY_IF(this->other_host);
+ this->other_host = other;
}
/**
- * Implementation of ike_sa_t.get_my_host.
+ * Implementation of ike_sa_t.get_peer_cfg
*/
-static host_t *get_my_host(private_ike_sa_t *this)
+static peer_cfg_t* get_peer_cfg(private_ike_sa_t *this)
{
- return this->my_host;
+ return this->peer_cfg;
}
/**
- * Implementation of ike_sa_t.set_my_host.
+ * Implementation of ike_sa_t.set_peer_cfg
*/
-static void set_my_host(private_ike_sa_t *this, host_t *me)
+static void set_peer_cfg(private_ike_sa_t *this, peer_cfg_t *peer_cfg)
{
- DESTROY_IF(this->my_host);
- this->my_host = me;
+ host_t *me, *other;
+ identification_t *my_id, *other_id;
+
+ peer_cfg->get_ref(peer_cfg);
+ this->peer_cfg = peer_cfg;
+ if (this->ike_cfg == NULL)
+ {
+ this->ike_cfg = peer_cfg->get_ike_cfg(peer_cfg);
+ this->ike_cfg->get_ref(this->ike_cfg);
+ }
+
+ /* apply values, so we are ready to initate/acquire */
+ if (this->my_host->is_anyaddr(this->my_host))
+ {
+ me = this->ike_cfg->get_my_host(this->ike_cfg);
+ set_my_host(this, me->clone(me));
+ }
+ if (this->other_host->is_anyaddr(this->other_host))
+ {
+ other = this->ike_cfg->get_other_host(this->ike_cfg);
+ set_other_host(this, other->clone(other));
+ }
+ my_id = this->peer_cfg->get_my_id(this->peer_cfg);
+ other_id = this->peer_cfg->get_other_id(this->peer_cfg);
+ DESTROY_IF(this->my_id);
+ DESTROY_IF(this->other_id);
+ this->my_id = my_id->clone(my_id);
+ this->other_id = other_id->clone(other_id);
}
/**
- * Implementation of ike_sa_t.get_other_host.
+ * Implementation of ike_sa_t.get_ike_cfg
*/
-static host_t *get_other_host(private_ike_sa_t *this)
+static ike_cfg_t *get_ike_cfg(private_ike_sa_t *this)
{
- return this->other_host;
+ return this->ike_cfg;
}
/**
- * Implementation of ike_sa_t.set_other_host.
+ * Implementation of ike_sa_t.set_ike_cfg
*/
-static void set_other_host(private_ike_sa_t *this, host_t *other)
+static void set_ike_cfg(private_ike_sa_t *this, ike_cfg_t *ike_cfg)
{
- DESTROY_IF(this->other_host);
- this->other_host = other;
+ ike_cfg->get_ref(ike_cfg);
+ this->ike_cfg = ike_cfg;
+}
+
+/**
+ * Implementation of ike_sa_t.send_dpd
+ */
+static status_t send_dpd(private_ike_sa_t *this)
+{
+ send_dpd_job_t *job;
+ time_t diff, delay;
+
+ delay = this->peer_cfg->get_dpd_delay(this->peer_cfg);
+
+ if (delay == 0)
+ {
+ /* DPD disabled */
+ return SUCCESS;
+ }
+
+ if (this->task_manager->busy(this->task_manager))
+ {
+ /* an exchange is in the air, no need to start a DPD check */
+ diff = 0;
+ }
+ else
+ {
+ /* check if there was any inbound traffic */
+ time_t last_in, now;
+ last_in = get_use_time(this, TRUE);
+ now = time(NULL);
+ diff = now - last_in;
+ if (diff >= delay)
+ {
+ /* to long ago, initiate dead peer detection */
+ task_t *task;
+
+ task = (task_t*)ike_dpd_create(TRUE);
+ diff = 0;
+ DBG1(DBG_IKE, "sending DPD request");
+
+ this->task_manager->queue_task(this->task_manager, task);
+ this->task_manager->initiate(this->task_manager);
+ }
+ }
+ /* recheck in "interval" seconds */
+ job = send_dpd_job_create(this->ike_sa_id);
+ charon->event_queue->add_relative(charon->event_queue, (job_t*)job,
+ (delay - diff) * 1000);
+ return SUCCESS;
+}
+
+/**
+ * Implementation of ike_sa_t.send_keepalive
+ */
+static void send_keepalive(private_ike_sa_t *this)
+{
+ send_keepalive_job_t *job;
+ time_t last_out, now, diff, interval;
+
+ last_out = get_use_time(this, FALSE);
+ now = time(NULL);
+
+ diff = now - last_out;
+ interval = charon->configuration->get_keepalive_interval(charon->configuration);
+
+ if (diff >= interval)
+ {
+ packet_t *packet;
+ chunk_t data;
+
+ packet = packet_create();
+ 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;
+ packet->set_data(packet, data);
+ charon->sender->send(charon->sender, packet);
+ DBG1(DBG_IKE, "sending keep alive");
+ diff = 0;
+ }
+ job = send_keepalive_job_create(this->ike_sa_id);
+ charon->event_queue->add_relative(charon->event_queue, (job_t*)job,
+ (interval - diff) * 1000);
+}
+
+/**
+ * Implementation of ike_sa_t.get_state.
+ */
+static ike_sa_state_t get_state(private_ike_sa_t *this)
+{
+ return this->state;
}
/**
- * Update connection host, as addresses may change (NAT)
+ * Implementation of ike_sa_t.set_state.
+ */
+static void set_state(private_ike_sa_t *this, ike_sa_state_t state)
+{
+ DBG1(DBG_IKE, "IKE_SA state change: %N => %N",
+ ike_sa_state_names, this->state,
+ ike_sa_state_names, state);
+
+ switch (state)
+ {
+ case IKE_ESTABLISHED:
+ {
+ if (this->state == IKE_CONNECTING)
+ {
+ job_t *job;
+ u_int32_t now = time(NULL);
+ u_int32_t soft, hard;
+ bool reauth;
+
+ this->time.established = now;
+ /* start DPD checks */
+ send_dpd(this);
+
+ /* schedule rekeying/reauthentication */
+ soft = this->peer_cfg->get_lifetime(this->peer_cfg, TRUE);
+ hard = this->peer_cfg->get_lifetime(this->peer_cfg, FALSE);
+ reauth = this->peer_cfg->use_reauth(this->peer_cfg);
+ DBG1(DBG_IKE, "scheduling %s in %ds, maximum lifetime %ds",
+ reauth ? "reauthentication": "rekeying", soft, hard);
+
+ if (soft)
+ {
+ this->time.rekey = now + soft;
+ job = (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, reauth);
+ charon->event_queue->add_relative(charon->event_queue, job,
+ soft * 1000);
+ }
+
+ if (hard)
+ {
+ this->time.delete = now + hard;
+ job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, TRUE);
+ charon->event_queue->add_relative(charon->event_queue, job,
+ hard * 1000);
+ }
+ }
+ break;
+ }
+ case IKE_DELETING:
+ {
+ /* delete may fail if a packet gets lost, so set a timeout */
+ job_t *job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, TRUE);
+ charon->event_queue->add_relative(charon->event_queue, job,
+ charon->configuration->get_half_open_ike_sa_timeout(
+ charon->configuration));
+ break;
+ }
+ default:
+ break;
+ }
+
+ this->state = state;
+}
+
+/**
+ * Implementation of ike_sa_t.reset
+ */
+static void reset(private_ike_sa_t *this)
+{
+ /* the responder ID is reset, as peer may choose another one */
+ if (this->ike_sa_id->is_initiator(this->ike_sa_id))
+ {
+ this->ike_sa_id->set_responder_spi(this->ike_sa_id, 0);
+ }
+
+ set_state(this, IKE_CREATED);
+
+ this->task_manager->reset(this->task_manager);
+}
+
+/**
+ * Update hosts, as addresses may change (NAT)
*/
static void update_hosts(private_ike_sa_t *this, host_t *me, host_t *other)
{
}
if (generate_message(this, response, &packet) == SUCCESS)
{
- charon->send_queue->add(charon->send_queue, packet);
+ charon->sender->send(charon->sender, packet);
}
response->destroy(response);
}
me = message->get_destination(message);
other = message->get_source(message);
- /* if this IKE_SA is virgin, we check for a connection */
- if (this->connection == NULL)
+ /* if this IKE_SA is virgin, we check for a config */
+ if (this->ike_cfg == NULL)
{
- this->connection = charon->connections->get_connection_by_hosts(
- charon->connections, me, other);
- if (this->connection == NULL)
+ job_t *job;
+ this->ike_cfg = charon->cfg_store->get_ike_cfg(charon->cfg_store,
+ me, other);
+ if (this->ike_cfg == NULL)
{
- /* no connection found for these hosts, destroy */
- DBG1(DBG_IKE, "no connection found for %H...%H, sending %N",
+ /* no config found for these hosts, destroy */
+ DBG1(DBG_IKE, "no IKE config found for %H...%H, sending %N",
me, other, notify_type_names, NO_PROPOSAL_CHOSEN);
send_notify_response(this, message, NO_PROPOSAL_CHOSEN);
return DESTROY_ME;
}
+ /* add a timeout if peer does not establish it completely */
+ job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, FALSE);
+ charon->event_queue->add_relative(charon->event_queue, job,
+ charon->configuration->get_half_open_ike_sa_timeout(
+ charon->configuration));
}
- /* check if message is trustworthy, and update connection information */
+ /* check if message is trustworthy, and update host information */
if (this->state == IKE_CREATED ||
message->get_exchange_type(message) != IKE_SA_INIT)
{
}
}
-/**
- * apply the connection/policy information to this IKE_SA
- */
-static void apply_config(private_ike_sa_t *this,
- connection_t *connection, policy_t *policy)
-{
- host_t *me, *other;
- identification_t *my_id, *other_id;
-
- if (this->connection == NULL && this->policy == NULL)
- {
- this->connection = connection;
- connection->get_ref(connection);
- this->policy = policy;
- policy->get_ref(policy);
-
- me = connection->get_my_host(connection);
- other = connection->get_other_host(connection);
- my_id = policy->get_my_id(policy);
- other_id = policy->get_other_id(policy);
- set_my_host(this, me->clone(me));
- set_other_host(this, other->clone(other));
- DESTROY_IF(this->my_id);
- DESTROY_IF(this->other_id);
- this->my_id = my_id->clone(my_id);
- this->other_id = other_id->clone(other_id);
- }
-}
-
/**
* Implementation of ike_sa_t.initiate.
*/
-static status_t initiate(private_ike_sa_t *this,
- connection_t *connection, policy_t *policy)
+static status_t initiate(private_ike_sa_t *this, child_cfg_t *child_cfg)
{
task_t *task;
if (this->state == IKE_CREATED)
{
- /* if we aren't established/establishing, do so */
- apply_config(this, connection, policy);
+
+ if (this->other_host->is_anyaddr(this->other_host))
+ {
+ SIG(IKE_UP_START, "initiating IKE_SA");
+ SIG(IKE_UP_FAILED, "unable to initiate to %%any");
+ return DESTROY_ME;
+ }
task = (task_t*)ike_init_create(&this->public, TRUE, NULL);
this->task_manager->queue_task(this->task_manager, task);
this->task_manager->queue_task(this->task_manager, task);
task = (task_t*)ike_auth_create(&this->public, TRUE);
this->task_manager->queue_task(this->task_manager, task);
- task = (task_t*)ike_config_create(&this->public, policy);
+ task = (task_t*)ike_config_create(&this->public, TRUE);
this->task_manager->queue_task(this->task_manager, task);
}
- task = (task_t*)child_create_create(&this->public, policy);
+ task = (task_t*)child_create_create(&this->public, child_cfg);
this->task_manager->queue_task(this->task_manager, task);
return this->task_manager->initiate(this->task_manager);
*/
static status_t acquire(private_ike_sa_t *this, u_int32_t reqid)
{
- policy_t *policy;
+ child_cfg_t *child_cfg;
iterator_t *iterator;
child_sa_t *current, *child_sa = NULL;
task_t *task;
return FAILED;
}
- policy = child_sa->get_policy(child_sa);
if (this->state == IKE_CREATED)
{
this->task_manager->queue_task(this->task_manager, task);
task = (task_t*)ike_auth_create(&this->public, TRUE);
this->task_manager->queue_task(this->task_manager, task);
- task = (task_t*)ike_config_create(&this->public, policy);
+ task = (task_t*)ike_config_create(&this->public, TRUE);
this->task_manager->queue_task(this->task_manager, task);
}
- child_create = child_create_create(&this->public, policy);
+ child_cfg = child_sa->get_config(child_sa);
+ child_create = child_create_create(&this->public, child_cfg);
child_create->use_reqid(child_create, reqid);
this->task_manager->queue_task(this->task_manager, (task_t*)child_create);
return this->task_manager->initiate(this->task_manager);
}
-/**
- * compare two lists of traffic selectors for equality
- */
-static bool ts_list_equals(linked_list_t *l1, linked_list_t *l2)
-{
- bool equals = TRUE;
- iterator_t *i1, *i2;
- traffic_selector_t *t1, *t2;
-
- if (l1->get_count(l1) != l2->get_count(l2))
- {
- return FALSE;
- }
-
- i1 = l1->create_iterator(l1, TRUE);
- i2 = l2->create_iterator(l2, TRUE);
- while (i1->iterate(i1, (void**)&t1) && i2->iterate(i2, (void**)&t2))
- {
- if (!t1->equals(t1, t2))
- {
- equals = FALSE;
- break;
- }
- }
- i1->destroy(i1);
- i2->destroy(i2);
- return equals;
-}
-
/**
* Implementation of ike_sa_t.route.
*/
-static status_t route(private_ike_sa_t *this, connection_t *connection, policy_t *policy)
+static status_t route(private_ike_sa_t *this, child_cfg_t *child_cfg)
{
- child_sa_t *child_sa = NULL;
+ child_sa_t *child_sa;
iterator_t *iterator;
linked_list_t *my_ts, *other_ts;
status_t status;
iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
while (iterator->iterate(iterator, (void**)&child_sa))
{
- if (child_sa->get_state(child_sa) == CHILD_ROUTED)
+ if (child_sa->get_state(child_sa) == CHILD_ROUTED &&
+ streq(child_sa->get_name(child_sa), child_cfg->get_name(child_cfg)))
{
- linked_list_t *my_ts_conf, *other_ts_conf;
-
- my_ts = child_sa->get_my_traffic_selectors(child_sa);
- other_ts = child_sa->get_other_traffic_selectors(child_sa);
-
- my_ts_conf = policy->get_my_traffic_selectors(policy, this->my_host);
- other_ts_conf = policy->get_other_traffic_selectors(policy, this->other_host);
-
- if (ts_list_equals(my_ts, my_ts_conf) &&
- ts_list_equals(other_ts, other_ts_conf))
- {
- iterator->destroy(iterator);
- my_ts_conf->destroy_offset(my_ts_conf, offsetof(traffic_selector_t, destroy));
- other_ts_conf->destroy_offset(other_ts_conf, offsetof(traffic_selector_t, destroy));
- SIG(CHILD_ROUTE_FAILED, "CHILD_SA with such a policy already routed");
- return FAILED;
- }
- my_ts_conf->destroy_offset(my_ts_conf, offsetof(traffic_selector_t, destroy));
- other_ts_conf->destroy_offset(other_ts_conf, offsetof(traffic_selector_t, destroy));
+ iterator->destroy(iterator);
+ SIG(CHILD_ROUTE_FAILED, "CHILD_SA with such a config already routed");
+ return FAILED;
}
}
iterator->destroy(iterator);
"unable to route CHILD_SA, as its IKE_SA gets deleted");
return FAILED;
case IKE_CREATED:
- /* apply connection information, we need it to acquire */
- apply_config(this, connection, policy);
- break;
case IKE_CONNECTING:
case IKE_ESTABLISHED:
default:
}
/* install kernel policies */
- child_sa = child_sa_create(this->my_host, this->other_host,
- this->my_id, this->other_id, policy, FALSE, 0);
+ child_sa = child_sa_create(this->my_host, this->other_host, this->my_id,
+ this->other_id, child_cfg, FALSE, 0);
- my_ts = policy->get_my_traffic_selectors(policy, this->my_host);
- other_ts = policy->get_other_traffic_selectors(policy, this->other_host);
+ my_ts = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL,
+ this->my_host);
+ other_ts = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL,
+ this->other_host);
status = child_sa->add_policies(child_sa, my_ts, other_ts,
- policy->get_mode(policy));
+ child_cfg->get_mode(child_cfg));
my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy));
other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy));
- this->child_sas->insert_last(this->child_sas, child_sa);
- SIG(CHILD_ROUTE_SUCCESS, "CHILD_SA routed");
+ if (status == SUCCESS)
+ {
+ this->child_sas->insert_last(this->child_sas, child_sa);
+ SIG(CHILD_ROUTE_SUCCESS, "CHILD_SA routed");
+ }
+ else
+ {
+ SIG(CHILD_ROUTE_FAILED, "routing CHILD_SA failed");
+ }
return status;
}
/**
* Implementation of ike_sa_t.unroute.
*/
-static status_t unroute(private_ike_sa_t *this, policy_t *policy)
+static status_t unroute(private_ike_sa_t *this, child_cfg_t *child_cfg)
{
iterator_t *iterator;
- child_sa_t *child_sa = NULL;
+ child_sa_t *child_sa;
bool found = FALSE;
- linked_list_t *my_ts, *other_ts, *my_ts_conf, *other_ts_conf;
SIG(CHILD_UNROUTE_START, "unrouting CHILD_SA");
iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
while (iterator->iterate(iterator, (void**)&child_sa))
{
- if (child_sa->get_state(child_sa) == CHILD_ROUTED)
+ if (child_sa->get_state(child_sa) == CHILD_ROUTED &&
+ streq(child_sa->get_name(child_sa), child_cfg->get_name(child_cfg)))
{
- my_ts = child_sa->get_my_traffic_selectors(child_sa);
- other_ts = child_sa->get_other_traffic_selectors(child_sa);
-
- my_ts_conf = policy->get_my_traffic_selectors(policy, this->my_host);
- other_ts_conf = policy->get_other_traffic_selectors(policy, this->other_host);
-
- if (ts_list_equals(my_ts, my_ts_conf) &&
- ts_list_equals(other_ts, other_ts_conf))
- {
- iterator->remove(iterator);
- SIG(CHILD_UNROUTE_SUCCESS, "CHILD_SA unrouted");
- child_sa->destroy(child_sa);
- my_ts_conf->destroy_offset(my_ts_conf, offsetof(traffic_selector_t, destroy));
- other_ts_conf->destroy_offset(other_ts_conf, offsetof(traffic_selector_t, destroy));
- found = TRUE;
- break;
- }
- my_ts_conf->destroy_offset(my_ts_conf, offsetof(traffic_selector_t, destroy));
- other_ts_conf->destroy_offset(other_ts_conf, offsetof(traffic_selector_t, destroy));
+ iterator->remove(iterator);
+ SIG(CHILD_UNROUTE_SUCCESS, "CHILD_SA unrouted");
+ child_sa->destroy(child_sa);
+ found = TRUE;
+ break;
}
}
iterator->destroy(iterator);
this->time.outbound = time(NULL);
if (this->task_manager->retransmit(this->task_manager, message_id) != SUCCESS)
{
- policy_t *policy;
+ child_cfg_t *child_cfg;
child_sa_t* child_sa;
linked_list_t *to_route, *to_restart;
iterator_t *iterator;
switch (this->state)
{
case IKE_CONNECTING:
+ {
+ /* retry IKE_SA_INIT if we have multiple keyingtries */
+ u_int32_t tries = this->peer_cfg->get_keyingtries(this->peer_cfg);
+ this->keyingtry++;
+ if (tries == 0 || tries > this->keyingtry)
+ {
+ SIG(IKE_UP_FAILED, "peer not responding, trying again "
+ "(%d/%d) in background ", this->keyingtry + 1, tries);
+ reset(this);
+ return this->task_manager->initiate(this->task_manager);
+ }
SIG(IKE_UP_FAILED, "establishing IKE_SA failed, peer not responding");
break;
+ }
case IKE_REKEYING:
SIG(IKE_REKEY_FAILED, "rekeying IKE_SA failed, peer not responding");
break;
iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
while (iterator->iterate(iterator, (void**)&child_sa))
{
- policy = child_sa->get_policy(child_sa);
+ child_cfg = child_sa->get_config(child_sa);
if (child_sa->get_state(child_sa) == CHILD_ROUTED)
{
/* reroute routed CHILD_SAs */
- to_route->insert_last(to_route, policy);
+ to_route->insert_last(to_route, child_cfg);
}
else
{
/* use DPD action for established CHILD_SAs */
- switch (policy->get_dpd_action(policy))
+ switch (this->peer_cfg->get_dpd_action(this->peer_cfg))
{
case DPD_ROUTE:
- to_route->insert_last(to_route, policy);
+ to_route->insert_last(to_route, child_cfg);
break;
case DPD_RESTART:
- to_restart->insert_last(to_restart, policy);
+ to_restart->insert_last(to_restart, child_cfg);
break;
default:
break;
/* create a new IKE_SA if we have to route or to restart */
if (to_route->get_count(to_route) || to_restart->get_count(to_restart))
{
- ike_sa_id_t *other_id;
private_ike_sa_t *new;
task_t *task;
- other_id = ike_sa_id_create(0, 0, TRUE);
- new = (private_ike_sa_t*)charon->ike_sa_manager->checkout(
- charon->ike_sa_manager, other_id);
- other_id->destroy(other_id);
+ new = (private_ike_sa_t*)charon->ike_sa_manager->checkout_new(
+ charon->ike_sa_manager, TRUE);
- apply_config(new, this->connection, this->policy);
- /* use actual used host, not the wildcarded one in connection */
+ set_peer_cfg(new, this->peer_cfg);
+ /* use actual used host, not the wildcarded one in config */
new->other_host->destroy(new->other_host);
new->other_host = this->other_host->clone(this->other_host);
/* install routes */
- while (to_route->remove_last(to_route, (void**)&policy) == SUCCESS)
+ while (to_route->remove_last(to_route, (void**)&child_cfg) == SUCCESS)
{
- route(new, new->connection, policy);
+ route(new, child_cfg);
}
/* restart children */
new->task_manager->queue_task(new->task_manager, task);
task = (task_t*)ike_cert_create(&new->public, TRUE);
new->task_manager->queue_task(new->task_manager, task);
- task = (task_t*)ike_config_create(&new->public, new->policy);
+ task = (task_t*)ike_config_create(&new->public, TRUE);
new->task_manager->queue_task(new->task_manager, task);
task = (task_t*)ike_auth_create(&new->public, TRUE);
new->task_manager->queue_task(new->task_manager, task);
- while (to_restart->remove_last(to_restart, (void**)&policy) == SUCCESS)
+ while (to_restart->remove_last(to_restart, (void**)&child_cfg) == SUCCESS)
{
- task = (task_t*)child_create_create(&new->public, policy);
+ task = (task_t*)child_create_create(&new->public, child_cfg);
new->task_manager->queue_task(new->task_manager, task);
}
new->task_manager->initiate(new->task_manager);
return SUCCESS;
}
-/**
- * Implementation of ike_sa_t.send_dpd
- */
-static status_t send_dpd(private_ike_sa_t *this)
-{
- send_dpd_job_t *job;
- time_t diff, delay;
-
- delay = this->connection->get_dpd_delay(this->connection);
-
- if (delay == 0)
- {
- /* DPD disabled */
- return SUCCESS;
- }
-
- if (this->task_manager->busy(this->task_manager))
- {
- /* an exchange is in the air, no need to start a DPD check */
- diff = 0;
- }
- else
- {
- /* check if there was any inbound traffic */
- time_t last_in, now;
- last_in = get_use_time(this, TRUE);
- now = time(NULL);
- diff = now - last_in;
- if (diff >= delay)
- {
- /* to long ago, initiate dead peer detection */
- task_t *task;
-
- task = (task_t*)ike_dpd_create(TRUE);
- diff = 0;
- DBG1(DBG_IKE, "sending DPD request");
-
- this->task_manager->queue_task(this->task_manager, task);
- this->task_manager->initiate(this->task_manager);
- }
- }
- /* recheck in "interval" seconds */
- job = send_dpd_job_create(this->ike_sa_id);
- charon->event_queue->add_relative(charon->event_queue, (job_t*)job,
- (delay - diff) * 1000);
- return SUCCESS;
-}
-
-/**
- * Implementation of ike_sa_t.send_keepalive
- */
-static void send_keepalive(private_ike_sa_t *this)
-{
- send_keepalive_job_t *job;
- time_t last_out, now, diff, interval;
-
- last_out = get_use_time(this, FALSE);
- now = time(NULL);
-
- diff = now - last_out;
- interval = charon->configuration->get_keepalive_interval(charon->configuration);
-
- if (diff >= interval)
- {
- packet_t *packet;
- chunk_t data;
-
- packet = packet_create();
- 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;
- packet->set_data(packet, data);
- charon->send_queue->add(charon->send_queue, packet);
- DBG1(DBG_IKE, "sending keep alive");
- diff = 0;
- }
- job = send_keepalive_job_create(this->ike_sa_id);
- charon->event_queue->add_relative(charon->event_queue, (job_t*)job,
- (interval - diff) * 1000);
-}
-
-/**
- * Implementation of ike_sa_t.get_state.
- */
-static ike_sa_state_t get_state(private_ike_sa_t *this)
-{
- return this->state;
-}
-
-/**
- * Implementation of ike_sa_t.set_state.
- */
-static void set_state(private_ike_sa_t *this, ike_sa_state_t state)
-{
- DBG1(DBG_IKE, "IKE_SA state change: %N => %N",
- ike_sa_state_names, this->state,
- ike_sa_state_names, state);
-
- if (state == IKE_ESTABLISHED)
- {
- job_t *job;
- u_int32_t now = time(NULL);
- u_int32_t soft, hard;
- bool reauth;
-
- this->time.established = now;
- /* start DPD checks */
- send_dpd(this);
-
- /* schedule rekeying/reauthentication */
- soft = this->connection->get_soft_lifetime(this->connection);
- hard = this->connection->get_hard_lifetime(this->connection);
- reauth = this->connection->get_reauth(this->connection);
- DBG1(DBG_IKE, "scheduling %s in %ds, maximum lifetime %ds",
- reauth ? "reauthentication": "rekeying", soft, hard);
-
- if (soft)
- {
- this->time.rekey = now + soft;
- job = (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, reauth);
- charon->event_queue->add_relative(charon->event_queue, job,
- soft * 1000);
- }
-
- if (hard)
- {
- this->time.delete = now + hard;
- job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, TRUE);
- charon->event_queue->add_relative(charon->event_queue, job,
- hard * 1000);
- }
- }
-
- this->state = state;
-}
-
/**
* Implementation of ike_sa_t.get_prf.
*/
*/
static void reestablish(private_ike_sa_t *this)
{
- ike_sa_id_t *other_id;
private_ike_sa_t *other;
iterator_t *iterator;
child_sa_t *child_sa;
- policy_t *policy;
+ child_cfg_t *child_cfg;
task_t *task;
job_t *job;
- other_id = ike_sa_id_create(0, 0, TRUE);
- other = (private_ike_sa_t*)charon->ike_sa_manager->checkout(
- charon->ike_sa_manager, other_id);
- other_id->destroy(other_id);
+ other = (private_ike_sa_t*)charon->ike_sa_manager->checkout_new(
+ charon->ike_sa_manager, TRUE);
- apply_config(other, this->connection, this->policy);
+ set_peer_cfg(other, this->peer_cfg);
other->other_host->destroy(other->other_host);
other->other_host = this->other_host->clone(this->other_host);
other->task_manager->queue_task(other->task_manager, task);
task = (task_t*)ike_cert_create(&other->public, TRUE);
other->task_manager->queue_task(other->task_manager, task);
- task = (task_t*)ike_config_create(&other->public, other->policy);
+ task = (task_t*)ike_config_create(&other->public, TRUE);
other->task_manager->queue_task(other->task_manager, task);
task = (task_t*)ike_auth_create(&other->public, TRUE);
other->task_manager->queue_task(other->task_manager, task);
}
default:
{
- policy = child_sa->get_policy(child_sa);
- task = (task_t*)child_create_create(&other->public, policy);
+ child_cfg = child_sa->get_config(child_sa);
+ task = (task_t*)child_create_create(&other->public, child_cfg);
other->task_manager->queue_task(other->task_manager, task);
break;
}
/**
* Implementation of ike_sa_t.inherit.
*/
-static void inherit(private_ike_sa_t *this, private_ike_sa_t *other)
+static status_t inherit(private_ike_sa_t *this, private_ike_sa_t *other)
{
child_sa_t *child_sa;
host_t *ip;
{
this->child_sas->insert_first(this->child_sas, (void*)child_sa);
}
+
+ /* move pending tasks to the new IKE_SA */
+ this->task_manager->adopt_tasks(this->task_manager, other->task_manager);
+
+ /* we have to initate here, there may be new tasks to handle */
+ return this->task_manager->initiate(this->task_manager);
}
/**
}
}
-/**
- * Implementation of ike_sa_t.reset
- */
-static void reset(private_ike_sa_t *this)
-{
- /* the responder ID is reset, as peer may choose another one */
- if (this->ike_sa_id->is_initiator(this->ike_sa_id))
- {
- this->ike_sa_id->set_responder_spi(this->ike_sa_id, 0);
- }
-
- set_state(this, IKE_CREATED);
-
- this->task_manager->reset(this->task_manager);
-}
-
/**
* Implementation of ike_sa_t.set_virtual_ip
*/
bool reauth = FALSE;
private_ike_sa_t *this = *((private_ike_sa_t**)(args[0]));
- if (this->connection)
+ if (this->peer_cfg)
{
- reauth = this->connection->get_reauth(this->connection);
+ reauth = this->peer_cfg->use_reauth(this->peer_cfg);
}
if (this == NULL)
this->unique_id, ike_sa_state_names, this->state,
this->my_host, this->my_id, this->other_host,
this->other_id);
- written += fprintf(stream, "\n%12s[%d]: IKE SPIs: %J, %s in %ds",
- get_name(this), this->unique_id, this->ike_sa_id,
- this->connection && reauth? "reauthentication":"rekeying",
- this->time.rekey - time(NULL));
-
- if (info->alt)
+ if (this->time.rekey)
{
-
+ written += fprintf(stream, "\n%12s[%d]: IKE SPIs: %J, %s in %ds",
+ get_name(this), this->unique_id, this->ike_sa_id,
+ reauth ? "reauthentication" : "rekeying",
+ this->time.rekey - time(NULL));
+ }
+ else
+ {
+ written += fprintf(stream, "\n%12s[%d]: IKE SPIs: %J, rekeying disabled",
+ get_name(this), this->unique_id, this->ike_sa_id);
}
+
return written;
}
DESTROY_IF(this->my_id);
DESTROY_IF(this->other_id);
- DESTROY_IF(this->connection);
- DESTROY_IF(this->policy);
+ DESTROY_IF(this->ike_cfg);
+ DESTROY_IF(this->peer_cfg);
this->ike_sa_id->destroy(this->ike_sa_id);
this->task_manager->destroy(this->task_manager);
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.process_message = (status_t(*)(ike_sa_t*, message_t*)) process_message;
- this->public.initiate = (status_t(*)(ike_sa_t*,connection_t*,policy_t*)) initiate;
- this->public.route = (status_t(*)(ike_sa_t*,connection_t*,policy_t*)) route;
- this->public.unroute = (status_t(*)(ike_sa_t*,policy_t*)) unroute;
+ this->public.initiate = (status_t(*)(ike_sa_t*,child_cfg_t*)) initiate;
+ this->public.route = (status_t(*)(ike_sa_t*,child_cfg_t*)) route;
+ this->public.unroute = (status_t(*)(ike_sa_t*,child_cfg_t*)) unroute;
this->public.acquire = (status_t(*)(ike_sa_t*,u_int32_t)) acquire;
- this->public.get_connection = (connection_t*(*)(ike_sa_t*))get_connection;
- this->public.set_connection = (void(*)(ike_sa_t*,connection_t*))set_connection;
- this->public.get_policy = (policy_t*(*)(ike_sa_t*))get_policy;
- this->public.set_policy = (void(*)(ike_sa_t*,policy_t*))set_policy;
+ this->public.get_ike_cfg = (ike_cfg_t*(*)(ike_sa_t*))get_ike_cfg;
+ this->public.set_ike_cfg = (void(*)(ike_sa_t*,ike_cfg_t*))set_ike_cfg;
+ this->public.get_peer_cfg = (peer_cfg_t*(*)(ike_sa_t*))get_peer_cfg;
+ this->public.set_peer_cfg = (void(*)(ike_sa_t*,peer_cfg_t*))set_peer_cfg;
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.set_my_host = (void(*)(ike_sa_t*,host_t*)) set_my_host;
this->public.is_natt_enabled = (bool(*)(ike_sa_t*)) is_natt_enabled;
this->public.rekey = (status_t(*)(ike_sa_t*))rekey;
this->public.reestablish = (void(*)(ike_sa_t*))reestablish;
- this->public.inherit = (void(*)(ike_sa_t*,ike_sa_t*))inherit;
+ this->public.inherit = (status_t(*)(ike_sa_t*,ike_sa_t*))inherit;
this->public.generate_message = (status_t(*)(ike_sa_t*,message_t*,packet_t**))generate_message;
this->public.reset = (void(*)(ike_sa_t*))reset;
this->public.get_unique_id = (u_int32_t(*)(ike_sa_t*))get_unique_id;
this->time.established = 0;
this->time.rekey = 0;
this->time.delete = 0;
- this->connection = NULL;
- this->policy = NULL;
+ this->ike_cfg = NULL;
+ this->peer_cfg = NULL;
this->task_manager = task_manager_create(&this->public);
this->unique_id = ++unique_id;
this->my_virtual_ip = NULL;
this->other_virtual_ip = NULL;
this->dns_servers = linked_list_create();
+ this->keyingtry = 0;
return &this->public;
}