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.
This commit is contained in:
Lennart Poettering 2016-01-15 20:45:17 +01:00
parent ed9717fcbf
commit c02cf2f41f
1 changed files with 38 additions and 0 deletions

View File

@ -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 */