摘要
- IP 头部某个字段变化时,RFC 1141 给出直接调整已存校验和的快捷公式,常见场景是路由器递减 TTL。
- RFC 1624 在 1994 年证明,公式遇到一的补码的双重零,会写出
0xFFFF;完整重算却是0x0000。修正公式保留了正确位型。
每经过一台路由器,IP 数据包的 TTL 通常要减一。头部跟着变,校验和也必须跟着改。倘若每次都把整段头部重新相加,机器会替许多根本没变的字节重复劳动。看起来最像正经工程的办法,就是从旧校验和扣掉旧值、加上新值。这个办法遇上零的时候,却发现零还有一个孪生兄弟。
1988 年 9 月的 RFC 1071梳理了互联网校验和的算法。它把相邻字节组成 16 位字,按一的补码规则求和,再将和取反写进校验和字段。验证时,把这个字段一并求和,结果为全 1 即通过。文档还讨论怎样让计算更快:并行求和、延后处理进位、利用不同字节序,甚至与内存复制合并。头部仅改动一个字段时,它也提出增量更新思路。
1990 年 1 月的 RFC 1141把这条思路写成可直接作用于头部现有校验和的公式。以 TTL 递减为例,如果它处于对应 16 位字的高字节,校验和字段可以加上 0x100。省力的理由很直白:同一数据包在转发路径上多次改 TTL,没必要反复扫描没有变化的部分。
问题并非一的补码算错了加法,而是人们习惯把两个零当成同一串位。在这种算术里,0x0000 是正零,0xFFFF 是负零;含义相似,位型相反。1994 年 5 月的 RFC 1624指出,RFC 1141 化简公式时假定了在零的边界并不成立的分配律。捷径会写下错误的那一个零。
RFC 1624 没让读者凭感觉相信它。例子中,头部某个 16 位字段从 0x5555 变成 0x3285,其余字段的和为 0xCD7A,旧校验和为 0xDD2F。完整重算后,新校验和字段应为 0x0000;按照 RFC 1141 捷径操作,却得到 0xFFFF。改正后的等式 HC' = ~(~HC + ~m + m') 则给出 0x0000。这里争论的是存进 IP 头部的具体位串,不是纸上写出的抽象数值。
接收方怎样检查,决定错误是否会浮出水面。按 RFC 1071 的方式,把整个头部连同校验和一起求和,再看是否全 1,在上述例子里两个版本都会通过。若接收方自己重算校验和字段,并拿重算出的位型与包里字段逐位比较,0xFFFF 就可能遭拒。一边的快捷更新与另一边的验收程序,合起来才构成真实的互通结果。
RFC 1624 还交代了发现经过:测试一个采用 RFC 1141 算法的产品时,边界条件冒了出来;修正算法又经模拟核验。文档没有给那个产品署名,也没有给影响规模造一个数字。它给的是更可用的证据链:一次测试、一组可复算的数、一个被推翻的化简步骤和新公式。担心额外指令成本的人,还能使用文档列出的带借位减法形式。
增量校验和并未因此失去价值。它只是必须认真对待最后写进数据包的每一位。路由器追求少算几步,接收端要判断眼前的位串;当零有两个版本时,少算的那一步就得格外精确。
会员简报
档案背景详情
使用相应会员等级登录,即可解锁完整简报与来源注释。
仅限 Strategic Circle
Strategic Circle
所有读者均可浏览。加入并登录后可解锁档案简报。
加入 Strategic Circle仅限 Leadership Alliance
Leadership Alliance
符合条件的 IP 资产所有者和管理层可登录查看 Leadership Alliance 简报。
加入 Leadership Alliance





