summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2016-01-15 20:45:17 +0100
committerLennart Poettering <lennart@poettering.net>2016-01-17 20:47:46 +0100
commitc02cf2f41fc9b4c33a3c353b6181847733d65e8c (patch)
tree160a1a75e83abfc8cc64e7ad947478d40b92fe83
parented9717fcbf52b0890a249b65418a95a9382de062 (diff)
resolved: when the server feature level changes between query and response restart transaction
In some cases we learn something about a server's feature level through its responses. If we notice that after doing basic checking of a response, and after collecting all auxiliary DNSSEC info the feature level of the server is lower than where we started, restart the whole transaction. This is useful to deal with servers that response rubbish when talked to with too high feature levels.
-rw-r--r--src/resolve/resolved-dns-transaction.c38
1 files changed, 38 insertions, 0 deletions
diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c
index ee055236fa..72ef283dde 100644
--- a/src/resolve/resolved-dns-transaction.c
+++ b/src/resolve/resolved-dns-transaction.c
@@ -362,6 +362,25 @@ static void dns_transaction_retry(DnsTransaction *t) {
dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES);
}
+static int dns_transaction_maybe_restart(DnsTransaction *t) {
+ assert(t);
+
+ if (!t->server)
+ return 0;
+
+ if (t->current_feature_level <= dns_server_possible_feature_level(t->server))
+ return 0;
+
+ /* The server's current feature level is lower than when we sent the original query. We learnt something from
+ the response or possibly an auxiliary DNSSEC response that we didn't know before. We take that as reason to
+ restart the whole transaction. This is a good idea to deal with servers that respond rubbish if we include
+ OPT RR or DO bit. One of these cases is documented here, for example:
+ https://open.nlnetlabs.nl/pipermail/dnssec-trigger/2014-November/000376.html */
+
+ log_debug("Server feature level is now lower than when we began our transaction. Restarting.");
+ return dns_transaction_go(t);
+}
+
static int on_stream_complete(DnsStream *s, int error) {
_cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
DnsTransaction *t;
@@ -546,6 +565,16 @@ static void dns_transaction_process_dnssec(DnsTransaction *t) {
if (dns_transaction_dnssec_is_live(t))
return;
+ /* See if we learnt things from the additional DNSSEC transactions, that we didn't know before, and better
+ * restart the lookup immediately. */
+ r = dns_transaction_maybe_restart(t);
+ if (r < 0) {
+ dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES);
+ return;
+ }
+ if (r > 0) /* Transaction got restarted... */
+ return;
+
/* All our auxiliary DNSSEC transactions are complete now. Try
* to validate our RRset now. */
r = dns_transaction_validate_dnssec(t);
@@ -747,6 +776,15 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) {
dns_server_packet_received(t->server, p->ipproto, t->current_feature_level, ts - t->start_usec, p->size);
}
+ /* See if we know things we didn't know before that indicate we better restart the lookup immediately. */
+ r = dns_transaction_maybe_restart(t);
+ if (r < 0) {
+ dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES);
+ return;
+ }
+ if (r > 0) /* Transaction got restarted... */
+ return;
+
if (IN_SET(t->scope->protocol, DNS_PROTOCOL_DNS, DNS_PROTOCOL_LLMNR)) {
/* Only consider responses with equivalent query section to the request */