當封鎖名單增長到成百上千條 iptables -A INPUT -s x.x.x.x -j DROP 規則時,核心需**線性遍歷**每條規則 (O(N)),導致封包處理延遲飆升、CPU 佔用率激增,甚至引發軟中斷風暴。ipset 利用哈希表/位圖實現 O(1) 常數時間查找,完美解決此問題。
| 類型 | 適用場景 | 支援功能 |
|---|---|---|
| hash:ip | 單個 IP 地址 (IPv4/IPv6) | 極快查找、動態增刪、計數器、超時自動過期 |
| hash:net | CIDR 網段 (如 192.168.1.0/24) | 同上,自動合併重疊網段 (需核心 3.8+) |
| hash:ip,port | IP+埠組合 | 精細封鎖特定服務埠 |
| hash:net,port | 網段+埠 | |
| bitmap:ip | 小範圍連續 IPv4 (如 /24 內) | 記憶體極省 (位圖),速度最快 |
| list:set | 集合的集合 (多層級管理) | 分類管理 (如: cn_blacklist, brute_force, scanner) |
# Debian/Ubuntu
apt update && apt install -y ipset iptables
# RHEL/CentOS/Fedora
dnf/yum install -y ipset iptables
# 現代系統建議改用 nftables (原生支援 set)
dnf install nftables
# 建立名為 "blacklist" 的集合,最大 100 萬條目
ipset create blacklist hash:net maxelem 1000000
# 可選:啟用計數器 (統計命中次數) 和超時自動清理 (秒)
ipset create blacklist hash:net maxelem 1000000 counters timeout 86400
# 手動單條添加
ipset add blacklist 1.2.3.4
ipset add blacklist 5.6.0.0/16
# 批量從文件導入 (格式: add blacklist 1.2.3.4/32)
ipset restore < blacklist.txt
# 從威脅情報源自動生成 (示例: FireHOL level1)
curl -s "https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/firehol_level1.netset" | \
sed 's/^/add blacklist /' | ipset restore
# iptables 方式 (傳統)
iptables -I INPUT -m set --match-set blacklist src -j DROP
# 指定協議/埠: -p tcp --dport 22,80,443
# nftables 方式 (現代、原生、高效) - 推薦
nft add table inet filter
nft add chain inet filter input { type filter hook input priority 0 \; }
nft add set inet filter blacklist { type ipv4_addr \; flags interval \; } # interval 自動合併 CIDR
nft add rule inet filter input ip saddr @blacklist drop
# 導入數據到 nft set
nft -f - <
# ipset 持久化
ipset save blacklist > /etc/ipset/blacklist.set
# 建立 systemd 服務或加入啟動腳本: ipset restore < /etc/ipset/blacklist.set
# iptables 持久化
iptables-save > /etc/iptables/rules.v4 # Debian/Ubuntu: apt install iptables-persistent
# 或 systemctl enable iptables (RHEL)
# nftables 持久化 (原生)
nft list ruleset > /etc/nftables.conf
systemctl enable nftables
#!/bin/bash
# /usr/local/bin/update-blacklist.sh
SET_NAME="blacklist"
URLS=(
"https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/firehol_level1.netset"
"https://lists.blocklist.de/lists/all.txt"
"https://rules.emergingthreats.net/blockrules/compromised-ips.txt"
)
TMP_FILE=$(mktemp)
echo "create $SET_NAME hash:net maxelem 2000000 counters timeout 2592000" > "$TMP_FILE" # 30天過期
for url in "${URLS[@]}"; do
curl -sL "$url" | grep -E '^[0-9]{1,3}(\.[0-9]{1,3}){3}(/[0-9]{1,2})?$' | \
sed "s/^/add $SET_NAME /" >> "$TMP_FILE"
done
# 原子性替換: 建立臨時集合 -> 交換名稱 -> 刪除舊集合
ipset create tmp_blacklist hash:net maxelem 2000000 counters timeout 2592000
ipset restore -f "$TMP_FILE" -exist # -exist 忽略重複
ipset swap tmp_blacklist "$SET_NAME"
ipset destroy tmp_blacklist
rm -f "$TMP_FILE"
logger "IP黑名單更新完成: $(ipset list $SET_NAME | grep 'Number of entries' | awk '{print $4}') 條目"
加入 crontab -e 定時執行 (如每 6 小時):0 */6 * * * /usr/local/bin/update-blacklist.sh
# 查看集合統計
ipset list blacklist | head -20
# Number of entries: 125430
# References: 1
# 即時監控命中 (需啟用 counters)
watch -n 1 'ipset list blacklist | grep -A1 "Number of entries"'
# 測試封鎖生效
ipset test blacklist 1.2.3.4 # 1.2.3.4 is in set blacklist.
# 實際連接測試 (從受信任 IP 發起)
curl -I https://your_server_ip
# 建立白名單集合
ipset create whitelist hash:ip
ipset add whitelist 203.0.113.50 # 管理員辦公室 IP
# iptables: 白名單規則放在黑名單之前 (優先級更高)
iptables -I INPUT -m set --match-set whitelist src -j ACCEPT
iptables -I INPUT -m set --match-set blacklist src -j DROP
# nftables: 規則順序決定優先級
nft add rule inet filter input ip saddr @whitelist accept
nft add rule inet filter input ip saddr @blacklist drop
ipset + iptables/nftables 是 Linux 主機層面應對海量 IP 封鎖的標準解決方案。關鍵要點:選擇 hash:net 支援 CIDR、啟用 counters 監控、使用 timeout 自動清理舊條目、採用 swap 原子更新避免競態、構建自動化威脅情報餵養管線、務必配置白名單防誤封。對於 >10Gbps 體積型攻擊,仍需依賴上游運營商/雲廠商清洗。