From 3d86429c9d9feb97c197feea450a767d5117cf86 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 15 Dec 2017 13:06:05 +0100 Subject: [PATCH 01/18] core: reorder code in "src/dns/nm-dns-manager.c" Just moving code around, no other changes. Follow a certain prefered order of declarations in source files. --- src/dns/nm-dns-manager.c | 84 +++++++++++++++++++++------------------- 1 file changed, 44 insertions(+), 40 deletions(-) diff --git a/src/dns/nm-dns-manager.c b/src/dns/nm-dns-manager.c index f7787ea52c..22c9e0d98b 100644 --- a/src/dns/nm-dns-manager.c +++ b/src/dns/nm-dns-manager.c @@ -70,6 +70,24 @@ #define PLUGIN_RATELIMIT_BURST 5 #define PLUGIN_RATELIMIT_DELAY 300 +/*****************************************************************************/ + +typedef enum { + SR_SUCCESS, + SR_NOTFOUND, + SR_ERROR +} SpawnResult; + +typedef struct { + GPtrArray *nameservers; + GPtrArray *searches; + GPtrArray *options; + const char *nis_domain; + GPtrArray *nis_servers; +} NMResolvConfData; + +/*****************************************************************************/ + enum { CONFIG_CHANGED, @@ -84,38 +102,6 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMDnsManager, static guint signals[LAST_SIGNAL] = { 0 }; -typedef enum { - SR_SUCCESS, - SR_NOTFOUND, - SR_ERROR -} SpawnResult; - -NM_DEFINE_SINGLETON_GETTER (NMDnsManager, nm_dns_manager_get, NM_TYPE_DNS_MANAGER); - -/*****************************************************************************/ - -#define _NMLOG_PREFIX_NAME "dns-mgr" -#define _NMLOG_DOMAIN LOGD_DNS -#define _NMLOG(level, ...) \ - G_STMT_START { \ - const NMLogLevel __level = (level); \ - \ - if (nm_logging_enabled (__level, _NMLOG_DOMAIN)) { \ - char __prefix[20]; \ - const NMDnsManager *const __self = (self); \ - \ - _nm_log (__level, _NMLOG_DOMAIN, 0, NULL, NULL, \ - "%s%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ - _NMLOG_PREFIX_NAME, \ - ((!__self || __self == singleton_instance) \ - ? "" \ - : nm_sprintf_buf (__prefix, "[%p]", __self)) \ - _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ - } \ - } G_STMT_END - -/*****************************************************************************/ - typedef struct { GPtrArray *configs; GVariant *config_variant; @@ -157,6 +143,32 @@ G_DEFINE_TYPE (NMDnsManager, nm_dns_manager, NM_TYPE_EXPORTED_OBJECT) #define NM_DNS_MANAGER_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMDnsManager, NM_IS_DNS_MANAGER) +NM_DEFINE_SINGLETON_GETTER (NMDnsManager, nm_dns_manager_get, NM_TYPE_DNS_MANAGER); + +/*****************************************************************************/ + +#define _NMLOG_PREFIX_NAME "dns-mgr" +#define _NMLOG_DOMAIN LOGD_DNS +#define _NMLOG(level, ...) \ + G_STMT_START { \ + const NMLogLevel __level = (level); \ + \ + if (nm_logging_enabled (__level, _NMLOG_DOMAIN)) { \ + char __prefix[20]; \ + const NMDnsManager *const __self = (self); \ + \ + _nm_log (__level, _NMLOG_DOMAIN, 0, NULL, NULL, \ + "%s%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ + _NMLOG_PREFIX_NAME, \ + ((!__self || __self == singleton_instance) \ + ? "" \ + : nm_sprintf_buf (__prefix, "[%p]", __self)) \ + _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ + } \ + } G_STMT_END + +/*****************************************************************************/ + static gboolean domain_is_valid (const gchar *domain, gboolean check_public_suffix) { @@ -171,14 +183,6 @@ domain_is_valid (const gchar *domain, gboolean check_public_suffix) /*****************************************************************************/ -typedef struct { - GPtrArray *nameservers; - GPtrArray *searches; - GPtrArray *options; - const char *nis_domain; - GPtrArray *nis_servers; -} NMResolvConfData; - NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_rc_manager_to_string, NMDnsManagerResolvConfManager, NM_UTILS_LOOKUP_DEFAULT_WARN (NULL), NM_UTILS_LOOKUP_STR_ITEM (NM_DNS_MANAGER_RESOLV_CONF_MAN_UNKNOWN, "unknown"), From 6dd69990c04b8a4e1bc439f6f717de48f4f8d9be Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 15 Dec 2017 14:07:09 +0100 Subject: [PATCH 02/18] build: first build dns-manager and dns-plugin before the plugins When doing changes that affect multiple source files, it's more convenient to build the parts that have less dependencies first. So, to fix the build failures from the core outward. --- Makefile.am | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Makefile.am b/Makefile.am index 913c22c4e3..32303b2f79 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1479,16 +1479,16 @@ src_libNetworkManager_la_SOURCES = \ src/dhcp/nm-dhcp-dhclient-utils.c \ src/dhcp/nm-dhcp-dhclient-utils.h \ \ + src/dns/nm-dns-manager.c \ + src/dns/nm-dns-manager.h \ + src/dns/nm-dns-plugin.c \ + src/dns/nm-dns-plugin.h \ src/dns/nm-dns-dnsmasq.c \ src/dns/nm-dns-dnsmasq.h \ src/dns/nm-dns-systemd-resolved.c \ src/dns/nm-dns-systemd-resolved.h \ src/dns/nm-dns-unbound.c \ src/dns/nm-dns-unbound.h \ - src/dns/nm-dns-manager.c \ - src/dns/nm-dns-manager.h \ - src/dns/nm-dns-plugin.c \ - src/dns/nm-dns-plugin.h \ \ src/dnsmasq/nm-dnsmasq-manager.c \ src/dnsmasq/nm-dnsmasq-manager.h \ From 2e2ff6f27aa1bfa7a27d49980b319873240ec84b Mon Sep 17 00:00:00 2001 From: Ismo Puustinen Date: Fri, 10 Nov 2017 14:49:27 +0200 Subject: [PATCH 03/18] mdns: add new connection property. Add support for mDNS as a connection-level property. Update ifcfg-rh and keyfile plugins to support it. --- clients/common/nm-meta-setting-desc.c | 8 +++ clients/common/settings-docs.c.in | 1 + libnm-core/nm-setting-connection.c | 59 +++++++++++++++++++ libnm-core/nm-setting-connection.h | 21 +++++++ libnm-core/tests/test-general.c | 1 + libnm/libnm.ver | 2 + .../plugins/ifcfg-rh/nms-ifcfg-rh-reader.c | 9 ++- .../plugins/ifcfg-rh/nms-ifcfg-rh-writer.c | 11 +++- 8 files changed, 109 insertions(+), 3 deletions(-) diff --git a/clients/common/nm-meta-setting-desc.c b/clients/common/nm-meta-setting-desc.c index 4aa135a925..9943b35eff 100644 --- a/clients/common/nm-meta-setting-desc.c +++ b/clients/common/nm-meta-setting-desc.c @@ -5577,6 +5577,14 @@ static const NMMetaPropertyInfo *const property_infos_CONNECTION[] = { | NM_META_PROPERTY_TYP_FLAG_ENUM_GET_PRETTY_TEXT, ), ), + PROPERTY_INFO_WITH_DESC (NM_SETTING_CONNECTION_MDNS, + .property_type = &_pt_gobject_enum, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( + PROPERTY_TYP_DATA_SUBTYPE (gobject_enum, + .get_gtype = nm_setting_connection_mdns_get_type, + ), + ), + ), NULL }; diff --git a/clients/common/settings-docs.c.in b/clients/common/settings-docs.c.in index 8f3a95763f..1f3a1a62be 100644 --- a/clients/common/settings-docs.c.in +++ b/clients/common/settings-docs.c.in @@ -144,6 +144,7 @@ #define DESCRIBE_DOC_NM_SETTING_CONNECTION_INTERFACE_NAME N_("The name of the network interface this connection is bound to. If not set, then the connection can be attached to any interface of the appropriate type (subject to restrictions imposed by other settings). For software devices this specifies the name of the created device. For connection types where interface names cannot easily be made persistent (e.g. mobile broadband or USB Ethernet), this property should not be used. Setting this property restricts the interfaces a connection can be used with, and if interface names change or are reordered the connection may be applied to the wrong interface.") #define DESCRIBE_DOC_NM_SETTING_CONNECTION_LLDP N_("Whether LLDP is enabled for the connection.") #define DESCRIBE_DOC_NM_SETTING_CONNECTION_MASTER N_("Interface name of the master device or UUID of the master connection.") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_MDNS N_("Whether mDNS is enabled for the connection. The permitted values are: yes: register hostname and resolving for the connection, no: disable mDNS for the interface, resolve: do not register hostname but allow resolving of mDNS host names. When updating this property on a currently activated connection, the change takes effect immediately. This feature requires a plugin which supports mDNS. One such plugin is dns-systemd-resolved.") #define DESCRIBE_DOC_NM_SETTING_CONNECTION_METERED N_("Whether the connection is metered. When updating this property on a currently activated connection, the change takes effect immediately.") #define DESCRIBE_DOC_NM_SETTING_CONNECTION_NAME N_("The setting's name, which uniquely identifies the setting within the connection. Each setting type has a name unique to that type, for example \"ppp\" or \"wireless\" or \"wired\".") #define DESCRIBE_DOC_NM_SETTING_CONNECTION_PERMISSIONS N_("An array of strings defining what access a given user has to this connection. If this is NULL or empty, all users are allowed to access this connection; otherwise users are allowed if and only if they are in this list. When this is not empty, the connection can be active only when one of the specified users is logged into an active session. Each entry is of the form \"[type]:[id]:[reserved]\"; for example, \"user:dcbw:blah\". At this time only the \"user\" [type] is allowed. Any other values are ignored and reserved for future use. [id] is the username that this permission refers to, which may not contain the \":\" character. Any [reserved] information present must be ignored and is reserved for future use. All of [type], [id], and [reserved] must be valid UTF-8.") diff --git a/libnm-core/nm-setting-connection.c b/libnm-core/nm-setting-connection.c index 24c65e7c5e..ba5bf8bf55 100644 --- a/libnm-core/nm-setting-connection.c +++ b/libnm-core/nm-setting-connection.c @@ -81,6 +81,7 @@ typedef struct { NMMetered metered; NMSettingConnectionLldp lldp; gint auth_retries; + NMSettingConnectionMdns mdns; } NMSettingConnectionPrivate; enum { @@ -103,6 +104,7 @@ enum { PROP_GATEWAY_PING_TIMEOUT, PROP_METERED, PROP_LLDP, + PROP_MDNS, PROP_STABLE_ID, PROP_AUTH_RETRIES, @@ -862,6 +864,23 @@ nm_setting_connection_get_lldp (NMSettingConnection *setting) return NM_SETTING_CONNECTION_GET_PRIVATE (setting)->lldp; } +/** + * nm_setting_connection_get_mdns: + * @setting: the #NMSettingConnection + * + * Returns: the #NMSettingConnection:mdns property of the setting. + * + * Since: 1.12 + **/ +NMSettingConnectionMdns +nm_setting_connection_get_mdns (NMSettingConnection *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_CONNECTION (setting), + NM_SETTING_CONNECTION_MDNS_UNKNOWN); + + return NM_SETTING_CONNECTION_GET_PRIVATE (setting)->mdns; +} + static void _set_error_missing_base_setting (GError **error, const char *type) { @@ -1332,6 +1351,9 @@ set_property (GObject *object, guint prop_id, case PROP_AUTH_RETRIES: priv->auth_retries = g_value_get_int (value); break; + case PROP_MDNS: + priv->mdns = g_value_get_int (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1420,6 +1442,9 @@ get_property (GObject *object, guint prop_id, case PROP_AUTH_RETRIES: g_value_set_int (value, priv->auth_retries); break; + case PROP_MDNS: + g_value_set_int (value, priv->mdns); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1982,4 +2007,38 @@ nm_setting_connection_class_init (NMSettingConnectionClass *setting_class) G_PARAM_CONSTRUCT | NM_SETTING_PARAM_FUZZY_IGNORE | G_PARAM_STATIC_STRINGS)); + + /** + * NMSettingConnection:mdns: + * + * Whether mDNS is enabled for the connection. + * + * The permitted values are: yes: register hostname and resolving + * for the connection, no: disable mDNS for the interface, resolve: + * do not register hostname but allow resolving of mDNS host names. + * When updating this property on a currently activated connection, + * the change takes effect immediately. + * + * This feature requires a plugin which supports mDNS. One such + * plugin is dns-systemd-resolved. + * + * Since: 1.12 + **/ + /* ---ifcfg-rh--- + * property: mdns + * variable: CONNECTION_MDNS(+) + * values: yes,no,resolve + * default: missing variable means global default + * description: Whether or not mDNS is enabled for the connection + * example: CONNECTION_MDNS=yes + * ---end--- + */ + g_object_class_install_property + (object_class, PROP_MDNS, + g_param_spec_int (NM_SETTING_CONNECTION_MDNS, "", "", + G_MININT32, G_MAXINT32, + NM_SETTING_CONNECTION_MDNS_UNKNOWN, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_STRINGS)); } diff --git a/libnm-core/nm-setting-connection.h b/libnm-core/nm-setting-connection.h index 02a7f5b10a..6fd88a906d 100644 --- a/libnm-core/nm-setting-connection.h +++ b/libnm-core/nm-setting-connection.h @@ -64,6 +64,7 @@ G_BEGIN_DECLS #define NM_SETTING_CONNECTION_METERED "metered" #define NM_SETTING_CONNECTION_LLDP "lldp" #define NM_SETTING_CONNECTION_AUTH_RETRIES "auth-retries" +#define NM_SETTING_CONNECTION_MDNS "mdns" /* Types for property values */ /** @@ -97,6 +98,24 @@ typedef enum { NM_SETTING_CONNECTION_LLDP_ENABLE_RX = 1, } NMSettingConnectionLldp; +/** + * NMSettingConnectionMdns: + * @NM_SETTING_CONNECTION_MDNS_UNKNOWN: default value + * @NM_SETTING_CONNECTION_MDNS_YES: disable mDNS + * @NM_SETTING_CONNECTION_MDNS_NO: enable mDNS + * @NM_SETTING_CONNECTION_MDNS_RESOLVE: support only resolving, do not register hostname + * + * #NMSettingConnectionMdns values indicate whether mDNS should be enabled. + * + * Since: 1.12 + */ +typedef enum { + NM_SETTING_CONNECTION_MDNS_UNKNOWN = 0, + NM_SETTING_CONNECTION_MDNS_YES = 1, + NM_SETTING_CONNECTION_MDNS_NO = 2, + NM_SETTING_CONNECTION_MDNS_RESOLVE = 3, +} NMSettingConnectionMdns; + /** * NMSettingConnection: * @@ -170,6 +189,8 @@ NMSettingConnectionLldp nm_setting_connection_get_lldp (NMSettingConnection *set NM_AVAILABLE_IN_1_10 gint nm_setting_connection_get_auth_retries (NMSettingConnection *setting); +NM_AVAILABLE_IN_1_12 +NMSettingConnectionMdns nm_setting_connection_get_mdns (NMSettingConnection *setting); G_END_DECLS #endif /* __NM_SETTING_CONNECTION_H__ */ diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c index e4a5aa5a13..9cf08c5d8c 100644 --- a/libnm-core/tests/test-general.c +++ b/libnm-core/tests/test-general.c @@ -2604,6 +2604,7 @@ test_connection_diff_a_only (void) { NM_SETTING_CONNECTION_METERED, NM_SETTING_DIFF_RESULT_IN_A }, { NM_SETTING_CONNECTION_LLDP, NM_SETTING_DIFF_RESULT_IN_A }, { NM_SETTING_CONNECTION_AUTH_RETRIES, NM_SETTING_DIFF_RESULT_IN_A }, + { NM_SETTING_CONNECTION_MDNS, NM_SETTING_DIFF_RESULT_IN_A }, { NULL, NM_SETTING_DIFF_RESULT_UNKNOWN } } }, { NM_SETTING_WIRED_SETTING_NAME, { diff --git a/libnm/libnm.ver b/libnm/libnm.ver index e5ded29ac1..29dfba7b58 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -1347,6 +1347,8 @@ global: nm_client_get_checkpoints; nm_device_ip_tunnel_get_flags; nm_ip_tunnel_flags_get_type; + nm_setting_connection_get_mdns; + nm_setting_connection_mdns_get_type; nm_setting_ip_tunnel_get_flags; nm_setting_vpn_get_data_keys; nm_setting_vpn_get_secret_keys; diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c index d6be2f3a14..04fbc38772 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c @@ -181,7 +181,7 @@ make_connection_setting (const char *file, const char *v; gs_free char *stable_id = NULL; const char *const *iter; - int vint64; + int vint64, i_val; ifcfg_name = utils_get_ifcfg_name (file, TRUE); if (!ifcfg_name) @@ -321,6 +321,13 @@ make_connection_setting (const char *file, vint64 = svGetValueInt64 (ifcfg, "AUTH_RETRIES", 10, -1, G_MAXINT32, -1); g_object_set (s_con, NM_SETTING_CONNECTION_AUTH_RETRIES, (gint) vint64, NULL); + i_val = NM_SETTING_CONNECTION_MDNS_UNKNOWN; + if (!svGetValueEnum (ifcfg, "MDNS", + nm_setting_connection_mdns_get_type (), + &i_val, NULL)) { + } + g_object_set (s_con, NM_SETTING_CONNECTION_MDNS, i_val, NULL); + return NM_SETTING (s_con); } diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c index 9c49c97483..55eab7bfa8 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c @@ -1727,7 +1727,7 @@ write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg) guint32 n, i; GString *str; const char *master, *master_iface = NULL, *type; - gint vint; + gint vint, i_val; guint32 vuint32; const char *tmp; @@ -1882,6 +1882,14 @@ write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg) vint = nm_setting_connection_get_auth_retries (s_con); svSetValueInt64_cond (ifcfg, "AUTH_RETRIES", vint >= 0, vint); + + i_val = nm_setting_connection_get_mdns (s_con); + if (i_val != NM_SETTING_CONNECTION_MDNS_UNKNOWN) { + svSetValueEnum (ifcfg, "MDNS", nm_setting_connection_mdns_get_type (), + i_val); + } else { + svUnsetValue (ifcfg, "MDNS"); + } } static char * @@ -3182,4 +3190,3 @@ nms_ifcfg_rh_writer_can_write_connection (NMConnection *connection, GError **err NM_PRINT_FMT_QUOTE_STRING (type)); return FALSE; } - From 25906eda9e669c53d1e5c450fe423cc4360d25e3 Mon Sep 17 00:00:00 2001 From: Ismo Puustinen Date: Fri, 10 Nov 2017 14:49:47 +0200 Subject: [PATCH 04/18] 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. --- src/dns/nm-dns-manager.c | 196 +++++++++++++++++++++++++----- src/dns/nm-dns-manager.h | 17 +++ src/dns/nm-dns-plugin.c | 12 ++ src/dns/nm-dns-plugin.h | 9 ++ src/dns/nm-dns-systemd-resolved.c | 43 +++++++ src/nm-policy.c | 61 +++++++++- 6 files changed, 306 insertions(+), 32 deletions(-) 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 From eec907b35a1eb85f66cf9b9e031291354d7a0bc2 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 15 Dec 2017 12:11:53 +0100 Subject: [PATCH 05/18] libnm: verify value for connection.mdns Also, keep the internal variable of type int. The only way to set the field is via the GObject property setter. At that point, don't yet cast the integer type to enum. --- libnm-core/nm-setting-connection.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/libnm-core/nm-setting-connection.c b/libnm-core/nm-setting-connection.c index ba5bf8bf55..015aa68648 100644 --- a/libnm-core/nm-setting-connection.c +++ b/libnm-core/nm-setting-connection.c @@ -81,7 +81,7 @@ typedef struct { NMMetered metered; NMSettingConnectionLldp lldp; gint auth_retries; - NMSettingConnectionMdns mdns; + int mdns; } NMSettingConnectionPrivate; enum { @@ -1076,6 +1076,17 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) return FALSE; } + if ( priv->mdns < NM_SETTING_CONNECTION_MDNS_UNKNOWN + || priv->mdns > NM_SETTING_CONNECTION_MDNS_RESOLVE) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("mdns value %d is not valid"), priv->mdns); + g_prefix_error (error, "%s.%s: ", NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_MDNS); + return FALSE; + } + /* *** errors above here should be always fatal, below NORMALIZABLE_ERROR *** */ if (!priv->uuid) { From 9d92848ada434c9ffb8f55db2986514079f58fa3 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 15 Dec 2017 12:15:05 +0100 Subject: [PATCH 06/18] libnm: rename MDns flag UNKNOWN to DEFAULT "UNKNOWN" is not a good name. If you don't set the property in the connection explicitly, it should be "DEFAULT". Also, make "DEFAULT" -1. For one, that ensures that the enum's underlying integer type is signed. Otherwise, it's cumbersome to test "if (mdns >= DEFAULT)" because in case of unsigned types, the compiler will warn about the check always being true. Also, it allows for "NO" to be zero. These are no strong reasons, but I tend to think this is better. Also, don't make the property of NMSettingConnection a CONSTRUCT property. Initialize the default manually in the init function. Also, order the numeric values so that DEFAULT < NO < RESOLVE < YES with YES being largest because it enables *the most*. --- libnm-core/nm-setting-connection.c | 10 ++++++---- libnm-core/nm-setting-connection.h | 14 +++++++------- src/dns/nm-dns-manager.c | 5 ++++- src/nm-policy.c | 15 ++++++++------- src/nm-types.h | 2 ++ .../plugins/ifcfg-rh/nms-ifcfg-rh-reader.c | 6 +++--- .../plugins/ifcfg-rh/nms-ifcfg-rh-writer.c | 9 +++++---- 7 files changed, 35 insertions(+), 26 deletions(-) diff --git a/libnm-core/nm-setting-connection.c b/libnm-core/nm-setting-connection.c index 015aa68648..470209a176 100644 --- a/libnm-core/nm-setting-connection.c +++ b/libnm-core/nm-setting-connection.c @@ -876,7 +876,7 @@ NMSettingConnectionMdns nm_setting_connection_get_mdns (NMSettingConnection *setting) { g_return_val_if_fail (NM_IS_SETTING_CONNECTION (setting), - NM_SETTING_CONNECTION_MDNS_UNKNOWN); + NM_SETTING_CONNECTION_MDNS_DEFAULT); return NM_SETTING_CONNECTION_GET_PRIVATE (setting)->mdns; } @@ -1076,7 +1076,7 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) return FALSE; } - if ( priv->mdns < NM_SETTING_CONNECTION_MDNS_UNKNOWN + if ( priv->mdns < NM_SETTING_CONNECTION_MDNS_DEFAULT || priv->mdns > NM_SETTING_CONNECTION_MDNS_RESOLVE) { g_set_error (error, NM_CONNECTION_ERROR, @@ -1244,6 +1244,9 @@ compare_property (NMSetting *setting, static void nm_setting_connection_init (NMSettingConnection *setting) { + NMSettingConnectionPrivate *priv = NM_SETTING_CONNECTION_GET_PRIVATE (setting); + + priv->mdns = NM_SETTING_CONNECTION_MDNS_DEFAULT; } static void @@ -2048,8 +2051,7 @@ nm_setting_connection_class_init (NMSettingConnectionClass *setting_class) (object_class, PROP_MDNS, g_param_spec_int (NM_SETTING_CONNECTION_MDNS, "", "", G_MININT32, G_MAXINT32, - NM_SETTING_CONNECTION_MDNS_UNKNOWN, + NM_SETTING_CONNECTION_MDNS_DEFAULT, G_PARAM_READWRITE | - G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS)); } diff --git a/libnm-core/nm-setting-connection.h b/libnm-core/nm-setting-connection.h index 6fd88a906d..cf083a48e1 100644 --- a/libnm-core/nm-setting-connection.h +++ b/libnm-core/nm-setting-connection.h @@ -100,20 +100,20 @@ typedef enum { /** * NMSettingConnectionMdns: - * @NM_SETTING_CONNECTION_MDNS_UNKNOWN: default value - * @NM_SETTING_CONNECTION_MDNS_YES: disable mDNS - * @NM_SETTING_CONNECTION_MDNS_NO: enable mDNS + * @NM_SETTING_CONNECTION_MDNS_DEFAULT: default value + * @NM_SETTING_CONNECTION_MDNS_NO: disable mDNS * @NM_SETTING_CONNECTION_MDNS_RESOLVE: support only resolving, do not register hostname + * @NM_SETTING_CONNECTION_MDNS_YES: enable mDNS * * #NMSettingConnectionMdns values indicate whether mDNS should be enabled. * * Since: 1.12 */ typedef enum { - NM_SETTING_CONNECTION_MDNS_UNKNOWN = 0, - NM_SETTING_CONNECTION_MDNS_YES = 1, - NM_SETTING_CONNECTION_MDNS_NO = 2, - NM_SETTING_CONNECTION_MDNS_RESOLVE = 3, + NM_SETTING_CONNECTION_MDNS_DEFAULT = -1, + NM_SETTING_CONNECTION_MDNS_NO = 0, + NM_SETTING_CONNECTION_MDNS_RESOLVE = 1, + NM_SETTING_CONNECTION_MDNS_YES = 2, } NMSettingConnectionMdns; /** diff --git a/src/dns/nm-dns-manager.c b/src/dns/nm-dns-manager.c index 6e2bdae8c8..889936f4b2 100644 --- a/src/dns/nm-dns-manager.c +++ b/src/dns/nm-dns-manager.c @@ -1445,7 +1445,10 @@ nm_dns_manager_add_connection_config (NMDnsManager *self, 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); + g_return_val_if_fail (NM_IN_SET (mdns, + NM_SETTING_CONNECTION_MDNS_NO, + NM_SETTING_CONNECTION_MDNS_YES, + NM_SETTING_CONNECTION_MDNS_RESOLVE), FALSE); priv = NM_DNS_MANAGER_GET_PRIVATE (self); plugin = priv->plugin; diff --git a/src/nm-policy.c b/src/nm-policy.c index 40bee9a588..dfc50a8463 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -1072,11 +1072,12 @@ add_connection_dns (NMPolicy *self, NMConnection *connection, const char *iface, if (s_con) { NMSettingConnectionMdns mdns = nm_setting_connection_get_mdns (s_con); - if (mdns != NM_SETTING_CONNECTION_MDNS_UNKNOWN) + if (mdns != NM_SETTING_CONNECTION_MDNS_DEFAULT) { nm_dns_manager_add_connection_config (NM_POLICY_GET_PRIVATE (self)->dns_manager, - iface, - ifindex, - mdns); + iface, + ifindex, + mdns); + } } } @@ -2163,9 +2164,9 @@ vpn_connection_deactivated (NMPolicy *self, NMVpnConnection *vpn) 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)); + remove_connection_dns (self, + nm_vpn_connection_get_ip_iface (vpn, TRUE), + nm_vpn_connection_get_ip_ifindex (vpn, TRUE)); } static void diff --git a/src/nm-types.h b/src/nm-types.h index 39510c3185..239202cf41 100644 --- a/src/nm-types.h +++ b/src/nm-types.h @@ -231,4 +231,6 @@ typedef struct _NMSettingsConnection NMSettingsConnection; /* utils */ typedef struct _NMUtilsIPv6IfaceId NMUtilsIPv6IfaceId; +#define NM_SETTING_CONNECTION_MDNS_UNKNOWN ((NMSettingConnectionMdns) -42) + #endif /* NM_TYPES_H */ diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c index 04fbc38772..400a7bd9b7 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c @@ -321,11 +321,11 @@ make_connection_setting (const char *file, vint64 = svGetValueInt64 (ifcfg, "AUTH_RETRIES", 10, -1, G_MAXINT32, -1); g_object_set (s_con, NM_SETTING_CONNECTION_AUTH_RETRIES, (gint) vint64, NULL); - i_val = NM_SETTING_CONNECTION_MDNS_UNKNOWN; + i_val = NM_SETTING_CONNECTION_MDNS_DEFAULT; if (!svGetValueEnum (ifcfg, "MDNS", nm_setting_connection_mdns_get_type (), - &i_val, NULL)) { - } + &i_val, NULL)) + PARSE_WARNING ("invalid MDNS setting"); g_object_set (s_con, NM_SETTING_CONNECTION_MDNS, i_val, NULL); return NM_SETTING (s_con); diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c index 55eab7bfa8..f326795254 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c @@ -1727,7 +1727,8 @@ write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg) guint32 n, i; GString *str; const char *master, *master_iface = NULL, *type; - gint vint, i_val; + gint vint; + NMSettingConnectionMdns mdns; guint32 vuint32; const char *tmp; @@ -1883,10 +1884,10 @@ write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg) vint = nm_setting_connection_get_auth_retries (s_con); svSetValueInt64_cond (ifcfg, "AUTH_RETRIES", vint >= 0, vint); - i_val = nm_setting_connection_get_mdns (s_con); - if (i_val != NM_SETTING_CONNECTION_MDNS_UNKNOWN) { + mdns = nm_setting_connection_get_mdns (s_con); + if (mdns != NM_SETTING_CONNECTION_MDNS_DEFAULT) { svSetValueEnum (ifcfg, "MDNS", nm_setting_connection_mdns_get_type (), - i_val); + mdns); } else { svUnsetValue (ifcfg, "MDNS"); } From 03cba938730bc19057e51131297bed672e47ae99 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 15 Dec 2017 13:18:31 +0100 Subject: [PATCH 07/18] dns/trivial: move code --- src/dns/nm-dns-dnsmasq.c | 90 ++++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/src/dns/nm-dns-dnsmasq.c b/src/dns/nm-dns-dnsmasq.c index 0665ea55d7..7b0eee1bb7 100644 --- a/src/dns/nm-dns-dnsmasq.c +++ b/src/dns/nm-dns-dnsmasq.c @@ -155,6 +155,51 @@ add_dnsmasq_nameserver (NMDnsDnsmasq *self, g_variant_builder_close (servers); } +static char * +ip6_addr_to_string (const struct in6_addr *addr, const char *iface) +{ + char buf[NM_UTILS_INET_ADDRSTRLEN]; + + if (IN6_IS_ADDR_V4MAPPED (addr)) + nm_utils_inet4_ntop (addr->s6_addr32[3], buf); + else + nm_utils_inet6_ntop (addr, buf); + + /* Need to scope link-local addresses with %. Before dnsmasq 2.58, + * only '@' was supported as delimiter. Since 2.58, '@' and '%' are + * supported. Due to a bug, since 2.73 only '%' works properly as "server" + * address. + */ + return g_strdup_printf ("%s%c%s", + buf, + IN6_IS_ADDR_LINKLOCAL (addr) ? '%' : '@', + iface); +} + +static void +add_global_config (NMDnsDnsmasq *self, GVariantBuilder *dnsmasq_servers, 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); + const char *name = nm_global_dns_domain_get_name (domain); + + g_return_if_fail (name); + + for (j = 0; servers && servers[j]; j++) { + if (!strcmp (name, "*")) + add_dnsmasq_nameserver (self, dnsmasq_servers, servers[j], NULL); + else + add_dnsmasq_nameserver (self, dnsmasq_servers, servers[j], name); + } + + } +} + static gboolean add_ip4_config (NMDnsDnsmasq *self, GVariantBuilder *servers, NMIP4Config *ip4, const char *iface, gboolean split) @@ -226,51 +271,6 @@ add_ip4_config (NMDnsDnsmasq *self, GVariantBuilder *servers, NMIP4Config *ip4, return TRUE; } -static char * -ip6_addr_to_string (const struct in6_addr *addr, const char *iface) -{ - char buf[NM_UTILS_INET_ADDRSTRLEN]; - - if (IN6_IS_ADDR_V4MAPPED (addr)) - nm_utils_inet4_ntop (addr->s6_addr32[3], buf); - else - nm_utils_inet6_ntop (addr, buf); - - /* Need to scope link-local addresses with %. Before dnsmasq 2.58, - * only '@' was supported as delimiter. Since 2.58, '@' and '%' are - * supported. Due to a bug, since 2.73 only '%' works properly as "server" - * address. - */ - return g_strdup_printf ("%s%c%s", - buf, - IN6_IS_ADDR_LINKLOCAL (addr) ? '%' : '@', - iface); -} - -static void -add_global_config (NMDnsDnsmasq *self, GVariantBuilder *dnsmasq_servers, 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); - const char *name = nm_global_dns_domain_get_name (domain); - - g_return_if_fail (name); - - for (j = 0; servers && servers[j]; j++) { - if (!strcmp (name, "*")) - add_dnsmasq_nameserver (self, dnsmasq_servers, servers[j], NULL); - else - add_dnsmasq_nameserver (self, dnsmasq_servers, servers[j], name); - } - - } -} - static gboolean add_ip6_config (NMDnsDnsmasq *self, GVariantBuilder *servers, NMIP6Config *ip6, const char *iface, gboolean split) From 49fd1e412617ffcdd10d6f1f76f387bba71ae9d8 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 15 Dec 2017 13:17:22 +0100 Subject: [PATCH 08/18] dns: merge IPv4 and IPv6 versions of add_ip_config() (part 1) --- src/dns/nm-dns-dnsmasq.c | 251 +++++++++++++++++++-------------------- 1 file changed, 122 insertions(+), 129 deletions(-) diff --git a/src/dns/nm-dns-dnsmasq.c b/src/dns/nm-dns-dnsmasq.c index 7b0eee1bb7..983565a4a0 100644 --- a/src/dns/nm-dns-dnsmasq.c +++ b/src/dns/nm-dns-dnsmasq.c @@ -201,144 +201,146 @@ add_global_config (NMDnsDnsmasq *self, GVariantBuilder *dnsmasq_servers, const N } static gboolean -add_ip4_config (NMDnsDnsmasq *self, GVariantBuilder *servers, NMIP4Config *ip4, - const char *iface, gboolean split) +add_ip_config (NMDnsDnsmasq *self, + GVariantBuilder *servers, + NMIPConfig *ip_config, + const char *iface, + gboolean split) { - char buf[INET_ADDRSTRLEN + 1 + IFNAMSIZ]; - char buf2[INET_ADDRSTRLEN]; - in_addr_t addr; - int nnameservers, i_nameserver, n, i; - gboolean added = FALSE; + int addr_family = nm_ip_config_get_addr_family (ip_config); - g_return_val_if_fail (iface, FALSE); - nnameservers = nm_ip4_config_get_num_nameservers (ip4); + if (addr_family == AF_INET) { + NMIP4Config *ip4 = (NMIP4Config *) ip_config; + char buf[INET_ADDRSTRLEN + 1 + IFNAMSIZ]; + char buf2[INET_ADDRSTRLEN]; + in_addr_t addr; + int nnameservers, i_nameserver, n, i; + gboolean added = FALSE; - if (split) { - char **domains, **iter; + g_return_val_if_fail (iface, FALSE); + nnameservers = nm_ip4_config_get_num_nameservers (ip4); - if (nnameservers == 0) - return FALSE; + if (split) { + char **domains, **iter; - for (i_nameserver = 0; i_nameserver < nnameservers; i_nameserver++) { - addr = nm_ip4_config_get_nameserver (ip4, i_nameserver); - g_snprintf (buf, sizeof (buf), "%s@%s", - nm_utils_inet4_ntop (addr, buf2), iface); + if (nnameservers == 0) + return FALSE; - /* searches are preferred over domains */ - n = nm_ip4_config_get_num_searches (ip4); - for (i = 0; i < n; i++) { - add_dnsmasq_nameserver (self, - servers, - buf, - nm_ip4_config_get_search (ip4, i)); - added = TRUE; - } + for (i_nameserver = 0; i_nameserver < nnameservers; i_nameserver++) { + addr = nm_ip4_config_get_nameserver (ip4, i_nameserver); + g_snprintf (buf, sizeof (buf), "%s@%s", + nm_utils_inet4_ntop (addr, buf2), iface); - if (n == 0) { - /* If not searches, use any domains */ - n = nm_ip4_config_get_num_domains (ip4); + /* searches are preferred over domains */ + n = nm_ip4_config_get_num_searches (ip4); for (i = 0; i < n; i++) { add_dnsmasq_nameserver (self, servers, buf, - nm_ip4_config_get_domain (ip4, i)); + nm_ip4_config_get_search (ip4, i)); added = TRUE; } - } - /* Ensure reverse-DNS works by directing queries for in-addr.arpa - * domains to the split domain's nameserver. - */ - domains = get_ip4_rdns_domains (ip4); - if (domains) { - for (iter = domains; iter && *iter; iter++) - add_dnsmasq_nameserver (self, servers, buf, *iter); - g_strfreev (domains); - } - } - } + if (n == 0) { + /* If not searches, use any domains */ + n = nm_ip4_config_get_num_domains (ip4); + for (i = 0; i < n; i++) { + add_dnsmasq_nameserver (self, + servers, + buf, + nm_ip4_config_get_domain (ip4, i)); + added = TRUE; + } + } - /* If no searches or domains, just add the nameservers */ - if (!added) { - for (i = 0; i < nnameservers; i++) { - addr = nm_ip4_config_get_nameserver (ip4, i); - g_snprintf (buf, sizeof (buf), "%s@%s", - nm_utils_inet4_ntop (addr, buf2), iface); - add_dnsmasq_nameserver (self, servers, buf, NULL); - } - } - - return TRUE; -} - -static gboolean -add_ip6_config (NMDnsDnsmasq *self, GVariantBuilder *servers, NMIP6Config *ip6, - const char *iface, gboolean split) -{ - const struct in6_addr *addr; - char *buf = NULL; - int nnameservers, i_nameserver, n, i; - gboolean added = FALSE; - - g_return_val_if_fail (iface, FALSE); - nnameservers = nm_ip6_config_get_num_nameservers (ip6); - - if (split) { - char **domains, **iter; - - if (nnameservers == 0) - return FALSE; - - for (i_nameserver = 0; i_nameserver < nnameservers; i_nameserver++) { - addr = nm_ip6_config_get_nameserver (ip6, i_nameserver); - buf = ip6_addr_to_string (addr, iface); - - /* searches are preferred over domains */ - n = nm_ip6_config_get_num_searches (ip6); - for (i = 0; i < n; i++) { - add_dnsmasq_nameserver (self, - servers, - buf, - nm_ip6_config_get_search (ip6, i)); - added = TRUE; - } - - if (n == 0) { - /* If not searches, use any domains */ - n = nm_ip6_config_get_num_domains (ip6); - for (i = 0; i < n; i++) { - add_dnsmasq_nameserver (self, - servers, - buf, - nm_ip6_config_get_domain (ip6, i)); - added = TRUE; + /* Ensure reverse-DNS works by directing queries for in-addr.arpa + * domains to the split domain's nameserver. + */ + domains = get_ip4_rdns_domains (ip4); + if (domains) { + for (iter = domains; iter && *iter; iter++) + add_dnsmasq_nameserver (self, servers, buf, *iter); + g_strfreev (domains); } } - - /* Ensure reverse-DNS works by directing queries for ip6.arpa - * domains to the split domain's nameserver. - */ - domains = get_ip6_rdns_domains (ip6); - if (domains) { - for (iter = domains; iter && *iter; iter++) - add_dnsmasq_nameserver (self, servers, buf, *iter); - g_strfreev (domains); - } - - g_free (buf); } - } - /* If no searches or domains, just add the nameservers */ - if (!added) { - for (i = 0; i < nnameservers; i++) { - addr = nm_ip6_config_get_nameserver (ip6, i); - buf = ip6_addr_to_string (addr, iface); - if (buf) { + /* If no searches or domains, just add the nameservers */ + if (!added) { + for (i = 0; i < nnameservers; i++) { + addr = nm_ip4_config_get_nameserver (ip4, i); + g_snprintf (buf, sizeof (buf), "%s@%s", + nm_utils_inet4_ntop (addr, buf2), iface); add_dnsmasq_nameserver (self, servers, buf, NULL); + } + } + } else { + NMIP6Config *ip6 = (NMIP6Config *) ip_config; + const struct in6_addr *addr; + char *buf = NULL; + int nnameservers, i_nameserver, n, i; + gboolean added = FALSE; + + g_return_val_if_fail (iface, FALSE); + nnameservers = nm_ip6_config_get_num_nameservers (ip6); + + if (split) { + char **domains, **iter; + + if (nnameservers == 0) + return FALSE; + + for (i_nameserver = 0; i_nameserver < nnameservers; i_nameserver++) { + addr = nm_ip6_config_get_nameserver (ip6, i_nameserver); + buf = ip6_addr_to_string (addr, iface); + + /* searches are preferred over domains */ + n = nm_ip6_config_get_num_searches (ip6); + for (i = 0; i < n; i++) { + add_dnsmasq_nameserver (self, + servers, + buf, + nm_ip6_config_get_search (ip6, i)); + added = TRUE; + } + + if (n == 0) { + /* If not searches, use any domains */ + n = nm_ip6_config_get_num_domains (ip6); + for (i = 0; i < n; i++) { + add_dnsmasq_nameserver (self, + servers, + buf, + nm_ip6_config_get_domain (ip6, i)); + added = TRUE; + } + } + + /* Ensure reverse-DNS works by directing queries for ip6.arpa + * domains to the split domain's nameserver. + */ + domains = get_ip6_rdns_domains (ip6); + if (domains) { + for (iter = domains; iter && *iter; iter++) + add_dnsmasq_nameserver (self, servers, buf, *iter); + g_strfreev (domains); + } + g_free (buf); } } + + /* If no searches or domains, just add the nameservers */ + if (!added) { + for (i = 0; i < nnameservers; i++) { + addr = nm_ip6_config_get_nameserver (ip6, i); + buf = ip6_addr_to_string (addr, iface); + if (buf) { + add_dnsmasq_nameserver (self, servers, buf, NULL); + g_free (buf); + } + } + } } return TRUE; @@ -347,20 +349,11 @@ add_ip6_config (NMDnsDnsmasq *self, GVariantBuilder *servers, NMIP6Config *ip6, static gboolean add_ip_config_data (NMDnsDnsmasq *self, GVariantBuilder *servers, const NMDnsIPConfigData *data) { - if (NM_IS_IP4_CONFIG (data->config)) { - return add_ip4_config (self, - servers, - (NMIP4Config *) data->config, - data->iface, - data->type == NM_DNS_IP_CONFIG_TYPE_VPN); - } else if (NM_IS_IP6_CONFIG (data->config)) { - return add_ip6_config (self, - servers, - (NMIP6Config *) data->config, - data->iface, - data->type == NM_DNS_IP_CONFIG_TYPE_VPN); - } else - g_return_val_if_reached (FALSE); + return add_ip_config (self, + servers, + data->config, + data->iface, + data->type == NM_DNS_IP_CONFIG_TYPE_VPN); } static void From 7d4def276400c3b28ff8c3f96e6791659f5bd0a9 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 15 Dec 2017 13:24:21 +0100 Subject: [PATCH 09/18] dns: merge IPv4 and IPv6 versions of add_ip_config() (part 2) --- src/dns/nm-dns-dnsmasq.c | 274 +++++++++++++++------------------------ 1 file changed, 105 insertions(+), 169 deletions(-) diff --git a/src/dns/nm-dns-dnsmasq.c b/src/dns/nm-dns-dnsmasq.c index 983565a4a0..2e1c9fbe78 100644 --- a/src/dns/nm-dns-dnsmasq.c +++ b/src/dns/nm-dns-dnsmasq.c @@ -76,54 +76,41 @@ G_DEFINE_TYPE (NMDnsDnsmasq, nm_dns_dnsmasq, NM_TYPE_DNS_PLUGIN) /*****************************************************************************/ static char ** -get_ip4_rdns_domains (NMIP4Config *ip4) +get_ip_rdns_domains (NMIPConfig *ip_config) { + int addr_family = nm_ip_config_get_addr_family (ip_config); char **strv; GPtrArray *domains = NULL; NMDedupMultiIter ipconf_iter; - const NMPlatformIP4Address *address; - const NMPlatformIP4Route *route; - g_return_val_if_fail (ip4 != NULL, NULL); + nm_assert_addr_family (addr_family); domains = g_ptr_array_sized_new (5); - nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, ip4, &address) - nm_utils_get_reverse_dns_domains_ip4 (address->address, address->plen, domains); + if (addr_family == AF_INET) { + NMIP4Config *ip4 = (gpointer) ip_config; + const NMPlatformIP4Address *address; + const NMPlatformIP4Route *route; - nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, ip4, &route) { - if (!NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) - nm_utils_get_reverse_dns_domains_ip4 (route->network, route->plen, domains); - } + nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, ip4, &address) + nm_utils_get_reverse_dns_domains_ip4 (address->address, address->plen, domains); - /* Terminating NULL so we can use g_strfreev() to free it */ - g_ptr_array_add (domains, NULL); + nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, ip4, &route) { + if (!NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) + nm_utils_get_reverse_dns_domains_ip4 (route->network, route->plen, domains); + } + } else { + NMIP6Config *ip6 = (gpointer) ip_config; + const NMPlatformIP6Address *address; + const NMPlatformIP6Route *route; - /* Free the array and return NULL if the only element was the ending NULL */ - strv = (char **) g_ptr_array_free (domains, (domains->len == 1)); + nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, ip6, &address) + nm_utils_get_reverse_dns_domains_ip6 (&address->address, address->plen, domains); - return _nm_utils_strv_cleanup (strv, FALSE, FALSE, TRUE); -} - -static char ** -get_ip6_rdns_domains (NMIP6Config *ip6) -{ - char **strv; - GPtrArray *domains = NULL; - NMDedupMultiIter ipconf_iter; - const NMPlatformIP6Address *address; - const NMPlatformIP6Route *route; - - g_return_val_if_fail (ip6 != NULL, NULL); - - domains = g_ptr_array_sized_new (5); - - nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, ip6, &address) - nm_utils_get_reverse_dns_domains_ip6 (&address->address, address->plen, domains); - - nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, ip6, &route) { - if (!NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) - nm_utils_get_reverse_dns_domains_ip6 (&route->network, route->plen, domains); + nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, ip6, &route) { + if (!NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) + nm_utils_get_reverse_dns_domains_ip6 (&route->network, route->plen, domains); + } } /* Terminating NULL so we can use g_strfreev() to free it */ @@ -155,25 +142,44 @@ add_dnsmasq_nameserver (NMDnsDnsmasq *self, g_variant_builder_close (servers); } -static char * -ip6_addr_to_string (const struct in6_addr *addr, const char *iface) +#define IP_ADDR_TO_STRING_BUFLEN (NM_UTILS_INET_ADDRSTRLEN + 1 + IFNAMSIZ) + +static const char * +ip_addr_to_string (int addr_family, gconstpointer addr, const char *iface, char *out_buf) { - char buf[NM_UTILS_INET_ADDRSTRLEN]; + int n_written; + char buf2[NM_UTILS_INET_ADDRSTRLEN]; + char separator; - if (IN6_IS_ADDR_V4MAPPED (addr)) - nm_utils_inet4_ntop (addr->s6_addr32[3], buf); - else - nm_utils_inet6_ntop (addr, buf); + nm_assert_addr_family (addr_family); + nm_assert (addr); + nm_assert (iface); + nm_assert (out_buf); - /* Need to scope link-local addresses with %. Before dnsmasq 2.58, - * only '@' was supported as delimiter. Since 2.58, '@' and '%' are - * supported. Due to a bug, since 2.73 only '%' works properly as "server" - * address. - */ - return g_strdup_printf ("%s%c%s", - buf, - IN6_IS_ADDR_LINKLOCAL (addr) ? '%' : '@', + if (addr_family == AF_INET) { + nm_utils_inet_ntop (addr_family, addr, buf2); + separator = '@'; + } else { + if (IN6_IS_ADDR_V4MAPPED (addr)) + nm_utils_inet4_ntop (((const struct in6_addr *) addr)->s6_addr32[3], buf2); + else + nm_utils_inet6_ntop (addr, buf2); + /* Need to scope link-local addresses with %. Before dnsmasq 2.58, + * only '@' was supported as delimiter. Since 2.58, '@' and '%' are + * supported. Due to a bug, since 2.73 only '%' works properly as "server" + * address. + */ + separator = IN6_IS_ADDR_LINKLOCAL (addr) ? '%' : '@'; + } + + n_written = g_snprintf (out_buf, + IP_ADDR_TO_STRING_BUFLEN, + "%s%c%s", + buf2, + separator, iface); + nm_assert (n_written < IP_ADDR_TO_STRING_BUFLEN); + return out_buf; } static void @@ -207,139 +213,69 @@ add_ip_config (NMDnsDnsmasq *self, const char *iface, gboolean split) { - int addr_family = nm_ip_config_get_addr_family (ip_config); + int addr_family; + gconstpointer addr; + gboolean added = FALSE; + guint nnameservers, i_nameserver, n, i; + char ip_addr_to_string_buf[IP_ADDR_TO_STRING_BUFLEN]; + char **domains, **iter; - if (addr_family == AF_INET) { - NMIP4Config *ip4 = (NMIP4Config *) ip_config; - char buf[INET_ADDRSTRLEN + 1 + IFNAMSIZ]; - char buf2[INET_ADDRSTRLEN]; - in_addr_t addr; - int nnameservers, i_nameserver, n, i; - gboolean added = FALSE; + g_return_val_if_fail (iface, FALSE); - g_return_val_if_fail (iface, FALSE); - nnameservers = nm_ip4_config_get_num_nameservers (ip4); + addr_family = nm_ip_config_get_addr_family (ip_config); + g_return_val_if_fail (NM_IN_SET (addr_family, AF_INET, AF_INET6), FALSE); - if (split) { - char **domains, **iter; + nnameservers = nm_ip_config_get_num_nameservers (ip_config); - if (nnameservers == 0) - return FALSE; + if (split) { + if (nnameservers == 0) + return FALSE; - for (i_nameserver = 0; i_nameserver < nnameservers; i_nameserver++) { - addr = nm_ip4_config_get_nameserver (ip4, i_nameserver); - g_snprintf (buf, sizeof (buf), "%s@%s", - nm_utils_inet4_ntop (addr, buf2), iface); + for (i_nameserver = 0; i_nameserver < nnameservers; i_nameserver++) { + addr = nm_ip_config_get_nameserver (ip_config, i_nameserver); - /* searches are preferred over domains */ - n = nm_ip4_config_get_num_searches (ip4); + ip_addr_to_string (addr_family, addr, iface, ip_addr_to_string_buf); + + /* searches are preferred over domains */ + n = nm_ip_config_get_num_searches (ip_config); + for (i = 0; i < n; i++) { + add_dnsmasq_nameserver (self, + servers, + ip_addr_to_string_buf, + nm_ip_config_get_search (ip_config, i)); + added = TRUE; + } + + if (n == 0) { + /* If not searches, use any domains */ + n = nm_ip_config_get_num_domains (ip_config); for (i = 0; i < n; i++) { add_dnsmasq_nameserver (self, servers, - buf, - nm_ip4_config_get_search (ip4, i)); + ip_addr_to_string_buf, + nm_ip_config_get_domain (ip_config, i)); added = TRUE; } + } - if (n == 0) { - /* If not searches, use any domains */ - n = nm_ip4_config_get_num_domains (ip4); - for (i = 0; i < n; i++) { - add_dnsmasq_nameserver (self, - servers, - buf, - nm_ip4_config_get_domain (ip4, i)); - added = TRUE; - } - } - - /* Ensure reverse-DNS works by directing queries for in-addr.arpa - * domains to the split domain's nameserver. - */ - domains = get_ip4_rdns_domains (ip4); - if (domains) { - for (iter = domains; iter && *iter; iter++) - add_dnsmasq_nameserver (self, servers, buf, *iter); - g_strfreev (domains); - } + /* Ensure reverse-DNS works by directing queries for in-addr4.arpa/ip6.arpa + * domains to the split domain's nameserver. + */ + domains = get_ip_rdns_domains (ip_config); + if (domains) { + for (iter = domains; *iter; iter++) + add_dnsmasq_nameserver (self, servers, ip_addr_to_string_buf, *iter); + g_strfreev (domains); } } + } - /* If no searches or domains, just add the nameservers */ - if (!added) { - for (i = 0; i < nnameservers; i++) { - addr = nm_ip4_config_get_nameserver (ip4, i); - g_snprintf (buf, sizeof (buf), "%s@%s", - nm_utils_inet4_ntop (addr, buf2), iface); - add_dnsmasq_nameserver (self, servers, buf, NULL); - } - } - } else { - NMIP6Config *ip6 = (NMIP6Config *) ip_config; - const struct in6_addr *addr; - char *buf = NULL; - int nnameservers, i_nameserver, n, i; - gboolean added = FALSE; - - g_return_val_if_fail (iface, FALSE); - nnameservers = nm_ip6_config_get_num_nameservers (ip6); - - if (split) { - char **domains, **iter; - - if (nnameservers == 0) - return FALSE; - - for (i_nameserver = 0; i_nameserver < nnameservers; i_nameserver++) { - addr = nm_ip6_config_get_nameserver (ip6, i_nameserver); - buf = ip6_addr_to_string (addr, iface); - - /* searches are preferred over domains */ - n = nm_ip6_config_get_num_searches (ip6); - for (i = 0; i < n; i++) { - add_dnsmasq_nameserver (self, - servers, - buf, - nm_ip6_config_get_search (ip6, i)); - added = TRUE; - } - - if (n == 0) { - /* If not searches, use any domains */ - n = nm_ip6_config_get_num_domains (ip6); - for (i = 0; i < n; i++) { - add_dnsmasq_nameserver (self, - servers, - buf, - nm_ip6_config_get_domain (ip6, i)); - added = TRUE; - } - } - - /* Ensure reverse-DNS works by directing queries for ip6.arpa - * domains to the split domain's nameserver. - */ - domains = get_ip6_rdns_domains (ip6); - if (domains) { - for (iter = domains; iter && *iter; iter++) - add_dnsmasq_nameserver (self, servers, buf, *iter); - g_strfreev (domains); - } - - g_free (buf); - } - } - - /* If no searches or domains, just add the nameservers */ - if (!added) { - for (i = 0; i < nnameservers; i++) { - addr = nm_ip6_config_get_nameserver (ip6, i); - buf = ip6_addr_to_string (addr, iface); - if (buf) { - add_dnsmasq_nameserver (self, servers, buf, NULL); - g_free (buf); - } - } + /* If no searches or domains, just add the nameservers */ + if (!added) { + for (i = 0; i < nnameservers; i++) { + addr = nm_ip_config_get_nameserver (ip_config, i); + ip_addr_to_string (addr_family, addr, iface, ip_addr_to_string_buf); + add_dnsmasq_nameserver (self, servers, ip_addr_to_string_buf, NULL); } } From 4ccfa7a79a2c3a10e39a8dea203cb0e51e603e80 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 19 Dec 2017 15:08:32 +0100 Subject: [PATCH 10/18] core: add nm_ip_config_get_ifindex() helper --- src/nm-ip4-config.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h index 59581b87bd..4f541ce000 100644 --- a/src/nm-ip4-config.h +++ b/src/nm-ip4-config.h @@ -373,6 +373,12 @@ nm_ip_config_get_addr_family (const NMIPConfig *config) } \ } G_STMT_END +static inline int +nm_ip_config_get_ifindex (const NMIPConfig *self) +{ + _NM_IP_CONFIG_DISPATCH (self, nm_ip4_config_get_ifindex, nm_ip6_config_get_ifindex); +} + static inline void nm_ip_config_add_address (NMIPConfig *self, const NMPlatformIPAddress *address) { From 2aad517b0b3b29615d1afdc907107a24cca6e1f2 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 19 Dec 2017 14:27:18 +0100 Subject: [PATCH 11/18] shared: add NMCListElem Sometimes, we want to use CList to track a simple data item. But contrary to GList/GSList, we need to define a structure to hold the data pointer and the CList member. Add a generic NMCListElem type that can be used for such simple uses. Before you ask: why not use GList/GSList? Because even simple operations like g_list_append() is O(n), which kinda defeats the purpose of having a doubly linked list. This code is added to a new header file nm-c-list.h, the reason is that there is no other good place: - "nm-utils/c-list.h" is a clone of upstream, it should not deviate. - "nm-utils/c-list-util.h" contains our utils functions for c-list.h but should be plain C, independent of glib. - "nm-utils/nm-shared-utils.h" contains our glib related utilities, but it should not drag in "c-list.h". So, "nm-c-list.h" is a utility libray that extends "c-list.h" and requires glib. --- Makefile.am | 1 + shared/nm-utils/nm-c-list.h | 74 +++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 shared/nm-utils/nm-c-list.h diff --git a/Makefile.am b/Makefile.am index 32303b2f79..c5d4f0ac28 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4498,6 +4498,7 @@ EXTRA_DIST += \ shared/nm-utils/c-list-util.c \ shared/nm-utils/c-list-util.h \ shared/nm-utils/gsystem-local-alloc.h \ + shared/nm-utils/nm-c-list.h \ shared/nm-utils/nm-compat.c \ shared/nm-utils/nm-compat.h \ shared/nm-utils/nm-glib.h \ diff --git a/shared/nm-utils/nm-c-list.h b/shared/nm-utils/nm-c-list.h new file mode 100644 index 0000000000..8352711899 --- /dev/null +++ b/shared/nm-utils/nm-c-list.h @@ -0,0 +1,74 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * (C) Copyright 2014 Red Hat, Inc. + */ + +#ifndef __NM_C_LIST_H__ +#define __NM_C_LIST_H__ + +#include "c-list.h" + +/*****************************************************************************/ + +typedef struct { + CList lst; + void *data; +} NMCListElem; + +static inline NMCListElem * +nm_c_list_elem_new_stale (void *data) +{ + NMCListElem *elem; + + elem = g_slice_new (NMCListElem); + elem->data = data; + return elem; +} + +static inline void * +nm_c_list_elem_get (CList *lst) +{ + if (!lst) + return NULL; + return c_list_entry (lst, NMCListElem, lst)->data; +} + +static inline void +nm_c_list_elem_free (NMCListElem *elem) +{ + if (elem) { + c_list_unlink_stale (&elem->lst); + g_slice_free (NMCListElem, elem); + } +} + +static inline void +nm_c_list_elem_free_all (CList *head, GDestroyNotify free_fcn) +{ + NMCListElem *elem; + + while ((elem = c_list_first_entry (head, NMCListElem, lst))) { + if (free_fcn) + free_fcn (elem->data); + c_list_unlink_stale (&elem->lst); + g_slice_free (NMCListElem, elem); + } +} + +#endif /* __NM_C_LIST_H__ */ From 901aa0315b592bc5f897b5abce05a5eed2ee3cad Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 8 Jan 2018 14:40:16 +0100 Subject: [PATCH 12/18] shared: add nm_cmp_int2ptr_p_with_data() helper A cmp() implementation, for sorting an array with pointers, where each pointer is an inteter according to GPOINTER_TO_INT(). That cames for example handy, if you have a GHashTable with keys GINT_TO_POINTER(). Then you get the list of keys via g_hash_table_get_keys_as_array() and want to sort them. --- shared/nm-utils/nm-macros-internal.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/shared/nm-utils/nm-macros-internal.h b/shared/nm-utils/nm-macros-internal.h index 4ee59f195e..852a87df5b 100644 --- a/shared/nm-utils/nm-macros-internal.h +++ b/shared/nm-utils/nm-macros-internal.h @@ -1049,6 +1049,25 @@ nm_cmp_uint32_p_with_data (gconstpointer p_a, gconstpointer p_b, gpointer user_d return 0; } +static inline int +nm_cmp_int2ptr_p_with_data (gconstpointer p_a, gconstpointer p_b, gpointer user_data) +{ + /* p_a and p_b are two pointers to a pointer, where the pointer is + * interpreted as a integer using GPOINTER_TO_INT(). + * + * That is the case of a hash-table that uses GINT_TO_POINTER() to + * convert integers as pointers, and the resulting keys-as-array + * array. */ + const int a = GPOINTER_TO_INT (*((gconstpointer *) p_a)); + const int b = GPOINTER_TO_INT (*((gconstpointer *) p_b)); + + if (a < b) + return -1; + if (a > b) + return 1; + return 0; +} + /*****************************************************************************/ /* Taken from systemd's UNIQ_T and UNIQ macros. */ From 4be4a3c21f63c53db4cd8ef02cd9e05c86f11b20 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 19 Dec 2017 15:07:53 +0100 Subject: [PATCH 13/18] dns: refactor update() in NMDnsSystemdResolved to use a hash table Use a GHashTable instead of a GArray to construct the list of @interfaces. Also, use NMCListElem instead of GList. With this, the runtime is O(n*log(n)) instead of O(n^2). I belive, we should take care that all our code has a reasonable runtime complexity, even in common use-cases the number of elements is small. This is not about performace, because likely we expect few entries anyway, and the direct GArray implementation is likely faster in those cases. It's about using the data structure that best suits the access pattern. The log(n) part comes from sorting the keys. I also believe we should always aim for a stable behavior. When sending the D-Bus request to resolved, the order of elements should be in ~some~ defined order. --- src/dns/nm-dns-systemd-resolved.c | 92 +++++++++++++++---------------- 1 file changed, 45 insertions(+), 47 deletions(-) diff --git a/src/dns/nm-dns-systemd-resolved.c b/src/dns/nm-dns-systemd-resolved.c index 8dd395d291..f37a1e7497 100644 --- a/src/dns/nm-dns-systemd-resolved.c +++ b/src/dns/nm-dns-systemd-resolved.c @@ -31,6 +31,7 @@ #include #include +#include "nm-utils/nm-c-list.h" #include "nm-core-internal.h" #include "platform/nm-platform.h" #include "nm-utils.h" @@ -49,7 +50,7 @@ typedef struct { int ifindex; - GList *configs; + CList configs_lst_head; } InterfaceConfig; /*****************************************************************************/ @@ -83,6 +84,13 @@ G_DEFINE_TYPE (NMDnsSystemdResolved, nm_dns_systemd_resolved, NM_TYPE_DNS_PLUGIN /*****************************************************************************/ +static void +_interface_config_free (InterfaceConfig *config) +{ + nm_c_list_elem_free_all (&config->configs_lst_head, NULL); + g_slice_free (InterfaceConfig, config); +} + static void call_done (GObject *source, GAsyncResult *r, gpointer user_data) { @@ -99,42 +107,6 @@ call_done (GObject *source, GAsyncResult *r, gpointer user_data) } } -static void -add_interface_configuration (NMDnsSystemdResolved *self, - GArray *interfaces, - const NMDnsIPConfigData *data, - gboolean skip) -{ - int i; - InterfaceConfig *ic = NULL; - int ifindex; - - if (NM_IS_IP4_CONFIG (data->config)) - ifindex = nm_ip4_config_get_ifindex (data->config); - else if (NM_IS_IP6_CONFIG (data->config)) - ifindex = nm_ip6_config_get_ifindex (data->config); - else - g_return_if_reached (); - - for (i = 0; i < interfaces->len; i++) { - InterfaceConfig *tic = &g_array_index (interfaces, InterfaceConfig, i); - if (ifindex == tic->ifindex) { - ic = tic; - break; - } - } - - if (!ic) { - g_array_set_size (interfaces, interfaces->len + 1); - ic = &g_array_index (interfaces, InterfaceConfig, - interfaces->len - 1); - ic->ifindex = ifindex; - } - - if (!skip) - ic->configs = g_list_append (ic->configs, data->config); -} - static void update_add_ip_config (NMDnsSystemdResolved *self, GVariantBuilder *dns, @@ -227,7 +199,7 @@ prepare_one_interface (NMDnsSystemdResolved *self, InterfaceConfig *ic) { NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE (self); GVariantBuilder dns, domains; - GList *l; + NMCListElem *elem; g_variant_builder_init (&dns, G_VARIANT_TYPE ("(ia(iay))")); g_variant_builder_add (&dns, "i", ic->ifindex); @@ -237,8 +209,8 @@ prepare_one_interface (NMDnsSystemdResolved *self, InterfaceConfig *ic) g_variant_builder_add (&domains, "i", ic->ifindex); g_variant_builder_open (&domains, G_VARIANT_TYPE ("a(sb)")); - for (l = ic->configs; l; l = l->next) - update_add_ip_config (self, &dns, &domains, l->data); + c_list_for_each_entry (elem, &ic->configs_lst_head, lst) + update_add_ip_config (self, &dns, &domains, elem->data); g_variant_builder_close (&dns); g_variant_builder_close (&domains); @@ -284,33 +256,59 @@ update (NMDnsPlugin *plugin, const char *hostname) { NMDnsSystemdResolved *self = NM_DNS_SYSTEMD_RESOLVED (plugin); - GArray *interfaces = g_array_new (TRUE, TRUE, sizeof (InterfaceConfig)); + gs_unref_hashtable GHashTable *interfaces = NULL; + gs_free gpointer *interfaces_keys = NULL; + guint interfaces_len; guint i; int prio, first_prio = 0; + interfaces = g_hash_table_new_full (nm_direct_hash, NULL, + NULL, (GDestroyNotify) _interface_config_free); + for (i = 0; i < configs->len; i++) { const NMDnsIPConfigData *data = configs->pdata[i]; gboolean skip = FALSE; + InterfaceConfig *ic = NULL; + int ifindex; prio = nm_ip_config_get_dns_priority (data->config); if (i == 0) first_prio = prio; else if (first_prio < 0 && first_prio != prio) skip = TRUE; - add_interface_configuration (self, interfaces, data, skip); + + ifindex = nm_ip_config_get_ifindex (data->config); + + ic = g_hash_table_lookup (interfaces, GINT_TO_POINTER (ifindex)); + if (!ic) { + ic = g_slice_new (InterfaceConfig); + ic->ifindex = ifindex; + c_list_init (&ic->configs_lst_head); + g_hash_table_insert (interfaces, GINT_TO_POINTER (ifindex), ic); + } + + if (!skip) { + c_list_link_tail (&ic->configs_lst_head, + &nm_c_list_elem_new_stale (data->config)->lst); + } } free_pending_updates (self); - for (i = 0; i < interfaces->len; i++) { - InterfaceConfig *ic = &g_array_index (interfaces, InterfaceConfig, i); + interfaces_keys = g_hash_table_get_keys_as_array (interfaces, &interfaces_len); + if (interfaces_len > 1) { + g_qsort_with_data (interfaces_keys, + interfaces_len, + sizeof (gpointer), + nm_cmp_int2ptr_p_with_data, + NULL); + } + for (i = 0; i < interfaces_len; i++) { + InterfaceConfig *ic = g_hash_table_lookup (interfaces, GINT_TO_POINTER (interfaces_keys[i])); prepare_one_interface (self, ic); - g_list_free (ic->configs); } - g_array_free (interfaces, TRUE); - send_updates (self); return TRUE; From b0f1a54c9bf0d4132a1e3f4b073be8d1d3387dde Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 20 Dec 2017 16:34:00 +0100 Subject: [PATCH 14/18] dns: rework pending request-queue in NMDnsSystemdResolved We had two separate queues, one for "SetLinkDNS" and one for "SetLinkDomains". Merge them into one, and track the operation as part of the new RequestItem structure. A visible change to before is that we now would make all requests per-interface first. Prevously, we would first make all SetLinkDNS requests (for all interfaces) and then all SetLinkDomains requests. It feels more correct to order the requests this way, not by type. The reason to merge is, that we will next get another operation and in the current scheme we would need 3 GQueue instances. While at it, refactor the code to use CList. We now anyway would need a new struct to track the operation, requiring to allocate and free it. Previously, we would only track the GVariant argument as data of the GQueue. --- src/dns/nm-dns-systemd-resolved.c | 82 +++++++++++++++++++++---------- 1 file changed, 56 insertions(+), 26 deletions(-) diff --git a/src/dns/nm-dns-systemd-resolved.c b/src/dns/nm-dns-systemd-resolved.c index f37a1e7497..73a0977cc9 100644 --- a/src/dns/nm-dns-systemd-resolved.c +++ b/src/dns/nm-dns-systemd-resolved.c @@ -53,6 +53,12 @@ typedef struct { CList configs_lst_head; } InterfaceConfig; +typedef struct { + CList request_queue_lst; + const char *operation; + GVariant *argument; +} RequestItem; + /*****************************************************************************/ typedef struct { @@ -60,8 +66,7 @@ typedef struct { GCancellable *init_cancellable; GCancellable *update_cancellable; GCancellable *mdns_cancellable; - GQueue dns_updates; - GQueue domain_updates; + CList request_queue_lst_head; } NMDnsSystemdResolvedPrivate; struct _NMDnsSystemdResolved { @@ -84,6 +89,29 @@ G_DEFINE_TYPE (NMDnsSystemdResolved, nm_dns_systemd_resolved, NM_TYPE_DNS_PLUGIN /*****************************************************************************/ +static void +_request_item_free (RequestItem *request_item) +{ + c_list_unlink_stale (&request_item->request_queue_lst); + g_variant_unref (request_item->argument); + g_slice_free (RequestItem, request_item); +} + +static void +_request_item_append (CList *request_queue_lst_head, + const char *operation, + GVariant *argument) +{ + RequestItem *request_item; + + request_item = g_slice_new (RequestItem); + request_item->operation = operation; + request_item->argument = g_variant_ref_sink (argument); + c_list_link_tail (request_queue_lst_head, &request_item->request_queue_lst); +} + +/*****************************************************************************/ + static void _interface_config_free (InterfaceConfig *config) { @@ -185,13 +213,13 @@ static void free_pending_updates (NMDnsSystemdResolved *self) { NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE (self); - GVariant *v; + RequestItem *request_item, *request_item_safe; - while ((v = g_queue_pop_head (&priv->dns_updates)) != NULL) - g_variant_unref (v); - - while ((v = g_queue_pop_head (&priv->domain_updates)) != NULL) - g_variant_unref (v); + c_list_for_each_entry_safe (request_item, + request_item_safe, + &priv->request_queue_lst_head, + request_queue_lst) + _request_item_free (request_item); } static void @@ -215,17 +243,19 @@ prepare_one_interface (NMDnsSystemdResolved *self, InterfaceConfig *ic) g_variant_builder_close (&dns); g_variant_builder_close (&domains); - g_queue_push_tail (&priv->dns_updates, - g_variant_ref_sink (g_variant_builder_end (&dns))); - g_queue_push_tail (&priv->domain_updates, - g_variant_ref_sink (g_variant_builder_end (&domains))); + _request_item_append (&priv->request_queue_lst_head, + "SetLinkDNS", + g_variant_builder_end (&dns)); + _request_item_append (&priv->request_queue_lst_head, + "SetLinkDomains", + g_variant_builder_end (&domains)); } static void send_updates (NMDnsSystemdResolved *self) { NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE (self); - GVariant *v; + RequestItem *request_item, *request_item_safe; nm_clear_g_cancellable (&priv->update_cancellable); @@ -234,18 +264,19 @@ send_updates (NMDnsSystemdResolved *self) priv->update_cancellable = g_cancellable_new (); - while ((v = g_queue_pop_head (&priv->dns_updates)) != NULL) { - g_dbus_proxy_call (priv->resolve, "SetLinkDNS", v, + c_list_for_each_entry_safe (request_item, + request_item_safe, + &priv->request_queue_lst_head, + request_queue_lst) { + g_dbus_proxy_call (priv->resolve, + request_item->operation, + request_item->argument, G_DBUS_CALL_FLAGS_NONE, - -1, priv->update_cancellable, call_done, self); - g_variant_unref (v); - } - - while ((v = g_queue_pop_head (&priv->domain_updates)) != NULL) { - g_dbus_proxy_call (priv->resolve, "SetLinkDomains", v, - G_DBUS_CALL_FLAGS_NONE, - -1, priv->update_cancellable, call_done, self); - g_variant_unref (v); + -1, + priv->update_cancellable, + call_done, + self); + _request_item_free (request_item); } } @@ -403,8 +434,7 @@ nm_dns_systemd_resolved_init (NMDnsSystemdResolved *self) NMBusManager *dbus_mgr; GDBusConnection *connection; - g_queue_init (&priv->dns_updates); - g_queue_init (&priv->domain_updates); + c_list_init (&priv->request_queue_lst_head); dbus_mgr = nm_bus_manager_get (); g_return_if_fail (dbus_mgr); From fc40d91b97a1e84ea72536d0dde89f4f479c8e97 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 19 Dec 2017 12:34:20 +0100 Subject: [PATCH 15/18] core/trivial: rename local variable in merge_one_ip_config() Next commit will unify naming of variables, do a trivial rename first to make the diff smaller. --- src/dns/nm-dns-manager.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/dns/nm-dns-manager.c b/src/dns/nm-dns-manager.c index 889936f4b2..87ae09ab3f 100644 --- a/src/dns/nm-dns-manager.c +++ b/src/dns/nm-dns-manager.c @@ -313,7 +313,7 @@ add_dns_option_item (GPtrArray *array, const char *str) static void merge_one_ip_config (NMResolvConfData *rc, - const NMIPConfig *config, + const NMIPConfig *ip_config, const char *iface) { int addr_family; @@ -321,15 +321,15 @@ merge_one_ip_config (NMResolvConfData *rc, char buf[NM_UTILS_INET_ADDRSTRLEN + 50]; const char *str; - addr_family = nm_ip_config_get_addr_family (config); + addr_family = nm_ip_config_get_addr_family (ip_config); nm_assert_addr_family (addr_family); - num = nm_ip_config_get_num_nameservers (config); + num = nm_ip_config_get_num_nameservers (ip_config); for (i = 0; i < num; i++) { const NMIPAddr *addr; - addr = nm_ip_config_get_nameserver (config, i); + addr = nm_ip_config_get_nameserver (ip_config, i); if (addr_family == AF_INET) nm_utils_inet_ntop (addr_family, addr, buf); else if (IN6_IS_ADDR_V4MAPPED (addr)) @@ -345,41 +345,41 @@ merge_one_ip_config (NMResolvConfData *rc, add_string_item (rc->nameservers, buf); } - num_domains = nm_ip_config_get_num_domains (config); - num_searches = nm_ip_config_get_num_searches (config); + num_domains = nm_ip_config_get_num_domains (ip_config); + num_searches = nm_ip_config_get_num_searches (ip_config); for (i = 0; i < num_searches; i++) { - str = nm_ip_config_get_search (config, i); + str = nm_ip_config_get_search (ip_config, i); if (domain_is_valid (str, FALSE)) add_string_item (rc->searches, str); } if (num_domains > 1 || !num_searches) { for (i = 0; i < num_domains; i++) { - str = nm_ip_config_get_domain (config, i); + str = nm_ip_config_get_domain (ip_config, i); if (domain_is_valid (str, FALSE)) add_string_item (rc->searches, str); } } - num = nm_ip_config_get_num_dns_options (config); + num = nm_ip_config_get_num_dns_options (ip_config); for (i = 0; i < num; i++) { add_dns_option_item (rc->options, - nm_ip_config_get_dns_option (config, i)); + nm_ip_config_get_dns_option (ip_config, i)); } if (addr_family == AF_INET) { - const NMIP4Config *config4 = (const NMIP4Config *) config; + const NMIP4Config *ip4_config = (const NMIP4Config *) ip_config; /* NIS stuff */ - num = nm_ip4_config_get_num_nis_servers (config4); + num = nm_ip4_config_get_num_nis_servers (ip4_config); for (i = 0; i < num; i++) { add_string_item (rc->nis_servers, - nm_utils_inet4_ntop (nm_ip4_config_get_nis_server (config4, i), buf)); + nm_utils_inet4_ntop (nm_ip4_config_get_nis_server (ip4_config, i), buf)); } - if (nm_ip4_config_get_nis_domain (config4)) { + if (nm_ip4_config_get_nis_domain (ip4_config)) { /* FIXME: handle multiple domains */ if (!rc->nis_domain) - rc->nis_domain = nm_ip4_config_get_nis_domain (config4); + rc->nis_domain = nm_ip4_config_get_nis_domain (ip4_config); } } } From b40729ca5f72a147872c4d38b2de6b5fb757f5b4 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sat, 16 Dec 2017 15:11:16 +0100 Subject: [PATCH 16/18] core: rework tracking config in dns-manager to use ifindex Don't track the per-device configuration in NMDnsManager by the ifname, but by the ifindex. We should consistently treat the ifindex as the ID of a link, like kernel does. At the few places where we actually need the ifname, resolve it by looking into the platform cache. That is not necessarily the same as the ifname that is currently tracked by NMDevice, because netdev interfaces can be renamed, and NMDevice updates it's link properties delayed. However, the platform cache has the most recent notion of the correct interface name for an ifindex, so if we ever hit a race here, we do it now more correctly. This also temporarily drops support for mdns. Will be re-added next, but differently. --- src/dns/nm-dns-dnsmasq.c | 131 +++---- src/dns/nm-dns-manager.c | 590 +++++++++++++----------------- src/dns/nm-dns-manager.h | 44 +-- src/dns/nm-dns-plugin.c | 16 +- src/dns/nm-dns-plugin.h | 13 +- src/dns/nm-dns-systemd-resolved.c | 59 +-- src/dns/nm-dns-unbound.c | 2 +- src/nm-ip4-config.h | 6 + src/nm-policy.c | 117 ++---- 9 files changed, 394 insertions(+), 584 deletions(-) diff --git a/src/dns/nm-dns-dnsmasq.c b/src/dns/nm-dns-dnsmasq.c index 2e1c9fbe78..c18aaba0da 100644 --- a/src/dns/nm-dns-dnsmasq.c +++ b/src/dns/nm-dns-dnsmasq.c @@ -149,16 +149,15 @@ ip_addr_to_string (int addr_family, gconstpointer addr, const char *iface, char { int n_written; char buf2[NM_UTILS_INET_ADDRSTRLEN]; - char separator; + const char *separator; nm_assert_addr_family (addr_family); nm_assert (addr); - nm_assert (iface); nm_assert (out_buf); if (addr_family == AF_INET) { nm_utils_inet_ntop (addr_family, addr, buf2); - separator = '@'; + separator = "@"; } else { if (IN6_IS_ADDR_V4MAPPED (addr)) nm_utils_inet4_ntop (((const struct in6_addr *) addr)->s6_addr32[3], buf2); @@ -169,15 +168,15 @@ ip_addr_to_string (int addr_family, gconstpointer addr, const char *iface, char * supported. Due to a bug, since 2.73 only '%' works properly as "server" * address. */ - separator = IN6_IS_ADDR_LINKLOCAL (addr) ? '%' : '@'; + separator = IN6_IS_ADDR_LINKLOCAL (addr) ? "%" : "@"; } n_written = g_snprintf (out_buf, IP_ADDR_TO_STRING_BUFLEN, - "%s%c%s", + "%s%s%s", buf2, - separator, - iface); + iface ? separator : "", + iface ?: ""); nm_assert (n_written < IP_ADDR_TO_STRING_BUFLEN); return out_buf; } @@ -206,11 +205,11 @@ add_global_config (NMDnsDnsmasq *self, GVariantBuilder *dnsmasq_servers, const N } } -static gboolean +static void add_ip_config (NMDnsDnsmasq *self, GVariantBuilder *servers, + int ifindex, NMIPConfig *ip_config, - const char *iface, gboolean split) { int addr_family; @@ -219,77 +218,79 @@ add_ip_config (NMDnsDnsmasq *self, guint nnameservers, i_nameserver, n, i; char ip_addr_to_string_buf[IP_ADDR_TO_STRING_BUFLEN]; char **domains, **iter; - - g_return_val_if_fail (iface, FALSE); + gboolean iface_resolved = FALSE; + const char *iface = NULL; addr_family = nm_ip_config_get_addr_family (ip_config); - g_return_val_if_fail (NM_IN_SET (addr_family, AF_INET, AF_INET6), FALSE); + g_return_if_fail (NM_IN_SET (addr_family, AF_INET, AF_INET6)); + + nm_assert (ifindex > 0); + nm_assert (ifindex == nm_ip_config_get_ifindex (ip_config)); nnameservers = nm_ip_config_get_num_nameservers (ip_config); if (split) { if (nnameservers == 0) - return FALSE; + return; - for (i_nameserver = 0; i_nameserver < nnameservers; i_nameserver++) { - addr = nm_ip_config_get_nameserver (ip_config, i_nameserver); + if (!iface_resolved) { + iface = nm_platform_link_get_name (NM_PLATFORM_GET, ifindex); + iface_resolved = TRUE; + } - ip_addr_to_string (addr_family, addr, iface, ip_addr_to_string_buf); + if (iface) { + for (i_nameserver = 0; i_nameserver < nnameservers; i_nameserver++) { + addr = nm_ip_config_get_nameserver (ip_config, i_nameserver); - /* searches are preferred over domains */ - n = nm_ip_config_get_num_searches (ip_config); - for (i = 0; i < n; i++) { - add_dnsmasq_nameserver (self, - servers, - ip_addr_to_string_buf, - nm_ip_config_get_search (ip_config, i)); - added = TRUE; - } + ip_addr_to_string (addr_family, addr, iface, ip_addr_to_string_buf); - if (n == 0) { - /* If not searches, use any domains */ - n = nm_ip_config_get_num_domains (ip_config); + /* searches are preferred over domains */ + n = nm_ip_config_get_num_searches (ip_config); for (i = 0; i < n; i++) { add_dnsmasq_nameserver (self, servers, ip_addr_to_string_buf, - nm_ip_config_get_domain (ip_config, i)); + nm_ip_config_get_search (ip_config, i)); added = TRUE; } - } - /* Ensure reverse-DNS works by directing queries for in-addr4.arpa/ip6.arpa - * domains to the split domain's nameserver. - */ - domains = get_ip_rdns_domains (ip_config); - if (domains) { - for (iter = domains; *iter; iter++) - add_dnsmasq_nameserver (self, servers, ip_addr_to_string_buf, *iter); - g_strfreev (domains); + if (n == 0) { + /* If not searches, use any domains */ + n = nm_ip_config_get_num_domains (ip_config); + for (i = 0; i < n; i++) { + add_dnsmasq_nameserver (self, + servers, + ip_addr_to_string_buf, + nm_ip_config_get_domain (ip_config, i)); + added = TRUE; + } + } + + /* Ensure reverse-DNS works by directing queries for in-addr4.arpa/ip6.arpa + * domains to the split domain's nameserver. + */ + domains = get_ip_rdns_domains (ip_config); + if (domains) { + for (iter = domains; *iter; iter++) + add_dnsmasq_nameserver (self, servers, ip_addr_to_string_buf, *iter); + g_strfreev (domains); + } } } } /* If no searches or domains, just add the nameservers */ if (!added) { - for (i = 0; i < nnameservers; i++) { - addr = nm_ip_config_get_nameserver (ip_config, i); - ip_addr_to_string (addr_family, addr, iface, ip_addr_to_string_buf); - add_dnsmasq_nameserver (self, servers, ip_addr_to_string_buf, NULL); + if (!iface_resolved) + iface = nm_platform_link_get_name (NM_PLATFORM_GET, ifindex); + if (iface) { + for (i = 0; i < nnameservers; i++) { + addr = nm_ip_config_get_nameserver (ip_config, i); + ip_addr_to_string (addr_family, addr, iface, ip_addr_to_string_buf); + add_dnsmasq_nameserver (self, servers, ip_addr_to_string_buf, NULL); + } } } - - return TRUE; -} - -static gboolean -add_ip_config_data (NMDnsDnsmasq *self, GVariantBuilder *servers, const NMDnsIPConfigData *data) -{ - return add_ip_config (self, - servers, - data->config, - data->iface, - data->type == NM_DNS_IP_CONFIG_TYPE_VPN); } static void @@ -477,15 +478,16 @@ start_dnsmasq (NMDnsDnsmasq *self) static gboolean update (NMDnsPlugin *plugin, - const GPtrArray *configs, const NMGlobalDnsConfig *global_config, + const CList *ip_config_lst_head, const char *hostname) { NMDnsDnsmasq *self = NM_DNS_DNSMASQ (plugin); NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE (self); GVariantBuilder servers; - guint i; int prio, first_prio; + const NMDnsIPConfigData *ip_data; + gboolean is_first = TRUE; start_dnsmasq (self); @@ -494,15 +496,18 @@ update (NMDnsPlugin *plugin, if (global_config) add_global_config (self, &servers, global_config); else { - for (i = 0; i < configs->len; i++) { - const NMDnsIPConfigData *data = configs->pdata[i]; - - prio = nm_ip_config_get_dns_priority (data->config); - if (i == 0) + c_list_for_each_entry (ip_data, ip_config_lst_head, ip_config_lst) { + prio = nm_ip_config_get_dns_priority (ip_data->ip_config); + if (is_first) { + is_first = FALSE; first_prio = prio; - else if (first_prio < 0 && first_prio != prio) + } else if (first_prio < 0 && first_prio != prio) break; - add_ip_config_data (self, &servers, data); + add_ip_config (self, + &servers, + ip_data->data->ifindex, + ip_data->ip_config, + ip_data->ip_config_type == NM_DNS_IP_CONFIG_TYPE_VPN); } } diff --git a/src/dns/nm-dns-manager.c b/src/dns/nm-dns-manager.c index 87ae09ab3f..0e9d0903fd 100644 --- a/src/dns/nm-dns-manager.c +++ b/src/dns/nm-dns-manager.c @@ -103,12 +103,15 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMDnsManager, static guint signals[LAST_SIGNAL] = { 0 }; typedef struct { - GPtrArray *ip_configs; - GPtrArray *connection_configs; + GHashTable *configs; + CList ip_config_lst_head; GVariant *config_variant; - NMDnsIPConfigData *best_conf4, *best_conf6; - bool need_sort:1; + NMDnsIPConfigData *best_ip_config_4; + NMDnsIPConfigData *best_ip_config_6; + + bool ip_config_lst_need_sort:1; + bool dns_touched:1; bool is_stopped:1; @@ -170,6 +173,12 @@ NM_DEFINE_SINGLETON_GETTER (NMDnsManager, nm_dns_manager_get, NM_TYPE_DNS_MANAGE /*****************************************************************************/ +static void _ip_config_dns_priority_changed (gpointer config, + GParamSpec *pspec, + NMDnsIPConfigData *ip_data); + +/*****************************************************************************/ + static gboolean domain_is_valid (const gchar *domain, gboolean check_public_suffix) { @@ -197,69 +206,109 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_rc_manager_to_string, NMDnsManagerResolvConf NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_config_type_to_string, NMDnsIPConfigType, NM_UTILS_LOOKUP_DEFAULT_WARN (""), + NM_UTILS_LOOKUP_STR_ITEM (NM_DNS_IP_CONFIG_TYPE_REMOVED, "removed"), NM_UTILS_LOOKUP_STR_ITEM (NM_DNS_IP_CONFIG_TYPE_DEFAULT, "default"), NM_UTILS_LOOKUP_STR_ITEM (NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE, "best"), NM_UTILS_LOOKUP_STR_ITEM (NM_DNS_IP_CONFIG_TYPE_VPN, "vpn"), ); +/*****************************************************************************/ + +static void +_ASSERT_config_data (const NMDnsConfigData *data) +{ + nm_assert (data); + nm_assert (NM_IS_DNS_MANAGER (data->self)); + nm_assert (data->ifindex > 0); +} + +static void +_ASSERT_ip_config_data (const NMDnsIPConfigData *ip_data) +{ + nm_assert (ip_data); + _ASSERT_config_data (ip_data->data); + nm_assert (NM_IS_IP_CONFIG (ip_data->ip_config)); + nm_assert (c_list_contains (&ip_data->data->data_lst_head, &ip_data->data_lst)); + nm_assert (ip_data->data->ifindex == nm_ip_config_get_ifindex (ip_data->ip_config)); +} + static NMDnsIPConfigData * -ip_config_data_new (gpointer config, NMDnsIPConfigType type, const char *iface) +_ip_config_data_new (NMDnsConfigData *data, + NMIPConfig *ip_config, + NMDnsIPConfigType ip_config_type) { - NMDnsIPConfigData *data; + NMDnsIPConfigData *ip_data; - data = g_slice_new0 (NMDnsIPConfigData); - data->config = g_object_ref (config); - data->iface = g_strdup (iface); - data->type = type; + _ASSERT_config_data (data); + nm_assert (NM_IS_IP_CONFIG (ip_config)); + nm_assert (ip_config_type != NM_DNS_IP_CONFIG_TYPE_REMOVED); - return data; -} + ip_data = g_slice_new0 (NMDnsIPConfigData); + ip_data->data = data; + ip_data->ip_config = g_object_ref (ip_config); + ip_data->ip_config_type = ip_config_type; + c_list_link_tail (&data->data_lst_head, &ip_data->data_lst); + c_list_link_tail (&NM_DNS_MANAGER_GET_PRIVATE (data->self)->ip_config_lst_head, &ip_data->ip_config_lst); -static NMDnsConnectionConfigData * -connection_config_data_new (NMSettingConnectionMdns mdns, const char *iface, int ifindex) -{ - NMDnsConnectionConfigData *data; + g_signal_connect (ip_config, + NM_IS_IP4_CONFIG (ip_config) + ? "notify::" NM_IP4_CONFIG_DNS_PRIORITY + : "notify::" NM_IP6_CONFIG_DNS_PRIORITY, + (GCallback) _ip_config_dns_priority_changed, ip_data); - data = g_slice_new0 (NMDnsConnectionConfigData); - data->mdns = mdns; - data->iface = g_strdup (iface); - data->ifindex = ifindex; - - return data; + _ASSERT_ip_config_data (ip_data); + return ip_data; } static void -ip_config_data_destroy (gpointer ptr) +_ip_config_data_free (NMDnsIPConfigData *ip_data) { - NMDnsIPConfigData *data = ptr; + _ASSERT_ip_config_data (ip_data); - if (!data) - return; + c_list_unlink_stale (&ip_data->data_lst); + c_list_unlink_stale (&ip_data->ip_config_lst); - g_object_unref (data->config); - g_free (data->iface); - g_slice_free (NMDnsIPConfigData, data); + g_signal_handlers_disconnect_by_func (ip_data->ip_config, + _ip_config_dns_priority_changed, + ip_data); + + g_object_unref (ip_data->ip_config); + g_slice_free (NMDnsIPConfigData, ip_data); +} + +static NMDnsIPConfigData * +_config_data_find_ip_config (NMDnsConfigData *data, + NMIPConfig *ip_config) +{ + NMDnsIPConfigData *ip_data; + + _ASSERT_config_data (data); + + c_list_for_each_entry (ip_data, &data->data_lst_head, data_lst) { + _ASSERT_ip_config_data (ip_data); + + if (ip_data->ip_config == ip_config) + return ip_data; + } + return NULL; } static void -connection_config_data_destroy (gpointer ptr) +_config_data_free (NMDnsConfigData *data) { - NMDnsConnectionConfigData *data = ptr; + _ASSERT_config_data (data); - if (!data) - return; - - g_free (data->iface); - g_slice_free (NMDnsConnectionConfigData, data); + nm_assert (c_list_is_empty (&data->data_lst_head)); + g_slice_free (NMDnsConfigData, data); } static gint -ip_config_data_compare (const NMDnsIPConfigData *a, const NMDnsIPConfigData *b) +_ip_config_data_cmp (const NMDnsIPConfigData *a, const NMDnsIPConfigData *b) { int a_prio, b_prio; - a_prio = nm_ip_config_get_dns_priority (a->config); - b_prio = nm_ip_config_get_dns_priority (b->config); + a_prio = nm_ip_config_get_dns_priority (a->ip_config); + b_prio = nm_ip_config_get_dns_priority (b->ip_config); /* Configurations with lower priority value first */ if (a_prio < b_prio) @@ -268,22 +317,38 @@ ip_config_data_compare (const NMDnsIPConfigData *a, const NMDnsIPConfigData *b) return 1; /* Sort also according to type */ - if (a->type > b->type) + if (a->ip_config_type > b->ip_config_type) return -1; - else if (a->type < b->type) + else if (a->ip_config_type < b->ip_config_type) return 1; return 0; } static gint -ip_config_data_ptr_compare (gconstpointer a, gconstpointer b) +_ip_config_lst_cmp (const CList *a, + const CList *b, + const void *user_data) { - const NMDnsIPConfigData *const *ptr_a = a, *const *ptr_b = b; - - return ip_config_data_compare (*ptr_a, *ptr_b); + return _ip_config_data_cmp (c_list_entry (a, NMDnsIPConfigData, ip_config_lst), + c_list_entry (b, NMDnsIPConfigData, ip_config_lst)); } +static CList * +_ip_config_lst_head (NMDnsManager *self) +{ + NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self); + + if (priv->ip_config_lst_need_sort) { + priv->ip_config_lst_need_sort = FALSE; + c_list_sort (&priv->ip_config_lst_head, _ip_config_lst_cmp, NULL); + } + + return &priv->ip_config_lst_head; +} + +/*****************************************************************************/ + static void add_string_item (GPtrArray *array, const char *str) { @@ -313,8 +378,8 @@ add_dns_option_item (GPtrArray *array, const char *str) static void merge_one_ip_config (NMResolvConfData *rc, - const NMIPConfig *ip_config, - const char *iface) + int ifindex, + const NMIPConfig *ip_config) { int addr_family; guint num, num_domains, num_searches, i; @@ -324,6 +389,8 @@ merge_one_ip_config (NMResolvConfData *rc, addr_family = nm_ip_config_get_addr_family (ip_config); nm_assert_addr_family (addr_family); + nm_assert (ifindex > 0); + nm_assert (ifindex == nm_ip_config_get_ifindex (ip_config)); num = nm_ip_config_get_num_nameservers (ip_config); for (i = 0; i < num; i++) { @@ -337,8 +404,13 @@ merge_one_ip_config (NMResolvConfData *rc, else { nm_utils_inet6_ntop (&addr->addr6, buf); if (IN6_IS_ADDR_LINKLOCAL (addr)) { - g_strlcat (buf, "%", sizeof (buf)); - g_strlcat (buf, iface, sizeof (buf)); + const char *ifname; + + ifname = nm_platform_link_get_name (NM_PLATFORM_GET, ifindex); + if (ifname) { + g_strlcat (buf, "%", sizeof (buf)); + g_strlcat (buf, ifname, sizeof (buf)); + } } } @@ -848,25 +920,21 @@ update_resolv_conf (NMDnsManager *self, static void compute_hash (NMDnsManager *self, const NMGlobalDnsConfig *global, guint8 buffer[HASH_LEN]) { - NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self); GChecksum *sum; gsize len = HASH_LEN; - guint i; + NMDnsIPConfigData *ip_data; sum = g_checksum_new (G_CHECKSUM_SHA1); - g_assert (len == g_checksum_type_get_length (G_CHECKSUM_SHA1)); + nm_assert (len == g_checksum_type_get_length (G_CHECKSUM_SHA1)); if (global) nm_global_dns_config_update_checksum (global, sum); else { - for (i = 0; i < priv->ip_configs->len; i++) { - NMDnsIPConfigData *data = priv->ip_configs->pdata[i]; + const CList *head; - if (NM_IS_IP4_CONFIG (data->config)) - nm_ip4_config_hash ((NMIP4Config *) data->config, sum, TRUE); - else if (NM_IS_IP6_CONFIG (data->config)) - nm_ip6_config_hash ((NMIP6Config *) data->config, sum, TRUE); - } + head = _ip_config_lst_head (self); + c_list_for_each_entry (ip_data, head, ip_config_lst) + nm_ip_config_hash (ip_data->ip_config, sum, TRUE); } g_checksum_get_digest (sum, buffer, &len); @@ -940,16 +1008,15 @@ _ptrarray_to_strv (GPtrArray *parray) } static void -_collect_resolv_conf_data (NMDnsManager *self, /* only for logging context, no other side-effects */ +_collect_resolv_conf_data (NMDnsManager *self, NMGlobalDnsConfig *global_config, - const GPtrArray *ip_configs, - const char *hostname, char ***out_searches, char ***out_options, char ***out_nameservers, char ***out_nis_servers, const char **out_nis_domain) { + NMDnsManagerPrivate *priv; guint i, num, len; NMResolvConfData rc = { .nameservers = g_ptr_array_new (), @@ -959,37 +1026,44 @@ _collect_resolv_conf_data (NMDnsManager *self, /* only for logging context, no o .nis_servers = g_ptr_array_new (), }; + priv = NM_DNS_MANAGER_GET_PRIVATE (self); + if (global_config) merge_global_dns_config (&rc, global_config); else { nm_auto_free_gstring GString *tmp_gstring = NULL; int prio, first_prio = 0; - NMDnsIPConfigData *current; + const NMDnsIPConfigData *ip_data; + const CList *head; + gboolean is_first = TRUE; - for (i = 0; i < ip_configs->len; i++) { + head = _ip_config_lst_head (self); + c_list_for_each_entry (ip_data, head, ip_config_lst) { gboolean skip = FALSE; - current = ip_configs->pdata[i]; + _ASSERT_ip_config_data (ip_data); - prio = nm_ip_config_get_dns_priority (current->config); + prio = nm_ip_config_get_dns_priority (ip_data->ip_config); - if (i == 0) + if (is_first) { + is_first = FALSE; first_prio = prio; - else if (first_prio < 0 && first_prio != prio) + } else if ( first_prio < 0 + && first_prio != prio) skip = TRUE; - if (nm_ip_config_get_num_nameservers (current->config)) { - _LOGT ("config: %8d %-7s v%c %-16s %s: %s", + if (nm_ip_config_get_num_nameservers (ip_data->ip_config)) { + _LOGT ("config: %8d %-7s v%c %-5d %s: %s", prio, - _config_type_to_string (current->type), - nm_utils_addr_family_to_char (nm_ip_config_get_addr_family (current->config)), - current->iface, + _config_type_to_string (ip_data->ip_config_type), + nm_utils_addr_family_to_char (nm_ip_config_get_addr_family (ip_data->ip_config)), + ip_data->data->ifindex, skip ? "" : "", - get_nameserver_list (current->config, &tmp_gstring)); + get_nameserver_list (ip_data->ip_config, &tmp_gstring)); } if (!skip) - merge_one_ip_config (&rc, current->config, current->iface); + merge_one_ip_config (&rc, ip_data->data->ifindex, ip_data->ip_config); } } @@ -1000,16 +1074,16 @@ _collect_resolv_conf_data (NMDnsManager *self, /* only for logging context, no o * (eg, "example.com"), then use the hostname itself as the search (since the user is * unlikely to want "com" as a search domain). */ - if (hostname) { - const char *hostdomain = strchr (hostname, '.'); + if (priv->hostname) { + const char *hostdomain = strchr (priv->hostname, '.'); if ( hostdomain - && !nm_utils_ipaddr_valid (AF_UNSPEC, hostname)) { + && !nm_utils_ipaddr_valid (AF_UNSPEC, priv->hostname)) { hostdomain++; if (domain_is_valid (hostdomain, TRUE)) add_string_item (rc.searches, hostdomain); - else if (domain_is_valid (hostname, TRUE)) - add_string_item (rc.searches, hostname); + else if (domain_is_valid (priv->hostname, TRUE)) + add_string_item (rc.searches, priv->hostname); } } @@ -1071,16 +1145,12 @@ update_dns (NMDnsManager *self, data = nm_config_get_data (priv->config); global_config = nm_config_data_get_global_dns_config (data); - if (priv->need_sort) { - 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->ip_configs, priv->hostname, - &searches, &options, &nameservers, &nis_servers, &nis_domain); + _collect_resolv_conf_data (self, global_config, + &searches, &options, &nameservers, + &nis_servers, &nis_domain); /* Let any plugins do their thing first */ if (priv->plugin) { @@ -1098,8 +1168,8 @@ update_dns (NMDnsManager *self, _LOGD ("update-dns: updating plugin %s", plugin_name); if (!nm_dns_plugin_update (plugin, - priv->ip_configs, global_config, + _ip_config_lst_head (self), priv->hostname)) { _LOGW ("update-dns: plugin %s update failed", plugin_name); @@ -1240,116 +1310,96 @@ plugin_child_quit (NMDnsPlugin *plugin, int exit_status, gpointer user_data) } static void -ip_config_dns_priority_changed (gpointer config, - GParamSpec *pspec, - NMDnsManager *self) +_ip_config_dns_priority_changed (gpointer config, + GParamSpec *pspec, + NMDnsIPConfigData *ip_data) { - NM_DNS_MANAGER_GET_PRIVATE (self)->need_sort = TRUE; -} + _ASSERT_ip_config_data (ip_data); -static void -forget_ip_data (NMDnsManager *self, NMDnsIPConfigData *data) -{ - NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self); - - if (data == priv->best_conf4) - priv->best_conf4 = NULL; - else if (data == priv->best_conf6) - priv->best_conf6 = NULL; - - 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; - } - } + NM_DNS_MANAGER_GET_PRIVATE (ip_data->data->self)->ip_config_lst_need_sort = TRUE; } gboolean -nm_dns_manager_add_ip_config (NMDnsManager *self, - const char *iface, - gpointer config, - NMDnsIPConfigType cfg_type) +nm_dns_manager_set_ip_config (NMDnsManager *self, + NMIPConfig *ip_config, + NMDnsIPConfigType ip_config_type) { NMDnsManagerPrivate *priv; GError *error = NULL; - NMDnsIPConfigData *data; - gboolean v4 = NM_IS_IP4_CONFIG (config); - guint i; + NMDnsIPConfigData *ip_data; + NMDnsConfigData *data; + int ifindex; + NMDnsIPConfigData **p_best; g_return_val_if_fail (NM_IS_DNS_MANAGER (self), FALSE); - g_return_val_if_fail (config, FALSE); - g_return_val_if_fail (iface && iface[0], FALSE); - nm_assert (NM_IS_IP_CONFIG (config)); + g_return_val_if_fail (NM_IS_IP_CONFIG (ip_config), FALSE); + + ifindex = nm_ip_config_get_ifindex (ip_config); + g_return_val_if_fail (ifindex > 0, FALSE); priv = NM_DNS_MANAGER_GET_PRIVATE (self); - 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_ip_data (self, data); - g_ptr_array_remove_index_fast (priv->ip_configs, i); - break; - } - } + data = g_hash_table_lookup (priv->configs, GINT_TO_POINTER (ifindex)); + if (!data) + ip_data = NULL; + else + ip_data = _config_data_find_ip_config (data, ip_config); + + if (ip_config_type == NM_DNS_IP_CONFIG_TYPE_REMOVED) { + if (!ip_data) + return FALSE; + if (priv->best_ip_config_4 == ip_data) + priv->best_ip_config_4 = NULL; + if (priv->best_ip_config_6 == ip_data) + priv->best_ip_config_6 = NULL; + /* deleting a config doesn't invalidate the configs' sort order. */ + _ip_config_data_free (ip_data); + if (c_list_is_empty (&data->data_lst_head)) + g_hash_table_remove (priv->configs, GINT_TO_POINTER (ifindex)); + goto changed; } - data = ip_config_data_new (config, cfg_type, iface); - g_ptr_array_add (priv->ip_configs, data); - g_signal_connect (config, - v4 ? - "notify::" NM_IP4_CONFIG_DNS_PRIORITY : - "notify::" NM_IP6_CONFIG_DNS_PRIORITY, - (GCallback) ip_config_dns_priority_changed, self); - priv->need_sort = TRUE; + if ( ip_data + && ip_data->ip_config_type == ip_config_type) { + /* nothing to do. */ + return FALSE; + } - if (cfg_type == NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE) { + if (!data) { + data = g_slice_new0 (NMDnsConfigData); + data->ifindex = ifindex; + data->self = self; + c_list_init (&data->data_lst_head); + _ASSERT_config_data (data); + g_hash_table_insert (priv->configs, GINT_TO_POINTER (ifindex), data); + } + + if (!ip_data) + ip_data = _ip_config_data_new (data, ip_config, ip_config_type); + else + ip_data->ip_config_type = ip_config_type; + + priv->ip_config_lst_need_sort = TRUE; + + p_best = NM_IS_IP4_CONFIG (ip_config) + ? &priv->best_ip_config_4 + : &priv->best_ip_config_6; + + if (ip_config_type == NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE) { /* Only one best-device per IP version is allowed */ - if (v4) { - if (priv->best_conf4) - priv->best_conf4->type = NM_DNS_IP_CONFIG_TYPE_DEFAULT; - priv->best_conf4 = data; - } else { - if (priv->best_conf6) - priv->best_conf6->type = NM_DNS_IP_CONFIG_TYPE_DEFAULT; - priv->best_conf6 = data; + if (*p_best != ip_data) { + if (*p_best) + (*p_best)->ip_config_type = NM_DNS_IP_CONFIG_TYPE_DEFAULT; + *p_best = ip_data; } + } else { + if (*p_best == ip_data) + *p_best = NULL; } - if (!priv->updates_queue && !update_dns (self, FALSE, &error)) { +changed: + if ( !priv->updates_queue + && !update_dns (self, FALSE, &error)) { _LOGW ("could not commit DNS changes: %s", error->message); g_clear_error (&error); } @@ -1357,38 +1407,6 @@ nm_dns_manager_add_ip_config (NMDnsManager *self, return TRUE; } -gboolean -nm_dns_manager_remove_ip_config (NMDnsManager *self, gpointer config) -{ - NMDnsManagerPrivate *priv; - GError *error = NULL; - NMDnsIPConfigData *data; - guint i; - - g_return_val_if_fail (NM_IS_DNS_MANAGER (self), FALSE); - g_return_val_if_fail (config, FALSE); - nm_assert (NM_IS_IP_CONFIG (config)); - - priv = NM_DNS_MANAGER_GET_PRIVATE (self); - - for (i = 0; i < priv->ip_configs->len; i++) { - data = priv->ip_configs->pdata[i]; - - if (data->config == config) { - 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); - g_clear_error (&error); - } - - return TRUE; - } - } - return FALSE; -} - void nm_dns_manager_set_initial_hostname (NMDnsManager *self, const char *hostname) @@ -1431,78 +1449,6 @@ 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 (NM_IN_SET (mdns, - NM_SETTING_CONNECTION_MDNS_NO, - NM_SETTING_CONNECTION_MDNS_YES, - NM_SETTING_CONNECTION_MDNS_RESOLVE), 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) { @@ -1550,11 +1496,6 @@ 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); - if (priv->need_sort) { - g_ptr_array_sort (priv->ip_configs, ip_config_data_ptr_compare); - priv->need_sort = FALSE; - } - 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"); @@ -1949,14 +1890,13 @@ _get_config_variant (NMDnsManager *self) NMGlobalDnsConfig *global_config; gs_free char *str = NULL; GVariantBuilder builder; - NMConfigData *data; - guint i, j; + NMDnsIPConfigData *ip_data; + const CList *head; 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); + global_config = nm_config_data_get_global_dns_config (nm_config_get_data (priv->config)); if (global_config) { priv->config_variant = _get_global_config_variant (global_config); _LOGT ("current configuration: %s", (str = g_variant_print (priv->config_variant, TRUE))); @@ -1965,25 +1905,26 @@ _get_config_variant (NMDnsManager *self) g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}")); - for (i = 0; i < priv->ip_configs->len; i++) { - NMDnsIPConfigData *current = priv->ip_configs->pdata[i]; - const NMIPConfig *config = current->config; + head = _ip_config_lst_head (self); + c_list_for_each_entry (ip_data, head, ip_config_lst) { + const NMIPConfig *ip_config = ip_data->ip_config; GVariantBuilder entry_builder; GVariantBuilder strv_builder; - guint num; - const int addr_family = nm_ip_config_get_addr_family (config); + guint i, num; + const int addr_family = nm_ip_config_get_addr_family (ip_config); char buf[NM_UTILS_INET_ADDRSTRLEN]; const NMIPAddr *addr; + const char *ifname; - num = nm_ip_config_get_num_nameservers (config); + num = nm_ip_config_get_num_nameservers (ip_config); if (!num) continue; g_variant_builder_init (&entry_builder, G_VARIANT_TYPE ("a{sv}")); g_variant_builder_init (&strv_builder, G_VARIANT_TYPE ("as")); - for (j = 0; j < num; j++) { - addr = nm_ip_config_get_nameserver (config, j); + for (i = 0; i < num; i++) { + addr = nm_ip_config_get_nameserver (ip_config, i); g_variant_builder_add (&strv_builder, "s", nm_utils_inet_ntop (addr_family, addr, buf)); @@ -1993,13 +1934,13 @@ _get_config_variant (NMDnsManager *self) "nameservers", g_variant_builder_end (&strv_builder)); - num = nm_ip_config_get_num_domains (config); + num = nm_ip_config_get_num_domains (ip_config); if (num > 0) { g_variant_builder_init (&strv_builder, G_VARIANT_TYPE ("as")); - for (j = 0; j < num; j++) { + for (i = 0; i < num; i++) { g_variant_builder_add (&strv_builder, "s", - nm_ip_config_get_domain (config, j)); + nm_ip_config_get_domain (ip_config, i)); } g_variant_builder_add (&entry_builder, "{sv}", @@ -2007,22 +1948,23 @@ _get_config_variant (NMDnsManager *self) g_variant_builder_end (&strv_builder)); } - if (current->iface) { + ifname = nm_platform_link_get_name (NM_PLATFORM_GET, ip_data->data->ifindex); + if (ifname) { g_variant_builder_add (&entry_builder, "{sv}", "interface", - g_variant_new_string (current->iface)); + g_variant_new_string (ifname)); } g_variant_builder_add (&entry_builder, "{sv}", "priority", - g_variant_new_int32 (nm_ip_config_get_dns_priority (config))); + g_variant_new_int32 (nm_ip_config_get_dns_priority (ip_config))); g_variant_builder_add (&entry_builder, "{sv}", "vpn", - g_variant_new_boolean (current->type == NM_DNS_IP_CONFIG_TYPE_VPN)); + g_variant_new_boolean (ip_data->ip_config_type == NM_DNS_IP_CONFIG_TYPE_VPN)); g_variant_builder_add (&builder, "a{sv}", &entry_builder); } @@ -2063,9 +2005,12 @@ nm_dns_manager_init (NMDnsManager *self) _LOGT ("creating..."); + c_list_init (&priv->ip_config_lst_head); + priv->config = g_object_ref (nm_config_get ()); - 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); + + priv->configs = g_hash_table_new_full (nm_direct_hash, NULL, + NULL, (GDestroyNotify) _config_data_free); /* Set the initial hash */ compute_hash (self, NULL, NM_DNS_MANAGER_GET_PRIVATE (self)->hash); @@ -2082,37 +2027,30 @@ dispose (GObject *object) { NMDnsManager *self = NM_DNS_MANAGER (object); NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self); - NMDnsIPConfigData *ip_data; - guint i; + NMDnsIPConfigData *ip_data, *ip_data_safe; _LOGT ("disposing"); if (!priv->is_stopped) nm_dns_manager_stop (self); + if (priv->config) + g_signal_handlers_disconnect_by_func (priv->config, config_changed_cb, self); + _clear_plugin (self); - if (priv->config) { - g_signal_handlers_disconnect_by_func (priv->config, config_changed_cb, self); - g_clear_object (&priv->config); - } + priv->best_ip_config_4 = NULL; + priv->best_ip_config_6 = NULL; - 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->ip_configs, TRUE); - priv->ip_configs = NULL; - } + c_list_for_each_entry_safe (ip_data, ip_data_safe, &priv->ip_config_lst_head, ip_config_lst) + _ip_config_data_free (ip_data); - if (priv->connection_configs) { - g_ptr_array_free (priv->connection_configs, TRUE); - priv->connection_configs = NULL; - } + g_clear_pointer (&priv->configs, g_hash_table_destroy); nm_clear_g_source (&priv->plugin_ratelimit.timer); + g_clear_object (&priv->config); + G_OBJECT_CLASS (nm_dns_manager_parent_class)->dispose (object); } diff --git a/src/dns/nm-dns-manager.h b/src/dns/nm-dns-manager.h index d2afe8143b..663a3ad258 100644 --- a/src/dns/nm-dns-manager.h +++ b/src/dns/nm-dns-manager.h @@ -29,9 +29,11 @@ #include "nm-setting-connection.h" typedef enum { + NM_DNS_IP_CONFIG_TYPE_REMOVED = -1, + NM_DNS_IP_CONFIG_TYPE_DEFAULT = 0, NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE, - NM_DNS_IP_CONFIG_TYPE_VPN + NM_DNS_IP_CONFIG_TYPE_VPN, } NMDnsIPConfigType; enum { @@ -39,17 +41,22 @@ enum { NM_DNS_PRIORITY_DEFAULT_VPN = 50, }; -typedef struct { - gpointer config; - NMDnsIPConfigType type; - char *iface; -} NMDnsIPConfigData; +struct _NMDnsConfigData; +struct _NMDnsManager; typedef struct { - NMSettingConnectionMdns mdns; - char *iface; + struct _NMDnsConfigData *data; + NMIPConfig *ip_config; + CList data_lst; + CList ip_config_lst; + NMDnsIPConfigType ip_config_type; +} NMDnsIPConfigData; + +typedef struct _NMDnsConfigData { + struct _NMDnsManager *self; + CList data_lst_head; int ifindex; -} NMDnsConnectionConfigData; +} NMDnsConfigData; #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)) @@ -77,28 +84,15 @@ NMDnsManager * nm_dns_manager_get (void); void nm_dns_manager_begin_updates (NMDnsManager *self, const char *func); void nm_dns_manager_end_updates (NMDnsManager *self, const char *func); -gboolean nm_dns_manager_add_ip_config (NMDnsManager *self, - const char *iface, - gpointer config, - NMDnsIPConfigType cfg_type); - -gboolean nm_dns_manager_remove_ip_config (NMDnsManager *self, gpointer config); +gboolean nm_dns_manager_set_ip_config (NMDnsManager *self, + NMIPConfig *ip_config, + NMDnsIPConfigType ip_config_type); void nm_dns_manager_set_initial_hostname (NMDnsManager *self, const char *hostname); 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 7ac57ce8b1..d9400e3e97 100644 --- a/src/dns/nm-dns-plugin.c +++ b/src/dns/nm-dns-plugin.c @@ -77,30 +77,18 @@ G_DEFINE_TYPE_EXTENDED (NMDnsPlugin, nm_dns_plugin, G_TYPE_OBJECT, G_TYPE_FLAG_A gboolean nm_dns_plugin_update (NMDnsPlugin *self, - const GPtrArray *configs, const NMGlobalDnsConfig *global_config, + const CList *ip_config_lst_head, const char *hostname) { g_return_val_if_fail (NM_DNS_PLUGIN_GET_CLASS (self)->update != NULL, FALSE); return NM_DNS_PLUGIN_GET_CLASS (self)->update (self, - configs, global_config, + ip_config_lst_head, 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 f6008270c8..80b77d95c6 100644 --- a/src/dns/nm-dns-plugin.h +++ b/src/dns/nm-dns-plugin.h @@ -50,8 +50,8 @@ typedef struct { * configuration. */ gboolean (*update) (NMDnsPlugin *self, - const GPtrArray *configs, const NMGlobalDnsConfig *global_config, + const CList *ip_config_lst_head, const char *hostname); /* Subclasses should override and return TRUE if they start a local @@ -60,11 +60,6 @@ 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); @@ -85,14 +80,10 @@ gboolean nm_dns_plugin_is_caching (NMDnsPlugin *self); const char *nm_dns_plugin_get_name (NMDnsPlugin *self); gboolean nm_dns_plugin_update (NMDnsPlugin *self, - const GPtrArray *configs, const NMGlobalDnsConfig *global_config, + const CList *ip_config_lst_head, 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 73a0977cc9..da049726dc 100644 --- a/src/dns/nm-dns-systemd-resolved.c +++ b/src/dns/nm-dns-systemd-resolved.c @@ -282,8 +282,8 @@ send_updates (NMDnsSystemdResolved *self) static gboolean update (NMDnsPlugin *plugin, - const GPtrArray *configs, const NMGlobalDnsConfig *global_config, + const CList *ip_config_lst_head, const char *hostname) { NMDnsSystemdResolved *self = NM_DNS_SYSTEMD_RESOLVED (plugin); @@ -292,23 +292,26 @@ update (NMDnsPlugin *plugin, guint interfaces_len; guint i; int prio, first_prio = 0; + NMDnsIPConfigData *ip_data; + gboolean is_first = TRUE; interfaces = g_hash_table_new_full (nm_direct_hash, NULL, NULL, (GDestroyNotify) _interface_config_free); - for (i = 0; i < configs->len; i++) { - const NMDnsIPConfigData *data = configs->pdata[i]; + c_list_for_each_entry (ip_data, ip_config_lst_head, ip_config_lst) { gboolean skip = FALSE; InterfaceConfig *ic = NULL; int ifindex; - prio = nm_ip_config_get_dns_priority (data->config); - if (i == 0) + prio = nm_ip_config_get_dns_priority (ip_data->ip_config); + if (is_first) { + is_first = FALSE; first_prio = prio; - else if (first_prio < 0 && first_prio != prio) + } else if (first_prio < 0 && first_prio != prio) skip = TRUE; - ifindex = nm_ip_config_get_ifindex (data->config); + ifindex = ip_data->data->ifindex; + nm_assert (ifindex == nm_ip_config_get_ifindex (ip_data->ip_config)); ic = g_hash_table_lookup (interfaces, GINT_TO_POINTER (ifindex)); if (!ic) { @@ -320,7 +323,7 @@ update (NMDnsPlugin *plugin, if (!skip) { c_list_link_tail (&ic->configs_lst_head, - &nm_c_list_elem_new_stale (data->config)->lst); + &nm_c_list_elem_new_stale (ip_data->ip_config)->lst); } } @@ -345,45 +348,6 @@ 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 @@ -486,6 +450,5 @@ 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/dns/nm-dns-unbound.c b/src/dns/nm-dns-unbound.c index 0b80055f1b..e06128aa91 100644 --- a/src/dns/nm-dns-unbound.c +++ b/src/dns/nm-dns-unbound.c @@ -39,8 +39,8 @@ G_DEFINE_TYPE (NMDnsUnbound, nm_dns_unbound, NM_TYPE_DNS_PLUGIN) static gboolean update (NMDnsPlugin *plugin, - const GPtrArray *configs, const NMGlobalDnsConfig *global_config, + const CList *ip_config_lst_head, const char *hostname) { char *argv[] = { DNSSEC_TRIGGER_SCRIPT, "--async", "--update", NULL }; diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h index 4f541ce000..ba2d6ad981 100644 --- a/src/nm-ip4-config.h +++ b/src/nm-ip4-config.h @@ -379,6 +379,12 @@ nm_ip_config_get_ifindex (const NMIPConfig *self) _NM_IP_CONFIG_DISPATCH (self, nm_ip4_config_get_ifindex, nm_ip6_config_get_ifindex); } +static inline void +nm_ip_config_hash (const NMIPConfig *self, GChecksum *sum, gboolean dns_only) +{ + _NM_IP_CONFIG_DISPATCH_VOID (self, nm_ip4_config_hash, nm_ip6_config_hash, sum, dns_only); +} + static inline void nm_ip_config_add_address (NMIPConfig *self, const NMPlatformIPAddress *address) { diff --git a/src/nm-policy.c b/src/nm-policy.c index dfc50a8463..90f13c7580 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -1059,58 +1059,25 @@ 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_DEFAULT) { - 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) { gpointer ip_config; const char *ip_iface = NULL; NMVpnConnection *vpn = NULL; - NMDnsIPConfigType dns_type = NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE; nm_assert_addr_family (addr_family); ip_config = get_best_ip_config (self, addr_family, &ip_iface, NULL, NULL, &vpn); if (ip_config) { - if (vpn) - dns_type = NM_DNS_IP_CONFIG_TYPE_VPN; - /* Tell the DNS manager this config is preferred by re-adding it with * a different IP config type. */ - nm_dns_manager_add_ip_config (NM_POLICY_GET_PRIVATE (self)->dns_manager, - ip_iface, + nm_dns_manager_set_ip_config (NM_POLICY_GET_PRIVATE (self)->dns_manager, ip_config, - dns_type); + vpn + ? NM_DNS_IP_CONFIG_TYPE_VPN + : NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE); } if (addr_family == AF_INET6) @@ -1741,7 +1708,6 @@ device_state_changed (NMDevice *device, NMPolicy *self = _PRIV_TO_SELF (priv); NMActiveConnection *ac; NMSettingsConnection *connection = nm_device_get_settings_connection (device); - const char *ip_iface = nm_device_get_ip_iface (device); NMIP4Config *ip4_config; NMIP6Config *ip6_config; NMSettingConnection *s_con = NULL; @@ -1824,9 +1790,6 @@ 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 */ @@ -1835,10 +1798,10 @@ device_state_changed (NMDevice *device, ip4_config = nm_device_get_ip4_config (device); if (ip4_config) - nm_dns_manager_add_ip_config (priv->dns_manager, ip_iface, ip4_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT); + nm_dns_manager_set_ip_config (priv->dns_manager, NM_IP_CONFIG_CAST (ip4_config), NM_DNS_IP_CONFIG_TYPE_DEFAULT); ip6_config = nm_device_get_ip6_config (device); if (ip6_config) - nm_dns_manager_add_ip_config (priv->dns_manager, ip_iface, ip6_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT); + nm_dns_manager_set_ip_config (priv->dns_manager, NM_IP_CONFIG_CAST (ip6_config), NM_DNS_IP_CONFIG_TYPE_DEFAULT); update_routing_and_dns (self, FALSE); @@ -1881,12 +1844,8 @@ 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); @@ -1942,7 +1901,6 @@ device_ip4_config_changed (NMDevice *device, { NMPolicyPrivate *priv = user_data; NMPolicy *self = _PRIV_TO_SELF (priv); - const char *ip_iface = nm_device_get_ip_iface (device); nm_dns_manager_begin_updates (priv->dns_manager, __func__); @@ -1953,10 +1911,10 @@ device_ip4_config_changed (NMDevice *device, */ if (nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED) { if (old_config != new_config) { - if (old_config) - nm_dns_manager_remove_ip_config (priv->dns_manager, old_config); if (new_config) - nm_dns_manager_add_ip_config (priv->dns_manager, ip_iface, new_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT); + nm_dns_manager_set_ip_config (priv->dns_manager, NM_IP_CONFIG_CAST (new_config), NM_DNS_IP_CONFIG_TYPE_DEFAULT); + if (old_config) + nm_dns_manager_set_ip_config (priv->dns_manager, NM_IP_CONFIG_CAST (old_config), NM_DNS_IP_CONFIG_TYPE_REMOVED); } update_ip_dns (self, AF_INET); update_ip4_routing (self, TRUE); @@ -1964,7 +1922,7 @@ device_ip4_config_changed (NMDevice *device, } else { /* Old configs get removed immediately */ if (old_config) - nm_dns_manager_remove_ip_config (priv->dns_manager, old_config); + nm_dns_manager_set_ip_config (priv->dns_manager, NM_IP_CONFIG_CAST (old_config), NM_DNS_IP_CONFIG_TYPE_REMOVED); } nm_dns_manager_end_updates (priv->dns_manager, __func__); @@ -1978,7 +1936,6 @@ device_ip6_config_changed (NMDevice *device, { NMPolicyPrivate *priv = user_data; NMPolicy *self = _PRIV_TO_SELF (priv); - const char *ip_iface = nm_device_get_ip_iface (device); nm_dns_manager_begin_updates (priv->dns_manager, __func__); @@ -1989,10 +1946,10 @@ device_ip6_config_changed (NMDevice *device, */ if (nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED) { if (old_config != new_config) { - if (old_config) - nm_dns_manager_remove_ip_config (priv->dns_manager, old_config); if (new_config) - nm_dns_manager_add_ip_config (priv->dns_manager, ip_iface, new_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT); + nm_dns_manager_set_ip_config (priv->dns_manager, NM_IP_CONFIG_CAST (new_config), NM_DNS_IP_CONFIG_TYPE_DEFAULT); + if (old_config) + nm_dns_manager_set_ip_config (priv->dns_manager, NM_IP_CONFIG_CAST (old_config), NM_DNS_IP_CONFIG_TYPE_REMOVED); } update_ip_dns (self, AF_INET6); update_ip6_routing (self, TRUE); @@ -2000,7 +1957,7 @@ device_ip6_config_changed (NMDevice *device, } else { /* Old configs get removed immediately */ if (old_config) - nm_dns_manager_remove_ip_config (priv->dns_manager, old_config); + nm_dns_manager_set_ip_config (priv->dns_manager, NM_IP_CONFIG_CAST (old_config), NM_DNS_IP_CONFIG_TYPE_REMOVED); } nm_dns_manager_end_updates (priv->dns_manager, __func__); @@ -2019,19 +1976,6 @@ 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) { @@ -2060,7 +2004,6 @@ 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); } @@ -2113,30 +2056,20 @@ vpn_connection_activated (NMPolicy *self, NMVpnConnection *vpn) NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); NMIP4Config *ip4_config; NMIP6Config *ip6_config; - const char *ip_iface; - NMConnection *connection; nm_dns_manager_begin_updates (priv->dns_manager, __func__); - ip_iface = nm_vpn_connection_get_ip_iface (vpn, TRUE); - - /* Add the VPN connection's IP configs from DNS */ - ip4_config = nm_vpn_connection_get_ip4_config (vpn); if (ip4_config) - nm_dns_manager_add_ip_config (priv->dns_manager, ip_iface, ip4_config, NM_DNS_IP_CONFIG_TYPE_VPN); + nm_dns_manager_set_ip_config (priv->dns_manager, NM_IP_CONFIG_CAST (ip4_config), NM_DNS_IP_CONFIG_TYPE_VPN); ip6_config = nm_vpn_connection_get_ip6_config (vpn); if (ip6_config) - nm_dns_manager_add_ip_config (priv->dns_manager, ip_iface, ip6_config, NM_DNS_IP_CONFIG_TYPE_VPN); + nm_dns_manager_set_ip_config (priv->dns_manager, NM_IP_CONFIG_CAST (ip6_config), NM_DNS_IP_CONFIG_TYPE_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 @@ -2149,24 +2082,16 @@ vpn_connection_deactivated (NMPolicy *self, NMVpnConnection *vpn) nm_dns_manager_begin_updates (priv->dns_manager, __func__); ip4_config = nm_vpn_connection_get_ip4_config (vpn); - if (ip4_config) { - /* Remove the VPN connection's IP4 config from DNS */ - nm_dns_manager_remove_ip_config (priv->dns_manager, ip4_config); - } + if (ip4_config) + nm_dns_manager_set_ip_config (priv->dns_manager, NM_IP_CONFIG_CAST (ip4_config), NM_DNS_IP_CONFIG_TYPE_REMOVED); ip6_config = nm_vpn_connection_get_ip6_config (vpn); - if (ip6_config) { - /* Remove the VPN connection's IP6 config from DNS */ - nm_dns_manager_remove_ip_config (priv->dns_manager, ip6_config); - } + if (ip6_config) + nm_dns_manager_set_ip_config (priv->dns_manager, NM_IP_CONFIG_CAST (ip6_config), NM_DNS_IP_CONFIG_TYPE_REMOVED); 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 From c03a5349638ac0fa911d5f7116e6f7c52d11b931 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 20 Dec 2017 14:49:32 +0100 Subject: [PATCH 17/18] core: implement setting MDNS setting for systemd The connection.mdns setting is a per-connection setting, so one might expect that one activated device can only have one MDNS setting at a time. However, with certain VPN plugins (those that don't have their own IP interface, like libreswan), the VPN configuration is merged into the configuration of the device. So, in this case, there might be multiple settings for one device that must be merged. We already have a mechanism for that. It's NMIP4Config. Let NMIP4Config track this piece of information. Although, stricitly speaking this is not tied to IPv4, the alternative would be to introduce a new object to track such data, which would be a tremendous effort and more complicated then this. Luckily, NMDnsManager and NMDnsPlugin are already equipped to handle multiple NMIPConfig instances per device (IPv4 vs. IPv6, and Device vs. VPN). Also make "connection.mdns" configurable via global defaults in NetworkManager.conf. --- man/NetworkManager.conf.xml | 3 ++ src/devices/nm-device.c | 32 +++++++++++++++++++ src/devices/nm-device.h | 1 + src/dns/nm-dns-systemd-resolved.c | 31 ++++++++++++++++-- src/nm-ip4-config.c | 32 +++++++++++++++++++ src/nm-ip4-config.h | 7 ++++ .../plugins/ifcfg-rh/nms-ifcfg-rh-writer.c | 3 +- src/vpn/nm-vpn-connection.c | 3 ++ 8 files changed, 108 insertions(+), 4 deletions(-) diff --git a/man/NetworkManager.conf.xml b/man/NetworkManager.conf.xml index 04f6b54b23..4171bfd09a 100644 --- a/man/NetworkManager.conf.xml +++ b/man/NetworkManager.conf.xml @@ -654,6 +654,9 @@ ipv6.ip6-privacy=0 connection.lldp + + connection.mdns + connection.stable-id diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index ce144c3b08..c4569ef613 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -1878,6 +1878,34 @@ out: return nm_utils_ip_route_metric_normalize (addr_family, route_metric); } +static NMSettingConnectionMdns +_get_mdns (NMDevice *self) +{ + NMConnection *connection; + NMSettingConnectionMdns mdns = NM_SETTING_CONNECTION_MDNS_DEFAULT; + + g_return_val_if_fail (NM_IS_DEVICE (self), NM_SETTING_CONNECTION_MDNS_DEFAULT); + + connection = nm_device_get_applied_connection (self); + if (connection) + mdns = nm_setting_connection_get_mdns (nm_connection_get_setting_connection (connection)); + + if (mdns == NM_SETTING_CONNECTION_MDNS_DEFAULT) { + gs_free char *value = NULL; + + value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, + "connection.mdns", + self); + mdns = _nm_utils_ascii_str_to_int64 (value, + 10, + NM_SETTING_CONNECTION_MDNS_NO, + NM_SETTING_CONNECTION_MDNS_YES, + NM_SETTING_CONNECTION_MDNS_DEFAULT); + } + + return mdns; +} + guint32 nm_device_get_route_table (NMDevice *self, int addr_family, @@ -5922,6 +5950,7 @@ ensure_con_ip4_config (NMDevice *self) priv->con_ip4_config = _ip4_config_new (self); nm_ip4_config_merge_setting (priv->con_ip4_config, nm_connection_get_setting_ip4_config (connection), + _get_mdns (self), nm_device_get_route_table (self, AF_INET, TRUE), nm_device_get_route_metric (self, AF_INET)); @@ -6217,6 +6246,7 @@ dhcp4_state_changed (NMDhcpClient *client, manual = _ip4_config_new (self); nm_ip4_config_merge_setting (manual, nm_connection_get_setting_ip4_config (connection), + NM_SETTING_CONNECTION_MDNS_DEFAULT, nm_device_get_route_table (self, AF_INET, TRUE), nm_device_get_route_metric (self, AF_INET)); @@ -6596,6 +6626,7 @@ act_stage3_ip4_config_start (NMDevice *self, config = _ip4_config_new (self); nm_ip4_config_merge_setting (config, nm_connection_get_setting_ip4_config (connection), + NM_SETTING_CONNECTION_MDNS_DEFAULT, nm_device_get_route_table (self, AF_INET, TRUE), nm_device_get_route_metric (self, AF_INET)); @@ -9313,6 +9344,7 @@ nm_device_reactivate_ip4_config (NMDevice *self, priv->con_ip4_config = _ip4_config_new (self); nm_ip4_config_merge_setting (priv->con_ip4_config, s_ip4_new, + _get_mdns (self), nm_device_get_route_table (self, AF_INET, TRUE), nm_device_get_route_metric (self, AF_INET)); diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index 8c823bab4d..3f3da48578 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -24,6 +24,7 @@ #include +#include "nm-setting-connection.h" #include "nm-exported-object.h" #include "nm-dbus-interface.h" #include "nm-connection.h" diff --git a/src/dns/nm-dns-systemd-resolved.c b/src/dns/nm-dns-systemd-resolved.c index da049726dc..7625bcaede 100644 --- a/src/dns/nm-dns-systemd-resolved.c +++ b/src/dns/nm-dns-systemd-resolved.c @@ -228,6 +228,8 @@ prepare_one_interface (NMDnsSystemdResolved *self, InterfaceConfig *ic) NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE (self); GVariantBuilder dns, domains; NMCListElem *elem; + NMSettingConnectionMdns mdns = NM_SETTING_CONNECTION_MDNS_DEFAULT; + const char *mdns_arg = NULL; g_variant_builder_init (&dns, G_VARIANT_TYPE ("(ia(iay))")); g_variant_builder_add (&dns, "i", ic->ifindex); @@ -237,18 +239,43 @@ prepare_one_interface (NMDnsSystemdResolved *self, InterfaceConfig *ic) g_variant_builder_add (&domains, "i", ic->ifindex); g_variant_builder_open (&domains, G_VARIANT_TYPE ("a(sb)")); - c_list_for_each_entry (elem, &ic->configs_lst_head, lst) - update_add_ip_config (self, &dns, &domains, elem->data); + c_list_for_each_entry (elem, &ic->configs_lst_head, lst) { + NMIPConfig *ip_config = elem->data; + + update_add_ip_config (self, &dns, &domains, ip_config); + + if (NM_IS_IP4_CONFIG (ip_config)) + mdns = NM_MAX (mdns, nm_ip4_config_mdns_get (NM_IP4_CONFIG (ip_config))); + } g_variant_builder_close (&dns); g_variant_builder_close (&domains); + switch (mdns) { + case NM_SETTING_CONNECTION_MDNS_NO: + mdns_arg = "no"; + break; + case NM_SETTING_CONNECTION_MDNS_RESOLVE: + mdns_arg = "resolve"; + break; + case NM_SETTING_CONNECTION_MDNS_YES: + mdns_arg = "yes"; + break; + case NM_SETTING_CONNECTION_MDNS_DEFAULT: + mdns_arg = ""; + break; + } + nm_assert (mdns_arg); + _request_item_append (&priv->request_queue_lst_head, "SetLinkDNS", g_variant_builder_end (&dns)); _request_item_append (&priv->request_queue_lst_head, "SetLinkDomains", g_variant_builder_end (&domains)); + _request_item_append (&priv->request_queue_lst_head, + "SetLinkMulticastDNS", + g_variant_new ("(is)", ic->ifindex, mdns_arg ?: "")); } static void diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index 5c51a4f66f..9893b14084 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -293,6 +293,7 @@ typedef struct { int ifindex; NMIPConfigSource mtu_source; gint dns_priority; + NMSettingConnectionMdns mdns; GArray *nameservers; GPtrArray *domains; GPtrArray *searches; @@ -901,6 +902,7 @@ _nm_ip_config_merge_route_attributes (int addr_family, void nm_ip4_config_merge_setting (NMIP4Config *self, NMSettingIPConfig *setting, + NMSettingConnectionMdns mdns, guint32 route_table, guint32 route_metric) { @@ -1017,6 +1019,8 @@ nm_ip4_config_merge_setting (NMIP4Config *self, if (priority) nm_ip4_config_set_dns_priority (self, priority); + nm_ip4_config_mdns_set (self, mdns); + g_object_thaw_notify (G_OBJECT (self)); } @@ -1232,6 +1236,11 @@ nm_ip4_config_merge (NMIP4Config *dst, if (nm_ip4_config_get_dns_priority (src)) nm_ip4_config_set_dns_priority (dst, nm_ip4_config_get_dns_priority (src)); + /* mdns */ + nm_ip4_config_mdns_set (dst, + NM_MAX (nm_ip4_config_mdns_get (src), + nm_ip4_config_mdns_get (dst))); + g_object_thaw_notify (G_OBJECT (dst)); } @@ -1468,6 +1477,10 @@ nm_ip4_config_subtract (NMIP4Config *dst, if (nm_ip4_config_get_dns_priority (src) == nm_ip4_config_get_dns_priority (dst)) nm_ip4_config_set_dns_priority (dst, 0); + /* mdns */ + if (nm_ip4_config_mdns_get (src) == nm_ip4_config_mdns_get (dst)) + nm_ip4_config_mdns_set (dst, NM_SETTING_CONNECTION_MDNS_DEFAULT); + g_object_thaw_notify (G_OBJECT (dst)); } @@ -1568,6 +1581,7 @@ _nm_ip4_config_intersect_helper (NMIP4Config *dst, /* ignore dns options */ /* ignore NIS */ /* ignore WINS */ + /* ignore mdns */ if (update_dst) g_object_thaw_notify (G_OBJECT (dst)); @@ -1846,6 +1860,8 @@ nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relev has_relevant_changes = TRUE; } + dst_priv->mdns = src_priv->mdns; + /* DNS priority */ if (src_priv->dns_priority != dst_priv->dns_priority) { nm_ip4_config_set_dns_priority (dst, src_priv->dns_priority); @@ -2523,6 +2539,21 @@ nm_ip4_config_get_dns_option (const NMIP4Config *self, guint i) /*****************************************************************************/ +NMSettingConnectionMdns +nm_ip4_config_mdns_get (const NMIP4Config *self) +{ + return NM_IP4_CONFIG_GET_PRIVATE (self)->mdns; +} + +void +nm_ip4_config_mdns_set (NMIP4Config *self, + NMSettingConnectionMdns mdns) +{ + NM_IP4_CONFIG_GET_PRIVATE (self)->mdns = mdns; +} + +/*****************************************************************************/ + void nm_ip4_config_set_dns_priority (NMIP4Config *self, gint priority) { @@ -3133,6 +3164,7 @@ nm_ip4_config_init (NMIP4Config *self) nm_ip_config_dedup_multi_idx_type_init ((NMIPConfigDedupMultiIdxType *) &priv->idx_ip4_routes, NMP_OBJECT_TYPE_IP4_ROUTE); + priv->mdns = NM_SETTING_CONNECTION_MDNS_DEFAULT; priv->nameservers = g_array_new (FALSE, FALSE, sizeof (guint32)); priv->domains = g_ptr_array_new_with_free_func (g_free); priv->searches = g_ptr_array_new_with_free_func (g_free); diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h index ba2d6ad981..d4c67d8943 100644 --- a/src/nm-ip4-config.h +++ b/src/nm-ip4-config.h @@ -21,6 +21,8 @@ #ifndef __NETWORKMANAGER_IP4_CONFIG_H__ #define __NETWORKMANAGER_IP4_CONFIG_H__ +#include "nm-setting-connection.h" + #include "nm-exported-object.h" #include "nm-setting-ip4-config.h" @@ -172,6 +174,7 @@ gboolean nm_ip4_config_commit (const NMIP4Config *self, void nm_ip4_config_merge_setting (NMIP4Config *self, NMSettingIPConfig *setting, + NMSettingConnectionMdns mdns, guint32 route_table, guint32 route_metric); NMSetting *nm_ip4_config_create_setting (const NMIP4Config *self); @@ -198,6 +201,10 @@ const NMPObject *_nm_ip4_config_best_default_route_find (const NMIP4Config *self in_addr_t nmtst_ip4_config_get_gateway (NMIP4Config *config); +NMSettingConnectionMdns nm_ip4_config_mdns_get (const NMIP4Config *self); +void nm_ip4_config_mdns_set (NMIP4Config *self, + NMSettingConnectionMdns mdns); + const NMDedupMultiHeadEntry *nm_ip4_config_lookup_addresses (const NMIP4Config *self); void nm_ip4_config_reset_addresses (NMIP4Config *self); void nm_ip4_config_add_address (NMIP4Config *self, const NMPlatformIP4Address *address); diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c index f326795254..32f056f7e0 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c @@ -1888,9 +1888,8 @@ write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg) if (mdns != NM_SETTING_CONNECTION_MDNS_DEFAULT) { svSetValueEnum (ifcfg, "MDNS", nm_setting_connection_mdns_get_type (), mdns); - } else { + } else svUnsetValue (ifcfg, "MDNS"); - } } static char * diff --git a/src/vpn/nm-vpn-connection.c b/src/vpn/nm-vpn-connection.c index 948d867333..964167fc8f 100644 --- a/src/vpn/nm-vpn-connection.c +++ b/src/vpn/nm-vpn-connection.c @@ -1460,6 +1460,7 @@ nm_vpn_connection_ip4_config_get (NMVpnConnection *self, GVariant *dict) NMPlatformIP4Address address; guint32 u32, route_metric; NMSettingIPConfig *s_ip; + NMSettingConnection *s_con; guint32 route_table; NMIP4Config *config; GVariantIter *iter; @@ -1564,6 +1565,7 @@ nm_vpn_connection_ip4_config_get (NMVpnConnection *self, GVariant *dict) route_table = get_route_table (self, AF_INET, TRUE); route_metric = nm_vpn_connection_get_ip4_route_metric (self); s_ip = nm_connection_get_setting_ip4_config (_get_applied_connection (self)); + s_con = nm_connection_get_setting_connection (_get_applied_connection (self)); if (nm_setting_ip_config_get_ignore_auto_routes (s_ip)) { /* ignore VPN routes */ @@ -1621,6 +1623,7 @@ nm_vpn_connection_ip4_config_get (NMVpnConnection *self, GVariant *dict) /* Merge in user overrides from the NMConnection's IPv4 setting */ nm_ip4_config_merge_setting (config, s_ip, + nm_setting_connection_get_mdns (s_con), route_table, route_metric); From d1de905ed3e6a524a9d574402b078bb08e8b3ffe Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 8 Jan 2018 15:44:05 +0100 Subject: [PATCH 18/18] policy: merge IPv4 and IPv6 versions of device_ip_config_changed() --- src/nm-policy.c | 76 +++++++++++++++++++------------------------------ 1 file changed, 29 insertions(+), 47 deletions(-) diff --git a/src/nm-policy.c b/src/nm-policy.c index 90f13c7580..9af731aaf5 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -1894,13 +1894,24 @@ device_state_changed (NMDevice *device, } static void -device_ip4_config_changed (NMDevice *device, - NMIP4Config *new_config, - NMIP4Config *old_config, - gpointer user_data) +device_ip_config_changed (NMDevice *device, + NMIPConfig *new_config, + NMIPConfig *old_config, + gpointer user_data) { NMPolicyPrivate *priv = user_data; NMPolicy *self = _PRIV_TO_SELF (priv); + int addr_family; + + nm_assert (new_config || old_config); + nm_assert (!new_config || NM_IS_IP_CONFIG (new_config)); + nm_assert (!old_config || NM_IS_IP_CONFIG (old_config)); + + if (new_config) { + addr_family = nm_ip_config_get_addr_family (new_config); + nm_assert (!old_config || addr_family == nm_ip_config_get_addr_family (old_config)); + } else + addr_family = nm_ip_config_get_addr_family (old_config); nm_dns_manager_begin_updates (priv->dns_manager, __func__); @@ -1912,52 +1923,23 @@ device_ip4_config_changed (NMDevice *device, if (nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED) { if (old_config != new_config) { if (new_config) - nm_dns_manager_set_ip_config (priv->dns_manager, NM_IP_CONFIG_CAST (new_config), NM_DNS_IP_CONFIG_TYPE_DEFAULT); + nm_dns_manager_set_ip_config (priv->dns_manager, new_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT); if (old_config) - nm_dns_manager_set_ip_config (priv->dns_manager, NM_IP_CONFIG_CAST (old_config), NM_DNS_IP_CONFIG_TYPE_REMOVED); + nm_dns_manager_set_ip_config (priv->dns_manager, old_config, NM_DNS_IP_CONFIG_TYPE_REMOVED); } - update_ip_dns (self, AF_INET); - update_ip4_routing (self, TRUE); - update_system_hostname (self, "ip4 conf"); + update_ip_dns (self, addr_family); + if (addr_family == AF_INET) + update_ip4_routing (self, TRUE); + else + update_ip6_routing (self, TRUE); + update_system_hostname (self, + addr_family == AF_INET + ? "ip4 conf" + : "ip6 conf"); } else { /* Old configs get removed immediately */ if (old_config) - nm_dns_manager_set_ip_config (priv->dns_manager, NM_IP_CONFIG_CAST (old_config), NM_DNS_IP_CONFIG_TYPE_REMOVED); - } - - nm_dns_manager_end_updates (priv->dns_manager, __func__); -} - -static void -device_ip6_config_changed (NMDevice *device, - NMIP6Config *new_config, - NMIP6Config *old_config, - gpointer user_data) -{ - NMPolicyPrivate *priv = user_data; - NMPolicy *self = _PRIV_TO_SELF (priv); - - nm_dns_manager_begin_updates (priv->dns_manager, __func__); - - /* We catch already all the IP events registering on the device state changes but - * the ones where the IP changes but the device state keep stable (i.e., activated): - * ignore IP config changes but when the device is in activated state. - * Prevents unecessary changes to DNS information. - */ - if (nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED) { - if (old_config != new_config) { - if (new_config) - nm_dns_manager_set_ip_config (priv->dns_manager, NM_IP_CONFIG_CAST (new_config), NM_DNS_IP_CONFIG_TYPE_DEFAULT); - if (old_config) - nm_dns_manager_set_ip_config (priv->dns_manager, NM_IP_CONFIG_CAST (old_config), NM_DNS_IP_CONFIG_TYPE_REMOVED); - } - update_ip_dns (self, AF_INET6); - update_ip6_routing (self, TRUE); - update_system_hostname (self, "ip6 conf"); - } else { - /* Old configs get removed immediately */ - if (old_config) - nm_dns_manager_set_ip_config (priv->dns_manager, NM_IP_CONFIG_CAST (old_config), NM_DNS_IP_CONFIG_TYPE_REMOVED); + nm_dns_manager_set_ip_config (priv->dns_manager, old_config, NM_DNS_IP_CONFIG_TYPE_REMOVED); } nm_dns_manager_end_updates (priv->dns_manager, __func__); @@ -2000,8 +1982,8 @@ devices_list_register (NMPolicy *self, NMDevice *device) /* Connect state-changed with _after, so that the handler is invoked after other handlers. */ g_signal_connect_after (device, NM_DEVICE_STATE_CHANGED, (GCallback) device_state_changed, priv); - g_signal_connect (device, NM_DEVICE_IP4_CONFIG_CHANGED, (GCallback) device_ip4_config_changed, priv); - g_signal_connect (device, NM_DEVICE_IP6_CONFIG_CHANGED, (GCallback) device_ip6_config_changed, priv); + g_signal_connect (device, NM_DEVICE_IP4_CONFIG_CHANGED, (GCallback) device_ip_config_changed, priv); + g_signal_connect (device, NM_DEVICE_IP6_CONFIG_CHANGED, (GCallback) device_ip_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_AUTOCONNECT, (GCallback) device_autoconnect_changed, priv);