openvpn通过ss隐藏流量

作为一个开发者,日常工作就是解决各类开发问题。但是,由于众所周知的原因,有些问题的难度不在于问题本身,而在于其它的东西

科学上网

  1. 浏览器上网问题(比如google一些资料啊),一般各种科学上网工具都都解决

  2. 一些软件需要外网,但是又没有配置代理的功能

    可以考虑用ss的全局代理或proxifier等工具

  3. 还有极少数的软件,用以上两种办法都没法解决的
    比如使用 go get

    通常,go get 可以在 GO111MODULEon时,使用代理。但是在使用 go-flutter时,要求不能设为on

    然后我尝试了各种方法,在win下面都不能成功正常使用(linux下却go get成功了),也不知道是不是win本身的问题

vpn

因为众所周知的原因,市面上各大vpn会被轻易的识别出来,因为vpn一般的不会隐藏流量。所以我们要学会用一些方法来隐藏一下流量,比如用利用隧道

openvpn为例

正常情况

openvpn client <-> openvpn server

用隧道的情况

openvpn client <-> 隧道入口 <-> 隧道服务(ss/ssh等) <-> 隧道出口 <-> openvpn server

即 client 和 server 之间,利用隧道来隐藏流量

ssh隧道

ssh隧道是很常见的一种方式,只是在下用得少

安全性肯定没得说,能否被某系统识别这就不知道了,毕竟用得少

ss隧道

我以前看过ss的wiki,发现有一个配置是也是讲openvpn的,用的是openvpn的内置代理socks-proxy,但是我试了几次都没成功,发现代理不生效。并且我把本的ss关了后,opv仍然能连接。。。

然后,思索了下,虽然没成功,也算有点灵感

ss-libev里面,有一个ss-tunnel就是专门用于端口转发的,那么我们可以用他来做个隧道。然后通过这个隧道来建立openvpn的c/s的连接

ps:笔者试了openvpn如果用udp方式连接,那么这种方式不成功,不知道是不是哪里的配置不小心搞错了。以下步骤是基于openvpn使用tcp方式连接

下面说一下具体步骤

1、先确定本地的ss client 能正常连接服务端的 ss server

由于这个前面已经写过了,这里就不用写了

shadowsocks常用配置

2、用ss-tunnel建立一个隧道

ss-tunel编译

下载好ss-tunnel,并在同一文件夹下建一个配置文件 config.json

1
2
3
4
5
6
7
8
9
10
{
"server": "SS_SERVER_IP",
"server_port": 8388,
"local_port": 1194,
"password": "PASSWORD",
"method": "aes-256-cfb",
"tunnel_address": "172.17.0.1:1194",
"mode": "tcp_and_udp",
"timeout": 5
}

比如在win中,目录结构如下

1
2
3
├─ config.json
├─ run.bat
├─ ss-tunnel-x64.exe

其中run.bat中,就一句代码

1
.\ss-tunnel-x64.exe -c .\config.json

将配置文件的设设置正确,与ss客户端的配置大致相同

其中:

local_port:本地监听端口,也就是上文提到的隧道入口的端口

tunnel_address: 目标地址和端口,即上文提到的隧道出口的地址和端口

示例中,因为我的openvpnss-server在同一台机器上,并且都是用docker跑的,所以用 172.17.0.1(用docker内网也可以,但是用docker内置dns则不能,原因未明)

3、在命令行中运行

1
.\ss-tunnel-x64.exe -c .\config.json

或者直接运行目录中的run.bat

隧道建立成功后,我们在本地访问 local_port (localhost:local_port),就会访问到相对于ss-server服务端的tunnel_address

以示例配置文件为config.json例,访问本地的1194端口时,ss-tunnel会将请求转发到服务端,并从服务端访问 172.17.0.1:1194

4、修改openvpn的配置文件

openvpn的配置文件为 xxxx.ovpn

修改你的ovpn配置文件

1
2
3
4
...
remote 127.0.0.1 1194 tcp
route SS_SERVER_IP 255.255.255.255 net_gateway
...

通常情况,一般为直接连接,则 remote 后面通常为一个公网ip,比如我把vpn搭在和ss-server搭在同一台电脑上,则这里的ip就和ss-server的ip一致。

现在,因为用到的隧道,就应该填隧道的ip和端口,以示例config.json为例,就填 remote 127.0.0.1 1194 tcp
(示例中,ss-tunnel和openvpn在同一台机器上,如果不同机,则以实际为准)

然后,就是还要加上一句 route XXX_IP 255.255.255.255 net_gateway

