Nic*_*ady 3 haskell checksum icmp
我正在努力理解为什么ICMP校验和总数(在补码之前)是此代码行中的总数+向右移16位:
checksum bs = let bs' = (if (BL.length bs) `mod` 2 == 0 then bs else BL.snoc bs 0)
ws = runGet listOfWord16 bs'
total = sum (map fromIntegral ws) :: Word32
in complement (fromIntegral total + fromIntegral (total `shiftR` 16))
Run Code Online (Sandbox Code Playgroud)
RFC 792关于计算校验和的说法是这样的:
校验和
校验和是ICMP消息以ICMP类型开头的补码和的16位补码。为了计算校验和,校验和字段应为零。如果总长度为奇数,则用零的一个八位位组填充接收到的数据以计算校验和。将来可能会替换此校验和。
我理解为什么bs'要按照“如果总长度为奇数,则将接收到的数据填充一个零的八位位组以计算校验和”的要求进行计算。
我也可以理解将本行代码中完成的16位字的总和 total = sum (map fromIntegral ws) :: Word32
我只是不知道为什么在这行代码中:
complement (fromIntegral total + fromIntegral (total `shiftR` 16))
Run Code Online (Sandbox Code Playgroud)
这+ fromIntegral (total `shiftR` 16)应该包括在所有。
注意:我已经用wireshark验证了校验和是正确的,仅当我total + total `shiftR` 16对链接的代码行中的进行补充时才正确。所以我知道这是正确的,我只是不明白为什么。
RFC 1071详细描述了校验和定义,包括以下重要部分:
在2的补码机上,必须通过“结束进位”来计算1的补码和,即,将最高有效位的任何溢出都加到最低有效位中。
在您的代码中
total = sum (map fromIntegral ws) :: Word32
Run Code Online (Sandbox Code Playgroud)
是32位和,即其低16位是不带进位的和,高16位将包含进位之和。通过使用fromIntegral :: Word32 -> Word16截断的事实,我们可以
low = fromIntegral total :: Word16
high = fromIntegral $ total `shiftR` 16 :: Word16
Run Code Online (Sandbox Code Playgroud)
这样我们就可以计算出
eac = low + high
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
130 次 |
| 最近记录: |