IP校驗和詳解
IP校驗和詳解
一、校驗和演算法
之前一直只知道IP校驗和演算法反碼求和相關的,但具體細節不清楚,今天瞭解了下。
IP校驗和主要是用來保證資料(IP包頭)的完整性的.它用的演算法非常簡單,就是反碼求和校驗.需要注意的是反碼求和又叫1的補碼(one'scomplement),而2的補碼就是我們通常說的補碼求和了.校驗演算法具體如下.
1、傳送方
i)將校驗和欄位置為0,然後將IP包頭按16位元分成多個單元,如包頭長度不是16位元的倍數,則用0位元填充到16位元的倍數;
ii)對各個單元採用反碼加法運算(即高位溢位位會加到低位,通常的補碼運算是直接丟掉溢位的高位),將得到的和的反碼填入校驗和欄位;
iii)傳送資料包.
2、接收方
i)將IP包頭按16位元分成多個單元,如包頭長度不是16位元的倍數,則用0位元填充到16位元的倍數;
ii)對各個單元採用反碼加法運算,檢查得到的和是否符合是全1(有的實現可能對得到的和會取反碼,然後判斷最終值是不是全0);
iii)如果是全1則進行下步處理,否則意味著包已變化從而丟棄之.
需要強調的是反碼和是採用高位溢位加到低位的,如3位元的反碼和運算:100b+101b=010b(因為100b+101b=1001b,高位溢位1,其應該加到低位,即001b+1b(高位溢位位)=010b),具體細節請參考文章:http://blog.chinaunix.net/u/20/showart_438418.html
二、校驗和原始碼
網上流傳多組實現,常見的有如下兩種(如追求效率可改寫為彙編程式碼):
1、RFC1071原始碼
unsigned short csum(unsigned char *addr, int count)
{
/* Compute Internet Checksum for "count" bytes
* beginning at location "addr".
*/
register long sum = 0;
while( count > 1 )
{
/* This is the inner loop */
sum += * (unsigned short) addr++;
count -= 2;
}
/* Add left-over byte, if any */
if( count > 0 )
sum += * (unsigned char *) addr;
/* Fold 32-bit sum to 16 bits */
while (sum>>16)
sum = (sum & 0xffff) + (sum >> 16);
return ~sum;
}
第一個while迴圈是做普通加法(2進位制補碼加法),因為IP包頭和TCP整個報文段比較短(沒達到2^17數量級),所以不可能導致4位元組的sum溢位(unsigned long 一般至少為4位元組)).
緊接著的一個判斷語句是為了能處理輸入資料是奇數個位元組的這種情況.
再接著的資料迴圈是實現反碼演算法(在前面的普通加法得到的資料的基礎上),由反碼和的高位溢位加到低位的性質,可得到"32位的資料的高位位元移位16位元,再加上原來的低16位元,不影響最終結果" 這個等價運算,因為sum的最初值(剛開始迴圈時)可能很大,所以這個等價運算需迴圈進行,直到sum的高位元(16位元以上)全為0.對於32位的 sum,事實上這個運算迴圈至多隻有兩輪,所以也有程式直接用兩條"sum = (sum & 0xffff) + (sum >> 16);"代替了整個迴圈.
最後,對和取反返回.
2、對資料長度沒限制的實現
unsigned short cksum (struct ip *ip, int len)
{
long sum = 0; /* assume 32 bit long, 16 bit short */
while ( len >1 )
{
sum += *((unsigned short *) ip)++;
if (sum & 8x00000000) /* if high-order bit set, fold */
sum = (sum & 0xFFFF) + (sum>> 16) ;
len -= 2;
}
if ( len ) /* take care of left over byte */
sum += ( unsigned short ) * (unsignedl char *) ip;
while ( sum >> 16)
sum =(sum & 0xFFFF) + (sum>> 16);
return ~sum;
}
這個實現與前面的一個的最大的不同是對資料的長度沒什麼限制了,因為它在第一個迴圈的加法運算中實時檢測sum的高位的值,一旦發現其有溢位的危險,就及時運用等價運算關係消除了這個危險.
三、幾個細節問題
1、資料部分改變時的重校驗
考慮這樣的應用場景:路由器轉發IP報文時,有可能只更改了IP資料包頭的部分內容(如更改了TTL,分片了或SNAT更改了源IP等~~~),卻需要重校驗的問題.為提高轉發效率,要求重校驗演算法儘可能快,故出現瞭如下所示的重校驗演算法(只是一個簡單的示例):
UpdateTTL(struct ip_hdr *ipptr, unsigned char n)
{
unsigned long sum;
unsigned short old;
ld = ntohs(*(unsigned short *)&ipptr->ttl);
ipptr->ttl -= n;
sum = old + (~ntohs(*(unsigned short *)&ipptr->ttl) & 0xffff);
sum += ntohs(ipptr->Checksum);
sum = (sum & 0xffff) + (sum>>16);
ipptr->Checksum = htons(sum + (sum>>16));
}
演算法的實現依據是這樣的.假設包頭原校驗和為~C,改變的欄位的原始值是m,更改後的值是m',設~C'為重校驗和,則有 ~C' = ~(C+(-m)+m') = ~C+(m-m') = ~C+m+~m'
等價關係的成立基於反碼的運算性質:取反運算滿足結合律,按位取反運算與符號取反(及相反數)是等價的(即~C=-C).
如果有多個欄位改變,只是上面的公式中的m和m'有多個而已,直接用反碼加法搞定即可。
2、為什麼採用反碼和運算
IP資料包校驗要求速度快,所以只採用了簡單的和校驗,為什麼採用反碼和而不是補碼和呢?
i)反碼和的溢位有後效性(蔓延性)
反碼和將高位溢位加到低位,導致這個溢位會對後面操作有永久影響,有後效性;而補碼和直接將高位和溢位,導致這個溢位對後面的操作再無影響,因此無後效性
ii)反碼校驗無需考慮位元組序
正因為反碼和的溢位有後效性,導致大端位元組序(big-endian)和小端位元組序(little-endian)對同一資料序列(如兩個16位元的序列)產生的校驗和也只是位元組序相反,而補碼和因為將溢位丟掉了,不同位元組序之間的校驗和大不相同且沒什麼聯絡。
基於以上的理由,校驗和運算既可選擇在資料被轉換成網路位元組序前,也可選擇在之後,只要保證被校驗的欄位和填寫的校驗和欄位的位元組序保持一致就可以了。(這其實可以看作是負負得正,計算校驗和與位元組序有關,然後寫校驗和欄位與位元組序有關,然後直接計算校驗和再寫校驗和欄位則與位元組序無關了~~)
一、校驗和演算法
之前一直只知道IP校驗和演算法反碼求和相關的,但具體細節不清楚,今天瞭解了下。
IP校驗和主要是用來保證資料(IP包頭)的完整性的.它用的演算法非常簡單,就是反碼求和校驗.需要注意的是反碼求和又叫1的補碼(one'scomplement),而2的補碼就是我們通常說的補碼求和了.校驗演算法具體如下.
1、傳送方
i)將校驗和欄位置為0,然後將IP包頭按16位元分成多個單元,如包頭長度不是16位元的倍數,則用0位元填充到16位元的倍數;
ii)對各個單元採用反碼加法運算(即高位溢位位會加到低位,通常的補碼運算是直接丟掉溢位的高位),將得到的和的反碼填入校驗和欄位;
iii)傳送資料包.
2、接收方
i)將IP包頭按16位元分成多個單元,如包頭長度不是16位元的倍數,則用0位元填充到16位元的倍數;
ii)對各個單元採用反碼加法運算,檢查得到的和是否符合是全1(有的實現可能對得到的和會取反碼,然後判斷最終值是不是全0);
iii)如果是全1則進行下步處理,否則意味著包已變化從而丟棄之.
需要強調的是反碼和是採用高位溢位加到低位的,如3位元的反碼和運算:100b+101b=010b(因為100b+101b=1001b,高位溢位1,其應該加到低位,即001b+1b(高位溢位位)=010b),具體細節請參考文章:http://blog.chinaunix.net/u/20/showart_438418.html
二、校驗和原始碼
網上流傳多組實現,常見的有如下兩種(如追求效率可改寫為彙編程式碼):
1、RFC1071原始碼
unsigned short csum(unsigned char *addr, int count)
{
/* Compute Internet Checksum for "count" bytes
* beginning at location "addr".
*/
register long sum = 0;
while( count > 1 )
{
/* This is the inner loop */
sum += * (unsigned short) addr++;
count -= 2;
}
/* Add left-over byte, if any */
if( count > 0 )
sum += * (unsigned char *) addr;
/* Fold 32-bit sum to 16 bits */
while (sum>>16)
sum = (sum & 0xffff) + (sum >> 16);
return ~sum;
}
第一個while迴圈是做普通加法(2進位制補碼加法),因為IP包頭和TCP整個報文段比較短(沒達到2^17數量級),所以不可能導致4位元組的sum溢位(unsigned long 一般至少為4位元組)).
緊接著的一個判斷語句是為了能處理輸入資料是奇數個位元組的這種情況.
再接著的資料迴圈是實現反碼演算法(在前面的普通加法得到的資料的基礎上),由反碼和的高位溢位加到低位的性質,可得到"32位的資料的高位位元移位16位元,再加上原來的低16位元,不影響最終結果" 這個等價運算,因為sum的最初值(剛開始迴圈時)可能很大,所以這個等價運算需迴圈進行,直到sum的高位元(16位元以上)全為0.對於32位的 sum,事實上這個運算迴圈至多隻有兩輪,所以也有程式直接用兩條"sum = (sum & 0xffff) + (sum >> 16);"代替了整個迴圈.
最後,對和取反返回.
2、對資料長度沒限制的實現
unsigned short cksum (struct ip *ip, int len)
{
long sum = 0; /* assume 32 bit long, 16 bit short */
while ( len >1 )
{
sum += *((unsigned short *) ip)++;
if (sum & 8x00000000) /* if high-order bit set, fold */
sum = (sum & 0xFFFF) + (sum>> 16) ;
len -= 2;
}
if ( len ) /* take care of left over byte */
sum += ( unsigned short ) * (unsignedl char *) ip;
while ( sum >> 16)
sum =(sum & 0xFFFF) + (sum>> 16);
return ~sum;
}
這個實現與前面的一個的最大的不同是對資料的長度沒什麼限制了,因為它在第一個迴圈的加法運算中實時檢測sum的高位的值,一旦發現其有溢位的危險,就及時運用等價運算關係消除了這個危險.
三、幾個細節問題
1、資料部分改變時的重校驗
考慮這樣的應用場景:路由器轉發IP報文時,有可能只更改了IP資料包頭的部分內容(如更改了TTL,分片了或SNAT更改了源IP等~~~),卻需要重校驗的問題.為提高轉發效率,要求重校驗演算法儘可能快,故出現瞭如下所示的重校驗演算法(只是一個簡單的示例):
UpdateTTL(struct ip_hdr *ipptr, unsigned char n)
{
unsigned long sum;
unsigned short old;
ld = ntohs(*(unsigned short *)&ipptr->ttl);
ipptr->ttl -= n;
sum = old + (~ntohs(*(unsigned short *)&ipptr->ttl) & 0xffff);
sum += ntohs(ipptr->Checksum);
sum = (sum & 0xffff) + (sum>>16);
ipptr->Checksum = htons(sum + (sum>>16));
}
演算法的實現依據是這樣的.假設包頭原校驗和為~C,改變的欄位的原始值是m,更改後的值是m',設~C'為重校驗和,則有 ~C' = ~(C+(-m)+m') = ~C+(m-m') = ~C+m+~m'
等價關係的成立基於反碼的運算性質:取反運算滿足結合律,按位取反運算與符號取反(及相反數)是等價的(即~C=-C).
如果有多個欄位改變,只是上面的公式中的m和m'有多個而已,直接用反碼加法搞定即可。
2、為什麼採用反碼和運算
IP資料包校驗要求速度快,所以只採用了簡單的和校驗,為什麼採用反碼和而不是補碼和呢?
i)反碼和的溢位有後效性(蔓延性)
反碼和將高位溢位加到低位,導致這個溢位會對後面操作有永久影響,有後效性;而補碼和直接將高位和溢位,導致這個溢位對後面的操作再無影響,因此無後效性
ii)反碼校驗無需考慮位元組序
正因為反碼和的溢位有後效性,導致大端位元組序(big-endian)和小端位元組序(little-endian)對同一資料序列(如兩個16位元的序列)產生的校驗和也只是位元組序相反,而補碼和因為將溢位丟掉了,不同位元組序之間的校驗和大不相同且沒什麼聯絡。
基於以上的理由,校驗和運算既可選擇在資料被轉換成網路位元組序前,也可選擇在之後,只要保證被校驗的欄位和填寫的校驗和欄位的位元組序保持一致就可以了。(這其實可以看作是負負得正,計算校驗和與位元組序有關,然後寫校驗和欄位與位元組序有關,然後直接計算校驗和再寫校驗和欄位則與位元組序無關了~~)
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/25897606/viewspace-704277/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Go IP 段範圍校驗Go
- IP資料包的校驗和演算法_儒雅演算法
- 引數校驗註解
- IP地址詳解
- 校驗和與編號
- SpringBoot分組校驗及自定義校驗註解Spring Boot
- 校驗IP-v6地址正規表示式
- springMVC:校驗框架:多規則校驗,巢狀校驗,分組校驗;ssm整合技術SpringMVC框架巢狀SSM
- haipproxy核心校驗和排程策略AI
- TCP的校驗和與編號TCP
- TCP/IP協議詳解TCP協議
- tcp/ip協議和opc協議對比詳解TCP協議
- SpringBoot中BeanValidation資料校驗與優雅處理詳解Spring BootBean
- Solon詳解(六)- Solon的校驗擴充套件框架使用與擴充套件套件框架
- 校驗IP-v4地址的正規表示式
- SpringBoot自定義校驗註解Spring Boot
- 【TCP/IP】TCP詳解筆記TCP筆記
- IP資料包格式詳解
- IP包頭結構詳解
- Django模型驗證器詳解和原始碼分析Django模型原始碼
- 自定義校驗註解ConstraintValidatorAI
- 行式填報 資料校驗 --- 小計校驗
- vxe-table 校驗,根據行屬性校驗
- IP和TCP抓包分析實驗TCP
- 計算校驗和工具:Checksum Thing MacMac
- tcp 偽頭部 結構 格式 校驗和TCP
- SAP的校驗和替代(validations and substitutions)[轉]
- CRC校驗原理
- 分組校驗
- 資料校驗
- Web頁面子資源完整性校驗詳細指南Web
- JavaScript數字和字母組合驗證碼詳解JavaScript
- 中學校園IP網路廣播系統解決方案-校園數字IP廣播系統方案設計指南
- Springboot mini - Solon詳解(六)- Solon的校驗框架使用、定製與擴充套件Spring Boot框架套件
- VR校園安全解決方案,開啟校園安全教育新體驗!VR
- Oracle驗證方式詳解Oracle
- rpm包的校驗和檔案讀取
- Gin(四):表單提交校驗和模型繫結模型