IP报头:
一.IP校验和
IP协议的校验和只包括IP报头。在IPV4中,IP校验和字段是一个16位字段,包括整个IP报头(含选项在内)。校验和首先由封包的发送发计算出来,然后在前往其目的地的沿路上再由一个又一个的跳点(比如路由器)更新。更新校验和前,每个跳点必须先检查封包的健康状态(比较封包的校验和以及本地所计算的校验和)。若检查失败,封包就被丢弃,但不会产生ICMP,有上层协议进行处理(比如,利用定时器,若特定时间内没有收到确认通知信息,就重传)。
下面是一些会触发校验和更新的情况:
1.递减TTL:路由器转发封包前,必须递减其IP报头中的TTL。因为IP校验和也包括该字段。
2.修改封包:改变一或数个IP报头字段都会强迫校验和重新计算。比如NAT。
3.IP选项处理:每次选项的处理方式使得IP报头必须有所新增(如新增时间戳)或修改时,都会重新计算时间戳。
4.分段:当封包被分段时,每个分段都会有不同的报头。比如分段报头中的offset字段就不同,校验和重新计算。
二.IP校验和算法
检验和算法可以分成两步来实现。
首先在发送端,有以下三步:
1.把即将发送的IP头部中的检验和设置为0,然后以16位为一个间隔,将IP头部分成许多个16位的字段;
2.将第1步获得的所有字段进行二进制相加求和;
3.把最终结果取反,就得到检验和,再将该值填充到IP头部。
其次在接收端,也有相应的三步:
1.把接收到的IP头部分成16位一个间隔的字段集合;
2.所有字段进行二进制相加求和;
3.将最终结果取反,判断该结果是否为0,若为0,则说明检验和正确,若不为0,则协议栈会丢掉这个包。
下面是校验和的代码实现:
ip_fast_csum指定IP报头和长度后,计算并返回IP校验和。用于验证输入封包以及计算外出封包的校验和。
-
unsigned short ip_fast_csum(unsigned char * iph,
-
unsigned int ihl)
-
{
-
unsigned int sum;
-
//(%1)就是iph数据包首地址,%0就是sum, %2数据包长度
-
//11-14行都是进行32位的加法运算
-
__asm__ __volatile__(
-
"movl (%1), %0 ;\n"
-
"subl $4, %2 ;\n"
-
"jbe 2f ;\n"
-
"addl 4(%1), %0 ;\n"
-
"adcl 8(%1), %0 ;\n"
-
"adcl 12(%1), %0 ;\n"
-
"1: adcl 16(%1), %0 ;\n"
-
"lea 4(%1), %1 ;\n" //没看懂
-
"decl %2 ;\n"
-
"jne 1b ;\n"
-
"adcl $0, %0 ;\n"
-
"movl %0, %2 ;\n" //保存sum的值到%2
-
"shrl $16, %0 ;\n" //右移16位(读取高16位)到%0
-
"addw %w2, %w0 ;\n" //%0的16位加%2的16位
-
"adcl $0, %0 ;\n" //若进位加上进位
-
"notl %0 ;\n" //取反
-
"2: ;\n"
-
/* Since the input registers which are loaded with iph and ihl
-
are modified, we must also specify them as outputs, or gcc
-
will assume they contain their original values. */
-
: "=r" (sum), "=r" (iph), "=r" (ihl)
-
: "1" (iph), "2" (ihl)
-
: "memory");
-
return(sum);
-
}
-
//jbe 2f和jne 1b的解释请查看
阅读(1557) | 评论(0) | 转发(0) |