diff --git a/scripts/reverse_tether.sh b/scripts/reverse_tether.sh new file mode 100755 index 000000000..82f7c59a4 --- /dev/null +++ b/scripts/reverse_tether.sh @@ -0,0 +1,261 @@ +#!/bin/bash +# Copyright 2010 Google Inc. +# All right reserved. +# Author: Szymon Jakubczak +# +# Configure the host and the Android phone for "reverse tethering". +# (Route all network traffic via the host.) + +# default values +: ${BRIDGE:=usbeth} +: ${LAN_DEV:=eth0} # LAN uplink on the host +: ${HOST_DEV:=usb0} # name of the RNDIS interface on the host +: ${PHONE_DEV:=rndis0} # name of the RNDIS interface on the phone + +: ${PHONE_IP:=192.168.77.2} # for NAT and tests +: ${HOST_IP:=192.168.77.1} +: ${NETMASK:=255.255.255.0} + +# location of the hwaddr utility +: ${HWADDR:=/home/build/nonconf/google3/experimental/users/szym/moblat/hwaddr/hwaddr-armeabi} +: ${PHONE_HW:=""} # hardware (Ethernet) address for the interface (bridge only) + +# for NAT configuration +: ${DNS1:=8.8.8.8} +: ${DNS2:=8.8.4.4} + +# export ADB=/path/to/sdk/adb for custom adb +ADB="${ADB:-adb} ${SERIAL:+-s $SERIAL}" + +set -e +trap error ERR + +error() { + echo >&2 "Error occured: $?" +} + +usage() { + echo "Usage: $0 " + echo " rndis -- start RNDIS and test ping the phone" + echo " nat -- use host as NAT" + echo " nat+secure -- nat + extra security" + echo " bridge -- use host as bridge" + echo " stop -- switch back to 3G" + echo " stop-all -- clean up everything" + echo + echo "Advanced Commands" + echo " Host:" + echo " nat_start " + echo " nat_secure " + echo " nat_stop " + echo " bridge_start " + echo " bridge_add " + echo " bridge_stop " + echo " Phone:" + echo " rndis_start " + echo " rndis_stop " + echo " rndis_test " + echo " route_nat " + echo " route_bridge " + echo " route_reset " + echo + echo "Options and Environment Variables:" + echo " -h|--help" + echo " -b bridge_name BRIDGE=$BRIDGE" + echo " -s serial_number SERIAL=$SERIAL" + echo " -u host_usb_device HOST_DEV=$HOST_DEV" + echo " -l host_lan_device LAN_DEV=$LAN_DEV" + echo " -d dns1 dns2 DNS1=$DNS1" + echo " DNS2=$DNS2" + echo " -p phone_ip PHONE_IP=$PHONE_IP" + echo " -a host_ip HOST_IP=$HOST_IP" + echo " -m netmask NETMASK=$NETMASK" + echo " -e hardware_addr PHONE_HW=$PHONE_HW" + echo + echo " HWADDR=$HWADDR" + echo " ADB=$ADB" +} + +################################## +### PHONE configuration routines +################################## +rndis_start() { + echo "Starting RNDIS..." + $ADB wait-for-device + $ADB shell "svc usb setFunction rndis" + $ADB wait-for-device + $ADB shell "ifconfig $PHONE_DEV down" + if [[ -n "$PHONE_HW" ]]; then + $ADB push $HWADDR /data/local/hwaddr # TODO(szym) handle failures? + $ADB shell "/data/local/hwaddr $PHONE_DEV $PHONE_HW" + $ADB shell "/data/local/hwaddr $PHONE_DEV" + fi +} + +rndis_stop() { + $ADB shell "svc usb setFunction" #empty to clear +} + +rndis_test() { + # configure some IPs, so that we can ping + $ADB shell "ifconfig $PHONE_DEV $PHONE_IP netmask $NETMASK up" + sudo ifconfig $HOST_DEV $HOST_IP netmask $NETMASK up + echo "Pinging the phone..." + ping -q -c 1 -W 1 $PHONE_IP + echo "Success!" +} + +update_dns() { + $ADB shell 'setprop net.dnschange $((`getprop net.dnschange`+1))' +} + +default_routes() { + $ADB shell 'cat /proc/net/route' | awk '{ if ($2==00000000) print $1 }' +} + +route_none() { + $ADB shell "svc data disable" + $ADB shell "svc wifi disable" + # kill all default route interfaces (just in case something remains) + for dev in `default_routes`; do + $ADB shell "ifconfig $dev down" + done +} +route_nat() { + echo "Setting up phone routes and DNS..." + route_none + $ADB shell "ifconfig $PHONE_DEV $PHONE_IP netmask $NETMASK up" + $ADB shell "route add default gw $HOST_IP dev $PHONE_DEV" + $ADB shell "setprop net.dns1 $DNS1" + $ADB shell "setprop net.dns2 $DNS2" + update_dns +} +route_bridge() { + echo "Running DHCP on the phone..." + route_none + $ADB shell "ifconfig $PHONE_DEV up" + $ADB shell "netcfg $PHONE_DEV dhcp" + $ADB shell "ifconfig $PHONE_DEV" # for diagnostics + + DNS1=`$ADB shell getprop net.${PHONE_DEV}.dns1` + $ADB shell "setprop net.dns1 $DNS1" + DNS2=`$ADB shell getprop net.${PHONE_DEV}.dns2` + $ADB shell "setprop net.dns2 $DNS2" + update_dns +} +route_reset() { + route_none + $ADB shell "svc data enable" +} + +################################# +### HOST configuration routines +################################# +nat_start() { + echo "Configuring NAT..." + sudo sysctl -w net.ipv4.ip_forward=1 + sudo iptables -F + sudo iptables -t nat -F + sudo iptables -t nat -A POSTROUTING -o $LAN_DEV -j MASQUERADE + sudo iptables -P FORWARD ACCEPT + sudo ifconfig $HOST_DEV $HOST_IP netmask $NETMASK up +} +nat_secure() { + echo "Making your NAT secure..." + sudo iptables -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT + sudo iptables -A FORWARD -m state --state NEW -i $HOST_DEV -j ACCEPT + sudo iptables -P FORWARD DROP + sudo ifconfig usb0 $HOST_IP netmask $NETMASK up +} +nat_stop() { + sudo sysctl -w net.ipv4.ip_forward=0 + sudo iptables -F + sudo iptables -t nat -F +} + +bridge_start() { + echo "Configuring bridge..." + sudo brctl addbr $BRIDGE || return 0 # all good + sudo brctl setfd $BRIDGE 0 + sudo ifconfig $LAN_DEV 0.0.0.0 + sudo brctl addif $BRIDGE $LAN_DEV + sudo dhclient $BRIDGE || { + echo "DHCP failed. Recovering..." + bridge_stop + false + } +} +bridge_add() { + echo "Adding usb0 to the bridge" + sudo brctl delif $BRIDGE $HOST_DEV 2>/dev/null || true # ignore + sudo ifconfig $HOST_DEV 0.0.0.0 + sudo brctl addif $BRIDGE $HOST_DEV +} +bridge_stop() { + sudo ifconfig $BRIDGE down || true # ignore errors + sudo brctl delbr $BRIDGE || true + sudo dhclient $LAN_DEV +} + +### command-line interpreter +if [ $# == "0" ]; then + usage +fi + +while (( $# )); do +case $1 in +--help|-h) + usage + exit + ;; + +-b) shift; BRIDGE=$1 ;; +-s) shift; SERIAL=$1 ;; +-u) shift; HOST_DEV=$1 ;; +-l) shift; LAN_DEV=$1 ;; +-d) shift; DNS1=$1; shift; DNS2=$1 ;; +-p) shift; PHONE_IP=$1 ;; +-a) shift; HOST_IP=$1 ;; +-m) shift; NETMASK=$1 ;; +-e) shift; PHONE_HW=$1 ;; + +rndis) + rndis_start + rndis_test + ;; + +bridge) + ifconfig $HOST_DEV >/dev/null || $0 rndis + bridge_start + bridge_add + route_bridge + ;; + +nat) + ifconfig $HOST_DEV >/dev/null || $0 rndis + nat_start + route_nat + ;; + +nat+secure) + $0 nat + nat_secure + ;; + +stop) + route_reset + ;; + +stop-all) + bridge_stop + nat_stop + route_reset + rndis_stop + ;; + +*) # execute 'advanced command' by function name + $1 + ;; +esac +shift +done