2015-12-04 278 views
2

我正在嘗試獲取正確的TCP校驗和,但失敗。我正在使用C++,我用winpcap獲取本地網絡的數據包,並試圖計算它們的tcp校驗和(我已經把正確的過濾器設置爲只有tcp數據包)。但是當我比較我的計算校驗和與wireshark tcp校驗和時,它們是不一樣的。TCP校驗和計算出錯

這是我用C++做的代碼,它使用位圖來檢測位承載。

u_char* tcp_checksum(const u_char* data, int size) 
{ 
    u_char *checksum = new u_char[2](); 
    uint16_t sumando = 0; 
    bitset<17> total; 

    //add ip src and ip dst 
    for (int i = 26; i < 33; i++){ 
     total = sumando + (uint16_t)((datos[i] << 8) + datos[i + 1]); 
     sumando += (uint16_t)((datos[i] << 8) + datos[i + 1]); 
     if (total[16] == 1) 
      sumando++; 
     i++; 
    } 

    //add el zero byte and number of protocol 
    total = sumando + (uint16_t)(0x06); 
    sumando += (uint16_t)(0x06); 
    if (total[16] == 1) 
     sumando++; 

    /*here I should add the tcp length to complete the tcp pseudo header but i didnt add anything because I dont know to calculate the tcp len correctly but its not a problem because a lot of times is cero and the tcp still failing.*/ 

    //okay we have just calculated the pseudoheader. 

    //add all tcp header except the 2 bytes of the checksum (20 bytes normally) 
    for (int i = 34; i < 54; i++){ 
     if (i != 50 && i != 52){//no sumo ni padding ni checksum. 
      total = sumando + (uint16_t)((datos[i] << 8) + datos[i + 1]); 
      sumando += (uint16_t)((datos[i] << 8) + datos[i + 1]); 
      if (total[16] == 1) 
       sumando++; 
     } 
     // 
     if (i == 52) break; 
     i++; 
    } 


    //add the tcp payload in 16 bits each adding. 
    for (int i = 55; i < tamaño - 1; i++){//tamaño - 1 
     total = sumando + (uint16_t)((datos[i] << 8) + datos[i + 1]); 
     sumando += (uint16_t)((datos[i] << 8) + datos[i + 1]); 
     if (total[16] == 1) 
      sumando++; 
     i++; 
    } 
    if (tamaño % 2 == 0){ 
     total = sumando + (uint16_t)((0x00 << 8) + datos[tamaño]); 
     sumando += (uint16_t)((0x00 << 8) + datos[tamaño]); 
     if (total[16] == 1) 
      sumando++; 
    } 

    //i get the complementary and i divided the u_short (16 bits) (uint16_t) in 2 bytes which i return 
    sumando = sumando & 0xFFFF; 
    sumando = ~sumando; 
    checksum[0] = (sumando >> 8) & 0x00FF; 
    checksum[1] = sumando & 0x00FF; 
    return checksum; 
    } 

好吧,當我嘗試不是真正的TCP校驗字節和我的TCP校驗其之間比較相同:

printf("%x%x==", pkt_data[50], pkt_data[51]); 
u_char *c = new u_char[2](); 
c= tcp_checksum(pkt_data, header->caplen); 
printf("%x%x\n", c[0], c[1]); 
cout << endl; 
delete c; 

我得到不同的字節,通常字節51和52一個數據包的tcp屬於tcp校驗和。當我輸出它們時,它們是不一樣的。

+0

難道你不能將你的校驗碼與Wireshark在用戶空間中做什麼比較,或者檢查linux內核並看看它是如何完成的? –

+0

這不是問題,因爲我讀過「校驗和卸載」也會影響IP校驗和,在這種情況下,我使用相同的方法計算了IP校驗和,結果是成功的。問題出在代碼中,所以請關注代碼,而不要關注不存在的問題。我的代碼是錯誤的,我在這裏發佈它來糾正它,而不是當我的代碼有100個錯誤沒有被糾正時談論「校驗和卸載」。 – Kaxperday

+0

你是否遵循RFC?請參閱[TCP校驗和功能設計](https://tools.ietf.org/html/rfc1071#section-2.4.4.5) –

回答

1

不要把你的結果與wireshark比較,至少不要關掉checksum offloading

由於網絡接口卡執行的校驗和卸載,通過libpcap/winpcap捕獲的數據包的校驗和爲often wrong

+0

(發佈時間[Kaxperday](https://stackoverflow.com/users/5615711/kaxperday) )這不是問題,因爲我讀過「校驗和卸載」也會影響IP校驗和,在這種情況下,我使用相同的方法計算了IP校驗和,並且它是成功的。 問題出在代碼中,所以請關注代碼,而不是不存在的問題。我的代碼是錯誤的,我在這裏發佈它來糾正它,而不是當我的代碼有100個錯誤沒有被糾正時談論「校驗和卸載」。 – ryanyuyu