diff options
author | Martin Willi <martin@revosec.ch> | 2012-08-21 13:50:32 +0200 |
---|---|---|
committer | Martin Willi <martin@revosec.ch> | 2012-08-30 16:43:42 +0200 |
commit | 101d26babeae0a6444bf7a355cbd3fb2e7497fae (patch) | |
tree | a6b6d2e9561d7a43c79203d69c11cac77a44f76e | |
parent | d8eec395b22cc890c6f38236392753c6c80b5cc6 (diff) | |
download | strongswan-101d26babeae0a6444bf7a355cbd3fb2e7497fae.tar.bz2 strongswan-101d26babeae0a6444bf7a355cbd3fb2e7497fae.tar.xz |
Support multiple virtual IPs on peer_cfg and ike_sa classes
34 files changed, 447 insertions, 264 deletions
diff --git a/src/charon-nm/nm/nm_service.c b/src/charon-nm/nm/nm_service.c index ccfa210a0..2eef51acc 100644 --- a/src/charon-nm/nm/nm_service.c +++ b/src/charon-nm/nm/nm_service.c @@ -507,8 +507,11 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection, 600, 600, /* jitter, over 10min */ TRUE, FALSE, /* mobike, aggressive */ 0, 0, /* DPD delay, timeout */ - virtual ? host_create_from_string("0.0.0.0", 0) : NULL, NULL, FALSE, NULL, NULL); /* pool, mediation */ + if (virtual) + { + peer_cfg->add_virtual_ip(peer_cfg, host_create_from_string("0.0.0.0", 0)); + } auth = auth_cfg_create(); auth->add(auth, AUTH_RULE_AUTH_CLASS, auth_class); auth->add(auth, AUTH_RULE_IDENTITY, user); diff --git a/src/conftest/config.c b/src/conftest/config.c index a3f23f3a4..61f3760f0 100644 --- a/src/conftest/config.c +++ b/src/conftest/config.c @@ -253,7 +253,7 @@ 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, IKEV2, ike_cfg, CERT_ALWAYS_SEND, UNIQUE_NO, 1, 0, 0, 0, 0, FALSE, FALSE, 0, 0, - NULL, NULL, FALSE, NULL, NULL); + NULL, 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 dfc0d2342..d472301db 100644 --- a/src/frontends/android/jni/libandroidbridge/backend/android_service.c +++ b/src/frontends/android/jni/libandroidbridge/backend/android_service.c @@ -235,21 +235,36 @@ static bool setup_tun_device(private_android_service_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa) { vpnservice_builder_t *builder; + enumerator_t *enumerator; + bool vip_found = FALSE; host_t *vip; int tunfd; DBG1(DBG_DMN, "setting up TUN device for CHILD_SA %s{%u}", child_sa->get_name(child_sa), child_sa->get_reqid(child_sa)); - vip = ike_sa->get_virtual_ip(ike_sa, TRUE); - if (!vip || vip->is_anyaddr(vip)) + + builder = charonservice->get_vpnservice_builder(charonservice); + + enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, TRUE); + while (enumerator->enumerate(enumerator, &vip)) + { + if (!vip->is_anyaddr(vip)) + { + if (!builder->add_address(builder, vip)) + { + break; + } + vip_found = TRUE; + } + } + enumerator->destroy(enumerator); + + if (!vip_found) { DBG1(DBG_DMN, "setting up TUN device failed, no virtual IP found"); return FALSE; } - - builder = charonservice->get_vpnservice_builder(charonservice); - if (!builder->add_address(builder, vip) || - !add_routes(builder, child_sa) || + if (!add_routes(builder, child_sa) || !builder->set_mtu(builder, TUN_DEFAULT_MTU)) { return FALSE; @@ -427,9 +442,8 @@ static job_requeue_t initiate(private_android_service_t *this) 600, 600, /* jitter, over 10min */ TRUE, FALSE, /* mobike, aggressive */ 0, 0, /* DPD delay, timeout */ - host_create_from_string("0.0.0.0", 0) /* virt */, NULL, FALSE, NULL, NULL); /* pool, mediation */ - + peer_cfg->add_virtual_ip(peer_cfg, host_create_from_string("0.0.0.0", 0)); auth = auth_cfg_create(); auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP); diff --git a/src/libcharon/config/peer_cfg.c b/src/libcharon/config/peer_cfg.c index d16aedc79..091176a25 100644 --- a/src/libcharon/config/peer_cfg.c +++ b/src/libcharon/config/peer_cfg.c @@ -141,9 +141,9 @@ struct private_peer_cfg_t { u_int32_t dpd_timeout; /** - * virtual IP to use locally + * List of virtual IPs (host_t*) to request */ - host_t *virtual_ip; + linked_list_t *vips; /** * pool to acquire configuration attributes from @@ -409,10 +409,16 @@ METHOD(peer_cfg_t, get_dpd_timeout, u_int32_t, return this->dpd_timeout; } -METHOD(peer_cfg_t, get_virtual_ip, host_t*, +METHOD(peer_cfg_t, add_virtual_ip, void, + private_peer_cfg_t *this, host_t *vip) +{ + this->vips->insert_last(this->vips, vip); +} + +METHOD(peer_cfg_t, create_virtual_ip_enumerator, enumerator_t*, private_peer_cfg_t *this) { - return this->virtual_ip; + return this->vips->create_enumerator(this->vips); } METHOD(peer_cfg_t, get_pool, char*, @@ -521,6 +527,9 @@ static bool auth_cfg_equal(private_peer_cfg_t *this, private_peer_cfg_t *other) METHOD(peer_cfg_t, equals, bool, private_peer_cfg_t *this, private_peer_cfg_t *other) { + enumerator_t *e1, *e2; + host_t *vip1, *vip2; + if (this == other) { return TRUE; @@ -530,6 +539,24 @@ METHOD(peer_cfg_t, equals, bool, return FALSE; } + if (this->vips->get_count(this->vips) != other->vips->get_count(other->vips)) + { + return FALSE; + } + e1 = create_virtual_ip_enumerator(this); + e2 = create_virtual_ip_enumerator(other); + if (e1->enumerate(e1, &vip1) && e2->enumerate(e2, &vip2)) + { + if (!vip1->ip_equals(vip1, vip2)) + { + e1->destroy(e1); + e2->destroy(e2); + return FALSE; + } + } + e1->destroy(e1); + e2->destroy(e2); + return ( this->ike_version == other->ike_version && this->cert_policy == other->cert_policy && @@ -541,9 +568,6 @@ METHOD(peer_cfg_t, equals, bool, this->jitter_time == other->jitter_time && this->over_time == other->over_time && this->dpd == other->dpd && - (this->virtual_ip == other->virtual_ip || - (this->virtual_ip && other->virtual_ip && - this->virtual_ip->equals(this->virtual_ip, other->virtual_ip))) && (this->pool == other->pool || (this->pool && other->pool && streq(this->pool, other->pool))) && auth_cfg_equal(this, other) @@ -572,11 +596,11 @@ METHOD(peer_cfg_t, destroy, void, this->ike_cfg->destroy(this->ike_cfg); this->child_cfgs->destroy_offset(this->child_cfgs, offsetof(child_cfg_t, destroy)); - DESTROY_IF(this->virtual_ip); this->local_auth->destroy_offset(this->local_auth, offsetof(auth_cfg_t, destroy)); this->remote_auth->destroy_offset(this->remote_auth, offsetof(auth_cfg_t, destroy)); + this->vips->destroy_offset(this->vips, offsetof(host_t, destroy)); #ifdef ME DESTROY_IF(this->mediated_by); DESTROY_IF(this->peer_id); @@ -597,8 +621,8 @@ peer_cfg_t *peer_cfg_create(char *name, ike_version_t ike_version, 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, host_t *virtual_ip, - char *pool, bool mediation, peer_cfg_t *mediated_by, + u_int32_t dpd_timeout, char *pool, + bool mediation, peer_cfg_t *mediated_by, identification_t *peer_id) { private_peer_cfg_t *this; @@ -631,7 +655,8 @@ peer_cfg_t *peer_cfg_create(char *name, ike_version_t ike_version, .use_aggressive = _use_aggressive, .get_dpd = _get_dpd, .get_dpd_timeout = _get_dpd_timeout, - .get_virtual_ip = _get_virtual_ip, + .add_virtual_ip = _add_virtual_ip, + .create_virtual_ip_enumerator = _create_virtual_ip_enumerator, .get_pool = _get_pool, .add_auth_cfg = _add_auth_cfg, .create_auth_cfg_enumerator = _create_auth_cfg_enumerator, @@ -660,7 +685,7 @@ peer_cfg_t *peer_cfg_create(char *name, ike_version_t ike_version, .aggressive = aggressive, .dpd = dpd, .dpd_timeout = dpd_timeout, - .virtual_ip = virtual_ip, + .vips = linked_list_create(), .pool = strdupnull(pool), .local_auth = linked_list_create(), .remote_auth = linked_list_create(), diff --git a/src/libcharon/config/peer_cfg.h b/src/libcharon/config/peer_cfg.h index 572153505..fd924dc2c 100644 --- a/src/libcharon/config/peer_cfg.h +++ b/src/libcharon/config/peer_cfg.h @@ -278,16 +278,20 @@ struct peer_cfg_t { u_int32_t (*get_dpd_timeout) (peer_cfg_t *this); /** - * Get a virtual IP for the local peer. + * Add a virtual IP to request as initiator. * - * If no virtual IP should be used, NULL is returned. %any means to request - * a virtual IP using configuration payloads. A specific address is also - * used for a request and may be changed by the server. + * @param vip virtual IP to request, may be %any or %any6 + */ + void (*add_virtual_ip)(peer_cfg_t *this, host_t *vip); + + /** + * Create an enumerator over virtual IPs to request. + * + * The returned enumerator enumerates over IPs added with add_virtual_ip(). * - * @param suggestion NULL, %any or specific - * @return virtual IP, %any or NULL + * @return enumerator over host_t* */ - host_t* (*get_virtual_ip) (peer_cfg_t *this); + enumerator_t* (*create_virtual_ip_enumerator)(peer_cfg_t *this); /** * Get the name of the pool to acquire configuration attributes from. @@ -374,7 +378,6 @@ struct peer_cfg_t { * @param aggressive use/accept aggressive mode with IKEv1 * @param dpd DPD check interval, 0 to disable * @param dpd_timeout DPD timeout interval (IKEv1 only), if 0 default applies - * @param virtual_ip virtual IP for local host, or NULL * @param pool pool name to get configuration attributes from, or NULL * @param mediation TRUE if this is a mediation connection * @param mediated_by peer_cfg_t of the mediation connection to mediate through @@ -387,8 +390,8 @@ peer_cfg_t *peer_cfg_create(char *name, ike_version_t ike_version, 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, host_t *virtual_ip, - char *pool, bool mediation, peer_cfg_t *mediated_by, + u_int32_t dpd_timeout, char *pool, + bool mediation, peer_cfg_t *mediated_by, identification_t *peer_id); #endif /** PEER_CFG_H_ @}*/ diff --git a/src/libcharon/plugins/android/android_service.c b/src/libcharon/plugins/android/android_service.c index f2d8ddce9..1236e4534 100644 --- a/src/libcharon/plugins/android/android_service.c +++ b/src/libcharon/plugins/android/android_service.c @@ -275,8 +275,8 @@ static job_requeue_t initiate(private_android_service_t *this) 600, 600, /* jitter, over 10min */ TRUE, FALSE, /* mobike, aggressive */ 0, 0, /* DPD delay, timeout */ - host_create_from_string("0.0.0.0", 0) /* virt */, NULL, FALSE, NULL, NULL); /* pool, mediation */ + peer_cfg->add_virtual_ip(peer_cfg, host_create_from_string("0.0.0.0", 0)); auth = auth_cfg_create(); auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP); diff --git a/src/libcharon/plugins/eap_radius/eap_radius_accounting.c b/src/libcharon/plugins/eap_radius/eap_radius_accounting.c index 243c76304..7690cf9f8 100644 --- a/src/libcharon/plugins/eap_radius/eap_radius_accounting.c +++ b/src/libcharon/plugins/eap_radius/eap_radius_accounting.c @@ -149,6 +149,7 @@ static bool send_message(private_eap_radius_accounting_t *this, */ static void add_ike_sa_parameters(radius_message_t *message, ike_sa_t *ike_sa) { + enumerator_t *enumerator; host_t *vip; char buf[64]; chunk_t data; @@ -157,17 +158,25 @@ static void add_ike_sa_parameters(radius_message_t *message, ike_sa_t *ike_sa) message->add(message, RAT_USER_NAME, chunk_create(buf, strlen(buf))); snprintf(buf, sizeof(buf), "%#H", ike_sa->get_other_host(ike_sa)); message->add(message, RAT_CALLING_STATION_ID, chunk_create(buf, strlen(buf))); - vip = ike_sa->get_virtual_ip(ike_sa, FALSE); - if (vip && vip->get_family(vip) == AF_INET) - { - message->add(message, RAT_FRAMED_IP_ADDRESS, vip->get_address(vip)); - } - if (vip && vip->get_family(vip) == AF_INET6) + + enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, FALSE); + while (enumerator->enumerate(enumerator, &vip)) { - /* we currently assign /128 prefixes, only (reserved, length) */ - data = chunk_from_chars(0, 128); - data = chunk_cata("cc", data, vip->get_address(vip)); - message->add(message, RAT_FRAMED_IPV6_PREFIX, data); + switch (vip->get_family(vip)) + { + case AF_INET: + message->add(message, RAT_FRAMED_IP_ADDRESS, + vip->get_address(vip)); + break; + case AF_INET6: + /* we currently assign /128 prefixes, only (reserved, length) */ + data = chunk_from_chars(0, 128); + data = chunk_cata("cc", data, vip->get_address(vip)); + message->add(message, RAT_FRAMED_IPV6_PREFIX, data); + break; + default: + break; + } } } diff --git a/src/libcharon/plugins/ha/ha_dispatcher.c b/src/libcharon/plugins/ha/ha_dispatcher.c index 8b6ec9180..8516f4f3e 100644 --- a/src/libcharon/plugins/ha/ha_dispatcher.c +++ b/src/libcharon/plugins/ha/ha_dispatcher.c @@ -344,10 +344,10 @@ static void process_ike_update(private_ha_dispatcher_t *this, ike_sa->set_other_host(ike_sa, value.host->clone(value.host)); break; case HA_LOCAL_VIP: - ike_sa->set_virtual_ip(ike_sa, TRUE, value.host); + ike_sa->add_virtual_ip(ike_sa, TRUE, value.host); break; case HA_REMOTE_VIP: - ike_sa->set_virtual_ip(ike_sa, FALSE, value.host); + ike_sa->add_virtual_ip(ike_sa, FALSE, value.host); received_vip = TRUE; break; case HA_PEER_ADDR: @@ -417,13 +417,18 @@ static void process_ike_update(private_ha_dispatcher_t *this, char *pool; peer_cfg = ike_sa->get_peer_cfg(ike_sa); - vip = ike_sa->get_virtual_ip(ike_sa, FALSE); - if (peer_cfg && vip) + if (peer_cfg) { pool = peer_cfg->get_pool(peer_cfg); if (pool) { - this->attr->reserve(this->attr, pool, vip); + enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, + FALSE); + while (enumerator->enumerate(enumerator, &vip)) + { + this->attr->reserve(this->attr, pool, vip); + } + enumerator->destroy(enumerator); } } } diff --git a/src/libcharon/plugins/ha/ha_ike.c b/src/libcharon/plugins/ha/ha_ike.c index d523e8919..442a3a23d 100644 --- a/src/libcharon/plugins/ha/ha_ike.c +++ b/src/libcharon/plugins/ha/ha_ike.c @@ -241,6 +241,34 @@ METHOD(listener_t, ike_state_change, bool, return TRUE; } +/** + * Send a virtual IP sync message for remote VIPs + */ +static void sync_vips(private_ha_ike_t *this, ike_sa_t *ike_sa) +{ + ha_message_t *m = NULL; + enumerator_t *enumerator; + host_t *vip; + + enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, FALSE); + while (enumerator->enumerate(enumerator, &vip)) + { + if (!m) + { + m = ha_message_create(HA_IKE_UPDATE); + m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa)); + } + m->add_attribute(m, HA_REMOTE_VIP, vip); + } + enumerator->destroy(enumerator); + + if (m) + { + this->socket->push(this->socket, m); + this->cache->cache(this->cache, ike_sa, m); + } +} + METHOD(listener_t, message_hook, bool, private_ha_ike_t *this, ike_sa_t *ike_sa, message_t *message, bool incoming, bool plain) @@ -276,18 +304,7 @@ METHOD(listener_t, message_hook, bool, { /* After IKE_SA has been established, sync peers virtual IP. * We cannot sync it in the state_change hook, it is installed later. * TODO: where to sync local VIP? */ - ha_message_t *m; - host_t *vip; - - vip = ike_sa->get_virtual_ip(ike_sa, FALSE); - if (vip) - { - m = ha_message_create(HA_IKE_UPDATE); - m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa)); - m->add_attribute(m, HA_REMOTE_VIP, vip); - this->socket->push(this->socket, m); - this->cache->cache(this->cache, ike_sa, m); - } + sync_vips(this, ike_sa); } } if (!plain && ike_sa->get_version(ike_sa) == IKEV1) @@ -296,7 +313,6 @@ METHOD(listener_t, message_hook, bool, keymat_v1_t *keymat; u_int32_t mid; chunk_t iv; - host_t *vip; mid = message->get_message_id(message); if (mid == 0) @@ -313,15 +329,7 @@ METHOD(listener_t, message_hook, bool, } if (!incoming && message->get_exchange_type(message) == TRANSACTION) { - vip = ike_sa->get_virtual_ip(ike_sa, FALSE); - if (vip) - { - m = ha_message_create(HA_IKE_UPDATE); - m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa)); - m->add_attribute(m, HA_REMOTE_VIP, vip); - this->socket->push(this->socket, m); - this->cache->cache(this->cache, ike_sa, m); - } + sync_vips(this, ike_sa); } } if (plain && ike_sa->get_version(ike_sa) == IKEV1 && diff --git a/src/libcharon/plugins/ha/ha_tunnel.c b/src/libcharon/plugins/ha/ha_tunnel.c index ad458caad..15ba28e1d 100644 --- a/src/libcharon/plugins/ha/ha_tunnel.c +++ b/src/libcharon/plugins/ha/ha_tunnel.c @@ -209,7 +209,7 @@ static void setup_tunnel(private_ha_tunnel_t *this, ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE)); peer_cfg = peer_cfg_create("ha", IKEV2, ike_cfg, CERT_NEVER_SEND, UNIQUE_KEEP, 0, 86400, 0, 7200, 3600, FALSE, FALSE, 30, - 0, NULL, NULL, FALSE, NULL, NULL); + 0, NULL, 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 f5da8b892..09e220b2d 100644 --- a/src/libcharon/plugins/load_tester/load_tester_config.c +++ b/src/libcharon/plugins/load_tester/load_tester_config.c @@ -268,8 +268,11 @@ static peer_cfg_t* generate_config(private_load_tester_config_t *this, uint num) FALSE, FALSE, /* mobike, aggressive mode */ this->dpd_delay, /* dpd_delay */ this->dpd_timeout, /* dpd_timeout */ - this->vip ? this->vip->clone(this->vip) : NULL, this->pool, FALSE, NULL, NULL); + if (this->vip) + { + peer_cfg->add_virtual_ip(peer_cfg, this->vip->clone(this->vip)); + } if (num) { /* initiator */ generate_auth_cfg(this, this->initiator_auth, peer_cfg, TRUE, num); diff --git a/src/libcharon/plugins/maemo/maemo_service.c b/src/libcharon/plugins/maemo/maemo_service.c index f638a81b7..e8718b954 100644 --- a/src/libcharon/plugins/maemo/maemo_service.c +++ b/src/libcharon/plugins/maemo/maemo_service.c @@ -335,8 +335,8 @@ static gboolean initiate_connection(private_maemo_service_t *this, 600, 600, /* jitter, over 10min */ TRUE, FALSE, /* mobike, aggressive */ 0, 0, /* DPD delay, timeout */ - host_create_from_string("0.0.0.0", 0) /* virt */, NULL, FALSE, NULL, NULL); /* pool, mediation */ + peer_cfg->add_virtual_ip(peer_cfg, host_create_from_string("0.0.0.0", 0)); auth = auth_cfg_create(); auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP); diff --git a/src/libcharon/plugins/medcli/medcli_config.c b/src/libcharon/plugins/medcli/medcli_config.c index 829c8f05e..f44ff39fe 100644 --- a/src/libcharon/plugins/medcli/medcli_config.c +++ b/src/libcharon/plugins/medcli/medcli_config.c @@ -129,7 +129,7 @@ METHOD(backend_t, get_peer_cfg_by_name, peer_cfg_t*, this->rekey*5, this->rekey*3, /* jitter, overtime */ TRUE, FALSE, /* mobike, aggressive */ this->dpd, 0, /* DPD delay, timeout */ - NULL, NULL, /* vip, pool */ + NULL, /* pool */ TRUE, NULL, NULL); /* mediation, med by, peer id */ e->destroy(e); @@ -167,7 +167,7 @@ METHOD(backend_t, get_peer_cfg_by_name, peer_cfg_t*, this->rekey*5, this->rekey*3, /* jitter, overtime */ TRUE, FALSE, /* mobike, aggressive */ this->dpd, 0, /* DPD delay, timeout */ - NULL, NULL, /* vip, pool */ + NULL, /* pool */ FALSE, med_cfg, /* mediation, med by */ identification_create_from_encoding(ID_KEY_ID, other)); @@ -243,7 +243,7 @@ METHOD(enumerator_t, peer_enumerator_enumerate, bool, this->rekey*5, this->rekey*3, /* jitter, overtime */ TRUE, FALSE, /* mobike, aggressive */ this->dpd, 0, /* DPD delay, timeout */ - NULL, NULL, /* vip, pool */ + NULL, /* pool */ FALSE, NULL, NULL); /* mediation, med by, peer id */ auth = auth_cfg_create(); diff --git a/src/libcharon/plugins/medsrv/medsrv_config.c b/src/libcharon/plugins/medsrv/medsrv_config.c index ebc142de2..edbf9cc88 100644 --- a/src/libcharon/plugins/medsrv/medsrv_config.c +++ b/src/libcharon/plugins/medsrv/medsrv_config.c @@ -94,7 +94,7 @@ METHOD(backend_t, create_peer_cfg_enumerator, enumerator_t*, this->rekey*5, this->rekey*3, /* jitter, overtime */ TRUE, FALSE, /* mobike, aggressiv */ this->dpd, 0, /* DPD delay, timeout */ - NULL, NULL, /* vip, pool */ + NULL, /* pool */ 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 890077157..343d6e40c 100644 --- a/src/libcharon/plugins/sql/sql_config.c +++ b/src/libcharon/plugins/sql/sql_config.c @@ -371,8 +371,12 @@ static peer_cfg_t *build_peer_cfg(private_sql_config_t *this, enumerator_t *e, peer_cfg = peer_cfg_create( name, IKEV2, ike, cert_policy, uniqueid, keyingtries, rekeytime, reauthtime, jitter, overtime, - mobike, FALSE, dpd_delay, 0, vip, pool, + mobike, FALSE, dpd_delay, 0, pool, mediation, mediated_cfg, peer_id); + if (vip) + { + peer_cfg->add_virtual_ip(peer_cfg, vip); + } auth = auth_cfg_create(); auth->add(auth, AUTH_RULE_AUTH_CLASS, auth_method); auth->add(auth, AUTH_RULE_IDENTITY, local_id); diff --git a/src/libcharon/plugins/stroke/stroke_config.c b/src/libcharon/plugins/stroke/stroke_config.c index bf93f2c34..e3ea5428a 100644 --- a/src/libcharon/plugins/stroke/stroke_config.c +++ b/src/libcharon/plugins/stroke/stroke_config.c @@ -778,9 +778,13 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this, msg->add_conn.rekey.tries, rekey, reauth, jitter, over, msg->add_conn.mobike, msg->add_conn.aggressive, msg->add_conn.dpd.delay, msg->add_conn.dpd.timeout, - vip, msg->add_conn.other.sourceip_mask ? + msg->add_conn.other.sourceip_mask ? msg->add_conn.name : msg->add_conn.other.sourceip, msg->add_conn.ikeme.mediation, mediated_by, peer_id); + if (vip) + { + peer_cfg->add_virtual_ip(peer_cfg, vip); + } /* build leftauth= */ auth_cfg = build_auth_cfg(this, msg, TRUE, TRUE); diff --git a/src/libcharon/plugins/stroke/stroke_control.c b/src/libcharon/plugins/stroke/stroke_control.c index 163a2a750..233d4088f 100644 --- a/src/libcharon/plugins/stroke/stroke_control.c +++ b/src/libcharon/plugins/stroke/stroke_control.c @@ -407,10 +407,10 @@ METHOD(stroke_control_t, rekey, void, METHOD(stroke_control_t, terminate_srcip, void, private_stroke_control_t *this, stroke_msg_t *msg, FILE *out) { - enumerator_t *enumerator; + enumerator_t *enumerator, *vips; ike_sa_t *ike_sa; host_t *start = NULL, *end = NULL, *vip; - chunk_t chunk_start, chunk_end = chunk_empty, chunk_vip; + chunk_t chunk_start, chunk_end = chunk_empty, chunk; if (msg->terminate_srcip.start) { @@ -438,33 +438,40 @@ METHOD(stroke_control_t, terminate_srcip, void, charon->controller, TRUE); while (enumerator->enumerate(enumerator, &ike_sa)) { - vip = ike_sa->get_virtual_ip(ike_sa, FALSE); - if (!vip) - { - continue; - } - if (!end) + bool match = FALSE; + + vips = ike_sa->create_virtual_ip_enumerator(ike_sa, FALSE); + while (vips->enumerate(vips, &vip)) { - if (!vip->ip_equals(vip, start)) + if (!end) { - continue; + if (vip->ip_equals(vip, start)) + { + match = TRUE; + break; + } } - } - else - { - chunk_vip = vip->get_address(vip); - if (chunk_vip.len != chunk_start.len || - chunk_vip.len != chunk_end.len || - memcmp(chunk_vip.ptr, chunk_start.ptr, chunk_vip.len) < 0 || - memcmp(chunk_vip.ptr, chunk_end.ptr, chunk_vip.len) > 0) + else { - continue; + chunk = vip->get_address(vip); + if (chunk.len == chunk_start.len && + chunk.len == chunk_end.len && + memcmp(chunk.ptr, chunk_start.ptr, chunk.len) >= 0 && + memcmp(chunk.ptr, chunk_end.ptr, chunk.len) <= 0) + { + match = TRUE; + break; + } } } + vips->destroy(vips); - /* schedule delete asynchronously */ - lib->processor->queue_job(lib->processor, (job_t*) + if (match) + { + /* schedule delete asynchronously */ + lib->processor->queue_job(lib->processor, (job_t*) delete_ike_sa_job_create(ike_sa->get_id(ike_sa), TRUE)); + } } enumerator->destroy(enumerator); start->destroy(start); diff --git a/src/libcharon/plugins/uci/uci_config.c b/src/libcharon/plugins/uci/uci_config.c index 5b698b8b2..140cbea60 100644 --- a/src/libcharon/plugins/uci/uci_config.c +++ b/src/libcharon/plugins/uci/uci_config.c @@ -178,7 +178,7 @@ METHOD(enumerator_t, peer_enumerator_enumerate, bool, 1800, 900, /* jitter, overtime */ TRUE, FALSE, /* mobike, aggressive */ 60, 0, /* DPD delay, timeout */ - NULL, NULL, /* vip, pool */ + NULL, /* pool */ FALSE, NULL, NULL); /* mediation, med by, peer id */ auth = auth_cfg_create(); auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK); diff --git a/src/libcharon/plugins/updown/updown_listener.c b/src/libcharon/plugins/updown/updown_listener.c index 944c46c6c..2f9f2ef91 100644 --- a/src/libcharon/plugins/updown/updown_listener.c +++ b/src/libcharon/plugins/updown/updown_listener.c @@ -134,6 +134,46 @@ static char *make_dns_vars(private_updown_listener_t *this, ike_sa_t *ike_sa) return strdup(total); } +/** + * Create variables for local virtual IPs + */ +static char *make_vip_vars(private_updown_listener_t *this, ike_sa_t *ike_sa) +{ + enumerator_t *enumerator; + host_t *host; + int v4 = 0, v6 = 0; + char total[512] = "", current[64]; + bool first = TRUE; + + enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, TRUE); + while (enumerator->enumerate(enumerator, &host)) + { + if (first) + { /* legacy variable for first VIP */ + snprintf(current, sizeof(current), + "PLUTO_MY_SOURCEIP='%H' ", host); + strncat(total, current, sizeof(total) - strlen(total) - 1); + } + switch (host->get_family(host)) + { + case AF_INET: + snprintf(current, sizeof(current), + "PLUTO_MY_SOURCEIP4_%d='%H' ", ++v4, host); + break; + case AF_INET6: + snprintf(current, sizeof(current), + "PLUTO_MY_SOURCEIP6_%d='%H' ", ++v6, host); + break; + default: + continue; + } + strncat(total, current, sizeof(total) - strlen(total) - 1); + } + enumerator->destroy(enumerator); + + return strdup(total); +} + METHOD(listener_t, child_updown, bool, private_updown_listener_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa, bool up) @@ -141,11 +181,10 @@ METHOD(listener_t, child_updown, bool, traffic_selector_t *my_ts, *other_ts; enumerator_t *enumerator; child_cfg_t *config; - host_t *vip, *me, *other; + host_t *me, *other; char *script; config = child_sa->get_config(child_sa); - vip = ike_sa->get_virtual_ip(ike_sa, TRUE); script = config->get_updown(config); me = ike_sa->get_my_host(ike_sa); other = ike_sa->get_other_host(ike_sa); @@ -169,20 +208,7 @@ METHOD(listener_t, child_updown, bool, my_ts->to_subnet(my_ts, &my_client, &my_client_mask); other_ts->to_subnet(other_ts, &other_client, &other_client_mask); - if (vip) - { - if (asprintf(&virtual_ip, "PLUTO_MY_SOURCEIP='%H' ", vip) < 0) - { - virtual_ip = NULL; - } - } - else - { - if (asprintf(&virtual_ip, "") < 0) - { - virtual_ip = NULL; - } - } + virtual_ip = make_vip_vars(this, ike_sa); /* check for the presence of an inbound mark */ mark = config->get_mark(config, TRUE); diff --git a/src/libcharon/processing/jobs/migrate_job.c b/src/libcharon/processing/jobs/migrate_job.c index 57f344980..2ebfc6714 100644 --- a/src/libcharon/processing/jobs/migrate_job.c +++ b/src/libcharon/processing/jobs/migrate_job.c @@ -79,9 +79,10 @@ METHOD(job_t, execute, job_requeue_t, } if (ike_sa) { - enumerator_t *children; + enumerator_t *children, *enumerator; child_sa_t *child_sa; host_t *host; + linked_list_t *vips; children = ike_sa->create_child_sa_enumerator(ike_sa); while (children->enumerate(children, (void**)&child_sa)) @@ -104,14 +105,22 @@ METHOD(job_t, execute, job_requeue_t, host->set_port(host, IKEV2_UDP_PORT); ike_sa->set_other_host(ike_sa, host); - if (child_sa->update(child_sa, this->local, this->remote, - ike_sa->get_virtual_ip(ike_sa, TRUE), + vips = linked_list_create(); + enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, TRUE); + while (enumerator->enumerate(enumerator, &host)) + { + vips->insert_last(vips, host); + } + enumerator->destroy(enumerator); + + if (child_sa->update(child_sa, this->local, this->remote, vips, ike_sa->has_condition(ike_sa, COND_NAT_ANY)) == NOT_SUPPORTED) { ike_sa->rekey_child_sa(ike_sa, child_sa->get_protocol(child_sa), child_sa->get_spi(child_sa, TRUE)); } charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + vips->destroy(vips); } else { diff --git a/src/libcharon/sa/child_sa.c b/src/libcharon/sa/child_sa.c index d5adb2527..c3fbd8b53 100644 --- a/src/libcharon/sa/child_sa.c +++ b/src/libcharon/sa/child_sa.c @@ -819,9 +819,18 @@ METHOD(child_sa_t, add_policies, status_t, return status; } +/** + * Callback to reinstall a virtual IP + */ +static void reinstall_vip(host_t *vip, host_t *me) +{ + hydra->kernel_interface->del_ip(hydra->kernel_interface, vip); + hydra->kernel_interface->add_ip(hydra->kernel_interface, vip, me); +} + METHOD(child_sa_t, update, status_t, - private_child_sa_t *this, host_t *me, host_t *other, host_t *vip, - bool encap) + private_child_sa_t *this, host_t *me, host_t *other, linked_list_t *vips, + bool encap) { child_sa_state_t old; bool transport_proxy_mode; @@ -927,13 +936,7 @@ METHOD(child_sa_t, update, status_t, /* we reinstall the virtual IP to handle interface roaming * correctly */ - if (vip) - { - hydra->kernel_interface->del_ip(hydra->kernel_interface, - vip); - hydra->kernel_interface->add_ip(hydra->kernel_interface, - vip, me); - } + vips->invoke_function(vips, (void*)reinstall_vip, me); /* reinstall updated policies */ install_policies_internal(this, me, other, my_ts, other_ts, diff --git a/src/libcharon/sa/child_sa.h b/src/libcharon/sa/child_sa.h index 712a4765c..dae3f2c18 100644 --- a/src/libcharon/sa/child_sa.h +++ b/src/libcharon/sa/child_sa.h @@ -346,12 +346,12 @@ struct child_sa_t { * * @param me the new local host * @param other the new remote host - * @param vip virtual IP, if any + * @param vips list of local virtual IPs * @param TRUE to use UDP encapsulation for NAT traversal * @return SUCCESS or FAILED */ status_t (*update)(child_sa_t *this, host_t *me, host_t *other, - host_t *vip, bool encap); + linked_list_t *vips, bool encap); /** * Destroys a child_sa. */ diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 1e3d00f02..26e65b2bb 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -182,14 +182,14 @@ struct private_ike_sa_t { keymat_t *keymat; /** - * Virtual IP on local host, if any + * Virtual IPs on local host */ - host_t *my_virtual_ip; + linked_list_t *my_vips; /** - * Virtual IP on remote host, if any + * Virtual IPs on remote host */ - host_t *other_virtual_ip; + linked_list_t *other_vips; /** * List of configuration attributes (attribute_entry_t) @@ -735,7 +735,7 @@ METHOD(ike_sa_t, get_keymat, keymat_t*, return this->keymat; } -METHOD(ike_sa_t, set_virtual_ip, void, +METHOD(ike_sa_t, add_virtual_ip, void, private_ike_sa_t *this, bool local, host_t *ip) { if (local) @@ -744,39 +744,27 @@ METHOD(ike_sa_t, set_virtual_ip, void, if (hydra->kernel_interface->add_ip(hydra->kernel_interface, ip, this->my_host) == SUCCESS) { - if (this->my_virtual_ip) - { - DBG1(DBG_IKE, "removing old virtual IP %H", this->my_virtual_ip); - hydra->kernel_interface->del_ip(hydra->kernel_interface, - this->my_virtual_ip); - } - DESTROY_IF(this->my_virtual_ip); - this->my_virtual_ip = ip->clone(ip); + this->my_vips->insert_last(this->my_vips, ip->clone(ip)); } else { DBG1(DBG_IKE, "installing virtual IP %H failed", ip); - this->my_virtual_ip = NULL; } } else { - DESTROY_IF(this->other_virtual_ip); - this->other_virtual_ip = ip->clone(ip); + this->other_vips->insert_last(this->other_vips, ip->clone(ip)); } } -METHOD(ike_sa_t, get_virtual_ip, host_t*, +METHOD(ike_sa_t, create_virtual_ip_enumerator, enumerator_t*, private_ike_sa_t *this, bool local) { if (local) { - return this->my_virtual_ip; - } - else - { - return this->other_virtual_ip; + return this->my_vips->create_enumerator(this->my_vips); } + return this->other_vips->create_enumerator(this->other_vips); } METHOD(ike_sa_t, add_peer_address, void, @@ -909,7 +897,7 @@ METHOD(ike_sa_t, update_hosts, void, while (enumerator->enumerate(enumerator, (void**)&child_sa)) { if (child_sa->update(child_sa, this->my_host, - this->other_host, this->my_virtual_ip, + this->other_host, this->my_vips, has_condition(this, COND_NAT_ANY)) == NOT_SUPPORTED) { this->public.rekey_child_sa(&this->public, @@ -1458,7 +1446,7 @@ METHOD(ike_sa_t, reauth, status_t, if (!has_condition(this, COND_ORIGINAL_INITIATOR)) { DBG1(DBG_IKE, "initiator did not reauthenticate as requested"); - if (this->other_virtual_ip != NULL || + if (this->other_vips->get_count(this->other_vips) != 0 || has_condition(this, COND_XAUTH_AUTHENTICATED) || has_condition(this, COND_EAP_AUTHENTICATED) #ifdef ME @@ -1562,7 +1550,7 @@ METHOD(ike_sa_t, reestablish, status_t, /* check if we are able to reestablish this IKE_SA */ if (!has_condition(this, COND_ORIGINAL_INITIATOR) && - (this->other_virtual_ip != NULL || + (this->other_vips->get_count(this->other_vips) != 0 || has_condition(this, COND_EAP_AUTHENTICATED) #ifdef ME || this->is_mediation_server @@ -1585,11 +1573,12 @@ METHOD(ike_sa_t, reestablish, status_t, host = this->my_host; new->set_my_host(new, host->clone(host)); /* if we already have a virtual IP, we reuse it */ - host = this->my_virtual_ip; - if (host) + enumerator = this->my_vips->create_enumerator(this->my_vips); + while (enumerator->enumerate(enumerator, &host)) { - new->set_virtual_ip(new, TRUE, host); + new->add_virtual_ip(new, TRUE, host); } + enumerator->destroy(enumerator); #ifdef ME if (this->peer_cfg->is_mediation(this->peer_cfg)) @@ -1732,7 +1721,7 @@ METHOD(ike_sa_t, set_auth_lifetime, status_t, * We send the notify in IKE_AUTH if not yet ESTABLISHED. */ send_update = this->state == IKE_ESTABLISHED && this->version == IKEV2 && !has_condition(this, COND_ORIGINAL_INITIATOR) && - (this->other_virtual_ip != NULL || + (this->other_vips->get_count(this->other_vips) != 0 || has_condition(this, COND_EAP_AUTHENTICATED)); if (lifetime < diff) @@ -1937,6 +1926,7 @@ METHOD(ike_sa_t, inherit, void, attribute_entry_t *entry; enumerator_t *enumerator; auth_cfg_t *cfg; + host_t *vip; /* apply hosts and ids */ this->my_host->destroy(this->my_host); @@ -1948,16 +1938,15 @@ METHOD(ike_sa_t, inherit, void, this->my_id = other->my_id->clone(other->my_id); this->other_id = other->other_id->clone(other->other_id); - /* apply virtual assigned IPs... */ - if (other->my_virtual_ip) + /* apply assigned virtual IPs... */ + while (this->my_vips->remove_last(this->my_vips, (void**)&vip) == SUCCESS) { - this->my_virtual_ip = other->my_virtual_ip; - other->my_virtual_ip = NULL; + other->my_vips->insert_first(other->my_vips, vip); } - if (other->other_virtual_ip) + while (this->other_vips->remove_last(this->other_vips, + (void**)&vip) == SUCCESS) { - this->other_virtual_ip = other->other_virtual_ip; - other->other_virtual_ip = NULL; + other->other_vips->insert_first(other->other_vips, vip); } /* authentication information */ @@ -2032,6 +2021,7 @@ METHOD(ike_sa_t, destroy, void, private_ike_sa_t *this) { attribute_entry_t *entry; + host_t *vip; charon->bus->set_sa(charon->bus, &this->public); @@ -2056,22 +2046,24 @@ METHOD(ike_sa_t, destroy, void, DESTROY_IF(this->keymat); - if (this->my_virtual_ip) + while (this->my_vips->remove_last(this->my_vips, (void**)&vip) == SUCCESS) { - hydra->kernel_interface->del_ip(hydra->kernel_interface, - this->my_virtual_ip); - this->my_virtual_ip->destroy(this->my_virtual_ip); + hydra->kernel_interface->del_ip(hydra->kernel_interface, vip); + vip->destroy(vip); } - if (this->other_virtual_ip) + this->my_vips->destroy(this->my_vips); + while (this->other_vips->remove_last(this->other_vips, + (void**)&vip) == SUCCESS) { if (this->peer_cfg && this->peer_cfg->get_pool(this->peer_cfg)) { hydra->attributes->release_address(hydra->attributes, this->peer_cfg->get_pool(this->peer_cfg), - this->other_virtual_ip, get_other_eap_id(this)); + vip, get_other_eap_id(this)); } - this->other_virtual_ip->destroy(this->other_virtual_ip); + vip->destroy(vip); } + this->other_vips->destroy(this->other_vips); this->peer_addresses->destroy_offset(this->peer_addresses, offsetof(host_t, destroy)); #ifdef ME @@ -2190,8 +2182,8 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator, .generate_message = _generate_message, .reset = _reset, .get_unique_id = _get_unique_id, - .set_virtual_ip = _set_virtual_ip, - .get_virtual_ip = _get_virtual_ip, + .add_virtual_ip = _add_virtual_ip, + .create_virtual_ip_enumerator = _create_virtual_ip_enumerator, .add_configuration_attribute = _add_configuration_attribute, .set_kmaddress = _set_kmaddress, .create_task_enumerator = _create_task_enumerator, @@ -2226,6 +2218,8 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator, .other_auths = linked_list_create(), .unique_id = ++unique_id, .peer_addresses = linked_list_create(), + .my_vips = linked_list_create(), + .other_vips = linked_list_create(), .attributes = linked_list_create(), .keepalive_interval = lib->settings->get_time(lib->settings, "%s.keep_alive", KEEPALIVE_INTERVAL, charon->name), diff --git a/src/libcharon/sa/ike_sa.h b/src/libcharon/sa/ike_sa.h index de9e0ede4..d2a394b6c 100644 --- a/src/libcharon/sa/ike_sa.h +++ b/src/libcharon/sa/ike_sa.h @@ -931,7 +931,7 @@ struct ike_sa_t { status_t (*set_auth_lifetime)(ike_sa_t *this, u_int32_t lifetime); /** - * Set the virtual IP to use for this IKE_SA and its children. + * Add a virtual IP to use for this IKE_SA and its children. * * The virtual IP is assigned per IKE_SA, not per CHILD_SA. It has the same * lifetime as the IKE_SA. @@ -939,15 +939,15 @@ struct ike_sa_t { * @param local TRUE to set local address, FALSE for remote * @param ip IP to set as virtual IP */ - void (*set_virtual_ip) (ike_sa_t *this, bool local, host_t *ip); + void (*add_virtual_ip) (ike_sa_t *this, bool local, host_t *ip); /** - * Get the virtual IP configured. + * Create an enumerator over virtual IPs. * * @param local TRUE to get local virtual IP, FALSE for remote - * @return host_t *virtual IP + * @return enumerator over host_t* */ - host_t* (*get_virtual_ip) (ike_sa_t *this, bool local); + enumerator_t* (*create_virtual_ip_enumerator) (ike_sa_t *this, bool local); /** * Register a configuration attribute to the IKE_SA. diff --git a/src/libcharon/sa/ikev1/phase1.c b/src/libcharon/sa/ikev1/phase1.c index fee304e6f..791f72827 100644 --- a/src/libcharon/sa/ikev1/phase1.c +++ b/src/libcharon/sa/ikev1/phase1.c @@ -597,6 +597,20 @@ METHOD(phase1_t, get_id, identification_t*, return NULL; } +METHOD(phase1_t, has_virtual_ip, bool, + private_phase1_t *this, peer_cfg_t *peer_cfg) +{ + enumerator_t *enumerator; + bool found = FALSE; + host_t *host; + + enumerator = peer_cfg->create_virtual_ip_enumerator(peer_cfg); + found = enumerator->enumerate(enumerator, &host); + enumerator->destroy(enumerator); + + return found; +} + METHOD(phase1_t, save_sa_payload, bool, private_phase1_t *this, message_t *message) { @@ -736,6 +750,7 @@ phase1_t *phase1_create(ike_sa_t *ike_sa, bool initiator) .get_auth_method = _get_auth_method, .get_id = _get_id, .select_config = _select_config, + .has_virtual_ip = _has_virtual_ip, .verify_auth = _verify_auth, .build_auth = _build_auth, .save_sa_payload = _save_sa_payload, diff --git a/src/libcharon/sa/ikev1/phase1.h b/src/libcharon/sa/ikev1/phase1.h index f1e95d88c..2f0a5f196 100644 --- a/src/libcharon/sa/ikev1/phase1.h +++ b/src/libcharon/sa/ikev1/phase1.h @@ -109,6 +109,14 @@ struct phase1_t { identification_t* (*get_id)(phase1_t *this, peer_cfg_t *peer_cfg, bool local); /** + * Check if peer config has virtual IPs to request + * + * @param peer_cfg peer_config to check + * @return TRUE if peer config contains at least one virtual IP + */ + bool (*has_virtual_ip)(phase1_t *this, peer_cfg_t *peer_cfg); + + /** * Extract and store SA payload bytes from encoded message. * * @param message message to extract SA payload bytes from diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c index 3c84b5114..e0dcf731d 100644 --- a/src/libcharon/sa/ikev1/task_manager_v1.c +++ b/src/libcharon/sa/ikev1/task_manager_v1.c @@ -346,15 +346,21 @@ METHOD(task_manager_t, retransmit, status_t, */ static bool mode_config_expected(private_task_manager_t *this) { + enumerator_t *enumerator; peer_cfg_t *peer_cfg; + host_t *host; peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); if (peer_cfg && peer_cfg->get_pool(peer_cfg)) { - if (!this->ike_sa->get_virtual_ip(this->ike_sa, FALSE)) - { + enumerator = this->ike_sa->create_virtual_ip_enumerator(this->ike_sa, + FALSE); + if (!enumerator->enumerate(enumerator, &host)) + { /* have a pool, but no VIP assigned yet */ + enumerator->destroy(enumerator); return TRUE; } + enumerator->destroy(enumerator); } return FALSE; } @@ -1309,11 +1315,12 @@ METHOD(task_manager_t, queue_ike_reauth, void, new->set_other_host(new, host->clone(host)); host = this->ike_sa->get_my_host(this->ike_sa); new->set_my_host(new, host->clone(host)); - host = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE); - if (host) + enumerator = this->ike_sa->create_virtual_ip_enumerator(this->ike_sa, TRUE); + while (enumerator->enumerate(enumerator, &host)) { - new->set_virtual_ip(new, TRUE, host); + new->add_virtual_ip(new, TRUE, host); } + enumerator->destroy(enumerator); enumerator = this->ike_sa->create_child_sa_enumerator(this->ike_sa); while (enumerator->enumerate(enumerator, &child_sa)) diff --git a/src/libcharon/sa/ikev1/tasks/aggressive_mode.c b/src/libcharon/sa/ikev1/tasks/aggressive_mode.c index 38962fc60..eb9b09e3f 100644 --- a/src/libcharon/sa/ikev1/tasks/aggressive_mode.c +++ b/src/libcharon/sa/ikev1/tasks/aggressive_mode.c @@ -320,7 +320,7 @@ METHOD(task_t, build_i, status_t, } break; } - if (this->peer_cfg->get_virtual_ip(this->peer_cfg)) + 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)); @@ -498,7 +498,7 @@ METHOD(task_t, process_r, status_t, break; } if (this->peer_cfg->get_pool(this->peer_cfg) == NULL && - this->peer_cfg->get_virtual_ip(this->peer_cfg)) + 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)); diff --git a/src/libcharon/sa/ikev1/tasks/main_mode.c b/src/libcharon/sa/ikev1/tasks/main_mode.c index 539286938..6f7753676 100644 --- a/src/libcharon/sa/ikev1/tasks/main_mode.c +++ b/src/libcharon/sa/ikev1/tasks/main_mode.c @@ -525,7 +525,7 @@ METHOD(task_t, build_r, status_t, break; } if (this->peer_cfg->get_pool(this->peer_cfg) == NULL && - this->peer_cfg->get_virtual_ip(this->peer_cfg)) + 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)); @@ -658,7 +658,7 @@ METHOD(task_t, process_i, status_t, } break; } - if (this->peer_cfg->get_virtual_ip(this->peer_cfg)) + 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)); diff --git a/src/libcharon/sa/ikev1/tasks/mode_config.c b/src/libcharon/sa/ikev1/tasks/mode_config.c index ab3a81386..6ba3e6768 100644 --- a/src/libcharon/sa/ikev1/tasks/mode_config.c +++ b/src/libcharon/sa/ikev1/tasks/mode_config.c @@ -242,12 +242,19 @@ METHOD(task_t, build_i, status_t, host_t *vip; /* reuse virtual IP if we already have one */ - vip = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE); - if (!vip) + enumerator = this->ike_sa->create_virtual_ip_enumerator(this->ike_sa, TRUE); + if (!enumerator->enumerate(enumerator, &vip)) { + enumerator->destroy(enumerator); config = this->ike_sa->get_peer_cfg(this->ike_sa); - vip = config->get_virtual_ip(config); + enumerator = config->create_virtual_ip_enumerator(config); + if (!enumerator->enumerate(enumerator, &vip)) + { + vip = NULL; + } } + enumerator->destroy(enumerator); + if (vip) { cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REQUEST); @@ -319,7 +326,7 @@ METHOD(task_t, build_r, status_t, if (vip) { DBG1(DBG_IKE, "assigning virtual IP %H to peer '%Y'", vip, id); - this->ike_sa->set_virtual_ip(this->ike_sa, FALSE, vip); + this->ike_sa->add_virtual_ip(this->ike_sa, FALSE, vip); cp->add_attribute(cp, build_vip(vip)); } else @@ -360,7 +367,7 @@ METHOD(task_t, process_i, status_t, if (this->virtual_ip) { - this->ike_sa->set_virtual_ip(this->ike_sa, TRUE, this->virtual_ip); + this->ike_sa->add_virtual_ip(this->ike_sa, TRUE, this->virtual_ip); } return SUCCESS; } diff --git a/src/libcharon/sa/ikev1/tasks/quick_mode.c b/src/libcharon/sa/ikev1/tasks/quick_mode.c index 67d1b45f1..73a23f4ea 100644 --- a/src/libcharon/sa/ikev1/tasks/quick_mode.c +++ b/src/libcharon/sa/ikev1/tasks/quick_mode.c @@ -398,11 +398,12 @@ static traffic_selector_t* select_ts(private_quick_mode_t *this, bool local, linked_list_t *supplied) { traffic_selector_t *ts; + enumerator_t *enumerator; linked_list_t *list; host_t *host; - host = this->ike_sa->get_virtual_ip(this->ike_sa, local); - if (!host) + enumerator = this->ike_sa->create_virtual_ip_enumerator(this->ike_sa, local); + if (!enumerator->enumerate(enumerator, &host)) { if (local) { @@ -413,6 +414,7 @@ static traffic_selector_t* select_ts(private_quick_mode_t *this, bool local, host = this->ike_sa->get_other_host(this->ike_sa); } } + enumerator->destroy(enumerator); list = this->config->get_traffic_selectors(this->config, local, supplied, host); if (list->get_first(list, (void**)&ts) == SUCCESS) @@ -831,6 +833,30 @@ static void check_for_rekeyed_child(private_quick_mode_t *this) enumerator->destroy(enumerator); } +/** + * Get host to use for dynamic traffic selectors + */ +static host_t *get_dynamic_host(ike_sa_t *ike_sa, bool local) +{ + enumerator_t *enumerator; + host_t *host; + + enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, local); + if (!enumerator->enumerate(enumerator, &host)) + { + if (local) + { + host = ike_sa->get_my_host(ike_sa); + } + else + { + host = ike_sa->get_other_host(ike_sa); + } + } + enumerator->destroy(enumerator); + return host; +} + METHOD(task_t, process_r, status_t, private_quick_mode_t *this, message_t *message) { @@ -841,7 +867,6 @@ METHOD(task_t, process_r, status_t, sa_payload_t *sa_payload; linked_list_t *tsi, *tsr, *list = NULL; peer_cfg_t *peer_cfg; - host_t *me, *other; u_int16_t group; bool private; @@ -849,16 +874,6 @@ METHOD(task_t, process_r, status_t, { return FAILED; } - me = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE); - if (!me) - { - me = this->ike_sa->get_my_host(this->ike_sa); - } - other = this->ike_sa->get_virtual_ip(this->ike_sa, FALSE); - if (!other) - { - other = this->ike_sa->get_other_host(this->ike_sa); - } peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); tsi = linked_list_create(); tsr = linked_list_create(); @@ -866,7 +881,8 @@ METHOD(task_t, process_r, status_t, tsr->insert_last(tsr, this->tsr); this->tsi = this->tsr = NULL; this->config = peer_cfg->select_child_cfg(peer_cfg, tsr, tsi, - me, other); + get_dynamic_host(this->ike_sa, TRUE), + get_dynamic_host(this->ike_sa, FALSE)); if (this->config) { this->tsi = select_ts(this, FALSE, tsi); diff --git a/src/libcharon/sa/ikev2/tasks/child_create.c b/src/libcharon/sa/ikev2/tasks/child_create.c index 5c5468dab..d7d912fdc 100644 --- a/src/libcharon/sa/ikev2/tasks/child_create.c +++ b/src/libcharon/sa/ikev2/tasks/child_create.c @@ -285,6 +285,30 @@ static void schedule_inactivity_timeout(private_child_create_t *this) } /** + * Get host to use for dynamic traffic selectors + */ +static host_t *get_dynamic_host(ike_sa_t *ike_sa, bool local) +{ + enumerator_t *enumerator; + host_t *host; + + enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, local); + if (!enumerator->enumerate(enumerator, &host)) + { + if (local) + { + host = ike_sa->get_my_host(ike_sa); + } + else + { + host = ike_sa->get_other_host(ike_sa); + } + } + enumerator->destroy(enumerator); + return host; +} + +/** * Install a CHILD_SA for usage, return value: * - FAILED: no acceptable proposal * - INVALID_ARG: diffie hellman group inacceptable @@ -298,7 +322,7 @@ static status_t select_and_install(private_child_create_t *this, chunk_t encr_i = chunk_empty, encr_r = chunk_empty; chunk_t integ_i = chunk_empty, integ_r = chunk_empty; linked_list_t *my_ts, *other_ts; - host_t *me, *other, *other_vip, *my_vip; + host_t *me, *other; bool private; if (this->proposals == NULL) @@ -314,8 +338,6 @@ static status_t select_and_install(private_child_create_t *this, me = this->ike_sa->get_my_host(this->ike_sa); other = this->ike_sa->get_other_host(this->ike_sa); - my_vip = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE); - other_vip = this->ike_sa->get_virtual_ip(this->ike_sa, FALSE); private = this->ike_sa->supports_extension(this->ike_sa, EXT_STRONGSWAN); this->proposal = this->config->select_proposal(this->config, @@ -354,15 +376,6 @@ static status_t select_and_install(private_child_create_t *this, this->dh_group = MODP_NONE; } - if (my_vip == NULL) - { - my_vip = me; - } - if (other_vip == NULL) - { - other_vip = other; - } - if (this->initiator) { nonce_i = this->my_nonce; @@ -378,9 +391,9 @@ static status_t select_and_install(private_child_create_t *this, other_ts = this->tsi; } my_ts = this->config->get_traffic_selectors(this->config, TRUE, my_ts, - my_vip); + get_dynamic_host(this->ike_sa, TRUE)); other_ts = this->config->get_traffic_selectors(this->config, FALSE, other_ts, - other_vip); + get_dynamic_host(this->ike_sa, FALSE)); if (this->initiator) { @@ -723,7 +736,8 @@ static void process_payloads(private_child_create_t *this, message_t *message) METHOD(task_t, build_i, status_t, private_child_create_t *this, message_t *message) { - host_t *me, *other, *vip; + enumerator_t *enumerator; + host_t *vip; peer_cfg_t *peer_cfg; switch (message->get_exchange_type(message)) @@ -763,22 +777,10 @@ METHOD(task_t, build_i, status_t, this->config->get_name(this->config)); } - /* reuse virtual IP if we already have one */ - me = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE); - if (me == NULL) - { - me = this->ike_sa->get_my_host(this->ike_sa); - } - other = this->ike_sa->get_virtual_ip(this->ike_sa, FALSE); - if (other == NULL) - { - other = this->ike_sa->get_other_host(this->ike_sa); - } - /* check if we want a virtual IP, but don't have one */ peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); - vip = peer_cfg->get_virtual_ip(peer_cfg); - if (!this->reqid && vip) + enumerator = peer_cfg->create_virtual_ip_enumerator(peer_cfg); + if (!this->reqid && enumerator->enumerate(enumerator, &vip)) { /* propose a 0.0.0.0/0 or ::/0 subnet when we use virtual ip */ vip = host_create_any(vip->get_family(vip)); @@ -788,11 +790,12 @@ METHOD(task_t, build_i, status_t, } else { /* but narrow it for host2host / if we already have a vip */ - this->tsi = this->config->get_traffic_selectors(this->config, TRUE, - NULL, me); + this->tsi = this->config->get_traffic_selectors(this->config, TRUE, NULL, + get_dynamic_host(this->ike_sa, TRUE)); } - this->tsr = this->config->get_traffic_selectors(this->config, FALSE, - NULL, other); + enumerator->destroy(enumerator); + this->tsr = this->config->get_traffic_selectors(this->config, FALSE, NULL, + get_dynamic_host(this->ike_sa, FALSE)); if (this->packet_tsi) { @@ -948,20 +951,10 @@ METHOD(task_t, build_r, status_t, peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); if (!this->config && peer_cfg && this->tsi && this->tsr) { - host_t *me, *other; - - me = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE); - if (me == NULL) - { - me = this->ike_sa->get_my_host(this->ike_sa); - } - other = this->ike_sa->get_virtual_ip(this->ike_sa, FALSE); - if (other == NULL) - { - other = this->ike_sa->get_other_host(this->ike_sa); - } - this->config = peer_cfg->select_child_cfg(peer_cfg, this->tsr, - this->tsi, me, other); + this->config = peer_cfg->select_child_cfg(peer_cfg, + this->tsr, this->tsi, + get_dynamic_host(this->ike_sa, TRUE), + get_dynamic_host(this->ike_sa, FALSE)); } if (this->config == NULL) diff --git a/src/libcharon/sa/ikev2/tasks/ike_config.c b/src/libcharon/sa/ikev2/tasks/ike_config.c index 932b02d42..63d35ec09 100644 --- a/src/libcharon/sa/ikev2/tasks/ike_config.c +++ b/src/libcharon/sa/ikev2/tasks/ike_config.c @@ -245,12 +245,19 @@ METHOD(task_t, build_i, status_t, host_t *vip; /* reuse virtual IP if we already have one */ - vip = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE); - if (!vip) + enumerator = this->ike_sa->create_virtual_ip_enumerator(this->ike_sa, + TRUE); + if (!enumerator->enumerate(enumerator, &vip)) { + enumerator->destroy(enumerator); config = this->ike_sa->get_peer_cfg(this->ike_sa); - vip = config->get_virtual_ip(config); + enumerator = config->create_virtual_ip_enumerator(config); + if (!enumerator->enumerate(enumerator, &vip)) + { + vip = NULL; + } } + enumerator->destroy(enumerator); if (vip) { cp = cp_payload_create_type(CONFIGURATION, CFG_REQUEST); @@ -335,7 +342,7 @@ METHOD(task_t, build_r, status_t, return SUCCESS; } DBG1(DBG_IKE, "assigning virtual IP %H to peer '%Y'", vip, id); - this->ike_sa->set_virtual_ip(this->ike_sa, FALSE, vip); + this->ike_sa->add_virtual_ip(this->ike_sa, FALSE, vip); cp = cp_payload_create_type(CONFIGURATION, CFG_REPLY); cp->add_attribute(cp, build_vip(vip)); @@ -379,7 +386,7 @@ METHOD(task_t, process_i, status_t, if (this->virtual_ip && !this->virtual_ip->is_anyaddr(this->virtual_ip)) { - this->ike_sa->set_virtual_ip(this->ike_sa, TRUE, this->virtual_ip); + this->ike_sa->add_virtual_ip(this->ike_sa, TRUE, this->virtual_ip); } return SUCCESS; } diff --git a/src/libcharon/sa/ikev2/tasks/ike_mobike.c b/src/libcharon/sa/ikev2/tasks/ike_mobike.c index 133bc296e..8c30ed96c 100644 --- a/src/libcharon/sa/ikev2/tasks/ike_mobike.c +++ b/src/libcharon/sa/ikev2/tasks/ike_mobike.c @@ -250,15 +250,26 @@ static void update_children(private_ike_mobike_t *this) { enumerator_t *enumerator; child_sa_t *child_sa; + linked_list_t *vips; + host_t *host; + + vips = linked_list_create(); + + enumerator = this->ike_sa->create_virtual_ip_enumerator(this->ike_sa, TRUE); + while (enumerator->enumerate(enumerator, &host)) + { + vips->insert_last(vips, host); + } + enumerator->destroy(enumerator); enumerator = this->ike_sa->create_child_sa_enumerator(this->ike_sa); while (enumerator->enumerate(enumerator, (void**)&child_sa)) { if (child_sa->update(child_sa, this->ike_sa->get_my_host(this->ike_sa), - this->ike_sa->get_other_host(this->ike_sa), - this->ike_sa->get_virtual_ip(this->ike_sa, TRUE), - this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY)) == NOT_SUPPORTED) + this->ike_sa->get_other_host(this->ike_sa), vips, + this->ike_sa->has_condition(this->ike_sa, + COND_NAT_ANY)) == NOT_SUPPORTED) { this->ike_sa->rekey_child_sa(this->ike_sa, child_sa->get_protocol(child_sa), @@ -266,6 +277,8 @@ static void update_children(private_ike_mobike_t *this) } } enumerator->destroy(enumerator); + + vips->destroy(vips); } /** |