前序文章:
前文内容回顾:
BitTorrent 是一种用于分发文件的协议,元数据文件采用 bencode 编码,分片进行 SHA-1 哈希计算比对,并介绍元数据文件数据结构,通过 HTTP 请求由 Trakcer 交换节点信息,节点直接直接进行通讯。
分布式哈希表(DHT)中,每个节点有自己的 ID 和路由表,通过 KRPC 在 DHT 中可以获取指定信息哈希对应的下载者信息,元数据传输拓展基于拓展协议,目的在对等节点之间传输元数据信息,使得磁铁链接(通过信息哈希等信息)获取元数据成为可能。
既然已经完成了 DHT 的分析,顺带把和 DHT 经常一起出现的 PEX 和本地服务发现一起讨论,虽然还没有讨论 IPv6 的内容,本部分的内容对 IPv6 没有特殊的处理,既然都看到这里了,应该可以认为大家具备理解能力了吧。
本文内容基于 BEP11 (版本7ad40d1b62068015b7b846e7d248f3770d0e9b6a)和 BEP14(版本023256c7581a4bed356e47caf8632be2834211bd) 完成,需要注意,该部分协议很可能发生变化,推荐结合最新协议进行分析。
安全问题应该放在最开始部分来进行阐述,无论是 DHT 还是 PEX 甚至本地服务发现,都存在着被恶意利用的风险,攻击者可利用这些协议来恶意宣告节点地址来实现 DDOS 攻击,故应该认为其获取到的节点信息是不可信且存在恶意的,为了缓解这些情况,应避免从单一节点获取所有对等连接信息,忽略同一地址的不同端口,以及结合 BEP40 中的相关技术进行处理。
在连接上其他节点后,对等点交换是除了之前提到的 Tracker 和 DHT 外的另一种对等点发现机制,它的实现基于上一篇文章提到的拓展协议,其拓展标记为 ut_pex
,如下述是一个支持 PEX 的拓展的握手信息,其申明了使用拓展信息 ID 1 为 PEX 使用的信息 ID。
{
"m": {
"ut_pex", 1,
},
"p": 6881,
"v": "QCloud_rand 1",
}
完成拓展握手后,节点之间便可以发送 PEX 信息,其消息负载如下:
{
"added": "",
"added.f": "", // BitFlag 标志位
"added6":"",
"added6.f": "", // BitFlag 标志位
"dropped": "",
"dropped6": "",
}
added、added6、dropped、dropped6 四个标记中至少应该存在一个。除标志位外,其他内容均为紧凑格式的字符串,当成功建立连接,节点被添加到 added 中,当建立的连接断开,节点被移动到 dropped 中,added 和 dropped 都应该在适当的时候进行发送,不发送 dropped 是不符合规范的,这有利于提高 PEX 有效性并一定程度上规避 DDOS 攻击分风险。标志位 BitFlags 内容和说明如下:
标识 | 说明 |
---|---|
0x01 | 建议加密连接 |
0x02 | 仅上传(做种状态) |
0x04 | 支持 UTP |
0x08 | 支持 ut_holepunch |
0x10 | 传出连接且对等方可达 |
PEX 发送的频率不需要很高,通常没分钟不超过 1 次发送,握手后也不需要立即发送 PEX 消息,added 和 dropped 中不应包含重复项,除了首次发送的数据,added 和 dropped 的节点数量不应该超过 50 个,客户端应主动断开严重违反规定的连接。
很明显,当一个资源不活跃、做种较多的时又或 IPv4 和 IPv6 选择性断开会导致 PEX 效率低下,所以如果客户端连接的客户端少于 25 个,则可以放宽活跃度要求,符合条件的连接即使已经断开,也可以放与 added 或 added6 中:
这一可以追溯最近断开的节点列表来填充 PEX 的规定对 IPv4 和 IPv6 列表单独生效。
下图是前文所述 Ubuntu 官方镜像的种子下载过程中的一条 PEX 消息的样例,首先进行了握手和拓展握手,随后对方(Transmission)返回了 PEX 信息,在图中对应的两个 HAVE 消息(绿框标注)之后的红框所标注的就是 一个 PEX 信息:
本地用户发现的实现实质是使用 239.192.152.143:6771 (org-local) 和 ff15::efc0:988f:6771 两个组播地址分别在 IPv4 和 IPv6 网络上广播类似 SSDP 的 LSD 公告信息:
BT-SEARCH * HTTP/1.1\r\n
Host: <host>\r\n
Port: <port>\r\n
Infohash: <ihash>\r\n
cookie: <cookie (optional)>\r\n
\r\n
\r\n
其中,一个组播可以包含多个连续的 Infohash ,以公告参与多个 torrent,但需要注意数据包长度,避免 MTU 导致拆包;cookie是一个私有值,方便发送客户端过滤掉自己发送的组播数据。同时需要注意组播地址比本地组播范围更广,应合理设置 IP_MULTICAST_TTL
。
参与组播的客户端应该在侦听 BitTorrent 连接的每个接口上每 5 分钟发送一个 LSD 公告,且每分钟发送的通告不应超过 1 个。如果超过 5 个 torrent 处于活动状态,除了前述的多个 infohash 的方式还可以循环宣布活动 torrent(部分早起实现不支持多个 Infohash 在同一个通告中),收到组播公告后,客户端必须根据 UDP 源地址确定可以联系远程客户端的 IP 地址。
私有种子通过私有 Trakcer 进行访问控制,访问受限的 torrent 称为私有 torrent。所有其他种子都是公共种子。为了促进共享,私有 Trakcer 通常会维护注册用户的统计数据,通常会对用户进行准入限制并通过控制返回节点来限制甚至阻止部分数据异常、仅下载不上传、不做种的用户以保障良好的社区生态。在前文创建元数据文件的实例中就出现过的私有种子,其实现方法在 info 中增加 private=1 的键值对来进行标明。
客户端获取声明为私有的元信息文件时,它必须仅向私有跟踪器发送 announce 信息,并必须仅建立从私有 Tracker 返回的对等点的连接,即使私有种子种声明了多个 Tracker,客户端也应该仅一次使用一个,且在故障切换时应断开目前建立的所有连接。
碎碎念:如果大家都遵循 BitTorrent,成为一个优秀的下载者,那私有跟踪器的存在作用就没那么大了,但由于早些年某些下载器的某些举动,造成了今天的现状。
既然都提到了多 Tracker ,就可以说明多 Tracker 拓展,这是对 BitTorrent 的一个拓展,在元数据中除了 announce 外,还可以有 announce-list 。内容为 Tracker URL 字符串的列表,如果客户端兼容,且存在 announce-list ,则 announce 应该倍忽略,即使未出现在 announce-list中。
如果没意外的话,文章还会继续写下去,还有一些内容希望和大家分享,不过剩下的内容已经不多了,更新之后的链接会放在这里:
Bittorrent 协议浅析(七)uTorrent 传输、穿透拓展和 UDP Tracker
最后,本文参加的征文活动广告:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。