MENU

【歪门邪道】BT下载的反吸血之路

August 1, 2025 • 瞎折腾

最近看到以183开头的IP地址在均匀地下载我tixati中挂的种子,虽然下载量不大,并且进度乍一看也没问题,但警觉的我意识到这不对劲,我可能又被人刷流量了。检查了一下IP黑名单,发现BTN的ip黑名单一直连接超时。想来想去,这样总不是个办法,还是得上正经的PeerBanHelper。于是,本文将记录我的折腾之路。

Tixati

Tixati一直是我最喜欢的BT下载软件之一,因为它好用,功能丰富,性能稳定,最重要的是还有跨平台支持,对于openSUSE来说,只需要安装一个rpm包即可。为了解决吸血和刷流量的问题,它自带一个IP屏蔽列表,所以我配置了BTN网络定期导出的IP黑名单,tixati会定期自动获取最新的列表并根据IP实行封禁。但这有个问题:btn网络的ip黑名单全都用的国外的服务器,有github,有cloudflare,还有jsdelivr。最近他们在tixati中全部都超时,获取不到。本打算弄个反向代理,但想来想去太麻烦了,并且BTN导出的ip黑名单总归有延迟,并且BTN规则列表的仓库也说了:

此项目不能作为唯一反吸血手段使用,它无法代替由反吸血程序提供的本地检测能力。它也并非是 PeerBanHelper 的核心 “全量” 数据。此项目的存在一切皆依赖于连接到 BTN 网络的用户。规则并不是大风吹来的
鼓励您使用在可能的情况下优先使用PeerBanHelper连接到 BTN 网络,以便向本仓库贡献数据。

任何已在反作弊辅助脚本、工具、程序中使用本项目提供的数据的朋友,请您考虑实现 BitTorrent Threat Network 标准规范,以便向网络提交数据。

本着支持开源项目以及「为众人抱薪者,不可使其冻毙于风雪」的指导思想,我开始更换到受BTN支持的bt下载器。

BiglyBT

BiglyBT是我第二喜欢的bt客户端,但很遗憾,在这次折腾中它没能成为我的最终选择。我喜欢这个客户端单纯是因为它是Java写的,但我也是Java开发者,我深知Java的弱点:调用C库。好巧不巧,BiglyBT就调用了GTK库来实现UI。具体来说,它通过一个名叫SWT的组件来调用系统的GTK库,它本身并不包含GTK二进制文件。而默认安装的3.8.0.2版本在openSUSE上有bug,每次我尝试调整库的列视图时,只要点保存就必定崩溃。经过一番调试,我发现是SWT的问题,因为updater提示无法自动更新SWT。我在这个issue中找到了一个3.8.0.3-B14的beta版,这个版本修复了SWT更新的问题,而更新好SWT之后,UI的bug解决了,不过还有新的问题。

在测试过程中,我注意到如果通过unraid的VM页面重启虚拟机,BiglyBT并不会收到关机信号并正常退出。重启之后自启动,会在右下角提示BiglyBT没有正常退出,而我观察到的问题是有些在seeding状态的种子,经过非正常退出之后会变成灰色的queued状态。在这种状态下并不会给他人上传,而我在文件中选择recheck强制重新检查文件后,这个种子又能重新seeding了。由于我的路由器ip会变化,而据我观察一些bt软件并不会更新获取到的ipv6地址,就导致路由器获取新的ip后,bt软件的联通性直接大幅下降。为了缓解这个问题,我在unraid中设定了脚本,每天凌晨在路由器重启半小时之后重启虚拟机,强制所有软件重新获取ipv6地址。如果每天重启都会随机导致一些种子无法正常seeding,对于我来说这还是挺严重的问题,因为我不可能每天都去检查nas上面软件的状态。

qBittorrent

qBittorrent并不是我最喜欢的bt软件,因为它ui有些简陋,并不像tixati那么花哨,功能上也没有BiglyBT那么丰富。但不得不说,因为ui简单,功能不复杂,因此这个软件运行起来确实稳定,并且也受BTN官方支持。

