Skip to content

Instantly share code, notes, and snippets.

@gcleaves
Last active March 21, 2024 16:31
Show Gist options
  • Save gcleaves/ec7a06f8c0bd436c1bc2eb922a246d26 to your computer and use it in GitHub Desktop.
Save gcleaves/ec7a06f8c0bd436c1bc2eb922a246d26 to your computer and use it in GitHub Desktop.
Wireguard peer as internet gateway, using Android USB tethering

Goal

Browse the Internet via the desired mobile network operator by connecting to a Wireguard network with a specific address. Why? You'll know why if you need it.

Advantages:

  • You probably have more old Android phones sitting around than 4G modems.
  • All network traffic will be routed via the VPN/MNO as opposed to setting up simple HTTP proxies (Every Proxy) on the Android devices, which is a much simpler option.

Disadvantages:

  • You need to manually enable USB tethering on the phone on each restart.
  • If you plug more than one phone into the same RPi, you need to keep track of which device is usb0, usb1, etc.
  • A 4G modem is cheaper than an Android phone.
  • (Semi) Complicated routing!

Summary

Wireguard

Gateway setup

Wireguard

1 Wireguard interface will be setup with multiple addresses/subnets. Each subnet will route traffic via a different MNO.

[Interface]
Table = 1234
Address = 10.0.0.1/24, 10.0.1.1/24, 10.0.2.1/24 # 1 network for each MNO
SaveConfig = false
ListenPort = 5555
PrivateKey = <private>

[Peer]
# normal browsing peer
PublicKey = <public>
AllowedIPs = 10.0.0.2/32,10.0.1.2/32,10.0.2.2/32 # 1 for each MNO

[Peer]
# normal browsing peer
PublicKey = <public>
AllowedIPs = 10.0.0.3/32,10.0.1.3/32,10.0.2.3/32 # 1 for each MNO

[Peer]
# rpi gw peer
PublicKey = <public>
AllowedIPs = 0.0.0.0/0 # this allows all traffic to exit the GW direction RPI as well as RPI to register any IP address (x.x.x.254) on the GW.

[Peer]
# rpi gw peer
PublicKey = <public>
AllowedIPs = 0.0.0.0/0 # this allows all traffic to exit the GW direction RPI as well as RPI to register any IP address (x.x.x.254) on the GW.

ip routes and rules

We need ip route tables and rules on the main gateway in order to route traffic to the correct RPi/phone. All of this should probably go into the Wireguard config PostUp.

sysctl -w net.ipv4.ip_forward=1
ip route add default via 10.0.0.254 dev wg0 table 1111
ip route add default via 10.0.1.254 dev wg0 table 2222
ip route add default via 10.0.2.254 dev wg0 table 3333
ip rule add from 10.0.0.254/24 lookup 1111
ip rule add from 10.0.1.254/24 lookup 2222
ip rule add from 10.0.2.254/24 lookup 3333

Raspberry Pi gateway setup

Routing and firewall

Enable IP forwarding and masquerading. Set up routes and rules so that traffic exits the correct USB tethered phone.

sysctl -w net.ipv4.ip_forward=1
iptables -A FORWARD -i wg0 -j ACCEPT # put in WG config
iptables -t nat -A POSTROUTING -o usb0 -j MASQUERADE # put in WG config
iptables -t nat -A POSTROUTING -o usb1 -j MASQUERADE # put in WG config
ip route add default via 192.168.42.129 dev usb0 table 1111 # put in WG config
ip route add default via 192.168.42.129 dev usb1 table 2222 # put in WG config
ip rule add from 10.0.0.254/24 lookup 1111 # put in WG config
ip rule add from 10.0.1.254/24 lookup 2222 # put in WG config

Wireguard

Browsing peer setup

Wireguard

wef
wef

The browsing peer will have an IP address on each network/MNO. When bringing up the

Wrapping up

Bring up wg0 on boot.

# attempt 6, success
# relies on Magisk auto start script
# pause script to give wireguard time to autostart
bullhead:/ # cat /data/adb/service.d/prep_gateway.sh
#!/system/bin/sh
sleep 2m
su -c 'iptables -F tetherctrl_FORWARD'
su -c 'sysctl -w net.ipv4.ip_forward=1'
su -c 'iptables -A FORWARD -i tun0 -j ACCEPT'
su -c 'iptables -t nat -A POSTROUTING -o rmnet_data0 -j MASQUERADE'
su -c 'ip rule add from all iif tun0 lookup rmnet_data0'
su -c 'ip rule add from all iif rmnet_data0 to 10.0.0.0/8 lookup tun0'
# attempt 1
iptables -F tetherctrl_FORWARD
sysctl -w net.ipv4.ip_forward=1
iptables -A FORWARD -i tun0 -j ACCEPT
iptables -t nat -A POSTROUTING -o rmnet_data0 -j MASQUERADE
ip rule add from all iif tun0 lookup rmnet_data0
ip rule add from all iif rmnet_data0 to 10.0.0.1/24 lookup tun0
# Error: argument "tun0" is wrong: invalid table ID
# turn on wireguard
ip rule add from all iif rmnet_data0 to 10.0.0.1/24 lookup tun0
# IT WORKS!
# attempt 2, autoconnect and 10.0.0.0/8
# first connect to wireguard VPN and set androind to auto connect to VPN.
# reboot
iptables -F tetherctrl_FORWARD
sysctl -w net.ipv4.ip_forward=1
iptables -A FORWARD -i tun0 -j ACCEPT
iptables -t nat -A POSTROUTING -o rmnet_data0 -j MASQUERADE
ip rule add from all iif tun0 lookup rmnet_data0
ip rule add from all iif rmnet_data0 to 10.0.0.0/8 lookup tun0
# IT WORKS!
# attempt 3, scripted
# add above to script
# add to /data/adb/service.d to Magisk can run it
# https://github.com/topjohnwu/Magisk/blob/master/docs/guides.md#boot-scripts
# script does not appear to be executed on boot
# FAIL, script doesn't run for some unknown reason
# attempt 4, execute script from AFWall+ by linking to existing script on phone
# FAIL again
# attempt 5 run the following in AFWall+ custom script
iptables -F tetherctrl_FORWARD
sysctl -w net.ipv4.ip_forward=1
ip route add 192.0.2.0 dev lo table tun0
iptables -A FORWARD -i tun0 -j ACCEPT
iptables -t nat -A POSTROUTING -o rmnet_data0 -j MASQUERADE
ip rule add from all iif tun0 lookup rmnet_data0
ip rule add from all iif rmnet_data0 to 10.0.0.0/8 lookup tun0
# FAIL
[Interface]
Table = 5678
Address = 192.168.99.1/16
SaveConfig = false
ListenPort = 5556
PrivateKey = PRIVATE
PostUp = iptables -A FORWARD -i wg1 -j ACCEPT; iptables -t nat -A POSTROUTING -s 192.168.99.0/24 -j SNAT --to-source 164.132.66.205; iptables -t nat -A POSTROUTING -s 192.168.100.0/24 -j SNAT --to-source 178.32.54.16
PostDown = iptables -D FORWARD -i wg1 -j ACCEPT; iptables -t nat -D POSTROUTING -s 192.168.99.0/24 -j SNAT --to-source 164.132.66.205; iptables -t nat -D POSTROUTING -s 192.168.100.0/24 -j SNAT --to-source 178.32.54.16
[Peer]
PublicKey = EXAMPLE
AllowedIPs = 192.168.99.11/32, 192.168.100.11/32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment