编译Android版本的OpenVPN

0x00 前言

目前网上看到的Android端OpenVPN客户端都是基于VPNService开发的,这种方法不需要root权限,因此使用非常广泛。但是,这种方法需要UI操作,还是不够完美,我更喜欢使用纯命令行的openvpn(需要root权限)。

以下是编译2.3.17 x86版本openvpn过程的记录。

编译环境为:Ubuntu 14.04 64位系统

源码下载地址为:http://build.openvpn.net/downloads/releases/

0x01 依赖库编译

openvpn依赖的库主要有:openssl、liblzo

编译openssl

github上找到一个提供编译方法的项目,它提供的是openssl-1.1.0f版本的编译,按照如下命令可以很快编译出x86版本的静态库。

./build-openssl4android.sh android-x86 x86

但是后来发现,openvpn用到的一些函数已经不支持openssl 1.1以上版本,因此改用1.0.2版本的openssl。下载地址为:https://www.openssl.org/source/old/1.0.2/

修改build-openssl4android.sh中openssl的文件名,然后运行脚本编译。完成后在会在libs\x86\lib目录下生成libcrypto.alibssl.a两个文件。

网上还找到另外一种方法,原理是一致的,方法略有差异。

export CC="$STANDALONE_TOOCHAIN_PATH/bin/i686-linux-android-gcc -mtune=atom -march=atom --sysroot=$STANDALONE_TOOCHAIN_PATH/sysroot"
export AR=$STANDALONE_TOOCHAIN_PATH/bin/i686-linux-android-ar
export RANLIB=$STANDALONE_TOOCHAIN_PATH/bin/i686-linux-android-ranlib
./Configure android-x86 -DOPENSSL_IA32_SSE2 -DAES_ASM -DVPAES_ASM
make

$STANDALONE_TOOCHAIN_PATH是生成的工具链目录,使用build-openssl4android.sh会自动生成该目录。

经过测试,也是可以的。

编译liblzo

liblzo源码可以从http://www.oberhumer.com/opensource/lzo/download/下载。

编译可以参考这个项目,在源码根目录下创建jni目录并进入该目录,创建Android.mk文件,输入以下内容:

LOCAL_PATH:= $(call my-dir)

common_SRC_FILES:=  \
        ../src/lzo_crc.c \
        ../src/lzo_init.c \
        ../src/lzo_ptr.c \
        ../src/lzo_str.c \
        ../src/lzo_util.c \
        ../src/lzo1.c \
        ../src/lzo1_99.c \
        ../src/lzo1a.c \
        ../src/lzo1a_99.c \
        ../src/lzo1b_1.c \
        ../src/lzo1b_2.c \
        ../src/lzo1b_3.c \
        ../src/lzo1b_4.c \
        ../src/lzo1b_5.c \
        ../src/lzo1b_6.c \
        ../src/lzo1b_7.c \
        ../src/lzo1b_8.c \
        ../src/lzo1b_9.c \
        ../src/lzo1b_99.c \
        ../src/lzo1b_9x.c \
        ../src/lzo1b_cc.c \
        ../src/lzo1b_d1.c \
        ../src/lzo1b_d2.c \
        ../src/lzo1b_rr.c \
        ../src/lzo1b_xx.c \
        ../src/lzo1c_1.c \
        ../src/lzo1c_2.c \
        ../src/lzo1c_3.c \
        ../src/lzo1c_4.c \
        ../src/lzo1c_5.c \
        ../src/lzo1c_6.c \
        ../src/lzo1c_7.c \
        ../src/lzo1c_8.c \
        ../src/lzo1c_9.c \
        ../src/lzo1c_99.c \
        ../src/lzo1c_d1.c \
        ../src/lzo1c_d2.c \
        ../src/lzo1c_rr.c \
        ../src/lzo1c_xx.c \
        ../src/lzo1f_1.c \
        ../src/lzo1f_9x.c \
        ../src/lzo1f_d1.c \
        ../src/lzo1f_d2.c \
        ../src/lzo1x_1.c \
        ../src/lzo1x_9x.c \
        ../src/lzo1x_d1.c \
        ../src/lzo1x_d2.c \
        ../src/lzo1x_d3.c \
        ../src/lzo1x_o.c \
        ../src/lzo1x_1k.c \
        ../src/lzo1x_1l.c \
        ../src/lzo1x_1o.c \
        ../src/lzo1y_1.c \
        ../src/lzo1y_9x.c \
        ../src/lzo1y_d1.c \
        ../src/lzo1y_d2.c \
        ../src/lzo1y_d3.c \
        ../src/lzo1y_o.c \
        ../src/lzo1z_9x.c \
        ../src/lzo1z_d1.c \
        ../src/lzo1z_d2.c \
        ../src/lzo1z_d3.c \
        ../src/lzo2a_9x.c \
        ../src/lzo2a_d1.c \
        ../src/lzo2a_d2.c


