From 964ae8cc391520440cf5aa13e2b9cc34850ea6c2 Mon Sep 17 00:00:00 2001 From: Michael Biebl Date: Tue, 26 Feb 2019 19:01:41 +0100 Subject: New upstream version 1.14.6 --- src/dns/nm-dns-dnsmasq.c | 13 +++- src/dns/nm-dns-manager.c | 163 +++++++++++++++++++++++++++++------------------ src/dns/nm-dns-manager.h | 6 ++ 3 files changed, 117 insertions(+), 65 deletions(-) (limited to 'src/dns') diff --git a/src/dns/nm-dns-dnsmasq.c b/src/dns/nm-dns-dnsmasq.c index b48c6b87..b54df730 100644 --- a/src/dns/nm-dns-dnsmasq.c +++ b/src/dns/nm-dns-dnsmasq.c @@ -254,9 +254,16 @@ name_owner_changed (GObject *object, priv->running = TRUE; send_dnsmasq_update (self); } else { - _LOGI ("dnsmasq disappeared"); - priv->running = FALSE; - g_signal_emit_by_name (self, NM_DNS_PLUGIN_FAILED); + if (priv->running) { + _LOGI ("dnsmasq disappeared"); + priv->running = FALSE; + g_signal_emit_by_name (self, NM_DNS_PLUGIN_FAILED); + } else { + /* The only reason for which (!priv->running) here + * is that the dnsmasq process quit. We don't care + * of that here, the manager handles child restarts + * by itself. */ + } } } diff --git a/src/dns/nm-dns-manager.c b/src/dns/nm-dns-manager.c index 6a59b41c..aebe3e12 100644 --- a/src/dns/nm-dns-manager.c +++ b/src/dns/nm-dns-manager.c @@ -55,7 +55,7 @@ #include "nm-dns-systemd-resolved.h" #include "nm-dns-unbound.h" -#define HASH_LEN 20 +#define HASH_LEN NM_UTILS_CHECKSUM_LENGTH_SHA1 #ifndef RESOLVCONF_PATH #define RESOLVCONF_PATH "/sbin/resolvconf" @@ -582,53 +582,85 @@ again: } static char * -create_resolv_conf (char **searches, - char **nameservers, - char **options) +create_resolv_conf (const char *const*searches, + const char *const*nameservers, + const char *const*options) { - gs_free char *searches_str = NULL; - gs_free char *nameservers_str = NULL; - gs_free char *options_str = NULL; - char *tmp_str; GString *str; - int i; + gsize i; - if (searches) { - tmp_str = g_strjoinv (" ", searches); - searches_str = g_strconcat ("search ", tmp_str, "\n", NULL); - g_free (tmp_str); - } + str = g_string_new_len (NULL, 245); - if (options) { - tmp_str = g_strjoinv (" ", options); - options_str = g_strconcat ("options ", tmp_str, "\n", NULL); - g_free (tmp_str); - } + g_string_append (str, "# Generated by NetworkManager\n"); - if (nameservers) { - int num = g_strv_length (nameservers); + if (searches && searches[0]) { + gsize search_base_idx; - str = g_string_new (""); - for (i = 0; i < num; i++) { - if (i == 3) { - g_string_append (str, "# "); - g_string_append (str, "NOTE: the libc resolver may not support more than 3 nameservers."); - g_string_append (str, "\n# "); - g_string_append (str, "The nameservers listed below may not be recognized."); - g_string_append_c (str, '\n'); + g_string_append (str, "search"); + search_base_idx = str->len; + + for (i = 0; searches[i]; i++) { + const char *s = searches[i]; + gsize l = strlen (s); + + if ( l == 0 + || NM_STRCHAR_ANY (s, ch, NM_IN_SET (ch, ' ', '\t', '\n'))) { + /* there should be no such characters in the search entry. Also, + * because glibc parser would treat them as line/word separator. + * + * Skip the value silently. */ + continue; } + if (search_base_idx > 0) { + if (str->len - search_base_idx + 1 + l > 254) { + /* this entry crosses the 256 character boundery. Older glibc versions + * would truncate the entry at this point. + * + * Fill the line with spaces to cross the 256 char boundary and continue + * afterwards. This way, the truncation happens between two search entries. */ + while (str->len - search_base_idx < 257) + g_string_append_c (str, ' '); + search_base_idx = 0; + } + } + + g_string_append_c (str, ' '); + g_string_append_len (str, s, l); + } + g_string_append_c (str, '\n'); + } + + if (nameservers && nameservers[0]) { + for (i = 0; nameservers[i]; i++) { + if (i == 3) { + g_string_append (str, "# NOTE: the libc resolver may not support more than 3 nameservers.\n"); + g_string_append (str, "# The nameservers listed below may not be recognized.\n"); + } g_string_append (str, "nameserver "); g_string_append (str, nameservers[i]); g_string_append_c (str, '\n'); } - nameservers_str = g_string_free (str, FALSE); } - return g_strdup_printf ("# Generated by NetworkManager\n%s%s%s", - searches_str ?: "", - nameservers_str ?: "", - options_str ?: ""); + if (options && options[0]) { + g_string_append (str, "options"); + for (i = 0; options[i]; i++) { + g_string_append_c (str, ' '); + g_string_append (str, options[i]); + } + g_string_append_c (str, '\n'); + } + + return g_string_free (str, FALSE); +} + +char * +nmtst_dns_create_resolv_conf (const char *const*searches, + const char *const*nameservers, + const char *const*options) +{ + return create_resolv_conf (searches, nameservers, options); } static gboolean @@ -654,9 +686,9 @@ write_resolv_conf_contents (FILE *f, static gboolean write_resolv_conf (FILE *f, - char **searches, - char **nameservers, - char **options, + const char *const*searches, + const char *const*nameservers, + const char *const*options, GError **error) { gs_free char *content = NULL; @@ -718,7 +750,11 @@ dispatch_resolvconf (NMDnsManager *self, return SR_ERROR; } - success = write_resolv_conf (f, searches, nameservers, options, error); + success = write_resolv_conf (f, + NM_CAST_STRV_CC (searches), + NM_CAST_STRV_CC (nameservers), + NM_CAST_STRV_CC (options), + error); err = pclose (f); if (err < 0) { errnosv = errno; @@ -757,9 +793,9 @@ _read_link_cached (const char *path, gboolean *is_cached, char **cached) static SpawnResult update_resolv_conf (NMDnsManager *self, - char **searches, - char **nameservers, - char **options, + const char *const*searches, + const char *const*nameservers, + const char *const*options, GError **error, NMDnsManagerResolvConfManager rc_manager) { @@ -958,12 +994,11 @@ update_resolv_conf (NMDnsManager *self, static void compute_hash (NMDnsManager *self, const NMGlobalDnsConfig *global, guint8 buffer[HASH_LEN]) { - GChecksum *sum; - gsize len = HASH_LEN; + nm_auto_free_checksum GChecksum *sum = NULL; NMDnsIPConfigData *ip_data; sum = g_checksum_new (G_CHECKSUM_SHA1); - nm_assert (len == g_checksum_type_get_length (G_CHECKSUM_SHA1)); + nm_assert (HASH_LEN == g_checksum_type_get_length (G_CHECKSUM_SHA1)); if (global) nm_global_dns_config_update_checksum (global, sum); @@ -977,8 +1012,7 @@ compute_hash (NMDnsManager *self, const NMGlobalDnsConfig *global, guint8 buffer nm_ip_config_hash (ip_data->ip_config, sum, TRUE); } - g_checksum_get_digest (sum, buffer, &len); - g_checksum_free (sum); + nm_utils_checksum_get_digest_len (sum, buffer, HASH_LEN); } static gboolean @@ -1066,7 +1100,6 @@ _collect_resolv_conf_data (NMDnsManager *self, const char **out_nis_domain) { NMDnsManagerPrivate *priv; - guint i, num, len; NMResolvConfData rc = { .nameservers = g_ptr_array_new (), .searches = g_ptr_array_new (), @@ -1136,17 +1169,6 @@ _collect_resolv_conf_data (NMDnsManager *self, } } - /* Per 'man resolv.conf', the search list is limited to 6 domains - * totalling 256 characters. - */ - num = MIN (rc.searches->len, 6u); - for (i = 0, len = 0; i < num; i++) { - len += strlen (rc.searches->pdata[i]) + 1; /* +1 for spaces */ - if (len > 256) - break; - } - g_ptr_array_set_size (rc.searches, i); - *out_searches = _ptrarray_to_strv (rc.searches); *out_options = _ptrarray_to_strv (rc.options); *out_nameservers = _ptrarray_to_strv (rc.nameservers); @@ -1449,7 +1471,12 @@ update_dns (NMDnsManager *self, switch (priv->rc_manager) { case NM_DNS_MANAGER_RESOLV_CONF_MAN_SYMLINK: case NM_DNS_MANAGER_RESOLV_CONF_MAN_FILE: - result = update_resolv_conf (self, searches, nameservers, options, error, priv->rc_manager); + result = update_resolv_conf (self, + NM_CAST_STRV_CC (searches), + NM_CAST_STRV_CC (nameservers), + NM_CAST_STRV_CC (options), + error, + priv->rc_manager); resolv_conf_updated = TRUE; /* If we have ended with no nameservers avoid updating again resolv.conf * on stop, as some external changes may be applied to it in the meanwhile */ @@ -1474,15 +1501,26 @@ update_dns (NMDnsManager *self, if (result == SR_NOTFOUND) { _LOGD ("update-dns: program not available, writing to resolv.conf"); g_clear_error (error); - result = update_resolv_conf (self, searches, nameservers, options, error, NM_DNS_MANAGER_RESOLV_CONF_MAN_SYMLINK); + result = update_resolv_conf (self, + NM_CAST_STRV_CC (searches), + NM_CAST_STRV_CC (nameservers), + NM_CAST_STRV_CC (options), + error, + NM_DNS_MANAGER_RESOLV_CONF_MAN_SYMLINK); resolv_conf_updated = TRUE; } } /* Unless we've already done it, update private resolv.conf in NMRUNDIR ignoring any errors */ - if (!resolv_conf_updated) - update_resolv_conf (self, searches, nameservers, options, NULL, NM_DNS_MANAGER_RESOLV_CONF_MAN_UNMANAGED); + if (!resolv_conf_updated) { + update_resolv_conf (self, + NM_CAST_STRV_CC (searches), + NM_CAST_STRV_CC (nameservers), + NM_CAST_STRV_CC (options), + NULL, + NM_DNS_MANAGER_RESOLV_CONF_MAN_UNMANAGED); + } /* signal that resolv.conf was changed */ if (update && result == SR_SUCCESS) @@ -1542,6 +1580,7 @@ plugin_child_quit (NMDnsPlugin *plugin, int exit_status, gpointer user_data) } else { priv->plugin_ratelimit.num_restarts++; if (priv->plugin_ratelimit.num_restarts > PLUGIN_RATELIMIT_BURST) { + plugin_failed (plugin, self); _LOGW ("plugin %s child respawning too fast, delaying update for %u seconds", nm_dns_plugin_get_name (plugin), PLUGIN_RATELIMIT_DELAY); priv->plugin_ratelimit.timer = g_timeout_add_seconds (PLUGIN_RATELIMIT_DELAY, diff --git a/src/dns/nm-dns-manager.h b/src/dns/nm-dns-manager.h index ed1974a5..a3e9472e 100644 --- a/src/dns/nm-dns-manager.h +++ b/src/dns/nm-dns-manager.h @@ -129,4 +129,10 @@ typedef enum { void nm_dns_manager_stop (NMDnsManager *self); +/*****************************************************************************/ + +char *nmtst_dns_create_resolv_conf (const char *const*searches, + const char *const*nameservers, + const char *const*options); + #endif /* __NETWORKMANAGER_DNS_MANAGER_H__ */ -- cgit 1.3.0-6-gf8a5 From 9a6dcbf895f9da01768e64b73cec88c16157d91e Mon Sep 17 00:00:00 2001 From: Michael Biebl Date: Tue, 26 Mar 2019 23:25:23 +0100 Subject: New upstream version 1.16.0 --- src/dns/nm-dns-manager.c | 198 +++++++++++++++++++++++++++++------------------ src/dns/nm-dns-manager.h | 2 + src/dns/nm-dns-plugin.c | 1 - 3 files changed, 125 insertions(+), 76 deletions(-) (limited to 'src/dns') diff --git a/src/dns/nm-dns-manager.c b/src/dns/nm-dns-manager.c index aebe3e12..c7c561c4 100644 --- a/src/dns/nm-dns-manager.c +++ b/src/dns/nm-dns-manager.c @@ -23,7 +23,6 @@ #include "nm-default.h" -#include #include #include #include @@ -122,6 +121,7 @@ typedef struct { NMDnsManagerResolvConfManager rc_manager; char *mode; + NMDnsPlugin *sd_resolve_plugin; NMDnsPlugin *plugin; NMConfig *config; @@ -311,37 +311,23 @@ _config_data_free (NMDnsConfigData *data) } static int -_ip_config_data_cmp (const NMDnsIPConfigData *a, const NMDnsIPConfigData *b) +_ip_config_lst_cmp (const CList *a_lst, + const CList *b_lst, + const void *user_data) { - int a_prio, b_prio; - - a_prio = nm_ip_config_get_dns_priority (a->ip_config); - b_prio = nm_ip_config_get_dns_priority (b->ip_config); + const NMDnsIPConfigData *a = c_list_entry (a_lst, NMDnsIPConfigData, ip_config_lst); + const NMDnsIPConfigData *b = c_list_entry (b_lst, NMDnsIPConfigData, ip_config_lst); /* Configurations with lower priority value first */ - if (a_prio < b_prio) - return -1; - else if (a_prio > b_prio) - return 1; + NM_CMP_DIRECT (nm_ip_config_get_dns_priority (a->ip_config), + nm_ip_config_get_dns_priority (b->ip_config)); - /* Sort also according to type */ - if (a->ip_config_type > b->ip_config_type) - return -1; - else if (a->ip_config_type < b->ip_config_type) - return 1; + /* Sort according to type (descendingly) */ + NM_CMP_FIELD (b, a, ip_config_type); return 0; } -static int -_ip_config_lst_cmp (const CList *a, - const CList *b, - const void *user_data) -{ - 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) { @@ -357,6 +343,21 @@ _ip_config_lst_head (NMDnsManager *self) /*****************************************************************************/ +gboolean +nm_dns_manager_has_systemd_resolved (NMDnsManager *self) +{ + NMDnsManagerPrivate *priv; + + g_return_val_if_fail (NM_IS_DNS_MANAGER (self), FALSE); + + priv = NM_DNS_MANAGER_GET_PRIVATE (self); + + return priv->sd_resolve_plugin + || NM_IS_DNS_SYSTEMD_RESOLVED (priv->plugin); +} + +/*****************************************************************************/ + static void add_string_item (GPtrArray *array, const char *str, gboolean dup) { @@ -534,6 +535,7 @@ dispatch_netconfig (NMDnsManager *self, { GPid pid; int fd; + int errsv; int status; gssize l; nm_auto_free_gstring GString *str = NULL; @@ -564,11 +566,10 @@ again: /* Wait until the process exits */ if (!nm_utils_kill_child_sync (pid, 0, LOGD_DNS, "netconfig", &status, 1000, 0)) { - int errsv = errno; - + errsv = errno; g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, "Error waiting for netconfig to exit: %s", - strerror (errsv)); + nm_strerror_native (errsv)); return SR_ERROR; } if (!WIFEXITED (status) || WEXITSTATUS (status) != EXIT_SUCCESS) { @@ -676,7 +677,7 @@ write_resolv_conf_contents (FILE *f, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, "Could not write " _PATH_RESCONF ": %s", - g_strerror (errsv)); + nm_strerror_native (errsv)); errno = errsv; return FALSE; } @@ -707,7 +708,8 @@ dispatch_resolvconf (NMDnsManager *self, gs_free char *cmd = NULL; FILE *f; gboolean success = FALSE; - int errnosv, err; + int errsv; + int err; char *argv[] = { RESOLVCONF_PATH, "-d", "NetworkManager", NULL }; int status; @@ -741,12 +743,13 @@ dispatch_resolvconf (NMDnsManager *self, cmd = g_strconcat (RESOLVCONF_PATH, " -a ", "NetworkManager", NULL); if ((f = popen (cmd, "w")) == NULL) { + errsv = errno; g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, "Could not write to %s: %s", RESOLVCONF_PATH, - g_strerror (errno)); + nm_strerror_native (errsv)); return SR_ERROR; } @@ -757,10 +760,10 @@ dispatch_resolvconf (NMDnsManager *self, error); err = pclose (f); if (err < 0) { - errnosv = errno; + errsv = errno; g_clear_error (error); - g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errnosv), - "Failed to close pipe to resolvconf: %d", errnosv); + g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv), + "Failed to close pipe to resolvconf: %d", errsv); return SR_ERROR; } else if (err > 0) { _LOGW ("resolvconf failed with status %d", err); @@ -787,9 +790,36 @@ _read_link_cached (const char *path, gboolean *is_cached, char **cached) return (*cached = g_file_read_link (path, NULL)); } -#define MY_RESOLV_CONF NMRUNDIR "/resolv.conf" -#define MY_RESOLV_CONF_TMP MY_RESOLV_CONF ".tmp" -#define RESOLV_CONF_TMP "/etc/.resolv.conf.NetworkManager" +#define MY_RESOLV_CONF NMRUNDIR"/resolv.conf" +#define MY_RESOLV_CONF_TMP MY_RESOLV_CONF".tmp" +#define RESOLV_CONF_TMP "/etc/.resolv.conf.NetworkManager" + +#define NO_STUB_RESOLV_CONF NMRUNDIR "/no-stub-resolv.conf" + +static void +update_resolv_conf_no_stub (NMDnsManager *self, + const char *const*searches, + const char *const*nameservers, + const char *const*options) +{ + gs_free char *content = NULL; + GError *local = NULL; + + content = create_resolv_conf (searches, nameservers, options); + + if (!g_file_set_contents (NO_STUB_RESOLV_CONF, + content, + -1, + &local)) { + _LOGD ("update-resolv-no-stub: failure to write file: %s", + local->message); + g_error_free (local); + return; + } + + _LOGT ("update-resolv-no-stub: '%s' successfully written", + NO_STUB_RESOLV_CONF); +} static SpawnResult update_resolv_conf (NMDnsManager *self, @@ -807,22 +837,6 @@ update_resolv_conf (NMDnsManager *self, gboolean resconf_link_cached = FALSE; gs_free char *resconf_link = NULL; - /* If we are not managing /etc/resolv.conf and it points to - * MY_RESOLV_CONF, don't write the private DNS configuration to - * MY_RESOLV_CONF otherwise we would overwrite the changes done by - * some external application. - * - * This is the only situation, where we don't try to update our - * internal resolv.conf file. */ - if (rc_manager == NM_DNS_MANAGER_RESOLV_CONF_MAN_UNMANAGED) { - if (nm_streq0 (_read_link_cached (_PATH_RESCONF, &resconf_link_cached, &resconf_link), - MY_RESOLV_CONF)) { - _LOGD ("update-resolv-conf: not updating " _PATH_RESCONF - " since it points to " MY_RESOLV_CONF); - return SR_SUCCESS; - } - } - content = create_resolv_conf (searches, nameservers, options); if ( rc_manager == NM_DNS_MANAGER_RESOLV_CONF_MAN_FILE @@ -873,9 +887,9 @@ update_resolv_conf (NMDnsManager *self, NM_MANAGER_ERROR_FAILED, "Could not open %s: %s", MY_RESOLV_CONF_TMP, - g_strerror (errsv)); + nm_strerror_native (errsv)); _LOGT ("update-resolv-conf: open temporary file %s failed (%s)", - MY_RESOLV_CONF_TMP, g_strerror (errsv)); + MY_RESOLV_CONF_TMP, nm_strerror_native (errsv)); return SR_ERROR; } @@ -883,7 +897,7 @@ update_resolv_conf (NMDnsManager *self, if (!success) { errsv = errno; _LOGT ("update-resolv-conf: write temporary file %s failed (%s)", - MY_RESOLV_CONF_TMP, g_strerror (errsv)); + MY_RESOLV_CONF_TMP, nm_strerror_native (errsv)); } if (fclose (f) < 0) { @@ -897,9 +911,9 @@ update_resolv_conf (NMDnsManager *self, NM_MANAGER_ERROR_FAILED, "Could not close %s: %s", MY_RESOLV_CONF_TMP, - g_strerror (errsv)); + nm_strerror_native (errsv)); _LOGT ("update-resolv-conf: close temporary file %s failed (%s)", - MY_RESOLV_CONF_TMP, g_strerror (errsv)); + MY_RESOLV_CONF_TMP, nm_strerror_native (errsv)); } return SR_ERROR; } else if (!success) @@ -912,9 +926,9 @@ update_resolv_conf (NMDnsManager *self, NM_MANAGER_ERROR_FAILED, "Could not replace %s: %s", MY_RESOLV_CONF, - g_strerror (errno)); + nm_strerror_native (errsv)); _LOGT ("update-resolv-conf: failed to rename temporary file %s to %s (%s)", - MY_RESOLV_CONF_TMP, MY_RESOLV_CONF, g_strerror (errsv)); + MY_RESOLV_CONF_TMP, MY_RESOLV_CONF, nm_strerror_native (errsv)); return SR_ERROR; } @@ -949,10 +963,10 @@ update_resolv_conf (NMDnsManager *self, NM_MANAGER_ERROR_FAILED, "Could not unlink %s: %s", RESOLV_CONF_TMP, - g_strerror (errsv)); + nm_strerror_native (errsv)); _LOGT ("update-resolv-conf: write internal file %s succeeded " "but canot delete temporary file %s: %s", - MY_RESOLV_CONF, RESOLV_CONF_TMP, g_strerror (errsv)); + MY_RESOLV_CONF, RESOLV_CONF_TMP, nm_strerror_native (errsv)); return SR_ERROR; } @@ -964,10 +978,10 @@ update_resolv_conf (NMDnsManager *self, "Could not create symlink %s pointing to %s: %s", RESOLV_CONF_TMP, MY_RESOLV_CONF, - g_strerror (errsv)); + nm_strerror_native (errsv)); _LOGT ("update-resolv-conf: write internal file %s succeeded " "but failed to symlink %s: %s", - MY_RESOLV_CONF, RESOLV_CONF_TMP, g_strerror (errsv)); + MY_RESOLV_CONF, RESOLV_CONF_TMP, nm_strerror_native (errsv)); return SR_ERROR; } @@ -979,10 +993,10 @@ update_resolv_conf (NMDnsManager *self, "Could not rename %s to %s: %s", RESOLV_CONF_TMP, _PATH_RESCONF, - g_strerror (errsv)); + nm_strerror_native (errsv)); _LOGT ("update-resolv-conf: write internal file %s succeeded " "but failed to rename temporary symlink %s to %s: %s", - MY_RESOLV_CONF, RESOLV_CONF_TMP, _PATH_RESCONF, g_strerror (errsv)); + MY_RESOLV_CONF, RESOLV_CONF_TMP, _PATH_RESCONF, nm_strerror_native (errsv)); return SR_ERROR; } @@ -1414,6 +1428,16 @@ update_dns (NMDnsManager *self, &searches, &options, &nameservers, &nis_servers, &nis_domain); + if (priv->plugin || priv->sd_resolve_plugin) + rebuild_domain_lists (self); + + if (priv->sd_resolve_plugin) { + nm_dns_plugin_update (priv->sd_resolve_plugin, + global_config, + _ip_config_lst_head (self), + priv->hostname); + } + /* Let any plugins do their thing first */ if (priv->plugin) { NMDnsPlugin *plugin = priv->plugin; @@ -1429,7 +1453,6 @@ 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), @@ -1441,15 +1464,21 @@ 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: ; } + /* 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); + + update_resolv_conf_no_stub (self, + NM_CAST_STRV_CC (searches), + NM_CAST_STRV_CC (nameservers), + NM_CAST_STRV_CC (options)); + /* If caching was successful, we only send 127.0.0.1 to /etc/resolv.conf * to ensure that the glibc resolver doesn't try to round-robin nameservers, * but only uses the local caching nameserver. @@ -1963,9 +1992,13 @@ init_resolv_conf_mode (NMDnsManager *self, gboolean force_reload_plugin) NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self); NMDnsManagerResolvConfManager rc_manager; const char *mode; - gboolean param_changed = FALSE, plugin_changed = FALSE; + gboolean systemd_resolved; + gboolean param_changed = FALSE; + gboolean plugin_changed = FALSE; + gboolean systemd_resolved_changed = FALSE; mode = nm_config_data_get_dns_mode (nm_config_get_data (priv->config)); + systemd_resolved = nm_config_data_get_systemd_resolved (nm_config_get_data (priv->config)); if (nm_streq0 (mode, "none")) rc_manager = NM_DNS_MANAGER_RESOLV_CONF_MAN_UNMANAGED; @@ -2011,6 +2044,7 @@ again: plugin_changed = TRUE; } mode = "systemd-resolved"; + systemd_resolved = FALSE; } else if (nm_streq0 (mode, "dnsmasq")) { if (force_reload_plugin || !NM_IS_DNS_DNSMASQ (priv->plugin)) { _clear_plugin (self); @@ -2033,7 +2067,18 @@ again: plugin_changed = TRUE; } - if (plugin_changed && priv->plugin) { + /* The systemd-resolved plugin is special. We typically always want to keep + * systemd-resolved up to date even if the configured plugin is different. */ + if (systemd_resolved) { + if (!priv->sd_resolve_plugin) { + priv->sd_resolve_plugin = nm_dns_systemd_resolved_new (); + systemd_resolved_changed = TRUE; + } + } else if (nm_clear_g_object (&priv->sd_resolve_plugin)) + systemd_resolved_changed = TRUE; + + if ( plugin_changed + && priv->plugin) { g_signal_connect (priv->plugin, NM_DNS_PLUGIN_FAILED, G_CALLBACK (plugin_failed), self); g_signal_connect (priv->plugin, NM_DNS_PLUGIN_CHILD_QUIT, G_CALLBACK (plugin_child_quit), self); } @@ -2053,9 +2098,11 @@ again: _notify (self, PROP_RC_MANAGER); } - if (param_changed || plugin_changed) { - _LOGI ("init: dns=%s, rc-manager=%s%s%s%s", - mode, _rc_manager_to_string (rc_manager), + if (param_changed || plugin_changed || systemd_resolved_changed) { + _LOGI ("init: dns=%s%s rc-manager=%s%s%s%s", + mode, + (systemd_resolved ? ",systemd-resolved" : ""), + _rc_manager_to_string (rc_manager), NM_PRINT_FMT_QUOTED (priv->plugin, ", plugin=", nm_dns_plugin_get_name (priv->plugin), "", "")); } @@ -2316,6 +2363,7 @@ dispose (GObject *object) if (priv->config) g_signal_handlers_disconnect_by_func (priv->config, config_changed_cb, self); + g_clear_object (&priv->sd_resolve_plugin); _clear_plugin (self); priv->best_ip_config_4 = NULL; diff --git a/src/dns/nm-dns-manager.h b/src/dns/nm-dns-manager.h index a3e9472e..7f6ed3ed 100644 --- a/src/dns/nm-dns-manager.h +++ b/src/dns/nm-dns-manager.h @@ -129,6 +129,8 @@ typedef enum { void nm_dns_manager_stop (NMDnsManager *self); +gboolean nm_dns_manager_has_systemd_resolved (NMDnsManager *self); + /*****************************************************************************/ char *nmtst_dns_create_resolv_conf (const char *const*searches, diff --git a/src/dns/nm-dns-plugin.c b/src/dns/nm-dns-plugin.c index 48f04b00..ce814186 100644 --- a/src/dns/nm-dns-plugin.c +++ b/src/dns/nm-dns-plugin.c @@ -21,7 +21,6 @@ #include "nm-dns-plugin.h" -#include #include #include #include -- cgit 1.3.0-6-gf8a5 From 85563b7fc7ec2cd21e38debb9b28db342e2e8e7c Mon Sep 17 00:00:00 2001 From: Michael Biebl Date: Sun, 21 Apr 2019 21:09:51 +0200 Subject: New upstream version 1.18.0 --- src/dns/nm-dns-manager.c | 11 +- src/dns/nm-dns-systemd-resolved.c | 283 +++++++++++++++++++++++++++++--------- src/dns/nm-dns-systemd-resolved.h | 2 + 3 files changed, 231 insertions(+), 65 deletions(-) (limited to 'src/dns') diff --git a/src/dns/nm-dns-manager.c b/src/dns/nm-dns-manager.c index c7c561c4..27c3e710 100644 --- a/src/dns/nm-dns-manager.c +++ b/src/dns/nm-dns-manager.c @@ -347,13 +347,20 @@ gboolean nm_dns_manager_has_systemd_resolved (NMDnsManager *self) { NMDnsManagerPrivate *priv; + NMDnsSystemdResolved *plugin = NULL; g_return_val_if_fail (NM_IS_DNS_MANAGER (self), FALSE); priv = NM_DNS_MANAGER_GET_PRIVATE (self); - return priv->sd_resolve_plugin - || NM_IS_DNS_SYSTEMD_RESOLVED (priv->plugin); + if (priv->sd_resolve_plugin) { + nm_assert (!NM_IS_DNS_SYSTEMD_RESOLVED (priv->plugin)); + plugin = NM_DNS_SYSTEMD_RESOLVED (priv->sd_resolve_plugin); + } else if (NM_IS_DNS_SYSTEMD_RESOLVED (priv->plugin)) + plugin = NM_DNS_SYSTEMD_RESOLVED (priv->plugin); + + return plugin + && nm_dns_systemd_resolved_is_running (plugin); } /*****************************************************************************/ diff --git a/src/dns/nm-dns-systemd-resolved.c b/src/dns/nm-dns-systemd-resolved.c index 10797b86..5d262ba3 100644 --- a/src/dns/nm-dns-systemd-resolved.c +++ b/src/dns/nm-dns-systemd-resolved.c @@ -31,7 +31,7 @@ #include #include -#include "nm-utils/nm-c-list.h" +#include "nm-glib-aux/nm-c-list.h" #include "nm-core-internal.h" #include "platform/nm-platform.h" #include "nm-utils.h" @@ -42,9 +42,11 @@ #include "nm-setting-connection.h" #include "devices/nm-device.h" #include "NetworkManagerUtils.h" +#include "nm-std-aux/nm-dbus-compat.h" -#define SYSTEMD_RESOLVED_DBUS_SERVICE "org.freedesktop.resolve1" -#define SYSTEMD_RESOLVED_DBUS_PATH "/org/freedesktop/resolve1" +#define SYSTEMD_RESOLVED_DBUS_SERVICE "org.freedesktop.resolve1" +#define SYSTEMD_RESOLVED_MANAGER_IFACE "org.freedesktop.resolve1.Manager" +#define SYSTEMD_RESOLVED_DBUS_PATH "/org/freedesktop/resolve1" /*****************************************************************************/ @@ -62,10 +64,14 @@ typedef struct { /*****************************************************************************/ typedef struct { - GDBusProxy *resolve; - GCancellable *init_cancellable; - GCancellable *update_cancellable; + GDBusConnection *dbus_connection; + GCancellable *cancellable; CList request_queue_lst_head; + guint name_owner_changed_id; + bool send_updates_warn_ratelimited:1; + bool try_start_blocked:1; + bool dbus_has_owner:1; + bool dbus_initied:1; } NMDnsSystemdResolvedPrivate; struct _NMDnsSystemdResolved { @@ -121,17 +127,26 @@ _interface_config_free (InterfaceConfig *config) static void call_done (GObject *source, GAsyncResult *r, gpointer user_data) { - GVariant *v; - GError *error = NULL; + gs_unref_variant GVariant *v = NULL; + gs_free_error GError *error = NULL; NMDnsSystemdResolved *self = (NMDnsSystemdResolved *) user_data; + NMDnsSystemdResolvedPrivate *priv; + + v = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), r, &error); + if ( !v + && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE (self); - v = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), r, &error); if (!v) { - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - _LOGW ("Failed: %s", error->message); - g_error_free (error); - } + if (!priv->send_updates_warn_ratelimited) { + priv->send_updates_warn_ratelimited = TRUE; + _LOGW ("send-updates failed to update systemd-resolved: %s", error->message); + } else + _LOGD ("send-updates failed: %s", error->message); + } else + priv->send_updates_warn_ratelimited = FALSE; } static void @@ -175,12 +190,11 @@ static void free_pending_updates (NMDnsSystemdResolved *self) { NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE (self); - RequestItem *request_item, *request_item_safe; + RequestItem *request_item; - c_list_for_each_entry_safe (request_item, - request_item_safe, - &priv->request_queue_lst_head, - request_queue_lst) + while ((request_item = c_list_first_entry (&priv->request_queue_lst_head, + RequestItem, + request_queue_lst))) _request_item_free (request_item); } @@ -267,27 +281,74 @@ static void send_updates (NMDnsSystemdResolved *self) { NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE (self); - RequestItem *request_item, *request_item_safe; + RequestItem *request_item; + + if (c_list_is_empty (&priv->request_queue_lst_head)) { + /* nothing to do. */ + return; + } + + if (!priv->dbus_initied) { + _LOGT ("send-updates: D-Bus connection not ready"); + return; + } - nm_clear_g_cancellable (&priv->update_cancellable); + if (!priv->dbus_has_owner) { + if (priv->try_start_blocked) { + /* we have no name owner and we already tried poking the service to + * autostart. */ + _LOGT ("send-updates: no name owner"); + return; + } - if (!priv->resolve) + _LOGT ("send-updates: no name owner. Try start service..."); + priv->try_start_blocked = TRUE; + + g_dbus_connection_call (priv->dbus_connection, + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + "StartServiceByName", + g_variant_new ("(su)", SYSTEMD_RESOLVED_DBUS_SERVICE, 0u), + G_VARIANT_TYPE ("(u)"), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + NULL, + NULL); return; + } - priv->update_cancellable = g_cancellable_new (); - - 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); + _LOGT ("send-updates: start %lu requests", + c_list_length (&priv->request_queue_lst_head)); + + nm_clear_g_cancellable (&priv->cancellable); + + priv->cancellable = g_cancellable_new (); + + while ((request_item = c_list_first_entry (&priv->request_queue_lst_head, + RequestItem, + request_queue_lst))) { + /* Above we explicitly call "StartServiceByName" trying to avoid D-Bus activating systmd-resolved + * multiple times. There is still a race, were we might hit this line although actually + * the service just quit this very moment. In that case, we would try to D-Bus activate the + * service multiple times during each call (something we wanted to avoid). + * + * But this is hard to avoid, because we'd have to check the error failure to detect the reason + * and retry. The race is not critical, because at worst it results in logging a warning + * about failure to start systemd.resolved. */ + g_dbus_connection_call (priv->dbus_connection, + SYSTEMD_RESOLVED_DBUS_SERVICE, + SYSTEMD_RESOLVED_DBUS_PATH, + SYSTEMD_RESOLVED_MANAGER_IFACE, + request_item->operation, + request_item->argument, + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->cancellable, + call_done, + self); _request_item_free (request_item); } } @@ -361,28 +422,100 @@ get_name (NMDnsPlugin *plugin) /*****************************************************************************/ static void -resolved_proxy_created (GObject *source, GAsyncResult *r, gpointer user_data) +name_owner_changed (NMDnsSystemdResolved *self, + const char *owner) { - NMDnsSystemdResolved *self = (NMDnsSystemdResolved *) user_data; + NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE (self); + + owner = nm_str_not_empty (owner); + + if (!owner) + _LOGT ("D-Bus name for systemd-resolved has no owner"); + else + _LOGT ("D-Bus name for systemd-resolved has owner %s", owner); + + priv->dbus_has_owner = !!owner; + if (owner) + priv->try_start_blocked = FALSE; + + send_updates (self); +} + +static void +name_owner_changed_cb (GDBusConnection *connection, + const char *sender_name, + const char *object_path, + const char *interface_name, + const char *signal_name, + GVariant *parameters, + gpointer user_data) +{ + NMDnsSystemdResolved *self = user_data; + NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE (self); + const char *new_owner; + + if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(sss)"))) + return; + + g_variant_get (parameters, + "(&s&s&s)", + NULL, + NULL, + &new_owner); + + if (!priv->dbus_initied) { + /* There was a race and we got a NameOwnerChanged signal before GetNameOwner + * returns. */ + priv->dbus_initied = TRUE; + nm_clear_g_cancellable (&priv->cancellable); + } + + name_owner_changed (user_data, new_owner); +} + +static void +get_name_owner_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + NMDnsSystemdResolved *self; NMDnsSystemdResolvedPrivate *priv; + gs_unref_variant GVariant *ret = NULL; gs_free_error GError *error = NULL; - GDBusProxy *resolve; + const char *owner = NULL; - resolve = g_dbus_proxy_new_finish (r, &error); - if ( !resolve + ret = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), res, &error); + if ( !ret && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) return; + if (ret) + g_variant_get (ret, "(&s)", &owner); + + self = user_data; priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE (self); - g_clear_object (&priv->init_cancellable); - if (!resolve) { - _LOGW ("failed to connect to resolved via DBus: %s", error->message); - g_signal_emit_by_name (self, NM_DNS_PLUGIN_FAILED); - return; - } - priv->resolve = resolve; - send_updates (self); + g_clear_object (&priv->cancellable); + + priv->dbus_initied = TRUE; + + name_owner_changed (self, owner); +} + +/*****************************************************************************/ + +gboolean +nm_dns_systemd_resolved_is_running (NMDnsSystemdResolved *self) +{ + NMDnsSystemdResolvedPrivate *priv; + + g_return_val_if_fail (NM_IS_DNS_SYSTEMD_RESOLVED (self), FALSE); + + priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE (self); + + return priv->dbus_initied + && ( priv->dbus_has_owner + || !priv->try_start_blocked); } /*****************************************************************************/ @@ -394,17 +527,35 @@ nm_dns_systemd_resolved_init (NMDnsSystemdResolved *self) c_list_init (&priv->request_queue_lst_head); - priv->init_cancellable = g_cancellable_new (); - g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | - G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, - NULL, - SYSTEMD_RESOLVED_DBUS_SERVICE, - SYSTEMD_RESOLVED_DBUS_PATH, - SYSTEMD_RESOLVED_DBUS_SERVICE ".Manager", - priv->init_cancellable, - resolved_proxy_created, - self); + priv->dbus_connection = nm_g_object_ref (nm_dbus_manager_get_dbus_connection (nm_dbus_manager_get ())); + if (!priv->dbus_connection) { + _LOGD ("no D-Bus connection"); + return; + } + + priv->name_owner_changed_id = g_dbus_connection_signal_subscribe (priv->dbus_connection, + DBUS_SERVICE_DBUS, + DBUS_INTERFACE_DBUS, + "NameOwnerChanged", + DBUS_PATH_DBUS, + SYSTEMD_RESOLVED_DBUS_SERVICE, + G_DBUS_SIGNAL_FLAGS_NONE, + name_owner_changed_cb, + self, + NULL); + priv->cancellable = g_cancellable_new (); + g_dbus_connection_call (priv->dbus_connection, + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + "GetNameOwner", + g_variant_new ("(s)", SYSTEMD_RESOLVED_DBUS_SERVICE), + G_VARIANT_TYPE ("(s)"), + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->cancellable, + get_name_owner_cb, + self); } NMDnsPlugin * @@ -420,9 +571,15 @@ dispose (GObject *object) NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE (self); free_pending_updates (self); - g_clear_object (&priv->resolve); - nm_clear_g_cancellable (&priv->init_cancellable); - nm_clear_g_cancellable (&priv->update_cancellable); + + if (priv->name_owner_changed_id != 0) { + g_dbus_connection_signal_unsubscribe (priv->dbus_connection, + nm_steal_int (&priv->name_owner_changed_id)); + } + + nm_clear_g_cancellable (&priv->cancellable); + + g_clear_object (&priv->dbus_connection); G_OBJECT_CLASS (nm_dns_systemd_resolved_parent_class)->dispose (object); } diff --git a/src/dns/nm-dns-systemd-resolved.h b/src/dns/nm-dns-systemd-resolved.h index 800a60c1..b79ff5e4 100644 --- a/src/dns/nm-dns-systemd-resolved.h +++ b/src/dns/nm-dns-systemd-resolved.h @@ -36,4 +36,6 @@ GType nm_dns_systemd_resolved_get_type (void); NMDnsPlugin *nm_dns_systemd_resolved_new (void); +gboolean nm_dns_systemd_resolved_is_running (NMDnsSystemdResolved *self); + #endif /* __NETWORKMANAGER_DNS_SYSTEMD_RESOLVED_H__ */ -- cgit 1.3.0-6-gf8a5