本文主要介绍的是 openvpn 部署过程 以及在 openwrt 搞透明全局代理

vps 系统类型: Centos7


vps 主要执行:

  1. 安装 openvpn 并设置
  2. 打开ipv4数据包转发
  3. 防火墙允许包转发
  4. 添加用户

服务器

添加EPEL源, 并执行更新

yum install epel-release -y && yum update -y && yum upgrade -y

安装openvpn 以及 工具

yum -y install openvpn easy-rsa

生成密钥

复制配置文件 cd /usr/share/easy-rsa/3 cp /usr/share/doc/easy-rsa-${ easy-rsa 版本号 }/vars.example vars

修改 var 项目

#set_var EASYRSA_REQ_COUNTRY     "US"
#set_var EASYRSA_REQ_PROVINCE    "California"
#set_var EASYRSA_REQ_CITY        "San Francisco"
#set_var EASYRSA_REQ_ORG         "Copyleft Certificate Co"
#set_var EASYRSA_REQ_EMAIL       "me@example.net"
#set_var EASYRSA_REQ_OU          "My Organizational Unit"
#set_var EASYRSA_KEY_SIZE        4096
#set_var EASYRSA_ALGO            rsa
#set_var EASYRSA_CA_EXPIRE       3650
#set_var EASYRSA_CERT_EXPIRE     365
#set_var EASYRSA_CERT_RENEW      180
#set_var EASYRSA_CRL_DAYS        60

创建PKI

./easyrsa init-pki

创建CA

./easyrsa build-ca nopass

创建服务器证书

./easyrsa build-server-full openvpn-server nopass

创建DH证书 ./easyrsa gen-dh

创建ta.key openvpn –genkey –secret pki/ta.key

此时目录下会存在几个文件:

- pki/ca.crt
- pki/dh.pem
- pki/issued/openvpn-server.crt
- pki/private/openvpn-server.key
- pki/ta.key

配置OpenVPN

创建日志目录

mkdir -p /var/log/openvpn
chown -R openvpn:openvpn /var/log/openvpn

复制配置文件模版

sudo cp /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz /etc/openvpn/

修改版本文件中的几行

port 1194   # 监听的端口号
proto udp   # 服务端用的协议,udp,默认udp
dev tap
ca ca.crt  #   CA 根证书路径
cert server.crt  # open VPN 服务器证书路径
key server.key  # open VPN 服务器密钥路径,This file should be kept secret
dh dh.pem  # Diffie-Hellman 算法密钥文件路径
tls-auth ta.key 0 # 开启TLS-auth,使用ta.key防御攻击。服务器端的第二个参数值为0,客户端的为1。
ifconfig-pool-persist ipp.txt #服务器自动给客户端分配IP后,客户端下次连接时,仍然采用上次的IP地址(第一次分配的IP保存在ipp.txt中,下一次分配其中保存的IP)。
server 10.8.0.0 255.255.255.0   # 该网段为 open VPN 虚拟网卡网段,不要和内网网段冲突即可。open VPN 默认为 10.8.0.0/24
push "dhcp-option DNS 8.8.8.8"  # DNS 服务器配置,可以根据需要指定其他 ns
push "dhcp-option DNS 8.8.4.4"
push "redirect-gateway def1"   # 客户端所有流量都通过 open VPN 转发,类似于代理开全局,VPN服务器本身要通过客户端原来的网关访问(取消redirect-gateway def1 bypass-dhcp选项后这项必须开启,否则无法访问OpenVPN服务器)
compress lzo
duplicate-cn   # 如果客户端都使用相同的证书和密钥连接VPN,一定要打开这个选项,否则每个证书只允许一个人连接VPN
keepalive 10 120  # 每10秒ping一次,连接超时时间设为120秒。
comp-lzo  # 开启VPN连接压缩,如果服务器端开启,客户端也必须开启
client-to-client #设置客户端是否可以访问客户端
persist-key # 持久化选项可以尽量避免访问在重启时由于用户权限降低而无法访问的某些资源。
persist-tun
max-clients 100 # 允许最大的客户端连接数,默认100
user openvpn  # open VPN 进程启动用户,openvpn 用户在安装完 openvpn 后就自动生成了
group openvpn
log /var/log/openvpn/server.log  # 指定 log 文件位置
log-append /var/log/openvpn/server.log
status /var/log/openvpn/status.log
verb 3
explicit-exit-notify 1  # 设置断线重连功能
cipher AES-256-CBC    #指定数据对称加密算法
auth SHA256
reneg-sec 0   #reneg-sec服务器端会定期检查认证情况,默认3600秒一小时,使用OTP的话尽量时间长一些,否则客户端需要重新输入用户名密码和OTP一次性密码。
auth-nocache  #断线后防止内存中保存用户名和密码来提高安全性

