If you only need to route traffic on Android through a ssh tunnel (not proxy), just use http://code.google.com/p/sshtunnel/
If all you need to do is to inspect network traffic, you can use Wireshark on Genymotion.

If however, you're on Genymotion and/or need to get Android traffic through a proxy, especially if you're trying to conduct MITM attacks or need to inspect network traffic, read-on. This article also assumes you're on either a Mac or Linux computer. Sorry, Windows users.

My requirements for this setup were:
1. inspect, save and playback network traffic
2. capture *all* incoming and outgoing TCP traffic from android devices, not just HTTP connections
3. write code to mangle and manipulate traffic as needed

I tried pretty much every technique I knew about and found on the internet, and found only *one* method consistently reliable and that worked on Genymotion: a combination of ssh, redsocks, iptables and a python proxy. To use this setup for an physical Android device, I connect it to the same wireless network, and then use ConnectBot to ssh-tunnel into the host computer.

Genymotion

First let's talk about getting this working on Genymotion.

Genymotion runs the Android emulator in a virtualbox instance. Contrary to what many report online, setting the proxy via Settings > Wifi > Manage really isn't enough. It doesn't force all network connections through a particular proxy. Interestingly, setting the proxy at host operating system level didn't work either (in Ubuntu 12.04 at least). Virtualbox seemed to be ignoring this setting and connecting directly. And running tsocks genymotion didn't work too. Neither did using connectbot or proxydroid with global proxy enabled.

Having said that, you should try the Wifi proxy approach first. It's way way easier and may be sufficient for your needs!

In the Genymotion Android emulator
Settings -> Wifi -> Long-presson active network
Select "Modify Network"
Select "Show Advanced Options"
Select "Proxy Settings -> Manual"
Hostname: 10.0.3.2
Port: 8888
Press Save

(this assumes Charles is listening in on port 8888). The 10.0.3.2 is Genymotion's special IP for the host IP. Now, if you use the Android browser, requests *should* be visible in Charles. If this is not happening, then something is wrong. If Android browser requests are visible in Charles but not the traffic you're interested in, then read on…

As this link explains really well, virtualbox operates at a lower level than socks, it's actually not possible to route virtualbox connections directly through a socks proxy. We'll get around this by using iptables and redsocks.

Our final application stack will look like this:

TCP requests from applications > iptables > redsocks > python proxy > ssh tunnel > internet

I'm almost positive it's possible to eliminate one or more steps with the right iptables wizardry, but I had already wasted so much time getting this working, I was just relieved to have a working solution.

First, setup your SSH tunnel with dynamic port forwarding (SOCKS forwarding) on port 7777. (I assume there is a SSH server you can tunnel into. If you don't have one, try the Amazon EC2 free-pricing tier)

 

Then setup iptables to route all TCP connections to port 5555. Remember: you have to do the SSH connect *before* changing iptables. Once the ssh connection is live, it stays alive (assuming you have keep-alive configured).

Put the following into a script called redsocks-iptables.sh

span class="st0">'user'

This iptables script basically redirects all tcp connections to port 5555.

And put this in redsocks-iptables-reset.sh

 

Use this to reset your iptables to the original state (assuming you don't already have any rules in there).

Now we use redsocks to route these tcp connections to a socks proxy. You may have to install some dependencies such as libevent.

 

Save this as redsocks.conf

span class="st0">"file:/tmp/reddi.log"

And run redsocks like so:

 

Now we need to setup the python proxy. This listens in on port 6666 (the port redsocks forwards requests to) and forwards requests out to 7777 (the ssh socks port). Download it from http://code.activestate.com/recipes/502293-hex-dump-port-forwarding-network-proxy-server/

Rename it to hexdump.py, and run it like so:

 

Now you're all setup. When you make *any* request from your Genymotion android device, it should appear as coming from your ssh server. And the hexdump of the data appears in the console from which you ran hexdump.py like so.

 

Physical Android devices

To inspect traffic from a physical Android device, I had to go 2 steps further:

1. Setup ssh server locally (where redsocks is running) NOT the destination ssh server
2. Install connectbot and route all network through host (remember to enable the Global proxy option)

Yes, unfortunately, root is required on the device to use the 'Global proxy' option. I read someplace about a non-root workaround using an app called Drony which uses a Android VPN to route traffic to a proxy of your choice, but I didn't get this to work. Maybe you can.

Manipulating traffic

The Python script is pretty easy to decipher. The 2 important functions are:

span class="st0">"client %s -> server %s (%d bytes)\n%s"'->'"dest""caching data until remote connection is open""client %s <= server %s (%d bytes)\n%s"'<='

Here you can intercept the data, inspect it, write it out to file, or modify it as you wish.

Notes

The really nice thing about using the python proxy is how easy it is to write data to file and to write rules to manipulate both incoming and outgoing traffic. Beats wireshark any day of the week. As I'm a little more familiar with Java, I initially got this working using Netty example's HexDumpProxy, but manipulating data in Netty was a gigantic PITA, not to mention the painful edit-compile-run cycle.

The major downside of this approach is not being able to (easily) see which server the data you're manipulating is destined for/coming from: the client and servers are both proxies. There's probably a way around this. If you figure it out, let me know!

If you need to decrypt and inspect SSL connections (I didn't), you can add Charles into the mix, after the python proxy and before the SSH tunnel. Just set the python proxy to out-go to the same port the Charles socks proxy is listening on, and set Charles' upstream socks proxy to the SSH tunnel port (in our case 7777). You'll find this setting in Charles under Proxy > External Proxy Settings

If at times one of the links in the chain breaks down, like the ssh connection dying, you may need to kill redsocks, reset iptables and start over. I didn't have to do this too often.

  • phpfalcon

    there are some apps like ProxyCap that do the ssh tunnel thing for you , just set the rules for "VBOXHEADLESS" ( I'm using osx ) thank you kelvin I just wanted to share that

  • http://www.supermind.org Kelvin Tan

    Tried that (and pretty much every app available) and I couldn't get any of them to trap TCP traffic, just HTTP traffic.

  • David

    interesting. I'm looking for a similar way, to route all Genymotion traffic via a socks proxy.
    My idea was simply to install redsocks directly on the android vm (vbox vm), redirecting android's traffic to an external socks proxy. Did you try this out… I think it's fairly simple.
    Did you give it a try as well?

  • B?o LĂȘ

    I have some question:

    The iptables is running on your host machine, right? How about MacOS user?
    We only use SSH server (tunneling configed) with dynamic port forwarding, and all of these tools are installed on host machine? Please correct me if i'm wrong.

  • Demontager

    I did step by step as you wrote and it worked for me, But one question – why my host system also goes via proxy ? I need only genny machine using it. May i also use predefined proxy which has ip and port to connect ?

  • Nick

    I'm so dumb that I am stuck here "Put the following into a script called redsocks-iptables.sh". Where is "redsocks-iptables.sh"? Thank you.

  • http://www.supermind.org Kelvin Tan

    It doesn't exist. You have to create it.

  • Nick

    Thank you. It works! But the problem is that when I use SSH (USA location) on my Mac and check with whoer.net, DNS shows in USA address just like the IP address. But when I check with whoer.net on Genymotion after following your tutorial, although the ip is the same with the ssh address, but DNS shows in Taiwan address? How to fix it back to USA DNS?