summary refs log tree commit diff
path: root/src/nm-ip4-config.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nm-ip4-config.c')
-rw-r--r--src/nm-ip4-config.c300
1 files changed, 219 insertions, 81 deletions
diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c
index 657ebfc0..6604711c 100644
--- a/src/nm-ip4-config.c
+++ b/src/nm-ip4-config.c
@@ -278,10 +278,12 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMIP4Config,
 	PROP_ROUTE_DATA,
 	PROP_ROUTES,
 	PROP_GATEWAY,
+	PROP_NAMESERVER_DATA,
 	PROP_NAMESERVERS,
 	PROP_DOMAINS,
 	PROP_SEARCHES,
 	PROP_DNS_OPTIONS,
+	PROP_WINS_SERVER_DATA,
 	PROP_WINS_SERVERS,
 	PROP_DNS_PRIORITY,
 );
@@ -291,8 +293,9 @@ typedef struct {
 	guint32 mtu;
 	int ifindex;
 	NMIPConfigSource mtu_source;
-	gint dns_priority;
+	int dns_priority;
 	NMSettingConnectionMdns mdns;
+	NMSettingConnectionLlmnr llmnr;
 	GArray *nameservers;
 	GPtrArray *domains;
 	GPtrArray *searches;
@@ -509,8 +512,8 @@ _notify_addresses (NMIP4Config *self)
 
 	nm_clear_g_variant (&priv->address_data_variant);
 	nm_clear_g_variant (&priv->addresses_variant);
-	_notify (self, PROP_ADDRESS_DATA);
-	_notify (self, PROP_ADDRESSES);
+	nm_gobject_notify_together (self, PROP_ADDRESS_DATA,
+	                                  PROP_ADDRESSES);
 }
 
 static void
@@ -521,13 +524,13 @@ _notify_routes (NMIP4Config *self)
 	nm_assert (priv->best_default_route == _nm_ip4_config_best_default_route_find (self));
 	nm_clear_g_variant (&priv->route_data_variant);
 	nm_clear_g_variant (&priv->routes_variant);
-	_notify (self, PROP_ROUTE_DATA);
-	_notify (self, PROP_ROUTES);
+	nm_gobject_notify_together (self, PROP_ROUTE_DATA,
+	                                  PROP_ROUTES);
 }
 
 /*****************************************************************************/
 
