2014-01-15 173 views
2

当TCP应该为0时,我得到一个较大的校验和结果。我正在通过将TCP psuedoheader复制到数组的前12个字节来解决此问题,然后复制TCP头和数据放入数组的下几个字节中,并将该数组及其长度传递给校验和函数。我无法弄清楚为什么校验和与正确的值有很大的不同(即当数据包中的一个数据包应该为0时,为9180)。TCP校验和C代码返回错误结果

这里是我的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; 

这里是我如何将数据复制到阵列中:

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)); 

这里是我正在计算校验:

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); 
} 

回答

0

您应该保存接收到的数据包的TCP校验和,然后将校验和字段设置为零他在计算伪报头和TCP段的校验和之前先tcp报头。然后将计算的校验和与先前保存的值进行匹配。如果网络传输没有错误,两者应该相等。 执行此

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

也计算你应该确保长度是网络校验前字节顺序

ts.len = htons(checkLen); 

memcpy(checkData + 12, tcp, checkLen); 

再经过

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

比较

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

能否详细说明我如何在代码中做到这一点?如果这是你的男人,我不认为伪头中有校验和字段。该程序读取已通过pcap文件捕获的数据包。 – PacSan

+0

也试试这个.. ts.len = htons(checkLen); –