dns: add support for global configuration in DNS manager

Modify the DNS manager to use the static global DNS configuration when
available. In addition, change DNS plugins interface to accept a new
argument for global configuration and add support for this new
parameter to the dnsmasq plugin.
This commit is contained in:
Beniamino Galvani
2015-06-15 09:03:53 +02:00
parent 55c204b9a3
commit ae9e82354a
7 changed files with 168 additions and 51 deletions

View File

@@ -135,6 +135,30 @@ ip6_addr_to_string (const struct in6_addr *addr, const char *iface)
return buf;
}
static void
add_global_config (GString *str, const NMGlobalDnsConfig *config)
{
guint i, j;
g_return_if_fail (config);
for (i = 0; i < nm_global_dns_config_get_num_domains (config); i++) {
NMGlobalDnsDomain *domain = nm_global_dns_config_get_domain (config, i);
const char *const *servers = nm_global_dns_domain_get_servers (domain);
for (j = 0; servers && servers[j]; j++) {
if (!strcmp (servers[j], "*"))
g_string_append_printf (str, "server=%s\n", servers[j]);
else {
g_string_append_printf (str, "server=/%s/%s\n",
nm_global_dns_domain_get_name (domain),
servers[j]);
}
}
}
}
static gboolean
add_ip6_config (GString *str, NMIP6Config *ip6, gboolean split)
{
@@ -201,6 +225,7 @@ update (NMDnsPlugin *plugin,
const GSList *vpn_configs,
const GSList *dev_configs,
const GSList *other_configs,
const NMGlobalDnsConfig *global_config,
const char *hostname)
{
NMDnsDnsmasq *self = NM_DNS_DNSMASQ (plugin);
@@ -229,6 +254,9 @@ update (NMDnsPlugin *plugin,
/* Build up the new dnsmasq config file */
conf = g_string_sized_new (150);
if (global_config)
add_global_config (conf, global_config);
else {
/* Use split DNS for VPN configs */
for (iter = (GSList *) vpn_configs; iter; iter = g_slist_next (iter)) {
if (NM_IS_IP4_CONFIG (iter->data))
@@ -252,6 +280,7 @@ update (NMDnsPlugin *plugin,
else if (NM_IS_IP6_CONFIG (iter->data))
add_ip6_config (conf, NM_IP6_CONFIG (iter->data), FALSE);
}
}
/* Write out the config file */
if (!g_file_set_contents (CONFFILE, conf->str, -1, &error)) {

View File

@@ -667,7 +667,7 @@ update_resolv_conf (NMDnsManager *self,
}
static void
compute_hash (NMDnsManager *self, guint8 buffer[HASH_LEN])
compute_hash (NMDnsManager *self, const NMGlobalDnsConfig *global, guint8 buffer[HASH_LEN])
{
NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self);
GChecksum *sum;
@@ -677,6 +677,9 @@ compute_hash (NMDnsManager *self, guint8 buffer[HASH_LEN])
sum = g_checksum_new (G_CHECKSUM_SHA1);
g_assert (len == g_checksum_type_get_length (G_CHECKSUM_SHA1));
if (global)
nm_global_dns_config_update_checksum (global, sum);
if (priv->ip4_vpn_config)
nm_ip4_config_hash (priv->ip4_vpn_config, sum, TRUE);
if (priv->ip4_device_config)
@@ -741,6 +744,38 @@ build_plugin_config_lists (NMDnsManager *self,
}
}
static gboolean
merge_global_dns_config (NMResolvConfData *rc, NMGlobalDnsConfig *global_conf)
{
NMGlobalDnsDomain *default_domain;
const char *const *searches;
const char *const *options;
const char *const *servers;
gint i;
if (!global_conf)
return FALSE;
searches = nm_global_dns_config_get_searches (global_conf);
options = nm_global_dns_config_get_options (global_conf);
for (i = 0; searches && searches[i]; i++) {
if (DOMAIN_IS_VALID (searches[i]))
add_string_item (rc->searches, searches[i]);
}
for (i = 0; options && options[i]; i++)
add_string_item (rc->options, options[i]);
default_domain = nm_global_dns_config_lookup_domain (global_conf, "*");
g_assert (default_domain);
servers = nm_global_dns_domain_get_servers (default_domain);
for (i = 0; servers && servers[i]; i++)
add_string_item (rc->nameservers, servers[i]);
return TRUE;
}
static gboolean
update_dns (NMDnsManager *self,
gboolean no_caching,
@@ -758,6 +793,8 @@ update_dns (NMDnsManager *self,
gboolean caching = FALSE, update = TRUE;
gboolean resolv_conf_updated = FALSE;
SpawnResult result = SR_ERROR;
NMConfigData *data;
NMGlobalDnsConfig *global_config;
g_return_val_if_fail (!error || !*error, FALSE);
@@ -771,8 +808,11 @@ update_dns (NMDnsManager *self,
_LOGD ("update-dns: updating resolv.conf");
}
data = nm_config_get_data (priv->config);
global_config = nm_config_data_get_global_dns_config (data);
/* Update hash with config we're applying */
compute_hash (self, priv->hash);
compute_hash (self, global_config, priv->hash);
rc.nameservers = g_ptr_array_new ();
rc.searches = g_ptr_array_new ();
@@ -780,6 +820,9 @@ update_dns (NMDnsManager *self,
rc.nis_domain = NULL;
rc.nis_servers = g_ptr_array_new ();
if (global_config)
merge_global_dns_config (&rc, global_config);
else {
if (priv->ip4_vpn_config)
merge_one_ip4_config (&rc, priv->ip4_vpn_config);
if (priv->ip4_device_config)
@@ -808,6 +851,7 @@ update_dns (NMDnsManager *self,
} else
g_assert_not_reached ();
}
}
/* If the hostname is a FQDN ("dcbw.example.com"), then add the domain part of it
* ("example.com") to the searches list, to ensure that we can still resolve its
@@ -879,6 +923,7 @@ update_dns (NMDnsManager *self,
caching = TRUE;
}
if (!global_config)
build_plugin_config_lists (self, &vpn_configs, &dev_configs, &other_configs);
_LOGD ("update-dns: updating plugin %s", plugin_name);
@@ -886,6 +931,7 @@ update_dns (NMDnsManager *self,
vpn_configs,
dev_configs,
other_configs,
global_config,
priv->hostname)) {
_LOGW ("update-dns: plugin %s update failed", plugin_name);
@@ -1212,7 +1258,7 @@ nm_dns_manager_end_updates (NMDnsManager *self, const char *func)
priv = NM_DNS_MANAGER_GET_PRIVATE (self);
g_return_if_fail (priv->updates_queue > 0);
compute_hash (self, new);
compute_hash (self, nm_config_data_get_global_dns_config (nm_config_get_data (priv->config)), new);
changed = (memcmp (new, priv->prev_hash, sizeof (new)) != 0) ? TRUE : FALSE;
_LOGD ("(%s): DNS configuration %s", func, changed ? "changed" : "did not change");
@@ -1346,7 +1392,8 @@ config_changed_cb (NMConfig *config,
if (NM_FLAGS_ANY (changes, NM_CONFIG_CHANGE_SIGHUP |
NM_CONFIG_CHANGE_SIGUSR1 |
NM_CONFIG_CHANGE_DNS_MODE |
NM_CONFIG_CHANGE_RC_MANAGER)) {
NM_CONFIG_CHANGE_RC_MANAGER |
NM_CONFIG_CHANGE_GLOBAL_DNS_CONFIG)) {
if (!update_dns (self, TRUE, &error)) {
_LOGW ("could not commit DNS changes: %s", error->message);
g_clear_error (&error);
@@ -1361,10 +1408,11 @@ nm_dns_manager_init (NMDnsManager *self)
_LOGt ("creating...");
/* Set the initial hash */
compute_hash (self, NM_DNS_MANAGER_GET_PRIVATE (self)->hash);
priv->config = g_object_ref (nm_config_get ());
/* Set the initial hash */
compute_hash (self, nm_config_data_get_global_dns_config (nm_config_get_data (priv->config)),
NM_DNS_MANAGER_GET_PRIVATE (self)->hash);
g_signal_connect (G_OBJECT (priv->config),
NM_CONFIG_SIGNAL_CONFIG_CHANGED,
G_CALLBACK (config_changed_cb),

View File

@@ -56,6 +56,7 @@ nm_dns_plugin_update (NMDnsPlugin *self,
const GSList *vpn_configs,
const GSList *dev_configs,
const GSList *other_configs,
const NMGlobalDnsConfig *global_config,
const char *hostname)
{
g_return_val_if_fail (NM_DNS_PLUGIN_GET_CLASS (self)->update != NULL, FALSE);
@@ -64,6 +65,7 @@ nm_dns_plugin_update (NMDnsPlugin *self,
vpn_configs,
dev_configs,
other_configs,
global_config,
hostname);
}

View File

@@ -21,6 +21,8 @@
#include "nm-default.h"
#include "nm-config-data.h"
#define NM_TYPE_DNS_PLUGIN (nm_dns_plugin_get_type ())
#define NM_DNS_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DNS_PLUGIN, NMDnsPlugin))
#define NM_DNS_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DNS_PLUGIN, NMDnsPluginClass))
@@ -46,13 +48,15 @@ typedef struct {
* NMIP4Config or NMIP6Config objects from VPN connections, while
* 'dev_configs' is a list of NMPI4Config or NMIP6Config objects from
* active devices. 'other_configs' represent other IP configuration that
* may be in-use. Configs of the same IP version are sorted in priority
* may be in-use. 'global_config' is the optional global DNS
* configuration. Configs of the same IP version are sorted in priority
* order.
*/
gboolean (*update) (NMDnsPlugin *self,
const GSList *vpn_configs,
const GSList *dev_configs,
const GSList *other_configs,
const NMGlobalDnsConfig *global_config,
const char *hostname);
/* Subclasses should override and return TRUE if they start a local
@@ -91,6 +95,7 @@ gboolean nm_dns_plugin_update (NMDnsPlugin *self,
const GSList *vpn_configs,
const GSList *dev_configs,
const GSList *other_configs,
const NMGlobalDnsConfig *global_config,
const char *hostname);
/* For subclasses/plugins */

View File

@@ -31,6 +31,7 @@ update (NMDnsPlugin *plugin,
const GSList *vpn_configs,
const GSList *dev_configs,
const GSList *other_configs,
const NMGlobalDnsConfig *global_config,
const char *hostname)
{
/* TODO: We currently call a script installed with the dnssec-trigger

View File

@@ -640,6 +640,37 @@ nm_global_dns_config_is_empty (const NMGlobalDnsConfig *dns)
&& g_hash_table_size (dns->domains) == 0;
}
void
nm_global_dns_config_update_checksum (const NMGlobalDnsConfig *dns, GChecksum *sum)
{
NMGlobalDnsDomain *domain;
GList *keys, *key;
guint i;
g_return_if_fail (dns);
g_return_if_fail (dns->domains);
g_return_if_fail (sum);
for (i = 0; dns->searches && dns->searches[i]; i++)
g_checksum_update (sum, (guchar *) dns->searches[i], strlen (dns->searches[i]));
for (i = 0; dns->options && dns->options[i]; i++)
g_checksum_update (sum, (guchar *) dns->options[i], strlen (dns->options[i]));
keys = g_list_sort (g_hash_table_get_keys (dns->domains), (GCompareFunc) strcmp);
for (key = keys; key; key = g_list_next (key)) {
domain = g_hash_table_lookup (dns->domains, key->data);
g_assert_nonnull (domain);
g_checksum_update (sum, (guchar *) domain->name, strlen (domain->name));
for (i = 0; domain->servers && domain->servers[i]; i++)
g_checksum_update (sum, (guchar *) domain->servers[i], strlen (domain->servers[i]));
for (i = 0; domain->options && domain->options[i]; i++)
g_checksum_update (sum, (guchar *) domain->options[i], strlen (domain->options[i]));
}
g_list_free (keys);
}
static void
global_dns_domain_free (NMGlobalDnsDomain *domain)
{

View File

@@ -150,6 +150,7 @@ const char *const *nm_global_dns_domain_get_servers (const NMGlobalDnsDomain *do
const char *const *nm_global_dns_domain_get_options (const NMGlobalDnsDomain *domain);
gboolean nm_global_dns_config_is_internal (const NMGlobalDnsConfig *dns);
gboolean nm_global_dns_config_is_empty (const NMGlobalDnsConfig *dns);
void nm_global_dns_config_update_checksum (const NMGlobalDnsConfig *dns, GChecksum *sum);
void nm_global_dns_config_free (NMGlobalDnsConfig *conf);
/* private accessors */