]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
resolvectl: implement SVCB and HTTPS presentation format
authorRonan Pigott <ronan@rjp.ie>
Fri, 29 Dec 2023 18:30:18 +0000 (11:30 -0700)
committerRonan Pigott <ronan@rjp.ie>
Tue, 16 Jan 2024 18:26:37 +0000 (11:26 -0700)
src/resolve/resolved-dns-rr.c

index 3b0fece1775c51df2aa11d820696c0719163b65b..3dfb5c0d8d68af168a9275e64dcc9d60c834dbda 100644 (file)
@@ -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(&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];
@@ -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)