diff options
Diffstat (limited to 'src/resolve/resolved-dns-rr.c')
-rw-r--r-- | src/resolve/resolved-dns-rr.c | 435 |
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(¶ms, 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; |