注意:本文档最初由 jrandom 于 2003 年编写。虽然我们努力保持其时效性,但某些信息可能已过时或不完整。传输和密码学部分截至 2025 年 1 月为最新版本。
简介
I2P是一个可扩展的、自组织的、弹性分组交换匿名网络层,在其之上可以运行任意数量的不同匿名或安全意识应用程序。这些应用程序中的每一个都可以在自己的匿名性、延迟和吞吐量之间进行权衡,而无需担心自由路由混合网络的正确实现,使它们能够将自己的活动与已经在I2P之上运行的更大匿名用户集合相融合。
现有的应用程序已经提供了完整的典型互联网活动范围——匿名网页浏览、网站托管、聊天、文件共享、电子邮件、博客和内容聚合,以及其他几个正在开发中的应用程序。
与托管在内容分发网络(如Freenet 或GNUnet )中的网站不同,I2P上托管的服务具有完全的交互性——这里有传统网络风格的搜索引擎、公告板、可以评论的博客、数据库驱动的网站,以及无需本地安装即可查询Freenet等静态系统的桥接服务。
通过所有这些启用匿名功能的应用程序,I2P承担了面向消息中间件的角色——应用程序表示它们想要向一个密码学标识符(一个"destination")发送某些数据,I2P负责确保数据安全且匿名地到达那里。I2P还捆绑了一个简单的流媒体 库,允许I2P的匿名尽力而为消息作为可靠的、有序的流进行传输,透明地提供了一个针对网络高带宽延迟乘积调优的基于TCP的拥塞控制算法。虽然已经有几个简单的SOCKS代理可用于将现有应用程序连接到网络中,但它们的价值有限,因为几乎每个应用程序都会常规性地暴露在匿名环境中属于敏感信息的内容。唯一安全的方法是对应用程序进行完整审计以确保正确运行,为了协助这一点,我们提供了各种语言的一系列API,可用于充分利用网络。
I2P不是一个研究项目——无论是学术、商业还是政府性质的——而是一个工程项目,旨在做任何必要的工作来为那些需要的人提供足够的匿名性保护。自2003年初以来,它一直在积极开发中,由一名全职开发者和一群来自世界各地的专门兼职贡献者组成。I2P上所做的所有工作都是开源的,可在网站 上免费获得,大部分代码直接发布到公共领域,不过使用了一些基于BSD风格许可证的加密例程。从事I2P工作的人员不控制用户在什么许可证下发布客户端应用程序,有几个GPL许可的应用程序可用(I2PTunnel 、susimail 、I2PSnark 、I2P-Bote、I2Phex等)。I2P的资金完全来自捐赠,目前在任何司法管辖区都不享受税收减免,因为许多开发者本身都是匿名的。
操作
概述
要理解I2P的运作方式,了解几个关键概念至关重要。首先,I2P严格区分参与网络的软件(“router”)和与各个应用程序关联的匿名端点(“destinations”)。某人正在运行I2P通常不是秘密。隐藏的是用户在做什么(如果有的话)的信息,以及特定destination连接到哪个router。终端用户通常在其router上有多个本地destinations——例如,一个代理到IRC服务器,另一个支持用户的匿名网络服务器(“I2P Site”),另一个用于I2Phex实例,另一个用于种子下载等。
另一个需要理解的关键概念是"tunnel"。tunnel是通过明确选定的router列表的定向路径。使用分层加密,因此每个router只能解密单一层。解密的信息包含下一个router的IP,以及要转发的加密信息。每个tunnel都有一个起始点(第一个router,也称为"gateway")和一个终点。消息只能单向发送。要发送回复消息,需要另一个tunnel。
存在两种类型的tunnel:“outbound” tunnel将消息从tunnel创建者发送出去,而**“inbound” tunnel**将消息带给tunnel创建者。将这两种tunnel结合使用,用户就可以相互发送消息。发送者(上图中的"Alice")建立一个outbound tunnel,而接收者(上图中的"Bob")创建一个inbound tunnel。inbound tunnel的网关可以接收来自任何其他用户的消息,并将其转发直到端点(“Bob”)。outbound tunnel的端点需要将消息发送到inbound tunnel的网关。为了实现这一点,发送者(“Alice”)在其加密消息中添加指令。一旦outbound tunnel的端点解密消息,它将获得转发消息到正确的inbound网关(通往"Bob"的网关)的指令。
要理解的第三个关键概念是I2P的**“network database”(或"netDb")——一对用于共享网络元数据的算法。承载的两种元数据类型是“routerInfo”和“leaseSets”**——routerInfo为router提供联系特定router所需的数据(它们的公钥、传输地址等),而leaseSet为router提供联系特定目标所需的信息。一个leaseSet包含多个"lease"。每个lease指定一个tunnel网关,允许到达特定目标。lease中包含的完整信息:
- 允许到达特定目的地的 tunnel 的入站网关。
- tunnel 过期的时间。
- 用于加密消息的公钥对(通过 tunnel 发送并到达目的地)。
Router 自己直接将其 routerInfo 发送到 netDb,而 leaseSet 则通过出站 tunnel 发送(leaseSet 需要匿名发送,以避免将 router 与其 leaseSet 关联起来)。
我们可以结合上述概念在网络中建立成功的连接。
为了建立自己的入站和出站 tunnel,Alice 在 netDb 中进行查找以收集 routerInfo。通过这种方式,她收集可以用作 tunnel 中跳点的对等节点列表。然后她可以向第一个跳点发送构建消息,请求构造 tunnel 并要求该 router 将构建消息继续转发,直到 tunnel 构建完成。
当Alice想要向Bob发送消息时,她首先在netDb中查找Bob的leaseSet,获取他当前的入站tunnel网关。然后她选择自己的一个出站tunnel,将消息发送到其中,并指示出站tunnel的端点将消息转发到Bob的某个入站tunnel网关。当出站tunnel端点收到这些指令时,它会按要求转发消息,当Bob的入站tunnel网关收到消息时,会将其沿着tunnel转发到Bob的router。如果Alice希望Bob能够回复消息,她需要在消息本身中明确传输自己的目标地址。这可以通过引入更高层次的层来实现,这在streaming 库中完成。Alice也可以通过将她最新的LeaseSet与消息捆绑来减少响应时间,这样Bob在想要回复时就不需要进行netDb查找,但这是可选的。
虽然tunnel本身具有分层加密来防止网络内部节点未经授权地泄露信息(正如传输层本身防止网络外部节点未经授权地泄露信息一样),但仍有必要添加额外的端到端加密层来对出站tunnel端点和入站tunnel网关隐藏消息。这种"garlic encryption “让Alice的router将多个消息包装成单个"garlic消息”,使用特定公钥加密,使得中间节点无法确定garlic中包含多少消息、这些消息的内容是什么,或者这些单独的clove要发往何处。对于Alice和Bob之间的典型端到端通信,garlic将使用Bob的leaseSet中发布的公钥进行加密,使得消息可以在不泄露Bob自己router的公钥的情况下进行加密。
另一个需要记住的重要事实是,I2P完全基于消息传递,并且某些消息可能会在传输过程中丢失。使用I2P的应用程序可以使用面向消息的接口并处理自己的拥塞控制和可靠性需求,但大多数应用程序最好重用提供的流 库,将I2P视为基于流的网络。
Tunnel
入站和出站 tunnel 都基于类似的原理工作。tunnel gateway 累积一定数量的 tunnel 消息,最终将它们预处理成适合 tunnel 传输的形式。接下来,gateway 对预处理后的数据进行加密,并将其转发到第一跳。该节点和后续的 tunnel 参与者在验证消息不是重复消息后,会添加一层加密,然后将其转发给下一个节点。最终,消息到达端点,在那里消息被重新分离并按要求转发。区别在于 tunnel 的创建者所做的工作——对于入站 tunnel,创建者是端点,他们只需解密所有添加的层级;而对于出站 tunnel,创建者是 gateway,他们预先解密所有层级,这样在添加了所有逐跳加密层之后,消息能够以明文形式到达 tunnel 端点。
选择特定的节点来传递消息以及它们的特定顺序对于理解I2P的匿名性和性能特征都很重要。虽然netDb(网络数据库)(见下文)有自己的标准来选择查询哪些节点以及在哪些节点上存储条目,但tunnel创建者可以按任何顺序使用网络中的任何节点(甚至在单个tunnel中多次使用任何数量的节点)。如果全局已知完美的延迟和容量数据,选择和排序将由客户端的特定需求结合其威胁模型来驱动。不幸的是,匿名收集延迟和容量数据并非易事,而依赖不可信的节点提供这些信息也有其严重的匿名性影响。
从匿名性的角度来看,最简单的技术是从整个网络中随机选择 peers,随机排列它们,并永远按照该顺序使用这些 peers。从性能的角度来看,最简单的技术是选择具有必要备用容量的最快 peers,将负载分散到不同的 peers 上以处理透明故障转移,并在容量信息发生变化时重建 tunnel。虽然前者既脆弱又低效,但后者需要无法获取的信息并提供不充分的匿名性。I2P 正在致力于提供一系列 peer 选择策略,结合匿名性感知的测量代码,按照 peers 的配置文件对其进行组织。
作为基础,I2P 通过测量与其交互的对等节点的间接行为来持续分析它们——例如,当一个对等节点在 1.3 秒内响应 netDb 查询时,这个往返延迟会被记录在所有参与请求和响应传递的两条 tunnel(入站和出站)中涉及的 router 的档案中,以及被查询对等节点的档案中。直接测量(如传输层延迟或拥塞)不会作为档案的一部分使用,因为它可能被操纵并与测量 router 相关联,从而使它们暴露于简单的攻击中。在收集这些档案时,会对每个档案运行一系列计算来总结其性能——延迟、处理大量活动的能力、当前是否过载,以及它们在网络中的集成程度。然后比较这些活跃对等节点的计算结果,将 router 组织成四个等级——快速且高容量、高容量、未故障和故障。这些等级的阈值是动态确定的,虽然它们目前使用相当简单的算法,但确实存在替代方案。
使用这些配置文件数据,最简单合理的对等节点选择策略是从顶级层(快速且高容量)中随机选择对等节点,这目前已部署用于客户端tunnel。探索性tunnel(用于netDb和tunnel管理)从"未失败"层中随机选择对等节点(该层也包括"更好"层中的router),允许对等节点更广泛地采样router,实际上通过随机化的爬山算法 优化对等节点选择。然而,仅这些策略确实会通过前驱节点和netDb收集攻击泄露有关router顶级层中对等节点的信息。反过来,存在几种替代方案,虽然不能像均匀地平衡负载,但能够解决特定类别对手发起的攻击。
通过选择一个随机密钥并根据各节点与其的XOR距离对节点进行排序,可以根据节点的故障率和层级的变动率减少在前任攻击和收集攻击中泄露的信息。应对netDb收集攻击的另一个简单策略是简单地固定入站tunnel网关,但随机化tunnel中更深层的节点。为了应对客户端联系的对手发起的前任攻击,出站tunnel端点也会保持固定。选择在最暴露点固定哪个节点当然需要有持续时间的限制,因为所有节点最终都会失效,所以可以被动调整或主动避免以模拟其他router的测量平均故障间隔时间。这两种策略可以结合使用,使用固定的暴露节点和tunnel内部基于XOR的排序。更严格的策略会固定潜在tunnel的确切节点和排序,只有在所有节点都同意每次以相同方式参与时才使用各个节点。这与基于XOR的排序不同,每个节点的前任和后继总是相同的,而XOR只确保它们的顺序不会改变。
如前所述,I2P 目前(版本 0.8)包含上述分层随机策略,采用基于 XOR 的排序。有关 tunnel 操作、管理和节点选择的详细机制讨论,可参见 tunnel 规范 。
网络数据库 (netDb)
如前所述,I2P的netDb用于共享网络的元数据。这在网络数据库 页面中有详细说明,但下面提供了基本解释。
所有 I2P router 都包含本地 netDb,但并非所有 router 都参与 DHT 或响应 leaseset 查找。那些参与 DHT 并响应 leaseset 查找的 router 被称为 ‘floodfill’。Router 可以手动配置为 floodfill,或者如果它们有足够的容量并满足可靠运行的其他条件,会自动成为 floodfill。
其他 I2P router 将通过向 floodfill 发送简单的 ‘store’ 和 ’lookup’ 查询来存储和查找数据。如果 floodfill router 收到 ‘store’ 查询,它会使用 Kademlia 算法 将信息传播到其他 floodfill router。’lookup’ 查询目前的工作方式有所不同,以避免一个重要的安全问题。当执行查找时,floodfill router 不会将查找转发给其他对等节点,而是始终自行回答(如果它有所请求的数据)。
网络数据库中存储了两种类型的信息。
- RouterInfo 存储特定 I2P router 的信息以及如何联系它
- LeaseSet 存储特定目的地的信息(例如 I2P 网站、电子邮件服务器…)
所有这些信息都由发布方签名,并由任何使用或存储该信息的 I2P router 进行验证。此外,数据包含时间信息,以避免存储旧条目和可能的攻击。这也是为什么 I2P 捆绑了维护正确时间的必要代码,偶尔查询一些 SNTP 服务器(默认为 pool.ntp.org 轮询),并在传输层检测 router 之间的时间偏差。
一些额外的说明也很重要。
未发布和加密的 leaseSet: 有时您可能只希望特定的人能够访问某个目标地址。这可以通过不在 netDb 中发布目标地址来实现。但是,您需要通过其他方式传输目标地址。这通过"加密 leaseSet"来支持。这些 leaseSet 只能由拥有解密密钥的人解码。
引导启动: 引导启动 netDb 相当简单。一旦 router 成功接收到一个可达对等节点的 routerInfo,它就可以查询该 router 以获取网络中其他 router 的引用。目前,许多用户将他们的 routerInfo 文件发布到网站上以提供这些信息。I2P 会自动连接到其中一个网站来收集 routerInfo 文件并进行引导启动。I2P 将这个引导过程称为"重新播种"。
查找可扩展性: I2P网络中的查找是迭代的,而非递归的。如果从某个floodfill的查找失败,查找将重复到下一个最接近的floodfill。floodfill不会递归地向另一个floodfill请求数据。迭代查找对于大型DHT网络具有可扩展性。
传输协议
router之间的通信需要提供机密性和完整性以抵御外部对手,同时验证联系的router确实是应该接收特定消息的那个。router之间具体如何通信并不重要——在不同时期使用了三种不同的协议来提供这些基本需求。
I2P目前支持两种传输协议:基于TCP的NTCP2 和基于UDP的SSU2 。这两种协议已经取代了之前版本的协议NTCP 和SSU ,后者现已弃用。两种协议都支持IPv4和IPv6。通过同时支持TCP和UDP传输,I2P能够有效穿越大多数防火墙,包括那些旨在阻止限制性审查制度下流量的防火墙。NTCP2和SSU2的设计采用了现代加密标准,提高了流量识别抗性,增强了效率和安全性,并使NAT穿越更加稳健。Router在netDb中发布每种支持的传输方式和IP地址。能够访问公共IPv4和IPv6网络的router通常会发布四个地址,分别对应NTCP2/SSU2与IPv4/IPv6的各种组合。
SSU2 支持并扩展了 SSU 的目标。SSU2 与其他现代基于 UDP 的协议(如 Wireguard 和 QUIC)有许多相似之处。除了通过 UDP 可靠传输网络消息外,SSU2 还提供了专门的点对点、协作式 IP 地址检测、防火墙检测和 NAT 穿透功能。如 SSU 规范 中所述:
该协议的目标是提供安全、经过身份验证、半可靠且无序的消息传递,仅向第三方暴露最少量易于识别的数据。它应该支持高度通信以及TCP友好的拥塞控制,并可能包括PMTU检测。它应该能够以满足家庭用户需求的速率高效传输大量数据。此外,它还应该支持解决网络障碍的技术,如大多数NAT或防火墙。
NTCP2 支持并扩展了 NTCP 的目标。它通过 TCP 提供高效且完全加密的网络消息传输,并使用现代加密标准来抵抗流量识别。
I2P 同时支持多种传输协议。通过"竞价"机制来选择出站连接的特定传输协议。每种传输协议都会为连接进行竞价,这些竞价的相对值决定了优先级。传输协议可能会根据是否已经与对等节点建立连接而给出不同的竞价。
出价(优先级)值取决于具体实现,可能会根据流量条件、连接数量和其他因素而变化。router还会在网络数据库中发布其对入站连接的传输偏好,以每种传输和地址的传输"成本"形式表示。
密码学
I2P在多个协议层使用密码学进行加密、身份验证和验证。主要的协议层包括:传输层、tunnel构建消息、tunnel层加密、网络数据库消息和端到端(garlic)消息。I2P的原始设计使用了一小组在当时被认为是安全的密码学原语。这些包括ElGamal非对称加密、DSA-SHA1签名、AES256/CBC对称加密和SHA-256哈希。随着可用计算能力的增长和密码学研究在这些年来的大幅发展,I2P需要升级其原语和协议。因此,我们添加了"加密类型"和"签名类型"的概念,并扩展了我们的协议以包含这些标识符并指示支持情况。这使我们能够定期更新和扩展网络对现代密码学的支持,并为新原语提供网络未来保障,而不会破坏向后兼容性或需要网络更新的"标志日"。一些签名和加密类型也保留用于实验用途。
当前在大多数协议层中使用的密码学原语包括 X25519 密钥交换、EdDSA 签名、ChaCha20/Poly1305 认证对称加密和 SHA-256 哈希。AES256 仍用于 tunnel 层加密。这些现代协议用于绝大多数网络通信。包括 ElGamal、ECDSA 和 DSA-SHA1 在内的较旧原语在与旧版 router 通信时,大多数实现仍支持以保持向后兼容性。一些旧协议已被弃用和/或完全移除。在不久的将来,我们将开始研究迁移到后量子 (PQ) 或混合 PQ 加密和签名,以维持我们强大的安全标准。
这些密码学原语结合在一起,为I2P提供了针对各种对手的分层防御。在最底层,router间通信受到传输层安全性的保护。通过传输层传递的tunnel 消息具有自己的分层加密。各种其他消息在"garlic消息"内传递,这些消息也是加密的。
Garlic Messages
Garlic 消息是"洋葱"分层加密的扩展,允许单个消息的内容包含多个"瓣"——完整的消息及其自己的传输指令。当消息本来会以明文形式通过不应访问该信息的对等节点时,消息就会被包装成 garlic 消息——例如,当一个 router 想要请求另一个 router 参与 tunnel 时,它们会将请求包装在 garlic 中,使用接收方 router 的公钥加密该 garlic,然后通过 tunnel 转发。另一个例子是当客户端想要向目标发送消息时——发送方的 router 会将该数据消息(连同其他一些消息)包装成 garlic,使用接收方 leaseSet 中公布的公钥加密该 garlic,然后通过适当的 tunnel 转发。
在加密层内每个clove附带的"指令"包括请求将clove在本地转发、转发到远程router或转发到远程router上的远程tunnel的能力。这些指令中有字段允许对等节点请求延迟传递直到满足特定时间或条件,尽管在部署非平凡延迟 之前不会执行这些请求。可以在不构建tunnel的情况下显式路由garlic消息任意跳数,甚至可以通过将tunnel消息包装在garlic消息中并在传递给tunnel中的下一跳之前转发若干跳来重新路由tunnel消息,但这些技术目前在现有实现中并未使用。
会话标签
作为一个不可靠、无序、基于消息的系统,I2P使用非对称和对称加密算法的简单组合来为garlic消息提供数据机密性和完整性。最初的组合被称为ElGamal/AES+SessionTags,但这是一种过于冗长的方式来描述2048位ElGamal、AES256、SHA256和32字节随机数的简单使用。虽然这个协议仍然受到支持,但网络的大部分已经迁移到新协议ECIES-X25519-AEAD-Ratchet。这个协议结合了X25519、ChaCha20/Poly1305和同步PRNG来生成32字节随机数。下面将简要描述这两种协议。
ElGamal/AES+SessionTags
当一个router第一次想要向另一个router加密garlic消息时,它们使用ElGamal加密AES256会话密钥的密钥材料,然后在该加密的ElGamal块之后附加AES256/CBC加密的载荷。除了加密的载荷外,AES加密部分还包含载荷长度、未加密载荷的SHA256哈希值,以及一些"会话标签"——随机的32字节随机数。下次发送者想要向另一个router加密garlic消息时,它们不再使用ElGamal加密新的会话密钥,而是简单地选择一个之前传递的会话标签,并像之前一样使用AES加密载荷,使用与该会话标签一起使用的会话密钥,并在前面加上会话标签本身。当router接收到garlic加密消息时,它们检查前32字节看是否匹配可用的会话标签——如果匹配,它们直接使用AES解密消息,但如果不匹配,它们会ElGamal解密第一个块。
每个会话标签只能使用一次,以防止内部对手不必要地将不同消息关联为同一router之间的通信。ElGamal/AES+SessionTag加密消息的发送方选择何时以及交付多少标签,为接收方预储足够的标签来覆盖一轮消息。Garlic消息可以通过将一个小的附加消息作为clove(“传输状态消息”)捆绑来检测成功的标签传输——当garlic消息到达预期接收方并成功解密时,这个小的传输状态消息是暴露的clove之一,并包含指示接收方将该clove发送回原始发送方的指令(当然是通过入站tunnel)。当原始发送方收到这个传输状态消息时,他们知道garlic消息中捆绑的会话标签已成功传输。
Session tags 本身有非常短的生存期,如果不使用就会被丢弃。此外,每个密钥存储的数量是有限的,密钥本身的数量也是如此——如果到达的数量过多,新消息或旧消息都可能被丢弃。发送方会跟踪使用 session tags 的消息是否正常传输,如果通信不充分,它可能会丢弃先前假定已正确传递的消息,回退到完整的昂贵的 ElGamal 加密。
ECIES-X25519-AEAD-Ratchet
ElGamal/AES+SessionTags在多个方面都需要大量开销。CPU使用率很高,因为ElGamal相当缓慢。带宽使用过多,因为需要提前传递大量会话标签,而且ElGamal公钥非常大。由于需要存储大量会话标签,内存使用率很高。会话标签传递丢失影响了可靠性。
ECIES-X25519-AEAD-Ratchet 的设计旨在解决这些问题。X25519 用于密钥交换。ChaCha20/Poly1305 用于认证对称加密。加密密钥采用"双重棘轮"或定期轮换。会话标签从 32 字节减少到 8 字节,并使用 PRNG 生成。该协议与 Signal 和 WhatsApp 中使用的 signal 协议有许多相似之处。此协议在 CPU、RAM 和带宽方面提供了显著更低的开销。
会话标签由运行在会话两端的确定性同步PRNG生成,用于生成会话标签和会话密钥。该PRNG是使用SHA-256 HMAC的HKDF,并从X25519 DH结果中获取种子。会话标签从不提前传输;它们只随消息一起包含。接收方存储有限数量的会话密钥,按会话标签索引。发送方不需要存储任何会话标签或密钥,因为它们不会提前发送;可以按需生成。通过保持发送方和接收方之间的PRNG大致同步(接收方预计算下一个例如50个标签的窗口),消除了定期捆绑大量标签的开销。
未来
I2P的协议在大多数平台上都很高效,包括手机,并且对大多数威胁模型都是安全的。然而,有几个领域需要进一步改进,以满足那些面临强大国家赞助对手的用户需求,并应对持续的密码学进步和不断增长的计算能力威胁。jrandom在2003年提出了两个可能的功能:受限路由和可变延迟。虽然我们不再计划实现这些功能,但下面对它们进行了描述。
受限路由操作
I2P是一个覆盖网络,旨在运行于功能性分组交换网络之上,利用端到端原则提供匿名性和安全性。虽然互联网由于NAT的使用已不再完全拥抱端到端原则,但I2P确实需要网络的大部分节点是可达的——边缘可能有一些使用受限路由运行的对等节点,但I2P不包含适用于大多数对等节点不可达这种退化情况的合适路由算法。不过,它可以在采用此类算法的网络上运行。
受限路由操作,即对可直接到达的对等节点存在限制,根据受限路由的处理方式不同,会产生几种不同的功能和匿名性影响。在最基本的层面上,当对等节点位于不允许入站连接的NAT或防火墙后面时,就会出现受限路由。通过将分布式打洞技术集成到传输层中,这个问题在很大程度上得到了解决,使得大多数NAT和防火墙后面的用户无需任何配置就能接收主动连接。然而,这并不能限制对等节点的IP地址暴露给网络内部的router,因为它们可以简单地通过已发布的introducer与该对等节点建立连接。
除了对受限路由的功能处理之外,还有两个级别的受限操作可以用来限制IP地址的暴露——使用router特定的tunnel进行通信,以及提供"客户端router"。对于前者,router可以构建新的tunnel池或重用其探索性池,将其中一些tunnel的入站网关作为其routerInfo的一部分发布,以替代其传输地址。当对等节点想要与它们取得联系时,它们在netDb中看到这些tunnel网关,并简单地通过其中一个已发布的tunnel向它们发送相关消息。如果受限路由后面的对等节点想要回复,它可以直接回复(如果它们愿意向对等节点暴露其IP)或通过其出站tunnel间接回复。当对等节点直接连接的router想要到达它时(例如转发tunnel消息),它们只需优先使用直接连接而不是已发布的tunnel网关。“客户端router"的概念只是通过不发布任何router地址来扩展受限路由。这样的router甚至不需要在netDb中发布其routerInfo,仅需向其联系的对等节点提供其自签名的routerInfo(传递router公钥所必需的)。
对于那些位于受限路由后面的用户来说,这存在权衡取舍,因为他们参与其他人tunnel的频率可能会降低,而且与他们连接的router能够推断出原本不会暴露的流量模式。另一方面,如果这种暴露的代价小于提供IP地址的代价,那么这可能是值得的。当然,这假设受限路由后面的router所联系的对等节点不是恶意的——要么网络足够大,使用恶意对等节点进行连接的概率足够小,要么使用可信任的(也许是临时的)对等节点。
受限路由很复杂,总体目标基本上已被放弃。几个相关的改进大大减少了对它们的需求。我们现在支持UPnP来自动打开防火墙端口。我们支持IPv4和IPv6。SSU2改进了地址检测、防火墙状态确定和协作式NAT打洞。SSU2、NTCP2和地址兼容性检查确保tunnel跳跃在tunnel构建之前能够连接。GeoIP和国家识别允许我们避免连接到具有限制性防火墙的国家的对等节点。对这些防火墙后面"隐藏"的router的支持已经改进。一些实现还支持连接到覆盖网络(如Yggdrasil)上的对等节点。
可变延迟
尽管I2P的初期工作重点主要集中在低延迟通信上,但从一开始它就是为可变延迟服务而设计的。在最基本的层面上,运行在I2P之上的应用程序可以提供中延迟和高延迟通信的匿名性,同时仍然将其流量模式与低延迟流量融合在一起。但在内部,I2P可以通过garlic encryption提供自己的中延迟和高延迟通信——指定消息应该在一定延迟后、在特定时间、在一定数量的消息通过后或通过其他混合策略发送。通过分层加密,只有clove暴露延迟请求的router才会知道该消息需要高延迟,从而允许流量进一步与低延迟流量融合。一旦传输前置条件得到满足,持有clove的router(它本身很可能是一个garlic消息)就会按要求简单地转发它——转发到一个router、一个tunnel,或者最有可能的是转发到一个远程客户端目标。
可变延迟服务的目标需要大量资源来支持存储转发机制。这些机制可以在各种消息应用程序中得到支持,比如 i2p-bote。在网络层面,像 Freenet 这样的替代网络提供了这些服务。我们已经决定不在 I2P router 级别追求这个目标。
类似系统
I2P 的架构建立在面向消息的中间件概念、DHT 拓扑结构、自由路由混合网络的匿名性和密码学,以及分组交换网络的适应性之上。其价值并非来自新颖的概念或算法,而是来自精心的工程设计,将现有系统和论文的研究成果相结合。虽然有一些类似的项目值得审查,无论是在技术还是功能比较方面,这里特别提出两个——Tor 和 Freenet。
另请参阅网络比较页面 。请注意,这些描述是由 jrandom 在 2003 年编写的,目前可能不够准确。
Tor
乍看之下,Tor 和 I2P 在功能和匿名性方面有许多相似之处。虽然 I2P 的开发始于我们了解 Tor 早期工作之前,但原始洋葱路由和 ZKS 工作的许多经验教训都被整合到了 I2P 的设计中。I2P 没有构建一个本质上受信任的、具有目录服务器的集中式系统,而是建立了一个自组织的网络数据库,每个节点都承担着分析其他 router 的责任,以确定如何最好地利用可用资源。另一个关键区别是,虽然 I2P 和 Tor 都使用分层和有序路径(tunnel 和电路/流),但 I2P 本质上是一个分组交换网络,而 Tor 本质上是一个电路交换网络,这使得 I2P 能够透明地绕过拥塞或其他网络故障,运行冗余路径,并在可用资源间进行负载均衡。虽然 Tor 通过提供集成的外部代理发现和选择功能来提供有用的外部代理功能,但 I2P 将此类应用层决策留给运行在 I2P 之上的应用程序——实际上,I2P 甚至将类似 TCP 的流媒体库本身外化到应用层,允许开发者尝试不同策略,利用他们的领域特定知识来提供更好的性能。
从匿名性角度来看,当比较核心网络时有很多相似之处。然而,存在一些关键差异。当面对内部对手或大多数外部对手时,I2P的单向tunnel(隧道)仅通过查看流量本身就比Tor的双向circuit(电路)暴露的流量数据少一半——HTTP请求和响应在Tor中会走相同路径,而在I2P中构成请求的数据包会通过一个或多个出站tunnel发出,构成响应的数据包会通过一个或多个不同的入站tunnel返回。虽然I2P的节点选择和排序策略应该能够充分应对前置节点攻击,但如果有必要切换到双向tunnel,我们可以简单地沿着相同的router构建一个入站和出站tunnel。
Tor使用伸缩式tunnel创建时会出现另一个匿名性问题,因为当电路中的数据包通过对手节点时,简单的数据包计数和时序测量会暴露关于对手在电路中位置的统计信息。I2P使用单向tunnel创建和单个消息,因此这些数据不会被暴露。保护tunnel中的位置很重要,否则对手就能够发起一系列强大的前驱攻击、交集攻击和流量确认攻击。
总的来说,Tor 和 I2P 在各自的重点上互为补充——Tor 致力于提供高速匿名的互联网出口代理,而 I2P 致力于提供一个去中心化的弹性网络本身。理论上,两者都可以用来实现这两个目的,但鉴于开发资源有限,它们都有各自的优势和劣势。I2P 开发者已经考虑过修改 Tor 以利用 I2P 设计优势所需的步骤,但对 Tor 在资源稀缺情况下可行性的担忧表明,I2P 的包交换架构将能够更有效地利用稀缺资源。
Freenet
Freenet 在 I2P 设计的初始阶段发挥了重要作用——证明了在网络内完全包含的充满活力的匿名社区的可行性,证明了可以避免出口代理固有的危险。I2P 的第一个雏形始于作为 Freenet 的替代通信层,试图将可扩展、匿名和安全的点对点通信的复杂性从抗审查分布式数据存储的复杂性中分离出来。然而,随着时间的推移,Freenet 算法中固有的一些匿名性和可扩展性问题使得 I2P 的重点应该严格专注于提供通用匿名通信层,而不是作为 Freenet 的组件变得明确。多年来,Freenet 开发者已经意识到了旧设计中的弱点,这促使他们建议需要一个"预混合"层来提供实质性的匿名性。换句话说,Freenet 需要在诸如 I2P 或 Tor 这样的混合网络之上运行,“客户端节点"通过混合网络向"服务器节点"请求和发布数据,然后这些服务器节点根据 Freenet 的启发式分布式数据存储算法获取和存储数据。
Freenet的功能与I2P非常互补,因为Freenet本身提供了许多用于运行中等和高延迟系统的工具,而I2P本身提供了适合提供足够匿名性的低延迟混合网络。从工程、匿名性、安全性和资源分配的角度来看,将混合网络与抗审查分布式数据存储分离的逻辑仍然是不言自明的,因此希望Freenet团队能够朝着这个方向努力,如果不是简单地重用(或根据需要帮助改进)像I2P或Tor这样的现有混合网络的话。
附录 A:应用层
I2P 本身实际上并不做太多工作——它只是向远程目标发送消息并接收针对本地目标的消息——大部分有趣的工作都在其上层进行。就其本身而言,I2P 可以被视为一个匿名和安全的 IP 层,而捆绑的流媒体库 则是在其之上实现的匿名和安全 TCP 层。除此之外,I2PTunnel 提供了一个通用的 TCP 代理系统,用于进入或退出 I2P 网络,此外还有各种网络应用程序为最终用户提供进一步的功能。
流媒体库
I2P streaming 库可以视为一个通用的流式传输接口(类似于 TCP socket),其实现支持滑动窗口协议 并进行了多项优化,以适应 I2P 网络的高延迟特性。各个流可以调整最大数据包大小和其他选项,不过默认的 4KB 压缩大小似乎在重传丢失消息的带宽成本和多条消息的延迟之间提供了合理的平衡。
此外,考虑到后续消息的相对较高成本,streaming库的消息调度和传递协议已经过优化,允许传递的单个消息包含尽可能多的可用信息。例如,通过streaming库代理的小型HTTP事务可以在单次往返中完成——第一个消息捆绑了SYN、FIN和小载荷(通常一个HTTP请求可以容纳),回复捆绑了SYN、FIN、ACK和小载荷(许多HTTP响应可以容纳)。虽然必须传输额外的ACK来告知HTTP服务器已收到SYN/FIN/ACK,但本地HTTP代理可以立即向浏览器传递完整的响应。
总的来说,流媒体库与 TCP 的抽象非常相似,具有滑动窗口、拥塞控制算法(慢启动和拥塞避免)以及一般的数据包行为(ACK、SYN、FIN、RST 等)。
命名库和地址簿
更多信息请参阅命名和地址簿 页面。
开发者:mihi, Ragnarok
在I2P中的命名一直是一个经常争论的话题,从一开始就有支持各种可能性的倡导者。然而,考虑到I2P对安全通信和去中心化操作的内在需求,传统的DNS风格命名系统显然是不可行的,“多数决定"的投票系统也是如此。相反,I2P配备了一个通用的命名库和一个基础实现,设计用于处理本地名称到destination的映射,以及一个名为"Address Book"的可选附加应用程序。address book是一个由信任网络驱动的安全、分布式和人类可读的命名系统,仅通过强制要求本地唯一性而牺牲了对所有人类可读名称全局唯一性的要求。虽然I2P中的所有消息都通过其destination进行密码学寻址,不同的人可以拥有指向不同destination的"Alice"的本地address book条目。人们仍然可以通过导入在其信任网络中指定的对等节点的已发布address book、添加通过第三方提供的条目,或者(如果一些人使用先到先得的注册系统组织一系列已发布的address book)人们可以选择将这些address book视为名称服务器,从而模拟传统DNS来发现新名称。
不过,I2P 并不提倡使用类似 DNS 的服务,因为劫持站点所造成的损害可能是巨大的——而不安全的 destination 毫无价值。DNSsec 本身仍然依赖于注册商和证书颁发机构,而在 I2P 中,发送到 destination 的请求无法被拦截,回复也无法被伪造,因为它们使用 destination 的公钥进行加密,而 destination 本身只是一对公钥和一个证书。另一方面,DNS 风格的系统允许查找路径上的任何名称服务器发起简单的拒绝服务和欺骗攻击。添加由某个集中式证书颁发机构签名验证响应的证书可以解决许多恶意名称服务器问题,但仍会留下重放攻击以及恶意证书颁发机构攻击的隐患。
投票式命名也很危险,特别是考虑到女巫攻击在匿名系统中的有效性——攻击者可以简单地创建任意数量的对等节点,并用每个节点进行"投票"来接管给定的名称。工作量证明方法可以用来使身份创建变得有成本,但随着网络的增长,联系所有人进行在线投票所需的负载变得不可行,或者如果没有查询完整网络,可能会得到不同的答案集合。
然而,与互联网一样,I2P将命名系统的设计和运行与(类似IP的)通信层分离。捆绑的命名库包含一个简单的服务提供者接口,替代命名系统可以插入其中,允许终端用户决定他们偏好的命名权衡方案。
I2PTunnel
开发者:mihi
I2PTunnel 可能是 I2P 最受欢迎且最多功能的客户端应用程序,允许在 I2P 网络内外进行通用代理。I2PTunnel 可以视为四个独立的代理应用程序——一个"客户端”,接收入站 TCP 连接并将其转发到指定的 I2P 目标;一个"httpclient”(也称为"eepproxy”),像 HTTP 代理一样工作,将请求转发到适当的 I2P 目标(必要时查询命名服务);一个"服务器",在目标上接收入站 I2P streaming 连接并将其转发到指定的 TCP 主机+端口;以及一个"httpserver",通过解析 HTTP 请求和响应来扩展"服务器"功能,以实现更安全的操作。还有一个额外的"socksclient"应用程序,但由于前面提到的原因,不鼓励使用它。
I2P 本身并不是一个出口代理网络——混合网络中将数据转发进出混合网络所固有的匿名性和安全性问题,使得 I2P 的设计专注于提供一个匿名网络,该网络能够满足用户的需求而无需外部资源。然而,I2PTunnel “httpclient” 应用程序为出口代理提供了一个钩子——如果请求的主机名不以 “.i2p” 结尾,它会从用户提供的出口代理集合中随机选择一个目标,并将请求转发给它们。这些目标只是由明确选择运行出口代理的志愿者运行的 I2PTunnel “server” 实例——默认情况下没有人是出口代理,运行出口代理也不会自动告诉其他人通过你进行代理。虽然出口代理确实有固有的弱点,但它们为使用 I2P 提供了一个简单的概念验证,并在威胁模型下提供了一些功能,这对某些用户来说可能是足够的。
I2PTunnel 支持大多数应用程序的使用。指向 Web 服务器的"httpserver"让任何人都能运行自己的匿名网站(或"I2P 站点")——I2P 为此目的捆绑了一个 Web 服务器,但可以使用任何 Web 服务器。任何人都可以运行指向匿名托管 IRC 服务器之一的"client",每个服务器都运行指向其本地 IRCd 的"server",并通过它们自己的"client" tunnel 在 IRCd 之间通信。最终用户还拥有指向 I2Pmail 的 POP3 和 SMTP 目标的"client" tunnel(这些反过来只是指向 POP3 和 SMTP 服务器的"server"实例),以及指向 I2P 的 CVS 服务器的"client" tunnel,允许匿名开发。有时人们甚至运行"client"代理来访问指向 NNTP 服务器的"server"实例。
I2PSnark
I2PSnark 开发者:jrandom 等人,移植自 mjw 的 Snark 客户端
I2PSnark 与 I2P 安装包捆绑,提供一个简单的匿名 BitTorrent 客户端,具有多种子功能,通过简单的 HTML 网页界面展示所有功能。
I2Pmail / Susimail
开发者:postman, susi23, mastiejaner
I2Pmail与其说是一个应用程序,不如说是一项服务——postman通过I2PTunnel实例访问一系列与mastiejaner共同开发的组件,提供内部和外部邮件服务以及POP3和SMTP服务,允许人们使用他们偏好的邮件客户端来匿名发送和接收邮件。然而,由于大多数邮件客户端会暴露大量身份识别信息,I2P捆绑了susi23开发的基于Web的susimail客户端,该客户端专门针对I2P的匿名需求而构建。I2Pmail/mail.i2p服务提供透明的病毒过滤以及通过hashcash增强配额的拒绝服务攻击防护。此外,每个用户都可以在通过mail.i2p出代理投递之前控制他们的批处理策略,这些出代理与mail.i2p SMTP和POP3服务器是分离的——出代理和入代理都通过I2P本身与mail.i2p SMTP和POP3服务器通信,因此即使那些非匿名位置被攻破,也无法获得用户的邮件账户或活动模式。