This is very easy with scripts. Add the visiting IP to a collections list. set a time-out on those detected IP for lets say 15 minutes on the list.
Then an other script goes regularly trough the list and takes the first IP in the list. Then it counts how many that IP converted to .0/24 is found in that list. If it counts for example three times you can add that .0/24 range to the block-list.
Then remove all IP in that range and repeat with the next IP in the detected list till you reach the end.
You can keep those blocked ones permanently or let those time-out after a few days.
You need so only one script.
Example for in Script:
## change to address-lists
{
/ip firewall address-list
# define empty array
:local arrayRange [:toarray ""]
:local arrayRange2list [:toarray ""]
:local arrayRange24 [:toarray ""]
# fill array
:foreach k,b in=[find where list="detectedTCP"] do={
:set $IPAddress [get value-name=address number=$b]
:set ($arrayRange->$k) $IPAddress;
:set ($arrayRange24->$k) (($IPAddress&255.255.255.0)."/24");
}; # foreach
## Loops through the address-list in the array till all entries are handled
:foreach a,IP2check in=$arrayRange24 do={
## resets the used variable in the foreach loop
:local countRange 0;
:set $rangeComment;
:set $numberOffFields (([:len $arrayRange24]) - $a);
:foreach g in=$arrayRange2list do={:if ($g = $IP2check) do={:set $countRange 499}};
:for b from=$a to=$numberOffFields do={ :if (($arrayRange24->$b) = $IP2check) do={ :set countRange ($countRange + 1) };
# three hits, promotes to bloklist
:if (($countRange = 3) && (($arrayRange24->$b) = $IP2check)) do={
:set $arrayRange2list ($arrayRange2list, ($arrayRange24->$b));
:foreach r in=$arrayRange do={:if ($r in $IP2check) do={:set $rangeComment ($rangeComment."$r ")}};
:do {add address=($arrayRange24->$b) list=perm24Block comment=$rangeComment} on-error={};
:log warning "$IP2check range added to perm2Block"
}; # if
}; # for
}; # foreach
## remove detected matching when adding to the perm24block
:foreach g in=$arrayRange2list do={remove [find where list=detectedTCP && address in $g]};
## Clean-up used arrays
#:set arrayRange
#:set arrayRange2list
#:set arrayRange24
}
This script can be still running while you schedule a other run so in scheduler an other script is checking first if the previous one is still running.
Schedule:
## Check if this this script is already running
/system script job
:foreach b in=[find where script="checkRange"] do={:log warning "script checkRange already executed"; error Script is already running; };
/system script run checkRange