summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/dns/nm-dns-systemd-resolved.c371
-rw-r--r--src/core/dns/nm-dns-systemd-resolved.h30
2 files changed, 384 insertions, 17 deletions
diff --git a/src/core/dns/nm-dns-systemd-resolved.c b/src/core/dns/nm-dns-systemd-resolved.c
index 8f71a83784..972ef643a3 100644
--- a/src/core/dns/nm-dns-systemd-resolved.c
+++ b/src/core/dns/nm-dns-systemd-resolved.c
@@ -52,6 +52,25 @@ 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 {
@@ -61,6 +80,7 @@ typedef struct {
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;
@@ -85,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);
/*****************************************************************************/
@@ -327,14 +377,29 @@ prepare_one_interface(NMDnsSystemdResolved *self, InterfaceConfig *ic)
static gboolean
_ensure_resolved_running_timeout(gpointer user_data)
{
- NMDnsSystemdResolved * self = user_data;
- NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self);
+ NMDnsSystemdResolved * self = user_data;
+ NMDnsSystemdResolvedPrivate * priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self);
+ NMDnsSystemdResolvedResolveHandle *handle;
nm_clear_g_source_inst(&priv->try_start_timeout_source);
- _LOGT("send-updates: timeout waiting for systemd-resolved to start. Systemd-resolved won't be "
+ _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;
+ }
+
return G_SOURCE_CONTINUE;
}
@@ -343,20 +408,17 @@ ensure_resolved_running(NMDnsSystemdResolved *self)
{
NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self);
- if (!priv->dbus_initied) {
- _LOGT("send-updates: D-Bus connection not ready");
+ 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 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 =
@@ -382,8 +444,9 @@ ensure_resolved_running(NMDnsSystemdResolved *self)
static void
send_updates(NMDnsSystemdResolved *self)
{
- NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self);
- RequestItem * request_item;
+ NMDnsSystemdResolvedPrivate * priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self);
+ RequestItem * request_item;
+ NMDnsSystemdResolvedResolveHandle *handle;
if (!priv->send_updates_waiting) {
/* nothing to do. */
@@ -398,16 +461,18 @@ send_updates(NMDnsSystemdResolved *self)
if (c_list_is_empty(&priv->request_queue_lst_head)) {
_LOGT("send-updates: no requests to send");
priv->send_updates_waiting = FALSE;
- return;
+ goto start_resolve;
}
- _LOGT("send-updates: start %lu requests", c_list_length(&priv->request_queue_lst_head));
-
priv->cancellable = g_cancellable_new();
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.
@@ -417,6 +482,10 @@ send_updates(NMDnsSystemdResolved *self)
continue;
}
+ _LOGT("send-updates: %s ( %s )",
+ request_item->operation,
+ (ss = g_variant_print(request_item->argument, FALSE)));
+
g_dbus_connection_call(priv->dbus_connection,
priv->dbus_owner,
SYSTEMD_RESOLVED_DBUS_PATH,
@@ -430,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
@@ -557,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);
@@ -577,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);
}
@@ -598,6 +678,252 @@ nm_dns_systemd_resolved_is_running(NMDnsSystemdResolved *self)
/*****************************************************************************/
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_strdup(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);
+}
+
+/*****************************************************************************/
+
+static void
nm_dns_systemd_resolved_init(NMDnsSystemdResolved *self)
{
NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self);
@@ -605,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);
@@ -637,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);
diff --git a/src/core/dns/nm-dns-systemd-resolved.h b/src/core/dns/nm-dns-systemd-resolved.h
index 4ab04ab49c..b7e30d81f7 100644
--- a/src/core/dns/nm-dns-systemd-resolved.h
+++ b/src/core/dns/nm-dns-systemd-resolved.h
@@ -30,4 +30,34 @@ NMDnsPlugin *nm_dns_systemd_resolved_new(void);
gboolean nm_dns_systemd_resolved_is_running(NMDnsSystemdResolved *self);
+/*****************************************************************************/
+
+typedef struct _NMDnsSystemdResolvedResolveHandle NMDnsSystemdResolvedResolveHandle;
+
+typedef struct {
+ const char *name;
+ int ifindex;
+} NMDnsSystemdResolvedAddressResult;
+
+typedef void (*NMDnsSystemdResolvedResolveAddressCallback)(
+ NMDnsSystemdResolved * self,
+ NMDnsSystemdResolvedResolveHandle * handle,
+ const NMDnsSystemdResolvedAddressResult *names,
+ guint names_len,
+ guint64 flags,
+ GError * error,
+ gpointer user_data);
+
+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);
+
+void nm_dns_systemd_resolved_resolve_cancel(NMDnsSystemdResolvedResolveHandle *handle);
+
#endif /* __NETWORKMANAGER_DNS_SYSTEMD_RESOLVED_H__ */