Хабрахабр

[Из песочницы] Собираем логи фаервола Mikrotik в базу данных

Добрый день.

Хочу рассказать как легко и непринужденно можно настроить сервер сбора метаданных сетевого трафика для маршрутизаторов Микротик.

Цель: Целью будет, хранение «пережеванных» логов фаервола в базе данных, для последующего анализа.

Так же нам потребуется СУБД, я выбрал mariadb. Средства: Для реализации подойдет любой свежий дистрибутив Linux с rsyslogd v8 и выше, возможно предложенный синтаксис будет работать и на v7. За месяц использования БД включая индексы выросла до 3,8Гб. Прирост БД будет варьироваться от количества журналируемых правил, потому размер накопителя на ваше усмотрение, в моем случае журналируются 30-40 правил, что в день составляет примерно 1200 тысяч строк.

Сервер rsyslog с помощью регулярных выражений проводит очистку строк от лишней информации, формирует SQL вставку и отправляет её в СУБД. Механика: Маршрутизатор отправляет лог на удаленный сервер по UDP. СУБД, с помощью триггера до вставки, проводит дополнительную очистку и разделение полей, которые не удалось разобрать в rsyslog.

Настраиваем RSYSLOG

Редактируем файл /etc/rsyslog.conf
Добавляем туда следующие строки:

module(load="ommysql")
module(load="imudp")
input(type="imudp" port="514")

Тем самым подгружаем необходимые модули и открываем 514 порт UDP.

Строка лога от Микротика выглядит так:

20180927155341 BLOCKSMKNETS forward: in:ether6 - LocalTORF out:VLAN55 - RT_INET, src-mac 00:15:17:31:b8:d7, proto TCP (SYN), 192.168.0.234:2457->192.168.6.14:65535, len 60

Как видим, много лишнего для хранения в БД и внятная выборка будет затруднена.
По идее, мне надо складывать такие данные:

20180927155341 ether6 VLAN5 192.168.0.234 2457 192.168.6.14 65535 00:15:17:31:b8:d7 TCP forward BLOCKSMKNETS 60

Получить такую строку средствами только одного rsyslog у меня не получилось. Регулярки rsyslog используют POSIX ERE/BRE, потому нет возможности применить такие фичи как, lookahead или lookbehind.

Только учтите что у некоторых протоколов sport и dport отсутствуют. Тут есть инструмент который позволяет проводить отладку регулярок, попробуйте может у вас получится отделить порт от адреса, а так же название интерфейса от in: и out:.

В общем у меня на выходе получилось так:

20180927155341 in:ether6 out:VLAN5 192.168.0.234:2457 192.168.6.14:65535 00:15:17:31:b8:d7 TCP forward BLOCKSMKNETS 60

Тут есть документация как готовить регулярки rsyslog.

В конечном виде файл конфигурации приема лога от Микротика /etc/rsyslog.d/20-remote.conf будет выглядеть так:

$template tpl_traflog,"insert into traflog.traffic (datetime, inif, outif, src, dst, smac, proto, chain, logpref, len) values ('%timereported:::date-mysql%', '%msg:R,ERE,0,BLANK,0:in:[a-zA-Z]+[0-9]+|in:<[a-zA-Z]+-[a-zA-Z]+>--end%', '%msg:R,ERE,0,BLANK,0:out:[a-zA-Z]+[0-9]+|out:<[a-zA-Z]+-[a-zA-Z]+>--end%', '%msg:R,ERE,0,BLANK,0:([0-9]+\.)[0-9]+[:]?([0-9]+)?--end%', '%msg:R,ERE,0,BLANK,1:([0-9]+\.){3}[0-9]+[:]?([0-9]+)?--end%', '%msg:R,ERE,0,BLANK:([0-f]+:){5}[0-f]+--end%', '%msg:R,ERE,0,DFLT:\b[A-X]{3,4}\b--end%', '%msg:R,ERE,0,BLANK:[a-x]+--end%', '%msg:F,32:2%', '%msg:R,ERE,0,BLANK:[0-9]+$--end%' )",SQL
if ($fromhost-ip == '192.168.0.230') then {action(type="ommysql" server="localhost" serverport="3306" db="traflog" uid="rsyslogger" pwd="..." template="tpl_traflog") stop}

