2015-12-04 281 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