Add functionality to serve stale DNS records
This commit is contained in:
Родитель
ad37bfd7fb
Коммит
7a29ef4dc8
|
@ -0,0 +1,512 @@
|
|||
From 5ed91481abea382dc486507556e5cdf0f36b796f Mon Sep 17 00:00:00 2001
|
||||
From: Kiran Vemula <vemulakiran@gmail.com>
|
||||
Date: Thu, 8 Jun 2023 18:42:11 +0530
|
||||
Subject: [PATCH] resolved: added serve stale feature implementation of RFC
|
||||
8767
|
||||
|
||||
serve stale feature to keep the DNS resource records beyond TTL to return them as stale records in case of upstream server is not reachable or returns negative response.
|
||||
SD_RESOLVED_NO_STALE flag has been added to disable serving stale records via dbus.
|
||||
added serve stale test cases to TEST-75-RESOLVED
|
||||
Fixes: #21815
|
||||
---
|
||||
man/org.freedesktop.resolve1.xml | 6 ++-
|
||||
man/resolvectl.xml | 8 ++++
|
||||
man/resolved.conf.xml | 15 ++++++
|
||||
shell-completion/bash/resolvectl | 2 +-
|
||||
src/resolve/resolvectl.c | 10 ++++
|
||||
src/resolve/resolved-bus.c | 1 +
|
||||
src/resolve/resolved-def.h | 3 ++
|
||||
src/resolve/resolved-dns-cache.c | 64 +++++++++++++++++++------
|
||||
src/resolve/resolved-dns-cache.h | 3 +-
|
||||
src/resolve/resolved-dns-transaction.c | 20 +++++++-
|
||||
src/resolve/resolved-gperf.gperf | 1 +
|
||||
src/resolve/resolved-link.c | 3 +-
|
||||
src/resolve/resolved-manager.h | 1 +
|
||||
src/resolve/resolved-mdns.c | 3 +-
|
||||
src/resolve/resolved-varlink.c | 1 +
|
||||
src/resolve/resolved.conf.in | 1 +
|
||||
test/TEST-75-RESOLVED/test.sh | 5 ++
|
||||
test/knot-data/zones/unsigned.test.zone | 1 +
|
||||
test/units/testsuite-75.sh | 63 ++++++++++++++++++++++++
|
||||
19 files changed, 189 insertions(+), 22 deletions(-)
|
||||
|
||||
diff --git a/man/org.freedesktop.resolve1.xml b/man/org.freedesktop.resolve1.xml
|
||||
index a2b4490fc7..403eb14538 100644
|
||||
--- a/man/org.freedesktop.resolve1.xml
|
||||
+++ b/man/org.freedesktop.resolve1.xml
|
||||
@@ -464,6 +464,7 @@ node /org/freedesktop/resolve1 {
|
||||
#define SD_RESOLVED_FROM_ZONE (UINT64_C(1) << 21)
|
||||
#define SD_RESOLVED_FROM_TRUST_ANCHOR (UINT64_C(1) << 22)
|
||||
#define SD_RESOLVED_FROM_NETWORK (UINT64_C(1) << 23)
|
||||
+#define SD_RESOLVED_NO_STALE (UINT64_C(1) << 24)
|
||||
</programlisting>
|
||||
|
||||
<para>On input, the first five flags control the protocols to use for the look-up. They refer to
|
||||
@@ -513,13 +514,14 @@ node /org/freedesktop/resolve1 {
|
||||
<para>NO_VALIDATE can be set to disable validation via DNSSEC even if it would normally be used.
|
||||
</para>
|
||||
|
||||
- <para>The next four flags allow disabling certain sources during resolution. NO_SYNTHESIZE disables
|
||||
+ <para>The next six flags allow disabling certain sources during resolution. NO_SYNTHESIZE disables
|
||||
synthetic records, e.g. the local host name, see section SYNTHETIC RECORDS in
|
||||
<citerefentry><refentrytitle>systemd-resolved.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
for more information. NO_CACHE disables the use of the cache of previously resolved records. NO_ZONE
|
||||
disables answers using locally registered public LLMNR/mDNS resource records. NO_TRUST_ANCHOR
|
||||
disables answers using locally configured trust anchors. NO_NETWORK requires all answers to be
|
||||
- provided without using the network, i.e. either from local sources or the cache.</para>
|
||||
+ provided without using the network, i.e. either from local sources or the cache. NO_STALE flag
|
||||
+ can be set to disable answering request with stale records.</para>
|
||||
|
||||
<para>With REQUIRE_PRIMARY the request must be answered from a "primary" answer, i.e. not from
|
||||
resource records acquired as a side-effect of a previous transaction.</para>
|
||||
diff --git a/man/resolvectl.xml b/man/resolvectl.xml
|
||||
index 37a51b4760..ed3918307c 100644
|
||||
--- a/man/resolvectl.xml
|
||||
+++ b/man/resolvectl.xml
|
||||
@@ -379,6 +379,14 @@
|
||||
query response are shown. Otherwise, this output is suppressed.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
+ <varlistentry>
|
||||
+ <term><option>--stale-data=</option><replaceable>BOOL</replaceable></term>
|
||||
+
|
||||
+ <listitem><para>Takes a boolean parameter; used in conjunction with <command>query</command>. If true
|
||||
+ (the default), lookups are answered with stale data (expired resource records) if
|
||||
+ possible. If false, the stale data is not considered for the lookup request.</para></listitem>
|
||||
+ </varlistentry>
|
||||
+
|
||||
<xi:include href="standard-options.xml" xpointer="help" />
|
||||
<xi:include href="standard-options.xml" xpointer="version" />
|
||||
<xi:include href="standard-options.xml" xpointer="no-pager" />
|
||||
diff --git a/man/resolved.conf.xml b/man/resolved.conf.xml
|
||||
index 2b9f482971..81401043a3 100644
|
||||
--- a/man/resolved.conf.xml
|
||||
+++ b/man/resolved.conf.xml
|
||||
@@ -329,6 +329,21 @@ DNSStubListenerExtra=udp:[2001:db8:0:f102::13]:9953</programlisting>
|
||||
url="https://www.iab.org/documents/correspondence-reports-documents/2013-2/iab-statement-dotless-domains-considered-harmful/">IAB
|
||||
Statement</ulink>, and may create a privacy and security risk.</para></listitem>
|
||||
</varlistentry>
|
||||
+ <varlistentry>
|
||||
+ <term>StaleRetentionSec=<replaceable>SECONDS</replaceable></term>
|
||||
+ <listitem><para>Takes a duration value, which determines the length of time DNS resource records can be retained
|
||||
+ in the cache beyond their Time To Live (TTL). This allows these records to be returned as stale records.
|
||||
+ By default, this value is set to zero, meaning that DNS resource records are not stored in the cache after their TTL expires.</para>
|
||||
+
|
||||
+ <para>This is useful when a DNS server failure occurs or becomes unreachable.
|
||||
+ In such cases, systemd-resolved continues to use the stale records to answer DNS queries, particularly when no valid response
|
||||
+ can be obtained from the upstream DNS servers. However, this doesn't apply to NXDOMAIN responses, as those are still perfectly valid responses.
|
||||
+ This feature enhances resilience against DNS infrastructure failures and outages.</para>
|
||||
+
|
||||
+ <para>systemd-resolved always attempts to reach the upstream DNS servers first, before providing the client application with any stale data.
|
||||
+ If this feature is enabled, cache will not be flushed when changing servers.</para>
|
||||
+ </listitem>
|
||||
+ </varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
diff --git a/shell-completion/bash/resolvectl b/shell-completion/bash/resolvectl
|
||||
index 21f80143c3..779842ea11 100644
|
||||
--- a/shell-completion/bash/resolvectl
|
||||
+++ b/shell-completion/bash/resolvectl
|
||||
@@ -37,6 +37,6 @@ _resolvectl() {
|
||||
[STANDALONE]='-h --help --version --no-pager -4 -6
|
||||
--service-address=no --service-txt=no
|
||||
- --cname=no --search=no --legend=no'
|
||||
+ --cname=no --search=no --legend=no --stale-data=no'
|
||||
[ARG]='-i --interface -p --protocol -t --type -c --class --raw'
|
||||
)
|
||||
local -A VERBS=(
|
||||
diff --git a/src/resolve/resolvectl.c b/src/resolve/resolvectl.c
|
||||
index d6ecaed3c6..72aa778792 100644
|
||||
--- a/src/resolve/resolvectl.c
|
||||
+++ b/src/resolve/resolvectl.c
|
||||
@@ -2671,6 +2671,7 @@ static int native_help(void) {
|
||||
" --validate=BOOL Allow DNSSEC validation (default: yes)\n"
|
||||
" --synthesize=BOOL Allow synthetic response (default: yes)\n"
|
||||
" --cache=BOOL Allow response from cache (default: yes)\n"
|
||||
+ " --stale-data=BOOL Allow response from cache with stale data (default: yes)\n"
|
||||
" --zone=BOOL Allow response from locally registered mDNS/LLMNR\n"
|
||||
" records (default: yes)\n"
|
||||
" --trust-anchor=BOOL Allow response from local trust anchor (default: yes)\n"
|
||||
@@ -3024,6 +3025,7 @@ static int native_parse_argv(int argc, char *argv[]) {
|
||||
ARG_RAW,
|
||||
ARG_SEARCH,
|
||||
ARG_NO_PAGER,
|
||||
+ ARG_STALE_DATA
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
@@ -3046,6 +3048,7 @@ static int native_parse_argv(int argc, char *argv[]) {
|
||||
{ "raw", optional_argument, NULL, ARG_RAW },
|
||||
{ "search", required_argument, NULL, ARG_SEARCH },
|
||||
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
|
||||
+ { "stale-data", required_argument, NULL, ARG_STALE_DATA },
|
||||
{}
|
||||
};
|
||||
|
||||
@@ -3183,6 +3186,13 @@ static int native_parse_argv(int argc, char *argv[]) {
|
||||
SET_FLAG(arg_flags, SD_RESOLVED_NO_CACHE, r == 0);
|
||||
break;
|
||||
|
||||
+ case ARG_STALE_DATA:
|
||||
+ r = parse_boolean_argument("--stale-data=", optarg, NULL);
|
||||
+ if (r < 0)
|
||||
+ return r;
|
||||
+ SET_FLAG(arg_flags, SD_RESOLVED_NO_STALE, r == 0);
|
||||
+ break;
|
||||
+
|
||||
case ARG_ZONE:
|
||||
r = parse_boolean_argument("--zone=", optarg, NULL);
|
||||
if (r < 0)
|
||||
diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c
|
||||
index 334ae8dcff..459adfec5c 100644
|
||||
--- a/src/resolve/resolved-bus.c
|
||||
+++ b/src/resolve/resolved-bus.c
|
||||
@@ -298,6 +298,7 @@ static int validate_and_mangle_flags(
|
||||
SD_RESOLVED_NO_ZONE|
|
||||
SD_RESOLVED_NO_TRUST_ANCHOR|
|
||||
SD_RESOLVED_NO_NETWORK|
|
||||
+ SD_RESOLVED_NO_STALE|
|
||||
ok))
|
||||
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid flags parameter");
|
||||
|
||||
diff --git a/src/resolve/resolved-def.h b/src/resolve/resolved-def.h
|
||||
index 36092afa48..b7a44f9571 100644
|
||||
--- a/src/resolve/resolved-def.h
|
||||
+++ b/src/resolve/resolved-def.h
|
||||
@@ -70,6 +70,9 @@
|
||||
/* Output: Result was (at least partially) answered from network */
|
||||
#define SD_RESOLVED_FROM_NETWORK (UINT64_C(1) << 23)
|
||||
|
||||
+/* Input: Don't answer request with stale data */
|
||||
+#define SD_RESOLVED_NO_STALE (UINT64_C(1) << 24)
|
||||
+
|
||||
#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)
|
||||
diff --git a/src/resolve/resolved-dns-cache.c b/src/resolve/resolved-dns-cache.c
|
||||
index 089ed3aa0a..3f8378ae30 100644
|
||||
--- a/src/resolve/resolved-dns-cache.c
|
||||
+++ b/src/resolve/resolved-dns-cache.c
|
||||
@@ -15,9 +15,12 @@
|
||||
* leave DNS caches unbounded, but that's crazy. */
|
||||
#define CACHE_MAX 4096
|
||||
|
||||
-/* We never keep any item longer than 2h in our cache */
|
||||
+/* We never keep any item longer than 2h in our cache unless StaleRetentionSec is greater than zero. */
|
||||
#define CACHE_TTL_MAX_USEC (2 * USEC_PER_HOUR)
|
||||
|
||||
+/* The max TTL for stale data is set to 30 seconds. See RFC 8767, Section 6. */
|
||||
+#define CACHE_STALE_TTL_MAX_USEC (30 * USEC_PER_SEC)
|
||||
+
|
||||
/* How long to cache strange rcodes, i.e. rcodes != SUCCESS and != NXDOMAIN (specifically: that's only SERVFAIL for
|
||||
* now) */
|
||||
#define CACHE_TTL_STRANGE_RCODE_USEC (10 * USEC_PER_SEC)
|
||||
@@ -42,7 +45,8 @@ struct DnsCacheItem {
|
||||
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 */
|
||||
|
||||
- usec_t until;
|
||||
+ usec_t until; /* If StaleRetentionSec is greater than zero, until is set to a duration of StaleRetentionSec from the time of TTL expiry. If StaleRetentionSec is zero, both until and until_valid will be set to ttl. */
|
||||
+ usec_t until_valid; /* The key is for storing the time when the TTL set to expire. */
|
||||
uint64_t query_flags; /* SD_RESOLVED_AUTHENTICATED and/or SD_RESOLVED_CONFIDENTIAL */
|
||||
DnssecResult dnssec_result;
|
||||
|
||||
@@ -313,7 +317,7 @@ static DnsCacheItem* dns_cache_get(DnsCache *c, DnsResourceRecord *rr) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
-static usec_t calculate_until(
|
||||
+static usec_t calculate_until_valid(
|
||||
DnsResourceRecord *rr,
|
||||
uint32_t min_ttl,
|
||||
uint32_t nsec_ttl,
|
||||
@@ -352,6 +356,13 @@ static usec_t calculate_until(
|
||||
return timestamp + u;
|
||||
}
|
||||
|
||||
+static usec_t calculate_until(
|
||||
+ usec_t until_valid,
|
||||
+ usec_t stale_retention_usec) {
|
||||
+
|
||||
+ return stale_retention_usec > 0 ? usec_add(until_valid, stale_retention_usec) : until_valid;
|
||||
+}
|
||||
+
|
||||
static void dns_cache_item_update_positive(
|
||||
DnsCache *c,
|
||||
DnsCacheItem *i,
|
||||
@@ -365,7 +376,8 @@ static void dns_cache_item_update_positive(
|
||||
usec_t timestamp,
|
||||
int ifindex,
|
||||
int owner_family,
|
||||
- const union in_addr_union *owner_address) {
|
||||
+ const union in_addr_union *owner_address,
|
||||
+ usec_t stale_retention_usec) {
|
||||
|
||||
assert(c);
|
||||
assert(i);
|
||||
@@ -395,7 +407,8 @@ static void dns_cache_item_update_positive(
|
||||
dns_packet_unref(i->full_packet);
|
||||
i->full_packet = full_packet;
|
||||
|
||||
- i->until = calculate_until(rr, min_ttl, UINT32_MAX, timestamp, false);
|
||||
+ i->until_valid = calculate_until_valid(rr, min_ttl, UINT32_MAX, timestamp, false);
|
||||
+ i->until = calculate_until(i->until_valid, stale_retention_usec);
|
||||
i->query_flags = query_flags & CACHEABLE_QUERY_FLAGS;
|
||||
i->shared_owner = shared_owner;
|
||||
i->dnssec_result = dnssec_result;
|
||||
@@ -419,7 +432,8 @@ static int dns_cache_put_positive(
|
||||
usec_t timestamp,
|
||||
int ifindex,
|
||||
int owner_family,
|
||||
- const union in_addr_union *owner_address) {
|
||||
+ const union in_addr_union *owner_address,
|
||||
+ usec_t stale_retention_usec) {
|
||||
|
||||
_cleanup_(dns_cache_item_freep) DnsCacheItem *i = NULL;
|
||||
char key_str[DNS_RESOURCE_KEY_STRING_MAX];
|
||||
@@ -467,7 +481,8 @@ static int dns_cache_put_positive(
|
||||
timestamp,
|
||||
ifindex,
|
||||
owner_family,
|
||||
- owner_address);
|
||||
+ owner_address,
|
||||
+ stale_retention_usec);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -482,13 +497,19 @@ static int dns_cache_put_positive(
|
||||
if (!i)
|
||||
return -ENOMEM;
|
||||
|
||||
+ /* If StaleRetentionSec is greater than zero, the 'until' property is set to a duration
|
||||
+ * of StaleRetentionSec from the time of TTL expiry.
|
||||
+ * If StaleRetentionSec is zero, both the 'until' and 'until_valid' are set to the TTL duration,
|
||||
+ * leading to the eviction of the record once the TTL expires.*/
|
||||
+ usec_t until_valid = calculate_until_valid(rr, min_ttl, UINT32_MAX, timestamp, false);
|
||||
*i = (DnsCacheItem) {
|
||||
.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, min_ttl, UINT32_MAX, timestamp, false),
|
||||
+ .until = calculate_until(until_valid, stale_retention_usec),
|
||||
+ .until_valid = until_valid,
|
||||
.query_flags = query_flags & CACHEABLE_QUERY_FLAGS,
|
||||
.shared_owner = shared_owner,
|
||||
.dnssec_result = dnssec_result,
|
||||
@@ -594,7 +615,7 @@ static int dns_cache_put_negative(
|
||||
* of some other RR. Let's better take the lowest option here than a needlessly high one */
|
||||
i->until =
|
||||
i->type == DNS_CACHE_RCODE ? timestamp + CACHE_TTL_STRANGE_RCODE_USEC :
|
||||
- calculate_until(soa, dns_answer_min_ttl(answer), nsec_ttl, timestamp, true);
|
||||
+ calculate_until_valid(soa, dns_answer_min_ttl(answer), nsec_ttl, timestamp, true);
|
||||
|
||||
if (i->type == DNS_CACHE_NXDOMAIN) {
|
||||
/* NXDOMAIN entries should apply equally to all types, so we use ANY as
|
||||
@@ -689,7 +710,8 @@ int dns_cache_put(
|
||||
DnssecResult dnssec_result,
|
||||
uint32_t nsec_ttl,
|
||||
int owner_family,
|
||||
- const union in_addr_union *owner_address) {
|
||||
+ const union in_addr_union *owner_address,
|
||||
+ usec_t stale_retention_usec) {
|
||||
|
||||
DnsResourceRecord *soa = NULL;
|
||||
bool weird_rcode = false;
|
||||
@@ -784,7 +806,8 @@ int dns_cache_put(
|
||||
timestamp,
|
||||
item->ifindex,
|
||||
owner_family,
|
||||
- owner_address);
|
||||
+ owner_address,
|
||||
+ stale_retention_usec);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
}
|
||||
@@ -840,7 +863,8 @@ int dns_cache_put(
|
||||
nsec_ttl,
|
||||
timestamp,
|
||||
soa,
|
||||
- owner_family, owner_address);
|
||||
+ owner_family,
|
||||
+ owner_address);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
@@ -1033,6 +1057,14 @@ int dns_cache_lookup(
|
||||
goto miss;
|
||||
}
|
||||
|
||||
+ /* Skip the next part if ttl is expired and requested with no stale flag. */
|
||||
+ if (FLAGS_SET(query_flags, SD_RESOLVED_NO_STALE) && j->until_valid < current) {
|
||||
+ log_debug("Requested with no stale and TTL expired for %s",
|
||||
+ 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)
|
||||
@@ -1065,6 +1097,10 @@ int dns_cache_lookup(
|
||||
dnssec_result = _DNSSEC_RESULT_INVALID;
|
||||
}
|
||||
|
||||
+ /* If the question is being resolved using stale data, the clamp TTL will be set to CACHE_STALE_TTL_MAX_USEC. */
|
||||
+ usec_t until = FLAGS_SET(query_flags, SD_RESOLVED_NO_STALE) ? j->until_valid
|
||||
+ : usec_add(current, CACHE_STALE_TTL_MAX_USEC);
|
||||
+
|
||||
/* 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
|
||||
@@ -1085,7 +1121,7 @@ int dns_cache_lookup(
|
||||
item->flags,
|
||||
item->rrsig,
|
||||
query_flags,
|
||||
- j->until,
|
||||
+ until,
|
||||
current);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -1100,7 +1136,7 @@ int dns_cache_lookup(
|
||||
FLAGS_SET(j->query_flags, SD_RESOLVED_AUTHENTICATED) ? DNS_ANSWER_AUTHENTICATED : 0,
|
||||
NULL,
|
||||
query_flags,
|
||||
- j->until,
|
||||
+ until,
|
||||
current);
|
||||
if (r < 0)
|
||||
return r;
|
||||
diff --git a/src/resolve/resolved-dns-cache.h b/src/resolve/resolved-dns-cache.h
|
||||
index bc045bc80c..d078ae9872 100644
|
||||
--- a/src/resolve/resolved-dns-cache.h
|
||||
+++ b/src/resolve/resolved-dns-cache.h
|
||||
@@ -34,7 +34,8 @@ int dns_cache_put(
|
||||
DnssecResult dnssec_result,
|
||||
uint32_t nsec_ttl,
|
||||
int owner_family,
|
||||
- const union in_addr_union *owner_address);
|
||||
+ const union in_addr_union *owner_address,
|
||||
+ usec_t stale_retention_usec);
|
||||
|
||||
int dns_cache_lookup(
|
||||
DnsCache *c,
|
||||
diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c
|
||||
index 400ca0d2e8..8fa48c0b43 100644
|
||||
--- a/src/resolve/resolved-dns-transaction.c
|
||||
+++ b/src/resolve/resolved-dns-transaction.c
|
||||
@@ -836,7 +836,8 @@ static void dns_transaction_cache_answer(DnsTransaction *t) {
|
||||
t->answer_dnssec_result,
|
||||
t->answer_nsec_ttl,
|
||||
t->received->family,
|
||||
- &t->received->sender);
|
||||
+ &t->received->sender,
|
||||
+ t->scope->manager->stale_retention_usec);
|
||||
}
|
||||
|
||||
static bool dns_transaction_dnssec_is_live(DnsTransaction *t) {
|
||||
@@ -1726,10 +1727,18 @@ static int dns_transaction_prepare(DnsTransaction *t, usec_t ts) {
|
||||
/* Let's then prune all outdated entries */
|
||||
dns_cache_prune(&t->scope->cache);
|
||||
|
||||
+ /* For the initial attempt or when no stale data is requested, disable serve stale
|
||||
+ * and answer the question from the cache (honors ttl property).
|
||||
+ * On the second attempt, if StaleRetentionSec is greater than zero,
|
||||
+ * try to answer the question using stale date (honors until property) */
|
||||
+ uint64_t query_flags = t->query_flags;
|
||||
+ if (t->n_attempts == 1 || t->scope->manager->stale_retention_usec == 0)
|
||||
+ query_flags |= SD_RESOLVED_NO_STALE;
|
||||
+
|
||||
r = dns_cache_lookup(
|
||||
&t->scope->cache,
|
||||
dns_transaction_key(t),
|
||||
- t->query_flags,
|
||||
+ query_flags,
|
||||
&t->answer_rcode,
|
||||
&t->answer,
|
||||
&t->received,
|
||||
@@ -1745,6 +1754,13 @@ static int dns_transaction_prepare(DnsTransaction *t, usec_t ts) {
|
||||
* packet. */
|
||||
dns_transaction_reset_answer(t);
|
||||
else {
|
||||
+ if (t->n_attempts > 1 && !FLAGS_SET(query_flags, SD_RESOLVED_NO_STALE)) {
|
||||
+ char key_str[DNS_RESOURCE_KEY_STRING_MAX];
|
||||
+ log_debug("Serve Stale response rcode=%s for %s",
|
||||
+ dns_rcode_to_string(t->answer_rcode),
|
||||
+ dns_resource_key_to_string(dns_transaction_key(t), key_str, sizeof key_str));
|
||||
+ }
|
||||
+
|
||||
t->answer_source = DNS_TRANSACTION_CACHE;
|
||||
if (t->answer_rcode == DNS_RCODE_SUCCESS)
|
||||
dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS);
|
||||
diff --git a/src/resolve/resolved-gperf.gperf b/src/resolve/resolved-gperf.gperf
|
||||
index eab4c7ee14..68839352f5 100644
|
||||
--- a/src/resolve/resolved-gperf.gperf
|
||||
+++ b/src/resolve/resolved-gperf.gperf
|
||||
@@ -32,3 +32,4 @@ Resolve.ReadEtcHosts, config_parse_bool, 0,
|
||||
Resolve.ResolveUnicastSingleLabel, config_parse_bool, 0, offsetof(Manager, resolve_unicast_single_label)
|
||||
Resolve.DNSStubListenerExtra, config_parse_dns_stub_listener_extra, 0, offsetof(Manager, dns_extra_stub_listeners)
|
||||
Resolve.CacheFromLocalhost, config_parse_bool, 0, offsetof(Manager, cache_from_localhost)
|
||||
+Resolve.StaleRetentionSec, config_parse_sec, 0, offsetof(Manager, stale_retention_usec)
|
||||
diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c
|
||||
index 9385b75e4b..dd5daddce4 100644
|
||||
--- a/src/resolve/resolved-link.c
|
||||
+++ b/src/resolve/resolved-link.c
|
||||
@@ -738,7 +738,8 @@ DnsServer* link_set_dns_server(Link *l, DnsServer *s) {
|
||||
dns_server_unref(l->current_dns_server);
|
||||
l->current_dns_server = dns_server_ref(s);
|
||||
|
||||
- if (l->unicast_scope)
|
||||
+ /* Skip flushing the cache if server stale feature is enabled. */
|
||||
+ if (l->unicast_scope && l->manager->stale_retention_usec == 0)
|
||||
dns_cache_flush(&l->unicast_scope->cache);
|
||||
|
||||
return s;
|
||||
diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h
|
||||
index f8f3af6fd0..46f6b4fedc 100644
|
||||
--- a/src/resolve/resolved-manager.h
|
||||
+++ b/src/resolve/resolved-manager.h
|
||||
@@ -42,6 +42,7 @@ struct Manager {
|
||||
DnsCacheMode enable_cache;
|
||||
bool cache_from_localhost;
|
||||
DnsStubListenerMode dns_stub_listener_mode;
|
||||
+ usec_t stale_retention_usec;
|
||||
|
||||
#if ENABLE_DNS_OVER_TLS
|
||||
DnsTlsManagerData dnstls_data;
|
||||
diff --git a/src/resolve/resolved-mdns.c b/src/resolve/resolved-mdns.c
|
||||
index cf6c22df3b..d4a919fc60 100644
|
||||
--- a/src/resolve/resolved-mdns.c
|
||||
+++ b/src/resolve/resolved-mdns.c
|
||||
@@ -408,7 +408,7 @@ static int on_mdns_packet(sd_event_source *s, int fd, uint32_t revents, void *us
|
||||
dns_transaction_process_reply(t, p, false);
|
||||
}
|
||||
|
||||
- dns_cache_put(&scope->cache, scope->manager->enable_cache, NULL, DNS_PACKET_RCODE(p), p->answer, NULL, false, _DNSSEC_RESULT_INVALID, UINT32_MAX, 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_MAX, p->family, &p->sender, scope->manager->stale_retention_usec);
|
||||
|
||||
} else if (dns_packet_validate_query(p) > 0) {
|
||||
log_debug("Got mDNS query packet for id %u", DNS_PACKET_ID(p));
|
||||
diff --git a/src/resolve/resolved-varlink.c b/src/resolve/resolved-varlink.c
|
||||
index fc224f627e..99022f5d2d 100644
|
||||
--- a/src/resolve/resolved-varlink.c
|
||||
+++ b/src/resolve/resolved-varlink.c
|
||||
@@ -128,6 +128,7 @@ static bool validate_and_mangle_flags(
|
||||
SD_RESOLVED_NO_ZONE|
|
||||
SD_RESOLVED_NO_TRUST_ANCHOR|
|
||||
SD_RESOLVED_NO_NETWORK|
|
||||
+ SD_RESOLVED_NO_STALE|
|
||||
ok))
|
||||
return false;
|
||||
|
||||
diff --git a/src/resolve/resolved.conf.in b/src/resolve/resolved.conf.in
|
||||
index 6d4176df52..f003574ac5 100644
|
||||
--- a/src/resolve/resolved.conf.in
|
||||
+++ b/src/resolve/resolved.conf.in
|
||||
@@ -32,3 +32,4 @@
|
||||
#DNSStubListenerExtra=
|
||||
#ReadEtcHosts=yes
|
||||
#ResolveUnicastSingleLabel=no
|
||||
+#StaleRetentionSec=0
|
|
@ -0,0 +1,27 @@
|
|||
From 88c6f8f894435c38a075dd268d34f7bcc839dfd2 Mon Sep 17 00:00:00 2001
|
||||
From: Kiran Vemula <vemulakiran@gmail.com>
|
||||
Date: Fri, 16 Jun 2023 17:34:37 +0530
|
||||
Subject: [PATCH] resolved: Initialize until_valid while storing
|
||||
negative/NXDOMAIN response in the cache
|
||||
|
||||
Initialize until_valid is properly for negative response, the cached negative responses can be used to answer the queries before contacting upstream server.
|
||||
---
|
||||
src/resolve/resolved-dns-cache.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/resolve/resolved-dns-cache.c b/src/resolve/resolved-dns-cache.c
|
||||
index 3f8378ae30..9d2a2fa1ac 100644
|
||||
--- a/src/resolve/resolved-dns-cache.c
|
||||
+++ b/src/resolve/resolved-dns-cache.c
|
||||
@@ -613,7 +613,7 @@ static int dns_cache_put_negative(
|
||||
/* Determine how long to cache this entry. In case we have some RRs in the answer use the lowest TTL
|
||||
* of any of them. Typically that's the SOA's TTL, which is OK, but could possibly be lower because
|
||||
* of some other RR. Let's better take the lowest option here than a needlessly high one */
|
||||
- i->until =
|
||||
+ i->until = i->until_valid =
|
||||
i->type == DNS_CACHE_RCODE ? timestamp + CACHE_TTL_STRANGE_RCODE_USEC :
|
||||
calculate_until_valid(soa, dns_answer_min_ttl(answer), nsec_ttl, timestamp, true);
|
||||
|
||||
--
|
||||
2.34.1
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
Summary: Systemd-250
|
||||
Name: systemd
|
||||
Version: 250.3
|
||||
Release: 16%{?dist}
|
||||
Release: 17%{?dist}
|
||||
License: LGPLv2+ AND GPLv2+ AND MIT
|
||||
Vendor: Microsoft Corporation
|
||||
Distribution: Mariner
|
||||
|
@ -25,6 +25,8 @@ Patch3: CVE-2022-3821.patch
|
|||
Patch4: CVE-2022-45873.patch
|
||||
Patch5: backport-helper-util-macros.patch
|
||||
Patch6: CVE-2022-4415.patch
|
||||
Patch7: serve-stale-0001-resolved-added-serve-stale-feature-implementation-of.patch
|
||||
Patch8: serve-stale-0002-resolved-Initialize-until_valid-while-storing-negati.patch
|
||||
BuildRequires: audit-devel
|
||||
BuildRequires: cryptsetup-devel
|
||||
BuildRequires: docbook-dtd-xml
|
||||
|
@ -281,6 +283,9 @@ fi
|
|||
%files lang -f %{name}.lang
|
||||
|
||||
%changelog
|
||||
* Fri Jul 07 2023 Dan Streetman <ddstreet@ieee.org> - 250.3-17
|
||||
- Add support to systemd-resolved to serve stale dns data
|
||||
|
||||
* Tue Jun 20 2023 Chris Gunn <chrisgun@microsoft.com> - 250.3-16
|
||||
- Enable audit integration
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче