自留地
切勿乱来!
     找回密码    哈林摇

CentOS拦截大量来自机房(指定运营商)的非法请求

#Linux专题

最近服务器受到大量来自机房的非法请求扫描,被后台监测到,纯纯的浪费服务器资源,所以写了一个脚本,利用CentOS防火墙进行自动封禁

#!/bin/bash
# Nginx日志DNS反查脚本 - 仅保存包含hwclouds的DNS记录并自动添加到防火墙
# 用途:读取nginx站点日志,获取访问IP,反查DNS记录,仅保存包含hwclouds的IP并添加到防火墙

# 设置颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# 配置参数
NGINX_LOG_PATH="/你的站点log"  # Nginx日志路径,请根据实际情况修改
OUTPUT_FILE="ip_dns_records.txt"             # 输出保存记录
TEMP_FILE="temp_ip_list.txt"                 # 临时IP列表文件
RESOLVE_TIMEOUT=3                            # DNS解析超时时间(秒)
MAX_PARALLEL=10                              # 最大并发数
FILTER_KEYWORD="hwclouds"                    # 过滤关键字,只保存包含此关键字的DNS记录
ENABLE_FIREWALL=1                            # 是否启用防火墙自动添加(1=启用,0=禁用)
FIREWALL_ZONE="public"                       # 防火墙区域
DRY_RUN=0                                    # 试运行模式(只显示将要执行的命令,不实际执行)

# 函数:打印带颜色的消息
print_message() {
    echo -e "${2}${1}${NC}"
}

