extra-repos/systemd: backport timesyncd DNSSEC NTP fix

43380.patch was merged upstream but is not yet in a release. The other
two patches are implicit dependencies of this patch and had to be
backported as well. They move json parsing into shared code and switch
resolvectl's query path to use varlink. They are large, but *seem* low
risk.

Fixes #4831

Signed-off-by: Clayton Craft <craftyguy@postmarketos.org>
Part-of: <https://gitlab.postmarketos.org/postmarketOS/pmaports/-/merge_requests/9416>
This commit is contained in:
Clayton Craft
2026-08-22 23:47:32 +00:00
parent 434e7af46d
commit 369c5ac3b6
6 changed files with 1422 additions and 2 deletions
+1 -1
View File
@@ -5,7 +5,7 @@ pkgname=systemd-stage0
pkgver=261.2
_pkgver="${pkgver/_/-}"
# pkgrel must match systemd!
pkgrel=0
pkgrel=1
pkgdesc="Minimal systemd bootstrap package"
url="https://github.com/systemd/systemd"
# armhf: pmb#2618
@@ -0,0 +1,249 @@
From c5f08a2e5cf1f246c908ddaaefbccdcfbdbaa754 Mon Sep 17 00:00:00 2001
From: Nick Rosbrook <enr0n@ubuntu.com>
Date: Fri, 19 Jun 2026 15:00:59 -0400
Subject: [PATCH] json-util: generalize json_dispatch_address_family
There are several places where address family is dispatched from JSON,
so take json_dispatch_address_family from networkd and put it in
json-util.c.
Update the all instances in the tree to use this new function, adding
SD_JSON_RELAX to the dispatch flags if AF_UNSPEC should be allowed
in that case.
---
src/libsystemd/sd-json/json-util.c | 24 ++++++++++++++++++++++++
src/libsystemd/sd-json/json-util.h | 1 +
src/network/networkd-serialize.c | 22 ----------------------
src/nss-resolve/nss-resolve.c | 23 +++--------------------
src/resolve/resolvectl.c | 2 +-
src/resolve/resolved-varlink.c | 15 +++------------
src/shared/dns-configuration.c | 14 +++++++-------
7 files changed, 39 insertions(+), 62 deletions(-)
diff --git a/src/libsystemd/sd-json/json-util.c b/src/libsystemd/sd-json/json-util.c
index c6727ac760..485b4a03c8 100644
--- a/src/libsystemd/sd-json/json-util.c
+++ b/src/libsystemd/sd-json/json-util.c
@@ -918,3 +918,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;
+}
diff --git a/src/libsystemd/sd-json/json-util.h b/src/libsystemd/sd-json/json-util.h
index ecb4e2d633..de7790a6d3 100644
--- a/src/libsystemd/sd-json/json-util.h
+++ b/src/libsystemd/sd-json/json-util.h
@@ -133,6 +133,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);
diff --git a/src/network/networkd-serialize.c b/src/network/networkd-serialize.c
index 394f03ced6..224fcc93a0 100644
--- a/src/network/networkd-serialize.c
+++ b/src/network/networkd-serialize.c
@@ -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;
diff --git a/src/nss-resolve/nss-resolve.c b/src/nss-resolve/nss-resolve.c
index 86eaf4e3b3..9f4225be3f 100644
--- a/src/nss-resolve/nss-resolve.c
+++ b/src/nss-resolve/nss-resolve.c
@@ -78,23 +78,6 @@ static uint32_t ifindex_to_scopeid(int family, const void *a, int ifindex) {
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;
@@ -159,9 +142,9 @@ static int json_dispatch_address(const char *name, sd_json_variant *variant, sd_
}
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 },
+ { "ifindex", SD_JSON_VARIANT_INTEGER, json_dispatch_ifindex, offsetof(AddressParameters, ifindex), 0 },
+ { "family", SD_JSON_VARIANT_INTEGER, json_dispatch_address_family, offsetof(AddressParameters, family), SD_JSON_MANDATORY },
+ { "address", SD_JSON_VARIANT_ARRAY, json_dispatch_address, 0, SD_JSON_MANDATORY },
{}
};
diff --git a/src/resolve/resolvectl.c b/src/resolve/resolvectl.c
index 67be81195a..b3895df6cf 100644
--- a/src/resolve/resolvectl.c
+++ b/src/resolve/resolvectl.c
@@ -2386,7 +2386,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 },
diff --git a/src/resolve/resolved-varlink.c b/src/resolve/resolved-varlink.c
index 2ac4ee9555..db26ccb11a 100644
--- a/src/resolve/resolved-varlink.c
+++ b/src/resolve/resolved-varlink.c
@@ -346,7 +346,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 +377,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 +472,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 +498,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 +955,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 +981,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))
diff --git a/src/shared/dns-configuration.c b/src/shared/dns-configuration.c
index 1194e87258..01b59bbd89 100644
--- a/src/shared/dns-configuration.c
+++ b/src/shared/dns-configuration.c
@@ -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);
--
2.55.0
@@ -0,0 +1,305 @@
From 3f73f1ef75d5c8da66eda2cff270676e70becf9b Mon Sep 17 00:00:00 2001
From: Nick Rosbrook <enr0n@ubuntu.com>
Date: Tue, 23 Jun 2026 12:02:19 -0400
Subject: [PATCH] json-util: introduce json_dispatch_in_addr_data
Generalize json_dispatch_address from nss-resolve, and add support for
strings to be compatible with the existing json_dispatch_{in,in6}_addr
helpers. This will be used in a later commit.
---
src/libsystemd/sd-json/json-util.c | 55 ++++++++
src/libsystemd/sd-json/json-util.h | 1 +
src/libsystemd/sd-json/test-json.c | 194 +++++++++++++++++++++++++++++
3 files changed, 250 insertions(+)
diff --git a/src/libsystemd/sd-json/json-util.c b/src/libsystemd/sd-json/json-util.c
index 485b4a03c8..193ee714d0 100644
--- a/src/libsystemd/sd-json/json-util.c
+++ b/src/libsystemd/sd-json/json-util.c
@@ -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;
diff --git a/src/libsystemd/sd-json/json-util.h b/src/libsystemd/sd-json/json-util.h
index de7790a6d3..2032566fdd 100644
--- a/src/libsystemd/sd-json/json-util.h
+++ b/src/libsystemd/sd-json/json-util.h
@@ -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);
diff --git a/src/libsystemd/sd-json/test-json.c b/src/libsystemd/sd-json/test-json.c
index bb94dfea4b..6992d095c6 100644
--- a/src/libsystemd/sd-json/test-json.c
+++ b/src/libsystemd/sd-json/test-json.c
@@ -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);
--
2.55.0
@@ -0,0 +1,440 @@
From 35d611622a0c4277e1a3e0b8866a800c0fc6fcf8 Mon Sep 17 00:00:00 2001
From: Nick Rosbrook <enr0n@ubuntu.com>
Date: Fri, 19 Jun 2026 15:01:00 -0400
Subject: [PATCH] resolvectl: use varlink instead of dbus for ResolveHostname
---
src/resolve/resolvectl.c | 202 +++++++++++++++++++-----------
src/shared/meson.build | 1 +
src/shared/resolve-varlink-util.c | 107 ++++++++++++++++
src/shared/resolve-varlink-util.h | 34 +++++
4 files changed, 274 insertions(+), 70 deletions(-)
create mode 100644 src/shared/resolve-varlink-util.c
create mode 100644 src/shared/resolve-varlink-util.h
diff --git a/src/resolve/resolvectl.c b/src/resolve/resolvectl.c
index b3895df6cf..4baa2f3868 100644
--- a/src/resolve/resolvectl.c
+++ b/src/resolve/resolvectl.c
@@ -48,6 +48,7 @@
#include "resolvectl.h"
#include "resolved-def.h"
#include "resolved-util.h"
+#include "resolve-varlink-util.h"
#include "set.h"
#include "socket-netlink.h"
#include "string-table.h"
@@ -278,20 +279,97 @@ static void print_ifindex_comment(int printed_so_far, int ifindex) {
ansi_grey(), ifname, ansi_normal());
}
-static int resolve_host_error(const char *name, int r, const sd_bus_error *error) {
- if (sd_bus_error_has_name(error, BUS_ERROR_DNS_NXDOMAIN))
- return log_error_errno(r, "%s: %s", name, bus_error_message(error, r));
+static int varlink_log_resolve_error(const char *name, const char *error_id, sd_json_variant *reply) {
+ int r;
+
+ 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);
- return log_error_errno(r, "%s: resolve call failed: %s", name, bus_error_message(error, r));
+ if (streq(error_id, "io.systemd.Resolve.CNAMELoop"))
+ return log_error_errno(ret, "%s: resolve call failed: CNAME loop detected, or CNAME resolving disabled on '%s'", name, name);
+
+ if (streq(error_id, "io.systemd.Resolve.ServiceNotProvided"))
+ return log_error_errno(ret, "%s: resolve call failed: '%s' does not provide the requested service", name, name);
+
+ if (streq(error_id, "io.systemd.Resolve.InconsistentServiceRecords"))
+ return log_error_errno(ret, "%s: resolve call failed: '%s' does not provide a consistent set of service resource records", name, name);
+
+ _cleanup_(resolve_error_done) ResolveError error = {
+ .rcode = _DNS_RCODE_INVALID,
+ .ede_rcode = _DNS_EDE_RCODE_INVALID,
+ };
+ r = dispatch_resolve_error(/* name = */ NULL, reply, SD_JSON_LOG, &error);
+ if (r < 0)
+ log_debug_errno(r, "Failed to dispatch error JSON, ignoring: %m");
+
+ _cleanup_free_ char *msg_extended = NULL;
+ if (error.ede_rcode >= 0) {
+ msg_extended = strjoin(" (",
+ FORMAT_DNS_EDE_RCODE(error.ede_rcode),
+ !isempty(error.ede_msg) ? ": " : "",
+ strempty(error.ede_msg),
+ ")");
+ if (!msg_extended)
+ return log_oom();
+ }
+
+ if (streq(error_id, "io.systemd.Resolve.DNSSECValidationFailed"))
+ return log_error_errno(ret, "%s: resolve call failed: DNSSEC validation failed: %s%s", name, error.result, strempty(msg_extended));
+
+ if (error.rcode != _DNS_RCODE_INVALID) {
+ if (error.rcode == DNS_RCODE_NXDOMAIN)
+ return log_error_errno(SYNTHETIC_ERRNO(ENXIO), "%s: resolve call failed: Name '%s' not found%s%s",
+ name, error.query_string ?: name, error.ede_rcode >= 0 ? ":" : "", strempty(msg_extended));
+
+ return log_error_errno(ret, "%s: resolve call failed: Could not resolve '%s', server or network returned error: %s%s",
+ name, error.query_string ?: name, FORMAT_DNS_RCODE(error.rcode), strempty(msg_extended));
+ }
+
+ return log_error_errno(ret, "%s: resolve call failed: %s", name, error_id);
}
-static int resolve_host(sd_bus *bus, const char *name) {
- _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- const char *canonical = NULL;
- unsigned c = 0;
- uint64_t flags;
- usec_t ts;
+static int varlink_connect_with_query_timeout(sd_varlink **vl) {
+ int r;
+
+ assert(vl);
+
+ r = sd_varlink_connect_address(vl, "/run/systemd/resolve/io.systemd.Resolve");
+ if (r < 0)
+ return log_error_errno(r, "Failed to connect to service /run/systemd/resolve/io.systemd.Resolve: %m");
+
+ r = sd_varlink_set_relative_timeout(*vl, SD_RESOLVED_QUERY_TIMEOUT_USEC);
+ if (r < 0)
+ return log_error_errno(r, "Failed to set query timeout: %m");
+
+ return 0;
+}
+
+static int resolve_host(const char *name) {
int r;
assert(name);
@@ -301,85 +379,69 @@ static int resolve_host(sd_bus *bus, const char *name) {
log_debug("Resolving %s (family %s, interface %s).", name, af_to_name(arg_family) ?: "*", isempty(arg_ifname) ? "*" : arg_ifname);
- r = bus_message_new_method_call(bus, &req, bus_resolve_mgr, "ResolveHostname");
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_append(req, "isit", arg_ifindex, name, arg_family, arg_flags);
+ _cleanup_(sd_varlink_unrefp) sd_varlink *vl = NULL;
+ r = varlink_connect_with_query_timeout(&vl);
if (r < 0)
- return bus_log_create_error(r);
+ return r;
- ts = now(CLOCK_MONOTONIC);
+ usec_t ts = now(CLOCK_MONOTONIC);
- r = sd_bus_call(bus, req, SD_RESOLVED_QUERY_TIMEOUT_USEC, &error, &reply);
+ const char *error_id = NULL;
+ sd_json_variant *v = NULL;
+ r = sd_varlink_callbo(
+ vl,
+ "io.systemd.Resolve.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 resolve_host_error(name, r, &error);
+ return log_error_errno(r, "Failed to issue varlink call: %m");
ts = now(CLOCK_MONOTONIC) - ts;
- r = sd_bus_message_enter_container(reply, 'a', "(iiay)");
+ if (!isempty(error_id))
+ return varlink_log_resolve_error(name, error_id, v);
+
+ _cleanup_(resolve_hostname_reply_done) ResolveHostnameReply reply = {};
+ r = dispatch_resolve_hostname_reply(/* name = */ NULL, v, SD_JSON_LOG, &reply);
if (r < 0)
- return bus_log_parse_error(r);
+ return r;
- while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) {
+ bool first = true;
+ FOREACH_ARRAY(address, reply.addresses, reply.n_addresses) {
_cleanup_free_ char *pretty = NULL;
- int ifindex, family, k;
- union in_addr_union a;
-
- assert_cc(sizeof(int) == sizeof(int32_t));
-
- r = sd_bus_message_read(reply, "i", &ifindex);
- if (r < 0)
- return bus_log_parse_error(r);
-
- sd_bus_error_free(&error);
- r = bus_message_read_in_addr_auto(reply, &error, &family, &a);
- if (r < 0 && !sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS))
- return log_error_errno(r, "%s: systemd-resolved returned invalid result: %s", name, bus_error_message(&error, r));
-
- r = sd_bus_message_exit_container(reply);
- if (r < 0)
- return bus_log_parse_error(r);
-
- if (sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS)) {
- log_debug_errno(r, "%s: systemd-resolved returned invalid result, ignoring: %s", name, bus_error_message(&error, r));
- continue;
- }
-
- r = in_addr_ifindex_to_string(family, &a, ifindex, &pretty);
+ r = in_addr_ifindex_to_string(address->family, &address->in_addr.address, address->ifindex, &pretty);
if (r < 0)
return log_error_errno(r, "Failed to print address for %s: %m", name);
- k = printf("%*s%s %s%s%s",
- (int) strlen(name), c == 0 ? name : "", c == 0 ? ":" : " ",
- ansi_highlight(), pretty, ansi_normal());
+ int k = printf("%*s%s %s%s%s",
+ (int) strlen(name),
+ first ? name : "",
+ first ? ":" : " ",
+ ansi_highlight(),
+ pretty,
+ ansi_normal());
- print_ifindex_comment(k, ifindex);
+ print_ifindex_comment(k, address->ifindex);
fputc('\n', stdout);
- c++;
+ first = false;
}
- if (r < 0)
- return bus_log_parse_error(r);
-
- r = sd_bus_message_exit_container(reply);
- if (r < 0)
- return bus_log_parse_error(r);
- r = sd_bus_message_read(reply, "st", &canonical, &flags);
- if (r < 0)
- return bus_log_parse_error(r);
-
- if (!streq(name, canonical))
+ if (!streq(name, reply.name))
printf("%*s%s (%s)\n",
- (int) strlen(name), c == 0 ? name : "", c == 0 ? ":" : " ",
- canonical);
+ (int) strlen(name),
+ reply.n_addresses == 0 ? name : "",
+ reply.n_addresses == 0 ? ":" : " ",
+ reply.name);
- if (c == 0)
- return log_error_errno(SYNTHETIC_ERRNO(ESRCH),
- "%s: no addresses found", name);
+ if (reply.n_addresses == 0)
+ return log_error_errno(SYNTHETIC_ERRNO(ESRCH), "%s: no addresses found", name);
- print_source(flags, ts);
+ print_source(reply.flags, ts);
return 0;
}
@@ -827,7 +889,7 @@ static int verb_query(int argc, char *argv[], uintptr_t _data, void *userdata) {
if (r >= 0)
RET_GATHER(ret, resolve_address(bus, family, &a, ifindex));
else
- RET_GATHER(ret, resolve_host(bus, *p));
+ RET_GATHER(ret, resolve_host(*p));
}
}
diff --git a/src/shared/meson.build b/src/shared/meson.build
index 6fa4216305..7b2a8b5ee2 100644
--- a/src/shared/meson.build
+++ b/src/shared/meson.build
@@ -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',
diff --git a/src/shared/resolve-varlink-util.c b/src/shared/resolve-varlink-util.c
new file mode 100644
index 0000000000..3459cfc9d6
--- /dev/null
+++ b/src/shared/resolve-varlink-util.c
@@ -0,0 +1,107 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "sd-json.h"
+
+#include "dns-packet.h"
+#include "json-util.h"
+#include "resolve-varlink-util.h"
+
+void resolve_error_done(ResolveError *error) {
+ if (!error)
+ return;
+
+ error->ede_msg = mfree(error->ede_msg);
+ error->query_string = mfree(error->query_string);
+ error->result = mfree(error->result);
+}
+
+int dispatch_resolve_error(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
+ static const sd_json_dispatch_field resolve_error_dispatch_table[] = {
+ { "rcode", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int, offsetof(ResolveError, rcode), 0 },
+ { "extendedDNSErrorCode", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int, offsetof(ResolveError, ede_rcode), 0 },
+ { "extendedDNSErrorMessage", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(ResolveError, ede_msg), 0 },
+ { "queryString", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(ResolveError, query_string), 0 },
+ { "result", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(ResolveError, result), 0 },
+ {},
+ };
+ ResolveError *ret = ASSERT_PTR(userdata);
+ int r;
+
+ _cleanup_(resolve_error_done) ResolveError error = {
+ .rcode = _DNS_RCODE_INVALID,
+ .ede_rcode = _DNS_EDE_RCODE_INVALID,
+ };
+ r = sd_json_dispatch(variant, resolve_error_dispatch_table, flags | SD_JSON_ALLOW_EXTENSIONS, &error);
+ if (r < 0)
+ return r;
+
+ *ret = TAKE_STRUCT(error);
+ return 0;
+}
+
+static int dispatch_resolved_address(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
+ static const sd_json_dispatch_field resolved_address_dispatch_table[] = {
+ { "ifindex", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_ifindex, offsetof(ResolvedAddress, ifindex), SD_JSON_RELAX },
+ { "family", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_address_family, offsetof(ResolvedAddress, family), SD_JSON_MANDATORY },
+ { "address", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_in_addr_data, offsetof(ResolvedAddress, in_addr), SD_JSON_MANDATORY },
+ {},
+ };
+ ResolvedAddress *ret = ASSERT_PTR(userdata);
+ int r;
+
+ ResolvedAddress address = {};
+ r = sd_json_dispatch(variant, resolved_address_dispatch_table, flags & ~SD_JSON_MANDATORY, &address);
+ if (r < 0)
+ return r;
+
+ if (address.family != address.in_addr.family)
+ return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "'%s' address and family are inconsistent.", strna(name));
+
+ *ret = TAKE_STRUCT(address);
+ return 0;
+}
+
+static int dispatch_resolved_address_array(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
+ ResolveHostnameReply *reply = ASSERT_PTR(userdata);
+ int r;
+
+ sd_json_variant *v;
+ JSON_VARIANT_ARRAY_FOREACH(v, variant) {
+ if (!GREEDY_REALLOC0(reply->addresses, reply->n_addresses + 1))
+ return json_log_oom(variant, flags);
+
+ r = dispatch_resolved_address(name, v, flags, &reply->addresses[reply->n_addresses++]);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
+void resolve_hostname_reply_done(ResolveHostnameReply *reply) {
+ if (!reply)
+ return;
+
+ reply->name = mfree(reply->name);
+ reply->addresses = mfree(reply->addresses);
+ reply->n_addresses = 0;
+}
+
+int dispatch_resolve_hostname_reply(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
+ static const sd_json_dispatch_field resolve_hostname_reply_dispatch_table[] = {
+ { "name", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(ResolveHostnameReply, name), SD_JSON_MANDATORY },
+ { "flags", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(ResolveHostnameReply, flags), SD_JSON_MANDATORY },
+ { "addresses", SD_JSON_VARIANT_ARRAY, dispatch_resolved_address_array, 0, SD_JSON_MANDATORY },
+ {},
+ };
+ ResolveHostnameReply *ret = ASSERT_PTR(userdata);
+ int r;
+
+ _cleanup_(resolve_hostname_reply_done) ResolveHostnameReply reply = {};
+ r = sd_json_dispatch(variant, resolve_hostname_reply_dispatch_table, flags | SD_JSON_ALLOW_EXTENSIONS, &reply);
+ if (r < 0)
+ return r;
+
+ *ret = TAKE_STRUCT(reply);
+ return 0;
+}
diff --git a/src/shared/resolve-varlink-util.h b/src/shared/resolve-varlink-util.h
new file mode 100644
index 0000000000..4e94fbe8c6
--- /dev/null
+++ b/src/shared/resolve-varlink-util.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include "in-addr-util.h"
+#include "shared-forward.h"
+
+typedef struct ResolveError {
+ int rcode;
+ int ede_rcode;
+ char *ede_msg;
+ char *query_string;
+ char *result;
+} ResolveError;
+
+void resolve_error_done(ResolveError *error);
+
+int dispatch_resolve_error(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
+
+typedef struct ResolvedAddress {
+ int ifindex;
+ int family;
+ struct in_addr_data in_addr;
+} ResolvedAddress;
+
+typedef struct ResolveHostnameReply {
+ char *name;
+ uint64_t flags;
+ ResolvedAddress *addresses;
+ size_t n_addresses;
+} ResolveHostnameReply;
+
+void resolve_hostname_reply_done(ResolveHostnameReply *reply);
+
+int dispatch_resolve_hostname_reply(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
--
2.55.0
+418
View File
@@ -0,0 +1,418 @@
From 98e7cc36f019e48a3f20db9787ccd38d899957f5 Mon Sep 17 00:00:00 2001
From: Clayton Craft <clayton@craftyguy.net>
Date: Thu, 13 Aug 2026 13:51:30 -0700
Subject: [PATCH 1/4] timesyncd: resolve NTP hostnames through resolved's
varlink interface
With DNSSEC on, resolved can't validate anything until the clock is
right, and without an RTC the only thing that fixes the clock is talking
to the NTP servers we're trying to resolve. On glibc the timesyncd unit
sets SYSTEMD_NSS_RESOLVE_VALIDATE=0 and nss-resolve turns that into a
per-query flag, which breaks the chicken/egg. musl (and other systems
not using nss-resolve) have no NSS, so nothing reads it there and we're
stuck.
So talk to resolved directly when it's there, and pass
SD_RESOLVED_NO_VALIDATE until we've synced the clock ourselves.
NTP-related lookups after that are validated normally, which is better
than what we get from nss. If resolved isn't around we just keep using
getaddrinfo().
The reply handler duplicates the tail of the getaddrinfo handler, since
the two differ in how they report failures. Varlink discards what the
callback returns, so it has to move on to the next host itself.
This also drops SYSTEMD_NSS_RESOLVE_VALIDATE=0 from the unit because
nss-resolve talks to resolved over the same socket we do, so the
getaddrinfo() path is only ever taken when resolved is unreachable, and
then nothing validates anyway.
---
src/timesync/timesyncd-manager.c | 136 +++++++++++++++++++++++++++--
src/timesync/timesyncd-manager.h | 1 +
units/systemd-timesyncd.service.in | 4 -
3 files changed, 132 insertions(+), 9 deletions(-)
diff --git a/src/timesync/timesyncd-manager.c b/src/timesync/timesyncd-manager.c
index b0f22516dfe3..7b2ed4f831a0 100644
--- a/src/timesync/timesyncd-manager.c
+++ b/src/timesync/timesyncd-manager.c
@@ -10,8 +10,10 @@
#include "sd-bus.h"
#include "sd-daemon.h"
+#include "sd-json.h"
#include "sd-messages.h"
#include "sd-network.h"
+#include "sd-varlink.h"
#include "alloc-util.h"
#include "clock-util.h"
@@ -23,6 +25,7 @@
#include "format-util.h"
#include "fs-util.h"
#include "hashmap.h"
+#include "in-addr-util.h"
#include "list.h"
#include "log.h"
#include "logarithm.h"
@@ -30,6 +33,8 @@
#include "random-util.h"
#include "ratelimit.h"
#include "resolve-private.h"
+#include "resolve-varlink-util.h"
+#include "resolved-def.h"
#include "socket-util.h"
#include "string-util.h"
#include "strv.h"
@@ -780,6 +785,119 @@ static int manager_resolve_handler(sd_resolve_query *q, int ret, const struct ad
return manager_begin(m);
}
+static int manager_resolve_varlink_reply(
+ sd_varlink *link,
+ sd_json_variant *parameters,
+ const char *error_id,
+ sd_varlink_reply_flags_t flags,
+ void *userdata) {
+
+ Manager *m = ASSERT_PTR(userdata);
+ int r;
+
+ assert(m->current_server_name);
+
+ _unused_ _cleanup_(sd_varlink_unrefp) sd_varlink *link_free = TAKE_PTR(m->resolve_varlink);
+
+ if (!isempty(error_id)) {
+ log_debug("Failed to resolve %s: %s", m->current_server_name->string, error_id);
+
+ /* Try next one */
+ return manager_connect(m);
+ }
+
+ _cleanup_(resolve_hostname_reply_done) ResolveHostnameReply reply = {};
+ r = dispatch_resolve_hostname_reply(/* name = */ NULL, parameters, SD_JSON_LOG, &reply);
+ if (r < 0) {
+ log_warning_errno(r, "Failed to parse reply for %s, ignoring: %m", m->current_server_name->string);
+
+ return manager_connect(m);
+ }
+
+ FOREACH_ARRAY(entry, reply.addresses, reply.n_addresses) {
+ _cleanup_free_ char *pretty = NULL;
+ union sockaddr_union sa = {};
+ ServerAddress *a;
+
+ if (!IN_SET(entry->family, AF_INET, AF_INET6)) {
+ log_debug("Ignoring unsuitable address protocol for %s.", m->current_server_name->string);
+ continue;
+ }
+
+ r = sockaddr_set_in_addr(&sa, entry->family, &entry->in_addr.address, 123);
+ if (r < 0) {
+ log_warning_errno(r, "Failed to convert address for %s, trying next host: %m", m->current_server_name->string);
+ return manager_connect(m);
+ }
+
+ /* Only link-local addresses need a scope, setting it on a global one pins us to one interface. */
+ if (entry->family == AF_INET6 && in6_addr_is_link_local(&entry->in_addr.address.in6))
+ sa.in6.sin6_scope_id = entry->ifindex;
+
+ r = server_address_new(m->current_server_name, &a, &sa, sockaddr_len(&sa));
+ if (r < 0) {
+ log_warning_errno(r, "Failed to add server address, trying next host: %m");
+ return manager_connect(m);
+ }
+
+ (void) server_address_pretty(a, &pretty);
+ log_debug("Resolved address %s for %s.", strna(pretty), m->current_server_name->string);
+ }
+
+ if (!m->current_server_name->addresses) {
+ log_error("Failed to find suitable address for host %s.", m->current_server_name->string);
+
+ /* Try next host */
+ return manager_connect(m);
+ }
+
+ manager_set_server_address(m, m->current_server_name->addresses);
+
+ return manager_begin(m);
+}
+
+/* Resolve the current server name through resolved's Varlink interface. This returns 0 if resolved is
+ * unavailable */
+static int manager_resolve_varlink(Manager *m) {
+ _cleanup_(sd_varlink_close_unrefp) sd_varlink *link = NULL;
+ int r;
+
+ assert(m);
+ assert(m->current_server_name);
+
+ r = sd_varlink_connect_address(&link, "/run/systemd/resolve/io.systemd.Resolve");
+ if (r < 0) {
+ log_debug_errno(r, "Failed to connect to systemd-resolved, using getaddrinfo(): %m");
+ return 0;
+ }
+
+ (void) sd_varlink_set_description(link, "timesyncd-resolve");
+ (void) sd_varlink_set_relative_timeout(link, SD_RESOLVED_QUERY_TIMEOUT_USEC);
+
+ r = sd_varlink_attach_event(link, m->event, SD_EVENT_PRIORITY_NORMAL);
+ if (r < 0)
+ return log_error_errno(r, "Failed to attach Varlink connection to event loop: %m");
+
+ r = sd_varlink_bind_reply(link, manager_resolve_varlink_reply);
+ if (r < 0)
+ return log_error_errno(r, "Failed to bind Varlink reply callback: %m");
+
+ sd_varlink_set_userdata(link, m);
+
+ /* Ask resolved to skip DNSSEC validation as long as our clock is not synchronized yet. */
+ r = sd_varlink_invokebo(
+ link,
+ "io.systemd.Resolve.ResolveHostname",
+ SD_JSON_BUILD_PAIR_STRING("name", m->current_server_name->string),
+ SD_JSON_BUILD_PAIR_CONDITION(!socket_ipv6_is_enabled(), "family", SD_JSON_BUILD_INTEGER(AF_INET)),
+ SD_JSON_BUILD_PAIR_UNSIGNED("flags", m->synchronized ? 0 : SD_RESOLVED_NO_VALIDATE));
+ if (r < 0)
+ return log_error_errno(r, "Failed to call ResolveHostname(): %m");
+
+ m->resolve_varlink = TAKE_PTR(link);
+ return 1;
+}
+
static int manager_retry_connect(sd_event_source *source, usec_t usec, void *userdata) {
Manager *m = ASSERT_PTR(userdata);
@@ -868,15 +986,22 @@ int manager_connect(Manager *m) {
manager_set_server_name(m, f);
}
- /* Tell the resolver to reread /etc/resolv.conf, in
- * case it changed. */
- res_init();
-
/* Flush out any previously resolved addresses */
server_name_flush_addresses(m->current_server_name);
log_debug("Resolving %s...", m->current_server_name->string);
+ /* Prefer resolved's varlink interface. If that's unavailable, then fall through to getaddrinfo below. */
+ r = manager_resolve_varlink(m);
+ if (r < 0)
+ return r;
+ if (r > 0)
+ return 1;
+
+ /* Tell the resolver to reread /etc/resolv.conf, in
+ * case it changed. */
+ res_init();
+
struct addrinfo hints = {
.ai_flags = AI_NUMERICSERV|AI_ADDRCONFIG,
.ai_socktype = SOCK_DGRAM,
@@ -901,6 +1026,7 @@ void manager_disconnect(Manager *m) {
assert(m);
m->resolve_query = sd_resolve_query_unref(m->resolve_query);
+ m->resolve_varlink = sd_varlink_close_unref(m->resolve_varlink);
m->event_timer = sd_event_source_unref(m->event_timer);
@@ -1035,7 +1161,7 @@ static bool manager_is_connected(Manager *m) {
/* Return true when the manager is sending a request, resolving a server name, or
* in a poll interval. */
- return m->server_socket >= 0 || m->resolve_query || m->event_timer;
+ return m->server_socket >= 0 || m->resolve_query || m->resolve_varlink || m->event_timer;
}
static int manager_network_event_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
diff --git a/src/timesync/timesyncd-manager.h b/src/timesync/timesyncd-manager.h
index 9966b64ac697..8c1e30f48fd5 100644
--- a/src/timesync/timesyncd-manager.h
+++ b/src/timesync/timesyncd-manager.h
@@ -41,6 +41,7 @@ typedef struct Manager {
/* peer */
sd_resolve_query *resolve_query;
+ sd_varlink *resolve_varlink;
sd_event_source *event_receive;
ServerName *current_server_name;
ServerAddress *current_server_address;
diff --git a/units/systemd-timesyncd.service.in b/units/systemd-timesyncd.service.in
index 560bcee92f4c..bc64e2414007 100644
--- a/units/systemd-timesyncd.service.in
+++ b/units/systemd-timesyncd.service.in
@@ -22,10 +22,6 @@ Wants=time-set.target
AmbientCapabilities=CAP_SYS_TIME
BusName=org.freedesktop.timesync1
CapabilityBoundingSet=CAP_SYS_TIME
-# Turn off DNSSEC validation for hostname look-ups, since those need the
-# correct time to work, but we likely won't acquire that without NTP. Let's
-# break this chicken-and-egg cycle here.
-Environment=SYSTEMD_NSS_RESOLVE_VALIDATE=0
ExecStart={{LIBEXECDIR}}/systemd-timesyncd
LockPersonality=yes
MemoryDenyWriteExecute=yes
From 6279910be7b26239ce7eb442b227a879cb66e24e Mon Sep 17 00:00:00 2001
From: Clayton Craft <clayton@craftyguy.net>
Date: Thu, 13 Aug 2026 14:01:59 -0700
Subject: [PATCH 2/4] timesyncd: order after systemd-resolved
Our first resolve happens way before sockets.target, and
systemd-resolved-varlink.socket has no ordering of its own, so there's
nothing making sure the socket is listening by then. Without this the
connect fails and we quietly fall back to getaddrinfo(), which is exactly
the case the varlink path is there for.
Order after both the service and the socket since either one is enough
on its own but neither covers every install situation. For example
resolved binds the socket itself when nothing hands it one, and on
systems where only the socket is enabled the service isn't started at
boot at all.
---
units/systemd-timesyncd.service.in | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/units/systemd-timesyncd.service.in b/units/systemd-timesyncd.service.in
index bc64e2414007..c1809710477b 100644
--- a/units/systemd-timesyncd.service.in
+++ b/units/systemd-timesyncd.service.in
@@ -13,7 +13,7 @@ Documentation=man:systemd-timesyncd.service(8)
ConditionCapability=CAP_SYS_TIME
ConditionVirtualization=!container
DefaultDependencies=no
-After=systemd-sysusers.service
+After=systemd-sysusers.service systemd-resolved.service systemd-resolved-varlink.socket
Before=time-set.target sysinit.target shutdown.target
Conflicts=shutdown.target
Wants=time-set.target
From 8027ff6ecd12058d08e0bb6dce046b86828f7dd4 Mon Sep 17 00:00:00 2001
From: Clayton Craft <clayton@craftyguy.net>
Date: Fri, 14 Aug 2026 15:19:56 -0700
Subject: [PATCH 3/4] timesyncd: don't ask for AAAA when IPv6 is disabled
ipv6_is_supported only tells us the kernel has IPv6, not that
it's usable. ipv6_is_enabled also checks the sysctl that turns
it off, so we stop resolving addresses we can't use.
---
src/timesync/timesyncd-manager.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/timesync/timesyncd-manager.c b/src/timesync/timesyncd-manager.c
index 7b2ed4f831a0..4b3978bebc7f 100644
--- a/src/timesync/timesyncd-manager.c
+++ b/src/timesync/timesyncd-manager.c
@@ -1005,7 +1005,7 @@ int manager_connect(Manager *m) {
struct addrinfo hints = {
.ai_flags = AI_NUMERICSERV|AI_ADDRCONFIG,
.ai_socktype = SOCK_DGRAM,
- .ai_family = socket_ipv6_is_supported() ? AF_UNSPEC : AF_INET,
+ .ai_family = socket_ipv6_is_enabled() ? AF_UNSPEC : AF_INET,
};
r = resolve_getaddrinfo(m->resolve, &m->resolve_query, m->current_server_name->string, "123", &hints, manager_resolve_handler, NULL, m);
From d52a6931643a384b1184b1c30badb739ff885f78 Mon Sep 17 00:00:00 2001
From: Clayton Craft <clayton@craftyguy.net>
Date: Fri, 14 Aug 2026 14:25:01 -0700
Subject: [PATCH 4/4] test: cover both of timesyncd's resolver paths
This checks that we resolve through resolved when it's running, and fall back
to getaddrinfo when it isn't.
---
test/units/TEST-45-TIMEDATE.sh | 71 ++++++++++++++++++++++++++++++++++
1 file changed, 71 insertions(+)
diff --git a/test/units/TEST-45-TIMEDATE.sh b/test/units/TEST-45-TIMEDATE.sh
index 820c3ae9f52e..0af99fc96ce7 100755
--- a/test/units/TEST-45-TIMEDATE.sh
+++ b/test/units/TEST-45-TIMEDATE.sh
@@ -248,6 +248,19 @@ assert_timesyncd_state() {
return 1
}
+assert_timesyncd_log() {
+ local cursor="${1:?}"
+ local match="${2:?}"
+
+ for _ in {0..29}; do
+ journalctl --sync
+ journalctl -q -u systemd-timesyncd.service --after-cursor="$(<"$cursor")" --grep "$match" >/dev/null && return 0
+ sleep .5
+ done
+
+ return 1
+}
+
testcase_ntp() {
# timesyncd has ConditionVirtualization=!container by default; drop/mock that for testing
if systemd-detect-virt --container --quiet; then
@@ -409,6 +422,64 @@ EOF
rm -f /run/systemd/network/ntp99.*
}
+teardown_timesyncd_resolve() {
+ set +eu
+
+ systemctl start systemd-resolved-varlink.socket
+ systemctl start systemd-resolved.service
+
+ rm -rf /run/systemd/system/systemd-timesyncd.service.d
+ systemctl daemon-reload
+ systemctl stop systemd-timesyncd
+}
+
+testcase_timesyncd_resolve() {
+ local cursor
+
+ if systemd-detect-virt -cq; then
+ echo "This test case requires a VM, skipping..."
+ return 0
+ fi
+
+ if ! command -v resolvectl >/dev/null; then
+ echo "This test requires systemd-resolved, skipping..."
+ return 0
+ fi
+
+ trap teardown_timesyncd_resolve RETURN
+
+ mkdir -p /run/systemd/system/systemd-timesyncd.service.d
+ cat >/run/systemd/system/systemd-timesyncd.service.d/10-debug.conf <<EOF
+[Service]
+Environment=SYSTEMD_LOG_LEVEL=debug
+EOF
+ systemctl daemon-reload
+
+ systemctl unmask systemd-resolved
+ systemctl unmask systemd-timesyncd
+ systemctl start systemd-resolved-varlink.socket
+ systemctl start systemd-resolved.service
+ systemctl restart systemd-timesyncd
+
+ cursor="$(mktemp)"
+
+ # Should use resolved for resolving names
+ journalctl -n0 -q --cursor-file="$cursor"
+ busctl call org.freedesktop.timesync1 /org/freedesktop/timesync1 org.freedesktop.timesync1.Manager \
+ SetRuntimeNTPServers as 1 foo.localhost
+ # Only the varlink path logs this, so it tells us which resolver ran
+ assert_timesyncd_log "$cursor" "io.systemd.Resolve.ResolveHostname"
+
+ # Without resolved, it should fall back to getaddrinfo
+ systemctl stop systemd-resolved-varlink.socket systemd-resolved-monitor.socket
+ systemctl stop systemd-resolved.service
+
+ journalctl -n0 -q --cursor-file="$cursor"
+ busctl call org.freedesktop.timesync1 /org/freedesktop/timesync1 org.freedesktop.timesync1.Manager \
+ SetRuntimeNTPServers as 1 foo.localhost
+ assert_timesyncd_log "$cursor" "Failed to connect to systemd-resolved, using getaddrinfo"
+}
+
teardown_timedated_alternate_paths() {
set +eu
+9 -1
View File
@@ -17,7 +17,7 @@ pkgname=systemd
pkgver=261.2
_pkgver="${pkgver/_/-}"
# pkgrel must match systemd-stage0!
pkgrel=0
pkgrel=1
pkgdesc="System and service manager"
url="https://github.com/systemd/systemd"
# armhf: no linux-stable
@@ -228,6 +228,10 @@ source="
$pkgname-$pkgver.tar.gz::https://github.com/systemd/systemd/archive/refs/tags/v$_pkgver.tar.gz
wired.network
42275.patch
43380.patch
0001-json-util-generalize-json_dispatch_address_family.patch
0001-json-util-introduce-json_dispatch_in_addr_data.patch
0001-resolvectl-use-varlink-instead-of-dbus-for-ResolveHo.patch
"
builddir=${_upstream_srcdir:-"$srcdir/$pkgname-$_pkgver"}
_meson_builddir=${_meson_builddir:-build}
@@ -643,4 +647,8 @@ sha512sums="
876f043970cb65b39ae15fba39f23bf94c7c3d80569503d6e8ea2c8013c30ee40ce43cb55cbcb1cf14d5c3021aafc09c0f67473bbf742d8964bf9fa30693b971 systemd-261.2.tar.gz
81c897fed8a3fbfb67ec591b2398a5d65e4af1b3ef379376c157c98d71f085b707f8ebc896d5571a94f99f8fc84fd6b43e3b879ca9b0d57fc6c4596034c7a777 wired.network
3e01f711f68e565f37e590e10f55ce9dfd371cc1f8d124f3a0fad47747449d92053d9701216eac96bb6203cf952a22dc8215bc9dff74c1866ce9a07f1cb84b3c 42275.patch
2991d3c38e7f78715970a964ece27c56c591e6e1daab5d41772c86023c3d66a07a4f89c22619a1da6422ff5447a8aee906c7862aeb4788274b66c807313ddbf1 43380.patch
ce7f4aa7a490da7e469f2e09fac4128d2dbab69a3c0c1384ec85c46a8b9f1d5074b75462f08ac60d4a09fb8cdea36d22850d634c8f7db434632497f47bae142f 0001-json-util-generalize-json_dispatch_address_family.patch
1267f3a25d9a242ed9a3027aeacb2b6adb38864ca316215c7db2edee8f8c66d2448f58c1754e3f08be1ba70cf68b3cc503aec67d170de64a378c09f18260e32b 0001-json-util-introduce-json_dispatch_in_addr_data.patch
8d9436dc5c150c9b8c3b1b19512fbea5fa1f0953a4261f4fb089a90878768156db5d47feb41450594bd9547d40ef14c50ca751c5a046cdd253bb5b72cf1fd54c 0001-resolvectl-use-varlink-instead-of-dbus-for-ResolveHo.patch
"