我尝试使用socat
将原始数据包发送到以太网接口,但收到“无此设备或地址”的提示。我应该如何使用socat
?
用法:
$ echo hi | sudo socat - SOCKET-SENDTO:17:3:0:x0003x00000002x0000x00x06xabcdef0123450000
分解:
domain - 17 (PF_PACKET)
type - 3 (SOCK_RAW)
protocol - 0
address - (data representation of a sockaddr structure)
sockaddr_ll
family - (without family)
protocol - x0003 (ETH_P_ALL (unsigned short))
ifindex - x00000002 (from /sys/class/net/eth0/ifindex (int))
hatype - x0000 (0 on send (unsigned short))
pkttype - x00 (0 on send (unsigned char))
halen - x06 (ETH_ALEN (unsigned char))
addr - xabcdef0123450000 (a MAC address on the same segment as ifindex, (unsigned char[8]))
结果:
$ echo hi | sudo socat - SOCKET-SENDTO:17:3:0:x0003x00000002x0000x00x06xabcdef0123450000
2020/05/29 16:05:29 socat[339113] E sendto(5, 0x555fd8ffac70, 3, 0, AF=17 AF=17 0x00030000000200000006abcdef01, 20): No such device or address
答案1
更具体地说,问题出在我的 STDIN 上(嗨)。我错误地认为 STDIN 只是数据包有效负载;然而,它实际上期望的是整个数据包。此外,我发现 sockaddr->protocol 和 sockaddr->ifindex(可能还有 sockaddr->hatype,但都是零,可能还有 sockaddr->pkttype 和 sockaddr->halen,但它们都是单个字节)的字节顺序是反转的。我找不到任何文档来支持这一点,但我的经验证实这是可行的。
因此,socat
我尝试创建的命令实际上只是 sendto() 的一个接口。因此,缓冲区参数(整个以太网数据包)在本例中由 STDIN 填充。其余命令行参数是 sendto() 的其余参数。
最终有效的原始套接字 SOCKET-SENDTO 命令如下:
$ echo -n -e "\xab\xcd\xef\x01\x23\x45\x01\x23\x45\xab\xcd\xef\x00\x02\x68\x69" | sudo socat - SOCKET-SENDTO:17:3:0:x0300x02000000x0000x00x06xabcdef0123450000
用法:
echo
-e (enable interpretation of backslash escapes, each byte needs a \x)
-n (do not output the trailing newline)
"\xab\xcd\xef\x01\x23\x45 (dst_mac)
\x01\x23\x45\xab\xcd\xef (src_mac)
\x00\x02 (length of payload)
\x68\x69 (payload ("hi" in this case))
"
domain - 17 (PF_PACKET, from `procan -c`)
type - 3 (SOCK_RAW, from `procan -c`)
protocol - 0
address - (data representation of a sockaddr structure, only the beginning needs an 'x', the rest are optional)
sockaddr_ll
family - (without family)
protocol - x0300 (ETH_P_ALL (unsigned short), from if_ether.h)
ifindex - x02000000 (interface to use for sending, from /sys/class/net/eth0/ifindex (int))
hatype - x0000 (0 on send (unsigned short))
pkttype - x00 (0 on send (unsigned char))
halen - x06 (ETH_ALEN (unsigned char), from if_ether.h)
addr - xabcdef0123450000 (dest MAC address on the same segment as ifindex, (unsigned char[8]))
编辑:感谢@meuh 提供的额外见解:
以太网数据包按定义是大端或网络顺序。因此,sockaddr 结构的数据类型是大端的,但正如 @meuh 指出的那样,我的机器 (x86) 是小端的。因此,结构的每个成员的字节都需要反转。让我措手不及的是,char 类型的 addr 成员不需要反转。这是因为 addr 是一个 char 数组。数组的每个元素,就像其他结构成员一样,都需要反转,但它们的长度只有一个字节;但进入数组的数据不需要反转。