]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
dco: add option check - disable DCO if conflict is detected
authorAntonio Quartulli <a@unstable.cc>
Mon, 18 Jul 2022 22:17:57 +0000 (00:17 +0200)
committerGert Doering <gert@greenie.muc.de>
Tue, 19 Jul 2022 08:53:15 +0000 (10:53 +0200)
Signed-off-by: Antonio Quartulli <a@unstable.cc>
Acked-by: Gert Doering <gert@greenie.muc.de>
Message-Id: <20220718221757.545-1-a@unstable.cc>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg24701.html
Signed-off-by: Gert Doering <gert@greenie.muc.de>
src/openvpn/Makefile.am
src/openvpn/dco.c [new file with mode: 0644]
src/openvpn/openvpn.vcxproj
src/openvpn/openvpn.vcxproj.filters
src/openvpn/options.c

index 91635b674a9687aabe8e8db6ec3503b0d11125bd..aaa1dbce38ea6818d3e30ba042e16e2ed5430fb8 100644 (file)
@@ -53,7 +53,7 @@ openvpn_SOURCES = \
        crypto.c crypto.h crypto_backend.h \
        crypto_openssl.c crypto_openssl.h \
        crypto_mbedtls.c crypto_mbedtls.h \
-       dco.h dco_internal.h \
+       dco.c dco.h dco_internal.h \
        dco_linux.c dco_linux.h \
        dhcp.c dhcp.h \
        dns.c dns.h \
