bt协议

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 字典,描述种子内包含的文件列表信息,这里有两种类型,一是单文件的,二是多文件的,具体看后面的说明。
  • announce 字节串,描述 Tracker 的 URL。
  • announce-list 列表,可选,这是一个对官方规范的扩展项,提供后向兼容。
  • creation date 字节串,可选,这是一个UNIX时间戳,表示种子文件的创建时间。
  • comment 字节串,可选,自由描述字段,一般描述种子的制作者。
  • created by 字节串,可选,描述用于制作这个种子文件的程序。
  • encoding 字节串,可选,描述 info.pieces 字段的编码方式。

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

  • piece length 整数,表示一个分片的长度(单位:字节),称之为 分片单位
  • pieces 字节串,是由多个分片的 SHA-1校验码(20字节/个) 拼凑而成的字节串,因此其长度总是为20的倍数。
  • private 整数,可选,如果这个值被置为1,那么 BT客户端 必须通过向 种子文件 中指定的 Tracker 汇报自身的存在,从而获取其它 伙伴 的信息。反之如果置0客户端 可以通过其它方法获取其它伙伴,例如 PEXDHT。因此,private 字段也可以理解为“禁止通过其它途径获取伙伴信息”。

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

  • name 字节串,种子内包含的唯一文件的名称,这不是强制性的命名,仅作参考。(下载时可以修改保存的文件名)
  • length 整数,种子内包含的唯一文件的大小,单位是字节。
  • md5sum 字节串,可选,这是一个32位的16进制字符串,表示种子内包含的唯一文件的 MD5 校验值。尽管几乎所有BT客户端都未使用到这个字段,但是它仍被保留作为兼容性字段

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

  • name 字节串,种子内所有文件的总名称,BT客户端下载时默认使用它作为资源的目录名称,同理,这不是强制性的命名,仅作参考。(下载时可以修改保存的目录名)

  • files列表,这是一个由多个字典组成的列表,每个字典对应一个文件的信息,这些字典的格式如下:

  • length 整数,文件的大小,单位是字节。
  • md5sum 字节串,可选,这是一个32位的16进制字符串,表示该文件的 MD5 校验值。尽管几乎所有BT客户端都未使用到这个字段,但是它仍被保留作为兼容性字段
  • path 列表 这是一个特殊的文件路径表示方式。假设一个文件在种子内对应的相对路径是a/bb/ccc/hello.txt,那么将其根据 / 分割开,得到顺序列表 [ 'a', 'bb', 'ccc', 'hello.txt' ],经过 BEncoding 编码后就是 l1:a2:bb3:ccc9:hello.txte

Tracker服务器

一般有http和udp两种

