Featured image of post wireguard 组建非对称路由

wireguard 组建非对称路由

通过第三台机器或者是端口流量转发,实现基于虚拟局域网的非对称路由,用以优化部分服务器的网络连接,降低延迟。

方案二(本地与远程服务器+中转节点实现非对称路由)个人感觉是一个更好的配置方案,并且其中的wireguard配置方式也在方案一中使用,步骤更简洁明确一些。所以推荐没有耐心看完的同学直接看方案二

奇怪的环境产生奇怪的需求——现在有一台机器去程只有移动能够直连,电信和联通都会绕日走ntt(tnt),一到了晚上就会产生剧烈的抖动以及严重丢包,那么是是否有办法去优化一下呢?使用一台移动网络的机器作为中转是一个方法,但是这样的话,所有的流量都会经过这台中转的机器,这台机器的速度成为了这个网络中的瓶颈,而且流量也会加倍消耗。既然我们只是去程绕路,那么是否有办法只优化去程的路由而保留原有的回程路由呢?在实际的互联网中“非对称路由”非常常见,即A到B和B到A走了不同的路径,而我们要想实现这个效果则需要先建立一个虚拟的网络,然后再在这个网络中配置路由,我这里使用了wireguard作为建立虚拟内网的工具。

三台机器上的非对称路由

环境准备

在这个实验中使用了三台机器:

  1. 本地机器A wireguard网内ip为 192.168.51.5 169.254.1.5
  2. 去程不错但是带宽较小的机器B 192.168.51.1 169.254.1.1
  3. 去程绕路但是回程不绕且带宽较大的机器C 192.168.51.2 169.254.1.2

需要实现的效果是 A 访问 C 路径为 A->B->C->A

在安装好wireguard后需要生成密钥且开启包转发:

1
2
3
4
5
6
7
apt install wireguard wireguard-tools
wg genkey  | tee privatekey | wg pubkey > publickey

echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
echo "net.ipv6.conf.default.forwarding=1" >> /etc/sysctl.conf
echo "net.ipv6.conf.all.forwarding=1" >> /etc/sysctl.conf
sysctl -p

两两之间建立连接

下面直接贴一下三台机器的wireguard配置,注意一点 需要设置 Table=off,即禁止 wireguard直接修改路由表, 且这里使用的是链路本地地址建立的连接。 另外,三台机器彼此之间要两两连接(对应单独的一个配置文件),也就是说需要自己写6个配置文件

节点A与节点B配置文件:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
[Interface]
PrivateKey = 
ListenPort = 27000
PostUp = ip addr add 169.254.1.5/32 peer 169.254.1.1/32 dev %i
PostDown = ip addr del 169.254.1.5/32 peer 169.254.1.1/32 dev %i
Table = off
# B
[Peer]
PublicKey =
AllowedIPs = 0.0.0.0/0
Endpoint = 
PersistentKeepalive = 10

节点A与节点C配置文件:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
[Interface]
PrivateKey = 
ListenPort = 27001
PostUp = ip addr add 169.254.1.5/32 peer 169.254.1.2/32 dev %i
PostDown = ip addr del 169.254.1.5/32 peer 169.254.1.2/32 dev %i
Table = off
# C
[Peer]
PublicKey = 
AllowedIPs = 0.0.0.0/0
Endpoint = 
PersistentKeepalive = 10

节点B与节点A配置文件:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
[Interface]
PrivateKey = 
ListenPort = 27000
PostUp = ip addr add 169.254.1.1/32 peer 169.254.1.5/32 dev %i
PostDown = ip addr del 169.254.1.1/32 peer 169.254.1.5/32 dev %i
Table = off
#A
[Peer]
PublicKey = 
AllowedIPs = 0.0.0.0/0

节点B与节点C配置文件:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
[Interface]
PrivateKey = 
ListenPort = 26002
PostUp = ip addr add 169.254.1.1/32 peer 169.254.1.2/32 dev %i
PostDown = ip addr del 169.254.1.1/32 peer 169.254.1.2/32 dev %i
Table = off
# C
[Peer]
PublicKey =
AllowedIPs = 0.0.0.0/0
Endpoint = 

节点C与节点A配置文件:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
[Interface]
PrivateKey = 
ListenPort = 27001
PostUp = ip addr add 169.254.1.2/32 peer 169.254.1.5/32 dev %i
PostDown = ip addr del 169.254.1.2/32 peer 169.254.1.5/32 dev %i
Table = off
#A
[Peer]
PublicKey = 
AllowedIPs = 0.0.0.0/0

节点C与节点B配置文件:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
[Interface]
PrivateKey =
ListenPort = 26002
PostUp = ip addr add 169.254.1.2/32 peer 169.254.1.1/32 dev %i
PostDown = ip addr del 169.254.1.2/32 peer 169.254.1.1/32 dev %i
Table = off
# thk
[Peer]
PublicKey = 
AllowedIPs = 0.0.0.0/0
Endpoint = 

ip分配与静态路由

在建立了两两之间的连接之后,我们还需要在每台机器上创建一个 dummy 网卡(也可以写到postup里面),用来获取到发给自己的包。

以机器A为例,BC上也要进行同样的操作(记得改ip)

1
2
3
4
# ip link del dummy
ip link add dummy type dummy
ip addr add 192.168.50.5/32 dev dummy
ip link set dummy up

此时 192.168.50.5(A) 到 192.168.50.2(C) 是还没有路由的,不过我们希望去程经过节点B,那么我们在A上设置静态路由:

