3 min read

FreeBSD 15 + blocklistd — это «тихая революция» в безопасности (и прощай, Fail2Ban)

Если вы когда-нибудь настраивали защиту SSH на Linux, то наверняка помните этот громоздкий танец с Fail2Ban: установка Python-зависимостей, написание километровых регулярок (regex), чтение логов и бесконечные жалобы на то, что парсер «отъедает» CPU.

С выходом FreeBSD 15 и развитием blocklistd, мир системного администрирования разделился на «до» и «после». Давайте разберем, почему эта связка — лучшее, что случалось с сетевой безопасностью за последние годы.


Проблема «Кувалды» (Fail2Ban/SSHGuard)

Классические утилиты работают по принципу постфактум:

  1. Злоумышленник ломится в SSH.
  2. sshd пишет ошибку в текстовый файл /var/log/auth.log.
  3. Сторонний демон (Fail2Ban) раз в N секунд просыпается, читает файл, парсит его регулярками.
  4. Если совпало — дергает команду iptables для бана.

Это медленно, ресурсозатратно и... честно говоря, костыльно.


Элегантность BlockListD: Хирургический скальпель

Blocklistd (впервые появившийся в NetBSD и доведенный до идеала во FreeBSD) работает иначе. Это не «читалка логов», это сервис-адресат.

1. Прямая связь (Zero Latency)

Вместо чтения логов, сервисы (например, тот же sshd) скомпилированы с поддержкой libblocklist. Как только происходит неудачная попытка входа, демон напрямую сообщает об этом blocklistd через сокет.

  • Результат: Бан происходит мгновенно. Никакого парсинга. Нулевая нагрузка на диск.

2. Часть экосистемы, а не «аддон»

Во FreeBSD 15 это штатный инструмент. Вам не нужно скачивать пакеты и бояться, что обновление Python сломает вашу защиту. Всё «из коробки» подогнано друг к другу с точностью швейцарских часов.

3. Интеграция с PF (Packet Filter)

Связка с файерволом PF выглядит как магия. Вам не нужно плодить сотни правил. blocklistd просто подкидывает IP в одну таблицу PF, и пакеты от злоумышленника дропаются на уровне ядра.


Как это выглядит на практике (FreeBSD 15)

Настройка занимает ровно 3 шага.

Шаг 1. Конфиг /etc/blocklistd.conf

Чистота и порядок. Никаких регулярок:

Plaintext

# Адрес   Тип     Протокол  Владелец  Попытки  Время_бана
[local]
ssh       stream  tcp       * 3        24h

Шаг 2. Добавляем якорь в /etc/pf.conf

PF

table <port_blockers> persist
block in quick on em0 from <port_blockers> to any

Шаг 3. Включаем и забываем

Bash

sysrc blocklistd_enable="YES"
service blocklistd start

Почему FreeBSD 15 — это круче любого дистрибутива Linux?

Перейдя на FreeBSD 15, ты понимаешь разницу между «сборкой» и «системой»:

  • Стабильность API: Ваш конфиг blocklistd будет работать и через 5, и через 10 лет.
  • ZFS в базе: Перед любыми экспериментами с защитой делаем bectl create safety_net — и у нас есть точка отката всей ОС за 0.1 секунды.
  • Документация: Каждая опция описана в man blocklistd.conf. Вам не нужно гуглить устаревшие треды на StackOverflow.

Вердикт

Если вам надоело, что ваш сервер тратит ресурсы на чтение собственных логов, чтобы просто забанить китайского бота — переходите на FreeBSD 15.

Blocklistd — это символ того, как должна работать современная безопасность: тихо, эффективно и незаметно для системы. Пока Linux-админы обновляют Docker-контейнеры с Fail2Ban, мы просто наслаждаемся тишиной в логах.


#!/bin/sh

SENT_LOG="/var/log/blocklist_sent.log"
touch "$SENT_LOG"

# Пути к утилитам
BLOCKLISTCTL="/usr/sbin/blocklistctl"
WHOIS="/usr/bin/whois"

# Обрабатываем вывод, пропуская заголовок
$BLOCKLISTCTL dump -b | grep "/" | while read -r line; do
    
    # Извлекаем IP (второе поле, отсекаем всё после '/')
    addr_field=$(echo "$line" | awk '{print $2}')
    ip=$(echo "$addr_field" | cut -d'/' -f1)
    
    [ -z "$ip" ] && continue
    
    # Проверяем, не отправляли ли уже (чтобы не спамить по крону)
    if grep -q "^$ip$" "$SENT_LOG"; then
        continue
    fi

    # Ищем e-mail владельца (abuse)
    ABUSE_MAIL=$($WHOIS "$ip" 2>/dev/null | grep -Ei "abuse-mailbox|abuse-email|e-mail|address" | grep -oE "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}" | head -n 1)

    # Если почта владельца найдена — шлем отчет
    if [ ! -z "$ABUSE_MAIL" ]; then
        echo "Sending report for $ip to $ABUSE_MAIL..."
        
        MESSAGE="Hello,
The IP address $ip was blocked on $(hostname) due to SSH brute-force attempts.
Time of last incident: $(date)

Please take appropriate measures.
This is an automated report."

        echo "$MESSAGE" | mail -s "Abuse report: $ip" "$ABUSE_MAIL"
        
        # Записываем в лог ТОЛЬКО если попытка отправки была
        echo "$ip" >> "$SENT_LOG"
    else
        echo "No abuse email found for $ip, skipping..."
    fi

    sleep 1 # Пауза для whois
done
sh -x /usr/local/bin/blocklist-cron.sh