这句的意思是 XXX_IP的流量,用直连方式,不通过vpn。这句很重要的,因为vpn是全局的,默认情况ss的连接也会走vpn,如果不排除,则ss也不能连接到远程服务器了

另因为我的ss-client和openvpn-client在同一机器,所以排除的是ss-client连接的服务端地址

如果ss-client和openvpn-client 不在同一机器,则应该排除的是ss-client的ip地址

5、将修改后的ovpn文件重新导入openvpn-client中,正常情况下,就能连接了

6、优点

  1. 全局,比proxifier的全局更彻底
  2. 用ss的加密隧道隐藏了openvpn的流量,使之相对不易被封
  3. 这种方式不用将openvpn的服务端的端口暴露(监听0.0.0.0),以示例来说,openvpn 只需监听172.17.0.1:1194就行了

7、缺点

肯定比较慢一点

其它

ss-tunnel编译

详情见
https://github.com/shadowsocks/shadowsocks-libev

我一般在linux下编译,跨平台编译依赖docker

1
2
3
4
5
6
7
git clone https://github.com/shadowsocks/shadowsocks-libev

cd shadowsocks-libev/docker/mingw

git submodule init && git submodule update

make

openvpn安装

一般习惯用docker了,然后用docker-compose编排

先上一个docker-compose.yml文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
version: '2.1'
services:
server:
container_name: 'openvpn'
image: 'kylemanna/openvpn'
volumes:
- openvpn_data:/etc/openvpn
ports:
- 1194:1194
privileged: true
networks:
- frontend
restart: always
env_file:
- .env
volumes:
openvpn_data:
external:
name: ovpn-data-example
networks:
frontend:
external:
name: frontend

其中的network和 volume 是个人习惯,即会先在外部用docker创建

1
2
docker network create frontend
docker volume create --name ovpn-data-example

步骤

准备工作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

# 先准备
# 随便找一个文件夹再创建一个openvpn文件夹。比如 ~/openvpn

mkdir ~/openvpn && cd ~/openvpn

# 创建一个上面的 docker-compose.yml 文件。

cat <<eof > docker-compose.yml
version: '2.1'
services:
server:
container_name: 'openvpn'
image: 'kylemanna/openvpn'
volumes:
- openvpn_data:/etc/openvpn
ports:
- 1194:1194
privileged: true
networks:
- frontend
restart: always
env_file:
- .env
volumes:
openvpn_data:
external:
name: ovpn-data-example
networks:
frontend:
external:
name: frontend
eof

# 新建 .env文件,写入相关信息
# 这一步我们定义两个变量,OPV_HOST 和 OPV_SCHEME
# OPV_HOST指你的公网ip,或域名
# OPV_SCHEME指opvpn的协议,openvpn支持 tcp 和udp. 本文中,在测试udp转发时失败了,所以用tcp

cat <<eof > .env
OPV_HOST=www.baidu.commmmm
OPV_SCHEME=tcp
eof


# 准备工作做完了,下面开始

运行一个容器并配置

  1. 运行一个容器

    1
    docker-compose run --rm server bash
  2. 创建配置

    1
    ovpn_genconfig -u ${OPV_SCHEME}://${OPV_HOST}
  3. 初始化

    1
    2
    touch /etc/openvpn/vars
    ovpn_initpki

    该步骤会填写相关信息

    Enter PEM pass phrase: 输入123456(你是看不见的)
    Verifying - Enter PEM pass phrase: 输入123456(你是看不见的)
    Common Name (eg: your user, host, or server name) [Easy-RSA CA]:回车一下
    Enter pass phrase for /etc/openvpn/pki/private/ca.key:输入123456

  4. 创建用户
    命令中的 CLIENTNAME 为你的客户端用户名

    1
    2
    easyrsa build-client-full CLIENTNAME nopass
    Enter pass phrase for /etc/openvpn/pki/private/ca.key:输入123456 (你是看不见的)
  5. 生成密钥
    生成的密钥因为需要使用并且还要传给客户端,所以退出容器操作比较方便

    按下 ctrl + d ,即可退出容器

    执行以下命令

    命令中的 CLIENTNAME 为你的客户端用户名

    1
    docker-compose run --rm server ovpn_getclient CLIENTNAME > CLIENTNAME.ovpn
  6. 将生成的 CLIENTNAME.ovpn 发送到客户端以供使用

  7. 运行openvpn服务

    1
    docker-compose up -d

    自此,openvpn服务就能成功运行了

0%