diff --git a/src/resolve/resolv.conf b/src/resolve/resolv.conf index 34a6b9257f..ffc460dbf2 100644 --- a/src/resolve/resolv.conf +++ b/src/resolve/resolv.conf @@ -4,7 +4,7 @@ # internal DNS stub resolver of systemd-resolved. This file lists no search # domains. # -# Run "systemd-resolve --status" to see details about the uplink DNS servers +# Run "resolvectl status" to see details about the uplink DNS servers # currently in use. # # Third party programs must not access this file directly, but only through the diff --git a/src/resolve/resolvconf-compat.c b/src/resolve/resolvconf-compat.c index a6b327e2f0..d7e68003e6 100644 --- a/src/resolve/resolvconf-compat.c +++ b/src/resolve/resolvconf-compat.c @@ -27,7 +27,7 @@ static void resolvconf_help(void) { " -f Ignore if specified interface does not exist\n" " -x Send DNS traffic preferably over this interface\n" "\n" - "This is a compatibility alias for the systemd-resolve(1) tool, providing native\n" + "This is a compatibility alias for the resolvectl(1) tool, providing native\n" "command line compatibility with the resolvconf(8) tool of various Linux\n" "distributions and BSD systems. Some options supported by other implementations\n" "are not supported and are ignored: -m, -p. Various options supported by other\n" diff --git a/src/resolve/resolvectl.c b/src/resolve/resolvectl.c index 0b58e9b57f..10c8fb5fb6 100644 --- a/src/resolve/resolvectl.c +++ b/src/resolve/resolvectl.c @@ -1169,6 +1169,66 @@ static int reset_server_features(int argc, char **argv, void *userdata) { return 0; } +static int read_dns_server_one(sd_bus_message *m, bool with_ifindex, char **ret) { + _cleanup_free_ char *pretty = NULL; + int ifindex, family, r; + const void *a; + size_t sz; + + assert(m); + assert(ret); + + r = sd_bus_message_enter_container(m, 'r', with_ifindex ? "iiay" : "iay"); + if (r <= 0) + return r; + + if (with_ifindex) { + r = sd_bus_message_read(m, "i", &ifindex); + if (r < 0) + return r; + } + + r = sd_bus_message_read(m, "i", &family); + if (r < 0) + return r; + + r = sd_bus_message_read_array(m, 'y', &a, &sz); + if (r < 0) + return r; + + r = sd_bus_message_exit_container(m); + if (r < 0) + return r; + + if (with_ifindex && ifindex != 0) { + /* only show the global ones here */ + *ret = NULL; + return 1; + } + + if (!IN_SET(family, AF_INET, AF_INET6)) { + log_debug("Unexpected family, ignoring: %i", family); + + *ret = NULL; + return 1; + } + + if (sz != FAMILY_ADDRESS_SIZE(family)) { + log_debug("Address size mismatch, ignoring."); + + *ret = NULL; + return 1; + } + + r = in_addr_to_string(family, a, &pretty); + if (r < 0) + return r; + + *ret = TAKE_PTR(pretty); + + return 1; +} + static int map_link_dns_servers(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) { char ***l = userdata; int r; @@ -1183,42 +1243,16 @@ static int map_link_dns_servers(sd_bus *bus, const char *member, sd_bus_message return r; for (;;) { - const void *a; - char *pretty; - int family; - size_t sz; + char *pretty = NULL; - r = sd_bus_message_enter_container(m, 'r', "iay"); + r = read_dns_server_one(m, false, &pretty); if (r < 0) return r; if (r == 0) break; - r = sd_bus_message_read(m, "i", &family); - if (r < 0) - return r; - - r = sd_bus_message_read_array(m, 'y', &a, &sz); - if (r < 0) - return r; - - r = sd_bus_message_exit_container(m); - if (r < 0) - return r; - - if (!IN_SET(family, AF_INET, AF_INET6)) { - log_debug("Unexpected family, ignoring."); + if (isempty(pretty)) continue; - } - - if (sz != FAMILY_ADDRESS_SIZE(family)) { - log_debug("Address size mismatch, ignoring."); - continue; - } - - r = in_addr_to_string(family, a, &pretty); - if (r < 0) - return r; r = strv_consume(l, pretty); if (r < 0) @@ -1232,6 +1266,46 @@ static int map_link_dns_servers(sd_bus *bus, const char *member, sd_bus_message return 0; } +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, false, 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; + 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 = strappend("~", domain); + else + str = strdup(domain); + if (!str) + return -ENOMEM; + + *ret = TAKE_PTR(str); + + return 1; +} + static int map_link_domains(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) { char ***l = userdata; int r; @@ -1246,22 +1320,16 @@ static int map_link_domains(sd_bus *bus, const char *member, sd_bus_message *m, return r; for (;;) { - const char *domain; - int route_only; - char *pretty; + char *pretty = NULL; - r = sd_bus_message_read(m, "(sb)", &domain, &route_only); + r = read_domain_one(m, false, &pretty); if (r < 0) return r; if (r == 0) break; - if (route_only) - pretty = strappend("~", domain); - else - pretty = strdup(domain); - if (!pretty) - return -ENOMEM; + if (isempty(pretty)) + continue; r = strv_consume(l, pretty); if (r < 0) @@ -1296,6 +1364,7 @@ static int status_ifindex(sd_bus *bus, int ifindex, const char *name, StatusMode const char *llmnr; const char *mdns; const char *dnssec; + char *current_dns; char **dns; char **domains; char **ntas; @@ -1303,14 +1372,15 @@ static int status_ifindex(sd_bus *bus, int ifindex, const char *name, StatusMode } link_info = {}; static const struct bus_properties_map property_map[] = { - { "ScopesMask", "t", NULL, offsetof(struct link_info, scopes_mask) }, - { "DNS", "a(iay)", map_link_dns_servers, offsetof(struct link_info, dns) }, - { "Domains", "a(sb)", map_link_domains, offsetof(struct link_info, domains) }, - { "LLMNR", "s", NULL, offsetof(struct link_info, llmnr) }, - { "MulticastDNS", "s", NULL, offsetof(struct link_info, mdns) }, - { "DNSSEC", "s", NULL, offsetof(struct link_info, dnssec) }, - { "DNSSECNegativeTrustAnchors", "as", NULL, offsetof(struct link_info, ntas) }, - { "DNSSECSupported", "b", NULL, offsetof(struct link_info, dnssec_supported) }, + { "ScopesMask", "t", NULL, offsetof(struct link_info, scopes_mask) }, + { "DNS", "a(iay)", map_link_dns_servers, offsetof(struct link_info, dns) }, + { "CurrentDNSServer", "(iay)", map_link_current_dns_server, offsetof(struct link_info, current_dns) }, + { "Domains", "a(sb)", map_link_domains, offsetof(struct link_info, domains) }, + { "LLMNR", "s", NULL, offsetof(struct link_info, llmnr) }, + { "MulticastDNS", "s", NULL, offsetof(struct link_info, mdns) }, + { "DNSSEC", "s", NULL, offsetof(struct link_info, dnssec) }, + { "DNSSECNegativeTrustAnchors", "as", NULL, offsetof(struct link_info, ntas) }, + { "DNSSECSupported", "b", NULL, offsetof(struct link_info, dnssec_supported) }, {} }; @@ -1414,11 +1484,13 @@ static int status_ifindex(sd_bus *bus, int ifindex, const char *name, StatusMode printf(" LLMNR setting: %s\n" "MulticastDNS setting: %s\n" " DNSSEC setting: %s\n" - " DNSSEC supported: %s\n", + " DNSSEC supported: %s\n" + " Current DNS Server: %s\n", strna(link_info.llmnr), strna(link_info.mdns), strna(link_info.dnssec), - yes_no(link_info.dnssec_supported)); + yes_no(link_info.dnssec_supported), + strna(link_info.current_dns)); STRV_FOREACH(i, link_info.dns) { printf(" %s %s\n", @@ -1444,6 +1516,7 @@ static int status_ifindex(sd_bus *bus, int ifindex, const char *name, StatusMode r = 0; finish: + free(link_info.current_dns); strv_free(link_info.dns); strv_free(link_info.domains); strv_free(link_info.ntas); @@ -1464,46 +1537,17 @@ static int map_global_dns_servers(sd_bus *bus, const char *member, sd_bus_messag return r; for (;;) { - const void *a; - char *pretty; - int family, ifindex; - size_t sz; + char *pretty = NULL; - r = sd_bus_message_enter_container(m, 'r', "iiay"); + r = read_dns_server_one(m, true, &pretty); if (r < 0) return r; if (r == 0) break; - r = sd_bus_message_read(m, "ii", &ifindex, &family); - if (r < 0) - return r; - - r = sd_bus_message_read_array(m, 'y', &a, &sz); - if (r < 0) - return r; - - r = sd_bus_message_exit_container(m); - if (r < 0) - return r; - - if (ifindex != 0) /* only show the global ones here */ + if (isempty(pretty)) continue; - if (!IN_SET(family, AF_INET, AF_INET6)) { - log_debug("Unexpected family, ignoring."); - continue; - } - - if (sz != FAMILY_ADDRESS_SIZE(family)) { - log_debug("Address size mismatch, ignoring."); - continue; - } - - r = in_addr_to_string(family, a, &pretty); - if (r < 0) - return r; - r = strv_consume(l, pretty); if (r < 0) return r; @@ -1516,6 +1560,13 @@ static int map_global_dns_servers(sd_bus *bus, const char *member, sd_bus_messag return 0; } +static int map_global_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, true, userdata); +} + static int map_global_domains(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) { char ***l = userdata; int r; @@ -1530,26 +1581,17 @@ static int map_global_domains(sd_bus *bus, const char *member, sd_bus_message *m return r; for (;;) { - const char *domain; - int route_only, ifindex; - char *pretty; + char *pretty = NULL; - r = sd_bus_message_read(m, "(isb)", &ifindex, &domain, &route_only); + r = read_domain_one(m, true, &pretty); if (r < 0) return r; if (r == 0) break; - if (ifindex != 0) /* only show the global ones here */ + if (isempty(pretty)) continue; - if (route_only) - pretty = strappend("~", domain); - else - pretty = strdup(domain); - if (!pretty) - return -ENOMEM; - r = strv_consume(l, pretty); if (r < 0) return r; @@ -1578,6 +1620,7 @@ static int status_print_strv_global(char **p) { static int status_global(sd_bus *bus, StatusMode mode, bool *empty_line) { struct global_info { + char *current_dns; char **dns; char **domains; char **ntas; @@ -1588,13 +1631,14 @@ static int status_global(sd_bus *bus, StatusMode mode, bool *empty_line) { } global_info = {}; static const struct bus_properties_map property_map[] = { - { "DNS", "a(iiay)", map_global_dns_servers, offsetof(struct global_info, dns) }, - { "Domains", "a(isb)", map_global_domains, offsetof(struct global_info, domains) }, - { "DNSSECNegativeTrustAnchors", "as", NULL, offsetof(struct global_info, ntas) }, - { "LLMNR", "s", NULL, offsetof(struct global_info, llmnr) }, - { "MulticastDNS", "s", NULL, offsetof(struct global_info, mdns) }, - { "DNSSEC", "s", NULL, offsetof(struct global_info, dnssec) }, - { "DNSSECSupported", "b", NULL, offsetof(struct global_info, dnssec_supported) }, + { "DNS", "a(iiay)", map_global_dns_servers, offsetof(struct global_info, dns) }, + { "CurrentDNSServer", "(iiay)", map_global_current_dns_server, offsetof(struct global_info, current_dns) }, + { "Domains", "a(isb)", map_global_domains, offsetof(struct global_info, domains) }, + { "DNSSECNegativeTrustAnchors", "as", NULL, offsetof(struct global_info, ntas) }, + { "LLMNR", "s", NULL, offsetof(struct global_info, llmnr) }, + { "MulticastDNS", "s", NULL, offsetof(struct global_info, mdns) }, + { "DNSSEC", "s", NULL, offsetof(struct global_info, dnssec) }, + { "DNSSECSupported", "b", NULL, offsetof(struct global_info, dnssec_supported) }, {} }; @@ -1665,11 +1709,13 @@ static int status_global(sd_bus *bus, StatusMode mode, bool *empty_line) { printf(" LLMNR setting: %s\n" "MulticastDNS setting: %s\n" " DNSSEC setting: %s\n" - " DNSSEC supported: %s\n", + " DNSSEC supported: %s\n" + " Current DNS Server: %s\n", strna(global_info.llmnr), strna(global_info.mdns), strna(global_info.dnssec), - yes_no(global_info.dnssec_supported)); + yes_no(global_info.dnssec_supported), + strna(global_info.current_dns)); STRV_FOREACH(i, global_info.dns) { printf(" %s %s\n", @@ -1695,6 +1741,7 @@ static int status_global(sd_bus *bus, StatusMode mode, bool *empty_line) { r = 0; finish: + free(global_info.current_dns); strv_free(global_info.dns); strv_free(global_info.domains); strv_free(global_info.ntas); diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c index fda43b84cf..bea0f2a06f 100644 --- a/src/resolve/resolved-bus.c +++ b/src/resolve/resolved-bus.c @@ -1219,7 +1219,13 @@ int bus_dns_server_append(sd_bus_message *reply, DnsServer *s, bool with_ifindex int r; assert(reply); - assert(s); + + if (!s) { + if (with_ifindex) + return sd_bus_message_append(reply, "(iiay)", 0, AF_UNSPEC, 0); + else + return sd_bus_message_append(reply, "(iay)", AF_UNSPEC, 0); + } r = sd_bus_message_open_container(reply, 'r', with_ifindex ? "iiay" : "iay"); if (r < 0) @@ -1293,6 +1299,25 @@ static int bus_property_get_dns_servers( return sd_bus_message_close_container(reply); } +static int bus_property_get_current_dns_server( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + DnsServer *s; + + assert(reply); + assert(userdata); + + s = *(DnsServer **) userdata; + + return bus_dns_server_append(reply, s, true); +} + static int bus_property_get_domains( sd_bus *bus, const char *path, @@ -1823,6 +1848,7 @@ static const sd_bus_vtable resolve_vtable[] = { SD_BUS_PROPERTY("LLMNR", "s", bus_property_get_resolve_support, offsetof(Manager, llmnr_support), 0), SD_BUS_PROPERTY("MulticastDNS", "s", bus_property_get_resolve_support, offsetof(Manager, mdns_support), 0), SD_BUS_PROPERTY("DNS", "a(iiay)", bus_property_get_dns_servers, 0, 0), + SD_BUS_PROPERTY("CurrentDNSServer", "(iiay)", bus_property_get_current_dns_server, offsetof(Manager, current_dns_server), 0), SD_BUS_PROPERTY("Domains", "a(isb)", bus_property_get_domains, 0, 0), SD_BUS_PROPERTY("TransactionStatistics", "(tt)", bus_property_get_transaction_statistics, 0, 0), SD_BUS_PROPERTY("CacheStatistics", "(ttt)", bus_property_get_cache_statistics, 0, 0), diff --git a/src/resolve/resolved-link-bus.c b/src/resolve/resolved-link-bus.c index 8200765edb..ceaf71a71d 100644 --- a/src/resolve/resolved-link-bus.c +++ b/src/resolve/resolved-link-bus.c @@ -61,6 +61,25 @@ static int property_get_dns( return sd_bus_message_close_container(reply); } +static int property_get_current_dns_server( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + DnsServer *s; + + assert(reply); + assert(userdata); + + s = *(DnsServer **) userdata; + + return bus_dns_server_append(reply, s, false); +} + static int property_get_domains( sd_bus *bus, const char *path, @@ -516,6 +535,7 @@ const sd_bus_vtable link_vtable[] = { SD_BUS_PROPERTY("ScopesMask", "t", property_get_scopes_mask, 0, 0), SD_BUS_PROPERTY("DNS", "a(iay)", property_get_dns, 0, 0), + SD_BUS_PROPERTY("CurrentDNSServer", "(iay)", property_get_current_dns_server, offsetof(Link, current_dns_server), 0), SD_BUS_PROPERTY("Domains", "a(sb)", property_get_domains, 0, 0), SD_BUS_PROPERTY("LLMNR", "s", bus_property_get_resolve_support, offsetof(Link, llmnr_support), 0), SD_BUS_PROPERTY("MulticastDNS", "s", bus_property_get_resolve_support, offsetof(Link, mdns_support), 0), diff --git a/src/resolve/resolved-resolv-conf.c b/src/resolve/resolved-resolv-conf.c index 4626eb4da7..b0942b701c 100644 --- a/src/resolve/resolved-resolv-conf.c +++ b/src/resolve/resolved-resolv-conf.c @@ -268,7 +268,7 @@ static int write_stub_resolv_conf_contents(FILE *f, OrderedSet *dns, OrderedSet "# internal DNS stub resolver of systemd-resolved. This file lists all\n" "# configured search domains.\n" "#\n" - "# Run \"systemd-resolve --status\" to see details about the uplink DNS servers\n" + "# Run \"resolvectl status\" to see details about the uplink DNS servers\n" "# currently in use.\n" "#\n" "# Third party programs must not access this file directly, but only through the\n"