進階
Banlist
深入了解 Bitcoin Core 的節點封禁機制,如何管理惡意或不良行為的對等節點。
10 分鐘
什麼是 Banlist?
Banlist 是 Bitcoin Core 維護的封禁節點清單,用於記錄因惡意行為或協議違規而被禁止連接的對等節點。 這是節點自我保護機制的重要組成部分,防止資源被惡意節點濫用。
封禁的目的
防止攻擊
- • 阻止 DoS 攻擊
- • 防止垃圾交易廣播
- • 抵禦 Eclipse 攻擊
節省資源
- • 避免處理無效數據
- • 保護頻寬
- • 維護連接品質
封禁 vs 斷開連接
兩者的區別
| 特性 | Disconnect | Ban |
|---|---|---|
| 持久性 | 臨時 | 持久(儲存到磁碟) |
| 重新連接 | 可以立即重連 | 封禁期間不可連接 |
| 預設時長 | N/A | 24 小時 |
| 適用情況 | 輕微問題 | 嚴重違規 |
Discourage(勸阻)
Bitcoin Core 26.0 引入了 discourage 機制,比 ban 更溫和。被勸阻的節點可以連接, 但會被優先斷開以騰出連接槽位給其他節點。
# 查看被勸阻的節點
bitcoin-cli listbanned
# 在輸出中,banned_until = 0 表示 discourage 而非 ban 封禁原因
自動封禁
Bitcoin Core 會自動封禁違反協議規則或行為異常的節點:
- ! 無效區塊
發送違反共識規則的區塊
- ! 無效交易
發送違反共識規則的交易
- ! DoS 行為
過多的無效請求或垃圾數據
- ! 協議違規
不遵循 P2P 協議的行為
DoS 評分系統
// Bitcoin Core 的 DoS 評分機制
interface PeerMisbehavior {
peerId: number;
score: number;
threshold: number; // 預設 100
}
// 違規行為的懲罰分數示例
const MISBEHAVIOR_SCORES = {
// 嚴重違規 - 立即封禁
INVALID_BLOCK: 100,
INVALID_TX_CONSENSUS: 100,
// 中等違規
INVALID_TX_POLICY: 10,
DUPLICATE_VERSION: 10,
UNKNOWN_MESSAGE: 1,
// 輕微違規
TIMEOUT: 1,
};
class PeerManager {
private misbehavior: Map = new Map();
private readonly banThreshold = 100;
// 記錄違規行為
misbehaving(peerId: number, howmuch: number, reason: string): void {
const current = this.misbehavior.get(peerId) || 0;
const newScore = current + howmuch;
console.log(`Peer ${peerId} misbehaving: ${reason} (+${howmuch})`);
this.misbehavior.set(peerId, newScore);
if (newScore >= this.banThreshold) {
this.banPeer(peerId);
}
}
private banPeer(peerId: number): void {
const peer = this.getPeer(peerId);
if (peer) {
this.addToBanlist(peer.address, 24 * 60 * 60); // 24 小時
this.disconnectPeer(peerId);
}
}
} 管理封禁清單
CLI 命令
# 查看所有封禁的節點
bitcoin-cli listbanned
# 輸出示例
[
{
"address": "192.168.1.100/32",
"ban_created": 1703980800,
"banned_until": 1704067200,
"ban_duration": 86400,
"time_remaining": 43200,
"ban_reason": "manually added"
}
]
# 手動封禁 IP
bitcoin-cli setban "192.168.1.100" "add" 86400 # 24 小時
# 封禁 IP 範圍(CIDR)
bitcoin-cli setban "192.168.1.0/24" "add" 86400
# 解除封禁
bitcoin-cli setban "192.168.1.100" "remove"
# 清除所有封禁
bitcoin-cli clearbanned
# 斷開特定節點(不封禁)
bitcoin-cli disconnectnode "192.168.1.100:8333" Banlist 檔案
# 封禁清單儲存位置
~/.bitcoin/banlist.json
# 檔案格式(JSON)
{
"banned_nets": [
{
"version": 1,
"ban_created": 1703980800,
"banned_until": 1704067200,
"address": "192.168.1.100/32"
}
]
}
# 舊版本使用 banlist.dat(二進制格式) 注意: 封禁是基於 IP 地址而非節點 ID。如果惡意節點使用 VPN 或動態 IP, 封禁可能無法完全阻止它們。
實現細節
封禁儲存
interface BanEntry {
subnet: string; // IP 或 CIDR
banCreated: number; // Unix timestamp
bannedUntil: number; // Unix timestamp(0 = discourage)
banReason: string;
}
class BanMan {
private banlist: Map = new Map();
private dirty: boolean = false;
// 檢查是否被封禁
isBanned(addr: string): boolean {
const now = Date.now() / 1000;
for (const [subnet, entry] of this.banlist) {
if (this.matchSubnet(addr, subnet)) {
if (entry.bannedUntil > now) {
return true;
}
// 封禁已過期,稍後清理
}
}
return false;
}
// 檢查是否被勸阻
isDiscouraged(addr: string): boolean {
for (const [subnet, entry] of this.banlist) {
if (this.matchSubnet(addr, subnet)) {
// bannedUntil = 0 表示 discourage
if (entry.bannedUntil === 0) {
return true;
}
}
}
return false;
}
// 添加封禁
ban(subnet: string, durationSeconds: number, reason: string): void {
const now = Date.now() / 1000;
this.banlist.set(subnet, {
subnet,
banCreated: now,
bannedUntil: now + durationSeconds,
banReason: reason,
});
this.dirty = true;
}
// 勸阻(不完全封禁)
discourage(subnet: string): void {
const now = Date.now() / 1000;
this.banlist.set(subnet, {
subnet,
banCreated: now,
bannedUntil: 0, // 0 表示 discourage
banReason: 'discouraged',
});
this.dirty = true;
}
// 儲存到磁碟
async dumpBanlist(): Promise {
if (!this.dirty) return;
const data = {
banned_nets: Array.from(this.banlist.values()),
};
await writeFile('banlist.json', JSON.stringify(data, null, 2));
this.dirty = false;
}
} 配置選項
# bitcoin.conf
# 設定封禁時長(秒),預設 86400(24 小時)
bantime=86400
# 禁止自動封禁(不建議)
# 只會 discourage 而不會 ban
# noban=1
# 使用白名單(繞過封禁檢查)
whitelist=192.168.1.0/24
# 白名單權限
whitebind=127.0.0.1:8333
whitelistrelay=1
whitelistforcerelay=1 白名單
白名單中的節點不會被自動封禁或斷開連接,即使它們的行為觸發了 DoS 保護。
# 白名單選項
-whitelist= # 添加到白名單
-whitebind= # 綁定地址並將連接加入白名單
# 白名單權限
-whitelistrelay # 允許中繼來自白名單的交易
-whitelistforcerelay # 強制中繼(即使不符合 mempool 政策) 最佳實踐
✓ 建議
- • 讓自動封禁機制正常運作
- • 定期檢查封禁清單
- • 為可信節點設定白名單
- • 監控異常連接模式
✗ 避免
- • 禁用自動封禁
- • 過度使用手動封禁
- • 封禁大範圍 IP
- • 忽略封禁日誌
總結
- ✓ 封禁機制:防止惡意節點消耗資源
- ✓ DoS 評分:累積違規行為觸發自動封禁
- ✓ Discourage:溫和的處理方式,優先斷開而非封禁
- ⚠ 注意:封禁基於 IP,無法阻止使用 VPN 的攻擊者
已複製連結