The usual Linux penguins are not cute enough, so we have a cuter polar animal for this post.
So, I did some truly evil things to my network yesterday. :-D
Physical setup
The main computer is runs Ubuntu Linux and has two 100MBit ethernet interfaces, eth0 and eht1. eth0 is connected to the laptop, eth1 is connected to the router.
Laptop runs Windows XP, and is connected to the main computer.
The router is overfirewalled in a particularly fascist way and is beyond my control. This was the reason why I did the whole hack thing.
Somewhere on the Internet there are
HTTP Tunnel servers. Everyone can connect to them using encrypted connections to port 80, for greater anonymity or simply to get around stupid firewalls.
Layer 1
The first layer of the setup was just a normal network.
Router gives the main computer IP through DHCP. Desktop-laptop connection is statically set up,
I may change it to use DHCP later, but it's more convienient to leave it static during frequent reconfiguration time.
Desktop is NATing laptop, and is getting NATed by router, nothing unusual:
ifconfig eth0 192.168.1.1
echo 1 >/proc/sys/net/ipv4/ip_forward
iptables -t nat -A POSTROUTING -j MASQUERADE -o eth1
Layer 2
Now let's get to the funny things. The unfortunate thing is that HTTP Tunnel client runs only on Windows. If it wasn't for that, there would be no need to have a setup as elaborate as this.
So I installed HTTP Tunnel on the laptop. It provides SOCKS4/5 server on 192.168.1.2:1080.
Now it is possible to anonymously use the Internet from either the laptop or the desktop, at least from the apps that support SOCKS4/5. However, configuring SOCKS4/5 in every single app isn't very convenient, so...
Layer 3
And now the fun part. I configured iptables so that it lets connection on the local network and to whitelisted ports through without:
/sbin/iptables -t nat -A OUTPUT -o lo -j RETURN
/sbin/iptables -t nat -A OUTPUT -d 127.0.0.1 -j RETURN
/sbin/iptables -t nat -A OUTPUT -d 192.168.0.0/16 -j RETURN
/sbin/iptables -t nat -A OUTPUT -p tcp --dport 22 -j RETURN # SSH
/sbin/iptables -t nat -A OUTPUT -p tcp --dport 80 -j RETURN # HTTP
/sbin/iptables -t nat -A OUTPUT -p tcp --dport 443 -j RETURN # HTTPS
/sbin/iptables -t nat -A OUTPUT -p udp --dport 53 -j RETURN # DNS
And to forward all other connections to
transocks server:
/sbin/iptables -t nat -A OUTPUT -p tcp --syn -j DNAT --to-destination 127.0.0.1:1211
So connections to slashdot.org:80 goes straight, while connections to irc.freenode.net:6667 get redirected to 127.0.0.1:1211. This is almost the right thing, however you can probably see a little problem here - how the heck does transocks know where the user wanted to get connected. That's the best part. Kernel remembers the original destination and we can get to it using:
getsockopt(clientfd, SOL_IP, SO_ORIGINAL_DST, (struct sockaddr *)&dstaddr, &dstlen);
Now transocks connects to the specified SOCKS4/5 server (configuration in /etc/socks.conf), and the server connects to the right website through a tunnel.
In the end
So the complete path the connection goes through is:
- An application on desktop tries to connect to irc.freenode.net:6667
- iptables redirect connection to transocks desktop:1211
- transocks on desktop reads the original destination using getsockopt
- transocks connects to SOCKS4/5 server (HTTP tunnel client) on laptop - 192.168.1.1:1080
- HTTP Tunnel client on laptop tries to connect to HTTP Tunnel servers
- desktop NATs the connection and lets it through
- router NATs the connection again and lets it through
- HTTP Tunnel server connects to irc.freenode.net:6667, wow :-D
The transocks trick also works perfectly with SSH tunneling (
ssh -D 1080 fred@your.shell.account).
Oh and by the way, compiling transocks is not trivial, just contact me if you need some support here :-)