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