Wednesday, July 2, 2014

Using iptables + socat to tunnel outbound connections through proxy

EDIT: Here is the tool I wrote to facilitate creation of transparent tunnels over http proxies - on my GitHub account.

I've known about socat for a while, but never really got into using it until recently. Its possibilities are endless and it's always reliable. I'm thinking about writing a wrapper around it.

For now, imagine you've got the following setup: A thick/thin app, script, program, whatever with no native proxy support, connecting to an external host. You may want to tunnel the connections through your company's proxy, or maybe perform man-in-the-middle on the outbound streams. (side note: Contextis' CANAPE is excellent for that matter, but more complex to setup, and Windows only).

Obviously, you could edit your hosts file, or even possibly modify the source code to make it connect to wherever you want. But there are some situations where you can't / don't want / are too lazy to do that.

You can use an iptables rule to redirect the outbound connections to that host to your loopback interface, then have socat listening on a local port and tunnel sessions through the proxy. It can also be used to setup a local man-in-the-middle scenario, where you want to be able to put an intercepting proxy in the middle of the communication.

The network flow diagram is as follows:




You can add the "reuseaddr" command-line parameter to the socat listening local socket parameter to allow it to rebind to a previously open port. Also add the "fork" parameter if needed to prevent it from exiting after the first tunneled TCP session is finished. You don't need to enable IP Forwarding on your box.

For example, if I want to tunnel all direct connections made to google.com:443. First, you need to create the Iptables rule accordingly. As root:

iptables -t nat -A OUTPUT -p tcp -d google.com --dport 443 -j DNAT --to-destination 127.0.0.1:443

Then, you must create the socat tunnel (reuseaddr and fork are optional). As root:

socat TCP4-LISTEN:443,bind=127.0.0.1,reuseaddr,fork PROXY:proxy.mycompany.com:google.com:443,proxyport=3128

When your work is finished, kill the socat instance with CTRL+C and delete the now useless iptables rule (just use -D instead of -A):

iptables -t nat -D OUTPUT -p tcp -d google.com --dport 443 -j DNAT --to-destination 127.0.0.1:443

And because I like shell scripts, here goes:

#!/bin/bash
if [ -z $2 ]; then
 echo "usage: $0 <dest_host> <dest_port>"
 exit
fi

if [ $EUID -ne 0 ]; then
 echo "error: must be run as root"
 exit
fi


PROXYHOST=192.168.100.1
PROXYPORT=3128

# Forward all outgoing traffic directed to ext_host:ext_port to the loopback interface
echo Creating rule...
iptables -t nat -A OUTPUT -p tcp -d $1 --dport $2 -j DNAT --to-destination 127.0.0.1:$2

# use socat to tunnel connections to the local port through the proxy
echo "127.0.0.1:$2 <--> $PROXYHOST:$PROXYPORT <--> $1:$2 (stop with ctrl+c)"
socat TCP4-LISTEN:$2,bind=127.0.0.1,reuseaddr,fork PROXY:$PROXYHOST:$1:$2,proxyport=$PROXYPORT

# remove created iptables rule
echo Removing rule...
iptables -t nat -D OUTPUT -p tcp -d $1 --dport $2 -j DNAT --to-destination 127.0.0.1:$2

Enjoy ;)

No comments:

Post a Comment