Skip to content
  • centos7x64
  • stunnel4.x
  • win_stunnel5.5

参考: https://medium.com/swlh/stunnel-openvpn-server-on-ubuntu-16-04-3c3d4a1910cc

一、简介

   众所周知的原因,在海外直接搭建 OpenVPN 根本无法使用(TCP 模式),或者用段时间就被墙了(UDP 模式)。本文主要介绍如何通过 Stunnel 隐藏 OpenVPN 流量,使其看起来像普通的 SSL 协议传输,从而绕过 gfw

   Stunnel 分为客户端和服务端,客户端负责接收用户 OpenVPN 客户端流量并转化成 SSL 协议加密数据包,然后转发给 Stunnel 服务端,实现 SSL 协议数据传输,服务端然后将流量转化成 OpenVPN 流量传输给 OpenVPN 服务端。因此我们可以在国内搭 Stunnel 客户端,国外搭 Stunnel 服务端。OpenVPN + Stunnel 整体架构如下

架构图

1. 首先需要有个 OpenVPN 服务端

OpenVPN安装

说明的是,Stunnel 不支持 udp 流量转换,所以 OpenVPN 需要以 TCP 模式运行

2.OpenVPN TCP 模式的配置示例

port 4001   # 监听的端口号
proto tcp-server
dev tun
ca /etc/openvpn/server/certs/ca.crt  #   CA 根证书路径
cert /etc/openvpn/server/certs/server.crt  # open VPN 服务器证书路径
key /etc/openvpn/server/certs/server.key  # open VPN 服务器密钥路径,This file should be kept secret
dh /etc/openvpn/server/certs/dh.pem  # Diffie-Hellman 算法密钥文件路径
tls-auth /etc/openvpn/server/certs/ta.key 0 #  tls-auth key,参数 0 可以省略,如果不省略,那么客户端
# 配置相应的参数该配成 1。如果省略,那么客户端不需要 tls-auth 配置
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 转发,类似于代理开全局
compress lzo
duplicate-cn   # 允许一个用户多个终端连接
keepalive 10 120
comp-lzo
persist-key
persist-tun
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
port 4001   # 监听的端口号
proto tcp-server
dev tun
ca /etc/openvpn/server/certs/ca.crt  #   CA 根证书路径
cert /etc/openvpn/server/certs/server.crt  # open VPN 服务器证书路径
key /etc/openvpn/server/certs/server.key  # open VPN 服务器密钥路径,This file should be kept secret
dh /etc/openvpn/server/certs/dh.pem  # Diffie-Hellman 算法密钥文件路径
tls-auth /etc/openvpn/server/certs/ta.key 0 #  tls-auth key,参数 0 可以省略,如果不省略,那么客户端
# 配置相应的参数该配成 1。如果省略,那么客户端不需要 tls-auth 配置
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 转发,类似于代理开全局
compress lzo
duplicate-cn   # 允许一个用户多个终端连接
keepalive 10 120
comp-lzo
persist-key
persist-tun
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

3. Stunnel 服务端安装配置

  • 安装配置 Stunnel 服务端(海外节点)
yum -y install stunnel
cd /etc/stunnel
[root@op stunnel]# openssl req -new -x509 -days 3650 -nodes -out stunnel.pem -keyout stunnel.pem
Generating a 2048 bit RSA private key
...........................................................+++
.........................+++
writing new private key to 'stunnel.pem'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:BeiJing
Locality Name (eg, city) [Default City]:BeiJing
Organization Name (eg, company) [Default Company Ltd]:BeiJing
Organizational Unit Name (eg, section) []:BJ
Common Name (eg, your name or your server's hostname) []:
Email Address []:
[root@op stunnel]# 

chmod 600 /etc/stunnel/stunnel.pem
vim stunnel.conf 填入如下内容:
pid = /var/run/stunnel.pid
output = /var/log/stunnel.log
client = no
[openvpn]
accept = 443   
connect = 127.0.0.1:4001
cert = /etc/stunnel/stunnel.pem
yum -y install stunnel
cd /etc/stunnel
[root@op stunnel]# openssl req -new -x509 -days 3650 -nodes -out stunnel.pem -keyout stunnel.pem
Generating a 2048 bit RSA private key
...........................................................+++
.........................+++
writing new private key to 'stunnel.pem'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:BeiJing
Locality Name (eg, city) [Default City]:BeiJing
Organization Name (eg, company) [Default Company Ltd]:BeiJing
Organizational Unit Name (eg, section) []:BJ
Common Name (eg, your name or your server's hostname) []:
Email Address []:
[root@op stunnel]# 

chmod 600 /etc/stunnel/stunnel.pem
vim stunnel.conf 填入如下内容:
pid = /var/run/stunnel.pid
output = /var/log/stunnel.log
client = no
[openvpn]
accept = 443   
connect = 127.0.0.1:4001
cert = /etc/stunnel/stunnel.pem

说明: accept = 443 # Stunnel 服务端监听端口

connect = 127.0.0.1:4001 # OpenVPN 服务端地址

启动 Stunnel 服务端:

为了管理方便,我们使用 systemd 管理 Stunnel 服务,编辑一个 systemd unit 文件,vim /lib/systemd/system/stunnel.service

[Unit]
Description=SSL tunnel for network daemons
After=network.target
After=syslog.target

[Install]
WantedBy=multi-user.target
Alias=stunnel.target

[Service]
Type=forking
ExecStart=/usr/bin/stunnel /etc/stunnel/stunnel.conf
ExecStop=/usr/bin/killall -9 stunnel

# Give up if ping don't get an answer
TimeoutSec=600

Restart=always
PrivateTmp=false
[Unit]
Description=SSL tunnel for network daemons
After=network.target
After=syslog.target

[Install]
WantedBy=multi-user.target
Alias=stunnel.target

[Service]
Type=forking
ExecStart=/usr/bin/stunnel /etc/stunnel/stunnel.conf
ExecStop=/usr/bin/killall -9 stunnel

# Give up if ping don't get an answer
TimeoutSec=600

Restart=always
PrivateTmp=false
systemctl start stunnel.service
systemctl enable stunnel.service
systemctl start stunnel.service
systemctl enable stunnel.service

4. Stunnel 客户端安装配置

Stunnel 的客户端安装和服务器一样,同样的软件,既可以作为客户端,也可以作为服务端,只是配置不同而已

  • 安装配置 Stunnel 客户端(国内节点)
yum -y install stunnel
cd /etc/stunnel
scp ....  # 将服务端的证书 stunnel.pem 拷贝到这里
chmod 600 /etc/stunnel/stunnel.pem
vim stunnel.conf 填入如下内容:
pid=/var/run/stunnel.pid
output=/var/log/stunnel.log
client = yes

[openvpn]
accept=8443
connect=stunnel_server_ip:443
cert = /etc/stunnel/stunnel.pem
yum -y install stunnel
cd /etc/stunnel
scp ....  # 将服务端的证书 stunnel.pem 拷贝到这里
chmod 600 /etc/stunnel/stunnel.pem
vim stunnel.conf 填入如下内容:
pid=/var/run/stunnel.pid
output=/var/log/stunnel.log
client = yes

[openvpn]
accept=8443
connect=stunnel_server_ip:443
cert = /etc/stunnel/stunnel.pem

说明:

accept=8443 # Stunnel 客户端监听端口

stunnel_server_ip:443 # stunnel 服务端 ip 及端口

  • 启动 Stunnel 客户端
systemctl start stunnel.service
systemctl enable stunnel.service
systemctl start stunnel.service
systemctl enable stunnel.service

5. 使用 OpenVPN 连接 Stunnel

Stunnel + OpenVPN 都配好后,就可以使用 OpenVPN 客户端实现自由上网了,需要注意的是 OpenVPN 客户端现在需要连接的是 Stunnel 客户端,不再是直接连接 OpenVPN 服务端

https://github.com/Xaqron/stunnel

原理

OpenVPN over TLS

VPN使用TCP作为传输协议. stunnel实例用于在TLS / TCP中封装TCP流的内容.你得到这个协议栈:

[IP     ]<------------------------>[IP     ]
[OpenVPN]<------------------------>[OpenVPN]
            [TLS   ]<~~~~~>[TLS]
[TCP    ]<->[TCP   ]<----->[TCP]<->[TCP    ]
[IP     ]<->[IP    ]<----->[IP ]<->[IP     ]
[       ]   [      ]       [   ]   [       ]
 Server      stunnel      stunnel  Client
[IP     ]<------------------------>[IP     ]
[OpenVPN]<------------------------>[OpenVPN]
            [TLS   ]<~~~~~>[TLS]
[TCP    ]<->[TCP   ]<----->[TCP]<->[TCP    ]
[IP     ]<->[IP    ]<----->[IP ]<->[IP     ]
[       ]   [      ]       [   ]   [       ]
 Server      stunnel      stunnel  Client

在stunnel实例之间,你有这个协议栈在线上:

[IP      ]
[OpenVPN ]
[TLS     ]
[TCP(443)]
[IP      ]
[...     ]
[IP      ]
[OpenVPN ]
[TLS     ]
[TCP(443)]
[IP      ]
[...     ]

由于TLS加密其有效负载,攻击者只能看到:

[???     ]
[TLS     ]
[TCP(443)]
[IP      ]
[...     ]
[???     ]
[TLS     ]
[TCP(443)]
[IP      ]
[...     ]

所以是的,它是普通的TLS流量(它可能是HTTP / TLS,SMTP / TLS,POP / TLS或任何其他用于查看流量的人,但它看起来很像HTTP / TLS,因为使用了TCP端口443).您可以使用wireshark进行检查:记录stunnel实例之间的流量.在wireshark UI(流的数据包右键)中,您可以让wireshark将流量解释为TLS:它会将其识别为TLS流量(您将看到不同的TLS消息,但不会看到TLS会话的有效负载

二、win完整配置

  • 下载stunnel

https://www.stunnel.org/downloads.html

下载 stunnel-5.55-win64-installer.exe

  • 安装

stunnel1

  • 启动

stunnel

1.1 win 配置证书

  • 把server端生成的{% em %} stunnel.pem {% endem %}放到win 下 C:\Program Files (x86)\stunnel\config(根据自己路径放置)

1.2 win stunnel.conf

C:\Program Files (x86)\stunnel\config\stunnel.conf
[openvpn]
cert = stunnel.pem
client = yes
accept = 127.0.0.1:8443
connect = 47.56.131.123:443
C:\Program Files (x86)\stunnel\config\stunnel.conf
[openvpn]
cert = stunnel.pem
client = yes
accept = 127.0.0.1:8443
connect = 47.56.131.123:443

accept: stunnel 本地监听port

connect: 指向stunnel server port , 一定的是443 port

注意:在文件末尾添加

1.3 win 配置vpn

  • 下载

https://openvpn.net/community-downloads/

  • 配置xxxx.ovpn
client
dev tun
proto tcp
sndbuf 0
rcvbuf 0
remote 127.0.0.1 8443
resolv-retry infinite
nobind
tun-mtu 1500
tun-mtu-extra 32
mssfix 1450
persist-key
persist-tun
remote-cert-tls server
auth SHA512
cipher AES-256-CBC
setenv opt block-outside-dns
key-direction 1
verb 3
<ca>
....
</ca>
<cert>
....
</cert>
<key>
...
</key>
<tls-auth>
.....
</tls-auth>
client
dev tun
proto tcp
sndbuf 0
rcvbuf 0
remote 127.0.0.1 8443
resolv-retry infinite
nobind
tun-mtu 1500
tun-mtu-extra 32
mssfix 1450
persist-key
persist-tun
remote-cert-tls server
auth SHA512
cipher AES-256-CBC
setenv opt block-outside-dns
key-direction 1
verb 3
<ca>
....
</ca>
<cert>
....
</cert>
<key>
...
</key>
<tls-auth>
.....
</tls-auth>

remote 127.0.0.1 8443 指向本地stunnel 端口

1.4 启动stunnel

以管理员身份运行

status

显示如上信息表示成功

1.5 启动openvpn

以管理员身份运行

启动openvpn