Tinc 是一个 MeshVPN 网络的实现。
以下是这玩意的踩坑记录。
传统星型结构和网状结构
在传统结构里,客户端接入的目的主要是获得与服务端相同的网络环境,
通常是为了访问服务器所在网络的资源。
故服务器上会一般配置 NAT 转发(或者直接分配内网地址),从而使客户端可以访问内网。
在网状结构里,节点之间是等价全连接的,
大家既是客户端也是服务端,具体的用途取决于额外的设置。
任意节点上可以与传统 VPN 一样配置 NAT 转发,允许其他节点透过自身访问网络资源。
虽然同样是虚拟网络,星型结构下,
客户端与客户端之间无法直接连接,缺少了服务端就是一盘散沙。
而网状结构下,
只要新节点能连上网络中已接入的任意节点即能连接成功,网络本身的运行不依赖单一节点。
Tinc 工作模式
Tinc 有三种模式,路由器、交换机及集线器。
其中集线器模式因为很蠢并不推荐使用(其实咱也没看过相关的帖子)。
同字面意思一样,路由器模式就是节点像路由器一样同其他节点连接,交换机模式同理。
假想环境
Tinc 网络名称:ELFNET
Tinc 内网:10.0.0.1/24
节点名称 - 系统 / 公网 IP 状况 / 内网 IP 静态分配
ElfA - Linux / 公网 IP A.B.C.A / Tinc 内网 IP 10.0.0.1
ElfB - Linux / IP A.B.C.B / Tinc 内网 IP 10.0.0.2
ElfC - Windows / 无公网 IP / Tinc 内网 IP 10.0.0.3
Tinc 配置目录结构
一般安装好的 tinc 配置在 /etc/tinc 里(Windows 下就是安装目录)。
如果没有这个目录就需要自己建立一个。
这一目录内的结构:
ELFNET (该网络的网络名,用于启动 tincd 时做标识)
|
+-tinc.conf (该网络的基本配置信息,必须)
|
+-tinc-up (tincd 启动该网络时会调用的脚本,可选)
|
+-tinc-down (tincd 关闭该网络时会调用的脚本,可选)
|
+-rsa_key.priv (tincd 生成的本机 RSA 私钥)
|
+-hosts (该网络下要连接到的节点配置文件存放目录)
|
+- <host> (文件名为某节点的名称,内容为该节点相关配置及其 RSA 公钥)
|
+- <host>-up (该节点连接上时会调用的脚本,可选)
|
+- <host>-down (该节点断开连接时会调用的脚本,可选)
路由器模式配置
配置的主要目的是让处于不同地区的机器连接在一块,允许互相访问开放端口。
配置后目录结构(每台设备都这样):
ELFNET
|
+-tinc.conf
|
+-tinc-up(Windows 上为 tinc-up.bat)
|
+-tinc-down(Windows 上为 tinc-down.bat)
|
+-rsa_key.priv
|
+-hosts
|
+- ElfA
|
+- ElfB
|
+- ElfC
ElfA 配置:
tinc.conf
Name = ElfA
Interface = tinc
tinc-up
#!/bin/sh
ip link set $INTERFACE up
ip address add 10.0.0.1/32 dev $INTERFACE
ip route add 10.0.0.0/24 via 10.0.0.1
tinc-down
#!/bin/sh
ip route del 10.0.0.0/24 via 10.0.0.1
ip address del 10.0.0.1/32 dev $INTERFACE
ip link set $INTERFACE down
ElfB 配置:
tinc.conf
Name = ElfB
Interface = tinc
tinc-up
#!/bin/sh
ip link set $INTERFACE up
ip address add 10.0.0.2/32 dev $INTERFACE
ip route add 10.0.0.0/24 via 10.0.0.2
tinc-down
#!/bin/sh
ip route del 10.0.0.0/24 via 10.0.0.2
ip address del 10.0.0.2/32 dev $INTERFACE
ip link set $INTERFACE down
ElfC 配置(这是 Windows 系统):
tinc.conf
Name = ElfB
Interface = tinc
tinc-up
netsh interface ip set address tinc static 10.0.0.3 255.255.255.255
netsh interface ipv4 add route prefix=10.0.0.0/24 interface="tinc" metric=2
netsh interface ipv4 add route prefix=10.0.0.255/32 interface="tinc" nexthop=10.0.0.3 metric=256
tinc-down
netsh interface ipv4 delete route prefix=10.0.0.0/24 interface="tinc"
netsh interface ipv4 delete route prefix=10.0.0.255/32 interface="tinc" nexthop=10.0.0.3
写好配置文件后,需要产生密钥对(Windows 需要在程序安装目录下执行):
tincd -n ELFNET -K 4096
这一步操作完成后 hosts 目录下会产生与 tinc.conf 配置中 name 相同的文件,
将这个文件放到另外两台设备的 hosts 目录下,然后稍作修改。
修改公匙文件:
ElfA
Address = A.B.C.A
Subnet = 10.0.0.1/32
-----BEGIN RSA PUBLIC KEY-----
此处省略
-----END RSA PUBLIC KEY-----
ElfA
Address = A.B.C.B
Subnet = 10.0.0.2/32
-----BEGIN RSA PUBLIC KEY-----
此处省略
-----END RSA PUBLIC KEY-----
ElfC
Subnet = 10.0.0.3/32
-----BEGIN RSA PUBLIC KEY-----
此处省略
-----END RSA PUBLIC KEY-----
为脚本赋予执行权限(Windows 不需要):
chmod +x tinc-up
chmod +x tinc-down
启动 tinc:
Linux:
systemctl start tinc@ELFNET
Windows(在安装目录下以管理员权限执行):
tincd.exe -n ELFNET
或者直接运行 bat 脚本:
@echo off
:: Check administrator privilege
fltmc>nul&&(goto MainProc)||(goto GetPrivilege)
:: Get administrator privilege
:GetPrivilege
if exist "%temp%\getadmin.vbs" del /f /q "%temp%\getadmin.vbs"
echo Set RequestUAC = CreateObject^("Shell.Application"^)>"%temp%\getadmin.vbs"
echo RequestUAC.ShellExecute "%~s0","","","runas",1 >>"%temp%\getadmin.vbs"
echo WScript.Quit >>"%temp%\getadmin.vbs"
"%temp%\getadmin.vbs" /f
if exist "%temp%\getadmin.vbs" del /f /q "%temp%\getadmin.vbs"
exit
:MainProc
pushd "%CD%"
CD /D "%~dp0"
tincd.exe -n ELFNET
pause
测试连通性:
在 ElfB 上 ping ElfA、ElfC:
ping 10.0.0.1
ping 10.0.0.3
此时可能无法 ping 通 Windows 设备,需要切换防火墙区域:
执行以下 PowerShell 脚本:
Set-NetConnectionProfile -InterfaceAlias "tinc" -NetworkCategory Private
执行开机自启动:
Linux:
systemctl enable tinc
systemctl enable tinc@ELFNET
Windows:
在服务里找到 tinc.ELFNET
,属性设置为自动
交换机模式配置
配置的主要目的是让 ElfB 透过 ElfA 访问互联网。
交换机模式下忽略 ElfC 的存在(懒)。
ElfA 配置后目录结构:
ELFNET
|
+-tinc.conf
|
+-tinc-up
|
+-tinc-down
|
+-rsa_key.priv
|
+-hosts
|
+- ElfA
|
+- ElfB
|
+- ElfB-up
|
+- ElfB-down
ElfB 配置后目录结构:
ELFNET
|
+-tinc.conf
|
+-rsa_key.priv
|
+-hosts
|
+- ElfA
|
+- ElfB
|
+- ElfA-up
|
+- ElfA-down
ElfA 配置:
tinc.conf
Name = ElfA
Interface = tinc
Mode=switch
tinc-up
#!/bin/sh
ip link set $INTERFACE up
ip addr add 10.0.0.1/24 dev $INTERFACE
tinc-down
#!/bin/sh
ip link set $INTERFACE down
ElfB-up
#!/bin/sh
#!/bin/sh
iptables -A POSTROUTING -t nat -s 10.0.0.0/24 -j MASQUERADE -o eth0
ElfB-down
#!/bin/sh
iptables -D POSTROUTING -t nat -s 10.0.0.0/24 -j MASQUERADE -o eth0
ElfB 配置:
tinc.conf
Name = ElfB
Interface = tinc
Mode=switch
ConnectTo=ElfA
ElfA-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
ElfA-down
#!/bin/sh
ip link set $INTERFACE down
ElfA 上开启内核转发:
net.ipv4.ip_forward = 1
sysctl -p
产生密钥对及修改公匙文件:
与路由器模式同理,但修改公匙文件时不需要加入 Subnet
字段。
赋予脚本执行权限:
chmod +x tinc-up
chmod +x tinc-down
chmod +x ElfA-up
chmod +x ElfA-down
chmod +x ElfB-up
chmod +x ElfB-down
执行测试(在 ElfB 上):
ping -I tinc 8.8.8.8
某些情况下添加的默认路由优先级不够,会导致流量未透过 tinc 接口转发。
可以临时加一条路由再测试:
ip route add 8.8.8.8/32 via 10.0.0.1 dev tinc
参考:
官方文档:https://www.tinc-vpn.org/docs/
DN42 配置参考:https://dn42.net/howto/tinc
多种配置方式:https://github.com/qmcclab/blog/blob/master/2013-09-20-a-mesh-network.md
交换模式:https://blog.zjustin.me/post/tinc-memo/
交换模式 + DHCP:https://blog.swineson.me/use-routeros-qemu-as-tinc-tap-vpn-dhcp-server/
后记:
其实这玩意相当硬核的,网状结构下可以玩的东西太多了,
只有大学选修划水学的『计算机网络』知识是不完全够的。
另外 WireGuard 配置比这玩意还简单(关键是还有内核直接支持),
怕不是再过一段时间又要换坑。