]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
resolved: refuse packets looped back to us
authorLennart Poettering <lennart@poettering.net>
Thu, 5 Nov 2020 14:40:53 +0000 (15:40 +0100)
committerLennart Poettering <lennart@poettering.net>
Sun, 14 Feb 2021 22:12:22 +0000 (23:12 +0100)
Fixes: #17413
src/resolve/resolved-dns-packet.c
src/resolve/resolved-dns-packet.h
src/resolve/resolved-dns-stub.c
src/resolve/resolved-manager.c
src/resolve/resolved-manager.h

index 59be55a0eb027747f0cc487439c9d17f03d750c8..1bdea641e035406657aa2135e5d361c8ef180599 100644 (file)
@@ -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",
index 9d93f31469503a00e5c0518ab7946133c341dc7f..815999ecc28b74c382360013d3ed83d4c74ea0b3 100644 (file)
@@ -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,
index 664244969762134ae5b45d62880548b7ea887f76..74a76ddccfa88d65d86b5501cb210caab6b3412c 100644 (file)
@@ -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");
index d72753918031b354d929e756459b934f23206d87..9d178abcb54469d46a50fca16a3664f44dbde50c 100644 (file)
@@ -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;
 
index faa9e25e30971878f24b4181acadfaed6fd7fde9..d2f9048fa7ea02b153ba030f7aa75fadb5eb4460 100644 (file)
@@ -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);