summaryrefslogtreecommitdiffstats
path: root/src/resolve/resolved-dns-packet.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/resolve/resolved-dns-packet.c312
1 files changed, 305 insertions, 7 deletions
diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c
index 426711b..e626740 100644
--- a/src/resolve/resolved-dns-packet.c
+++ b/src/resolve/resolved-dns-packet.c
@@ -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"
@@ -569,7 +570,7 @@ int dns_packet_append_name(
while (!dns_name_is_root(name)) {
const char *z = name;
- char label[DNS_LABEL_MAX];
+ char label[DNS_LABEL_MAX+1];
size_t n = 0;
if (allow_compression)
@@ -792,7 +793,7 @@ int dns_packet_append_opt(
static const uint8_t rfc6975[] = {
- 0, 5, /* OPTION_CODE: DAU */
+ 0, DNS_EDNS_OPT_DAU, /* OPTION_CODE */
#if PREFER_OPENSSL || (HAVE_GCRYPT && GCRYPT_VERSION_NUMBER >= 0x010600)
0, 7, /* LIST_LENGTH */
#else
@@ -808,13 +809,13 @@ int dns_packet_append_opt(
DNSSEC_ALGORITHM_ED25519,
#endif
- 0, 6, /* OPTION_CODE: DHU */
+ 0, DNS_EDNS_OPT_DHU, /* OPTION_CODE */
0, 3, /* LIST_LENGTH */
DNSSEC_DIGEST_SHA1,
DNSSEC_DIGEST_SHA256,
DNSSEC_DIGEST_SHA384,
- 0, 7, /* OPTION_CODE: N3U */
+ 0, DNS_EDNS_OPT_N3U, /* OPTION_CODE */
0, 1, /* LIST_LENGTH */
NSEC3_ALGORITHM_SHA1,
};
@@ -1182,6 +1183,31 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, const DnsAns
r = dns_packet_append_blob(p, rr->tlsa.data, rr->tlsa.data_size, NULL);
break;
+ case DNS_TYPE_SVCB:
+ case DNS_TYPE_HTTPS:
+ r = dns_packet_append_uint16(p, rr->svcb.priority, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_append_name(p, rr->svcb.target_name, false, false, NULL);
+ if (r < 0)
+ goto fail;
+
+ LIST_FOREACH(params, i, rr->svcb.params) {
+ r = dns_packet_append_uint16(p, i->key, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_append_uint16(p, i->length, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_append_blob(p, i->value, i->length, NULL);
+ if (r < 0)
+ goto fail;
+ }
+ break;
+
case DNS_TYPE_CAA:
r = dns_packet_append_uint8(p, rr->caa.flags, NULL);
if (r < 0)
@@ -1194,6 +1220,30 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, const DnsAns
r = dns_packet_append_blob(p, rr->caa.value, rr->caa.value_size, NULL);
break;
+ case DNS_TYPE_NAPTR:
+ r = dns_packet_append_uint16(p, rr->naptr.order, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_append_uint16(p, rr->naptr.preference, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_append_string(p, rr->naptr.flags, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_append_string(p, rr->naptr.services, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_append_string(p, rr->naptr.regexp, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_append_name(p, rr->naptr.replacement, /* allow_compression= */ false, /* canonical_candidate= */ true, NULL);
+ break;
+
case DNS_TYPE_OPT:
case DNS_TYPE_OPENPGPKEY:
case _DNS_TYPE_INVALID: /* unparsable */
@@ -1688,6 +1738,41 @@ static bool loc_size_ok(uint8_t size) {
return m <= 9 && e <= 9 && (m > 0 || e == 0);
}
+static bool dns_svc_param_is_valid(DnsSvcParam *i) {
+ if (!i)
+ return false;
+
+ switch (i->key) {
+ /* RFC 9460, section 7.1.1: alpn-ids must exactly fill SvcParamValue */
+ case DNS_SVC_PARAM_KEY_ALPN: {
+ size_t sz = 0;
+ if (i->length <= 0)
+ return false;
+ while (sz < i->length)
+ sz += 1 + i->value[sz]; /* N.B. will not overflow */
+ return sz == i->length;
+ }
+
+ /* RFC 9460, section 7.1.1: value must be empty */
+ case DNS_SVC_PARAM_KEY_NO_DEFAULT_ALPN:
+ return i->length == 0;
+
+ /* RFC 9460, section 7.2 */
+ case DNS_SVC_PARAM_KEY_PORT:
+ return i->length == 2;
+
+ /* RFC 9460, section 7.3: addrs must exactly fill SvcParamValue */
+ case DNS_SVC_PARAM_KEY_IPV4HINT:
+ return i->length % (sizeof (struct in_addr)) == 0;
+ case DNS_SVC_PARAM_KEY_IPV6HINT:
+ return i->length % (sizeof (struct in6_addr)) == 0;
+
+ /* Otherwise, permit any value */
+ default:
+ return true;
+ }
+}
+
int dns_packet_read_rr(
DnsPacket *p,
DnsResourceRecord **ret,
@@ -2122,6 +2207,52 @@ int dns_packet_read_rr(
break;
+ case DNS_TYPE_SVCB:
+ case DNS_TYPE_HTTPS:
+ r = dns_packet_read_uint16(p, &rr->svcb.priority, NULL);
+ if (r < 0)
+ return r;
+
+ r = dns_packet_read_name(p, &rr->svcb.target_name, false /* uncompressed */, NULL);
+ if (r < 0)
+ return r;
+
+ DnsSvcParam *last = NULL;
+ while (p->rindex - offset < rdlength) {
+ _cleanup_free_ DnsSvcParam *i = NULL;
+ uint16_t svc_param_key;
+ uint16_t sz;
+
+ r = dns_packet_read_uint16(p, &svc_param_key, NULL);
+ if (r < 0)
+ return r;
+ /* RFC 9460, section 2.2 says we must consider an RR malformed if SvcParamKeys are
+ * not in strictly increasing order */
+ if (last && last->key >= svc_param_key)
+ return -EBADMSG;
+
+ r = dns_packet_read_uint16(p, &sz, NULL);
+ if (r < 0)
+ return r;
+
+ i = malloc0(offsetof(DnsSvcParam, value) + sz);
+ if (!i)
+ return -ENOMEM;
+
+ i->key = svc_param_key;
+ i->length = sz;
+ r = dns_packet_read_blob(p, &i->value, sz, NULL);
+ if (r < 0)
+ return r;
+ if (!dns_svc_param_is_valid(i))
+ return -EBADMSG;
+
+ LIST_INSERT_AFTER(params, rr->svcb.params, last, i);
+ last = TAKE_PTR(i);
+ }
+
+ break;
+
case DNS_TYPE_CAA:
r = dns_packet_read_uint8(p, &rr->caa.flags, NULL);
if (r < 0)
@@ -2140,6 +2271,30 @@ int dns_packet_read_rr(
break;
+ case DNS_TYPE_NAPTR:
+ r = dns_packet_read_uint16(p, &rr->naptr.order, NULL);
+ if (r < 0)
+ return r;
+
+ r = dns_packet_read_uint16(p, &rr->naptr.preference, NULL);
+ if (r < 0)
+ return r;
+
+ r = dns_packet_read_string(p, &rr->naptr.flags, NULL);
+ if (r < 0)
+ return r;
+
+ r = dns_packet_read_string(p, &rr->naptr.services, NULL);
+ if (r < 0)
+ return r;
+
+ r = dns_packet_read_string(p, &rr->naptr.regexp, NULL);
+ if (r < 0)
+ return r;
+
+ r = dns_packet_read_name(p, &rr->naptr.replacement, /* allow_compressed= */ false, NULL);
+ break;
+
case DNS_TYPE_OPT: /* we only care about the header of OPT for now. */
case DNS_TYPE_OPENPGPKEY:
default:
@@ -2197,7 +2352,7 @@ static bool opt_is_good(DnsResourceRecord *rr, bool *rfc6975) {
return false;
/* RFC 6975 DAU, DHU or N3U fields found. */
- if (IN_SET(option_code, 5, 6, 7))
+ if (IN_SET(option_code, DNS_EDNS_OPT_DAU, DNS_EDNS_OPT_DHU, DNS_EDNS_OPT_N3U))
found_dau_dhu_n3u = true;
p += option_length + 4U;
@@ -2567,7 +2722,7 @@ int dns_packet_patch_ttls(DnsPacket *p, usec_t timestamp) {
static void dns_packet_hash_func(const DnsPacket *s, struct siphash *state) {
assert(s);
- siphash24_compress(&s->size, sizeof(s->size), state);
+ siphash24_compress_typesafe(s->size, state);
siphash24_compress(DNS_PACKET_DATA((DnsPacket*) s), s->size, state);
}
@@ -2587,6 +2742,85 @@ 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, int *ret_ede_rcode, char **ret_ede_msg) {
+ const uint8_t *d;
+ size_t l;
+ int r;
+
+ assert(p);
+
+ if (!p->opt)
+ return -ENOENT;
+
+ 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) {
+ _cleanup_free_ char *msg = NULL;
+
+ if (length < 2U)
+ return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG),
+ "EDNS0 truncated EDE info code.");
+
+ 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.");
+
+ if (ret_ede_msg) {
+ if (!utf8_is_valid(msg)) {
+ _cleanup_free_ char *msg_escaped = NULL;
+
+ msg_escaped = cescape(msg);
+ if (!msg_escaped)
+ return log_oom_debug();
+
+ *ret_ede_msg = TAKE_PTR(msg_escaped);
+ } else
+ *ret_ede_msg = TAKE_PTR(msg);
+ }
+
+ if (ret_ede_rcode)
+ *ret_ede_rcode = unaligned_read_be16(d + 4);
+
+ return 0;
+ }
+
+ d += 4U + length;
+ l -= 4U + length;
+ }
+
+ return -ENOENT;
+}
+
+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;
@@ -2614,7 +2848,7 @@ int dns_packet_has_nsid_request(DnsPacket *p) {
return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG),
"Truncated option in EDNS0 variable part.");
- if (code == 3) {
+ if (code == DNS_EDNS_OPT_NSID) {
if (has_nsid)
return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG),
"Duplicate NSID option in EDNS0 variable part.");
@@ -2659,6 +2893,7 @@ static const char* const dns_rcode_table[_DNS_RCODE_MAX_DEFINED] = {
[DNS_RCODE_NXRRSET] = "NXRRSET",
[DNS_RCODE_NOTAUTH] = "NOTAUTH",
[DNS_RCODE_NOTZONE] = "NOTZONE",
+ [DNS_RCODE_DSOTYPENI] = "DSOTYPENI",
[DNS_RCODE_BADVERS] = "BADVERS",
[DNS_RCODE_BADKEY] = "BADKEY",
[DNS_RCODE_BADTIME] = "BADTIME",
@@ -2678,6 +2913,69 @@ const char *format_dns_rcode(int i, char buf[static DECIMAL_STR_MAX(int)]) {
return snprintf_ok(buf, DECIMAL_STR_MAX(int), "%i", i);
}
+static const char* const dns_ede_rcode_table[_DNS_EDE_RCODE_MAX_DEFINED] = {
+ [DNS_EDE_RCODE_OTHER] = "Other",
+ [DNS_EDE_RCODE_UNSUPPORTED_DNSKEY_ALG] = "Unsupported DNSKEY Algorithm",
+ [DNS_EDE_RCODE_UNSUPPORTED_DS_DIGEST] = "Unsupported DS Digest Type",
+ [DNS_EDE_RCODE_STALE_ANSWER] = "Stale Answer",
+ [DNS_EDE_RCODE_FORGED_ANSWER] = "Forged Answer",
+ [DNS_EDE_RCODE_DNSSEC_INDETERMINATE] = "DNSSEC Indeterminate",
+ [DNS_EDE_RCODE_DNSSEC_BOGUS] = "DNSSEC Bogus",
+ [DNS_EDE_RCODE_SIG_EXPIRED] = "Signature Expired",
+ [DNS_EDE_RCODE_SIG_NOT_YET_VALID] = "Signature Not Yet Valid",
+ [DNS_EDE_RCODE_DNSKEY_MISSING] = "DNSKEY Missing",
+ [DNS_EDE_RCODE_RRSIG_MISSING] = "RRSIG Missing",
+ [DNS_EDE_RCODE_NO_ZONE_KEY_BIT] = "No Zone Key Bit Set",
+ [DNS_EDE_RCODE_NSEC_MISSING] = "NSEC Missing",
+ [DNS_EDE_RCODE_CACHED_ERROR] = "Cached Error",
+ [DNS_EDE_RCODE_NOT_READY] = "Not Ready",
+ [DNS_EDE_RCODE_BLOCKED] = "Blocked",
+ [DNS_EDE_RCODE_CENSORED] = "Censored",
+ [DNS_EDE_RCODE_FILTERED] = "Filtered",
+ [DNS_EDE_RCODE_PROHIBITIED] = "Prohibited",
+ [DNS_EDE_RCODE_STALE_NXDOMAIN_ANSWER] = "Stale NXDOMAIN Answer",
+ [DNS_EDE_RCODE_NOT_AUTHORITATIVE] = "Not Authoritative",
+ [DNS_EDE_RCODE_NOT_SUPPORTED] = "Not Supported",
+ [DNS_EDE_RCODE_UNREACH_AUTHORITY] = "No Reachable Authority",
+ [DNS_EDE_RCODE_NET_ERROR] = "Network Error",
+ [DNS_EDE_RCODE_INVALID_DATA] = "Invalid Data",
+ [DNS_EDE_RCODE_SIG_NEVER] = "Signature Never Valid",
+ [DNS_EDE_RCODE_TOO_EARLY] = "Too Early",
+ [DNS_EDE_RCODE_UNSUPPORTED_NSEC3_ITER] = "Unsupported NSEC3 Iterations",
+ [DNS_EDE_RCODE_TRANSPORT_POLICY] = "Impossible Transport Policy",
+ [DNS_EDE_RCODE_SYNTHESIZED] = "Synthesized",
+};
+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);
+ if (p)
+ return p;
+
+ return snprintf_ok(buf, DECIMAL_STR_MAX(int), "%i", i);
+}
+
+static const char* const dns_svc_param_key_table[_DNS_SVC_PARAM_KEY_MAX_DEFINED] = {
+ [DNS_SVC_PARAM_KEY_MANDATORY] = "mandatory",
+ [DNS_SVC_PARAM_KEY_ALPN] = "alpn",
+ [DNS_SVC_PARAM_KEY_NO_DEFAULT_ALPN] = "no-default-alpn",
+ [DNS_SVC_PARAM_KEY_PORT] = "port",
+ [DNS_SVC_PARAM_KEY_IPV4HINT] = "ipv4hint",
+ [DNS_SVC_PARAM_KEY_ECH] = "ech",
+ [DNS_SVC_PARAM_KEY_IPV6HINT] = "ipv6hint",
+ [DNS_SVC_PARAM_KEY_DOHPATH] = "dohpath",
+ [DNS_SVC_PARAM_KEY_OHTTP] = "ohttp",
+};
+DEFINE_STRING_TABLE_LOOKUP_TO_STRING(dns_svc_param_key, int);
+
+const char *format_dns_svc_param_key(uint16_t i, char buf[static DECIMAL_STR_MAX(uint16_t)+3]) {
+ const char *p = dns_svc_param_key_to_string(i);
+ if (p)
+ return p;
+
+ return snprintf_ok(buf, DECIMAL_STR_MAX(uint16_t)+3, "key%i", i);
+}
+
static const char* const dns_protocol_table[_DNS_PROTOCOL_MAX] = {
[DNS_PROTOCOL_DNS] = "dns",
[DNS_PROTOCOL_MDNS] = "mdns",