diff options
Diffstat (limited to 'src/resolve')
27 files changed, 388 insertions, 285 deletions
diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c index 12c17003e9..f0a3b607d4 100644 --- a/src/resolve/resolved-bus.c +++ b/src/resolve/resolved-bus.c @@ -19,9 +19,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" #include "bus-common-errors.h" #include "bus-util.h" - #include "dns-domain.h" #include "resolved-bus.h" #include "resolved-def.h" @@ -191,7 +191,7 @@ static void bus_method_resolve_hostname_complete(DnsQuery *q) { /* This has a cname? Then update the query with the * new cname. */ - r = dns_query_cname_redirect(q, cname->cname.name); + r = dns_query_cname_redirect(q, cname); if (r < 0) { if (r == -ELOOP) r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop on '%s'", q->request_hostname); @@ -220,8 +220,6 @@ static void bus_method_resolve_hostname_complete(DnsQuery *q) { added++; } - // what about the cache? - /* If we didn't find anything, then let's restart the * query, this time with the cname */ if (added <= 0) { diff --git a/src/resolve/resolved-conf.c b/src/resolve/resolved-conf.c index 7af63b0a82..9207719551 100644 --- a/src/resolve/resolved-conf.c +++ b/src/resolve/resolved-conf.c @@ -19,13 +19,15 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" #include "conf-parser.h" - +#include "def.h" +#include "extract-word.h" +#include "parse-util.h" #include "resolved-conf.h" +#include "string-util.h" int manager_parse_dns_server(Manager *m, DnsServerType type, const char *string) { - const char *word, *state; - size_t length; DnsServer *first; int r; @@ -34,19 +36,22 @@ int manager_parse_dns_server(Manager *m, DnsServerType type, const char *string) first = type == DNS_SERVER_FALLBACK ? m->fallback_dns_servers : m->dns_servers; - FOREACH_WORD_QUOTED(word, length, string, state) { - char buffer[length+1]; - int family; + for(;;) { + _cleanup_free_ char *word = NULL; union in_addr_union addr; bool found = false; DnsServer *s; + int family; - memcpy(buffer, word, length); - buffer[length] = 0; + r = extract_first_word(&string, &word, NULL, 0); + if (r < 0) + return log_error_errno(r, "Failed to parse resolved dns server syntax \"%s\": %m", string); + if (r == 0) + break; - r = in_addr_from_string_auto(buffer, &family, &addr); + r = in_addr_from_string_auto(word, &family, &addr); if (r < 0) { - log_warning("Ignoring invalid DNS address '%s'", buffer); + log_warning("Ignoring invalid DNS address '%s'", word); continue; } @@ -92,10 +97,10 @@ int config_parse_dnsv( /* Empty assignment means clear the list */ manager_flush_dns_servers(m, ltype); else { - /* Otherwise add to the list */ + /* Otherwise, add to the list */ r = manager_parse_dns_server(m, ltype, rvalue); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to parse DNS server string '%s'. Ignoring.", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse DNS server string '%s'. Ignoring.", rvalue); return 0; } } @@ -131,7 +136,7 @@ int config_parse_support( if (support < 0) { r = parse_boolean(rvalue); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to parse support level '%s'. Ignoring.", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse support level '%s'. Ignoring.", rvalue); return 0; } @@ -145,8 +150,8 @@ int config_parse_support( int manager_parse_config_file(Manager *m) { assert(m); - return config_parse_many("/etc/systemd/resolved.conf", - CONF_DIRS_NULSTR("systemd/resolved.conf"), + return config_parse_many(PKGSYSCONFDIR "/resolved.conf", + CONF_PATHS_NULSTR("systemd/resolved.conf.d"), "Resolve\0", config_item_perf_lookup, resolved_gperf_lookup, false, m); diff --git a/src/resolve/resolved-dns-answer.c b/src/resolve/resolved-dns-answer.c index 13ad4ca6bd..3cf9c68074 100644 --- a/src/resolve/resolved-dns-answer.c +++ b/src/resolve/resolved-dns-answer.c @@ -19,8 +19,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "resolved-dns-answer.h" +#include "alloc-util.h" #include "dns-domain.h" +#include "resolved-dns-answer.h" +#include "string-util.h" DnsAnswer *dns_answer_new(unsigned n) { DnsAnswer *a; @@ -149,6 +151,19 @@ int dns_answer_contains(DnsAnswer *a, DnsResourceKey *key) { return 0; } +int dns_answer_match_soa(DnsResourceKey *key, DnsResourceKey *soa) { + if (soa->class != DNS_CLASS_IN) + return 0; + + if (soa->type != DNS_TYPE_SOA) + return 0; + + if (!dns_name_endswith(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(soa))) + return 0; + + return 1; +} + int dns_answer_find_soa(DnsAnswer *a, DnsResourceKey *key, DnsResourceRecord **ret) { unsigned i; @@ -164,13 +179,7 @@ int dns_answer_find_soa(DnsAnswer *a, DnsResourceKey *key, DnsResourceRecord **r for (i = 0; i < a->n_rrs; i++) { - if (a->items[i].rr->key->class != DNS_CLASS_IN) - continue; - - if (a->items[i].rr->key->type != DNS_TYPE_SOA) - continue; - - if (dns_name_endswith(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(a->items[i].rr->key))) { + if (dns_answer_match_soa(key, a->items[i].rr->key)) { *ret = a->items[i].rr; return 1; } diff --git a/src/resolve/resolved-dns-answer.h b/src/resolve/resolved-dns-answer.h index 0757dd60d0..044d73b19c 100644 --- a/src/resolve/resolved-dns-answer.h +++ b/src/resolve/resolved-dns-answer.h @@ -49,6 +49,7 @@ DnsAnswer *dns_answer_unref(DnsAnswer *a); int dns_answer_add(DnsAnswer *a, DnsResourceRecord *rr, int ifindex); int dns_answer_add_soa(DnsAnswer *a, const char *name, uint32_t ttl); int dns_answer_contains(DnsAnswer *a, DnsResourceKey *key); +int dns_answer_match_soa(DnsResourceKey *key, DnsResourceKey *soa); int dns_answer_find_soa(DnsAnswer *a, DnsResourceKey *key, DnsResourceRecord **ret); DnsAnswer *dns_answer_merge(DnsAnswer *a, DnsAnswer *b); diff --git a/src/resolve/resolved-dns-cache.c b/src/resolve/resolved-dns-cache.c index cbbbed8c8a..04f64022e0 100644 --- a/src/resolve/resolved-dns-cache.c +++ b/src/resolve/resolved-dns-cache.c @@ -19,6 +19,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" #include "resolved-dns-cache.h" #include "resolved-dns-packet.h" @@ -277,13 +278,14 @@ static int dns_cache_put_positive( /* New TTL is 0? Delete the entry... */ if (rr->ttl <= 0) { - if (dns_cache_remove(c, rr->key)) { - r = dns_resource_key_to_string(rr->key, &key_str); - if (r < 0) - return r; + r = dns_resource_key_to_string(rr->key, &key_str); + if (r < 0) + return r; + if (dns_cache_remove(c, rr->key)) log_debug("Removed zero TTL entry from cache: %s", key_str); - } + else + log_debug("Not caching zero TTL cache entry: %s", key_str); return 0; } @@ -361,7 +363,7 @@ static int dns_cache_put_negative( if (r < 0) return r; - log_debug("Ignored negative cache entry with zero SOA TTL: %s", key_str); + log_debug("Not caching negative entry with zero SOA TTL: %s", key_str); return 0; } @@ -402,7 +404,7 @@ static int dns_cache_put_negative( int dns_cache_put( DnsCache *c, - DnsQuestion *q, + DnsResourceKey *key, int rcode, DnsAnswer *answer, unsigned max_rrs, @@ -410,16 +412,16 @@ int dns_cache_put( int owner_family, const union in_addr_union *owner_address) { + DnsResourceRecord *soa = NULL; unsigned cache_keys, i; int r; assert(c); - if (q) { - /* First, if we were passed a question, delete all matching old RRs, + if (key) { + /* First, if we were passed a key, 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]); + dns_cache_remove(c, key); } if (!answer) @@ -437,8 +439,8 @@ int dns_cache_put( cache_keys = answer->n_rrs; - if (q) - cache_keys += q->n_keys; + if (key) + cache_keys ++; /* Make some space for our new entries */ dns_cache_make_space(c, cache_keys); @@ -453,44 +455,63 @@ int dns_cache_put( goto fail; } - if (!q) + if (!key) return 0; - /* Third, add in negative entries for all keys with no RR */ - for (i = 0; i < q->n_keys; i++) { - DnsResourceRecord *soa = NULL; + /* Third, add in negative entries if the key has no RR */ + r = dns_answer_contains(answer, key); + if (r < 0) + goto fail; + if (r > 0) + return 0; - r = dns_answer_contains(answer, q->keys[i]); - if (r < 0) - goto fail; - if (r > 0) - continue; + /* See https://tools.ietf.org/html/rfc2308, which + * say that a matching SOA record in the packet + * is used to to enable negative caching. */ - /* See https://tools.ietf.org/html/rfc2308, which - * say that a matching SOA record in the packet - * is used to to enable negative caching. */ + r = dns_answer_find_soa(answer, key, &soa); + if (r < 0) + goto fail; + if (r == 0) + return 0; - r = dns_answer_find_soa(answer, q->keys[i], &soa); - if (r < 0) - goto fail; - if (r == 0) - continue; + /* Also, if the requested key is an alias, the negative response should + be cached for each name in the redirect chain. Any CNAME record in + the response is from the redirection chain, though only the final one + is guaranteed to be included. This means that we cannot verify the + chain and that we need to cache them all as it may be incomplete. */ + for (i = 0; i < answer->n_rrs; i++) { + DnsResourceRecord *answer_rr = answer->items[i].rr; - r = dns_cache_put_negative(c, q->keys[i], rcode, timestamp, MIN(soa->soa.minimum, soa->ttl), owner_family, owner_address); - if (r < 0) - goto fail; + if (answer_rr->key->type == DNS_TYPE_CNAME) { + _cleanup_(dns_resource_key_unrefp) DnsResourceKey *canonical_key = NULL; + + canonical_key = dns_resource_key_new_redirect(key, answer_rr); + if (!canonical_key) + goto fail; + + /* Let's not add negative cache entries for records outside the current zone. */ + if (!dns_answer_match_soa(canonical_key, soa->key)) + continue; + + r = dns_cache_put_negative(c, canonical_key, rcode, timestamp, MIN(soa->soa.minimum, soa->ttl), owner_family, owner_address); + if (r < 0) + goto fail; + } } + r = dns_cache_put_negative(c, key, rcode, timestamp, MIN(soa->soa.minimum, soa->ttl), owner_family, owner_address); + if (r < 0) + goto fail; + return 0; fail: /* Adding all RRs failed. Let's clean up what we already * added, just in case */ - if (q) { - for (i = 0; i < q->n_keys; i++) - dns_cache_remove(c, q->keys[i]); - } + if (key) + dns_cache_remove(c, key); for (i = 0; i < answer->n_rrs; i++) dns_cache_remove(c, answer->items[i].rr->key); @@ -498,6 +519,29 @@ fail: return r; } +static DnsCacheItem *dns_cache_get_by_key_follow_cname(DnsCache *c, DnsResourceKey *k) { + _cleanup_(dns_resource_key_unrefp) DnsResourceKey *cname_key = NULL; + DnsCacheItem *i, *j; + + assert(c); + assert(k); + + i = hashmap_get(c->by_key, k); + if (i || k->type == DNS_TYPE_CNAME) + return i; + + /* check if we have a CNAME record instead */ + cname_key = dns_resource_key_new_cname(k); + if (!cname_key) + return NULL; + + j = hashmap_get(c->by_key, cname_key); + if (j) + return j; + + return i; +} + int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **ret) { _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; unsigned n = 0; @@ -527,7 +571,7 @@ int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **r return 0; } - first = hashmap_get(c->by_key, key); + first = dns_cache_get_by_key_follow_cname(c, key); if (!first) { /* If one question cannot be answered we need to refresh */ diff --git a/src/resolve/resolved-dns-cache.h b/src/resolve/resolved-dns-cache.h index 1225e58de4..164435b4fb 100644 --- a/src/resolve/resolved-dns-cache.h +++ b/src/resolve/resolved-dns-cache.h @@ -23,23 +23,23 @@ #include "hashmap.h" +#include "list.h" #include "prioq.h" #include "time-util.h" -#include "list.h" typedef struct DnsCache { Hashmap *by_key; Prioq *by_expiry; } DnsCache; -#include "resolved-dns-rr.h" -#include "resolved-dns-question.h" #include "resolved-dns-answer.h" +#include "resolved-dns-question.h" +#include "resolved-dns-rr.h" void dns_cache_flush(DnsCache *c); void dns_cache_prune(DnsCache *c); -int dns_cache_put(DnsCache *c, DnsQuestion *q, int rcode, DnsAnswer *answer, unsigned max_rrs, usec_t timestamp, int owner_family, const union in_addr_union *owner_address); +int dns_cache_put(DnsCache *c, DnsResourceKey *key, int rcode, DnsAnswer *answer, unsigned max_rrs, usec_t timestamp, int owner_family, const union in_addr_union *owner_address); int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **answer); int dns_cache_check_conflicts(DnsCache *cache, DnsResourceRecord *rr, int owner_family, const union in_addr_union *owner_address); diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c index bebd1ee4a6..f23b3cf893 100644 --- a/src/resolve/resolved-dns-packet.c +++ b/src/resolve/resolved-dns-packet.c @@ -19,12 +19,14 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "utf8.h" -#include "util.h" -#include "strv.h" -#include "unaligned.h" +#include "alloc-util.h" #include "dns-domain.h" #include "resolved-dns-packet.h" +#include "string-table.h" +#include "strv.h" +#include "unaligned.h" +#include "utf8.h" +#include "util.h" int dns_packet_new(DnsPacket **ret, DnsProtocol protocol, size_t mtu) { DnsPacket *p; diff --git a/src/resolve/resolved-dns-packet.h b/src/resolve/resolved-dns-packet.h index fbbabaf232..73803e4e82 100644 --- a/src/resolve/resolved-dns-packet.h +++ b/src/resolve/resolved-dns-packet.h @@ -21,21 +21,21 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <netinet/udp.h> #include <netinet/ip.h> +#include <netinet/udp.h> -#include "macro.h" -#include "sparse-endian.h" #include "hashmap.h" #include "in-addr-util.h" +#include "macro.h" +#include "sparse-endian.h" typedef struct DnsPacketHeader DnsPacketHeader; typedef struct DnsPacket DnsPacket; -#include "resolved-dns-rr.h" -#include "resolved-dns-question.h" -#include "resolved-dns-answer.h" #include "resolved-def.h" +#include "resolved-dns-answer.h" +#include "resolved-dns-question.h" +#include "resolved-dns-rr.h" typedef enum DnsProtocol { DNS_PROTOCOL_DNS, diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c index c0b4c8ba81..f7cb84e2a6 100644 --- a/src/resolve/resolved-dns-query.c +++ b/src/resolve/resolved-dns-query.c @@ -19,10 +19,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "hostname-util.h" +#include "alloc-util.h" #include "dns-domain.h" +#include "hostname-util.h" #include "local-addresses.h" - #include "resolved-dns-query.h" /* How long to wait for the query in total */ @@ -831,7 +831,7 @@ void dns_query_ready(DnsQuery *q) { dns_query_complete(q, state); } -int dns_query_cname_redirect(DnsQuery *q, const char *name) { +int dns_query_cname_redirect(DnsQuery *q, const DnsResourceRecord *cname) { _cleanup_(dns_question_unrefp) DnsQuestion *nq = NULL; int r; @@ -840,7 +840,7 @@ int dns_query_cname_redirect(DnsQuery *q, const char *name) { if (q->n_cname_redirects > CNAME_MAX) return -ELOOP; - r = dns_question_cname_redirect(q->question, name, &nq); + r = dns_question_cname_redirect(q->question, cname, &nq); if (r < 0) return r; diff --git a/src/resolve/resolved-dns-query.h b/src/resolve/resolved-dns-query.h index 93d49301fa..2c28a7e284 100644 --- a/src/resolve/resolved-dns-query.h +++ b/src/resolve/resolved-dns-query.h @@ -23,12 +23,13 @@ #include "sd-bus.h" + #include "set.h" typedef struct DnsQuery DnsQuery; -#include "resolved-dns-question.h" #include "resolved-dns-answer.h" +#include "resolved-dns-question.h" #include "resolved-dns-stream.h" struct DnsQuery { @@ -72,7 +73,7 @@ DnsQuery *dns_query_free(DnsQuery *q); int dns_query_go(DnsQuery *q); void dns_query_ready(DnsQuery *q); -int dns_query_cname_redirect(DnsQuery *q, const char *name); +int dns_query_cname_redirect(DnsQuery *q, const DnsResourceRecord *cname); int dns_query_bus_track(DnsQuery *q, sd_bus_message *m); diff --git a/src/resolve/resolved-dns-question.c b/src/resolve/resolved-dns-question.c index c94928d725..48951221dc 100644 --- a/src/resolve/resolved-dns-question.c +++ b/src/resolve/resolved-dns-question.c @@ -19,8 +19,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "resolved-dns-question.h" +#include "alloc-util.h" #include "dns-domain.h" +#include "resolved-dns-question.h" DnsQuestion *dns_question_new(unsigned n) { DnsQuestion *q; @@ -242,13 +243,13 @@ int dns_question_is_equal(DnsQuestion *a, DnsQuestion *b) { return 1; } -int dns_question_cname_redirect(DnsQuestion *q, const char *name, DnsQuestion **ret) { +int dns_question_cname_redirect(DnsQuestion *q, const DnsResourceRecord *cname, DnsQuestion **ret) { _cleanup_(dns_question_unrefp) DnsQuestion *n = NULL; bool same = true; unsigned i; int r; - assert(name); + assert(cname); assert(ret); if (!q) { @@ -262,7 +263,7 @@ int dns_question_cname_redirect(DnsQuestion *q, const char *name, DnsQuestion ** } for (i = 0; i < q->n_keys; i++) { - r = dns_name_equal(DNS_RESOURCE_KEY_NAME(q->keys[i]), name); + r = dns_name_equal(DNS_RESOURCE_KEY_NAME(q->keys[i]), cname->cname.name); if (r < 0) return r; @@ -286,7 +287,7 @@ int dns_question_cname_redirect(DnsQuestion *q, const char *name, DnsQuestion ** for (i = 0; i < q->n_keys; i++) { _cleanup_(dns_resource_key_unrefp) DnsResourceKey *k = NULL; - k = dns_resource_key_new(q->keys[i]->class, q->keys[i]->type, name); + k = dns_resource_key_new_redirect(q->keys[i], cname); if (!k) return -ENOMEM; diff --git a/src/resolve/resolved-dns-question.h b/src/resolve/resolved-dns-question.h index 77de0c7a2c..13cd1f20f3 100644 --- a/src/resolve/resolved-dns-question.h +++ b/src/resolve/resolved-dns-question.h @@ -46,6 +46,6 @@ int dns_question_is_superset(DnsQuestion *q, DnsQuestion *other); int dns_question_contains(DnsQuestion *a, DnsResourceKey *k); int dns_question_is_equal(DnsQuestion *a, DnsQuestion *b); -int dns_question_cname_redirect(DnsQuestion *q, const char *name, DnsQuestion **ret); +int dns_question_cname_redirect(DnsQuestion *q, const DnsResourceRecord *cname, DnsQuestion **ret); DEFINE_TRIVIAL_CLEANUP_FUNC(DnsQuestion*, dns_question_unref); diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c index f31644eebc..ba2ea686f3 100644 --- a/src/resolve/resolved-dns-rr.c +++ b/src/resolve/resolved-dns-rr.c @@ -21,12 +21,14 @@ #include <math.h> -#include "strv.h" - +#include "alloc-util.h" #include "dns-domain.h" -#include "resolved-dns-rr.h" -#include "resolved-dns-packet.h" #include "dns-type.h" +#include "hexdecoct.h" +#include "resolved-dns-packet.h" +#include "resolved-dns-rr.h" +#include "string-util.h" +#include "strv.h" DnsResourceKey* dns_resource_key_new(uint16_t class, uint16_t type, const char *name) { DnsResourceKey *k; @@ -48,6 +50,19 @@ DnsResourceKey* dns_resource_key_new(uint16_t class, uint16_t type, const char * return k; } +DnsResourceKey* dns_resource_key_new_cname(const DnsResourceKey *key) { + assert(key); + + return dns_resource_key_new(key->class, DNS_TYPE_CNAME, DNS_RESOURCE_KEY_NAME(key)); +} + +DnsResourceKey* dns_resource_key_new_redirect(const DnsResourceKey *key, const DnsResourceRecord *cname) { + assert(key); + assert(cname); + + return dns_resource_key_new(key->class, key->type, cname->cname.name); +} + DnsResourceKey* dns_resource_key_new_consume(uint16_t class, uint16_t type, char *name) { DnsResourceKey *k; @@ -133,15 +148,14 @@ int dns_resource_key_match_cname(const DnsResourceKey *key, const DnsResourceRec return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(key)); } -static unsigned long dns_resource_key_hash_func(const void *i, const uint8_t hash_key[HASH_KEY_SIZE]) { +static void dns_resource_key_hash_func(const void *i, struct siphash *state) { const DnsResourceKey *k = i; - unsigned long ul; - ul = dns_name_hash_func(DNS_RESOURCE_KEY_NAME(k), hash_key); - ul = ul * hash_key[0] + ul + k->class; - ul = ul * hash_key[1] + ul + k->type; + assert(k); - return ul; + dns_name_hash_func(DNS_RESOURCE_KEY_NAME(k), state); + siphash24_compress(&k->class, sizeof(k->class), state); + siphash24_compress(&k->type, sizeof(k->type), state); } static int dns_resource_key_compare_func(const void *a, const void *b) { diff --git a/src/resolve/resolved-dns-rr.h b/src/resolve/resolved-dns-rr.h index 8986a298af..a23546f757 100644 --- a/src/resolve/resolved-dns-rr.h +++ b/src/resolve/resolved-dns-rr.h @@ -24,9 +24,9 @@ #include <netinet/in.h> #include "bitmap.h" +#include "dns-type.h" #include "hashmap.h" #include "in-addr-util.h" -#include "dns-type.h" typedef struct DnsResourceKey DnsResourceKey; typedef struct DnsResourceRecord DnsResourceRecord; @@ -177,6 +177,8 @@ static inline const char* DNS_RESOURCE_KEY_NAME(const DnsResourceKey *key) { } DnsResourceKey* dns_resource_key_new(uint16_t class, uint16_t type, const char *name); +DnsResourceKey* dns_resource_key_new_cname(const DnsResourceKey *key); +DnsResourceKey* dns_resource_key_new_redirect(const DnsResourceKey *key, const DnsResourceRecord *cname); DnsResourceKey* dns_resource_key_new_consume(uint16_t class, uint16_t type, char *name); DnsResourceKey* dns_resource_key_ref(DnsResourceKey *key); DnsResourceKey* dns_resource_key_unref(DnsResourceKey *key); diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index 9e6f595a1b..873d76e40c 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -21,15 +21,17 @@ #include <netinet/tcp.h> -#include "missing.h" -#include "strv.h" -#include "socket-util.h" #include "af-list.h" -#include "random-util.h" -#include "hostname-util.h" +#include "alloc-util.h" #include "dns-domain.h" -#include "resolved-llmnr.h" +#include "fd-util.h" +#include "hostname-util.h" +#include "missing.h" +#include "random-util.h" #include "resolved-dns-scope.h" +#include "resolved-llmnr.h" +#include "socket-util.h" +#include "strv.h" #define MULTICAST_RATELIMIT_INTERVAL_USEC (1*USEC_PER_SEC) #define MULTICAST_RATELIMIT_BURST 1000 @@ -541,6 +543,7 @@ static void dns_scope_verify_conflicts(DnsScope *s, DnsPacket *p) { void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) { _cleanup_(dns_packet_unrefp) DnsPacket *reply = NULL; _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL; + DnsResourceKey *key = NULL; bool tentative = false; int r, fd; @@ -574,7 +577,10 @@ void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) { return; } - r = dns_zone_lookup(&s->zone, p->question, &answer, &soa, &tentative); + assert(p->question->n_keys == 1); + key = p->question->keys[0]; + + r = dns_zone_lookup(&s->zone, key, &answer, &soa, &tentative); if (r < 0) { log_debug_errno(r, "Failed to lookup key: %m"); return; diff --git a/src/resolve/resolved-dns-scope.h b/src/resolve/resolved-dns-scope.h index b75f212897..f9b2bfda9d 100644 --- a/src/resolve/resolved-dns-scope.h +++ b/src/resolve/resolved-dns-scope.h @@ -25,9 +25,9 @@ typedef struct DnsScope DnsScope; -#include "resolved-dns-server.h" -#include "resolved-dns-packet.h" #include "resolved-dns-cache.h" +#include "resolved-dns-packet.h" +#include "resolved-dns-server.h" #include "resolved-dns-zone.h" #include "resolved-link.h" diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c index 2ff5b192df..e803f635ab 100644 --- a/src/resolve/resolved-dns-server.c +++ b/src/resolve/resolved-dns-server.c @@ -19,9 +19,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "siphash24.h" - +#include "alloc-util.h" #include "resolved-dns-server.h" +#include "siphash24.h" /* After how much time to repeat classic DNS requests */ #define DNS_TIMEOUT_MIN_USEC (500 * USEC_PER_MSEC) @@ -137,14 +137,13 @@ void dns_server_packet_lost(DnsServer *s, usec_t usec) { s->resend_timeout = MIN(s->resend_timeout * 2, DNS_TIMEOUT_MAX_USEC); } -static unsigned long dns_server_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) { +static void dns_server_hash_func(const void *p, struct siphash *state) { const DnsServer *s = p; - uint64_t u; - siphash24((uint8_t*) &u, &s->address, FAMILY_ADDRESS_SIZE(s->family), hash_key); - u = u * hash_key[0] + u + s->family; + assert(s); - return u; + siphash24_compress(&s->family, sizeof(s->family), state); + siphash24_compress(&s->address, FAMILY_ADDRESS_SIZE(s->family), state); } static int dns_server_compare_func(const void *a, const void *b) { diff --git a/src/resolve/resolved-dns-stream.c b/src/resolve/resolved-dns-stream.c index 7f47e7223a..1c501182fb 100644 --- a/src/resolve/resolved-dns-stream.c +++ b/src/resolve/resolved-dns-stream.c @@ -21,6 +21,9 @@ #include <netinet/tcp.h> +#include "alloc-util.h" +#include "fd-util.h" +#include "io-util.h" #include "missing.h" #include "resolved-dns-stream.h" diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index 8092bb514d..37f47c47c0 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -20,11 +20,13 @@ ***/ #include "af-list.h" - -#include "resolved-llmnr.h" -#include "resolved-dns-transaction.h" -#include "random-util.h" +#include "alloc-util.h" #include "dns-domain.h" +#include "fd-util.h" +#include "random-util.h" +#include "resolved-dns-transaction.h" +#include "resolved-llmnr.h" +#include "string-table.h" DnsTransaction* dns_transaction_free(DnsTransaction *t) { DnsQuery *q; @@ -458,7 +460,7 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { } /* According to RFC 4795, section 2.9. only the RRs from the answer section shall be cached */ - dns_cache_put(&t->scope->cache, p->question, DNS_PACKET_RCODE(p), p->answer, DNS_PACKET_ANCOUNT(p), 0, p->family, &p->sender); + dns_cache_put(&t->scope->cache, t->key, DNS_PACKET_RCODE(p), p->answer, DNS_PACKET_ANCOUNT(p), 0, p->family, &p->sender); if (DNS_PACKET_RCODE(p) == DNS_RCODE_SUCCESS) dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS); @@ -624,6 +626,20 @@ int dns_transaction_go(DnsTransaction *t) { t->cached = dns_answer_unref(t->cached); t->cached_rcode = 0; + /* Check the zone, but obly if this transaction is not used + * for probing or verifying a zone item. */ + if (set_isempty(t->zone_items)) { + + r = dns_zone_lookup(&t->scope->zone, t->key, &t->cached, NULL, NULL); + if (r < 0) + return r; + if (r > 0) { + t->cached_rcode = DNS_RCODE_SUCCESS; + dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS); + return 0; + } + } + /* Check the cache, but only if this transaction is not used * for probing or verifying a zone item. */ if (set_isempty(t->zone_items)) { diff --git a/src/resolve/resolved-dns-transaction.h b/src/resolve/resolved-dns-transaction.h index acf6a6f651..d0970bd695 100644 --- a/src/resolve/resolved-dns-transaction.h +++ b/src/resolve/resolved-dns-transaction.h @@ -39,10 +39,10 @@ enum DnsTransactionState { _DNS_TRANSACTION_STATE_INVALID = -1 }; -#include "resolved-dns-scope.h" +#include "resolved-dns-answer.h" #include "resolved-dns-packet.h" #include "resolved-dns-question.h" -#include "resolved-dns-answer.h" +#include "resolved-dns-scope.h" struct DnsTransaction { DnsScope *scope; diff --git a/src/resolve/resolved-dns-zone.c b/src/resolve/resolved-dns-zone.c index 674bb6af28..a021ecb93d 100644 --- a/src/resolve/resolved-dns-zone.c +++ b/src/resolve/resolved-dns-zone.c @@ -19,11 +19,12 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "list.h" - -#include "resolved-dns-zone.h" +#include "alloc-util.h" #include "dns-domain.h" +#include "list.h" #include "resolved-dns-packet.h" +#include "resolved-dns-zone.h" +#include "string-util.h" /* Never allow more than 1K entries */ #define ZONE_MAX 1024 @@ -90,11 +91,8 @@ void dns_zone_flush(DnsZone *z) { assert(hashmap_size(z->by_key) == 0); assert(hashmap_size(z->by_name) == 0); - hashmap_free(z->by_key); - z->by_key = NULL; - - hashmap_free(z->by_name); - z->by_name = NULL; + z->by_key = hashmap_free(z->by_key); + z->by_name = hashmap_free(z->by_name); } static DnsZoneItem* dns_zone_get(DnsZone *z, DnsResourceRecord *rr) { @@ -285,97 +283,76 @@ int dns_zone_put(DnsZone *z, DnsScope *s, DnsResourceRecord *rr, bool probe) { return 0; } -int dns_zone_lookup(DnsZone *z, DnsQuestion *q, DnsAnswer **ret_answer, DnsAnswer **ret_soa, bool *ret_tentative) { +int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, DnsAnswer **ret_answer, DnsAnswer **ret_soa, bool *ret_tentative) { _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL; - unsigned i, n_answer = 0, n_soa = 0; - bool tentative = true; + unsigned n_answer = 0; + DnsZoneItem *j, *first; + bool tentative = true, need_soa = false; int r; assert(z); - assert(q); + assert(key); assert(ret_answer); - assert(ret_soa); - if (q->n_keys <= 0) { - *ret_answer = NULL; - *ret_soa = NULL; + /* First iteration, count what we have */ - if (ret_tentative) - *ret_tentative = false; + if (key->type == DNS_TYPE_ANY || key->class == DNS_CLASS_ANY) { + bool found = false, added = false; + int k; - return 0; - } + /* If this is a generic match, then we have to + * go through the list by the name and look + * for everything manually */ - /* First iteration, count what we have */ - for (i = 0; i < q->n_keys; i++) { - DnsZoneItem *j, *first; - - if (q->keys[i]->type == DNS_TYPE_ANY || - q->keys[i]->class == DNS_CLASS_ANY) { - bool found = false, added = false; - int k; + first = hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(key)); + LIST_FOREACH(by_name, j, first) { + if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING)) + continue; - /* If this is a generic match, then we have to - * go through the list by the name and look - * for everything manually */ + found = true; - first = hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(q->keys[i])); - LIST_FOREACH(by_name, j, first) { - if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING)) - continue; + k = dns_resource_key_match_rr(key, j->rr); + if (k < 0) + return k; + if (k > 0) { + n_answer++; + added = true; + } - found = true; + } - k = dns_resource_key_match_rr(q->keys[i], j->rr); - if (k < 0) - return k; - if (k > 0) { - n_answer++; - added = true; - } + if (found && !added) + need_soa = true; - } + } else { + bool found = false; - if (found && !added) - n_soa++; + /* If this is a specific match, then look for + * the right key immediately */ - } else { - bool found = false; + first = hashmap_get(z->by_key, key); + LIST_FOREACH(by_key, j, first) { + if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING)) + continue; - /* If this is a specific match, then look for - * the right key immediately */ + found = true; + n_answer++; + } - first = hashmap_get(z->by_key, q->keys[i]); - LIST_FOREACH(by_key, j, first) { + if (!found) { + first = hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(key)); + LIST_FOREACH(by_name, j, first) { if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING)) continue; - found = true; - n_answer++; - } - - if (!found) { - first = hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(q->keys[i])); - LIST_FOREACH(by_name, j, first) { - if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING)) - continue; - - n_soa++; - break; - } + need_soa = true; + break; } } } - if (n_answer <= 0 && n_soa <= 0) { - *ret_answer = NULL; - *ret_soa = NULL; - - if (ret_tentative) - *ret_tentative = false; - - return 0; - } + if (n_answer <= 0 && !need_soa) + goto return_empty; if (n_answer > 0) { answer = dns_answer_new(n_answer); @@ -383,99 +360,113 @@ int dns_zone_lookup(DnsZone *z, DnsQuestion *q, DnsAnswer **ret_answer, DnsAnswe return -ENOMEM; } - if (n_soa > 0) { - soa = dns_answer_new(n_soa); + if (need_soa) { + soa = dns_answer_new(1); if (!soa) return -ENOMEM; } /* Second iteration, actually add the RRs to the answers */ - for (i = 0; i < q->n_keys; i++) { - DnsZoneItem *j, *first; - - if (q->keys[i]->type == DNS_TYPE_ANY || - q->keys[i]->class == DNS_CLASS_ANY) { - bool found = false, added = false; - int k; - - first = hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(q->keys[i])); - LIST_FOREACH(by_name, j, first) { - if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING)) - continue; + if (key->type == DNS_TYPE_ANY || key->class == DNS_CLASS_ANY) { + bool found = false, added = false; + int k; - found = true; - - if (j->state != DNS_ZONE_ITEM_PROBING) - tentative = false; + first = hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(key)); + LIST_FOREACH(by_name, j, first) { + if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING)) + continue; - k = dns_resource_key_match_rr(q->keys[i], j->rr); - if (k < 0) - return k; - if (k > 0) { - r = dns_answer_add(answer, j->rr, 0); - if (r < 0) - return r; + found = true; - added = true; - } - } + if (j->state != DNS_ZONE_ITEM_PROBING) + tentative = false; - if (found && !added) { - r = dns_answer_add_soa(soa, DNS_RESOURCE_KEY_NAME(q->keys[i]), LLMNR_DEFAULT_TTL); + k = dns_resource_key_match_rr(key, j->rr); + if (k < 0) + return k; + if (k > 0) { + r = dns_answer_add(answer, j->rr, 0); if (r < 0) return r; + + added = true; } - } else { - bool found = false; + } - first = hashmap_get(z->by_key, q->keys[i]); - LIST_FOREACH(by_key, j, first) { - if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING)) - continue; + if (found && !added) { + r = dns_answer_add_soa(soa, DNS_RESOURCE_KEY_NAME(key), LLMNR_DEFAULT_TTL); + if (r < 0) + return r; + } + } else { + bool found = false; - found = true; + first = hashmap_get(z->by_key, key); + LIST_FOREACH(by_key, j, first) { + if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING)) + continue; - if (j->state != DNS_ZONE_ITEM_PROBING) - tentative = false; + found = true; - r = dns_answer_add(answer, j->rr, 0); - if (r < 0) - return r; - } + if (j->state != DNS_ZONE_ITEM_PROBING) + tentative = false; - if (!found) { - bool add_soa = false; + r = dns_answer_add(answer, j->rr, 0); + if (r < 0) + return r; + } + + if (!found) { + bool add_soa = false; - first = hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(q->keys[i])); - LIST_FOREACH(by_name, j, first) { - if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING)) - continue; + first = hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(key)); + LIST_FOREACH(by_name, j, first) { + if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING)) + continue; - if (j->state != DNS_ZONE_ITEM_PROBING) - tentative = false; + if (j->state != DNS_ZONE_ITEM_PROBING) + tentative = false; - add_soa = true; - } + add_soa = true; + } - if (add_soa) { - r = dns_answer_add_soa(soa, DNS_RESOURCE_KEY_NAME(q->keys[i]), LLMNR_DEFAULT_TTL); - if (r < 0) - return r; - } + if (add_soa) { + r = dns_answer_add_soa(soa, DNS_RESOURCE_KEY_NAME(key), LLMNR_DEFAULT_TTL); + if (r < 0) + return r; } } } + /* If the caller sets ret_tentative to NULL, then use this as + * indication to not return tentative entries */ + + if (!ret_tentative && tentative) + goto return_empty; + *ret_answer = answer; answer = NULL; - *ret_soa = soa; - soa = NULL; + if (ret_soa) { + *ret_soa = soa; + soa = NULL; + } if (ret_tentative) *ret_tentative = tentative; return 1; + +return_empty: + *ret_answer = NULL; + + if (ret_soa) + *ret_soa = NULL; + + if (ret_tentative) + *ret_tentative = false; + + return 0; } void dns_zone_item_conflict(DnsZoneItem *i) { diff --git a/src/resolve/resolved-dns-zone.h b/src/resolve/resolved-dns-zone.h index 495d17cdb1..44a8624c30 100644 --- a/src/resolve/resolved-dns-zone.h +++ b/src/resolve/resolved-dns-zone.h @@ -31,9 +31,9 @@ typedef struct DnsZone { typedef struct DnsZoneItem DnsZoneItem; typedef enum DnsZoneItemState DnsZoneItemState; -#include "resolved-dns-rr.h" -#include "resolved-dns-question.h" #include "resolved-dns-answer.h" +#include "resolved-dns-question.h" +#include "resolved-dns-rr.h" #include "resolved-dns-transaction.h" /* RFC 4795 Section 2.8. suggests a TTL of 30s by default */ @@ -67,7 +67,7 @@ void dns_zone_flush(DnsZone *z); int dns_zone_put(DnsZone *z, DnsScope *s, DnsResourceRecord *rr, bool probe); void dns_zone_remove_rr(DnsZone *z, DnsResourceRecord *rr); -int dns_zone_lookup(DnsZone *z, DnsQuestion *q, DnsAnswer **answer, DnsAnswer **soa, bool *tentative); +int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, DnsAnswer **answer, DnsAnswer **soa, bool *tentative); void dns_zone_item_conflict(DnsZoneItem *i); void dns_zone_item_ready(DnsZoneItem *i); diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c index 47f461a37d..2892641075 100644 --- a/src/resolve/resolved-link.c +++ b/src/resolve/resolved-link.c @@ -22,9 +22,13 @@ #include <net/if.h> #include "sd-network.h" -#include "strv.h" + +#include "alloc-util.h" #include "missing.h" +#include "parse-util.h" #include "resolved-link.h" +#include "string-util.h" +#include "strv.h" int link_new(Manager *m, Link **ret, int ifindex) { _cleanup_(link_freep) Link *l = NULL; @@ -238,8 +242,7 @@ static int link_update_domains(Link *l) { if (!l->unicast_scope) return 0; - strv_free(l->unicast_scope->domains); - l->unicast_scope->domains = NULL; + l->unicast_scope->domains = strv_free(l->unicast_scope->domains); r = sd_network_link_get_domains(l->ifindex, &l->unicast_scope->domains); diff --git a/src/resolve/resolved-llmnr.c b/src/resolve/resolved-llmnr.c index 8afaf8db6e..6a7ff9d245 100644 --- a/src/resolve/resolved-llmnr.c +++ b/src/resolve/resolved-llmnr.c @@ -19,11 +19,12 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <resolv.h> #include <netinet/in.h> +#include <resolv.h> -#include "resolved-manager.h" +#include "fd-util.h" #include "resolved-llmnr.h" +#include "resolved-manager.h" void manager_llmnr_stop(Manager *m) { assert(m); diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index de924e3ed9..a588538b52 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -19,26 +19,31 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <netinet/in.h> +#include <poll.h> #include <resolv.h> #include <sys/ioctl.h> -#include <poll.h> -#include <netinet/in.h> -#include "netlink-util.h" -#include "network-internal.h" -#include "socket-util.h" #include "af-list.h" -#include "utf8.h" +#include "alloc-util.h" +#include "dns-domain.h" +#include "fd-util.h" #include "fileio-label.h" +#include "hostname-util.h" +#include "io-util.h" +#include "netlink-util.h" +#include "network-internal.h" #include "ordered-set.h" +#include "parse-util.h" #include "random-util.h" -#include "hostname-util.h" - -#include "dns-domain.h" -#include "resolved-conf.h" #include "resolved-bus.h" -#include "resolved-manager.h" +#include "resolved-conf.h" #include "resolved-llmnr.h" +#include "resolved-manager.h" +#include "socket-util.h" +#include "string-table.h" +#include "string-util.h" +#include "utf8.h" #define SEND_TIMEOUT_USEC (200 * USEC_PER_MSEC) diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h index fe7fe99505..074ce6c63d 100644 --- a/src/resolve/resolved-manager.h +++ b/src/resolve/resolved-manager.h @@ -22,10 +22,11 @@ ***/ #include "sd-event.h" -#include "sd-network.h" #include "sd-netlink.h" -#include "list.h" +#include "sd-network.h" + #include "hashmap.h" +#include "list.h" typedef struct Manager Manager; typedef enum Support Support; diff --git a/src/resolve/resolved.c b/src/resolve/resolved.c index 32e61af925..7ba0546f4a 100644 --- a/src/resolve/resolved.c +++ b/src/resolve/resolved.c @@ -19,15 +19,16 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "sd-event.h" #include "sd-daemon.h" +#include "sd-event.h" + +#include "capability-util.h" #include "mkdir.h" -#include "capability.h" +#include "resolved-conf.h" +#include "resolved-manager.h" #include "selinux-util.h" #include "signal-util.h" - -#include "resolved-manager.h" -#include "resolved-conf.h" +#include "user-util.h" int main(int argc, char *argv[]) { _cleanup_(manager_freep) Manager *m = NULL; |