和BiglyBT需要使用sh脚本安装不同,openSUSE本身就有qBittorrent的包,所以直接用zypper安装即可。安装完成后配置起来也不难,大部分情况下默认设置都能工作得很好,BTN也能和它配合。

按理说事情就应该告一段落了,但我在测试下载新种子的时候发现qBittorrent无法写入任何数据。具体表现是开始下载种子后,直接提示错误,错误内容是Invalid argument。查看日志发现,具体错误原因与file_mmap这个函数有关。虽然这个函数是libtorrent的,但从过名字可以推断,这个函数应该是会调用Linux的mmap函数来将文件的一部分直接映射到内存,这样可以进行高性能的随机读写。而从目前的状况来看,读取验证哈希没有问题,但写入有问题,于是我开始怀疑unraid提供的挂载点。

我原本认为我是用的是virtiofs来将unraid的共享文件夹挂载到虚拟机里,于是就以此为出发点,开始研究virtiofs对于mmap的支持。经过一番搜索,我找到了Introduce allow-mmap flag这个合并请求。这个合并请求的内容是给virtiofs的服务端添加命令行选项来决定它是否允许mmap。既然都添加了cli开关了,那想必virtiofs应该是支持mmap才对。我想来想去,想不明白,总不能是我挂载选项写错了吧。于是打开/etc/fstab一看,啊?我没用virtiofs,用的是9p。合着我刚才跟空气斗智斗勇来着呗?

于是我花了两分钟在unraid中将挂载点从9p模式改成virtiofs,然后启动虚拟机,果不其然启动失败,因为fstab还是9p,改成virtiofs之后再次重启,qBittorrent一下子就好了。而且挂载点的读写性能也有显著的上升。我的ZFS卷采用3盘raidz1的vdev,一共有两个,总共6个盘位。之前不知何故,在读取文件验证哈希时,虚拟机内只能读到60MB/s,多个线程一起读也才勉强140MB/s,我当时以为是虚拟化的性能损失,就没太在意。现在从9p切换到了virtiofs,虚拟机内的读取性能可以达到683MB/s,差不多是这6块硬盘的极限了。

9p vs virtiofs

因为一开始配置挂载点的时候我也没有详细了解9p和virtiofs的区别,所以就选了默认的第一个,正好是9p。今天切换到virtiofs之后解决了问题,于是我想趁此机会了解一下二者的区别。这种时候gemini就派上了用场。

以下内容由gemini 2.5 flash生成,没用pro是因为充不起会员。请批判性地阅读以下内容,如果要做严肃用途的参考,请务必独立查证后使用。本文作者并不为以下段落的误导性信息负责。

根据Gemini 2.5 Flash所说,9p是Plan 9文件系统协议,最初是贝尔实验室在1992年开发。其核心设计理念是“一切皆文件”,即将各种系统组件(如窗口、网络连接、进程)都表示为文件,并通过统一的文件系统接口进行访问和操作 。在QEMU中(unraid系统使用的虚拟化后端),客户端使用9p协议主要通过virtio进行通讯。而9p本质上是一种网络协议 。虚拟机和宿主机之间的通信通过消息进行 。它采用客户端-服务器模型,其中客户端(虚拟机)发送请求消息(T-messages),服务器(宿主机)发送回复消息(R-messages) 。QEMU的9p服务器可以将I/O任务分派给工作线程,从而允许主线程处理其他请求,以实现并发处理 。

