Blame SOURCES/rh1031763-0002-core-capture-DNS-configuration-from-resolv.conf-when.patch

2186fd
From 00009b2a238555b6777aab79b3190a8a46df56d2 Mon Sep 17 00:00:00 2001
2186fd
From: Dan Williams <dcbw@redhat.com>
2186fd
Date: Tue, 19 Nov 2013 22:28:36 -0600
2186fd
Subject: [PATCH] core: capture DNS configuration from resolv.conf when
2186fd
 generating connections
2186fd
2186fd
If the interface who's IP configuration is being captured has the default
2186fd
route, then read DNS servers from resolv.conf into the NMIP[4|6]Config.
2186fd
---
2186fd
 .gitignore                          |   1 +
2186fd
 src/NetworkManagerUtils.c           | 138 ++++++++++++++++++++++++++++
2186fd
 src/NetworkManagerUtils.h           |   8 ++
2186fd
 src/devices/nm-device.c             |  10 +-
2186fd
 src/nm-ip4-config.c                 |  13 ++-
2186fd
 src/nm-ip4-config.h                 |   2 +-
2186fd
 src/nm-ip6-config.c                 |  11 ++-
2186fd
 src/nm-ip6-config.h                 |   2 +-
2186fd
 src/tests/Makefile.am               |  12 ++-
2186fd
 src/tests/test-resolvconf-capture.c | 176 ++++++++++++++++++++++++++++++++++++
2186fd
 10 files changed, 362 insertions(+), 11 deletions(-)
2186fd
 create mode 100644 src/tests/test-resolvconf-capture.c
2186fd
2186fd
diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c
2186fd
index c2cf5e7..5a5fb7f 100644
2186fd
--- a/src/NetworkManagerUtils.c
2186fd
+++ b/src/NetworkManagerUtils.c
2186fd
@@ -21,14 +21,15 @@
2186fd
 
2186fd
 #include <glib.h>
2186fd
 #include <errno.h>
2186fd
 #include <fcntl.h>
2186fd
 #include <string.h>
2186fd
 #include <unistd.h>
2186fd
 #include <stdlib.h>
2186fd
+#include <resolv.h>
2186fd
 
2186fd
 #include "NetworkManagerUtils.h"
2186fd
 #include "nm-utils.h"
2186fd
 #include "nm-logging.h"
2186fd
 #include "nm-device.h"
2186fd
 #include "nm-setting-connection.h"
2186fd
 #include "nm-setting-ip4-config.h"
2186fd
@@ -607,7 +608,136 @@ nm_utils_complete_generic (NMConnection *connection,
2186fd
 char *
2186fd
 nm_utils_new_vlan_name (const char *parent_iface, guint32 vlan_id)
2186fd
 {
2186fd
 	/* Basically VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD */
2186fd
 	return g_strdup_printf ("%s.%d", parent_iface, vlan_id);
2186fd
 }
2186fd
 
2186fd
+static GPtrArray *
2186fd
+read_nameservers (const char *test_rc_contents)
2186fd
+{
2186fd
+	GPtrArray *nameservers = NULL;
2186fd
+	char *contents = NULL;
2186fd
+	char **lines, **iter;
2186fd
+	char *p;
2186fd
+
2186fd
+	if (test_rc_contents)
2186fd
+		contents = g_strdup (test_rc_contents);
2186fd
+	else {
2186fd
+		if (!g_file_get_contents (_PATH_RESCONF, &contents, NULL, NULL))
2186fd
+			return NULL;
2186fd
+	}
2186fd
+
2186fd
+	nameservers = g_ptr_array_new_full (3, g_free);
2186fd
+
2186fd
+	lines = g_strsplit_set (contents, "\r\n", -1);
2186fd
+	for (iter = lines; iter && *iter; iter++) {
2186fd
+		if (!g_str_has_prefix (*iter, "nameserver"))
2186fd
+			continue;
2186fd
+		p = *iter + strlen ("nameserver");
2186fd
+		while (g_ascii_isspace (*p))
2186fd
+			p++;
2186fd
+
2186fd
+		g_ptr_array_add (nameservers, g_strdup (p));
2186fd
+	}
2186fd
+
2186fd
+	g_free (contents);
2186fd
+	g_strfreev (lines);
2186fd
+	return nameservers;
2186fd
+}
2186fd
+
2186fd
+#define IS_10(a)  ((ntohl (a) & 0xff000000) == 0x0a000000)
2186fd
+#define IS_172(a) ((ntohl (a) & 0xfff00000) == 0xac100000)
2186fd
+#define IS_192(a) ((ntohl (a) & 0xffff0000) == 0xc0a80000)
2186fd
+
2186fd
+/**
2186fd
+ * nm_utils_capture_resolv_conf_ip4():
2186fd
+ * @addresses: array of #NMPlatformIP4Address structures
2186fd
+ * @nameservers: array of guint32
2186fd
+ * @test_rc_contents: for testing; the contents of resolv.conf
2186fd
+ *
2186fd
+ * Reads all /etc/resolv.conf IPv4 nameservers and adds them to @nameservers,
2186fd
+ * which checks to ensure that private-network nameservers are not added if
2186fd
+ * @addresses does not contain an address in that private network.
2186fd
+ */
2186fd
+void
2186fd
+nm_utils_capture_resolv_conf_ip4 (const GArray *addresses,
2186fd
+                                  GArray *nameservers,
2186fd
+                                  const char *test_rc_contents)
2186fd
+{
2186fd
+	GPtrArray *read_ns;
2186fd
+	gboolean has_10 = FALSE, has_172 = FALSE, has_192 = FALSE;
2186fd
+	guint i;
2186fd
+
2186fd
+	g_return_if_fail (nameservers != NULL);
2186fd
+
2186fd
+	read_ns = read_nameservers (test_rc_contents);
2186fd
+	if (!read_ns)
2186fd
+		return;
2186fd
+
2186fd
+	for (i = 0; addresses && i < addresses->len; i++) {
2186fd
+		NMPlatformIP4Address *addr = &g_array_index (addresses, NMPlatformIP4Address, i);
2186fd
+
2186fd
+		if (IS_10 (addr->address))
2186fd
+			has_10 = TRUE;
2186fd
+		else if (IS_172 (addr->address))
2186fd
+			has_172 = TRUE;
2186fd
+		else if (IS_192 (addr->address))
2186fd
+			has_192 = TRUE;
2186fd
+	}
2186fd
+
2186fd
+	for (i = 0; i < read_ns->len; i++) {
2186fd
+		const char *s = g_ptr_array_index (read_ns, i);
2186fd
+		guint32 ns = 0;
2186fd
+
2186fd
+		if (!inet_pton (AF_INET, s, (void *) &ns) || !ns)
2186fd
+			continue;
2186fd
+
2186fd
+		/* Ignore any private-network addresses that aren't in this
2186fd
+		 * interface's address space.
2186fd
+		 */
2186fd
+		if (   (IS_10 (ns) && !has_10)
2186fd
+		    || (IS_172 (ns) && !has_172)
2186fd
+		    || (IS_192 (ns) && !has_192))
2186fd
+			continue;
2186fd
+
2186fd
+		g_array_append_val (nameservers, ns);
2186fd
+	}
2186fd
+
2186fd
+	g_ptr_array_unref (read_ns);
2186fd
+}
2186fd
+
2186fd
+/**
2186fd
+ * nm_utils_capture_resolv_conf_ip6():
2186fd
+ * @addresses: array of #NMPlatformIP6Address structures
2186fd
+ * @nameservers: array of struct in6_addr
2186fd
+ * @test_rc_contents: for testing; the contents of resolv.conf
2186fd
+ *
2186fd
+ * Reads all /etc/resolv.conf IPv6 nameservers and adds them to @nameservers.
2186fd
+ */
2186fd
+void
2186fd
+nm_utils_capture_resolv_conf_ip6 (const GArray *addresses,
2186fd
+                                  GArray *nameservers,
2186fd
+                                  const char *test_rc_contents)
2186fd
+{
2186fd
+	GPtrArray *read_ns;
2186fd
+	guint i;
2186fd
+
2186fd
+	g_return_if_fail (nameservers != NULL);
2186fd
+
2186fd
+	read_ns = read_nameservers (test_rc_contents);
2186fd
+	if (!read_ns)
2186fd
+		return;
2186fd
+
2186fd
+	for (i = 0; i < read_ns->len; i++) {
2186fd
+		const char *s = g_ptr_array_index (read_ns, i);
2186fd
+		struct in6_addr ns = IN6ADDR_ANY_INIT;
2186fd
+
2186fd
+		if (!inet_pton (AF_INET6, s, (void *) &ns) || IN6_IS_ADDR_UNSPECIFIED (&ns))
2186fd
+			continue;
2186fd
+
2186fd
+		g_array_append_val (nameservers, ns);
2186fd
+	}
2186fd
+
2186fd
+	g_ptr_array_unref (read_ns);
2186fd
+}
2186fd
+
2186fd
diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h
2186fd
index 93ec111..cd30ece 100644
2186fd
--- a/src/NetworkManagerUtils.h
2186fd
+++ b/src/NetworkManagerUtils.h
2186fd
@@ -80,8 +80,16 @@ void nm_utils_complete_generic (NMConnection *connection,
2186fd
                                 const GSList *existing,
2186fd
                                 const char *format,
2186fd
                                 const char *preferred,
2186fd
                                 gboolean default_enable_ipv6);
2186fd
 
2186fd
 char *nm_utils_new_vlan_name (const char *parent_iface, guint32 vlan_id);
2186fd
 
2186fd
+void nm_utils_capture_resolv_conf_ip4 (const GArray *addresses,
2186fd
+                                       GArray *nameservers,
2186fd
+                                       const char *test_rc_contents);
2186fd
+
2186fd
+void nm_utils_capture_resolv_conf_ip6 (const GArray *addresses,
2186fd
+                                       GArray *nameservers,
2186fd
+                                       const char *test_rc_contents);
2186fd
+
2186fd
 #endif /* NETWORK_MANAGER_UTILS_H */
2186fd
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
2186fd
index cc678ce..f03ecbb 100644
2186fd
--- a/src/devices/nm-device.c
2186fd
+++ b/src/devices/nm-device.c
2186fd
@@ -353,15 +353,15 @@ static void cp_connection_updated (NMConnectionProvider *cp, NMConnection *conne
2186fd
 
2186fd
 static const char *state_to_string (NMDeviceState state);
2186fd
 
2186fd
 static void link_changed_cb (NMPlatform *platform, int ifindex, NMPlatformLink *info, NMPlatformReason reason, NMDevice *device);
2186fd
 static void check_carrier (NMDevice *device);
2186fd
 
2186fd
 static void nm_device_queued_ip_config_change_clear (NMDevice *self);
2186fd
-static void update_ip_config (NMDevice *self, gboolean capture_dhcp);
2186fd
+static void update_ip_config (NMDevice *self, gboolean initial);
2186fd
 static void device_ip_changed (NMPlatform *platform, int ifindex, gpointer platform_object, NMPlatformReason reason, gpointer user_data);
2186fd
 
2186fd
 static void nm_device_slave_notify_enslave (NMDevice *dev, gboolean success);
2186fd
 static void nm_device_slave_notify_release (NMDevice *dev, gboolean master_failed);
2186fd
 
2186fd
 static void addrconf6_start_with_link_ready (NMDevice *self);
2186fd
 
2186fd
@@ -6493,44 +6493,44 @@ capture_lease_config (NMDevice *device,
2186fd
 		if (out_ip6_config && strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) == 0) {
2186fd
 			/* FIXME: implement find_ip6_lease_config() */
2186fd
 		}
2186fd
 	}
2186fd
 }
