From: Ronan Pigott Date: Fri, 29 Dec 2023 18:30:18 +0000 (-0700) Subject: resolvectl: implement SVCB and HTTPS presentation format X-Git-Tag: v256-rc1~1119^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f0d261a714b7ee1e94fcb3e15533fc618149f522;p=thirdparty%2Fsystemd.git resolvectl: implement SVCB and HTTPS presentation format --- diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c index 3b0fece1775..3dfb5c0d8d6 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; @@ -826,6 +827,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]; @@ -1136,6 +1238,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)