From 06c28aa0d83edde4fdd173ced33a646b8f7b0073 Mon Sep 17 00:00:00 2001 From: Filipe Brandenburger Date: Mon, 16 Jul 2018 15:16:37 -0700 Subject: [PATCH] resolvectl: Take empty string argument to clear lists in "dns", "domain" and "nta" options The current CLI does not support a way to clear these lists, since without any additional arguments, the command will list the current values. Introduce a new way to clear the lists by passing a single '' argument to these subcommands. Update the man page to document this. Tested: $ build/resolvectl domain eth1 Link 3 (eth1): ~. $ build/resolvectl domain eth1 '' $ build/resolvectl domain eth1 Link 3 (eth1): $ build/resolvectl domain eth1 '~.' '~example.com' $ build/resolvectl domain eth1 Link 3 (eth1): ~. ~example.com $ build/resolvectl domain eth1 '' $ build/resolvectl domain eth1 Link 3 (eth1): $ build/resolvectl domain eth1 '~.' $ build/resolvectl domain eth1 Link 3 (eth1): ~. And similar for "dns" and "nta". --- man/resolvectl.xml | 8 +++- src/resolve/resolvectl.c | 92 +++++++++++++++++++++++----------------- 2 files changed, 59 insertions(+), 41 deletions(-) diff --git a/man/resolvectl.xml b/man/resolvectl.xml index ff5b8ad101..cf97628f86 100644 --- a/man/resolvectl.xml +++ b/man/resolvectl.xml @@ -258,8 +258,12 @@ ~, and configures a per-interface search or route-only domain. The , , and commands may be used to configure the per-interface LLMNR, MulticastDNS, DNSSEC and DNSOverTLS settings. Finally, command - may be used to configure additional per-interface DNSSEC NTA domains. For details about these settings, their - possible values and their effect, see the corresponding options in + may be used to configure additional per-interface DNSSEC NTA domains. + + Options , and can take + a single empty string argument to clear their respective value lists. + + For details about these settings, their possible values and their effect, see the corresponding options in systemd.network5. diff --git a/src/resolve/resolvectl.c b/src/resolve/resolvectl.c index d04c756d73..7f29546de1 100644 --- a/src/resolve/resolvectl.c +++ b/src/resolve/resolvectl.c @@ -1930,28 +1930,32 @@ static int verb_dns(int argc, char **argv, void *userdata) { if (r < 0) return bus_log_create_error(r); - STRV_FOREACH(p, argv + 2) { - struct in_addr_data data; + /* If only argument is the empty string, then call SetLinkDNS() with an + * empty list, which will clear the list of domains for an interface. */ + if (!strv_equal(argv + 2, STRV_MAKE(""))) { + STRV_FOREACH(p, argv + 2) { + struct in_addr_data data; - r = in_addr_from_string_auto(*p, &data.family, &data.address); - if (r < 0) - return log_error_errno(r, "Failed to parse DNS server address: %s", *p); + r = in_addr_from_string_auto(*p, &data.family, &data.address); + 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 (r < 0) - return bus_log_create_error(r); + r = sd_bus_message_open_container(req, 'r', "iay"); + if (r < 0) + return bus_log_create_error(r); - r = sd_bus_message_append(req, "i", data.family); - if (r < 0) - return bus_log_create_error(r); + r = sd_bus_message_append(req, "i", data.family); + if (r < 0) + return bus_log_create_error(r); - r = sd_bus_message_append_array(req, 'y', &data.address, FAMILY_ADDRESS_SIZE(data.family)); - if (r < 0) - return bus_log_create_error(r); + r = sd_bus_message_append_array(req, 'y', &data.address, FAMILY_ADDRESS_SIZE(data.family)); + 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); + r = sd_bus_message_close_container(req); + if (r < 0) + return bus_log_create_error(r); + } } r = sd_bus_message_close_container(req); @@ -2010,22 +2014,26 @@ static int verb_domain(int argc, char **argv, void *userdata) { if (r < 0) return bus_log_create_error(r); - STRV_FOREACH(p, argv + 2) { - const char *n; + /* If only argument is the empty string, then call SetLinkDomains() with an + * empty list, which will clear the list of domains for an interface. */ + if (!strv_equal(argv + 2, STRV_MAKE(""))) { + STRV_FOREACH(p, argv + 2) { + const char *n; - n = **p == '~' ? *p + 1 : *p; + n = **p == '~' ? *p + 1 : *p; - 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; + 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; + } + + r = sd_bus_message_append(req, "(sb)", n, **p == '~'); + if (r < 0) + return bus_log_create_error(r); } - - r = sd_bus_message_append(req, "(sb)", n, **p == '~'); - if (r < 0) - return bus_log_create_error(r); } r = sd_bus_message_close_container(req); @@ -2209,6 +2217,7 @@ static int verb_nta(int argc, char **argv, void *userdata) { sd_bus *bus = userdata; char **p; int r; + bool clear; assert(bus); @@ -2222,15 +2231,20 @@ static int verb_nta(int argc, char **argv, void *userdata) { if (argc == 2) return status_ifindex(bus, arg_ifindex, NULL, STATUS_NTA, NULL); - STRV_FOREACH(p, argv + 2) { - 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 only argument is the empty string, then call SetLinkDNSSECNegativeTrustAnchors() + * with an empty list, which will clear the list of domains for an interface. */ + clear = strv_equal(argv + 2, STRV_MAKE("")); + + if (!clear) + STRV_FOREACH(p, argv + 2) { + 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; + } } - } r = sd_bus_message_new_method_call( bus, @@ -2246,7 +2260,7 @@ static int verb_nta(int argc, char **argv, void *userdata) { if (r < 0) return bus_log_create_error(r); - r = sd_bus_message_append_strv(req, argv + 2); + r = sd_bus_message_append_strv(req, clear ? NULL : argv + 2); if (r < 0) return bus_log_create_error(r);