1
0
mirror of https://github.com/systemd/systemd.git synced 2024-11-01 00:51:24 +03:00

Merge pull request #17823 from poettering/resolved-just-bypass

resolved: just the dnssec bypass logic
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2021-02-11 00:10:25 +01:00 committed by GitHub
commit 39755e0014
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 1686 additions and 637 deletions

View File

@ -75,6 +75,7 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = {
SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_LINK, ENXIO),
SD_BUS_ERROR_MAP(BUS_ERROR_LINK_BUSY, EBUSY),
SD_BUS_ERROR_MAP(BUS_ERROR_NETWORK_DOWN, ENETDOWN),
SD_BUS_ERROR_MAP(BUS_ERROR_NO_SOURCE, ESRCH),
SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_DNSSD_SERVICE, ENOENT),
SD_BUS_ERROR_MAP(BUS_ERROR_DNSSD_SERVICE_EXISTS, EEXIST),

View File

@ -73,6 +73,7 @@
#define BUS_ERROR_NO_SUCH_LINK "org.freedesktop.resolve1.NoSuchLink"
#define BUS_ERROR_LINK_BUSY "org.freedesktop.resolve1.LinkBusy"
#define BUS_ERROR_NETWORK_DOWN "org.freedesktop.resolve1.NetworkDown"
#define BUS_ERROR_NO_SOURCE "org.freedesktop.resolve1.NoSource"
#define BUS_ERROR_NO_SUCH_DNSSD_SERVICE "org.freedesktop.resolve1.NoSuchDnssdService"
#define BUS_ERROR_DNSSD_SERVICE_EXISTS "org.freedesktop.resolve1.DnssdServiceExists"
#define _BUS_ERROR_DNS "org.freedesktop.resolve1.DnsError."

View File

