注:下面的说明可能存在问题,只是作为个人的备忘记录下来。一切配置详细信息请以官方文档为准。

前言

暑假实习稍微有点闲钱,为了提高网络生活质量就下狠心组了一个基于赛扬 J1900 的软路由。系统嘛为了方便各种配置且不会因为虚拟化可能产生的网络 I/O 开销直接用的 Debian Jessie。最开始时采用过去的老办法,OpenConnect 连到远端,内部采用路由表来决定直连还是走 OpenConnect。这样确实并无太大问题,但是总感觉这种多弄一次 NAT 的行为有些浪费。加之之前了解过 Tinc 这样一个小东西,现在经过一番测试,终于配置成功。故有了这篇备忘。

Tinc 模式选择

Tinc 的配置还是十分自由的。其中一个重要的点就是模式的选择。它共有三种模式支持:

  • 路由器模式(router)。该模式需要通过各个 host 配置文件中的 Subnet 来决定包要发到哪。
  • 交换机模式(switch)。该模式下 Tinc 的转发会和交换机类似,即:通过动态建立 ARP 表的方式决定包发到哪里。
  • 集线器模式(hub)。和上模式类似,只是该模式会把所有发到 Tinc 使用的 Interface 上的包在任何情况下向所有接入该 Tinc 网络的节点广播。

由于是在路由器上进行 Tinc 连接,一个最简单的想法便是我们只需要将所有来自内网的、需要转发到远端服务器上再连出的包通过 Tinc 的 Interface 发出,然后服务端接收到这些包再 NAT 转发出去即可。所以可以采用交换机模式,只利用系统路由来完成包转发路由的确定,从而跳过 Tinc 在路由器模式下内部需要的路由配置。

Tinc 配置目录格式

Tinc 的配置有着比较规范的目录格式。其配置目录格式如下:

/etc/tinc
		|
		+-NETNAME (该网络的网络名,用于启动 tincd 时做标识)
			|
			+-tinc.conf (该网络的基本配置信息,必须)
			|
			+-tinc-up (tincd 启动该网络时会调用的脚本,可选)
			|
			+-tinc-down (tincd 关闭该网络时会调用的脚本,可选)
			|
			+-rsa_key.priv (tincd 生成的本机非对称私钥)
			|
			+-hosts (该网络下要连接到的节点配置文件存放目录)
				|
				+- <host> (文件名为某节点的名称,内容为该节点相关配置及其公钥PEM)
				|
				+- <host>-up (该节点连接上时会调用的脚本,可选)
				|
				+- <host>-down (该节点断开连接时会调用的脚本,可选)
				|
				...

所以,根据以上格式,我们即可建立自己所需要的配置。以下将简单介绍具体步骤。再次强调,本文只是作为备忘,可能有提示的作用,但详细配置的说明请参照官方文档。

步骤简单说明

首先,简单说明要实现的网络结构。结构拓扑如下:

+--------+
| Client |----+
+--------+    |
              |
+--------+    |
| Client |----+
+--------+    | 100.64.0.0/24   +--------+                  +--------+
              +-----------------| Router |----(Internet)----| Server |----(Internet)
    ·         |                 +---+----+                  +----+---+
    · --------+                     | 10.0.0.2          10.0.0.1 |
    ·                               +----------------------------+

依旧假设我们使用的是 Debian Jessie。那么安装 Tinc 其实非常简单:

sudo apt-get install tinc

完成这一步后,我们就可以进行配置了。以下配置中,假定服务端在网络中的节点为server,路由器端在网络中的节点为home。当然,这些名称均可以随便改动,只要不重名就好。

###服务端

首先,由于我们服务端需要实现转发,所以不要忘了在/etc/sysctl.conf中设置net.ipv4.ip_forward = 1,并通过sysctl -p来应用配置。

我们根据需要,建立服务端的 tinc.conf

Name=server
Interface=ggw
Port=345
Mode=switch

上述内容中,Name指定的是自身是该网络的哪个节点,由于是服务器我们指定为serverInterface指定的是该网络激活后对应到该 VPN 连接的 Interface 名称,理论上可以任意指定,保险起见只要别和固有的名称(如ethx)和已有的名称重复即可。Port指定监听端口,如果不指定则默认为655Mode指定上面说过的模式,这里采用交换机模式。

当然,还有一些可以指定的较为重要的内容,那就是对称加密算法和摘要算法的选择,可以这样指定:

Cipher=<Cipher Name>
Digest=<Digest Name>

其中,Cipher可以指定任意一个 OpenSSL 所支持的加密法,比如 aes-128-cbcaes-256-cbc等,默认为blowfishDigest可以指定任意一个 OpenSSL 所支持的摘要算法,默认为sha1,个人推荐设置成SHA512以保证验证的安全性。

接下来我们指定激活该网络时会运行的脚本 tinc-up

