2009-09-26 313 views
18

在/usr/include/netinet/udp.h定義的UDP報頭結構是如下UDP校驗和計算

struct udphdr 
{ 
    u_int16_t source; 
    u_int16_t dest; 
    u_int16_t len; 
    u_int16_t check; 
}; 

什麼值被存儲在所述報頭的校驗字段?如何驗證校驗和是否正確?我的意思是校驗和計算的數據是什麼? (它只是udp頭或udp頭加上後面的有效載荷?)

謝謝。

回答

27

的UDP校驗和在整個有效載荷進行,在報頭中的其他字段,從IP報頭的某些字段。爲了執行計算(通過這個僞報頭,UDP報頭和有效載荷完成),從IP報頭構造僞報頭。包含僞頭的原因是要捕獲已路由到錯誤IP地址的數據包。

基本上,在接收端,標題加上數據區的所有16位字被加在一起(包裝在16位)並且結果與0xffff對照。

在發送方面,它稍微複雜一些。對所有16位值執行1的補碼和,然後用補碼(即,反轉所有位)取該值來填充校驗和字段(附加條件是計算的零校驗和將被改變爲全部一個位)。

1的補數是而不是只是所有補碼值的總和。這有點複雜。

基本上,您有一個從零開始的運行16位累加器,並且您將每個16位值添加到該位。每當這些添加中的一個導致進位時,該值將被纏繞,並且再次爲該值添加一個值。這有效地採用16位加法的進位並將其添加到該值。


順便說一句,這是我的一部分純粹是主觀臆測,但這很可能通過使用ADC來高效地完成(進位加)指令,而不是ADD(令人驚訝的是,添加),或無論您在當時的CPU上有何等效的指令。

如果沒有進位,ADC只會增加進位的零位。在完成這些工作的時代(不幸的是,我認爲這是舊的),內存與速度相比,更多地是一個制約因素,而不是現在的情況,因此在代碼中保存幾個字節可能會提升你到半神皇帝的最宇宙的:-)


注意的水平,你從來沒有擔心隨身攜帶的第二次(或兩個與下進ADC如果您使用前一段中提到的方法),因爲兩個最大的16位值在求和時產生(從0x1fffe截取)0xfffe - 向其中添加一個永遠不會導致另一個進位。

一旦計算出的補碼和被計算出來後,它的位反轉並插入到數據包中,這將導致接收端的計算產生0xffff,假設傳輸過程中沒有錯誤。

值得注意的是,有效負載總是被填充以確保有16位字的整數。如果它填充了,則長度字段會告訴您實際的長度。

RFC768是詳細說明這一點的規範。

+0

謝謝你。我對Pseudo-Header部分有些困惑......但是RFC清除了空氣。 「 – Deepak 2009-09-26 07:03:48

+1

」所有標題的16位字(其中UDP校驗和爲零)被添加,並且補碼(即,反轉所有位)被放入校驗和字段中。「不,RFC說什麼會導致「所有人的頭補充(即反轉所有比特)的頭(UDP校驗和爲零)的16位字被添加,並且這個補碼是什麼得到了進入校驗和字段「。 否則完美答案+1。 – Joren 2009-09-26 07:17:57

+1

這是不對的。 「補數和」並不意味着取每個詞的補碼並將它們加在一起。這意味着你將這些單詞加在一起,並且當一個進位位被產生時,你給運行總和加1。參見http://mathforum.org/library/drmath/view/54379.html。 – 2010-04-22 15:51:03

1

一個很好的和容易理解的例子UDP校驗和計算是由格爾德·霍夫曼做。

您可以谷歌「網checksum.c格爾德·霍夫曼」 或看這裏的文件:

https://gist.github.com/fxlv/81209bbd150abfeaceb1f85ff076c9f3

可以使用net_checksum_tcpudp功能,給它的UDP有效載荷長度,原,SRC和dst IP,然後是UDP有效載荷本身,它會做正確的事情。

最後你必須在校驗碼上撥打htons(),你很好。