1#!/bin/bash
2# Copyright 2010 Google Inc.
3# All right reserved.
4# Author: Szymon Jakubczak <[email protected]>
5#
6# Configure the host and the Android phone for "reverse tethering".
7# (Route all network traffic via the host.)
8
9# default values
10: ${BRIDGE:=usbeth}
11: ${LAN_DEV:=eth0}          # LAN uplink on the host
12: ${HOST_DEV:=usb0}         # name of the RNDIS interface on the host
13: ${PHONE_DEV:=rndis0}        # name of the RNDIS interface on the phone
14
15: ${PHONE_IP:=192.168.77.2} # for NAT and tests
16: ${HOST_IP:=192.168.77.1}
17: ${NETMASK:=255.255.255.0}
18
19# location of the hwaddr utility
20: ${HWADDR:=/home/build/nonconf/google3/experimental/users/szym/moblat/hwaddr/hwaddr-armeabi}
21: ${PHONE_HW:=""}  # hardware (Ethernet) address for the interface (bridge only)
22
23# for NAT configuration
24: ${DNS1:=8.8.8.8}
25: ${DNS2:=8.8.4.4}
26
27# export ADB=/path/to/sdk/adb for custom adb
28ADB="${ADB:-adb} ${SERIAL:+-s $SERIAL}"
29
30set -e
31trap error ERR
32
33error() {
34  echo >&2 "Error occured: $?"
35}
36
37usage() {
38  echo "Usage: $0 <command>"
39  echo "    rndis      -- start RNDIS and test ping the phone"
40  echo "    nat        -- use host as NAT"
41  echo "    nat+secure -- nat + extra security"
42  echo "    bridge     -- use host as bridge"
43  echo "    stop       -- switch back to 3G"
44  echo "    stop-all   -- clean up everything"
45  echo
46  echo "Advanced Commands"
47  echo "  Host:"
48  echo "    nat_start "
49  echo "    nat_secure "
50  echo "    nat_stop "
51  echo "    bridge_start "
52  echo "    bridge_add "
53  echo "    bridge_stop "
54  echo "  Phone:"
55  echo "    rndis_start "
56  echo "    rndis_stop "
57  echo "    rndis_test "
58  echo "    route_nat "
59  echo "    route_bridge "
60  echo "    route_reset "
61  echo
62  echo "Options and Environment Variables:"
63  echo " -h|--help"
64  echo " -b bridge_name                 BRIDGE=$BRIDGE"
65  echo " -s serial_number               SERIAL=$SERIAL"
66  echo " -u host_usb_device             HOST_DEV=$HOST_DEV"
67  echo " -l host_lan_device             LAN_DEV=$LAN_DEV"
68  echo " -d dns1 dns2                   DNS1=$DNS1"
69  echo "                                DNS2=$DNS2"
70  echo " -p phone_ip                    PHONE_IP=$PHONE_IP"
71  echo " -a host_ip                     HOST_IP=$HOST_IP"
72  echo " -m netmask                     NETMASK=$NETMASK"
73  echo " -e hardware_addr               PHONE_HW=$PHONE_HW"
74  echo
75  echo " HWADDR=$HWADDR"
76  echo " ADB=$ADB"
77}
78
79##################################
80### PHONE configuration routines
81##################################
82rndis_start() {
83  echo "Starting RNDIS..."
84  $ADB wait-for-device
85  $ADB shell "svc usb setFunction rndis"
86  $ADB wait-for-device
87  $ADB shell "ifconfig $PHONE_DEV down"
88  if [[ -n "$PHONE_HW" ]]; then
89    $ADB push $HWADDR /data/local/hwaddr  # TODO(szym) handle failures?
90    $ADB shell "/data/local/hwaddr $PHONE_DEV $PHONE_HW"
91    $ADB shell "/data/local/hwaddr $PHONE_DEV"
92  fi
93}
94
95rndis_stop() {
96  $ADB shell "svc usb setFunction" #empty to clear
97}
98
99rndis_test() {
100  # configure some IPs, so that we can ping
101  $ADB shell "ifconfig $PHONE_DEV $PHONE_IP netmask $NETMASK up"
102  sudo ifconfig $HOST_DEV $HOST_IP netmask $NETMASK up
103  echo "Pinging the phone..."
104  ping -q -c 1 -W 1 $PHONE_IP
105  echo "Success!"
106}
107
108update_dns() {
109  $ADB shell 'setprop net.dnschange $((`getprop net.dnschange`+1))'
110}
111
112default_routes() {
113  $ADB shell 'cat /proc/net/route' | awk '{ if ($2==00000000) print $1 }'
114}
115
116route_none() {
117  $ADB shell "svc data disable"
118  $ADB shell "svc wifi disable"
119  # kill all default route interfaces (just in case something remains)
120  for dev in `default_routes`; do
121    $ADB shell "ifconfig $dev down"
122  done
123}
124route_nat() {
125  echo "Setting up phone routes and DNS..."
126  route_none
127  $ADB shell "ifconfig $PHONE_DEV $PHONE_IP netmask $NETMASK up"
128  $ADB shell "route add default gw $HOST_IP dev $PHONE_DEV"
129  $ADB shell "setprop net.dns1 $DNS1"
130  $ADB shell "setprop net.dns2 $DNS2"
131  update_dns
132}
133route_bridge() {
134  echo "Running DHCP on the phone..."
135  route_none
136  $ADB shell "ifconfig $PHONE_DEV up"
137  $ADB shell "netcfg $PHONE_DEV dhcp"
138  $ADB shell "ifconfig $PHONE_DEV"  # for diagnostics
139
140  DNS1=`$ADB shell getprop net.${PHONE_DEV}.dns1`
141  $ADB shell "setprop net.dns1 $DNS1"
142  DNS2=`$ADB shell getprop net.${PHONE_DEV}.dns2`
143  $ADB shell "setprop net.dns2 $DNS2"
144  update_dns
145}
146route_reset() {
147  route_none
148  $ADB shell "svc data enable"
149}
150
151#################################
152### HOST configuration routines
153#################################
154nat_start() {
155  echo "Configuring NAT..."
156  sudo sysctl -w net.ipv4.ip_forward=1
157  sudo iptables -F
158  sudo iptables -t nat -F
159  sudo iptables -t nat -A POSTROUTING -o $LAN_DEV -j MASQUERADE
160  sudo iptables -P FORWARD ACCEPT
161  sudo ifconfig $HOST_DEV $HOST_IP netmask $NETMASK up
162}
163nat_secure() {
164  echo "Making your NAT secure..."
165  sudo iptables -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
166  sudo iptables -A FORWARD -m state --state NEW -i $HOST_DEV -j ACCEPT
167  sudo iptables -P FORWARD DROP
168  sudo ifconfig usb0 $HOST_IP netmask $NETMASK up
169}
170nat_stop() {
171  sudo sysctl -w net.ipv4.ip_forward=0
172  sudo iptables -F
173  sudo iptables -t nat -F
174}
175
176bridge_start() {
177  echo "Configuring bridge..."
178  sudo brctl addbr $BRIDGE || return 0 # all good
179  sudo brctl setfd $BRIDGE 0
180  sudo ifconfig $LAN_DEV 0.0.0.0
181  sudo brctl addif $BRIDGE $LAN_DEV
182  sudo dhclient $BRIDGE || {
183    echo "DHCP failed. Recovering..."
184    bridge_stop
185    false
186  }
187}
188bridge_add() {
189  echo "Adding usb0 to the bridge"
190  sudo brctl delif $BRIDGE $HOST_DEV 2>/dev/null || true # ignore
191  sudo ifconfig $HOST_DEV 0.0.0.0
192  sudo brctl addif $BRIDGE $HOST_DEV
193}
194bridge_stop() {
195  sudo ifconfig $BRIDGE down || true # ignore errors
196  sudo brctl delbr $BRIDGE || true
197  sudo dhclient $LAN_DEV
198}
199
200### command-line interpreter
201if [ $# == "0" ]; then
202  usage
203fi
204
205while (( $# )); do
206case $1 in
207--help|-h)
208  usage
209  exit
210  ;;
211
212-b) shift; BRIDGE=$1 ;;
213-s) shift; SERIAL=$1 ;;
214-u) shift; HOST_DEV=$1 ;;
215-l) shift; LAN_DEV=$1 ;;
216-d) shift; DNS1=$1; shift; DNS2=$1 ;;
217-p) shift; PHONE_IP=$1 ;;
218-a) shift; HOST_IP=$1 ;;
219-m) shift; NETMASK=$1 ;;
220-e) shift; PHONE_HW=$1 ;;
221
222rndis)
223  rndis_start
224  rndis_test
225  ;;
226
227bridge)
228  ifconfig $HOST_DEV >/dev/null || $0 rndis
229  bridge_start
230  bridge_add
231  route_bridge
232  ;;
233
234nat)
235  ifconfig $HOST_DEV >/dev/null || $0 rndis
236  nat_start
237  route_nat
238  ;;
239
240nat+secure)
241  $0 nat
242  nat_secure
243  ;;
244
245stop)
246  route_reset
247  ;;
248
249stop-all)
250  bridge_stop
251  nat_stop
252  route_reset
253  rndis_stop
254  ;;
255
256*) # execute 'advanced command' by function name
257  $1
258  ;;
259esac
260shift
261done
262