From: Vishal Chillara Srinivas Date: Mon, 20 Nov 2023 06:33:28 +0000 (+0530) Subject: resolved: remove entry from cache when goodbye packet received X-Git-Tag: v256-rc1~638 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d08566fad7c97df153d38e314670aea3822106e1;p=thirdparty%2Fsystemd.git resolved: remove entry from cache when goodbye packet received RFC6762 10.1 says that queriers receiving a Multicast DNS response with a TTL of zero SHOULD record a TTL of 1 and then delete the record one second later. Added a timer event to trigger a callback to clean-up the cache one second after a goodbye packet is received. The callback also checks for any cache entries expiring within the next one second and schedules follow-up cleanup callbacks accordingly. --- diff --git a/src/resolve/resolved-dns-cache.c b/src/resolve/resolved-dns-cache.c index ec92406a7e5..e778bd48c84 100644 --- a/src/resolve/resolved-dns-cache.c +++ b/src/resolve/resolved-dns-cache.c @@ -243,6 +243,22 @@ void dns_cache_prune(DnsCache *c) { } } +bool dns_cache_expiry_in_one_second(DnsCache *c, usec_t t) { + DnsCacheItem *i; + + assert(c); + + /* Check if any items expire within the next second */ + i = prioq_peek(c->by_expiry); + if (!i) + return false; + + if (i->until <= usec_add(t, USEC_PER_SEC)) + return true; + + return false; +} + static int dns_cache_item_prioq_compare_func(const void *a, const void *b) { const DnsCacheItem *x = a, *y = b; diff --git a/src/resolve/resolved-dns-cache.h b/src/resolve/resolved-dns-cache.h index d078ae9872c..6a45b95a600 100644 --- a/src/resolve/resolved-dns-cache.h +++ b/src/resolve/resolved-dns-cache.h @@ -58,3 +58,5 @@ bool dns_cache_is_empty(DnsCache *cache); unsigned dns_cache_size(DnsCache *cache); int dns_cache_export_shared_to_packet(DnsCache *cache, DnsPacket *p, usec_t ts, unsigned max_rr); + +bool dns_cache_expiry_in_one_second(DnsCache *c, usec_t t); diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index e390715807f..f13233c8da2 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -41,6 +41,7 @@ int dns_scope_new(Manager *m, DnsScope **ret, Link *l, DnsProtocol protocol, int .protocol = protocol, .family = family, .resend_timeout = MULTICAST_RESEND_TIMEOUT_MIN_USEC, + .mdns_goodbye_event_source = NULL, }; if (protocol == DNS_PROTOCOL_DNS) { @@ -115,6 +116,8 @@ DnsScope* dns_scope_free(DnsScope *s) { sd_event_source_disable_unref(s->announce_event_source); + sd_event_source_disable_unref(s->mdns_goodbye_event_source); + dns_cache_flush(&s->cache); dns_zone_flush(&s->zone); diff --git a/src/resolve/resolved-dns-scope.h b/src/resolve/resolved-dns-scope.h index ca33fd007a6..82218e70faa 100644 --- a/src/resolve/resolved-dns-scope.h +++ b/src/resolve/resolved-dns-scope.h @@ -45,6 +45,8 @@ struct DnsScope { sd_event_source *announce_event_source; + sd_event_source *mdns_goodbye_event_source; + RateLimit ratelimit; usec_t resend_timeout; diff --git a/src/resolve/resolved-mdns.c b/src/resolve/resolved-mdns.c index 3e6e83fe625..60ae0b8fbd0 100644 --- a/src/resolve/resolved-mdns.c +++ b/src/resolve/resolved-mdns.c @@ -349,6 +349,33 @@ static int mdns_scope_process_query(DnsScope *s, DnsPacket *p) { return 0; } +static int mdns_goodbye_callback(sd_event_source *s, uint64_t usec, void *userdata) { + DnsScope *scope = userdata; + int r; + + assert(s); + assert(scope); + + scope->mdns_goodbye_event_source = sd_event_source_disable_unref(scope->mdns_goodbye_event_source); + + dns_cache_prune(&scope->cache); + + if (dns_cache_expiry_in_one_second(&scope->cache, usec)) { + r = sd_event_add_time_relative( + scope->manager->event, + &scope->mdns_goodbye_event_source, + CLOCK_BOOTTIME, + USEC_PER_SEC, + 0, + mdns_goodbye_callback, + scope); + if (r < 0) + return log_error_errno(r, "mDNS: Failed to re-schedule goodbye callback: %m"); + } + + return 0; +} + static int on_mdns_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) { _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL; Manager *m = userdata; @@ -407,6 +434,22 @@ static int on_mdns_packet(sd_event_source *s, int fd, uint32_t revents, void *us log_debug("Got a goodbye packet"); /* See the section 10.1 of RFC6762 */ rr->ttl = 1; + + /* Look at the cache 1 second later and remove stale entries. + * This is particularly useful to keep service browsers updated on service removal, + * as there are no other reliable triggers to propogate that info. */ + if (!scope->mdns_goodbye_event_source) { + r = sd_event_add_time_relative( + scope->manager->event, + &scope->mdns_goodbye_event_source, + CLOCK_BOOTTIME, + USEC_PER_SEC, + 0, + mdns_goodbye_callback, + scope); + if (r < 0) + return r; + } } }