# 函数:检查依赖工具
check_dependencies() {
    local missing_tools=()

    if ! command -v dig &> /dev/null; then
        missing_tools+=("bind-utils (dig)")
    fi

    if ! command -v awk &> /dev/null; then
        missing_tools+=("awk")
    fi

    if ! command -v sort &> /dev/null; then
        missing_tools+=("sort")
    fi

    if [ $ENABLE_FIREWALL -eq 1 ] && ! command -v firewall-cmd &> /dev/null; then
        print_message "警告:firewall-cmd 未找到,将禁用防火墙功能" "${YELLOW}"
        ENABLE_FIREWALL=0
    fi

    if [ ${#missing_tools[@]} -gt 0 ]; then
        print_message "错误:缺少以下工具,请先安装:" "${RED}"
        for tool in "${missing_tools[@]}"; do
            echo "  - $tool"
        done
        echo ""
        echo "安装命令:"
        echo "  CentOS/RHEL: yum install bind-utils gawk"
        echo "  Ubuntu/Debian: apt-get install dnsutils gawk"
        exit 1
    fi
}

# 函数:检查日志文件是否存在
check_log_file() {
    if [ ! -f "$NGINX_LOG_PATH" ]; then
        print_message "错误:Nginx日志文件不存在: $NGINX_LOG_PATH" "${RED}"
        exit 1
    fi
}

# 函数:从nginx日志提取IP地址
extract_ips() {
    print_message "正在从nginx日志提取IP地址..." "${GREEN}"

    # 常见nginx日志格式提取IP(第一列通常是IP)
    # 如果日志格式不同,请调整awk命令
    awk '{print $1}' "$NGINX_LOG_PATH" | \
        grep -E '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$' | \
        sort -u > "$TEMP_FILE"

    local ip_count=$(wc -l < "$TEMP_FILE")
    print_message "提取到 $ip_count 个唯一IP地址" "${YELLOW}"

    if [ $ip_count -eq 0 ]; then
        print_message "错误:未提取到有效的IP地址" "${RED}"
        exit 1
    fi
}

# 函数:反查单个IP的DNS记录(仅返回包含hwclouds的记录)
resolve_ip() {
    local ip=$1
    local result=""

    # 使用dig进行反向DNS查询
    # 使用+short选项获取简洁输出,设置超时时间
    result=$(dig -x "$ip" +short +timeout="$RESOLVE_TIMEOUT" +tries=1 2>/dev/null | head -1)

    if [ -n "$result" ] && [ "$result" != "." ]; then
        # 去掉末尾的点
        result=$(echo "$result" | sed 's/\.$//')

        # 检查DNS记录是否包含过滤关键字
        if echo "$result" | grep -qi "$FILTER_KEYWORD"; then
            echo "$ip -> $result"
            return 0
        fi
    fi
    return 1
}

# 函数:检查防火墙规则是否已存在
check_firewall_rule_exists() {
    local ip=$1
    local rule="rule family=\"ipv4\" source address=\"$ip\" drop"

    if firewall-cmd --zone="$FIREWALL_ZONE" --query-rich-rule="$rule" &>/dev/null; then
        return 0  # 规则存在
    else
        return 1  # 规则不存在
    fi
}

# 函数:添加IP到防火墙
add_ip_to_firewall() {
    local ip=$1
    local dns_record=$2
    local rule="rule family=\"ipv4\" source address=\"$ip\" drop"

    # 检查规则是否已存在
    if check_firewall_rule_exists "$ip"; then
        print_message "  [跳过] IP $ip ($dns_record) - 防火墙规则已存在" "${YELLOW}"
        return 0
    fi

    # 试运行模式
    if [ $DRY_RUN -eq 1 ]; then
        print_message "  [试运行] 将添加规则: firewall-cmd --zone=$FIREWALL_ZONE --permanent --add-rich-rule='$rule'" "${BLUE}"
        return 0
    fi

    # 实际添加防火墙规则
    if firewall-cmd --zone="$FIREWALL_ZONE" --permanent --add-rich-rule="$rule" &>/dev/null; then
        print_message "  [成功] 已添加 IP $ip ($dns_record) 到防火墙" "${GREEN}"
        return 0
    else
        print_message "  [失败] 添加 IP $ip 到防火墙失败" "${RED}"
        return 1
    fi
}

# 函数:批量添加IP到防火墙
batch_add_to_firewall() {
    if [ $ENABLE_FIREWALL -eq 0 ]; then
        print_message "防火墙功能已禁用,跳过添加规则" "${YELLOW}"
        return 0
    fi

    print_message "\n正在添加IP到防火墙..." "${GREEN}"

    if [ $DRY_RUN -eq 1 ]; then
        print_message "试运行模式:不会实际添加防火墙规则" "${BLUE}"
    fi

    local success_count=0
    local skip_count=0
    local fail_count=0

    # 读取输出文件中的IP和DNS记录
    while IFS=' -> ' read -r ip dns_record; do
        if [ -n "$ip" ] && [ -n "$dns_record" ]; then
            if add_ip_to_firewall "$ip" "$dns_record"; then
                if check_firewall_rule_exists "$ip"; then
                    if [ $DRY_RUN -eq 0 ]; then
                        skip_count=$((skip_count + 1))
                    else
                        success_count=$((success_count + 1))
                    fi
                else
                    success_count=$((success_count + 1))
                fi
            else
                fail_count=$((fail_count + 1))
            fi
        fi
    done < "$OUTPUT_FILE"

    # 重载防火墙规则(如果有新增)
    if [ $DRY_RUN -eq 0 ] && [ $success_count -gt 0 ] && [ $ENABLE_FIREWALL -eq 1 ]; then
        print_message "\n正在重载防火墙规则..." "${YELLOW}"
        if firewall-cmd --reload &>/dev/null; then
            print_message "防火墙规则重载成功" "${GREEN}"
        else
            print_message "防火墙规则重载失败" "${RED}"
        fi
    fi

    print_message "\n防火墙添加统计:" "${YELLOW}"
    echo "  成功添加: $success_count"
    echo "  已存在跳过: $skip_count"
    echo "  添加失败: $fail_count"
}

# 函数:导出函数以便在子shell中使用
export -f resolve_ip
export RESOLVE_TIMEOUT
export FILTER_KEYWORD

# 函数:批量反查DNS(使用xargs并发处理)
batch_resolve_dns() {
    print_message "正在反查DNS记录(并发数: $MAX_PARALLEL)..." "${GREEN}"
    print_message "过滤条件: 仅保存包含 \"$FILTER_KEYWORD\" 的DNS记录" "${YELLOW}"

    # 清空输出文件
    > "$OUTPUT_FILE"

    local total=$(wc -l < "$TEMP_FILE")
    local current=0
    local found=0

    # 使用xargs进行并发处理
    while IFS= read -r ip; do
        current=$((current + 1))
        echo -ne "进度: $current/$total\r" >&2

        # 调用解析函数
        result=$(resolve_ip "$ip")
        if [ $? -eq 0 ]; then
            echo "$result" >> "$OUTPUT_FILE"
            found=$((found + 1))
            echo -ne "\n找到匹配记录: $result                    \n" >&2
        fi
    done < "$TEMP_FILE"

    echo "" >&2
    print_message "完成!共找到 $found 个包含 \"$FILTER_KEYWORD\" 的DNS记录" "${GREEN}"
}

# 函数:使用并发方式(更快的版本,可选)
batch_resolve_dns_fast() {
    print_message "正在反查DNS记录(快速模式,并发数: $MAX_PARALLEL)..." "${GREEN}"
    print_message "过滤条件: 仅保存包含 \"$FILTER_KEYWORD\" 的DNS记录" "${YELLOW}"

    # 清空输出文件
    > "$OUTPUT_FILE"

    # 使用xargs并发执行,并过滤结果
    cat "$TEMP_FILE" | xargs -P "$MAX_PARALLEL" -I {} bash -c '
        result=$(dig -x {} +short +timeout='"$RESOLVE_TIMEOUT"' +tries=1 2>/dev/null | head -1)
        if [ -n "$result" ] && [ "$result" != "." ]; then
            result=$(echo "$result" | sed "s/\.$//")
            if echo "$result" | grep -qi "'"$FILTER_KEYWORD"'"; then
                echo "{} -> $result"
            fi
        fi
    ' > "$OUTPUT_FILE"

    local found=$(wc -l < "$OUTPUT_FILE")
    print_message "完成!共找到 $found 个包含 \"$FILTER_KEYWORD\" 的DNS记录" "${GREEN}"
}

# 函数:显示统计信息
show_statistics() {
    if [ -f "$OUTPUT_FILE" ] && [ -s "$OUTPUT_FILE" ]; then
        print_message "\n统计信息:" "${YELLOW}"

        local total_records=$(wc -l < "$OUTPUT_FILE")
        echo "总记录数: $total_records"

        echo ""
        print_message "所有找到的记录:" "${YELLOW}"
        cat "$OUTPUT_FILE"

        # 统计域名后缀分布(只统计匹配的记录)
        echo ""
        print_message "域名后缀分布:" "${YELLOW}"
        awk -F'-> ' '{print $2}' "$OUTPUT_FILE" | \
            awk -F'.' '{print $NF}' | \
            sort | uniq -c | sort -rn | head -10

        # 统计包含hwclouds的域名
        echo ""
        print_message "包含 \"$FILTER_KEYWORD\" 的域名列表:" "${YELLOW}"
        awk -F'-> ' '{print $2}' "$OUTPUT_FILE" | sort -u
    else
        print_message "未找到包含 \"$FILTER_KEYWORD\" 的DNS记录" "${YELLOW}"
    fi
}

# 函数:清理临时文件
cleanup() {
    if [ -f "$TEMP_FILE" ]; then
        rm -f "$TEMP_FILE"
    fi
}

# 函数:显示使用方法
show_usage() {
    cat << EOF
使用方法: $0 [选项]

选项:
    -l, --log PATH        指定nginx日志文件路径(默认: /www/wwwlogs/yourdomain.log)
    -o, --output FILE     指定输出文件路径(默认: ip_dns_records.txt)
    -t, --timeout SEC     DNS解析超时时间,单位秒(默认: 3)
    -p, --parallel NUM    并发数(默认: 10)
    -k, --keyword KEY     过滤关键字,只保存包含此关键字的DNS记录(默认: hwclouds)
    -f, --fast            使用快速并发模式(xargs)
    --enable-firewall     启用防火墙自动添加(默认启用)
    --disable-firewall    禁用防火墙自动添加
    --zone ZONE           指定防火墙区域(默认: public)
    --dry-run             试运行模式,只显示将要执行的命令,不实际执行
    -h, --help            显示此帮助信息

示例:
    # 基本用法:查找hwclouds记录并添加到防火墙
    $0

    # 自定义关键字
    $0 -k "huawei"

    # 快速模式,只查找不添加防火墙
    $0 -f --disable-firewall

    # 试运行模式,查看将要执行的操作
    $0 --dry-run

    # 显示当前防火墙规则
    $0 --show-rules

    # 指定防火墙区域
    $0 --zone internal -k "hwclouds"
EOF
    exit 0
}

# 主函数
main() {
    # 解析命令行参数
    local fast_mode=0
    local show_rules=0

    while [[ $# -gt 0 ]]; do
        case $1 in
            -l|--log)
                NGINX_LOG_PATH="$2"
                shift 2
                ;;
            -o|--output)
                OUTPUT_FILE="$2"
                shift 2
                ;;
            -t|--timeout)
                RESOLVE_TIMEOUT="$2"
                shift 2
                ;;
            -p|--parallel)
                MAX_PARALLEL="$2"
                shift 2
                ;;
            -k|--keyword)
                FILTER_KEYWORD="$2"
                shift 2
                ;;
            -f|--fast)
                fast_mode=1
                shift
                ;;
            --enable-firewall)
                ENABLE_FIREWALL=1
                shift
                ;;
            --disable-firewall)
                ENABLE_FIREWALL=0
                shift
                ;;
            --zone)
                FIREWALL_ZONE="$2"
                shift 2
                ;;
            --dry-run)
                DRY_RUN=1
                shift
                ;;
            --show-rules)
                show_rules=1
                shift
                ;;
            -h|--help)
                show_usage
                ;;
            *)
                print_message "未知选项: $1" "${RED}"
                show_usage
                ;;
        esac
    done

    # 如果只是显示防火墙规则
    if [ $show_rules -eq 1 ]; then
        check_dependencies
        exit 0
    fi

    # 显示配置信息
    print_message "========================================" "${GREEN}"
    print_message "Nginx日志DNS反查脚本(防火墙自动封禁版)" "${GREEN}"
    print_message "========================================" "${GREEN}"
    echo "日志文件: $NGINX_LOG_PATH"
    echo "输出文件: $OUTPUT_FILE"
    echo "DNS超时: ${RESOLVE_TIMEOUT}秒"
    echo "并发数: $MAX_PARALLEL"
    echo "过滤关键字: $FILTER_KEYWORD"
    echo "快速模式: $([ $fast_mode -eq 1 ] && echo '是' || echo '否')"
    echo "防火墙功能: $([ $ENABLE_FIREWALL -eq 1 ] && echo '启用' || echo '禁用')"
    if [ $ENABLE_FIREWALL -eq 1 ]; then
        echo "防火墙区域: $FIREWALL_ZONE"
        echo "试运行模式: $([ $DRY_RUN -eq 1 ] && echo '是' || echo '否')"
    fi
    echo ""

    # 检查依赖
    check_dependencies

    # 检查日志文件
    check_log_file

    # 提取IP地址
    extract_ips

    # 反查DNS
    if [ $fast_mode -eq 1 ]; then
        batch_resolve_dns_fast
    else
        batch_resolve_dns
    fi

    # 显示统计信息
    show_statistics

    # 添加IP到防火墙
    if [ $ENABLE_FIREWALL -eq 1 ] && [ -s "$OUTPUT_FILE" ]; then
        batch_add_to_firewall
    elif [ $ENABLE_FIREWALL -eq 1 ] && [ ! -s "$OUTPUT_FILE" ]; then
        print_message "没有找到需要添加的IP,跳过防火墙配置" "${YELLOW}"
    fi

    # 清理临时文件
    cleanup

    print_message "\n结果已保存到: $OUTPUT_FILE" "${GREEN}"
}