common_C_INCLUDES += $(LOCAL_PATH)/../include

# static library
# =====================================================

include $(CLEAR_VARS)
LOCAL_SRC_FILES:= $(common_SRC_FILES)
LOCAL_C_INCLUDES:= $(common_C_INCLUDES)
LOCAL_MODULE := liblzo
LOCAL_PRELINK_MODULE:= false
include $(BUILD_STATIC_LIBRARY)

然后,再创建Application.mk文件,输入以下内容:

# The ARMv7 is significanly faster due to the use of the hardware FPU
NDK_TOOLCHAIN_VERSION := 4.9
APP_ABI := x86  
#
APP_PLATFORM := android-8
#APP_STL:=stlport_static
APP_STL := gnustl_static
APP_CPPFLAGS += -std=c++11

这样可以只编译x86版本。

最后,调用ndk编译($NDK为NDK根目录)。

$NDK/ndk-build

编译完会生成/path/to/liblzo/source/obj/local/x86/liblzo.a文件。

0x02 编译openvpn

环境准备

进入openvpn源码根目录,执行:

./configure

这步操作主要是为了生成config.h文件,里面包含了编译时用到的各种宏定义。

在源码根目录下创建jni目录,将config.h拷贝到jni目录中,并编辑该文件。

  • 注释掉#define HAVE_GETPASS 1行,因为Android中没有getpass函数
  • #define IFCONFIG_PATH "/sbin/ifconfig"修改为#define IFCONFIG_PATH "/system/bin/ifconfig"
  • #define IPROUTE_PATH "/sbin/ip"修改为#define IPROUTE_PATH "/system/bin/ip"
  • #define ROUTE_PATH "/sbin/route"修改为#define ROUTE_PATH "/system/bin/route"

