【问题标题】:如果我已经填充了 iphdr 的所有字段,那么如何计算 tcphdr->doff 和 iphdr->ihl | tcp数据偏移量和ip头长度
【发布时间】:2022-01-23 16:41:02
【问题描述】:

在我的系统中 /usr/include/netinet/iphdr 这是结构 iphdr 的样子

struct iphdr
  {
#if __BYTE_ORDER == __LITTLE_ENDIAN
    unsigned int ihl:4;
    unsigned int version:4;
#elif __BYTE_ORDER == __BIG_ENDIAN
    unsigned int version:4;
    unsigned int ihl:4;
#else
# error "Please fix <bits/endian.h>"
#endif
    uint8_t tos;
    uint16_t tot_len;
    uint16_t id;
    uint16_t frag_off;
    uint8_t ttl;
    uint8_t protocol;
    uint16_t check;
    uint32_t saddr;
    uint32_t daddr;
    /*The options start here. */
  };

假设我已经制作了所有带有值的 ip 标头字段。现在我想计算 ip 标头长度,即我系统上的 iphdr->ihl 字段。我假设这是 ip header 长度,所以我制作的 ip header 的长度不能是sizeof(struct iphdr) 那可能是什么。

struct tcphdr 也是这个样子

struct tcphdr
  {
    __extension__ union
    {
      struct
      {
    uint16_t th_sport;  /* source port */
    uint16_t th_dport;  /* destination port */
    tcp_seq th_seq;     /* sequence number */
    tcp_seq th_ack;     /* acknowledgement number */
# if __BYTE_ORDER == __LITTLE_ENDIAN
    uint8_t th_x2:4;    /* (unused) */
    uint8_t th_off:4;   /* data offset */
# endif
# if __BYTE_ORDER == __BIG_ENDIAN
    uint8_t th_off:4;   /* data offset */
    uint8_t th_x2:4;    /* (unused) */
# endif
    uint8_t th_flags;
# define TH_FIN 0x01
# define TH_SYN 0x02
# define TH_RST 0x04
# define TH_PUSH    0x08
# define TH_ACK 0x10
# define TH_URG 0x20
    uint16_t th_win;    /* window */
    uint16_t th_sum;    /* checksum */
    uint16_t th_urp;    /* urgent pointer */
      };
      struct
      {
    uint16_t source;
    uint16_t dest;
    uint32_t seq;
    uint32_t ack_seq;
# if __BYTE_ORDER == __LITTLE_ENDIAN
    uint16_t res1:4;
    uint16_t doff:4;
    uint16_t fin:1;
    uint16_t syn:1;
    uint16_t rst:1;
    uint16_t psh:1;
    uint16_t ack:1;
    uint16_t urg:1;
    uint16_t res2:2;
# elif __BYTE_ORDER == __BIG_ENDIAN
    uint16_t doff:4;
    uint16_t res1:4;
    uint16_t res2:2;
    uint16_t urg:1;
    uint16_t ack:1;
    uint16_t psh:1;
    uint16_t rst:1;
    uint16_t syn:1;
    uint16_t fin:1;
# else
#  error "Adjust your <bits/endian.h> defines"
# endif
    uint16_t window;
    uint16_t check;
    uint16_t urg_ptr;
      };
    };
};

所以再次假设我已经用值填充了 tcphdr 的所有字段,现在我想要doff(数据偏移)。怎么计算的

  struct iphdr *iph=buffer;
   // populate the fields of iph
   //but what is iph->ihl? to calculate how?
   int iphdrlen = iph->ihl*4;
   struct tcphdr *tcph=(struct tcphdr *)(buffer + iphdrlen);
   //populate all the fields of tcph
   //but also how to calculate tcph->doff

应该像 iphdr->ihl

//after populating all the fields of iph then  just do following to get iph->ihl

  iph->ihl=sizeof(iph);

它应该像 tcph->doff

 //after populating all the fields of tcph just do following

  tcph->doff = (unsigned int)(sizeof(iph))+sizeof(tcph)));

这样就行了,行吗?

【问题讨论】:

    标签: c sockets tcp ip


    【解决方案1】:

    IP 标头有两个“部分” - 一个强制固定大小的部分,由 struct iphdr 表示,后者由 可选 可以存在的选项表示(参见注释 /*The options start here. */ )。标头长度是带有选项的整个标头长度。因此,除非您实际上添加了一些选项,否则它只是标题的长度,您可以在standard 中计算或读取它:

    国际人道法:4 位

    Internet Header Length 是 Internet 标头的长度,以 32 为单位 位字,因此指向数据的开头。注意 正确标题的最小值是 5

    现在,1 个字节是 4 位,32 位是 4 个字。因此它要么是sizeof(struct iphdr)/4,要么你可以将它设置为5

    TCP数据偏移量基本相同,只不过是针对TCP的。由于 TCP 标头也可以包含选项,因此适用相同的逻辑。根据standard(滚动到下一页):

    数据偏移量:4 位

    TCP Header 中 32 位字的数量。这表明在哪里 数据开始。 TCP 标头(甚至包括选项)是一个 32 位长的整数。

    所以,基本上它的计算方式相同。它不是指针,它是一个表示头部长度的数字。根据wikipedia如果你的header没有选项,这个字段的值也是5

    【讨论】:

    • 关于 tcp if your header has no options, the value of this field is also 5. 如果我有选择,那会是什么?在那种情况下数据偏移? tcphdr 和 iphdr 中的哪个字段也是选项。你能在我的问题中举例说明 iphdr 和 tcphdr 的结构吗?
    • doff 将是标题的总长度,将所有选项和填充,(当然是 32 位字的数量)。链接的维基百科页面有一个 TCP 选项列表。选项出现在公共标头(您所指的结构)之后,也就是说,第一个选项(如果存在)将从公共标头之后的下一个位/字节开始。例如,可以在this rfc 中找到 tcp 时间戳选项的格式。我会假设某个地方的每个选项都有单独的结构,尽管可变大小的选项可以以不同的方式解析。
    • 不知道有没有相关的IP选项,实际使用的。
    猜你喜欢
    • 1970-01-01
    • 2017-08-08
    • 2020-03-31
    • 2022-01-24
    • 2013-03-19
    • 2021-10-26
    • 1970-01-01
    • 2017-11-02
    • 2011-05-12
    相关资源
    最近更新 更多