HOWTO Cross Compile OpenVPN for Android

Alright. Yeah, I know. Cross Compiling is a nightmare. Probably the google people are asking, why on earth would you want openvpn on Android. Well, this is good for getting around the Android "virtual router" / firewall business. I particularly wanted it because I need a raw L2 ethernet tap device on Android (for doing network RAM over wifi - yeah another stupid question).

Assumptions

  1. You already have a working QEMU emulator as well an SDK for device that you can throw a new kernel onto.
  2. Your wifi works or you can successfully "ssh" out of your QEMU environment to pre-configured host address outside the emulator at 10.0.2.2
  3. You're not looking for a static openvpn. I never tried that. It's not really necessary anyway.

Quick Test For the impatient who just want the binary and don't care about rebuilding it, you can get get that here:

openvpn-2.0.9-arm-android-with-lzo-dynamicssl.tgz

agcc Download a shell script called "agcc" from this location and put it into your path. Apparently, this script wraps a lot of the prebuilt ARM libary locations in the Android SDK properly, particularly libc. You can read the script if you want, but I would just trust it.

The script assumes that the Android ARM tool-chain "arm-eabi-gcc" is in your path. Add "path_to_android/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin/" to your path. If you don't the script will throw up on you.

Next, we'll feed "agcc" to openvpn's ./configure

./configure Now, we have to setup configure correctly. Here's how I did it:

withOUT lzo compression:

$ CC="agcc" ./configure --host=arm-eabi-linux -with-ssl-headers=PATH_TO_ANDROID/external/openssl/include -with-ssl-libs=PATH_TO_ANDROID/out/target/product/generic/obj/lib/ --disable-lzo
$ make

If you want lzo compression, then you have to download and build lzo with the same configure options as above and then feed the lzo path information to openvpn during configure time after you've built lzo. Once you build lzo, just skip the make install step and configure openvpn like so:

$ CC="agcc" ./configure [same options as before] --with-lzo-headers=PATH_TO_LZO/include --with-lzo-lib=PATH_TO_LZO/src/.libs/
$ make

Upload to Device Finally:

$ adb push openvpn-X.X.X/openvpn /data/.
$ adb push PATH_TO_LZO/src/ /data/. #only if you need it

In order to run openvpn, you need a kernel with tun/tap support on the device. (And of course google neglected to build that into the default git configuration). Go to your kernel config location in the SDK, and run make menuconfig. The option is called "Universal Tun / Tap" something or other in the network devices section. Rebuild the kernel and throw it on your device or restart your emulator.

Run OpenVPN NOTE: OpenVPN requires two primary files. I'm assuming you have a correctly configured openvpn server running on the internet or on the host that is running QEMU somewhere. In order for the openvpn client on the device to properly install the dynamic IP addresses and tun/tap devices issued by your openvpn server, the binary needs access to two files on the device:

$ /dev/tun # normally this is /dev/net/tun on Ubuntu

and...

$ /sbin/ifconfig # normally this is /system/bin/ifconfig on the device

However, Android's ifconfig is defective and /dev/tun is in the wrong place. So you have to run OpenVPN like the following:

$ adb shell
$ cd /data/
$ export PATH=/data/busybox:$PATH # get busybox from the .tgz file above
$ ./openvpn --config client.conf --dev-node /dev/tun

And that should get you up and running.....