diff options
| author | Michael Biebl <biebl@debian.org> | 2020-12-06 21:57:59 +0100 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2020-12-06 21:57:59 +0100 |
| commit | 65f86e8f56267192d42f2b629fc6b0c99fb9cd0c (patch) | |
| tree | 180827692f002e5f1dad6a0fa8ca489e6bb6438f /src/dns/nm-dns-systemd-resolved.c | |
| parent | f2ddac4cbc895837ddcc55015fae112f9859cd0a (diff) | |
New upstream version 1.28.0 upstream/1.28.0
Diffstat (limited to 'src/dns/nm-dns-systemd-resolved.c')
| -rw-r--r-- | src/dns/nm-dns-systemd-resolved.c | 234 |
1 files changed, 173 insertions, 61 deletions
diff --git a/src/dns/nm-dns-systemd-resolved.c b/src/dns/nm-dns-systemd-resolved.c index 24c0ddb5..fe2e78af 100644 --- a/src/dns/nm-dns-systemd-resolved.c +++ b/src/dns/nm-dns-systemd-resolved.c @@ -34,6 +34,9 @@ #define SYSTEMD_RESOLVED_MANAGER_IFACE "org.freedesktop.resolve1.Manager" #define SYSTEMD_RESOLVED_DBUS_PATH "/org/freedesktop/resolve1" +/* define a variable, so that we can compare the operation with pointer equality. */ +static const char *const DBUS_OP_SET_LINK_DEFAULT_ROUTE = "SetLinkDefaultRoute"; + /*****************************************************************************/ typedef struct { @@ -42,15 +45,18 @@ typedef struct { } InterfaceConfig; typedef struct { - CList request_queue_lst; - const char *operation; - GVariant * argument; + CList request_queue_lst; + const char * operation; + GVariant * argument; + NMDnsSystemdResolved *self; + int ifindex; } RequestItem; /*****************************************************************************/ typedef struct { GDBusConnection *dbus_connection; + GHashTable * dirty_interfaces; GCancellable * cancellable; CList request_queue_lst_head; guint name_owner_changed_id; @@ -58,6 +64,8 @@ typedef struct { bool try_start_blocked : 1; bool dbus_has_owner : 1; bool dbus_initied : 1; + bool request_queue_to_send : 1; + NMTernary has_link_default_route : 3; } NMDnsSystemdResolvedPrivate; struct _NMDnsSystemdResolved { @@ -87,18 +95,26 @@ _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); + nm_g_slice_free(request_item); } static void -_request_item_append(CList *request_queue_lst_head, const char *operation, GVariant *argument) +_request_item_append(NMDnsSystemdResolved *self, + const char * operation, + int ifindex, + GVariant * argument) { - RequestItem *request_item; + NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self); + 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); + request_item = g_slice_new(RequestItem); + *request_item = (RequestItem){ + .operation = operation, + .argument = g_variant_ref_sink(argument), + .self = self, + .ifindex = ifindex, + }; + c_list_link_tail(&priv->request_queue_lst_head, &request_item->request_queue_lst); } /*****************************************************************************/ @@ -115,43 +131,69 @@ call_done(GObject *source, GAsyncResult *r, gpointer user_data) { gs_unref_variant GVariant *v = NULL; gs_free_error GError * error = NULL; - NMDnsSystemdResolved * self = (NMDnsSystemdResolved *) user_data; + NMDnsSystemdResolved * self; NMDnsSystemdResolvedPrivate *priv; + RequestItem * request_item; + NMLogLevel log_level; 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)) + if (nm_utils_error_is_cancelled(error)) return; - priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self); + request_item = user_data; + self = request_item->self; + priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self); - if (!v) { - 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 + if (v) { + if (request_item->operation == DBUS_OP_SET_LINK_DEFAULT_ROUTE + && priv->has_link_default_route == NM_TERNARY_DEFAULT) { + priv->has_link_default_route = NM_TERNARY_TRUE; + _LOGD("systemd-resolved support for SetLinkDefaultRoute(): API supported"); + } priv->send_updates_warn_ratelimited = FALSE; + return; + } + + if (request_item->operation == DBUS_OP_SET_LINK_DEFAULT_ROUTE + && nm_g_error_matches(error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD)) { + if (priv->has_link_default_route == NM_TERNARY_DEFAULT) { + priv->has_link_default_route = NM_TERNARY_FALSE; + _LOGD("systemd-resolved support for SetLinkDefaultRoute(): API not supported"); + } + return; + } + + log_level = LOGL_DEBUG; + if (!priv->send_updates_warn_ratelimited) { + priv->send_updates_warn_ratelimited = TRUE; + log_level = LOGL_WARN; + } + _NMLOG(log_level, + "send-updates %s@%d failed: %s", + request_item->operation, + request_item->ifindex, + error->message); } -static void +static gboolean update_add_ip_config(NMDnsSystemdResolved *self, GVariantBuilder * dns, GVariantBuilder * domains, NMDnsIPConfigData * data) { - int addr_family; - gsize addr_size; - guint i, n; - gboolean is_routing; - const char **iter; - const char * domain; + int addr_family; + gsize addr_size; + guint i, n; + gboolean is_routing; + const char *domain; + gboolean has_config = FALSE; addr_family = nm_ip_config_get_addr_family(data->ip_config); addr_size = nm_utils_addr_family_to_size(addr_family); - if (!data->domains.search || !data->domains.search[0]) - return; + if ((!data->domains.search || !data->domains.search[0]) + && !data->domains.has_default_route_exclusive && !data->domains.has_default_route) + return FALSE; n = nm_ip_config_get_num_nameservers(data->ip_config); for (i = 0; i < n; i++) { @@ -164,12 +206,22 @@ update_add_ip_config(NMDnsSystemdResolved *self, addr_size, 1)); g_variant_builder_close(dns); + has_config = TRUE; } - 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); + if (!data->domains.has_default_route_explicit && data->domains.has_default_route_exclusive) { + g_variant_builder_add(domains, "(sb)", ".", TRUE); + has_config = TRUE; } + if (data->domains.search) { + for (i = 0; data->domains.search[i]; i++) { + domain = nm_utils_parse_dns_domain(data->domains.search[i], &is_routing); + g_variant_builder_add(domains, "(sb)", domain[0] ? domain : ".", is_routing); + has_config = TRUE; + } + } + + return has_config; } static void @@ -183,15 +235,17 @@ free_pending_updates(NMDnsSystemdResolved *self) _request_item_free(request_item); } -static void +static gboolean 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; - NMSettingConnectionLlmnr llmnr = NM_SETTING_CONNECTION_LLMNR_DEFAULT; - const char * mdns_arg = NULL, *llmnr_arg = NULL; + GVariantBuilder dns; + GVariantBuilder domains; + NMCListElem * elem; + NMSettingConnectionMdns mdns = NM_SETTING_CONNECTION_MDNS_DEFAULT; + NMSettingConnectionLlmnr llmnr = NM_SETTING_CONNECTION_LLMNR_DEFAULT; + const char * mdns_arg = NULL, *llmnr_arg = NULL; + gboolean has_config = FALSE; + gboolean has_default_route = FALSE; g_variant_builder_init(&dns, G_VARIANT_TYPE("(ia(iay))")); g_variant_builder_add(&dns, "i", ic->ifindex); @@ -205,7 +259,10 @@ prepare_one_interface(NMDnsSystemdResolved *self, InterfaceConfig *ic) NMDnsIPConfigData *data = elem->data; NMIPConfig * ip_config = data->ip_config; - update_add_ip_config(self, &dns, &domains, data); + has_config |= update_add_ip_config(self, &dns, &domains, data); + + if (data->domains.has_default_route) + has_default_route = TRUE; if (NM_IS_IP4_CONFIG(ip_config)) { mdns = NM_MAX(mdns, nm_ip4_config_mdns_get(NM_IP4_CONFIG(ip_config))); @@ -248,16 +305,25 @@ prepare_one_interface(NMDnsSystemdResolved *self, InterfaceConfig *ic) } nm_assert(llmnr_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, + if (!nm_str_is_empty(mdns_arg) || !nm_str_is_empty(llmnr_arg)) + has_config = TRUE; + + _request_item_append(self, "SetLinkDomains", ic->ifindex, g_variant_builder_end(&domains)); + _request_item_append(self, + DBUS_OP_SET_LINK_DEFAULT_ROUTE, + ic->ifindex, + g_variant_new("(ib)", ic->ifindex, has_default_route)); + _request_item_append(self, "SetLinkMulticastDNS", + ic->ifindex, g_variant_new("(is)", ic->ifindex, mdns_arg ?: "")); - _request_item_append(&priv->request_queue_lst_head, + _request_item_append(self, "SetLinkLLMNR", + ic->ifindex, g_variant_new("(is)", ic->ifindex, llmnr_arg ?: "")); + _request_item_append(self, "SetLinkDNS", ic->ifindex, g_variant_builder_end(&dns)); + + return has_config; } static void @@ -266,7 +332,7 @@ send_updates(NMDnsSystemdResolved *self) NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self); RequestItem * request_item; - if (c_list_is_empty(&priv->request_queue_lst_head)) { + if (!priv->request_queue_to_send) { /* nothing to do. */ return; } @@ -296,15 +362,30 @@ send_updates(NMDnsSystemdResolved *self) return; } - _LOGT("send-updates: start %lu requests", c_list_length(&priv->request_queue_lst_head)); - 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; + } + + _LOGT("send-updates: start %lu requests", c_list_length(&priv->request_queue_lst_head)); + priv->cancellable = g_cancellable_new(); - while ( - (request_item = - c_list_first_entry(&priv->request_queue_lst_head, RequestItem, request_queue_lst))) { + priv->request_queue_to_send = FALSE; + + c_list_for_each_entry (request_item, &priv->request_queue_lst_head, request_queue_lst) { + 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. + * We detected that it is not supported, and skip the call. There + * is no special workaround, because in this case we rely on systemd-resolved + * to do the right thing automatically. */ + 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 @@ -324,8 +405,7 @@ send_updates(NMDnsSystemdResolved *self) -1, priv->cancellable, call_done, - self); - _request_item_free(request_item); + request_item); } } @@ -336,19 +416,22 @@ update(NMDnsPlugin * plugin, const char * hostname, GError ** error) { - NMDnsSystemdResolved *self = NM_DNS_SYSTEMD_RESOLVED(plugin); + NMDnsSystemdResolved * self = NM_DNS_SYSTEMD_RESOLVED(plugin); + NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self); gs_unref_hashtable GHashTable *interfaces = NULL; gs_free gpointer * interfaces_keys = NULL; guint interfaces_len; - guint i; + int ifindex; + gpointer pointer; NMDnsIPConfigData *ip_data; + GHashTableIter iter; + guint i; 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) { InterfaceConfig *ic = NULL; - int ifindex; ifindex = ip_data->data->ifindex; nm_assert(ifindex == nm_ip_config_get_ifindex(ip_data->ip_config)); @@ -371,11 +454,33 @@ update(NMDnsPlugin * plugin, 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); + if (prepare_one_interface(self, ic)) + g_hash_table_add(priv->dirty_interfaces, GINT_TO_POINTER(ic->ifindex)); + else + g_hash_table_remove(priv->dirty_interfaces, GINT_TO_POINTER(ic->ifindex)); } - send_updates(self); + /* If we previously configured an ifindex with non-empty values in + * resolved, and the current update doesn't contain that interface, + * reset the resolved configuration for that ifindex. */ + g_hash_table_iter_init(&iter, priv->dirty_interfaces); + while (g_hash_table_iter_next(&iter, (gpointer *) &pointer, NULL)) { + ifindex = GPOINTER_TO_INT(pointer); + if (!g_hash_table_contains(interfaces, GINT_TO_POINTER(ifindex))) { + InterfaceConfig ic; + + _LOGT("clear previously configured ifindex %d", ifindex); + ic = (InterfaceConfig){ + .ifindex = ifindex, + .configs_lst_head = C_LIST_INIT(ic.configs_lst_head), + }; + prepare_one_interface(self, &ic); + g_hash_table_iter_remove(&iter); + } + } + priv->request_queue_to_send = TRUE; + send_updates(self); return TRUE; } @@ -394,8 +499,11 @@ name_owner_changed(NMDnsSystemdResolved *self, const char *owner) _LOGT("D-Bus name for systemd-resolved has owner %s", owner); priv->dbus_has_owner = !!owner; - if (owner) - priv->try_start_blocked = FALSE; + if (owner) { + priv->try_start_blocked = FALSE; + priv->request_queue_to_send = TRUE; + } else + priv->has_link_default_route = NM_TERNARY_DEFAULT; send_updates(self); } @@ -468,7 +576,10 @@ nm_dns_systemd_resolved_init(NMDnsSystemdResolved *self) { NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self); + priv->has_link_default_route = NM_TERNARY_DEFAULT; + c_list_init(&priv->request_queue_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); if (!priv->dbus_connection) { @@ -510,6 +621,7 @@ dispose(GObject *object) nm_clear_g_cancellable(&priv->cancellable); 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); } |