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));

}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章