summary refs log tree commit diff
path: root/src/core/dns/nm-dns-systemd-resolved.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/dns/nm-dns-systemd-resolved.c')
-rw-r--r--src/core/dns/nm-dns-systemd-resolved.c465
1 files changed, 416 insertions, 49 deletions
diff --git a/src/core/dns/nm-dns-systemd-resolved.c b/src/core/dns/nm-dns-systemd-resolved.c
index f6e116f3..4b8c4f94 100644
--- a/src/core/dns/nm-dns-systemd-resolved.c
+++ b/src/core/dns/nm-dns-systemd-resolved.c
@@ -16,10 +16,10 @@
 #include <sys/stat.h>
 #include <linux/if.h>
 
-#include "nm-glib-aux/nm-c-list.h"
-#include "nm-glib-aux/nm-dbus-aux.h"
-#include "nm-core-internal.h"
-#include "platform/nm-platform.h"
+#include "libnm-glib-aux/nm-c-list.h"
+#include "libnm-glib-aux/nm-dbus-aux.h"
+#include "libnm-core-intern/nm-core-internal.h"
+#include "libnm-platform/nm-platform.h"
 #include "nm-utils.h"
 #include "nm-ip4-config.h"
 #include "nm-ip6-config.h"
@@ -28,7 +28,7 @@
 #include "nm-setting-connection.h"
 #include "devices/nm-device.h"
 #include "NetworkManagerUtils.h"
-#include "nm-std-aux/nm-dbus-compat.h"
+#include "libnm-std-aux/nm-dbus-compat.h"
 
 #define SYSTEMD_RESOLVED_DBUS_SERVICE  "org.freedesktop.resolve1"
 #define SYSTEMD_RESOLVED_MANAGER_IFACE "org.freedesktop.resolve1.Manager"
@@ -52,19 +52,40 @@ typedef struct {
     int                   ifindex;
 } RequestItem;
 
+struct _NMDnsSystemdResolvedResolveHandle {
+    CList                 handle_lst;
+    NMDnsSystemdResolved *self;
+    GSource *             timeout_source;
+    GCancellable *        handle_cancellable;
+    gpointer              callback_user_data;
+    guint                 timeout_msec;
+    bool                  is_failing_on_idle;
+    union {
+        struct {
+            NMDnsSystemdResolvedResolveAddressCallback callback;
+            guint64                                    flags;
+            int                                        ifindex;
+            int                                        addr_family;
+            NMIPAddr                                   addr;
+        } r_address;
+    };
+};
+
 /*****************************************************************************/
 
 typedef struct {
     GDBusConnection *dbus_connection;
     GHashTable *     dirty_interfaces;
     GCancellable *   cancellable;
+    GSource *        try_start_timeout_source;
     CList            request_queue_lst_head;
+    char *           dbus_owner;
+    CList            handle_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;
-    bool             request_queue_to_send : 1;
+    bool             send_updates_waiting : 1;
     NMTernary        has_link_default_route : 3;
 } NMDnsSystemdResolvedPrivate;
 
@@ -84,9 +105,39 @@ G_DEFINE_TYPE(NMDnsSystemdResolved, nm_dns_systemd_resolved, NM_TYPE_DNS_PLUGIN)
 
 /*****************************************************************************/
 
-#define _NMLOG_DOMAIN LOGD_DNS
+#define _NMLOG_DOMAIN      LOGD_DNS
+#define _NMLOG_PREFIX_NAME "dns-sd-resolved"
+
 #define _NMLOG(level, ...) \
