Last active
September 7, 2024 23:36
-
-
Save chrisob/f4750f94b14f45f9af04 to your computer and use it in GitHub Desktop.
Android reverse tethering over bridged SSH tap interface
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# Based on the scripts written by class101 of xda-developers.com: | |
# http://forum.xda-developers.com/showpost.php?p=57490025&postcount=205 | |
# | |
# This script enables a secure tunnel for your android phone to "reverse tether" | |
# and access the internet/a private network via the following steps: | |
# | |
# 1. Establish a level 3 (TAP) tunnel from your local host to a remote server via SSH (tap0) | |
# 2. Establish a level 3 interface between your local host and your android phone via USB (usb0) | |
# 3. Bridge these two devices on the local host, so your android uses the remote server as a gateway | |
# 4. Configure the appropriate addresses, routes, firewall rules, and DNS servers | |
# | |
# Initial required setup: | |
# | |
# On all hosts: | |
# -root access | |
# -iptables and iproute installed | |
# | |
# On the remote SSH host: | |
# -At least OpenSSH server 4.3 | |
# -Your SSH public key is in /root/.ssh/authorized_keys | |
# -"PermitRootLogin yes" is in /etc/ssh/sshd_config | |
# -"PermitTunnel yes" is in /etc/ssh/sshd_config | |
# | |
# On the local host: | |
# -At least OpenSSH client 4.3 | |
# -The bridge kernel module loaded | |
# -Android ADB is installed | |
# -Access to your device with "adb shell" | |
# | |
# On your android device (tested with 5.1): | |
# -Permanent access to your device via ADB from your PC (by fingerprint) | |
# | |
# | |
# Interfaces: | |
# tap0 - Level 3 (ethernet) tunnel between local host and remote host (both called tap0) | |
# usb0 - Local NIC to android phone | |
# br0 - Local bridge NIC bridging tap0 and usb0 | |
# rndis0 - Android internal NIC; other side of usb0 | |
# | |
# Limitations: | |
# Only tested with Android 5.1, and CentOS-6 for both the remote and local hosts. | |
# All android apps that rely on android's "ConnectivityManager" for networking will not work, | |
# such as the android market, hangouts, etc. | |
# More information found at https://code.google.com/p/android/issues/detail?id=99034 | |
REMOTE_SSH_IP=1.2.3.4 | |
REMOTE_SSH_PORT=22 | |
SSH_KEY=/root/.ssh/id_rsa | |
SSH_SOCK=/root/tunnel.sock | |
SSH_PROXY_COMMAND="none" | |
BRIDGE_SUBNET=10.123.123.0 | |
PREFIX=24 | |
REMOTE_GATEWAY=10.123.123.100 | |
ANDROID_IP=10.123.123.200 | |
DNS1=8.8.8.8 | |
DNS2=8.8.4.4 | |
ANDROID_UP=" | |
echo -- rndis0: adding ip rule -- | |
ip rule add from all lookup main | |
echo -- rndis0: flushing interface -- | |
ip addr flush dev rndis0 | |
echo -- rndis0: setting ip -- | |
ip addr add ${ANDROID_IP}/${PREFIX} dev rndis0 | |
echo -- rndis0: starting the interface -- | |
ip link set rndis0 up | |
echo -- rndis0: setting route -- | |
ip route add default via ${REMOTE_GATEWAY} dev rndis0 | |
echo -- rndis0: setting iptables -- | |
iptables -t nat -I POSTROUTING 1 -o rndis0 -j MASQUERADE | |
echo -- rndis0: setting ip_forward -- | |
echo 1 > /proc/sys/net/ipv4/ip_forward | |
echo -- rndis0: setting properties -- | |
setprop net.dns1 ${DNS1} | |
setprop net.dns2 ${DNS2} | |
setprop net.rndis0.dns1 ${DNS1} | |
setprop net.rndis0.dns2 ${DNS2} | |
setprop net.rndis0.gw ${REMOTE_GATEWAY} | |
setprop net.rndis0.gateway ${REMOTE_GATEWAY} | |
echo -- rndis0: starting dnsmasq -- | |
killall dnsmasq &> /dev/null | |
dnsmasq --no-poll --pid-file --interface=rndis0 --interface=wlan0 --interface=rmnet0 --bogus-priv --filterwin2k --no-resolv --server=${DNS1} --server=${DNS2} < /dev/null | |
" | |
ANDROID_DOWN=" | |
echo -- rndis0: stopping the interface -- | |
ip link set rndis0 down | |
echo -- rndis0: flushing interface -- | |
ip addr flush dev rndis0 | |
echo -- rndis0: deleting ip rule -- | |
ip rule del from all lookup main | |
echo -- rndis0: stopping dnsmasq -- | |
killall dnsmasq &> /dev/null | |
echo -- rndis0: deleting iptables rule -- | |
iptables -t nat -D POSTROUTING -o rndis0 -j MASQUERADE | |
echo -- rndis0: setting back usb mode to mtp -- | |
setprop sys.usb.config 'mtp,adb' | |
" | |
REMOTE_UP=" | |
ip addr add ${REMOTE_GATEWAY}/${PREFIX} dev tap0 | |
ip link set tap0 up | |
iptables -t filter -I FORWARD 1 -i tap0 -j ACCEPT | |
iptables -t filter -I INPUT 1 -i tap0 -s ${BRIDGE_SUBNET}/${PREFIX} -j ACCEPT | |
iptables -t nat -I POSTROUTING 1 -o eth0 -s ${BRIDGE_SUBNET}/${PREFIX} -j MASQUERADE | |
" | |
REMOTE_DOWN=" | |
iptables -t filter -D FORWARD -i tap0 -j ACCEPT | |
iptables -t filter -D INPUT -i tap0 -s ${BRIDGE_SUBNET}/${PREFIX} -j ACCEPT | |
iptables -t nat -D POSTROUTING -o eth0 -s ${BRIDGE_SUBNET}/${PREFIX} -j MASQUERADE | |
" | |
function usage { | |
echo -e "Usage:\n$0 {up|down}\n" | |
} | |
echo | |
if [ "$1" == "up" ]; then | |
echo "Checking if local tap0 exists..." | |
ip addr show tap0 > /dev/null 2>&1 | |
if [ $? -ne 0 ]; then | |
echo "Creating local and remote tap0..." | |
ssh -f root@${REMOTE_SSH_IP} \ | |
-o "Port ${REMOTE_SSH_PORT}" \ | |
-o "IdentityFile ${SSH_KEY}" \ | |
-o "ProxyCommand ${SSH_PROXY_COMMAND}" \ | |
-o "Tunnel ethernet" \ | |
-o "TunnelDevice 0:0" \ | |
-o "ExitOnForwardFailure yes" \ | |
-o "ServerAliveInterval 60" \ | |
-o "ControlMaster yes" \ | |
-o "ControlPath ${SSH_SOCK}" \ | |
"${REMOTE_UP}" | |
fi | |
echo "Waiting for android to become available..." | |
adb wait-for-device | |
echo "Enabling android rndis0..." | |
adb shell su -c "setprop sys.usb.config rndis,adb" | |
echo "Waiting for android to become available..." | |
sleep 5 | |
adb wait-for-device | |
# Disable local usb0 to android device to prevent receiving a dhcp address | |
ip link set usb0 down | |
echo "Configuring android rndis0..." | |
adb shell su -c "${ANDROID_UP}" | |
echo "Configuring local br0..." | |
brctl addbr br0 | |
brctl addif br0 tap0 | |
brctl addif br0 usb0 | |
ip addr flush dev usb0 | |
ip addr flush dev tap0 | |
ip addr flush dev br0 | |
echo "Enabling local br0..." | |
ip link set br0 up | |
echo "Enabling local tap0..." | |
ip link set tap0 up | |
echo "Enabling local usb0..." | |
ip link set usb0 up | |
echo "Creating local iptables rules..." | |
iptables -t filter -I FORWARD 1 -i br0 -s ${BRIDGE_SUBNET}/${PREFIX} -j ACCEPT | |
iptables -t filter -I FORWARD 1 -i br0 -d ${BRIDGE_SUBNET}/${PREFIX} -j ACCEPT | |
elif [ "$1" == "down" ]; then | |
# TODO: teardown isn't as thorough as configuration, some configs aren't reset | |
echo "Checking if local tap0 exists..." | |
ip addr show tap0 > /dev/null 2>&1 | |
if [ $? -eq 0 ]; then | |
echo "Disabling local and remote tap0..." | |
ssh -S "${SSH_SOCK}" -O exit does-not-matter-what-goes-here-blaahh > /dev/null | |
echo "Removing remote iptables rules..." | |
ssh root@${REMOTE_SSH_IP} \ | |
-o "Port ${REMOTE_SSH_PORT}" \ | |
-o "IdentityFile ${SSH_KEY}" \ | |
-o "ProxyCommand ${SSH_PROXY_COMMAND}" \ | |
"${REMOTE_DOWN}" | |
fi | |
echo "Disabling local br0..." | |
ip link set usb0 down | |
USB0_IS_PRESENT=$? | |
ip link set br0 down | |
brctl delbr br0 | |
echo "Removing local iptables rules..." | |
iptables -t filter -D FORWARD -i br0 -s ${BRIDGE_SUBNET}/${PREFIX} -j ACCEPT | |
iptables -t filter -D FORWARD -i br0 -d ${BRIDGE_SUBNET}/${PREFIX} -j ACCEPT | |
if [ $USB0_IS_PRESENT -eq 0 ]; then | |
echo "Waiting for android to become available..." | |
adb wait-for-device | |
echo "Disabling android rndis0..." | |
adb shell su -c "${ANDROID_DOWN}" | |
fi | |
else | |
usage | |
exit 1 | |
fi | |
echo "Done!" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment