diff options
author | Yves-Alexis Perez <corsac@debian.org> | 2013-11-01 13:32:07 +0100 |
---|---|---|
committer | Yves-Alexis Perez <corsac@debian.org> | 2013-11-01 13:32:07 +0100 |
commit | 5313d2d78ca150515f7f5eb39801c100690b6b29 (patch) | |
tree | c78e420367283bb1b16f14210b12687cdfbd26eb /src/libcharon/sa/ikev1 | |
parent | 6b99c8d9cff7b3e8ae8f3204b99e7ea40f791349 (diff) | |
download | vyos-strongswan-5313d2d78ca150515f7f5eb39801c100690b6b29.tar.gz vyos-strongswan-5313d2d78ca150515f7f5eb39801c100690b6b29.zip |
Imported Upstream version 5.1.1
Diffstat (limited to 'src/libcharon/sa/ikev1')
-rw-r--r-- | src/libcharon/sa/ikev1/keymat_v1.c | 8 | ||||
-rw-r--r-- | src/libcharon/sa/ikev1/task_manager_v1.c | 54 | ||||
-rw-r--r-- | src/libcharon/sa/ikev1/tasks/aggressive_mode.c | 67 | ||||
-rw-r--r-- | src/libcharon/sa/ikev1/tasks/main_mode.c | 66 | ||||
-rw-r--r-- | src/libcharon/sa/ikev1/tasks/mode_config.c | 269 | ||||
-rw-r--r-- | src/libcharon/sa/ikev1/tasks/mode_config.h | 3 | ||||
-rw-r--r-- | src/libcharon/sa/ikev1/tasks/quick_delete.c | 2 | ||||
-rw-r--r-- | src/libcharon/sa/ikev1/tasks/quick_mode.c | 91 | ||||
-rw-r--r-- | src/libcharon/sa/ikev1/tasks/xauth.c | 2 |
9 files changed, 455 insertions, 107 deletions
diff --git a/src/libcharon/sa/ikev1/keymat_v1.c b/src/libcharon/sa/ikev1/keymat_v1.c index 39e4cad20..bf1b0046c 100644 --- a/src/libcharon/sa/ikev1/keymat_v1.c +++ b/src/libcharon/sa/ikev1/keymat_v1.c @@ -196,6 +196,13 @@ METHOD(aead_t, get_iv_size, size_t, return 0; } +METHOD(aead_t, get_iv_gen, iv_gen_t*, + private_aead_t *this) +{ + /* IVs are retrieved via keymat_v1.get_iv() */ + return NULL; +} + METHOD(aead_t, get_key_size, size_t, private_aead_t *this) { @@ -304,6 +311,7 @@ static aead_t *create_aead(proposal_t *proposal, prf_t *prf, chunk_t skeyid_e) .get_block_size = _get_block_size, .get_icv_size = _get_icv_size, .get_iv_size = _get_iv_size, + .get_iv_gen = _get_iv_gen, .get_key_size = _get_key_size, .set_key = _set_key, .destroy = _aead_destroy, diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c index 857cb027e..597416e36 100644 --- a/src/libcharon/sa/ikev1/task_manager_v1.c +++ b/src/libcharon/sa/ikev1/task_manager_v1.c @@ -413,7 +413,6 @@ static bool send_packet(private_task_manager_t *this, bool request, { bool use_frags = FALSE; ike_cfg_t *ike_cfg; - host_t *src, *dst; chunk_t data; ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa); @@ -438,15 +437,18 @@ static bool send_packet(private_task_manager_t *this, bool request, fragment_payload_t *fragment; u_int8_t num, count; size_t len, frag_size; - bool nat; - - /* reduce size due to non-ESP marker */ - nat = this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY); - frag_size = this->frag.size - (nat ? 4 : 0); + host_t *src, *dst; src = packet->get_source(packet); dst = packet->get_destination(packet); - count = (data.len / (frag_size + 1)) + 1; + + frag_size = this->frag.size; + if (dst->get_port(dst) != IKEV2_UDP_PORT && + src->get_port(src) != IKEV2_UDP_PORT) + { /* reduce size due to non-ESP marker */ + frag_size -= 4; + } + count = data.len / frag_size + (data.len % frag_size ? 1 : 0); DBG1(DBG_IKE, "sending IKE message with length of %zu bytes in " "%hhu fragments", data.len, count); @@ -537,23 +539,40 @@ static bool mode_config_expected(private_task_manager_t *this) enumerator_t *enumerator; peer_cfg_t *peer_cfg; char *pool; + bool local; host_t *host; peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); if (peer_cfg) { - enumerator = peer_cfg->create_pool_enumerator(peer_cfg); - if (!enumerator->enumerate(enumerator, &pool)) - { /* no pool configured */ + if (peer_cfg->use_pull_mode(peer_cfg)) + { + enumerator = peer_cfg->create_pool_enumerator(peer_cfg); + if (!enumerator->enumerate(enumerator, &pool)) + { /* no pool configured */ + enumerator->destroy(enumerator); + return FALSE; + } enumerator->destroy(enumerator); - return FALSE; + + local = FALSE; } - enumerator->destroy(enumerator); + else + { + enumerator = peer_cfg->create_virtual_ip_enumerator(peer_cfg); + if (!enumerator->enumerate(enumerator, &host)) + { /* not requesting a vip */ + enumerator->destroy(enumerator); + return FALSE; + } + enumerator->destroy(enumerator); + local = TRUE; + } enumerator = this->ike_sa->create_virtual_ip_enumerator(this->ike_sa, - FALSE); + local); if (!enumerator->enumerate(enumerator, &host)) - { /* have a pool, but no VIP assigned yet */ + { /* expecting a VIP exchange, but no VIP assigned yet */ enumerator->destroy(enumerator); return TRUE; } @@ -1085,7 +1104,8 @@ static status_t process_request(private_task_manager_t *this, case TRANSACTION: if (this->ike_sa->get_state(this->ike_sa) != IKE_CONNECTING) { - task = (task_t *)mode_config_create(this->ike_sa, FALSE); + task = (task_t *)mode_config_create(this->ike_sa, + FALSE, TRUE); } else { @@ -1253,7 +1273,7 @@ static status_t handle_fragment(private_task_manager_t *this, message_t *msg) return FAILED; } - if (this->frag.id != payload->get_id(payload)) + if (!this->frag.list || this->frag.id != payload->get_id(payload)) { clear_fragments(this, payload->get_id(payload)); this->frag.list = linked_list_create(); @@ -1765,7 +1785,7 @@ static bool have_equal_ts(child_sa_t *child1, child_sa_t *child2, bool local) { equal = ts1->equals(ts1, ts2); } - e1->destroy(e1); + e2->destroy(e2); e1->destroy(e1); return equal; diff --git a/src/libcharon/sa/ikev1/tasks/aggressive_mode.c b/src/libcharon/sa/ikev1/tasks/aggressive_mode.c index 6b00706bf..46cbb879b 100644 --- a/src/libcharon/sa/ikev1/tasks/aggressive_mode.c +++ b/src/libcharon/sa/ikev1/tasks/aggressive_mode.c @@ -196,6 +196,17 @@ static status_t send_delete(private_aggressive_mode_t *this) return ALREADY_DONE; } +/** + * Schedule a timeout for the IKE_SA should it not establish + */ +static void schedule_timeout(ike_sa_t *ike_sa) +{ + job_t *job; + + job = (job_t*)delete_ike_sa_job_create(ike_sa->get_id(ike_sa), FALSE); + lib->scheduler->schedule_job(lib->scheduler, job, HALF_OPEN_IKE_SA_TIMEOUT); +} + METHOD(task_t, build_i, status_t, private_aggressive_mode_t *this, message_t *message) { @@ -300,20 +311,15 @@ METHOD(task_t, build_i, status_t, case AUTH_XAUTH_INIT_PSK: case AUTH_XAUTH_INIT_RSA: case AUTH_HYBRID_INIT_RSA: - { /* wait for XAUTH request, since this may never come, - * we queue a timeout */ - job_t *job = (job_t*)delete_ike_sa_job_create( - this->ike_sa->get_id(this->ike_sa), FALSE); - lib->scheduler->schedule_job(lib->scheduler, job, - HALF_OPEN_IKE_SA_TIMEOUT); + /* wait for XAUTH request */ + schedule_timeout(this->ike_sa); break; - } case AUTH_XAUTH_RESP_PSK: case AUTH_XAUTH_RESP_RSA: case AUTH_HYBRID_RESP_RSA: this->ike_sa->queue_task(this->ike_sa, (task_t*)xauth_create(this->ike_sa, TRUE)); - return SUCCESS; + break; default: if (charon->ike_sa_manager->check_uniqueness( charon->ike_sa_manager, this->ike_sa, FALSE)) @@ -328,10 +334,30 @@ METHOD(task_t, build_i, status_t, } break; } + /* check for and prepare mode config push/pull */ if (this->ph1->has_virtual_ip(this->ph1, this->peer_cfg)) { - this->ike_sa->queue_task(this->ike_sa, - (task_t*)mode_config_create(this->ike_sa, TRUE)); + if (this->peer_cfg->use_pull_mode(this->peer_cfg)) + { + this->ike_sa->queue_task(this->ike_sa, + (task_t*)mode_config_create(this->ike_sa, TRUE, TRUE)); + } + else + { + schedule_timeout(this->ike_sa); + } + } + else if (this->ph1->has_pool(this->ph1, this->peer_cfg)) + { + if (this->peer_cfg->use_pull_mode(this->peer_cfg)) + { + schedule_timeout(this->ike_sa); + } + else + { + this->ike_sa->queue_task(this->ike_sa, + (task_t*)mode_config_create(this->ike_sa, TRUE, FALSE)); + } } return SUCCESS; } @@ -482,7 +508,7 @@ METHOD(task_t, process_r, status_t, case AUTH_HYBRID_INIT_RSA: this->ike_sa->queue_task(this->ike_sa, (task_t*)xauth_create(this->ike_sa, TRUE)); - return SUCCESS; + break; case AUTH_XAUTH_RESP_PSK: case AUTH_XAUTH_RESP_RSA: case AUTH_HYBRID_RESP_RSA: @@ -505,11 +531,22 @@ METHOD(task_t, process_r, status_t, this->ike_sa->get_id(this->ike_sa))); break; } - if (!this->ph1->has_pool(this->ph1, this->peer_cfg) && - this->ph1->has_virtual_ip(this->ph1, this->peer_cfg)) + /* check for and prepare mode config push/pull */ + if (this->ph1->has_virtual_ip(this->ph1, this->peer_cfg)) { - this->ike_sa->queue_task(this->ike_sa, - (task_t*)mode_config_create(this->ike_sa, TRUE)); + if (this->peer_cfg->use_pull_mode(this->peer_cfg)) + { + this->ike_sa->queue_task(this->ike_sa, + (task_t*)mode_config_create(this->ike_sa, TRUE, TRUE)); + } + } + else if (this->ph1->has_pool(this->ph1, this->peer_cfg)) + { + if (!this->peer_cfg->use_pull_mode(this->peer_cfg)) + { + this->ike_sa->queue_task(this->ike_sa, + (task_t*)mode_config_create(this->ike_sa, TRUE, FALSE)); + } } return SUCCESS; } diff --git a/src/libcharon/sa/ikev1/tasks/main_mode.c b/src/libcharon/sa/ikev1/tasks/main_mode.c index 441bd7a78..81638169a 100644 --- a/src/libcharon/sa/ikev1/tasks/main_mode.c +++ b/src/libcharon/sa/ikev1/tasks/main_mode.c @@ -504,7 +504,7 @@ METHOD(task_t, build_r, status_t, case AUTH_HYBRID_INIT_RSA: this->ike_sa->queue_task(this->ike_sa, (task_t*)xauth_create(this->ike_sa, TRUE)); - return SUCCESS; + break; case AUTH_XAUTH_RESP_PSK: case AUTH_XAUTH_RESP_RSA: case AUTH_HYBRID_RESP_RSA: @@ -527,11 +527,21 @@ METHOD(task_t, build_r, status_t, this->ike_sa->get_id(this->ike_sa))); break; } - if (!this->ph1->has_pool(this->ph1, this->peer_cfg) && - this->ph1->has_virtual_ip(this->ph1, this->peer_cfg)) + if (this->ph1->has_virtual_ip(this->ph1, this->peer_cfg)) + { + if (this->peer_cfg->use_pull_mode(this->peer_cfg)) + { + this->ike_sa->queue_task(this->ike_sa, + (task_t*)mode_config_create(this->ike_sa, TRUE, TRUE)); + } + } + else if (this->ph1->has_pool(this->ph1, this->peer_cfg)) { - this->ike_sa->queue_task(this->ike_sa, - (task_t*)mode_config_create(this->ike_sa, TRUE)); + if (!this->peer_cfg->use_pull_mode(this->peer_cfg)) + { + this->ike_sa->queue_task(this->ike_sa, + (task_t*)mode_config_create(this->ike_sa, TRUE, FALSE)); + } } return SUCCESS; } @@ -540,6 +550,17 @@ METHOD(task_t, build_r, status_t, } } +/** + * Schedule a timeout for the IKE_SA should it not establish + */ +static void schedule_timeout(ike_sa_t *ike_sa) +{ + job_t *job; + + job = (job_t*)delete_ike_sa_job_create(ike_sa->get_id(ike_sa), FALSE); + lib->scheduler->schedule_job(lib->scheduler, job, HALF_OPEN_IKE_SA_TIMEOUT); +} + METHOD(task_t, process_i, status_t, private_main_mode_t *this, message_t *message) { @@ -639,20 +660,15 @@ METHOD(task_t, process_i, status_t, case AUTH_XAUTH_INIT_PSK: case AUTH_XAUTH_INIT_RSA: case AUTH_HYBRID_INIT_RSA: - { /* wait for XAUTH request, since this may never come, - * we queue a timeout */ - job_t *job = (job_t*)delete_ike_sa_job_create( - this->ike_sa->get_id(this->ike_sa), FALSE); - lib->scheduler->schedule_job(lib->scheduler, job, - HALF_OPEN_IKE_SA_TIMEOUT); + /* wait for XAUTH request */ + schedule_timeout(this->ike_sa); break; - } case AUTH_XAUTH_RESP_PSK: case AUTH_XAUTH_RESP_RSA: case AUTH_HYBRID_RESP_RSA: this->ike_sa->queue_task(this->ike_sa, (task_t*)xauth_create(this->ike_sa, TRUE)); - return SUCCESS; + break; default: if (charon->ike_sa_manager->check_uniqueness( charon->ike_sa_manager, this->ike_sa, FALSE)) @@ -667,10 +683,30 @@ METHOD(task_t, process_i, status_t, } break; } + /* check for and prepare mode config push/pull */ if (this->ph1->has_virtual_ip(this->ph1, this->peer_cfg)) { - this->ike_sa->queue_task(this->ike_sa, - (task_t*)mode_config_create(this->ike_sa, TRUE)); + if (this->peer_cfg->use_pull_mode(this->peer_cfg)) + { + this->ike_sa->queue_task(this->ike_sa, + (task_t*)mode_config_create(this->ike_sa, TRUE, TRUE)); + } + else + { + schedule_timeout(this->ike_sa); + } + } + else if (this->ph1->has_pool(this->ph1, this->peer_cfg)) + { + if (this->peer_cfg->use_pull_mode(this->peer_cfg)) + { + schedule_timeout(this->ike_sa); + } + else + { + this->ike_sa->queue_task(this->ike_sa, + (task_t*)mode_config_create(this->ike_sa, TRUE, FALSE)); + } } return SUCCESS; } diff --git a/src/libcharon/sa/ikev1/tasks/mode_config.c b/src/libcharon/sa/ikev1/tasks/mode_config.c index ce897727a..17fe02538 100644 --- a/src/libcharon/sa/ikev1/tasks/mode_config.c +++ b/src/libcharon/sa/ikev1/tasks/mode_config.c @@ -42,14 +42,19 @@ struct private_mode_config_t { bool initiator; /** + * Use pull (CFG_REQUEST/RESPONSE) or push (CFG_SET/ACK)? + */ + bool pull; + + /** * Received list of virtual IPs, host_t* */ linked_list_t *vips; /** - * list of attributes requested and its handler, entry_t + * Requested/received list of attributes, entry_t */ - linked_list_t *requested; + linked_list_t *attributes; /** * Identifier to include in response @@ -58,12 +63,12 @@ struct private_mode_config_t { }; /** - * Entry for a requested attribute and the requesting handler + * Entry for a attribute and associated handler */ typedef struct { - /** attribute requested */ + /** attribute type */ configuration_attribute_type_t type; - /** handler requesting this attribute */ + /** handler for this attribute */ attribute_handler_t *handler; } entry_t; @@ -117,13 +122,13 @@ static void handle_attribute(private_mode_config_t *this, entry_t *entry; /* find the handler which requested this attribute */ - enumerator = this->requested->create_enumerator(this->requested); + enumerator = this->attributes->create_enumerator(this->attributes); while (enumerator->enumerate(enumerator, &entry)) { if (entry->type == ca->get_type(ca)) { handler = entry->handler; - this->requested->remove_at(this->requested, enumerator); + this->attributes->remove_at(this->attributes, enumerator); free(entry); break; } @@ -180,7 +185,7 @@ static void process_attribute(private_mode_config_t *this, } default: { - if (this->initiator) + if (this->initiator == this->pull) { handle_attribute(this, ca); } @@ -189,6 +194,24 @@ static void process_attribute(private_mode_config_t *this, } /** + * Check if config allows push mode when acting as task responder + */ +static bool accept_push(private_mode_config_t *this) +{ + enumerator_t *enumerator; + peer_cfg_t *config; + bool vip; + host_t *host; + + config = this->ike_sa->get_peer_cfg(this->ike_sa); + enumerator = config->create_virtual_ip_enumerator(config); + vip = enumerator->enumerate(enumerator, &host); + enumerator->destroy(enumerator); + + return vip && !config->use_pull_mode(config); +} + +/** * Scan for configuration payloads and attributes */ static void process_payloads(private_mode_config_t *this, message_t *message) @@ -206,6 +229,15 @@ static void process_payloads(private_mode_config_t *this, message_t *message) switch (cp->get_type(cp)) { + case CFG_SET: + /* when acting as a responder, we detect the mode using + * the type of configuration payload. But we should double + * check the peer is allowed to use push mode on us. */ + if (!this->initiator && accept_push(this)) + { + this->pull = FALSE; + } + /* FALL */ case CFG_REQUEST: this->identifier = cp->get_identifier(cp); /* FALL */ @@ -219,6 +251,8 @@ static void process_payloads(private_mode_config_t *this, message_t *message) } attributes->destroy(attributes); break; + case CFG_ACK: + break; default: DBG1(DBG_IKE, "ignoring %N config payload", config_type_names, cp->get_type(cp)); @@ -229,8 +263,29 @@ static void process_payloads(private_mode_config_t *this, message_t *message) enumerator->destroy(enumerator); } -METHOD(task_t, build_i, status_t, - private_mode_config_t *this, message_t *message) +/** + * Add an attribute to a configuration payload, and store it in task + */ +static void add_attribute(private_mode_config_t *this, cp_payload_t *cp, + configuration_attribute_type_t type, chunk_t data, + attribute_handler_t *handler) +{ + entry_t *entry; + + cp->add_attribute(cp, + configuration_attribute_create_chunk(CONFIGURATION_ATTRIBUTE_V1, + type, data)); + INIT(entry, + .type = type, + .handler = handler, + ); + this->attributes->insert_last(this->attributes, entry); +} + +/** + * Build a CFG_REQUEST as initiator + */ +static status_t build_request(private_mode_config_t *this, message_t *message) { cp_payload_t *cp; enumerator_t *enumerator; @@ -279,18 +334,7 @@ METHOD(task_t, build_i, status_t, this->ike_sa->get_other_id(this->ike_sa), vips); while (enumerator->enumerate(enumerator, &handler, &type, &data)) { - entry_t *entry; - - DBG2(DBG_IKE, "building %N attribute", - configuration_attribute_type_names, type); - cp->add_attribute(cp, - configuration_attribute_create_chunk(CONFIGURATION_ATTRIBUTE_V1, - type, data)); - INIT(entry, - .type = type, - .handler = handler, - ); - this->requested->insert_last(this->requested, entry); + add_attribute(this, cp, type, data, handler); } enumerator->destroy(enumerator); @@ -301,15 +345,121 @@ METHOD(task_t, build_i, status_t, return NEED_MORE; } +/** + * Build a CFG_SET as initiator + */ +static status_t build_set(private_mode_config_t *this, message_t *message) +{ + enumerator_t *enumerator; + configuration_attribute_type_t type; + chunk_t value; + cp_payload_t *cp; + peer_cfg_t *config; + identification_t *id; + linked_list_t *pools; + host_t *any4, *any6, *found; + char *name; + + cp = cp_payload_create_type(CONFIGURATION_V1, CFG_SET); + + id = this->ike_sa->get_other_eap_id(this->ike_sa); + config = this->ike_sa->get_peer_cfg(this->ike_sa); + any4 = host_create_any(AF_INET); + any6 = host_create_any(AF_INET6); + + this->ike_sa->clear_virtual_ips(this->ike_sa, FALSE); + + /* in push mode, we ask each configured pool for an address */ + enumerator = config->create_pool_enumerator(config); + while (enumerator->enumerate(enumerator, &name)) + { + pools = linked_list_create_with_items(name, NULL); + /* try IPv4, then IPv6 */ + found = hydra->attributes->acquire_address(hydra->attributes, + pools, id, any4); + if (!found) + { + found = hydra->attributes->acquire_address(hydra->attributes, + pools, id, any6); + } + pools->destroy(pools); + if (found) + { + DBG1(DBG_IKE, "assigning virtual IP %H to peer '%Y'", found, id); + this->ike_sa->add_virtual_ip(this->ike_sa, FALSE, found); + cp->add_attribute(cp, build_vip(found)); + this->vips->insert_last(this->vips, found); + } + } + enumerator->destroy(enumerator); + + any4->destroy(any4); + any6->destroy(any6); + + /* query registered providers for additional attributes to include */ + pools = linked_list_create_from_enumerator( + config->create_pool_enumerator(config)); + enumerator = hydra->attributes->create_responder_enumerator( + hydra->attributes, pools, id, this->vips); + while (enumerator->enumerate(enumerator, &type, &value)) + { + add_attribute(this, cp, type, value, NULL); + } + enumerator->destroy(enumerator); + pools->destroy(pools); + + message->add_payload(message, (payload_t*)cp); + + return SUCCESS; +} + +METHOD(task_t, build_i, status_t, + private_mode_config_t *this, message_t *message) +{ + if (this->pull) + { + return build_request(this, message); + } + return build_set(this, message); +} + +/** + * Store received virtual IPs to the IKE_SA, install them + */ +static void install_vips(private_mode_config_t *this) +{ + enumerator_t *enumerator; + host_t *host; + + this->ike_sa->clear_virtual_ips(this->ike_sa, TRUE); + + enumerator = this->vips->create_enumerator(this->vips); + while (enumerator->enumerate(enumerator, &host)) + { + if (!host->is_anyaddr(host)) + { + this->ike_sa->add_virtual_ip(this->ike_sa, TRUE, host); + } + } + enumerator->destroy(enumerator); +} + METHOD(task_t, process_r, status_t, private_mode_config_t *this, message_t *message) { process_payloads(this, message); + + if (!this->pull) + { + install_vips(this); + } return NEED_MORE; } -METHOD(task_t, build_r, status_t, - private_mode_config_t *this, message_t *message) +/** + * Build CFG_REPLY message after receiving CFG_REQUEST + */ +static status_t build_reply(private_mode_config_t *this, message_t *message) { enumerator_t *enumerator; configuration_attribute_type_t type; @@ -360,8 +510,6 @@ METHOD(task_t, build_r, status_t, hydra->attributes, pools, id, vips); while (enumerator->enumerate(enumerator, &type, &value)) { - DBG2(DBG_IKE, "building %N attribute", - configuration_attribute_type_names, type); cp->add_attribute(cp, configuration_attribute_create_chunk(CONFIGURATION_ATTRIBUTE_V1, type, value)); @@ -376,26 +524,72 @@ METHOD(task_t, build_r, status_t, return SUCCESS; } -METHOD(task_t, process_i, status_t, - private_mode_config_t *this, message_t *message) +/** + * Build CFG_ACK for a received CFG_SET + */ +static status_t build_ack(private_mode_config_t *this, message_t *message) { + cp_payload_t *cp; enumerator_t *enumerator; host_t *host; + configuration_attribute_type_t type; + entry_t *entry; - process_payloads(this, message); + cp = cp_payload_create_type(CONFIGURATION_V1, CFG_ACK); - this->ike_sa->clear_virtual_ips(this->ike_sa, TRUE); + /* return empty attributes for installed IPs */ enumerator = this->vips->create_enumerator(this->vips); while (enumerator->enumerate(enumerator, &host)) { - if (!host->is_anyaddr(host)) + type = INTERNAL_IP6_ADDRESS; + if (host->get_family(host) == AF_INET6) { - this->ike_sa->add_virtual_ip(this->ike_sa, TRUE, host); + type = INTERNAL_IP6_ADDRESS; } + else + { + type = INTERNAL_IP4_ADDRESS; + } + cp->add_attribute(cp, configuration_attribute_create_chunk( + CONFIGURATION_ATTRIBUTE_V1, type, chunk_empty)); } enumerator->destroy(enumerator); + enumerator = this->attributes->create_enumerator(this->attributes); + while (enumerator->enumerate(enumerator, &entry)) + { + cp->add_attribute(cp, + configuration_attribute_create_chunk(CONFIGURATION_ATTRIBUTE_V1, + entry->type, chunk_empty)); + } + enumerator->destroy(enumerator); + + cp->set_identifier(cp, this->identifier); + message->add_payload(message, (payload_t*)cp); + + return SUCCESS; +} + +METHOD(task_t, build_r, status_t, + private_mode_config_t *this, message_t *message) +{ + if (this->pull) + { + return build_reply(this, message); + } + return build_ack(this, message); +} + +METHOD(task_t, process_i, status_t, + private_mode_config_t *this, message_t *message) +{ + process_payloads(this, message); + + if (this->pull) + { + install_vips(this); + } return SUCCESS; } @@ -411,22 +605,22 @@ METHOD(task_t, migrate, void, this->ike_sa = ike_sa; this->vips->destroy_offset(this->vips, offsetof(host_t, destroy)); this->vips = linked_list_create(); - this->requested->destroy_function(this->requested, free); - this->requested = linked_list_create(); + this->attributes->destroy_function(this->attributes, free); + this->attributes = linked_list_create(); } METHOD(task_t, destroy, void, private_mode_config_t *this) { this->vips->destroy_offset(this->vips, offsetof(host_t, destroy)); - this->requested->destroy_function(this->requested, free); + this->attributes->destroy_function(this->attributes, free); free(this); } /* * Described in header. */ -mode_config_t *mode_config_create(ike_sa_t *ike_sa, bool initiator) +mode_config_t *mode_config_create(ike_sa_t *ike_sa, bool initiator, bool pull) { private_mode_config_t *this; @@ -439,8 +633,9 @@ mode_config_t *mode_config_create(ike_sa_t *ike_sa, bool initiator) }, }, .initiator = initiator, + .pull = initiator ? pull : TRUE, .ike_sa = ike_sa, - .requested = linked_list_create(), + .attributes = linked_list_create(), .vips = linked_list_create(), ); diff --git a/src/libcharon/sa/ikev1/tasks/mode_config.h b/src/libcharon/sa/ikev1/tasks/mode_config.h index 462bee374..c2da7a086 100644 --- a/src/libcharon/sa/ikev1/tasks/mode_config.h +++ b/src/libcharon/sa/ikev1/tasks/mode_config.h @@ -43,8 +43,9 @@ struct mode_config_t { * * @param ike_sa IKE_SA this task works for * @param initiator TRUE for initiator + * @param pull TRUE to pull, FALSE to push (applies if initiator only) * @return mode_config task to handle by the task_manager */ -mode_config_t *mode_config_create(ike_sa_t *ike_sa, bool initiator); +mode_config_t *mode_config_create(ike_sa_t *ike_sa, bool initiator, bool pull); #endif /** MODE_CONFIG_H_ @}*/ diff --git a/src/libcharon/sa/ikev1/tasks/quick_delete.c b/src/libcharon/sa/ikev1/tasks/quick_delete.c index 1a2cdb777..605c10cea 100644 --- a/src/libcharon/sa/ikev1/tasks/quick_delete.c +++ b/src/libcharon/sa/ikev1/tasks/quick_delete.c @@ -177,7 +177,7 @@ METHOD(task_t, build_i, status_t, DBG1(DBG_IKE, "sending DELETE for %N CHILD_SA with SPI %.8x", protocol_id_names, this->protocol, ntohl(this->spi)); - delete_payload = delete_payload_create(DELETE_V1, PROTO_ESP); + delete_payload = delete_payload_create(DELETE_V1, this->protocol); delete_payload->add_spi(delete_payload, this->spi); message->add_payload(message, &delete_payload->payload_interface); diff --git a/src/libcharon/sa/ikev1/tasks/quick_mode.c b/src/libcharon/sa/ikev1/tasks/quick_mode.c index 6271e5b05..12ee594b9 100644 --- a/src/libcharon/sa/ikev1/tasks/quick_mode.c +++ b/src/libcharon/sa/ikev1/tasks/quick_mode.c @@ -165,6 +165,11 @@ struct private_quick_mode_t { */ ipsec_mode_t mode; + /* + * SA protocol (ESP|AH) negotiated + */ + protocol_id_t proto; + /** * Use UDP encapsulation */ @@ -722,7 +727,7 @@ static status_t send_notify(private_quick_mode_t *this, notify_type_t type) notify_payload_t *notify; notify = notify_payload_create_from_protocol_and_type(NOTIFY_V1, - PROTO_ESP, type); + this->proto, type); notify->set_spi(notify, this->spi_i); this->ike_sa->queue_task(this->ike_sa, @@ -733,6 +738,38 @@ static status_t send_notify(private_quick_mode_t *this, notify_type_t type) return ALREADY_DONE; } +/** + * Prepare a list of proposals from child_config containing only the specified + * DH group, unless it is set to MODP_NONE. + */ +static linked_list_t *get_proposals(private_quick_mode_t *this, + diffie_hellman_group_t group) +{ + linked_list_t *list; + proposal_t *proposal; + enumerator_t *enumerator; + + list = this->config->get_proposals(this->config, FALSE); + enumerator = list->create_enumerator(list); + while (enumerator->enumerate(enumerator, &proposal)) + { + if (group != MODP_NONE) + { + if (!proposal->has_dh_group(proposal, group)) + { + list->remove_at(list, enumerator); + proposal->destroy(proposal); + continue; + } + proposal->strip_dh(proposal, group); + } + proposal->set_spi(proposal, this->spi_i); + } + enumerator->destroy(enumerator); + + return list; +} + METHOD(task_t, build_i, status_t, private_quick_mode_t *this, message_t *message) { @@ -740,7 +777,6 @@ METHOD(task_t, build_i, status_t, { case QM_INIT: { - enumerator_t *enumerator; sa_payload_t *sa_payload; linked_list_t *list, *tsi, *tsr; proposal_t *proposal; @@ -770,42 +806,55 @@ METHOD(task_t, build_i, status_t, } } - this->spi_i = this->child_sa->alloc_spi(this->child_sa, PROTO_ESP); + list = this->config->get_proposals(this->config, MODP_NONE); + if (list->get_first(list, (void**)&proposal) == SUCCESS) + { + this->proto = proposal->get_protocol(proposal); + } + list->destroy_offset(list, offsetof(proposal_t, destroy)); + this->spi_i = this->child_sa->alloc_spi(this->child_sa, this->proto); if (!this->spi_i) { DBG1(DBG_IKE, "allocating SPI from kernel failed"); return FAILED; } + group = this->config->get_dh_group(this->config); if (group != MODP_NONE) { + proposal_t *proposal; + u_int16_t preferred_group; + + proposal = this->ike_sa->get_proposal(this->ike_sa); + proposal->get_algorithm(proposal, DIFFIE_HELLMAN_GROUP, + &preferred_group, NULL); + /* try the negotiated DH group from IKE_SA */ + list = get_proposals(this, preferred_group); + if (list->get_count(list)) + { + group = preferred_group; + } + else + { + /* fall back to the first configured DH group */ + list->destroy(list); + list = get_proposals(this, group); + } + this->dh = this->keymat->keymat.create_dh(&this->keymat->keymat, group); if (!this->dh) { DBG1(DBG_IKE, "configured DH group %N not supported", diffie_hellman_group_names, group); + list->destroy_offset(list, offsetof(proposal_t, destroy)); return FAILED; } } - - list = this->config->get_proposals(this->config, FALSE); - enumerator = list->create_enumerator(list); - while (enumerator->enumerate(enumerator, &proposal)) + else { - if (group != MODP_NONE) - { - if (!proposal->has_dh_group(proposal, group)) - { - list->remove_at(list, enumerator); - proposal->destroy(proposal); - continue; - } - proposal->strip_dh(proposal, group); - } - proposal->set_spi(proposal, this->spi_i); + list = get_proposals(this, MODP_NONE); } - enumerator->destroy(enumerator); get_lifetimes(this); encap = get_encap(this->ike_sa, this->udp); @@ -1103,7 +1152,8 @@ METHOD(task_t, build_r, status_t, sa_payload_t *sa_payload; encap_t encap; - this->spi_r = this->child_sa->alloc_spi(this->child_sa, PROTO_ESP); + this->proto = this->proposal->get_protocol(this->proposal); + this->spi_r = this->child_sa->alloc_spi(this->child_sa, this->proto); if (!this->spi_r) { DBG1(DBG_IKE, "allocating SPI from kernel failed"); @@ -1311,6 +1361,7 @@ quick_mode_t *quick_mode_create(ike_sa_t *ike_sa, child_cfg_t *config, .state = QM_INIT, .tsi = tsi ? tsi->clone(tsi) : NULL, .tsr = tsr ? tsr->clone(tsr) : NULL, + .proto = PROTO_ESP, ); if (config) diff --git a/src/libcharon/sa/ikev1/tasks/xauth.c b/src/libcharon/sa/ikev1/tasks/xauth.c index 31114e592..f5555ecd2 100644 --- a/src/libcharon/sa/ikev1/tasks/xauth.c +++ b/src/libcharon/sa/ikev1/tasks/xauth.c @@ -127,7 +127,7 @@ static xauth_method_t *load_method(private_xauth_t* this) { if (name) { - DBG1(DBG_CFG, "no XAuth method found named '%s'", name); + DBG1(DBG_CFG, "no XAuth method found for '%s'", name); } else { |