diff options
Diffstat (limited to 'src/libcharon/sa')
-rw-r--r-- | src/libcharon/sa/child_sa.c | 13 | ||||
-rw-r--r-- | src/libcharon/sa/child_sa.h | 7 | ||||
-rw-r--r-- | src/libcharon/sa/ike_sa.c | 41 | ||||
-rw-r--r-- | src/libcharon/sa/ike_sa_manager.c | 8 | ||||
-rw-r--r-- | src/libcharon/sa/ikev1/task_manager_v1.c | 19 | ||||
-rw-r--r-- | src/libcharon/sa/ikev1/tasks/aggressive_mode.c | 6 | ||||
-rw-r--r-- | src/libcharon/sa/ikev1/tasks/isakmp_vendor.c | 4 | ||||
-rw-r--r-- | src/libcharon/sa/ikev1/tasks/quick_mode.c | 2 | ||||
-rw-r--r-- | src/libcharon/sa/ikev2/keymat_v2.c | 30 | ||||
-rw-r--r-- | src/libcharon/sa/ikev2/task_manager_v2.c | 15 | ||||
-rw-r--r-- | src/libcharon/sa/ikev2/tasks/child_create.c | 4 | ||||
-rw-r--r-- | src/libcharon/sa/ikev2/tasks/ike_auth.c | 2 | ||||
-rw-r--r-- | src/libcharon/sa/ikev2/tasks/ike_cert_pre.c | 2 | ||||
-rw-r--r-- | src/libcharon/sa/ikev2/tasks/ike_vendor.c | 79 | ||||
-rw-r--r-- | src/libcharon/sa/task_manager.h | 5 | ||||
-rw-r--r-- | src/libcharon/sa/trap_manager.c | 87 | ||||
-rw-r--r-- | src/libcharon/sa/xauth/xauth_manager.c | 3 |
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> |