1
2
ip route add 192.168.51.2/32 dev [AB之间连接对应的wireguard接口名]
# 或者 ip route add 192.168.51.2/32 via 169.254.1.1

然后还需要在节点B上设置到C的静态路由:

1
2
ip route add 192.168.51.2/32 dev [BC之间连接对应的wireguard接口]
# 或者 ip route add 192.168.51.2/32 via 169.254.1.2

此时,在A上pingC,在B上抓包,我们便能得到如下结果:

PING C

在B上只能看见单向的数据流,而A是可以得到回应的,再在C上抓包看看:

C上分别查看两个接口 B-C 与 C-A 的接口

B-C

C-A

可以发现一点,实际上B作为路由进行转发时,源ip是什么是无所谓的,只需要有目的ip即可,而目的ip的路由方式通过静态路由指定了,那么在C上则会收到来自于A的链路本地地址(169.254.1.5)的包,而C与A直接连接,且wireguard创建了到169.254.1.5的连接,所以C的响应是可以不经过B直接走到A的。这样就实现了一个非对称的路由。 现在的设置下,A 主动 访问C时会经过B,C还没办法主动的连接A,因为还没有设置C到A的静态路由,我们可以重复一遍前面的步骤,在C上与B上指定到A的静态路由,也可以直接让C访问A而不经过A。不过由于该需求中我只需要A能够主动访问到C即可,所以不再进行这些设置。

为什么使用了链路本地地址

为什么在配置文件中使用了169开头的地址,而不是直接用192开头的地址建立连接并参与后续的路由设置呢?因为(至少是在我这种配置方式下),ip addr add xxx peer xxx 建立点对点连接时,会自动添加一条路由规则,会和我们后续添加的手动路由冲突。所以我只能退一步,使用另一个地址来建立点对点连接,然后用新的地址来设置静态路由。 wireguard工作在网络层,大概不支持不设置ip直接通过mac来连接?

只用两台机器实现非对称路由

上一节实现了三台机器组建的网络的非对称路由,那么能否更进一步,借助现有的“流量转发”服务,实现两台机器建立非对称路由呢?这样我们便不再需要第三台服务器转发去程,且优质线路在流量转发服务中也常见一些,且由于只有去程走了转发,实际上是花不了多少钱的。

个人测试下来,这个方案也很容易实现。以本地机器A与远程机器C为例,每台机器上都要设置两个wireguard接口,分别对应通过端口转发建立的wireguard以及直接连接建立的wireguard。

命名如下:

  1. a1 本地对应的通过流量转发建立的wireguard连接的接口 169.254.2.1 192.168.51.3
  2. a2 本地对应的通过直接连接建立的wireguard连接的接口 169.254.2.2 192.168.51.3
  3. c1 远程对应的通过流量转发建立的wireguard连接接口 169.254.2.3 192.168.51.2
  4. c2 远程对应的通过直接连接建立的wireguard连接接口 169.254.2.4 192.168.51.2

配置文件如下,注意这里没有用 ip addr add peer 的命令,而完全采用静态路由来实现,也不再需要dummy设备,而是直接使用了后面需要用的ip。对,没写错,其实并没有规定一个ip只能分配给一个接口,只需要我们后面静态路由别写错就好,上一节采用三台服务器的方案也可以这样的配置形式,而不是用dummy接口。

a1配置

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
[Interface]
PrivateKey = 
Address = 192.168.51.3/32
PostUp = ip route add 192.168.51.2/32 dev %i
#PostDown = 
Table = off
#hkg
[Peer]
PublicKey = 
AllowedIPs = 0.0.0.0/0
Endpoint = [填写端口转发服务的地址]:14967
PersistentKeepalive = 10

a2配置 a1和a2只有endpoint ip、端口不一样

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
[Interface]
PrivateKey = 
Address = 192.168.51.3/32
#PostUp = 
#PostDown = 
Table = off
#hkg
[Peer]
PublicKey = 
AllowedIPs = 0.0.0.0/0
Endpoint = [C的地址]:14967
PersistentKeepalive = 10

c1、c2配置,注意 c1和c2只有端口不一样

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
[Interface]
PrivateKey = 
ListenPort = 27002
Address = 192.168.51.2/32
PostUp = ip route add 192.168.51.3/32 dev %i # c2配置文件进行该设置,指定直连
#PostDown = 
Table = off
# local
[Peer]
PublicKey = 
AllowedIPs = 0.0.0.0/0

然后配置静态路由

本地机器上,去程通过a1(经过流量转发) ip route add 192.168.51.2/32 dev a1

远程机器上,回程直连 ip route add 192.168.51.2/32 dev c2

之后我们尝试在本地 ping 192.168.51.2 看看效果

ping 192.168.51.2

延迟降低到了30ms,而之前去程绕日ntt延迟有70ms,并且抖动剧烈,可以看出效果还是很明显的。

总结

目前的方案感觉依旧不是最优解,用链路本地地址建立连接再添加dummy设备多少有些繁琐,计算机网络上还有很多我没搞清楚的,且这个网络节点较少,在较多(>3)路由节点的情况下,是否能直接这样简单的配置还是一个问题。不过关于这方面的资料实在是太少了,而当前的配置方法虽然比较麻烦,但是也不是不能用,还望大家多多指教,有更好的连接方式请留下评论给我一点提示。

上面那段总结是针对方案1的,而针对方案2的配置方式,我觉得可以很好的实现这个需求,并且效果还挺不错,并且只需要在本地与远程两台服务器上进行配置即可。

comments powered by Disqus
本站访客数:
使用 Hugo 构建
主题 StackJimmy 设计