From socket(2) to .onion with pf(4)
Published:
I’ve been rebuilding my IRC bouncer setup and as part of this process I’ve
decided to connect to IRC via onion services where possible. This setup isn’t
intended to provide anonymity as once I’m connected I’m going to identify to
NickServ
anyway. I guess it provides a little protection in that my IP
address shouldn’t be visible in that gap between connection and a cloak
activating, but there’s so many other ways that my identity could leak.
You might wonder why I even bothered if not for anonymity. There are two reasons:
- to learn more about tor(1) and pf(4), and
- to figure out how to get non-proxy aware software to talk to onion services.
I often would find examples of socat, torsocks, etc. but none of them seemed to
fit with my goal of wanting to use an onion service as if it were just another
host on the Internet. By this I mean, with a socket(AF_INET, SOCK_STREAM)
that
didn’t also affect my ability to connect to other Internet hosts.
Onion services don’t have IP addresses. They have names that look like DNS names
but that are not actually in DNS. So the first problem here is going to be that
we’re not going to be able to give an onion address to the kernel, it wants an
IP address. In my setup I chose 10.10.10.0/24
as a subnet that will have IP
addresses that when connected to, will actually connect to onion services.
In the torrc file you can use MapAddress
to encode these mappings, for
example:
MapAddress 10.10.10.10 ajnvpgl6prmkb7yktvue6im5wiedlz2w32uhcwaamdiecdrfpwwgnlqd.onion # Freenode
MapAddress 10.10.10.11 dtlbunzs5b7s5sl775quwezleyeplxzicdoh3cnhm7feolxmkfd42nqd.onion # Hackint
MapAddress 10.10.10.12 awwqg2ishrohngue.onion # 2600net - broken(?)
MapAddress 10.10.10.13 darksci3bfoka7tw.onion # darkscience
MapAddress 10.10.10.14 akeyxc6hie26nlfylwiuyuf3a4tdwt4os7wiz3fsafijpvbgrkrzx2qd.onion # Indymedia
Now when tor(1) is asked to connect to 10.10.10.10
it will map this to the
address of Freenode’s onion service, and connect to that instead. The next part
of the problem is allowing tor(1) to receive these requests from a non-proxy
aware application, in my case ZNC. This setup will also need a network
interface to act as the interface to tor(1). A loopback interface will suffice
and it’s not necessary to add an IP address to it:
# ifconfig lo1 up
pf is a firewall for OpenBSD, that can also perform some other related
functions. One such function is called divert-to
. Unfortunately, there is
also divert-packet
which is completely unrelated. tor(1) supports receiving
packets that have been processed by a divert-to
rule and this is often used
for routing all traffic from a network through the Tor network. This
arrangement is known as a “transparent proxy” because the application is
unaware that anything is going on.
In my setup, I’m only routing traffic for specific onion services via the Tor network, but the same concepts are used.
In the torrc:
TransPort 127.0.0.1:1338
TransProxyType pf-divert
In pf.conf(5):
pass in quick on lo1 inet proto tcp all divert-to 127.0.0.1 port 1338
pass out inet proto tcp to 10.10.10.0/24 route-to lo1
and that’s it! I’m now able to connect to 10.10.10.10
from ZNC and pf
will divert the traffic to tor.
On names and TLS certificates: I’m using TLS to connect to the onion
services, but I’m not validating the certificates. I’ve already verified the
server identities because they have the key for the onion service, the reason
I’m using TLS is because I’m then presenting a client certificate to the
servers (CertFP) to log in to NickServ. The TLS is there for the server’s
benefit while the onion service authentication is for my benefit. You could add
entries to your /etc/hosts
file with mappings from irc.freenode.org
to
10.10.10.10
but it seemed like a bit of a fragile arrangement. If pf or
tor stop functioning currently, then no connection is made, but if the
/etc/hosts
file were to be rewritten, you’d then connect over the Internet
and you’ve disabled TLS verification because you’re relying on the onion
service to do that, which you’re not using.
On types of tranparent proxy: There are a few different types of
transparent proxy supported by tor. pf-divert
seemed like the most
appropriate one to use in my case. It’s possible that the
natd(8)
“protocol” referred to in the NATDPort
torrc option is actually talking
about divert(4) sockets which are
supported in OpenBSD, and that’s another option, but it’s not clear which would
be the preferred way to do it. If I had more time I’d dig into
which methods are useful and which are redundant as removing code is often a
good thing to do.