From: Nick Rosbrook Date: Fri, 19 Jun 2026 19:01:03 +0000 (-0400) Subject: resolvectl: use varlink instead of dbus for ResolveService X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F41840%2Fhead;p=thirdparty%2Fsystemd.git resolvectl: use varlink instead of dbus for ResolveService --- diff --git a/src/resolve/resolvectl.c b/src/resolve/resolvectl.c index 327cf101407..af7ed436726 100644 --- a/src/resolve/resolvectl.c +++ b/src/resolve/resolvectl.c @@ -18,7 +18,6 @@ #include "bus-common-errors.h" #include "bus-error.h" #include "bus-locator.h" -#include "bus-message-util.h" #include "bus-util.h" #include "crypto-util.h" #include "dns-configuration.h" @@ -27,7 +26,6 @@ #include "dns-rr.h" #include "errno-list.h" #include "errno-util.h" -#include "escape.h" #include "format-ifname.h" #include "format-table.h" #include "glyph-util.h" @@ -851,18 +849,9 @@ static int verb_query(int argc, char *argv[], uintptr_t _data, void *userdata) { return ret; } -static int resolve_service(sd_bus *bus, const char *name, const char *type, const char *domain) { - const char *canonical_name, *canonical_type, *canonical_domain; - _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL; - _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - size_t indent, sz; - uint64_t flags; - const char *p; - unsigned c; - usec_t ts; +static int resolve_service(const char *name, const char *type, const char *domain) { int r; - assert(bus); assert(domain); name = empty_to_null(name); @@ -875,141 +864,83 @@ static int resolve_service(sd_bus *bus, const char *name, const char *type, cons else log_debug("Resolving service type %s (family %s, interface %s).", domain, af_to_name(arg_family) ?: "*", isempty(arg_ifname) ? "*" : arg_ifname); - r = bus_message_new_method_call(bus, &req, bus_resolve_mgr, "ResolveService"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_append(req, "isssit", arg_ifindex, name, type, domain, arg_family, arg_flags); + _cleanup_(sd_varlink_unrefp) sd_varlink *vl = NULL; + r = varlink_connect_with_query_timeout(&vl); if (r < 0) - return bus_log_create_error(r); + return r; - ts = now(CLOCK_MONOTONIC); + usec_t ts = now(CLOCK_MONOTONIC); - r = sd_bus_call(bus, req, SD_RESOLVED_QUERY_TIMEOUT_USEC, &error, &reply); + const char *error_id = NULL; + sd_json_variant *v = NULL; + r = sd_varlink_callbo( + vl, + "io.systemd.Resolve.ResolveService", + &v, + &error_id, + SD_JSON_BUILD_PAIR_STRING("domain", domain), + JSON_BUILD_PAIR_STRING_NON_EMPTY("name", name), + JSON_BUILD_PAIR_STRING_NON_EMPTY("type", type), + JSON_BUILD_PAIR_CONDITION_UNSIGNED(arg_ifindex > 0, "ifindex", arg_ifindex), + JSON_BUILD_PAIR_CONDITION_UNSIGNED(arg_family != AF_UNSPEC, "family", arg_family), + JSON_BUILD_PAIR_UNSIGNED_NON_ZERO("flags", arg_flags)); if (r < 0) - return log_error_errno(r, "Resolve call failed: %s", bus_error_message(&error, r)); + return log_error_errno(r, "Failed to issue varlink call: %m"); ts = now(CLOCK_MONOTONIC) - ts; - r = sd_bus_message_enter_container(reply, 'a', "(qqqsa(iiay)s)"); - if (r < 0) - return bus_log_parse_error(r); - - indent = - (name ? strlen(name) + 1 : 0) + - (type ? strlen(type) + 1 : 0) + - strlen(domain) + 2; + if (!isempty(error_id)) + return varlink_log_resolve_error(domain, error_id, v, /* warn_missing = */ true); - c = 0; - while ((r = sd_bus_message_enter_container(reply, 'r', "qqqsa(iiay)s")) > 0) { - uint16_t priority, weight, port; - const char *hostname, *canonical; + _cleanup_(resolve_service_reply_done) ResolveServiceReply reply = {}; + r = dispatch_resolve_service_reply(/* name = */ NULL, v, SD_JSON_LOG, &reply); + if (r < 0) + return r; - r = sd_bus_message_read(reply, "qqqs", &priority, &weight, &port, &hostname); - if (r < 0) - return bus_log_parse_error(r); + size_t indent = (name ? strlen(name) + 1 : 0) + + (type ? strlen(type) + 1 : 0) + + strlen(domain) + 2; + bool first = true; + FOREACH_ARRAY(service, reply.services, reply.n_services) { if (name) - printf("%*s%s", (int) strlen(name), c == 0 ? name : "", c == 0 ? "/" : " "); + printf("%*s%s", (int) strlen(name), first ? name : "", first ? "/" : " "); if (type) - printf("%*s%s", (int) strlen(type), c == 0 ? type : "", c == 0 ? "/" : " "); + printf("%*s%s", (int) strlen(type), first ? type : "", first ? "/" : " "); printf("%*s%s %s:%u [priority=%u, weight=%u]\n", - (int) strlen(domain), c == 0 ? domain : "", - c == 0 ? ":" : " ", - hostname, port, - priority, weight); - - r = sd_bus_message_enter_container(reply, 'a', "(iiay)"); - if (r < 0) - return bus_log_parse_error(r); - - while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) { + (int) strlen(domain), + first ? domain : "", + first ? ":" : " ", + service->hostname, + service->port, + service->priority, + service->weight); + + FOREACH_ARRAY(address, service->addresses, service->n_addresses) { _cleanup_free_ char *pretty = NULL; - int ifindex, family, k; - union in_addr_union a; - - assert_cc(sizeof(int) == sizeof(int32_t)); - - r = sd_bus_message_read(reply, "i", &ifindex); - if (r < 0) - return bus_log_parse_error(r); - - sd_bus_error_free(&error); - r = bus_message_read_in_addr_auto(reply, &error, &family, &a); - if (r < 0 && !sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS)) - return log_error_errno(r, "%s: systemd-resolved returned invalid result: %s", name, bus_error_message(&error, r)); - - r = sd_bus_message_exit_container(reply); - if (r < 0) - return bus_log_parse_error(r); - - if (sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS)) { - log_debug_errno(r, "%s: systemd-resolved returned invalid result, ignoring: %s", name, bus_error_message(&error, r)); - continue; - } - - r = in_addr_ifindex_to_string(family, &a, ifindex, &pretty); + r = in_addr_ifindex_to_string(address->family, &address->in_addr.address, address->ifindex, &pretty); if (r < 0) return log_error_errno(r, "Failed to print address for %s: %m", name); - k = printf("%*s%s", (int) indent, "", pretty); - print_ifindex_comment(k, ifindex); + int k = printf("%*s%s", (int) indent, "", pretty); + + print_ifindex_comment(k, address->ifindex); fputc('\n', stdout); } - if (r < 0) - return bus_log_parse_error(r); - - r = sd_bus_message_exit_container(reply); - if (r < 0) - return bus_log_parse_error(r); - - r = sd_bus_message_read(reply, "s", &canonical); - if (r < 0) - return bus_log_parse_error(r); - - if (!streq(hostname, canonical)) - printf("%*s(%s)\n", (int) indent, "", canonical); - r = sd_bus_message_exit_container(reply); - if (r < 0) - return bus_log_parse_error(r); + if (service->canonical_name && !streq_ptr(service->hostname, service->canonical_name)) + printf("%*s(%s)\n", (int) indent, "", service->canonical_name); - c++; - } - if (r < 0) - return bus_log_parse_error(r); - - r = sd_bus_message_exit_container(reply); - if (r < 0) - return bus_log_parse_error(r); - - r = sd_bus_message_enter_container(reply, 'a', "ay"); - if (r < 0) - return bus_log_parse_error(r); - - while ((r = sd_bus_message_read_array(reply, 'y', (const void**) &p, &sz)) > 0) { - _cleanup_free_ char *escaped = NULL; - - escaped = cescape_length(p, sz); - if (!escaped) - return log_oom(); - - printf("%*s%s\n", (int) indent, "", escaped); + first = false; } - if (r < 0) - return bus_log_parse_error(r); - - r = sd_bus_message_exit_container(reply); - if (r < 0) - return bus_log_parse_error(r); - r = sd_bus_message_read(reply, "ssst", &canonical_name, &canonical_type, &canonical_domain, &flags); - if (r < 0) - return bus_log_parse_error(r); + STRV_FOREACH(p, reply.txt) + printf("%*s%s\n", (int) indent, "", *p); - canonical_name = empty_to_null(canonical_name); - canonical_type = empty_to_null(canonical_type); + const char *canonical_name = empty_to_null(reply.canonical.name); + const char *canonical_type = empty_to_null(reply.canonical.type); + const char *canonical_domain = reply.canonical.domain; if (!streq_ptr(name, canonical_name) || !streq_ptr(type, canonical_type) || @@ -1025,7 +956,7 @@ static int resolve_service(sd_bus *bus, const char *name, const char *type, cons printf("%s)\n", canonical_domain); } - print_source(flags, ts); + print_source(reply.flags, ts); return 0; } @@ -1033,22 +964,15 @@ static int resolve_service(sd_bus *bus, const char *name, const char *type, cons VERB(verb_service, "service", "[[NAME] TYPE] DOMAIN", 2, 4, 0, "Resolve service (SRV)"); static int verb_service(int argc, char *argv[], uintptr_t _data, void *userdata) { - _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; - int r; - - r = acquire_bus(&bus); - if (r < 0) - return r; - if (sd_json_format_enabled(arg_json_format_flags)) return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Use --json=pretty with --type= to acquire resource record information in JSON format."); if (argc == 2) - return resolve_service(bus, NULL, NULL, argv[1]); + return resolve_service(NULL, NULL, argv[1]); else if (argc == 3) - return resolve_service(bus, NULL, argv[1], argv[2]); + return resolve_service(NULL, argv[1], argv[2]); else - return resolve_service(bus, argv[1], argv[2], argv[3]); + return resolve_service(argv[1], argv[2], argv[3]); } #if HAVE_OPENSSL diff --git a/src/shared/resolve-varlink-util.c b/src/shared/resolve-varlink-util.c index c3a638f3ad2..779770a523c 100644 --- a/src/shared/resolve-varlink-util.c +++ b/src/shared/resolve-varlink-util.c @@ -6,6 +6,7 @@ #include "iovec-util.h" #include "json-util.h" #include "resolve-varlink-util.h" +#include "strv.h" void resolve_error_done(ResolveError *error) { if (!error) @@ -247,3 +248,129 @@ int dispatch_resolve_record_reply(const char *name, sd_json_variant *variant, sd *ret = TAKE_STRUCT(reply); return 0; } + +static void resolved_service_done(ResolvedService *service) { + if (!service) + return; + + service->hostname = mfree(service->hostname); + service->canonical_name = mfree(service->canonical_name); + service->addresses = mfree(service->addresses); + service->n_addresses = 0; +} + +static int dispatch_resolved_service_address_array(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) { + ResolvedService *service = ASSERT_PTR(userdata); + int r; + + sd_json_variant *v; + JSON_VARIANT_ARRAY_FOREACH(v, variant) { + if (!GREEDY_REALLOC0(service->addresses, service->n_addresses + 1)) + return json_log_oom(variant, flags); + + r = dispatch_resolved_address(name, v, flags, &service->addresses[service->n_addresses++]); + if (r < 0) + return r; + } + + return 0; +} + +static int dispatch_resolved_service(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) { + static const sd_json_dispatch_field resolved_service_dispatch_table[] = { + { "priority", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint16, offsetof(ResolvedService, priority), SD_JSON_MANDATORY }, + { "weight", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint16, offsetof(ResolvedService, weight), SD_JSON_MANDATORY }, + { "port", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint16, offsetof(ResolvedService, port), SD_JSON_MANDATORY }, + { "hostname", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(ResolvedService, hostname), SD_JSON_MANDATORY }, + { "canonicalName", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(ResolvedService, canonical_name), SD_JSON_NULLABLE }, + { "addresses", SD_JSON_VARIANT_ARRAY, dispatch_resolved_service_address_array, 0, SD_JSON_NULLABLE }, + {}, + }; + ResolvedService *ret = ASSERT_PTR(userdata); + int r; + + _cleanup_(resolved_service_done) ResolvedService service = {}; + r = sd_json_dispatch(variant, resolved_service_dispatch_table, flags & ~SD_JSON_MANDATORY, &service); + if (r < 0) + return r; + + *ret = TAKE_STRUCT(service); + return 0; +} + +static int dispatch_resolved_service_array(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) { + ResolveServiceReply *reply = ASSERT_PTR(userdata); + int r; + + sd_json_variant *v; + JSON_VARIANT_ARRAY_FOREACH(v, variant) { + if (!GREEDY_REALLOC0(reply->services, reply->n_services + 1)) + return json_log_oom(variant, flags); + + r = dispatch_resolved_service(name, v, flags, &reply->services[reply->n_services++]); + if (r < 0) + return r; + } + + return 0; +} + +static void resolved_canonical_done(ResolvedCanonical *canonical) { + if (!canonical) + return; + + canonical->name = mfree(canonical->name); + canonical->type = mfree(canonical->type); + canonical->domain = mfree(canonical->domain); +} + +static int dispatch_resolved_canonical(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) { + static const sd_json_dispatch_field resolved_canonical_dispatch_table[] = { + { "name", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(ResolvedCanonical, name), SD_JSON_NULLABLE }, + { "type", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(ResolvedCanonical, type), SD_JSON_MANDATORY }, + { "domain", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(ResolvedCanonical, domain), SD_JSON_MANDATORY }, + {}, + }; + ResolvedCanonical *ret = ASSERT_PTR(userdata); + int r; + + _cleanup_(resolved_canonical_done) ResolvedCanonical canonical = {}; + r = sd_json_dispatch(variant, resolved_canonical_dispatch_table, flags & ~SD_JSON_MANDATORY, &canonical); + if (r < 0) + return r; + + *ret = TAKE_STRUCT(canonical); + return 0; +} + +void resolve_service_reply_done(ResolveServiceReply *reply) { + if (!reply) + return; + + FOREACH_ARRAY(service, reply->services, reply->n_services) + resolved_service_done(service); + reply->services = mfree(reply->services); + reply->n_services = 0; + reply->txt = strv_free(reply->txt); + resolved_canonical_done(&reply->canonical); +} + +int dispatch_resolve_service_reply(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) { + static const sd_json_dispatch_field resolve_service_reply_dispatch_table[] = { + { "services", SD_JSON_VARIANT_ARRAY, dispatch_resolved_service_array, 0, SD_JSON_MANDATORY }, + { "txt", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_strv, offsetof(ResolveServiceReply, txt), SD_JSON_NULLABLE }, + { "canonical", SD_JSON_VARIANT_OBJECT, dispatch_resolved_canonical, offsetof(ResolveServiceReply, canonical), SD_JSON_MANDATORY }, + { "flags", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(ResolveServiceReply, flags), SD_JSON_MANDATORY }, + {}, + }; + ResolveServiceReply *ret = ASSERT_PTR(userdata); + int r; + + _cleanup_(resolve_service_reply_done) ResolveServiceReply reply = {}; + r = sd_json_dispatch(variant, resolve_service_reply_dispatch_table, flags | SD_JSON_ALLOW_EXTENSIONS, &reply); + if (r < 0) + return r; + + *ret = TAKE_STRUCT(reply); + return 0; +} diff --git a/src/shared/resolve-varlink-util.h b/src/shared/resolve-varlink-util.h index 58e8f4d9184..a05e18daea5 100644 --- a/src/shared/resolve-varlink-util.h +++ b/src/shared/resolve-varlink-util.h @@ -64,3 +64,31 @@ typedef struct ResolveRecordReply { void resolve_record_reply_done(ResolveRecordReply *reply); int dispatch_resolve_record_reply(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata); + +typedef struct ResolvedService { + uint16_t priority; + uint16_t weight; + uint16_t port; + char *hostname; + char *canonical_name; + ResolvedAddress *addresses; + size_t n_addresses; +} ResolvedService; + +typedef struct ResolvedCanonical { + char *name; + char *type; + char *domain; +} ResolvedCanonical; + +typedef struct ResolveServiceReply { + ResolvedService *services; + size_t n_services; + char **txt; + ResolvedCanonical canonical; + uint64_t flags; +} ResolveServiceReply; + +void resolve_service_reply_done(ResolveServiceReply *reply); + +int dispatch_resolve_service_reply(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);