From patchwork Mon Sep 9 15:12:55 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "ralf_lici (Code Review)" X-Patchwork-Id: 3814 Return-Path: Delivered-To: patchwork@openvpn.net Received: by 2002:a05:7000:6bd4:b0:5b9:581e:f939 with SMTP id c20csp1579591max; Mon, 9 Sep 2024 08:13:19 -0700 (PDT) X-Forwarded-Encrypted: i=2; AJvYcCWsXP1OIHpKNvjeC44cAVVTNJE4rTmFuEhA23mCdCJWQoxcaVnrgEyHaNv9gQ4+8IxFkVsbg/lVjks=@openvpn.net X-Google-Smtp-Source: AGHT+IHQEpnKn/3PAazCrwnheS5WotANHqzas/y/vkSoAQk3fFY2d28nrxuuxNugFWHuxFTeeM5j X-Received: by 2002:a05:6602:3fd5:b0:82a:217c:eb94 with SMTP id ca18e2360f4ac-82a9622ad68mr1263756439f.13.1725894799120; Mon, 09 Sep 2024 08:13:19 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1725894799; cv=none; d=google.com; s=arc-20240605; b=ZYeZLOtxSe8vipGTo9KUpXXW8Krnsr8ytBBmppPtk4ecclxjgvTz9l7EanMvYVA4nu 0NA0XxKpvbjoIiBZcgCgjrtOg5+kZTh706Moacjlm4o8/fjGRedhTfIiTqTf3TuuJNsE AOK3k24bdkZ/FHJUyAdtmhQueli2CkiSR6DAk4LCAVGNHVu2sR28Dd3tn2nrT8C64ZqM hDhJ5sckb5mlberbn6jb4aCdqddqmBdYYiTJiyyJ9eZNBqP0NicQSZFPH/DIFGVeAGS3 529kpFQ3pmOu1JRPAtPqwUeSFFjK+1GmJWy6h72lbudwJ69wbF1wKaIV9yX3nj73EdlW Cvvw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=errors-to:cc:reply-to:list-subscribe:list-help:list-post :list-archive:list-unsubscribe:list-id:precedence:subject:user-agent :mime-version:message-id:references:auto-submitted:to:date:from :dkim-signature:dkim-signature:dkim-signature; bh=LJ9JaTZfTewWZHRXruRUwooQOMlLKIYLPh+FK2ZxB9s=; fh=U7wEyxtwz2o5+UdevFSA47vNeG9knhWH0KV//QhD5a0=; b=gxRaL04oy7iF4CDqfWoK6i4jJE/NMgyUKODCV7/nODmqLFeg2JD/Pb7gulE4eTr32j lym90hVcyb4YsowXBDNNDSD//ciAKM2S7A1vKQUiD+vGyMaSnm2mWMT2TQKHh0rUCIMU Di1ZLrWMHr3qw8XR6y5sZ/1RL366Rd8tDSVnpcItzfwgHAp2kkvAikLw8rmpyqgm06eh DNI1Y5+tP2D4QJulpdEdtPLfEXGfa4WiNu9b1Fo/zvSKy36IWeowIIq1bebFyYWI4Gli WTFIx/3cvH2wGjBF6L6CQcPLxuw52v3JT9c9XWWnf+wJcL3Rz5g8uyI+2FI6IW1kEJuX Zq3Q==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=h+F4HRWa; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=jZFSa6+p; dkim=neutral (body hash did not verify) header.i=@openvpn.net header.s=google header.b="drPwvj/5"; spf=pass (google.com: domain of openvpn-devel-bounces@lists.sourceforge.net designates 216.105.38.7 as permitted sender) smtp.mailfrom=openvpn-devel-bounces@lists.sourceforge.net; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=openvpn.net; dara=fail header.i=@openvpn.net Received: from lists.sourceforge.net (lists.sourceforge.net. [216.105.38.7]) by mx.google.com with ESMTPS id ca18e2360f4ac-82aa733ce96si236955439f.11.2024.09.09.08.13.18 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 09 Sep 2024 08:13:19 -0700 (PDT) Received-SPF: pass (google.com: domain of openvpn-devel-bounces@lists.sourceforge.net designates 216.105.38.7 as permitted sender) client-ip=216.105.38.7; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=h+F4HRWa; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=jZFSa6+p; dkim=neutral (body hash did not verify) header.i=@openvpn.net header.s=google header.b="drPwvj/5"; spf=pass (google.com: domain of openvpn-devel-bounces@lists.sourceforge.net designates 216.105.38.7 as permitted sender) smtp.mailfrom=openvpn-devel-bounces@lists.sourceforge.net; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=openvpn.net; dara=fail header.i=@openvpn.net Received: from [127.0.0.1] (helo=sfs-ml-2.v29.lw.sourceforge.com) by sfs-ml-2.v29.lw.sourceforge.com with esmtp (Exim 4.95) (envelope-from ) id 1sng4m-0002vd-I1; Mon, 09 Sep 2024 15:13:12 +0000 Received: from [172.30.29.66] (helo=mx.sourceforge.net) by sfs-ml-2.v29.lw.sourceforge.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.95) (envelope-from ) id 1sng4l-0002vT-6l for openvpn-devel@lists.sourceforge.net; Mon, 09 Sep 2024 15:13:11 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=Content-Type:Content-Transfer-Encoding:MIME-Version :Message-ID:Reply-To:References:Subject:List-Unsubscribe:List-Id:Cc:To:Date: From:Sender:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:List-Help: List-Subscribe:List-Post:List-Owner:List-Archive; bh=iXz2xC934JZK/JcZmQ+A9VZlrbtQPuh3Z+3PBtZaI6I=; b=h+F4HRWaoNG6gv/Bn93gjyR17l XlB6M++DyC6Nfios/4NEpl3sQSkfmiu4zeg7nDgCpeRoITmKMvlYcaEu33ordkwUmxuiDB5Mv0bnS mHi0KF5JqwcVuIXdG0XCvqUtZ54E8tk8ep8bv13eqn5o6fDX3mR/cj1DVf3U9TKZBsYY=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Content-Type:Content-Transfer-Encoding:MIME-Version:Message-ID:Reply-To: References:Subject:List-Unsubscribe:List-Id:Cc:To:Date:From:Sender:Content-ID :Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To: Resent-Cc:Resent-Message-ID:In-Reply-To:List-Help:List-Subscribe:List-Post: List-Owner:List-Archive; bh=iXz2xC934JZK/JcZmQ+A9VZlrbtQPuh3Z+3PBtZaI6I=; b=j ZFSa6+pWqxK4ykE5K9KL0chIo4oS79VLn00Xw8JtzB+iqliOMPmTJRktYf5S3pfA9a70gqXl3l2hG EhyvXMvAoyvQAQU/o+BxKK/baSN1bZjTWFRz7chvMm3nRQrd2sm6xXVbSvegMIBmO4o/CUn0IWKxv Uy0uzt37OJ45ygPs=; Received: from mail-wm1-f54.google.com ([209.85.128.54]) by sfi-mx-2.v28.lw.sourceforge.com with esmtps (TLS1.2:ECDHE-RSA-AES128-GCM-SHA256:128) (Exim 4.95) id 1sng4e-0005xC-Rh for openvpn-devel@lists.sourceforge.net; Mon, 09 Sep 2024 15:13:11 +0000 Received: by mail-wm1-f54.google.com with SMTP id 5b1f17b1804b1-42cbaf9bfdbso5222905e9.0 for ; Mon, 09 Sep 2024 08:13:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=openvpn.net; s=google; t=1725894778; x=1726499578; darn=lists.sourceforge.net; h=user-agent:content-disposition:content-transfer-encoding :mime-version:message-id:reply-to:references:subject :list-unsubscribe:list-id:auto-submitted:cc:to:date:from:from:to:cc :subject:date:message-id:reply-to; bh=iXz2xC934JZK/JcZmQ+A9VZlrbtQPuh3Z+3PBtZaI6I=; b=drPwvj/5AFN0uWA9U2WVhbVjKavX1gZvMOhtu/YdiwJ59ahnC7g7COV/l95Eu6PtWT BQjKMsJjkjs3SC7H3EQSO6mG+rbauR2kBds/RgegZqjFQ5rhOHzoduPc4oKOEYttHwhs uuRhAw9ec0rPehOe6ykD+L7yXmCPe7YKCBY17JelATFF1czZsoJnkTJLY3Wpb65ZFUhl AT7g+lXvytZ6wVjqUfcvZ3LYVgFK9XsXv0tck31PEu7LHPLVfhFBA/a2e2zv+xlRssAO hXFPStei19hdt0b19Sg5t1SIx3Imh02WV8qRfn7zm4Q1j4S2TC8ju6lUnZPdnfPHc1Xu yvKQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1725894778; x=1726499578; h=user-agent:content-disposition:content-transfer-encoding :mime-version:message-id:reply-to:references:subject :list-unsubscribe:list-id:auto-submitted:cc:to:date:from :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=iXz2xC934JZK/JcZmQ+A9VZlrbtQPuh3Z+3PBtZaI6I=; b=VX7V8Hj9z6fASyijC/8buzvniLWlJnvFCkj5/cRxGCF3SImh1kmF/MyQ+6A7UJQJf1 +KDIGh01eXiDP3nANViJj1Gvt+IswBq0TU53ezq7ROBW+KEfvFazKJVSt5cu5qlF9x/x ohsnQPUl09FTyDzyIPQPJY2lvvAjrByQwTBdt7643OIHDwbEp+1QytOKnenjyO8EUrv7 HWWe2WadRYBX7NC2F9ot4PvFqR6up9AoZkyk9dBLha1CicelYvlS+DtuhK2MUmWcFjWd bvr1wiuK98g946w2/F7Uj3Kp07Exwo+yZ5DJfjnpkbcZ4EcsH5gXNejRmQPbWLuSI74t aQmw== X-Gm-Message-State: AOJu0Yz962tdkERSkQf6lrEZO+en6W5OGfyzhzRTAt3yjE3oOgCmXh5n aWn+U2RwUsk5FfTAPZNORg7q5QQei3OQ1kfdwIc5rDkL1i/sczdIWtktjQsW2lA= X-Received: by 2002:a05:600c:3144:b0:42c:87dc:85e7 with SMTP id 5b1f17b1804b1-42c9f9879efmr74665945e9.18.1725894777145; Mon, 09 Sep 2024 08:12:57 -0700 (PDT) Received: from gerrit.openvpn.in (ec2-18-159-0-78.eu-central-1.compute.amazonaws.com. [18.159.0.78]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-42cb742d0a1sm41088435e9.2.2024.09.09.08.12.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 09 Sep 2024 08:12:56 -0700 (PDT) From: "ralf_lici (Code Review)" X-Google-Original-From: "ralf_lici (Code Review)" X-Gerrit-PatchSet: 1 Date: Mon, 9 Sep 2024 15:12:55 +0000 To: plaisthos , flichtenheld Auto-Submitted: auto-generated X-Gerrit-MessageType: newchange X-Gerrit-Change-Id: Iae04ad8715e40dfc76475c2c5b9a766c9604efc9 X-Gerrit-Change-Number: 739 X-Gerrit-Project: openvpn X-Gerrit-ChangeURL: X-Gerrit-Commit: f83c5e7781e50d7e7b38b26a3007a6d8e6e98ffe References: Message-ID: <36ae7618c415a2084827364fe4cf304b42c7987f-HTML@gerrit.openvpn.net> MIME-Version: 1.0 User-Agent: Gerrit/3.8.2 X-Spam-Score: -0.2 (/) X-Spam-Report: Spam detection software, running on the system "util-spamd-1.v13.lw.sourceforge.com", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: Attention is currently required from: flichtenheld, plaisthos. Hello plaisthos, flichtenheld, I'd like you to do a code review. Please visit Content analysis details: (-0.2 points, 6.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [209.85.128.54 listed in list.dnswl.org] -0.0 RCVD_IN_MSPIKE_H2 RBL: Average reputation (+2) [209.85.128.54 listed in wl.mailspike.net] -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 0.0 WEIRD_PORT URI: Uses non-standard port number for HTTP 0.0 HTML_MESSAGE BODY: HTML included in message -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.0 T_KAM_HTML_FONT_INVALID Test for Invalidly Named or Formatted Colors in HTML X-Headers-End: 1sng4e-0005xC-Rh Subject: [Openvpn-devel] [L] Change in openvpn[master]: Support CIDR on options and extend netbits usage 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: , Reply-To: ralf@mandelbit.com, arne-openvpn@rfc2549.org, openvpn-devel@lists.sourceforge.net, frank@lichtenheld.com Cc: openvpn-devel Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox X-GMAIL-THRID: =?utf-8?q?1809731864746554314?= X-GMAIL-MSGID: =?utf-8?q?1809731864746554314?= X-getmail-filter-classifier: gerrit message type newchange Attention is currently required from: flichtenheld, plaisthos. Hello plaisthos, flichtenheld, I'd like you to do a code review. Please visit http://gerrit.openvpn.net/c/openvpn/+/739?usp=email to review the following change. Change subject: Support CIDR on options and extend netbits usage ...................................................................... Support CIDR on options and extend netbits usage Add support for CIDR notation on all suitable options (client-nat, ifconfig, ifconfig-pull, ifconfig-push, ifconfig-push-constraint, iroute, route, server, server-bridge). Anyway push of ifconfig is done without CIDR in order to support older peers. Also netmask env vars have been preserved while also introducing the corresponding netbits vars. Some of the internal logic has also been modified to use netbits instead of netmasks. Change-Id: Iae04ad8715e40dfc76475c2c5b9a766c9604efc9 Signed-off-by: Ralf Lici --- M src/openvpn/basic.h M src/openvpn/clinat.c M src/openvpn/clinat.h M src/openvpn/helper.c M src/openvpn/init.c M src/openvpn/manage.c M src/openvpn/multi.c M src/openvpn/options.c M src/openvpn/options.h M src/openvpn/pool.c M src/openvpn/push.c M src/openvpn/route.c M src/openvpn/route.h M src/openvpn/socket.c M src/openvpn/socket.h M src/openvpn/tun.c M src/openvpn/tun.h 17 files changed, 521 insertions(+), 284 deletions(-) git pull ssh://gerrit.openvpn.net:29418/openvpn refs/changes/39/739/1 diff --git a/src/openvpn/basic.h b/src/openvpn/basic.h index d1075b2..6658008 100644 --- a/src/openvpn/basic.h +++ b/src/openvpn/basic.h @@ -33,5 +33,6 @@ #define CLEAR(x) memset(&(x), 0, sizeof(x)) #define IPV4_NETMASK_HOST 0xffffffffU +#define IPV4_NETBITS_HOST 32U #endif diff --git a/src/openvpn/clinat.c b/src/openvpn/clinat.c index 2d3b359..eaf5abb 100644 --- a/src/openvpn/clinat.c +++ b/src/openvpn/clinat.c @@ -31,6 +31,7 @@ #include "proto.h" #include "socket.h" #include "memdbg.h" +#include "route.h" static bool add_entry(struct client_nat_option_list *dest, @@ -60,11 +61,11 @@ for (i = 0; i < list->n; ++i) { const struct client_nat_entry *e = &list->entries[i]; - msg(msglevel, " CNAT[%d] t=%d %s/%s/%s", + msg(msglevel, " CNAT[%d] t=%d %s/%d %s", i, e->type, print_in_addr_t(e->network, IA_NET_ORDER, &gc), - print_in_addr_t(e->netmask, IA_NET_ORDER, &gc), + e->netbits, print_in_addr_t(e->foreign_network, IA_NET_ORDER, &gc)); } } @@ -111,6 +112,7 @@ int msglevel) { struct client_nat_entry e; + unsigned int netbits = 0; bool ok; if (!strcmp(type, "snat")) @@ -127,19 +129,35 @@ return; } - e.network = getaddr(0, network, 0, &ok, NULL); + e.network = getaddr(0, network, &netbits, 0, &ok, NULL); if (!ok) { msg(msglevel, "client-nat: bad network: %s", network); return; } - e.netmask = getaddr(0, netmask, 0, &ok, NULL); - if (!ok) + if (netmask) { - msg(msglevel, "client-nat: bad netmask: %s", netmask); + const in_addr_t mask = getaddr(0, netmask, NULL, 0, &ok, NULL); + const int bits = netmask_to_netbits2(mask); + + if (!ok || bits <= 0) + { + msg(msglevel, "client-nat: bad netmask: %s", netmask); + return; + } + msg(M_WARN, "client-nat network parameter can also be specified as a CIDR address instead of using the separate netmask parameter"); + e.netbits = bits; + } + else if (netbits > 0) + { + e.netbits = netbits; + } + else + { + msg(msglevel, "client-nat: netmask or bits must be specified"); return; } - e.foreign_network = getaddr(0, foreign_network, 0, &ok, NULL); + e.foreign_network = getaddr(0, foreign_network, NULL, 0, &ok, NULL); if (!ok) { msg(msglevel, "client-nat: bad foreign network: %s", foreign_network); @@ -210,6 +228,7 @@ for (i = 0; i < list->n; ++i) { const struct client_nat_entry *e = &list->entries[i]; /* current NAT rule */ + const in_addr_t netmask = netbits_to_netmask((int)e->netbits); if (e->type ^ direction) { addr = *(addr_ptr = &h->ip.daddr); @@ -231,13 +250,13 @@ to = &e->foreign_network; } - if (((addr & e->netmask) == *from) && !(amask & alog)) + if (((addr & netmask) == *from) && !(amask & alog)) { /* pre-adjust IP checksum */ ADD_CHECKSUM_32(accumulate, addr); /* do NAT transform */ - addr = (addr & ~e->netmask) | *to; + addr = (addr & ~netmask) | *to; /* post-adjust IP checksum */ SUB_CHECKSUM_32(accumulate, addr); diff --git a/src/openvpn/clinat.h b/src/openvpn/clinat.h index 94141f5..bebd012 100644 --- a/src/openvpn/clinat.h +++ b/src/openvpn/clinat.h @@ -36,7 +36,7 @@ #define CN_DNAT 1 int type; in_addr_t network; - in_addr_t netmask; + unsigned int netbits; in_addr_t foreign_network; }; diff --git a/src/openvpn/helper.c b/src/openvpn/helper.c index bbdbc04..30f3539 100644 --- a/src/openvpn/helper.c +++ b/src/openvpn/helper.c @@ -64,22 +64,21 @@ } static const char * -print_opt_route(const in_addr_t network, const in_addr_t netmask, struct gc_arena *gc) +print_opt_route(const in_addr_t network, const int netbits, struct gc_arena *gc) { struct buffer out = alloc_buf_gc(128, gc); ASSERT(network); - if (netmask) - { - buf_printf(&out, "route %s %s", - print_in_addr_t(network, 0, gc), - print_in_addr_t(netmask, 0, gc)); - } - else + if (netbits < 0) { buf_printf(&out, "route %s", print_in_addr_t(network, 0, gc)); } + else + { + buf_printf(&out, "route %s/%d", + print_in_addr_t(network, 0, gc), netbits); + } return BSTR(&out); } @@ -111,27 +110,28 @@ } static void -helper_add_route(const in_addr_t network, const in_addr_t netmask, struct options *o) +helper_add_route(const in_addr_t network, const int netbits, struct options *o) { rol_check_alloc(o); add_route_to_option_list(o->routes, print_in_addr_t(network, 0, &o->gc), - print_in_addr_t(netmask, 0, &o->gc), + print_in_addr_t(netbits_to_netmask(netbits), 0, &o->gc), NULL, NULL); } static void -verify_common_subnet(const char *opt, const in_addr_t a, const in_addr_t b, const in_addr_t subnet) +verify_common_subnet(const char *opt, const in_addr_t a, const in_addr_t b, const unsigned int netbits) { struct gc_arena gc = gc_new(); - if ((a & subnet) != (b & subnet)) + const unsigned int var = 32 - netbits; + if ((a >> var) != (b >> var)) { - msg(M_USAGE, "%s IP addresses %s and %s are not in the same %s subnet", + msg(M_USAGE, "%s IP addresses %s and %s are not in the same /%d subnet", opt, print_in_addr_t(a, 0, &gc), print_in_addr_t(b, 0, &gc), - print_in_addr_t(subnet, 0, &gc)); + netbits); } gc_free(&gc); } @@ -268,9 +268,6 @@ if (o->server_defined) { - int netbits = -2; - bool status = false; - if (o->client) { msg(M_USAGE, "--server and --client cannot be used together"); @@ -296,34 +293,24 @@ msg(M_USAGE, "--server directive only makes sense with --dev tun or --dev tap"); } - status = netmask_to_netbits(o->server_network, o->server_netmask, &netbits); - if (!status) - { - msg(M_USAGE, "--server directive network/netmask combination is invalid"); - } - - if (netbits < 0) - { - msg(M_USAGE, "--server directive netmask is invalid"); - } - - if (netbits < IFCONFIG_POOL_MIN_NETBITS) + if (o->server_netbits < IFCONFIG_POOL_MIN_NETBITS) { msg(M_USAGE, "--server directive netmask allows for too many host addresses (subnet must be %s or higher)", print_netmask(IFCONFIG_POOL_MIN_NETBITS, &gc)); } + const in_addr_t server_netmask = netbits_to_netmask((int)o->server_netbits); if (dev == DEV_TYPE_TUN) { int pool_end_reserve = 4; - if (netbits > 29) + if (o->server_netbits > 29) { msg(M_USAGE, "--server directive when used with --dev tun must define a subnet of %s or lower", print_netmask(29, &gc)); } - if (netbits == 29) + if (o->server_netbits == 29) { pool_end_reserve = 0; } @@ -342,14 +329,14 @@ { o->ifconfig_pool_defined = true; o->ifconfig_pool_start = o->server_network + 4; - o->ifconfig_pool_end = (o->server_network | ~o->server_netmask) - pool_end_reserve; + o->ifconfig_pool_end = (o->server_network | ~server_netmask) - pool_end_reserve; ifconfig_pool_verify_range(M_USAGE, o->ifconfig_pool_start, o->ifconfig_pool_end); } - helper_add_route(o->server_network, o->server_netmask, o); + helper_add_route(o->server_network, o->server_netbits, o); if (o->enable_c2c) { - push_option(o, print_opt_route(o->server_network, o->server_netmask, &o->gc), M_USAGE); + push_option(o, print_opt_route(o->server_network, o->server_netbits, &o->gc), M_USAGE); } else if (o->topology == TOP_NET30) { @@ -359,16 +346,16 @@ else if (o->topology == TOP_SUBNET) { o->ifconfig_local = print_in_addr_t(o->server_network + 1, 0, &o->gc); - o->ifconfig_remote_netmask = print_in_addr_t(o->server_netmask, 0, &o->gc); + o->ifconfig_remote_netmask = print_in_addr_t(server_netmask, 0, &o->gc); if (!(o->server_flags & SF_NOPOOL)) { o->ifconfig_pool_defined = true; o->ifconfig_pool_start = o->server_network + 2; - o->ifconfig_pool_end = (o->server_network | ~o->server_netmask) - 1; + o->ifconfig_pool_end = (o->server_network | ~server_netmask) - 1; ifconfig_pool_verify_range(M_USAGE, o->ifconfig_pool_start, o->ifconfig_pool_end); } - o->ifconfig_pool_netmask = o->server_netmask; + o->ifconfig_pool_netbits = o->server_netbits; push_option(o, print_opt_route_gateway(o->server_network + 1, &o->gc), M_USAGE); if (!o->route_default_gateway) @@ -393,7 +380,7 @@ } else if (dev == DEV_TYPE_TAP) { - if (netbits > 30) + if (o->server_netbits > 30) { msg(M_USAGE, "--server directive when used with --dev tap must define a subnet of %s or lower", print_netmask(30, &gc)); @@ -402,16 +389,16 @@ o->mode = MODE_SERVER; o->tls_server = true; o->ifconfig_local = print_in_addr_t(o->server_network + 1, 0, &o->gc); - o->ifconfig_remote_netmask = print_in_addr_t(o->server_netmask, 0, &o->gc); + o->ifconfig_remote_netmask = print_in_addr_t(server_netmask, 0, &o->gc); if (!(o->server_flags & SF_NOPOOL)) { o->ifconfig_pool_defined = true; o->ifconfig_pool_start = o->server_network + 2; - o->ifconfig_pool_end = (o->server_network | ~o->server_netmask) - 1; + o->ifconfig_pool_end = (o->server_network | ~server_netmask) - 1; ifconfig_pool_verify_range(M_USAGE, o->ifconfig_pool_start, o->ifconfig_pool_end); } - o->ifconfig_pool_netmask = o->server_netmask; + o->ifconfig_pool_netbits = o->server_netbits; push_option(o, print_opt_route_gateway(o->server_network + 1, &o->gc), M_USAGE); } @@ -425,7 +412,7 @@ { o->push_ifconfig_constraint_defined = true; o->push_ifconfig_constraint_network = o->server_network; - o->push_ifconfig_constraint_netmask = o->server_netmask; + o->push_ifconfig_constraint_netbits = o->server_netbits; } } @@ -478,9 +465,9 @@ if (o->server_bridge_defined) { - verify_common_subnet("--server-bridge", o->server_bridge_ip, o->server_bridge_pool_start, o->server_bridge_netmask); - verify_common_subnet("--server-bridge", o->server_bridge_pool_start, o->server_bridge_pool_end, o->server_bridge_netmask); - verify_common_subnet("--server-bridge", o->server_bridge_ip, o->server_bridge_pool_end, o->server_bridge_netmask); + verify_common_subnet("--server-bridge", o->server_bridge_ip, o->server_bridge_pool_start, o->server_bridge_netbits); + verify_common_subnet("--server-bridge", o->server_bridge_pool_start, o->server_bridge_pool_end, o->server_bridge_netbits); + verify_common_subnet("--server-bridge", o->server_bridge_ip, o->server_bridge_pool_end, o->server_bridge_netbits); } o->mode = MODE_SERVER; @@ -492,7 +479,7 @@ o->ifconfig_pool_start = o->server_bridge_pool_start; o->ifconfig_pool_end = o->server_bridge_pool_end; ifconfig_pool_verify_range(M_USAGE, o->ifconfig_pool_start, o->ifconfig_pool_end); - o->ifconfig_pool_netmask = o->server_bridge_netmask; + o->ifconfig_pool_netbits = o->server_bridge_netbits; push_option(o, print_opt_route_gateway(o->server_bridge_ip, &o->gc), M_USAGE); } else if (o->server_bridge_proxy_dhcp && !(o->server_flags & SF_NO_PUSH_ROUTE_GATEWAY)) diff --git a/src/openvpn/init.c b/src/openvpn/init.c index dd56961..7f72f8d 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -115,6 +115,7 @@ const char *dev_type, int tun_mtu, const char *ifconfig_local, + const int ifconfig_netbits, const char *ifconfig_remote, const char *context, const char *signal_text, @@ -144,7 +145,14 @@ } if (!ifconfig_remote) { - ifconfig_remote = ""; + if (ifconfig_netbits > 0) + { + ifconfig_remote = print_in_addr_t(netbits_to_netmask(ifconfig_netbits), 0, &gc); + } + else + { + ifconfig_remote = ""; + } } if (!context) { @@ -1948,7 +1956,8 @@ dev_type_string(c->options.dev, c->options.dev_type), c->c2.frame.tun_mtu, print_in_addr_t(c->c1.tuntap->local, IA_EMPTY_IF_UNDEF, &gc), - print_in_addr_t(c->c1.tuntap->remote_netmask, IA_EMPTY_IF_UNDEF, &gc), + c->c1.tuntap->netbits, + print_in_addr_t(c->c1.tuntap->remote, IA_EMPTY_IF_UNDEF, &gc), "init", NULL, "up", @@ -1988,7 +1997,8 @@ dev_type_string(c->options.dev, c->options.dev_type), c->c2.frame.tun_mtu, print_in_addr_t(c->c1.tuntap->local, IA_EMPTY_IF_UNDEF, &gc), - print_in_addr_t(c->c1.tuntap->remote_netmask, IA_EMPTY_IF_UNDEF, &gc), + c->c1.tuntap->netbits, + print_in_addr_t(c->c1.tuntap->remote, IA_EMPTY_IF_UNDEF, &gc), "restart", NULL, "up", @@ -2045,7 +2055,8 @@ struct gc_arena gc = gc_new(); const char *tuntap_actual = string_alloc(c->c1.tuntap->actual_name, &gc); const in_addr_t local = c->c1.tuntap->local; - const in_addr_t remote_netmask = c->c1.tuntap->remote_netmask; + const int netbits = c->c1.tuntap->netbits; + const in_addr_t remote = c->c1.tuntap->remote; unsigned long adapter_index = 0; #ifdef _WIN32 adapter_index = c->c1.tuntap->adapter_index; @@ -2077,7 +2088,8 @@ NULL, c->c2.frame.tun_mtu, print_in_addr_t(local, IA_EMPTY_IF_UNDEF, &gc), - print_in_addr_t(remote_netmask, IA_EMPTY_IF_UNDEF, &gc), + netbits, + print_in_addr_t(remote, IA_EMPTY_IF_UNDEF, &gc), "init", signal_description(c->sig->signal_received, c->sig->signal_text), @@ -2107,7 +2119,8 @@ NULL, c->c2.frame.tun_mtu, print_in_addr_t(local, IA_EMPTY_IF_UNDEF, &gc), - print_in_addr_t(remote_netmask, IA_EMPTY_IF_UNDEF, &gc), + netbits, + print_in_addr_t(remote, IA_EMPTY_IF_UNDEF, &gc), "init", signal_description(c->sig->signal_received, c->sig->signal_text), @@ -2137,7 +2150,8 @@ NULL, c->c2.frame.tun_mtu, print_in_addr_t(local, IA_EMPTY_IF_UNDEF, &gc), - print_in_addr_t(remote_netmask, IA_EMPTY_IF_UNDEF, &gc), + netbits, + print_in_addr_t(remote, IA_EMPTY_IF_UNDEF, &gc), "restart", signal_description(c->sig->signal_received, c->sig->signal_text), diff --git a/src/openvpn/manage.c b/src/openvpn/manage.c index 05b5a1a..a88ee5f 100644 --- a/src/openvpn/manage.c +++ b/src/openvpn/manage.c @@ -554,7 +554,7 @@ { /* IP:port specified */ bool status; - const in_addr_t addr = getaddr(GETADDR_HOST_ORDER|GETADDR_MSG_VIRT_OUT, p1, 0, &status, NULL); + const in_addr_t addr = getaddr(GETADDR_HOST_ORDER|GETADDR_MSG_VIRT_OUT, p1, NULL, 0, &status, NULL); if (status) { const int port = atoi(p2); @@ -2803,6 +2803,7 @@ "untrusted_ip=", "ifconfig_local=", "ifconfig_netmask=", + "ifconfig_netbits=", "daemon_start_time=", "daemon_pid=", "dev=", diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index 0509911..aba1a0f 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -1433,7 +1433,8 @@ const struct options *o = &c->options; if (o->push_ifconfig_constraint_defined && c->c2.push_ifconfig_defined) { - return (o->push_ifconfig_constraint_netmask & c->c2.push_ifconfig_local) == o->push_ifconfig_constraint_network; + const unsigned int var = 32 - o->push_ifconfig_constraint_netbits; + return (c->c2.push_ifconfig_local >> var) == (o->push_ifconfig_constraint_network >> var); } else { @@ -1512,10 +1513,10 @@ mi->context.c2.push_ifconfig_local = remote; if (tunnel_type == DEV_TYPE_TAP || (tunnel_type == DEV_TYPE_TUN && tunnel_topology == TOP_SUBNET)) { - mi->context.c2.push_ifconfig_remote_netmask = mi->context.options.ifconfig_pool_netmask; + mi->context.c2.push_ifconfig_remote_netmask = netbits_to_netmask((int)mi->context.options.ifconfig_pool_netbits); if (!mi->context.c2.push_ifconfig_remote_netmask) { - mi->context.c2.push_ifconfig_remote_netmask = mi->context.c1.tuntap->remote_netmask; + mi->context.c2.push_ifconfig_remote_netmask = netbits_to_netmask((int)mi->context.c1.tuntap->netbits); } } else if (tunnel_type == DEV_TYPE_TUN) @@ -2425,15 +2426,14 @@ { const char *ifconfig_constraint_network = print_in_addr_t(mi->context.options.push_ifconfig_constraint_network, 0, &gc); - const char *ifconfig_constraint_netmask = - print_in_addr_t(mi->context.options.push_ifconfig_constraint_netmask, 0, &gc); /* JYFIXME -- this should cause the connection to fail */ msg(D_MULTI_ERRORS, "MULTI ERROR: primary virtual IP for %s (%s) " - "violates tunnel network/netmask constraint (%s/%s)", + "violates tunnel network/subnet constraint (%s/%d)", multi_instance_string(mi, false, &gc), print_in_addr_t(mi->context.c2.push_ifconfig_local, 0, &gc), - ifconfig_constraint_network, ifconfig_constraint_netmask); + ifconfig_constraint_network, + mi->context.options.push_ifconfig_constraint_netbits); } /* diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 649f48b..84e9db4 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -1075,7 +1075,7 @@ #endif /* ifndef _WIN32 */ static in_addr_t -get_ip_addr(const char *ip_string, int msglevel, bool *error) +get_ip_addr(const char *ip_string, unsigned int *netbits, int msglevel, bool *error) { unsigned int flags = GETADDR_HOST_ORDER; bool succeeded = false; @@ -1086,7 +1086,7 @@ flags |= GETADDR_FATAL; } - ret = getaddr(flags, ip_string, 0, &succeeded, NULL); + ret = getaddr(flags, ip_string, netbits, 0, &succeeded, NULL); if (!succeeded && error) { *error = true; @@ -1333,7 +1333,7 @@ if (ip_addr_dotted_quad_safe(parm)) /* FQDN -- IP address only */ { bool error = false; - const in_addr_t addr = get_ip_addr(parm, msglevel, &error); + const in_addr_t addr = get_ip_addr(parm, NULL, msglevel, &error); if (!error) { array[(*len)++] = addr; @@ -1513,12 +1513,10 @@ { struct gc_arena gc = gc_new(); - msg(D_SHOW_PARMS, " server_network = %s", print_in_addr_t(o->server_network, 0, &gc)); - msg(D_SHOW_PARMS, " server_netmask = %s", print_in_addr_t(o->server_netmask, 0, &gc)); + msg(D_SHOW_PARMS, " server_network = %s/%d", print_in_addr_t(o->server_network, 0, &gc), o->server_netbits); msg(D_SHOW_PARMS, " server_network_ipv6 = %s", print_in6_addr(o->server_network_ipv6, 0, &gc) ); SHOW_INT(server_netbits_ipv6); - msg(D_SHOW_PARMS, " server_bridge_ip = %s", print_in_addr_t(o->server_bridge_ip, 0, &gc)); - msg(D_SHOW_PARMS, " server_bridge_netmask = %s", print_in_addr_t(o->server_bridge_netmask, 0, &gc)); + msg(D_SHOW_PARMS, " server_bridge_ip = %s/%d", print_in_addr_t(o->server_bridge_ip, 0, &gc), o->server_bridge_netbits); msg(D_SHOW_PARMS, " server_bridge_pool_start = %s", print_in_addr_t(o->server_bridge_pool_start, 0, &gc)); msg(D_SHOW_PARMS, " server_bridge_pool_end = %s", print_in_addr_t(o->server_bridge_pool_end, 0, &gc)); if (o->push_list.head) @@ -1534,9 +1532,8 @@ } } SHOW_BOOL(ifconfig_pool_defined); - msg(D_SHOW_PARMS, " ifconfig_pool_start = %s", print_in_addr_t(o->ifconfig_pool_start, 0, &gc)); + msg(D_SHOW_PARMS, " ifconfig_pool_start = %s/%d", print_in_addr_t(o->ifconfig_pool_start, 0, &gc), o->ifconfig_pool_netbits); msg(D_SHOW_PARMS, " ifconfig_pool_end = %s", print_in_addr_t(o->ifconfig_pool_end, 0, &gc)); - msg(D_SHOW_PARMS, " ifconfig_pool_netmask = %s", print_in_addr_t(o->ifconfig_pool_netmask, 0, &gc)); SHOW_STR(ifconfig_pool_persist_filename); SHOW_INT(ifconfig_pool_persist_refresh_freq); SHOW_BOOL(ifconfig_ipv6_pool_defined); @@ -1597,14 +1594,15 @@ int msglevel) { struct iroute *ir; + unsigned int netbits = 0; ALLOC_OBJ_GC(ir, struct iroute, &o->gc); - ir->network = getaddr(GETADDR_HOST_ORDER, network_str, 0, NULL, NULL); - ir->netbits = 32; /* host route if no netmask given */ + ir->network = getaddr(GETADDR_HOST_ORDER, network_str, &netbits, 0, NULL, NULL); + ir->netbits = 32; /* host route if no netmask or netbits given */ if (netmask_str) { - const in_addr_t netmask = getaddr(GETADDR_HOST_ORDER, netmask_str, 0, NULL, NULL); + const in_addr_t netmask = getaddr(GETADDR_HOST_ORDER, netmask_str, NULL, 0, NULL, NULL); ir->netbits = netmask_to_netbits2(netmask); if (ir->netbits < 0) @@ -1614,6 +1612,11 @@ netmask_str); return; } + msg(M_WARN, "iroute network parameter can also be specified as a CIDR address instead of using the separate netmask parameter"); + } + else if (netbits) + { + ir->netbits = (int)netbits; } ir->next = o->iroutes; @@ -2631,9 +2634,9 @@ { msg(M_USAGE, "--connect-freq only works with --mode server --proto udp. Try --max-clients instead."); } - if (!(dev == DEV_TYPE_TAP || (dev == DEV_TYPE_TUN && options->topology == TOP_SUBNET)) && options->ifconfig_pool_netmask) + if (!(dev == DEV_TYPE_TAP || (dev == DEV_TYPE_TUN && options->topology == TOP_SUBNET)) && options->ifconfig_pool_netbits > 0) { - msg(M_USAGE, "The third parameter to --ifconfig-pool (netmask) is only valid in --dev tap mode"); + msg(M_USAGE, "The netbits parameter to --ifconfig-pool is only valid in --dev tap mode"); } if (options->routes && (options->routes->flags & RG_ENABLE)) { @@ -6092,11 +6095,29 @@ iproute_path = p[1]; } #endif - else if (streq(p[0], "ifconfig") && p[1] && p[2] && !p[3]) + else if (streq(p[0], "ifconfig") && p[1] && !p[3]) { + bool error = false; + VERIFY_PERMISSION(OPT_P_UP); - if (ip_or_dns_addr_safe(p[1], options->allow_pull_fqdn) && ip_or_dns_addr_safe(p[2], options->allow_pull_fqdn)) /* FQDN -- may be DNS name */ + if (!p[2]) /* p[1] must be in CIDR format */ { + unsigned int netbits = 0; + get_ip_addr(p[1], &netbits, msglevel, &error); + if (error || !netbits) + { + msg(msglevel, "ifconfig parm '%s' must be a valid address/bits", p[1]); + goto err; + } + options->ifconfig_local = strtok(p[1], "/"); + /* convert netbits to netmask to unify the storage as string + * representation of in_addr_t variables and simplify parsing */ + options->ifconfig_remote_netmask = print_in_addr_t(netbits_to_netmask((int)netbits), 0, &options->gc); + } + else if (ip_or_dns_addr_safe(p[1], options->allow_pull_fqdn) && ip_or_dns_addr_safe(p[2], options->allow_pull_fqdn)) /* FQDN -- may be DNS name */ + { + /* don't suggest CIDR usage here since we don't know if it's a + * remote address or a netmask */ options->ifconfig_local = p[1]; options->ifconfig_remote_netmask = p[2]; } @@ -6999,35 +7020,62 @@ VERIFY_PERMISSION(OPT_P_PERSIST_IP); options->persist_remote_ip = true; } - else if (streq(p[0], "client-nat") && p[1] && p[2] && p[3] && p[4] && !p[5]) + else if (streq(p[0], "client-nat") && p[1] && p[2] && p[3] && !p[5]) { + size_t i = 1; + const char *type = p[i++]; + const char *network = p[i++]; + const char *netmask = p[i+1] ? p[i++] : NULL; + const char *foreign_network = p[i]; + VERIFY_PERMISSION(OPT_P_ROUTE); cnol_check_alloc(options); - add_client_nat_to_option_list(options->client_nat, p[1], p[2], p[3], p[4], msglevel); + add_client_nat_to_option_list(options->client_nat, type, network, netmask, foreign_network, msglevel); } else if (streq(p[0], "route") && p[1] && !p[5]) { + size_t i = 1; + char *cidr = strchr(p[i], '/'); + if (cidr && !no_more_than_n_args(msglevel, p, 4, NM_QUOTE_HINT)) + { + goto err; + } + VERIFY_PERMISSION(OPT_P_ROUTE); rol_check_alloc(options); if (pull_mode) { - if (!ip_or_dns_addr_safe(p[1], options->allow_pull_fqdn) && !is_special_addr(p[1])) /* FQDN -- may be DNS name */ + + const char *network = strtok(p[i++], "/"); /* this modifies p[1] */ + if (!ip_or_dns_addr_safe(network, options->allow_pull_fqdn) && !is_special_addr(p[1])) /* FQDN -- may be DNS name */ { - msg(msglevel, "route parameter network/IP '%s' must be a valid address", p[1]); + msg(msglevel, "route parameter network/IP '%s' must be a valid address or address/bits", p[1]); goto err; } - if (p[2] && !ip_addr_dotted_quad_safe(p[2])) /* FQDN -- must be IP address */ + if (!cidr && p[i]) { - msg(msglevel, "route parameter netmask '%s' must be an IP address", p[2]); - goto err; + if (!ip_addr_dotted_quad_safe(p[i++])) /* FQDN -- must be IP address */ + { + msg(msglevel, "route parameter netmask '%s' must be an IP address", p[2]); + goto err; + } } - if (p[3] && !ip_or_dns_addr_safe(p[3], options->allow_pull_fqdn) && !is_special_addr(p[3])) /* FQDN -- may be DNS name */ + if (p[i] && !ip_or_dns_addr_safe(p[i], options->allow_pull_fqdn) && !is_special_addr(p[i])) /* FQDN -- may be DNS name */ { - msg(msglevel, "route parameter gateway '%s' must be a valid address", p[3]); + msg(msglevel, "route parameter gateway '%s' must be a valid address", p[i]); goto err; } } - add_route_to_option_list(options->routes, p[1], p[2], p[3], p[4]); + + if (cidr) + { + *cidr = (char)('/'); /* restore the original CIDR notation for p[1] */ + add_route_to_option_list(options->routes, p[1], NULL, p[2], p[3]); + } + else + { + add_route_to_option_list(options->routes, p[1], p[2], p[3], p[4]); + } } else if (streq(p[0], "route-ipv6") && p[1] && !p[4]) { @@ -7348,33 +7396,57 @@ VERIFY_PERMISSION(OPT_P_GENERAL); options->occ = false; } - else if (streq(p[0], "server") && p[1] && p[2] && !p[4]) + else if (streq(p[0], "server") && p[1] && !p[4]) { const int lev = M_WARN; bool error = false; - in_addr_t network, netmask; + in_addr_t network; + unsigned int netbits = 0; + size_t i = 1; VERIFY_PERMISSION(OPT_P_GENERAL); - network = get_ip_addr(p[1], lev, &error); - netmask = get_ip_addr(p[2], lev, &error); - if (error || !network || !netmask) + network = get_ip_addr(p[i++], &netbits, lev, &error); + if (netbits) + { + if (!no_more_than_n_args(msglevel, p, 3, NM_QUOTE_HINT)) + { + goto err; + } + } + else + { + const in_addr_t netmask = get_ip_addr(p[i++], NULL, lev, &error); + const int nb = netmask_to_netbits2(netmask); + if (netmask && nb > 0) + { + msg(M_WARN, "server network parameter can also be specified as a CIDR address instead of using the separate netmask parameter"); + netbits = nb; + } + else + { + msg(M_USAGE, "--server directive network/netmask combination is invalid"); + goto err; + } + } + + if (error || !network || !netbits) { msg(msglevel, "error parsing --server parameters"); goto err; } options->server_defined = true; options->server_network = network; - options->server_netmask = netmask; + options->server_netbits = netbits; - if (p[3]) + if (p[i]) { - if (streq(p[3], "nopool")) + if (streq(p[i], "nopool")) { options->server_flags |= SF_NOPOOL; } else { - msg(msglevel, "error parsing --server: %s is not a recognized flag", p[3]); + msg(msglevel, "error parsing --server: %s is not a recognized flag", p[i]); goto err; } } @@ -7403,25 +7475,43 @@ options->server_network_ipv6 = network; options->server_netbits_ipv6 = netbits; } - else if (streq(p[0], "server-bridge") && p[1] && p[2] && p[3] && p[4] && !p[5]) + else if (streq(p[0], "server-bridge") && p[1] && p[2] && p[3] && !p[5]) { const int lev = M_WARN; bool error = false; - in_addr_t ip, netmask, pool_start, pool_end; + in_addr_t ip, pool_start, pool_end; + unsigned int netbits = 0; + size_t i = 1; VERIFY_PERMISSION(OPT_P_GENERAL); - ip = get_ip_addr(p[1], lev, &error); - netmask = get_ip_addr(p[2], lev, &error); - pool_start = get_ip_addr(p[3], lev, &error); - pool_end = get_ip_addr(p[4], lev, &error); - if (error || !ip || !netmask || !pool_start || !pool_end) + ip = get_ip_addr(p[i++], &netbits, lev, &error); + if (netbits) + { + if (!no_more_than_n_args(msglevel, p, 4, NM_QUOTE_HINT)) + { + goto err; + } + } + else + { + const in_addr_t netmask = get_ip_addr(p[i++], NULL, lev, &error); + const int nb = netmask_to_netbits2(netmask); + if (netmask && nb > 0) + { + msg(M_WARN, "server-bridge gateway parameter can also be specified as a CIDR address instead of using the separate netmask parameter"); + netbits = nb; + } + } + pool_start = get_ip_addr(p[i++], NULL, lev, &error); + pool_end = get_ip_addr(p[i], NULL, lev, &error); + if (error || !ip || !netbits || !pool_start || !pool_end) { msg(msglevel, "error parsing --server-bridge parameters"); goto err; } options->server_bridge_defined = true; options->server_bridge_ip = ip; - options->server_bridge_netmask = netmask; + options->server_bridge_netbits = netbits; options->server_bridge_pool_start = pool_start; options->server_bridge_pool_end = pool_end; } @@ -7456,15 +7546,27 @@ { const int lev = M_WARN; bool error = false; - in_addr_t start, end, netmask = 0; + in_addr_t start, end; + unsigned int netbits = 0; VERIFY_PERMISSION(OPT_P_GENERAL); - start = get_ip_addr(p[1], lev, &error); - end = get_ip_addr(p[2], lev, &error); - if (p[3]) + start = get_ip_addr(p[1], &netbits, lev, &error); + end = get_ip_addr(p[2], NULL, lev, &error); + if (!netbits && p[3]) { - netmask = get_ip_addr(p[3], lev, &error); + const in_addr_t netmask = get_ip_addr(p[3], NULL, lev, NULL); + const int nb = netmask_to_netbits2(netmask); + if (netmask && nb >= 0) + { + msg(M_WARN, "ifconfig-pool start-IP parameter can also be specified as a CIDR address instead of using the separate netmask parameter"); + netbits = nb; + } } + else if (netbits && !no_more_than_n_args(msglevel, p, 3, NM_QUOTE_HINT)) + { + goto err; + } + if (error) { msg(msglevel, "error parsing --ifconfig-pool parameters"); @@ -7478,10 +7580,7 @@ options->ifconfig_pool_defined = true; options->ifconfig_pool_start = start; options->ifconfig_pool_end = end; - if (netmask) - { - options->ifconfig_pool_netmask = netmask; - } + options->ifconfig_pool_netbits = netbits; } else if (streq(p[0], "ifconfig-pool-persist") && p[1] && !p[3]) { @@ -7802,45 +7901,77 @@ VERIFY_PERMISSION(OPT_P_INSTANCE); option_iroute_ipv6(options, p[1], msglevel); } - else if (streq(p[0], "ifconfig-push") && p[1] && p[2] && !p[4]) + else if (streq(p[0], "ifconfig-push") && p[1] && !p[4]) { - in_addr_t local, remote_netmask; + in_addr_t local, remote_netmask = 0; + unsigned int netbits; + size_t i = 1; VERIFY_PERMISSION(OPT_P_INSTANCE); - local = getaddr(GETADDR_HOST_ORDER|GETADDR_RESOLVE, p[1], 0, NULL, NULL); - remote_netmask = getaddr(GETADDR_HOST_ORDER|GETADDR_RESOLVE, p[2], 0, NULL, NULL); + local = getaddr(GETADDR_HOST_ORDER|GETADDR_RESOLVE, p[i++], &netbits, 0, NULL, NULL); + if (netbits) /* convert netbits to netmask */ + { + if (!no_more_than_n_args(msglevel, p, 3, NM_QUOTE_HINT)) + { + goto err; + } + remote_netmask = netbits_to_netmask((int)netbits); + } + else if (p[i]) + { + /* don't suggest CIDR usage here since we don't know if it's a + * remote address or a netmask */ + remote_netmask = getaddr(GETADDR_HOST_ORDER|GETADDR_RESOLVE, p[i++], NULL, 0, NULL, NULL); + } + if (local && remote_netmask) { options->push_ifconfig_defined = true; options->push_ifconfig_local = local; options->push_ifconfig_remote_netmask = remote_netmask; - if (p[3]) + if (p[i]) { - options->push_ifconfig_local_alias = getaddr(GETADDR_HOST_ORDER|GETADDR_RESOLVE, p[3], 0, NULL, NULL); + options->push_ifconfig_local_alias = getaddr(GETADDR_HOST_ORDER|GETADDR_RESOLVE, p[i], NULL, 0, NULL, NULL); } } else { - msg(msglevel, "cannot parse --ifconfig-push addresses"); + msg(msglevel, "cannot parse --ifconfig-push parameters"); goto err; } } - else if (streq(p[0], "ifconfig-push-constraint") && p[1] && p[2] && !p[3]) + else if (streq(p[0], "ifconfig-push-constraint") && p[1] && !p[3]) { - in_addr_t network, netmask; + in_addr_t network; + unsigned int netbits = 0; + size_t i = 1; VERIFY_PERMISSION(OPT_P_GENERAL); - network = getaddr(GETADDR_HOST_ORDER|GETADDR_RESOLVE, p[1], 0, NULL, NULL); - netmask = getaddr(GETADDR_HOST_ORDER, p[2], 0, NULL, NULL); - if (network && netmask) + network = getaddr(GETADDR_HOST_ORDER|GETADDR_RESOLVE, p[i++], &netbits, 0, NULL, NULL); + if (!netbits && p[i]) + { + const in_addr_t netmask = getaddr(GETADDR_HOST_ORDER, p[2], NULL, 0, NULL, NULL); + const int nb = netmask_to_netbits2(netmask); + if (netmask && nb > 0) + { + netbits = nb; + msg(M_WARN, "ifconfig-push-constraint network parameter can also be specified as a CIDR address instead of using the separate netmask parameter"); + } + } + else if (netbits && !no_more_than_n_args(msglevel, p, 2, NM_QUOTE_HINT)) + { + goto err; + } + + if (network && netbits) { options->push_ifconfig_constraint_defined = true; options->push_ifconfig_constraint_network = network; - options->push_ifconfig_constraint_netmask = netmask; + options->push_ifconfig_constraint_netbits = netbits; } else { - msg(msglevel, "cannot parse --ifconfig-push-constraint addresses"); + msg(msglevel, "cannot parse --ifconfig-push-constraint parameters"); goto err; } } diff --git a/src/openvpn/options.h b/src/openvpn/options.h index f608cb8..88de24c 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -450,7 +450,7 @@ const char *tmp_dir; bool server_defined; in_addr_t server_network; - in_addr_t server_netmask; + unsigned int server_netbits; bool server_ipv6_defined; /* IPv6 */ struct in6_addr server_network_ipv6; /* IPv6 */ unsigned int server_netbits_ipv6; /* IPv6 */ @@ -464,7 +464,7 @@ bool server_bridge_defined; in_addr_t server_bridge_ip; - in_addr_t server_bridge_netmask; + unsigned int server_bridge_netbits; in_addr_t server_bridge_pool_start; in_addr_t server_bridge_pool_end; @@ -472,7 +472,7 @@ bool ifconfig_pool_defined; in_addr_t ifconfig_pool_start; in_addr_t ifconfig_pool_end; - in_addr_t ifconfig_pool_netmask; + unsigned int ifconfig_pool_netbits; const char *ifconfig_pool_persist_filename; int ifconfig_pool_persist_refresh_freq; @@ -499,7 +499,7 @@ in_addr_t push_ifconfig_local_alias; bool push_ifconfig_constraint_defined; in_addr_t push_ifconfig_constraint_network; - in_addr_t push_ifconfig_constraint_netmask; + unsigned int push_ifconfig_constraint_netbits; 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/pool.c b/src/openvpn/pool.c index e3c3708..84227b6 100644 --- a/src/openvpn/pool.c +++ b/src/openvpn/pool.c @@ -652,8 +652,8 @@ if (strlen(ip_buf) > 0) { bool v4_ok = true; - in_addr_t addr = getaddr(GETADDR_HOST_ORDER, ip_buf, 0, &v4_ok, - NULL); + in_addr_t addr = getaddr(GETADDR_HOST_ORDER, ip_buf, NULL, 0, + &v4_ok, NULL); if (!v4_ok) { diff --git a/src/openvpn/push.c b/src/openvpn/push.c index 6c06374..b8ab470 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -1136,9 +1136,20 @@ if (p[0] && !strcmp(p[0], "route") && !p[3] && o->iroutes) { /* get route parameters */ - bool status1, status2; - const in_addr_t network = getaddr(GETADDR_HOST_ORDER, p[1], 0, &status1, NULL); - const in_addr_t netmask = getaddr(GETADDR_HOST_ORDER, p[2] ? p[2] : "255.255.255.255", 0, &status2, NULL); + bool status1, status2 = true; + int netbits = -1; + + /* get netbits from CIDR or convert netmask to netbits */ + const in_addr_t network = getaddr(GETADDR_HOST_ORDER, p[1], (unsigned int *)&netbits, 0, &status1, NULL); + if (p[2]) + { + const in_addr_t netmask = getaddr(GETADDR_HOST_ORDER, p[2], NULL, 0, &status2, NULL); + netbits = netmask_to_netbits2(netmask); + } + if (netbits <= 0) + { + netbits = 32; + } /* did route parameters parse correctly? */ if (status1 && status2) @@ -1148,7 +1159,7 @@ /* does route match an iroute? */ for (ir = o->iroutes; ir != NULL; ir = ir->next) { - if (network == ir->network && netmask == netbits_to_netmask(ir->netbits >= 0 ? ir->netbits : 32)) + if (network == ir->network && netbits == (ir->netbits >= 0 ? ir->netbits : 32)) { enable = false; break; diff --git a/src/openvpn/route.c b/src/openvpn/route.c index 91f2032..b743433 100644 --- a/src/openvpn/route.c +++ b/src/openvpn/route.c @@ -189,9 +189,9 @@ route_string(const struct route_ipv4 *r, struct gc_arena *gc) { struct buffer out = alloc_buf_gc(256, gc); - buf_printf(&out, "ROUTE network %s netmask %s gateway %s", + buf_printf(&out, "ROUTE network %s/%d gateway %s", print_in_addr_t(r->network, 0, gc), - print_in_addr_t(r->netmask, 0, gc), + r->netbits, print_in_addr_t(r->gateway, 0, gc) ); if (r->flags & RT_METRIC_DEFINED) @@ -321,11 +321,17 @@ const struct route_option *ro, const struct route_list *rl) { - const in_addr_t default_netmask = IPV4_NETMASK_HOST; + const in_addr_t default_netbits = IPV4_NETBITS_HOST; bool status; int ret; struct in_addr special = {0}; + /* separate address and prefix if present */ + char *network = strdup(ro->network); + const char *cidr = strchr(network, '/'); + const char *addr = strtok(network, "/"); + const char *prefix = strtok(NULL, "/"); + CLEAR(*r); r->option = ro; @@ -355,7 +361,7 @@ else { ret = openvpn_getaddrinfo(GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL, - ro->network, NULL, 0, NULL, AF_INET, network_list); + addr, NULL, 0, NULL, AF_INET, network_list); } status = (ret == 0); @@ -365,25 +371,41 @@ goto fail; } - /* netmask */ + /* netbits */ + r->netbits = default_netbits; if (is_route_parm_defined(ro->netmask)) { - r->netmask = getaddr( + const in_addr_t netmask = getaddr( GETADDR_HOST_ORDER | GETADDR_WARN_ON_SIGNAL, ro->netmask, + NULL, 0, &status, NULL); - if (!status) + const int netbits = netmask_to_netbits2(netmask); + + if (!status || netbits < 0) { goto fail; } + msg(M_WARN, "route parameter network/IP can also be specified as a CIDR address instead of using the separate netmask parameter"); + r->netbits = netbits; } - else + else if (cidr) { - r->netmask = default_netmask; + if (!prefix) /* handle 'aa.bb.cc.dd/' case */ + { + goto fail; + } + char *endp = NULL; + const unsigned long netbits = strtoul(prefix, &endp, 10); + if ((*endp != '\0') || (netbits > sizeof(in_addr_t) * 8)) + { + goto fail; + } + r->netbits = netbits; } /* gateway */ @@ -397,6 +419,7 @@ | GETADDR_HOST_ORDER | GETADDR_WARN_ON_SIGNAL, ro->gateway, + NULL, 0, &status, NULL); @@ -428,7 +451,7 @@ if (r->metric < 0) { msg(M_WARN, PACKAGE_NAME " ROUTE: route metric for network %s (%s) must be >= 0", - ro->network, + addr, ro->metric); goto fail; } @@ -442,11 +465,13 @@ r->flags |= RT_DEFINED; + free(network); return true; fail: msg(M_WARN, PACKAGE_NAME " ROUTE: failed to parse/resolve route for host/network: %s", ro->network); + free(network); return false; } @@ -516,7 +541,7 @@ struct route_option *ro; ALLOC_OBJ_GC(ro, struct route_option, l->gc); ro->network = network; - ro->netmask = netmask; + ro->netmask = netmask; /* NULL if network has CIDR notation */ ro->gateway = gateway; ro->metric = metric; ro->next = l->routes; @@ -582,7 +607,7 @@ r1->flags = RT_DEFINED; r1->gateway = target; r1->network = gateway->addr & gateway->netmask; - r1->netmask = ~(l2-1); + r1->netbits = netmask_to_netbits2(gateway->netmask) + 1; r1->next = rl->routes; rl->routes = r1; @@ -681,6 +706,7 @@ | GETADDR_HOST_ORDER | GETADDR_WARN_ON_SIGNAL, remote_endpoint, + NULL, 0, &defined, NULL); @@ -921,7 +947,7 @@ static bool add_route3(in_addr_t network, - in_addr_t netmask, + unsigned int netbits, in_addr_t gateway, const struct tuntap *tt, unsigned int flags, @@ -933,14 +959,14 @@ CLEAR(r); r.flags = RT_DEFINED; r.network = network; - r.netmask = netmask; + r.netbits = netbits; r.gateway = gateway; return add_route(&r, tt, flags, rgi, es, ctx); } static void del_route3(in_addr_t network, - in_addr_t netmask, + unsigned int netbits, in_addr_t gateway, const struct tuntap *tt, unsigned int flags, @@ -952,7 +978,7 @@ CLEAR(r); r.flags = RT_DEFINED|RT_ADDED; r.network = network; - r.netmask = netmask; + r.netbits = netbits; r.gateway = gateway; delete_route(&r, tt, flags, rgi, es, ctx); } @@ -971,7 +997,7 @@ { if (rb->bypass[i]) { - ret = add_route3(rb->bypass[i], IPV4_NETMASK_HOST, gateway, tt, + ret = add_route3(rb->bypass[i], IPV4_NETBITS_HOST, gateway, tt, flags | ROUTE_REF_GW, rgi, es, ctx) && ret; } } @@ -993,7 +1019,7 @@ if (rb->bypass[i]) { del_route3(rb->bypass[i], - IPV4_NETMASK_HOST, + IPV4_NETBITS_HOST, gateway, tt, flags | ROUTE_REF_GW, @@ -1057,7 +1083,7 @@ if ((rl->spec.flags & RTSA_REMOTE_HOST) && rl->spec.remote_host != IPV4_INVALID_ADDR) { - ret = add_route3(rl->spec.remote_host, IPV4_NETMASK_HOST, + ret = add_route3(rl->spec.remote_host, IPV4_NETBITS_HOST, rl->rgi.gateway.addr, tt, flags | ROUTE_REF_GW, &rl->rgi, es, ctx); rl->iflags |= RL_DID_LOCAL; @@ -1078,11 +1104,11 @@ if (rl->flags & RG_DEF1) { /* add new default route (1st component) */ - ret = add_route3(0x00000000, 0x80000000, rl->spec.remote_endpoint, + ret = add_route3(0x00000000, 1, rl->spec.remote_endpoint, tt, flags, &rl->rgi, es, ctx) && ret; /* add new default route (2nd component) */ - ret = add_route3(0x80000000, 0x80000000, rl->spec.remote_endpoint, + ret = add_route3(0x80000000, 1, rl->spec.remote_endpoint, tt, flags, &rl->rgi, es, ctx) && ret; } else @@ -1120,7 +1146,7 @@ if (rl->iflags & RL_DID_LOCAL) { del_route3(rl->spec.remote_host, - IPV4_NETMASK_HOST, + IPV4_NETBITS_HOST, rl->rgi.gateway.addr, tt, flags | ROUTE_REF_GW, @@ -1140,7 +1166,7 @@ { /* delete default route (1st component) */ del_route3(0x00000000, - 0x80000000, + 1, rl->spec.remote_endpoint, tt, flags, @@ -1150,7 +1176,7 @@ /* delete default route (2nd component) */ del_route3(0x80000000, - 0x80000000, + 1, rl->spec.remote_endpoint, tt, flags, @@ -1215,7 +1241,7 @@ for (r = rl->routes; r; r = r->next) { - check_subnet_conflict(r->network, r->netmask, "route"); + check_subnet_conflict(r->network, netbits_to_netmask((int)r->netbits), "route"); if (flags & ROUTE_DELETE_FIRST) { delete_route(r, tt, flags, &rl->rgi, es, ctx); @@ -1432,14 +1458,18 @@ if (r->flags & RT_DEFINED) { setenv_route_addr(es, "network", r->network, i); - setenv_route_addr(es, "netmask", r->netmask, i); + setenv_route_addr(es, "netmask", netbits_to_netmask(r->netbits), i); setenv_route_addr(es, "gateway", r->gateway, i); + struct buffer name1 = alloc_buf_gc(256, &gc); + buf_printf(&name1, "route_netbits_%d", i); + setenv_int(es, BSTR(&name1), (int)r->netbits); + if (r->flags & RT_METRIC_DEFINED) { - struct buffer name = alloc_buf_gc(256, &gc); - buf_printf(&name, "route_metric_%d", i); - setenv_int(es, BSTR(&name), r->metric); + struct buffer name2 = alloc_buf_gc(256, &gc); + buf_printf(&name2, "route_metric_%d", i); + setenv_int(es, BSTR(&name2), r->metric); } } gc_free(&gc); @@ -1519,7 +1549,7 @@ static int local_route(in_addr_t network, - in_addr_t netmask, + unsigned int netbits, in_addr_t gateway, const struct route_gateway_info *rgi) { @@ -1528,7 +1558,7 @@ if (rgi && (rgi->flags & rgi_needed) == rgi_needed && gateway == rgi->gateway.addr - && netmask == 0xFFFFFFFF) + && netbits == IPV4_NETBITS_HOST) { if (((network ^ rgi->gateway.addr) & rgi->gateway.netmask) == 0) { @@ -1583,12 +1613,12 @@ #if !defined(TARGET_LINUX) const char *network = print_in_addr_t(r->network, 0, &gc); #if !defined(TARGET_AIX) - const char *netmask = print_in_addr_t(r->netmask, 0, &gc); + const char *netmask = print_in_addr_t(netbits_to_netmask((int)r->netbits), 0, &gc); #endif const char *gateway = print_in_addr_t(r->gateway, 0, &gc); #endif - is_local_route = local_route(r->network, r->netmask, r->gateway, rgi); + is_local_route = local_route(r->network, r->netbits, r->gateway, rgi); if (is_local_route == LR_ERROR) { goto done; @@ -1609,7 +1639,7 @@ } status = RTA_SUCCESS; - int ret = net_route_v4_add(ctx, &r->network, netmask_to_netbits2(r->netmask), + int ret = net_route_v4_add(ctx, &r->network, (int)r->netbits, &r->gateway, iface, 0, metric); if (ret == -EEXIST) { @@ -1840,10 +1870,9 @@ #elif defined(TARGET_AIX) { - int netbits = netmask_to_netbits2(r->netmask); argv_printf(&argv, "%s add -net %s/%d %s", ROUTE_PATH, - network, netbits, gateway); + network, r->netbits, gateway); argv_msg(D_ROUTE, &argv); bool ret = openvpn_execve_check(&argv, es, 0, "ERROR: AIX route add command failed"); @@ -2176,14 +2205,14 @@ #if !defined(TARGET_LINUX) network = print_in_addr_t(r->network, 0, &gc); #if !defined(TARGET_AIX) - netmask = print_in_addr_t(r->netmask, 0, &gc); + netmask = print_in_addr_t(netbits_to_netmask((int)r->netbits), 0, &gc); #endif #if !defined(TARGET_ANDROID) gateway = print_in_addr_t(r->gateway, 0, &gc); #endif #endif - is_local_route = local_route(r->network, r->netmask, r->gateway, rgi); + is_local_route = local_route(r->network, r->netbits, r->gateway, rgi); if (is_local_route == LR_ERROR) { goto done; @@ -2196,7 +2225,7 @@ metric = r->metric; } - if (net_route_v4_del(ctx, &r->network, netmask_to_netbits2(r->netmask), + if (net_route_v4_del(ctx, &r->network, (int)r->netbits, &r->gateway, NULL, 0, metric) < 0) { msg(M_WARN, "ERROR: Linux route delete command failed"); @@ -2318,10 +2347,9 @@ #elif defined(TARGET_AIX) { - int netbits = netmask_to_netbits2(r->netmask); argv_printf(&argv, "%s delete -net %s/%d %s", ROUTE_PATH, - network, netbits, gateway); + network, r->netbits, gateway); argv_msg(D_ROUTE, &argv); openvpn_execve_check(&argv, es, 0, "ERROR: AIX route delete command failed"); } @@ -2840,13 +2868,14 @@ int ret = RTA_ERROR; DWORD status; const DWORD if_index = (adapter_index == TUN_ADAPTER_INDEX_INVALID) ? windows_route_find_if_index(r, tt) : adapter_index; + const in_addr_t netmask = netbits_to_netmask((int)r->netbits); if (if_index != TUN_ADAPTER_INDEX_INVALID) { MIB_IPFORWARDROW fr; CLEAR(fr); fr.dwForwardDest = htonl(r->network); - fr.dwForwardMask = htonl(r->netmask); + fr.dwForwardMask = htonl(netmask); fr.dwForwardPolicy = 0; fr.dwForwardNextHop = htonl(r->gateway); fr.dwForwardIfIndex = if_index; @@ -2860,11 +2889,11 @@ fr.dwForwardMetric4 = METRIC_NOT_USED; fr.dwForwardMetric5 = METRIC_NOT_USED; - if ((r->network & r->netmask) != r->network) + if ((r->network & netmask) != r->network) { msg(M_WARN, "Warning: address %s is not a network address in relation to netmask %s", print_in_addr_t(r->network, 0, &gc), - print_in_addr_t(r->netmask, 0, &gc)); + print_in_addr_t(netmask, 0, &gc)); } status = CreateIpForwardEntry(&fr); @@ -2932,6 +2961,7 @@ bool ret = false; DWORD status; const DWORD if_index = windows_route_find_if_index(r, tt); + const in_addr_t netmask = netbits_to_netmask((int)r->netbits); if (if_index != TUN_ADAPTER_INDEX_INVALID) { @@ -2939,7 +2969,7 @@ CLEAR(fr); fr.dwForwardDest = htonl(r->network); - fr.dwForwardMask = htonl(r->netmask); + fr.dwForwardMask = htonl(netmask); fr.dwForwardPolicy = 0; fr.dwForwardNextHop = htonl(r->gateway); fr.dwForwardIfIndex = if_index; @@ -3016,7 +3046,7 @@ .metric = (r->flags & RT_METRIC_DEFINED ? r->metric : -1) }; - netmask_to_netbits(r->network, r->netmask, &msg.prefix_len); + msg.prefix_len = r->netbits; if (msg.prefix_len == -1) { msg.prefix_len = 32; @@ -3996,7 +4026,7 @@ while (iplist) { bool succeed = false; - const in_addr_t ip = getaddr(GETADDR_HOST_ORDER, iplist->IpAddress.String, 0, &succeed, NULL); + const in_addr_t ip = getaddr(GETADDR_HOST_ORDER, iplist->IpAddress.String, NULL, 0, &succeed, NULL); if (succeed) { add_host_route_if_nonlocal(rb, ip); @@ -4096,7 +4126,7 @@ { if (rgi) { - if (local_route(addr, 0xFFFFFFFF, rgi->gateway.addr, rgi)) + if (local_route(addr, IPV4_NETBITS_HOST, rgi->gateway.addr, rgi)) { return TLA_LOCAL; } diff --git a/src/openvpn/route.h b/src/openvpn/route.h index 421e7d2..a117584 100644 --- a/src/openvpn/route.h +++ b/src/openvpn/route.h @@ -117,7 +117,7 @@ unsigned int flags; const struct route_option *option; in_addr_t network; - in_addr_t netmask; + unsigned int netbits; in_addr_t gateway; int metric; }; diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index 17c5e76..767036f 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -179,6 +179,7 @@ in_addr_t getaddr(unsigned int flags, const char *hostname, + unsigned int *netbits, int resolve_retry_seconds, bool *succeeded, struct signal_info *sig_info) @@ -186,7 +187,7 @@ in_addr_t addr; int status; - status = get_addr_generic(AF_INET, flags, hostname, &addr, NULL, + status = get_addr_generic(AF_INET, flags, hostname, &addr, netbits, resolve_retry_seconds, sig_info, M_WARN); if (status==0) diff --git a/src/openvpn/socket.h b/src/openvpn/socket.h index 47083ad..f6165b2 100644 --- a/src/openvpn/socket.h +++ b/src/openvpn/socket.h @@ -524,6 +524,7 @@ */ in_addr_t getaddr(unsigned int flags, const char *hostname, + unsigned int *netbits, int resolve_retry_seconds, bool *succeeded, struct signal_info *sig_info); diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index 739e008..92c5e2b 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -113,7 +113,7 @@ if (addr.family == AF_INET) { addr.address.ipv4.s_addr = htonl(tt->local); - addr.prefix_len = netmask_to_netbits2(tt->adapter_netmask); + addr.prefix_len = tt->netbits; msg(D_IFCONFIG, "INET address service: %s %s/%d", add ? "add" : "remove", print_in_addr_t(tt->local, 0, &gc), addr.prefix_len); @@ -499,17 +499,17 @@ static const char ifconfig_warn_how_to_silence[] = "(silence this warning with --ifconfig-nowarn)"; /* - * If !tun_p2p, make sure ifconfig_remote_netmask looks - * like a netmask. + * If !tun_p2p, make sure either ifconfig_netbits is + * set or ifconfig_remote looks like a netmask. * - * If tun_p2p, make sure ifconfig_remote_netmask looks + * If tun_p2p, make sure ifconfig_remote looks * like an IPv4 address. */ static void -ifconfig_sanity_check(bool tun_p2p, in_addr_t addr) +ifconfig_sanity_check(bool tun_p2p, in_addr_t addr, int netbits) { struct gc_arena gc = gc_new(); - const bool looks_like_netmask = ((addr & 0xFF000000) == 0xFF000000); + const bool looks_like_netmask = addr && ((addr & 0xFF000000) == 0xFF000000); if (tun_p2p) { if (looks_like_netmask) @@ -521,9 +521,11 @@ } else { - if (!looks_like_netmask) + if (netbits < 0 || !looks_like_netmask) { - msg(M_WARN, "WARNING: Since you are using subnet topology, the second argument to --ifconfig must be a netmask, for example something like 255.255.255.0. %s", + msg(M_WARN, "WARNING: Since you are using topology subnet, you must either " + "provide a valid prefix length in the first argument of --ifconfig (eg. 10.8.0.0/24) " + "or a valid netmask as the second argument (eg. 255.255.255.0). %s", ifconfig_warn_how_to_silence); } } @@ -539,34 +541,36 @@ int type, in_addr_t public, in_addr_t local, - in_addr_t remote_netmask) + in_addr_t remote, + int netbits) { struct gc_arena gc = gc_new(); #if 0 - msg(M_INFO, "CHECK_ADDR_CLASH type=%d public=%s local=%s, remote_netmask=%s", + msg(M_INFO, "CHECK_ADDR_CLASH type=%d public=%s local=%s, netbits=%d, remote=%s", type, print_in_addr_t(public, 0, &gc), print_in_addr_t(local, 0, &gc), - print_in_addr_t(remote_netmask, 0, &gc)); + netbits, + print_in_addr_t(remote, 0, &gc)); #endif if (public) { if (type == DEV_TYPE_TUN) { - const in_addr_t test_netmask = 0xFFFFFF00; - const in_addr_t public_net = public &test_netmask; - const in_addr_t local_net = local & test_netmask; - const in_addr_t remote_net = remote_netmask & test_netmask; + const in_addr_t netmask = netbits < 0 ? 0xFFFFFF00 : netbits_to_netmask(netbits); + const in_addr_t public_net = public &netmask; + const in_addr_t local_net = local & netmask; + const in_addr_t remote_net = remote & netmask; - if (public == local || public == remote_netmask) + if (public == local || public == remote) { msg(M_WARN, "WARNING: --%s address [%s] conflicts with --ifconfig address pair [%s, %s]. %s", name, print_in_addr_t(public, 0, &gc), print_in_addr_t(local, 0, &gc), - print_in_addr_t(remote_netmask, 0, &gc), + print_in_addr_t(remote, 0, &gc), ifconfig_warn_how_to_silence); } @@ -577,22 +581,23 @@ name, print_in_addr_t(public, 0, &gc), print_in_addr_t(local, 0, &gc), - print_in_addr_t(remote_netmask, 0, &gc), + print_in_addr_t(remote ? remote : netmask, 0, &gc), ifconfig_warn_how_to_silence); } } else if (type == DEV_TYPE_TAP) { - const in_addr_t public_network = public &remote_netmask; - const in_addr_t virtual_network = local & remote_netmask; - if (public_network == virtual_network) + const in_addr_t netmask = netbits_to_netmask(netbits); + const in_addr_t public_network = public &netmask; + const in_addr_t virtual_network = local & netmask; + if (netmask && public_network == virtual_network) { msg(M_WARN, - "WARNING: --%s address [%s] conflicts with --ifconfig subnet [%s, %s] -- local and remote addresses cannot be inside of the --ifconfig subnet. %s", + "WARNING: --%s address [%s] conflicts with --ifconfig subnet [%s/%d] -- local and remote addresses cannot be inside of the --ifconfig subnet. %s", name, print_in_addr_t(public, 0, &gc), print_in_addr_t(local, 0, &gc), - print_in_addr_t(remote_netmask, 0, &gc), + netbits, ifconfig_warn_how_to_silence); } } @@ -669,9 +674,10 @@ { if (!is_tun_p2p(tt)) { + const in_addr_t netmask = netbits_to_netmask(tt->netbits); buf_printf(&out, "%s %s", - print_in_addr_t(tt->local & tt->remote_netmask, 0, gc), - print_in_addr_t(tt->remote_netmask, 0, gc)); + print_in_addr_t(tt->local & netmask, 0, gc), + print_in_addr_t(netmask, 0, gc)); } else if (tt->type == DEV_TYPE_TUN) /* tun p2p topology */ { @@ -679,12 +685,12 @@ if (remote) { r = print_in_addr_t(tt->local, 0, gc); - l = print_in_addr_t(tt->remote_netmask, 0, gc); + l = print_in_addr_t(tt->remote, 0, gc); } else { l = print_in_addr_t(tt->local, 0, gc); - r = print_in_addr_t(tt->remote_netmask, 0, gc); + r = print_in_addr_t(tt->remote, 0, gc); } buf_printf(&out, "%s %s", r, l); } @@ -765,7 +771,8 @@ { struct gc_arena gc = gc_new(); const char *ifconfig_local = print_in_addr_t(tt->local, 0, &gc); - const char *ifconfig_remote_netmask = print_in_addr_t(tt->remote_netmask, 0, &gc); + const char *ifconfig_remote = tt->remote ? print_in_addr_t(tt->remote, 0, &gc) : NULL; + const char *ifconfig_netmask = tt->netbits >= 0 ? print_in_addr_t(netbits_to_netmask(tt->netbits), 0, &gc) : NULL; /* * Set environmental variables with ifconfig parameters. @@ -777,11 +784,12 @@ setenv_str(es, "ifconfig_local", ifconfig_local); if (tun) { - setenv_str(es, "ifconfig_remote", ifconfig_remote_netmask); + setenv_str(es, "ifconfig_remote", ifconfig_remote); } else { - setenv_str(es, "ifconfig_netmask", ifconfig_remote_netmask); + setenv_int(es, "ifconfig_netbits", tt->netbits); + setenv_str(es, "ifconfig_netmask", ifconfig_netmask); } } @@ -837,7 +845,7 @@ bool tun_p2p = is_tun_p2p(tt); /* - * Convert arguments to binary IPv4 addresses. + * Convert arguments to binary IPv4 addresses and netbits. */ tt->local = getaddr( @@ -846,27 +854,48 @@ | GETADDR_FATAL_ON_SIGNAL | GETADDR_FATAL, ifconfig_local_parm, + NULL, 0, NULL, NULL); - tt->remote_netmask = getaddr( + tt->remote = getaddr( (tun_p2p ? GETADDR_RESOLVE : 0) | GETADDR_HOST_ORDER | GETADDR_FATAL_ON_SIGNAL | GETADDR_FATAL, ifconfig_remote_netmask_parm, + NULL, 0, NULL, NULL); + /* in p2p mode discard the netbits otherwise discard the remote */ + if (!tun_p2p) + { + if (tt->remote) + { + tt->netbits = netmask_to_netbits2(tt->remote); + tt->remote = 0; + } + else + { + msg(M_FATAL, "init_tun: can not figure out the subnet from the remote parameter (%s)", ifconfig_remote_netmask_parm); + } + tt->remote = 0; + } + else + { + tt->netbits = -1; + } + /* * Look for common errors in --ifconfig parms */ if (strict_warn) { struct addrinfo *curele; - ifconfig_sanity_check(tun_p2p, tt->remote_netmask); + ifconfig_sanity_check(tun_p2p, tt->remote, tt->netbits); /* * If local_public or remote_public addresses are defined, @@ -877,11 +906,13 @@ { if (curele->ai_family == AF_INET) { + const in_addr_t local = ntohl(((struct sockaddr_in *)curele->ai_addr)->sin_addr.s_addr); check_addr_clash("local", tt->type, - ((struct sockaddr_in *)curele->ai_addr)->sin_addr.s_addr, + local, tt->local, - tt->remote_netmask); + tt->remote, + tt->netbits); } } @@ -889,17 +920,19 @@ { if (curele->ai_family == AF_INET) { + const in_addr_t remote = ntohl(((struct sockaddr_in *)curele->ai_addr)->sin_addr.s_addr); check_addr_clash("remote", tt->type, - ((struct sockaddr_in *)curele->ai_addr)->sin_addr.s_addr, + remote, tt->local, - tt->remote_netmask); + tt->remote, + tt->netbits); } } if (!tun_p2p) { - check_subnet_conflict(tt->local, tt->remote_netmask, "TUN/TAP adapter"); + check_subnet_conflict(tt->local, netbits_to_netmask(tt->netbits), "TUN/TAP adapter"); } else { @@ -914,12 +947,12 @@ */ if (tun_p2p) { - verify_255_255_255_252(tt->local, tt->remote_netmask); + verify_255_255_255_252(tt->local, tt->remote); tt->adapter_netmask = ~3; } else { - tt->adapter_netmask = tt->remote_netmask; + tt->adapter_netmask = netbits_to_netmask(tt->netbits); } #endif @@ -1062,8 +1095,9 @@ create_arbitrary_remote( struct tuntap *tt ) { in_addr_t remote; + const in_addr_t netmask = netbits_to_netmask(tt->netbits); - remote = (tt->local & tt->remote_netmask) +1; + remote = (tt->local & netmask) +1; if (remote == tt->local) { @@ -1300,7 +1334,11 @@ #if !defined(TARGET_LINUX) const char *ifconfig_local = NULL; - const char *ifconfig_remote_netmask = NULL; +#if !defined(_WIN32) + const char *ifconfig_remote = NULL; +#endif + const char *ifconfig_netmask = NULL; + const in_addr_t netmask = netbits_to_netmask(tt->netbits); struct argv argv = argv_new(); struct gc_arena gc = gc_new(); @@ -1308,7 +1346,10 @@ * Set ifconfig parameters */ ifconfig_local = print_in_addr_t(tt->local, 0, &gc); - ifconfig_remote_netmask = print_in_addr_t(tt->remote_netmask, 0, &gc); +#if !defined(_WIN32) + ifconfig_remote = print_in_addr_t(tt->remote, 0, &gc); +#endif + ifconfig_netmask = print_in_addr_t(netmask, 0, &gc); #endif #if defined(TARGET_LINUX) @@ -1324,16 +1365,14 @@ if (tun_p2p) { - if (net_addr_ptp_v4_add(ctx, ifname, &tt->local, - &tt->remote_netmask) < 0) + if (net_addr_ptp_v4_add(ctx, ifname, &tt->local, &tt->remote) < 0) { msg(M_FATAL, "Linux can't add IP to interface %s", ifname); } } else { - if (net_addr_v4_add(ctx, ifname, &tt->local, - netmask_to_netbits2(tt->remote_netmask)) < 0) + if (net_addr_v4_add(ctx, ifname, &tt->local, tt->netbits) < 0) { msg(M_FATAL, "Linux can't add IP to interface %s", ifname); } @@ -1341,8 +1380,11 @@ #elif defined(TARGET_ANDROID) char out[64]; - snprintf(out, sizeof(out), "%s %s %d %s", ifconfig_local, - ifconfig_remote_netmask, tun_mtu, print_topology(tt->topology)); + snprintf(out, sizeof(out), "%s %s %d %s", + ifconfig_local, + ifconfig_remote ? ifconfig_remote : ifconfig_netmask, + tun_mtu, + print_topology(tt->topology)); management_android_control(management, "IFCONFIG", out); #elif defined(TARGET_SOLARIS) @@ -1354,7 +1396,7 @@ if (tun_p2p) { argv_printf(&argv, "%s %s %s %s mtu %d up", IFCONFIG_PATH, ifname, - ifconfig_local, ifconfig_remote_netmask, tun_mtu); + ifconfig_local, ifconfig_remote, tun_mtu); argv_msg(M_INFO, &argv); if (!openvpn_execve_check(&argv, es, 0, "Solaris ifconfig phase-1 failed")) @@ -1369,13 +1411,13 @@ { argv_printf(&argv, "%s %s %s %s netmask %s mtu %d up", IFCONFIG_PATH, ifname, ifconfig_local, ifconfig_local, - ifconfig_remote_netmask, tun_mtu); + ifconfig_netmask, tun_mtu); } else /* tap */ { argv_printf(&argv, "%s %s %s netmask %s up", IFCONFIG_PATH, ifname, ifconfig_local, - ifconfig_remote_netmask); + ifconfig_netmask); } argv_msg(M_INFO, &argv); @@ -1390,8 +1432,8 @@ struct route_ipv4 r; CLEAR(r); r.flags = RT_DEFINED | RT_METRIC_DEFINED; - r.network = tt->local & tt->remote_netmask; - r.netmask = tt->remote_netmask; + r.network = tt->local & netmask; + r.netbits = tt->netbits; r.gateway = tt->local; r.metric = 0; add_route(&r, tt, 0, NULL, es, NULL); @@ -1413,7 +1455,7 @@ argv_printf(&argv, "%s %s %s %s mtu %d netmask 255.255.255.255 up -link0", IFCONFIG_PATH, ifname, ifconfig_local, - ifconfig_remote_netmask, tun_mtu); + ifconfig_remote, tun_mtu); } else if (tt->type == DEV_TYPE_TUN) { @@ -1421,13 +1463,13 @@ argv_printf(&argv, "%s %s %s %s mtu %d netmask %s up -link0", IFCONFIG_PATH, ifname, ifconfig_local, print_in_addr_t(remote_end, 0, &gc), tun_mtu, - ifconfig_remote_netmask); + ifconfig_netmask); } else /* tap */ { argv_printf(&argv, "%s %s %s netmask %s mtu %d link0", IFCONFIG_PATH, ifname, ifconfig_local, - ifconfig_remote_netmask, tun_mtu); + ifconfig_netmask, tun_mtu); } argv_msg(M_INFO, &argv); openvpn_execve_check(&argv, es, S_FATAL, "OpenBSD ifconfig failed"); @@ -1438,8 +1480,8 @@ struct route_ipv4 r; CLEAR(r); r.flags = RT_DEFINED; - r.network = tt->local & tt->remote_netmask; - r.netmask = tt->remote_netmask; + r.network = tt->local & netmask; + r.netbits = tt->netbits; r.gateway = remote_end; add_route(&r, tt, 0, NULL, es, NULL); } @@ -1451,14 +1493,14 @@ { argv_printf(&argv, "%s %s %s %s mtu %d netmask 255.255.255.255 up", IFCONFIG_PATH, ifname, ifconfig_local, - ifconfig_remote_netmask, tun_mtu); + ifconfig_remote, tun_mtu); } else if (tt->type == DEV_TYPE_TUN) { remote_end = create_arbitrary_remote(tt); argv_printf(&argv, "%s %s %s %s mtu %d netmask %s up", IFCONFIG_PATH, ifname, ifconfig_local, print_in_addr_t(remote_end, 0, &gc), - tun_mtu, ifconfig_remote_netmask); + tun_mtu, ifconfig_netmask); } else /* tap */ { @@ -1469,7 +1511,7 @@ */ argv_printf(&argv, "%s %s %s netmask %s mtu %d", IFCONFIG_PATH, ifname, ifconfig_local, - ifconfig_remote_netmask, tun_mtu); + ifconfig_netmask, tun_mtu); } argv_msg(M_INFO, &argv); openvpn_execve_check(&argv, es, S_FATAL, "NetBSD ifconfig failed"); @@ -1480,8 +1522,8 @@ struct route_ipv4 r; CLEAR(r); r.flags = RT_DEFINED; - r.network = tt->local & tt->remote_netmask; - r.netmask = tt->remote_netmask; + r.network = tt->local & netmask; + r.netbits = tt->netbits; r.gateway = remote_end; add_route(&r, tt, 0, NULL, es, NULL); } @@ -1503,18 +1545,18 @@ { argv_printf(&argv, "%s %s %s %s mtu %d netmask 255.255.255.255 up", IFCONFIG_PATH, ifname, ifconfig_local, - ifconfig_remote_netmask, tun_mtu); + ifconfig_remote, tun_mtu); } else if (tt->type == DEV_TYPE_TUN) { argv_printf(&argv, "%s %s %s %s netmask %s mtu %d up", IFCONFIG_PATH, ifname, ifconfig_local, ifconfig_local, - ifconfig_remote_netmask, tun_mtu); + ifconfig_netmask, tun_mtu); } else /* tap */ { argv_printf(&argv, "%s %s %s netmask %s mtu %d up", IFCONFIG_PATH, - ifname, ifconfig_local, ifconfig_remote_netmask, + ifname, ifconfig_local, ifconfig_netmask, tun_mtu); } @@ -1527,8 +1569,8 @@ struct route_ipv4 r; CLEAR(r); r.flags = RT_DEFINED; - r.network = tt->local & tt->remote_netmask; - r.netmask = tt->remote_netmask; + r.network = tt->local & netmask; + r.netbits = tt->netbits; r.gateway = tt->local; add_route(&r, tt, 0, NULL, es, NULL); } @@ -1540,13 +1582,12 @@ { argv_printf(&argv, "%s %s %s %s mtu %d netmask 255.255.255.255 up", IFCONFIG_PATH, ifname, ifconfig_local, - ifconfig_remote_netmask, tun_mtu); + ifconfig_remote, tun_mtu); } else /* tun with topology subnet and tap mode (always subnet) */ { - int netbits = netmask_to_netbits2(tt->remote_netmask); argv_printf(&argv, "%s %s %s/%d mtu %d up", IFCONFIG_PATH, - ifname, ifconfig_local, netbits, tun_mtu ); + ifname, ifconfig_local, tt->netbits, tun_mtu ); } argv_msg(M_INFO, &argv); @@ -1565,7 +1606,7 @@ /* example: ifconfig tap0 172.30.1.1 netmask 255.255.254.0 up */ argv_printf(&argv, "%s %s %s netmask %s mtu %d up", IFCONFIG_PATH, - ifname, ifconfig_local, ifconfig_remote_netmask, tun_mtu); + ifname, ifconfig_local, ifconfig_netmask, tun_mtu); argv_msg(M_INFO, &argv); openvpn_execve_check(&argv, aix_es, S_FATAL, "AIX ifconfig failed"); @@ -1578,7 +1619,7 @@ msg(M_INFO, "******** NOTE: Please manually set the IP/netmask of '%s' to %s/%s (if it is not already set)", ifname, ifconfig_local, - ifconfig_remote_netmask); + ifconfig_netmask); } else if (tt->options.ip_win32_type == IPW32_SET_DHCP_MASQ || tt->options.ip_win32_type == IPW32_SET_ADAPTIVE) { @@ -1660,12 +1701,10 @@ undo_ifconfig_ipv4(struct tuntap *tt, openvpn_net_ctx_t *ctx) { #if defined(TARGET_LINUX) - int netbits = netmask_to_netbits2(tt->remote_netmask); - if (is_tun_p2p(tt)) { if (net_addr_ptp_v4_del(ctx, tt->actual_name, &tt->local, - &tt->remote_netmask) < 0) + &tt->remote) < 0) { msg(M_WARN, "Linux can't del IP from iface %s", tt->actual_name); @@ -1673,7 +1712,7 @@ } else { - if (net_addr_v4_del(ctx, tt->actual_name, &tt->local, netbits) < 0) + if (net_addr_v4_del(ctx, tt->actual_name, &tt->local, tt->netbits) < 0) { msg(M_WARN, "Linux can't del IP from iface %s", tt->actual_name); @@ -4683,8 +4722,8 @@ if (ip_str && netmask_str && strlen(ip_str) && strlen(netmask_str)) { - *ip = getaddr(getaddr_flags, ip_str, 0, &succeed1, NULL); - *netmask = getaddr(getaddr_flags, netmask_str, 0, &succeed2, NULL); + *ip = getaddr(getaddr_flags, ip_str, NULL, 0, &succeed1, NULL); + *netmask = getaddr(getaddr_flags, netmask_str, NULL, 0, &succeed2, NULL); ret = (succeed1 == true && succeed2 == true); } } @@ -5370,7 +5409,7 @@ break; } - ip = getaddr(getaddr_flags, ip_str, 0, &succeed, NULL); + ip = getaddr(getaddr_flags, ip_str, NULL, 0, &succeed, NULL); if (!succeed) { break; @@ -6428,11 +6467,12 @@ if (!tt->did_ifconfig_setup || tt->topology == TOP_SUBNET) { in_addr_t ep[3]; + const in_addr_t netmask = netbits_to_netmask(tt->netbits); BOOL status; ep[0] = htonl(tt->local); - ep[1] = htonl(tt->local & tt->remote_netmask); - ep[2] = htonl(tt->remote_netmask); + ep[1] = htonl(tt->local & netmask); + ep[2] = htonl(netmask); status = DeviceIoControl(tt->hand, TAP_WIN_IOCTL_CONFIG_TUN, ep, sizeof(ep), @@ -6456,7 +6496,7 @@ { in_addr_t ep[2]; ep[0] = htonl(tt->local); - ep[1] = htonl(tt->remote_netmask); + ep[1] = htonl(tt->remote); if (!DeviceIoControl(tt->hand, TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT, ep, sizeof(ep), @@ -6485,11 +6525,11 @@ { if (tt->topology == TOP_SUBNET) { - ep[2] = dhcp_masq_addr(tt->local, tt->remote_netmask, tt->options.dhcp_masq_custom_offset ? tt->options.dhcp_masq_offset : 0); + ep[2] = dhcp_masq_addr(tt->local, netbits_to_netmask(tt->netbits), tt->options.dhcp_masq_custom_offset ? tt->options.dhcp_masq_offset : 0); } else { - ep[2] = htonl(tt->remote_netmask); + ep[2] = htonl(tt->remote); } } else diff --git a/src/openvpn/tun.h b/src/openvpn/tun.h index 33b9552..68aa3b8 100644 --- a/src/openvpn/tun.h +++ b/src/openvpn/tun.h @@ -188,7 +188,8 @@ /* ifconfig parameters */ in_addr_t local; - in_addr_t remote_netmask; + in_addr_t remote; + int netbits; struct in6_addr local_ipv6; struct in6_addr remote_ipv6;