OpenWrt 将CIDR格式IP地址集下载并导入ipset脚本

脚本代码:

#!/bin/sh

# 脚本功能: 1. 从 URL 下载 V4/V6 CIDR 列表。
#           2. *高效智能分析* 文件内容 (仅V4, 仅V6, 或 混合)。
#           3. 根据分析结果创建 ipset。
#           4. 将所有持久化规则写入 *一个* 文件 /etc/ipset.d/<name>.ipset
#           5. (精简) 移除所有条目计数功能,以确保稳定和高效。

# --- 参数检查 ---
if [ $# -ne 2 ]; then
    echo "错误: 参数不足。"
    echo "使用方法: $0 <URL> <基础名称>"
    echo "例如: $0 http://example.com/list.txt my_blacklist"
    exit 1
fi

URL="$1"
BASE_NAME="$2"
TMP_FILE=$(mktemp)

PERSIST_DIR="/etc/ipset.d"
PERSIST_FILE="$PERSIST_DIR/$BASE_NAME.ipset"

# --- 依赖和环境检查 ---
if ! command -v ipset >/dev/null; then
    echo "错误: 'ipset' 命令未找到。请安装: opkg update && opkg install ipset"
    rm "$TMP_FILE" 2>/dev/null
    exit 1
fi
if ! command -v wget >/dev/null; then
    echo "错误: 'wget' 命令未找到。请安装: opkg update && opkg install wget-ssl"
    rm "$TMP_FILE" 2>/dev/null
    exit 1
fi

mkdir -p "$PERSIST_DIR"
if [ -f "/etc/init.d/ipset" ] && [ ! -L "/etc/rc.d/S*ipset" ]; then
    echo "启用 ipset 开机启动服务..."
    /etc/init.d/ipset enable
fi

# --- 下载IP列表 ---
echo "正在从 $URL 下载IP列表..."
wget -q -O "$TMP_FILE" "$URL"
if [ $? -ne 0 ]; then
    echo "错误: 下载文件失败: $URL"
    rm "$TMP_FILE"
    exit 1
fi

# --- 高效分析文件内容 (流式检测) ---
HAS_V4=false
HAS_V6=false
# -q: 找到第一个匹配就退出
# -E: 使用扩展正则
# '^[ \t]*[^# \t]*\.': 匹配非注释行中的 .
# '^[ \t]*[^# \t]*:': 匹配非注释行中的 :
if grep -q -E '^[ \t]*[^# \t]*\.' "$TMP_FILE"; then
    HAS_V4=true
fi
if grep -q -E '^[ \t]*[^# \t]*:' "$TMP_FILE"; then
    HAS_V6=true
fi

# --- 辅助函数: 处理 "仅单一类型" 的列表 ---
process_single() {
    local SET_NAME="$1"
    local FAMILY="$2"
    
    echo "模式: 仅 $FAMILY。正在处理 ipset: $SET_NAME"
    
    # 1. 更新当前 ipset
    ipset destroy "$SET_NAME" >/dev/null 2>&1
    if ! ipset create "$SET_NAME" hash:net family "$FAMILY" -exist; then
        echo "错误: 创建 *当前* ipset '$SET_NAME' (family $FAMILY) 失败。"
        return 1
    fi
    
    # 2. 写入持久化文件 (覆盖)
    echo "创建/覆盖 *单一* 持久化文件: $PERSIST_FILE"
    echo "create $SET_NAME hash:net family $FAMILY -exist" > "$PERSIST_FILE"

    echo "正在导入条目到 $SET_NAME ..."
    # 3. 逐行导入 (流式处理)
    grep -vE '^[ \t]*#|^[ \t]*$' "$TMP_FILE" | while read -r line; do
        if [ -n "$line" ]; then
            # -exist: 忽略重复条目,不报错
            ipset add "$SET_NAME" "$line" -exist
            echo "add $SET_NAME $line" >> "$PERSIST_FILE"
        fi
    done
    
    echo "导入 $SET_NAME 完成。"
}

# --- 辅助函数: 处理 "混合类型" 的列表 ---
process_mixed() {
    local SET_NAME_V4="${BASE_NAME}_v4"
    local SET_NAME_V6="${BASE_NAME}_v6"

    echo "模式: 混合 (V4+V6)。正在处理 ipset: $SET_NAME_V4 和 $SET_NAME_V6"

    # 1. 更新当前 ipset
    ipset destroy "$SET_NAME_V4" >/dev/null 2>&1
    ipset destroy "$SET_NAME_V6" >/dev/null 2>&1
    if ! ipset create "$SET_NAME_V4" hash:net family inet -exist; then return 1; fi
    if ! ipset create "$SET_NAME_V6" hash:net family inet6 -exist; then return 1; fi

    # 2. 写入持久化文件 (覆盖)
    echo "创建/覆盖 *单一* 持久化文件: $PERSIST_FILE"
    echo "create $SET_NAME_V4 hash:net family inet -exist" > "$PERSIST_FILE"
    echo "create $SET_NAME_V6 hash:net family inet6 -exist" >> "$PERSIST_FILE"

    echo "正在分类导入 V4 和 V6 条目..."
    # 3. 逐行导入 (流式处理)
    grep -vE '^[ \t]*#|^[ \t]*$' "$TMP_FILE" | while read -r line; do
        if [ -z "$line" ]; then continue; fi
        
        if echo "$line" | grep -q ":"; then
            ipset add "$SET_NAME_V6" "$line" -exist
            echo "add $SET_NAME_V6 $line" >> "$PERSIST_FILE"
        elif echo "$line" | grep -q "\."; then
            ipset add "$SET_NAME_V4" "$line" -exist
            echo "add $SET_NAME_V4 $line" >> "$PERSIST_FILE"
        fi
    done
    
    echo "导入 $SET_NAME_V4 和 $SET_NAME_V6 完成。"
}

# --- 主要逻辑: 根据分析结果调用不同函数 ---
if [ "$HAS_V4" = true ] && [ "$HAS_V6" = true ]; then
    process_mixed
elif [ "$HAS_V4" = true ]; then
    process_single "$BASE_NAME" "inet"
elif [ "$HAS_V6" = true ]; then
    process_single "$BASE_NAME" "inet6"
else
    echo "警告: 在 $URL 中未找到有效的 IPv4 或 IPv6 地址。"
    echo "清空旧的 ipset (如果存在)..."
    ipset destroy "${BASE_NAME}" >/dev/null 2>&1
    ipset destroy "${BASE_NAME}_v4" >/dev/null 2>&1
    ipset destroy "${BASE_NAME}_v6" >/dev/null 2>&1
    # 写入一个空文件,以防旧的持久化文件被加载
    echo "# Empty ruleset" > "$PERSIST_FILE"
fi

# --- 清理 ---
rm "$TMP_FILE"
echo "脚本执行完毕。"

exit 0

使用方法

sh ipsetimporter.sh URL地址 名称

标签: none

添加新评论