[network-manager-openvpn/jk/import-route-rh753578] import/export: import and export "route" option (bgo #753578)



commit fc68fe76d4f9d00f7aec8a57d7a9aa602cb625cd
Author: Jiří Klimeš <jklimes redhat com>
Date:   Wed Nov 18 17:18:17 2015 +0100

    import/export: import and export "route" option (bgo #753578)
    
    We do not allow openvpn to configure routes (--routes-noexec), but let's
    configure these routes in ipv4 setting.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=753578

 properties/import-export.c            |   99 +++++++++++++++++++++
 properties/tests/conf/Makefile.am     |    3 +-
 properties/tests/conf/route.ovpn      |   26 ++++++
 properties/tests/test-import-export.c |  152 +++++++++++++++++++++++++++-----
 4 files changed, 255 insertions(+), 25 deletions(-)
---
diff --git a/properties/import-export.c b/properties/import-export.c
index 451f475..78624a1 100644
--- a/properties/import-export.c
+++ b/properties/import-export.c
@@ -38,6 +38,7 @@
 #include <nm-setting-vpn.h>
 #include <nm-setting-connection.h>
 #include <nm-setting-ip4-config.h>
+#include <nm-utils.h>
 
 #include "import-export.h"
 #include "nm-openvpn.h"
@@ -80,6 +81,7 @@
 #define TLS_REMOTE_TAG "tls-remote "
 #define REMOTE_CERT_TLS_TAG "remote-cert-tls "
 #define TUNMTU_TAG "tun-mtu "
+#define ROUTE_TAG "route "
 
 
 static char *
@@ -363,11 +365,26 @@ parse_http_proxy_auth (const char *path,
        return *out_user && *out_pass;
 }
 
+static gboolean
+parse_ip (const char *str, const char *line, guint32 *out_ip)
+{
+       struct in_addr ip;
+
+       if (inet_pton (AF_INET, str, &ip) <= 0) {
+               g_warning ("%s: invalid IP '%s' in option '%s'", __func__, str, line);
+               return FALSE;
+       }
+       if (out_ip)
+               *out_ip = ip.s_addr;
+       return TRUE;
+}
+
 NMConnection *
 do_import (const char *path, char **lines, GError **error)
 {
        NMConnection *connection = NULL;
        NMSettingConnection *s_con;
+       NMSettingIP4Config *s_ip4;
        NMSettingVPN *s_vpn;
        char *last_dot;
        char **line;
@@ -382,6 +399,8 @@ do_import (const char *path, char **lines, GError **error)
        connection = nm_connection_new ();
        s_con = NM_SETTING_CONNECTION (nm_setting_connection_new ());
        nm_connection_add_setting (connection, NM_SETTING (s_con));
+       s_ip4 = NM_SETTING_IP4_CONFIG (nm_setting_ip4_config_new ());
+       nm_connection_add_setting (connection, NM_SETTING (s_ip4));
 
        s_vpn = NM_SETTING_VPN (nm_setting_vpn_new ());
 
@@ -784,6 +803,56 @@ do_import (const char *path, char **lines, GError **error)
                        g_strfreev (items);
                        continue;
                }
+
+               if (!strncmp (*line, ROUTE_TAG, strlen (ROUTE_TAG))) {
+                       items = get_args (*line + strlen (ROUTE_TAG), &nitems);
+                       if (nitems >= 1 && nitems <= 4) {
+                               guint32 dest, next_hop, prefix, metric;
+                               NMIP4Route *route;
+
+                               if (!parse_ip (items[0], *line, &dest))
+                                       goto route_fail;
+
+                               /* init default values */
+                               next_hop = 0;
+                               prefix = 32;
+                               metric = 0;
+                               if (nitems >= 2) {
+                                       if (!parse_ip (items[1], *line, &prefix))
+                                               goto route_fail;
+                                       prefix = nm_utils_ip4_netmask_to_prefix (prefix);
+                                       if (nitems >= 3) {
+                                               if (!parse_ip (items[2], *line, &next_hop))
+                                                       goto route_fail;
+                                               if (nitems == 4) {
+                                                       long num;
+                                                       errno = 0;
+                                                       num = strtol (items[3], NULL, 10);
+                                                       if ((errno == 0) && (num >= 0) && (num <= 65535))
+                                                               metric = (guint32) num;
+                                                       else {
+                                                               g_warning ("%s: invalid metric '%s' in option 
'%s'",
+                                                                          __func__, items[3], *line);
+                                                               goto route_fail;
+                                                       }
+                                               }
+                                       }
+                               }
+
+                               route = nm_ip4_route_new ();
+                               nm_ip4_route_set_dest (route, dest);
+                               nm_ip4_route_set_prefix (route, prefix);
+                               nm_ip4_route_set_next_hop (route, next_hop);
+                               nm_ip4_route_set_metric (route, metric);
+                               nm_setting_ip4_config_add_route (s_ip4, route);
+                               nm_ip4_route_unref (route);
+                       } else
+                               g_warning ("%s: invalid number of arguments in option '%s'", __func__, *line);
+
+route_fail:
+                       g_strfreev (items);
+                       continue;
+               }
        }
 
        if (!have_client && !have_sk) {
@@ -865,6 +934,7 @@ gboolean
 do_export (const char *path, NMConnection *connection, GError **error)
 {
        NMSettingConnection *s_con;
+       NMSettingIP4Config *s_ip4;
        NMSettingVPN *s_vpn;
        FILE *f;
        const char *value;
@@ -900,6 +970,7 @@ do_export (const char *path, NMConnection *connection, GError **error)
        const char *proxy_retry = NULL;
        const char *proxy_username = NULL;
        const char *proxy_password = NULL;
+       int i;
 
        s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
        g_assert (s_con);
@@ -1160,6 +1231,34 @@ do_export (const char *path, NMConnection *connection, GError **error)
                }
        }
 
+       /* Static routes */
+       s_ip4 = nm_connection_get_setting_ip4_config (connection);
+       for (i = 0; s_ip4 && i < nm_setting_ip4_config_get_num_routes (s_ip4); i++) {
+               char dest_str[INET_ADDRSTRLEN];
+               char netmask_str[INET_ADDRSTRLEN];
+               char next_hop_str[INET_ADDRSTRLEN];
+               guint32 dest, netmask, next_hop;
+               NMIP4Route *route = nm_setting_ip4_config_get_route (s_ip4, i);
+
+               dest = nm_ip4_route_get_dest (route);
+               memset (dest_str, '\0', sizeof (dest_str));
+               inet_ntop (AF_INET, (const void *) &dest, dest_str, sizeof (dest_str));
+
+               memset (netmask_str, '\0', sizeof (netmask_str));
+               netmask = nm_utils_ip4_prefix_to_netmask (nm_ip4_route_get_prefix (route));
+               inet_ntop (AF_INET, (const void *) &netmask, netmask_str, sizeof (netmask_str));
+
+               next_hop = nm_ip4_route_get_next_hop (route);
+               memset (next_hop_str, '\0', sizeof (next_hop_str));
+               inet_ntop (AF_INET, (const void *) &next_hop, next_hop_str, sizeof (next_hop_str));
+
+               fprintf (f, "route %s %s %s %u\n",
+                        dest_str,
+                        netmask_str,
+                        next_hop_str,
+                        nm_ip4_route_get_metric (route));
+       }
+
        /* Add hard-coded stuff */
        fprintf (f,
                 "nobind\n"
diff --git a/properties/tests/conf/Makefile.am b/properties/tests/conf/Makefile.am
index 7d1858a..4a56558 100644
--- a/properties/tests/conf/Makefile.am
+++ b/properties/tests/conf/Makefile.am
@@ -14,5 +14,6 @@ EXTRA_DIST = \
        proxy-http-with-auth.ovpn \
        keysize.ovpn \
        device.ovpn \
-       device-notype.ovpn
+       device-notype.ovpn \
+       route.ovpn
 
diff --git a/properties/tests/conf/route.ovpn b/properties/tests/conf/route.ovpn
new file mode 100644
index 0000000..4c09c3d
--- /dev/null
+++ b/properties/tests/conf/route.ovpn
@@ -0,0 +1,26 @@
+route 1.2.3.0 255.255.255.0 1.2.3.254 99
+route 5.6.7.8 255.255.255.252
+route 192.168.0.0 255.255.0.0 192.168.44.1
+
+remote 173.8.149.245
+resolv-retry infinite
+
+dev tun
+persist-key
+persist-tun
+link-mtu 1400
+proto udp
+nobind
+pull
+tls-client
+
+ca keys/mg8.ca
+cert keys/clee.crt
+key keys/clee.key
+
+tls-auth keys/46.key 1
+tls-remote "/CN=myvpn.company.com"
+
+comp-lzo
+verb 3
+
diff --git a/properties/tests/test-import-export.c b/properties/tests/test-import-export.c
index 4ab8b1e..d3bc519 100644
--- a/properties/tests/test-import-export.c
+++ b/properties/tests/test-import-export.c
@@ -110,7 +110,6 @@ test_password_import (NMVpnPluginUiInterface *plugin, const char *dir)
 {
        NMConnection *connection;
        NMSettingConnection *s_con;
-       NMSettingIP4Config *s_ip4;
        NMSettingVPN *s_vpn;
        const char *expected_id = "password";
        char *expected_cacert;
@@ -129,11 +128,6 @@ test_password_import (NMVpnPluginUiInterface *plugin, const char *dir)
        ASSERT (nm_setting_connection_get_uuid (s_con) == NULL,
                "password-import", "unexpected valid UUID");
 
-       /* IP4 setting */
-       s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG);
-       ASSERT (s_ip4 == NULL,
-               "password-import", "unexpected 'ip4-config' setting");
-
        /* VPN setting */
        s_vpn = (NMSettingVPN *) nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN);
        ASSERT (s_vpn != NULL,
@@ -240,7 +234,6 @@ test_tls_import (NMVpnPluginUiInterface *plugin, const char *dir)
 {
        NMConnection *connection;
        NMSettingConnection *s_con;
-       NMSettingIP4Config *s_ip4;
        NMSettingVPN *s_vpn;
        const char *expected_id = "tls";
        char *expected_path;
@@ -259,11 +252,6 @@ test_tls_import (NMVpnPluginUiInterface *plugin, const char *dir)
        ASSERT (nm_setting_connection_get_uuid (s_con) == NULL,
                "tls-import", "unexpected valid UUID");
 
-       /* IP4 setting */
-       s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG);
-       ASSERT (s_ip4 == NULL,
-               "tls-import", "unexpected 'ip4-config' setting");
-
        /* VPN setting */
        s_vpn = (NMSettingVPN *) nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN);
        ASSERT (s_vpn != NULL,
@@ -355,7 +343,6 @@ test_pkcs12_import (NMVpnPluginUiInterface *plugin, const char *dir)
 {
        NMConnection *connection;
        NMSettingConnection *s_con;
-       NMSettingIP4Config *s_ip4;
        NMSettingVPN *s_vpn;
        const char *expected_id = "pkcs12";
        char *expected_path;
@@ -374,11 +361,6 @@ test_pkcs12_import (NMVpnPluginUiInterface *plugin, const char *dir)
        ASSERT (nm_setting_connection_get_uuid (s_con) == NULL,
                "pkcs12-import", "unexpected valid UUID");
 
-       /* IP4 setting */
-       s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG);
-       ASSERT (s_ip4 == NULL,
-               "pkcs12-import", "unexpected 'ip4-config' setting");
-
        /* VPN setting */
        s_vpn = (NMSettingVPN *) nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN);
        ASSERT (s_vpn != NULL,
@@ -504,7 +486,6 @@ test_static_key_import (NMVpnPluginUiInterface *plugin, const char *dir)
 {
        NMConnection *connection;
        NMSettingConnection *s_con;
-       NMSettingIP4Config *s_ip4;
        NMSettingVPN *s_vpn;
        const char *expected_id = "static";
        char *expected_path;
@@ -523,11 +504,6 @@ test_static_key_import (NMVpnPluginUiInterface *plugin, const char *dir)
        ASSERT (nm_setting_connection_get_uuid (s_con) == NULL,
                "static-key-import", "unexpected valid UUID");
 
-       /* IP4 setting */
-       s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG);
-       ASSERT (s_ip4 == NULL,
-               "static-key-import", "unexpected 'ip4-config' setting");
-
        /* VPN setting */
        s_vpn = (NMSettingVPN *) nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN);
        ASSERT (s_vpn != NULL,
@@ -1074,6 +1050,131 @@ test_device_export (NMVpnPluginUiInterface *plugin,
        g_free (path);
 }
 
+static void
+test_route_import (NMVpnPluginUiInterface *plugin,
+                   const char *detail,
+                   const char *dir)
+{
+       NMConnection *connection;
+       NMSettingConnection *s_con;
+       NMSettingIP4Config *s_ip4;
+       NMSettingVPN *s_vpn;
+       int num_routes;
+       NMIP4Route *route;
+       guint32 expected_dest1 =   0x00030201;
+       guint32 expected_prefix1 = 0x00000018;
+       guint32 expected_nh1 =     0xFE030201;
+       guint32 expected_metric1 = 0x00000063;
+       guint32 expected_dest2 =   0x08070605;
+       guint32 expected_prefix2 = 0x0000001E;
+       guint32 expected_nh2 =     0x00000000;
+       guint32 expected_metric2 = 0x00000000;
+       guint32 expected_dest3 =   0x0000A8C0;
+       guint32 expected_prefix3 = 0x00000010;
+       guint32 expected_nh3 =     0x012CA8C0;
+       guint32 expected_metric3 = 0x00000000;
+
+       connection = get_basic_connection (detail, plugin, dir, "route.ovpn");
+       ASSERT (connection != NULL, detail, "failed to import connection");
+
+       /* Connection setting */
+       s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
+       ASSERT (s_con != NULL,
+               detail, "missing 'connection' setting");
+
+       /* VPN setting */
+       s_vpn = (NMSettingVPN *) nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN);
+       ASSERT (s_vpn != NULL,
+               detail, "missing 'vpn' setting");
+
+       /* Data items */
+       test_item (detail, s_vpn, NM_OPENVPN_KEY_CONNECTION_TYPE, NM_OPENVPN_CONTYPE_TLS);
+
+       /* IP4 setting */
+       s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG);
+       ASSERT (s_ip4 != NULL,
+               detail, "missing 'ip4-config' setting");
+       num_routes = nm_setting_ip4_config_get_num_routes (s_ip4);
+       ASSERT (num_routes == 3, detail, "incorrect number of static routes");
+       /* route 1 */
+       route = nm_setting_ip4_config_get_route (s_ip4, 0);
+       ASSERT (nm_ip4_route_get_dest (route) == expected_dest1,
+               detail, "unexpected dest of 1. route");
+       ASSERT (nm_ip4_route_get_prefix (route) == expected_prefix1,
+               detail, "unexpected prefix of 1. route");
+       ASSERT (nm_ip4_route_get_next_hop (route) == expected_nh1,
+               detail, "unexpected next_hop of 1. route");
+       ASSERT (nm_ip4_route_get_metric (route) == expected_metric1,
+               detail, "unexpected metric of 1. route");
+
+       /* route 2 */
+       route = nm_setting_ip4_config_get_route (s_ip4, 1);
+       ASSERT (nm_ip4_route_get_dest (route) == expected_dest2,
+               detail, "unexpected dest of 2. route");
+       ASSERT (nm_ip4_route_get_prefix (route) == expected_prefix2,
+               detail, "unexpected prefix of 2. route");
+       ASSERT (nm_ip4_route_get_next_hop (route) == expected_nh2,
+               detail, "unexpected next_hop of 2. route");
+       ASSERT (nm_ip4_route_get_metric (route) == expected_metric2,
+               detail, "unexpected metric of 2. route");
+
+       /* route 3 */
+       route = nm_setting_ip4_config_get_route (s_ip4, 2);
+       ASSERT (nm_ip4_route_get_dest (route) == expected_dest3,
+               detail, "unexpected dest of 3. route");
+       ASSERT (nm_ip4_route_get_prefix (route) == expected_prefix3,
+               detail, "unexpected prefix of 3. route");
+       ASSERT (nm_ip4_route_get_next_hop (route) == expected_nh3,
+               detail, "unexpected next_hop of 3. route");
+       ASSERT (nm_ip4_route_get_metric (route) == expected_metric3,
+               detail, "unexpected metric of 3. route");
+
+       g_object_unref (connection);
+}
+
+#define ROUTE_EXPORTED_NAME "route.ovpntest"
+static void
+test_route_export (NMVpnPluginUiInterface *plugin,
+                   const char *detail,
+                   const char *dir,
+                   const char *tmpdir)
+{
+       NMConnection *connection;
+       NMConnection *reimported;
+       char *path;
+       gboolean success;
+       GError *error = NULL;
+
+       connection = get_basic_connection (detail, plugin, dir, "route.ovpn");
+       ASSERT (connection != NULL, detail, "failed to import connection");
+
+       path = g_build_path ("/", tmpdir, ROUTE_EXPORTED_NAME, NULL);
+       success = nm_vpn_plugin_ui_interface_export (plugin, path, connection, &error);
+       if (!success) {
+               if (!error)
+                       FAIL (detail, "export failed with missing error");
+               else
+                       FAIL (detail, "export failed: %s", error->message);
+       }
+
+       /* Now re-import it and compare the connections to ensure they are the same */
+       reimported = get_basic_connection (detail, plugin, tmpdir, ROUTE_EXPORTED_NAME);
+       (void) unlink (path);
+       ASSERT (reimported != NULL, detail, "failed to re-import connection");
+
+       /* Clear secrets first, since they don't get exported, and thus would
+        * make the connection comparison below fail.
+        */
+       remove_secrets (connection);
+
+       ASSERT (nm_connection_compare (connection, reimported, NM_SETTING_COMPARE_FLAG_EXACT) == TRUE,
+               detail, "original and reimported connection differ");
+
+       g_object_unref (reimported);
+       g_object_unref (connection);
+       g_free (path);
+}
+
 int main (int argc, char **argv)
 {
        GError *error = NULL;
@@ -1151,6 +1252,9 @@ int main (int argc, char **argv)
        test_device_import (plugin, "device-import", test_dir, "device-notype.ovpn", "tap", NULL);
        test_device_export (plugin, "device-export", test_dir, argv[2], "device-notype.ovpn", 
"device-notype.ovpntest");
 
+       test_route_import (plugin, "route-import", test_dir);
+       test_route_export (plugin, "route-export", test_dir, argv[2]);
+
        g_object_unref (plugin);
 
        basename = g_path_get_basename (argv[0]);


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