В первой строке описание шаблона(template) — строка SQL кода, для передачи её в СУБД.
Вторая строка это условие когда будет происходить действие, то есть запись в СУБД.
Условие выглядит так: если источник лога = 192.168.0.230 (if ($fromhost-ip == '192.168.0.230')), то используя модуль ommysql с параметрами подключения (then {action(type="ommysql" server="localhost" serverport="3306" db="traflog" uid="rsyslogger" pwd="..." ) вызываем шаблон tpl_traflog (template="tpl_traflog")), а после этого прекращаем дальнейшую обработку строки (stop}).

Для отладки сделаем следующее, вторую строку комментируем, добавляем новый шаблон и два новых условия: Возможно что в вашем случае что-либо пойдет не так, это может быть связано с названиями интерфейсов или префиксами логов, возможно что-то еще.

$template tpl_traflog_test,"'%timereported:::date-mysql%', '%msg:R,ERE,0,BLANK,0:in:[a-zA-Z]+[0-9]+|in:<[a-zA-Z]+-[a-zA-Z]+>--end%', '%msg:R,ERE,0,BLANK,0:out:[a-zA-Z]+[0-9]+|out:<[a-zA-Z]+-[a-zA-Z]+>--end%', '%msg:R,ERE,0,BLANK,0:([0-9]+\.){3}[0-9]+[:]?([0-9]+)?--end%', '%msg:R,ERE,0,BLANK,1:([0-9]+\.){3}[0-9]+[:]?([0-9]+)?--end%', '%msg:R,ERE,0,BLANK:([0-f]+:){5}[0-f]+--end%', '%msg:R,ERE,0,BLANK:\b[A-X]{3,4}\b--end%', '%msg:R,ERE,0,BLANK:[a-x]+--end%', '%msg:F,32:2%', '%msg:R,ERE,0,BLANK:[0-9]+$--end%' "
if ($fromhost-ip == '192.168.0.230') then {action(type="omfile" file="/var/log/remote/192.168.0.230.log" )}
if ($fromhost-ip == '192.168.0.230') then {action(type="omfile" file="/var/log/remote/192.168.0.230.log" template="tpl_traflog_test" ) stop}

Перезапустим логгер.

Шаблон tpl_traflog_test аналогичен tpl_traflog но без SQL INSERT.

168. Первое условие добавляет не обработанную строку %msg% в файл /var/log/remote/192. 230.log. 0.

Так будет удобнее сравнивать.
Далее подготовим базу данных. Второе условие добавляет обработанную строку в тот же файл.

Готовим БД

Настройку СУБД опустим, тут все стандартно.

Запускаем консоль mysql и выполняем следующий код:

--добавляем базу данных
create database traflog character set utf8 collate utf8_bin;
use traflog; --добавляем таблицу
create table traffic (id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
datetime DATETIME,
inif VARCHAR(20),
outif VARCHAR(20),
src VARCHAR(21),
sport INT(5),
dst VARCHAR(21),
dport INT(5),
smac VARCHAR(17),
proto VARCHAR(4),
chain VARCHAR(8),
logpref VARCHAR(24),
len INT(5)) ENGINE=MYISAM; --добавляем пользователя
create user rsyslogger@localhost identified by '...';
grant all privileges on traflog.* to rsyslogger@localhost;

Таблица готова, пользователь есть.

Теперь добавим триггер, он сделает то, что не удалось логгеру, отделит адрес от порта и названия интерфейсов:

--добавляем триггер
DELIMITER //
create TRIGGER delim_ip_port BEFORE insert ON traffic
FOR EACH ROW
begin
set NEW.inif = REGEXP_REPLACE ((NEW.inif), 'in:', '' );
set NEW.outif = REGEXP_REPLACE ((NEW.outif), 'out:', '' );
set NEW.sport = REGEXP_REPLACE ((NEW.src), '([0-9]+\.){3}[0-9]+:|([0-9]+\.){3}[0-9]+', '' );
set NEW.src = REGEXP_REPLACE ((NEW.src), ':[0-9]+', '' );
set NEW.dport = REGEXP_REPLACE ((NEW.dst), '([0-9]+\.){3}[0-9]+:|([0-9]+\.){3}[0-9]+', '' );
set NEW.dst = REGEXP_REPLACE ((NEW.dst), ':[0-9]+', '' );
end //
delimiter ;

