resolvectl: re-implement normal status output using varlink (#40529)

Currently, `resolvectl status` (and other status commands like
`resolvectl dns $iface`) uses varlink when asked to print JSON, but uses
dbus otherwise. This PR re-implements the regular status output to use
varlink instead of dbus.

This both simplifies the `resolvectl status` code, and is an incremental
step in replacing dbus usage with varlink throughout `resolvectl`.

The first several commits move `dns-configuration.[ch]` from
`src/network/wait-online` to `src/shared`, and complete the JSON
dispatching so that all fields are available in a concrete type. The
next few commits re-implement global, link, and delegate status output.
Finally, the last commits consolidate and simplify the status logic
since varlink and the `DNSConfiguration` type can be used in all cases.
This commit is contained in:
Yu Watanabe
2026-02-04 15:47:02 +09:00
committed by GitHub
7 changed files with 590 additions and 1097 deletions
-1
View File
@@ -116,7 +116,6 @@ systemd_networkd_extract_sources = files(
)
systemd_networkd_wait_online_sources = files(
'wait-online/dns-configuration.c',
'wait-online/wait-online-link.c',
'wait-online/wait-online-manager.c',
'wait-online/wait-online.c',
+443 -1065
View File
File diff suppressed because it is too large Load Diff
+5
View File
@@ -2055,6 +2055,7 @@ static int dns_configuration_json_append(
Set *negative_trust_anchors,
Set *dns_scopes,
DnssecMode dnssec_mode,
bool dnssec_supported,
DnsOverTlsMode dns_over_tls_mode,
ResolveSupport llmnr_support,
ResolveSupport mdns_support,
@@ -2138,6 +2139,7 @@ static int dns_configuration_json_append(
SD_JSON_BUILD_PAIR_CONDITION(!set_isempty(negative_trust_anchors),
"negativeTrustAnchors",
JSON_BUILD_STRING_SET(negative_trust_anchors)),
JSON_BUILD_PAIR_CONDITION_BOOLEAN(dnssec_mode >= 0, "dnssecSupported", dnssec_supported),
JSON_BUILD_PAIR_STRING_NON_EMPTY("dnssec", dnssec_mode_to_string(dnssec_mode)),
JSON_BUILD_PAIR_STRING_NON_EMPTY("dnsOverTLS", dns_over_tls_mode_to_string(dns_over_tls_mode)),
JSON_BUILD_PAIR_STRING_NON_EMPTY("llmnr", resolve_support_to_string(llmnr_support)),
@@ -2169,6 +2171,7 @@ static int global_dns_configuration_json_append(Manager *m, sd_json_variant **co
m->trust_anchor.negative_by_name,
scopes,
manager_get_dnssec_mode(m),
manager_dnssec_supported(m),
manager_get_dns_over_tls_mode(m),
m->llmnr_support,
m->mdns_support,
@@ -2225,6 +2228,7 @@ static int link_dns_configuration_json_append(Link *l, sd_json_variant **configu
l->dnssec_negative_trust_anchors,
scopes,
link_get_dnssec_mode(l),
link_dnssec_supported(l),
link_get_dns_over_tls_mode(l),
link_get_llmnr_support(l),
link_get_mdns_support(l),
@@ -2255,6 +2259,7 @@ static int delegate_dns_configuration_json_append(DnsDelegate *d, sd_json_varian
/* negative_trust_anchors= */ NULL,
scopes,
/* dnssec_mode= */ _DNSSEC_MODE_INVALID,
/* dnssec_supported= */ false,
/* dns_over_tls_mode= */ _DNS_OVER_TLS_MODE_INVALID,
/* llmnr_support= */ _RESOLVE_SUPPORT_INVALID,
/* mdns_support= */ _RESOLVE_SUPPORT_INVALID,
@@ -9,8 +9,10 @@
#include "in-addr-util.h"
#include "iovec-util.h"
#include "json-util.h"
#include "ordered-set.h"
#include "set.h"
#include "string-util.h"
#include "strv.h"
DNSServer* dns_server_free(DNSServer *s) {
if (!s)
@@ -57,6 +59,7 @@ static int dispatch_dns_server(const char *name, sd_json_variant *variant, sd_js
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL),
"Dispatched address size (%zu) is incompatible with the family (%s).",
s->addr.iov_len, af_to_ipv4_ipv6(s->family));
memcpy_safe(&s->in_addr, s->addr.iov_base, s->addr.iov_len);
*ret = TAKE_PTR(s);
@@ -64,8 +67,8 @@ static int dispatch_dns_server(const char *name, sd_json_variant *variant, sd_js
}
static int dispatch_dns_server_array(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
Set **ret = ASSERT_PTR(userdata);
_cleanup_set_free_ Set *dns_servers = NULL;
OrderedSet **ret = ASSERT_PTR(userdata);
_cleanup_ordered_set_free_ OrderedSet *dns_servers = NULL;
sd_json_variant *v;
int r;
@@ -76,12 +79,13 @@ static int dispatch_dns_server_array(const char *name, sd_json_variant *variant,
if (r < 0)
return json_log(v, flags, r, "JSON array element is not a valid DNSServer.");
r = set_ensure_consume(&dns_servers, &dns_server_hash_ops, TAKE_PTR(s));
r = ordered_set_ensure_put(&dns_servers, &dns_server_hash_ops, s);
if (r < 0)
return r;
TAKE_PTR(s);
}
set_free_and_replace(*ret, dns_servers);
free_and_replace_full(*ret, dns_servers, ordered_set_free);
return 0;
}
@@ -128,8 +132,8 @@ static int dispatch_search_domain(const char *name, sd_json_variant *variant, sd
}
static int dispatch_search_domain_array(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
Set **ret = ASSERT_PTR(userdata);
_cleanup_set_free_ Set *search_domains = NULL;
OrderedSet **ret = ASSERT_PTR(userdata);
_cleanup_ordered_set_free_ OrderedSet *search_domains = NULL;
sd_json_variant *v;
int r;
@@ -140,12 +144,82 @@ static int dispatch_search_domain_array(const char *name, sd_json_variant *varia
if (r < 0)
return json_log(v, flags, r, "JSON array element is not a valid SearchDomain.");
r = set_ensure_consume(&search_domains, &search_domain_hash_ops, TAKE_PTR(d));
r = ordered_set_ensure_put(&search_domains, &search_domain_hash_ops, d);
if (r < 0)
return r;
TAKE_PTR(d);
}
free_and_replace_full(*ret, search_domains, ordered_set_free);
return 0;
}
DNSScope* dns_scope_free(DNSScope *s) {
if (!s)
return NULL;
free(s->ifname);
free(s->protocol);
free(s->dnssec_mode_str);
free(s->dns_over_tls_mode_str);
return mfree(s);
}
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
dns_scope_hash_ops,
void,
trivial_hash_func,
trivial_compare_func,
DNSScope,
dns_scope_free);
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 },
{},
};
DNSScope **ret = ASSERT_PTR(userdata);
int r;
_cleanup_(dns_scope_freep) DNSScope *s = new0(DNSScope, 1);
if (!s)
return log_oom();
r = sd_json_dispatch(variant, dns_scope_dispatch_table, flags, s);
if (r < 0)
return r;
*ret = TAKE_PTR(s);
return 0;
}
static int dispatch_dns_scope_array(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
Set **ret = ASSERT_PTR(userdata);
_cleanup_set_free_ Set *dns_scopes = NULL;
sd_json_variant *v;
int r;
JSON_VARIANT_ARRAY_FOREACH(v, variant) {
_cleanup_(dns_scope_freep) DNSScope *s = NULL;
r = dispatch_dns_scope(name, v, flags, &s);
if (r < 0)
return json_log(v, flags, r, "JSON array element is not a valid DNSScope.");
r = set_ensure_consume(&dns_scopes, &dns_scope_hash_ops, TAKE_PTR(s));
if (r < 0)
return r;
}
set_free_and_replace(*ret, search_domains);
set_free_and_replace(*ret, dns_scopes);
return 0;
}
@@ -155,9 +229,18 @@ DNSConfiguration* dns_configuration_free(DNSConfiguration *c) {
return NULL;
dns_server_free(c->current_dns_server);
set_free(c->dns_servers);
set_free(c->search_domains);
ordered_set_free(c->dns_servers);
ordered_set_free(c->search_domains);
ordered_set_free(c->fallback_dns_servers);
set_free(c->dns_scopes);
free(c->ifname);
free(c->dnssec_mode_str);
free(c->dns_over_tls_mode_str);
free(c->llmnr_mode_str);
free(c->mdns_mode_str);
free(c->resolv_conf_mode_str);
free(c->delegate);
strv_free(c->negative_trust_anchors);
return mfree(c);
}
@@ -172,23 +255,22 @@ DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
static int dispatch_dns_configuration(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
static const sd_json_dispatch_field dns_configuration_dispatch_table[] = {
{ "ifname", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(DNSConfiguration, ifname), 0 },
{ "ifindex", SD_JSON_VARIANT_UNSIGNED, json_dispatch_ifindex, offsetof(DNSConfiguration, ifindex), SD_JSON_RELAX },
{ "defaultRoute", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(DNSConfiguration, default_route), 0 },
{ "currentServer", SD_JSON_VARIANT_OBJECT, dispatch_dns_server, offsetof(DNSConfiguration, current_dns_server), 0 },
{ "servers", SD_JSON_VARIANT_ARRAY, dispatch_dns_server_array, offsetof(DNSConfiguration, dns_servers), 0 },
{ "searchDomains", SD_JSON_VARIANT_ARRAY, dispatch_search_domain_array, offsetof(DNSConfiguration, search_domains), 0 },
/* The remaining fields are currently unused by wait-online. */
{ "delegate", _SD_JSON_VARIANT_TYPE_INVALID, NULL, 0, 0 },
{ "fallbackServers", _SD_JSON_VARIANT_TYPE_INVALID, NULL, 0, 0 },
{ "negativeTrustAnchors", _SD_JSON_VARIANT_TYPE_INVALID, NULL, 0, 0 },
{ "dnssec", _SD_JSON_VARIANT_TYPE_INVALID, NULL, 0, 0 },
{ "dnsOverTLS", _SD_JSON_VARIANT_TYPE_INVALID, NULL, 0, 0 },
{ "llmnr", _SD_JSON_VARIANT_TYPE_INVALID, NULL, 0, 0 },
{ "mDNS", _SD_JSON_VARIANT_TYPE_INVALID, NULL, 0, 0 },
{ "resolvConfMode", _SD_JSON_VARIANT_TYPE_INVALID, NULL, 0, 0 },
{ "scopes", _SD_JSON_VARIANT_TYPE_INVALID, NULL, 0, 0 },
{ "ifname", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(DNSConfiguration, ifname), 0 },
{ "ifindex", SD_JSON_VARIANT_UNSIGNED, json_dispatch_ifindex, offsetof(DNSConfiguration, ifindex), SD_JSON_RELAX },
{ "defaultRoute", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(DNSConfiguration, default_route), 0 },
{ "currentServer", SD_JSON_VARIANT_OBJECT, dispatch_dns_server, offsetof(DNSConfiguration, current_dns_server), 0 },
{ "servers", SD_JSON_VARIANT_ARRAY, dispatch_dns_server_array, offsetof(DNSConfiguration, dns_servers), 0 },
{ "searchDomains", SD_JSON_VARIANT_ARRAY, dispatch_search_domain_array, offsetof(DNSConfiguration, search_domains), 0 },
{ "dnssecSupported", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(DNSConfiguration, dnssec_supported), 0 },
{ "dnssec", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(DNSConfiguration, dnssec_mode_str), 0 },
{ "dnsOverTLS", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(DNSConfiguration, dns_over_tls_mode_str), 0 },
{ "llmnr", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(DNSConfiguration, llmnr_mode_str), 0 },
{ "mDNS", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(DNSConfiguration, mdns_mode_str), 0 },
{ "fallbackServers", SD_JSON_VARIANT_ARRAY, dispatch_dns_server_array, offsetof(DNSConfiguration, fallback_dns_servers), 0 },
{ "negativeTrustAnchors", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_strv, offsetof(DNSConfiguration, negative_trust_anchors), 0 },
{ "resolvConfMode", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(DNSConfiguration, resolv_conf_mode_str), 0 },
{ "scopes", SD_JSON_VARIANT_ARRAY, dispatch_dns_scope_array, offsetof(DNSConfiguration, dns_scopes), 0 },
{ "delegate", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(DNSConfiguration, delegate), 0 },
{},
};
@@ -204,6 +286,8 @@ static int dispatch_dns_configuration(const char *name, sd_json_variant *variant
if (r < 0)
return r;
strv_sort(c->negative_trust_anchors);
*ret = TAKE_PTR(c);
return 0;
@@ -222,7 +306,7 @@ bool dns_is_accessible(DNSConfiguration *c) {
if (c->current_dns_server && c->current_dns_server->accessible)
return true;
SET_FOREACH(s, c->dns_servers)
ORDERED_SET_FOREACH(s, c->dns_servers)
if (s->accessible)
return true;
@@ -237,7 +321,7 @@ bool dns_configuration_contains_search_domain(DNSConfiguration *c, const char *d
if (!c)
return false;
SET_FOREACH(d, c->search_domains)
ORDERED_SET_FOREACH(d, c->search_domains)
if (streq(d->name, domain))
return true;
@@ -3,6 +3,7 @@
#include <sys/uio.h>
#include "in-addr-util.h"
#include "shared-forward.h"
typedef struct DNSServer {
@@ -12,6 +13,7 @@ typedef struct DNSServer {
int ifindex;
char *server_name;
bool accessible;
union in_addr_union in_addr;
} DNSServer;
DNSServer* dns_server_free(DNSServer *s);
@@ -23,6 +25,18 @@ typedef struct SearchDomain {
int ifindex;
} SearchDomain;
typedef struct DNSScope {
char *ifname;
int ifindex;
char *protocol;
int family;
char *dnssec_mode_str;
char *dns_over_tls_mode_str;
} DNSScope;
DNSScope* dns_scope_free(DNSScope *s);
DEFINE_TRIVIAL_CLEANUP_FUNC(DNSScope*, dns_scope_free);
SearchDomain* search_domain_free(SearchDomain *d);
DEFINE_TRIVIAL_CLEANUP_FUNC(SearchDomain*, search_domain_free);
@@ -31,8 +45,18 @@ typedef struct DNSConfiguration {
int ifindex;
bool default_route;
DNSServer *current_dns_server;
Set *dns_servers;
Set *search_domains;
OrderedSet *dns_servers;
OrderedSet *search_domains;
OrderedSet *fallback_dns_servers;
Set *dns_scopes;
char *dnssec_mode_str;
char *dns_over_tls_mode_str;
char *llmnr_mode_str;
char *mdns_mode_str;
char **negative_trust_anchors;
char *resolv_conf_mode_str;
char *delegate;
bool dnssec_supported;
} DNSConfiguration;
DNSConfiguration* dns_configuration_free(DNSConfiguration *c);
+1
View File
@@ -61,6 +61,7 @@ shared_sources = files(
'dissect-image.c',
'dm-util.c',
'dns-answer.c',
'dns-configuration.c',
'dns-domain.c',
'dns-packet.c',
'dns-question.c',
+2
View File
@@ -274,6 +274,8 @@ SD_VARLINK_DEFINE_STRUCT_TYPE(
SD_VARLINK_DEFINE_FIELD(negativeTrustAnchors, SD_VARLINK_STRING, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("DNSSEC mode."),
SD_VARLINK_DEFINE_FIELD(dnssec, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Indicates if the current DNS server supports DNSSEC. Always false if DNSSEC mode is \"no\"."),
SD_VARLINK_DEFINE_FIELD(dnssecSupported, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("DNSOverTLS mode."),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(dnsOverTLS, DNSOverTLSMode, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("LLMNR support."),