我在Mac 10.6.8中使用套接字进行编程。每当我收到一个数据包时,它都会从IP头开始。我一直在使用Wireshark来分析传入的数据包,我注意到我的机器的套接字实现将持续改变"总长度" IP标头中的字段。具体来说,它将减去IP头长度并反转字节(从网络到主机顺序)。
例如,这是Wireshark报告的IP头的开头:
45 c0 00 38 ...
分解如下:
但是,当我为同一个数据包打印由recvfrom
填充的缓冲区的内容时,我会得到一个不同的文字:
ssize_t recvbytes = recvfrom(sock->fd, buffer, size, /*flags=*/0,
(struct sockaddr*)src, &src_len);
返回
45 c0 24 00 ...
我发现在我访问缓冲区之前,套接字实现正在读取总长度,减去IP头长度,然后按主机顺序(我的机器上的小端)而不是网络顺序写回(大端)。在这个例子中,这意味着:
问题变得更糟。它不会只是改变最外层IP头的总长度。它还将改变内部IP报头的总长度字段,例如,埋在ICMP中的那个字段"时间超过" message(必须包含丢弃数据包的原始IP头)。有趣的是,它不会从内部标题中减去IP标题长度;它只是反转字节顺序。
这是否发生在其他人身上?它是我不知道的标准的一部分吗?有没有办法修复我的机器的套接字实现以停止篡改数据包? Wireshark如何解决这个问题?
提前感谢您的考虑。
编辑:我的代码和Makefile可用on 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(从trunk构建)还是GCC 4.7(MacPorts端口)编译都存在问题,因此我认为问题在于套接字实现(与Mac OS一起打包)或Mac OS X本身。 / p>
答案 0 :(得分:2)
BSD平台套件(不包括OpenBSD)以主机字节顺序显示IP偏移量和长度。所有其他平台以接收的网络字节顺序出现。这是一个“功能”,在IP(4) - Internet Protocol(FreeBSD,OS X)的手册页中引用。
必须以主机字节顺序提供ip_len和ip_off字段。 必须以网络字节顺序提供所有其他字段。
在FreeBSD / NetBSD中,IP长度可以等于packet length - IP header length
。
参考: Stevens / Fenner / Rudolph,Unix网络编程第1卷,第739页
我必须使用PGM网络协议的用户空间实现处理这些异常,具体代码:
https://code.google.com/p/openpgm/source/browse/trunk/openpgm/pgm/packet_parse.c#76
检测AutoConf实际上非常烦人,我认为所有软件包都是基于每个平台进行硬编码的。我已经看到本周在这个问题上提出的错误报告(header byte order config options detected incorrectly)。
答案 1 :(得分:0)
Mac本身不太可能这样做。如果是这样的话,那将从根本上打破IP协议。更有可能的是捕获数据包并将它们传递给recvfrom()
(可能是你正在进行混杂的网络捕获,对吗?)是在Mac完成处理之后转换数据的原因。 ireshark在较低级别运行,可以访问实际的网络数据。