]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/resolve/resolved-dns-scope.c
Merge pull request #30284 from YHNdnzj/fstab-wantedby-defaultdeps
[thirdparty/systemd.git] / src / resolve / resolved-dns-scope.c
index 852829569ddf014988c7df0153325b4800ac2d57..40615ff605139f349ba3f1275f353ee60017c056 100644 (file)
@@ -71,7 +71,7 @@ int dns_scope_new(Manager *m, DnsScope **ret, Link *l, DnsProtocol protocol, int
         log_debug("New scope on link %s, protocol %s, family %s", l ? l->ifname : "*", dns_protocol_to_string(protocol), family == AF_UNSPEC ? "*" : af_to_name(family));
 
         /* Enforce ratelimiting for the multicast protocols */
-        s->ratelimit = (RateLimit) { MULTICAST_RATELIMIT_INTERVAL_USEC, MULTICAST_RATELIMIT_BURST };
+        s->ratelimit = (const RateLimit) { MULTICAST_RATELIMIT_INTERVAL_USEC, MULTICAST_RATELIMIT_BURST };
 
         *ret = s;
         return 0;
@@ -351,7 +351,7 @@ static int dns_scope_socket(
                 uint16_t port,
                 union sockaddr_union *ret_socket_address) {
 
-        _cleanup_close_ int fd = -1;
+        _cleanup_close_ int fd = -EBADF;
         union sockaddr_union sa;
         socklen_t salen;
         int r, ifindex;
@@ -424,7 +424,7 @@ static int dns_scope_socket(
                         return r;
         }
 
-        if (s->link) {
+        if (ifindex != 0) {
                 r = socket_set_unicast_if(fd, sa.sa.sa_family, ifindex);
                 if (r < 0)
                         return r;
@@ -474,7 +474,8 @@ static int dns_scope_socket(
                  * host result in EHOSTUNREACH, since Linux won't send the packets out of the specified
                  * interface, but delivers them directly to the local socket. */
                 if (s->link &&
-                    !manager_find_link_address(s->manager, sa.sa.sa_family, sockaddr_in_addr(&sa.sa))) {
+                    !manager_find_link_address(s->manager, sa.sa.sa_family, sockaddr_in_addr(&sa.sa)) &&
+                    in_addr_is_localhost(sa.sa.sa_family, sockaddr_in_addr(&sa.sa)) == 0) {
                         r = socket_bind_to_ifindex(fd, ifindex);
                         if (r < 0)
                                 return r;
@@ -555,6 +556,9 @@ static DnsScopeMatch match_subnet_reverse_lookups(
         if (s->family != AF_UNSPEC && f != s->family)
                 return _DNS_SCOPE_MATCH_INVALID; /* Don't look for IPv4 addresses on LLMNR/mDNS over IPv6 and vice versa */
 
+        if (in_addr_is_null(f, &ia))
+                return DNS_SCOPE_NO;
+
         LIST_FOREACH(addresses, a, s->link->addresses) {
 
                 if (a->family != f)
@@ -568,6 +572,10 @@ static DnsScopeMatch match_subnet_reverse_lookups(
                 if (a->prefixlen == UCHAR_MAX) /* don't know subnet mask */
                         continue;
 
+                /* Don't send mDNS queries for the IPv4 broadcast address */
+                if (f == AF_INET && in_addr_equal(f, &a->in_addr_broadcast, &ia) > 0)
+                        return DNS_SCOPE_NO;
+
                 /* Check if the address is in the local subnet */
                 r = in_addr_prefix_covers(f, &a->in_addr, a->prefixlen, &ia);
                 if (r < 0)
@@ -635,8 +643,11 @@ DnsScopeMatch dns_scope_good_domain(
         if (dns_name_dont_resolve(domain))
                 return DNS_SCOPE_NO;
 
-        /* Never go to network for the _gateway or _outbound domain — they're something special, synthesized locally. */
-        if (is_gateway_hostname(domain) || is_outbound_hostname(domain))
+        /* Never go to network for the _gateway, _outbound, _localdnsstub, _localdnsproxy domain — they're something special, synthesized locally. */
+        if (is_gateway_hostname(domain) ||
+            is_outbound_hostname(domain) ||
+            is_dns_stub_hostname(domain) ||
+            is_dns_proxy_stub_hostname(domain))
                 return DNS_SCOPE_NO;
 
         switch (s->protocol) {
@@ -646,11 +657,11 @@ DnsScopeMatch dns_scope_good_domain(
                 DnsScopeMatch m;
                 int n_best = -1;
 
-                if (dns_name_is_empty(domain)) {
+                if (dns_name_is_root(domain)) {
                         DnsResourceKey *t;
                         bool found = false;
 
-                        /* Refuse empty name if only A and/or AAAA records are requested. */
+                        /* Refuse root name if only A and/or AAAA records are requested. */
 
                         DNS_QUESTION_FOREACH(t, question)
                                 if (!IN_SET(t->type, DNS_TYPE_A, DNS_TYPE_AAAA)) {
@@ -687,7 +698,7 @@ DnsScopeMatch dns_scope_good_domain(
                 }
 
                 /* If there's a true search domain defined for this scope, and the query is single-label,
-                 * then let's resolve things here, prefereably. Note that LLMNR considers itself
+                 * then let's resolve things here, preferably. Note that LLMNR considers itself
                  * authoritative for single-label names too, at the same preference, see below. */
                 if (has_search_domains && dns_name_is_single_label(domain))
                         return DNS_SCOPE_YES_BASE + 1;
@@ -764,8 +775,6 @@ DnsScopeMatch dns_scope_good_domain(
                         return DNS_SCOPE_MAYBE;
 
                 if ((dns_name_is_single_label(domain) && /* only resolve single label names via LLMNR */
-                     !is_gateway_hostname(domain) && /* don't resolve "_gateway" with LLMNR, let local synthesizing logic handle that */
-                     !is_outbound_hostname(domain) && /* similar for "_outbound" */
                      dns_name_equal(domain, "local") == 0 && /* don't resolve "local" with LLMNR, it's the top-level domain of mDNS after all, see above */
                      manager_is_own_hostname(s->manager, domain) <= 0))  /* never resolve the local hostname via LLMNR */
                         return DNS_SCOPE_YES_BASE + 1; /* Return +1, as we consider ourselves authoritative
@@ -1116,7 +1125,7 @@ DnsTransaction *dns_scope_find_transaction(
                     !(t->query_flags & SD_RESOLVED_NO_CACHE))
                         continue;
 
-                /* If we are asked to clamp ttls an the existing transaction doesn't do it, we can't
+                /* If we are asked to clamp ttls and the existing transaction doesn't do it, we can't
                  * reuse */
                 if ((query_flags & SD_RESOLVED_CLAMP_TTL) &&
                     !(t->query_flags & SD_RESOLVED_CLAMP_TTL))
@@ -1356,7 +1365,17 @@ bool dns_scope_name_wants_search_domain(DnsScope *s, const char *name) {
         if (s->protocol != DNS_PROTOCOL_DNS)
                 return false;
 
-        return dns_name_is_single_label(name);
+        if (!dns_name_is_single_label(name))
+                return false;
+
+        /* If we allow single-label domain lookups on unicast DNS, and this scope has a search domain that matches
+         * _exactly_ this name, then do not use search domains. */
+        if (s->manager->resolve_unicast_single_label)
+                LIST_FOREACH(domains, d, dns_scope_get_search_domains(s))
+                        if (dns_name_equal(name, d->name) > 0)
+                                return false;
+
+        return true;
 }
 
 bool dns_scope_network_good(DnsScope *s) {
@@ -1409,9 +1428,17 @@ int dns_scope_announce(DnsScope *scope, bool goodbye) {
         if (scope->protocol != DNS_PROTOCOL_MDNS)
                 return 0;
 
+        r = sd_event_get_state(scope->manager->event);
+        if (r < 0)
+                return log_debug_errno(r, "Failed to get event loop state: %m");
+
+        /* If this is called on exit, through manager_free() -> link_free(), then we cannot announce. */
+        if (r == SD_EVENT_FINISHED)
+                return 0;
+
         /* Check if we're done with probing. */
         LIST_FOREACH(transactions_by_scope, t, scope->transactions)
-                if (DNS_TRANSACTION_IS_LIVE(t->state))
+                if (t->probing && DNS_TRANSACTION_IS_LIVE(t->state))
                         return 0;
 
         /* Check if there're services pending conflict resolution. */
@@ -1530,7 +1557,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;
@@ -1634,3 +1661,23 @@ bool dns_scope_is_default_route(DnsScope *scope) {
          * volunteer as default route. */
         return !dns_scope_has_route_only_domains(scope);
 }
+
+int dns_scope_dump_cache_to_json(DnsScope *scope, JsonVariant **ret) {
+        _cleanup_(json_variant_unrefp) JsonVariant *cache = NULL;
+        int r;
+
+        assert(scope);
+        assert(ret);
+
+        r = dns_cache_dump_to_json(&scope->cache, &cache);
+        if (r < 0)
+                return r;
+
+        return json_build(ret,
+                          JSON_BUILD_OBJECT(
+                                          JSON_BUILD_PAIR_STRING("protocol", dns_protocol_to_string(scope->protocol)),
+                                          JSON_BUILD_PAIR_CONDITION(scope->family != AF_UNSPEC, "family", JSON_BUILD_INTEGER(scope->family)),
+                                          JSON_BUILD_PAIR_CONDITION(scope->link, "ifindex", JSON_BUILD_INTEGER(scope->link ? scope->link->ifindex : 0)),
+                                          JSON_BUILD_PAIR_CONDITION(scope->link, "ifname", JSON_BUILD_STRING(scope->link ? scope->link->ifname : NULL)),
+                                          JSON_BUILD_PAIR_VARIANT("cache", cache)));
+}