*本文原创作者:追影人
“种子”是生命的起点,是未来的希望,同时也解决了无数宅男腐女的寂寞时光。本文将带领各位童鞋了解BT种子(torrent)及P2P网络的运行机制,教您如何更加科学的搜索热门种子资源。
早些时期,文件下载一般都由专门的文件服务器作为下载源,统一对客户机提供下载服务。这种集中式下载方式存在着天然缺陷,当服务器宕机后,将会影响所有用户的下载;
另外,多客户同时进行下载,会因为服务器带宽有限,分配给每个客户机的网速很低,从而出现下图这种痛心疾首的状况。
显然这极大影响了求片心切童鞋的心情,在这用户至上的时代,为了改善这一缺陷,提高用户体验,服务商不得不增加服务器的数量,以应对大流量下载。
但随着互联网的迅速普及,文件数量和体积成指数增长,服务商已经无法承担无限扩增的服务器的成本,尤其对于一些媒体资源服务商,这种状况更加突出。
既然该问题的瓶颈在于服务商,那么是否可以对客户端进行改进?P2P的分布式下载方式较好解决了该问题。
P2P(peer-to-peer)网络,顾名思义,网络中的节点角色对等,节点即是客户端又是服务器,彼此在进行文件下载时可以直接访问无须经过其他中间实体,没有任何“中间商”(NAT后的节点需要进行UDP穿透)。
整个网络“一般”不依赖专用的集中服务器(请注意此处所加的引号,这里并非真正意义上的完全不需要,而是需要一些辅助服务器,后续我们将介绍),也没有专用的工作站,在网络中进行资源下载、查询、响应时完全依赖于各个节点。
P2P网络的出现,改变了互联网以大网络服务商为中心的状态,重新回到了“非中心化”,把权力交还了用户。同时,P2P网络以可扩展、耐攻击、高容错、高性价比等优势迅速普及。
P2P网络中节点角色对等,那么如何查找资源成为关键。早期解决这一问题,是由tracker服务器提供资源位置信息。当客户端需要下载资源时,先链接tracker服务器,报告自身信息,从而得到持有该资源的其他节点信息。
Tracker服务器对所有的资源持有者信息进行统一维护,当收到下载请求后,将请求者信息加入到最新的下载资源节点列表中。
一定程度上,tracker服务器起到了中心节点的作用,维护着全网的资源位置。后来,由于法律风险问题以及版权争议,很多tracker服务器被强制关闭,直接影响了网络的正常运行。
为此,DHT(Distributed Hash Table,分布式哈希表)网络诞生,目前很多P2P软件均采用tracker模式和DHT模式相结合的下载方式。
DHT网络中,所有节点的角色对等,各节点即是信息消费者又是信息生产者,路由功能完全由节点间扩散完成。DHT网络在节点路由和资源查询方面使用的最著名的算法便是kademlia算法(简称KAD)。
首先我们先认识两个术语:
Peer:”peer”节点实现了BT协议,使用TCP协议,用于资源文件的传输; node:”node”节点用于实现DHT协议,使用UDP协议,用于节点的路由管理和资源位置的查询。
在实际应用中,peer和node一般都位于同一个物理节点上,我们可以将其理解为两个不同的服务,前者用于资源文件的下载,后者用于DHT网络节点位置的查询以及资源文件所在peer位置的查询定位。
KAD协议主要用于DHT网络的资源查询,由于网络中节点和资源非常众多,而DHT网络中又没有集中式的路由管理节点,所以网络中的每一个节点都需要存储路由信息。
将整个网络的资源信息存储在每一个节点上显然是不现实的,因此每一个节点只存储部分资源信息即可。
标识
KAD协议利用SHA-1算法为node节点随机分配一个全局唯一的nodeID标识,长度为160bit,同时也对资源文件进行计算,也生成一个160bit的标识infohashes。
距离
节点之间的距离由nodeID异或计算。即distance(A,B)=|A xor B|
路由
每一个节点都保存有一个路由表,该路由表以K-buckets(k-桶)的形式存在,每一个bucket对应一个nodeID范围,涵盖了0-2^160的所有范围的ID。
极限情况下,路由表中会有160个k桶,每一个k桶内所放置的节点与本节点的距离如上图所示,且k桶内的节点数目最多不超过k个。
节点通常保存的路由信息并不能完全填充上面的160个k桶,所以节点在初始化时,k桶只有1个,范围覆盖0-2^160,随着后续节点路由信息的不断加入,路由信息数超过k时,k桶便会分裂成两个,每一个新桶的范围都变为原桶的一半,第一个为0-2^159,第二个为2^159-2^160,迭代分裂。
资源
节点持有资源时,需要尽可能多的通知其他节点,以便于其他节点的查询。节点会将自已的位置通知给那些nodeID和资源文件infohashes接近的节点。
这样在网络中查询资源时,只需要去查找资源infohashes附近的节点即可找到资源文件的所在位置信息。
请求
ping:测试节点是否在线。 find_node:发送节点查询请求。 find_value(get_peers):查找资源文件所在位置。 store (announce_peer):将资源文件所在位置通知给目标节点用于其存储。
从KAD协议运行过程可见,在查找资源时,非常重要的一个要素就是文件所对应的infohashes。由于infohashes只是一段160bit的hash值,用户无法从中得到任何明文信息,所以设计者为其添加了其他附属信息,形成了一个文本文件,即种子文件,通常以.torrent作为后缀名。
种子文件又称"Metainfo file",里面存储有关于下载内容的tracker服务器地址、文件长度、资源SHA1值等内容。它由Bencode编码组成,且字符串是用UTF-8编码。
种子文件的格式
文件以字典形式存储内容,具体有如下关键字:
announce:tracker服务器的URL
announce-list(可选):备用tracker服务器列表
creation date(可选):种子创建的时间,以unix时间戳形式存在
comment(可选):备注
created by(可选):创建人或创建程序的信息
info:一个字典结构,包含文件的主要信息,为分二种情况:单文件结构或多文件结构
nodes:最后的一个字段是nodes字段,这个字段包含一系列ip和相应端口的列表,是用于连接DHT初始node。
单文件结构如下:
length:文件长度,单位字节(整数)
md5sum(可选):长32个字符的文件的MD5校验和,BT不使用这个值,只是为了兼容一些程序所保留(字符串)
name:文件名(字符串)
piece length:每个块的大小,单位字节(整数)
pieces:每个块的20个字节的SHA1 Hash的值(二进制格式)
多文件结构如下:
files:一个字典结构
length:文件长度,单位字节(整数)
md5sum(可选):同单文件结构中相同
path:文件的路径和名字,是一个列表结构,如/test/test.txt 列表为l4:test8test.txte
name:最上层的目录名字(字符串)
piece length:同单文件结构中相同
pieces:同单文件结构中相同
细心的同学发现,整个种子文件中并没有出现20字节的infohashes,那么下载器是如何通过种子文件去tracker查询该文件呢?难道是通过文件名称?
答案是否定的。以文件名的方式去唯一标定资源,很大概率会发生同名冲突,因此BT协议利用种子文件中的内容计算出infohashes值进行唯一标定。
计算时,从种子文件info字段开始(不包含"info"这四个字节),一直到nodes字段为止(不包含"nodes"这5个字节和nodes前边表示nodes字段长度的"5:"这两个字节),对中间的内容进行SHA-1计算形成infohashes值。
下图为利用某种子搜索平台搜索《变形金刚4:绝迹重生》(英文名:Transformers: Age of Extinction)的结果。
进入某种子链接的详细页面,我们可以看到网站对种子的相关关键字做了解析。
下载该种子,利用notepad将其打开,可见其中的内容如下。
获得种子文件后,下一步关键是如何找到下载源(即资源的存储位置)。第一代P2P网络以tracker服务器作为中心节点,为客户端提供下载源查询服务。
该过程大致如下:
1、客户端通过对种子文件的解析和计算,获得tracker服务器列表和文件的infohashes值; 2、客户端通过http协议向服务器请求该infohashes对应文件资源的下载源peers列表; 3、tracker服务器会响应该查询请求,返回可用下载源peer的ID、IP、PORT等信息; 4、客户端得到peers列表后,进行点对点的文件下载。
实践出真理,我们依旧举个栗子。
使用迅雷打开上一节我们获取的种子文件。
切换到“属性设置”页面,可以看到tracker服务器列表。
开始下载后,针对tracker服务器列表发送DNS查询请求。
这是其中的一台tracker服务器DNS查询记录。
客户端对该tracker发出的http请求,用于tracker服务器的peers获取。
Tracker查询
● info_hash:.torrent文件中的infohashes,共20字节。 ● peer_id:客户端ID,共20字节。 ● ip:可选,IP地址,没有的话服务器会自己找到。 ● port:监听端口。 ● uploaded/downloaded:上传/下载的字节数(从客户端向Tracker服务器发送”started”开始计算,用于断点续传) ● left:还需下载的字节数。 ● numwant:可选。客户端希望从Tracker服务器得到的对等方的数目。 ● key:可选。一个扩展的唯一性标识,即使改变了IP地址,也可以使用该字段标识该客户端。 ● compact:压缩标志。如果值为1表示接受压缩格式的对等方列表,即用6byte表示一个对等方 (前4byte表示IP地址,后2byte表示端口号);值为0表示不接受。
Tracker响应
Tracker服务器响应是用Bencoding编码的字典。
● 如果响应中有关键字failure reason,则表示查询失败,其值为失败原因字符串。 ● 否则有两个关键字: Interval: 两次发送请求的时间间隔 Peers: 一个字典的列表,每个字典包括一下关键字Peer Id , IP , Port,分别对应Peer所选择的ID, IP地址。
P2P下载方式以其诸多优势,碾压传统的集中式下载,迅速普及,先后出现多款P2P下载软件。随着用户量的激增,用户生态逐渐复杂,各类问题也相应出现。文件污染、版权问题、犯罪等问题,使得相关部门不得不对P2P网络下手,一些国家还逮捕了相关作者。
虽然P2P网络为对等网络,下载过程不需要中心服务器,但是在查询资源peers时,需要tracker服务器的辅助,因此整个网络又退回到了拥有中心节点的状态。‘
相关部门也持着“挑软柿子捏”的心态,强制关闭了大量tracker服务器,导致很多资源都无法正常下载,P2P的下载方式也陷入了低谷。
此时,第二节中所介绍的DHT网络闪亮登场,可谓是给P2P下载网络施加了一把肥料。该网络无需tracker中心服务器,所有的peers列表信息都分布在网络中的各个节点上,进一步增强了网络的鲁棒性,P2P下载也由此进入2.0时代。
有关DHT网络的情况在第二节已经介绍了一些,下面重点介绍torrent文件如何和DHT网络结合使用。
一个无tracker服务器的种子文件不包含tracker服务器列表,而是存储着一些节点信息,其内容为torrent创建者的路由表中K个nodeID最接近infohashes的nodes。由此可以看出,在DHT网络中最关键的步骤是让客户端找到网络中的可用节点。
当一个新的客户节点首次试图加入DHT网络时,需要做如下三件事:
1、获知一个已经加入DHT网络的节点信息,并将其加入自己的k-buckets; 2、向该节点发起一次针对自己NodeID的节点查询请求,从而通过该节点获取一系列与自己距离邻近的其他节点的信息; 3、刷新所有的k-bucket,保证自己所获得的节点信息全部都是可用的。
而在第一个步骤中,节点一般通过如下方式获取已知节点信息:
1、种子文件中预置; 2、客户端中预置有长期稳定在线的节点信息; 3、从公网中的DHT服务器获取在线节点信息,例如router.bittorrent.com: 6881,router.utorrent.com:6881,router.bitcomet.com: 6881,dht.transmissionbt.com:6881
节点加入DHT网络后,通过find_value请求携带种子文件的infohashes值查询资源所在的位置,如果被查询的节点持有该资源的相关源信息,则会返回一个token,并将下载源的ID、IP和PORT等信息返回给客户端。
此时客户端便开始从下载源下载资源,同时该客户端也成为新的下载源,为了能够被其他下载客户查询到,需要将自身的信息扩散。客户端会携带刚才的token和自己的地址信息,以store请求的形式向之前的查询节点发送请求,将自己的信息存储在查询节点上。
随着BT服务器的大量关闭,导致很多种子文件无法获取。既然DHT网络的资源查询只需要infohashes即可,那么种子文件便可以简化成一个链接,这便是磁力链接(Magnet links)。
磁力链接是以“magnet:?xt=urn:btih:”开头的字符串,后面则是资源文件的infohashes值。
magnet:?xt=urn:btih:D3F7987EDF395104240AA16B30564B7372E55FFA
该链接为变形金刚4的磁力链接,是从迅雷下载中直接复制得到。由于HASH是不可逆的,所以从磁力链接上不能倒退出种子文件的信息,需要借助第三方种子库完成该转换。
迅雷种子库hxxp://bt.box.n0808.com提供该服务,转换时需要访问hxxp://bt.box.n0808.com/D3/FA/D3F7987EDF395104240AA16B30564B7372E55FFA.torrent即可下载对应的种子文件,其中的/D3/FA分别为infohashes的第一个字节后末尾字节。
我们在使用迅雷打开磁力链接进行下载时,迅雷会先从种子库中获取种子,得到具体文件信息后再进行下载。
迅雷之所以这样做,而非直接使用infohashes去DHT网络查询,也是为了给客户展示更过文件信息,提供良好客户体验,而不是下载时只能看到一个以HASH值为名的文件。
基于DHT网络的开放性,所有节点都在不断的加入和退出,而不需要特殊的认证机制,因此这也给DHT网络带来了诸多安全隐患。
1. DHT网络没有可信的认证中心,提供身份认证、通信加密等服务; 2.DHT网络的节点的NodeID虽然是随机生成,但是并没有严格的唯一性认证,容易被身份伪造; 3.DHT网络的节点对于路由消息的来源和内容无安全判断,可能导致路由表反射攻击和路由表污染攻击; 4.DHT网络对于节点发布的资源信息的来源和内容无安全判断,可能导致资源索引污染攻击;
因此,DHT网络可能会遭受多种攻击,例如Sybil攻击、Eclipse攻击、路由表攻击、DDoS攻击等。
DHT爬虫便是一个很好的说明,其利用DHT的开放性,将自己伪装成一个节点,收集其他节点的find_node、find_value、store等请求,从而获取到资源信息。如果将大批僵尸节点伪装为DHT节点加入DHT网络,对路由表和资源索引进行攻击,则会直接影响到整个网络的安全运行。
本文从种子文件出发,简要介绍了P2P网络的发展历程,KAD协议、DHT网络、种子文件、磁力链接的基本知识,并指出DHT网络的脆弱性。
由于版权的问题,P2P网络从一开始就备受争议,版权组织和软件作者进行了一次次的交锋,从tracker服务器的关闭到磁力链接的诞生,这都是交锋后的产物,那么P2P的3.0时代会是怎么样呢?我们拭目以待。
DHT Protocol http://www.bittorrent.org/beps/bep_0005.html
BT(带中心Tracker)通信协议的分析 http://blog.chinaunix.net/uid-26548237-id-3056731.html
百度百科-磁力链接
对BitTorrent通信协议的分析与检测 http://www.dns001.com/tech/content-47-27541-1.html
B编码以及BT种子文件分析 http://www.cnblogs.com/DxSoft/archive/2012/02/11/2346314.html
* 作者:追影人,本文属FreeBuf原创奖励计划文章,未经许可禁止转载