WiFi HotSpot: Pass all traffic to internal MITM Proxy over port

Hi Resin and friends,

TL;DR - How do I forward wlan0 hotspot traffic to an internal proxy before it passes through to eth0?

I’m currently developing an application for Raspberry Pi 3 on Resin to deploy to a fleet once done. I’m attempting to transfer over something I made locally on Raspbian, and port forwarding at the host level is a must. Here’s how it works:

I need to insert a MITMProxy in the middle to sniff traffic (intercepting OTT device traffic as they often don’t provide tools to do so natively, making troubleshooting a real pain). In Raspbian, this was accomplished with the standard HostAPD/DNSMasq/IP Tables set up, but I’m struggling to get the same in Resin. IP Tables takes all port 80 traffic on the wlan0 and forwards to port 8888, where MITMProxy picks it up and logs http traffic before passing on transparently. Here’s the IP Tables config I’m trying to match:

*nat
:PREROUTING ACCEPT [4:580]
:INPUT ACCEPT [2:458]
:OUTPUT ACCEPT [2:128]
:POSTROUTING ACCEPT [2:128]
-A PREROUTING -i wlan0 -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 8888
-A POSTROUTING -o eth0 -j MASQUERADE
COMMIT
*filter
:INPUT ACCEPT [13:6552]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [12:1399]
-A FORWARD -i wlan0 -o eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i eth0 -o wlan0 -j ACCEPT

Is there a way to modify IP Tables on the Host OS without breaking the Docker network? I’m trying to do the actual updating commands from a run-once Docker container defined in the Docker Compose, but I’m wondering if I’m missing a more native way to accomplish this.

Thanks!

Update: I’m currently pulling the running iptables rules, modifying them to add what I need for the port forwarding, and applying with a shell script run as the CMD in the IP Tables Dockerfile. I’m wondering if this method is portable, since I’m not sure the IP Tables config will be the same across different devices. Is this method going to work, or do I have the ability to do it smarter? Excuse the massive file, but here’s the new static iptables.rules I apply when the application starts up:

*nat
:PREROUTING ACCEPT [1056:115532]
:INPUT ACCEPT [420:73837]
:OUTPUT ACCEPT [727:47733]
:POSTROUTING ACCEPT [724:47529]
-A PREROUTING -i wlan0 -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 8888
-A POSTROUTING -o eth0 -j MASQUERADE
:DOCKER - [0:0]
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
-A POSTROUTING -s 172.17.0.0/16 ! -o supervisor0 -j MASQUERADE
-A POSTROUTING -s 10.114.101.0/24 ! -o balena0 -j MASQUERADE
-A POSTROUTING -s 172.18.0.0/16 ! -o br-a83c07aa5890 -j MASQUERADE
-A POSTROUTING -s 10.42.0.0/24 ! -d 10.42.0.0/24 -j MASQUERADE
-A DOCKER -i supervisor0 -j RETURN
-A DOCKER -i balena0 -j RETURN
-A DOCKER -i br-a83c07aa5890 -j RETURN
COMMIT
# Completed on Tue Jun 19 21:10:45 2018
# Generated by iptables-save v1.6.1 on Tue Jun 19 21:10:45 2018
*filter
:INPUT ACCEPT [1966:300078]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [1526:182426]
:DOCKER - [0:0]
:DOCKER-ISOLATION - [0:0]
:DOCKER-USER - [0:0]
-A INPUT -i supervisor0 -p tcp -m tcp --dport 48484 -j ACCEPT
-A INPUT -i lo -p tcp -m tcp --dport 48484 -j ACCEPT
-A INPUT -i docker0 -p tcp -m tcp --dport 48484 -j ACCEPT
-A INPUT -i tun0 -p tcp -m tcp --dport 48484 -j ACCEPT
-A INPUT -i resin-vpn -p tcp -m tcp --dport 48484 -j ACCEPT
-A INPUT -i wlan0 -p udp -m udp --dport 67 -j ACCEPT
-A INPUT -i wlan0 -p tcp -m tcp --dport 67 -j ACCEPT
-A INPUT -i wlan0 -p udp -m udp --dport 53 -j ACCEPT
-A INPUT -i wlan0 -p tcp -m tcp --dport 53 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 48484 -j REJECT --reject-with icmp-port-unreachable
-A FORWARD -j DOCKER-USER
-A FORWARD -j DOCKER-ISOLATION
-A FORWARD -o supervisor0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o supervisor0 -j DOCKER
-A FORWARD -i supervisor0 ! -o supervisor0 -j ACCEPT
-A FORWARD -i supervisor0 -o supervisor0 -j ACCEPT
-A FORWARD -o balena0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o balena0 -j DOCKER
-A FORWARD -i balena0 ! -o balena0 -j ACCEPT
-A FORWARD -i balena0 -o balena0 -j ACCEPT
-A FORWARD -o br-a83c07aa5890 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o br-a83c07aa5890 -j DOCKER
-A FORWARD -i br-a83c07aa5890 ! -o br-a83c07aa5890 -j ACCEPT
-A FORWARD -i br-a83c07aa5890 -o br-a83c07aa5890 -j ACCEPT
-A FORWARD -d 10.42.0.0/24 -o wlan0 -m state --state RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -s 10.42.0.0/24 -i wlan0 -j ACCEPT
-A FORWARD -i wlan0 -o wlan0 -j ACCEPT
-A FORWARD -i wlan0 -o eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o wlan0 -j REJECT --reject-with icmp-port-unreachable
-A FORWARD -i wlan0 -j REJECT --reject-with icmp-port-unreachable
-A FORWARD -i eth0 -o wlan0 -j ACCEPT
-A DOCKER-ISOLATION -i br-a83c07aa5890 -o supervisor0 -j DROP
-A DOCKER-ISOLATION -i supervisor0 -o br-a83c07aa5890 -j DROP
-A DOCKER-ISOLATION -i balena0 -o supervisor0 -j DROP
-A DOCKER-ISOLATION -i supervisor0 -o balena0 -j DROP
-A DOCKER-ISOLATION -i br-a83c07aa5890 -o balena0 -j DROP
-A DOCKER-ISOLATION -i balena0 -o br-a83c07aa5890 -j DROP
-A DOCKER-ISOLATION -j RETURN
-A DOCKER-USER -j RETURN
COMMIT

Hi,

The interface names usually change across different devices types, so using a single iptables config across device types will probably be a non-portable solution.

I figured as much - are there any other options anyone can think of, or will the IP Tables rules have to be parsed individually at runtime per device?

Hi,
looking at iptables help, I could see

–in-interface -i input name[+]
network interface name ([+] for wildcard)

and

–out-interface -o output name[+]
network interface name ([+] for wildcard)

So you could use wildcards to some extent (like -i eth+ to work for interfaces named eth1, eth2 etc).
This won’t however work if the wired interface name is something like ensp[xyz] but you could still use wildcards with this.
So you could eitehr do a combination of wildcarding with multiple rules to cover the cases, or you could before hand inspect with ifconfig the available interfaces and just use exactly the ones available in your iptables rules

Great suggestion! I’ll dig deeper into the wildcard feature and report back if that’s enough to get the job done.