Community discussions

MikroTik App
 
User avatar
janisk
MikroTik Support
MikroTik Support
Topic Author
Posts: 6263
Joined: Tue Feb 14, 2006 9:46 am
Location: Riga, Latvia

Useful scripts

Wed Mar 31, 2010 8:43 am

I will try to get all the useful links to threads to look at when some script is needed, that is not yet in wiki or is in wiki, just to get them not buried under loads other posts.

Check time of the post, to make some link to RouterOS version these where created for.
 
namo
Long time Member
Long time Member
Posts: 530
Joined: Sat Oct 03, 2009 4:44 pm

Re: Useful scripts

Tue Dec 14, 2010 5:10 am

thank you janisk. It also useful to mention the RouterOS version that the script work with because sometimes I found old scripts for v2.9 and they don't work with v4.14
 
User avatar
janisk
MikroTik Support
MikroTik Support
Topic Author
Posts: 6263
Joined: Tue Feb 14, 2006 9:46 am
Location: Riga, Latvia

Re: Useful scripts

Thu Jan 05, 2012 12:26 pm

in that case take CLI script editor (inside RouterOS) and edit script in there. Most of the syntax changes can be caught using that. F5 to refresh highlighting.
 
angboontiong
Forum Guru
Forum Guru
Posts: 1136
Joined: Fri Jan 16, 2009 9:59 am

Re: Useful scripts

Sat Mar 17, 2012 1:42 pm

in that case take CLI script editor (inside RouterOS) and edit script in there. Most of the syntax changes can be caught using that. F5 to refresh highlighting.
all version have this editor?
where it's located?

thanks.
 
User avatar
janisk
MikroTik Support
MikroTik Support
Topic Author
Posts: 6263
Joined: Tue Feb 14, 2006 9:46 am
Location: Riga, Latvia

Re: Useful scripts

Wed Mar 28, 2012 10:20 am

all RouterOS have this.
in CLI - /system script edit <script-name> source
 
Nima1394
just joined
Posts: 1
Joined: Tue Jun 19, 2012 12:10 pm

Re: The Scrip does not work!

Tue Jun 19, 2012 12:33 pm

Hi guys
Why the scrip does not work?!
set[/ip route find dst 0.0.0.0] gateway 10.0.0.1
this command mentioned in wiki.mikrotik:
http://wiki.mikrotik.com/wiki/Manual:Tools/Netwatch
after enter the command, notting happen and the default route doesn't change.
I want to write a script to change the default route gateway.
 
rdc
just joined
Posts: 10
Joined: Wed Jan 09, 2013 3:40 am

Re: Useful scripts

Wed Jan 09, 2013 12:50 pm

I don't know where to post this but this is by far the best place to post it. Basically what the script does is that it will check for dynamic leases on my dhcp server, take their mac addresses and check it against firewall filter. If it's not there it will add it and drop everything that's coming from those mac addresses. I'm using this to prevent users from using my internet bandwidth without prior permission and they just happen to know my wireless key from a colleague.

The script below is tested to work on 2.9.x:
:foreach i in=[/ip dhcp-server lease find dynamic=yes] do={
   :set dynamicMAC [/ip dhcp-server lease get $i mac-address];
   :set dynamicHOST [/ip dhcp-server lease get $i host-name];
   :set macfound [/ip firewall filter find src-mac-address=$dynamicMAC];

    :if ($macfound != "") do={
        :log info ($dynamicMAC. " already filtered")
    } else= {
        /ip firewall filter add chain=forward src-mac-address=$dynamicMAC action=drop comment=($dynamicHOST . " - " . $dynamicMAC . " Unregistered device")
        :log info ("Added " . $dynamicMAC. " to firewall filter")
    }
}
The code below is tested to work on 5.19:
:foreach i in=[/ip dhcp-server lease find dynamic] do={
   :local dynamicMAC [/ip dhcp-server lease get $i mac-address];
   :local dynamicHOST [/ip dhcp-server lease get $i host-name];
   :local macfound [/ip firewall filter find src-mac-address=$dynamicMAC];

    :if ($macfound != "") do={
        :log info ($dynamicMAC. " already filtered")
    } else= {
        /ip firewall filter add chain=forward src-mac-address=$dynamicMAC action=drop comment=($dynamicHOST . " - " . $dynamicMAC . " Unregistered device")
        :log info ("Added " . $dynamicMAC. " to firewall filter")
    }
}
Good luck!
 
solelunauno
Member Candidate
Member Candidate
Posts: 120
Joined: Mon Jul 16, 2012 7:00 pm
Location: Roseto Capo Spulico CS Italy
Contact:

backup to FTP with sd-card

Fri Aug 23, 2013 12:55 pm

Hallo,
i made this simple script in order to backup daily the router settings and usermanager database, using sd-card as buffer in order to reduce router nand's use.
It is especially useful when yuo plan to enlarge usermanager database until gigabyte size, making backup into router's nand not more possible.
I'll write also another script to "rebuild" database and logs every week, to reduce backup's size.
This script will erase always the same two files, in order to have always the last good version in ftp.

#automated System
:log info message=System_Export_started;
:local exportname ([/system identity get name].".rsc");
:local UMname ([/system identity get name].".umb");
export compact file=micro-sd/exportSy.rsc;
/tool user-manager database save name=micro-sd/backupUM.umb;
:log info message=System_Export_finished;
# Upload the System Backup to External FTP;
/tool fetch address=192.168.1.1 port=21 src-path=micro-sd/exportSy.rsc upload=yes \
user=FTPuser mode=ftp password="FTPpassword" dst-path=$exportname;
/tool fetch address=192.168.1.1 port=21 src-path=micro-sd/backupUM.umb upload=yes \
user=FTPuser mode=ftp password="FTPpassword" dst-path=$UMname;
/file remove micro-sd/backupUM.umb;
/file remove micro-sd/exportSy.rsc;
:log info message=System_Export_uploaded;

where you have to put your ftp server address instead of "192.168.1.1" and your FTP user and password.
I take inspiration from this post: http://forum.mikrotik.com/viewtopic.php?f=9&t=52371 and I hope it will be useful for someone. :D
It works with RouterOS 6.2 .
 
nurmia
newbie
Posts: 28
Joined: Thu Oct 03, 2013 4:34 pm

Re: Useful scripts

Sun Nov 10, 2013 10:50 am

thank you janisk for good info. your post is very helpful for me.
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 12379
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Useful scripts

Wed Mar 19, 2014 10:25 pm

I open another thread for my script:

Check locked PPPOE, PPTP, L2TP, SSTP, OVPN, and PPP connections

http://forum.mikrotik.com/viewtopic.php?f=9&t=83132
Last edited by rextended on Mon Mar 20, 2023 6:31 pm, edited 3 times in total.
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 12379
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Useful scripts

Tue Mar 25, 2014 11:13 pm

I open another thread for my script:

How to ***really*** block invalid TCP and UDP packet

http://forum.mikrotik.com/viewtopic.php?f=9&t=83387
Last edited by rextended on Mon Mar 20, 2023 6:31 pm, edited 1 time in total.
 
User avatar
cdiedrich
Forum Veteran
Forum Veteran
Posts: 997
Joined: Thu Feb 13, 2014 2:03 pm
Location: Basel, Switzerland // Bremen, Germany
Contact:

Re: Useful scripts

Tue Apr 29, 2014 11:26 am

Here's one I just wrote to centrally push new (beta) firmwares to our CAPsMAN managed Wireless system in a batch:

ros code

/system script
add name=pushupdate policy=ftp,read,write,policy,test,winbox,password,sniff,sensitive,api source="
:foreach i in=[/ip firewall address-list find list=accesspoints] do={
[/tool fetch  address=[/ip firewall address-list  get $i address] mode=ftp user=login password=password src-path=updates/wireless-fp-6.13rc7-mipsbe.npk dst-path=wireless-fp-6.13rc7-mipsbe.npk upload=yes];
[/tool fetch  address=[/ip firewall address-list  get $i address] mode=ftp user=login password=password src-path=updates/routeros-mipsbe-6.13rc7.npk dst-path=routeros-mipsbe-6.13rc7.npk upload=yes];
[/tool fetch  address=[/ip firewall address-list  get $i address] mode=ftp user=login password=password src-path=updates/reboot.rsc dst-path=reboot.auto.rsc upload=yes];
}
I have all the Access Points in the address list "accesspoints".
The filenames are hard coded on purpose to keep an eye on the versions.

The reboot.rsc script looks like this:

ros code

:file remove reboot.auto.rsc
:log warning "Firmware upgrade initiated"
:delay 1s
:system reboot
...(Warnings and errors are logged to disk, everything else to memory only, this is why I issue a warning).

In case anything goes wrong, I have a downgrade script with 6.12 in place as well.
The reboot script then invokes /system package downgrade instead of reboot.

Maybe this is helpful for someone.

Cheers
-Chris
 
plisken
Forum Guru
Forum Guru
Posts: 2511
Joined: Sun May 15, 2011 12:24 am
Location: Belgium
Contact:

Re: Useful scripts

Sat May 10, 2014 1:04 pm

Where and how set you a list with registered users?

I don't know where to post this but this is by far the best place to post it. Basically what the script does is that it will check for dynamic leases on my dhcp server, take their mac addresses and check it against firewall filter. If it's not there it will add it and drop everything that's coming from those mac addresses. I'm using this to prevent users from using my internet bandwidth without prior permission and they just happen to know my wireless key from a colleague.

The script below is tested to work on 2.9.x:
:foreach i in=[/ip dhcp-server lease find dynamic=yes] do={
   :set dynamicMAC [/ip dhcp-server lease get $i mac-address];
   :set dynamicHOST [/ip dhcp-server lease get $i host-name];
   :set macfound [/ip firewall filter find src-mac-address=$dynamicMAC];

    :if ($macfound != "") do={
        :log info ($dynamicMAC. " already filtered")
    } else= {
        /ip firewall filter add chain=forward src-mac-address=$dynamicMAC action=drop comment=($dynamicHOST . " - " . $dynamicMAC . " Unregistered device")
        :log info ("Added " . $dynamicMAC. " to firewall filter")
    }
}
The code below is tested to work on 5.19:
:foreach i in=[/ip dhcp-server lease find dynamic] do={
   :local dynamicMAC [/ip dhcp-server lease get $i mac-address];
   :local dynamicHOST [/ip dhcp-server lease get $i host-name];
   :local macfound [/ip firewall filter find src-mac-address=$dynamicMAC];

    :if ($macfound != "") do={
        :log info ($dynamicMAC. " already filtered")
    } else= {
        /ip firewall filter add chain=forward src-mac-address=$dynamicMAC action=drop comment=($dynamicHOST . " - " . $dynamicMAC . " Unregistered device")
        :log info ("Added " . $dynamicMAC. " to firewall filter")
    }
}
Good luck!
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 12379
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Useful scripts

Sat May 10, 2014 5:00 pm

Add manually the devices on DHCP leases...
 
IntrusDave
Forum Guru
Forum Guru
Posts: 1286
Joined: Fri May 09, 2014 4:36 am
Location: Rancho Cucamonga, CA

Re: Useful scripts

Fri Jul 24, 2015 10:41 am

Script to download a current address-list to blacklist known botnets, spammers, scammers and C&C servers.
http://forum.mikrotik.com/viewtopic.php?f=9&t=98804
 
User avatar
Cha0s
Forum Guru
Forum Guru
Posts: 1158
Joined: Tue Oct 11, 2005 4:53 pm

Re: Useful scripts

Thu Aug 13, 2015 7:00 pm

Script to send notifications to multiple email addresses for multiple BGP Peers if their status is not 'established'
http://forum.mikrotik.com/viewtopic.php ... 04#p494204
 
gammy69er
Frequent Visitor
Frequent Visitor
Posts: 86
Joined: Sun May 18, 2014 3:01 am

Re: Useful scripts

Fri Aug 14, 2015 7:16 am

have Just added a Script for Hotspot Data Limit

http://forum.mikrotik.com/viewtopic.php?f=9&t=99515

Sets Data Limit On Login - no scripted monitoring required - and disconnects once data is used
 
User avatar
favincen
just joined
Posts: 21
Joined: Mon Jun 08, 2015 1:56 pm
Location: Grenoble, France

Re: Useful scripts

Fri Aug 28, 2015 2:00 pm

all RouterOS have this.
in CLI - /system script edit <script-name> source
Beware that this won't work if your script is above 4Kb ! (See this post ).
So it only works for small script... :evil:
 
jfrawley
just joined
Posts: 3
Joined: Sun Jan 10, 2016 9:16 pm

Re: Useful scripts

Sun Jan 10, 2016 9:26 pm

Looking to edit my Voltage report script I have been using, currently it is set to send email of report daily at 11pm, I am trying to change to 8am but I have been getting negative hour results such as -1 -2 -3 etc. I made two changes and am going to see what happens tomorrow but if you know of simple way to fix please let me know- below is the script I been using from the site (2 scripts). I am not script smart but am trying to figure some of this out, just would like reports at 8am rather than 11pm

# I changed a line below from 23 - $x to 08 + $x in hopes to get positive numbers
:global highvolt
:global lowvolt
:global hivolttime
:global lovolttime
:global starttime
:global vh
:local tvolt
:local thisbox [/system identity get name]
:local thisdate [/system clock get date]
:local thishour
:local emessage "Daily voltage report for $thisbox on $thisdate\n\n"
:if ([:len $vh] > 0) do={
:for x from=0 to=([:len $vh]-1) step=1 do={
:set tvolt [:tostr [:pick $vh $x]]
:set thishour [:tostr (08 + $x)]
:while ([:len $thishour] < 2) do={:set thishour ("0" . $thishour)}
:set emessage ($emessage . $thishour . ":00 = " . [:pick $tvolt 0 2] . "." . [:pick $tvolt 2 3] . "\n")
}
:set emessage ($emessage . "\nSince voltmonitor started on " . $starttime . "\n")
:set tvolt [:tostr $highvolt]
:set emessage ($emessage . "Maximum = " . [:pick $tvolt 0 2] . "." . [:pick $tvolt 2 3] . "v at " . $hivolttime . "\n")
:set tvolt [:tostr $lowvolt]
:set emessage ($emessage . "Minimum = " . [:pick $tvolt 0 2] . "." . [:pick $tvolt 2 3] . "v at " . $lovolttime . "\n")
# set email address in next line
/tool e-mail send to="myemail" subject="$thisbox Voltage Report" body=$emessage}

# remark out the next line for testing to avoid resetting the voltage array
:set vh


##########################################################################
Volt monitor script-
# I changed the line below for when to run the report script from thishour 23 to thishour 08

#set lowvoltalarm to desired alarm voltage in tenths of a volt. 118 = 11.8v # the +015 is for volt offset of real volts
:global lowvoltalarm 225
:global highvolt
:global lowvolt
:global starttime
:global hivolttime
:global lovolttime
:global vh
:local thisbox [/system identity get name]
:global voltage ([/system health get voltage] + 015)
:local thistime [/system clock get time]
:local thisdate [/system clock get date]
:local thishour [:pick $thistime 0 2]
:local emessage ($thisbox . " voltage is " . [:pick $voltage 0 2] . "." . [:pick $voltage 2 3])
:if ([:len $lowvolt] < 1) do={:set lowvolt 999; :set highvolt 0}
:if ($voltage <= $lowvoltalarm) do={/tool e-mail send to="mycelltext" subject="$thisbox low voltage" body=$emessage}
:if ($voltage <= $lowvoltalarm) do={/tool e-mail send to="hiscelltext" subject="$thisbox low voltage" body=$emessage}
:if ($voltage > $highvolt) do={:set highvolt $voltage; :set hivolttime ($thistime . " " . $thisdate)}
:if ($voltage < $lowvolt) do={:set lowvolt $voltage; :set lovolttime ($thistime . " " . $thisdate)}
:if ([:len $vh] > 0) do={:set vh ([:toarray $voltage] + $vh)} else={:set vh [:toarray $voltage]}
:if ([:len $starttime] < 1) do={:set starttime ($thistime . " " . $thisdate)}
:if ($thishour = "08") do={:execute voltreport}
 
Trezona
Frequent Visitor
Frequent Visitor
Posts: 63
Joined: Wed Feb 22, 2006 6:34 pm

Re: Useful scripts

Thu Jan 21, 2016 1:08 pm

Hello jfrawley,

Did you get your voltage monitoring script to work on 6.33.5?
I also have a similar votage monitoring script to yours, i have it working great on 6.29,
but i cannot get it to work on any version higher than 6.30...

Here is my script:

#set lowvoltalarm to desired alarm voltage in tenths of a volt. 125 = 12.5v
:global lowvoltalarm 200
:global highvoltalarm 280
:global highvolt
:global lowvolt
:global starttime
:global hivolttime
:global lovolttime
:global vh
:local thisbox [/system identity get name]
:global voltage [/system health get voltage]
:local thistime [/system clock get time]
:local thisdate [/system clock get date]
:local thishour [:pick $thistime 0 2]
:local emessage ($thisbox . " voltage is: " . [:pick $voltage 0 2] . "." . [:pick $voltage 2 3])
:if ([:len $lowvolt] < 1) do={:set lowvolt 999; :set highvolt 0}
# set your email address in the next line
:if ($voltage <= $lowvoltalarm) do={/tool e-mail send to="test@test.com" subject="$thisbox Voltage Statistics" body=$emessage}
:if ($voltage >= $highvoltalarm) do={/tool e-mail send to="test@test.com" subject="$thisbox Voltage Statistics" body=$emessage}
:if ($voltage > $highvolt) do={:set highvolt $voltage; :set hivolttime ($thistime . " " . $thisdate)}
:if ($voltage < $lowvolt) do={:set lowvolt $voltage; :set lovolttime ($thistime . " " . $thisdate)}
:if ([:len $vh] > 0) do={:set vh ([:toarray $voltage] + $vh)} else={:set vh [:toarray $voltage]}
:if ([:len $starttime] < 1) do={:set starttime ($thistime . " " . $thisdate)}
:if ($thishour = "23") do={:execute voltreport}

I run this every 30 minutes.

Could somone one please tell me why this now does not work on all versions higher than 6.30?

Thanks.
 
hamster922
just joined
Posts: 8
Joined: Thu Jul 08, 2010 4:58 pm

Re: Useful scripts

Sat Apr 09, 2016 7:37 pm

Same Problem here, can't get the same script working on 6.30.4

Anyone?
 
drnitinarora
newbie
Posts: 32
Joined: Fri Sep 25, 2009 6:08 pm

Re: Useful scripts

Sun May 15, 2016 1:48 pm

Is there a way we can restrict the Active user sessions in Hotspot?

Eg.
- If we have 100 connected hosts to mikrotik
- If we set active users to 10 , then only 10 active users are allowed to login out of 100 connected hosts at any given time.

Thanks in anticipation
 
alexathinaios
just joined
Posts: 4
Joined: Sat Jun 14, 2014 2:46 am
Contact:

Re: Useful scripts

Thu Jun 30, 2016 11:51 am

Hello there,

Here is mine if you have pppoe client and pptp server on your gateways for sharing internet and your adsl lines needs an eye on them.

http://forum.mikrotik.com/viewtopic.php ... 1fc574e085
 
User avatar
koolandrew
newbie
Posts: 28
Joined: Tue Dec 06, 2011 7:20 pm
Location: Toronto
Contact:

WAN Failover Script using Netwatch

Wed Oct 05, 2016 10:34 pm

Please help me with this script as i spent a crazy amount of time and it still doesnt completely work.
. I have tried so many ways to make this work, and i can get Netwatch to work beautifully when the first route goes down, but it doesnt work when the route comes back up again. I have borrowed from many different forums, the largest part from Steve Discher..

I have tried to change the distance, enable=true, disable=false, enabled=true, enabled=yes, and everything else i could think of but nothing works to make the primary route, the primary route.

/ip firewall filter
add action=drop chain=output comment=\
"Drop pings to 4.2.2.4 if they go through PROVIDER2" dst-address=4.2.2.4 \
out-interface=ether2-gateway
/ip route
add comment=PROVIDER1 distance=1 gateway=192.168.2.1 scope=11
add comment=PROVIDER2 distance=10 gateway=192.168.3.1
add comment="Force test pings through PROVIDER1" distance=1 dst-address=\
4.2.2.4/32 gateway=192.168.2.1

Here is my first netwatch script, it works great until provider 2 starts working, and the distance remains at 20, so it doesnt work, and no emails get sent.

/tool netwatch
add comment=CheckCon down-script="/ip route set [find comment=\"PROVIDER1\"] d\
istance=20\r\
\n/ip route set [find comment=\"PROVIDER2\"] disabled=no\r\
\n/tool e-mail send to=\"andrew.wells@xx.xxx\" body=\"Connection with\
\_PROVIDER1 Lost, Switched to PROVIDER2\" subject=\"Lost connection with P\
ROVIDER1\"\r\
\n/tool e-mail send to=\"andrewwells@xx.xxx\" body=\"Connection with \
PROVIDER1 Lost, Switched to PROVIDER2\" subject=\"Lost connection with PRO\
VIDER1\"\r\
\n:log error \"Primary internet connection down\"\r\
\n/ ip firewall connection remove [/ip firewall connection find dst-addres\
s~\"xx.xxx.137.117:5060\"]" host=4.2.2.4 interval=5s timeout=2s \
up-script="/ip route set [find comment=\"PROVIDER1\"] distance=1\r\
\n/ip route set [find comment=\"PROVIDER2\"] disabled=no\r\
\n/tool e-mail send to=\"andrew.wells@xx.xxx\"\r\
\nbody=\"Connection with PROVIDER1 Regained, Switched back to PROVIDER1\" \
subject=\"Regained connection with PROVIDER1\"\r\
\n/tool e-mail send to=\"andrewwells@xx.xxx\"\r\
\nbody=\"Connection with PROVIDER1 Regained, Switched back to PROVIDER1\" \
subject=\"Regained connection with PROVIDER1\"\r\
\n/ ip firewall connection remove [/ip firewall connection find dst-addres\
s~\"xx.xxx.137.117:5060\"]"

Here is my 80th attempt, with changes to the up script, and i have tried everything i could find on the forums. Now the route remains disabled, and again, no emails go out.

/tool netwatch
add comment=CheckCon down-script="/ip route set [find comment=\"PROVIDER1\"] d\
isabled=yes\r\
\n/ip route set [find comment=\"PROVIDER2\"] disabled=no\r\
\n/tool e-mail send to=\"andrew.wells@xx.xxx\" body=\"Connection with\
\_PROVIDER1 Lost, Switched to PROVIDER2\" subject=\"Lost connection with P\
ROVIDER1\"\r\
\n/tool e-mail send to=\"andrewwells@xx.xxx\" body=\"Connection with \
PROVIDER1 Lost, Switched to PROVIDER2\" subject=\"Lost connection with PRO\
VIDER1\"\r\
\n:log error \"Primary internet connection down\"\r\
\n/ ip firewall connection remove [/ip firewall connection find dst-addres\
s~\"xx.xxx.137.117:5060\"]\r\
\n/ ip firewall connection remove [/ip firewall connection find dst-addres\
s~\"xx.xxx.137.116:5060\"]" host=4.2.2.4 interval=5s timeout=2s \
up-script="/ip route get [find comment=\"PROVIDER1\"] disabled=true\r\
\n/ip route set [find comment=\"PROVIDER1\"] disabled=no\r\
\n/ip route set [find comment=\"PROVIDER2\"] disabled=no\r\
\n/tool e-mail send to=\"andrew.wells@xx.xxx\"\r\
\nbody=\"Connection with PROVIDER1 Regained, Switched back to PROVIDER1\" \
subject=\"Regained connection with PROVIDER1\"\r\
\n/tool e-mail send to=\"andrewwells@xx.xxx\"\r\
\nbody=\"Connection with PROVIDER1 Regained, Switched back to PROVIDER1\" \
subject=\"Regained connection with PROVIDER1\"\r\
\n/ ip firewall connection remove [/ip firewall connection find dst-addres\
s~\"xx.xxx.137.117:5060\"]\r\
\n/ ip firewall connection remove [/ip firewall connection find dst-addres\
s~\"xx.xxx.137.116:5060\"]"
 
fernando1787
just joined
Posts: 9
Joined: Mon Apr 11, 2016 6:32 pm

/ip route add comment=PROVIDER1 distance=1 gateway=192.168.2.1 scope=11 add comment=PROVIDER2 distance=10 gateway=192.16

Wed Jan 25, 2017 11:38 pm

Please help me with this script as i spent a crazy amount of time and it still doesnt completely work.
. I have tried so many ways to make this work, and i can get Netwatch to work beautifully when the first route goes down, but it doesnt work when the route comes back up again. I have borrowed from many different forums, the largest part from Steve Discher..

I have tried to change the distance, enable=true, disable=false, enabled=true, enabled=yes, and everything else i could think of but nothing works to make the primary route, the primary route.

/ip firewall filter
add action=drop chain=output comment=\
"Drop pings to 4.2.2.4 if they go through PROVIDER2" dst-address=4.2.2.4 \
out-interface=ether2-gateway
/ip route
add comment=PROVIDER1 distance=1 gateway=192.168.2.1 scope=11
add comment=PROVIDER2 distance=10 gateway=192.168.3.1
add comment="Force test pings through PROVIDER1" distance=1 dst-address=\
4.2.2.4/32 gateway=192.168.2.1

Here is my first netwatch script, it works great until provider 2 starts working, and the distance remains at 20, so it doesnt work, and no emails get sent.

/tool netwatch
add comment=CheckCon down-script="/ip route set [find comment=\"PROVIDER1\"] d\
istance=20\r\
\n/ip route set [find comment=\"PROVIDER2\"] disabled=no\r\
\n/tool e-mail send to=\"andrew.wells@xx.xxx\" body=\"Connection with\
\_PROVIDER1 Lost, Switched to PROVIDER2\" subject=\"Lost connection with P\
ROVIDER1\"\r\
\n/tool e-mail send to=\"andrewwells@xx.xxx\" body=\"Connection with \
PROVIDER1 Lost, Switched to PROVIDER2\" subject=\"Lost connection with PRO\
VIDER1\"\r\
\n:log error \"Primary internet connection down\"\r\
\n/ ip firewall connection remove [/ip firewall connection find dst-addres\
s~\"xx.xxx.137.117:5060\"]" host=4.2.2.4 interval=5s timeout=2s \
up-script="/ip route set [find comment=\"PROVIDER1\"] distance=1\r\
\n/ip route set [find comment=\"PROVIDER2\"] disabled=no\r\
\n/tool e-mail send to=\"andrew.wells@xx.xxx\"\r\
\nbody=\"Connection with PROVIDER1 Regained, Switched back to PROVIDER1\" \
subject=\"Regained connection with PROVIDER1\"\r\
\n/tool e-mail send to=\"andrewwells@xx.xxx\"\r\
\nbody=\"Connection with PROVIDER1 Regained, Switched back to PROVIDER1\" \
subject=\"Regained connection with PROVIDER1\"\r\
\n/ ip firewall connection remove [/ip firewall connection find dst-addres\
s~\"xx.xxx.137.117:5060\"]"

Here is my 80th attempt, with changes to the up script, and i have tried everything i could find on the forums. Now the route remains disabled, and again, no emails go out.

/tool netwatch
add comment=CheckCon down-script="/ip route set [find comment=\"PROVIDER1\"] d\
isabled=yes\r\
\n/ip route set [find comment=\"PROVIDER2\"] disabled=no\r\
\n/tool e-mail send to=\"andrew.wells@xx.xxx\" body=\"Connection with\
\_PROVIDER1 Lost, Switched to PROVIDER2\" subject=\"Lost connection with P\
ROVIDER1\"\r\
\n/tool e-mail send to=\"andrewwells@xx.xxx\" body=\"Connection with \
PROVIDER1 Lost, Switched to PROVIDER2\" subject=\"Lost connection with PRO\
VIDER1\"\r\
\n:log error \"Primary internet connection down\"\r\
\n/ ip firewall connection remove [/ip firewall connection find dst-addres\
s~\"xx.xxx.137.117:5060\"]\r\
\n/ ip firewall connection remove [/ip firewall connection find dst-addres\
s~\"xx.xxx.137.116:5060\"]" host=4.2.2.4 interval=5s timeout=2s \
up-script="/ip route get [find comment=\"PROVIDER1\"] disabled=true\r\
\n/ip route set [find comment=\"PROVIDER1\"] disabled=no\r\
\n/ip route set [find comment=\"PROVIDER2\"] disabled=no\r\
\n/tool e-mail send to=\"andrew.wells@xx.xxx\"\r\
\nbody=\"Connection with PROVIDER1 Regained, Switched back to PROVIDER1\" \
subject=\"Regained connection with PROVIDER1\"\r\
\n/tool e-mail send to=\"andrewwells@xx.xxx\"\r\
\nbody=\"Connection with PROVIDER1 Regained, Switched back to PROVIDER1\" \
subject=\"Regained connection with PROVIDER1\"\r\
\n/ ip firewall connection remove [/ip firewall connection find dst-addres\
s~\"xx.xxx.137.117:5060\"]\r\
\n/ ip firewall connection remove [/ip firewall connection find dst-addres\
s~\"xx.xxx.137.116:5060\"]"
 
TechDan1
just joined
Posts: 1
Joined: Wed Aug 23, 2017 9:31 am

Re: Useful scripts

Wed Aug 23, 2017 9:34 am

Thank you so much for sharing. I have found so many useful information up there.
 
User avatar
horhay
newbie
Posts: 29
Joined: Sat Jun 20, 2015 7:19 pm
Location: Ontario, Canada
Contact:

Re: Useful scripts

Mon Aug 28, 2017 8:50 pm

Prior to the addition of fasttrack you could remove all firewall filters with
/ip firewall filter
rem [find]
Now that we have fasttrack you must use this
/ip firewall filter
rem [find where !dynamic]
 
CTSsean
Frequent Visitor
Frequent Visitor
Posts: 79
Joined: Fri Sep 15, 2017 12:56 pm

Re: Useful scripts

Sun Nov 05, 2017 8:43 pm

Here are my FreeDNS script for updating a FreeDNS domain, when you have more than 1 FreeDNS domain.
It also posts the start and stop of the script in the log. It was originally created by LESHIY_ODESSA, but I've improved it by adding some error checking and making this work when you have more than 1 FreenDNS domain. Also, instead of checking the wan interface only, I check the ether interface first and then check the web to see what the IP shows.
The only catch 22 is if you force a change of the FreeDNS ip on their site and don't restart your router/update the variable, the router will still have the old value and will never update unless your actual ip changes.

If you are double nat'd, you'll need to modify it to fit that environment.

:log warning ("DNS script begin")
##############    Script FreeDNS.afraid.org   ##################
##############    CREATED LESHIY_ODESSA   ##################
##############    Improved by SEAN SCARFO  ##################
# Specify your domain or subdomain.
:global "dns-domain" "whatever.woot.me"

# Define IP checker website variable.  Any website that returns only the ip address in text format. examples listed
#https://www.trackip.net/ip/
#http://wgetip.com/
#https://api.ipify.org/
#If not pointing to a specific file, must end in a /
# Case sensitive.
:global "wanChecker" "http://wgetip.com/"

#specify your internet interface.  naming does not have to be exact as long as it has "ether" in the name
:global "wanInterface" "ether1"


# Specify the "Direct URL", which is https://freedns.afraid.org/dynamic/
# In front of the sign "?" put a backslash "\".
:global "direct-url" "https://freedns.afraid.org/dynamic/update.php\?98675985876548765486547654jhdf"

# Specify the URL API "ASCII"
# Log in under your account and open the page https://freedns.afraid.org/api/
# Then copy the URL of your site - Available API Interfaces : ASCII (!!! NOT XML !!!)
# ATTENTION!!!! Before the question mark, put a backslash "\".
:global "api-url" "https://freedns.afraid.org/api/\?action=getdyndns&v=2&sha=87587657865hjgfhgfjhgf"


       
# !!!!!!!!!!!!!!!!! Nothing more do not need to edit!!!!!!!!!!!!!!!!!
:global "current-ip"
:global "dns-domain-ip"
:if ([:len $"current-ip"] <7) do={
    :log error ("current-ip variable has no value, setting it to 1.1.1.1");
    :global "current-ip" 1.1.1.1;
} else={
    :log warning ("current IP variable exists and has a value")
#pause for 1 seconds
:delay 1

#Fetch Current IP from ether1
:global "current-ip" [/ip address get value-name=address [find interface~$"wanInterface"]]
:global "current-ip-endloc" ([:len $"current-ip"] -3)
:global "current-ip" [:pick $"current-ip" 0 $"current-ip-endloc"]

# Compare global IP variables
# Compare the external IP with the IP address of the DNS domain.
    :if ($"current-ip" = $"dns-domain-ip") do={
    :log warning ("current-ip matches dns-domain-ip, script is done!")
    } else={
#pause for 1 seconds
:delay 1

	:log error ("$"current-ip" does not match $"dns-domain-ip", updating IP FreeDNS")
#pause for 1 seconds
:delay 1

#Fetch Last Known IP info from WanChecker       
    /tool fetch url="$wanChecker" dst-path="/wanCheckerfile.txt"
#pause for 1 seconds
:delay 1

# Find the current IP address on the external interface
    :global "current-ip" [/file get wanCheckerfile.txt contents]
#pause for 1 seconds
:delay 1
	
#Fetch Last Known IP info from FreeDNS       
    /tool fetch url=$"api-url" dst-path="/freedns.txt"
#pause for 1 seconds
:delay 1

# Find out the IP address of the domain using the API and parsing.
# Split the file
    :local "result" [/file get freedns.txt contents]
    :local "startloc" ([:find $result $"dns-domain"] + [:len $"dns-domain"] + 1)
    :local "endloc" ([:find $"result" "https" [:find $result $"dns-domain"]] -1)
    :global "dns-domain-ip" [:pick $"result" $"startloc" $"endloc"]
#pause for 1 seconds
:delay 1

# Compare global IP variables
# Compare the external IP with the IP address of the DNS domain.
    :if ($"current-ip" = $"dns-domain-ip") do={
    :log warning ("current-ip matches dns-domain-ip, script is done!")
    } else={
#pause for 1 seconds
:delay 1

# Send new IP to freedns.afraid.org our external IP by using Direct URL
    :log error ("Service Dynamic DNS: old IP address $"dns-domain-ip" for $"dns-domain" CHANGED to -> $"current-ip"")
    /tool fetch mode=https url=$"direct-url" keep-result=no
    }
}
}
:log warning ("DNS script end")
 
icosasupport
newbie
Posts: 29
Joined: Fri Oct 13, 2017 8:37 pm

Re: Useful scripts

Wed Nov 08, 2017 6:57 pm

Hi all,

Here's a script to convert strings to upper or lower

To call it simply reference the function in your code and call it:
:local replace [:parse [:system script get replace-upper-lower source]]
:set $var [$replace "convert me to upper" ] 
OR
:set $var [$replace "CONVERT ME TO LOWER" 1 ]
Just call this script 'replace-upper-lower'
:local lower [:toarray "a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z"]
:local upper [:toarray "A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z"]
# Pass as param 2 to toggle conversion
:local mode false
:local result
:if (($2 = "") || ($2 = nil)) do={:set $mode true}
:for idx from=0 to=([:len $1] - 1) do={ 
	:local char [:pick $1 $idx]
	:local match
	:if ($mode) do={
		:for i from=0 to=[:len $lower] do={
			:set $match ($lower->$i)
			:if ($char = $match) do={:set $char ($upper->$i)}
		}
	} else={
		:for i from=0 to=[:len $upper] do={
			:set $match ($upper->$i)
			:if ($char = $match) do={:set $char ($lower->$i)}
		}
	}
	:set $result ($result.$char)
}
:return $result
 
icosasupport
newbie
Posts: 29
Joined: Fri Oct 13, 2017 8:37 pm

Re: Useful scripts

Wed Nov 08, 2017 7:22 pm

Hey all,

Here's a script that reads a "config" file, parses it as a key:value pair and returns an array of key:value pairs with the K:V pair as an array also.
Each line of the config file represents the index value of the main array, and then each key:value pair in the array can be indexed as position zero OR position one.
This is really useful if you need your scripts to be dynamic without have to hard code certain parameters into the script itself.
We use this method so that if the config file gets replaced with updated values, the script will still function without editing it.

Sample usage:
1. Create the config file and save it to the router (example below) you can only create and use .txt files
[I do realize that the filename can have any extension. However if you use the router file commands to create the file then it will give it the extension of .TXT by default]
2. Put one key:value pair on each line, the default delimiter is : however the second parameter of the function will let you use a custom delimiter.
3. On the last line of the config file you need to have a CRLF as the termination (Note: a carriage return not the letters CRLF)
4. Reference your config file as the first parameter of the function, you can omit the .txt extension if you want

E.G monitor-api.txt file :
user:api
pass:api
protocol:https://
server:monitor.domain.local
url:/api/v0/devices
[CRLF]

In this example the :pick statement reads the value from the index of the array ($config->0) at position zero, and picks the second value in that array.
In this case we just want the username and password values, not the the key name. There are other times when both values are needed,
then it's a simple matter of picking position zero for the key and position one for the value.
:local keyfile [:parse [:system script get read-keyfile source]]
:local config [$keyfile "monitor-api" ":"]
:local user [:pick ($config->0) 1]
:local password [:pick ($config->1) 1]
..... More logic here.....
Create the script as read-keyfile
:local filename $1
:local delimiter $2
:local result {nil}
:local aidx 0
:local eof -1
:local eol 0
:local idx 0
:local line
:local cfgfile
:do {
	:if (($delimiter = "") || ($delimiter = nil)) do={:set $delimiter ":"}
	:if ([:file find name=$filename] != "") do={
		:set $cfgfile [:file get [:file find name=$filename] contents]
	}
	:if ([:len $cfgfile] < 1) do={
		:set $cfgfile [:file get [:file find name=($filename.".txt")] contents]
	}
	:if ([:len $cfgfile] < 1) do={:return {1,1}}
	:set $eof [:len $cfgfile]
	:do {
		:set $eol ([:find $cfgfile "\r"]);
		:if ( ($eol=0)||($eol=nil) ) do={:set $eol ([:find $cfgfile "\n"])}
		:if ( ($eol=0)||($eol=nil) ) do={:set $eol $eof}
		:set $line [:pick $cfgfile 0 $eol]
		:if ([:len $line] > 1) do={
			:set $idx [:find $line $delimiter]
			:set ($result->$aidx) {[:pick $line 0 ($idx)];[:pick $line ($idx+1) $eol]}
			:set $aidx ($aidx + 1);
		}
		:set $cfgfile [:pick $cfgfile ($eol +2) $eof]
		:set $eof ($eof - $eol);
	} while=($eol > 0)
} on-error={:log error "Could not read configuration file $filename"}
:return $result
Last edited by icosasupport on Thu Nov 23, 2017 4:26 am, edited 6 times in total.
 
icosasupport
newbie
Posts: 29
Joined: Fri Oct 13, 2017 8:37 pm

Re: Useful scripts

Wed Nov 08, 2017 7:31 pm

Hey all,

Here's a simple function that will replace a single character in a string of text with another

To call the function simply reference it in your code.
The first parameter is the string to replace a character in
Parameter 2 is the character to find
Parameter 3 is the "replacement" character
:local replace [:parse [:system script get replace-char source]]
:local hostname [$replace ([:system identity get name]) " " "-"]
Create the script as replace-char
:local match $2
:local replace $3
:local result
:for i from=0 to=([:len $1] - 1) do={ 
	:local char [:pick $1 $i]
	:if ($char = $match) do={:set $char $replace}
	:set $result ($result.$char)
}
:return $result
Last edited by icosasupport on Wed Nov 08, 2017 8:37 pm, edited 1 time in total.
 
icosasupport
newbie
Posts: 29
Joined: Fri Oct 13, 2017 8:37 pm

Re: Useful scripts

Wed Nov 08, 2017 8:05 pm

Hey all,

Here's an advanced function that will add a device to Observium http://docs.observium.org/api/#adding-a-device via the REST API call. You do however need the licensed version to use the API calls. This has not been fully tested in the latest version! (17.9.xxx) so some adjustments may have to be made, since the dev team @observium has not fully committed the API yet.

I needed to first post the support functions this script uses in order to tie it all together. (See the previous posts for the support scripts)
The monitor-api.txt sample provides the key:value pairs you'll need to call the API, please adjust them for your environment.

We're currently using it to add devices when they successfully get an IP address from the DHCP server. You can add some custom filtering if you need so that not all devices are given to the API, however that's up to you in your environment.

When calling addmonitor the first parameter is the hostname and the second parameter is the domain name suffix.
We use dynamically created DNS to resolve each device on the Observium side, if you don't have this in place then passing the IP address as the hostname should work with no domainname suffix.
We've chosen to statically set out domainname suffix in the DHCP script instead of dynamically looking it up, the choice is yours.

Create this code as the lease-script for your DHCP server, as below or copy it into the winbox script window
/ip dhcp-server
add authoritative=yes disabled=no interface=ether1 address-pool=pool1 lease-time=7d name=equipment-dhcp use-radius=no \
	lease-script="...[DHCP LEASE SCRIPT]......."
DHCP lease script to paste into WINBOX.
DHCP-LEASE-WINBOX.JPG
:local replace [:parse [:system script get replace-char source]]
:local addmonitor [:parse [:system script get add-monitor-device source]]
:local domainname "equipment.domain.local"
/ip dhcp-server lease
:if ($leaseBound = 1) do={
	:local hostname [ get [find where active-address=$leaseActIP] host-name]
	:set $hostname [$replace $hostname "." "-"]
	:if ([:len $hostname] <= 1) do={:set $hostname [$replace $leaseActMAC ":" ""]}
	:do {
		[$addmonitor $hostname $domainname]
	} on-error={:log error "Error updating API for DHCP client"}
}
Here's an idea of code to do filtering based on a simple regex. You can place it in either the DHCP lease script or in the add-monitor-device script
:if (!($hostname ~"COMPARE TO ME")) do={:return -1}
Create the script as add-monitor-device
You can change the keep variable to save the results of the API call to the router and possibly parse it to check the status. The sample code at the end is commented out, it just echoed the file to the console and log.
Note: The Observium API returns a JSON string from the API call so parsing it can be tricky with ROS scripts.
:global configfolder
:local keyfile [:parse [:system script get read-keyfile source]]
:local replace [:parse [:system script get replace-char source]]
:local convert [:parse [:system script get replace-lowup source]]
:local domainname "router.domain.local"
:local community "public"
:local hostname [$replace ([:system identity get name]) " " "-"]
:local keep true
:local apikey ($configfolder."monitor-api")
:local results ($configfolder."monitor-results.txt")
:local api
:local user
:local pass
:local url
:if (($1 != "") && ($1 != nil)) do={:set $hostname [$replace $1 " " "-"]}
:if (($2 != "") && ($2 != nil)) do={:set $domainname $2}
:do {
	:if (!($hostname ~"XXX-")) do={:return -1}
	:set $hostname [$convert $hostname 1]
}
:do {:set $api [$keyfile $apikey ":"]} on-error={:log error "Could not load API information from file $apikey"}
:do {
	:set $user [:pick ($api->0) 1]
	:set $pass [:pick ($api->1) 1]
	:set $url ([:pick ($api->2) 1].[:pick ($api->3) 1].[:pick ($api->4) 1])
} on-error={:log error "Could not parse API array"; return 0}
:do {[:file remove [:file find name=$results]]} on-error={}
:log info "Start add device $hostname.$domainname to monitor server via API [$url]"
:do {
	:local content "hostname=$hostname.$domainname&snmp_community=$community"
	#:log info $content
	[:tool fetch user=$user password=$pass url=$url keep-result=$keep http-method=post http-data=$content check-certificate=no dst-path=$results]
	:log info "Added device to monitoring server completed"
} on-error={:log warn "Warning calling monitor API to add device $hostname"; return 0}
:if ($keep) do={
	:delay 1s
	:set $results [:file get [:file find name=$results] contents]
}
:return $results
We've achieved some really complex scripting by using scripts as functions inside of other scripts. I hope this example gives you and idea of what is possible when scripts are created this way with re-usable functions.