@ -101,6 +101,9 @@ static int reply_query_state(DnsQuery *q) {
* thus quickly know that we cannot resolve an in-addr.arpa or ip6.arpa address. */
return sd_bus_reply_method_errorf(q->bus_request, _BUS_ERROR_DNS "NXDOMAIN", "'%s' not found", dns_query_string(q));
case DNS_TRANSACTION_NO_SOURCE:
return sd_bus_reply_method_errorf(q->bus_request, BUS_ERROR_NO_SOURCE, "All suitable resolution sources turned off");
case DNS_TRANSACTION_RCODE_FAILURE: {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
@ -274,8 +277,8 @@ static int validate_and_mangle_flags(
*
* 1. Checks that the interface index is either 0 (meaning *all* interfaces) or positive
*
* 2. Only the protocols flags and the NO_CNAME flag are set, at most. Plus additional flags specific
* to our method, passed in the "ok" parameter.
* 2. Only the protocols flags and a bunch of NO_XYZ flags are set, at most. Plus additional flags
* specific to our method, passed in the "ok" parameter.
*
* 3. If zero protocol flags are specified it is automatically turned into *all* protocols. This way
* clients can simply pass 0 as flags and all will work as it should. They can also use this so
@ -283,7 +286,15 @@ static int validate_and_mangle_flags(
* to mean "all supported protocols".
*/
if (*flags & ~(SD_RESOLVED_PROTOCOLS_ALL|SD_RESOLVED_NO_CNAME|ok))
if (*flags & ~(SD_RESOLVED_PROTOCOLS_ALL|
SD_RESOLVED_NO_CNAME|
SD_RESOLVED_NO_VALIDATE|
SD_RESOLVED_NO_SYNTHESIZE|
SD_RESOLVED_NO_CACHE|
SD_RESOLVED_NO_ZONE|
SD_RESOLVED_NO_TRUST_ANCHOR|
SD_RESOLVED_NO_NETWORK|
ok))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid flags parameter");
if ((*flags & SD_RESOLVED_PROTOCOLS_ALL) == 0) /* If no protocol is enabled, enable all */
@ -406,7 +417,7 @@ static int bus_method_resolve_hostname(sd_bus_message *message, void *userdata,
if (r < 0 && r != -EALREADY)
return r;
r = dns_query_new(m, &q, question_utf8, question_idna ?: question_utf8, ifindex, flags);
r = dns_query_new(m, &q, question_utf8, question_idna ?: question_utf8, NULL, ifindex, flags);
if (r < 0)
return r;
@ -548,7 +559,7 @@ static int bus_method_resolve_address(sd_bus_message *message, void *userdata, s
if (r < 0)
return r;
r = dns_query_new(m, &q, question, question, ifindex, flags|SD_RESOLVED_NO_SEARCH);
r = dns_query_new(m, &q, question, question, NULL, ifindex, flags|SD_RESOLVED_NO_SEARCH);
if (r < 0)
return r;
@ -724,14 +735,12 @@ static int bus_method_resolve_record(sd_bus_message *message, void *userdata, sd
if (r < 0)
return r;
r = dns_query_new(m, &q, question, question, ifindex, flags|SD_RESOLVED_NO_SEARCH);
/* Setting SD_RESOLVED_CLAMP_TTL: let's request that the TTL is fixed up for locally cached entries,
* after all we return it in the wire format blob. */
r = dns_query_new(m, &q, question, question, NULL, ifindex, flags|SD_RESOLVED_NO_SEARCH|SD_RESOLVED_CLAMP_TTL);
if (r < 0)
return r;
/* Let's request that the TTL is fixed up for locally cached entries, after all we return it in the wire format
* blob */
q->clamp_ttl = true;
q->bus_request = sd_bus_message_ref(message);
q->complete = bus_method_resolve_record_complete;
@ -1088,7 +1097,7 @@ static int resolve_service_hostname(DnsQuery *q, DnsResourceRecord *rr, int ifin
if (r < 0)
return r;
r = dns_query_new(q->manager, &aux, question, question, ifindex, q->flags|SD_RESOLVED_NO_SEARCH);
r = dns_query_new(q->manager, &aux, question, question, NULL, ifindex, q->flags|SD_RESOLVED_NO_SEARCH);
if (r < 0)
return r;
@ -1258,7 +1267,7 @@ static int bus_method_resolve_service(sd_bus_message *message, void *userdata, s
if (r < 0)
return r;
r = dns_query_new(m, &q, question_utf8, question_idna, ifindex, flags|SD_RESOLVED_NO_SEARCH);
r = dns_query_new(m, &q, question_utf8, question_idna, NULL, ifindex, flags|SD_RESOLVED_NO_SEARCH);
if (r < 0)
return r;

View File

@ -27,6 +27,31 @@
/* Output: Result is authenticated */
#define SD_RESOLVED_AUTHENTICATED (UINT64_C(1) << 9)
/* Input: Don't DNSSEC validate request */
#define SD_RESOLVED_NO_VALIDATE (UINT64_C(1) << 10)
/* Input: Don't answer request from locally synthesized records (which includes /etc/hosts) */
#define SD_RESOLVED_NO_SYNTHESIZE (UINT64_C(1) << 11)
/* Input: Don't answer request from cache */
#define SD_RESOLVED_NO_CACHE (UINT64_C(1) << 12)
/* Input: Don't answer request from locally registered public LLMNR/mDNS RRs */
#define SD_RESOLVED_NO_ZONE (UINT64_C(1) << 13)
/* Input: Don't answer request from locally registered public LLMNR/mDNS RRs */
#define SD_RESOLVED_NO_TRUST_ANCHOR (UINT64_C(1) << 14)
/* Input: Don't go to network for this request */
#define SD_RESOLVED_NO_NETWORK (UINT64_C(1) << 15)
/* Input: Require that request is answered from a "primary" answer, i.e. not from RRs acquired as
* side-effect of a previous transaction */
#define SD_RESOLVED_REQUIRE_PRIMARY (UINT64_C(1) << 16)
/* Input: If reply is answered from cache, the TTLs will be adjusted by age of cache entry */
#define SD_RESOLVED_CLAMP_TTL (UINT64_C(1) << 17)
#define SD_RESOLVED_LLMNR (SD_RESOLVED_LLMNR_IPV4|SD_RESOLVED_LLMNR_IPV6)
#define SD_RESOLVED_MDNS (SD_RESOLVED_MDNS_IPV4|SD_RESOLVED_MDNS_IPV6)
#define SD_RESOLVED_PROTOCOLS_ALL (SD_RESOLVED_MDNS|SD_RESOLVED_LLMNR|SD_RESOLVED_DNS)

View File

@ -55,20 +55,21 @@ DnsAnswer *dns_answer_new(size_t n) {
a->n_ref = 1;
a->n_allocated = n;
a->set_items = TAKE_PTR(s);
return a;
}
static void dns_answer_flush(DnsAnswer *a) {
DnsResourceRecord *rr;
DnsAnswerItem *item;
if (!a)
return;
a->set_items = set_free(a->set_items);
DNS_ANSWER_FOREACH(rr, a)
dns_resource_record_unref(rr);
DNS_ANSWER_FOREACH_ITEM(item, a) {
dns_resource_record_unref(item->rr);
dns_resource_record_unref(item->rrsig);
}
a->n_rrs = 0;
}
@ -82,7 +83,13 @@ static DnsAnswer *dns_answer_free(DnsAnswer *a) {
DEFINE_TRIVIAL_REF_UNREF_FUNC(DnsAnswer, dns_answer, dns_answer_free);
static int dns_answer_add_raw(DnsAnswer *a, DnsResourceRecord *rr, int ifindex, DnsAnswerFlags flags) {
static int dns_answer_add_raw(
DnsAnswer *a,
DnsResourceRecord *rr,
int ifindex,
DnsAnswerFlags flags,
DnsResourceRecord *rrsig) {
int r;
assert(rr);
@ -97,6 +104,7 @@ static int dns_answer_add_raw(DnsAnswer *a, DnsResourceRecord *rr, int ifindex,
.rr = rr,
.ifindex = ifindex,
.flags = flags,
.rrsig = dns_resource_record_ref(rrsig),
};
r = set_put(a->set_items, &a->items[a->n_rrs]);
@ -112,12 +120,16 @@ static int dns_answer_add_raw(DnsAnswer *a, DnsResourceRecord *rr, int ifindex,
}
static int dns_answer_add_raw_all(DnsAnswer *a, DnsAnswer *source) {
DnsResourceRecord *rr;
DnsAnswerFlags flags;
int ifindex, r;
DnsAnswerItem *item;
int r;
DNS_ANSWER_FOREACH_FULL(rr, ifindex, flags, source) {
r = dns_answer_add_raw(a, rr, ifindex, flags);
DNS_ANSWER_FOREACH_ITEM(item, source) {
r = dns_answer_add_raw(
a,
item->rr,
item->ifindex,
item->flags,
item->rrsig);
if (r < 0)
return r;
}
@ -125,7 +137,13 @@ static int dns_answer_add_raw_all(DnsAnswer *a, DnsAnswer *source) {
return 0;
}
int dns_answer_add(DnsAnswer *a, DnsResourceRecord *rr, int ifindex, DnsAnswerFlags flags) {
int dns_answer_add(
DnsAnswer *a,
DnsResourceRecord *rr,
int ifindex,
DnsAnswerFlags flags,
DnsResourceRecord *rrsig) {
DnsAnswerItem tmp, *exist;
assert(rr);
@ -152,22 +170,28 @@ int dns_answer_add(DnsAnswer *a, DnsResourceRecord *rr, int ifindex, DnsAnswerFl
if (rr->ttl > exist->rr->ttl) {
dns_resource_record_unref(exist->rr);
exist->rr = dns_resource_record_ref(rr);
/* Update RRSIG and RR at the same time */
if (rrsig) {
dns_resource_record_ref(rrsig);
dns_resource_record_unref(exist->rrsig);
exist->rrsig = rrsig;
}
}
exist->flags |= flags;
return 0;
}
return dns_answer_add_raw(a, rr, ifindex, flags);
return dns_answer_add_raw(a, rr, ifindex, flags, rrsig);
}
static int dns_answer_add_all(DnsAnswer *a, DnsAnswer *b) {
DnsResourceRecord *rr;
DnsAnswerFlags flags;
int ifindex, r;
DnsAnswerItem *item;
int r;
DNS_ANSWER_FOREACH_FULL(rr, ifindex, flags, b) {
r = dns_answer_add(a, rr, ifindex, flags);
DNS_ANSWER_FOREACH_ITEM(item, b) {
r = dns_answer_add(a, item->rr, item->ifindex, item->flags, item->rrsig);
if (r < 0)
return r;
}
@ -175,7 +199,13 @@ static int dns_answer_add_all(DnsAnswer *a, DnsAnswer *b) {
return 0;
}
int dns_answer_add_extend(DnsAnswer **a, DnsResourceRecord *rr, int ifindex, DnsAnswerFlags flags) {
int dns_answer_add_extend(
DnsAnswer **a,
DnsResourceRecord *rr,
int ifindex,
DnsAnswerFlags flags,
DnsResourceRecord *rrsig) {
int r;
assert(a);
@ -185,7 +215,7 @@ int dns_answer_add_extend(DnsAnswer **a, DnsResourceRecord *rr, int ifindex, Dns
if (r < 0)
return r;
return dns_answer_add(*a, rr, ifindex, flags);
return dns_answer_add(*a, rr, ifindex, flags, rrsig);
}
int dns_answer_add_soa(DnsAnswer *a, const char *name, uint32_t ttl, int ifindex) {
@ -211,7 +241,7 @@ int dns_answer_add_soa(DnsAnswer *a, const char *name, uint32_t ttl, int ifindex
soa->soa.expire = 1;
soa->soa.minimum = ttl;
return dns_answer_add(a, soa, ifindex, DNS_ANSWER_AUTHENTICATED);
return dns_answer_add(a, soa, ifindex, DNS_ANSWER_AUTHENTICATED, NULL);
}
int dns_answer_match_key(DnsAnswer *a, const DnsResourceKey *key, DnsAnswerFlags *ret_flags) {
@ -249,10 +279,9 @@ int dns_answer_match_key(DnsAnswer *a, const DnsResourceKey *key, DnsAnswerFlags
int dns_answer_contains_nsec_or_nsec3(DnsAnswer *a) {
DnsResourceRecord *i;
DNS_ANSWER_FOREACH(i, a) {
DNS_ANSWER_FOREACH(i, a)
if (IN_SET(i->key->type, DNS_TYPE_NSEC, DNS_TYPE_NSEC3))
return true;
}
return false;
}
@ -284,7 +313,22 @@ int dns_answer_contains_zone_nsec3(DnsAnswer *answer, const char *zone) {
return false;
}
int dns_answer_find_soa(DnsAnswer *a, const DnsResourceKey *key, DnsResourceRecord **ret, DnsAnswerFlags *flags) {
int dns_answer_contains(DnsAnswer *answer, DnsResourceRecord *rr) {
DnsResourceRecord *i;
DNS_ANSWER_FOREACH(i, answer)
if (dns_resource_record_equal(i, rr))
return true;
return false;
}
int dns_answer_find_soa(
DnsAnswer *a,
const DnsResourceKey *key,
DnsResourceRecord **ret,
DnsAnswerFlags *ret_flags) {
DnsResourceRecord *rr, *soa = NULL;
DnsAnswerFlags rr_flags, soa_flags = 0;
int r;
@ -293,7 +337,7 @@ int dns_answer_find_soa(DnsAnswer *a, const DnsResourceKey *key, DnsResourceReco
/* For a SOA record we can never find a matching SOA record */
if (key->type == DNS_TYPE_SOA)
return 0;
goto not_found;
DNS_ANSWER_FOREACH_FLAGS(rr, rr_flags, a) {
r = dns_resource_key_match_soa(key, rr->key);
@ -315,17 +359,30 @@ int dns_answer_find_soa(DnsAnswer *a, const DnsResourceKey *key, DnsResourceReco
}
if (!soa)
return 0;
goto not_found;
if (ret)
*ret = soa;
if (flags)
*flags = soa_flags;
if (ret_flags)
*ret_flags = soa_flags;
return 1;
not_found:
if (ret)
*ret = NULL;
if (ret_flags)
*ret_flags = 0;
return 0;
}
int dns_answer_find_cname_or_dname(DnsAnswer *a, const DnsResourceKey *key, DnsResourceRecord **ret, DnsAnswerFlags *flags) {
int dns_answer_find_cname_or_dname(
DnsAnswer *a,
const DnsResourceKey *key,
DnsResourceRecord **ret,
DnsAnswerFlags *ret_flags) {
DnsResourceRecord *rr;
DnsAnswerFlags rr_flags;
int r;
@ -343,12 +400,17 @@ int dns_answer_find_cname_or_dname(DnsAnswer *a, const DnsResourceKey *key, DnsR
if (r > 0) {
if (ret)
*ret = rr;
if (flags)
*flags = rr_flags;
if (ret_flags)
*ret_flags = rr_flags;
return 1;
}
}
if (ret)
*ret = NULL;
if (ret_flags)
*ret_flags = 0;
return 0;
}
@ -440,21 +502,20 @@ int dns_answer_remove_by_key(DnsAnswer **a, const DnsResourceKey *key) {
if ((*a)->n_ref > 1) {
_cleanup_(dns_answer_unrefp) DnsAnswer *copy = NULL;
DnsAnswerFlags flags;
int ifindex;
DnsAnswerItem *item;
copy = dns_answer_new((*a)->n_rrs);
if (!copy)
return -ENOMEM;
DNS_ANSWER_FOREACH_FULL(rr, ifindex, flags, *a) {
r = dns_resource_key_equal(rr->key, key);
DNS_ANSWER_FOREACH_ITEM(item, *a) {
r = dns_resource_key_equal(item->rr->key, key);
if (r < 0)
return r;
if (r > 0)
continue;
r = dns_answer_add_raw(copy, rr, ifindex, flags);
r = dns_answer_add_raw(copy, item->rr, item->ifindex, item->flags, item->rrsig);
if (r < 0)
return r;
}
@ -479,6 +540,8 @@ int dns_answer_remove_by_key(DnsAnswer **a, const DnsResourceKey *key) {
/* Kill this entry */
dns_resource_record_unref((*a)->items[i].rr);
dns_resource_record_unref((*a)->items[i].rrsig);
memmove((*a)->items + i, (*a)->items + i + 1, sizeof(DnsAnswerItem) * ((*a)->n_rrs - i - 1));
(*a)->n_rrs--;
continue;
@ -525,21 +588,20 @@ int dns_answer_remove_by_rr(DnsAnswer **a, DnsResourceRecord *rm) {
if ((*a)->n_ref > 1) {
_cleanup_(dns_answer_unrefp) DnsAnswer *copy = NULL;
DnsAnswerFlags flags;
int ifindex;
DnsAnswerItem *item;
copy = dns_answer_new((*a)->n_rrs);
if (!copy)
return -ENOMEM;
DNS_ANSWER_FOREACH_FULL(rr, ifindex, flags, *a) {
r = dns_resource_record_equal(rr, rm);
DNS_ANSWER_FOREACH_ITEM(item, *a) {
r = dns_resource_record_equal(item->rr, rm);
if (r < 0)
return r;
if (r > 0)
continue;
r = dns_answer_add_raw(copy, rr, ifindex, flags);
r = dns_answer_add_raw(copy, item->rr, item->ifindex, item->flags, item->rrsig);
if (r < 0)
return r;
}
@ -564,6 +626,7 @@ int dns_answer_remove_by_rr(DnsAnswer **a, DnsResourceRecord *rm) {
/* Kill this entry */
dns_resource_record_unref((*a)->items[i].rr);
dns_resource_record_unref((*a)->items[i].rrsig);
memmove((*a)->items + i, (*a)->items + i + 1, sizeof(DnsAnswerItem) * ((*a)->n_rrs - i - 1));
(*a)->n_rrs--;
continue;
@ -576,19 +639,24 @@ int dns_answer_remove_by_rr(DnsAnswer **a, DnsResourceRecord *rm) {
return 1;
}
int dns_answer_copy_by_key(DnsAnswer **a, DnsAnswer *source, const DnsResourceKey *key, DnsAnswerFlags or_flags) {
DnsResourceRecord *rr_source;
int ifindex_source, r;
DnsAnswerFlags flags_source;
int dns_answer_copy_by_key(
DnsAnswer **a,
DnsAnswer *source,
const DnsResourceKey *key,
DnsAnswerFlags or_flags,
DnsResourceRecord *rrsig) {
DnsAnswerItem *item;
int r;
assert(a);
assert(key);
/* Copy all RRs matching the specified key from source into *a */
DNS_ANSWER_FOREACH_FULL(rr_source, ifindex_source, flags_source, source) {
DNS_ANSWER_FOREACH_ITEM(item, source) {
r = dns_resource_key_equal(rr_source->key, key);
r = dns_resource_key_equal(item->rr->key, key);
if (r < 0)
return r;
if (r == 0)
@ -599,7 +667,7 @@ int dns_answer_copy_by_key(DnsAnswer **a, DnsAnswer *source, const DnsResourceKe
if (r < 0)
return r;
r = dns_answer_add(*a, rr_source, ifindex_source, flags_source|or_flags);
r = dns_answer_add(*a, item->rr, item->ifindex, item->flags|or_flags, item->rrsig);
if (r < 0)
return r;
}
@ -607,14 +675,19 @@ int dns_answer_copy_by_key(DnsAnswer **a, DnsAnswer *source, const DnsResourceKe
return 0;
}
int dns_answer_move_by_key(DnsAnswer **to, DnsAnswer **from, const DnsResourceKey *key, DnsAnswerFlags or_flags) {
int dns_answer_move_by_key(
DnsAnswer **to,
DnsAnswer **from,
const DnsResourceKey *key,
DnsAnswerFlags or_flags,
DnsResourceRecord *rrsig) {
int r;
assert(to);
assert(from);
assert(key);
r = dns_answer_copy_by_key(to, *from, key, or_flags);
r = dns_answer_copy_by_key(to, *from, key, or_flags, rrsig);
if (r < 0)
return r;
@ -744,19 +817,17 @@ int dns_answer_reserve_or_clone(DnsAnswer **a, size_t n_free) {
* This function is not used in the code base, but is useful when debugging. Do not delete.
*/
void dns_answer_dump(DnsAnswer *answer, FILE *f) {
DnsResourceRecord *rr;
DnsAnswerFlags flags;
int ifindex;
DnsAnswerItem *item;
if (!f)
f = stdout;
DNS_ANSWER_FOREACH_FULL(rr, ifindex, flags, answer) {
DNS_ANSWER_FOREACH_ITEM(item, answer) {
const char *t;
fputc('\t', f);
t = dns_resource_record_to_string(rr);
t = dns_resource_record_to_string(item->rr);
if (!t) {
log_oom();
continue;
@ -764,21 +835,29 @@ void dns_answer_dump(DnsAnswer *answer, FILE *f) {
fputs(t, f);
if (ifindex != 0 || flags != 0)
if (item->ifindex != 0 || item->rrsig || item->flags != 0)
fputs("\t;", f);
if (ifindex != 0)
fprintf(f, " ifindex=%i", ifindex);
if (flags & DNS_ANSWER_AUTHENTICATED)
if (item->ifindex != 0)
fprintf(f, " ifindex=%i", item->ifindex);
if (item->rrsig)
fputs(" rrsig", f);
if (item->flags & DNS_ANSWER_AUTHENTICATED)
fputs(" authenticated", f);
if (flags & DNS_ANSWER_CACHEABLE)
if (item->flags & DNS_ANSWER_CACHEABLE)
fputs(" cacheable", f);
if (flags & DNS_ANSWER_SHARED_OWNER)
if (item->flags & DNS_ANSWER_SHARED_OWNER)
fputs(" shared-owner", f);
if (flags & DNS_ANSWER_CACHE_FLUSH)
if (item->flags & DNS_ANSWER_CACHE_FLUSH)
fputs(" cache-flush", f);
if (flags & DNS_ANSWER_GOODBYE)
if (item->flags & DNS_ANSWER_GOODBYE)
fputs(" goodbye", f);
if (item->flags & DNS_ANSWER_SECTION_ANSWER)
fputs(" section-answer", f);
if (item->flags & DNS_ANSWER_SECTION_AUTHORITY)
fputs(" section-authority", f);
if (item->flags & DNS_ANSWER_SECTION_ADDITIONAL)
fputs(" section-additional", f);
fputc('\n', f);
}

View File

@ -8,23 +8,25 @@ typedef struct DnsAnswerItem DnsAnswerItem;
#include "resolved-dns-rr.h"
#include "set.h"
/* A simple array of resource records. We keep track of the
* originating ifindex for each RR where that makes sense, so that we
* can qualify A and AAAA RRs referring to a local link with the
* right ifindex.
/* A simple array of resource records. We keep track of the originating ifindex for each RR where that makes
* sense, so that we can qualify A and AAAA RRs referring to a local link with the right ifindex.
*
* Note that we usually encode the empty DnsAnswer object as a simple NULL. */
typedef enum DnsAnswerFlags {
DNS_ANSWER_AUTHENTICATED = 1 << 0, /* Item has been authenticated */
DNS_ANSWER_CACHEABLE = 1 << 1, /* Item is subject to caching */
DNS_ANSWER_SHARED_OWNER = 1 << 2, /* For mDNS: RRset may be owner by multiple peers */
DNS_ANSWER_CACHE_FLUSH = 1 << 3, /* For mDNS: sets cache-flush bit in the rrclass of response records */
DNS_ANSWER_GOODBYE = 1 << 4, /* For mDNS: item is subject to disappear */
DNS_ANSWER_AUTHENTICATED = 1 << 0, /* Item has been authenticated */
DNS_ANSWER_CACHEABLE = 1 << 1, /* Item is subject to caching */
DNS_ANSWER_SHARED_OWNER = 1 << 2, /* For mDNS: RRset may be owner by multiple peers */
DNS_ANSWER_CACHE_FLUSH = 1 << 3, /* For mDNS: sets cache-flush bit in the rrclass of response records */
DNS_ANSWER_GOODBYE = 1 << 4, /* For mDNS: item is subject to disappear */
DNS_ANSWER_SECTION_ANSWER = 1 << 5, /* When parsing: RR originates from answer section */
DNS_ANSWER_SECTION_AUTHORITY = 1 << 6, /* When parsing: RR originates from authority section */
DNS_ANSWER_SECTION_ADDITIONAL = 1 << 7, /* When parsing: RR originates from additional section */
} DnsAnswerFlags;
struct DnsAnswerItem {
DnsResourceRecord *rr;
DnsResourceRecord *rrsig; /* Optionally, also store RRSIG RR that successfully validates this item */
int ifindex;
DnsAnswerFlags flags;
};
@ -40,16 +42,17 @@ DnsAnswer *dns_answer_new(size_t n);
DnsAnswer *dns_answer_ref(DnsAnswer *a);
DnsAnswer *dns_answer_unref(DnsAnswer *a);
int dns_answer_add(DnsAnswer *a, DnsResourceRecord *rr, int ifindex, DnsAnswerFlags flags);
int dns_answer_add_extend(DnsAnswer **a, DnsResourceRecord *rr, int ifindex, DnsAnswerFlags flags);
int dns_answer_add(DnsAnswer *a, DnsResourceRecord *rr, int ifindex, DnsAnswerFlags flags, DnsResourceRecord *rrsig);
int dns_answer_add_extend(DnsAnswer **a, DnsResourceRecord *rr, int ifindex, DnsAnswerFlags flags, DnsResourceRecord *rrsig);
int dns_answer_add_soa(DnsAnswer *a, const char *name, uint32_t ttl, int ifindex);
int dns_answer_match_key(DnsAnswer *a, const DnsResourceKey *key, DnsAnswerFlags *combined_flags);
int dns_answer_contains_nsec_or_nsec3(DnsAnswer *a);
int dns_answer_contains_zone_nsec3(DnsAnswer *answer, const char *zone);
int dns_answer_contains(DnsAnswer *answer, DnsResourceRecord *rr);
int dns_answer_find_soa(DnsAnswer *a, const DnsResourceKey *key, DnsResourceRecord **ret, DnsAnswerFlags *flags);
int dns_answer_find_cname_or_dname(DnsAnswer *a, const DnsResourceKey *key, DnsResourceRecord **ret, DnsAnswerFlags *flags);
int dns_answer_find_soa(DnsAnswer *a, const DnsResourceKey *key, DnsResourceRecord **ret, DnsAnswerFlags *ret_flags);
int dns_answer_find_cname_or_dname(DnsAnswer *a, const DnsResourceKey *key, DnsResourceRecord **ret, DnsAnswerFlags *ret_flags);
int dns_answer_merge(DnsAnswer *a, DnsAnswer *b, DnsAnswer **ret);
int dns_answer_extend(DnsAnswer **a, DnsAnswer *b);
@ -62,8 +65,8 @@ int dns_answer_reserve_or_clone(DnsAnswer **a, size_t n_free);
int dns_answer_remove_by_key(DnsAnswer **a, const DnsResourceKey *key);
int dns_answer_remove_by_rr(DnsAnswer **a, DnsResourceRecord *rr);
int dns_answer_copy_by_key(DnsAnswer **a, DnsAnswer *source, const DnsResourceKey *key, DnsAnswerFlags or_flags);
int dns_answer_move_by_key(DnsAnswer **to, DnsAnswer **from, const DnsResourceKey *key, DnsAnswerFlags or_flags);
int dns_answer_copy_by_key(DnsAnswer **a, DnsAnswer *source, const DnsResourceKey *key, DnsAnswerFlags or_flags, DnsResourceRecord *rrsig);
int dns_answer_move_by_key(DnsAnswer **to, DnsAnswer **from, const DnsResourceKey *key, DnsAnswerFlags or_flags, DnsResourceRecord *rrsig);
int dns_answer_has_dname_for_cname(DnsAnswer *a, DnsResourceRecord *cname);
@ -115,17 +118,13 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(DnsAnswer*, dns_answer_unref);
#define DNS_ANSWER_FOREACH_FLAGS(kk, flags, a) _DNS_ANSWER_FOREACH_FLAGS(UNIQ, kk, flags, a)
#define _DNS_ANSWER_FOREACH_FULL(q, kk, ifi, fl, a) \
#define _DNS_ANSWER_FOREACH_ITEM(q, item, a) \
for (size_t UNIQ_T(i, q) = ({ \
(kk) = ((a) && (a)->n_rrs > 0) ? (a)->items[0].rr : NULL; \
(ifi) = ((a) && (a)->n_rrs > 0) ? (a)->items[0].ifindex : 0; \
(fl) = ((a) && (a)->n_rrs > 0) ? (a)->items[0].flags : 0; \
(item) = dns_answer_isempty(a) ? NULL : (a)->items; \
0; \
}); \
(a) && (UNIQ_T(i, q) < (a)->n_rrs); \
UNIQ_T(i, q) < dns_answer_size(a); \
UNIQ_T(i, q)++, \
(kk) = ((UNIQ_T(i, q) < (a)->n_rrs) ? (a)->items[UNIQ_T(i, q)].rr : NULL), \
(ifi) = ((UNIQ_T(i, q) < (a)->n_rrs) ? (a)->items[UNIQ_T(i, q)].ifindex : 0), \
(fl) = ((UNIQ_T(i, q) < (a)->n_rrs) ? (a)->items[UNIQ_T(i, q)].flags : 0))
(item) = ((UNIQ_T(i, q) < dns_answer_size(a)) ? (a)->items + UNIQ_T(i, q) : NULL))
#define DNS_ANSWER_FOREACH_FULL(kk, ifindex, flags, a) _DNS_ANSWER_FOREACH_FULL(UNIQ, kk, ifindex, flags, a)
#define DNS_ANSWER_FOREACH_ITEM(item, a) _DNS_ANSWER_FOREACH_ITEM(UNIQ, item, a)

View File

@ -34,13 +34,16 @@ enum DnsCacheItemType {
struct DnsCacheItem {
DnsCacheItemType type;
DnsResourceKey *key;
DnsResourceRecord *rr;
DnsResourceKey *key; /* The key for this item, i.e. the lookup key */
DnsResourceRecord *rr; /* The RR for this item, i.e. the lookup value for positive queries */
DnsAnswer *answer; /* The full validated answer, if this is an RRset acquired via a "primary" lookup */
DnsPacket *full_packet; /* The full packet this information was acquired with */
int rcode;
usec_t until;
bool authenticated:1;
bool shared_owner:1;
DnssecResult dnssec_result;
int ifindex;
int owner_family;
@ -50,6 +53,12 @@ struct DnsCacheItem {
LIST_FIELDS(DnsCacheItem, by_key);
};
/* Returns true if this is a cache item created as result of an explicit lookup, or created as "side-effect"
* of another request. "Primary" entries will carry the full answer data (with NSEC, ) that can aso prove
* wildcard expansion, non-existance and such, while entries that were created as "side-effect" just contain
* immediate RR data for the specified RR key, but nothing else. */
#define DNS_CACHE_ITEM_IS_PRIMARY(item) (!!(item)->answer)
static const char *dns_cache_item_type_to_string(DnsCacheItem *item) {
assert(item);
@ -77,6 +86,8 @@ static void dns_cache_item_free(DnsCacheItem *i) {
dns_resource_record_unref(i->rr);
dns_resource_key_unref(i->key);
dns_answer_unref(i->answer);
dns_packet_unref(i->full_packet);
free(i);
}
@ -340,8 +351,11 @@ static void dns_cache_item_update_positive(
DnsCache *c,
DnsCacheItem *i,
DnsResourceRecord *rr,
DnsAnswer *answer,
DnsPacket *full_packet,
bool authenticated,
bool shared_owner,
DnssecResult dnssec_result,
usec_t timestamp,
int ifindex,
int owner_family,
@ -367,9 +381,18 @@ static void dns_cache_item_update_positive(
dns_resource_key_unref(i->key);
i->key = dns_resource_key_ref(rr->key);
i->until = calculate_until(rr, (uint32_t) -1, timestamp, false);
dns_answer_ref(answer);
dns_answer_unref(i->answer);
i->answer = answer;
dns_packet_ref(full_packet);
dns_packet_unref(i->full_packet);
i->full_packet = full_packet;
i->until = calculate_until(rr, UINT32_MAX, timestamp, false);
i->authenticated = authenticated;
i->shared_owner = shared_owner;
i->dnssec_result = dnssec_result;
i->ifindex = ifindex;
@ -382,8 +405,11 @@ static void dns_cache_item_update_positive(
static int dns_cache_put_positive(
DnsCache *c,
DnsResourceRecord *rr,
DnsAnswer *answer,
DnsPacket *full_packet,
bool authenticated,
bool shared_owner,
DnssecResult dnssec_result,
usec_t timestamp,
int ifindex,
int owner_family,
@ -420,8 +446,11 @@ static int dns_cache_put_positive(
c,
existing,
rr,
answer,
full_packet,
authenticated,
shared_owner,
dnssec_result,
timestamp,
ifindex,
owner_family,
@ -444,9 +473,12 @@ static int dns_cache_put_positive(
.type = DNS_CACHE_POSITIVE,
.key = dns_resource_key_ref(rr->key),
.rr = dns_resource_record_ref(rr),
.answer = dns_answer_ref(answer),
.full_packet = dns_packet_ref(full_packet),
.until = calculate_until(rr, (uint32_t) -1, timestamp, false),
.authenticated = authenticated,
.shared_owner = shared_owner,
.dnssec_result = dnssec_result,
.ifindex = ifindex,
.owner_family = owner_family,
.owner_address = *owner_address,
@ -481,7 +513,10 @@ static int dns_cache_put_negative(
DnsCache *c,
DnsResourceKey *key,
int rcode,
DnsAnswer *answer,
DnsPacket *full_packet,
bool authenticated,
DnssecResult dnssec_result,
uint32_t nsec_ttl,
usec_t timestamp,
DnsResourceRecord *soa,
@ -532,10 +567,13 @@ static int dns_cache_put_negative(
rcode == DNS_RCODE_SUCCESS ? DNS_CACHE_NODATA :
rcode == DNS_RCODE_NXDOMAIN ? DNS_CACHE_NXDOMAIN : DNS_CACHE_RCODE,
.authenticated = authenticated,
.dnssec_result = dnssec_result,
.owner_family = owner_family,
.owner_address = *owner_address,
.prioq_idx = PRIOQ_IDX_NULL,
.rcode = rcode,
.answer = dns_answer_ref(answer),
.full_packet = dns_packet_ref(full_packet),
};
i->until =
@ -630,17 +668,20 @@ int dns_cache_put(
DnsResourceKey *key,
int rcode,
DnsAnswer *answer,
DnsPacket *full_packet,
bool authenticated,
DnssecResult dnssec_result,
uint32_t nsec_ttl,
usec_t timestamp,
int owner_family,
const union in_addr_union *owner_address) {
DnsResourceRecord *soa = NULL, *rr;
DnsResourceRecord *soa = NULL;
bool weird_rcode = false;
DnsAnswerItem *item;
DnsAnswerFlags flags;
unsigned cache_keys;
int r, ifindex;
usec_t timestamp;
int r;
assert(c);
assert(owner_address);
@ -660,6 +701,7 @@ int dns_cache_put(
log_debug("Not caching negative entry without a SOA record: %s",
dns_resource_key_to_string(key, key_str, sizeof key_str));
}
return 0;
}
@ -679,23 +721,53 @@ int dns_cache_put(
/* Make some space for our new entries */
dns_cache_make_space(c, cache_keys);
if (timestamp <= 0)
timestamp = now(clock_boottime_or_monotonic());
timestamp = now(clock_boottime_or_monotonic());
/* Second, add in positive entries for all contained RRs */
DNS_ANSWER_FOREACH_FULL(rr, ifindex, flags, answer) {
if ((flags & DNS_ANSWER_CACHEABLE) == 0 ||
!rr_eligible(rr))
DNS_ANSWER_FOREACH_ITEM(item, answer) {
int primary = false;
if (!FLAGS_SET(item->flags, DNS_ANSWER_CACHEABLE) ||
!rr_eligible(item->rr))
continue;
if (key) {
/* We store the auxiliary RRs and packet data in the cache only if they were in
* direct response to the original query. If we cache an RR we also received, and
* that is just auxiliary information we can't use the data, hence don't. */
primary = dns_resource_key_match_rr(key, item->rr, NULL);
if (primary < 0)
return primary;
if (primary == 0) {
primary = dns_resource_key_match_cname_or_dname(key, item->rr->key, NULL);
if (primary < 0)
return primary;
}
}
if (!primary) {
DnsCacheItem *first;
/* Do not replace existing cache items for primary lookups with non-primary
* data. After all the primary lookup data is a lot more useful. */
first = hashmap_get(c->by_key, item->rr->key);
if (first && DNS_CACHE_ITEM_IS_PRIMARY(first))
return 0;
}
r = dns_cache_put_positive(
c,
rr,
flags & DNS_ANSWER_AUTHENTICATED,
flags & DNS_ANSWER_SHARED_OWNER,
item->rr,
primary ? answer : NULL,
primary ? full_packet : NULL,
item->flags & DNS_ANSWER_AUTHENTICATED,
item->flags & DNS_ANSWER_SHARED_OWNER,
dnssec_result,
timestamp,
ifindex,
owner_family, owner_address);
item->ifindex,
owner_family,
owner_address);
if (r < 0)
goto fail;
}
@ -745,7 +817,10 @@ int dns_cache_put(
c,
key,
rcode,
answer,
full_packet,
authenticated,
dnssec_result,
nsec_ttl,
timestamp,
soa,
@ -762,11 +837,11 @@ fail:
if (key)
dns_cache_remove_by_key(c, key);
DNS_ANSWER_FOREACH_FLAGS(rr, flags, answer) {
if ((flags & DNS_ANSWER_CACHEABLE) == 0)
DNS_ANSWER_FOREACH_ITEM(item, answer) {
if ((item->flags & DNS_ANSWER_CACHEABLE) == 0)
continue;
dns_cache_remove_by_key(c, rr->key);
dns_cache_remove_by_key(c, item->rr->key);
}
return r;
@ -827,7 +902,59 @@ static DnsCacheItem *dns_cache_get_by_key_follow_cname_dname_nsec(DnsCache *c, D
return NULL;
}
int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, bool clamp_ttl, int *rcode, DnsAnswer **ret, bool *authenticated) {
static int answer_add_clamp_ttl(
DnsAnswer **answer,
DnsResourceRecord *rr,
int ifindex,
DnsAnswerFlags answer_flags,
DnsResourceRecord *rrsig,
uint64_t query_flags,
usec_t until,
usec_t current) {
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *patched = NULL, *patched_rrsig = NULL;
int r;
assert(answer);
assert(rr);
if (FLAGS_SET(query_flags, SD_RESOLVED_CLAMP_TTL)) {
patched = dns_resource_record_ref(rr);
r = dns_resource_record_clamp_ttl(&patched, LESS_BY(until, current) / USEC_PER_SEC);
if (r < 0)
return r;
rr = patched;
if (rrsig) {
patched_rrsig = dns_resource_record_ref(rrsig);
r = dns_resource_record_clamp_ttl(&patched_rrsig, LESS_BY(until, current) / USEC_PER_SEC);
if (r < 0)
return r;
rrsig = patched_rrsig;
}
}
r = dns_answer_add_extend(answer, rr, ifindex, answer_flags, rrsig);
if (r < 0)
return r;
return 0;
}
int dns_cache_lookup(
DnsCache *c,
DnsResourceKey *key,
uint64_t query_flags,
int *ret_rcode,
DnsAnswer **ret_answer,
DnsPacket **ret_full_packet,
bool *ret_authenticated,
DnssecResult *ret_dnssec_result) {
_cleanup_(dns_packet_unrefp) DnsPacket *full_packet = NULL;
_cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
char key_str[DNS_RESOURCE_KEY_STRING_MAX];
unsigned n = 0;
@ -837,27 +964,19 @@ int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, bool clamp_ttl, int *rcod
bool have_authenticated = false, have_non_authenticated = false;
usec_t current;
int found_rcode = -1;
DnssecResult dnssec_result = -1;
int have_dnssec_result = -1;
assert(c);
assert(key);
assert(rcode);
assert(ret);
assert(authenticated);
if (key->type == DNS_TYPE_ANY || key->class == DNS_CLASS_ANY) {
/* If we have ANY lookups we don't use the cache, so
* that the caller refreshes via the network. */
/* If we have ANY lookups we don't use the cache, so that the caller refreshes via the
* network. */
log_debug("Ignoring cache for ANY lookup: %s",
dns_resource_key_to_string(key, key_str, sizeof key_str));
c->n_miss++;
*ret = NULL;
*rcode = DNS_RCODE_SUCCESS;
*authenticated = false;
return 0;
goto miss;
}
first = dns_cache_get_by_key_follow_cname_dname_nsec(c, key);
@ -866,31 +985,80 @@ int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, bool clamp_ttl, int *rcod
log_debug("Cache miss for %s",
dns_resource_key_to_string(key, key_str, sizeof key_str));
c->n_miss++;
*ret = NULL;
*rcode = DNS_RCODE_SUCCESS;
*authenticated = false;
return 0;
goto miss;
}
if (FLAGS_SET(query_flags, SD_RESOLVED_CLAMP_TTL))
current = now(clock_boottime_or_monotonic());
LIST_FOREACH(by_key, j, first) {
if (j->rr) {
/* If the caller doesn't allow us to answer questions from cache data learned from
* "side-effect", skip this entry. */
if (FLAGS_SET(query_flags, SD_RESOLVED_REQUIRE_PRIMARY) &&
!DNS_CACHE_ITEM_IS_PRIMARY(j)) {
log_debug("Primary answer was requested for cache lookup for %s, which we don't have.",
dns_resource_key_to_string(key, key_str, sizeof key_str));
goto miss;
}
if (j->type == DNS_CACHE_NXDOMAIN)
nxdomain = true;
else if (j->type == DNS_CACHE_RCODE)
found_rcode = j->rcode;
else if (j->rr) {
if (j->rr->key->type == DNS_TYPE_NSEC)
nsec = j;
n++;
} else if (j->type == DNS_CACHE_NXDOMAIN)
nxdomain = true;
else if (j->type == DNS_CACHE_RCODE)
found_rcode = j->rcode;
}
if (j->authenticated)
have_authenticated = true;
else
have_non_authenticated = true;
if (j->dnssec_result < 0) {
have_dnssec_result = false; /* an entry without dnssec result? then invalidate things for good */
dnssec_result = _DNSSEC_RESULT_INVALID;
} else if (have_dnssec_result < 0) {
have_dnssec_result = true; /* So far no result seen, let's pick this one up */
dnssec_result = j->dnssec_result;
} else if (have_dnssec_result > 0 && j->dnssec_result != dnssec_result) {
have_dnssec_result = false; /* conflicting result seen? then invalidate for good */
dnssec_result = _DNSSEC_RESULT_INVALID;
}
/* Append the answer RRs to our answer. Ideally we have the answer object, which we
* preferably use. But if the cached entry was generated as "side-effect" of a reply,
* i.e. from validated auxiliary records rather than from the main reply, then we use the
* individual RRs only instead. */
if (j->answer) {
/* Minor optimization, if the full answer object of this and the previous RR is the
* same, don't bother adding it again. Typically we store a full RRset here, hence
* that should be the case. */
if (!j->by_key_prev || j->answer != j->by_key_prev->answer) {
DnsAnswerItem *item;
DNS_ANSWER_FOREACH_ITEM(item, j->answer) {
r = answer_add_clamp_ttl(&answer, item->rr, item->ifindex, item->flags, item->rrsig, query_flags, j->until, current);
if (r < 0)
return r;
}
}
} else if (j->rr) {
r = answer_add_clamp_ttl(&answer, j->rr, j->ifindex, j->authenticated ? DNS_ANSWER_AUTHENTICATED : 0, NULL, query_flags, j->until, current);
if (r < 0)
return r;
}
/* We'll return any packet we have for this. Typically all cache entries for the same key
* should come from the same packet anyway, hence it doesn't really matter which packet we
* return here, they should all resolve to the same anyway. */
if (!full_packet && j->full_packet)
full_packet = dns_packet_ref(j->full_packet);
}
if (found_rcode >= 0) {
@ -898,28 +1066,41 @@ int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, bool clamp_ttl, int *rcod
dns_rcode_to_string(found_rcode),
dns_resource_key_to_string(key, key_str, sizeof(key_str)));
*ret = NULL;
*rcode = found_rcode;
*authenticated = false;
if (ret_rcode)
*ret_rcode = found_rcode;
if (ret_answer)
*ret_answer = TAKE_PTR(answer);
if (ret_full_packet)
*ret_full_packet = TAKE_PTR(full_packet);
if (ret_authenticated)
*ret_authenticated = false;
if (ret_dnssec_result)
*ret_dnssec_result = dnssec_result;
c->n_hit++;
return 1;
}
if (nsec && !IN_SET(key->type, DNS_TYPE_NSEC, DNS_TYPE_DS)) {
/* Note that we won't derive information for DS RRs from an NSEC, because we only cache NSEC RRs from
* the lower-zone of a zone cut, but the DS RRs are on the upper zone. */
/* Note that we won't derive information for DS RRs from an NSEC, because we only cache NSEC
* RRs from the lower-zone of a zone cut, but the DS RRs are on the upper zone. */
log_debug("NSEC NODATA cache hit for %s",
dns_resource_key_to_string(key, key_str, sizeof key_str));
/* We only found an NSEC record that matches our name.
* If it says the type doesn't exist report
* NODATA. Otherwise report a cache miss. */
/* We only found an NSEC record that matches our name. If it says the type doesn't exist
* report NODATA. Otherwise report a cache miss. */
*ret = NULL;
*rcode = DNS_RCODE_SUCCESS;
*authenticated = nsec->authenticated;
if (ret_rcode)
*ret_rcode = DNS_RCODE_SUCCESS;
if (ret_answer)
*ret_answer = TAKE_PTR(answer);
if (ret_full_packet)
*ret_full_packet = TAKE_PTR(full_packet);
if (ret_authenticated)
*ret_authenticated = nsec->authenticated;
if (ret_dnssec_result)
*ret_dnssec_result = nsec->dnssec_result;
if (!bitmap_isset(nsec->rr->nsec.types, key->type) &&
!bitmap_isset(nsec->rr->nsec.types, DNS_TYPE_CNAME) &&
@ -940,46 +1121,49 @@ int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, bool clamp_ttl, int *rcod
if (n <= 0) {
c->n_hit++;
*ret = NULL;
*rcode = nxdomain ? DNS_RCODE_NXDOMAIN : DNS_RCODE_SUCCESS;
*authenticated = have_authenticated && !have_non_authenticated;
if (ret_rcode)
*ret_rcode = nxdomain ? DNS_RCODE_NXDOMAIN : DNS_RCODE_SUCCESS;
if (ret_answer)
*ret_answer = TAKE_PTR(answer);
if (ret_full_packet)
*ret_full_packet = TAKE_PTR(full_packet);
if (ret_authenticated)
*ret_authenticated = have_authenticated && !have_non_authenticated;
if (ret_dnssec_result)
*ret_dnssec_result = dnssec_result;
return 1;
}
answer = dns_answer_new(n);
if (!answer)
return -ENOMEM;
if (clamp_ttl)
current = now(clock_boottime_or_monotonic());
LIST_FOREACH(by_key, j, first) {
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
if (!j->rr)
continue;
if (clamp_ttl) {
rr = dns_resource_record_ref(j->rr);
r = dns_resource_record_clamp_ttl(&rr, LESS_BY(j->until, current) / USEC_PER_SEC);
if (r < 0)
return r;
}
r = dns_answer_add(answer, rr ?: j->rr, j->ifindex, j->authenticated ? DNS_ANSWER_AUTHENTICATED : 0);
if (r < 0)
return r;
}
c->n_hit++;
*ret = answer;
*rcode = DNS_RCODE_SUCCESS;
*authenticated = have_authenticated && !have_non_authenticated;
answer = NULL;
if (ret_rcode)
*ret_rcode = DNS_RCODE_SUCCESS;
if (ret_answer)
*ret_answer = TAKE_PTR(answer);
if (ret_full_packet)
*ret_full_packet = TAKE_PTR(full_packet);
if (ret_authenticated)
*ret_authenticated = have_authenticated && !have_non_authenticated;
if (ret_dnssec_result)
*ret_dnssec_result = dnssec_result;
return n;
miss:
if (ret_rcode)
*ret_rcode = DNS_RCODE_SUCCESS;
if (ret_answer)
*ret_answer = NULL;
if (ret_full_packet)
*ret_full_packet = NULL;
if (ret_authenticated)
*ret_authenticated = false;
if (ret_dnssec_result)
*ret_dnssec_result = _DNSSEC_RESULT_INVALID;
c->n_miss++;
return 0;
}
int dns_cache_check_conflicts(DnsCache *cache, DnsResourceRecord *rr, int owner_family, const union in_addr_union *owner_address) {

View File

@ -5,6 +5,7 @@
#include "list.h"
#include "prioq.h"
#include "resolve-util.h"
#include "resolved-dns-dnssec.h"
#include "time-util.h"
typedef struct DnsCache {
@ -22,8 +23,28 @@ typedef struct DnsCache {
void dns_cache_flush(DnsCache *c);
void dns_cache_prune(DnsCache *c);
int dns_cache_put(DnsCache *c, DnsCacheMode cache_mode, DnsResourceKey *key, int rcode, DnsAnswer *answer, bool authenticated, uint32_t nsec_ttl, usec_t timestamp, int owner_family, const union in_addr_union *owner_address);
int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, bool clamp_ttl, int *rcode, DnsAnswer **answer, bool *authenticated);
int dns_cache_put(
DnsCache *c,
DnsCacheMode cache_mode,
DnsResourceKey *key,
int rcode,
DnsAnswer *answer,
DnsPacket *full_packet,
bool authenticated,
DnssecResult dnssec_result,
uint32_t nsec_ttl,
int owner_family,
const union in_addr_union *owner_address);
int dns_cache_lookup(
DnsCache *c,
DnsResourceKey *key,
uint64_t query_flags,
int *ret_rcode,
DnsAnswer **ret_answer,
DnsPacket **ret_full_packet,
bool *ret_authenticated,
DnssecResult *ret_dnssec_result);
int dns_cache_check_conflicts(DnsCache *cache, DnsResourceRecord *rr, int owner_family, const union in_addr_union *owner_address);

View File

@ -160,6 +160,38 @@ int dns_packet_new_query(DnsPacket **ret, DnsProtocol protocol, size_t min_alloc
return 0;
}
int dns_packet_dup(DnsPacket **ret, DnsPacket *p) {
DnsPacket *c;
int r;
assert(ret);
assert(p);
r = dns_packet_validate(p);
if (r < 0)
return r;
c = malloc(ALIGN(sizeof(DnsPacket)) + p->size);
if (!c)
return -ENOMEM;
*c = (DnsPacket) {
.n_ref = 1,
.protocol = p->protocol,
.size = p->size,
.rindex = DNS_PACKET_HEADER_SIZE,
.allocated = p->size,
.max_size = p->max_size,
.opt_start = (size_t) -1,
.opt_size = (size_t) -1,
};
memcpy(DNS_PACKET_DATA(c), DNS_PACKET_DATA(p), p->size);
*ret = c;
return 0;
}
DnsPacket *dns_packet_ref(DnsPacket *p) {
if (!p)
@ -1183,7 +1215,7 @@ int dns_packet_append_question(DnsPacket *p, DnsQuestion *q) {
return 0;
}
int dns_packet_append_answer(DnsPacket *p, DnsAnswer *a) {
int dns_packet_append_answer(DnsPacket *p, DnsAnswer *a, unsigned *completed) {
DnsResourceRecord *rr;
DnsAnswerFlags flags;
int r;
@ -1194,6 +1226,9 @@ int dns_packet_append_answer(DnsPacket *p, DnsAnswer *a) {
r = dns_packet_append_rr(p, rr, flags, NULL, NULL);
if (r < 0)
return r;
if (completed)
(*completed)++;
}
return 0;
@ -1298,7 +1333,8 @@ int dns_packet_read_uint16(DnsPacket *p, uint16_t *ret, size_t *start) {
if (r < 0)
return r;
*ret = unaligned_read_be16(d);
if (ret)
*ret = unaligned_read_be16(d);
return 0;
}
@ -1384,19 +1420,19 @@ int dns_packet_read_raw_string(DnsPacket *p, const void **ret, size_t *size, siz
int dns_packet_read_name(
DnsPacket *p,
char **_ret,
char **ret,
bool allow_compression,
size_t *start) {
size_t *ret_start) {
_cleanup_(rewind_dns_packet) DnsPacketRewinder rewinder;
size_t after_rindex = 0, jump_barrier;
_cleanup_free_ char *ret = NULL;
_cleanup_free_ char *name = NULL;
size_t n = 0, allocated = 0;
bool first = true;
int r;
assert(p);
assert(_ret);
INIT_REWINDER(rewinder, p);
jump_barrier = p->rindex;
@ -1421,15 +1457,15 @@ int dns_packet_read_name(
if (r < 0)
return r;
if (!GREEDY_REALLOC(ret, allocated, n + !first + DNS_LABEL_ESCAPED_MAX))
if (!GREEDY_REALLOC(name, allocated, n + !first + DNS_LABEL_ESCAPED_MAX))
return -ENOMEM;
if (first)
first = false;
else
ret[n++] = '.';
name[n++] = '.';
r = dns_label_escape(label, c, ret + n, DNS_LABEL_ESCAPED_MAX);
r = dns_label_escape(label, c, name + n, DNS_LABEL_ESCAPED_MAX);
if (r < 0)
return r;
@ -1457,18 +1493,19 @@ int dns_packet_read_name(
return -EBADMSG;
}
if (!GREEDY_REALLOC(ret, allocated, n + 1))
if (!GREEDY_REALLOC(name, allocated, n + 1))
return -ENOMEM;
ret[n] = 0;
name[n] = 0;
if (after_rindex != 0)
p->rindex= after_rindex;
*_ret = TAKE_PTR(ret);
if (ret)
*ret = TAKE_PTR(name);
if (ret_start)
*ret_start = rewinder.saved_rindex;
if (start)
*start = rewinder.saved_rindex;
CANCEL_REWINDER(rewinder);
return 0;
@ -1570,16 +1607,19 @@ static int dns_packet_read_type_windows(DnsPacket *p, Bitmap **types, size_t siz
return 0;
}
int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, bool *ret_cache_flush, size_t *start) {
int dns_packet_read_key(
DnsPacket *p,
DnsResourceKey **ret,
bool *ret_cache_flush,
size_t *ret_start) {
_cleanup_(rewind_dns_packet) DnsPacketRewinder rewinder;
_cleanup_free_ char *name = NULL;
bool cache_flush = false;
uint16_t class, type;
DnsResourceKey *key;
int r;
assert(p);
assert(ret);
INIT_REWINDER(rewinder, p);
r = dns_packet_read_name(p, &name, true, NULL);
@ -1603,19 +1643,23 @@ int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, bool *ret_cache_flus
}
}
key = dns_resource_key_new_consume(class, type, name);
if (!key)
return -ENOMEM;
if (ret) {
DnsResourceKey *key;
name = NULL;
*ret = key;
key = dns_resource_key_new_consume(class, type, name);
if (!key)
return -ENOMEM;
TAKE_PTR(name);
*ret = key;
}
if (ret_cache_flush)
*ret_cache_flush = cache_flush;
if (start)
*start = rewinder.saved_rindex;
CANCEL_REWINDER(rewinder);
if (ret_start)
*ret_start = rewinder.saved_rindex;
CANCEL_REWINDER(rewinder);
return 0;
}
@ -1625,7 +1669,12 @@ static bool loc_size_ok(uint8_t size) {
return m <= 9 && e <= 9 && (m > 0 || e == 0);
}
int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_flush, size_t *start) {
int dns_packet_read_rr(
DnsPacket *p,
DnsResourceRecord **ret,
bool *ret_cache_flush,
size_t *ret_start) {
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
_cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
_cleanup_(rewind_dns_packet) DnsPacketRewinder rewinder;
@ -1635,7 +1684,6 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl
int r;
assert(p);
assert(ret);
INIT_REWINDER(rewinder, p);
@ -2076,14 +2124,14 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl
if (p->rindex != offset + rdlength)
return -EBADMSG;
*ret = TAKE_PTR(rr);
if (ret)
*ret = TAKE_PTR(rr);
if (ret_cache_flush)
*ret_cache_flush = cache_flush;
if (start)
*start = rewinder.saved_rindex;
CANCEL_REWINDER(rewinder);
if (ret_start)
*ret_start = rewinder.saved_rindex;
CANCEL_REWINDER(rewinder);
return 0;
}
@ -2203,8 +2251,9 @@ static int dns_packet_extract_answer(DnsPacket *p, DnsAnswer **ret_answer) {
for (i = 0; i < n; i++) {
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
bool cache_flush = false;
size_t start;
r = dns_packet_read_rr(p, &rr, &cache_flush, NULL);
r = dns_packet_read_rr(p, &rr, &cache_flush, &start);
if (r < 0)
return r;
@ -2272,15 +2321,26 @@ static int dns_packet_extract_answer(DnsPacket *p, DnsAnswer **ret_answer) {
}
p->opt = dns_resource_record_ref(rr);
p->opt_start = start;
assert(p->rindex >= start);
p->opt_size = p->rindex - start;
} else {
/* According to RFC 4795, section 2.9. only the RRs from the Answer section
* shall be cached. Hence mark only those RRs as cacheable by default, but
* not the ones from the Additional or Authority sections. */
DnsAnswerFlags flags =
(i < DNS_PACKET_ANCOUNT(p) ? DNS_ANSWER_CACHEABLE : 0) |
(p->protocol == DNS_PROTOCOL_MDNS && !cache_flush ? DNS_ANSWER_SHARED_OWNER : 0);
DnsAnswerFlags flags = 0;
r = dns_answer_add(answer, rr, p->ifindex, flags);
if (p->protocol == DNS_PROTOCOL_MDNS && !cache_flush)
flags |= DNS_ANSWER_SHARED_OWNER;
/* According to RFC 4795, section 2.9. only the RRs from the Answer section shall be
* cached. Hence mark only those RRs as cacheable by default, but not the ones from
* the Additional or Authority sections. */
if (i < DNS_PACKET_ANCOUNT(p))
flags |= DNS_ANSWER_CACHEABLE|DNS_ANSWER_SECTION_ANSWER;
else if (i < DNS_PACKET_ANCOUNT(p) + DNS_PACKET_NSCOUNT(p))
flags |= DNS_ANSWER_SECTION_AUTHORITY;
else
flags |= DNS_ANSWER_SECTION_ADDITIONAL;
r = dns_answer_add(answer, rr, p->ifindex, flags, NULL);
if (r < 0)
return r;
}
@ -2356,6 +2416,106 @@ int dns_packet_is_reply_for(DnsPacket *p, const DnsResourceKey *key) {
return dns_resource_key_equal(p->question->keys[0], key);
}
int dns_packet_patch_max_udp_size(DnsPacket *p, uint16_t max_udp_size) {
assert(p);
assert(max_udp_size >= DNS_PACKET_UNICAST_SIZE_MAX);
if (p->opt_start == (size_t) -1) /* No OPT section, nothing to patch */
return 0;
assert(p->opt_size != (size_t) -1);
assert(p->opt_size >= 5);
unaligned_write_be16(DNS_PACKET_DATA(p) + p->opt_start + 3, max_udp_size);
return 1;
}
static int patch_rr(DnsPacket *p, usec_t age) {
_cleanup_(rewind_dns_packet) DnsPacketRewinder rewinder;
size_t ttl_index;
uint32_t ttl;
uint16_t type, rdlength;
int r;
INIT_REWINDER(rewinder, p);
/* Patches the RR at the current rindex, substracts the specified time from the TTL */
r = dns_packet_read_name(p, NULL, true, NULL);
if (r < 0)
return r;
r = dns_packet_read_uint16(p, &type, NULL);
if (r < 0)
return r;
r = dns_packet_read_uint16(p, NULL, NULL);
if (r < 0)
return r;
r = dns_packet_read_uint32(p, &ttl, &ttl_index);
if (r < 0)
return r;
if (type != DNS_TYPE_OPT) { /* The TTL of the OPT field is not actually a TTL, skip it */
ttl = LESS_BY(ttl * USEC_PER_SEC, age) / USEC_PER_SEC;
unaligned_write_be32(DNS_PACKET_DATA(p) + ttl_index, ttl);
}
r = dns_packet_read_uint16(p, &rdlength, NULL);
if (r < 0)
return r;
r = dns_packet_read(p, rdlength, NULL, NULL);
if (r < 0)
return r;
CANCEL_REWINDER(rewinder);
return 0;
}
int dns_packet_patch_ttls(DnsPacket *p, usec_t timestamp) {
_cleanup_(rewind_dns_packet) DnsPacketRewinder rewinder = {};
unsigned i, n;
usec_t k;
int r;
assert(p);
assert(timestamp_is_set(timestamp));
/* Adjusts all TTLs in the packet by subtracting the time difference between now and the specified timestamp */
k = now(clock_boottime_or_monotonic());
assert(k >= timestamp);
k -= timestamp;
INIT_REWINDER(rewinder, p);
dns_packet_rewind(p, DNS_PACKET_HEADER_SIZE);
n = DNS_PACKET_QDCOUNT(p);
for (i = 0; i < n; i++) {
r = dns_packet_read_key(p, NULL, NULL, NULL);
if (r < 0)
return r;
}
n = DNS_PACKET_RRCOUNT(p);
for (i = 0; i < n; i++) {
/* DNS servers suck, hence the RR count is in many servers off. If we reached the end
* prematurely, accept that, exit early */
if (p->rindex == p->size)
break;
r = patch_rr(p, k);
if (r < 0)
return r;
}
return 0;
}
static void dns_packet_hash_func(const DnsPacket *s, struct siphash *state) {
assert(s);

View File

@ -176,6 +176,8 @@ static inline unsigned DNS_PACKET_RRCOUNT(DnsPacket *p) {
int dns_packet_new(DnsPacket **p, DnsProtocol protocol, size_t min_alloc_dsize, size_t max_size);
int dns_packet_new_query(DnsPacket **p, DnsProtocol protocol, size_t min_alloc_dsize, bool dnssec_checking_disabled);
int dns_packet_dup(DnsPacket **ret, DnsPacket *p);
void dns_packet_set_flags(DnsPacket *p, bool dnssec_checking_disabled, bool truncated);
DnsPacket *dns_packet_ref(DnsPacket *p);
@ -201,7 +203,10 @@ int dns_packet_append_key(DnsPacket *p, const DnsResourceKey *key, const DnsAnsw
int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, const DnsAnswerFlags flags, size_t *start, size_t *rdata_start);
int dns_packet_append_opt(DnsPacket *p, uint16_t max_udp_size, bool edns0_do, bool include_rfc6975, int rcode, size_t *start);
int dns_packet_append_question(DnsPacket *p, DnsQuestion *q);
int dns_packet_append_answer(DnsPacket *p, DnsAnswer *a);
int dns_packet_append_answer(DnsPacket *p, DnsAnswer *a, unsigned *completed);
int dns_packet_patch_max_udp_size(DnsPacket *p, uint16_t max_udp_size);
int dns_packet_patch_ttls(DnsPacket *p, usec_t timestamp);
void dns_packet_truncate(DnsPacket *p, size_t sz);
int dns_packet_truncate_opt(DnsPacket *p);

View File

@ -97,20 +97,35 @@ static int dns_query_candidate_next_search_domain(DnsQueryCandidate *c) {
return 1;
}
static int dns_query_candidate_add_transaction(DnsQueryCandidate *c, DnsResourceKey *key) {
static int dns_query_candidate_add_transaction(
DnsQueryCandidate *c,
DnsResourceKey *key,
DnsPacket *bypass) {
_cleanup_(dns_transaction_gcp) DnsTransaction *t = NULL;
int r;
assert(c);
assert(key);
t = dns_scope_find_transaction(c->scope, key, true);
if (!t) {
r = dns_transaction_new(&t, c->scope, key);
if (key) {
/* Regular lookup with a resource key */
assert(!bypass);
t = dns_scope_find_transaction(c->scope, key, c->query->flags);
if (!t) {
r = dns_transaction_new(&t, c->scope, key, NULL, c->query->flags);
if (r < 0)
return r;
} else if (set_contains(c->transactions, t))
return 0;
} else {
/* "Bypass" lookup with a query packet */
assert(bypass);
r = dns_transaction_new(&t, c->scope, NULL, bypass, c->query->flags);
if (r < 0)
return r;
} else if (set_contains(c->transactions, t))
return 0;
}
r = set_ensure_allocated(&t->notify_query_candidates_done, NULL);
if (r < 0)
@ -126,7 +141,6 @@ static int dns_query_candidate_add_transaction(DnsQueryCandidate *c, DnsResource
return r;
}
t->clamp_ttl = c->query->clamp_ttl;
TAKE_PTR(t);
return 1;
}
@ -214,6 +228,21 @@ static int dns_query_candidate_setup_transactions(DnsQueryCandidate *c) {
dns_query_candidate_stop(c);
if (c->query->question_bypass) {
/* If this is a bypass query, then pass the original query packet along to the transaction */
assert(dns_question_size(c->query->question_bypass->question) == 1);
if (!dns_scope_good_key(c->scope, c->query->question_bypass->question->keys[0]))
return 0;
r = dns_query_candidate_add_transaction(c, NULL, c->query->question_bypass);
if (r < 0)
goto fail;
return 1;
}
question = dns_query_question_for_protocol(c->query, c->scope->protocol);
/* Create one transaction per question key */
@ -233,7 +262,7 @@ static int dns_query_candidate_setup_transactions(DnsQueryCandidate *c) {
if (!dns_scope_good_key(c->scope, qkey))
continue;
r = dns_query_candidate_add_transaction(c, qkey);
r = dns_query_candidate_add_transaction(c, qkey, NULL);
if (r < 0)
goto fail;
@ -321,6 +350,7 @@ static void dns_query_reset_answer(DnsQuery *q) {
q->answer_protocol = _DNS_PROTOCOL_INVALID;
q->answer_family = AF_UNSPEC;
q->answer_search_domain = dns_search_domain_unref(q->answer_search_domain);
q->answer_full_packet = dns_packet_unref(q->answer_full_packet);
}
DnsQuery *dns_query_free(DnsQuery *q) {
@ -340,6 +370,7 @@ DnsQuery *dns_query_free(DnsQuery *q) {
dns_question_unref(q->question_idna);
dns_question_unref(q->question_utf8);
dns_packet_unref(q->question_bypass);
dns_query_reset_answer(q);
@ -351,13 +382,15 @@ DnsQuery *dns_query_free(DnsQuery *q) {
varlink_unref(q->varlink_request);
}
dns_packet_unref(q->request_dns_packet);
dns_packet_unref(q->reply_dns_packet);
dns_packet_unref(q->request_packet);
dns_answer_unref(q->reply_answer);
dns_answer_unref(q->reply_authoritative);
dns_answer_unref(q->reply_additional);
if (q->request_dns_stream) {
if (q->request_stream) {
/* Detach the stream from our query, in case something else keeps a reference to it. */
(void) set_remove(q->request_dns_stream->queries, q);
q->request_dns_stream = dns_stream_unref(q->request_dns_stream);
(void) set_remove(q->request_stream->queries, q);
q->request_stream = dns_stream_unref(q->request_stream);
}
free(q->request_address_string);
@ -375,36 +408,27 @@ int dns_query_new(
DnsQuery **ret,
DnsQuestion *question_utf8,
DnsQuestion *question_idna,
DnsPacket *question_bypass,
int ifindex,
uint64_t flags) {
_cleanup_(dns_query_freep) DnsQuery *q = NULL;
DnsResourceKey *key;
bool good = false;
int r;
char key_str[DNS_RESOURCE_KEY_STRING_MAX];
DnsResourceKey *key;
int r;
assert(m);
if (dns_question_size(question_utf8) > 0) {
r = dns_question_is_valid_for_query(question_utf8);
if (r < 0)
return r;
if (r == 0)
if (question_bypass) {
/* It's either a "bypass" query, or a regular one, but can't be both. */
if (question_utf8 || question_idna)
return -EINVAL;
good = true;
}
} else {
bool good = false;
/* If the IDNA and UTF8 questions are the same, merge their references */
r = dns_question_is_equal(question_idna, question_utf8);
if (r < 0)
return r;
if (r > 0)
question_idna = question_utf8;
else {
if (dns_question_size(question_idna) > 0) {
r = dns_question_is_valid_for_query(question_idna);
if (dns_question_size(question_utf8) > 0) {
r = dns_question_is_valid_for_query(question_utf8);
if (r < 0)
return r;
if (r == 0)
@ -412,10 +436,28 @@ int dns_query_new(
good = true;
}
}
if (!good) /* don't allow empty queries */
return -EINVAL;
/* If the IDNA and UTF8 questions are the same, merge their references */
r = dns_question_is_equal(question_idna, question_utf8);
if (r < 0)
return r;
if (r > 0)
question_idna = question_utf8;
else {
if (dns_question_size(question_idna) > 0) {
r = dns_question_is_valid_for_query(question_idna);
if (r < 0)
return r;
if (r == 0)
return -EINVAL;
good = true;
}
}
if (!good) /* don't allow empty queries */
return -EINVAL;
}
if (m->n_dns_queries >= QUERIES_MAX)
return -EBUSY;
@ -427,6 +469,7 @@ int dns_query_new(
*q = (DnsQuery) {
.question_utf8 = dns_question_ref(question_utf8),
.question_idna = dns_question_ref(question_idna),
.question_bypass = dns_packet_ref(question_bypass),
.ifindex = ifindex,
.flags = flags,
.answer_dnssec_result = _DNSSEC_RESULT_INVALID,
@ -434,21 +477,27 @@ int dns_query_new(
.answer_family = AF_UNSPEC,
};
/* First dump UTF8 question */
DNS_QUESTION_FOREACH(key, question_utf8)
log_debug("Looking up RR for %s.",
dns_resource_key_to_string(key, key_str, sizeof key_str));
if (question_bypass) {
DNS_QUESTION_FOREACH(key, question_bypass->question)
log_debug("Looking up bypass packet for %s.",
dns_resource_key_to_string(key, key_str, sizeof key_str));
} else {
/* First dump UTF8 question */
DNS_QUESTION_FOREACH(key, question_utf8)
log_debug("Looking up RR for %s.",
dns_resource_key_to_string(key, key_str, sizeof key_str));
/* And then dump the IDNA question, but only what hasn't been dumped already through the UTF8 question. */
DNS_QUESTION_FOREACH(key, question_idna) {
r = dns_question_contains(question_utf8, key);
if (r < 0)
return r;
if (r > 0)
continue;
/* And then dump the IDNA question, but only what hasn't been dumped already through the UTF8 question. */
DNS_QUESTION_FOREACH(key, question_idna) {
r = dns_question_contains(question_utf8, key);
if (r < 0)
return r;
if (r > 0)
continue;
log_debug("Looking up IDNA RR for %s.",
dns_resource_key_to_string(key, key_str, sizeof key_str));
log_debug("Looking up IDNA RR for %s.",
dns_resource_key_to_string(key, key_str, sizeof key_str));
}
}
LIST_PREPEND(queries, m->dns_queries, q);
@ -457,8 +506,8 @@ int dns_query_new(
if (ret)
*ret = q;
q = NULL;
TAKE_PTR(q);
return 0;
}
@ -559,9 +608,12 @@ static int dns_query_synthesize_reply(DnsQuery *q, DnsTransactionState *state) {
DNS_TRANSACTION_NOT_FOUND))
return 0;
if (FLAGS_SET(q->flags, SD_RESOLVED_NO_SYNTHESIZE))
return 0;
r = dns_synthesize_answer(
q->manager,
q->question_utf8,
q->question_bypass ? q->question_bypass->question : q->question_utf8,
q->ifindex,
&answer);
if (r == -ENXIO) {
@ -601,9 +653,12 @@ static int dns_query_try_etc_hosts(DnsQuery *q) {
/* Looks in /etc/hosts for matching entries. Note that this is done *before* the normal lookup is
* done. The data from /etc/hosts hence takes precedence over the network. */
if (FLAGS_SET(q->flags, SD_RESOLVED_NO_SYNTHESIZE))
return 0;
r = manager_etc_hosts_lookup(
q->manager,
q->question_utf8,
q->question_bypass ? q->question_bypass->question : q->question_utf8,
&answer);
if (r <= 0)
return r;
@ -757,6 +812,7 @@ static void dns_query_accept(DnsQuery *q, DnsQueryCandidate *c) {
q->answer_dnssec_result = _DNSSEC_RESULT_INVALID;
q->answer_authenticated = false;
q->answer_errno = c->error_code;
q->answer_full_packet = dns_packet_unref(q->answer_full_packet);
}
SET_FOREACH(t, c->transactions) {
@ -764,14 +820,24 @@ static void dns_query_accept(DnsQuery *q, DnsQueryCandidate *c) {
switch (t->state) {
case DNS_TRANSACTION_SUCCESS: {
/* We found a successfully reply, merge it into the answer */
r = dns_answer_extend(&q->answer, t->answer);
if (r < 0)
goto fail;
/* We found a successful reply, merge it into the answer */
if (state == DNS_TRANSACTION_SUCCESS) {
r = dns_answer_extend(&q->answer, t->answer);
if (r < 0)
goto fail;
} else {
/* Override non-successful previous answers */
dns_answer_unref(q->answer);
q->answer = dns_answer_ref(t->answer);
}
q->answer_rcode = t->answer_rcode;
q->answer_errno = 0;
dns_packet_unref(q->answer_full_packet);
q->answer_full_packet = dns_packet_ref(t->received);
if (t->answer_authenticated) {
has_authenticated = true;
dnssec_result_authenticated = t->answer_dnssec_result;
@ -800,11 +866,14 @@ static void dns_query_accept(DnsQuery *q, DnsQueryCandidate *c) {
if (q->answer_authenticated && !t->answer_authenticated)
continue;
q->answer = dns_answer_unref(q->answer);
dns_answer_unref(q->answer);
q->answer = dns_answer_ref(t->answer);
q->answer_rcode = t->answer_rcode;
q->answer_dnssec_result = t->answer_dnssec_result;
q->answer_authenticated = t->answer_authenticated;
q->answer_errno = t->answer_errno;
dns_packet_unref(q->answer_full_packet);
q->answer_full_packet = dns_packet_ref(t->received);
state = t->state;
break;
@ -998,6 +1067,9 @@ int dns_query_process_cname(DnsQuery *q) {
DnsQuestion* dns_query_question_for_protocol(DnsQuery *q, DnsProtocol protocol) {
assert(q);
if (q->question_bypass)
return q->question_bypass->question;
switch (protocol) {
case DNS_PROTOCOL_DNS:
@ -1018,6 +1090,9 @@ const char *dns_query_string(DnsQuery *q) {
/* Returns a somewhat useful human-readable lookup key string for this query */
if (q->question_bypass)
return dns_question_first_name(q->question_bypass->question);
if (q->request_address_string)
return q->request_address_string;

View File

@ -49,12 +49,13 @@ struct DnsQuery {
DnsQuestion *question_idna;
DnsQuestion *question_utf8;
/* If this is not a question by ourselves, but a "bypass" request, we propagate the original packet
* here, and use that instead. */
DnsPacket *question_bypass;
uint64_t flags;
int ifindex;
/* If true, the RR TTLs of the answer will be clamped by their current left validity in the cache */
bool clamp_ttl;
DnsTransactionState state;
unsigned n_cname_redirects;
@ -71,6 +72,7 @@ struct DnsQuery {
DnsSearchDomain *answer_search_domain;
int answer_errno; /* if state is DNS_TRANSACTION_ERRNO */
bool previous_redirect_unauthenticated;
DnsPacket *answer_full_packet;
/* Bus + Varlink client information */
sd_bus_message *bus_request;
@ -82,9 +84,11 @@ struct DnsQuery {
char *request_address_string;
/* DNS stub information */
DnsPacket *request_dns_packet;
DnsStream *request_dns_stream;
DnsPacket *reply_dns_packet;
DnsPacket *request_packet;
DnsStream *request_stream;
DnsAnswer *reply_answer;
DnsAnswer *reply_authoritative;
DnsAnswer *reply_additional;
DnsStubListenerExtra *stub_listener_extra;
/* Completion callback */
@ -109,7 +113,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(DnsQueryCandidate*, dns_query_candidate_unref);
void dns_query_candidate_notify(DnsQueryCandidate *c);
int dns_query_new(Manager *m, DnsQuery **q, DnsQuestion *question_utf8, DnsQuestion *question_idna, int family, uint64_t flags);
int dns_query_new(Manager *m, DnsQuery **q, DnsQuestion *question_utf8, DnsQuestion *question_idna, DnsPacket *question_bypass, int family, uint64_t flags);
DnsQuery *dns_query_free(DnsQuery *q);
int dns_query_make_auxiliary(DnsQuery *q, DnsQuery *auxiliary_for);

View File

@ -646,11 +646,10 @@ bool dns_scope_good_key(DnsScope *s, const DnsResourceKey *key) {
assert(s);
assert(key);
/* Check if it makes sense to resolve the specified key on
* this scope. Note that this call assumes as fully qualified
* name, i.e. the search suffixes already appended. */
/* Check if it makes sense to resolve the specified key on this scope. Note that this call assumes a
* fully qualified name, i.e. the search suffixes already appended. */
if (key->class != DNS_CLASS_IN)
if (!IN_SET(key->class, DNS_CLASS_IN, DNS_CLASS_ANY))
return false;
if (s->protocol == DNS_PROTOCOL_DNS) {
@ -672,8 +671,7 @@ bool dns_scope_good_key(DnsScope *s, const DnsResourceKey *key) {
return !dns_name_is_root(name);
}
/* On mDNS and LLMNR, send A and AAAA queries only on the
* respective scopes */
/* On mDNS and LLMNR, send A and AAAA queries only on the respective scopes */
key_family = dns_type_to_af(key->type);
if (key_family < 0)
@ -765,6 +763,7 @@ int dns_scope_make_reply_packet(
DnsPacket **ret) {
_cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
unsigned n_answer = 0, n_soa = 0;
int r;
assert(s);
@ -796,15 +795,15 @@ int dns_scope_make_reply_packet(
return r;
DNS_PACKET_HEADER(p)->qdcount = htobe16(dns_question_size(q));
r = dns_packet_append_answer(p, answer);
r = dns_packet_append_answer(p, answer, &n_answer);
if (r < 0)
return r;
DNS_PACKET_HEADER(p)->ancount = htobe16(dns_answer_size(answer));
DNS_PACKET_HEADER(p)->ancount = htobe16(n_answer);
r = dns_packet_append_answer(p, soa);
r = dns_packet_append_answer(p, soa, &n_soa);
if (r < 0)
return r;
DNS_PACKET_HEADER(p)->arcount = htobe16(dns_answer_size(soa));
DNS_PACKET_HEADER(p)->arcount = htobe16(n_soa);
*ret = TAKE_PTR(p);
@ -926,26 +925,50 @@ void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) {
}
}
DnsTransaction *dns_scope_find_transaction(DnsScope *scope, DnsResourceKey *key, bool cache_ok) {
DnsTransaction *t;
DnsTransaction *dns_scope_find_transaction(
DnsScope *scope,
DnsResourceKey *key,
uint64_t query_flags) {
DnsTransaction *first, *t;
assert(scope);
assert(key);
/* Try to find an ongoing transaction that is a equal to the
* specified question */
t = hashmap_get(scope->transactions_by_key, key);
if (!t)
return NULL;
/* Iterate through the list of transactions with a matching key */
first = hashmap_get(scope->transactions_by_key, key);
LIST_FOREACH(transactions_by_key, t, first) {
/* 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_RCODE_FAILURE) &&
t->answer_source != DNS_TRANSACTION_NETWORK)
return NULL;
/* These four flags must match exactly: we cannot use a validated response for a
* non-validating client, and we cannot use a non-validated response for a validating
* client. Similar, if the sources don't match things aren't usable either. */
if (((query_flags ^ t->query_flags) &
(SD_RESOLVED_NO_VALIDATE|
SD_RESOLVED_NO_ZONE|
SD_RESOLVED_NO_TRUST_ANCHOR|
SD_RESOLVED_NO_NETWORK)) != 0)
continue;
return t;
/* We can reuse a primary query if a regular one is requested, but not vice versa */
if ((query_flags & SD_RESOLVED_REQUIRE_PRIMARY) &&
!(t->query_flags & SD_RESOLVED_REQUIRE_PRIMARY))
continue;
/* Don't reuse a transaction that allowed caching when we got told not to use it */
if ((query_flags & SD_RESOLVED_NO_CACHE) &&
!(t->query_flags & SD_RESOLVED_NO_CACHE))
continue;
/* If we are are asked to clamp ttls an 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))
continue;
return t;
}
return NULL;
}
static int dns_scope_make_conflict_packet(
@ -1289,7 +1312,7 @@ int dns_scope_announce(DnsScope *scope, bool goodbye) {
else
flags = goodbye ? (DNS_ANSWER_GOODBYE|DNS_ANSWER_CACHE_FLUSH) : DNS_ANSWER_CACHE_FLUSH;
r = dns_answer_add(answer, i->rr, 0 , flags);
r = dns_answer_add(answer, i->rr, 0, flags, NULL);
if (r < 0)
return log_debug_errno(r, "Failed to add RR to announce: %m");
}
@ -1307,7 +1330,7 @@ int dns_scope_announce(DnsScope *scope, bool goodbye) {
if (r < 0)
log_warning_errno(r, "Failed to add DNS-SD PTR record to MDNS zone: %m");
r = dns_answer_add(answer, rr, 0 , 0);
r = dns_answer_add(answer, rr, 0, 0, NULL);
if (r < 0)
return log_debug_errno(r, "Failed to add RR to announce: %m");
}

View File

@ -53,14 +53,12 @@ struct DnsScope {
LIST_HEAD(DnsQueryCandidate, query_candidates);
/* Note that we keep track of ongoing transactions in two
* ways: once in a hashmap, indexed by the rr key, and once in
* a linked list. We use the hashmap to quickly find
* transactions we can reuse for a key. But note that there
* might be multiple transactions for the same key (because
* the zone probing can't reuse a transaction answered from
* the zone or the cache), and the hashmap only tracks the
* most recent entry. */
/* Note that we keep track of ongoing transactions in two ways: once in a hashmap, indexed by the rr
* key, and once in a linked list. We use the hashmap to quickly find transactions we can reuse for a
* key. But note that there might be multiple transactions for the same key (because the associated
* query flags might differ in incompatible ways: e.g. we may not reuse a non-validating transaction
* as validating. Hence we maintain a per-key list of transactions, which we iterate through to find
* one we can reuse with matching flags. */
Hashmap *transactions_by_key;
LIST_HEAD(DnsTransaction, transactions);
@ -90,7 +88,7 @@ int dns_scope_mdns_membership(DnsScope *s, bool b);
int dns_scope_make_reply_packet(DnsScope *s, uint16_t id, int rcode, DnsQuestion *q, DnsAnswer *answer, DnsAnswer *soa, bool tentative, DnsPacket **ret);
void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p);
DnsTransaction *dns_scope_find_transaction(DnsScope *scope, DnsResourceKey *key, bool cache_ok);
DnsTransaction *dns_scope_find_transaction(DnsScope *scope, DnsResourceKey *key, uint64_t query_flags);
int dns_scope_notify_conflict(DnsScope *scope, DnsResourceRecord *rr);
void dns_scope_check_conflicts(DnsScope *scope, DnsPacket *p);

View File

@ -85,69 +85,259 @@ DnsStubListenerExtra *dns_stub_listener_extra_free(DnsStubListenerExtra *p) {
return mfree(p);
}
static int dns_stub_make_reply_packet(
DnsPacket **p,
size_t max_size,
DnsQuestion *q,
static int dns_stub_collect_answer_by_question(
DnsAnswer **reply,
DnsAnswer *answer,
bool *ret_truncated) {
DnsQuestion *question,
bool with_rrsig) { /* Add RRSIG RR matching each RR */
bool truncated = false;
DnsResourceRecord *rr;
DnsAnswerItem *item;
int r;
assert(reply);
/* Copies all RRs from 'answer' into 'reply', if they match 'question'. */
DNS_ANSWER_FOREACH_ITEM(item, answer) {
if (question) {
bool match = false;
r = dns_question_matches_rr(question, item->rr, NULL);
if (r < 0)
return r;
else if (r > 0)
match = true;
else {
r = dns_question_matches_cname_or_dname(question, item->rr, NULL);
if (r < 0)
return r;
if (r > 0)
match = true;
}
if (!match)
continue;
}
r = dns_answer_add_extend(reply, item->rr, item->ifindex, item->flags, item->rrsig);
if (r < 0)
return r;
if (with_rrsig && item->rrsig) {
r = dns_answer_add_extend(reply, item->rrsig, item->ifindex, item->flags, NULL);
if (r < 0)
return r;
}
}
return 0;
}
static int dns_stub_collect_answer_by_section(
DnsAnswer **reply,
DnsAnswer *answer,
DnsAnswerFlags section,
DnsAnswer *exclude1,
DnsAnswer *exclude2,
bool with_dnssec) { /* Include DNSSEC RRs. RRSIG, NSEC, … */
DnsAnswerItem *item;
unsigned c = 0;
int r;
assert(p);
assert(reply);
/* Note that we don't bother with any additional RRs, as this is stub is for local lookups only, and hence
* roundtrips aren't expensive. */
/* Copies all RRs from 'answer' into 'reply', if they originate from the specified section. Also,
* avoid any RRs listed in 'exclude'. */
if (!*p) {
r = dns_packet_new(p, DNS_PROTOCOL_DNS, 0, max_size);
if (r < 0)
return r;
DNS_ANSWER_FOREACH_ITEM(item, answer) {
r = dns_packet_append_question(*p, q);
if (r < 0)
return r;
if (dns_answer_contains(exclude1, item->rr) ||
dns_answer_contains(exclude2, item->rr))
continue;
DNS_PACKET_HEADER(*p)->qdcount = htobe16(dns_question_size(q));
}
if (!with_dnssec &&
dns_type_is_dnssec(item->rr->key->type))
continue;
DNS_ANSWER_FOREACH(rr, answer) {
if (((item->flags ^ section) & (DNS_ANSWER_SECTION_ANSWER|DNS_ANSWER_SECTION_AUTHORITY|DNS_ANSWER_SECTION_ADDITIONAL)) != 0)
continue;
r = dns_question_matches_rr(q, rr, NULL);
if (r < 0)
return r;
if (r > 0)
goto add;
r = dns_question_matches_cname_or_dname(q, rr, NULL);
if (r < 0)
return r;
if (r > 0)
goto add;
continue;
add:
r = dns_packet_append_rr(*p, rr, 0, NULL, NULL);
if (r == -EMSGSIZE) {
truncated = true;
break;
}
r = dns_answer_add_extend(reply, item->rr, item->ifindex, item->flags, item->rrsig);
if (r < 0)
return r;
c++;
if (with_dnssec && item->rrsig) {
r = dns_answer_add_extend(reply, item->rrsig, item->ifindex, item->flags, NULL);
if (r < 0)
return r;
c++;
}
}
return (int) c;
}
static int dns_stub_assign_sections(
DnsQuery *q,
DnsQuestion *question,
bool edns0_do) {
int r;
assert(q);
assert(question);
/* Let's assign the 'answer' and 'answer_auxiliary' RRs we collected to their respective sections in
* the reply datagram. We try to reproduce a section assignment similar to what the upstream DNS
* server responded to us. We use the DNS_ANSWER_SECTION_xyz flags to match things up, which is where
* the original upstream's packet section assignment is stored in the DnsAnswer object. Not all RRs
* in the 'answer' and 'answer_auxiliary' objects come with section information though (for example,
* because they were synthesized locally, and not from a DNS packet). To deal with that we extend the
* assignment logic a bit: anything from the 'answer' object that directly matches the original
* question is always put in the ANSWER section, regardless if it carries section info, or what that
* section info says. Then, anything from the 'answer' and 'answer_auxiliary' objects that is from
* the ANSWER or AUTHORITY sections, and wasn't already added to the ANSWER section is placed in the
* AUTHORITY section. Everything else from either object is added to the ADDITIONAL section. */
/* Include all RRs that directly answer the question in the answer section */
r = dns_stub_collect_answer_by_question(
&q->reply_answer,
q->answer,
question,
edns0_do);
if (r < 0)
return r;
/* Include all RRs that originate from the answer or authority sections, and aren't listed in the
* answer section, in the authority section */
r = dns_stub_collect_answer_by_section(
&q->reply_authoritative,
q->answer,
DNS_ANSWER_SECTION_ANSWER,
q->reply_answer, NULL,
edns0_do);
if (r < 0)
return r;
/* Include all RRs that originate from the answer or authority sections, and aren't listed in the
* answer section, in the authority section */
r = dns_stub_collect_answer_by_section(
&q->reply_authoritative,
q->answer,
DNS_ANSWER_SECTION_AUTHORITY,
q->reply_answer, NULL,
edns0_do);
if (r < 0)
return r;
/* Include all RRs that originate from the additional sections in the additional section (except if
* already listed in the other two sections). Also add all RRs with no section marking. */
r = dns_stub_collect_answer_by_section(
&q->reply_additional,
q->answer,
DNS_ANSWER_SECTION_ADDITIONAL,
q->reply_answer, q->reply_authoritative,
edns0_do);
if (r < 0)
return r;
r = dns_stub_collect_answer_by_section(
&q->reply_additional,
q->answer,
0,
q->reply_answer, q->reply_authoritative,
edns0_do);
if (r < 0)
return r;
return 0;
}
static int dns_stub_make_reply_packet(
DnsPacket **ret,
size_t max_size,
DnsQuestion *q,
bool *ret_truncated) {
_cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
bool tc = false;
int r;
assert(ret);
r = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0, max_size);
if (r < 0)
return r;
r = dns_packet_append_question(p, q);
if (r == -EMSGSIZE)
tc = true;
else if (r < 0)
return r;
if (ret_truncated)
*ret_truncated = truncated;
else if (truncated)
*ret_truncated = tc;
else if (tc)
return -EMSGSIZE;
DNS_PACKET_HEADER(*p)->ancount = htobe16(be16toh(DNS_PACKET_HEADER(*p)->ancount) + c);
DNS_PACKET_HEADER(p)->qdcount = htobe16(dns_question_size(q));
*ret = TAKE_PTR(p);
return 0;
}
static int dns_stub_add_reply_packet_body(
DnsPacket *p,
DnsAnswer *answer,
DnsAnswer *authoritative,
DnsAnswer *additional,
bool edns0_do, /* Client expects DNSSEC RRs? */
bool *truncated) {
unsigned n_answer = 0, n_authoritative = 0, n_additional = 0;
bool tc = false;
int r;
assert(p);
/* Add the three sections to the packet. If the answer section doesn't fit we'll signal that as
* truncation. If the authoritative section doesn't fit and we are in DNSSEC mode, also signal
* truncation. In all other cases where things don't fit don't signal truncation, as for those cases
* the dropped RRs should not be essential. */
r = dns_packet_append_answer(p, answer, &n_answer);
if (r == -EMSGSIZE)
tc = true;
else if (r < 0)
return r;
else {
r = dns_packet_append_answer(p, authoritative, &n_authoritative);
if (r == -EMSGSIZE) {
if (edns0_do)
tc = true;
} else if (r < 0)
return r;
else {
r = dns_packet_append_answer(p, additional, &n_additional);
if (r < 0 && r != -EMSGSIZE)
return r;
}
}
if (tc) {
if (!truncated)
return -EMSGSIZE;
*truncated = true;
}
DNS_PACKET_HEADER(p)->ancount = htobe16(n_answer);
DNS_PACKET_HEADER(p)->nscount = htobe16(n_authoritative);
DNS_PACKET_HEADER(p)->arcount = htobe16(n_additional);
return 0;
}
@ -159,6 +349,7 @@ static int dns_stub_finish_reply_packet(
bool add_opt, /* add an OPT RR to this packet? */
bool edns0_do, /* set the EDNS0 DNSSEC OK bit? */
bool ad, /* set the DNSSEC authenticated data bit? */
bool cd, /* set the DNSSEC checking disabled bit? */
uint16_t max_udp_size) { /* The maximum UDP datagram size to advertise to clients */
int r;
@ -171,19 +362,21 @@ static int dns_stub_finish_reply_packet(
tc = true;
else if (r < 0)
return r;
} else {
/* If the client can't to EDNS0, don't do DO either */
edns0_do = false;
/* If the client didn't do EDNS, clamp the rcode to 4 bit */
/* If we don't do EDNS, clamp the rcode to 4 bit */
if (rcode > 0xF)
rcode = DNS_RCODE_SERVFAIL;
}
/* Don't set the AD bit unless DO is on, too */
if (!edns0_do)
/* Don't set the AD or CD bit unless DO is on, too */
if (!edns0_do) {
ad = false;
cd = false;
}
DNS_PACKET_HEADER(p)->id = id;
@ -195,7 +388,7 @@ static int dns_stub_finish_reply_packet(
1 /* rd */,
1 /* ra */,
ad /* ad */,
0 /* cd */,
cd /* cd */,
rcode));
return 0;
@ -231,6 +424,66 @@ static int dns_stub_send(
return 0;
}
static int dns_stub_send_reply(
DnsQuery *q,
int rcode) {
_cleanup_(dns_packet_unrefp) DnsPacket *reply = NULL;
bool truncated, edns0_do;
int r;
assert(q);
/* Reply with DNSSEC DO set? Only if client supports it; and we did any DNSSEC verification
* ourselves, or consider the data fully authenticated because we generated it locally, or
* the client set cd */
edns0_do =
DNS_PACKET_DO(q->request_packet) &&
(q->answer_dnssec_result >= 0 || /* we did proper DNSSEC validation … */
dns_query_fully_authenticated(q) || /* … or we considered it authentic otherwise … */
DNS_PACKET_CD(q->request_packet)); /* … or client set CD */
r = dns_stub_assign_sections(
q,
q->request_packet->question,
edns0_do);
if (r < 0)
return log_debug_errno(r, "Failed to assign sections: %m");
r = dns_stub_make_reply_packet(
&reply,
DNS_PACKET_PAYLOAD_SIZE_MAX(q->request_packet),
q->request_packet->question,
&truncated);
if (r < 0)
return log_debug_errno(r, "Failed to build reply packet: %m");
r = dns_stub_add_reply_packet_body(
reply,
q->reply_answer,
q->reply_authoritative,
q->reply_additional,
edns0_do,
&truncated);
if (r < 0)
return log_debug_errno(r, "Failed to append reply packet body: %m");
r = dns_stub_finish_reply_packet(
reply,
DNS_PACKET_ID(q->request_packet),
rcode,
truncated,
!!q->request_packet->opt,
edns0_do,
dns_query_fully_authenticated(q),
DNS_PACKET_CD(q->request_packet),
q->stub_listener_extra ? ADVERTISE_EXTRA_DATAGRAM_SIZE_MAX : ADVERTISE_DATAGRAM_SIZE_MAX);
if (r < 0)
return log_debug_errno(r, "Failed to build failure packet: %m");
return dns_stub_send(q->manager, q->stub_listener_extra, q->request_stream, q->request_packet, reply);
}
static int dns_stub_send_failure(
Manager *m,
DnsStubListenerExtra *l,
@ -240,12 +493,17 @@ static int dns_stub_send_failure(
bool authenticated) {
_cleanup_(dns_packet_unrefp) DnsPacket *reply = NULL;
bool truncated;
int r;
assert(m);
assert(p);
r = dns_stub_make_reply_packet(&reply, DNS_PACKET_PAYLOAD_SIZE_MAX(p), p->question, NULL, NULL);
r = dns_stub_make_reply_packet(
&reply,
DNS_PACKET_PAYLOAD_SIZE_MAX(p),
p->question,
&truncated);
if (r < 0)
return log_debug_errno(r, "Failed to make failure packet: %m");
@ -253,10 +511,11 @@ static int dns_stub_send_failure(
reply,
DNS_PACKET_ID(p),
rcode,
/* truncated = */ false,
truncated,
!!p->opt,
DNS_PACKET_DO(p),
authenticated,
DNS_PACKET_CD(p),
l ? ADVERTISE_EXTRA_DATAGRAM_SIZE_MAX : ADVERTISE_DATAGRAM_SIZE_MAX);
if (r < 0)
return log_debug_errno(r, "Failed to build failure packet: %m");
@ -264,27 +523,87 @@ static int dns_stub_send_failure(
return dns_stub_send(m, l, s, p, reply);
}
static int dns_stub_patch_bypass_reply_packet(
DnsPacket **ret, /* Where to place the patched packet */
DnsPacket *original, /* The packet to patch */
DnsPacket *request) { /* The packet the patched packet shall look like a reply to */
_cleanup_(dns_packet_unrefp) DnsPacket *c = NULL;
int r;
assert(ret);
assert(original);
assert(request);
r = dns_packet_dup(&c, original);
if (r < 0)
return r;
/* Extract the packet, so that we know where the OPT field is */
r = dns_packet_extract(c);
if (r < 0)
return r;
/* Copy over the original client request ID, so that we can make the upstream query look like our own reply. */
DNS_PACKET_HEADER(c)->id = DNS_PACKET_HEADER(request)->id;
/* Patch in our own maximum datagram size, if EDNS0 was on */
r = dns_packet_patch_max_udp_size(c, ADVERTISE_DATAGRAM_SIZE_MAX);
if (r < 0)
return r;
/* Lower all TTLs by the time passed since we received the datagram. */
if (timestamp_is_set(original->timestamp)) {
r = dns_packet_patch_ttls(c, original->timestamp);
if (r < 0)
return r;
}
/* Our upstream connection might have supported larger DNS requests than our downstream one, hence
* set the TC bit if our reply is larger than what the client supports, and truncate. */
if (c->size > DNS_PACKET_PAYLOAD_SIZE_MAX(request)) {
log_debug("Artificially truncating stub response, as advertised size of client is smaller than upstream one.");
dns_packet_truncate(c, DNS_PACKET_PAYLOAD_SIZE_MAX(request));
DNS_PACKET_HEADER(c)->flags = htobe16(be16toh(DNS_PACKET_HEADER(c)->flags) | DNS_PACKET_FLAG_TC);
}
*ret = TAKE_PTR(c);
return 0;
}
static void dns_stub_query_complete(DnsQuery *q) {
int r;
assert(q);
assert(q->request_dns_packet);
assert(q->request_packet);
if (q->question_bypass) {
/* This is a bypass reply. If so, let's propagate the upstream packet, if we have it and it
* is regular DNS. (We can't do this if the upstream packet is LLMNR or mDNS, since the
* packets are not 100% compatible.) */
if (q->answer_full_packet &&
q->answer_full_packet->protocol == DNS_PROTOCOL_DNS) {
_cleanup_(dns_packet_unrefp) DnsPacket *reply = NULL;
r = dns_stub_patch_bypass_reply_packet(&reply, q->answer_full_packet, q->request_packet);
if (r < 0)
log_debug_errno(r, "Failed to patch bypass reply packet: %m");
else
(void) dns_stub_send(q->manager, q->stub_listener_extra, q->request_stream, q->request_packet, reply);
dns_query_free(q);
return;
}
}
switch (q->state) {
case DNS_TRANSACTION_SUCCESS: {
bool truncated;
r = dns_stub_make_reply_packet(&q->reply_dns_packet, DNS_PACKET_PAYLOAD_SIZE_MAX(q->request_dns_packet), q->question_idna, q->answer, &truncated);
if (r < 0) {
log_debug_errno(r, "Failed to build reply packet: %m");
break;
}
if (!truncated) {
case DNS_TRANSACTION_SUCCESS:
/* Follow CNAMEs, and accumulate answers. Except if DNSSEC is requested, then let the client do that. */
if (!DNS_PACKET_DO(q->request_packet)) {
r = dns_query_process_cname(q);
if (r == -ELOOP) {
(void) dns_stub_send_failure(q->manager, q->stub_listener_extra, q->request_dns_stream, q->request_dns_packet, DNS_RCODE_SERVFAIL, false);
if (r == -ELOOP) { /* CNAME loop */
(void) dns_stub_send_reply(q, DNS_RCODE_SERVFAIL);
break;
}
if (r < 0) {
@ -295,30 +614,15 @@ static void dns_stub_query_complete(DnsQuery *q) {
return;
}
r = dns_stub_finish_reply_packet(
q->reply_dns_packet,
DNS_PACKET_ID(q->request_dns_packet),
q->answer_rcode,
truncated,
!!q->request_dns_packet->opt,
DNS_PACKET_DO(q->request_dns_packet),
dns_query_fully_authenticated(q),
q->stub_listener_extra ? ADVERTISE_EXTRA_DATAGRAM_SIZE_MAX : ADVERTISE_DATAGRAM_SIZE_MAX);
if (r < 0) {
log_debug_errno(r, "Failed to finish reply packet: %m");
break;
}
(void) dns_stub_send(q->manager, q->stub_listener_extra, q->request_dns_stream, q->request_dns_packet, q->reply_dns_packet);
(void) dns_stub_send_reply(q, q->answer_rcode);
break;
}
case DNS_TRANSACTION_RCODE_FAILURE:
(void) dns_stub_send_failure(q->manager, q->stub_listener_extra, q->request_dns_stream, q->request_dns_packet, q->answer_rcode, dns_query_fully_authenticated(q));
(void) dns_stub_send_reply(q, q->answer_rcode);
break;
case DNS_TRANSACTION_NOT_FOUND:
(void) dns_stub_send_failure(q->manager, q->stub_listener_extra, q->request_dns_stream, q->request_dns_packet, DNS_RCODE_NXDOMAIN, dns_query_fully_authenticated(q));
(void) dns_stub_send_reply(q, DNS_RCODE_NXDOMAIN);
break;
case DNS_TRANSACTION_TIMEOUT:
@ -334,7 +638,8 @@ static void dns_stub_query_complete(DnsQuery *q) {
case DNS_TRANSACTION_NO_TRUST_ANCHOR:
case DNS_TRANSACTION_RR_TYPE_UNSUPPORTED:
case DNS_TRANSACTION_NETWORK_DOWN:
(void) dns_stub_send_failure(q->manager, q->stub_listener_extra, q->request_dns_stream, q->request_dns_packet, DNS_RCODE_SERVFAIL, false);
case DNS_TRANSACTION_NO_SOURCE:
(void) dns_stub_send_reply(q, DNS_RCODE_SERVFAIL);
break;
case DNS_TRANSACTION_NULL:
@ -398,13 +703,13 @@ static void dns_stub_process_query(Manager *m, DnsStubListenerExtra *l, DnsStrea
if (dns_type_is_obsolete(p->question->keys[0]->type)) {
log_debug("Got message with obsolete key type, refusing.");
dns_stub_send_failure(m, l, s, p, DNS_RCODE_NOTIMP, false);
dns_stub_send_failure(m, l, s, p, DNS_RCODE_REFUSED, false);
return;
}
if (dns_type_is_zone_transer(p->question->keys[0]->type)) {
log_debug("Got request for zone transfer, refusing.");
dns_stub_send_failure(m, l, s, p, DNS_RCODE_NOTIMP, false);
dns_stub_send_failure(m, l, s, p, DNS_RCODE_REFUSED, false);
return;
}
@ -416,23 +721,29 @@ static void dns_stub_process_query(Manager *m, DnsStubListenerExtra *l, DnsStrea
}
if (DNS_PACKET_DO(p) && DNS_PACKET_CD(p)) {
log_debug("Got request with DNSSEC CD bit set, refusing.");
dns_stub_send_failure(m, l, s, p, DNS_RCODE_NOTIMP, false);
return;
}
log_debug("Got request with DNSSEC checking disabled, enabling bypass logic.");
r = dns_query_new(m, &q, p->question, p->question, 0, SD_RESOLVED_PROTOCOLS_ALL|SD_RESOLVED_NO_SEARCH);
r = dns_query_new(m, &q, NULL, NULL, p, 0,
SD_RESOLVED_PROTOCOLS_ALL|
SD_RESOLVED_NO_CNAME|
SD_RESOLVED_NO_SEARCH|
SD_RESOLVED_NO_VALIDATE|
SD_RESOLVED_REQUIRE_PRIMARY|
SD_RESOLVED_CLAMP_TTL);
} else
r = dns_query_new(m, &q, p->question, p->question, NULL, 0,
SD_RESOLVED_PROTOCOLS_ALL|
SD_RESOLVED_NO_SEARCH|
(DNS_PACKET_DO(p) ? SD_RESOLVED_NO_CNAME|SD_RESOLVED_REQUIRE_PRIMARY : 0)|
SD_RESOLVED_CLAMP_TTL);
if (r < 0) {
log_error_errno(r, "Failed to generate query object: %m");
dns_stub_send_failure(m, l, s, p, DNS_RCODE_SERVFAIL, false);
return;
}
/* Request that the TTL is corrected by the cached time for this lookup, so that we return vaguely useful TTLs */
q->clamp_ttl = true;
q->request_dns_packet = dns_packet_ref(p);
q->request_dns_stream = dns_stream_ref(s); /* make sure the stream stays around until we can send a reply through it */
q->request_packet = dns_packet_ref(p);
q->request_stream = dns_stream_ref(s); /* make sure the stream stays around until we can send a reply through it */
q->stub_listener_extra = l;
q->complete = dns_stub_query_complete;

View File

@ -76,7 +76,7 @@ static int synthesize_localhost_rr(Manager *m, const DnsResourceKey *key, int if
rr->a.in_addr.s_addr = htobe32(INADDR_LOOPBACK);
r = dns_answer_add(*answer, rr, dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED);
r = dns_answer_add(*answer, rr, dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED, NULL);
if (r < 0)
return r;
}
@ -90,7 +90,7 @@ static int synthesize_localhost_rr(Manager *m, const DnsResourceKey *key, int if
rr->aaaa.in6_addr = in6addr_loopback;
r = dns_answer_add(*answer, rr, dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED);
r = dns_answer_add(*answer, rr, dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED, NULL);
if (r < 0)
return r;
}
@ -109,7 +109,7 @@ static int answer_add_ptr(DnsAnswer **answer, const char *from, const char *to,
if (!rr->ptr.name)
return -ENOMEM;
return dns_answer_add(*answer, rr, ifindex, flags);
return dns_answer_add(*answer, rr, ifindex, flags, NULL);
}
static int synthesize_localhost_ptr(Manager *m, const DnsResourceKey *key, int ifindex, DnsAnswer **answer) {
@ -155,7 +155,7 @@ static int answer_add_addresses_rr(
if (r < 0)
return r;
r = dns_answer_add(*answer, rr, addresses[j].ifindex, DNS_ANSWER_AUTHENTICATED);
r = dns_answer_add(*answer, rr, addresses[j].ifindex, DNS_ANSWER_AUTHENTICATED, NULL);
if (r < 0)
return r;
}
@ -197,7 +197,7 @@ static int answer_add_addresses_ptr(
if (r < 0)
return r;
r = dns_answer_add(*answer, rr, addresses[j].ifindex, DNS_ANSWER_AUTHENTICATED);
r = dns_answer_add(*answer, rr, addresses[j].ifindex, DNS_ANSWER_AUTHENTICATED, NULL);
if (r < 0)
return r;

File diff suppressed because it is too large Load Diff

View File

@ -5,6 +5,7 @@
#include "in-addr-util.h"
typedef struct DnsTransaction DnsTransaction;
typedef struct DnsTransactionFinder DnsTransactionFinder;
typedef enum DnsTransactionState DnsTransactionState;
typedef enum DnsTransactionSource DnsTransactionSource;
@ -31,6 +32,7 @@ enum DnsTransactionState {
DNS_TRANSACTION_RR_TYPE_UNSUPPORTED,
DNS_TRANSACTION_NETWORK_DOWN,
DNS_TRANSACTION_NOT_FOUND, /* like NXDOMAIN, but when LLMNR/TCP connections fail */
DNS_TRANSACTION_NO_SOURCE, /* All suitable DnsTransactionSource turned off */
_DNS_TRANSACTION_STATE_MAX,
_DNS_TRANSACTION_STATE_INVALID = -EINVAL,
};
@ -49,7 +51,10 @@ enum DnsTransactionSource {
struct DnsTransaction {
DnsScope *scope;
DnsResourceKey *key;
DnsResourceKey *key; /* For regular lookups the RR key to look for */
DnsPacket *bypass; /* For bypass lookups the full original request packet */
uint64_t query_flags;
DnsTransactionState state;
@ -60,8 +65,6 @@ struct DnsTransaction {
bool initial_jitter_scheduled:1;
bool initial_jitter_elapsed:1;
bool clamp_ttl:1;
bool probing:1;
DnsPacket *sent, *received;
@ -133,9 +136,10 @@ struct DnsTransaction {
LIST_FIELDS(DnsTransaction, transactions_by_scope);
LIST_FIELDS(DnsTransaction, transactions_by_stream);
LIST_FIELDS(DnsTransaction, transactions_by_key);
};
int dns_transaction_new(DnsTransaction **ret, DnsScope *s, DnsResourceKey *key);
int dns_transaction_new(DnsTransaction **ret, DnsScope *s, DnsResourceKey *key, DnsPacket *bypass, uint64_t flags);
DnsTransaction* dns_transaction_free(DnsTransaction *t);
bool dns_transaction_gc(DnsTransaction *t);
@ -150,6 +154,23 @@ void dns_transaction_notify(DnsTransaction *t, DnsTransaction *source);
int dns_transaction_validate_dnssec(DnsTransaction *t);
int dns_transaction_request_dnssec_keys(DnsTransaction *t);
static inline DnsResourceKey *dns_transaction_key(DnsTransaction *t) {
assert(t);
/* Return the lookup key of this transaction. Either takes the lookup key from the bypass packet if
* we are a bypass transaction. Or take the configured key for regular transactions. */
if (t->key)
return t->key;
assert(t->bypass);
if (dns_question_isempty(t->bypass->question))
return NULL;
return t->bypass->question->keys[0];
}
const char* dns_transaction_state_to_string(DnsTransactionState p) _const_;
DnsTransactionState dns_transaction_state_from_string(const char *s) _pure_;

View File

@ -60,7 +60,7 @@ static int add_root_ksk(
if (!rr->ds.digest)
return -ENOMEM;
r = dns_answer_add(answer, rr, 0, DNS_ANSWER_AUTHENTICATED);
r = dns_answer_add(answer, rr, 0, DNS_ANSWER_AUTHENTICATED, NULL);
if (r < 0)
return r;
@ -354,7 +354,7 @@ static int dns_trust_anchor_load_positive(DnsTrustAnchor *d, const char *path, u
old_answer = hashmap_get(d->positive_by_key, rr->key);
answer = dns_answer_ref(old_answer);
r = dns_answer_add_extend(&answer, rr, 0, DNS_ANSWER_AUTHENTICATED);
r = dns_answer_add_extend(&answer, rr, 0, DNS_ANSWER_AUTHENTICATED, NULL);
if (r < 0)
return log_error_errno(r, "Failed to add trust anchor RR: %m");

View File

@ -170,7 +170,10 @@ static int dns_zone_item_probe_start(DnsZoneItem *i) {
if (i->probe_transaction)
return 0;
t = dns_scope_find_transaction(i->scope, &DNS_RESOURCE_KEY_CONST(i->rr->key->class, DNS_TYPE_ANY, dns_resource_key_name(i->rr->key)), false);
t = dns_scope_find_transaction(
i->scope,
&DNS_RESOURCE_KEY_CONST(i->rr->key->class, DNS_TYPE_ANY, dns_resource_key_name(i->rr->key)),
SD_RESOLVED_NO_CACHE|SD_RESOLVED_NO_ZONE);
if (!t) {
_cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
@ -178,7 +181,7 @@ static int dns_zone_item_probe_start(DnsZoneItem *i) {
if (!key)
return -ENOMEM;
r = dns_transaction_new(&t, i->scope, key);
r = dns_transaction_new(&t, i->scope, key, NULL, SD_RESOLVED_NO_CACHE|SD_RESOLVED_NO_ZONE);
if (r < 0)
return r;
}
@ -296,7 +299,7 @@ static int dns_zone_add_authenticated_answer(DnsAnswer *a, DnsZoneItem *i, int i
else
flags = DNS_ANSWER_AUTHENTICATED;
return dns_answer_add(a, i->rr, ifindex, flags);
return dns_answer_add(a, i->rr, ifindex, flags, NULL);
}
int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, int ifindex, DnsAnswer **ret_answer, DnsAnswer **ret_soa, bool *ret_tentative) {

View File

@ -406,7 +406,7 @@ int manager_etc_hosts_lookup(Manager *m, DnsQuestion* q, DnsAnswer **answer) {
if (!rr->ptr.name)
return -ENOMEM;
r = dns_answer_add(*answer, rr, 0, DNS_ANSWER_AUTHENTICATED);
r = dns_answer_add(*answer, rr, 0, DNS_ANSWER_AUTHENTICATED, NULL);
if (r < 0)
return r;
}
@ -458,7 +458,7 @@ int manager_etc_hosts_lookup(Manager *m, DnsQuestion* q, DnsAnswer **answer) {
if (r < 0)
return r;
r = dns_answer_add(*answer, rr, 0, DNS_ANSWER_AUTHENTICATED);
r = dns_answer_add(*answer, rr, 0, DNS_ANSWER_AUTHENTICATED, NULL);
if (r < 0)
return r;
}

View File

@ -301,25 +301,25 @@ static int on_mdns_packet(sd_event_source *s, int fd, uint32_t revents, void *us
rr->ttl = 1;
}
t = dns_scope_find_transaction(scope, rr->key, false);
t = dns_scope_find_transaction(scope, rr->key, SD_RESOLVED_NO_CACHE|SD_RESOLVED_NO_ZONE);
if (t)
dns_transaction_process_reply(t, p);
/* Also look for the various types of ANY transactions */
t = dns_scope_find_transaction(scope, &DNS_RESOURCE_KEY_CONST(rr->key->class, DNS_TYPE_ANY, dns_resource_key_name(rr->key)), false);
t = dns_scope_find_transaction(scope, &DNS_RESOURCE_KEY_CONST(rr->key->class, DNS_TYPE_ANY, dns_resource_key_name(rr->key)), SD_RESOLVED_NO_CACHE|SD_RESOLVED_NO_ZONE);
if (t)
dns_transaction_process_reply(t, p);
t = dns_scope_find_transaction(scope, &DNS_RESOURCE_KEY_CONST(DNS_CLASS_ANY, rr->key->type, dns_resource_key_name(rr->key)), false);
t = dns_scope_find_transaction(scope, &DNS_RESOURCE_KEY_CONST(DNS_CLASS_ANY, rr->key->type, dns_resource_key_name(rr->key)), SD_RESOLVED_NO_CACHE|SD_RESOLVED_NO_ZONE);
if (t)
dns_transaction_process_reply(t, p);
t = dns_scope_find_transaction(scope, &DNS_RESOURCE_KEY_CONST(DNS_CLASS_ANY, DNS_TYPE_ANY, dns_resource_key_name(rr->key)), false);
t = dns_scope_find_transaction(scope, &DNS_RESOURCE_KEY_CONST(DNS_CLASS_ANY, DNS_TYPE_ANY, dns_resource_key_name(rr->key)), SD_RESOLVED_NO_CACHE|SD_RESOLVED_NO_ZONE);
if (t)
dns_transaction_process_reply(t, p);
}
dns_cache_put(&scope->cache, scope->manager->enable_cache, NULL, DNS_PACKET_RCODE(p), p->answer, false, (uint32_t) -1, 0, p->family, &p->sender);
dns_cache_put(&scope->cache, scope->manager->enable_cache, NULL, DNS_PACKET_RCODE(p), p->answer, NULL, false, _DNSSEC_RESULT_INVALID, (uint32_t) -1, p->family, &p->sender);
} else if (dns_packet_validate_query(p) > 0) {
log_debug("Got mDNS query packet for id %u", DNS_PACKET_ID(p));

View File

@ -57,6 +57,9 @@ static int reply_query_state(DnsQuery *q) {
case DNS_TRANSACTION_NETWORK_DOWN:
return varlink_error(q->varlink_request, "io.systemd.Resolve.NetworkDown", NULL);
case DNS_TRANSACTION_NO_SOURCE:
return varlink_error(q->varlink_request, "io.systemd.Resolve.NoSource", NULL);
case DNS_TRANSACTION_NOT_FOUND:
/* We return this as NXDOMAIN. This is only generated when a host doesn't implement LLMNR/TCP, and we
* thus quickly know that we cannot resolve an in-addr.arpa or ip6.arpa address. */
@ -103,7 +106,7 @@ static bool validate_and_mangle_flags(
/* This checks that the specified client-provided flags parameter actually makes sense, and mangles
* it slightly. Specifically:
*
* 1. We check that only the protocol flags and the NO_CNAME flag are on at most, plus the
* 1. We check that only the protocol flags and a bunch of NO_XYZ flags are on at most, plus the
* method-specific flags specified in 'ok'.
*
* 2. If no protocols are enabled we automatically convert that to "all protocols are enabled".
@ -114,7 +117,15 @@ static bool validate_and_mangle_flags(
* "everything".
*/
if (*flags & ~(SD_RESOLVED_PROTOCOLS_ALL|SD_RESOLVED_NO_CNAME|ok))
if (*flags & ~(SD_RESOLVED_PROTOCOLS_ALL|
SD_RESOLVED_NO_CNAME|
SD_RESOLVED_NO_VALIDATE|
SD_RESOLVED_NO_SYNTHESIZE|
SD_RESOLVED_NO_CACHE|
SD_RESOLVED_NO_ZONE|
SD_RESOLVED_NO_TRUST_ANCHOR|
SD_RESOLVED_NO_NETWORK|
ok))
return false;
if ((*flags & SD_RESOLVED_PROTOCOLS_ALL) == 0) /* If no protocol is enabled, enable all */
@ -312,7 +323,7 @@ static int vl_method_resolve_hostname(Varlink *link, JsonVariant *parameters, Va
if (r < 0 && r != -EALREADY)
return r;
r = dns_query_new(m, &q, question_utf8, question_idna ?: question_utf8, p.ifindex, p.flags);
r = dns_query_new(m, &q, question_utf8, question_idna ?: question_utf8, NULL, p.ifindex, p.flags);
if (r < 0)
return r;
@ -481,7 +492,7 @@ static int vl_method_resolve_address(Varlink *link, JsonVariant *parameters, Var
if (r < 0)
return r;
r = dns_query_new(m, &q, question, question, p.ifindex, p.flags|SD_RESOLVED_NO_SEARCH);
r = dns_query_new(m, &q, question, question, NULL, p.ifindex, p.flags|SD_RESOLVED_NO_SEARCH);
if (r < 0)
return r;

View File

@ -170,7 +170,7 @@ static void test_dnssec_verify_rfc8080_ed25519_example1(void) {
answer = dns_answer_new(1);
assert_se(answer);
assert_se(dns_answer_add(answer, mx, 0, DNS_ANSWER_AUTHENTICATED) >= 0);
assert_se(dns_answer_add(answer, mx, 0, DNS_ANSWER_AUTHENTICATED, NULL) >= 0);
assert_se(dnssec_verify_rrset(answer, mx->key, rrsig, dnskey,
rrsig->rrsig.inception * USEC_PER_SEC, &result) >= 0);
@ -262,7 +262,7 @@ static void test_dnssec_verify_rfc8080_ed25519_example2(void) {
answer = dns_answer_new(1);
assert_se(answer);
assert_se(dns_answer_add(answer, mx, 0, DNS_ANSWER_AUTHENTICATED) >= 0);
assert_se(dns_answer_add(answer, mx, 0, DNS_ANSWER_AUTHENTICATED, NULL) >= 0);
assert_se(dnssec_verify_rrset(answer, mx->key, rrsig, dnskey,
rrsig->rrsig.inception * USEC_PER_SEC, &result) >= 0);
@ -344,7 +344,7 @@ static void test_dnssec_verify_rrset(void) {
answer = dns_answer_new(1);
assert_se(answer);
assert_se(dns_answer_add(answer, a, 0, DNS_ANSWER_AUTHENTICATED) >= 0);
assert_se(dns_answer_add(answer, a, 0, DNS_ANSWER_AUTHENTICATED, NULL) >= 0);
/* Validate the RR as it if was 2015-12-2 today */
assert_se(dnssec_verify_rrset(answer, a->key, rrsig, dnskey, 1449092754*USEC_PER_SEC, &result) >= 0);
@ -436,7 +436,7 @@ static void test_dnssec_verify_rrset2(void) {
answer = dns_answer_new(1);
assert_se(answer);
assert_se(dns_answer_add(answer, nsec, 0, DNS_ANSWER_AUTHENTICATED) >= 0);
assert_se(dns_answer_add(answer, nsec, 0, DNS_ANSWER_AUTHENTICATED, NULL) >= 0);
/* Validate the RR as it if was 2015-12-11 today */
assert_se(dnssec_verify_rrset(answer, nsec->key, rrsig, dnskey, 1449849318*USEC_PER_SEC, &result) >= 0);
@ -563,10 +563,10 @@ static void test_dnssec_verify_rrset3(void) {
answer = dns_answer_new(4);
assert_se(answer);
assert_se(dns_answer_add(answer, mx1, 0, DNS_ANSWER_AUTHENTICATED) >= 0);
assert_se(dns_answer_add(answer, mx2, 0, DNS_ANSWER_AUTHENTICATED) >= 0);
assert_se(dns_answer_add(answer, mx3, 0, DNS_ANSWER_AUTHENTICATED) >= 0);
assert_se(dns_answer_add(answer, mx4, 0, DNS_ANSWER_AUTHENTICATED) >= 0);
assert_se(dns_answer_add(answer, mx1, 0, DNS_ANSWER_AUTHENTICATED, NULL) >= 0);
assert_se(dns_answer_add(answer, mx2, 0, DNS_ANSWER_AUTHENTICATED, NULL) >= 0);
assert_se(dns_answer_add(answer, mx3, 0, DNS_ANSWER_AUTHENTICATED, NULL) >= 0);
assert_se(dns_answer_add(answer, mx4, 0, DNS_ANSWER_AUTHENTICATED, NULL) >= 0);
/* Validate the RR as it if was 2020-02-24 today */
assert_se(dnssec_verify_rrset(answer, mx1->key, rrsig, dnskey, 1582534685*USEC_PER_SEC, &result) >= 0);