概述
有关 Streaming 协议的概述,请参阅 Streaming Library 。
协议版本
streaming 协议不包含版本字段。下面列出的版本适用于 Java I2P。实现和实际的加密支持可能有所不同。无法确定远端是否支持任何特定版本或功能。下表仅供参考,用于了解各种功能的发布日期。
下面列出的功能是针对协议本身的。各种配置选项在Streaming Library 中有文档说明,同时也标明了它们在哪个Java I2P版本中实现。
| Router Version | Streaming Features |
|---|---|
| 0.9.58 | Bob's hash in NACKs field of SYN packet |
| 0.9.39 | OFFLINE_SIGNATURE option |
| 0.9.36 | I2CP protocol number enforced |
| 0.9.20 | FROM_INCLUDED no longer required in RESET |
| 0.9.18 | PINGs and PONGs may include a payload |
| 0.9.15 | EdDSA Ed25519 sig type |
| 0.9.12 | ECDSA P-256, P-384, and P-521 sig types |
| 0.9.11 | Variable-length signatures |
| 0.7.1 | Protocol numbers defined in I2CP |
数据包格式
流协议中单个数据包的格式如下所示。最小头部大小为22字节,不包括NACK或选项数据。
流协议中没有长度字段。帧结构由底层协议提供 - I2CP 和 I2NP。
+----+----+----+----+----+----+----+----+
| send Stream ID | rcv Stream ID |
+----+----+----+----+----+----+----+----+
| sequence Num | ack Through |
+----+----+----+----+----+----+----+----+
| nc | nc*4 bytes of NACKs (optional)
+----+----+----+----+----+----+----+----+
| rd | flags | opt size| opt data
+----+----+----+----+----+----+----+----+
... (optional, see below) |
+----+----+----+----+----+----+----+----+
| payload ...
+----+----+----+-//
sendStreamId :: 4 字节 Integer : 由数据包接收方在发送第一个 SYN 回复数据包之前选择的随机数,在连接的生命周期内保持不变,大于零。在连接发起方发送的 SYN 消息中为 0,在后续消息中也为 0,直到收到包含对方 stream ID 的 SYN 回复。
receiveStreamId :: 4 字节 Integer : 在发送第一个 SYN 数据包之前由数据包发起者选择的随机数,在连接的整个生命周期内保持不变,必须大于零。如果未知则可能为 0,例如在 RESET 数据包中。
sequenceNum :: 4 字节 Integer : 此消息的序列号,在 SYN 消息中从 0 开始,在每个消息中递增 1,但纯 ACK 和重传消息除外。如果 sequenceNum 为 0 且未设置 SYN 标志,则这是一个不应被 ACK 的纯 ACK 数据包。
ackThrough :: 4 字节 Integer : 在 receiveStreamId 上接收到的最高数据包序列号。此字段在初始连接数据包(其中 receiveStreamId 为未知 id)或设置了 NO_ACK 标志时被忽略。所有序列号小于等于此值的数据包都被确认(ACK),除了下面 NACKs 中列出的数据包。
NACK count :: 1字节 Integer : 下一个字段中4字节NACK的数量,或者从0.9.58版本开始与SYNCHRONIZE一起用于重放防护时为8;见下文。
NACKs :: nc * 4字节 Integer s : 小于ackThrough但尚未接收到的序列号。对一个数据包的两次NACK是对该数据包进行"快速重传"的请求。从0.9.58版本开始,也与SYNCHRONIZE一起用于防止重放攻击;见下文。
resendDelay :: 1 字节 Integer : 此数据包的创建者在重新发送此数据包之前将等待多长时间(如果尚未收到 ACK)。该值是自数据包创建以来的秒数。目前在接收时被忽略。
flags :: 2 字节值:见下文。
option size :: 2 字节 Integer : 下一个字段中的字节数
选项数据 :: 0 或更多字节 : 按标志指定。见下文。
payload :: 剩余数据包大小
标志和选项数据字段
上面的标志字段指定了数据包的一些元数据,并且可能需要包含某些附加数据。标志如下所示。任何指定的数据结构都必须按给定顺序添加到选项区域中。
位序:15….0(15是最高有效位)
| Bit | Flag | Option Order | Option Data | Function |
|---|---|---|---|---|
| 0 | SYNCHRONIZE | -- | -- | Similar to TCP SYN. Set in the initial packet and in the first response. FROM_INCLUDED and SIGNATURE_INCLUDED must also be set. |
| 1 | CLOSE | -- | -- | Similar to TCP FIN. If the response to a SYNCHRONIZE fits in a single message, the response will contain both SYNCHRONIZE and CLOSE. SIGNATURE_INCLUDED must also be set. |
| 2 | RESET | -- | -- | Abnormal close. SIGNATURE_INCLUDED must also be set. Prior to release 0.9.20, due to a bug, FROM_INCLUDED must also be set. |
| 3 | SIGNATURE_INCLUDED | 5 | variable length Signature | Currently sent only with SYNCHRONIZE, CLOSE, and RESET, where it is required, and with ECHO, where it is required for a ping. The signature uses the Destination's SigningPrivateKey to sign the entire header and payload with the space in the option data field for the signature being set to all zeroes. Prior to release 0.9.11, the signature was always 40 bytes. As of release 0.9.11, the signature may be variable-length, see below for details. |
| 4 | SIGNATURE_REQUESTED | -- | -- | Unused. Requests every packet in the other direction to have SIGNATURE_INCLUDED |
| 5 | FROM_INCLUDED | 2 | 387+ byte Destination | Currently sent only with SYNCHRONIZE, where it is required, and with ECHO, where it is required for a ping. Prior to release 0.9.20, due to a bug, must also be sent with RESET. |
| 6 | DELAY_REQUESTED | 1 | 2 byte Integer | Optional delay. How many milliseconds the sender of this packet wants the recipient to wait before sending any more data. A value greater than 60000 indicates choking. A value of 0 requests an immediate ack. |
| 7 | MAX_PACKET_SIZE_INCLUDED | 3 | 2 byte Integer | The maximum length of the payload. Send with SYNCHRONIZE. |
| 8 | PROFILE_INTERACTIVE | -- | -- | Unused or ignored; the interactive profile is unimplemented. |
| 9 | ECHO | -- | -- | Unused except by ping programs. If set, most other options are ignored. See the streaming docs. |
| 10 | NO_ACK | -- | -- | This flag simply tells the recipient to ignore the ackThrough field in the header. Currently set in the initial SYN packet, otherwise the ackThrough field is always valid. Note that this does not save any space, the ackThrough field is before the flags and is always present. |
| 11 | OFFLINE_SIGNATURE | 4 | variable length OfflineSig | Contains the offline signature section from LS2. See proposal 123 and the common structures specification. FROM_INCLUDED must also be set. Contains an OfflineSig: 1) Expires timestamp (4 bytes, seconds since epoch, rolls over in 2106) 2) Transient sig type (2 bytes) 3) Transient SigningPublicKey (length as implied by sig type) 4) Signature of expires timestamp, transient sig type, and public key, by the destination public key. Length of sig as implied by the destination public key sig type. |
| 12-15 | unused | Set to zero for compatibility with future uses. |
在 0.9.11 版本发布之前,选项字段中的签名始终是 40 字节。
从 0.9.11 版本开始,签名长度是可变的。签名类型和长度是从 FROM_INCLUDED 选项中使用的密钥类型和签名 文档中推断出来的。
从 0.9.39 版本开始,支持 OFFLINE_SIGNATURE 选项。如果存在此选项,则使用临时的 SigningPublicKey 来验证任何已签名的数据包,签名长度和类型从选项中的临时 SigningPublicKey 推断得出。
当数据包同时包含 FROM_INCLUDED 和 SIGNATURE_INCLUDED(如在 SYNCHRONIZE 中)时,可以直接进行推断。
当数据包不包含 FROM_INCLUDED 时,必须从之前的 SYNCHRONIZE 数据包中进行推断。
当数据包不包含 FROM_INCLUDED,且之前没有 SYNCHRONIZE 数据包时(例如游离的 CLOSE 或 RESET 数据包),可以从剩余选项的长度推断出这一点(因为 SIGNATURE_INCLUDED 是最后一个选项),但数据包可能会被丢弃,因为没有可用的 FROM 来验证签名。如果将来定义了更多选项字段,必须将它们考虑在内。
重放防护
为了防止 Bob 通过存储从 Alice 收到的有效签名 SYNCHRONIZE 数据包并稍后将其发送给受害者 Charlie 来进行重放攻击,Alice 必须在 SYNCHRONIZE 数据包中包含 Bob 的目标哈希值,如下所示:
Set NACK count field to 8
Set the NACKs field to Bob's 32-byte destination hash
收到SYNCHRONIZE后,如果NACK count字段为8,Bob必须将NACKs字段解释为32字节的目标哈希,并且必须验证它与他的目标哈希匹配。他还必须像往常一样验证数据包的签名,因为签名覆盖整个数据包,包括NACK count和NACKs字段。如果NACK count为8且NACKs字段不匹配,Bob必须丢弃该数据包。
这是版本 0.9.58 及更高版本所必需的。这与旧版本向后兼容,因为在 SYNCHRONIZE 数据包中不期望出现 NACK。目标节点不知道也无法知道对端正在运行什么版本。
从Bob发送给Alice的SYNCHRONIZE ACK数据包无需更改;不要在该数据包中包含NACK。
参考资料
- [Destination] Destination
- [Integer] Integer
- [OfflineSig] OfflineSignature
- [Signature] Signature
- [SigningPrivateKey] SigningPrivateKey
- [SigningPublicKey] SigningPublicKey
- [STREAMING] 流媒体库