#!/usr/bin/bash

# my_ban_ips.sh 
# 作者: 羽山秋人 (https://3wa.tw)
# 版本: V0.01

# 1. 安裝所需套件
# sudo apt install -y ipset iptables curl 

# 2. 本檔案內容存成：/root/my_ban_ips.sh
# curl "https://3wa.tw/myapache_banip/my_ban_ips.sh" -o /root/my_ban_ips.sh

# 3. 給執行權限
# chmod +x /root/my_ban_ips.sh

# 4. 手動執行一次
# sudo /root/my_ban_ips.sh

# 5. 檢查結果
# 看 ipset 內容：
# ipset list blacklist
# 看 iptables 規則：
# iptables -L INPUT -n --line-numbers
# 你應該會看到類似：
# match-set blacklist src DROP

# 6. 設定自動更新
# 最簡單先用 crontab。
# 編輯 root 的排程：
# crontab -e
# 每 30 分鐘跑一次：

# my_ban_ips
# */30 * * * * /root/my_ban_ips.sh >> /var/log/my_ban_ips.log 2>&1

# 7. 如果要移除這套規則
# 先刪 iptables 規則：
# iptables -D INPUT -m set --match-set blacklist src -j DROP

# 再刪 ipset：
# ipset destroy blacklist

# 如果還有排程，也一起刪：
# crontab -e
# 把那行移掉。

set -euo pipefail

SET_NAME="blacklist"
RULE_COMMENT="Block bad IPs from remote list"
URL="https://3wa.tw/myapache_banip/data/banip_csv.txt"
TMP_FILE="/tmp/banip_csv.txt"
TMP_RESTORE="/tmp/ipset_restore.txt"

# 下載清單
curl -fsSL "$URL" -o "$TMP_FILE"

if [ ! -s "$TMP_FILE" ]; then
    echo "Download failed or file is empty"
    exit 1
fi

# 建立暫時 restore 檔
{
    echo "create ${SET_NAME}_new hash:ip family inet hashsize 4096 maxelem 65536 -exist"

    while IFS= read -r line; do
        ip="$(echo "$line" | tr -d '\r' | xargs)"
        [ -z "$ip" ] && continue

        # 如果你的檔案其實是 csv: 1.2.3.4,reason
        # 可改成：
        # ip="$(echo "$line" | cut -d',' -f1 | tr -d '\r' | xargs)"

        if [[ "$ip" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then
            echo "add ${SET_NAME}_new $ip"
        else
            echo "SKIP: [$ip]" >&2
        fi
    done < "$TMP_FILE"
} > "$TMP_RESTORE"

# 載入新 set
ipset restore < "$TMP_RESTORE"

# 若正式 set 不存在，先建立
ipset create "$SET_NAME" hash:ip family inet hashsize 4096 maxelem 65536 -exist

# 原子替換
ipset swap "${SET_NAME}_new" "$SET_NAME"

# 清理暫存 set
ipset destroy "${SET_NAME}_new" 2>/dev/null || true

# 確保 iptables 規則存在
if ! iptables -C INPUT -m set --match-set "$SET_NAME" src -j DROP 2>/dev/null; then
    iptables -I INPUT -m set --match-set "$SET_NAME" src -j DROP
fi

COUNT=$(ipset list "$SET_NAME" | awk '/Number of entries:/ {print $4}')
echo "Done. Total blocked IPs: ${COUNT:-0}"