['systemd-socket-proxyd', '8', [], ''],
['systemd-soft-reboot.service', '8', [], ''],
['systemd-ssh-generator', '8', [], ''],
+ ['systemd-ssh-proxy', '1', [], ''],
['systemd-stdio-bridge', '1', [], ''],
['systemd-storagetm.service', '8', ['systemd-storagetm'], 'ENABLE_STORAGETM'],
['systemd-stub',
--- /dev/null
+<?xml version='1.0'?> <!--*-nxml-*-->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+ "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
+
+<refentry id="systemd-ssh-proxy"
+ xmlns:xi="http://www.w3.org/2001/XInclude">
+
+ <refentryinfo>
+ <title>systemd-ssh-proxy</title>
+ <productname>systemd</productname>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>systemd-ssh-proxy</refentrytitle>
+ <manvolnum>1</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname>systemd-ssh-proxy</refname>
+ <refpurpose>SSH client plugin for connecting to <constant>AF_VSOCK</constant> and
+ <constant>AF_UNIX</constant> sockets</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <programlisting>
+Host unix/* vsock/*
+ ProxyCommand /usr/lib/systemd/systemd-ssh-proxy %h %p
+ ProxyUseFdpass yes
+</programlisting>
+ <cmdsynopsis>
+ <command>/usr/lib/systemd/systemd-ssh-proxy</command> <arg>ADDRESS</arg> <arg>PORT</arg>
+ </cmdsynopsis>
+ </refsynopsisdiv>
+
+
+ <refsect1>
+ <title>Description</title>
+
+ <para><command>systemd-ssh-proxy</command> is a small "proxy" plugin for the <citerefentry
+ project="man-pages"><refentrytitle>ssh</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ tool that allows connecting to <constant>AF_UNIX</constant> and <constant>AF_VSOCK</constant> sockets. It
+ implements the interface defined by <filename>ssh</filename>'s <varname>ProxyCommand</varname>
+ configuration option. It's supposed to be used with an <citerefentry
+ project="man-pages"><refentrytitle>ssh_config</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ configuration fragment like the following:</para>
+
+ <programlisting>
+Host unix/* vsock/*
+ ProxyCommand /usr/lib/systemd/systemd-ssh-proxy %h %p
+ ProxyUseFdpass yes
+ CheckHostIP no
+
+Host .host
+ ProxyCommand /usr/lib/systemd/systemd-ssh-proxy unix/run/ssh-unix-local/socket %p
+ ProxyUseFdpass yes
+ CheckHostIP no
+</programlisting>
+
+ <para>A configuration fragment along these lines is by default installed into
+ <filename>/etc/ssh/ssh_config.d/20-systemd-ssh-proxy.conf.in</filename>.</para>
+
+ <para>With this in place, SSH connections to host string <literal>unix/</literal> followed by an absolute
+ <constant>AF_UNIX</constant> file system path to a socket will be directed to the specified socket, which
+ must be of type <constant>SOCK_STREAM</constant>. Similar, SSH connections to <literal>vsock/</literal>
+ followed by an <constant>AF_VSOCK</constant> CID will result in an SSH connection made to that
+ CID. Moreover connecting to <literal>.host</literal> will connect to the local host via SSH, without
+ involving networking.</para>
+
+ <para>This tool is supposed to be used together with
+ <citerefentry><refentrytitle>systemd-ssh-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ which when run inside a VM or container will bind SSH to suitable
+ addresses. <command>systemd-ssh-generator</command> is supposed to run in the container of VM guest, and
+ <command>systemd-ssh-proxy</command> is run on the host, in order to connect to the container or VM
+ guest.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>Exit status</title>
+
+ <para>On success, 0 is returned, a non-zero failure code
+ otherwise.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>Examples</title>
+
+ <example>
+ <title>Talk to a local VM with CID 4711</title>
+
+ <programlisting>ssh vsock/4711</programlisting>
+ </example>
+
+ <example>
+ <title>Talk to the local host via ssh</title>
+
+ <programlisting>ssh .host</programlisting>
+
+ <para>or equivalent:</para>
+
+ <programlisting>ssh unix/run/ssh-unix-local/socket</programlisting>
+ </example>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+ <para><simplelist type="inline">
+ <member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
+ <member><citerefentry><refentrytitle>systemd-ssh-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
+ <member><citerefentry project="man-pages"><refentrytitle>vsock</refentrytitle><manvolnum>7</manvolnum></citerefentry></member>
+ <member><citerefentry project="man-pages"><refentrytitle>unix</refentrytitle><manvolnum>7</manvolnum></citerefentry></member>
+ <member><citerefentry project="man-pages"><refentrytitle>ssh</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
+ <member><citerefentry project="man-pages"><refentrytitle>sshd</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
+ </simplelist></para>
+ </refsect1>
+</refentry>
pamconfdir = prefixdir / 'lib/pam.d'
endif
+sshconfdir = get_option('sshconfdir')
+if sshconfdir == ''
+ sshconfdir = sysconfdir / 'ssh/ssh_config.d'
+endif
+
sshdconfdir = get_option('sshdconfdir')
if sshdconfdir == ''
sshdconfdir = sysconfdir / 'ssh/sshd_config.d'
conf.set_quoted('RANDOM_SEED', randomseeddir / 'random-seed')
conf.set_quoted('RANDOM_SEED_DIR', randomseeddir)
conf.set_quoted('RC_LOCAL_PATH', get_option('rc-local'))
+conf.set_quoted('SSHCONFDIR', sshconfdir)
conf.set_quoted('SSHDCONFDIR', sshdconfdir)
conf.set_quoted('SYSCONF_DIR', sysconfdir)
conf.set_quoted('SYSCTL_DIR', sysctldir)
'SysV rc?.d directories' : sysvrcnd_path,
'PAM modules directory' : pamlibdir,
'PAM configuration directory' : pamconfdir,
- 'ssh configuration directory' : sshdconfdir,
+ 'ssh server configuration directory' : sshdconfdir,
+ 'ssh client configuration directory' : sshconfdir,
'libcryptsetup plugins directory' : libcryptsetup_plugins_dir,
'RPM macros directory' : rpmmacrosdir,
'modprobe.d directory' : modprobedir,
description : 'directory for PAM modules')
option('pamconfdir', type : 'string',
description : 'directory for PAM configuration ["no" disables]')
+option('sshconfdir', type : 'string',
+ description : 'directory for SSH client configuration ["no" disables]')
option('sshdconfdir', type : 'string',
description : 'directory for SSH server configuration ["no" disables]')
option('libcryptsetup-plugins-dir', type : 'string',
--- /dev/null
+# 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
+#
+Host unix/* vsock/*
+ ProxyCommand {{LIBEXECDIR}}/systemd-ssh-proxy %h %p
+ ProxyUseFdpass yes
+ CheckHostIP no
+
+ # 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
'name' : 'systemd-ssh-generator',
'sources' : files('ssh-generator.c'),
},
+ libexec_template + {
+ 'name' : 'systemd-ssh-proxy',
+ 'sources' : files('ssh-proxy.c'),
+ },
]
+
+custom_target(
+ '20-systemd-ssh-proxy.conf',
+ input : '20-systemd-ssh-proxy.conf.in',
+ output : '20-systemd-ssh-proxy.conf',
+ command : [jinja2_cmdline, '@INPUT@', '@OUTPUT@'],
+ install : true,
+ install_dir : libexecdir / 'ssh_config.d')
+
+install_emptydir(sshconfdir)
+
+meson.add_install_script(sh, '-c',
+ ln_s.format(libexecdir / 'ssh_config.d' / '20-systemd-ssh-proxy.conf', sshconfdir / '20-systemd-ssh-proxy.conf'))
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <net/if_arp.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "fd-util.h"
+#include "iovec-util.h"
+#include "log.h"
+#include "main-func.h"
+#include "missing_socket.h"
+#include "parse-util.h"
+#include "socket-util.h"
+#include "string-util.h"
+#include "strv.h"
+
+static int process_vsock(const char *host, const char *port) {
+ int r;
+
+ assert(host);
+ assert(port);
+
+ union sockaddr_union sa = {
+ .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);
+
+ _cleanup_close_ int fd = socket(AF_VSOCK, SOCK_STREAM|SOCK_CLOEXEC, 0);
+ if (fd < 0)
+ return log_error_errno(errno, "Failed to allocate AF_VSOCK socket: %m");
+
+ if (connect(fd, &sa.sa, SOCKADDR_LEN(sa)) < 0)
+ return log_error_errno(errno, "Failed to connect to vsock:%u:%u: %m", sa.vm.svm_cid, sa.vm.svm_port);
+
+ /* OpenSSH wants us to send a single byte along with the file descriptor, hence do so */
+ r = send_one_fd_iov(STDOUT_FILENO, fd, &IOVEC_NUL_BYTE, /* n_iovec= */ 1, /* flags= */ 0);
+ if (r < 0)
+ return log_error_errno(r, "Failed to send socket via STDOUT: %m");
+
+ log_debug("Successfully sent AF_VSOCK socket via STDOUT.");
+ return 0;
+}
+
+static int process_unix(const char *path) {
+ int r;
+
+ assert(path);
+
+ /* We assume the path is absolute unless it starts with a dot (or is already explicitly absolute) */
+ _cleanup_free_ char *prefixed = NULL;
+ if (!STARTSWITH_SET(path, "/", "./")) {
+ prefixed = strjoin("/", path);
+ if (!prefixed)
+ return log_oom();
+
+ path = prefixed;
+ }
+
+ _cleanup_close_ int fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
+ if (fd < 0)
+ return log_error_errno(errno, "Failed to allocate AF_UNIX socket: %m");
+
+ r = connect_unix_path(fd, AT_FDCWD, path);
+ if (r < 0)
+ return log_error_errno(r, "Failed to connect to AF_UNIX socket %s: %m", path);
+
+ r = send_one_fd_iov(STDOUT_FILENO, fd, &IOVEC_NUL_BYTE, /* n_iovec= */ 1, /* flags= */ 0);
+ if (r < 0)
+ return log_error_errno(r, "Failed to send socket via STDOUT: %m");
+
+ log_debug("Successfully sent AF_UNIX socket via STDOUT.");
+ return 0;
+}
+
+static int run(int argc, char* argv[]) {
+
+ log_setup();
+
+ if (argc != 3)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Expected two arguments: host and port.");
+
+ const char *host = argv[1], *port = argv[2];
+
+ const char *p = startswith(host, "vsock/");
+ if (p)
+ return process_vsock(p, port);
+
+ p = startswith(host, "unix/");
+ if (p)
+ return process_unix(p);
+
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Don't know how to parse host name specification: %s", host);
+}
+
+DEFINE_MAIN_FUNCTION(run);
--- /dev/null
+# This file is part of systemd.
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+
+# See tmpfiles.d(5) for details
+
+L {{SSHCONFDIR}}/20-systemd-ssh-proxy.conf - - - - {{LIBEXECDIR}}/ssh_config.d/20-systemd-ssh-proxy.conf
['systemd.conf', ''],
['var.conf', ''],
['20-systemd-userdb.conf', 'ENABLE_USERDB'],
+ ['20-systemd-ssh-generator.conf', ''],
]
foreach pair : in_files