Ранее в первой (теоретической) части статьи была подробно описана сущность сетевого соединения глазами ядра маршрутизатора. В текущей части мы закрепим информацию в результате рассмотрения работы прикладного протокола DNS через подсистемы RouterOS.
В заключительной части речь пойдёт о диаграмме потока пакетов, при работе с которой важно понимать сущность рассматриваемого сетевого соединения, а также о не документированной в явном виде особенности работы NAT. Материала достаточно много, и чтобы читатель не потерял смысловую нить к концу статьи, она разделена на 3 части: теория, практика и особенность NAT.
Материалы носят в основном теоретический характер и предназначены для людей, тонко настраивающих Firewall, Qos и маршрутизацию, где им придётся непосредственно работать с рассматриваемыми connections. Цикл статей не предназначен для новичков и может их только запутать. Полагаю, что читатель хорошо знаком с предметом разговора.Научиться настраивать MikroTik с нуля или систематизировать уже имеющиеся знания можно на углубленном курсе по администрированию MikroTik. Без лишних слов приступим к описанию практической задачи. Имеем классическую локальную сеть, в которой клиенты (в том числе беспроводные) подключены к маршрутизатору (со стороны LAN IP адрес 192.168.1.1, со стороны WAN IP адрес 10.0.2.47) и получают посредством работы DHCP протокола в качестве DNS сервера непосредственно IP адрес роутера. Сам роутер использует в качестве сервера DNS IP адрес Cloudflare (/ip dns set allow-remote-requests=yes servers=1.1.1.1). Пользователь загружает свой ноутбук (PC), подключается к Wi-Fi сети, получает от DHCP сервера IP адрес 192.168.1.2 и в браузере открывает сайт, например, mail.ru. Для простоты сосредоточимся на работе не шифрованного DNS протокола, позволяющего увидеть содержание пакетов на прикладном уровне.
Сколько типов DNS соединений будет создано в RouterOS?
Разберёмся детально и разложим всё по полочкам. Если кто-то не уверен в ответе, то после прочтения ясность будет внесена. В действительности имеем следующие DNS запросы и ответы, передающиеся по транспортному протоколу UDP:
- PC -> MikroTik;
- MikroTik -> DNS servers;
- DNS servers -> MikroTik;
- MikroTik -> PC.
Рассчитываю, что читатель понимает, почему это так, и не отвлекаюсь на описание работы непосредственно DNS протокола. Выделим пакеты каждого варианта запросов, для этого воспользуемся маркировкой трафика:
/ip firewall mangle
add action=mark-connection chain=prerouting comment=\
"DNS catcher PC->MikroTik Connections" dst-address=192.168.1.1 dst-port=\
53 new-connection-mark="DNS catcher PC->MikroTik Connections" \
passthrough=yes protocol=udp
add action=mark-packet chain=prerouting comment=\
"DNS catcher PC->MikroTik Packets" connection-mark=\
"DNS catcher PC->MikroTik Connections" new-packet-mark=\
"DNS catcher PC->MikroTik packets" passthrough=no
add action=mark-connection chain=prerouting comment=\
"DNS catcher DNS Servers->MikroTik Connections" new-connection-mark=\
"DNS catcher DNS Servers->MikroTik Connections" passthrough=yes protocol=\
udp src-address-list="DNS servers" src-port=53
add action=mark-packet chain=prerouting comment=\
"DNS catcher DNS Servers->MikroTik Packets" connection-mark=\
"DNS catcher DNS Servers->MikroTik Connections" new-packet-mark=\
"DNS catcher DNS Servers->MikroTik Packets" passthrough=no
add action=mark-connection chain=output comment=\
"DNS catcher MikroTik->PC Connections" new-connection-mark=\
"DNS catcher MikroTik->PC Connections" passthrough=yes protocol=udp \
src-address=192.168.1.1 src-port=53
add action=mark-packet chain=output comment=\
"DNS catcher MikroTik->PC Packets" connection-mark=\
"DNS catcher MikroTik->PC Connections" new-packet-mark=\
"DNS catcher MikroTik->PC Packets" passthrough=no
add action=mark-connection chain=output comment=\
"DNS catcher MikroTik->DNS Servers Connections" dst-address-list=\
"DNS servers" dst-port=53 new-connection-mark=\
"DNS catcher MikroTik->DNS Servers Connections" passthrough=yes protocol= udp
add action=mark-packet chain=output comment=\
"DNS catcher MikroTik->DNS Servers Packets" connection-mark=\
"DNS catcher MikroTik->DNS Servers Connections" new-packet-mark=\
"DNS catcher MikroTik->DNS Servers Packets" passthrough=no
Маркировка осуществляется по схеме: сначала обозначаются соединения (mark-connection) затем пакеты этих соединений (mark-packet). Соединения «PC -> MikroTik» отлавливаются по IP адресу роутера и 53 номеру порта назначения. Здесь и далее я опускаю одинаковый и потому не информативный в текущем контексте префикс «DNS catcher». Соединения «MikroTik -> DNS servers» помечаются только по 53 номеру порта назначения. Соединения «DNS servers -> MikroTik» маркируются по такой же схеме, только в правиле используется 53 порт отправителя. Соединения «MikroTik -> PC» отлавливаются на основе IP адреса маршрутизатора и 53 порта отправителя. Для исключения ошибки перемаркировка пакетов ограничена (passthrough=no). Обращаю внимание, пакетов, а не соединений. Чтобы убедиться в корректности работы Mangle, по очереди зеркалируем пакеты каждого типа соединений. Пример, как это делается для пакетов «MikroTik -> DNS servers», представлен ниже:
/ip firewall mangle
add action=sniff-tzsp chain=postrouting comment="Sniffer"
packet-mark="DNS catcher MikroTik->DNS Servers Packets" sniff-target=\
IP_адрес_принимающего_сервера sniff-target-port=37008
Как сохранить трафик на принимающей стороне, рассмотрено здесь. Для зеркалируемых пакетов не забываем снять ограничение, озвученное выше, и выставить passthrough=yes, иначе правило /ip firewall mangle add action=sniff-tzsp будет проигнорировано. Почему для разных типов соединений используются различные цепочки в Firewall (Prerouting, Output, Postrouting) будет рассмотрено ниже. Для тех, кто вообще не в теме, коротко прокомментирую: пакет проходит через различные части сетевой подсистемы Linux, ядро применяет правила из определённых цепочек (chains) к пакетам. После получения нового пакета от физического уровня ядро активизирует правила в цепочках, соответствующих вводу. Все эти структуры данных обслуживаются ядром. Такая подсистема в целом и является Firewall-ом, который из пространства пользователя создаёт правила и управляет ими. Иллюстрация, взятая здесь, в очень упрощённом варианте отображает связь между различными цепочками:
В качестве DNS клиента удобно использовать встроенную во многие операционные системы программу nslookup, которой можно указать IP адрес DNS сервера (192.168.1.1) куда будет отправлен запрос:
nslookup mail.ru 192.168.1.1
Посмотрим, что представляет из себя каждый тип выделенных нами пакетов:
- Соединения с меткой «PC->MikroTik Connections» (содержат пакеты «PC->MikroTik packets») передают DNS query;
- Соединения с меткой «MikroTik->DNS Servers Connections» (содержат пакеты «MikroTik->DNS Servers Packets») также передают DNS query;
- Соединения с меткой «DNS Servers->MikroTik Connections» (содержат пакеты «DNS Servers->MikroTik Packets») передают DNS query response;
- Соединения с меткой «MikroTik->PC Connections» (содержат пакеты «MikroTik->PC Packets») также передают DNS query response.
Видно, что маркировка соответствует своим названиям, и, следовательно, выполнена корректно. Пришло время ответить на вопрос, сколько типов соединений создано в RouterOS? Теоретическая часть цикла статей позволяет нам на него ответить – будет создано 2 типа соединения, которые должны получить метки «PC->MikroTik Connections» и «MikroTik->DNS Servers Connections». Внутри операционной системы созданы всего 2 типа соответствующих сокетов (с одинаковыми Stream index). Хотя с точки зрения UDP протокола, будет 4 типа отправки пакетов, ведь UDP ничего не знает про полезную нагрузку прикладного протокола DNS, и что в нём идут запросы и ответы на них, и какие там существуют клиент-серверные взаимосвязи. Чтобы это проверить, дополним правило для «MikroTik->PC Connections» параметром «established», т.е. соединение, которое установлено ранее:
/ip firewall mangle
add action=mark-connection chain=output comment=\
"DNS catcher MikroTik->PC Connections" connection-state=established \
new-connection-mark="DNS catcher MikroTik->PC Connections" passthrough=yes \
protocol=udp src-address= 192.168.1.1 src-port=53
Ничего не изменится, счётчик пакетов будет отрабатывать, потому как соединение было установлено ранее на этапе «PC->MikroTik Connections». А если укажем connection-state=new, то счётчик замрёт, таких новых соединений нет. Попробуем ещё дополнительно повесить указанную марку на соединения, которые ранее не размечались (connection-mark=no-mark):
/ip firewall mangle
add action=mark-connection chain=output comment=\
"DNS catcher MikroTik->PC Connections" connection-mark=no-mark \
new-connection-mark="DNS catcher MikroTik->PC Connections"\
passthrough=yes protocol=udp src-address=192.168.1.1 src-port=53
Счётчики остановятся и возобновят свою работу только, если мы укажем не пустой маркер, а «PC->MikroTik Connections». Для других правил будет аналогичная ситуация. Однако если заглянуть в Connection tracking, то там можно увидеть следующую картину:
Как видно, маркировка как бы перевёрнута, что вначале может даже ошеломить. Чтобы такого с вами не произошло, разберу ситуацию подробно. Если мы укажем для соединений «MikroTik->PC Connections» и «DNS Servers->MikroTik Connections» условие connection-mark=no-mark, то Connection tracking даст ожидаемый результат:
Без него происходит перемаркировка соединений, а с ним уже существующие соединения не получат новую марку. Вышесказанное звучит достаточно запутанно, поэтому передам туже самую мысль, касательно не корректной ситуации в Connection tracking, другими словами. Внутри маршрутизатора возникает следующая ситуация. DNS запрос от PC поступает на DNS сервер, интегрированный в MikroTik. RouterOS внутри себя создаёт первое сетевое соединение «PC->MikroTik Connections». Далее роутер осуществляет DNS запрос к серверу Cloudflare, и создаётся второе соединение «MikroTik->DNS Servers Connections». Далее от сервиса Cloudflare приходит DNS query response, что является продолжением и окончанием второго соединения. После этого роутер выполняет DNS query response в сторону PC, что является продолжением и окончанием первого соединения. Правилами Mangle мы вмешиваемся в вышеописанные действия.
Первая половина первого запроса у нас маркируется как «PC->MikroTik Connections» (корректно), а вторая половина первого запроса маркируется как «MikroTik->PC Connections» (что и должно было вызвать смуту в нашей голове при просмотре Connection tracking, как показано на рисунке с некорректной ситуацией). На деле это одно и то же соединение внутри RouterOS. Однако половина его вышла с одной меткой, а вторая половина с другой, и Connection tracking отрисовал только ту метку, которая пришла к нему последней (в последнем блоке по движению пакетов внутри операционной системы, об этом подробнее будет в третьей части цикла статей). Для соединений «MikroTik->DNS Servers Connections» и «DNS Servers->MikroTik Connections» возникает ровно такая же ситуация. Поэтому выровнять ситуацию нам помог параметр connection-mark=no-mark.
Отмечу, что если в правилах Mangle указать passthrough=no, которое при срабатывании пропустит трафик, минуя оставшиеся правила маркировки (значение по умолчанию для параметра passthrough=yes, поэтому в явном виде оно не указывается), то при отсутствующем параметре connection-mark=no-mark перемаркировка всё равно произойдёт. Ключевую роль опять же играет прохождение соединений и пакетов внутри операционной системы маршрутизатора, о чём мы подробно поговорим в третьей части цикла статей. Параметр passthrough=no попросту не отработает, так как первая половина соединения и вторая половина соединения проходят различными маршрутами внутри роутера.
Резюмирую вышесказанное. При работе описанной классической сети для одного DNS запроса клиента LAN в реальности UDP соединение отрабатывает 4 раза: в направление роутера, затем до DNS сервера Cloudflare и обратно. Однако RouterOS будет воспринимать их только как 2 соединения: от клиента Wi-Fi в направлении маршрутизатора и обратно, а также от роутера до DNS сервера Cloudflare и обратно. В глазах MikroTik, любой одиночный UDP пакет — это новое соединение до тех пор, пока не будет отправлен ответ в обратном направлении. Когда есть ответ, то это уже для него UDP соединение. Разумеется, вышесказанное правило ограничено во времени в соответствии с таймаутами, о которых речь шла в первой части цикла статей.
Ранее говорилось, что защита роутера от DOS атак на L3 уровне может базироваться на правилах обработки сетевых соединений. На практике это будет выглядеть так:
/ip firewall filter
add action=add-src-to-address-list address-list=DOS address-list-timeout=1h chain=input comment="List DOS" connection-limit=100,32 connection-state=new in-interface=WAN
add action=drop chain=input comment="Drop DOS list" src-address-list=DOS
Логика работы приведённых правил следующая: не более 100 новых сетевых соединений с IP адреса с 32 маской, иначе IP адрес идет в бан. Подробнее про возможности можно почитать здесь. В комментариях правильно отметили, что правильнее банить не в таблице Firewall Filter, а в таблице Firewall Raw, почему это так станет очевидно после прочтения третьей части цикла статей:
/ip firewall raw
add action=drop chain=input comment="Drop DOS list" src-address-list=DOS
▍ Заключение
В статье с практической точки зрения рассмотрено, что такое сетевое соединение в ядре Linux. Внутри RouterOS и других, «Linux based» операционных систем, понятие сетевое соединение не идентично клиент-серверному соединению. MikroTik работает с виртуальными сокетами, под которыми следует понимать совокупность пар IP адрес отправителя и номера порта отправителя, а также IP адрес получателя и номера порта получателя, искусственно введённых для обеспечения функционирования устройства. Это особенно важно при настройке Firewall, а следовательно, и связанных с ним Qos и маршрутизации, в некоторых случаях.
Часть 1
Часть 2 (вы тут)
Часть 3