summaryrefslogtreecommitdiff
path: root/src/libcharon/sa
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcharon/sa')
-rw-r--r--src/libcharon/sa/child_sa.c13
-rw-r--r--src/libcharon/sa/child_sa.h7
-rw-r--r--src/libcharon/sa/ike_sa.c41
-rw-r--r--src/libcharon/sa/ike_sa_manager.c8
-rw-r--r--src/libcharon/sa/ikev1/task_manager_v1.c19
-rw-r--r--src/libcharon/sa/ikev1/tasks/aggressive_mode.c6
-rw-r--r--src/libcharon/sa/ikev1/tasks/isakmp_vendor.c4
-rw-r--r--src/libcharon/sa/ikev1/tasks/quick_mode.c2
-rw-r--r--src/libcharon/sa/ikev2/keymat_v2.c30
-rw-r--r--src/libcharon/sa/ikev2/task_manager_v2.c15
-rw-r--r--src/libcharon/sa/ikev2/tasks/child_create.c4
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_auth.c2
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_cert_pre.c2
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_vendor.c79
-rw-r--r--src/libcharon/sa/task_manager.h5
-rw-r--r--src/libcharon/sa/trap_manager.c87
-rw-r--r--src/libcharon/sa/xauth/xauth_manager.c3
17 files changed, 205 insertions, 122 deletions
diff --git a/src/libcharon/sa/child_sa.c b/src/libcharon/sa/child_sa.c
index 9c3876a94..720a58553 100644
--- a/src/libcharon/sa/child_sa.c
+++ b/src/libcharon/sa/child_sa.c
@@ -120,6 +120,11 @@ struct private_child_sa_t {
time_t expire_time;
/**
+ * absolute time when SA has been installed
+ */
+ time_t install_time;
+
+ /**
* state of the CHILD_SA
*/
child_sa_state_t state;
@@ -586,6 +591,12 @@ METHOD(child_sa_t, get_lifetime, time_t,
return hard ? this->expire_time : this->rekey_time;
}
+METHOD(child_sa_t, get_installtime, time_t,
+ private_child_sa_t *this)
+{
+ return this->install_time;
+}
+
METHOD(child_sa_t, alloc_spi, u_int32_t,
private_child_sa_t *this, protocol_id_t protocol)
{
@@ -1140,6 +1151,7 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
.get_proposal = _get_proposal,
.set_proposal = _set_proposal,
.get_lifetime = _get_lifetime,
+ .get_installtime = _get_installtime,
.get_usestats = _get_usestats,
.get_mark = _get_mark,
.has_encap = _has_encap,
@@ -1170,6 +1182,7 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
.reqid = config->get_reqid(config),
.mark_in = config->get_mark(config, TRUE),
.mark_out = config->get_mark(config, FALSE),
+ .install_time = time_monotonic(NULL),
);
this->config = config;
diff --git a/src/libcharon/sa/child_sa.h b/src/libcharon/sa/child_sa.h
index ed52d60b1..a0c6c357f 100644
--- a/src/libcharon/sa/child_sa.h
+++ b/src/libcharon/sa/child_sa.h
@@ -265,6 +265,13 @@ struct child_sa_t {
time_t (*get_lifetime)(child_sa_t *this, bool hard);
/**
+ * Get the absolute time when this SA has been installed.
+ *
+ * @return monotonic absolute install time
+ */
+ time_t (*get_installtime)(child_sa_t *this);
+
+ /**
* Get last use time and the number of bytes processed.
*
* @param inbound TRUE for inbound traffic, FALSE for outbound
diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c
index 028208782..2c15dc5eb 100644
--- a/src/libcharon/sa/ike_sa.c
+++ b/src/libcharon/sa/ike_sa.c
@@ -687,6 +687,14 @@ METHOD(ike_sa_t, set_state, void,
DBG1(DBG_IKE, "maximum IKE_SA lifetime %ds", t);
}
trigger_dpd = this->peer_cfg->get_dpd(this->peer_cfg);
+ if (trigger_dpd)
+ {
+ /* Some peers delay the DELETE after rekeying an IKE_SA.
+ * If this delay is longer than our DPD delay, we would
+ * send a DPD request here. The IKE_SA is not ready to do
+ * so yet, so prevent that. */
+ this->stats[STAT_INBOUND] = this->stats[STAT_ESTABLISHED];
+ }
}
break;
}
@@ -1162,26 +1170,13 @@ METHOD(ike_sa_t, initiate, status_t,
#endif /* ME */
)
{
- bool is_anyaddr;
- host_t *host;
char *addr;
- addr = this->ike_cfg->get_my_addr(this->ike_cfg);
- host = this->ike_cfg->resolve_other(this->ike_cfg, AF_UNSPEC);
- is_anyaddr = host && host->is_anyaddr(host);
- DESTROY_IF(host);
-
- if (is_anyaddr || !this->retry_initiate_interval)
+ addr = this->ike_cfg->get_other_addr(this->ike_cfg);
+ if (!this->retry_initiate_interval)
{
- if (is_anyaddr)
- {
- DBG1(DBG_IKE, "unable to initiate to %s", addr);
- }
- else
- {
- DBG1(DBG_IKE, "unable to resolve %s, initiate aborted",
- addr);
- }
+ DBG1(DBG_IKE, "unable to resolve %s, initiate aborted",
+ addr);
DESTROY_IF(child_cfg);
charon->bus->alert(charon->bus, ALERT_PEER_ADDR_FAILED);
return DESTROY_ME;
@@ -2130,7 +2125,10 @@ METHOD(ike_sa_t, destroy, void,
charon->bus->set_sa(charon->bus, &this->public);
set_state(this, IKE_DESTROYING);
- DESTROY_IF(this->task_manager);
+ if (this->task_manager)
+ {
+ this->task_manager->flush(this->task_manager);
+ }
/* remove attributes first, as we pass the IKE_SA to the handler */
while (array_remove(this->attributes, ARRAY_TAIL, &entry))
@@ -2174,6 +2172,7 @@ METHOD(ike_sa_t, destroy, void,
charon->bus->set_sa(charon->bus, NULL);
array_destroy(this->child_sas);
+ DESTROY_IF(this->task_manager);
DESTROY_IF(this->keymat);
array_destroy(this->attributes);
array_destroy(this->my_vips);
@@ -2330,11 +2329,11 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator,
.attributes = array_create(sizeof(attribute_entry_t), 0),
.unique_id = ref_get(&unique_id),
.keepalive_interval = lib->settings->get_time(lib->settings,
- "%s.keep_alive", KEEPALIVE_INTERVAL, charon->name),
+ "%s.keep_alive", KEEPALIVE_INTERVAL, lib->ns),
.retry_initiate_interval = lib->settings->get_time(lib->settings,
- "%s.retry_initiate_interval", 0, charon->name),
+ "%s.retry_initiate_interval", 0, lib->ns),
.flush_auth_cfg = lib->settings->get_bool(lib->settings,
- "%s.flush_auth_cfg", FALSE, charon->name),
+ "%s.flush_auth_cfg", FALSE, lib->ns),
);
if (version == IKEV2)
diff --git a/src/libcharon/sa/ike_sa_manager.c b/src/libcharon/sa/ike_sa_manager.c
index 5768803aa..f2f81cf33 100644
--- a/src/libcharon/sa/ike_sa_manager.c
+++ b/src/libcharon/sa/ike_sa_manager.c
@@ -2150,17 +2150,17 @@ ike_sa_manager_t *ike_sa_manager_create()
}
this->ikesa_limit = lib->settings->get_int(lib->settings,
- "%s.ikesa_limit", 0, charon->name);
+ "%s.ikesa_limit", 0, lib->ns);
this->table_size = get_nearest_powerof2(lib->settings->get_int(
lib->settings, "%s.ikesa_table_size",
- DEFAULT_HASHTABLE_SIZE, charon->name));
+ DEFAULT_HASHTABLE_SIZE, lib->ns));
this->table_size = max(1, min(this->table_size, MAX_HASHTABLE_SIZE));
this->table_mask = this->table_size - 1;
this->segment_count = get_nearest_powerof2(lib->settings->get_int(
lib->settings, "%s.ikesa_table_segments",
- DEFAULT_SEGMENT_COUNT, charon->name));
+ DEFAULT_SEGMENT_COUNT, lib->ns));
this->segment_count = max(1, min(this->segment_count, this->table_size));
this->segment_mask = this->segment_count - 1;
@@ -2200,6 +2200,6 @@ ike_sa_manager_t *ike_sa_manager_create()
}
this->reuse_ikesa = lib->settings->get_bool(lib->settings,
- "%s.reuse_ikesa", TRUE, charon->name);
+ "%s.reuse_ikesa", TRUE, lib->ns);
return &this->public;
}
diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c
index 597416e36..8fc158bba 100644
--- a/src/libcharon/sa/ikev1/task_manager_v1.c
+++ b/src/libcharon/sa/ikev1/task_manager_v1.c
@@ -339,10 +339,8 @@ METHOD(task_manager_t, flush_queue, void,
}
}
-/**
- * flush all tasks in the task manager
- */
-static void flush(private_task_manager_t *this)
+METHOD(task_manager_t, flush, void,
+ private_task_manager_t *this)
{
flush_queue(this, TASK_QUEUE_QUEUED);
flush_queue(this, TASK_QUEUE_PASSIVE);
@@ -1581,7 +1579,7 @@ METHOD(task_manager_t, process_message, status_t,
lib->scheduler->schedule_job(lib->scheduler, job,
lib->settings->get_int(lib->settings,
"%s.half_open_timeout", HALF_OPEN_IKE_SA_TIMEOUT,
- charon->name));
+ lib->ns));
}
this->ike_sa->update_hosts(this->ike_sa, me, other, TRUE);
charon->bus->message(charon->bus, msg, TRUE, TRUE);
@@ -2070,6 +2068,7 @@ task_manager_v1_t *task_manager_v1_create(ike_sa_t *ike_sa)
.adopt_child_tasks = _adopt_child_tasks,
.busy = _busy,
.create_task_enumerator = _create_task_enumerator,
+ .flush = _flush,
.flush_queue = _flush_queue,
.destroy = _destroy,
},
@@ -2083,9 +2082,9 @@ task_manager_v1_t *task_manager_v1_create(ike_sa_t *ike_sa)
.frag = {
.exchange = ID_PROT,
.max_packet = lib->settings->get_int(lib->settings,
- "%s.max_packet", MAX_PACKET, charon->name),
+ "%s.max_packet", MAX_PACKET, lib->ns),
.size = lib->settings->get_int(lib->settings,
- "%s.fragment_size", MAX_FRAGMENT_SIZE, charon->name),
+ "%s.fragment_size", MAX_FRAGMENT_SIZE, lib->ns),
},
.ike_sa = ike_sa,
.rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK),
@@ -2093,11 +2092,11 @@ task_manager_v1_t *task_manager_v1_create(ike_sa_t *ike_sa)
.active_tasks = linked_list_create(),
.passive_tasks = linked_list_create(),
.retransmit_tries = lib->settings->get_int(lib->settings,
- "%s.retransmit_tries", RETRANSMIT_TRIES, charon->name),
+ "%s.retransmit_tries", RETRANSMIT_TRIES, lib->ns),
.retransmit_timeout = lib->settings->get_double(lib->settings,
- "%s.retransmit_timeout", RETRANSMIT_TIMEOUT, charon->name),
+ "%s.retransmit_timeout", RETRANSMIT_TIMEOUT, lib->ns),
.retransmit_base = lib->settings->get_double(lib->settings,
- "%s.retransmit_base", RETRANSMIT_BASE, charon->name),
+ "%s.retransmit_base", RETRANSMIT_BASE, lib->ns),
);
if (!this->rng)
diff --git a/src/libcharon/sa/ikev1/tasks/aggressive_mode.c b/src/libcharon/sa/ikev1/tasks/aggressive_mode.c
index 46cbb879b..6cc3e04b3 100644
--- a/src/libcharon/sa/ikev1/tasks/aggressive_mode.c
+++ b/src/libcharon/sa/ikev1/tasks/aggressive_mode.c
@@ -421,7 +421,7 @@ METHOD(task_t, process_r, status_t,
case AUTH_PSK:
if (!lib->settings->get_bool(lib->settings, "%s.i_dont_care"
"_about_security_and_use_aggressive_mode_psk",
- FALSE, charon->name))
+ FALSE, lib->ns))
{
DBG1(DBG_IKE, "Aggressive Mode PSK disabled for "
"security reasons");
@@ -478,7 +478,7 @@ METHOD(task_t, process_r, status_t,
while (TRUE)
{
if (this->ph1->verify_auth(this->ph1, this->method, message,
- this->id_data))
+ chunk_clone(this->id_data)))
{
break;
}
@@ -487,12 +487,10 @@ METHOD(task_t, process_r, status_t,
this->method, TRUE, NULL);
if (!this->peer_cfg)
{
- this->id_data = chunk_empty;
return send_delete(this);
}
this->ike_sa->set_peer_cfg(this->ike_sa, this->peer_cfg);
}
- this->id_data = chunk_empty;
if (!charon->bus->authorize(charon->bus, FALSE))
{
diff --git a/src/libcharon/sa/ikev1/tasks/isakmp_vendor.c b/src/libcharon/sa/ikev1/tasks/isakmp_vendor.c
index 11155b287..e07ac0ab4 100644
--- a/src/libcharon/sa/ikev1/tasks/isakmp_vendor.c
+++ b/src/libcharon/sa/ikev1/tasks/isakmp_vendor.c
@@ -191,9 +191,9 @@ static void build(private_isakmp_vendor_t *this, message_t *message)
int i;
strongswan = lib->settings->get_bool(lib->settings,
- "%s.send_vendor_id", FALSE, charon->name);
+ "%s.send_vendor_id", FALSE, lib->ns);
cisco_unity = lib->settings->get_bool(lib->settings,
- "%s.cisco_unity", FALSE, charon->name);
+ "%s.cisco_unity", FALSE, lib->ns);
ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa);
fragmentation = ike_cfg->fragmentation(ike_cfg) != FRAGMENTATION_NO;
if (!this->initiator && fragmentation)
diff --git a/src/libcharon/sa/ikev1/tasks/quick_mode.c b/src/libcharon/sa/ikev1/tasks/quick_mode.c
index 12ee594b9..6e7da9852 100644
--- a/src/libcharon/sa/ikev1/tasks/quick_mode.c
+++ b/src/libcharon/sa/ikev1/tasks/quick_mode.c
@@ -194,7 +194,7 @@ static void schedule_inactivity_timeout(private_quick_mode_t *this)
if (timeout)
{
close_ike = lib->settings->get_bool(lib->settings,
- "%s.inactivity_close_ike", FALSE, charon->name);
+ "%s.inactivity_close_ike", FALSE, lib->ns);
lib->scheduler->schedule_job(lib->scheduler, (job_t*)
inactivity_job_create(this->child_sa->get_reqid(this->child_sa),
timeout, close_ike), timeout);
diff --git a/src/libcharon/sa/ikev2/keymat_v2.c b/src/libcharon/sa/ikev2/keymat_v2.c
index 4d0683f0a..8c7ba8d55 100644
--- a/src/libcharon/sa/ikev2/keymat_v2.c
+++ b/src/libcharon/sa/ikev2/keymat_v2.c
@@ -278,6 +278,7 @@ METHOD(keymat_v2_t, derive_ike_keys, bool,
{
DBG1(DBG_IKE, "no %N selected",
transform_type_names, PSEUDO_RANDOM_FUNCTION);
+ chunk_clear(&secret);
return FALSE;
}
this->prf_alg = alg;
@@ -287,6 +288,7 @@ METHOD(keymat_v2_t, derive_ike_keys, bool,
DBG1(DBG_IKE, "%N %N not supported!",
transform_type_names, PSEUDO_RANDOM_FUNCTION,
pseudo_random_function_names, alg);
+ chunk_clear(&secret);
return FALSE;
}
DBG4(DBG_IKE, "shared Diffie Hellman secret %B", &secret);
@@ -339,6 +341,7 @@ METHOD(keymat_v2_t, derive_ike_keys, bool,
{
DBG1(DBG_IKE, "PRF of old SA %N not supported!",
pseudo_random_function_names, rekey_function);
+ chunk_clear(&secret);
chunk_free(&full_nonce);
chunk_free(&fixed_nonce);
chunk_clear(&prf_plus_seed);
@@ -450,17 +453,6 @@ METHOD(keymat_v2_t, derive_child_keys, bool,
chunk_t seed, secret = chunk_empty;
prf_plus_t *prf_plus;
- if (dh)
- {
- if (dh->get_shared_secret(dh, &secret) != SUCCESS)
- {
- return FALSE;
- }
- DBG4(DBG_CHD, "DH secret %B", &secret);
- }
- seed = chunk_cata("mcc", secret, nonce_i, nonce_r);
- DBG4(DBG_CHD, "seed %B", &seed);
-
if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM,
&enc_alg, &enc_size))
{
@@ -527,7 +519,21 @@ METHOD(keymat_v2_t, derive_child_keys, bool,
{
return FALSE;
}
+
+ if (dh)
+ {
+ if (dh->get_shared_secret(dh, &secret) != SUCCESS)
+ {
+ return FALSE;
+ }
+ DBG4(DBG_CHD, "DH secret %B", &secret);
+ }
+ seed = chunk_cata("scc", secret, nonce_i, nonce_r);
+ DBG4(DBG_CHD, "seed %B", &seed);
+
prf_plus = prf_plus_create(this->prf, TRUE, seed);
+ memwipe(seed.ptr, seed.len);
+
if (!prf_plus)
{
return FALSE;
@@ -590,7 +596,7 @@ METHOD(keymat_v2_t, get_auth_octets, bool,
idx = chunk_cata("cc", chunk, id->get_encoding(id));
DBG3(DBG_IKE, "IDx' %B", &idx);
- DBG3(DBG_IKE, "SK_p %B", &skp);
+ DBG4(DBG_IKE, "SK_p %B", &skp);
if (!this->prf->set_key(this->prf, skp) ||
!this->prf->allocate_bytes(this->prf, idx, &chunk))
{
diff --git a/src/libcharon/sa/ikev2/task_manager_v2.c b/src/libcharon/sa/ikev2/task_manager_v2.c
index 8e6da1609..ac3be900f 100644
--- a/src/libcharon/sa/ikev2/task_manager_v2.c
+++ b/src/libcharon/sa/ikev2/task_manager_v2.c
@@ -184,10 +184,8 @@ METHOD(task_manager_t, flush_queue, void,
}
}
-/**
- * flush all tasks in the task manager
- */
-static void flush(private_task_manager_t *this)
+METHOD(task_manager_t, flush, void,
+ private_task_manager_t *this)
{
flush_queue(this, TASK_QUEUE_QUEUED);
flush_queue(this, TASK_QUEUE_PASSIVE);
@@ -1231,7 +1229,7 @@ METHOD(task_manager_t, process_message, status_t,
lib->scheduler->schedule_job(lib->scheduler, job,
lib->settings->get_int(lib->settings,
"%s.half_open_timeout", HALF_OPEN_IKE_SA_TIMEOUT,
- charon->name));
+ lib->ns));
}
return SUCCESS;
}
@@ -1569,6 +1567,7 @@ task_manager_v2_t *task_manager_v2_create(ike_sa_t *ike_sa)
.adopt_child_tasks = _adopt_child_tasks,
.busy = _busy,
.create_task_enumerator = _create_task_enumerator,
+ .flush = _flush,
.flush_queue = _flush_queue,
.destroy = _destroy,
},
@@ -1579,11 +1578,11 @@ task_manager_v2_t *task_manager_v2_create(ike_sa_t *ike_sa)
.active_tasks = array_create(0, 0),
.passive_tasks = array_create(0, 0),
.retransmit_tries = lib->settings->get_int(lib->settings,
- "%s.retransmit_tries", RETRANSMIT_TRIES, charon->name),
+ "%s.retransmit_tries", RETRANSMIT_TRIES, lib->ns),
.retransmit_timeout = lib->settings->get_double(lib->settings,
- "%s.retransmit_timeout", RETRANSMIT_TIMEOUT, charon->name),
+ "%s.retransmit_timeout", RETRANSMIT_TIMEOUT, lib->ns),
.retransmit_base = lib->settings->get_double(lib->settings,
- "%s.retransmit_base", RETRANSMIT_BASE, charon->name),
+ "%s.retransmit_base", RETRANSMIT_BASE, lib->ns),
);
return &this->public;
diff --git a/src/libcharon/sa/ikev2/tasks/child_create.c b/src/libcharon/sa/ikev2/tasks/child_create.c
index 7cfa537a9..df7bc96d6 100644
--- a/src/libcharon/sa/ikev2/tasks/child_create.c
+++ b/src/libcharon/sa/ikev2/tasks/child_create.c
@@ -293,7 +293,7 @@ static void schedule_inactivity_timeout(private_child_create_t *this)
if (timeout)
{
close_ike = lib->settings->get_bool(lib->settings,
- "%s.inactivity_close_ike", FALSE, charon->name);
+ "%s.inactivity_close_ike", FALSE, lib->ns);
lib->scheduler->schedule_job(lib->scheduler, (job_t*)
inactivity_job_create(this->child_sa->get_reqid(this->child_sa),
timeout, close_ike), timeout);
@@ -1072,7 +1072,7 @@ static void handle_child_sa_failure(private_child_create_t *this,
{
if (message->get_exchange_type(message) == IKE_AUTH &&
lib->settings->get_bool(lib->settings,
- "%s.close_ike_on_child_failure", FALSE, charon->name))
+ "%s.close_ike_on_child_failure", FALSE, lib->ns))
{
/* we delay the delete for 100ms, as the IKE_AUTH response must arrive
* first */
diff --git a/src/libcharon/sa/ikev2/tasks/ike_auth.c b/src/libcharon/sa/ikev2/tasks/ike_auth.c
index 8f83c4884..800dab07e 100644
--- a/src/libcharon/sa/ikev2/tasks/ike_auth.c
+++ b/src/libcharon/sa/ikev2/tasks/ike_auth.c
@@ -120,7 +120,7 @@ struct private_ike_auth_t {
static bool multiple_auth_enabled()
{
return lib->settings->get_bool(lib->settings,
- "%s.multiple_authentication", TRUE, charon->name);
+ "%s.multiple_authentication", TRUE, lib->ns);
}
/**
diff --git a/src/libcharon/sa/ikev2/tasks/ike_cert_pre.c b/src/libcharon/sa/ikev2/tasks/ike_cert_pre.c
index 2cbe8f8c5..bd28b29d7 100644
--- a/src/libcharon/sa/ikev2/tasks/ike_cert_pre.c
+++ b/src/libcharon/sa/ikev2/tasks/ike_cert_pre.c
@@ -428,7 +428,7 @@ static void build_certreqs(private_ike_cert_pre_t *this, message_t *message)
message->add_payload(message, (payload_t*)req);
if (lib->settings->get_bool(lib->settings,
- "%s.hash_and_url", FALSE, charon->name))
+ "%s.hash_and_url", FALSE, lib->ns))
{
message->add_notify(message, FALSE, HTTP_CERT_LOOKUP_SUPPORTED,
chunk_empty);
diff --git a/src/libcharon/sa/ikev2/tasks/ike_vendor.c b/src/libcharon/sa/ikev2/tasks/ike_vendor.c
index 2730f5876..16ac16673 100644
--- a/src/libcharon/sa/ikev2/tasks/ike_vendor.c
+++ b/src/libcharon/sa/ikev2/tasks/ike_vendor.c
@@ -42,24 +42,60 @@ struct private_ike_vendor_t {
};
/**
- * strongSwan specific vendor ID without version, MD5("strongSwan")
+ * Vendor ID database entry
*/
-static chunk_t strongswan_vid = chunk_from_chars(
- 0x88,0x2f,0xe5,0x6d,0x6f,0xd2,0x0d,0xbc,
- 0x22,0x51,0x61,0x3b,0x2e,0xbe,0x5b,0xeb
-);
+typedef struct {
+ /* Description */
+ char *desc;
+ /* extension flag negotiated with vendor ID, if any */
+ ike_extension_t extension;
+ /* length of vendor ID string, 0 for NULL terminated */
+ int len;
+ /* vendor ID string */
+ char *id;
+} vid_data_t;
+
+/**
+ * Get the data of a vendor ID as a chunk
+ */
+static chunk_t get_vid_data(vid_data_t *data)
+{
+ return chunk_create(data->id, data->len ?: strlen(data->id));
+}
+
+/**
+ * IKEv2 Vendor ID database entry
+ */
+static vid_data_t vids[] = {
+ /* strongSwan MD5("strongSwan") */
+ { "strongSwan", EXT_STRONGSWAN, 16,
+ "\x88\x2f\xe5\x6d\x6f\xd2\x0d\xbc\x22\x51\x61\x3b\x2e\xbe\x5b\xeb"},
+ { "Cisco Delete Reason", 0, 0,
+ "CISCO-DELETE-REASON" },
+ { "Cisco Copyright (c) 2009", 0, 0,
+ "CISCO(COPYRIGHT)&Copyright (c) 2009 Cisco Systems, Inc." },
+ { "FRAGMENTATION", 0, 16,
+ "\x40\x48\xb7\xd5\x6e\xbc\xe8\x85\x25\xe7\xde\x7f\x00\xd6\xc2\xd3"},
+};
METHOD(task_t, build, status_t,
private_ike_vendor_t *this, message_t *message)
{
- if (lib->settings->get_bool(lib->settings,
- "%s.send_vendor_id", FALSE, charon->name))
- {
- vendor_id_payload_t *vid;
+ vendor_id_payload_t *vid;
+ bool strongswan;
+ int i;
- vid = vendor_id_payload_create_data(VENDOR_ID,
- chunk_clone(strongswan_vid));
- message->add_payload(message, &vid->payload_interface);
+ strongswan = lib->settings->get_bool(lib->settings,
+ "%s.send_vendor_id", FALSE, lib->ns);
+ for (i = 0; i < countof(vids); i++)
+ {
+ if (vids[i].extension == EXT_STRONGSWAN && strongswan)
+ {
+ DBG2(DBG_IKE, "sending %s vendor ID", vids[i].desc);
+ vid = vendor_id_payload_create_data(VENDOR_ID,
+ chunk_clone(get_vid_data(&vids[i])));
+ message->add_payload(message, &vid->payload_interface);
+ }
}
return this->initiator ? NEED_MORE : SUCCESS;
@@ -70,6 +106,7 @@ METHOD(task_t, process, status_t,
{
enumerator_t *enumerator;
payload_t *payload;
+ int i;
enumerator = message->create_payload_enumerator(message);
while (enumerator->enumerate(enumerator, &payload))
@@ -78,16 +115,26 @@ METHOD(task_t, process, status_t,
{
vendor_id_payload_t *vid;
chunk_t data;
+ bool found = FALSE;
vid = (vendor_id_payload_t*)payload;
data = vid->get_data(vid);
- if (chunk_equals(data, strongswan_vid))
+ for (i = 0; i < countof(vids); i++)
{
- DBG1(DBG_IKE, "received strongSwan vendor ID");
- this->ike_sa->enable_extension(this->ike_sa, EXT_STRONGSWAN);
+ if (chunk_equals(get_vid_data(&vids[i]), data))
+ {
+ DBG1(DBG_IKE, "received %s vendor ID", vids[i].desc);
+ if (vids[i].extension)
+ {
+ this->ike_sa->enable_extension(this->ike_sa,
+ vids[i].extension);
+ }
+ found = TRUE;
+ break;
+ }
}
- else
+ if (!found)
{
DBG1(DBG_ENC, "received unknown vendor ID: %#B", &data);
}
diff --git a/src/libcharon/sa/task_manager.h b/src/libcharon/sa/task_manager.h
index a1ebb4117..e7a6bf463 100644
--- a/src/libcharon/sa/task_manager.h
+++ b/src/libcharon/sa/task_manager.h
@@ -261,6 +261,11 @@ struct task_manager_t {
task_queue_t queue);
/**
+ * Flush all tasks, regardless of the queue.
+ */
+ void (*flush)(task_manager_t *this);
+
+ /**
* Flush a queue, cancelling all tasks.
*
* @param queue queue to flush
diff --git a/src/libcharon/sa/trap_manager.c b/src/libcharon/sa/trap_manager.c
index 1f66d6ceb..7e55d6b0f 100644
--- a/src/libcharon/sa/trap_manager.c
+++ b/src/libcharon/sa/trap_manager.c
@@ -19,7 +19,6 @@
#include <hydra.h>
#include <daemon.h>
#include <threading/rwlock.h>
-#include <threading/thread_value.h>
#include <collections/linked_list.h>
@@ -63,11 +62,6 @@ struct private_trap_manager_t {
rwlock_t *lock;
/**
- * track if the current thread is installing a trap policy
- */
- thread_value_t *installing;
-
- /**
* listener to track acquiring IKE_SAs
*/
trap_listener_t listener;
@@ -77,6 +71,8 @@ struct private_trap_manager_t {
* A installed trap entry
*/
typedef struct {
+ /** name of the trapped CHILD_SA */
+ char *name;
/** ref to peer_cfg to initiate */
peer_cfg_t *peer_cfg;
/** ref to instanciated CHILD_SA */
@@ -94,6 +90,7 @@ static void destroy_entry(entry_t *entry)
{
entry->child_sa->destroy(entry->child_sa);
entry->peer_cfg->destroy(entry->peer_cfg);
+ free(entry->name);
free(entry);
}
@@ -137,27 +134,42 @@ METHOD(trap_manager_t, install, u_int32_t,
}
this->lock->write_lock(this->lock);
- this->installing->set(this->installing, this);
enumerator = this->traps->create_enumerator(this->traps);
while (enumerator->enumerate(enumerator, &entry))
{
- if (streq(entry->child_sa->get_name(entry->child_sa),
- child->get_name(child)))
+ if (streq(entry->name, child->get_name(child)))
{
- this->traps->remove_at(this->traps, enumerator);
found = entry;
+ if (entry->child_sa)
+ { /* replace it with an updated version, if already installed */
+ this->traps->remove_at(this->traps, enumerator);
+ }
break;
}
}
enumerator->destroy(enumerator);
if (found)
- { /* config might have changed so update everything */
- DBG1(DBG_CFG, "updating already routed CHILD_SA '%s'",
- child->get_name(child));
+ {
+ if (!found->child_sa)
+ {
+ DBG1(DBG_CFG, "CHILD_SA '%s' is already being routed", found->name);
+ this->lock->unlock(this->lock);
+ return 0;
+ }
+ /* config might have changed so update everything */
+ DBG1(DBG_CFG, "updating already routed CHILD_SA '%s'", found->name);
reqid = found->child_sa->get_reqid(found->child_sa);
}
+ INIT(entry,
+ .name = strdup(child->get_name(child)),
+ .peer_cfg = peer->get_ref(peer),
+ );
+ this->traps->insert_first(this->traps, entry);
+ /* don't hold lock while creating CHILD_SA and installing policies */
+ this->lock->unlock(this->lock);
+
/* create and route CHILD_SA */
child_sa = child_sa_create(me, other, child, reqid, FALSE);
@@ -185,24 +197,19 @@ METHOD(trap_manager_t, install, u_int32_t,
if (status != SUCCESS)
{
DBG1(DBG_CFG, "installing trap failed");
+ this->lock->write_lock(this->lock);
+ this->traps->remove(this->traps, entry, NULL);
+ this->lock->unlock(this->lock);
+ entry->child_sa = child_sa;
+ destroy_entry(entry);
reqid = 0;
- /* hold off destroying the CHILD_SA until we released the lock */
}
else
{
- INIT(entry,
- .child_sa = child_sa,
- .peer_cfg = peer->get_ref(peer),
- );
- this->traps->insert_last(this->traps, entry);
reqid = child_sa->get_reqid(child_sa);
- }
- this->installing->set(this->installing, NULL);
- this->lock->unlock(this->lock);
-
- if (status != SUCCESS)
- {
- child_sa->destroy(child_sa);
+ this->lock->write_lock(this->lock);
+ entry->child_sa = child_sa;
+ this->lock->unlock(this->lock);
}
if (found)
{
@@ -221,7 +228,8 @@ METHOD(trap_manager_t, uninstall, bool,
enumerator = this->traps->create_enumerator(this->traps);
while (enumerator->enumerate(enumerator, &entry))
{
- if (entry->child_sa->get_reqid(entry->child_sa) == reqid)
+ if (entry->child_sa &&
+ entry->child_sa->get_reqid(entry->child_sa) == reqid)
{
this->traps->remove_at(this->traps, enumerator);
found = entry;
@@ -236,7 +244,6 @@ METHOD(trap_manager_t, uninstall, bool,
DBG1(DBG_CFG, "trap %d not found to uninstall", reqid);
return FALSE;
}
-
destroy_entry(found);
return TRUE;
}
@@ -247,6 +254,10 @@ METHOD(trap_manager_t, uninstall, bool,
static bool trap_filter(rwlock_t *lock, entry_t **entry, peer_cfg_t **peer_cfg,
void *none, child_sa_t **child_sa)
{
+ if (!(*entry)->child_sa)
+ { /* skip entries that are currently being installed */
+ return FALSE;
+ }
if (peer_cfg)
{
*peer_cfg = (*entry)->peer_cfg;
@@ -271,28 +282,24 @@ METHOD(trap_manager_t, find_reqid, u_int32_t,
private_trap_manager_t *this, child_cfg_t *child)
{
enumerator_t *enumerator;
- child_cfg_t *current;
entry_t *entry;
u_int32_t reqid = 0;
- if (this->installing->get(this->installing))
- { /* current thread holds the lock */
- return reqid;
- }
this->lock->read_lock(this->lock);
enumerator = this->traps->create_enumerator(this->traps);
while (enumerator->enumerate(enumerator, &entry))
{
- current = entry->child_sa->get_config(entry->child_sa);
- if (streq(current->get_name(current), child->get_name(child)))
+ if (streq(entry->name, child->get_name(child)))
{
- reqid = entry->child_sa->get_reqid(entry->child_sa);
+ if (entry->child_sa)
+ {
+ reqid = entry->child_sa->get_reqid(entry->child_sa);
+ }
break;
}
}
enumerator->destroy(enumerator);
this->lock->unlock(this->lock);
-
return reqid;
}
@@ -310,7 +317,8 @@ METHOD(trap_manager_t, acquire, void,
enumerator = this->traps->create_enumerator(this->traps);
while (enumerator->enumerate(enumerator, &entry))
{
- if (entry->child_sa->get_reqid(entry->child_sa) == reqid)
+ if (entry->child_sa &&
+ entry->child_sa->get_reqid(entry->child_sa) == reqid)
{
found = entry;
break;
@@ -365,6 +373,7 @@ METHOD(trap_manager_t, acquire, void,
else
{
ike_sa->destroy(ike_sa);
+ charon->bus->set_sa(charon->bus, NULL);
}
}
peer->destroy(peer);
@@ -445,7 +454,6 @@ METHOD(trap_manager_t, destroy, void,
{
charon->bus->remove_listener(charon->bus, &this->listener.listener);
this->traps->destroy_function(this->traps, (void*)destroy_entry);
- this->installing->destroy(this->installing);
this->lock->destroy(this->lock);
free(this);
}
@@ -476,7 +484,6 @@ trap_manager_t *trap_manager_create(void)
},
.traps = linked_list_create(),
.lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
- .installing = thread_value_create(NULL),
);
charon->bus->add_listener(charon->bus, &this->listener.listener);
diff --git a/src/libcharon/sa/xauth/xauth_manager.c b/src/libcharon/sa/xauth/xauth_manager.c
index 17eecc2c9..3aabe7eae 100644
--- a/src/libcharon/sa/xauth/xauth_manager.c
+++ b/src/libcharon/sa/xauth/xauth_manager.c
@@ -13,6 +13,9 @@
* for more details.
*/
+#define _GNU_SOURCE /* for stdndup() */
+#include <string.h>
+
#include "xauth_manager.h"
#include <collections/linked_list.h>