摘要

  • RIPE NCC 9 月 10 日的一次 Whois 提交,让 NRTMv4 服务通过 NrtmSourceSlaveDao 枚举并校验来源;这个类明确接入 nrtmSlaveDataSource。
  • 通知文件查询本来具有“副本查不到就转主库”的保护,但服务会先在副本目录里把来源名称解析成对象;这一步失败,后面的回退根本没有机会运行。
  • 公开证据只证明代码顺序,不证明这段代码已上线,更不证明发生过延迟或故障。适当的补丁是一张“来源目录准入凭证”,不是取消副本读取。

真正值得关注的,不是“系统用了副本”这件事,而是哪个判断发生在回退之前。

RIPE NCC 的 Whois 代码库在 2026 年 9 月 10 日记录了提交 252681a0865d5a10dbcfeaeeaf81bf33ef2c3855。标题直白:让 NRTMv4 服务使用只读(slave)来源 DAO。提交只涉及三个路径:原有 NrtmSourceDao 增加 @Primary;新增一个 20 行的 NrtmSourceSlaveDao;NrtmService 注入的类型由前者改为后者。

先替这项设计作最强的辩护。来源目录很小,名称也不会随着每次镜像抓取而变化。把公开请求的反复读取移出主库,可以减少主路径争用,也能把写入职责与服务职责分开。NRTMv4 本身并不缺少证据控制:更新通知文件有签名,快照与增量文件有哈希,session_id 与单调递增的版本号能让客户端识别历史断裂并重新加载。代码里甚至已经存在一次有意识的主库回退。问题不是无人考虑一致性,而是现有回退覆盖的对象比一句“有回退”更窄。

同一张来源表承担两次判断

NrtmSourceDao 的构造函数使用 nrtmMasterDataSource,并保存配置中的主来源与非权威来源名称。它的 getSources() 从 source 表读取每一行的编号与名称。新类继承同一套查询,却把数据源换成 nrtmSlaveDataSource。随后,NrtmService 的两条路径都开始使用这个新类。

第一条是根页面。服务遍历 getSources() 的结果,为每个来源拼出一条更新通知文件链接。副本没有返回的名称,自然也不会出现在列表里。

第二条更关键。收到某个来源的更新通知请求时,服务执行的逻辑相当紧凑:先调用 getSource(source),再把所得对象交给 findLastNotification(...)。getSource() 又会查询副本目录,按名称寻找那一行;找不到便抛出“Invalid source”。

Java 会先计算方法参数,才进入被调用的方法。因此,后面的通知查询不可能替前面的来源校验补漏。只有目录已经给出一个 NrtmSource 对象,findLastNotification() 才能开始工作。

而这个后续组件的防御其实写得很好。UpdateNotificationFileSourceAwareDao 先查询最近的通知载荷;如果结果为空,当前上下文又是副本,它会临时切换到同名主来源,重新查询,并在 finally 中恢复原上下文。它解决的是“来源已被识别,但副本还没有通知载荷”这一状态。它没有声称要解决“副本目录尚未识别来源”这一更早状态。

把两者笼统概括成“副本为空时会回主库”,就会丢掉这条顺序信息。根列表没有这次回退;直接请求虽有载荷回退,却要先通过目录闸门。

风险位于启用瞬间,而不是日常读取

这条边界并不意味着已有 RIPE 来源正在失效。对稳定运行的目录而言,两行或少量来源记录很可能早已复制到服务侧。只要名称存在,校验就能通过,后面的通知查询仍保留主库回退。公开仓库没有给出任何真实副本延迟、漏行、错误响应或受影响客户端。

真正需要治理的是状态变化:新增一个来源、重新创建一行、数据源恢复、配置切换,或者某次重新同步之后重新准入。在这些时刻,主库可能已经知道一个名称,而服务端副本尚不知道。按当前代码顺序,根页面会暂时不列出它;直接请求则可能在进入通知查询前被判为无效。这里的“可能”来自条件推演,不是事故报告。

同样不能从一个主分支提交推断生产状态。证据包没有发布版本映射,没有部署记录,没有线上响应采样,也没有复制指标。把它称作安全漏洞会混淆访问控制与发布准备度。它更像一道低频启用流程中的验收缺口:系统需要明确知道何时可以让副本的判断对公众生效。

副本也不是“不完整的主库”。它通常以异步收敛或有界陈旧性换取容量与隔离。治理的任务不是消灭这种取舍,而是区分哪些决策可以容忍它。反复读取成熟目录可以;改变公众能够发现和请求的来源集合,则应当先完成一次准入证明。

签名能证明内容,不能证明目录已到位

IETF Datatracker 在本次抓取时给出的 NRTMv4 草案版本是 11。它规定了通过 HTTPS 单向同步互联网路由注册库记录的方法。一个发布单元包括一份更新通知文件、一份当前快照,以及零份或多份增量文件。

更新通知采用 JSON Web Signature。客户端预先配置通知地址、IRR 数据库名称与公钥,验证通知中的来源,核验签名,再用其中的 SHA-256 哈希验证快照和增量文件。session_id 给版本序列划界;会话变化时,客户端不能假定增量历史继续完整,而要从最新快照重载。给定会话和版本的快照、增量都是不可变的。

这些规则已经回答了许多更重的问题:通知是否来自预期签名者,下载内容是否与签名引用一致,版本链是否连续,何时必须放弃增量恢复。它们不回答发布服务器内部的一道前置问题:决定“这个来源是否存在”的副本目录,是否在启用前看见了对应记录。

客户端无法验证一个尚未获准请求的通知。反过来,也没有理由把数据库拓扑塞进 NRTMv4 线协议。这里缺的不是新的网络字段,而是一项发布方自己的启用不变量。

用准入凭证封住时间缝隙

最小改进是一张内部的“来源目录准入凭证”。它不必公开主机名、复制位点、内部行号或凭据;若 RIPE NCC 认为有公共价值,只需公布汇总状态。凭证的作用,是把“副本应该已经追上”改成一个完成并可追溯的步骤。

每次启用可记录:来源名称、发布或配置代次、主侧批准时间、预期提供目录查询的数据源、服务侧观察时间或等价准备度水位、通过该服务路径首次成功取得并验证签名通知的时刻、所见会话与版本、签名密钥引用、根列表检查、直接路径检查、批准人、启用时间、回滚条件与后继凭证。

流程也可以很短。先在写侧创建或批准来源;等待 NrtmService 实际使用的数据源能够读取它;沿预定服务路径取得第一份通知并验证签名;最后才对外开放。如果在限定时间内未准备好,就暂缓启用,或者使用一条明确授权、可撤销的临时查询路径。

测试需要把两个状态拆开。一项集成测试让主目录已有新来源而副本目录暂时没有,用来证明系统选择的是暂停、有限回退还是另一种清楚响应。另一项测试让来源行已经可见、通知载荷却未到副本,用来确认既有主库回退仍然有效。把两种状态合成一个“副本延迟测试”,反而会遮住边界。

这样做还有一项好处:不必因为一次低频转换,就把所有高频目录查询重新压回主库。控制应放在改变可准入集合的事件上,而不是让每个日常请求反复支付成本。

来源