所需软件:lzo-2.10.tar.gz openvpn-2.4.3.tar.gz

其他版本下载地址:

http://www.oberhumer.com/opensource/lzo/download/

http://build.openvpn.net/downloads/releases/

安装软件:yum install -y gcc gcc-c++ openssl-devel  pam-devel

安装lzo:

tar xf lzo-2.10.tar.gz
cd lzo-2.10
./configure --prefix=/usr/local
make && make install

安装路径使用/usr/local而不是/usr/local/lzo是为了解决安装openvpn时候找不到 lzo_lib 的问题。

tar xf openvpn-2.4.3.tar.gz
cd openvpn-2.4.3
./configure --prefix=/usr/local/openvpn
make && make install

编译访问控制模块 :

在当前安装目录中新建文件 minimal_pf.c

/* minimal_pf.c 
 * ultra-minimal Open××× plugin to enable internal packet filter */
#include <stdio.h>
#include <stdlib.h>
 
#include "include/openvpn-plugin.h"
 
/* dummy context, as we need no state */
struct plugin_context {
  int dummy;
};
 
/* Initialization function */
OPEN×××_EXPORT openvpn_plugin_handle_t openvpn_plugin_open_v1 (unsigned int *type_mask, const char *argv[], const char *envp[]) {
  struct plugin_context *context;
  /* Allocate our context */
  context = (struct plugin_context *) calloc (1, sizeof (struct plugin_context));
 
  /* Which callbacks to intercept. */
  *type_mask = OPEN×××_PLUGIN_MASK (OPEN×××_PLUGIN_ENABLE_PF);
 
  return (openvpn_plugin_handle_t) context;
}
 
/* Worker function */
OPEN×××_EXPORT int openvpn_plugin_func_v2 (openvpn_plugin_handle_t handle,
            const int type,
            const char *argv[],
            const char *envp[],
            void *per_client_context,
            struct openvpn_plugin_string_list **return_list) {
   
  if (type == OPEN×××_PLUGIN_ENABLE_PF) {
    return OPEN×××_PLUGIN_FUNC_SUCCESS;
  } else {
    /* should not happen! */
    return OPEN×××_PLUGIN_FUNC_ERROR;
  }
}
 
/* Cleanup function */
OPEN×××_EXPORT void openvpn_plugin_close_v1 (openvpn_plugin_handle_t handle) {
  struct plugin_context *context = (struct plugin_context *) handle;
  free (context);
}

