摘要

  • RFC 7112 规定,Fragment Offset 为零的 IPv6 首片必须包含从 IPv6 基础头直至首个上层协议头的完整头链。无状态过滤器因此可以先看见协议类型和可用的端口字段,再执行本地规则。
  • “首片完整”不等于“数据报完整”。源端如何构造、路径 MTU、中间设备配置、目的主机处理、ICMPv6 Type 4 Code 3、后续 offset、重叠与超时、重组和应用结果都必须分别留证。

地址到了,端口没有到

IPv6 的扩展头按 Next Header 串成一条链。基础头后可以接多个扩展头,最后才轮到 TCP、UDP 或 ICMPv6。目的主机可以等待所有分片后再重组,但路径中的无状态防火墙通常逐包处理,不愿为每个数据报建立重组状态。

问题出现在切点落在上层协议头之前。首片告诉防火墙源地址、目的地址和分片标识,却没带来 TCP 端口。若设备放行,它可能把本应拒绝的流量送往下一跳;若一律丢弃,又可能误伤本应允许的流量。规则本身没有消失,规则所需的证据被拆到另一片去了。

RFC 7112 没有把所有中间节点改造成重组器,而是约束产生分片的主机:一旦分片,首片必须装下整条 IPv6 头链。这样,发送者在要求下一台机器决定之前,先把“这是什么协议”交代清楚。

这是一条很薄的共同规则。它不规定网络必须开放哪个端口,也不授权某个标准组织替运营商制定策略。它只保证执行本地策略时,关键协议边界不会故意或意外藏在后片。

“完整”的终点不是应用数据

RFC 对头链终点有精确定义。起点是最初的 IPv6 头,随后是零个或多个 IPv6 扩展头。遇到第一个不属于 IPv6 头或扩展头的上层协议头,链条结束;如果没有后续协议,No Next Header 也可终止。IPv6 套 IPv6 时,第二个 IPv6 头在此定义下被视为上层协议头;ESP 也成为终点。

上层载荷不属于头链。TCP 头必须在首片,TCP 后面的应用数据不必。也就是说,RFC 7112 没有禁止大载荷,更没有要求第一片装下整次会话。它只是把分片切点推到一个能够识别协议的边界之后。

这也限定了安全含义。端口可见,可以支持一条端口 ACL;应用正文尚未可见,不能据此宣称深度内容检查完成。头链符合规范,不会证明源地址真实,不会证明发送者获得授权,也不会证明后片无害。

“证据足以回答这一问”与“证据足以回答所有问题”之间,正是这项机制最重要的边界。

偏移为零只说明位置

RFC 7112 把首片定义为 Fragment Offset 等于零的 IPv6 分片。这个条件可以由任何接收设备自行读取,无需查询中央登记,也无需等待重组。

但 offset 不是身份。恶意程序同样能生成 offset 为零且头链完整的首片。可见的 IPv6 源地址也不是密码学证明。一台设备只能说:“我看到的这一片从原数据报的可分片部分起点开始,并且已经沿头链走到某个上层协议。”

策略仍归本地。甲网络可以允许该端口,乙网络可以拒绝。一个中间设备可以启用不完整首片丢弃,另一个可能为了旧实现打开兼容模式。目的主机还会独立处理它收到的分片。

因此,首片完整性适合放在最小共同层:数据包结构提供确定条件,各参与者本地验证,各自承担处理结果。文档作者、IETF 与设备厂商都不能仅凭发布或标签接管运营商的判断。

三种规范动词,三条责任线

源端、中间系统和目的主机在 RFC 中承担的义务并不相同。

产生分片的主机“必须”把完整头链放进首片。这是构造侧的硬条件。若首片不符合,接收主机“应当”丢弃,并在符合 ICMPv6 通用规则的前提下“应当”向源地址发送错误。为了向后兼容,实现“可以”提供接受此类分片的选项。

路由器或防火墙等中间系统则“可以”丢弃,也“可以”发送错误;具备该能力时,“应当”支持是否丢弃的配置。把所有设备描述成无条件强制丢弃,会抹掉原文为兼容和本地策略保留的空间。

规范动词必须进入事件记录。报告不能只写“RFC 7112 拦截”。它要说明哪台设备、哪一接口、哪一软件版本、哪一规则修订、是否开启兼容选项、是否产生 ICMPv6,以及目的端最终有没有看见首片。

只有这样,规范才是可复核的行为边界,而不是模糊的权威名义。

Code 3 是诊断回执,不是全网保证

当主机或中间系统因头链不完整而丢弃首片,并决定发送错误时,RFC 7112 指定 ICMPv6 Parameter Problem:Type 4、Code 3,Pointer 为零。IANA 为它登记的含义就是 IPv6 首片含有不完整头链。

专用错误码给排障提供了抓手。源端开发者能针对引用的数据包复现。网络团队可以把 Code 3 增长与系统升级、隧道变更或新扩展头组合对应。安全团队可以比较返回报文、丢弃计数器与两侧抓包。

