+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sd-messages.h>
+#include "sd-messages.h"
#include "af-list.h"
#include "alloc-util.h"
#include "string-table.h"
#define TRANSACTIONS_MAX 4096
+#define TRANSACTION_TCP_TIMEOUT_USEC (10U*USEC_PER_SEC)
static void dns_transaction_reset_answer(DnsTransaction *t) {
assert(t);
return -EOPNOTSUPP;
/* We only support the IN class */
- if (key->class != DNS_CLASS_IN && key->class != DNS_CLASS_ANY)
+ if (!IN_SET(key->class, DNS_CLASS_IN, DNS_CLASS_ANY))
return -EOPNOTSUPP;
if (hashmap_size(s->manager->dns_transactions) >= TRANSACTIONS_MAX)
* should hence not attempt to access the query or transaction
* after calling this function. */
- log_debug("Processing incoming packet on transaction %" PRIu16".", t->id);
+ log_debug("Processing incoming packet on transaction %" PRIu16". (rcode=%s)", t->id, dns_rcode_to_string(DNS_PACKET_RCODE(p)));
switch (t->scope->protocol) {
/* Request failed, immediately try again with reduced features */
- if (t->current_feature_level <= DNS_SERVER_FEATURE_LEVEL_WORST) {
- /* This was already at the lowest possible feature level? If so, we can't downgrade
- * this transaction anymore, hence let's process the response, and accept the rcode. */
+ if (t->current_feature_level <= DNS_SERVER_FEATURE_LEVEL_UDP) {
+ /* This was already at UDP feature level? If so, it doesn't make sense to downgrade
+ * this transaction anymore, hence let's process the response, and accept the
+ * rcode. Note that we don't retry on TCP, since that's a suitable way to mitigate
+ * packet loss, but is not going to give us better rcodes should we actually have
+ * managed to get them already at UDP level. */
+
log_debug("Server returned error: %s", dns_rcode_to_string(DNS_PACKET_RCODE(p)));
break;
}
return r;
if (t->current_feature_level < DNS_SERVER_FEATURE_LEVEL_UDP)
- return -EAGAIN;
+ return -EAGAIN; /* Sorry, can't do UDP, try TCP! */
if (!dns_server_dnssec_supported(t->server) && dns_type_is_dnssec(t->key->type))
return -EOPNOTSUPP;
assert(t);
assert(t->scope);
+
switch (t->scope->protocol) {
case DNS_PROTOCOL_DNS:
+
+ /* When we do TCP, grant a much longer timeout, as in this case there's no need for us to quickly
+ * resend, as the kernel does that anyway for us, and we really don't want to interrupt it in that
+ * needlessly. */
+ if (t->stream)
+ return TRANSACTION_TCP_TIMEOUT_USEC;
+
assert(t->server);
return t->server->resend_timeout;
af_to_name_short(t->scope->family));
if (!t->initial_jitter_scheduled &&
- (t->scope->protocol == DNS_PROTOCOL_LLMNR ||
- t->scope->protocol == DNS_PROTOCOL_MDNS)) {
+ IN_SET(t->scope->protocol, DNS_PROTOCOL_LLMNR, DNS_PROTOCOL_MDNS)) {
usec_t jitter, accuracy;
/* RFC 4795 Section 2.7 suggests all queries should be
r = dns_transaction_emit_udp(t);
if (r == -EMSGSIZE)
log_debug("Sending query via TCP since it is too large.");
- if (r == -EAGAIN)
+ else if (r == -EAGAIN)
log_debug("Sending query via TCP since server doesn't support UDP.");
- if (r == -EMSGSIZE || r == -EAGAIN)
+ if (IN_SET(r, -EMSGSIZE, -EAGAIN))
r = dns_transaction_open_tcp(t);
}
r = dns_resource_key_match_rr(t->key, rr, NULL);
if (r < 0)
return r;
- if (r == 0)
- continue;
+ if (r == 0) {
+ /* Hmm, so this SOA RR doesn't match our original question. In this case, maybe this is
+ * a negative reply, and we need the a SOA RR's TTL in order to cache a negative entry?
+ * If so, we need to validate it, too. */
+
+ r = dns_answer_match_key(t->answer, t->key, NULL);
+ if (r < 0)
+ return r;
+ if (r > 0) /* positive reply, we won't need the SOA and hence don't need to validate
+ * it. */
+ continue;
+ }
r = dnssec_has_rrsig(t->answer, rr->key);
if (r < 0)
if (r > 0) {
/* The lookup is from a TLD that is proven not to
* exist, and we are in downgrade mode, hence ignore
- * that fact that we didn't get any NSEC RRs.*/
+ * that fact that we didn't get any NSEC RRs. */
log_info("Detected a negative query %s in a private DNS zone, permitting unsigned response.",
dns_resource_key_to_string(t->key, key_str, sizeof key_str));
const char *source;
/* This RRset validated, but as a wildcard. This means we need
- * to prove via NSEC/NSEC3 that no matching non-wildcard RR exists.*/
+ * to prove via NSEC/NSEC3 that no matching non-wildcard RR exists. */
/* First step, determine the source of synthesis */
r = dns_resource_record_source(rrsig, &source);
return r;
if (r == 0) {
/* Data does not require signing. In that case, just copy it over,
- * but remember that this is by no means authenticated.*/
+ * but remember that this is by no means authenticated. */
r = dns_answer_move_by_key(validated, &t->answer, rr->key, 0);
if (r < 0)
return r;