Compare commits
13 Commits
b6abc2acb4
...
e8607daf7d
Author | SHA1 | Date |
---|---|---|
PhoenixDiscord | e8607daf7d | |
Chris Down | 33e1a5d8d3 | |
Zbigniew Jędrzejewski-Szmek | bb2aee7d11 | |
Lennart Poettering | 0c73f4f075 | |
Lennart Poettering | 9581bb8424 | |
Lennart Poettering | c17b5ce739 | |
Lennart Poettering | 65a01e8242 | |
Lennart Poettering | c9de4e0f5b | |
Lennart Poettering | d4f72f0d21 | |
Lennart Poettering | b97e3e3d7a | |
Lennart Poettering | 0710343ce7 | |
Lennart Poettering | 7466e94f13 | |
Lennart Poettering | c7dfa1df8b |
|
@ -196,8 +196,8 @@ The currently used part of the file is the **header_size** plus the
|
|||
**arena_size** field of the header. If a writer needs to write to a file where
|
||||
the actual file size on disk is smaller than the reported value it shall
|
||||
immediately rotate the file and start a new one. If a writer is asked to write
|
||||
to a file with a header that is shorter than his own definition of the struct
|
||||
Header, he shall immediately rotate the file and start a new one.
|
||||
to a file with a header that is shorter than its own definition of the struct
|
||||
Header, it shall immediately rotate the file and start a new one.
|
||||
|
||||
The **n_objects** field contains a counter for objects currently available in
|
||||
this file. As objects are appended to the end of the file this counter is
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
union in_addr_union {
|
||||
struct in_addr in;
|
||||
struct in6_addr in6;
|
||||
uint8_t bytes[CONST_MAX(sizeof(struct in_addr), sizeof(struct in6_addr))];
|
||||
};
|
||||
|
||||
struct in_addr_data {
|
||||
|
|
|
@ -21,7 +21,7 @@ struct LookupPaths {
|
|||
char **search_path;
|
||||
|
||||
/* Where we shall create or remove our installation symlinks, aka "configuration", and where the user/admin
|
||||
* shall place his own unit files. */
|
||||
* shall place their own unit files. */
|
||||
char *persistent_config;
|
||||
char *runtime_config;
|
||||
|
||||
|
|
|
@ -638,16 +638,27 @@ int find_binary(const char *name, char **ret) {
|
|||
if (!j)
|
||||
return -ENOMEM;
|
||||
|
||||
if (is_dir(j, true))
|
||||
continue;
|
||||
|
||||
if (access(j, X_OK) >= 0) {
|
||||
/* Found it! */
|
||||
_cleanup_free_ char *with_dash;
|
||||
|
||||
if (ret)
|
||||
*ret = path_simplify(TAKE_PTR(j), false);
|
||||
with_dash = strjoin(j, "/");
|
||||
if (!with_dash)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
/* If this passes, it must be a directory, and so should be skipped. */
|
||||
if (access(with_dash, X_OK) >= 0)
|
||||
continue;
|
||||
|
||||
/**
|
||||
* We can't just `continue` inverting this case, since we need to update last_error.
|
||||
*/
|
||||
if (errno == ENOTDIR) {
|
||||
/* Found it! */
|
||||
if (ret)
|
||||
*ret = path_simplify(TAKE_PTR(j), false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* PATH entries which we don't have access to are ignored, as per tradition. */
|
||||
|
|
|
@ -65,7 +65,7 @@ int procfs_tasks_set_limit(uint64_t limit) {
|
|||
|
||||
if (limit == 0) /* This makes no sense, we are userspace and hence count as tasks too, and we want to live,
|
||||
* hence the limit conceptually has to be above 0. Also, most likely if anyone asks for a zero
|
||||
* limit he/she probably means "no limit", hence let's better refuse this to avoid
|
||||
* limit they probably mean "no limit", hence let's better refuse this to avoid
|
||||
* confusion. */
|
||||
return -EINVAL;
|
||||
|
||||
|
|
|
@ -412,7 +412,7 @@ static int acquire_path(const char *path, int flags, mode_t mode) {
|
|||
|
||||
if (connect(fd, &sa.sa, sa_len) < 0)
|
||||
return errno == EINVAL ? -ENXIO : -errno; /* Propagate initial error if we get EINVAL, i.e. we have
|
||||
* indication that his wasn't an AF_UNIX socket after all */
|
||||
* indication that this wasn't an AF_UNIX socket after all */
|
||||
|
||||
if ((flags & O_ACCMODE) == O_RDONLY)
|
||||
r = shutdown(fd, SHUT_WR);
|
||||
|
|
|
@ -1337,7 +1337,7 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
return log_oom();
|
||||
|
||||
/* If the user asked for a particular
|
||||
* property, show it to him, even if it is
|
||||
* property, show it to them, even if it is
|
||||
* empty. */
|
||||
arg_all = true;
|
||||
break;
|
||||
|
|
|
@ -2672,7 +2672,7 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
return log_oom();
|
||||
|
||||
/* If the user asked for a particular
|
||||
* property, show it to him, even if it is
|
||||
* property, show it to them, even if it is
|
||||
* empty. */
|
||||
arg_all = true;
|
||||
break;
|
||||
|
|
|
@ -7,10 +7,6 @@
|
|||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "sd-bus.h"
|
||||
|
||||
#include "bus-common-errors.h"
|
||||
#include "bus-locator.h"
|
||||
#include "errno-util.h"
|
||||
#include "in-addr-util.h"
|
||||
#include "macro.h"
|
||||
|
@ -18,69 +14,36 @@
|
|||
#include "resolved-def.h"
|
||||
#include "signal-util.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
#include "varlink.h"
|
||||
|
||||
NSS_GETHOSTBYNAME_PROTOTYPES(resolve);
|
||||
NSS_GETHOSTBYADDR_PROTOTYPES(resolve);
|
||||
|
||||
static bool bus_error_shall_fallback(sd_bus_error *e) {
|
||||
return sd_bus_error_has_names(e,
|
||||
SD_BUS_ERROR_SERVICE_UNKNOWN,
|
||||
SD_BUS_ERROR_NAME_HAS_NO_OWNER,
|
||||
SD_BUS_ERROR_NO_REPLY,
|
||||
SD_BUS_ERROR_ACCESS_DENIED,
|
||||
SD_BUS_ERROR_DISCONNECTED,
|
||||
SD_BUS_ERROR_TIMEOUT,
|
||||
BUS_ERROR_NO_SUCH_UNIT);
|
||||
static bool error_shall_fallback(const char *error_id) {
|
||||
return STR_IN_SET(error_id,
|
||||
VARLINK_ERROR_DISCONNECTED,
|
||||
VARLINK_ERROR_TIMEOUT,
|
||||
VARLINK_ERROR_PROTOCOL,
|
||||
VARLINK_ERROR_INTERFACE_NOT_FOUND,
|
||||
VARLINK_ERROR_METHOD_NOT_FOUND,
|
||||
VARLINK_ERROR_METHOD_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
static int count_addresses(sd_bus_message *m, int af, const char **canonical) {
|
||||
int c = 0, r;
|
||||
static int connect_to_resolved(Varlink **ret) {
|
||||
_cleanup_(varlink_unrefp) Varlink *link = NULL;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(canonical);
|
||||
|
||||
r = sd_bus_message_enter_container(m, 'a', "(iiay)");
|
||||
r = varlink_connect_address(&link, "/run/systemd/resolve/io.systemd.Resolve");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
while ((r = sd_bus_message_enter_container(m, 'r', "iiay")) > 0) {
|
||||
int family, ifindex;
|
||||
|
||||
assert_cc(sizeof(int32_t) == sizeof(int));
|
||||
|
||||
r = sd_bus_message_read(m, "ii", &ifindex, &family);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_skip(m, "ay");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_exit_container(m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (af != AF_UNSPEC && family != af)
|
||||
continue;
|
||||
|
||||
c++;
|
||||
}
|
||||
r = varlink_set_relative_timeout(link, SD_RESOLVED_QUERY_TIMEOUT_USEC);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_exit_container(m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_read(m, "s", canonical);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_rewind(m, true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return c;
|
||||
*ret = TAKE_PTR(link);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t ifindex_to_scopeid(int family, const void *a, int ifindex) {
|
||||
|
@ -97,20 +60,111 @@ static uint32_t ifindex_to_scopeid(int family, const void *a, int ifindex) {
|
|||
return IN6_IS_ADDR_LINKLOCAL(&in6) ? ifindex : 0;
|
||||
}
|
||||
|
||||
static bool avoid_deadlock(void) {
|
||||
static int json_dispatch_ifindex(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
|
||||
int *ifi = userdata;
|
||||
intmax_t t;
|
||||
|
||||
/* Check whether this lookup might have a chance of deadlocking because we are called from the service manager
|
||||
* code activating systemd-resolved.service. After all, we shouldn't synchronously do lookups to
|
||||
* systemd-resolved if we are required to finish before it can be started. This of course won't detect all
|
||||
* possible dead locks of this kind, but it should work for the most obvious cases. */
|
||||
assert(variant);
|
||||
assert(ifi);
|
||||
|
||||
if (geteuid() != 0) /* Ignore the env vars unless we are privileged. */
|
||||
return false;
|
||||
if (!json_variant_is_integer(variant))
|
||||
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an integer.", strna(name));
|
||||
|
||||
return streq_ptr(getenv("SYSTEMD_ACTIVATION_UNIT"), "systemd-resolved.service") &&
|
||||
streq_ptr(getenv("SYSTEMD_ACTIVATION_SCOPE"), "system");
|
||||
t = json_variant_integer(variant);
|
||||
if (t <= 0 || t > INT_MAX)
|
||||
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is out of bounds for an interface index.", strna(name));
|
||||
|
||||
*ifi = (int) t;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int json_dispatch_family(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
|
||||
int *family = userdata;
|
||||
intmax_t t;
|
||||
|
||||
assert(variant);
|
||||
assert(family);
|
||||
|
||||
if (!json_variant_is_integer(variant))
|
||||
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an integer.", strna(name));
|
||||
|
||||
t = json_variant_integer(variant);
|
||||
if (t < 0 || t > INT_MAX)
|
||||
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a valid family.", strna(name));
|
||||
|
||||
*family = (int) t;
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef struct ResolveHostnameReply {
|
||||
JsonVariant *addresses;
|
||||
char *name;
|
||||
uint64_t flags;
|
||||
} ResolveHostnameReply;
|
||||
|
||||
static void resolve_hostname_reply_destroy(ResolveHostnameReply *p) {
|
||||
assert(p);
|
||||
|
||||
json_variant_unref(p->addresses);
|
||||
free(p->name);
|
||||
}
|
||||
|
||||
static const JsonDispatch resolve_hostname_reply_dispatch_table[] = {
|
||||
{ "addresses", JSON_VARIANT_ARRAY, json_dispatch_variant, offsetof(ResolveHostnameReply, addresses), JSON_MANDATORY },
|
||||
{ "name", JSON_VARIANT_STRING, json_dispatch_string, offsetof(ResolveHostnameReply, name), 0 },
|
||||
{ "flags", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(ResolveHostnameReply, flags), 0 },
|
||||
{}
|
||||
};
|
||||
|
||||
typedef struct AddressParameters {
|
||||
int ifindex;
|
||||
int family;
|
||||
union in_addr_union address;
|
||||
size_t address_size;
|
||||
} AddressParameters;
|
||||
|
||||
static int json_dispatch_address(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
|
||||
AddressParameters *p = userdata;
|
||||
union in_addr_union buf = {};
|
||||
JsonVariant *i;
|
||||
size_t n, k = 0;
|
||||
|
||||
assert(variant);
|
||||
assert(p);
|
||||
|
||||
if (!json_variant_is_array(variant))
|
||||
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an array.", strna(name));
|
||||
|
||||
n = json_variant_elements(variant);
|
||||
if (!IN_SET(n, 4, 16))
|
||||
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is array of unexpected size.", strna(name));
|
||||
|
||||
JSON_VARIANT_ARRAY_FOREACH(i, variant) {
|
||||
intmax_t b;
|
||||
|
||||
if (!json_variant_is_integer(i))
|
||||
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "Element %zu of JSON field '%s' is not an integer.", k, strna(name));
|
||||
|
||||
b = json_variant_integer(i);
|
||||
if (b < 0 || b > 0xff)
|
||||
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "Element %zu of JSON field '%s' is out of range 0…255.", k, strna(name));
|
||||
|
||||
buf.bytes[k++] = (uint8_t) b;
|
||||
}
|
||||
|
||||
p->address = buf;
|
||||
p->address_size = k;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const JsonDispatch address_parameters_dispatch_table[] = {
|
||||
{ "ifindex", JSON_VARIANT_INTEGER, json_dispatch_ifindex, offsetof(AddressParameters, ifindex), 0 },
|
||||
{ "family", JSON_VARIANT_INTEGER, json_dispatch_family, offsetof(AddressParameters, family), JSON_MANDATORY },
|
||||
{ "address", JSON_VARIANT_ARRAY, json_dispatch_address, 0, JSON_MANDATORY },
|
||||
{}
|
||||
};
|
||||
|
||||
enum nss_status _nss_resolve_gethostbyname4_r(
|
||||
const char *name,
|
||||
struct gaih_addrtuple **pat,
|
||||
|
@ -118,14 +172,15 @@ enum nss_status _nss_resolve_gethostbyname4_r(
|
|||
int *errnop, int *h_errnop,
|
||||
int32_t *ttlp) {
|
||||
|
||||
_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;
|
||||
struct gaih_addrtuple *r_tuple, *r_tuple_first = NULL;
|
||||
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
||||
const char *canonical = NULL;
|
||||
size_t l, ms, idx;
|
||||
_cleanup_(resolve_hostname_reply_destroy) ResolveHostnameReply p = {};
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *cparams = NULL;
|
||||
struct gaih_addrtuple *r_tuple = NULL, *r_tuple_first = NULL;
|
||||
_cleanup_(varlink_unrefp) Varlink *link = NULL;
|
||||
const char *canonical = NULL, *error_id = NULL;
|
||||
JsonVariant *entry, *rparams;
|
||||
size_t l, ms, idx, c = 0;
|
||||
char *r_name;
|
||||
int c, r, i = 0;
|
||||
int r;
|
||||
|
||||
PROTECT_ERRNO;
|
||||
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
|
||||
|
@ -136,50 +191,53 @@ enum nss_status _nss_resolve_gethostbyname4_r(
|
|||
assert(errnop);
|
||||
assert(h_errnop);
|
||||
|
||||
if (avoid_deadlock()) {
|
||||
r = -EDEADLK;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = sd_bus_open_system(&bus);
|
||||
r = connect_to_resolved(&link);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
r = bus_message_new_method_call(bus, &req, bus_resolve_mgr, "ResolveHostname");
|
||||
r = json_build(&cparams, JSON_BUILD_OBJECT(
|
||||
JSON_BUILD_PAIR("name", JSON_BUILD_STRING(name))));
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
r = sd_bus_message_set_auto_start(req, false);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
r = sd_bus_message_append(req, "isit", 0, name, AF_UNSPEC, (uint64_t) 0);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
r = sd_bus_call(bus, req, SD_RESOLVED_QUERY_TIMEOUT_USEC, &error, &reply);
|
||||
r = varlink_call(link, "io.systemd.Resolve.ResolveHostname", cparams, &rparams, &error_id, NULL);
|
||||
if (r < 0) {
|
||||
if (!bus_error_shall_fallback(&error))
|
||||
if (!error_shall_fallback(error_id))
|
||||
goto not_found;
|
||||
|
||||
/* Return NSS_STATUS_UNAVAIL when communication with systemd-resolved fails,
|
||||
allowing falling back to other nss modules. Treat all other error conditions as
|
||||
NOTFOUND. This includes DNSSEC errors and suchlike. (We don't use UNAVAIL in this
|
||||
case so that the nsswitch.conf configuration can distinguish such executed but
|
||||
negative replies from complete failure to talk to resolved). */
|
||||
/* Return NSS_STATUS_UNAVAIL when communication with systemd-resolved fails, allowing falling
|
||||
back to other nss modules. Treat all other error conditions as NOTFOUND. This includes
|
||||
DNSSEC errors and suchlike. (We don't use UNAVAIL in this case so that the nsswitch.conf
|
||||
configuration can distinguish such executed but negative replies from complete failure to
|
||||
talk to resolved). */
|
||||
goto fail;
|
||||
}
|
||||
|
||||
c = count_addresses(reply, AF_UNSPEC, &canonical);
|
||||
if (c < 0) {
|
||||
r = c;
|
||||
r = json_dispatch(rparams, resolve_hostname_reply_dispatch_table, NULL, 0, &p);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
}
|
||||
if (c == 0)
|
||||
if (json_variant_is_blank_object(p.addresses))
|
||||
goto not_found;
|
||||
|
||||
if (isempty(canonical))
|
||||
canonical = name;
|
||||
JSON_VARIANT_ARRAY_FOREACH(entry, p.addresses) {
|
||||
AddressParameters q = {};
|
||||
|
||||
r = json_dispatch(entry, address_parameters_dispatch_table, NULL, 0, &q);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
if (!IN_SET(q.family, AF_INET, AF_INET6))
|
||||
continue;
|
||||
|
||||
if (q.address_size != FAMILY_ADDRESS_SIZE(q.family)) {
|
||||
r = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
c++;
|
||||
}
|
||||
|
||||
canonical = p.name ?: name;
|
||||
|
||||
l = strlen(canonical);
|
||||
ms = ALIGN(l+1) + ALIGN(sizeof(struct gaih_addrtuple)) * c;
|
||||
|
@ -198,56 +256,29 @@ enum nss_status _nss_resolve_gethostbyname4_r(
|
|||
/* Second, append addresses */
|
||||
r_tuple_first = (struct gaih_addrtuple*) (buffer + idx);
|
||||
|
||||
r = sd_bus_message_enter_container(reply, 'a', "(iiay)");
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
JSON_VARIANT_ARRAY_FOREACH(entry, p.addresses) {
|
||||
AddressParameters q = {};
|
||||
|
||||
while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) {
|
||||
int family, ifindex;
|
||||
const void *a;
|
||||
size_t sz;
|
||||
|
||||
assert_cc(sizeof(int32_t) == sizeof(int));
|
||||
|
||||
r = sd_bus_message_read(reply, "ii", &ifindex, &family);
|
||||
r = json_dispatch(entry, address_parameters_dispatch_table, NULL, 0, &q);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
if (ifindex < 0) {
|
||||
r = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = sd_bus_message_read_array(reply, 'y', &a, &sz);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
r = sd_bus_message_exit_container(reply);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
if (!IN_SET(family, AF_INET, AF_INET6))
|
||||
if (!IN_SET(q.family, AF_INET, AF_INET6))
|
||||
continue;
|
||||
|
||||
if (sz != FAMILY_ADDRESS_SIZE(family)) {
|
||||
r = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r_tuple = (struct gaih_addrtuple*) (buffer + idx);
|
||||
r_tuple->next = i == c-1 ? NULL : (struct gaih_addrtuple*) ((char*) r_tuple + ALIGN(sizeof(struct gaih_addrtuple)));
|
||||
r_tuple->next = (struct gaih_addrtuple*) ((char*) r_tuple + ALIGN(sizeof(struct gaih_addrtuple)));
|
||||
r_tuple->name = r_name;
|
||||
r_tuple->family = family;
|
||||
r_tuple->scopeid = ifindex_to_scopeid(family, a, ifindex);
|
||||
memcpy(r_tuple->addr, a, sz);
|
||||
r_tuple->family = q.family;
|
||||
r_tuple->scopeid = ifindex_to_scopeid(q.family, &q.address, q.ifindex);
|
||||
memcpy(r_tuple->addr, &q.address, q.address_size);
|
||||
|
||||
idx += ALIGN(sizeof(struct gaih_addrtuple));
|
||||
i++;
|
||||
}
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
assert(i == c);
|
||||
assert(r_tuple);
|
||||
r_tuple->next = NULL; /* Override last next pointer */
|
||||
|
||||
assert(idx == ms);
|
||||
|
||||
if (*pat)
|
||||
|
@ -285,13 +316,14 @@ enum nss_status _nss_resolve_gethostbyname3_r(
|
|||
int32_t *ttlp,
|
||||
char **canonp) {
|
||||
|
||||
_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;
|
||||
_cleanup_(resolve_hostname_reply_destroy) ResolveHostnameReply p = {};
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *cparams = NULL;
|
||||
char *r_name, *r_aliases, *r_addr, *r_addr_list;
|
||||
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
||||
size_t l, idx, ms, alen;
|
||||
const char *canonical;
|
||||
int c, r, i = 0;
|
||||
_cleanup_(varlink_unrefp) Varlink *link = NULL;
|
||||
const char *canonical, *error_id = NULL;
|
||||
size_t l, idx, ms, alen, i = 0, c = 0;
|
||||
JsonVariant *entry, *rparams;
|
||||
int r;
|
||||
|
||||
PROTECT_ERRNO;
|
||||
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
|
||||
|
@ -310,50 +342,53 @@ enum nss_status _nss_resolve_gethostbyname3_r(
|
|||
goto fail;
|
||||
}
|
||||
|
||||
if (avoid_deadlock()) {
|
||||
r = -EDEADLK;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = sd_bus_open_system(&bus);
|
||||
r = connect_to_resolved(&link);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
r = bus_message_new_method_call(bus, &req, bus_resolve_mgr, "ResolveHostname");
|
||||
r = json_build(&cparams, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("name", JSON_BUILD_STRING(name)),
|
||||
JSON_BUILD_PAIR("family", JSON_BUILD_INTEGER(af))));
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
r = sd_bus_message_set_auto_start(req, false);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
r = sd_bus_message_append(req, "isit", 0, name, af, (uint64_t) 0);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
r = sd_bus_call(bus, req, SD_RESOLVED_QUERY_TIMEOUT_USEC, &error, &reply);
|
||||
r = varlink_call(link, "io.systemd.Resolve.ResolveHostname", cparams, &rparams, &error_id, NULL);
|
||||
if (r < 0) {
|
||||
if (!bus_error_shall_fallback(&error))
|
||||
if (!error_shall_fallback(error_id))
|
||||
goto not_found;
|
||||
|
||||
goto fail;
|
||||
}
|
||||
|
||||
c = count_addresses(reply, af, &canonical);
|
||||
if (c < 0) {
|
||||
r = c;
|
||||
r = json_dispatch(rparams, resolve_hostname_reply_dispatch_table, NULL, 0, &p);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
}
|
||||
if (c == 0)
|
||||
if (json_variant_is_blank_object(p.addresses))
|
||||
goto not_found;
|
||||
|
||||
if (isempty(canonical))
|
||||
canonical = name;
|
||||
JSON_VARIANT_ARRAY_FOREACH(entry, p.addresses) {
|
||||
AddressParameters q = {};
|
||||
|
||||
r = json_dispatch(entry, address_parameters_dispatch_table, NULL, 0, &q);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
if (!IN_SET(q.family, AF_INET, AF_INET6))
|
||||
continue;
|
||||
|
||||
if (q.address_size != FAMILY_ADDRESS_SIZE(q.family)) {
|
||||
r = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
c++;
|
||||
}
|
||||
|
||||
canonical = p.name ?: name;
|
||||
|
||||
alen = FAMILY_ADDRESS_SIZE(af);
|
||||
l = strlen(canonical);
|
||||
|
||||
ms = ALIGN(l+1) + c * ALIGN(alen) + (c+2) * sizeof(char*);
|
||||
ms = ALIGN(l+1) + c*ALIGN(alen) + (c+2) * sizeof(char*);
|
||||
|
||||
if (buflen < ms) {
|
||||
UNPROTECT_ERRNO;
|
||||
|
@ -375,45 +410,24 @@ enum nss_status _nss_resolve_gethostbyname3_r(
|
|||
/* Third, append addresses */
|
||||
r_addr = buffer + idx;
|
||||
|
||||
r = sd_bus_message_enter_container(reply, 'a', "(iiay)");
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
JSON_VARIANT_ARRAY_FOREACH(entry, p.addresses) {
|
||||
AddressParameters q = {};
|
||||
|
||||
while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) {
|
||||
int ifindex, family;
|
||||
const void *a;
|
||||
size_t sz;
|
||||
|
||||
r = sd_bus_message_read(reply, "ii", &ifindex, &family);
|
||||
r = json_dispatch(entry, address_parameters_dispatch_table, NULL, 0, &q);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
if (ifindex < 0) {
|
||||
r = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = sd_bus_message_read_array(reply, 'y', &a, &sz);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
r = sd_bus_message_exit_container(reply);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
if (family != af)
|
||||
if (q.family != af)
|
||||
continue;
|
||||
|
||||
if (sz != alen) {
|
||||
if (q.address_size != alen) {
|
||||
r = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
memcpy(r_addr + i*ALIGN(alen), a, alen);
|
||||
memcpy(r_addr + i*ALIGN(alen), &q.address, alen);
|
||||
i++;
|
||||
}
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
assert(i == c);
|
||||
idx += c * ALIGN(alen);
|
||||
|
@ -458,6 +472,40 @@ not_found:
|
|||
return NSS_STATUS_NOTFOUND;
|
||||
}
|
||||
|
||||
typedef struct ResolveAddressReply {
|
||||
JsonVariant *names;
|
||||
uint64_t flags;
|
||||
} ResolveAddressReply;
|
||||
|
||||
static void resolve_address_reply_destroy(ResolveAddressReply *p) {
|
||||
assert(p);
|
||||
|
||||
json_variant_unref(p->names);
|
||||
}
|
||||
|
||||
static const JsonDispatch resolve_address_reply_dispatch_table[] = {
|
||||
{ "names", JSON_VARIANT_ARRAY, json_dispatch_variant, offsetof(ResolveAddressReply, names), JSON_MANDATORY },
|
||||
{ "flags", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(ResolveAddressReply, flags), 0 },
|
||||
{}
|
||||
};
|
||||
|
||||
typedef struct NameParameters {
|
||||
int ifindex;
|
||||
char *name;
|
||||
} NameParameters;
|
||||
|
||||
static void name_parameters_destroy(NameParameters *p) {
|
||||
assert(p);
|
||||
|
||||
free(p->name);
|
||||
}
|
||||
|
||||
static const JsonDispatch name_parameters_dispatch_table[] = {
|
||||
{ "ifindex", JSON_VARIANT_INTEGER, json_dispatch_ifindex, offsetof(NameParameters, ifindex), 0 },
|
||||
{ "name", JSON_VARIANT_UNSIGNED, json_dispatch_string, offsetof(NameParameters, name), JSON_MANDATORY },
|
||||
{}
|
||||
};
|
||||
|
||||
enum nss_status _nss_resolve_gethostbyaddr2_r(
|
||||
const void* addr, socklen_t len,
|
||||
int af,
|
||||
|
@ -466,14 +514,15 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
|
|||
int *errnop, int *h_errnop,
|
||||
int32_t *ttlp) {
|
||||
|
||||
_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;
|
||||
_cleanup_(resolve_address_reply_destroy) ResolveAddressReply p = {};
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *cparams = NULL;
|
||||
char *r_name, *r_aliases, *r_addr, *r_addr_list;
|
||||
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
||||
_cleanup_(varlink_unrefp) Varlink *link = NULL;
|
||||
JsonVariant *entry, *rparams;
|
||||
const char *n, *error_id;
|
||||
unsigned c = 0, i = 0;
|
||||
size_t ms = 0, idx;
|
||||
const char *n;
|
||||
int r, ifindex;
|
||||
int r;
|
||||
|
||||
PROTECT_ERRNO;
|
||||
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
|
||||
|
@ -496,70 +545,42 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
|
|||
goto fail;
|
||||
}
|
||||
|
||||
if (avoid_deadlock()) {
|
||||
r = -EDEADLK;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = sd_bus_open_system(&bus);
|
||||
r = connect_to_resolved(&link);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
r = bus_message_new_method_call(bus, &req, bus_resolve_mgr, "ResolveAddress");
|
||||
r = json_build(&cparams, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("address", JSON_BUILD_BYTE_ARRAY(addr, len)),
|
||||
JSON_BUILD_PAIR("family", JSON_BUILD_INTEGER(af))));
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
r = sd_bus_message_set_auto_start(req, false);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
r = sd_bus_message_append(req, "ii", 0, af);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
r = sd_bus_message_append_array(req, 'y', addr, len);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
r = sd_bus_message_append(req, "t", (uint64_t) 0);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
r = sd_bus_call(bus, req, SD_RESOLVED_QUERY_TIMEOUT_USEC, &error, &reply);
|
||||
r = varlink_call(link, "io.systemd.Resolve.ResolveAddress", cparams, &rparams, &error_id, NULL);
|
||||
if (r < 0) {
|
||||
if (!bus_error_shall_fallback(&error))
|
||||
if (!error_shall_fallback(error_id))
|
||||
goto not_found;
|
||||
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = sd_bus_message_enter_container(reply, 'a', "(is)");
|
||||
r = json_dispatch(rparams, resolve_address_reply_dispatch_table, NULL, 0, &p);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
while ((r = sd_bus_message_read(reply, "(is)", &ifindex, &n)) > 0) {
|
||||
|
||||
if (ifindex < 0) {
|
||||
r = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
c++;
|
||||
ms += ALIGN(strlen(n) + 1);
|
||||
}
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
r = sd_bus_message_rewind(reply, false);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
if (c <= 0)
|
||||
if (json_variant_is_blank_object(p.names))
|
||||
goto not_found;
|
||||
|
||||
ms += ALIGN(len) + /* the address */
|
||||
2 * sizeof(char*) + /* pointers to the address, plus trailing NULL */
|
||||
c * sizeof(char*); /* pointers to aliases, plus trailing NULL */
|
||||
JSON_VARIANT_ARRAY_FOREACH(entry, p.names) {
|
||||
_cleanup_(name_parameters_destroy) NameParameters q = {};
|
||||
|
||||
r = json_dispatch(entry, name_parameters_dispatch_table, NULL, 0, &q);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
ms += ALIGN(strlen(q.name) + 1);
|
||||
}
|
||||
|
||||
ms += ALIGN(len) + /* the address */
|
||||
2 * sizeof(char*) + /* pointers to the address, plus trailing NULL */
|
||||
json_variant_elements(p.names) * sizeof(char*); /* pointers to aliases, plus trailing NULL */
|
||||
|
||||
if (buflen < ms) {
|
||||
UNPROTECT_ERRNO;
|
||||
|
@ -586,22 +607,25 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
|
|||
/* Fourth, place aliases */
|
||||
i = 0;
|
||||
r_name = buffer + idx;
|
||||
while ((r = sd_bus_message_read(reply, "(is)", &ifindex, &n)) > 0) {
|
||||
char *p;
|
||||
JSON_VARIANT_ARRAY_FOREACH(entry, p.names) {
|
||||
_cleanup_(name_parameters_destroy) NameParameters q = {};
|
||||
size_t l;
|
||||
char *z;
|
||||
|
||||
l = strlen(n);
|
||||
p = buffer + idx;
|
||||
memcpy(p, n, l+1);
|
||||
r = json_dispatch(entry, name_parameters_dispatch_table, NULL, 0, &q);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
l = strlen(q.name);
|
||||
z = buffer + idx;
|
||||
memcpy(z, n, l+1);
|
||||
|
||||
if (i > 0)
|
||||
((char**) r_aliases)[i-1] = p;
|
||||
((char**) r_aliases)[i-1] = z;
|
||||
i++;
|
||||
|
||||
idx += ALIGN(l+1);
|
||||
}
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
((char**) r_aliases)[c-1] = NULL;
|
||||
assert(idx == ms);
|
||||
|
|
|
@ -17,53 +17,55 @@ basic_dns_sources = files('''
|
|||
dns_type_h = files('dns-type.h')[0]
|
||||
|
||||
systemd_resolved_sources = files('''
|
||||
resolved.c
|
||||
resolved-manager.c
|
||||
resolved-manager.h
|
||||
resolved-dnssd.c
|
||||
resolved-dnssd.h
|
||||
resolved-dnssd-bus.c
|
||||
resolved-dnssd-bus.h
|
||||
resolved-conf.c
|
||||
resolved-conf.h
|
||||
resolved-resolv-conf.c
|
||||
resolved-resolv-conf.h
|
||||
resolved-bus.c
|
||||
resolved-bus.h
|
||||
resolved-link.h
|
||||
resolved-link.c
|
||||
resolved-conf.c
|
||||
resolved-conf.h
|
||||
resolved-def.h
|
||||
resolved-dns-cache.c
|
||||
resolved-dns-cache.h
|
||||
resolved-dns-query.c
|
||||
resolved-dns-query.h
|
||||
resolved-dns-scope.c
|
||||
resolved-dns-scope.h
|
||||
resolved-dns-search-domain.c
|
||||
resolved-dns-search-domain.h
|
||||
resolved-dns-server.c
|
||||
resolved-dns-server.h
|
||||
resolved-dns-stream.c
|
||||
resolved-dns-stream.h
|
||||
resolved-dns-stub.c
|
||||
resolved-dns-stub.h
|
||||
resolved-dns-synthesize.c
|
||||
resolved-dns-synthesize.h
|
||||
resolved-dns-transaction.c
|
||||
resolved-dns-transaction.h
|
||||
resolved-dns-trust-anchor.c
|
||||
resolved-dns-trust-anchor.h
|
||||
resolved-dns-zone.c
|
||||
resolved-dns-zone.h
|
||||
resolved-dnssd-bus.c
|
||||
resolved-dnssd-bus.h
|
||||
resolved-dnssd.c
|
||||
resolved-dnssd.h
|
||||
resolved-dnstls.h
|
||||
resolved-etc-hosts.c
|
||||
resolved-etc-hosts.h
|
||||
resolved-link-bus.c
|
||||
resolved-link-bus.h
|
||||
resolved-llmnr.h
|
||||
resolved-link.c
|
||||
resolved-link.h
|
||||
resolved-llmnr.c
|
||||
resolved-mdns.h
|
||||
resolved-llmnr.h
|
||||
resolved-manager.c
|
||||
resolved-manager.h
|
||||
resolved-mdns.c
|
||||
resolved-def.h
|
||||
resolved-dns-query.h
|
||||
resolved-dns-query.c
|
||||
resolved-dns-synthesize.h
|
||||
resolved-dns-synthesize.c
|
||||
resolved-dns-transaction.h
|
||||
resolved-dns-transaction.c
|
||||
resolved-dns-scope.h
|
||||
resolved-dns-scope.c
|
||||
resolved-dns-server.h
|
||||
resolved-dns-server.c
|
||||
resolved-dns-search-domain.h
|
||||
resolved-dns-search-domain.c
|
||||
resolved-dns-cache.h
|
||||
resolved-dns-cache.c
|
||||
resolved-dns-zone.h
|
||||
resolved-dns-zone.c
|
||||
resolved-dns-stream.h
|
||||
resolved-dns-stream.c
|
||||
resolved-dns-trust-anchor.h
|
||||
resolved-dns-trust-anchor.c
|
||||
resolved-dns-stub.h
|
||||
resolved-dns-stub.c
|
||||
resolved-etc-hosts.h
|
||||
resolved-etc-hosts.c
|
||||
resolved-dnstls.h
|
||||
resolved-mdns.h
|
||||
resolved-resolv-conf.c
|
||||
resolved-resolv-conf.h
|
||||
resolved-varlink.c
|
||||
resolved-varlink.h
|
||||
resolved.c
|
||||
'''.split())
|
||||
|
||||
resolvectl_sources = files('''
|
||||
|
|
|
@ -24,45 +24,81 @@
|
|||
|
||||
BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_resolve_support, resolve_support, ResolveSupport);
|
||||
|
||||
static int query_on_bus_track(sd_bus_track *t, void *userdata) {
|
||||
DnsQuery *q = userdata;
|
||||
|
||||
assert(t);
|
||||
assert(q);
|
||||
|
||||
if (!DNS_TRANSACTION_IS_LIVE(q->state))
|
||||
return 0;
|
||||
|
||||
log_debug("Client of active query vanished, aborting query.");
|
||||
dns_query_complete(q, DNS_TRANSACTION_ABORTED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dns_query_bus_track(DnsQuery *q, sd_bus_message *m) {
|
||||
int r;
|
||||
|
||||
assert(q);
|
||||
assert(m);
|
||||
|
||||
if (!q->bus_track) {
|
||||
r = sd_bus_track_new(sd_bus_message_get_bus(m), &q->bus_track, query_on_bus_track, q);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_bus_track_add_sender(q->bus_track, m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reply_query_state(DnsQuery *q) {
|
||||
|
||||
assert(q);
|
||||
assert(q->bus_request);
|
||||
|
||||
switch (q->state) {
|
||||
|
||||
case DNS_TRANSACTION_NO_SERVERS:
|
||||
return sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found");
|
||||
return sd_bus_reply_method_errorf(q->bus_request, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found");
|
||||
|
||||
case DNS_TRANSACTION_TIMEOUT:
|
||||
return sd_bus_reply_method_errorf(q->request, SD_BUS_ERROR_TIMEOUT, "Query timed out");
|
||||
return sd_bus_reply_method_errorf(q->bus_request, SD_BUS_ERROR_TIMEOUT, "Query timed out");
|
||||
|
||||
case DNS_TRANSACTION_ATTEMPTS_MAX_REACHED:
|
||||
return sd_bus_reply_method_errorf(q->request, SD_BUS_ERROR_TIMEOUT, "All attempts to contact name servers or networks failed");
|
||||
return sd_bus_reply_method_errorf(q->bus_request, SD_BUS_ERROR_TIMEOUT, "All attempts to contact name servers or networks failed");
|
||||
|
||||
case DNS_TRANSACTION_INVALID_REPLY:
|
||||
return sd_bus_reply_method_errorf(q->request, BUS_ERROR_INVALID_REPLY, "Received invalid reply");
|
||||
return sd_bus_reply_method_errorf(q->bus_request, BUS_ERROR_INVALID_REPLY, "Received invalid reply");
|
||||
|
||||
case DNS_TRANSACTION_ERRNO:
|
||||
return sd_bus_reply_method_errnof(q->request, q->answer_errno, "Lookup failed due to system error: %m");
|
||||
return sd_bus_reply_method_errnof(q->bus_request, q->answer_errno, "Lookup failed due to system error: %m");
|
||||
|
||||
case DNS_TRANSACTION_ABORTED:
|
||||
return sd_bus_reply_method_errorf(q->request, BUS_ERROR_ABORTED, "Query aborted");
|
||||
return sd_bus_reply_method_errorf(q->bus_request, BUS_ERROR_ABORTED, "Query aborted");
|
||||
|
||||
case DNS_TRANSACTION_DNSSEC_FAILED:
|
||||
return sd_bus_reply_method_errorf(q->request, BUS_ERROR_DNSSEC_FAILED, "DNSSEC validation failed: %s",
|
||||
return sd_bus_reply_method_errorf(q->bus_request, BUS_ERROR_DNSSEC_FAILED, "DNSSEC validation failed: %s",
|
||||
dnssec_result_to_string(q->answer_dnssec_result));
|
||||
|
||||
case DNS_TRANSACTION_NO_TRUST_ANCHOR:
|
||||
return sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_TRUST_ANCHOR, "No suitable trust anchor known");
|
||||
return sd_bus_reply_method_errorf(q->bus_request, BUS_ERROR_NO_TRUST_ANCHOR, "No suitable trust anchor known");
|
||||
|
||||
case DNS_TRANSACTION_RR_TYPE_UNSUPPORTED:
|
||||
return sd_bus_reply_method_errorf(q->request, BUS_ERROR_RR_TYPE_UNSUPPORTED, "Server does not support requested resource record type");
|
||||
return sd_bus_reply_method_errorf(q->bus_request, BUS_ERROR_RR_TYPE_UNSUPPORTED, "Server does not support requested resource record type");
|
||||
|
||||
case DNS_TRANSACTION_NETWORK_DOWN:
|
||||
return sd_bus_reply_method_errorf(q->request, BUS_ERROR_NETWORK_DOWN, "Network is down");
|
||||
return sd_bus_reply_method_errorf(q->bus_request, BUS_ERROR_NETWORK_DOWN, "Network is down");
|
||||
|
||||
case DNS_TRANSACTION_NOT_FOUND:
|
||||
/* We return this as NXDOMAIN. This is only generated when a host doesn't implement LLMNR/TCP, and we
|
||||
* thus quickly know that we cannot resolve an in-addr.arpa or ip6.arpa address. */
|
||||
return sd_bus_reply_method_errorf(q->request, _BUS_ERROR_DNS "NXDOMAIN", "'%s' not found", dns_query_string(q));
|
||||
return sd_bus_reply_method_errorf(q->bus_request, _BUS_ERROR_DNS "NXDOMAIN", "'%s' not found", dns_query_string(q));
|
||||
|
||||
case DNS_TRANSACTION_RCODE_FAILURE: {
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
|
@ -83,7 +119,7 @@ static int reply_query_state(DnsQuery *q) {
|
|||
sd_bus_error_setf(&error, n, "Could not resolve '%s', server or network returned error %s", dns_query_string(q), rc);
|
||||
}
|
||||
|
||||
return sd_bus_reply_method_error(q->request, &error);
|
||||
return sd_bus_reply_method_error(q->bus_request, &error);
|
||||
}
|
||||
|
||||
case DNS_TRANSACTION_NULL:
|
||||
|
@ -139,6 +175,7 @@ static void bus_method_resolve_hostname_complete(DnsQuery *q) {
|
|||
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *canonical = NULL;
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
_cleanup_free_ char *normalized = NULL;
|
||||
DnsQuestion *question;
|
||||
DnsResourceRecord *rr;
|
||||
unsigned added = 0;
|
||||
int ifindex, r;
|
||||
|
@ -152,7 +189,7 @@ static void bus_method_resolve_hostname_complete(DnsQuery *q) {
|
|||
|
||||
r = dns_query_process_cname(q);
|
||||
if (r == -ELOOP) {
|
||||
r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_query_string(q));
|
||||
r = sd_bus_reply_method_errorf(q->bus_request, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_query_string(q));
|
||||
goto finish;
|
||||
}
|
||||
if (r < 0)
|
||||
|
@ -160,7 +197,7 @@ static void bus_method_resolve_hostname_complete(DnsQuery *q) {
|
|||
if (r == DNS_QUERY_RESTARTED) /* This was a cname, and the query was restarted. */
|
||||
return;
|
||||
|
||||
r = sd_bus_message_new_method_return(q->request, &reply);
|
||||
r = sd_bus_message_new_method_return(q->bus_request, &reply);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
|
@ -168,10 +205,9 @@ static void bus_method_resolve_hostname_complete(DnsQuery *q) {
|
|||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, q->answer) {
|
||||
DnsQuestion *question;
|
||||
question = dns_query_question_for_protocol(q, q->answer_protocol);
|
||||
|
||||
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, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain));
|
||||
if (r < 0)
|
||||
|
@ -190,7 +226,7 @@ static void bus_method_resolve_hostname_complete(DnsQuery *q) {
|
|||
}
|
||||
|
||||
if (added <= 0) {
|
||||
r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "'%s' does not have any RR of the requested type", dns_query_string(q));
|
||||
r = sd_bus_reply_method_errorf(q->bus_request, BUS_ERROR_NO_SUCH_RR, "'%s' does not have any RR of the requested type", dns_query_string(q));
|
||||
goto finish;
|
||||
}
|
||||
|
||||
|
@ -198,14 +234,14 @@ static void bus_method_resolve_hostname_complete(DnsQuery *q) {
|
|||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
/* The key names are not necessarily normalized, make sure that they are when we return them to our bus
|
||||
* clients. */
|
||||
/* The key names are not necessarily normalized, make sure that they are when we return them to our
|
||||
* bus clients. */
|
||||
assert(canonical);
|
||||
r = dns_name_normalize(dns_resource_key_name(canonical->key), 0, &normalized);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
/* Return the precise spelling and uppercasing and CNAME target reported by the server */
|
||||
assert(canonical);
|
||||
r = sd_bus_message_append(
|
||||
reply, "st",
|
||||
normalized,
|
||||
|
@ -218,15 +254,29 @@ static void bus_method_resolve_hostname_complete(DnsQuery *q) {
|
|||
finish:
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to send hostname reply: %m");
|
||||
sd_bus_reply_method_errno(q->request, r, NULL);
|
||||
sd_bus_reply_method_errno(q->bus_request, r, NULL);
|
||||
}
|
||||
|
||||
dns_query_free(q);
|
||||
}
|
||||
|
||||
static int check_ifindex_flags(int ifindex, uint64_t *flags, uint64_t ok, sd_bus_error *error) {
|
||||
static int validate_and_mangle_ifindex_and_flags(int ifindex, uint64_t *flags, uint64_t ok, sd_bus_error *error) {
|
||||
assert(flags);
|
||||
|
||||
/* Checks that the client supplied interface index and flags parameter actually are valid and make
|
||||
* sense in our method call context. Specifically:
|
||||
*
|
||||
* 1. Checks that the interface index is either 0 (meaning *all* interfaces) or positive
|
||||
*
|
||||
* 2. Only the protocols flags and the NO_CNAME flag are set, at most. Plus additional flags specific
|
||||
* to our method, passed in the "ok" parameter.
|
||||
*
|
||||
* 3. If zero protocol flags are specified it is automatically turned into *all* protocols. This way
|
||||
* clients can simply pass 0 as flags and all will work as it should. They can also use this so
|
||||
* that clients don't have to know all the protocols resolved implements, but can just specify 0
|
||||
* to mean "all supported protocols".
|
||||
*/
|
||||
|
||||
if (ifindex < 0)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
|
||||
|
||||
|
@ -324,7 +374,7 @@ static int bus_method_resolve_hostname(sd_bus_message *message, void *userdata,
|
|||
if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
|
||||
|
||||
r = check_ifindex_flags(ifindex, &flags, SD_RESOLVED_NO_SEARCH, error);
|
||||
r = validate_and_mangle_ifindex_and_flags(ifindex, &flags, SD_RESOLVED_NO_SEARCH, error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -350,10 +400,9 @@ static int bus_method_resolve_hostname(sd_bus_message *message, void *userdata,
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
q->request = sd_bus_message_ref(message);
|
||||
q->bus_request = sd_bus_message_ref(message);
|
||||
q->request_family = family;
|
||||
q->complete = bus_method_resolve_hostname_complete;
|
||||
q->suppress_unroutable_family = family == AF_UNSPEC;
|
||||
|
||||
r = dns_query_bus_track(q, message);
|
||||
if (r < 0)
|
||||
|
@ -386,7 +435,7 @@ static void bus_method_resolve_address_complete(DnsQuery *q) {
|
|||
|
||||
r = dns_query_process_cname(q);
|
||||
if (r == -ELOOP) {
|
||||
r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_query_string(q));
|
||||
r = sd_bus_reply_method_errorf(q->bus_request, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_query_string(q));
|
||||
goto finish;
|
||||
}
|
||||
if (r < 0)
|
||||
|
@ -394,7 +443,7 @@ static void bus_method_resolve_address_complete(DnsQuery *q) {
|
|||
if (r == DNS_QUERY_RESTARTED) /* This was a cname, and the query was restarted. */
|
||||
return;
|
||||
|
||||
r = sd_bus_message_new_method_return(q->request, &reply);
|
||||
r = sd_bus_message_new_method_return(q->bus_request, &reply);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
|
@ -428,7 +477,7 @@ static void bus_method_resolve_address_complete(DnsQuery *q) {
|
|||
_cleanup_free_ char *ip = NULL;
|
||||
|
||||
(void) in_addr_to_string(q->request_family, &q->request_address, &ip);
|
||||
r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR,
|
||||
r = sd_bus_reply_method_errorf(q->bus_request, BUS_ERROR_NO_SUCH_RR,
|
||||
"Address '%s' does not have any RR of requested type", strnull(ip));
|
||||
goto finish;
|
||||
}
|
||||
|
@ -446,7 +495,7 @@ static void bus_method_resolve_address_complete(DnsQuery *q) {
|
|||
finish:
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to send address reply: %m");
|
||||
sd_bus_reply_method_errno(q->request, r, NULL);
|
||||
sd_bus_reply_method_errno(q->bus_request, r, NULL);
|
||||
}
|
||||
|
||||
dns_query_free(q);
|
||||
|
@ -478,7 +527,7 @@ static int bus_method_resolve_address(sd_bus_message *message, void *userdata, s
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = check_ifindex_flags(ifindex, &flags, 0, error);
|
||||
r = validate_and_mangle_ifindex_and_flags(ifindex, &flags, 0, error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -490,7 +539,7 @@ static int bus_method_resolve_address(sd_bus_message *message, void *userdata, s
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
q->request = sd_bus_message_ref(message);
|
||||
q->bus_request = sd_bus_message_ref(message);
|
||||
q->request_family = family;
|
||||
q->request_address = a;
|
||||
q->complete = bus_method_resolve_address_complete;
|
||||
|
@ -555,7 +604,7 @@ static void bus_method_resolve_record_complete(DnsQuery *q) {
|
|||
|
||||
r = dns_query_process_cname(q);
|
||||
if (r == -ELOOP) {
|
||||
r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_query_string(q));
|
||||
r = sd_bus_reply_method_errorf(q->bus_request, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_query_string(q));
|
||||
goto finish;
|
||||
}
|
||||
if (r < 0)
|
||||
|
@ -563,7 +612,7 @@ static void bus_method_resolve_record_complete(DnsQuery *q) {
|
|||
if (r == DNS_QUERY_RESTARTED) /* This was a cname, and the query was restarted. */
|
||||
return;
|
||||
|
||||
r = sd_bus_message_new_method_return(q->request, &reply);
|
||||
r = sd_bus_message_new_method_return(q->bus_request, &reply);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
|
@ -588,7 +637,7 @@ static void bus_method_resolve_record_complete(DnsQuery *q) {
|
|||
}
|
||||
|
||||
if (added <= 0) {
|
||||
r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "Name '%s' does not have any RR of the requested type", dns_query_string(q));
|
||||
r = sd_bus_reply_method_errorf(q->bus_request, BUS_ERROR_NO_SUCH_RR, "Name '%s' does not have any RR of the requested type", dns_query_string(q));
|
||||
goto finish;
|
||||
}
|
||||
|
||||
|
@ -605,7 +654,7 @@ static void bus_method_resolve_record_complete(DnsQuery *q) {
|
|||
finish:
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to send record reply: %m");
|
||||
sd_bus_reply_method_errno(q->request, r, NULL);
|
||||
sd_bus_reply_method_errno(q->bus_request, r, NULL);
|
||||
}
|
||||
|
||||
dns_query_free(q);
|
||||
|
@ -643,7 +692,7 @@ static int bus_method_resolve_record(sd_bus_message *message, void *userdata, sd
|
|||
if (dns_type_is_obsolete(type))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Specified DNS resource record type %" PRIu16 " is obsolete.", type);
|
||||
|
||||
r = check_ifindex_flags(ifindex, &flags, 0, error);
|
||||
r = validate_and_mangle_ifindex_and_flags(ifindex, &flags, 0, error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -667,7 +716,7 @@ static int bus_method_resolve_record(sd_bus_message *message, void *userdata, sd
|
|||
* blob */
|
||||
q->clamp_ttl = true;
|
||||
|
||||
q->request = sd_bus_message_ref(message);
|
||||
q->bus_request = sd_bus_message_ref(message);
|
||||
q->complete = bus_method_resolve_record_complete;
|
||||
|
||||
r = dns_query_bus_track(q, message);
|
||||
|
@ -891,7 +940,7 @@ static void resolve_service_all_complete(DnsQuery *q) {
|
|||
assert(bad->auxiliary_result != 0);
|
||||
|
||||
if (bad->auxiliary_result == -ELOOP) {
|
||||
r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_query_string(bad));
|
||||
r = sd_bus_reply_method_errorf(q->bus_request, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_query_string(bad));
|
||||
goto finish;
|
||||
}
|
||||
|
||||
|
@ -904,7 +953,7 @@ static void resolve_service_all_complete(DnsQuery *q) {
|
|||
}
|
||||
}
|
||||
|
||||
r = sd_bus_message_new_method_return(q->request, &reply);
|
||||
r = sd_bus_message_new_method_return(q->bus_request, &reply);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
|
@ -913,6 +962,7 @@ static void resolve_service_all_complete(DnsQuery *q) {
|
|||
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)
|
||||
|
@ -933,7 +983,7 @@ static void resolve_service_all_complete(DnsQuery *q) {
|
|||
}
|
||||
|
||||
if (added <= 0) {
|
||||
r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "'%s' does not have any RR of the requested type", dns_query_string(q));
|
||||
r = sd_bus_reply_method_errorf(q->bus_request, BUS_ERROR_NO_SUCH_RR, "'%s' does not have any RR of the requested type", dns_query_string(q));
|
||||
goto finish;
|
||||
}
|
||||
|
||||
|
@ -979,7 +1029,7 @@ static void resolve_service_all_complete(DnsQuery *q) {
|
|||
finish:
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to send service reply: %m");
|
||||
sd_bus_reply_method_errno(q->request, r, NULL);
|
||||
sd_bus_reply_method_errno(q->bus_request, r, NULL);
|
||||
}
|
||||
|
||||
dns_query_free(q);
|
||||
|
@ -1071,7 +1121,7 @@ static void bus_method_resolve_service_complete(DnsQuery *q) {
|
|||
|
||||
r = dns_query_process_cname(q);
|
||||
if (r == -ELOOP) {
|
||||
r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_query_string(q));
|
||||
r = sd_bus_reply_method_errorf(q->bus_request, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_query_string(q));
|
||||
goto finish;
|
||||
}
|
||||
if (r < 0)
|
||||
|
@ -1115,12 +1165,12 @@ static void bus_method_resolve_service_complete(DnsQuery *q) {
|
|||
* domain. Report this as a recognizable
|
||||
* error. See RFC 2782, Section "Usage
|
||||
* Rules". */
|
||||
r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_SERVICE, "'%s' does not provide the requested service", dns_query_string(q));
|
||||
r = sd_bus_reply_method_errorf(q->bus_request, BUS_ERROR_NO_SUCH_SERVICE, "'%s' does not provide the requested service", dns_query_string(q));
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (found <= 0) {
|
||||
r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "'%s' does not have any RR of the requested type", dns_query_string(q));
|
||||
r = sd_bus_reply_method_errorf(q->bus_request, BUS_ERROR_NO_SUCH_RR, "'%s' does not have any RR of the requested type", dns_query_string(q));
|
||||
goto finish;
|
||||
}
|
||||
|
||||
|
@ -1131,7 +1181,7 @@ static void bus_method_resolve_service_complete(DnsQuery *q) {
|
|||
finish:
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to send service reply: %m");
|
||||
sd_bus_reply_method_errno(q->request, r, NULL);
|
||||
sd_bus_reply_method_errno(q->bus_request, r, NULL);
|
||||
}
|
||||
|
||||
dns_query_free(q);
|
||||
|
@ -1177,7 +1227,7 @@ static int bus_method_resolve_service(sd_bus_message *message, void *userdata, s
|
|||
if (name && !type)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Service name cannot be specified without service type.");
|
||||
|
||||
r = check_ifindex_flags(ifindex, &flags, SD_RESOLVED_NO_TXT|SD_RESOLVED_NO_ADDRESS, error);
|
||||
r = validate_and_mangle_ifindex_and_flags(ifindex, &flags, SD_RESOLVED_NO_TXT|SD_RESOLVED_NO_ADDRESS, error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -1193,7 +1243,7 @@ static int bus_method_resolve_service(sd_bus_message *message, void *userdata, s
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
q->request = sd_bus_message_ref(message);
|
||||
q->bus_request = sd_bus_message_ref(message);
|
||||
q->request_family = family;
|
||||
q->complete = bus_method_resolve_service_complete;
|
||||
|
||||
|
@ -1690,7 +1740,7 @@ static int bus_method_reset_server_features(sd_bus_message *message, void *userd
|
|||
return sd_bus_reply_method_return(message, NULL);
|
||||
}
|
||||
|
||||
static int on_bus_track(sd_bus_track *t, void *userdata) {
|
||||
static int dnssd_service_on_bus_track(sd_bus_track *t, void *userdata) {
|
||||
DnssdService *s = userdata;
|
||||
|
||||
assert(t);
|
||||
|
@ -1863,7 +1913,7 @@ static int bus_method_register_service(sd_bus_message *message, void *userdata,
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_track_new(sd_bus_message_get_bus(message), &bus_track, on_bus_track, service);
|
||||
r = sd_bus_track_new(sd_bus_message_get_bus(message), &bus_track, dnssd_service_on_bus_track, service);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
|
|
@ -338,9 +338,14 @@ DnsQuery *dns_query_free(DnsQuery *q) {
|
|||
|
||||
dns_query_reset_answer(q);
|
||||
|
||||
sd_bus_message_unref(q->request);
|
||||
sd_bus_message_unref(q->bus_request);
|
||||
sd_bus_track_unref(q->bus_track);
|
||||
|
||||
if (q->varlink_request) {
|
||||
varlink_set_userdata(q->varlink_request, NULL);
|
||||
varlink_unref(q->varlink_request);
|
||||
}
|
||||
|
||||
dns_packet_unref(q->request_dns_packet);
|
||||
dns_packet_unref(q->reply_dns_packet);
|
||||
|
||||
|
@ -473,14 +478,13 @@ int dns_query_make_auxiliary(DnsQuery *q, DnsQuery *auxiliary_for) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void dns_query_complete(DnsQuery *q, DnsTransactionState state) {
|
||||
void dns_query_complete(DnsQuery *q, DnsTransactionState state) {
|
||||
assert(q);
|
||||
assert(!DNS_TRANSACTION_IS_LIVE(state));
|
||||
assert(DNS_TRANSACTION_IS_LIVE(q->state));
|
||||
|
||||
/* Note that this call might invalidate the query. Callers
|
||||
* should hence not attempt to access the query or transaction
|
||||
* after calling this function. */
|
||||
/* Note that this call might invalidate the query. Callers should hence not attempt to access the
|
||||
* query or transaction after calling this function. */
|
||||
|
||||
q->state = state;
|
||||
|
||||
|
@ -987,36 +991,6 @@ int dns_query_process_cname(DnsQuery *q) {
|
|||
return DNS_QUERY_RESTARTED; /* We restarted the query for a new cname */
|
||||
}
|
||||
|
||||
static int on_bus_track(sd_bus_track *t, void *userdata) {
|
||||
DnsQuery *q = userdata;
|
||||
|
||||
assert(t);
|
||||
assert(q);
|
||||
|
||||
log_debug("Client of active query vanished, aborting query.");
|
||||
dns_query_complete(q, DNS_TRANSACTION_ABORTED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dns_query_bus_track(DnsQuery *q, sd_bus_message *m) {
|
||||
int r;
|
||||
|
||||
assert(q);
|
||||
assert(m);
|
||||
|
||||
if (!q->bus_track) {
|
||||
r = sd_bus_track_new(sd_bus_message_get_bus(m), &q->bus_track, on_bus_track, q);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_bus_track_add_sender(q->bus_track, m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DnsQuestion* dns_query_question_for_protocol(DnsQuery *q, DnsProtocol protocol) {
|
||||
assert(q);
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "sd-bus.h"
|
||||
|
||||
#include "set.h"
|
||||
#include "varlink.h"
|
||||
|
||||
typedef struct DnsQueryCandidate DnsQueryCandidate;
|
||||
typedef struct DnsQuery DnsQuery;
|
||||
|
@ -48,10 +49,6 @@ struct DnsQuery {
|
|||
uint64_t flags;
|
||||
int ifindex;
|
||||
|
||||
/* If true, A or AAAA RR lookups will be suppressed on links with no routable address of the matching address
|
||||
* family */
|
||||
bool suppress_unroutable_family;
|
||||
|
||||
/* If true, the RR TTLs of the answer will be clamped by their current left validity in the cache */
|
||||
bool clamp_ttl;
|
||||
|
||||
|
@ -72,8 +69,9 @@ struct DnsQuery {
|
|||
int answer_errno; /* if state is DNS_TRANSACTION_ERRNO */
|
||||
bool previous_redirect_unauthenticated;
|
||||
|
||||
/* Bus client information */
|
||||
sd_bus_message *request;
|
||||
/* Bus + Varlink client information */
|
||||
sd_bus_message *bus_request;
|
||||
Varlink *varlink_request;
|
||||
int request_family;
|
||||
bool request_address_valid;
|
||||
union in_addr_union request_address;
|
||||
|
@ -116,7 +114,7 @@ void dns_query_ready(DnsQuery *q);
|
|||
|
||||
int dns_query_process_cname(DnsQuery *q);
|
||||
|
||||
int dns_query_bus_track(DnsQuery *q, sd_bus_message *m);
|
||||
void dns_query_complete(DnsQuery *q, DnsTransactionState state);
|
||||
|
||||
DnsQuestion* dns_query_question_for_protocol(DnsQuery *q, DnsProtocol protocol);
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include "resolved-manager.h"
|
||||
#include "resolved-mdns.h"
|
||||
#include "resolved-resolv-conf.h"
|
||||
#include "resolved-varlink.h"
|
||||
#include "socket-util.h"
|
||||
#include "string-table.h"
|
||||
#include "string-util.h"
|
||||
|
@ -663,6 +664,10 @@ int manager_start(Manager *m) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = manager_varlink_init(m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -706,6 +711,7 @@ Manager *manager_free(Manager *m) {
|
|||
manager_llmnr_stop(m);
|
||||
manager_mdns_stop(m);
|
||||
manager_dns_stub_stop(m);
|
||||
manager_varlink_done(m);
|
||||
|
||||
bus_verify_polkit_async_registry_free(m->polkit_registry);
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "list.h"
|
||||
#include "ordered-set.h"
|
||||
#include "resolve-util.h"
|
||||
#include "varlink.h"
|
||||
|
||||
typedef struct Manager Manager;
|
||||
|
||||
|
@ -140,6 +141,8 @@ struct Manager {
|
|||
sd_event_source *dns_stub_tcp_event_source;
|
||||
|
||||
Hashmap *polkit_registry;
|
||||
|
||||
VarlinkServer *varlink_server;
|
||||
};
|
||||
|
||||
/* Manager */
|
||||
|
|
|
@ -0,0 +1,534 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
|
||||
#include "in-addr-util.h"
|
||||
#include "resolved-dns-synthesize.h"
|
||||
#include "resolved-varlink.h"
|
||||
#include "socket-netlink.h"
|
||||
|
||||
typedef struct LookupParameters {
|
||||
int ifindex;
|
||||
uint64_t flags;
|
||||
int family;
|
||||
union in_addr_union address;
|
||||
size_t address_size;
|
||||
char *name;
|
||||
} LookupParameters;
|
||||
|
||||
static void lookup_parameters_destroy(LookupParameters *p) {
|
||||
assert(p);
|
||||
free(p->name);
|
||||
}
|
||||
|
||||
static int reply_query_state(DnsQuery *q) {
|
||||
|
||||
assert(q);
|
||||
assert(q->varlink_request);
|
||||
|
||||
switch (q->state) {
|
||||
|
||||
case DNS_TRANSACTION_NO_SERVERS:
|
||||
return varlink_error(q->varlink_request, "io.systemd.Resolve.NoNameServers", NULL);
|
||||
|
||||
case DNS_TRANSACTION_TIMEOUT:
|
||||
return varlink_error(q->varlink_request, "io.systemd.Resolve.QueryTimedOut", NULL);
|
||||
|
||||
case DNS_TRANSACTION_ATTEMPTS_MAX_REACHED:
|
||||
return varlink_error(q->varlink_request, "io.systemd.Resolve.MaxAttemptsReached", NULL);
|
||||
|
||||
case DNS_TRANSACTION_INVALID_REPLY:
|
||||
return varlink_error(q->varlink_request, "io.systemd.Resolve.InvalidReply", NULL);
|
||||
|
||||
case DNS_TRANSACTION_ERRNO:
|
||||
return varlink_error_errno(q->varlink_request, q->answer_errno);
|
||||
|
||||
case DNS_TRANSACTION_ABORTED:
|
||||
return varlink_error(q->varlink_request, "io.systemd.Resolve.QueryAborted", NULL);
|
||||
|
||||
case DNS_TRANSACTION_DNSSEC_FAILED:
|
||||
return varlink_errorb(q->varlink_request, "io.systemd.Resolve.DNSSECValidationFailed",
|
||||
JSON_BUILD_OBJECT(JSON_BUILD_PAIR("result", JSON_BUILD_STRING(dnssec_result_to_string(q->answer_dnssec_result)))));
|
||||
|
||||
case DNS_TRANSACTION_NO_TRUST_ANCHOR:
|
||||
return varlink_error(q->varlink_request, "io.systemd.Resolve.NoTrustAnchor", NULL);
|
||||
|
||||
case DNS_TRANSACTION_RR_TYPE_UNSUPPORTED:
|
||||
return varlink_error(q->varlink_request, "io.systemd.Resolve.ResourceRecordTypeUnsupported", NULL);
|
||||
|
||||
case DNS_TRANSACTION_NETWORK_DOWN:
|
||||
return varlink_error(q->varlink_request, "io.systemd.Resolve.NetworkDown", NULL);
|
||||
|
||||
case DNS_TRANSACTION_NOT_FOUND:
|
||||
/* We return this as NXDOMAIN. This is only generated when a host doesn't implement LLMNR/TCP, and we
|
||||
* thus quickly know that we cannot resolve an in-addr.arpa or ip6.arpa address. */
|
||||
return varlink_errorb(q->varlink_request, "io.systemd.Resolve.DNSError",
|
||||
JSON_BUILD_OBJECT(JSON_BUILD_PAIR("rcode", JSON_BUILD_INTEGER(DNS_RCODE_NXDOMAIN))));
|
||||
|
||||
case DNS_TRANSACTION_RCODE_FAILURE:
|
||||
return varlink_errorb(q->varlink_request, "io.systemd.Resolve.DNSError",
|
||||
JSON_BUILD_OBJECT(JSON_BUILD_PAIR("rcode", JSON_BUILD_INTEGER(q->answer_rcode))));
|
||||
|
||||
case DNS_TRANSACTION_NULL:
|
||||
case DNS_TRANSACTION_PENDING:
|
||||
case DNS_TRANSACTION_VALIDATING:
|
||||
case DNS_TRANSACTION_SUCCESS:
|
||||
default:
|
||||
assert_not_reached("Impossible state");
|
||||
}
|
||||
}
|
||||
|
||||
static void vl_on_disconnect(VarlinkServer *s, Varlink *link, void *userdata) {
|
||||
DnsQuery *q;
|
||||
|
||||
assert(s);
|
||||
assert(link);
|
||||
|
||||
q = varlink_get_userdata(link);
|
||||
if (!q)
|
||||
return;
|
||||
|
||||
if (!DNS_TRANSACTION_IS_LIVE(q->state))
|
||||
return;
|
||||
|
||||
log_debug("Client of active query vanished, aborting query.");
|
||||
dns_query_complete(q, DNS_TRANSACTION_ABORTED);
|
||||
}
|
||||
|
||||
static bool validate_and_mangle_flags(uint64_t *flags, uint64_t ok) {
|
||||
assert(flags);
|
||||
|
||||
/* This checks that the specified client-provided flags parameter actually makes sense, and mangles
|
||||
* it slightly. Specifically:
|
||||
*
|
||||
* 1. We check that only the protocol flags and the NO_CNAME flag are on at most, plus the
|
||||
* method-specific flags specified in 'ok'.
|
||||
*
|
||||
* 2. If no protocols are enabled we automatically convert that to "all protocols are enabled".
|
||||
*
|
||||
* The second rule means that clients can just pass 0 as flags for the common case, and all supported
|
||||
* protocols are enabled. Moreover it's useful so that client's do not have to be aware of all
|
||||
* protocols implemented in resolved, but can use 0 as protocols flags set as indicator for
|
||||
* "everything".
|
||||
*/
|
||||
|
||||
if (*flags & ~(SD_RESOLVED_PROTOCOLS_ALL|SD_RESOLVED_NO_CNAME|ok))
|
||||
return false;
|
||||
|
||||
if ((*flags & SD_RESOLVED_PROTOCOLS_ALL) == 0) /* If no protocol is enabled, enable all */
|
||||
*flags |= SD_RESOLVED_PROTOCOLS_ALL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void vl_method_resolve_hostname_complete(DnsQuery *q) {
|
||||
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *canonical = NULL;
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *array = NULL;
|
||||
_cleanup_free_ char *normalized = NULL;
|
||||
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(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_RESTARTED) /* This was a cname, and the query was restarted. */
|
||||
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));
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
if (r == 0)
|
||||
continue;
|
||||
|
||||
if (rr->key->type == DNS_TYPE_A) {
|
||||
family = AF_INET;
|
||||
p = &rr->a.in_addr;
|
||||
} else if (rr->key->type == DNS_TYPE_AAAA) {
|
||||
family = AF_INET6;
|
||||
p = &rr->aaaa.in6_addr;
|
||||
} else {
|
||||
r = -EAFNOSUPPORT;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = json_build(&entry,
|
||||
JSON_BUILD_OBJECT(
|
||||
JSON_BUILD_PAIR("ifindex", JSON_BUILD_INTEGER(ifindex)),
|
||||
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);
|
||||
|
||||
r = json_variant_append_array(&array, entry);
|
||||
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;
|
||||
}
|
||||
|
||||
assert(canonical);
|
||||
r = dns_name_normalize(dns_resource_key_name(canonical->key), 0, &normalized);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
r = varlink_replyb(q->varlink_request,
|
||||
JSON_BUILD_OBJECT(
|
||||
JSON_BUILD_PAIR("addresses", JSON_BUILD_VARIANT(array)),
|
||||
JSON_BUILD_PAIR("name", JSON_BUILD_STRING(normalized)),
|
||||
JSON_BUILD_PAIR("flags", JSON_BUILD_INTEGER(SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, dns_query_fully_authenticated(q))))));
|
||||
finish:
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to send hostname reply: %m");
|
||||
r = varlink_error_errno(q->varlink_request, r);
|
||||
}
|
||||
|
||||
dns_query_free(q);
|
||||
}
|
||||
|
||||
static int parse_as_address(Varlink *link, LookupParameters *p) {
|
||||
_cleanup_free_ char *canonical = NULL;
|
||||
int r, ff, parsed_ifindex, ifindex;
|
||||
union in_addr_union parsed;
|
||||
|
||||
assert(link);
|
||||
assert(p);
|
||||
|
||||
/* Check if this parses as literal address. If so, just parse it and return that, do not involve networking */
|
||||
r = in_addr_ifindex_from_string_auto(p->name, &ff, &parsed, &parsed_ifindex);
|
||||
if (r < 0)
|
||||
return 0; /* not a literal address */
|
||||
|
||||
/* Make sure the data we parsed matches what is requested */
|
||||
if ((p->family != AF_UNSPEC && ff != p->family) ||
|
||||
(p->ifindex > 0 && parsed_ifindex > 0 && parsed_ifindex != p->ifindex))
|
||||
return varlink_error(link, "io.systemd.Resolve.NoSuchResourceRecord", NULL);
|
||||
|
||||
ifindex = parsed_ifindex > 0 ? parsed_ifindex : p->ifindex;
|
||||
|
||||
/* Reformat the address as string, to return as canonicalized name */
|
||||
r = in_addr_ifindex_to_string(ff, &parsed, ifindex, &canonical);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return varlink_replyb(
|
||||
link,
|
||||
JSON_BUILD_OBJECT(
|
||||
JSON_BUILD_PAIR("addresses",
|
||||
JSON_BUILD_ARRAY(
|
||||
JSON_BUILD_OBJECT(
|
||||
JSON_BUILD_PAIR_CONDITION(ifindex > 0, "ifindex", JSON_BUILD_INTEGER(ifindex)),
|
||||
JSON_BUILD_PAIR("family", JSON_BUILD_INTEGER(ff)),
|
||||
JSON_BUILD_PAIR("address", JSON_BUILD_BYTE_ARRAY(&parsed, FAMILY_ADDRESS_SIZE(ff)))))),
|
||||
JSON_BUILD_PAIR("name", JSON_BUILD_STRING(canonical)),
|
||||
JSON_BUILD_PAIR("flags", JSON_BUILD_INTEGER(SD_RESOLVED_FLAGS_MAKE(dns_synthesize_protocol(p->flags), ff, true)))));
|
||||
}
|
||||
|
||||
static int vl_method_resolve_hostname(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata) {
|
||||
static const JsonDispatch dispatch_table[] = {
|
||||
{ "ifindex", JSON_VARIANT_UNSIGNED, json_dispatch_int, offsetof(LookupParameters, ifindex), 0 },
|
||||
{ "name", JSON_VARIANT_STRING, json_dispatch_string, offsetof(LookupParameters, name), JSON_MANDATORY },
|
||||
{ "family", JSON_VARIANT_UNSIGNED, json_dispatch_int, offsetof(LookupParameters, family), 0 },
|
||||
{ "flags", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(LookupParameters, flags), 0 },
|
||||
{}
|
||||
};
|
||||
|
||||
_cleanup_(dns_question_unrefp) DnsQuestion *question_idna = NULL, *question_utf8 = NULL;
|
||||
_cleanup_(lookup_parameters_destroy) LookupParameters p = {
|
||||
.family = AF_UNSPEC,
|
||||
};
|
||||
Manager *m = userdata;
|
||||
DnsQuery *q;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(m);
|
||||
|
||||
if (FLAGS_SET(flags, VARLINK_METHOD_ONEWAY))
|
||||
return -EINVAL;
|
||||
|
||||
r = json_dispatch(parameters, dispatch_table, NULL, 0, &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 (!IN_SET(p.family, AF_UNSPEC, AF_INET, AF_INET6))
|
||||
return varlink_error_invalid_parameter(link, JSON_VARIANT_STRING_CONST("family"));
|
||||
|
||||
if (!validate_and_mangle_flags(&p.flags, SD_RESOLVED_NO_SEARCH))
|
||||
return varlink_error_invalid_parameter(link, JSON_VARIANT_STRING_CONST("flags"));
|
||||
|
||||
r = parse_as_address(link, &p);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
r = dns_question_new_address(&question_utf8, p.family, p.name, false);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dns_question_new_address(&question_idna, p.family, p.name, true);
|
||||
if (r < 0 && r != -EALREADY)
|
||||
return r;
|
||||
|
||||
r = dns_query_new(m, &q, question_utf8, question_idna ?: question_utf8, p.ifindex, p.flags);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
q->varlink_request = varlink_ref(link);
|
||||
varlink_set_userdata(link, q);
|
||||
q->request_family = p.family;
|
||||
q->complete = vl_method_resolve_hostname_complete;
|
||||
|
||||
r = dns_query_go(q);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
dns_query_free(q);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int json_dispatch_address(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
|
||||
LookupParameters *p = userdata;
|
||||
union in_addr_union buf = {};
|
||||
JsonVariant *i;
|
||||
size_t n, k = 0;
|
||||
|
||||
assert(variant);
|
||||
assert(p);
|
||||
|
||||
if (!json_variant_is_array(variant))
|
||||
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an array.", strna(name));
|
||||
|
||||
n = json_variant_elements(variant);
|
||||
if (!IN_SET(n, 4, 16))
|
||||
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is array of unexpected size.", strna(name));
|
||||
|
||||
JSON_VARIANT_ARRAY_FOREACH(i, variant) {
|
||||
intmax_t b;
|
||||
|
||||
if (!json_variant_is_integer(i))
|
||||
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "Element %zu of JSON field '%s' is not an integer.", k, strna(name));
|
||||
|
||||
b = json_variant_integer(i);
|
||||
if (b < 0 || b > 0xff)
|
||||
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "Element %zu of JSON field '%s' is out of range 0…255.", k, strna(name));
|
||||
|
||||
buf.bytes[k++] = (uint8_t) b;
|
||||
}
|
||||
|
||||
p->address = buf;
|
||||
p->address_size = k;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vl_method_resolve_address_complete(DnsQuery *q) {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *array = NULL;
|
||||
DnsQuestion *question;
|
||||
DnsResourceRecord *rr;
|
||||
int ifindex, r;
|
||||
|
||||
assert(q);
|
||||
|
||||
if (q->state != DNS_TRANSACTION_SUCCESS) {
|
||||
r = reply_query_state(q);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = dns_query_process_cname(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_RESTARTED) /* This was a cname, and the query was restarted. */
|
||||
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;
|
||||
_cleanup_free_ char *normalized = NULL;
|
||||
|
||||
r = dns_question_matches_rr(question, rr, NULL);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
if (r == 0)
|
||||
continue;
|
||||
|
||||
r = dns_name_normalize(rr->ptr.name, 0, &normalized);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
r = json_build(&entry,
|
||||
JSON_BUILD_OBJECT(
|
||||
JSON_BUILD_PAIR("ifindex", JSON_BUILD_INTEGER(ifindex)),
|
||||
JSON_BUILD_PAIR("name", JSON_BUILD_STRING(normalized))));
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
r = json_variant_append_array(&array, entry);
|
||||
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;
|
||||
}
|
||||
|
||||
r = varlink_replyb(q->varlink_request,
|
||||
JSON_BUILD_OBJECT(
|
||||
JSON_BUILD_PAIR("names", JSON_BUILD_VARIANT(array)),
|
||||
JSON_BUILD_PAIR("flags", JSON_BUILD_INTEGER(SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, dns_query_fully_authenticated(q))))));
|
||||
finish:
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to send address reply: %m");
|
||||
r = varlink_error_errno(q->varlink_request, r);
|
||||
}
|
||||
|
||||
dns_query_free(q);
|
||||
}
|
||||
|
||||
static int vl_method_resolve_address(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata) {
|
||||
static const JsonDispatch dispatch_table[] = {
|
||||
{ "ifindex", JSON_VARIANT_UNSIGNED, json_dispatch_int, offsetof(LookupParameters, ifindex), 0 },
|
||||
{ "family", JSON_VARIANT_UNSIGNED, json_dispatch_int, offsetof(LookupParameters, family), JSON_MANDATORY },
|
||||
{ "address", JSON_VARIANT_ARRAY, json_dispatch_address, 0, JSON_MANDATORY },
|
||||
{ "flags", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(LookupParameters, flags), 0 },
|
||||
{}
|
||||
};
|
||||
|
||||
_cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
|
||||
_cleanup_(lookup_parameters_destroy) LookupParameters p = {
|
||||
.family = AF_UNSPEC,
|
||||
};
|
||||
Manager *m = userdata;
|
||||
DnsQuery *q;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(m);
|
||||
|
||||
if (FLAGS_SET(flags, VARLINK_METHOD_ONEWAY))
|
||||
return -EINVAL;
|
||||
|
||||
r = json_dispatch(parameters, dispatch_table, NULL, 0, &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_UNSPEC, AF_INET, AF_INET6))
|
||||
return varlink_error_invalid_parameter(link, JSON_VARIANT_STRING_CONST("family"));
|
||||
|
||||
if (FAMILY_ADDRESS_SIZE(p.family) != p.address_size)
|
||||
return varlink_error(link, "io.systemd.UserDatabase.BadAddressSize", NULL);
|
||||
|
||||
if (!validate_and_mangle_flags(&p.flags, 0))
|
||||
return varlink_error_invalid_parameter(link, JSON_VARIANT_STRING_CONST("flags"));
|
||||
|
||||
r = dns_question_new_reverse(&question, p.family, &p.address);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dns_query_new(m, &q, question, question, p.ifindex, p.flags|SD_RESOLVED_NO_SEARCH);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
q->varlink_request = varlink_ref(link);
|
||||
varlink_set_userdata(link, q);
|
||||
|
||||
q->request_family = p.family;
|
||||
q->request_address = p.address;
|
||||
q->complete = vl_method_resolve_address_complete;
|
||||
|
||||
r = dns_query_go(q);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
dns_query_free(q);
|
||||
return r;
|
||||
}
|
||||
|
||||
int manager_varlink_init(Manager *m) {
|
||||
_cleanup_(varlink_server_unrefp) VarlinkServer *s = NULL;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
|
||||
if (m->varlink_server)
|
||||
return 0;
|
||||
|
||||
r = varlink_server_new(&s, VARLINK_SERVER_ACCOUNT_UID);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to allocate varlink server object: %m");
|
||||
|
||||
varlink_server_set_userdata(s, m);
|
||||
|
||||
r = varlink_server_bind_method_many(
|
||||
s,
|
||||
"io.systemd.Resolve.ResolveHostname", vl_method_resolve_hostname,
|
||||
"io.systemd.Resolve.ResolveAddress", vl_method_resolve_address);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to register varlink methods: %m");
|
||||
|
||||
r = varlink_server_bind_disconnect(s, vl_on_disconnect);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to register varlink disconnect handler: %m");
|
||||
|
||||
r = varlink_server_listen_address(s, "/run/systemd/resolve/io.systemd.Resolve", 0666);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to bind to varlink socket: %m");
|
||||
|
||||
r = varlink_server_attach_event(s, m->event, SD_EVENT_PRIORITY_NORMAL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to attach varlink connection to event loop: %m");
|
||||
|
||||
m->varlink_server = TAKE_PTR(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void manager_varlink_done(Manager *m) {
|
||||
assert(m);
|
||||
|
||||
m->varlink_server = varlink_server_unref(m->varlink_server);
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
#pragma once
|
||||
|
||||
#include "resolved-manager.h"
|
||||
|
||||
int manager_varlink_init(Manager *m);
|
||||
void manager_varlink_done(Manager *m);
|
|
@ -3624,6 +3624,36 @@ int json_buildv(JsonVariant **ret, va_list ap) {
|
|||
break;
|
||||
}
|
||||
|
||||
case _JSON_BUILD_BYTE_ARRAY: {
|
||||
const void *array;
|
||||
size_t n;
|
||||
|
||||
if (!IN_SET(current->expect, EXPECT_TOPLEVEL, EXPECT_OBJECT_VALUE, EXPECT_ARRAY_ELEMENT)) {
|
||||
r = -EINVAL;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
array = va_arg(ap, const void*);
|
||||
n = va_arg(ap, size_t);
|
||||
|
||||
if (current->n_suppress == 0) {
|
||||
r = json_variant_new_array_bytes(&add, array, n);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
}
|
||||
|
||||
n_subtract = 1;
|
||||
|
||||
if (current->expect == EXPECT_TOPLEVEL)
|
||||
current->expect = EXPECT_END;
|
||||
else if (current->expect == EXPECT_OBJECT_VALUE)
|
||||
current->expect = EXPECT_OBJECT_KEY;
|
||||
else
|
||||
assert(current->expect == EXPECT_ARRAY_ELEMENT);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case _JSON_BUILD_OBJECT_BEGIN:
|
||||
|
||||
if (!IN_SET(current->expect, EXPECT_TOPLEVEL, EXPECT_OBJECT_VALUE, EXPECT_ARRAY_ELEMENT)) {
|
||||
|
|
|
@ -228,6 +228,7 @@ enum {
|
|||
_JSON_BUILD_STRV,
|
||||
_JSON_BUILD_BASE64,
|
||||
_JSON_BUILD_ID128,
|
||||
_JSON_BUILD_BYTE_ARRAY,
|
||||
_JSON_BUILD_MAX,
|
||||
};
|
||||
|
||||
|
@ -249,6 +250,7 @@ enum {
|
|||
#define JSON_BUILD_STRV(l) _JSON_BUILD_STRV, ({ char **_x = l; _x; })
|
||||
#define JSON_BUILD_BASE64(p, n) _JSON_BUILD_BASE64, ({ const void *_x = p; _x; }), ({ size_t _y = n; _y; })
|
||||
#define JSON_BUILD_ID128(id) _JSON_BUILD_ID128, ({ sd_id128_t _x = id; _x; })
|
||||
#define JSON_BUILD_BYTE_ARRAY(v, n) _JSON_BUILD_BYTE_ARRAY, ({ const void *_x = v; _x; }), ({ size_t _y = n; _y; })
|
||||
|
||||
int json_build(JsonVariant **ret, ...);
|
||||
int json_buildv(JsonVariant **ret, va_list ap);
|
||||
|
@ -302,6 +304,12 @@ assert_cc(sizeof(uintmax_t) == sizeof(uint64_t));
|
|||
assert_cc(sizeof(intmax_t) == sizeof(int64_t));
|
||||
#define json_dispatch_int64 json_dispatch_integer
|
||||
|
||||
assert_cc(sizeof(uint32_t) == sizeof(unsigned));
|
||||
#define json_dispatch_uint json_dispatch_uint32
|
||||
|
||||
assert_cc(sizeof(int32_t) == sizeof(int));
|
||||
#define json_dispatch_int json_dispatch_int32
|
||||
|
||||
static inline int json_dispatch_level(JsonDispatchFlags flags) {
|
||||
|
||||
/* Did the user request no logging? If so, then never log higher than LOG_DEBUG. Also, if this is marked as
|
||||
|
|
|
@ -862,7 +862,7 @@ static int varlink_dispatch_method(Varlink *v) {
|
|||
|
||||
/* We got an error back from the callback. Propagate it to the client if the method call remains unanswered. */
|
||||
if (!FLAGS_SET(flags, VARLINK_METHOD_ONEWAY)) {
|
||||
r = varlink_errorb(v, VARLINK_ERROR_SYSTEM, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("errno", JSON_BUILD_INTEGER(-r))));
|
||||
r = varlink_error_errno(v, r);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
@ -1659,6 +1659,13 @@ int varlink_error_invalid_parameter(Varlink *v, JsonVariant *parameters) {
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
int varlink_error_errno(Varlink *v, int error) {
|
||||
return varlink_errorb(
|
||||
v,
|
||||
VARLINK_ERROR_SYSTEM,
|
||||
JSON_BUILD_OBJECT(JSON_BUILD_PAIR("errno", JSON_BUILD_INTEGER(abs(error)))));
|
||||
}
|
||||
|
||||
int varlink_notify(Varlink *v, JsonVariant *parameters) {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *m = NULL;
|
||||
int r;
|
||||
|
|
|
@ -100,6 +100,7 @@ int varlink_replyb(Varlink *v, ...);
|
|||
int varlink_error(Varlink *v, const char *error_id, JsonVariant *parameters);
|
||||
int varlink_errorb(Varlink *v, const char *error_id, ...);
|
||||
int varlink_error_invalid_parameter(Varlink *v, JsonVariant *parameters);
|
||||
int varlink_error_errno(Varlink *v, int error);
|
||||
|
||||
/* Enqueue a "more" reply */
|
||||
int varlink_notify(Varlink *v, JsonVariant *parameters);
|
||||
|
|
|
@ -1005,7 +1005,7 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
return log_oom();
|
||||
|
||||
/* If the user asked for a particular
|
||||
* property, show it to him, even if it is
|
||||
* property, show it to them, even if it is
|
||||
* empty. */
|
||||
arg_all = true;
|
||||
break;
|
||||
|
|
|
@ -186,7 +186,7 @@ static int dev_pci_onboard(sd_device *dev, struct netnames *names) {
|
|||
/* Some BIOSes report rubbish indexes that are excessively high (2^24-1 is an index VMware likes to
|
||||
* report for example). Let's define a cut-off where we don't consider the index reliable anymore. We
|
||||
* pick some arbitrary cut-off, which is somewhere beyond the realistic number of physical network
|
||||
* interface a system might have. Ideally the kernel would already filter his crap for us, but it
|
||||
* interface a system might have. Ideally the kernel would already filter this crap for us, but it
|
||||
* doesn't currently. */
|
||||
if (idx > ONBOARD_INDEX_MAX)
|
||||
return -ENOENT;
|
||||
|
|
Loading…
Reference in New Issue