前序文章:
- Bittorrent 协议浅析(一)元数据文件 https://cloud.tencent.com/developer/article/2332701
- Bittorrent 协议浅析(二)Tracker 和 对等节点https://cloud.tencent.com/developer/article/2333043
- Bittorrent 协议浅析(三)对等数据传输实例https://cloud.tencent.com/developer/article/2333677
- Bittorrent 协议浅析(四)分布式哈希 https://cloud.tencent.com/developer/article/2334440
- Bittorrent 协议浅析(五)拓展协议 及 元数据传输拓展 https://cloud.tencent.com/developer/article/2334776
前文内容回顾:
BitTorrent 是一种用于分发文件的协议,元数据文件采用 bencode 编码,分片进行 SHA-1 哈希计算比对,并介绍元数据文件数据结构,通过 HTTP 或 UDP 请求由 Trakcer 交换节点信息,节点之间直接建立 TCP 连接或建立基于 UDP 的 uTP 连接通讯。穿透拓展为在 NAT 后的节点连接提供了协助。
拓展协议中的元数据传输拓展可在节点之间传输元数据,PEX 拓展允许节点交换节点信息,DHT 可通过 KRPC 根据信息哈希获取节点,本地服务发现基于组播,在私有种子中这些内容均须禁用。
截至目前,所阐述和涉及的内容几乎都是基于 TCP 的 BitTorrent 实现。在部分网络环境下,通过 TCP 建立连接具有一定的局限性,过多的 TCP 连接会不公平的消耗网络资源,基于 UDP 的 uTorrent 和 穿透拓展能很好的解决这方面的问题,同时为位于 NAT 或防火墙后的下载器提供连接可能。
在前述文章中,通过 Sockit 工具模拟了基于 TCP 的 Bittorrent 请求,但 uTP 是一个基于 UDP 的协议,逐步构造请求进行分析存在较大难度,故直接通过 Wireshark 抓取一个连接对其进行分析。
分析使用前文所述的 Ubuntu 系统镜像进行连接,通过 WireShark 可以捕获到其通讯过程,来分析 uTP 的握手和数据传输。
注:笔者的设备安装了 Docker Desktop,其修改了 hosts 使 host.docker.internal 指向了网络出口 IP 地址。
首先通过 WireShark 开始抓取,并在获取到一定数据后停止,如前文所述,uTP 通过 UDP 进行数据传输,其数据报没有明显标识特征,故在 WireShark 中不会有分类,需要人工根据端口号和传输内容进行筛选判断,在符合条件 WireShark 数据上右键,选择解析为,设置为 BT-uTP 以通过 WireShark 对数据进行解析,如下图:
设置完成后,点击 OK,即可查看到对应数据包的分析,下图给出了其中一个连接的流和握手数据包:
为方便分析,这里再次给出第七部分文章中所给出的数据包结构:
0 4 8 16 24 32
+-------+-------+---------------+---------------+---------------+
| type | ver | extension | connection_id |
+-------+-------+---------------+---------------+---------------+
| timestamp_microseconds |
+---------------+---------------+---------------+---------------+
| timestamp_difference_microseconds |
+---------------+---------------+---------------+---------------+
| wnd_size |
+---------------+---------------+---------------+---------------+
| seq_nr | ack_nr |
+---------------+---------------+---------------+---------------+
现在来看这个数据流的第一个数据包:
这个数据包是 uTP 连接的握手包,由本地端口发起连接,
UDP 数据内容:
21 02 45 f9 22 30 32 fc 00 00 00 00 00 38 00 00 91 1a 3f 0e 00 08 00 00 00 00 00 00 00 00
包括的内容:
第二个数据包:
在收到握手数据包后,连接请求接收方发送一个状态数据包,其内容:
21 02 45 f9 22 30 32 fc 00 00 00 00 00 38 00 00 91 1a 3f 0e 00 08 00 00 00 00 00 00 00 00
接下来就可以传输数据了。
这里在测试过程中踩了一些坑,由于完成上述内容之前进行的测试将 Transmission 下载器的加密设置成了“优先加密”,故获取到的是加密后的数据,未能有效进行分析,将加密设置为允许加密,这样不会主动加密传出的连接,可以看到在 uTP 握手完成后的 BitTorrent 握手信息:
加密传输是一个有趣的内容,但分析较为复杂,目前为止我的了解也只停留在表面,加密传输这个内容并没有在任何一个 BEP 中进行提现,也没有在任何文档材料中出现,可以对其进行了解的,只能通过对其开源实现的分析,有兴趣的话可以重点关注:
在 libtorrent 的加密的实现主要在 bt_peer_connection.cpp
和 pe_crypto.cpp
中,重点可以关注这三个函数和相关实现:write_pe1_2_dhkey()
初始化加密握手,生成 Diffie-Hellman 密钥对,发送本地公钥;write_pe3_sync()
执行同步握手,生成共享密钥,设置 RC4 加密密钥,并发送同步请求;write_pe4_sync()
处理同步响应。
该部分内容通过分析一个实际的 uTP 数据传输来再次回顾 uTP 协议,虽然在这里结束这部分也是可以的,但还是增加一些其他内容吧,比如很多人注意到但又不太理解的超级种子。
超级做种模式是 BEP 草案所提出的,可能经常修改变化,请结合 BEP16 进行阅读。
在日常使用 BitTorrent下载器过程中,经常看到超级种子、超级做种模式的选项,那它到底是什么呢?在阅读这部分内容之前,强烈建议仔细阅读并理解Bittorrent 协议浅析(三)对等数据传输实例,熟悉节点在传输数据中所发生的数据内容。
当一个下载器在“超级做种模式”下运行时,它会伪装成一个没有数据的普通客户端。当其他节点连接时,它会通过 have 消息告诉客户端自己已经拥有一个未被发送过的片段。这会使节点仅尝试下载该片段,当客户端完成下载这个片段后,做种节点不会宣告拥有其他片段,直到之前发送的片段至少出现在另一个节点上,这就是超级做种模式。
超级种子减少了冗余数据的发送量,又限制了只下载不为集群做出贡献的节点下载。
通常是不应该使用这个模式和选项的,除了初始做种的下载器,其他节点不应该使用该模式。
在完成这系列文章过程中越发的发现,很多曾经以为很简单的东西,在实际实现过程中可能存在很多不确定因素,也并不是所有其他人或程序都会按约定的协议进行,有的内容似乎是约定俗称的,大家都大概知道是什么,应该怎么做,但并没有文档的记录形式。
到这里,理解 BitTorrent 在非Web做种情况下所必须掌握的内容都已经阐述完成了,还有一些应用并不是特别广泛或者影响不是很大的 BEP,以及一些有趣的实现还可以进一步进行探讨,后续如果有新的文章链接会在这里:
最后,本文参加的征文活动广告:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。