-static gint
+static int
 _addresses_sort_cmp_get_prio (in_addr_t addr)
 {
 	if (nm_utils_ip4_address_is_link_local (addr))
@@ -538,7 +541,7 @@ _addresses_sort_cmp_get_prio (in_addr_t addr)
 static int
 _addresses_sort_cmp (gconstpointer a, gconstpointer b, gpointer user_data)
 {
-	gint p1, p2;
+	int p1, p2;
 	const NMPlatformIP4Address *a1 = NMP_OBJECT_CAST_IP4_ADDRESS (*((const NMPObject **) a));
 	const NMPlatformIP4Address *a2 = NMP_OBJECT_CAST_IP4_ADDRESS (*((const NMPObject **) b));
 	guint32 n1, n2;
@@ -914,6 +917,7 @@ void
 nm_ip4_config_merge_setting (NMIP4Config *self,
                              NMSettingIPConfig *setting,
                              NMSettingConnectionMdns mdns,
+                             NMSettingConnectionLlmnr llmnr,
                              guint32 route_table,
                              guint32 route_metric)
 {
@@ -1031,6 +1035,7 @@ nm_ip4_config_merge_setting (NMIP4Config *self,
 		nm_ip4_config_set_dns_priority (self, priority);
 
 	nm_ip4_config_mdns_set (self, mdns);
+	nm_ip4_config_llmnr_set (self, llmnr);
 
 	g_object_thaw_notify (G_OBJECT (self));
 }
@@ -1251,6 +1256,10 @@ nm_ip4_config_merge (NMIP4Config *dst,
 	nm_ip4_config_mdns_set (dst,
 	                        NM_MAX (nm_ip4_config_mdns_get (src),
 	                                nm_ip4_config_mdns_get (dst)));
+	/* LLMNR */
+	nm_ip4_config_llmnr_set (dst,
+	                         NM_MAX (nm_ip4_config_llmnr_get (src),
+	                                 nm_ip4_config_llmnr_get (dst)));
 
 	g_object_thaw_notify (G_OBJECT (dst));
 }
@@ -1367,7 +1376,7 @@ nm_ip4_config_subtract (NMIP4Config *dst,
 {
 	NMIP4ConfigPrivate *dst_priv;
 	guint i;
-	gint idx;
+	int idx;
 	const NMPlatformIP4Address *a;
 	const NMPlatformIP4Route *r;
 	NMDedupMultiIter ipconf_iter;
@@ -1492,12 +1501,17 @@ nm_ip4_config_subtract (NMIP4Config *dst,
 	if (nm_ip4_config_mdns_get (src) == nm_ip4_config_mdns_get (dst))
 		nm_ip4_config_mdns_set (dst, NM_SETTING_CONNECTION_MDNS_DEFAULT);
 
+	/* LLMNR */
+	if (nm_ip4_config_llmnr_get (src) == nm_ip4_config_llmnr_get (dst))
+		nm_ip4_config_llmnr_set (dst, NM_SETTING_CONNECTION_LLMNR_DEFAULT);
+
 	g_object_thaw_notify (G_OBJECT (dst));
 }
 
 static gboolean
 _nm_ip4_config_intersect_helper (NMIP4Config *dst,
                                  const NMIP4Config *src,
+                                 gboolean intersect_routes,
                                  guint32 default_route_metric_penalty,
                                  gboolean update_dst)
 {
@@ -1542,6 +1556,9 @@ _nm_ip4_config_intersect_helper (NMIP4Config *dst,
 	/* ignore nameservers */
 
 	/* routes */
+	if (!intersect_routes)
+		goto skip_routes;
+
 	changed = FALSE;
 	new_best_default_route = NULL;
 	nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, dst, &r) {
@@ -1582,6 +1599,7 @@ _nm_ip4_config_intersect_helper (NMIP4Config *dst,
 		_notify (dst, PROP_GATEWAY);
 	}
 
+skip_routes:
 	if (changed) {
 		_notify_routes (dst);
 		result = TRUE;
@@ -1593,6 +1611,7 @@ _nm_ip4_config_intersect_helper (NMIP4Config *dst,
 	/* ignore NIS */
 	/* ignore WINS */
 	/* ignore mdns */
+	/* ignore LLMNR */
 
 	if (update_dst)
 		g_object_thaw_notify (G_OBJECT (dst));
@@ -1611,9 +1630,10 @@ _nm_ip4_config_intersect_helper (NMIP4Config *dst,
 void
 nm_ip4_config_intersect (NMIP4Config *dst,
                          const NMIP4Config *src,
+                         gboolean intersect_routes,
                          guint32 default_route_metric_penalty)
 {
-	_nm_ip4_config_intersect_helper (dst, src, default_route_metric_penalty, TRUE);
+	_nm_ip4_config_intersect_helper (dst, src, intersect_routes, default_route_metric_penalty, TRUE);
 }
 
 /**
@@ -1634,14 +1654,17 @@ nm_ip4_config_intersect (NMIP4Config *dst,
 NMIP4Config *
 nm_ip4_config_intersect_alloc (const NMIP4Config *a,
                                const NMIP4Config *b,
+                               gboolean intersect_routes,
                                guint32 default_route_metric_penalty)
 {
 	NMIP4Config *a_copy;
 
 	if (_nm_ip4_config_intersect_helper ((NMIP4Config *) a, b,
+	                                     intersect_routes,
 	                                     default_route_metric_penalty, FALSE)) {
 		a_copy = nm_ip4_config_clone (a);
-		_nm_ip4_config_intersect_helper (a_copy, b, default_route_metric_penalty, TRUE);
+		_nm_ip4_config_intersect_helper (a_copy, b, intersect_routes,
+		                                 default_route_metric_penalty, TRUE);
 		return a_copy;
 	} else
 		return NULL;
@@ -1871,7 +1894,15 @@ nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relev
 		has_relevant_changes = TRUE;
 	}
 
-	dst_priv->mdns = src_priv->mdns;
+	if (src_priv->mdns != dst_priv->mdns) {
+		dst_priv->mdns = src_priv->mdns;
+		has_relevant_changes = TRUE;
+	}
+
+	if (src_priv->llmnr != dst_priv->llmnr) {
+		dst_priv->llmnr = src_priv->llmnr;
+		has_relevant_changes = TRUE;
+	}
 
 	/* DNS priority */
 	if (src_priv->dns_priority != dst_priv->dns_priority) {
@@ -1949,71 +1980,90 @@ nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relev
 }
 
 void
-nm_ip4_config_dump (const NMIP4Config *self, const char *detail)
+nm_ip_config_dump (const NMIPConfig *self,
+                   const char *detail,
+                   NMLogLevel level,
+                   NMLogDomain domain)
 {
-	guint32 tmp;
-	guint i;
-	const char *str;
 	NMDedupMultiIter ipconf_iter;
-	const NMPlatformIP4Address *address;
-	const NMPlatformIP4Route *route;
-
-	g_message ("--------- NMIP4Config %p (%s)", self, detail);
+	const NMPlatformIP4Address *addr4;
+	const NMPlatformIP6Address *addr6;
+	const NMPlatformIP4Route *route4;
+	const NMPlatformIP6Route *route6;
+	const NMIP4Config *ip4;
+	const NMIP6Config *ip6;
+	int addr_family = AF_UNSPEC;
+	char addr_family_char = '?';
+	const char *path;
+	gconstpointer ptr;
+	guint i;
 
-	if (self == NULL) {
-		g_message (" (null)");
-		return;
+	if (self) {
+		addr_family = nm_ip_config_get_addr_family (self);
+		addr_family_char = nm_utils_addr_family_to_char (addr_family);
 	}
 
-	str = nm_dbus_object_get_path (NM_DBUS_OBJECT (self));
-	if (str)
-		g_message ("   path: %s", str);
-
-	/* addresses */
-	nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, self, &address)
-		g_message ("      a: %s", nm_platform_ip4_address_to_string (address, NULL, 0));
-
-	/* nameservers */
-	for (i = 0; i < nm_ip4_config_get_num_nameservers (self); i++) {
-		tmp = nm_ip4_config_get_nameserver (self, i);
-		g_message ("     ns: %s", nm_utils_inet4_ntop (tmp, NULL));
-	}
+	nm_log (level, domain, NULL, NULL,
+	        "---- NMIP%cConfig %p (%s)",
+	        addr_family_char,
+	        self,
+	        detail);
 
-	/* routes */
-	nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, self, &route)
-		g_message ("     rt: %s", nm_platform_ip4_route_to_string (route, NULL, 0));
+	if (!self)
+		return;
 
-	/* domains */
-	for (i = 0; i < nm_ip4_config_get_num_domains (self); i++)
-		g_message (" domain: %s", nm_ip4_config_get_domain (self, i));
+	path = nm_dbus_object_get_path (NM_DBUS_OBJECT (self));
+	if (path)
+		nm_log (level, domain, NULL, NULL, " path     : %s", path);
 
-	/* dns searches */
-	for (i = 0; i < nm_ip4_config_get_num_searches (self); i++)
-		g_message (" search: %s", nm_ip4_config_get_search (self, i));
+	if (addr_family == AF_INET) {
+		ip4 = NM_IP4_CONFIG (self);
+		nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, ip4, &addr4) {
+			nm_log (level, domain, NULL, NULL, " address  : %s",
+			        nm_platform_ip4_address_to_string (addr4, NULL, 0));
+		}
+		nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, ip4, &route4) {
+			nm_log (level, domain, NULL, NULL, " route    : %s",
+			        nm_platform_ip4_route_to_string (route4, NULL, 0));
+		}
+	} else {
+		ip6 = NM_IP6_CONFIG (self);
+		nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, ip6, &addr6) {
+			nm_log (level, domain, NULL, NULL, " address  : %s",
+			        nm_platform_ip6_address_to_string (addr6, NULL, 0));
+		}
+		nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, ip6, &route6) {
+			nm_log (level, domain, NULL, NULL, " route    : %s",
+			        nm_platform_ip6_route_to_string (route6, NULL, 0));
+		}
+	}
 
-	/* dns options */
-	for (i = 0; i < nm_ip4_config_get_num_dns_options (self); i++)
-		g_message (" dnsopt: %s", nm_ip4_config_get_dns_option (self, i));
+	for (i = 0; i < nm_ip_config_get_num_nameservers (self); i++) {
+		ptr = nm_ip_config_get_nameserver (self, i);
+		nm_log (level, domain, NULL, NULL, " dns      : %s",
+		        nm_utils_inet_ntop (addr_family, ptr, NULL));
+	}
 
-	g_message (" dnspri: %d", nm_ip4_config_get_dns_priority (self));
+	for (i = 0; i < nm_ip_config_get_num_domains (self); i++)
+		nm_log (level, domain, NULL, NULL, " domain   : %s", nm_ip_config_get_domain (self, i));
 
-	g_message ("    mtu: %"G_GUINT32_FORMAT" (source: %d)", nm_ip4_config_get_mtu (self), (int) nm_ip4_config_get_mtu_source (self));
+	for (i = 0; i < nm_ip_config_get_num_searches (self); i++)
+		nm_log (level, domain, NULL, NULL, " search   : %s", nm_ip_config_get_search (self, i));
 
-	/* NIS */
-	for (i = 0; i < nm_ip4_config_get_num_nis_servers (self); i++) {
-		tmp = nm_ip4_config_get_nis_server (self, i);
-		g_message ("    nis: %s", nm_utils_inet4_ntop (tmp, NULL));
-	}
+	for (i = 0; i < nm_ip_config_get_num_dns_options (self); i++)
+		nm_log (level, domain, NULL, NULL, "dns-option: %s", nm_ip_config_get_dns_option (self, i));
 
-	g_message (" nisdmn: %s", nm_ip4_config_get_nis_domain (self) ?: "(none)");
+	nm_log (level, domain, NULL, NULL, " dns-prio : %d", nm_ip_config_get_dns_priority (self));
 
-	/* WINS */
-	for (i = 0; i < nm_ip4_config_get_num_wins (self); i++) {
-		tmp = nm_ip4_config_get_wins (self, i);
-		g_message ("   wins: %s", nm_utils_inet4_ntop (tmp, NULL));
+	if (addr_family == AF_INET) {
+		ip4 = NM_IP4_CONFIG (self);
+		nm_log (level, domain, NULL, NULL,
+		        " mtu      : %"G_GUINT32_FORMAT" (source: %d)",
+		        nm_ip4_config_get_mtu (ip4),
+		        (int) nm_ip4_config_get_mtu_source (ip4));
+		nm_log (level, domain, NULL, NULL, " metered  : %d",
+		        (int) nm_ip4_config_get_metered (ip4));
 	}
-
-	g_message (" mtrd:   %d", (int) nm_ip4_config_get_metered (self));
 }
 
 /*****************************************************************************/
@@ -2307,7 +2357,8 @@ nm_ip4_config_reset_nameservers (NMIP4Config *self)
 
 	if (priv->nameservers->len != 0) {
 		g_array_set_size (priv->nameservers, 0);
-		_notify (self, PROP_NAMESERVERS);
+		nm_gobject_notify_together (self, PROP_NAMESERVER_DATA,
+		                                  PROP_NAMESERVERS);
 	}
 }
 
@@ -2324,7 +2375,8 @@ nm_ip4_config_add_nameserver (NMIP4Config *self, guint32 new)
 			return;
 
 	g_array_append_val (priv->nameservers, new);
-	_notify (self, PROP_NAMESERVERS);
+	nm_gobject_notify_together (self, PROP_NAMESERVER_DATA,
+	                                  PROP_NAMESERVERS);
 }
 
 void
@@ -2335,7 +2387,8 @@ nm_ip4_config_del_nameserver (NMIP4Config *self, guint i)
 	g_return_if_fail (i < priv->nameservers->len);
 
 	g_array_remove_index (priv->nameservers, i);
-	_notify (self, PROP_NAMESERVERS);
+	nm_gobject_notify_together (self, PROP_NAMESERVER_DATA,
+	                                  PROP_NAMESERVERS);
 }
 
 guint
@@ -2557,10 +2610,23 @@ nm_ip4_config_mdns_set (NMIP4Config *self,
 	NM_IP4_CONFIG_GET_PRIVATE (self)->mdns = mdns;
 }
 
+NMSettingConnectionLlmnr
+nm_ip4_config_llmnr_get (const NMIP4Config *self)
+{
+	return NM_IP4_CONFIG_GET_PRIVATE (self)->llmnr;
+}
+
+void
+nm_ip4_config_llmnr_set (NMIP4Config *self,
+                         NMSettingConnectionLlmnr llmnr)
+{
+	NM_IP4_CONFIG_GET_PRIVATE (self)->llmnr = llmnr;
+}
+
 /*****************************************************************************/
 
 void
-nm_ip4_config_set_dns_priority (NMIP4Config *self, gint priority)
+nm_ip4_config_set_dns_priority (NMIP4Config *self, int priority)
 {
 	NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self);
 
@@ -2570,7 +2636,7 @@ nm_ip4_config_set_dns_priority (NMIP4Config *self, gint priority)
 	}
 }
 
-gint
+int
 nm_ip4_config_get_dns_priority (const NMIP4Config *self)
 {
 	const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self);
@@ -2653,7 +2719,8 @@ nm_ip4_config_reset_wins (NMIP4Config *self)
 
 	if (priv->wins->len != 0) {
 		g_array_set_size (priv->wins, 0);
-		_notify (self, PROP_WINS_SERVERS);
+		nm_gobject_notify_together (self, PROP_WINS_SERVER_DATA,
+		                                  PROP_WINS_SERVERS);
 	}
 }
 
