Commit 1e89b9f1 authored by Ismo Puustinen's avatar Ismo Puustinen Committed by Beniamino Galvani
Browse files

dns: add mechanism for propagating mDNS setting.

Update nm-policy.c and nm-dns-manager.c so that the connection-specific
settings get propagated to DNS manger. Currently the only such value is
the mDNS status.

Add update_mdns() function to DNS plugin interface. If a DNS plugin
supports mDNS, it can set an interface with a given index to support
mDNS resolving or also register the current hostname.

The mDNS support is currently added only to systemd-resolved DNS plugin.

(cherry picked from commit 25906eda)
parent 19d7e660
......@@ -103,7 +103,8 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMDnsManager,
static guint signals[LAST_SIGNAL] = { 0 };
typedef struct {
GPtrArray *configs;
GPtrArray *ip_configs;
GPtrArray *connection_configs;
GVariant *config_variant;
NMDnsIPConfigData *best_conf4, *best_conf6;
......@@ -214,6 +215,19 @@ ip_config_data_new (gpointer config, NMDnsIPConfigType type, const char *iface)
return data;
}
static NMDnsConnectionConfigData *
connection_config_data_new (NMSettingConnectionMdns mdns, const char *iface, int ifindex)
{
NMDnsConnectionConfigData *data;
data = g_slice_new0 (NMDnsConnectionConfigData);
data->mdns = mdns;
data->iface = g_strdup (iface);
data->ifindex = ifindex;
return data;
}
static void
ip_config_data_destroy (gpointer ptr)
{
......@@ -227,6 +241,18 @@ ip_config_data_destroy (gpointer ptr)
g_slice_free (NMDnsIPConfigData, data);
}
static void
connection_config_data_destroy (gpointer ptr)
{
NMDnsConnectionConfigData *data = ptr;
if (!data)
return;
g_free (data->iface);
g_slice_free (NMDnsConnectionConfigData, data);
}
static gint
ip_config_data_compare (const NMDnsIPConfigData *a, const NMDnsIPConfigData *b)
{
......@@ -832,8 +858,8 @@ compute_hash (NMDnsManager *self, const NMGlobalDnsConfig *global, guint8 buffer
if (global)
nm_global_dns_config_update_checksum (global, sum);
else {
for (i = 0; i < priv->configs->len; i++) {
NMDnsIPConfigData *data = priv->configs->pdata[i];
for (i = 0; i < priv->ip_configs->len; i++) {
NMDnsIPConfigData *data = priv->ip_configs->pdata[i];
if (NM_IS_IP4_CONFIG (data->config))
nm_ip4_config_hash ((NMIP4Config *) data->config, sum, TRUE);
......@@ -915,7 +941,7 @@ _ptrarray_to_strv (GPtrArray *parray)
static void
_collect_resolv_conf_data (NMDnsManager *self, /* only for logging context, no other side-effects */
NMGlobalDnsConfig *global_config,
const GPtrArray *configs,
const GPtrArray *ip_configs,
const char *hostname,
char ***out_searches,
char ***out_options,
......@@ -923,7 +949,7 @@ _collect_resolv_conf_data (NMDnsManager *self, /* only for logging context, no o
char ***out_nis_servers,
const char **out_nis_domain)
{
guint i, j, num, len;
guint i, num, len;
NMResolvConfData rc = {
.nameservers = g_ptr_array_new (),
.searches = g_ptr_array_new (),
......@@ -939,10 +965,10 @@ _collect_resolv_conf_data (NMDnsManager *self, /* only for logging context, no o
int prio, first_prio = 0;
NMDnsIPConfigData *current;
for (i = 0, j = 0; i < configs->len; i++) {
for (i = 0; i < ip_configs->len; i++) {
gboolean skip = FALSE;
current = configs->pdata[i];
current = ip_configs->pdata[i];
prio = nm_ip_config_get_dns_priority (current->config);
......@@ -1045,14 +1071,14 @@ update_dns (NMDnsManager *self,
global_config = nm_config_data_get_global_dns_config (data);
if (priv->need_sort) {
g_ptr_array_sort (priv->configs, ip_config_data_ptr_compare);
g_ptr_array_sort (priv->ip_configs, ip_config_data_ptr_compare);
priv->need_sort = FALSE;
}
/* Update hash with config we're applying */
compute_hash (self, global_config, priv->hash);
_collect_resolv_conf_data (self, global_config, priv->configs, priv->hostname,
_collect_resolv_conf_data (self, global_config, priv->ip_configs, priv->hostname,
&searches, &options, &nameservers, &nis_servers, &nis_domain);
/* Let any plugins do their thing first */
......@@ -1071,7 +1097,7 @@ update_dns (NMDnsManager *self,
_LOGD ("update-dns: updating plugin %s", plugin_name);
if (!nm_dns_plugin_update (plugin,
priv->configs,
priv->ip_configs,
global_config,
priv->hostname)) {
_LOGW ("update-dns: plugin %s update failed", plugin_name);
......@@ -1217,7 +1243,7 @@ ip_config_dns_priority_changed (gpointer config,
}
static void
forget_data (NMDnsManager *self, NMDnsIPConfigData *data)
forget_ip_data (NMDnsManager *self, NMDnsIPConfigData *data)
{
NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self);
......@@ -1229,6 +1255,40 @@ forget_data (NMDnsManager *self, NMDnsIPConfigData *data)
g_signal_handlers_disconnect_by_func (data->config, ip_config_dns_priority_changed, self);
}
void nm_dns_manager_update_ifindex (NMDnsManager *self,
const char *iface,
int new_ifindex)
{
NMDnsConnectionConfigData *data;
NMDnsManagerPrivate *priv;
NMDnsPlugin *plugin;
guint i;
g_return_if_fail (NM_IS_DNS_MANAGER (self));
g_return_if_fail (iface && iface[0]);
g_return_if_fail (new_ifindex > 0);
priv = NM_DNS_MANAGER_GET_PRIVATE (self);
plugin = priv->plugin;
for (i = 0; i < priv->connection_configs->len; i++) {
data = priv->connection_configs->pdata[i];
if (nm_streq (data->iface, iface)) {
if (data->ifindex == new_ifindex)
return;
nm_dns_plugin_update_mdns (plugin,
data->ifindex,
NM_SETTING_CONNECTION_MDNS_UNKNOWN);
data->ifindex = new_ifindex;
nm_dns_plugin_update_mdns (plugin,
data->ifindex,
data->mdns);
return;
}
}
}
gboolean
nm_dns_manager_add_ip_config (NMDnsManager *self,
const char *iface,
......@@ -1248,22 +1308,22 @@ nm_dns_manager_add_ip_config (NMDnsManager *self,
priv = NM_DNS_MANAGER_GET_PRIVATE (self);
for (i = 0; i < priv->configs->len; i++) {
data = priv->configs->pdata[i];
for (i = 0; i < priv->ip_configs->len; i++) {
data = priv->ip_configs->pdata[i];
if (data->config == config) {
if ( nm_streq (data->iface, iface)
&& data->type == cfg_type)
return FALSE;
else {
forget_data (self, data);
g_ptr_array_remove_index_fast (priv->configs, i);
forget_ip_data (self, data);
g_ptr_array_remove_index_fast (priv->ip_configs, i);
break;
}
}
}
data = ip_config_data_new (config, cfg_type, iface);
g_ptr_array_add (priv->configs, data);
g_ptr_array_add (priv->ip_configs, data);
g_signal_connect (config,
v4 ?
"notify::" NM_IP4_CONFIG_DNS_PRIORITY :
......@@ -1306,12 +1366,12 @@ nm_dns_manager_remove_ip_config (NMDnsManager *self, gpointer config)
priv = NM_DNS_MANAGER_GET_PRIVATE (self);
for (i = 0; i < priv->configs->len; i++) {
data = priv->configs->pdata[i];
for (i = 0; i < priv->ip_configs->len; i++) {
data = priv->ip_configs->pdata[i];
if (data->config == config) {
forget_data (self, data);
g_ptr_array_remove_index (priv->configs, i);
forget_ip_data (self, data);
g_ptr_array_remove_index (priv->ip_configs, i);
if (!priv->updates_queue && !update_dns (self, FALSE, &error)) {
_LOGW ("could not commit DNS changes: %s", error->message);
......@@ -1366,6 +1426,75 @@ nm_dns_manager_set_hostname (NMDnsManager *self,
}
}
gboolean
nm_dns_manager_add_connection_config (NMDnsManager *self,
const char *iface,
int ifindex,
NMSettingConnectionMdns mdns)
{
NMDnsConnectionConfigData *data;
NMDnsManagerPrivate *priv;
NMDnsPlugin *plugin;
guint i;
g_return_val_if_fail (NM_IS_DNS_MANAGER (self), FALSE);
g_return_val_if_fail (ifindex > 0, FALSE);
g_return_val_if_fail (iface != NULL && iface[0], FALSE);
g_return_val_if_fail (mdns != NM_SETTING_CONNECTION_MDNS_UNKNOWN, FALSE);
priv = NM_DNS_MANAGER_GET_PRIVATE (self);
plugin = priv->plugin;
for (i = 0; i < priv->connection_configs->len; i++) {
data = priv->connection_configs->pdata[i];
if (nm_streq (data->iface, iface)) {
if (data->mdns == mdns)
/* already there */
return FALSE;
else {
data->mdns = mdns;
return nm_dns_plugin_update_mdns (plugin,
ifindex,
mdns);
}
}
}
data = connection_config_data_new (mdns, iface, ifindex);
g_ptr_array_add (priv->connection_configs, data);
return nm_dns_plugin_update_mdns (plugin, ifindex, mdns);
}
void
nm_dns_manager_remove_connection_config (NMDnsManager *self,
const char *iface,
int ifindex)
{
NMDnsConnectionConfigData *data;
NMDnsManagerPrivate *priv;
NMDnsPlugin *plugin;
guint i;
g_return_if_fail (NM_IS_DNS_MANAGER (self));
g_return_if_fail (iface != NULL && iface[0]);
g_return_if_fail (ifindex > 0);
priv = NM_DNS_MANAGER_GET_PRIVATE (self);
plugin = priv->plugin;
for (i = 0; i < priv->connection_configs->len; i++) {
data = priv->connection_configs->pdata[i];
if (nm_streq (data->iface, iface)) {
nm_dns_plugin_update_mdns (plugin,
ifindex,
NM_SETTING_CONNECTION_MDNS_UNKNOWN);
g_ptr_array_remove_index_fast (priv->connection_configs, i);
return;
}
}
}
gboolean
nm_dns_manager_get_resolv_conf_explicit (NMDnsManager *self)
{
......@@ -1414,7 +1543,7 @@ nm_dns_manager_end_updates (NMDnsManager *self, const char *func)
g_return_if_fail (priv->updates_queue > 0);
if (priv->need_sort) {
g_ptr_array_sort (priv->configs, ip_config_data_ptr_compare);
g_ptr_array_sort (priv->ip_configs, ip_config_data_ptr_compare);
priv->need_sort = FALSE;
}
......@@ -1830,8 +1959,8 @@ _get_config_variant (NMDnsManager *self)
g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}"));
for (i = 0; i < priv->configs->len; i++) {
NMDnsIPConfigData *current = priv->configs->pdata[i];
for (i = 0; i < priv->ip_configs->len; i++) {
NMDnsIPConfigData *current = priv->ip_configs->pdata[i];
const NMIPConfig *config = current->config;
GVariantBuilder entry_builder;
GVariantBuilder strv_builder;
......@@ -1929,7 +2058,8 @@ nm_dns_manager_init (NMDnsManager *self)
_LOGT ("creating...");
priv->config = g_object_ref (nm_config_get ());
priv->configs = g_ptr_array_new_full (8, ip_config_data_destroy);
priv->ip_configs = g_ptr_array_new_full (8, ip_config_data_destroy);
priv->connection_configs = g_ptr_array_new_full (8, connection_config_data_destroy);
/* Set the initial hash */
compute_hash (self, NULL, NM_DNS_MANAGER_GET_PRIVATE (self)->hash);
......@@ -1946,7 +2076,7 @@ dispose (GObject *object)
{
NMDnsManager *self = NM_DNS_MANAGER (object);
NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self);
NMDnsIPConfigData *data;
NMDnsIPConfigData *ip_data;
guint i;
_LOGT ("disposing");
......@@ -1961,13 +2091,18 @@ dispose (GObject *object)
g_clear_object (&priv->config);
}
if (priv->configs) {
for (i = 0; i < priv->configs->len; i++) {
data = priv->configs->pdata[i];
forget_data (self, data);
if (priv->ip_configs) {
for (i = 0; i < priv->ip_configs->len; i++) {
ip_data = priv->ip_configs->pdata[i];
forget_ip_data (self, ip_data);
}
g_ptr_array_free (priv->configs, TRUE);
priv->configs = NULL;
g_ptr_array_free (priv->ip_configs, TRUE);
priv->ip_configs = NULL;
}
if (priv->connection_configs) {
g_ptr_array_free (priv->connection_configs, TRUE);
priv->connection_configs = NULL;
}
nm_clear_g_source (&priv->plugin_ratelimit.timer);
......@@ -2033,4 +2168,3 @@ nm_dns_manager_class_init (NMDnsManagerClass *klass)
NMDBUS_TYPE_DNS_MANAGER_SKELETON,
NULL);
}
......@@ -26,6 +26,7 @@
#include "nm-ip4-config.h"
#include "nm-ip6-config.h"
#include "nm-setting-connection.h"
typedef enum {
NM_DNS_IP_CONFIG_TYPE_DEFAULT = 0,
......@@ -44,6 +45,12 @@ typedef struct {
char *iface;
} NMDnsIPConfigData;
typedef struct {
NMSettingConnectionMdns mdns;
char *iface;
int ifindex;
} NMDnsConnectionConfigData;
#define NM_TYPE_DNS_MANAGER (nm_dns_manager_get_type ())
#define NM_DNS_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), NM_TYPE_DNS_MANAGER, NMDnsManager))
#define NM_DNS_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), NM_TYPE_DNS_MANAGER, NMDnsManagerClass))
......@@ -82,6 +89,16 @@ void nm_dns_manager_set_initial_hostname (NMDnsManager *self,
void nm_dns_manager_set_hostname (NMDnsManager *self,
const char *hostname,
gboolean skip_update);
gboolean nm_dns_manager_add_connection_config (NMDnsManager *self,
const char *iface,
int ifindex,
NMSettingConnectionMdns mdns);
void nm_dns_manager_remove_connection_config (NMDnsManager *self,
const char *iface,
int ifindex);
void nm_dns_manager_update_ifindex (NMDnsManager *self,
const char *ip_iface,
int new_ifindex);
/**
* NMDnsManagerResolvConfManager
......
......@@ -89,6 +89,18 @@ nm_dns_plugin_update (NMDnsPlugin *self,
hostname);
}
gboolean
nm_dns_plugin_update_mdns (NMDnsPlugin *self,
int ifindex,
NMSettingConnectionMdns mdns)
{
g_return_val_if_fail (NM_DNS_PLUGIN_GET_CLASS (self)->update_mdns != NULL, FALSE);
return NM_DNS_PLUGIN_GET_CLASS (self)->update_mdns (self,
ifindex,
mdns);
}
static gboolean
is_caching (NMDnsPlugin *self)
{
......
......@@ -60,6 +60,11 @@ typedef struct {
*/
gboolean (*is_caching) (NMDnsPlugin *self);
/* Subclasses wishing to control interface mDNS status should override. */
gboolean (*update_mdns) (NMDnsPlugin *self,
int ifindex,
NMSettingConnectionMdns mdns);
/* Subclasses should override this and return their plugin name */
const char *(*get_name) (NMDnsPlugin *self);
......@@ -84,6 +89,10 @@ gboolean nm_dns_plugin_update (NMDnsPlugin *self,
const NMGlobalDnsConfig *global_config,
const char *hostname);
gboolean nm_dns_plugin_update_mdns (NMDnsPlugin *self,
int ifindex,
NMSettingConnectionMdns mdns);
void nm_dns_plugin_stop (NMDnsPlugin *self);
/* For subclasses/plugins */
......
......@@ -38,6 +38,7 @@
#include "nm-ip6-config.h"
#include "nm-bus-manager.h"
#include "nm-manager.h"
#include "nm-setting-connection.h"
#include "devices/nm-device.h"
#include "NetworkManagerUtils.h"
......@@ -57,6 +58,7 @@ typedef struct {
GDBusProxy *resolve;
GCancellable *init_cancellable;
GCancellable *update_cancellable;
GCancellable *mdns_cancellable;
GQueue dns_updates;
GQueue domain_updates;
} NMDnsSystemdResolvedPrivate;
......@@ -316,6 +318,45 @@ update (NMDnsPlugin *plugin,
return TRUE;
}
static gboolean
update_mdns (NMDnsPlugin *plugin, int ifindex, NMSettingConnectionMdns mdns)
{
NMDnsSystemdResolved *self = NM_DNS_SYSTEMD_RESOLVED (plugin);
NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE (self);
char *value;
_LOGI ("update_mdns: %i/%d", ifindex, mdns);
nm_clear_g_cancellable (&priv->mdns_cancellable);
if (!priv->resolve)
return FALSE;
priv->mdns_cancellable = g_cancellable_new ();
switch (mdns) {
case NM_SETTING_CONNECTION_MDNS_YES:
value = "yes";
break;
case NM_SETTING_CONNECTION_MDNS_NO:
value = "no";
break;
case NM_SETTING_CONNECTION_MDNS_RESOLVE:
value = "resolve";
break;
default:
/* reset to system default */
value = "";
}
g_dbus_proxy_call (priv->resolve, "SetLinkMulticastDNS",
g_variant_new ("(is)", ifindex, value),
G_DBUS_CALL_FLAGS_NONE,
-1, priv->mdns_cancellable, call_done, self);
return TRUE;
}
/*****************************************************************************/
static gboolean
......@@ -404,6 +445,7 @@ dispose (GObject *object)
g_clear_object (&priv->resolve);
nm_clear_g_cancellable (&priv->init_cancellable);
nm_clear_g_cancellable (&priv->update_cancellable);
nm_clear_g_cancellable (&priv->mdns_cancellable);
G_OBJECT_CLASS (nm_dns_systemd_resolved_parent_class)->dispose (object);
}
......@@ -418,5 +460,6 @@ nm_dns_systemd_resolved_class_init (NMDnsSystemdResolvedClass *dns_class)
plugin_class->is_caching = is_caching;
plugin_class->update = update;
plugin_class->update_mdns = update_mdns;
plugin_class->get_name = get_name;
}
......@@ -1059,6 +1059,35 @@ update_ip6_routing (NMPolicy *self, gboolean force_update)
_notify (self, PROP_DEFAULT_IP6_DEVICE);
}
static void
add_connection_dns (NMPolicy *self, NMConnection *connection, const char *iface, int ifindex)
{
NMSettingConnection *s_con = NULL;
if (connection == NULL)
return;
s_con = nm_connection_get_setting_connection (connection);
if (s_con) {
NMSettingConnectionMdns mdns = nm_setting_connection_get_mdns (s_con);
if (mdns != NM_SETTING_CONNECTION_MDNS_UNKNOWN)
nm_dns_manager_add_connection_config (NM_POLICY_GET_PRIVATE (self)->dns_manager,
iface,
ifindex,
mdns);
}
}
static void
remove_connection_dns (NMPolicy *self, const char *iface, int ifindex)
{
nm_dns_manager_remove_connection_config (NM_POLICY_GET_PRIVATE (self)->dns_manager,
iface,
ifindex);
}
static void
update_ip_dns (NMPolicy *self, int addr_family)
{
......@@ -1804,6 +1833,9 @@ device_state_changed (NMDevice *device,
*/
nm_connection_clear_secrets (NM_CONNECTION (connection));
/* Add connection settings (currently link mDNS state) */
add_connection_dns (self, NM_CONNECTION (connection), ip_iface, nm_device_get_ip_ifindex (device));
}
/* Add device's new IPv4 and IPv6 configs to DNS */
......@@ -1858,8 +1890,12 @@ device_state_changed (NMDevice *device,
&& old_state == NM_DEVICE_STATE_UNAVAILABLE)
reset_autoconnect_all (self, device, FALSE);
if (old_state > NM_DEVICE_STATE_DISCONNECTED)
if (old_state > NM_DEVICE_STATE_DISCONNECTED) {
update_routing_and_dns (self, FALSE);
/* Remove connection settings (currently link mDNS state) */
remove_connection_dns (self, ip_iface, nm_device_get_ip_ifindex (device));
}
/* Device is now available for auto-activation */
schedule_activate_check (self, device);
......@@ -1992,6 +2028,19 @@ device_autoconnect_changed (NMDevice *device,
schedule_activate_check (self, device);
}
static void
device_ifindex_changed (NMDevice *device,
GParamSpec *pspec,
gpointer user_data)
{
NMPolicyPrivate *priv = user_data;
const char *ip_iface = nm_device_get_ip_iface (device);
int ifindex = nm_device_get_ifindex (device);
/* update ifindex mapping in DNS manager */
nm_dns_manager_update_ifindex (priv->dns_manager, ip_iface, ifindex);
}
static void
device_recheck_auto_activate (NMDevice *device, gpointer user_data)
{
......@@ -2020,6 +2069,7 @@ devices_list_register (NMPolicy *self, NMDevice *device)
g_signal_connect (device, NM_DEVICE_IP6_CONFIG_CHANGED, (GCallback) device_ip6_config_changed, priv);
g_signal_connect (device, NM_DEVICE_IP6_PREFIX_DELEGATED, (GCallback) device_ip6_prefix_delegated, priv);
g_signal_connect (device, NM_DEVICE_IP6_SUBNET_NEEDED, (GCallback) device_ip6_subnet_needed, priv);
g_signal_connect (device, "notify::" NM_DEVICE_IFINDEX, (GCallback) device_ifindex_changed, priv);
g_signal_connect (device, "notify::" NM_DEVICE_AUTOCONNECT, (GCallback) device_autoconnect_changed, priv);
g_signal_connect (device, NM_DEVICE_RECHECK_AUTO_ACTIVATE, (GCallback) device_recheck_auto_activate, priv);
}
......@@ -2073,6 +2123,7 @@ vpn_connection_activated (NMPolicy *self, NMVpnConnection *vpn)
NMIP4Config *ip4_config;
NMIP6Config *ip6_config;
const char *ip_iface;
NMConnection *connection;
nm_dns_manager_begin_updates (priv->dns_manager, __func__);
......@@ -2091,6 +2142,10 @@ vpn_connection_activated (NMPolicy *self, NMVpnConnection *vpn)
update_routing_and_dns (self, TRUE);
nm_dns_manager_end_updates (priv->dns_manager, __func__);
/* Make sure the connection settings are set */
connection = nm_active_connection_get_applied_connection (NM_ACTIVE_CONNECTION (vpn));
add_connection_dns (self, connection, ip_iface, nm_vpn_connection_get_ip_ifindex (vpn, TRUE));
}
static void
......@@ -2117,6 +2172,10 @@ vpn_connection_deactivated (NMPolicy *self, NMVpnConnection *vpn)
update_routing_and_dns (self, TRUE);
nm_dns_manager_end_updates (priv->dns_manager, __func__);
remove_connection_dns(self,
nm_vpn_connection_get_ip_iface (vpn, TRUE),
nm_vpn_connection_get_ip_ifindex (vpn, TRUE));
}
static void
......
Markdown is supported
0%