[M] Change in openvpn[master]: multi: assign IPv6 addresses from a tagged subnet-pool

"ordex \(Code Review\) via Openvpn-devel" <[email protected]>
Newsgroups gmane.network.openvpn.devel
Message-ID <[email protected]>
Attention is currently required from: plaisthos.

Hello plaisthos,

I'd like you to do a code review.
Please visit

    http://gerrit.openvpn.net/c/openvpn/+/1786?usp=email

to review the following change.


Change subject: multi: assign IPv6 addresses from a tagged subnet-pool
......................................................................

multi: assign IPv6 addresses from a tagged subnet-pool

Add the IPv6 counterpart of --subnet-pool:

  subnet-pool-ipv6 <tag> <network>/<bits> [<gateway>]   (main config)

selected by the same per-client --subnet-pool-tag. A client's tag is
resolved against the IPv6 pool list too and, when it matches, an IPv6
address is handed out from the group's pool alongside any IPv4 one (a
single dual-stack ifconfig_pool per tag). A tag matching neither family
is still declined with AUTH_FAILED.

Change-Id: I64e0850d48647a2c0e3d385c2f20a9f445931727
GitHub: closes openvpn/OpenVPN#987
Signed-off-by: Antonio Quartulli <[email protected]>
---
M doc/man-sections/server-options.rst
M src/openvpn/multi.c
M src/openvpn/options.c
M src/openvpn/options.h
M src/openvpn/options_util.c
M src/openvpn/options_util.h
6 files changed, 136 insertions(+), 25 deletions(-)



  git pull ssh://gerrit.openvpn.net:29418/openvpn refs/changes/86/1786/1

diff --git a/doc/man-sections/server-options.rst b/doc/man-sections/server-options.rst
index 8800b98..cf92905 100644
--- a/doc/man-sections/server-options.rst
+++ b/doc/man-sections/server-options.rst
@@ -349,11 +349,24 @@
   ``--route-gateway`` inside the subnet, and a host route back to the server's
   VPN IP, so it is reachable without manual per-client route pushes.
 
+--subnet-pool-ipv6 args
+  The IPv6 counterpart of ``--subnet-pool``. Repeatable main-config directive.
+
+  Valid syntax:
+  ::
+
+     subnet-pool-ipv6 tag network/bits [gateway]
+
+  ``bits`` must be between 64 and 124; ``gateway`` defaults to the first
+  address of the network. A tag may name an IPv4 pool, an IPv6 pool, or both;
+  a client referencing it with ``--subnet-pool-tag`` is then assigned an
+  address from each family the tag defines.
+
 --subnet-pool-tag tag
-  Assign this client to the ``--subnet-pool`` named ``tag``. Must be
-  associated with a specific client instance via ``--client-config-dir`` or
-  ``--client-connect``. Several clients may reference the same tag and are
-  then served from the same shared pool.
+  Assign this client to the ``--subnet-pool`` / ``--subnet-pool-ipv6`` named
+  ``tag``. Must be associated with a specific client instance via
+  ``--client-config-dir`` or ``--client-connect``. Several clients may
+  reference the same tag and are then served from the same shared pool(s).
 
 --ifconfig-ipv6-push args
   for ``--client-config-dir`` per-client static IPv6 interface
diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c
index da46cf4..1cd84b6 100644
--- a/src/openvpn/multi.c
+++ b/src/openvpn/multi.c
@@ -1438,11 +1438,14 @@
     }
 
     const struct subnet_pool_def *d4 = subnet_pool_by_tag(m->top.options.subnet_pools, tag);
+    const struct subnet_pool6_def *d6 = subnet_pool6_by_tag(m->top.options.subnet_pools_ipv6, tag);
     ALLOC_OBJ_CLEAR(sp, struct subnet_pool);
