4

我正在使用 Mac 10.6.8 中的套接字进行编程。每当我收到一个数据包时,它都会从 IP 标头开始。我一直在使用 Wireshark 来分析传入的数据包,我注意到我机器的套接字实现会不断地更改 IP 标头中的“总长度”字段。具体来说,它将减去 IP 标头长度并反转字节(从网络到主机顺序)。

例如,这是 Wireshark 报告的 IP 标头的开头:

45 c0 00 38 ...

分解如下:

  • 4 位 (0x4):IP 版本:4
  • 4 位 (0x5):IP 标头长度:5 个字(20 字节)
  • 8 位 (0xc0):区分服务标志
  • 16位(0x0038):总长度:56字节

但是,当我打印为同一个数据包填充的缓冲区内容时recvfrom,我得到了不同的 lede:

ssize_t recvbytes = recvfrom(sock->fd, buffer, size, /*flags=*/0,
  (struct sockaddr*)src, &src_len);

返回

45 c0 24 00 ...
  • 4 位 (0x4):IP 版本:4
  • 4 位 (0x5):IP 标头长度:5 个字(20 字节)
  • 8 位 (0xc0):区分服务标志
  • 16 位(0x2400):总长度:9216 字节(?!)

我发现在访问缓冲区之前,套接字实现是读取总长度,减去 IP 标头长度,然后按主机顺序(我机器上的小端序)而不是网络顺序(大端序)写回. 在此示例中,这意味着:

  • 读取总长度:0x0038 = 56
  • 减去标题长度:56 - 20 = 36
  • 按主机顺序写回:36 = 0x0024(大端)= 0x2400(小端=我机器上的主机顺序)

问题变得更糟。它不仅会改变最外层 IP 标头的总长度。它还将更改内部 IP 报头的总长度字段,例如,埋在 ICMP“超时”消息中的字段(它必须包括丢弃数据包的原始 IP 报头)。更有趣的是,它不会从内部标头中减去 IP 标头长度;它只是颠倒了字节顺序。

这是否发生在其他人身上?它是我不知道的标准的一部分吗?有没有办法修复我机器的套接字实现以停止篡改数据包?Wireshark 如何解决这个问题?

提前感谢您的考虑。

编辑:我的代码和 Makefile在 GitHub 上可用。我编写了一个fixip_osx函数来验证 IP 校验和:

https://github.com/thejohnfreeman/netutils/blob/master/lib/ip.c

void fixip_osx(struct ip* ip) {
  /* Something on my Mac subtracts the header length from `ip_len` and stores
   * it in host order (little endian). */
  u16_t ip_hdrlen = ip->ip_hl << 2;
  u16_t ip_totlen = ip->ip_len + ip_hdrlen;
  ip->ip_len = htons(ip_totlen);
}

但是,当有效负载包含另一个 IP 标头时,验证 ICMP 校验和仍然是一个问题。

无论我使用 Clang 3.2(从主干构建)还是 GCC 4.7(MacPorts 端口)编译都存在问题,所以我认为问题在于套接字实现(与 Mac OS 一起打包)或 Mac OS X 本身。

4

2 回答 2

3

BSD 平台套件(不包括 OpenBSD)以主机字节顺序显示 IP 偏移量和长度。接收到的网络字节顺序中存在的所有其他平台。这是一个“功能”,在IP(4) - Internet Protocol (FreeBSD, OS X ) 的手册页中有引用。

ip_len 和 ip_off 字段必须按主机字节顺序提供。所有其他字段必须按网络字节顺序提供。

packet length - IP header length在 FreeBSD/NetBSD 中IP 长度可以相等。

参考:Stevens/Fenner/Rudolph,Unix Network Programming Vol.1,p.739

我必须通过 PGM 网络协议的用户空间实现来处理这些异常,具体代码:

https://code.google.com/p/openpgm/source/browse/trunk/openpgm/pgm/packet_parse.c#76

检测 AutoConf 实际上很烦人,我认为所有软件包都在每个平台上进行了硬编码。我看到了本周针对这个问题提出的错误报告(错误地检测到标头字节顺序配置选项)。

于 2013-04-08T14:31:26.303 回答
0

Mac 本身不太可能这样做。如果是这样,那将从根本上破坏 IP 协议。更有可能的是捕获数据包并将它们传送到recvfrom()(大概您正在执行混杂的网络捕获,对吗?)是在 Mac 完成处理数据之后转换数据的原因。ireshark 在较低级别上运行,可以访问实际的网络数据。

于 2012-12-11T23:31:23.427 回答