當發送IP包時,需要計算IP前序的校正和:
1、 把校正和欄位置為0;
2、 對IP頭部中的每16bit進行二進位求和;
3、 如果和的高16bit不為0,則將和的高16bit和低16bit反覆相加,直到和的高16bit為0,從而獲得一個16bit的值;
4、 將該16bit的值取反,存入校正和欄位。
◆當接收IP包時,需要對前序進行確認,檢查IP頭是否有誤,演算法同上2、3步,然後判斷取反的結果是否為0,是則正確,否則有錯。
演算法:
SHORT checksum(USHORT* buffer, int size)
{
unsigned long cksum = 0;
while(size>1)
{
cksum += *buffer++;
size -= sizeof(USHORT);
}
if(size)
{
cksum += *(UCHAR*)buffer;
}
cksum = (cksum>>16) + (cksum&0xffff); //將高16bit與低16bit相加
cksum += (cksum>>16); //將進位到高位的16bit與低16bit 再相加
return (USHORT)(~cksum);
}
執行個體:
IP頭:
45 00 00 31
89 F5 00 00
6E 06 00 00(校正欄位)
DE B7 45 5D -> 222.183.69.93
C0 A8 00 DC -> 192.168.0.220
計算:
4500 + 0031 +89F5 + 0000 + 6e06+ 0000 + DEB7 + 455D + C0A8 + 00DC =3 22C4
0003 + 22C4 = 22C7
~22C7 = DD38 ->即為應填充的校正和
當接受到IP資料包時,要檢查IP頭是否正確,則對IP頭進行檢驗,方法同上:
計算:
4500 + 0031 +89F5 + 0000 + 6E06+ DD38 + DEB7 + 455D + C0A8 + 00DC =3 FFFC
0003 + FFFC = FFFF
~FFFF = 00000 ->正確
TCP首部檢驗和與IP首部校正和的計算方法相同,在程式中使用同一個函數來計算。
需要注意的是,由於TCP首部中不包含源地址與目標地址等資訊,為了保證TCP校正的有效性,在進行TCP校正和的計算時,需要增加一個TCP偽首部的校正和,定義如下:
struct
{
unsigned long saddr; //源地址
unsigned long daddr; //目的地址
char mbz;//置空
char ptcl; //協議類型
unsigned short tcpl; //TCP長度
}psd_header;
然後我們將這兩個欄位複製到同一個緩衝區SendBuf中並計算TCP校正和:
memcpy(SendBuf,&psd_header,sizeof(psd_header));
memcpy(SendBuf+sizeof(psd_header),&tcp_header,sizeof(tcp_header));
tcp_header.th_sum=checksum((USHORT *)SendBuf,sizeof(psd_header)+sizeof(tcp_header));