Hi @Azrael,
sorry for the late reply, I was busy too - and this topic is not that trivial.
First I have to say that I'm not a pf
specialist, but mainly work with iptables/nftables
i.e. netfilter
. Their syntax, logic and semantic differ significantly. I played around with fwbuilder
, trying to migrate iptables
to pf
rules, but that wasn't really productive, so I tested the rules on my own. In the end, the following rule set turned out to be working:
int_if = vtnet0
# local net(s)
non_tor = "{ 192.168.0.0/24 }"
trans_port = 9040
dns_port = 1053
scrub in
rdr pass on { lo1 $int_if } inet proto tcp to !($int_if) -> 127.0.0.1 port $trans_port
rdr pass on lo0 inet proto udp to port domain -> 127.0.0.2 port $dns_port
# don't lock me out
pass in quick inet proto tcp to self port ssh
pass out quick inet proto tcp to self port ssh keep state
block return out
pass quick on { lo0 lo1 } keep state
pass out quick inet proto tcp user _tor flags S/SA modulate state
pass out quick route-to lo1 inet proto udp to port $dns_port keep state
pass out quick inet to $non_tor keep state
pass out route-to lo1 inet proto tcp all flags S/SA modulate state
I haven't tested if that set is really minimal. And I'm much too lazy to exlpain it in detail Note that the set is adapted for a single client working as a tor host, not for a router. In that case you would have to configure additional rules resp. change some rules.
The most important rules relate to NAT (rdr pass
) and PBR (route-to
), which in effect do the redirection of the traffic. Installing a separate dns server (I used bind916
) isn't really necessary, I just took over that (as the other configs and rules) from Shawn's excellent guide. But there is an inaccuracy, probably a typo:
rdr pass on lo0 inet proto udp to port domain -> 127.0.0.1 port 1053
This has to be 127.0.0.2, see the rule set above.
There are of course some system modifications needed:
# rc.conf
sshd_enable="YES"
pf_enable="YES"
named_enable="YES"
tor_enable="YES"
cloned_interfaces="lo1"
ifconfig_lo1="127.0.0.2"
# torrc
VirtualAddrNetwork 10.192.0.0/10
AutomapHostsOnResolve 1
TransPort 9040
DNSPort 127.0.0.2:1053
$ echo "supersede domain-name-servers 127.0.0.1;" > /etc/dhclient.conf
# configuring google's dns server as a forwarder isn't needed
After reboot, check if all is running properly:
$ sockstat -4l | egrep 'tor|bind'
# 9050: socks listener, 9040: transparent pf listener
_tor tor 1091 5 tcp4 127.0.0.1:9050 *:*
_tor tor 1091 6 udp4 127.0.0.2:1053 *:*
_tor tor 1091 7 tcp4 127.0.0.1:9040 *:*
bind named 815 26 udp4 127.0.0.1:53 *:*
Check if it's working as desired:
-
$ host juhanurmihxlp77nkq76byazcldy2hlmovfu2epvl5ankdibsot4csyd.onion
$ host juhanurmihxlp77nkq76byazcldy2hlmovfu2epvl5ankdibsot4csyd.onion 8.8.8.8
(compare the outputs on the tor host and on a non-tor host)
- If you have an external server under your control:
On the server: $ tcpdump port 42042
On the tor host: $ echo | telnet server 42042
(or use netcat
)
Then on the server you should see a line like this:
09:50:22.309110 IP tor-exit-62.for-privacy.net.21814 > server.fq.dn.42042: Flags [S] ...
(if port 42042 is blocked somewhere, try 443 instead)
For dumping traffic resp. checking for proper redirections, tcpdump
is an essential (magic) tool. As an admin, you can't miss it.