За несколько лет работы, мы для себя нашли некоторую золотую середину в настройке Firewall MikroTik, и естественно хотим поделится её с вами.

MikroTik Firewall Filter

Хочу признаться мне не очень нравиться дефолтный конфиг Firewall, но я прекрасно понимаю, что тем кто его придумал, была задача найти условно общую конфигурацию которая бы подходила к большинству и покрывала решение зада большенства, но мы не большинство, и будем "лепить" свой конфиг.

Естественно чистим конфигурацию или просто очищаем полностью Filter Firewall-а.

/ip firewall filter remove [find]

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

Interface List ISP

В моём случае для примера у меня три провайдера ether1, ether2, ether3 и поверх ether3 запущен PPPoE туннель для получения доступа к интернету.

Создадим лист интерфейсов в котором перечисляем все интерфейсы подключенные к сетям провайдеров. Причём не важно один или два или десять у вас таковых интерфейсов.

/interface list add name=ISP

Как вы его назовёте, не имеет значения, главное чтобы вам был понятен смысл имени и наверное очень важно, то что-бы было понятно любому другому человеку который взглянет на ваши настройки. Ведь согласитесь если вы его назовёте "Bla-bla-bla" смысл для любого человека будет непонятен, хотя возможно для вас он и будет иметь сакральный смысл.

Я предпочитаю называть данный лист ISP, что обозначает Internet Service Provider.

Соответственно добавляем в данный лист все интерфейсы провайдеров.

/interface list member
add list=ISP interface=ether1
add list=ISP interface=ether2
add list=ISP interface=ether3
add list=ISP interface=ether3.PPPoE

Обратите вниманию я добавил ether3 и PPPoE интерфейс которые поднят через него же. По поводу наименование PPPoE туннеля не удивляйтесь у меня есть привычка использовать в наименовании интерфейсов точку в случае если данные интерфейс является sub интерфейсом другого интерфейса. К примеру если у меня будет vlan 100 на первом интерфейсе его имя будет ether1.100.

На данный момент, мы закончили с настройкой листа ISP и может приступить непосредственно к настройке Firewall.

Firewall Filter

Начнём непосредственно настраивать наш filter.

Firewall Filter Input

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

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

/ip firewall filter 

Самым первым правилом отправляем весь трафик с интерфейсов провайдеров в кастомную цепочку (custom chain) с помощью jump.

add chain=input in-interface-list=ISP action=jump jump-target=ISP-Input

С этого момента мы будет работать ТОЛЬКО с цепочкой ISP-Input, про цепочку input можете пока забыть, хотя она нам ещё понадобится.

Следующим правило мы разрешаем, пакеты established которые возвращаются на уже установленное соединение, такие пакеты необходимо разрешать.

add chain=ISP-Input connection-state=established action=accept

Обратите внимание что я не указываю не интерфейсы не список интерфейсов, нам нет необходимости этого делать, так как самое первое правило отправило в данную цепочку только трафик которые приходит с интерфейсов провайдеров перечисленных в листе ISP.

Следующее правило разрешаем related, это пакеты которые создали вторичное соединение, такие пакеты помечаются когда на основании какого либо payload создаются новые соединения, например если вы используете NAT-helper ftp или SIP. Также related в некоторых случаях это ICMP ответ маршрутизатора.

add chain=ISP-Input connection-state=related action=accept

Мы часто используем возможность снижение нагрузки на connection-tracker с помощью исключения пакетов с помощью raw untracked, также используется для обхода NAT в случае когда необходимо исключить процедуру изменения заголовка пакета.

add chain=ISP-Input connection-state=untracked action=accept

Кто-то из вас скажет, "Стоп-стоп но ведь мы может все эти три последние правила описать одним, просто перечислив состояния через запятую!!! Зачем создавать три правила?!" Да можем, но моя задача во-первых показать вам все правила наглядно, а во вторых у нас появляется возможность видеть количество трафика и нагрузку pps по каждому конкретному типу пакетов, и в случае необходимости изменить порядок для оптимизации.

Ну что-же наше первое запрещающее правило, мы должны запретить пакеты с состоянием invalid, таким состоянием помечаются пакеты в нескольких случаях:

  1. Если на вашем маршрутизаторе закончится память и connection-tracker не сможет создать запись для соединения, но это редкий случай.
  2. Если пакет принадлежит к одному из протоколов GRE, ICMP или TCP то RouterOS умеет понимать по содержимому пакетов данных протоколов должен являться данный пакет частью существующего соединения или нет. Если по признакам он является частью соединения, но соединения нет в connection-tracker, то такой пакет помечается как invalid. Пример на маршрутизатор пришёл один пакет TCP с флагами syn и ack, т.е. Какой-то хост "по идеи" ответил на посылку syn пакета, но если соединения нет, то нам такой пакет не нужен. Также это простая защита от TCP RST Flood.
