Discussion:
Unix socket support for sshd
(too old to reply)
David Goulet
2016-02-04 12:40:39 UTC
Permalink
Greetings everyone!

I would like to know if adding support for Unix socket to sshd would be a
feature that would be consider to be added upstream? (ListenAddress).

One of the main reason for this question to you all is that tor now has Unix
socket support for hidden services that is traffic of a hidden service can be
forwarded to a Unix socket (see HiddenServicePort in tor.1). The rationale
behind that is basically so someone can set up a server with no inet traffic
allowed (firewall, namespace, <insert sandboxing tech>) _except_ for the tor
daemon and use hidden service to access services on the local machine using
only Unix socket, in this case ssh.

That being said, if you wouldn't object to this feature being added to ssh,
I'm willing to implement it and make the efforts for upstream merge. But
before I do start the work, I would like to make sure it's something that
won't get an automatic NACK just based on the original idea :).

Big thanks!
David
Daniel Kahn Gillmor
2016-02-04 15:46:55 UTC
Permalink
Post by David Goulet
I would like to know if adding support for Unix socket to sshd would be a
feature that would be consider to be added upstream? (ListenAddress).
fwiw, i think this is a good idea, but i wouldn't implement it as an
explicit ListenAddress option: i'd rather have sshd be able to listen on
an inherited file descriptor. This would allow generic socket
activation, regardless of socket type.

--dkg
Ron Frederick
2016-02-04 15:57:21 UTC
Permalink
Post by Daniel Kahn Gillmor
Post by David Goulet
I would like to know if adding support for Unix socket to sshd would be a
feature that would be consider to be added upstream? (ListenAddress).
fwiw, i think this is a good idea, but i wouldn't implement it as an
explicit ListenAddress option: i'd rather have sshd be able to listen on
an inherited file descriptor. This would allow generic socket
activation, regardless of socket type.
Can’t this already be done with “sshd -i”, by passing in the socket via stdin/stdout? A simple wrapper which listened on the UNIX domain socket could fork & exec “sshd -i” as new UNIX domain socket connections arrived, similar to inetd.
--
Ron Frederick
***@timeheart.net
David Goulet
2016-02-04 16:00:27 UTC
Permalink
Post by Daniel Kahn Gillmor
Post by David Goulet
I would like to know if adding support for Unix socket to sshd would be a
feature that would be consider to be added upstream? (ListenAddress).
fwiw, i think this is a good idea, but i wouldn't implement it as an
explicit ListenAddress option: i'd rather have sshd be able to listen on
an inherited file descriptor. This would allow generic socket
activation, regardless of socket type.
Hrm... not sure I fully understand here. How would sshd inherited an fd? And
what do you mean by "allow generic socket activation"? If I understand it,
wouldn't that require a wrapper over sshd?

Let's assume I set up an sshd and want it to use Unix socket in
/foo/bar/ssh.sock, how would that work without me being able to specify
somewhere the path?

Thanks!
David
Post by Daniel Kahn Gillmor
--dkg
Daniel Kahn Gillmor
2016-02-04 16:25:36 UTC
Permalink
Post by Ron Frederick
Post by Daniel Kahn Gillmor
fwiw, i think this is a good idea, but i wouldn't implement it as an
explicit ListenAddress option: i'd rather have sshd be able to listen on
an inherited file descriptor. This would allow generic socket
activation, regardless of socket type.
Can’t this already be done with “sshd -i”, by passing in the socket
via stdin/stdout? A simple wrapper which listened on the UNIX domain
socket could fork & exec “sshd -i” as new UNIX domain socket
connections arrived, similar to inetd.
I've done this before (and even had ssh running over the serial console
with it), but forking and exec'ing a new sshd instance for each
connection is rather different from having a running sshd that can make
overall decisions about the state of the machine (e.g. MaxStartups in
sshd_config(5)), and it also requires a bunch of initial setup work each
time a connection comes in.

