В наше время возникла необходимость создать программируемый и настраиваемый роутер, который обеспечивал бы доступ в Интернет домашней сети без геополитических ограничений. Поискав среди старых вещей, обнаружил материнскую плату двадцатилетней давности с твердотельными конденсаторами на борту, которая, издав тихий писк, успешно стартовала. Подробности технических характеристик ПК здесь не важны, поскольку передача пакетов процесс не требовательный к мощности "железа". Докупив дополнительную сетевую карту Wi-Fi стандарта 5G и установив Ubuntu 20.04, настроил устройство согласно руководству на данном сайте, дополнительно подключив и настроил поддержку протоколов IKEv2 и SSTP. Всё работало прекрасно вплоть до неожиданного происшествия — произвольного перезагрузки устройства. Изучив лог-файлы системы после инцидента, обнаружил сообщение ядра Linux о подозрительной активности типа TCP flood.

Кратко разберемся с теорией. В протоколе TCP соединение устанавливается следующим образом: клиент отправляет серверу пакет SYN, ожидая подтверждения от сервера. Однако злоумышленники часто злоупотребляют этим механизмом, отправляя огромное количество таких запросов, заставляя систему расходовать вычислительные ресурсы на обработку несуществующих попыток подключения. Стандартно операционная система не ведет учет соединений.

Изучив проблему подробнее, нашёл подходящий инструмент — модуль hashlimit в фаерволе iptables, поставляемый вместе с операционной системой. Этот модуль позволяет отслеживать частоту новых соединений и сообщать о превышениях лимитов в системный лог. До этого момента я уже использовал утилиту Fail2Ban, которая эффективно блокировала атаки на порт SSH (22). Решил расширить её возможности и применить к защите от SYN-flooding атак. Давайте перейдем от теории к практике.

  • Создаем новое правило, которое размещается первым в очереди обработки входящих пакетов:

iptables -I INPUT 1 -i интерфейс -p tcp --syn -m hashlimit --hashlimit 200/sec --hashlimit-burst 100 --hashlimit-mode srcip --hashlimit-name synflood -j LOG --log-prefix "[SYNFLOOD] "

Здесь мы задаем фильтрацию по определенному интерфейсу для протокола TCP, отслеживая запросы на установление связи (--syn). Если частота превышает порог 200 запросов/секунду, запись фиксируется в журнале системы с отметкой [SYNFLOOD]. Фильтрация ведется по источнику (ключ srcip), что позволяет ограничить объем атакующего трафика от конкретного узла.

  • Fail2Ban получает события из журнала и применяет заданные правила блокировки, автоматически создавая цепочку в таблице фильтрации iptables. Далее настраиваем фильтр для Fail2Ban, создадим файл /etc/fail2ban/filter.d/synflood.conf следующего содержания:

[Definition]
failregex = $$SYNFLOOD$$.*SRC=.*PROTO=TCP.*SYN
ignoreregex =

Затем добавляем секцию в конфигурационный файл /etc/fail2ban/jail.local:

[synflood]
enabled = true
filter = synflood
action = iptables-allports[name=synflood, protocol=tcp]
backend = systemd
maxretry = N # Количество превышений порога за указанный период findtime (целое число)
findtime = 5m
bantime = 1d

Таким образом, Fail2Ban автоматически блокирует узлы, превысившие установленный предел запросов на подключение и разблокирует через время bantime. Перезапускаем службу systemctl restart Fail2Ban.service и проверяем статус systemctl status Fail2Ban.service. Для мониторинга и точной настройки смотрим вывод команды iptables -L -n. После внесения изменений в правила, для удобства управления, создал простой bash-скрипт, позволяющий снять блокировки со всех узлов одновременно, :

#!/bin/bash

jails=$(sudo fail2ban-client status | grep 'Jail list' | cut -d':' -f2 | tr -d ' ' | tr ',' ' ')

for jail in $jails; do
  echo "Обрабатываю jail: $jail"
  banned_ips=$(sudo fail2ban-client status $jail | grep 'Banned IP list' | cut -d':' -f2)
  for ip in $banned_ips; do
    if [[ $ip != "" ]]; then
      echo "Разбаниваю IP $ip из $jail"
      sudo fail2ban-client set $jail unbanip $ip
    fi
  done
done

echo "Все заблокированные IP были освобождены."

Система работает стабильно уже около трех месяцев, периодически проверяю список забаненных адресов — случайных пользователей среди них не наблюдалось. Надеюсь, мой опыт окажется полезным!

Всем успехов!

Комментарии (2)


  1. pae174
    02.09.2025 10:41

    Для этго существует механизм SYN cookies. Блокировать источник флуда по IP на уровне фаерволла это так себе идея по двум причинам:

    • IP адреса источника можно подделать на стороне отправителя. Если вы баните по IP источника SYN сегмента то у скрипткидди появляется отличная возможность, ну например, сделать ваш сервер недоступным для поисковиков или даже для вас самих.

    • При бокировке по IP на уровне фаерволла все же тратится память на хранение таблицы забаненных IP и тратится время на проверку по этой таблице. Еще fail2ban этот живет отдельным процессом, логи писать/читать - затратно это все. SYN cookies не тратит память, но тратит время на генерацию кукиса, но это не много.


    1. xaht88 Автор
      02.09.2025 10:41

      В /etc/sysctl.conf были включены SYN cookies. Это просто одно из решений, мне такой путь показался интересней, с логам и гибче. Правило айпитэбла можно вырубить, а можно перезаписать с DROP.