壹,准备工作
一,下载Openvpn2.4.6的源码:请前往官网下载:https://www.openvpn.net/截止发稿时,最新的OpenVpn的版本是2.4.6
二,下载openssl。
openssl有两个来源,一个是从官网上下载源码,自己编译。不过openssl的编译也挺复杂,且本文重点也不是编译openssl。所以我们可以直接下载OpenSSL的安装包:http://slproweb.com/download/Win64OpenSSL-1_1_0h.exe。
下载后直接安装,安装后openssl的dll库就出现在安装目录中了(如果安装时选择把文件放到系统目录,则dll就在系统目录中了)。
注1:openssl 1.1.0开始由原先的libeay32.dll、ssleay32.dll变成了libcrypto-1_1.dll、libssl-1_1.dll,一些加密方式也发生了变化。
注2:安装后如果没有把openssl的目录添加到环境变量中,可能在编译时就要设置openssl库的路径了。
三,下载lzo,自行前往官网下载:http://www.oberhumer.com/opensource/lzo/,我下载的是2.10版本
四,下载tap 9驱动,下载地址:https://download.csdn.net/download/sspdfn/10474182
五,这里简单介绍下
1、tap驱动是Open实现的核心,它可以在windows上创建一个虚拟网卡,所有的vpn操作都是基于此的。
2、lzo是一解压缩库,类似于zip。
3、openssl,加密用的,编译openvpn会用到这个。
六,安装VS2015/2017
编译2.4.6,要用到wdk10,这只有在vs2015之后的版本才有。笔者一开始用vs2013,但会有问题,详情在后面会写到。
理论上,可以单独下载wdk10,然后vs2013引用 wdk10。这个方法没试过。不过好像wdk10从vs2015后就没有开发单独下载的包,都直接集成到VS IDE中了。有试过这个方法的同学,欢迎留言。
七、vs2013编译openvpn2.3.8
可以参考我的另一篇文章
win7下用vs2013编译openvpn2.3.8源码并生成客户端
贰,编译
一,新建一个工程OpenVpn
1、新建一个工程,工程名叫OpenVpn,选择控制台应用程序,因为Openvpn的核心Openvpn.exe程序就是一个控制台程序。勾选空项目,点完成。
2、把openvpn-2.4.6/src/openvpn中的所有*.h,*.c文件拖到OpenVpn目录中,并将这些文件载入到工程中。
3、把lzo-2.10/src下的所有*.h,*.c,*.ch文件拖到OpenVpn目录中,并将这些文件载入工程中
二、compat.lib的编译
1、解压后的目录openvpn-2.4.6中有一个Openvpn.sln文件,用vs2013打开。打开后可以看到有四个项目,分别是Compat,msvc-generate,openvpn,openvpnserv。今天我们主要讲解对openvpn的编译。但编译openvpn时,有用到compat项目生成的lib,所以我们先把准备工作做好,先讲下compat.lib的编译。
2、将compat目录复制到我们新建的Openvpn工程目录中
在新建的OpenVpn项目中,右键解决方案,添加现有项目,打开compat目录,把compat.vcxproj添加进工程中。这样,就把compat工程添加到我们自己的OpenVpn中了。
3、右键compat生成,报了一堆错,我们一个个解决。
a、无法打开包括文件:config-msvc.h
这个文件就在openvpn-2.4.6下。我们可以看到有一个config-msvc.h和config-msvc-version.h.in文件。这两个文件就是我们想要的。
在OpenVpn项目中新建一个ThirdInclude目录,将上面两个文件添加到C++包含目录中。其他依赖项的头文件,我们都会放在这个ThirdInclude目录中。这个目录也会被OpenVpna项目用到。
b、inet_ntop,inet_pton重定义问题。
相比于openvpn2.3.8,我们没有碰到inet_ntop重定义的问题。因为在config-msvc.h文件末尾对此做了处理:
#if _WIN32_WINNT >= _WIN32_WINNT_VISTA
#define HAVE_INET_NTOP
#define HAVE_INET_PTON
#endif
c、重新生成,就在win32-output中生成了compat.lib。
三,编译OpenVpn
右键OpenVpn生成,报了一堆错
1、无法打开包括文件:config-msvc.h
与编译compat.lib库一样的解决方法,不赘述。
2、无法打开包括文件:compat.h
将openvpn2.4.6/src/compat目录中的compat.h和compat-lz4.h
3、无法打开lzo文件
还记得我们下载的lzo文件吗。解压后,打到include目录,将该目录添加到c++的包含目录中
4、无法打开openssl文件。
我们之前安装了openssl吗,把安装目录中的include/openssl目录,复制到ThirdInclude目录中
5、console_systemd.c中无法打开config.h
这是因为console_systemd.c中引用了config.h,但在windows下,我们不会引用 config.h,所以可以注释或者修改为:
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
5、无法打开openvpn-plugin.h,openvpn-msg.h文件
该文件在openvpn2.3.8下的include目录中,将该目录中这两个文件复制到ThirdInclude目录中
6、无法打开pkcs11-helper-1.0/pkcs11h-certificate.h
这是一难点。因为当把这个文件导入后,会引发出更多问题,到后面就走向了绝路。但事实上,这个文件其实根本没必要引入!
我们打开config-msvc.h编辑,并注释以下:
//#define ENABLE_PKCS11 1
7、无法打开tap-windows.h
该文件在tap-windows-9.9.0_master的include目录中,将该文件复制到ThirdInclude中
8、如果出现错误:未知字符:0x40
打开config-msvc-version.h,将下面三个宏
#define OPENVPN_VERSION_RESOURCE @PRODUCT_VERSION_RESOURCE@
#define TAP_WIN_MIN_MAJOR @PRODUCT_TAP_WIN_MIN_MAJOR@
#define TAP_WIN_MIN_MINOR @PRODUCT_TAP_WIN_MIN_MINOR@
改为
#define OPENVPN_VERSION_RESOURCE 2.4.6
#define TAP_WIN_MIN_MAJOR 9
#define TAP_WIN_MIN_MINOR 21
9、使用了未定义类型"evp_md_ctx_st"
在config-msvc.h中编辑,把 ENABLE_CRYPTO;ENABLE_CRYPTO_OPENSSL; 这两个宏注释另外,再添加三个宏:
_WINSOCK_DEPRECATED_NO_WARNINGS
_CRT_SECURE_NO_WARNINGS
_CRT_NONSTDC_NO_WARNINGS
到预处理器定义中
10,错误C2146
error C2146: 语法错误: 缺少“)”(在标识符“PRIi64”的前面) \openvpn\error.c 345.
PRIi6的定义是:
#define PRIi64 _PFX_64 "i"
在c:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\inttypes.h中被定义。但可能vs2017中没有相关定义。
这个定义只有在error.c 第345行中有引用。所以我们可以把代码改为:
fprintf(fp, "%i.%06lu %x %s%s%s%s",
(int64_t)tv.tv_sec,
(unsigned long)tv.tv_usec,
flags,
prefix,
prefix_sep,
m1,
"\n");
10、无法解析的外部符号 _imp_closesocket@4
右键属性,链接器->输入->附加依赖项,添加wininet.lib;crypt32.lib;iphlpapi.lib;winmm.lib;ws2_32.lib;
11、无法解析的外部符号 _basename。
还记得我们编译出的compat.lib库吗。在VpnProj下新建lib目录,把compat.lib复制到此。然后把lib目录添加到属性-》链接器-》常规-》附加库目录中。然后把compat.lib添加到附加依赖项中。
12、无法解析的外部符号 FwpmEngineClose0
FwpmEngineClose0有用到wdk10中的lib库。百度解决方法,说是要
添加库:ntoskrnl.lib ndis.lib fwpkclnt.lib uuid.lib
添加宏定义:NDIS_SUPPORT_NDIS6但没用。一开始我是用vs2013来编译,但vs2013中没有相关的库,或者准确讲上面几个库,只有wdk10中才有。
为了解决这个问题,我下载了vs2017,并安装。(注:用vs2015安装也可以)
无论是vs2015,还是vs2017,安装时要勾选wdk10,选最新的那个版本。安装完后,用vs2017打开工程,就没报这个错了。
13、无法解析的外部符号 fwpmGetAppIdFromFileName0
添加附加依赖项 Fwpuclnt.lib;
14、生成项目,编译成功,至此大功告成。
四、如果出现以下错误
1、如果出现语法错误;
const cipher_kt_t *cipher_ctx_get_cipher_kt (const cipher_ctx_t *ctx)
__attribute__((nonnull));
无法识别__attribute,这是一个编译选项,注释就行。
const cipher_kt_t *cipher_ctx_get_cipher_kt (const cipher_ctx_t *ctx)
/* __attribute__((nonnull))*/;