Страница 1 из 1

Dovecot Postfix SASL Report Auth attempts

Добавлено: 05 сен 2026, 16:57
Padonak
скрипт, который анализирует логи Dovecot, Postfix и выводит статистику неудачных попыток входа за последний день и отправляет отчёт на почту.

установка:

Код: Выделить всё

 vim /usr/local/bin/dovecot_failed_auth.sh

Код: Выделить всё


#!/bin/bash

# ============================================================
# Скрипт для анализа неудачных попыток входа с геолокацией
# ============================================================

# === UTF-8 ===
export LANG=ru_RU.UTF-8
export LC_ALL=ru_RU.UTF-8
export LANGUAGE=ru_RU.UTF-8

# === НАСТРОЙКИ ===
EMAIL_TO="admin@padonak.su"
HOSTNAME=$(hostname -f)

# Пути к логам
DOVECOT_LOG="/var/log/dovecot/dovecot_info.log"
POSTFIX_LOG="/var/log/mail.log"

REPORT_FILE=$(mktemp)
TEMP_GEOCACHE="/tmp/geo_cache_$$.txt"

# === ФУНКЦИЯ ДЛЯ ПОЛУЧЕНИЯ ГЕОЛОКАЦИИ ===
get_geo() {
    local ip=$1
    
    if [ -f "$TEMP_GEOCACHE" ]; then
        local cached=$(grep "^$ip|" "$TEMP_GEOCACHE" 2>/dev/null | cut -d'|' -f2-)
        if [ -n "$cached" ]; then
            echo "$cached"
            return
        fi
    fi
    
    if [[ "$ip" == 127.0.0.1 || "$ip" == ::1 || "$ip" == 192.168.* || "$ip" == 10.* || "$ip" == 172.16.* || "$ip" == 93.95.101.238 ]]; then
        echo "Локальный"
        echo "$ip|Локальный" >> "$TEMP_GEOCACHE"
        return
    fi
    
    local geo=$(curl -s --connect-timeout 3 --max-time 5 "http://ip-api.com/line/$ip?fields=country,city" 2>/dev/null)
    
    if [ -n "$geo" ]; then
        local country=$(echo "$geo" | sed -n '1p' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
        local city=$(echo "$geo" | sed -n '2p' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
        
        if [ -n "$country" ] && [ "$country" != "fail" ] && [ "$country" != "private" ]; then
            local result="${country:-Неизв}"
            [ -n "$city" ] && [ "$city" != "fail" ] && result="$result, $city"
            echo "$result"
            echo "$ip|$result" >> "$TEMP_GEOCACHE"
            return
        fi
    fi
    
    echo "Неизвестно"
    echo "$ip|Неизвестно" >> "$TEMP_GEOCACHE"
}

# === ФУНКЦИЯ ДЛЯ ФОРМАТИРОВАНИЯ ДАТЫ ===
format_date() {
    date '+%Y-%m-%d %H:%M:%S'
}

# === ФУНКЦИЯ ОТПРАВКИ ПИСЬМА ===
send_report() {
    mail -s "[Dovecot/Postfix] Отчёт о неудачных входах на $HOSTNAME" "$EMAIL_TO" < "$REPORT_FILE"
}

# === ГЛАВНАЯ ЛОГИКА ===
{
    echo "============================================================"
    echo "  📊 ОТЧЁТ ПО НЕУДАЧНЫМ ПОПЫТКАМ ВХОДА"
    echo "  Сервер: $HOSTNAME"
    echo "  Дата: $(format_date)"
    echo "============================================================"
    echo ""

    # ============================================================
    # 1. НЕУДАЧНЫЕ ПОПЫТКИ IMAP (Dovecot) С ГЕОЛОКАЦИЕЙ
    # ============================================================
    echo "📧 1. НЕУДАЧНЫЕ ПОПЫТКИ IMAP (Dovecot) — за 24 часа"
    echo "------------------------------------------------------------------------------------------"
    printf "  %-30s %-18s %-35s %5s\n" "ПОЛЬЗОВАТЕЛЬ" "IP АДРЕС" "ГЕОЛОКАЦИЯ" "ПОПЫТКИ"
    echo "------------------------------------------------------------------------------------------"

    if [ -f "$DOVECOT_LOG" ]; then
        # Парсим логи Dovecot - формат: user=<test@padonak.su>, ... rip=127.0.0.1
        grep -E "auth failed.*auth_failed" "$DOVECOT_LOG" 2>/dev/null | \
        grep -v "user=<>" | \
        awk -F'user=<|>.*rip=' '
        {
            if (NF >= 3) {
                user = $2
                ip = $3
                # Обрезаем ip до первого пробела или запятой
                split(ip, arr, "[ ,]")
                if (arr[1] != "") {
                    print user "|" arr[1]
                }
            }
        }' | \
        sort | uniq -c | sort -rn | head -20 | \
        while read count user_ip; do
            username=$(echo "$user_ip" | cut -d'|' -f1)
            ip=$(echo "$user_ip" | cut -d'|' -f2)
            if [ -n "$ip" ] && [ -n "$username" ] && [ "$ip" != " " ] && [ "$ip" != "" ]; then
                geo=$(get_geo "$ip")
                printf "  %-30s %-18s %-35s %5d\n" "$username" "$ip" "$geo" "$count"
            fi
        done
    else
        echo "  ⚠️ Лог-файл не найден: $DOVECOT_LOG"
    fi

    echo "------------------------------------------------------------------------------------------"
    echo ""

    # ============================================================
    # 2. НЕУДАЧНЫЕ ПОПЫТКИ SASL (Postfix) С ГЕОЛОКАЦИЕЙ
    # ============================================================
    echo "📨 2. НЕУДАЧНЫЕ ПОПЫТКИ SASL (Postfix SMTP) — за 24 часа"
    echo "------------------------------------------------------------------------------------------"
    printf "  %-30s %-18s %-35s %5s\n" "ПОЛЬЗОВАТЕЛЬ" "IP АДРЕС" "ГЕОЛОКАЦИЯ" "ПОПЫТКИ"
    echo "------------------------------------------------------------------------------------------"

    if [ -f "$POSTFIX_LOG" ]; then
        # Парсим логи Postfix - формат: unknown[37.208.46.130]: ... sasl_username=pfcnfdf@npomis.ru
        grep "SASL PLAIN authentication failed" "$POSTFIX_LOG" 2>/dev/null | \
        sed -n 's/.*unknown\[\([0-9.]*\)\].*sasl_username=\([^,]*\).*/\2|\1/p' | \
        sort | uniq -c | sort -rn | head -20 | \
        while read count user_ip; do
            username=$(echo "$user_ip" | cut -d'|' -f1)
            ip=$(echo "$user_ip" | cut -d'|' -f2)
            if [ -n "$ip" ] && [ -n "$username" ]; then
                geo=$(get_geo "$ip")
                printf "  %-30s %-18s %-35s %5d\n" "$username" "$ip" "$geo" "$count"
            fi
        done
    else
        echo "  ⚠️ Лог-файл не найден: $POSTFIX_LOG"
    fi

    echo "------------------------------------------------------------------------------------------"
    echo ""

    # ============================================================
    # 3. ГЕОЛОКАЦИЯ АТАКУЮЩИХ IP (топ-10)
    # ============================================================
    echo "🌍 3. ГЕОЛОКАЦИЯ АТАКУЮЩИХ IP (топ-10)"
    echo "------------------------------------------------------------"
    printf "  %-18s %-35s %8s\n" "IP АДРЕС" "ГЕОЛОКАЦИЯ" "ПОПЫТКИ"
    echo "------------------------------------------------------------"

    if [ -f "$POSTFIX_LOG" ]; then
        grep "SASL PLAIN authentication failed" "$POSTFIX_LOG" 2>/dev/null | \
        grep -oE '\[[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\]' | \
        tr -d '[]' | \
        sort | uniq -c | sort -rn | head -10 | \
        while read count ip; do
            geo=$(get_geo "$ip")
            printf "  %-18s %-35s %8d\n" "$ip" "$geo" "$count"
        done
    fi

    echo "------------------------------------------------------------"
    echo ""

    # ============================================================
    # 4. ОБЩАЯ СТАТИСТИКА
    # ============================================================
    echo "📊 4. ОБЩАЯ СТАТИСТИКА"
    echo "------------------------------------------------------------"

    IMAP_TOTAL=0
    SASL_TOTAL=0
    UNIQ_IMAP_USERS=0
    UNIQ_SASL_USERS=0

    if [ -f "$DOVECOT_LOG" ]; then
        IMAP_TOTAL=$(grep -E "auth failed.*auth_failed" "$DOVECOT_LOG" 2>/dev/null | grep -v "user=<>" | wc -l)
        UNIQ_IMAP_USERS=$(grep -E "auth failed.*auth_failed" "$DOVECOT_LOG" 2>/dev/null | grep -v "user=<>" | sed -n 's/.*user=<\([^>]*\)>.*/\1/p' | sort -u | wc -l)
    fi

    if [ -f "$POSTFIX_LOG" ]; then
        SASL_TOTAL=$(grep "SASL PLAIN authentication failed" "$POSTFIX_LOG" 2>/dev/null | wc -l)
        UNIQ_SASL_USERS=$(grep "SASL PLAIN authentication failed" "$POSTFIX_LOG" 2>/dev/null | sed -n 's/.*sasl_username=\([^,]*\).*/\1/p' | sort -u | wc -l)
    fi

    echo "  📧 IMAP: $IMAP_TOTAL попыток, $UNIQ_IMAP_USERS уникальных пользователей"
    echo "  📨 SASL: $SASL_TOTAL попыток, $UNIQ_SASL_USERS уникальных пользователей"
    
    TOTAL_ATTEMPTS=$((IMAP_TOTAL + SASL_TOTAL))
    echo "  📊 Всего попыток: $TOTAL_ATTEMPTS"
    echo "------------------------------------------------------------"
    echo ""

    # ============================================================
    # 5. СОВЕТЫ ПО БЕЗОПАСНОСТИ
    # ============================================================
    echo "🛡️ 5. РЕКОМЕНДАЦИИ ПО БЕЗОПАСНОСТИ"
    echo "------------------------------------------------------------"
    
    if [ $SASL_TOTAL -gt 100 ]; then
        echo "  ⚠️ Обнаружено более 100 неудачных попыток SASL!"
        echo "  Рекомендации:"
        echo "    • Включите fail2ban для Postfix"
        echo "    • Ограничьте количество соединений с одного IP"
        echo "    • Используйте сложные пароли"
    elif [ $SASL_TOTAL -gt 50 ]; then
        echo "  ⚠️ Обнаружено более 50 неудачных попыток SASL."
        echo "  Рекомендуется проверить настройки безопасности."
    else
        echo "  ✅ Уровень атак в пределах нормы."
    fi
    
    echo "------------------------------------------------------------"
    echo ""

    echo "============================================================"
    echo "Отчёт сгенерирован: $(format_date)"
    echo "============================================================"

} > "$REPORT_FILE"

# === ОТПРАВЛЯЕМ ПИСЬМО ===
send_report

# === ЧИСТИМ ВРЕМЕННЫЕ ФАЙЛЫ ===
rm -f "$REPORT_FILE" "$TEMP_GEOCACHE" 2>/dev/null

echo "✅ Отчёт отправлен на $EMAIL_TO в $(format_date)"

Код: Выделить всё

chmod +x /usr/local/bin/dovecot_failed_auth.sh
добавление в cron

Код: Выделить всё

sudo crontab -e

Код: Выделить всё

0 8 * * * /usr/local/bin/dovecot_failed_auth.sh
часть из письма :

Код: Выделить всё

 3. ГЕОЛОКАЦИЯ АТАКУЮЩИХ IP (топ-10)
------------------------------------------------------------
  IP ADDRESS          COUNTRY/CITY               ATTEMPTS
------------------------------------------------------------
  210.0.90.82        Australia, Forest Lodge      10
  222.117.0.253      South Korea, Anyang-si        8
  210.0.90.81        Australia, Forest Lodge       6
  111.0.81.84        China, Hangzhou               5
  45.178.227.0       Brazil, Paquetá              4
  131.0.190.152      Brazil, Santa Luzia           4
  49.0.82.4          Thailand, Bangkok             3
  31.173.0.140       Russia, Moscow                3
  201.46.124.0       Colombia, Bogotá             3
  180.111.0.21       China, Nanjing                3
------------------------------------------------------------

📊 4. ОБЩАЯ СТАТИСТИКА
------------------------------------------------------------
  📧 IMAP: 5 попыток, 3 уникальных пользователей
  📨 SASL: 1161 попыток, 116 уникальных пользователей
------------------------------------------------------------

============================================================
Отчёт сгенерирован: 2026-09-05 16:56:09
============================================================