From: Lennart Poettering Date: Tue, 3 Sep 2024 08:56:31 +0000 (+0200) Subject: resolved: add concept of delegating lookups below certain domains to specific DNS... X-Git-Tag: v258-rc1~563^2~4 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7928c0e0a13cdcc068e58c9ff9106cf40d17ab1b;p=thirdparty%2Fsystemd.git resolved: add concept of delegating lookups below certain domains to specific DNS servers This permits configuration of additional "delegates" which ensure that lookups for certain DNS zones are routed to specific sets of DNS servers, in addition to the routes we create for each network interface. For now, this allows only static configuration, but eventually we should open this up to IPC. Fixes: #5573 #14159 #20485 #21260 #24532 #32022 (Fixes #32022, because now redundant) --- diff --git a/man/org.freedesktop.resolve1.xml b/man/org.freedesktop.resolve1.xml index 324b6888537..7d5e997b833 100644 --- a/man/org.freedesktop.resolve1.xml +++ b/man/org.freedesktop.resolve1.xml @@ -115,6 +115,9 @@ node /org/freedesktop/resolve1 { ResetStatistics(); FlushCaches(); ResetServerFeatures(); + GetDelegate(in s id, + out o path); + ListDelegates(out a(so) delegates); properties: readonly s LLMNRHostname = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("false") @@ -202,6 +205,10 @@ node /org/freedesktop/resolve1 { + + + + @@ -423,13 +430,13 @@ node /org/freedesktop/resolve1 { The RevertLink() method may be used to revert all per-link settings described above to the defaults. - The FlushCaches() flushes all resource record caches maintained by the + The FlushCaches() method flushes all resource record caches maintained by the resolver, and ensures that any subsequent lookups re-request their responses from their sources. - The ResetServerFeatures() flushes any feature information learned about - remote DNS servers. This ensures that subsequent lookups will be initially attempted at the highest DNS - protocol feature level again, possibly requiring a (potentially slow) downgrade cycle to recognize the - supported feature level again. + The ResetServerFeatures() method flushes any feature information learned + about remote DNS servers. This ensures that subsequent lookups will be initially attempted at the + highest DNS protocol feature level again, possibly requiring a (potentially slow) downgrade cycle to + recognize the supported feature level again. The RegisterService() method may be used to register a DNS-SD service on the host. This functionality is closely related to the functionality provided by @@ -447,6 +454,12 @@ node /org/freedesktop/resolve1 { RegisterService() and deletes a DNS-SD service previously created via IPC again. + The GetDelegate() method returns the D-Bus object path for the specified DNS + delegate ID. + + The ListDelegates() method returns a list of the IDs and D-Bus object paths + of the currently configured DNS delegates. + The Flags Parameter @@ -936,6 +949,15 @@ $ gdbus introspect --system \ + + History + + The Manager Object + + GetDelegate() and ListDelegates() were added in version 258. + + + See Also diff --git a/src/libsystemd/sd-bus/bus-common-errors.c b/src/libsystemd/sd-bus/bus-common-errors.c index c911a64ca4f..1075c29ed64 100644 --- a/src/libsystemd/sd-bus/bus-common-errors.c +++ b/src/libsystemd/sd-bus/bus-common-errors.c @@ -86,6 +86,7 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = { SD_BUS_ERROR_MAP(BUS_ERROR_STUB_LOOP, ELOOP), SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_DNSSD_SERVICE, ENOENT), SD_BUS_ERROR_MAP(BUS_ERROR_DNSSD_SERVICE_EXISTS, EEXIST), + SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_DELEGATE, ENXIO), SD_BUS_ERROR_MAP(BUS_ERROR_DNS_FORMERR, EBADMSG), SD_BUS_ERROR_MAP(BUS_ERROR_DNS_SERVFAIL, EHOSTDOWN), diff --git a/src/libsystemd/sd-bus/bus-common-errors.h b/src/libsystemd/sd-bus/bus-common-errors.h index e69f6194dd5..ad6b45ae397 100644 --- a/src/libsystemd/sd-bus/bus-common-errors.h +++ b/src/libsystemd/sd-bus/bus-common-errors.h @@ -84,6 +84,7 @@ #define BUS_ERROR_STUB_LOOP "org.freedesktop.resolve1.StubLoop" #define BUS_ERROR_NO_SUCH_DNSSD_SERVICE "org.freedesktop.resolve1.NoSuchDnssdService" #define BUS_ERROR_DNSSD_SERVICE_EXISTS "org.freedesktop.resolve1.DnssdServiceExists" +#define BUS_ERROR_NO_SUCH_DELEGATE "org.freedesktop.resolve1.NoSuchDelegate" #define _BUS_ERROR_DNS "org.freedesktop.resolve1.DnsError." #define BUS_ERROR_DNS_FORMERR _BUS_ERROR_DNS "FORMERR" diff --git a/src/resolve/meson.build b/src/resolve/meson.build index a814551a9b9..b47dfd27249 100644 --- a/src/resolve/meson.build +++ b/src/resolve/meson.build @@ -13,6 +13,8 @@ systemd_resolved_extract_sources = files( 'resolved-conf.c', 'resolved-dns-answer.c', 'resolved-dns-cache.c', + 'resolved-dns-delegate.c', + 'resolved-dns-delegate-bus.c', 'resolved-dns-dnssec.c', 'resolved-dns-packet.c', 'resolved-dns-query.c', @@ -90,8 +92,14 @@ resolved_dnssd_gperf_c = custom_target( output : 'resolved-dnssd-gperf.c', command : [gperf, '@INPUT@', '--output-file', '@OUTPUT@']) -generated_sources += [dns_type_from_name_h, dns_type_to_name_h, resolved_gperf_c, resolved_dnssd_gperf_c] -systemd_resolved_extract_sources += [dns_type_from_name_h, dns_type_to_name_h, resolved_gperf_c, resolved_dnssd_gperf_c] +resolved_dns_delegate_gperf_c = custom_target( + 'resolved-dns-delegate-gperf.c', + input : 'resolved-dns-delegate-gperf.gperf', + output : 'resolved-dns-delegate-gperf.c', + command : [gperf, '@INPUT@', '--output-file', '@OUTPUT@']) + +generated_sources += [dns_type_from_name_h, dns_type_to_name_h, resolved_gperf_c, resolved_dnssd_gperf_c, resolved_dns_delegate_gperf_c] +systemd_resolved_extract_sources += [dns_type_from_name_h, dns_type_to_name_h, resolved_gperf_c, resolved_dnssd_gperf_c, resolved_dns_delegate_gperf_c] if conf.get('ENABLE_DNS_OVER_TLS') == 1 systemd_resolved_extract_sources += files( diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c index e9b47488e75..be927e07060 100644 --- a/src/resolve/resolved-bus.c +++ b/src/resolve/resolved-bus.c @@ -16,6 +16,8 @@ #include "resolved-bus.h" #include "resolved-def.h" #include "resolved-dns-answer.h" +#include "resolved-dns-delegate.h" +#include "resolved-dns-delegate-bus.h" #include "resolved-dns-dnssec.h" #include "resolved-dns-packet.h" #include "resolved-dns-query.h" @@ -2068,6 +2070,64 @@ static int bus_method_unregister_service(sd_bus_message *message, void *userdata return call_dnssd_method(m, message, bus_dnssd_method_unregister, error); } +static int bus_method_get_delegate(sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_free_ char *p = NULL; + Manager *m = ASSERT_PTR(userdata); + int r; + + assert(message); + + const char *id; + r = sd_bus_message_read(message, "s", &id); + if (r < 0) + return r; + + DnsDelegate *d = hashmap_get(m->delegates, id); + if (!d) + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_DELEGATE, "Delegate '%s' not known", id); + + p = dns_delegate_bus_path(d); + if (!p) + return -ENOMEM; + + return sd_bus_reply_method_return(message, "o", p); +} + +static int bus_method_list_delegates(sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + Manager *m = ASSERT_PTR(userdata); + int r; + + assert(message); + + r = sd_bus_message_new_method_return(message, &reply); + if (r < 0) + return r; + + r = sd_bus_message_open_container(reply, 'a', "(so)"); + if (r < 0) + return r; + + DnsDelegate *d; + HASHMAP_FOREACH(d, m->delegates) { + _cleanup_free_ char *p = NULL; + + p = dns_delegate_bus_path(d); + if (!p) + return -ENOMEM; + + r = sd_bus_message_append(reply, "(so)", d->id, p); + if (r < 0) + return r; + } + + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; + + return sd_bus_message_send(reply); +} + static const sd_bus_vtable resolve_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY("LLMNRHostname", "s", NULL, offsetof(Manager, llmnr_hostname), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), @@ -2206,6 +2266,16 @@ static const sd_bus_vtable resolve_vtable[] = { SD_BUS_NO_RESULT, bus_method_reset_server_features, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("GetDelegate", + SD_BUS_ARGS("s", id), + SD_BUS_RESULT("o", path), + bus_method_get_delegate, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("ListDelegates", + SD_BUS_NO_ARGS, + SD_BUS_RESULT("a(so)", delegates), + bus_method_list_delegates, + SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_VTABLE_END, }; @@ -2215,7 +2285,8 @@ const BusObjectImplementation manager_object = { "org.freedesktop.resolve1.Manager", .vtables = BUS_VTABLES(resolve_vtable), .children = BUS_IMPLEMENTATIONS(&link_object, - &dnssd_object), + &dnssd_object, + &dns_delegate_object), }; static int match_prepare_for_sleep(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) { diff --git a/src/resolve/resolved-dns-delegate-bus.c b/src/resolve/resolved-dns-delegate-bus.c new file mode 100644 index 00000000000..60134b504ce --- /dev/null +++ b/src/resolve/resolved-dns-delegate-bus.c @@ -0,0 +1,156 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "bus-get-properties.h" +#include "resolved-bus.h" +#include "resolved-dns-delegate.h" +#include "resolved-dns-delegate-bus.h" +#include "resolved-dns-search-domain.h" +#include "resolved-dns-server.h" +#include "resolved-manager.h" +#include "strv.h" + +static int property_get_dns( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + DnsDelegate *d = ASSERT_PTR(userdata); + int r; + + assert(reply); + + r = sd_bus_message_open_container(reply, 'a', "(iiayqs)"); + if (r < 0) + return r; + + LIST_FOREACH(servers, s, d->dns_servers) { + r = bus_dns_server_append(reply, s, /* with_ifindex= */ true, /* extended= */ true); + if (r < 0) + return r; + } + + return sd_bus_message_close_container(reply); +} + +static int property_get_current_dns_server( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + DnsDelegate *d = ASSERT_PTR(userdata); + + assert(reply); + + return bus_dns_server_append(reply, d->current_dns_server, /* with_ifindex= */ true, /* extended= */ true); +} + +static int property_get_domains( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + DnsDelegate *delegate = ASSERT_PTR(userdata); + int r; + + assert(reply); + + r = sd_bus_message_open_container(reply, 'a', "(sb)"); + if (r < 0) + return r; + + LIST_FOREACH(domains, d, delegate->search_domains) { + r = sd_bus_message_append(reply, "(sb)", d->name, d->route_only); + if (r < 0) + return r; + } + + return sd_bus_message_close_container(reply); +} + +static int dns_delegate_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) { + Manager *m = ASSERT_PTR(userdata); + + assert(bus); + assert(path); + assert(interface); + assert(found); + + _cleanup_free_ char *e = NULL; + if (sd_bus_path_decode(path, "/org/freedesktop/resolve1/dns_delegate", &e) <= 0) + return 0; + + DnsDelegate *d = hashmap_get(m->delegates, e); + if (!d) + return 0; + + *found = d; + return 1; +} + +char* dns_delegate_bus_path(const DnsDelegate *d) { + char *p; + + assert(d); + + if (sd_bus_path_encode("/org/freedesktop/resolve1/dns_delegate", d->id, &p) < 0) + return NULL; + + return p; +} + +static int dns_delegate_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) { + Manager *m = ASSERT_PTR(userdata); + int r; + + assert(bus); + assert(path); + assert(nodes); + + _cleanup_strv_free_ char **l = NULL; + DnsDelegate *d; + HASHMAP_FOREACH(d, m->delegates) { + _cleanup_free_ char *p = NULL; + + p = dns_delegate_bus_path(d); + if (!p) + return -ENOMEM; + + r = strv_consume(&l, TAKE_PTR(p)); + if (r < 0) + return r; + } + + *nodes = TAKE_PTR(l); + + return 1; +} + +static const sd_bus_vtable dns_delegate_vtable[] = { + SD_BUS_VTABLE_START(0), + + SD_BUS_PROPERTY("DNS", "a(iiayqs)", property_get_dns, 0, 0), + SD_BUS_PROPERTY("CurrentDNSServer", "(iiayqs)", property_get_current_dns_server, 0, 0), + SD_BUS_PROPERTY("Domains", "a(sb)", property_get_domains, 0, 0), + SD_BUS_PROPERTY("DefaultRoute", "b", bus_property_get_tristate, offsetof(DnsDelegate, default_route), 0), + + SD_BUS_VTABLE_END +}; + +const BusObjectImplementation dns_delegate_object = { + "/org/freedesktop/resolve1/dns_delegate", + "org.freedesktop.resolve1.DnsDelegate", + .fallback_vtables = BUS_FALLBACK_VTABLES({dns_delegate_vtable, dns_delegate_object_find}), + .node_enumerator = dns_delegate_node_enumerator, +}; diff --git a/src/resolve/resolved-dns-delegate-bus.h b/src/resolve/resolved-dns-delegate-bus.h new file mode 100644 index 00000000000..7acdd5a983e --- /dev/null +++ b/src/resolve/resolved-dns-delegate-bus.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +typedef struct BusObjectImplementation BusObjectImplementation; +typedef struct DnsDelegate DnsDelegate; + +extern const BusObjectImplementation dns_delegate_object; + +char* dns_delegate_bus_path(const DnsDelegate *d); diff --git a/src/resolve/resolved-dns-delegate-gperf.gperf b/src/resolve/resolved-dns-delegate-gperf.gperf new file mode 100644 index 00000000000..3040770f3ad --- /dev/null +++ b/src/resolve/resolved-dns-delegate-gperf.gperf @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +%{ +#if __GNUC__ >= 15 +_Pragma("GCC diagnostic ignored \"-Wzero-as-null-pointer-constant\"") +#endif +#include +#include "conf-parser.h" +#include "resolved-dns-delegate.h" +%} +struct ConfigPerfItem; +%null_strings +%language=ANSI-C +%define slot-name section_and_lvalue +%define hash-function-name resolved_dns_delegate_gperf_hash +%define lookup-function-name resolved_dns_delegate_gperf_lookup +%readonly-tables +%omit-struct-type +%struct-type +%includes +%% +Delegate.DNS, config_parse_delegate_dns_servers, 0, 0 +Delegate.Domains, config_parse_delegate_domains, 0, 0 +Delegate.DefaultRoute, config_parse_tristate, 0, offsetof(DnsDelegate, default_route) diff --git a/src/resolve/resolved-dns-delegate.c b/src/resolve/resolved-dns-delegate.c new file mode 100644 index 00000000000..6a094ce68e6 --- /dev/null +++ b/src/resolve/resolved-dns-delegate.c @@ -0,0 +1,366 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "conf-files.h" +#include "dns-domain.h" +#include "in-addr-util.h" +#include "path-util.h" +#include "resolved-dns-delegate.h" +#include "resolved-dns-scope.h" +#include "resolved-dns-search-domain.h" +#include "resolved-dns-server.h" +#include "resolved-manager.h" +#include "socket-netlink.h" +#include "strv.h" + +#define DNS_DELEGATES_MAX 4096U +#define DNS_DELEGATE_SEARCH_DIRS ((const char* const*) CONF_PATHS_STRV("systemd/dns-delegate.d")) + +DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR( + dns_delegate_hash_ops, + char, + string_hash_func, + string_compare_func, + DnsDelegate, + dns_delegate_free); + +int dns_delegate_new(Manager *m, const char *id, DnsDelegate **ret) { + int r; + + assert(m); + assert(id); + + if (hashmap_size(m->delegates) >= DNS_DELEGATES_MAX) + return -E2BIG; + + _cleanup_free_ char *id_copy = strdup(id); + if (!id_copy) + return -ENOMEM; + + _cleanup_(dns_delegate_freep) DnsDelegate *d = new(DnsDelegate, 1); + if (!d) + return -ENOMEM; + + *d = (DnsDelegate) { + .id = TAKE_PTR(id_copy), + .default_route = -1, + }; + + r = dns_scope_new( + m, + &d->scope, + DNS_SCOPE_DELEGATE, + /* link= */ NULL, + d, + DNS_PROTOCOL_DNS, + AF_UNSPEC); + if (r < 0) + return r; + + r = hashmap_ensure_put(&m->delegates, &dns_delegate_hash_ops, d->id, d); + if (r < 0) + return r; + + d->manager = m; + + log_debug("New delegate '%s'.", id); + + if (ret) + *ret = d; + + TAKE_PTR(d); + return 0; +} + +DnsDelegate *dns_delegate_free(DnsDelegate *d) { + if (!d) + return NULL; + + Manager *m = d->manager; + + log_debug("Removing delegate '%s'.", d->id); + + dns_server_unlink_all(d->dns_servers); + dns_search_domain_unlink_all(d->search_domains); + + dns_scope_free(d->scope); + + if (m) + hashmap_remove(m->delegates, d->id); + + free(d->id); + + return mfree(d); +} + +DnsServer* dns_delegate_set_dns_server(DnsDelegate *d, DnsServer *s) { + assert(d); + + if (d->current_dns_server == s) + return s; + + if (s) + log_debug("Switching delegate '%s' to DNS server %s.", d->id, strna(dns_server_string_full(s))); + + dns_server_unref(d->current_dns_server); + d->current_dns_server = dns_server_ref(s); + + /* Skip flushing the cache if server stale feature is enabled. */ + if (d->manager->stale_retention_usec == 0) + dns_cache_flush(&d->scope->cache); + + return s; +} + +DnsServer *dns_delegate_get_dns_server(DnsDelegate *d) { + assert(d); + + if (!d->current_dns_server) + dns_delegate_set_dns_server(d, d->dns_servers); + + return d->current_dns_server; +} + +void dns_delegate_next_dns_server(DnsDelegate *d, DnsServer *if_current) { + assert(d); + + /* If we have issues with a DNS server, let's switch to the next one (in a round robin scheme). If + * non-NULL if_current points to the DNS server that was selected at the beginning of whatever bigger + * operation we are currently executing, and hence if we already switched away from it we suppress + * switching again, so that each operation only results in a single switch, not multiple. */ + + /* If the current server of the transaction is specified, and we already are at a different one, + * don't do anything */ + if (if_current && d->current_dns_server != if_current) + return; + + /* If currently have no DNS server, then don't do anything, we'll pick it lazily the next time a DNS + * server is needed. */ + if (!d->current_dns_server) + return; + + /* Change to the next one, but make sure to follow the linked list only if this server is actually + * still linked. */ + if (d->current_dns_server->linked && d->current_dns_server->servers_next) { + dns_delegate_set_dns_server(d, d->current_dns_server->servers_next); + return; + } + + /* Pick the first one again, after we reached the end */ + dns_delegate_set_dns_server(d, d->dns_servers); +} + +static int dns_delegate_load(Manager *m, const char *path) { + int r; + + assert(m); + assert(path); + + _cleanup_free_ char *fn = NULL; + r = path_extract_filename(path, &fn); + if (r < 0) + return log_error_errno(r, "Failed to extract filename from path '%s': %m", path); + + const char *e = endswith(fn, ".dns-delegate"); + if (!e) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "DNS delegate file name does not end in .dns-delegate, refusing: %s", fn); + + _cleanup_free_ char *id = strndup(fn, e - fn); + if (!string_is_safe(id)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "DNS delegate file name contains weird characters, refusing: %s", fn); + + _cleanup_free_ char *dropin_dirname = strjoin(id, ".dns-delegate.d"); + if (!dropin_dirname) + return log_oom(); + + _cleanup_(dns_delegate_freep) DnsDelegate *d = NULL; + r = dns_delegate_new(m, id, &d); + if (r < 0) + return log_error_errno(r, "Failed to allocate delegate '%s': %m", id); + + r = config_parse_many( + STRV_MAKE_CONST(path), + DNS_DELEGATE_SEARCH_DIRS, + dropin_dirname, + /* root= */ NULL, + "Delegate\0", + config_item_perf_lookup, + resolved_dns_delegate_gperf_lookup, + /* flags= */ 0, + d, + /* ret_stats_by_path= */ NULL, + /* ret_drop_in_files= */ NULL); + if (r < 0) + return r; + + log_info("Successfully loaded delegate '%s'.", d->id); + + TAKE_PTR(d); + return 0; +} + +int manager_load_delegates(Manager *m) { + _cleanup_strv_free_ char **files = NULL; + int r; + + assert(m); + + r = conf_files_list_strv(&files, ".dns-delegate", /* root= */ NULL, /* flags= */ 0, DNS_DELEGATE_SEARCH_DIRS); + if (r < 0) + return log_error_errno(r, "Failed to enumerate .dns-delegate files: %m"); + + STRV_FOREACH(f, files) + (void) dns_delegate_load(m, *f); + + return 0; +} + +int config_parse_delegate_dns_servers( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + DnsDelegate *d = ASSERT_PTR(userdata); + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + + /* Empty assignment means clear the list */ + if (isempty(rvalue)) { + dns_server_unlink_all(d->dns_servers); + return 0; + } + + /* Otherwise, add to the list */ + for (;;) { + _cleanup_free_ char *word = NULL; + r = extract_first_word(&rvalue, &word, NULL, 0); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to parse DNS server string '%s', ignoring.", rvalue); + return 0; + } + if (r == 0) + break; + + _cleanup_free_ char *server_name = NULL; + union in_addr_union address; + int family, ifindex = 0; + uint16_t port; + r = in_addr_port_ifindex_name_from_string_auto(word, &family, &address, &port, &ifindex, &server_name); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to parse DNS server string '%s', ignoring.", word); + continue; + } + + /* Silently filter out 0.0.0.0, 127.0.0.53, 127.0.0.54 (our own stub DNS listener) */ + if (!dns_server_address_valid(family, &address)) + continue; + + /* By default, the port number is determined with the transaction feature level. + * See dns_transaction_port() and dns_server_port(). */ + if (IN_SET(port, 53, 853)) + port = 0; + + /* Filter out duplicates */ + DnsServer *s = dns_server_find(d->dns_servers, family, &address, port, ifindex, server_name); + if (s) { + /* Drop the marker. This is used to find the servers that ceased to exist, see + * manager_mark_dns_servers() and manager_flush_marked_dns_servers(). */ + dns_server_move_back_and_unmark(s); + return 0; + } + + r = dns_server_new( + d->manager, + /* ret= */ NULL, + DNS_SERVER_DELEGATE, + /* link= */ NULL, + d, + family, + &address, + port, + ifindex, + server_name, + RESOLVE_CONFIG_SOURCE_FILE); + if (r < 0) + return log_error_errno(r, "Failed to add DNS server: %m"); + } + + return 0; +} + +int config_parse_delegate_domains( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + DnsDelegate *d = ASSERT_PTR(userdata); + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + + /* Empty assignment means clear the list */ + if (isempty(rvalue)) { + dns_search_domain_unlink_all(d->search_domains); + return 0; + } + + /* Otherwise, add to the list */ + for (;;) { + _cleanup_free_ char *word = NULL; + r = extract_first_word(&rvalue, &word, NULL, 0); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to parse search domains string '%s', ignoring.", rvalue); + return 0; + } + if (r == 0) + break; + + const char *name = word; + + bool route_only = name[0] == '~'; + if (route_only) + name++; + + if (dns_name_is_root(name) || streq(name, "*")) { + route_only = true; + name = "."; + } + + DnsSearchDomain *domain; + r = dns_search_domain_find(d->search_domains, name, &domain); + if (r < 0) + return log_error_errno(r, "Failed to find search domain: %m"); + if (r > 0) + dns_search_domain_move_back_and_unmark(domain); + else { + r = dns_search_domain_new(d->manager, &domain, DNS_SEARCH_DOMAIN_DELEGATE, /* link= */ NULL, d, name); + if (r < 0) + return r; + } + + domain->route_only = route_only; + } + + return 0; +} diff --git a/src/resolve/resolved-dns-delegate.h b/src/resolve/resolved-dns-delegate.h new file mode 100644 index 00000000000..3ce3c1e172b --- /dev/null +++ b/src/resolve/resolved-dns-delegate.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include "conf-parser.h" +#include "list.h" + +typedef struct DnsDelegate DnsDelegate; +typedef struct DnsScope DnsScope; +typedef struct DnsSearchDomain DnsSearchDomain; +typedef struct DnsServer DnsServer; +typedef struct Manager Manager; + +#define DELEGATE_SEARCH_DOMAINS_MAX 256 +#define DELEGATE_DNS_SERVERS_MAX 256 + +/* A DnsDelegate object is used to manage additional, explicitly configured unicast DNS lookup scopes, + * independent from any network link and from the global scope. */ + +struct DnsDelegate { + Manager *manager; + char *id; + + LIST_HEAD(DnsServer, dns_servers); + unsigned n_dns_servers; + DnsServer *current_dns_server; + + LIST_HEAD(DnsSearchDomain, search_domains); + unsigned n_search_domains; + + int default_route; + + DnsScope *scope; + + LIST_FIELDS(DnsDelegate, delegates); +}; + +int dns_delegate_new(Manager *m, const char *id, DnsDelegate **ret); +DnsDelegate *dns_delegate_free(DnsDelegate *d); + +DEFINE_TRIVIAL_CLEANUP_FUNC(DnsDelegate*, dns_delegate_free); + +DnsServer* dns_delegate_set_dns_server(DnsDelegate *d, DnsServer *s); +DnsServer *dns_delegate_get_dns_server(DnsDelegate *d); +void dns_delegate_next_dns_server(DnsDelegate *d, DnsServer *if_current); + +int manager_load_delegates(Manager *m); + +const struct ConfigPerfItem* resolved_dns_delegate_gperf_lookup(const char *key, GPERF_LEN_TYPE length); + +CONFIG_PARSER_PROTOTYPE(config_parse_delegate_dns_servers); +CONFIG_PARSER_PROTOTYPE(config_parse_delegate_domains); diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index d4bfbccdc3b..4525f253de7 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -12,6 +12,7 @@ #include "missing_network.h" #include "random-util.h" #include "resolved-dns-answer.h" +#include "resolved-dns-delegate.h" #include "resolved-dns-packet.h" #include "resolved-dns-query.h" #include "resolved-dns-question.h" @@ -44,6 +45,7 @@ int dns_scope_new( DnsScope **ret, DnsScopeOrigin origin, Link *link, + DnsDelegate *delegate, DnsProtocol protocol, int family) { @@ -55,6 +57,7 @@ int dns_scope_new( assert(origin < _DNS_SCOPE_ORIGIN_MAX); assert(!!link == (origin == DNS_SCOPE_LINK)); + assert(!!delegate == (origin == DNS_SCOPE_DELEGATE)); s = new(DnsScope, 1); if (!s) @@ -63,6 +66,7 @@ int dns_scope_new( *s = (DnsScope) { .manager = m, .link = link, + .delegate = delegate, .origin = origin, .protocol = protocol, .family = family, @@ -97,11 +101,12 @@ int dns_scope_new( dns_scope_llmnr_membership(s, true); dns_scope_mdns_membership(s, true); - log_debug("New scope on link %s, protocol %s, family %s, origin %s", + log_debug("New scope on link %s, protocol %s, family %s, origin %s, delegate %s", link ? link->ifname : "*", dns_protocol_to_string(protocol), family == AF_UNSPEC ? "*" : af_to_name(family), - dns_scope_origin_to_string(origin)); + dns_scope_origin_to_string(origin), + s->delegate ? s->delegate->id : "n/a"); *ret = s; return 0; @@ -129,11 +134,12 @@ DnsScope* dns_scope_free(DnsScope *s) { if (!s) return NULL; - log_debug("Removing scope on link %s, protocol %s, family %s, origin %s", + log_debug("Removing scope on link %s, protocol %s, family %s, origin %s, delegate %s", s->link ? s->link->ifname : "*", dns_protocol_to_string(s->protocol), s->family == AF_UNSPEC ? "*" : af_to_name(s->family), - dns_scope_origin_to_string(s->origin)); + dns_scope_origin_to_string(s->origin), + s->delegate ? s->delegate->id : "n/a"); dns_scope_llmnr_membership(s, false); dns_scope_mdns_membership(s, false); @@ -164,8 +170,11 @@ DnsServer *dns_scope_get_dns_server(DnsScope *s) { if (s->protocol != DNS_PROTOCOL_DNS) return NULL; - if (s->link) + if (s->link) { + assert(!s->delegate); return link_get_dns_server(s->link); + } else if (s->delegate) + return dns_delegate_get_dns_server(s->delegate); else return manager_get_dns_server(s->manager); } @@ -176,8 +185,11 @@ unsigned dns_scope_get_n_dns_servers(DnsScope *s) { if (s->protocol != DNS_PROTOCOL_DNS) return 0; - if (s->link) + if (s->link) { + assert(!s->delegate); return s->link->n_dns_servers; + } else if (s->delegate) + return s->delegate->n_dns_servers; else return s->manager->n_dns_servers; } @@ -193,6 +205,8 @@ void dns_scope_next_dns_server(DnsScope *s, DnsServer *if_current) { if (s->link) link_next_dns_server(s->link, if_current); + else if (s->delegate) + dns_delegate_next_dns_server(s->delegate, if_current); else manager_next_dns_server(s->manager, if_current); } @@ -300,6 +314,7 @@ static int dns_scope_emit_one(DnsScope *s, int fd, int family, DnsPacket *p) { if (fd < 0) return fd; + assert(s->link); r = manager_send(s->manager, fd, s->link->ifindex, family, &addr, LLMNR_PORT, NULL, p); if (r < 0) return r; @@ -331,6 +346,7 @@ static int dns_scope_emit_one(DnsScope *s, int fd, int family, DnsPacket *p) { if (fd < 0) return fd; + assert(s->link); r = manager_send(s->manager, fd, s->link->ifindex, family, &addr, p->destination_port ?: MDNS_PORT, NULL, p); if (r < 0) return r; @@ -1403,6 +1419,12 @@ void dns_scope_dump(DnsScope *s, FILE *f) { fputs(" origin=", f); fputs(dns_scope_origin_to_string(s->origin), f); + + if (s->delegate) { + fputs(" id=", f); + fputs(s->delegate->id, f); + } + fputs("]\n", f); if (!dns_zone_is_empty(&s->zone)) { @@ -1424,6 +1446,8 @@ DnsSearchDomain *dns_scope_get_search_domains(DnsScope *s) { if (s->link) return s->link->search_domains; + if (s->delegate) + return s->delegate->search_domains; return s->manager->search_domains; } @@ -1709,6 +1733,8 @@ static bool dns_scope_has_route_only_domains(DnsScope *scope) { if (scope->link) first = scope->link->search_domains; + else if (scope->delegate) + first = scope->delegate->search_domains; else first = scope->manager->search_domains; @@ -1734,18 +1760,27 @@ bool dns_scope_is_default_route(DnsScope *scope) { if (scope->protocol != DNS_PROTOCOL_DNS) return false; - /* The global DNS scope is always suitable as default route */ - if (!scope->link) - return true; + if (scope->link) { + + /* Honour whatever is explicitly configured. This is really the best approach, and trumps any + * automatic logic. */ + if (scope->link->default_route >= 0) + return scope->link->default_route; + + /* Otherwise check if we have any route-only domains, as a sensible heuristic: if so, let's not + * volunteer as default route. */ + return !dns_scope_has_route_only_domains(scope); + + } else if (scope->delegate) { - /* Honour whatever is explicitly configured. This is really the best approach, and trumps any - * automatic logic. */ - if (scope->link->default_route >= 0) - return scope->link->default_route; + if (scope->delegate->default_route >= 0) + return scope->delegate->default_route; - /* Otherwise check if we have any route-only domains, as a sensible heuristic: if so, let's not - * volunteer as default route. */ - return !dns_scope_has_route_only_domains(scope); + /* Delegates are by default not used as default route */ + return false; + } else + /* The global DNS scope is always suitable as default route */ + return true; } int dns_scope_dump_cache_to_json(DnsScope *scope, sd_json_variant **ret) { @@ -1831,8 +1866,9 @@ int dns_question_types_suitable_for_protocol(DnsQuestion *q, DnsProtocol protoco } static const char* const dns_scope_origin_table[_DNS_SCOPE_ORIGIN_MAX] = { - [DNS_SCOPE_GLOBAL] = "global", - [DNS_SCOPE_LINK] = "link", + [DNS_SCOPE_GLOBAL] = "global", + [DNS_SCOPE_LINK] = "link", + [DNS_SCOPE_DELEGATE] = "delegate", }; DEFINE_STRING_TABLE_LOOKUP(dns_scope_origin, DnsScopeOrigin); diff --git a/src/resolve/resolved-dns-scope.h b/src/resolve/resolved-dns-scope.h index 54f0b7b7a33..872457ffc20 100644 --- a/src/resolve/resolved-dns-scope.h +++ b/src/resolve/resolved-dns-scope.h @@ -12,6 +12,7 @@ #include "resolved-dns-zone.h" #include "socket-util.h" +typedef struct DnsDelegate DnsDelegate; typedef struct DnsQuery DnsQuery; typedef struct DnsQueryCandidate DnsQueryCandidate; typedef struct DnsQuestion DnsQuestion; @@ -34,6 +35,7 @@ typedef enum DnsScopeMatch { typedef enum DnsScopeOrigin { DNS_SCOPE_GLOBAL, DNS_SCOPE_LINK, + DNS_SCOPE_DELEGATE, _DNS_SCOPE_ORIGIN_MAX, _DNS_SCOPE_ORIGIN_INVALID = -EINVAL, } DnsScopeOrigin; @@ -51,6 +53,7 @@ struct DnsScope { DnsOverTlsMode dns_over_tls_mode; Link *link; + DnsDelegate *delegate; DnsCache cache; DnsZone zone; @@ -83,7 +86,7 @@ struct DnsScope { bool announced; }; -int dns_scope_new(Manager *m, DnsScope **ret, DnsScopeOrigin origin, Link *link, DnsProtocol protocol, int family); +int dns_scope_new(Manager *m, DnsScope **ret, DnsScopeOrigin origin, Link *link, DnsDelegate *delegate, DnsProtocol protocol, int family); DnsScope* dns_scope_free(DnsScope *s); void dns_scope_packet_received(DnsScope *s, usec_t rtt); diff --git a/src/resolve/resolved-dns-search-domain.c b/src/resolve/resolved-dns-search-domain.c index 642d52c6ea3..63790ad1fc0 100644 --- a/src/resolve/resolved-dns-search-domain.c +++ b/src/resolve/resolved-dns-search-domain.c @@ -4,6 +4,7 @@ #include "alloc-util.h" #include "dns-domain.h" +#include "resolved-dns-delegate.h" #include "resolved-dns-search-domain.h" #include "resolved-link.h" #include "resolved-manager.h" @@ -12,7 +13,8 @@ int dns_search_domain_new( Manager *m, DnsSearchDomain **ret, DnsSearchDomainType type, - Link *l, + Link *link, + DnsDelegate *delegate, const char *name) { _cleanup_free_ char *normalized = NULL; @@ -20,15 +22,19 @@ int dns_search_domain_new( int r; assert(m); - assert((type == DNS_SEARCH_DOMAIN_LINK) == !!l); + assert((type == DNS_SEARCH_DOMAIN_LINK) == !!link); + assert((type == DNS_SEARCH_DOMAIN_DELEGATE) == !!delegate); assert(name); r = dns_name_normalize(name, 0, &normalized); if (r < 0) return r; - if (l) { - if (l->n_search_domains >= LINK_SEARCH_DOMAINS_MAX) + if (link) { + if (link->n_search_domains >= LINK_SEARCH_DOMAINS_MAX) + return -E2BIG; + } else if (delegate) { + if (delegate->n_search_domains >= DELEGATE_SEARCH_DOMAINS_MAX) return -E2BIG; } else { if (m->n_search_domains >= MANAGER_SEARCH_DOMAINS_MAX) @@ -49,9 +55,9 @@ int dns_search_domain_new( switch (type) { case DNS_SEARCH_DOMAIN_LINK: - d->link = l; - LIST_APPEND(domains, l->search_domains, d); - l->n_search_domains++; + d->link = link; + LIST_APPEND(domains, link->search_domains, d); + link->n_search_domains++; break; case DNS_SEARCH_DOMAIN_SYSTEM: @@ -59,6 +65,12 @@ int dns_search_domain_new( m->n_search_domains++; break; + case DNS_SEARCH_DOMAIN_DELEGATE: + d->delegate = delegate; + LIST_APPEND(domains, delegate->search_domains, d); + delegate->n_search_domains++; + break; + default: assert_not_reached(); } @@ -101,6 +113,13 @@ void dns_search_domain_unlink(DnsSearchDomain *d) { LIST_REMOVE(domains, d->manager->search_domains, d); d->manager->n_search_domains--; break; + + case DNS_SEARCH_DOMAIN_DELEGATE: + assert(d->delegate); + assert(d->delegate->n_search_domains > 0); + LIST_REMOVE(domains, d->delegate->search_domains, d); + d->delegate->n_search_domains--; + break; } d->linked = false; @@ -136,6 +155,13 @@ void dns_search_domain_move_back_and_unmark(DnsSearchDomain *d) { LIST_INSERT_AFTER(domains, d->manager->search_domains, tail, d); break; + case DNS_SEARCH_DOMAIN_DELEGATE: + assert(d->delegate); + tail = LIST_FIND_TAIL(domains, d); + LIST_REMOVE(domains, d->delegate->search_domains, d); + LIST_INSERT_AFTER(domains, d->delegate->search_domains, tail, d); + break; + default: assert_not_reached(); } diff --git a/src/resolve/resolved-dns-search-domain.h b/src/resolve/resolved-dns-search-domain.h index fbd9a4490f1..63bd357b831 100644 --- a/src/resolve/resolved-dns-search-domain.h +++ b/src/resolve/resolved-dns-search-domain.h @@ -7,6 +7,7 @@ #include "macro.h" #include "memory-util.h" +typedef struct DnsDelegate DnsDelegate; typedef struct DnsSearchDomain DnsSearchDomain; typedef struct Link Link; typedef struct Manager Manager; @@ -14,6 +15,7 @@ typedef struct Manager Manager; typedef enum DnsSearchDomainType { DNS_SEARCH_DOMAIN_SYSTEM, DNS_SEARCH_DOMAIN_LINK, + DNS_SEARCH_DOMAIN_DELEGATE, } DnsSearchDomainType; struct DnsSearchDomain { @@ -23,6 +25,7 @@ struct DnsSearchDomain { DnsSearchDomainType type; Link *link; + DnsDelegate *delegate; char *name; @@ -38,6 +41,7 @@ int dns_search_domain_new( DnsSearchDomain **ret, DnsSearchDomainType type, Link *link, + DnsDelegate *delegate, const char *name); DnsSearchDomain* dns_search_domain_ref(DnsSearchDomain *d); diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c index 5996d9bcc6a..7845dcfd217 100644 --- a/src/resolve/resolved-dns-server.c +++ b/src/resolve/resolved-dns-server.c @@ -11,6 +11,7 @@ #include "json-util.h" #include "resolved-bus.h" #include "resolved-dns-cache.h" +#include "resolved-dns-delegate.h" #include "resolved-dns-packet.h" #include "resolved-dns-scope.h" #include "resolved-dns-search-domain.h" @@ -36,7 +37,8 @@ int dns_server_new( Manager *m, DnsServer **ret, DnsServerType type, - Link *l, + Link *link, + DnsDelegate *delegate, int family, const union in_addr_union *in_addr, uint16_t port, @@ -48,14 +50,18 @@ int dns_server_new( DnsServer *s; assert(m); - assert((type == DNS_SERVER_LINK) == !!l); + assert((type == DNS_SERVER_LINK) == !!link); + assert((type == DNS_SERVER_DELEGATE) == !!delegate); assert(in_addr); if (!IN_SET(family, AF_INET, AF_INET6)) return -EAFNOSUPPORT; - if (l) { - if (l->n_dns_servers >= LINK_DNS_SERVERS_MAX) + if (link) { + if (link->n_dns_servers >= LINK_DNS_SERVERS_MAX) + return -E2BIG; + } else if (delegate) { + if (delegate->n_dns_servers >= DELEGATE_DNS_SERVERS_MAX) return -E2BIG; } else { if (m->n_dns_servers >= MANAGER_DNS_SERVERS_MAX) @@ -90,9 +96,9 @@ int dns_server_new( switch (type) { case DNS_SERVER_LINK: - s->link = l; - LIST_APPEND(servers, l->dns_servers, s); - l->n_dns_servers++; + s->link = link; + LIST_APPEND(servers, link->dns_servers, s); + link->n_dns_servers++; break; case DNS_SERVER_SYSTEM: @@ -105,16 +111,20 @@ int dns_server_new( m->n_dns_servers++; break; + case DNS_SERVER_DELEGATE: + s->delegate = delegate; + LIST_APPEND(servers, delegate->dns_servers, s); + delegate->n_dns_servers++; + break; default: assert_not_reached(); } s->linked = true; - /* A new DNS server that isn't fallback is added and the one - * we used so far was a fallback one? Then let's try to pick - * the new one */ - if (type != DNS_SERVER_FALLBACK && dns_server_is_fallback(m->current_dns_server)) + /* A new non-fallback DNS server is added and the one we used so far was a fallback one? Then + * let's try to pick the new one */ + if (type == DNS_SERVER_SYSTEM && dns_server_is_fallback(m->current_dns_server)) manager_set_dns_server(m, NULL); if (ret) @@ -171,6 +181,14 @@ void dns_server_unlink(DnsServer *s) { LIST_REMOVE(servers, s->manager->fallback_dns_servers, s); s->manager->n_dns_servers--; break; + + case DNS_SERVER_DELEGATE: + assert(s->delegate); + assert(s->delegate->n_dns_servers > 0); + LIST_REMOVE(servers, s->delegate->dns_servers, s); + s->delegate->n_dns_servers--; + break; + default: assert_not_reached(); } @@ -183,6 +201,9 @@ void dns_server_unlink(DnsServer *s) { if (s->manager->current_dns_server == s) manager_set_dns_server(s->manager, NULL); + if (s->delegate && s->delegate->current_dns_server == s) + dns_delegate_set_dns_server(s->delegate, NULL); + /* No need to keep a default stream around anymore */ dns_server_unref_stream(s); @@ -202,8 +223,8 @@ void dns_server_move_back_and_unmark(DnsServer *s) { if (!s->linked || !s->servers_next) return; - /* Move us to the end of the list, so that the order is - * strictly kept, if we are not at the end anyway. */ + /* Move us to the end of the list, so that the order is strictly kept, if we are not at the end + * anyway. */ switch (s->type) { @@ -226,6 +247,13 @@ void dns_server_move_back_and_unmark(DnsServer *s) { LIST_INSERT_AFTER(servers, s->manager->fallback_dns_servers, tail, s); break; + case DNS_SERVER_DELEGATE: + assert(s->delegate); + tail = LIST_FIND_TAIL(servers, s); + LIST_REMOVE(servers, s->delegate->dns_servers, s); + LIST_INSERT_AFTER(servers, s->delegate->dns_servers, tail, s); + break; + default: assert_not_reached(); } @@ -886,7 +914,18 @@ static int manager_add_dns_server_by_string(Manager *m, DnsServerType type, cons return 0; } - return dns_server_new(m, NULL, type, NULL, family, &address, port, ifindex, server_name, RESOLVE_CONFIG_SOURCE_FILE); + return dns_server_new( + m, + /* ret= */ NULL, + type, + /* link= */ NULL, + /* delegate= */ NULL, + family, + &address, + port, + ifindex, + server_name, + RESOLVE_CONFIG_SOURCE_FILE); } int manager_parse_dns_server_string_and_warn(Manager *m, DnsServerType type, const char *string) { @@ -931,7 +970,13 @@ static int manager_add_search_domain_by_string(Manager *m, const char *domain) { if (r > 0) dns_search_domain_move_back_and_unmark(d); else { - r = dns_search_domain_new(m, &d, DNS_SEARCH_DOMAIN_SYSTEM, NULL, domain); + r = dns_search_domain_new( + m, + &d, + DNS_SEARCH_DOMAIN_SYSTEM, + /* link= */ NULL, + /* delegate= */ NULL, + domain); if (r < 0) return r; } @@ -999,8 +1044,27 @@ DnsServer *manager_set_dns_server(Manager *m, DnsServer *s) { return s; } +static bool manager_search_default_route_dns_server(Manager *m) { + assert(m); + + LIST_FOREACH(scopes, scope, m->dns_scopes) { + /* Ignore the global scope, it's handled separately */ + if (scope->origin == DNS_SCOPE_GLOBAL) + continue; + + /* Scope has no DNS server? */ + if (dns_scope_get_n_dns_servers(scope) == 0) + continue; + + /* If this is suitable as default route, we found what we are looking for */ + if (dns_scope_is_default_route(scope)) + return true; + } + + return false; +} + DnsServer *manager_get_dns_server(Manager *m) { - Link *l; assert(m); /* Try to read updates resolv.conf */ @@ -1019,22 +1083,10 @@ DnsServer *manager_get_dns_server(Manager *m) { manager_set_dns_server(m, NULL); } - if (!m->current_dns_server) { - bool found = false; - - /* No DNS servers configured, let's see if there are - * any on any links. If not, we use the fallback - * servers */ - - HASHMAP_FOREACH(l, m->links) - if (l->dns_servers && l->default_route) { - found = true; - break; - } - - if (!found) - manager_set_dns_server(m, m->fallback_dns_servers); - } + /* If no DNS servers are configured, let's see if there are any on any links or delegates. If not, we + * use the fallback servers */ + if (!m->current_dns_server && !manager_search_default_route_dns_server(m)) + manager_set_dns_server(m, m->fallback_dns_servers); return m->current_dns_server; } @@ -1090,11 +1142,15 @@ void dns_server_flush_cache(DnsServer *s) { /* Flush the cache of the scope this server belongs to */ - current = s->link ? s->link->current_dns_server : s->manager->current_dns_server; + current = s->link ? s->link->current_dns_server : + s->delegate ? s->delegate->current_dns_server : + s->manager->current_dns_server; if (current != s) return; - scope = s->link ? s->link->unicast_scope : s->manager->unicast_scope; + scope = s->link ? s->link->unicast_scope : + s->delegate ? s->delegate->scope : + s->manager->unicast_scope; if (!scope) return; @@ -1199,10 +1255,14 @@ void dns_server_unref_stream(DnsServer *s) { DnsScope *dns_server_scope(DnsServer *s) { assert(s); + assert(s->linked); assert((s->type == DNS_SERVER_LINK) == !!s->link); + assert((s->type == DNS_SERVER_DELEGATE) == !!s->delegate); if (s->link) return s->link->unicast_scope; + if (s->delegate) + return s->delegate->scope; return s->manager->unicast_scope; } diff --git a/src/resolve/resolved-dns-server.h b/src/resolve/resolved-dns-server.h index bb3c0e109f5..bef352aa421 100644 --- a/src/resolve/resolved-dns-server.h +++ b/src/resolve/resolved-dns-server.h @@ -10,10 +10,11 @@ #include "resolved-dnstls.h" #include "time-util.h" +typedef struct DnsDelegate DnsDelegate; +typedef struct DnsPacket DnsPacket; typedef struct DnsScope DnsScope; typedef struct DnsServer DnsServer; typedef struct DnsStream DnsStream; -typedef struct DnsPacket DnsPacket; typedef struct Link Link; typedef struct Manager Manager; @@ -21,6 +22,7 @@ typedef enum DnsServerType { DNS_SERVER_SYSTEM, DNS_SERVER_FALLBACK, DNS_SERVER_LINK, + DNS_SERVER_DELEGATE, _DNS_SERVER_TYPE_MAX, _DNS_SERVER_TYPE_INVALID = -EINVAL, } DnsServerType; @@ -56,6 +58,7 @@ struct DnsServer { DnsServerType type; Link *link; + DnsDelegate *delegate; int family; union in_addr_union address; @@ -114,6 +117,7 @@ int dns_server_new( DnsServer **ret, DnsServerType type, Link *link, + DnsDelegate *delegate, int family, const union in_addr_union *address, uint16_t port, diff --git a/src/resolve/resolved-link-bus.c b/src/resolve/resolved-link-bus.c index 9c5f7a836ae..9e5371684aa 100644 --- a/src/resolve/resolved-link-bus.c +++ b/src/resolve/resolved-link-bus.c @@ -258,7 +258,7 @@ static int bus_link_method_set_dns_servers_internal(sd_bus_message *message, voi if (s) dns_server_move_back_and_unmark(s); else { - r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, dns[i]->family, &dns[i]->address, dns[i]->port, 0, dns[i]->server_name, RESOLVE_CONFIG_SOURCE_DBUS); + r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, /* delegate= */ NULL, dns[i]->family, &dns[i]->address, dns[i]->port, 0, dns[i]->server_name, RESOLVE_CONFIG_SOURCE_DBUS); if (r < 0) { dns_server_unlink_all(l->dns_servers); goto finalize; @@ -266,7 +266,6 @@ static int bus_link_method_set_dns_servers_internal(sd_bus_message *message, voi changed = true; } - } changed = dns_server_unlink_marked(l->dns_servers) || changed; @@ -387,7 +386,7 @@ int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_ if (r > 0) dns_search_domain_move_back_and_unmark(d); else { - r = dns_search_domain_new(l->manager, &d, DNS_SEARCH_DOMAIN_LINK, l, name); + r = dns_search_domain_new(l->manager, &d, DNS_SEARCH_DOMAIN_LINK, l, /* delegate= */ NULL, name); if (r < 0) goto clear; diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c index 432d7cf8b0f..55c8aa36cf6 100644 --- a/src/resolve/resolved-link.c +++ b/src/resolve/resolved-link.c @@ -139,7 +139,7 @@ void link_allocate_scopes(Link *l) { if (!l->unicast_scope) { dns_server_reset_features_all(l->dns_servers); - r = dns_scope_new(l->manager, &l->unicast_scope, DNS_SCOPE_LINK, l, DNS_PROTOCOL_DNS, AF_UNSPEC); + r = dns_scope_new(l->manager, &l->unicast_scope, DNS_SCOPE_LINK, l, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_UNSPEC); if (r < 0) log_link_warning_errno(l, r, "Failed to allocate DNS scope, ignoring: %m"); } @@ -149,7 +149,7 @@ void link_allocate_scopes(Link *l) { if (link_relevant(l, AF_INET, true) && link_get_llmnr_support(l) != RESOLVE_SUPPORT_NO) { if (!l->llmnr_ipv4_scope) { - r = dns_scope_new(l->manager, &l->llmnr_ipv4_scope, DNS_SCOPE_LINK, l, DNS_PROTOCOL_LLMNR, AF_INET); + r = dns_scope_new(l->manager, &l->llmnr_ipv4_scope, DNS_SCOPE_LINK, l, /* delegate= */ NULL, DNS_PROTOCOL_LLMNR, AF_INET); if (r < 0) log_link_warning_errno(l, r, "Failed to allocate LLMNR IPv4 scope, ignoring: %m"); } @@ -159,7 +159,7 @@ void link_allocate_scopes(Link *l) { if (link_relevant(l, AF_INET6, true) && link_get_llmnr_support(l) != RESOLVE_SUPPORT_NO) { if (!l->llmnr_ipv6_scope) { - r = dns_scope_new(l->manager, &l->llmnr_ipv6_scope, DNS_SCOPE_LINK, l, DNS_PROTOCOL_LLMNR, AF_INET6); + r = dns_scope_new(l->manager, &l->llmnr_ipv6_scope, DNS_SCOPE_LINK, l, /* delegate= */ NULL, DNS_PROTOCOL_LLMNR, AF_INET6); if (r < 0) log_link_warning_errno(l, r, "Failed to allocate LLMNR IPv6 scope, ignoring: %m"); } @@ -169,7 +169,7 @@ void link_allocate_scopes(Link *l) { if (link_relevant(l, AF_INET, true) && link_get_mdns_support(l) != RESOLVE_SUPPORT_NO) { if (!l->mdns_ipv4_scope) { - r = dns_scope_new(l->manager, &l->mdns_ipv4_scope, DNS_SCOPE_LINK, l, DNS_PROTOCOL_MDNS, AF_INET); + r = dns_scope_new(l->manager, &l->mdns_ipv4_scope, DNS_SCOPE_LINK, l, /* delegate= */ NULL, DNS_PROTOCOL_MDNS, AF_INET); if (r < 0) log_link_warning_errno(l, r, "Failed to allocate mDNS IPv4 scope, ignoring: %m"); } @@ -179,7 +179,7 @@ void link_allocate_scopes(Link *l) { if (link_relevant(l, AF_INET6, true) && link_get_mdns_support(l) != RESOLVE_SUPPORT_NO) { if (!l->mdns_ipv6_scope) { - r = dns_scope_new(l->manager, &l->mdns_ipv6_scope, DNS_SCOPE_LINK, l, DNS_PROTOCOL_MDNS, AF_INET6); + r = dns_scope_new(l->manager, &l->mdns_ipv6_scope, DNS_SCOPE_LINK, l, /* delegate= */ NULL, DNS_PROTOCOL_MDNS, AF_INET6); if (r < 0) log_link_warning_errno(l, r, "Failed to allocate mDNS IPv6 scope, ignoring: %m"); } @@ -279,7 +279,7 @@ static int link_update_dns_server_one(Link *l, const char *str) { return 0; } - return dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, family, &a, port, 0, name, RESOLVE_CONFIG_SOURCE_NETWORKD); + return dns_server_new(l->manager, /* ret= */ NULL, DNS_SERVER_LINK, l, /* delegate= */ NULL, family, &a, port, 0, name, RESOLVE_CONFIG_SOURCE_NETWORKD); } static int link_update_dns_servers(Link *l) { @@ -498,7 +498,7 @@ static int link_update_search_domain_one(Link *l, const char *name, bool route_o if (r > 0) dns_search_domain_move_back_and_unmark(d); else { - r = dns_search_domain_new(l->manager, &d, DNS_SEARCH_DOMAIN_LINK, l, name); + r = dns_search_domain_new(l->manager, &d, DNS_SEARCH_DOMAIN_LINK, l, /* delegate= */ NULL, name); if (r < 0) return r; } diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index 856161fa47c..f44fde2882a 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -34,6 +34,7 @@ #include "resolved-bus.h" #include "resolved-conf.h" #include "resolved-dns-answer.h" +#include "resolved-dns-delegate.h" #include "resolved-dns-packet.h" #include "resolved-dns-query.h" #include "resolved-dns-question.h" @@ -577,6 +578,10 @@ static int manager_sigusr1(sd_event_source *s, const struct signalfd_siginfo *si HASHMAP_FOREACH(l, m->links) LIST_FOREACH(servers, server, l->dns_servers) dns_server_dump(server, f); + DnsDelegate *delegate; + HASHMAP_FOREACH(delegate, m->delegates) + LIST_FOREACH(servers, server, delegate->dns_servers) + dns_server_dump(server, f); return memstream_dump(LOG_INFO, &ms); } @@ -655,6 +660,7 @@ static int manager_dispatch_reload_signal(sd_event_source *s, const struct signa m->dns_extra_stub_listeners = ordered_set_free(m->dns_extra_stub_listeners); dnssd_service_clear_on_reload(m->dnssd_services); m->unicast_scope = dns_scope_free(m->unicast_scope); + m->delegates = hashmap_free(m->delegates); dns_trust_anchor_flush(&m->trust_anchor); @@ -672,9 +678,11 @@ static int manager_dispatch_reload_signal(sd_event_source *s, const struct signa if (r < 0) log_warning_errno(r, "Failed to load DNS-SD configuration files: %m"); + manager_load_delegates(m); + /* The default scope configuration is influenced by the manager's configuration (modes, etc.), so * recreate it on reload. */ - r = dns_scope_new(m, &m->unicast_scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, DNS_PROTOCOL_DNS, AF_UNSPEC); + r = dns_scope_new(m, &m->unicast_scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_UNSPEC); if (r < 0) return r; @@ -755,7 +763,9 @@ int manager_new(Manager **ret) { if (r < 0) log_warning_errno(r, "Failed to load DNS-SD configuration files: %m"); - r = dns_scope_new(m, &m->unicast_scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, DNS_PROTOCOL_DNS, AF_UNSPEC); + manager_load_delegates(m); + + r = dns_scope_new(m, &m->unicast_scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_UNSPEC); if (r < 0) return r; @@ -824,7 +834,6 @@ int manager_start(Manager *m) { Manager *manager_free(Manager *m) { Link *l; - DnssdService *s; if (!m) return NULL; @@ -836,12 +845,13 @@ Manager *manager_free(Manager *m) { while ((l = hashmap_first(m->links))) link_free(l); + m->delegates = hashmap_free(m->delegates); + while (m->dns_queries) dns_query_free(m->dns_queries); m->stub_queries_by_packet = hashmap_free(m->stub_queries_by_packet); - - dns_scope_free(m->unicast_scope); + m->unicast_scope = dns_scope_free(m->unicast_scope); /* At this point only orphaned streams should remain. All others should have been freed already by their * owners */ @@ -894,6 +904,7 @@ Manager *manager_free(Manager *m) { free(m->llmnr_hostname); free(m->mdns_hostname); + DnssdService *s; while ((s = hashmap_first(m->dnssd_services))) dnssd_service_free(s); hashmap_free(m->dnssd_services); @@ -1621,7 +1632,7 @@ int manager_compile_dns_servers(Manager *m, OrderedSet **dns) { } /* Then, add the per-link servers */ - HASHMAP_FOREACH(l, m->links) { + HASHMAP_FOREACH(l, m->links) LIST_FOREACH(servers, s, l->dns_servers) { r = ordered_set_put(*dns, s); if (r == -EEXIST) @@ -1629,7 +1640,17 @@ int manager_compile_dns_servers(Manager *m, OrderedSet **dns) { if (r < 0) return r; } - } + + /* Third, add the delegate servers and domains */ + DnsDelegate *d; + HASHMAP_FOREACH(d, m->delegates) + LIST_FOREACH(servers, s, d->dns_servers) { + r = ordered_set_put(*dns, s); + if (r == -EEXIST) + continue; + if (r < 0) + return r; + } /* If we found nothing, add the fallback servers */ if (ordered_set_isempty(*dns)) { @@ -1651,7 +1672,6 @@ int manager_compile_dns_servers(Manager *m, OrderedSet **dns) { * > 0 or true: return only domains which are for routing only */ int manager_compile_search_domains(Manager *m, OrderedSet **domains, int filter_route) { - Link *l; int r; assert(m); @@ -1674,8 +1694,23 @@ int manager_compile_search_domains(Manager *m, OrderedSet **domains, int filter_ return r; } - HASHMAP_FOREACH(l, m->links) { + DnsDelegate *delegate; + HASHMAP_FOREACH(delegate, m->delegates) + LIST_FOREACH(domains, d, delegate->search_domains) { + + if (filter_route >= 0 && + d->route_only != !!filter_route) + continue; + + r = ordered_set_put(*domains, d->name); + if (r == -EEXIST) + continue; + if (r < 0) + return r; + } + Link *l; + HASHMAP_FOREACH(l, m->links) LIST_FOREACH(domains, d, l->search_domains) { if (filter_route >= 0 && @@ -1688,7 +1723,6 @@ int manager_compile_search_domains(Manager *m, OrderedSet **domains, int filter_ if (r < 0) return r; } - } return 0; } @@ -1771,14 +1805,18 @@ void manager_flush_caches(Manager *m, int log_level) { } void manager_reset_server_features(Manager *m) { - Link *l; dns_server_reset_features_all(m->dns_servers); dns_server_reset_features_all(m->fallback_dns_servers); + Link *l; HASHMAP_FOREACH(l, m->links) dns_server_reset_features_all(l->dns_servers); + DnsDelegate *d; + HASHMAP_FOREACH(d, m->delegates) + dns_server_reset_features_all(d->dns_servers); + log_info("Resetting learnt feature levels on all servers."); } diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h index e3f98be33db..bb398e83b7f 100644 --- a/src/resolve/resolved-manager.h +++ b/src/resolve/resolved-manager.h @@ -89,6 +89,8 @@ typedef struct Manager { LIST_HEAD(DnsScope, dns_scopes); DnsScope *unicast_scope; + Hashmap *delegates; /* id string → DnsDelegate objects */ + /* LLMNR */ int llmnr_ipv4_udp_fd; int llmnr_ipv6_udp_fd; diff --git a/src/resolve/test-dns-query.c b/src/resolve/test-dns-query.c index ca4bd22ce38..83460e1c2d4 100644 --- a/src/resolve/test-dns-query.c +++ b/src/resolve/test-dns-query.c @@ -786,7 +786,7 @@ static void go_env_setup(GoEnvironment *env, GoConfig *cfg) { } if (cfg->has_scope) { - ASSERT_OK(dns_scope_new(&env->manager, &env->scope, env->link ? DNS_SCOPE_LINK : DNS_SCOPE_GLOBAL, env->link, env->protocol, env->family)); + ASSERT_OK(dns_scope_new(&env->manager, &env->scope, env->link ? DNS_SCOPE_LINK : DNS_SCOPE_GLOBAL, env->link, /* delegate= */ NULL, env->protocol, env->family)); ASSERT_NOT_NULL(env->scope); env->server_addr.in.s_addr = htobe32(0x7f000001); @@ -794,7 +794,7 @@ static void go_env_setup(GoEnvironment *env, GoConfig *cfg) { env->server_port = 53; ASSERT_OK(dns_server_new(&env->manager, &env->server, env->server_type, - env->link, env->family, &env->server_addr, env->server_port, + env->link, /* delegate= */ NULL, env->family, &env->server_addr, env->server_port, env->ifindex, env->server_name, RESOLVE_CONFIG_SOURCE_DBUS)); ASSERT_NOT_NULL(env->server); @@ -808,7 +808,7 @@ static void go_env_setup(GoEnvironment *env, GoConfig *cfg) { for (size_t i = 0 ; i < env->n_search_domains; i++) { DnsSearchDomainType type = (env->link == NULL) ? DNS_SEARCH_DOMAIN_SYSTEM : DNS_SEARCH_DOMAIN_LINK; - ASSERT_OK(dns_search_domain_new(&env->manager, &env->search_domains[i], type, env->link, SEARCH_DOMAINS[i])); + ASSERT_OK(dns_search_domain_new(&env->manager, &env->search_domains[i], type, env->link, /* delegate= */ NULL, SEARCH_DOMAINS[i])); ASSERT_NOT_NULL(env->search_domains[i]); } } diff --git a/src/resolve/test-dns-search-domain.c b/src/resolve/test-dns-search-domain.c index b1229dc916c..8c1f8415cc7 100644 --- a/src/resolve/test-dns-search-domain.c +++ b/src/resolve/test-dns-search-domain.c @@ -28,7 +28,7 @@ TEST(dns_search_domain_new_system) { Manager manager = {}; _cleanup_(dns_search_domain_unrefp) DnsSearchDomain *sd = NULL; - ASSERT_OK(dns_search_domain_new(&manager, &sd, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "local")); + ASSERT_OK(dns_search_domain_new(&manager, &sd, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "local")); ASSERT_NOT_NULL(sd); ASSERT_TRUE(sd->linked); @@ -40,12 +40,12 @@ TEST(dns_search_domain_new_system_limit) { DnsSearchDomain *sd = NULL; for (size_t i = 0; i < MANAGER_SEARCH_DOMAINS_MAX; i++) { - ASSERT_OK(dns_search_domain_new(&manager, &sd, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "local")); + ASSERT_OK(dns_search_domain_new(&manager, &sd, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "local")); ASSERT_NOT_NULL(sd); ASSERT_EQ(manager.n_search_domains, i + 1); } - ASSERT_ERROR(dns_search_domain_new(&manager, &sd, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "local"), E2BIG); + ASSERT_ERROR(dns_search_domain_new(&manager, &sd, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "local"), E2BIG); ASSERT_NOT_NULL(sd); dns_search_domain_unlink_all(manager.search_domains); @@ -59,7 +59,7 @@ TEST(dns_search_domain_new_link) { ASSERT_OK(link_new(&manager, &link, 1)); ASSERT_NOT_NULL(link); - ASSERT_OK(dns_search_domain_new(&manager, &sd, DNS_SEARCH_DOMAIN_LINK, link, "local.")); + ASSERT_OK(dns_search_domain_new(&manager, &sd, DNS_SEARCH_DOMAIN_LINK, link, /* delegate= */ NULL, "local.")); ASSERT_NOT_NULL(sd); ASSERT_TRUE(sd->linked); @@ -75,12 +75,12 @@ TEST(dns_search_domain_new_link_limit) { ASSERT_NOT_NULL(link); for (size_t i = 0; i < LINK_SEARCH_DOMAINS_MAX; i++) { - ASSERT_OK(dns_search_domain_new(&manager, &sd, DNS_SEARCH_DOMAIN_LINK, link, "local")); + ASSERT_OK(dns_search_domain_new(&manager, &sd, DNS_SEARCH_DOMAIN_LINK, link, /* delegate= */ NULL, "local")); ASSERT_NOT_NULL(sd); ASSERT_EQ(link->n_search_domains, i + 1); } - ASSERT_ERROR(dns_search_domain_new(&manager, &sd, DNS_SEARCH_DOMAIN_LINK, link, "local"), E2BIG); + ASSERT_ERROR(dns_search_domain_new(&manager, &sd, DNS_SEARCH_DOMAIN_LINK, link, /* delegate= */ NULL, "local"), E2BIG); ASSERT_NOT_NULL(sd); } @@ -93,13 +93,13 @@ TEST(dns_search_domain_unlink_system) { _cleanup_(dns_search_domain_unrefp) DnsSearchDomain *sd1 = NULL, *sd3 = NULL; DnsSearchDomain *sd2 = NULL; - dns_search_domain_new(&manager, &sd1, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "local"); + dns_search_domain_new(&manager, &sd1, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "local"); ASSERT_NOT_NULL(sd1); - dns_search_domain_new(&manager, &sd2, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "vpn.example.com"); + dns_search_domain_new(&manager, &sd2, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "vpn.example.com"); ASSERT_NOT_NULL(sd2); - dns_search_domain_new(&manager, &sd3, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "org"); + dns_search_domain_new(&manager, &sd3, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "org"); ASSERT_NOT_NULL(sd3); ASSERT_TRUE(sd2->linked); @@ -122,13 +122,13 @@ TEST(dns_search_domain_unlink_link) { ASSERT_OK(link_new(&manager, &link, 1)); ASSERT_NOT_NULL(link); - dns_search_domain_new(&manager, &sd1, DNS_SEARCH_DOMAIN_LINK, link, "local"); + dns_search_domain_new(&manager, &sd1, DNS_SEARCH_DOMAIN_LINK, link, /* delegate= */ NULL, "local"); ASSERT_NOT_NULL(sd1); - dns_search_domain_new(&manager, &sd2, DNS_SEARCH_DOMAIN_LINK, link, "vpn.example.com"); + dns_search_domain_new(&manager, &sd2, DNS_SEARCH_DOMAIN_LINK, link, /* delegate= */ NULL, "vpn.example.com"); ASSERT_NOT_NULL(sd2); - dns_search_domain_new(&manager, &sd3, DNS_SEARCH_DOMAIN_LINK, link, "org"); + dns_search_domain_new(&manager, &sd3, DNS_SEARCH_DOMAIN_LINK, link, /* delegate= */ NULL, "org"); ASSERT_NOT_NULL(sd3); ASSERT_TRUE(sd2->linked); @@ -150,13 +150,13 @@ TEST(dns_search_domain_mark_all) { Manager manager = {}; _cleanup_(dns_search_domain_unrefp) DnsSearchDomain *sd1 = NULL, *sd2 = NULL, *sd3 = NULL; - dns_search_domain_new(&manager, &sd1, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "local"); + dns_search_domain_new(&manager, &sd1, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "local"); ASSERT_NOT_NULL(sd1); - dns_search_domain_new(&manager, &sd2, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "vpn.example.com"); + dns_search_domain_new(&manager, &sd2, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "vpn.example.com"); ASSERT_NOT_NULL(sd2); - dns_search_domain_new(&manager, &sd3, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "org"); + dns_search_domain_new(&manager, &sd3, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "org"); ASSERT_NOT_NULL(sd3); ASSERT_FALSE(sd1->marked); @@ -178,13 +178,13 @@ TEST(dns_search_domain_move_back_and_unmark) { Manager manager = {}; _cleanup_(dns_search_domain_unrefp) DnsSearchDomain *sd1 = NULL, *sd2 = NULL, *sd3 = NULL; - dns_search_domain_new(&manager, &sd1, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "local"); + dns_search_domain_new(&manager, &sd1, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "local"); ASSERT_NOT_NULL(sd1); - dns_search_domain_new(&manager, &sd2, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "vpn.example.com"); + dns_search_domain_new(&manager, &sd2, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "vpn.example.com"); ASSERT_NOT_NULL(sd2); - dns_search_domain_new(&manager, &sd3, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "org"); + dns_search_domain_new(&manager, &sd3, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "org"); ASSERT_NOT_NULL(sd3); dns_search_domain_move_back_and_unmark(sd1); @@ -210,13 +210,13 @@ TEST(dns_search_domain_unlink_marked) { DnsSearchDomain *sd1 = NULL, *sd2 = NULL; _cleanup_(dns_search_domain_unrefp) DnsSearchDomain *sd3 = NULL; - dns_search_domain_new(&manager, &sd1, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "local"); + dns_search_domain_new(&manager, &sd1, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "local"); ASSERT_NOT_NULL(sd1); - dns_search_domain_new(&manager, &sd2, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "vpn.example.com"); + dns_search_domain_new(&manager, &sd2, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "vpn.example.com"); ASSERT_NOT_NULL(sd2); - dns_search_domain_new(&manager, &sd3, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "org"); + dns_search_domain_new(&manager, &sd3, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "org"); ASSERT_NOT_NULL(sd3); dns_search_domain_unlink_marked(sd1); @@ -244,13 +244,13 @@ TEST(dns_search_domain_unlink_all) { Manager manager = {}; DnsSearchDomain *sd1 = NULL, *sd2 = NULL, *sd3 = NULL; - dns_search_domain_new(&manager, &sd1, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "local"); + dns_search_domain_new(&manager, &sd1, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "local"); ASSERT_NOT_NULL(sd1); - dns_search_domain_new(&manager, &sd2, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "vpn.example.com"); + dns_search_domain_new(&manager, &sd2, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "vpn.example.com"); ASSERT_NOT_NULL(sd2); - dns_search_domain_new(&manager, &sd3, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "org"); + dns_search_domain_new(&manager, &sd3, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "org"); ASSERT_NOT_NULL(sd3); dns_search_domain_unlink_all(sd1); @@ -266,13 +266,13 @@ TEST(dns_search_domain_find) { Manager manager = {}; _cleanup_(dns_search_domain_unrefp) DnsSearchDomain *sd1 = NULL, *sd2 = NULL, *sd3 = NULL, *ret = NULL; - dns_search_domain_new(&manager, &sd1, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "local"); + dns_search_domain_new(&manager, &sd1, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "local"); ASSERT_NOT_NULL(sd1); - dns_search_domain_new(&manager, &sd2, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "vpn.example.com"); + dns_search_domain_new(&manager, &sd2, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "vpn.example.com"); ASSERT_NOT_NULL(sd2); - dns_search_domain_new(&manager, &sd3, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "org"); + dns_search_domain_new(&manager, &sd3, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "org"); ASSERT_NOT_NULL(sd3); ASSERT_TRUE(dns_search_domain_find(sd1, "local", &ret)); diff --git a/src/resolve/test-dns-zone.c b/src/resolve/test-dns-zone.c index 120080d94e8..2c461e9d88d 100644 --- a/src/resolve/test-dns-zone.c +++ b/src/resolve/test-dns-zone.c @@ -27,7 +27,7 @@ TEST(dns_zone_put_simple) { DnsZoneItem *item = NULL; _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; - ASSERT_OK(dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, DNS_PROTOCOL_DNS, AF_INET)); + ASSERT_OK(dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_INET)); ASSERT_NOT_NULL(scope); zone = &scope->zone; @@ -51,7 +51,7 @@ TEST(dns_zone_put_any_class_is_invalid) { DnsZone *zone = NULL; _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; - dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, DNS_PROTOCOL_DNS, AF_INET); + dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_INET); ASSERT_NOT_NULL(scope); zone = &scope->zone; @@ -69,7 +69,7 @@ TEST(dns_zone_put_any_type_is_invalid) { DnsZone *zone = NULL; _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; - dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, DNS_PROTOCOL_DNS, AF_INET); + dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_INET); ASSERT_NOT_NULL(scope); zone = &scope->zone; @@ -91,7 +91,7 @@ TEST(dns_zone_remove_rr_match) { DnsZone *zone = NULL; _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr_in = NULL, *rr_out = NULL; - dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, DNS_PROTOCOL_DNS, AF_INET); + dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_INET); ASSERT_NOT_NULL(scope); zone = &scope->zone; @@ -116,7 +116,7 @@ TEST(dns_zone_remove_rr_match_one) { DnsZone *zone = NULL; _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr_in = NULL, *rr_out = NULL; - dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, DNS_PROTOCOL_DNS, AF_INET); + dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_INET); ASSERT_NOT_NULL(scope); zone = &scope->zone; @@ -149,7 +149,7 @@ TEST(dns_zone_remove_rr_different_payload) { DnsZone *zone = NULL; _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr_in = NULL, *rr_out = NULL; - dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, DNS_PROTOCOL_DNS, AF_INET); + dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_INET); ASSERT_NOT_NULL(scope); zone = &scope->zone; @@ -179,7 +179,7 @@ TEST(dns_zone_remove_rrs_by_key) { _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr1 = NULL, *rr2 = NULL, *rr3 = NULL; DnsResourceKey *key = NULL; - dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, DNS_PROTOCOL_DNS, AF_INET); + dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_INET); ASSERT_NOT_NULL(scope); zone = &scope->zone; @@ -249,7 +249,7 @@ TEST(dns_zone_lookup_match_a) { _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL; bool tentative; - dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, DNS_PROTOCOL_DNS, AF_INET); + dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_INET); ASSERT_NOT_NULL(scope); add_zone_rrs(scope); @@ -271,7 +271,7 @@ TEST(dns_zone_lookup_match_cname) { _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL; bool tentative; - dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, DNS_PROTOCOL_DNS, AF_INET); + dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_INET); ASSERT_NOT_NULL(scope); add_zone_rrs(scope); @@ -294,7 +294,7 @@ TEST(dns_zone_lookup_match_any) { _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL; bool tentative; - dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, DNS_PROTOCOL_DNS, AF_INET); + dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_INET); ASSERT_NOT_NULL(scope); add_zone_rrs(scope); @@ -325,7 +325,7 @@ TEST(dns_zone_lookup_match_any_apex) { _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL; bool tentative; - dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, DNS_PROTOCOL_DNS, AF_INET); + dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_INET); ASSERT_NOT_NULL(scope); add_zone_rrs(scope); @@ -350,7 +350,7 @@ TEST(dns_zone_lookup_match_nothing) { _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL; bool tentative; - dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, DNS_PROTOCOL_DNS, AF_INET); + dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_INET); ASSERT_NOT_NULL(scope); add_zone_rrs(scope); @@ -371,7 +371,7 @@ TEST(dns_zone_lookup_match_nothing_with_soa) { _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL; bool tentative; - dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, DNS_PROTOCOL_DNS, AF_INET); + dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_INET); ASSERT_NOT_NULL(scope); add_zone_rrs(scope); diff --git a/src/resolve/test-resolved-link.c b/src/resolve/test-resolved-link.c index 0336c73aa9c..96f62a362fb 100644 --- a/src/resolve/test-resolved-link.c +++ b/src/resolve/test-resolved-link.c @@ -184,7 +184,7 @@ static void link_alloc_env_setup(LinkAllocEnv *env, int family, DnsServerType se link = env->link; ASSERT_OK(dns_server_new(&env->manager, &env->server, env->server_type, - link, family, &env->server_addr, env->server_port, + link, /* delegate= */ NULL, family, &env->server_addr, env->server_port, env->ifindex, env->server_name, RESOLVE_CONFIG_SOURCE_DBUS)); ASSERT_NOT_NULL(env->server);