]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
resolve: several follow-ups for resolving service via varlink
authorYu Watanabe <watanabe.yu+github@gmail.com>
Sat, 17 Feb 2024 21:50:39 +0000 (06:50 +0900)
committerLennart Poettering <lennart@poettering.net>
Mon, 19 Feb 2024 21:13:07 +0000 (22:13 +0100)
Follow-ups for e1634bb8321c5534a8e5d16b474c7e9d43ef3baa.

- Allow to call the method without "name" and "type".
- Allow to specify SD_RESOLVE_NO_TXT and SD_RESOLVE_NO_ADDRESS.
- Allow to provide multiple services, and fix memory leak.
- Rearrange the return value format.
- Encode TXT field with octescape() to make the field matches with the
  io.systemd.Resolve.Monitor interface.

Fixes #31371.

src/resolve/resolved-varlink.c
src/shared/varlink-io.systemd.Resolve.c
test/units/testsuite-75.sh

index 2f0971a7f0e1e8f130ce0101fd3dded1da44cbbd..a85a27867629d5865edaf3f4bc0aec9eb477fb0b 100644 (file)
@@ -23,7 +23,7 @@ typedef struct LookupParametersResolveService {
         const char *domain;
         int family;
         int ifindex;
-        uint64_t in_flags;
+        uint64_t flags;
 } LookupParametersResolveService;
 
 static void lookup_parameters_destroy(LookupParameters *p) {
@@ -577,7 +577,7 @@ static int append_txt(JsonVariant **txt, DnsResourceRecord *rr) {
                 if (i->length <= 0)
                         continue;
 
-                r = json_variant_new_base64(&entry, i->data, i->length);
+                r = json_variant_new_octescape(&entry, i->data, i->length);
                 if (r < 0)
                         return r;
 
@@ -589,20 +589,20 @@ static int append_txt(JsonVariant **txt, DnsResourceRecord *rr) {
         return 1;
 }
 
-static int append_srv(DnsQuery *q,
-                      JsonVariant **ret_srv,
-                      JsonVariant **ret_addr,
-                      char **ret_norm,
-                      DnsResourceRecord *rr) {
+static int append_srv(
+                DnsQuery *q,
+                DnsResourceRecord *rr,
+                JsonVariant **array) {
+
         _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *canonical = NULL;
+        _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
         _cleanup_free_ char *normalized = NULL;
-        _cleanup_(json_variant_unrefp) JsonVariant *srv = NULL, *addr = NULL;
-
         int r;
 
         assert(q);
         assert(rr);
         assert(rr->key);
+        assert(array);
 
         if (rr->key->type != DNS_TYPE_SRV)
                 return 0;
@@ -651,7 +651,7 @@ static int append_srv(DnsQuery *q,
         if (r < 0)
                 return r;
 
-        r = json_build(&srv,
+        r = json_build(&v,
                        JSON_BUILD_OBJECT(
                                         JSON_BUILD_PAIR("priority", JSON_BUILD_UNSIGNED(rr->srv.priority)),
                                         JSON_BUILD_PAIR("weight", JSON_BUILD_UNSIGNED(rr->srv.weight)),
@@ -660,7 +660,21 @@ static int append_srv(DnsQuery *q,
         if (r < 0)
                 return r;
 
+        if (canonical) {
+                normalized = mfree(normalized);
+
+                r = dns_name_normalize(dns_resource_key_name(canonical->key), 0, &normalized);
+                if (r < 0)
+                        return r;
+
+                r = json_variant_set_field_string(&v, "canonicalName", normalized);
+                if (r < 0)
+                        return r;
+        }
+
         if ((q->flags & SD_RESOLVED_NO_ADDRESS) == 0) {
+                _cleanup_(json_variant_unrefp) JsonVariant *addresses = NULL;
+
                 LIST_FOREACH(auxiliary_queries, aux, q->auxiliary_queries) {
                         DnsQuestion *question;
 
@@ -677,25 +691,21 @@ static int append_srv(DnsQuery *q,
                         if (r == 0)
                                 continue;
 
-                        r = find_addr_records(&addr, question, aux, NULL, NULL);
+                        r = find_addr_records(&addresses, question, aux, NULL, NULL);
                         if (r < 0)
                                 return r;
                 }
-        }
 
-        if (canonical) {
-                normalized = mfree(normalized);
-
-                r = dns_name_normalize(dns_resource_key_name(canonical->key), 0, &normalized);
+                r = json_variant_set_field(&v, "addresses", addresses);
                 if (r < 0)
                         return r;
         }
 
-        *ret_srv = TAKE_PTR(srv);
-        *ret_addr = TAKE_PTR(addr);
-        *ret_norm = TAKE_PTR(normalized);
+        r = json_variant_append_array(array, v);
+        if (r < 0)
+                return r;
 
-        return 1;
+        return 1; /* added */
 }
 
 static Varlink *get_vl_link_aux_query(DnsQuery *aux) {
@@ -710,12 +720,11 @@ static Varlink *get_vl_link_aux_query(DnsQuery *aux) {
 
 static void resolve_service_all_complete(DnsQuery *query) {
         _cleanup_(dns_query_freep) DnsQuery *q = query;
-        _cleanup_(json_variant_unrefp) JsonVariant *srv = NULL, *addr = NULL, *txt = NULL;
-        _cleanup_free_ char *name = NULL, *type = NULL, *domain = NULL, *norm = NULL;
+        _cleanup_(json_variant_unrefp) JsonVariant *srv = NULL, *txt = NULL;
+        _cleanup_free_ char *name = NULL, *type = NULL, *domain = NULL;
         _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *canonical = NULL;
         DnsQuestion *question;
         DnsResourceRecord *rr;
-        unsigned added = 0;
         int r;
 
         assert(q);
@@ -782,7 +791,7 @@ static void resolve_service_all_complete(DnsQuery *query) {
                 if (r == 0)
                         continue;
 
-                r = append_srv(q, &srv, &addr, &norm, rr);
+                r = append_srv(q, rr, &srv);
                 if (r < 0)
                         goto finish;
                 if (r == 0) /* not an SRV record */
@@ -790,11 +799,9 @@ static void resolve_service_all_complete(DnsQuery *query) {
 
                 if (!canonical)
                         canonical = dns_resource_record_ref(rr);
-
-                added++;
         }
 
-        if (added <= 0) {
+        if (json_variant_is_blank_object(srv)) {
                 r = varlink_error(query->varlink_request, "io.systemd.Resolve.NoSuchResourceRecord", NULL);
                 goto finish;
         }
@@ -820,14 +827,13 @@ static void resolve_service_all_complete(DnsQuery *query) {
                 goto finish;
 
         r = varlink_replyb(query->varlink_request, JSON_BUILD_OBJECT(
-                                        JSON_BUILD_PAIR("srv", JSON_BUILD_VARIANT(srv)),
-                                        JSON_BUILD_PAIR("addr", JSON_BUILD_VARIANT(addr)),
-                                        JSON_BUILD_PAIR("txt", JSON_BUILD_VARIANT(txt)),
-                                        JSON_BUILD_PAIR("normalized", JSON_BUILD_STRING(norm)),
+                                        JSON_BUILD_PAIR("services", JSON_BUILD_VARIANT(srv)),
+                                        JSON_BUILD_PAIR_CONDITION(!json_variant_is_blank_object(txt), "txt", JSON_BUILD_VARIANT(txt)),
                                         JSON_BUILD_PAIR("canonical", JSON_BUILD_OBJECT(
                                                                         JSON_BUILD_PAIR("name", JSON_BUILD_STRING(name)),
                                                                         JSON_BUILD_PAIR("type", JSON_BUILD_STRING(type)),
-                                                                        JSON_BUILD_PAIR("domain", JSON_BUILD_STRING(domain))))));
+                                                                        JSON_BUILD_PAIR("domain", JSON_BUILD_STRING(domain)))),
+                                        JSON_BUILD_PAIR("flags", JSON_BUILD_UNSIGNED(dns_query_reply_flags_make(query)))));
 
 finish:
         if (r < 0) {
@@ -983,12 +989,12 @@ finish:
 
 static int vl_method_resolve_service(Varlink* link, JsonVariant* parameters, VarlinkMethodFlags flags, void* userdata) {
         static const JsonDispatch dispatch_table[] = {
-                { "name",    JSON_VARIANT_STRING,   json_dispatch_const_string, offsetof(LookupParametersResolveService, name),     JSON_MANDATORY },
-                { "type",    JSON_VARIANT_STRING,   json_dispatch_const_string, offsetof(LookupParametersResolveService, type),     JSON_MANDATORY },
-                { "domain",  JSON_VARIANT_STRING,   json_dispatch_const_string, offsetof(LookupParametersResolveService, domain),   JSON_MANDATORY },
-                { "ifindex", JSON_VARIANT_UNSIGNED, json_dispatch_int,          offsetof(LookupParametersResolveService, ifindex),  0              },
-                { "family",  JSON_VARIANT_INTEGER,  json_dispatch_int,          offsetof(LookupParametersResolveService, family),   0              },
-                { "flags",   JSON_VARIANT_UNSIGNED, json_dispatch_uint64,       offsetof(LookupParametersResolveService, in_flags), 0              },
+                { "name",    JSON_VARIANT_STRING,        json_dispatch_const_string, offsetof(LookupParametersResolveService, name),    0              },
+                { "type",    JSON_VARIANT_STRING,        json_dispatch_const_string, offsetof(LookupParametersResolveService, type),    0              },
+                { "domain",  JSON_VARIANT_STRING,        json_dispatch_const_string, offsetof(LookupParametersResolveService, domain),  JSON_MANDATORY },
+                { "ifindex", _JSON_VARIANT_TYPE_INVALID, json_dispatch_int,          offsetof(LookupParametersResolveService, ifindex), 0              },
+                { "family",  _JSON_VARIANT_TYPE_INVALID, json_dispatch_int,          offsetof(LookupParametersResolveService, family),  0              },
+                { "flags",   _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64,       offsetof(LookupParametersResolveService, flags),   0              },
                 {}
         };
 
@@ -1035,18 +1041,21 @@ static int vl_method_resolve_service(Varlink* link, JsonVariant* parameters, Var
         if (r == 0)
                 return varlink_error_invalid_parameter(link, JSON_VARIANT_STRING_CONST("domain"));
 
-        if (!validate_and_mangle_flags(p.name, &p.in_flags, 0))
+        if (p.name && !p.type) /* Service name cannot be specified without service type. */
+                return varlink_error_invalid_parameter(link, JSON_VARIANT_STRING_CONST("type"));
+
+        if (!validate_and_mangle_flags(p.name, &p.flags, SD_RESOLVED_NO_TXT|SD_RESOLVED_NO_ADDRESS))
                 return varlink_error_invalid_parameter(link, JSON_VARIANT_STRING_CONST("flags"));
 
-        r = dns_question_new_service(&question_utf8, p.name, p.type, p.domain, !(p.in_flags & SD_RESOLVED_NO_TXT), false);
+        r = dns_question_new_service(&question_utf8, p.name, p.type, p.domain, !(p.flags & SD_RESOLVED_NO_TXT), false);
         if (r < 0)
                 return r;
 
-        r = dns_question_new_service(&question_idna, p.name, p.type, p.domain, !(p.in_flags & SD_RESOLVED_NO_TXT), true);
+        r = dns_question_new_service(&question_idna, p.name, p.type, p.domain, !(p.flags & SD_RESOLVED_NO_TXT), true);
         if (r < 0)
                 return r;
 
-        r = dns_query_new(m, &q, question_utf8, question_idna, NULL, p.ifindex, p.in_flags|SD_RESOLVED_NO_SEARCH);
+        r = dns_query_new(m, &q, question_utf8, question_idna, NULL, p.ifindex, p.flags|SD_RESOLVED_NO_SEARCH);
         if (r < 0)
                 return r;
 
index 88dad32b045f563a1c037e5e9df4b4472b9e7ba5..12111b240488aebf3ba9151d08bfdd938a9b33e5 100644 (file)
@@ -37,7 +37,9 @@ static VARLINK_DEFINE_STRUCT_TYPE(
                 VARLINK_DEFINE_FIELD(priority, VARLINK_INT, 0),
                 VARLINK_DEFINE_FIELD(weight, VARLINK_INT, 0),
                 VARLINK_DEFINE_FIELD(port, VARLINK_INT, 0),
-                VARLINK_DEFINE_FIELD(hostname, VARLINK_STRING, 0));
+                VARLINK_DEFINE_FIELD(hostname, VARLINK_STRING, 0),
+                VARLINK_DEFINE_FIELD(canonicalName, VARLINK_STRING, VARLINK_NULLABLE),
+                VARLINK_DEFINE_FIELD_BY_TYPE(addresses, ResolvedAddress, VARLINK_ARRAY|VARLINK_NULLABLE));
 
 static VARLINK_DEFINE_STRUCT_TYPE(
                 ResolvedCanonical,
@@ -47,17 +49,16 @@ static VARLINK_DEFINE_STRUCT_TYPE(
 
 static VARLINK_DEFINE_METHOD(
                 ResolveService,
-                VARLINK_DEFINE_INPUT(name, VARLINK_STRING, 0),
-                VARLINK_DEFINE_INPUT(type, VARLINK_STRING, 0),
+                VARLINK_DEFINE_INPUT(name, VARLINK_STRING, VARLINK_NULLABLE),
+                VARLINK_DEFINE_INPUT(type, VARLINK_STRING, VARLINK_NULLABLE),
                 VARLINK_DEFINE_INPUT(domain, VARLINK_STRING, 0),
                 VARLINK_DEFINE_INPUT(ifindex, VARLINK_INT, VARLINK_NULLABLE),
                 VARLINK_DEFINE_INPUT(family, VARLINK_INT, VARLINK_NULLABLE),
                 VARLINK_DEFINE_INPUT(flags, VARLINK_INT, VARLINK_NULLABLE),
-                VARLINK_DEFINE_OUTPUT_BY_TYPE(srv, ResolvedService, 0),
-                VARLINK_DEFINE_OUTPUT_BY_TYPE(addr, ResolvedAddress, VARLINK_ARRAY),
-                VARLINK_DEFINE_OUTPUT(txt, VARLINK_STRING, VARLINK_ARRAY),
-                VARLINK_DEFINE_OUTPUT(normalized, VARLINK_STRING, 0),
-                VARLINK_DEFINE_OUTPUT_BY_TYPE(canonical, ResolvedCanonical, 0));
+                VARLINK_DEFINE_OUTPUT_BY_TYPE(services, ResolvedService, VARLINK_ARRAY),
+                VARLINK_DEFINE_OUTPUT(txt, VARLINK_STRING, VARLINK_ARRAY|VARLINK_NULLABLE),
+                VARLINK_DEFINE_OUTPUT_BY_TYPE(canonical, ResolvedCanonical, 0),
+                VARLINK_DEFINE_OUTPUT(flags, VARLINK_INT, 0));
 
 static VARLINK_DEFINE_ERROR(NoNameServers);
 static VARLINK_DEFINE_ERROR(NoSuchResourceRecord);
index 4b7a8063253d2736c0ae568f786f8832b0dc2a17..b92ebf6b3319e283a154a6b12e3d4a38a2398f0d 100755 (executable)
@@ -437,14 +437,23 @@ grep -qF "authenticated: yes" "$RUN_OUT"
 
 # Test service resolve over Varlink
 run varlinkctl call /run/systemd/resolve/io.systemd.Resolve io.systemd.Resolve.ResolveService '{"name":"","type":"_mysvc._tcp","domain":"signed.test"}'
-grep -qF '"srv":{"priority":10,"weight":5,"port":1234,"hostname":"myservice.signed.test"}' "$RUN_OUT"
-grep -qF '"addr":[{"ifindex":' "$RUN_OUT"
+grep -qF '"services":[{"priority":10,"weight":5,"port":1234,"hostname":"myservice.signed.test","canonicalName":"myservice.signed.test","addresses":[{"ifindex":' "$RUN_OUT"
 grep -qF '"family":10,"address":[253,0,222,173,190,239,202,254,0,0,0,0,0,0,0,23]' "$RUN_OUT"
 grep -qF '"family":2,"address":[10,0,0,20]' "$RUN_OUT"
-grep -qF '"normalized":"myservice.signed.test"' "$RUN_OUT"
-grep -qF '"canonical":{"name":null,"type":"_mysvc._tcp","domain":"signed.test"}' "$RUN_OUT"
-TXT_OUT=$(grep -a -o -P '(?<=\"txt\"\:\[\").*(?=\"\])' "$RUN_OUT" | base64 --decode)
-assert_in "This is TXT for myservice" "$TXT_OUT"
+grep -qF '}]}],"txt":["This is TXT for myservice"],"canonical":{"name":null,"type":"_mysvc._tcp","domain":"signed.test"},"flags":' "$RUN_OUT"
+
+# without name
+run varlinkctl call /run/systemd/resolve/io.systemd.Resolve io.systemd.Resolve.ResolveService '{"type":"_mysvc._tcp","domain":"signed.test"}'
+# without txt (SD_RESOLVE_NO_TXT)
+run varlinkctl call /run/systemd/resolve/io.systemd.Resolve io.systemd.Resolve.ResolveService '{"type":"_mysvc._tcp","domain":"signed.test","flags":64}'
+(! grep -qF '"txt"' "$RUN_OUT")
+# without address (SD_RESOLVE_NO_ADDRESS)
+run varlinkctl call /run/systemd/resolve/io.systemd.Resolve io.systemd.Resolve.ResolveService '{"type":"_mysvc._tcp","domain":"signed.test","flags":128}'
+(! grep -qF '"addresses"' "$RUN_OUT")
+# without txt and address
+run varlinkctl call /run/systemd/resolve/io.systemd.Resolve io.systemd.Resolve.ResolveService '{"type":"_mysvc._tcp","domain":"signed.test","flags":192}'
+(! grep -qF '"txt"' "$RUN_OUT")
+(! grep -qF '"addresses"' "$RUN_OUT")
 
 (! run resolvectl service _invalidsvc._udp signed.test)
 grep -qE "invalidservice\.signed\.test' not found" "$RUN_OUT"