一个部分替换tinc的方案。可以实现基于权重、延迟和链路质量的选路。

Tinc的问题

tinc可以很方便地构建一个局域网。它可以提供纯tcp模式(服务器中转)模式以很好地适应国内网络(避免QoS),以及任意两个节点之间只要有路径相连,便可经由连接的链路进行中转以实现相互通信。
如有3个客户端C1、C2、C3和两个服务器S1、S2的情况下,若S1和S2没有直接建立连接,C1和C2连接了S1,C2和C3连接了S2,那么当C1要连接C3的时候便可通过C1-S1-C2-S2-C3的路径进行通信。
然而,在实际使用中,节点并不能方便的确认和选择实际建立起通信的路径。
比如同一城市的两个节点A和B直接连接,但同时又连接有附近城市的节点C,以及远在2000km外的节点D。如果节点A和B之间的直接连接断了,那当A需要访问B的时候,如果没有设置权重的话,A-C-B的路径和A-D-B的路径是等价的。如果切换到了A-D-B路径,那么延迟和带宽都可能非常难看。
tinc可以在hosts中配置权重,但如果有更为复杂的中转关系,tinc的权重设置不能较好地应对实际情况。

Babel安装和配置

使用Babel可以实现动态组网,并能根据权重、延迟、链路质量来选择路径。此外,在路由器上部署的Babel可以向其他节点发部该节点直接连接的IP段,使得虚拟局域网可以很容易的进行多地的局域网进行组网。
大多数Linux发行版的软件源中都有Babel,如在Debian中,直接使用apt安装babeld即可(注意需要root权限):

apt-get install babeld

在配置Babeld之前,可以先创建好隧道和连接好有线网络。
实际上,Babeld配置文件中的interface上线与否,不影响Babeld的正常工作。也就是说既可以先配置Babeld,也可以先配置好隧道。但先配置好隧道并确认好隧道的正常工作,可以避免Babeld的配置文件有误导致实际网络工作与预期不符时无法确认是Babeld还是隧道软件的问题的情况。
Babeld的配置文件默认存放在/etc/babeld.conf,一个参考配置文件如下:

# For more information about this configuration file, refer to
# babeld(8)

# 启用随机节点ID,该项按需启用
random-id true 
# 如果没有启用随机ID,则需要手动给每个节点配置一个不一样的Router ID
# router-id 12:34:56:78:9a:bc:de:f0

# 本地数据端口,用于与BabelWeb通信
local-port 8474

# 设置默认interface的模式为tunnel,tunnel模式默认启用基于时间戳和延迟的权重计算方法
default type tunnel
# 设置默认启用一项针对点对点或有限连接的优化
default split-horizon true
# 设置默认启用对远距离连接的优化
default faraway true

# 以下每一行对应一个Interface
# Tunnels
interface tunnel1 rxcost 48 rtt-min 3 rtt-max 500 max-rtt-penalty 400 link-quality true
interface tunnel2 rtt-min 3 rtt-max 500 max-rtt-penalty 400 link-quality true
interface tunnel3 rxcost 384 rtt-min 3 rtt-max 500 max-rtt-penalty 400 link-quality true
# Wired
interface eth1 wired rxcost 4

# 过滤器设置
# Import rules
in ip fd00:1::/32 le 64 ge 32 allow
in ip fd00:1::/32 eq 128 allow
in ip 10.40.0.0/16 le 32 ge 16 allow
in deny
# Redistribute rules
redistribute ip 10.40.100.0/24 eq 24 metric 96

redistribute ip fd00:1::/32 le 64 ge 32 allow
redistribute ip fd00:1::/32 eq 128 allow
redistribute ip 10.40.0.0/16 ge 16 le 32 local allow # tunnel neighbors
redistribute local ip 10.40.0.0/16 eq 32 allow
redistribute local deny
# Export rules
out ip 10.40.0.0/16 allow
out ip fd00:1::/32 allow
out deny

上述配置文件中,过滤器部分描述中,局域网IPv4所使用的段为10.40.0.0/16,IPv6所使用的段为fd00:1::/32。
在interface部分,每一行代表一个需要启用babel协议与对端通信的interface。由于default type设置为了tunnel,延迟计算会默认启用,权重默认为96(对于无线连接,权重默认为256)。可以按实际需要调整rxcost,值越低则优先级越高。如例子中,tunnel1为一个对端在大局域网内的隧道,故将rxcost调为了48;tunnel2为对端在公网,带宽较大的隧道,rxcost为默认值;tunnel3为一个带宽很小的隧道,故rxcost调得很低,这样只有当另外两个隧道都断开,或访问的网端只有tunnel3的对端可及时,才会通过tunnel3进行传输。
再上述例子中,除了tunnel类型外,还有类型为wired的eth1,用于与其他节点进行有线的直接连接。此处对于物理连接,设置rxcost为4,相对于其他连接类型具有最高的优先级。
由于该路由器作为另一个局域网的默认网关,该局域网的地址范围为10.40.100.0/24,因此在过滤器部分,额外有一行redistribute ip 10.40.100.0/24,表示向其他节点额外发送一个10.40.100.0/24的可及域。这样,其他节点可以得知该节点可以访问10.40.100.0/24这一网段,从而将这一局域网也接入到了虚拟局域网中。这一配置也可用在部署了虚拟机的服务器中,用于将虚拟机的网段接入整个虚拟局域网中。
对于完整的配置文件说明,可以参考https://manpages.debian.org/testing/babeld/babeld.8.en.html

