ssh-proxy: add support for connecting to VMs by AF_VSOCK via "machine/…" host specs

With this one can type "ssh machine/foobar" to connect to locally
registered machine "foobar" via SSH-over-AF_VSOCK.
This commit is contained in:
Lennart Poettering 2024-05-11 19:56:10 +02:00
parent 1c7642a3b7
commit 26b455d815
2 changed files with 70 additions and 15 deletions

View file

@ -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

View file

@ -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);
}