1
0
mirror of https://github.com/systemd/systemd.git synced 2025-03-19 22:50:17 +03:00

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.
This commit is contained in:
Vishal Chillara Srinivas 2023-11-20 12:03:28 +05:30 committed by Lennart Poettering
parent 11d1c90c49
commit d08566fad7
5 changed files with 66 additions and 0 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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;
}
}
}