隧道

任何一个隧道软件均可用于组网。
如果ISP不限制UDP流量,则推荐使用WireGuard连接节点。否则可以使用如vtun之类的tcp隧道。
使用tinc也可以构建点对点连接。对于每个所需的连接建立一个网络即可。可以将tinc-up的网络配置部分和hosts中的Subnet的内网IPv4修改成分配的内网地址,并将CIDR设置为/32。babeld会通过IPv6的Local Link发现对方,并在路由表中为相应的interface添加IPv4的/32的路由,和节点相应的IPv6路由。
关于隧道的配置,在此不过多赘述。

使用dummy网卡避免隧道故障导致的IPv4无法连接

对于IPv4的连接,使用隧道时,会添加本端IPv4和对端IPv4,这会导致隧道本端访问对端IPv4时仅会选择从隧道通过,如果隧道故障则这两个节点之间的IPv4会无法正常通信。
如3台服务器A、B、C分别为10.40.0.1/32、10.40.0.2/32、10.40.0.3/32,两两之间建立了隧道。在A上,与B连接的隧道tunA_B会显示为10.40.0.1 peer 10.40.0.2,与C连接的隧道tunA_C会显示为10.40.0.1 peer 10.40.0.3,同时会有两条路由表10.40.0.2/32 dev tunA_B和10.40.0.3/32 dev tunA_C。若此时A和B之间的隧道故障了,如果没有将隧道ifdown,则访问B时,A仍然会选择tunA_B隧道访问B。而不是经由服务器C来访问B。
一个解决方法时建立网络时,使用dummy网卡添加另一个IP地址,实际使用时仅通过dummy网卡的地址进行访问。如上述例子中,建立隧道时使用10.40.0.0/24范围内的地址建立隧道,并额外增加一个10.40.1.0/24范围内的网卡地址,即A、B、C上分别增加10.40.1.1/32、10.40.1.2/32、10.40.1.3/32。应用建立连接时选择10.40.1.0/24进行访问,10.40.0.0/24范围内的地址仅用于建立隧道连接。
Debian中添加dummy网卡的例子如下(注意需要root权限):

# modprobe dummy
ip link add dummy0 type dummy
ip link set dummy0 up
ip addr add 10.40.0.1/32 dev dummy0
ip addr add 10.40.1.1/32 dev dummy0
ip -6 addr add fd00:1::1/128 dev dummy0

也可以直接将dummy网卡的配置写在/etc/network/interfaces中,如:

# Dummy0
iface dummy0 inet static
    address 10.40.0.1/32
    pre-up ip link add dummy0 type dummy
    post-up ip addr add 10.40.1.1/32 dev dummy0
    post-up ip -6 addr add fd00:1::1/128 dev dummy0

之后使用ifup dummy0添加该网卡。下次开机时,dummy0网卡会自动添加。
添加了dummy网卡后,babeld.conf中无需在interface行中添加相应的dummy网卡的interface名称,只要网卡地址范围在过滤器描述的范围内,该地址就会发送给其他节点。
IPv6本身可以经由fe80::/64的地址进行路由,故不存在以上问题。

其他说明

如果需要查看babeld的运行状况,可以使用BabelWeb(https://github.com/kerneis/babelweb)或者BabelWeb2(https://github.com/Vivena/babelweb2)。
也可以使用NetCat直接访问babeld的本地端口,发送dump命令输出数据:

echo "dump" | nc -i 1 -q 1 ::1 8474

如果使用WireGuard建立隧道,AllowedIPs除了需要包括虚拟局域网的IP段(如本例子中的10.40.0.0/16和fd00:1::/32),还需要放行fe80::/64用于IPv6路由和ff02::1:6/128用于babeld之间的通信。
如果节点的公网IPv6是通过ra获取到的,启用babeld服务后,默认网关会消失。注意需要先保存好信息,然后在启用babeld服务后手动添加默认路由表。

标签: Linux, Debian, SDLAN

添加新评论