diff options
Diffstat (limited to 'src/resolve/resolved-dns-scope.c')
-rw-r--r-- | src/resolve/resolved-dns-scope.c | 92 |
1 files changed, 88 insertions, 4 deletions
diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index af8e9cd..17bc823 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -12,6 +12,7 @@ #include "random-util.h" #include "resolved-dnssd.h" #include "resolved-dns-scope.h" +#include "resolved-dns-synthesize.h" #include "resolved-dns-zone.h" #include "resolved-llmnr.h" #include "resolved-mdns.h" @@ -41,6 +42,7 @@ int dns_scope_new(Manager *m, DnsScope **ret, Link *l, DnsProtocol protocol, int .protocol = protocol, .family = family, .resend_timeout = MULTICAST_RESEND_TIMEOUT_MIN_USEC, + .mdns_goodbye_event_source = NULL, }; if (protocol == DNS_PROTOCOL_DNS) { @@ -115,6 +117,8 @@ DnsScope* dns_scope_free(DnsScope *s) { sd_event_source_disable_unref(s->announce_event_source); + sd_event_source_disable_unref(s->mdns_goodbye_event_source); + dns_cache_flush(&s->cache); dns_zone_flush(&s->zone); @@ -616,12 +620,13 @@ static bool dns_refuse_special_use_domain(const char *domain, DnsQuestion *quest DnsScopeMatch dns_scope_good_domain( DnsScope *s, - DnsQuery *q) { + DnsQuery *q, + uint64_t query_flags) { DnsQuestion *question; const char *domain; uint64_t flags; - int ifindex; + int ifindex, r; /* This returns the following return values: * @@ -680,6 +685,15 @@ DnsScopeMatch dns_scope_good_domain( is_dns_proxy_stub_hostname(domain)) return DNS_SCOPE_NO; + /* Don't look up the local host name via the network, unless user turned of local synthesis of it */ + if (manager_is_own_hostname(s->manager, domain) && shall_synthesize_own_hostname_rrs()) + return DNS_SCOPE_NO; + + /* Never send SOA or NS or DNSSEC request to LLMNR, where they make little sense. */ + r = dns_question_types_suitable_for_protocol(question, s->protocol); + if (r <= 0) + return DNS_SCOPE_NO; + switch (s->protocol) { case DNS_PROTOCOL_DNS: { @@ -735,7 +749,8 @@ DnsScopeMatch dns_scope_good_domain( /* If ResolveUnicastSingleLabel=yes and the query is single-label, then bump match result to prevent LLMNR monopoly among candidates. */ - if (s->manager->resolve_unicast_single_label && dns_name_is_single_label(domain)) + if ((s->manager->resolve_unicast_single_label || (query_flags & SD_RESOLVED_RELAX_SINGLE_LABEL)) && + dns_name_is_single_label(domain)) return DNS_SCOPE_YES_BASE + 1; /* Let's return the number of labels in the best matching result */ @@ -1588,7 +1603,7 @@ int dns_scope_add_dnssd_services(DnsScope *scope) { assert(scope); - if (hashmap_size(scope->manager->dnssd_services) == 0) + if (hashmap_isempty(scope->manager->dnssd_services)) return 0; scope->announced = false; @@ -1600,6 +1615,12 @@ int dns_scope_add_dnssd_services(DnsScope *scope) { if (r < 0) log_warning_errno(r, "Failed to add PTR record to MDNS zone: %m"); + if (service->sub_ptr_rr) { + r = dns_zone_put(&scope->zone, scope, service->sub_ptr_rr, false); + if (r < 0) + log_warning_errno(r, "Failed to add selective PTR record to MDNS zone: %m"); + } + r = dns_zone_put(&scope->zone, scope, service->srv_rr, true); if (r < 0) log_warning_errno(r, "Failed to add SRV record to MDNS zone: %m"); @@ -1632,6 +1653,7 @@ int dns_scope_remove_dnssd_services(DnsScope *scope) { HASHMAP_FOREACH(service, scope->manager->dnssd_services) { dns_zone_remove_rr(&scope->zone, service->ptr_rr); + dns_zone_remove_rr(&scope->zone, service->sub_ptr_rr); dns_zone_remove_rr(&scope->zone, service->srv_rr); LIST_FOREACH(items, txt_data, service->txt_data_items) dns_zone_remove_rr(&scope->zone, txt_data->rr); @@ -1712,3 +1734,65 @@ int dns_scope_dump_cache_to_json(DnsScope *scope, JsonVariant **ret) { JSON_BUILD_PAIR_CONDITION(scope->link, "ifname", JSON_BUILD_STRING(scope->link ? scope->link->ifname : NULL)), JSON_BUILD_PAIR_VARIANT("cache", cache))); } + +int dns_type_suitable_for_protocol(uint16_t type, DnsProtocol protocol) { + + /* Tests whether it makes sense to route queries for the specified DNS RR types to the specified + * protocol. For classic DNS pretty much all RR types are suitable, but for LLMNR/mDNS let's + * allowlist only a few that make sense. We use this when routing queries so that we can more quickly + * return errors for queries that will almost certainly fail/time-out otherwise. For example, this + * ensures that SOA, NS, or DS/DNSKEY queries are never routed to mDNS/LLMNR where they simply make + * no sense. */ + + if (dns_type_is_obsolete(type)) + return false; + + if (!dns_type_is_valid_query(type)) + return false; + + switch (protocol) { + + case DNS_PROTOCOL_DNS: + return true; + + case DNS_PROTOCOL_LLMNR: + return IN_SET(type, + DNS_TYPE_ANY, + DNS_TYPE_A, + DNS_TYPE_AAAA, + DNS_TYPE_CNAME, + DNS_TYPE_PTR, + DNS_TYPE_TXT); + + case DNS_PROTOCOL_MDNS: + return IN_SET(type, + DNS_TYPE_ANY, + DNS_TYPE_A, + DNS_TYPE_AAAA, + DNS_TYPE_CNAME, + DNS_TYPE_PTR, + DNS_TYPE_TXT, + DNS_TYPE_SRV, + DNS_TYPE_NSEC, + DNS_TYPE_HINFO); + + default: + return -EPROTONOSUPPORT; + } +} + +int dns_question_types_suitable_for_protocol(DnsQuestion *q, DnsProtocol protocol) { + DnsResourceKey *key; + int r; + + /* Tests whether the types in the specified question make any sense to be routed to the specified + * protocol, i.e. if dns_type_suitable_for_protocol() is true for any of the contained RR types */ + + DNS_QUESTION_FOREACH(key, q) { + r = dns_type_suitable_for_protocol(key->type, protocol); + if (r != 0) + return r; + } + + return false; +} |