本文目录导读:

我可以为您提供一个完整的Shell脚本,用于扫描开放端口并在发现特定服务时发送告警,以下是几种不同方案的实现:
基于nc(netcat)的简单端口扫描脚本
#!/bin/bash
# 配置参数
TARGET_HOST="192.168.1.1" # 目标主机IP
PORTS=(22 80 443 3306 8080) # 要扫描的端口列表
TIMEOUT=2 # 超时时间(秒)
LOG_FILE="/var/log/port_scan.log"
ALERT_EMAIL="admin@example.com"
# 颜色代码
RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m' # 无颜色
# 创建日志目录
mkdir -p "$(dirname "$LOG_FILE")"
echo "========== 端口扫描报告 ==========" > "$LOG_FILE"
echo "扫描时间: $(date)" >> "$LOG_FILE"
echo "目标主机: $TARGET_HOST" >> "$LOG_FILE"
echo "--------------------------------" >> "$LOG_FILE"
echo "开始扫描 $TARGET_HOST 的端口..."
open_ports=""
for port in "${PORTS[@]}"; do
# 使用nc检查端口
if nc -z -w "$TIMEOUT" "$TARGET_HOST" "$port" 2>/dev/null; then
echo -e "${GREEN}[开放]${NC} 端口 $port"
echo "[开放] 端口 $port" >> "$LOG_FILE"
# 收集开放端口信息用于告警
if [ -z "$open_ports" ]; then
open_ports="$port"
else
open_ports="$open_ports, $port"
fi
else
echo -e "${RED}[关闭]${NC} 端口 $port"
echo "[关闭] 端口 $port" >> "$LOG_FILE"
fi
done
echo "--------------------------------" >> "$LOG_FILE"
echo "扫描完成: $(date)" >> "$LOG_FILE"
# 如果有开放端口,发送告警
if [ -n "$open_ports" ]; then
echo "⚠️ 发现开放端口: $open_ports"
# 发送邮件告警
if command -v mail &> /dev/null; then
echo "目标 $TARGET_HOST 发现开放端口: $open_ports" | \
mail -s "[告警] 端口扫描结果 - $TARGET_HOST" "$ALERT_EMAIL"
fi
# 发送系统日志
logger "端口扫描告警: $TARGET_HOST 开放端口: $open_ports"
fi
使用nmap的高级扫描脚本
#!/bin/bash
# 配置参数
TARGET_SUBNET="192.168.1.0/24" # 目标子网
SCAN_PORTS="1-1000" # 扫描端口范围
SCAN_SPEED="T4" # 扫描速度 T1-T5
LOG_DIR="/var/log/port_scans"
ALERT_THRESHOLD=5 # 开放端口超过此数量则告警
# 依赖检查
if ! command -v nmap &> /dev/null; then
echo "错误: 未安装nmap,请先安装"
exit 1
fi
# 创建日志目录
mkdir -p "$LOG_DIR"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
LOG_FILE="$LOG_DIR/scan_$TIMESTAMP.log"
# 执行nmap扫描
echo "开始扫描 $TARGET_SUBNET ..."
nmap -"$SCAN_SPEED" -p "$SCAN_PORTS" --open "$TARGET_SUBNET" \
-oN "$LOG_FILE" 2>/dev/null
# 解析结果
OPEN_PORT_COUNT=$(grep -c "^[0-9]/tcp" "$LOG_FILE")
echo "发现 $OPEN_PORT_COUNT 个开放端口"
# 告警逻辑
if [ "$OPEN_PORT_COUNT" -gt "$ALERT_THRESHOLD" ]; then
echo "⚠️ 端口开放数量超过阈值!"
# 保存告警报告
REPORT_FILE="$LOG_DIR/alert_$TIMESTAMP.txt"
{
echo "时间: $(date)"
echo "目标: $TARGET_SUBNET"
echo "开放端口数: $OPEN_PORT_COUNT"
echo "详情:"
grep "^[0-9]/tcp" "$LOG_FILE"
} > "$REPORT_FILE"
# Slack/Webhook 告警示例
if [ -n "$SLACK_WEBHOOK_URL" ]; then
curl -X POST -H "Content-Type: application/json" \
-d "{\"text\":\"端口扫描告警: $TARGET_SUBNET 发现 $OPEN_PORT_COUNT 个开放端口\"}" \
"$SLACK_WEBHOOK_URL"
fi
fi
带Webhook和状态检查的完整监控脚本
#!/bin/bash
# ========== 配置区域 ==========
TARGET_HOST="example.com"
PORTS=(80 443 22 3306 6379 8080)
TIMEOUT=3
CHECK_INTERVAL=300 # 检查间隔(秒)
STATE_DIR="/tmp/port_monitor"
# 告警配置
ENABLE_EMAIL=false
EMAIL_ADDRESS=""
ENABLE_WEBHOOK=true
WEBHOOK_URL="https://hooks.example.com/alert"
ENABLE_LOGGING=true
LOG_FILE="/var/log/port_monitor.log"
# 服务名称映射
declare -A SERVICE_NAMES=(
[22]="SSH"
[80]="HTTP"
[443]="HTTPS"
[3306]="MySQL"
[6379]="Redis"
[8080]="HTTP-Alt"
)
# ========== 函数定义 ==========
log_message() {
local level="$1"
local message="$2"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
if [ "$ENABLE_LOGGING" = true ]; then
echo "[$timestamp] [$level] $message" >> "$LOG_FILE"
fi
echo "[$timestamp] [$level] $message"
}
send_alert() {
local subject="$1"
local message="$2"
# Webhook 告警
if [ "$ENABLE_WEBHOOK" = true ] && [ -n "$WEBHOOK_URL" ]; then
local payload=$(cat <<EOF
{: "$subject",
"message": "$message",
"timestamp": "$(date -Iseconds)"
}
EOF
)
curl -s -X POST -H "Content-Type: application/json" \
-d "$payload" "$WEBHOOK_URL" &>/dev/null
fi
# 邮件告警
if [ "$ENABLE_EMAIL" = true ] && [ -n "$EMAIL_ADDRESS" ]; then
echo "$message" | mail -s "$subject" "$EMAIL_ADDRESS"
fi
}
check_port() {
local host="$1"
local port="$2"
local service_name="${SERVICE_NAMES[$port]:-$port}"
# 使用 /dev/tcp 进行端口检查
timeout "$TIMEOUT" bash -c "echo >/dev/tcp/$host/$port" 2>/dev/null
return $?
}
get_service_banner() {
local host="$1"
local port="$2"
# 尝试获取服务banner
exec 3<>/dev/tcp/$host/$port 2>/dev/null
if [ $? -eq 0 ]; then
read -t 2 banner <&3
exec 3>&-
echo "$banner"
fi
}
# ========== 主逻辑 ==========
# 创建状态目录
mkdir -p "$STATE_DIR"
echo "========== 端口监控服务启动 =========="
log_message "INFO" "监控目标: $TARGET_HOST"
log_message "INFO" "监控端口: ${PORTS[*]}"
while true; do
timestamp=$(date '+%Y-%m-%d %H:%M:%S')
changes_detected=false
for port in "${PORTS[@]}"; do
state_file="$STATE_DIR/${port}_state"
service_name="${SERVICE_NAMES[$port]:-$port}"
# 检查端口状态
if check_port "$TARGET_HOST" "$port"; then
current_state="open"
# 获取服务banner
banner=$(get_service_banner "$TARGET_HOST" "$port")
else
current_state="closed"
banner=""
fi
# 读取上次状态
if [ -f "$state_file" ]; then
last_state=$(cat "$state_file")
else
last_state=""
fi
# 状态变化检测
if [ "$current_state" != "$last_state" ]; then
changes_detected=true
echo "$current_state" > "$state_file"
if [ "$current_state" = "open" ]; then
alert_msg="${service_name}($port) 端口从关闭变为开放"
alert_data="服务: $service_name\n端口: $port\n目标: $TARGET_HOST\n时间: $timestamp\nBanner: ${banner:-无}"
else
alert_msg="${service_name}($port) 端口从开放变为关闭"
alert_data="服务: $service_name\n端口: $port\n目标: $TARGET_HOST\n时间: $timestamp"
fi
log_message "WARN" "$alert_msg"
send_alert "[端口监控] $alert_msg" "$alert_data"
fi
done
if [ "$changes_detected" = false ]; then
log_message "DEBUG" "未检测到端口状态变化"
fi
sleep "$CHECK_INTERVAL"
done
使用说明
安装依赖
# 方案一需要 apt-get install netcat-openbsd # Debian/Ubuntu yum install nmap-ncat # CentOS/RHEL # 方案二需要 apt-get install nmap # Debian/Ubuntu yum install nmap # CentOS/RHEL
运行脚本
# 赋予执行权限 chmod +x port_scanner.sh # 运行方案一 ./port_scanner.sh # 方案三作为服务运行 nohup ./port_monitor.sh > /dev/null 2>&1 & # 或者使用systemd创建服务 cat > /etc/systemd/system/port-monitor.service << EOF [Unit] Description=Port Monitor Service After=network.target [Service] ExecStart=/path/to/port_monitor.sh Restart=always User=root [Install] WantedBy=multi-user.target EOF systemctl daemon-reload systemctl enable port-monitor systemctl start port-monitor
告警方式
脚本支持多种告警方式:
- 邮件告警 - 使用mail命令
- Webhook - 支持Slack、钉钉等
- 系统日志 - 通过logger命令
- 文件日志 - 记录到指定文件
您可以根据实际需求选择适合的方案并进行配置。