resolvectl: support networkd managed interfaces
authorYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 27 May 2019 01:50:52 +0000 (10:50 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 16 Jul 2019 21:59:12 +0000 (06:59 +0900)
Closes #9808.

man/resolvectl.xml
src/resolve/resolvectl.c

index d4c04a1..a59fa4c 100644 (file)
 
         <listitem>
           <para>Get/set per-interface DNS configuration. These commands may be used to configure various DNS settings
-          for network interfaces that aren't managed by
-          <citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>. (These
-          commands will fail when used on interfaces that are managed by <command>systemd-networkd</command>, please
-          configure their DNS settings directly inside the <filename>.network</filename> files instead.) These commands
-          may be used to inform <command>systemd-resolved</command> about per-interface DNS configuration determined
+          for network interfaces. These commands may be used to inform <command>systemd-resolved</command> or
+          <command>systemd-networkd</command> about per-interface DNS configuration determined
           through external means. The <option>dns</option> command expects IPv4 or IPv6 address specifications of DNS
           servers to use. The <option>domain</option> command expects valid DNS domains, possibly prefixed with
           <literal>~</literal>, and configures a per-interface search or route-only domain. The
index f44d0b8..8d2ae89 100644 (file)
@@ -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);
+        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 (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;
@@ -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]);
+        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 (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;
@@ -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]);
+        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 (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;
@@ -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]);
+        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 (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;
@@ -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]);
+        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 (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;
@@ -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 = 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 = 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_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))