TCP 校验和与wireshark 校验和不匹配(正好相差1)

Posted

技术标签:

【中文标题】TCP 校验和与wireshark 校验和不匹配(正好相差1)【英文标题】:TCP Checksum does not match the wireshark checksum (off by exactly 1) 【发布时间】:2021-03-20 12:52:36 【问题描述】:

我有以下过程来计算tcp校验和

static inline uint32_t
csum_part(const void *buf, size_t len, uint32_t sum)

   uintptr_t p = (uintptr_t)buf;

   while (len > 1)
   
      sum += *(uint16_t *)p;
      len -= 2;
      p += 2;

        

   if (len)
     sum += *(uint8_t *)p;


return sum;

以及下面的函数来打包它

uint16_t calc(uint32_t x)

  while((x >> 16) != 0) 
  x = (x & 0xffff) + (x>>16);

  return ~x;

当我计算标头的校验和时,我使用以下代码

uint32_t calc_tcp_checksum(char * pkt, int hdrlen, int pktlen) 

  struct ip *  ih = (struct ip *)
    (pkt+ hdrlen - sizeof(struct tcphdr) - sizeof(struct ip));


  struct tcphdr *  th = (struct tcphdr *)
    (pkt + hdrlen - sizeof(struct tcphdr));


#ifndef __FAVOR_BSD
  th->check = 0;
#else
  th->th_sum = 0;
#endif
  //th->

  uint32_t header_chksum = csum_part(th, sizeof(struct tcphdr), 0);

  uint32_t pseudo = (uint32_t)ih->ip_src.s_addr + ih->ip_dst.s_addr +
    htons(IPPROTO_TCP) + htons(pktlen); 


  header_chksum += pseudo;

  return header_chksum;


我有一个如下的数据包

0000   58 f3 9c 81 2b bc 00 1c 73 13 1f 94 08 00 45 00
0010   00 dc 00 00 40 00 40 06 40 19 0a e6 35 90 ac 13
0020   0d 7a b9 be 2a 44 63 36 c2 98 c7 82 d0 1e 50 18
0030   10 00 eb 15 00 00 00 b4 00 00 09 cd 1c fb 66 40
0040   ec c7 0d 30 cb 0b e4 cb 88 74 13 3d 4e 20 00 00
0050   9a d6 00 00 00 00 9f db 4f 50 54 49 44 58 42 41
0060   4e 4b 4e 49 46 54 59 20 4d 03 8a e8 00 2d ed d0
0070   43 45 46 4e 45 30 30 30 37 20 20 20 00 01 00 02
0080   00 00 00 00 00 00 00 4b 00 00 a7 7b 00 00 00 00
0090   02 00 00 02 00 00 9a d6 39 30 30 35 39 4f 49 43
00a0   49 43 49 30 30 30 30 35 32 30 00 01 02 00 b0 6d
00b0   c8 04 42 f6 bd f9 52 7c 42 80 41 41 45 43 45 32
00c0   34 31 33 51 00 00 a1 e4 00 00 00 00 00 00 00 00
00d0   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00e0   00 00 00 00 00 00 00 00 00 00 72 dd 89 69

在上面的例子中, pktlen = 180 hdrlen = 54

我得到校验和是 0xeb15,wireshark 说它是 0xea15。我究竟做错了什么?请注意,它总是不正确,只是有时。

【问题讨论】:

【参考方案1】:

RFC 1071 的第 4.1 节 - 计算 Internet 校验和提供了“C”中的实现示例,这似乎是您实现实现的基础的方法。除了 RFC 1071 示例将 folding 部分组合在计算校验和的同一函数中,而您的实现没有。 RFC 1071 显然假设伪标头已经包含在addr 指向的缓冲区中,但同样,您的没有。这一切都可以,只是你从来没有通过调用calc() 函数来真正折叠最终结果,至少我看不到。

因此,对于您的实现,似乎任何计算的 TCP 校验和没有在 32 位累加器的高 16 位设置任何位都是正确的,但任何计算的校验和至少有 1在累加器的高 16 位中设置的位将导致 TCP 计算不正确。我相信这可以解释为什么您的代码计算的某些校验和是正确的而有些是错误的。

如果您有兴趣,可以查看 Wireshark 在 in_cksum.c 中的 Internet 校验和实现以及如何从 TCP dissector 中调用它。

【讨论】:

以上是关于TCP 校验和与wireshark 校验和不匹配(正好相差1)的主要内容,如果未能解决你的问题,请参考以下文章

TCP 校验和能否检测到错误?如果是,如何处理?

WireShark开启IP, TCP,UDP校验和的办法

是否有永久修复 SVN 校验和不匹配的解决方案?

尝试运行 svnadmin verify 会导致校验和不匹配

svn:校验和不匹配

校验和不匹配错误 paytm 支付集成