tracker

bt协议

2017-05-24  本文已影响173人  云烟1f3bca320ba6

BT协议

bt种子文件

编码 bencode

bencode 有 4 种数据类型: string, integer, list 和 dictionary。

  1. string

    e.g.: <字符串长度>:<字符串>

  2. integer

    e.g.: i<整数>e

  3. list

    e.g.: l数据1数据2数据3e

  4. dictionary

    e.g.: d[key1][value1][key2][value2][…]e,其中 key 必须是 string 而且按照字母顺序排序

种子文件结构

无论是单文件格式还是多文件格式种子文件,其 info 字段下都可以包含以下 3 个字段

当种子内仅包含一个文件的信息时,其 info 字段 内必须包括如下字段

当种子内包含多个文件的信息时,其 info 字段 内必须包括如下字段

Tracker服务器

一般有http和udp两种

入参

响应

DHT

概述 Overview

每个节点有一个全局唯一的标识符,作为 "node ID"。节点 ID 是一个随机选择的 160bit 空间,BitTorrent infohash[2] 也使用这样的 160bit 空间。 "距离"用来比较两个节点 ID 之间或者节点 ID 和 infohash 之间的"远近"。节点必须维护一个路由表,路由表中含有一部分其它节点的联系信息。其它节点距离自己越近时,路由表信息越详细。因此每个节点都知道 DHT 中离自己很"近"的节点的联系信息,而离自己非常远的 ID 的联系信息却知道的很少。

在 Kademlia 网络中,距离是通过异或(XOR)计算的,结果为无符号整数。distance(A, B) = |A xor B|,值越小表示越近。

当节点要为 torrent 寻找 peer 时,它将自己路由表中的节点 ID 和 torrent 的 infohash 进行"距离对比"。然后向路由表中离 infohash 最近的节点发送请求,问它们正在下载这个 torrent 的 peer 的联系信息。如果一个被联系的节点知道下载这个 torrent 的 peer 信息,那个 peer 的联系信息将被回复给当前节点。否则,那个被联系的节点则必须回复在它的路由表中离该 torrent 的 infohash 最近的节点的联系信息。最初的节点重复地请求比目标 infohash 更近的节点,直到不能再找到更近的节点为止。查询完了之后,客户端把自己作为一个 peer 插入到所有回复节点中离种子最近的那个节点中。

请求 peer 的返回值包含一个不透明的值,称之为"令牌(token)"。如果一个节点宣布它所控制的 peer 正在下载一个种子,它必须在回复请求节点的同时,附加上对方向我们发送的最近的"令牌(token)"。这样当一个节点试图"宣布"正在下载一个种子时,被请求的节点核对令牌和发出请求的节点的 IP 地址。这是为了防止恶意的主机登记其它主机的种子。由于令牌仅仅由请求节点返回给收到令牌的同一个节点,所以没有规定他的具体实现。但是令牌必须在一个规定的时间内被接受,超时后令牌则失效。在 BitTorrent 的实现中,token 是在 IP 地址后面连接一个 secret(通常是一个随机数),这个 secret 每五分钟改变一次,其中 token 在十分钟以内是可接受的。

路由表 Routing Table

每个节点维护一个路由表保存已知的好节点。路由表中的节点是用来作为在 DHT 中请求的起始点。路由表中的节点是在不断的向其他节点请求过程中,对方节点回复的。

并不是我们在请求过程中收到得节点都是平等的,有的节点是好的,而另一些则不是。许多使用 DHT 协议的节点都可以发送请求并接收回复,但是不能主动回复其他节点的请求。节点的路由表只包含已知的好节点,这很重要。好节点是指在过去的 15 分钟以内,曾经对我们的某一个请求给出过回复的节点,或者曾经对我们的请求给出过一个回复(不用在15分钟以内),并且在过去的 15 分钟给我们发送过请求。上述两种情况都可将节点视为好节点。在 15 分钟之后,对方没有上述 2 种情况发生,这个节点将变为可疑的。当节点不能给我们的一系列请求给出回复时,这个节点将变为坏的。相比那些未知状态的节点,已知的好节点会被给于更高的优先级。

