maleadt     about     archive

Bypassing connection tracking for BitTorrent traffic

iptables doesn’t like torrent traffic. More specifically, its connection tracker (dubbed conntrack) easily gets confused by connections to and from the swarm. In order to get all traffic through, I decided to bypass connection tracking for BitTorrent traffic, which has significantly improved my up- and downloading speeds!

The most common problem with tracking BitTorrent connections is the high volume of them, causing internal state tables to overflow. I bumped into another issue, where certain incoming RST-flagged packets got blocked, much like how this forum post details. This thoroughly messed with my torrent client, which got stuck with many closed connections thinking they were still valid.

I ultimately decided to get rid of connection tracking for BitTorrent traffic altogether. By marking packages NOTRACK in the respective raw tables, we instruct iptables not to track these packages. However, this also means losing some helpful functionality. conntrack and NAT helper will simply not work, and we’ll need to handle ICMP errors ourselves. Luckily, BitTorrent traffic is not state-full (as opposed to, for example, FTP), so we don’t need any helpers.

The following snippet lists the required iptables commands (usable with ip6tables too):

# BitTorrent "server"
SERVER="40000"
for PROTO in tcp udp; do
  # incoming traffic
  iptables -t raw -I PREROUTING -p $PROTO \
           --dport ${SERVER} -j NOTRACK
  iptables -I INPUT -i eth0 -p $PROTO \
           --dport ${SERVER} -j ACCEPT

  # outgoing traffic (replies)
  iptables -t raw -I OUTPUT -p $PROTO \
           --sport ${SERVER} -j NOTRACK
  iptables -I OUTPUT -p $PROTO \
           --sport ${SERVER} -j ACCEPT                               
done

# BitTorrent "client"
CLIENT="40001:40999"
for PROTO in tcp udp; do
  # outgoing traffic
  iptables -t raw -I OUTPUT -p $PROTO \
           --sport ${CLIENT} -j NOTRACK
  iptables -I OUTPUT -p $PROTO \
           --sport ${CLIENT} -j ACCEPT                               

  # incoming traffic (replies)
  iptables -t raw -I PREROUTING -p $PROTO \
           --dport ${CLIENT} -j NOTRACK
  iptables -I INPUT -i eth0 -p $PROTO \
           --dport ${CLIENT} -j ACCEPT
done

Recall that due to marking all packages NOTRACK, iptables will not be able to tie ICMP replies to the corresponding connection, and as a result treat those packages as invalid. To resolve this, we should explicitly allow such control messages:

for TYPE in destination-unreachable source-quench \
            ttl-exceeded parameter-problem; do
  iptables -I INPUT -p icmp \
           --icmp-type $TYPE -j ACCEPT
  iptables -I OUTPUT -p icmp \
           --icmp-type $TYPE -j ACCEPT
done
for TYPE in destination-unreachable packet-too-big \
            ttl-exceeded parameter-problem; do
  ip6tables -I INPUT -p icmpv6 \
            --icmpv6-type $TYPE -j ACCEPT
  ip6tables -I OUTPUT -p icmpv6 \
            --icmpv6-type $TYPE -j ACCEPT
done

If required, you could still tighten these rules up a bit. Some ideas: