[network-manager-openvpn] add support for IP address family specifier for remote protocol



commit 3c5c7efba75ffd121be3b0ac179c36ca9aa772b0
Author: Thomas Haller <thaller redhat com>
Date:   Fri Aug 18 12:41:13 2017 +0200

    add support for IP address family specifier for remote protocol
    
    Add support for udp4/udp6/tcp4/tcp6 and the tcp*-client specifiers.
    
    - refactor parsing of host:port:proto for --remote into a function
      nmovpn_remote_parse(). Also, search for the ':' delimiter from
      the right side. That way, one could use colons in the host, like
      using an IPv6 address "aa:bb::1::udp" (or just "aa:bb::1::").
    
    - for IPv6 addresses (which also contain ':') we make a special exception:
      if we can parse part of the remote as valid IPv6 address
      (or as valid IPv6 address with square brackets), we don't split at the
      colon. For example, "dead:beef::1:1194" is taken as IPv6 address
      without port specifier. When the user wants the entre such an address,
      he can enter "[dead:beef::1]:1194".
    
    - due to treating IPv6 addresses special, we cannot unambigiously import
      certain configurations. For example "remote a:" cannot be imported
      because both "a::" and "[a:]" would be wrong. That means, due to the
      special handling of IPv6 addresses, certain host names not be expressed.
      For example, during import we may import something different then was in the
      file. On the other hand, it only applies to configurations with hosts that
      have a colon, do not validate as an IPv6 address, but suddenly validate as IPv6
      address after appending ":" or ":PORT:". That is a known shortcoming, but
      shouldn't hurt because such DNS names seem very unlikely (they do have a dot,
      right?).
    
    - during export, also consider '\t' as delimiter for mulitple
      remotes.
    
    - during export, if port is unspecified but proto is given (a very
      unusual case), export port as "1194" instead of "443" for TCP. That
      is what server also does in case port is missing, and also is 1194
      the default port for OpenVPN.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=731620

 po/POTFILES.in                        |    1 +
 properties/import-export.c            |   60 +++++++------
 properties/nm-openvpn-editor.c        |   66 +++++---------
 properties/tests/conf/proxy-http.ovpn |    2 +-
 properties/tests/test-import-export.c |   69 ++++++++++++++-
 shared/utils.c                        |  156 +++++++++++++++++++++++++++++++++
 shared/utils.h                        |   18 ++++
 src/nm-openvpn-service.c              |   33 ++++---
 8 files changed, 320 insertions(+), 85 deletions(-)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index d15f424..133d9b4 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -8,6 +8,7 @@ properties/nm-openvpn-editor-plugin.c
 properties/nm-openvpn-editor.c
 shared/nm-utils/nm-shared-utils.c
 shared/nm-utils/nm-vpn-plugin-utils.c
+shared/utils.c
 src/nm-openvpn-service.c
 src/nm-openvpn-service-openvpn-helper.c
 [type: gettext/glade]properties/nm-openvpn-dialog.ui