路由表覆盖从 0 到 2^160 全部的节点 ID 空间。路由表又被划分为桶(bucket),每个桶包含一部分的 ID 空间。空的路由表只有一个桶,它的 ID 范围从 min=0 到 max=2^160。当 ID 为 N 的节点插入到表中时,它将被放到 ID 范围在 min <= N < max 的 桶 中。空的路由表只有一个桶,所以所有的节点都将被放到这个桶中。每个桶最多只能保存 K 个节点,当前 K=8。当一个桶放满了好节点之后,将不再允许新的节点加入,除非我们自身的节点 ID 在这个桶的范围内。在这样的情况下,这个桶将被分裂为 2 个新的桶,每个新桶的范围都是原来旧桶的一半。原来旧桶中的节点将被重新分配到这两个新的桶中。如果一个新表只有一个桶,这个包含整个范围的桶将总被分裂为 2 个新的桶,每个桶的覆盖范围从 0..2^159 和 2159..2160。

当桶装满了好节点,新的节点会被丢弃。一旦桶中的某个节点变为了坏的节点,那么我们就用新的节点来替换这个坏的节点。如果桶中有在 15 分钟内都没有活跃过的节点,我们将这样的节点视为可疑的节点,这时我们向最久没有联系的节点发送 ping。如果被 ping 的节点给出了回复,那么我们向下一个可疑的节点发送 ping,不断这样循环下去,直到有某一个节点没有给出 ping 的回复,或者当前桶中的所有节点都是好的(也就是所有节点都不是可疑节点,他们在过去 15 分钟内都有活动)。如果桶中的某个节点没有对我们的 ping 给出回复,我们最好再试一次(再发送一次 ping,因为这个节点也许仍然是活跃的,但由于网络拥塞,所以发生了丢包现象,注意 DHT 的包都是 UDP 的),而不是立即丢弃这个节点或者直接用新节点来替代它。这样,我们得路由表将充满稳定的长时间在线的节点。

每个桶都应该维持一个 lastchange 字段来表明桶中节点的"新鲜"度。当桶中的节点被 ping 并给出了回复,或者一个节点被加入到了桶,或者一个节点被新的节点所替代,桶的 lastchange 字段都应当被更新。如果一个桶的 lastchange 在过去的 15 分钟内都没有变化,那么我们将更新它。这个更新桶操作是这样完成的:从这个桶所覆盖的范围中随机选择一个 ID,并对这个 ID 执行 find_nodes查找操作。常常收到请求的节点通常不需要常常更新自己的桶,反之,不常常收到请求的节点常常需要周期性的执行更新所有桶的操作,这样才能保证当我们用到 DHT 的时候,里面有足够多的好的节点。

在插入第一个节点到路由表并启动服务后,这个节点应试着查找 DHT 中离自己更近的节点,这个查找工作是通过不断的发出find_node 消息给越来越近的节点来完成的,当不能找到更近的节点时,这个扩散工作就结束了。路由表应当被启动工作和客户端软件保存(也就是启动的时候从客户端中读取路由表信息,结束的时候客户端软件记录到文件中)。

协议消息

Kademlia协议共有四种消息

1. PING消息: 用来测试节点是否仍然在线
2. STORE消息: 在某个节点中存储一个键值对
3. FIND_NODE消息: 消息请求的接收者将返回自己桶中离请求键值最近的K个节点: 将请求者请求的节点HASH和自己的HASH进行XOR计算,将计算结果
4. FIND_VALUE消息: 与FIND_NODE一样,不过当请求的接收者存有请求者所请求的键的时候,它将返回相应键的值

DHT嗅探器的原理

DHT这种对等分布式网络在带来抗DDOS的优点的同时,也带来了一些缺点

1. 伪造攻击: 有些不听话的用户可能会在DHT网络里捣乱,譬如说撒谎,明明自己不是奥巴马,却偏说自己是奥巴马,这样会误导其他人无法正常获取想要的资源
2. 嗅探攻击: 另外,用户在DHT网络里的隐私可能会被窃听,因为在DHT网络里跟其他用户交换资源的时候,难免会暴露自己的IP地址,所以别人就会知道你有什么资源,你在请求什么资源了。这也是目前DHT网络里一直存在的一个弱点

参考:

https://wiki.theory.org/index.php/BitTorrentSpecification#Notes

https://fenying.gitbooks.io/bittorrent-specification-chinese-edition/content/

https://segmentfault.com/a/1190000002528378

http://www.cnblogs.com/LittleHann/p/6180296.html

上一篇 下一篇

猜你喜欢

热点阅读