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:
Yu Watanabe
2026-06-27 12:21:19 +09:00
committed by GitHub
13 changed files with 1108 additions and 631 deletions
+79
View File
@@ -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;
}
+2
View File
@@ -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);
+194
View File
@@ -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);
-22
View File
@@ -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
View File
@@ -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
View File
@@ -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 },
+7 -14
View File
@@ -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))
+7 -7
View File
@@ -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);
+1
View File
@@ -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',
+376
View File
@@ -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;
}
+94
View File
@@ -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);
+1
View File
@@ -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);
+8 -8
View File
@@ -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"