【发布时间】:2016-03-09 06:41:15
【问题描述】:
我正在尝试获取正确的 TCP 校验和,但它失败了。我正在使用 C++,并使用 winpcap 获取本地网络的数据包,并且尝试计算它们的 tcp 校验和(我已放置正确的过滤器以仅获取 tcp 数据包)。但是当我将计算出的校验和与wireshark 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;
我得到不同的字节,通常数据包 tcp 的字节 51 和 52 属于 tcp 校验和。当我输出它们时,它们是不一样的。
【问题讨论】:
-
您不能将您的校验和代码与wireshark 在用户空间中所做的比较,或者检查一下Linux 内核,看看它是如何完成的吗?
-
这不是问题,因为我已经读过“校验和卸载”也会影响 IP 校验和,在这种情况下,我用相同的方法计算了 IP 校验和并且它是成功的。问题出在代码中,所以请关注代码,不要关注不存在的问题。我的代码是错误的,我在这里发帖纠正它,而不是在我的代码有 100 个未纠正的错误时谈论“校验和卸载”。
-
您是否遵循了 RFC?见TCP Checksum Function Design
标签: c++ networking tcp network-programming