Thanks.
Icosa
You do not have the required permissions to view the files attached to this post.
Last edited by icosasupport on Thu Nov 23, 2017 2:27 am, edited 3 times in total.
 
icosasupport
newbie
Posts: 29
Joined: Fri Oct 13, 2017 8:37 pm

Re: Useful scripts

Wed Nov 08, 2017 9:26 pm

Hey all,

Need to calculate your IP subnets but don't have access to the internet? How about as part of scripts? Maybe to create dynamic IP pools?
Here's our IP subnet calculator function. It's probably not optimized in the calculation part, but it does work so we're just using it 'as is'
We make this part of the router startup routine so that it's a global variable you can access in a terminal window without having to load parse it.
You can get results in two ways, one as text to display the calc and two as an array to use in other functions.

Sample usage from the terminal window.
Call ipcalc with 2 parameters, first is the IP subnet in CIDR format, second is the flag to display the results.
:local ipcalc [:parse [:system script get ip-calc source]]; :put [$ipcalc 192.168.10.0/24 1]
Results:
Start: 192.168.10.1 End: 192.168.10.254 Network: 192.168.10.0 Broadcast: 192.168.10.255 Subnetmask: 255.255.255.0 Usable: 254

Sample usage from a script.
Calling ipcalc without the second parameter returns and array so you can use it as a variable.
The array is structured with the same layout as you can see on the console with a starting index of zero.
:local ipcalc [:parse [:system script get ip-calc source]]; 
:local subnet [$ipcalc 192.168.10.0/24]
:log info ("Broadcast address is ".($subnet->3))
Array structure: $subnet will equal {192.168.10.1;192.168.10.254;192.168.10.0;192.168.10.255;255.255.255.0;254}

Create script as ip-calc
:local ipnetwork [:toip ([:pick $1 0 [:find $1 "/"]])]
:local cidrsubnet [:pick $1 ([:find $1 "/"] + 1) [:len $1]]
:local subnetmask  (0.0.0.0 | (255.255.255.255 << (32-$cidrsubnet)))
:local ipbroadcast ($ipnetwork | ~(255.255.255.255 << (32-$cidrsubnet)))
:local ipstart
:local ipend
:local ipusable
:set ipstart ($ipnetwork + 1) 
:set ipend (($ipnetwork | $ipbroadcast) - 1)
:local usable (~$subnetmask)
:local y 0
:local char
:local result
:while ($y < ([:len $usable] + 1)) do={
	:set char [:pick $usable $y ($y + 1)]
	:if ($char != ".") do={
		:set $result ($result.$char)
	} else={
		:set $result ($result.",")
	}
	:set $y ($y + 1)
}
:set $result [:toarray $result]
:for i from=0 to=2 do={
:set ipusable ($ipusable + ([:pick $result $i] * (256 << (8 * (2 - $i)))))
}
:set ipusable (($ipusable + [:pick $result 3]) - 1)
:if ([:len $2] != 0) do={
	:return "Start: $ipstart End: $ipend Network: $ipnetwork Broadcast: $ipbroadcast Subnetmask: $subnetmask Usable: $ipusable"
} else={
	:return [:toarray ($ipstart,$ipend,$ipnetwork,$ipbroadcast,$subnetmask,$ipusable)]
}
Please remember us or reference us when you use our scripts on your routers, we like giving back to the community as much as we can.
Thanks,
Icosa.
 
Swordforthelord
Frequent Visitor
Frequent Visitor
Posts: 71
Joined: Thu Jul 08, 2010 10:18 pm

Re: Useful scripts

Sun Apr 08, 2018 7:19 pm

Here's a script I recently created for enabling/disabling my guest wifi. I plan to attach this script to the external mode button of a hap AC2. Please note, in the context of the script, "Guest" is the name of the wireless interface. This script checks to see if the guest wifi is disabled. If it is, it enables it and then plays two lower tones and then a high tone over the beeper. If it isn't disabled, it disables it and then plays two high tones and a low tone. This script works on my RB951G version 6.40.7. I don't know yet if it will need to be modifed for the hap AC2 as that will be my first dual-band routerboard.

{
:if ([/interface wireless get Guest disabled]=true) \
do={[/interface wireless enable Guest; /beep frequency=380 length=300ms;
:delay 300ms;
:beep frequency=380 length=300ms;
:delay 300ms;
:beep frequency=770 length=600ms;]} \
else={[/interface wireless disable Guest; beep frequency=770 length=300ms;
:delay 300ms;
:beep frequency=770 length=300ms;
:delay 300ms;
:beep frequency=380 length=600ms;]}
}
 
Swordforthelord
Frequent Visitor
Frequent Visitor
Posts: 71
Joined: Thu Jul 08, 2010 10:18 pm

Re: Useful scripts

Sun Apr 22, 2018 3:31 am

Here's a script I recently created for enabling/disabling my guest wifi. I plan to attach this script to the external mode button of a hap AC2. Please note, in the context of the script, "Guest" is the name of the wireless interface. This script checks to see if the guest wifi is disabled. If it is, it enables it and then plays two lower tones and then a high tone over the beeper. If it isn't disabled, it disables it and then plays two high tones and a low tone. This script works on my RB951G version 6.40.7. I don't know yet if it will need to be modifed for the hap AC2 as that will be my first dual-band routerboard.

{
:if ([/interface wireless get Guest disabled]=true) \
do={[/interface wireless enable Guest; /beep frequency=380 length=300ms;
:delay 300ms;
:beep frequency=380 length=300ms;
:delay 300ms;
:beep frequency=770 length=600ms;]} \
else={[/interface wireless disable Guest; beep frequency=770 length=300ms;
:delay 300ms;
:beep frequency=770 length=300ms;
:delay 300ms;
:beep frequency=380 length=600ms;]}
}
I've updated my script as it turns out the hap AC2 does not have a beeper; this new script, in addition to triggering the beeper (no harm done if your RB doesn't have one), also turns on the user-led when the guest wifi is on and turns the led off when the guest wifi is off.
{
:if ([/interface wireless get Guest disabled]=true) \
do={[/interface wireless enable Guest;
/beep frequency=380 length=300ms;
:delay 300ms;
:beep frequency=380 length=300ms;
:delay 300ms;
:beep frequency=770 length=600ms;
/system leds set [find where leds=user-led] type=on;]} \
else={[/interface wireless disable Guest;
/beep frequency=770 length=300ms;
:delay 300ms;
:beep frequency=770 length=300ms;
:delay 300ms;
:beep frequency=380 length=600ms;
/system leds set [find where leds=user-led] type=off;]}
}
Please note that for this to work, you would first need to run the command:
/system leds add leds=user-led type=off
This creates the LED setting for the command in the script to manipulate.
 
snakefox666
just joined
Posts: 1
Joined: Wed Apr 18, 2018 9:01 am

Re: Useful scripts

Wed May 09, 2018 5:15 pm

Here's a script I recently created for enabling/disabling my guest wifi. I plan to attach this script to the external mode button of a hap AC2. Please note, in the context of the script, "Guest" is the name of the wireless interface. This script checks to see if the guest wifi is disabled. If it is, it enables it and then plays two lower tones and then a high tone over the beeper. If it isn't disabled, it disables it and then plays two high tones and a low tone. This script works on my RB951G version 6.40.7. I don't know yet if it will need to be modifed for the hap AC2 as that will be my first dual-band routerboard.

{
:if ([/interface wireless get Guest disabled]=true) \
do={[/interface wireless enable Guest; /beep frequency=380 length=300ms;
:delay 300ms;
:beep frequency=380 length=300ms;
:delay 300ms;
:beep frequency=770 length=600ms;]} \
else={[/interface wireless disable Guest; beep frequency=770 length=300ms;
:delay 300ms;
:beep frequency=770 length=300ms;
:delay 300ms;
:beep frequency=380 length=600ms;]}
}
I've updated my script as it turns out the hap AC2 does not have a beeper; this new script, in addition to triggering the beeper (no harm done if your RB doesn't have one), also turns on the user-led when the guest wifi is on and turns the led off when the guest wifi is off.
{
:if ([/interface wireless get Guest disabled]=true) \
do={[/interface wireless enable Guest;
/beep frequency=380 length=300ms;
:delay 300ms;
:beep frequency=380 length=300ms;
:delay 300ms;
:beep frequency=770 length=600ms;
/system leds set [find where leds=user-led] type=on;]} \
else={[/interface wireless disable Guest;
/beep frequency=770 length=300ms;
:delay 300ms;
:beep frequency=770 length=300ms;
:delay 300ms;
:beep frequency=380 length=600ms;
/system leds set [find where leds=user-led] type=off;]}
}
Please note that for this to work, you would first need to run the command:
/system leds add leds=user-led type=off
This creates the LED setting for the command in the script to manipulate.
Hello, thanks for sharing your script ;)
I'm very interested in your script, I tried to put it in place without success but I'm using a RouterBoard hEX as CAPSMan and a cAP ac as AP. So my question is how can we trigger something from the button on the cAP ac and disable the guest wifi (for example) that is managed by the hEX :-(
Don't know if it's clear enough ...
 
vineetlogicsofts
just joined
Posts: 3
Joined: Wed Jun 13, 2018 5:13 pm
Location: Melbourne

Re: Useful scripts

Wed Jun 13, 2018 5:22 pm

Thanks, :) Janisk. I found these scripts very useful for the RouterOS version which I am using and want to discover more about this.
 
User avatar
doneware
Trainer
Trainer
Posts: 647
Joined: Mon Oct 08, 2012 8:39 pm
Location: Hungary

proper BGP peer logging

Sat Jul 14, 2018 3:05 pm

If you need cisco/juniper like bgp peer logging you might find this script handy. tested on routeros 6.42.5, but in general shall work in all v6 releases. it will generate logs with severity=info if the peer state advances from disabled towards enstablished, and it will log "errors" as it decreases, i.e. an established peer is disrupted.
you should run this from scheduler in 1m intervals.
       :global oldbgpstate
       :if (:len $oldbgpstate = 0 ) do={ :set $oldbgpstate {"_dummy"=33} }
       :local bgpstates ({disabled=0},{idle=1},{connect=2},{active=3},{opensent=4},{openconfirm=5},{established=6})
       /routing bgp peer
       :local peerstate
       :foreach peer in=[/routing bgp peer find ] do={
            :local pstate [get $peer state]
            :if ( [get $peer disabled] ) do={ :set $pstate value="disabled" }
            :local peername [get $peer name]
            :local severity "info"
       
            :if ( ($bgpstates->($oldbgpstate->$peername)) > ($bgpstates->$pstate) ) do={
                #raise error if state is decreasing
                :set $severity "error"
                }
            :if ($oldbgpstate->$peername != $pstate) do={
                #peer state changed
                :local peerip [get $peer "remote-address"]
                :local message "bgp,$severity peer $peerip ($peername) changed state to $pstate"
                :if ($severity = "error") do={
                    :log error message=$message
                } else={
                    :log info message=$message
                }
            }
            :set ($oldbgpstate->$peername) value="$pstate"
       }

 
gabryb85
just joined
Posts: 3
Joined: Mon Apr 23, 2018 9:54 am

VPN with DDNS

Wed Sep 05, 2018 1:19 pm

Hi,
i made and tested a code for setting every 15 minutes VPN with DDNS. Sorry for Italian in comments.
#Imposta ID della VPN (ID - 1)
:global VPNID 1
# Imposta DDNS_Sorgente attualmente legato al DDNS 
:global DDNSSorgente [:resolve xxxxxxxxxxx.sn.mynetname.net]
# Imposta DDNS_Destinazione attualmente legato al DDNS
:global DDNSDestinazione [:resolve yyyyyyyyyyyyyy.sn.mynetname.net]
# Imposta VPN_Sorgente
:global VPNSorgente [/ip ipsec policy get $VPNID sa-src-address]
#Imposta VPN_Destinazione
:global VPNDestinazione [/ip ipsec policy get $VPNID sa-dst-address]

#Verifica se cambiato IP Sorgente, nel caso lo modifica nella VPN
:if ($DDNSSorgente !=$VPNSorgente)  do={
:log info "IP sorgente $VPNSorgente cambiato in $DDNSSorgente"
/ip ipsec policy set $VPNID sa-src-address=$DDNSSorgente} else= {:log info "Nessun cambiamento IP sorgente"}
:log info "Verifica IP Sorgente $DDNSSorgente con successo"

#Verifica se cambiato IP Destinazione, nel caso lo modifica nella VPN
:if ($DDNSDestinazione!=$VPNDestinazione)  do={
:log info "IP destinazione $VPNDestinazione cambiato in $DDNSDestinazione"
/ip ipsec policy set $VPNID sa-dst-address=$DDNSDestinazione} else= {:log info "Nessun cambiamento IP Destinazione"}
:log info "Verifica IP Destinazione $DDNSDestinazione eseguita con successo"
 
User avatar
astounding
Member Candidate
Member Candidate
Posts: 121
Joined: Tue Dec 16, 2008 12:17 am

Unix-style Timestamp Functions

Wed Nov 14, 2018 11:40 pm

I've need to do some date/time comparisons on RouterOS 6.40.9, and as new scripting commands to make this easier don't yet exist--see the "Built in function library" thread--I did it the hard way.

This script provides three basic timestamp functions. All three use name-based arguments, not positional.
  • getUnixTimestamp date time [offset]
  • getNow
  • getFileTimestamp filename
More documentation appears in comments in the code below:

NOTE: Updated to version 1.1 fixing a few bugs
## -----
## timestamp - a few utility functions for handling date + time timestamps as Unix-style
##             integer timestamps (seconds since the midnight Jan. 1, 1970 GMT epoch)
##
##   Version 1.1
##
##   Written by Aaron D. Gifford
##   https://www.aarongifford.com/
##
##   The above author, and original copyright owner, InfoWest, Inc. hereby place this code in the
##   PUBLIC DOMAIN.  You may use this code in any way.  You may alter it.  Redistribute it or any
##   derivitave with NO requirements whatsoever.  You may remove this notice or remove the
##   author's name.  You could even claim you wrote it (though that's not very cool).  Attribution
##   or acknowledgement is appreciated, but not required.  Have fun!  (NO WARRANTIES, etc.)
## -----

## FUNCTION:
##   getUnixTimestamp date="jan/01/1970" time="00:00:00" [offset=0]
##    * date is a string in the form "mon/DD/YYYY"
##    * time is a string in the form "HH:MM:SS" (24-hour clock)
##    * offset is an OPTIONAL signed integer number of seconds east of GMT
##      such that a positive offset is for zones east of GMT and a negative
##      offset is for zones west of GMT.  IF NOT included, the script will
##      retrieve the currently ative device offset using:
##        /system clock get gmt-offset
##
##   Example use:
##     {
##       :local timestamp [$getUnixTimestamp time=[/system clock get date] date=[/system clock get time]]
##       ...
##
##   RETURNS a Unix-style timestamp, an integer number of seconds elapsed since the Unix epoch
##   (01 JAN 1970 GMT).  Hopefully MikroTik will soon add a system funtion to return a timestamp
##   directly, making this obsolete.
##
## FUNCTION:
##   getNow
##
##   RETURNS the same thing as doing:
##     $getUnixTimestamp time=[/system clock get date] date=[/system clock get time]
##
## FUNCTION:
##   getFileTimestamp fname="filename.txt"
##    * fname - the name/path of the file for which a creation timestamp will be retrieved
##
##   RETURNS:
##     Unix-style timestamp of creation date/time for file OR returns false if file was not found
##


:global getUnixTimestamp do={
  :local timestr [:tostr $time]
  :local datestr [:tostr $date]
  :local timestamp ([:tonum [:pick $timestr 0 2]]*3600 + [:tonum [:pick $timestr 3 5]]*60 + [:tonum [:pick $timestr 6 8]])

  ## Month number, zero-based (0=January)
  :local mon ([:find "janfebmaraprmayjunjulaugsepoctnovdec" [:pick $datestr 0 3]]/3)

  ## For each month already passed, account for the days passed (ignoring Feb. 29th for now):
  :local i 0
  :while ($i < $mon) do={
    :set timestamp ([:pick {31;28;31;30;31;30;31;31;30;31;30;31} $i] * 86400 + $timestamp)
    :set i ($i+1)
  }

  ## Account for the number of days already passed for the current month:
  :set timestamp (86400*([:tonum [:pick $datestr 4 6]]-1)+$timestamp)

  :local year [:tonum [:pick $datestr 7 11]]

  ## For each year completed since the epoch, include 365 days worth of seconds (again ignoring leap years):
  :set timestamp (($year-1970)*31536000+$timestamp)

  ## Account for Feb. 29 additionl days in leap years already completed:
  :set i 1970
  :while ($i<$year) do={
    :if (($i+3)/4 = $i/4 && (($i+99)/100 != $i/100 || ($i+399)/400 = $i/400)) do={
      ## REMEMBER: Leap years occur on years evenly divisible by 4 EXCEPT for those
      ## that are ALSO evenly divisible by 100 UNLESS the century year is ALSO
      ## divisible by 400 (in which case it IS a leap year after all):
      :set timestamp (86400+$timestamp)
    }
    :set i ($i+1)
  }

  ## IF the date in question is already past February, account for a leap day IF this year is
  ## a leap year too:
  :if ($mon > 1 && ($year+3)/4 = $year/4 && (($year+99)/100 != $year/100 || ($year+399)/400 = $year/400)) do={
    :set timestamp (86400+$timestamp)
  }

  ## Account for time zone offset:
  :local tzoffset $offset
  :if ([:typeof $tzoffset] = "nothing") do={
    :set tzoffset [/system clock get gmt-offset]
  }
  :if ($tzoffset > 2147483648) do={
    ## A VERY LARGE integer indicates that the offset is negative (west). Convert
    ## the offset and subtract the resulting negative integer from the timestamp
    ## (i.e. add the positive absolute value to the timestamp):
    :set timestamp (4294967296-$tzoffset+$timestamp)
  } else={
    ## A small integer indicates the offset is positive (east).  Simply subtract
    ## it from the timestamp:
    :set timestamp ($timestamp-$tzoffset)
  }

  :return $timestamp
}


:global getNow do={
  :global getUnixTimestamp
  :return [$getUnixTimestamp date=[/system clock get date] time=[/system clock get time]]
}


:global getFileTimestamp do={
  :global getUnixTimestamp
  :local fts [/file find where name="$fname"]
  :if ([:len $fts]=0) do={
    ## No file found!
    :return false
  }
  :set fts [:tostr [/file get value-name=creation-time $fts]]
  :return [$getUnixTimestamp date=[:pick $fts 0 11] time=[:pick $fts 12 20]]
}

## The End
Enjoy!

-Astounding
 
fgonzalezm
just joined
Posts: 1
Joined: Mon Feb 11, 2019 5:31 pm

Re: Useful scripts

Mon Feb 11, 2019 5:36 pm

Hi all, i am a newbie on mikrotik, and actually use Winbox for admin the Secrets.... anyone have an script to export a TXT file with the complete data from the secrets ? ... thanks a lot
 
User avatar
hilton
Long time Member
Long time Member
Posts: 634
Joined: Thu Sep 07, 2006 5:12 pm
Location: Jozi (aka Johannesburg), South Africa

Re: Useful scripts

Wed Feb 13, 2019 10:47 am

Would this not work?
/ppp secret export file=secrets
 
rostikk
just joined
Posts: 4
Joined: Wed Mar 06, 2019 12:17 am

Re: Useful scripts

Mon Mar 11, 2019 4:48 am

HI! I am looking for a way to get the router to act when a certain LAN client (ip address) sends a packet to a certain WAN address. The action would be a webhook. What would be the most effective way to setup something like this? Can anyone point me to the right direction, please?

Would I have to use packet sniffer and fetch?

Thank you!
 
rostikk
just joined
Posts: 4
Joined: Wed Mar 06, 2019 12:17 am

Re: Useful scripts

Wed Mar 13, 2019 3:16 pm

HI! I am looking for a way to get the router to act when a certain LAN client (ip address) sends a packet to a certain WAN address. The action would be a webhook. What would be the most effective way to setup something like this? Can anyone point me to the right direction, please?

Would I have to use packet sniffer and fetch?

Thank you!
Bump!

I guess, one way to do this is to setup a firewall rule, which would then trigger a script similar to this https://wiki.mikrotik.com/wiki/Wake_on_ ... te_Desktop

However, the script would have to run every 10 seconds... Is there another way to have the firewall rule trigger a script?
 
nostromog
Member Candidate
Member Candidate
Posts: 226
Joined: Wed Jul 18, 2018 3:39 pm

Re: Useful scripts

Wed Mar 13, 2019 6:41 pm


However, the script would have to run every 10 seconds... Is there another way to have the firewall rule trigger a script?
I don't think so. There are a few places where scripts can be triggered in response to events:
  • in /ppp profile (on-up, on-down), useful for all ppp-based interfaces (pptp, l2tp, sstp, pppoe, ovpn...)
  • in /ip dhcp-server (lease-script) when a dhcp-lease changes
  • in /ip dhcp-client (script)
  • ditto for /ipv6 dhcp-* except that the server attribute is called binding-script
  • in /tool netwatch (down-script, up-script) to fire when a host is visible
  • (...) Not sure if there are more hooks

I was missing another one for /interface wireless registration-table, to fire when either our station interface connects, or else when our AP interface gets a station connected. This would be similar to the dhcp stuff at the 802.11 L2 level.
I have also missed generic on-down/on-up for hardware interfaces, similar to ppp actions but at the /interface level.
I'd also woul like a scripted action for logs, something like /system logging add topics=health action=script where the script action would call a script with the log line...

But of course I understand the developers need to concentrate efforts, though, and keep the distribution size under control.
 
