🚀 运行: ...
IP: ...
ISP: 检测中...

给 ImmortalWrt 装个“捕鼠夹”:一键部署自动蜜罐防火墙 (NFTables版)

前情提要:开放7088端口是为方便自己在外看iptv电视的,无奈太多吊毛扫描到了自己看不说还分享出去,全国各地的叼毛都来连。与其被动挨打,不如主动出击。

思路由作者本人构想,细节完成全靠AI

今天分享一个AI制作的 ImmortalWrt 专用蜜罐防火墙脚本。它的逻辑非常简单粗暴:谁敢碰我的诱捕端口,我就直接把它的 IP 拉黑。

🛡️ 脚本功能亮点

  • 全自动诱捕:监听指定端口(默认 TCP/UDP 7088),一旦有人扫描或尝试连接,立即触发报警。
  • 秒级封禁:Python 后台脚本实时监控日志,发现非法探测 IP 毫秒级拉黑。
  • NFTables 原生支持:专为新版 OpenWrt (Firewall4) 设计,无需安装 iptables,性能更高。
  • 白名单保护:自动识别内网 IP,支持手动添加白名单,防止把自己锁在门外。
  • 一键管理:提供类似老毛子固件的终端管理菜单,支持启动、停止、查看日志、管理黑白名单。
  • 无残留卸载:脚本自带“自毁”功能,不想用了可以一键彻底卸载,不留垃圾。

⚠️ 部署前必读(非常重要)

在执行脚本之前,必须关闭 OpenWrt 的“网络加速”功能。

因为开启硬件/软件分流后,流量会绕过 CPU 直接转发,导致防火墙无法抓取到诱捕包,脚本将失效。

  1. 进入路由器后台 -> 网络 -> 防火墙
  2. 找到 “路由/NAT 分流”“Turbo ACC 网络加速”
  3. 取消勾选 “软件流量分流” 和 “硬件流量分流”。
  4. 点击 保存并应用

🚀 一键部署命令

无需手动创建文件,连接 SSH 后,复制下面整段命令并回车,即可自动完成环境安装、脚本写入、服务配置和防火墙规则注入。

cat << 'INSTALL_EOF' > /tmp/install_honeypot.sh
#!/bin/bash

# ================= 变量定义 =================
PY_FILE="/root/main.py"
SVC_FILE="/etc/init.d/autoban"
MGR_FILE="/root/manager.sh"
BAN_LIST="/etc/ban_blacklist.txt"
WHITE_LIST="/etc/ban_whitelist.txt"
PORT_FILE="/etc/ban_port.conf"
LINK_BIN="/usr/bin/ban"

# 默认端口
DEFAULT_PORT="7088"

echo "-----------------------------------------------"
echo "正在安装 蜜罐防火墙 (全功能最终版)..."
echo "特性: 自动断连 / 本机豁免 / 自动刷新 / 历史日志"
echo "-----------------------------------------------"

# 0. 初始化配置
if [[ ! -f "$PORT_FILE" ]]; then
    echo "$DEFAULT_PORT" > "$PORT_FILE"
fi
[[ ! -f "$BAN_LIST" ]] && touch "$BAN_LIST"
[[ ! -f "$WHITE_LIST" ]] && touch "$WHITE_LIST"

# 1. 安装依赖 (关键包含 conntrack)
echo "[1/6] 安装系统依赖..."
opkg update
for pkg in python3 bash nano conntrack; do
    if ! opkg list-installed | grep -q "^$pkg"; then
        echo "安装 $pkg ..."
        opkg install "$pkg"
    fi
done

# 2. 写入核心 Python 脚本
echo "[2/6] 部署核心防护引擎..."
cat << 'EOF' > "$PY_FILE"
import subprocess, re, os, sys, time, threading

BLACKLIST_FILE = "/etc/ban_blacklist.txt"
WHITELIST_FILE = "/etc/ban_whitelist.txt"
PORT_FILE = "/etc/ban_port.conf"
LOG_PREFIX = "BAN_ME" 

def get_target_port():
    try:
        if os.path.exists(PORT_FILE):
            with open(PORT_FILE, 'r') as f:
                return f.read().strip()
    except: pass
    return "7088"

