From e1634bb8321c5534a8e5d16b474c7e9d43ef3baa Mon Sep 17 00:00:00 2001 From: Vishal Chillara Srinivas Date: Wed, 15 Nov 2023 12:38:23 +0530 Subject: [PATCH] resolve: provide service resolve over varlink ported the d-bus implementation of service resolve to varlink extended TEST-75-RESOLVED to cover this use-case --- src/resolve/resolved-varlink.c | 605 ++++++++++++++++++++++-- src/shared/varlink-io.systemd.Resolve.c | 30 ++ test/knot-data/zones/signed.test.zone | 1 + test/units/testsuite-75.sh | 12 + 4 files changed, 609 insertions(+), 39 deletions(-) diff --git a/src/resolve/resolved-varlink.c b/src/resolve/resolved-varlink.c index 4e7e91bdfb..2f0971a7f0 100644 --- a/src/resolve/resolved-varlink.c +++ b/src/resolve/resolved-varlink.c @@ -17,6 +17,15 @@ typedef struct LookupParameters { char *name; } LookupParameters; +typedef struct LookupParametersResolveService { + const char *name; + const char *type; + const char *domain; + int family; + int ifindex; + uint64_t in_flags; +} LookupParametersResolveService; + static void lookup_parameters_destroy(LookupParameters *p) { assert(p); free(p->name); @@ -168,45 +177,23 @@ static bool validate_and_mangle_flags( return true; } -static void vl_method_resolve_hostname_complete(DnsQuery *query) { - _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *canonical = NULL; - _cleanup_(json_variant_unrefp) JsonVariant *array = NULL; - _cleanup_(dns_query_freep) DnsQuery *q = query; - _cleanup_free_ char *normalized = NULL; +static int find_addr_records( + JsonVariant **array, + DnsQuestion *question, + DnsQuery *q, + DnsResourceRecord **canonical, + const char *search_domain) { DnsResourceRecord *rr; - DnsQuestion *question; int ifindex, r; - assert(q); - - if (q->state != DNS_TRANSACTION_SUCCESS) { - r = reply_query_state(q); - goto finish; - } - - r = dns_query_process_cname_many(q); - if (r == -ELOOP) { - r = varlink_error(q->varlink_request, "io.systemd.Resolve.CNAMELoop", NULL); - goto finish; - } - if (r < 0) - goto finish; - if (r == DNS_QUERY_CNAME) { - /* This was a cname, and the query was restarted. */ - TAKE_PTR(q); - return; - } - - question = dns_query_question_for_protocol(q, q->answer_protocol); - DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, q->answer) { _cleanup_(json_variant_unrefp) JsonVariant *entry = NULL; int family; const void *p; - r = dns_question_matches_rr(question, rr, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain)); + r = dns_question_matches_rr(question, rr, search_domain); if (r < 0) - goto finish; + return r; if (r == 0) continue; @@ -217,8 +204,7 @@ static void vl_method_resolve_hostname_complete(DnsQuery *query) { family = AF_INET6; p = &rr->aaaa.in6_addr; } else { - r = -EAFNOSUPPORT; - goto finish; + return -EAFNOSUPPORT; } r = json_build(&entry, @@ -227,16 +213,53 @@ static void vl_method_resolve_hostname_complete(DnsQuery *query) { JSON_BUILD_PAIR("family", JSON_BUILD_INTEGER(family)), JSON_BUILD_PAIR("address", JSON_BUILD_BYTE_ARRAY(p, FAMILY_ADDRESS_SIZE(family))))); if (r < 0) - goto finish; - - if (!canonical) - canonical = dns_resource_record_ref(rr); + return r; - r = json_variant_append_array(&array, entry); + r = json_variant_append_array(array, entry); if (r < 0) - goto finish; + return r; + + if (canonical && !*canonical) + *canonical = dns_resource_record_ref(rr); } + return 0; +} + +static void vl_method_resolve_hostname_complete(DnsQuery *query) { + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *canonical = NULL; + _cleanup_(json_variant_unrefp) JsonVariant *array = NULL; + _cleanup_(dns_query_freep) DnsQuery *q = query; + _cleanup_free_ char *normalized = NULL; + DnsQuestion *question; + int r; + + assert(q); + + if (q->state != DNS_TRANSACTION_SUCCESS) { + r = reply_query_state(q); + goto finish; + } + + r = dns_query_process_cname_many(q); + if (r == -ELOOP) { + r = varlink_error(q->varlink_request, "io.systemd.Resolve.CNAMELoop", NULL); + goto finish; + } + if (r < 0) + goto finish; + if (r == DNS_QUERY_CNAME) { + /* This was a cname, and the query was restarted. */ + TAKE_PTR(q); + return; + } + + question = dns_query_question_for_protocol(q, q->answer_protocol); + + r = find_addr_records(&array, question, q, &canonical, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain)); + if (r < 0) + goto finish; + if (json_variant_is_blank_object(array)) { r = varlink_error(q->varlink_request, "io.systemd.Resolve.NoSuchResourceRecord", NULL); goto finish; @@ -538,6 +561,509 @@ static int vl_method_resolve_address(Varlink *link, JsonVariant *parameters, Var return 1; } +static int append_txt(JsonVariant **txt, DnsResourceRecord *rr) { + int r; + + assert(txt); + assert(rr); + assert(rr->key); + + if (rr->key->type != DNS_TYPE_TXT) + return 0; + + LIST_FOREACH(items, i, rr->txt.items) { + _cleanup_(json_variant_unrefp) JsonVariant *entry = NULL; + + if (i->length <= 0) + continue; + + r = json_variant_new_base64(&entry, i->data, i->length); + if (r < 0) + return r; + + r = json_variant_append_array(txt, entry); + if (r < 0) + return r; + } + + return 1; +} + +static int append_srv(DnsQuery *q, + JsonVariant **ret_srv, + JsonVariant **ret_addr, + char **ret_norm, + DnsResourceRecord *rr) { + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *canonical = NULL; + _cleanup_free_ char *normalized = NULL; + _cleanup_(json_variant_unrefp) JsonVariant *srv = NULL, *addr = NULL; + + int r; + + assert(q); + assert(rr); + assert(rr->key); + + if (rr->key->type != DNS_TYPE_SRV) + return 0; + + if ((q->flags & SD_RESOLVED_NO_ADDRESS) == 0) { + /* First, let's see if we could find an appropriate A or AAAA + * record for the SRV record */ + LIST_FOREACH(auxiliary_queries, aux, q->auxiliary_queries) { + DnsResourceRecord *zz; + DnsQuestion *question; + + if (aux->state != DNS_TRANSACTION_SUCCESS) + continue; + if (aux->auxiliary_result != 0) + continue; + + question = dns_query_question_for_protocol(aux, aux->answer_protocol); + + r = dns_name_equal(dns_question_first_name(question), rr->srv.name); + if (r < 0) + return r; + if (r == 0) + continue; + + DNS_ANSWER_FOREACH(zz, aux->answer) { + r = dns_question_matches_rr(question, zz, NULL); + if (r < 0) + return r; + if (r == 0) + continue; + + canonical = dns_resource_record_ref(zz); + break; + } + + if (canonical) + break; + } + + /* Is there are successful A/AAAA lookup for this SRV RR? If not, don't add it */ + if (!canonical) + return 0; + } + + r = dns_name_normalize(rr->srv.name, 0, &normalized); + if (r < 0) + return r; + + r = json_build(&srv, + JSON_BUILD_OBJECT( + JSON_BUILD_PAIR("priority", JSON_BUILD_UNSIGNED(rr->srv.priority)), + JSON_BUILD_PAIR("weight", JSON_BUILD_UNSIGNED(rr->srv.weight)), + JSON_BUILD_PAIR("port", JSON_BUILD_UNSIGNED(rr->srv.port)), + JSON_BUILD_PAIR("hostname", JSON_BUILD_STRING(normalized)))); + if (r < 0) + return r; + + if ((q->flags & SD_RESOLVED_NO_ADDRESS) == 0) { + LIST_FOREACH(auxiliary_queries, aux, q->auxiliary_queries) { + DnsQuestion *question; + + if (aux->state != DNS_TRANSACTION_SUCCESS) + continue; + if (aux->auxiliary_result != 0) + continue; + + question = dns_query_question_for_protocol(aux, aux->answer_protocol); + + r = dns_name_equal(dns_question_first_name(question), rr->srv.name); + if (r < 0) + return r; + if (r == 0) + continue; + + r = find_addr_records(&addr, 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); + if (r < 0) + return r; + } + + *ret_srv = TAKE_PTR(srv); + *ret_addr = TAKE_PTR(addr); + *ret_norm = TAKE_PTR(normalized); + + return 1; +} + +static Varlink *get_vl_link_aux_query(DnsQuery *aux) { + assert(aux); + + /* Find the main query */ + while (aux->auxiliary_for) + aux = aux->auxiliary_for; + + return aux->varlink_request; +} + +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_(dns_resource_record_unrefp) DnsResourceRecord *canonical = NULL; + DnsQuestion *question; + DnsResourceRecord *rr; + unsigned added = 0; + int r; + + assert(q); + + if (q->block_all_complete > 0) { + TAKE_PTR(q); + return; + } + + if ((q->flags & SD_RESOLVED_NO_ADDRESS) == 0) { + DnsQuery *bad = NULL; + bool have_success = false; + + LIST_FOREACH(auxiliary_queries, aux, q->auxiliary_queries) { + switch (aux->state) { + + case DNS_TRANSACTION_PENDING: + /* If an auxiliary query is still pending, let's wait */ + TAKE_PTR(q); + return; + + case DNS_TRANSACTION_SUCCESS: + if (aux->auxiliary_result == 0) + have_success = true; + else + bad = aux; + break; + + default: + bad = aux; + break; + } + } + if (!have_success) { + /* We can only return one error, hence pick the last error we encountered */ + + assert(bad); + if (bad->state == DNS_TRANSACTION_SUCCESS) { + assert(bad->auxiliary_result != 0); + + if (bad->auxiliary_result == -ELOOP) { + r = varlink_error(query->varlink_request, "io.systemd.Resolve.CNAMELoop", NULL); + goto finish; + } + + assert(bad->auxiliary_result < 0); + r = bad->auxiliary_result; + goto finish; + } + + bad->varlink_request = get_vl_link_aux_query(bad); + r = reply_query_state(bad); + bad->varlink_request = NULL; + goto finish; + } + } + + question = dns_query_question_for_protocol(q, q->answer_protocol); + + DNS_ANSWER_FOREACH(rr, q->answer) { + r = dns_question_matches_rr(question, rr, NULL); + if (r < 0) + goto finish; + if (r == 0) + continue; + + r = append_srv(q, &srv, &addr, &norm, rr); + if (r < 0) + goto finish; + if (r == 0) /* not an SRV record */ + continue; + + if (!canonical) + canonical = dns_resource_record_ref(rr); + + added++; + } + + if (added <= 0) { + r = varlink_error(query->varlink_request, "io.systemd.Resolve.NoSuchResourceRecord", NULL); + goto finish; + } + + DNS_ANSWER_FOREACH(rr, q->answer) { + r = dns_question_matches_rr(question, rr, NULL); + if (r < 0) + goto finish; + if (r == 0) + continue; + + if (rr->key->type != DNS_TYPE_TXT) + continue; + + r = append_txt(&txt, rr); + if (r < 0) + goto finish; + } + + assert(canonical); + r = dns_service_split(dns_resource_key_name(canonical->key), &name, &type, &domain); + if (r < 0) + 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("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)))))); + +finish: + if (r < 0) { + log_error_errno(r, "Failed to resolve service: %m"); + r = varlink_error_errno(q->varlink_request, r); + } +} + +static void resolve_service_hostname_complete(DnsQuery *q) { + int r; + + assert(q); + assert(q->auxiliary_for); + + if (q->state != DNS_TRANSACTION_SUCCESS) { + resolve_service_all_complete(q->auxiliary_for); + return; + } + + r = dns_query_process_cname_many(q); + if (r == DNS_QUERY_CNAME) /* This was a cname, and the query was restarted. */ + return; + + /* This auxiliary lookup is finished or failed, let's see if all are finished now. */ + q->auxiliary_result = r < 0 ? r : 0; + resolve_service_all_complete(q->auxiliary_for); +} + +static int resolve_service_hostname(DnsQuery *q, DnsResourceRecord *rr, int ifindex) { + _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL; + _cleanup_(dns_query_freep) DnsQuery *aux = NULL; + int r; + + assert(q); + assert(rr); + assert(rr->key); + assert(rr->key->type == DNS_TYPE_SRV); + + /* OK, we found an SRV record for the service. Let's resolve + * the hostname included in it */ + + r = dns_question_new_address(&question, q->request_family, rr->srv.name, false); + if (r < 0) + return r; + + r = dns_query_new(q->manager, &aux, question, question, NULL, ifindex, q->flags|SD_RESOLVED_NO_SEARCH); + if (r < 0) + return r; + + aux->request_family = q->request_family; + aux->complete = resolve_service_hostname_complete; + + r = dns_query_make_auxiliary(aux, q); + if (r == -EAGAIN) + /* Too many auxiliary lookups? If so, don't complain, + * let's just not add this one, we already have more + * than enough */ + return 0; + if (r < 0) + return r; + + /* Note that auxiliary queries do not track the original + * client, only the primary request does that. */ + + r = dns_query_go(aux); + if (r < 0) + return r; + + TAKE_PTR(aux); + return 1; +} + +static void vl_method_resolve_service_complete(DnsQuery *query) { + _cleanup_(dns_query_freep) DnsQuery *q = query; + bool has_root_domain = false; + DnsResourceRecord *rr; + DnsQuestion *question; + unsigned found = 0; + int ifindex, r; + + assert(q); + + if (q->state != DNS_TRANSACTION_SUCCESS) { + r = reply_query_state(q); + goto finish; + } + + r = dns_query_process_cname_many(q); + if (r == -ELOOP) { + r = varlink_error(q->varlink_request, "io.systemd.Resolve.CNAMELoop", NULL); + goto finish; + } + if (r < 0) + goto finish; + if (r == DNS_QUERY_CNAME) { + /* This was a cname, and the query was restarted. */ + TAKE_PTR(q); + return; + } + + question = dns_query_question_for_protocol(q, q->answer_protocol); + + DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, q->answer) { + r = dns_question_matches_rr(question, rr, NULL); + if (r < 0) + goto finish; + if (r == 0) + continue; + + if (rr->key->type != DNS_TYPE_SRV) + continue; + + if (dns_name_is_root(rr->srv.name)) { + has_root_domain = true; + continue; + } + + if ((q->flags & SD_RESOLVED_NO_ADDRESS) == 0) { + q->block_all_complete++; + r = resolve_service_hostname(q, rr, ifindex); + q->block_all_complete--; + + if (r < 0) + goto finish; + } + + found++; + } + + if (has_root_domain && found <= 0) { + /* If there's exactly one SRV RR and it uses the root domain as hostname, then the service is + * explicitly not offered on the domain. Report this as a recognizable error. See RFC 2782, + * Section "Usage Rules". */ + r = varlink_error(q->varlink_request, "io.systemd.Resolve.ServiceNotProvided", NULL); + goto finish; + } + + if (found <= 0) { + r = varlink_error(q->varlink_request, "io.systemd.Resolve.NoSuchResourceRecord", NULL); + goto finish; + } + + /* Maybe we are already finished? check now... */ + resolve_service_all_complete(TAKE_PTR(q)); + return; + +finish: + if (r < 0) { + log_error_errno(r, "Failed to send address reply: %m"); + r = varlink_error_errno(q->varlink_request, r); + } +} + +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 }, + {} + }; + + _cleanup_(dns_question_unrefp) DnsQuestion *question_idna = NULL, *question_utf8 = NULL; + LookupParametersResolveService p = { + .family = AF_UNSPEC, + }; + + _cleanup_(dns_query_freep) DnsQuery *q = NULL; + Manager *m; + int r; + + assert(link); + + m = varlink_server_get_userdata(varlink_get_server(link)); + assert(m); + + if (FLAGS_SET(flags, VARLINK_METHOD_ONEWAY)) + return -EINVAL; + + r = varlink_dispatch(link, parameters, dispatch_table, &p); + if (r < 0) + return r; + + if (p.ifindex < 0) + return varlink_error_invalid_parameter(link, JSON_VARIANT_STRING_CONST("ifindex")); + + if (!IN_SET(p.family, AF_INET, AF_INET6, AF_UNSPEC)) + return varlink_error_invalid_parameter(link, JSON_VARIANT_STRING_CONST("family")); + + if (isempty(p.name)) + p.name = NULL; + else if (!dns_service_name_is_valid(p.name)) + return varlink_error_invalid_parameter(link, JSON_VARIANT_STRING_CONST("name")); + + if (isempty(p.type)) + p.type = NULL; + else if (!dns_srv_type_is_valid(p.type)) + return varlink_error_invalid_parameter(link, JSON_VARIANT_STRING_CONST("type")); + + r = dns_name_is_valid(p.domain); + if (r < 0) + return r; + 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)) + 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); + 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); + 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); + if (r < 0) + return r; + + q->varlink_request = varlink_ref(link); + q->request_family = p.family; + q->complete = vl_method_resolve_service_complete; + + varlink_set_userdata(link, q); + + r = dns_query_go(q); + if (r < 0) + return r; + + TAKE_PTR(q); + return 1; +} + static int vl_method_subscribe_query_results(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata) { Manager *m; int r; @@ -762,7 +1288,8 @@ static int varlink_main_server_init(Manager *m) { r = varlink_server_bind_method_many( s, "io.systemd.Resolve.ResolveHostname", vl_method_resolve_hostname, - "io.systemd.Resolve.ResolveAddress", vl_method_resolve_address); + "io.systemd.Resolve.ResolveAddress", vl_method_resolve_address, + "io.systemd.Resolve.ResolveService", vl_method_resolve_service); if (r < 0) return log_error_errno(r, "Failed to register varlink methods: %m"); diff --git a/src/shared/varlink-io.systemd.Resolve.c b/src/shared/varlink-io.systemd.Resolve.c index 627b062ab0..5e27080abc 100644 --- a/src/shared/varlink-io.systemd.Resolve.c +++ b/src/shared/varlink-io.systemd.Resolve.c @@ -32,6 +32,33 @@ static VARLINK_DEFINE_METHOD( VARLINK_DEFINE_OUTPUT_BY_TYPE(names, ResolvedName, VARLINK_ARRAY), VARLINK_DEFINE_OUTPUT(flags, VARLINK_INT, 0)); +static VARLINK_DEFINE_STRUCT_TYPE( + ResolvedService, + 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)); + +static VARLINK_DEFINE_STRUCT_TYPE( + ResolvedCanonical, + VARLINK_DEFINE_FIELD(name, VARLINK_STRING, 0), + VARLINK_DEFINE_FIELD(type, VARLINK_STRING, 0), + VARLINK_DEFINE_FIELD(domain, VARLINK_STRING, 0)); + +static VARLINK_DEFINE_METHOD( + ResolveService, + VARLINK_DEFINE_INPUT(name, VARLINK_STRING, 0), + VARLINK_DEFINE_INPUT(type, VARLINK_STRING, 0), + 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)); + static VARLINK_DEFINE_ERROR(NoNameServers); static VARLINK_DEFINE_ERROR(NoSuchResourceRecord); static VARLINK_DEFINE_ERROR(QueryTimedOut); @@ -61,8 +88,11 @@ VARLINK_DEFINE_INTERFACE( "io.systemd.Resolve", &vl_method_ResolveHostname, &vl_method_ResolveAddress, + &vl_method_ResolveService, &vl_type_ResolvedAddress, &vl_type_ResolvedName, + &vl_type_ResolvedService, + &vl_type_ResolvedCanonical, &vl_error_NoNameServers, &vl_error_NoSuchResourceRecord, &vl_error_QueryTimedOut, diff --git a/test/knot-data/zones/signed.test.zone b/test/knot-data/zones/signed.test.zone index a2baac4284..5d75aa0a74 100644 --- a/test/knot-data/zones/signed.test.zone +++ b/test/knot-data/zones/signed.test.zone @@ -53,6 +53,7 @@ follow14.final A 10.0.0.14 myservice A 10.0.0.20 myservice AAAA fd00:dead:beef:cafe::17 _mysvc._tcp SRV 10 5 1234 myservice +_mysvc._tcp TXT "This is TXT for myservice" _invalidsvc._udp SRV 5 5 1111 invalidservice diff --git a/test/units/testsuite-75.sh b/test/units/testsuite-75.sh index 818a23736d..4b7a806325 100755 --- a/test/units/testsuite-75.sh +++ b/test/units/testsuite-75.sh @@ -434,6 +434,18 @@ grep -qF "myservice.signed.test:1234" "$RUN_OUT" grep -qF "10.0.0.20" "$RUN_OUT" grep -qF "fd00:dead:beef:cafe::17" "$RUN_OUT" 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 '"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" + (! run resolvectl service _invalidsvc._udp signed.test) grep -qE "invalidservice\.signed\.test' not found" "$RUN_OUT" run resolvectl service _untrustedsvc._udp signed.test -- 2.25.1