入参

  • info_hash:元信息文件中 20 字节的 SHA-1 散列值。注意此值会进入编码字典中,如上述的信息关键字的定义所述。与不需编码的 peer_id 相比,它总是被 URL 编码。
  • peer_id:客户端 ID ,客户端用来唯一标识自己 ID 的 20 字节的串,它在客户端启动时生成。允许为任何值,包括二进制数据。目前没有特定的算法来生成客户端 ID。但是,人们会认为它至少对于自己的本地机器是唯一的,从而应该像进程 ID 一样合并数据,也可能在启动时由时标记录。见本区域下面的一般客户端编码的 peer_id。
  • port:客户端监听的端口号。BitTorrent 所使用的典型端口是 6881-6889。如果此范围的端口都无效,可以选择其他的。
  • uploaded:从客户端发送“已开始”事件到服务器算起的上传总量,数值采用 10 进制的 ASCII。对于没有在官方规范明确指出的,该值应为已上传的字节总数。
  • downloaded:从客户端发送“已开始”事件到服务器算起的下载总量,数值采用 10 进制的 ASCII。对于没有在官方规范明确指出的,该值应为已下载的字节总数。
  • left:客户端需要下载的字节数,以 10 进制 ASCII 编码。
  • no_peer_id:客户端接受一个紧密的响应。客户端列表由客户端串代替,此串中每个客户端都编码成 6 字节。前 4 字节是主机名(以网络的字节顺序),后两个字节是端口号(同样以网络字节的顺序)。
  • event:如果被指定,则是已开始已完成已停止中的一个,或者为空(表示未指定)。如果未指定,此请求为常规时间间隔中的一次运行。
    • started:向服务器发送的第一个请求,必须包含开始值的事件关键字。
    • stopped:如果客户端关机则须发送到服务器上。
    • completed:完成下载时必须发送到服务器上。但是,当客户端启动时下载完成度为 100%(即:做种中)则不会发送。可能这是允许服务器增加“已完成下载”的方法。
  • ip:可选。客户端的真实 IP 地址,以点分四元组格式或 RFC3513 中定义的 16 进制 IPv6 地址。注意:大体上此参数没有客户端地址重要,它能由 IP 地址决定,HTTP 请求也来自该处。仅在请求参与的 IP 地址不是客户端的 IP 地址的情况下才需要。这种情况发生在客户端通过代理服务器与服务器进行通信的情形。当客户端和服务器同时处在本地 NAT 网关时也需要。原因是服务器会发出客户端的内部地址(RFC1918),这是不可到达的。所以客户端必须清楚地把自己的外部可到达的 IP 地址发送到其他客户端中。不同的服务器对此参数的解释有所不同。某些只有当请求参与的 IP 地址属于 RFC1918 时才允许。有些无条件允许,但有些则完全忽略。如果使用 IPv6 地址(如:2001:db8:1:2::100),则表示客户端能通过 IPv6 进行通信。
  • numwant:可选。客户端想从服务器接收的用户数目。允许此值为“0”。如果不用此项,则默认值为 50 个用户。
  • key:可选。一个不与任何用户共享的另外的标识。当 IP 地址改变后,允许客户端证明它们的标识。
  • trackerid:可选。如果先前发布包含服务器的 id,它应放在这里。

响应

  • failure reason:如果当前使用此值,则其余关键字不会使用。该值是可读的错误消息,包括请求失败的原因。(字符串)
  • warning message:(新)与失败原因相似,但响应仍然会被正常处理。警告消息看起来像错误。
  • interval:以秒计算,是客户端发送规则请求到服务器之后等待的时间。(强制)
  • min interval:最小发布时间间隔。当前客户重发间隔不能小于此值。
  • tracker id:一个客户端应在下一个通告发回的字符串。如果没有该值,先前通告会发出一个服务器 id ,不要丢弃旧的值,一直使用它。
  • complete:拥有完整文件的用户数,即做种者(整数)
  • incomplete:非种子用户的数目,也叫“吸血者”(整数)
  • peers:是字典的列表,每个值都有如下的关键字:
    • peer id:用户的自选择 ID,如上述用来发送服务器请求的(字符串)
    • ip:用户的 IP 地址(IPv4 或 IPv6 格式)或域名(字符串)
    • port:用户的端口号(整数)

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,425评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,058评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,186评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,848评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,249评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,554评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,830评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,536评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,239评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,505评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,004评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,346评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,999评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,060评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,821评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,574评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,480评论 2 267

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,099评论 18 139
  • 前言 做了一个磁力链接和BT种子的搜索引擎 {Magnet & Torrent},因此把 DHT 协议重新看了一遍...
    justjavac阅读 8,229评论 1 24
  • 今早六点,天天还没亮,独自从宝石山庄南门出发,漫步草山。 草山的树林。 草山的朝霞。 传...
    好心情_4dea阅读 476评论 0 0
  • 小鸭子 铁路边有一个小湖 小湖里有一群小鸭子 小鸭子在湖里 追呀追闹啊闹 不管铁路向何方 一列一列的火车 连着车里...
    路雨飞飞阅读 396评论 10 3
  • 我如此的期待你的到来,虽然我内心是如此的清楚,这对于你不公平,我的孩子! 我曾一度希望自己做好所有准备,变成理想中...
    病小喵阅读 235评论 0 0