feat: подпись сервера во всех уведомлениях и документация

Добавлены message_ensure_server_line и SERVER_DISPLAY_NAME; версия 1.1.3-server-label.
Гайды по уведомлениям и автообновлению.
This commit is contained in:
2026-05-25 09:23:32 +10:00
parent e2c0d5cbc7
commit b801cf2385
7 changed files with 321 additions and 31 deletions
+54 -27
View File
@@ -7,7 +7,7 @@ IFS=$'\n\t'
# ============================================
CONFIG_FILE="/etc/ssh-monitor.conf"
SSH_MONITOR_VERSION="1.1.2-ipset"
SSH_MONITOR_VERSION="1.1.3-server-label"
TELEGRAM_BOT_TOKEN=""
TELEGRAM_CHAT_ID=""
@@ -38,6 +38,8 @@ DAILY_REPORT_TOP_IPS=5
DAILY_REPORT_TZ=""
# IANA-зона для строк «🕐 Время» в Telegram/email. Пусто = тогда DAILY_REPORT_TZ, если она задана, иначе зона процесса (часто UTC у systemd — см. README).
NOTIFY_TZ=""
# Подпись сервера в уведомлениях: пусто = hostname (+ IPv4); иначе фиксированное имя (удобно при одинаковых hostname).
SERVER_DISPLAY_NAME=""
# Не слать повтор «Accepted» для той же пары user+IP чаще, чем раз в N секунд (разные port в журнале — один вход).
SSH_ACCEPT_NOTIFY_DEDUP_SEC=5
@@ -162,6 +164,7 @@ load_config() {
local cfg_daily_report_top_ips="${DAILY_REPORT_TOP_IPS}"
local cfg_daily_report_tz="${DAILY_REPORT_TZ}"
local cfg_notify_tz="${NOTIFY_TZ:-}"
local cfg_server_display_name="${SERVER_DISPLAY_NAME:-}"
local cfg_ssh_accept_notify_dedup_sec="${SSH_ACCEPT_NOTIFY_DEDUP_SEC:-5}"
local cfg_last_ssh_check_file="${LAST_SSH_CHECK_FILE}"
local cfg_last_sudo_check_file="${LAST_SUDO_CHECK_FILE}"
@@ -231,6 +234,7 @@ load_config() {
DAILY_REPORT_TOP_IPS="${DAILY_REPORT_TOP_IPS:-$cfg_daily_report_top_ips}"
DAILY_REPORT_TZ="$(trim_value "${DAILY_REPORT_TZ:-$cfg_daily_report_tz}")"
NOTIFY_TZ="$(trim_value "${NOTIFY_TZ:-$cfg_notify_tz}")"
SERVER_DISPLAY_NAME="$(trim_value "${SERVER_DISPLAY_NAME:-$cfg_server_display_name}")"
SSH_ACCEPT_NOTIFY_DEDUP_SEC="$(trim_value "${SSH_ACCEPT_NOTIFY_DEDUP_SEC:-$cfg_ssh_accept_notify_dedup_sec}")"
if ! [[ "${SSH_ACCEPT_NOTIFY_DEDUP_SEC:-5}" =~ ^[0-9]+$ ]]; then
SSH_ACCEPT_NOTIFY_DEDUP_SEC=5
@@ -477,6 +481,53 @@ write_log() {
echo "${timestamp} - ${message}"
}
# ============================================
# Подпись сервера в текстах уведомлений
# ============================================
# Для Telegram и отчётов: «hostname (IPv4)» или SERVER_DISPLAY_NAME (+ IPv4); без IPv4 — только имя.
server_display_name_with_ip() {
local hn ip
if [ -n "${SERVER_DISPLAY_NAME:-}" ]; then
hn="${SERVER_DISPLAY_NAME}"
else
hn=$(hostname 2>/dev/null | tr -d '\r\n')
[ -z "$hn" ] && hn="(unknown)"
fi
ip=""
if command -v ip >/dev/null 2>&1; then
ip=$(ip -4 route get 1.1.1.1 2>/dev/null | awk '/\bsrc\b/ {for (i = 1; i < NF; i++) if ($i == "src") { print $(i + 1); exit }}')
[ -z "$ip" ] && ip=$(ip -4 route get 8.8.8.8 2>/dev/null | awk '/\bsrc\b/ {for (i = 1; i < NF; i++) if ($i == "src") { print $(i + 1); exit }}')
fi
if [ -z "$ip" ] && command -v hostname >/dev/null 2>&1; then
if hostname -I >/dev/null 2>&1; then
ip=$(hostname -I 2>/dev/null | tr ' ' '\n' | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' | grep -Ev '^(127\.|0\.0\.0\.0)$' | head -n1)
fi
fi
if [ -n "$ip" ]; then
printf '%s (%s)' "$hn" "$ip"
else
printf '%s' "$hn"
fi
}
# Вставляет «🖥️ Сервер: …» сразу после первой строки (заголовка), если строки ещё нет.
message_ensure_server_line() {
local msg="$1"
if [[ "$msg" == *'🖥️ Сервер:'* ]]; then
printf '%s' "$msg"
return 0
fi
local first rest
first="${msg%%$'\n'*}"
if [ "$first" = "$msg" ]; then
printf '%s\n🖥️ Сервер: %s' "$first" "$(server_display_name_with_ip)"
else
rest="${msg#*$'\n'}"
printf '%s\n🖥️ Сервер: %s\n%s' "$first" "$(server_display_name_with_ip)" "$rest"
fi
}
# ============================================
# УВЕДОМЛЕНИЯ: telegram / email — по NOTIFY_CHAIN во все перечисленные каналы; BACKUP_WEBHOOK только если все неуспешны.
# ============================================
@@ -603,6 +654,7 @@ PY
notify_send() {
local message="$1"
message="$(message_ensure_server_line "$message")"
if [ "${DRY_RUN:-0}" = "1" ]; then
printf '[DRY-RUN notify] %s\n' "$(printf '%s' "$message" | tr '\n' ' ')" >&2
return 0
@@ -1501,28 +1553,6 @@ monitor_logind() {
echo "$current_time" >"$LAST_LOGIND_CHECK_FILE"
}
# Для Telegram и отчётов: «hostname (IPv4)»; без доступного IPv4 — только hostname.
server_display_name_with_ip() {
local hn ip
hn=$(hostname 2>/dev/null | tr -d '\r\n')
[ -z "$hn" ] && hn="(unknown)"
ip=""
if command -v ip >/dev/null 2>&1; then
ip=$(ip -4 route get 1.1.1.1 2>/dev/null | awk '/\bsrc\b/ {for (i = 1; i < NF; i++) if ($i == "src") { print $(i + 1); exit }}')
[ -z "$ip" ] && ip=$(ip -4 route get 8.8.8.8 2>/dev/null | awk '/\bsrc\b/ {for (i = 1; i < NF; i++) if ($i == "src") { print $(i + 1); exit }}')
fi
if [ -z "$ip" ] && command -v hostname >/dev/null 2>&1; then
if hostname -I >/dev/null 2>&1; then
ip=$(hostname -I 2>/dev/null | tr ' ' '\n' | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' | grep -Ev '^(127\.|0\.0\.0\.0)$' | head -n1)
fi
fi
if [ -n "$ip" ]; then
printf '%s (%s)' "$hn" "$ip"
else
printf '%s' "$hn"
fi
}
# ============================================
# Ежедневный отчёт
# ============================================
@@ -1606,7 +1636,6 @@ send_daily_report() {
fi
local message=" 📊 ЕЖЕДНЕВНЫЙ ОТЧЕТ SSH МОНИТОРИНГА "$'\n'
message="${message}🖥️ Сервер: $(server_display_name_with_ip)"$'\n'
message="${message}🕐 Время отчета: ${current_time}"$'\n'
message="${message}"$'\n'
message="${message} 📈 СТАТИСТИКА ЗА ПОСЛЕДНИЕ 24 ЧАСА: "$'\n'
@@ -1686,7 +1715,6 @@ send_heartbeat() {
timestamp_human=$(notification_date '+%d.%m.%Y %H:%M:%S')
local message=" ❤️ Heartbeat - скрипт мониторинга работает "$'\n'
message="${message}🖥️ Сервер: $(server_display_name_with_ip)"$'\n'
message="${message}🕐 Время: ${timestamp_human}"
notify_send "$message"
@@ -1745,7 +1773,6 @@ send_startup_notification() {
local message=" ✅ СКРИПТ МОНИТОРИНГА ЗАПУЩЕН "$'\n'
message="${message}📌 Версия: ${SSH_MONITOR_VERSION:-?}"$'\n'
message="${message}🖥️ Сервер: $(server_display_name_with_ip)"$'\n'
message="${message}🕐 Время запуска: ${timestamp}"$'\n'
message="${message}📊 Мониторинг SSH, SUDO и systemd-logind активирован"$'\n'
if [ "${ENABLE_IP_BAN:-1}" = "1" ]; then
@@ -1768,7 +1795,6 @@ send_shutdown_notification() {
local timestamp
timestamp=$(notification_date '+%d.%m.%Y %H:%M:%S')
local message=" ⚠️ СКРИПТ МОНИТОРИНГА ОСТАНОВЛЕН "$'\n'
message="${message}🖥️ Сервер: $(server_display_name_with_ip)"$'\n'
message="${message}🕐 Время остановки: ${timestamp}"
notify_send "$message"
@@ -1826,6 +1852,7 @@ run_check_config() {
printf 'DAILY_REPORT_HOUR=%s\n' "$DAILY_REPORT_HOUR"
printf 'DAILY_REPORT_TZ=%s (пусто = зона процесса/date)\n' "${DAILY_REPORT_TZ:-}"
printf 'NOTIFY_TZ=%s (пусто = DAILY_REPORT_TZ или зона процесса; см. README)\n' "${NOTIFY_TZ:-}"
printf 'SERVER_DISPLAY_NAME=%s (пусто = hostname; эффективно: %s)\n' "${SERVER_DISPLAY_NAME:-}" "$(server_display_name_with_ip)"
printf 'SSH_ACCEPT_NOTIFY_DEDUP_SEC=%s\n' "${SSH_ACCEPT_NOTIFY_DEDUP_SEC:-5}"
printf 'DAILY_REPORT_TOP_IPS=%s\n' "$DAILY_REPORT_TOP_IPS"
printf 'BRUTE_WINDOW_SEC=%s BRUTE_MIN_FAILS=%s\n' "$BRUTE_WINDOW_SEC" "$BRUTE_MIN_FAILS"