add chain=ISP-Input connection-state=invalid action=drop

Как вы наверное знаете в RouterOS с включенным connection-tracker существует пять состояний пакетов, четыре из которых мы описали, а так как правила в firewall терминирующие, т.е после срабатывания правила пакет прекращает обработку в filter. У нас остаётся всего один тип пакетов это new это те самые пакеты которые создают соединения, другими словами когда кто-то инициализирует соединение к маршрутизатору такой пакет имеет состояние new. Но так как мы описали четыре состояния, нет смысла указывать состояние, так как подразумевается по остаточному принципу, что в следующем правиле и так будут только new.

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

Выносим все разрешающие правила в отдельную цепочку например с именем ISP-Input-Allow. В таком случае нет необходимости думать в каком месте по порядку разместить правила, чтобы они были правильно расположены относительно всех других правил.

add chain=ISP-Input action=jump jump-target=ISP-Input-Allow

Следующим правилом мы запрещает все остальные пакеты, которые дошли до следующего правила. Будте аккуратны, возможно если вы подключены через провайдера к маршрутизатору, вы не сможете подключится к маршрутизатору в случае разрыва соединения.

add chain=ISP-Input action=drop

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

Для закрепления результата представим, что у нас поднят на RouterOS l2tp сервер и мы хотим иметь возможность подключаться по ssh, а также маршрутизатор должен отвечать на запросы icmp.

Мы будем использовать кастомную цепочку ISP-Input-Allow и порядок правил в нём не важен, а также не важно расположение правил в этой цепочке относительно всех других правил, хоть в разнобой, хоть в конце, хоть в начале. Это не принципиально. Наверное всё таки для удобства желательно расположить их по порядку и в одном месте, но это только для тех кто использует winbox для настроек, а для тех кто используется CLI или как-то оркестратор типа ansible, как раз проявляется удобство в том, что вам не надо думать о прядке правил.

Опишу правила одним блоком

add chain=ISP-Input-Allow protocol=icmp action=accept
add chain=ISP-Input-Allow protocol=tcp dst-port=22 action=accept
add chain=ISP-Input-Allow protocol=udp dst-port=1701 action=accept

Если пакет которых поступает в данную цепочку дойдёт до конца её, то он перейдёт на следующее правило после которого он попал в данную цепочку.

Вот таким образом у вас должен выглядеть filter в winbox.

vasilevkirill mikrotik Filter Firewall

Я отформатировал вывод убрав отображение некоторых столбцов.

А теперь давайте посмотрим как будут работать данные правила, при поступления трафика в цепочку INPUT.

Первый пример HOST 5.5.5.5 хочет установить соединение с SSH MikroTik с адресом 2.2.2.2.

Хост 5.5.5.5 отправляет syn пакет для установления соединения с ssh сервером на MikroTik

vasilevkirill mikrotik Filter Firewall

Такой пакет первым же правилом попадает под jump и отправляется к custom chain ISP-Input

Далее маршрутизатор находит все правила в кастомной цепочке ISP-Input переберать соответствию пакета дял правила

vasilevkirill mikrotik Filter Firewall

В первых 4 правилах в цепочке ISP-Input он не найдёт соответствия, а вот в пятом правиле сделает jump на ещё одну цепочку. Соответственно выберет все правила из новой цепочке ISP-Input-Allow

vasilevkirill mikrotik Filter Firewall

И будет снова сверять по порядку, соответствия пакета правилу.

vasilevkirill mikrotik Filter Firewall

Как только найдено терминирующее правило, а в нашем случае это accept, маршрутизатор заканчивает обработку данного пакета в filter firewall и отправляет пакет в Local Process.

SSH сервер ответит пакетом TCP c флагами syn,ack после получения такого пакета клиент отправит пакет с флагом ACK и такой пакет уже будет обрабатываться как established.

vasilevkirill mikrotik Filter Firewall

vasilevkirill mikrotik Filter Firewall

Но первым же правилом в цепочек ISP-input у нас есть разрешающее терминирующее правило для пакетов с состоянием established. Такой пакет сразу отправиться в Local Process.

vasilevkirill mikrotik Filter Firewall

А теперь давайте попробуем разобраться, что будет если хост отправит пакет на порт Winbox TCP 8291, который мы явно не запрещали.

Начало будет одинаковое

vasilevkirill mikrotik Filter Firewall

vasilevkirill mikrotik Filter Firewall

Когда пакет будет проверяться соответствиям правилам в цепочке ISP-Input-Allow, для него не найдётся не одного подходящего правила.

vasilevkirill mikrotik Filter Firewall

В этом случае произойдёт автоматически return, и обработка выйдет из цепочки ISP-Input-Allow и продолжит обрабатываться в цепочке ISP-Input, а у нас есть правило, которое отбрасывает все пакеты DROP всё, такой пакет не когда не попадёт в Local Process.

vasilevkirill mikrotik Filter Firewall

