最近碰到了一个ROS的疑难杂症,发现Mikrotik 路由器ROS系统中Wireguard服务的一些设计特点与普通的客户端软件(比如手机或电脑)存在区别。
症状:
Mikrotik ROS 7.12 版的系统,设为ROS1,作为客户端使用系统Wireguard接口与其他ROS连接,访问无障碍。与使用普通Wireguard软件的服务器(wgquick)、使用docker版本Wireguard软件(例如:wg-access)能成功建立连接,但建立连接后,只有隧道两端(ROS路由器——服务器)之间能连接,双向内网不能互访,ROS客户端所在内网中其他主机也不能透过对端访问0.0.0.0/0。
同样,另一台作为服务器使用的ROS2无此问题。该Mikrotik设备的Wireguard1
接口,同时作为客户端和服务器使用。作为客户端连接另一台服务器,同时作为服务器接受来自外部(如移动端)的连接。开放端口为8964,即Listen Port 为 ros2.server:8964
。ROS2设备防火墙开启了8964
端口。此时,ROS2设备及内网中其他主机能通过Wireguard1
接口与对端Mikrotik的Wireguard服务连接,并访问对端内网。
同时该设备ROS2上的另一个wg接口 Wireguard2
执行与某普通wg服务器(wg-remote)连接,ROS端Wireguard2接口定义ListenPort为 ros2.server:8965
。ROS2设备防火墙未开启8965端口。此时,ROS2及内网中其他主机能通过Wireguard2
与wg-remote服务器正常连接,并通过Wireguard服务器访问0.0.0.0/0。
参考网上的说法,有人说是因为对端TCP必须连接到本端的ListenPort,因此必须在本端开启ListenPort的防火墙。
但是ROS设备只有8964端口开放,8965端口未开放,使用ListenPort 8965的Wireguard2
也能实现正常上网。
Wireguard服务器端分析
打开wg-remote服务器,使用wg命令查询当前连接,可以看到 ros2.server:8965 已经与wg-remote 建立连接,并产生握手包和数据流。而ros1.server:8964 也已经建立连接,但只有很少数据,应该只有握手包。从wg-remote ping 对端 ros1.server 和 ros2.server 都能正确得到回应,但无法ping通ros1.server 所在的内网中的主机(路由已经配置)
打开ros2.server连接的另一台Mikrotik服务器的Peers,发现此时由于ros2.server作为客户端,服务器端并未配置其Endpoint信息(IP/端口均无)。
回到wg-remote服务器,使用一个手机连接wg-remote,可以看到wg-remote自动配置了对端的Peer端口(如54321),这是因为手机客户端生成并开放了一个随机端口,并告知服务器端。
此时怀疑,ros1与wg-remote连接时,申请了8964(即wireguard1接口的ListenPort)作为对端连接的端口,但防火墙并未开放,因此对端不能发回信息,开放8964/udp端口后,问题即解决,连接成功建立。
问题呈现
似乎看起来,Mikrotik ROS 作为Wireguard客户端时,必须手动开启自身Wireguard 接口定义的ListenPort
端口,以便与对端连接,而不是像手机或PC计算机一样,自动选择并开启自身的ListenPort。
但是问题来了:
1,端口开启后,连接已建立,都开始正常使用了,但是在防火墙里这个8964端口的流量永远是0。看不见ROS对该端口的流量统计。
2,对于上面的设备ROS2,有两个对外的Wireguard连接(Wireguard1 和 Wireguard2),且都是作为客户端主动连接对端,这两个接口的ListenPort分别为8964、8965。 但防火墙实际上只开启了8964,8965未开启,但Wireguard2 接口可以正常使用。
关闭8964端口后,两个Wireguard连接均不可用。
也就是实际上这个防火墙规则并不起作用,但必须设置一个防火墙规则。同时如果有多个wg连接,只要设定其中一个的ListenPort Accept,则所有的wg连接(不管Listen哪个端口)均可顺利接受对端的连接。
这似乎是ROS系统的一个bug而不是一个功能。
也就是ROS 7.12 当然也会在主动发起对外的wg连接后开启一个端口并通知对端,但如果你人为设置了ListenPort,它会通知对端你设定的这个端口。但是需要假装在防火墙上开启,而实际上数据却没有经过防火墙。哪怕有多个接口,开启其中一个,其他的也就顺利通过了。