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值对结果没有影响.
算法如下:
-
u_int16_t check_sum(u_int16_t *buffer, int size)
-
{
-
//建议将变量放入寄存器, 提高处理效率.
-
register int len = size;
-
register u_int16_t *p = buffer;
-
register u_int32_t cs = 0;
-
-
//16bit求和
-
while( len >= 2)
-
{
-
cs += *(p++);
-
len -= 2;
-
}
-
-
//最后的单字节直接求和
-
if( len == 1)
-
cs += *((u_int8_t *)buffer);
-
-
//高16bit与低16bit求和, 直到高16bit为0
-
while( (cs&0xffff0000) != 0)
-
cs = (cs>>16) + (cs&0xffff);
-
-
//取反
-
return (u_int16_t)(~cs);
-
}
二 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)攻击》中应用到的代码及详细解释.
-
{
-
//ip首部中的ttl. 在伪首部计算时, 要先设置为0
-
ip->ip_ttl = 0;
-
-
//ip首部的校验和字段, 作为伪首部时, 存放tcp长度
-
ip->ip_sum = htons(sizeof(struct tcphdr));
-
-
//因为是攻击包, 源地址随机产生
-
ip->ip_src.s_addr = random();
-
-
//校验前, 将校验和字段设置为0
-
tcp->check = 0;
-
-
//计算tcp校验和时, 避开ip首部的8个字节. 并设置需要校验的长度
-
tcp->check = check_sum((u_int16_t *)buffer + 4, sizeof(buffer) - 8);
-
-
//恢复ip的ttl
-
ip->ip_ttl = MAXTTL;
-
-
sendto( sockfd, buffer, len, 0, (struct sockaddr *)(&addr), sizeof(struct sockaddr_in));
-
}
三 计算结果
1 校验和错误时, 没有服务器的SYN+ACK包
2 校验和正确, 双向SYN包. 服务器等待第3次握手
3 正确的tcp校验和结果
阅读(1206) | 评论(0) | 转发(0) |