diff --git a/man/resolvectl.xml b/man/resolvectl.xml index d4c04a1e324..a59fa4c66d2 100644 --- a/man/resolvectl.xml +++ b/man/resolvectl.xml @@ -247,11 +247,8 @@ Get/set per-interface DNS configuration. These commands may be used to configure various DNS settings - for network interfaces that aren't managed by - systemd-networkd.service8. (These - commands will fail when used on interfaces that are managed by systemd-networkd, please - configure their DNS settings directly inside the .network files instead.) These commands - may be used to inform systemd-resolved about per-interface DNS configuration determined + for network interfaces. These commands may be used to inform systemd-resolved or + systemd-networkd about per-interface DNS configuration determined through external means. The command expects IPv4 or IPv6 address specifications of DNS servers to use. The command expects valid DNS domains, possibly prefixed with ~, and configures a per-interface search or route-only domain. The diff --git a/src/resolve/resolvectl.c b/src/resolve/resolvectl.c index f44d0b83431..8d2ae892813 100644 --- a/src/resolve/resolvectl.c +++ b/src/resolve/resolvectl.c @@ -1844,42 +1844,17 @@ static int verb_status(int argc, char **argv, void *userdata) { return r; } -static int log_interface_is_managed(int r, int ifindex) { - char ifname[IF_NAMESIZE + 1]; - - return log_error_errno(r, - "The specified interface %s is managed by systemd-networkd. Operation refused.\n" - "Please configure DNS settings for systemd-networkd managed interfaces directly in their .network files.", - strna(format_ifname(ifindex, ifname))); -} - -static int verb_dns(int argc, char **argv, void *userdata) { - _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; +static int call_dns(sd_bus *bus, char **dns, const char *destination, const char *path, const char *interface, sd_bus_error *error) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL; - sd_bus *bus = userdata; char **p; int r; - assert(bus); - - if (argc >= 2) { - r = ifname_mangle(argv[1]); - if (r < 0) - return r; - } - - if (arg_ifindex <= 0) - return status_all(bus, STATUS_DNS); - - if (argc < 3) - return status_ifindex(bus, arg_ifindex, NULL, STATUS_DNS, NULL); - r = sd_bus_message_new_method_call( bus, &req, - "org.freedesktop.resolve1", - "/org/freedesktop/resolve1", - "org.freedesktop.resolve1.Manager", + destination, + path, + interface, "SetLinkDNS"); if (r < 0) return bus_log_create_error(r); @@ -1894,8 +1869,8 @@ static int verb_dns(int argc, char **argv, void *userdata) { /* 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) { + if (!strv_equal(dns, STRV_MAKE(""))) + STRV_FOREACH(p, dns) { struct in_addr_data data; r = in_addr_from_string_auto(*p, &data.family, &data.address); @@ -1918,32 +1893,17 @@ static int verb_dns(int argc, char **argv, void *userdata) { 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_call(bus, req, 0, &error, NULL); - if (r < 0) { - if (sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) - return log_interface_is_managed(r, arg_ifindex); - - if (arg_ifindex_permissive && - sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_LINK)) - return 0; - - return log_error_errno(r, "Failed to set DNS configuration: %s", bus_error_message(&error, r)); - } - - return 0; + return sd_bus_call(bus, req, 0, error, NULL); } -static int verb_domain(int argc, char **argv, void *userdata) { +static int verb_dns(int argc, char **argv, void *userdata) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL; sd_bus *bus = userdata; - char **p; int r; assert(bus); @@ -1955,17 +1915,47 @@ static int verb_domain(int argc, char **argv, void *userdata) { } if (arg_ifindex <= 0) - return status_all(bus, STATUS_DOMAIN); + return status_all(bus, STATUS_DNS); if (argc < 3) - return status_ifindex(bus, arg_ifindex, NULL, STATUS_DOMAIN, NULL); + return status_ifindex(bus, arg_ifindex, NULL, STATUS_DNS, NULL); + + r = call_dns(bus, argv + 2, + "org.freedesktop.resolve1", + "/org/freedesktop/resolve1", + "org.freedesktop.resolve1.Manager", + &error); + if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) { + sd_bus_error_free(&error); + + r = call_dns(bus, argv + 2, + "org.freedesktop.network1", + "/org/freedesktop/network1", + "org.freedesktop.network1.Manager", + &error); + } + if (r < 0) { + if (arg_ifindex_permissive && + sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_LINK)) + return 0; + + return log_error_errno(r, "Failed to set DNS configuration: %s", bus_error_message(&error, r)); + } + + return 0; +} + +static int call_domain(sd_bus *bus, char **domain, const char *destination, const char *path, const char *interface, sd_bus_error *error) { + _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL; + char **p; + int r; r = sd_bus_message_new_method_call( bus, &req, - "org.freedesktop.resolve1", - "/org/freedesktop/resolve1", - "org.freedesktop.resolve1.Manager", + destination, + path, + interface, "SetLinkDomains"); if (r < 0) return bus_log_create_error(r); @@ -1980,8 +1970,8 @@ static int verb_domain(int argc, char **argv, void *userdata) { /* 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) { + if (!strv_equal(domain, STRV_MAKE(""))) + STRV_FOREACH(p, domain) { const char *n; n = **p == '~' ? *p + 1 : *p; @@ -1998,17 +1988,48 @@ static int verb_domain(int argc, char **argv, void *userdata) { 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_call(bus, req, 0, &error, NULL); - if (r < 0) { - if (sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) - return log_interface_is_managed(r, arg_ifindex); + return sd_bus_call(bus, req, 0, error, NULL); +} +static int verb_domain(int argc, char **argv, void *userdata) { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + sd_bus *bus = userdata; + int r; + + assert(bus); + + if (argc >= 2) { + r = ifname_mangle(argv[1]); + if (r < 0) + return r; + } + + if (arg_ifindex <= 0) + return status_all(bus, STATUS_DOMAIN); + + if (argc < 3) + return status_ifindex(bus, arg_ifindex, NULL, STATUS_DOMAIN, NULL); + + r = call_domain(bus, argv + 2, + "org.freedesktop.resolve1", + "/org/freedesktop/resolve1", + "org.freedesktop.resolve1.Manager", + &error); + if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) { + sd_bus_error_free(&error); + + r = call_domain(bus, argv + 2, + "org.freedesktop.network1", + "/org/freedesktop/network1", + "org.freedesktop.network1.Manager", + &error); + } + if (r < 0) { if (arg_ifindex_permissive && sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_LINK)) return 0; @@ -2042,18 +2063,29 @@ static int verb_default_route(int argc, char **argv, void *userdata) { if (b < 0) return log_error_errno(b, "Failed to parse boolean argument: %s", argv[2]); - r = sd_bus_call_method(bus, - "org.freedesktop.resolve1", - "/org/freedesktop/resolve1", - "org.freedesktop.resolve1.Manager", - "SetLinkDefaultRoute", - &error, - NULL, - "ib", arg_ifindex, b); - if (r < 0) { - if (sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) - return log_interface_is_managed(r, arg_ifindex); + r = sd_bus_call_method( + bus, + "org.freedesktop.resolve1", + "/org/freedesktop/resolve1", + "org.freedesktop.resolve1.Manager", + "SetLinkDefaultRoute", + &error, + NULL, + "ib", arg_ifindex, b); + if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) { + sd_bus_error_free(&error); + r = sd_bus_call_method( + bus, + "org.freedesktop.network1", + "/org/freedesktop/network1", + "org.freedesktop.network1.Manager", + "SetLinkDefaultRoute", + &error, + NULL, + "ib", arg_ifindex, b); + } + if (r < 0) { if (arg_ifindex_permissive && sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_LINK)) return 0; @@ -2083,18 +2115,29 @@ static int verb_llmnr(int argc, char **argv, void *userdata) { if (argc < 3) return status_ifindex(bus, arg_ifindex, NULL, STATUS_LLMNR, NULL); - r = sd_bus_call_method(bus, - "org.freedesktop.resolve1", - "/org/freedesktop/resolve1", - "org.freedesktop.resolve1.Manager", - "SetLinkLLMNR", - &error, - NULL, - "is", arg_ifindex, argv[2]); - if (r < 0) { - if (sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) - return log_interface_is_managed(r, arg_ifindex); + r = sd_bus_call_method( + bus, + "org.freedesktop.resolve1", + "/org/freedesktop/resolve1", + "org.freedesktop.resolve1.Manager", + "SetLinkLLMNR", + &error, + NULL, + "is", arg_ifindex, argv[2]); + if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) { + sd_bus_error_free(&error); + r = sd_bus_call_method( + bus, + "org.freedesktop.network1", + "/org/freedesktop/network1", + "org.freedesktop.network1.Manager", + "SetLinkLLMNR", + &error, + NULL, + "is", arg_ifindex, argv[2]); + } + if (r < 0) { if (arg_ifindex_permissive && sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_LINK)) return 0; @@ -2124,18 +2167,29 @@ static int verb_mdns(int argc, char **argv, void *userdata) { if (argc < 3) return status_ifindex(bus, arg_ifindex, NULL, STATUS_MDNS, NULL); - r = sd_bus_call_method(bus, - "org.freedesktop.resolve1", - "/org/freedesktop/resolve1", - "org.freedesktop.resolve1.Manager", - "SetLinkMulticastDNS", - &error, - NULL, - "is", arg_ifindex, argv[2]); - if (r < 0) { - if (sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) - return log_interface_is_managed(r, arg_ifindex); + r = sd_bus_call_method( + bus, + "org.freedesktop.resolve1", + "/org/freedesktop/resolve1", + "org.freedesktop.resolve1.Manager", + "SetLinkMulticastDNS", + &error, + NULL, + "is", arg_ifindex, argv[2]); + if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) { + sd_bus_error_free(&error); + r = sd_bus_call_method( + bus, + "org.freedesktop.network1", + "/org/freedesktop/network1", + "org.freedesktop.network1.Manager", + "SetLinkMulticastDNS", + &error, + NULL, + "is", arg_ifindex, argv[2]); + } + if (r < 0) { if (arg_ifindex_permissive && sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_LINK)) return 0; @@ -2165,18 +2219,29 @@ static int verb_dns_over_tls(int argc, char **argv, void *userdata) { if (argc < 3) return status_ifindex(bus, arg_ifindex, NULL, STATUS_PRIVATE, NULL); - r = sd_bus_call_method(bus, - "org.freedesktop.resolve1", - "/org/freedesktop/resolve1", - "org.freedesktop.resolve1.Manager", - "SetLinkDNSOverTLS", - &error, - NULL, - "is", arg_ifindex, argv[2]); - if (r < 0) { - if (sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) - return log_interface_is_managed(r, arg_ifindex); + r = sd_bus_call_method( + bus, + "org.freedesktop.resolve1", + "/org/freedesktop/resolve1", + "org.freedesktop.resolve1.Manager", + "SetLinkDNSOverTLS", + &error, + NULL, + "is", arg_ifindex, argv[2]); + if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) { + sd_bus_error_free(&error); + r = sd_bus_call_method( + bus, + "org.freedesktop.network1", + "/org/freedesktop/network1", + "org.freedesktop.network1.Manager", + "SetLinkDNSOverTLS", + &error, + NULL, + "is", arg_ifindex, argv[2]); + } + if (r < 0) { if (arg_ifindex_permissive && sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_LINK)) return 0; @@ -2206,18 +2271,29 @@ static int verb_dnssec(int argc, char **argv, void *userdata) { if (argc < 3) return status_ifindex(bus, arg_ifindex, NULL, STATUS_DNSSEC, NULL); - r = sd_bus_call_method(bus, - "org.freedesktop.resolve1", - "/org/freedesktop/resolve1", - "org.freedesktop.resolve1.Manager", - "SetLinkDNSSEC", - &error, - NULL, - "is", arg_ifindex, argv[2]); - if (r < 0) { - if (sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) - return log_interface_is_managed(r, arg_ifindex); + r = sd_bus_call_method( + bus, + "org.freedesktop.resolve1", + "/org/freedesktop/resolve1", + "org.freedesktop.resolve1.Manager", + "SetLinkDNSSEC", + &error, + NULL, + "is", arg_ifindex, argv[2]); + if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) { + sd_bus_error_free(&error); + r = sd_bus_call_method( + bus, + "org.freedesktop.network1", + "/org/freedesktop/network1", + "org.freedesktop.network1.Manager", + "SetLinkDNSSEC", + &error, + NULL, + "is", arg_ifindex, argv[2]); + } + if (r < 0) { if (arg_ifindex_permissive && sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_LINK)) return 0; @@ -2228,9 +2304,33 @@ static int verb_dnssec(int argc, char **argv, void *userdata) { return 0; } +static int call_nta(sd_bus *bus, char **nta, const char *destination, const char *path, const char *interface, sd_bus_error *error) { + _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL; + int r; + + r = sd_bus_message_new_method_call( + bus, + &req, + destination, + path, + interface, + "SetLinkDNSSECNegativeTrustAnchors"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append(req, "i", arg_ifindex); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_strv(req, nta); + if (r < 0) + return bus_log_create_error(r); + + return sd_bus_call(bus, req, 0, error, NULL); +} + static int verb_nta(int argc, char **argv, void *userdata) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL; sd_bus *bus = userdata; char **p; int r; @@ -2265,29 +2365,21 @@ static int verb_nta(int argc, char **argv, void *userdata) { } } - r = sd_bus_message_new_method_call( - bus, - &req, - "org.freedesktop.resolve1", - "/org/freedesktop/resolve1", - "org.freedesktop.resolve1.Manager", - "SetLinkDNSSECNegativeTrustAnchors"); - if (r < 0) - return bus_log_create_error(r); + r = call_nta(bus, clear ? NULL : argv + 2, + "org.freedesktop.resolve1", + "/org/freedesktop/resolve1", + "org.freedesktop.resolve1.Manager", + &error); + if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) { + sd_bus_error_free(&error); - r = sd_bus_message_append(req, "i", arg_ifindex); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_append_strv(req, clear ? NULL : argv + 2); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_call(bus, req, 0, &error, NULL); + r = call_nta(bus, clear ? NULL : argv + 2, + "org.freedesktop.network1", + "/org/freedesktop/network1", + "org.freedesktop.network1.Manager", + &error); + } if (r < 0) { - if (sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) - return log_interface_is_managed(r, arg_ifindex); - if (arg_ifindex_permissive && sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_LINK)) return 0; @@ -2314,14 +2406,28 @@ static int verb_revert_link(int argc, char **argv, void *userdata) { if (arg_ifindex <= 0) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Interface argument required."); - r = sd_bus_call_method(bus, - "org.freedesktop.resolve1", - "/org/freedesktop/resolve1", - "org.freedesktop.resolve1.Manager", - "RevertLink", - &error, - NULL, - "i", arg_ifindex); + r = sd_bus_call_method( + bus, + "org.freedesktop.resolve1", + "/org/freedesktop/resolve1", + "org.freedesktop.resolve1.Manager", + "RevertLink", + &error, + NULL, + "i", arg_ifindex); + if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) { + sd_bus_error_free(&error); + + r = sd_bus_call_method( + bus, + "org.freedesktop.network1", + "/org/freedesktop/network1", + "org.freedesktop.network1.Manager", + "RevertLinkDNS", + &error, + NULL, + "i", arg_ifindex); + } if (r < 0) { if (arg_ifindex_permissive && sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_LINK))