diff options
Diffstat (limited to 'src/resolve')
-rw-r--r-- | src/resolve/resolved-bus.c | 16 | ||||
-rw-r--r-- | src/resolve/resolved-dns-cache.c | 30 | ||||
-rw-r--r-- | src/resolve/resolved-dns-packet.c | 43 | ||||
-rw-r--r-- | src/resolve/resolved-dns-packet.h | 9 | ||||
-rw-r--r-- | src/resolve/resolved-dns-query.c | 8 | ||||
-rw-r--r-- | src/resolve/resolved-dns-scope.c | 60 | ||||
-rw-r--r-- | src/resolve/resolved-dns-scope.h | 2 | ||||
-rw-r--r-- | src/resolve/resolved-dns-transaction.c | 48 |
8 files changed, 119 insertions, 97 deletions
diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c index 1f23834ce3..12c17003e9 100644 --- a/src/resolve/resolved-bus.c +++ b/src/resolve/resolved-bus.c @@ -226,10 +226,6 @@ static void bus_method_resolve_hostname_complete(DnsQuery *q) { * query, this time with the cname */ if (added <= 0) { r = dns_query_go(q); - if (r == -ESRCH) { - r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found"); - goto finish; - } if (r < 0) { r = sd_bus_reply_method_errno(q->request, -r, NULL); goto finish; @@ -346,10 +342,6 @@ static int bus_method_resolve_hostname(sd_bus_message *message, void *userdata, r = dns_query_go(q); if (r < 0) { dns_query_free(q); - - if (r == -ESRCH) - sd_bus_error_setf(error, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found"); - return r; } @@ -494,10 +486,6 @@ static int bus_method_resolve_address(sd_bus_message *message, void *userdata, s r = dns_query_go(q); if (r < 0) { dns_query_free(q); - - if (r == -ESRCH) - sd_bus_error_setf(error, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found"); - return r; } @@ -647,10 +635,6 @@ static int bus_method_resolve_record(sd_bus_message *message, void *userdata, sd r = dns_query_go(q); if (r < 0) { dns_query_free(q); - - if (r == -ESRCH) - sd_bus_error_setf(error, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found"); - return r; } diff --git a/src/resolve/resolved-dns-cache.c b/src/resolve/resolved-dns-cache.c index efc407dbc6..7ee098397c 100644 --- a/src/resolve/resolved-dns-cache.c +++ b/src/resolve/resolved-dns-cache.c @@ -411,16 +411,17 @@ int dns_cache_put( int owner_family, const union in_addr_union *owner_address) { - unsigned i; + unsigned cache_keys, i; int r; assert(c); - assert(q); - /* First, delete all matching old RRs, so that we only keep - * complete by_key in place. */ - for (i = 0; i < q->n_keys; i++) - dns_cache_remove(c, q->keys[i]); + if (q) { + /* First, if we were passed a question, delete all matching old RRs, + * so that we only keep complete by_key in place. */ + for (i = 0; i < q->n_keys; i++) + dns_cache_remove(c, q->keys[i]); + } if (!answer) return 0; @@ -435,8 +436,13 @@ int dns_cache_put( if (!IN_SET(rcode, DNS_RCODE_SUCCESS, DNS_RCODE_NXDOMAIN)) return 0; + cache_keys = answer->n_rrs; + + if (q) + cache_keys += q->n_keys; + /* Make some space for our new entries */ - dns_cache_make_space(c, answer->n_rrs + q->n_keys); + dns_cache_make_space(c, cache_keys); if (timestamp <= 0) timestamp = now(clock_boottime_or_monotonic()); @@ -448,6 +454,9 @@ int dns_cache_put( goto fail; } + if (!q) + return 0; + /* Third, add in negative entries for all keys with no RR */ for (i = 0; i < q->n_keys; i++) { DnsResourceRecord *soa = NULL; @@ -479,8 +488,11 @@ fail: /* Adding all RRs failed. Let's clean up what we already * added, just in case */ - for (i = 0; i < q->n_keys; i++) - dns_cache_remove(c, q->keys[i]); + if (q) { + for (i = 0; i < q->n_keys; i++) + dns_cache_remove(c, q->keys[i]); + } + for (i = 0; i < answer->n_rrs; i++) dns_cache_remove(c, answer->items[i].rr->key); diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c index bebd1ee4a6..784d949cce 100644 --- a/src/resolve/resolved-dns-packet.c +++ b/src/resolve/resolved-dns-packet.c @@ -64,7 +64,7 @@ int dns_packet_new(DnsPacket **ret, DnsProtocol protocol, size_t mtu) { int dns_packet_new_query(DnsPacket **ret, DnsProtocol protocol, size_t mtu) { DnsPacket *p; DnsPacketHeader *h; - int r; + int r, rd; assert(ret); @@ -74,26 +74,27 @@ int dns_packet_new_query(DnsPacket **ret, DnsProtocol protocol, size_t mtu) { h = DNS_PACKET_HEADER(p); - if (protocol == DNS_PROTOCOL_LLMNR) - h->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0 /* qr */, - 0 /* opcode */, - 0 /* c */, - 0 /* tc */, - 0 /* t */, - 0 /* ra */, - 0 /* ad */, - 0 /* cd */, - 0 /* rcode */)); - else - h->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0 /* qr */, - 0 /* opcode */, - 0 /* aa */, - 0 /* tc */, - 1 /* rd (ask for recursion) */, - 0 /* ra */, - 0 /* ad */, - 0 /* cd */, - 0 /* rcode */)); + switch (protocol) { + case DNS_PROTOCOL_LLMNR: + /* no recursion for link-local resolving protocols */ + rd = 0; + break; + + default: + /* ask for recursion */ + rd = 1; + break; + } + + h->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0 /* qr */, + 0 /* opcode */, + 0 /* aa */, + 0 /* tc */, + rd /* rd */, + 0 /* ra */, + 0 /* ad */, + 0 /* cd */, + 0 /* rcode */)); *ret = p; return 0; diff --git a/src/resolve/resolved-dns-packet.h b/src/resolve/resolved-dns-packet.h index e81f8a8202..8a72b898da 100644 --- a/src/resolve/resolved-dns-packet.h +++ b/src/resolve/resolved-dns-packet.h @@ -239,11 +239,16 @@ static inline uint64_t SD_RESOLVED_FLAGS_MAKE(DnsProtocol protocol, int family) /* Converts a protocol + family into a flags field as used in queries */ - if (protocol == DNS_PROTOCOL_DNS) + switch (protocol) { + case DNS_PROTOCOL_DNS: return SD_RESOLVED_DNS; - if (protocol == DNS_PROTOCOL_LLMNR) + case DNS_PROTOCOL_LLMNR: return family == AF_INET6 ? SD_RESOLVED_LLMNR_IPV6 : SD_RESOLVED_LLMNR_IPV4; + default: + break; + } + return 0; } diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c index d9f5b342b2..c0b4c8ba81 100644 --- a/src/resolve/resolved-dns-query.c +++ b/src/resolve/resolved-dns-query.c @@ -651,12 +651,8 @@ int dns_query_go(DnsQuery *q) { DnsTransactionState state = DNS_TRANSACTION_NO_SERVERS; dns_query_synthesize_reply(q, &state); - if (state != DNS_TRANSACTION_NO_SERVERS) { - dns_query_complete(q, state); - return 1; - } - - return -ESRCH; + dns_query_complete(q, state); + return 1; } r = dns_query_add_transaction_split(q, first); diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index 57a2c7d6c1..77034a0be8 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -78,8 +78,7 @@ DnsScope* dns_scope_free(DnsScope *s) { dns_scope_llmnr_membership(s, false); - while ((t = s->transactions)) { - + while ((t = hashmap_steal_first(s->transactions))) { /* Abort the transaction, but make sure it is not * freed while we still look at it */ @@ -90,6 +89,8 @@ DnsScope* dns_scope_free(DnsScope *s) { dns_transaction_free(t); } + hashmap_free(s->transactions); + while ((rr = ordered_hashmap_steal_first(s->conflict_queue))) dns_resource_record_unref(rr); @@ -165,7 +166,8 @@ int dns_scope_emit(DnsScope *s, int fd, DnsPacket *p) { } else mtu = manager_find_mtu(s->manager); - if (s->protocol == DNS_PROTOCOL_DNS) { + switch (s->protocol) { + case DNS_PROTOCOL_DNS: if (DNS_PACKET_QDCOUNT(p) > 1) return -EOPNOTSUPP; @@ -179,8 +181,9 @@ int dns_scope_emit(DnsScope *s, int fd, DnsPacket *p) { if (r < 0) return r; - } else if (s->protocol == DNS_PROTOCOL_LLMNR) { + break; + case DNS_PROTOCOL_LLMNR: if (DNS_PACKET_QDCOUNT(p) > 1) return -EOPNOTSUPP; @@ -204,8 +207,12 @@ int dns_scope_emit(DnsScope *s, int fd, DnsPacket *p) { r = manager_send(s->manager, fd, ifindex, family, &addr, port, p); if (r < 0) return r; - } else + + break; + + default: return -EAFNOSUPPORT; + } return 1; } @@ -340,27 +347,25 @@ DnsScopeMatch dns_scope_good_domain(DnsScope *s, int ifindex, uint64_t flags, co if (dns_name_endswith(domain, *i) > 0) return DNS_SCOPE_YES; - if (s->protocol == DNS_PROTOCOL_DNS) { + switch (s->protocol) { + case DNS_PROTOCOL_DNS: if (dns_name_endswith(domain, "254.169.in-addr.arpa") == 0 && dns_name_endswith(domain, "0.8.e.f.ip6.arpa") == 0 && dns_name_single_label(domain) == 0) return DNS_SCOPE_MAYBE; return DNS_SCOPE_NO; - } - if (s->protocol == DNS_PROTOCOL_MDNS) { + case DNS_PROTOCOL_MDNS: if ((s->family == AF_INET && dns_name_endswith(domain, "in-addr.arpa") > 0) || (s->family == AF_INET6 && dns_name_endswith(domain, "ip6.arpa") > 0) || (dns_name_endswith(domain, "local") > 0 && /* only resolve names ending in .local via mDNS */ dns_name_equal(domain, "local") == 0 && /* but not the single-label "local" name itself */ manager_is_own_hostname(s->manager, domain) <= 0)) /* never resolve the local hostname via mDNS */ - return DNS_SCOPE_MAYBE; return DNS_SCOPE_NO; - } - if (s->protocol == DNS_PROTOCOL_LLMNR) { + case DNS_PROTOCOL_LLMNR: if ((s->family == AF_INET && dns_name_endswith(domain, "in-addr.arpa") > 0) || (s->family == AF_INET6 && dns_name_endswith(domain, "ip6.arpa") > 0) || (dns_name_single_label(domain) > 0 && /* only resolve single label names via LLMNR */ @@ -369,9 +374,10 @@ DnsScopeMatch dns_scope_good_domain(DnsScope *s, int ifindex, uint64_t flags, co return DNS_SCOPE_MAYBE; return DNS_SCOPE_NO; - } - assert_not_reached("Unknown scope protocol"); + default: + assert_not_reached("Unknown scope protocol"); + } } int dns_scope_good_key(DnsScope *s, DnsResourceKey *key) { @@ -623,24 +629,20 @@ DnsTransaction *dns_scope_find_transaction(DnsScope *scope, DnsResourceKey *key, assert(scope); assert(key); - /* Try to find an ongoing transaction that is a equal or a - * superset of the specified question */ - - LIST_FOREACH(transactions_by_scope, t, scope->transactions) { - - /* Refuse reusing transactions that completed based on - * cached data instead of a real packet, if that's - * requested. */ - if (!cache_ok && - IN_SET(t->state, DNS_TRANSACTION_SUCCESS, DNS_TRANSACTION_FAILURE) && - !t->received) - continue; + /* Try to find an ongoing transaction that is a equal to the + * specified question */ + t = hashmap_get(scope->transactions, key); + if (!t) + return NULL; - if (dns_resource_key_equal(t->key, key) > 0) - return t; - } + /* Refuse reusing transactions that completed based on cached + * data instead of a real packet, if that's requested. */ + if (!cache_ok && + IN_SET(t->state, DNS_TRANSACTION_SUCCESS, DNS_TRANSACTION_FAILURE) && + !t->received) + return NULL; - return NULL; + return t; } static int dns_scope_make_conflict_packet( diff --git a/src/resolve/resolved-dns-scope.h b/src/resolve/resolved-dns-scope.h index 47f285db47..88fb8224e2 100644 --- a/src/resolve/resolved-dns-scope.h +++ b/src/resolve/resolved-dns-scope.h @@ -60,7 +60,7 @@ struct DnsScope { usec_t resend_timeout; usec_t max_rtt; - LIST_HEAD(DnsTransaction, transactions); + Hashmap *transactions; LIST_FIELDS(DnsScope, scopes); }; diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index 81156dfa45..7b84c1bab8 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -35,7 +35,6 @@ DnsTransaction* dns_transaction_free(DnsTransaction *t) { sd_event_source_unref(t->timeout_event_source); - dns_resource_key_unref(t->key); dns_packet_unref(t->sent); dns_packet_unref(t->received); dns_answer_unref(t->cached); @@ -47,12 +46,14 @@ DnsTransaction* dns_transaction_free(DnsTransaction *t) { dns_stream_free(t->stream); if (t->scope) { - LIST_REMOVE(transactions_by_scope, t->scope->transactions, t); + hashmap_remove(t->scope->transactions, t->key); if (t->id != 0) hashmap_remove(t->scope->manager->dns_transactions, UINT_TO_PTR(t->id)); } + dns_resource_key_unref(t->key); + while ((q = set_steal_first(t->queries))) set_remove(q->transactions, t); set_free(t->queries); @@ -89,14 +90,18 @@ int dns_transaction_new(DnsTransaction **ret, DnsScope *s, DnsResourceKey *key) if (r < 0) return r; + r = hashmap_ensure_allocated(&s->transactions, &dns_resource_key_hash_ops); + if (r < 0) + return r; + t = new0(DnsTransaction, 1); if (!t) return -ENOMEM; t->dns_fd = -1; - t->key = dns_resource_key_ref(key); + /* Find a fresh, unused transaction id */ do random_bytes(&t->id, sizeof(t->id)); while (t->id == 0 || @@ -108,7 +113,12 @@ int dns_transaction_new(DnsTransaction **ret, DnsScope *s, DnsResourceKey *key) return r; } - LIST_PREPEND(transactions_by_scope, s->transactions, t); + r = hashmap_put(s->transactions, t->key, t); + if (r < 0) { + hashmap_remove(s->manager->dns_transactions, UINT_TO_PTR(t->id)); + return r; + } + t->scope = s; if (ret) @@ -176,9 +186,6 @@ void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) { assert(t); assert(!IN_SET(state, DNS_TRANSACTION_NULL, DNS_TRANSACTION_PENDING)); - if (!IN_SET(t->state, DNS_TRANSACTION_NULL, DNS_TRANSACTION_PENDING)) - return; - /* Note that this call might invalidate the query. Callers * should hence not attempt to access the query or transaction * after calling this function. */ @@ -253,10 +260,12 @@ static int dns_transaction_open_tcp(DnsTransaction *t) { if (t->stream) return 0; - if (t->scope->protocol == DNS_PROTOCOL_DNS) + switch (t->scope->protocol) { + case DNS_PROTOCOL_DNS: fd = dns_scope_tcp_socket(t->scope, AF_UNSPEC, NULL, 53, &server); - else if (t->scope->protocol == DNS_PROTOCOL_LLMNR) { + break; + case DNS_PROTOCOL_LLMNR: /* When we already received a reply to this (but it was truncated), send to its sender address */ if (t->received) fd = dns_scope_tcp_socket(t->scope, t->received->family, &t->received->sender, t->received->sender_port, NULL); @@ -274,12 +283,16 @@ static int dns_transaction_open_tcp(DnsTransaction *t) { if (r == 0) return -EINVAL; if (family != t->scope->family) - return -EAFNOSUPPORT; + return -ESRCH; fd = dns_scope_tcp_socket(t->scope, family, &address, LLMNR_PORT, NULL); } - } else + + break; + + default: return -EAFNOSUPPORT; + } if (fd < 0) return fd; @@ -335,7 +348,8 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { * should hence not attempt to access the query or transaction * after calling this function. */ - if (t->scope->protocol == DNS_PROTOCOL_LLMNR) { + switch (t->scope->protocol) { + case DNS_PROTOCOL_LLMNR: assert(t->scope->link); /* For LLMNR we will not accept any packets from other @@ -354,6 +368,14 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { dns_transaction_tentative(t, p); return; } + + break; + + case DNS_PROTOCOL_DNS: + break; + + default: + assert_not_reached("Invalid DNS protocol."); } if (t->received != p) { @@ -390,7 +412,7 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { break; default: - assert_not_reached("Invalid DNS protocol."); + break; } if (DNS_PACKET_TC(p)) { |