摘要
- 迟到的确认可能让 TFTP 两端都重发当前数据包,使一条旧 ACK 带出后续块的重复流量。
- RFC 1123 要求 DATA 发送方收到重复 ACK 时不得重发当前块;风险是拥塞可能使传输超时,而不是已完成文件被改坏。
只保留一个待确认的数据块
1981 年 6 月,Karen Sollins 发布了《简单文件传输协议》的第二版。这里的“简单”指接口刻意克制:远端文件可以读取或写入,但协议本身不列目录,也不提供用户认证。数据按 512 字节分块,每个非末尾块都要先收到确认,发送方才能继续。因此发送方只需留住当前一个包用于重传。停等机制也提供了流量控制,并省去了重新排序数据块的需要。
这对还没有加载完整操作系统的主机很重要。1989 年 RFC 1123 说,TFTP 最重要的用途是通过本地网络引导主机,因为它足够小,可以放进 EPROM。BOOTP 可以先交付地址等配置,随后由 TFTP 搬运系统映像;二者处理的是启动流程里相邻但不同的任务。文件传输仍要面对确认和计时器。
TFTP 运行在 UDP 上,因此可靠传输由应用协议自己负责。如果期望的响应没有在超时前到达,发送方可以重发正在等待的包。包丢失时,这条规则看似直接;包只是延迟时,局面就不同了。
一条旧 ACK 如何制造新的重复包
假设主机 A 收到 ACK X−1 后发送 DATA X。主机 B 收到它并回复 ACK X,但确认包在网络里迟到了。A 的计时器先到期,于是又发送一次 DATA X。B 已经接收过这一块,识别出重复包后,再发一次 ACK X。随后第一条迟到的 ACK X 到达,A 以为这一块已确认,便发送 DATA X+1。接着第二条 ACK X 到达。按原先规则,A 对这条旧确认的响应不是忽略它,而是重发自己当前正在发送的包:DATA X+1。
B 随后收到两份 X+1,并各自回应 ACK X+1。如果其中一份旧确认在 A 已经转到 DATA X+2 后才到达,它还能促使 A 再重发当前块。旧包触发的不是对旧状态的简单回放,而是按照双方此刻状态生成的新响应。一个重复包于是能在另一端引出新的重复包。
Robert Braden 在 RFC 1123 中将它命名为“魔法师学徒综合征”。文中的步骤表明,之后的包都可能成对传输,直到某个数据报丢失才打断这种重复。它不等于文件内容必然出错。RFC 1123 明确说,传输若能完成,文件仍然正确;问题在于大量重发会耗掉时间和链路容量,让传输在完成前超时。
所以“可靠”并不意味着“不会受时延影响”。块编号能标明某条确认指向哪一块,却不能保证对旧块的所有响应都无害。DATA 的发送方与 ACK 的发送方都可能对重复包重发自己的当前包。单看一端,这似乎是在积极恢复;两端合在一起却构成反馈循环。
时延反过来加重拥塞
1989 年的主机要求文件把这条路径说清楚:一次超时可能已经触发 DATA 重发,而迟到的 ACK 随后又抵达。重复 DATA 产生新的 ACK。若先前的确认在发送方推进之后才到,发送方会重复新的块,接收方又产生更多确认。若没有丢包打断,后续块也会持续重复。
拥塞既可能启动这个循环,也可能被它加重。繁忙路径让 ACK 延迟到足以触发重传;重复的 DATA 和 ACK 随后占用更多容量,又增加新的延迟机会。RFC 1123 指出,这会带来更多拥塞和延迟。它并没有说所有慢速 TFTP 都会触发漏洞,也没有把某次历史网络故障归咎于它;它描述的是协议层的正反馈机制。
RFC 1123 还把这个缺陷与普通计时策略区分开。它要求使用自适应超时,建议至少采用指数退避。更好的计时值可以容忍时延变化,却无法取消“旧 ACK 能让发送方重发当前 DATA”这条行为规则。修复必须改变收到重复确认时的响应。
在正式修订前,先加一条规则
RFC 1123 把修复写成 MUST:DATA 发送方收到重复 ACK 时,绝不能重发当前 DATA。停止这一响应后,重复 ACK 不再引出下一份重复 DATA,循环便无法继续向后传播。接收端的 ACK 重发计时器也可以移除,因为再次发 ACK 不会触发动作;但若重复 ACK 可以替代真正丢失的确认,它也可以保留。DATA 发送方仍然需要重传计时器。
对于要运行在启动程序中的协议,这还可能简化接收端。修复不需要更大的窗口、不需要改变 512 字节分块,也不要求抛弃 UDP。它只切断危险的反馈路径,保留单包内存模型。
1992 年 7 月,RFC 1350 取代 RFC 783,并成为 STD 33。它的致谢说明,Noel Chiappa 在 1992 年 5 月的修订中修复了魔法师学徒漏洞。时间关系应准确表达:RFC 1123 早在 1989 年已规定实现必须遵守的行为;1992 年文档又把修复写入 TFTP 的新版本。后来的 RFC 日期不能证明所有实现直到 1992 年都存在缺陷,也不能证明所有实现都在 1989 年完成更新。
后续 TFTP 扩展处理的是另一条边界。1998 年的块大小选项,以及后来的超时和传输大小协商,让停等模型不再那么限制吞吐;2015 年的窗口选项还允许多个块同时在途。这些不是重复 ACK 的修复。扩大传输能力,与阻止旧确认复制当前流量,是两种不同的变化。
TFTP 的历史说明,极简设计会把复杂性从包格式转移到状态转换上。一次只保持一块活动,减少了内存与实现工作;但时延让两台主机对“当前包”的理解错开。修复也同样小:不要让重复 ACK 命令 DATA 发送方重发它现在正在发送的块。可靠性不仅是知道何时重试,也包括知道什么时候不该再试。
来源
- RFC 783 — The TFTP Protocol (Revision 2), 1981
- RFC 1123 — Requirements for Internet Hosts, 1989, §§4.2.1–4.2.3
- RFC 1350 — The TFTP Protocol (Revision 2), 1992
- RFC 768 — User Datagram Protocol
- RFC 951 — Bootstrap Protocol
- RFC 1542 — BOOTP Clarifications and Extensions
- RFC 2347 — TFTP Option Extension
- RFC 2348 — TFTP Blocksize Option
- RFC 2349 — TFTP Timeout and Transfer Size Options
- RFC 7440 — TFTP Windowsize Option
会员简报
档案背景详情
使用相应会员等级登录,即可解锁完整简报与来源注释。
仅限 Strategic Circle
Strategic Circle
所有读者均可浏览。加入并登录后可解锁档案简报。
加入 Strategic Circle仅限 Leadership Alliance
Leadership Alliance
符合条件的 IP 资产所有者和管理层可登录查看 Leadership Alliance 简报。
加入 Leadership Alliance