Т.е если в custom chain не найдено соответствие не с одним правилом, то обработка такого пакета возвращается обратно и продолжает обработку по порядку со следующего правила места входа.

Для удобства восприятия поставил слева номера, чтобы был понятен порядок обработки

vasilevkirill mikrotik Filter Firewall

И ещё раз порядок правил имеет значения только для каждой отдельной цепочки, а не относительно всех цепочек.

На этом этапе мы закончили работу с трафиком Input и переходим к Forward.

Firewall Filter Forward

Естественно нам необходимо защитить трафик которых проходит со стороны провайдеров через маршрутизатор.

Многие наверное скажут, а зачем его защищать, ведь трафик нельзя отправить через маршрутизатор, для этого необходимо адрес маршрутизатора прописать как шлюз, что в свою очередь говорит о том, что маршрутизатор должен находится в Connected сети.

Вот вам маленькая история.

Мне провайдер выдаёт внутренней адрес из сети /22 и со всеми соседями я нахожусь в одном брудкаст домене. Получилось так, что пропустил платёж и мне провайдер на шлюзе зарезал интернет, но он не отключил порт на коммутаторе, и мне всё также была доступна внутренняя сеть. Запустил LLDP на интерфейсе провайдера и увидел что со мной в одной сети находятся как минимум пять маршрутизаторов MikroTik. И логика была у меня такая:

По умолчания в RouterOS на первом порту отключен LLDP, а если я вижу это значит что либо конфигурации была сброшена либо используется порт не ether1. Соответственно возможно, что на нём неправильно настроен firewall.

Так и получилось я на своём маршрутизаторе прописал адрес MikroTik первого из списка и у меня появился интернет, да с другого IP адреса, но этого достаточно. Сразу скажу, что на всех пяти MikroTik-ах которые я видел, и кстати до сих пор я наблюдаю в сети данные MikroTik c таким образом настроенным Firewall, что я в любой момент могу получить доступ в интернет через них.

Вот именно от таких ситуаций нам необходимо защитится.

И опять же мы будем использовать кастомную цепочку.

Первым правилом мы отправляем весь проходящий forward трафик с интерфейсов провайдеров в цепочку ISP-Forward.

add action=jump chain=forward in-interface-list=ISP jump-target=ISP-Forward

Следующие правила вам должны быть уже знакомы. Не буду повторять описание

add chain=ISP-Forward connection-state=established action=accept
add chain=ISP-Forward connection-state=related action=accept
add chain=ISP-Forward connection-state=untracked action=accept
add chain=ISP-Forward connection-state=invalid action=drop

Единственно, что необходимо уточнить, что в случае если вы используете BGP или у вас возникает ситуация, что у вас может быть асинхронная маршрутизация. То вам необходимо разрешать трафик invalid. Но в большинстве случаев это не так.

Далее вы помните, что по типу исключения у нас остаётся только пакеты которые имеют состояние new, и если по думать то такие пакеты могут проходить через маршрутизатор со стороны провайдера только если они попадают под процедуру изменения адреса назначения.

Поэтому нам необходимо разрешить пакеты new которые попадают под dst Нат.

add chain=ISP-Forward connection-nat-state=dstnat action=accept

И последний правилом мы закрывает доступ из вне всем отвальным пакетам.

add chain=ISP-Forward action=drop

Собственно всё.

Давайте взглянем на наши правила.

vasilevkirill mikrotik Filter Firewall

Соответственно, если вам необходимо разрешить подключаться к маршрутизатору, будь то по VPN или ещё как-то, вы всегда можете добавить правило в цепочку ISP-Input-Allow и не думать о порядке правил.

Я приведу итоговый результат немного отформатированный.

/ip firewall filter
add chain=input in-interface-list=ISP action=jump jump-target=ISP-Input
add chain=forward in-interface-list=ISP action=jump jump-target=ISP-Forward

add chain=ISP-Input connection-state=established action=accept 
add chain=ISP-Input connection-state=related action=accept
add chain=ISP-Input connection-state=untracked action=accept
add chain=ISP-Input connection-state=invalid action=drop
add chain=ISP-Input jump-target=ISP-Input-Allow action=jump
add chain=ISP-Input action=drop

add chain=ISP-Forward connection-state=established action=accept
add chain=ISP-Forward connection-state=related action=accept
add chain=ISP-Forward connection-state=untracked action=accept
add chain=ISP-Forward connection-state=invalid action=drop
add chain=ISP-Forward connection-nat-state=dstnat action=accept
add chain=ISP-Forward action=drop

add chain=ISP-Input-Allow protocol=icmp action=accept
add chain=ISP-Input-Allow dst-port=22 protocol=tcp action=accept
add chain=ISP-Input-Allow dst-port=1701 protocol=udp action=accept

На этом на сегодня всё, продолжение следует...

Рассказать друзьям

Чатик телеграм

@mikrotikme