-    __NMLOG_DEFAULT_WITH_ADDR(level, _NMLOG_DOMAIN, "dns-sd-resolved", __VA_ARGS__)
+    __NMLOG_DEFAULT_WITH_ADDR(level, _NMLOG_DOMAIN, _NMLOG_PREFIX_NAME, __VA_ARGS__)
+
+#define _NMLOG2(level, handle, ...)                                                         \
+    G_STMT_START                                                                            \
+    {                                                                                       \
+        const NMLogLevel _level = (level);                                                  \
+                                                                                            \
+        if (nm_logging_enabled(_level, (_NMLOG_DOMAIN))) {                                  \
+            const NMDnsSystemdResolvedResolveHandle *const _handle = (handle);              \
+                                                                                            \
+            _nm_log(_level,                                                                 \
+                    (_NMLOG_DOMAIN),                                                        \
+                    0,                                                                      \
+                    NULL,                                                                   \
+                    NULL,                                                                   \
+                    "%s[" NM_HASH_OBFUSCATE_PTR_FMT "]: request[" NM_HASH_OBFUSCATE_PTR_FMT \
+                    "]: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__),                               \
+                    _NMLOG_PREFIX_NAME,                                                     \
+                    NM_HASH_OBFUSCATE_PTR(self),                                            \
+                    NM_HASH_OBFUSCATE_PTR(_handle) _NM_UTILS_MACRO_REST(__VA_ARGS__));      \
+        }                                                                                   \
+    }                                                                                       \
+    G_STMT_END
+
+/*****************************************************************************/
+
+static void _resolve_complete_error(NMDnsSystemdResolvedResolveHandle *handle, GError *error);
+
+static void _resolve_start(NMDnsSystemdResolved *self, NMDnsSystemdResolvedResolveHandle *handle);
 
 /*****************************************************************************/
 
@@ -201,10 +252,7 @@ update_add_ip_config(NMDnsSystemdResolved *self,
         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(data->ip_config, i),
-                                      addr_size,
-                                      1));
+            nm_g_variant_new_ay(nm_ip_config_get_nameserver(data->ip_config, i), addr_size));
         g_variant_builder_close(dns);
         has_config = TRUE;
     }
@@ -326,57 +374,105 @@ prepare_one_interface(NMDnsSystemdResolved *self, InterfaceConfig *ic)
     return has_config;
 }
 
-static void
-send_updates(NMDnsSystemdResolved *self)
+static gboolean
+_ensure_resolved_running_timeout(gpointer user_data)
 {
-    NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self);
-    RequestItem *                request_item;
+    NMDnsSystemdResolved *             self = user_data;
+    NMDnsSystemdResolvedPrivate *      priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self);
+    NMDnsSystemdResolvedResolveHandle *handle;
 
-    if (!priv->request_queue_to_send) {
-        /* nothing to do. */
-        return;
-    }
+    nm_clear_g_source_inst(&priv->try_start_timeout_source);
 
-    if (!priv->dbus_initied) {
-        _LOGT("send-updates: D-Bus connection not ready");
-        return;
+    _LOGT("timeout waiting to D-Bus activate systemd-resolved. Systemd-resolved won't be "
+          "used until it appears on the bus");
+
+again:
+    c_list_for_each_entry (handle, &priv->handle_lst_head, handle_lst) {
+        gs_free_error GError *error = NULL;
+
+        if (handle->is_failing_on_idle)
+            continue;
+
+        nm_utils_error_set_literal(&error,
+                                   NM_UTILS_ERROR_NOT_READY,
+                                   "timeout waiting for systemd-resolved to start");
+        _resolve_complete_error(handle, error);
+        goto again;
     }
 
-    if (!priv->dbus_has_owner) {
+    return G_SOURCE_CONTINUE;
+}
+
+static NMTernary
+ensure_resolved_running(NMDnsSystemdResolved *self)
+{
+    NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self);
+
+    if (!priv->dbus_initied)
+        return NM_TERNARY_DEFAULT;
+
+    if (!priv->dbus_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;
+            return NM_TERNARY_FALSE;
         }
 
-        _LOGT("send-updates: no name owner. Try start service...");
+        _LOGT("try D-Bus activating systemd-resolved...");
         priv->try_start_blocked = TRUE;
 
+        priv->try_start_timeout_source =
+            nm_g_source_attach(nm_g_timeout_source_new(4000,
+                                                       G_PRIORITY_DEFAULT,
+                                                       _ensure_resolved_running_timeout,
+                                                       self,
+                                                       NULL),
+                               NULL);
+
         nm_dbus_connection_call_start_service_by_name(priv->dbus_connection,
                                                       SYSTEMD_RESOLVED_DBUS_SERVICE,
                                                       -1,
                                                       NULL,
                                                       NULL,
                                                       NULL);
+        return NM_TERNARY_DEFAULT;
+    }
+
+    return NM_TERNARY_TRUE;
+}
+
+static void
+send_updates(NMDnsSystemdResolved *self)
+{
+    NMDnsSystemdResolvedPrivate *      priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self);
+    RequestItem *                      request_item;
+    NMDnsSystemdResolvedResolveHandle *handle;
+
+    if (!priv->send_updates_waiting) {
+        /* nothing to do. */
         return;
     }
 
