diff --git a/man/org.freedesktop.resolve1.xml b/man/org.freedesktop.resolve1.xml index 324b688853..7d5e997b83 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 c911a64ca4..1075c29ed6 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 e69f6194dd..ad6b45ae39 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 a814551a9b..b47dfd2724 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 e9b47488e7..be927e0706 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 0000000000..60134b504c --- /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 0000000000..7acdd5a983 --- /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 0000000000..3040770f3a --- /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 0000000000..6a094ce68e --- /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 0000000000..3ce3c1e172 --- /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 d4bfbccdc3..4525f253de 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) + 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) { + + if (scope->delegate->default_route >= 0) + return scope->delegate->default_route; + + /* Delegates are by default not used as default route */ + return false; + } else + /* The global DNS scope is always suitable as default route */ return true; - - /* 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); } 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 54f0b7b7a3..872457ffc2 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 642d52c6ea..63790ad1fc 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 fbd9a4490f..63bd357b83 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 5996d9bcc6..7845dcfd21 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 bb3c0e109f..bef352aa42 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 9c5f7a836a..9e5371684a 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 432d7cf8b0..55c8aa36cf 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 856161fa47..f44fde2882 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 e3f98be33d..bb398e83b7 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 ca4bd22ce3..83460e1c2d 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 b1229dc916..8c1f8415cc 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 120080d94e..2c461e9d88 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 0336c73aa9..96f62a362f 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);