系统设置

允许IP转发

#/etc/sysctl.conf
net.ipv4.ip_forward = 1

执行 sudo sysctl -p 使配置生效

修改防火墙, 添加流量转发

iptables -F
iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -j MASQUERADE

持久化防火墙配置

iptables-save > /etc/sysconfig/iptables

查看防火墙

iptables -nvL -t nat

但是 我测试主机重启 转发失效了, 不清楚为啥; 只要开启firewall

firewall-cmd --permanent --zone=public --add-masquerade
firewall-cmd --zone=external --add-masquerade --permanent
firewall-cmd --permanent --direct --passthrough ipv4 -t nat POSTROUTING -o eth0 -j MASQUERADE -s 10.8.0.0/24
firewall-cmd --reload

启动 OpenVPN

systemctl start openvpn-server@srv.service

日志里看到 journal -xe -f Initialization Sequence Completed 信息, 表示服务端已启动。

添加用户

vim /usr/local/bin/ovpn_mgmt.sh
chmod +x /usr/local/bin/ovpn_mgmt.sh
#!/bin/bash
set -e

# 定义环境变量
export EASY_RSA_DIR="/usr/share/easy-rsa/3"
export CLIENT_CONFIG_DIR="/etc/openvpn/client/config"
export PKI_DIR="${EASY_RSA_DIR}/pki"
export TEMPLATES_DIR="/etc/openvpn/templates"
export CLIENT_USER_DIR="/etc/openvpn/client/user"

# 创建ovpn配置
generate_ovpn() {
	USER_OVPN="${CLIENT_USER_DIR}/${EXPIRED}-${USER}.ovpn"
	# 根据证书生成对应的ovpn文件
    mkdir -p  ${CLIENT_USER_DIR}/
    cp -f ${TEMPLATES_DIR}/ovpn.template ${USER_OVPN}
    echo "<ca>" >> ${USER_OVPN}
    cat ${PKI_DIR}/ca.crt >> ${USER_OVPN}
    echo "</ca>" >> ${USER_OVPN}
    echo "<cert>" >> ${USER_OVPN}
    cat ${PKI_DIR}/issued/${USER}.crt >> ${USER_OVPN}
    echo "</cert>" >> ${USER_OVPN}
    echo "<key>" >> ${USER_OVPN}
    cat ${PKI_DIR}/private/${USER}.key >> ${USER_OVPN}
    echo "</key>" >> ${USER_OVPN}
    echo "<tls-auth>" >> ${USER_OVPN}
    cat /etc/openvpn/pki/ta.key >> ${USER_OVPN}
    echo "</tls-auth>" >> ${USER_OVPN}
    sz --binary ${USER_OVPN}
}

# 添加客户端IP
client_ip_config() {
	# 根据ip地址生成对应的client-config
    sed -e "s,#ipaddress#,${IPADDRESS},g" \
        ${TEMPLATES_DIR}/ipconfig_push.template \
        > ${CLIENT_CONFIG_DIR}/${USER}
}

# 生成客户端证书
add_cert() {
	# 切换到easy-rsa目录
    cd ${EASY_RSA_DIR}
    ${EASY_RSA_DIR}/easyrsa build-client-full ${USER} nopass
}