9p协议的“一切皆文件”理念,虽然对于Plan 9这样的分布式操作系统来说非常优雅,因为它通过分层命名空间暴露所有资源,但在面对现代应用程序对高级IO原语(例如mmap)的需求时,其局限性便显现出来 。mmap操作与传统的readwrite的字节流语义截然不同,它允许应用程序将文件内容直接映射到内存中进行访问,这是一种随机访问的高性能原语 ,而9p协议围绕流式文件的设计,使其难以在网络边界上高效且正确地表示和传输。这不光导致9p协议的IO性能存在瓶颈,更是导致9p无法完全实现unix文件系统语义的关键原因。即使QEMU的9p实现通过virtio技术来借助内核驱动和共享内存进行加速,其底层协议仍然是网络协议 。网络协议固有的消息序列化、反序列化以及即使在本地通信中也存在的上下文切换(vmexits)开销,限制了其性能。此外,9p协议在mmap支持方面存在具体限制。默认情况下,9p提供只读的mmap功能。这意味着,如果尝试以读写模式打开文件并进行mmap操作,后续的mmap可能会失败 。为了启用写入功能,需要在虚拟机客户端的挂载命令中明确指定cache选项,例如cache=mmapcache=fscache 。如果未启用CONFIG_9P_FSCACHE,内核侧客户端代码会使用generic_file_readonly_mmap,从而导致写操作的mmap失败 。对于qBittorrent这类需要频繁进行文件预分配和随机写入的应用,这种只读mmap的默认行为和对特定缓存选项的依赖,直接导致了下载种子时出现file_mmap的IO错误 。9p的性能也受到msize参数的显著影响,该参数定义了9p服务器和客户端之间最大消息大小 。在Linux内核5.15版本之前,默认的msize仅为8KB,导致性能表现不佳,有时甚至低至12MB/s 。尽管内核5.15及更高版本将默认msize提高到128KB,但对于大多数机器而言,这仍然会限制性能 。通过在挂载命令或/etc/fstab中手动增加msize(例如,msize=262144msize=104857600)可以显著提高速度,但Linux 9p客户端目前将msize上限限制在512KB 。这些限制进一步解释了9p模式下性能不佳的原因。

而virtiofs的开发旨在解决现有解决方案(如virtio-9p)的不足,这些方案基于未针对虚拟化优化的网络协议 。这些旧有解决方案缺乏本地文件系统语义,且性能不足以满足现代工作负载的需求 。VirtioFS的目标是在共享目录树的多个虚拟机之间提供本地文件系统语义 ,这对于轻量级虚拟机和容器工作负载尤为有用 。VirtioFS以FUSE(用户空间文件系统)为基础 。虚拟机内核充当FUSE客户端,而virtiofsd守护进程则作为FUSE服务器运行在宿主机上 。一个半虚拟化的virtio设备virtio-fs负责在虚拟机和宿主机之间传输FUSE消息 ,取代了传统的/dev/fuse接口 。

VirtioFS最根本的创新在于其明确利用了“虚拟机和宿主机协同定位”的优势 。与9p将虚拟机-宿主机通信视为网络问题不同,VirtioFS通过共享内存和直接访问(DAX)技术,将昂贵的通信(vmexits)替换为更廉价、更直接的内存访问 。这是一种从基于网络协议的共享方式向更高效的内存共享方式的范式转变。这种设计选择是VirtioFS实现卓越性能的主要驱动力,尤其对于I/O密集型工作负载而言,因为它最大限度地减少了传统网络文件系统固有的开销,因此能够极大地提高IO性能。同时,VirtioFS采用FUSE作为协议 ,为其提供了“丰富的原生Linux文件系统接口” 。FUSE是一个成熟且被广泛理解的用户空间文件系统实现框架,这使得VirtioFS能够向虚拟机呈现高度兼容且完整的文件系统抽象。这对于qBittorrent这类需要标准POSIX文件系统语义来执行复杂操作(如mmap和文件预分配)的应用程序至关重要。FUSE基础,结合VirtioFS的扩展,使其能够“像本地文件系统一样”运行 ,这正是qBittorrent所需的功能。

