Skip to content

BitTorrent Guard Plugin (bittorrent) ​

The BitTorrent Guard Plugin provides protocol-aware security and policy enforcement for all three transports of the BitTorrent ecosystem:

  • Peer Wire Protocol over TCP (BEP 3)
  • Mainline DHT (Distributed Hash Table) over UDP (BEP 5)
  • Micro Transport Protocol (uTP) over UDP (BEP 29)

It inspects initial handshakes, decodes bencoded DHT RPC dictionaries, enforces client peer ID policies, and stops DHT amplification attacks.


Capabilities & Threat Defense ​

Threat / Attack VectorDefense MechanismAction Taken
Unauthorized / Copyright TorrentsSHA-1 Info-hash filtering (blocked_info_hashes / allowed_info_hashes)Handshake dropped before swarm data transfer begins
Malicious Bots & ScannersEnforces -CCVVVV- format (require_peer_id_format) and client prefixes (allowed_peer_id_prefixes)Non-compliant or unknown client peer IDs rejected
DHT Amplification AttacksEnforces max_dht_packet_size and filters query typesLarge reflection payloads and crafted queries discarded silently
DHT Swarm Poisoningblocked_dht_methods: ["announce_peer"] blocks unwanted peer advertisementsBencoded announce_peer RPCs dropped before polluting DHT index
Private Swarm DHT Leaksprivate_tracker_mode: true checks extension bits in handshakePeers advertising DHT capability (BEP 5 bit) dropped to preserve private swarms
uTP Channel Abuseblock_utp: true drops UDP datagrams matching the 20-byte uTP header (BEP 29)Forces clients onto TCP for uniform stream rate limiting

Installation ​

Install the BitTorrent plugin using the CLI or declaratively:

# Install using short nametcp-warden plugins install bittorrent# Or install via Git repository URLtcp-warden plugins install https://github.com/routewarden/plugins/bittorrent

Configuration Reference ​

Configure a multi-transport BitTorrent guard in tcp-warden.yaml:

services:  torrent_gateway:    listen: ":6881"    upstream: "10.0.0.50:6881"    transport: "both"                 # Inspects Peer Wire over TCP + DHT/uTP over UDP    protocol: "bittorrent"    rate_limit:      connections_per_minute: 600      burst: 100    udp:      session_timeout: "30s"      max_sessions: 15000      read_buffer_size: 65535    plugin_config:      # Block or allow specific torrents by SHA-1 info-hash (40 hex chars)      blocked_info_hashes:        - "aabbccddeeff00112233445566778899aabbccdd"      allowed_info_hashes: []         # If non-empty, ONLY these torrents are permitted      # Client identity validation      require_peer_id_format: true    # Enforces standard Azureus style (-CCVVVV-...) to drop bots      allowed_peer_id_prefixes:        - "-qB-"                      # qBittorrent        - "-TR-"                      # Transmission        - "-DE-"                      # Deluge        - "-lt-"                      # libtorrent      blocked_peer_id_prefixes: []      # Private tracker and discovery controls      private_tracker_mode: false     # When true, rejects peers advertising DHT extensions (BEP 5)      block_dht: false                # Block all UDP DHT discovery traffic      block_utp: false                # Block Micro Transport Protocol (BEP 29) over UDP      blocked_dht_methods:        - "announce_peer"             # Mitigate DHT poisoning and unwanted peer injection      max_dht_packet_size: 1500       # Mitigate UDP amplification attacks

Configuration Options ​

FieldTypeDefaultDescription
listenstring":6881"Local proxy listen address and port.
upstreamstring"10.0.0.50:6881"Upstream BitTorrent client or seeder node.
transportstring"both"Network transport: "both" (binds TCP for Peer Wire and UDP for DHT/uTP), "tcp", or "udp".
protocolstring"bittorrent"Must be set to "bittorrent", "bittorrent-tcp", "bittorrent-dht", or "bittorrent-utp".
plugin_config.blocked_info_hashes[]string[]List of 40-character hex SHA-1 info-hashes to block. Case-insensitive.
plugin_config.allowed_info_hashes[]string[]If non-empty, only matching info-hashes are permitted (whitelist / corporate distribution mode).
plugin_config.require_peer_id_formatboolfalseWhen true, rejects peers whose 20-byte peer ID does not conform to the standard Azureus convention (-CCVVVV-...).
plugin_config.allowed_peer_id_prefixes[]string[]List of allowed client peer ID prefixes (e.g. ["-qB-", "-TR-", "-DE-"]).
plugin_config.blocked_peer_id_prefixes[]string[]Explicitly blocked client prefixes.
plugin_config.private_tracker_modeboolfalseWhen true, peers advertising DHT support in their 8-byte handshake extension flags are dropped.
plugin_config.block_dhtboolfalseWhen true, drops all UDP DHT queries and responses.
plugin_config.block_utpboolfalseWhen true, drops all UDP uTP packets (forcing TCP transport).
plugin_config.blocked_dht_methods[]string[]DHT query methods to block (e.g., ["announce_peer", "get_peers"]).
plugin_config.allowed_dht_methods[]string[]If non-empty, only these DHT methods are accepted. Queries whose method name cannot be parsed from the bencode payload are dropped when an allowlist is active (since v3.4.0).
plugin_config.max_dht_packet_sizeint1500Maximum allowed UDP DHT packet size in bytes to prevent amplification.

Network & Deployment Architecture ​

Option A: Kernel Firewall Redirection (nftables / iptables) ​

Redirect external BitTorrent traffic across TCP & UDP ports to RouteWarden port 6881:

# Redirect incoming BitTorrent ports (TCP & UDP 6881-6889) to RouteWarden port 6881sudo nft add rule ip routewarden_nat prerouting iifname "eth0" tcp dport 6881-6889 redirect to :6881sudo nft add rule ip routewarden_nat prerouting iifname "eth0" udp dport 6881-6889 redirect to :6881

Option B: Docker Compose with Dedicated Torrent Client ​

Isolate your download client container behind RouteWarden:

services:  routewarden:    image: ghcr.io/routewarden/tcp-warden:latest    network_mode: host    volumes:      - ./tcp-warden.yaml:/etc/routewarden/tcp-warden.yaml:ro      - routewarden-data:/var/lib/routewarden    depends_on:      - qbittorrent  qbittorrent:    image: lscr.io/linuxserver/qbittorrent:latest    network_mode: host    environment:      - WEBUI_PORT=8080      - TORRENTING_PORT=6882          # Client listens on internal port; RouteWarden guards 6881    volumes:      - ./config:/config      - ./downloads:/downloadsvolumes:  routewarden-data:

Testing & Verification ​

Verify TCP handshakes, DHT RPC inspection, and info-hash blocking:

# Send a synthetic BitTorrent 68-byte handshake (PSTR: "BitTorrent protocol")printf '\x13BitTorrent protocol\x00\x00\x00\x00\x00\x00\x00\x00\xaa\xbb\xcc\xdd\xee\xff\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd-qB4500-123456789012' | nc 127.0.0.1 6881

Released under the MIT License.