mirror of
https://github.com/systemd/systemd.git
synced 2025-09-13 05:44:40 +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:
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
#include "dns-domain.h"
|
#include "dns-domain.h"
|
||||||
|
#include "escape.h"
|
||||||
#include "memory-util.h"
|
#include "memory-util.h"
|
||||||
#include "resolved-dns-packet.h"
|
#include "resolved-dns-packet.h"
|
||||||
#include "set.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;
|
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) {
|
int dns_packet_has_nsid_request(DnsPacket *p) {
|
||||||
bool has_nsid = false;
|
bool has_nsid = false;
|
||||||
const uint8_t *d;
|
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_TRANSPORT_POLICY] = "Impossible Transport Policy",
|
||||||
[DNS_EDE_RCODE_SYNTHESIZED] = "Synthesized",
|
[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 *format_dns_ede_rcode(int i, char buf[static DECIMAL_STR_MAX(int)]) {
|
||||||
const char *p = dns_ede_rcode_to_string(i);
|
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);
|
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);
|
int dns_packet_has_nsid_request(DnsPacket *p);
|
||||||
|
|
||||||
/* https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-6 */
|
/* 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) {
|
switch (t->scope->protocol) {
|
||||||
|
|
||||||
case DNS_PROTOCOL_DNS:
|
case DNS_PROTOCOL_DNS: {
|
||||||
|
int ede_rcode;
|
||||||
|
_cleanup_free_ char *ede_msg = NULL;
|
||||||
|
|
||||||
assert(t->server);
|
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 &&
|
if (!t->bypass &&
|
||||||
IN_SET(DNS_PACKET_RCODE(p), DNS_RCODE_FORMERR, DNS_RCODE_SERVFAIL, DNS_RCODE_NOTIMP)) {
|
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 */
|
/* 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) {
|
if (DNS_PACKET_RCODE(p) == DNS_RCODE_REFUSED) {
|
||||||
/* This server refused our request? If so, try again, use a different server */
|
/* 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.");
|
log_debug("Server returned REFUSED, switching servers, and retrying.");
|
||||||
|
|
||||||
if (dns_transaction_limited_retry(t))
|
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);
|
dns_server_packet_truncated(t->server, t->current_feature_level);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case DNS_PROTOCOL_LLMNR:
|
case DNS_PROTOCOL_LLMNR:
|
||||||
case DNS_PROTOCOL_MDNS:
|
case DNS_PROTOCOL_MDNS:
|
||||||
|
Reference in New Issue
Block a user