]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
machine: generalise logic GetMachineAddresses to later use it in varlink interface
authorIvan Kruglov <mail@ikruglov.com>
Tue, 24 Sep 2024 12:56:16 +0000 (14:56 +0200)
committerIvan Kruglov <mail@ikruglov.com>
Tue, 1 Oct 2024 17:00:25 +0000 (19:00 +0200)
src/machine/machine-dbus.c
src/machine/machined-core.c
src/machine/machined.h
src/shared/local-addresses.c
src/shared/local-addresses.h

index 783463896f61a807ac113f594218b507cf2d3087..a8c376dee9713f94df2bb76c8334bfecfcead386 100644 (file)
@@ -19,7 +19,6 @@
 #include "format-util.h"
 #include "fs-util.h"
 #include "in-addr-util.h"
-#include "iovec-util.h"
 #include "local-addresses.h"
 #include "machine-dbus.h"
 #include "machine.h"
@@ -169,6 +168,7 @@ int bus_machine_method_kill(sd_bus_message *message, void *userdata, sd_bus_erro
 
 int bus_machine_method_get_addresses(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+        _cleanup_free_ struct local_address *addresses = NULL;
         Machine *m = ASSERT_PTR(userdata);
         int r;
 
@@ -182,154 +182,30 @@ int bus_machine_method_get_addresses(sd_bus_message *message, void *userdata, sd
         if (r < 0)
                 return r;
 
-        switch (m->class) {
-
-        case MACHINE_HOST: {
-                _cleanup_free_ struct local_address *addresses = NULL;
-                int n;
-
-                n = local_addresses(NULL, 0, AF_UNSPEC, &addresses);
-                if (n < 0)
-                        return n;
-
-                for (int i = 0; i < n; i++) {
-                        r = sd_bus_message_open_container(reply, 'r', "iay");
-                        if (r < 0)
-                                return r;
-
-                        r = sd_bus_message_append(reply, "i", addresses[i].family);
-                        if (r < 0)
-                                return r;
-
-                        r = sd_bus_message_append_array(reply, 'y', &addresses[i].address, FAMILY_ADDRESS_SIZE(addresses[i].family));
-                        if (r < 0)
-                                return r;
-
-                        r = sd_bus_message_close_container(reply);
-                        if (r < 0)
-                                return r;
-                }
-
-                break;
-        }
-
-        case MACHINE_CONTAINER: {
-                _cleanup_close_pair_ int pair[2] = EBADF_PAIR;
-                _cleanup_close_ int netns_fd = -EBADF;
-                pid_t child;
+        int n = machine_get_addresses(m, &addresses);
+        if (n == -ENONET)
+                return sd_bus_error_setf(error, BUS_ERROR_NO_PRIVATE_NETWORKING, "Machine %s does not use private networking", m->name);
+        if (ERRNO_IS_NEG_NOT_SUPPORTED(n))
+                return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Requesting IP address data is only supported on container machines.");
+        if (n < 0)
+                return sd_bus_error_set_errnof(error, n, "Failed to get addresses: %m");
 
-                r = in_same_namespace(0, m->leader.pid, NAMESPACE_NET);
+        for (int i = 0; i < n; i++) {
+                r = sd_bus_message_open_container(reply, 'r', "iay");
                 if (r < 0)
                         return r;
-                if (r > 0)
-                        return sd_bus_error_setf(error, BUS_ERROR_NO_PRIVATE_NETWORKING, "Machine %s does not use private networking", m->name);
 
-                r = pidref_namespace_open(&m->leader,
-                                          /* ret_pidns_fd = */ NULL,
-                                          /* ret_mntns_fd = */ NULL,
-                                          &netns_fd,
-                                          /* ret_userns_fd = */ NULL,
-                                          /* ret_root_fd = */ NULL);
+                r = sd_bus_message_append(reply, "i", addresses[i].family);
                 if (r < 0)
                         return r;
 
-                if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
-                        return -errno;
-
-                r = namespace_fork("(sd-addrns)", "(sd-addr)", NULL, 0, FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGKILL,
-                                   -1, -1, netns_fd, -1, -1, &child);
+                r = sd_bus_message_append_array(reply, 'y', &addresses[i].address, FAMILY_ADDRESS_SIZE(addresses[i].family));
                 if (r < 0)
-                        return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
-                if (r == 0) {
-                        _cleanup_free_ struct local_address *addresses = NULL;
-                        struct local_address *a;
-                        int i, n;
-
-                        pair[0] = safe_close(pair[0]);
-
-                        n = local_addresses(NULL, 0, AF_UNSPEC, &addresses);
-                        if (n < 0)
-                                _exit(EXIT_FAILURE);
-
-                        for (a = addresses, i = 0; i < n; a++, i++) {
-                                struct iovec iov[2] = {
-                                        { .iov_base = &a->family, .iov_len = sizeof(a->family) },
-                                        { .iov_base = &a->address, .iov_len = FAMILY_ADDRESS_SIZE(a->family) },
-                                };
-
-                                r = writev(pair[1], iov, 2);
-                                if (r < 0)
-                                        _exit(EXIT_FAILURE);
-                        }
-
-                        pair[1] = safe_close(pair[1]);
-
-                        _exit(EXIT_SUCCESS);
-                }
-
-                pair[1] = safe_close(pair[1]);
-
-                for (;;) {
-                        int family;
-                        ssize_t n;
-                        union in_addr_union in_addr;
-                        struct iovec iov[2];
-                        struct msghdr mh = {
-                                .msg_iov = iov,
-                                .msg_iovlen = 2,
-                        };
-
-                        iov[0] = IOVEC_MAKE(&family, sizeof(family));
-                        iov[1] = IOVEC_MAKE(&in_addr, sizeof(in_addr));
-
-                        n = recvmsg_safe(pair[0], &mh, 0);
-                        if (n < 0)
-                                return n;
-                        if ((size_t) n < sizeof(family))
-                                break;
-
-                        r = sd_bus_message_open_container(reply, 'r', "iay");
-                        if (r < 0)
-                                return r;
-
-                        r = sd_bus_message_append(reply, "i", family);
-                        if (r < 0)
-                                return r;
-
-                        switch (family) {
-
-                        case AF_INET:
-                                if (n != sizeof(struct in_addr) + sizeof(family))
-                                        return -EIO;
-
-                                r = sd_bus_message_append_array(reply, 'y', &in_addr.in, sizeof(in_addr.in));
-                                break;
-
-                        case AF_INET6:
-                                if (n != sizeof(struct in6_addr) + sizeof(family))
-                                        return -EIO;
-
-                                r = sd_bus_message_append_array(reply, 'y', &in_addr.in6, sizeof(in_addr.in6));
-                                break;
-                        }
-                        if (r < 0)
-                                return r;
-
-                        r = sd_bus_message_close_container(reply);
-                        if (r < 0)
-                                return r;
-                }
+                        return r;
 
-                r = wait_for_terminate_and_check("(sd-addrns)", child, 0);
+                r = sd_bus_message_close_container(reply);
                 if (r < 0)
-                        return sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m");
-                if (r != EXIT_SUCCESS)
-                        return sd_bus_error_set(error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
-                break;
-        }
-
-        default:
-                return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Requesting IP address data is only supported on container machines.");
+                        return r;
         }
 
         r = sd_bus_message_close_container(reply);
index 1a840a6a37c9bae0ef2ef00fd0aa7ab9f09c3b77..df6e4378350d234106772da0af984338a9f23bd3 100644 (file)
@@ -1,8 +1,11 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "cgroup-util.h"
+#include "fd-util.h"
+#include "iovec-util.h"
 #include "machined.h"
 #include "process-util.h"
+#include "socket-util.h"
 #include "strv.h"
 #include "user-util.h"
 
@@ -175,3 +178,124 @@ void manager_enqueue_gc(Manager *m) {
 
         (void) sd_event_source_set_description(m->deferred_gc_event_source, "deferred-gc");
 }
+
+int machine_get_addresses(Machine* machine, struct local_address **ret_addresses) {
+        assert(machine);
+        assert(ret_addresses);
+
+        switch (machine->class) {
+
+        case MACHINE_HOST: {
+                _cleanup_free_ struct local_address *addresses = NULL;
+                int n;
+
+                n = local_addresses(/* rtnl = */ NULL, /* ifindex = */ 0, AF_UNSPEC, &addresses);
+                if (n < 0)
+                        return log_debug_errno(n, "Failed to get local addresses: %m");
+
+                *ret_addresses = TAKE_PTR(addresses);
+                return n;
+        }
+
+        case MACHINE_CONTAINER: {
+                _cleanup_close_pair_ int pair[2] = EBADF_PAIR;
+                _cleanup_close_ int netns_fd = -EBADF;
+                pid_t child;
+                int r;
+
+                r = in_same_namespace(/* pid1 = */ 0, machine->leader.pid, NAMESPACE_NET);
+                if (r < 0)
+                        return log_debug_errno(r, "Failed to check if container has private network: %m");
+                if (r > 0)
+                        return -ENONET;
+
+                r = pidref_namespace_open(&machine->leader,
+                                          /* ret_pidns_fd = */ NULL,
+                                          /* ret_mntns_fd = */ NULL,
+                                          &netns_fd,
+                                          /* ret_userns_fd = */ NULL,
+                                          /* ret_root_fd = */ NULL);
+                if (r < 0)
+                        return log_debug_errno(r, "Failed to open namespace: %m");
+
+                if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
+                        return log_debug_errno(errno, "Failed to call socketpair(): %m");
+
+                r = namespace_fork("(sd-addrns)",
+                                   "(sd-addr)",
+                                   /* except_fds = */ NULL,
+                                   /* n_except_fds = */ 0,
+                                   FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGKILL,
+                                   /* pidns_fd = */ -1,
+                                   /* mntns_fd = */ -1,
+                                   netns_fd,
+                                   /* userns_fd = */ -1,
+                                   /* root_fd = */ -1,
+                                   &child);
+                if (r < 0)
+                        return log_debug_errno(r, "Failed to fork(): %m");
+                if (r == 0) {
+                        _cleanup_free_ struct local_address *addresses = NULL;
+
+                        pair[0] = safe_close(pair[0]);
+
+                        int n = local_addresses(/* rtnl = */ NULL, /* ifindex = */ 0, AF_UNSPEC, &addresses);
+                        if (n < 0) {
+                                log_debug_errno(n, "Failed to get local addresses: %m");
+                                _exit(EXIT_FAILURE);
+                        }
+
+                        FOREACH_ARRAY(a, addresses, n) {
+                                r = write(pair[1], a, sizeof(*a));
+                                if (r < 0) {
+                                        log_debug_errno(errno, "Failed to write to socket: %m");
+                                        _exit(EXIT_FAILURE);
+                                }
+                        }
+
+                        pair[1] = safe_close(pair[1]);
+
+                        _exit(EXIT_SUCCESS);
+                }
+
+                pair[1] = safe_close(pair[1]);
+
+                _cleanup_free_ struct local_address *list = NULL;
+                size_t n_list = 0;
+
+                for (;;) {
+                        ssize_t n;
+                        struct local_address la;
+
+                        n = read(pair[0], &la, sizeof(la));
+                        if (n < 0)
+                                return log_debug_errno(errno, "Failed to read from socket(): %m");
+                        if (n == 0)
+                                break;
+                        if ((size_t) n < sizeof(la))
+                                return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Received unexpectedly short message");
+
+                        r = add_local_address(&list,
+                                              &n_list,
+                                              la.ifindex,
+                                              la.scope,
+                                              la.family,
+                                              &la.address);
+                        if (r < 0)
+                                return log_debug_errno(r, "Failed to add local address: %m");
+                }
+
+                r = wait_for_terminate_and_check("(sd-addrns)", child, /* flags = */ 0);
+                if (r < 0)
+                        return log_debug_errno(r, "Failed to wait for child: %m");
+                if (r != EXIT_SUCCESS)
+                        return log_debug_errno(SYNTHETIC_ERRNO(ESHUTDOWN), "Child died abnormally");
+
+                *ret_addresses = TAKE_PTR(list);
+                return (int) n_list;
+        }
+
+        default:
+                return -EOPNOTSUPP;
+        }
+}
index 4ba54ebe201d9419cc409170461bedb2b888c808..f1d0d157c8815a6ad76d47b2aa1d49beb8d9df87 100644 (file)
@@ -12,6 +12,7 @@ typedef struct Manager Manager;
 #include "hashmap.h"
 #include "image-dbus.h"
 #include "list.h"
+#include "local-addresses.h"
 #include "machine-dbus.h"
 #include "machine.h"
 #include "operation.h"
@@ -63,3 +64,5 @@ int manager_find_machine_for_gid(Manager *m, gid_t host_gid, Machine **ret_machi
 
 void manager_gc(Manager *m, bool drop_not_started);
 void manager_enqueue_gc(Manager *m);
+
+int machine_get_addresses(Machine* machine, struct local_address **ret_addresses);
index 5d5435f54b52fcd392817d078a2d96d7a4d8d96a..10550fca206e222f030cb0e7758f9341629be3b2 100644 (file)
@@ -104,7 +104,7 @@ static int add_local_address_full(
         return 1;
 }
 
-static int add_local_address(
+int add_local_address(
                 struct local_address **list,
                 size_t *n_list,
                 int ifindex,
index 399d0c6fb8099c2273a3b57609632a65b3ab1a81..42abca783815e78451ed2c5bd95fe2281d2171ae 100644 (file)
@@ -16,6 +16,8 @@ struct local_address {
 
 bool has_local_address(const struct local_address *addresses, size_t n_addresses, const struct local_address *needle);
 
+int add_local_address(struct local_address **list, size_t *n_list, int ifindex, unsigned char scope, int family, const union in_addr_union *address);
+
 int local_addresses(sd_netlink *rtnl, int ifindex, int af, struct local_address **ret);
 
 int local_gateways(sd_netlink *rtnl, int ifindex, int af, struct local_address **ret);