# 设置信号处理,确保清理临时文件
trap cleanup EXIT INT TERM

# 运行主函数
main "$@"

1. 保存脚本

# 保存脚本到文件
vi nginx_dns_resolver.sh

# 添加执行权限
chmod +x nginx_dns_resolver.sh

CentOS拦截大量来自机房(指定运营商)的非法请求
2. 基本使用

# 查找并自动添加防火墙规则
# 默认只保存包含hwclouds的记录
./nginx_dns_resolver.sh

# 自定义关键字
./nginx_dns_resolver.sh -k "huawei"

# 使用快速模式
./nginx_dns_resolver.sh -f -k "hwclouds"

# 支持多个关键字(需要修改grep参数,如改为 grep -E "$FILTER_KEYWORD")
./nginx_dns_resolver.sh -k "hwclouds|huawei"

# 只查找不添加防火墙
./nginx_dns_resolver.sh --disable-firewall

# 试运行模式(不实际添加)
./nginx_dns_resolver.sh --dry-run

# 自定义防火墙区域
./nginx_dns_resolver.sh --zone internal -k "hwclouds"

# 快速模式并添加防火墙
./nginx_dns_resolver.sh -f --enable-firewall

3.实现机制

利用bind-utils (dig)反查日志中的访问IP,获取含有dns的IP,比如:ecs-113-44-105-101.compute.hwclouds-dns.com 这种肯定是机房服务器,而不是真实用户。

然后记录下来并写入操作系统的防火墙firewall,进行阻断访问,宝塔面板的安全-系统防火墙-IP规则里会有记录增加!

收藏 打赏
×
版权声明:本文采用知识共享 署名4.0国际许可协议 [BY-NC-SA] 进行授权
文章名称:《CentOS拦截大量来自机房(指定运营商)的非法请求》
文章链接:https://www.ediok.cn/blog/2026/04/6694.html
本站资源仅供个人学习交流,请于下载后24小时内删除,不允许用于商业用途,否则法律问题自行承担。
分享到

评论 抢沙发

评论前必须登录!

 

关注互联网发展前沿,关注PHPCMS技术演进,钻研PHPCMS技术开发

问答社区 联系我们
后退
Alt+←
前进
Alt+→
刷新
F5
无法复制?

登录

登录即表示同意本站用户协议隐私政策
©2026 周涛博客 All rights reserved

注册

注册即表示同意本站用户协议隐私政策
©2026 周涛博客 All rights reserved

觉得文章有用就打赏一下文章作者

非常感谢你的打赏,我们将继续给力更多优质内容,让我们一起创建更加美好的网络世界!

微信扫一扫

微信扫一扫