#include "alloc-util.h"
#include "bus-common-errors.h"
#include "bus-error.h"
-#include "bus-util.h"
+#include "bus-locator.h"
+#include "bus-map-properties.h"
+#include "bus-message-util.h"
#include "dns-domain.h"
#include "escape.h"
#include "format-table.h"
#include "resolved-def.h"
#include "resolved-dns-packet.h"
#include "socket-netlink.h"
+#include "sort-util.h"
#include "stdio-util.h"
#include "string-table.h"
#include "strv.h"
#include "terminal-util.h"
+#include "utf8.h"
#include "verbs.h"
static int arg_family = AF_UNSPEC;
STATUS_NTA,
} StatusMode;
+typedef struct InterfaceInfo {
+ int index;
+ const char *name;
+} InterfaceInfo;
+
+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(const char *s) {
_cleanup_free_ char *iface = NULL;
const char *dot;
while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) {
_cleanup_free_ char *pretty = NULL;
int ifindex, family, k;
- const void *a;
- size_t sz;
+ union in_addr_union a;
assert_cc(sizeof(int) == sizeof(int32_t));
- r = sd_bus_message_read(reply, "ii", &ifindex, &family);
+ r = sd_bus_message_read(reply, "i", &ifindex);
if (r < 0)
return bus_log_parse_error(r);
- r = sd_bus_message_read_array(reply, 'y', &a, &sz);
- if (r < 0)
- return bus_log_parse_error(r);
+ sd_bus_error_free(&error);
+ r = bus_message_read_in_addr_auto(reply, &error, &family, &a);
+ if (r < 0 && !sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS))
+ return log_error_errno(r, "%s: systemd-resolved returned invalid result: %s", name, bus_error_message(&error, r));
r = sd_bus_message_exit_container(reply);
if (r < 0)
return bus_log_parse_error(r);
- if (!IN_SET(family, AF_INET, AF_INET6)) {
- log_debug("%s: skipping entry with family %d (%s)", name, family, af_to_name(family) ?: "unknown");
+ if (sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS)) {
+ log_debug_errno(r, "%s: systemd-resolved returned invalid result, ignoring: %s", name, bus_error_message(&error, r));
continue;
}
- if (sz != FAMILY_ADDRESS_SIZE(family)) {
- log_error("%s: systemd-resolved returned address of invalid size %zu for family %s", name, sz, af_to_name(family) ?: "unknown");
- return -EINVAL;
- }
-
- r = in_addr_ifindex_to_string(family, a, ifindex, &pretty);
+ r = in_addr_ifindex_to_string(family, &a, ifindex, &pretty);
if (r < 0)
return log_error_errno(r, "Failed to print address for %s: %m", name);
(int) strlen(name), c == 0 ? name : "", c == 0 ? ":" : " ",
canonical);
- if (c == 0) {
- log_error("%s: no addresses found", name);
- return -ESRCH;
- }
+ if (c == 0)
+ return log_error_errno(SYNTHETIC_ERRNO(ESRCH),
+ "%s: no addresses found", name);
print_source(flags, ts);
if (r < 0)
return bus_log_parse_error(r);
- if (c == 0) {
- log_error("%s: no names found", pretty);
- return -ESRCH;
- }
+ if (c == 0)
+ return log_error_errno(SYNTHETIC_ERRNO(ESRCH),
+ "%s: no names found", pretty);
print_source(flags, ts);
while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) {
_cleanup_free_ char *pretty = NULL;
int ifindex, family, k;
- const void *a;
+ union in_addr_union a;;
assert_cc(sizeof(int) == sizeof(int32_t));
- r = sd_bus_message_read(reply, "ii", &ifindex, &family);
+ r = sd_bus_message_read(reply, "i", &ifindex);
if (r < 0)
return bus_log_parse_error(r);
- r = sd_bus_message_read_array(reply, 'y', &a, &sz);
- if (r < 0)
- return bus_log_parse_error(r);
+ sd_bus_error_free(&error);
+ r = bus_message_read_in_addr_auto(reply, &error, &family, &a);
+ if (r < 0 && !sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS))
+ return log_error_errno(r, "%s: systemd-resolved returned invalid result: %s", name, bus_error_message(&error, r));
r = sd_bus_message_exit_container(reply);
if (r < 0)
return bus_log_parse_error(r);
- if (!IN_SET(family, AF_INET, AF_INET6)) {
- log_debug("%s: skipping entry with family %d (%s)", name, family, af_to_name(family) ?: "unknown");
+ if (sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS)) {
+ log_debug_errno(r, "%s: systemd-resolved returned invalid result, ignoring: %s", name, bus_error_message(&error, r));
continue;
}
- if (sz != FAMILY_ADDRESS_SIZE(family)) {
- log_error("%s: systemd-resolved returned address of invalid size %zu for family %s", name, sz, af_to_name(family) ?: "unknown");
- return -EINVAL;
- }
-
- r = in_addr_ifindex_to_string(family, a, ifindex, &pretty);
+ r = in_addr_ifindex_to_string(family, &a, ifindex, &pretty);
if (r < 0)
return log_error_errno(r, "Failed to print address for %s: %m", name);
r = table_print(table, NULL);
if (r < 0)
- return log_error_errno(r, "Failed to print table: %m");
+ return table_log_print_error(r);
return 0;
}
return 0;
}
-static int read_dns_server_one(sd_bus_message *m, bool with_ifindex, char **ret) {
+static int read_dns_server_one(sd_bus_message *m, bool with_ifindex, bool extended, char **ret) {
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_free_ char *pretty = NULL;
- int ifindex, family, r;
- const void *a;
- size_t sz;
+ int ifindex, family, r, k;
+ union in_addr_union a;
+ const char *name = NULL;
+ uint16_t port = 0;
assert(m);
assert(ret);
- r = sd_bus_message_enter_container(m, 'r', with_ifindex ? "iiay" : "iay");
+ r = sd_bus_message_enter_container(m, 'r', with_ifindex ? (extended ? "iiayqs" : "iiay") : (extended ? "iayqs" : "iay"));
if (r <= 0)
return r;
return r;
}
- r = sd_bus_message_read(m, "i", &family);
- if (r < 0)
- return r;
+ k = bus_message_read_in_addr_auto(m, &error, &family, &a);
+ if (k < 0 && !sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS))
+ return k;
- r = sd_bus_message_read_array(m, 'y', &a, &sz);
- if (r < 0)
- return r;
+ if (extended) {
+ r = sd_bus_message_read(m, "q", &port);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_read(m, "s", &name);
+ 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 */
+ if (k < 0) {
+ log_debug("Invalid DNS server, ignoring: %s", bus_error_message(&error, k));
*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.");
-
+ if (with_ifindex && ifindex != 0) {
+ /* only show the global ones here */
*ret = NULL;
return 1;
}
- r = in_addr_to_string(family, a, &pretty);
+ r = in_addr_port_ifindex_name_to_string(family, &a, port, ifindex, name, &pretty);
if (r < 0)
return r;
return 1;
}
-static int map_link_dns_servers(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
+static int map_link_dns_servers_internal(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata, bool extended) {
char ***l = userdata;
int r;
assert(m);
assert(l);
- r = sd_bus_message_enter_container(m, 'a', "(iay)");
+ r = sd_bus_message_enter_container(m, 'a', extended ? "(iayqs)" : "(iay)");
if (r < 0)
return r;
for (;;) {
_cleanup_free_ char *pretty = NULL;
- r = read_dns_server_one(m, false, &pretty);
+ r = read_dns_server_one(m, false, extended, &pretty);
if (r < 0)
return r;
if (r == 0)
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_link_dns_servers_internal(bus, member, m, error, userdata, false);
+}
+
+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_link_dns_servers_internal(bus, member, m, error, userdata, true);
+}
+
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);
+ return read_dns_server_one(m, false, false, 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, false, true, userdata);
}
static int read_domain_one(sd_bus_message *m, bool with_ifindex, char **ret) {
if (r < 0)
return r;
+ strv_sort(*l);
+
return 0;
}
static int status_print_strv_ifindex(int ifindex, const char *ifname, 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
+ printf("%s%nGlobal%n%s:", ansi_highlight(), &pos1, &pos2, ansi_normal());
+
+ size_t cols = columns(), position = pos2 - pos1 + 2;
char **i;
- printf("%sLink %i (%s)%s:",
- ansi_highlight(), ifindex, ifname, ansi_normal());
+ STRV_FOREACH(i, p) {
+ size_t our_len = utf8_console_width(*i); /* This returns -1 on invalid utf-8 (which shouldn't happen).
+ * If that happens, we'll just print one item per line. */
- STRV_FOREACH(i, p)
- printf(" %s", *i);
+ if (position <= indent || size_add(size_add(position, 1), our_len) < cols) {
+ printf(" %s", *i);
+ position = size_add(size_add(position, 1), our_len);
+ } else {
+ printf("\n%*s%s", indent, "", *i);
+ position = size_add(our_len, indent);
+ }
+ }
printf("\n");
return 0;
}
-struct link_info {
+static int status_print_strv_global(char **p) {
+ return status_print_strv_ifindex(0, 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;
+
+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_clear(LinkInfo *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 void link_info_clear(struct link_info *p) {
+static void global_info_clear(GlobalInfo *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);
}
r = table_add_many(table,
TABLE_STRING, prefix,
- TABLE_STRV, l);
+ TABLE_STRV_WRAPPED, l);
if (r < 0)
return table_log_add_error(r);
return 0;
}
+static int strv_extend_extended_bool(char ***strv, const char *name, const char *value) {
+ int r;
+
+ if (value) {
+ r = parse_boolean(value);
+ if (r >= 0)
+ return strv_extendf(strv, "%s%s", plus_minus(r), name);
+ }
+
+ 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 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_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(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) },
- { "DefaultRoute", "b", NULL, offsetof(struct link_info, default_route) },
- { "LLMNR", "s", NULL, offsetof(struct link_info, llmnr) },
- { "MulticastDNS", "s", NULL, offsetof(struct link_info, mdns) },
- { "DNSOverTLS", "s", NULL, offsetof(struct link_info, dns_over_tls) },
- { "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(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_clear) struct link_info link_info = {};
+ _cleanup_(link_info_clear) LinkInfo link_info = {};
_cleanup_(table_unrefp) Table *table = NULL;
_cleanup_free_ char *p = NULL;
char ifi[DECIMAL_STR_MAX(int)], ifname[IF_NAMESIZE + 1] = "";
(void) pager_open(arg_pager_flags);
if (mode == STATUS_DNS)
- return status_print_strv_ifindex(ifindex, name, link_info.dns);
+ return status_print_strv_ifindex(ifindex, name, link_info.dns_ex ?: link_info.dns);
if (mode == STATUS_DOMAIN)
return status_print_strv_ifindex(ifindex, name, link_info.domains);
if (r < 0)
return table_log_add_error(r);
+ _cleanup_strv_free_ char **pstatus = link_protocol_status(&link_info);
+ if (!pstatus)
+ return log_oom();
+
r = table_add_many(table,
- TABLE_STRING, "DefaultRoute setting:",
- TABLE_BOOLEAN, link_info.default_route,
- TABLE_STRING, "LLMNR setting:",
- TABLE_STRING, strna(link_info.llmnr),
- TABLE_STRING, "MulticastDNS setting:",
- TABLE_STRING, strna(link_info.mdns),
- TABLE_STRING, "DNSOverTLS setting:",
- TABLE_STRING, strna(link_info.dns_over_tls),
- TABLE_STRING, "DNSSEC setting:",
- TABLE_STRING, strna(link_info.dnssec),
- TABLE_STRING, "DNSSEC supported:",
- TABLE_BOOLEAN, link_info.dnssec_supported);
+ TABLE_STRING, "Protocols:",
+ TABLE_STRV_WRAPPED, pstatus);
if (r < 0)
return table_log_add_error(r);
if (link_info.current_dns) {
r = table_add_many(table,
TABLE_STRING, "Current DNS Server:",
- TABLE_STRING, link_info.current_dns);
+ TABLE_STRING, link_info.current_dns_ex ?: link_info.current_dns);
if (r < 0)
return table_log_add_error(r);
}
- r = dump_list(table, "DNS Servers:", link_info.dns);
+ r = dump_list(table, "DNS Servers:", link_info.dns_ex ?: link_info.dns);
if (r < 0)
return r;
if (r < 0)
return r;
- r = dump_list(table, "DNSSEC NTA:", link_info.ntas);
- if (r < 0)
- return r;
-
r = table_print(table, NULL);
if (r < 0)
- return log_error_errno(r, "Failed to print table: %m");
+ return table_log_print_error(r);
if (empty_line)
*empty_line = true;
return 0;
}
-static int map_global_dns_servers(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
+static int map_global_dns_servers_internal(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata, bool extended) {
char ***l = userdata;
int r;
assert(m);
assert(l);
- r = sd_bus_message_enter_container(m, 'a', "(iiay)");
+ r = sd_bus_message_enter_container(m, 'a', extended ? "(iiayqs)" : "(iiay)");
if (r < 0)
return r;
for (;;) {
_cleanup_free_ char *pretty = NULL;
- r = read_dns_server_one(m, true, &pretty);
+ r = read_dns_server_one(m, true, extended, &pretty);
if (r < 0)
return r;
if (r == 0)
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, false);
+}
+
+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, true);
+}
+
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);
+ return read_dns_server_one(m, true, false, 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) {
+ assert(m);
+ assert(userdata);
+
+ return read_dns_server_one(m, true, true, userdata);
}
static int map_global_domains(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
if (r < 0)
return r;
- return 0;
-}
-
-static int status_print_strv_global(char **p) {
- char **i;
-
- printf("%sGlobal%s:", ansi_highlight(), ansi_normal());
-
- STRV_FOREACH(i, p)
- printf(" %s", *i);
-
- printf("\n");
+ strv_sort(*l);
return 0;
}
-struct global_info {
- char *current_dns;
- char **dns;
- char **fallback_dns;
- char **domains;
- char **ntas;
- const char *llmnr;
- const char *mdns;
- const char *dns_over_tls;
- const char *dnssec;
- bool dnssec_supported;
-};
-
-static void global_info_clear(struct global_info *p) {
- free(p->current_dns);
- strv_free(p->dns);
- strv_free(p->fallback_dns);
- strv_free(p->domains);
- strv_free(p->ntas);
-}
-
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(struct global_info, dns) },
- { "FallbackDNS", "a(iiay)", map_global_dns_servers, offsetof(struct global_info, fallback_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) },
- { "DNSOverTLS", "s", NULL, offsetof(struct global_info, dns_over_tls) },
- { "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(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_clear) struct global_info global_info = {};
+ _cleanup_(global_info_clear) GlobalInfo global_info = {};
_cleanup_(table_unrefp) Table *table = NULL;
int r;
(void) pager_open(arg_pager_flags);
if (mode == STATUS_DNS)
- return status_print_strv_global(global_info.dns);
+ return status_print_strv_global(global_info.dns_ex ?: global_info.dns);
if (mode == STATUS_DOMAIN)
return status_print_strv_global(global_info.domains);
table_set_header(table, false);
+ _cleanup_strv_free_ char **pstatus = global_protocol_status(&global_info);
+ if (!pstatus)
+ return log_oom();
+
r = table_add_many(table,
- TABLE_STRING, "LLMNR setting:",
+ TABLE_STRING, "Protocols:",
TABLE_SET_ALIGN_PERCENT, 100,
- TABLE_STRING, strna(global_info.llmnr),
- TABLE_STRING, "MulticastDNS setting:",
- TABLE_STRING, strna(global_info.mdns),
- TABLE_STRING, "DNSOverTLS setting:",
- TABLE_STRING, strna(global_info.dns_over_tls),
- TABLE_STRING, "DNSSEC setting:",
- TABLE_STRING, strna(global_info.dnssec),
- TABLE_STRING, "DNSSEC supported:",
- TABLE_BOOLEAN, global_info.dnssec_supported);
+ TABLE_STRV_WRAPPED, pstatus);
if (r < 0)
return table_log_add_error(r);
+ if (global_info.resolv_conf_mode) {
+ r = table_add_many(table,
+ TABLE_STRING, "resolv.conf mode:",
+ TABLE_STRING, global_info.resolv_conf_mode);
+ if (r < 0)
+ return table_log_add_error(r);
+ }
+
if (global_info.current_dns) {
r = table_add_many(table,
TABLE_STRING, "Current DNS Server:",
- TABLE_STRING, global_info.current_dns);
+ TABLE_STRING, global_info.current_dns_ex ?: global_info.current_dns);
if (r < 0)
return table_log_add_error(r);
}
- r = dump_list(table, "DNS Servers:", global_info.dns);
+ r = dump_list(table, "DNS Servers:", global_info.dns_ex ?: global_info.dns);
if (r < 0)
return r;
- r = dump_list(table, "Fallback DNS Servers:", global_info.fallback_dns);
+ r = dump_list(table, "Fallback DNS Servers:", global_info.fallback_dns_ex ?: global_info.fallback_dns);
if (r < 0)
return r;
if (r < 0)
return r;
- strv_sort(global_info.ntas);
- r = dump_list(table, "DNSSEC NTA:", global_info.ntas);
- if (r < 0)
- return r;
-
r = table_print(table, NULL);
if (r < 0)
- return log_error_errno(r, "Failed to print table: %m");
+ return table_log_print_error(r);
*empty_line = true;
static int status_all(sd_bus *bus, StatusMode mode) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
- sd_netlink_message *i;
bool empty_line = false;
int r;
if (r < 0)
return log_error_errno(r, "Failed to enumerate links: %m");
- r = 0;
- for (i = reply; i; i = sd_netlink_message_next(i)) {
+ _cleanup_free_ InterfaceInfo *infos = NULL;
+ size_t n_allocated = 0, n_infos = 0;
+
+ for (sd_netlink_message *i = reply; i; i = sd_netlink_message_next(i)) {
const char *name;
- int ifindex, q;
+ int ifindex;
uint16_t type;
- q = sd_netlink_message_get_type(i, &type);
- if (q < 0)
- return rtnl_log_parse_error(q);
+ r = sd_netlink_message_get_type(i, &type);
+ if (r < 0)
+ return rtnl_log_parse_error(r);
if (type != RTM_NEWLINK)
continue;
- q = sd_rtnl_message_link_get_ifindex(i, &ifindex);
- if (q < 0)
- return rtnl_log_parse_error(q);
+ r = sd_rtnl_message_link_get_ifindex(i, &ifindex);
+ if (r < 0)
+ return rtnl_log_parse_error(r);
if (ifindex == LOOPBACK_IFINDEX)
continue;
- q = sd_netlink_message_read_string(i, IFLA_IFNAME, &name);
- if (q < 0)
- return rtnl_log_parse_error(q);
+ r = sd_netlink_message_read_string(i, IFLA_IFNAME, &name);
+ if (r < 0)
+ return rtnl_log_parse_error(r);
- q = status_ifindex(bus, ifindex, name, mode, &empty_line);
+ if (!GREEDY_REALLOC(infos, n_allocated, n_infos + 1))
+ return log_oom();
+
+ infos[n_infos++] = (InterfaceInfo) { ifindex, name };
+ }
+
+ typesafe_qsort(infos, n_infos, interface_info_compare);
+
+ r = 0;
+ for (size_t i = 0; i < n_infos; i++) {
+ int q = status_ifindex(bus, infos[i].index, infos[i].name, mode, &empty_line);
if (q < 0 && r >= 0)
r = q;
}
return r;
}
-static int call_dns(sd_bus *bus, char **dns, const BusLocator *locator, sd_bus_error *error) {
+static int call_dns(sd_bus *bus, char **dns, const BusLocator *locator, sd_bus_error *error, bool extended) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL;
char **p;
int r;
- r = bus_message_new_method_call(bus, &req, locator, "SetLinkDNS");
+ r = bus_message_new_method_call(bus, &req, locator, extended ? "SetLinkDNSEx" : "SetLinkDNS");
if (r < 0)
return bus_log_create_error(r);
if (r < 0)
return bus_log_create_error(r);
- r = sd_bus_message_open_container(req, 'a', "(iay)");
+ r = sd_bus_message_open_container(req, 'a', extended ? "(iayqs)" : "(iay)");
if (r < 0)
return bus_log_create_error(r);
* empty list, which will clear the list of domains for an interface. */
if (!strv_equal(dns, STRV_MAKE("")))
STRV_FOREACH(p, dns) {
+ _cleanup_free_ char *name = NULL;
struct in_addr_data data;
+ uint16_t port;
+ int ifindex;
- r = in_addr_from_string_auto(*p, &data.family, &data.address);
+ r = in_addr_port_ifindex_name_from_string_auto(*p, &data.family, &data.address, &port, &ifindex, &name);
if (r < 0)
return log_error_errno(r, "Failed to parse DNS server address: %s", *p);
- r = sd_bus_message_open_container(req, 'r', "iay");
+ if (ifindex != 0 && ifindex != arg_ifindex)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid ifindex: %i", ifindex);
+
+ r = sd_bus_message_open_container(req, 'r', extended ? "iayqs" : "iay");
if (r < 0)
return bus_log_create_error(r);
if (r < 0)
return bus_log_create_error(r);
+ if (extended) {
+ r = sd_bus_message_append(req, "q", port);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append(req, "s", name);
+ if (r < 0)
+ return bus_log_create_error(r);
+ }
+
r = sd_bus_message_close_container(req);
if (r < 0)
return bus_log_create_error(r);
if (r < 0)
return bus_log_create_error(r);
- return sd_bus_call(bus, req, 0, error, NULL);
+ r = sd_bus_call(bus, req, 0, error, NULL);
+ if (r < 0 && extended && sd_bus_error_has_name(error, SD_BUS_ERROR_UNKNOWN_METHOD)) {
+ sd_bus_error_free(error);
+ return call_dns(bus, dns, locator, error, false);
+ }
+ return r;
}
static int verb_dns(int argc, char **argv, void *userdata) {
if (argc < 3)
return status_ifindex(bus, arg_ifindex, NULL, STATUS_DNS, NULL);
- r = call_dns(bus, argv + 2, bus_resolve_mgr, &error);
+ r = call_dns(bus, argv + 2, bus_resolve_mgr, &error, true);
if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) {
sd_bus_error_free(&error);
- r = call_dns(bus, argv + 2, bus_network_mgr, &error);
+ r = call_dns(bus, argv + 2, bus_network_mgr, &error, true);
}
if (r < 0) {
if (arg_ifindex_permissive &&
r = dns_name_is_valid(n);
if (r < 0)
return log_error_errno(r, "Failed to validate specified domain %s: %m", n);
- if (r == 0) {
- log_error("Domain not valid: %s", n);
- return -EINVAL;
- }
+ if (r == 0)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Domain not valid: %s",
+ n);
r = sd_bus_message_append(req, "(sb)", n, **p == '~');
if (r < 0)
r = dns_name_is_valid(*p);
if (r < 0)
return log_error_errno(r, "Failed to validate specified domain %s: %m", *p);
- if (r == 0) {
- log_error("Domain not valid: %s", *p);
- return -EINVAL;
- }
+ if (r == 0)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Domain not valid: %s",
+ *p);
}
r = call_nta(bus, clear ? NULL : argv + 2, bus_resolve_mgr, &error);
" dnssec [LINK [MODE]] Get/set per-interface DNSSEC mode\n"
" nta [LINK [DOMAIN...]] Get/set per-interface DNSSEC NTA\n"
" revert LINK Revert per-interface configuration\n"
+ " log-level [LEVEL] Get/set logging threshold for systemd-resolved\n"
"\nOptions:\n"
" -h --help Show this help\n"
" --version Show package version\n"
static int translate(const char *verb, const char *single_arg, size_t num_args, char **args, sd_bus *bus) {
char **fake, **p;
- size_t num, i;
+ size_t num;
assert(verb);
assert(num_args == 0 || args);
*p++ = (char *) verb;
if (single_arg)
*p++ = (char *) single_arg;
- for (i = 0; i < num_args; i++)
+ for (size_t i = 0; i < num_args; i++)
*p++ = args[i];
optind = 0;
int r;
setlocale(LC_ALL, "");
- log_show_color(true);
- log_parse_environment();
- log_open();
+ log_setup_cli();
if (streq(program_invocation_short_name, "resolvconf"))
r = resolvconf_parse_argv(argc, argv);