一直跟你索取数据,你有求必应地给它了,等你跟它请求的时候,不好意思,没有,不信你看我进度,我可是 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
重启该任务。
#!/usr/bin/env sh
HOST="localhost:9091"
AUTH="username:password"
CLIENTS="xunlei thunder gt[[:digit:]]\{4\} xl0012 xf dandanplay dl3760 qq libtorrent"
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; }
HASH_SHORT=
error_with_hash_tag() { error "[$HASH_SHORT]" "$@"; }
pattern=$(echo "$CLIENTS" | xargs -0 | 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() {
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_with_hash_tag "Blocking leecher"
if grep -qs -- "$line" "$LIST"; then
error_with_hash_tag "Duplicate: $line"
else
echo "$line"
echo "$line" >>"$LIST"
fi
result=0
done <<EOF
$leechers
EOF
return $result
}
trans_restart_torrent() {
error_with_hash_tag "Restarting"
retry_max=5
for _ in $(seq 0 "$retry_max"); do
if transmission-remote "$HOST" --auth "$AUTH" --torrent "$1" --stop | grep -qs success; then
break
fi
sleep 1
done
stopped=false
for _ in $(seq 0 "$retry_max"); do
if transmission-remote "$HOST" --auth "$AUTH" --torrent "$1" --info | grep -qs 'State: Stopped'; then
error_with_hash_tag "Stopped"
stopped=true
break
fi
sleep 1
done
if [ "$stopped" = false ]; then
error_with_hash_tag "Unable to stop, skipping"
return 1
fi
for _ in $(seq 0 "$retry_max"); do
if transmission-remote "$HOST" --auth "$AUTH" --torrent "$1" --start | grep -qs success; then
break
fi
sleep 1
done
for _ in $(seq 0 "$retry_max"); do
if transmission-remote "$HOST" --auth "$AUTH" --torrent "$1" --info | grep -qs 'State: Stopped'; then
sleep 1
continue
fi
error_with_hash_tag "Started"
stopped=false
break
done
if [ "$stopped" = true ]; then
error_with_hash_tag "Unable to start"
error_with_hash_tag "You may have to start manually"
return 1
fi
}
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
HASH_SHORT="$(echo "$h" | cut -c -8)"
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 脚本
[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?
(异口同声)__!
Feature request: client-based blocking · Issue #735 · transmission/transmission ↩︎
qianbinbin/transmission-block: 为 Transmission 屏蔽迅雷等吸血客户端 | For Transmission to block leecher clients like Xunlei ↩︎
when updating blocklist, check peer connections for blocked IP to disconnect · Issue #2959 · transmission/transmission ↩︎
新的吸血客户端?客户端:libtorrent/0.15.9.0,Peer ID:AL1000 · Issue #61 · c0re100/qBittorrent-Enhanced-Edition ↩︎
ipv6 blocklist format · Issue #740 · transmission/transmission ↩︎
Transmission tries to connect IPv6 instances even ipv6 addresses are disabled. · Issue #86 · transmission/transmission ↩︎