+    if (ensure_resolved_running(self) != NM_TERNARY_TRUE)
+        return;
+
     nm_clear_g_cancellable(&priv->cancellable);
 
     if (c_list_is_empty(&priv->request_queue_lst_head)) {
         _LOGT("send-updates: no requests to send");
-        priv->request_queue_to_send = FALSE;
-        return;
+        priv->send_updates_waiting = FALSE;
+        goto start_resolve;
     }
 
-    _LOGT("send-updates: start %lu requests", c_list_length(&priv->request_queue_lst_head));
-
     priv->cancellable = g_cancellable_new();
 
-    priv->request_queue_to_send = FALSE;
+    priv->send_updates_waiting = FALSE;
+
+    _LOGT("send-updates: start %lu requests", c_list_length(&priv->request_queue_lst_head));
 
     c_list_for_each_entry (request_item, &priv->request_queue_lst_head, request_queue_lst) {
+        gs_free char *ss = NULL;
+
         if (request_item->operation == DBUS_OP_SET_LINK_DEFAULT_ROUTE
             && priv->has_link_default_route == NM_TERNARY_FALSE) {
             /* The "SetLinkDefaultRoute" API is only supported since v240.
@@ -386,16 +482,12 @@ send_updates(NMDnsSystemdResolved *self)
             continue;
         }
 
-        /* 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. */
+        _LOGT("send-updates: %s ( %s )",
+              request_item->operation,
+              (ss = g_variant_print(request_item->argument, FALSE)));
+
         g_dbus_connection_call(priv->dbus_connection,
-                               SYSTEMD_RESOLVED_DBUS_SERVICE,
+                               priv->dbus_owner,
                                SYSTEMD_RESOLVED_DBUS_PATH,
                                SYSTEMD_RESOLVED_MANAGER_IFACE,
                                request_item->operation,
@@ -407,6 +499,15 @@ send_updates(NMDnsSystemdResolved *self)
                                call_done,
                                request_item);
     }
+
+start_resolve:
+    c_list_for_each_entry (handle, &priv->handle_lst_head, handle_lst) {
+        if (handle->handle_cancellable)
+            continue;
+        if (handle->is_failing_on_idle)
+            continue;
+        _resolve_start(self, handle);
+    }
 }
 
 static gboolean
@@ -479,7 +580,7 @@ update(NMDnsPlugin *            plugin,
         }
     }
 
-    priv->request_queue_to_send = TRUE;
+    priv->send_updates_waiting = TRUE;
     send_updates(self);
     return TRUE;
 }
@@ -498,10 +599,13 @@ name_owner_changed(NMDnsSystemdResolved *self, const char *owner)
     else
         _LOGT("D-Bus name for systemd-resolved has owner %s", owner);
 
-    priv->dbus_has_owner = !!owner;
+    nm_clear_g_source_inst(&priv->try_start_timeout_source);
+
+    nm_utils_strdup_reset(&priv->dbus_owner, owner);
+
     if (owner) {
-        priv->try_start_blocked     = FALSE;
-        priv->request_queue_to_send = TRUE;
+        priv->try_start_blocked    = FALSE;
+        priv->send_updates_waiting = TRUE;
     } else
         priv->has_link_default_route = NM_TERNARY_DEFAULT;
 
@@ -531,6 +635,7 @@ name_owner_changed_cb(GDBusConnection *connection,
          * returns. */
         priv->dbus_initied = TRUE;
         nm_clear_g_cancellable(&priv->cancellable);
+        _LOGT("D-Bus connection is ready");
     }
 
     name_owner_changed(user_data, new_owner);