efiniste
just joined
Posts: 10
Joined: Fri Mar 14, 2014 6:35 pm

Re: Useful scripts

Fri May 24, 2019 1:10 pm

HI! I am looking for a way to get the router to act when a certain LAN client (ip address) sends a packet to a certain WAN address. The action would be a webhook. What would be the most effective way to setup something like this? Can anyone point me to the right direction, please?

Would I have to use packet sniffer and fetch?

Thank you!
Bump!

I guess, one way to do this is to setup a firewall rule, which would then trigger a script similar to this https://wiki.mikrotik.com/wiki/Wake_on_ ... te_Desktop

However, the script would have to run every 10 seconds... Is there another way to have the firewall rule trigger a script?
Did you ever get anywhere with this? I'm trying to figure out the same thing. When my video doorbell is pressed it sends an alert via a "cloud" service. I'm trying to trigger something local too and this would be ideal.

Steve
 
beeyev
just joined
Posts: 11
Joined: Wed Aug 08, 2018 3:00 pm

Re: Useful scripts

Sun Aug 04, 2019 1:19 am

Share couple of my scripts here.

1. Script automatically updates router to the latest firmware.
When script finds new update it sends email notification that upgrade process has started, system backup and config file are in attachment. After firmware and routerboard got updated, it sends second email which tells that upgrade process has been finished.
You can choose update channel and even allow to update only patch versions.
Link to instruction: https://github.com/beeyev/Mikrotik-Firm ... to-Updater

2. Simple script that updates your public IP in DuckDNS dynamic ip service. (Free dyndns alternative)
Link to instruction: https://github.com/beeyev/Mikrotik-Duck ... IP-Updater
 
User avatar
Jotne
Forum Guru
Forum Guru
Posts: 3334
Joined: Sat Dec 24, 2016 11:17 am
Location: Magrathean

Re: Useful scripts

Sun Aug 04, 2019 9:32 am

From all the problem I see that MT have after updating routers, I would not recommend to do an automatically upgrade without any possible to control it when it should run. At least on remote devices. I did lost my L2TP IPSec tunnel after upgrade due to change in config. So take care with this.
Another thing is that a backup of the router may not work across upgrade, so you may need to downgrade to restore a backup.

You could setup a web page that each router in a script fetch some data. If it get upgrade_hap_lite=ok found on the page, then It can upgrade automatically, since you then can hold the upgrade until you have tested the release in a controlled environment.

I see that you can set it to only upgrade minor version, that may help some with backup restore, but not when MT add error or big changes in minor version as it has happen many times lately. (change in wifi that made it stop depending on what you have setup)

Also you can remove the ; at end of all lines. Only needed if you have more than one command at same line.
You have even some line with ; and some without like:
:if ($osVerNewNum > $osVerCurrentNum) do={
:set isUpdateAvailable true;
:log info ("New firmware version found: $osVerNew");
} else={
:log info ("New firmware version not found.")
}
When you send message to the log system, I do like better that it are in a machine readable format. Since I work allot with Splunk, it reads message with out any modification if you do change from:
text some more text data
to:
text_some_more_text=data
if data has spaces, use quotes
router_identity="rotuer 128"

Eks (join word, use =, remove comma, if there are spaces in data use double quotes example if board_name has space)
"Upgrading firmware on router $[/system identity get name], board name: $[/system resource get board-name],
"script=firmware_upgrade router=$[/system identity get name] board_name=\"$[/system resource get board-name]\" ........
 
GATYRA
just joined
Posts: 1
Joined: Fri Oct 25, 2019 12:10 am

Re: Useful scripts

Fri Oct 25, 2019 12:11 am

Same Problem here, can't get the same script working on 6.30.4

Anyone?
in that case take CLI script editor (inside RouterOS) and edit script in there. Most of the syntax changes can be caught using that. F5 to refresh highlighting.
 
ceylan
newbie
Posts: 27
Joined: Sat Feb 10, 2018 3:03 pm
Location: CYPRUS
Contact:

Re: Useful scripts

Thu Jan 30, 2020 3:52 pm

i have problem about my script...
-first of all i am changing mikrotik user name and password and delete standard username
user add name=******* password=******* group=full
user remove admin
/system scheduler add name="30 gunde reboot" start-date="jul/12/1970" start-time="04:00:00" interval="1d 00:00:00" policy="read,write" on-event=":if ([/system resource get uptime] > 30d00h00m00s) do={:if ([/system clock get time] < 06:30:00) do={:if ([/system clock get time] > 04:30:00) do={/system reboot}}}"
at the last ..i am adding scheduler, but when i am checking this scheduler, I saw owner admin. that why scheduler isn't working
so how can fix this situation ???

i have text file for my this user and system sittings.I'm copying script and open new terminal for past it there.
 
User avatar
macsrwe
Forum Guru
Forum Guru
Posts: 1008
Joined: Mon Apr 02, 2007 5:43 am
Location: Arizona, USA
Contact:

Re: Useful scripts

Sat Feb 01, 2020 2:39 am

i have problem about my script...
-first of all i am changing mikrotik user name and password and delete standard username
user add name=******* password=******* group=full
user remove admin
/system scheduler add name="30 gunde reboot" start-date="jul/12/1970" start-time="04:00:00" interval="1d 00:00:00" policy="read,write" on-event=":if ([/system resource get uptime] > 30d00h00m00s) do={:if ([/system clock get time] < 06:30:00) do={:if ([/system clock get time] > 04:30:00) do={/system reboot}}}"
at the last ..i am adding scheduler, but when i am checking this scheduler, I saw owner admin. that why scheduler isn't working
so how can fix this situation ???

i have text file for my this user and system sittings.I'm copying script and open new terminal for past it there.

You may have deleted the user admin, but you are still running as the user admin, so that's what ownership becomes! Two ways to address this:

Create the script BEFORE deleting the user admin. I have found that such action tends to move all scripts owned by admin to the new full user. But I don't think this is documented or guaranteed in any way, and I would consider it a kludge.

Or specify "owner=********" when you create the script, most straightforward.
 
gbudny
just joined
Posts: 16
Joined: Tue Feb 09, 2016 10:57 am
Location: Poland, Katowice

Re: Useful scripts

Sun Feb 02, 2020 9:26 am

Hi all,

Let me also share my scripts collection with you - maybe you will find few of them helpful or useful as they are to me;)

https://github.com/gbudny93/RouterOS_Useful_Scripts

Greg
 
SudiFreeman
just joined
Posts: 2
Joined: Mon Feb 10, 2020 11:32 am

Re: Useful scripts

Mon Feb 10, 2020 1:14 pm

Hi guys,
A quick one, So I want to upload a certain rule to a number of mikrotik haplites in my network, however I don't want to keep logging into the particular haplite routers and pasting the rule on the terminal, this is because the routers are too many(over 2000) and it'll take me forever to login into all of them. Is there a script I can run that will post the rule I want to these routers without me having to login into every one of them. Like a mass rollout of the particular rule to these 2000+ haplites. Please any suggestion will be highly appreciated.
 
willyfontana
just joined
Posts: 8
Joined: Fri Dec 27, 2013 4:54 pm

Re: Useful scripts

Sat Feb 29, 2020 1:01 pm

Hello SudiFreeman.
If you had all your routers registered in The Dude server, you could write a simple script inside Dude to write the new rules you need to all the routers. I haven't tested this, but I think it could work.
Please let us know if you tried it and the outcome.
Regards
 
Harry53
just joined
Posts: 8
Joined: Sat Feb 29, 2020 6:41 pm

Re: Useful scripts

Sat Feb 29, 2020 7:13 pm

Thanks a lot Janisk,
your post is very helpful.It is too much helpful.
 
cj3666
just joined
Posts: 6
Joined: Mon Dec 02, 2019 1:42 am

Re: Useful scripts

Wed Apr 22, 2020 1:16 am

I am looking for Someone expert to create script for mikrotik Hotspot.

payment for the service.
 
Thadd
just joined
Posts: 7
Joined: Mon May 11, 2015 3:05 am

Re: Useful scripts

Sat Jun 20, 2020 11:44 pm

Is there a way to write a script to monitor bandwidth for a simple queue? Basically, I have a connection that keeps maxing out the upload and I want the router to notify me when that specific queue is maxing out for an extensive amount of time.
 
User avatar
Jotne
Forum Guru
Forum Guru
Posts: 3334
Joined: Sat Dec 24, 2016 11:17 am
Location: Magrathean

Re: Useful scripts

Tue Jun 23, 2020 8:09 am

Please only post script or comment for script here.
If you like a script, post a request here:
viewforum.php?f=9
 
wirelessmate
just joined
Posts: 1
Joined: Tue May 24, 2011 4:16 pm
Location: Sydney

Re: Useful scripts

Mon Jul 06, 2020 3:55 pm

Hi Greg,
seems like you are pretty efficient with scripting, maybe you could help ?
I want to get all devices with mac address a1:17:23 that are in the subnet emailed or displayed in log.
I understand these are existing in ARP then in dhcp-server leases one could find their names...Can you help?

cheers,
adam

Let me also share my scripts collection with you - maybe you will find few of them helpful or useful as they are to me;)

https://github.com/gbudny93/RouterOS_Useful_Scripts

Greg
[/quote]
 
gsbiz
just joined
Posts: 24
Joined: Sat Nov 17, 2018 5:18 pm

Re: Useful scripts

Tue Jul 28, 2020 5:04 pm

Hi All,
This is a little script set I wrote to check the IP of visitors to your service against DNS RBL's. Handy to block known botnets and/or bad IP's. This filter is a little complex but simply put it, will record the IP's of any system connecting to the firewall on port 22 (or any other service port you want to put a JUMP rule in for) and check them against a DNS based Blacklist of known attackers. So you don't have to put up with the hassle of them on your systems.

First are the firewall filters:
/ip firewall filter add action=jump chain=forward comment="Check intruders in \"Dynamic_blacklist\" chain (SSH)" dst-port=22 in-interface-list=WAN jump-target=dynamic_blacklist protocol=tcp
/ip firewall filter add action=add-src-to-address-list address-list=DNSBL_unchecked address-list-timeout=30m chain=dynamic_blacklist comment="DNS Blacklist add ip to list to check." connection-state=!established,related in-interface-list=WAN src-address-list=!DNSBL_unchecked
/ip firewall filter add action=return chain=dynamic_blacklist comment="Return to the chain that jumped into dynamic_blacklist chain"
/ip firewall raw add action=drop chain=prerouting comment="Drop blacklist" in-interface-list=WAN log-prefix="DYNAMIC BLACKLIST IP (Raw)" src-address-list=bl_blacklist
Next is the script to check the DNS blacklist, schedule this to run every 5,10 or 15 mins. I chose bl.blocklist.de but you can use your favourite. the script only checks for a positive response it does not localise the return to a particular listing type, though you could improve the script to check for this.

### DNS Blacklist Script ###
# DNS Blacklist service call
:local blserver "bl.blocklist.de"
:local ToListIPList [:toarray ""]
:local octets
:local revip
:local bllookup
:local blresult
:local i
:global returnOctet;

# for each IP in the unchecked list load it into an array
:set i (0);
:foreach fwlist in=[/ip firewall address-list find where list=DNSBL_unchecked] do={
:foreach ip in=[/ip firewall address-list get $fwlist value-name=address] do={
:set ($ToListIPList->"$i") $ip;
:put "$ip is loaded into array at index $i"
#remove ip from address list to check ether way
/ip firewall address-list { remove [find address=$ip list=DNSBL_unchecked]};
:set i ($i + 1);
};
};

#delete entire list=DNSBL_unchecked
#/ip firewall address-list remove [/ip firewall address-list find list="DNSBL_unchecked"];

#take the IPs and Progress;
:foreach ip in=$ToListIPList do={
:put $ip;
# seperate IP into $octets array;
:set octets [$returnOctet $ip 5];
# Reverse the IP address for reverse DNS lookup;
:set revip ([:tostr [:pick $octets 3]] . "." . [:tostr [:pick $octets 2]] . "." . [:tostr [:pick $octets 1]] . "." . [:tostr [:pick $octets 0]]);
# construct the blacklist lookup
:set bllookup ($revip . "." . $blserver);
:put $bllookup;
# perform the lookup and correct an empty response;
:do {
:set blresult [:resolve $bllookup];
} on-error={
#"No blacklist record found, correct the error";
:set $blresult "fail";
}
# check the result
:if ( $blresult != "fail" ) do={
# if the address is listed add it to the blacklist
:put "listing ip";
/ip firewall address-list add address=$ip list=DNSBL_listed timeout=168h;
};
};
The second script is a global function stolen fair and square from Rextended on viewtopic.php?t=85205 though i did do a little error correcting on it. Just put this in your scripts so it is accessible by the DNS blacklist script.
:global returnOctet do={
:if ([:typeof [:toip $1]] != "ip") do={ :error message="You did not specify any VALID IP Address."; };
:if ( (($2 + 0) < 1) || (($2 + 0) > 5) ) do={ :error message="You did not specify any VALID argument to return."; };
:local workString value=[:tostr [:toip $1]];
:local endString value="";
:local thisChar value="";
:for i from=0 to=[:len $workString] step=1 do={
:set $thisChar value=[:pick $workString $i ($i+1)];
:if ($thisChar = ".") do={ :set $thisChar value=",";};
:set $endString value=($endString.$thisChar);
};
:local resultArray value=[:toarray $endString];
:if (($2 + 0) = 5) do={ :return value=$resultArray; } else={ :return value=($resultArray->($2 - 1)); };
}
 
gsbiz
just joined
Posts: 24
Joined: Sat Nov 17, 2018 5:18 pm

Re: Useful scripts

Tue Jul 28, 2020 5:20 pm

Hi All,
A script to automatically check and update HE.net Dynamic DNS, schedule it to run every 15 mins & on reboot. Fill in your ddns host, WAN interface and the associated key.
:local currentIP
:local newIP
:local ddnshost "<Dynamic Domain>"
:local key "<Domain Key>"
:local updatehost "dyn.dns.he.net"
:local lookupserver "ns1.he.net"
:local WANinterface "<WAN Interface>"
:local outputfile ("HE_DDNS" . ".txt")


  :set newIP [/ip address get [/ip address find interface=$WANinterface] address]
  :set newIP [:pick [:tostr $newIP] 0 [:find [:tostr $newIP] "/"]]
  :set currentIP [:resolve $ddnshost server=$lookupserver]
  
#check error
:if ([:len $newIP] = 0) do={
   :log error ("Could not get IP for interface " . $WANinterface)
   :error ("Could not get IP for interface " . $WANinterface)
} else={
 
 
  :if ($newIP != $currentIP) do={
    :log info ("WAN IPv4 address $currentIP changed to $newIP")
	:log info ("Updating DDNS IPv4 address" . " Client IPv4 address to new IP " . $newIP . "...")
	/tool fetch mode=http url="http://$ddnshost:$key@$updatehost/nic/update?hostname=$ddnshost&myip=$ipv4addr" \
dst-path=$outputfile
	:set currentIP $newIP
	:log info ([/file get ($outputfile) contents])
	/file remove ($outputfile)
  } else={
#  :log info ("WAN IPv4 address has not changed")
  }
}
 
gsbiz
just joined
Posts: 24
Joined: Sat Nov 17, 2018 5:18 pm

Re: Useful scripts

Tue Jul 28, 2020 5:32 pm

Hi All,
A small script to download and update Geofilters into an IP address list (with the name of the TLD). you will need to create the firewall rule to drop (or whatever) the list(s). Change your TLD's & download locations to suit.
foreach i in={ "NL"; "CN"; "RU"; "DE"; "UA"; "IN"; "IT"; "ID"; "TH"; "BR"; "IR"; "VN"; "PK"} do={
/tool fetch url="http://www.iwik.org/ipcountry/mikrotik/$i" dst-path=/SDHX/downloads/$i;
/import file-name=/SDHX/downloads/$i;
/file remove /SDHX/downloads/$i;
}
Last edited by gsbiz on Tue Jul 28, 2020 6:02 pm, edited 1 time in total.
 
gsbiz
just joined
Posts: 24
Joined: Sat Nov 17, 2018 5:18 pm

Re: Useful scripts

Tue Jul 28, 2020 5:39 pm

Hi All,
OK not really a script, but I thought it may be in the same flavour. I created this Dynamic Blacklist firewall rule set that counts excessive connection attempts from the same IP within a given time frame and eventually blocks them for X number of days. I was initially going to put in a geo-fence for service brute forcers but i found this to be quite effective instead and not limited geographic attackers. Basically it will start counting any IP you send it via the port/protocol parameters in the first jump rule. You can have more than one jump feeding into the list from different chains.

This example is setup to guard SSH for multiple connection attempts. The time outs can be changed to suit your needs but this will block any IP that averages 3 connection attempts within 5 mins.
add chain=forward action=jump jump-target=dynamic_blacklist protocol=tcp dst-port=22 log=no log-prefix="" comment="Check intruders in "Dynamic_blacklist" chain"
add chain=dynamic_blacklist action=drop src-address-list=bl_blacklist log=no log-prefix="DYNAMIC BLACKLIST IP" comment="drop brute forcers" disabled=no
add chain=dynamic_blacklist action=add-src-to-address-list connection-state=new src-address-list=bl_stage3 address-list=bl_blacklist address-list-timeout=5d log=no log-prefix=""
add chain=dynamic_blacklist action=add-src-to-address-list connection-state=new src-address-list=bl_stage2 address-list=bl_stage3 address-list-timeout=5m log=no log-prefix=""
add chain=dynamic_blacklist action=add-src-to-address-list connection-state=new src-address-list=bl_stage1 address-list=bl_stage2 address-list-timeout=7m log=no log-prefix=""
add chain=dynamic_blacklist action=add-src-to-address-list connection-state=new address-list=bl_stage1 in-interface-list=WAN address-list-timeout=10m log=no log-prefix=""
add chain=dynamic_blacklist action=return log=no log-prefix="" comment="Return to the chain that jumped into dynamic_blacklist chain" disabled=no
 
tomislav91
Member
Member
Posts: 308
Joined: Fri May 26, 2017 12:47 pm

Re: Useful scripts

Tue Oct 27, 2020 10:49 am

Hi All,
OK not really a script, but I thought it may be in the same flavour. I created this Dynamic Blacklist firewall rule set that counts excessive connection attempts from the same IP within a given time frame and eventually blocks them for X number of days. I was initially going to put in a geo-fence for service brute forcers but i found this to be quite effective instead and not limited geographic attackers. Basically it will start counting any IP you send it via the port/protocol parameters in the first jump rule. You can have more than one jump feeding into the list from different chains.

This example is setup to guard SSH for multiple connection attempts. The time outs can be changed to suit your needs but this will block any IP that averages 3 connection attempts within 5 mins.
add chain=forward action=jump jump-target=dynamic_blacklist protocol=tcp dst-port=22 log=no log-prefix="" comment="Check intruders in "Dynamic_blacklist" chain"
add chain=dynamic_blacklist action=drop src-address-list=bl_blacklist log=no log-prefix="DYNAMIC BLACKLIST IP" comment="drop brute forcers" disabled=no
add chain=dynamic_blacklist action=add-src-to-address-list connection-state=new src-address-list=bl_stage3 address-list=bl_blacklist address-list-timeout=5d log=no log-prefix=""
add chain=dynamic_blacklist action=add-src-to-address-list connection-state=new src-address-list=bl_stage2 address-list=bl_stage3 address-list-timeout=5m log=no log-prefix=""
add chain=dynamic_blacklist action=add-src-to-address-list connection-state=new src-address-list=bl_stage1 address-list=bl_stage2 address-list-timeout=7m log=no log-prefix=""
add chain=dynamic_blacklist action=add-src-to-address-list connection-state=new address-list=bl_stage1 in-interface-list=WAN address-list-timeout=10m log=no log-prefix=""
add chain=dynamic_blacklist action=return log=no log-prefix="" comment="Return to the chain that jumped into dynamic_blacklist chain" disabled=no
just need to fix first forward chain \"dynamic_blacklist\" instead of "dynamic_blacklist"
add chain=forward action=jump jump-target=dynamic_blacklist protocol=tcp dst-port=22 log=no log-prefix="" comment="check intruders in \"dynamic_blacklist\" chain"
 
msatter
Forum Guru
Forum Guru
Posts: 2935
Joined: Tue Feb 18, 2014 12:56 am
Location: Netherlands / Nīderlande

Re: Useful scripts

Sun Nov 08, 2020 10:45 pm

Hi all,

Let me also share my scripts collection with you - maybe you will find few of them helpful or useful as they are to me;)

https://github.com/gbudny93/RouterOS_Useful_Scripts

Greg
Easier append array: viewtopic.php?p=819886#p728850
 
cldmgzn
just joined
Posts: 5
Joined: Wed Nov 04, 2020 9:16 am

Re: Useful scripts

Mon Nov 23, 2020 12:16 pm

Hi,
Can you help me please with a script to automatically create an address list from this: https://lists.blocklist.de/lists/all.txt ?

Thank you
 
msatter
Forum Guru
Forum Guru
Posts: 2935
Joined: Tue Feb 18, 2014 12:56 am
Location: Netherlands / Nīderlande

Re: Useful scripts

Mon Nov 23, 2020 12:42 pm

If it is bigger than 63KB then that is not possible in RouterOS.
 
cldmgzn
just joined
Posts: 5
Joined: Wed Nov 04, 2020 9:16 am

Re: Useful scripts

Mon Nov 23, 2020 2:53 pm

If it is bigger than 63KB then that is not possible in RouterOS.
In this case I'll use a smaller ip list: https://lists.blocklist.de/lists/ftp.txt

But I don't know how to put those IPs in an address list. :(
 
msatter
Forum Guru
Forum Guru
Posts: 2935
Joined: Tue Feb 18, 2014 12:56 am
Location: Netherlands / Nīderlande

Re: Useful scripts

Mon Nov 23, 2020 3:21 pm