2186fd
 
2186fd
 static void
2186fd
-update_ip_config (NMDevice *self, gboolean capture_dhcp)
2186fd
+update_ip_config (NMDevice *self, gboolean initial)
2186fd
 {
2186fd
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
2186fd
 	int ifindex;
2186fd
 	gboolean linklocal6_just_completed = FALSE;
2186fd
 
2186fd
 	ifindex = nm_device_get_ip_ifindex (self);
2186fd
 	if (!ifindex)
2186fd
 		return;
2186fd
 
2186fd
 	/* IPv4 */
2186fd
 	g_clear_object (&priv->ext_ip4_config);
2186fd
-	priv->ext_ip4_config = nm_ip4_config_capture (ifindex);
2186fd
+	priv->ext_ip4_config = nm_ip4_config_capture (ifindex, initial);
2186fd
 
2186fd
 	if (priv->ext_ip4_config) {
2186fd
-		if (capture_dhcp) {
2186fd
+		if (initial) {
2186fd
 			g_clear_object (&priv->dev_ip4_config);
2186fd
 			capture_lease_config (self, priv->ext_ip4_config, &priv->dev_ip4_config, NULL, NULL);
2186fd
 		}
2186fd
 		if (priv->dev_ip4_config)
2186fd
 			nm_ip4_config_subtract (priv->ext_ip4_config, priv->dev_ip4_config);
2186fd
 		if (priv->vpn4_config)
2186fd
 			nm_ip4_config_subtract (priv->ext_ip4_config, priv->vpn4_config);
2186fd
 
2186fd
 		ip4_config_merge_and_apply (self, NULL, FALSE, NULL);
2186fd
 	}
2186fd
 
2186fd
 	/* IPv6 */
2186fd
 	g_clear_object (&priv->ext_ip6_config);
2186fd
-	priv->ext_ip6_config = nm_ip6_config_capture (ifindex);
2186fd
+	priv->ext_ip6_config = nm_ip6_config_capture (ifindex, initial);
2186fd
 	if (priv->ext_ip6_config) {
2186fd
 
2186fd
 		/* Check this before modifying ext_ip6_config */
2186fd
 		linklocal6_just_completed = priv->linklocal6_timeout_id &&
2186fd
 		                            linklocal6_config_is_ready (priv->ext_ip6_config);
2186fd
 
2186fd
 		if (priv->ac_ip6_config)
2186fd
diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c
2186fd
index 5229ef9..e27a557 100644
2186fd
--- a/src/nm-ip4-config.c
2186fd
+++ b/src/nm-ip4-config.c
2186fd
@@ -25,14 +25,15 @@
2186fd
 
2186fd
 #include "libgsystem.h"
2186fd
 #include "nm-platform.h"
2186fd
 #include "nm-utils.h"
2186fd
 #include "nm-dbus-manager.h"
2186fd
 #include "nm-dbus-glib-types.h"
2186fd
 #include "nm-ip4-config-glue.h"
2186fd
+#include "NetworkManagerUtils.h"
2186fd
 
2186fd
 
2186fd
 G_DEFINE_TYPE (NMIP4Config, nm_ip4_config, G_TYPE_OBJECT)
2186fd
 
2186fd
 #define NM_IP4_CONFIG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_IP4_CONFIG, NMIP4ConfigPrivate))
2186fd
 
2186fd
 typedef struct {
2186fd
@@ -121,20 +122,20 @@ static gboolean
2186fd
 routes_are_duplicate (const NMPlatformIP4Route *a, const NMPlatformIP4Route *b, gboolean consider_gateway_and_metric)
2186fd
 {
2186fd
 	return a->network == b->network && a->plen == b->plen &&
2186fd
 	       (!consider_gateway_and_metric || (a->gateway == b->gateway && a->metric == b->metric));
2186fd
 }
2186fd
 
2186fd
 NMIP4Config *
2186fd
-nm_ip4_config_capture (int ifindex)
2186fd
+nm_ip4_config_capture (int ifindex, gboolean capture_resolv_conf)
2186fd
 {
2186fd
 	NMIP4Config *config;
2186fd
 	NMIP4ConfigPrivate *priv;
2186fd
-	guint i;
2186fd
 	gboolean gateway_changed = FALSE;
2186fd
+	guint i;
2186fd
 
2186fd
 	/* Slaves have no IP configuration */
2186fd
 	if (nm_platform_link_get_master (ifindex) > 0)
2186fd
 		return NULL;
2186fd
 
2186fd
 	config = nm_ip4_config_new ();
2186fd
 	priv = NM_IP4_CONFIG_GET_PRIVATE (config);
2186fd
@@ -156,14 +157,22 @@ nm_ip4_config_capture (int ifindex)
2186fd
 			}
2186fd
 			/* Remove the default route from the list */
2186fd
 			g_array_remove_index (priv->routes, i);
2186fd
 			break;
2186fd
 		}
2186fd
 	}
2186fd
 
2186fd
+	/* If the interface has the default route, and has IPv4 addresses, capture
2186fd
+	 * nameservers from /etc/resolv.conf.
2186fd
+	 */
2186fd
+	if (priv->addresses->len && priv->gateway && capture_resolv_conf) {
2186fd
+		nm_utils_capture_resolv_conf_ip4 (priv->addresses, priv->nameservers, NULL);
2186fd
+		_NOTIFY (config, PROP_NAMESERVERS);
2186fd
+	}
2186fd
+
2186fd
 	/* actually, nobody should be connected to the signal, just to be sure, notify */
2186fd
 	_NOTIFY (config, PROP_ADDRESSES);
2186fd
 	_NOTIFY (config, PROP_ROUTES);
2186fd
 	if (gateway_changed)
2186fd
 		_NOTIFY (config, PROP_GATEWAY);
2186fd
 
2186fd
 	return config;
2186fd
diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h
2186fd
index 3b2b250..4ecfb76 100644
2186fd
--- a/src/nm-ip4-config.h
2186fd
+++ b/src/nm-ip4-config.h
2186fd
@@ -55,15 +55,15 @@ GType nm_ip4_config_get_type (void);
2186fd
 NMIP4Config * nm_ip4_config_new (void);
2186fd
 
2186fd
 /* D-Bus integration */
2186fd
 void nm_ip4_config_export (NMIP4Config *config);
2186fd
 const char * nm_ip4_config_get_dbus_path (const NMIP4Config *config);
2186fd
 
2186fd
 /* Integration with nm-platform and nm-setting */
2186fd
-NMIP4Config *nm_ip4_config_capture (int ifindex);
2186fd
+NMIP4Config *nm_ip4_config_capture (int ifindex, gboolean capture_resolv_conf);
2186fd
 gboolean nm_ip4_config_commit (const NMIP4Config *config, int ifindex, int priority);
2186fd
 void nm_ip4_config_merge_setting (NMIP4Config *config, NMSettingIP4Config *setting);
2186fd
 void nm_ip4_config_update_setting (const NMIP4Config *config, NMSettingIP4Config *setting);
2186fd
 
2186fd
 /* Utility functions */
2186fd
 void nm_ip4_config_merge (NMIP4Config *dst, const NMIP4Config *src);
2186fd
 void nm_ip4_config_subtract (NMIP4Config *dst, const NMIP4Config *src);
2186fd
diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c
2186fd
index 7522164..726e658 100644
2186fd
--- a/src/nm-ip6-config.c
2186fd
+++ b/src/nm-ip6-config.c
2186fd
@@ -26,14 +26,15 @@
2186fd
 #include "nm-glib-compat.h"
2186fd
 #include "libgsystem.h"
2186fd
 #include "nm-platform.h"
2186fd
 #include "nm-utils.h"
2186fd
 #include "nm-dbus-manager.h"
2186fd
 #include "nm-dbus-glib-types.h"
2186fd
 #include "nm-ip6-config-glue.h"
2186fd
+#include "NetworkManagerUtils.h"
2186fd
 
2186fd
 G_DEFINE_TYPE (NMIP6Config, nm_ip6_config, G_TYPE_OBJECT)
2186fd
 
2186fd
 #define NM_IP6_CONFIG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_IP6_CONFIG, NMIP6ConfigPrivate))
2186fd
 
2186fd
 typedef struct {
2186fd
 	char *path;
2186fd
@@ -121,15 +122,15 @@ static gboolean
2186fd
 routes_are_duplicate (const NMPlatformIP6Route *a, const NMPlatformIP6Route *b, gboolean consider_gateway_and_metric)
2186fd
 {
2186fd
 	return IN6_ARE_ADDR_EQUAL (&a->network, &b->network) && a->plen == b->plen &&
2186fd
 	       (!consider_gateway_and_metric || (IN6_ARE_ADDR_EQUAL (&a->gateway, &b->gateway) && a->metric == b->metric));
2186fd
 }
2186fd
 
2186fd
 NMIP6Config *
2186fd
-nm_ip6_config_capture (int ifindex)
2186fd
+nm_ip6_config_capture (int ifindex, gboolean capture_resolv_conf)
2186fd
 {
2186fd
 	NMIP6Config *config;
2186fd
 	NMIP6ConfigPrivate *priv;
2186fd
 	guint i;
2186fd
 	gboolean gateway_changed = FALSE;
2186fd
 
2186fd
 	/* Slaves have no IP configuration */
2186fd
@@ -156,14 +157,22 @@ nm_ip6_config_capture (int ifindex)
2186fd
 			}
2186fd
 			/* Remove the default route from the list */
2186fd
 			g_array_remove_index (priv->routes, i);
2186fd
 			break;
2186fd
 		}
2186fd
 	}
2186fd
 
2186fd
+	/* If the interface has the default route, and has IPv4 addresses, capture
2186fd
+	 * nameservers from /etc/resolv.conf.
2186fd
+	 */
2186fd
+	if (priv->addresses->len && !IN6_IS_ADDR_UNSPECIFIED (&priv->gateway) && capture_resolv_conf) {
2186fd
+		nm_utils_capture_resolv_conf_ip6 (priv->addresses, priv->nameservers, NULL);
2186fd
+		_NOTIFY (config, PROP_NAMESERVERS);
2186fd
+	}
2186fd
+
2186fd
 	/* actually, nobody should be connected to the signal, just to be sure, notify */
2186fd
 	_NOTIFY (config, PROP_ADDRESSES);
2186fd
 	_NOTIFY (config, PROP_ROUTES);
2186fd
 	if (gateway_changed)
2186fd
 		_NOTIFY (config, PROP_GATEWAY);
2186fd
 
2186fd
 	return config;
2186fd
diff --git a/src/nm-ip6-config.h b/src/nm-ip6-config.h
2186fd
index 538490a..2b1ba8b 100644
2186fd
--- a/src/nm-ip6-config.h
2186fd
+++ b/src/nm-ip6-config.h
2186fd
@@ -54,15 +54,15 @@ GType nm_ip6_config_get_type (void);
2186fd
 NMIP6Config * nm_ip6_config_new (void);
2186fd
 
2186fd
 /* D-Bus integration */
2186fd
 void nm_ip6_config_export (NMIP6Config *config);
2186fd
 const char * nm_ip6_config_get_dbus_path (const NMIP6Config *config);
2186fd
 
2186fd
 /* Integration with nm-platform and nm-setting */
2186fd
-NMIP6Config *nm_ip6_config_capture (int ifindex);
2186fd
+NMIP6Config *nm_ip6_config_capture (int ifindex, gboolean initial);
2186fd
 gboolean nm_ip6_config_commit (const NMIP6Config *config, int ifindex, int priority);
2186fd
 void nm_ip6_config_merge_setting (NMIP6Config *config, NMSettingIP6Config *setting);
2186fd
 void nm_ip6_config_update_setting (const NMIP6Config *config, NMSettingIP6Config *setting);
2186fd
 
2186fd
 /* Utility functions */
2186fd
 void nm_ip6_config_merge (NMIP6Config *dst, const NMIP6Config *src);
2186fd
 void nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src);
