×

iptables filter表FORWARD规则管理脚本

hqy hqy 发表于2025-10-16 16:13:16 浏览9 评论0

抢沙发发表评论

  iptables filter表FORWARD规则管理脚本

iptables filter表的FORWARD规则管理脚本主要用于管理和控制Linux系统中数据包的转发规则。这也是Linux开启转发后用的比较的防火墙规则,可以通过以下脚本方便快捷维护规则,减低iptables管理的复杂度,大大提升效率。

#!/bin/bash
# 防火墙规则智能管理工具 - 完整功能版
CONFIG_FILE="/etc/iptables/firewall_rules.cfg"
RULES_FILE="/etc/iptables/rules.v4"
# 检查root权限
check_root() {
    [ "$(id -u)" -ne 0 ] && echo "错误:需要root权限" && exit 1
}
# 检测后端类型
detect_backend() {
    iptables --version 2>&1 | grep -q nf_tables && echo "nft" || echo "legacy"
}
# 保存规则
save_rules() {
    if iptables-save > "$RULES_FILE" 2>/dev/null; then
        echo "✓ 规则已保存到 $RULES_FILE"
    else
        echo "⚠ 保存规则文件失败,但规则已添加到运行时"
    fi
}
# 显示当前规则带行号
show_rules_with_numbers() {
    echo "当前FORWARD链规则(带行号):"
    echo "============================="
    iptables -L FORWARD -n --line-numbers --verbose
    echo ""
}
# 智能添加规则(支持选择ACCEPT/DROP)
add_rule_smart() {
    local source_ip="$1"
    local dest="$2"
    local port="$3"
    local protocol="$4"
    local action="$5"
    local insert_position="$6"
    local comment="$7"
    local backend=$(detect_backend)
    echo "系统后端: $backend"
    [ "$protocol" == "any" ] && protocol="tcp"
    # 对于nftables后端,使用兼容方法
    if [ "$backend" == "nft" ]; then
        add_rule_nft_compatible "$source_ip" "$dest" "$port" "$protocol" "$action" "$insert_position" "$comment"
    else
        add_rule_legacy "$source_ip" "$dest" "$port" "$protocol" "$action" "$insert_position" "$comment"
    fi
}
# nftables后端兼容方法
add_rule_nft_compatible() {
    local source_ip="$1"
    local dest="$2"
    local port="$3"
    local protocol="$4"
    local action="$5"
    local insert_position="$6"
    local comment="$7"
    local success_count=0
    echo "检测到nftables后端,使用兼容方法..."
    # 处理端口范围和多端口
    if [ "$port" != "any" ] && [ -n "$port" ]; then
        if echo "$port" | grep -q ":"; then
            # 端口范围: 22:23 → 分别添加22和23
            local start_port=${port%:*}
            local end_port=${port#*:}
            if [ "$start_port" -le "$end_port" ] 2>/dev/null; then
                echo "检测到端口范围 $port,将拆分为单个端口添加..."
                for ((p=start_port; p<=end_port; p++)); do
                    if add_single_rule "$source_ip" "$dest" "$p" "$protocol" "$action" "$insert_position" "$comment"; then
                        ((success_count++))
                    fi
                done
            else
                echo "✗ 无效的端口范围: $port"
                return 1
            fi
        elif echo "$port" | grep -q ","; then
            # 多端口: 80,443 → 分别添加
            IFS=',' read -ra ports <<< "$port"
            for p in "${ports[@]}"; do
                p=$(echo "$p" | xargs)
                [ -z "$p" ] && continue
                if add_single_rule "$source_ip" "$dest" "$p" "$protocol" "$action" "$insert_position" "$comment"; then
                    ((success_count++))
                fi
            done
        else
            # 单个端口
            if add_single_rule "$source_ip" "$dest" "$port" "$protocol" "$action" "$insert_position" "$comment"; then
                ((success_count++))
            fi
        fi
    else
        # 任意端口
        if add_single_rule "$source_ip" "$dest" "" "$protocol" "$action" "$insert_position" "$comment"; then
            ((success_count++))
        fi
    fi
    [ $success_count -gt 0 ] && return 0 || return 1
}
# 添加单条规则(支持ACCEPT/DROP选择)
add_single_rule() {
    local source_ip="$1"
    local dest="$2"
    local port="$3"
    local protocol="$4"
    local action="$5"
    local insert_position="$6"
    local comment="$7"
    local cmd="iptables"
    # 判断是插入还是追加
    if [ -n "$insert_position" ] && [ "$insert_position" -gt 0 ]; then
        cmd="$cmd -I FORWARD $insert_position"
    else
        cmd="$cmd -A FORWARD"
    fi
    cmd="$cmd -s $source_ip -d $dest -p $protocol"
    if [ -n "$port" ]; then
        cmd="$cmd --dport $port"
    fi
    # 根据用户选择设置动作
    cmd="$cmd -j $action"
    echo "执行: $cmd"
    if eval "$cmd" 2>/dev/null; then
        echo "✓ 规则添加成功(动作: $action)"
        # 记录规则信息到配置文件
        local rule_id="rule_$(date +%s)_$RANDOM"
        local rule_info="$rule_id|$source_ip|$dest|$port|$protocol|$action|$insert_position||$comment"
        echo "$rule_info" >> "$CONFIG_FILE"
        echo "✓ 规则已记录 (ID: $rule_id)"
        return 0
    else
        echo "✗ 规则添加失败"
        return 1
    fi
}
# 传统iptables后端
add_rule_legacy() {
    local source_ip="$1"
    local dest="$2"
    local port="$3"
    local protocol="$4"
    local action="$5"
    local insert_position="$6"
    local comment="$7"
    local cmd="iptables"
    if [ -n "$insert_position" ] && [ "$insert_position" -gt 0 ]; then
        cmd="$cmd -I FORWARD $insert_position"
    else
        cmd="$cmd -A FORWARD"
    fi
    cmd="$cmd -s $source_ip -d $dest -p $protocol"
    if [ "$port" != "any" ] && [ -n "$port" ]; then
        if echo "$port" | grep -q ","; then
            cmd="$cmd -m multiport --dports $port"
        else
            cmd="$cmd --dport $port"
        fi
    fi
    # 根据用户选择设置动作
    cmd="$cmd -j $action"
    echo "执行: $cmd"
    if eval "$cmd"; then
        echo "✓ 规则添加成功(动作: $action)"
        local rule_id="rule_$(date +%s)_$RANDOM"
        echo "$rule_id|$source_ip|$dest|$port|$protocol|$action|$insert_position||$comment" >> "$CONFIG_FILE"
        echo "✓ 规则已记录 (ID: $rule_id)"
        return 0
    else
        echo "✗ 规则添加失败"
        return 1
    fi
}
# 添加规则主函数
add_rule() {
    echo "添加防火墙规则"
    echo "================"
    show_rules_with_numbers
    read -p "源IP地址/CIDR: " source_ip
    read -p "目标地址/CIDR: " dest
    read -p "端口 (支持: 80 / 80,443 / 22:23 / any): " port
    read -p "协议 (tcp/udp, 默认tcp): " protocol
    # 选择ACCEPT/DROP动作
    echo ""
    echo "选择规则动作:"
    echo "1. ACCEPT (允许通过)"
    echo "2. DROP (拒绝并丢弃)"
    echo "3. REJECT (拒绝并返回错误)"
    read -p "请选择动作 (1-3, 默认1): " action_choice
    case $action_choice in
        1|"") action="ACCEPT" ;;
        2) action="DROP" ;;
        3) action="REJECT" ;;
        *) action="ACCEPT" ; echo "使用默认动作: ACCEPT" ;;
    esac
    read -p "插入位置行号 (直接回车追加到末尾): " insert_position
    read -p "备注说明: " comment
    [ -z "$protocol" ] && protocol="tcp"
    [ -z "$port" ] && port="any"
    [ -z "$insert_position" ] && insert_position=""
    # 验证输入
    if ! echo "$source_ip" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+(/[0-9]+)?$' || \
       ! echo "$dest" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+(/[0-9]+)?$'; then
        echo "✗ IP地址格式错误" && return 1
    fi
    echo -e "\n规则摘要:"
    echo "源: $source_ip -> 目标: $dest"
    echo "协议: $protocol, 端口: $port"
    echo "动作: $action"
    [ -n "$insert_position" ] && echo "插入位置: 第 $insert_position 行"
    echo "备注: $comment"
    read -p "确认添加? (y/n): " confirm
    if [ "$confirm" == "y" ] || [ "$confirm" == "Y" ]; then
        if add_rule_smart "$source_ip" "$dest" "$port" "$protocol" "$action" "$insert_position" "$comment"; then
            save_rules
            echo -e "\n添加后的规则列表:"
            show_rules_with_numbers
        else
            echo "✗ 规则添加失败"
        fi
    else
        echo "操作取消"
    fi
}
# 修复的规则内容匹配删除功能(解决图片中的问题)
delete_rule_by_content_fixed() {
    echo "按规则内容匹配删除(修复版)"
    echo "==========================="
    show_rules_with_numbers
    read -p "输入要删除的规则源IP: " source_ip
    read -p "输入要删除的规则目标IP: " dest_ip
    read -p "输入要删除的规则端口 (可选): " port
    read -p "输入要删除的规则协议 (可选): " protocol
    # 输入验证
    if [ -z "$source_ip" ] && [ -z "$dest_ip" ]; then
        echo "错误:至少需要输入源IP或目标IP"
        return 1
    fi
    echo -e "\n搜索条件:"
    [ -n "$source_ip" ] && echo "源IP: $source_ip"
    [ -n "$dest_ip" ] && echo "目标IP: $dest_ip"
    [ -n "$port" ] && echo "端口: $port"
    [ -n "$protocol" ] && echo "协议: $protocol"
    echo ""
    # 获取规则并匹配(修复字段解析)
    local rules_output=$(iptables -L FORWARD -n --line-numbers | tail -n +3)
    local matched_lines=()
    local match_count=0
    echo "匹配的规则:"
    while IFS= read -r line; do
        [ -z "$line" ] && continue
        # 修复:使用更可靠的字段解析方法
        local line_num=$(echo "$line" | awk '{print $1}')
        local rule_target=$(echo "$line" | awk '{print $2}')
        local rule_prot=$(echo "$line" | awk '{print $3}')
        # 修复:正确提取源IP和目标IP(解决图片中的问题)
        # 使用正则表达式提取IP地址,不依赖固定位置
        local ip_matches=$(echo "$line" | grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}(/[0-9]{1,2})?' | head -2)
        local rule_src=$(echo "$ip_matches" | sed -n '1p')
        local rule_dst=$(echo "$ip_matches" | sed -n '2p')
        # 修复:正确提取端口信息
        local rule_port=""
        if echo "$line" | grep -q "dpt:"; then
            rule_port=$(echo "$line" | grep -oE 'dpt:[0-9]+' | head -1 | cut -d: -f2)
        fi
        # 调试信息(显示解析结果)
        echo "调试: 行$line_num 源:$rule_src 目标:$rule_dst 协议:$rule_prot 端口:$rule_port"
        # 检查是否匹配
        local match=1
        # 源IP匹配(精确匹配)
        if [ -n "$source_ip" ]; then
            if [ "$rule_src" != "$source_ip" ]; then
                match=0
                echo "调试: 源IP不匹配 - 规则:$rule_src 输入:$source_ip"
            fi
        fi
        # 目标IP匹配
        if [ $match -eq 1 ] && [ -n "$dest_ip" ]; then
            if [ "$rule_dst" != "$dest_ip" ]; then
                match=0
                echo "调试: 目标IP不匹配 - 规则:$rule_dst 输入:$dest_ip"
            fi
        fi
        # 协议匹配
        if [ $match -eq 1 ] && [ -n "$protocol" ]; then
            if [ "$rule_prot" != "$protocol" ] && [ "$rule_prot" != "all" ]; then
                match=0
                echo "调试: 协议不匹配 - 规则:$rule_prot 输入:$protocol"
            fi
        fi
        # 端口匹配
        if [ $match -eq 1 ] && [ -n "$port" ]; then
            if [ -z "$rule_port" ] || [ "$rule_port" != "$port" ]; then
                match=0
                echo "调试: 端口不匹配 - 规则端口:$rule_port 输入端口:$port"
            fi
        fi
        # 只匹配ACCEPT/DROP/REJECT规则,避免匹配DOCKER链等
        if [ $match -eq 1 ] && [[ "$rule_target" =~ ^(ACCEPT|DROP|REJECT)$ ]]; then
            echo "✓ 匹配规则行号 $line_num: $line"
            matched_lines+=($line_num)
            ((match_count++))
        elif [ $match -eq 1 ]; then
            echo "调试: 规则目标不匹配 - $rule_target"
        fi
    done <<< "$rules_output"
    if [ $match_count -eq 0 ]; then
        echo "未找到匹配的规则"
        echo ""
        echo "可能的原因:"
        echo "1. IP地址输入错误(请检查源IP和目标IP)"
        echo "2. 规则可能在其他链中(如DOCKER-USER)"
        echo "3. 匹配条件太严格"
        echo "4. 规则显示格式解析问题(已修复)"
        return 1
    fi
    echo -e "\n找到 $match_count 条匹配规则"
    read -p "确认删除这些规则? (y/n): " confirm
    if [ "$confirm" = "y" ] || [ "$confirm" = "Y" ]; then
        local deleted_count=0
        # 倒序删除(避免行号变化)
        for ((i=${#matched_lines[@]}-1; i>=0; i--)); do
            local line_num=${matched_lines[i]}
            echo "删除行号 $line_num..."
            if iptables -D FORWARD $line_num 2>/dev/null; then
                echo "✓ 删除成功"
                ((deleted_count++))
                sleep 0.1
            else
                echo "✗ 删除失败"
            fi
        done
        echo "删除完成: $deleted_count/$match_count 条规则被删除"
        save_rules
        echo -e "\n删除后的规则列表:"
        show_rules_with_numbers
    else
        echo "删除操作已取消"
    fi
}
# 批量删除行号功能
delete_rule_by_number_enhanced() {
    show_rules_with_numbers
    echo "批量删除说明:"
    echo "• 输入单个行号: 删除指定规则"
    echo "• 输入多个行号(用逗号分隔): 7,8,9"
    echo "• 输入范围: 10-15"
    echo "• 混合输入: 7,8,10-12,15"
    echo ""
    read -p "输入要删除的行号: " line_input
    if [ -z "$line_input" ]; then
        echo "错误:请输入行号"
        return 1
    fi
    # 解析输入的行号
    local lines_to_delete=()
    IFS=',' read -ra parts <<< "$line_input"
    for part in "${parts[@]}"; do
        part=$(echo "$part" | xargs)
        if [[ "$part" == *"-"* ]]; then
            local start_range=${part%-*}
            local end_range=${part#*-}
            if [[ "$start_range" =~ ^[0-9]+$ ]] && [[ "$end_range" =~ ^[0-9]+$ ]] && [ "$start_range" -le "$end_range" ]; then
                for ((i=start_range; i<=end_range; i++)); do
                    lines_to_delete+=($i)
                done
            else
                echo "⚠ 忽略无效范围: $part"
            fi
        else
            if [[ "$part" =~ ^[0-9]+$ ]]; then
                lines_to_delete+=($part)
            else
                echo "⚠ 忽略无效行号: $part"
            fi
        fi
    done
    if [ ${#lines_to_delete[@]} -eq 0 ]; then
        echo "错误:没有有效的行号输入"
        return 1
    fi
    lines_to_delete=($(printf "%s\n" "${lines_to_delete[@]}" | sort -nu))
    echo "将要删除的行号: ${lines_to_delete[*]}"
    echo -e "\n将要删除的规则:"
    local total_rules=$(iptables -L FORWARD -n --line-numbers | tail -n +3 | wc -l)
    for line_num in "${lines_to_delete[@]}"; do
        if [ "$line_num" -ge 1 ] && [ "$line_num" -le "$total_rules" ]; then
            local rule_info=$(iptables -L FORWARD -n --line-numbers | awk -v line="$line_num" '$1 == line')
            echo "行号 $line_num: $rule_info"
        else
            echo "⚠ 行号 $line_num 无效(有效范围: 1-$total_rules)"
        fi
    done
    read -p "确认删除以上规则? (y/n): " confirm
    if [ "$confirm" == "y" ] || [ "$confirm" == "Y" ]; then
        local deleted_count=0
        local failed_count=0
        IFS=$'\n' sorted_lines=($(sort -nr <<< "${lines_to_delete[*]}"))
        unset IFS
        for line_num in "${sorted_lines[@]}"; do
            if [ "$line_num" -ge 1 ] && [ "$line_num" -le "$total_rules" ]; then
                echo "删除行号 $line_num..."
                if iptables -D FORWARD "$line_num" 2>/dev/null; then
                    echo "✓ 删除成功"
                    ((deleted_count++))
                    sleep 0.1
                else
                    echo "✗ 删除失败"
                    ((failed_count++))
                fi
            else
                echo "⚠ 跳过无效行号: $line_num"
                ((failed_count++))
            fi
        done
        echo "删除完成: 成功 $deleted_count 条, 失败 $failed_count 条"
        save_rules
        echo -e "\n删除后的规则列表:"
        show_rules_with_numbers
    else
        echo "删除操作已取消"
    fi
}
# 删除规则主函数
delete_rule() {
    echo "删除规则选项:"
    echo "1. 按行号删除(支持批量删除多条规则)"
    echo "2. 按规则内容匹配删除(修复版)"
    echo "3. 清空整个FORWARD链"
    read -p "请选择删除方式 (1-3): " delete_method
    case $delete_method in
        1) delete_rule_by_number_enhanced ;;
        2) delete_rule_by_content_fixed ;;
        3)
            read -p "确认清空整个FORWARD链? (y/n): " confirm
            if [ "$confirm" == "y" ]; then
                iptables -F FORWARD
                echo "✓ FORWARD链已清空"
                save_rules
                echo -e "\n清空后的规则列表:"
                show_rules_with_numbers
            else
                echo "操作取消"
            fi
            ;;
        *)
            echo "无效选择"
            ;;
    esac
}
# 主菜单
main_menu() {
    check_root
    mkdir -p /etc/iptables
    echo "防火墙规则智能管理工具"
    echo "系统信息: iptables $(iptables --version 2>&1 | head -1)"
    echo "后端类型: $(detect_backend)"
    while true; do
        echo -e "\n请选择操作:"
        echo "1. 添加规则(支持选择ACCEPT/DROP)"
        echo "2. 删除规则(包含修复的内容匹配删除)"
        echo "3. 查看当前规则"
        echo "4. 保存规则到文件"
        echo "5. 退出"
        read -p "选择 (1-5): " choice
        case $choice in
            1) add_rule ;;
            2) delete_rule ;;
            3) show_rules_with_numbers ;;
            4) save_rules ;;
            5) exit 0 ;;
            *) echo "无效选择" ;;
        esac
    done
}
# 启动脚本
main_menu


测试界面如下


图片




打赏

本文链接:https://kinber.cn/post/5718.html 转载需授权!

分享到:


推荐本站淘宝优惠价购买喜欢的宝贝:

image.png

 您阅读本篇文章共花了: 

群贤毕至

访客