Source: viewtopic.php?f=9&t=152632&p=796712&hilit=63+kb#p759427
# Written by Shumkov
# Adapted by blacklister
# 20201025
{
/ip firewall address-list
:local update do={
 :do {
 :local result [/tool fetch url=$url as-value output=user]; :if ($result->"downloaded" != "63") do={ :local data ($result->"data")
  :do { remove [find list=$blacklist] } on-error={}
   :while ([:len $data]!=0) do={
      :if ([:pick $data 0 [:find $data "\n"]]~"^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}") do={
      :do {add list=$blacklist address=([:pick $data 0 [:find $data $delimiter]].$cidr) timeout=7d} on-error={}
      }
   :set data [:pick $data ([:find $data "\n"]+1) [:len $data]]
   } ;  :log warning "Imported address list < $blacklist> from file: $url"
   } else={:log warning "Address list: <$blacklist>, downloaded file to big: $url" }
 } on-error={:log warning "Address list <$blacklist> update failed"}
}

$update url=https://lists.blocklist.de/lists/ftp.txt blacklist="blackAddressList" delimiter=("\n") 
}
It will import ftp.txt from https://lists.blocklist and put in the address-list with the name blackAddressList. The file read uses Newlines "\n" to indicate the end of line.

My version of the Sumkov won't try to import files bigger than 63KB and does some logging. By design you can add more lines to get download and import you will see how that is done in the thread I linked to.
 
cldmgzn
just joined
Posts: 5
Joined: Wed Nov 04, 2020 9:16 am

Re: Useful scripts

Mon Nov 23, 2020 4:07 pm

Loading the lines directly in Address list is hard.

There is a chance to create a .rsc file from the IP list https://lists.blocklist.de/lists/ftp.txt (every IP is on a new line)?
 
msatter
Forum Guru
Forum Guru
Posts: 2935
Joined: Tue Feb 18, 2014 12:56 am
Location: Netherlands / Nīderlande

Re: Useful scripts

Mon Nov 23, 2020 4:24 pm

Please open a new topic about this because this thread is about Useful scripts and you want something specific. You could also use search because this is talked about many many times and yes you can use HUGE lists, but you have to prepare them first on a computer and then import it.

See: viewtopic.php?f=2&t=157591
 
User avatar
Larsa
Forum Guru
Forum Guru
Posts: 1456
Joined: Sat Aug 29, 2015 7:40 pm
Location: The North Pole, Santa's Workshop

Re: Useful scripts

Mon Nov 23, 2020 4:28 pm

In this case I'll use a smaller ip list: https://lists.blocklist.de/lists/ftp.txt

For those interested, there is a pretty good overview and current status of the various ip block lists at http://iplists.firehol.org/. Most lists are clickable for detailed information and are downloadable at https://github.com/firehol/blocklist-ipsets
 
Sallysally
just joined
Posts: 1
Joined: Thu Jan 21, 2021 11:13 am

Router OS

Thu Jan 21, 2021 11:20 am

Router OS automates network operations with streamlined precision, furthers operational efficiency, and frees up valuable time and resources for top-line growth opportunities.
 
User avatar
SpiderMattX
just joined
Posts: 6
Joined: Fri Jan 29, 2021 1:43 pm
Location: Indiana, United States

Automatic Bandwidth Testing Script

Sat Jan 30, 2021 8:29 pm

This is the first revision of my automated bandwidth testing script. It will run 4 sequential tests, TCP downstream, TCP upstream, UDP downstream, and UDP upstream. You may configure the duration for each test by protocol. You may also configure the RX and TX packet sizes for UDP tests. Depending on how your network is setup, you may have to tweak the beginning of the script to obtain the btest server address. It is currently setup to use the gateway address of the default route.

Once all tests have been completed, the results are logged to the system logging facility. From there it is up to you how you want to aggregate the information. We use syslog servers for message convergence which seems to be the most ideal for us so far. A basic way to get started with it would be to use the scheduler feature to schedule an execution of this script.

Be cautious of your scheduling strategy! It's important to remember that these tests can often saturate an Ethernet link depending on it's capacity and the testing equipment capabilities.

I am going to use this for automated testing of a fixed wireless network in the big picture. My next revision will have a scheduling component to offset these tests across a network automatically to prevent excessive link saturation and skewed test results. Let me know if you're interested and I'll be sure to share it's progress back.
{
	:local timestampLabel "$[/system clock get date] $[/system clock get time]"
	:local routeID [/ip route find dst-address=0.0.0.0/0]

	# BTest Server Settings
	:local btestServer { username="btest" ; password="Ek4@C;f%(-(P3+~5" ; hostname=[/ip route get $routeID value-name=gateway] }

	# TCP Test Settings
	:local tcpOptions { duration="5s" ; "updateInterval"="1s" }

	# UDP Test Settings
	:local udpOptions { duration="5s" ; "updateInterval"="1s" ; "rxSize"=1000 ; "txSize"=1000 }

	# Test Results
	:local tcpRxTest { start="" ; updated="" ; end="" ; peak=0 ; current=0 ; average=0 ; "lostPackets"=0 ; size=0 }
	:local tcpTxTest { start="" ; updated="" ; end="" ; peak=0 ; current=0 ; average=0 ; "lostPackets"=0 ; size=0 }
	:local udpRxTest { start="" ; updated="" ; end="" ; peak=0 ; current=0 ; average=0 ; "lostPackets"=0 ; size=0 }
	:local udpTxTest { start="" ; updated="" ; end="" ; peak=0 ; current=0 ; average=0 ; "lostPackets"=0 ; size=0 }

	# TCP Downstream Test

	:set ($tcpRxTest->"start") "$[/system clock get date] $[/system clock get time]"
	
	/tool bandwidth-test ($btestServer->"hostname") protocol=tcp random-data=no direction=receive duration=($tcpOptions->"duration") user=($btestServer->"username") password=($btestServer->"password") do={

		:set ($tcpRxTest->"updated") "$[/system clock get date] $[/system clock get time]"
		:set ($tcpRxTest->"current") ($"rx-current" / 1000000)
		:set ($tcpRxTest->"average") ($"rx-total-average" / 1000000)
		:set ($tcpRxTest->"lostPackets") ($"lost-packets" / 1)
		:set ($tcpRxTest->"size") ($"rx-size" / 1)

		:if ( ($tcpRxTest->"peak") < ($tcpRxTest->"current") ) do={
			:set ($tcpRxTest->"peak") ($tcpRxTest->"current")
		}
	}
	
	:set ($tcpRxTest->"end") "$[/system clock get date] $[/system clock get time]"

	# TCP Upstream Test

	:set ($tcpTxTest->"start") "$[/system clock get date] $[/system clock get time]"
	
	/tool bandwidth-test ($btestServer->"hostname") protocol=tcp random-data=no direction=transmit duration=($tcpOptions->"duration") user=($btestServer->"username") password=($btestServer->"password") do={

		:set ($tcpTxTest->"updated") "$[/system clock get date] $[/system clock get time]"
		:set ($tcpTxTest->"current") ($"tx-current" / 1000000)
		:set ($tcpTxTest->"average") ($"tx-total-average" / 1000000)
		:set ($tcpTxTest->"lostPackets") ($"lost-packets" / 1)
		:set ($tcpTxTest->"size") ($"tx-size" / 1)

		:if ( ($tcpTxTest->"peak") < ($tcpTxTest->"current") ) do={
			:set ($tcpTxTest->"peak") ($tcpTxTest->"current")
		}
	}

	:set ($tcpTxTest->"end") "$[/system clock get date] $[/system clock get time]"
	
	# UDP Downstream Test

	:set ($udpRxTest->"start") "$[/system clock get date] $[/system clock get time]"
	
	/tool bandwidth-test ($btestServer->"hostname") protocol=udp random-data=no direction=receive duration=($udpOptions->"duration") user=($btestServer->"username") password=($btestServer->"password") remote-udp-tx-size=($udpOptions->"rxSize") do={

		:set ($udpRxTest->"updated") "$[/system clock get date] $[/system clock get time]"
		:set ($udpRxTest->"current") ($"rx-current" / 1000000)
		:set ($udpRxTest->"average") ($"rx-total-average" / 1000000)
		:set ($udpRxTest->"lostPackets") ($"lost-packets" / 1)
		:set ($udpRxTest->"size") ($"rx-size" / 1)

		:if ( ($udpRxTest->"peak") < ($udpRxTest->"current") ) do={
			:set ($udpRxTest->"peak") ($udpRxTest->"current")
		}
	}

	:set ($udpRxTest->"end") "$[/system clock get date] $[/system clock get time]"
	
	# UDP Upstream Test

	:set ($udpTxTest->"start") "$[/system clock get date] $[/system clock get time]"
	
	/tool bandwidth-test ($btestServer->"hostname") protocol=udp random-data=no direction=transmit duration=($udpOptions->"duration") user=($btestServer->"username") password=($btestServer->"password") local-udp-tx-size=($udpOptions->"txSize") do={

		:set ($udpTxTest->"updated") "$[/system clock get date] $[/system clock get time]"
		:set ($udpTxTest->"current") ($"tx-current" / 1000000)
		:set ($udpTxTest->"average") ($"tx-total-average" / 1000000)
		:set ($udpTxTest->"lostPackets") ($"lost-packets" / 1)
		:set ($udpTxTest->"size") ($"tx-size" / 1)

		:if ( ($udpTxTest->"peak") < ($udpTxTest->"current") ) do={
			:set ($udpTxTest->"peak") ($udpTxTest->"current")
		}
	}

	:set ($udpTxTest->"end") "$[/system clock get date] $[/system clock get time]"
	
	# Report results via system log facility, syslog aggregation will handle the rest
	
	# Log TCP Test Results
	:log info ("Bandwidth test of TCP Downstream; Started: " . ($tcpRxTest->"start") . "; Completed: " . ($tcpRxTest->"end") . "; Server: " . ($btestServer->"hostname") . "; Peak: " . ($tcpRxTest->"peak") . " Mbps; Average: " . ($tcpRxTest->"average") . " Mbps; Duration: " . ($tcpOptions->"duration") . ";")
	:log info ("Bandwidth test of TCP Upstream; Started: " . ($tcpTxTest->"start") . "; Completed: " . ($tcpTxTest->"end") . "; Server: " . ($btestServer->"hostname") . "; Peak: " . ($tcpTxTest->"peak") . " Mbps; Average: " . ($tcpTxTest->"average") . " Mbps; Duration: " . ($tcpOptions->"duration") . ";")

	# Log UDP Test Results
	:log info ("Bandwidth test of UDP Downstream; Started: " . ($udpRxTest->"start") . "; Completed: " . ($udpRxTest->"end") . "; Server: " . ($btestServer->"hostname") . "; Peak: " . ($udpRxTest->"peak") . " Mbps; Average: " . ($udpRxTest->"average") . " Mbps; Packet Size: " . ($udpRxTest->"size") . "; Duration: " . ($udpOptions->"duration") . "; Lost Packets: " . ($udpRxTest->"lostPackets") . ";")
	:log info ("Bandwidth test of UDP Upstream; Started: " . ($udpTxTest->"start") . "; Completed: " . ($udpTxTest->"end") . "; Server: " . ($btestServer->"hostname") . "; Peak: " . ($udpTxTest->"peak") . " Mbps; Average: " . ($udpTxTest->"average") . " Mbps; Packet Size: " . ($udpTxTest->"size") . "; Duration: " . ($udpOptions->"duration") . ";")
}
 
User avatar
SpiderMattX
just joined
Posts: 6
Joined: Fri Jan 29, 2021 1:43 pm
Location: Indiana, United States

Automatic System Upgrade / Downgrade

Sun Jan 31, 2021 5:33 pm

This is my second revision of my automatic update script. It's intended purpose is to automatically handle the standard two-step process for updating both RouterOS packages and RouterBoard firmware. Since the process of upgrading and downgrading differ slightly, I created this script to deal with that scenario. This now allows me to easily rollback software updates that seem to cause trouble in the network.


Currently this has one user configurable option which is ($config->"targetVersion"). Set this to the release version you want to change to. Then you just need to schedule this script to run twice, allowing at least a few minutes in between executions. If your device has a slow connection to the Internet for downloading the package, you should compensate for this as well in the delay. You don't want the second execution to be missed because the device was in a reboot state from the first execution or delayed by a long download. I am considering building in a third stage of execution so that downloading the update early is the first stage.


This script depends on another script named "func_parseVersionString".


Source for func_parseVersionString:

:local version { full="$1"; major=0; minor=0; patch=0 }
:local segment 1
:local match "$1"
:local length [:len $match]

:while ($segment < 4) do={
	:local part ""
	:local result [:find $match "."]

	:if ([:typeof $result] = "num") do={
		:set part [:pick $match 0 $result]
	} else={
		:set part [:pick $match 0 $length]
	}

	:if ($segment=1) do={
		:set ($version->"major") [:tonum $part]
	}

	:if ($segment=2) do={
		:set ($version->"minor") [:tonum $part]
	}

	:if ($segment=3) do={
		:set ($version->"patch") [:tonum $part]
	}

	:if ([:typeof $result] = "num") do={
		:set segment ($segment + 1)
		:set match [:pick $match ($result + 1) $length]
        :set length [:len $match]
	} else={
		:set segment 4
	}
}

:return $version

Source for system-auto-update:

:local config { "targetVersion"="6.47.4"; architecture=[/system resource get architecture-name]; "packageURL"="" }

:local parseVersionString [:parse [/system script get func_parseVersionString source]]

:local packageVersion "$[/system package get system version]"
:local routerBoardVersion "$[/system routerboard get current-firmware]"

:local packageMeta [$parseVersionString $packageVersion]
:local routerBoardMeta [$parseVersionString $routerBoardVersion]
:local targetMeta [$parseVersionString ($config->"targetVersion")]

:set ($config->"packageURL") ("https://download.mikrotik.com/routeros/" . ($config->"targetVersion") . "/routeros-" . ($config->"architecture") . "-" . ($config->"targetVersion") . ".npk")

if (($packageMeta->"full") != ($targetMeta->"full")) do={
	:log info ("Package version (" . ($packageMeta->"full") . ") does not match target version (" . ($targetMeta->"full") . "). Downloading package file from " . ($config->"packageURL") .".")
	/tool fetch url=($config->"packageURL");

	if (($packageMeta->"major") > ($targetMeta->"major") || ($packageMeta->"minor") > ($targetMeta->"minor") || ($packageMeta->"patch") > ($targetMeta->"patch")) do={
		:log info ("Target package version (" . ($targetMeta->"full") . ") is older than current package version (" . ($packageMeta->"full") . "). Executing downgrade...");
		/system package downgrade;
	} else={
		:log info ("Target package version (" . ($targetMeta->"full") . ") is newer than current package version (" . ($packageMeta->"full") . "). Executing upgrade...");
		/system reboot;
	}
} else={
	if (($routerBoardMeta->"full") != ($packageMeta->"full")) do={
		:log info ("RouterBoard firmware (" . ($routerBoardMeta->"full") . ") does not match target version (" . ($targetMeta->"full") . "). Executing update...");
		/system routerboard upgrade;
		/system reboot;
	} else={
		:log info ("Software and firmware currently match target version (" . ($targetMeta->"full") . "). No changes necessary.");
	}
}

Enjoy!
 
User avatar
SpiderMattX
just joined
Posts: 6
Joined: Fri Jan 29, 2021 1:43 pm
Location: Indiana, United States

Automatic Bandwidth Testing Script Version 1.1

Sun Jan 31, 2021 5:50 pm

This is my updated automatic bandwidth testing script. It includes updated date and time formatting and removes bad information references. This script will run 4 sequential tests, TCP downstream, TCP upstream, UDP downstream, and UDP upstream. Once all tests have been completed, the results are logged to the system logging facility. From there it is up to you how you want to aggregate the information. We use syslog servers for message convergence which seems to be the most ideal for us so far. A basic way to get started with it would be to use the scheduler feature to schedule an execution of this script.

Be cautious of your scheduling strategy! It's important to remember that these tests can often saturate an Ethernet link depending on it's capacity and the testing equipment capabilities.

This has some user configurable options. You can configure the "username" and "password" elements of the btestServer array. You can configure the test duration independently for both TCP and UDP tests via the "duration" element of the tcpOptions and udpOptions arrays. You can configure the test update interval independently for both TCP and UDP tests via the "updateInterval" element of the tcpOptions and udpOptions arrays. Additionally, you can configure the receive and transmit packet size for the UDP tests via the "rxSize" and "txSize" elements of the udpOptions array.

Depending on how your network is setup, you may have to tweak the beginning of the script to obtain the btest server address. It is currently setup to use the gateway address of the default route. I am going to use this for automated testing of a fixed wireless network in the big picture. My next revision will have a scheduling component to offset these tests across a network automatically to prevent excessive link saturation and skewed test results. Let me know if you're interested and I'll be sure to share it's progress back.


This script depends on other scripts named "func_getCurrentDateTime" and "func_formatDateTime".


Source for func_getCurrentDateTime:
:local months {"jan"="01";"feb"="02";"mar"="03";"apr"="04";"may"="05";"jun"="06";"jul"="07";"aug"="08";"sep"="09";"oct"=10;"nov"=11;"dec"=12}
:local fullDate [/system clock get date]
:local fullTime [/system clock get time]
:local dateTime { "fullDate"=$fullDate ; "fullTime"=$fullTime ; month=[ :pick $fullDate 0 3 ] ; mm=0 ; day=[ :pick $fullDate 4 6 ] ; year=[ :pick $fullDate 7 11 ] ; hour=[ :pick $fullTime 0 2 ] ; hh=[ :pick $fullTime 0 2 ] ; minute=[ :pick $fullTime 3 5 ] ; second=[ :pick $fullTime 6 8 ] ; meridiem="AM" }

:local month ($dateTime->"month")

:set ($dateTime->"mm") ($months->$month)

:if ($dateTime->"hour" > 12) do={
	:set ($dateTime->"meridiem") "PM"
	:set ($dateTime->"hh") (($dateTime->"hour") - 12)
}

:return ($dateTime)

Source for func_formatDateTime:

:local getCurrentDateTime [:parse [/system script get func_getCurrentDateTime source]]
:local dateTime [$getCurrentDateTime]
:return (($dateTime->"year") . "-" . ($dateTime->"mm") . "-" . ($dateTime->"day") . " @ " . ($dateTime->"hh") . ":" . ($dateTime->"minute") . " " . ($dateTime->"meridiem"))

Source for tools-automatic-btest:

{
	:local formatDateTime [:parse [/system script get func_formatDateTime source]]
	:local routeID [/ip route find dst-address=0.0.0.0/0]

	# BTest Server Settings
	:local btestServer { username="btest" ; password="Ek4@C;f%(-(P3+~5" ; hostname=[/ip route get $routeID value-name=gateway] }

	# TCP Test Settings
	:local tcpOptions { duration="2s" ; "updateInterval"="1s" }

	# UDP Test Settings
	:local udpOptions { duration="2s" ; "updateInterval"="1s" ; "rxSize"=1000 ; "txSize"=1000 }

	# Test Results
	:local tcpRxTest { start="" ; updated="" ; end="" ; peak=0 ; current=0 ; average=0 }
	:local tcpTxTest { start="" ; updated="" ; end="" ; peak=0 ; current=0 ; average=0 }
	:local udpRxTest { start="" ; updated="" ; end="" ; peak=0 ; current=0 ; average=0 ; size=0 ;  "lostPackets"=0 }
	:local udpTxTest { start="" ; updated="" ; end="" ; peak=0 ; current=0 ; average=0 ; size=0 }

	# TCP Downstream Test

	:set ($tcpRxTest->"start") [$formatDateTime]
	
	/tool bandwidth-test ($btestServer->"hostname") protocol=tcp random-data=no direction=receive duration=($tcpOptions->"duration") user=($btestServer->"username") password=($btestServer->"password") do={

		:set ($tcpRxTest->"updated") [$formatDateTime]
		:set ($tcpRxTest->"current") ($"rx-current" / 1000000)
		:set ($tcpRxTest->"average") ($"rx-total-average" / 1000000)

		:if ( ($tcpRxTest->"peak") < ($tcpRxTest->"current") ) do={
			:set ($tcpRxTest->"peak") ($tcpRxTest->"current")
		}
	}
	
	:set ($tcpRxTest->"end") [$formatDateTime]

	# Log Test Results
	:log info ("Bandwidth test of TCP Downstream; Started: " . ($tcpRxTest->"start") . "; Completed: " . ($tcpRxTest->"end") . "; Server: " . ($btestServer->"hostname") . "; Peak: " . ($tcpRxTest->"peak") . " Mbps; Average: " . ($tcpRxTest->"average") . " Mbps; Duration: " . ($tcpOptions->"duration") . ";")
	
	# TCP Upstream Test

	:set ($tcpTxTest->"start") [$formatDateTime]
	
	/tool bandwidth-test ($btestServer->"hostname") protocol=tcp random-data=no direction=transmit duration=($tcpOptions->"duration") user=($btestServer->"username") password=($btestServer->"password") do={

		:set ($tcpTxTest->"updated") [$formatDateTime]
		:set ($tcpTxTest->"current") ($"tx-current" / 1000000)
		:set ($tcpTxTest->"average") ($"tx-total-average" / 1000000)

		:if ( ($tcpTxTest->"peak") < ($tcpTxTest->"current") ) do={
			:set ($tcpTxTest->"peak") ($tcpTxTest->"current")
		}
	}

	:set ($tcpTxTest->"end") [$formatDateTime]
	
	# Log Test Results
	:log info ("Bandwidth test of TCP Upstream; Started: " . ($tcpTxTest->"start") . "; Completed: " . ($tcpTxTest->"end") . "; Server: " . ($btestServer->"hostname") . "; Peak: " . ($tcpTxTest->"peak") . " Mbps; Average: " . ($tcpTxTest->"average") . " Mbps; Duration: " . ($tcpOptions->"duration") . ";")
	
	# UDP Downstream Test

	:set ($udpRxTest->"start") [$formatDateTime]
	
	/tool bandwidth-test ($btestServer->"hostname") protocol=udp random-data=no direction=receive duration=($udpOptions->"duration") user=($btestServer->"username") password=($btestServer->"password") remote-udp-tx-size=($udpOptions->"rxSize") do={

		:set ($udpRxTest->"updated") [$formatDateTime]
		:set ($udpRxTest->"current") ($"rx-current" / 1000000)
		:set ($udpRxTest->"average") ($"rx-total-average" / 1000000)
		:set ($udpRxTest->"lostPackets") ($"lost-packets" / 1)
		:set ($udpRxTest->"size") ($"rx-size" / 1)

		:if ( ($udpRxTest->"peak") < ($udpRxTest->"current") ) do={
			:set ($udpRxTest->"peak") ($udpRxTest->"current")
		}
	}

	:set ($udpRxTest->"end") [$formatDateTime]
	
	# Log Test Results
	:log info ("Bandwidth test of UDP Downstream; Started: " . ($udpRxTest->"start") . "; Completed: " . ($udpRxTest->"end") . "; Server: " . ($btestServer->"hostname") . "; Peak: " . ($udpRxTest->"peak") . " Mbps; Average: " . ($udpRxTest->"average") . " Mbps; Packet Size: " . ($udpRxTest->"size") . "; Duration: " . ($udpOptions->"duration") . "; Lost Packets: " . ($udpRxTest->"lostPackets") . ";")
	
	# UDP Upstream Test

	:set ($udpTxTest->"start") [$formatDateTime]
	
	/tool bandwidth-test ($btestServer->"hostname") protocol=udp random-data=no direction=transmit duration=($udpOptions->"duration") user=($btestServer->"username") password=($btestServer->"password") local-udp-tx-size=($udpOptions->"txSize") do={

		:set ($udpTxTest->"updated") [$formatDateTime]
		:set ($udpTxTest->"current") ($"tx-current" / 1000000)
		:set ($udpTxTest->"average") ($"tx-total-average" / 1000000)
		:set ($udpTxTest->"size") ($"tx-size" / 1)

		:if ( ($udpTxTest->"peak") < ($udpTxTest->"current") ) do={
			:set ($udpTxTest->"peak") ($udpTxTest->"current")
		}
	}

	:set ($udpTxTest->"end") [$formatDateTime]
	
	# Log Test Results
	:log info ("Bandwidth test of UDP Upstream; Started: " . ($udpTxTest->"start") . "; Completed: " . ($udpTxTest->"end") . "; Server: " . ($btestServer->"hostname") . "; Peak: " . ($udpTxTest->"peak") . " Mbps; Average: " . ($udpTxTest->"average") . " Mbps; Packet Size: " . ($udpTxTest->"size") . "; Duration: " . ($udpOptions->"duration") . ";")
}