# 注销客户端证书
revoke_cert() {
	# 切换到easy-rsa目录
    cd ${EASY_RSA_DIR}
    echo "yes" | ${EASY_RSA_DIR}/easyrsa revoke ${USER}
	${EASY_RSA_DIR}/easyrsa gen-crl
}

# 更新客户端证书
renew_cert() {
	# 切换到easy-rsa目录
    cd ${EASY_RSA_DIR}
    echo "yes" | ${EASY_RSA_DIR}/easyrsa renew ${USER} nopass
}

# 检查证书过期时间
check_cert_expired() {
	export EXPIRED=$(date --date="$(openssl x509 -enddate -noout -in ${PKI_DIR}/issued/${USER}.crt |cut -d= -f 2)" --iso-8601)
}

# 创建用户
add_user() {
	if [[ -e "${EASY_RSA_DIR}/pki/reqs/${USER}.req" ]];then
		read -p"此用户已经申请证书,是否重新生成?[y/n]:" ANSWER
		case ${ANSWER} in
		    y|Y)
		        revoke_cert
		        check_cert_expired
		        client_ip_config
		        add_cert
		        generate_ovpn
		        exit 0
		        ;;
			n|N)
				check_cert_expired
				client_ip_config
				generate_ovpn
				;;
		esac
	else
		add_cert
		check_cert_expired
		client_ip_config
		generate_ovpn
	fi
}
# 删除用户
del_user() {
	revoke_cert
	rm -rf ${CLIENT_USER_DIR}/*${USER}.ovpn
	rm -rf ${CLIENT_CONFIG_DIR}/${USER}
}
# 用户旧证过期重新生成证书
renew_user() {
	if [[ -e "${EASY_RSA_DIR}/pki/reqs/${USER}.req" ]];then
        renew_cert
        check_cert_expired
        generate_ovpn
    else
    	echo "用户证书不存在!"
    	exit 1
    fi
}

main() {
    # 切换到easy-rsa目录
    cd ${EASY_RSA_DIR}
    # 根据传入的method运行对应函数
    ${METHOD}
}

# 获取参数
while getopts 'm:u:i:r' OPT;do
    case $OPT in
        u)
            USER="$OPTARG"
            echo "USER=${USER}"
            ;;
        i)
            IPADDRESS="$OPTARG"
            echo "IPADDRESS=${IPADDRESS}"
            ;;
        m)
            METHOD="$OPTARG"
            echo "METHOD=${METHOD}"
            ;;
        ?)
            echo "Usage: $(base \"$0\") -m [add_user|del_user|renew_user] -u USER -i IPADDRESS"
            exit 0
            ;;
    esac
done

main

添加用户

/usr/local/bin/ovpn_mgmt.sh -m add_user -u USERNAME -i 10.8.0.10

删除用户

/usr/local/bin/ovpn_mgmt.sh -m del_user -u USERNAME

客户端

Mac 可以使用 tunnelblick 开源客户端

XXX.ovpn

client
proto udp
dev tap
remote 主机Ip 主机Port
ca ca.crt
cert 生成的用户.crt
key 生成的用户.key
tls-auth ta.key 1
remote-cert-tls server
comp-lzo
verb 0
mute-replay-warnings
resolv-retry infinite
nobind
redirect-gateway
persist-key
persist-tun
cipher AES-256-CBC
auth SHA256

openwrt 使用 openvpn

  1. 添加正常的 openvpn 配置;开启 openvpnredirect-gateway;并启动 openvpn; 会看到一个新的网卡设备(tap 模式), 例如 tap0
  2. 添加 openwrt 一个接口;接口绑定 tap0 设备; 例如 ovn
  3. 在防火墙 zone 添加一个区域 ovn, 并绑定设备 ovn; 调整转发区域; lan -> ovn; ovn -> wan;

测试

  1. https://ipleak.net/
  2. https://dnsleaktest.com/
  3. https://ipv6-test.com/

参考:

  1. CentOS7部署OpenVPN实现内网互通