From: Ronan Pigott Date: Mon, 7 Oct 2024 18:05:18 +0000 (-0700) Subject: resolved: authenticate bypass queries X-Git-Tag: v257-rc1~180^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=008f23b7c5f255e48c71c3b4da74a85448667817;p=thirdparty%2Fsystemd.git resolved: authenticate bypass queries Following 13e15dae9f0b, resolved does not forward the AD bit for bypass queries, but resolved also didn't do it's own validation, making these replies appear to never be authentic. We should enable validation for bypass queries. Let's disable our own validation when processing a +cd query, and also ensure that it skips the cache so that we don't accidentally fail to return inauthentic replies from upstream. Previously, when we had a bypass transaction without cd, a cached, authenticated, reply with cd could be served, leaving the cd bit erroneously set in the reply. Only reply with a CD bit if the client requested it. Fixes: 13e15dae9f0b (resolved: clear the AD bit for bypass packets) --- diff --git a/src/resolve/resolved-dns-packet.h b/src/resolve/resolved-dns-packet.h index 13d65a02c32..437c220b6af 100644 --- a/src/resolve/resolved-dns-packet.h +++ b/src/resolve/resolved-dns-packet.h @@ -111,6 +111,7 @@ static inline uint8_t* DNS_PACKET_DATA(const DnsPacket *p) { #define DNS_PACKET_AD(p) ((be16toh(DNS_PACKET_HEADER(p)->flags) >> 5) & 1) #define DNS_PACKET_CD(p) ((be16toh(DNS_PACKET_HEADER(p)->flags) >> 4) & 1) +#define DNS_PACKET_FLAG_CD (UINT16_C(1) << 4) #define DNS_PACKET_FLAG_AD (UINT16_C(1) << 5) #define DNS_PACKET_FLAG_TC (UINT16_C(1) << 9) diff --git a/src/resolve/resolved-dns-stub.c b/src/resolve/resolved-dns-stub.c index c604a51c4bb..ee1e31010c7 100644 --- a/src/resolve/resolved-dns-stub.c +++ b/src/resolve/resolved-dns-stub.c @@ -686,6 +686,7 @@ 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 */ + bool validated, bool authenticated) { _cleanup_(dns_packet_unrefp) DnsPacket *c = NULL; int r; @@ -726,9 +727,14 @@ static int dns_stub_patch_bypass_reply_packet( DNS_PACKET_HEADER(c)->flags = htobe16(be16toh(DNS_PACKET_HEADER(c)->flags) | DNS_PACKET_FLAG_TC); } + /* Patch the cd bit to reflect the state of validation: set when both we and the upstream + * resolver have checking disabled. */ + DNS_PACKET_HEADER(c)->flags = htobe16(UPDATE_FLAG(be16toh(DNS_PACKET_HEADER(c)->flags), + DNS_PACKET_FLAG_CD, DNS_PACKET_CD(original) && !validated)); + /* Ensure we don't pass along an untrusted ad flag for bypass packets */ - if (!authenticated) - DNS_PACKET_HEADER(c)->flags = htobe16(be16toh(DNS_PACKET_HEADER(c)->flags) & ~DNS_PACKET_FLAG_AD); + DNS_PACKET_HEADER(c)->flags = htobe16(UPDATE_FLAG(be16toh(DNS_PACKET_HEADER(c)->flags), + DNS_PACKET_FLAG_AD, authenticated)); *ret = TAKE_PTR(c); return 0; @@ -751,6 +757,7 @@ static void dns_stub_query_complete(DnsQuery *query) { _cleanup_(dns_packet_unrefp) DnsPacket *reply = NULL; r = dns_stub_patch_bypass_reply_packet(&reply, q->answer_full_packet, q->request_packet, + /* validated = */ !FLAGS_SET(q->flags, SD_RESOLVED_NO_VALIDATE), FLAGS_SET(q->answer_query_flags, SD_RESOLVED_AUTHENTICATED)); if (r < 0) log_debug_errno(r, "Failed to patch bypass reply packet: %m"); @@ -982,7 +989,7 @@ static void dns_stub_process_query(Manager *m, DnsStubListenerExtra *l, DnsStrea protocol_flags| SD_RESOLVED_NO_CNAME| SD_RESOLVED_NO_SEARCH| - SD_RESOLVED_NO_VALIDATE| + (DNS_PACKET_CD(p) ? SD_RESOLVED_NO_VALIDATE | SD_RESOLVED_NO_CACHE : 0)| SD_RESOLVED_REQUIRE_PRIMARY| SD_RESOLVED_CLAMP_TTL| SD_RESOLVED_RELAX_SINGLE_LABEL);