简体   繁体   English

TCP校验和C代码返回错误结果

[英]TCP checksum C code returns wrong result

I am getting a large checksum result for TCP, when it is supposed to be 0. I am approaching this by copying the TCP psuedoheader into the first 12 bytes of an array, then copy the TCP header and data into the next several bytes of the array, and pass that array and its length to the checksum function. 当将TCP的pssumedheader复制到数组的前12个字节中,然后将TCP标头和数据复制到数组的后几个字节中时,我收到了一个较大的TCP校验和结果,方法是将TCP psuedoheader复制到数组的前12个字节中。数组,然后将该数组及其长度传递给校验和函数。 I cannot figure out why the checksum is significantly different from the correct value (ie 9180 for one of the packets packet when it should be 0). 我无法弄清楚为什么校验和与正确值有显着差异(例如,其中一个数据包应为0时为9180)。

Here are my IP, TCP and pseudo TCP headers: 这是我的IP,TCP和伪TCP标头:

typedef struct __attribute__((__packed__)) IPHeader {
  #if __BYTE_ORDER__ == __LITTLE_ENDIAN__
  uint8_t hdrLen:4;
  uint8_t version:4;
  #else
  uint8_t version:4;
  uint8_t hdrLen:4;
  #endif
  uint8_t TOS;
  uint16_t totLen;
  uint16_t id;
  uint16_t offset;
  #define DF 0x4            
  #define MF 0x2           
  #define OFF 0 
  uint8_t TTL;
  uint8_t protocol;
  uint16_t checksum;
  struct in_addr srcIP;
  struct in_addr destIP; 
}IPHeader;

typedef struct __attribute__((__packed__)) TCPHeader {
  uint16_t srcPort;
  uint16_t destPort;
  uint32_t seqNum;
  uint32_t ackNum;
  uint8_t offset:4;
  uint8_t res:4;
  uint8_t flags;
  uint16_t window;
  uint16_t checksum;
  uint16_t urg;
}TCPHeader;

typedef struct __attribute__((__packed__)) TCPPseudo {
  struct in_addr srcAddr;
  struct in_addr destAddr;
  uint8_t zeroes;
  uint8_t protocol;
  uint16_t len;
}TCPPseudo;

Here is how I am copying the data into the array: 这是我将数据复制到数组中的方式:

IPHeader *iph
TCPPseudo ts;
TCPHeader *tcp;
u_char checkData[1000];
uint16_t checkLen = 0;
---
tcp = (TCPHeader *)(packet + ETHER_SIZE + iph->hdrLen * 4);
ts.srcAddr = iph->srcIP;
ts.destAddr = iph->destIP;
ts.zeroes = 0;
ts.protocol = iph->protocol;
checkLen = ntohs(iph->totLen) - (iph->hdrLen * 4);
ts.len = checkLen;
memcpy(checkData, &ts, 12);
memcpy(checkData + 12, tcp, checkLen);
getTCPInfo(tcp, iph, checkData, checkLen);
---
unsigned short checksum = in_cksum((unsigned short *)checkData, len + 12);
printf("\t\tChecksum: %d, (0x%x)", checksum, htons(tcp->checksum)); 

Here is how I am calculating the checksum: 这是我计算校验和的方法:

unsigned short in_cksum(unsigned short *addr,int len)
{
    register int sum = 0;
    u_short answer = 0;
    register u_short *w = addr;
    register int nleft = len;

    /*
     * Our algorithm is simple, using a 32 bit accumulator (sum), we add
     * sequential 16 bit words to it, and at the end, fold back all the
     * carry bits from the top 16 bits into the lower 16 bits.
     */
    while (nleft > 1)  {
            sum += *w++;
            nleft -= 2;
    }

    /* mop up an odd byte, if necessary */
    if (nleft == 1) {
            *(u_char *)(&answer) = *(u_char *)w ;
            sum += answer;
    }

    /* add back carry outs from top 16 bits to low 16 bits */
    sum = (sum >> 16) + (sum & 0xffff);     /* add hi 16 to low 16 */
    sum += (sum >> 16);                     /* add carry */
    answer = ~sum;                          /* truncate to 16 bits */
    return(answer);
}

You should save the TCP checksum of the received packet, then set the checksum field to zero in the tcp header before calculating the checksum over the pseudo header and TCP segment. 您应该保存接收到的数据包的TCP校验和,然后在计算伪报头和TCP段的校验和之前,在tcp报头中将校验和字段设置为零。 Then match the calculated checksum with the previous saved value. 然后将计算出的校验和与先前保存的值匹配。 Both should be equal if there are no errors in transmission over the network. 如果网络传输中没有错误,则两者应该相等。 Do this 做这个

recvPktChkSum = tcp->checksum
tcp->checksum = 0;

also before calculating the checksum you should make sure that length is in network bytes order 同样在计算校验和之前,您应确保长度以网络字节顺序

ts.len = htons(checkLen);

before 之前

memcpy(checkData + 12, tcp, checkLen);

then after 然后

checksum = in_cksum((unsigned short *)checkData, len + 12);

compare 相比

if(htons(recvPktChkSum) == htons(checksum))
   printf("checksum valid"); 

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

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