diff --git a/src/openvpn/dco.c b/src/openvpn/dco.c
new file mode 100644 (file)
index 0000000..b3fd135
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ *  OpenVPN -- An application to securely tunnel IP networks
+ *             over a single TCP/UDP port, with support for SSL/TLS-based
+ *             session authentication and key exchange,
+ *             packet encryption, packet authentication, and
+ *             packet compression.
+ *
+ *  Copyright (C) 2021-2022 Arne Schwabe <arne@rfc2549.org>
+ *  Copyright (C) 2021-2022 Antonio Quartulli <a@unstable.cc>
+ *  Copyright (C) 2021-2022 OpenVPN Inc <sales@openvpn.net>
+ *
+ *  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 (see the file COPYING included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#elif defined(_MSC_VER)
+#include "config-msvc.h"
+#endif
+
+#if defined(ENABLE_DCO)
+
+#include "syshead.h"
+#include "dco.h"
+#include "networking.h"
+#include "options.h"
+#include "ssl_ncp.h"
+#include "tun.h"
+
+static bool
+dco_check_option_conflict_platform(int msglevel, const struct options *o)
+{
+#if defined(TARGET_LINUX)
+    /* if the device name is fixed, we need to check if an interface with this
+     * name already exists. IF it does, it must be a DCO interface, otherwise
+     * DCO has to be disabled in order to continue.
+     */
+    if (tun_name_is_fixed(o->dev))
+    {
+        char iftype[IFACE_TYPE_LEN_MAX];
+        /* we pass NULL as net_ctx because using DCO on Linux implies that we
+         * are using SITNL and the latter does not need any context. This way we
+         * don't need to have the net_ctx percolate all the way here
+         */
+        int ret = net_iface_type(NULL, o->dev, iftype);
+        if ((ret == 0) && (strcmp(iftype, "ovpn-dco") != 0))
+        {
+            msg(msglevel, "Interface %s exists and is non-DCO. Disabling data channel offload",
+                o->dev);
+            return false;
+        }
+        else if ((ret < 0) && (ret != -ENODEV))
+        {
+            msg(msglevel, "Cannot retrieve type of device %s: %s (%d)", o->dev,
+                strerror(-ret), ret);
+        }
+    }
+#endif /* if defined(TARGET_LINUX) */
+    return true;
+}
+
+static bool
+dco_check_option_conflict_ce(const struct connection_entry *ce, int msglevel)
+{
+    if (ce->fragment)
+    {
+        msg(msglevel, "Note: --fragment disables data channel offload.");
+        return false;
+    }
+
+    if (ce->http_proxy_options)
+    {
+        msg(msglevel, "Note: --http-proxy disables data channel offload.");
+        return false;
+    }
+
+    if (ce->socks_proxy_server)
+    {
+        msg(msglevel, "Note: --socks-proxy disables data channel offload.");
+        return false;
+    }
+
+    return true;
+}
+
+bool
+dco_check_option_conflict(int msglevel, const struct options *o)
+{
+    if (o->tuntap_options.disable_dco)
+    {
+        /* already disabled by --disable-dco, no need to print warnings */
+        return false;
+    }
+
+    if (!dco_available(msglevel))
+    {
+        return false;
+    }
+
+    if (!dco_check_option_conflict_platform(msglevel, o))
+    {
+        return false;
+    }
+
+    if (dev_type_enum(o->dev, o->dev_type) != DEV_TYPE_TUN)
+    {
+        msg(msglevel, "Note: dev-type not tun, disabling data channel offload.");
+        return false;
+    }
+
+    /* At this point the ciphers have already been normalised */
+    if (o->enable_ncp_fallback
+        && !tls_item_in_cipher_list(o->ciphername, DCO_SUPPORTED_CIPHERS))
+    {
+        msg(msglevel, "Note: --data-cipher-fallback with cipher '%s' "
+            "disables data channel offload.", o->ciphername);
+        return false;
+    }
+
+    if (o->connection_list)
+    {
+        const struct connection_list *l = o->connection_list;
+        for (int i = 0; i < l->len; ++i)
+        {
+            if (!dco_check_option_conflict_ce(l->array[i], msglevel))
+            {
+                return false;
+            }
+        }
+    }
+    else
+    {
+        if (!dco_check_option_conflict_ce(&o->ce, msglevel))
+        {
+            return false;
+        }
+    }
+
+    if (o->mode == MODE_SERVER && o->topology != TOP_SUBNET)
+    {
+        msg(msglevel, "Note: NOT using '--topology subnet' disables data channel offload.");
+        return false;
+    }
+
+#if defined(USE_COMP)
+    if (o->comp.alg != COMP_ALG_UNDEF)
+    {
+        msg(msglevel, "Note: Using compression disables data channel offload.");
+
+        if (o->mode == MODE_SERVER && !(o->comp.flags & COMP_F_MIGRATE))
+        {
+            /* We can end up here from the multi.c call, only print the
+             * note if it is not already enabled */
+            msg(msglevel, "Consider using the '--compress migrate' option.");
+        }
+        return false;
+    }
+#endif
+
+    struct gc_arena gc = gc_new();
+    char *tmp_ciphers = string_alloc(o->ncp_ciphers, &gc);
+    const char *token;
+    while ((token = strsep(&tmp_ciphers, ":")))
+    {
+        if (!tls_item_in_cipher_list(token, DCO_SUPPORTED_CIPHERS))
+        {
+            msg(msglevel, "Note: cipher '%s' in --data-ciphers is not supported "
+                "by ovpn-dco, disabling data channel offload.", token);
+            gc_free(&gc);
+            return false;
+        }
+    }
+    gc_free(&gc);
+
+    return true;
+}
+
+#endif /* defined(ENABLE_DCO) */
index bc1a0300bf7b41722e2cac0cb56685b86b9c8bb2..0b3db7c76990ad542d31f648407bf08a72c11d57 100644 (file)
     <ClCompile Include="crypto.c" />
     <ClCompile Include="crypto_openssl.c" />
     <ClCompile Include="cryptoapi.c" />
+    <ClCompile Include="dco.c" />
     <ClCompile Include="dco_linux.c" />
     <ClCompile Include="dhcp.c" />
     <ClCompile Include="dns.c" />
index 3c21a4c6f144944b12fd30be65c1365bc2704876..169050798f4cda0a19022dff96a052d228eecf9e 100644 (file)
@@ -36,6 +36,9 @@
     <ClCompile Include="cryptoapi.c">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="dco.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
     <ClCompile Include="dco_linux.c">
       <Filter>Source Files</Filter>
     </ClCompile>
index 95d4008a974c78433f3252bd9984ed9822db15e3..7b919a1e680e860e0b485b74e14bf4f2a0fe9c20 100644 (file)
@@ -3645,6 +3645,11 @@ options_postprocess_mutate(struct options *o, struct env_set *es)
         o->verify_hash_no_ca = true;
     }
 
+    /* check if any option should force disabling DCO */
+#if defined(TARGET_LINUX)
+    o->tuntap_options.disable_dco = !dco_check_option_conflict(D_DCO, o);
+#endif
+
     /*
      * Save certain parms before modifying options during connect, especially
      * when using --pull