iptables for transparent TCP proxy

Here's my situation. I have an iPad, a TiVo, and an dd-wrt router on my network, along with a machine that I'd like to use to sniff/decrypt draffic between the iPad and the TiVo.

The iPad has an app that A) automatically discovers the IP for the TiVo and B) speaks to the TiVo over SSL. The iPad is on my wifi network, while the TiVo is wired, guaranteeing that the packets are passing through my dd-wrt router; I can sniff them with tcpdump, but they are encrypted.

I'd like to try to use tcpcatcher to attempt a man-in-the-middle with ssl decryption and re-encryption. I'd assume that I could use some simple iptable rules on the dd-wrt router to forward/redirect/nat the packets that would be traveling between the ipad and tivo, much like you can do for transparent http proxying. I have not found the right rules to do this, however, and would like some assistance.


Doing a redirect with iptables can be accomplished as so :

iptables -t nat -A PREROUTING -i eth1 -p tcp -m tcp --dport 80 -j DNAT --to-destination 192.168.0.1:3128

This is a standard web redirect to a proxy server. The rule is placed in the NAT table PREROUTING chain for packets coming in on the eth1 interface for the tcp protocol port 80 and DESTINATION NATTED to an ip and port.

Once the traffic is redirected however, your going to have to get it back to its original destination without the endpoint knowing. I'd be interested in knowing how you accomplish that.


You can use my tun2socks program for the "TCP catching" part. This program makes a virtual TUN network interface that forwards all outgoing TCP connections through a SOCKS proxy. If you add a routing rule (ip rule) to forward Ipad's connection into tun2socks' TUN interface, tun2socks will forward it to your SOCKS5 proxy. It should be much easier to perform the MITM attack in/as a SOCKS proxy.

Note that this approach is similar to the iptables redirect rule from your point of view, but you don't have to do anything special to figure out the real destination of the connection - it will be present in the SOCKS5 protocol headers.

UPDATE: getting packets from the Ipad into the TUN interface is in fact harder than it seems. I'm assuming that you router has a br0 bridge interface which bridges wlan0 (where the Ipad is) and eth0 (where the Tivo is). Note that I'm not very familiar with DD-WRT, so the names may be different (check with brctl show).

Now the problem is that packets from the Ipad (wlan0) to Tivo (eth0) are not routed, but bridged (i.e. the same thing that a switch does). This means that even if you add ip rules, they won't matter, because those packets won't go through the router, at least logically speaking. To solve this, you have to redirect the packets from the Ipad as if they were directed directly to the MAC address of br0 and not to the MAC address of the Tivo, which is at eth0; this will make the kernel treat them as incoming IP packets, hopefully routing them according to the ip rules and routing table. Finally, the command is:

ebtables -t nat -A PREROUTING -i wlan0 -p ipv4 --ip-source <ip_of_ipad> --ip-destination <ip_of_tivo> --ip-protocol TCP -j dnat --to-destination <mac_of_br0>

This adds an ebtables rule that will redirect matching packets received on wlan0 directly to br0. You may have to add more conditions here if this catches too much. Note that dnat does not mean the usual (IP) NAT - in ebtables, NAT means changing the MAC address of frames, rather than the IP address.

You can get a compiled version of tun2socks for DD-WRT here; hopefully it will work on your device.


Here is a good tutorial for accomplishing this. Basically, you need to DNAT packets to the proxy server, and also SNAT them so that the router gets the responses from the proxy server (and then undoes the NAT). The iptables rules should be something like this (assuming that the proxy server's IP is 10.0.0.10):

iptables --table nat --append PREROUTING --in-interface eth0 --source !10.0.0.10 --protocol tcp --dport 80 --jump DNAT --to 10.0.0.10:3128
iptables --table nat --append POSTROUTING --out-interface eth0 --source 10.0.0.0/24 --destination 10.0.0.10 --jump MASQUERADE

The first rule redirects packets destined for port 80 to the proxy server (excluding packets from the proxy server itself because it needs to actually contact the web server on the Internet), and the second rule changes the source address on the redirected packets when sending to the proxy server. (I'm assuming that the FORWARD chain accepts these packets, if not you need another rule in there as well.)