性能基准测试清晰地展示了VirtioFS的显著优势。在fio mmap测试中,virtio-9p的mmap模式下,单文件(单线程)性能为28 MB/s,4文件(4线程)性能为140 MB/s 。相比之下,VirtioFS在none + dax模式下,单文件性能达到126 MB/s,4文件性能达到501 MB/s;在always模式下,单文件性能为235 MB/s,4文件性能为858 MB/s 。即使是always + dax模式,其性能(单文件121 MB/s,4文件487 MB/s)也远超virtio-9p 。这些数据表明,VirtioFS,尤其是在启用DAX或always缓存模式时,为mmap操作提供了显著更高的吞吐量 。

即便抛开virtiofs的性能优势,执意使用9p也会造成兼容性问题。9p对mmap操作的默认只读行为以及对特定缓存选项的严格要求,使其在面对qBittorrent这类需要复杂文件操作的应用时,容易出现兼容性问题和I/O错误 。而VirtioFS利用共享内存中的元数据版本表,在无需昂贵通信的情况下为多个虚拟机提供一致的访问 。VirtioFS的元数据版本号通过原子比较-交换操作实现,当版本号发生变化时,虚拟机将刷新其元数据缓存。对应地,如果开启9p对mmap的支持,在遇到多虚拟机访问同一文件的场景时,其主要依赖于宿主机进行仲裁(使用同步锁进行竞争,在频繁发生的场景下性能远不如原子比较-交换操作),并且9p协议本身并不原生提供缓存一致性机制,这意味着如果一个虚拟机在竞争中胜出,其他虚拟机可能仍然持有旧版本的mmap缓存,导致数据不一致、Last Writer Wins(最后一个写入块的客户端会覆盖掉之前所有其他虚拟机的修改,因为它不知道这些修改的存在)以及性能下降(竞争频繁的情况下可能会频繁刷新缓存)。其中last writer wins是破坏数据的主要问题,这可能会使得一些关键性的修改被丢弃,进而导致数据损坏。

总结:用户在Unraid虚拟机上使用qBittorrent时,从9p模式切换到VirtioFS模式后,IO错误的解决和性能的显著提升,清晰地证明了VirtioFS在现代虚拟化文件共享场景中的压倒性优势。

9p协议,作为Plan 9分布式操作系统中的通用网络文件系统协议,其“一切皆文件”的设计理念和基于消息传递的通信方式,使其在处理如qBittorrent这类对mmap和高并发IO有严格要求的应用时,暴露出固有的局限性。其默认的只读mmap行为和对msize等参数的敏感性,导致了性能瓶颈和功能不兼容。即使经过优化,9p作为网络协议的本质决定了其无法完全消除通信开销,难以提供真正的本地文件系统语义。

相比之下,VirtioFS是专为解决虚拟化环境中的文件共享挑战而设计的。它通过以下关键创新实现了卓越的性能和兼容性:

  1. 利用FUSE协议: VirtioFS以FUSE为基础,提供了丰富的原生Linux文件系统接口,使其能够像本地文件系统一样运行,满足应用程序对标准POSIX文件系统语义的期望。
  2. 直接访问(DAX): 这是VirtioFS的核心优势。通过将宿主机的文件内容直接映射到虚拟机内存,DAX绕过了虚拟机页面缓存和传统的I/O路径,显著减少了通信开销,并实现了高效的mmap操作,确保了多虚拟机间共享文件的一致性。
  3. 协同定位优势: VirtioFS的设计明确利用了虚拟机和宿主机在同一物理机器上协同定位的特点,将昂贵的通信(vmexits)替换为更高效的直接内存访问,这是其性能超越9p的根本原因。

因此,对于需要高性能、低延迟以及依赖本地文件系统语义(特别是mmap功能)的虚拟化工作负载,如qBittorrent下载、数据库操作或开发编译环境等,VirtioFS是明确的首选方案。而9p协议虽然在某些轻量级或对性能要求不高的共享场景中仍有其应用,但其在处理复杂I/O和mmap密集型任务时的局限性使其不再是现代虚拟化环境中的理想选择。

以上内容由gemini 2.5 flash生成。请批判性地阅读以上内容,如果要做严肃用途的参考,请务必独立查证后使用。本文作者并不为以上段落的误导性信息负责。

