dns_transaction_complete_errno(t, r);
}
+static bool dns_transaction_limited_retry(DnsTransaction *t) {
+ assert(t);
+
+ /* If we haven't tried all different servers yet, let's try again with a different server */
+
+ if (t->n_picked_servers >= dns_scope_get_n_dns_servers(t->scope))
+ return false;
+
+ dns_transaction_retry(t, /* next_server= */ true);
+ return true;
+}
+
static int dns_transaction_maybe_restart(DnsTransaction *t) {
int r;
assert(t);
- /* Returns > 0 if the transaction was restarted, 0 if not */
+ /* Restarts the transaction, under a new ID if the feature level of the server changed since we first
+ * tried, without changing DNS server. Returns > 0 if the transaction was restarted, 0 if not. */
if (!t->server)
return 0;
/* We are not in automatic downgrade mode, and the server is bad. Let's try a different server, maybe
* that works. */
- if (t->n_picked_servers < dns_scope_get_n_dns_servers(t->scope)) {
- /* We tried fewer servers on this transaction than we know, let's try another one then */
- dns_transaction_retry(t, true);
+ if (dns_transaction_limited_retry(t))
return;
- }
/* OK, let's give up, apparently all servers we tried didn't work. */
dns_transaction_complete(t, DNS_TRANSACTION_DNSSEC_FAILED);
* packet loss, but is not going to give us better rcodes should we actually have
* managed to get them already at UDP level. */
- if (t->n_picked_servers < dns_scope_get_n_dns_servers(t->scope)) {
- /* We tried fewer servers on this transaction than we know, let's try another one then */
- dns_transaction_retry(t, true);
+ if (dns_transaction_limited_retry(t))
return;
- }
/* Give up, accept the rcode */
log_debug("Server returned error: %s", dns_rcode_to_string(DNS_PACKET_RCODE(p)));
if (DNS_PACKET_RCODE(p) == DNS_RCODE_REFUSED) {
/* This server refused our request? If so, try again, use a different server */
log_debug("Server returned REFUSED, switching servers, and retrying.");
- dns_transaction_retry(t, true /* pick a new server */);
- return;
+
+ if (dns_transaction_limited_retry(t))
+ return;
+
+ break;
}
if (DNS_PACKET_TC(p))
goto fail;
/* On DNS, couldn't send? Try immediately again, with a new server */
- dns_transaction_retry(t, true);
+ if (dns_transaction_limited_retry(t))
+ return;
+
+ /* No new server to try, give up */
+ dns_transaction_complete(t, DNS_TRANSACTION_ATTEMPTS_MAX_REACHED);
}
return;
dns_transaction_close_connection(t, /* use_graveyard = */ false);
- dns_transaction_retry(t, true);
+ if (dns_transaction_limited_retry(t)) /* Try a different server */
+ return 0;
+
+ dns_transaction_complete_errno(t, r);
return 0;
}
if (r < 0) {
log_debug("Timeout reached on transaction %" PRIu16 ".", t->id);
- dns_transaction_retry(t, true);
+ dns_transaction_retry(t, true); /* try a different server, but given this means packet loss, let's do
+ * so even if we already tried a bunch */
return 0;
}