diff --git a/src/resolve/org.freedesktop.resolve1.policy b/src/resolve/org.freedesktop.resolve1.policy
index b96c8c0d6a..097e78e73c 100644
--- a/src/resolve/org.freedesktop.resolve1.policy
+++ b/src/resolve/org.freedesktop.resolve1.policy
@@ -150,6 +150,17 @@
unix-user:systemd-resolve
+
+ Subscribe to DNS configuration
+ Authentication is required to subscribe to DNS configuration.
+
+ auth_admin
+ auth_admin
+ auth_admin_keep
+
+ unix-user:systemd-resolve
+
+
Dump cache
Authentication is required to dump cache.
diff --git a/src/resolve/resolved-dns-search-domain.c b/src/resolve/resolved-dns-search-domain.c
index a11b21350a..642d52c6ea 100644
--- a/src/resolve/resolved-dns-search-domain.c
+++ b/src/resolve/resolved-dns-search-domain.c
@@ -1,5 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#include "sd-json.h"
+
#include "alloc-util.h"
#include "dns-domain.h"
#include "resolved-dns-search-domain.h"
@@ -197,3 +199,21 @@ int dns_search_domain_find(DnsSearchDomain *first, const char *name, DnsSearchDo
*ret = NULL;
return 0;
}
+
+int dns_search_domain_dump_to_json(DnsSearchDomain *domain, sd_json_variant **ret) {
+ int ifindex = 0;
+
+ assert(domain);
+ assert(ret);
+
+ if (domain->type == DNS_SEARCH_DOMAIN_LINK) {
+ assert(domain->link);
+ ifindex = domain->link->ifindex;
+ }
+
+ return sd_json_buildo(
+ ret,
+ SD_JSON_BUILD_PAIR_STRING("name", domain->name),
+ SD_JSON_BUILD_PAIR_BOOLEAN("routeOnly", domain->route_only),
+ SD_JSON_BUILD_PAIR_CONDITION(ifindex > 0, "ifindex", SD_JSON_BUILD_UNSIGNED(ifindex)));
+}
diff --git a/src/resolve/resolved-dns-search-domain.h b/src/resolve/resolved-dns-search-domain.h
index f0d96aca37..3e5229c12f 100644
--- a/src/resolve/resolved-dns-search-domain.h
+++ b/src/resolve/resolved-dns-search-domain.h
@@ -1,6 +1,8 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
+#include "sd-json.h"
+
#include "list.h"
#include "macro.h"
@@ -54,3 +56,5 @@ static inline const char* DNS_SEARCH_DOMAIN_NAME(DnsSearchDomain *d) {
}
DEFINE_TRIVIAL_CLEANUP_FUNC(DnsSearchDomain*, dns_search_domain_unref);
+
+int dns_search_domain_dump_to_json(DnsSearchDomain *domain, sd_json_variant **ret);
diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c
index 1702866a14..54d0d32ec5 100644
--- a/src/resolve/resolved-dns-server.c
+++ b/src/resolve/resolved-dns-server.c
@@ -7,6 +7,7 @@
#include "alloc-util.h"
#include "errno-util.h"
#include "fd-util.h"
+#include "json-util.h"
#include "resolved-bus.h"
#include "resolved-dns-server.h"
#include "resolved-dns-stub.h"
@@ -881,6 +882,7 @@ DnsServer *manager_set_dns_server(Manager *m, DnsServer *s) {
dns_cache_flush(&m->unicast_scope->cache);
(void) manager_send_changed(m, "CurrentDNSServer");
+ (void) manager_send_dns_configuration_changed(m, NULL, /* reset= */ false);
return s;
}
@@ -1180,3 +1182,28 @@ void dns_server_reset_accessible_all(DnsServer *first) {
LIST_FOREACH(servers, s, first)
dns_server_reset_accessible(s);
}
+
+int dns_server_dump_configuration_to_json(DnsServer *server, sd_json_variant **ret) {
+ bool accessible = false;
+ int ifindex, r;
+
+ assert(server);
+ assert(ret);
+
+ ifindex = dns_server_ifindex(server);
+
+ r = dns_server_is_accessible(server);
+ if (r < 0)
+ log_debug_errno(r, "Failed to check if %s is accessible, assume not: %m", dns_server_string_full(server));
+ else
+ accessible = r;
+
+ return sd_json_buildo(
+ ret,
+ JSON_BUILD_PAIR_IN_ADDR("address", &server->address, server->family),
+ SD_JSON_BUILD_PAIR_INTEGER("family", server->family),
+ SD_JSON_BUILD_PAIR_UNSIGNED("port", dns_server_port(server)),
+ SD_JSON_BUILD_PAIR_CONDITION(ifindex > 0, "ifindex", SD_JSON_BUILD_UNSIGNED(ifindex)),
+ JSON_BUILD_PAIR_STRING_NON_EMPTY("name", server->server_name),
+ SD_JSON_BUILD_PAIR_BOOLEAN("accessible", accessible));
+}
diff --git a/src/resolve/resolved-dns-server.h b/src/resolve/resolved-dns-server.h
index 8915b87e95..0f066b15b9 100644
--- a/src/resolve/resolved-dns-server.h
+++ b/src/resolve/resolved-dns-server.h
@@ -190,6 +190,7 @@ static inline bool dns_server_is_fallback(DnsServer *s) {
}
int dns_server_dump_state_to_json(DnsServer *server, sd_json_variant **ret);
+int dns_server_dump_configuration_to_json(DnsServer *server, sd_json_variant **ret);
int dns_server_is_accessible(DnsServer *s);
static inline void dns_server_reset_accessible(DnsServer *s) {
diff --git a/src/resolve/resolved-link-bus.c b/src/resolve/resolved-link-bus.c
index b0c4b833b5..77d2663e4f 100644
--- a/src/resolve/resolved-link-bus.c
+++ b/src/resolve/resolved-link-bus.c
@@ -272,6 +272,7 @@ static int bus_link_method_set_dns_servers_internal(sd_bus_message *message, voi
(void) link_save_user(l);
(void) manager_write_resolv_conf(l->manager);
(void) manager_send_changed(l->manager, "DNS");
+ (void) manager_send_dns_configuration_changed(l->manager, l, /* reset= */ true);
if (j)
log_link_info(l, "Bus client set DNS server list to: %s", j);
@@ -751,6 +752,7 @@ int bus_link_method_revert(sd_bus_message *message, void *userdata, sd_bus_error
(void) link_save_user(l);
(void) manager_write_resolv_conf(l->manager);
(void) manager_send_changed(l->manager, "DNS");
+ (void) manager_send_dns_configuration_changed(l->manager, l, /* reset= */ true);
manager_llmnr_maybe_stop(l->manager);
manager_mdns_maybe_stop(l->manager);
diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c
index 883bc09701..e374978691 100644
--- a/src/resolve/resolved-manager.c
+++ b/src/resolve/resolved-manager.c
@@ -22,6 +22,7 @@
#include "idn-util.h"
#include "io-util.h"
#include "iovec-util.h"
+#include "json-util.h"
#include "memstream-util.h"
#include "missing_network.h"
#include "missing_socket.h"
@@ -108,6 +109,11 @@ static int manager_process_link(sd_netlink *rtnl, sd_netlink_message *mm, void *
/* Now check all the links, and if mDNS/llmr are disabled everywhere, stop them globally too. */
manager_llmnr_maybe_stop(m);
manager_mdns_maybe_stop(m);
+
+ /* The accessible flag on link DNS servers will have been reset by
+ * link_update(). Just reset the global DNS servers. */
+ (void) manager_send_dns_configuration_changed(m, NULL, /* reset= */ true);
+
return 0;
fail:
@@ -192,6 +198,8 @@ static int manager_process_address(sd_netlink *rtnl, sd_netlink_message *mm, voi
break;
}
+ (void) manager_send_dns_configuration_changed(m, l, /* reset= */ true);
+
return 0;
fail:
@@ -199,6 +207,38 @@ fail:
return 0;
}
+static int manager_process_route(sd_netlink *rtnl, sd_netlink_message *mm, void *userdata) {
+ Manager *m = ASSERT_PTR(userdata);
+ Link *l = NULL;
+ uint16_t type;
+ uint32_t ifindex = 0;
+ int r;
+
+ assert(rtnl);
+ assert(mm);
+
+ r = sd_netlink_message_get_type(mm, &type);
+ if (r < 0) {
+ log_warning_errno(r, "Failed not get message type, ignoring: %m");
+ return 0;
+ }
+
+ if (!IN_SET(type, RTM_NEWROUTE, RTM_DELROUTE)) {
+ log_warning("Unexpected message type %u when processing route, ignoring.", type);
+ return 0;
+ }
+
+ r = sd_netlink_message_read_u32(mm, RTA_OIF, &ifindex);
+ if (r < 0)
+ log_full_errno(r == -ENODATA ? LOG_DEBUG : LOG_WARNING, r, "Failed to get route ifindex, ignoring: %m");
+ else
+ l = hashmap_get(m->links, INT_TO_PTR(ifindex));
+
+ (void) manager_send_dns_configuration_changed(m, l, /* reset= */ true);
+
+ return 0;
+}
+
static int manager_rtnl_listen(Manager *m) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
int r;
@@ -289,6 +329,7 @@ static int on_network_event(sd_event_source *s, int fd, uint32_t revents, void *
(void) manager_write_resolv_conf(m);
(void) manager_send_changed(m, "DNS");
+ (void) manager_send_dns_configuration_changed(m, NULL, /* reset= */ true);
/* Now check all the links, and if mDNS/llmr are disabled everywhere, stop them globally too. */
manager_llmnr_maybe_stop(m);
@@ -808,10 +849,14 @@ Manager *manager_free(Manager *m) {
sd_event_source_unref(m->network_event_source);
sd_network_monitor_unref(m->network_monitor);
+ sd_netlink_slot_unref(m->netlink_new_route_slot);
+ sd_netlink_slot_unref(m->netlink_del_route_slot);
sd_netlink_unref(m->rtnl);
sd_event_source_unref(m->rtnl_event_source);
sd_event_source_unref(m->clock_change_event_source);
+ sd_json_variant_unref(m->dns_configuration_json);
+
manager_llmnr_stop(m);
manager_mdns_stop(m);
manager_dns_stub_stop(m);
@@ -1938,3 +1983,181 @@ void dns_manager_reset_statistics(Manager *m) {
m->n_failure_responses_served_stale_total = 0;
zero(m->n_dnssec_verdict);
}
+
+static int dns_configuration_json_append(
+ const char *ifname,
+ int ifindex,
+ int default_route,
+ DnsServer *current_dns_server,
+ DnsServer *dns_servers,
+ DnsSearchDomain *search_domains,
+ sd_json_variant **configuration) {
+
+ _cleanup_(sd_json_variant_unrefp) sd_json_variant *dns_servers_json = NULL,
+ *search_domains_json = NULL,
+ *current_dns_server_json = NULL;
+ int r;
+
+ assert(configuration);
+
+ if (dns_servers) {
+ r = sd_json_variant_new_array(&dns_servers_json, NULL, 0);
+ if (r < 0)
+ return r;
+ }
+
+ if (search_domains) {
+ r = sd_json_variant_new_array(&search_domains_json, NULL, 0);
+ if (r < 0)
+ return r;
+ }
+
+ if (current_dns_server) {
+ r = dns_server_dump_configuration_to_json(current_dns_server, ¤t_dns_server_json);
+ if (r < 0)
+ return r;
+ }
+
+ LIST_FOREACH(servers, s, dns_servers) {
+ _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
+
+ assert(dns_servers_json);
+
+ r = dns_server_dump_configuration_to_json(s, &v);
+ if (r < 0)
+ return r;
+
+ r = sd_json_variant_append_array(&dns_servers_json, v);
+ if (r < 0)
+ return r;
+ }
+
+ LIST_FOREACH(domains, d, search_domains) {
+ _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
+
+ assert(search_domains_json);
+
+ r = dns_search_domain_dump_to_json(d, &v);
+ if (r < 0)
+ return r;
+
+ r = sd_json_variant_append_array(&search_domains_json, v);
+ if (r < 0)
+ return r;
+ }
+
+ return sd_json_variant_append_arraybo(
+ configuration,
+ JSON_BUILD_PAIR_STRING_NON_EMPTY("ifname", ifname),
+ SD_JSON_BUILD_PAIR_CONDITION(ifindex > 0, "ifindex", SD_JSON_BUILD_UNSIGNED(ifindex)),
+ SD_JSON_BUILD_PAIR_CONDITION(ifindex > 0, "defaultRoute", SD_JSON_BUILD_BOOLEAN(default_route > 0)),
+ JSON_BUILD_PAIR_VARIANT_NON_NULL("currentServer", current_dns_server_json),
+ JSON_BUILD_PAIR_VARIANT_NON_NULL("servers", dns_servers_json),
+ JSON_BUILD_PAIR_VARIANT_NON_NULL("searchDomains", search_domains_json));
+}
+
+int manager_dump_dns_configuration_json(Manager *m, sd_json_variant **ret) {
+ _cleanup_(sd_json_variant_unrefp) sd_json_variant *configuration = NULL;
+ Link *l;
+ int r;
+
+ assert(m);
+ assert(ret);
+
+ /* Global DNS configuration */
+ r = dns_configuration_json_append(
+ /* ifname = */ NULL,
+ /* ifindex = */ 0,
+ /* default_route = */ 0,
+ manager_get_dns_server(m),
+ m->dns_servers,
+ m->search_domains,
+ &configuration);
+ if (r < 0)
+ return r;
+
+ /* Append configuration for each link */
+ HASHMAP_FOREACH(l, m->links) {
+ r = dns_configuration_json_append(
+ l->ifname,
+ l->ifindex,
+ link_get_default_route(l),
+ link_get_dns_server(l),
+ l->dns_servers,
+ l->search_domains,
+ &configuration);
+ if (r < 0)
+ return r;
+ }
+
+ return sd_json_buildo(ret, SD_JSON_BUILD_PAIR_VARIANT("configuration", configuration));
+}
+
+int manager_send_dns_configuration_changed(Manager *m, Link *l, bool reset) {
+ _cleanup_(sd_json_variant_unrefp) sd_json_variant *configuration = NULL;
+ int r;
+
+ assert(m);
+
+ if (set_isempty(m->varlink_dns_configuration_subscription))
+ return 0;
+
+ if (reset) {
+ dns_server_reset_accessible_all(m->dns_servers);
+
+ if (l)
+ dns_server_reset_accessible_all(l->dns_servers);
+ }
+
+ r = manager_dump_dns_configuration_json(m, &configuration);
+ if (r < 0)
+ return log_warning_errno(r, "Failed to dump DNS configuration json: %m");
+
+ if (sd_json_variant_equal(configuration, m->dns_configuration_json))
+ return 0;
+
+ JSON_VARIANT_REPLACE(m->dns_configuration_json, TAKE_PTR(configuration));
+
+ r = varlink_many_notify(m->varlink_dns_configuration_subscription, m->dns_configuration_json);
+ if (r < 0)
+ return log_warning_errno(r, "Failed to send DNS configuration event: %m");
+
+ return 0;
+}
+
+int manager_start_dns_configuration_monitor(Manager *m) {
+ Link *l;
+ int r;
+
+ assert(m);
+ assert(!m->dns_configuration_json);
+ assert(!m->netlink_new_route_slot);
+ assert(!m->netlink_del_route_slot);
+
+ dns_server_reset_accessible_all(m->dns_servers);
+
+ HASHMAP_FOREACH(l, m->links)
+ dns_server_reset_accessible_all(l->dns_servers);
+
+ r = manager_dump_dns_configuration_json(m, &m->dns_configuration_json);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_add_match(m->rtnl, &m->netlink_new_route_slot, RTM_NEWROUTE, manager_process_route, NULL, m, "resolve-NEWROUTE");
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_add_match(m->rtnl, &m->netlink_del_route_slot, RTM_DELROUTE, manager_process_route, NULL, m, "resolve-DELROUTE");
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
+void manager_stop_dns_configuration_monitor(Manager *m) {
+ assert(m);
+
+ m->dns_configuration_json = sd_json_variant_unref(m->dns_configuration_json);
+ m->netlink_new_route_slot = sd_netlink_slot_unref(m->netlink_new_route_slot);
+ m->netlink_del_route_slot = sd_netlink_slot_unref(m->netlink_del_route_slot);
+}
diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h
index 5d870111d1..3481a8836b 100644
--- a/src/resolve/resolved-manager.h
+++ b/src/resolve/resolved-manager.h
@@ -153,6 +153,12 @@ struct Manager {
sd_varlink_server *varlink_monitor_server;
Set *varlink_query_results_subscription;
+ Set *varlink_dns_configuration_subscription;
+
+ sd_json_variant *dns_configuration_json;
+
+ sd_netlink_slot *netlink_new_route_slot;
+ sd_netlink_slot *netlink_del_route_slot;
sd_event_source *clock_change_event_source;
@@ -225,3 +231,9 @@ int socket_disable_pmtud(int fd, int af);
int dns_manager_dump_statistics_json(Manager *m, sd_json_variant **ret);
void dns_manager_reset_statistics(Manager *m);
+
+int manager_dump_dns_configuration_json(Manager *m, sd_json_variant **ret);
+int manager_send_dns_configuration_changed(Manager *m, Link *l, bool reset);
+
+int manager_start_dns_configuration_monitor(Manager *m);
+void manager_stop_dns_configuration_monitor(Manager *m);
diff --git a/src/resolve/resolved-varlink.c b/src/resolve/resolved-varlink.c
index fd2fc58853..02e00eef7d 100644
--- a/src/resolve/resolved-varlink.c
+++ b/src/resolve/resolved-varlink.c
@@ -127,15 +127,25 @@ static void vl_on_disconnect(sd_varlink_server *s, sd_varlink *link, void *userd
static void vl_on_notification_disconnect(sd_varlink_server *s, sd_varlink *link, void *userdata) {
Manager *m = ASSERT_PTR(userdata);
+ sd_varlink *removed_link = NULL;
assert(s);
assert(link);
- sd_varlink *removed_link = set_remove(m->varlink_query_results_subscription, link);
+ removed_link = set_remove(m->varlink_query_results_subscription, link);
if (removed_link) {
sd_varlink_unref(removed_link);
log_debug("%u query result monitor clients remain active", set_size(m->varlink_query_results_subscription));
}
+
+ removed_link = set_remove(m->varlink_dns_configuration_subscription, link);
+ if (removed_link) {
+ sd_varlink_unref(removed_link);
+ log_debug("%u DNS monitor clients remain active", set_size(m->varlink_dns_configuration_subscription));
+
+ if (set_isempty(m->varlink_dns_configuration_subscription))
+ manager_stop_dns_configuration_monitor(m);
+ }
}
static bool validate_and_mangle_flags(
@@ -1354,6 +1364,45 @@ static int vl_method_reset_statistics(sd_varlink *link, sd_json_variant *paramet
return sd_varlink_replyb(link, SD_JSON_BUILD_EMPTY_OBJECT);
}
+static int vl_method_subscribe_dns_configuration(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
+ Manager *m = ASSERT_PTR(sd_varlink_get_userdata(ASSERT_PTR(link)));
+ int r;
+
+ /* if the client didn't set the more flag, it is using us incorrectly */
+ if (!FLAGS_SET(flags, SD_VARLINK_METHOD_MORE))
+ return sd_varlink_error(link, SD_VARLINK_ERROR_EXPECTED_MORE, NULL);
+
+ r = verify_polkit(link, parameters, "org.freedesktop.resolve1.subscribe-dns-configuration");
+ if (r <= 0)
+ return r;
+
+ if (set_isempty(m->varlink_dns_configuration_subscription)) {
+ r = manager_start_dns_configuration_monitor(m);
+ if (r < 0)
+ return log_error_errno(r, "Failed to start DNS configuration monitor: %m");
+ }
+
+ r = sd_varlink_notify(link, m->dns_configuration_json);
+ if (r < 0)
+ goto fail;
+
+ r = set_ensure_put(&m->varlink_dns_configuration_subscription, NULL, link);
+ if (r < 0)
+ goto fail;
+ sd_varlink_ref(link);
+
+ log_debug("%u clients now attached for link configuration varlink notifications",
+ set_size(m->varlink_dns_configuration_subscription));
+
+ return 1;
+fail:
+ if (set_isempty(m->varlink_dns_configuration_subscription))
+ manager_stop_dns_configuration_monitor(m);
+
+
+ return log_debug_errno(r, "Failed to subscribe client to DNS configuration monitor: %m");
+}
+
static int varlink_monitor_server_init(Manager *m) {
_cleanup_(sd_varlink_server_unrefp) sd_varlink_server *server = NULL;
int r;
@@ -1377,7 +1426,8 @@ static int varlink_monitor_server_init(Manager *m) {
"io.systemd.Resolve.Monitor.DumpCache", vl_method_dump_cache,
"io.systemd.Resolve.Monitor.DumpServerState", vl_method_dump_server_state,
"io.systemd.Resolve.Monitor.DumpStatistics", vl_method_dump_statistics,
- "io.systemd.Resolve.Monitor.ResetStatistics", vl_method_reset_statistics);
+ "io.systemd.Resolve.Monitor.ResetStatistics", vl_method_reset_statistics,
+ "io.systemd.Resolve.Monitor.SubscribeDNSConfiguration", vl_method_subscribe_dns_configuration);
if (r < 0)
return log_error_errno(r, "Failed to register varlink methods: %m");
diff --git a/src/shared/varlink-io.systemd.Resolve.Monitor.c b/src/shared/varlink-io.systemd.Resolve.Monitor.c
index bc8907ddbe..18d4eafefa 100644
--- a/src/shared/varlink-io.systemd.Resolve.Monitor.c
+++ b/src/shared/varlink-io.systemd.Resolve.Monitor.c
@@ -112,6 +112,52 @@ static SD_VARLINK_DEFINE_METHOD(
ResetStatistics,
VARLINK_DEFINE_POLKIT_INPUT);
+static SD_VARLINK_DEFINE_STRUCT_TYPE(
+ DNSServer,
+ SD_VARLINK_FIELD_COMMENT("IPv4 or IPv6 address of the server."),
+ SD_VARLINK_DEFINE_FIELD(address, SD_VARLINK_INT, SD_VARLINK_ARRAY),
+ SD_VARLINK_FIELD_COMMENT("Address family of the server, one of AF_INET or AF_INET6."),
+ SD_VARLINK_DEFINE_FIELD(family, SD_VARLINK_INT, 0),
+ SD_VARLINK_FIELD_COMMENT("Port number of the server."),
+ SD_VARLINK_DEFINE_FIELD(port, SD_VARLINK_INT, 0),
+ SD_VARLINK_FIELD_COMMENT("Interface index for which this server is configured."),
+ SD_VARLINK_DEFINE_FIELD(ifindex, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
+ SD_VARLINK_FIELD_COMMENT("Server Name Indication (SNI) of the server."),
+ SD_VARLINK_DEFINE_FIELD(name, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
+ SD_VARLINK_FIELD_COMMENT("Indicates if the DNS server is accessible or not."),
+ SD_VARLINK_DEFINE_FIELD(accessible, SD_VARLINK_BOOL, 0));
+
+static SD_VARLINK_DEFINE_STRUCT_TYPE(
+ SearchDomain,
+ SD_VARLINK_FIELD_COMMENT("Domain name."),
+ SD_VARLINK_DEFINE_FIELD(name, SD_VARLINK_STRING, 0),
+ SD_VARLINK_FIELD_COMMENT("Indicates whether or not this is a routing-only domain."),
+ SD_VARLINK_DEFINE_FIELD(routeOnly, SD_VARLINK_BOOL, 0),
+ SD_VARLINK_FIELD_COMMENT("Interface index for which this search domain is configured."),
+ SD_VARLINK_DEFINE_FIELD(ifindex, SD_VARLINK_INT, SD_VARLINK_NULLABLE));
+
+static SD_VARLINK_DEFINE_STRUCT_TYPE(
+ DNSConfiguration,
+ SD_VARLINK_FIELD_COMMENT("Interface name, if any, associated with this configuration. Empty for global configuration."),
+ SD_VARLINK_DEFINE_FIELD(ifname, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
+ SD_VARLINK_FIELD_COMMENT("Interface index, if any, associated with this configuration. Empty for global configuration."),
+ SD_VARLINK_DEFINE_FIELD(ifindex, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
+ SD_VARLINK_FIELD_COMMENT("Indicates whether or not this link's DNS servers will be used for resolving domain names that do not match any link's configured domains."),
+ SD_VARLINK_DEFINE_FIELD(defaultRoute, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
+ SD_VARLINK_FIELD_COMMENT("DNS server currently selected to use for lookups."),
+ SD_VARLINK_DEFINE_FIELD_BY_TYPE(currentServer, DNSServer, SD_VARLINK_NULLABLE),
+ SD_VARLINK_FIELD_COMMENT("Array of configured DNS servers."),
+ SD_VARLINK_DEFINE_FIELD_BY_TYPE(servers, DNSServer, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
+ SD_VARLINK_FIELD_COMMENT("Array of configured search domains."),
+ SD_VARLINK_DEFINE_FIELD_BY_TYPE(searchDomains, SearchDomain, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE));
+
+static SD_VARLINK_DEFINE_METHOD_FULL(
+ SubscribeDNSConfiguration,
+ SD_VARLINK_REQUIRES_MORE,
+ SD_VARLINK_DEFINE_INPUT(allowInteractiveAuthentication, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
+ SD_VARLINK_FIELD_COMMENT("The current global and per-interface DNS configurations"),
+ SD_VARLINK_DEFINE_OUTPUT_BY_TYPE(configuration, DNSConfiguration, SD_VARLINK_ARRAY));
+
SD_VARLINK_DEFINE_INTERFACE(
io_systemd_Resolve_Monitor,
"io.systemd.Resolve.Monitor",
@@ -129,4 +175,12 @@ SD_VARLINK_DEFINE_INTERFACE(
&vl_type_TransactionStatistics,
&vl_type_CacheStatistics,
&vl_type_DnssecStatistics,
- &vl_type_ServerState);
+ &vl_type_ServerState,
+ SD_VARLINK_SYMBOL_COMMENT("Encapsulates a DNS server address specification."),
+ &vl_type_DNSServer,
+ SD_VARLINK_SYMBOL_COMMENT("Encapsulates a search domain specification."),
+ &vl_type_SearchDomain,
+ SD_VARLINK_SYMBOL_COMMENT("Encapsulates a global or per-link DNS configuration, including configured DNS servers, search domains, and more."),
+ &vl_type_DNSConfiguration,
+ SD_VARLINK_SYMBOL_COMMENT("Sends the complete global and per-link DNS configurations when any changes are made to them. The current configurations are given immediately when this method is invoked."),
+ &vl_method_SubscribeDNSConfiguration);