REGEXP_REPLACE ищет второй после запятой параметр(регулярку) и заменяет на третий параметр, в нашем случае в кавычках ничего нет поэтому просто уберет то что нашел.

Сделаем тестовую вставку, аналогично тому как будет делать логгер:

--вставка тестовой строки
insert into traffic (datetime, inif, outif, src, dst, smac, proto, chain, logpref)
values (20180730075437, 'in:ether6', 'out:VLAN55', '192.168.0.234:4997', '192.168.6.18:65535', '00:15:17:31:b8:d7', 'TCP', 'forward', 'BLOCKSMKNETS');

Посмотрим что получилось:

select * from tarffic;

Если все верно, тогда идем дальше. Если нет ищем в чем ошибка.

Я не мастер создавать индексы, но как понял, в mysql для разных запросов правильнее использовать индексы с разными стыкующими полями, так как один запрос может использовать только один индекс(или я не прав?). Добавим хотя бы один индекс. Для примера хватит этого: Если понимаете, сделайте на свое усмотрение.

--добалвяем индекс
create index traffic_index on traffic (src, dst, dport, datetime);

Готово.

Теперь нужно запустить отправку на маршрутизаторе, добавьте настройку удаленного сервера логов и действие к нему, добавьте опцию log в одно из правил фаервола, добавьте префикс не более 24 символов.

В консоли микротика это выглядит примерно так:

/system logging action
set 3 remote=192.168.0.94 src-address=192.168.0.230
add name=remote2 remote=192.168.0.19 syslog-facility=local6 target=remote
/system logging
add action=remote topics=error,account,critical,event,info
add action=remote2 topics=firewall /ip firewall filter
...
add action=drop chain=input comment="drop ssh brute forcers" dst-port=22,8291 log=yes log-prefix=DROP_SSH_BRUTE protocol=tcp src-address-list=ssh_blacklist
...

Где 192.168.0.230 адрес маршрутизатора, 192.168.0.19 адрес лог сервера для логов фаервол, а 192.168.0.94 это другой лог сервер туда у меня валятся системные логи микротика, он нам сейчас не нужен. Наша настройка это remote2.

Далее смотрите что повалится в файл:

tail -f /var/log/remote/192.168.0.230.log

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

Тогда вместо пустоты какого либо поля появятся какие-то буквы, непомню уже какие. Если каких-то полей не хватает, то есть не соблюдается последовательность datetime, inif, outif, src, dst, smac, proto, chain, logpref, len, то можно попробовать поменять параметр в отладочных шаблонах логгера, заменить BLANK на DLFT. Если такое произошло, значит с регуляркой что-то не так и надо исправить.

Если все пошло как надо то отключаем тестовые условия и шаблон.

Еще надо дефолтный конфиг в /etc/rsyslog.d/ спустить ниже, я переименовал его в 50-default.conf, дабы remote логи не сыпались в системный журнал /var/log/message
Перезапустим логгер.

Далее можем начинать выборку. Подождем немного, пока наша БД наполнится.

Несколько запросов для примера:

Что бы посмотреть размер БД и количество строк:

MariaDB [traflog]> select table_schema as "database", round(sum(data_length + index_length)/1024/1024,2) as "size Mb", TABLE_ROWS as "count rows" from information_schema.tables group by table_schema; +--------------------+---------+------------+
| database | size Mb | count rows |
+--------------------+---------+------------+
| information_schema | 0.17 | NULL |
| traflog | 3793.39 | 21839553 |
+--------------------+---------+------------+
2 rows in set (0.48 sec)

За месяц выросла почти 4Гб, но это зависит от количества и свойств логгируемых правил фаервола

Количество логгируемых префиксов

Количество логгируемых префиксов не равно количеству правил, некоторые правила работают с одним префиксом, но все же сколько всего префиксов? и сколько по ним отработано правил?:

