注册 登录  
 加关注
查看详情
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

ideality

@linux c 编程@

 
 
 

日志

 
 
 
 

ip协议栈【转】  

2013-03-09 13:41:32|  分类: netfilter |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

Author:zfive5(zhaozidong)

Email :zfive5@yahoo.com.cn

 

最近一段时间,对网络又开始追根溯源,最好的办法就是打开开源协议栈看一个究竟,不求写一个完整的ip协议栈,但求通达解惑!

 

众所周知,IP头定义如下:

struct IPHeader

{

   unsigned char  ver_hlen;  

   unsigned char  tos;

   unsigned short  len;

   unsigned short  id;

   unsigned short  offset;

   unsigned char   ttl;

   unsigned char   type;

   unsigned short   cksum_header;

   unsigned long   ipsrc;

   unsigned long   ipdest;

   /*

     后面可能存在option数据

   */

};

IP头中的大多字段都好理解,只要一本TCP/IP入门的书就可以明明白白了,对cksum字段理解,如果只是看书,到头来很可能还不清楚怎么算它!

 

关于cksum_header的描述在《tcp/ip卷一》中是这样描述的:

   首部检验和字段是根据I P 首部计算的检验和码。它不对首部后面的数据进行计算。I C M P I G M P U D P T C P 在它们各自的首部中均含有同时覆盖首部和数据检验和码。

   为了计算一份数据报的I P 检验和,首先把检验和字段置为0 。然后,对首部中每个16 bit进行二进制反码求和(整个首部看成是由一串16 bit 的字组成),结果存在检验和字段中。当收到一份I P数据报后,同样对首部中每个16 bit 进行二进制反码的求和。由于接收方在计算过,程中包含了发送方存在首部中的检验和,因此,如果首部在传输过程中没有发生任何差错,那么接收方计算的结果应该为全1 。如果结果不是全1 (即检验和错误),那么I P 就丢弃收到的数据报。但是不生成差错报文,由上层去发现丢失的数据报并进行重传。

 

不知道有多少能人看完此描述后,写出算法或函数来!

 

正确的函数如下:

unsigned short CheckSum(unsigned short *szBUF,int iSize)

      

       unsigned long ckSum=0;

    for(;iSize>1;iSize-=sizeof(unsigned short))

              ckSum+=*szBUF++;

 

       if(iSize==1)

              ckSum+=*(unsigned char *)szBUF;

 

       ckSum=(ckSum>>16)+(ckSum&0xffff);

       ckSum+=(ckSum>>16);

       return(unsigned short )(~ckSum);

}

 

让我们假设一个IP头数据,来解cksum的惑!

 

IP头数据:

 

01000101   / *ver_hlen; */ 

00000000   /*tos*/

00000000 00000010/*len*/

00000000 00000000/*id*/

00000000 00000000/*offset*/

00000001/*ttl*/

00010001/*type*/

00000000 00000000/*cksum(0)*/

01111111 00000000 00000000 0000001/*sip*/

01111111 00000000 00000000 0000001/*dip*/

 

运算过程(注意是大端格式加):

 

01000101 00000000(ver_hlen+tos)

01000101 00000000 ( 和)

00000000 00000010 (len)

01000101 00000010 (上次和+len)

00000000 00000000 (id)

01000101 00000010  (上次和+id)

00000000 00000000 (offset)

01000101 00000010

00000100 00010001

01001001 00010011

00000000 00000000

01001001 00010011

01111111 00000000

11001000 00010011

00000000 00000001

11001000 00010100

01111111 00000000

101000111 00010100

00000000 00000001

和: 101000111 00010101

                  

ckSum=(ckSum>>16)+(ckSum&0xffff)后:

 

   00000000 00000001                1

 01000111 00010101

和: 01000111 00010110

 

ckSum+=(ckSum>>16)后:

   

   01000111 00010110

   00000000 00000000

和: 01000111 00010110

 

~: 10111000 11101000(效检和)

 

 

运算过程(注意用小端格式加):

 

00000000 01000101

00000000 01000101

00000010 00000000

00000010 01000101

00000000 00000000

00000010 01000101

00000000 00000000

00000010 01000101

00010001 00000100

00010011 01001001

00000000 00000000  

00010011 01001001

00000000 01111111  

00010011  11001000

00000001 00000000  

00010100 11001000

00000000 01111111  

00010101 01000111

00000001 00000000  

和: 00010110 01000111

ckSum=(ckSum>>16)+(ckSum&0xffff)后:

 

   00000000 00000000                1

 00010110 01000111

和: 00010110 01000111

 

ckSum+=(ckSum>>16)后:

   

   00010110 01000111

   00000000 00000000

和: 00010110 01000111

 

~: 11101001 10111000(效检和)

 

 

checksum211101000 10111000(小端)

 

checksum110111000 11101000(大端)

 

算法一样,说白了就是循环加,加到没有进位为止,然后在取反!

 

在现在《TCP/IP卷二》中的cksum实现有以下语句:

while(sum>>16)

 sum=(sum&0xffff)+(sum>>16);

 

通过它更能说明就是在作循环加操作,现在又有一个疑问:

       ckSum=(ckSum>>16)+(ckSum&0xffff);

       ckSum+=(ckSum>>16);         

while(sum>>16)

   sum=(sum&0xffff)+(sum>>16);

等价吗?

 

等价,在一定条件下等价,大家都知道ip理论上最长是0xffff

那么

checksum最大不会超过:0xffff0000

这样>>16后为0xffff

0xffff+checksum最大0x1fffe,

0x1fffe >>16+0x1fffe=0xffff

注意了没有了进位

所以得到等价的结论!

 

 

以前每读到cksum注解时,书上只是草草曰16位反码和之云云,没有强调进位也要参加运算一点征兆,直到最近写了不少程序才看清楚这个细节!

 

源码之下必解惑!

  评论这张
 
阅读(696)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018