带有负载的数据包的 TCP 校验和不正确
TCP checksum incorrect for packets with payload
我正在用 C 开发一个 Ubuntu 盒子。
校验和计算代码如下:
unsigned short csum(unsigned short *buf, int nwords)
{
unsigned long sum;
for(sum=0; nwords>0; nwords=nwords-2){
sum += *buf;
//printf("%04x\n", *buf);
buf++;
}
if(nwords>0)
sum += *buf++;
while(sum >> 16)
sum = (sum >> 16) + (sum &0xffff);
/* sum += (sum >> 16);*/
return (unsigned short)(~sum);
}
不过,这对于 IP 和 ICMP 网段一直运行良好,所以我非常怀疑这就是问题所在。
为了找出问题所在,我目前正在捕获随机数据包,构建 tcp header 部分的伪 header + deepcopy,然后打印出原始校验和和计算出的校验和。
struct tcphdr *tcph = (struct tcphdr *)(buffer + sizeof(struct ethhdr) + iphdrlen);
int tcphdrlen = size - sizeof(struct ethhdr) - iphdrlen;
int pseudo_len = sizeof(iph->saddr) + sizeof(iph->daddr) + 1 + sizeof(iph->protocol) + 2 + tcphdrlen;
test = (u_char *) malloc(pseudo_len);
memset(test, 0, pseudo_len);
memcpy(test, &(iph->saddr), sizeof(iph->saddr));
int pos = sizeof(iph->saddr);
memcpy(test + pos, &(iph->daddr), sizeof(iph->daddr));
pos += sizeof(iph->daddr);
memset(test + pos, 0, 1);
pos += 1;
memcpy(test + pos, &(iph->protocol), sizeof(iph->protocol));
int tcphdrlenhtons = htons(tcphdrlen);
pos += sizeof(iph->protocol);
memcpy(test + pos, &tcphdrlenhtons, 2);
pos += 2;
memcpy(test + pos, tcph, tcphdrlen);
struct tcphdr *t_tcph = (struct tcphdr *)(test + pos);
memset(&(t_tcph->check), 0, sizeof(t_tcph->check));
printf("correct tcp checksum: %d\n", ntohs(tcph->check));
printf("my tcp checksum: %d\n", ntohs((unsigned short) csum((unsigned short *)test, pseudo_len)));
在测试中,我发现计算出的校验和是正确的,但前提是数据包没有负载。
如果有人能告诉我我可能做错了什么,我将不胜感激。
与其说这是一个建议,不如说这是一个真正的答案。您的测试代码有点难以理解。像 test
这样的变量不会让其他人阅读和理解代码变得容易。
尝试为 pseudo-header 创建一个实际的结构,并定期分配而不是 memcpy
之类的 IPv4 地址。它们只有 4 个字节长,这将使您的代码更易于阅读。
这一行:
memset(test + pos, 0, 1);
让我有点困扰,因为你将什么设置为 0 并不明显。我还想知道你是否将正确的字节数设置为 0。
我试图弄清楚您是否有字节序问题,但这很困难,因为我无法遵循您的测试代码。
正如 David Schwartz 指出的那样,程序在计算校验和之前捕获数据包,导致捕获的数据包的校验和不正确。该程序实际上给出了正确的校验和。
我正在用 C 开发一个 Ubuntu 盒子。
校验和计算代码如下:
unsigned short csum(unsigned short *buf, int nwords)
{
unsigned long sum;
for(sum=0; nwords>0; nwords=nwords-2){
sum += *buf;
//printf("%04x\n", *buf);
buf++;
}
if(nwords>0)
sum += *buf++;
while(sum >> 16)
sum = (sum >> 16) + (sum &0xffff);
/* sum += (sum >> 16);*/
return (unsigned short)(~sum);
}
不过,这对于 IP 和 ICMP 网段一直运行良好,所以我非常怀疑这就是问题所在。
为了找出问题所在,我目前正在捕获随机数据包,构建 tcp header 部分的伪 header + deepcopy,然后打印出原始校验和和计算出的校验和。
struct tcphdr *tcph = (struct tcphdr *)(buffer + sizeof(struct ethhdr) + iphdrlen);
int tcphdrlen = size - sizeof(struct ethhdr) - iphdrlen;
int pseudo_len = sizeof(iph->saddr) + sizeof(iph->daddr) + 1 + sizeof(iph->protocol) + 2 + tcphdrlen;
test = (u_char *) malloc(pseudo_len);
memset(test, 0, pseudo_len);
memcpy(test, &(iph->saddr), sizeof(iph->saddr));
int pos = sizeof(iph->saddr);
memcpy(test + pos, &(iph->daddr), sizeof(iph->daddr));
pos += sizeof(iph->daddr);
memset(test + pos, 0, 1);
pos += 1;
memcpy(test + pos, &(iph->protocol), sizeof(iph->protocol));
int tcphdrlenhtons = htons(tcphdrlen);
pos += sizeof(iph->protocol);
memcpy(test + pos, &tcphdrlenhtons, 2);
pos += 2;
memcpy(test + pos, tcph, tcphdrlen);
struct tcphdr *t_tcph = (struct tcphdr *)(test + pos);
memset(&(t_tcph->check), 0, sizeof(t_tcph->check));
printf("correct tcp checksum: %d\n", ntohs(tcph->check));
printf("my tcp checksum: %d\n", ntohs((unsigned short) csum((unsigned short *)test, pseudo_len)));
在测试中,我发现计算出的校验和是正确的,但前提是数据包没有负载。
如果有人能告诉我我可能做错了什么,我将不胜感激。
与其说这是一个建议,不如说这是一个真正的答案。您的测试代码有点难以理解。像 test
这样的变量不会让其他人阅读和理解代码变得容易。
尝试为 pseudo-header 创建一个实际的结构,并定期分配而不是 memcpy
之类的 IPv4 地址。它们只有 4 个字节长,这将使您的代码更易于阅读。
这一行:
memset(test + pos, 0, 1);
让我有点困扰,因为你将什么设置为 0 并不明显。我还想知道你是否将正确的字节数设置为 0。
我试图弄清楚您是否有字节序问题,但这很困难,因为我无法遵循您的测试代码。
正如 David Schwartz 指出的那样,程序在计算校验和之前捕获数据包,导致捕获的数据包的校验和不正确。该程序实际上给出了正确的校验和。