diff options
author | Martin Willi <martin@revosec.ch> | 2013-09-04 10:35:26 +0200 |
---|---|---|
committer | Martin Willi <martin@revosec.ch> | 2013-09-04 10:35:26 +0200 |
commit | f7cb6eaaa88d8f43e7d65fbca5f81d9c117aa959 (patch) | |
tree | e4065153815b9eebc0e7bf2b19a8b8372b046760 | |
parent | 0b47bb5377193520d8d95fe66d6d3644abaf2307 (diff) | |
parent | a858064455bc2fda9f54889395eccee8f91fd424 (diff) | |
download | strongswan-f7cb6eaaa88d8f43e7d65fbca5f81d9c117aa959.tar.bz2 strongswan-f7cb6eaaa88d8f43e7d65fbca5f81d9c117aa959.tar.xz |
Merge branch 'ikev1-pushmode'
Implements Mode Config Push mode in IKEv1 using the existing modeconfig=push
ipsec.conf option.
23 files changed, 416 insertions, 99 deletions
diff --git a/man/ipsec.conf.5.in b/man/ipsec.conf.5.in index 4c64e86ca..61abc0a0e 100644 --- a/man/ipsec.conf.5.in +++ b/man/ipsec.conf.5.in @@ -931,8 +931,7 @@ Accepted values are and .B pull (the default). -Push mode is currently not supported in charon, hence this parameter has no -effect. +Push mode is currently not supported with IKEv2. .TP .BR reauth " = " yes " | no" whether rekeying of an IKE_SA should also reauthenticate the peer. In IKEv1, diff --git a/src/charon-cmd/cmd/cmd_connection.c b/src/charon-cmd/cmd/cmd_connection.c index 5c459f99f..a697da804 100644 --- a/src/charon-cmd/cmd/cmd_connection.c +++ b/src/charon-cmd/cmd/cmd_connection.c @@ -170,7 +170,7 @@ static peer_cfg_t* create_peer_cfg(private_cmd_connection_t *this) CERT_SEND_IF_ASKED, UNIQUE_REPLACE, 1, /* keyingtries */ 36000, 0, /* rekey 10h, reauth none */ 600, 600, /* jitter, over 10min */ - TRUE, aggressive, /* mobike, aggressive */ + TRUE, aggressive, TRUE, /* mobike, aggressive, pull */ 30, 0, /* DPD delay, timeout */ FALSE, NULL, NULL); /* mediation */ peer_cfg->add_virtual_ip(peer_cfg, host_create_from_string("0.0.0.0", 0)); diff --git a/src/charon-nm/nm/nm_service.c b/src/charon-nm/nm/nm_service.c index 901abd348..f97c11c18 100644 --- a/src/charon-nm/nm/nm_service.c +++ b/src/charon-nm/nm/nm_service.c @@ -536,7 +536,7 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection, CERT_SEND_IF_ASKED, UNIQUE_REPLACE, 1, /* keyingtries */ 36000, 0, /* rekey 10h, reauth none */ 600, 600, /* jitter, over 10min */ - TRUE, FALSE, /* mobike, aggressive */ + TRUE, FALSE, TRUE, /* mobike, aggressive, pull */ 0, 0, /* DPD delay, timeout */ FALSE, NULL, NULL); /* mediation */ if (virtual) diff --git a/src/conftest/config.c b/src/conftest/config.c index 7f05e9c72..1aa931004 100644 --- a/src/conftest/config.c +++ b/src/conftest/config.c @@ -249,8 +249,8 @@ static peer_cfg_t *load_peer_config(private_config_t *this, ike_cfg = load_ike_config(this, settings, config); peer_cfg = peer_cfg_create(config, ike_cfg, CERT_ALWAYS_SEND, - UNIQUE_NO, 1, 0, 0, 0, 0, FALSE, FALSE, 0, 0, - FALSE, NULL, NULL); + UNIQUE_NO, 1, 0, 0, 0, 0, FALSE, FALSE, TRUE, + 0, 0, FALSE, NULL, NULL); auth = auth_cfg_create(); auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY); diff --git a/src/frontends/android/jni/libandroidbridge/backend/android_service.c b/src/frontends/android/jni/libandroidbridge/backend/android_service.c index c35d348ba..59a4e14cf 100644 --- a/src/frontends/android/jni/libandroidbridge/backend/android_service.c +++ b/src/frontends/android/jni/libandroidbridge/backend/android_service.c @@ -535,7 +535,7 @@ static job_requeue_t initiate(private_android_service_t *this) UNIQUE_REPLACE, 0, /* keyingtries */ 36000, 0, /* rekey 10h, reauth none */ 600, 600, /* jitter, over 10min */ - TRUE, FALSE, /* mobike, aggressive */ + TRUE, FALSE, TRUE, /* mobike, aggressive, pull */ 0, 0, /* DPD delay, timeout */ FALSE, NULL, NULL); /* mediation */ peer_cfg->add_virtual_ip(peer_cfg, host_create_any(AF_INET)); diff --git a/src/frontends/osx/charon-xpc/xpc_dispatch.c b/src/frontends/osx/charon-xpc/xpc_dispatch.c index 0a5de15fd..0757e9baf 100644 --- a/src/frontends/osx/charon-xpc/xpc_dispatch.c +++ b/src/frontends/osx/charon-xpc/xpc_dispatch.c @@ -91,7 +91,7 @@ static peer_cfg_t* create_peer_cfg(char *name, char *host) CERT_SEND_IF_ASKED, UNIQUE_REPLACE, 1, /* keyingtries */ 36000, 0, /* rekey 10h, reauth none */ 600, 600, /* jitter, over 10min */ - TRUE, FALSE, /* mobike, aggressive */ + TRUE, FALSE, TRUE, /* mobike, aggressive, pull */ 30, 0, /* DPD delay, timeout */ FALSE, NULL, NULL); /* mediation */ peer_cfg->add_virtual_ip(peer_cfg, host_create_from_string("0.0.0.0", 0)); diff --git a/src/libcharon/config/peer_cfg.c b/src/libcharon/config/peer_cfg.c index eb983199b..d198503d0 100644 --- a/src/libcharon/config/peer_cfg.c +++ b/src/libcharon/config/peer_cfg.c @@ -100,6 +100,11 @@ struct private_peer_cfg_t { bool aggressive; /** + * Use pull or push in mode config? + */ + bool pull_mode; + + /** * Time before starting rekeying */ u_int32_t rekey_time; @@ -390,6 +395,12 @@ METHOD(peer_cfg_t, use_aggressive, bool, return this->aggressive; } +METHOD(peer_cfg_t, use_pull_mode, bool, + private_peer_cfg_t *this) +{ + return this->pull_mode; +} + METHOD(peer_cfg_t, get_dpd, u_int32_t, private_peer_cfg_t *this) { @@ -588,6 +599,7 @@ METHOD(peer_cfg_t, equals, bool, this->over_time == other->over_time && this->dpd == other->dpd && this->aggressive == other->aggressive && + this->pull_mode == other->pull_mode && auth_cfg_equal(this, other) #ifdef ME && this->mediation == other->mediation && @@ -638,8 +650,8 @@ peer_cfg_t *peer_cfg_create(char *name, unique_policy_t unique, u_int32_t keyingtries, u_int32_t rekey_time, u_int32_t reauth_time, u_int32_t jitter_time, u_int32_t over_time, - bool mobike, bool aggressive, u_int32_t dpd, - u_int32_t dpd_timeout, + bool mobike, bool aggressive, bool pull_mode, + u_int32_t dpd, u_int32_t dpd_timeout, bool mediation, peer_cfg_t *mediated_by, identification_t *peer_id) { @@ -671,6 +683,7 @@ peer_cfg_t *peer_cfg_create(char *name, .get_over_time = _get_over_time, .use_mobike = _use_mobike, .use_aggressive = _use_aggressive, + .use_pull_mode = _use_pull_mode, .get_dpd = _get_dpd, .get_dpd_timeout = _get_dpd_timeout, .add_virtual_ip = _add_virtual_ip, @@ -701,6 +714,7 @@ peer_cfg_t *peer_cfg_create(char *name, .over_time = over_time, .use_mobike = mobike, .aggressive = aggressive, + .pull_mode = pull_mode, .dpd = dpd, .dpd_timeout = dpd_timeout, .vips = linked_list_create(), diff --git a/src/libcharon/config/peer_cfg.h b/src/libcharon/config/peer_cfg.h index e62e03ec5..7e82b517f 100644 --- a/src/libcharon/config/peer_cfg.h +++ b/src/libcharon/config/peer_cfg.h @@ -248,6 +248,13 @@ struct peer_cfg_t { bool (*use_aggressive)(peer_cfg_t *this); /** + * Use pull or push mode for mode config? + * + * @return TRUE to use pull, FALSE to use push mode + */ + bool (*use_pull_mode)(peer_cfg_t *this); + + /** * Get the DPD check interval. * * @return dpd_delay in seconds @@ -366,6 +373,7 @@ struct peer_cfg_t { * @param over_time maximum overtime before closing a rekeying/reauth SA * @param mobike use MOBIKE (RFC4555) if peer supports it * @param aggressive use/accept aggressive mode with IKEv1 + * @param pullmode TRUE to use modeconfig pull, FALSE for push * @param dpd DPD check interval, 0 to disable * @param dpd_timeout DPD timeout interval (IKEv1 only), if 0 default applies * @param mediation TRUE if this is a mediation connection @@ -378,8 +386,8 @@ peer_cfg_t *peer_cfg_create(char *name, unique_policy_t unique, u_int32_t keyingtries, u_int32_t rekey_time, u_int32_t reauth_time, u_int32_t jitter_time, u_int32_t over_time, - bool mobike, bool aggressive, u_int32_t dpd, - u_int32_t dpd_timeout, + bool mobike, bool aggressive, bool pull_mode, + u_int32_t dpd, u_int32_t dpd_timeout, bool mediation, peer_cfg_t *mediated_by, identification_t *peer_id); diff --git a/src/libcharon/plugins/ha/ha_tunnel.c b/src/libcharon/plugins/ha/ha_tunnel.c index 4e656e73b..26d152c8f 100644 --- a/src/libcharon/plugins/ha/ha_tunnel.c +++ b/src/libcharon/plugins/ha/ha_tunnel.c @@ -208,8 +208,8 @@ static void setup_tunnel(private_ha_tunnel_t *this, remote, FALSE, IKEV2_UDP_PORT, FRAGMENTATION_NO, 0); ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE)); peer_cfg = peer_cfg_create("ha", ike_cfg, CERT_NEVER_SEND, - UNIQUE_KEEP, 0, 86400, 0, 7200, 3600, FALSE, FALSE, 30, - 0, FALSE, NULL, NULL); + UNIQUE_KEEP, 0, 86400, 0, 7200, 3600, FALSE, FALSE, + TRUE, 30, 0, FALSE, NULL, NULL); auth_cfg = auth_cfg_create(); auth_cfg->add(auth_cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK); diff --git a/src/libcharon/plugins/load_tester/load_tester_config.c b/src/libcharon/plugins/load_tester/load_tester_config.c index ebadf44ca..26c9871f0 100644 --- a/src/libcharon/plugins/load_tester/load_tester_config.c +++ b/src/libcharon/plugins/load_tester/load_tester_config.c @@ -561,7 +561,7 @@ static peer_cfg_t* generate_config(private_load_tester_config_t *this, uint num) CERT_SEND_IF_ASKED, UNIQUE_NO, 1, /* keytries */ this->ike_rekey, 0, /* rekey, reauth */ 0, this->ike_rekey, /* jitter, overtime */ - FALSE, FALSE, /* mobike, aggressive mode */ + FALSE, FALSE, TRUE, /* mobike, aggressive, pull */ this->dpd_delay, /* dpd_delay */ this->dpd_timeout, /* dpd_timeout */ FALSE, NULL, NULL); diff --git a/src/libcharon/plugins/maemo/maemo_service.c b/src/libcharon/plugins/maemo/maemo_service.c index d7539c2da..f04bc5a4c 100644 --- a/src/libcharon/plugins/maemo/maemo_service.c +++ b/src/libcharon/plugins/maemo/maemo_service.c @@ -334,7 +334,7 @@ static gboolean initiate_connection(private_maemo_service_t *this, UNIQUE_REPLACE, 1, /* keyingtries */ 36000, 0, /* rekey 10h, reauth none */ 600, 600, /* jitter, over 10min */ - TRUE, FALSE, /* mobike, aggressive */ + TRUE, FALSE, TRUE, /* mobike, aggressive, pull */ 0, 0, /* DPD delay, timeout */ FALSE, NULL, NULL); /* mediation */ peer_cfg->add_virtual_ip(peer_cfg, host_create_from_string("0.0.0.0", 0)); diff --git a/src/libcharon/plugins/medcli/medcli_config.c b/src/libcharon/plugins/medcli/medcli_config.c index 2bff70307..e852e3f47 100644 --- a/src/libcharon/plugins/medcli/medcli_config.c +++ b/src/libcharon/plugins/medcli/medcli_config.c @@ -112,7 +112,7 @@ METHOD(backend_t, get_peer_cfg_by_name, peer_cfg_t*, CERT_NEVER_SEND, UNIQUE_REPLACE, 1, this->rekey*60, 0, /* keytries, rekey, reauth */ this->rekey*5, this->rekey*3, /* jitter, overtime */ - TRUE, FALSE, /* mobike, aggressive */ + TRUE, FALSE, TRUE, /* mobike, aggressive, pull */ this->dpd, 0, /* DPD delay, timeout */ TRUE, NULL, NULL); /* mediation, med by, peer id */ e->destroy(e); @@ -149,7 +149,7 @@ METHOD(backend_t, get_peer_cfg_by_name, peer_cfg_t*, CERT_NEVER_SEND, UNIQUE_REPLACE, 1, this->rekey*60, 0, /* keytries, rekey, reauth */ this->rekey*5, this->rekey*3, /* jitter, overtime */ - TRUE, FALSE, /* mobike, aggressive */ + TRUE, FALSE, TRUE, /* mobike, aggressive, pull */ this->dpd, 0, /* DPD delay, timeout */ FALSE, med_cfg, /* mediation, med by */ identification_create_from_encoding(ID_KEY_ID, other)); @@ -224,7 +224,7 @@ METHOD(enumerator_t, peer_enumerator_enumerate, bool, CERT_NEVER_SEND, UNIQUE_REPLACE, 1, this->rekey*60, 0, /* keytries, rekey, reauth */ this->rekey*5, this->rekey*3, /* jitter, overtime */ - TRUE, FALSE, /* mobike, aggressive */ + TRUE, FALSE, TRUE, /* mobike, aggressive, pull */ this->dpd, 0, /* DPD delay, timeout */ FALSE, NULL, NULL); /* mediation, med by, peer id */ diff --git a/src/libcharon/plugins/medsrv/medsrv_config.c b/src/libcharon/plugins/medsrv/medsrv_config.c index 06339220a..45487a976 100644 --- a/src/libcharon/plugins/medsrv/medsrv_config.c +++ b/src/libcharon/plugins/medsrv/medsrv_config.c @@ -92,7 +92,7 @@ METHOD(backend_t, create_peer_cfg_enumerator, enumerator_t*, CERT_NEVER_SEND, UNIQUE_REPLACE, 1, this->rekey*60, 0, /* keytries, rekey, reauth */ this->rekey*5, this->rekey*3, /* jitter, overtime */ - TRUE, FALSE, /* mobike, aggressiv */ + TRUE, FALSE, TRUE, /* mobike, aggressive, pull */ this->dpd, 0, /* DPD delay, timeout */ TRUE, NULL, NULL); /* mediation, med by, peer id */ e->destroy(e); diff --git a/src/libcharon/plugins/sql/sql_config.c b/src/libcharon/plugins/sql/sql_config.c index c3471a078..e6b69a4f4 100644 --- a/src/libcharon/plugins/sql/sql_config.c +++ b/src/libcharon/plugins/sql/sql_config.c @@ -374,7 +374,7 @@ static peer_cfg_t *build_peer_cfg(private_sql_config_t *this, enumerator_t *e, peer_cfg = peer_cfg_create( name, ike, cert_policy, uniqueid, keyingtries, rekeytime, reauthtime, jitter, overtime, - mobike, FALSE, dpd_delay, 0, + mobike, FALSE, TRUE, dpd_delay, 0, mediation, mediated_cfg, peer_id); if (vip) { diff --git a/src/libcharon/plugins/stroke/stroke_config.c b/src/libcharon/plugins/stroke/stroke_config.c index 079e65f11..2e36ce3a3 100644 --- a/src/libcharon/plugins/stroke/stroke_config.c +++ b/src/libcharon/plugins/stroke/stroke_config.c @@ -731,6 +731,7 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this, msg->add_conn.me.sendcert, unique, msg->add_conn.rekey.tries, rekey, reauth, jitter, over, msg->add_conn.mobike, msg->add_conn.aggressive, + msg->add_conn.pushmode == 0, msg->add_conn.dpd.delay, msg->add_conn.dpd.timeout, msg->add_conn.ikeme.mediation, mediated_by, peer_id); @@ -780,7 +781,13 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this, enumerator->destroy(enumerator); } - if (msg->add_conn.me.sourceip) + if (msg->add_conn.me.sourceip && msg->add_conn.other.sourceip) + { + DBG1(DBG_CFG, "'%s' has both left- and rightsourceip, but IKE can " + "negotiate one virtual IP only, ignoring local virtual IP", + msg->add_conn.name); + } + else if (msg->add_conn.me.sourceip) { enumerator_t *enumerator; char *token; diff --git a/src/libcharon/plugins/uci/uci_config.c b/src/libcharon/plugins/uci/uci_config.c index b58d120c1..040d8a84f 100644 --- a/src/libcharon/plugins/uci/uci_config.c +++ b/src/libcharon/plugins/uci/uci_config.c @@ -162,7 +162,7 @@ METHOD(enumerator_t, peer_enumerator_enumerate, bool, name, ike_cfg, CERT_SEND_IF_ASKED, UNIQUE_NO, 1, create_rekey(ike_rekey), 0, /* keytries, rekey, reauth */ 1800, 900, /* jitter, overtime */ - TRUE, FALSE, /* mobike, aggressive */ + TRUE, FALSE, TRUE, /* mobike, aggressive, pull */ 60, 0, /* DPD delay, timeout */ FALSE, NULL, NULL); /* mediation, med by, peer id */ auth = auth_cfg_create(); diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c index dfceb5446..d97ef0ebe 100644 --- a/src/libcharon/sa/ikev1/task_manager_v1.c +++ b/src/libcharon/sa/ikev1/task_manager_v1.c @@ -539,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; } @@ -1087,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 { 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/starter/starterstroke.c b/src/starter/starterstroke.c index cc447c41f..f4541937b 100644 --- a/src/starter/starterstroke.c +++ b/src/starter/starterstroke.c @@ -186,6 +186,7 @@ int starter_stroke_add_conn(starter_config_t *cfg, starter_conn_t *conn) msg.add_conn.ipcomp = conn->options & SA_OPTION_COMPRESS; msg.add_conn.install_policy = conn->install_policy; msg.add_conn.aggressive = conn->aggressive; + msg.add_conn.pushmode = conn->options & SA_OPTION_MODECFG_PUSH; msg.add_conn.crl_policy = (crl_policy_t)cfg->setup.strictcrlpolicy; msg.add_conn.unique = cfg->setup.uniqueids; msg.add_conn.algorithms.ike = push_string(&msg, conn->ike); diff --git a/src/stroke/stroke_msg.h b/src/stroke/stroke_msg.h index a4dfc5e7a..6c8dcf5f9 100644 --- a/src/stroke/stroke_msg.h +++ b/src/stroke/stroke_msg.h @@ -258,6 +258,7 @@ struct stroke_msg_t { int mode; int mobike; int aggressive; + int pushmode; int force_encap; int fragmentation; int ipcomp; |