@@ -2670,7 +2737,8 @@ nm_ip4_config_add_wins (NMIP4Config *self, guint32 wins)
 			return;
 
 	g_array_append_val (priv->wins, wins);
-	_notify (self, PROP_WINS_SERVERS);
+	nm_gobject_notify_together (self, PROP_WINS_SERVER_DATA,
+	                                  PROP_WINS_SERVERS);
 }
 
 void
@@ -2681,7 +2749,8 @@ nm_ip4_config_del_wins (NMIP4Config *self, guint i)
 	g_return_if_fail (i < priv->wins->len);
 
 	g_array_remove_index (priv->wins, i);
-	_notify (self, PROP_WINS_SERVERS);
+	nm_gobject_notify_together (self, PROP_WINS_SERVER_DATA,
+	                                  PROP_WINS_SERVERS);
 }
 
 guint
@@ -2843,6 +2912,7 @@ nm_ip4_config_hash (const NMIP4Config *self, GChecksum *sum, gboolean dns_only)
 	NMDedupMultiIter ipconf_iter;
 	const NMPlatformIP4Address *address;
 	const NMPlatformIP4Route *route;
+	int val;
 
 	g_return_if_fail (self);
 	g_return_if_fail (sum);
@@ -2889,6 +2959,25 @@ nm_ip4_config_hash (const NMIP4Config *self, GChecksum *sum, gboolean dns_only)
 		s = nm_ip4_config_get_dns_option (self, i);
 		g_checksum_update (sum, (const guint8 *) s, strlen (s));
 	}
