summaryrefslogtreecommitdiffstats
path: root/src/resolve/resolved-dns-rr.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-12 03:50:42 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-12 03:50:42 +0000
commit78e9bb837c258ac0ec7712b3d612cc2f407e731e (patch)
treef515d16b6efd858a9aeb5b0ef5d6f90bf288283d /src/resolve/resolved-dns-rr.c
parentAdding debian version 255.5-1. (diff)
downloadsystemd-78e9bb837c258ac0ec7712b3d612cc2f407e731e.tar.xz
systemd-78e9bb837c258ac0ec7712b3d612cc2f407e731e.zip
Merging upstream version 256.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/resolve/resolved-dns-rr.c')
-rw-r--r--src/resolve/resolved-dns-rr.c435
1 files changed, 378 insertions, 57 deletions
diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c
index b280a5a..204d4a6 100644
--- a/src/resolve/resolved-dns-rr.c
+++ b/src/resolve/resolved-dns-rr.c
@@ -15,6 +15,7 @@
#include "string-util.h"
#include "strv.h"
#include "terminal-util.h"
+#include "unaligned.h"
DnsResourceKey* dns_resource_key_new(uint16_t class, uint16_t type, const char *name) {
DnsResourceKey *k;
@@ -195,7 +196,7 @@ bool dns_resource_key_is_dnssd_two_label_ptr(const DnsResourceKey *key) {
if (dns_name_parent(&name) <= 0)
return false;
- return dns_name_equal(name, "_tcp.local") || dns_name_equal(name, "_udp.local");
+ return dns_name_equal(name, "_tcp.local") > 0 || dns_name_equal(name, "_udp.local") > 0;
}
int dns_resource_key_equal(const DnsResourceKey *a, const DnsResourceKey *b) {
@@ -310,8 +311,8 @@ static void dns_resource_key_hash_func(const DnsResourceKey *k, struct siphash *
assert(k);
dns_name_hash_func(dns_resource_key_name(k), state);
- siphash24_compress(&k->class, sizeof(k->class), state);
- siphash24_compress(&k->type, sizeof(k->type), state);
+ siphash24_compress_typesafe(k->class, state);
+ siphash24_compress_typesafe(k->type, state);
}
static int dns_resource_key_compare_func(const DnsResourceKey *x, const DnsResourceKey *y) {
@@ -486,11 +487,24 @@ static DnsResourceRecord* dns_resource_record_free(DnsResourceRecord *rr) {
free(rr->tlsa.data);
break;
+ case DNS_TYPE_SVCB:
+ case DNS_TYPE_HTTPS:
+ free(rr->svcb.target_name);
+ dns_svc_param_free_all(rr->svcb.params);
+ break;
+
case DNS_TYPE_CAA:
free(rr->caa.tag);
free(rr->caa.value);
break;
+ case DNS_TYPE_NAPTR:
+ free(rr->naptr.flags);
+ free(rr->naptr.services);
+ free(rr->naptr.regexp);
+ free(rr->naptr.replacement);
+ break;
+
case DNS_TYPE_OPENPGPKEY:
default:
if (!rr->unparsable)
@@ -665,19 +679,24 @@ int dns_resource_record_payload_equal(const DnsResourceRecord *a, const DnsResou
case DNS_TYPE_RRSIG:
/* do the fast comparisons first */
- return a->rrsig.type_covered == b->rrsig.type_covered &&
- a->rrsig.algorithm == b->rrsig.algorithm &&
- a->rrsig.labels == b->rrsig.labels &&
- a->rrsig.original_ttl == b->rrsig.original_ttl &&
- a->rrsig.expiration == b->rrsig.expiration &&
- a->rrsig.inception == b->rrsig.inception &&
- a->rrsig.key_tag == b->rrsig.key_tag &&
- FIELD_EQUAL(a->rrsig, b->rrsig, signature) &&
- dns_name_equal(a->rrsig.signer, b->rrsig.signer);
+ if (!(a->rrsig.type_covered == b->rrsig.type_covered &&
+ a->rrsig.algorithm == b->rrsig.algorithm &&
+ a->rrsig.labels == b->rrsig.labels &&
+ a->rrsig.original_ttl == b->rrsig.original_ttl &&
+ a->rrsig.expiration == b->rrsig.expiration &&
+ a->rrsig.inception == b->rrsig.inception &&
+ a->rrsig.key_tag == b->rrsig.key_tag &&
+ FIELD_EQUAL(a->rrsig, b->rrsig, signature)))
+ return false;
+
+ return dns_name_equal(a->rrsig.signer, b->rrsig.signer);
case DNS_TYPE_NSEC:
- return dns_name_equal(a->nsec.next_domain_name, b->nsec.next_domain_name) &&
- bitmap_equal(a->nsec.types, b->nsec.types);
+ r = dns_name_equal(a->nsec.next_domain_name, b->nsec.next_domain_name);
+ if (r <= 0)
+ return r;
+
+ return bitmap_equal(a->nsec.types, b->nsec.types);
case DNS_TYPE_NSEC3:
return a->nsec3.algorithm == b->nsec3.algorithm &&
@@ -693,11 +712,31 @@ int dns_resource_record_payload_equal(const DnsResourceRecord *a, const DnsResou
a->tlsa.matching_type == b->tlsa.matching_type &&
FIELD_EQUAL(a->tlsa, b->tlsa, data);
+ case DNS_TYPE_SVCB:
+ case DNS_TYPE_HTTPS:
+
+ if (!(a->svcb.priority == b->svcb.priority &&
+ dns_svc_params_equal(a->svcb.params, b->svcb.params)))
+ return false;
+
+ return dns_name_equal(a->svcb.target_name, b->svcb.target_name);
+
case DNS_TYPE_CAA:
return a->caa.flags == b->caa.flags &&
streq(a->caa.tag, b->caa.tag) &&
FIELD_EQUAL(a->caa, b->caa, value);
+ case DNS_TYPE_NAPTR:
+ r = dns_name_equal(a->naptr.replacement, b->naptr.replacement);
+ if (r <= 0)
+ return r;
+
+ return a->naptr.order == b->naptr.order &&
+ a->naptr.preference == b->naptr.preference &&
+ streq(a->naptr.flags, b->naptr.flags) &&
+ streq(a->naptr.services, b->naptr.services) &&
+ streq(a->naptr.regexp, b->naptr.regexp);
+
case DNS_TYPE_OPENPGPKEY:
default:
return FIELD_EQUAL(a->generic, b->generic, data);
@@ -831,6 +870,107 @@ static char *format_txt(DnsTxtItem *first) {
return s;
}
+static char *format_svc_param_value(DnsSvcParam *i) {
+ _cleanup_free_ char *value = NULL;
+
+ assert(i);
+
+ switch (i->key) {
+ case DNS_SVC_PARAM_KEY_ALPN: {
+ size_t offset = 0;
+ _cleanup_strv_free_ char **values_strv = NULL;
+ while (offset < i->length) {
+ size_t sz = (uint8_t) i->value[offset++];
+
+ char *alpn = cescape_length((char *)&i->value[offset], sz);
+ if (!alpn)
+ return NULL;
+
+ if (strv_push(&values_strv, alpn) < 0)
+ return NULL;
+
+ offset += sz;
+ }
+ value = strv_join(values_strv, ",");
+ if (!value)
+ return NULL;
+ break;
+
+ }
+ case DNS_SVC_PARAM_KEY_PORT: {
+ uint16_t port = unaligned_read_be16(i->value);
+ if (asprintf(&value, "%" PRIu16, port) < 0)
+ return NULL;
+ return TAKE_PTR(value);
+ }
+ case DNS_SVC_PARAM_KEY_IPV4HINT: {
+ const struct in_addr *addrs = i->value_in_addr;
+ _cleanup_strv_free_ char **values_strv = NULL;
+ for (size_t n = 0; n < i->length / sizeof (struct in_addr); n++) {
+ char *addr;
+ if (in_addr_to_string(AF_INET, (const union in_addr_union*) &addrs[n], &addr) < 0)
+ return NULL;
+ if (strv_push(&values_strv, addr) < 0)
+ return NULL;
+ }
+ return strv_join(values_strv, ",");
+ }
+ case DNS_SVC_PARAM_KEY_IPV6HINT: {
+ const struct in6_addr *addrs = i->value_in6_addr;
+ _cleanup_strv_free_ char **values_strv = NULL;
+ for (size_t n = 0; n < i->length / sizeof (struct in6_addr); n++) {
+ char *addr;
+ if (in_addr_to_string(AF_INET6, (const union in_addr_union*) &addrs[n], &addr) < 0)
+ return NULL;
+ if (strv_push(&values_strv, addr) < 0)
+ return NULL;
+ }
+ return strv_join(values_strv, ",");
+ }
+ default: {
+ value = decescape((char *)&i->value, " ,", i->length);
+ if (!value)
+ return NULL;
+ break;
+ }
+ }
+
+ char *qvalue;
+ if (asprintf(&qvalue, "\"%s\"", value) < 0)
+ return NULL;
+ return qvalue;
+}
+
+static char *format_svc_param(DnsSvcParam *i) {
+ const char *key = FORMAT_DNS_SVC_PARAM_KEY(i->key);
+ _cleanup_free_ char *value = NULL;
+
+ assert(i);
+
+ if (i->length == 0)
+ return strdup(key);
+
+ value = format_svc_param_value(i);
+ if (!value)
+ return NULL;
+
+ return strjoin(key, "=", value);
+}
+
+static char *format_svc_params(DnsSvcParam *first) {
+ _cleanup_strv_free_ char **params = NULL;
+
+ LIST_FOREACH(params, i, first) {
+ char *param = format_svc_param(i);
+ if (!param)
+ return NULL;
+ if (strv_push(&params, param) < 0)
+ return NULL;
+ }
+
+ return strv_join(params, " ");
+}
+
const char *dns_resource_record_to_string(DnsResourceRecord *rr) {
_cleanup_free_ char *s = NULL, *t = NULL;
char k[DNS_RESOURCE_KEY_STRING_MAX];
@@ -1141,6 +1281,19 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) {
break;
+ case DNS_TYPE_SVCB:
+ case DNS_TYPE_HTTPS:
+ t = format_svc_params(rr->svcb.params);
+ if (!t)
+ return NULL;
+ r = asprintf(&s, "%s %d %s %s", k, rr->svcb.priority,
+ isempty(rr->svcb.target_name) ? "." : rr->svcb.target_name,
+ t);
+ if (r < 0)
+ return NULL;
+
+ break;
+
case DNS_TYPE_OPENPGPKEY:
r = asprintf(&s, "%s", k);
if (r < 0)
@@ -1153,6 +1306,31 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) {
return NULL;
break;
+ case DNS_TYPE_NAPTR: {
+ _cleanup_free_ char *tt = NULL, *ttt = NULL;
+
+ t = octescape(rr->naptr.flags, SIZE_MAX);
+ if (!t)
+ return NULL;
+
+ tt = octescape(rr->naptr.services, SIZE_MAX);
+ if (!tt)
+ return NULL;
+
+ ttt = octescape(rr->naptr.regexp, SIZE_MAX);
+ if (!ttt)
+ return NULL;
+
+ if (asprintf(&s, "%" PRIu16 " %" PRIu16 " \"%s\" \"%s\" \"%s\" %s.",
+ rr->naptr.order,
+ rr->naptr.preference,
+ t,
+ tt,
+ ttt,
+ rr->naptr.replacement) < 0)
+ return NULL;
+ break;
+ }
default:
/* Format as documented in RFC 3597, Section 5 */
if (rr->generic.data_size == 0)
@@ -1344,9 +1522,9 @@ void dns_resource_record_hash_func(const DnsResourceRecord *rr, struct siphash *
switch (rr->unparsable ? _DNS_TYPE_INVALID : rr->key->type) {
case DNS_TYPE_SRV:
- siphash24_compress(&rr->srv.priority, sizeof(rr->srv.priority), state);
- siphash24_compress(&rr->srv.weight, sizeof(rr->srv.weight), state);
- siphash24_compress(&rr->srv.port, sizeof(rr->srv.port), state);
+ siphash24_compress_typesafe(rr->srv.priority, state);
+ siphash24_compress_typesafe(rr->srv.weight, state);
+ siphash24_compress_typesafe(rr->srv.port, state);
dns_name_hash_func(rr->srv.name, state);
break;
@@ -1375,59 +1553,59 @@ void dns_resource_record_hash_func(const DnsResourceRecord *rr, struct siphash *
}
case DNS_TYPE_A:
- siphash24_compress(&rr->a.in_addr, sizeof(rr->a.in_addr), state);
+ siphash24_compress_typesafe(rr->a.in_addr, state);
break;
case DNS_TYPE_AAAA:
- siphash24_compress(&rr->aaaa.in6_addr, sizeof(rr->aaaa.in6_addr), state);
+ siphash24_compress_typesafe(rr->aaaa.in6_addr, state);
break;
case DNS_TYPE_SOA:
dns_name_hash_func(rr->soa.mname, state);
dns_name_hash_func(rr->soa.rname, state);
- siphash24_compress(&rr->soa.serial, sizeof(rr->soa.serial), state);
- siphash24_compress(&rr->soa.refresh, sizeof(rr->soa.refresh), state);
- siphash24_compress(&rr->soa.retry, sizeof(rr->soa.retry), state);
- siphash24_compress(&rr->soa.expire, sizeof(rr->soa.expire), state);
- siphash24_compress(&rr->soa.minimum, sizeof(rr->soa.minimum), state);
+ siphash24_compress_typesafe(rr->soa.serial, state);
+ siphash24_compress_typesafe(rr->soa.refresh, state);
+ siphash24_compress_typesafe(rr->soa.retry, state);
+ siphash24_compress_typesafe(rr->soa.expire, state);
+ siphash24_compress_typesafe(rr->soa.minimum, state);
break;
case DNS_TYPE_MX:
- siphash24_compress(&rr->mx.priority, sizeof(rr->mx.priority), state);
+ siphash24_compress_typesafe(rr->mx.priority, state);
dns_name_hash_func(rr->mx.exchange, state);
break;
case DNS_TYPE_LOC:
- siphash24_compress(&rr->loc.version, sizeof(rr->loc.version), state);
- siphash24_compress(&rr->loc.size, sizeof(rr->loc.size), state);
- siphash24_compress(&rr->loc.horiz_pre, sizeof(rr->loc.horiz_pre), state);
- siphash24_compress(&rr->loc.vert_pre, sizeof(rr->loc.vert_pre), state);
- siphash24_compress(&rr->loc.latitude, sizeof(rr->loc.latitude), state);
- siphash24_compress(&rr->loc.longitude, sizeof(rr->loc.longitude), state);
- siphash24_compress(&rr->loc.altitude, sizeof(rr->loc.altitude), state);
+ siphash24_compress_typesafe(rr->loc.version, state);
+ siphash24_compress_typesafe(rr->loc.size, state);
+ siphash24_compress_typesafe(rr->loc.horiz_pre, state);
+ siphash24_compress_typesafe(rr->loc.vert_pre, state);
+ siphash24_compress_typesafe(rr->loc.latitude, state);
+ siphash24_compress_typesafe(rr->loc.longitude, state);
+ siphash24_compress_typesafe(rr->loc.altitude, state);
break;
case DNS_TYPE_SSHFP:
- siphash24_compress(&rr->sshfp.algorithm, sizeof(rr->sshfp.algorithm), state);
- siphash24_compress(&rr->sshfp.fptype, sizeof(rr->sshfp.fptype), state);
+ siphash24_compress_typesafe(rr->sshfp.algorithm, state);
+ siphash24_compress_typesafe(rr->sshfp.fptype, state);
siphash24_compress_safe(rr->sshfp.fingerprint, rr->sshfp.fingerprint_size, state);
break;
case DNS_TYPE_DNSKEY:
- siphash24_compress(&rr->dnskey.flags, sizeof(rr->dnskey.flags), state);
- siphash24_compress(&rr->dnskey.protocol, sizeof(rr->dnskey.protocol), state);
- siphash24_compress(&rr->dnskey.algorithm, sizeof(rr->dnskey.algorithm), state);
+ siphash24_compress_typesafe(rr->dnskey.flags, state);
+ siphash24_compress_typesafe(rr->dnskey.protocol, state);
+ siphash24_compress_typesafe(rr->dnskey.algorithm, state);
siphash24_compress_safe(rr->dnskey.key, rr->dnskey.key_size, state);
break;
case DNS_TYPE_RRSIG:
- siphash24_compress(&rr->rrsig.type_covered, sizeof(rr->rrsig.type_covered), state);
- siphash24_compress(&rr->rrsig.algorithm, sizeof(rr->rrsig.algorithm), state);
- siphash24_compress(&rr->rrsig.labels, sizeof(rr->rrsig.labels), state);
- siphash24_compress(&rr->rrsig.original_ttl, sizeof(rr->rrsig.original_ttl), state);
- siphash24_compress(&rr->rrsig.expiration, sizeof(rr->rrsig.expiration), state);
- siphash24_compress(&rr->rrsig.inception, sizeof(rr->rrsig.inception), state);
- siphash24_compress(&rr->rrsig.key_tag, sizeof(rr->rrsig.key_tag), state);
+ siphash24_compress_typesafe(rr->rrsig.type_covered, state);
+ siphash24_compress_typesafe(rr->rrsig.algorithm, state);
+ siphash24_compress_typesafe(rr->rrsig.labels, state);
+ siphash24_compress_typesafe(rr->rrsig.original_ttl, state);
+ siphash24_compress_typesafe(rr->rrsig.expiration, state);
+ siphash24_compress_typesafe(rr->rrsig.inception, state);
+ siphash24_compress_typesafe(rr->rrsig.key_tag, state);
dns_name_hash_func(rr->rrsig.signer, state);
siphash24_compress_safe(rr->rrsig.signature, rr->rrsig.signature_size, state);
break;
@@ -1440,34 +1618,53 @@ void dns_resource_record_hash_func(const DnsResourceRecord *rr, struct siphash *
break;
case DNS_TYPE_DS:
- siphash24_compress(&rr->ds.key_tag, sizeof(rr->ds.key_tag), state);
- siphash24_compress(&rr->ds.algorithm, sizeof(rr->ds.algorithm), state);
- siphash24_compress(&rr->ds.digest_type, sizeof(rr->ds.digest_type), state);
+ siphash24_compress_typesafe(rr->ds.key_tag, state);
+ siphash24_compress_typesafe(rr->ds.algorithm, state);
+ siphash24_compress_typesafe(rr->ds.digest_type, state);
siphash24_compress_safe(rr->ds.digest, rr->ds.digest_size, state);
break;
case DNS_TYPE_NSEC3:
- siphash24_compress(&rr->nsec3.algorithm, sizeof(rr->nsec3.algorithm), state);
- siphash24_compress(&rr->nsec3.flags, sizeof(rr->nsec3.flags), state);
- siphash24_compress(&rr->nsec3.iterations, sizeof(rr->nsec3.iterations), state);
+ siphash24_compress_typesafe(rr->nsec3.algorithm, state);
+ siphash24_compress_typesafe(rr->nsec3.flags, state);
+ siphash24_compress_typesafe(rr->nsec3.iterations, state);
siphash24_compress_safe(rr->nsec3.salt, rr->nsec3.salt_size, state);
siphash24_compress_safe(rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size, state);
/* FIXME: We leave the bitmaps out */
break;
case DNS_TYPE_TLSA:
- siphash24_compress(&rr->tlsa.cert_usage, sizeof(rr->tlsa.cert_usage), state);
- siphash24_compress(&rr->tlsa.selector, sizeof(rr->tlsa.selector), state);
- siphash24_compress(&rr->tlsa.matching_type, sizeof(rr->tlsa.matching_type), state);
+ siphash24_compress_typesafe(rr->tlsa.cert_usage, state);
+ siphash24_compress_typesafe(rr->tlsa.selector, state);
+ siphash24_compress_typesafe(rr->tlsa.matching_type, state);
siphash24_compress_safe(rr->tlsa.data, rr->tlsa.data_size, state);
break;
+ case DNS_TYPE_SVCB:
+ case DNS_TYPE_HTTPS:
+ dns_name_hash_func(rr->svcb.target_name, state);
+ siphash24_compress_typesafe(rr->svcb.priority, state);
+ LIST_FOREACH(params, j, rr->svcb.params) {
+ siphash24_compress_typesafe(j->key, state);
+ siphash24_compress_safe(j->value, j->length, state);
+ }
+ break;
+
case DNS_TYPE_CAA:
- siphash24_compress(&rr->caa.flags, sizeof(rr->caa.flags), state);
+ siphash24_compress_typesafe(rr->caa.flags, state);
string_hash_func(rr->caa.tag, state);
siphash24_compress_safe(rr->caa.value, rr->caa.value_size, state);
break;
+ case DNS_TYPE_NAPTR:
+ siphash24_compress_typesafe(rr->naptr.order, state);
+ siphash24_compress_typesafe(rr->naptr.preference, state);
+ string_hash_func(rr->naptr.flags, state);
+ string_hash_func(rr->naptr.services, state);
+ string_hash_func(rr->naptr.regexp, state);
+ dns_name_hash_func(rr->naptr.replacement, state);
+ break;
+
case DNS_TYPE_OPENPGPKEY:
default:
siphash24_compress_safe(rr->generic.data, rr->generic.data_size, state);
@@ -1675,6 +1872,34 @@ DnsResourceRecord *dns_resource_record_copy(DnsResourceRecord *rr) {
copy->caa.value_size = rr->caa.value_size;
break;
+ case DNS_TYPE_SVCB:
+ case DNS_TYPE_HTTPS:
+ copy->svcb.priority = rr->svcb.priority;
+ copy->svcb.target_name = strdup(rr->svcb.target_name);
+ if (!copy->svcb.target_name)
+ return NULL;
+ copy->svcb.params = dns_svc_params_copy(rr->svcb.params);
+ if (rr->svcb.params && !copy->svcb.params)
+ return NULL;
+ break;
+
+ case DNS_TYPE_NAPTR:
+ copy->naptr.order = rr->naptr.order;
+ copy->naptr.preference = rr->naptr.preference;
+ copy->naptr.flags = strdup(rr->naptr.flags);
+ if (!copy->naptr.flags)
+ return NULL;
+ copy->naptr.services = strdup(rr->naptr.services);
+ if (!copy->naptr.services)
+ return NULL;
+ copy->naptr.regexp = strdup(rr->naptr.regexp);
+ if (!copy->naptr.regexp)
+ return NULL;
+ copy->naptr.replacement = strdup(rr->naptr.replacement);
+ if (!copy->naptr.replacement)
+ return NULL;
+ break;
+
case DNS_TYPE_OPT:
default:
copy->generic.data = memdup(rr->generic.data, rr->generic.data_size);
@@ -1789,6 +2014,13 @@ DnsTxtItem *dns_txt_item_free_all(DnsTxtItem *first) {
return NULL;
}
+DnsSvcParam *dns_svc_param_free_all(DnsSvcParam *first) {
+ LIST_FOREACH(params, i, first)
+ free(i);
+
+ return NULL;
+}
+
bool dns_txt_item_equal(DnsTxtItem *a, DnsTxtItem *b) {
DnsTxtItem *bb = b;
@@ -1825,6 +2057,45 @@ DnsTxtItem *dns_txt_item_copy(DnsTxtItem *first) {
return copy;
}
+bool dns_svc_params_equal(DnsSvcParam *a, DnsSvcParam *b) {
+ DnsSvcParam *bb = b;
+
+ if (a == b)
+ return true;
+
+ LIST_FOREACH(params, aa, a) {
+ if (!bb)
+ return false;
+
+ if (aa->key != bb->key)
+ return false;
+
+ if (memcmp_nn(aa->value, aa->length, bb->value, bb->length) != 0)
+ return false;
+
+ bb = bb->params_next;
+ }
+
+ return !bb;
+}
+
+DnsSvcParam *dns_svc_params_copy(DnsSvcParam *first) {
+ DnsSvcParam *copy = NULL, *end = NULL;
+
+ LIST_FOREACH(params, i, first) {
+ DnsSvcParam *j;
+
+ j = memdup(i, offsetof(DnsSvcParam, value) + i->length);
+ if (!j)
+ return dns_svc_param_free_all(copy);
+
+ LIST_INSERT_AFTER(params, copy, end, j);
+ end = j;
+ }
+
+ return copy;
+}
+
int dns_txt_item_new_empty(DnsTxtItem **ret) {
DnsTxtItem *i;
@@ -1947,10 +2218,33 @@ static int txt_to_json(DnsTxtItem *items, JsonVariant **ret) {
r = json_variant_new_array(ret, elements, n);
finalize:
- for (size_t i = 0; i < n; i++)
- json_variant_unref(elements[i]);
+ json_variant_unref_many(elements, n);
+ return r;
+}
+
+static int svc_params_to_json(DnsSvcParam *params, JsonVariant **ret) {
+ JsonVariant **elements = NULL;
+ size_t n = 0;
+ int r;
+
+ assert(ret);
+
+ LIST_FOREACH(params, i, params) {
+ if (!GREEDY_REALLOC(elements, n + 1)) {
+ r = -ENOMEM;
+ goto finalize;
+ }
- free(elements);
+ r = json_variant_new_base64(elements + n, i->value, i->length);
+ if (r < 0)
+ goto finalize;
+
+ n++;
+ }
+
+ r = json_variant_new_array(ret, elements, n);
+finalize:
+ json_variant_unref_many(elements, n);
return r;
}
@@ -2129,6 +2423,21 @@ int dns_resource_record_to_json(DnsResourceRecord *rr, JsonVariant **ret) {
JSON_BUILD_PAIR("matchingType", JSON_BUILD_UNSIGNED(rr->tlsa.matching_type)),
JSON_BUILD_PAIR("data", JSON_BUILD_HEX(rr->tlsa.data, rr->tlsa.data_size))));
+ case DNS_TYPE_SVCB:
+ case DNS_TYPE_HTTPS: {
+ _cleanup_(json_variant_unrefp) JsonVariant *p = NULL;
+ r = svc_params_to_json(rr->svcb.params, &p);
+ if (r < 0)
+ return r;
+
+ return json_build(ret,
+ JSON_BUILD_OBJECT(
+ JSON_BUILD_PAIR("key", JSON_BUILD_VARIANT(k)),
+ JSON_BUILD_PAIR("priority", JSON_BUILD_UNSIGNED(rr->svcb.priority)),
+ JSON_BUILD_PAIR("target", JSON_BUILD_STRING(rr->svcb.target_name)),
+ JSON_BUILD_PAIR("params", JSON_BUILD_VARIANT(p))));
+ }
+
case DNS_TYPE_CAA:
return json_build(ret,
JSON_BUILD_OBJECT(
@@ -2137,6 +2446,18 @@ int dns_resource_record_to_json(DnsResourceRecord *rr, JsonVariant **ret) {
JSON_BUILD_PAIR("tag", JSON_BUILD_STRING(rr->caa.tag)),
JSON_BUILD_PAIR("value", JSON_BUILD_OCTESCAPE(rr->caa.value, rr->caa.value_size))));
+ case DNS_TYPE_NAPTR:
+ return json_build(ret,
+ JSON_BUILD_OBJECT(
+ JSON_BUILD_PAIR("key", JSON_BUILD_VARIANT(k)),
+ JSON_BUILD_PAIR("order", JSON_BUILD_UNSIGNED(rr->naptr.order)),
+ JSON_BUILD_PAIR("preference", JSON_BUILD_UNSIGNED(rr->naptr.preference)),
+ /* NB: we name this flags field here naptrFlags, because there's already another "flags" field (for example in CAA) which has a different type */
+ JSON_BUILD_PAIR("naptrFlags", JSON_BUILD_STRING(rr->naptr.flags)),
+ JSON_BUILD_PAIR("services", JSON_BUILD_STRING(rr->naptr.services)),
+ JSON_BUILD_PAIR("regexp", JSON_BUILD_STRING(rr->naptr.regexp)),
+ JSON_BUILD_PAIR("replacement", JSON_BUILD_STRING(rr->naptr.replacement))));
+
default:
/* Can't provide broken-down format */
*ret = NULL;