resolvectl: use varlink instead of dbus for ResolveHostname
This commit is contained in:
+133
-71
@@ -48,6 +48,7 @@
|
||||
#include "resolvectl.h"
|
||||
#include "resolved-def.h"
|
||||
#include "resolved-util.h"
|
||||
#include "resolve-varlink-util.h"
|
||||
#include "set.h"
|
||||
#include "socket-netlink.h"
|
||||
#include "string-table.h"
|
||||
@@ -278,20 +279,97 @@ static void print_ifindex_comment(int printed_so_far, int ifindex) {
|
||||
ansi_grey(), ifname, ansi_normal());
|
||||
}
|
||||
|
||||
static int resolve_host_error(const char *name, int r, const sd_bus_error *error) {
|
||||
if (sd_bus_error_has_name(error, BUS_ERROR_DNS_NXDOMAIN))
|
||||
return log_error_errno(r, "%s: %s", name, bus_error_message(error, r));
|
||||
static int varlink_log_resolve_error(const char *name, const char *error_id, sd_json_variant *reply) {
|
||||
int r;
|
||||
|
||||
return log_error_errno(r, "%s: resolve call failed: %s", name, bus_error_message(error, r));
|
||||
assert(name);
|
||||
assert(!isempty(error_id));
|
||||
|
||||
int ret = sd_varlink_error_to_errno(error_id, reply);
|
||||
static const struct {
|
||||
const char *error_id;
|
||||
const char *msg;
|
||||
} error_message_table[] = {
|
||||
{ "io.systemd.Resolve.NoNameServers", "No appropriate name servers or networks for name found" },
|
||||
{ "io.systemd.Resolve.QueryTimedOut", "Query timed out" },
|
||||
{ "io.systemd.Resolve.MaxAttemptsReached", "All attempts to contact name servers or networks failed" },
|
||||
{ "io.systemd.Resolve.InvalidReply", "Received invalid reply" },
|
||||
{ "io.systemd.Resolve.QueryAborted", "Query aborted" },
|
||||
{ "io.systemd.Resolve.QueryRefused", "DNS query type refused" },
|
||||
{ "io.systemd.Resolve.NoTrustAnchor", "No suitable trust anchor known" },
|
||||
{ "io.systemd.Resolve.ResourceRecordTypeUnsupported", "Server does not support requested resource record type" },
|
||||
{ "io.systemd.Resolve.NetworkDown", "Network is down" },
|
||||
{ "io.systemd.Resolve.NoSource", "All suitable resolution sources turned off" },
|
||||
{ "io.systemd.Resolve.StubLoop", "Configured DNS server loops back to us" },
|
||||
{ "io.systemd.Resolve.ZoneTransfersNotPermitted", "Zone transfers not permitted via this programming interface" },
|
||||
};
|
||||
FOREACH_ELEMENT(em, error_message_table)
|
||||
if (streq(em->error_id, error_id))
|
||||
return log_error_errno(ret, "%s: resolve call failed: %s", name, em->msg);
|
||||
|
||||
if (streq(error_id, "io.systemd.Resolve.NoSuchResourceRecord"))
|
||||
return log_error_errno(ret, "%s: resolve call failed: '%s' does not have any RR of the requested type", name, name);
|
||||
|
||||
if (streq(error_id, "io.systemd.Resolve.CNAMELoop"))
|
||||
return log_error_errno(ret, "%s: resolve call failed: CNAME loop detected, or CNAME resolving disabled on '%s'", name, name);
|
||||
|
||||
if (streq(error_id, "io.systemd.Resolve.ServiceNotProvided"))
|
||||
return log_error_errno(ret, "%s: resolve call failed: '%s' does not provide the requested service", name, name);
|
||||
|
||||
if (streq(error_id, "io.systemd.Resolve.InconsistentServiceRecords"))
|
||||
return log_error_errno(ret, "%s: resolve call failed: '%s' does not provide a consistent set of service resource records", name, name);
|
||||
|
||||
_cleanup_(resolve_error_done) ResolveError error = {
|
||||
.rcode = _DNS_RCODE_INVALID,
|
||||
.ede_rcode = _DNS_EDE_RCODE_INVALID,
|
||||
};
|
||||
r = dispatch_resolve_error(/* name = */ NULL, reply, SD_JSON_LOG, &error);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to dispatch error JSON, ignoring: %m");
|
||||
|
||||
_cleanup_free_ char *msg_extended = NULL;
|
||||
if (error.ede_rcode >= 0) {
|
||||
msg_extended = strjoin(" (",
|
||||
FORMAT_DNS_EDE_RCODE(error.ede_rcode),
|
||||
!isempty(error.ede_msg) ? ": " : "",
|
||||
strempty(error.ede_msg),
|
||||
")");
|
||||
if (!msg_extended)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
if (streq(error_id, "io.systemd.Resolve.DNSSECValidationFailed"))
|
||||
return log_error_errno(ret, "%s: resolve call failed: DNSSEC validation failed: %s%s", name, error.result, strempty(msg_extended));
|
||||
|
||||
if (error.rcode != _DNS_RCODE_INVALID) {
|
||||
if (error.rcode == DNS_RCODE_NXDOMAIN)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENXIO), "%s: resolve call failed: Name '%s' not found%s%s",
|
||||
name, error.query_string ?: name, error.ede_rcode >= 0 ? ":" : "", strempty(msg_extended));
|
||||
|
||||
return log_error_errno(ret, "%s: resolve call failed: Could not resolve '%s', server or network returned error: %s%s",
|
||||
name, error.query_string ?: name, FORMAT_DNS_RCODE(error.rcode), strempty(msg_extended));
|
||||
}
|
||||
|
||||
return log_error_errno(ret, "%s: resolve call failed: %s", name, error_id);
|
||||
}
|
||||
|
||||
static int resolve_host(sd_bus *bus, const char *name) {
|
||||
_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;
|
||||
const char *canonical = NULL;
|
||||
unsigned c = 0;
|
||||
uint64_t flags;
|
||||
usec_t ts;
|
||||
static int varlink_connect_with_query_timeout(sd_varlink **vl) {
|
||||
int r;
|
||||
|
||||
assert(vl);
|
||||
|
||||
r = sd_varlink_connect_address(vl, "/run/systemd/resolve/io.systemd.Resolve");
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to connect to service /run/systemd/resolve/io.systemd.Resolve: %m");
|
||||
|
||||
r = sd_varlink_set_relative_timeout(*vl, SD_RESOLVED_QUERY_TIMEOUT_USEC);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set query timeout: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int resolve_host(const char *name) {
|
||||
int r;
|
||||
|
||||
assert(name);
|
||||
@@ -301,85 +379,69 @@ static int resolve_host(sd_bus *bus, const char *name) {
|
||||
|
||||
log_debug("Resolving %s (family %s, interface %s).", name, af_to_name(arg_family) ?: "*", isempty(arg_ifname) ? "*" : arg_ifname);
|
||||
|
||||
r = bus_message_new_method_call(bus, &req, bus_resolve_mgr, "ResolveHostname");
|
||||
_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;
|
||||
|
||||
r = sd_bus_message_append(req, "isit", arg_ifindex, name, arg_family, arg_flags);
|
||||
usec_t ts = now(CLOCK_MONOTONIC);
|
||||
|
||||
const char *error_id = NULL;
|
||||
sd_json_variant *v = NULL;
|
||||
r = sd_varlink_callbo(
|
||||
vl,
|
||||
"io.systemd.Resolve.ResolveHostname",
|
||||
&v,
|
||||
&error_id,
|
||||
SD_JSON_BUILD_PAIR_STRING("name", name),
|
||||
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 bus_log_create_error(r);
|
||||
|
||||
ts = now(CLOCK_MONOTONIC);
|
||||
|
||||
r = sd_bus_call(bus, req, SD_RESOLVED_QUERY_TIMEOUT_USEC, &error, &reply);
|
||||
if (r < 0)
|
||||
return resolve_host_error(name, r, &error);
|
||||
return log_error_errno(r, "Failed to issue varlink call: %m");
|
||||
|
||||
ts = now(CLOCK_MONOTONIC) - ts;
|
||||
|
||||
r = sd_bus_message_enter_container(reply, 'a', "(iiay)");
|
||||
if (!isempty(error_id))
|
||||
return varlink_log_resolve_error(name, error_id, v);
|
||||
|
||||
_cleanup_(resolve_hostname_reply_done) ResolveHostnameReply reply = {};
|
||||
r = dispatch_resolve_hostname_reply(/* name = */ NULL, v, SD_JSON_LOG, &reply);
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
return r;
|
||||
|
||||
while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) {
|
||||
bool first = true;
|
||||
FOREACH_ARRAY(address, reply.addresses, reply.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 %s%s%s",
|
||||
(int) strlen(name), c == 0 ? name : "", c == 0 ? ":" : " ",
|
||||
ansi_highlight(), pretty, ansi_normal());
|
||||
int k = printf("%*s%s %s%s%s",
|
||||
(int) strlen(name),
|
||||
first ? name : "",
|
||||
first ? ":" : " ",
|
||||
ansi_highlight(),
|
||||
pretty,
|
||||
ansi_normal());
|
||||
|
||||
print_ifindex_comment(k, ifindex);
|
||||
print_ifindex_comment(k, address->ifindex);
|
||||
fputc('\n', stdout);
|
||||
|
||||
c++;
|
||||
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, "st", &canonical, &flags);
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
if (!streq(name, canonical))
|
||||
if (!streq(name, reply.name))
|
||||
printf("%*s%s (%s)\n",
|
||||
(int) strlen(name), c == 0 ? name : "", c == 0 ? ":" : " ",
|
||||
canonical);
|
||||
(int) strlen(name),
|
||||
reply.n_addresses == 0 ? name : "",
|
||||
reply.n_addresses == 0 ? ":" : " ",
|
||||
reply.name);
|
||||
|
||||
if (c == 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ESRCH),
|
||||
"%s: no addresses found", name);
|
||||
if (reply.n_addresses == 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ESRCH), "%s: no addresses found", name);
|
||||
|
||||
print_source(flags, ts);
|
||||
print_source(reply.flags, ts);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -827,7 +889,7 @@ static int verb_query(int argc, char *argv[], uintptr_t _data, void *userdata) {
|
||||
if (r >= 0)
|
||||
RET_GATHER(ret, resolve_address(bus, family, &a, ifindex));
|
||||
else
|
||||
RET_GATHER(ret, resolve_host(bus, *p));
|
||||
RET_GATHER(ret, resolve_host(*p));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -185,6 +185,7 @@ shared_sources = files(
|
||||
'resize-fs.c',
|
||||
'resolve-hook-util.c',
|
||||
'resolve-util.c',
|
||||
'resolve-varlink-util.c',
|
||||
'rm-rf.c',
|
||||
'seccomp-util.c',
|
||||
'securebits-util.c',
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "sd-json.h"
|
||||
|
||||
#include "dns-packet.h"
|
||||
#include "json-util.h"
|
||||
#include "resolve-varlink-util.h"
|
||||
|
||||
void resolve_error_done(ResolveError *error) {
|
||||
if (!error)
|
||||
return;
|
||||
|
||||
error->ede_msg = mfree(error->ede_msg);
|
||||
error->query_string = mfree(error->query_string);
|
||||
error->result = mfree(error->result);
|
||||
}
|
||||
|
||||
int dispatch_resolve_error(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
|
||||
static const sd_json_dispatch_field resolve_error_dispatch_table[] = {
|
||||
{ "rcode", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int, offsetof(ResolveError, rcode), 0 },
|
||||
{ "extendedDNSErrorCode", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int, offsetof(ResolveError, ede_rcode), 0 },
|
||||
{ "extendedDNSErrorMessage", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(ResolveError, ede_msg), 0 },
|
||||
{ "queryString", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(ResolveError, query_string), 0 },
|
||||
{ "result", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(ResolveError, result), 0 },
|
||||
{},
|
||||
};
|
||||
ResolveError *ret = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
_cleanup_(resolve_error_done) ResolveError error = {
|
||||
.rcode = _DNS_RCODE_INVALID,
|
||||
.ede_rcode = _DNS_EDE_RCODE_INVALID,
|
||||
};
|
||||
r = sd_json_dispatch(variant, resolve_error_dispatch_table, flags | SD_JSON_ALLOW_EXTENSIONS, &error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*ret = TAKE_STRUCT(error);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dispatch_resolved_address(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
|
||||
static const sd_json_dispatch_field resolved_address_dispatch_table[] = {
|
||||
{ "ifindex", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_ifindex, offsetof(ResolvedAddress, ifindex), SD_JSON_RELAX },
|
||||
{ "family", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_address_family, offsetof(ResolvedAddress, family), SD_JSON_MANDATORY },
|
||||
{ "address", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_in_addr_data, offsetof(ResolvedAddress, in_addr), SD_JSON_MANDATORY },
|
||||
{},
|
||||
};
|
||||
ResolvedAddress *ret = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
ResolvedAddress address = {};
|
||||
r = sd_json_dispatch(variant, resolved_address_dispatch_table, flags & ~SD_JSON_MANDATORY, &address);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (address.family != address.in_addr.family)
|
||||
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "'%s' address and family are inconsistent.", strna(name));
|
||||
|
||||
*ret = TAKE_STRUCT(address);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dispatch_resolved_address_array(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
|
||||
ResolveHostnameReply *reply = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
sd_json_variant *v;
|
||||
JSON_VARIANT_ARRAY_FOREACH(v, variant) {
|
||||
if (!GREEDY_REALLOC0(reply->addresses, reply->n_addresses + 1))
|
||||
return json_log_oom(variant, flags);
|
||||
|
||||
r = dispatch_resolved_address(name, v, flags, &reply->addresses[reply->n_addresses++]);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void resolve_hostname_reply_done(ResolveHostnameReply *reply) {
|
||||
if (!reply)
|
||||
return;
|
||||
|
||||
reply->name = mfree(reply->name);
|
||||
reply->addresses = mfree(reply->addresses);
|
||||
reply->n_addresses = 0;
|
||||
}
|
||||
|
||||
int dispatch_resolve_hostname_reply(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
|
||||
static const sd_json_dispatch_field resolve_hostname_reply_dispatch_table[] = {
|
||||
{ "name", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(ResolveHostnameReply, name), SD_JSON_MANDATORY },
|
||||
{ "flags", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(ResolveHostnameReply, flags), SD_JSON_MANDATORY },
|
||||
{ "addresses", SD_JSON_VARIANT_ARRAY, dispatch_resolved_address_array, 0, SD_JSON_MANDATORY },
|
||||
{},
|
||||
};
|
||||
ResolveHostnameReply *ret = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
_cleanup_(resolve_hostname_reply_done) ResolveHostnameReply reply = {};
|
||||
r = sd_json_dispatch(variant, resolve_hostname_reply_dispatch_table, flags | SD_JSON_ALLOW_EXTENSIONS, &reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*ret = TAKE_STRUCT(reply);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "in-addr-util.h"
|
||||
#include "shared-forward.h"
|
||||
|
||||
typedef struct ResolveError {
|
||||
int rcode;
|
||||
int ede_rcode;
|
||||
char *ede_msg;
|
||||
char *query_string;
|
||||
char *result;
|
||||
} ResolveError;
|
||||
|
||||
void resolve_error_done(ResolveError *error);
|
||||
|
||||
int dispatch_resolve_error(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
|
||||
|
||||
typedef struct ResolvedAddress {
|
||||
int ifindex;
|
||||
int family;
|
||||
struct in_addr_data in_addr;
|
||||
} ResolvedAddress;
|
||||
|
||||
typedef struct ResolveHostnameReply {
|
||||
char *name;
|
||||
uint64_t flags;
|
||||
ResolvedAddress *addresses;
|
||||
size_t n_addresses;
|
||||
} ResolveHostnameReply;
|
||||
|
||||
void resolve_hostname_reply_done(ResolveHostnameReply *reply);
|
||||
|
||||
int dispatch_resolve_hostname_reply(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
|
||||
Reference in New Issue
Block a user