TARGET_PORT = get_target_port()

def load_set(filepath):
    if not os.path.exists(filepath): return set()
    try:
        with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
            return set(line.strip() for line in f if line.strip())
    except: return set()

# === 获取本机所有 IP (防自杀) ===
def get_self_ips():
    ips = set()
    try:
        cmd = "ip -4 addr | grep 'inet ' | awk '{print $2}' | cut -d/ -f1"
        res = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, text=True)
        if res.stdout:
            for line in res.stdout.splitlines():
                ip = line.strip()
                if ip: ips.add(ip)
    except: pass
    return ips

def is_whitelisted(ip):
    # 1. 基础内网段
    if ip.startswith("192.168.") or ip.startswith("10.") or ip.startswith("127."): return True
    # 2. 用户自定义白名单
    if ip in load_set(WHITELIST_FILE): return True
    # 3. 本机 IP (动态)
    if ip in get_self_ips(): return True
    return False

# 核心封禁动作
def execute_ban(ip):
    # 删除旧规则(防报错) -> 插入新规则 -> 切断连接
    subprocess.run(f"nft delete rule inet fw4 input ip saddr {ip} drop", shell=True, stderr=subprocess.DEVNULL)
    subprocess.run(f"nft insert rule inet fw4 input ip saddr {ip} drop", shell=True, stderr=subprocess.DEVNULL)
    subprocess.run(f"conntrack -D -s {ip}", shell=True, stderr=subprocess.DEVNULL)

def block_ip(ip, current_blacklist):
    if is_whitelisted(ip): return
    
    if ip not in current_blacklist:
        print(f"🚫 [封禁] 捕获 IP: {ip}")
        if ip not in load_set(BLACKLIST_FILE):
            try:
                with open(BLACKLIST_FILE, 'a') as f: f.write(f"{ip}\n")
            except: pass
        current_blacklist.add(ip)
    
    # 只要触发就强制执行封禁动作确保规则生效
    execute_ban(ip)

def scan_active_connections(current_blacklist):
    try:
        port = get_target_port()
        cmd = f"netstat -nt | grep ':{port}'"
        res = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, text=True)
        if res.stdout:
            for line in res.stdout.splitlines():
                parts = line.split()
                for p in parts:
                    if ":" in p and p.count('.') == 3:
                        ip = p.split(':')[0]
                        if ip not in ["0.0.0.0", "127.0.0.1"]:
                            block_ip(ip, current_blacklist)
    except: pass

def periodic_scan(current_blacklist):
    while True:
        scan_active_connections(current_blacklist)
        time.sleep(30)

