编译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两个文件。

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

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

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

经过测试,也是可以的。

编译liblzo

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

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

  1. LOCAL_PATH:= $(call my-dir)
  2. common_SRC_FILES:= \
  3. ../src/lzo_crc.c \
  4. ../src/lzo_init.c \
  5. ../src/lzo_ptr.c \
  6. ../src/lzo_str.c \
  7. ../src/lzo_util.c \
  8. ../src/lzo1.c \
  9. ../src/lzo1_99.c \
  10. ../src/lzo1a.c \
  11. ../src/lzo1a_99.c \
  12. ../src/lzo1b_1.c \
  13. ../src/lzo1b_2.c \
  14. ../src/lzo1b_3.c \
  15. ../src/lzo1b_4.c \
  16. ../src/lzo1b_5.c \
  17. ../src/lzo1b_6.c \
  18. ../src/lzo1b_7.c \
  19. ../src/lzo1b_8.c \
  20. ../src/lzo1b_9.c \
  21. ../src/lzo1b_99.c \
  22. ../src/lzo1b_9x.c \
  23. ../src/lzo1b_cc.c \
  24. ../src/lzo1b_d1.c \
  25. ../src/lzo1b_d2.c \
  26. ../src/lzo1b_rr.c \
  27. ../src/lzo1b_xx.c \
  28. ../src/lzo1c_1.c \
  29. ../src/lzo1c_2.c \
  30. ../src/lzo1c_3.c \
  31. ../src/lzo1c_4.c \
  32. ../src/lzo1c_5.c \
  33. ../src/lzo1c_6.c \
  34. ../src/lzo1c_7.c \
  35. ../src/lzo1c_8.c \
  36. ../src/lzo1c_9.c \
  37. ../src/lzo1c_99.c \
  38. ../src/lzo1c_d1.c \
  39. ../src/lzo1c_d2.c \
  40. ../src/lzo1c_rr.c \
  41. ../src/lzo1c_xx.c \
  42. ../src/lzo1f_1.c \
  43. ../src/lzo1f_9x.c \
  44. ../src/lzo1f_d1.c \
  45. ../src/lzo1f_d2.c \
  46. ../src/lzo1x_1.c \
  47. ../src/lzo1x_9x.c \
  48. ../src/lzo1x_d1.c \
  49. ../src/lzo1x_d2.c \
  50. ../src/lzo1x_d3.c \
  51. ../src/lzo1x_o.c \
  52. ../src/lzo1x_1k.c \
  53. ../src/lzo1x_1l.c \
  54. ../src/lzo1x_1o.c \
  55. ../src/lzo1y_1.c \
  56. ../src/lzo1y_9x.c \
  57. ../src/lzo1y_d1.c \
  58. ../src/lzo1y_d2.c \
  59. ../src/lzo1y_d3.c \
  60. ../src/lzo1y_o.c \
  61. ../src/lzo1z_9x.c \
  62. ../src/lzo1z_d1.c \
  63. ../src/lzo1z_d2.c \
  64. ../src/lzo1z_d3.c \
  65. ../src/lzo2a_9x.c \
  66. ../src/lzo2a_d1.c \
  67. ../src/lzo2a_d2.c
  68. common_C_INCLUDES += $(LOCAL_PATH)/../include
  69. # static library
  70. # =====================================================
  71. include $(CLEAR_VARS)
  72. LOCAL_SRC_FILES:= $(common_SRC_FILES)
  73. LOCAL_C_INCLUDES:= $(common_C_INCLUDES)
  74. LOCAL_MODULE := liblzo
  75. LOCAL_PRELINK_MODULE:= false
  76. include $(BUILD_STATIC_LIBRARY)
COPY

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

  1. # The ARMv7 is significanly faster due to the use of the hardware FPU
  2. NDK_TOOLCHAIN_VERSION := 4.9
  3. APP_ABI := x86
  4. #
  5. APP_PLATFORM := android-8
  6. #APP_STL:=stlport_static
  7. APP_STL := gnustl_static
  8. APP_CPPFLAGS += -std=c++11
COPY

