summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Gundersen <teg@jklm.no>2015-07-09 02:58:15 +0200
committerTom Gundersen <teg@jklm.no>2015-07-14 18:50:57 +0200
commit29815b6c608b836cada5e349d06a96b63eaa65f3 (patch)
tree7be9d6fd1f0b2a4017d245b2836b17d97a50e5b6
parent8300ba218e3cf5049496937be8bce10f22d09bbc (diff)
resolved: implement RFC5452
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.
-rw-r--r--TODO1
-rw-r--r--src/resolve/resolved-dns-transaction.c16
2 files changed, 13 insertions, 4 deletions
diff --git a/TODO b/TODO
index 2904e2b445..c1b57beeb9 100644
--- 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
diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c
index 7fa73cd01a..3260ded424 100644
--- a/src/resolve/resolved-dns-transaction.c
+++ b/src/resolve/resolved-dns-transaction.c
@@ -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);