machine: generalise logic GetMachineAddresses to later use it in varlink interface

This commit is contained in:
Ivan Kruglov
2024-09-24 14:56:16 +02:00
parent e996663475
commit f1daf9fb74
5 changed files with 154 additions and 149 deletions

View 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;
r = in_same_namespace(0, m->leader.pid, NAMESPACE_NET);
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);
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);
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;
}
r = wait_for_terminate_and_check("(sd-addrns)", child, 0);
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:
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");
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;
}
r = sd_bus_message_close_container(reply);

View 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;
}
}

View 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);

View 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,

View 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);