Transmission 屏蔽迅雷等吸血客户端

2022-04-26

一直跟你索取数据,你有求必应地给它了,等你跟它请求的时候,不好意思,没有,不信你看我进度,我可是 0% 啊!

——这就是吸血。

然而 BT 协议非常宽松,大多数开源客户端并不屏蔽吸血客户端,有些客户端如 qee,可以通过 Peer/Client ID 识别它们并屏蔽。

个人使用的 Transmission 就只能屏蔽 IP,而且作者表示不会加入屏蔽客户端这种功能1。我只好写了个 Shell 脚本2,检测到特定客户端就屏蔽它的 IP。

transmission-remote 的 API 并不能获取 Peer ID,只有 Client ID,也就是根据客户端名称屏蔽的,通过 CLIENTS 来设置。

由于 IP 动态分配,也建议设置一下 TIMEOUT_SECONDS,这样每过一段时间就会清空黑名单。至于 NAT 共用 IP 什么的,那就不在考虑范围内了,误伤就误伤了吧。

另一个问题是加入黑名单后即使 reload 了也不会立即生效,这个我已经提了 issue3。目前暂时的解决方法是设置 RESTART_TORRENT=true 重启该任务。

transmission-block/trans-block.sh
#!/usr/bin/env sh

HOST="localhost:9091"

AUTH="username:password"

CLIENTS="xunlei thunder gt0002 xl0012 xf dandanplay dl3760 qq"

LIST="$HOME/.config/transmission-daemon/blocklists/leechers.txt"
BIN="$LIST.bin"

# Clear blocklist
# 0=disable
# TIMEOUT_SECONDS=$((60 * 60 * 24)) # 24 hours
TIMEOUT_SECONDS=0

# Restart related torrents immediately if leechers detected
RESTART_TORRENT=true

error() { echo "$@" >&2; }

pattern=$(echo "$CLIENTS" | xargs | sed 's/ /\\)\\|\\(/g')
pattern="\(\($pattern\)\)"

trans_reload() {
  error "Reloading"
  # reload: https://github.com/transmission/transmission/blob/main/docs/Editing-Configuration-Files.md#reload-settings
  killall -HUP transmission-daemon
}

block_leechers() {
  # error "Checking leechers for: $(echo "$1" | cut -c -8)"
  peers=$(transmission-remote "$HOST" --auth "$AUTH" --torrent "$1" --info-peers)
  leechers=$(echo "$peers" | grep -i "$pattern")
  result=1

  while IFS= read -r leecher; do
    [ -z "$leecher" ] && continue
    # https://en.wikipedia.org/wiki/PeerGuardian#P2P_plaintext_format
    client=$(echo "$leecher" | awk '{ print $6 }')
    client=$(echo "$leecher" | grep -o -- "$client.*$")
    ip=$(echo "$leecher" | awk '{ print $1 }')
    line="$client:$ip-$ip"
    error "Blocking for $(echo "$1" | cut -c -8):"
    if grep -qs -- "$line" "$LIST"; then
      error "Duplicate: $line"
    else
      echo "$line"
      echo "$line" >>"$LIST"
    fi
    result=0
  done <<EOF
$leechers
EOF

  return $result
}

trans_restart_torrent() {
  error "Restarting torrent: $(echo "$1" | cut -c -8)"
  retry=0
  while [ $retry -lt 3 ]; do
    if transmission-remote "$HOST" --auth "$AUTH" --torrent "$1" --stop | grep -qs success; then
      break
    fi
    sleep 1
    : $((retry += 1))
  done
  sleep 3
  retry=0
  while [ $retry -lt 3 ]; do
    if transmission-remote "$HOST" --auth "$AUTH" --torrent "$1" --start | grep -qs success; then
      break
    fi
    sleep 1
    : $((retry += 1))
  done
}

start=$(date +%s)
while true; do
  diff=$(($(date +%s) - start))
  if [ $TIMEOUT_SECONDS -ne 0 ] && [ $diff -ge $TIMEOUT_SECONDS ]; then
    error "Clearing blocklist"
    rm -f "$LIST"
    rm -f "$BIN"
    start=$(date +%s)
    trans_reload
  fi

  hashes=$(transmission-remote "$HOST" --auth "$AUTH" --torrent all --info | grep Hash | awk '{ print $2 }')
  for h in $hashes; do
    if block_leechers "$h"; then
      trans_reload
      if [ $RESTART_TORRENT = true ]; then
        trans_restart_torrent "$h"
      fi
    fi
  done

  sleep 30
done

通过 Peer ID 或 Client ID 屏蔽只是权宜之计,且不说可以随意修改,迅雷的离线服务器也是用的 libtorrent4,而且普通用户吸血也是不能这样简单判断的。如果要根据其百分比、是否上传之类的判断,实现就会比较复杂,先凑合用吧。

还有一个已知问题,目前 Transmission 黑名单不支持 IPv65,甚至应用本身也没法禁用 IPv66。如果要禁就只能系统里禁了。

systemd 脚本

transmission-block/transmission-block.service
[Unit]
Description=Block Specified Clients for Transmission
Requires=network.target

[Service]
User=debian-transmission
ExecStart=/path/to/trans-block.sh
CPUSchedulingPolicy=idle
Nice=19

[Install]
WantedBy=multi-user.target

加戏时间

不吸血我怎么办?开会员?

更不能用。

一个号称离线下载的?

正经人谁用离线啊。

是啊。

你用离线吗?

我不用,你用吗?

玩 P2P 的能用离线下载?

用离线下载的能叫 P2P?

(异口同声)__!

LinuxShellBitTorrent
知识共享许可协议
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

在 Android 上部署 Linux

Dnsmasq 去 DNS 污染和广告