统计尝试SSH连接的IP地址脚本

ssh-login-stat.sh

#!/bin/bash
# 文件名: ssh-login-stat.sh
# 作者: wanghongwei
# 日期: 2026年8月20日
# 版本: 1.0
# 描述: 统计尝试 SSH 连接的 IP 地址:成功、无效用户、失败、其他探测、关闭、总计(按连接去重)
# 使用方式: ./ssh-login-stat.sh [日志文件,默认/var/log/secure]

logfile="${1:-/var/log/secure}"
if [[ ! -f "$logfile" ]]; then
    echo "错误:日志文件 '$logfile' 不存在" >&2
    exit 1
fi

# 单元格内容宽度定义
IP_W=20
SUC_W=10
INV_W=12
FAIL_W=10
OTHER_W=10
CLOSE_W=10
TOTAL_W=10

# 打印分隔线
print_sep() {
    printf "+"
    printf "%0.s-" $(seq 1 $((IP_W + 2))); printf "+"
    printf "%0.s-" $(seq 1 $((SUC_W + 2))); printf "+"
    printf "%0.s-" $(seq 1 $((INV_W + 2))); printf "+"
    printf "%0.s-" $(seq 1 $((FAIL_W + 2))); printf "+"
    printf "%0.s-" $(seq 1 $((OTHER_W + 2))); printf "+"
    printf "%0.s-" $(seq 1 $((CLOSE_W + 2))); printf "+"
    printf "%0.s-" $(seq 1 $((TOTAL_W + 2))); printf "+\n"
}

# 打印表头
print_sep
printf "| %-*s | %-*s | %-*s | %-*s | %-*s | %-*s | %-*s |\n" \
    $IP_W "IP Address" $SUC_W "Success" $INV_W "Invalid User" $FAIL_W "Failure" $OTHER_W "Other" $CLOSE_W "Close" $TOTAL_W "Total"
print_sep

# 使用 gawk 统计,按 sshd 进程号(PID)识别连接,状态优先级 1>2>3>4>5
gawk '
{
    # 跳过 sshd 服务状态日志
    if ($0 ~ /Server listening/) {
        next
    }

    # 提取 sshd 进程号,无 PID 则跳过
    if (!match($0, /sshd(-session)?\[([0-9]+)\]/, arr_pid)) {
        next
    }
    pid = arr_pid[2]

    # 提取 IP 地址,无 IP 则跳过
    if (!match($0, /[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/)) {
        next
    }
    ip = substr($0, RSTART, RLENGTH)

    key = pid
    conn_ip[key] = ip

    # 状态优先级:成功(1) > 无效用户(2) > 失败(3) > 关闭(4) > 其他(5)
    if ($0 ~ /Accepted publickey|Accepted password/) {
        if (status[key] == 0 || 1 < status[key]) status[key] = 1
    } else if ($0 ~ /Invalid user|Connection closed by invalid user/) {
        if (status[key] == 0 || 2 < status[key]) status[key] = 2
    } else if ($0 ~ /Failed password|Connection closed by authenticating user|drop connection.*MaxStartups|Connection reset by/) {
        if (status[key] == 0 || 3 < status[key]) status[key] = 3
    } else if ($0 ~ /Connection closed by/) {
        if (status[key] == 0 || 4 < status[key]) status[key] = 4
    } else {
        if (status[key] == 0) status[key] = 5
    }
}
END {
    # 按连接状态汇总到每个 IP
    for (key in status) {
        ip = conn_ip[key]
        if (status[key] == 1) succ[ip]++
        else if (status[key] == 2) inv[ip]++
        else if (status[key] == 3) fail[ip]++
        else if (status[key] == 4) closed[ip]++
        else if (status[key] == 5) other[ip]++
    }

    # 收集所有出现过的 IP
    for (ip in succ) all_ip[ip] = 1
    for (ip in inv)  all_ip[ip] = 1
    for (ip in fail) all_ip[ip] = 1
    for (ip in closed) all_ip[ip] = 1
    for (ip in other) all_ip[ip] = 1

    # 输出结果(列顺序:IP, Success, Invalid User, Failure, Other, Close, Total)
    for (ip in all_ip) {
        s = succ[ip] + 0
        i = inv[ip] + 0
        f = fail[ip] + 0
        o = other[ip] + 0
        c = closed[ip] + 0
        t = s + i + f + o + c
        print ip, s, i, f, o, c, t
    }
}' "$logfile" | sort -nr -k7 | while read -r ip s i f o c t; do
    printf "| %-*s | %-*d | %-*d | %-*d | %-*d | %-*d | %-*d |\n" \
        $IP_W "$ip" $SUC_W "$s" $INV_W "$i" $FAIL_W "$f" $OTHER_W "$o" $CLOSE_W "$c" $TOTAL_W "$t"
done

print_sep
posted @ 2026-08-20 08:12  wanghongwei-dev  阅读(3)  评论(0)    收藏  举报