2014-01-15 172 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); –