[network-manager-openvpn] import/export: import and export "route" option (bgo #753578)
- From: Jiří Klimeš <jklimes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [network-manager-openvpn] import/export: import and export "route" option (bgo #753578)
- Date: Fri, 27 Nov 2015 07:35:13 +0000 (UTC)
commit 4eb5f3ad43cdc62c6d4d254731e24c90b87ba91a
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 static routes in ipv4 setting.
https://bugzilla.gnome.org/show_bug.cgi?id=753578
properties/import-export.c | 174 +++++++++++++++++++++++++++++++++
properties/tests/conf/Makefile.am | 3 +-
properties/tests/conf/route.ovpn | 26 +++++
properties/tests/test-import-export.c | 150 ++++++++++++++++++++++++-----
4 files changed, 328 insertions(+), 25 deletions(-)
---
diff --git a/properties/import-export.c b/properties/import-export.c
index ceccae2..bad0369 100644
--- a/properties/import-export.c
+++ b/properties/import-export.c
@@ -27,6 +27,7 @@
#include <sys/types.h>
#include <stdlib.h>
#include <sys/stat.h>
+#include <arpa/inet.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
@@ -40,8 +41,12 @@
#include <nm-setting-vpn.h>
#include <nm-setting-connection.h>
#include <nm-setting-ip4-config.h>
+#include <nm-utils.h>
#define nm_simple_connection_new nm_connection_new
+#define NM_SETTING_IP_CONFIG NM_SETTING_IP4_CONFIG
+#define NM_SETTING_IP_CONFIG_METHOD NM_SETTING_IP4_CONFIG_METHOD
+#define NMSettingIPConfig NMSettingIP4Config
#define OPENVPN_EDITOR_PLUGIN_ERROR NM_SETTING_VPN_ERROR
#define OPENVPN_EDITOR_PLUGIN_ERROR_FILE_NOT_OPENVPN NM_SETTING_VPN_ERROR_UNKNOWN
@@ -101,6 +106,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 *
@@ -448,11 +454,26 @@ handle_num_seconds_item (const char *line,
return FALSE;
}
+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;
+ NMSettingIPConfig *s_ip4;
NMSettingVpn *s_vpn;
char *last_dot;
char **line;
@@ -467,6 +488,9 @@ do_import (const char *path, char **lines, GError **error)
connection = nm_simple_connection_new ();
s_con = NM_SETTING_CONNECTION (nm_setting_connection_new ());
nm_connection_add_setting (connection, NM_SETTING (s_con));
+ s_ip4 = NM_SETTING_IP_CONFIG (nm_setting_ip4_config_new ());
+ nm_connection_add_setting (connection, NM_SETTING (s_ip4));
+ g_object_set (s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);
s_vpn = NM_SETTING_VPN (nm_setting_vpn_new ());
@@ -926,6 +950,105 @@ do_import (const char *path, char **lines, GError **error)
g_strfreev (items);
continue;
}
+
+#ifdef NM_OPENVPN_OLD
+ 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;
+ }
+#else
+ if (!strncmp (*line, ROUTE_TAG, strlen (ROUTE_TAG))) {
+ items = get_args (*line + strlen (ROUTE_TAG), &nitems);
+ if (nitems >= 1 && nitems <= 4) {
+ guint32 prefix = 32;
+ guint32 metric = 0;
+ const char *dest = items[0];
+ const char *next_hop = "0.0.0.0";
+ NMIPRoute *route;
+
+ if (!parse_ip (items[0], *line, NULL))
+ goto route_fail;
+
+ 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, NULL))
+ goto route_fail;
+ next_hop = items[2];
+ 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_ip_route_new (AF_INET, dest, prefix, next_hop, metric, NULL);
+ nm_setting_ip_config_add_route (s_ip4, route);
+ nm_ip_route_unref (route);
+ } else
+ g_warning ("%s: invalid number of arguments in option '%s'", __func__, *line);
+
+route_fail:
+ g_strfreev (items);
+ continue;
+ }
+#endif
+
}
if (!have_client && !have_sk) {
@@ -1007,6 +1130,7 @@ gboolean
do_export (const char *path, NMConnection *connection, GError **error)
{
NMSettingConnection *s_con;
+ NMSettingIPConfig *s_ip4;
NMSettingVpn *s_vpn;
FILE *f;
const char *value;
@@ -1047,6 +1171,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_connection_get_setting_connection (connection);
g_assert (s_con);
@@ -1366,6 +1491,55 @@ do_export (const char *path, NMConnection *connection, GError **error)
}
}
+#ifdef NM_OPENVPN_OLD
+ /* Route handling is different in libnm-util and libnm */
+ /* 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));
+ }
+#else
+ /* Static routes */
+ s_ip4 = nm_connection_get_setting_ip4_config (connection);
+ for (i = 0; s_ip4 && i < nm_setting_ip_config_get_num_routes (s_ip4); i++) {
+ char netmask_str[INET_ADDRSTRLEN];
+ guint32 netmask;
+ NMIPRoute *route = nm_setting_ip_config_get_route (s_ip4, i);
+
+ memset (netmask_str, '\0', sizeof (netmask_str));
+ netmask = nm_utils_ip4_prefix_to_netmask (nm_ip_route_get_prefix (route));
+ inet_ntop (AF_INET, (const void *) &netmask, netmask_str, sizeof (netmask_str));
+
+ fprintf (f, "route %s %s %s %ld\n",
+ nm_ip_route_get_dest (route),
+ netmask_str,
+ nm_ip_route_get_next_hop (route) ? nm_ip_route_get_next_hop (route) : "0.0.0.0",
+ nm_ip_route_get_metric (route));
+ }
+#endif
+
/* Add hard-coded stuff */
fprintf (f,
"nobind\n"
diff --git a/properties/tests/conf/Makefile.am b/properties/tests/conf/Makefile.am
index a91c743..ee12b43 100644
--- a/properties/tests/conf/Makefile.am
+++ b/properties/tests/conf/Makefile.am
@@ -17,4 +17,5 @@ EXTRA_DIST = \
device-notype.ovpn \
keepalive.ovpn \
ping-with-exit.ovpn \
- ping-with-restart.ovpn
+ ping-with-restart.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 b889717..fb476ca 100644
--- a/properties/tests/test-import-export.c
+++ b/properties/tests/test-import-export.c
@@ -104,7 +104,6 @@ test_password_import (NMVpnEditorPlugin *plugin, const char *dir)
{
NMConnection *connection;
NMSettingConnection *s_con;
- NMSettingIPConfig *s_ip4;
NMSettingVpn *s_vpn;
const char *expected_id = "password";
char *expected_cacert;
@@ -123,11 +122,6 @@ test_password_import (NMVpnEditorPlugin *plugin, const char *dir)
ASSERT (nm_setting_connection_get_uuid (s_con) == NULL,
"password-import", "unexpected valid UUID");
- /* IP4 setting */
- s_ip4 = nm_connection_get_setting_ip4_config (connection);
- ASSERT (s_ip4 == NULL,
- "password-import", "unexpected 'ip4-config' setting");
-
/* VPN setting */
s_vpn = nm_connection_get_setting_vpn (connection);
ASSERT (s_vpn != NULL,
@@ -235,7 +229,6 @@ test_tls_import (NMVpnEditorPlugin *plugin, const char *dir)
{
NMConnection *connection;
NMSettingConnection *s_con;
- NMSettingIPConfig *s_ip4;
NMSettingVpn *s_vpn;
const char *expected_id = "tls";
char *expected_path;
@@ -254,11 +247,6 @@ test_tls_import (NMVpnEditorPlugin *plugin, const char *dir)
ASSERT (nm_setting_connection_get_uuid (s_con) == NULL,
"tls-import", "unexpected valid UUID");
- /* IP4 setting */
- s_ip4 = nm_connection_get_setting_ip4_config (connection);
- ASSERT (s_ip4 == NULL,
- "tls-import", "unexpected 'ip4-config' setting");
-
/* VPN setting */
s_vpn = nm_connection_get_setting_vpn (connection);
ASSERT (s_vpn != NULL,
@@ -351,7 +339,6 @@ test_pkcs12_import (NMVpnEditorPlugin *plugin, const char *dir)
{
NMConnection *connection;
NMSettingConnection *s_con;
- NMSettingIPConfig *s_ip4;
NMSettingVpn *s_vpn;
const char *expected_id = "pkcs12";
char *expected_path;
@@ -370,11 +357,6 @@ test_pkcs12_import (NMVpnEditorPlugin *plugin, const char *dir)
ASSERT (nm_setting_connection_get_uuid (s_con) == NULL,
"pkcs12-import", "unexpected valid UUID");
- /* IP4 setting */
- s_ip4 = nm_connection_get_setting_ip4_config (connection);
- ASSERT (s_ip4 == NULL,
- "pkcs12-import", "unexpected 'ip4-config' setting");
-
/* VPN setting */
s_vpn = nm_connection_get_setting_vpn (connection);
ASSERT (s_vpn != NULL,
@@ -501,7 +483,6 @@ test_static_key_import (NMVpnEditorPlugin *plugin, const char *dir)
{
NMConnection *connection;
NMSettingConnection *s_con;
- NMSettingIPConfig *s_ip4;
NMSettingVpn *s_vpn;
const char *expected_id = "static";
char *expected_path;
@@ -520,11 +501,6 @@ test_static_key_import (NMVpnEditorPlugin *plugin, const char *dir)
ASSERT (nm_setting_connection_get_uuid (s_con) == NULL,
"static-key-import", "unexpected valid UUID");
- /* IP4 setting */
- s_ip4 = nm_connection_get_setting_ip4_config (connection);
- ASSERT (s_ip4 == NULL,
- "static-key-import", "unexpected 'ip4-config' setting");
-
/* VPN setting */
s_vpn = nm_connection_get_setting_vpn (connection);
ASSERT (s_vpn != NULL,
@@ -1107,6 +1083,129 @@ test_device_export (NMVpnEditorPlugin *plugin,
g_free (path);
}
+static void
+test_route_import (NMVpnEditorPlugin *plugin,
+ const char *detail,
+ const char *dir)
+{
+ NMConnection *connection;
+ NMSettingConnection *s_con;
+ NMSettingIPConfig *s_ip4;
+ NMSettingVpn *s_vpn;
+ int num_routes;
+ NMIPRoute *route;
+ const char *expected_dest1 = "1.2.3.0";
+ guint32 expected_prefix1 = 24;
+ const char *expected_nh1 = "1.2.3.254";
+ guint32 expected_metric1 = 99;
+ const char *expected_dest2 = "5.6.7.8";
+ guint32 expected_prefix2 = 30;
+ const char *expected_nh2 = "0.0.0.0";
+ guint32 expected_metric2 = 0;
+ const char *expected_dest3 = "192.168.0.0";
+ guint32 expected_prefix3 = 16;
+ const char *expected_nh3 = "192.168.44.1";
+ guint32 expected_metric3 = 0;
+
+ connection = get_basic_connection (detail, plugin, dir, "route.ovpn");
+ ASSERT (connection != NULL, detail, "failed to import connection");
+
+ /* Connection setting */
+ s_con = nm_connection_get_setting_connection (connection);
+ ASSERT (s_con != NULL, detail, "missing 'connection' setting");
+
+ /* VPN setting */
+ s_vpn = nm_connection_get_setting_vpn (connection);
+ 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 = nm_connection_get_setting_ip4_config (connection);
+ ASSERT (s_ip4 != NULL, detail, "missing 'ip4-config' setting");
+ num_routes = nm_setting_ip_config_get_num_routes (s_ip4);
+ ASSERT (num_routes == 3, detail, "incorrect number of static routes");
+ /* route 1 */
+ route = nm_setting_ip_config_get_route (s_ip4, 0);
+ ASSERT (g_strcmp0 (nm_ip_route_get_dest (route), expected_dest1) == 0,
+ detail, "unexpected dest of 1. route");
+ ASSERT (nm_ip_route_get_prefix (route) == expected_prefix1,
+ detail, "unexpected prefix of 1. route");
+ ASSERT (g_strcmp0 (nm_ip_route_get_next_hop (route), expected_nh1) == 0,
+ detail, "unexpected next_hop of 1. route");
+ ASSERT (nm_ip_route_get_metric (route) == expected_metric1,
+ detail, "unexpected metric of 1. route");
+
+ /* route 2 */
+ route = nm_setting_ip_config_get_route (s_ip4, 1);
+ ASSERT (g_strcmp0 (nm_ip_route_get_dest (route), expected_dest2) == 0,
+ detail, "unexpected dest of 2. route");
+ ASSERT (nm_ip_route_get_prefix (route) == expected_prefix2,
+ detail, "unexpected prefix of 2. route");
+ ASSERT ( nm_ip_route_get_next_hop (route) == NULL
+ || g_strcmp0 (nm_ip_route_get_next_hop (route), expected_nh2) == 0,
+ detail, "unexpected next_hop of 2. route");
+ ASSERT (nm_ip_route_get_metric (route) == expected_metric2,
+ detail, "unexpected metric of 2. route");
+
+ /* route 3 */
+ route = nm_setting_ip_config_get_route (s_ip4, 2);
+ ASSERT (g_strcmp0 (nm_ip_route_get_dest (route), expected_dest3) == 0,
+ detail, "unexpected dest of 3. route");
+ ASSERT (nm_ip_route_get_prefix (route) == expected_prefix3,
+ detail, "unexpected prefix of 3. route");
+ ASSERT (g_strcmp0 (nm_ip_route_get_next_hop (route), expected_nh3) == 0,
+ detail, "unexpected next_hop of 3. route");
+ ASSERT (nm_ip_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 (NMVpnEditorPlugin *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_editor_plugin_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;
@@ -1190,6 +1289,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]