From patchwork Fri May 29 14:05:55 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Antonio Quartulli X-Patchwork-Id: 1138 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director11.mail.ord1d.rsapps.net ([172.27.255.7]) by backend30.mail.ord1d.rsapps.net with LMTP id AJzUAuqj0V5mEwAAIUCqbw for ; Fri, 29 May 2020 20:08:10 -0400 Received: from proxy18.mail.iad3a.rsapps.net ([172.27.255.7]) by director11.mail.ord1d.rsapps.net with LMTP id AN9DAOqj0V6WGwAAvGGmqA ; Fri, 29 May 2020 20:08:10 -0400 Received: from smtp31.gate.iad3a ([172.27.255.7]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy18.mail.iad3a.rsapps.net with LMTP id mCoMNumj0V5VUQAAon3hFg ; Fri, 29 May 2020 20:08:09 -0400 X-Spam-Threshold: 95 X-Spam-Score: 0 X-Spam-Flag: NO X-Virus-Scanned: OK X-Orig-To: openvpnslackdevel@openvpn.net X-Originating-Ip: [216.105.38.7] Authentication-Results: smtp31.gate.iad3a.rsapps.net; iprev=pass policy.iprev="216.105.38.7"; spf=pass smtp.mailfrom="openvpn-devel-bounces@lists.sourceforge.net" smtp.helo="lists.sourceforge.net"; dkim=fail (signature verification failed) header.d=sourceforge.net; dkim=fail (signature verification failed) header.d=sf.net; dmarc=none (p=nil; dis=none) header.from=unstable.cc X-Suspicious-Flag: YES X-Classification-ID: a4c4fa72-a209-11ea-af60-5254003d9392-1-1 Received: from [216.105.38.7] ([216.105.38.7:35864] helo=lists.sourceforge.net) by smtp31.gate.iad3a.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id 74/28-10615-9E3A1DE5; Fri, 29 May 2020 20:08:09 -0400 Received: from [127.0.0.1] (helo=sfs-ml-4.v29.lw.sourceforge.com) by sfs-ml-4.v29.lw.sourceforge.com with esmtp (Exim 4.90_1) (envelope-from ) id 1jep1x-0003j9-LQ; Sat, 30 May 2020 00:07:17 +0000 Received: from [172.30.20.202] (helo=mx.sourceforge.net) by sfs-ml-4.v29.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.90_1) (envelope-from ) id 1jep1g-0003iA-Vh for openvpn-devel@lists.sourceforge.net; Sat, 30 May 2020 00:07:01 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=Content-Transfer-Encoding:MIME-Version:References: In-Reply-To:Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=LOMCIy61p7RNITj2A0emHjqyitwo23Suhy3mRERiNtg=; b=lC71/VoGhh7rpfHV6ebdbIwp2G nm2IJ27RyxMAIlJcg+Y63zGD4EByjPN88U82nIAjIjDZpQIZKvWhxI4N88AMksR4HPLFFDprKvxSz Rr/2IH1hfig0WIJxkWTEyQWbxXPZGmAgEFswpvkOaCpp1AYSOReDmGnxYuzbi93wiT6o=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-Id: Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=LOMCIy61p7RNITj2A0emHjqyitwo23Suhy3mRERiNtg=; b=MFZ5cyOhjxaofAmMb+f2lKzy1U ahBs0rPCcQD3K4a1tFf45122kHW96RT28e3qeSNmSCeI3wpBYESfJS3YmyhGCDB5SqXH7aDcSqpq0 b/Ir6fqDlVQBc84M+UhCKOHyzGS6wyxrXJcSHpxKUql3QBtB2X7k9SeSCjbHFHek5FN0=; Received: from s2.neomailbox.net ([5.148.176.60]) by sfi-mx-1.v28.lw.sourceforge.com with esmtps (TLSv1.2:DHE-RSA-AES256-GCM-SHA384:256) (Exim 4.92.2) id 1jep1c-00D3dv-P5 for openvpn-devel@lists.sourceforge.net; Sat, 30 May 2020 00:07:00 +0000 From: Antonio Quartulli To: openvpn-devel@lists.sourceforge.net Date: Sat, 30 May 2020 02:05:55 +0200 Message-Id: <20200530000600.1680-3-a@unstable.cc> In-Reply-To: <20200530000600.1680-1-a@unstable.cc> References: <20200530000600.1680-1-a@unstable.cc> MIME-Version: 1.0 X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. 0.0 URIBL_BLOCKED ADMINISTRATOR NOTICE: The query to URIBL was blocked. See http://wiki.apache.org/spamassassin/DnsBlocklists#dnsbl-block for more information. [URIs: openvpn.net] -0.0 SPF_HELO_PASS SPF: HELO matches SPF record -0.0 SPF_PASS SPF: sender matches SPF record 0.0 AWL AWL: Adjusted score from AWL reputation of From: address X-Headers-End: 1jep1c-00D3dv-P5 Subject: [Openvpn-devel] [PATCH v4 2/7] pool: allow to configure an IPv6-only ifconfig-pool X-BeenThere: openvpn-devel@lists.sourceforge.net X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Antonio Quartulli Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox From: Antonio Quartulli With this change a server is allowed to allocate an IPv6-only pool. This is required to make it capable of managing an IPv6-only tunnel. Trac: #208 Signed-off-by: Antonio Quartulli --- Changes from v3: - properly compute pool size taking into account the actual base address src/openvpn/multi.c | 10 ++- src/openvpn/pool.c | 181 ++++++++++++++++++++++++++++++++------------ src/openvpn/pool.h | 8 +- 3 files changed, 146 insertions(+), 53 deletions(-) diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index 7f61350d..2fbbe9ec 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -388,7 +388,8 @@ multi_init(struct multi_context *m, struct context *t, bool tcp_mode, int thread * differently based on whether a tun or tap style * tunnel. */ - if (t->options.ifconfig_pool_defined) + if (t->options.ifconfig_pool_defined + || t->options.ifconfig_ipv6_pool_defined) { int pool_type = IFCONFIG_POOL_INDIV; @@ -397,7 +398,8 @@ multi_init(struct multi_context *m, struct context *t, bool tcp_mode, int thread pool_type = IFCONFIG_POOL_30NET; } - m->ifconfig_pool = ifconfig_pool_init(pool_type, + m->ifconfig_pool = ifconfig_pool_init(t->options.ifconfig_pool_defined, + pool_type, t->options.ifconfig_pool_start, t->options.ifconfig_pool_end, t->options.duplicate_cn, @@ -1495,7 +1497,9 @@ multi_select_virtual_addr(struct multi_context *m, struct multi_instance *mi) const int tunnel_topology = TUNNEL_TOPOLOGY(mi->context.c1.tuntap); msg( M_INFO, "MULTI_sva: pool returned IPv4=%s, IPv6=%s", - print_in_addr_t( remote, 0, &gc ), + (mi->context.options.ifconfig_pool_defined + ? print_in_addr_t(remote, 0, &gc) + : "(Not enabled)"), (mi->context.options.ifconfig_ipv6_pool_defined ? print_in6_addr( remote_ipv6, 0, &gc ) : "(Not enabled)") ); diff --git a/src/openvpn/pool.c b/src/openvpn/pool.c index 6dd72bb9..48f3ec95 100644 --- a/src/openvpn/pool.c +++ b/src/openvpn/pool.c @@ -58,6 +58,29 @@ ifconfig_pool_entry_free(struct ifconfig_pool_entry *ipe, bool hard) } } +static const int +ifconfig_pool_size(const struct ifconfig_pool *pool) +{ + int min = INT_MAX; + + if (!pool->ipv4.enabled && !pool->ipv6.enabled) + { + return 0; + } + + if (pool->ipv4.enabled) + { + min = pool->ipv4.size; + } + + if (pool->ipv6.enabled && pool->ipv6.size < min) + { + min = pool->ipv6.size; + } + + return min; +} + static int ifconfig_pool_find(struct ifconfig_pool *pool, const char *common_name) { @@ -65,8 +88,9 @@ ifconfig_pool_find(struct ifconfig_pool *pool, const char *common_name) time_t earliest_release = 0; int previous_usage = -1; int new_usage = -1; + int pool_size = ifconfig_pool_size(pool); - for (i = 0; i < pool->ipv4.size; ++i) + for (i = 0; i < pool_size; ++i) { struct ifconfig_pool_entry *ipe = &pool->list[i]; if (!ipe->in_use) @@ -147,34 +171,43 @@ ifconfig_pool_verify_range(const int msglevel, const in_addr_t start, const in_a } struct ifconfig_pool * -ifconfig_pool_init(enum pool_type type, in_addr_t start, in_addr_t end, - const bool duplicate_cn, +ifconfig_pool_init(const bool ipv4_pool, enum pool_type type, in_addr_t start, + in_addr_t end, const bool duplicate_cn, const bool ipv6_pool, const struct in6_addr ipv6_base, const int ipv6_netbits ) { struct gc_arena gc = gc_new(); struct ifconfig_pool *pool = NULL; + int pool_size = -1; ASSERT(start <= end && end - start < IFCONFIG_POOL_MAX); ALLOC_OBJ_CLEAR(pool, struct ifconfig_pool); - pool->ipv4.type = type; pool->duplicate_cn = duplicate_cn; - switch (pool->ipv4.type) + pool->ipv4.enabled = ipv4_pool; + + if (pool->ipv4.enabled) { - case IFCONFIG_POOL_30NET: - pool->ipv4.base = start & ~3; - pool->ipv4.size = (((end | 3) + 1) - pool->ipv4.base) >> 2; - break; + pool->ipv4.type = type; + switch (pool->ipv4.type) + { + case IFCONFIG_POOL_30NET: + pool->ipv4.base = start & ~3; + pool->ipv4.size = (((end | 3) + 1) - pool->ipv4.base) >> 2; + break; - case IFCONFIG_POOL_INDIV: - pool->ipv4.base = start; - pool->ipv4.size = end - start + 1; - break; + case IFCONFIG_POOL_INDIV: + pool->ipv4.base = start; + pool->ipv4.size = end - start + 1; + break; - default: - ASSERT(0); + default: + ASSERT(0); + } + + msg(D_IFCONFIG_POOL, "IFCONFIG POOL: base=%s size=%d", + print_in_addr_t(pool->ipv4.base, 0, &gc), pool->ipv4.size); } /* IPv6 pools are always "INDIV" type */ @@ -182,26 +215,60 @@ ifconfig_pool_init(enum pool_type type, in_addr_t start, in_addr_t end, if (pool->ipv6.enabled) { + /* the host portion of the address will always be contained in the last + * 4 bytes, therefore we can just extract that and use it as base in + * integer form + */ + uint32_t base = (ipv6_base.s6_addr[12] << 24) + | (ipv6_base.s6_addr[13] << 16) + | (ipv6_base.s6_addr[14] << 8) + | ipv6_base.s6_addr[15]; + /* some bits of the last 4 bytes may still be part of the network + * portion of the address, therefore we need to set them to 0 + */ + if ((128 - ipv6_netbits) < 32) + { + /* extract only the bits that are really part of the host portion of + * the address. + * + * Example: if we have netbits=31, the first bit has to be zero'd, + * the following operation first computes off=0x3fffff and then uses + * mask to extract the wanted bits from base + */ + uint32_t mask = (1 << (128 - ipv6_netbits - 1)) - 1; + base &= mask; + } + pool->ipv6.base = ipv6_base; - pool->ipv6.size = ipv6_netbits > 112 ? (1 << (128 - ipv6_netbits)) + pool->ipv6.size = ipv6_netbits > 112 + ? (1 << (128 - ipv6_netbits)) - base : IFCONFIG_POOL_MAX; - msg( D_IFCONFIG_POOL, "IFCONFIG POOL IPv6: (IPv4) size=%d, size_ipv6=%d, netbits=%d, base_ipv6=%s", - pool->ipv4.size, pool->ipv6.size, ipv6_netbits, - print_in6_addr(pool->ipv6.base, 0, &gc)); + msg(D_IFCONFIG_POOL, "IFCONFIG POOL IPv6: base=%s size=%d netbits=%d", + print_in6_addr(pool->ipv6.base, 0, &gc), pool->ipv6.size, + ipv6_netbits); + } - /* the current code is very simple and assumes that the IPv6 - * pool is at least as big as the IPv4 pool, and we don't need - * to do separate math etc. for IPv6 - */ - ASSERT(pool->ipv4.size < pool->ipv6.size); + if (pool->ipv4.enabled && pool->ipv6.enabled) + { + if (pool->ipv4.size < pool->ipv6.size) + { + msg(M_INFO, "NOTE: IPv4 pool size is %d, IPv6 pool size is %d. " + "IPv4 pool size limits the number of clients that can be " + "served from the pool", pool->ipv4.size, pool->ipv6.size); + } + else if (pool->ipv4.size > pool->ipv6.size) + { + msg(M_WARN, "WARNING: IPv4 pool size is %d, IPv6 pool size is %d. " + "IPv6 pool size limits the number of clients that can be " + "served from the pool. This is likely a MISTAKE - please check " + "your configuration", pool->ipv4.size, pool->ipv6.size); + } } - ALLOC_ARRAY_CLEAR(pool->list, struct ifconfig_pool_entry, pool->ipv4.size); + pool_size = ifconfig_pool_size(pool); - msg(D_IFCONFIG_POOL, "IFCONFIG POOL: base=%s size=%d, ipv6=%d", - print_in_addr_t(pool->ipv4.base, 0, &gc), - pool->ipv4.size, pool->ipv6.enabled); + ALLOC_ARRAY_CLEAR(pool->list, struct ifconfig_pool_entry, pool_size); gc_free(&gc); return pool; @@ -212,8 +279,9 @@ ifconfig_pool_free(struct ifconfig_pool *pool) { if (pool) { - int i; - for (i = 0; i < pool->ipv4.size; ++i) + int i, pool_size = ifconfig_pool_size(pool); + + for (i = 0; i < pool_size; ++i) { ifconfig_pool_entry_free(&pool->list[i], true); } @@ -239,26 +307,29 @@ ifconfig_pool_acquire(struct ifconfig_pool *pool, in_addr_t *local, in_addr_t *r ipe->common_name = string_alloc(common_name, NULL); } - switch (pool->ipv4.type) + if (pool->ipv4.enabled && local && remote) { - case IFCONFIG_POOL_30NET: + switch (pool->ipv4.type) { - in_addr_t b = pool->ipv4.base + (i << 2); - *local = b + 1; - *remote = b + 2; - break; - } + case IFCONFIG_POOL_30NET: + { + in_addr_t b = pool->ipv4.base + (i << 2); + *local = b + 1; + *remote = b + 2; + break; + } - case IFCONFIG_POOL_INDIV: - { - in_addr_t b = pool->ipv4.base + i; - *local = 0; - *remote = b; - break; - } + case IFCONFIG_POOL_INDIV: + { + in_addr_t b = pool->ipv4.base + i; + *local = 0; + *remote = b; + break; + } - default: - ASSERT(0); + default: + ASSERT(0); + } } /* IPv6 pools are always INDIV (--linear) */ @@ -274,7 +345,9 @@ bool ifconfig_pool_release(struct ifconfig_pool *pool, ifconfig_pool_handle hand, const bool hard) { bool ret = false; - if (pool && hand >= 0 && hand < pool->ipv4.size) + int pool_size = ifconfig_pool_size(pool); + + if (pool && hand >= 0 && hand < pool_size) { ifconfig_pool_entry_free(&pool->list[hand], hard); ret = true; @@ -286,6 +359,7 @@ ifconfig_pool_release(struct ifconfig_pool *pool, ifconfig_pool_handle hand, con * private access functions */ +/* currently handling IPv4 logic only */ static ifconfig_pool_handle ifconfig_pool_ip_base_to_handle(const struct ifconfig_pool *pool, const in_addr_t addr) { @@ -380,9 +454,9 @@ ifconfig_pool_list(const struct ifconfig_pool *pool, struct status_output *out) if (pool && out) { struct gc_arena gc = gc_new(); - int i; + int i, pool_size = ifconfig_pool_size(pool); - for (i = 0; i < pool->ipv4.size; ++i) + for (i = 0; i < pool_size; ++i) { const struct ifconfig_pool_entry *e = &pool->list[i]; if (e->common_name) @@ -475,6 +549,15 @@ ifconfig_pool_read(struct ifconfig_pool_persist *persist, struct ifconfig_pool * const int buf_size = 128; update_time(); + + /* IPv6 logic not implemented yet, therefore bail out if no IPv4 pool was + * configured + */ + if (pool && !pool->ipv4.enabled) + { + return; + } + if (persist && persist->file && pool) { struct gc_arena gc = gc_new(); diff --git a/src/openvpn/pool.h b/src/openvpn/pool.h index 73ea5599..6af04645 100644 --- a/src/openvpn/pool.h +++ b/src/openvpn/pool.h @@ -52,6 +52,7 @@ struct ifconfig_pool { bool duplicate_cn; struct { + bool enabled; enum pool_type type; in_addr_t base; int size; @@ -72,7 +73,12 @@ struct ifconfig_pool_persist typedef int ifconfig_pool_handle; -struct ifconfig_pool *ifconfig_pool_init(enum pool_type type, in_addr_t start, in_addr_t end, const bool duplicate_cn, const bool ipv6_pool, const struct in6_addr ipv6_base, const int ipv6_netbits ); +struct ifconfig_pool *ifconfig_pool_init(const bool ipv4_pool, + enum pool_type type, in_addr_t start, + in_addr_t end, const bool duplicate_cn, + const bool ipv6_pool, + const struct in6_addr ipv6_base, + const int ipv6_netbits); void ifconfig_pool_free(struct ifconfig_pool *pool);