btdad 磁力搜索原理(详解磁力链接与 DHT 网络)

磁力链接不是下载地址,而是用文件内容算出来的一串”数字指纹”。btdad 这类磁力搜索站点只用几十个字符就能定位到一个资源,靠的不是某台中心服务器,而是 BitTorrent 的 infohash 加 DHT 分布式网络。把这层原理拆开,就能解释两个长期困扰新手的现象:有的链接一直卡在”获取元数据”,有的显示名和真实内容对不上。

磁力链接从 magnet URI 到拿到数据的完整链路

磁力链接到底是什么

磁力链接(Magnet URI)是一种按内容寻址的标识符,严格说不属于 URL。URL 回答的是”去哪台机器取”,磁力链接回答的是”取什么东西”——它由文件内容的哈希值构成,任何持有该文件的人都能独立算出同一串值,不需要中心机构发放。

这个标准的草稿出现于 2002 年,初衷是把 eDonkey2000 的 ed2k: 与 Freenet 的 freenet: 两种 URI 格式做”厂商与项目中立化”的统一,并尽量贴近 IETF 官方的 URI 标准。一条典型磁力链接如下(为便于阅读做了换行,实际是一整行):

magnet:?xt=urn:btih:c12fe1c06bba254a9dc9f519b335aa7c1367a88a
       &dn=Big+Buck+Bunny
       &tr=udp%3A%2F%2Ftracker.example.com%3A6969

参数之间顺序无关,格式与 HTTP 末尾的查询字符串相同。解析时按 & 切分,每个键值对按第一个 = 切分(tracker 地址自身可能含 =,不能多切),值再做 URL 解码:%3A 还原成冒号,+ 还原成空格。常见参数的含义如下。

参数全称作用是否必填
xtexact topic内容的哈希 URN,如 urn:btih: 加 40 位十六进制必填
dndisplay name显示名,仅作界面提示选填
trtrackertracker 服务器地址,可重复出现选填
xlexact length文件总字节数提示选填
ws / xswebseed / exact sourceHTTP 直连下载的备用地址选填

这张表里有个容易踩的坑:dn 只是客户端显示用的提示,可以随意伪造,真正决定身份的只有 xt。搜索结果里那个漂亮的文件名,和哈希算出来的究竟是什么内容,两者之间没有任何绑定关系。

infohash 是怎么算出来的

infohash 是对种子文件里的 info 字典做 SHA-1 得到的 20 字节摘要,写成十六进制就是 40 个字符。info 字典里放着文件名、大小、分片长度(piece length)和每个分片的哈希串,唯独不含真实数据本身——哈希只覆盖元数据,改动其中任意一个字节,整串 infohash 都会跟着变。想自己验证,用下面这段脚本可以直接算出来:

import hashlib, bencodepy  # 安装:pip install bencodepy

with open("demo.torrent", "rb") as f:
    meta = bencodepy.decode(f.read())

info = bencodepy.encode(meta[b"info"])
infohash = hashlib.sha1(info).hexdigest()
print(infohash)  # 40 位十六进制,即磁力链接里 urn:btih: 后面的那串值

BitTorrent v1 与 v2 在哈希方案上的差异,值得单独拉出来对比。

维度v1v2
哈希算法SHA-1SHA-256
摘要长度20 字节(40 位十六进制)32 字节(64 位十六进制)
磁力前缀urn:btih:urn:btmh:
分片校验分片哈希平铺存放Merkle 树,叶节点固定 16 KiB 块
文件粒度整个种子一个哈希每个文件单独成树,可跨种子去重

v2 改用 SHA-256 的直接原因,是 SHA-1 已被证实存在碰撞风险。为了兼容只认 20 字节哈希的 DHT 与 tracker 报文结构,v2 在与这两类组件通信时会把 SHA-256 结果截断到 20 字节。v2 还引入了混合种子(hybrid torrent),同时携带两套哈希,让新老客户端能进同一个网络。

没有 tracker 时怎么找到同伴

DHT 网络替掉了 tracker 的角色,让每个客户端自己成为一台”小型 tracker”。BitTorrent 的 DHT 实现定义在 BEP-5 中,基于 Kademlia 算法跑在 UDP 之上,用四类 RPC 报文通信:ping、findnode、getpeers、announce_peer。它的寻址逻辑可以压缩成三句话:

  1. 每个节点随机生成 160 位 Node ID,与 infohash 处在同一个 160 位地址空间;
  2. 节点之间的”距离”用异或(XOR)计算,结果越小代表在地址空间上离目标哈希越近;
  3. 查询 get_peers 时,被问到的节点要么返回持有该资源的 peer 列表,要么返回它知道的、离目标更近的节点,请求方不断迭代逼近,直到找不到更近的节点为止。

路由表按距离前缀分成多个 k-bucket 维护,15 分钟内响应过请求的节点算”好节点”,连续多次不响应的会被剔除。为防止恶意节点替别人登记资源,announcepeer 必须带上此前 getpeers 拿到的 token,token 由被查询节点按 IP 生成并设有有效期。到这里,”不需要中心服务器”这句话才算有了具体的技术落点。

磁力搜索站点在这条链路上做什么

磁力搜索站点本身不存文件,它是一个”infohash 采集器 + 元数据索引器”。从一条磁力链接到一条可检索的索引,链路大致是这样走的:

  1. 在 DHT 网络里维持大量节点身份,监听 announce_peer 报文,持续收集 infohash;
  2. 对收集到的 infohash 主动发 get_peers,拿到正在做种或下载的 peer 地址;
  3. 与 peer 建立 TCP 连接,先做 BitTorrent 握手,在保留位里声明支持扩展协议(BEP-10);
  4. 通过扩展握手协商出 ut_metadata,再按 16 KiB 一片把 info 字典拉回来(BEP-9);
  5. 对拼装好的元数据做哈希校验,与 infohash 比对一致后才入库建索引。

第 5 步是整条链路的安全支点:infohash 是内容地址,peer 无法伪造一份哈希值恰好匹配的元数据。这也是为什么”论坛里贴的 40 个字符”在技术上与原始种子文件等价。反过来看,这条链路也解释了两个常见困惑——冷门资源搜不到,是因为没有任何 peer 在线,元数据无从获取;显示名与内容不符,是因为 dn 本就是未经验证的提示。

技术本身中立,边界要自己划清

磁力链接是中性技术,Linux 发行版镜像、开源数据集、游戏客户端补丁都在用它分发,能显著降低发布方的带宽压力。是否侵权取决于所传播内容的授权状态,与链接格式无关。

需要提醒的是,BitTorrent 协议本身不提供匿名性。同一个 swarm 里的参与者通常能看到彼此的 IP 地址。因此使用这类技术时,遵守所在地区的法律法规与内容授权要求,是使用者自己的责任。

常见问题(FAQ)

Q1:磁力链接和种子文件有什么区别?

种子文件自带完整元数据,磁力链接只带哈希,元数据需要从 DHT 网络里的 peer 处现取。

Q2:磁力链接为什么一直卡在获取元数据?

说明没找到持有该 infohash 元数据的在线 peer,网络里暂时没有可用来源。

Q3:磁力链接能隐藏下载者的 IP 吗?

不能。BitTorrent 协议本身不匿名,同一 swarm 内的参与者可以看到彼此的 IP 地址。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 qiqicto@qq.com 举报,一经查实,本站将立刻删除。
赞 (0)
拓扑大师的头像拓扑大师普通用户

相关推荐

返回顶部