#!/bin/sh
ip link set $INTERFACE up
ip addr add 10.0.0.1/24 dev $INTERFACE
iptables -I INPUT -p tcp --dport 345 -j ACCEPT
iptables -I INPUT -p udp --dport 345 -j ACCEPT

上述脚本实际上完成的工作为:将 VPN 所使用的 interface 激活;指定其 IP 为 10.0.0.1(按照上述拓扑图),子网掩码为24位1(即255.255.255.0,这样设置子网掩码就不需要为了保证服务器客户端连通再多设置一条路由规则了);设置防火墙开启需要用来监听和进行通信的345端口(上面配置中指定)。

对应地,我们指定该网络关断时会运行的脚本tinc-down

#!/bin/sh
ip link set $INTERFACE down
iptables -D INPUT -p tcp --dport 345 -j ACCEPT
iptables -D INPUT -p udp --dport 345 -j ACCEPT

然后,在hosts目录下,我们首先指定服务端节点的配置hosts/server

Address=<Your Server IP> 345

其中<Your Server IP>填入你的服务器端外网IP。该文件是用来标识节点一些特征信息的,在该文件后面追加自动生成的公钥后,可以直接复制到客户端用来做连接服务器必要的信息来源。

为了让路由和防火墙NAT规则在有需要的时候才规定,我们可以指定hosts/home-up

#!/bin/sh
ip route add 100.64.0.0/24 via 10.0.0.2 dev $INTERFACE
iptables -A POSTROUTING -t nat -s 100.64.0.0/24 -j MASQUERADE -o eth0
iptables -A POSTROUTING -t nat -s 10.0.0.0/24 -j MASQUERADE -o eth0

hosts/home-down

#!/bin/sh
ip route del 100.64.0.0/24 via 10.0.0.2 dev $INTERFACE
iptables -D POSTROUTING -t nat -s 100.64.0.0/24 -j MASQUERADE -o eth0
iptables -D POSTROUTING -t nat -s 10.0.0.0/24 -j MASQUERADE -o eth0

这样只有在路由器连接到服务器后,这些路由和NAT规则才会生效。当然,不要忘记将这些脚本加上执行权限(如chmod +x tinc-up),否则脚本将无法执行。后面的路由器端配置也要做相同处理!

最后,我们执行一下命令tincd -n NETNAME -K4096。其中,NETNAME是你指定的上述目录结构中的该网络配置的名称,当然你可以起任何名字,比如exciting,那么在这种情况下上述的tinc.conf文件对应的绝对路径便成为/etc/tinc/exciting/tinc.conf,其余路径以此类推,上面的命令也就变成了tincd -n exciting -K4096。在后面询问保存私钥和公钥的文件路径时直接回车使用默认路径。随后在/etc/tinc/nets.boot文件后追加该NETNAME,服务器配置暂时告一段落。

###路由器(客户端)

由于路由器本身应该配置好转发的,所以在此默认内核转发已开启。

跟上面类似,首先是tinc.conf

ConnectTo=server
Name=home
Interface=ggw
Mode=switch

当然,如果上面你指定了CipherDigest,不要忘了在这里也加上同样的配置。

由于路由器端为客户端,为了便于了解连接是否真的建立,我们在此不设置tinc-uptinc-down,而是在hosts目录下设置server-upserver-down,这样即可通过观察激活的 interface 中是否有你指定的 interface 来快速了解连接状况。

下面是hosts目录下配置。首先将上述配置完毕后的服务端上的hosts/server文件(后面有PEM格式的公钥)复制为路由器上的hosts/server。然后指定server-up

#!/bin/sh
ip link set $INTERFACE up
ip addr add 10.0.0.2/24 dev $INTERFACE
ip route add default via 10.0.0.1 dev $INTERFACE

以及server-down

#!/bin/sh
ip link set $INTERFACE down

至于hosts/home,由于并不需要配置什么,只需要放置客户端的公钥,所以直接touch hosts/home建立一个空的文件即可。

设置好脚本权限后,同样再次执行tincd -n NETNAME -K4096生成客户端的非对称密钥对,然后将hosts/home中的内容复制为服务器上的hosts/home。同样的将NETNAME加入/etc/hosts/nets.boot中,至此配置部分完成。

###运行 在服务器和路由器上分别执行:

sudo systemctl restart tinc

接下来如果一切正常的话,路由器的默认路由应该就是通过服务器转发了。至于测试,你可以随你喜欢的执行诸如traceroute 8.8.8.8查看路由追踪来查看转发是否成功来决定。

Tinc 作为一个轻型的 VPN,现在只能说貌似还没被盯上,但是实际使用时感觉可能是因为所谓「异常加密高流量」的特征所以可能会导致一定时间内的「惩罚」,具体情况还需使用几日才能确定。