翻譯惹的禍: IP、ICMP、TCP和UDP包的校驗和的那些事

1、網絡協議校驗和定義

RFC 1071中說到校驗和的定義:html

(1) Adjacent octets to be checksummed are paired to form 16-bit integers, and the 1's complement sum of these 16-bit integers is formed.
(2) To generate a checksum, the checksum field itself is cleared, the 16-bit 1's complement sum is computed over the octets concerned, and the 1's complement of this sum is placed in the checksum field.
(3) To check a checksum, the 1's complement sum is computed over the same set of octets, including the checksum field. If the result is all 1 bits (-0 in 1's complement arithmetic), the check succeeds.

IP校驗和是報頭中全部16位字的補碼之和的16個位的補碼。
許多人可能會問的一個問題是「1的補碼和是多少?」。這是由於全部計算機都使用‘2的補碼’表示,而不使用‘1的補碼’。如下簡要介紹。網絡

那麼什麼是 1的補碼(ones's complement sum)、什麼是2的補碼(two's complement sum):this

1.1什麼是1的補碼(反碼、ones's complement sum、1's complement sum)

1的補碼(ones's complement sum): 也稱爲反碼。之因此稱爲「反碼」,是由於反碼錶示的負數,在形式上能夠看作對其所對應正數(其相反數)的「按位求反」(將全部0換爲1,1換爲0),例如,十進制數6,用8位二進制數表示爲00000110,則-6表示爲11111001。
2.pngspa

這一名稱十分直觀地體現了反碼的外貌,通俗易懂。可是「1的補碼」這個名字就有點讓人摸不着頭腦了,徹底不明白是什麼意思。其實,這是翻譯的鍋。 反碼的英文叫作 Ones' complement (注意不是 One's complement),意即「(複數個)一的補」。因爲漢語中名詞不能經過詞形變化來體現單複數,咱們沒法經過譯名來體會這個名字的含義。仍取上面的例子,咱們將反碼的+6與-6按二進制加法相加,發現獲得了「一串一」。
1.png.net

仔細想一想能夠發現,任意一對相反數的反碼的「和」都是一串一,因此咱們能夠這樣定義負數N的n位二進制反碼:
3.png
這即是反碼叫作「(複數個)一的補」的緣由。翻譯

1.2什麼是2的補碼(反碼、two's complement sum、2's complement sum)

而後你是否是覺得「二的補」就是這樣:
4.png3d

並不!二進制數中不會出現「2」。事實上,「2的補碼」,英文是 Two's complement (而不是Twos' complement),因此它是「(一個)2的補碼」,與「1的補碼」其實不是同一個意思。負數的補碼的定義以下:
5.png
這裏的「two」就是指上式中的「2」。code

總結:orm

「1的補碼」是指「以一串一爲模求補」
  「2的補碼」是指「以二的n次冪爲模求補」

1.3舉個栗子

2的補碼定點整數(8-bit)

Binary Decimal Hex
00000000 0 00
00000001 1 01
00000010 2 02
00000011 3 03
11111111 -1 FF
11111110 -2 FE
11111101 -3 FD

兩個整數相加:
-3 + 5 = 2
FD + 05 = 01 02
丟棄進位(01)會獲得正確的結果。htm

1的補碼定點整數(8-bit)

Binary Decimal Hex
00000000 0 00
00000001 1 01
00000010 2 02
00000011 3 03
11111111 -0 FF
11111110 -1 FE
11111101 -2 FD
11111100 -3 FC

一樣的兩個數相加:
-3 + 5 = 2
FC + 05 = 01 01
將進位(01)相加到低位(01)會獲得正確的結果:
01 + 01 = 02

所以,1的補碼和是經過對數字求和並在結果中加上一個或多個進位來完成的。

一個簡單的例子

假設咱們有一個使用2的補碼的8位機器而且發送一個數據包:
FE 05 00
00是校驗和字段。

讓咱們計算和校驗網絡校驗和,這個普通的相加獲得的結果:
FE + 05  =  01 03

1的補碼和要求將進位(01)加到結果裏:
03 + 01 = 04 

因此FE + 05的1的補碼和是04。

1的補碼的1的補碼和就是:
~04  = FB

數據包將會是:
FE 05 FB 

如今,在接收端咱們將收到的字節相加,包括校驗和:
FE + 05 + FB  = 01 FE 

這1的補碼和是:
FE + 01 = FF = -0 

校驗和爲-0說明是ok的。

另外一個複雜一點的例子(32位機器):

僞數據包:
01 00 F2 03 F4 F5 F6 F7 00 00
(00 00 是校驗和字段)

按16位分組:
0100 F203 F4F5 F6F7

計算求和:
0100 + F203 + F4F5 + F6F7 = 0002 DEEF (值存在32位內存)

將進位(0002)加到結果裏,獲得1的補碼和:
DEEF + 002 = DEF1

計算1的補碼和的1的補碼(Calculate 1's complement of the 1's complement sum):
~DEF1 = 210E

包含校驗和(21 0E)的數據包:
01 00 F2 03 F4 F5 F6 F7 21 0E

在接收端:
0100 + F203 + F4F5 + F6F7 + 210E = 0002 FFFD
FFFD + 0002 = FFFF

校驗結果爲FFFF,說明校驗經過。

1.4總結

在2的補碼機上使用1的補碼加法可能看起來很籠統。可是,這種方法有其自身的優勢。
可能最重要的是它是字節序獨立的。小端字節序計算機將LSB(Least Significant Bit--最低有效位)放在最後(例如Intel處理器)。 大端字節序計算機將LSB放在首位(例如IBM大型機)。當將進位加到LSB上以造成1的補碼和時(請參見示例),咱們加03 + 01仍是01 + 03都不要緊。結果是相同的。

一、LSB(Least Significant Bit)--最低有效位
LSB表明二進制中最小的單位,能夠用來指示數字很小的變化。也就是說,LSB是一個二進制數字中的第0位(即最低位),具備權值爲2^0,能夠用來檢測數的奇偶性。
二、MSB(Most Significant Bit)--最高有效位
MSB表明一個n位二進制數字中的n-1位,具備最高的權值2^(n-1).對於有符號的二進制數,負數採用反碼或補碼形式,此時MSB用來表示符號,msb爲1表示負數,0表示正數。

其餘好處包括易於檢查傳輸和校驗和計算,以及經過僅更新已更改的IP協議的字段來加快計算速度的多種方法。

2、ICMP協議與校驗和

2.1 ICMP協議

wiki對ICMP協議的介紹

3、ICMP實現[rust版本]

未完待續

參考:
一、《Short description of the Internet checksum》
二、《反碼,補碼爲何又叫「一的補」,「二的補」?》
三、RFC 1071四、

相關文章
相關標籤/搜索