The problem of the lack of the full DHCP-snooping function in MikroTik devices has already been said and written too much. And everywhere for catching the villainous DHCP they offer to load the CPU. I will tell you how to kill someone else's DHCP server using a switch chip integrated into MikroTik CRS switches.
Common materials on the network relate to the work of MikroTik routers. And they all use scant CPU resources to capture DHCP. At the same time, a relatively fresh line of switches is chronically neglected. By the way, completely in vain.
So, the experimental device
CRS125-24G-1S is installed on access. For some time now, occasional IP addresses began to fall on user devices. Naturally, the task “to find and neutralize” arose. In the standard RouterOS arsenal, there is a tool called “DHCP-server Alert” that can trigger some actions when it detects a third-party DHCP server on the network.
Fine? Perhaps. Only a closer look at the tool was not very informative. To understand why, consider the typical architecture of routing equipment MikroTik (picture from the wiki):
')

In fact, the main part of the device is divided into two:
1) software-configured switch, performing switching at maximum speed;
2) CPU responsible for routing, filtering and also able to perform switching at the software level, slower and more resource-intensive.
IP services on such a device, of course, hang at the top level. On the master interface ascending to the CPU Routerboard or on the software bridge. There lives a DHCP server and its alert service. All the solutions I have seen before also had two drawbacks arising from this architecture:
1) Traffic filtering from the villain was performed on the bridge, through the “use ip firewall” and took away the meager CPU resources;
2) The villain connected to the switch continued to uncontrollably dirty the subscribers on the neighboring ports of this switch.
For example, subscribers hanging on port2 and port3 still continued to receive bjaku arriving from port4. But that all changed when MikroTik got the CRS line - the guys installed a more powerful and functional switch chip, which I decided to try to use, win and save CPU resources.
Step # 1
We configure "DHCP-server Alert". The setting itself is not complicated, almost everything is described in the vendor's wiki - we enable, set the interface on which to monitor (for example, bridge-local), specify our trusted DHCP. We can add a script to call in case of anything. Cheers - parameters are automatically transferred to the script: $ interface $ mac-address $ address of the detected villain! Hooray? So easy? But here the first underwater rake is hidden. And not alone.
First rake: in $ interface, the interface name is passed on which the alert itself sits. Therefore, even if the villain is connected to the “port4” interface (see the picture above), the variable will still be “bridge-local”. In the log we see almost the same thing:
"dhcp-alert on bridge-local: discovered unknown dhcp server, mac xx:xx:xx:xx:xx:xx, ip xyz.xyz.xyz.xyz"
Khm How many ports do we have? 24? Okay. I'm going to look for ...
Step 2
According to the rake. It is necessary to search in a unicast-fdb switch, according to the variable $ mac-address. And here the second rake was waiting for me. Real underwater. The script was called, but did not want to work. Those who are engaged in script writing for MikroTik will confirm that debugging an automatically launched script is not a trivial task in itself. Moreover, the on-error {} handler was silent for some reason. It was experimentally discovered that the code
:set portname [/interface ethernet switch unicast-fdb get [find mac-address=$mac-address] port ]
works well on the terminal command line and only on it. In the body of the script does not want. The reason is a strange interpretation of the name by your own (defined by the vendor!) Variable $ mac-address.
Feature: interpretation of commands in the script goes
through ... in a different way. For successful work, the name of the system variable must be escaped:
($"mac-address")
. At the same time, tricks are not excluded in further use.
I went another way, creating a local variable with a normally interpreted name:
:local smac ($"mac-address")
It became easier. Now you can see the name of the real interface on the switch to which the pest is connected. It remains to figure out how to kill him.
As you know, a real Jedi uses power, and a real engineer uses a brain. Therefore, the idea of ​​stupidly completely chopping off the found port was discarded by me - what if there are several users and / or devices sitting behind this port? Fortunately, the switch chip in MikroTik CRS allows you to make a MAC-Based-Vlan. The decision came immediately - to allocate traffic from the villain by MAC and wrap it in a separate unused Vlan. As a result, we got a compact script that reliably disconnects another device from the network with a DHCP server raised on it.
#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))
The variable $ stubvid, as it should be clear from the name, is the number of the Vlan stub. The $ imac variable is an array. For some reason, MikroTik allows you to make several entries with the same MAC in the mac-based-vlan table, which caused a failure when trying to get a single value. Warnings are simply written in log error, but nothing prevents you from adding more persistent information to the network administrator.
The call of the alert and script is registered as follows:
/ip dhcp-server alert add disabled=no interface=bridge-local on-alert=dhcpsnooper valid-server=MAC__DHCP
Thank you for reading to the end. I hope you find it useful someday.