На серверах, которые я обслуживаю часто и остро всплывает проблема с син-флуд атаками разной мощности. Не имея аппаратной защиты от DDOS приходится изощряться с IPTables.
Ранее, когда системы мониторинга оповещали о возросшей нагрузке целый ряд действий диагностически-карательного характера приходилось делать вручную. Перечислю ниже:
- Для проверки количества SynRequest использовал команду netstat -n -p|grep SYN_REC | wc -l — тут, как мне кажется, расшифровывать ничего не нужно.
- Для получения списка IP-адресов, с которых идут эти запроы использовал netstat -n -p | grep SYN_REC | sort -u | awk {‘print $5’} | cut -d : -f1 — тут уже чуть сложнее, с помощью awk получаем 5й аргумент — IP-адрес, с которого идут запросы, отсеивая протокол, IP самого сервера и прочий мусор.
- И слишком грубый метод, от которого пришлось отказаться — etstat -n -p | grep SYN_REC | sort -u | awk {‘print $5’} | cut -d : -f1 | xargs -t -l iptables -A INPUT -p tcp -j DROP -s предыдущая команда, с передачей IP-адресов в IPTables с их последующей блокировкой.
- Следующим шагом стало улучшение команды блокировки, команда получилась уж больно объемной, зато более правильно построенной в плане логики борьбы с синфлудом — netstat -n -p | grep SYN_REC | sort -u | awk {‘print $5’} | cut -d : -f1 |uniq -cd |sort -nr| head -n 3|awk {‘print $2’}| xargs -t -l iptables -A INPUT -p tcp -j DROP -s -тут чуть подробней: с помощью uniq -cd отсортированы только повторы (-d) и указано их количество(-c), с помощью sort -nr сортируем их по кол-ву в убывающем порядке, с помощью head -n 3 получаем только трёх “лидеров”, а с помощью awk {‘print $2’} удаляем кол-во коннектов из списка “лидеров”, получая только второй аргумент — собственно сам IP-адрес. А далее это все вновь передается в IPTables.
- И, чтобы понять, как часто срабатывает защита, какие IP-адреса попали под блокировку, и, чтоб после проверить по логам на какой сайт велась атака, чуть-чуть видоизменяем последнюю строку и добавляем еще одно echo с записью в файл: exec («date >> synstat.txt»);
exec («netstat -n -p | grep SYN_REC | sort -u | awk {‘print $5’} | cut -d : -f1 |uniq -cd |sort -nr| head -n 5|awk {‘print $2’}| xargs -t -l echo >> synstat.txt»);
Оставалось это автоматизировать. Так как количество Syn-запросов практически всегда больше нуля нужно было определить порог, при котором настает время запускать карающий инструмент, иначе IPTables оказался бы забит тысячами адресов уже за пару часов работы. Потому порогом, при котором срабатывает скрипт было выбрано число в 100 одновременных syn rec.
Оговорюсь сразу — я люблю большие и сложные построения команд в shell и считаю их гораздо более практичными, чем использование десятков библиотек и модулей в других языках программирования, но я не люблю писать на чистом Bash. Потому мною был порожден гибрид shell с php, который не претендует на красоту, лаконичность, образцовый код и т.д., но который делает свою работу верно и быстро, чем меня полностью устраивает.
<?php
function killemall() {
exec («netstat -n -p | grep SYN_REC | sort -u | awk {‘print $5’} | cut -d : -f1 |uniq -cd |sort -nr| head -n 3|awk {‘print $2’}| xargs -t -l iptables -A INPUT -p tcp -j DROP -s»);
exec («date >> synstat.txt»);
exec («netstat -n -p | grep SYN_REC | sort -u | awk {‘print $5’} | cut -d : -f1 |uniq -cd |sort -nr| head -n 5|awk {‘print $2’}| xargs -t -l echo >> synstat.txt»);
}
$syncount = exec (‘netstat -n -p|grep SYN_REC | wc -l’);
if ($syncount > 100) {
killemall ();
}
Далее сие чудо было добавлено в крон на выполнение каждую минуту способом, который не попадал под проверку моим прошлым мини-скриптом — выполнение каждую минуту было задано не символом *, а интервалом 0-59.