【问题标题】:Error parsing IP header解析 IP 标头时出错
【发布时间】:2010-02-22 07:03:41
【问题描述】:

我有一个尝试打印 IP 标头的片段偏移量的小函数。

ParseIpHeader(unsigned char *packet, int len)
{
    struct ethhdr *ethernet_header;
    struct iphdr *ip_header;

    /* First Check if the packet contains an IP header using
       the Ethernet header                                */

    ethernet_header = (struct ethhdr *)packet;

    if(ntohs(ethernet_header->h_proto) == ETH_P_IP)
    {
            /* The IP header is after the Ethernet header  */

            if(len >= (sizeof(struct ethhdr) + sizeof(struct iphdr)))
            {
                    ip_header = (struct iphdr*)(packet + sizeof(struct ethhdr));

                    /* print the Source and Destination IP address */

                    //printf("Dest IP address: %s\n", inet_ntoa(ip_header->daddr));
                    //printf("Source IP address: %s\n", inet_ntoa(ip_header->saddr));
                    printf("protocol %d\n", ip_header->protocol);
                    printf("Fragment off is %d\n", ntohs(ip_header->frag_off));

            }

}

我的数据包是 TCP(ip_header->protocol 总是 6。问题是 frag_off 一直是 16384。我发送了很多数据,为什么 frag_off 总是恒定的?

谢谢。

【问题讨论】:

  • 另外——也许你会澄清你计划用它的代码/用例实现的最终目标——也许我可以扩展答案。
  • 我正在使用 recvfrom 从网络中获取数据。 recvfrom 的最大缓冲区为 65K。所以在下一个数据包中收到了一些数据,我想合并它们

标签: c network-programming network-protocols


【解决方案1】:

片段偏移与标志共享。您设置了“DF”(不要分段)位。

如果片段偏移量为 0,则整个 16 位字段的值为 16384。

看看http://www.ietf.org/rfc/rfc791.txt,从第10页开始。

编辑

您正在接收的 TCP 段中的 DF 位由远程端设置,以执行Path MTU discovery - 简而言之,试图避免碎片。 在这种情况下,发送方了解整个路径可以处理的最大 MTU,并切分 TCP 段,使它们在封装成 IP 后不会超过它。

EDIT2

关于 recvfrom() 和 TCP 的使用:TCP 是一个面向连接的协议,所有的分段/分片细节都已经由它处理(分片显然是由低层 IP 处理的)——所以你做不需要处理它。您在发送端 write() 的任何内容最终都会在另一端被 read() - 可能 not 在相同的块中 - 即两次 4K 写入有时可能导致单个 8K 读取,有时在两次 4K 读取中 - 取决于中间媒体在重新排序/丢失方面的行为。

IP 分片和重组由操作系统透明处理,因此您无需担心,就像数据包乱序等一样(您只会看到性能下降对应用程序的影响) .

我可以推荐的一本好书是:UNIX network programming。鉴于 Steven 参与了 TCP,无论您使用哪种操作系统,这都是一本好书。

EDIT3:

如果您正在做某事以成为“中间人”(假设您有充分且正当的理由这样做:-) - 那么您可以通过查看现有技术来评估即将进行的工作:chaosreader (一种适用于 pcap 文件的脚本方法,但适用于其他东西),或 LibNIDS - 确实模拟 IP 碎片整理和 TCP 流重组;也许只是为了你的目的而重复使用它们。

【讨论】:

  • 感谢您的回复。但是我正在查询数据包中的数据。我没有设置 DF 标志。 if ((ntohs(ip_header->frag_off) & 0x3fff) == 0) 这意味着我正在读取第一个数据包。
  • 由于标志占据了三个最高有效位,所以上面的检查实际上检查了这个数据包根本没有分片(偏移量为零并且MF(更多分片)没有设置)。在任何情况下,这个 0x3fff 掩码都会删除远程端设置的 DF(大多数系统的默认设置,用于执行路径 MTU 发现)。
  • 谢谢安德鲁。那么我需要什么样的代码来查看这是否是第一个片段?
  • 如果您只需要知道片段偏移量,那么您可以使用 0x1fff 作为掩码来掩码 3 位标志。虽然知道你打算用这个做什么会很有趣 - 仅仅知道某事是第一个片段可能或可能不够。 IE。如果您假设 TCP 标头始终适合第一个片段 - 在另一端的恶意/错误实现的情况下,这将不是一个正确的假设。
  • 好的。假设我有一个发送文本行的回显服务器。我在嗅电线。第一个数据包包含文本“Hello ...”,片刻之后出现一个带有文本“... world”的新数据包。我怎么知道第一个数据包之后的第二个数据包是下一个数据包?我想连接它们以创建 buf="hello ... world"。
猜你喜欢
  • 2018-07-20
  • 2019-11-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-30
  • 2017-12-06
相关资源
最近更新 更多