From: Lennart Poettering Date: Wed, 24 Mar 2021 17:36:41 +0000 (+0100) Subject: resolved: pass mDNS reply packets to each transaction exactly once X-Git-Tag: v248-2~19 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=8640566ac41447e07bb8b4e990626a17b183c80c;p=thirdparty%2Fsystemd.git resolved: pass mDNS reply packets to each transaction exactly once Previously we'd iterate through the RRs of an mDNS reply and then find exactly one matching transaction on our scope for it, and pass it as reply to that. If multiple RRs of the same packet match we'd pas the packet multiple times to the transaction even. This all doesn't really work anymore since there can be multiple open transactions for the same key (with different flags), and it's kinda ugly anywy. Hence let's turn this around: let's iterate through the transactions and check if any of the included RRs match it, and if so pass the packet to that transaction exactly once. This speeds up mDNS a bit, since previously we'd oftentimes fail to find all suitable transactions for an mDNS reply (because there can be multiple transactions for the same RR key with different flags, and we checked exactly one flag combination). Which would then mean the transaction would time out, and be retried – at which point the cache would be populated and thus it would still succeed, but only after this timeout. With this fix this is corrected: every transaction that matches will get the reply, instantly as we get it. --- diff --git a/src/resolve/resolved-mdns.c b/src/resolve/resolved-mdns.c index bfd71575d63..2857b58e89e 100644 --- a/src/resolve/resolved-mdns.c +++ b/src/resolve/resolved-mdns.c @@ -265,6 +265,7 @@ static int on_mdns_packet(sd_event_source *s, int fd, uint32_t revents, void *us if (dns_packet_validate_reply(p) > 0) { DnsResourceRecord *rr; + DnsTransaction *t; log_debug("Got mDNS reply packet"); @@ -286,8 +287,9 @@ static int on_mdns_packet(sd_event_source *s, int fd, uint32_t revents, void *us dns_scope_check_conflicts(scope, p); DNS_ANSWER_FOREACH(rr, p->answer) { - const char *name = dns_resource_key_name(rr->key); - DnsTransaction *t; + const char *name; + + name = dns_resource_key_name(rr->key); /* If the received reply packet contains ANY record that is not .local * or .in-addr.arpa or .ip6.arpa, we assume someone's playing tricks on @@ -302,22 +304,13 @@ static int on_mdns_packet(sd_event_source *s, int fd, uint32_t revents, void *us /* See the section 10.1 of RFC6762 */ rr->ttl = 1; } + } - t = dns_scope_find_transaction(scope, rr->key, SD_RESOLVED_NO_CACHE|SD_RESOLVED_NO_ZONE); - if (t) - dns_transaction_process_reply(t, p, false); - - /* 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)), SD_RESOLVED_NO_CACHE|SD_RESOLVED_NO_ZONE); - if (t) - dns_transaction_process_reply(t, p, 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, 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) + LIST_FOREACH(transactions_by_scope, t, scope->transactions) { + r = dns_answer_match_key(p->answer, t->key, NULL); + if (r < 0) + log_debug_errno(r, "Failed to match resource key, ignoring: %m"); + else if (r > 0) /* This packet matches the transaction, let's pass it on as reply */ dns_transaction_process_reply(t, p, false); }