My IRC bouncer: systemd, znc, tor, socat

Background

IRC is the chat protocol I use everyday. I’d like to do it in a secure way, but xchat is really dumb, and doesn’t allow certificate pinning. Tor hidden services are great in this, because their name is also the proof of their identity; you can’t have MITM with them.

Then we have another problem: tor on a home ADSL connection is usually slow and unreliable. It’s annoying to have a client which disconnects from time to time.

As I have a server, I’ll run tor and irc on that server, using a bouncer. Then I’ll connect to the bouncer using his own tor hidden service; this time, even if the connection is unreliable, it’s not a big deal: my bouncer will stay fine, and I will not lose messages.

So here’s the plan: a debian box with “torified” znc; it will be used to connect to networks through tor.

Systemd

About systemd: on a plain wheezy installation, just apt-get install systemd systemd-sysv.

I love it: it’s easier to see the status of your machine, easier to write advanced configurations for your daemons, and I feel much more in control when restricting capabilities of my daemons is so easy.

Having to start from a “vanilla” box, I chose to use it, because I had to manage “complex” relationships between programs that don’t like to behave as daemons.

Znc

Znc is easy to install and configure; the bad part is that it is not easy to “torify” it, so we’ll just let him connect to socat, which will do the heavy job (just use localhost:4141)

Tor

Then we need to install tor, socat, znc.

Some notes about the following services:

  • socat -ly daemon is to make it use syslog
  • the restartsec is because we need the address to be freed

This is tor.service:

[Unit]
Description=Anonymizing Overlay Network
After=network.target

[Service]
Type=forking
GuessMainPID=yes
ExecStart=/usr/bin/tor -f /etc/tor/torrc --quiet
ExecReload=/bin/kill -HUP $MAINPID
KillSignal=SIGINT
LimitNOFILE=8192

[Install]
WantedBy=multi-user.target

This is znc.service

[Unit]
Description=IRC Bouncer
Requires=network.target
Wants=socat_torai.service

[Service]
Type=forking
User=znc
Group=znc
ExecStart=/usr/bin/znc

[Install]
WantedBy=multi-user.target

This, instead, is socat_torai.service

[Unit]
Description=Socket for a/i hidden service
Requires=tor.service

[Service]
Type=simple
User=nobody
Group=nogroup
ExecStart=/usr/bin/socat -lydaemon TCP4-LISTEN:4141,fork,bind=localhost SOCKS4A:localhost:wi7qkxyrdpu5cmvr.onion:6667,socksport=9050
NoNewPrivileges=true
RestartSec=5
Restart=on-failure

[Install]
WantedBy=multi-user.target

TODO and footnotes

  • If we really want to ensure that znc is totally torified, we should deny him access to net. This should be easy to do with systemd PrivateNetwork option
  • A bit of  security wouldn’t be bad: I’d like to deny as much as possible (/etc, /var/, …) using InaccessibleDirectories, but I still have not tested it
  • We could have used another approach for “torifying” znc, that is redsocks + some iptables rule. Maybe it would have been even easier.