[NetworkManager-openvpn/th/rework-detect-version] service: rework detection of openvpn version
- From: Thomas Haller <thaller src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [NetworkManager-openvpn/th/rework-detect-version] service: rework detection of openvpn version
- Date: Mon, 3 Oct 2022 19:21:17 +0000 (UTC)
commit aab0d902d7d485fc7a54c079b52bb9a0a843f84f
Author: Thomas Haller <thaller redhat com>
Date: Fri Sep 30 16:31:08 2022 +0200
service: rework detection of openvpn version
The few enums we detected before are not flexible enough. Also, they
require code changes to the parsing, whenever we want to detect a new
version.
Rework the parsing and combine the number to one version that can be
compared with greater/less.
https://gitlab.gnome.org/GNOME/NetworkManager-openvpn/-/merge_requests/61
properties/tests/test-import-export.c | 114 ++++++++++++++++++++++++++++++++++
shared/utils.c | 44 +++++++++++++
shared/utils.h | 26 ++++++++
src/nm-openvpn-service.c | 89 +++++++++-----------------
4 files changed, 213 insertions(+), 60 deletions(-)
---
diff --git a/properties/tests/test-import-export.c b/properties/tests/test-import-export.c
index fdc9e50..7f585d0 100644
--- a/properties/tests/test-import-export.c
+++ b/properties/tests/test-import-export.c
@@ -1264,6 +1264,118 @@ test_args_parse_line (void)
/*****************************************************************************/
+static void test_version(void) {
+ const struct {
+ guint version;
+ char *const data;
+ } test_data[] = {
+ {
+ .version = 20507,
+ .data =
+ "OpenVPN 2.5.7 x86_64-redhat-linux-gnu [SSL (OpenSSL)] "
+ "[LZO] "
+ "[LZ4] "
+ "[EPOLL] [PKCS11] [MH/PKTINFO] [AEAD] built on May 31 "
+ "2022\n"
+ "library versions: OpenSSL 3.0.5 5 Jul 2022, LZO 2.10\n"
+ "Originally developed by James Yonan\n"
+ "Copyright (C) 2002-2022 OpenVPN Inc <sales openvpn net>\n"
+ "Compile time defines: enable_async_push=yes "
+ "enable_comp_stub=no "
+ "enable_crypto_ofb_cfb=yes enable_debug=yes "
+ "enable_def_auth=yes "
+ "enable_dependency_tracking=no enable_dlopen=unknown "
+ "enable_dlopen_self=unknown "
+ "enable_dlopen_self_static=unknown "
+ "enable_fast_install=needless enable_fragment=yes "
+ "enable_iproute2=no "
+ "enable_libtool_lock=yes enable_lz4=yes enable_lzo=yes "
+ "enable_management=yes enable_multihome=yes "
+ "enable_pam_dlopen=no "
+ "enable_pedantic=no enable_pf=yes enable_pkcs11=yes "
+ "enable_plugin_auth_pam=yes enable_plugin_down_root=yes "
+ "enable_plugins=yes enable_port_share=yes "
+ "enable_selinux=yes "
+ "enable_shared=yes enable_shared_with_static_runtimes=no "
+ "enable_silent_rules=yes enable_small=no enable_static=yes "
+ "enable_strict=no enable_strict_options=no "
+ "enable_systemd=yes "
+ "enable_werror=no enable_win32_dll=yes "
+ "enable_x509_alt_username=yes "
+ "with_aix_soname=aix with_crypto_library=openssl "
+ "with_gnu_ld=yes "
+ "with_mem_check=no with_openssl_engine=auto "
+ "with_sysroot=no\n"
+ "",
+ },
+ {
+ .version = 20310,
+ .data =
+ "OpenVPN 2.3.10 x86_64-pc-linux-gnu [SSL (OpenSSL)] [LZO] "
+ "[EPOLL] [PKCS11] [MH] [IPv6] built on Jan 9 2019\n"
+ "library versions: OpenSSL 1.0.2g 1 Mar 2016, LZO 2.08\n"
+ "Originally developed by James Yonan\n"
+ "Copyright (C) 2002-2010 OpenVPN Technologies, Inc. "
+ "<sales openvpn net>\n"
+ "Compile time defines: enable_crypto=yes "
+ "enable_crypto_ofb_cfb=yes enable_debug=yes "
+ "enable_def_auth=yes enable_dependency_tracking=no "
+ "enable_dlopen=unknown enable_dlopen_self=unknown "
+ "enable_dlopen_self_static=unknown enable_fast_install=yes "
+ "enable_fragment=yes enable_http_proxy=yes "
+ "enable_iproute2=yes enable_libtool_lock=yes "
+ "enable_lzo=yes enable_lzo_stub=no "
+ "enable_maintainer_mode=no enable_management=yes "
+ "enable_multi=yes enable_multihome=yes "
+ "enable_pam_dlopen=no enable_password_save=yes "
+ "enable_pedantic=no enable_pf=yes enable_pkcs11=yes "
+ "enable_plugin_auth_pam=yes enable_plugin_down_root=yes "
+ "enable_plugins=yes enable_port_share=yes "
+ "enable_selinux=no enable_server=yes enable_shared=yes "
+ "enable_shared_with_static_runtimes=no "
+ "enable_silent_rules=no enable_small=no enable_socks=yes "
+ "enable_ssl=yes enable_static=yes enable_strict=no "
+ "enable_strict_options=no enable_systemd=yes "
+ "enable_win32_dll=yes enable_x509_alt_username=yes "
+ "with_crypto_library=openssl with_gnu_ld=yes "
+ "with_mem_check=no with_plugindir='${prefix}/lib/openvpn' "
+ "with_sysroot=no\n"
+ "",
+ },
+ };
+ int i;
+
+ for (i = 0; i < (int)G_N_ELEMENTS(test_data); i++) {
+ g_assert_cmpint(test_data[i].version, ==,
+ nmovpn_version_parse(test_data[i].data));
+ }
+
+#define _test_version(v_x, v_y, v_z, encoded) \
+ G_STMT_START { \
+ const guint _encoded = (encoded); \
+ const guint _v_x = (v_x); \
+ const guint _v_y = (v_y); \
+ const guint _v_z = (v_z); \
+ guint _v2_x; \
+ guint _v2_y; \
+ guint _v2_z; \
+ \
+ g_assert_cmpint(nmovpn_version_encode(_v_x, _v_y, _v_z), ==, _encoded); \
+ \
+ nmovpn_version_decode(_encoded, &_v2_x, &_v2_y, &_v2_z); \
+ g_assert_cmpint(_v_x, ==, _v2_x); \
+ g_assert_cmpint(_v_y, ==, _v2_y); \
+ g_assert_cmpint(_v_z, ==, _v2_z); \
+ } G_STMT_END
+
+ _test_version(1, 5, 88, 10588);
+ _test_version(2, 5, 0, 20500);
+ _test_version(2, 5, 4, 20504);
+ _test_version(3, 0, 0, 30000);
+}
+
+/*****************************************************************************/
+
NMTST_DEFINE ();
int main (int argc, char **argv)
@@ -1396,6 +1508,8 @@ int main (int argc, char **argv)
_add_test_func_simple (test_args_parse_line);
+ _add_test_func_simple (test_version);
+
result = g_test_run ();
if (result != EXIT_SUCCESS)
return result;
diff --git a/shared/utils.c b/shared/utils.c
index 133da87..d688adc 100644
--- a/shared/utils.c
+++ b/shared/utils.c
@@ -335,3 +335,47 @@ out_fail:
}
/*****************************************************************************/
+
+guint
+nmovpn_version_parse (const char *version_str)
+{
+ const char *s;
+ guint v_x;
+ guint v_y;
+ guint v_z;
+
+ /* the output for --version starts with title_string, which starts with PACKAGE_STRING,
+ * which looks like "OpenVPN 2.#...". Do a strict parsing here... */
+ if ( !version_str
+ || !g_str_has_prefix (version_str, "OpenVPN 2."))
+ return NMOVPN_VERSION_UNKNOWN;
+ s = &version_str[NM_STRLEN ("OpenVPN 2.")];
+
+ if (!g_ascii_isdigit (s[0]))
+ return NMOVPN_VERSION_UNKNOWN;
+
+ v_x = 2;
+
+ v_y = 0;
+ do {
+ if (v_y > G_MAXINT / 100)
+ return NMOVPN_VERSION_UNKNOWN;
+ v_y = (v_y * 10) + (s[0] - '0');
+ } while (g_ascii_isdigit ((++s)[0]));
+ if (v_y > 99)
+ return NMOVPN_VERSION_UNKNOWN;
+
+ v_z = 0;
+ if (s[0] == '.') {
+ s++;
+ do {
+ if (v_z > G_MAXINT / 100)
+ break;
+ v_z = (v_z * 10) + (s[0] - '0');
+ } while (g_ascii_isdigit ((++s)[0]));
+ }
+ if (v_z > 99)
+ v_z = 0;
+
+ return nmovpn_version_encode (v_x, v_y, v_z);
+}
diff --git a/shared/utils.h b/shared/utils.h
index 064da72..216b708 100644
--- a/shared/utils.h
+++ b/shared/utils.h
@@ -144,4 +144,30 @@ void nmovpn_compression_to_options (NMOvpnComp comp,
const char **comp_lzo,
const char **compress);
+/*****************************************************************************/
+
+#define NMOVPN_VERSION_MAX 999999u
+#define NMOVPN_VERSION_UNKNOWN (NMOVPN_VERSION_MAX+1u)
+#define NMOVPN_VERSION_INVALID (NMOVPN_VERSION_MAX+2u)
+
+static inline guint
+nmovpn_version_encode (guint x, guint y, guint z)
+{
+ nm_assert(x <= 99);
+ nm_assert(y <= 99);
+ nm_assert(z <= 99);
+
+ return ((x * 100u + y) * 100u) + z;
+}
+
+static inline void
+nmovpn_version_decode (guint version, guint *out_x, guint *out_y, guint *out_z)
+{
+ *out_x = (version / 10000u);
+ *out_y = (version / 100u) % 100u;
+ *out_z = (version % 100u);
+}
+
+guint nmovpn_version_parse (const char *version_str);
+
#endif /* UTILS_H */
diff --git a/src/nm-openvpn-service.c b/src/nm-openvpn-service.c
index c5c6eee..aeb0cdb 100644
--- a/src/nm-openvpn-service.c
+++ b/src/nm-openvpn-service.c
@@ -85,14 +85,6 @@ NMOpenvpnPlugin *nm_openvpn_plugin_new (const char *bus_name);
/*****************************************************************************/
-typedef enum {
- OPENVPN_BINARY_VERSION_INVALID,
- OPENVPN_BINARY_VERSION_UNKNOWN,
- OPENVPN_BINARY_VERSION_2_3_OR_OLDER,
- OPENVPN_BINARY_VERSION_2_4_OR_OLDER,
- OPENVPN_BINARY_VERSION_2_4_OR_NEWER,
-} OpenvpnBinaryVersion;
-
typedef struct {
GPid pid;
guint watch_id;
@@ -530,15 +522,13 @@ openvpn_binary_find_exepath (void)
return NULL;
}
-static OpenvpnBinaryVersion
+static guint
openvpn_binary_detect_version (const char *exepath)
{
gs_free char *s_stdout = NULL;
- const char *s;
int exit_code;
- int n;
- g_return_val_if_fail (exepath && exepath[0] == '/', OPENVPN_BINARY_VERSION_UNKNOWN);
+ g_return_val_if_fail (exepath && exepath[0] == '/', NMOVPN_VERSION_UNKNOWN);
if (!g_spawn_sync (NULL,
(char *[]) { (char *) exepath, "--version", NULL },
@@ -550,61 +540,40 @@ openvpn_binary_detect_version (const char *exepath)
NULL,
&exit_code,
NULL))
- return OPENVPN_BINARY_VERSION_UNKNOWN;
+ return NMOVPN_VERSION_UNKNOWN;
if ( !WIFEXITED (exit_code)
|| !NM_IN_SET(WEXITSTATUS (exit_code), 0, 1)) {
/* expect return code 1 (OPENVPN_EXIT_STATUS_USAGE).
* Since 2.5.0, it returns 0. */
- return OPENVPN_BINARY_VERSION_UNKNOWN;
+ return NMOVPN_VERSION_UNKNOWN;
}
- /* the output for --version starts with title_string, which starts with PACKAGE_STRING,
- * which looks like "OpenVPN 2.#...". Do a strict parsing here... */
- if ( !s_stdout
- || !g_str_has_prefix (s_stdout, "OpenVPN 2."))
- return OPENVPN_BINARY_VERSION_UNKNOWN;
- s = &s_stdout[NM_STRLEN ("OpenVPN 2.")];
-
- if (!g_ascii_isdigit (s[0]))
- return OPENVPN_BINARY_VERSION_UNKNOWN;
-
- n = 0;
- do {
- if (n > G_MAXINT / 100)
- return OPENVPN_BINARY_VERSION_UNKNOWN;
- n = (n * 10) + (s[0] - '0');
- } while (g_ascii_isdigit ((++s)[0]));
-
- if (n <= 3)
- return OPENVPN_BINARY_VERSION_2_3_OR_OLDER;
- if (n <= 4)
- return OPENVPN_BINARY_VERSION_2_4_OR_OLDER;
-
- return OPENVPN_BINARY_VERSION_2_4_OR_NEWER;
+ return nmovpn_version_parse (s_stdout);
}
-static OpenvpnBinaryVersion
-openvpn_binary_detect_version_cached (const char *exepath, OpenvpnBinaryVersion *cached)
+static guint
+openvpn_binary_detect_version_cached (const char *exepath, guint *cached)
{
- if (G_UNLIKELY (*cached == OPENVPN_BINARY_VERSION_INVALID)) {
- const char *str;
+ guint v;
+
+ v = *cached;
+ if (G_UNLIKELY (v == NMOVPN_VERSION_INVALID)) {
+ v = openvpn_binary_detect_version (exepath);
+ if (v >= NMOVPN_VERSION_UNKNOWN) {
+ v = NMOVPN_VERSION_UNKNOWN;
+ _LOGI ("detected openvpn version UNKNOWN, assume max");
+ } else {
+ guint v_x;
+ guint v_y;
+ guint v_z;
- *cached = openvpn_binary_detect_version (exepath);
- switch (*cached) {
- case OPENVPN_BINARY_VERSION_2_3_OR_OLDER:
- str = "2.3 or older";
- break;
- case OPENVPN_BINARY_VERSION_2_4_OR_NEWER:
- str = "2.4 or newer";
- break;
- default:
- str = "unknown";
- break;
+ nmovpn_version_decode (v, &v_x, &v_y, &v_z);
+ _LOGI ("detected openvpn version %u.%u.%u", v_x, v_y, v_z);
}
- _LOGI ("detected openvpn version %s", str);
+ *cached = v;
}
- return *cached;
+ return v;
}
/*****************************************************************************/
@@ -1352,7 +1321,7 @@ nm_openvpn_start_openvpn_binary (NMOpenvpnPlugin *plugin,
NMSettingVpn *s_vpn;
const char *connection_type;
gint64 v_int64;
- OpenvpnBinaryVersion openvpn_binary_version = OPENVPN_BINARY_VERSION_INVALID;
+ guint openvpn_binary_version = NMOVPN_VERSION_INVALID;
guint num_remotes = 0;
gs_free char *cmd_log = NULL;
NMOvpnComp comp;
@@ -1547,7 +1516,7 @@ nm_openvpn_start_openvpn_binary (NMOpenvpnPlugin *plugin,
openvpn_binary_detect_version_cached (openvpn_binary, &openvpn_binary_version);
if (nmovpn_arg_is_set (allow_compression)) {
- if (openvpn_binary_version == OPENVPN_BINARY_VERSION_2_4_OR_OLDER) {
+ if (openvpn_binary_version < nmovpn_version_encode (2, 5, 0)) {
_LOGW ("\"allow-compression\" is only supported in OpenVPN 2.5 and later versions");
} else {
args_add_strv (args, "--allow-compression", allow_compression);
@@ -1559,7 +1528,7 @@ nm_openvpn_start_openvpn_binary (NMOpenvpnPlugin *plugin,
case NMOVPN_COMP_DISABLED:
break;
case NMOVPN_COMP_LZO:
- if (openvpn_binary_version == OPENVPN_BINARY_VERSION_2_3_OR_OLDER)
+ if (openvpn_binary_version < nmovpn_version_encode (2, 4, 0))
args_add_strv (args, "--comp-lzo", "yes");
else
args_add_strv (args, "--compress", "lzo");
@@ -1567,7 +1536,7 @@ nm_openvpn_start_openvpn_binary (NMOpenvpnPlugin *plugin,
case NMOVPN_COMP_LZ4:
case NMOVPN_COMP_LZ4_V2:
case NMOVPN_COMP_AUTO:
- if (openvpn_binary_version == OPENVPN_BINARY_VERSION_2_3_OR_OLDER)
+ if (openvpn_binary_version < nmovpn_version_encode (2, 4, 0))
_LOGW ("\"compress\" option supported only by OpenVPN >= 2.4");
if (comp == NMOVPN_COMP_LZ4)
@@ -1579,7 +1548,7 @@ nm_openvpn_start_openvpn_binary (NMOpenvpnPlugin *plugin,
break;
case NMOVPN_COMP_LEGACY_LZO_DISABLED:
case NMOVPN_COMP_LEGACY_LZO_ADAPTIVE:
- if (openvpn_binary_version != OPENVPN_BINARY_VERSION_2_3_OR_OLDER)
+ if (openvpn_binary_version >= nmovpn_version_encode (2, 4, 0))
_LOGW ("\"comp-lzo\" is deprecated and will be removed in future OpenVPN
releases");
args_add_strv (args, "--comp-lzo",
@@ -1767,7 +1736,7 @@ nm_openvpn_start_openvpn_binary (NMOpenvpnPlugin *plugin,
tmp = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_TLS_REMOTE);
if (nmovpn_arg_is_set (tmp)) {
- if (openvpn_binary_detect_version_cached (openvpn_binary, &openvpn_binary_version) ==
OPENVPN_BINARY_VERSION_2_3_OR_OLDER) {
+ if (openvpn_binary_detect_version_cached (openvpn_binary, &openvpn_binary_version) <
nmovpn_version_encode (2, 4, 0)) {
_LOGW ("the tls-remote option is deprecated and removed from OpenVPN 2.4. Update your
connection to use verify-x509-name (for example, \"verify-x509-name=name:%s\")", tmp);
args_add_strv (args, "--tls-remote", tmp);
} else {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]