diff --git a/properties/import-export.c b/properties/import-export.c
index b2f555d..5d46b50 100644
--- a/properties/import-export.c
+++ b/properties/import-export.c
@@ -1071,6 +1071,8 @@ do_import (const char *path, const char *contents, gsize contents_len, GError **
                        const char *prev;
                        GString *new_remote;
                        int port = -1;
+                       gboolean host_has_colon;
+                       struct in6_addr a;
 
                        if (!args_params_check_nargs_minmax (params, 1, 3, &line_error))
                                goto handle_line_error;
@@ -1092,8 +1094,8 @@ do_import (const char *path, const char *contents, gsize contents_len, GError **
                                port = v_int64;
 
                                if (params[3]) {
-                                       if (!NM_IN_STRSET (params[3], "udp", "tcp")) {
-                                               line_error = g_strdup_printf (_("remote expects protocol 
either udp or remote"));
+                                       if (!NM_IN_STRSET (params[3], NMOVPN_PROTCOL_TYPES)) {
+                                               line_error = g_strdup_printf (_("remote expects protocol type 
like 'udp' or 'tcp'"));
                                                goto handle_line_error;
                                        }
                                }
@@ -1106,14 +1108,25 @@ do_import (const char *path, const char *contents, gsize contents_len, GError **
                                g_string_assign (new_remote, prev);
                                g_string_append (new_remote, ", ");
                        }
-                       g_string_append (new_remote, params[1]);
+
+                       host_has_colon = (strchr (params[1], ':') != NULL);
+                       if (   host_has_colon
+                           && inet_pton (AF_INET6, params[1], &a) == 1) {
+                               /* need to escape the host. */
+                               g_string_append_printf (new_remote, "[%s]", params[1]);
+                       } else
+                               g_string_append (new_remote, params[1]);
+
                        if (params[2]) {
                                g_string_append_printf (new_remote, ":%d", port);
                                if (params[3]) {
                                        g_string_append_c (new_remote, ':');
                                        g_string_append (new_remote, params[3]);
-                               }
-                       }
+                               } else if (host_has_colon)
+                                       g_string_append_c (new_remote, ':');
+                       } else if (host_has_colon)
+                               g_string_append (new_remote, "::");
+
                        setting_vpn_add_data_item (s_vpn, NM_OPENVPN_KEY_REMOTE, new_remote->str);
                        g_string_free (new_remote, TRUE);
 
@@ -1800,32 +1813,25 @@ do_export_create (NMConnection *connection, const char *path, GError **error)
        args_write_line (f, NMV_OVPN_TAG_CLIENT);
 
        /* 'remote' */
-       gw_list = g_strsplit_set (gateways, " ,", 0);
+       gw_list = g_strsplit_set (gateways, " \t,", 0);
        for (gw_iter = gw_list; gw_iter && *gw_iter; gw_iter++) {
-               char *tmp_host, *tmp_port,*tmp_proto;
-
-               if (**gw_iter == '\0')
+               gs_free char *str_free = NULL;
+               const char *host, *port, *proto;
+               gssize eidx;
+
+               eidx = nmovpn_remote_parse (*gw_iter,
+                                           &str_free,
+                                           &host,
+                                           &port,
+                                           &proto,
+                                           NULL);
+               if (eidx >= 0)
                        continue;
-               tmp_host = g_strstrip (*gw_iter);
-               tmp_port = strchr (tmp_host, ':');
-               tmp_proto = tmp_port ? strchr (tmp_port + 1, ':') : NULL;
-               if (tmp_port)
-                       *tmp_port++ = '\0';
-               if (tmp_proto)
-                       *tmp_proto++ = '\0';
-               if (tmp_port && !*tmp_port)
-                       tmp_port = NULL;
-               if (tmp_proto && !*tmp_proto)
-                       tmp_proto = NULL;
-
                args_write_line (f,
                                 NMV_OVPN_TAG_REMOTE,
-                                *gw_iter,
-                                tmp_port
-                                    ?: (tmp_proto
-                                            ? (nm_streq (tmp_proto, "udp") ? "1194" : "443")
-                                            : NULL),
-                                tmp_proto);
+                                host,
+                                port ?: (proto ? "1194" : NULL),
+                                proto);
        }
        g_strfreev (gw_list);
 
diff --git a/properties/nm-openvpn-editor.c b/properties/nm-openvpn-editor.c
index 16858d0..81dcdfa 100644
--- a/properties/nm-openvpn-editor.c
+++ b/properties/nm-openvpn-editor.c
@@ -37,6 +37,7 @@
 #include <gtk/gtk.h>
 
 #include "auth-helpers.h"
+#include "utils.h"
 
 /*****************************************************************************/
 
@@ -64,48 +65,30 @@ typedef struct {
 #define COL_AUTH_PAGE 1
 #define COL_AUTH_TYPE 2
 
-/* Example: abc.com:1234:udp, ovpnserver.company.com:443, vpn.example.com::tcp */
 static gboolean
 check_gateway_entry (const char *str)
 {
-       char **list, **iter;
-       char *host, *port, *proto;
-       long int port_int;
+       gs_free char *str_clone = NULL;
+       char *str_iter;
+       const char *tok;
        gboolean success = FALSE;
 
-       if (!str || !*str)
+       if (!str || !str[0])
                return FALSE;
 
-       list = g_strsplit_set (str, " \t,", -1);
-       for (iter = list; iter && *iter; iter++) {
-               if (!**iter)
-                       continue;
-               host = g_strstrip (*iter);
-               port = strchr (host, ':');
-               proto = port ? strchr (port + 1, ':') : NULL;
-               if (port)
-                       *port++ = '\0';
-               if (proto)
-                       *proto++ = '\0';
-
-               /* check hostname */
-               if (!*host)
-                       goto out;
-               /* check port */
-               if (port && *port) {
-                       char *end;
-                       errno = 0;
-                       port_int = strtol (port, &end, 10);
-                       if (errno != 0 || *end != '\0' || port_int < 1 || port_int > 65535)
-                               goto out;
-               }
-               /* check proto */
-               if (proto && strcmp (proto, "udp") && strcmp (proto, "tcp"))
-                       goto out;
+       str_clone = g_strdup (str);
+       str_iter = str_clone;
+       while ((tok = strsep (&str_iter, " \t,"))) {
+               if (   tok[0]
+                   && (nmovpn_remote_parse (tok,
+                                            NULL,
+                                            NULL,
+                                            NULL,
+                                            NULL,
+                                            NULL) != -1))
+                  return FALSE;
+               success = TRUE;
        }
-       success = TRUE;
-out:
-       g_strfreev (list);
        return success;
 }
 
@@ -118,16 +101,13 @@ check_validity (OpenvpnEditor *self, GError **error)
        GtkTreeModel *model;
        GtkTreeIter iter;
        const char *contype = NULL;
-       gboolean gateway_valid;
        gboolean success;
 
        widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "gateway_entry"));
        str = gtk_entry_get_text (GTK_ENTRY (widget));
-       gateway_valid = check_gateway_entry (str);
-       /* Change entry background colour while editing */
-       if (gateway_valid) {
+       if (str && check_gateway_entry (str))
                gtk_style_context_remove_class (gtk_widget_get_style_context (widget), "error");
-       } else {
+       else {
                gtk_style_context_add_class (gtk_widget_get_style_context (widget), "error");
                g_set_error (error,
                             NMV_EDITOR_PLUGIN_ERROR,
@@ -401,7 +381,8 @@ update_connection (NMVpnEditor *iface,
        OpenvpnEditorPrivate *priv = OPENVPN_EDITOR_GET_PRIVATE (self);
        NMSettingVpn *s_vpn;
        GtkWidget *widget;
-       char *str, *auth_type;
+       char *auth_type;
+       const char *str;
        gboolean valid = FALSE;
 
        if (!check_validity (self, error))
@@ -410,10 +391,9 @@ update_connection (NMVpnEditor *iface,
        s_vpn = NM_SETTING_VPN (nm_setting_vpn_new ());
        g_object_set (s_vpn, NM_SETTING_VPN_SERVICE_TYPE, NM_VPN_SERVICE_TYPE_OPENVPN, NULL);
 
-       /* Gateway */
        widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "gateway_entry"));
-       str = (char *) gtk_entry_get_text (GTK_ENTRY (widget));
-       if (str && strlen (str))
+       str = gtk_entry_get_text (GTK_ENTRY (widget));
+       if (str && str[0])
                nm_setting_vpn_add_data_item (s_vpn, NM_OPENVPN_KEY_REMOTE, str);
 
        auth_type = get_auth_type (priv->builder);
diff --git a/properties/tests/conf/proxy-http.ovpn b/properties/tests/conf/proxy-http.ovpn
index b96c88f..efaa3f1 100644
--- a/properties/tests/conf/proxy-http.ovpn
+++ b/properties/tests/conf/proxy-http.ovpn
@@ -5,7 +5,7 @@ proto tcp
 topology subnet
 
 rport 2352
-remote test.server.com 443
+remote aa:bb::1 1194 udp
 nobind
 persist-key
 persist-tun
diff --git a/properties/tests/test-import-export.c b/properties/tests/test-import-export.c
index e9d4496..64025ac 100644
--- a/properties/tests/test-import-export.c
+++ b/properties/tests/test-import-export.c
@@ -43,6 +43,71 @@
 
 /*****************************************************************************/
 
+static void
+_test_nmovpn_remote_parse (const char *str,
+                           const char *exp_host,
+                           const char *exp_port,
+                           const char *exp_proto)
+{
+       gs_free char *str_free = NULL;
+       gssize r;
+       const char *host, *port, *proto;
+       gs_free_error GError *error = NULL;
+
+       g_assert (exp_host || (!exp_port && !exp_proto));
+
+       r = nmovpn_remote_parse (str, &str_free, &host, &port, &proto, &error);
+       if (!exp_host) {
+               g_assert (r >= 0);
+               g_assert (error);
+               return;
+       }
+       nmtst_assert_success (r == -1, error);
+
+       g_assert_cmpstr (exp_host, ==, host);
+       g_assert_cmpstr (exp_port, ==, port);
+       g_assert_cmpstr (exp_proto, ==, proto);
+}
+
+static void
+test_nmovpn_remote_parse (void)
+{
+       _test_nmovpn_remote_parse ("a",                          "a",                      NULL,    NULL);
+       _test_nmovpn_remote_parse ("a:",                         "a",                      NULL,    NULL);
+       _test_nmovpn_remote_parse ("t::",                        "t",                      NULL,    NULL);
+       _test_nmovpn_remote_parse ("a::",                        "a::",                    NULL,    NULL);
+       _test_nmovpn_remote_parse ("[a::]:",                     "a::",                    NULL,    NULL);
+       _test_nmovpn_remote_parse ("t:::",                       "t:",                     NULL,    NULL);
+       _test_nmovpn_remote_parse ("a:::",                       "a::",                    NULL,    NULL);
+       _test_nmovpn_remote_parse ("a:t::",                      "a:t",                    NULL,    NULL);
+       _test_nmovpn_remote_parse ("a:b::",                      "a:b::",                  NULL,    NULL);
+       _test_nmovpn_remote_parse ("a::udp",                     "a",                      NULL,    "udp");
+       _test_nmovpn_remote_parse ("a:1:",                       "a",                      "1",     NULL);
+       _test_nmovpn_remote_parse ("t::1:",                      "t:",                     "1",     NULL);
+       _test_nmovpn_remote_parse ("t::1:",                      "t:",                     "1",     NULL);
+       _test_nmovpn_remote_parse ("[a:]:1:",                    "[a:]",                   "1",     NULL);
+       _test_nmovpn_remote_parse ("a::1:",                      "a::1",                   NULL,    NULL);
+       _test_nmovpn_remote_parse ("a::1:1194",                  "a::1:1194",              NULL,    NULL);
+       _test_nmovpn_remote_parse ("[a::1]:1194",                "a::1",                   "1194",  NULL);
+       _test_nmovpn_remote_parse ("a::1194",                    "a::1194",                NULL,    NULL);
+       _test_nmovpn_remote_parse ("a::1194:",                   "a::1194",                NULL,    NULL);
+       _test_nmovpn_remote_parse ("[a:]:1194:",                 "[a:]",                   "1194",  NULL);
+       _test_nmovpn_remote_parse ("a:1:tcp",                    "a",                      "1",     "tcp");
+       _test_nmovpn_remote_parse ("aa:bb::1:1194:udp",          NULL,                     NULL,    NULL);
+       _test_nmovpn_remote_parse ("[aa:bb::1]:1194:udp",        "aa:bb::1",               "1194",  "udp");
+       _test_nmovpn_remote_parse ("[aa:bb::1]::udp",            "aa:bb::1",               NULL,    "udp");
+       _test_nmovpn_remote_parse ("aa:bb::1::udp",              "aa:bb::1",               NULL,    "udp");
+       _test_nmovpn_remote_parse ("aa:bb::1::",                 "aa:bb::1",               NULL,    NULL);
+       _test_nmovpn_remote_parse ("abc.com:1234:udp",           "abc.com",                "1234",  "udp");
+       _test_nmovpn_remote_parse ("ovpnserver.company.com:443", "ovpnserver.company.com", "443",   NULL);
+       _test_nmovpn_remote_parse ("vpn.example.com::tcp",       "vpn.example.com",        NULL,    "tcp");
+       _test_nmovpn_remote_parse ("dead:beef::1:1194",          "dead:beef::1:1194",      NULL,    NULL);
+       _test_nmovpn_remote_parse ("dead:beef::1:1194",          "dead:beef::1:1194",      NULL,    NULL);
+       _test_nmovpn_remote_parse ("2001:dead:beef::1194::",     "2001:dead:beef::1194",   NULL,    NULL);
+}
+
+/*****************************************************************************/
+
 static NMVpnEditorPlugin *
 _create_plugin (void)
 {
@@ -678,7 +743,7 @@ test_proxy_http_import (void)
        _check_item (s_vpn, NM_OPENVPN_KEY_COMP_LZO, NULL);
        _check_item (s_vpn, NM_OPENVPN_KEY_FLOAT, NULL);
        _check_item (s_vpn, NM_OPENVPN_KEY_RENEG_SECONDS, "0");
-       _check_item (s_vpn, NM_OPENVPN_KEY_REMOTE, "test.server.com:443");
+       _check_item (s_vpn, NM_OPENVPN_KEY_REMOTE, "[aa:bb::1]:1194:udp");
        _check_item (s_vpn, NM_OPENVPN_KEY_PORT, "2352");
        _check_item (s_vpn, NM_OPENVPN_KEY_CERT, NULL);
        _check_item (s_vpn, NM_OPENVPN_KEY_KEY, NULL);
@@ -1096,6 +1161,8 @@ int main (int argc, char **argv)
 #define _add_test_func_simple(func)       g_test_add_func ("/ovpn/properties/" #func, func)
 #define _add_test_func(detail, func, ...) nmtst_add_test_func ("/ovpn/properties/" detail, func, 
##__VA_ARGS__)
 
+       _add_test_func_simple (test_nmovpn_remote_parse);
+
        _add_test_func_simple (test_password_import);
        _add_test_func ("password-export", test_export_compare, "password.conf", "password.ovpntest");
 
diff --git a/shared/utils.c b/shared/utils.c
index 5565d4d..aa2565e 100644
--- a/shared/utils.c
+++ b/shared/utils.c
@@ -25,6 +25,9 @@
 
 #include <string.h>
 #include <errno.h>
+#include <arpa/inet.h>
+
+#include "nm-utils/nm-shared-utils.h"
 
 gboolean
 is_pkcs12 (const char *filepath)
@@ -91,4 +94,157 @@ is_encrypted (const char *filename)
        return encrypted;
 }
 
+static gboolean
+_is_inet6_addr (const char *str, gboolean with_square_brackets)
+{
+       struct in6_addr a;
+       gsize l;
+
+       if (   with_square_brackets
+           && str[0] == '[') {
+               l = strlen (str);
+               if (str[l - 1] == ']') {
+                       gs_free char *s = g_strndup (&str[1], l - 2);
+
+                       return inet_pton (AF_INET6, s, &a) == 1;
+               }
+       }
+       return inet_pton (AF_INET6, str, &a) == 1;
+}
+
+/**
+ * nmovpn_remote_parse:
+ * @str: the input string to be split. It is modified inplace.
+ * @out_buf: an allocated string, to which the other arguments
+ *   point to. Must be freeded by caller.
+ * @out_host: pointer to the host out argument.
+ * @out_port: pointer to the port out argument.
+ * @out_proto: pointer to the proto out argument.
+ * @error:
+ *
+ * Splits @str in three parts host, port and proto.
+ *
+ * Returns: -1 on success or index in @str of first invalid character.
+ *  Note that the error index can be at strlen(str), if some data is missing.
+ **/
+gssize
+nmovpn_remote_parse (const char *str,
+                     char **out_buf,
+                     const char **out_host,
+                     const char **out_port,
+                     const char **out_proto,
+                     GError **error)
+{
+       gs_free char *str_copy = NULL;
+       char *t;
+       char *host = NULL;
+       char *port = NULL;
+       char *proto = NULL;
+       gssize idx_fail;
+
+       g_return_val_if_fail (str, 0);
+       if (!out_buf) {
+               /* one can omit @out_buf only if also no other out-arguments
+                * are requested. */
+               if (out_host || out_port || out_proto)
+                       g_return_val_if_reached (0);
+       }
+       g_return_val_if_fail (!error || !*error, 0);
+
+       t = strchr (str, ' ');
+       if (!t)
+               t = strchr (str, ',');
+       if (t) {
+               g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
+                            _("invalid delimiter character '%c'"), t[0]);
+               idx_fail = t - str;
+               goto out_fail;
+       }
+
+       if (!g_utf8_validate (str, -1, (const char **) &t)) {
+               g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
+                            _("invalid non-utf-8 character"));
+               idx_fail = t - str;
+               goto out_fail;
+       }
+
+       str_copy = g_strdup (str);
+
+       /* we already checked that there is no space above.
+        * Strip tabs nonetheless. */
+       host = nm_str_skip_leading_spaces (str_copy);
+       g_strchomp (host);
+
+       t = strrchr (host, ':');
+       if (   t
+           && !_is_inet6_addr (host, TRUE)) {
+               t[0] = '\0';
+               port = &t[1];
+               t = strrchr (host, ':');
+               if (   t
+                   && !_is_inet6_addr (host, TRUE)) {
+                       t[0] = '\0';
+                       proto = port;
+                       port = &t[1];
+               }
+       }
+
+       if (!host[0]) {
+               g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
+                            _("empty host"));
+               idx_fail = host - str;
+               goto out_fail;
+       }
+       if (port) {
+               if (!port[0]) {
+                       /* allow empty port like "host::udp". */
+                       port = NULL;
+               } else if (_nm_utils_ascii_str_to_int64 (port, 10, 1, 0xFFFF, 0) == 0) {
+                       g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
+                                    _("invalid port"));
+                       idx_fail = port - str;
+                       goto out_fail;
+               }
+       }
+       if (proto) {
+               if (!proto[0]) {
+                       /* allow empty proto, so that host can contain ':'. */
+                       proto = NULL;
+               } else if (!NM_IN_STRSET (proto, NMOVPN_PROTCOL_TYPES)) {
+                       g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
+                                    _("invalid protocol"));
+                       idx_fail = proto - str;
+                       goto out_fail;
+               }
+       }
+
+       if (out_buf) {
+               *out_buf = g_steal_pointer (&str_copy);
+               if (   host[0] == '['
+                   && _is_inet6_addr (host, TRUE)
+                   && !_is_inet6_addr (host, FALSE)) {
+                       gsize l;
+
+                       host++;
+                       l = strlen (host);
+                       nm_assert (l > 0 && host[l - 1] == ']');
+                       host[l - 1] = '\0';
+                       nm_assert (_is_inet6_addr (host, FALSE));
+               }
+               NM_SET_OUT (out_host, host);
+               NM_SET_OUT (out_port, port);
+               NM_SET_OUT (out_proto, proto);
+       }
+       return -1;
+
+out_fail:
+       if (out_buf) {
+               *out_buf = NULL;
+               NM_SET_OUT (out_host, NULL);
+               NM_SET_OUT (out_port, NULL);
+               NM_SET_OUT (out_proto, NULL);
+       }
+       return idx_fail;
+}
+
 /*****************************************************************************/
diff --git a/shared/utils.h b/shared/utils.h
index ed4ae98..353ddef 100644
--- a/shared/utils.h
+++ b/shared/utils.h
@@ -80,4 +80,22 @@ gboolean is_pkcs12 (const char *filepath);
 
 gboolean is_encrypted (const char *filename);
 
+#define NMOVPN_PROTCOL_TYPES \
+       "udp", \
+       "udp4", \
+       "udp6", \
+       "tcp", \
+       "tcp4", \
+       "tcp6", \
+       "tcp-client", \
+       "tcp4-client", \
+       "tcp6-client"
+
+gssize nmovpn_remote_parse (const char *str,
+                            char **out_buf,
+                            const char **out_host,
+                            const char **out_port,
+                            const char **out_proto,
+                            GError **error);
+
 #endif  /* UTILS_H */
diff --git a/src/nm-openvpn-service.c b/src/nm-openvpn-service.c
index 659ac2f..923517f 100644
--- a/src/nm-openvpn-service.c
+++ b/src/nm-openvpn-service.c
@@ -1330,22 +1330,25 @@ nm_openvpn_start_openvpn_binary (NMOpenvpnPlugin *plugin,
        if (tmp && *tmp) {
                gs_free char *tmp_clone = NULL;
                char *tmp_remaining;
-               char *tok, *port, *proto;
+               const char *tok;
 
                tmp_remaining = tmp_clone = g_strdup (tmp);
                while ((tok = strsep (&tmp_remaining, " \t,")) != NULL) {
-                       if (!*tok)
+                       gs_free char *str_free = NULL;
+                       const char *host, *port, *proto;
+                       gssize eidx;
+
+                       eidx = nmovpn_remote_parse (tok,
+                                                   &str_free,
+                                                   &host,
+                                                   &port,
+                                                   &proto,
+                                                   NULL);
+                       if (eidx >= 0)
                                continue;
 
-                       port = strchr (tok, ':');
-                       proto = port ? strchr (port + 1, ':') : NULL;
-                       if (port)
-                               *port++ = '\0';
-                       if (proto)
-                               *proto++ = '\0';
-
                        add_openvpn_arg (args, "--remote");
-                       add_openvpn_arg (args, tok);
+                       add_openvpn_arg (args, host);
                        if (port) {
                                if (!add_openvpn_arg_int (args, port)) {
                                        g_set_error (error,
@@ -1367,10 +1370,14 @@ nm_openvpn_start_openvpn_binary (NMOpenvpnPlugin *plugin,
                                add_openvpn_arg (args, "1194"); /* default IANA port */
 
                        if (proto) {
-                               if (!strcmp (proto, "udp"))
-                                       add_openvpn_arg (args, proto);
-                               else if (!strcmp (proto, "tcp"))
+                               if (nm_streq (proto, "tcp"))
                                        add_openvpn_arg (args, "tcp-client");
+                               else if (nm_streq (proto, "tcp4"))
+                                       add_openvpn_arg (args, "tcp4-client");
+                               else if (nm_streq (proto, "tcp6"))
+                                       add_openvpn_arg (args, "tcp6-client");
+                               else if (NM_IN_STRSET (proto, NMOVPN_PROTCOL_TYPES))
+                                       add_openvpn_arg (args, proto);
                                else {
                                        g_set_error (error,
                                                     NM_VPN_PLUGIN_ERROR,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]