#!/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