-    sp->tag = d4->tag;
-    sp->pool = ifconfig_pool_init(true, IFCONFIG_POOL_INDIV, d4->network + 2,
-                                  (d4->network | ~d4->netmask) - 1, m->top.options.duplicate_cn,
-                                  false, in6addr_any, 0);
+    sp->tag = d4 ? d4->tag : d6->tag;
+    sp->pool = ifconfig_pool_init(d4 != NULL, IFCONFIG_POOL_INDIV, d4 ? d4->network + 2 : 0,
+                                  d4 ? (d4->network | ~d4->netmask) - 1 : 0,
+                                  m->top.options.duplicate_cn, d6 != NULL,
+                                  d6 ? add_in6_addr(d6->network, 2) : in6addr_any,
+                                  d6 ? (int)d6->netbits : 0);
     sp->next = m->subnet_pools;
     m->subnet_pools = sp;
     return sp->pool;
@@ -1472,6 +1475,18 @@
             mi->context.options.subnet_pool_gateway = d->gateway;
         }
     }
+    if (mi->context.options.subnet_pool_tag && !mi->context.options.subnet_pool_ipv6_defined)
+    {
+        const struct subnet_pool6_def *d = subnet_pool6_by_tag(
+            m->top.options.subnet_pools_ipv6, mi->context.options.subnet_pool_tag);
+        if (d)
+        {
+            mi->context.options.subnet_pool_ipv6_defined = true;
+            mi->context.options.subnet_pool_ipv6_network = d->network;
+            mi->context.options.subnet_pool_ipv6_netbits = d->netbits;
+            mi->context.options.subnet_pool_ipv6_gateway = d->gateway;
+        }
+    }
 
     /*
      * If ifconfig addresses were set by dynamic config file,
@@ -1506,42 +1521,60 @@
                 "MULTI_sva: WARNING: if --ifconfig-push is used for IPv4, automatic IPv6 assignment from --ifconfig-ipv6-pool does not work.  Use --ifconfig-ipv6-push for IPv6 then.");
         }
     }
-    else if (mi->context.options.subnet_pool_defined)
+    else if (mi->context.options.subnet_pool_tag)
     {
-        /* dynamic address from this client's --subnet-pool group */
+        /* dynamic address(es) from this client's --subnet-pool group */
 
         /* the CCD is read after a global-pool address may already have been
-         * acquired; drop it so we can serve this client from its group */
+         * acquired; drop it so we serve this client from its group only */
         if (mi->vaddr_handle >= 0 && !mi->vaddr_pool)
         {
             ifconfig_pool_release(m->ifconfig_pool, mi->vaddr_handle, true);
             mi->vaddr_handle = -1;
+            mi->context.c2.push_ifconfig_defined = false;
+            mi->context.c2.push_ifconfig_ipv6_defined = false;
         }
 
-        if (mi->vaddr_handle < 0)
+        if ((mi->context.options.subnet_pool_defined
+             || mi->context.options.subnet_pool_ipv6_defined)
+            && mi->vaddr_handle < 0)
         {
             in_addr_t local = 0, remote = 0;
+            struct in6_addr remote_ipv6;
             const char *cn = NULL;
 
+            CLEAR(remote_ipv6);
             if (!mi->context.options.duplicate_cn)
             {
                 cn = tls_common_name(mi->context.c2.tls_multi, true);
             }
 
             mi->vaddr_pool = multi_get_group_pool(m, mi->context.options.subnet_pool_tag);
-            mi->vaddr_handle = ifconfig_pool_acquire(mi->vaddr_pool, &local, &remote, NULL, cn);
-            if (mi->vaddr_handle >= 0)
-            {
-                mi->context.c2.push_ifconfig_local = remote;
-                mi->context.c2.push_ifconfig_remote_netmask =
-                    mi->context.options.subnet_pool_netmask;
-                mi->context.c2.push_ifconfig_defined = true;
-            }
-            else
+            mi->vaddr_handle =
+                ifconfig_pool_acquire(mi->vaddr_pool, &local, &remote, &remote_ipv6, cn);
+            if (mi->vaddr_handle < 0)
             {
                 msg(D_MULTI_ERRORS, "MULTI: no free --subnet-pool addresses are available for %s",
                     multi_instance_string(mi, false, &gc));
             }
+            else
+            {
+                if (mi->context.options.subnet_pool_defined)
+                {
+                    mi->context.c2.push_ifconfig_local = remote;
+                    mi->context.c2.push_ifconfig_remote_netmask =
+                        mi->context.options.subnet_pool_netmask;
+                    mi->context.c2.push_ifconfig_defined = true;
+                }
+                if (mi->context.options.subnet_pool_ipv6_defined)
+                {
+                    mi->context.c2.push_ifconfig_ipv6_local = remote_ipv6;
+                    mi->context.c2.push_ifconfig_ipv6_remote = mi->context.c1.tuntap->local_ipv6;
+                    mi->context.c2.push_ifconfig_ipv6_netbits =
+                        mi->context.options.subnet_pool_ipv6_netbits;
+                    mi->context.c2.push_ifconfig_ipv6_defined = true;
+                }
+            }
         }
     }
     else if (m->ifconfig_pool && mi->vaddr_handle < 0) /* otherwise, choose a pool address */
