#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"
#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"
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);
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;
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;
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) },
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);
+static int status_global(DNSConfiguration *configuration, StatusMode mode, bool *empty_line) {
+ _cleanup_(table_unrefp) Table *table = NULL;
int r;
- assert(bus);
- assert(member);
- assert(m);
+ assert(configuration);
+ assert(configuration->ifindex == 0);
+ assert(!configuration->delegate);
+ assert(empty_line);
- r = sd_bus_message_enter_container(m, 'a', FLAGS_SET(flags, READ_DNS_EXTENDED) ? "(iiayqs)" : "(iiay)");
- if (r < 0)
- return r;
+ pager_open(arg_pager_flags);
- for (;;) {
- _cleanup_free_ char *pretty = NULL;
+ switch (mode) {
- r = read_dns_server_one(m, flags, &pretty);
+ 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;
- if (r == 0)
- break;
- if (isempty(pretty))
- continue;
+ return status_print_strv_global(dns_servers);
+ }
- r = strv_consume(l, TAKE_PTR(pretty));
+ 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;
- }
-
- 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 = {};
- _cleanup_(table_unrefp) Table *table = NULL;
- int r;
-
- assert(bus);
- 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_DOMAIN:
- return status_print_strv_global(global_info.domains);
+ 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;
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",
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, "DNS Servers", dns_servers);
+ 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;
+
+ r = dump_list(table, "Fallback DNS Servers", fallback_dns_servers);
if (r < 0)
return r;
- r = dump_list(table, "Fallback DNS Servers", global_info.fallback_dns_ex ?: global_info.fallback_dns);
+ _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", global_info.domains);
+ r = dump_list(table, "DNS Domain", search_domains);
if (r < 0)
return r;
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;