def monitor_logs(current_blacklist):
    print(f"正在启动日志监控 (端口 {TARGET_PORT})...")
    proc = subprocess.Popen(['logread', '-f'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
    pat = re.compile(r'SRC=(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})')
    while True:
        line = proc.stdout.readline()
        if not line: break
        if LOG_PREFIX in line:
            m = pat.search(line)
            if m: block_ip(m.group(1), current_blacklist)

if __name__ == "__main__":
    sys.stdout.reconfigure(line_buffering=True)
    print("正在初始化规则...")
    
    current_blacklist = load_set(BLACKLIST_FILE)
    count = 0
    for ip in current_blacklist:
        if not is_whitelisted(ip):
            execute_ban(ip)
            count += 1
            
    print(f"✅ 已恢复 {count} 条历史封禁规则")
    
    t = threading.Thread(target=periodic_scan, args=(current_blacklist,), daemon=True)
    t.start()
    
    try: monitor_logs(current_blacklist)
    except KeyboardInterrupt: pass
EOF
chmod +x "$PY_FILE"

# 3. 写入系统服务
echo "[3/6] 配置系统守护进程..."
cat << 'EOF' > "$SVC_FILE"
#!/bin/sh /etc/rc.common
START=99
USE_PROCD=1
SCRIPT_PATH="/root/main.py"
PYTHON_BIN="/usr/bin/python3"

start_service() {
    procd_open_instance
    procd_set_param command "$PYTHON_BIN" "$SCRIPT_PATH"
    procd_set_param respawn 3600 5 0
    procd_set_param stdout 1
    procd_set_param stderr 1
    procd_close_instance
}
EOF
chmod +x "$SVC_FILE"
/etc/init.d/autoban enable

# 4. 写入管理菜单 (集成所有管理功能)
echo "[4/6] 生成智能管理菜单..."
cat << 'EOF' > "$MGR_FILE"
#!/bin/bash
SERVICE="autoban"
FILE_B="/etc/ban_blacklist.txt"
FILE_W="/etc/ban_whitelist.txt"
PORT_FILE="/etc/ban_port.conf"

[[ ! -f "$FILE_B" ]] && touch "$FILE_B"
[[ ! -f "$FILE_W" ]] && touch "$FILE_W"
[[ ! -f "$PORT_FILE" ]] && echo "7088" > "$PORT_FILE"

do_svc() { /etc/init.d/$SERVICE $1; sleep 1; }
get_st() { if pgrep -f "main.py">/dev/null; then echo -e "\033[32m运行中\033[0m"; else echo -e "\033[31m已停止\033[0m"; fi; }
get_port() { cat "$PORT_FILE"; }

# 全量刷新重启防火墙+重启服务
full_reload() {
    echo "-----------------------------------"
    echo "🔄 正在重载系统防火墙 (应用修改)..."
    /etc/init.d/firewall restart >/dev/null 2>&1
    echo "🔄 正在重启蜜罐服务..."
    /etc/init.d/$SERVICE restart >/dev/null 2>&1
    echo "✅ 状态已刷新。"
    sleep 1
}

change_port() {
    local old_port=$(get_port)
    echo "当前蜜罐端口: $old_port"
    read -p "请输入新的端口号 (1-65535): " new_port
    if [[ "$new_port" =~ ^[0-9]+$ ]] && [ "$new_port" -ge 1 ] && [ "$new_port" -le 65535 ]; then
        echo "$new_port" > "$PORT_FILE"
        uci set firewall.honeypot_tcp.dest_port="$new_port"
        uci set firewall.honeypot_udp.dest_port="$new_port"
        uci commit firewall
        full_reload
        echo "✅ 端口已修改为 $new_port"
        read -p "按回车继续..."
    else
        echo "❌ 无效的端口号!"
        sleep 1
    fi
}

manage_list_ui() {
    local file=$1
    local name=$2
    while true; do
        clear
        echo "=== $name 管理 (自动刷新防火墙) ==="
        if [[ ! -s "$file" ]]; then echo "(列表为空)"; else awk '{print NR". " $0}' "$file"; fi
        echo "----------------------------"
        echo "1. 添加 IP"
        echo "2. 删除 IP (按序号)"
        echo "3. 手动编辑 (Nano)"
        echo "0. 返回"
        echo "----------------------------"
        read -p "请选择: " opt
        case $opt in
            1) read -p "输入IP: " nip; [[ -n "$nip" ]] && { echo "$nip" >> "$file"; full_reload; };;
            2) read -p "输入序号: " num; [[ "$num" =~ ^[0-9]+$ ]] && { sed -i "${num}d" "$file"; full_reload; };;
            3) nano "$file"; full_reload;;
            0) break;;
        esac
    done
}

# 优化的日志查看先看历史再看实时
view_logs() {
    clear
    echo "=== 拦截日志查看器 ==="
    echo "正在读取最近 20 条历史记录..."
    echo "----------------------------------------------------"
    logread | grep -E "BAN_ME|python3" | tail -n 20
    echo "----------------------------------------------------"
    echo "📜 以上是历史记录 | 📡 以下是实时监控 (Ctrl+C 退出)"
    echo "----------------------------------------------------"
    trap 'return' SIGINT
    logread -f | grep -E "python3|BAN_ME"
    trap - SIGINT
}

uninstall_all() {
    read -p "确认卸载请输入 'yes': " c
    if [[ "$c" == "yes" ]]; then
        /etc/init.d/$SERVICE stop
        /etc/init.d/$SERVICE disable
        rm -f /etc/init.d/$SERVICE /root/main.py /root/manager.sh /usr/bin/ban
        uci delete firewall.honeypot_tcp
        uci delete firewall.honeypot_udp
        uci commit firewall
        /etc/init.d/firewall restart
        echo "已卸载"
        exit 0
    fi
}

