Детектор торрентов для Remnawave: ловим то, что пропускает штатный блокировщик
Штатный Torrent Blocker в ноде Remnawave опирается на сниффер xray, а тот видит лишь малую часть торрент-трафика: современные клиенты шифруют соединения с пирами, и опознавать в них BitTorrent не по чему. В этой статье вы поставите открытый детектор fsnt-torrent-blocker, который закрывает этот пробел двумя независимыми сигналами, сначала посмотрите его находки без банов, а потом переведёте в боевой режим.
Детектор — дополнение к штатной схеме, а не замена ей. Он только находит нарушителя и отдаёт отчёт ноде; банит, считает срок и рассылает уведомления по-прежнему плагин Torrent Blocker. Если база не настроена — сниффинг, правила маршрутизации, outbound и сам плагин, — детектору некому отдавать находки, и он ничего не сделает.
Что понадобится
- VPS ForestsNet Cloud с доступом по SSH под
rootили пользователем сsudo. - Уже настроенная штатная блокировка по шагам из статьи Как заблокировать торренты на своём VPN или прокси: включён сниффинг, заданы правила маршрутизации, заведён outbound и включён плагин Torrent Blocker в ноде. Без этого детектор бесполезен.
- Remnawave Node версии 2.7.0 или новее, контейнер ноды запущен с
cap_add: NET_ADMIN. - Access-лог xray не выключен: в конфиге
log.accessне должен быть"none". Без лога детектору не с чем работать. systemdиpython3версии 3.6 или новее. Еслиpython3в системе нет, установщик поставит его сам: внешних зависимостей у детектора нет, хватает стандартной библиотеки.
Почему штатного блокировщика не хватает
Документация Remnawave прямо оговаривает: сниффер xray опознаёт BitTorrent примерно в 10–30% случаев. Мимо проходят три класса трафика.
Шифрованные пиры. В qBittorrent и большинстве клиентов протокольное шифрование MSE/PE включено по умолчанию. Открытого рукопожатия BitTorrent protocol в TCP просто нет — опознавать нечего.
DHT. Распределённая таблица, через которую клиент находит пиры без трекера, живёт поверх UDP. Отдельного сниффера для неё в xray нет вовсе.
Правила по портам и доменам трекеров. Пиры ходят по голым IP на случайных высоких портах. Ни geosite:category-public-tracker, ни список портов их не ловят — туда попадают только обращения к трекерам, а это малая часть обмена.
Как устроена блокировка торрентов в целом и что делать, если у вас не Remnawave, а WireGuard или OpenVPN, разобрано в той же статье — Как заблокировать торренты на своём VPN или прокси.
Как детектор ловит торренты
Сигнал 1. Веер соединений
Детектор читает access-лог xray и для каждого пользователя считает, к скольким разным адресам и на сколько разных портов тот обратился за скользящее окно — по умолчанию за 60 секунд.
Торрент-клиент открывает соединения к десяткам пиров, и у каждого пира свой порт. Такого веера не даёт ни браузер, ни мессенджер, ни видеозвонок: у обычного пользователя за минуту набирается до двух десятков адресов на высоких портах, у торрентящего — 50–150.
Соединения по доменным именам, к частным адресам и на порты веба, DNS, почты, мессенджеров и STUN/TURN в подсчёт не идут. Именно так ловятся шифрованные MSE/PE-пиры, у которых нет никакой сигнатуры.
Сигнал 2. btguard — UDP-контрплан
Вместе с детектором ставится nft-таблица btguard. Она дропает на выходе то, что сниффер xray по UDP пропускает:
- DHT (BEP 5) — по началу bencode-словаря запроса и ответа;
- uTP-хендшейк (BEP 29) — по полям заголовка пакета
ST_SYN; - connect к UDP-трекеру (BEP 15) — по магическому числу протокола и нулевому коду действия.
Каждый дроп попадает в kernel-лог вместе с адресом пира. Детектор читает этот лог и восстанавливает, кто именно торрентил: тот же поток есть в access-логе как udp:<пир>:<порт> email:<клиент>, так что по паре «адрес-порт» находится клиент.
Что происходит после срабатывания
Детектор отправляет отчёт во внутренний вебхук ноды — тот самый, куда отчитывается и сам xray. Дальше нода работает штатно: банит IP клиента в nftables на срок blockDuration с учётом ignoreLists, рвёт его текущие соединения и передаёт отчёт в панель, а панель — в Telegram и в вебхук torrent_blocker.report.
Адрес вебхука детектор каждый раз берёт из работающего конфига xray, поэтому переживает перезапуски ноды без донастройки. Поддержаны оба поколения ноды — и с абстрактным сокетом, и с файловым.
Установка
Сначала поставьте детектор в режиме наблюдения. Он будет писать находки в журнал и никого не банить — так вы увидите, кого он поймает на вашем трафике, ничем не рискуя.
curl -fsSL https://raw.githubusercontent.com/forestsnet/torrent-blocker/main/install.sh | sudo bash -s -- --dry-run
journalctl -u fsnt-torrent-blocker -fУстановщик кладёт детектор в /usr/local/sbin/fsnt-torrent-blocker, настройки — в /etc/default/fsnt-torrent-blocker, заводит юнит fsnt-torrent-blocker.service и правила btguard (/etc/nftables.d/btguard.nft плюс oneshot-юнит btguard.service). Флаг --no-btguard ставит только веерный детект по логу, без nft-правил.
Перед тем как включить сервис, установщик прогоняет selftest: находит xray, вебхук и лог, отправляет пробный отчёт без пользователя (нода проверит формат, но никого не забанит) и заведомо битый отчёт, который нода должна отвергнуть. Если что-то не сошлось — сервис не включается.
Посмотрели находки, убедились, что ложных нет, — переводите в боевой режим:
curl -fsSL https://raw.githubusercontent.com/forestsnet/torrent-blocker/main/install.sh | sudo bash -s -- --liveПовторный запуск установщика обновляет детектор и сохраняет ваши настройки.
Если узлов несколько, поставьте сразу на все со своей машины. Детектор вшит в install.sh целиком, поэтому доступ сервера к GitHub не нужен:
for h in 10.0.0.1 10.0.0.2 10.0.0.3; do ssh deploy@$h 'sudo bash -s' < install.sh; doneНастройка порогов
Пороги задаются флагами при установке и потом правятся в /etc/default/fsnt-torrent-blocker — после правки перезапустите сервис. Флаг установки и переменная конфига означают одно и то же:
--window N/FTB_WINDOW, по умолчанию60— окно наблюдения в секундах.--min-hosts N/FTB_MIN_HOSTS, по умолчанию25— порог по числу разных адресов назначения за окно.--min-ports N/FTB_MIN_PORTS, по умолчанию20— порог по числу разных портов назначения за окно. Сработает, только если выполнены оба условия сразу.--cooldown N/FTB_COOLDOWN, по умолчанию300— не отправлять повторный отчёт на тот же IP чаще, чем раз в столько секунд.--max-reports N/FTB_MAX_REPORTS_PER_MIN, по умолчанию10— предохранитель: если отчётов в минуту больше, отправка встаёт на паузу на 10 минут.--ignore-ports L/FTB_IGNORE_PORTS, по умолчанию пусто — дополнительные порты назначения через запятую, которые не считать веером.--no-btguard/FTB_BTGUARD, по умолчаниюauto—autoвключает корреляцию с btguard, если nft-таблица есть;offоставляет только веер;onфорсирует.--dry-runи--live/FTB_DRY_RUN, по умолчанию0— режим наблюдения против боевого.
Пороги подобраны по замерам на реальном трафике, и между легальным трафиком и торрентом здесь широкий зазор: самые «веерные» легальные сервисы — P2P-раздача обновлений, WebRTC-звонки, игры — дают за окно до пятнадцати разных портов, торрент-клиент даёт 140–250. Порог в 20 портов сидит ровно в этом зазоре.
Главную роль играет условие «и адреса, и порты». Сервис, который бьёт по десяткам адресов, но на узком наборе портов, под детектор не попадает: так ведут себя и раздача обновлений Windows, и голосовой звонок.
Какие порты не считаются веером
Обращения ко многим адресам на этих портах — нормальное поведение, поэтому детектор их пропускает. Список собран по типовому легальному трафику, по каждому порту смотрели реальные адреса назначения и rDNS:
22,53,80,443,8080,8443— SSH, DNS, HTTP и HTTPS, в том числе поверх QUIC.123и2002— синхронизация времени: NTP и Roughtime.465,587,993,995,853— почта и DNS-over-TLS.554и1935— потоковое видео: RTSP с камер и RTMP.3478–3497,5349,16384–16403,19302–19309— STUN, TURN и RTP: установка и медиа p2p-звонков в WebRTC, мессенджерах и Google Meet.5222,5223,5228— XMPP и push-уведомления, в том числе Google FCM.7680— раздача обновлений Windows между машинами, десятки жилых адресов на один порт.
Порты, веер по которым как раз интересно видеть, в список осознанно не попали — например 3333 и другие порты майнинг-пулов.
Если какой-то легальный сервис на вашем узле всё же светит много разных портов и цепляется под детектор, добавьте его порты в FTB_IGNORE_PORTS — общий список ради одного узла править не нужно.
Как отличить срабатывание детектора от штатного
Отчёты детектора приходят по тому же пути, что и родные, поэтому отличать их стоит по метке протокола:
- В Telegram. У штатного —
Protocol: bittorrent (tcp), у детектора —Protocol: fsnt-torrent-blocker (tcp). - В панели, в отчётах Torrent Blocker — фильтр
Protocolсо значениемbittorrentпротивfsnt-torrent-blocker. - В вебхуке
torrent_blocker.report— у штатногоxrayReport.outboundTagравенRW_TB_OUTBOUND_BLOCK, у детектора иprotocol, иoutboundTagравныfsnt-torrent-blocker.
Цифры самой находки лежат в xrayReport.routeTarget и выглядят так: fanout 73 hosts / 58 ports / 86 conns in 60s (tcp 85, udp 1). В поле destination — один из пиров.
Проверка
sudo fsnt-torrent-blocker --selftest
systemctl status fsnt-torrent-blocker
journalctl -u fsnt-torrent-blocker -fИсправный selftest выглядит так:
ok xray pid 1464055, API ноды — файловый сокет
ok вебхук Torrent Blocker найден
ok лог /proc/18868/root/var/log/remnanode/access.log
ok вебхук принимает отчёты (HTTP 200)
ok обработчик ноды разбирает формат детектора
итог: OKА находка в журнале — так:
2026-09-23 10:45:55Z user=1042 ip=203.0.113.7 fanout 73 hosts / 58 ports / 86 conns in 60s (tcp 85, udp 1) -> принят нодойОграничения
О них лучше знать до установки, а не после первой жалобы.
Бан ставится по IP клиента — так же, как у штатного плагина. За адресом мобильного оператора с CGNAT может оказаться несколько абонентов.
Каждая нода решает по своему трафику. Панель узнаёт о бане и шлёт уведомление, но на другие ноды бан не переходит — так устроен плагин. Чтобы отключить нарушителя везде, обрабатывайте вебхук torrent_blocker.report у себя: например, переводите пользователя в DISABLED.
Детектор ходит во внутренний API ноды, а не в публичный. После крупных обновлений Remnawave Node сначала прогоняйте --selftest.
Трафик мимо access-лога детектор не увидит. При log.access равном "none" работать не с чем.
Удаление
curl -fsSL https://raw.githubusercontent.com/forestsnet/torrent-blocker/main/install.sh | sudo bash -s -- --uninstallНастройки при этом остаются — чтобы снести и их, добавьте --purge.
Источники
- forestsnet/torrent-blocker — исходный код детектора и nft-правил.
- Remnawave — плагины ноды, Torrent Blocker
- Jolymmiles/Xray-core — форк, по которому сверены сигнатуры DHT, uTP и UDP-трекера.