From 9b2f263f30ea0eb3706f87ed2027ef5d5cc6313f Mon Sep 17 00:00:00 2001 From: Nick Rosbrook Date: Fri, 30 Jan 2026 14:34:03 -0500 Subject: [PATCH 01/16] resolve: add DNSConfiguration field to indicate DNSSEC support The varlink API is currently missing the "DNSSEC supported" field, which is required for to re-implement the existing resolvectl status output with varlink instead of dbus. Add this field to DNSConfiguration. --- src/resolve/resolved-manager.c | 5 +++++ src/shared/varlink-io.systemd.Resolve.c | 2 ++ 2 files changed, 7 insertions(+) diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index 95e635d852..cc63152e0b 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -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, diff --git a/src/shared/varlink-io.systemd.Resolve.c b/src/shared/varlink-io.systemd.Resolve.c index 3f20c9f6cc..c84453851b 100644 --- a/src/shared/varlink-io.systemd.Resolve.c +++ b/src/shared/varlink-io.systemd.Resolve.c @@ -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."), From 271f7630a2af59bc52fbd50568f4761f5acb3e74 Mon Sep 17 00:00:00 2001 From: Nick Rosbrook Date: Fri, 30 Jan 2026 14:34:09 -0500 Subject: [PATCH 02/16] shared: move wait-online's dns-configuration.[ch] to shared --- src/network/meson.build | 1 - src/{network/wait-online => shared}/dns-configuration.c | 0 src/{network/wait-online => shared}/dns-configuration.h | 0 src/shared/meson.build | 1 + 4 files changed, 1 insertion(+), 1 deletion(-) rename src/{network/wait-online => shared}/dns-configuration.c (100%) rename src/{network/wait-online => shared}/dns-configuration.h (100%) diff --git a/src/network/meson.build b/src/network/meson.build index 353294c1a3..d872510b24 100644 --- a/src/network/meson.build +++ b/src/network/meson.build @@ -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', diff --git a/src/network/wait-online/dns-configuration.c b/src/shared/dns-configuration.c similarity index 100% rename from src/network/wait-online/dns-configuration.c rename to src/shared/dns-configuration.c diff --git a/src/network/wait-online/dns-configuration.h b/src/shared/dns-configuration.h similarity index 100% rename from src/network/wait-online/dns-configuration.h rename to src/shared/dns-configuration.h diff --git a/src/shared/meson.build b/src/shared/meson.build index 9fa976925a..e692334544 100644 --- a/src/shared/meson.build +++ b/src/shared/meson.build @@ -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', From fb0bd15d15f51563f6bc0d6a01b0020019bcc58e Mon Sep 17 00:00:00 2001 From: Nick Rosbrook Date: Fri, 30 Jan 2026 14:34:15 -0500 Subject: [PATCH 03/16] dns-configuration: dispatch all protocol modes to DNSConfiguration This is one of several commits to dispatch all fields of the DNSConfiguration JSON. --- src/shared/dns-configuration.c | 24 ++++++++++++++---------- src/shared/dns-configuration.h | 4 ++++ 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/shared/dns-configuration.c b/src/shared/dns-configuration.c index 9efd2d8f7b..03c4f3e2f1 100644 --- a/src/shared/dns-configuration.c +++ b/src/shared/dns-configuration.c @@ -158,6 +158,10 @@ DNSConfiguration* dns_configuration_free(DNSConfiguration *c) { set_free(c->dns_servers); set_free(c->search_domains); 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); return mfree(c); } @@ -172,21 +176,21 @@ 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 }, + { "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 }, + { "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 }, /* 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 }, {}, diff --git a/src/shared/dns-configuration.h b/src/shared/dns-configuration.h index e865defaab..9e2addd0a0 100644 --- a/src/shared/dns-configuration.h +++ b/src/shared/dns-configuration.h @@ -33,6 +33,10 @@ typedef struct DNSConfiguration { DNSServer *current_dns_server; Set *dns_servers; Set *search_domains; + char *dnssec_mode_str; + char *dns_over_tls_mode_str; + char *llmnr_mode_str; + char *mdns_mode_str; } DNSConfiguration; DNSConfiguration* dns_configuration_free(DNSConfiguration *c); From d3b60567d7b56050cb97aa784e6a6093840eff5d Mon Sep 17 00:00:00 2001 From: Nick Rosbrook Date: Fri, 30 Jan 2026 14:34:16 -0500 Subject: [PATCH 04/16] dns-configuration: dispatch fallback servers to DNSConfiguration This is one of several commits to dispatch all fields of the DNSConfiguration JSON. --- src/shared/dns-configuration.c | 3 ++- src/shared/dns-configuration.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/shared/dns-configuration.c b/src/shared/dns-configuration.c index 03c4f3e2f1..e79ecdd24f 100644 --- a/src/shared/dns-configuration.c +++ b/src/shared/dns-configuration.c @@ -157,6 +157,7 @@ DNSConfiguration* dns_configuration_free(DNSConfiguration *c) { dns_server_free(c->current_dns_server); set_free(c->dns_servers); set_free(c->search_domains); + set_free(c->fallback_dns_servers); free(c->ifname); free(c->dnssec_mode_str); free(c->dns_over_tls_mode_str); @@ -186,10 +187,10 @@ static int dispatch_dns_configuration(const char *name, sd_json_variant *variant { "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 }, /* 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 }, { "resolvConfMode", _SD_JSON_VARIANT_TYPE_INVALID, NULL, 0, 0 }, { "scopes", _SD_JSON_VARIANT_TYPE_INVALID, NULL, 0, 0 }, diff --git a/src/shared/dns-configuration.h b/src/shared/dns-configuration.h index 9e2addd0a0..8372fa86aa 100644 --- a/src/shared/dns-configuration.h +++ b/src/shared/dns-configuration.h @@ -33,6 +33,7 @@ typedef struct DNSConfiguration { DNSServer *current_dns_server; Set *dns_servers; Set *search_domains; + Set *fallback_dns_servers; char *dnssec_mode_str; char *dns_over_tls_mode_str; char *llmnr_mode_str; From 4a8f4efd44ffd39042685bc03e5e9da72cf7f420 Mon Sep 17 00:00:00 2001 From: Nick Rosbrook Date: Fri, 30 Jan 2026 14:34:19 -0500 Subject: [PATCH 05/16] dns-configuration: dispatch negative trust anchors to DNSConfiguration This is one of several commits to dispatch all fields of the DNSConfiguration JSON. --- src/shared/dns-configuration.c | 28 ++++++++++++++++------------ src/shared/dns-configuration.h | 1 + 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/shared/dns-configuration.c b/src/shared/dns-configuration.c index e79ecdd24f..2fa9d10f88 100644 --- a/src/shared/dns-configuration.c +++ b/src/shared/dns-configuration.c @@ -11,6 +11,7 @@ #include "json-util.h" #include "set.h" #include "string-util.h" +#include "strv.h" DNSServer* dns_server_free(DNSServer *s) { if (!s) @@ -163,6 +164,7 @@ DNSConfiguration* dns_configuration_free(DNSConfiguration *c) { free(c->dns_over_tls_mode_str); free(c->llmnr_mode_str); free(c->mdns_mode_str); + strv_free(c->negative_trust_anchors); return mfree(c); } @@ -177,21 +179,21 @@ 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 }, - { "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 }, + { "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 }, + { "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 }, /* The remaining fields are currently unused by wait-online. */ { "delegate", _SD_JSON_VARIANT_TYPE_INVALID, NULL, 0, 0 }, - { "negativeTrustAnchors", _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 }, {}, @@ -209,6 +211,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; diff --git a/src/shared/dns-configuration.h b/src/shared/dns-configuration.h index 8372fa86aa..0b337c58b2 100644 --- a/src/shared/dns-configuration.h +++ b/src/shared/dns-configuration.h @@ -38,6 +38,7 @@ typedef struct DNSConfiguration { char *dns_over_tls_mode_str; char *llmnr_mode_str; char *mdns_mode_str; + char **negative_trust_anchors; } DNSConfiguration; DNSConfiguration* dns_configuration_free(DNSConfiguration *c); From e90180f50c6817f79d1cfb7a8e0aefccd7fbb72e Mon Sep 17 00:00:00 2001 From: Nick Rosbrook Date: Fri, 30 Jan 2026 14:34:22 -0500 Subject: [PATCH 06/16] dns-configuration: dispatch resolv conf mode to DNSConfiguration This is one of several commits to dispatch all fields of the DNSConfiguration JSON. --- src/shared/dns-configuration.c | 3 ++- src/shared/dns-configuration.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/shared/dns-configuration.c b/src/shared/dns-configuration.c index 2fa9d10f88..16301d585f 100644 --- a/src/shared/dns-configuration.c +++ b/src/shared/dns-configuration.c @@ -164,6 +164,7 @@ DNSConfiguration* dns_configuration_free(DNSConfiguration *c) { free(c->dns_over_tls_mode_str); free(c->llmnr_mode_str); free(c->mdns_mode_str); + free(c->resolv_conf_mode_str); strv_free(c->negative_trust_anchors); return mfree(c); @@ -191,10 +192,10 @@ static int dispatch_dns_configuration(const char *name, sd_json_variant *variant { "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 }, /* The remaining fields are currently unused by wait-online. */ { "delegate", _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 }, {}, diff --git a/src/shared/dns-configuration.h b/src/shared/dns-configuration.h index 0b337c58b2..53192ad596 100644 --- a/src/shared/dns-configuration.h +++ b/src/shared/dns-configuration.h @@ -39,6 +39,7 @@ typedef struct DNSConfiguration { char *llmnr_mode_str; char *mdns_mode_str; char **negative_trust_anchors; + char *resolv_conf_mode_str; } DNSConfiguration; DNSConfiguration* dns_configuration_free(DNSConfiguration *c); From 3afb9c20b644ff11ea0493cd41817460583c7988 Mon Sep 17 00:00:00 2001 From: Nick Rosbrook Date: Fri, 30 Jan 2026 14:34:23 -0500 Subject: [PATCH 07/16] dns-configuration: dispatch scopes to DNSConfiguration This is one of several commits to dispatch all fields of the DNSConfiguration JSON. Introduce a DNSScope type, and all required JSON dispatching helpers. --- src/shared/dns-configuration.c | 72 +++++++++++++++++++++++++++++++++- src/shared/dns-configuration.h | 13 ++++++ 2 files changed, 84 insertions(+), 1 deletion(-) diff --git a/src/shared/dns-configuration.c b/src/shared/dns-configuration.c index 16301d585f..b188849d96 100644 --- a/src/shared/dns-configuration.c +++ b/src/shared/dns-configuration.c @@ -151,6 +151,75 @@ static int dispatch_search_domain_array(const char *name, sd_json_variant *varia 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, dns_scopes); + + return 0; +} + DNSConfiguration* dns_configuration_free(DNSConfiguration *c) { if (!c) return NULL; @@ -159,6 +228,7 @@ DNSConfiguration* dns_configuration_free(DNSConfiguration *c) { set_free(c->dns_servers); set_free(c->search_domains); 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); @@ -193,10 +263,10 @@ static int dispatch_dns_configuration(const char *name, sd_json_variant *variant { "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 }, /* The remaining fields are currently unused by wait-online. */ { "delegate", _SD_JSON_VARIANT_TYPE_INVALID, NULL, 0, 0 }, - { "scopes", _SD_JSON_VARIANT_TYPE_INVALID, NULL, 0, 0 }, {}, }; diff --git a/src/shared/dns-configuration.h b/src/shared/dns-configuration.h index 53192ad596..79cf8ecc80 100644 --- a/src/shared/dns-configuration.h +++ b/src/shared/dns-configuration.h @@ -23,6 +23,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); @@ -34,6 +46,7 @@ typedef struct DNSConfiguration { Set *dns_servers; Set *search_domains; Set *fallback_dns_servers; + Set *dns_scopes; char *dnssec_mode_str; char *dns_over_tls_mode_str; char *llmnr_mode_str; From 8731d33b58c06c81537d36facdee274360165b04 Mon Sep 17 00:00:00 2001 From: Nick Rosbrook Date: Fri, 30 Jan 2026 14:34:27 -0500 Subject: [PATCH 08/16] dns-configuration: dispatch delegate name to DNSConfiguration This is one of several commits to dispatch all fields of the DNSConfiguration JSON. --- src/shared/dns-configuration.c | 33 ++++++++++++++++----------------- src/shared/dns-configuration.h | 1 + 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/shared/dns-configuration.c b/src/shared/dns-configuration.c index b188849d96..2e0ee8f014 100644 --- a/src/shared/dns-configuration.c +++ b/src/shared/dns-configuration.c @@ -235,6 +235,7 @@ DNSConfiguration* dns_configuration_free(DNSConfiguration *c) { 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); @@ -250,23 +251,21 @@ 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 }, - { "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 }, - - /* The remaining fields are currently unused by wait-online. */ - { "delegate", _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 }, + { "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 }, {}, }; diff --git a/src/shared/dns-configuration.h b/src/shared/dns-configuration.h index 79cf8ecc80..93123f4467 100644 --- a/src/shared/dns-configuration.h +++ b/src/shared/dns-configuration.h @@ -53,6 +53,7 @@ typedef struct DNSConfiguration { char *mdns_mode_str; char **negative_trust_anchors; char *resolv_conf_mode_str; + char *delegate; } DNSConfiguration; DNSConfiguration* dns_configuration_free(DNSConfiguration *c); From d9757721ab16f05a8e2c5114ca2bbd076bf1b252 Mon Sep 17 00:00:00 2001 From: Nick Rosbrook Date: Fri, 30 Jan 2026 14:34:28 -0500 Subject: [PATCH 09/16] dns-configuration: add in_addr_union field to DNSServer type This makes it easier to use DNSServer with helpers from in-addr-util.h. --- src/shared/dns-configuration.c | 1 + src/shared/dns-configuration.h | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/shared/dns-configuration.c b/src/shared/dns-configuration.c index 2e0ee8f014..e148c2f8fd 100644 --- a/src/shared/dns-configuration.c +++ b/src/shared/dns-configuration.c @@ -58,6 +58,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); diff --git a/src/shared/dns-configuration.h b/src/shared/dns-configuration.h index 93123f4467..af6e061780 100644 --- a/src/shared/dns-configuration.h +++ b/src/shared/dns-configuration.h @@ -3,6 +3,7 @@ #include +#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); From 8894f29a4ed2a5205c64c2c99857c19aae96c7cc Mon Sep 17 00:00:00 2001 From: Nick Rosbrook Date: Fri, 30 Jan 2026 14:34:33 -0500 Subject: [PATCH 10/16] dns-configuration: add DNSSEC support boolean to DNSConfiguration This is one of several commits to dispatch all fields of the DNSConfiguration JSON. --- src/shared/dns-configuration.c | 1 + src/shared/dns-configuration.h | 1 + 2 files changed, 2 insertions(+) diff --git a/src/shared/dns-configuration.c b/src/shared/dns-configuration.c index e148c2f8fd..1003f497fa 100644 --- a/src/shared/dns-configuration.c +++ b/src/shared/dns-configuration.c @@ -258,6 +258,7 @@ static int dispatch_dns_configuration(const char *name, sd_json_variant *variant { "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 }, diff --git a/src/shared/dns-configuration.h b/src/shared/dns-configuration.h index af6e061780..e195570b62 100644 --- a/src/shared/dns-configuration.h +++ b/src/shared/dns-configuration.h @@ -56,6 +56,7 @@ typedef struct DNSConfiguration { char **negative_trust_anchors; char *resolv_conf_mode_str; char *delegate; + bool dnssec_supported; } DNSConfiguration; DNSConfiguration* dns_configuration_free(DNSConfiguration *c); From 7bfc82bf5aaacf6b19ecaf3e39aab53ee1c4a75a Mon Sep 17 00:00:00 2001 From: Nick Rosbrook Date: Fri, 30 Jan 2026 14:34:34 -0500 Subject: [PATCH 11/16] dns-configuration: use OrderedSet for servers and domains This only has a small effect, which mostly matters for generating status output. It ensures that the order of servers and domains displayed matches the order they are stored on the daemon side, which keeps the new resolvectl output consistent with the old. --- src/shared/dns-configuration.c | 29 ++++++++++++++++------------- src/shared/dns-configuration.h | 6 +++--- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/shared/dns-configuration.c b/src/shared/dns-configuration.c index 1003f497fa..1194e87258 100644 --- a/src/shared/dns-configuration.c +++ b/src/shared/dns-configuration.c @@ -9,6 +9,7 @@ #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" @@ -66,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; @@ -78,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; } @@ -130,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; @@ -142,12 +144,13 @@ 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); } - set_free_and_replace(*ret, search_domains); + free_and_replace_full(*ret, search_domains, ordered_set_free); return 0; } @@ -226,9 +229,9 @@ 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); - set_free(c->fallback_dns_servers); + 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); @@ -303,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; @@ -318,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; diff --git a/src/shared/dns-configuration.h b/src/shared/dns-configuration.h index e195570b62..40f0a4ad16 100644 --- a/src/shared/dns-configuration.h +++ b/src/shared/dns-configuration.h @@ -45,9 +45,9 @@ typedef struct DNSConfiguration { int ifindex; bool default_route; DNSServer *current_dns_server; - Set *dns_servers; - Set *search_domains; - Set *fallback_dns_servers; + OrderedSet *dns_servers; + OrderedSet *search_domains; + OrderedSet *fallback_dns_servers; Set *dns_scopes; char *dnssec_mode_str; char *dns_over_tls_mode_str; From a56366182ee353f8d777d0384a37580a309ed4b6 Mon Sep 17 00:00:00 2001 From: Nick Rosbrook Date: Fri, 30 Jan 2026 14:34:38 -0500 Subject: [PATCH 12/16] resolvectl: use varlink to report global status This is an incremental commit to replacing dbus usage with varlink for all status output. Re-implement regular global status output using the DumpDNSConfiguration varlink method. And, remove the GlobalInfo type and associated functions which were used to map dbus properties. --- src/resolve/resolvectl.c | 377 +++++++++++++++++++++------------------ 1 file changed, 208 insertions(+), 169 deletions(-) diff --git a/src/resolve/resolvectl.c b/src/resolve/resolvectl.c index d6609fe2ed..d9f93b5cbc 100644 --- a/src/resolve/resolvectl.c +++ b/src/resolve/resolvectl.c @@ -21,6 +21,7 @@ #include "bus-map-properties.h" #include "bus-message-util.h" #include "bus-util.h" +#include "dns-configuration.h" #include "dns-domain.h" #include "dns-packet.h" #include "dns-rr.h" @@ -35,6 +36,7 @@ #include "missing-network.h" #include "netlink-util.h" #include "openssl-util.h" +#include "ordered-set.h" #include "pager.h" #include "parse-argument.h" #include "parse-util.h" @@ -1699,23 +1701,6 @@ typedef struct LinkInfo { bool default_route; } LinkInfo; -typedef struct GlobalInfo { - char *current_dns; - char *current_dns_ex; - char **dns; - char **dns_ex; - char **fallback_dns; - char **fallback_dns_ex; - char **domains; - char **ntas; - const char *llmnr; - const char *mdns; - const char *dns_over_tls; - const char *dnssec; - const char *resolv_conf_mode; - bool dnssec_supported; -} GlobalInfo; - static void link_info_done(LinkInfo *p) { assert(p); @@ -1727,19 +1712,6 @@ static void link_info_done(LinkInfo *p) { strv_free(p->ntas); } -static void global_info_done(GlobalInfo *p) { - assert(p); - - free(p->current_dns); - free(p->current_dns_ex); - strv_free(p->dns); - strv_free(p->dns_ex); - strv_free(p->fallback_dns); - strv_free(p->fallback_dns_ex); - strv_free(p->domains); - strv_free(p->ntas); -} - static int dump_list(Table *table, const char *field, char * const *l) { int r; @@ -1790,26 +1762,6 @@ static char** link_protocol_status(const LinkInfo *info) { return TAKE_PTR(s); } -static char** global_protocol_status(const GlobalInfo *info) { - _cleanup_strv_free_ char **s = NULL; - - if (strv_extend_extended_bool(&s, "LLMNR", info->llmnr) < 0) - return NULL; - - if (strv_extend_extended_bool(&s, "mDNS", info->mdns) < 0) - return NULL; - - if (strv_extend_extended_bool(&s, "DNSOverTLS", info->dns_over_tls) < 0) - return NULL; - - if (strv_extendf(&s, "DNSSEC=%s/%s", - info->dnssec ?: "???", - info->dnssec_supported ? "supported" : "unsupported") < 0) - return NULL; - - return TAKE_PTR(s); -} - static int status_json_filter_fields(sd_json_variant **configuration, StatusMode mode) { _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL; sd_json_variant *w; @@ -1929,6 +1881,112 @@ static int status_json(StatusMode mode, char **links) { return sd_json_variant_dump(configuration, arg_json_format_flags, /* f= */ NULL, /* prefix= */ NULL); } +static int format_dns_server_one(DNSServer *s, bool with_ifindex, bool only_global, char **ret) { + int r; + + assert(s); + assert(ret); + + if (only_global && s->ifindex > 0 && s->ifindex != LOOPBACK_IFINDEX) { + /* This one has an (non-loopback) ifindex set, and we were told to suppress those. Hence do so. */ + *ret = NULL; + return 0; + } + + r = in_addr_port_ifindex_name_to_string( + s->family, + &s->in_addr, + s->port != 53 ? s->port : 0, + with_ifindex ? s->ifindex : 0, + s->server_name, + ret); + if (r < 0) + return r; + + return 1; +} + +static int format_dns_servers(OrderedSet *servers, bool with_ifindex, bool only_global, char ***ret) { + int r; + + assert(ret); + + _cleanup_strv_free_ char **l = NULL; + DNSServer *s; + ORDERED_SET_FOREACH(s, servers) { + _cleanup_free_ char *str = NULL; + r = format_dns_server_one(s, with_ifindex, only_global, &str); + if (r < 0) + return r; + if (r > 0) { + r = strv_consume(&l, TAKE_PTR(str)); + if (r < 0) + return log_oom(); + } + } + + *ret = TAKE_PTR(l); + return 0; +} + +static int format_search_domains(OrderedSet *domains, bool only_global, char ***ret) { + int r; + + assert(ret); + + _cleanup_strv_free_ char **l = NULL; + SearchDomain *d; + ORDERED_SET_FOREACH(d, domains) { + if (only_global && d->ifindex > 0) + /* Only show the global ones here */ + continue; + + _cleanup_free_ char *str = NULL; + if (d->route_only) + str = strjoin("~", d->name); + else + str = strdup(d->name); + if (!str) + return log_oom(); + + r = strv_consume(&l, TAKE_PTR(str)); + if (r < 0) + return log_oom(); + } + + *ret = TAKE_PTR(l); + return 0; +} + +static int format_protocol_status(DNSConfiguration *configuration, char ***ret) { + _cleanup_strv_free_ char **s = NULL; + int r; + + assert(configuration); + assert(ret); + + r = strv_extend_extended_bool(&s, "LLMNR", configuration->llmnr_mode_str); + if (r < 0) + return r; + + r = strv_extend_extended_bool(&s, "mDNS", configuration->mdns_mode_str); + if (r < 0) + return r; + + r = strv_extend_extended_bool(&s, "DNSOverTLS", configuration->dns_over_tls_mode_str); + if (r < 0) + return r; + + r = strv_extendf(&s, "DNSSEC=%s/%s", + configuration->dnssec_mode_str ?: "???", + configuration->dnssec_supported ? "supported" : "unsupported"); + if (r < 0) + return r; + + *ret = TAKE_PTR(s); + return 0; +} + static int status_ifindex(sd_bus *bus, int ifindex, const char *name, StatusMode mode, bool *empty_line) { static const struct bus_properties_map property_map[] = { { "ScopesMask", "t", NULL, offsetof(LinkInfo, scopes_mask) }, @@ -2120,141 +2178,66 @@ static int status_ifindex(sd_bus *bus, int ifindex, const char *name, StatusMode return 0; } -static int map_global_dns_servers_internal( - sd_bus *bus, - const char *member, - sd_bus_message *m, - sd_bus_error *error, - void *userdata, - ReadDNSFlag flags) { - - char ***l = ASSERT_PTR(userdata); - int r; - - assert(bus); - assert(member); - assert(m); - - r = sd_bus_message_enter_container(m, 'a', FLAGS_SET(flags, READ_DNS_EXTENDED) ? "(iiayqs)" : "(iiay)"); - if (r < 0) - return r; - - for (;;) { - _cleanup_free_ char *pretty = NULL; - - r = read_dns_server_one(m, flags, &pretty); - if (r < 0) - return r; - if (r == 0) - break; - - if (isempty(pretty)) - continue; - - r = strv_consume(l, TAKE_PTR(pretty)); - if (r < 0) - return r; - } - - r = sd_bus_message_exit_container(m); - if (r < 0) - return r; - - return 0; -} - -static int map_global_dns_servers(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) { - return map_global_dns_servers_internal(bus, member, m, error, userdata, READ_DNS_WITH_IFINDEX | READ_DNS_ONLY_GLOBAL); -} - -static int map_global_dns_servers_ex(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) { - return map_global_dns_servers_internal(bus, member, m, error, userdata, READ_DNS_WITH_IFINDEX | READ_DNS_ONLY_GLOBAL | READ_DNS_EXTENDED); -} - -static int map_global_current_dns_server(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) { - return read_dns_server_one(m, READ_DNS_WITH_IFINDEX | READ_DNS_ONLY_GLOBAL, userdata); -} - -static int map_global_current_dns_server_ex(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) { - return read_dns_server_one(m, READ_DNS_WITH_IFINDEX | READ_DNS_ONLY_GLOBAL | READ_DNS_EXTENDED, userdata); -} - -static int map_global_domains(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) { - return map_domains_internal(bus, member, m, /* with_ifindex= */ true, error, userdata); -} - -static int status_global(sd_bus *bus, StatusMode mode, bool *empty_line) { - static const struct bus_properties_map property_map[] = { - { "DNS", "a(iiay)", map_global_dns_servers, offsetof(GlobalInfo, dns) }, - { "DNSEx", "a(iiayqs)", map_global_dns_servers_ex, offsetof(GlobalInfo, dns_ex) }, - { "FallbackDNS", "a(iiay)", map_global_dns_servers, offsetof(GlobalInfo, fallback_dns) }, - { "FallbackDNSEx", "a(iiayqs)", map_global_dns_servers_ex, offsetof(GlobalInfo, fallback_dns_ex) }, - { "CurrentDNSServer", "(iiay)", map_global_current_dns_server, offsetof(GlobalInfo, current_dns) }, - { "CurrentDNSServerEx", "(iiayqs)", map_global_current_dns_server_ex, offsetof(GlobalInfo, current_dns_ex) }, - { "Domains", "a(isb)", map_global_domains, offsetof(GlobalInfo, domains) }, - { "DNSSECNegativeTrustAnchors", "as", bus_map_strv_sort, offsetof(GlobalInfo, ntas) }, - { "LLMNR", "s", NULL, offsetof(GlobalInfo, llmnr) }, - { "MulticastDNS", "s", NULL, offsetof(GlobalInfo, mdns) }, - { "DNSOverTLS", "s", NULL, offsetof(GlobalInfo, dns_over_tls) }, - { "DNSSEC", "s", NULL, offsetof(GlobalInfo, dnssec) }, - { "DNSSECSupported", "b", NULL, offsetof(GlobalInfo, dnssec_supported) }, - { "ResolvConfMode", "s", NULL, offsetof(GlobalInfo, resolv_conf_mode) }, - {} - }; - _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; - _cleanup_(global_info_done) GlobalInfo global_info = {}; +static int status_global(DNSConfiguration *configuration, StatusMode mode, bool *empty_line) { _cleanup_(table_unrefp) Table *table = NULL; int r; - assert(bus); + assert(configuration); + assert(configuration->ifindex == 0); + assert(!configuration->delegate); assert(empty_line); - r = bus_map_all_properties(bus, - "org.freedesktop.resolve1", - "/org/freedesktop/resolve1", - property_map, - BUS_MAP_BOOLEAN_AS_BOOL, - &error, - &m, - &global_info); - if (r < 0) - return log_error_errno(r, "Failed to get global data: %s", bus_error_message(&error, r)); - pager_open(arg_pager_flags); switch (mode) { - case STATUS_DNS: - return status_print_strv_global(global_info.dns_ex ?: global_info.dns); + case STATUS_DNS: { + _cleanup_strv_free_ char **dns_servers = NULL; + r = format_dns_servers(configuration->dns_servers, + /* with_ifindex= */ true, + /* only_global= */ true, + &dns_servers); + if (r < 0) + return r; - case STATUS_DOMAIN: - return status_print_strv_global(global_info.domains); + return status_print_strv_global(dns_servers); + } + + case STATUS_DOMAIN: { + _cleanup_strv_free_ char **search_domains = NULL; + r = format_search_domains(configuration->search_domains, + /* only_global= */ true, + &search_domains); + if (r < 0) + return r; + + return status_print_strv_global(search_domains); + } case STATUS_NTA: - return status_print_strv_global(global_info.ntas); + return status_print_strv_global(configuration->negative_trust_anchors); case STATUS_LLMNR: printf("%sGlobal%s: %s\n", ansi_highlight(), ansi_normal(), - strna(global_info.llmnr)); + strna(configuration->llmnr_mode_str)); return 0; case STATUS_MDNS: printf("%sGlobal%s: %s\n", ansi_highlight(), ansi_normal(), - strna(global_info.mdns)); + strna(configuration->mdns_mode_str)); return 0; case STATUS_DNS_OVER_TLS: printf("%sGlobal%s: %s\n", ansi_highlight(), ansi_normal(), - strna(global_info.dns_over_tls)); + strna(configuration->dns_over_tls_mode_str)); return 0; case STATUS_DNSSEC: printf("%sGlobal%s: %s\n", ansi_highlight(), ansi_normal(), - strna(global_info.dnssec)); + strna(configuration->dnssec_mode_str)); return 0; @@ -2271,9 +2254,10 @@ static int status_global(sd_bus *bus, StatusMode mode, bool *empty_line) { if (!table) return log_oom(); - _cleanup_strv_free_ char **pstatus = global_protocol_status(&global_info); - if (!pstatus) - return log_oom(); + _cleanup_strv_free_ char **pstatus = NULL; + r = format_protocol_status(configuration, &pstatus); + if (r < 0) + return r; r = table_add_many(table, TABLE_FIELD, "Protocols", @@ -2282,31 +2266,63 @@ static int status_global(sd_bus *bus, StatusMode mode, bool *empty_line) { if (r < 0) return table_log_add_error(r); - if (global_info.resolv_conf_mode) { + if (configuration->resolv_conf_mode_str) { r = table_add_many(table, TABLE_FIELD, "resolv.conf mode", - TABLE_STRING, global_info.resolv_conf_mode); + TABLE_STRING, configuration->resolv_conf_mode_str); if (r < 0) return table_log_add_error(r); } - if (global_info.current_dns) { - r = table_add_many(table, - TABLE_FIELD, "Current DNS Server", - TABLE_STRING, global_info.current_dns_ex ?: global_info.current_dns); + if (configuration->current_dns_server) { + _cleanup_free_ char *current_dns = NULL; + r = format_dns_server_one(configuration->current_dns_server, + /* with_ifindex= */ true, + /* only_global= */ true, + ¤t_dns); if (r < 0) - return table_log_add_error(r); + return r; + if (r > 0) { + r = table_add_many(table, + TABLE_FIELD, "Current DNS Server", + TABLE_STRING, current_dns); + if (r < 0) + return table_log_add_error(r); + } } - r = dump_list(table, "DNS Servers", global_info.dns_ex ?: global_info.dns); + _cleanup_strv_free_ char **dns_servers = NULL; + r = format_dns_servers(configuration->dns_servers, + /* with_ifindex= */ true, + /* only_global= */ true, + &dns_servers); if (r < 0) return r; - r = dump_list(table, "Fallback DNS Servers", global_info.fallback_dns_ex ?: global_info.fallback_dns); + r = dump_list(table, "DNS Servers", dns_servers); if (r < 0) return r; - r = dump_list(table, "DNS Domain", global_info.domains); + _cleanup_strv_free_ char **fallback_dns_servers = NULL; + r = format_dns_servers(configuration->fallback_dns_servers, + /* with_ifindex= */ true, + /* only_global= */ true, + &fallback_dns_servers); + if (r < 0) + return r; + + r = dump_list(table, "Fallback DNS Servers", fallback_dns_servers); + if (r < 0) + return r; + + _cleanup_strv_free_ char **search_domains = NULL; + r = format_search_domains(configuration->search_domains, + /* only_global= */ true, + &search_domains); + if (r < 0) + return r; + + r = dump_list(table, "DNS Domain", search_domains); if (r < 0) return r; @@ -2566,10 +2582,33 @@ static int status_all(sd_bus *bus, StatusMode mode) { if (sd_json_format_enabled(arg_json_format_flags)) return status_json(mode, /* links= */ NULL); - r = status_global(bus, mode, &empty_line); + _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL; + r = varlink_dump_dns_configuration(&v); if (r < 0) return r; + _cleanup_(dns_configuration_freep) DNSConfiguration *global_config = NULL; + sd_json_variant *w; + JSON_VARIANT_ARRAY_FOREACH(w, v) { + _cleanup_(dns_configuration_freep) DNSConfiguration *c = NULL; + r = dns_configuration_from_json(w, &c); + if (r < 0) + return r; + + if (c->ifindex > 0 || c->delegate) + continue; + else { + assert(!global_config); + global_config = TAKE_PTR(c); + } + } + + if (global_config) { + r = status_global(global_config, mode, &empty_line); + if (r < 0) + return r; + } + r = status_links(bus, mode, &empty_line); if (r < 0) return r; From d076d0f94f0ea32565f8be7bfcabdfdea2f25cf6 Mon Sep 17 00:00:00 2001 From: Nick Rosbrook Date: Fri, 30 Jan 2026 14:34:41 -0500 Subject: [PATCH 13/16] resolvectl: use varlink to report link status This is an incremental commit to replacing dbus usage with varlink for all status output. Re-implement regular link status output using the DumpDNSConfiguration varlink method. And, remove the LinkInfo type and associated functions which were used to map dbus properties. --- src/resolve/resolvectl.c | 436 ++++++++++++++++----------------------- 1 file changed, 183 insertions(+), 253 deletions(-) diff --git a/src/resolve/resolvectl.c b/src/resolve/resolvectl.c index d9f93b5cbc..0064b37809 100644 --- a/src/resolve/resolvectl.c +++ b/src/resolve/resolvectl.c @@ -49,8 +49,6 @@ #include "resolved-util.h" #include "set.h" #include "socket-netlink.h" -#include "sort-util.h" -#include "stdio-util.h" #include "string-table.h" #include "string-util.h" #include "strv.h" @@ -125,11 +123,6 @@ static const char* const status_mode_json_field_table[_STATUS_MAX] = { DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(status_mode_json_field, StatusMode); -typedef struct InterfaceInfo { - int index; - const char *name; -} InterfaceInfo; - static int acquire_bus(sd_bus **ret) { _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL; int r; @@ -146,16 +139,6 @@ static int acquire_bus(sd_bus **ret) { return 0; } -static int interface_info_compare(const InterfaceInfo *a, const InterfaceInfo *b) { - int r; - - r = CMP(a->index, b->index); - if (r != 0) - return r; - - return strcmp_ptr(a->name, b->name); -} - int ifname_mangle_full(const char *s, bool drop_protocol_specifier) { _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; _cleanup_strv_free_ char **found = NULL; @@ -1541,28 +1524,6 @@ static int map_dns_servers_internal(sd_bus *bus, const char *member, sd_bus_mess return 0; } -static int map_link_dns_servers(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) { - return map_dns_servers_internal(bus, member, m, /* flags= */ 0, error, userdata); -} - -static int map_link_dns_servers_ex(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) { - return map_dns_servers_internal(bus, member, m, READ_DNS_EXTENDED, error, userdata); -} - -static int map_link_current_dns_server(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) { - assert(m); - assert(userdata); - - return read_dns_server_one(m, /* flags= */ 0, userdata); -} - -static int map_link_current_dns_server_ex(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) { - assert(m); - assert(userdata); - - return read_dns_server_one(m, READ_DNS_EXTENDED, userdata); -} - static int read_domain_one(sd_bus_message *m, bool with_ifindex, char **ret) { _cleanup_free_ char *str = NULL; int ifindex, route_only, r; @@ -1638,10 +1599,6 @@ static int map_domains_internal( return 0; } -static int map_link_domains(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) { - return map_domains_internal(bus, member, m, /* with_ifindex= */ false, error, userdata); -} - static int status_print_strv_full(int ifindex, const char *ifname, const char *delegate_id, char **p) { const unsigned indent = strlen("Global: "); /* Use the same indentation everywhere to make things nice */ int pos1, pos2; @@ -1685,33 +1642,6 @@ static int status_print_strv_global(char **p) { return status_print_strv_full(0, NULL, NULL, p); } -typedef struct LinkInfo { - uint64_t scopes_mask; - const char *llmnr; - const char *mdns; - const char *dns_over_tls; - const char *dnssec; - char *current_dns; - char *current_dns_ex; - char **dns; - char **dns_ex; - char **domains; - char **ntas; - bool dnssec_supported; - bool default_route; -} LinkInfo; - -static void link_info_done(LinkInfo *p) { - assert(p); - - free(p->current_dns); - free(p->current_dns_ex); - strv_free(p->dns); - strv_free(p->dns_ex); - strv_free(p->domains); - strv_free(p->ntas); -} - static int dump_list(Table *table, const char *field, char * const *l) { int r; @@ -1739,29 +1669,6 @@ static int strv_extend_extended_bool(char ***strv, const char *name, const char return strv_extendf(strv, "%s=%s", name, value ?: "???"); } -static char** link_protocol_status(const LinkInfo *info) { - _cleanup_strv_free_ char **s = NULL; - - if (strv_extendf(&s, "%sDefaultRoute", plus_minus(info->default_route)) < 0) - return NULL; - - if (strv_extend_extended_bool(&s, "LLMNR", info->llmnr) < 0) - return NULL; - - if (strv_extend_extended_bool(&s, "mDNS", info->mdns) < 0) - return NULL; - - if (strv_extend_extended_bool(&s, "DNSOverTLS", info->dns_over_tls) < 0) - return NULL; - - if (strv_extendf(&s, "DNSSEC=%s/%s", - info->dnssec ?: "???", - info->dnssec_supported ? "supported" : "unsupported") < 0) - return NULL; - - return TAKE_PTR(s); -} - static int status_json_filter_fields(sd_json_variant **configuration, StatusMode mode) { _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL; sd_json_variant *w; @@ -1965,6 +1872,12 @@ static int format_protocol_status(DNSConfiguration *configuration, char ***ret) assert(configuration); assert(ret); + if (configuration->ifindex > 0) { + r = strv_extendf(&s, "%sDefaultRoute", plus_minus(configuration->default_route)); + if (r < 0) + return r; + } + r = strv_extend_extended_bool(&s, "LLMNR", configuration->llmnr_mode_str); if (r < 0) return r; @@ -1987,106 +1900,97 @@ static int format_protocol_status(DNSConfiguration *configuration, char ***ret) return 0; } -static int status_ifindex(sd_bus *bus, int ifindex, const char *name, StatusMode mode, bool *empty_line) { - static const struct bus_properties_map property_map[] = { - { "ScopesMask", "t", NULL, offsetof(LinkInfo, scopes_mask) }, - { "DNS", "a(iay)", map_link_dns_servers, offsetof(LinkInfo, dns) }, - { "DNSEx", "a(iayqs)", map_link_dns_servers_ex, offsetof(LinkInfo, dns_ex) }, - { "CurrentDNSServer", "(iay)", map_link_current_dns_server, offsetof(LinkInfo, current_dns) }, - { "CurrentDNSServerEx", "(iayqs)", map_link_current_dns_server_ex, offsetof(LinkInfo, current_dns_ex) }, - { "Domains", "a(sb)", map_link_domains, offsetof(LinkInfo, domains) }, - { "DefaultRoute", "b", NULL, offsetof(LinkInfo, default_route) }, - { "LLMNR", "s", NULL, offsetof(LinkInfo, llmnr) }, - { "MulticastDNS", "s", NULL, offsetof(LinkInfo, mdns) }, - { "DNSOverTLS", "s", NULL, offsetof(LinkInfo, dns_over_tls) }, - { "DNSSEC", "s", NULL, offsetof(LinkInfo, dnssec) }, - { "DNSSECNegativeTrustAnchors", "as", bus_map_strv_sort, offsetof(LinkInfo, ntas) }, - { "DNSSECSupported", "b", NULL, offsetof(LinkInfo, dnssec_supported) }, - {} - }; - _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; - _cleanup_(link_info_done) LinkInfo link_info = {}; +static int status_link(DNSConfiguration *configuration, StatusMode mode, bool *empty_line) { _cleanup_(table_unrefp) Table *table = NULL; _cleanup_free_ char *p = NULL; - char ifi[DECIMAL_STR_MAX(int)], ifname[IF_NAMESIZE]; int r; - assert(bus); - assert(ifindex > 0); - - if (!name) { - r = format_ifname(ifindex, ifname); - if (r < 0) - return log_error_errno(r, "Failed to resolve interface name for %i: %m", ifindex); - - name = ifname; - } - - if (sd_json_format_enabled(arg_json_format_flags)) - return status_json(mode, STRV_MAKE(name)); - - xsprintf(ifi, "%i", ifindex); - r = sd_bus_path_encode("/org/freedesktop/resolve1/link", ifi, &p); - if (r < 0) - return log_oom(); - - r = bus_map_all_properties(bus, - "org.freedesktop.resolve1", - p, - property_map, - BUS_MAP_BOOLEAN_AS_BOOL, - &error, - &m, - &link_info); - if (r < 0) - return log_error_errno(r, "Failed to get link data for %i: %s", ifindex, bus_error_message(&error, r)); + assert(configuration); + assert(configuration->ifindex > 0); pager_open(arg_pager_flags); switch (mode) { - case STATUS_DNS: - return status_print_strv_ifindex(ifindex, name, link_info.dns_ex ?: link_info.dns); + case STATUS_DNS: { + _cleanup_strv_free_ char **dns_servers = NULL; + r = format_dns_servers(configuration->dns_servers, + /* with_ifindex= */ false, + /* only_global= */ false, + &dns_servers); + if (r < 0) + return r; - case STATUS_DOMAIN: - return status_print_strv_ifindex(ifindex, name, link_info.domains); + return status_print_strv_ifindex(configuration->ifindex, + configuration->ifname, + dns_servers); + } + + case STATUS_DOMAIN: { + _cleanup_strv_free_ char **search_domains = NULL; + r = format_search_domains(configuration->search_domains, + /* only_global= */ false, + &search_domains); + if (r < 0) + return r; + + return status_print_strv_ifindex(configuration->ifindex, + configuration->ifname, + search_domains); + } case STATUS_NTA: - return status_print_strv_ifindex(ifindex, name, link_info.ntas); + return status_print_strv_ifindex(configuration->ifindex, + configuration->ifname, + configuration->negative_trust_anchors); case STATUS_DEFAULT_ROUTE: printf("%sLink %i (%s)%s: %s\n", - ansi_highlight(), ifindex, name, ansi_normal(), - yes_no(link_info.default_route)); + ansi_highlight(), + configuration->ifindex, + configuration->ifname, + ansi_normal(), + yes_no(configuration->default_route)); return 0; case STATUS_LLMNR: printf("%sLink %i (%s)%s: %s\n", - ansi_highlight(), ifindex, name, ansi_normal(), - strna(link_info.llmnr)); + ansi_highlight(), + configuration->ifindex, + configuration->ifname, + ansi_normal(), + strna(configuration->llmnr_mode_str)); return 0; case STATUS_MDNS: printf("%sLink %i (%s)%s: %s\n", - ansi_highlight(), ifindex, name, ansi_normal(), - strna(link_info.mdns)); + ansi_highlight(), + configuration->ifindex, + configuration->ifname, + ansi_normal(), + strna(configuration->mdns_mode_str)); return 0; case STATUS_DNS_OVER_TLS: printf("%sLink %i (%s)%s: %s\n", - ansi_highlight(), ifindex, name, ansi_normal(), - strna(link_info.dns_over_tls)); + ansi_highlight(), + configuration->ifindex, + configuration->ifname, + ansi_normal(), + strna(configuration->dns_over_tls_mode_str)); return 0; case STATUS_DNSSEC: printf("%sLink %i (%s)%s: %s\n", - ansi_highlight(), ifindex, name, ansi_normal(), - strna(link_info.dnssec)); + ansi_highlight(), + configuration->ifindex, + configuration->ifname, + ansi_normal(), + strna(configuration->dnssec_mode_str)); return 0; @@ -2101,7 +2005,10 @@ static int status_ifindex(sd_bus *bus, int ifindex, const char *name, StatusMode fputc('\n', stdout); printf("%sLink %i (%s)%s\n", - ansi_highlight(), ifindex, name, ansi_normal()); + ansi_highlight(), + configuration->ifindex, + configuration->ifname, + ansi_normal()); table = table_new_vertical(); if (!table) @@ -2113,18 +2020,31 @@ static int status_ifindex(sd_bus *bus, int ifindex, const char *name, StatusMode if (r < 0) return table_log_add_error(r); - if (link_info.scopes_mask == 0) + if (!configuration->dns_scopes) r = table_add_cell(table, NULL, TABLE_STRING, "none"); else { + uint64_t scopes_mask = 0; + DNSScope *scope; + SET_FOREACH(scope, configuration->dns_scopes) + if (streq(scope->protocol, "dns")) + scopes_mask |= SD_RESOLVED_DNS; + else if (streq(scope->protocol, "llmnr")) + scopes_mask |= scope->family == AF_INET ? + SD_RESOLVED_LLMNR_IPV4 : + SD_RESOLVED_LLMNR_IPV6; + else if (streq(scope->protocol, "mdns")) + scopes_mask |= scope->family == AF_INET ? + SD_RESOLVED_MDNS_IPV4 : + SD_RESOLVED_MDNS_IPV6; + _cleanup_free_ char *buf = NULL; size_t len; - if (asprintf(&buf, "%s%s%s%s%s", - link_info.scopes_mask & SD_RESOLVED_DNS ? "DNS " : "", - link_info.scopes_mask & SD_RESOLVED_LLMNR_IPV4 ? "LLMNR/IPv4 " : "", - link_info.scopes_mask & SD_RESOLVED_LLMNR_IPV6 ? "LLMNR/IPv6 " : "", - link_info.scopes_mask & SD_RESOLVED_MDNS_IPV4 ? "mDNS/IPv4 " : "", - link_info.scopes_mask & SD_RESOLVED_MDNS_IPV6 ? "mDNS/IPv6 " : "") < 0) + scopes_mask & SD_RESOLVED_DNS ? "DNS " : "", + scopes_mask & SD_RESOLVED_LLMNR_IPV4 ? "LLMNR/IPv4 " : "", + scopes_mask & SD_RESOLVED_LLMNR_IPV6 ? "LLMNR/IPv6 " : "", + scopes_mask & SD_RESOLVED_MDNS_IPV4 ? "mDNS/IPv4 " : "", + scopes_mask & SD_RESOLVED_MDNS_IPV6 ? "mDNS/IPv6 " : "") < 0) return log_oom(); len = strlen(buf); @@ -2136,9 +2056,10 @@ static int status_ifindex(sd_bus *bus, int ifindex, const char *name, StatusMode if (r < 0) return table_log_add_error(r); - _cleanup_strv_free_ char **pstatus = link_protocol_status(&link_info); - if (!pstatus) - return log_oom(); + _cleanup_strv_free_ char **pstatus = NULL; + r = format_protocol_status(configuration, &pstatus); + if (r < 0) + return r; r = table_add_many(table, TABLE_FIELD, "Protocols", @@ -2146,25 +2067,49 @@ static int status_ifindex(sd_bus *bus, int ifindex, const char *name, StatusMode if (r < 0) return table_log_add_error(r); - if (link_info.current_dns) { - r = table_add_many(table, - TABLE_FIELD, "Current DNS Server", - TABLE_STRING, link_info.current_dns_ex ?: link_info.current_dns); + if (configuration->current_dns_server) { + _cleanup_free_ char *current_dns = NULL; + r = format_dns_server_one(configuration->current_dns_server, + /* with_ifindex= */ false, + /* only_global= */ false, + ¤t_dns); if (r < 0) - return table_log_add_error(r); + return r; + if (r > 0) { + r = table_add_many(table, + TABLE_FIELD, "Current DNS Server", + TABLE_STRING, current_dns); + if (r < 0) + return table_log_add_error(r); + } } - r = dump_list(table, "DNS Servers", link_info.dns_ex ?: link_info.dns); + _cleanup_strv_free_ char **dns_servers = NULL; + r = format_dns_servers(configuration->dns_servers, + /* with_ifindex= */ false, + /* only_global= */ false, + &dns_servers); if (r < 0) return r; - r = dump_list(table, "DNS Domain", link_info.domains); + r = dump_list(table, "DNS Servers", dns_servers); + if (r < 0) + return r; + + _cleanup_strv_free_ char **search_domains = NULL; + r = format_search_domains(configuration->search_domains, + /* only_global= */ false, + &search_domains); + if (r < 0) + return r; + + r = dump_list(table, "DNS Domain", search_domains); if (r < 0) return r; r = table_add_many(table, TABLE_FIELD, "Default Route", - TABLE_BOOLEAN, link_info.default_route); + TABLE_BOOLEAN, configuration->default_route); if (r < 0) return table_log_add_error(r); @@ -2178,6 +2123,42 @@ static int status_ifindex(sd_bus *bus, int ifindex, const char *name, StatusMode return 0; } +static int status_ifindex(int ifindex, StatusMode mode, bool *empty_line) { + int r; + + assert(ifindex > 0); + + if (sd_json_format_enabled(arg_json_format_flags)) { + char ifname[IF_NAMESIZE]; + r = format_ifname(ifindex, ifname); + if (r < 0) + return log_error_errno(r, "Failed to resolve interface name for %i: %m", ifindex); + + return status_json(mode, STRV_MAKE(ifname)); + } + + _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL; + r = varlink_dump_dns_configuration(&v); + if (r < 0) + return r; + + sd_json_variant *w; + JSON_VARIANT_ARRAY_FOREACH(w, v) { + int found = sd_json_variant_unsigned(sd_json_variant_by_key(w, "ifindex")); + if (found != ifindex) + continue; + + _cleanup_(dns_configuration_freep) DNSConfiguration *c = NULL; + r = dns_configuration_from_json(w, &c); + if (r < 0) + return r; + + return status_link(c, mode, empty_line); + } + + return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "No DNS configuration for interface %d", ifindex); +} + static int status_global(DNSConfiguration *configuration, StatusMode mode, bool *empty_line) { _cleanup_(table_unrefp) Table *table = NULL; int r; @@ -2335,69 +2316,6 @@ static int status_global(DNSConfiguration *configuration, StatusMode mode, bool return 0; } -static int status_links(sd_bus *bus, StatusMode mode, bool *empty_line) { - _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; - _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; - int ret = 0, r; - - assert(bus); - - r = sd_netlink_open(&rtnl); - if (r < 0) - return log_error_errno(r, "Failed to connect to netlink: %m"); - - r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0); - if (r < 0) - return rtnl_log_create_error(r); - - r = sd_netlink_message_set_request_dump(req, true); - if (r < 0) - return rtnl_log_create_error(r); - - r = sd_netlink_call(rtnl, req, 0, &reply); - if (r < 0) - return log_error_errno(r, "Failed to enumerate links: %m"); - - _cleanup_free_ InterfaceInfo *infos = NULL; - size_t n_infos = 0; - - for (sd_netlink_message *i = reply; i; i = sd_netlink_message_next(i)) { - const char *name; - int ifindex; - uint16_t type; - - r = sd_netlink_message_get_type(i, &type); - if (r < 0) - return rtnl_log_parse_error(r); - - if (type != RTM_NEWLINK) - continue; - - r = sd_rtnl_message_link_get_ifindex(i, &ifindex); - if (r < 0) - return rtnl_log_parse_error(r); - - if (ifindex == LOOPBACK_IFINDEX) - continue; - - r = sd_netlink_message_read_string(i, IFLA_IFNAME, &name); - if (r < 0) - return rtnl_log_parse_error(r); - - if (!GREEDY_REALLOC(infos, n_infos + 1)) - return log_oom(); - - infos[n_infos++] = (InterfaceInfo) { ifindex, name }; - } - - typesafe_qsort(infos, n_infos, interface_info_compare); - - FOREACH_ARRAY(info, infos, n_infos) - RET_GATHER(ret, status_ifindex(bus, info->index, info->name, mode, empty_line)); - - return ret; -} - typedef struct DelegateInfo { char *current_dns; char **dns; @@ -2588,6 +2506,7 @@ static int status_all(sd_bus *bus, StatusMode mode) { return r; _cleanup_(dns_configuration_freep) DNSConfiguration *global_config = NULL; + _cleanup_ordered_set_free_ OrderedSet *link_configs = NULL; sd_json_variant *w; JSON_VARIANT_ARRAY_FOREACH(w, v) { _cleanup_(dns_configuration_freep) DNSConfiguration *c = NULL; @@ -2595,7 +2514,15 @@ static int status_all(sd_bus *bus, StatusMode mode) { if (r < 0) return r; - if (c->ifindex > 0 || c->delegate) + if (c->ifindex == LOOPBACK_IFINDEX) + continue; + + if (c->ifindex > 0) { + r = ordered_set_ensure_put(&link_configs, &dns_configuration_hash_ops, c); + if (r < 0) + return r; + TAKE_PTR(c); + } else if (c->delegate) continue; else { assert(!global_config); @@ -2609,9 +2536,12 @@ static int status_all(sd_bus *bus, StatusMode mode) { return r; } - r = status_links(bus, mode, &empty_line); - if (r < 0) - return r; + DNSConfiguration *c; + ORDERED_SET_FOREACH(c, link_configs) { + r = status_link(c, mode, &empty_line); + if (r < 0) + return r; + } r = status_delegates(bus, mode, &empty_line); if (r < 0) @@ -2645,7 +2575,7 @@ static int verb_status(int argc, char **argv, void *userdata) { continue; } - RET_GATHER(ret, status_ifindex(bus, ifindex, NULL, STATUS_ALL, &empty_line)); + RET_GATHER(ret, status_ifindex(ifindex, STATUS_ALL, &empty_line)); } return ret; @@ -2743,7 +2673,7 @@ static int verb_dns(int argc, char **argv, void *userdata) { return status_all(bus, STATUS_DNS); if (argc < 3) - return status_ifindex(bus, arg_ifindex, NULL, STATUS_DNS, NULL); + return status_ifindex(arg_ifindex, STATUS_DNS, NULL); char **args = strv_skip(argv, 2); r = call_dns(bus, args, bus_resolve_mgr, &error, true); @@ -2828,7 +2758,7 @@ static int verb_domain(int argc, char **argv, void *userdata) { return status_all(bus, STATUS_DOMAIN); if (argc < 3) - return status_ifindex(bus, arg_ifindex, NULL, STATUS_DOMAIN, NULL); + return status_ifindex(arg_ifindex, STATUS_DOMAIN, NULL); char **args = strv_skip(argv, 2); r = call_domain(bus, args, bus_resolve_mgr, &error); @@ -2867,7 +2797,7 @@ static int verb_default_route(int argc, char **argv, void *userdata) { return status_all(bus, STATUS_DEFAULT_ROUTE); if (argc < 3) - return status_ifindex(bus, arg_ifindex, NULL, STATUS_DEFAULT_ROUTE, NULL); + return status_ifindex(arg_ifindex, STATUS_DEFAULT_ROUTE, NULL); b = parse_boolean(argv[2]); if (b < 0) @@ -2913,7 +2843,7 @@ static int verb_llmnr(int argc, char **argv, void *userdata) { return status_all(bus, STATUS_LLMNR); if (argc < 3) - return status_ifindex(bus, arg_ifindex, NULL, STATUS_LLMNR, NULL); + return status_ifindex(arg_ifindex, STATUS_LLMNR, NULL); llmnr_support = resolve_support_from_string(argv[2]); if (llmnr_support < 0) @@ -2971,7 +2901,7 @@ static int verb_mdns(int argc, char **argv, void *userdata) { return status_all(bus, STATUS_MDNS); if (argc < 3) - return status_ifindex(bus, arg_ifindex, NULL, STATUS_MDNS, NULL); + return status_ifindex(arg_ifindex, STATUS_MDNS, NULL); mdns_support = resolve_support_from_string(argv[2]); if (mdns_support < 0) @@ -3033,7 +2963,7 @@ static int verb_dns_over_tls(int argc, char **argv, void *userdata) { return status_all(bus, STATUS_DNS_OVER_TLS); if (argc < 3) - return status_ifindex(bus, arg_ifindex, NULL, STATUS_DNS_OVER_TLS, NULL); + return status_ifindex(arg_ifindex, STATUS_DNS_OVER_TLS, NULL); (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL, arg_ask_password); @@ -3079,7 +3009,7 @@ static int verb_dnssec(int argc, char **argv, void *userdata) { return status_all(bus, STATUS_DNSSEC); if (argc < 3) - return status_ifindex(bus, arg_ifindex, NULL, STATUS_DNSSEC, NULL); + return status_ifindex(arg_ifindex, STATUS_DNSSEC, NULL); (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL, arg_ask_password); @@ -3142,7 +3072,7 @@ static int verb_nta(int argc, char **argv, void *userdata) { return status_all(bus, STATUS_NTA); if (argc < 3) - return status_ifindex(bus, arg_ifindex, NULL, STATUS_NTA, NULL); + return status_ifindex(arg_ifindex, STATUS_NTA, NULL); (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL, arg_ask_password); From 67746cd3b234a869dd91390eb263cb8794c54e90 Mon Sep 17 00:00:00 2001 From: Nick Rosbrook Date: Fri, 30 Jan 2026 14:34:41 -0500 Subject: [PATCH 14/16] resolvectl: use varlink to report delegate status This is an incremental commit to replacing dbus usage with varlink for all status output. Re-implement regular delegate status output using the DumpDNSConfiguration varlink method. And, remove the DelegateInfo type and associated functions which were used to map dbus properties. Since this is the last type of status output to be switched to varlink, lots of other code becomes dead with these changes, e.g. read_dns_server_one(), map_dns_servers_internal(), etc., so remove those too. Finally, status_all() no longer needs sd_bus, so drop that parameter. --- src/resolve/resolvectl.c | 447 ++++++++------------------------------- 1 file changed, 88 insertions(+), 359 deletions(-) diff --git a/src/resolve/resolvectl.c b/src/resolve/resolvectl.c index 0064b37809..9d86c5f6fc 100644 --- a/src/resolve/resolvectl.c +++ b/src/resolve/resolvectl.c @@ -18,7 +18,6 @@ #include "bus-common-errors.h" #include "bus-error.h" #include "bus-locator.h" -#include "bus-map-properties.h" #include "bus-message-util.h" #include "bus-util.h" #include "dns-configuration.h" @@ -1386,219 +1385,6 @@ static int reset_server_features(int argc, char **argv, void *userdata) { return 0; } -typedef enum { - READ_DNS_WITH_IFINDEX = 1 << 0, /* read "ifindex" reply that also carries an interface index */ - READ_DNS_EXTENDED = 1 << 1, /* read "extended" reply, i.e. with port number and server name */ - READ_DNS_ONLY_GLOBAL = 1 << 2, /* suppress entries with an (non-loopback) ifindex set (i.e. which are specific to some interface) */ -} ReadDNSFlag; - -static const char *dns_server_property_signature(ReadDNSFlag flags) { - switch (flags & (READ_DNS_WITH_IFINDEX|READ_DNS_EXTENDED)) { - - case 0: - return "iay"; - - case READ_DNS_WITH_IFINDEX: - return "iiay"; - - case READ_DNS_EXTENDED: - return "iayqs"; - - case READ_DNS_WITH_IFINDEX|READ_DNS_EXTENDED: - return "iiayqs"; - - default: - assert_not_reached(); - } -} - -static int read_dns_server_one(sd_bus_message *m, ReadDNSFlag flags, char **ret) { - _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_free_ char *pretty = NULL; - union in_addr_union a; - const char *name = NULL; - int32_t ifindex = 0; - int family, r; - uint16_t port = 0; - - assert(m); - assert(ret); - - r = sd_bus_message_enter_container( - m, - 'r', - dns_server_property_signature(flags)); - if (r <= 0) - return r; - - if (FLAGS_SET(flags, READ_DNS_WITH_IFINDEX)) { - r = sd_bus_message_read(m, "i", &ifindex); - if (r < 0) - return r; - } - - r = bus_message_read_in_addr_auto(m, &error, &family, &a); - if (r < 0) { - if (sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS)) { - /* CurrentDNSServer provides AF_UNSPEC when no current server assigned. */ - log_debug("Invalid DNS server, ignoring: %s", bus_error_message(&error, r)); - - for (;;) { - r = sd_bus_message_skip(m, NULL); - if (r == -ENXIO) /* End of the container */ - break; - if (r < 0) - return r; - } - - r = sd_bus_message_exit_container(m); - if (r < 0) - return r; - - *ret = NULL; - return 1; - } - - return r; - } - - if (FLAGS_SET(flags, READ_DNS_EXTENDED)) { - r = sd_bus_message_read(m, "qs", &port, &name); - if (r < 0) - return r; - } - - r = sd_bus_message_exit_container(m); - if (r < 0) - return r; - - if (FLAGS_SET(flags, READ_DNS_ONLY_GLOBAL) && ifindex > 0 && ifindex != LOOPBACK_IFINDEX) { - /* This one has an (non-loopback) ifindex set, and we were told to suppress those. Hence do so. */ - *ret = NULL; - return 1; - } - - r = in_addr_port_ifindex_name_to_string(family, &a, port, ifindex, name, &pretty); - if (r < 0) - return r; - - *ret = TAKE_PTR(pretty); - return 1; -} - -static int map_dns_servers_internal(sd_bus *bus, const char *member, sd_bus_message *m, ReadDNSFlag flags, sd_bus_error *error, void *userdata) { - char ***l = ASSERT_PTR(userdata); - int r; - - assert(bus); - assert(member); - assert(m); - - const char *sig = strjoina("(", dns_server_property_signature(flags), ")"); - - r = sd_bus_message_enter_container(m, 'a', sig); - if (r < 0) - return r; - - for (;;) { - _cleanup_free_ char *pretty = NULL; - - r = read_dns_server_one(m, flags, &pretty); - if (r < 0) - return r; - if (r == 0) - break; - - if (isempty(pretty)) - continue; - - r = strv_consume(l, TAKE_PTR(pretty)); - if (r < 0) - return r; - } - - r = sd_bus_message_exit_container(m); - if (r < 0) - return r; - - return 0; -} - -static int read_domain_one(sd_bus_message *m, bool with_ifindex, char **ret) { - _cleanup_free_ char *str = NULL; - int ifindex, route_only, r; - const char *domain; - - assert(m); - assert(ret); - - if (with_ifindex) - r = sd_bus_message_read(m, "(isb)", &ifindex, &domain, &route_only); - else - r = sd_bus_message_read(m, "(sb)", &domain, &route_only); - if (r <= 0) - return r; - - if (with_ifindex && ifindex != 0) { - /* only show the global ones here */ - *ret = NULL; - return 1; - } - - if (route_only) - str = strjoin("~", domain); - else - str = strdup(domain); - if (!str) - return -ENOMEM; - - *ret = TAKE_PTR(str); - return 1; -} - -static int map_domains_internal( - sd_bus *bus, - const char *member, - sd_bus_message *m, - bool with_ifindex, - sd_bus_error *error, - void *userdata) { - - char ***l = ASSERT_PTR(userdata); - int r; - - assert(bus); - assert(member); - assert(m); - - r = sd_bus_message_enter_container(m, 'a', with_ifindex ? "(isb)" : "(sb)"); - if (r < 0) - return r; - - for (;;) { - _cleanup_free_ char *pretty = NULL; - - r = read_domain_one(m, with_ifindex, &pretty); - if (r < 0) - return r; - if (r == 0) - break; - - if (isempty(pretty)) - continue; - - r = strv_consume(l, TAKE_PTR(pretty)); - if (r < 0) - return r; - } - - r = sd_bus_message_exit_container(m); - if (r < 0) - return r; - - return 0; -} - static int status_print_strv_full(int ifindex, const char *ifname, const char *delegate_id, char **p) { const unsigned indent = strlen("Global: "); /* Use the same indentation everywhere to make things nice */ int pos1, pos2; @@ -2316,82 +2102,47 @@ static int status_global(DNSConfiguration *configuration, StatusMode mode, bool return 0; } -typedef struct DelegateInfo { - char *current_dns; - char **dns; - char **domains; - bool default_route; -} DelegateInfo; - -static void delegate_info_done(DelegateInfo *p) { - assert(p); - - free(p->current_dns); - strv_free(p->dns); - strv_free(p->domains); -} - -static int map_delegate_dns_servers(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) { - return map_dns_servers_internal(bus, member, m, READ_DNS_WITH_IFINDEX|READ_DNS_EXTENDED, error, userdata); -} - -static int map_delegate_current_dns_server(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) { - return read_dns_server_one(m, READ_DNS_WITH_IFINDEX|READ_DNS_EXTENDED, userdata); -} - -static int map_delegate_domains(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) { - return map_domains_internal(bus, member, m, /* with_ifindex= */ false, error, userdata); -} - -static int status_delegate_one(sd_bus *bus, const char *id, StatusMode mode, bool *empty_line) { - - static const struct bus_properties_map property_map[] = { - { "DNS", "a(iiayqs)", map_delegate_dns_servers, offsetof(DelegateInfo, dns) }, - { "CurrentDNSServer", "(iiayqs)", map_delegate_current_dns_server, offsetof(DelegateInfo, current_dns) }, - { "Domains", "a(sb)", map_delegate_domains, offsetof(DelegateInfo, domains) }, - { "DefaultRoute", "b", NULL, offsetof(DelegateInfo, default_route) }, - {} - }; - - _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_(delegate_info_done) DelegateInfo delegate_info = {}; - _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; - _cleanup_free_ char *p = NULL; +static int status_delegate(DNSConfiguration *configuration, StatusMode mode, bool *empty_line) { int r; - assert(bus); - assert(id); - - r = sd_bus_path_encode("/org/freedesktop/resolve1/dns_delegate", id, &p); - if (r < 0) - return log_oom(); - - r = bus_map_all_properties( - bus, - "org.freedesktop.resolve1", - p, - property_map, - BUS_MAP_BOOLEAN_AS_BOOL, - &error, - &m, - &delegate_info); - if (r < 0) - return log_error_errno(r, "Failed to get delegate data for %s: %s", id, bus_error_message(&error, r)); + assert(configuration); + assert(configuration->delegate); pager_open(arg_pager_flags); switch (mode) { - case STATUS_DNS: - return status_print_strv_delegate(id, delegate_info.dns); + case STATUS_DNS: { + _cleanup_strv_free_ char **dns_servers = NULL; + r = format_dns_servers(configuration->dns_servers, + /* with_ifindex= */ true, + /* only_global= */ false, + &dns_servers); + if (r < 0) + return r; - case STATUS_DOMAIN: - return status_print_strv_delegate(id, delegate_info.domains); + return status_print_strv_delegate(configuration->delegate, + dns_servers); + } + + case STATUS_DOMAIN: { + _cleanup_strv_free_ char **search_domains = NULL; + r = format_search_domains(configuration->search_domains, + /* only_global= */ false, + &search_domains); + if (r < 0) + return r; + + return status_print_strv_delegate(configuration->delegate, + search_domains); + } case STATUS_DEFAULT_ROUTE: printf("%sDelegate %s%s: %s\n", - ansi_highlight(), id, ansi_normal(), - yes_no(delegate_info.default_route)); + ansi_highlight(), + configuration->delegate, + ansi_normal(), + yes_no(configuration->default_route)); return 0; @@ -2406,32 +2157,58 @@ static int status_delegate_one(sd_bus *bus, const char *id, StatusMode mode, boo fputc('\n', stdout); printf("%sDelegate %s%s\n", - ansi_highlight(), id, ansi_normal()); + ansi_highlight(), + configuration->delegate, + ansi_normal()); _cleanup_(table_unrefp) Table *table = table_new_vertical(); if (!table) return log_oom(); - if (delegate_info.current_dns) { - r = table_add_many(table, - TABLE_FIELD, "Current DNS Server", - TABLE_STRING, delegate_info.current_dns); + if (configuration->current_dns_server) { + _cleanup_free_ char *current_dns = NULL; + r = format_dns_server_one(configuration->current_dns_server, + /* with_ifindex= */ true, + /* only_global= */ false, + ¤t_dns); if (r < 0) - return table_log_add_error(r); + return r; + if (r > 0) { + r = table_add_many(table, + TABLE_FIELD, "Current DNS Server", + TABLE_STRING, current_dns); + if (r < 0) + return table_log_add_error(r); + } } - r = dump_list(table, "DNS Servers", delegate_info.dns); + _cleanup_strv_free_ char **dns_servers = NULL; + r = format_dns_servers(configuration->dns_servers, + /* with_ifindex= */ true, + /* only_global= */ false, + &dns_servers); if (r < 0) return r; - r = dump_list(table, "DNS Domain", delegate_info.domains); + r = dump_list(table, "DNS Servers", dns_servers); + if (r < 0) + return r; + + _cleanup_strv_free_ char **search_domains = NULL; + r = format_search_domains(configuration->search_domains, + /* only_global= */ false, + &search_domains); + if (r < 0) + return r; + + r = dump_list(table, "DNS Domain", search_domains); if (r < 0) return r; r = table_add_many(table, TABLE_FIELD, "Default Route", TABLE_SET_MINIMUM_WIDTH, 19, - TABLE_BOOLEAN, delegate_info.default_route); + TABLE_BOOLEAN, configuration->default_route); if (r < 0) return table_log_add_error(r); @@ -2445,58 +2222,10 @@ static int status_delegate_one(sd_bus *bus, const char *id, StatusMode mode, boo return 0; } -static int status_delegates(sd_bus *bus, StatusMode mode, bool *empty_line) { - _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; - _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - int r, ret = 0; - - assert(bus); - - r = bus_call_method(bus, bus_resolve_mgr, "ListDelegates", &error, &reply, NULL); - if (r < 0) { - if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD)) { - log_debug("Delegates not supported, skipping."); - return 0; - } - return log_error_errno(r, "Failed to list delegates: %s", bus_error_message(&error, r)); - } - - r = sd_bus_message_enter_container(reply, 'a', "(so)"); - if (r < 0) - return bus_log_parse_error(r); - - _cleanup_strv_free_ char **l = NULL; - for (;;) { - const char *id; - - r = sd_bus_message_read(reply, "(so)", &id, NULL); - if (r < 0) - return bus_log_parse_error(r); - if (r == 0) - break; - - if (strv_extend(&l, id) < 0) - return log_oom(); - } - - r = sd_bus_message_exit_container(reply); - if (r < 0) - return bus_log_parse_error(r); - - strv_sort(l); - - STRV_FOREACH(i, l) - RET_GATHER(ret, status_delegate_one(bus, *i, mode, empty_line)); - - return ret; -} - -static int status_all(sd_bus *bus, StatusMode mode) { +static int status_all(StatusMode mode) { bool empty_line = false; int r; - assert(bus); - if (sd_json_format_enabled(arg_json_format_flags)) return status_json(mode, /* links= */ NULL); @@ -2506,7 +2235,7 @@ static int status_all(sd_bus *bus, StatusMode mode) { return r; _cleanup_(dns_configuration_freep) DNSConfiguration *global_config = NULL; - _cleanup_ordered_set_free_ OrderedSet *link_configs = NULL; + _cleanup_ordered_set_free_ OrderedSet *link_configs = NULL, *delegate_configs = NULL; sd_json_variant *w; JSON_VARIANT_ARRAY_FOREACH(w, v) { _cleanup_(dns_configuration_freep) DNSConfiguration *c = NULL; @@ -2522,9 +2251,12 @@ static int status_all(sd_bus *bus, StatusMode mode) { if (r < 0) return r; TAKE_PTR(c); - } else if (c->delegate) - continue; - else { + } else if (c->delegate) { + r = ordered_set_ensure_put(&delegate_configs, &dns_configuration_hash_ops, c); + if (r < 0) + return r; + TAKE_PTR(c); + } else { assert(!global_config); global_config = TAKE_PTR(c); } @@ -2543,28 +2275,25 @@ static int status_all(sd_bus *bus, StatusMode mode) { return r; } - r = status_delegates(bus, mode, &empty_line); - if (r < 0) - return r; + ORDERED_SET_FOREACH(c, delegate_configs) { + r = status_delegate(c, mode, &empty_line); + if (r < 0) + return r; + } return 0; } static int verb_status(int argc, char **argv, void *userdata) { - _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; bool empty_line = false; - int r, ret = 0; + int ret = 0; if (sd_json_format_enabled(arg_json_format_flags)) return status_json(STATUS_ALL, argc > 1 ? strv_skip(argv, 1) : NULL); - r = acquire_bus(&bus); - if (r < 0) - return r; - if (argc <= 1) - return status_all(bus, STATUS_ALL); + return status_all(STATUS_ALL); STRV_FOREACH(ifname, strv_skip(argv, 1)) { int ifindex; @@ -2670,7 +2399,7 @@ static int verb_dns(int argc, char **argv, void *userdata) { } if (arg_ifindex <= 0) - return status_all(bus, STATUS_DNS); + return status_all(STATUS_DNS); if (argc < 3) return status_ifindex(arg_ifindex, STATUS_DNS, NULL); @@ -2755,7 +2484,7 @@ static int verb_domain(int argc, char **argv, void *userdata) { } if (arg_ifindex <= 0) - return status_all(bus, STATUS_DOMAIN); + return status_all(STATUS_DOMAIN); if (argc < 3) return status_ifindex(arg_ifindex, STATUS_DOMAIN, NULL); @@ -2794,7 +2523,7 @@ static int verb_default_route(int argc, char **argv, void *userdata) { } if (arg_ifindex <= 0) - return status_all(bus, STATUS_DEFAULT_ROUTE); + return status_all(STATUS_DEFAULT_ROUTE); if (argc < 3) return status_ifindex(arg_ifindex, STATUS_DEFAULT_ROUTE, NULL); @@ -2840,7 +2569,7 @@ static int verb_llmnr(int argc, char **argv, void *userdata) { } if (arg_ifindex <= 0) - return status_all(bus, STATUS_LLMNR); + return status_all(STATUS_LLMNR); if (argc < 3) return status_ifindex(arg_ifindex, STATUS_LLMNR, NULL); @@ -2898,7 +2627,7 @@ static int verb_mdns(int argc, char **argv, void *userdata) { } if (arg_ifindex <= 0) - return status_all(bus, STATUS_MDNS); + return status_all(STATUS_MDNS); if (argc < 3) return status_ifindex(arg_ifindex, STATUS_MDNS, NULL); @@ -2960,7 +2689,7 @@ static int verb_dns_over_tls(int argc, char **argv, void *userdata) { } if (arg_ifindex <= 0) - return status_all(bus, STATUS_DNS_OVER_TLS); + return status_all(STATUS_DNS_OVER_TLS); if (argc < 3) return status_ifindex(arg_ifindex, STATUS_DNS_OVER_TLS, NULL); @@ -3006,7 +2735,7 @@ static int verb_dnssec(int argc, char **argv, void *userdata) { } if (arg_ifindex <= 0) - return status_all(bus, STATUS_DNSSEC); + return status_all(STATUS_DNSSEC); if (argc < 3) return status_ifindex(arg_ifindex, STATUS_DNSSEC, NULL); @@ -3069,7 +2798,7 @@ static int verb_nta(int argc, char **argv, void *userdata) { } if (arg_ifindex <= 0) - return status_all(bus, STATUS_NTA); + return status_all(STATUS_NTA); if (argc < 3) return status_ifindex(arg_ifindex, STATUS_NTA, NULL); From 480ebdfdddbe61c7c47d41ee1be31f867eb0269f Mon Sep 17 00:00:00 2001 From: Nick Rosbrook Date: Fri, 30 Jan 2026 15:10:49 -0500 Subject: [PATCH 15/16] resolvectl: consolidate JSON and regular status output paths Now that varlink is always used for status output, consolidate the JSON and regular status code paths. Add status_full(), which is the single point that calls DumpDNSConfiguration, filters based on link names and mode if needed, and prints the output in the appropriate format. This simplifies status_ifindex(), and removes the need for a separate status_json(). --- src/resolve/resolvectl.c | 132 ++++++++++++--------------------------- 1 file changed, 39 insertions(+), 93 deletions(-) diff --git a/src/resolve/resolvectl.c b/src/resolve/resolvectl.c index 9d86c5f6fc..a6074a3ade 100644 --- a/src/resolve/resolvectl.c +++ b/src/resolve/resolvectl.c @@ -1555,25 +1555,6 @@ static int varlink_dump_dns_configuration(sd_json_variant **ret) { return 0; } -static int status_json(StatusMode mode, char **links) { - _cleanup_(sd_json_variant_unrefp) sd_json_variant *configuration = NULL; - int r; - - r = varlink_dump_dns_configuration(&configuration); - if (r < 0) - return r; - - r = status_json_filter_links(&configuration, links); - if (r < 0) - return log_error_errno(r, "Failed to filter configuration JSON links: %m"); - - r = status_json_filter_fields(&configuration, mode); - if (r < 0) - return log_error_errno(r, "Failed to filter configuration JSON fields: %m"); - - return sd_json_variant_dump(configuration, arg_json_format_flags, /* f= */ NULL, /* prefix= */ NULL); -} - static int format_dns_server_one(DNSServer *s, bool with_ifindex, bool only_global, char **ret) { int r; @@ -1909,42 +1890,6 @@ static int status_link(DNSConfiguration *configuration, StatusMode mode, bool *e return 0; } -static int status_ifindex(int ifindex, StatusMode mode, bool *empty_line) { - int r; - - assert(ifindex > 0); - - if (sd_json_format_enabled(arg_json_format_flags)) { - char ifname[IF_NAMESIZE]; - r = format_ifname(ifindex, ifname); - if (r < 0) - return log_error_errno(r, "Failed to resolve interface name for %i: %m", ifindex); - - return status_json(mode, STRV_MAKE(ifname)); - } - - _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL; - r = varlink_dump_dns_configuration(&v); - if (r < 0) - return r; - - sd_json_variant *w; - JSON_VARIANT_ARRAY_FOREACH(w, v) { - int found = sd_json_variant_unsigned(sd_json_variant_by_key(w, "ifindex")); - if (found != ifindex) - continue; - - _cleanup_(dns_configuration_freep) DNSConfiguration *c = NULL; - r = dns_configuration_from_json(w, &c); - if (r < 0) - return r; - - return status_link(c, mode, empty_line); - } - - return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "No DNS configuration for interface %d", ifindex); -} - static int status_global(DNSConfiguration *configuration, StatusMode mode, bool *empty_line) { _cleanup_(table_unrefp) Table *table = NULL; int r; @@ -2222,18 +2167,27 @@ static int status_delegate(DNSConfiguration *configuration, StatusMode mode, boo return 0; } -static int status_all(StatusMode mode) { +static int status_full(StatusMode mode, char **links) { bool empty_line = false; int r; - if (sd_json_format_enabled(arg_json_format_flags)) - return status_json(mode, /* links= */ NULL); - _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL; r = varlink_dump_dns_configuration(&v); if (r < 0) return r; + r = status_json_filter_links(&v, links); + if (r < 0) + return log_error_errno(r, "Failed to filter configuration JSON links: %m"); + + if (sd_json_format_enabled(arg_json_format_flags)) { + r = status_json_filter_fields(&v, mode); + if (r < 0) + return log_error_errno(r, "Failed to filter configuration JSON fields: %m"); + + return sd_json_variant_dump(v, arg_json_format_flags, /* f= */ NULL, /* prefix= */ NULL); + } + _cleanup_(dns_configuration_freep) DNSConfiguration *global_config = NULL; _cleanup_ordered_set_free_ OrderedSet *link_configs = NULL, *delegate_configs = NULL; sd_json_variant *w; @@ -2243,9 +2197,6 @@ static int status_all(StatusMode mode) { if (r < 0) return r; - if (c->ifindex == LOOPBACK_IFINDEX) - continue; - if (c->ifindex > 0) { r = ordered_set_ensure_put(&link_configs, &dns_configuration_hash_ops, c); if (r < 0) @@ -2284,30 +2235,25 @@ static int status_all(StatusMode mode) { return 0; } +static int status_all(StatusMode mode) { + return status_full(mode, /* links= */ NULL); +} + +static int status_ifindex(int ifindex, StatusMode mode) { + int r; + char ifname[IF_NAMESIZE]; + + assert(ifindex > 0); + + r = format_ifname(ifindex, ifname); + if (r < 0) + return log_error_errno(r, "Failed to resolve interface name for %i: %m", ifindex); + + return status_full(mode, STRV_MAKE(ifname)); +} + static int verb_status(int argc, char **argv, void *userdata) { - _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; - bool empty_line = false; - int ret = 0; - - if (sd_json_format_enabled(arg_json_format_flags)) - return status_json(STATUS_ALL, argc > 1 ? strv_skip(argv, 1) : NULL); - - if (argc <= 1) - return status_all(STATUS_ALL); - - STRV_FOREACH(ifname, strv_skip(argv, 1)) { - int ifindex; - - ifindex = rtnl_resolve_interface(&rtnl, *ifname); - if (ifindex < 0) { - log_warning_errno(ifindex, "Failed to resolve interface \"%s\", ignoring: %m", *ifname); - continue; - } - - RET_GATHER(ret, status_ifindex(ifindex, STATUS_ALL, &empty_line)); - } - - return ret; + return status_full(STATUS_ALL, strv_skip(argv, 1)); } static int call_dns(sd_bus *bus, char **dns, const BusLocator *locator, sd_bus_error *error, bool extended) { @@ -2402,7 +2348,7 @@ static int verb_dns(int argc, char **argv, void *userdata) { return status_all(STATUS_DNS); if (argc < 3) - return status_ifindex(arg_ifindex, STATUS_DNS, NULL); + return status_ifindex(arg_ifindex, STATUS_DNS); char **args = strv_skip(argv, 2); r = call_dns(bus, args, bus_resolve_mgr, &error, true); @@ -2487,7 +2433,7 @@ static int verb_domain(int argc, char **argv, void *userdata) { return status_all(STATUS_DOMAIN); if (argc < 3) - return status_ifindex(arg_ifindex, STATUS_DOMAIN, NULL); + return status_ifindex(arg_ifindex, STATUS_DOMAIN); char **args = strv_skip(argv, 2); r = call_domain(bus, args, bus_resolve_mgr, &error); @@ -2526,7 +2472,7 @@ static int verb_default_route(int argc, char **argv, void *userdata) { return status_all(STATUS_DEFAULT_ROUTE); if (argc < 3) - return status_ifindex(arg_ifindex, STATUS_DEFAULT_ROUTE, NULL); + return status_ifindex(arg_ifindex, STATUS_DEFAULT_ROUTE); b = parse_boolean(argv[2]); if (b < 0) @@ -2572,7 +2518,7 @@ static int verb_llmnr(int argc, char **argv, void *userdata) { return status_all(STATUS_LLMNR); if (argc < 3) - return status_ifindex(arg_ifindex, STATUS_LLMNR, NULL); + return status_ifindex(arg_ifindex, STATUS_LLMNR); llmnr_support = resolve_support_from_string(argv[2]); if (llmnr_support < 0) @@ -2630,7 +2576,7 @@ static int verb_mdns(int argc, char **argv, void *userdata) { return status_all(STATUS_MDNS); if (argc < 3) - return status_ifindex(arg_ifindex, STATUS_MDNS, NULL); + return status_ifindex(arg_ifindex, STATUS_MDNS); mdns_support = resolve_support_from_string(argv[2]); if (mdns_support < 0) @@ -2692,7 +2638,7 @@ static int verb_dns_over_tls(int argc, char **argv, void *userdata) { return status_all(STATUS_DNS_OVER_TLS); if (argc < 3) - return status_ifindex(arg_ifindex, STATUS_DNS_OVER_TLS, NULL); + return status_ifindex(arg_ifindex, STATUS_DNS_OVER_TLS); (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL, arg_ask_password); @@ -2738,7 +2684,7 @@ static int verb_dnssec(int argc, char **argv, void *userdata) { return status_all(STATUS_DNSSEC); if (argc < 3) - return status_ifindex(arg_ifindex, STATUS_DNSSEC, NULL); + return status_ifindex(arg_ifindex, STATUS_DNSSEC); (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL, arg_ask_password); @@ -2801,7 +2747,7 @@ static int verb_nta(int argc, char **argv, void *userdata) { return status_all(STATUS_NTA); if (argc < 3) - return status_ifindex(arg_ifindex, STATUS_NTA, NULL); + return status_ifindex(arg_ifindex, STATUS_NTA); (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL, arg_ask_password); From a4750a6612b20cf108d56cd2acc5e109adfa91c3 Mon Sep 17 00:00:00 2001 From: Nick Rosbrook Date: Fri, 30 Jan 2026 16:04:37 -0500 Subject: [PATCH 16/16] resolvectl: add print_configuration() to consolidate status logic There is a lot of duplication across the functions for printing global, link, and delegate output. Since these all use a common DNSConfiguration type now, the logic can be consolidated. Adapt printing and format helper functions to accept a DNSConfiguration parameter to appropriately format output. Then, add print_configuration(), a single function that prints the appropriate status output based on the contents of DNSConfiguration. --- src/resolve/resolvectl.c | 600 +++++++++++---------------------------- 1 file changed, 167 insertions(+), 433 deletions(-) diff --git a/src/resolve/resolvectl.c b/src/resolve/resolvectl.c index a6074a3ade..9f5616c272 100644 --- a/src/resolve/resolvectl.c +++ b/src/resolve/resolvectl.c @@ -1385,14 +1385,16 @@ static int reset_server_features(int argc, char **argv, void *userdata) { return 0; } -static int status_print_strv_full(int ifindex, const char *ifname, const char *delegate_id, char **p) { +static int status_print_strv(DNSConfiguration *c, char **p) { const unsigned indent = strlen("Global: "); /* Use the same indentation everywhere to make things nice */ int pos1, pos2; - if (ifname) - printf("%s%nLink %i (%s)%n%s:", ansi_highlight(), &pos1, ifindex, ifname, &pos2, ansi_normal()); - else if (delegate_id) - printf("%s%nDelegate %s%n%s:", ansi_highlight(), &pos1, delegate_id, &pos2, ansi_normal()); + assert(c); + + if (c->ifname) + printf("%s%nLink %i (%s)%n%s:", ansi_highlight(), &pos1, c->ifindex, c->ifname, &pos2, ansi_normal()); + else if (c->delegate) + printf("%s%nDelegate %s%n%s:", ansi_highlight(), &pos1, c->delegate, &pos2, ansi_normal()); else printf("%s%nGlobal%n%s:", ansi_highlight(), &pos1, &pos2, ansi_normal()); @@ -1416,16 +1418,42 @@ static int status_print_strv_full(int ifindex, const char *ifname, const char *d return 0; } -static int status_print_strv_ifindex(int ifindex, const char *ifname, char **p) { - return status_print_strv_full(ifindex, ifname, NULL, p); +static void status_print_string(DNSConfiguration *c, const char *p) { + assert(c); + + if (c->ifname) + printf("%sLink %i (%s)%s: %s\n", + ansi_highlight(), + c->ifindex, + c->ifname, + ansi_normal(), + p); + else if (c->delegate) + printf("%sDelegate %s%s: %s\n", + ansi_highlight(), + c->delegate, + ansi_normal(), + p); + else + printf("%sGlobal%s: %s\n", ansi_highlight(), ansi_normal(), p); } -static int status_print_strv_delegate(const char *delegate_id, char **p) { - return status_print_strv_full(0, NULL, delegate_id, p); -} +static void status_print_header(DNSConfiguration *c) { + assert(c); -static int status_print_strv_global(char **p) { - return status_print_strv_full(0, NULL, NULL, p); + if (c->ifname) + printf("%sLink %i (%s)%s\n", + ansi_highlight(), + c->ifindex, + c->ifname, + ansi_normal()); + else if (c->delegate) + printf("%sDelegate %s%s\n", + ansi_highlight(), + c->delegate, + ansi_normal()); + else + printf("%sGlobal%s\n", ansi_highlight(), ansi_normal()); } static int dump_list(Table *table, const char *field, char * const *l) { @@ -1555,13 +1583,17 @@ static int varlink_dump_dns_configuration(sd_json_variant **ret) { return 0; } -static int format_dns_server_one(DNSServer *s, bool with_ifindex, bool only_global, char **ret) { +static int format_dns_server_one(DNSConfiguration *configuration, DNSServer *s, char **ret) { + bool global, with_ifindex; int r; assert(s); assert(ret); - if (only_global && s->ifindex > 0 && s->ifindex != LOOPBACK_IFINDEX) { + global = !(configuration->ifindex > 0 || configuration->delegate); + with_ifindex = configuration->ifindex <= 0; + + if (global && s->ifindex > 0 && s->ifindex != LOOPBACK_IFINDEX) { /* This one has an (non-loopback) ifindex set, and we were told to suppress those. Hence do so. */ *ret = NULL; return 0; @@ -1580,7 +1612,7 @@ static int format_dns_server_one(DNSServer *s, bool with_ifindex, bool only_glob return 1; } -static int format_dns_servers(OrderedSet *servers, bool with_ifindex, bool only_global, char ***ret) { +static int format_dns_servers(DNSConfiguration *configuration, OrderedSet *servers, char ***ret) { int r; assert(ret); @@ -1589,7 +1621,7 @@ static int format_dns_servers(OrderedSet *servers, bool with_ifindex, bool only_ DNSServer *s; ORDERED_SET_FOREACH(s, servers) { _cleanup_free_ char *str = NULL; - r = format_dns_server_one(s, with_ifindex, only_global, &str); + r = format_dns_server_one(configuration, s, &str); if (r < 0) return r; if (r > 0) { @@ -1603,7 +1635,7 @@ static int format_dns_servers(OrderedSet *servers, bool with_ifindex, bool only_ return 0; } -static int format_search_domains(OrderedSet *domains, bool only_global, char ***ret) { +static int format_search_domains(DNSConfiguration *configuration, OrderedSet *domains, char ***ret) { int r; assert(ret); @@ -1611,7 +1643,7 @@ static int format_search_domains(OrderedSet *domains, bool only_global, char *** _cleanup_strv_free_ char **l = NULL; SearchDomain *d; ORDERED_SET_FOREACH(d, domains) { - if (only_global && d->ifindex > 0) + if (!(configuration->ifindex > 0 || configuration->delegate) && d->ifindex > 0) /* Only show the global ones here */ continue; @@ -1667,317 +1699,140 @@ static int format_protocol_status(DNSConfiguration *configuration, char ***ret) return 0; } -static int status_link(DNSConfiguration *configuration, StatusMode mode, bool *empty_line) { +static int format_scopes_string(DNSConfiguration *configuration, char **ret) { + assert(configuration); + assert(ret); + + if (!configuration->dns_scopes) { + *ret = NULL; + return 0; + } + + uint64_t scopes_mask = 0; + DNSScope *scope; + SET_FOREACH(scope, configuration->dns_scopes) { + if (streq(scope->protocol, "dns")) + scopes_mask |= SD_RESOLVED_DNS; + else if (streq(scope->protocol, "llmnr")) + scopes_mask |= scope->family == AF_INET ? + SD_RESOLVED_LLMNR_IPV4 : + SD_RESOLVED_LLMNR_IPV6; + else if (streq(scope->protocol, "mdns")) + scopes_mask |= scope->family == AF_INET ? + SD_RESOLVED_MDNS_IPV4 : + SD_RESOLVED_MDNS_IPV6; + } + + _cleanup_free_ char *buf = NULL; + if (asprintf(&buf, "%s%s%s%s%s", + scopes_mask & SD_RESOLVED_DNS ? "DNS " : "", + scopes_mask & SD_RESOLVED_LLMNR_IPV4 ? "LLMNR/IPv4 " : "", + scopes_mask & SD_RESOLVED_LLMNR_IPV6 ? "LLMNR/IPv6 " : "", + scopes_mask & SD_RESOLVED_MDNS_IPV4 ? "mDNS/IPv4 " : "", + scopes_mask & SD_RESOLVED_MDNS_IPV6 ? "mDNS/IPv6 " : "") < 0) + return log_oom(); + + size_t len = strlen(buf); + assert(len > 0); + buf[len - 1] = '\0'; + + *ret = TAKE_PTR(buf); + return 0; +} + +static int print_configuration(DNSConfiguration *configuration, StatusMode mode, bool *empty_line) { _cleanup_(table_unrefp) Table *table = NULL; - _cleanup_free_ char *p = NULL; int r; assert(configuration); - assert(configuration->ifindex > 0); pager_open(arg_pager_flags); - switch (mode) { - - case STATUS_DNS: { - _cleanup_strv_free_ char **dns_servers = NULL; - r = format_dns_servers(configuration->dns_servers, - /* with_ifindex= */ false, - /* only_global= */ false, - &dns_servers); + bool global = !(configuration->ifindex > 0 || configuration->delegate); + if (mode == STATUS_DNS) { + _cleanup_strv_free_ char **l = NULL; + r = format_dns_servers(configuration, configuration->dns_servers, &l); if (r < 0) return r; - return status_print_strv_ifindex(configuration->ifindex, - configuration->ifname, - dns_servers); - } + return status_print_strv(configuration, l); - case STATUS_DOMAIN: { - _cleanup_strv_free_ char **search_domains = NULL; - r = format_search_domains(configuration->search_domains, - /* only_global= */ false, - &search_domains); + } else if (mode == STATUS_DOMAIN) { + _cleanup_strv_free_ char **l = NULL; + r = format_search_domains(configuration, configuration->search_domains, &l); if (r < 0) return r; - return status_print_strv_ifindex(configuration->ifindex, - configuration->ifname, - search_domains); - } + return status_print_strv(configuration, l); - case STATUS_NTA: - return status_print_strv_ifindex(configuration->ifindex, - configuration->ifname, - configuration->negative_trust_anchors); + } else if (mode == STATUS_NTA) { + if (configuration->delegate) + return 0; - case STATUS_DEFAULT_ROUTE: - printf("%sLink %i (%s)%s: %s\n", - ansi_highlight(), - configuration->ifindex, - configuration->ifname, - ansi_normal(), - yes_no(configuration->default_route)); + return status_print_strv(configuration, configuration->negative_trust_anchors); + + } else if (mode == STATUS_DEFAULT_ROUTE) { + if (global) + return 0; + + status_print_string(configuration, yes_no(configuration->default_route)); return 0; - case STATUS_LLMNR: - printf("%sLink %i (%s)%s: %s\n", - ansi_highlight(), - configuration->ifindex, - configuration->ifname, - ansi_normal(), - strna(configuration->llmnr_mode_str)); + } else if (IN_SET(mode, STATUS_LLMNR, STATUS_MDNS, STATUS_DNS_OVER_TLS, STATUS_DNSSEC)) { + if (configuration->delegate) + return 0; + + status_print_string(configuration, + strna(mode == STATUS_LLMNR ? configuration->llmnr_mode_str : + mode == STATUS_MDNS ? configuration->mdns_mode_str : + mode == STATUS_DNS_OVER_TLS ? configuration->dns_over_tls_mode_str : + configuration->dnssec_mode_str)); return 0; - case STATUS_MDNS: - printf("%sLink %i (%s)%s: %s\n", - ansi_highlight(), - configuration->ifindex, - configuration->ifname, - ansi_normal(), - strna(configuration->mdns_mode_str)); - + } else if (mode != STATUS_ALL) return 0; - case STATUS_DNS_OVER_TLS: - printf("%sLink %i (%s)%s: %s\n", - ansi_highlight(), - configuration->ifindex, - configuration->ifname, - ansi_normal(), - strna(configuration->dns_over_tls_mode_str)); - - return 0; - - case STATUS_DNSSEC: - printf("%sLink %i (%s)%s: %s\n", - ansi_highlight(), - configuration->ifindex, - configuration->ifname, - ansi_normal(), - strna(configuration->dnssec_mode_str)); - - return 0; - - case STATUS_ALL: - break; - - default: - return 0; - } - if (empty_line && *empty_line) fputc('\n', stdout); - printf("%sLink %i (%s)%s\n", - ansi_highlight(), - configuration->ifindex, - configuration->ifname, - ansi_normal()); + status_print_header(configuration); table = table_new_vertical(); if (!table) return log_oom(); - r = table_add_many(table, - TABLE_FIELD, "Current Scopes", - TABLE_SET_MINIMUM_WIDTH, 19); - if (r < 0) - return table_log_add_error(r); - - if (!configuration->dns_scopes) - r = table_add_cell(table, NULL, TABLE_STRING, "none"); - else { - uint64_t scopes_mask = 0; - DNSScope *scope; - SET_FOREACH(scope, configuration->dns_scopes) - if (streq(scope->protocol, "dns")) - scopes_mask |= SD_RESOLVED_DNS; - else if (streq(scope->protocol, "llmnr")) - scopes_mask |= scope->family == AF_INET ? - SD_RESOLVED_LLMNR_IPV4 : - SD_RESOLVED_LLMNR_IPV6; - else if (streq(scope->protocol, "mdns")) - scopes_mask |= scope->family == AF_INET ? - SD_RESOLVED_MDNS_IPV4 : - SD_RESOLVED_MDNS_IPV6; - - _cleanup_free_ char *buf = NULL; - size_t len; - if (asprintf(&buf, "%s%s%s%s%s", - scopes_mask & SD_RESOLVED_DNS ? "DNS " : "", - scopes_mask & SD_RESOLVED_LLMNR_IPV4 ? "LLMNR/IPv4 " : "", - scopes_mask & SD_RESOLVED_LLMNR_IPV6 ? "LLMNR/IPv6 " : "", - scopes_mask & SD_RESOLVED_MDNS_IPV4 ? "mDNS/IPv4 " : "", - scopes_mask & SD_RESOLVED_MDNS_IPV6 ? "mDNS/IPv6 " : "") < 0) - return log_oom(); - - len = strlen(buf); - assert(len > 0); - buf[len - 1] = '\0'; - - r = table_add_cell(table, NULL, TABLE_STRING, buf); - } - if (r < 0) - return table_log_add_error(r); - - _cleanup_strv_free_ char **pstatus = NULL; - r = format_protocol_status(configuration, &pstatus); - if (r < 0) - return r; - - r = table_add_many(table, - TABLE_FIELD, "Protocols", - TABLE_STRV_WRAPPED, pstatus); - if (r < 0) - return table_log_add_error(r); - - if (configuration->current_dns_server) { - _cleanup_free_ char *current_dns = NULL; - r = format_dns_server_one(configuration->current_dns_server, - /* with_ifindex= */ false, - /* only_global= */ false, - ¤t_dns); + if (configuration->ifindex > 0) { + r = table_add_many(table, + TABLE_FIELD, "Current Scopes", + TABLE_SET_MINIMUM_WIDTH, 19); if (r < 0) - return r; - if (r > 0) { - r = table_add_many(table, - TABLE_FIELD, "Current DNS Server", - TABLE_STRING, current_dns); - if (r < 0) - return table_log_add_error(r); - } - } + return table_log_add_error(r); - _cleanup_strv_free_ char **dns_servers = NULL; - r = format_dns_servers(configuration->dns_servers, - /* with_ifindex= */ false, - /* only_global= */ false, - &dns_servers); - if (r < 0) - return r; - - r = dump_list(table, "DNS Servers", dns_servers); - if (r < 0) - return r; - - _cleanup_strv_free_ char **search_domains = NULL; - r = format_search_domains(configuration->search_domains, - /* only_global= */ false, - &search_domains); - if (r < 0) - return r; - - r = dump_list(table, "DNS Domain", search_domains); - if (r < 0) - return r; - - r = table_add_many(table, - TABLE_FIELD, "Default Route", - TABLE_BOOLEAN, configuration->default_route); - if (r < 0) - return table_log_add_error(r); - - r = table_print(table, NULL); - if (r < 0) - return table_log_print_error(r); - - if (empty_line) - *empty_line = true; - - return 0; -} - -static int status_global(DNSConfiguration *configuration, StatusMode mode, bool *empty_line) { - _cleanup_(table_unrefp) Table *table = NULL; - int r; - - assert(configuration); - assert(configuration->ifindex == 0); - assert(!configuration->delegate); - assert(empty_line); - - pager_open(arg_pager_flags); - - switch (mode) { - - case STATUS_DNS: { - _cleanup_strv_free_ char **dns_servers = NULL; - r = format_dns_servers(configuration->dns_servers, - /* with_ifindex= */ true, - /* only_global= */ true, - &dns_servers); + _cleanup_free_ char *s = NULL; + r = format_scopes_string(configuration, &s); if (r < 0) return r; - return status_print_strv_global(dns_servers); + r = table_add_cell(table, NULL, TABLE_STRING, s ?: "none"); + if (r < 0) + return table_log_add_error(r); } - case STATUS_DOMAIN: { - _cleanup_strv_free_ char **search_domains = NULL; - r = format_search_domains(configuration->search_domains, - /* only_global= */ true, - &search_domains); + if (!configuration->delegate) { + _cleanup_strv_free_ char **l = NULL; + r = format_protocol_status(configuration, &l); if (r < 0) return r; - return status_print_strv_global(search_domains); + r = table_add_many(table, + TABLE_FIELD, "Protocols", + TABLE_STRV_WRAPPED, l); + if (r < 0) + return table_log_add_error(r); } - case STATUS_NTA: - return status_print_strv_global(configuration->negative_trust_anchors); - - case STATUS_LLMNR: - printf("%sGlobal%s: %s\n", ansi_highlight(), ansi_normal(), - strna(configuration->llmnr_mode_str)); - - return 0; - - case STATUS_MDNS: - printf("%sGlobal%s: %s\n", ansi_highlight(), ansi_normal(), - strna(configuration->mdns_mode_str)); - - return 0; - - case STATUS_DNS_OVER_TLS: - printf("%sGlobal%s: %s\n", ansi_highlight(), ansi_normal(), - strna(configuration->dns_over_tls_mode_str)); - - return 0; - - case STATUS_DNSSEC: - printf("%sGlobal%s: %s\n", ansi_highlight(), ansi_normal(), - strna(configuration->dnssec_mode_str)); - - return 0; - - case STATUS_ALL: - break; - - default: - return 0; - } - - printf("%sGlobal%s\n", ansi_highlight(), ansi_normal()); - - table = table_new_vertical(); - if (!table) - return log_oom(); - - _cleanup_strv_free_ char **pstatus = NULL; - r = format_protocol_status(configuration, &pstatus); - if (r < 0) - return r; - - r = table_add_many(table, - TABLE_FIELD, "Protocols", - TABLE_SET_MINIMUM_WIDTH, 19, - TABLE_STRV_WRAPPED, pstatus); - if (r < 0) - return table_log_add_error(r); - if (configuration->resolv_conf_mode_str) { r = table_add_many(table, TABLE_FIELD, "resolv.conf mode", @@ -1987,27 +1842,20 @@ static int status_global(DNSConfiguration *configuration, StatusMode mode, bool } if (configuration->current_dns_server) { - _cleanup_free_ char *current_dns = NULL; - r = format_dns_server_one(configuration->current_dns_server, - /* with_ifindex= */ true, - /* only_global= */ true, - ¤t_dns); + _cleanup_free_ char *s = NULL; + r = format_dns_server_one(configuration, configuration->current_dns_server, &s); if (r < 0) return r; - if (r > 0) { - r = table_add_many(table, - TABLE_FIELD, "Current DNS Server", - TABLE_STRING, current_dns); - if (r < 0) - return table_log_add_error(r); - } + + r = table_add_many(table, + TABLE_FIELD, "Current DNS Server", + TABLE_STRING, s); + if (r < 0) + return table_log_add_error(r); } _cleanup_strv_free_ char **dns_servers = NULL; - r = format_dns_servers(configuration->dns_servers, - /* with_ifindex= */ true, - /* only_global= */ true, - &dns_servers); + r = format_dns_servers(configuration, configuration->dns_servers, &dns_servers); if (r < 0) return r; @@ -2015,22 +1863,19 @@ static int status_global(DNSConfiguration *configuration, StatusMode mode, bool if (r < 0) return r; - _cleanup_strv_free_ char **fallback_dns_servers = NULL; - r = format_dns_servers(configuration->fallback_dns_servers, - /* with_ifindex= */ true, - /* only_global= */ true, - &fallback_dns_servers); - if (r < 0) - return r; + if (global) { + _cleanup_strv_free_ char **l = NULL; + r = format_dns_servers(configuration, configuration->fallback_dns_servers, &l); + if (r < 0) + return r; - r = dump_list(table, "Fallback DNS Servers", fallback_dns_servers); - if (r < 0) - return r; + r = dump_list(table, "Fallback DNS Servers", l); + if (r < 0) + return r; + } _cleanup_strv_free_ char **search_domains = NULL; - r = format_search_domains(configuration->search_domains, - /* only_global= */ true, - &search_domains); + r = format_search_domains(configuration, configuration->search_domains, &search_domains); if (r < 0) return r; @@ -2038,125 +1883,14 @@ static int status_global(DNSConfiguration *configuration, StatusMode mode, bool if (r < 0) return r; - r = table_print(table, NULL); - if (r < 0) - return table_log_print_error(r); - - *empty_line = true; - - return 0; -} - -static int status_delegate(DNSConfiguration *configuration, StatusMode mode, bool *empty_line) { - int r; - - assert(configuration); - assert(configuration->delegate); - - pager_open(arg_pager_flags); - - switch (mode) { - - case STATUS_DNS: { - _cleanup_strv_free_ char **dns_servers = NULL; - r = format_dns_servers(configuration->dns_servers, - /* with_ifindex= */ true, - /* only_global= */ false, - &dns_servers); + if (!global) { + r = table_add_many(table, + TABLE_FIELD, "Default Route", + TABLE_BOOLEAN, configuration->default_route); if (r < 0) - return r; - - return status_print_strv_delegate(configuration->delegate, - dns_servers); + return table_log_add_error(r); } - case STATUS_DOMAIN: { - _cleanup_strv_free_ char **search_domains = NULL; - r = format_search_domains(configuration->search_domains, - /* only_global= */ false, - &search_domains); - if (r < 0) - return r; - - return status_print_strv_delegate(configuration->delegate, - search_domains); - } - - case STATUS_DEFAULT_ROUTE: - printf("%sDelegate %s%s: %s\n", - ansi_highlight(), - configuration->delegate, - ansi_normal(), - yes_no(configuration->default_route)); - - return 0; - - case STATUS_ALL: - break; - - default: - return 0; - } - - if (empty_line && *empty_line) - fputc('\n', stdout); - - printf("%sDelegate %s%s\n", - ansi_highlight(), - configuration->delegate, - ansi_normal()); - - _cleanup_(table_unrefp) Table *table = table_new_vertical(); - if (!table) - return log_oom(); - - if (configuration->current_dns_server) { - _cleanup_free_ char *current_dns = NULL; - r = format_dns_server_one(configuration->current_dns_server, - /* with_ifindex= */ true, - /* only_global= */ false, - ¤t_dns); - if (r < 0) - return r; - if (r > 0) { - r = table_add_many(table, - TABLE_FIELD, "Current DNS Server", - TABLE_STRING, current_dns); - if (r < 0) - return table_log_add_error(r); - } - } - - _cleanup_strv_free_ char **dns_servers = NULL; - r = format_dns_servers(configuration->dns_servers, - /* with_ifindex= */ true, - /* only_global= */ false, - &dns_servers); - if (r < 0) - return r; - - r = dump_list(table, "DNS Servers", dns_servers); - if (r < 0) - return r; - - _cleanup_strv_free_ char **search_domains = NULL; - r = format_search_domains(configuration->search_domains, - /* only_global= */ false, - &search_domains); - if (r < 0) - return r; - - r = dump_list(table, "DNS Domain", search_domains); - if (r < 0) - return r; - - r = table_add_many(table, - TABLE_FIELD, "Default Route", - TABLE_SET_MINIMUM_WIDTH, 19, - TABLE_BOOLEAN, configuration->default_route); - if (r < 0) - return table_log_add_error(r); - r = table_print(table, NULL); if (r < 0) return table_log_print_error(r); @@ -2214,20 +1948,20 @@ static int status_full(StatusMode mode, char **links) { } if (global_config) { - r = status_global(global_config, mode, &empty_line); + r = print_configuration(global_config, mode, &empty_line); if (r < 0) return r; } DNSConfiguration *c; ORDERED_SET_FOREACH(c, link_configs) { - r = status_link(c, mode, &empty_line); + r = print_configuration(c, mode, &empty_line); if (r < 0) return r; } ORDERED_SET_FOREACH(c, delegate_configs) { - r = status_delegate(c, mode, &empty_line); + r = print_configuration(c, mode, &empty_line); if (r < 0) return r; }