Re: s6, listen(8), etc.

From: Daniel Kahn Gillmor <dkg_at_fifthhorseman.net>
Date: Thu, 01 Sep 2016 01:52:55 -0400

Hi Laurent--

On Tue 2016-08-30 17:46:24 -0400, Laurent Bercot wrote:
> On 30/08/2016 22:51, Daniel Kahn Gillmor wrote:
>> Thanks, once i make it past the angry words, this page has some
>> interesting ideas to work from.
>
> My words have all the right in the world to be angry;

no one is objecting to you being angry -- that is absolutely your right!
I was just observing that it takes me extra work+time to read through
the anger and into the technical discussion.

> All I can find about it is the sd_listen_fds() man page, which says:
> "Internally, ... otherwise, it parses the number passed in the $LISTEN_FDS
> environment variable..."
> In other words, this is internal workings of systemd, this is not an
> official API. If at some point systemd decides to change how sd_listen_fds()
> is implemented, all the other software relying on LISTEN_FDS will just have
> to adapt.

no one has said that this is an "official API" -- i never called it that
either. I said it was a "convention", and it's one that would be very
difficult to actually make backwards-incompatible change to (for reasons
i can go into later if you're interested).

> Even if that convention never changes, a bigger issue is that this use
> of an environment variable presupposes an architecture that is similar
> to systemd. A daemon that uses sd_listen_fds() will connect to some
> hardcoded path to a Unix domain socket to receive the descriptors over
> (and if it's not hardcoded, it needs to be given in another environment
> variable such as NOTIFY_SOCKET), which means the supervision architecture
> also has to provide a daemon that transmits the fds over that socket,
> etc.

I think you might have misunderstood the description of the convention,
actually. There's no unix domain socket for receiving the descriptors
at all. Rather, the descriptors are already open and present in the
process.

This is how listen(8) will work as well.

yes, there are additional features (if you want them) whereby a process
can hand its file descriptor back to another process to hold on to, and
then retrieve them again later if they really want, and you're right
that some of those workflows would require the kind of fd-passing that
you're describing.

But the underlying assumptions of the standard workflow come from the
standard unix design of fork(2), exec(2), dup(2), and environment
variables, and nothing more. it's unix ;)

> etc. In other words, either the supervision architecture looks very much
> like systemd, or the protocol is unusable.

I don't think that's the case. As a particular example, i'm envisioning
launching the knot resolver as a runit-supervised service with a ./run
script something like this:

    #!/bin/sh
    mkdir -p /run/kresd/workdir && \
    setfacl -m u:kresd:rwx /run/kresd/workdir && \
    cd /run/kresd/workdir && \
    exec listen -udp::53 \
                -tcp::53 \
                -tcp:label=tls:853 \
                -unix:label=control,mode=0600:/run/kresd/control \
    chpst -u kresd -p 1 \
    /usr/sbin/kresd

This means kresd doesn't need to know about dropping privileges, opening
listening ports, or resource constraints at all (listen and chpst take
care of that), but kresd can still retain in-memory state that might be
useful for handling multiple connections with no exec() ever involved.

Even better, kresd can now offer neat tricks like universal DNS
resolution over a unix-domain datagram socket without any change to
kresd at all, just an additional line in the ./run script:

   -unix:mode=0666:/run/kresd/query.socket \

> LISTEN_FDS, just as NOTIFY_SOCKET, may seem very simple and innocuous
> protocols at first sight, but when you look a bit deeper, you find that
> they are designed to tighten systemd's monopoly: if you have an alternative,
> it has to exactly copy systemd's workings in order to be able to correctly
> implement the protocols - and at this point, designing an alternative is
> simply useless.

I'm afraid i don't see that here, sorry :/ All listen is doing is
opening file descriptors and setting environment variables according to
a simple convention.

> s6 already provides a complete set of fd-holding tools.
> If you have a s6-fdholderd process running, you can give it descriptors
> via the s6-fdholder-store command, and get descriptors from it via the
> s6-fdholder-retrieve command. Those commands are chain-loading, so it's
> easy to call them sequentially to put your process in the exact state
> you want it, with all the descriptors you need in the right place, before
> exec'ing into your daemon. It's how s6-rc works internally.

Hm, i don't see a way to communicate to your daemon which sockets are to
be used for what purpose. Using kresd above as an example, what if you
wanted your daemon to offer dns-over-tls on TCP port 443 as well? what
if you wanted to offer a second control socket in an unusual location
with unusual ownership or permissions?

All the best,

        --dkg
Received on Thu Sep 01 2016 - 05:52:55 UTC

This archive was generated by hypermail 2.3.0 : Sun May 09 2021 - 19:44:19 UTC