进入jni目录,使用前面的方法创建Application.mk文件;然后创建Android.mk文件,输入以下内容(修改自:https://github.com/fries/android-external-openvpn/blob/master/Android.mk):

LOCAL_PATH:= $(call my-dir)

#on a 32bit maschine run ./configure --enable-password-save --disable-pkcs11 --with-ifconfig-path=/system/bin/ifconfig --with-route-path=/system/bin/route
#from generated Makefile copy variable contents of openvpn_SOURCES to common_SRC_FILES
# append missing.c to the end of the list
# missing.c defines undefined functions.
# in tun.c replace /dev/net/tun with /dev/tun


include $(CLEAR_VARS)
LOCAL_MODULE := libcrypto
LOCAL_SRC_FILES := $(LOCAL_PATH)/openssl/$(TARGET_ARCH_ABI)/lib/libcrypto.a
include $(PREBUILT_STATIC_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := libssl
LOCAL_SRC_FILES := $(LOCAL_PATH)/openssl/$(TARGET_ARCH_ABI)/lib/libssl.a
include $(PREBUILT_STATIC_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := liblzo
LOCAL_SRC_FILES := $(LOCAL_PATH)/liblzo/$(TARGET_ARCH_ABI)/lib/liblzo.a
include $(PREBUILT_STATIC_LIBRARY)

include $(CLEAR_VARS)

common_SRC_FILES:= \
        ../src/openvpn/openvpn.c \
        ../src/openvpn/base64.c \
        ../src/openvpn/buffer.c \
        ../src/openvpn/clinat.c \
        ../src/openvpn/console.c \
        ../src/openvpn/cryptoapi.c \
        ../src/openvpn/crypto.c \
        ../src/openvpn/crypto_openssl.c \
        ../src/openvpn/dhcp.c \
        ../src/openvpn/error.c \
        ../src/openvpn/event.c \
        ../src/openvpn/fdmisc.c \
        ../src/openvpn/forward.c \
        ../src/openvpn/fragment.c \
        ../src/openvpn/gremlin.c \
        ../src/openvpn/helper.c \
        ../src/openvpn/httpdigest.c \
        ../src/openvpn/init.c \
        ../src/openvpn/interval.c \
        ../src/openvpn/list.c \
        ../src/openvpn/lladdr.c \
        ../src/openvpn/lzo.c \
        ../src/openvpn/manage.c \
        ../src/openvpn/mbuf.c \
        ../src/openvpn/misc.c \
        ../src/openvpn/mroute.c \
        ../src/openvpn/mss.c \
        ../src/openvpn/mstats.c \
        ../src/openvpn/mtcp.c \
        ../src/openvpn/mtu.c \
        ../src/openvpn/mudp.c \
        ../src/openvpn/multi.c \
        ../src/openvpn/ntlm.c \
        ../src/openvpn/occ.c \
        ../src/openvpn/options.c \
        ../src/openvpn/otime.c \
        ../src/openvpn/packet_id.c \
        ../src/openvpn/perf.c \
        ../src/openvpn/pf.c \
        ../src/openvpn/ping.c \
        ../src/openvpn/pkcs11.c \
        ../src/openvpn/pkcs11_openssl.c \
        ../src/openvpn/platform.c \
        ../src/openvpn/plugin.c \
        ../src/openvpn/pool.c \
        ../src/openvpn/proto.c \
        ../src/openvpn/proxy.c \
        ../src/openvpn/ps.c \
        ../src/openvpn/push.c \
        ../src/openvpn/reliable.c \
        ../src/openvpn/route.c \
        ../src/openvpn/schedule.c \
        ../src/openvpn/session_id.c \
        ../src/openvpn/shaper.c \
        ../src/openvpn/sig.c \
        ../src/openvpn/socket.c \
        ../src/openvpn/socks.c \
        ../src/openvpn/ssl.c \
        ../src/openvpn/ssl_openssl.c \
        ../src/openvpn/ssl_verify.c \
        ../src/openvpn/ssl_verify_openssl.c \
        ../src/openvpn/status.c \
        ../src/openvpn/tun.c 

common_CFLAGS += -DHAVE_CONFIG_H

common_C_INCLUDES += \
        $(LOCAL_PATH)/openssl/include \
        $(LOCAL_PATH)/liblzo/include \
        $(LOCAL_PATH)/../include \
        $(LOCAL_PATH)/../src/compat

common_SHARED_LIBRARIES := 



# static linked binary
# =====================================================

include $(CLEAR_VARS)
LOCAL_SRC_FILES:= $(common_SRC_FILES)
LOCAL_CFLAGS:= $(common_CFLAGS)
LOCAL_C_INCLUDES:= $(common_C_INCLUDES)

LOCAL_SHARED_LIBRARIES += $(common_SHARED_LIBRARIES)
LOCAL_STATIC_LIBRARIES:= libssl libcrypto liblzo

LOCAL_MODULE:= openvpn
LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
include $(BUILD_EXECUTABLE)

libcrypto.alibssl.a拷贝到jni/openssl/x86/lib目录下(自行创建)。

liblzo.a拷贝到jni/liblzo/x86/lib目录下。

将liblzo源码根目录下的include目录拷贝到jni/liblzo目录下。

将openssl源码根目录下的include目录拷贝到jni/openssl目录下。

开始编译

$NDK/ndk-build

完成后,会生成/path/to/openvpn/source/libs/x86/openvpn文件。

0x03 使用Android模拟器测试

openvpn拷贝到模拟器,修改可执行权限;准备好ovpn文件。

  1. 确保ovpn文件中存在dev-node /dev/tun这行,因为Android中和Linux中tun设备路径不一致
  2. 由于默认临时目录为/tmp,需要修改为export TMPDIR=/data/local/tmp;不要通过在命令行增加--tmp-dir /data/local/tmp的方法来实现,否则会导致ovpn文件里的配置项无法被正常加载
  3. ip rule add from 0/0 table main pref 1000修改默认路由表的优先级,避免openvpn修改的路由信息不生效(我不确定这种做法会不会有副作用)
  4. ./openvpn client.ovpn

如果一切顺利的话,此时已经连接成功,可以使用浏览器打开ip138.com进行测试。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏慎独

UITableView实现QQ好友列表实战(动态插入删除Cell)

1225
来自专栏Android开发指南

安卓模拟器

3719
来自专栏流媒体

Android平台下RTMPDump的使用简介

RTMPDump是一个用来处理RTMP流媒体的工具包,是一个C++的开源工程。而我们需要将Android平台下直接使用RTMPDump来进行RTMP推流,这里就...

943
来自专栏醉梦轩

编译Android版本的OpenVPN

1772
来自专栏小鹏的专栏

在mac上安装Xgboost Python库

最近在mac上用到xgboost库,安装时遇到颇多大坑,网上查了很多答案几乎都是win上的问题,没遇到理想的,自己也就摸着石头把几个大坑给填了,总结一下,给后...

22010
来自专栏用户2442861的专栏

CMake使用总结

CMake意为cross-platform make,可用于管理c/c++工程。CMake解析配置文件CMakeLists.txt生成Makefile,相比直...

791
来自专栏张善友的专栏

如何合并Git 代码库中牛人的代码到自己的库

github for Windows使用介绍 这篇文章可以很好带我们入门github,同时还带了一个gitshell,这个工具可以运行github的所有命令,命...

1848
来自专栏QQ音乐技术团队的专栏

Android点九图总结以及在聊天气泡中的使用

点九图的本质实际上是在图片的四周各增加了1px的像素,并使用纯黑的线进行标记,其它的与原图没有任何区别。

4333
来自专栏大数据文摘

Jupyter Notebook的27个窍门,技巧和快捷键

29811
来自专栏iOS开发攻城狮的集散地

iOS开源小项目-WSL

2376

扫码关注云+社区