| #!/bin/bash |
| # Copyright 2010 Google Inc. |
| # All right reserved. |
| # Author: Szymon Jakubczak <szym@google.com> |
| # |
| # 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 <command>" |
| 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 |