#include "random-util.h"
#include "resolved-dns-cache.h"
#include "resolved-dns-transaction.h"
-#include "resolved-llmnr.h"
-#if ENABLE_DNS_OVER_TLS
#include "resolved-dnstls.h"
-#endif
+#include "resolved-llmnr.h"
#include "string-table.h"
#define TRANSACTIONS_MAX 4096
t->id,
dns_resource_key_to_string(t->key, key_str, sizeof key_str),
dns_protocol_to_string(t->scope->protocol),
- t->scope->link ? t->scope->link->name : "*",
+ t->scope->link ? t->scope->link->ifname : "*",
af_to_name_short(t->scope->family),
strnull(pretty));
"DNS_TRANSACTION=%" PRIu16, t->id,
"DNS_QUESTION=%s", key_str,
"DNSSEC_RESULT=%s", dnssec_result_to_string(t->answer_dnssec_result),
- "DNS_SERVER=%s", dns_server_string(t->server),
+ "DNS_SERVER=%s", strna(dns_server_string_full(t->server)),
"DNS_SERVER_FEATURE_LEVEL=%s", dns_server_feature_level_to_string(t->server->possible_feature_level));
}
t->id,
dns_resource_key_to_string(t->key, key_str, sizeof key_str),
dns_protocol_to_string(t->scope->protocol),
- t->scope->link ? t->scope->link->name : "*",
+ t->scope->link ? t->scope->link->ifname : "*",
af_to_name_short(t->scope->family),
st,
t->answer_source < 0 ? "none" : dns_transaction_source_to_string(t->answer_source),
dns_transaction_gc(t);
}
+static void dns_transaction_complete_errno(DnsTransaction *t, int error) {
+ assert(t);
+ assert(error != 0);
+
+ t->answer_errno = abs(error);
+ dns_transaction_complete(t, DNS_TRANSACTION_ERRNO);
+}
+
static int dns_transaction_pick_server(DnsTransaction *t) {
DnsServer *server;
t->n_picked_servers ++;
- log_debug("Using DNS server %s for transaction %u.", dns_server_string(t->server), t->id);
+ log_debug("Using DNS server %s for transaction %u.", strna(dns_server_string_full(t->server)), t->id);
return 1;
}
dns_scope_next_dns_server(t->scope);
r = dns_transaction_go(t);
- if (r < 0) {
- t->answer_errno = -r;
- dns_transaction_complete(t, DNS_TRANSACTION_ERRNO);
- }
+ if (r < 0)
+ dns_transaction_complete_errno(t, r);
}
static int dns_transaction_maybe_restart(DnsTransaction *t) {
dns_transaction_retry(t, true);
return;
}
- if (error != 0) {
- t->answer_errno = error;
- dns_transaction_complete(t, DNS_TRANSACTION_ERRNO);
- }
+ if (error != 0)
+ dns_transaction_complete_errno(t, error);
}
static int dns_transaction_on_stream_packet(DnsTransaction *t, DnsPacket *p) {
return 0;
}
-static uint16_t dns_port_for_feature_level(DnsServerFeatureLevel level) {
- return DNS_SERVER_FEATURE_LEVEL_IS_TLS(level) ? 853 : 53;
+static uint16_t dns_transaction_port(DnsTransaction *t) {
+ if (t->server->port > 0)
+ return t->server->port;
+ return DNS_SERVER_FEATURE_LEVEL_IS_TLS(t->current_feature_level) ? 853 : 53;
}
static int dns_transaction_emit_tcp(DnsTransaction *t) {
if (t->server->stream && (DNS_SERVER_FEATURE_LEVEL_IS_TLS(t->current_feature_level) == t->server->stream->encrypted))
s = dns_stream_ref(t->server->stream);
else
- fd = dns_scope_socket_tcp(t->scope, AF_UNSPEC, NULL, t->server, dns_port_for_feature_level(t->current_feature_level), &sa);
+ fd = dns_scope_socket_tcp(t->scope, AF_UNSPEC, NULL, t->server, dns_transaction_port(t), &sa);
type = DNS_STREAM_LOOKUP;
break;
return;
/* Caching disabled? */
- if (!t->scope->manager->enable_cache)
+ if (t->scope->manager->enable_cache == DNS_CACHE_MODE_NO)
return;
/* We never cache if this packet is from the local host, under
return;
dns_cache_put(&t->scope->cache,
+ t->scope->manager->enable_cache,
t->key,
t->answer_rcode,
t->answer,
static bool dns_transaction_dnssec_is_live(DnsTransaction *t) {
DnsTransaction *dt;
- Iterator i;
assert(t);
- SET_FOREACH(dt, t->dnssec_transactions, i)
+ SET_FOREACH(dt, t->dnssec_transactions)
if (DNS_TRANSACTION_IS_LIVE(dt->state))
return true;
static int dns_transaction_dnssec_ready(DnsTransaction *t) {
DnsTransaction *dt;
- Iterator i;
assert(t);
/* Checks whether the auxiliary DNSSEC transactions of our transaction have completed, or are still
* ongoing. Returns 0, if we aren't ready for the DNSSEC validation, positive if we are. */
- SET_FOREACH(dt, t->dnssec_transactions, i) {
+ SET_FOREACH(dt, t->dnssec_transactions) {
switch (dt->state) {
}
/* Fall-through: NXDOMAIN/SERVFAIL is good enough for us. This is because some DNS servers
- * erronously return NXDOMAIN/SERVFAIL for empty non-terminals (Akamai...) or missing DS
+ * erroneously return NXDOMAIN/SERVFAIL for empty non-terminals (Akamai...) or missing DS
* records (Facebook), and we need to handle that nicely, when asking for parent SOA or similar
* RRs to make unsigned proofs. */
return;
fail:
- t->answer_errno = -r;
- dns_transaction_complete(t, DNS_TRANSACTION_ERRNO);
+ dns_transaction_complete_errno(t, r);
}
static int dns_transaction_has_positive_answer(DnsTransaction *t, DnsAnswerFlags *flags) {
return;
fail:
- t->answer_errno = -r;
- dns_transaction_complete(t, DNS_TRANSACTION_ERRNO);
+ dns_transaction_complete_errno(t, r);
}
static int on_dns_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
assert(t->scope);
r = manager_recv(t->scope->manager, fd, DNS_PROTOCOL_DNS, &p);
- if (ERRNO_IS_DISCONNECT(-r)) {
+ if (ERRNO_IS_DISCONNECT(r)) {
usec_t usec;
- /* UDP connection failure get reported via ICMP and then are possible delivered to us on the next
- * recvmsg(). Treat this like a lost packet. */
+ /* UDP connection failures get reported via ICMP and then are possibly delivered to us on the
+ * next recvmsg(). Treat this like a lost packet. */
log_debug_errno(r, "Connection failure for DNS UDP packet: %m");
assert_se(sd_event_now(t->scope->manager->event, clock_boottime_or_monotonic(), &usec) >= 0);
return 0;
}
if (r < 0) {
- dns_transaction_complete(t, DNS_TRANSACTION_ERRNO);
- t->answer_errno = -r;
+ dns_transaction_complete_errno(t, r);
return 0;
}
+ if (r == 0)
+ /* Spurious wakeup without any data */
+ return 0;
r = dns_packet_validate_reply(p);
if (r < 0) {
dns_transaction_close_connection(t);
- fd = dns_scope_socket_udp(t->scope, t->server, 53);
+ fd = dns_scope_socket_udp(t->scope, t->server);
if (fd < 0)
return fd;
}
if (t->n_attempts >= TRANSACTION_ATTEMPTS_MAX(t->scope->protocol)) {
- dns_transaction_complete(t, DNS_TRANSACTION_ATTEMPTS_MAX_REACHED);
+ DnsTransactionState result;
+
+ if (t->scope->protocol == DNS_PROTOCOL_LLMNR)
+ /* If we didn't find anything on LLMNR, it's not an error, but a failure to resolve
+ * the name. */
+ result = DNS_TRANSACTION_NOT_FOUND;
+ else
+ result = DNS_TRANSACTION_ATTEMPTS_MAX_REACHED;
+
+ dns_transaction_complete(t, result);
return 0;
}
_cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
bool add_known_answers = false;
DnsTransaction *other;
- Iterator i;
DnsResourceKey *tkey;
_cleanup_set_free_ Set *keys = NULL;
unsigned qdcount;
add_known_answers = true;
if (t->key->type == DNS_TYPE_ANY) {
- r = set_ensure_allocated(&keys, &dns_resource_key_hash_ops);
- if (r < 0)
- return r;
-
- r = set_put(keys, t->key);
+ r = set_ensure_put(&keys, &dns_resource_key_hash_ops, t->key);
if (r < 0)
return r;
}
/*
* For mDNS, we want to coalesce as many open queries in pending transactions into one single
* query packet on the wire as possible. To achieve that, we iterate through all pending transactions
- * in our current scope, and see whether their timing contraints allow them to be sent.
+ * in our current scope, and see whether their timing constraints allow them to be sent.
*/
assert_se(sd_event_now(t->scope->manager->event, clock_boottime_or_monotonic(), &ts) >= 0);
add_known_answers = true;
if (other->key->type == DNS_TYPE_ANY) {
- r = set_ensure_allocated(&keys, &dns_resource_key_hash_ops);
- if (r < 0)
- return r;
-
- r = set_put(keys, other->key);
+ r = set_ensure_put(&keys, &dns_resource_key_hash_ops, other->key);
if (r < 0)
return r;
}
return r;
}
- SET_FOREACH(tkey, keys, i) {
+ SET_FOREACH(tkey, keys) {
_cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
bool tentative;
t->id,
dns_resource_key_to_string(t->key, key_str, sizeof key_str),
dns_protocol_to_string(t->scope->protocol),
- t->scope->link ? t->scope->link->name : "*",
+ t->scope->link ? t->scope->link->ifname : "*",
af_to_name_short(t->scope->family));
if (!t->initial_jitter_scheduled &&
dns_transaction_complete(t, DNS_TRANSACTION_RR_TYPE_UNSUPPORTED);
return 0;
}
- if (t->scope->protocol == DNS_PROTOCOL_LLMNR && ERRNO_IS_DISCONNECT(-r)) {
+ if (t->scope->protocol == DNS_PROTOCOL_LLMNR && ERRNO_IS_DISCONNECT(r)) {
/* On LLMNR, if we cannot connect to a host via TCP when doing reverse lookups. This means we cannot
* answer this request with this protocol. */
dns_transaction_complete(t, DNS_TRANSACTION_NOT_FOUND);
static int dns_transaction_find_cyclic(DnsTransaction *t, DnsTransaction *aux) {
DnsTransaction *n;
- Iterator i;
int r;
assert(t);
if (t == aux)
return 1;
- SET_FOREACH(n, aux->dnssec_transactions, i) {
+ SET_FOREACH(n, aux->dnssec_transactions) {
r = dns_transaction_find_cyclic(t, n);
if (r != 0)
return r;
}
static int dns_transaction_add_dnssec_transaction(DnsTransaction *t, DnsResourceKey *key, DnsTransaction **ret) {
- DnsTransaction *aux;
+ _cleanup_(dns_transaction_gcp) DnsTransaction *aux = NULL;
int r;
assert(t);
}
}
- r = set_ensure_allocated(&t->dnssec_transactions, NULL);
- if (r < 0)
- goto gc;
-
- r = set_ensure_allocated(&aux->notify_transactions, NULL);
- if (r < 0)
- goto gc;
-
r = set_ensure_allocated(&aux->notify_transactions_done, NULL);
if (r < 0)
- goto gc;
+ return r;
- r = set_put(t->dnssec_transactions, aux);
+ r = set_ensure_put(&t->dnssec_transactions, NULL, aux);
if (r < 0)
- goto gc;
+ return r;
- r = set_put(aux->notify_transactions, t);
+ r = set_ensure_put(&aux->notify_transactions, NULL, t);
if (r < 0) {
(void) set_remove(t->dnssec_transactions, aux);
- goto gc;
+ return r;
}
- *ret = aux;
+ *ret = TAKE_PTR(aux);
return 1;
-
-gc:
- dns_transaction_gc(aux);
- return r;
}
static int dns_transaction_request_dnssec_rr(DnsTransaction *t, DnsResourceKey *key) {
static bool dns_transaction_dnssec_supported_full(DnsTransaction *t) {
DnsTransaction *dt;
- Iterator i;
assert(t);
if (!dns_transaction_dnssec_supported(t))
return false;
- SET_FOREACH(dt, t->dnssec_transactions, i)
+ SET_FOREACH(dt, t->dnssec_transactions)
if (!dns_transaction_dnssec_supported(dt))
return false;
if (t->answer_source != DNS_TRANSACTION_NETWORK)
return 0; /* We only need to validate stuff from the network */
if (!dns_transaction_dnssec_supported(t))
- return 0; /* If we can't do DNSSEC anyway there's no point in geting the auxiliary RRs */
+ return 0; /* If we can't do DNSSEC anyway there's no point in getting the auxiliary RRs */
DNS_ANSWER_FOREACH(rr, t->answer) {
* RRs for stuff we didn't really ask for, and
* also to avoid request loops, where
* additional RRs from one transaction result
- * in another transaction whose additonal RRs
+ * in another transaction whose additional RRs
* point back to the original transaction, and
* we deadlock. */
r = dns_name_endswith(dns_resource_key_name(t->key), rr->rrsig.signer);
case DNS_TYPE_SOA:
case DNS_TYPE_NS: {
DnsTransaction *dt;
- Iterator i;
/* For SOA or NS RRs we look for a matching DS transaction */
- SET_FOREACH(dt, t->dnssec_transactions, i) {
+ SET_FOREACH(dt, t->dnssec_transactions) {
if (dt->key->class != rr->key->class)
continue;
case DNS_TYPE_DNAME: {
const char *parent = NULL;
DnsTransaction *dt;
- Iterator i;
/*
* CNAME/DNAME RRs cannot be located at a zone apex, hence look directly for the parent SOA.
* DS RRs are signed if the parent is signed, hence also look at the parent SOA
*/
- SET_FOREACH(dt, t->dnssec_transactions, i) {
+ SET_FOREACH(dt, t->dnssec_transactions) {
if (dt->key->class != rr->key->class)
continue;
default: {
DnsTransaction *dt;
- Iterator i;
/* Any other kind of RR (including DNSKEY/NSEC/NSEC3). Let's see if our SOA lookup was authenticated */
- SET_FOREACH(dt, t->dnssec_transactions, i) {
+ SET_FOREACH(dt, t->dnssec_transactions) {
if (dt->key->class != rr->key->class)
continue;
static int dns_transaction_in_private_tld(DnsTransaction *t, const DnsResourceKey *key) {
DnsTransaction *dt;
const char *tld;
- Iterator i;
int r;
/* If DNSSEC downgrade mode is on, checks whether the
if (!dns_name_is_single_label(tld))
return false;
- SET_FOREACH(dt, t->dnssec_transactions, i) {
+ SET_FOREACH(dt, t->dnssec_transactions) {
if (dt->key->class != key->class)
continue;
DnsTransaction *dt;
const char *name;
uint16_t type = 0;
- Iterator i;
int r;
assert(t);
/* For all other RRs we check the SOA on the same level to see
* if it's signed. */
- SET_FOREACH(dt, t->dnssec_transactions, i) {
+ SET_FOREACH(dt, t->dnssec_transactions) {
if (dt->key->class != t->key->class)
continue;
DNS_ANSWER_FOREACH(rrsig, t->answer) {
DnsTransaction *dt;
- Iterator i;
r = dnssec_key_match_rrsig(rr->key, rrsig);
if (r < 0)
if (r == 0)
continue;
- SET_FOREACH(dt, t->dnssec_transactions, i) {
+ SET_FOREACH(dt, t->dnssec_transactions) {
if (dt->key->class != rr->key->class)
continue;
static int dns_transaction_copy_validated(DnsTransaction *t) {
DnsTransaction *dt;
- Iterator i;
int r;
assert(t);
/* Copy all validated RRs from the auxiliary DNSSEC transactions into our set of validated RRs */
- SET_FOREACH(dt, t->dnssec_transactions, i) {
+ SET_FOREACH(dt, t->dnssec_transactions) {
if (DNS_TRANSACTION_IS_LIVE(dt->state))
continue;