@@ -551,6 +656,7 @@ get_name_owner_cb(const char *name_owner, GError *error, gpointer user_data)
     g_clear_object(&priv->cancellable);
 
     priv->dbus_initied = TRUE;
+    _LOGT("D-Bus connection is ready");
 
     name_owner_changed(self, name_owner);
 }
@@ -566,7 +672,253 @@ nm_dns_systemd_resolved_is_running(NMDnsSystemdResolved *self)
 
     priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self);
 
-    return priv->dbus_initied && (priv->dbus_has_owner || !priv->try_start_blocked);
+    return priv->dbus_initied && (priv->dbus_owner || !priv->try_start_blocked);
+}
+
+/*****************************************************************************/
+
+static void
+_resolve_complete(NMDnsSystemdResolvedResolveHandle *      handle,
+                  const NMDnsSystemdResolvedAddressResult *names,
+                  guint                                    names_len,
+                  guint64                                  flags,
+                  GError *                                 error)
+{
+    NMDnsSystemdResolved *       self;
+    NMDnsSystemdResolvedPrivate *priv;
+
+    g_return_if_fail(handle && NM_IS_DNS_SYSTEMD_RESOLVED(handle->self));
+
+    self = handle->self;
+    priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self);
+
+    nm_assert(c_list_contains(&priv->handle_lst_head, &handle->handle_lst));
+
+    c_list_unlink(&handle->handle_lst);
+
+    handle->self = NULL;
+
+    nm_clear_g_source_inst(&handle->timeout_source);
+    nm_clear_g_cancellable(&handle->handle_cancellable);
+
+    handle->r_address
+        .callback(self, handle, names, names_len, flags, error, handle->callback_user_data);
+
+    nm_g_slice_free(handle);
+}
+
+static void
+_resolve_complete_error(NMDnsSystemdResolvedResolveHandle *handle, GError *error)
+{
+    NMDnsSystemdResolved *self = handle->self;
+
+    nm_assert(error);
+    _LOG2T(handle, "request failed: %s", error->message);
+    _resolve_complete(handle, NULL, 0, 0, error);
+}
+
+static void
+_resolve_handle_call_cb(GObject *source, GAsyncResult *result, gpointer user_data)
+{
+    gs_unref_variant GVariant *v             = NULL;
+    gs_free_error GError *             error = NULL;
+    NMDnsSystemdResolvedResolveHandle *handle;
+    NMDnsSystemdResolved *             self;
+    GVariantIter *                     v_names_iter;
+    guint64                            v_flags;
+    int                                v_ifindex;
+    char *                             v_name;
+    gs_unref_array GArray *v_names = NULL;
+    gs_free char *         ss      = NULL;
+
+    v = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), result, &error);
+    if (nm_utils_error_is_cancelled(error))
+        return;
+
+    handle = user_data;
+    self   = handle->self;
+
+    if (error) {
+        gs_free char *remote_error = NULL;
+
+        remote_error = g_dbus_error_get_remote_error(error);
+        if (nm_streq0(remote_error, "org.freedesktop.DBus.Error.ServiceUnknown")) {
+            _LOG2T(handle, "request failed due to service stop. Retry");
+            g_clear_object(&handle->handle_cancellable);
+            _resolve_start(self, handle);
+            return;
+        }
+
+        _resolve_complete_error(handle, error);
+        return;
+    }
+
+    _LOG2T(handle, "request completed: %s", (ss = g_variant_print(v, FALSE)));
+
+    v_names = g_array_new(FALSE, FALSE, sizeof(NMDnsSystemdResolvedAddressResult));
+
+    G_STATIC_ASSERT_EXPR(G_STRUCT_OFFSET(NMDnsSystemdResolvedAddressResult, name) == 0);
+    g_array_set_clear_func(v_names, nm_indirect_g_free);
+
+    g_variant_get(v, "(a(is)t)", &v_names_iter, &v_flags);
+
+    while (g_variant_iter_next(v_names_iter, "(is)", &v_ifindex, &v_name)) {
+        NMDnsSystemdResolvedAddressResult *n;
+
+        n  = nm_g_array_append_new(v_names, NMDnsSystemdResolvedAddressResult);
+        *n = (NMDnsSystemdResolvedAddressResult){
+            .name    = g_steal_pointer(&v_name),
+            .ifindex = v_ifindex,
+        };
+    }
+    g_variant_iter_free(v_names_iter);
+
+    _resolve_complete(handle,
+                      &g_array_index(v_names, NMDnsSystemdResolvedAddressResult, 0),
+                      v_names->len,
+                      v_flags,
+                      NULL);
+}
+
+static gboolean
+_resolve_failing_on_idle(gpointer user_data)
+{
+    NMDnsSystemdResolvedResolveHandle *handle = user_data;
+    gs_free_error GError *error               = NULL;
+
+    nm_utils_error_set_literal(&error,
+                               NM_UTILS_ERROR_NOT_READY,
+                               "systemd-resolved is not available");
+    _resolve_complete_error(handle, error);
+    return G_SOURCE_CONTINUE;
+}
+
+static gboolean
+_resolve_handle_timeout(gpointer user_data)
+{
+    NMDnsSystemdResolvedResolveHandle *handle = user_data;
+    gs_free_error GError *error               = NULL;
+
+    nm_utils_error_set_literal(&error, NM_UTILS_ERROR_UNKNOWN, "timeout for request");
+    _resolve_complete_error(handle, error);
+    return G_SOURCE_CONTINUE;
+}
+
+static void
+_resolve_start(NMDnsSystemdResolved *self, NMDnsSystemdResolvedResolveHandle *handle)
+{
+    NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self);
+    NMTernary                    is_running;
+
+    nm_assert(!handle->handle_cancellable);
+    nm_assert(!handle->is_failing_on_idle);
+
+    is_running = ensure_resolved_running(self);
+
+    if (is_running == NM_TERNARY_FALSE) {
+        /* Systemd-resolved is not is_running and shall not be used. We fail
+         * on an idle handler. */
+        _LOG2T(handle, "systemd-resolved not running. Failing on idle...");
+        nm_assert(!handle->timeout_source);
+        handle->is_failing_on_idle = TRUE;
+        handle->timeout_source     = nm_g_source_attach(
+            nm_g_idle_source_new(G_PRIORITY_DEFAULT, _resolve_failing_on_idle, handle, NULL),
+            NULL);
+        return;
+    }
+
+    if (!handle->timeout_source) {
+        handle->timeout_source = nm_g_source_attach(nm_g_timeout_source_new(handle->timeout_msec,
+                                                                            G_PRIORITY_DEFAULT,
+                                                                            _resolve_handle_timeout,
+                                                                            handle,
+                                                                            NULL),
+                                                    NULL);
+    }
+
+    if (is_running == NM_TERNARY_DEFAULT) {
+        /* we are D-Bus activating systemd-resolved. Wait for it... */
+        _LOG2T(handle, "waiting for systemd-resolved to start...");
+        return;
+    }
+
+    nm_assert(!priv->send_updates_waiting);
+
+    handle->handle_cancellable = g_cancellable_new();
+
+    _LOG2T(handle, "start D-Bus request...");
+    g_dbus_connection_call(priv->dbus_connection,
+                           priv->dbus_owner,
+                           SYSTEMD_RESOLVED_DBUS_PATH,
+                           SYSTEMD_RESOLVED_MANAGER_IFACE,
+                           "ResolveAddress",
+                           g_variant_new("(ii@ayt)",
+                                         handle->r_address.ifindex,
+                                         handle->r_address.addr_family,
+                                         nm_g_variant_new_ay_inaddr(handle->r_address.addr_family,
+                                                                    &handle->r_address.addr),
+                                         handle->r_address.flags),
+                           G_VARIANT_TYPE("(a(is)t)"),
+                           G_DBUS_CALL_FLAGS_NONE,
+                           handle->timeout_msec + 1000u,
+                           handle->handle_cancellable,
+                           _resolve_handle_call_cb,
+                           handle);
+}
+
+NMDnsSystemdResolvedResolveHandle *
+nm_dns_systemd_resolved_resolve_address(NMDnsSystemdResolved *                     self,
+                                        int                                        ifindex,
+                                        int                                        addr_family,
+                                        const NMIPAddr *                           addr,
+                                        guint64                                    flags,
+                                        guint                                      timeout_msec,
+                                        NMDnsSystemdResolvedResolveAddressCallback callback,
+                                        gpointer                                   user_data)
+{
+    NMDnsSystemdResolvedPrivate *      priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self);
+    NMDnsSystemdResolvedResolveHandle *handle;
+    char                               addr_str[NM_UTILS_INET_ADDRSTRLEN];
+
+    g_return_val_if_fail(NM_IS_DNS_SYSTEMD_RESOLVED(self), NULL);
+    nm_assert_addr_family(addr_family);
+    nm_assert(addr);
+    nm_assert(callback);
+
+    handle  = g_slice_new(NMDnsSystemdResolvedResolveHandle);
+    *handle = (NMDnsSystemdResolvedResolveHandle){
+        .self               = self,
+        .timeout_msec       = timeout_msec,
+        .callback_user_data = user_data,
+        .r_address =
+            {
+                .ifindex     = ifindex,
+                .addr_family = addr_family,
+                .addr        = *addr,
+                .flags       = flags,
+                .callback    = callback,
+            },
+    };
+    c_list_link_tail(&priv->handle_lst_head, &handle->handle_lst);
+
+    _LOG2T(handle,
+           "resolve-address(ifindex=%d, %s, flags=%" G_GINT64_MODIFIER "x): new request",
+           handle->r_address.ifindex,
+           nm_utils_inet_ntop(handle->r_address.addr_family, &handle->r_address.addr, addr_str),
+           handle->r_address.flags);
+
+    _resolve_start(self, handle);
+
+    return handle;
+}
+
+void
+nm_dns_systemd_resolved_resolve_cancel(NMDnsSystemdResolvedResolveHandle *handle)
+{
+    gs_free_error GError *error = NULL;
+
+    nm_utils_error_set_cancelled(&error, FALSE, "NMDnsSystemdResolved");
+    _resolve_complete_error(handle, error);
 }
 
 /*****************************************************************************/
