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/+/1790?usp=email
to review the following change.
Change subject: pool, multi: persist subnet pools via --ifconfig-pool-persist
......................................................................
pool, multi: persist subnet pools via --ifconfig-pool-persist
Extend --ifconfig-pool-persist so its single file covers the global pool
and every --subnet-pool. ifconfig_pool_read()/ifconfig_pool_write() now
operate on the set of pools: each persisted entry is routed to the pool
whose address range owns it, and an entry matching no configured pool is
ignored on load (e.g. a --subnet-pool that was removed). When persist is
enabled the subnet pools are created eagerly at startup so their saved
allocations can be reloaded before the first client connects.
Change-Id: I0bff8d0a549a65b7da01ea0e785b7ec8bea17f05
GitHub: closes openvpn/OpenVPN#987
Signed-off-by: Antonio Quartulli <[email protected]>
---
M CMakeLists.txt
M doc/man-sections/server-options.rst
M src/openvpn/multi.c
M src/openvpn/options.c
M src/openvpn/pool.c
M src/openvpn/pool.h
M tests/unit_tests/openvpn/Makefile.am
A tests/unit_tests/openvpn/test_pool.c
8 files changed, 393 insertions(+), 39 deletions(-)
git pull ssh://gerrit.openvpn.net:29418/openvpn refs/changes/90/1790/1
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3463b5a..0259234 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -668,6 +668,7 @@
"test_options_parse"
"test_packet_id"
"test_pkt"
+ "test_pool"
"test_provider"
"test_socket"
"test_ssl"
@@ -835,6 +836,15 @@
src/openvpn/options_util.c
)
+ target_sources(test_pool PRIVATE
+ tests/unit_tests/openvpn/mock_get_random.c
+ src/openvpn/pool.c
+ src/openvpn/status.c
+ src/openvpn/otime.c
+ src/openvpn/fdmisc.c
+ src/openvpn/interval.c
+ )
+
target_sources(test_ncp PRIVATE
src/openvpn/crypto_epoch.c
src/openvpn/crypto_mbedtls.c
diff --git a/doc/man-sections/server-options.rst
b/doc/man-sections/server-options.rst
index 0146594..910a414 100644
--- a/doc/man-sections/server-options.rst
+++ b/doc/man-sections/server-options.rst
@@ -275,6 +275,11 @@
``file`` is a comma-delimited ASCII file, formatted as
:code:`<Common-Name>,<IP-address>`.
+ A single ``file`` covers the global pool and every ``--subnet-pool``: each
+ entry is associated with a pool by its address, and on load an entry whose
+ address falls in no configured pool (for example a ``--subnet-pool`` that is
+ no longer defined) is ignored.
+
If ``seconds`` = :code:`0`, ``file`` will be treated as read-only. This
is useful if you would like to treat ``file`` as a configuration file.
diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c
index 1cd84b6..a281764 100644
--- a/src/openvpn/multi.c
+++ b/src/openvpn/multi.c
@@ -65,6 +65,41 @@
struct ifconfig_pool *pool;
};
+static struct ifconfig_pool *multi_get_group_pool(struct multi_context *m,
+ const struct options *o,
const char *tag);
+
+/*
+ * Collect every address pool (the global one plus each --subnet-pool group)
+ * into a gc-allocated array, for the single combined --ifconfig-pool-persist
+ * file. Returns the number of pools.
+ */
+static int
+multi_all_pools(struct multi_context *m, struct gc_arena *gc, struct
ifconfig_pool ***pools)
+{
+ struct subnet_pool *sp;
+ int n = m->ifconfig_pool ? 1 : 0;
+
+ for (sp = m->subnet_pools; sp; sp = sp->next)
+ {
+ n++;
+ }
+
+ struct ifconfig_pool **arr = gc_malloc(n * sizeof(struct ifconfig_pool *),
true, gc);
+ int i = 0;
+
+ if (m->ifconfig_pool)
+ {
+ arr[i++] = m->ifconfig_pool;
+ }
+ for (sp = m->subnet_pools; sp; sp = sp->next)
+ {
+ arr[i++] = sp->pool;
+ }
+
+ *pools = arr;
+ return n;
+}
+
/*#define MULTI_DEBUG_EVENT_LOOP*/
#ifdef MULTI_DEBUG_EVENT_LOOP
@@ -161,11 +196,16 @@
void
multi_ifconfig_pool_persist(struct multi_context *m, bool force)
{
- /* write pool data to file */
- if (m->ifconfig_pool && m->top.c1.ifconfig_pool_persist
+ /* write the global pool and every --subnet-pool to the one persist file */
+ if (m->top.c1.ifconfig_pool_persist
&& (force ||
ifconfig_pool_write_trigger(m->top.c1.ifconfig_pool_persist)))
{
- ifconfig_pool_write(m->top.c1.ifconfig_pool_persist, m->ifconfig_pool);
+ struct gc_arena gc = gc_new();
+ struct ifconfig_pool **pools;
+ int n = multi_all_pools(m, &gc, &pools);
+
+ ifconfig_pool_write(m->top.c1.ifconfig_pool_persist, pools, n);
+ gc_free(&gc);
}
}
@@ -368,12 +408,29 @@
t->options.ifconfig_pool_end, t->options.duplicate_cn,
t->options.ifconfig_ipv6_pool_defined,
t->options.ifconfig_ipv6_pool_base,
t->options.ifconfig_ipv6_pool_netbits);
+ }
- /* reload pool data from file */
- if (t->c1.ifconfig_pool_persist)
+ /* With --ifconfig-pool-persist the single file covers the global pool and
+ * every configured --subnet-pool, so eagerly create the subnet pools and
+ * reload them all in one pass (entries for unknown pools are ignored). */
+ if (t->c1.ifconfig_pool_persist)
+ {
+ struct gc_arena gc = gc_new();
+ struct ifconfig_pool **pools;
+ int n;
+
+ for (const struct subnet_pool_def *d = t->options.subnet_pools; d; d =
d->next)
{
- ifconfig_pool_read(t->c1.ifconfig_pool_persist, m->ifconfig_pool);
+ multi_get_group_pool(m, &t->options, d->tag);
}
+ for (const struct subnet_pool6_def *d = t->options.subnet_pools_ipv6;
d; d = d->next)
+ {
+ multi_get_group_pool(m, &t->options, d->tag);
+ }
+
+ n = multi_all_pools(m, &gc, &pools);
+ ifconfig_pool_read(t->c1.ifconfig_pool_persist, pools, n);
+ gc_free(&gc);
}
/*
@@ -1425,7 +1482,7 @@
* on first use from the matching --subnet-pool definition.
*/
static struct ifconfig_pool *
-multi_get_group_pool(struct multi_context *m, const char *tag)
+multi_get_group_pool(struct multi_context *m, const struct options *o, const
char *tag)
{
struct subnet_pool *sp;
@@ -1437,14 +1494,13 @@
}
}
- 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);
+ const struct subnet_pool_def *d4 = subnet_pool_by_tag(o->subnet_pools,
tag);
+ const struct subnet_pool6_def *d6 =
subnet_pool6_by_tag(o->subnet_pools_ipv6, tag);
ALLOC_OBJ_CLEAR(sp, struct subnet_pool);
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,
+ d4 ? (d4->network | ~d4->netmask) - 1 : 0,
o->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;
@@ -1549,7 +1605,8 @@
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_pool =
+ multi_get_group_pool(m, &m->top.options,
mi->context.options.subnet_pool_tag);
mi->vaddr_handle =
ifconfig_pool_acquire(mi->vaddr_pool, &local, &remote,
&remote_ipv6, cn);
if (mi->vaddr_handle < 0)
diff --git a/src/openvpn/options.c b/src/openvpn/options.c
index b4485ca..40a195d 100644
--- a/src/openvpn/options.c
+++ b/src/openvpn/options.c
@@ -441,6 +441,7 @@
"--ifconfig-pool-persist file [seconds] : Persist/unpersist
ifconfig-pool\n"
" data to file, at seconds intervals (default=600).\n"
" If seconds=0, file will be treated as read-only.\n"
+ " Covers the global pool and every --subnet-pool.\n"
"--ifconfig-ipv6-pool base-IP/bits : set aside an IPv6 network block\n"
" to be dynamically allocated to connecting clients.\n"
"--subnet-pool tag network netmask [gateway] : Define a named pool of\n"
@@ -2566,10 +2567,11 @@
MUST_BE_UNDEF(route_delay_defined, "route-delay");
MUST_BE_UNDEF(up_delay, "up-delay");
if (!options->ifconfig_pool_defined &&
!options->ifconfig_ipv6_pool_defined
+ && !options->subnet_pools && !options->subnet_pools_ipv6
&& options->ifconfig_pool_persist_filename)
{
- msg(M_USAGE,
- "--ifconfig-pool-persist must be used with --ifconfig-pool or
--ifconfig-ipv6-pool");
+ msg(M_USAGE, "--ifconfig-pool-persist must be used with
--ifconfig-pool, "
+ "--ifconfig-ipv6-pool or --subnet-pool");
}
if (options->ifconfig_ipv6_pool_defined &&
!options->ifconfig_ipv6_local)
{
diff --git a/src/openvpn/pool.c b/src/openvpn/pool.c
index ff74e7c..b260cc8 100644
--- a/src/openvpn/pool.c
+++ b/src/openvpn/pool.c
@@ -583,13 +583,14 @@
}
void
-ifconfig_pool_read(struct ifconfig_pool_persist *persist, struct ifconfig_pool
*pool)
+ifconfig_pool_read(struct ifconfig_pool_persist *persist, struct ifconfig_pool
**pools,
+ int n_pools)
{
const int buf_size = 128;
update_time();
- if (persist && persist->file && pool)
+ if (persist && persist->file && n_pools > 0)
{
struct gc_arena gc = gc_new();
struct buffer in = alloc_buf_gc(256, &gc);
@@ -634,6 +635,9 @@
continue;
}
+ /* the address selects which pool this entry belongs to; an entry
+ * matching none of the configured pools is ignored */
+ struct ifconfig_pool *pool = NULL;
ifconfig_pool_handle h = -1, h6 = -1;
if (strlen(ip_buf) > 0)
@@ -647,10 +651,13 @@
}
else
{
- h = ifconfig_pool_ip_base_to_handle(pool, addr);
- if (h < 0)
+ for (int i = 0; i < n_pools && !pool; ++i)
{
- msg(M_WARN, "pool: IPv4 (%s) out of pool range for
CN=%s", ip_buf, cn_buf);
+ h = ifconfig_pool_ip_base_to_handle(pools[i], addr);
+ if (h >= 0)
+ {
+ pool = pools[i];
+ }
}
}
}
@@ -663,12 +670,20 @@
{
msg(M_WARN, "pool: invalid IPv6 (%s) for CN=%s", ip6_buf,
cn_buf);
}
+ else if (pool)
+ {
+ /* IPv4 already picked the pool; v4 and v6 share the
handle */
+ h6 = ifconfig_pool_ipv6_base_to_handle(pool, &addr6);
+ }
else
{
- h6 = ifconfig_pool_ipv6_base_to_handle(pool, &addr6);
- if (h6 < 0)
+ for (int i = 0; i < n_pools && !pool; ++i)
{
- msg(M_WARN, "pool: IPv6 (%s) out of pool range for
CN=%s", ip6_buf, cn_buf);
+ h6 = ifconfig_pool_ipv6_base_to_handle(pools[i],
&addr6);
+ if (h6 >= 0)
+ {
+ pool = pools[i];
+ }
}
/* Rely on IPv6 if no IPv4 was provided or the one provided
@@ -681,40 +696,44 @@
}
}
- /* at the moment IPv4 and IPv6 share the same pool, therefore
offsets
- * have to match for the same client.
- *
- * If offsets differ we use the IPv4, therefore warn the user
about this.
- */
+ /* IPv4 and IPv6 share the same pool handle, so their offsets have
+ * to match; if they differ we use the IPv4 and warn */
if ((h6 >= 0) && (h != h6))
{
msg(M_WARN, "pool: IPv4 (%s) and IPv6 (%s) have different
offsets! Relying on IPv4",
ip_buf, ip6_buf);
}
- /* if at least one among v4 and v6 was properly parsed, attempt
- * setting an handle for this client
- */
- if (h >= 0)
+ /* set the handle if the entry belongs to one of the pools */
+ if (pool && h >= 0)
{
- msg(M_INFO, "succeeded -> ifconfig_pool_set(hand=%d)", h);
ifconfig_pool_set(pool, cn_buf, h, persist->fixed);
}
}
- ifconfig_pool_msg(pool, D_IFCONFIG_POOL);
+ for (int i = 0; i < n_pools; ++i)
+ {
+ ifconfig_pool_msg(pools[i], D_IFCONFIG_POOL);
+ }
gc_free(&gc);
}
}
void
-ifconfig_pool_write(struct ifconfig_pool_persist *persist, const struct
ifconfig_pool *pool)
+ifconfig_pool_write(struct ifconfig_pool_persist *persist, struct
ifconfig_pool *const *pools,
+ int n_pools)
{
- if (persist && persist->file && (status_rw_flags(persist->file) &
STATUS_OUTPUT_WRITE) && pool)
+ if (persist && persist->file && (status_rw_flags(persist->file) &
STATUS_OUTPUT_WRITE))
{
status_reset(persist->file);
- ifconfig_pool_list(pool, persist->file);
+ for (int i = 0; i < n_pools; ++i)
+ {
+ if (pools[i])
+ {
+ ifconfig_pool_list(pools[i], persist->file);
+ }
+ }
status_flush(persist->file);
}
}
diff --git a/src/openvpn/pool.h b/src/openvpn/pool.h
index e2d3f82..79f3ac5 100644
--- a/src/openvpn/pool.h
+++ b/src/openvpn/pool.h
@@ -92,9 +92,15 @@
bool ifconfig_pool_write_trigger(struct ifconfig_pool_persist *persist);
-void ifconfig_pool_read(struct ifconfig_pool_persist *persist, struct
ifconfig_pool *pool);
+/* Read a persist file into a set of pools, routing each entry to the pool
+ * whose address range owns it. Entries matching no pool (e.g. a --subnet-pool
+ * that is no longer configured) are ignored. */
+void ifconfig_pool_read(struct ifconfig_pool_persist *persist, struct
ifconfig_pool **pools,
+ int n_pools);
-void ifconfig_pool_write(struct ifconfig_pool_persist *persist, const struct
ifconfig_pool *pool);
+/* Write a set of pools to a single persist file. */
+void ifconfig_pool_write(struct ifconfig_pool_persist *persist,
+ struct ifconfig_pool *const *pools, int n_pools);
#ifdef IFCONFIG_POOL_TEST
void ifconfig_pool_test(in_addr_t start, in_addr_t end);
diff --git a/tests/unit_tests/openvpn/Makefile.am
b/tests/unit_tests/openvpn/Makefile.am
index bfb7284..d1d9574 100644
--- a/tests/unit_tests/openvpn/Makefile.am
+++ b/tests/unit_tests/openvpn/Makefile.am
@@ -17,6 +17,7 @@
options_parse_testdriver \
packet_id_testdriver \
pkt_testdriver \
+ pool_testdriver \
provider_testdriver \
push_update_msg_testdriver \
socket_testdriver \
@@ -362,6 +363,23 @@
$(top_srcdir)/src/openvpn/platform.c \
$(top_srcdir)/src/openvpn/mbuf.c
+pool_testdriver_CFLAGS = \
+ -I$(top_srcdir)/include -I$(top_srcdir)/src/compat
-I$(top_srcdir)/src/openvpn \
+ @TEST_CFLAGS@
+
+pool_testdriver_LDFLAGS = @TEST_LDFLAGS@
+
+pool_testdriver_SOURCES = test_pool.c \
+ mock_msg.c test_common.h \
+ mock_get_random.c \
+ $(top_srcdir)/src/openvpn/pool.c \
+ $(top_srcdir)/src/openvpn/status.c \
+ $(top_srcdir)/src/openvpn/buffer.c \
+ $(top_srcdir)/src/openvpn/otime.c \
+ $(top_srcdir)/src/openvpn/platform.c \
+ $(top_srcdir)/src/openvpn/fdmisc.c \
+ $(top_srcdir)/src/openvpn/interval.c
+
subnet_pool_testdriver_CFLAGS = \
-I$(top_srcdir)/include -I$(top_srcdir)/src/compat
-I$(top_srcdir)/src/openvpn \
@TEST_CFLAGS@
diff --git a/tests/unit_tests/openvpn/test_pool.c
b/tests/unit_tests/openvpn/test_pool.c
new file mode 100644
index 0000000..daadb32
--- /dev/null
+++ b/tests/unit_tests/openvpn/test_pool.c
@@ -0,0 +1,237 @@
+/*
+ * OpenVPN -- An application to securely tunnel IP networks
+ * over a single UDP port, with support for SSL/TLS-based
+ * session authentication and key exchange,
+ * packet encryption, packet authentication, and
+ * packet compression.
+ *
+ * Copyright (C) 2026 OpenVPN Inc <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "syshead.h"
+
+#include <stdlib.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include "pool.h"
+#include "buffer.h"
+#include "test_common.h"
+#include "mock_msg.h"
+
+/*
+ * pool.c pulls in a few socket.c/socket_util.c helpers for address parsing and
+ * formatting. The pool logic under test does not need the full socket stack,
+ * so provide small IPv4 implementations here (the IPv6 ones are not reached by
+ * these IPv4-only pools, but must exist to link).
+ */
+struct signal_info;
+
+in_addr_t
+getaddr(unsigned int flags, const char *hostname, int resolve_retry_seconds,
bool *succeeded,
+ struct signal_info *sig_info)
+{
+ struct in_addr a;
+ int ok = inet_pton(AF_INET, hostname, &a) == 1;
+
+ if (succeeded)
+ {
+ *succeeded = ok;
+ }
+ return ok ? ntohl(a.s_addr) : 0;
+}
+
+const char *
+print_in_addr_t(in_addr_t addr, unsigned int flags, struct gc_arena *gc)
+{
+ struct in_addr a = { .s_addr = htonl(addr) };
+ char buf[INET_ADDRSTRLEN] = { 0 };
+
+ inet_ntop(AF_INET, &a, buf, sizeof(buf));
+ return string_alloc(buf, gc);
+}
+
+bool
+get_ipv6_addr(const char *hostname, struct in6_addr *network, unsigned int
*netbits,
+ msglvl_t msglevel)
+{
+ return false;
+}
+
+const char *
+print_in6_addr(struct in6_addr a6, unsigned int flags, struct gc_arena *gc)
+{
+ return "";
+}
+
+struct in6_addr
+add_in6_addr(struct in6_addr base, uint32_t add)
+{
+ return base;
+}
+
+#define IP(a, b, c, d) (((in_addr_t)(a) << 24) | ((b) << 16) | ((c) << 8) |
(d))
+
+/* three non-overlapping /24 pools: the global one and two --subnet-pool
groups */
+#define GLOBAL_START IP(10, 1, 1, 2)
+#define GLOBAL_END IP(10, 1, 1, 254)
+#define A_START IP(10, 2, 1, 2)
+#define A_END IP(10, 2, 1, 254)
+#define B_START IP(10, 2, 2, 2)
+#define B_END IP(10, 2, 2, 254)
+
+static struct ifconfig_pool *
+make_pool(in_addr_t start, in_addr_t end)
+{
+ struct in6_addr any = { 0 };
+
+ return ifconfig_pool_init(true, IFCONFIG_POOL_INDIV, start, end, false,
false, any, 0);
+}
+
+static in_addr_t
+acquire(struct ifconfig_pool *pool, const char *cn)
+{
+ in_addr_t local = 0, remote = 0;
+
+ ifconfig_pool_acquire(pool, &local, &remote, NULL, cn);
+ return remote;
+}
+
+/* whether any entry of the pool is reserved for common name cn */
+static bool
+pool_has_cn(const struct ifconfig_pool *pool, const char *cn)
+{
+ for (int i = 0; i < pool->size; ++i)
+ {
+ if (pool->list[i].common_name && !strcmp(pool->list[i].common_name,
cn))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+static const char *persist_file;
+
+/* Write {global, A, B} to one persist file, reload into a fresh set, and check
+ * that every entry was routed back to the pool that owns its address. */
+static void
+test_persist_roundtrip(void **state)
+{
+ struct ifconfig_pool *g = make_pool(GLOBAL_START, GLOBAL_END);
+ struct ifconfig_pool *a = make_pool(A_START, A_END);
+ struct ifconfig_pool *b = make_pool(B_START, B_END);
+
+ assert_int_equal(acquire(g, "alice"), GLOBAL_START);
+ assert_int_equal(acquire(a, "bob"), A_START);
+ assert_int_equal(acquire(b, "carol"), B_START);
+
+ struct ifconfig_pool *pools[] = { g, a, b };
+ struct ifconfig_pool_persist *wp =
ifconfig_pool_persist_init(persist_file, 5);
+ ifconfig_pool_write(wp, pools, 3);
+ ifconfig_pool_persist_close(wp);
+
+ struct ifconfig_pool *g2 = make_pool(GLOBAL_START, GLOBAL_END);
+ struct ifconfig_pool *a2 = make_pool(A_START, A_END);
+ struct ifconfig_pool *b2 = make_pool(B_START, B_END);
+ struct ifconfig_pool *pools2[] = { g2, a2, b2 };
+ struct ifconfig_pool_persist *rp =
ifconfig_pool_persist_init(persist_file, 0);
+ ifconfig_pool_read(rp, pools2, 3);
+ ifconfig_pool_persist_close(rp);
+
+ /* each client was routed to its own pool (handle 0 == the pool's base) */
+ assert_string_equal(g2->list[0].common_name, "alice");
+ assert_string_equal(a2->list[0].common_name, "bob");
+ assert_string_equal(b2->list[0].common_name, "carol");
+
+ /* and nowhere else */
+ assert_false(pool_has_cn(g2, "bob"));
+ assert_false(pool_has_cn(g2, "carol"));
+ assert_false(pool_has_cn(a2, "alice"));
+
+ /* the reservation is honoured: the same CN gets its persisted address
back */
+ assert_int_equal(acquire(a2, "bob"), A_START);
+
+ ifconfig_pool_free(g);
+ ifconfig_pool_free(a);
+ ifconfig_pool_free(b);
+ ifconfig_pool_free(g2);
+ ifconfig_pool_free(a2);
+ ifconfig_pool_free(b2);
+}
+
+/* An entry whose address matches no configured pool (here: B's, when B is not
+ * in the set) is ignored on load and does not disturb the other pools. */
+static void
+test_persist_ignore_unknown(void **state)
+{
+ struct ifconfig_pool *g = make_pool(GLOBAL_START, GLOBAL_END);
+ struct ifconfig_pool *a = make_pool(A_START, A_END);
+ struct ifconfig_pool *b = make_pool(B_START, B_END);
+
+ acquire(g, "alice");
+ acquire(a, "bob");
+ acquire(b, "carol");
+
+ struct ifconfig_pool *pools[] = { g, a, b };
+ struct ifconfig_pool_persist *wp =
ifconfig_pool_persist_init(persist_file, 5);
+ ifconfig_pool_write(wp, pools, 3);
+ ifconfig_pool_persist_close(wp);
+
+ /* reload into a set WITHOUT pool B: carol's entry now matches no pool */
+ struct ifconfig_pool *g2 = make_pool(GLOBAL_START, GLOBAL_END);
+ struct ifconfig_pool *a2 = make_pool(A_START, A_END);
+ struct ifconfig_pool *pools2[] = { g2, a2 };
+ struct ifconfig_pool_persist *rp =
ifconfig_pool_persist_init(persist_file, 0);
+ ifconfig_pool_read(rp, pools2, 2);
+ ifconfig_pool_persist_close(rp);
+
+ assert_string_equal(g2->list[0].common_name, "alice");
+ assert_string_equal(a2->list[0].common_name, "bob");
+ assert_false(pool_has_cn(g2, "carol"));
+ assert_false(pool_has_cn(a2, "carol"));
+
+ ifconfig_pool_free(g);
+ ifconfig_pool_free(a);
+ ifconfig_pool_free(b);
+ ifconfig_pool_free(g2);
+ ifconfig_pool_free(a2);
+}
+
+const struct CMUnitTest pool_tests[] = {
+ cmocka_unit_test(test_persist_roundtrip),
+ cmocka_unit_test(test_persist_ignore_unknown),
+};
+
+int
+main(void)
+{
+ char template[] = "/tmp/ovpn_pool_persist_ut.XXXXXX";
+ int fd = mkstemp(template);
+
+ assert_true(fd >= 0);
+ close(fd);
+ persist_file = template;
+
+ openvpn_unit_test_setup();
+ int ret = cmocka_run_group_tests(pool_tests, NULL, NULL);
+
+ unlink(template);
+ return ret;
+}
--
To view, visit http://gerrit.openvpn.net/c/openvpn/+/1790?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: I0bff8d0a549a65b7da01ea0e785b7ec8bea17f05
Gerrit-Change-Number: 1790
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