mirror of
https://github.com/systemd/systemd
synced 2024-10-01 13:55:20 +00:00
Merge pull request #33000 from poettering/ssh-proxy-machine
systemd-ssh-proxy: look for VSOCK CIDs in machined
This commit is contained in:
commit
9ca01a6475
|
@ -139,6 +139,7 @@ enum {
|
|||
_JSON_BUILD_HW_ADDR,
|
||||
_JSON_BUILD_STRING_SET,
|
||||
_JSON_BUILD_STRING_UNDERSCORIFY,
|
||||
_JSON_BUILD_DUAL_TIMESTAMP,
|
||||
|
||||
_JSON_BUILD_PAIR_UNSIGNED_NON_ZERO,
|
||||
_JSON_BUILD_PAIR_FINITE_USEC,
|
||||
|
@ -166,6 +167,7 @@ enum {
|
|||
#define JSON_BUILD_HW_ADDR(v) _JSON_BUILD_HW_ADDR, (const struct hw_addr_data*) { v }
|
||||
#define JSON_BUILD_STRING_SET(s) _JSON_BUILD_STRING_SET, (Set *) { s }
|
||||
#define JSON_BUILD_STRING_UNDERSCORIFY(s) _JSON_BUILD_STRING_UNDERSCORIFY, (const char *) { s }
|
||||
#define JSON_BUILD_DUAL_TIMESTAMP(t) _JSON_BUILD_DUAL_TIMESTAMP, (dual_timestamp*) { t }
|
||||
|
||||
#define JSON_BUILD_PAIR_UNSIGNED_NON_ZERO(name, u) _JSON_BUILD_PAIR_UNSIGNED_NON_ZERO, (const char*) { name }, (uint64_t) { u }
|
||||
#define JSON_BUILD_PAIR_FINITE_USEC(name, u) _JSON_BUILD_PAIR_FINITE_USEC, (const char*) { name }, (usec_t) { u }
|
||||
|
|
|
@ -4079,6 +4079,40 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) {
|
|||
break;
|
||||
}
|
||||
|
||||
case _JSON_BUILD_DUAL_TIMESTAMP: {
|
||||
dual_timestamp *ts;
|
||||
|
||||
if (!IN_SET(current->expect, EXPECT_TOPLEVEL, EXPECT_OBJECT_VALUE, EXPECT_ARRAY_ELEMENT)) {
|
||||
r = -EINVAL;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
ts = va_arg(ap, dual_timestamp*);
|
||||
|
||||
if (current->n_suppress == 0) {
|
||||
if (dual_timestamp_is_set(ts)) {
|
||||
r = sd_json_buildo(
|
||||
&add,
|
||||
SD_JSON_BUILD_PAIR("realtime", SD_JSON_BUILD_UNSIGNED(ts->realtime)),
|
||||
SD_JSON_BUILD_PAIR("monotonic", SD_JSON_BUILD_UNSIGNED(ts->monotonic)));
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else
|
||||
add = JSON_VARIANT_MAGIC_NULL;
|
||||
}
|
||||
|
||||
n_subtract = 1;
|
||||
|
||||
if (current->expect == EXPECT_TOPLEVEL)
|
||||
current->expect = EXPECT_END;
|
||||
else if (current->expect == EXPECT_OBJECT_VALUE)
|
||||
current->expect = EXPECT_OBJECT_KEY;
|
||||
else
|
||||
assert(current->expect == EXPECT_ARRAY_ELEMENT);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case _SD_JSON_BUILD_CALLBACK: {
|
||||
sd_json_build_callback_t cb;
|
||||
void *userdata;
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "format-util.h"
|
||||
#include "hostname-util.h"
|
||||
#include "json-util.h"
|
||||
#include "machine-varlink.h"
|
||||
#include "machined-varlink.h"
|
||||
#include "mkdir.h"
|
||||
#include "socket-util.h"
|
||||
#include "user-util.h"
|
||||
#include "varlink.h"
|
||||
#include "varlink-io.systemd.Machine.h"
|
||||
|
@ -383,6 +385,83 @@ static int vl_method_get_memberships(Varlink *link, sd_json_variant *parameters,
|
|||
return varlink_error(link, "io.systemd.UserDatabase.NoRecordFound", NULL);
|
||||
}
|
||||
|
||||
static int list_machine_one(Varlink *link, Machine *m, bool more) {
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(m);
|
||||
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
|
||||
|
||||
r = sd_json_buildo(
|
||||
&v,
|
||||
SD_JSON_BUILD_PAIR("name", SD_JSON_BUILD_STRING(m->name)),
|
||||
SD_JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(m->id), "id", SD_JSON_BUILD_ID128(m->id)),
|
||||
SD_JSON_BUILD_PAIR("class", SD_JSON_BUILD_STRING(machine_class_to_string(m->class))),
|
||||
SD_JSON_BUILD_PAIR_CONDITION(!!m->service, "service", SD_JSON_BUILD_STRING(m->service)),
|
||||
SD_JSON_BUILD_PAIR_CONDITION(!!m->root_directory, "rootDirectory", SD_JSON_BUILD_STRING(m->root_directory)),
|
||||
SD_JSON_BUILD_PAIR_CONDITION(!!m->unit, "unit", SD_JSON_BUILD_STRING(m->unit)),
|
||||
SD_JSON_BUILD_PAIR_CONDITION(pidref_is_set(&m->leader), "leader", SD_JSON_BUILD_UNSIGNED(m->leader.pid)),
|
||||
SD_JSON_BUILD_PAIR_CONDITION(dual_timestamp_is_set(&m->timestamp), "timestamp", JSON_BUILD_DUAL_TIMESTAMP(&m->timestamp)),
|
||||
SD_JSON_BUILD_PAIR_CONDITION(m->vsock_cid != VMADDR_CID_ANY, "vSockCid", SD_JSON_BUILD_UNSIGNED(m->vsock_cid)),
|
||||
SD_JSON_BUILD_PAIR_CONDITION(!!m->ssh_address, "sshAddress", SD_JSON_BUILD_STRING(m->ssh_address)));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (more)
|
||||
return varlink_notify(link, v);
|
||||
|
||||
return varlink_reply(link, v);
|
||||
}
|
||||
|
||||
static int vl_method_list(Varlink *link, sd_json_variant *parameters, VarlinkMethodFlags flags, void *userdata) {
|
||||
Manager *m = ASSERT_PTR(userdata);
|
||||
const char *mn = NULL;
|
||||
|
||||
const sd_json_dispatch_field dispatch_table[] = {
|
||||
{ "name", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, PTR_TO_SIZE(&mn), 0 },
|
||||
{}
|
||||
};
|
||||
|
||||
int r;
|
||||
|
||||
assert(parameters);
|
||||
|
||||
r = varlink_dispatch(link, parameters, dispatch_table, 0);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
if (mn) {
|
||||
if (!hostname_is_valid(mn, /* flags= */ VALID_HOSTNAME_DOT_HOST))
|
||||
return varlink_error_invalid_parameter_name(link, "name");
|
||||
|
||||
Machine *machine = hashmap_get(m->machines, mn);
|
||||
if (!machine)
|
||||
return varlink_error(link, "io.systemd.Machine.NoSuchMachine", NULL);
|
||||
|
||||
return list_machine_one(link, machine, /* more= */ false);
|
||||
}
|
||||
|
||||
if (!FLAGS_SET(flags, VARLINK_METHOD_MORE))
|
||||
return varlink_error(link, VARLINK_ERROR_EXPECTED_MORE, NULL);
|
||||
|
||||
Machine *previous = NULL, *i;
|
||||
HASHMAP_FOREACH(i, m->machines) {
|
||||
if (previous) {
|
||||
r = list_machine_one(link, previous, /* more= */ true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
previous = i;
|
||||
}
|
||||
|
||||
if (previous)
|
||||
return list_machine_one(link, previous, /* more= */ false);
|
||||
|
||||
return varlink_error(link, "io.systemd.Machine.NoSuchMachine", NULL);
|
||||
}
|
||||
|
||||
static int manager_varlink_init_userdb(Manager *m) {
|
||||
_cleanup_(varlink_server_unrefp) VarlinkServer *s = NULL;
|
||||
int r;
|
||||
|
@ -443,7 +522,10 @@ static int manager_varlink_init_machine(Manager *m) {
|
|||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to add UserDatabase interface to varlink server: %m");
|
||||
|
||||
r = varlink_server_bind_method(s, "io.systemd.Machine.Register", vl_method_register);
|
||||
r = varlink_server_bind_method_many(
|
||||
s,
|
||||
"io.systemd.Machine.Register", vl_method_register,
|
||||
"io.systemd.Machine.List", vl_method_list);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to register varlink methods: %m");
|
||||
|
||||
|
|
|
@ -16,10 +16,49 @@ static VARLINK_DEFINE_METHOD(
|
|||
VARLINK_DEFINE_INPUT(sshAddress, VARLINK_STRING, VARLINK_NULLABLE),
|
||||
VARLINK_DEFINE_INPUT(sshPrivateKeyPath, VARLINK_STRING, VARLINK_NULLABLE));
|
||||
|
||||
static VARLINK_DEFINE_STRUCT_TYPE(
|
||||
Timestamp,
|
||||
VARLINK_FIELD_COMMENT("Timestamp in µs in the CLOCK_REALTIME clock (wallclock)"),
|
||||
VARLINK_DEFINE_FIELD(realtime, VARLINK_INT, VARLINK_NULLABLE),
|
||||
VARLINK_FIELD_COMMENT("Timestamp in µs in the CLOCK_MONOTONIC clock"),
|
||||
VARLINK_DEFINE_FIELD(monotonic, VARLINK_INT, VARLINK_NULLABLE));
|
||||
|
||||
static VARLINK_DEFINE_METHOD(
|
||||
List,
|
||||
VARLINK_FIELD_COMMENT("If non-null the name of a running machine to report details on. If null/unspecified enumerates all running machines."),
|
||||
VARLINK_DEFINE_INPUT(name, VARLINK_STRING, VARLINK_NULLABLE),
|
||||
VARLINK_FIELD_COMMENT("Name of the machine"),
|
||||
VARLINK_DEFINE_OUTPUT(name, VARLINK_STRING, 0),
|
||||
VARLINK_FIELD_COMMENT("128bit ID identifying this machine, formatted in hexadecimal"),
|
||||
VARLINK_DEFINE_OUTPUT(id, VARLINK_STRING, VARLINK_NULLABLE),
|
||||
VARLINK_FIELD_COMMENT("Name of the software that registered this machine"),
|
||||
VARLINK_DEFINE_OUTPUT(service, VARLINK_STRING, VARLINK_NULLABLE),
|
||||
VARLINK_FIELD_COMMENT("The class of this machine"),
|
||||
VARLINK_DEFINE_OUTPUT(class, VARLINK_STRING, 0),
|
||||
VARLINK_FIELD_COMMENT("Leader process PID of this machine"),
|
||||
VARLINK_DEFINE_OUTPUT(leader, VARLINK_INT, VARLINK_NULLABLE),
|
||||
VARLINK_FIELD_COMMENT("Root directory of this machine, if known, relative to host file system"),
|
||||
VARLINK_DEFINE_OUTPUT(rootDirectory, VARLINK_STRING, VARLINK_NULLABLE),
|
||||
VARLINK_FIELD_COMMENT("The service manager unit this machine resides in"),
|
||||
VARLINK_DEFINE_OUTPUT(unit, VARLINK_STRING, VARLINK_NULLABLE),
|
||||
VARLINK_FIELD_COMMENT("Timestamp when the machine was activated"),
|
||||
VARLINK_DEFINE_OUTPUT_BY_TYPE(timestamp, Timestamp, VARLINK_NULLABLE),
|
||||
VARLINK_FIELD_COMMENT("AF_VSOCK CID of the machine if known and applicable"),
|
||||
VARLINK_DEFINE_OUTPUT(vSockCid, VARLINK_INT, VARLINK_NULLABLE),
|
||||
VARLINK_FIELD_COMMENT("SSH address to connect to"),
|
||||
VARLINK_DEFINE_OUTPUT(sshAddress, VARLINK_STRING, VARLINK_NULLABLE));
|
||||
|
||||
static VARLINK_DEFINE_ERROR(NoSuchMachine);
|
||||
static VARLINK_DEFINE_ERROR(MachineExists);
|
||||
|
||||
VARLINK_DEFINE_INTERFACE(
|
||||
io_systemd_Machine,
|
||||
"io.systemd.Machine",
|
||||
VARLINK_SYMBOL_COMMENT("A timestamp object consisting of both CLOCK_REALTIME and CLOCK_MONOTONIC timestamps"),
|
||||
&vl_type_Timestamp,
|
||||
&vl_method_Register,
|
||||
VARLINK_SYMBOL_COMMENT("List running machines"),
|
||||
&vl_method_List,
|
||||
VARLINK_SYMBOL_COMMENT("No matching machine currently running"),
|
||||
&vl_error_NoSuchMachine,
|
||||
&vl_error_MachineExists);
|
||||
|
|
|
@ -1,8 +1,15 @@
|
|||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
#
|
||||
# Make sure unix/* and vsock/* can be used to connect to AF_UNIX and AF_VSOCK paths
|
||||
# Allow connecting to the local host directly via ".host"
|
||||
Host .host machine/.host
|
||||
ProxyCommand {{LIBEXECDIR}}/systemd-ssh-proxy unix/run/ssh-unix-local/socket %p
|
||||
ProxyUseFdpass yes
|
||||
CheckHostIP no
|
||||
|
||||
# Make sure unix/* and vsock/* can be used to connect to AF_UNIX and AF_VSOCK paths.
|
||||
# Make sure machine/* can be used to connect to local machines registered in machined.
|
||||
#
|
||||
Host unix/* vsock/*
|
||||
Host unix/* vsock/* machine/*
|
||||
ProxyCommand {{LIBEXECDIR}}/systemd-ssh-proxy %h %p
|
||||
ProxyUseFdpass yes
|
||||
CheckHostIP no
|
||||
|
@ -10,9 +17,3 @@ Host unix/* vsock/*
|
|||
# Disable all kinds of host identity checks, since these addresses are generally ephemeral.
|
||||
StrictHostKeyChecking no
|
||||
UserKnownHostsFile /dev/null
|
||||
|
||||
# Allow connecting to the local host directly via ".host"
|
||||
Host .host
|
||||
ProxyCommand {{LIBEXECDIR}}/systemd-ssh-proxy unix/run/ssh-unix-local/socket %p
|
||||
ProxyUseFdpass yes
|
||||
CheckHostIP no
|
||||
|
|
|
@ -14,21 +14,19 @@
|
|||
#include "socket-util.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
#include "varlink.h"
|
||||
|
||||
static int process_vsock(const char *host, const char *port) {
|
||||
static int process_vsock_cid(unsigned cid, const char *port) {
|
||||
int r;
|
||||
|
||||
assert(host);
|
||||
assert(cid != VMADDR_CID_ANY);
|
||||
assert(port);
|
||||
|
||||
union sockaddr_union sa = {
|
||||
.vm.svm_cid = cid,
|
||||
.vm.svm_family = AF_VSOCK,
|
||||
};
|
||||
|
||||
r = vsock_parse_cid(host, &sa.vm.svm_cid);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse vsock cid: %s", host);
|
||||
|
||||
r = vsock_parse_port(port, &sa.vm.svm_port);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse vsock port: %s", port);
|
||||
|
@ -47,6 +45,21 @@ static int process_vsock(const char *host, const char *port) {
|
|||
|
||||
log_debug("Successfully sent AF_VSOCK socket via STDOUT.");
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static int process_vsock_string(const char *host, const char *port) {
|
||||
unsigned cid;
|
||||
int r;
|
||||
|
||||
assert(host);
|
||||
assert(port);
|
||||
|
||||
r = vsock_parse_cid(host, &cid);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse vsock cid: %s", host);
|
||||
|
||||
return process_vsock_cid(cid, port);
|
||||
}
|
||||
|
||||
static int process_unix(const char *path) {
|
||||
|
@ -124,6 +137,43 @@ static int process_vsock_mux(const char *path, const char *port) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int process_machine(const char *machine, const char *port) {
|
||||
_cleanup_(varlink_unrefp) Varlink *vl = NULL;
|
||||
int r;
|
||||
|
||||
assert(machine);
|
||||
assert(port);
|
||||
|
||||
r = varlink_connect_address(&vl, "/run/systemd/machine/io.systemd.Machine");
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to connect to machined on /run/systemd/machine/io.systemd.Machine: %m");
|
||||
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *result = NULL;
|
||||
r = varlink_callbo_and_log(
|
||||
vl,
|
||||
"io.systemd.Machine.List",
|
||||
&result,
|
||||
SD_JSON_BUILD_PAIR("name", SD_JSON_BUILD_STRING(machine)));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
uint32_t cid = VMADDR_CID_ANY;
|
||||
|
||||
const sd_json_dispatch_field dispatch_table[] = {
|
||||
{ "vSockCid", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uint32, PTR_TO_SIZE(&cid), 0 },
|
||||
{}
|
||||
};
|
||||
|
||||
r = sd_json_dispatch(result, dispatch_table, SD_JSON_ALLOW_EXTENSIONS, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse Varlink reply: %m");
|
||||
|
||||
if (cid == VMADDR_CID_ANY)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Machine has no AF_VSOCK CID assigned.");
|
||||
|
||||
return process_vsock_cid(cid, port);
|
||||
}
|
||||
|
||||
static int run(int argc, char* argv[]) {
|
||||
|
||||
log_setup();
|
||||
|
@ -135,7 +185,7 @@ static int run(int argc, char* argv[]) {
|
|||
|
||||
const char *p = startswith(host, "vsock/");
|
||||
if (p)
|
||||
return process_vsock(p, port);
|
||||
return process_vsock_string(p, port);
|
||||
|
||||
p = startswith(host, "unix/");
|
||||
if (p)
|
||||
|
@ -145,6 +195,10 @@ static int run(int argc, char* argv[]) {
|
|||
if (p)
|
||||
return process_vsock_mux(p, port);
|
||||
|
||||
p = startswith(host, "machine/");
|
||||
if (p)
|
||||
return process_machine(p, port);
|
||||
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Don't know how to parse host name specification: %s", host);
|
||||
}
|
||||
|
||||
|
|
|
@ -222,3 +222,6 @@ done
|
|||
(! machinectl read-only container1 "")
|
||||
(! machinectl read-only container1 foo)
|
||||
(! machinectl read-only container1 -- -1)
|
||||
|
||||
varlinkctl --more call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.List '{}'
|
||||
varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.List '{"name":".host"}'
|
||||
|
|
|
@ -53,6 +53,7 @@ mkdir -p /usr/share/empty.sshd /var/empty /var/empty/sshd /run/sshd
|
|||
|
||||
ssh -o StrictHostKeyChecking=no -v -i "$ROOTID" .host cat /etc/machine-id | cmp - /etc/machine-id
|
||||
ssh -o StrictHostKeyChecking=no -v -i "$ROOTID" unix/run/ssh-unix-local/socket cat /etc/machine-id | cmp - /etc/machine-id
|
||||
ssh -o StrictHostKeyChecking=no -v -i "$ROOTID" machine/.host cat /etc/machine-id | cmp - /etc/machine-id
|
||||
|
||||
modprobe vsock_loopback ||:
|
||||
if test -e /dev/vsock -a -d /sys/module/vsock_loopback ; then
|
||||
|
|
Loading…
Reference in a new issue