使用 socat 进行 SOCKET-SENDTO

使用 socat 进行 SOCKET-SENDTO

我尝试使用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 数组。数组的每个元素,就像其他结构成员一样,都需要反转,但它们的长度只有一个字节;但进入数组的数据不需要反转。

相关内容