其他版本的openvpn可能需要修改包含头文件(#include "include/openvpn-plugin.h"),2.1.4版本的openvpn-plugin.h是在根目录

编译:

CC_FLAGS="-O2 -Wall -g"
NAME=minimal_pf
gcc $CC_FLAGS -fPIC -c $NAME.c && gcc $CC_FLAGS -fPIC -shared -Wl,-soname,$NAME.so -o $NAME.so $NAME.o -lc

把编译产生的文件复制到openvpn文件夹中

cp -a minimal_pf.so /usr/local/openvpn/lib/openvpn/plugins/

新版本openvpn好像没有证书管理工具,可以从旧版本中复制过来,只是为了生成一套根证书而已,直接从其他服务器复制几个证书文件过来也可以用。

从旧版本openvpn-2.1.4.tar.gz中复制easy-rsa目录,使用2.0版本工具,修改vars文件中的变量(非必须),加载到当前Shell。

cp -a openvpn-2.4.3/easy-rsa /usr/local/openvpn/
cd /usr/local/openvpn/easy-rsa/2.0/
source vars

清理证书目录

./clean-all

生成CA证书,输入部分可以直接回车,[y/n]部分填y

./build-ca

生成服务器证书,server为任意名字,输入部分可以直接回车,[y/n]部分填y

./build-key-server server

生成Diffie Hellman文件,提高安全性

./build-dh

建立其他目录

cd /usr/local/openvpn/
mkdir ccd  conf logs  pf

openvpn服务器配置:conf/server.conf

port 1194
proto udp
dev tun
ca /usr/local/openvpn/easy-rsa/2.0/keys/ca.crt
cert /usr/local/openvpn/easy-rsa/2.0/keys/server.crt
key /usr/local/openvpn/easy-rsa/2.0/keys/server.key
dh /usr/local/openvpn/easy-rsa/2.0/keys/dh1024.pem
server 10.8.0.0 255.255.255.0
ifconfig-pool-persist /usr/local/openvpn/conf/ipp.txt
push "route 192.168.100.0 255.255.255.0"
keepalive 10 120
comp-lzo
persist-key
persist-tun
status /usr/local/openvpn/logs/openvpn-status.log
log /usr/local/openvpn/logs/openvpn.log
verb 3
auth-user-pass-verify /usr/local/openvpn/sbin/checkpsw.sh via-env
plugin /usr/local/openvpn/lib/openvpn/plugins/minimal_pf.so
client-connect /usr/local/openvpn/sbin/client-connect.sh
client-config-dir /usr/local/openvpn/ccd
client-to-client
client-cert-not-required
username-as-common-name
script-security 3

密码认证脚本/usr/local/openvpn/sbin/checkpsw.sh:

#!/bin/bash
PASSFILE="/usr/local/openvpn/conf/psw-file"
LOG_FILE="/usr/local/openvpn/logs/openvpn-password.log"
TIME_STAMP=`date "+%Y-%m-%d %T"`
if [ ! -r "${PASSFILE}" ]; then
  echo "${TIME_STAMP}: Could not open password file \"${PASSFILE}\" for reading." >> ${LOG_FILE}
  exit 1
fi
CORRECT_PASSWORD=`awk '!/^;/&&!/^#/&&$1=="'${username}'"{print $2;exit}' ${PASSFILE}`
if [ "${CORRECT_PASSWORD}" = "" ]; then 
  echo "${TIME_STAMP}: User does not exist: username=\"${username}\", password=\"${password}\"." >> ${LOG_FILE}
  exit 1
fi

if [ "${password}" = "${CORRECT_PASSWORD}" ]; then 
  echo "${TIME_STAMP}: Successful authentication: username=\"${username}\"." >> ${LOG_FILE}
  exit 0
fi
echo "${TIME_STAMP}: Incorrect password: username=\"${username}\", password=\"${password}\"." >> ${LOG_FILE}
exit 1

访问控制脚本 /usr/local/openvpn/sbin/client-connect.sh:

#!/bin/bash
template="/usr/local/openvpn/pf/${common_name}.pf"
 
if [ -f "$template" ] && [ ! -z "$pf_file" ]; then
  cp -- "$template" "$pf_file"
else
  exit 1
fi

加可执行权限:

chmod +x sbin/checkpsw.sh sbin/client-connect.sh

增加用户名和密码文件:

cat /usr/local/openvpn/conf/psw-file
user1 passd1
user2 passd2

增加个人配置文件(用于根据用户分配路由等配置,非必须):

cat /usr/local/openvpn/ccd/user1
push "route 192.168.101.0 255.255.255.0"

增加访问控制文件(必须),缺少访问控制文件则登录失败,防止权限出错:

cat /usr/local/openvpn/pf/user1
[CLIENTS ACCEPT]
[SUBNETS ACCEPT]
+192.168.100.0/28
-0.0.0.0/0
[END]

以上配置文件,+是允许,-是拒绝,ACCEPT也可以改为DROP,CLIENTS部分填写用户名,具体用法有待探讨。

开启IP转发和NAT,端口eth0和网段10.8.0.0/24根据实际配置调整:

echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf 
sysctp -p
iptables -t nat -A POSTROUTING -o eth0 -s 10.8.0.0/24 -j MASQUERADE
/etc/init.d/iptables save
chkconfig iptables on

启动openvpn服务:

/usr/local/openvpn/sbin/openvpn --config /usr/local/openvpn/conf/server.conf --daemon

查看日志,出现 Initialization Sequence Completed 则启动成功:

tailf logs/openvpn.log
Thu Sep 28 14:06:30 2017 MULTI: multi_init called, r=256 v=256
Thu Sep 28 14:06:30 2017 IFCONFIG POOL: base=10.8.0.4 size=62, ipv6=0
Thu Sep 28 14:06:30 2017 ifconfig_pool_read(), in='ouzy,10.8.0.4', TODO: IPv6
Thu Sep 28 14:06:30 2017 succeeded -> ifconfig_pool_set()
Thu Sep 28 14:06:30 2017 ifconfig_pool_read(), in='gcc,10.8.0.8', TODO: IPv6
Thu Sep 28 14:06:30 2017 succeeded -> ifconfig_pool_set()
Thu Sep 28 14:06:30 2017 IFCONFIG POOL LIST
Thu Sep 28 14:06:30 2017 ouzy,10.8.0.4
Thu Sep 28 14:06:30 2017 gcc,10.8.0.8
Thu Sep 28 14:06:30 2017 Initialization Sequence Completed

Windows客户端从openvpn.net下载安装 openvpn-install-*.exe

下载页面:https://openvpn.net/index.php/open-source/downloads.html

把服务器的CA证书 /usr/local/openvpn/easy-rsa/2.0/keys/ca.crt 下载并复制到客户端的openvpn安装目录config下,再在config目录新建一个配置文件 client.ovpn ,名字随意,后缀名要一致,把配置文件的x.x.x.x换成openvpn服务器IP:

setenv CLIENT_CERT 0
client
dev tun
proto udp
remote x.x.x.x 1194
resolv-retry infinite
nobind
persist-key
persist-tun
auth-user-pass
ns-cert-type server
comp-lzo
verb 3
auth-nocache
reneg-sec 0
ca ca.crt

打开客户端连接,输入用户名密码即可。