@@ -2852,7 +2885,9 @@
     }
 
     if (mi->context.options.subnet_pool_tag
-        && !subnet_pool_by_tag(m->top.options.subnet_pools, mi->context.options.subnet_pool_tag))
+        && !subnet_pool_by_tag(m->top.options.subnet_pools, mi->context.options.subnet_pool_tag)
+        && !subnet_pool6_by_tag(m->top.options.subnet_pools_ipv6,
+                                mi->context.options.subnet_pool_tag))
     {
         msg(D_MULTI_ERRORS, "MULTI: client has been rejected due to unknown --subnet-pool-tag '%s'",
             mi->context.options.subnet_pool_tag);
diff --git a/src/openvpn/options.c b/src/openvpn/options.c
index c395671..027d5f8 100644
--- a/src/openvpn/options.c
+++ b/src/openvpn/options.c
@@ -7653,6 +7653,37 @@
         sp->next = options->subnet_pools;
         options->subnet_pools = sp;
     }
+    else if (streq(p[0], "subnet-pool-ipv6") && p[1] && p[2] && !p[4])
+    {
+        struct subnet_pool6_def *sp;
+        struct in6_addr network, gateway;
+        unsigned int netbits = 0;
+
+        VERIFY_PERMISSION(OPT_P_GENERAL);
+        if (!get_ipv6_addr(p[2], &network, &netbits, msglevel))
+        {
+            msg(msglevel, "cannot parse --subnet-pool-ipv6 network");
+            goto err;
+        }
+        if (netbits < 64 || netbits > 124)
+        {
+            msg(msglevel, "--subnet-pool-ipv6 network must be between /64 and /124 (not /%d)",
+                netbits);
+            goto err;
+        }
+        if (p[3] && !get_ipv6_addr(p[3], &gateway, NULL, msglevel))
+        {
+            msg(msglevel, "cannot parse --subnet-pool-ipv6 gateway");
+            goto err;
+        }
+        ALLOC_OBJ_GC(sp, struct subnet_pool6_def, &options->gc);
+        sp->tag = p[1];
+        sp->network = network;
+        sp->netbits = netbits;
+        sp->gateway = p[3] ? gateway : add_in6_addr(network, 1);
+        sp->next = options->subnet_pools_ipv6;
+        options->subnet_pools_ipv6 = sp;
+    }
     else if (streq(p[0], "subnet-pool-tag") && p[1] && !p[2])
     {
         VERIFY_PERMISSION(OPT_P_INSTANCE);
diff --git a/src/openvpn/options.h b/src/openvpn/options.h
index 0c810b3..7f0e3ce 100644
--- a/src/openvpn/options.h
+++ b/src/openvpn/options.h
@@ -261,6 +261,16 @@
     in_addr_t gateway;
 };
 
