|
|
www.lissyara.su
—> статьи
—> FreeBSD
—> почтовые системы
—> Защита от DDoS
Попытка защитить свой почтовый сервер от DDoS атаки.
Автор: buryanov.
Друг попросил о помощи, его почтовик подвергся ddos атаке. У меня были написаны скрипты, но у меня не настолько большая нагрузка, чтобы можно было их потестить по нормальному, да и времени тоже не было. Навеяло на их написание, точнее дописание обсуждение Защита exim от DDoS. А тут как раз и повод появился.
В моём случае почтовый сервер и почтовый релей - это два разных сервера, но, если это один и тот же сервер - то всё работает также прекрасно, что и было доказано.
Топология:
- пограничный маршрутизатор: FreeBSD 7.2/i386, Atom c 1 сетевой картой, зато с кучей vlan
- почтовик, он же и прокся, он же и MySQL сервер: FreeBSD 7.2/amd64, Core2Duo E8500, 8G Ram
Теперь по порядку:
8 - 10 тысяч одновременных конектов к exim, при условии, что в офисе работает 50 человек. Это уже слишком. Попахивает DDos'ом.
Ддосили smtp, imap не юзается, точнее юзается imaps, а его, почему-то, не ддосят.
Перед какими либо действиями обновляем порты, я это делаю с помощью cvsup.
[root@mx ]# cd /usr/ports/net/cvsup-without-gui
[root@mx ]# make install clean
| Создаём к ниму конфиг-файл /usr/local/etc/cvsup/ports-sup
*default host=cvsup3.uk.freebsd.org
*default base=/var/db
*default prefix=/usr
*default release=cvs tag=.
*default delete use-rel-suffix
*default compress
ports-all
| После чего командой
cvsup -g -L 2 /usr/local/etc/cvsup/ports-sup
| обновляем порты.
Ставим Mysql:
[root@mx /usr/ports]# cd /usr/ports/databases/mysql51-server/
[root@mx ]# make install clean
[root@mx ]# echo 'mysql_enable="YES"' >> /etc/rc.conf
| В конфиге указывываем побольше количество коннектов, параметр max_connections=1000 в секции [mysqld]. В моём случае это было 10000. По умолчанию файл конфигурации my.cnf будет находится в каталоге с самой базой /var/db/mysql, но пока мы не инициализируем mysql, там ничего не будет. Это можно сделать несколькими способами, один из них, запустить mysql, он сам всё сделает, затем отредактировать конфигурационный файл и перезапустить mysql. Запуск осуществляется командой
[root@mx /var/db]# /usr/local/etc/rc.d/mysql-server start
| Более детально установка MySQL описана в статье Установка MySQL Автор Lissyara.
Ставим exim:
[root@mx /var/db]# cd /usr/ports/mail/exim
[root@mx /usr/ports/mail/exim]# make install clean
[root@mx ]# echo 'exim_enable="YES"' >> /etc/rc.conf
| На этом сайте приведено множество примеров конфигурирования exim под разные цели: exim & dovecot, exim + exchange автор Lissyara, мои конфиги базируются на этих статьях, поэтому повторяться не буду, напишу только свои дополнения:
В файле конфигурации /usr/local/etc/exim/configure, если ваш файл разбит на несколько файлов, то в соответвтвующих файлах, параметр
# Максимальное число одновременных подключений по
# SMTP. Рассчитывать надо исходя из нагрузки на сервер
smtp_accept_max = 50
| необходимо сделать побольше, иначе ваш exim буквально сразу захлебнётся. Перед begin acl создаём макрос:
MYSQL_IPFW = INSERT INTO `ipfw` \
(`ip`, `date`, `type`, `coun`,`email`) VALUES \
('$sender_host_address', now(), '$acl_m18', '1', '$sender_address')
| Далее в разделе acl, создаём переменные:
warn set acl_m18 = 0
warn set acl_m19 = 0
| и добавляем в секции проверок, в которых идут следующие запреты:
set acl_m18 = HELO1
set acl_m19 = ${lookup mysql{MYSQL_IPFW}}
| В разделе на проверки на EHLO/HELO, для каждой проверки можно присваивать свои значения $acl_m18, HELO1,HELO2,HELO10, чтобы потом отслеживать , где попался
set acl_m18 = DNSRBL
set acl_m19 = ${lookup mysql{MYSQL_IPFW}}
| вносим, на проверке на RBL
set acl_m18 = UnUser
set acl_m19 = ${lookup mysql{MYSQL_IPFW}}
| вносим, за попытку отправить почту несуществующим пользователям.
Создаём таблицы в MySQL, у меня exim использует базу exim_db, если у вас другая, то необходимо исправить на свою:
-- Создаём таблицу для занесения статистики
CREATE TABLE ipfw(
ip CHAR (15) NOT NULL,
`date` CHAR (19) NOT NULL,
type CHAR (9) NOT NULL,
coun INT (8) NOT NULL,
email VARCHAR (64) DEFAULT NULL,
INDEX `date` USING BTREE (`date` (13)),
INDEX ip USING BTREE (ip),
INDEX type USING BTREE (type)
)
ENGINE = MYISAM
CHARACTER SET latin1
COLLATE latin1_swedish_ci;
-- Создаём таблицы для анализа и занесения результатов
CREATE TABLE ddos_analis(
ip CHAR (15),
type CHAR (9) DEFAULT NULL,
date_in CHAR (19) DEFAULT NULL,
date_last CHAR (19) DEFAULT NULL,
date_exp CHAR (19) DEFAULT NULL,
coun INT (8) UNSIGNED DEFAULT NULL,
PRIMARY KEY (ip),
UNIQUE INDEX ip_type USING BTREE (ip, type)
)
ENGINE = MEMORY
CHARACTER SET koi8r
COLLATE koi8r_general_ci;
CREATE TABLE ddos_exp(
ip CHAR (15) NOT NULL,
date_delete CHAR (19) DEFAULT NULL,
active CHAR (1) DEFAULT '0',
UNIQUE INDEX ip USING HASH (ip)
)
ENGINE = MEMORY
CHARACTER SET koi8r
COLLATE koi8r_general_ci;
| Теперь создаём логику, которая и будет почти всё делать
CREATE
TRIGGER ddos_analis1
AFTER INSERT
ON ipfw
FOR EACH ROW
BEGIN
SET @coun = new.coun + 1;
SET @ip = new.ip;
SET @type = new.type;
-- Время первого заноса в таблицу
SET @date_in = new.`date`;
-- Время последнего заноса в таблицу
SET @date_last = new.`date`;
-- Интервал, за который идёт анализ
SET @date_exp = NOW() + INTERVAL 5 MINUTE;
-- Интервал, для чего-то создавался, мож быть где-то пригодиться
-- SET @date_delete = NOW() + INTERVAL 1 DAY;
-- Заносим данные в таблицу колектор и, в случаи нахождения ip,
-- обновляем и добавляем очки
INSERT
INTO exim_db.ddos_analis (ip, type, date_in, date_last, date_exp, coun)
VALUES (@ip, @type, @date_in, @date_last, @date_exp, 1)
ON DUPLICATE KEY
UPDATE
exim_db.ddos_analis.coun = exim_db.ddos_analis.coun + 1,
exim_db.ddos_analis.date_last = @date_last,
exim_db.ddos_analis.date_exp = @date_exp;
-- Заносим данные в таблицу, из которой информацию черпает фаервол
-- Данные заносятся из таблицы коллектора
-- coun >10 - это условие, при котором можно с уверенностью сказать,
-- что вас или спамят или ддосят, интервал анализа - @date_exp
-- date_exp + INTERVAL 10 MINUTE интервал,
-- сколько в фаерволе будет находится ip
INSERT IGNORE
INTO exim_db.ddos_exp (ip, date_delete)
SELECT
ip, date_exp + INTERVAL 10 MINUTE
FROM
exim_db.ddos_analis
WHERE
coun > 10;
-- Удаляем просроченные записи или записи из таблицы коллектора
-- по времени оканчания срока жизни @date_exp
DELETE
FROM
exim_db.ddos_analis
WHERE
LEFT(date_exp, 16) < NOW();
-- Удаляем из таблицы коллектора свои подсети
-- Надо будет переделать на свой whitelist, хранимый в мускуле
DELETE
FROM
exim_db.ddos_analis
WHERE
ip LIKE '10.4.%' OR ip LIKE '192.168.%';
END
| В триггере присутствуют комментарии, поэтому писать не буду ничего
Создаём скрипт на маршрутизаторе add_ipfw.sh:
#!/bin/sh
/usr/local/bin/mysql --host=ip_you_mysql_server \
--password='xх' --user=user_to_access_to_mysql_server exim_db --execute=' \
update exim_db.ddos_exp \
set active = 2 \
WHERE \
LEFT(date_delete, 16) < NOW() and active = 1; \
UPDATE exim.ddos_exp \
SET active = 5 where active = 0; \
SELECT "ipfw table 125 add " asdf, ip FROM exim_db.ddos_exp \
WHERE \
active = 5; \
SELECT "ipfw table 125 delete " asdf, ip FROM exim_db.ddos_exp \
WHERE \
active = 2; \
UPDATE exim_db.ddos_exp \
SET active = 1 where active = 5; \
delete FROM exim_db.ddos_exp \
WHERE \
LEFT(date_delete, 16) < NOW() and active = 2;'| \
grep -v asdf>/tmp/exim_ipfw_add_table_blacklist.sh
. /tmp/exim_ipfw_add_table_blacklist.sh
rm /tmp/exim_ipfw_add_table_blacklist.sh
| Делаем скрипт выполнимым
[root@hqgw1 ]$ chmod +x add_ipfw.sh
| Комментарии: в таблице ddos_exp есть поле active, которое отвечает за состояние ip в фаерволе, может принимать 3 значения:
0 - ip ожидают вноса в таблицу фаервола
1 - данные внесены
2 - данные ожидают удаления из фаервола
| У меня используется ipfw. В крон root добавляем
* * * * * /путь/к/вашему/скрипту/add_ipfw.sh
| В фаер добавляем:
#deny mail
${fwcmd} add 56 deny log ip from table\(125\) to any 25 via ${ifwan}
| .
.
.
.
Следующей немаловажной защитой является защита от так называемых пустых коннекшинов, трафик как бы не идёт, но слот занят и потом отваливается с записью в логе
2009-09-07 15:12:42 [40591] SMTP connection from [91.78.180.232]:1666
I=[217.112.209.34]:25 lost
2009-09-07 15:12:42 [40591] no MAIL in SMTP connection from [91.78.180.232]:1666
I=[217.112.209.34]:25 D=4m38s
|
С помощью конфига Exim, я не нашел способа бороться, но у меня есть замечательный файл /var/log/all.log, в который пишется весь(почти) лог. Создаётся он так: в файле /etc/syslog.conf раскомментируется строка:
затем
touch /var/log/all.log
/etc/rc.d/syslogd restart
| Этот файл у меня и так парсится на предмет перебора паролей на ftp, ssh. Так пусть и exim'у он тоже поможет.
Создаём таблицу для занесения статистики:
CREATE TABLE ddos_nomail(
`data` VARCHAR (255) DEFAULT NULL
)
ENGINE = MYISAM
CHARACTER SET koi8r
COLLATE koi8r_general_ci;
| Создаём логику:
CREATE
TRIGGER trigger_nomail
AFTER INSERT
ON ddos_nomail
FOR EACH ROW
BEGIN
SET @ip = new.`data`;
SET @type = "noMAIL";
-- Время первого заноса в таблицу
SET @date_in = NOW();
-- Время последнего заноса в таблицу
SET @date_last = NOW();
-- Интервал, за который идёт анализ
SET @date_exp = NOW() + INTERVAL 5 MINUTE;
-- Интервал, для чего-то создавался, мож быть где-то пригодиться
-- SET @date_delete = NOW() + INTERVAL 1 DAY;
-- Заносим данные в таблицу коллектор и, в случае нахождения ip,
-- обновляем и добавляем очки
INSERT
INTO exim_db.ddos_analis (ip, type, date_in, date_last, date_exp, coun)
VALUES (SUBSTRING_INDEX(SUBSTRING_INDEX(@ip, "]:", 2), "[", -1),
@type, @date_in, @date_last, @date_exp, 1)
ON DUPLICATE KEY
UPDATE
exim_db.ddos_analis.coun = exim_db.ddos_analis.coun + 1,
exim_db.ddos_analis.date_last = @date_last,
exim_db.ddos_analis.date_exp = @date_exp;
-- Заносим данные в таблицу, из которой информацию черпает фаервол
-- Данные заносятся из таблицы коллектора
-- coun >10 - это условие, при котором можно с уверенностью сказать,
-- что вас или спамят или ддосят, интервал анализа - @date_exp
-- date_exp + INTERVAL 10 MINUTE интервал,
-- сколько в фаерволе будет находится ip
INSERT IGNORE
INTO exim_db.ddos_exp (ip, date_delete)
SELECT
ip, date_exp + INTERVAL 10 MINUTE
FROM
exim_db.ddos_analis
WHERE
coun > 10;
-- Удаляем просроченные записи или записи из таблици коллектора
-- по времени окончания срока жизни @date_exp
DELETE
FROM
exim_db.ddos_analis
WHERE
LEFT(date_exp, 16) < NOW();
-- Удаляем из таблицы коллектора свои подсети
-- Надо будет переделать на свой whitelist, хранимый в мускуле
DELETE
FROM
exim_db.ddos_analis
WHERE
ip LIKE '10.4.%' OR ip LIKE '192.168.%';
END
| Создаём очередной скрипт all_log_pars.sh
#!/bin/sh
msql_e="/usr/local/bin/mysql --user=exim_ins --password=х \
--database=exim_db --host=12.12.12.12"
lf="/var/log/all.log"
cp ${lf} ${lf}.tmp
> ${lf}
cat ${lf}.tmp >> ${lf}.store
## Exim analis for no MAIL in SMTP connection
cat ${lf}.tmp|grep 'no MAIL in SMTP connection'| \
awk '{print "insert into exim_db.ddos_nomail value (\""$0"\");"}' \
|${msql_e}
rm -f ${lf}.tmp
| и делаем его исполнимым
В root cron добавляем его выполнение по расписанию.
* * * * * /путь/к/вашему/скрипту/all_log_pars.sh
| Данный метод анализа и защиты использует таблицы и скрипт из первой части статьи.
Следует обратить внимание, что у таблиц ddos_exp и ddos_analis тип MEMORY, нечего насиловать винт, для временных таблиц.
Ссылка на обсуждение: http://forum.lissyara.su/viewtopic.php?f=14&t=20665.
размещено: 2009-09-28,
последнее обновление: 2010-10-07,
автор: buryanov
|
|
|
|
2014-07-27, lissyara
gmirror
Удалённое создание софтверного зеркала средствами gmirror, на диске разбитом с использованием gpart. Использование меток дисков для монтирования разделов.
2013-08-20, zentarim
Scan+Print server FreeBSD 9
Настройка сервера печати и сервера сканирования под управлением операционной системы FreebSD 9 для МФУ Canon PIXMA MP540
2011-11-20, BlackCat
Разъём на WiFi-карту
Делаем съёмной несъёмную антену на WiFi-карте путём установки ВЧ-разъёма
2011-09-14, manefesto
Настройка git+gitosis
Настройка системы контроля версия исходного кода в связке git+gitosis+ssh
|
Комментарии пользователей [6 шт.]