嗯,总之就是virtiofs是一个更加现代化的解决方案,以后就用它了。

PeerBanHelper

这里简单给大家介绍一下这个用来检测并封禁peer的工具:PeerBanHelper。由于最近吸血的不光是迅雷,还有pcdn和idc机房通过吸血bt上传者来平衡上下行流量比。我认为后者比迅雷更加可耻,引用我在搭建NAS时就说过的话

我一直不鼓励大家运行 pcdn 给互联网公司花钱当狗,但愿意当狗是个人自由,因此我只反对这种行为。但为了避免 ISP 限制自己的家宽而刷别人的上传量,这种就属于损人利己的脑瘫行为了,必须要重拳出击。

而PeerBanHelper正是用来解决这个问题的,虽然我对于其实现方式不够认同,但它确实是现行最流行的威胁保护工具。由于家用宽带上行有限,因此我必须保证我上传的每一字节都传给需要的人,哪怕对方下载了但不上传,我这也算是有效共享。而这种刷流量的人在获取到我传给他的数据后直接丢弃,这就是浪费我的上行带宽,绝对不能容忍。

我认为理想的BT辅助工具应该和BitTorrent一样是分布式去中心的。因此我理想的PeerBanHelper应该是采用类似DHT的网络结构,所有peer能够发布自己收集到的数据,并且中继自己从其他节点收集到的信息。这些信息可以使用密钥进行签名来防止伪造,并且通过算法在不同节点的报告中自行决定应该封禁哪些节点,同时算法还应该能够抵御赛贝尔攻击来防止刷流量的人自导自演,或其他人通过这个工具来封禁其他正常的节点。

总之,我理解PeerBanHelper为什么要做成中心化的服务器,因为这种实现最简单。参考I2P、区块链以及其他开放的分布式系统设计,想要设计一个去中心化的分布式系统很简单,但想要让这个系统安全可靠高效且不被攻击和滥用,那就非常难了。也许实现这样一个系统非常困难,甚至不可能,可我觉得我们应当始终心怀对完美事物的追求,这样才会有发展与进步。

由于我进行bt下载的软件就是安装在虚拟机里面,如果再装个docker就显得有些套娃了。当然可以部署在unraid的docker上,但我想让所有与p2p操作的部分都放在虚拟机里面,而的rpm包只支持redhat,所以我就采用了sh脚本的安装方式。安装后去社区的实例上注册个帐号,然后参照官方文档配置即可。其中有一个是否允许服务器下发脚本,虽然介绍说可以更加精准地识别一些威胁,但我还是不喜欢没有经过我审阅的脚本在我的设备上运行,何况PBH的知名度和可靠性远不如BOINC。

不过即便是没有开启下发脚本,PBH还是成功地封禁了那些183开头的IP,至于封禁原因嘛,也很好猜:IDC机房刷流量。

截图 2025-07-20 01-25-41.png

后记

至此我的BT方案应该算是够我用上一段了。虽然上一篇答应大家写我是怎么处理照片的,但抱歉一鸽再鸽,毕竟bt下载这个事儿更加紧急一些,而且防止我忘了,要赶紧写出来赶紧发。所以处理照片的流程就放到下个月啦,一定会写的!

-全文完-


知识共享许可协议
【歪门邪道】BT下载的反吸血之路天空 Blond 采用 知识共享 署名 - 非商业性使用 - 相同方式共享 4.0 国际 许可协议进行许可。
本许可协议授权之外的使用权限可以从 https://skyblond.info/about.html 处获得。

Archives QR Code
QR Code for this page
Tipping QR Code
Leave a Comment

已有 1 条评论
  1. 刷流量,本质上是将个人利益粗暴地建立在​​牺牲、欺骗、并摧毁其他真正分享者的有限资源之上​​。它非但不是不是他们口中的“对抗ISP强权的侠客行为”,反而是对同行者的“背后捅刀”,是数字世界的公敌与污点。