Transparent Tethering for Android & Linux

Update 10/4/2010: New post that does this in a much simpler way using OpenVPN.

I’m a new Android user on my HTC Incredible, and while I’ve read that the next version of Android is going to support tethering, it might take a while for this to be supported on existing HTC devices and I’m not sure I believe Verizon will let HTC ship it. So the hacker that I am, I found a relatively elegant way to tether. The only catch is that you need some other Linux machine with a public facing address on the Internet to serve as your “router”.

The only other good technique I found that works on Linux is to use an app that provides port forwarding or a SOCKS server. This isn’t really tethering as I understand it. SOCKS gets you only so far: it won’t do DNS, for instance, and it only works in applications that support SOCKS. The solution here provides what looks like a full Internet connection to the tethered device.

The gist is:

  • The laptop you want to tether uses the socat tool to create basically a virtual ethernet device (“tun0”) that forwards packets over a TCP connection, rather than a physical cable. The tun0 device is set up as the default gateway for the computer so that its Internet connection goes through the virtual device.
  • This TCP connection goes first to localhost, but an Andr0id SDK tool forwards the TCP connection over the USB cable to your phone.
  • The Connect Bot app on your phone makes an SSH connection to the host computer and sets up port forwarding from the phone to the host. I’m not particularly concerned about encrypting the traffic, but the advantage of using a port-forward over SSH (versus using e.g. the Internet Sharer app by JADS to forward directly) is that on the host side we can make sure that we only provide Internet sharing for ourselves and not the whole world.
  • The host computer is listening for the connection from localhost only and forwards packets from the connection back into a second virtual ethernet device (“tun0” on the hots). Internet sharing (NAT) is enabled for the tun0 device so that the packets get routed to the Internet.

You will need…

  • An Android phone. I’m testing on Android 2.1. No root access is required here.
  • A Linux computer to tether. I’m testing on Ubuntu 9.04. Root access required.
  • A Linux computer that has a permanent connection to the Internet with a public IP address on which you have root access. This is the host computer. I’m testing this one with Ubuntu 10.04.

Before you begin…

On the phone, install the free Connect Bot app from the marketplace. Enable USB debugging on the phone in Settings -> Applications -> Development -> USB debugging, which allows us to forward connections over the USB cable.

On the computer to tether, while you still have an Internet connection, download  the Android SDK for Linux. Extract it and find the adb tool. On both the computer to tether and the host computer, make sure you have socat installed. (In Ubuntu, apt-get install socat.)

On the phone:

Start the Connect Bot app. Create & start a new SSH connection to your host computer. Add a port forward (hit Menu) with the options: Type=Local; Source port=9000; Destination=localhost:9000.
On the forwarding host computer:
You can do this either locally before you leave, or through the SSH connection you just made. Everything here must be run as root:
Forward connections from local port 9000 to a new virtual tunnel device tun0 and assign the computer the IP address 192.168.0.1 on this network:

sudo socat TUN:192.168.0.1/24,up

TCP-LISTEN:9000,bind=127.0.0.1

(TUN goes first so that the device is set up before socat blocks while listening for connections)

Set up the NAT internet connection sharing. If you use Firestarter, a nice firewall configuration tool, you can enable this easily in Edit -> Preferences, choose the local network device as tun0, and turn on enable internet connection sharing. This probably won’t stick across a reboot since the tun0 device won’t be available when Firestarter starts next time.
To set up NAT from a command line, see these instructions, but substitute tun0 for eth1:
echo 1 > /proc/sys/net/ipv4/ip_forward
/sbin/iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
/sbin/iptables -A FORWARD -i eth0 -o tun0 -m state –state RELATED,ESTABLISHED -j ACCEPT
/sbin/iptables -A FORWARD -i tun0 -o eth0 -j ACCEPT
On the tethering computer:
It would be a good idea to turn off wireless networking and unplug any ethernet cables at this point. Then connect the computer to the phone with the USB cable.
Start the connection forwarding from the directory containing the adb tool from the Android SDK:
sudo ./adb forward tcp:9000 tcp:9000
sudo socat TUN:192.168.0.2/24,up TCP:localhost:9000
Put socat into the background with CTRL+Z and bg, or start a new terminal. Add routing information for the rest of the network:
sudo route add default tun0

Check that the connections are working:
ping 192.168.0.2 <— pinging itself, should be fast
ping 192.168.0.1 <— pinging host computer, should be slow

Add to /etc/resolv.conf the IP address of the DNS nameserver used by the forwarding host computer, i.e.:
nameserver 192.168.1.1
Or check out what you need by running:
ssh 192.168.0.1 -C “cat /etc/resolv.conf” | grep nameserver

And you should be good to go.