mirror of
https://github.com/systemd/systemd.git
synced 2024-12-22 17:35:35 +03:00
resolved: support RFC 8914 EDE error codes
If the server is able to indicate an extended error to us, using a degraded feature set is unlikely to help.
This commit is contained in:
parent
3fcd83645a
commit
ac6844460c
@ -6,6 +6,7 @@
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "dns-domain.h"
|
||||
#include "escape.h"
|
||||
#include "memory-util.h"
|
||||
#include "resolved-dns-packet.h"
|
||||
#include "set.h"
|
||||
@ -2570,6 +2571,78 @@ bool dns_packet_equal(const DnsPacket *a, const DnsPacket *b) {
|
||||
return dns_packet_compare_func(a, b) == 0;
|
||||
}
|
||||
|
||||
int dns_packet_ede_rcode(DnsPacket *p, char **ret_ede_msg) {
|
||||
assert(p);
|
||||
|
||||
_cleanup_free_ char *msg = NULL, *msg_escaped = NULL;
|
||||
int ede_rcode = _DNS_EDNS_OPT_MAX_DEFINED;
|
||||
int r;
|
||||
const uint8_t *d;
|
||||
size_t l;
|
||||
|
||||
if (!p->opt)
|
||||
return _DNS_EDE_RCODE_INVALID;
|
||||
|
||||
d = p->opt->opt.data;
|
||||
l = p->opt->opt.data_size;
|
||||
|
||||
while (l > 0) {
|
||||
uint16_t code, length;
|
||||
|
||||
if (l < 4U)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG),
|
||||
"EDNS0 variable part has invalid size.");
|
||||
|
||||
code = unaligned_read_be16(d);
|
||||
length = unaligned_read_be16(d + 2);
|
||||
|
||||
if (l < 4U + length)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG),
|
||||
"Truncated option in EDNS0 variable part.");
|
||||
|
||||
if (code == DNS_EDNS_OPT_EXT_ERROR) {
|
||||
if (length < 2U)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG),
|
||||
"EDNS0 truncated EDE info code.");
|
||||
ede_rcode = unaligned_read_be16(d + 4);
|
||||
r = make_cstring((char *)d + 6, length - 2U, MAKE_CSTRING_ALLOW_TRAILING_NUL, &msg);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Invalid EDE text in opt");
|
||||
else if (!utf8_is_valid(msg))
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "Invalid EDE text in opt");
|
||||
else if (ede_rcode < _DNS_EDNS_OPT_MAX_DEFINED) {
|
||||
msg_escaped = cescape(msg);
|
||||
if (!msg_escaped)
|
||||
return -ENOMEM;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
d += 4U + length;
|
||||
l -= 4U + length;
|
||||
}
|
||||
|
||||
if (ret_ede_msg)
|
||||
*ret_ede_msg = TAKE_PTR(msg_escaped);
|
||||
|
||||
return ede_rcode;
|
||||
}
|
||||
|
||||
bool dns_ede_rcode_is_dnssec(int ede_rcode) {
|
||||
return IN_SET(ede_rcode,
|
||||
DNS_EDE_RCODE_UNSUPPORTED_DNSKEY_ALG,
|
||||
DNS_EDE_RCODE_UNSUPPORTED_DS_DIGEST,
|
||||
DNS_EDE_RCODE_DNSSEC_INDETERMINATE,
|
||||
DNS_EDE_RCODE_DNSSEC_BOGUS,
|
||||
DNS_EDE_RCODE_SIG_EXPIRED,
|
||||
DNS_EDE_RCODE_SIG_NOT_YET_VALID,
|
||||
DNS_EDE_RCODE_DNSKEY_MISSING,
|
||||
DNS_EDE_RCODE_RRSIG_MISSING,
|
||||
DNS_EDE_RCODE_NO_ZONE_KEY_BIT,
|
||||
DNS_EDE_RCODE_NSEC_MISSING
|
||||
);
|
||||
}
|
||||
|
||||
int dns_packet_has_nsid_request(DnsPacket *p) {
|
||||
bool has_nsid = false;
|
||||
const uint8_t *d;
|
||||
@ -2693,7 +2766,7 @@ static const char* const dns_ede_rcode_table[_DNS_EDE_RCODE_MAX_DEFINED] = {
|
||||
[DNS_EDE_RCODE_TRANSPORT_POLICY] = "Impossible Transport Policy",
|
||||
[DNS_EDE_RCODE_SYNTHESIZED] = "Synthesized",
|
||||
};
|
||||
DEFINE_STRING_TABLE_LOOKUP(dns_ede_rcode, int);
|
||||
DEFINE_STRING_TABLE_LOOKUP_TO_STRING(dns_ede_rcode, int);
|
||||
|
||||
const char *format_dns_ede_rcode(int i, char buf[static DECIMAL_STR_MAX(int)]) {
|
||||
const char *p = dns_ede_rcode_to_string(i);
|
||||
|
@ -253,6 +253,8 @@ int dns_packet_extract(DnsPacket *p);
|
||||
|
||||
bool dns_packet_equal(const DnsPacket *a, const DnsPacket *b);
|
||||
|
||||
int dns_packet_ede_rcode(DnsPacket *p, char **ret_ede_msg);
|
||||
bool dns_ede_rcode_is_dnssec(int ede_rcode);
|
||||
int dns_packet_has_nsid_request(DnsPacket *p);
|
||||
|
||||
/* https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-6 */
|
||||
|
@ -1200,11 +1200,51 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p, bool encrypt
|
||||
|
||||
switch (t->scope->protocol) {
|
||||
|
||||
case DNS_PROTOCOL_DNS:
|
||||
case DNS_PROTOCOL_DNS: {
|
||||
int ede_rcode;
|
||||
_cleanup_free_ char *ede_msg = NULL;
|
||||
|
||||
assert(t->server);
|
||||
|
||||
ede_rcode = dns_packet_ede_rcode(p, &ede_msg);
|
||||
if (ede_rcode < 0 && ede_rcode != -EINVAL)
|
||||
log_debug_errno(ede_rcode, "Unable to extract EDE error code from packet, ignoring: %m");
|
||||
|
||||
if (!t->bypass &&
|
||||
IN_SET(DNS_PACKET_RCODE(p), DNS_RCODE_FORMERR, DNS_RCODE_SERVFAIL, DNS_RCODE_NOTIMP)) {
|
||||
/* If the server has replied with detailed error data, using a degraded feature set
|
||||
* will likely not help anyone. Examine the detailed error to determine the best
|
||||
* course of action. */
|
||||
if (ede_rcode >= 0 && DNS_PACKET_RCODE(p) == DNS_RCODE_SERVFAIL) {
|
||||
/* These codes are related to DNSSEC configuration errors. If accurate,
|
||||
* this is the domain operator's problem, and retrying won't help. */
|
||||
if (dns_ede_rcode_is_dnssec(ede_rcode)) {
|
||||
log_debug("Server returned error: %s (%s%s%s). Lookup failed.",
|
||||
FORMAT_DNS_RCODE(DNS_PACKET_RCODE(p)),
|
||||
FORMAT_DNS_EDE_RCODE(ede_rcode),
|
||||
isempty(ede_msg) ? "" : ": ", ede_msg);
|
||||
dns_transaction_complete(t, DNS_TRANSACTION_DNSSEC_FAILED);
|
||||
return;
|
||||
}
|
||||
|
||||
/* These codes probably indicate a transient error. Let's try again. */
|
||||
if (IN_SET(ede_rcode, DNS_EDE_RCODE_NOT_READY, DNS_EDE_RCODE_NET_ERROR)) {
|
||||
log_debug("Server returned error: %s (%s%s%s), retrying transaction.",
|
||||
FORMAT_DNS_RCODE(DNS_PACKET_RCODE(p)),
|
||||
FORMAT_DNS_EDE_RCODE(ede_rcode),
|
||||
isempty(ede_msg) ? "" : ": ", ede_msg);
|
||||
dns_transaction_retry(t, false);
|
||||
return;
|
||||
}
|
||||
|
||||
/* OK, the query failed, but we still shouldn't degrade the feature set for
|
||||
* this server. */
|
||||
log_debug("Server returned error: %s (%s%s%s)",
|
||||
FORMAT_DNS_RCODE(DNS_PACKET_RCODE(p)),
|
||||
FORMAT_DNS_EDE_RCODE(ede_rcode),
|
||||
isempty(ede_msg) ? "" : ": ", ede_msg);
|
||||
break;
|
||||
} /* No EDE rcode, or EDE rcode we don't understand */
|
||||
|
||||
/* Request failed, immediately try again with reduced features */
|
||||
|
||||
@ -1261,6 +1301,10 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p, bool encrypt
|
||||
|
||||
if (DNS_PACKET_RCODE(p) == DNS_RCODE_REFUSED) {
|
||||
/* This server refused our request? If so, try again, use a different server */
|
||||
if (ede_rcode > 0)
|
||||
log_debug("Server returned REFUSED (%s), switching servers, and retrying.",
|
||||
FORMAT_DNS_EDE_RCODE(ede_rcode));
|
||||
else
|
||||
log_debug("Server returned REFUSED, switching servers, and retrying.");
|
||||
|
||||
if (dns_transaction_limited_retry(t))
|
||||
@ -1273,6 +1317,7 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p, bool encrypt
|
||||
dns_server_packet_truncated(t->server, t->current_feature_level);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case DNS_PROTOCOL_LLMNR:
|
||||
case DNS_PROTOCOL_MDNS:
|
||||
|
Loading…
Reference in New Issue
Block a user