Мне довольно часто достают какие то боты непонятной природы, которые как саранча быстро наваливаются на сервер, качают все что можно в сотни потоков и так же быстро исчезают.

Решил написать простенькую банилку. Обращаю внимание, банилка простенькая, в качестве БД используется MySQL – не рекомендуется как защита от DDoS атак. Возможно позже переведу ее на Berkeley DB.

Платформа: Nginx + ipfw + MySQL + свой скрипт. Впрочем, подойдет любой другой веб сервер, который умеет выборочно писать логи, например, apache+mod_setenv_if

Nginx:

Нам нужно заставить вебсервер писать логи обращений к скриптам. Именно к скриптам, т.к. учитывать обращение к медиа файлам лучше не стоит ) В nginx это делается просто.

nginx.conf:

location ~* \.php$ {
log_format IP ‘[$time_local] $remote_addr’;
access_log /home/logs/nginx.ip.log IP;
….. # далее директивы proxy_pass
}

Таким образом в файл /home/logs/nginx.ip.log будут писаться айпишники и время доступа к скриптам. Осталось этот файл периодически анализировать.

Скрипт анализа я написал на пхп )) : nginx.ip.ban.php (требуемые расширения: Posix, MySQL). Запускается из командной строки, если ему дать права на запуск. Скрипт был написан под FreeBSD, на других системах … а на других системах нет ipfw :)

Настраиваемые переменные в скрипте:

$dir - путь к лог файлу
$logfile – вышеупомянутый лог файл
$email_to – высылать уведомление о бане айпи на емейл
$email_from – от кого слать письмо
$ipwhitelist – массив регекспов для айпи, которые будут игнорироваться (белый список)
$check_interval,$max_conn_per_interval,$ban_time – Если за $check_interval минут с одного айпи было $max_conn_per_interval коннектов, то забанить этот айпи на $ban_time секунд.
$keep_history – сколько дней хранить историю коннектов в мускуле
$mypidfile – файл с PID’ом процесса nginx.ip.ban.php
$pidfile – расположение PID файла nginx (чтобы корректно сбрасывать логи)
$db_host,$db_user,$db_pass,$db_name – параметры подключения к базе

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

# ipfw add 10 deny ip from table \(1\) to me

Так же позаботиться чтобы это правило не исчезало после ребута, прописав его в /etc/rc.local например.

MySQL:

Структура таблиц:

CREATE TABLE `stat` (
`ts` datetime NOT NULL,
`ip` int(11) NOT NULL,
KEY `idx` (`ts`,`ip`),
KEY `idx2` (`ip`,`ts`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;

CREATE TABLE `ban` (
`ip` int(11) NOT NULL,
`ts` int(10) unsigned NOT NULL,
KEY `ip` (`ip`),
KEY `ts` (`ts`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci

В принципе все. Можно проверять работу скрипта, отстреливать баги ) В конце концов скрипт должен быть прописан в кроне от рута на выполнение каждую минуту:

/etc/crontab:

* * * * * root /root/scripts/nginx.ip.ban.php > /dev/null

Скрипт относительно умный и проверяет, не запущен ли процесс-клон. По этому беспокоиться за его размножение в памяти не стоит. Таблицы он чистит автоматически, логи тоже чистит. Следов за собой не оставляет.

Вся эта штука работает на 1 млн хитов в сутки и прекрасно себя чувствует, не позволяя китайцам взять мои сервера измором )