while true; do
    clear
    echo "=== 蜜罐防火墙 (端口: $(get_port)) ==="
    echo "状态: $(get_st)"
    echo "---------------------------"
    echo "1. 启动服务"
    echo "2. 停止服务"
    echo "3. 重启服务"
    echo "4. 查看日志 (历史+实时)"
    echo "5. 黑名单管理 (自动刷新)"
    echo "6. 白名单管理 (自动刷新)"
    echo "7. 修改端口"
    echo "9. 卸载"
    echo "0. 退出"
    read -p "选项: " c
    case $c in
        1) do_svc start ;;
        2) do_svc stop ;;
        3) do_svc restart ;;
        4) view_logs ;;
        5) manage_list_ui "$FILE_B" "黑名单" ;;
        6) manage_list_ui "$FILE_W" "白名单" ;;
        7) change_port ;;
        9) uninstall_all ;;
        0) exit ;;
    esac
done
EOF
chmod +x "$MGR_FILE"
ln -sf "$MGR_FILE" "$LINK_BIN"

# 5. 防火墙配置
echo "[5/6] 配置防火墙规则..."
CURRENT_PORT=$(cat "$PORT_FILE")
uci delete firewall.honeypot_tcp 2>/dev/null
uci delete firewall.honeypot_udp 2>/dev/null
uci set firewall.honeypot_tcp=rule
uci set firewall.honeypot_tcp.name='Honeypot-TCP'
uci set firewall.honeypot_tcp.src='wan'
uci set firewall.honeypot_tcp.proto='tcp'
uci set firewall.honeypot_tcp.dest_port="$CURRENT_PORT"
uci set firewall.honeypot_tcp.target='LOG'
uci set firewall.honeypot_tcp.log_prefix='BAN_ME: '
uci set firewall.honeypot_udp=rule
uci set firewall.honeypot_udp.name='Honeypot-UDP'
uci set firewall.honeypot_udp.src='wan'
uci set firewall.honeypot_udp.proto='udp'
uci set firewall.honeypot_udp.dest_port="$CURRENT_PORT"
uci set firewall.honeypot_udp.target='LOG'
uci set firewall.honeypot_udp.log_prefix='BAN_ME: '
uci commit firewall
/etc/init.d/firewall restart

# 6. 启动服务
echo "[6/6] 启动防护服务..."
/etc/init.d/autoban restart

echo "-----------------------------------------------"
echo "✅ 安装成功!输入 ban 即可管理。"
echo "-----------------------------------------------"
INSTALL_EOF

# 执行安装
bash /tmp/install_honeypot.sh && rm -f /tmp/install_honeypot.sh

🎮 使用说明

  1. 呼出菜单:在 SSH 终端输入 ban 即可进入管理界面。
  2. 验证效果
    • 关闭手机 WiFi,使用 4G/5G 流量。
    • 在手机浏览器访问 http://你的公网IP:7088
    • 在电脑 SSH 终端输入 ban -> 选择 4. 查看实时日志
    • 你应该会看到 IP 被自动拉黑的提示。
  3. 如何解封自己?如果因为误操作导致自己无法连接 SSH,请重启路由器(拔电源),然后连接内网(192.168.x.x)进入后台,在 ban 菜单中编辑黑名单删除自己的 IP。

⚙️ 技术原理 (How it works)

这个系统由三个部分协同工作:

  1. 诱捕 (Trap):利用 nftables 在路由器的 input 链头部插入一条规则,任何访问 7088 端口的 TCP/UDP 流量都会被标记 BAN_ME: 并记录到系统日志。
  2. 监控 (Monitor):后台运行的 Python 脚本通过 logread -f 实时读取系统日志,使用正则匹配 BAN_ME: 关键词。
  3. 执行 (Action):一旦匹配到 IP,脚本会立即调用 nft insert ... drop 命令将该 IP 封禁,并将其写入永久黑名单文件。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注