2186fd
diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am
2186fd
index 9d17e9a..eaa9d51 100644
2186fd
--- a/src/tests/Makefile.am
2186fd
+++ b/src/tests/Makefile.am
2186fd
@@ -12,15 +12,16 @@ AM_CPPFLAGS = \
2186fd
 
2186fd
 noinst_PROGRAMS = \
2186fd
 	test-dhcp-options \
2186fd
 	test-policy-hosts \
2186fd
 	test-wifi-ap-utils \
2186fd
 	test-ip4-config \
2186fd
 	test-ip6-config \
2186fd
-	test-dcb
2186fd
+	test-dcb \
2186fd
+	test-resolvconf-capture
2186fd
 
2186fd
 ####### DHCP options test #######
2186fd
 
2186fd
 test_dhcp_options_SOURCES = \
2186fd
 	test-dhcp-options.c
2186fd
 
2186fd
 test_dhcp_options_CPPFLAGS = \
2186fd
@@ -67,21 +68,30 @@ test_ip6_config_LDADD = \
2186fd
 
2186fd
 test_dcb_SOURCES = \
2186fd
 	test-dcb.c
2186fd
 
2186fd
 test_dcb_LDADD = \
2186fd
 	$(top_builddir)/src/libNetworkManager.la
2186fd
 