socket activation handed off to a single running master daemon addresses
both of these legit engineering concerns better than an inetd-spawned
"sshd -i" would.

--dkg
Daniel Kahn Gillmor
2016-02-04 17:31:12 UTC
Permalink
Post by David Goulet
Post by Daniel Kahn Gillmor
Post by David Goulet
I would like to know if adding support for Unix socket to sshd would be a
feature that would be consider to be added upstream? (ListenAddress).
fwiw, i think this is a good idea, but i wouldn't implement it as an
explicit ListenAddress option: i'd rather have sshd be able to listen on
an inherited file descriptor. This would allow generic socket
activation, regardless of socket type.
Hrm... not sure I fully understand here. How would sshd inherited an fd? And
what do you mean by "allow generic socket activation"? If I understand it,
wouldn't that require a wrapper over sshd?
Let's assume I set up an sshd and want it to use Unix socket in
/foo/bar/ssh.sock, how would that work without me being able to specify
somewhere the path?
The most common toolchain for doing this sort of thing today on
GNU/Linux systems is systemd, which acts as pid 1.

systemd's pid 1 instance is configured to know which sockets will be
listened for by all the daemons on the host, and it pre-opens all of
those sockets. Then, when a connection is made to a socket that it
knows should belong to a daemon, if that daemon isn't already running,
it spawns (fork/execs) it, handing over the relevant socket(s) to the
daemon as a file descriptor during startup.

There are several advantages to this:

* if the daemon can be run in a non-privileged mode, it can start in
the non-privileged mode from the beginning. no need for each daemon
to need to start privileged to grab the relevant socket and then drop
privileges. we've seen many bugs around daemons not properly
dropping privileges

* no race for grabbing the socket. In the event that multiple daemons
are want to listen on the same socket, there's a predictable arbiter
(pid 1) who decides where the socket gets passed to, and other
daemons that try to listen on that socket get rejected, because the
socket is already busy.

* before any daemons are running, the sockets are opened for incoming
connections. This means there will be much smaller (possibly
non-existent) window of time during system startup or daemon restart
where the socket itself is closed. Connections made to these sockets
before the associated daemon starts up will of course hang until the
daemon gets around to responding, but the system won't reject the
connections.

* socket activation also enables the OS to selectively start services
on an as-needed basis. If daemon X depends on daemon Y operationally
(because X needs to talk to Y over Y's listening socket), there is no
need for explicit representation of this startup dependency --
rather, the daemons are spawned as the first connections come in.

Note that the daemon management service (what systemd's pid 1 provides)
needs some way to communicate to the spawned daemon which file
descriptors it has inherited should be treated as listeners. for
systemd, this is a contiguious block of file descriptors starting at fd
3 (SD_LISTEN_FDS_START), and the enviornment variable LISTEN_FDS is a
decimal number indicating how many file descriptors to use for listening
(see sd_listen_fds(3) from libsystemd for more detail).

A reasonable approach that would avoid linking in libsystemd might be to
just specify something like ListenFDs N:M (meaning file descriptors N
through M are sockets you should listen on). (perhaps -L N:M on the
command line, so that the config file could stay static and the spawning
daemon manager could dynamically adjust the invocation as sockets were
added or removed)

--dkg
Darren Tucker
2016-02-05 00:11:13 UTC
Permalink
On Fri, Feb 5, 2016 at 2:57 AM, Ron Frederick <***@timeheart.net> wrote:
[...]
Post by Ron Frederick
Can’t this already be done with “sshd -i”, by passing in the socket via stdin/stdout?
yes.
Post by Ron Frederick
similar to inetd.
Looks like inetd on many BSDs and some implementations on Linux
already support listening on unix domain sockets.
--
Darren Tucker (dtucker at zip.com.au)
GPG key 8FF4FA69 / D9A3 86E9 7EEE AF4B B2D4 37C9 C982 80C7 8FF4 FA69
Good judgement comes with experience. Unfortunately, the experience
usually comes from bad judgement.
Loading...