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;
* 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;
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)
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)
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)) {
}
/* 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;
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) {
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. */
assert(scope);
- if (hashmap_size(scope->manager->dnssd_services) == 0)
+ if (hashmap_isempty(scope->manager->dnssd_services))
return 0;
scope->announced = false;
* 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)));
+}