IP/UDP/TCP/ICMP数据报协议的校验和的区别和计算


IP/UDP/TCP/ICMP数据报协议的校验和的区别和计算




1、现针对各种协议数据包校验的区别总结如下:

(1)IP校验和:

IP数据报的校验和只检验IP数据报的首部。

(2)UDP校验和:

UDP数据报计算校验和的方法和IP数据报校验和的方法相似,但是UDP的校验和是将首部和数据部分一起都校验。
并且在计算UDP校验和之前需要封装一个伪首部,伪首部结构如下(具体结构定义见后面代码部分):

源IP地址 | 目的IP地址 | 全 0 | 协 议 | UDP长度


(3)TCP校验和:

TCP 的校验和计算方法同UDP一样,同样要加上一个伪头部,区别是伪头部的协议码是0x06,长度是整个TCP报文的长度(包含TCP头部)。

(4)ICMP校验和:

ICMP校验和的计算方法一样,只不过只是对ICMP包整个进行校验和,没有伪头部,也不包括IP包头部。

总结如下: 计算IP数据报和ICMP的校验和时不需要封装伪首部,他俩不同的是IP数据报只检验IP数据报的首部,而ICMP数据报校验包括ICMP头部和数据部分(整个ICMP长度),TCP和UDP的校验方法和IP、ICMP校验方法一样,但是TCP和UDP校验之前需要封装伪首部。还有一个需要注意的是校验的顺序是从上(层)到下(层),如校验ICMP时,先校验ICMP后校验IP(ICMP数据包结构=ether + IP + ICMP), 并且校验之前需要先将校验和的值初始化为0.

2、以上的几种数据报的校验和的计算方法都一样,把校验部分看成以16位为单位的数字组成,依次进行二进制反码求和。

具体如下:
unsigned short check_sum(unsigned short *packet,int packlen)
{
register unsigned long sum = 0;
while (packlen > 1)
{
sum += *(packet++);
packlen -= 2;
}
if (packlen > 0)
sum += *(unsigned char *) packet;
while (sum >> 16)
sum = (sum & 0xffff) + (sum >> 16);


return (unsigned short) (~sum);
}

3、应用举例(UDP校验):

注:当一个数据包中有多个数据报协议时,校验的顺序必须是从上往下,
例:一个数据报的封装为 以太网首部+IP首部+UDP首部+数据,那么在计算校验和的步骤如下:
(1)分别将IP和UDP的校验和置0;
(2)计算UDP校验和(包括已封装伪首部的UDP头+数据);
(3)计算IP校验和;

下面为计算UDP校验和的示例:
//定义校验UDP时的伪首部结构体
typedef struct {
struct in_addr s_addr;         //源IP
struct in_addr d_addr;         //目的IP
unsigned char mbz;             //全0
unsigned char ptcl;            //协议
unsigned short plen;           //UDP长度(UDP头+数据)
}udp_psd_header;



udph->check = 0;           //不能省略
udph->check = udp_chksum(iph, udp_len); 
//校验和,这里传入参数iph(IP首部指针)是因为封装UDP伪首部时需要知道源IP、目的IP,而知道了IP首部指针,自然也就知道了UDP首部指针
iph->ip_sum = 0;            //不能省略
iph->ip_sum = check_sum((unsigned short*)iph, sizeof(struct ip));  //校验和

//UDP校验和程序
//校验UDP/TCP首部首先需要封装一个为首部,然后再校验,校验长度包括头和数据部分
unsigned short udp_chksum(void *data_ip,int udp_len)   //udp_len = UDP首部+数据
{
udp_psd_header * pudp_psd_header;
pudp_psd_header = (udp_psd_header *)malloc(udp_len+sizeof(udp_psd_header));
if(!pudp_psd_header) 
return -1;
memset(pudp_psd_header,0,udp_len+sizeof(udp_psd_header));
//封装伪首部
pudp_psd_header->s_addr= ((struct ip *)data_ip)->ip_src;
pudp_psd_header->d_addr= ((struct ip *)data_ip)->ip_dst;
pudp_psd_header->mbz=0;
pudp_psd_header->ptcl=IPPROTO_UDP;
pudp_psd_header->plen=htons(udp_len);

memcpy((unsigned char *)pudp_psd_header+sizeof(udp_psd_header),(unsigned char *)data_ip+sizeof(struct ip),udp_len);
return check_sum((unsigned short *)pudp_psd_header,udp_len+sizeof(udp_psd_header));

}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值