Enjoy!
 
User avatar
SpiderMattX
just joined
Posts: 6
Joined: Fri Jan 29, 2021 1:43 pm
Location: Indiana, United States

Version String Parsing Function

Sun Jan 31, 2021 6:09 pm

This is my first revision of a method used to parse a standard software version string (i.e. "6.47.4" or "6.48"). As a result, it produces an array with four named elements; "full" which is set to the original input string, "major" which is set to the first segment of the version string, "minor" which is set to the second segment of the version string, and "patch" which is set to the third segment of the version string. The values for "major", "minor", and "patch" are all converted to number types automatically for use with Mathematical operators.


One way to use this function is to import it into your script like this:
:local parseVersionString [:parse [/system script get func_parseVersionString source]]

Then you can call it like this:
:local packageMeta [$parseVersionString "6.47.4"]
:put ("Full Version: " . ($packageMeta->"full"))
:put ("Major Version: " . ($packageMeta->"major"))
:put ("Minor Version: " . ($packageMeta->"minor"))
:put ("Patch Version: " . ($packageMeta->"patch"))

If you input "6.47.4", you get { full="6.47.4"; major=6; minor=47; patch=4 }

If you input "6.48", you get { full="6.48"; major=6; minor=48; patch=0 }

If you input "7", you get { full="7"; major=7; minor=0; patch=0 }


Source for func_parseVersionString:

:local version { full="$1"; major=0; minor=0; patch=0 }
:local segment 1
:local match "$1"
:local length [:len $match]

:while ($segment < 4) do={
	:local part ""
	:local result [:find $match "."]

	:if ([:typeof $result] = "num") do={
		:set part [:pick $match 0 $result]
	} else={
		:set part [:pick $match 0 $length]
	}

	:if ($segment=1) do={
		:set ($version->"major") [:tonum $part]
	}

	:if ($segment=2) do={
		:set ($version->"minor") [:tonum $part]
	}

	:if ($segment=3) do={
		:set ($version->"patch") [:tonum $part]
	}

	:if ([:typeof $result] = "num") do={
		:set segment ($segment + 1)
		:set match [:pick $match ($result + 1) $length]
        :set length [:len $match]
	} else={
		:set segment 4
	}
}

:return $version

Enjoy!
 
User avatar
v1nce
just joined
Posts: 2
Joined: Sun Apr 25, 2021 12:27 am
Location: Philippines

Re: Useful scripts

Tue May 04, 2021 11:08 pm

NEED HELP! I've been working and searching for solutions about this.
This script will do automatic simple queue adding with child queue which is for bandwidth management using mangle rules.
But what I want is to automatically update everything with same user.
Ex. If I have 10mbps, then there are 2 users using the same credentials. I want them to have 5mbps each. even the child queues will be divided depends on how many devices where the user credential was used.
# ********** \\\\\\\\\\ === On Login === ////////// ********** #
:local loginUser $user;
:local a "20000";
:local b "15000"
:local c "5000"
:local devices [/ip hotspot active print count-only where user="$loginUser"];
:set $a ($a/$devices);
:set $b ($b/$devices);
:set $c ($c/$devices);

/queue simple
add max-limit=($a."k/".$a."k") name=($loginUser." - ".$address) parent="Hotspot Connection" target=$address
add limit-at=64k/64k max-limit=($a."k/".$a."k") name=($loginUser." : ".$address." - speedtest") packet-marks=speedtest-pkt parent=($loginUser." - ".$address) priority=2/2 target=""
add limit-at=64k/64k max-limit=($b."k/".$b."k") name=($loginUser." : ".$address." - stream") packet-marks=streaming-pkt parent=($loginUser." - ".$address) target=""
add limit-at=64k/64k max-limit=($b."k/".$b."k") name=($loginUser." : ".$address." - all traffic") packet-marks=all-traffic parent=($loginUser." - ".$address) priority=3/3 target=""
add limit-at=64k/64k max-limit=($c."k/".$c."k") name=($loginUser." : ".$address." - mbl gaming") packet-marks=mobile-gaming-pkt parent=($loginUser." - ".$address) priority=1/1 target=""
add limit-at=64k/64k max-limit=($b."k/".$b."k") name=($loginUser." : ".$address." - pc gaming") packet-marks=pc-gaming-pkt parent=($loginUser." - ".$address) priority=1/2 target=""

:foreach QReset in=[/queue simple find active=$loginUser] do={
	/queue simple 
	set $QReset max-limit=($a."k/".$a."k")
}

# ********** \\\\\\\\\\ === On Logout === ////////// ********** #
:local loginUser $user;

/queue simple
remove [find name=($loginUser." - ".$address)]
remove [find name=($loginUser." : ".$address." - speedtest")]
remove [find name=($loginUser." : ".$address." - stream")]
remove [find name=($loginUser." : ".$address." - all traffic")]
remove [find name=($loginUser." : ".$address." - mbl gaming")]
remove [find name=($loginUser." : ".$address." - pc gaming")]
 
dmyers6978
just joined
Posts: 4
Joined: Fri Jan 26, 2018 4:15 pm

Re: Useful scripts

Mon Jun 21, 2021 6:20 pm

Here is a function that I wrote that takes in some parameters and outputs the results from the "/tool snmp-get" command in a usable way. Without doing some manipulation you can view the result but can't do anything with it. this returns an array that can be used to make logical decisions on the router. This works on version 6.46.8 and probably more, just nothing below this version.
#Function to parse SNMP-get on mikrotik routers
#PARAMS
#ip - the IP to poll
#community - the SNMP community for the device
#oid - the OID to retrieve from the device
#ver- the SNMP version to use
#call the function by using 
#:global ip "x.x.x.x"; - set the IP variable
#:global community "public"; - set the community variable
#:global oid "x.x.x.x.x.x.x.x.x.x.x.x.x"; - set the OID variable
#global version "x"; - Choices are as follows: 1, 2c, 3
#:global result [$snmpGet ip=$ip community=$community oid=$oid version=$version]; retrieve and parse the result
:global snmpGet do={
:global address $ip;
:global comm $community;
:global id $oid;
:global ver $version;
:execute script={
/tool snmp-get address=$address community=$comm version=$ver oid=$id} file=temp.txt;
:while ([:len [/file find where name="temp.txt"]] = 0) do={
:delay 1s;
}
:while ([/file get temp.txt contents] = "") do={
:delay 1s;
}
:local res [:pick [/file get temp.txt contents] 81 [:len [/file get temp.txt contents]]];
if ([:pick $res [find "VALUE"]] > 0) do={
:local prev "";
:local str "";
:local count 0;
:local arr "";
:for i from=0 to=([:len $res] - 1) do={ 
:local char [:pick $res $i]
:if ($char = " ") do={
:if ($prev != " " && $prev != ";" && $prev != "") do={
:set $char ";";
:set $count ($count + 1);
} else={
:set $char "";
}
}
:if ($count <= 3) do={
:set $str ($str . $char);
}
:if ($char = ";") do={
:if ($arr = "") do={
:set $arr [:pick $str 0 ([:len $str]-1)];
} else={
:set $arr ($arr, [:pick $str 0 ([:len $str]-1)]);
}
:set $str "";
}
:set $prev $char;
}
:if ([:len [/file find where name="temp.txt"]] > 0) do={
/file remove [find where name="temp.txt"];
}
:if ([:len [/system script environment find where name="address"]] > 0) do={
/system script environment remove [find where name="address"];
}
:if ([:len [/system script environment find where name="comm"]] > 0) do={
/system script environment remove [find where name="comm"];
}
:if ([:len [/system script environment find where name="id"]] > 0) do={
/system script environment remove [find where name="id"];
}
:if ([:len [/system script environment find where name="ver"]] > 0) do={
/system script environment remove [find where name="ver"];
}
:if ([:len $arr] != 3) do={
:return "Invalid OID, community, IP, or version.";
} else={
:return $arr;
}
} else={
:return "Error retrieving SNMP value.";
}
}
 
User avatar
Jotne
Forum Guru
Forum Guru
Posts: 3334
Joined: Sat Dec 24, 2016 11:17 am
Location: Magrathean

Re: Useful scripts

Mon Jul 19, 2021 3:14 pm

Not sure how to use the script so can you post some detail on how to use it?
Here is a cleaned up version with ; removed (only needed between multiple command on same line) and tab inserted to see where the loop is.
Do you need all this global variable, can the not be local?
#Function to parse SNMP-get on mikrotik routers
#PARAMS
#ip - the IP to poll
#community - the SNMP community for the device
#oid - the OID to retrieve from the device
#ver- the SNMP version to use
#call the function by using 
#:global ip "x.x.x.x" - set the IP variable
#:global community "public" - set the community variable
#:global oid "x.x.x.x.x.x.x.x.x.x.x.x.x" - set the OID variable
#global version "x"; - Choices are as follows: 1, 2c, 3
#:global result [$snmpGet ip=$ip community=$community oid=$oid version=$version]; retrieve and parse the result
:global snmpGet do={
	:global address $ip
	:global comm $community
	:global id $oid
	:global ver $version
	:execute script={
		/tool snmp-get address=$address community=$comm version=$ver oid=$id
	} file=temp.txt
	:while ([:len [/file find where name="temp.txt"]] = 0) do={
		:delay 1s
	}
	:while ([/file get temp.txt contents] = "") do={
		:delay 1s
	}
	:local res [:pick [/file get temp.txt contents] 81 [:len [/file get temp.txt contents]]]
	if ([:pick $res [find "VALUE"]] > 0) do={
		:local prev ""
		:local str ""
		:local count 0
		:local arr ""
		:for i from=0 to=([:len $res] - 1) do={ 
			:local char [:pick $res $i]
			:if ($char = " ") do={
				:if ($prev != " " && $prev != ";" && $prev != "") do={
					:set $char ";"
					:set $count ($count + 1)
				} else={
					:set $char ""
				}
			}
			:if ($count <= 3) do={
				:set $str ($str . $char)
			}
			:if ($char = ";") do={
				:if ($arr = "") do={
					:set $arr [:pick $str 0 ([:len $str]-1)]
				} else={
					:set $arr ($arr, [:pick $str 0 ([:len $str]-1)])
				}
				:set $str ""
			}
			:set $prev $char
		}
		:if ([:len [/file find where name="temp.txt"]] > 0) do={
			/file remove [find where name="temp.txt"]
		}
		:if ([:len [/system script environment find where name="address"]] > 0) do={
			/system script environment remove [find where name="address"]
		}
		:if ([:len [/system script environment find where name="comm"]] > 0) do={
			/system script environment remove [find where name="comm"]
		}
		:if ([:len [/system script environment find where name="id"]] > 0) do={
			/system script environment remove [find where name="id"]
		}
		:if ([:len [/system script environment find where name="ver"]] > 0) do={
			/system script environment remove [find where name="ver"]
		}
		:if ([:len $arr] != 3) do={
			:return "Invalid OID, community, IP, or version."
		} else={
			:return $arr
		}
	} else={
		:return "Error retrieving SNMP value."
	}
}
An this has removed some unneeded double code using foreach instead. PS Not tested:
#Function to parse SNMP-get on mikrotik routers
#PARAMS
#ip - the IP to poll
#community - the SNMP community for the device
#oid - the OID to retrieve from the device
#ver- the SNMP version to use
#call the function by using 
#:global ip "x.x.x.x" - set the IP variable
#:global community "public" - set the community variable
#:global oid "x.x.x.x.x.x.x.x.x.x.x.x.x" - set the OID variable
#global version "x"; - Choices are as follows: 1, 2c, 3
#:global result [$snmpGet ip=$ip community=$community oid=$oid version=$version]; retrieve and parse the result
:global snmpGet do={
	:global address $ip
	:global comm $community
	:global id $oid
	:global ver $version
	:execute script={
		/tool snmp-get address=$address community=$comm version=$ver oid=$id
	} file=temp.txt
	:while ([:len [/file find where name="temp.txt"]] = 0) do={
		:delay 1s
	}
	:while ([/file get temp.txt contents] = "") do={
		:delay 1s
	}
	:local res [:pick [/file get temp.txt contents] 81 [:len [/file get temp.txt contents]]]
	if ([:pick $res [find "VALUE"]] > 0) do={
		:local prev ""
		:local str ""
		:local count 0
		:local arr ""
		:for i from=0 to=([:len $res] - 1) do={ 
			:local char [:pick $res $i]
			:if ($char = " ") do={
				:if ($prev != " " && $prev != ";" && $prev != "") do={
					:set $char ";"
					:set $count ($count + 1)
				} else={
					:set $char ""
				}
			}
			:if ($count <= 3) do={
				:set $str ($str . $char)
			}
			:if ($char = ";") do={
				:if ($arr = "") do={
					:set $arr [:pick $str 0 ([:len $str]-1)]
				} else={
					:set $arr ($arr, [:pick $str 0 ([:len $str]-1)])
				}
				:set $str ""
			}
			:set $prev $char
		}
		:if ([:len [/file find where name="temp.txt"]] > 0) do={
			/file remove [find where name="temp.txt"]
		}
		:foreach test in={"address";"comm";"id";"ver"} do={
			:if ([:len [/system script environment find where name=$test]] > 0) do={
				/system script environment remove [find where name=$test]
			}
		}
		:if ([:len $arr] != 3) do={
			:return "Invalid OID, community, IP, or version."
		} else={
			:return $arr
		}
	} else={
		:return "Error retrieving SNMP value."
	}
}
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 12379
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Useful scripts

Mon Jul 19, 2021 3:34 pm

	:if ([:len [/file find where name="temp.txt"]] > 0) do={
			/file remove [find where name="temp.txt"]
		}
		:foreach test in={"address";"comm";"id";"ver"} do={
			:if ([:len [/system script environment find where name=$test]] > 0) do={
				/system script environment remove [find where name=$test]
			}
		}
can be reduced again to
(if tested on terminal put \ before $ )
/file remove [find where name="temp.txt"]
/system script environment remove [find where name~"^(address|comm|id|ver)$"]
Last edited by rextended on Mon Jul 19, 2021 3:43 pm, edited 3 times in total.
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 12379
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Useful scripts

Mon Jul 19, 2021 3:40 pm

The script can be used for read OID value(s) from other system (or unusefully to itself) because the standard function
/tool snmp-get address=192.168.1.60 community=public version=2c oid="1.3.6.1.4.1.14988.1.1.3.8.0"
can only print to video the results.

The script save the "video" inside a file, open and elaborate it to obtain a value usable on other scripts.

I hope I have explain what original author want do.
 
User avatar
merlinthemagic7
Frequent Visitor
Frequent Visitor
Posts: 59
Joined: Fri Sep 16, 2016 8:49 pm

Re: Useful scripts

Sat Oct 02, 2021 2:51 pm

Hi,

I made a library of functions that can all be invoked with an object like syntax.

https://github.com/merlinthemagic/MTM-R ... -Scripting

100s of functions, like string split, trim, replace, to uppercase, lowercase, or file functions like getContent, setContent, create, delete. Overcomes lots of the 4095 byte limitations when working with ROS files etc.

Documentation :
Tool examples: https://github.com/merlinthemagic/MTM-R ... tion/Tools
Ethernet example: https://github.com/merlinthemagic/MTM-R ... thernet.md
Look around the documentations folder, lots of good stuff you might need when scripting.
##Init:
/import flash/MTM/Facts.rsc;
:global MtmFacts;

##Examples:
##Epoch formatted time:
:local epoch [($MtmFacts->"execute") nsStr="getTools()->getTime()->getEpoch()->getCurrent()"];
:put ($epoch ); #1633096186

##Strings functions:
:local strTool [($MtmFacts->"execute") nsStr="getTools()->getStrings()"];

#trim
:local myStr " My string with leading and traling spaces and line breaks and chr returns \n\r";
:local result [($strTool->"trim") str=$myStr];
:put ($result); # "My string with leading and traling spaces and line breaks and chr returns";

#replace
:local myStr "Hello World";
:local find "Hell";
:local replace "gkTks";
:local result [($strTool->"replace") str=$myStr find=$find replace=$replace];
:put ($result); #"gkTkso World";

##IP
:local ipv4Tool [($MtmFacts->"execute") nsStr="getTools()->getParsing()->getIPv4()"];

:local addr "10.0.0.1";
:local result [($ipv4Tool >"isRFC1918") $addr];
:put ($result); #true


## literally 100s more. Also tons of model "objects", with methods for manipulating interfaces, dhcp servers, ips etc.
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 12379
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Useful scripts

Sat Oct 02, 2021 3:01 pm

Another one reinvented the wheel...

Is better what I do on my Snippets: one simply clear action without interdipendency than can broke someting (or all) if something is changed on "shared" functions...
 
User avatar
merlinthemagic7
Frequent Visitor
Frequent Visitor
Posts: 59
Joined: Fri Sep 16, 2016 8:49 pm

Re: Useful scripts

Sat Oct 02, 2021 3:17 pm

Another one reinvented the wheel...

Is better what I do on my Snippets: one simply clear action without interdipendency than can broke someting (or all) if something is changed on "shared" functions...
It would seem to me that snippets strewn throughout your code means you are refactoring everything when MT makes a change.

Code reuse is your friend, but hey you are more than welcome to contribute a test suite. Problem solved :)
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 12379
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Useful scripts

Sat Oct 02, 2021 3:42 pm

If MikroTik make a change, like syntax on v7, you have the probability that all your "system" stop working because interdipendance exist,
instead with my methods of scripting, are blocked only the script that have inside the change involved.
And are easily debuggable and fixable, because are all-in-one, without search problems on other scripts.

And about scripting, try to code with more readability
# from
:local classId "tool-directories";
:global MtmFacts;
:if ($MtmFacts = nil) do={
	:error ($classId.": MTM Factories not loaded");
}

# to
:local classId "tool-directories"
:global MtmFacts
:if ($MtmFacts = nil) do={ :error "$classId: MTM Factories not loaded" }

Apparently change nothing, but for readability are better.
 
User avatar
merlinthemagic7
Frequent Visitor
Frequent Visitor
Posts: 59
Joined: Fri Sep 16, 2016 8:49 pm

Re: Useful scripts

Sat Oct 02, 2021 3:58 pm

Good tip on readabillity, thx.

The idea behind a lib is that each method should abstract from the environment. E.g. like you said, v7 change in syntax, so the factory will check the version of ROS that is running and return an "instance" of the class that works.

The method names, parameters and returns must stay consistent across versions, but its transparent to the user. They update ROS and call the function like they used to and get their expected return value.

Take a look at the logic for getting the wireless interface factory: https://github.com/merlinthemagic/MTM-R ... es.rsc#L28

If the wireless package is not installed / enabled then loading a script that has any command like "/interface wireless" results in a fatal error when the interpreter runs (well before you call a method).

If you look at the logic you will see that the factory checks if there are wireless capabilities, if there is not it returns an "object" with identical methods that return results as expected when there are no wireless interfaces present. This means the user does not have to do a bunch of validations before they invoke a method call, they get exactly what they expect every time.

Same for v7, stuff will break until the methods have been updated to accommodate v7 syntax. Once that is done, the user again does not have to care what version they load the lib on. It just works. Does it get slower to load over time? yes, thats the life of a lib as it evolves more validations have to be made so the user does not have to.

Does this make sense?
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 12379
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Useful scripts

Sat Oct 02, 2021 4:05 pm

Ok, I write "someone reinvented the wheel",
but I do not say that your work (among the other dozen of scripts libraries like your) is useless.

