![Socat:从标准输入发送 UDP 广播,但使用 SYSTEM 处理响应](https://linux22.com/image/181033/Socat%EF%BC%9A%E4%BB%8E%E6%A0%87%E5%87%86%E8%BE%93%E5%85%A5%E5%8F%91%E9%80%81%20UDP%20%E5%B9%BF%E6%92%AD%EF%BC%8C%E4%BD%86%E4%BD%BF%E7%94%A8%20SYSTEM%20%E5%A4%84%E7%90%86%E5%93%8D%E5%BA%94.png)
我正在尝试使用socat
.该发现是通过将 UDP 广播发送到具有小负载的明确定义的端口,然后侦听来自我的网络上的这些设备的“回复”来完成的。
如果我使用双向socat
并且“响应”转到标准输出,则这有效:
echo -ne "\x00\x01\x00\xF6" | socat -t5 - udp-datagram:255.255.255.255:30718,broadcast |xxd -p
来自我的本地网络上的一些设备的示例响应(每行都是来自不同设备的响应):
000000f70020300258366d112c15000062a71b21ff0000000080a3d2ded9
000000f70020300258366d112c15000062a71b21ff0000000080a3a40670
000000f70020300258366d112c15000062a71b21ff0000000080a3b94ca0
000000f70020300258366d112c15000062a71b21ff0000000080a3a4046b
有效负载是我所期望的,然而我缺少的是发件人元数据,特别是如果我使用ip-pktinfo,fork SYSTEM:
.所以我想要的是从标准输入发送初始广播,但用于SYSTEM
处理返回的结果数据包。
我尝试了单向模式的一些变体-u
,但我似乎没有在侦听器上接收到数据:
# Listener:
socat -u udp-recvfrom:30222,reuseaddr,ip-pktinfo,fork SYSTEM:./test.sh &
# Broadcast:
echo -ne "\x00\x01\x00\xF6" | socat -u - udp-datagram:255.255.255.255:30222,sourceport=30222,broadcast,reuseaddr
请注意,“这一端”的源端口可能是随机的,因此我明确选择30222
,以便我的广播源端口将与我的响应侦听器匹配。例如,如果广播来自端口 9987,客户端会将其单播响应发送回端口 9987。如果我以这种方式运行单向广播,我将偶尔得到回应;我有一种感觉,这取决于广播过程退出的速度。
(我打算接下来检查数据包捕获;我正在远程计算机上进行测试,我必须首先刷新我的记忆tcpdump
。)
参考:
答案1
OP 提到ip-pktinfo
这通常是一个 Linux 套接字选项(用于IP_PKTINFO
)。下面我将假设使用 Linux(但请参阅最后的 *BSD 注释)。实际上不需要此选项(另请参阅末尾的注释),但可以添加以获取更多信息。
关键部分是使用reuseport
切换的选项SO_REUSEPORT
套接字选项:
SO_REUSEPORT
(从 Linux 3.9 开始)允许将多个 AF_INET 或 AF_INET6 套接字绑定到相同的套接字地址。在调用套接字上的bind(2) 之前,必须在每个套接字(包括第一个套接字)上设置此选项。为了防止端口劫持,绑定到同一地址的所有进程必须具有相同的有效 UID。此选项可用于 TCP 和 UDP 套接字。
除了缺少这个选项之外,OP 已经获得了所需的一切。
主要是为了其他读者的利益,我将描述所做的事情并给出一个完整的示例。
如果一个索卡特由于限制,命令无法完成工作,使用两个索卡特对于这种情况,将全双工通信通道分成两个单工通道。
一个将用于读回答案,另一个用于发送广播。再次,解决方法索卡特限制,阅读索卡特必须UDP-RECVFROM
与fork
and一起使用-u
(用于只读,因此其结果将是标准输出,而不是被发送回响应者),而不是通常自然的选择UDP-RECV
:即允许为每个数据包分叉一个命令,并通过环境变量传输每个数据包的元数据。另外,正如OP所写,必须提前选择一个端口,以便它们都使用相同的端口。发送套接字也必须使用-u
以避免读回答案并将其窃取到其他专用套接字的风险索卡特命令。
以下是 LAN 中的示例,其中本地系统具有 192.0.2.2/24,对等系统具有 192.0.2.3/24。
对等系统(响应者)命名同行:
$ socat udp4-recvfrom:30718,fork system:hostname
本地系统的 term1 (也可以选择使用,ip-pktinfo
):
$ socat -u udp4-recvfrom:30222,reuseport,fork system:'cat; printenv|grep -E \"SOCAT_.*(ADDR|PORT)\"'
本地系统的术语2:
$ echo dummyprobe | socat -u - udp-datagram:255.255.255.255:30718,bind=:30222,reuseport,broadcast
第 1 学期收到的回复:
peer
SOCAT_PEERADDR=192.0.2.3
SOCAT_PEERPORT=30718
笔记
FreeBSD 有类似的描述
SO_REUSEPORT
(更确切地说,Linux 最近与 *BSD 保持一致):SO_REUSEPORT
如果多个进程在绑定端口之前都设置了 SO_REUSEPORT,则允许多个进程进行完全重复的绑定。此选项允许程序的多个实例分别接收发往绑定端口的 UDP/IP 多播或广播数据报。ip-pktinfo
不需要检索同行的地址。需要检索当地的地址,对于多宿主系统最有用,因此它知道其多个地址中的哪一个接收到数据报,或者还知道接收到的数据报是否是广播。即使没有此选项,对等方的地址信息也始终可用。 *BSD 只需要将此选项替换为ip-recvdstaddr,ip-recvif
(=>IP_RECVDSTADDR
+IP_RECVIF
) 即可接收相同的信息。