Support multiple virtual IPs on peer_cfg and ike_sa classes
authorMartin Willi <martin@revosec.ch>
Tue, 21 Aug 2012 11:50:32 +0000 (13:50 +0200)
committerMartin Willi <martin@revosec.ch>
Thu, 30 Aug 2012 14:43:42 +0000 (16:43 +0200)
34 files changed:
src/charon-nm/nm/nm_service.c
src/conftest/config.c
src/frontends/android/jni/libandroidbridge/backend/android_service.c
src/libcharon/config/peer_cfg.c
src/libcharon/config/peer_cfg.h
src/libcharon/plugins/android/android_service.c
src/libcharon/plugins/eap_radius/eap_radius_accounting.c
src/libcharon/plugins/ha/ha_dispatcher.c
src/libcharon/plugins/ha/ha_ike.c
src/libcharon/plugins/ha/ha_tunnel.c
src/libcharon/plugins/load_tester/load_tester_config.c
src/libcharon/plugins/maemo/maemo_service.c
src/libcharon/plugins/medcli/medcli_config.c
src/libcharon/plugins/medsrv/medsrv_config.c
src/libcharon/plugins/sql/sql_config.c
src/libcharon/plugins/stroke/stroke_config.c
src/libcharon/plugins/stroke/stroke_control.c
src/libcharon/plugins/uci/uci_config.c
src/libcharon/plugins/updown/updown_listener.c
src/libcharon/processing/jobs/migrate_job.c
src/libcharon/sa/child_sa.c
src/libcharon/sa/child_sa.h
src/libcharon/sa/ike_sa.c
src/libcharon/sa/ike_sa.h
src/libcharon/sa/ikev1/phase1.c
src/libcharon/sa/ikev1/phase1.h
src/libcharon/sa/ikev1/task_manager_v1.c
src/libcharon/sa/ikev1/tasks/aggressive_mode.c
src/libcharon/sa/ikev1/tasks/main_mode.c
src/libcharon/sa/ikev1/tasks/mode_config.c
src/libcharon/sa/ikev1/tasks/quick_mode.c
src/libcharon/sa/ikev2/tasks/child_create.c
src/libcharon/sa/ikev2/tasks/ike_config.c
src/libcharon/sa/ikev2/tasks/ike_mobike.c

index ccfa210..2eef51a 100644 (file)
@@ -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);
index a3f23f3..61f3760 100644 (file)
@@ -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);
index dfc0d23..d472301 100644 (file)
@@ -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);
index d16aedc..091176a 100644 (file)
@@ -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(),
index 5721535..fd924dc 100644 (file)
@@ -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_ @}*/
index f2d8ddc..1236e45 100644 (file)
@@ -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);
index 243c763..7690cf9 100644 (file)
@@ -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;
+               }
        }
 }
 
index 8b6ec91..8516f4f 100644 (file)
@@ -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);
                                }
                        }
                }
index d523e89..442a3a2 100644 (file)
@@ -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 &&
index ad458ca..15ba28e 100644 (file)
@@ -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);
index f5da8b8..09e220b 100644 (file)
@@ -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);
index f638a81..e8718b9 100644 (file)
@@ -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);
index 829c8f0..f44ff39 100644 (file)
@@ -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();
index ebc142d..edbf9cc 100644 (file)
@@ -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);
 
index 8900771..343d6e4 100644 (file)
@@ -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);
index bf93f2c..e3ea542 100644 (file)
@@ -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);
index 163a2a7..233d408 100644 (file)
@@ -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);
index 5b698b8..140cbea 100644 (file)
@@ -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);
index 944c46c..2f9f2ef 100644 (file)
@@ -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);
index 57f3449..2ebfc67 100644 (file)
@@ -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
        {
index d5adb25..c3fbd8b 100644 (file)
@@ -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,
index 712a476..dae3f2c 100644 (file)
@@ -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.
         */
index 1e3d00f..26e65b2 100644 (file)
@@ -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),
index de9e0ed..d2a394b 100644 (file)
@@ -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.
index fee304e..791f728 100644 (file)
@@ -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,
index f1e95d8..2f0a5f1 100644 (file)
@@ -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
index 3c84b51..e0dcf73 100644 (file)
@@ -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))
index 38962fc..eb9b09e 100644 (file)
@@ -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));
index 5392869..6f77536 100644 (file)
@@ -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));
index ab3a813..6ba3e67 100644 (file)
@@ -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;
 }
index 67d1b45..73a23f4 100644 (file)
@@ -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);
index 5c5468d..d7d912f 100644 (file)
@@ -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)
index 932b02d..63d35ec 100644 (file)
@@ -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;
        }
index 133bc29..8c30ed9 100644 (file)
@@ -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);
 }
 
 /**