Remembert than I'm everytime ready to help and learn from others, you included.

About:
:if ([/system package get [find name=wireless] disabled] = false) do= {
# >is false<
} else={
# >is true<
}

# that I would have written instead

/system package
:if ([get [find where name=wireless] disabled]) do={
# >is true<
} else={
# >is false<
}

1) On future do not exist wireless package, ROS7 is all-in-one

2) If wireless package is enabled, this not mean that wireless interface exist...
/interface
:if ([:len [find where type=wlan]] > 0) do={
# at least one wireless interface is present on board
} else={
# no wireless interfaces present on board
}
 
User avatar
merlinthemagic7
Frequent Visitor
Frequent Visitor
Posts: 59
Joined: Fri Sep 16, 2016 8:49 pm

Re: Useful scripts

Sat Oct 02, 2021 4:25 pm

Hi,

Appreciate the feedback!

The reason every command is executed in full, instead of breaking it up into path / command, was because initially i was uncertain how the state of the command execution shell was maintained across method calls.

It seems each { ... } is local in scope even for the shell, so both ways work. My concern was that if i left a method that invoked "/interface wireless", then the next method would pick up a shell with interface -> wireless as its working directory.
 
ALittleRusty
just joined
Posts: 1
Joined: Tue Feb 22, 2022 3:34 pm

Re: Useful scripts

Fri May 13, 2022 2:30 pm

Created a script that adds an address list to routing rules.
In my use case, I route Path of Exile game traffic through a VPN for latency purposes.
This works for any device on my lan.

First i mark VPN connections and routing.
/ip firewall mangle
add action=mark-connection chain=input in-interface="MyVPN" new-connection-mark=VPNConnection passthrough=yes
add action=mark-routing chain=output connection-mark=VPNConnection new-routing-mark=VPNRoute passthrough=no
Add default route with routing mark for VPN:
/ip route
add distance=1 gateway="MyVPN" routing-mark=VPNRoute
Then, I have a mangle rule that adds the dst-address to the address-list if traffic uses TCP port 6112
/ip firewall mangle
add action=add-dst-to-address-list address-list=POE address-list-timeout=none-static chain=prerouting comment="PoE Add IP to Address List" dst-port=6112 protocol=tcp
Then, i have a script that checks each entry of the address list and compares it to the rules under ip route rules to see if the address is already there. If it isnt there, it adds it.
/system script
add dont-require-permissions=no name="Dynamic Routes from address-list" owner=admin policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":foreach i in=[/ip firewall address-list\
    \_find disabled=no] do={\r\
    \n   :local poeIP [/ip firewall address-list get \$i address];\r\
    \n   :local poeROUTE [/ip route rule find comment=\$poeIP];\r\
    \n\r\
    \n  :if (\$poeROUTE != \"\") do={\r\
    \n      :log info message=\"\$poeIP already routed\"\r\
    \n} else= {\r\
    \n       /ip route rule add dst-address=\$poeIP src-address=\"10.0.32.0/24\" table=VPNRoute comment=\"\$poeIP\"\r\
    \n       :log info message=\"address \$poeIP route added\"\r\
    \n    }\r\
    \n}"
I then schedule this script to run however often i want.

5 notes
10.0.32.0/24 is my internal range. You should change this to your internal local range
I know this script spams your logs if you run it too often, so you can always remove the log message that responds if the route is already there. That way you will just see new IPs that are added.
I also realize this script takes all address-lists as long as its not disabled, so if you have multiple address lists, it will need to be adjusted. I am very new to scripts so I struggled to get this working as it is and since i only have one address list, i figured it's fine for me.
I also couldn't get it to work with just comparing the route rule dst-address, so ended up having to comment the rule when its added and comparing future checks to the comments.
In my case, when ever a new IP is found and added, the game disconnects me and i need to reconnect since that active connection was suddenly interrupted and forced through the VPN. This only happens when theres a new IP not yet routed, and any future connections to that IP will be routed correctly.

Im sure this could be used to match SIP traffic with dynamic / multiple IPs or any traffic where there is a range of IPs used for the service as long as it uses a specific port.
Good luck
 
ashpri
Member Candidate
Member Candidate
Posts: 154
Joined: Sun Oct 14, 2018 3:11 am

Re: Useful scripts

Sat Aug 13, 2022 6:11 pm

This script is courtesy of user ukzerosniper from viewtopic.php?p=951621

This script searches a route based on it's comment and sends an email based on status changes (UP / DOWN).

In my case my office has 3 WAN routes. Because they are fail-over and load-balanced, if one ISP fails, internet access is not affected and nobody knows. So I needed a script which would detect when a route fails and sends an email.

{
:global prevstatus;
:global status [:ip route get value-name=active [:ip route find comment="3.  Recursive lookup for Virgin connection (Via WAN routing table)"]]
:if ( "$status" != "$prevstatus" ) do={
:log warn "Virgin gateway changed status from \"$prevstatus\" -> \"$status\" (true=up, false=down, nothing=unintialized)";
:tool e-mail send to=user1@jdomain1.com subject="Virgin WAN gateway changed status" body=( [ :system clock get date ] . " " . [ :system clock get time ] . " gateway changed status from \"$prevstatus\" -> \"$status\" (true=up, false=down, nothing=unintialized)" )
:tool e-mail send to=user2@domain2.com subject="Virgin WAN gateway changed status" body=( [ :system clock get date ] . " " . [ :system clock get time ] . " gateway changed status from \"$prevstatus\" -> \"$status\" (true=up, false=down, nothing=unintialized)" )
}
:global prevstatus $status
}

All I needed to do was:
1. Change the email address in the script
2. Change the comment search text
3. Make sure the SMTP server is setup properly so that the mikrotik can send emails
4. Schedule the script to run every few minutes.
5. Repeat for WAN-2 and WAN-3 (I assume you need to chg the global variables for status and prevstatus for each wan. For example statusw1 and prevtatusw1 for WAN-1, and so on)

I am a beginner to MT scripting and this script worked flawlessly. I don't know if it is the optimal way to do so but for now it is perfect.

Note: The above script sends an email to 2 different email addresses. If you only need to send one email, delete the corresponding line(s).
 
User avatar
Lokamaya
Frequent Visitor
Frequent Visitor
Posts: 52
Joined: Thu Nov 11, 2021 4:40 am
Location: Bandung

Re: Useful scripts

Fri Sep 16, 2022 4:15 pm

I will try to get all the useful links to threads to look at when some script is needed, that is not yet in wiki or is in wiki, just to get them not buried under loads other posts.

Check time of the post, to make some link to RouterOS version these where created for.
New script for RouterOS v7, please
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 12379
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Useful scripts

Fri Sep 16, 2022 4:38 pm

Take these 3, are for v7
:put "Hello Word"

:put "Hello Excel"

:put "Hello Access"
 
howdey57
Member Candidate
Member Candidate
Posts: 129
Joined: Wed Dec 31, 2014 2:36 pm

Re: Useful scripts

Thu Nov 03, 2022 8:40 pm

This is my script that I use in both the Up and Down of any Netwatch I have. I hope this is useful to someone.
#########################################################################
#A single script to manage Netwatch
#########################################################################
/tool netwatch
:local myHost $host
:local myStatus  [ get  [find where host=$myHost ] status ]
:local myComment [ get  [find where host=$myHost ] comment ]
# Notify ################################################################
:log error "Connection $myStatus to $host:$myComment at $[/system clock get time]"
/tool e-mail send to="mail@here" subject="$myComment: $myStatus to $host from $[/system identity get name] at $[/system clock get time]" body="Netwatch"
 
howdey57
Member Candidate
Member Candidate
Posts: 129
Joined: Wed Dec 31, 2014 2:36 pm

Re: Useful scripts

Sun Nov 13, 2022 9:45 pm

This is a script that fetches a script from a RPi on my home network. I do this so I can use Notepad++ with Mikrotik highlightng to make it easier to get the code correct - scripting is not easy and very fragile in Mikrotik.

Also:
  • It uses global variables for my Pi username and password
  • It has a switch to stop the fetch happening - it will use the copy on the Mikrotik
  • It has a switch to disable "info" logging - fetch puts in a log entry every time that clogs up the Log File
  • It enables the logging again even if the fetch is in error
  • It sets a global switch that stops two scripts running at the same time if the previous one has not finnished


#######################################################################
# Fetch and Run a remote script and stop duplicated runs
#######################################################################
:global piUsername
:global piPassword
:local scriptFile "IPDB2.rsc"
:local sourceFolder "files"
:local destFolder "scripts"
:local piIPaddr "192.x.x.x"
:local fetchFileFirst true
:global IPDBscriptNotRunning
:local DisableFetchLogging true
#######################################################################
# Only run if another version is not running
#######################################################################
:if ( $IPDBscriptNotRunning ) do={
    /log info "Going to run $sourceFolder/$scriptFile - Will be be fetched first? $fetchFileFirst "
    :if ( $fetchFileFirst ) do={
        :do {
            :if ( $DisableFetchLogging ) do={ [ /system logging  set [find where topics~"info" and disabled=no] disabled=yes] }
            /tool fetch address=$piIPaddr src-path="$sourceFolder/$scriptFile" user="$piUsername" mode=ftp password="$piPassword" dst-path="$destFolder/$scriptFile" 
            :if ( $DisableFetchLogging ) do={ [ /system logging  set [find where topics~"info" and disabled=yes] disabled=no] }
         } on-error={  
            :if ( $DisableFetchLogging ) do={ [ /system logging  set [find where topics~"info" and disabled=yes] disabled=no] }    
         }         
    } else={
        /log info "Using saved version of $sourceFolder/$scriptFile"
    }
    # Set flag to stop this script duplicating
    :set IPDBscriptNotRunning false
    /import "$destFolder/$scriptFile"
    # Unset flag once script has run
    :set IPDBscriptNotRunning true
} else={
    /log info "[IPDB] another currently running. Not starting"
}
 
User avatar
chechito
Forum Guru
Forum Guru
Posts: 3079
Joined: Sun Aug 24, 2014 3:14 am
Location: Bogota Colombia
Contact:

Re: Useful scripts

Sun Nov 13, 2022 11:45 pm

interesting, thanks for sharing
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 12379
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Useful scripts

Mon Nov 14, 2022 2:13 am

[*]It has a switch to disable "info" logging - fetch puts in a log entry every time that clogs up the Log File
It works incorrectly, if there is any disabled log entry, for example for debugging, it is unnecessarily enabled.
The script must remember what has been disabled and later enable only what has been disabled.
 
howdey57
Member Candidate
Member Candidate
Posts: 129
Joined: Wed Dec 31, 2014 2:36 pm

Re: Useful scripts

Mon Nov 14, 2022 11:37 pm

rextended. It works for me. Perhaps you might suggest how to selectively disable/enable log rules rather than leaving a slightly passive-aggresive comment.
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 12379
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Useful scripts

Tue Nov 15, 2022 12:48 am

you might suggest how to selectively disable/enable log rules
rather than leaving a slightly passive-aggresive comment.
Don't ask the water to stop wetting.
I always help in the end, anyway...
{
:local logIDs [/system logging find where topics~"info" and disabled=no]

/system logging set $logIDs disabled=yes

# /tool fetch

/system logging set $logIDs disabled=no
}
 
holvoetn
Forum Guru
Forum Guru
Posts: 6138
Joined: Tue Apr 13, 2021 2:14 am
Location: Belgium

Re: Useful scripts

Wed Nov 16, 2022 9:50 am

Don't ask the water to stop wetting.
That's easy. Just freeze it and it's not wet anymore -> problem solved.
 
kujo
Member Candidate
Member Candidate
Posts: 169
Joined: Sat Jun 18, 2016 10:17 am
Location: Ukraine
Contact:

Re: Useful scripts

Fri Mar 03, 2023 10:34 pm

Hi)
Script add comment to caps-man access-list from dhcp lease list info.
:local wifiItem;
:local wifiItemMac;
:local dhcpItem;
:local dhcpIPaddr; 
:local dhcpServer;
:local dhcpName;
:local dhcpStatus;
:local dhcpLastSeen;
:local newComment;
:local currentComment;

:foreach wifiItem in=[/caps-man registration-table find] do={
		:set wifiItemMac [/caps-man registration-table get $wifiItem value-name=mac-address];
		:set dhcpItem [/ip dhcp-server lease find where mac-address=$wifiItemMac];
		:if ($dhcpItem !=  "") do={
			:set dhcpIPaddr [/ip dhcp-server lease get $dhcpItem value-name=active-address];
			:set dhcpName [/ip dhcp-server lease get $dhcpItem value-name=host-name];
			:set dhcpServer [/ip dhcp-server lease get $dhcpItem value-name=server];
			:set dhcpStatus [/ip dhcp-server lease get $dhcpItem value-name=status];
			#:set dhcpLastSeen [/ip dhcp-server lease get $dhcpItem value-name=last-seen];
			:set newComment ($dhcpIPaddr . "::" . $dhcpName . "::" . \
				$dhcpServer. "::" . $dhcpStatus . "::" . \
				$dhcpLastSeen);
			#:put ($newComment . " for " . $wifiItemMac);
			if ([/caps-man access-list find where mac-address=$wifiItemMac] = "") do={
				#didnt find a comment, add new
				:put ("Add access-list " . $newComment . " for " . $wifiItemMac);
				[/caps-man access-list add mac-address=$wifiItemMac action=accept comment=$newComment];
			} else={
				#found a comment, check comment content
				:set currentComment [/caps-man access-list  get [/caps-man access-list find where mac-address=$wifiItemMac] value-name=comment];
				if ($currentComment != $newComment) do={
					[/caps-man access-list set [/caps-man access-list find where mac-address=$wifiItemMac] comment=$newComment];
				} else={
					:put ("Comment that didnt change " . $currentComment);
				}
			}
		} else={
			:put ("No dhcp item for " . $wifiItemMac);
		};

};
When the access list is modified/created, the Wi-Fi client will be disconnect
 
hardcorec
just joined
Posts: 3
Joined: Sun Mar 26, 2023 8:11 pm

Re: Useful scripts

Sun Mar 26, 2023 8:15 pm

can someone update this script?
(i want to send Firewall Filter info on mail)

https://wiki.mikrotik.com/wiki/Firewall_Usage

Tnx
 
hardcorec
just joined
Posts: 3
Joined: Sun Mar 26, 2023 8:11 pm

Re: Useful scripts

Mon Apr 03, 2023 6:02 pm

can someone update this script?
(i want to send Firewall Filter info on mail)

https://wiki.mikrotik.com/wiki/Firewall_Usage

Tnx
Someone?
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 12379
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Useful scripts

Mon Apr 03, 2023 10:42 pm

Someone?
Open a separate topic for request something new, this section is for what is already ready and work.
 
BillyVan
newbie
Posts: 38
Joined: Tue Sep 04, 2018 10:29 pm
Location: Greece

Re: Useful scripts

Thu Jul 06, 2023 3:27 pm

Working Script
:local emailTo "XXXXXX@gmail.com"
:local emailSubject "Unreachable Gateway Detected"
:local emailBody "An unreachable gateway has been detected."
:local DeviceName [/system identity get name]
:local commentFilters ("From WAN 1", "From WAN 2", "From WAN 3")

:foreach commentFilter in=$commentFilters do={
  :local unreachableGateways [:toarray [/routing route find where unreachable and comment=$commentFilter]]
  :if ([:len $unreachableGateways] > 0) do={
    :log warning ("An unreachable gateway has been detected " . $commentFilter)
    /tool e-mail send to="XXXXXX@gmail.com" subject="\E2\9A\A0 [$DeviceName] $emailSubject $commentFilter" body="$emailBody" 
   }
}
In above working script with Ros 7 checking 3 wan....waiting for unreachable response for comment From WAN 1 or 2 or 3.

If WAN 1 unreachable then sends email with detail on subject.
Last edited by BillyVan on Thu Jul 06, 2023 6:00 pm, edited 1 time in total.
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 12379
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Useful scripts

Thu Jul 06, 2023 3:47 pm

...
Last edited by rextended on Thu Jul 06, 2023 6:04 pm, edited 1 time in total.
 
BillyVan
newbie
Posts: 38
Joined: Tue Sep 04, 2018 10:29 pm
Location: Greece

Re: Useful scripts

Thu Jul 06, 2023 6:02 pm

SPAM, this topic is for what already work, not for ask support on not working script.
Kepp the working one

Thank you
 
User avatar
Kentzo
Long time Member
Long time Member
Posts: 596
Joined: Mon Jan 27, 2014 3:35 pm
Location: California

Re: Useful scripts

Wed Jul 19, 2023 8:09 am

Script to parse an IPv6 address and address prefix into a structured array: viewtopic.php?t=197913
 
msatter
Forum Guru
Forum Guru
Posts: 2935
Joined: Tue Feb 18, 2014 12:56 am
Location: Netherlands / Nīderlande

Re: Useful scripts

Tue Aug 08, 2023 11:48 am

Some script lines to logout non-existing/deactivated users and sessions that are left open for a long time. This now apply to only local sessions (terminal).

Disconnect users that are are removed as user:
:foreach item in=[/user/active find] do={:if ([/user find name=[/user/active get $item]->"name"]) do={} else={:do {/user/active request-logout $item} on-error={:put "bugger"}}}
Disconnect disabled users:
:foreach item in=[/user/active find] do={:if ([/user find name=[/user/active get $item]->"name" disabled] ) do={:do {/user/active request-logout $item} on-error={:put "bugger"}}} 
Disconnect users that have the terminal open for more than 23 hours. Using also the date is a bit of more work, so I let to others to do that:
:foreach item in=[/user/active find] do={:if ([/user find name=[/user/active get $item]->"name"] ) do={:if ((([:totime [:pick [/user/active get $item value-name="when"] 11 19]])-23:00:00) >  0)  do={:do {/user/active request-logout $item} on-error={:put "bugger"}}}}
 
tkeller
just joined
Posts: 2
Joined: Sat Nov 25, 2023 9:10 pm

Re: Useful scripts

Sat Nov 25, 2023 9:15 pm

I was surprised that /user active request-logout is undocumented. Also it's not a request :lol:

This one uses the date too. Apparently force logging out a user requires reboot permission for this script to work.
# Function to convert date and time to seconds since Unix epoch (1970-01-01)
# Assumes each month is 30 days but this is good enough for me
:local dateTimeToSeconds do={
    :local dateTime $1;
    :local date [:pick $dateTime 0 10];
    :local time [:pick $dateTime 11 19];
    :local y [:tonum [:pick $date 0 4]];
    :local m [:tonum [:pick $date 5 7]];
    :local d [:tonum [:pick $date 8 10]];
    :local h [:tonum [:pick $time 0 2]];
    :local min [:tonum [:pick $time 3 5]];
    :local s [:tonum [:pick $time 6 8]];
    :local epoch [:tonum [/system clock get time]];
    :return (((((($y - 1970) * 365 + ($y - 1969) / 4 - ($y - 1901) / 100 + ($y - 1601) / 400 + $d + ($m - 1) * 30) * 24 + $h) * 60 + $min) * 60 + $s) - $epoch);
}

:local sessionTimeLimit 28800; # in seconds

# Get current date and time
:local currentDate [/system clock get date];
:local currentTime [/system clock get time];
:local currentDateTime ($currentDate . " " . $currentTime);

# Convert current date and time to seconds since Unix epoch
:local currentDateTimeSec [$dateTimeToSeconds $currentDateTime];

:foreach i in=[/user active find] do={
    :put $i
    :local userDateTime [/user active get $i value-name=when];
    :put $userDateTime
    # Convert user login date and time to seconds since Unix epoch
    :local userDateTimeSec [$dateTimeToSeconds $userDateTime];
    :put $userDateTimeSec
    # Calculate the duration of the user session in seconds
    :local sessionDuration ($currentDateTimeSec - $userDateTimeSec);
    :put $sessionDuration
    # Check if the user has been logged in for more than the limit
    if ($sessionDuration > $sessionTimeLimit) do={
        :do {
            # Force log out the user
            /user active request-logout numbers=$i
            :log info ("Logged out user: " . [/user active get $i value-name=name] . " for exceeding login time limit")
        } on-error={
            :log warning ("Error logging out user: " . [/user active get $i value-name=name])
        };
    }
}
 
User avatar
diamuxin
Member
Member
Posts: 323
Joined: Thu Sep 09, 2021 5:46 pm

Re: Useful scripts

Tue Nov 28, 2023 8:24 pm

I was surprised that /user active request-logout is undocumented. Also it's not a request :lol:

This one uses the date too. Apparently force logging out a user requires reboot permission for this script to work.
It works fine but the active session via Winbox does not disconnect, it only disconnects the active sessions via SSH (CLI).
 
aanistratenko
just joined
Posts: 10
Joined: Fri Mar 10, 2023 10:27 pm

Re: Useful scripts

Sun Dec 03, 2023 3:35 pm

Useful script for "Netwatch notification via Telegram with Markdown and Emoji"
I whant to use minimum manual writing, all variables given from ROS and simple copiing script in Netwatch test, only Comment need to writing.

Src: School1-GW-2 -from Identity
Dst: AP-3-37 -from Netwatch test comment
Stat: UP ✅ -from Netwatch test Status
Type: simple -from Netwatch test Type
Host: 192.168.111.37 -from Netwatch test Host
Since: dec/03/2023 13:56:16 -from Netwatch test Since
:local bot1 ***
:local chatid1 ***
:local src [/system identity get name]
:local ip $host
:local test $type
:local dst $comment
:local time $since
:local stat $status
:local stattext
:if ($stat = "up") do={
   :set stattext "UP"
} else={
   :set stattext "DOWN"
}

:local logmessage "Src: $src  Dst: $dst Stat: $stattext  Type: $test Host: $ip Since: $time"  
/log warning "$logmessage"

:local tgmessage "Src: *$src*  %0ADst: *$dst* %0AStat: *$stattext*  %0AType: $test %0AHost: $ip %0ASince: $time"  
/tool fetch url="https://api.telegram.org/bot$bot1/sendMessage?chat_id=$chatid1&text=$tgmessage&parse_mode=Markdown" dst-path=telegram.txt
You do not have the required permissions to view the files attached to this post.
 
