From 2da1366905b0f9981ff443a67c0c69f1cb66da97 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Mon, 20 Nov 2017 11:21:58 +0100 Subject: [PATCH 01/33] core: drop unused macro argument (cherry picked from commit 057744b7229d792585d4efe6b4049947da03468c) --- src/nm-ip4-config.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h index 7c345d2052..93a254b8c6 100644 --- a/src/nm-ip4-config.h +++ b/src/nm-ip4-config.h @@ -338,7 +338,7 @@ nm_ip_config_get_addr_family (const NMIPConfig *config) g_return_val_if_reached (AF_UNSPEC); } -#define _NM_IP_CONFIG_DISPATCH(config, v4_func, v6_func, dflt, ...) \ +#define _NM_IP_CONFIG_DISPATCH(config, v4_func, v6_func, ...) \ G_STMT_START { \ gconstpointer _config = (config); \ \ @@ -353,55 +353,55 @@ nm_ip_config_get_addr_family (const NMIPConfig *config) static inline int nm_ip_config_get_dns_priority (const NMIPConfig *self) { - _NM_IP_CONFIG_DISPATCH (self, nm_ip4_config_get_dns_priority, nm_ip6_config_get_dns_priority, 0); + _NM_IP_CONFIG_DISPATCH (self, nm_ip4_config_get_dns_priority, nm_ip6_config_get_dns_priority); } static inline guint nm_ip_config_get_num_nameservers (const NMIPConfig *self) { - _NM_IP_CONFIG_DISPATCH (self, nm_ip4_config_get_num_nameservers, nm_ip6_config_get_num_nameservers, 0); + _NM_IP_CONFIG_DISPATCH (self, nm_ip4_config_get_num_nameservers, nm_ip6_config_get_num_nameservers); } static inline gconstpointer nm_ip_config_get_nameserver (const NMIPConfig *self, guint i) { - _NM_IP_CONFIG_DISPATCH (self, _nm_ip4_config_get_nameserver, nm_ip6_config_get_nameserver, 0, i); + _NM_IP_CONFIG_DISPATCH (self, _nm_ip4_config_get_nameserver, nm_ip6_config_get_nameserver, i); } static inline guint nm_ip_config_get_num_domains (const NMIPConfig *self) { - _NM_IP_CONFIG_DISPATCH (self, nm_ip4_config_get_num_domains, nm_ip6_config_get_num_domains, 0); + _NM_IP_CONFIG_DISPATCH (self, nm_ip4_config_get_num_domains, nm_ip6_config_get_num_domains); } static inline const char * nm_ip_config_get_domain (const NMIPConfig *self, guint i) { - _NM_IP_CONFIG_DISPATCH (self, nm_ip4_config_get_domain, nm_ip6_config_get_domain, NULL, i); + _NM_IP_CONFIG_DISPATCH (self, nm_ip4_config_get_domain, nm_ip6_config_get_domain, i); } static inline guint nm_ip_config_get_num_searches (const NMIPConfig *self) { - _NM_IP_CONFIG_DISPATCH (self, nm_ip4_config_get_num_searches, nm_ip6_config_get_num_searches, 0); + _NM_IP_CONFIG_DISPATCH (self, nm_ip4_config_get_num_searches, nm_ip6_config_get_num_searches); } static inline const char * nm_ip_config_get_search (const NMIPConfig *self, guint i) { - _NM_IP_CONFIG_DISPATCH (self, nm_ip4_config_get_search, nm_ip6_config_get_search, NULL, i); + _NM_IP_CONFIG_DISPATCH (self, nm_ip4_config_get_search, nm_ip6_config_get_search, i); } static inline guint nm_ip_config_get_num_dns_options (const NMIPConfig *self) { - _NM_IP_CONFIG_DISPATCH (self, nm_ip4_config_get_num_dns_options, nm_ip6_config_get_num_dns_options, 0); + _NM_IP_CONFIG_DISPATCH (self, nm_ip4_config_get_num_dns_options, nm_ip6_config_get_num_dns_options); } static inline const char * nm_ip_config_get_dns_option (const NMIPConfig *self, guint i) { - _NM_IP_CONFIG_DISPATCH (self, nm_ip4_config_get_dns_option, nm_ip6_config_get_dns_option, NULL, i); + _NM_IP_CONFIG_DISPATCH (self, nm_ip4_config_get_dns_option, nm_ip6_config_get_dns_option, i); } #endif /* __NETWORKMANAGER_IP4_CONFIG_H__ */ From a0e4dd7ade0ce61bbecafe4132db7643131bd87f Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 15 Dec 2017 13:06:05 +0100 Subject: [PATCH 02/33] 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. (cherry picked from commit 3d86429c9d9feb97c197feea450a767d5117cf86) --- 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 dc54547023..dc03292daf 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 2306f8650a610d5ea93d797217c1933ed5ea7b27 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 15 Dec 2017 14:07:09 +0100 Subject: [PATCH 03/33] 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. (cherry picked from commit 6dd69990c04b8a4e1bc439f6f717de48f4f8d9be) --- Makefile.am | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Makefile.am b/Makefile.am index 94ba15a8a1..502be781fe 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1448,16 +1448,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 19d7e66099ee43f47d6be0e740dc710fc365d200 Mon Sep 17 00:00:00 2001 From: Ismo Puustinen Date: Fri, 10 Nov 2017 14:49:27 +0200 Subject: [PATCH 04/33] mdns: add new connection property. Add support for mDNS as a connection-level property. Update ifcfg-rh and keyfile plugins to support it. (cherry picked from commit 2e2ff6f27aa1bfa7a27d49980b319873240ec84b) --- 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/nm-version.h | 7 +++ libnm-core/tests/test-general.c | 1 + libnm/libnm.ver | 6 ++ .../plugins/ifcfg-rh/nms-ifcfg-rh-reader.c | 9 ++- .../plugins/ifcfg-rh/nms-ifcfg-rh-writer.c | 11 +++- 9 files changed, 120 insertions(+), 3 deletions(-) diff --git a/clients/common/nm-meta-setting-desc.c b/clients/common/nm-meta-setting-desc.c index 94404e9088..addcdef714 100644 --- a/clients/common/nm-meta-setting-desc.c +++ b/clients/common/nm-meta-setting-desc.c @@ -5603,6 +5603,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 f3769ba498..8218d0a9d2 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..96fca5e9ee 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.10.14 + **/ +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.10.14 + **/ + /* ---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..ac8cc2cc6e 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.10.14 + */ +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_10_14 +NMSettingConnectionMdns nm_setting_connection_get_mdns (NMSettingConnection *setting); G_END_DECLS #endif /* __NM_SETTING_CONNECTION_H__ */ diff --git a/libnm-core/nm-version.h b/libnm-core/nm-version.h index 61bfa5b1a8..b50c2a7fe0 100644 --- a/libnm-core/nm-version.h +++ b/libnm-core/nm-version.h @@ -152,4 +152,11 @@ # define NM_AVAILABLE_IN_1_10_2 #endif +#if NM_VERSION_MAX_ALLOWED < NM_VERSION_1_10_14 +# define NM_AVAILABLE_IN_1_10_14 G_UNAVAILABLE(1,10.14) +#else +# define NM_AVAILABLE_IN_1_10_14 +#endif + + #endif /* NM_VERSION_H */ diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c index 520ed5814c..9a38ae4cd0 100644 --- a/libnm-core/tests/test-general.c +++ b/libnm-core/tests/test-general.c @@ -2572,6 +2572,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 7646a93185..6e0d9277d9 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -1331,3 +1331,9 @@ global: nm_utils_tc_tfilter_from_str; nm_utils_tc_tfilter_to_str; } libnm_1_10_0; + +libnm_1_10_14 { +global: + nm_setting_connection_get_mdns; + nm_setting_connection_mdns_get_type; +} libnm_1_10_2; 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 13ef5d2b77..366dd83476 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) @@ -338,6 +338,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 e9dd08b7d0..e2c2a5d2a2 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; @@ -1888,6 +1888,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 * @@ -3188,4 +3196,3 @@ nms_ifcfg_rh_writer_can_write_connection (NMConnection *connection, GError **err NM_PRINT_FMT_QUOTE_STRING (type)); return FALSE; } - From 1e89b9f18e98f9c9bf4a377d751feeeaf3f47fbc Mon Sep 17 00:00:00 2001 From: Ismo Puustinen Date: Fri, 10 Nov 2017 14:49:47 +0200 Subject: [PATCH 05/33] dns: add mechanism for propagating mDNS setting. Update nm-policy.c and nm-dns-manager.c so that the connection-specific settings get propagated to DNS manger. Currently the only such value is the mDNS status. Add update_mdns() function to DNS plugin interface. If a DNS plugin supports mDNS, it can set an interface with a given index to support mDNS resolving or also register the current hostname. The mDNS support is currently added only to systemd-resolved DNS plugin. (cherry picked from commit 25906eda9e669c53d1e5c450fe423cc4360d25e3) --- src/dns/nm-dns-manager.c | 198 +++++++++++++++++++++++++----- 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, 307 insertions(+), 33 deletions(-) diff --git a/src/dns/nm-dns-manager.c b/src/dns/nm-dns-manager.c index dc03292daf..6cdacd2e79 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) { @@ -832,8 +858,8 @@ compute_hash (NMDnsManager *self, const NMGlobalDnsConfig *global, guint8 buffer if (global) nm_global_dns_config_update_checksum (global, sum); else { - for (i = 0; i < priv->configs->len; i++) { - NMDnsIPConfigData *data = priv->configs->pdata[i]; + for (i = 0; i < priv->ip_configs->len; i++) { + NMDnsIPConfigData *data = priv->ip_configs->pdata[i]; if (NM_IS_IP4_CONFIG (data->config)) nm_ip4_config_hash ((NMIP4Config *) data->config, sum, TRUE); @@ -915,7 +941,7 @@ _ptrarray_to_strv (GPtrArray *parray) static void _collect_resolv_conf_data (NMDnsManager *self, /* only for logging context, no other side-effects */ NMGlobalDnsConfig *global_config, - const GPtrArray *configs, + const GPtrArray *ip_configs, const char *hostname, char ***out_searches, char ***out_options, @@ -923,7 +949,7 @@ _collect_resolv_conf_data (NMDnsManager *self, /* only for logging context, no o char ***out_nis_servers, const char **out_nis_domain) { - guint i, j, num, len; + guint i, num, len; NMResolvConfData rc = { .nameservers = g_ptr_array_new (), .searches = g_ptr_array_new (), @@ -939,10 +965,10 @@ _collect_resolv_conf_data (NMDnsManager *self, /* only for logging context, no o int prio, first_prio = 0; NMDnsIPConfigData *current; - for (i = 0, j = 0; i < configs->len; i++) { + for (i = 0; i < ip_configs->len; i++) { gboolean skip = FALSE; - current = configs->pdata[i]; + current = ip_configs->pdata[i]; prio = nm_ip_config_get_dns_priority (current->config); @@ -1045,14 +1071,14 @@ update_dns (NMDnsManager *self, global_config = nm_config_data_get_global_dns_config (data); if (priv->need_sort) { - g_ptr_array_sort (priv->configs, ip_config_data_ptr_compare); + g_ptr_array_sort (priv->ip_configs, ip_config_data_ptr_compare); priv->need_sort = FALSE; } /* Update hash with config we're applying */ compute_hash (self, global_config, priv->hash); - _collect_resolv_conf_data (self, global_config, priv->configs, priv->hostname, + _collect_resolv_conf_data (self, global_config, priv->ip_configs, priv->hostname, &searches, &options, &nameservers, &nis_servers, &nis_domain); /* Let any plugins do their thing first */ @@ -1071,7 +1097,7 @@ update_dns (NMDnsManager *self, _LOGD ("update-dns: updating plugin %s", plugin_name); if (!nm_dns_plugin_update (plugin, - priv->configs, + priv->ip_configs, global_config, priv->hostname)) { _LOGW ("update-dns: plugin %s update failed", plugin_name); @@ -1217,7 +1243,7 @@ ip_config_dns_priority_changed (gpointer config, } static void -forget_data (NMDnsManager *self, NMDnsIPConfigData *data) +forget_ip_data (NMDnsManager *self, NMDnsIPConfigData *data) { NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self); @@ -1229,6 +1255,40 @@ forget_data (NMDnsManager *self, NMDnsIPConfigData *data) g_signal_handlers_disconnect_by_func (data->config, ip_config_dns_priority_changed, self); } +void nm_dns_manager_update_ifindex (NMDnsManager *self, + const char *iface, + int new_ifindex) +{ + NMDnsConnectionConfigData *data; + NMDnsManagerPrivate *priv; + NMDnsPlugin *plugin; + guint i; + + g_return_if_fail (NM_IS_DNS_MANAGER (self)); + g_return_if_fail (iface && iface[0]); + g_return_if_fail (new_ifindex > 0); + + priv = NM_DNS_MANAGER_GET_PRIVATE (self); + plugin = priv->plugin; + + for (i = 0; i < priv->connection_configs->len; i++) { + data = priv->connection_configs->pdata[i]; + if (nm_streq (data->iface, iface)) { + if (data->ifindex == new_ifindex) + return; + + nm_dns_plugin_update_mdns (plugin, + data->ifindex, + NM_SETTING_CONNECTION_MDNS_UNKNOWN); + data->ifindex = new_ifindex; + nm_dns_plugin_update_mdns (plugin, + data->ifindex, + data->mdns); + return; + } + } +} + gboolean nm_dns_manager_add_ip_config (NMDnsManager *self, const char *iface, @@ -1248,22 +1308,22 @@ nm_dns_manager_add_ip_config (NMDnsManager *self, priv = NM_DNS_MANAGER_GET_PRIVATE (self); - for (i = 0; i < priv->configs->len; i++) { - data = priv->configs->pdata[i]; + for (i = 0; i < priv->ip_configs->len; i++) { + data = priv->ip_configs->pdata[i]; if (data->config == config) { if ( nm_streq (data->iface, iface) && data->type == cfg_type) return FALSE; else { - forget_data (self, data); - g_ptr_array_remove_index_fast (priv->configs, i); + forget_ip_data (self, data); + g_ptr_array_remove_index_fast (priv->ip_configs, i); break; } } } data = ip_config_data_new (config, cfg_type, iface); - g_ptr_array_add (priv->configs, data); + g_ptr_array_add (priv->ip_configs, data); g_signal_connect (config, v4 ? "notify::" NM_IP4_CONFIG_DNS_PRIORITY : @@ -1306,12 +1366,12 @@ nm_dns_manager_remove_ip_config (NMDnsManager *self, gpointer config) priv = NM_DNS_MANAGER_GET_PRIVATE (self); - for (i = 0; i < priv->configs->len; i++) { - data = priv->configs->pdata[i]; + for (i = 0; i < priv->ip_configs->len; i++) { + data = priv->ip_configs->pdata[i]; if (data->config == config) { - forget_data (self, data); - g_ptr_array_remove_index (priv->configs, i); + forget_ip_data (self, data); + g_ptr_array_remove_index (priv->ip_configs, i); if (!priv->updates_queue && !update_dns (self, FALSE, &error)) { _LOGW ("could not commit DNS changes: %s", error->message); @@ -1366,6 +1426,75 @@ nm_dns_manager_set_hostname (NMDnsManager *self, } } +gboolean +nm_dns_manager_add_connection_config (NMDnsManager *self, + const char *iface, + int ifindex, + NMSettingConnectionMdns mdns) +{ + NMDnsConnectionConfigData *data; + NMDnsManagerPrivate *priv; + NMDnsPlugin *plugin; + guint i; + + g_return_val_if_fail (NM_IS_DNS_MANAGER (self), FALSE); + g_return_val_if_fail (ifindex > 0, FALSE); + g_return_val_if_fail (iface != NULL && iface[0], FALSE); + g_return_val_if_fail (mdns != NM_SETTING_CONNECTION_MDNS_UNKNOWN, FALSE); + + priv = NM_DNS_MANAGER_GET_PRIVATE (self); + plugin = priv->plugin; + + for (i = 0; i < priv->connection_configs->len; i++) { + data = priv->connection_configs->pdata[i]; + if (nm_streq (data->iface, iface)) { + if (data->mdns == mdns) + /* already there */ + return FALSE; + else { + data->mdns = mdns; + return nm_dns_plugin_update_mdns (plugin, + ifindex, + mdns); + } + } + } + + data = connection_config_data_new (mdns, iface, ifindex); + g_ptr_array_add (priv->connection_configs, data); + + return nm_dns_plugin_update_mdns (plugin, ifindex, mdns); +} + +void +nm_dns_manager_remove_connection_config (NMDnsManager *self, + const char *iface, + int ifindex) +{ + NMDnsConnectionConfigData *data; + NMDnsManagerPrivate *priv; + NMDnsPlugin *plugin; + guint i; + + g_return_if_fail (NM_IS_DNS_MANAGER (self)); + g_return_if_fail (iface != NULL && iface[0]); + g_return_if_fail (ifindex > 0); + + priv = NM_DNS_MANAGER_GET_PRIVATE (self); + plugin = priv->plugin; + + for (i = 0; i < priv->connection_configs->len; i++) { + data = priv->connection_configs->pdata[i]; + if (nm_streq (data->iface, iface)) { + nm_dns_plugin_update_mdns (plugin, + ifindex, + NM_SETTING_CONNECTION_MDNS_UNKNOWN); + g_ptr_array_remove_index_fast (priv->connection_configs, i); + return; + } + } +} + gboolean nm_dns_manager_get_resolv_conf_explicit (NMDnsManager *self) { @@ -1414,7 +1543,7 @@ nm_dns_manager_end_updates (NMDnsManager *self, const char *func) g_return_if_fail (priv->updates_queue > 0); if (priv->need_sort) { - g_ptr_array_sort (priv->configs, ip_config_data_ptr_compare); + g_ptr_array_sort (priv->ip_configs, ip_config_data_ptr_compare); priv->need_sort = FALSE; } @@ -1830,8 +1959,8 @@ _get_config_variant (NMDnsManager *self) g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}")); - for (i = 0; i < priv->configs->len; i++) { - NMDnsIPConfigData *current = priv->configs->pdata[i]; + for (i = 0; i < priv->ip_configs->len; i++) { + NMDnsIPConfigData *current = priv->ip_configs->pdata[i]; const NMIPConfig *config = current->config; GVariantBuilder entry_builder; GVariantBuilder strv_builder; @@ -1929,7 +2058,8 @@ nm_dns_manager_init (NMDnsManager *self) _LOGT ("creating..."); priv->config = g_object_ref (nm_config_get ()); - priv->configs = g_ptr_array_new_full (8, ip_config_data_destroy); + priv->ip_configs = g_ptr_array_new_full (8, ip_config_data_destroy); + priv->connection_configs = g_ptr_array_new_full (8, connection_config_data_destroy); /* Set the initial hash */ compute_hash (self, NULL, NM_DNS_MANAGER_GET_PRIVATE (self)->hash); @@ -1946,7 +2076,7 @@ dispose (GObject *object) { NMDnsManager *self = NM_DNS_MANAGER (object); NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self); - NMDnsIPConfigData *data; + NMDnsIPConfigData *ip_data; guint i; _LOGT ("disposing"); @@ -1961,13 +2091,18 @@ dispose (GObject *object) g_clear_object (&priv->config); } - if (priv->configs) { - for (i = 0; i < priv->configs->len; i++) { - data = priv->configs->pdata[i]; - forget_data (self, data); + if (priv->ip_configs) { + for (i = 0; i < priv->ip_configs->len; i++) { + ip_data = priv->ip_configs->pdata[i]; + forget_ip_data (self, ip_data); } - g_ptr_array_free (priv->configs, TRUE); - priv->configs = NULL; + g_ptr_array_free (priv->ip_configs, TRUE); + priv->ip_configs = NULL; + } + + if (priv->connection_configs) { + g_ptr_array_free (priv->connection_configs, TRUE); + priv->connection_configs = NULL; } nm_clear_g_source (&priv->plugin_ratelimit.timer); @@ -2033,4 +2168,3 @@ nm_dns_manager_class_init (NMDnsManagerClass *klass) NMDBUS_TYPE_DNS_MANAGER_SKELETON, NULL); } - 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 6ab2ea186f..ba219e851d 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; @@ -316,6 +318,45 @@ update (NMDnsPlugin *plugin, return TRUE; } +static gboolean +update_mdns (NMDnsPlugin *plugin, int ifindex, NMSettingConnectionMdns mdns) +{ + NMDnsSystemdResolved *self = NM_DNS_SYSTEMD_RESOLVED (plugin); + NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE (self); + char *value; + + _LOGI ("update_mdns: %i/%d", ifindex, mdns); + + nm_clear_g_cancellable (&priv->mdns_cancellable); + + if (!priv->resolve) + return FALSE; + + priv->mdns_cancellable = g_cancellable_new (); + + switch (mdns) { + case NM_SETTING_CONNECTION_MDNS_YES: + value = "yes"; + break; + case NM_SETTING_CONNECTION_MDNS_NO: + value = "no"; + break; + case NM_SETTING_CONNECTION_MDNS_RESOLVE: + value = "resolve"; + break; + default: + /* reset to system default */ + value = ""; + } + + g_dbus_proxy_call (priv->resolve, "SetLinkMulticastDNS", + g_variant_new ("(is)", ifindex, value), + G_DBUS_CALL_FLAGS_NONE, + -1, priv->mdns_cancellable, call_done, self); + + return TRUE; +} + /*****************************************************************************/ static gboolean @@ -404,6 +445,7 @@ dispose (GObject *object) g_clear_object (&priv->resolve); nm_clear_g_cancellable (&priv->init_cancellable); nm_clear_g_cancellable (&priv->update_cancellable); + nm_clear_g_cancellable (&priv->mdns_cancellable); G_OBJECT_CLASS (nm_dns_systemd_resolved_parent_class)->dispose (object); } @@ -418,5 +460,6 @@ nm_dns_systemd_resolved_class_init (NMDnsSystemdResolvedClass *dns_class) plugin_class->is_caching = is_caching; plugin_class->update = update; + plugin_class->update_mdns = update_mdns; plugin_class->get_name = get_name; } diff --git a/src/nm-policy.c b/src/nm-policy.c index 54b3595d76..d7aa7168aa 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) { @@ -1804,6 +1833,9 @@ device_state_changed (NMDevice *device, */ nm_connection_clear_secrets (NM_CONNECTION (connection)); + + /* Add connection settings (currently link mDNS state) */ + add_connection_dns (self, NM_CONNECTION (connection), ip_iface, nm_device_get_ip_ifindex (device)); } /* Add device's new IPv4 and IPv6 configs to DNS */ @@ -1858,8 +1890,12 @@ device_state_changed (NMDevice *device, && old_state == NM_DEVICE_STATE_UNAVAILABLE) reset_autoconnect_all (self, device, FALSE); - if (old_state > NM_DEVICE_STATE_DISCONNECTED) + if (old_state > NM_DEVICE_STATE_DISCONNECTED) { update_routing_and_dns (self, FALSE); + /* Remove connection settings (currently link mDNS state) */ + remove_connection_dns (self, ip_iface, nm_device_get_ip_ifindex (device)); + } + /* Device is now available for auto-activation */ schedule_activate_check (self, device); @@ -1992,6 +2028,19 @@ device_autoconnect_changed (NMDevice *device, schedule_activate_check (self, device); } +static void +device_ifindex_changed (NMDevice *device, + GParamSpec *pspec, + gpointer user_data) +{ + NMPolicyPrivate *priv = user_data; + const char *ip_iface = nm_device_get_ip_iface (device); + int ifindex = nm_device_get_ifindex (device); + + /* update ifindex mapping in DNS manager */ + nm_dns_manager_update_ifindex (priv->dns_manager, ip_iface, ifindex); +} + static void device_recheck_auto_activate (NMDevice *device, gpointer user_data) { @@ -2020,6 +2069,7 @@ devices_list_register (NMPolicy *self, NMDevice *device) g_signal_connect (device, NM_DEVICE_IP6_CONFIG_CHANGED, (GCallback) device_ip6_config_changed, priv); g_signal_connect (device, NM_DEVICE_IP6_PREFIX_DELEGATED, (GCallback) device_ip6_prefix_delegated, priv); g_signal_connect (device, NM_DEVICE_IP6_SUBNET_NEEDED, (GCallback) device_ip6_subnet_needed, priv); + g_signal_connect (device, "notify::" NM_DEVICE_IFINDEX, (GCallback) device_ifindex_changed, priv); g_signal_connect (device, "notify::" NM_DEVICE_AUTOCONNECT, (GCallback) device_autoconnect_changed, priv); g_signal_connect (device, NM_DEVICE_RECHECK_AUTO_ACTIVATE, (GCallback) device_recheck_auto_activate, priv); } @@ -2073,6 +2123,7 @@ vpn_connection_activated (NMPolicy *self, NMVpnConnection *vpn) NMIP4Config *ip4_config; NMIP6Config *ip6_config; const char *ip_iface; + NMConnection *connection; nm_dns_manager_begin_updates (priv->dns_manager, __func__); @@ -2091,6 +2142,10 @@ vpn_connection_activated (NMPolicy *self, NMVpnConnection *vpn) update_routing_and_dns (self, TRUE); nm_dns_manager_end_updates (priv->dns_manager, __func__); + + /* Make sure the connection settings are set */ + connection = nm_active_connection_get_applied_connection (NM_ACTIVE_CONNECTION (vpn)); + add_connection_dns (self, connection, ip_iface, nm_vpn_connection_get_ip_ifindex (vpn, TRUE)); } static void @@ -2117,6 +2172,10 @@ vpn_connection_deactivated (NMPolicy *self, NMVpnConnection *vpn) update_routing_and_dns (self, TRUE); nm_dns_manager_end_updates (priv->dns_manager, __func__); + + remove_connection_dns(self, + nm_vpn_connection_get_ip_iface (vpn, TRUE), + nm_vpn_connection_get_ip_ifindex (vpn, TRUE)); } static void From 230eb628219a4822eebb5dc776df0fa79839d33a Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 15 Dec 2017 12:11:53 +0100 Subject: [PATCH 06/33] 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. (cherry picked from commit eec907b35a1eb85f66cf9b9e031291354d7a0bc2) --- 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 96fca5e9ee..bc99065e71 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 97db8306d95fac111dc65887f860ec1835fb5d55 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 15 Dec 2017 12:15:05 +0100 Subject: [PATCH 07/33] 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*. (cherry picked from commit 9d92848ada434c9ffb8f55db2986514079f58fa3) --- 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 bc99065e71..e26d547aeb 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 ac8cc2cc6e..ec3b38a758 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.10.14 */ 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 6cdacd2e79..01d5384d6b 100644 --- a/src/dns/nm-dns-manager.c +++ b/src/dns/nm-dns-manager.c @@ -1440,7 +1440,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 d7aa7168aa..112965f033 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); + } } } @@ -2173,9 +2174,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 794b0a1c39..5084454f80 100644 --- a/src/nm-types.h +++ b/src/nm-types.h @@ -238,4 +238,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 366dd83476..827ba92b06 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c @@ -338,11 +338,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 e2c2a5d2a2..33cc172a0b 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; @@ -1889,10 +1890,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 678327e18f6263dec85ea55c1a9805cbe9a10743 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 15 Dec 2017 13:18:31 +0100 Subject: [PATCH 08/33] dns/trivial: move code (cherry picked from commit 03cba938730bc19057e51131297bed672e47ae99) --- 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 e6436c79e5..eef591017c 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 0e41dd6b4f443164fe9d44fedeeeafb28c221646 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 15 Dec 2017 13:17:22 +0100 Subject: [PATCH 09/33] dns: merge IPv4 and IPv6 versions of add_ip_config() (part 1) (cherry picked from commit 49fd1e412617ffcdd10d6f1f76f387bba71ae9d8) --- 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 eef591017c..fe53ac1766 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 8aea6745c4370b40b3cdcd7f1a696b50518f6da0 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 15 Dec 2017 13:24:21 +0100 Subject: [PATCH 10/33] dns: merge IPv4 and IPv6 versions of add_ip_config() (part 2) (cherry picked from commit 7d4def276400c3b28ff8c3f96e6791659f5bd0a9) --- 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 fe53ac1766..3c8557e450 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 0d3f19774f0eace031e3b0a7a29be6f89b131fab Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 19 Dec 2017 15:08:32 +0100 Subject: [PATCH 11/33] core: add nm_ip_config_get_ifindex() helper (cherry picked from commit 4ccfa7a79a2c3a10e39a8dea203cb0e51e603e80) --- 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 93a254b8c6..209336c895 100644 --- a/src/nm-ip4-config.h +++ b/src/nm-ip4-config.h @@ -350,6 +350,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 int nm_ip_config_get_dns_priority (const NMIPConfig *self) { From fb64e268bbbea58b889e80ee39c14fe23a151877 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 19 Dec 2017 14:27:18 +0100 Subject: [PATCH 12/33] 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. (cherry picked from commit 2aad517b0b3b29615d1afdc907107a24cca6e1f2) --- 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 502be781fe..0f291d34d0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4545,6 +4545,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-glib.h \ shared/nm-utils/nm-obj.h \ shared/nm-utils/nm-macros-internal.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 f2590e86b34749cd5be2ae052560a9efe83d8e42 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 8 Jan 2018 14:40:16 +0100 Subject: [PATCH 13/33] 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. (cherry picked from commit 901aa0315b592bc5f897b5abce05a5eed2ee3cad) --- 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 29678bb6fc..0a5de45923 100644 --- a/shared/nm-utils/nm-macros-internal.h +++ b/shared/nm-utils/nm-macros-internal.h @@ -1020,6 +1020,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 2642407dc2a10167cbff00ecc1c8104a42507f19 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 19 Dec 2017 15:07:53 +0100 Subject: [PATCH 14/33] 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. (cherry picked from commit 4be4a3c21f63c53db4cd8ef02cd9e05c86f11b20) --- 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 ba219e851d..e861c4b710 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) { @@ -101,42 +109,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, @@ -229,7 +201,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); @@ -239,8 +211,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); @@ -286,33 +258,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 9d5be62ffabe27184f8d430017ca8719cf5864fd Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 20 Dec 2017 16:34:00 +0100 Subject: [PATCH 15/33] 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. (cherry picked from commit b0f1a54c9bf0d4132a1e3f4b073be8d1d3387dde) --- 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 e861c4b710..db8b6e5b95 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) { @@ -187,13 +215,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 @@ -217,17 +245,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); @@ -236,18 +266,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); } } @@ -405,8 +436,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 e4270341caaf936e8b5f4d3e6595fe3d8445929d Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 19 Dec 2017 12:34:20 +0100 Subject: [PATCH 16/33] 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. (cherry picked from commit fc40d91b97a1e84ea72536d0dde89f4f479c8e97) --- 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 01d5384d6b..686dca3e82 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 0daa4db81bc3741ee61aa35c916609521b69de58 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Wed, 10 Jan 2018 11:21:27 +0100 Subject: [PATCH 17/33] dns: split out domains retrieval (cherry picked from commit e78bfb63cd7c4727a283fb38cf196350fe974922) --- src/dns/nm-dns-manager.c | 41 ++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/src/dns/nm-dns-manager.c b/src/dns/nm-dns-manager.c index 858d8ed79c..4ce322e31c 100644 --- a/src/dns/nm-dns-manager.c +++ b/src/dns/nm-dns-manager.c @@ -376,15 +376,37 @@ add_dns_option_item (GPtrArray *array, const char *str) g_ptr_array_add (array, g_strdup (str)); } +static void +add_dns_domains (GPtrArray *array, const NMIPConfig *ip_config) +{ + guint num_domains, num_searches, i; + const char *str; + + 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 (ip_config, i); + if (domain_is_valid (str, FALSE)) + add_string_item (array, str); + } + if (num_domains > 1 || !num_searches) { + for (i = 0; i < num_domains; i++) { + str = nm_ip_config_get_domain (ip_config, i); + if (domain_is_valid (str, FALSE)) + add_string_item (array, str); + } + } +} + static void merge_one_ip_config (NMResolvConfData *rc, int ifindex, const NMIPConfig *ip_config) { int addr_family; - guint num, num_domains, num_searches, i; + guint num, i; char buf[NM_UTILS_INET_ADDRSTRLEN + 50]; - const char *str; addr_family = nm_ip_config_get_addr_family (ip_config); @@ -417,20 +439,7 @@ merge_one_ip_config (NMResolvConfData *rc, add_string_item (rc->nameservers, buf); } - 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 (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 (ip_config, i); - if (domain_is_valid (str, FALSE)) - add_string_item (rc->searches, str); - } - } + add_dns_domains (rc->searches, ip_config); num = nm_ip_config_get_num_dns_options (ip_config); for (i = 0; i < num; i++) { From f43febc2ab5dde1bcb11a35f5328d93baae19fc1 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Wed, 10 Jan 2018 11:22:11 +0100 Subject: [PATCH 18/33] dns: add @dup argument to add_dns_domains() and add_string_item() Add a @dup argument that tells whether the new item should be duplicated. (cherry picked from commit b4db0e8362fa0587fcf25a13a2086864fd3062e2) --- src/dns/nm-dns-manager.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/dns/nm-dns-manager.c b/src/dns/nm-dns-manager.c index 4ce322e31c..297fce0af7 100644 --- a/src/dns/nm-dns-manager.c +++ b/src/dns/nm-dns-manager.c @@ -350,7 +350,7 @@ _ip_config_lst_head (NMDnsManager *self) /*****************************************************************************/ static void -add_string_item (GPtrArray *array, const char *str) +add_string_item (GPtrArray *array, const char *str, gboolean dup) { int i; @@ -366,7 +366,7 @@ add_string_item (GPtrArray *array, const char *str) } /* No dupes, add the new item */ - g_ptr_array_add (array, g_strdup (str)); + g_ptr_array_add (array, dup ? g_strdup (str): (gpointer) str); } static void @@ -377,7 +377,7 @@ add_dns_option_item (GPtrArray *array, const char *str) } static void -add_dns_domains (GPtrArray *array, const NMIPConfig *ip_config) +add_dns_domains (GPtrArray *array, const NMIPConfig *ip_config, gboolean dup) { guint num_domains, num_searches, i; const char *str; @@ -388,13 +388,13 @@ add_dns_domains (GPtrArray *array, const NMIPConfig *ip_config) for (i = 0; i < num_searches; i++) { str = nm_ip_config_get_search (ip_config, i); if (domain_is_valid (str, FALSE)) - add_string_item (array, str); + add_string_item (array, str, dup); } if (num_domains > 1 || !num_searches) { for (i = 0; i < num_domains; i++) { str = nm_ip_config_get_domain (ip_config, i); if (domain_is_valid (str, FALSE)) - add_string_item (array, str); + add_string_item (array, str, dup); } } } @@ -436,10 +436,10 @@ merge_one_ip_config (NMResolvConfData *rc, } } - add_string_item (rc->nameservers, buf); + add_string_item (rc->nameservers, buf, TRUE); } - add_dns_domains (rc->searches, ip_config); + add_dns_domains (rc->searches, ip_config, TRUE); num = nm_ip_config_get_num_dns_options (ip_config); for (i = 0; i < num; i++) { @@ -454,7 +454,8 @@ merge_one_ip_config (NMResolvConfData *rc, 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 (ip4_config, i), buf)); + nm_utils_inet4_ntop (nm_ip4_config_get_nis_server (ip4_config, i), buf), + TRUE); } if (nm_ip4_config_get_nis_domain (ip4_config)) { @@ -966,17 +967,17 @@ merge_global_dns_config (NMResolvConfData *rc, NMGlobalDnsConfig *global_conf) for (i = 0; searches && searches[i]; i++) { if (domain_is_valid (searches[i], FALSE)) - add_string_item (rc->searches, searches[i]); + add_string_item (rc->searches, searches[i], TRUE); } for (i = 0; options && options[i]; i++) - add_string_item (rc->options, options[i]); + add_string_item (rc->options, options[i], TRUE); default_domain = nm_global_dns_config_lookup_domain (global_conf, "*"); g_assert (default_domain); servers = nm_global_dns_domain_get_servers (default_domain); for (i = 0; servers && servers[i]; i++) - add_string_item (rc->nameservers, servers[i]); + add_string_item (rc->nameservers, servers[i], TRUE); return TRUE; } @@ -1089,9 +1090,9 @@ _collect_resolv_conf_data (NMDnsManager *self, && !nm_utils_ipaddr_valid (AF_UNSPEC, priv->hostname)) { hostdomain++; if (domain_is_valid (hostdomain, TRUE)) - add_string_item (rc.searches, hostdomain); + add_string_item (rc.searches, hostdomain, TRUE); else if (domain_is_valid (priv->hostname, TRUE)) - add_string_item (rc.searches, priv->hostname); + add_string_item (rc.searches, priv->hostname, TRUE); } } From fd5550e97c486c35da48253cb20857d18cbfad96 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sat, 16 Dec 2017 15:11:16 +0100 Subject: [PATCH 19/33] 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. (cherry picked from commit b40729ca5f72a147872c4d38b2de6b5fb757f5b4) --- 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 | 18 + src/nm-policy.c | 117 ++---- 9 files changed, 406 insertions(+), 584 deletions(-) diff --git a/src/dns/nm-dns-dnsmasq.c b/src/dns/nm-dns-dnsmasq.c index 3c8557e450..f1cf406c91 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 @@ -479,15 +480,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); @@ -496,15 +498,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 686dca3e82..858d8ed79c 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)); + } } } @@ -847,25 +919,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); @@ -939,16 +1007,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 (), @@ -958,37 +1025,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); } } @@ -999,16 +1073,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); } } @@ -1070,16 +1144,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) { @@ -1097,8 +1167,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); @@ -1235,116 +1305,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); } @@ -1352,38 +1402,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) @@ -1426,78 +1444,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) { @@ -1545,11 +1491,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"); @@ -1946,14 +1887,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))); @@ -1962,25 +1902,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)); @@ -1990,13 +1931,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}", @@ -2004,22 +1945,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); } @@ -2060,9 +2002,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); @@ -2079,37 +2024,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 db8b6e5b95..95a89059dc 100644 --- a/src/dns/nm-dns-systemd-resolved.c +++ b/src/dns/nm-dns-systemd-resolved.c @@ -284,8 +284,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); @@ -294,23 +294,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) { @@ -322,7 +325,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); } } @@ -347,45 +350,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 @@ -488,6 +452,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 209336c895..2f20a7b23f 100644 --- a/src/nm-ip4-config.h +++ b/src/nm-ip4-config.h @@ -350,12 +350,30 @@ nm_ip_config_get_addr_family (const NMIPConfig *config) } \ } G_STMT_END +#define _NM_IP_CONFIG_DISPATCH_VOID(config, v4_func, v6_func, ...) \ + G_STMT_START { \ + gconstpointer _config = (config); \ + \ + if (NM_IS_IP4_CONFIG (_config)) { \ + v4_func ((NMIP4Config *) _config, ##__VA_ARGS__); \ + } else { \ + nm_assert (NM_IS_IP6_CONFIG (_config)); \ + v6_func ((NMIP6Config *) _config, ##__VA_ARGS__); \ + } \ + } 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_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 int nm_ip_config_get_dns_priority (const NMIPConfig *self) { diff --git a/src/nm-policy.c b/src/nm-policy.c index 112965f033..97407f3c94 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) @@ -1745,7 +1712,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; @@ -1834,9 +1800,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 */ @@ -1845,10 +1808,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); @@ -1891,12 +1854,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); @@ -1952,7 +1911,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__); @@ -1963,10 +1921,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); @@ -1974,7 +1932,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__); @@ -1988,7 +1946,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__); @@ -1999,10 +1956,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); @@ -2010,7 +1967,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__); @@ -2029,19 +1986,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) { @@ -2070,7 +2014,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); } @@ -2123,30 +2066,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 @@ -2159,24 +2092,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 d4ca953620c4fb95d9fde9d9c851fba23d861caf Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Wed, 10 Jan 2018 11:22:44 +0100 Subject: [PATCH 20/33] dns: export search list in the D-Bus "domain" attribute The "domain" key of the D-Bus configuration dictionary specifies the domains a configuration applies to. In DNS code we consider domains and searches as equivalent, so they should be exported via D-Bus using the same logic used to populate resolv.conf and for plugins. (cherry picked from commit 70550e2740ce26234aa715e11f5fc38091c5d7ea) --- src/dns/nm-dns-manager.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/dns/nm-dns-manager.c b/src/dns/nm-dns-manager.c index 297fce0af7..17a170a48e 100644 --- a/src/dns/nm-dns-manager.c +++ b/src/dns/nm-dns-manager.c @@ -1899,6 +1899,7 @@ _get_config_variant (NMDnsManager *self) GVariantBuilder builder; NMDnsIPConfigData *ip_data; const CList *head; + gs_unref_ptrarray GPtrArray *array_domains = NULL; if (priv->config_variant) return priv->config_variant; @@ -1941,18 +1942,28 @@ _get_config_variant (NMDnsManager *self) "nameservers", g_variant_builder_end (&strv_builder)); + num = nm_ip_config_get_num_domains (ip_config); + num += nm_ip_config_get_num_searches (ip_config); if (num > 0) { - g_variant_builder_init (&strv_builder, G_VARIANT_TYPE ("as")); - for (i = 0; i < num; i++) { - g_variant_builder_add (&strv_builder, - "s", - nm_ip_config_get_domain (ip_config, i)); + if (!array_domains) + array_domains = g_ptr_array_sized_new (num); + else + g_ptr_array_set_size (array_domains, 0); + + add_dns_domains (array_domains, ip_config, FALSE); + if (array_domains->len) { + g_variant_builder_init (&strv_builder, G_VARIANT_TYPE ("as")); + for (i = 0; i < array_domains->len; i++) { + g_variant_builder_add (&strv_builder, + "s", + array_domains->pdata[i]); + } + g_variant_builder_add (&entry_builder, + "{sv}", + "domains", + g_variant_builder_end (&strv_builder)); } - g_variant_builder_add (&entry_builder, - "{sv}", - "domains", - g_variant_builder_end (&strv_builder)); } ifname = nm_platform_link_get_name (NM_PLATFORM_GET, ip_data->data->ifindex); From d7ebbd69a05c8bee636c5eeba2206176ba29bdc3 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 20 Dec 2017 14:49:32 +0100 Subject: [PATCH 21/33] 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. (cherry picked from commit c03a5349638ac0fa911d5f7116e6f7c52d11b931) --- 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 446540aa1b..135550ce27 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 d45f1bb07b..ce6c585364 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -1788,6 +1788,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, @@ -5867,6 +5895,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)); @@ -6177,6 +6206,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)); @@ -6555,6 +6585,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)); @@ -9250,6 +9281,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 ac73ee0c4b..c7d233ff7d 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 95a89059dc..b03d9842cb 100644 --- a/src/dns/nm-dns-systemd-resolved.c +++ b/src/dns/nm-dns-systemd-resolved.c @@ -230,6 +230,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); @@ -239,18 +241,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 15157739c1..aeb5bbe8a8 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; @@ -893,6 +894,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) { @@ -1012,6 +1014,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)); } @@ -1227,6 +1231,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)); } @@ -1463,6 +1472,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)); } @@ -1550,6 +1563,7 @@ nm_ip4_config_intersect (NMIP4Config *dst, /* ignore dns options */ /* ignore NIS */ /* ignore WINS */ + /* ignore mdns */ g_object_thaw_notify (G_OBJECT (dst)); } @@ -1779,6 +1793,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); @@ -2456,6 +2472,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) { @@ -3065,6 +3096,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 2f20a7b23f..c2ead0c66e 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" @@ -171,6 +173,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); @@ -194,6 +197,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 33cc172a0b..af70c83b0f 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c @@ -1894,9 +1894,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 d5a649ba03..1a093e674c 100644 --- a/src/vpn/nm-vpn-connection.c +++ b/src/vpn/nm-vpn-connection.c @@ -1462,6 +1462,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; @@ -1566,6 +1567,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 */ @@ -1623,6 +1625,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 f144eac12c3a02169e4fb375b77d5fcc4a419108 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Wed, 10 Jan 2018 11:23:13 +0100 Subject: [PATCH 22/33] dns: systemd-resolved: use generic ip-config functions (cherry picked from commit 42ea86fb7a678d84c4cf490e83a4c5189af7b2cc) --- src/dns/nm-dns-systemd-resolved.c | 45 +++++++------------------------ 1 file changed, 10 insertions(+), 35 deletions(-) diff --git a/src/dns/nm-dns-systemd-resolved.c b/src/dns/nm-dns-systemd-resolved.c index b03d9842cb..ec8561fac0 100644 --- a/src/dns/nm-dns-systemd-resolved.c +++ b/src/dns/nm-dns-systemd-resolved.c @@ -141,40 +141,23 @@ static void update_add_ip_config (NMDnsSystemdResolved *self, GVariantBuilder *dns, GVariantBuilder *domains, - gpointer config) + NMIPConfig *config) { int addr_family; gsize addr_size; guint i, n; gboolean route_only; - if (NM_IS_IP4_CONFIG (config)) - addr_family = AF_INET; - else if (NM_IS_IP6_CONFIG (config)) - addr_family = AF_INET6; - else - g_return_if_reached (); - + addr_family = nm_ip_config_get_addr_family (config); addr_size = nm_utils_addr_family_to_size (addr_family); - n = addr_family == AF_INET - ? nm_ip4_config_get_num_nameservers (config) - : nm_ip6_config_get_num_nameservers (config); + n = nm_ip_config_get_num_nameservers (config); for (i = 0 ; i < n; i++) { - in_addr_t ns4; - gconstpointer ns; - - if (addr_family == AF_INET) { - ns4 = nm_ip4_config_get_nameserver (config, i); - ns = &ns4; - } else - ns = nm_ip6_config_get_nameserver (config, i); - g_variant_builder_open (dns, G_VARIANT_TYPE ("(iay)")); g_variant_builder_add (dns, "i", addr_family); g_variant_builder_add_value (dns, g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, - ns, + nm_ip_config_get_nameserver (config, i), addr_size, 1)); g_variant_builder_close (dns); @@ -183,29 +166,21 @@ update_add_ip_config (NMDnsSystemdResolved *self, /* If this link is never the default (e.g. only used for resources on this * network) add a routing domain. */ route_only = addr_family == AF_INET - ? !nm_ip4_config_best_default_route_get (config) - : !nm_ip6_config_best_default_route_get (config); + ? !nm_ip4_config_best_default_route_get (NM_IP4_CONFIG (config)) + : !nm_ip6_config_best_default_route_get (NM_IP6_CONFIG (config)); - n = addr_family == AF_INET - ? nm_ip4_config_get_num_searches (config) - : nm_ip6_config_get_num_searches (config); + n = nm_ip_config_get_num_searches (config); if (n > 0) { for (i = 0; i < n; i++) { g_variant_builder_add (domains, "(sb)", - addr_family == AF_INET - ? nm_ip4_config_get_search (config, i) - : nm_ip6_config_get_search (config, i), + nm_ip_config_get_search (config, i), route_only); } } else { - n = addr_family == AF_INET - ? nm_ip4_config_get_num_domains (config) - : nm_ip6_config_get_num_domains (config); + n = nm_ip_config_get_num_domains (config); for (i = 0; i < n; i++) { g_variant_builder_add (domains, "(sb)", - addr_family == AF_INET - ? nm_ip4_config_get_domain (config, i) - : nm_ip6_config_get_domain (config, i), + nm_ip_config_get_domain (config, i), route_only); } } From 427c978e308aa41b1d41911f14a6e77d413ea402 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 8 Jan 2018 15:44:05 +0100 Subject: [PATCH 23/33] policy: merge IPv4 and IPv6 versions of device_ip_config_changed() (cherry picked from commit d1de905ed3e6a524a9d574402b078bb08e8b3ffe) --- 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 97407f3c94..85c1dec14a 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -1904,13 +1904,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__); @@ -1922,52 +1933,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__); @@ -2010,8 +1992,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); From 3422988c2a12426c48f396034ee1331008145469 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Wed, 10 Jan 2018 11:23:33 +0100 Subject: [PATCH 24/33] dns: introduce routing domains Similarly to what systemd-resolved does, introduce the concept of "routing" domain, which is a domain in the search list that is used only to decide the interface over which a query must be forwarded, but is not used to complete unqualified host names. Routing domains are those starting with a tilde ('~') before the actual domain name. Domains without the initial tilde are used both for completing unqualified names and for the routing decision. (cherry picked from commit e91f1a7d2a6b8400b6b331d5b72287dcb5164a39) --- clients/common/settings-docs.c.in | 4 ++-- libnm-core/nm-setting-ip-config.c | 5 ++++- src/dns/nm-dns-dnsmasq.c | 8 ++++--- src/dns/nm-dns-manager.c | 36 ++++++++++++++++++++++--------- src/dns/nm-dns-systemd-resolved.c | 21 +++++++++--------- src/nm-core-utils.c | 15 +++++++++++++ src/nm-core-utils.h | 2 ++ 7 files changed, 64 insertions(+), 27 deletions(-) diff --git a/clients/common/settings-docs.c.in b/clients/common/settings-docs.c.in index 8218d0a9d2..da1f24fa64 100644 --- a/clients/common/settings-docs.c.in +++ b/clients/common/settings-docs.c.in @@ -217,7 +217,7 @@ #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS N_("Array of IP addresses of DNS servers.") #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_OPTIONS N_("Array of DNS options as described in man 5 resolv.conf. NULL means that the options are unset and left at the default. In this case NetworkManager will use default options. This is distinct from an empty list of properties.") #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_PRIORITY N_("Intra-connection DNS priority. The relative priority to be used when determining the order of DNS servers in resolv.conf. A lower value means that servers will be on top of the file. Zero selects the default value, which is 50 for VPNs and 100 for other connections. Note that the priority is to order DNS settings for multiple active connections. It does not disambiguate multiple DNS servers within the same connection profile. For that, just specify the DNS servers in the desired order. When multiple devices have configurations with the same priority, the one with an active default route will be preferred. Note that when using dns=dnsmasq the order is meaningless since dnsmasq forwards queries to all known servers at the same time. Negative values have the special effect of excluding other configurations with a greater priority value; so in presence of at least a negative priority, only DNS servers from connections with the lowest priority value will be used.") -#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_SEARCH N_("Array of DNS search domains.") +#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_SEARCH N_("Array of DNS search domains. Domains starting with a tilde ('~') are considered 'routing' domains and are used only to decide the interface over which a query must be forwarded; they are not used to complete unqualified host names.") #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_GATEWAY N_("The gateway associated with this configuration. This is only meaningful if \"addresses\" is also set.") #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_IGNORE_AUTO_DNS N_("When \"method\" is set to \"auto\" and this property to TRUE, automatically configured nameservers and search domains are ignored and only nameservers and search domains specified in the \"dns\" and \"dns-search\" properties, if any, are used.") #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_IGNORE_AUTO_ROUTES N_("When \"method\" is set to \"auto\" and this property to TRUE, automatically configured routes are ignored and only routes specified in the \"routes\" property, if any, are used.") @@ -237,7 +237,7 @@ #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS N_("Array of IP addresses of DNS servers.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_OPTIONS N_("Array of DNS options as described in man 5 resolv.conf. NULL means that the options are unset and left at the default. In this case NetworkManager will use default options. This is distinct from an empty list of properties.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_PRIORITY N_("Intra-connection DNS priority. The relative priority to be used when determining the order of DNS servers in resolv.conf. A lower value means that servers will be on top of the file. Zero selects the default value, which is 50 for VPNs and 100 for other connections. Note that the priority is to order DNS settings for multiple active connections. It does not disambiguate multiple DNS servers within the same connection profile. For that, just specify the DNS servers in the desired order. When multiple devices have configurations with the same priority, the one with an active default route will be preferred. Note that when using dns=dnsmasq the order is meaningless since dnsmasq forwards queries to all known servers at the same time. Negative values have the special effect of excluding other configurations with a greater priority value; so in presence of at least a negative priority, only DNS servers from connections with the lowest priority value will be used.") -#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_SEARCH N_("Array of DNS search domains.") +#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_SEARCH N_("Array of DNS search domains. Domains starting with a tilde ('~') are considered 'routing' domains and are used only to decide the interface over which a query must be forwarded; they are not used to complete unqualified host names.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_GATEWAY N_("The gateway associated with this configuration. This is only meaningful if \"addresses\" is also set.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_IGNORE_AUTO_DNS N_("When \"method\" is set to \"auto\" and this property to TRUE, automatically configured nameservers and search domains are ignored and only nameservers and search domains specified in the \"dns\" and \"dns-search\" properties, if any, are used.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_IGNORE_AUTO_ROUTES N_("When \"method\" is set to \"auto\" and this property to TRUE, automatically configured routes are ignored and only routes specified in the \"routes\" property, if any, are used.") diff --git a/libnm-core/nm-setting-ip-config.c b/libnm-core/nm-setting-ip-config.c index 779d4428ff..18d93f9deb 100644 --- a/libnm-core/nm-setting-ip-config.c +++ b/libnm-core/nm-setting-ip-config.c @@ -2960,7 +2960,10 @@ nm_setting_ip_config_class_init (NMSettingIPConfigClass *setting_class) /** * NMSettingIPConfig:dns-search: * - * Array of DNS search domains. + * Array of DNS search domains. Domains starting with a tilde ('~') + * are considered 'routing' domains and are used only to decide the + * interface over which a query must be forwarded; they are not used + * to complete unqualified host names. **/ g_object_class_install_property (object_class, PROP_DNS_SEARCH, diff --git a/src/dns/nm-dns-dnsmasq.c b/src/dns/nm-dns-dnsmasq.c index f1cf406c91..bc6ef4a26d 100644 --- a/src/dns/nm-dns-dnsmasq.c +++ b/src/dns/nm-dns-dnsmasq.c @@ -219,7 +219,7 @@ add_ip_config (NMDnsDnsmasq *self, char ip_addr_to_string_buf[IP_ADDR_TO_STRING_BUFLEN]; char **domains, **iter; gboolean iface_resolved = FALSE; - const char *iface = NULL; + const char *iface = NULL, *domain; addr_family = nm_ip_config_get_addr_family (ip_config); g_return_if_fail (NM_IN_SET (addr_family, AF_INET, AF_INET6)); @@ -247,21 +247,23 @@ add_ip_config (NMDnsDnsmasq *self, /* searches are preferred over domains */ n = nm_ip_config_get_num_searches (ip_config); for (i = 0; i < n; i++) { + domain = nm_utils_parse_dns_domain (nm_ip_config_get_search (ip_config, i), NULL); add_dnsmasq_nameserver (self, servers, ip_addr_to_string_buf, - nm_ip_config_get_search (ip_config, i)); + domain); added = TRUE; } if (n == 0) { /* If not searches, use any domains */ n = nm_ip_config_get_num_domains (ip_config); + domain = nm_utils_parse_dns_domain (nm_ip_config_get_domain (ip_config, i), NULL); for (i = 0; i < n; i++) { add_dnsmasq_nameserver (self, servers, ip_addr_to_string_buf, - nm_ip_config_get_domain (ip_config, i)); + domain); added = TRUE; } } diff --git a/src/dns/nm-dns-manager.c b/src/dns/nm-dns-manager.c index 17a170a48e..6813e9b86c 100644 --- a/src/dns/nm-dns-manager.c +++ b/src/dns/nm-dns-manager.c @@ -180,7 +180,7 @@ static void _ip_config_dns_priority_changed (gpointer config, /*****************************************************************************/ static gboolean -domain_is_valid (const gchar *domain, gboolean check_public_suffix) +domain_is_valid (const char *domain, gboolean check_public_suffix) { if (*domain == '\0') return FALSE; @@ -191,6 +191,12 @@ domain_is_valid (const gchar *domain, gboolean check_public_suffix) return TRUE; } +static gboolean +domain_is_routing (const char *domain) +{ + return domain[0] == '~'; +} + /*****************************************************************************/ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_rc_manager_to_string, NMDnsManagerResolvConfManager, @@ -377,7 +383,8 @@ add_dns_option_item (GPtrArray *array, const char *str) } static void -add_dns_domains (GPtrArray *array, const NMIPConfig *ip_config, gboolean dup) +add_dns_domains (GPtrArray *array, const NMIPConfig *ip_config, + gboolean include_routing, gboolean dup) { guint num_domains, num_searches, i; const char *str; @@ -387,14 +394,20 @@ add_dns_domains (GPtrArray *array, const NMIPConfig *ip_config, gboolean dup) for (i = 0; i < num_searches; i++) { str = nm_ip_config_get_search (ip_config, i); - if (domain_is_valid (str, FALSE)) - add_string_item (array, str, dup); + if (!include_routing && domain_is_routing (str)) + continue; + if (!domain_is_valid (nm_utils_parse_dns_domain (str, NULL), FALSE)) + continue; + add_string_item (array, str, dup); } if (num_domains > 1 || !num_searches) { for (i = 0; i < num_domains; i++) { str = nm_ip_config_get_domain (ip_config, i); - if (domain_is_valid (str, FALSE)) - add_string_item (array, str, dup); + if (!include_routing && domain_is_routing (str)) + continue; + if (!domain_is_valid (nm_utils_parse_dns_domain (str, NULL), FALSE)) + continue; + add_string_item (array, str, dup); } } } @@ -439,7 +452,7 @@ merge_one_ip_config (NMResolvConfData *rc, add_string_item (rc->nameservers, buf, TRUE); } - add_dns_domains (rc->searches, ip_config, TRUE); + add_dns_domains (rc->searches, ip_config, FALSE, TRUE); num = nm_ip_config_get_num_dns_options (ip_config); for (i = 0; i < num; i++) { @@ -966,8 +979,11 @@ merge_global_dns_config (NMResolvConfData *rc, NMGlobalDnsConfig *global_conf) options = nm_global_dns_config_get_options (global_conf); for (i = 0; searches && searches[i]; i++) { - if (domain_is_valid (searches[i], FALSE)) - add_string_item (rc->searches, searches[i], TRUE); + if (domain_is_routing (searches[i])) + continue; + if (!domain_is_valid (searches[i], FALSE)) + continue; + add_string_item (rc->searches, searches[i], TRUE); } for (i = 0; options && options[i]; i++) @@ -1951,7 +1967,7 @@ _get_config_variant (NMDnsManager *self) else g_ptr_array_set_size (array_domains, 0); - add_dns_domains (array_domains, ip_config, FALSE); + add_dns_domains (array_domains, ip_config, TRUE, FALSE); if (array_domains->len) { g_variant_builder_init (&strv_builder, G_VARIANT_TYPE ("as")); for (i = 0; i < array_domains->len; i++) { diff --git a/src/dns/nm-dns-systemd-resolved.c b/src/dns/nm-dns-systemd-resolved.c index ec8561fac0..4692f978fe 100644 --- a/src/dns/nm-dns-systemd-resolved.c +++ b/src/dns/nm-dns-systemd-resolved.c @@ -146,7 +146,8 @@ update_add_ip_config (NMDnsSystemdResolved *self, int addr_family; gsize addr_size; guint i, n; - gboolean route_only; + gboolean is_routing; + const char *domain; addr_family = nm_ip_config_get_addr_family (config); addr_size = nm_utils_addr_family_to_size (addr_family); @@ -163,25 +164,23 @@ update_add_ip_config (NMDnsSystemdResolved *self, g_variant_builder_close (dns); } - /* If this link is never the default (e.g. only used for resources on this - * network) add a routing domain. */ - route_only = addr_family == AF_INET - ? !nm_ip4_config_best_default_route_get (NM_IP4_CONFIG (config)) - : !nm_ip6_config_best_default_route_get (NM_IP6_CONFIG (config)); - n = nm_ip_config_get_num_searches (config); if (n > 0) { for (i = 0; i < n; i++) { + domain = nm_utils_parse_dns_domain (nm_ip_config_get_search (config, i), + &is_routing); g_variant_builder_add (domains, "(sb)", - nm_ip_config_get_search (config, i), - route_only); + domain, + is_routing); } } else { n = nm_ip_config_get_num_domains (config); for (i = 0; i < n; i++) { + domain = nm_utils_parse_dns_domain (nm_ip_config_get_domain (config, i), + &is_routing); g_variant_builder_add (domains, "(sb)", - nm_ip_config_get_domain (config, i), - route_only); + domain, + is_routing); } } } diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c index f6b33a1490..a8c593ecaa 100644 --- a/src/nm-core-utils.c +++ b/src/nm-core-utils.c @@ -4329,6 +4329,21 @@ nm_utils_format_con_diff_for_audit (GHashTable *diff) return g_string_free (str, FALSE); } +const char * +nm_utils_parse_dns_domain (const char *domain, gboolean *is_routing) +{ + g_return_val_if_fail (domain, NULL); + g_return_val_if_fail (domain[0], NULL); + + if (domain[0] == '~') { + domain++; + NM_SET_OUT (is_routing, TRUE); + } else + NM_SET_OUT (is_routing, FALSE); + + return domain; +} + /*****************************************************************************/ NM_UTILS_ENUM2STR_DEFINE (nm_icmpv6_router_pref_to_string, NMIcmpv6RouterPref, diff --git a/src/nm-core-utils.h b/src/nm-core-utils.h index cc78472442..f43648c1bb 100644 --- a/src/nm-core-utils.h +++ b/src/nm-core-utils.h @@ -450,4 +450,6 @@ const char *nm_activation_type_to_string (NMActivationType activation_type); /*****************************************************************************/ +const char *nm_utils_parse_dns_domain (const char *domain, gboolean *is_routing); + #endif /* __NM_CORE_UTILS_H__ */ From 6a0e5fdd47166f73af4ded9364f26d55a044097f Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Fri, 23 Mar 2018 18:49:15 +0100 Subject: [PATCH 25/33] dns: dnsmasq: fix adding multiple domains Fixes: e91f1a7d2a6b8400b6b331d5b72287dcb5164a39 (cherry picked from commit 14b6e330e268f60678e336df4a6dce5acf62af69) --- src/dns/nm-dns-dnsmasq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dns/nm-dns-dnsmasq.c b/src/dns/nm-dns-dnsmasq.c index bc6ef4a26d..9fd34aeb7c 100644 --- a/src/dns/nm-dns-dnsmasq.c +++ b/src/dns/nm-dns-dnsmasq.c @@ -258,8 +258,8 @@ add_ip_config (NMDnsDnsmasq *self, if (n == 0) { /* If not searches, use any domains */ n = nm_ip_config_get_num_domains (ip_config); - domain = nm_utils_parse_dns_domain (nm_ip_config_get_domain (ip_config, i), NULL); for (i = 0; i < n; i++) { + domain = nm_utils_parse_dns_domain (nm_ip_config_get_domain (ip_config, i), NULL); add_dnsmasq_nameserver (self, servers, ip_addr_to_string_buf, From f853788290eb5f9d7a2752bd65367553f5fac3e2 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Sat, 24 Mar 2018 09:34:35 +0100 Subject: [PATCH 26/33] core: reject invalid domains from ip configurations Reject domains containing ".." or starting with "." (cherry picked from commit 82ebfa73514d853f4da39c5108b30f4643ce727e) --- src/nm-ip4-config.c | 66 +++++++++++++++++-------------------- src/nm-ip4-config.h | 2 ++ src/nm-ip6-config.c | 41 +++-------------------- src/tests/test-ip4-config.c | 6 +++- src/tests/test-ip6-config.c | 6 +++- 5 files changed, 47 insertions(+), 74 deletions(-) diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index aeb5bbe8a8..803a7de05e 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -2286,6 +2286,31 @@ _nm_ip4_config_get_nameserver (const NMIP4Config *self, guint i) /*****************************************************************************/ +gboolean +_nm_ip_config_check_and_add_domain (GPtrArray *array, const char *domain) +{ + char *copy = NULL; + size_t len; + + g_return_val_if_fail (domain, FALSE); + g_return_val_if_fail (domain[0] != '\0', FALSE); + + if (domain[0] == '.' || strstr (domain, "..")) + return FALSE; + + len = strlen (domain); + if (domain[len - 1] == '.') + domain = copy = g_strndup (domain, len - 1); + + if (nm_utils_strv_find_first ((char **) array->pdata, array->len, domain) >= 0) { + g_free (copy); + return FALSE; + } + + g_ptr_array_add (array, copy ?: g_strdup (domain)); + return TRUE; +} + void nm_ip4_config_reset_domains (NMIP4Config *self) { @@ -2301,17 +2326,9 @@ void nm_ip4_config_add_domain (NMIP4Config *self, const char *domain) { NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); - int i; - g_return_if_fail (domain != NULL); - g_return_if_fail (domain[0] != '\0'); - - for (i = 0; i < priv->domains->len; i++) - if (!g_strcmp0 (g_ptr_array_index (priv->domains, i), domain)) - return; - - g_ptr_array_add (priv->domains, g_strdup (domain)); - _notify (self, PROP_DOMAINS); + if (_nm_ip_config_check_and_add_domain (priv->domains, domain)) + _notify (self, PROP_DOMAINS); } void @@ -2355,35 +2372,12 @@ nm_ip4_config_reset_searches (NMIP4Config *self) } void -nm_ip4_config_add_search (NMIP4Config *self, const char *new) +nm_ip4_config_add_search (NMIP4Config *self, const char *search) { NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); - char *search; - size_t len; - g_return_if_fail (new != NULL); - g_return_if_fail (new[0] != '\0'); - - search = g_strdup (new); - - /* Remove trailing dot as it has no effect */ - len = strlen (search); - if (search[len - 1] == '.') - search[len - 1] = 0; - - if (!search[0]) { - g_free (search); - return; - } - - if (nm_utils_strv_find_first ((char **) priv->searches->pdata, - priv->searches->len, search) >= 0) { - g_free (search); - return; - } - - g_ptr_array_add (priv->searches, search); - _notify (self, PROP_SEARCHES); + if (_nm_ip_config_check_and_add_domain (priv->searches, search)) + _notify (self, PROP_SEARCHES); } void diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h index c2ead0c66e..497ba3f0e2 100644 --- a/src/nm-ip4-config.h +++ b/src/nm-ip4-config.h @@ -280,6 +280,8 @@ gboolean nm_ip4_config_nmpobj_remove (NMIP4Config *self, void nm_ip4_config_hash (const NMIP4Config *self, GChecksum *sum, gboolean dns_only); gboolean nm_ip4_config_equal (const NMIP4Config *a, const NMIP4Config *b); +gboolean _nm_ip_config_check_and_add_domain (GPtrArray *array, const char *domain); + /*****************************************************************************/ #include "nm-ip6-config.h" diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index ea3a202987..7f360921dc 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -2054,17 +2054,9 @@ void nm_ip6_config_add_domain (NMIP6Config *self, const char *domain) { NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); - int i; - g_return_if_fail (domain != NULL); - g_return_if_fail (domain[0] != '\0'); - - for (i = 0; i < priv->domains->len; i++) - if (!g_strcmp0 (g_ptr_array_index (priv->domains, i), domain)) - return; - - g_ptr_array_add (priv->domains, g_strdup (domain)); - _notify (self, PROP_DOMAINS); + if (_nm_ip_config_check_and_add_domain (priv->domains, domain)) + _notify (self, PROP_DOMAINS); } void @@ -2108,35 +2100,12 @@ nm_ip6_config_reset_searches (NMIP6Config *self) } void -nm_ip6_config_add_search (NMIP6Config *self, const char *new) +nm_ip6_config_add_search (NMIP6Config *self, const char *search) { NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); - char *search; - size_t len; - g_return_if_fail (new != NULL); - g_return_if_fail (new[0] != '\0'); - - search = g_strdup (new); - - /* Remove trailing dot as it has no effect */ - len = strlen (search); - if (search[len - 1] == '.') - search[len - 1] = 0; - - if (!search[0]) { - g_free (search); - return; - } - - if (nm_utils_strv_find_first ((char **) priv->searches->pdata, - priv->searches->len, search) >= 0) { - g_free (search); - return; - } - - g_ptr_array_add (priv->searches, search); - _notify (self, PROP_SEARCHES); + if (_nm_ip_config_check_and_add_domain (priv->searches, search)) + _notify (self, PROP_SEARCHES); } void diff --git a/src/tests/test-ip4-config.c b/src/tests/test-ip4-config.c index 4c3c344e46..9fea6af5b1 100644 --- a/src/tests/test-ip4-config.c +++ b/src/tests/test-ip4-config.c @@ -319,11 +319,15 @@ test_strip_search_trailing_dot (void) nm_ip4_config_add_search (config, "bar."); nm_ip4_config_add_search (config, "baz.com"); nm_ip4_config_add_search (config, "baz.com."); + nm_ip4_config_add_search (config, "foobar.."); + nm_ip4_config_add_search (config, ".foobar"); + nm_ip4_config_add_search (config, "~."); - g_assert_cmpuint (nm_ip4_config_get_num_searches (config), ==, 3); + g_assert_cmpuint (nm_ip4_config_get_num_searches (config), ==, 4); g_assert_cmpstr (nm_ip4_config_get_search (config, 0), ==, "foo"); g_assert_cmpstr (nm_ip4_config_get_search (config, 1), ==, "bar"); g_assert_cmpstr (nm_ip4_config_get_search (config, 2), ==, "baz.com"); + g_assert_cmpstr (nm_ip4_config_get_search (config, 3), ==, "~"); g_object_unref (config); } diff --git a/src/tests/test-ip6-config.c b/src/tests/test-ip6-config.c index bcbeee3e10..eb322b4789 100644 --- a/src/tests/test-ip6-config.c +++ b/src/tests/test-ip6-config.c @@ -338,11 +338,15 @@ test_strip_search_trailing_dot (void) nm_ip6_config_add_search (config, "bar."); nm_ip6_config_add_search (config, "baz.com"); nm_ip6_config_add_search (config, "baz.com."); + nm_ip6_config_add_search (config, "foobar.."); + nm_ip6_config_add_search (config, ".foobar"); + nm_ip6_config_add_search (config, "~."); - g_assert_cmpuint (nm_ip6_config_get_num_searches (config), ==, 3); + g_assert_cmpuint (nm_ip6_config_get_num_searches (config), ==, 4); g_assert_cmpstr (nm_ip6_config_get_search (config, 0), ==, "foo"); g_assert_cmpstr (nm_ip6_config_get_search (config, 1), ==, "bar"); g_assert_cmpstr (nm_ip6_config_get_search (config, 2), ==, "baz.com"); + g_assert_cmpstr (nm_ip6_config_get_search (config, 3), ==, "~"); g_object_unref (config); } From ad0400408ef797c75407e3bc016379ff0944aa16 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Fri, 23 Mar 2018 18:49:46 +0100 Subject: [PATCH 27/33] dns: use dns-priority to provide a preprocessed domain list to plugins Do some preprocessing on the DNS configuration sent to plugins: - add the '~' default routing (lookup) domain to IP configurations with the default route or, when there is none, to all non-VPN IP configurations - use the dns-priority to decide which connection to use in case multiple connections have the same domain - consider a negative dns-priority value as a way to 'shadow' all subdomains from other connections - compute reverse DNS domains and add the resulting domain list to NMDnsIPConfigData so that split-DNS plugins can use that directly instead of reimplementing the same logic themselves. (cherry picked from commit dd1e671fe5cf28ee1b8cf701895f041f6f3b8b1a) --- src/dns/nm-dns-dnsmasq.c | 1 + src/dns/nm-dns-manager.c | 199 +++++++++++++++++++++++++++++++++++++++ src/dns/nm-dns-manager.h | 4 + src/nm-ip4-config.h | 6 ++ 4 files changed, 210 insertions(+) diff --git a/src/dns/nm-dns-dnsmasq.c b/src/dns/nm-dns-dnsmasq.c index 9fd34aeb7c..c3065ea2db 100644 --- a/src/dns/nm-dns-dnsmasq.c +++ b/src/dns/nm-dns-dnsmasq.c @@ -75,6 +75,7 @@ G_DEFINE_TYPE (NMDnsDnsmasq, nm_dns_dnsmasq, NM_TYPE_DNS_PLUGIN) /*****************************************************************************/ +/* FIXME: this is a duplicate of the function in nm-dns-manager.c */ static char ** get_ip_rdns_domains (NMIPConfig *ip_config) { diff --git a/src/dns/nm-dns-manager.c b/src/dns/nm-dns-manager.c index 6813e9b86c..657a99a5d8 100644 --- a/src/dns/nm-dns-manager.c +++ b/src/dns/nm-dns-manager.c @@ -274,6 +274,9 @@ _ip_config_data_free (NMDnsIPConfigData *ip_data) c_list_unlink_stale (&ip_data->data_lst); c_list_unlink_stale (&ip_data->ip_config_lst); + g_free (ip_data->domains.search); + g_strfreev (ip_data->domains.reverse); + g_signal_handlers_disconnect_by_func (ip_data->ip_config, _ip_config_dns_priority_changed, ip_data); @@ -1130,6 +1133,197 @@ _collect_resolv_conf_data (NMDnsManager *self, *out_nis_domain = rc.nis_domain; } +static char ** +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; + + nm_assert_addr_family (addr_family); + + domains = g_ptr_array_sized_new (5); + + if (addr_family == AF_INET) { + NMIP4Config *ip4 = (gpointer) ip_config; + const NMPlatformIP4Address *address; + const NMPlatformIP4Route *route; + + nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, ip4, &address) + nm_utils_get_reverse_dns_domains_ip4 (address->address, address->plen, domains); + + 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; + + 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); + } + } + + /* Terminating NULL so we can use g_strfreev() to free it */ + g_ptr_array_add (domains, NULL); + + /* Free the array and return NULL if the only element was the ending NULL */ + strv = (char **) g_ptr_array_free (domains, (domains->len == 1)); + + return _nm_utils_strv_cleanup (strv, FALSE, FALSE, TRUE); +} + +/* Check if the domain is shadowed by a parent domain with more negative priority */ +static gboolean +domain_is_shadowed (GHashTable *ht, + const char *domain, int priority, + const char **out_parent, int *out_parent_priority) +{ + char *parent; + int parent_priority; + + nm_assert (!g_hash_table_contains (ht, domain)); + + parent_priority = GPOINTER_TO_INT (g_hash_table_lookup (ht, "")); + if (parent_priority < 0 && parent_priority < priority) { + *out_parent = ""; + *out_parent_priority = parent_priority; + return TRUE; + } + + parent = strchr (domain, '.'); + while (parent && parent[1]) { + parent++; + parent_priority = GPOINTER_TO_INT (g_hash_table_lookup (ht, parent)); + if (parent_priority < 0 && parent_priority < priority) { + *out_parent = parent; + *out_parent_priority = parent_priority; + return TRUE; + } + parent = strchr (parent, '.'); + } + + return FALSE; +} + +static void +rebuild_domain_lists (NMDnsManager *self) +{ + NMDnsIPConfigData *ip_data; + gs_unref_hashtable GHashTable *ht = NULL; + gboolean default_route_found = FALSE; + CList *head; + + ht = g_hash_table_new (nm_str_hash, g_str_equal); + + head = _ip_config_lst_head (self); + c_list_for_each_entry (ip_data, head, ip_config_lst) { + NMIPConfig *ip_config = ip_data->ip_config; + + if (!nm_ip_config_get_num_nameservers (ip_config)) + continue; + if (nm_ip_config_best_default_route_get (ip_config)) { + default_route_found = TRUE; + break; + } + } + + c_list_for_each_entry (ip_data, head, ip_config_lst) { + NMIPConfig *ip_config = ip_data->ip_config; + int priority, old_priority; + guint i, n, n_domains = 0; + const char **domains; + + if (!nm_ip_config_get_num_nameservers (ip_config)) + continue; + + priority = nm_ip_config_get_dns_priority (ip_config); + nm_assert (priority != 0); + g_free (ip_data->domains.search); + domains = g_new0 (const char *, + 2 + NM_MAX (nm_ip_config_get_num_searches (ip_config), + nm_ip_config_get_num_domains (ip_config))); + ip_data->domains.search = domains; + + /* Add wildcard lookup domain to connections with the default route. + * If there is no default route, add the wildcard domain to all non-VPN + * connections */ + if (default_route_found) { + if (nm_ip_config_best_default_route_get (ip_config)) + domains[n_domains++] = "~"; + } else { + if (ip_data->ip_config_type != NM_DNS_IP_CONFIG_TYPE_VPN) + domains[n_domains++] = "~"; + } + + /* searches are preferred over domains */ + n = nm_ip_config_get_num_searches (ip_config); + for (i = 0; i < n; i++) + domains[n_domains++] = nm_ip_config_get_search (ip_config, i); + + if (n == 0) { + /* If not searches, use any domains */ + n = nm_ip_config_get_num_domains (ip_config); + for (i = 0; i < n; i++) + domains[n_domains++] = nm_ip_config_get_domain (ip_config, i); + } + + n = 0; + for (i = 0; i < n_domains; i++) { + const char *domain_clean; + const char *parent; + int parent_priority; + + domain_clean = nm_utils_parse_dns_domain (domains[i], NULL); + + /* Remove domains with lower priority */ + old_priority = GPOINTER_TO_INT (g_hash_table_lookup (ht, domain_clean)); + if (old_priority) { + if (old_priority < priority) { + _LOGT ("plugin: drop domain '%s' (i=%d, p=%d) because it already exists with p=%d", + domains[i], ip_data->data->ifindex, + priority, old_priority); + continue; + } + } else if (domain_is_shadowed (ht, domain_clean, priority, &parent, &parent_priority)) { + _LOGT ("plugin: drop domain '%s' (i=%d, p=%d) shadowed by '%s' (p=%d)", + domains[i], + ip_data->data->ifindex, priority, + parent, parent_priority); + continue; + } + + _LOGT ("plugin: add domain '%s' (i=%d, p=%d)", domains[i], ip_data->data->ifindex, priority); + g_hash_table_insert (ht, (gpointer) domain_clean, GINT_TO_POINTER (priority)); + domains[n++] = domains[i]; + } + domains[n] = NULL; + + g_strfreev (ip_data->domains.reverse); + ip_data->domains.reverse = get_ip_rdns_domains (ip_config); + } +} + +static void +clear_domain_lists (NMDnsManager *self) +{ + NMDnsIPConfigData *ip_data; + CList *head; + + head = _ip_config_lst_head (self); + c_list_for_each_entry (ip_data, head, ip_config_lst) { + g_clear_pointer (&ip_data->domains.search, g_free); + g_clear_pointer (&ip_data->domains.reverse, g_strfreev); + } +} + static gboolean update_dns (NMDnsManager *self, gboolean no_caching, @@ -1192,6 +1386,7 @@ update_dns (NMDnsManager *self, } _LOGD ("update-dns: updating plugin %s", plugin_name); + rebuild_domain_lists (self); if (!nm_dns_plugin_update (plugin, global_config, _ip_config_lst_head (self), @@ -1203,6 +1398,10 @@ update_dns (NMDnsManager *self, */ caching = FALSE; } + /* Clear the generated search list as it points to + * strings owned by IP configurations and we can't + * guarantee they stay alive. */ + clear_domain_lists (self); skip: ; diff --git a/src/dns/nm-dns-manager.h b/src/dns/nm-dns-manager.h index 663a3ad258..75a29b9a2d 100644 --- a/src/dns/nm-dns-manager.h +++ b/src/dns/nm-dns-manager.h @@ -50,6 +50,10 @@ typedef struct { CList data_lst; CList ip_config_lst; NMDnsIPConfigType ip_config_type; + struct { + const char **search; + char **reverse; + } domains; } NMDnsIPConfigData; typedef struct _NMDnsConfigData { diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h index 497ba3f0e2..88f22daffc 100644 --- a/src/nm-ip4-config.h +++ b/src/nm-ip4-config.h @@ -437,4 +437,10 @@ nm_ip_config_get_dns_option (const NMIPConfig *self, guint i) _NM_IP_CONFIG_DISPATCH (self, nm_ip4_config_get_dns_option, nm_ip6_config_get_dns_option, i); } +static inline const NMPObject * +nm_ip_config_best_default_route_get (const NMIPConfig *self) +{ + _NM_IP_CONFIG_DISPATCH (self, nm_ip4_config_best_default_route_get, nm_ip6_config_best_default_route_get); +} + #endif /* __NETWORKMANAGER_IP4_CONFIG_H__ */ From ad98a41399c02f1eefcaac6d2faf876227ad82bc Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Thu, 8 Feb 2018 11:18:06 +0100 Subject: [PATCH 28/33] dns: fix compilation error Fixes the following error when building with gcc 4.8.5 and address sanitizer: src/dns/nm-dns-dnsmasq.c: In function 'update': src/dns/nm-dns-dnsmasq.c:506:44: error: 'first_prio' may be used uninitialized in this function [-Werror=maybe-uninitialized] } else if (first_prio < 0 && first_prio != prio) ^ (cherry picked from commit 10ef61408e2a40f2b0cd6b5a801a2025cec1bdda) --- src/dns/nm-dns-dnsmasq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dns/nm-dns-dnsmasq.c b/src/dns/nm-dns-dnsmasq.c index c3065ea2db..3739a28eb2 100644 --- a/src/dns/nm-dns-dnsmasq.c +++ b/src/dns/nm-dns-dnsmasq.c @@ -490,7 +490,7 @@ update (NMDnsPlugin *plugin, NMDnsDnsmasq *self = NM_DNS_DNSMASQ (plugin); NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE (self); GVariantBuilder servers; - int prio, first_prio; + int prio, first_prio = 0; const NMDnsIPConfigData *ip_data; gboolean is_first = TRUE; From bd1021a0a09b3279c23c584b6273be1ac967c998 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Sat, 24 Mar 2018 09:43:16 +0100 Subject: [PATCH 29/33] dns: dnsmasq: honor dns-priority Honor dns-priority by using the preprocessed list of domains provided by the manager. (cherry picked from commit 6409e7719c0341baedfdb063366457e390894ed9) --- src/dns/nm-dns-dnsmasq.c | 162 ++++++--------------------------------- 1 file changed, 22 insertions(+), 140 deletions(-) diff --git a/src/dns/nm-dns-dnsmasq.c b/src/dns/nm-dns-dnsmasq.c index 3739a28eb2..745d3d6742 100644 --- a/src/dns/nm-dns-dnsmasq.c +++ b/src/dns/nm-dns-dnsmasq.c @@ -75,54 +75,6 @@ G_DEFINE_TYPE (NMDnsDnsmasq, nm_dns_dnsmasq, NM_TYPE_DNS_PLUGIN) /*****************************************************************************/ -/* FIXME: this is a duplicate of the function in nm-dns-manager.c */ -static char ** -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; - - nm_assert_addr_family (addr_family); - - domains = g_ptr_array_sized_new (5); - - if (addr_family == AF_INET) { - NMIP4Config *ip4 = (gpointer) ip_config; - const NMPlatformIP4Address *address; - const NMPlatformIP4Route *route; - - nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, ip4, &address) - nm_utils_get_reverse_dns_domains_ip4 (address->address, address->plen, domains); - - 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; - - 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); - } - } - - /* Terminating NULL so we can use g_strfreev() to free it */ - g_ptr_array_add (domains, NULL); - - /* Free the array and return NULL if the only element was the ending NULL */ - strv = (char **) g_ptr_array_free (domains, (domains->len == 1)); - - return _nm_utils_strv_cleanup (strv, FALSE, FALSE, TRUE); -} - static void add_dnsmasq_nameserver (NMDnsDnsmasq *self, GVariantBuilder *servers, @@ -207,91 +159,34 @@ add_global_config (NMDnsDnsmasq *self, GVariantBuilder *dnsmasq_servers, const N } static void -add_ip_config (NMDnsDnsmasq *self, - GVariantBuilder *servers, - int ifindex, - NMIPConfig *ip_config, - gboolean split) +add_ip_config (NMDnsDnsmasq *self, GVariantBuilder *servers, const NMDnsIPConfigData *ip_data) { - int addr_family; + NMIPConfig *ip_config = ip_data->ip_config; gconstpointer addr; - gboolean added = FALSE; - guint nnameservers, i_nameserver, n, i; + const char *iface, *domain; char ip_addr_to_string_buf[IP_ADDR_TO_STRING_BUFLEN]; - char **domains, **iter; - gboolean iface_resolved = FALSE; - const char *iface = NULL, *domain; + int addr_family; + guint i, j, num; + iface = nm_platform_link_get_name (NM_PLATFORM_GET, ip_data->data->ifindex); addr_family = nm_ip_config_get_addr_family (ip_config); - 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; - - if (!iface_resolved) { - iface = nm_platform_link_get_name (NM_PLATFORM_GET, ifindex); - iface_resolved = TRUE; + num = nm_ip_config_get_num_nameservers (ip_config); + for (i = 0; i < num; i++) { + addr = nm_ip_config_get_nameserver (ip_config, i); + ip_addr_to_string (addr_family, addr, iface, ip_addr_to_string_buf); + for (j = 0; ip_data->domains.search[j]; j++) { + domain = nm_utils_parse_dns_domain (ip_data->domains.search[j], NULL); + add_dnsmasq_nameserver (self, + servers, + ip_addr_to_string_buf, + domain[0] ? domain : NULL); } - if (iface) { - for (i_nameserver = 0; i_nameserver < nnameservers; i_nameserver++) { - addr = nm_ip_config_get_nameserver (ip_config, i_nameserver); - - 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++) { - domain = nm_utils_parse_dns_domain (nm_ip_config_get_search (ip_config, i), NULL); - add_dnsmasq_nameserver (self, - servers, - ip_addr_to_string_buf, - domain); - 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++) { - domain = nm_utils_parse_dns_domain (nm_ip_config_get_domain (ip_config, i), NULL); - add_dnsmasq_nameserver (self, - servers, - ip_addr_to_string_buf, - domain); - 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) { - 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); - } + for (j = 0; ip_data->domains.reverse[j]; j++) { + add_dnsmasq_nameserver (self, servers, + ip_addr_to_string_buf, + ip_data->domains.reverse[j]); } } } @@ -490,9 +385,7 @@ update (NMDnsPlugin *plugin, NMDnsDnsmasq *self = NM_DNS_DNSMASQ (plugin); NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE (self); GVariantBuilder servers; - int prio, first_prio = 0; const NMDnsIPConfigData *ip_data; - gboolean is_first = TRUE; start_dnsmasq (self); @@ -501,19 +394,8 @@ update (NMDnsPlugin *plugin, if (global_config) add_global_config (self, &servers, global_config); else { - 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) - break; - add_ip_config (self, - &servers, - ip_data->data->ifindex, - ip_data->ip_config, - ip_data->ip_config_type == NM_DNS_IP_CONFIG_TYPE_VPN); - } + c_list_for_each_entry (ip_data, ip_config_lst_head, ip_config_lst) + add_ip_config (self, &servers, ip_data); } g_clear_pointer (&priv->set_server_ex_args, g_variant_unref); From 4e9555699d8ec3263b19dc2c8c1bb1d8d945b65b Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Fri, 23 Mar 2018 18:50:17 +0100 Subject: [PATCH 30/33] dns: sd-resolved: honor dns-priority Honor dns-priority by using the preprocessed list of domains provided by the manager. (cherry picked from commit 5df69330b5f515d5d2c2699cdba88c265d5d29dd) --- src/dns/nm-dns-systemd-resolved.c | 54 +++++++++---------------------- 1 file changed, 16 insertions(+), 38 deletions(-) diff --git a/src/dns/nm-dns-systemd-resolved.c b/src/dns/nm-dns-systemd-resolved.c index 4692f978fe..1317662adf 100644 --- a/src/dns/nm-dns-systemd-resolved.c +++ b/src/dns/nm-dns-systemd-resolved.c @@ -141,47 +141,36 @@ static void update_add_ip_config (NMDnsSystemdResolved *self, GVariantBuilder *dns, GVariantBuilder *domains, - NMIPConfig *config) + NMDnsIPConfigData *data) { int addr_family; gsize addr_size; guint i, n; gboolean is_routing; + const char **iter; const char *domain; - addr_family = nm_ip_config_get_addr_family (config); + addr_family = nm_ip_config_get_addr_family (data->ip_config); addr_size = nm_utils_addr_family_to_size (addr_family); - n = nm_ip_config_get_num_nameservers (config); + if (!data->domains.search || !data->domains.search[0]) + return; + + n = nm_ip_config_get_num_nameservers (data->ip_config); for (i = 0 ; i < n; i++) { g_variant_builder_open (dns, G_VARIANT_TYPE ("(iay)")); g_variant_builder_add (dns, "i", addr_family); g_variant_builder_add_value (dns, g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, - nm_ip_config_get_nameserver (config, i), + nm_ip_config_get_nameserver (data->ip_config, i), addr_size, 1)); g_variant_builder_close (dns); } - n = nm_ip_config_get_num_searches (config); - if (n > 0) { - for (i = 0; i < n; i++) { - domain = nm_utils_parse_dns_domain (nm_ip_config_get_search (config, i), - &is_routing); - g_variant_builder_add (domains, "(sb)", - domain, - is_routing); - } - } else { - n = nm_ip_config_get_num_domains (config); - for (i = 0; i < n; i++) { - domain = nm_utils_parse_dns_domain (nm_ip_config_get_domain (config, i), - &is_routing); - g_variant_builder_add (domains, "(sb)", - domain, - is_routing); - } + for (iter = data->domains.search; *iter; iter++) { + domain = nm_utils_parse_dns_domain (*iter, &is_routing); + g_variant_builder_add (domains, "(sb)", domain[0] ? domain : ".", is_routing); } } @@ -216,9 +205,10 @@ prepare_one_interface (NMDnsSystemdResolved *self, InterfaceConfig *ic) g_variant_builder_open (&domains, G_VARIANT_TYPE ("a(sb)")); c_list_for_each_entry (elem, &ic->configs_lst_head, lst) { - NMIPConfig *ip_config = elem->data; + NMDnsIPConfigData *data = elem->data; + NMIPConfig *ip_config = data->ip_config; - update_add_ip_config (self, &dns, &domains, ip_config); + update_add_ip_config (self, &dns, &domains, data); if (NM_IS_IP4_CONFIG (ip_config)) mdns = NM_MAX (mdns, nm_ip4_config_mdns_get (NM_IP4_CONFIG (ip_config))); @@ -294,25 +284,15 @@ update (NMDnsPlugin *plugin, gs_free gpointer *interfaces_keys = NULL; 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); 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 (ip_data->ip_config); - if (is_first) { - is_first = FALSE; - first_prio = prio; - } else if (first_prio < 0 && first_prio != prio) - skip = TRUE; - ifindex = ip_data->data->ifindex; nm_assert (ifindex == nm_ip_config_get_ifindex (ip_data->ip_config)); @@ -324,10 +304,8 @@ update (NMDnsPlugin *plugin, 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 (ip_data->ip_config)->lst); - } + c_list_link_tail (&ic->configs_lst_head, + &nm_c_list_elem_new_stale (ip_data)->lst); } free_pending_updates (self); From 107c7f27af1a754cb94f65857d2e85f09cc50743 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Fri, 23 Mar 2018 18:50:36 +0100 Subject: [PATCH 31/33] libnm-core: document dns priority (cherry picked from commit 1fbadecdbc00f3a61afe98790e5a21e6cb9b7933) --- clients/common/settings-docs.c.in | 4 +-- libnm-core/nm-setting-ip-config.c | 42 +++++++++++++++++++------------ 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/clients/common/settings-docs.c.in b/clients/common/settings-docs.c.in index da1f24fa64..0abe983dde 100644 --- a/clients/common/settings-docs.c.in +++ b/clients/common/settings-docs.c.in @@ -216,7 +216,7 @@ #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_TIMEOUT N_("A timeout for a DHCP transaction in seconds.") #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS N_("Array of IP addresses of DNS servers.") #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_OPTIONS N_("Array of DNS options as described in man 5 resolv.conf. NULL means that the options are unset and left at the default. In this case NetworkManager will use default options. This is distinct from an empty list of properties.") -#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_PRIORITY N_("Intra-connection DNS priority. The relative priority to be used when determining the order of DNS servers in resolv.conf. A lower value means that servers will be on top of the file. Zero selects the default value, which is 50 for VPNs and 100 for other connections. Note that the priority is to order DNS settings for multiple active connections. It does not disambiguate multiple DNS servers within the same connection profile. For that, just specify the DNS servers in the desired order. When multiple devices have configurations with the same priority, the one with an active default route will be preferred. Note that when using dns=dnsmasq the order is meaningless since dnsmasq forwards queries to all known servers at the same time. Negative values have the special effect of excluding other configurations with a greater priority value; so in presence of at least a negative priority, only DNS servers from connections with the lowest priority value will be used.") +#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_PRIORITY N_("DNS servers priority. The relative priority for DNS servers specified by this setting. A lower value is better (higher priority). Zero selects the default value, which is 50 for VPNs and 100 for other connections. Note that the priority is to order DNS settings for multiple active connections. It does not disambiguate multiple DNS servers within the same connection profile. When using dns=default, servers with higher priority will be on top of resolv.conf. To prioritize a given server over another one within the same connection, just specify them in the desired order. When multiple devices have configurations with the same priority, the one with an active default route will be preferred. Negative values have the special effect of excluding other configurations with a greater priority value; so in presence of at least a negative priority, only DNS servers from connections with the lowest priority value will be used. When using a DNS resolver that supports split-DNS as dns=dnsmasq or dns=systemd-resolved, each connection is used to query domains in its search list. Queries for domains not present in any search list are routed through connections having the '~.' special wildcard domain, which is added automatically to connections with the default route (or can be added manually). When multiple connections specify the same domain, the one with the highest priority (lowest numerical value) wins. If a connection specifies a domain which is subdomain of another domain with a negative DNS priority value, the subdomain is ignored.") #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_SEARCH N_("Array of DNS search domains. Domains starting with a tilde ('~') are considered 'routing' domains and are used only to decide the interface over which a query must be forwarded; they are not used to complete unqualified host names.") #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_GATEWAY N_("The gateway associated with this configuration. This is only meaningful if \"addresses\" is also set.") #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_IGNORE_AUTO_DNS N_("When \"method\" is set to \"auto\" and this property to TRUE, automatically configured nameservers and search domains are ignored and only nameservers and search domains specified in the \"dns\" and \"dns-search\" properties, if any, are used.") @@ -236,7 +236,7 @@ #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DHCP_TIMEOUT N_("A timeout for a DHCP transaction in seconds.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS N_("Array of IP addresses of DNS servers.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_OPTIONS N_("Array of DNS options as described in man 5 resolv.conf. NULL means that the options are unset and left at the default. In this case NetworkManager will use default options. This is distinct from an empty list of properties.") -#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_PRIORITY N_("Intra-connection DNS priority. The relative priority to be used when determining the order of DNS servers in resolv.conf. A lower value means that servers will be on top of the file. Zero selects the default value, which is 50 for VPNs and 100 for other connections. Note that the priority is to order DNS settings for multiple active connections. It does not disambiguate multiple DNS servers within the same connection profile. For that, just specify the DNS servers in the desired order. When multiple devices have configurations with the same priority, the one with an active default route will be preferred. Note that when using dns=dnsmasq the order is meaningless since dnsmasq forwards queries to all known servers at the same time. Negative values have the special effect of excluding other configurations with a greater priority value; so in presence of at least a negative priority, only DNS servers from connections with the lowest priority value will be used.") +#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_PRIORITY N_("DNS servers priority. The relative priority for DNS servers specified by this setting. A lower value is better (higher priority). Zero selects the default value, which is 50 for VPNs and 100 for other connections. Note that the priority is to order DNS settings for multiple active connections. It does not disambiguate multiple DNS servers within the same connection profile. When using dns=default, servers with higher priority will be on top of resolv.conf. To prioritize a given server over another one within the same connection, just specify them in the desired order. When multiple devices have configurations with the same priority, the one with an active default route will be preferred. Negative values have the special effect of excluding other configurations with a greater priority value; so in presence of at least a negative priority, only DNS servers from connections with the lowest priority value will be used. When using a DNS resolver that supports split-DNS as dns=dnsmasq or dns=systemd-resolved, each connection is used to query domains in its search list. Queries for domains not present in any search list are routed through connections having the '~.' special wildcard domain, which is added automatically to connections with the default route (or can be added manually). When multiple connections specify the same domain, the one with the highest priority (lowest numerical value) wins. If a connection specifies a domain which is subdomain of another domain with a negative DNS priority value, the subdomain is ignored.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_SEARCH N_("Array of DNS search domains. Domains starting with a tilde ('~') are considered 'routing' domains and are used only to decide the interface over which a query must be forwarded; they are not used to complete unqualified host names.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_GATEWAY N_("The gateway associated with this configuration. This is only meaningful if \"addresses\" is also set.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_IGNORE_AUTO_DNS N_("When \"method\" is set to \"auto\" and this property to TRUE, automatically configured nameservers and search domains are ignored and only nameservers and search domains specified in the \"dns\" and \"dns-search\" properties, if any, are used.") diff --git a/libnm-core/nm-setting-ip-config.c b/libnm-core/nm-setting-ip-config.c index 18d93f9deb..31da2dbe64 100644 --- a/libnm-core/nm-setting-ip-config.c +++ b/libnm-core/nm-setting-ip-config.c @@ -2993,24 +2993,34 @@ nm_setting_ip_config_class_init (NMSettingIPConfigClass *setting_class) /** * NMSettingIPConfig:dns-priority: * - * Intra-connection DNS priority. + * DNS servers priority. * - * The relative priority to be used when determining the order of DNS - * servers in resolv.conf. A lower value means that servers will be on top - * of the file. Zero selects the default value, which is 50 for VPNs and - * 100 for other connections. Note that the priority is to order DNS - * settings for multiple active connections. It does not disambiguate - * multiple DNS servers within the same connection profile. For that, - * just specify the DNS servers in the desired order. - * When multiple devices have configurations with the same priority, the - * one with an active default route will be preferred. - * Note that when using dns=dnsmasq the order is meaningless - * since dnsmasq forwards queries to all known servers at the same time. + * The relative priority for DNS servers specified by this setting. A lower + * value is better (higher priority). Zero selects the default value, which + * is 50 for VPNs and 100 for other connections. * - * Negative values have the special effect of excluding other configurations - * with a greater priority value; so in presence of at least a negative - * priority, only DNS servers from connections with the lowest priority - * value will be used. + * Note that the priority is to order DNS settings for multiple active + * connections. It does not disambiguate multiple DNS servers within the + * same connection profile. + * + * When using dns=default, servers with higher priority will be on top of + * resolv.conf. To prioritize a given server over another one within the + * same connection, just specify them in the desired order. When multiple + * devices have configurations with the same priority, the one with an + * active default route will be preferred. Negative values have the special + * effect of excluding other configurations with a greater priority value; + * so in presence of at least a negative priority, only DNS servers from + * connections with the lowest priority value will be used. + * + * When using a DNS resolver that supports split-DNS as dns=dnsmasq or + * dns=systemd-resolved, each connection is used to query domains in its + * search list. Queries for domains not present in any search list are + * routed through connections having the '~.' special wildcard domain, which + * is added automatically to connections with the default route (or can be + * added manually). When multiple connections specify the same domain, the + * one with the highest priority (lowest numerical value) wins. If a + * connection specifies a domain which is subdomain of another domain with a + * negative DNS priority value, the subdomain is ignored. * * Since: 1.4 **/ From be483778e784649530f16f3ac5053a4333022bae Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Thu, 13 Sep 2018 14:50:32 +0200 Subject: [PATCH 32/33] dns: dnsmasq: avoid crash when no reverse domains exist ip_data->domains.reverse can be NULL when the device is being removed and has no IP configuration for a short moment. Fixes: 6409e7719c0341baedfdb063366457e390894ed9 https://bugzilla.gnome.org/show_bug.cgi?id=797022 (cherry picked from commit f0c075f05082e4c77fac75ad06d303e7538e4fc7) (cherry picked from commit 8309a7a6964d3677e0705046fb2f91810ef3ab65) --- src/dns/nm-dns-dnsmasq.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/dns/nm-dns-dnsmasq.c b/src/dns/nm-dns-dnsmasq.c index 745d3d6742..2163ec016a 100644 --- a/src/dns/nm-dns-dnsmasq.c +++ b/src/dns/nm-dns-dnsmasq.c @@ -183,10 +183,12 @@ add_ip_config (NMDnsDnsmasq *self, GVariantBuilder *servers, const NMDnsIPConfig domain[0] ? domain : NULL); } - for (j = 0; ip_data->domains.reverse[j]; j++) { - add_dnsmasq_nameserver (self, servers, - ip_addr_to_string_buf, - ip_data->domains.reverse[j]); + if (ip_data->domains.reverse) { + for (j = 0; ip_data->domains.reverse[j]; j++) { + add_dnsmasq_nameserver (self, servers, + ip_addr_to_string_buf, + ip_data->domains.reverse[j]); + } } } } From 58bb588fbe0fbad5f9c31e306fcc695f64ac8a46 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Sat, 21 Apr 2018 18:40:57 +0200 Subject: [PATCH 33/33] libnm-core: fix validation of connection.mdns setting Commit 9d92848ada43 ("libnm: rename MDns flag UNKNOWN to DEFAULT") changed the enum order without updating verify(). Fixes: 9d92848ada434c9ffb8f55db2986514079f58fa3 (cherry picked from commit 0498c5487fe29ffddc93955faa159a8c99790c90) --- libnm-core/nm-setting-connection.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libnm-core/nm-setting-connection.c b/libnm-core/nm-setting-connection.c index e26d547aeb..45120449db 100644 --- a/libnm-core/nm-setting-connection.c +++ b/libnm-core/nm-setting-connection.c @@ -1077,7 +1077,7 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) } if ( priv->mdns < NM_SETTING_CONNECTION_MDNS_DEFAULT - || priv->mdns > NM_SETTING_CONNECTION_MDNS_RESOLVE) { + || priv->mdns > NM_SETTING_CONNECTION_MDNS_YES) { g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY,