我正在编写一个简单的程序来发送/接收TCP数据包。我被困在计算TCP数据包的校验和。
对于校验和功能,我重复使用如下代码:
static int
in_cksum(u_short *addr, int len)
{
register int nleft = len;
register u_short *w = addr;
register int sum = 0;
u_short answer = 0;
/*
* 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);
}
我收到了一个数据包并存储在char缓冲区[2048]中。为了得到IP头,我做:
struct iphdr* ip;
ip = (struct iphdr*) buffer;
以下是我获取tcp标头的方法:
tcp=(struct tcphdr*) (buffer+(4*ip->ihl));
这是我的伪TCP结构
struct tcp_pseudohdr{
uint32_t tcp_ip_src, tcp_ip_dst;
uint8_t tcp_reserved;
uint8_t tcp_ip_protocol;
uint16_t tcp_length;
struct tcphdr tcp_hdr;
}
struct tcp_pseudohdr pseudo_tcp;
memset(&pseudo_tcp,0,sizeof(struct tcp_pseudohdr));
然后我填写TCP伪结构并计算tcp校验和,如下所示:
pseudo_tcp.tcp_ip_src = ip->saddr;
pseudo_tcp.tcp_ip_dst = ip->daddr;
pseudo_tcp.tcp_ip_protocol = ip->protocol;
pseudo_tcp.tcp_reserved = 0;
pseudo_tco.tcp_length = htons(ntohs(ip->tot_length)-(4*ip->ihl));
memcpy(&pseudo_tcp,tcp,ntohs(ip->tot_length)-(4*ip->ihl));
在此之后,我能够准确地准备回伪信息在pseudo_tcp.tcp_hdr.source,pseudo_tcp.tcp_hdr.check等中。
然后我最终计算校验和如下:
tcp->check=0;
tcp->check=in_cksum((unsigned short*)&pseudo_tcp, ntohs(ip->tot_length)-(4*ip->ihl)+12);
此函数的输出ntohs(tcp-> check)= 0.我觉得我真的很接近,但可能会遗漏一些东西。通常,当我在计算之前没有设置校验和= 0时,cksum函数返回0。但是,在这种情况下,我做了,并且不确定发生了什么。
我注意到的一件事是struct tcphdr的大小= 20,但是当我记忆时,这个ntohs(ip-> tot_length) - (4 * ip-> ihl)= 40,因为它包含选项。不知道这是否会导致问题或是否存在其他问题。
非常感谢任何帮助。提前谢谢!
答案 0 :(得分:2)
设置tcp->check = 0
没有做任何事情,因为你正在校验伪pseudo_tcp,这是tcp的副本。在将tcp复制到pseudo_tcp之前设置tcp->check = 0
,或者将pseudo_tcp中的校验和设置为0。