From: Daan De Meyer Date: Thu, 19 Feb 2026 09:54:07 +0000 (+0100) Subject: ssh-proxy: Support ssh machine/xxx for nspawn containers X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e6be5fb7200fb02e78e4f27f49a4d734b7b850a0;p=thirdparty%2Fsystemd.git ssh-proxy: Support ssh machine/xxx for nspawn containers --- diff --git a/src/basic/stat-util.c b/src/basic/stat-util.c index f50b64e4846..43f82dd9268 100644 --- a/src/basic/stat-util.c +++ b/src/basic/stat-util.c @@ -157,6 +157,11 @@ int stat_verify_socket(const struct stat *st) { return 0; } +int is_socket(const char *path) { + assert(!isempty(path)); + return verify_stat_at(AT_FDCWD, path, /* follow= */ true, stat_verify_socket, /* verify= */ false); +} + int stat_verify_linked(const struct stat *st) { assert(st); diff --git a/src/basic/stat-util.h b/src/basic/stat-util.h index e4138e960a3..0e4bec513b1 100644 --- a/src/basic/stat-util.h +++ b/src/basic/stat-util.h @@ -21,6 +21,7 @@ int fd_verify_symlink(int fd); int is_symlink(const char *path); int stat_verify_socket(const struct stat *st); +int is_socket(const char *path); int stat_verify_linked(const struct stat *st); int fd_verify_linked(int fd); diff --git a/src/ssh-generator/ssh-proxy.c b/src/ssh-generator/ssh-proxy.c index 219e523d6b3..337153787ec 100644 --- a/src/ssh-generator/ssh-proxy.c +++ b/src/ssh-generator/ssh-proxy.c @@ -11,7 +11,9 @@ #include "log.h" #include "main-func.h" #include "path-lookup.h" +#include "path-util.h" #include "socket-util.h" +#include "stat-util.h" #include "string-util.h" #include "strv.h" #include "time-util.h" @@ -309,27 +311,65 @@ static int process_machine(const char *machine, const char *port) { assert(port); _cleanup_(sd_json_variant_unrefp) sd_json_variant *result = NULL; - r = fetch_machine(machine, RUNTIME_SCOPE_USER, &result); - if (r == -ESRCH) - r = fetch_machine(machine, RUNTIME_SCOPE_SYSTEM, &result); + RuntimeScope scope = RUNTIME_SCOPE_USER; + r = fetch_machine(machine, scope, &result); + if (r == -ESRCH) { + scope = RUNTIME_SCOPE_SYSTEM; + r = fetch_machine(machine, scope, &result); + } if (r < 0) return r; - uint32_t cid = VMADDR_CID_ANY; + struct { + uint32_t cid; + const char *class; + const char *service; + } p = { + .cid = VMADDR_CID_ANY, + }; static const sd_json_dispatch_field dispatch_table[] = { - { "vSockCid", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uint32, 0, 0 }, - {} + { "vSockCid", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uint32, voffsetof(p, cid), 0 }, + { "class", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, voffsetof(p, class), SD_JSON_MANDATORY }, + { "service", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, voffsetof(p, service), 0 }, }; - r = sd_json_dispatch(result, dispatch_table, SD_JSON_ALLOW_EXTENSIONS, &cid); + r = sd_json_dispatch(result, dispatch_table, SD_JSON_ALLOW_EXTENSIONS, &p); if (r < 0) return log_error_errno(r, "Failed to parse Varlink reply: %m"); - if (cid == VMADDR_CID_ANY) + if (streq(p.class, "container")) { + _cleanup_free_ char *path = NULL; + + if (!streq_ptr(p.service, "systemd-nspawn")) + return log_error_errno(SYNTHETIC_ERRNO(EMEDIUMTYPE), "Don't know how to SSH into '%s' container %s.", p.service, machine); + + r = runtime_directory_generic(scope, "systemd/nspawn/unix-export", &path); + if (r < 0) + return log_error_errno(r, "Failed to determine runtime directory: %m"); + + if (!path_extend(&path, machine, "ssh")) + return log_oom(); + + r = is_socket(path); + if (r < 0) + return log_error_errno(r, "Failed to check if '%s' exists and is a socket: %m", path); + if (r == 0) + return log_error_errno( + SYNTHETIC_ERRNO(ENOENT), + "'%s' does not exist or is not a socket, are sshd and systemd-ssh-generator installed and enabled in the container?", + path); + + return process_unix(path); + } + + if (!streq(p.class, "vm")) + return log_error_errno(SYNTHETIC_ERRNO(EMEDIUMTYPE), "Don't know how to SSH into machine %s with class '%s'.", machine, p.class); + + if (p.cid == VMADDR_CID_ANY) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Machine %s has no AF_VSOCK CID assigned.", machine); - return process_vsock_cid(cid, port); + return process_vsock_cid(p.cid, port); } static char *startswith_sep(const char *s, const char *prefix) {