From: Lennart Poettering Date: Thu, 5 Nov 2020 14:40:53 +0000 (+0100) Subject: resolved: refuse packets looped back to us X-Git-Tag: v248-rc1~132^2~1 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a9fd8837d42581ed9a72c92855c121f99e423e6f;p=thirdparty%2Fsystemd.git resolved: refuse packets looped back to us Fixes: #17413 --- diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c index 59be55a0eb0..1bdea641e03 100644 --- a/src/resolve/resolved-dns-packet.c +++ b/src/resolve/resolved-dns-packet.c @@ -2535,6 +2535,10 @@ static int dns_packet_compare_func(const DnsPacket *x, const DnsPacket *y) { DEFINE_HASH_OPS(dns_packet_hash_ops, DnsPacket, dns_packet_hash_func, dns_packet_compare_func); +bool dns_packet_equal(const DnsPacket *a, const DnsPacket *b) { + return dns_packet_compare_func(a, b) == 0; +} + static const char* const dns_rcode_table[_DNS_RCODE_MAX_DEFINED] = { [DNS_RCODE_SUCCESS] = "SUCCESS", [DNS_RCODE_FORMERR] = "FORMERR", diff --git a/src/resolve/resolved-dns-packet.h b/src/resolve/resolved-dns-packet.h index 9d93f314695..815999ecc28 100644 --- a/src/resolve/resolved-dns-packet.h +++ b/src/resolve/resolved-dns-packet.h @@ -227,6 +227,8 @@ void dns_packet_rewind(DnsPacket *p, size_t idx); int dns_packet_skip_question(DnsPacket *p); int dns_packet_extract(DnsPacket *p); +bool dns_packet_equal(const DnsPacket *a, const DnsPacket *b); + /* https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-6 */ enum { DNS_RCODE_SUCCESS = 0, diff --git a/src/resolve/resolved-dns-stub.c b/src/resolve/resolved-dns-stub.c index 66424496976..74a76ddccfa 100644 --- a/src/resolve/resolved-dns-stub.c +++ b/src/resolve/resolved-dns-stub.c @@ -688,6 +688,11 @@ static void dns_stub_process_query(Manager *m, DnsStubListenerExtra *l, DnsStrea return; } + if (manager_packet_from_our_transaction(m, p)) { + log_debug("Got our own packet looped back, ignoring."); + return; + } + r = dns_packet_extract(p); if (r < 0) { log_debug_errno(r, "Failed to extract resources from incoming packet, ignoring packet: %m"); diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index d7275391803..9d178abcb54 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -1264,6 +1264,22 @@ bool manager_packet_from_local_address(Manager *m, DnsPacket *p) { return !!manager_find_link_address(m, p->family, &p->sender); } +bool manager_packet_from_our_transaction(Manager *m, DnsPacket *p) { + DnsTransaction *t; + + assert(m); + assert(p); + + /* Let's see if we have a transaction with a query message with the exact same binary contents as the + * one we just got. If so, it's almost definitely a packet loop of some kind. */ + + t = hashmap_get(m->dns_transactions, UINT_TO_PTR(DNS_PACKET_ID(p))); + if (!t) + return false; + + return t->sent && dns_packet_equal(t->sent, p); +} + DnsScope* manager_find_scope(Manager *m, DnsPacket *p) { Link *l; diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h index faa9e25e309..d2f9048fa7e 100644 --- a/src/resolve/resolved-manager.h +++ b/src/resolve/resolved-manager.h @@ -166,6 +166,8 @@ void manager_refresh_rrs(Manager *m); int manager_next_hostname(Manager *m); bool manager_packet_from_local_address(Manager *m, DnsPacket *p); +bool manager_packet_from_our_transaction(Manager *m, DnsPacket *p); + DnsScope* manager_find_scope(Manager *m, DnsPacket *p); void manager_verify_all(Manager *m);