MariaDB [traflog]> select logpref,count(logpref) from traffic group by logpref order by count(logpref) desc;
+----------------------+----------------+
| logpref | count(logpref) |
+----------------------+----------------+
| ACCEPT_TORF_INET | 14582602 |
| ACCEPT_SMK_PPP | 1085791 |
| DROP_FORWARD_INVALID | 982374 |
| REJECT_BNK01 | 961503 |
| ACCEPT_MMAX_TORF | 802455 |
| ACCEPT_TORF_PPP | 736803 |
| SMTP_DNAT | 689533 |
| ACCEPT_SMK_INET | 451411 |
| ACCEPT_INET_TORF | 389857 |
| BLOCK_SMKNETS | 335424 |
| DROP_SMTP_BRUTE | 285850 |
| ACCEPT_ROZN_TORF | 154811 |
| ACCEPT_TORF_MMAX | 148393 |
| DROP_ETHALL_ETHALL | 80679 |
| ACCEPT_SMTP | 48921 |
| DROP_SMTP_DDOS | 32190 |
| RDP_DNAT | 28757 |
| ACCEPT_TORF_ROZN | 18456 |
| SIP_DNAT | 15494 |
| 1CWEB_DNAT | 6406 |
| BLOCKSMKNETS | 5789 |
| DROP_SSH_BRUTE | 3162 |
| POP_DNAT | 1997 |
| DROP_RDP_BRUTE | 442 |
| DROP_BNK01 | 291 |
| DROPALL | 138 |
| ACCEPT_RTP_FORWARD | 90 |
| REJECT_SMTP_BRUTE | 72 |
| L2TP_INPUT_ACCEPT | 33 |
+----------------------+----------------+
29 rows in set (2 min 51.03 sec)

ACCEPT_TORF_INET в лидерах, по этому префиксу можно найти всех кто сходил в интернет из нашей локальной сети, протоколы и порты записаны, настанет время и доступ кое-кому будет закрыт. Тут есть опорные данные для будущей работы над ошибками.

Лидер smtp тыка

Посмотрим кто сегодня пытался подобраться к smtp серверу:

MariaDB [traflog]> select src,count(dport) from traffic where logpref='SMTP_DNAT' and datetime > '2018101600000000' group by src order by count(dport) desc limit 10;
+----------------+--------------+
| src | count(dport) |
+----------------+--------------+
| 191.96.249.92 | 12440 |
| 191.96.249.24 | 4556 |
| 191.96.249.61 | 4537 |
| 185.255.31.122 | 3119 |
| 178.57.79.250 | 226 |
| 185.36.81.174 | 216 |
| 185.234.219.32 | 211 |
| 89.248.162.145 | 40 |
| 45.125.66.157 | 32 |
| 188.165.124.31 | 21 |
+----------------+--------------+
10 rows in set, 1 warning (21.36 sec)

Понятно, узел 191.96.249.92 сегодня победитель. Посмотрим в каких логгируемых правилах он еще фигурировал:

MariaDB [traflog]> select src,dport,count(dport),logpref from traffic where src='191.96.249.92' group by logpref order by count(dport) desc;
+---------------+-------+--------------+-----------------+
| src | dport | count(dport) | logpref |
+---------------+-------+--------------+-----------------+
| 191.96.249.92 | 25 | 226989 | SMTP_DNAT |
| 191.96.249.92 | 25 | 170714 | DROP_SMTP_BRUTE |
| 191.96.249.92 | 25 | 2907 | DROP_SMTP_DDOS |
| 191.96.249.92 | 25 | 2061 | ACCEPT_SMTP |
+---------------+-------+--------------+-----------------+
4 rows in set (10 min 44.21 sec)

Этот специализируется только на smtp, ~1% попаданий для попытки подбора пароля или попытки отправки какой-нибудь фигни, остальное ушло в баню.

Запрос формировался 10 минут это много, текущие индексы не подходят для него, либо можно переформулировать запрос, но сейчас не будем об этом.

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

Всем спасибо!

Список литературы:

Документация по rsyslog
Документация по mysql
Документация по Mikrotik logging

Спасибо сообществу LOR за подсказки

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть