使用tinc替代OpenVPN作为路由器自动翻墙方案

多年前发现了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

  1. 首先你得有一个不在GFW里的服务器。我用的是Linode东京的VPS,系统使用Arch Linux。最便宜的套餐$10一个月,一次性购买一年/两年有打折~ 购买链接
  2. 你需要在路由上安装tinc。这意味着你需要现在路由上部署Optware/Entware。本文使用Entware为例。
  3. The ability to RTFM and follow instructions.

服务器端配置

i. Enable IPv4 Forwarding in sysctl.conf

首先,你必须把服务器的IPv4转发打开。在大多数Linux发行版中,这个选项默认是关闭的。

在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协议,配置上会有出入,而且据闻性能没有原来的版本好。

在Debian/Ubuntu中则是

iii. 配置tinc

Arch Linux:

tinc在安装后不会自动在/etc目录下建立文件夹,我们要手动建立:

这里面的server是你的NETNAME,这个名字将用于后面启用服务时使用。
hosts文件夹用于存放每个host的信息,后面会讲到。

写入配置文件:

(a) tinc.conf的内容

当中Name的值server为本机(服务器端)的名称。记住你的名称,在后面还会用到。

(b) tinc-up的内容

我使用的网段是192.168.4.0/24,你可以根据自己的需要对这个进行更改。记得把其他地方的subnet也改掉哦!最后的iptables规则中,第三条的eth0是你的VPS面向公网的网卡。

(c) tinc-down的内容

同样,根据需要修改subnet,必须与tinc-up中的保持一致。

(d) hosts/server的内容

在这里,server这个文件名必须对应前面在tinc.conf中设置的Name参数的值。tinc会根据Name去匹配hosts目录下的配置文件。

需要填写的配置文件只有这四个。完成以后,生成private key:

这样会生成一个4096 bit的私钥,生成的密钥保存在默认路径即可。-n参数后面的server为你的NETNAME,即/etc/tinc/serverserver部分。

Debian/Ubuntu

配置的过程基本相同,但是因为手上没有Debian/Ubuntu的机器,也懒得整VM,所以不能保证正确性。

根据Ubuntu的manpage,Debian/Ubuntu上的tinc所使用的config结构与Arch Linux不同:tincd将直接读取/etc/tinc中的内容,无需指定NETNAME。即:

服务器端的配置暂时告一段落。

客户端(路由器)配置

这里我仅以Tomato + Entware为例。使用其他平台的配置应该大同小异,请自行摸索。

路由器默认你已刷Tomato固件,并且配置Entware环境。具体操作不在此介绍,请自行Google。

文中Entware安装路径为默认的/opt

i. 安装tinc

使用Entware的opkg工具安装tinc以及git

完成安装后,git可能需要进行额外配置,步骤不在此细述。

ii. 配置tinc

安装完成后,从GitHub上将脚本clone下来:

执行配置脚本setup.sh(随手写的,有bug请大喊)

客户端的配置暂告一段落。

交换公钥

完成两边的配置以后,需要把生成的公钥放到另外的节点上。如果你是一直按照本文的设置进行的话,那么:

服务器端公钥位于:

Arch Linux

Debian/Ubuntu

客户端公钥位于:

tinc的公钥,当中实际上还包括对应节点的连接信息。例如,在/etc/tinc/server/hosts/server中:

这代表tincd将会在YOUR.IP.ADDRESS655端口上监听,允许来自0.0.0.0/0子网的用户。

/etc/tinc/hosts/client中:

则表示该节点被分配到的子网为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

注意@后面的server是你的NETNAME,即/etc/tinc/serverserver部分。

Debian/Ubuntu

客户端(路由器):

Tomato的网页GUI中,找到Administration -> Scripts -> WAN Up,填入:

大功告成!

PS: GitHub上我放的脚本其实跟autoddvpn的非常相似,基本上只是把OpenVPN换成了tinc而已。在GitHub的README中,我会简单说明里面各个文件的用途。另外,如果你需要配置多于一个客户端,你只需要把客户端的Subnet地址(即上文中的192.168.4.2)换一下,重新生成private key,和服务器端再交换一下公钥就可以了。

from 

Replacing OpenVPN with tinc on Tomato/OpenWRT/dd-wrt for bypassing GFW // 使用tinc替代OpenVPN作为路由器自动翻墙方案 | this is my place.