简体   繁体   English

TCP校验和对于有效负载的数据包不正确

[英]TCP checksum incorrect for packets with payload

I'm working on an Ubuntu box in C. 我正在用C语言编写Ubuntu盒子。
The checksum calculation code is as follows: 校验和计算代码如下:

unsigned short csum(unsigned short *buf, int nwords)
{
  unsigned long sum;
  for(sum=0; nwords>0; nwords=nwords-2){
    sum += *buf;
    //printf("%04x\n", *buf);
    buf++;
  }
  if(nwords>0)
    sum += *buf++;
  while(sum >> 16)
    sum = (sum >> 16) + (sum &0xffff);
  /* sum += (sum >> 16);*/
  return (unsigned short)(~sum);
}

This has been working fine for IP and ICMP segments, though, so I highly doubt this is the problem. 但是,对于IP和ICMP细分市场来说,这一直很好用,所以我高度怀疑这是问题所在。
In an attempt to discern the problem, I am currently capturing random packets, constructing the pseudo header + deepcopy of the tcp header portion, then printing out the original checksum and calculated checksum. 为了试图找出问题,我目前正在捕获随机数据包,构造tcp标头部分的伪标头+深度拷贝,然后打印出原始校验和和计算出的校验和。

  struct tcphdr *tcph = (struct tcphdr *)(buffer + sizeof(struct ethhdr) + iphdrlen);
  int tcphdrlen = size - sizeof(struct ethhdr) - iphdrlen;
  int pseudo_len = sizeof(iph->saddr) + sizeof(iph->daddr) + 1 + sizeof(iph->protocol) + 2 + tcphdrlen;
  test = (u_char *) malloc(pseudo_len);
  memset(test, 0, pseudo_len);
  memcpy(test, &(iph->saddr), sizeof(iph->saddr));
  int pos = sizeof(iph->saddr);
  memcpy(test + pos, &(iph->daddr), sizeof(iph->daddr));
  pos += sizeof(iph->daddr);
  memset(test + pos, 0, 1);
  pos += 1;
  memcpy(test + pos, &(iph->protocol), sizeof(iph->protocol));
  int tcphdrlenhtons = htons(tcphdrlen);
  pos += sizeof(iph->protocol);
  memcpy(test + pos, &tcphdrlenhtons, 2);
  pos += 2;
  memcpy(test + pos, tcph, tcphdrlen);

  struct tcphdr *t_tcph = (struct tcphdr *)(test + pos);
  memset(&(t_tcph->check), 0, sizeof(t_tcph->check));

  printf("correct tcp checksum: %d\n", ntohs(tcph->check));
  printf("my tcp checksum: %d\n", ntohs((unsigned short) csum((unsigned short *)test, pseudo_len)));

In testing, I've found that the calculated checksum will be correct, but only if the packet had no payload. 在测试中,我发现计算得出的校验和是正确的,但前提是数据包没有有效载荷。
If anyone could give me an idea what I might be doing wrong, I'd appreciate it. 如果有人可以告诉我我可能做错了什么,我将不胜感激。

This isn't really an answer so much as a suggestion. 这实际上不是一个建议,而是一个答案。 Your test code is a bit difficult to follow. 您的测试代码很难遵循。 Variables like test don't make it easy for others to read and understand the code. test这样的变量不能使其他人容易阅读和理解代码。

Try making an actual struct for the pseudo-header and do regular assignment rather than memcpy for things like IPv4 addresses. 尝试为伪头制作一个实际的结构,并对诸如IPv4地址之类的内容进行常规分配,而不是memcpy分配。 They're only 4 bytes long and it will make your code much easier to read. 它们只有4个字节长,这将使您的代码更易于阅读。

This line: 这行:

memset(test + pos, 0, 1);

bothers me a bit since it isn't obvious what you're setting to 0. I also wonder if you're setting the right number of bytes to 0. 因为将您设置为0并不明显,这使我有些困扰。我还想知道您是否将正确的字节数设置为0。

I tried to figure out if you might have an endian issue, but that was difficult since I had trouble following your test code. 我试图弄清楚您是否可能遇到了字节序问题,但这很困难,因为我很难遵循您的测试代码。

As David Schwartz had pointed out, the program was capturing the packets before the checksum was being calculated, making the captured packets' checksums to be incorrect. 正如David Schwartz指出的那样,该程序在计算校验和之前就捕获了数据包,从而使捕获的数据包的校验和不正确。 The program was actually giving out correct checksums. 该程序实际上给出了正确的校验和。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM