Chinaunix首页 | 论坛 | 博客
  • 博客访问: 647572
  • 博文数量: 363
  • 博客积分: 110
  • 博客等级: 民兵
  • 技术积分: 1347
  • 用 户 组: 普通用户
  • 注册时间: 2011-06-22 16:07
文章分类

全部博文(363)

文章存档

2018年(83)

2016年(1)

2014年(2)

2013年(34)

2012年(236)

2011年(7)

分类:

2012-04-14 09:06:54

TCP/IP协议族校验和的计算方法相同, 差别在于进行校验的数据.
 
一 校验和计算方法
   1. 将数据流按16bit求和, 存放在32Bit及更大的空间(eg. u_int32_t cs).
   2. 如果数据流为单字节(留8bit数据), 将之前求和的值与最后8bit求和.
   3. 如cs高16bit不为0, 则将高16bit与低16bit相加, 直到高16bit为0.
   4. 将低16bit的值取反, 得到校验和.
 
   这种校验和的计算方法有两个特点:
   1 把数据流按16bit化分为若干u_int16_t的字段. 计算结果并不依赖u_int16_t的顺序.
   2 在检验和计算中加上全0值对结果没有影响.
   算法如下:
  1. u_int16_t check_sum(u_int16_t *buffer, int size)
  2. {
  3.     //建议将变量放入寄存器, 提高处理效率.
  4.     register int len = size;       
  5.     register u_int16_t *p = buffer;
  6.     register u_int32_t cs = 0;
  7.     //16bit求和
  8.     while( len >= 2)
  9.     {
  10.         cs += *(p++);
  11.         len -= 2;
  12.     }
  13.     //最后的单字节直接求和
  14.     if( len == 1)
  15.         cs += *((u_int8_t *)buffer);
  16.     //高16bit与低16bit求和, 直到高16bit为0
  17.     while( (cs&0xffff0000) != 0)
  18.         cs = (cs>>16) + (cs&0xffff);
  19.     //取反
  20.     return (u_int16_t)(~cs);
  21. }

二 TCP/UDP的校验和计算方法
   TCP/UDP的校验和计算方法相同, 都包括了以下数据的计算: 1) 12字节的伪首部(包含了IP层信息). 2) TCP/UDP首部. 3) TCP/UDP数据.   
   我们用IP首部/UDP首部为例(1 示例不包含IP选项. 2 引用的图来自于《TCP/IP详解-卷二》)
   1. 首先看在缓冲区内的UDP/IP数据, 灰色部份IP填充, 白色UDP填充
   2. 伪首部的数据

    考虑到校验和算法的两个特点 顺序无关/全0无关, 我们可以认为: 缓冲区内, 8字节以后的数据与伪部首完全一至, 可以直接进行校验和计算.
注: 1 TCP数据校验方法和UDP完全相同.
    2 也可以另外建立一个缓冲区, 将数据拷贝过去进行计算, 但效率太低.

    以下是上一篇文章《网络协议及应用之一:socket构造数据包及DOS(SYNflood)攻击》中应用到的代码及详细解释.

  1.     {
  2.         //ip首部中的ttl. 在伪首部计算时, 要先设置为0
  3.         ip->ip_ttl = 0; 
  4.         
  5.         //ip首部的校验和字段, 作为伪首部时, 存放tcp长度
  6.         ip->ip_sum = htons(sizeof(struct tcphdr));
  7.         //因为是攻击包, 源地址随机产生
  8.         ip->ip_src.s_addr = random();        
  9.         //校验前, 将校验和字段设置为0
  10.         tcp->check = 0;
  11.         
  12.         //计算tcp校验和时, 避开ip首部的8个字节. 并设置需要校验的长度
  13.         tcp->check = check_sum((u_int16_t *)buffer + 4, sizeof(buffer) - 8);

  14.         //恢复ip的ttl 
  15.         ip->ip_ttl = MAXTTL;        

  16.         sendto( sockfd, buffer, len, 0, (struct sockaddr *)(&addr), sizeof(struct sockaddr_in));
  17.     }

三 计算结果
   1 校验和错误时, 没有服务器的SYN+ACK包


   2 校验和正确, 双向SYN包. 服务器等待第3次握手


   3 正确的tcp校验和结果

 

阅读(1206) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~