一、UDP校验和计算
UDP计算校验和的方法和IP数据报首部校验和的方法相似。不同的是:IP数据报校验和只校验IP数据报的首部,但UDP的校验和是把首部和数据部分一起都检验。
UDP的校验和需要计算UDP首部加数据荷载部分,但也需要加上UDP伪首部。这个伪首部指,源地址、目的地址、UDP数据长度、协议类型(0x11),协议类型就一个字节,但需要补一个字节的0x0,构成12个字节。伪首部+UDP首部+数据一起计算校验和。
UDP检验和的计算方法是:
按每16位求和得出一个32位的数;
如果这个32位的数,高16位不为0,则高16位加低16位再得到一个32位的数;
重复第2步直到高16位为0,将低16位取反,得到校验和。
二、实战
伪首部:
源IP地址:138.0.0.87(0x8a00 0x0057)
目的IP地址:138.0.0.85(0x8a00 0x0055)
协议号:0x0011 (补一个字节的0x0)
UDP长度:51(0x0033)
UDP头部:
0x0064 0x000a 0x0033 0x0000(校验和清零)
数据部分:
0x212f33203c6d70652a2a313e3a3130300a503d31363834333533327b0a433d2d7b0a4d463d524f4f547d7d
算法:
#include <stdio.h>
unsigned short check_sum(unsigned short *a, int len)
{
unsigned int sum = 0;
while (len > 1) {
sum += *a++;
len -= 2;
}
if (len) {
sum += *(unsigned char *)a;
}
while (sum >> 16) {
sum = (sum >> 16) + (sum & 0xffff);
}
return (unsigned short)(~sum);
}
int main()
{
unsigned short sum;
char buffer[] = {0x8a,0x00,0x00,0x57,0x8a,0x00,0x00,0x55,0x00,0x11,0x00,0x33,\
0x00,0x64,0x00,0x0a,0x00,0x33,0x00,0x00,\
0x21,0x2f,0x33,0x20,0x3c,0x6d,0x70,0x65,0x2a,0x2a,0x31,0x3e,0x3a,0x31,\
0x30,0x30,0x0a,0x50,0x3d,0x31,0x36,0x38,0x34,0x33,0x35,0x33,0x32,0x7b,0x0a,0x43,0x3d,0x2d,0x7b,0x0a,0x4d,0x46,0x3d,0x52,0x4f,0x4f,0x54,0x7d,0x7d};
sum = check_sum((unsigned short*)buffer,sizeof(buffer));
printf("IP CheckSum:%x\n",htons(sum));
return 0;
}
运行结果:
[root@localhost test]# ./thread
IP CheckSum:9c06
与抓包结果相同。