Maybe this script will be interesting for someone.
Some time ago I have administering ISP routers with many clients using static ips.
To make things more secure we added ip->arp entries for clientip+clientmac.
It was very boring and unreliable to add this rules manually.
So I invented this algorithm and implemented it in script.
- search for all dynamic mac addresses whose ip not in whitelist (add router gateway subnet here and trusted ips)
- make a database of dynamic mac with corresponding ip
- monitor for 3 days for this ips to appear again
3.1. if ip appears again with the same mac in second day - add to list of “good” ips
3.2. if ip appears again with the different mac in second day - add ip to blacklist (not monitored) or you could just start monitoring over again - if it appears again with the same mac in the third day and ip is in the list of good ips, then make an ip->arp record
Very simply, isn’t it?
But we used RouterOS version 2.8 and it takes a lot of time to implement it.
Few more word on environment:
- script language is for RouterOS 2.8!
- routers shouldn’t be rebooted at least 3 days to script make one monitoring cycle
- script can monitor N ips simultaneously (it’s set in variable)
- script should be scheduled to run every hour
- all the used ips have ip->arp disabled record with any mac address (so, if user changes pc or router, you just disabled ip->arp record and script will monitor for the new mac) and not used ips have enabled ip->arp record with inexistent mac (00:00:00:00:00:00 for example).
I have used two script - first is the monitoring itself and second is for whitelist and blacklist (it shouldn’t be erased on reboots, so I recorded it to different script).
To make things easier I’m not storing mac addresses in scripts or variables, I just add disabled ip->arp record.
Script also send e-mail with information about any new ip->arp record made by script.
MAC-ROBOT-v2.0:
#MAC-ROBOT-v2.0 by whale at klub dot lv
#http://whale.klub.lv/
#number of simultaneously monitored ips
:global num
:set num 5
#create 3 empty arrays:
#ip-arp-list contains monitored ips
#hours-list contain number of hours corresponding ip been monitored
#hours-list check contain algorithm stage 3.1 good ips
#note, macs are not stored in variables, they are stored in ip->arp disabled records
:global ip-arp-list
:if ($ip-arp-list = "") do={ :set ip-arp-list (0)
:for n from=2 to=$num do={
:set ip-arp-list ($ip-arp-list . ",0")
}
}
:global hours-list
:if ($hours-list = "") do={ :set hours-list (0)
:for n from=2 to=$num do={
:set hours-list ($hours-list . ",0")
}
}
:global hours-list-check
:set hours-list-check ($hours-list)
:global day2-list
:if ($day2-list = "") do={ :set day2-list (0)
:for n from=2 to=$num do={
:set day2-list ($day2-list . ",0")
}
}
#let's make all the checks for every monitored ip
:for n from=1 to=$num do={
#1-arp-ip contain ip number "n" from array ip-arp-list
:local 1-arp-ip
:local count
:set count 1
:foreach k in $ip-arp-list do={
:if ($count = $n) do={:set 1-arp-ip $k}
:set count ($count+1)
}
#1-hours contain number of hours this ip been monitored
:local 1-hours
:set count 1
:foreach k in $hours-list do={
:if ($count = $n) do={:set 1-hours $k}
:set count ($count+1)
}
#1-day2 contain mark for good ip (algorithm stage 3.1)
:local 1-day2
:set count 1
:foreach k in $day2-list do={
:if ($count = $n) do={:set 1-day2 $k}
:set count ($count+1)
}
#if first ip not monitored let's monitor it!
:if ($1-arp-ip = "0") do={
:local iaddr
:local imac
:local stop
:local stop2
:set stop 0
#load whitelist and blacklist in environment
/system script run dynarp-statarp-robot-blacklist
#search for all dynamic macs
:foreach a in [/ip arp find dynamic=yes DHCP=no] do={
#still has no candidate for monitoring
:if ($stop = 0) do={
:set stop2 0
#get first dynamic mac and ip in variables
:set iaddr [/ip arp get $a address]
:set imac [/ip arp get $a mac-address]
#make sure ip not monitored already or in black/whitelists
:foreach b in ($ip-arp-list . "," . $mac-blacklist . "," . $mac-whitelist) do={
:if ($iaddr = $b) do={:set stop2 1}
}
:if (($stop = 0) && ($stop2 = 0) && ([/ip arp find address=$iaddr dynamic=no disabled=yes] != "") && ((a . $imac) != a)) do={
:set 1-arp-ip $iaddr
/ip arp set [/ip arp find address=$iaddr dynamic=no disabled=yes] mac-address=$imac
#if you want to know what ip is monitored uncomment following line
# /tool e-mail send to=a@b.c subject=($iaddr . " IS BEING MONITORED") body=("ip" . $iaddr . " was seen with this MAC " . [/ip arp get [/ip arp find address=$iaddr dynamic=no disabled=yes] mac-address])
:set stop 1
}
}}
#if this ip is monitored already, then let's make some MAC checks
} else={
#+1 hour to monitored time
:set 1-hours ($1-hours+1)
#if we haven't seen any mac fot this ip in second day or in third day, then cancel monitoring
:if (($1-hours >= 48) && ($1-day2 != 1)) do={
:set 1-arp-ip "0"
:set 1-hours "0"
:set 1-day2 "0"
}
:if ($1-hours > 72) do={
:set 1-arp-ip "0"
:set 1-hours "0"
:set 1-day2 "0"
}
:if ($1-arp-ip != "0") do={
:local imac-d
:local imac-s
:local imac-num
:set imac-num [/ip arp find address=$1-arp-ip dynamic=yes]
:if ($imac-num != "") do={
:set imac-d [/ip arp get $imac-num mac-address]
:set imac-s [/ip arp get [/ip arp find address=$1-arp-ip dynamic=no disabled=yes] mac-address]
#if mac stored in ip->arp disabled record is the same as we see now, then...
:if ($imac-d = $imac-s) do={
#...if it is second day of monitoring make the good ip mark
:if (($1-hours >= 24) && ($1-hours < 48)) do={
:set 1-day2 1
}
#...if it is third day make ip dependent on the MAC in ip->arp and inform someone by e-mail
:if (($1-hours >= 48) && ($1-hours < 72)) do={
/ip arp enable [/ip arp find address=$1-arp-ip dynamic=no disabled=yes]
/tool e-mail send to=a@b.c subject=($1-arp-ip . " depends on MAC" . "-" . $n) body=($1-arp-ip . " depends on MAC " . $imac-s)
:set 1-arp-ip "0"
:set 1-hours "0"
:set 1-day2 "0"
}
#if new mac is not the same as we seen earlier, then add it to blacklist
} else={
/system script set dynarp-statarp-robot-blacklist source=([/system script get dynarp-statarp-robot-blacklist source] . , . $1-arp-ip)
:set 1-arp-ip "0"
:set 1-hours "0"
:set 1-day2 "0"
}
}
}
}
#save all arrays with new data
:local temp
:set count 1
:foreach k in $ip-arp-list do={
:if ($count = 1) do={:if ($n = $count) do={:set temp $1-arp-ip} else={:set temp $k}}
:if ($count != 1) do={:if ($n = $count) do={:set temp ($temp . "," . $1-arp-ip)} else={:set temp ($temp . "," . $k)}}
:set count ($count+1)
}
:set ip-arp-list ($temp)
:set count 1
:foreach k in $hours-list do={
:if ($count = 1) do={:if ($n = $count) do={:set temp $1-hours} else={:set temp $k}}
:if ($count != 1) do={:if ($n = $count) do={:set temp ($temp . "," . $1-hours)} else={:set temp ($temp . "," . $k)}}
:set count ($count+1)
}
:set hours-list ($temp)
:set count 1
:foreach k in $day2-list do={
:if ($count = 1) do={:if ($n = $count) do={:set temp $1-day2} else={:set temp $k}}
:if ($count != 1) do={:if ($n = $count) do={:set temp ($temp . "," . $1-day2)} else={:set temp ($temp . "," . $k)}}
:set count ($count+1)
}
:set day2-list ($temp)
}
MAC-ROBOT-BLACKLIST-v2.0:
#whitelisted ips not monitored and can be with dynamic mac forever
#blacklisted ips were monitored, then they have changed mac and now they are not monitored (ips dynamically added here by script)
:global mac-blacklist
:global mac-whitelist
:set mac-whitelist 1.1.1.1,2.2.2.2
:set mac-blacklist 1.1.1.1
So this is the script for RouterOS 2.8, but it should not take much time to rewrite it for v3 or v4.