Given a SOCKS proxy (such as tor), the goal is to selectively route packets through the SOCKS proxy by using iptables packet marking and mangling. The problem is that a SOCKS proxy operates at the OSI session layer 5 whilst iptables mainly operates on lower layers such as OSI layer 3 (for IP addresses) or 4 for ports - in other words, to bridge the gap, one would need some TCP/IP application layer software that will accept packets and push them through the SOCKS proxy.
ip
is available,/etc/init.d/badvpn-tun2socks
tun2socks
binary is placed at /usr/local/sbin/badvpn-tun2socks
badvpn is needed, either as a distribution package or compiled manually. This step can be skipped if the distribution provides binaries.
To compile manually on distributions that do not bundle badvpn
, clone the repository:
git clone https://github.com/ambrop72/badvpn.git
and then compile the source by issuing:
cd badvpn mkdir build cd build cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local -DBUILD_NOTHING_BY_DEFAULT=1 -DBUILD_TUN2SOCKS=1 make
and copy the badvpn-tun2socks
into /usr/local/sbin
. The compilation may require libnss3-dev
and libnspr4-dev
to be installed in order to succeed.
Next, copy the following contents into a file at /etc/systemd/system/tun2socks-tor1.service
:
[Unit] Description = Tun2Socks for Tor1 After = network.target [Service] # Configuration Environment=TUN_IF_NAME=tor1 Environment=TUN_IF_NETWORK=169.254.1.1/30 Environment=FW_MARK=0x32 Environment=RT_TABLE=tor1 Environment=TUN_IF_GATEWAY=169.254.1.2 Environment=TUN_IF_NETMASK=255.255.255.252 Environment=SOCKS_SERVER=127.0.0.1:9051 # Service settings Restart=always PIDFile = /var/run/tun2socks-tor1.pid User=root Group=root # Pre start (brings interfaces up and establishes routes). ExecStartPre = -/sbin/ip tuntap add dev ${TUN_IF_NAME} mode tun ExecStartPre = -/sbin/ip link set ${TUN_IF_NAME} up ExecStartPre = -/sbin/ip addr add ${TUN_IF_NETWORK} dev ${TUN_IF_NAME} ExecStartPre = -/sbin/ip rule add fwmark ${FW_MARK} lookup ${RT_TABLE} ExecStartPre = -/sbin/ip route add default via ${TUN_IF_GATEWAY} table ${RT_TABLE} # Start (starts tun2socks) ExecStart = /usr/local/sbin/badvpn-tun2socks --logger syslog --loglevel info --tundev ${TUN_IF_NAME} --netif-ipaddr ${TUN_IF_GATEWAY} --netif-netmask ${TUN_IF_NETMASK} --socks-server-addr ${SOCKS_SERVER} # Post stop (removes established routes and brings down interfaces). ExecStopPost = -/sbin/ip route del default via ${TUN_IF_GATEWAY} table ${RT_TABLE} ExecStopPost = -/sbin/ip rule del table ${RT_TABLE} ExecStopPost = -/sbin/ip addr del ${TUN_IF_NETWORK} dev ${TUN_IF_NAME} ExecStopPost = -/sbin/ip link set ${TUN_IF_NAME} down ExecStopPost = -/sbin/ip tuntap del dev ${TUN_IF_NAME} mode tun [Install] WantedBy = multi-user.target
and proceed to configure the file.
If you look at the newly created file at /etc/systemd/system/tun2socks-tor1.service
it contains the following section preceded by a Configuration
comment:
Environment=TUN_IF_NAME=tor1 Environment=TUN_IF_NETWORK=169.254.1.1/30 Environment=FW_MARK=0x32 Environment=RT_TABLE=tor1 Environment=TUN_IF_GATEWAY=169.254.1.2 Environment=TUN_IF_NETMASK=255.255.255.252 Environment=SOCKS_SERVER=127.0.0.1:9051
where:
TUN_IF_NAME
is the name of a virtual network interface that will be used to route packets through the SOCKS proxy,TUN_IF_NETWORK
is a network for the virtual network interface consisting in an IP address for the interface 169.254.1.1
and a netmask 30
,FW_MARK
is the packet marking that will be routed through the SOCKS proxy - in this case, in hex 0x32
is equivalent to 50
decimal,RT_TABLE
is the name of an iproute2 table defined usually in the file /etc/iproute2/rt_tables
.TUN_IF_GATEWAY
is the gateway of the virtual network interface,255.255.255.252
is the netmask of the virtual network interface and,127.0.0.1:9051
is the IP address and port where a SOCKS proxy will be listening
With the configuration explained, the file /etc/iproute2/rt_tables
has to be modified in order to define a routing table. Following the example, a new line would be added reading:
50 tor1
where:
50
is an identifying ID number (the same as the decimal value of FW_MARK
for simplicity's sake),tor1
is the name of the table and corresponds to the RT_TABLE
setting.
Similarly, a SOCKS proxy such as Tor can be setup to listen on the IP address 127.0.0.1
and port 9051
by editing the Tor configuration file commonly found at /etc/tor/torrc
:
SocksPort 127.0.0.1:9051
Now, with the table defined and the file /etc/systemd/system/tun2socks-tor1.service
edited to adjust the configuration, the following commands can be used to start tun2socks
:
systemctl enable tun2socks-tor1.service
systemctl start tun2socks-tor1
if all goes well, no output shall be returned - otherwise, systemctl
and journalctl
can be used to debug why the service has not started.
Following the example, one can check whether the TUN interface has been brought up by issuing:
ifconfig tor1
which should output something similar to:
tor1: flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST> mtu 1500 inet 169.254.1.1 netmask 255.255.255.252 destination 169.254.1.1 inet6 fe80::47a6:fb65:d814:aa06 prefixlen 64 scopeid 0x20<link> unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 txqueuelen 500 (UNSPEC) RX packets 0 bytes 0 (0.0 MiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 MiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
Next, to check that the routes have been applied properly, issue:
ip rule show
which should show an output similar to:
145: from all fwmark 0x32 lookup tor1
This says that all packets marked with the identifier 0x32
(or 50
in decimal) shall look up the table tor1
for routing decisions.
Now, to check that the table tor1
contains the desired routing decisions, issue:
ip route show table tor1
which should output something similar to:
default via 169.254.1.2 dev tor1
The systemd service file, performs the following operations in order:
tor1
,0x32
lookup a table named tor1
,169.254.1.2
and the device tor1
to the table tor1
.such that it is easy to check, given a potential failure, which command failed in the process of starting up the service.
Now, we can play around with packets, for instance, we can route all outbound SSH connections through the SOCKS proxy:
iptables -t mangle -A PREROUTING -p tcp --dport 22 -j MARK --set-mark 0x32
Or even route entire subnet traffic through the SOCKS proxy:
iptables -t mangle -A PREROUTING -s 192.168.2.0/24 -j MARK --set-mark 0x32
and so on and so forth.
The Squid proxy has a very interesting feature that allows traffic through the proxy to be marked depending on ACLs defined in the configuration.
For instance, using Squid, an ACL can be defined that matches the destination domain google.com
:
acl google dstdom google.com
Now, given the google
ACL, Squid can be told to mark all packets matching the ACL with an identifier, for instance, by adding the line:
tcp_outgoing_mark 0x32 google
Whenever a client behind the Squid proxy browses to google.com, all packets will be marked with the identifier 0x32
and they will then be, in turn, routed to the virtual network device tor1
where tun2socks
will pick up the connection and route it through the Tor SOCKS proxy listening on the IP 127.0.0.1
and port 9051
.
In essence, this method would allow passing requests from clients behind a Squid proxy to Tor without using an upstream helper proxy such as polipo
or privoxy
.
If Squid is configured to do SSL interception, then all bumped domains would have to be fetched directly, thereby loosing the ability to route the data through the Tor network. By using this setup, all direct requests made my Squid will fetch all resources through the Tor network and retain the privacy properties.