[tor-dev] RFC patch: systemd socket activation

Marti Raudsepp marti at juffo.org
Sun May 19 19:26:02 UTC 2013


Hi!

Thanks for the comments. Sorry if my reply is long-winded, but you
left me no other choice. :)

On Sun, May 19, 2013 at 6:55 PM, Jacob Appelbaum <jacob at appelbaum.net> wrote:
> Could you open a ticket on trac?

Done: https://trac.torproject.org/projects/tor/ticket/8908

> It seems to me that this requires a bit of documentation

Sure. Sorry, I should have included some info about how to use this thing :)

Since systemd has no way of knowing which ports Tor actually needs,
there needs to be another systemd unit file called tor.socket (in
addition to the regular tor.service)

Given for example a torrc:
SocksPort 9050
ControlPort 9051
TransPort 9040
DNSPort 9053

You need to have an accompanying tor.socket file with:
[Socket]
ListenStream=127.0.0.1:9050
ListenStream=127.0.0.1:9051
ListenStream=127.0.0.1:9040
ListenDatagram=127.0.0.1:9053
[Install]
WantedBy=sockets.target

Normally you'd put it in /etc/systemd/system.
Then run "systemctl daemon-reload; systemctl enable tor.socket"

The matching of listening ports to services is done in Tor based on
socket type, bind address and port.

If torrc has some ports that tor.socket doesn't define, then those
aren't involved in socket activation. But when Tor starts (e.g.
started manually or by activation on other ports), it will bind the
remaining ports as usual.

In other cases, if the two config files don't match up, Tor will log a
warning (and might fail to start up). Fortunately systemd provides
easy access to log messages (via "systemctl status tor")

> do you expect to run Tor as say, some-tor-user as usual (what is it on
> Fedora, anyway?)?

Yeah, it gets started as usual. The user is "tor" on Arch Linux, not
sure about Fedora. This is unrelated to socket activation.

An extra benefit of socket activation is that systemd can bind
privileged ports like 443 on behalf of Tor, even if Tor starts as an
unprivileged user.

> How do you expect UDP to be handled as Tor does not
> actually support UDP (excepting DNSPort, of course)

DNSPort is the use case I had in mind. If a ListenDatagram socket
doesn't match up to a DNSPort in torrc then a warning is logged and
the socket is closed.

> Do you expect this
> to be used by Tor only in client mode? Or do you expect it to be used by
> bridges or relays? It seems that socket activation is generally a
> reasonable idea - though I expect it will simply result in a Tor running
> nearly all of the time, no?

That's up to the user, really. I agree it's not very useful for
running a relay, but it doesn't hurt either.

I expect distros to ship a tor.socket file that matches their default
torrc configuration (just 9050) and use that by default. If the user
wants to customize it, they have to keep the two in sync, or use the
old way of launching it.

If it's installed with "systemctl enable tor.service" then it gets
started at boot. "systemctl enable tor.socket" will enable socket
activation.

> If nothing else, I suspect it will often
> allow the control port controllers to easily connect - even if Tor isn't
> started.

Yeah, I tried and it works nicely with Vidalia.

> If anything, we may have an easy way to ensure that any
> authorized Tor controller may start a Tor, which is actually quite nice!

Hmm, making sure that the starter is actually authorized can get
complicated. I'd prefer not having to write that dirty code. :)

> I have a bunch of questions that come to mind about anti-forensics - for
> example, if we restart Tor, what happens to data sitting in buffers in
> memory? The data stays queued, right?

During a restart all the client connections are dropped and their
buffers are presumably deallocated. Only the listen sockets persist.

But new inbound connects will be queued and any data sent on those
will be buffered in the kernel's TCP buffers as usual, until Tor
catches up and handles it. However, the data will stay in buffers
longer during startup. Not sure if this is a concern or not.

systemd itself doesn't buffer data, it only grabs the listening socket
and passes it on.

> How do we ensure that Tor, if
> started for SOCKS will allow only the right configurations?

Sorry, I don't understand this question.

> Will this
> need to be enabled on all Tor Gnu/Linux builds or should we only enable
> this code for systemd supporting systems and only with a configuration
> option, even if we have it compiled into Tor?

I think it's easiest to enable it always. There are no extra
dependencies and it doesn't do anything if it's not started by
systemd.

> src/ext/README should include information on the author as well as the
> original location of the source.

Will do.

---
> I suspect we want to ensure that we only include mqueue.h if we have it.
...
> What
> priviledges are required or set for /dev/mqueue I wonder?

This code is already disabled, I added this to sd-daemon.h:
#define SD_DAEMON_DISABLE_MQ 1

Now that you mention it, I realized that this doesn't work --
sd-daemon.h gets included too late. Will fix.

> There is a mix of !defined() and defined()
...
> Shouldn't 'foosddaemonhfoo' be a bit more... Torish? :)

Well this code (sd-daemon.c and .h) comes from systemd upstream; I
think we shouldn't modify it unless really necessary.

Or if we do want to modify it, we should just delete all the parts
that we don't use. Should I do that?

> I tend to prefer code like:
>  if (NULL != e) {
> to code like:
>  if (!e) {

> I also tend to be more specific with my ints - rather than int, why not
> uint32_t?

I tried to follow patterns already used in the connection.c file. File
descriptors, socket types, booleans and return codes seem to be using
type "int". Should I change them all or...?

> Furthermore - will the stats leave behind a trace?

The stats?

> Will all logging be redirected into the Tor logging subsystem?

Erm, I'm using Tor's log_* functions, so yes.

> This code seems to be optimized for your use path:
>
> +    s = get_pending_socket(type, socktype, &addr, usePort);
...
> +      s = tor_open_socket(tor_addr_family(&addr), socktype, is_tcp ?

> what happens if we never take your path? Is there a performance hit?

Well this code is only executed when the configuration gets loaded (at
startup/reload), once for each *Port definition. And the overhead is
pretty small if the pending_sockets list is empty (when not using
socket activation).

Doing it the other way around seems silly (try to bind the socket,
then go down the other path if it returned EADDRINUSE) and it seems
wouldn't work for UDP.

> When you apply this patch and enable debugging, do you see any warnings?

Do you mean "Log debug syslog", or what kind of debugging?

Apart from the fact that hibernation is broken (as stated in the
initial mail), I don't see any warnings.

> On what platform did you test it where you expect it to work? How about
> other platforms where it shouldn't work but also shouldn't do harm?

I tested this on Linux (Arch Linux x86_64)

On other platforms sd_listen_fds() will return 0, in which case it
works just as if socket activation isn't used.

Unfortunately I don't have a development environment on any other
platform, but I'm fairly confident it will work.

Regards,
Marti


More information about the tor-dev mailing list