TCP校验和详细讲解和计算

首先看看TCP校验和计算原理:

TCP校验字段占两个字节如0x62,0x0d,实际上是这样计算来的:
对方IP+我方IP+报文长度+信息长度+0x06(协议类型)+
TCP各字段长度以及数据各字段和(注意此时将对应的校验和字段--TCP的第17,18位,实际对应数组下标的16,17位--都设为0x00.同时
每两个字节组合为一个数值如0x01,0x02组合为0x0102,数据abc对应为0x61,0x62,0x63,则组合成0x6162,0x6300)

上述算出来的校验和(设为resule)假如超过0xffff的话,将超过的部分添加到result的低位去再用0xffff减去该值,如:0x54321最终应成为:0xffff-(0x4321+0x05)

其次根据抓包工具抓住的TCP报文我们看到下列图片中已经有一个包含了双方IP,TCP报文以及信息的报文,根据图片中给出的信息,依照上述原理手动计算一个TCP校验和:






本地Ip:0xc0,0xa8,0x9f,0x01;
对方IP:0xc0,0xa8,0x9f,0x82
TCP字段:0x04, 0xc6, 0x87, 0x01, 0x4b, 0xd7, 0x89, 0x9f, 0x4e, 0x3b, 0x90, 0xae, 0x50, 0x18, 0xff, 0xff, 0xeb, 0x69, 0x00, 0x00
从上述实际报文可见该TCP的校验和为eb69
将对应的校验和字段设为0x00后TCP报文实际为:
0x04, 0xc6, 0x87, 0x01, 0x4b, 0xd7, 0x89, 0x9f, 0x4e, 0x3b, 0x90, 0xae, 0x50, 0x18, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00
数据字段abc,对应0x61,0x62,0x63;
TCP报文长度为20,信息长度为3,23化为16进制即0x17
所以result=(0xc0a8+0x9f01)+(0xc0a8+0x9f82)+(0x04c6+0x8701+0x4bd7+0x899f+0x4e3b+0x90ae+0x5018+0xffff+0x0000+0x0000)+(0x17+0x06)+(0x6162+0x6300)
得出result=0x7148f,将超出0xffff的位加到低位上去,reuslt=0xffff-(0x148f + 0x0007)=0xeb69正好和抓包工具显示的校验和字段是一样的.

最后就是给出一个计算校验和的函数了

  1. #include <stdio.h>  
  2. INT8U sum[2]={0};           //两个保存校验和的全局变量  
  3. INT8U Info[30]={0};         //保存实际数据的全局变量  
  4. /* 
  5. *计算校验和的函数,传递过来的参数分别是:指向纯TCP报文的的指针data,指向本地IP的指针mIP,指向对方IP的指针yIP,实际要传送的数据长度 length 
  6. *该函数计算TCP校验和字段的实际填充信息,通过全局变量数组sum[2]返回. 
  7. */  
  8. void checksum(INT8U *data,INT8U *mIP,INT8U *yIP,INT16U length)  
  9. {  
  10.     INT16U csum;   
  11.     INT16U i;  
  12.     INT32U dat[30]={0};             //保存TCP的的数组  
  13.     INT32U shu[30]={0};             //保存信息的数组  
  14.     INT16U temp;  
  15.     INT32U result,temp1,temp2,temp3,temp4=0,temp5=0;  
  16.   
  17.     //将IP字段从数组中取出组合成新的数据  
  18.     temp1=((INT16U)mIP[0]<<8)+(INT16U)mIP[1]+((INT16U)mIP[2]<<8)+(INT16U)mIP[3];  
  19.     temp2=((INT16U)yIP[0]<<8)+(INT16U)yIP[1]+((INT16U)yIP[2]<<8)+(INT16U)yIP[3];  
  20.       
  21.     //数据长度+协议类型  
  22.     temp3=(INT16U)(length)+0x06;      
  23.     for(i=0 ; i<length ; i++)  
  24.     {  
  25.         if(i%2==0)              //将偶数位左移放到高位  
  26.         {  
  27.             dat[i]=(INT16U)data[i]<<8;  
  28.             shu[i]=(INT16U)Info[i]<<8;  
  29.         }  
  30.         else                    //奇数位不变  
  31.         {  
  32.             dat[i]=(INT16U)data[i];  
  33.             shu[i]=(INT16U)Info[i];  
  34.         }         
  35.     }   
  36.     dat[16]=0x00;               //校验和字段初始置0  
  37.     dat[17]=0x00;  
  38.     for(i=0 ; i<length ; i++)  
  39.     {  
  40.         temp4=dat[i]+temp4;  
  41.         temp5=shu[i]+temp5;  
  42.     }  
  43.     result=temp1+temp2+temp3+temp4+temp5;     
  44.     if(result>0xffff)  
  45.     {  
  46.         temp=result/0xffff;//得到高位   
  47.         csum=(INT16U)result;//得到低位  
  48.         csum=0xffff-(csum+temp);  
  49.     }  
  50.     //将计算出来的数据和高位和低位分别放到数组对应字段中  
  51.     sum[0]=csum>>8;  
  52.     sum[1]=(INT8U)csum;  
  53. }  
  54.   
  55. int main()  
  56. {  
  57.     INT8U length=20;  
  58.     INT8U i,j=0;  
  59.     INT8U info[30]={'a','b','c'};  
  60.     INT8U mIP[]={0xc0,0xa8,0x9f,0x01};  
  61.     INT8U yIP[]={0xc0,0xa8,0x9f,0x82};  
  62.     INT8U PSH_ACK[30]={0x04,0xc6,0x87,0x01,0x4b,0xd7,0x89,0x9f,0x4e,0x3b,<span style="white-space:pre">                     </span>//一个TCP数组  
  63.         0x90,0xae,0x50,0x18,0xff,0xff,0x00,0x00,0x00,0x00};  
  64.     for(i=0;i<30;i++)                                                //数据放到全局变量   
  65.         Info[i]=info[i];  
  66.     while(Info[j]!=0)  
  67.         j++; <span style="white-space:pre">                                                 </span>//获得实际信息的长度  
  68.     length=length+j;  
  69.     checksum(psh,mIP,yIP,length);                                     
  70.     printf("\n\nlength:%x%x\n\n",sum[0],sum[1]); <span style="white-space:pre">                                 </span><span style="background-color: rgb(255, 255, 255); ">//看答案是否是620d</span>  
  71.     return 0;  
  72. }  


注意其中的INT8U等类型是这样定义的

  1. typedef unsigned char  INT8U;                   /* 无符号8位整型变量                        */  
  2. typedef unsigned short INT16U;                  /* 无符号16位整型变量                       */  
  3. typedef unsigned int   INT32U;                  /* 无符号32位整型变量                       */  

该计算TCP校验和的函数最初是为"嵌入式IP_TCP协议栈"的实现而编写的,其环境是

操作系统:    uCOS

网络芯片:    enc28j60

硬件环境:    使用Proteus + LPC2124

开发环境:    Keil V0.3

当放到嵌入式keil v0.3的时候,将相关头文件和库函数如printf和stdio.h更换掉,或干脆不用.

当然因为它最初是在vs里完成的也可以用在windows里需要计算校验和的地方.

当然该函数有不尽人意的地方,比如完全可以将信息放到TCP数组的里面,这样可以减少很多累赘的语句提高运行速度,希望各位IT好友提出其他的建议和意见大笑!


来源:http://blog.csdn.net/wangshiqilin_fjy/article/details/7889316

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值