IP、TCP校验和
IP、TCP校验和
在网上看了半天,没看明白,现在总算明白了。
下面是一条最简单的指令,没有数据
45 0 0 34 4D C5 40 0 72 6 20 E1 D3 93 4 CC C0 A8 1 16
4E 23 6 8F 36 CA 45 A3 EC 73 CB FB 80 10 1E E8 D0 2A 0 0
1 1 8 A 15 F AC FE 0 0 A1 EF
第一行是IP包头,
(2-3)字节0 34 表示包总长hex(34)=52
计算校验和时,先把(10-11)16位IP首部校验和置0(如果不置0,算出的校验和是0,这就相当于检测原来的校验和是否正确),在去用网上流传的checksum 函数就可算出来了。(20 E1)和指令中的一致。
4500+0034+4DC5+4000+7206+0(20E1置0)+D393+4CC+c0A8+116=2DF1C
2+DF1C=DF1E
~DF1E=20E1
第二行是TCP包头,
(12)80 表示TCP包头长hex(80/4)=32,后面的12个字节是TCP包头的可选项(可怜我一直以为是TCP的伪包头,实际上TCP的伪包头是不发的,根本就不存在)。
计算TCP的校验和时,有三部分:TCP伪包头+TCP包头+数据。
这条指令没有数据,就只用算两部分,
伪包头自己写,
源IP地址 目的IP地址 置空(0) 协议类型 TCP包的总长度
D3 93 4 CC C0 A8 1 16 0 6 0 20
源IP地址,目的IP地址,协议类型在IP包头中有,直接移过来, TCP包的总长度用IP包中的总长度0x34-IP包的长度0x14(定长20)=0x20。
然后把TCP伪包头+TCP包头+数据三部分合起来(TCP包头的(16-17)校验和置0),再用鼎鼎大名的checksum函数,就可算出校验和 D0 2A .
______________________________________________
unsigned short checksum(unsigned short *buf, int nword)
{
unsigned long sum;
for(sum = 0; nword > 0; nword--)
sum += *buf++;
sum = (sum>>16) + (sum&0xffff);
sum += (sum>>16);
return ~sum;
}
Type IPHeader
lenver As Byte '(0)4位首部长度+4位IP版本号
tos As Byte '(1)8位服务类型TOS
len As Integer '(2-3)16位总长度(字节)* 包括数据
ident As Integer '(4-5)16位标识**
flags As Integer '(6-7)3位标志位
ttl As Byte '(8)8位生存时间 TTL
proto As Byte '(9)8位协议 (TCP, UDP 或其他)
CheckSum As Integer '(10-11)16位IP首部校验和 **
sourceIP As Long '(12-15)32位源IP地址*
destIP As Long '(16-19)32位目的IP地址*
End Type
Type TcpHeader
srcPort As Integer '(0-1)源端口
dstPort As Integer '(2-3)目的端口
seqNum As Long '(4-7)顺序号**
ackNum As Long '(8-11)期待获得对方的TCP包编号**
h_len As Byte '(12)以32比特为单位的TCP报头长度,h_len / 4 即得到实际长度,包括ipheader和TCP伪首部的长度
flags As Byte '(13)标志(URG、ACK等)
indow As Integer '(14-15)窗口大小**
chksum As Integer '(16-17)校验和**
urgptr As Integer '(18-19)紧急指针
End Type
'TCP伪首部 用于进行TCP校验和的计算,保证TCP效验的有效性
Type TcpPsdHeader
sourceIP As Long '(0-3)源IP地址
destIP As Long '(4-7)目的IP地址
mbz As Byte ' '(8)置空(0)
ptcl As Byte '(9)协议类型(IPPROTO_TCP)
tcpl As Integer '(10-11)TCP包的总长度(单位:字节)*
End Type