mirror of
https://github.com/systemd/systemd.git
synced 2026-08-03 06:30:30 +00:00
machine: generalise logic GetMachineAddresses to later use it in varlink interface
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user