不过,没有 Code 3 不代表全路径都接受了数据包。中间系统没有必须发送,ICMPv6 规则可能限制生成,限速和返程过滤也可能让回执消失。源地址伪造还可能把错误送给第三方。

看到 Code 3 也不能自动定位设备。有效回执至少要带时间、抓包点、引用包、接口、规则版本和本地计数器。错误码给原因命名,证据链才给行为署名。

一张合格的运行回执

首片事件至少要保留八组字段。

第一组是线上的包形:源、目的、分片标识、offset、M 位、Next Header 顺序、实际抵达的首个上层协议头和头链长度。第二组是抓包位置,因为封装和解封装会改变不同位置看到的结构。

第三组是路径 MTU。RFC 7112 要求头链长度不能超过到目的地的路径 MTU;若主机没有发现路径 MTU,就必须把头链限制在 1280 字节以内。隧道降低有效 MTU、源端缓存过期或异常长的扩展头,都可能使原先正常的构造变成违规。

第四组是构造源:操作系统、网络栈、应用或封装器版本。第五组是处理设备:型号、接口、解析器版本、规则修订、兼容模式和 verdict。第六组是 Code 3 的生成、限速、过滤和接收状态。

第七组属于重组:后续分片的 offset、长度、重复、重叠、到达顺序和超时。第八组才是服务:TCP 是否建立、应用是否完成、重传是否改变了分包方式。

把八组压成一个“IPv6 fragment blocked”字段,等于主动删除因果关系。标准提供了可分开的状态,运营系统必须有能力把它们留住。

首片准入与目的端重组是两台机器

RFC 8200 取代 RFC 2460 后,把 RFC 7112 的规则纳入 IPv6 基础规范。它把原数据报拆成不同部分:每片都带的头、Fragment 头、必须在首片出现的后续扩展头与上层协议头,以及实际分片数据。

首片验证只看入口条件。目的端重组还要依据源地址、目的地址与分片标识把分片归组,再用 offset 和长度恢复位置。缺片超过 60 秒,重组放弃;长度不合法会触发相应错误;重叠出现时,整个数据报都必须丢弃;精确重复片可以单独识别并舍弃。

所以,首片合规并不保证最后一片到达,也不保证无重叠或最终服务成功。反过来,防火墙丢弃首片后仍可能转发后片;没有 offset 为零的那片,目的端无法完成原数据报,策略仍可能已经生效。

运营语言需要分三句:“首片通过头链检查”“重组成功”“应用完成”。其中一句成立,另外两句都可能不成立。

原子分片不是“小号首片”

Fernando Gont 独立撰写的 RFC 6946 处理另一种状态:原子分片。它带有 Fragment 头,但 offset 和 M 位都为零,整个数据报无需等待任何其他片。

一些旧实现仍把原子分片放进重组队列,与源、目的和分片标识相同的其他片混合。攻击者可利用这种不必要的混合干扰合法数据。RFC 6946 要求原子分片独立处理,RFC 8200 继承了这一规则。

这与 RFC 7112 不能互换。头链不完整的首片、已经完整的原子分片、互相重叠的多片,是三个不同状态。日志若只留下“含 Fragment 头”,就无法知道修复应落在构造、独立处理还是重组冲突。

协议字段本来足以区分。丢失区分的往往不是线上的包,而是过度归一化的遥测。

从补丁进入基础规范

RFC 7112 于 2014 年更新 RFC 2460。2017 年发布的 RFC 8200 废止旧规范,并明确要求 Fragment 头之后的扩展头和上层协议头必须在首片;若首片未覆盖至上层协议头,应当丢弃并发送 Code 3。

RFC 9099 又把它变成面向运营的安全建议:防火墙、安全设备和目的节点应丢弃没有包含完整头链(包括传输层头)的首片,否则无状态过滤可能被绕过。

文档沿革证明共同规范发生了变化,却不能证明部署在某个机房里的设备已经变化。旧兼容开关、ASIC 解析深度、异常扩展头顺序、不同的 ICMPv6 行为,都需要实测。

合格的采用证据来自构造测试包、两侧抓包、计数器、版本化配置和真实服务结果。RFC 定义测试向量,运行代码填写结果。

Fernando Gont 的有界贡献

RFC 7112 的三位作者是 Fernando Gont、Vishwas Manral 和 Ron Bonica。Standards Track 身份来自 IETF 的公开审查与共识,不能改写成任何个人的独占发明,也不会让作者拥有全网实施权。

选择 Gont 作为人物线索,依据是连续的方法,而不是权威崇拜。RFC 6946 把不应进入重组队列的原子分片单独分离;RFC 7112 让首片在被判断前展示必要协议边界。IETF 当前资料列出他参与的 40 份 RFC,并记录其协议安全研究背景。

这两项分片工作都在做同一类整理:把实现曾经混在一起的状态拆开,交给运行系统一个本地可验证的条件。标准只规定共同边界,设备负责执行,目的端负责重组,应用负责证明服务是否完成。

首片不用讲完整个故事。它只需诚实地介绍下一个协议,让下一台机器明确自己正在回答哪一个问题。

来源