From 0fe9c5da020ac7b5307496622ca782eedd8fc6e5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 4 Mar 2024 10:18:36 +0100 Subject: [PATCH 1/2] resolved: move ResourceKey/ResourceRecord varlink types to generic Resolve interface Let's define this in the generic interface and then import it into the Monitor interface too. This is preparation for adding an interface to resolve arbitrary RRs via Varlink, which means we want the type in both interfaces. --- .../varlink-io.systemd.Resolve.Monitor.c | 69 +------------------ src/shared/varlink-io.systemd.Resolve.c | 69 +++++++++++++++++++ src/shared/varlink-io.systemd.Resolve.h | 3 + 3 files changed, 75 insertions(+), 66 deletions(-) diff --git a/src/shared/varlink-io.systemd.Resolve.Monitor.c b/src/shared/varlink-io.systemd.Resolve.Monitor.c index 3ea97432db..ba928fa2cf 100644 --- a/src/shared/varlink-io.systemd.Resolve.Monitor.c +++ b/src/shared/varlink-io.systemd.Resolve.Monitor.c @@ -2,72 +2,9 @@ #include "varlink-io.systemd.Resolve.Monitor.h" -static VARLINK_DEFINE_STRUCT_TYPE( - ResourceKey, - VARLINK_DEFINE_FIELD(class, VARLINK_INT, 0), - VARLINK_DEFINE_FIELD(type, VARLINK_INT, 0), - VARLINK_DEFINE_FIELD(name, VARLINK_STRING, 0)); - -static VARLINK_DEFINE_STRUCT_TYPE( - ResourceRecord, - VARLINK_DEFINE_FIELD_BY_TYPE(key, ResourceKey, 0), - VARLINK_DEFINE_FIELD(priority, VARLINK_INT, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(weight, VARLINK_INT, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(port, VARLINK_INT, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(name, VARLINK_STRING, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(cpu, VARLINK_STRING, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(os, VARLINK_STRING, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(items, VARLINK_STRING, VARLINK_NULLABLE|VARLINK_ARRAY), - VARLINK_DEFINE_FIELD(address, VARLINK_INT, VARLINK_NULLABLE|VARLINK_ARRAY), - VARLINK_DEFINE_FIELD(mname, VARLINK_STRING, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(rname, VARLINK_STRING, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(serial, VARLINK_INT, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(refresh, VARLINK_INT, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(expire, VARLINK_INT, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(minimum, VARLINK_INT, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(exchange, VARLINK_STRING, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(version, VARLINK_INT, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(size, VARLINK_INT, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(horiz_pre, VARLINK_INT, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(vert_pre, VARLINK_INT, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(latitude, VARLINK_INT, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(longitude, VARLINK_INT, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(altitude, VARLINK_INT, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(keyTag, VARLINK_INT, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(algorithm, VARLINK_INT, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(digestType, VARLINK_INT, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(digest, VARLINK_STRING, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(fptype, VARLINK_INT, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(fingerprint, VARLINK_STRING, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(flags, VARLINK_INT, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(protocol, VARLINK_INT, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(dnskey, VARLINK_STRING, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(signer, VARLINK_STRING, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(typeCovered, VARLINK_INT, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(labels, VARLINK_INT, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(originalTtl, VARLINK_INT, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(expiration, VARLINK_INT, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(inception, VARLINK_INT, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(signature, VARLINK_STRING, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(nextDomain, VARLINK_STRING, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(types, VARLINK_INT, VARLINK_NULLABLE|VARLINK_ARRAY), - VARLINK_DEFINE_FIELD(iterations, VARLINK_INT, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(salt, VARLINK_STRING, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(hash, VARLINK_STRING, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(certUsage, VARLINK_INT, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(selector, VARLINK_INT, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(matchingType, VARLINK_INT, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(data, VARLINK_STRING, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(tag, VARLINK_STRING, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(value, VARLINK_STRING, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(target, VARLINK_STRING, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(params, VARLINK_STRING, VARLINK_NULLABLE|VARLINK_ARRAY), - VARLINK_DEFINE_FIELD(order, VARLINK_INT, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(preference, VARLINK_INT, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(naptrFlags, VARLINK_STRING, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(services, VARLINK_STRING, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(regexp, VARLINK_STRING, VARLINK_NULLABLE), - VARLINK_DEFINE_FIELD(replacement, VARLINK_STRING, VARLINK_NULLABLE)); +/* We want to reuse the ResourceKey and ResourceRecord structures from the io.systemd.Resolve interface, + * hence import them here. */ +#include "varlink-io.systemd.Resolve.h" static VARLINK_DEFINE_STRUCT_TYPE( ResourceRecordArray, diff --git a/src/shared/varlink-io.systemd.Resolve.c b/src/shared/varlink-io.systemd.Resolve.c index 12111b2404..c7d934ba77 100644 --- a/src/shared/varlink-io.systemd.Resolve.c +++ b/src/shared/varlink-io.systemd.Resolve.c @@ -2,6 +2,73 @@ #include "varlink-io.systemd.Resolve.h" +VARLINK_DEFINE_STRUCT_TYPE( + ResourceKey, + VARLINK_DEFINE_FIELD(class, VARLINK_INT, 0), + VARLINK_DEFINE_FIELD(type, VARLINK_INT, 0), + VARLINK_DEFINE_FIELD(name, VARLINK_STRING, 0)); + +VARLINK_DEFINE_STRUCT_TYPE( + ResourceRecord, + VARLINK_DEFINE_FIELD_BY_TYPE(key, ResourceKey, 0), + VARLINK_DEFINE_FIELD(priority, VARLINK_INT, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(weight, VARLINK_INT, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(port, VARLINK_INT, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(name, VARLINK_STRING, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(cpu, VARLINK_STRING, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(os, VARLINK_STRING, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(items, VARLINK_STRING, VARLINK_NULLABLE|VARLINK_ARRAY), + VARLINK_DEFINE_FIELD(address, VARLINK_INT, VARLINK_NULLABLE|VARLINK_ARRAY), + VARLINK_DEFINE_FIELD(mname, VARLINK_STRING, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(rname, VARLINK_STRING, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(serial, VARLINK_INT, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(refresh, VARLINK_INT, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(expire, VARLINK_INT, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(minimum, VARLINK_INT, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(exchange, VARLINK_STRING, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(version, VARLINK_INT, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(size, VARLINK_INT, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(horiz_pre, VARLINK_INT, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(vert_pre, VARLINK_INT, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(latitude, VARLINK_INT, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(longitude, VARLINK_INT, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(altitude, VARLINK_INT, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(keyTag, VARLINK_INT, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(algorithm, VARLINK_INT, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(digestType, VARLINK_INT, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(digest, VARLINK_STRING, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(fptype, VARLINK_INT, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(fingerprint, VARLINK_STRING, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(flags, VARLINK_INT, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(protocol, VARLINK_INT, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(dnskey, VARLINK_STRING, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(signer, VARLINK_STRING, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(typeCovered, VARLINK_INT, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(labels, VARLINK_INT, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(originalTtl, VARLINK_INT, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(expiration, VARLINK_INT, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(inception, VARLINK_INT, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(signature, VARLINK_STRING, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(nextDomain, VARLINK_STRING, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(types, VARLINK_INT, VARLINK_NULLABLE|VARLINK_ARRAY), + VARLINK_DEFINE_FIELD(iterations, VARLINK_INT, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(salt, VARLINK_STRING, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(hash, VARLINK_STRING, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(certUsage, VARLINK_INT, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(selector, VARLINK_INT, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(matchingType, VARLINK_INT, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(data, VARLINK_STRING, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(tag, VARLINK_STRING, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(value, VARLINK_STRING, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(target, VARLINK_STRING, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(params, VARLINK_STRING, VARLINK_NULLABLE|VARLINK_ARRAY), + VARLINK_DEFINE_FIELD(order, VARLINK_INT, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(preference, VARLINK_INT, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(naptrFlags, VARLINK_STRING, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(services, VARLINK_STRING, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(regexp, VARLINK_STRING, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(replacement, VARLINK_STRING, VARLINK_NULLABLE)); + static VARLINK_DEFINE_STRUCT_TYPE( ResolvedAddress, VARLINK_DEFINE_FIELD(ifindex, VARLINK_INT, VARLINK_NULLABLE), @@ -94,6 +161,8 @@ VARLINK_DEFINE_INTERFACE( &vl_type_ResolvedName, &vl_type_ResolvedService, &vl_type_ResolvedCanonical, + &vl_type_ResourceKey, + &vl_type_ResourceRecord, &vl_error_NoNameServers, &vl_error_NoSuchResourceRecord, &vl_error_QueryTimedOut, diff --git a/src/shared/varlink-io.systemd.Resolve.h b/src/shared/varlink-io.systemd.Resolve.h index 5c7ed39d0d..48a9241ef4 100644 --- a/src/shared/varlink-io.systemd.Resolve.h +++ b/src/shared/varlink-io.systemd.Resolve.h @@ -3,4 +3,7 @@ #include "varlink-idl.h" +extern const VarlinkSymbol vl_type_ResourceKey; +extern const VarlinkSymbol vl_type_ResourceRecord; + extern const VarlinkInterface vl_interface_io_systemd_Resolve; From cf1c8cdb87d4e2c1f52130a7b11381f4aff4c2f1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 4 Mar 2024 11:22:41 +0100 Subject: [PATCH 2/2] resolved: expose raw RR resolver via Varlink too Now that we have an address, hostname, and service resolve, at the last kind of resovler we expose over D-Bus also to Varlink. --- src/resolve/resolved-varlink.c | 161 +++++++++++++++++++++++- src/shared/varlink-io.systemd.Resolve.c | 26 +++- test/units/testsuite-75.sh | 4 + 3 files changed, 187 insertions(+), 4 deletions(-) diff --git a/src/resolve/resolved-varlink.c b/src/resolve/resolved-varlink.c index cdd5ca41fd..6b835904be 100644 --- a/src/resolve/resolved-varlink.c +++ b/src/resolve/resolved-varlink.c @@ -15,6 +15,8 @@ typedef struct LookupParameters { union in_addr_union address; size_t address_size; char *name; + uint16_t class; + uint16_t type; } LookupParameters; typedef struct LookupParametersResolveService { @@ -1074,6 +1076,158 @@ static int vl_method_resolve_service(Varlink* link, JsonVariant* parameters, Var return 1; } +static void vl_method_resolve_record_complete(DnsQuery *query) { + _cleanup_(json_variant_unrefp) JsonVariant *array = NULL; + _cleanup_(dns_query_freep) DnsQuery *q = query; + 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); + + unsigned added = 0; + int ifindex; + DnsResourceRecord *rr; + DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, q->answer) { + _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; + + r = dns_question_matches_rr(question, rr, NULL); + if (r < 0) + goto finish; + if (r == 0) + continue; + + r = dns_resource_record_to_json(rr, &v); + if (r < 0) + goto finish; + + r = dns_resource_record_to_wire_format(rr, /* canonical= */ false); /* don't use DNSSEC canonical format, since it removes casing, but we want that for DNS_SD compat */ + if (r < 0) + goto finish; + + r = json_variant_append_arrayb( + &array, + JSON_BUILD_OBJECT(JSON_BUILD_PAIR_CONDITION(ifindex > 0, "ifindex", JSON_BUILD_INTEGER(ifindex)), + JSON_BUILD_PAIR_CONDITION(v, "rr", JSON_BUILD_VARIANT(v)), + JSON_BUILD_PAIR("raw", JSON_BUILD_BASE64(rr->wire_format, rr->wire_format_size)))); + if (r < 0) + goto finish; + + added++; + } + + if (added <= 0) { + r = varlink_error(q->varlink_request, "io.systemd.Resolve.NoSuchResourceRecord", NULL); + goto finish; + } + + r = varlink_replyb(q->varlink_request, + JSON_BUILD_OBJECT( + JSON_BUILD_PAIR("rrs", JSON_BUILD_VARIANT(array)), + JSON_BUILD_PAIR("flags", JSON_BUILD_INTEGER(dns_query_reply_flags_make(q))))); +finish: + if (r < 0) { + log_full_errno(ERRNO_IS_DISCONNECT(r) ? LOG_DEBUG : LOG_ERR, r, "Failed to send record reply: %m"); + varlink_error_errno(q->varlink_request, r); + } +} + +static int vl_method_resolve_record(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata) { + static const JsonDispatch dispatch_table[] = { + { "ifindex", _JSON_VARIANT_TYPE_INVALID, json_dispatch_int, offsetof(LookupParameters, ifindex), 0 }, + { "name", JSON_VARIANT_STRING, json_dispatch_string, offsetof(LookupParameters, name), JSON_MANDATORY }, + { "class", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint16, offsetof(LookupParameters, class), 0 }, + { "type", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint16, offsetof(LookupParameters, type), JSON_MANDATORY }, + { "flags", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(LookupParameters, flags), 0 }, + {} + }; + + _cleanup_(lookup_parameters_destroy) LookupParameters p = { + .class = DNS_CLASS_IN, + .type = _DNS_TYPE_INVALID, + }; + _cleanup_(dns_query_freep) DnsQuery *q = NULL; + Manager *m; + int r; + + assert(link); + + m = ASSERT_PTR(varlink_server_get_userdata(varlink_get_server(link))); + + 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")); + + r = dns_name_is_valid(p.name); + if (r < 0) + return r; + if (r == 0) + return varlink_error_invalid_parameter(link, JSON_VARIANT_STRING_CONST("name")); + + if (!dns_type_is_valid_query(p.type)) + return varlink_error(link, "io.systemd.Resolve.ResourceRecordTypeInvalidForQuery", NULL); + if (dns_type_is_zone_transfer(p.type)) + return varlink_error(link, "io.systemd.Resolve.ZoneTransfersNotPermitted", NULL); + if (dns_type_is_obsolete(p.type)) + return varlink_error(link, "io.systemd.Resolve.ResourceRecordTypeObsolete", NULL); + + if (!validate_and_mangle_flags(p.name, &p.flags, SD_RESOLVED_NO_SEARCH)) + return varlink_error_invalid_parameter(link, JSON_VARIANT_STRING_CONST("flags")); + + _cleanup_(dns_question_unrefp) DnsQuestion *question = dns_question_new(1); + if (!question) + return -ENOMEM; + + _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; + key = dns_resource_key_new(p.class, p.type, p.name); + if (!key) + return -ENOMEM; + + r = dns_question_add(question, key, /* flags= */ 0); + if (r < 0) + return r; + + r = dns_query_new(m, &q, question, question, NULL, p.ifindex, p.flags|SD_RESOLVED_NO_SEARCH|SD_RESOLVED_CLAMP_TTL); + if (r < 0) + return r; + + q->varlink_request = varlink_ref(link); + varlink_set_userdata(link, q); + q->complete = vl_method_resolve_record_complete; + + 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; @@ -1297,9 +1451,10 @@ 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.ResolveService", vl_method_resolve_service); + "io.systemd.Resolve.ResolveHostname", vl_method_resolve_hostname, + "io.systemd.Resolve.ResolveAddress", vl_method_resolve_address, + "io.systemd.Resolve.ResolveService", vl_method_resolve_service, + "io.systemd.Resolve.ResolveRecord", vl_method_resolve_record); 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 c7d934ba77..a6c501ab01 100644 --- a/src/shared/varlink-io.systemd.Resolve.c +++ b/src/shared/varlink-io.systemd.Resolve.c @@ -127,6 +127,22 @@ static VARLINK_DEFINE_METHOD( VARLINK_DEFINE_OUTPUT_BY_TYPE(canonical, ResolvedCanonical, 0), VARLINK_DEFINE_OUTPUT(flags, VARLINK_INT, 0)); +static VARLINK_DEFINE_STRUCT_TYPE( + ResolvedRecord, + VARLINK_DEFINE_FIELD(ifindex, VARLINK_INT, 0), + VARLINK_DEFINE_FIELD_BY_TYPE(rr, ResourceRecord, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(raw, VARLINK_STRING, 0)); + +static VARLINK_DEFINE_METHOD( + ResolveRecord, + VARLINK_DEFINE_INPUT(ifindex, VARLINK_INT, VARLINK_NULLABLE), + VARLINK_DEFINE_INPUT(name, VARLINK_STRING, 0), + VARLINK_DEFINE_INPUT(class, VARLINK_INT, VARLINK_NULLABLE), + VARLINK_DEFINE_INPUT(type, VARLINK_INT, 0), + VARLINK_DEFINE_INPUT(flags, VARLINK_INT, VARLINK_NULLABLE), + VARLINK_DEFINE_OUTPUT_BY_TYPE(rrs, ResolvedRecord, VARLINK_ARRAY), + VARLINK_DEFINE_OUTPUT(flags, VARLINK_INT, 0)); + static VARLINK_DEFINE_ERROR(NoNameServers); static VARLINK_DEFINE_ERROR(NoSuchResourceRecord); static VARLINK_DEFINE_ERROR(QueryTimedOut); @@ -150,6 +166,9 @@ static VARLINK_DEFINE_ERROR( VARLINK_DEFINE_FIELD(extendedDNSErrorMessage, VARLINK_STRING, VARLINK_NULLABLE)); static VARLINK_DEFINE_ERROR(CNAMELoop); static VARLINK_DEFINE_ERROR(BadAddressSize); +static VARLINK_DEFINE_ERROR(ResourceRecordTypeInvalidForQuery); +static VARLINK_DEFINE_ERROR(ZoneTransfersNotPermitted); +static VARLINK_DEFINE_ERROR(ResourceRecordTypeObsolete); VARLINK_DEFINE_INTERFACE( io_systemd_Resolve, @@ -157,12 +176,14 @@ VARLINK_DEFINE_INTERFACE( &vl_method_ResolveHostname, &vl_method_ResolveAddress, &vl_method_ResolveService, + &vl_method_ResolveRecord, &vl_type_ResolvedAddress, &vl_type_ResolvedName, &vl_type_ResolvedService, &vl_type_ResolvedCanonical, &vl_type_ResourceKey, &vl_type_ResourceRecord, + &vl_type_ResolvedRecord, &vl_error_NoNameServers, &vl_error_NoSuchResourceRecord, &vl_error_QueryTimedOut, @@ -177,4 +198,7 @@ VARLINK_DEFINE_INTERFACE( &vl_error_StubLoop, &vl_error_DNSError, &vl_error_CNAMELoop, - &vl_error_BadAddressSize); + &vl_error_BadAddressSize, + &vl_error_ResourceRecordTypeInvalidForQuery, + &vl_error_ZoneTransfersNotPermitted, + &vl_error_ResourceRecordTypeObsolete); diff --git a/test/units/testsuite-75.sh b/test/units/testsuite-75.sh index 71f299a406..7bfc067e05 100755 --- a/test/units/testsuite-75.sh +++ b/test/units/testsuite-75.sh @@ -846,6 +846,10 @@ run resolvectl reset-statistics --json=short test "$(resolvectl --json=short query -t AAAA localhost)" == '{"key":{"class":1,"type":28,"name":"localhost"},"address":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1]}' test "$(resolvectl --json=short query -t A localhost)" == '{"key":{"class":1,"type":1,"name":"localhost"},"address":[127,0,0,1]}' +# Test ResolveRecord RR resolving via Varlink +test "$(varlinkctl call /run/systemd/resolve/io.systemd.Resolve io.systemd.Resolve.ResolveRecord '{"name":"localhost","type":1}' --json=short)" == '{"rrs":[{"ifindex":1,"rr":{"key":{"class":1,"type":1,"name":"localhost"},"address":[127,0,0,1]},"raw":"CWxvY2FsaG9zdAAAAQABAAAAAAAEfwAAAQ=="}],"flags":786945}' +test "$(varlinkctl call /run/systemd/resolve/io.systemd.Resolve io.systemd.Resolve.ResolveRecord '{"name":"localhost","type":28}' --json=short)" == '{"rrs":[{"ifindex":1,"rr":{"key":{"class":1,"type":28,"name":"localhost"},"address":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1]},"raw":"CWxvY2FsaG9zdAAAHAABAAAAAAAQAAAAAAAAAAAAAAAAAAAAAQ=="}],"flags":786945}' + # Check if resolved exits cleanly. restart_resolved