Replacing OpenVPN with tinc on Tomato/OpenWRT/dd-wrt for bypassing GFW // 使用tinc替代OpenVPN作为路由器自动翻墙方案
作者:Maddie
欢迎转载!转载时请保留作者,注明出处,并在转文中附带原文链接。谢谢!
多年前发现了autoddvpn项目以后,从之前使用dd-wrt到现在用Tomato,都是把这套没人维护的代码不断的修修补补地放到路由上面用。虽然有一些其他搭梯子的方案,但是用OpenVPN加上自定义的routes,用起来感觉是最干净的,所有的用户都不需要在自己的电脑中设置,连接这个路由器的网络就可以自动爬梯了。
不过随着最近GFW越来越强大,它的Advanced DPI对普通的OpenVPN连接会进行干扰,导致使用一段时间就断开,或者干脆就连不上。按照我一贯的作风(懒),装个stunnel以后,把OpenVPN以TCP模式通过stunnel连接也将就用着了。
然后慢慢地发现,在吞吐量高的情况下,通过OpenVPN的所有流量,延迟都会变成非常高(4000ms+),要是看YouTube 1080p的话,别说开其他网页,能不buffering就不错了。OpenVPN用TCP的性能本来就没有UDP的好,加上一层stunnel,性能就更加不要提了。而且stunnel和OpenVPN全部都在路由器上面跑,除非你的是RT-AC68U、R7000这样的ARM路由,否则性能也就别想好到什么地方去了。
也因为这个原因,每当打开Google+各种卡的时候,我都会很自然地打开Chrome寻找替代方案……直到最近,我遇见了tinc。
其实之前也已经看到过关于tinc的一些介绍,但是总觉得挺麻烦的,许多东西都要自己手动去配置(其实还是懒……)。但是实在忍无可忍了,既然决定折腾,那么就动手吧~
经过无数次trial and error,以及在网上参考了一些资料以及tinc的mail list以后,最终成功搭起来了!然后我把我用的脚本以及配置上传到了GitHub。
虽然tinc支持IPv4 and IPv6,但是由于IPv6现在还比较少用的,所以这里就只针对IPv4了。
下面来简单说一下整个过程(以Tomato为例,其他平台配置应该也相似):
Prerequisites
- 首先你得有一个不在GFW里的服务器。我用的是Linode东京的VPS,系统使用Arch Linux。最便宜的套餐$10一个月,一次性购买一年/两年有打折~ 购买链接
- 你需要在路由上安装tinc。这意味着你需要现在路由上部署Optware/Entware。本文使用Entware为例。
- The ability to RTFM and follow instructions.
服务器端配置
i. Enable IPv4 Forwarding in sysctl.conf
首先,你必须把服务器的IPv4转发打开。在大多数Linux发行版中,这个选项默认是关闭的。
# sysctl -w net.ipv4.ip_forward=1
在Arch Linux中,你需要在/etc/sysctl.d/
中新建一个文件(例如50-ip_forward.conf
)来让这个设置在启动时自动生效。
在Debian/Ubuntu等系统中,你需要在/etc/sysctl.conf
中添加net.ipv4.ip_forward=1
来让这个设置在启动时自动生效。
CentOS的话……请自行Google,真没什么使用经验。
ii. 安装tinc
我使用的是Arch Linux的community中的tinc,版本为1.0.24-2。AUR中有一个tinc-pre,版本为1.1pre10,这个版本不建议使用,它使用新的experimental协议,配置上会有出入,而且据闻性能没有原来的版本好。
# pacman -S tinc
在Debian/Ubuntu中则是
# apt-get install tinc
iii. 配置tinc
Arch Linux:
tinc在安装后不会自动在/etc
目录下建立文件夹,我们要手动建立:
# mkdir -p /etc/tinc/server/hosts
这里面的server
是你的NETNAME
,这个名字将用于后面启用服务时使用。
hosts
文件夹用于存放每个host的信息,后面会讲到。
写入配置文件:
(a) tinc.conf
的内容
# cd /etc/tinc/server
# cat tinc.conf
Name = server
Interface = tinc0
当中Name
的值server
为本机(服务器端)的名称。记住你的名称,在后面还会用到。
(b) tinc-up
的内容
# cat tinc-up
#!/bin/sh
ip link set $INTERFACE up
ip addr add 192.168.4.1 dev $INTERFACE
ip route add 192.168.4.254 dev $INTERFACE proto kernel scope link src 192.168.4.1
iptables -A FORWARD -s 192.168.4.0/24 -j ACCEPT
iptables -A FORWARD -d 192.168.4.0/24 -j ACCEPT
iptables -A POSTROUTING -t nat -s 192.168.4.0/24 -j MASQUERADE -o eth0
我使用的网段是192.168.4.0/24,你可以根据自己的需要对这个进行更改。记得把其他地方的subnet也改掉哦!最后的iptables规则中,第三条的eth0是你的VPS面向公网的网卡。
© tinc-down
的内容
# cat tinc-down
#!/bin/sh
ip link set $INTERFACE down
iptables -D FORWARD -s 192.168.4.0/24 -j ACCEPT
iptables -D FORWARD -d 192.168.4.0/24 -j ACCEPT
iptables -D POSTROUTING -t nat -s 192.168.4.0/24 -j MASQUERADE -o eth0
同样,根据需要修改subnet,必须与tinc-up中的保持一致。
(d) hosts/server
的内容
在这里,server
这个文件名必须对应前面在tinc.conf
中设置的Name
参数的值。tinc会根据Name
去匹配hosts
目录下的配置文件。
# cat hosts/server
Address = YOUR.IP.ADDRESS (你的公网地址)
Port = 655
Subnet = 0.0.0.0/0
需要填写的配置文件只有这四个。完成以后,生成private key:
# tincd -n server -K4096
Generating 4096 bits keys:
.................................................................................................................................................................................................++ p
..................................++ q
Done.
Please enter a file to save private RSA key to [/etc/tinc/server/rsa_key.priv]: (私钥)
Please enter a file to save public RSA key to [/etc/tinc/server/hosts/server]: (公钥)
这样会生成一个4096 bit的私钥,生成的密钥保存在默认路径即可。-n
参数后面的server
为你的NETNAME
,即/etc/tinc/server
中server
部分。
Debian/Ubuntu
配置的过程基本相同,但是因为手上没有Debian/Ubuntu的机器,也懒得整VM,所以不能保证正确性。
根据Ubuntu的manpage,Debian/Ubuntu上的tinc所使用的config结构与Arch Linux不同:tincd
将直接读取/etc/tinc
中的内容,无需指定NETNAME
。即:
# mkdir -p /etc/tinc/hosts
# cd /etc/tinc
# cat tinc.conf
Name = server
Interface = tinc0
# cat tinc-up
#!/bin/sh
ip link set $INTERFACE up
ip addr add 192.168.4.1 dev $INTERFACE
ip route add 192.168.4.254 dev $INTERFACE proto kernel scope link src 192.168.4.1
iptables -A FORWARD -s 192.168.4.0/24 -j ACCEPT
iptables -A FORWARD -d 192.168.4.0/24 -j ACCEPT
iptables -A POSTROUTING -t nat -s 192.168.4.0/24 -j MASQUERADE -o eth0
# cat tinc-down
#!/bin/sh
ip link set $INTERFACE down
iptables -D FORWARD -s 192.168.4.0/24 -j ACCEPT
iptables -D FORWARD -d 192.168.4.0/24 -j ACCEPT
iptables -D POSTROUTING -t nat -s 192.168.4.0/24 -j MASQUERADE -o eth0
# cat hosts/server
Address = YOUR.IP.ADDRESS (你的公网地址)
Port = 655
Subnet = 0.0.0.0/0
# tincd -K4096 (注意此处不带-n参数)
Generating 4096 bits keys:
.................................................................................................................................................................................................++ p
..................................++ q
Done.
Please enter a file to save private RSA key to [/etc/tinc/rsa_key.priv]:
Please enter a file to save public RSA key to [/etc/tinc/hosts/server]:
服务器端的配置暂时告一段落。
客户端(路由器)配置
这里我仅以Tomato + Entware为例。使用其他平台的配置应该大同小异,请自行摸索。
路由器默认你已刷Tomato固件,并且配置Entware环境。具体操作不在此介绍,请自行Google。
文中Entware安装路径为默认的/opt
。
i. 安装tinc
使用Entware的opkg
工具安装tinc
以及git
:
# opkg install tinc
# opkg install git
完成安装后,git
可能需要进行额外配置,步骤不在此细述。
ii. 配置tinc
安装完成后,从GitHub上将脚本clone下来:
# git clone https://github.com/maddie/tinc-on-routers.git /opt/etc/tinc
执行配置脚本setup.sh
(随手写的,有bug请大喊)
# cd /opt/etc/tinc
# ./setup.sh
Enter your router name [client]: (输入这个节点的名称,默认client)
No input. Defaulting to 'client'.
Enter your server name [server]: (输入需要服务器的名称,请参考服务器端tinc.conf中Name参数的值)
No input. Defaulting to 'server'.
Enter your local address [192.168.4.2]: (这个节点的IP地址,必须在服务器配置的Subnet中,且唯一)
No input. Defaulting to '192.168.4.2'.
Enter remote subnet [192.168.4.0/24]: (远端配置的subnet,上面local address应在这个子网范围中)
No input. Defaulting to '192.168.4.0/24'.
Log file [/opt/var/log/tincd.log]: (Log文件路径,通常默认即可)
No input. Defaulting to '/opt/var/log/tincd.log'.
tinc config path [/opt/etc/tinc]: (客户端的tinc配置文件路径,通常默认即可)
No input. Defaulting to '/opt/etc/tinc'.
Your LAN Subnet [192.168.1.0/24]: (你的LAN所在Subnet,用于设置iptables规则)
No input. Defaulting to '192.168.1.0/24'.
Configuration summary: (这里会显示你输入的信息)
Local name: client
Remote name: server
Local address: 192.168.4.2
Log file: /opt/var/log/tincd.log
Config path: /opt/etc/tinc
LAN Subnet: 192.168.1.0/24
(确认无误后,按任意键继续。否则按Ctrl+C终止配置脚本。)
Press any key to continue, otherwise hit Ctrl+C to abort.
Applying configurations...
(生成密钥)
Generating private key for this client...
This may take a few minutes on a router.
Please wait patiently. :)
Generating 4096 bits keys:
.................................................................................................................................................................................................++ p
..................................++ q
Done.
Please enter a file to save private RSA key to [/opt/etc/tinc/rsa_key.priv]:
Please enter a file to save public RSA key to [/opt/etc/tinc/hosts/client]:
Done.
Please add these lines to your WAN Up script:
> sleep 15
> modprobe tun && tincd
客户端的配置暂告一段落。
交换公钥
完成两边的配置以后,需要把生成的公钥放到另外的节点上。如果你是一直按照本文的设置进行的话,那么:
服务器端公钥位于:
Arch Linux
/etc/tinc/server/hosts/server
Debian/Ubuntu
/etc/tinc/hosts/server
客户端公钥位于:
/opt/etc/tinc/hosts/client
tinc的公钥,当中实际上还包括对应节点的连接信息。例如,在/etc/tinc/server/hosts/server
中:
Address = YOUR.IP.ADDRESS
Port = 655
Subnet = 0.0.0.0/0
这代表tincd
将会在YOUR.IP.ADDRESS
的655
端口上监听,允许来自0.0.0.0/0
子网的用户。
在/etc/tinc/hosts/client
中:
Subnet = 192.168.4.2
则表示该节点被分配到的子网为192.168.4.2/32
。从这里其实可以看出,tinc支持将一个Subnet分配给一个节点,让该节点通过DHCP或者static routing的方式来对整个VPN进行访问。但是我们只是用于简单的routing作gateway,因此分配一个地址就足够了。
那么,交换公钥这个动作就如字面所说的一样了。将服务器端的/etc/tinc/server/hosts/server
放到客户端(路由器)的/opt/etc/tinc/hosts
下;再将客户端的/opt/etc/tinc/hosts/client
放到服务器端的/etc/tinc/server/hosts
下。
这样,两边通过读取tinc.conf
中的Name
来决定自己的身份,客户端通过其中的ConnectTo
参数来决定连接的节点,然后再通过hosts
中的公钥和各自的私钥来进行身份的验证,最后建立连接。
tinc服务自启动
其实都比较简单:
服务器端:
Arch Linux
# systemctl enable tincd@server
# systemctl start tincd@server
注意@
后面的server
是你的NETNAME
,即/etc/tinc/server
中server
部分。
Debian/Ubuntu
# update-rc.d -f tincd defaults
# service tincd restart
客户端(路由器):
Tomato的网页GUI中,找到Administration -> Scripts -> WAN Up,填入:
sleep 15
modprobe tun && tincd
大功告成!
PS: GitHub上我放的脚本其实跟autoddvpn的非常相似,基本上只是把OpenVPN换成了tinc而已。在GitHub的README中,我会简单说明里面各个文件的用途。另外,如果你需要配置多于一个客户端,你只需要把客户端的Subnet地址(即上文中的192.168.4.2)换一下,重新生成private key,和服务器端再交换一下公钥就可以了。
如果文中有哪里措辞不当或者有误,欢迎指正!谢谢!
Any comments or questions, please post here or email me: maddie at emzee dot be
You can also open issues on GitHub.
小插曲:
把这篇文章从Ghost移过来GitHub Pages以后,发现这个文章总是进不来,而且只要我点过这个文章的链接,整个网络都没办法再访问GitHub Pages了。后来把permalink改成URL里面那个,居然就可以了。。狗日的Games for Windows :)
Edit on 2019-10-16T14:52:34+08:00 ->
这个教程里面的内容很多都已经过时了,当然还是可以照着用,不过有更好的方案可以选择。tinc到目前为止作为VPN来说还是比较稳定的,目前在路由器上面的transparent proxy比较推荐的方案就是SS或者tinc了。