@@ -579,6 +931,7 @@ nm_dns_systemd_resolved_init(NMDnsSystemdResolved *self)
     priv->has_link_default_route = NM_TERNARY_DEFAULT;
 
     c_list_init(&priv->request_queue_lst_head);
+    c_list_init(&priv->handle_lst_head);
     priv->dirty_interfaces = g_hash_table_new(nm_direct_hash, NULL);
 
     priv->dbus_connection = nm_g_object_ref(NM_MAIN_DBUS_CONNECTION_GET);
@@ -611,8 +964,18 @@ nm_dns_systemd_resolved_new(void)
 static void
 dispose(GObject *object)
 {
-    NMDnsSystemdResolved *       self = NM_DNS_SYSTEMD_RESOLVED(object);
-    NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self);
+    NMDnsSystemdResolved *             self = NM_DNS_SYSTEMD_RESOLVED(object);
+    NMDnsSystemdResolvedPrivate *      priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self);
+    NMDnsSystemdResolvedResolveHandle *handle;
+
+    while ((handle = c_list_first_entry(&priv->handle_lst_head,
+                                        NMDnsSystemdResolvedResolveHandle,
+                                        handle_lst))) {
+        gs_free_error GError *error = NULL;
+
+        nm_utils_error_set_cancelled(&error, TRUE, "NMDnsSystemdResolved");
+        _resolve_complete_error(handle, error);
+    }
 
     free_pending_updates(self);
 
@@ -620,10 +983,14 @@ dispose(GObject *object)
 
     nm_clear_g_cancellable(&priv->cancellable);
 
+    nm_clear_g_source_inst(&priv->try_start_timeout_source);
+
     g_clear_object(&priv->dbus_connection);
     nm_clear_pointer(&priv->dirty_interfaces, g_hash_table_unref);
 
     G_OBJECT_CLASS(nm_dns_systemd_resolved_parent_class)->dispose(object);
+
+    nm_clear_g_free(&priv->dbus_owner);
 }
 
 static void