Highlights
- Torrent traffic detection now works end to end. Routing rules that match
protocol: ["bittorrent"]now cover BitTorrent peer connections (TCP handshake and uTP), Mainline DHT (KRPC), and UDP trackers (BEP 15). Previously only the TCP handshake was detected; the uTP sniffer could never match any packet.
Fork fixes
- BitTorrent uTP sniffing repaired (correctness).
SniffUTPrejected every packet ever sent: its timestamp gate compared the packet's 32-bit monotonic clock value against Unix-epoch microseconds with a 24-hour window expressed in nanoseconds, while deployed stacks (libutp:CLOCK_MONOTONIC, libtorrent:high_resolution_clocktruncated to 32 bits) put monotonic — not epoch — timestamps on the wire. The extension chain was also parsed before the fixed 20-byte header instead of after it per BEP 29, and libtorrent's close-reason extension (id 3) was rejected. Impact: uTP peer traffic from qBittorrent, Transmission, Deluge and other libtorrent/libutp clients — the dominant transport of modern torrent clients — was invisible to bittorrent routing rules. - New: Mainline DHT detection. KRPC bencode messages (queries, responses, errors) are structurally validated — message kind
y, transaction idt, deployed query names, 20-byte node id in responses,[code, message]error lists — and reported asbittorrent. - New: UDP tracker detection. BEP 15 connect requests (protocol id
0x41727101980), announces on cached connection ids (98 bytes, event and port sanity), and scrapes are reported asbittorrent. - False-positive hardening. WireGuard handshake initiations (
01 00 00 00+ key material), which pass every structural uTP check, are now rejected deterministically. The corpus verifies DNS, NTP, QUIC, WireGuard and random datagrams are not classified as torrents.
Upstream changes
- None since v26.8.20: upstream/main is fully contained in this release; this version ships fork-only detection fixes.
Compatibility notes
- No wire or protocol behavior changed; the sniffing improvements only affect sniffing-based routing. Rules using
sniffingwithdestOverride: ["bittorrent"]or routing conditionprotocol: ["bittorrent"]now additionally match uTP, DHT and UDP tracker flows. Operators with rules that route or block by that condition should review the wider coverage. - Known limits: HTTP(S) tracker traffic is still sniffed as
http/tls(domain routing preserved); a uTP session whose SYN carries connection id 0 (about 1 in 65536 sessions in deployed stacks) falls through the WireGuard-shaped guard.
Validation
- Wire-format corpus built from the libutp and libtorrent (RC_2_0) sources: 108 subtests green, covering TCP handshakes of six client families, every uTP packet type with SACK and close-reason extension chains, every KRPC message kind (including BEP 44 mutable puts), and tracker requests; the false-positive corpus covers DNS, NTP, WireGuard, QUIC and random datagrams.
go build ./...,go vet, unit tests-count=1, and-raceon changed packages green.- Linux/amd64 build gate:
CGO_ENABLED=0 GOAMD64=v1 -trimpathwith release linker flags; static stripped ELF; sha256f6943625d8b12fe89e7587c58e0b4f571cb0193f1ef229bfd84fef67d2d5e6fb.