Support multiple addresses/pools in left/rightsourceip
authorMartin Willi <martin@revosec.ch>
Mon, 27 Aug 2012 09:19:46 +0000 (11:19 +0200)
committerMartin Willi <martin@revosec.ch>
Thu, 30 Aug 2012 14:43:42 +0000 (16:43 +0200)
src/libcharon/plugins/stroke/stroke_attribute.c
src/libcharon/plugins/stroke/stroke_attribute.h
src/libcharon/plugins/stroke/stroke_config.c
src/libcharon/plugins/stroke/stroke_config.h
src/libcharon/plugins/stroke/stroke_socket.c
src/starter/confread.c
src/starter/confread.h
src/starter/starterstroke.c
src/stroke/stroke_msg.h

index aa3b1d2..ebae6fc 100644 (file)
@@ -17,7 +17,6 @@
 #include "stroke_attribute.h"
 
 #include <daemon.h>
-#include <attributes/mem_pool.h>
 #include <utils/linked_list.h>
 #include <threading/rwlock.h>
 
@@ -96,6 +95,7 @@ METHOD(attribute_provider_t, acquire_address, host_t*,
 {
        mem_pool_t *pool;
        host_t *addr = NULL;
+
        this->lock->read_lock(this->lock);
        pool = find_pool(this, name);
        if (pool)
@@ -112,6 +112,7 @@ METHOD(attribute_provider_t, release_address, bool,
 {
        mem_pool_t *pool;
        bool found = FALSE;
+
        this->lock->read_lock(this->lock);
        pool = find_pool(this, name);
        if (pool)
@@ -179,36 +180,48 @@ METHOD(attribute_provider_t, create_attribute_enumerator, enumerator_t*,
 }
 
 METHOD(stroke_attribute_t, add_pool, void,
-       private_stroke_attribute_t *this, stroke_msg_t *msg)
+       private_stroke_attribute_t *this, mem_pool_t *pool)
 {
-       if (msg->add_conn.other.sourceip_mask)
-       {
-               mem_pool_t *pool;
-               host_t *base = NULL;
-               u_int32_t bits = 0;
+       enumerator_t *enumerator;
+       mem_pool_t *current;
+       host_t *base;
+       int size;
 
-               /* if %config, add an empty pool, otherwise */
-               if (msg->add_conn.other.sourceip)
+       base = pool->get_base(pool);
+       size = pool->get_size(pool);
+
+       this->lock->write_lock(this->lock);
+
+       enumerator = this->pools->create_enumerator(this->pools);
+       while (enumerator->enumerate(enumerator, &current))
+       {
+               if (base && current->get_base(current) &&
+                       base->ip_equals(base, current->get_base(current)) &&
+                       size == current->get_size(current))
                {
-                       DBG1(DBG_CFG, "adding virtual IP address pool '%s': %s/%d",
-                                msg->add_conn.name, msg->add_conn.other.sourceip,
-                                msg->add_conn.other.sourceip_mask);
-                       base = host_create_from_string(msg->add_conn.other.sourceip, 0);
-                       if (!base)
-                       {
-                               DBG1(DBG_CFG, "virtual IP address invalid, discarded");
-                               return;
-                       }
-                       bits = msg->add_conn.other.sourceip_mask;
+                       pool->destroy(pool);
+                       pool = NULL;
+                       DBG1(DBG_CFG, "reusing virtual IP address pool %H/%d", base, size);
+                       break;
                }
-               pool = mem_pool_create(msg->add_conn.name, base, bits);
-               DESTROY_IF(base);
+       }
+       enumerator->destroy(enumerator);
 
-               this->lock->write_lock(this->lock);
+       if (pool)
+       {
+               if (base)
+               {
+                       DBG1(DBG_CFG, "adding virtual IP address pool %H/%d", base, size);
+               }
                this->pools->insert_last(this->pools, pool);
-               this->lock->unlock(this->lock);
        }
 
+       this->lock->unlock(this->lock);
+}
+
+METHOD(stroke_attribute_t, add_dns, void,
+       private_stroke_attribute_t *this, stroke_msg_t *msg)
+{
        if (msg->add_conn.other.dns)
        {
                enumerator_t *enumerator;
@@ -246,25 +259,13 @@ METHOD(stroke_attribute_t, add_pool, void,
        }
 }
 
-METHOD(stroke_attribute_t, del_pool, void,
+METHOD(stroke_attribute_t, del_dns, void,
        private_stroke_attribute_t *this, stroke_msg_t *msg)
 {
        enumerator_t *enumerator;
        attributes_t *attr;
-       mem_pool_t *pool;
 
        this->lock->write_lock(this->lock);
-       enumerator = this->pools->create_enumerator(this->pools);
-       while (enumerator->enumerate(enumerator, &pool))
-       {
-               if (streq(msg->del_conn.name, pool->get_name(pool)))
-               {
-                       this->pools->remove_at(this->pools, enumerator);
-                       pool->destroy(pool);
-                       break;
-               }
-       }
-       enumerator->destroy(enumerator);
 
        enumerator = this->attrs->create_enumerator(this->attrs);
        while (enumerator->enumerate(enumerator, &attr))
@@ -289,6 +290,11 @@ static bool pool_filter(void *lock, mem_pool_t **poolp, const char **name,
                                                void *d3, u_int *offline)
 {
        mem_pool_t *pool = *poolp;
+
+       if (pool->get_size(pool) == 0)
+       {
+               return FALSE;
+       }
        *name = pool->get_name(pool);
        *size = pool->get_size(pool);
        *online = pool->get_online(pool);
@@ -344,7 +350,8 @@ stroke_attribute_t *stroke_attribute_create()
                                .create_attribute_enumerator = _create_attribute_enumerator,
                        },
                        .add_pool = _add_pool,
-                       .del_pool = _del_pool,
+                       .add_dns = _add_dns,
+                       .del_dns = _del_dns,
                        .create_pool_enumerator = _create_pool_enumerator,
                        .create_lease_enumerator = _create_lease_enumerator,
                        .destroy = _destroy,
index 249a989..f1b9d13 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <stroke_msg.h>
 #include <attributes/attribute_provider.h>
+#include <attributes/mem_pool.h>
 
 typedef struct stroke_attribute_t stroke_attribute_t;
 
@@ -37,18 +38,28 @@ struct stroke_attribute_t {
        attribute_provider_t provider;
 
        /**
-        * Add a virtual IP address pool.
+        * Add a memory pool to this virtual IP backend.
         *
-        * @param msg           stroke message
+        * The pool gets owned by the provider, or destroyed if such a pool
+        * is already registered.
+        *
+        * @param pool          virtual IP pool to add
+        */
+       void (*add_pool)(stroke_attribute_t *this, mem_pool_t *pool);
+
+       /**
+        * Add connection specific DNS servers.
+        *
+        * @param msg           stroke add message
         */
-       void (*add_pool)(stroke_attribute_t *this, stroke_msg_t *msg);
+       void (*add_dns)(stroke_attribute_t *this, stroke_msg_t *msg);
 
        /**
-        * Remove a virtual IP address pool.
+        * Remove connection specific DNS servers.
         *
-        * @param msg           stroke message
+        * @param msg           stroke del message
         */
-       void (*del_pool)(stroke_attribute_t *this, stroke_msg_t *msg);
+       void (*del_dns)(stroke_attribute_t *this, stroke_msg_t *msg);
 
        /**
         * Create an enumerator over installed pools.
index 5f32072..fe8baf1 100644 (file)
@@ -52,6 +52,11 @@ struct private_stroke_config_t {
         * credentials
         */
        stroke_cred_t *cred;
+
+       /**
+        * Virtual IP pool / DNS backend
+        */
+       stroke_attribute_t *attributes;
 };
 
 METHOD(backend_t, create_peer_cfg_enumerator, enumerator_t*,
@@ -649,7 +654,6 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this,
 {
        identification_t *peer_id = NULL;
        peer_cfg_t *mediated_by = NULL;
-       host_t *vip = NULL;
        unique_policy_t unique;
        u_int32_t rekey = 0, reauth = 0, over, jitter;
        peer_cfg_t *peer_cfg;
@@ -708,49 +712,6 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this,
        {
                rekey = msg->add_conn.rekey.ike_lifetime - over;
        }
-       if (msg->add_conn.me.sourceip_mask)
-       {
-               if (msg->add_conn.me.sourceip)
-               {
-                       vip = host_create_from_string(msg->add_conn.me.sourceip, 0);
-               }
-               if (!vip)
-               {       /* if it is set to something like %poolname, request an address */
-                       if (msg->add_conn.me.subnets)
-                       {       /* use the same family as in local subnet, if any */
-                               if (strchr(msg->add_conn.me.subnets, '.'))
-                               {
-                                       vip = host_create_any(AF_INET);
-                               }
-                               else
-                               {
-                                       vip = host_create_any(AF_INET6);
-                               }
-                       }
-                       else if (msg->add_conn.other.subnets)
-                       {       /* use the same family as in remote subnet, if any */
-                               if (strchr(msg->add_conn.other.subnets, '.'))
-                               {
-                                       vip = host_create_any(AF_INET);
-                               }
-                               else
-                               {
-                                       vip = host_create_any(AF_INET6);
-                               }
-                       }
-                       else
-                       {
-                               if (strchr(ike_cfg->get_my_addr(ike_cfg, NULL), ':'))
-                               {
-                                       vip = host_create_any(AF_INET6);
-                               }
-                               else
-                               {
-                                       vip = host_create_any(AF_INET);
-                               }
-                       }
-               }
-       }
        switch (msg->add_conn.unique)
        {
                case 1: /* yes */
@@ -779,17 +740,123 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this,
                msg->add_conn.mobike, msg->add_conn.aggressive,
                msg->add_conn.dpd.delay, msg->add_conn.dpd.timeout,
                msg->add_conn.ikeme.mediation, mediated_by, peer_id);
-       if (vip)
-       {
-               peer_cfg->add_virtual_ip(peer_cfg, vip);
-       }
-       if (msg->add_conn.other.sourceip_mask)
+
+       if (msg->add_conn.other.sourceip)
        {
-               peer_cfg->add_pool(peer_cfg, msg->add_conn.name);
+               enumerator_t *enumerator;
+               char *token;
+
+               enumerator = enumerator_create_token(msg->add_conn.other.sourceip,
+                                                                                        ",", " ");
+               while (enumerator->enumerate(enumerator, &token))
+               {
+                       if (streq(token, "%modeconfig") || streq(token, "%modecfg") ||
+                               streq(token, "%config") || streq(token, "%cfg") ||
+                               streq(token, "%config4") || streq(token, "%config6"))
+                       {
+                               /* empty pool, uses connection name */
+                               this->attributes->add_pool(this->attributes,
+                                                               mem_pool_create(msg->add_conn.name, NULL, 0));
+                               peer_cfg->add_pool(peer_cfg, msg->add_conn.name);
+                       }
+                       else if (*token == '%')
+                       {
+                               /* external named pool */
+                               peer_cfg->add_pool(peer_cfg, token + 1);
+                       }
+                       else
+                       {
+                               /* in-memory pool, named using CIDR notation */
+                               host_t *base;
+                               int bits;
+
+                               base = host_create_from_subnet(token, &bits);
+                               if (base)
+                               {
+                                       this->attributes->add_pool(this->attributes,
+                                                                               mem_pool_create(token, base, bits));
+                                       peer_cfg->add_pool(peer_cfg, token);
+                                       base->destroy(base);
+                               }
+                               else
+                               {
+                                       DBG1(DBG_CFG, "IP pool %s invalid, ignored", token);
+                               }
+                       }
+               }
+               enumerator->destroy(enumerator);
        }
-       else if (msg->add_conn.other.sourceip)
+
+       if (msg->add_conn.me.sourceip)
        {
-               peer_cfg->add_pool(peer_cfg, msg->add_conn.other.sourceip);
+               enumerator_t *enumerator;
+               char *token;
+
+               enumerator = enumerator_create_token(msg->add_conn.me.sourceip, ",", " ");
+               while (enumerator->enumerate(enumerator, &token))
+               {
+                       host_t *vip = NULL;
+
+                       if (streq(token, "%modeconfig") || streq(token, "%modecfg") ||
+                               streq(token, "%config") || streq(token, "%cfg"))
+                       {       /* try to deduce an address family */
+                               if (msg->add_conn.me.subnets)
+                               {       /* use the same family as in local subnet, if any */
+                                       if (strchr(msg->add_conn.me.subnets, '.'))
+                                       {
+                                               vip = host_create_any(AF_INET);
+                                       }
+                                       else
+                                       {
+                                               vip = host_create_any(AF_INET6);
+                                       }
+                               }
+                               else if (msg->add_conn.other.subnets)
+                               {       /* use the same family as in remote subnet, if any */
+                                       if (strchr(msg->add_conn.other.subnets, '.'))
+                                       {
+                                               vip = host_create_any(AF_INET);
+                                       }
+                                       else
+                                       {
+                                               vip = host_create_any(AF_INET6);
+                                       }
+                               }
+                               else
+                               {
+                                       if (strchr(ike_cfg->get_my_addr(ike_cfg, NULL), ':'))
+                                       {
+                                               vip = host_create_any(AF_INET6);
+                                       }
+                                       else
+                                       {
+                                               vip = host_create_any(AF_INET);
+                                       }
+                               }
+                       }
+                       else if (streq(token, "%config4"))
+                       {
+                               vip = host_create_any(AF_INET);
+                       }
+                       else if (streq(token, "%config6"))
+                       {
+                               vip = host_create_any(AF_INET6);
+                       }
+                       else
+                       {
+                               vip = host_create_from_string(token, 0);
+                               if (vip)
+                               {
+                                       DBG1(DBG_CFG, "ignored invalid subnet token: %s", token);
+                               }
+                       }
+
+                       if (vip)
+                       {
+                               peer_cfg->add_virtual_ip(peer_cfg, vip);
+                       }
+               }
+               enumerator->destroy(enumerator);
        }
 
        /* build leftauth= */
@@ -1250,7 +1317,8 @@ METHOD(stroke_config_t, destroy, void,
 /*
  * see header file
  */
-stroke_config_t *stroke_config_create(stroke_ca_t *ca, stroke_cred_t *cred)
+stroke_config_t *stroke_config_create(stroke_ca_t *ca, stroke_cred_t *cred,
+                                                                         stroke_attribute_t *attributes)
 {
        private_stroke_config_t *this;
 
@@ -1270,6 +1338,7 @@ stroke_config_t *stroke_config_create(stroke_ca_t *ca, stroke_cred_t *cred)
                .mutex = mutex_create(MUTEX_TYPE_RECURSIVE),
                .ca = ca,
                .cred = cred,
+               .attributes = attributes,
        );
 
        return &this->public;
index 450d517..894e03c 100644 (file)
@@ -26,6 +26,7 @@
 #include <stroke_msg.h>
 #include "stroke_ca.h"
 #include "stroke_cred.h"
+#include "stroke_attribute.h"
 
 typedef struct stroke_config_t stroke_config_t;
 
@@ -71,6 +72,7 @@ struct stroke_config_t {
 /**
  * Create a stroke_config instance.
  */
-stroke_config_t *stroke_config_create(stroke_ca_t *ca, stroke_cred_t *cred);
+stroke_config_t *stroke_config_create(stroke_ca_t *ca, stroke_cred_t *cred,
+                                                                         stroke_attribute_t *attributes);
 
 #endif /** STROKE_CONFIG_H_ @}*/
index df43e16..241f0fb 100644 (file)
@@ -243,7 +243,7 @@ static void stroke_add_conn(private_stroke_socket_t *this, stroke_msg_t *msg)
        DBG2(DBG_CFG, "  keyexchange=ikev%u", msg->add_conn.version);
 
        this->config->add(this->config, msg);
-       this->attribute->add_pool(this->attribute, msg);
+       this->attribute->add_dns(this->attribute, msg);
        this->handler->add_attributes(this->handler, msg);
 }
 
@@ -256,7 +256,7 @@ static void stroke_del_conn(private_stroke_socket_t *this, stroke_msg_t *msg)
        DBG1(DBG_CFG, "received stroke: delete connection '%s'", msg->del_conn.name);
 
        this->config->del(this->config, msg);
-       this->attribute->del_pool(this->attribute, msg);
+       this->attribute->del_dns(this->attribute, msg);
        this->handler->del_attributes(this->handler, msg);
 }
 
@@ -831,7 +831,7 @@ stroke_socket_t *stroke_socket_create()
        this->attribute = stroke_attribute_create();
        this->handler = stroke_handler_create();
        this->ca = stroke_ca_create(this->cred);
-       this->config = stroke_config_create(this->ca, this->cred);
+       this->config = stroke_config_create(this->ca, this->cred, this->attribute);
        this->control = stroke_control_create();
        this->list = stroke_list_create(this->attribute);
 
index 9199fce..f30f218 100644 (file)
@@ -231,59 +231,6 @@ static void kw_end(starter_conn_t *conn, starter_end_t *end, kw_token_t token,
                end->host = strdupnull(value);
                break;
        case KW_SOURCEIP:
-               if (value[0] == '%')
-               {
-                       if (streq(value, "%modeconfig") || streq(value, "%modecfg") ||
-                               streq(value, "%config") || streq(value, "%cfg"))
-                       {
-                               /* request ip via config payload */
-                               free(end->sourceip);
-                               end->sourceip = NULL;
-                               end->sourceip_mask = 1;
-                       }
-                       else
-                       {       /* %poolname, strip %, serve ip requests */
-                               free(end->sourceip);
-                               end->sourceip = strdupnull(value+1);
-                               end->sourceip_mask = 0;
-                       }
-                       end->modecfg = TRUE;
-               }
-               else
-               {
-                       host_t *host;
-                       char *sep;
-
-                       sep = strchr(value, '/');
-                       if (sep)
-                       {       /* CIDR notation, address pool */
-                               *sep = '\0';
-                               host = host_create_from_string(value, 0);
-                               if (!host)
-                               {
-                                       DBG1(DBG_APP, "# bad subnet: %s=%s", name, value);
-                                       goto err;
-                               }
-                               host->destroy(host);
-                               free(end->sourceip);
-                               end->sourceip = strdupnull(value);
-                               end->sourceip_mask = atoi(sep + 1);
-                               /* restore the original text in case also= is used */
-                               *sep = '/';
-                       }
-                       else
-                       {       /* fixed srcip */
-                               host = host_create_from_string(value, 0);
-                               if (!host)
-                               {
-                                       DBG1(DBG_APP, "# bad addr: %s=%s", name, value);
-                                       goto err;
-                               }
-                               end->sourceip_mask = (host->get_family(host) == AF_INET) ?
-                                                                         32 : 128;
-                               host->destroy(host);
-                       }
-               }
                conn->mode = MODE_TUNNEL;
                conn->proxy_mode = FALSE;
                break;
index d01d9c1..3f20798 100644 (file)
@@ -111,7 +111,6 @@ struct starter_end {
                u_int16_t       port;
                u_int8_t        protocol;
                char            *sourceip;
-               int                             sourceip_mask;
                char            *dns;
 };
 
index 79bb0ba..d6ad3eb 100644 (file)
@@ -140,7 +140,6 @@ static void starter_stroke_add_end(stroke_msg_t *msg, stroke_end_t *msg_end, sta
        msg_end->ikeport = conn_end->ikeport;
        msg_end->subnets = push_string(msg, conn_end->subnet);
        msg_end->sourceip = push_string(msg, conn_end->sourceip);
-       msg_end->sourceip_mask = conn_end->sourceip_mask;
        msg_end->dns = push_string(msg, conn_end->dns);
        msg_end->sendcert = conn_end->sendcert;
        msg_end->hostaccess = conn_end->hostaccess;
index c941aaf..662feed 100644 (file)
@@ -158,7 +158,6 @@ struct stroke_end_t {
        char *address;
        u_int16_t ikeport;
        char *sourceip;
-       int sourceip_mask;
        char *dns;
        char *subnets;
        int sendcert;