]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
resolved: implement RFC5452
authorTom Gundersen <teg@jklm.no>
Thu, 9 Jul 2015 00:58:15 +0000 (02:58 +0200)
committerTom Gundersen <teg@jklm.no>
Tue, 14 Jul 2015 16:50:57 +0000 (18:50 +0200)
This improves the resilience against cache poisoning by being stricter
about only accepting responses that match precisely the requst they
are in reply to.

It should be noted that we still only use one port (which is picked
at random), rather than one port for each transaction. Port
randomization would improve things further, but is not required by
the RFC.

TODO
src/resolve/resolved-dns-transaction.c

diff --git a/TODO b/TODO
index 2904e2b44542534c5f4030455434b8ef5d008828..c1b57beeb92d427fafc55f0be426cc4c8a52d1a5 100644 (file)
--- a/TODO
+++ b/TODO
@@ -354,7 +354,6 @@ Features:
   - dname
   - cname on PTR (?)
   - maybe randomize DNS UDP source ports
-  - maybe compare query section of DNS replies
 
 * Allow multiple ExecStart= for all Type= settings, so that we can cover rescue.service nicely
 
index 7fa73cd01a78830207f035040a4ff8e6baf3da8a..3260ded424c738c17a08788297cb9acf1b05408f 100644 (file)
@@ -338,10 +338,15 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) {
         if (t->scope->protocol == DNS_PROTOCOL_DNS) {
 
                 /* For DNS we are fine with accepting packets on any
-                 * interface, but the source IP address must be one of
-                 * a valid DNS server */
+                 * interface, but the source IP address must be the
+                 * one of the DNS server we queried */
 
-                if (!dns_scope_good_dns_server(t->scope, p->family, &p->sender))
+                assert(t->server);
+
+                if (t->server->family != p->family)
+                        return;
+
+                if (!in_addr_equal(p->family, &p->sender, &t->server->address))
                         return;
 
                 if (p->sender_port != 53)
@@ -403,6 +408,11 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) {
                 return;
         }
 
+        /* Only consider responses with equivalent query section to the request */
+        if (!dns_question_is_superset(p->question, t->question) ||
+            !dns_question_is_superset(t->question, p->question))
+                dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY);
+
         /* According to RFC 4795, section 2.9. only the RRs from the answer section shall be cached */
         dns_cache_put(&t->scope->cache, p->question, DNS_PACKET_RCODE(p), p->answer, DNS_PACKET_ANCOUNT(p), 0, p->family, &p->sender);