+/* The IPv6 counterpart of struct subnet_pool_def (--subnet-pool-ipv6). */
+struct subnet_pool6_def
+{
+    struct subnet_pool6_def *next;
+    const char *tag;
+    struct in6_addr network;
+    unsigned int netbits;
+    struct in6_addr gateway;
+};
+
 /* Command line options */
 struct options
 {
@@ -526,12 +536,17 @@
     bool push_ifconfig_constraint_defined;
     in_addr_t push_ifconfig_constraint_network;
     in_addr_t push_ifconfig_constraint_netmask;
-    struct subnet_pool_def *subnet_pools; /* named pools (server config) */
-    const char *subnet_pool_tag;          /* which pool this client uses (CCD) */
-    bool subnet_pool_defined;             /* resolved from the tag at connect */
+    struct subnet_pool_def *subnet_pools;       /* named IPv4 pools (server config) */
+    struct subnet_pool6_def *subnet_pools_ipv6; /* named IPv6 pools (server config) */
+    const char *subnet_pool_tag;                /* which pool this client uses (CCD) */
+    bool subnet_pool_defined;                   /* resolved from the tag at connect */
     in_addr_t subnet_pool_network;
     in_addr_t subnet_pool_netmask;
     in_addr_t subnet_pool_gateway;
+    bool subnet_pool_ipv6_defined; /* resolved from the tag at connect */
+    struct in6_addr subnet_pool_ipv6_network;
+    unsigned int subnet_pool_ipv6_netbits;
+    struct in6_addr subnet_pool_ipv6_gateway;
     bool push_ifconfig_ipv4_blocked;           /* IPv4 */
     bool push_ifconfig_ipv6_defined;           /* IPv6 */
     struct in6_addr push_ifconfig_ipv6_local;  /* IPv6 */
diff --git a/src/openvpn/options_util.c b/src/openvpn/options_util.c
index ba04917..7826458 100644
--- a/src/openvpn/options_util.c
+++ b/src/openvpn/options_util.c
@@ -44,6 +44,19 @@
     return NULL;
 }
 
+const struct subnet_pool6_def *
+subnet_pool6_by_tag(const struct subnet_pool6_def *pools, const char *tag)
+{
+    for (const struct subnet_pool6_def *d = pools; d; d = d->next)
+    {
+        if (!strcmp(d->tag, tag))
+        {
+            return d;
+        }
+    }
+    return NULL;
+}
+
 const char *
 parse_auth_failed_temp(struct options *o, const char *reason)
 {
diff --git a/src/openvpn/options_util.h b/src/openvpn/options_util.h
index c54357c..ed2017a 100644
--- a/src/openvpn/options_util.h
+++ b/src/openvpn/options_util.h
@@ -38,6 +38,10 @@
 const struct subnet_pool_def *subnet_pool_by_tag(const struct subnet_pool_def *pools,
                                                  const char *tag);
 
+/** IPv6 counterpart of subnet_pool_by_tag(). */
+const struct subnet_pool6_def *subnet_pool6_by_tag(const struct subnet_pool6_def *pools,
+                                                   const char *tag);
+
 
 /** Checks if the string is a valid integer by checking if it can be
  *  converted to an integer */

-- 
To view, visit http://gerrit.openvpn.net/c/openvpn/+/1786?usp=email
To unsubscribe, or for help writing mail filters, visit http://gerrit.openvpn.net/settings?usp=email

Gerrit-MessageType: newchange
Gerrit-Project: openvpn
Gerrit-Branch: master
Gerrit-Change-Id: I64e0850d48647a2c0e3d385c2f20a9f445931727
Gerrit-Change-Number: 1786
Gerrit-PatchSet: 1
Gerrit-Owner: ordex <[email protected]>
Gerrit-Reviewer: plaisthos <[email protected]>
Gerrit-CC: openvpn-devel <[email protected]>
Gerrit-Attention: plaisthos <[email protected]>

_______________________________________________
Openvpn-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/openvpn-devel
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.