Commit e3c67177 authored by Beniamino Galvani's avatar Beniamino Galvani

dns: export current configuration through D-Bus

It is useful to let clients retrieve the current DNS configuration,
which can be displayed to users or used (together with dns=none) to
implement custom DNS configuration logic through external tools.
parent 14105ece
......@@ -22,5 +22,18 @@
-->
<property name="RcManager" type="s" access="read"/>
<!--
Configuration:
The current DNS configuration represented as an array of
dictionaries. Each dictionary has the "nameservers",
"priority" keys and, optionally, "interface" and "vpn".
"nameservers" is the list of DNS servers, "priority" their
relative priority, "interface" the interface on which these
servers are contacted, "vpn" a boolean telling whether the
configuration was obtained from a VPN connection.
-->
<property name="Configuration" type="aa{sv}" access="read"/>
</interface>
</node>
......@@ -42,6 +42,8 @@
#include "nm-ip6-config.h"
#include "NetworkManagerUtils.h"
#include "nm-config.h"
#include "devices/nm-device.h"
#include "nm-manager.h"
#include "nm-dns-plugin.h"
#include "nm-dns-dnsmasq.h"
......@@ -87,6 +89,7 @@ enum {
NM_GOBJECT_PROPERTIES_DEFINE (NMDnsManager,
PROP_MODE,
PROP_RC_MANAGER,
PROP_CONFIGURATION,
);
static guint signals[LAST_SIGNAL] = { 0 };
......@@ -123,6 +126,7 @@ typedef enum {
typedef struct {
GPtrArray *configs;
GVariant *config_variant;
NMDnsIPConfigData *best_conf4, *best_conf6;
gboolean need_sort;
......@@ -1204,6 +1208,9 @@ update_dns (NMDnsManager *self,
if (update && result == SR_SUCCESS)
g_signal_emit (self, signals[CONFIG_CHANGED], 0);
g_clear_pointer (&priv->config_variant, g_variant_unref);
_notify (self, PROP_CONFIGURATION);
if (searches)
g_strfreev (searches);
if (options)
......@@ -1773,6 +1780,198 @@ config_changed_cb (NMConfig *config,
}
}
static GVariant *
_get_global_config_variant (NMGlobalDnsConfig *global)
{
NMGlobalDnsDomain *domain;
GVariantBuilder builder;
guint i, num;
g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}"));
num = nm_global_dns_config_get_num_domains (global);
for (i = 0; i < num; i++) {
GVariantBuilder conf_builder;
GVariantBuilder item_builder;
const char *domain_name;
const char * const *servers;
g_variant_builder_init (&conf_builder, G_VARIANT_TYPE ("a{sv}"));
domain = nm_global_dns_config_get_domain (global, i);
domain_name = nm_global_dns_domain_get_name (domain);
if (domain_name && !nm_streq0 (domain_name, "*")) {
g_variant_builder_init (&item_builder, G_VARIANT_TYPE ("as"));
g_variant_builder_add (&item_builder,
"s",
domain_name);
g_variant_builder_add (&conf_builder,
"{sv}",
"domains",
g_variant_builder_end (&item_builder));
}
g_variant_builder_init (&item_builder, G_VARIANT_TYPE ("as"));
for (servers = nm_global_dns_domain_get_servers (domain); *servers; servers++) {
g_variant_builder_add (&item_builder,
"s",
*servers);
}
g_variant_builder_add (&conf_builder,
"{sv}",
"nameservers",
g_variant_builder_end (&item_builder));
g_variant_builder_add (&conf_builder,
"{sv}",
"priority",
g_variant_new_int32 (NM_DNS_PRIORITY_DEFAULT_NORMAL));
g_variant_builder_add (&builder, "a{sv}", &conf_builder);
}
return g_variant_ref_sink (g_variant_builder_end (&builder));
}
static GVariant *
_get_config_variant (NMDnsManager *self)
{
NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self);
NMGlobalDnsConfig *global_config;
GVariantBuilder builder;
NMConfigData *data;
guint i, j;
if (priv->config_variant)
return priv->config_variant;
data = nm_config_get_data (priv->config);
global_config = nm_config_data_get_global_dns_config (data);
if (global_config) {
priv->config_variant = _get_global_config_variant (global_config);
_LOGT ("current configuration: %s", g_variant_print (priv->config_variant, TRUE));
return priv->config_variant;
}
g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}"));
for (i = 0; i < priv->configs->len; i++) {
NMDnsIPConfigData *current = priv->configs->pdata[i];
GVariantBuilder entry_builder;
GVariantBuilder strv_builder;
gboolean v4 = NM_IS_IP4_CONFIG (current->config);
gint priority;
g_variant_builder_init (&entry_builder, G_VARIANT_TYPE ("a{sv}"));
g_variant_builder_init (&strv_builder, G_VARIANT_TYPE ("as"));
if (v4) {
NMIP4Config *config = NM_IP4_CONFIG (current->config);
guint num = nm_ip4_config_get_num_nameservers (config);
guint32 ns;
if (!num)
continue;
/* Add nameservers */
for (j = 0; j < num; j++) {
ns = nm_ip4_config_get_nameserver (config, j);
g_variant_builder_add (&strv_builder,
"s",
nm_utils_inet4_ntop (ns, NULL));
}
g_variant_builder_add (&entry_builder,
"{sv}",
"nameservers",
g_variant_builder_end (&strv_builder));
/* Add domains */
g_variant_builder_init (&strv_builder, G_VARIANT_TYPE ("as"));
num = nm_ip4_config_get_num_domains (config);
for (j = 0; j < num; j++) {
g_variant_builder_add (&strv_builder,
"s",
nm_ip4_config_get_domain (config, j));
}
if (num) {
g_variant_builder_add (&entry_builder,
"{sv}",
"domains",
g_variant_builder_end (&strv_builder));
}
priority = nm_ip4_config_get_dns_priority (config);
} else {
NMIP6Config *config = NM_IP6_CONFIG (current->config);
guint num = nm_ip6_config_get_num_nameservers (config);
const struct in6_addr *ns;
if (!num)
continue;
/* Add nameservers */
for (j = 0; j < num; j++) {
ns = nm_ip6_config_get_nameserver (config, j);
g_variant_builder_add (&strv_builder,
"s",
nm_utils_inet6_ntop (ns, NULL));
}
g_variant_builder_add (&entry_builder,
"{sv}",
"nameservers",
g_variant_builder_end (&strv_builder));
/* Add domains */
g_variant_builder_init (&strv_builder, G_VARIANT_TYPE ("as"));
num = nm_ip6_config_get_num_domains (config);
for (j = 0; j < num; j++) {
g_variant_builder_add (&strv_builder,
"s",
nm_ip6_config_get_domain (config, j));
}
if (num) {
g_variant_builder_add (&entry_builder,
"{sv}",
"domains",
g_variant_builder_end (&strv_builder));
}
priority = nm_ip6_config_get_dns_priority (config);
}
/* Add device */
if (current->iface) {
g_variant_builder_add (&entry_builder,
"{sv}",
"interface",
g_variant_new_string (current->iface));
}
/* Add priority */
g_variant_builder_add (&entry_builder,
"{sv}",
"priority",
g_variant_new_int32 (priority));
/* Add VPN */
g_variant_builder_add (&entry_builder,
"{sv}",
"vpn",
g_variant_new_boolean (current->type == NM_DNS_IP_CONFIG_TYPE_VPN));
g_variant_builder_add (&builder, "a{sv}", &entry_builder);
}
priv->config_variant = g_variant_ref_sink (g_variant_builder_end (&builder));
_LOGT ("current configuration: %s", g_variant_print (priv->config_variant, TRUE));
return priv->config_variant;
}
static void
get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
......@@ -1787,6 +1986,9 @@ get_property (GObject *object, guint prop_id,
case PROP_RC_MANAGER:
g_value_set_string (value, _rc_manager_to_string (priv->rc_manager));
break;
case PROP_CONFIGURATION:
g_value_set_variant (value, _get_config_variant (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
......@@ -1893,6 +2095,13 @@ nm_dns_manager_class_init (NMDnsManagerClass *klass)
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS);
obj_properties[PROP_CONFIGURATION] =
g_param_spec_variant (NM_DNS_MANAGER_CONFIGURATION, "", "",
G_VARIANT_TYPE ("aa{sv}"),
NULL,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
signals[CONFIG_CHANGED] =
......
......@@ -54,6 +54,7 @@ typedef struct {
/* properties */
#define NM_DNS_MANAGER_MODE "mode"
#define NM_DNS_MANAGER_RC_MANAGER "rc-manager"
#define NM_DNS_MANAGER_CONFIGURATION "configuration"
/* internal signals */
#define NM_DNS_MANAGER_CONFIG_CHANGED "config-changed"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment