解决校园网中单播互通的不同子网间的 LocalSend 发现问题

解决校园网中单播互通的不同子网间的 LocalSend 发现问题
问题背景#咱实验室有一台连接着打印机的计算机我们在这台机器上挂了一个专门注册的 QQ 账号需要打印文件时把文件发送到这个 QQ 账号上在打印机计算机上下载下来就行了。但是吧像是比较机密文件的话如果这样过一道别人的服务器感觉不太好正好咱当时也找到了局域网文件传输工具 LocalSend遂试了试。结果我发现打印机计算机上的 LocalSend 客户端无法发现我笔记本上的 LocalSend 端反之亦然。我还得到打印机计算机上手动输入笔记本电脑被分配的 IP 地址才能传输文件略显麻烦。更不提校园网这有线网和无线网给设备分配的全是动态 IP可能过一段时间就会变。分析了一下发现没有办法互相发现是因为我的笔记本接入的是校园网无线网络而打印机计算机接入的是有线网络两个主机在不同的子网段内这阻隔了 LocalSend 发出的组播包 (可以参考 LocalSend 协议)。可以手动输入 IP 地址来指定客户端传输文件是因为 LocalSend 实际的传输等请求是单播的而校园网在三层设备上有配置路由转发所以单播包是可以互通的。于是咱要解决的问题就是如何在这种多播 (组播) 隔离但是单播互通的不同局域子网间实现 LocalSend 的发现功能。1. 问题描述#Figure 1: 问题示意图。 可以看到 VLAN 0 中的 LocalSend 客户端无法成功发现 VLAN 2 中的 LocalSend 客户端反之亦然。LocalSend 客户端采用 UDP 组播来把自己的存在通告给局域网中其他客户端。然而像校园网这种大型局域网通常为了管理和减小广播域规模等目的会将网络划分为多个 VLAN虚拟局域网对应多个子网即使是现实中距离很近的两个设备也有可能在不同的 VLAN 中。比如我连接到校园网 WiFi 的笔记本电脑和连接有线校园网的实验室打印机电脑虽然在同一间屋子但就是处于不同网段的网络中。不同子网之间的数据转发依赖于第三层路由设备来实现不幸的是LocalSend 向224.0.0.x组播地址及应用端口发送的 UDP 报文段是不会被三层设备转发的而且其 TTL 值为1Wireshark 抓包如下Figure 2: Wireshark 抓包显示 LocalSend 发送的组播 UDP 报文段的 TTL 值为 1。因此就有了明明两台设备近在咫尺但是却没法互相发现对方 LocalSend 客户端的尴尬局面 ㄟ( ▔, ▔ )ㄏ。2. 解决问题#2.0. 思路#尽管多播被隔离了但是办公区校园网在三层配置上是会转发单播包的我可以通过单播和不同的 VLAN 中的主机进行通信。一个 LocalSend 客户端在尝试发现局域网内其他客户端时会发送组播 UDP 包来声明自己的存在其他客户端收到组播包后会通过单播的 HTTP 请求来在这个客户端上进行注册。因为单播可以跨 VLAN所以这个注册操作是可以实现的我可以替 LocalSend 客户端向局域网内的其他 LocalSend 客户端发送注册请求从而实现跨 VLAN 的发现和注册。从官方的协议文档可以看到 LocalSend 的通告包和注册请求的负载中都只有端口信息没有源 IP 信息客户端在处理到来的请求时实际上是从网络层分组头部获取到源 IP 地址的因此这个请求必须从 LocalSend 客户端所处的主机上发出。为了实现这点我可以在每台有 LocalSend 的主机上都额外运行一个工具进程来代发注册请求。关键的问题来了这些工具进程怎么知道局域网内其他 LocalSend 客户端的存在呢其实我可以借助单播传输来实现这些工具进程之间的通信从而让它们互相交换各自了解的 LocalSend 客户端信息。为了解决动态 IP 的问题我可以把其中一个或多个工具进程作为交换节点部署在拥有静态 IP 的服务器上内网和外网的均可然后让其他工具进程连接到这些交换节点当交换过程收敛时这些工具进程就能互相了解对方所处主机上的 LocalSend 客户端信息了也让 LocalSend 客户端互相知晓了对方的存在。正好最近学了 Go 语言照着上面这个思路实现下来LocalSend Switch 这个工具就诞生辣٩(௰)و简单来说 LocalSend Switch 充当的角色就有点类似于 BT 下载中的 Tracker 服务器了但同时也会帮忙发送单播的注册请求用于辅助组播隔离、单播允许的局域网子网之间的 LocalSend 客户端互相发现。2.1. 工作原理#Figure 3: LocalSend Switch 的工作原理示意图。实线表示的是单播分组的传播路径虚线表示的是 TCP 逻辑连接虚线上的箭头对应数据在逻辑上的传播方向。LocalSend 客户端和 Switch 进程的旁边标记了连接端口只有 VLAN 1 中的 Switch 进程监听了服务端口7761其余两个 Switch 进程的均为 OS 分配的临时端口LocalSend 客户端默认服务端口是53317。Fig.3 为 LocalSend Switch 的工作原理示意图展示了单次的客户端信息传播以及注册请求代发的过程。图中首先10.84.0.0/15网段中10.84.123.223这台主机上的 LocalSend 客户端发送了组播包通告自己的存在被同一台机器上的 LocalSend Switch 捕获到Switch 进程随后将该通告信息通过单播发送 (图中标记为CLIENT ANNOUNCE传播路径为蓝色) 给它所连接的所有 Switch 节点 (图中只有192.168.232.47:7761这一个)。发送的数据中封装了 LocalSend客户端的 IP 和端口无论被转发多少次这部分数据都不会变指向最初发出这条通告信息的 LocalSend 客户端。47主机上 Switch 节点接收到通告的客户端信息后会将该信息转发至它所连接的其他Switch 节点图中只有10.94.23.114:52341图中标记为FORWARD ANNOUNCE传播路径为紫色。因为这台主机上没有 LocalSend 客户端所以不会有注册请求的代发操作。114主机上的 Switch 节点接收到通告信息后会将该信息发送给它所连接的其他所有 Switch 节点图中没有其他节点了因为这台主机上有 LocalSend 客户端所以 Switch 节点随后会向通告信息中携带的 LocalSend 客户端地址 (图中为10.84.123.223:53317) 发送 HTTP(S) 注册请求图中标记为REGISTER CLIENT传播路径为棕色告知对方本地客户端的 IP 和地址 (图中为10.94.23.114:53317)完成注册请求的代发操作。注意这个注册请求是直接由 Switch 发送给 LocalSend 客户端的。实际上每个 Switch 节点都有这样的转发功能甚至可以在逻辑上串联或者组成树形、星型、网状、混合等拓扑结构。3. 更进一步#解决了 LocalSend 互相发现的问题后我又考虑并解决了以下几个问题传输安全性问题。交换信息的环路问题。自启动问题。注这节的 Switch 均指 LocalSend Switch 工具。3.0. 传输安全性问题#Switch 节点间的数据传输在 TCP 连接上进行默认情况下是明文的其中主要是 Lo