这样可以只编译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):

  1. LOCAL_PATH:= $(call my-dir)
  2. #on a 32bit maschine run ./configure --enable-password-save --disable-pkcs11 --with-ifconfig-path=/system/bin/ifconfig --with-route-path=/system/bin/route
  3. #from generated Makefile copy variable contents of openvpn_SOURCES to common_SRC_FILES
  4. # append missing.c to the end of the list
  5. # missing.c defines undefined functions.
  6. # in tun.c replace /dev/net/tun with /dev/tun
  7. include $(CLEAR_VARS)
  8. LOCAL_MODULE := libcrypto
  9. LOCAL_SRC_FILES := $(LOCAL_PATH)/openssl/$(TARGET_ARCH_ABI)/lib/libcrypto.a
  10. include $(PREBUILT_STATIC_LIBRARY)
  11. include $(CLEAR_VARS)
  12. LOCAL_MODULE := libssl
  13. LOCAL_SRC_FILES := $(LOCAL_PATH)/openssl/$(TARGET_ARCH_ABI)/lib/libssl.a
  14. include $(PREBUILT_STATIC_LIBRARY)
  15. include $(CLEAR_VARS)
  16. LOCAL_MODULE := liblzo
  17. LOCAL_SRC_FILES := $(LOCAL_PATH)/liblzo/$(TARGET_ARCH_ABI)/lib/liblzo.a
  18. include $(PREBUILT_STATIC_LIBRARY)
  19. include $(CLEAR_VARS)
  20. common_SRC_FILES:= \
  21. ../src/openvpn/openvpn.c \
  22. ../src/openvpn/base64.c \
  23. ../src/openvpn/buffer.c \
  24. ../src/openvpn/clinat.c \
  25. ../src/openvpn/console.c \
  26. ../src/openvpn/cryptoapi.c \
  27. ../src/openvpn/crypto.c \
  28. ../src/openvpn/crypto_openssl.c \
  29. ../src/openvpn/dhcp.c \
  30. ../src/openvpn/error.c \
  31. ../src/openvpn/event.c \
  32. ../src/openvpn/fdmisc.c \
  33. ../src/openvpn/forward.c \
  34. ../src/openvpn/fragment.c \
  35. ../src/openvpn/gremlin.c \
  36. ../src/openvpn/helper.c \
  37. ../src/openvpn/httpdigest.c \
  38. ../src/openvpn/init.c \
  39. ../src/openvpn/interval.c \
  40. ../src/openvpn/list.c \
  41. ../src/openvpn/lladdr.c \
  42. ../src/openvpn/lzo.c \
  43. ../src/openvpn/manage.c \
  44. ../src/openvpn/mbuf.c \
  45. ../src/openvpn/misc.c \
  46. ../src/openvpn/mroute.c \
  47. ../src/openvpn/mss.c \
  48. ../src/openvpn/mstats.c \
  49. ../src/openvpn/mtcp.c \
  50. ../src/openvpn/mtu.c \
  51. ../src/openvpn/mudp.c \
  52. ../src/openvpn/multi.c \
  53. ../src/openvpn/ntlm.c \
  54. ../src/openvpn/occ.c \
  55. ../src/openvpn/options.c \
  56. ../src/openvpn/otime.c \
  57. ../src/openvpn/packet_id.c \
  58. ../src/openvpn/perf.c \
  59. ../src/openvpn/pf.c \
  60. ../src/openvpn/ping.c \
  61. ../src/openvpn/pkcs11.c \
  62. ../src/openvpn/pkcs11_openssl.c \
  63. ../src/openvpn/platform.c \
  64. ../src/openvpn/plugin.c \
  65. ../src/openvpn/pool.c \
  66. ../src/openvpn/proto.c \
  67. ../src/openvpn/proxy.c \
  68. ../src/openvpn/ps.c \
  69. ../src/openvpn/push.c \
  70. ../src/openvpn/reliable.c \
  71. ../src/openvpn/route.c \
  72. ../src/openvpn/schedule.c \
  73. ../src/openvpn/session_id.c \
  74. ../src/openvpn/shaper.c \
  75. ../src/openvpn/sig.c \
  76. ../src/openvpn/socket.c \
  77. ../src/openvpn/socks.c \
  78. ../src/openvpn/ssl.c \
  79. ../src/openvpn/ssl_openssl.c \
  80. ../src/openvpn/ssl_verify.c \
  81. ../src/openvpn/ssl_verify_openssl.c \
  82. ../src/openvpn/status.c \
  83. ../src/openvpn/tun.c
  84. common_CFLAGS += -DHAVE_CONFIG_H
  85. common_C_INCLUDES += \
  86. $(LOCAL_PATH)/openssl/include \
  87. $(LOCAL_PATH)/liblzo/include \
  88. $(LOCAL_PATH)/../include \
  89. $(LOCAL_PATH)/../src/compat
  90. common_SHARED_LIBRARIES :=
  91. # static linked binary
  92. # =====================================================
  93. include $(CLEAR_VARS)
  94. LOCAL_SRC_FILES:= $(common_SRC_FILES)
  95. LOCAL_CFLAGS:= $(common_CFLAGS)
  96. LOCAL_C_INCLUDES:= $(common_C_INCLUDES)
  97. LOCAL_SHARED_LIBRARIES += $(common_SHARED_LIBRARIES)
  98. LOCAL_STATIC_LIBRARIES:= libssl libcrypto liblzo
  99. LOCAL_LDLIBS += -lz
  100. LOCAL_MODULE:= openvpn
  101. LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
  102. include $(BUILD_EXECUTABLE)
COPY

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进行测试。

分享

Related Issues not found

Please contact @drunkdream to initialize the comment