Script to limit according to number of packets

Hi,

I have tried to compile a script that would monitor the total number of packets according to individual IP’s and block those IP’s in the firewall.
I still have to add a line to reset the queue counters after the script has run, however the beginnings of the script is below, I have tried to run this script and it doesn’t work.
This is my first script, so please feel free to tell me what I am doing wrong.

:global interval;
:global threshold;
:set interval 10;
:set threshold 2000;

:local recipients {“user@example.com”}

:local subject “Subject of Message”

:for i from=1 to=254 do={
:if ([/queue simple find target-addresses=(“192.168.1.” . $i)] != “”) do={
:set pack [get [find target-addresses=(“192.168.1.” . $i)] packets]
:if ($pack / $interval > $threshold) do={
/ip firewall filter add action=reject chain=forward src-address=(“192.168.1.” . $i) disabled=yes
:foreach r in=[:toarray $recipients] do={
:put ("Sending email to " . [:tostr $r])
/tool e-mail send from=“mikrotik@scottnet.co.za” server=“196.41.123.125” to=[:tostr $r] subject=[:tostr $subject] body=“Body of Message”
}
}
}
}

To troubleshoot a script, I start by enclosing the whole script in brackets and pasting into the terminal (right-click, paste). This allows you to use local variables and also see errors in the script. These brackets can be removed when script is ready for production:

{
script...
....
}

I re-worked the script a bit. Instead of looping through all 254 IP addresses, it finds all simple queues that contain 192.168.1 and then checks packet totals.

One note on target-addresses: Because there can be multiple ones, the addresses are returned as an array. The script assumes that there is only one target-address per queue, and it is converted to a string. If queues have multiple addresses, the script will need to be changed.

:local interval 10;
:local threshold 2000;

:local recipients {"user@example.com"}

/queue simple
# find simple queues that contain base IP
:foreach i in=[find target-addresses~"192.168.1"] do={
# convert target-addresses array to a string
  :local ip [:tostr [get $i target-addresses]]
  :local packets [get $i total-packets]
  :if ($packets / $interval > $threshold) do={
   /ip firewall filter add action=reject chain=forward src-address=$ip disabled=no
   :foreach j in=$recipients do={
      :put ("Sending email to " . $j)
      /tool e-mail send ...
    }
  }
}

HTH

~ is regex, so escape accordingly:

[find target-addresses~"^192\\.168\\.1\\."]

Also be aware that syntax has changed for RouterOS 6 (at least in 6.19):

[find target~"^192\\.168\\.1\\."]

Thanks for the help skot, I will use your way of testing scripts in future, will certainly be better.
Thanks for the advice on target-addresses as well.
I like the way the re-worked script is, however there are certain queues that I don’t want to be part of this. Is there a way to exclude some queues in the re-worked script, or would it be better to try another way of achieving the same goal?
I was going to use :for from= to= to achieve this as the queues I want to skip are 192.168.1.1 and 192.168.1.200-254

Use comments and filter with that:

[find comment="ThisOne"]

or combine:

[find target-addresses~"^192\\.168\\.1\\." comment="ThisOne"]

of course you can use name as well:

[find name~"contain this text"]

Thanks psamsig, I will give that a try and see which works better.

Ah, ok… in that case your original plan was probably better! :slight_smile:

Something like this would loop through by numbers and do the same checking:

:local interval 10;
:local threshold 2000;

:local recipients {"user@example.com"}

/queue simple
:for i from=2 to=199 do={
  :local search [find target-addresses=("192.168.1." . $i . "/32")]
  :if ($search != "") do={
    :local id $search
    :local ip [:tostr [get $id target-addresses]]
    :local packets [get $id total-packets]
    :if ($packets / $interval > $threshold) do={
      /ip firewall filter add action=reject chain=forward src-address=$ip disabled=no
      :foreach j in=$recipients do={
        :put ("Sending email to " . $j)
        /tool e-mail send ...
      }
    }
  }
}

HTH

Hi skot,

Just to say thanks, I have tested the script, and got it to work.
I did have to make one change though, target-addresses needed to be target.

:local search [find target-addresses=("192.168.1." . $i . "/32")]
  :if ($search != "") do={
    :local id $search
    :local ip [:tostr [get $id target-addresses]]

Thanks for the help from both you and psamsig.