diff --git a/src/dns/nm-dns-manager.c b/src/dns/nm-dns-manager.c index 22c9e0d98b..6e2bdae8c8 100644 --- a/src/dns/nm-dns-manager.c +++ b/src/dns/nm-dns-manager.c @@ -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) { @@ -833,8 +859,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); @@ -916,7 +942,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, @@ -940,10 +966,10 @@ _collect_resolv_conf_data (NMDnsManager *self, /* only for logging context, no o int prio, first_prio = 0; NMDnsIPConfigData *current; - for (i = 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); @@ -1046,14 +1072,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 */ @@ -1072,7 +1098,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); @@ -1222,7 +1248,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); @@ -1234,6 +1260,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, @@ -1253,22 +1313,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 : @@ -1311,12 +1371,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); @@ -1371,6 +1431,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) { @@ -1419,7 +1548,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; } @@ -1833,8 +1962,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; @@ -1932,7 +2061,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); @@ -1949,7 +2079,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"); @@ -1964,13 +2094,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); @@ -2036,4 +2171,3 @@ nm_dns_manager_class_init (NMDnsManagerClass *klass) NMDBUS_TYPE_DNS_MANAGER_SKELETON, NULL); } - diff --git a/src/dns/nm-dns-manager.h b/src/dns/nm-dns-manager.h index b38ea701b4..d2afe8143b 100644 --- a/src/dns/nm-dns-manager.h +++ b/src/dns/nm-dns-manager.h @@ -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 diff --git a/src/dns/nm-dns-plugin.c b/src/dns/nm-dns-plugin.c index 5805b7d858..7ac57ce8b1 100644 --- a/src/dns/nm-dns-plugin.c +++ b/src/dns/nm-dns-plugin.c @@ -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) { diff --git a/src/dns/nm-dns-plugin.h b/src/dns/nm-dns-plugin.h index 996695c0f7..f6008270c8 100644 --- a/src/dns/nm-dns-plugin.h +++ b/src/dns/nm-dns-plugin.h @@ -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 */ diff --git a/src/dns/nm-dns-systemd-resolved.c b/src/dns/nm-dns-systemd-resolved.c index 71424d182d..8dd395d291 100644 --- a/src/dns/nm-dns-systemd-resolved.c +++ b/src/dns/nm-dns-systemd-resolved.c @@ -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; @@ -314,6 +316,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 @@ -402,6 +443,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); } @@ -416,5 +458,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; } diff --git a/src/nm-policy.c b/src/nm-policy.c index d6fcf95e77..40bee9a588 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -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) { @@ -1794,6 +1823,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 */ @@ -1848,8 +1880,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); @@ -1982,6 +2018,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) { @@ -2010,6 +2059,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); } @@ -2063,6 +2113,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__); @@ -2081,6 +2132,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 @@ -2107,6 +2162,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