resolvectl: use more varlink (#41840)
There are already varlink methods for `ResolveHostname`, `ResolveAddress`, and `ResolveRecord`. Use those in `resolvectl` instead of the dbus equivalents.
This commit is contained in:
@@ -248,6 +248,61 @@ int json_dispatch_in6_addr(const char *name, sd_json_variant *variant, sd_json_d
|
||||
return 0;
|
||||
}
|
||||
|
||||
int json_dispatch_in_addr_data(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
|
||||
struct in_addr_data *ret = ASSERT_PTR(userdata), data = { .family = AF_UNSPEC, .address = IN_ADDR_NULL };
|
||||
int r;
|
||||
|
||||
assert(variant);
|
||||
|
||||
if (sd_json_variant_is_null(variant)) {
|
||||
*ret = data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We support both a more human readable string based encoding and an array based encoding */
|
||||
if (sd_json_variant_is_string(variant)) {
|
||||
r = in_addr_from_string_auto(sd_json_variant_string(variant), &data.family, &data.address);
|
||||
if (r < 0)
|
||||
return json_log(variant, flags, r,
|
||||
"JSON field '%s' is not a valid IPv4 or IPv6 address string: %s", strna(name), sd_json_variant_string(variant));
|
||||
*ret = data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!sd_json_variant_is_array(variant))
|
||||
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an array.", strna(name));
|
||||
|
||||
switch (sd_json_variant_elements(variant)) {
|
||||
case sizeof(struct in_addr):
|
||||
data.family = AF_INET;
|
||||
break;
|
||||
case sizeof(struct in6_addr):
|
||||
data.family = AF_INET6;
|
||||
break;
|
||||
default:
|
||||
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is array of unexpected size.", strna(name));
|
||||
}
|
||||
|
||||
size_t k = 0;
|
||||
sd_json_variant *i;
|
||||
JSON_VARIANT_ARRAY_FOREACH(i, variant) {
|
||||
if (!sd_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));
|
||||
|
||||
int64_t b = sd_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%s255.",
|
||||
k, strna(name), glyph(GLYPH_ELLIPSIS));
|
||||
|
||||
data.address.bytes[k++] = (uint8_t) b;
|
||||
}
|
||||
assert(k == FAMILY_ADDRESS_SIZE_SAFE(data.family));
|
||||
|
||||
*ret = data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int json_dispatch_const_path(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
|
||||
const char **p = ASSERT_PTR(userdata), *path;
|
||||
|
||||
@@ -918,3 +973,27 @@ int json_variant_compare(sd_json_variant *a, sd_json_variant *b) {
|
||||
|
||||
return CMP(sd_json_variant_type(a), sd_json_variant_type(b));
|
||||
}
|
||||
|
||||
int json_dispatch_address_family(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
|
||||
int *family = ASSERT_PTR(userdata), r;
|
||||
|
||||
assert(variant);
|
||||
|
||||
if (sd_json_variant_is_negative(variant))
|
||||
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL),
|
||||
"JSON field '%s' for an address family cannot be negative.", strna(name));
|
||||
|
||||
int k = AF_UNSPEC;
|
||||
if (!sd_json_variant_is_null(variant)) {
|
||||
r = sd_json_dispatch_int(name, variant, flags, &k);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (!IN_SET(k, AF_INET, AF_INET6) && !(FLAGS_SET(flags, SD_JSON_RELAX) && k == AF_UNSPEC))
|
||||
return json_log(variant, flags, SYNTHETIC_ERRNO(ERANGE),
|
||||
"JSON field '%s' out of range for an address family.", strna(name));
|
||||
|
||||
*family = k;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -119,6 +119,7 @@ int json_dispatch_const_user_group_name(const char *name, sd_json_variant *varia
|
||||
int json_dispatch_const_unit_name(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
|
||||
int json_dispatch_in_addr(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
|
||||
int json_dispatch_in6_addr(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
|
||||
int json_dispatch_in_addr_data(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
|
||||
int json_dispatch_path(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
|
||||
int json_dispatch_const_path(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
|
||||
int json_dispatch_strv_path(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
|
||||
@@ -133,6 +134,7 @@ int json_dispatch_log_level(const char *name, sd_json_variant *variant, sd_json_
|
||||
int json_dispatch_strv_environment(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
|
||||
int json_dispatch_access_mode(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
|
||||
int json_dispatch_job_id(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
|
||||
int json_dispatch_address_family(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
|
||||
|
||||
static inline int json_variant_unbase64_iovec(sd_json_variant *v, struct iovec *ret) {
|
||||
return sd_json_variant_unbase64(v, ret ? &ret->iov_base : NULL, ret ? &ret->iov_len : NULL);
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "fd-util.h"
|
||||
#include "format-util.h"
|
||||
#include "fileio.h"
|
||||
#include "in-addr-util.h"
|
||||
#include "io-util.h"
|
||||
#include "iovec-util.h"
|
||||
#include "json-internal.h"
|
||||
@@ -1998,4 +1999,197 @@ TEST(json_dispatch_in6_addr) {
|
||||
ASSERT_EQ(data.addr.s6_addr[i], 0);
|
||||
}
|
||||
|
||||
TEST(json_dispatch_in_addr_data) {
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *j = NULL;
|
||||
|
||||
/* 192.168.1.1 = { 192, 168, 1, 1 } */
|
||||
ASSERT_OK(sd_json_build(&j, SD_JSON_BUILD_OBJECT(
|
||||
SD_JSON_BUILD_PAIR("addr", JSON_BUILD_IN4_ADDR(&(const struct in_addr) { .s_addr = htobe32(0xC0A80101U) })),
|
||||
SD_JSON_BUILD_PAIR("null_addr", SD_JSON_BUILD_NULL))));
|
||||
|
||||
struct {
|
||||
struct in_addr_data addr;
|
||||
struct in_addr_data null_addr;
|
||||
} data = {};
|
||||
|
||||
ASSERT_OK(sd_json_dispatch(j,
|
||||
(const sd_json_dispatch_field[]) {
|
||||
{ "addr", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_in_addr_data, offsetof(typeof(data), addr) },
|
||||
{ "null_addr", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_in_addr_data, offsetof(typeof(data), null_addr) },
|
||||
{},
|
||||
},
|
||||
/* flags= */ 0,
|
||||
&data));
|
||||
|
||||
ASSERT_EQ(be32toh(data.addr.address.in.s_addr), 0xC0A80101U);
|
||||
ASSERT_EQ(data.null_addr.address.in.s_addr, 0U);
|
||||
ASSERT_EQ(data.addr.family, AF_INET);
|
||||
ASSERT_EQ(data.null_addr.family, AF_UNSPEC);
|
||||
|
||||
struct in_addr_data dummy = {};
|
||||
|
||||
/* Too few bytes (3 instead of 4) */
|
||||
j = sd_json_variant_unref(j);
|
||||
ASSERT_OK(sd_json_build(&j, SD_JSON_BUILD_OBJECT(
|
||||
SD_JSON_BUILD_PAIR("addr", SD_JSON_BUILD_ARRAY(SD_JSON_BUILD_UNSIGNED(192), SD_JSON_BUILD_UNSIGNED(168), SD_JSON_BUILD_UNSIGNED(1))))));
|
||||
ASSERT_ERROR(sd_json_dispatch(j,
|
||||
(const sd_json_dispatch_field[]) {
|
||||
{ "addr", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_in_addr_data, 0 },
|
||||
{},
|
||||
},
|
||||
/* flags= */ 0,
|
||||
&dummy), EINVAL);
|
||||
|
||||
/* Too many bytes (5 instead of 4) */
|
||||
j = sd_json_variant_unref(j);
|
||||
ASSERT_OK(sd_json_build(&j, SD_JSON_BUILD_OBJECT(
|
||||
SD_JSON_BUILD_PAIR("addr", SD_JSON_BUILD_ARRAY(SD_JSON_BUILD_UNSIGNED(192), SD_JSON_BUILD_UNSIGNED(168), SD_JSON_BUILD_UNSIGNED(1), SD_JSON_BUILD_UNSIGNED(1), SD_JSON_BUILD_UNSIGNED(0))))));
|
||||
ASSERT_ERROR(sd_json_dispatch(j,
|
||||
(const sd_json_dispatch_field[]) {
|
||||
{ "addr", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_in_addr_data, 0 },
|
||||
{},
|
||||
},
|
||||
/* flags= */ 0,
|
||||
&dummy), EINVAL);
|
||||
|
||||
/* Not an array or string */
|
||||
j = sd_json_variant_unref(j);
|
||||
ASSERT_OK(sd_json_build(&j, SD_JSON_BUILD_OBJECT(
|
||||
SD_JSON_BUILD_PAIR("addr", SD_JSON_BUILD_BOOLEAN(true)))));
|
||||
ASSERT_ERROR(sd_json_dispatch(j,
|
||||
(const sd_json_dispatch_field[]) {
|
||||
{ "addr", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_in_addr_data, 0 },
|
||||
{},
|
||||
},
|
||||
/* flags= */ 0,
|
||||
&dummy), EINVAL);
|
||||
|
||||
/* A string */
|
||||
j = sd_json_variant_unref(j);
|
||||
ASSERT_OK(sd_json_build(&j, SD_JSON_BUILD_OBJECT(
|
||||
SD_JSON_BUILD_PAIR("addr", JSON_BUILD_CONST_STRING("192.168.1.1")))));
|
||||
zero(data);
|
||||
ASSERT_OK(sd_json_dispatch(j,
|
||||
(const sd_json_dispatch_field[]) {
|
||||
{ "addr", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_in_addr_data, 0 },
|
||||
{},
|
||||
},
|
||||
/* flags= */ 0,
|
||||
&data));
|
||||
ASSERT_EQ(be32toh(data.addr.address.in.s_addr), 0xC0A80101U);
|
||||
ASSERT_EQ(data.addr.family, AF_INET);
|
||||
|
||||
/* Byte value out of range (> 255) */
|
||||
j = sd_json_variant_unref(j);
|
||||
ASSERT_OK(sd_json_build(&j, SD_JSON_BUILD_OBJECT(
|
||||
SD_JSON_BUILD_PAIR("addr", SD_JSON_BUILD_ARRAY(SD_JSON_BUILD_UNSIGNED(256), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(1))))));
|
||||
ASSERT_ERROR(sd_json_dispatch(j,
|
||||
(const sd_json_dispatch_field[]) {
|
||||
{ "addr", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_in_addr_data, 0 },
|
||||
{},
|
||||
},
|
||||
/* flags= */ 0,
|
||||
&dummy), EINVAL);
|
||||
|
||||
/* Negative element */
|
||||
j = sd_json_variant_unref(j);
|
||||
ASSERT_OK(sd_json_build(&j, SD_JSON_BUILD_OBJECT(
|
||||
SD_JSON_BUILD_PAIR("addr", SD_JSON_BUILD_ARRAY(SD_JSON_BUILD_INTEGER(-1), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(1))))));
|
||||
ASSERT_ERROR(sd_json_dispatch(j,
|
||||
(const sd_json_dispatch_field[]) {
|
||||
{ "addr", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_in_addr_data, 0 },
|
||||
{},
|
||||
},
|
||||
/* flags= */ 0,
|
||||
&dummy), EINVAL);
|
||||
|
||||
/* ::1 */
|
||||
j = sd_json_variant_unref(j);
|
||||
ASSERT_OK(sd_json_build(&j, SD_JSON_BUILD_OBJECT(
|
||||
SD_JSON_BUILD_PAIR("addr", JSON_BUILD_IN6_ADDR(&(const struct in6_addr) { .s6_addr = { [15] = 1 } })),
|
||||
SD_JSON_BUILD_PAIR("null_addr", SD_JSON_BUILD_NULL))));
|
||||
|
||||
zero(data);
|
||||
ASSERT_OK(sd_json_dispatch(j,
|
||||
(const sd_json_dispatch_field[]) {
|
||||
{ "addr", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_in_addr_data, offsetof(typeof(data), addr) },
|
||||
{ "null_addr", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_in_addr_data, offsetof(typeof(data), null_addr) },
|
||||
{},
|
||||
},
|
||||
/* flags= */ 0,
|
||||
&data));
|
||||
|
||||
ASSERT_EQ(data.addr.address.in6.s6_addr[15], 1);
|
||||
for (size_t i = 0; i < 15; i++)
|
||||
ASSERT_EQ(data.addr.address.in6.s6_addr[i], 0);
|
||||
for (size_t i = 0; i < 16; i++)
|
||||
ASSERT_EQ(data.null_addr.address.in6.s6_addr[i], 0);
|
||||
ASSERT_EQ(data.addr.family, AF_INET6);
|
||||
ASSERT_EQ(data.null_addr.family, AF_UNSPEC);
|
||||
|
||||
/* Too few bytes (15 instead of 16) */
|
||||
j = sd_json_variant_unref(j);
|
||||
ASSERT_OK(sd_json_build(&j, SD_JSON_BUILD_OBJECT(
|
||||
SD_JSON_BUILD_PAIR("addr", SD_JSON_BUILD_ARRAY(
|
||||
SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0),
|
||||
SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0),
|
||||
SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0),
|
||||
SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(1))))));
|
||||
ASSERT_ERROR(sd_json_dispatch(j,
|
||||
(const sd_json_dispatch_field[]) {
|
||||
{ "addr", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_in_addr_data, 0 },
|
||||
{},
|
||||
},
|
||||
/* flags= */ 0,
|
||||
&dummy), EINVAL);
|
||||
|
||||
/* Too many bytes (17 instead of 16) */
|
||||
j = sd_json_variant_unref(j);
|
||||
ASSERT_OK(sd_json_build(&j, SD_JSON_BUILD_OBJECT(
|
||||
SD_JSON_BUILD_PAIR("addr", SD_JSON_BUILD_ARRAY(
|
||||
SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0),
|
||||
SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0),
|
||||
SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0),
|
||||
SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(1),
|
||||
SD_JSON_BUILD_UNSIGNED(0))))));
|
||||
ASSERT_ERROR(sd_json_dispatch(j,
|
||||
(const sd_json_dispatch_field[]) {
|
||||
{ "addr", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_in_addr_data, 0 },
|
||||
{},
|
||||
},
|
||||
/* flags= */ 0,
|
||||
&dummy), EINVAL);
|
||||
|
||||
/* Not an array */
|
||||
j = sd_json_variant_unref(j);
|
||||
ASSERT_OK(sd_json_build(&j, SD_JSON_BUILD_OBJECT(
|
||||
SD_JSON_BUILD_PAIR("addr", SD_JSON_BUILD_BOOLEAN(true)))));
|
||||
ASSERT_ERROR(sd_json_dispatch(j,
|
||||
(const sd_json_dispatch_field[]) {
|
||||
{ "addr", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_in_addr_data, 0 },
|
||||
{},
|
||||
},
|
||||
/* flags= */ 0,
|
||||
&dummy), EINVAL);
|
||||
|
||||
/* A string */
|
||||
j = sd_json_variant_unref(j);
|
||||
ASSERT_OK(sd_json_build(&j, SD_JSON_BUILD_OBJECT(
|
||||
SD_JSON_BUILD_PAIR("addr", JSON_BUILD_CONST_STRING("::1")))));
|
||||
|
||||
zero(data);
|
||||
ASSERT_OK(sd_json_dispatch(j,
|
||||
(const sd_json_dispatch_field[]) {
|
||||
{ "addr", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_in_addr_data, 0 },
|
||||
{},
|
||||
},
|
||||
/* flags= */ 0,
|
||||
&data));
|
||||
|
||||
ASSERT_EQ(data.addr.address.in6.s6_addr[15], 1);
|
||||
for (size_t i = 0; i < 15; i++)
|
||||
ASSERT_EQ(data.addr.address.in6.s6_addr[i], 0);
|
||||
ASSERT_EQ(data.addr.family, AF_INET6);
|
||||
}
|
||||
|
||||
DEFINE_TEST_MAIN(LOG_DEBUG);
|
||||
|
||||
@@ -102,28 +102,6 @@ int manager_set_serialization_fd(Manager *manager, int fd, const char *name) {
|
||||
|
||||
static JSON_DISPATCH_ENUM_DEFINE(json_dispatch_network_config_source, NetworkConfigSource, network_config_source_from_string);
|
||||
|
||||
static int json_dispatch_address_family(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
|
||||
int r, *i = ASSERT_PTR(userdata);
|
||||
int64_t i64;
|
||||
|
||||
assert_return(variant, -EINVAL);
|
||||
|
||||
if (FLAGS_SET(flags, SD_JSON_RELAX) && sd_json_variant_is_null(variant)) {
|
||||
*i = AF_UNSPEC;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_json_dispatch_int64(name, variant, flags, &i64);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!IN_SET(i64, AF_INET, AF_INET6) && !(FLAGS_SET(flags, SD_JSON_RELAX) && i64 == AF_UNSPEC))
|
||||
return json_log(variant, flags, SYNTHETIC_ERRNO(ERANGE), "JSON field '%s' out of bounds for an address family.", strna(name));
|
||||
|
||||
*i = (int) i64;
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef struct AddressParam {
|
||||
int family;
|
||||
struct iovec address;
|
||||
|
||||
+45
-213
@@ -14,6 +14,7 @@
|
||||
#include "json-util.h"
|
||||
#include "netlink-util.h"
|
||||
#include "nss-util.h"
|
||||
#include "resolve-varlink-util.h"
|
||||
#include "resolved-def.h"
|
||||
#include "signal-util.h"
|
||||
#include "string-util.h"
|
||||
@@ -64,107 +65,6 @@ static int connect_to_resolved(sd_varlink **ret) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t ifindex_to_scopeid(int family, const void *a, int ifindex) {
|
||||
struct in6_addr in6;
|
||||
|
||||
if (family != AF_INET6 || ifindex == 0)
|
||||
return 0;
|
||||
|
||||
/* Some apps can't deal with the scope ID attached to non-link-local addresses. Hence, let's suppress that. */
|
||||
|
||||
assert(sizeof(in6) == FAMILY_ADDRESS_SIZE(AF_INET6));
|
||||
memcpy(&in6, a, sizeof(struct in6_addr));
|
||||
|
||||
return in6_addr_is_link_local(&in6) ? ifindex : 0;
|
||||
}
|
||||
|
||||
static int json_dispatch_family(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
|
||||
int *family = ASSERT_PTR(userdata);
|
||||
int64_t t;
|
||||
|
||||
assert(variant);
|
||||
|
||||
if (!sd_json_variant_is_integer(variant))
|
||||
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an integer.", strna(name));
|
||||
|
||||
t = sd_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 {
|
||||
sd_json_variant *addresses;
|
||||
char *name;
|
||||
uint64_t flags;
|
||||
} ResolveHostnameReply;
|
||||
|
||||
static void resolve_hostname_reply_destroy(ResolveHostnameReply *p) {
|
||||
assert(p);
|
||||
|
||||
sd_json_variant_unref(p->addresses);
|
||||
free(p->name);
|
||||
}
|
||||
|
||||
static const sd_json_dispatch_field resolve_hostname_reply_dispatch_table[] = {
|
||||
{ "addresses", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_variant, offsetof(ResolveHostnameReply, addresses), SD_JSON_MANDATORY },
|
||||
{ "name", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(ResolveHostnameReply, name), 0 },
|
||||
{ "flags", _SD_JSON_VARIANT_TYPE_INVALID, sd_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, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
|
||||
AddressParameters *p = ASSERT_PTR(userdata);
|
||||
union in_addr_union buf = {};
|
||||
sd_json_variant *i;
|
||||
size_t n, k = 0;
|
||||
|
||||
assert(variant);
|
||||
|
||||
if (!sd_json_variant_is_array(variant))
|
||||
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an array.", strna(name));
|
||||
|
||||
n = sd_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) {
|
||||
int64_t b;
|
||||
|
||||
if (!sd_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 = sd_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%s255.",
|
||||
k, strna(name), glyph(GLYPH_ELLIPSIS));
|
||||
|
||||
buf.bytes[k++] = (uint8_t) b;
|
||||
}
|
||||
|
||||
p->address = buf;
|
||||
p->address_size = k;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const sd_json_dispatch_field address_parameters_dispatch_table[] = {
|
||||
{ "ifindex", SD_JSON_VARIANT_INTEGER, json_dispatch_ifindex, offsetof(AddressParameters, ifindex), 0 },
|
||||
{ "family", SD_JSON_VARIANT_INTEGER, json_dispatch_family, offsetof(AddressParameters, family), SD_JSON_MANDATORY },
|
||||
{ "address", SD_JSON_VARIANT_ARRAY, json_dispatch_address, 0, SD_JSON_MANDATORY },
|
||||
{}
|
||||
};
|
||||
|
||||
static uint64_t query_flag(
|
||||
const char *name,
|
||||
const int value,
|
||||
@@ -208,6 +108,19 @@ static int query_ifindex(void) {
|
||||
return ifindex;
|
||||
}
|
||||
|
||||
static uint32_t ifindex_to_scopeid(ResolvedAddress *addr) {
|
||||
assert(addr);
|
||||
|
||||
if (addr->family != AF_INET6 || addr->ifindex == 0)
|
||||
return 0;
|
||||
|
||||
/* Some apps can't deal with the scope ID attached to non-link-local addresses. Hence, let's suppress that. */
|
||||
if (in6_addr_is_link_local(&addr->in_addr.address.in6))
|
||||
return addr->ifindex;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum nss_status _nss_resolve_gethostbyname4_r(
|
||||
const char *name,
|
||||
struct gaih_addrtuple **pat,
|
||||
@@ -217,8 +130,8 @@ enum nss_status _nss_resolve_gethostbyname4_r(
|
||||
|
||||
_cleanup_(sd_varlink_unrefp) sd_varlink *link = NULL;
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *cparams = NULL;
|
||||
_cleanup_(resolve_hostname_reply_destroy) ResolveHostnameReply p = {};
|
||||
sd_json_variant *rparams, *entry;
|
||||
_cleanup_(resolve_hostname_reply_done) ResolveHostnameReply p = {};
|
||||
sd_json_variant *rparams;
|
||||
int r;
|
||||
|
||||
PROTECT_ERRNO;
|
||||
@@ -261,28 +174,17 @@ enum nss_status _nss_resolve_gethostbyname4_r(
|
||||
goto not_found;
|
||||
}
|
||||
|
||||
r = sd_json_dispatch(rparams, resolve_hostname_reply_dispatch_table, nss_json_dispatch_flags, &p);
|
||||
r = dispatch_resolve_hostname_reply(NULL, rparams, nss_json_dispatch_flags, &p);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
if (sd_json_variant_is_blank_array(p.addresses))
|
||||
if (p.n_addresses == 0)
|
||||
goto not_found;
|
||||
|
||||
size_t n_addresses = 0;
|
||||
JSON_VARIANT_ARRAY_FOREACH(entry, p.addresses) {
|
||||
AddressParameters q = {};
|
||||
|
||||
r = sd_json_dispatch(entry, address_parameters_dispatch_table, nss_json_dispatch_flags, &q);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
if (!IN_SET(q.family, AF_INET, AF_INET6))
|
||||
FOREACH_ARRAY(entry, p.addresses, p.n_addresses) {
|
||||
if (!IN_SET(entry->family, AF_INET, AF_INET6))
|
||||
continue;
|
||||
|
||||
if (q.address_size != FAMILY_ADDRESS_SIZE(q.family)) {
|
||||
r = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
n_addresses++;
|
||||
}
|
||||
|
||||
@@ -309,22 +211,16 @@ enum nss_status _nss_resolve_gethostbyname4_r(
|
||||
struct gaih_addrtuple *r_tuple = NULL,
|
||||
*r_tuple_first = (struct gaih_addrtuple*) (buffer + idx);
|
||||
|
||||
JSON_VARIANT_ARRAY_FOREACH(entry, p.addresses) {
|
||||
AddressParameters q = {};
|
||||
|
||||
r = sd_json_dispatch(entry, address_parameters_dispatch_table, nss_json_dispatch_flags, &q);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
if (!IN_SET(q.family, AF_INET, AF_INET6))
|
||||
FOREACH_ARRAY(entry, p.addresses, p.n_addresses) {
|
||||
if (!IN_SET(entry->family, AF_INET, AF_INET6))
|
||||
continue;
|
||||
|
||||
r_tuple = (struct gaih_addrtuple*) (buffer + idx);
|
||||
r_tuple->next = (struct gaih_addrtuple*) ((char*) r_tuple + ALIGN(sizeof(struct gaih_addrtuple)));
|
||||
r_tuple->name = r_name;
|
||||
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);
|
||||
r_tuple->family = entry->family;
|
||||
r_tuple->scopeid = ifindex_to_scopeid(entry);
|
||||
memcpy(r_tuple->addr, entry->in_addr.address.bytes, FAMILY_ADDRESS_SIZE_SAFE(entry->family));
|
||||
|
||||
idx += ALIGN(sizeof(struct gaih_addrtuple));
|
||||
}
|
||||
@@ -381,8 +277,8 @@ enum nss_status _nss_resolve_gethostbyname3_r(
|
||||
|
||||
_cleanup_(sd_varlink_unrefp) sd_varlink *link = NULL;
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *cparams = NULL;
|
||||
_cleanup_(resolve_hostname_reply_destroy) ResolveHostnameReply p = {};
|
||||
sd_json_variant *rparams, *entry;
|
||||
_cleanup_(resolve_hostname_reply_done) ResolveHostnameReply p = {};
|
||||
sd_json_variant *rparams;
|
||||
int r;
|
||||
|
||||
PROTECT_ERRNO;
|
||||
@@ -429,28 +325,17 @@ enum nss_status _nss_resolve_gethostbyname3_r(
|
||||
goto not_found;
|
||||
}
|
||||
|
||||
r = sd_json_dispatch(rparams, resolve_hostname_reply_dispatch_table, nss_json_dispatch_flags, &p);
|
||||
r = dispatch_resolve_hostname_reply(NULL, rparams, nss_json_dispatch_flags, &p);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
if (sd_json_variant_is_blank_array(p.addresses))
|
||||
if (p.n_addresses == 0)
|
||||
goto no_data;
|
||||
|
||||
size_t n_addresses = 0;
|
||||
JSON_VARIANT_ARRAY_FOREACH(entry, p.addresses) {
|
||||
AddressParameters q = {};
|
||||
|
||||
r = sd_json_dispatch(entry, address_parameters_dispatch_table, nss_json_dispatch_flags, &q);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
if (q.family != af)
|
||||
FOREACH_ARRAY(entry, p.addresses, p.n_addresses) {
|
||||
if (entry->family != af)
|
||||
continue;
|
||||
|
||||
if (q.address_size != FAMILY_ADDRESS_SIZE(q.family)) {
|
||||
r = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
n_addresses++;
|
||||
}
|
||||
|
||||
@@ -485,22 +370,16 @@ enum nss_status _nss_resolve_gethostbyname3_r(
|
||||
char *r_addr = buffer + idx;
|
||||
|
||||
size_t i = 0;
|
||||
JSON_VARIANT_ARRAY_FOREACH(entry, p.addresses) {
|
||||
AddressParameters q = {};
|
||||
|
||||
r = sd_json_dispatch(entry, address_parameters_dispatch_table, nss_json_dispatch_flags, &q);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
if (q.family != af)
|
||||
FOREACH_ARRAY(entry, p.addresses, p.n_addresses) {
|
||||
if (entry->family != af)
|
||||
continue;
|
||||
|
||||
if (q.address_size != alen) {
|
||||
if (FAMILY_ADDRESS_SIZE_SAFE(entry->family) != alen) {
|
||||
r = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
memcpy(r_addr + i*ALIGN(alen), &q.address, alen);
|
||||
memcpy(r_addr + i*ALIGN(alen), entry->in_addr.address.bytes, alen);
|
||||
i++;
|
||||
}
|
||||
|
||||
@@ -557,40 +436,6 @@ try_again:
|
||||
return NSS_STATUS_TRYAGAIN;
|
||||
}
|
||||
|
||||
typedef struct ResolveAddressReply {
|
||||
sd_json_variant *names;
|
||||
uint64_t flags;
|
||||
} ResolveAddressReply;
|
||||
|
||||
static void resolve_address_reply_destroy(ResolveAddressReply *p) {
|
||||
assert(p);
|
||||
|
||||
sd_json_variant_unref(p->names);
|
||||
}
|
||||
|
||||
static const sd_json_dispatch_field resolve_address_reply_dispatch_table[] = {
|
||||
{ "names", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_variant, offsetof(ResolveAddressReply, names), SD_JSON_MANDATORY },
|
||||
{ "flags", _SD_JSON_VARIANT_TYPE_INVALID, sd_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 sd_json_dispatch_field name_parameters_dispatch_table[] = {
|
||||
{ "ifindex", SD_JSON_VARIANT_INTEGER, json_dispatch_ifindex, offsetof(NameParameters, ifindex), 0 },
|
||||
{ "name", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(NameParameters, name), SD_JSON_MANDATORY },
|
||||
{}
|
||||
};
|
||||
|
||||
enum nss_status _nss_resolve_gethostbyaddr2_r(
|
||||
const void* addr, socklen_t len,
|
||||
int af,
|
||||
@@ -601,8 +446,8 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
|
||||
|
||||
_cleanup_(sd_varlink_unrefp) sd_varlink *link = NULL;
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *cparams = NULL;
|
||||
_cleanup_(resolve_address_reply_destroy) ResolveAddressReply p = {};
|
||||
sd_json_variant *rparams, *entry;
|
||||
_cleanup_(resolve_address_reply_done) ResolveAddressReply p = {};
|
||||
sd_json_variant *rparams;
|
||||
int r;
|
||||
|
||||
PROTECT_ERRNO;
|
||||
@@ -651,25 +496,18 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
|
||||
goto not_found;
|
||||
}
|
||||
|
||||
r = sd_json_dispatch(rparams, resolve_address_reply_dispatch_table, nss_json_dispatch_flags, &p);
|
||||
r = dispatch_resolve_address_reply(NULL, rparams, nss_json_dispatch_flags, &p);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
if (sd_json_variant_is_blank_array(p.names))
|
||||
if (p.n_names == 0)
|
||||
goto not_found;
|
||||
|
||||
size_t ms = 0, idx;
|
||||
|
||||
JSON_VARIANT_ARRAY_FOREACH(entry, p.names) {
|
||||
_cleanup_(name_parameters_destroy) NameParameters q = {};
|
||||
FOREACH_ARRAY(entry, p.names, p.n_names)
|
||||
ms += ALIGN(strlen(entry->name) + 1);
|
||||
|
||||
r = sd_json_dispatch(entry, name_parameters_dispatch_table, nss_json_dispatch_flags, &q);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
ms += ALIGN(strlen(q.name) + 1);
|
||||
}
|
||||
|
||||
size_t n_names = sd_json_variant_elements(p.names);
|
||||
size_t n_names = p.n_names;
|
||||
ms += ALIGN(len) + /* the address */
|
||||
2 * sizeof(char*) + /* pointer to the address, plus trailing NULL */
|
||||
n_names * sizeof(char*); /* pointers to aliases, plus trailing NULL */
|
||||
@@ -700,16 +538,10 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
|
||||
char *r_name = buffer + idx;
|
||||
|
||||
size_t i = 0;
|
||||
JSON_VARIANT_ARRAY_FOREACH(entry, p.names) {
|
||||
_cleanup_(name_parameters_destroy) NameParameters q = {};
|
||||
|
||||
r = sd_json_dispatch(entry, name_parameters_dispatch_table, nss_json_dispatch_flags, &q);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
size_t l = strlen(q.name);
|
||||
FOREACH_ARRAY(entry, p.names, p.n_names) {
|
||||
size_t l = strlen(entry->name);
|
||||
char *z = buffer + idx;
|
||||
memcpy(z, q.name, l + 1);
|
||||
memcpy(z, entry->name, l + 1);
|
||||
|
||||
if (i > 0)
|
||||
((char**) r_aliases)[i - 1] = z;
|
||||
|
||||
+294
-367
@@ -18,7 +18,6 @@
|
||||
#include "bus-common-errors.h"
|
||||
#include "bus-error.h"
|
||||
#include "bus-locator.h"
|
||||
#include "bus-message-util.h"
|
||||
#include "bus-util.h"
|
||||
#include "crypto-util.h"
|
||||
#include "dns-configuration.h"
|
||||
@@ -27,7 +26,6 @@
|
||||
#include "dns-rr.h"
|
||||
#include "errno-list.h"
|
||||
#include "errno-util.h"
|
||||
#include "escape.h"
|
||||
#include "format-ifname.h"
|
||||
#include "format-table.h"
|
||||
#include "glyph-util.h"
|
||||
@@ -48,6 +46,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 +277,101 @@ 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, bool warn_missing) {
|
||||
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) {
|
||||
if (!warn_missing)
|
||||
return -ENXIO;
|
||||
|
||||
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,99 +381,76 @@ 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, /* warn_missing = */ true);
|
||||
|
||||
_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;
|
||||
}
|
||||
|
||||
static int resolve_address(sd_bus *bus, int family, const union in_addr_union *address, int ifindex) {
|
||||
_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_free_ char *pretty = NULL;
|
||||
uint64_t flags;
|
||||
unsigned c = 0;
|
||||
usec_t ts;
|
||||
static int resolve_address(int family, const union in_addr_union *address, int ifindex) {
|
||||
int r;
|
||||
|
||||
assert(bus);
|
||||
assert(IN_SET(family, AF_INET, AF_INET6));
|
||||
assert(address);
|
||||
|
||||
@@ -403,93 +460,72 @@ static int resolve_address(sd_bus *bus, int family, const union in_addr_union *a
|
||||
if (ifindex <= 0)
|
||||
ifindex = arg_ifindex;
|
||||
|
||||
_cleanup_free_ char *pretty = NULL;
|
||||
r = in_addr_ifindex_to_string(family, address, ifindex, &pretty);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
log_debug("Resolving %s.", pretty);
|
||||
|
||||
r = bus_message_new_method_call(bus, &req, bus_resolve_mgr, "ResolveAddress");
|
||||
_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, "ii", ifindex, family);
|
||||
usec_t ts = now(CLOCK_MONOTONIC);
|
||||
|
||||
const char *error_id = NULL;
|
||||
sd_json_variant *v = NULL;
|
||||
r = sd_varlink_callbo(
|
||||
vl,
|
||||
"io.systemd.Resolve.ResolveAddress",
|
||||
&v,
|
||||
&error_id,
|
||||
SD_JSON_BUILD_PAIR_BYTE_ARRAY("address", &address->bytes, FAMILY_ADDRESS_SIZE_SAFE(family)),
|
||||
SD_JSON_BUILD_PAIR_UNSIGNED("family", family),
|
||||
JSON_BUILD_PAIR_CONDITION_UNSIGNED(ifindex > 0, "ifindex", ifindex),
|
||||
JSON_BUILD_PAIR_UNSIGNED_NON_ZERO("flags", arg_flags));
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_append_array(req, 'y', address, FAMILY_ADDRESS_SIZE(family));
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_append(req, "t", 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 log_error_errno(r, "%s: resolve call failed: %s", pretty, bus_error_message(&error, r));
|
||||
return log_error_errno(r, "Failed to issue varlink call: %m");
|
||||
|
||||
ts = now(CLOCK_MONOTONIC) - ts;
|
||||
|
||||
r = sd_bus_message_enter_container(reply, 'a', "(is)");
|
||||
if (!isempty(error_id))
|
||||
return varlink_log_resolve_error(pretty, error_id, v, /* warn_missing = */ true);
|
||||
|
||||
_cleanup_(resolve_address_reply_done) ResolveAddressReply reply = {};
|
||||
r = dispatch_resolve_address_reply(/* name = */ NULL, v, SD_JSON_LOG, &reply);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
return r;
|
||||
|
||||
while ((r = sd_bus_message_enter_container(reply, 'r', "is")) > 0) {
|
||||
const char *n;
|
||||
int k;
|
||||
bool first = true;
|
||||
FOREACH_ARRAY(name, reply.names, reply.n_names) {
|
||||
int k = printf("%*s%s %s%s%s",
|
||||
(int) strlen(pretty),
|
||||
first ? pretty : "",
|
||||
first ? ":" : " ",
|
||||
ansi_highlight(),
|
||||
name->name,
|
||||
ansi_normal());
|
||||
|
||||
assert_cc(sizeof(int) == sizeof(int32_t));
|
||||
|
||||
r = sd_bus_message_read(reply, "is", &ifindex, &n);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_exit_container(reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
k = printf("%*s%s %s%s%s",
|
||||
(int) strlen(pretty), c == 0 ? pretty : "",
|
||||
c == 0 ? ":" : " ",
|
||||
ansi_highlight(), n, ansi_normal());
|
||||
|
||||
print_ifindex_comment(k, ifindex);
|
||||
print_ifindex_comment(k, name->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);
|
||||
if (reply.n_names == 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ESRCH), "%s: no names found", pretty);
|
||||
|
||||
r = sd_bus_message_read(reply, "t", &flags);
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
if (c == 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ESRCH),
|
||||
"%s: no names found", pretty);
|
||||
|
||||
print_source(flags, ts);
|
||||
print_source(reply.flags, ts);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int output_rr_packet(const void *d, size_t l, int ifindex) {
|
||||
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
|
||||
static int output_rr_packet(DnsResourceRecord *rr, int ifindex) {
|
||||
int r;
|
||||
|
||||
assert(d || l == 0);
|
||||
|
||||
r = dns_resource_record_new_from_raw(&rr, d, l);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse RR: %m");
|
||||
assert(rr);
|
||||
|
||||
if (sd_json_format_enabled(arg_json_format_flags)) {
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *j = NULL;
|
||||
@@ -572,14 +608,7 @@ static bool single_label_nonsynthetic(const char *name) {
|
||||
return !streq(name, first_label);
|
||||
}
|
||||
|
||||
static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_t type, bool warn_missing) {
|
||||
_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_free_ char *idnafied = NULL;
|
||||
bool needs_authentication = false;
|
||||
unsigned n = 0;
|
||||
uint64_t flags;
|
||||
usec_t ts;
|
||||
static int resolve_record(const char *name, uint16_t class, uint16_t type, bool warn_missing) {
|
||||
int r;
|
||||
|
||||
assert(name);
|
||||
@@ -590,6 +619,7 @@ static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_
|
||||
log_notice("(Note that search domains are not appended when --type= is specified. "
|
||||
"Please specify fully qualified domain names, or remove --type= switch from invocation in order to request regular hostname resolution.)");
|
||||
|
||||
_cleanup_free_ char *idnafied = NULL;
|
||||
r = idna_candidate(name, &idnafied);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -598,85 +628,76 @@ static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_
|
||||
"Please specify translated domain names — i.e. '%s' — when resolving raw records, or remove --type= switch from invocation in order to request regular hostname resolution.",
|
||||
idnafied);
|
||||
|
||||
r = bus_message_new_method_call(bus, &req, bus_resolve_mgr, "ResolveRecord");
|
||||
_cleanup_(sd_varlink_unrefp) sd_varlink *vl = NULL;
|
||||
r = varlink_connect_with_query_timeout(&vl);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_append(req, "isqqt", arg_ifindex, name, class, type, 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) {
|
||||
if (warn_missing || r != -ENXIO)
|
||||
log_error("%s: resolve call failed: %s", name, bus_error_message(&error, r));
|
||||
return r;
|
||||
}
|
||||
|
||||
usec_t ts = now(CLOCK_MONOTONIC);
|
||||
|
||||
const char *error_id = NULL;
|
||||
sd_json_variant *v = NULL;
|
||||
r = sd_varlink_callbo(
|
||||
vl,
|
||||
"io.systemd.Resolve.ResolveRecord",
|
||||
&v,
|
||||
&error_id,
|
||||
SD_JSON_BUILD_PAIR_STRING("name", name),
|
||||
SD_JSON_BUILD_PAIR_UNSIGNED("type", type),
|
||||
JSON_BUILD_PAIR_CONDITION_UNSIGNED(arg_ifindex > 0, "ifindex", arg_ifindex),
|
||||
JSON_BUILD_PAIR_UNSIGNED_NON_ZERO("class", class),
|
||||
JSON_BUILD_PAIR_UNSIGNED_NON_ZERO("flags", arg_flags));
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to issue varlink call: %m");
|
||||
|
||||
ts = now(CLOCK_MONOTONIC) - ts;
|
||||
|
||||
r = sd_bus_message_enter_container(reply, 'a', "(iqqay)");
|
||||
if (!isempty(error_id)) {
|
||||
if (streq(error_id, "io.systemd.Resolve.ResourceRecordTypeInvalidForQuery"))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Specified resource record type %" PRIu16 " may not be used in a query", type);
|
||||
|
||||
if (streq(error_id, "io.systemd.Resolve.ResourceRecordTypeObsolete"))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Specified DNS resource record type %" PRIu16 " is obsolete", type);
|
||||
|
||||
return varlink_log_resolve_error(name, error_id, v, warn_missing);
|
||||
}
|
||||
|
||||
_cleanup_(resolve_record_reply_done) ResolveRecordReply reply = {};
|
||||
r = dispatch_resolve_record_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', "iqqay")) > 0) {
|
||||
uint16_t c, t;
|
||||
int ifindex;
|
||||
const void *d;
|
||||
size_t l;
|
||||
|
||||
assert_cc(sizeof(int) == sizeof(int32_t));
|
||||
|
||||
r = sd_bus_message_read(reply, "iqq", &ifindex, &c, &t);
|
||||
bool needs_authentication = false;
|
||||
FOREACH_ARRAY(record, reply.records, reply.n_records) {
|
||||
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
|
||||
r = dns_resource_record_new_from_raw(&rr, record->raw.iov_base, record->raw.iov_len);
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
r = sd_bus_message_read_array(reply, 'y', &d, &l);
|
||||
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);
|
||||
return log_error_errno(r, "Failed to parse RR: %m");
|
||||
|
||||
if (arg_raw == RAW_PACKET) {
|
||||
uint64_t u64 = htole64(l);
|
||||
uint64_t u64 = htole64(record->raw.iov_len);
|
||||
|
||||
fwrite(&u64, sizeof(u64), 1, stdout);
|
||||
fwrite(d, 1, l, stdout);
|
||||
fwrite(record->raw.iov_base, 1, record->raw.iov_len, stdout);
|
||||
} else {
|
||||
r = output_rr_packet(d, l, ifindex);
|
||||
r = output_rr_packet(rr, record->ifindex);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (dns_type_needs_authentication(t))
|
||||
if (dns_type_needs_authentication(rr->key->type))
|
||||
needs_authentication = true;
|
||||
|
||||
n++;
|
||||
}
|
||||
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, "t", &flags);
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
if (n == 0) {
|
||||
if (reply.n_records == 0) {
|
||||
if (warn_missing)
|
||||
log_error("%s: no records found", name);
|
||||
return -ESRCH;
|
||||
}
|
||||
|
||||
print_source(flags, ts);
|
||||
print_source(reply.flags, ts);
|
||||
|
||||
if ((flags & SD_RESOLVED_AUTHENTICATED) == 0 && needs_authentication) {
|
||||
if ((reply.flags & SD_RESOLVED_AUTHENTICATED) == 0 && needs_authentication) {
|
||||
fflush(stdout);
|
||||
|
||||
fprintf(stderr, "\n%s"
|
||||
@@ -691,12 +712,11 @@ static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int resolve_rfc4501(sd_bus *bus, const char *name) {
|
||||
static int resolve_rfc4501(const char *name) {
|
||||
uint16_t type = 0, class = 0;
|
||||
const char *p, *q, *n;
|
||||
int r;
|
||||
|
||||
assert(bus);
|
||||
assert(name);
|
||||
assert(startswith(name, "dns:"));
|
||||
|
||||
@@ -794,7 +814,7 @@ static int resolve_rfc4501(sd_bus *bus, const char *name) {
|
||||
if (type == 0)
|
||||
type = arg_type ?: DNS_TYPE_A;
|
||||
|
||||
return resolve_record(bus, n, class, type, true);
|
||||
return resolve_record(n, class, type, true);
|
||||
|
||||
invalid:
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
@@ -804,48 +824,34 @@ invalid:
|
||||
VERB(verb_query, "query", "HOSTNAME|ADDRESS…", 2, VERB_ANY, 0,
|
||||
"Resolve domain names, IPv4 and IPv6 addresses");
|
||||
static int verb_query(int argc, char *argv[], uintptr_t _data, void *userdata) {
|
||||
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
||||
int ret = 0, r;
|
||||
|
||||
r = acquire_bus(&bus);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (arg_type != 0)
|
||||
STRV_FOREACH(p, strv_skip(argv, 1))
|
||||
RET_GATHER(ret, resolve_record(bus, *p, arg_class, arg_type, true));
|
||||
RET_GATHER(ret, resolve_record(*p, arg_class, arg_type, true));
|
||||
|
||||
else
|
||||
STRV_FOREACH(p, strv_skip(argv, 1)) {
|
||||
if (startswith(*p, "dns:"))
|
||||
RET_GATHER(ret, resolve_rfc4501(bus, *p));
|
||||
RET_GATHER(ret, resolve_rfc4501(*p));
|
||||
else {
|
||||
int family, ifindex;
|
||||
union in_addr_union a;
|
||||
|
||||
r = in_addr_ifindex_from_string_auto(*p, &family, &a, &ifindex);
|
||||
if (r >= 0)
|
||||
RET_GATHER(ret, resolve_address(bus, family, &a, ifindex));
|
||||
RET_GATHER(ret, resolve_address(family, &a, ifindex));
|
||||
else
|
||||
RET_GATHER(ret, resolve_host(bus, *p));
|
||||
RET_GATHER(ret, resolve_host(*p));
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int resolve_service(sd_bus *bus, const char *name, const char *type, const char *domain) {
|
||||
const char *canonical_name, *canonical_type, *canonical_domain;
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
size_t indent, sz;
|
||||
uint64_t flags;
|
||||
const char *p;
|
||||
unsigned c;
|
||||
usec_t ts;
|
||||
static int resolve_service(const char *name, const char *type, const char *domain) {
|
||||
int r;
|
||||
|
||||
assert(bus);
|
||||
assert(domain);
|
||||
|
||||
name = empty_to_null(name);
|
||||
@@ -858,141 +864,83 @@ static int resolve_service(sd_bus *bus, const char *name, const char *type, cons
|
||||
else
|
||||
log_debug("Resolving service type %s (family %s, interface %s).", domain, af_to_name(arg_family) ?: "*", isempty(arg_ifname) ? "*" : arg_ifname);
|
||||
|
||||
r = bus_message_new_method_call(bus, &req, bus_resolve_mgr, "ResolveService");
|
||||
_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, "isssit", arg_ifindex, name, type, domain, 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.ResolveService",
|
||||
&v,
|
||||
&error_id,
|
||||
SD_JSON_BUILD_PAIR_STRING("domain", domain),
|
||||
JSON_BUILD_PAIR_STRING_NON_EMPTY("name", name),
|
||||
JSON_BUILD_PAIR_STRING_NON_EMPTY("type", type),
|
||||
JSON_BUILD_PAIR_CONDITION_UNSIGNED(arg_ifindex > 0, "ifindex", arg_ifindex),
|
||||
JSON_BUILD_PAIR_CONDITION_UNSIGNED(arg_family != AF_UNSPEC, "family", arg_family),
|
||||
JSON_BUILD_PAIR_UNSIGNED_NON_ZERO("flags", arg_flags));
|
||||
if (r < 0)
|
||||
return 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 log_error_errno(r, "Resolve call failed: %s", bus_error_message(&error, r));
|
||||
return log_error_errno(r, "Failed to issue varlink call: %m");
|
||||
|
||||
ts = now(CLOCK_MONOTONIC) - ts;
|
||||
|
||||
r = sd_bus_message_enter_container(reply, 'a', "(qqqsa(iiay)s)");
|
||||
if (!isempty(error_id))
|
||||
return varlink_log_resolve_error(domain, error_id, v, /* warn_missing = */ true);
|
||||
|
||||
_cleanup_(resolve_service_reply_done) ResolveServiceReply reply = {};
|
||||
r = dispatch_resolve_service_reply(/* name = */ NULL, v, SD_JSON_LOG, &reply);
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
return r;
|
||||
|
||||
indent =
|
||||
(name ? strlen(name) + 1 : 0) +
|
||||
(type ? strlen(type) + 1 : 0) +
|
||||
strlen(domain) + 2;
|
||||
|
||||
c = 0;
|
||||
while ((r = sd_bus_message_enter_container(reply, 'r', "qqqsa(iiay)s")) > 0) {
|
||||
uint16_t priority, weight, port;
|
||||
const char *hostname, *canonical;
|
||||
|
||||
r = sd_bus_message_read(reply, "qqqs", &priority, &weight, &port, &hostname);
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
size_t indent = (name ? strlen(name) + 1 : 0) +
|
||||
(type ? strlen(type) + 1 : 0) +
|
||||
strlen(domain) + 2;
|
||||
|
||||
bool first = true;
|
||||
FOREACH_ARRAY(service, reply.services, reply.n_services) {
|
||||
if (name)
|
||||
printf("%*s%s", (int) strlen(name), c == 0 ? name : "", c == 0 ? "/" : " ");
|
||||
printf("%*s%s", (int) strlen(name), first ? name : "", first ? "/" : " ");
|
||||
if (type)
|
||||
printf("%*s%s", (int) strlen(type), c == 0 ? type : "", c == 0 ? "/" : " ");
|
||||
printf("%*s%s", (int) strlen(type), first ? type : "", first ? "/" : " ");
|
||||
|
||||
printf("%*s%s %s:%u [priority=%u, weight=%u]\n",
|
||||
(int) strlen(domain), c == 0 ? domain : "",
|
||||
c == 0 ? ":" : " ",
|
||||
hostname, port,
|
||||
priority, weight);
|
||||
(int) strlen(domain),
|
||||
first ? domain : "",
|
||||
first ? ":" : " ",
|
||||
service->hostname,
|
||||
service->port,
|
||||
service->priority,
|
||||
service->weight);
|
||||
|
||||
r = sd_bus_message_enter_container(reply, 'a', "(iiay)");
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) {
|
||||
FOREACH_ARRAY(address, service->addresses, service->n_addresses) {
|
||||
_cleanup_free_ char *pretty = NULL;
|
||||
int ifindex, family, k;
|
||||
union in_addr_union a;
|
||||
|
||||
assert_cc(sizeof(int) == sizeof(int32_t));
|
||||
|
||||
r = sd_bus_message_read(reply, "i", &ifindex);
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
sd_bus_error_free(&error);
|
||||
r = bus_message_read_in_addr_auto(reply, &error, &family, &a);
|
||||
if (r < 0 && !sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS))
|
||||
return log_error_errno(r, "%s: systemd-resolved returned invalid result: %s", name, bus_error_message(&error, r));
|
||||
|
||||
r = sd_bus_message_exit_container(reply);
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
if (sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS)) {
|
||||
log_debug_errno(r, "%s: systemd-resolved returned invalid result, ignoring: %s", name, bus_error_message(&error, r));
|
||||
continue;
|
||||
}
|
||||
|
||||
r = in_addr_ifindex_to_string(family, &a, ifindex, &pretty);
|
||||
r = in_addr_ifindex_to_string(address->family, &address->in_addr.address, address->ifindex, &pretty);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to print address for %s: %m", name);
|
||||
|
||||
k = printf("%*s%s", (int) indent, "", pretty);
|
||||
print_ifindex_comment(k, ifindex);
|
||||
int k = printf("%*s%s", (int) indent, "", pretty);
|
||||
|
||||
print_ifindex_comment(k, address->ifindex);
|
||||
fputc('\n', stdout);
|
||||
}
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
r = sd_bus_message_exit_container(reply);
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
if (service->canonical_name && !streq_ptr(service->hostname, service->canonical_name))
|
||||
printf("%*s(%s)\n", (int) indent, "", service->canonical_name);
|
||||
|
||||
r = sd_bus_message_read(reply, "s", &canonical);
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
if (!streq(hostname, canonical))
|
||||
printf("%*s(%s)\n", (int) indent, "", canonical);
|
||||
|
||||
r = sd_bus_message_exit_container(reply);
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
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);
|
||||
STRV_FOREACH(p, reply.txt)
|
||||
printf("%*s%s\n", (int) indent, "", *p);
|
||||
|
||||
r = sd_bus_message_enter_container(reply, 'a', "ay");
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
while ((r = sd_bus_message_read_array(reply, 'y', (const void**) &p, &sz)) > 0) {
|
||||
_cleanup_free_ char *escaped = NULL;
|
||||
|
||||
escaped = cescape_length(p, sz);
|
||||
if (!escaped)
|
||||
return log_oom();
|
||||
|
||||
printf("%*s%s\n", (int) indent, "", escaped);
|
||||
}
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
r = sd_bus_message_exit_container(reply);
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
r = sd_bus_message_read(reply, "ssst", &canonical_name, &canonical_type, &canonical_domain, &flags);
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
canonical_name = empty_to_null(canonical_name);
|
||||
canonical_type = empty_to_null(canonical_type);
|
||||
const char *canonical_name = empty_to_null(reply.canonical.name);
|
||||
const char *canonical_type = empty_to_null(reply.canonical.type);
|
||||
const char *canonical_domain = reply.canonical.domain;
|
||||
|
||||
if (!streq_ptr(name, canonical_name) ||
|
||||
!streq_ptr(type, canonical_type) ||
|
||||
@@ -1008,7 +956,7 @@ static int resolve_service(sd_bus *bus, const char *name, const char *type, cons
|
||||
printf("%s)\n", canonical_domain);
|
||||
}
|
||||
|
||||
print_source(flags, ts);
|
||||
print_source(reply.flags, ts);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1016,29 +964,21 @@ static int resolve_service(sd_bus *bus, const char *name, const char *type, cons
|
||||
VERB(verb_service, "service", "[[NAME] TYPE] DOMAIN", 2, 4, 0,
|
||||
"Resolve service (SRV)");
|
||||
static int verb_service(int argc, char *argv[], uintptr_t _data, void *userdata) {
|
||||
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
||||
int r;
|
||||
|
||||
r = acquire_bus(&bus);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (sd_json_format_enabled(arg_json_format_flags))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Use --json=pretty with --type= to acquire resource record information in JSON format.");
|
||||
|
||||
if (argc == 2)
|
||||
return resolve_service(bus, NULL, NULL, argv[1]);
|
||||
return resolve_service(NULL, NULL, argv[1]);
|
||||
else if (argc == 3)
|
||||
return resolve_service(bus, NULL, argv[1], argv[2]);
|
||||
return resolve_service(NULL, argv[1], argv[2]);
|
||||
else
|
||||
return resolve_service(bus, argv[1], argv[2], argv[3]);
|
||||
return resolve_service(argv[1], argv[2], argv[3]);
|
||||
}
|
||||
|
||||
#if HAVE_OPENSSL
|
||||
static int resolve_openpgp(sd_bus *bus, const char *address) {
|
||||
static int resolve_openpgp(const char *address) {
|
||||
int r;
|
||||
|
||||
assert(bus);
|
||||
assert(address);
|
||||
|
||||
const char *domain = strrchr(address, '@');
|
||||
@@ -1069,7 +1009,6 @@ static int resolve_openpgp(sd_bus *bus, const char *address) {
|
||||
log_debug("Looking up \"%s\".", full);
|
||||
|
||||
r = resolve_record(
|
||||
bus,
|
||||
full,
|
||||
arg_class ?: DNS_CLASS_IN,
|
||||
arg_type ?: DNS_TYPE_OPENPGPKEY,
|
||||
@@ -1089,7 +1028,6 @@ static int resolve_openpgp(sd_bus *bus, const char *address) {
|
||||
log_debug("Looking up \"%s\".", full);
|
||||
|
||||
return resolve_record(
|
||||
bus,
|
||||
full,
|
||||
arg_class ?: DNS_CLASS_IN,
|
||||
arg_type ?: DNS_TYPE_OPENPGPKEY,
|
||||
@@ -1101,18 +1039,13 @@ VERB(verb_openpgp, "openpgp", "EMAIL@DOMAIN…", 2, VERB_ANY, 0,
|
||||
"Query OpenPGP public key");
|
||||
static int verb_openpgp(int argc, char *argv[], uintptr_t _data, void *userdata) {
|
||||
#if HAVE_OPENSSL
|
||||
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
||||
int r, ret = 0;
|
||||
|
||||
r = acquire_bus(&bus);
|
||||
if (r < 0)
|
||||
return r;
|
||||
int ret = 0;
|
||||
|
||||
if (sd_json_format_enabled(arg_json_format_flags))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Use --json=pretty with --type= to acquire resource record information in JSON format.");
|
||||
|
||||
STRV_FOREACH(p, strv_skip(argv, 1))
|
||||
RET_GATHER(ret, resolve_openpgp(bus, *p));
|
||||
RET_GATHER(ret, resolve_openpgp(*p));
|
||||
|
||||
return ret;
|
||||
#else
|
||||
@@ -1120,13 +1053,12 @@ static int verb_openpgp(int argc, char *argv[], uintptr_t _data, void *userdata)
|
||||
#endif
|
||||
}
|
||||
|
||||
static int resolve_tlsa(sd_bus *bus, const char *family, const char *address) {
|
||||
static int resolve_tlsa(const char *family, const char *address) {
|
||||
const char *port;
|
||||
uint16_t port_num = 443;
|
||||
_cleanup_free_ char *full = NULL;
|
||||
int r;
|
||||
|
||||
assert(bus);
|
||||
assert(address);
|
||||
|
||||
port = strrchr(address, ':');
|
||||
@@ -1147,7 +1079,7 @@ static int resolve_tlsa(sd_bus *bus, const char *family, const char *address) {
|
||||
|
||||
log_debug("Looking up \"%s\".", full);
|
||||
|
||||
return resolve_record(bus, full,
|
||||
return resolve_record(full,
|
||||
arg_class ?: DNS_CLASS_IN,
|
||||
arg_type ?: DNS_TYPE_TLSA, true);
|
||||
}
|
||||
@@ -1159,17 +1091,12 @@ static bool service_family_is_valid(const char *s) {
|
||||
VERB(verb_tlsa, "tlsa", "DOMAIN[:PORT]…", 2, VERB_ANY, 0,
|
||||
"Query TLS public key");
|
||||
static int verb_tlsa(int argc, char *argv[], uintptr_t _data, void *userdata) {
|
||||
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
||||
const char *family = "tcp";
|
||||
char **args;
|
||||
int r, ret = 0;
|
||||
int ret = 0;
|
||||
|
||||
assert(argc >= 2);
|
||||
|
||||
r = acquire_bus(&bus);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (sd_json_format_enabled(arg_json_format_flags))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Use --json=pretty with --type= to acquire resource record information in JSON format.");
|
||||
|
||||
@@ -1180,7 +1107,7 @@ static int verb_tlsa(int argc, char *argv[], uintptr_t _data, void *userdata) {
|
||||
args = strv_skip(argv, 1);
|
||||
|
||||
STRV_FOREACH(p, args)
|
||||
RET_GATHER(ret, resolve_tlsa(bus, family, *p));
|
||||
RET_GATHER(ret, resolve_tlsa(family, *p));
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -2386,7 +2313,7 @@ static int dump_cache_scope(sd_json_variant *scope) {
|
||||
|
||||
static const sd_json_dispatch_field dispatch_table[] = {
|
||||
{ "protocol", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(struct scope_info, protocol), SD_JSON_MANDATORY },
|
||||
{ "family", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int, offsetof(struct scope_info, family), 0 },
|
||||
{ "family", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_address_family, offsetof(struct scope_info, family), SD_JSON_RELAX },
|
||||
{ "ifindex", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_ifindex, offsetof(struct scope_info, ifindex), SD_JSON_RELAX },
|
||||
{ "ifname", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(struct scope_info, ifname), 0 },
|
||||
{ "cache", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_variant_noref, offsetof(struct scope_info, cache), SD_JSON_MANDATORY },
|
||||
|
||||
@@ -135,7 +135,8 @@ static int reply_query_state(DnsQuery *q) {
|
||||
/* 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_varlink_errorbo(q->varlink_request, "io.systemd.Resolve.DNSError",
|
||||
SD_JSON_BUILD_PAIR_INTEGER("rcode", DNS_RCODE_NXDOMAIN));
|
||||
SD_JSON_BUILD_PAIR_INTEGER("rcode", DNS_RCODE_NXDOMAIN),
|
||||
JSON_BUILD_PAIR_STRING_NON_EMPTY("queryString", dns_query_string(q)));
|
||||
|
||||
case DNS_TRANSACTION_RCODE_FAILURE:
|
||||
return sd_varlink_errorbo(q->varlink_request, "io.systemd.Resolve.DNSError",
|
||||
@@ -143,7 +144,8 @@ static int reply_query_state(DnsQuery *q) {
|
||||
SD_JSON_BUILD_PAIR_CONDITION(q->answer_ede_rcode >= 0,
|
||||
"extendedDNSErrorCode", SD_JSON_BUILD_INTEGER(q->answer_ede_rcode)),
|
||||
SD_JSON_BUILD_PAIR_CONDITION(q->answer_ede_rcode >= 0 && !isempty(q->answer_ede_msg),
|
||||
"extendedDNSErrorMessage", SD_JSON_BUILD_STRING(q->answer_ede_msg)));
|
||||
"extendedDNSErrorMessage", SD_JSON_BUILD_STRING(q->answer_ede_msg)),
|
||||
JSON_BUILD_PAIR_STRING_NON_EMPTY("queryString", dns_query_string(q)));
|
||||
|
||||
case DNS_TRANSACTION_NULL:
|
||||
case DNS_TRANSACTION_PENDING:
|
||||
@@ -346,7 +348,7 @@ static int vl_method_resolve_hostname(sd_varlink *link, sd_json_variant *paramet
|
||||
static const sd_json_dispatch_field dispatch_table[] = {
|
||||
{ "ifindex", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_ifindex, offsetof(LookupParameters, ifindex), SD_JSON_RELAX },
|
||||
{ "name", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(LookupParameters, name), SD_JSON_MANDATORY },
|
||||
{ "family", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int, offsetof(LookupParameters, family), 0 },
|
||||
{ "family", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_address_family, offsetof(LookupParameters, family), SD_JSON_RELAX },
|
||||
{ "flags", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(LookupParameters, flags), 0 },
|
||||
{}
|
||||
};
|
||||
@@ -377,9 +379,6 @@ static int vl_method_resolve_hostname(sd_varlink *link, sd_json_variant *paramet
|
||||
if (r == 0)
|
||||
return sd_varlink_error_invalid_parameter(link, JSON_VARIANT_STRING_CONST("name"));
|
||||
|
||||
if (!IN_SET(p.family, AF_UNSPEC, AF_INET, AF_INET6))
|
||||
return sd_varlink_error_invalid_parameter(link, JSON_VARIANT_STRING_CONST("family"));
|
||||
|
||||
if (validate_and_mangle_query_flags(m, &p.flags, p.name, SD_RESOLVED_NO_SEARCH) < 0)
|
||||
return sd_varlink_error_invalid_parameter(link, JSON_VARIANT_STRING_CONST("flags"));
|
||||
|
||||
@@ -475,7 +474,7 @@ finish:
|
||||
static int vl_method_resolve_address(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
|
||||
static const sd_json_dispatch_field dispatch_table[] = {
|
||||
{ "ifindex", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_ifindex, offsetof(LookupParameters, ifindex), SD_JSON_RELAX },
|
||||
{ "family", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int, offsetof(LookupParameters, family), SD_JSON_MANDATORY },
|
||||
{ "family", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_address_family, offsetof(LookupParameters, family), SD_JSON_MANDATORY },
|
||||
{ "address", SD_JSON_VARIANT_ARRAY, json_dispatch_byte_array_iovec, offsetof(LookupParameters, address), SD_JSON_MANDATORY },
|
||||
{ "flags", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(LookupParameters, flags), 0 },
|
||||
{}
|
||||
@@ -501,9 +500,6 @@ static int vl_method_resolve_address(sd_varlink *link, sd_json_variant *paramete
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
if (!IN_SET(p.family, AF_INET, AF_INET6))
|
||||
return sd_varlink_error_invalid_parameter(link, JSON_VARIANT_STRING_CONST("family"));
|
||||
|
||||
if (FAMILY_ADDRESS_SIZE(p.family) != p.address.iov_len)
|
||||
return sd_varlink_error(link, "io.systemd.Resolve.BadAddressSize", NULL);
|
||||
|
||||
@@ -961,7 +957,7 @@ static int vl_method_resolve_service(sd_varlink* link, sd_json_variant* paramete
|
||||
{ "type", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(LookupParametersResolveService, type), 0 },
|
||||
{ "domain", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(LookupParametersResolveService, domain), SD_JSON_MANDATORY },
|
||||
{ "ifindex", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_ifindex, offsetof(LookupParametersResolveService, ifindex), SD_JSON_RELAX },
|
||||
{ "family", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int, offsetof(LookupParametersResolveService, family), 0 },
|
||||
{ "family", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_address_family, offsetof(LookupParametersResolveService, family), SD_JSON_RELAX },
|
||||
{ "flags", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(LookupParametersResolveService, flags), 0 },
|
||||
{}
|
||||
};
|
||||
@@ -987,9 +983,6 @@ static int vl_method_resolve_service(sd_varlink* link, sd_json_variant* paramete
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
if (!IN_SET(p.family, AF_INET, AF_INET6, AF_UNSPEC))
|
||||
return sd_varlink_error_invalid_parameter(link, JSON_VARIANT_STRING_CONST("family"));
|
||||
|
||||
if (isempty(p.name))
|
||||
p.name = NULL;
|
||||
else if (!dns_service_name_is_valid(p.name))
|
||||
|
||||
@@ -36,7 +36,7 @@ static int dispatch_dns_server(const char *name, sd_json_variant *variant, sd_js
|
||||
static const sd_json_dispatch_field dns_server_dispatch_table[] = {
|
||||
{ "address", SD_JSON_VARIANT_ARRAY, json_dispatch_byte_array_iovec, offsetof(DNSServer, addr), SD_JSON_MANDATORY },
|
||||
{ "addressString", _SD_JSON_VARIANT_TYPE_INVALID, NULL, 0, 0 },
|
||||
{ "family", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uint, offsetof(DNSServer, family), SD_JSON_MANDATORY },
|
||||
{ "family", SD_JSON_VARIANT_INTEGER, json_dispatch_address_family, offsetof(DNSServer, family), SD_JSON_MANDATORY },
|
||||
{ "port", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uint16, offsetof(DNSServer, port), 0 },
|
||||
{ "ifindex", SD_JSON_VARIANT_UNSIGNED, json_dispatch_ifindex, offsetof(DNSServer, ifindex), SD_JSON_RELAX },
|
||||
{ "name", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(DNSServer, server_name), 0 },
|
||||
@@ -177,12 +177,12 @@ DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
|
||||
|
||||
static int dispatch_dns_scope(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
|
||||
static const sd_json_dispatch_field dns_scope_dispatch_table[] = {
|
||||
{ "protocol", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(DNSScope, protocol), SD_JSON_MANDATORY },
|
||||
{ "family", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uint, offsetof(DNSScope, family), 0 },
|
||||
{ "ifname", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(DNSScope, ifname), 0 },
|
||||
{ "ifindex", SD_JSON_VARIANT_UNSIGNED, json_dispatch_ifindex, offsetof(DNSScope, ifindex), SD_JSON_RELAX },
|
||||
{ "dnssec", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(DNSScope, dnssec_mode_str), 0 },
|
||||
{ "dnsOverTLS", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(DNSScope, dns_over_tls_mode_str), 0 },
|
||||
{ "protocol", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(DNSScope, protocol), SD_JSON_MANDATORY },
|
||||
{ "family", SD_JSON_VARIANT_INTEGER, json_dispatch_address_family, offsetof(DNSScope, family), SD_JSON_RELAX },
|
||||
{ "ifname", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(DNSScope, ifname), 0 },
|
||||
{ "ifindex", SD_JSON_VARIANT_UNSIGNED, json_dispatch_ifindex, offsetof(DNSScope, ifindex), SD_JSON_RELAX },
|
||||
{ "dnssec", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(DNSScope, dnssec_mode_str), 0 },
|
||||
{ "dnsOverTLS", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(DNSScope, dns_over_tls_mode_str), 0 },
|
||||
{},
|
||||
};
|
||||
DNSScope **ret = ASSERT_PTR(userdata);
|
||||
|
||||
@@ -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,376 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "sd-json.h"
|
||||
|
||||
#include "dns-packet.h"
|
||||
#include "iovec-util.h"
|
||||
#include "json-util.h"
|
||||
#include "resolve-varlink-util.h"
|
||||
#include "strv.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;
|
||||
}
|
||||
|
||||
static void resolved_name_done(ResolvedName *name) {
|
||||
if (!name)
|
||||
return;
|
||||
|
||||
name->name = mfree(name->name);
|
||||
}
|
||||
|
||||
static int dispatch_resolved_name(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
|
||||
static const sd_json_dispatch_field resolved_name_dispatch_table[] = {
|
||||
{ "ifindex", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_ifindex, offsetof(ResolvedName, ifindex), SD_JSON_RELAX },
|
||||
{ "name", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(ResolvedName, name), SD_JSON_MANDATORY },
|
||||
{},
|
||||
};
|
||||
ResolvedName *ret = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
_cleanup_(resolved_name_done) ResolvedName resolved_name = {};
|
||||
r = sd_json_dispatch(variant, resolved_name_dispatch_table, flags & ~SD_JSON_MANDATORY, &resolved_name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*ret = TAKE_STRUCT(resolved_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dispatch_resolved_name_array(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
|
||||
ResolveAddressReply *reply = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
sd_json_variant *v;
|
||||
JSON_VARIANT_ARRAY_FOREACH(v, variant) {
|
||||
if (!GREEDY_REALLOC0(reply->names, reply->n_names + 1))
|
||||
return json_log_oom(variant, flags);
|
||||
|
||||
r = dispatch_resolved_name(name, v, flags, &reply->names[reply->n_names++]);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void resolve_address_reply_done(ResolveAddressReply *reply) {
|
||||
if (!reply)
|
||||
return;
|
||||
|
||||
FOREACH_ARRAY(n, reply->names, reply->n_names)
|
||||
resolved_name_done(n);
|
||||
reply->names = mfree(reply->names);
|
||||
reply->n_names = 0;
|
||||
}
|
||||
|
||||
int dispatch_resolve_address_reply(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
|
||||
static const sd_json_dispatch_field resolve_address_reply_dispatch_table[] = {
|
||||
{ "flags", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(ResolveAddressReply, flags), SD_JSON_MANDATORY },
|
||||
{ "names", SD_JSON_VARIANT_ARRAY, dispatch_resolved_name_array, 0, SD_JSON_MANDATORY },
|
||||
{},
|
||||
};
|
||||
ResolveAddressReply *ret = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
_cleanup_(resolve_address_reply_done) ResolveAddressReply reply = {};
|
||||
r = sd_json_dispatch(variant, resolve_address_reply_dispatch_table, flags | SD_JSON_ALLOW_EXTENSIONS, &reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*ret = TAKE_STRUCT(reply);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void resolved_record_done(ResolvedRecord *record) {
|
||||
if (!record)
|
||||
return;
|
||||
|
||||
iovec_done(&record->raw);
|
||||
}
|
||||
|
||||
static int dispatch_resolved_record(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
|
||||
static const sd_json_dispatch_field resolved_record_dispatch_table[] = {
|
||||
{ "ifindex", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_ifindex, offsetof(ResolvedRecord, ifindex), SD_JSON_RELAX },
|
||||
{ "raw", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_unbase64_iovec, offsetof(ResolvedRecord, raw), SD_JSON_MANDATORY },
|
||||
{ "rr", _SD_JSON_VARIANT_TYPE_INVALID, NULL, 0, 0 },
|
||||
{},
|
||||
};
|
||||
ResolvedRecord *ret = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
_cleanup_(resolved_record_done) ResolvedRecord record = {};
|
||||
r = sd_json_dispatch(variant, resolved_record_dispatch_table, flags & ~SD_JSON_MANDATORY, &record);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*ret = TAKE_STRUCT(record);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dispatch_resolved_record_array(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
|
||||
ResolveRecordReply *reply = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
sd_json_variant *v;
|
||||
JSON_VARIANT_ARRAY_FOREACH(v, variant) {
|
||||
if (!GREEDY_REALLOC0(reply->records, reply->n_records + 1))
|
||||
return json_log_oom(variant, flags);
|
||||
|
||||
r = dispatch_resolved_record(name, v, flags, &reply->records[reply->n_records++]);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void resolve_record_reply_done(ResolveRecordReply *reply) {
|
||||
if (!reply)
|
||||
return;
|
||||
|
||||
FOREACH_ARRAY(record, reply->records, reply->n_records)
|
||||
resolved_record_done(record);
|
||||
reply->records = mfree(reply->records);
|
||||
reply->n_records = 0;
|
||||
}
|
||||
|
||||
int dispatch_resolve_record_reply(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
|
||||
static const sd_json_dispatch_field resolve_record_reply_dispatch_table[] = {
|
||||
{ "flags", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(ResolveRecordReply, flags), SD_JSON_MANDATORY },
|
||||
{ "rrs", SD_JSON_VARIANT_ARRAY, dispatch_resolved_record_array, 0, SD_JSON_MANDATORY },
|
||||
{},
|
||||
};
|
||||
ResolveRecordReply *ret = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
_cleanup_(resolve_record_reply_done) ResolveRecordReply reply = {};
|
||||
r = sd_json_dispatch(variant, resolve_record_reply_dispatch_table, flags | SD_JSON_ALLOW_EXTENSIONS, &reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*ret = TAKE_STRUCT(reply);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void resolved_service_done(ResolvedService *service) {
|
||||
if (!service)
|
||||
return;
|
||||
|
||||
service->hostname = mfree(service->hostname);
|
||||
service->canonical_name = mfree(service->canonical_name);
|
||||
service->addresses = mfree(service->addresses);
|
||||
service->n_addresses = 0;
|
||||
}
|
||||
|
||||
static int dispatch_resolved_service_address_array(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
|
||||
ResolvedService *service = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
sd_json_variant *v;
|
||||
JSON_VARIANT_ARRAY_FOREACH(v, variant) {
|
||||
if (!GREEDY_REALLOC0(service->addresses, service->n_addresses + 1))
|
||||
return json_log_oom(variant, flags);
|
||||
|
||||
r = dispatch_resolved_address(name, v, flags, &service->addresses[service->n_addresses++]);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dispatch_resolved_service(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
|
||||
static const sd_json_dispatch_field resolved_service_dispatch_table[] = {
|
||||
{ "priority", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint16, offsetof(ResolvedService, priority), SD_JSON_MANDATORY },
|
||||
{ "weight", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint16, offsetof(ResolvedService, weight), SD_JSON_MANDATORY },
|
||||
{ "port", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint16, offsetof(ResolvedService, port), SD_JSON_MANDATORY },
|
||||
{ "hostname", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(ResolvedService, hostname), SD_JSON_MANDATORY },
|
||||
{ "canonicalName", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(ResolvedService, canonical_name), SD_JSON_NULLABLE },
|
||||
{ "addresses", SD_JSON_VARIANT_ARRAY, dispatch_resolved_service_address_array, 0, SD_JSON_NULLABLE },
|
||||
{},
|
||||
};
|
||||
ResolvedService *ret = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
_cleanup_(resolved_service_done) ResolvedService service = {};
|
||||
r = sd_json_dispatch(variant, resolved_service_dispatch_table, flags & ~SD_JSON_MANDATORY, &service);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*ret = TAKE_STRUCT(service);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dispatch_resolved_service_array(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
|
||||
ResolveServiceReply *reply = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
sd_json_variant *v;
|
||||
JSON_VARIANT_ARRAY_FOREACH(v, variant) {
|
||||
if (!GREEDY_REALLOC0(reply->services, reply->n_services + 1))
|
||||
return json_log_oom(variant, flags);
|
||||
|
||||
r = dispatch_resolved_service(name, v, flags, &reply->services[reply->n_services++]);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void resolved_canonical_done(ResolvedCanonical *canonical) {
|
||||
if (!canonical)
|
||||
return;
|
||||
|
||||
canonical->name = mfree(canonical->name);
|
||||
canonical->type = mfree(canonical->type);
|
||||
canonical->domain = mfree(canonical->domain);
|
||||
}
|
||||
|
||||
static int dispatch_resolved_canonical(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
|
||||
static const sd_json_dispatch_field resolved_canonical_dispatch_table[] = {
|
||||
{ "name", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(ResolvedCanonical, name), SD_JSON_NULLABLE },
|
||||
{ "type", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(ResolvedCanonical, type), SD_JSON_MANDATORY },
|
||||
{ "domain", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(ResolvedCanonical, domain), SD_JSON_MANDATORY },
|
||||
{},
|
||||
};
|
||||
ResolvedCanonical *ret = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
_cleanup_(resolved_canonical_done) ResolvedCanonical canonical = {};
|
||||
r = sd_json_dispatch(variant, resolved_canonical_dispatch_table, flags & ~SD_JSON_MANDATORY, &canonical);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*ret = TAKE_STRUCT(canonical);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void resolve_service_reply_done(ResolveServiceReply *reply) {
|
||||
if (!reply)
|
||||
return;
|
||||
|
||||
FOREACH_ARRAY(service, reply->services, reply->n_services)
|
||||
resolved_service_done(service);
|
||||
reply->services = mfree(reply->services);
|
||||
reply->n_services = 0;
|
||||
reply->txt = strv_free(reply->txt);
|
||||
resolved_canonical_done(&reply->canonical);
|
||||
}
|
||||
|
||||
int dispatch_resolve_service_reply(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
|
||||
static const sd_json_dispatch_field resolve_service_reply_dispatch_table[] = {
|
||||
{ "services", SD_JSON_VARIANT_ARRAY, dispatch_resolved_service_array, 0, SD_JSON_MANDATORY },
|
||||
{ "txt", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_strv, offsetof(ResolveServiceReply, txt), SD_JSON_NULLABLE },
|
||||
{ "canonical", SD_JSON_VARIANT_OBJECT, dispatch_resolved_canonical, offsetof(ResolveServiceReply, canonical), SD_JSON_MANDATORY },
|
||||
{ "flags", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(ResolveServiceReply, flags), SD_JSON_MANDATORY },
|
||||
{},
|
||||
};
|
||||
ResolveServiceReply *ret = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
_cleanup_(resolve_service_reply_done) ResolveServiceReply reply = {};
|
||||
r = sd_json_dispatch(variant, resolve_service_reply_dispatch_table, flags | SD_JSON_ALLOW_EXTENSIONS, &reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*ret = TAKE_STRUCT(reply);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include <sys/uio.h>
|
||||
|
||||
#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);
|
||||
|
||||
typedef struct ResolvedName {
|
||||
int ifindex;
|
||||
char *name;
|
||||
} ResolvedName;
|
||||
|
||||
typedef struct ResolveAddressReply {
|
||||
uint64_t flags;
|
||||
ResolvedName *names;
|
||||
size_t n_names;
|
||||
} ResolveAddressReply;
|
||||
|
||||
void resolve_address_reply_done(ResolveAddressReply *reply);
|
||||
|
||||
int dispatch_resolve_address_reply(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
|
||||
|
||||
typedef struct ResolvedRecord {
|
||||
int ifindex;
|
||||
struct iovec raw;
|
||||
} ResolvedRecord;
|
||||
|
||||
typedef struct ResolveRecordReply {
|
||||
uint64_t flags;
|
||||
ResolvedRecord *records;
|
||||
size_t n_records;
|
||||
} ResolveRecordReply;
|
||||
|
||||
void resolve_record_reply_done(ResolveRecordReply *reply);
|
||||
|
||||
int dispatch_resolve_record_reply(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
|
||||
|
||||
typedef struct ResolvedService {
|
||||
uint16_t priority;
|
||||
uint16_t weight;
|
||||
uint16_t port;
|
||||
char *hostname;
|
||||
char *canonical_name;
|
||||
ResolvedAddress *addresses;
|
||||
size_t n_addresses;
|
||||
} ResolvedService;
|
||||
|
||||
typedef struct ResolvedCanonical {
|
||||
char *name;
|
||||
char *type;
|
||||
char *domain;
|
||||
} ResolvedCanonical;
|
||||
|
||||
typedef struct ResolveServiceReply {
|
||||
ResolvedService *services;
|
||||
size_t n_services;
|
||||
char **txt;
|
||||
ResolvedCanonical canonical;
|
||||
uint64_t flags;
|
||||
} ResolveServiceReply;
|
||||
|
||||
void resolve_service_reply_done(ResolveServiceReply *reply);
|
||||
|
||||
int dispatch_resolve_service_reply(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
|
||||
@@ -337,6 +337,7 @@ static SD_VARLINK_DEFINE_ERROR(StubLoop);
|
||||
static SD_VARLINK_DEFINE_ERROR(
|
||||
DNSError,
|
||||
SD_VARLINK_DEFINE_FIELD(rcode, SD_VARLINK_INT, 0),
|
||||
SD_VARLINK_DEFINE_FIELD(queryString, SD_VARLINK_STRING, 0),
|
||||
SD_VARLINK_DEFINE_FIELD(extendedDNSErrorCode, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_DEFINE_FIELD(extendedDNSErrorMessage, SD_VARLINK_STRING, SD_VARLINK_NULLABLE));
|
||||
static SD_VARLINK_DEFINE_ERROR(CNAMELoop);
|
||||
|
||||
@@ -770,7 +770,7 @@ testcase_08_resolved() {
|
||||
grep -qE "^edns-extra-text.forwarded.test.+: SERVFAIL \(Censored: Nothing to see here!\)" "$RUN_OUT"
|
||||
(! run varlinkctl call /run/systemd/resolve/io.systemd.Resolve io.systemd.Resolve.ResolveHostname '{"name" : "edns-extra-text.forwarded.test"}')
|
||||
grep -qF "io.systemd.Resolve.DNSError" "$RUN_OUT"
|
||||
grep -qF '{"rcode":2,"extendedDNSErrorCode":16,"extendedDNSErrorMessage":"Nothing to see here!"}' "$RUN_OUT"
|
||||
grep -qF '{"rcode":2,"extendedDNSErrorCode":16,"extendedDNSErrorMessage":"Nothing to see here!","queryString":"edns-extra-text.forwarded.test"}' "$RUN_OUT"
|
||||
journalctl --sync
|
||||
journalctl -u systemd-resolved.service --cursor-file="$JOURNAL_CURSOR" --grep "Server returned error: SERVFAIL \(Censored: Nothing to see here!\)"
|
||||
|
||||
@@ -779,7 +779,7 @@ testcase_08_resolved() {
|
||||
grep -qE "^edns-code-zero.forwarded.test:.+: SERVFAIL \(Other: 🐱\)" "$RUN_OUT"
|
||||
(! run varlinkctl call /run/systemd/resolve/io.systemd.Resolve io.systemd.Resolve.ResolveHostname '{"name" : "edns-code-zero.forwarded.test"}')
|
||||
grep -qF "io.systemd.Resolve.DNSError" "$RUN_OUT"
|
||||
grep -qF '{"rcode":2,"extendedDNSErrorCode":0,"extendedDNSErrorMessage":"🐱"}' "$RUN_OUT"
|
||||
grep -qF '{"rcode":2,"extendedDNSErrorCode":0,"extendedDNSErrorMessage":"🐱","queryString":"edns-code-zero.forwarded.test"}' "$RUN_OUT"
|
||||
journalctl --sync
|
||||
journalctl -u systemd-resolved.service --cursor-file="$JOURNAL_CURSOR" --grep "Server returned error: SERVFAIL \(Other: 🐱\)"
|
||||
|
||||
@@ -788,7 +788,7 @@ testcase_08_resolved() {
|
||||
grep -qE "^edns-invalid-code.forwarded.test:.+: SERVFAIL \([0-9]+\)" "$RUN_OUT"
|
||||
(! run varlinkctl call /run/systemd/resolve/io.systemd.Resolve io.systemd.Resolve.ResolveHostname '{"name" : "edns-invalid-code.forwarded.test"}')
|
||||
grep -qF "io.systemd.Resolve.DNSError" "$RUN_OUT"
|
||||
grep -qE '{"rcode":2,"extendedDNSErrorCode":[0-9]+}' "$RUN_OUT"
|
||||
grep -qE '{"rcode":2,"extendedDNSErrorCode":[0-9]+,"queryString":"edns-invalid-code.forwarded.test"}' "$RUN_OUT"
|
||||
journalctl --sync
|
||||
journalctl -u systemd-resolved.service --cursor-file="$JOURNAL_CURSOR" --grep "Server returned error: SERVFAIL \(\d+\)"
|
||||
|
||||
@@ -797,7 +797,7 @@ testcase_08_resolved() {
|
||||
grep -qE '^edns-invalid-code-with-extra-text.forwarded.test:.+: SERVFAIL \([0-9]+: Hello \[#\]\$%~ World\)' "$RUN_OUT"
|
||||
(! run varlinkctl call /run/systemd/resolve/io.systemd.Resolve io.systemd.Resolve.ResolveHostname '{"name" : "edns-invalid-code-with-extra-text.forwarded.test"}')
|
||||
grep -qF "io.systemd.Resolve.DNSError" "$RUN_OUT"
|
||||
grep -qE '{"rcode":2,"extendedDNSErrorCode":[0-9]+,"extendedDNSErrorMessage":"Hello \[#\]\$%~ World"}' "$RUN_OUT"
|
||||
grep -qE '{"rcode":2,"extendedDNSErrorCode":[0-9]+,"extendedDNSErrorMessage":"Hello \[#\]\$%~ World","queryString":"edns-invalid-code-with-extra-text.forwarded.test"}' "$RUN_OUT"
|
||||
journalctl --sync
|
||||
journalctl -u systemd-resolved.service --cursor-file="$JOURNAL_CURSOR" --grep "Server returned error: SERVFAIL \(\d+: Hello \[\#\]\\$%~ World\)"
|
||||
}
|
||||
@@ -1258,13 +1258,13 @@ testcase_14_refuse_record_types() {
|
||||
grep -qF "127.128.0.5" "$RUN_OUT"
|
||||
|
||||
(! run resolvectl query localhost5 --type=SRV)
|
||||
grep -qF "DNS query type refused." "$RUN_OUT"
|
||||
grep -qF "DNS query type refused" "$RUN_OUT"
|
||||
|
||||
(! run resolvectl query localhost5 --type=TXT)
|
||||
grep -qF "DNS query type refused." "$RUN_OUT"
|
||||
grep -qF "DNS query type refused" "$RUN_OUT"
|
||||
|
||||
(! run resolvectl query localhost5 --type=AAAA)
|
||||
grep -qF "DNS query type refused." "$RUN_OUT"
|
||||
grep -qF "DNS query type refused" "$RUN_OUT"
|
||||
|
||||
run resolvectl query localhost5 --type=A
|
||||
grep -qF "127.128.0.5" "$RUN_OUT"
|
||||
@@ -1304,7 +1304,7 @@ testcase_14_refuse_record_types() {
|
||||
grep -qF "does not have any RR of the requested type" "$RUN_OUT"
|
||||
|
||||
(! run resolvectl query localhost5 --type=AAAA)
|
||||
grep -qF "DNS query type refused." "$RUN_OUT"
|
||||
grep -qF "DNS query type refused" "$RUN_OUT"
|
||||
|
||||
run resolvectl service _mysvc._tcp signed.test
|
||||
grep -qF "myservice.signed.test:1234" "$RUN_OUT"
|
||||
|
||||
Reference in New Issue
Block a user