概览
从发布 0.9.32 开始,更新 netdb 规范以弃用路由信息中的主机名,或者更准确地说,在单个路由地址中弃用主机名。在所有 I2P 实现中,配置了主机名的发布路由器应在发布之前用 IP 替换主机名,而其他路由器应忽略带有主机名的地址。路由器不应对已发布的主机名进行 DNS 查询。
动机
自 I2P 创建以来,路由地址中一直允许使用主机名。然而,很少有路由器公布主机名,因为这需要一个公共主机名(很少有用户具备)以及手动配置(很少有用户愿意这样做)。在最近的一个样本中,0.7% 的路由器正在发布一个主机名。
主机名的最初目的是帮助用户应对频繁变化的 IP 和动态 DNS 服务(例如 http://dyn.com/dns/),以便在 IP 更改时不会失去连接。然而,彼时网络很小,路由信息过期时间较长。同时,Java 代码并没有有效的逻辑来在本地 IP 发生变化时重启路由器或重新发布路由信息。
此外,最初 I2P 不支持 IPv6,因此将主机名解析为 IPv4 或 IPv6 地址的复杂性不存在。
在 Java I2P 中,一直以来都是一个挑战,将配置的主机名传播到已发布的传输中,并且随着 IPv6 的出现,问题变得更加复杂。不清楚一个双栈主机是否应该同时发布一个主机名和一个字面 IPv6 地址。
最近,乔治亚理工学院的研究提到了 DNS 问题(无论是间接地还是直接地)。研究人员运行了大量带有已发布主机名的 floodfill。对于一小部分可能存在本地 DNS 问题的用户来说,立即的问题是 I2P 完全挂起。
更大的问题是 DNS 总体上,以及 DNS(无论是主动的还是被动的)如何可用于非常快速地枚举网络,特别是如果发布的路由器是 floodfill。 无效的主机名或没有响应的、缓慢的或者恶意的 DNS 响应者可能被用于其他攻击。 EDNS0 可能提供进一步的枚举或攻击场景。 DNS 也可能基于查询时间提供攻击路径,揭示路由器到路由器连接时间,帮助构建连接图,估算流量,以及其他推断。
此外,由大卫·达贡领导的乔治亚理工学院小组列出了在注重隐私的应用程序中与 DNS 有关的几个问题。DNS 查询通常由低级库执行,而不是由应用程序控制。这些库未专门为匿名设计;可能不提供应用程序可精细控制的功能;其输出可能被指纹识别。特别是 Java 库可能存在问题,但这不仅仅是 Java 的问题。一些库使用的 DNS ANY 查询可能会被拒绝。所有这些问题都因为被动 DNS 监测和查询的广泛存在而令人担忧,这些监测和查询对多个组织可用。所有的 DNS 监测和攻击从 I2P 路由器的角度来看是带外的,几乎不需要或根本不需要网络内的 I2P 资源,也不需要修改现有的实现。
尽管我们尚未完全考虑清楚可能的问题,但攻击面似乎很大。还有其他方法可以枚举网络并收集相关数据,但 DNS 攻击可能更容易、更快捷且不易察觉。
路由器实现理论上可以切换到使用复杂的第三方 DNS 库,但这将相当复杂,是一种维护负担,并且完全超出 I2P 开发人员的核心专长。
Java 0.9.31 的即时解决方案包括修复挂起问题、增加 DNS 缓存时间和实现 DNS 负缓存。当然,增加缓存时间从一开始就减少了路由信息中包含主机名的好处。
然而,这些更改只是短期的缓解措施,并未解决以上根本问题。因此,最简单且最完整的修复方法是禁止在路由信息中使用主机名,从而消除对此的 DNS 查询。
设计
对于路由信息发布代码,实现者有两个选择,或者禁用/移除主机名的配置选项,或者在发布时将配置的主机名转换为 IP。不论选择哪种方式,路由器在其 IP 更改时应立即重新发布。
对于路由信息验证和传输连接代码,实现者应忽略包含主机名的路由地址,并使用其他包含 IP 的已发布地址(如果有的话)。如果路由信息中的所有地址都不包含 IP,则路由器不应连接到已发布的路由器。在任何情况下,路由器都不应对已发布的主机名进行 DNS 查询,无论是直接调用还是通过底层库。
规范
更改 NTCP 和 SSU 传输规范,表明“host”参数必须是一个 IP,而不是主机名,并且路由器应忽略包含主机名的单个路由地址。
这也适用于 SSU 地址中的“ihost0”、“ihost1”和“ihost2”参数。 路由器应忽略包含主机名的介绍者地址。
注释
该提议未涉及重新造种主机的主机名。虽然重新造种主机的 DNS 查询频率较低,但它们仍可能是一个问题。如有必要,可以通过在硬编码的 URL 列表中用 IP 替换主机名来简单地解决;无需进行规范或代码更改。
迁移
此提案可以立即实施,无需逐步迁移,因为很少有路由器发布主机名,并且那些仍在发布的一般不会在所有地址中都发布主机名。
路由器无需在决定忽略主机名之前检查已发布路由器的版本,不需要协调发布或在各种路由器实现之间采用统一的策略。
对于那些仍在发布主机名的路由器,它们将获得更少的入站连接,并可能最终在建立入站隧道方面遇到困难。
为了进一步减少影响,实现者可以首先仅忽略 floodfill 路由器中带有主机名的路由地址,或低于 0.9.32 版本的路由器,在稍后的版本中忽略所有路由器的主机名。