Отстрел чужих DHCP-серверов на коммутаторе MikroTik CRS

О проблеме отсутствия функции полноценного DHCP-snooping в устройствах MikroTik уже было сказано и написано слишком много. И везде для отлова злодейских DHCP предлагают нагружать CPU. Я же расскажу, как убить чужой DHCP-сервер с помощью свитч-чипа интегрированного в коммутаторы MikroTik CRS.

Распространенные в сети материалы касаются работы именно маршрутизаторов MikroTik. И все они для отлова DHCP используют скудные ресурсы CPU. При этом, относительно свежая линейка коммутаторов хронически остается без внимания. Между прочим, совершенно напрасно.

Итак, подопытный аппарат CRS125-24G-1S установлен на доступе. С некоторых пор изредка на пользовательские устройства стали выпадать посторонние IP-адреса. Естественно возникла задача «найти и обезвредить». В стандартном арсенале RouterOS есть инструмент «DHCP-server Alert», способный вызывать некие действия при обнаружении в сети стороннего DHCP-сервера.

Отлично? Пожалуй. Только инструмент при ближайшем рассмотрении оказался не слишком информативный. Чтобы понять почему, рассмотрим типичную архитектуру маршрутизирующего оборудования MikroTik (картинка из вики):

image

По сути основная часть устройства делится на две:

1) програмно-конфигурируемый свитч, осуществляющий коммутацию на максимальной скорости;
2) CPU отвечающий за маршрутизацию, фильтрацию а также умеющий осуществлять коммутацию на программном уровне, медленнее и более ресурсоёмко.

IP-сервисы на таком устройстве, само собой висят на верхнем уровне. На Master-интерфейсе восходящем к CPU Routerboard или на программном бридже. Там и живет DHCP-сервер и его служба алертов. Все виденные мною ранее решения имели также два недостатка вытекающие из этой архитектуры:

1) Фильтрация трафика от злодея выполнялась на бридже, через «use ip firewall» и отнимала без того скудные ресурсы CPU;
2) Злодей подключенный к свитчу продолжал неконтролируемо пакостить абонентам на соседних портах этого свича.

Например, абоненты висящие на port2 и port3 всё равно продолжали получать бяку прилетающую со стороны port4. Но всё изменилось, когда у MikroTik появилась линейка CRS — ребята установили более мощный и функциональный свитч-чип, который я и решил попытаться использовать, победить и сохранить ресурсы CPU.

Шаг №1


Настраиваем «DHCP-server Alert». Настройка сама по себе не сложная, почти всё описано в вендорской вики — включаем, задаем интерфейс на котором следить (например bridge-local), указываем доверенный наш DHCP. Можем добавить скрипт, который вызывать в случае чего. Ура — скрипту автоматически передаются параметры: $interface $mac-address $address обнаруженного злодея! Ура? Так легко? Но вот тут-то и спрятаны первые подводные грабли. И не одни.

Грабли первые: в $interface передается имя интерфейса на котором сидит сам алертер. Потому, если даже злодей подключен к интерфейсу «port4» (см. картинку выше), в переменной всё равно будет «bridge-local». В логе видим почти то же самое:

"dhcp-alert on bridge-local: discovered unknown dhcp server, mac xx:xx:xx:xx:xx:xx, ip xyz.xyz.xyz.xyz"


Кхм. Сколько у нас портов? 24? Ладно. Я иду искать…

Шаг №2


По граблям. Искать приходится в unicast-fdb свича, по переменной $mac-address. И вот тут-то меня ждали вторые грабли. Настоящие подводные. Скрипт вызывался, но никак не хотел работать. Кто занимается скриптописательством для MikroTik подтвердит — отладка автоматически запускаемого скрипта сама по себе задача нифига не тривиальная. Да еще и обработчик on-error{} почему-то молчал. Опытным путём было обнаружено, что код

:set portname [/interface ethernet switch unicast-fdb get [find mac-address=$mac-address] port ]


отлично отрабатывает в командной строке терминала и только в ней. В теле скрипта не желает. Причина — странная интерпретация имени собственной (определенной вендором!) переменной $mac-address.

Фича: интерпретация команд в скрипте идет через... иным путём. Для успешной работы, имя системной переменной надо экранировать: ($"mac-address") . При этом в дальнейшем использовании тоже не исключены фокусы.

Я пошел другим путем, создав локальную переменную с нормально интерпретируемым именем:

:local smac ($"mac-address")


Стало легче. Появилась возможность видеть название реального интерфейса на свитче, к которому подключен вредитель. Осталось придумать как его убить.

Как известно, настоящий джедай использует силу, а настоящий инженер использует мозг. Поэтому, идея тупо полностью отрубить найденный порт была мною отброшена — а вдруг за этим портом сидит несколько пользователей и/или устройств? К счастью свитч-чип в MikroTik CRS позволяет делать MAC-Based-Vlan. Решение пришло тут же — выделить трафик от злодея по MAC и завернуть в отдельный неиспользуемый Vlan. В итоге, получился компактный скрипт, надежно отключающий от сети чужое устройство с поднятым на нём DHCP-сервером.

#dhcpsnooper - script to cut off rogue DHCP server
#stubvid - Stub Vlan Id to move rogue DHCP server. Set your own value according your vlan config
:local stubvid 666
:local smac ($"mac-address")
:local portname [/int eth sw uni get [find mac-address=$smac] port ]
:local imac  [/int eth sw mac find src-mac-address=$smac]
if ([:len $imac]<1)   do={/interface ethernet switch mac-based-vlan add   new-customer-vid=($stubvid) src-mac-address=($smac) } else={
foreach i in $imac  do={/interface ethernet switch mac-based-vlan set $i new-customer-vid=($stubvid) src-mac-address=($smac) disabled=no }         }
/interface ethernet switch port set $portname allow-fdb-based-vlan-translate=yes
log error ("DHCP found on PORT:".($"portname")."   MAC:".($"mac-address")."   IP:".($address))


Переменная $stubvid, как должно быть понятно из названия — номер Vlan-заглушки. Переменная $imac — массив. MikroTik зачем-то позволяет делать несколько записей с одинаковым MAC в таблице mac-based-vlan, что вызывало сбой при попытке получить единственное значение. Предупреждения просто пишутся в log error, но ничто не мешает дописать более настойчивое информирование администратора сети.

Вызов алерта и скрипта у меня прописан следующим образом:

/ip dhcp-server alert add disabled=no interface=bridge-local on-alert=dhcpsnooper  valid-server=MAC_своего_DHCP


Спасибо, что дочитали до конца. Надеюсь, вам это когда-нибудь пригодится.

Додати коментар


Захисний код
Оновити

EcoMonitoring

ЛІЧІЛЬНИК ВІДВІДУВАННЬ

Сьогодні 498
Вчора386
Цього тижня 884
Минулого тижня 2262
Цей місяць 8442
Минулий місяць 9310
За весь час 172476
Ваш IP: 18.216.67.104
Сегодня: 2025-04-28
Пользователей на сайте: 0
Гостей на сайте: 45