2186fd
+####### resolv.conf capture test #######
2186fd
+
2186fd
+test_resolvconf_capture_SOURCES = \
2186fd
+	test-resolvconf-capture.c
2186fd
+
2186fd
+test_resolvconf_capture_LDADD = \
2186fd
+	$(top_builddir)/src/libNetworkManager.la
2186fd
+
2186fd
 ####### secret agent interface test #######
2186fd
 
2186fd
 EXTRA_DIST = test-secret-agent.py
2186fd
 
2186fd
 ###########################################
2186fd
 
2186fd
 check-local: test-dhcp-options test-policy-hosts test-wifi-ap-utils test-ip4-config test-ip6-config
2186fd
 	$(abs_builddir)/test-dhcp-options
2186fd
 	$(abs_builddir)/test-policy-hosts
2186fd
 	$(abs_builddir)/test-wifi-ap-utils
2186fd
 	$(abs_builddir)/test-ip4-config
2186fd
 	$(abs_builddir)/test-ip6-config
2186fd
 	$(abs_builddir)/test-dcb
2186fd
+	$(abs_builddir)/test-resolvconf-capture
2186fd
 
2186fd
diff --git a/src/tests/test-resolvconf-capture.c b/src/tests/test-resolvconf-capture.c
2186fd
new file mode 100644
2186fd
index 0000000..0343d17
2186fd
--- /dev/null
2186fd
+++ b/src/tests/test-resolvconf-capture.c
2186fd
@@ -0,0 +1,176 @@
2186fd
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2186fd
+/*
2186fd
+ * This program is free software; you can redistribute it and/or modify
2186fd
+ * it under the terms of the GNU General Public License as published by
2186fd
+ * the Free Software Foundation; either version 2, or (at your option)
2186fd
+ * any later version.
2186fd
+ *
2186fd
+ * This program is distributed in the hope that it will be useful,
2186fd
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2186fd
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
2186fd
+ * GNU General Public License for more details.
2186fd
+ *
2186fd
+ * You should have received a copy of the GNU General Public License along
2186fd
+ * with this program; if not, write to the Free Software Foundation, Inc.,
2186fd
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
2186fd
+ *
2186fd
+ * Copyright (C) 2013 Red Hat, Inc.
2186fd
+ *
2186fd
+ */
2186fd
+
2186fd
+#include <glib.h>
2186fd
+#include <string.h>
2186fd
+
2186fd
+#include "NetworkManagerUtils.h"
2186fd
+#include "nm-platform.h"
2186fd
+
2186fd
+static void
2186fd
+test_capture_empty (void)
2186fd
+{
2186fd
+	GArray *ns4 = g_array_new (FALSE, FALSE, sizeof (guint32));
2186fd
+	GArray *ns6 = g_array_new (FALSE, FALSE, sizeof (struct in6_addr));
2186fd
+
2186fd
+	nm_utils_capture_resolv_conf_ip4 (NULL, ns4, "");
2186fd
+	g_assert_cmpint (ns4->len, ==, 0);
2186fd
+
2186fd
+	nm_utils_capture_resolv_conf_ip6 (NULL, ns6, "");
2186fd
+	g_assert_cmpint (ns6->len, ==, 0);
2186fd
+
2186fd
+	g_array_free (ns4, TRUE);
2186fd
+	g_array_free (ns6, TRUE);
2186fd
+}
2186fd
+
2186fd
+static void
2186fd
+assert_dns4_entry (const GArray *a, guint i, const char *s)
2186fd
+{
2186fd
+	guint32 n, m;
2186fd
+
2186fd
+	g_assert (inet_aton (s, (void *) &n) != 0);
2186fd
+	m = g_array_index (a, guint32, i);
2186fd
+	g_assert_cmpint (m, ==, n);
2186fd
+}
2186fd
+
2186fd
+static void
2186fd
+assert_dns6_entry (const GArray *a, guint i, const char *s)
2186fd
+{
2186fd
+	struct in6_addr n = IN6ADDR_ANY_INIT;
2186fd
+	struct in6_addr *m;
2186fd
+
2186fd
+	g_assert (inet_pton (AF_INET6, s, (void *) &n) == 1);
2186fd
+	m = &g_array_index (a, struct in6_addr, i);
2186fd
+	g_assert (IN6_ARE_ADDR_EQUAL (&n, m));
2186fd
+}
2186fd
+
2186fd
+static void
2186fd
+test_capture_basic4 (void)
2186fd
+{
2186fd
+	GArray *ns4 = g_array_new (FALSE, FALSE, sizeof (guint32));
2186fd
+	const char *rc =
2186fd
+"# neato resolv.conf\r\n"
2186fd
+"domain foobar.com\r\n"
2186fd
+"search foobar.com\r\n"
2186fd
+"nameserver 4.2.2.1\r\n"
2186fd
+"nameserver 4.2.2.2\r\n"
2186fd
+"nameserver 192.168.1.1\r\n";
2186fd
+
2186fd
+	nm_utils_capture_resolv_conf_ip4 (NULL, ns4, rc);
2186fd
+	g_assert_cmpint (ns4->len, ==, 2);
2186fd
+	assert_dns4_entry (ns4, 0, "4.2.2.1");
2186fd
+	assert_dns4_entry (ns4, 1, "4.2.2.2");
2186fd
+	/* 192.x not present because no addresses given */
2186fd
+
2186fd
+	g_array_free (ns4, TRUE);
2186fd
+}
2186fd
+
2186fd
+static void
2186fd
+test_capture_basic6 (void)
2186fd
+{
2186fd
+	GArray *ns6 = g_array_new (FALSE, FALSE, sizeof (struct in6_addr));
2186fd
+	const char *rc =
2186fd
+"# neato resolv.conf\r\n"
2186fd
+"domain foobar.com\r\n"
2186fd
+"search foobar.com\r\n"
2186fd
+"nameserver 2001:4860:4860::8888\r\n"
2186fd
+"nameserver 2001:4860:4860::8844\r\n";
2186fd
+
2186fd
+	nm_utils_capture_resolv_conf_ip6 (NULL, ns6, rc);
2186fd
+	g_assert_cmpint (ns6->len, ==, 2);
2186fd
+	assert_dns6_entry (ns6, 0, "2001:4860:4860::8888");
2186fd
+	assert_dns6_entry (ns6, 1, "2001:4860:4860::8844");
2186fd
+
2186fd
+	g_array_free (ns6, TRUE);
2186fd
+}
2186fd
+
2186fd
+static void
2186fd
+test_capture_private_net4 (void)
2186fd
+{
2186fd
+	GArray *ns4 = g_array_new (FALSE, FALSE, sizeof (guint32));
2186fd
+	const char *rc =
2186fd
+"# neato resolv.conf\r\n"
2186fd
+"domain foobar.com\r\n"
2186fd
+"search foobar.com\r\n"
2186fd
+"nameserver 4.2.2.1\r\n"
2186fd
+"nameserver 4.2.2.2\r\n"
2186fd
+"nameserver 10.2.3.4\r\n"
2186fd
+"nameserver 172.17.6.3\r\n"
2186fd
+"nameserver 192.168.1.1\r\n";
2186fd
+	GArray *addrs = g_array_new (FALSE, FALSE, sizeof (NMPlatformIP4Address));
2186fd
+	NMPlatformIP4Address a, *b;
2186fd
+
2186fd
+	memset (&a, 0, sizeof (a));
2186fd
+	a.address = htonl (0x0a000006);
2186fd
+	a.plen = 8;
2186fd
+	g_array_append_val (addrs, a);
2186fd
+
2186fd
+	/* 10.x test */
2186fd
+	nm_utils_capture_resolv_conf_ip4 (addrs, ns4, rc);
2186fd
+	g_assert_cmpint (ns4->len, ==, 3);
2186fd
+	assert_dns4_entry (ns4, 0, "4.2.2.1");
2186fd
+	assert_dns4_entry (ns4, 1, "4.2.2.2");
2186fd
+	assert_dns4_entry (ns4, 2, "10.2.3.4");
2186fd
+
2186fd
+	/* 172.x test */
2186fd
+	b = &g_array_index (addrs, NMPlatformIP4Address, 0);
2186fd
+	b->address = htonl (0xac100003);
2186fd
+
2186fd
+	g_array_set_size (ns4, 0);
2186fd
+	nm_utils_capture_resolv_conf_ip4 (addrs, ns4, rc);
2186fd
+	g_assert_cmpint (ns4->len, ==, 3);
2186fd
+	assert_dns4_entry (ns4, 0, "4.2.2.1");
2186fd
+	assert_dns4_entry (ns4, 1, "4.2.2.2");
2186fd
+	assert_dns4_entry (ns4, 2, "172.17.6.3");
2186fd
+
2186fd
+	/* 192.x test */
2186fd
+	b = &g_array_index (addrs, NMPlatformIP4Address, 0);
2186fd
+	b->address = htonl (0xc0a80010);
2186fd
+
2186fd
+	g_array_set_size (ns4, 0);
2186fd
+	nm_utils_capture_resolv_conf_ip4 (addrs, ns4, rc);
2186fd
+	g_assert_cmpint (ns4->len, ==, 3);
2186fd
+	assert_dns4_entry (ns4, 0, "4.2.2.1");
2186fd
+	assert_dns4_entry (ns4, 1, "4.2.2.2");
2186fd
+	assert_dns4_entry (ns4, 2, "192.168.1.1");
2186fd
+
2186fd
+	g_array_free (ns4, TRUE);
2186fd
+	g_array_free (addrs, TRUE);
2186fd
+}
2186fd
+
2186fd
+/*******************************************/
2186fd
+
2186fd
+int
2186fd
+main (int argc, char **argv)
2186fd
+{
2186fd
+	g_test_init (&argc, &argv, NULL);
2186fd
+
2186fd
+#if !GLIB_CHECK_VERSION (2,36,0)
2186fd
+	g_type_init ();
2186fd
+#endif
2186fd
+
2186fd
+	g_test_add_func ("/resolvconf-capture/empty", test_capture_empty);
2186fd
+	g_test_add_func ("/resolvconf-capture/basic4", test_capture_basic4);
2186fd
+	g_test_add_func ("/resolvconf-capture/basic6", test_capture_basic6);
2186fd
+	g_test_add_func ("/resolvconf-capture/private-net4", test_capture_private_net4);
2186fd
+
2186fd
+	return g_test_run ();
2186fd
+}
2186fd
+
2186fd
-- 
2186fd
1.8.3.1
2186fd