+
+	val = nm_ip4_config_mdns_get (self);
+	if (val != NM_SETTING_CONNECTION_MDNS_DEFAULT)
+		g_checksum_update (sum, (const guint8 *) &val, sizeof (val));
+
+	val = nm_ip4_config_llmnr_get (self);
+	if (val != NM_SETTING_CONNECTION_LLMNR_DEFAULT)
+		g_checksum_update (sum, (const guint8 *) &val, sizeof (val));
+
+	/* FIXME(ip-config-checksum): the DNS priority should be considered relevant
+	 * and added into the checksum as well, but this can't be done right now
+	 * because in the DNS manager we rely on the fact that an empty
+	 * configuration (i.e. just created) has a zero checksum. This is needed to
+	 * avoid rewriting resolv.conf when there is no change.
+	 *
+	 * The DNS priority initial value depends on the connection type (VPN or
+	 * not), so it's a bit difficult to add it to checksum maintaining the
+	 * assumption of checksum(empty)=0
+	 */
 }
 
 /**
@@ -2944,6 +3033,7 @@ get_property (GObject *object, guint prop_id,
 	NMDedupMultiIter ipconf_iter;
 	const NMPlatformIP4Route *route;
 	GVariantBuilder builder_data, builder_legacy;
+	guint i;
 
 	switch (prop_id) {
 	case PROP_IFINDEX:
@@ -2962,7 +3052,7 @@ get_property (GObject *object, guint prop_id,
 		head_entry = nm_ip4_config_lookup_addresses (self);
 		if (head_entry) {
 			gs_free const NMPObject **addresses = NULL;
-			guint naddr, i;
+			guint naddr;
 
 			addresses = (const NMPObject **) nm_dedup_multi_objs_to_array_head (head_entry, NULL, NULL, &naddr);
 			nm_assert (addresses && naddr);
@@ -3098,6 +3188,26 @@ out_routes_cached:
 		} else
 			g_value_set_string (value, NULL);
 		break;
+	case PROP_NAMESERVER_DATA:
+		g_variant_builder_init (&builder_data, G_VARIANT_TYPE ("aa{sv}"));
+
+		for (i = 0; i < priv->nameservers->len; i++) {
+			GVariantBuilder nested_builder;
+			char addr_str[NM_UTILS_INET_ADDRSTRLEN];
+
+			nm_utils_inet4_ntop (g_array_index (priv->nameservers, in_addr_t, i),
+			                     addr_str);
+
+			g_variant_builder_init (&nested_builder, G_VARIANT_TYPE ("a{sv}"));
+			g_variant_builder_add (&nested_builder, "{sv}",
+			                       "address",
+			                       g_variant_new_string (addr_str));
+			g_variant_builder_add (&builder_data, "a{sv}", &nested_builder);
+		}
+
+		g_value_take_variant (value,
+		                      g_variant_builder_end (&builder_data));
+		break;
 	case PROP_NAMESERVERS:
 		g_value_take_variant (value,
 		                      g_variant_new_fixed_array (G_VARIANT_TYPE_UINT32,
@@ -3117,6 +3227,19 @@ out_routes_cached:
 	case PROP_DNS_PRIORITY:
 		g_value_set_int (value, priv->dns_priority);
 		break;
+	case PROP_WINS_SERVER_DATA:
+		g_variant_builder_init (&builder_data, G_VARIANT_TYPE ("as"));
+		for (i = 0; i < priv->wins->len; i++) {
+			char addr_str[NM_UTILS_INET_ADDRSTRLEN];
+
+			g_variant_builder_add (&builder_data,
+			                       "s",
+			                       nm_utils_inet4_ntop (g_array_index (priv->wins, in_addr_t, i),
+			                                            addr_str));
+		}
+		g_value_take_variant (value,
+		                      g_variant_builder_end (&builder_data));
+		break;
 	case PROP_WINS_SERVERS:
 		g_value_take_variant (value,
 		                      g_variant_new_fixed_array (G_VARIANT_TYPE_UINT32,
@@ -3170,6 +3293,7 @@ nm_ip4_config_init (NMIP4Config *self)
 	                                        NMP_OBJECT_TYPE_IP4_ROUTE);
 
 	priv->mdns = NM_SETTING_CONNECTION_MDNS_DEFAULT;
+	priv->llmnr = NM_SETTING_CONNECTION_LLMNR_DEFAULT;
 	priv->nameservers = g_array_new (FALSE, FALSE, sizeof (guint32));
 	priv->domains = g_ptr_array_new_with_free_func (g_free);
 	priv->searches = g_ptr_array_new_with_free_func (g_free);
@@ -3224,17 +3348,19 @@ static const NMDBusInterfaceInfoExtended interface_info_ip4_config = {
 			&nm_signal_info_property_changed_legacy,
 		),
 		.properties = NM_DEFINE_GDBUS_PROPERTY_INFOS (
-			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Addresses",   "aau",    NM_IP4_CONFIG_ADDRESSES),
-			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("AddressData", "aa{sv}", NM_IP4_CONFIG_ADDRESS_DATA),
-			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Gateway",     "s",      NM_IP4_CONFIG_GATEWAY),
-			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Routes",      "aau",    NM_IP4_CONFIG_ROUTES),
-			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("RouteData",   "aa{sv}", NM_IP4_CONFIG_ROUTE_DATA),
-			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Nameservers", "au",     NM_IP4_CONFIG_NAMESERVERS),
-			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Domains",     "as",     NM_IP4_CONFIG_DOMAINS),
-			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Searches",    "as",     NM_IP4_CONFIG_SEARCHES),
-			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("DnsOptions",  "as",     NM_IP4_CONFIG_DNS_OPTIONS),
-			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("DnsPriority", "i",      NM_IP4_CONFIG_DNS_PRIORITY),
-			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("WinsServers", "au",     NM_IP4_CONFIG_WINS_SERVERS),
+			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Addresses",      "aau",    NM_IP4_CONFIG_ADDRESSES),
+			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("AddressData",    "aa{sv}", NM_IP4_CONFIG_ADDRESS_DATA),
+			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Gateway",        "s",      NM_IP4_CONFIG_GATEWAY),
+			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Routes",         "aau",    NM_IP4_CONFIG_ROUTES),
+			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("RouteData",      "aa{sv}", NM_IP4_CONFIG_ROUTE_DATA),
+			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE   ("NameserverData", "aa{sv}", NM_IP4_CONFIG_NAMESERVER_DATA),
+			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Nameservers",    "au",     NM_IP4_CONFIG_NAMESERVERS),
+			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Domains",        "as",     NM_IP4_CONFIG_DOMAINS),
+			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Searches",       "as",     NM_IP4_CONFIG_SEARCHES),
+			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("DnsOptions",     "as",     NM_IP4_CONFIG_DNS_OPTIONS),
+			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("DnsPriority",    "i",      NM_IP4_CONFIG_DNS_PRIORITY),
+			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE   ("WinsServerData", "as",     NM_IP4_CONFIG_WINS_SERVER_DATA),
+			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("WinsServers",    "au",     NM_IP4_CONFIG_WINS_SERVERS),
 		),
 	),
 	.legacy_property_changed = TRUE,
@@ -3293,6 +3419,12 @@ nm_ip4_config_class_init (NMIP4ConfigClass *config_class)
 	                         NULL,
 	                         G_PARAM_READABLE |
 	                         G_PARAM_STATIC_STRINGS);
+	obj_properties[PROP_NAMESERVER_DATA] =
+	    g_param_spec_variant (NM_IP4_CONFIG_NAMESERVER_DATA, "", "",
+	                          G_VARIANT_TYPE ("aa{sv}"),
+	                          NULL,
+	                          G_PARAM_READABLE |
+	                          G_PARAM_STATIC_STRINGS);
 	obj_properties[PROP_NAMESERVERS] =
 	    g_param_spec_variant (NM_IP4_CONFIG_NAMESERVERS, "", "",
 	                          G_VARIANT_TYPE ("au"),
@@ -3319,6 +3451,12 @@ nm_ip4_config_class_init (NMIP4ConfigClass *config_class)
 	                       G_MININT32, G_MAXINT32, 0,
 	                       G_PARAM_READABLE |
 	                       G_PARAM_STATIC_STRINGS);
+	obj_properties[PROP_WINS_SERVER_DATA] =
+	    g_param_spec_variant (NM_IP4_CONFIG_WINS_SERVER_DATA, "", "",
+	                          G_VARIANT_TYPE ("as"),
+	                          NULL,
+	                          G_PARAM_READABLE |
+	                          G_PARAM_STATIC_STRINGS);
 	obj_properties[PROP_WINS_SERVERS] =
 	    g_param_spec_variant (NM_IP4_CONFIG_WINS_SERVERS, "", "",
 	                          G_VARIANT_TYPE ("au"),