User avatar
DenSyo77
newbie
Posts: 25
Joined: Tue Jan 09, 2024 10:38 am
Contact:

Re: Useful scripts

Thu Jan 11, 2024 9:24 am

Function cyrb53a (c) 2023 bryc (github.com/bryc) to calculate 53-bit hash from string
https://github.com/bryc/code/blob/maste ... /cyrb53.js
:local cyrb53a do={
  :local h1 (0xdeadbeef ^ [:tonum $2])
  :local h2 (0x41c6ce57 ^ [:tonum $2])
  :local imul do={
    :local ah (([:tonum $1] >> 16) & 0xffff)
    :local al ([:tonum $1] & 0xffff)
    :local bh (([:tonum $2] >> 16) & 0xffff)
    :local bl ([:tonum $2] & 0xffff)
    :return (($al * $bl + (($ah * $bl + $al * $bh) << 16)) & 0xffffffff)
  }
  :for i from=0 to=([:len $1] - 1) step=1 do={
    :local ch [:tonum "0x$[:convert [:pick $1 $i] to=hex]"]
    :set h1 [$imul ($h1 ^ $ch) 0x85ebca77]
    :set h2 [$imul ($h2 ^ $ch) 0xc2b2ae3d]
  }
  :set h1 ($h1 ^ [$imul ($h1 ^ ($h2 >> 15)) 0x735a2d97])
  :set h2 ($h2 ^ [$imul ($h2 ^ ($h1 >> 15)) 0xcaf649a9])
  :set h1 ($h1 ^ ($h2 >> 16))
  :set h2 ($h2 ^ ($h1 >> 16))
  :return (2097152 * $h2 + ($h1 >> 11))
}

:put [$cyrb53a "We like MikroTik RouterOS script writing" 0]

64-bit simplified version
:local cyrb53a do={
  :local h1 (0xdeadbeef ^ [:tonum $2])
  :local h2 (0x41c6ce57 ^ [:tonum $2])
  :for i from=0 to=([:len $1] - 1) step=1 do={
    :local ch [:tonum "0x$[:convert [:pick $1 $i] to=hex]"]
    :set h1 (($h1 ^ $ch) * 0x85ebca77)
    :set h2 (($h2 ^ $ch) * 0xc2b2ae3d)
  }
  :set h1 ($h1 ^ (($h1 ^ ($h2 >> 15)) * 0x735a2d97))
  :set h2 ($h2 ^ (($h2 ^ ($h1 >> 15)) * 0xcaf649a9))
  :set h1 ($h1 ^ ($h2 >> 16))
  :set h2 ($h2 ^ ($h1 >> 16))
  :return ((2097152 * $h2 + ($h1 >> 11)) & 0xffffffffffffffff)
}

:put [$cyrb53a "We like MikroTik RouterOS script writing" 0]

Sometimes they ask about hashes, maybe it will be useful for someone. I use it in my projects to organize quick searches in big data to calculate the keys of associative arrays, to do this, first convert the number to hex string.
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 12379
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Useful scripts

Thu Jan 11, 2024 10:49 am

Both work only on v7.?.? (where ":convert" is added) because inside is present :convert

refresh code

:global cyrb53a do={
    :local imul do={
        :local s1 [:tonum $1]
        :local s2 [:tonum $2]
        :local ah (($s1 >> 16) & 0xffff)
        :local al ( $s1        & 0xffff)
        :local bh (($s2 >> 16) & 0xffff)
        :local bl ( $s2        & 0xffff)

        :return (($al * $bl + (($ah * $bl + $al * $bh) << 16)) & 0xffffffff)
    }

    :local p1 [:tostr $1]
    :local p2 [:tonum $2]
    :local h1 (0xdeadbeef ^ $p2)
    :local h2 (0x41c6ce57 ^ $p2)
    :local ch ""

    :for i from=0 to=([:len $p1] - 1) step=1 do={
        :set ch [:tonum "0x$[:convert [:pick $p1 $i] to=hex]"]
        :set h1 [$imul ($h1 ^ $ch) 0x85ebca77]
        :set h2 [$imul ($h2 ^ $ch) 0xc2b2ae3d]
    }
    :set h1 ($h1 ^ [$imul ($h1 ^ ($h2 >> 15)) 0x735a2d97])
    :set h2 ($h2 ^ [$imul ($h2 ^ ($h1 >> 15)) 0xcaf649a9])
    :set h1 ($h1 ^               ($h2 >> 16)             )
    :set h2 ($h2 ^               ($h1 >> 16)             )

    :return (2097152 * $h2 + ($h1 >> 11))
}

:put [$cyrb53a "We like MikroTik RouterOS script writing" 0]

refresh64 code

:global cyrb53a do={
    :local p1 [:tostr $1]
    :local p2 [:tonum $2]
    :local h1 (0xdeadbeef ^ $p2)
    :local h2 (0x41c6ce57 ^ $p2)
    :local ch ""

    :for i from=0 to=([:len $p1] - 1) step=1 do={
        :set ch [:tonum "0x$[:convert [:pick $p1 $i] to=hex]"]
        :set h1 (($h1 ^ $ch) * 0x85ebca77)
        :set h2 (($h2 ^ $ch) * 0xc2b2ae3d)
    }
    :set h1 ($h1 ^ (($h1 ^ ($h2 >> 15)) * 0x735a2d97))
    :set h2 ($h2 ^ (($h2 ^ ($h1 >> 15)) * 0xcaf649a9))
    :set h1 ($h1 ^         ($h2 >> 16)               )
    :set h2 ($h2 ^         ($h1 >> 16)               )

    :return ((2097152 * $h2 + ($h1 >> 11)) & 0xffffffffffffffff)
}

:put [$cyrb53a "We like MikroTik RouterOS script writing" 0]
 
User avatar
DenSyo77
newbie
Posts: 25
Joined: Tue Jan 09, 2024 10:38 am
Contact:

Re: Useful scripts

Fri Jan 12, 2024 2:15 pm

The function of obtaining an array of subnets between two ip4 addresses. May be useful for organizing addresses database. The order of the transmitted addresses does not matter. And function for obtaining an array of subnets included in a given one (warning, do not call this function with a large prefix increment value, now the limit is no more than 12, but this is not small).
# return common subnet prefix of two ip
:global getIpCommonPrefix do={
  :local xored ([:tonum [:toip $1]] ^ [:tonum [:toip $2]])
  :local prefix 32
  
  :while ($xored) do={
    :set xored ($xored >> 1)
    :set prefix ($prefix - 1)
  }
  
  :return $prefix
}

:put [$getIpCommonPrefix 192.168.88.77 192.168.88.111]

# return array with subnets between two ip
:global getSubnetsBetweenIp do={
  :local ip1 [:toip $1]
  :local ip2 [:toip $2]
  :local subnets [:toarray ""]
  :global getIpCommonPrefix
  :local prefix [$getIpCommonPrefix $1 $2]
  :local submask (255.255.255.255 << (32 - $prefix))
  :local addrspace (~$submask)
  :local network
  :local broadcast
  :if ($prefix = 0) do={
    :set network 0.0.0.0
    :set broadcast 255.255.255.255
  } else={
    :set network ($ip1 & $submask)
    :set broadcast ($ip1 | $addrspace)
  }
  
  :if ($ip1 > $ip2) do={
    :set ip1 $ip2
    :set ip2 [:toip $1]
  }
  
  :if ($ip1 = $network && $ip2 = $broadcast) do={
    :set subnets ($subnets, ($network."/".$prefix))
  } else={
    :local finded1
    :local finded2
    
    :while ($prefix < 32 && !($finded1 = $ip1 && $finded2 = $ip2)) do={
      :set prefix ($prefix + 1)
      :set submask (255.255.255.255 << (32 - $prefix))
      :set addrspace (~$submask)
      :set network ($ip1 & $submask)
      :local loop true
      
      :while ($loop && $network <= $ip2) do={
        :if ($network >= $finded1 && $network <= $finded2) do={
          :if ($finded2 < 255.255.255.255) do={
            :set network ($finded2 + 1)
          } else={
            :set loop false
          }
        }
        
        :if ($loop) do={
          :set broadcast ($network | $addrspace)
          
          :if ($network >= $ip1 && $broadcast <= $ip2) do={
            :if ($network < $finded1 || [:typeof $finded1] = "nothing") do={ :set finded1 $network }
            :if ($broadcast > $finded2 || [:typeof $finded2] = "nothing") do={ :set finded2 $broadcast }
            :set subnets ($subnets, ($network."/".$prefix))
          }
          
          :if ($broadcast < 255.255.255.255) do={
            :set network ($broadcast + 1)
          } else={
            :set loop false
          }
        }
      }
    }
  }
  
  :return $subnets
}

:put [$getSubnetsBetweenIp 0.0.0.1 255.255.255.254]
:put [$getSubnetsBetweenIp 255.255.255.254 0.0.0.0]
:put [$getSubnetsBetweenIp 0.0.0.1 255.255.255.255]
:put [$getSubnetsBetweenIp 0.0.0.0 255.255.255.255]

# return an array of subnets included in the given subnet
:global getIncludedSubnets do={
  :local prefix [:tonum [:pick $1 ([:find $1 "/"] + 1) [:len $1]]]
  :local add [:tonum $2]
  :local subnets [:toarray ""]
  
  :if ($add >= 0 && $add <= 12 && ($prefix + $add) <= 32) do={
    :local ip [:toip [:pick $1 0 [:find $1 "/"]]]
    :local submask (255.255.255.255 << (32 - $prefix))
    :local addrspace (~$submask)
    :local network
    :local broadcast
    :if ($prefix = 0) do={
      :set network 0.0.0.0
      :set broadcast 255.255.255.255
    } else={
      :set network ($ip & $submask)
      :set broadcast ($ip | $addrspace)
    }
    
    :if ($add = 0) do={
      :set subnets ($subnets, ($network."/".$prefix))
    } else={
      :set prefix ($prefix + $add)
      :local step (1 << (32 - $prefix))
      :local loop true
      
      :while ($loop && $network <= $broadcast) do={
        :set subnets ($subnets, ($network."/".$prefix))
        :if ((255.255.255.255 - $network) >= $step) do={
          :set network ($network + $step)
        } else={
          :set loop false
        }
      }
    }
  }
  
  :return $subnets
}

:put [$getIncludedSubnets 192.168.88.77/24 5]
:put [$getIncludedSubnets 192.168.88.77/24 0]
:put [$getIncludedSubnets 255.255.255.255/0 0]

Example of addresses searching in lists using associative arrays - may give better performance in scripts for works with large addresses base. Building array is called once, then, when adding new address to list from which the array is compiled, add the address to list and to array. Weak point of algorithm is the presence of large subnets in lists. Search for each address takes place in a cycle with a number of steps: (33 minus the minimum prefix value in the checked lists), the presence of subnets such as 10.0.0.0/8 in array significantly affects search performance. It is better to check whether an address is included in large subnets separately.
:global mylist [:toarray ""]
:global minprefix 32

:local addrlist [/ip firewall address-list print detail as-value where ";allowed-ip;white-list;local-networks;service-addresses;test-list;"~list]

:foreach addr in=$addrlist do={
  :local ip
  :local prefix
  :if ([:find ($addr->"address") "/"] > 0) do={
    :set ip [:toip [:pick ($addr->"address") 0 [:find ($addr->"address") "/"]]]
    :set prefix [:tonum [:pick ($addr->"address") ([:find ($addr->"address") "/"] + 1) [:len ($addr->"address")]]]
  } else={
    :set ip [:toip ($addr->"address")]
    :set prefix 32
  }
  
  :if ([:typeof $ip] != "nil") do={
    :local submask (255.255.255.255 << (32 - $prefix))
    :local subnet
    :if ($prefix = 0) do={
      :set subnet "0.0.0.0"
    } else={
      :set subnet [:tostr ($ip & $submask)]
    }
    
    :if ([:typeof ($mylist->$subnet)] = "nothing" || ($mylist->$subnet) > $prefix) do={
      :set ($mylist->$subnet) $prefix
    }
    
    :if ($minprefix > $prefix) do={
      :set minprefix $prefix
    }
  }
}

:global inMyList do={
  :global mylist
  :global minprefix
  :local network [:toip $1]
  :local submask 255.255.255.255
  
  :for prefix from=32 to=$minprefix step=-1 do={
    :local subnet [:tostr $network]
    :if ([:typeof ($mylist->$subnet)] != "nothing" && ($mylist->$subnet) <= $prefix) do={ :return true }
    :set submask ($submask << 1)
    :set network ($network & $submask)
  }
  
  :return false
}

# Usage test
:local ip 192.168.88.1
:for i from=1 to=254 step=1 do={
  :if ([$inMyList $ip]) do={
    :put $ip
  } else={
    :set ($mylist->[:tostr $ip]) 32
#   /ip firewall address-list add address=$ip list=test-list
  }
  :set ip ($ip + 1)
}

There is also a tool for working with address databases, if anyone is interested syo.su
 
User avatar
DenSyo77
newbie
Posts: 25
Joined: Tue Jan 09, 2024 10:38 am
Contact:

Re: Useful scripts

Tue Jan 23, 2024 4:43 am

Method of working with regional ip address databases without using a firewall address list - does not take away the performance of executing rules using lists.
:global ipLocation {
"1.0.0.0"={24;"US"};
"1.0.1.0"={24;"CN"};
"1.0.2.0"={23;"CN"};
"1.0.4.0"={22;"AU"};
"1.0.8.0"={21;"CN"};
"1.0.16.0"={20;"JP"};
# . . . . . . . . .
}

:global ipCountries {
"AU"="Australia";
"CN"="China";
"JP"="Japan";
"US"="United States of America";
# . . . . . . . . .
}

:global ipMinPrefix 32
:global ipMaxPrefix 0

:foreach param in=$ipLocation do={
  :if (($param->0) < $ipMinPrefix) do={ :set ipMinPrefix ($param->0) }
  :if (($param->0) > $ipMaxPrefix) do={ :set ipMaxPrefix ($param->0) }
}

:global ipGetLocation do={
  :global ipLocation
  :global ipMaxPrefix
  :global ipMinPrefix
  :local submask (255.255.255.255 << (32 - $ipMaxPrefix))
  :local network ([:toip $1] & $submask)
  
  :for prefix from=$ipMaxPrefix to=$ipMinPrefix step=-1 do={
    :local subnet [:tostr $network]
    
    :if ([:typeof ($ipLocation->$subnet)] != "nothing" && ($ipLocation->$subnet->0) <= $prefix) do={
      :return ($ipLocation->$subnet->1)
    }
    
    :set submask ($submask << 1)
    :set network ($network & $submask)
  }
  
  :return []
}

:global ipGetSubnet do={
  :global ipLocation
  :global ipMaxPrefix
  :global ipMinPrefix
  :local submask (255.255.255.255 << (32 - $ipMaxPrefix))
  :local network ([:toip $1] & $submask)
  
  :for prefix from=$ipMaxPrefix to=$ipMinPrefix step=-1 do={
    :local subnet [:tostr $network]
    
    :if ([:typeof ($ipLocation->$subnet)] != "nothing" && ($ipLocation->$subnet->0) <= $prefix) do={
      :return ($subnet."/".($ipLocation->$subnet->0))
    }
    
    :set submask ($submask << 1)
    :set network ($network & $submask)
  }
  
  :return []
}

:global ipGetInfo do={
  :global ipLocation
  :global ipMaxPrefix
  :global ipMinPrefix
  :local submask (255.255.255.255 << (32 - $ipMaxPrefix))
  :local network ([:toip $1] & $submask)
  
  :for prefix from=$ipMaxPrefix to=$ipMinPrefix step=-1 do={
    :local subnet [:tostr $network]
    
    :if ([:typeof ($ipLocation->$subnet)] != "nothing" && ($ipLocation->$subnet->0) <= $prefix) do={
      :return {($subnet."/".($ipLocation->$subnet->0)); ($ipLocation->$subnet->1)}
    }
    
    :set submask ($submask << 1)
    :set network ($network & $submask)
  }
  
  :return [:toarray ""]
}

Usage example
:global ipCountries
:global ipGetLocation
:local allConn [/ip firewall connection print detail as-value]
:foreach conn in=$allConn do={
  :local src [:pick ($conn->"src-address") 0 [:find ($conn->"src-address") ":"]]
  :local dst [:pick ($conn->"dst-address") 0 [:find ($conn->"dst-address") ":"]]
  :local srcWhois $src
  :local dstWhois $dst
  
  :if ($src = "Your external ip here") do={
    :set srcWhois "Router"
  } else={
    :local ip [:toip $src]
    
    :if ($ip & 255.0.0.0 = 10.0.0.0 || $ip & 255.255.0.0 = 192.168.0.0 || $ip & 255.240.0.0 = 172.16.0.0) do={
      :set srcWhois "Localhost"
    } else={
      :local ipCode [$ipGetLocation $src]
      
      :if ([:typeof $ipCode] != "nil") do={
        :set srcWhois ($ipCountries->$ipCode)
      }
    }
  }
  
  :if ($dst = "Your external ip here") do={
    :set dstWhois "Router"
  } else={
    :local ip [:toip $dst]
    
    :if ($ip & 255.0.0.0 = 10.0.0.0 || $ip & 255.255.0.0 = 192.168.0.0 || $ip & 255.240.0.0 = 172.16.0.0) do={
      :set dstWhois "Localhost"
    } else={
      :local ipCode [$ipGetLocation $dst]
      
      :if ([:typeof $ipCode] != "nil") do={
        :set dstWhois ($ipCountries->$ipCode)
      }
    }
  }
  
  :put ($srcWhois." -> ".$dstWhois)
}

# same thing using another function
:global ipGetInfo
:foreach conn in=$allConn do={
  :local src [:pick ($conn->"src-address") 0 [:find ($conn->"src-address") ":"]]
  :local dst [:pick ($conn->"dst-address") 0 [:find ($conn->"dst-address") ":"]]
  :local srcWhois $src
  :local dstWhois $dst
  
  :if ($src = "Your external ip here") do={
    :set srcWhois "Router"
  } else={
    :local ip [:toip $src]
    
    :if ($ip & 255.0.0.0 = 10.0.0.0 || $ip & 255.255.0.0 = 192.168.0.0 || $ip & 255.240.0.0 = 172.16.0.0) do={
      :set srcWhois "Localhost"
    } else={
      :local ipInfo [$ipGetInfo $src]
      
      :if ([:len $ipInfo]) do={
        :set srcWhois (($ipCountries->($ipInfo->1))." (".($ipInfo->0).")")
      }
    }
  }
  
  :if ($dst = "Your external ip here") do={
    :set dstWhois "Router"
  } else={
    :local ip [:toip $dst]
    
    :if ($ip & 255.0.0.0 = 10.0.0.0 || $ip & 255.255.0.0 = 192.168.0.0 || $ip & 255.240.0.0 = 172.16.0.0) do={
      :set dstWhois "Localhost"
    } else={
      :local ipInfo [$ipGetInfo $dst]
      
      :if ([:len $ipInfo]) do={
        :set dstWhois (($ipCountries->($ipInfo->1))." (".($ipInfo->0).")")
      }
    }
  }
  
  :put ($srcWhois." -> ".$dstWhois)
}

Ready file with regional database: https://syo.su/download/MikroTikIpLocation.zip other https://syo.su/download/MikroTikIpMaxMind.zip
To run this file on your device, need about 80-100MB free of RAM. Unzip archive and download the file to device. Run the command:
import file=MikroTikIpLocation.rsc
After rebooting the device, all variables will disappear, such a script run is required every time the device starts working. Save the usage example as a script, paste your external ip address into it and run it in the console.

In this way, you can identify unnecessary addresses that are currently accessing the device and place them in a dynamic ban list - the CPU load will be less than storing the regional ip addresses database on the firewall. This will also allow you to play around with large address databases without cluttering up the device’s memory. The database loaded in this way on the device takes up 2 times less RAM than if you load the same addresses into firewall address list. Searching for an address is faster than a standard search in firewall address list. Moreover, if you increase size of the database several times, for example, create a database with addresses linked by city, the speed of searching for an address in the database will practically not change, only more RAM will be required (but you won’t be able to check whether I’m telling the truth; due to restrictions on the size of the array, you can only create an array 1.5-2 times larger than the one I posted).

To assemble an array with a database of addresses yourself, download, for example, the CSV file with database DB1 from https://lite.ip2location.com/database-download
Go to page http://syo.su expand the section "Create subnets from CSV files with network addresses in any form", open downloaded file and set:
File delimiter: , (comma)
Files contains headers: uncheck
First or only addresses range column: 1
Second addresses range column: 2
Addresses format: integer
Addresses mask column: none
Files have joined data tables: uncheck
JavaScript expression of list names values:
COLUMN[3] == '-' ? '' : COLUMN[3]
JavaScript expression of comments values:
COLUMN[4]
Header row value: not set
Merge ranges with same list name into the same subnet, if possible: check
Also group by comments: check
Set output file name
Limit file size: empty or 0
Select output file template: MikroTik search array
Click button Get file by template
Change output file name and select template: MikroTik search array addon
Click button Get file by template

The resulting files can be combined into one, or you can download and run separately in any order. You can also check the database for intersection of subnets - this method of searching for addresses assumes that all subnets in the database are unique. And you can get a list of subnets missed in the database.

Updated 2024-02-05 - fixed bug in first step of address searching, sorry...
Last edited by DenSyo77 on Mon Feb 05, 2024 5:06 am, edited 1 time in total.
 
koalabambu
just joined
Posts: 7
Joined: Tue Dec 05, 2023 11:32 pm

Re: Useful scripts

Mon Jan 29, 2024 4:37 am

Method of working with regional ip address databases without using a firewall address list - does not take away the performance of executing rules using lists.

t all subnets in the database are unique. And you can get a list of subnets missed in the database.
many thanks

Who is online

Users browsing this forum: divB and 18 guests