最近服务器受到大量来自机房的非法请求扫描,被后台监测到,纯纯的浪费服务器资源,所以写了一个脚本,利用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

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规则里会有记录增加!
周涛博客








评论前必须登录!
注册