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,28 +254,32 @@ update (NMDnsPlugin *plugin,
/* Build up the new dnsmasq config file */
conf = g_string_sized_new (150);
/* Use split DNS for VPN configs */
for (iter = (GSList *) vpn_configs; iter; iter = g_slist_next (iter)) {
if (NM_IS_IP4_CONFIG (iter->data))
add_ip4_config (conf, NM_IP4_CONFIG (iter->data), TRUE);
else if (NM_IS_IP6_CONFIG (iter->data))
add_ip6_config (conf, NM_IP6_CONFIG (iter->data), TRUE);
}
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))
add_ip4_config (conf, NM_IP4_CONFIG (iter->data), TRUE);
else if (NM_IS_IP6_CONFIG (iter->data))
add_ip6_config (conf, NM_IP6_CONFIG (iter->data), TRUE);
}
/* Now add interface configs without split DNS */
for (iter = (GSList *) dev_configs; iter; iter = g_slist_next (iter)) {
if (NM_IS_IP4_CONFIG (iter->data))
add_ip4_config (conf, NM_IP4_CONFIG (iter->data), FALSE);
else if (NM_IS_IP6_CONFIG (iter->data))
add_ip6_config (conf, NM_IP6_CONFIG (iter->data), FALSE);
}
/* Now add interface configs without split DNS */
for (iter = (GSList *) dev_configs; iter; iter = g_slist_next (iter)) {
if (NM_IS_IP4_CONFIG (iter->data))
add_ip4_config (conf, NM_IP4_CONFIG (iter->data), FALSE);
else if (NM_IS_IP6_CONFIG (iter->data))
add_ip6_config (conf, NM_IP6_CONFIG (iter->data), FALSE);
}
/* And any other random configs */
for (iter = (GSList *) other_configs; iter; iter = g_slist_next (iter)) {
if (NM_IS_IP4_CONFIG (iter->data))
add_ip4_config (conf, NM_IP4_CONFIG (iter->data), FALSE);
else if (NM_IS_IP6_CONFIG (iter->data))
add_ip6_config (conf, NM_IP6_CONFIG (iter->data), FALSE);
/* And any other random configs */
for (iter = (GSList *) other_configs; iter; iter = g_slist_next (iter)) {
if (NM_IS_IP4_CONFIG (iter->data))
add_ip4_config (conf, NM_IP4_CONFIG (iter->data), FALSE);
else if (NM_IS_IP6_CONFIG (iter->data))
add_ip6_config (conf, NM_IP6_CONFIG (iter->data), FALSE);
}
}
/* Write out the config file */

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,33 +820,37 @@ update_dns (NMDnsManager *self,
rc.nis_domain = NULL;
rc.nis_servers = g_ptr_array_new ();
if (priv->ip4_vpn_config)
merge_one_ip4_config (&rc, priv->ip4_vpn_config);
if (priv->ip4_device_config)
merge_one_ip4_config (&rc, priv->ip4_device_config);
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)
merge_one_ip4_config (&rc, priv->ip4_device_config);
if (priv->ip6_vpn_config)
merge_one_ip6_config (&rc, priv->ip6_vpn_config);
if (priv->ip6_device_config)
merge_one_ip6_config (&rc, priv->ip6_device_config);
if (priv->ip6_vpn_config)
merge_one_ip6_config (&rc, priv->ip6_vpn_config);
if (priv->ip6_device_config)
merge_one_ip6_config (&rc, priv->ip6_device_config);
for (iter = priv->configs; iter; iter = g_slist_next (iter)) {
if ( (iter->data == priv->ip4_vpn_config)
|| (iter->data == priv->ip4_device_config)
|| (iter->data == priv->ip6_vpn_config)
|| (iter->data == priv->ip6_device_config))
continue;
for (iter = priv->configs; iter; iter = g_slist_next (iter)) {
if ( (iter->data == priv->ip4_vpn_config)
|| (iter->data == priv->ip4_device_config)
|| (iter->data == priv->ip6_vpn_config)
|| (iter->data == priv->ip6_device_config))
continue;
if (NM_IS_IP4_CONFIG (iter->data)) {
NMIP4Config *config = NM_IP4_CONFIG (iter->data);
if (NM_IS_IP4_CONFIG (iter->data)) {
NMIP4Config *config = NM_IP4_CONFIG (iter->data);
merge_one_ip4_config (&rc, config);
} else if (NM_IS_IP6_CONFIG (iter->data)) {
NMIP6Config *config = NM_IP6_CONFIG (iter->data);
merge_one_ip4_config (&rc, config);
} else if (NM_IS_IP6_CONFIG (iter->data)) {
NMIP6Config *config = NM_IP6_CONFIG (iter->data);
merge_one_ip6_config (&rc, config);
} else
g_assert_not_reached ();
merge_one_ip6_config (&rc, config);
} else
g_assert_not_reached ();
}
}
/* If the hostname is a FQDN ("dcbw.example.com"), then add the domain part of it
@ -879,13 +923,15 @@ update_dns (NMDnsManager *self,
caching = TRUE;
}
build_plugin_config_lists (self, &vpn_configs, &dev_configs, &other_configs);
if (!global_config)
build_plugin_config_lists (self, &vpn_configs, &dev_configs, &other_configs);
_LOGD ("update-dns: updating plugin %s", plugin_name);
if (!nm_dns_plugin_update (plugin,
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 */