Advertisement
Guest User

Untitled

a guest
Jan 16th, 2024
186
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 169.90 KB | None | 0 0
  1. # 2024-01-16 17:49:15 by RouterOS 7.13.2
  2. # software id = A93J-ZXMT
  3. #
  4. # model = C53UiG+5HPaxD2HPaxD
  5. # serial number = HER09FWBYE6
  6. /disk
  7. set usb1 type=hardware
  8. add parent=usb1 partition-number=1 partition-offset=512 partition-size=\
  9.     "7 763 656 192" type=partition
  10. /interface bridge
  11. add arp=proxy-arp name=bridge-lan port-cost-mode=short
  12. /interface ethernet
  13. set [ find default-name=ether2 ] arp=local-proxy-arp
  14. /interface wifi
  15. set [ find default-name=wifi2 ] channel.band=2ghz-ax .skip-dfs-channels=\
  16.     10min-cac .width=20/40mhz configuration.country=Russia .mode=ap .ssid=\
  17.     /dev/null .tx-chains="" datapath.bridge=bridge-lan disabled=no mtu=1500 \
  18.     security.authentication-types=wpa2-psk,wpa3-psk .disable-pmkid=yes .ft=\
  19.     yes .ft-over-ds=yes .group-key-update=1h .management-protection=allowed
  20. /interface wireguard
  21. add comment=WB listen-port=13333 mtu=1420 name=WB
  22. add listen-port=13256 mtu=1420 name=WireguardHome
  23. add listen-port=13331 mtu=1420 name=wireguard-alpina
  24. add comment="FineVPN interface" listen-port=51820 mtu=1420 name=wireguard2
  25. add listen-port=13232 mtu=1420 name=wireguard2ccc
  26. /interface vlan
  27. add interface=bridge-lan name=bridge.2 vlan-id=1002
  28. add disabled=yes interface=bridge-lan name=vlan1000 vlan-id=1000
  29. /interface pppoe-client
  30. add add-default-route=yes disabled=no interface=ether1 keepalive-timeout=\
  31.     disabled name=vrn.tv user=ripab238
  32. /interface list
  33. add include=all name=WAN-LIST
  34. add name=LAN-LIST
  35. /ip dhcp-server option
  36. add code=42 name="NTP Server" value="'192.168.254.1'"
  37. add code=119 name=Domain_Search_value value="'DUNE.ZONE'"
  38. add code=15 name="Domain_Name value" value="'DUNE.ZONE'"
  39. add code=66 name=pxe value="'192.168.254.5'"
  40. add code=6 name=YandexDNS value="'77.88.8.7'"
  41. /ip pool
  42. add name=dhcp_pool0 ranges=192.168.254.25-192.168.254.229
  43. add name=dhcp2-pool ranges=192.168.154.0/24
  44. add name=dhcp_pool2 ranges=192.168.154.2-192.168.154.254
  45. /ip dhcp-server
  46. add add-arp=yes address-pool=dhcp_pool0 comment="domain=dune.zone" interface=\
  47.     bridge-lan lease-script="# MikroTik (RouterOS) script for automatically se\
  48.    tting DNS records\r\
  49.    \n# for clients when they obtain a DHCP lease.\r\
  50.    \n#\r\
  51.    \n# author SmartFinn <https://gist.github.com/SmartFinn>\r\
  52.    \n\r\
  53.    \n:local dnsTTL \"00:15:00\";\r\
  54.    \n:local token \"\$leaseServerName-\$leaseActMAC\";\r\
  55.    \n\r\
  56.    \n# Normalize hostname (e.g. \"-= My Phone =-\" -> \"My-Phone\")\r\
  57.    \n# - truncate length to 63 chars\r\
  58.    \n# - substitute disallowed chars with a hyphen\r\
  59.    \n# param: name\r\
  60.    \n:local normalizeHostname do={\r\
  61.    \n  :local result;\r\
  62.    \n  :local isInvalidChar true;\r\
  63.    \n  :for i from=0 to=([:len \$name]-1) do={\r\
  64.    \n    :local char [:pick \$name \$i];\r\
  65.    \n    :if (\$i < 63) do={\r\
  66.    \n      :if (\$char~\"[a-zA-Z0-9]\") do={\r\
  67.    \n        :set result (\$result . \$char);\r\
  68.    \n        :set isInvalidChar false;\r\
  69.    \n      } else={\r\
  70.    \n        :if (!\$isInvalidChar) do={\r\
  71.    \n          :set result (\$result . \"-\");\r\
  72.    \n          :set isInvalidChar true;\r\
  73.    \n        };\r\
  74.    \n      };\r\
  75.    \n    };\r\
  76.    \n  };\r\
  77.    \n# delete trailing hyphen\r\
  78.    \n  :if (\$isInvalidChar) do={\r\
  79.    \n    :set result [:pick \$result 0 ([:len \$result]-1)];\r\
  80.    \n  }\r\
  81.    \n  :return \$result;\r\
  82.    \n};\r\
  83.    \n\r\
  84.    \n:if (\$leaseBound = 1) do={\r\
  85.    \n# Getting the hostname and delete all disallowed chars from it\r\
  86.    \n  :local hostName \$\"lease-hostname\";\r\
  87.    \n  :set hostName [\$normalizeHostname name=\$hostName];\r\
  88.    \n\r\
  89.    \n# Use MAC address as a hostname if the hostname is missing or contains o\
  90.    nly\r\
  91.    \n# disallowed chars\r\
  92.    \n  :if ([:len \$hostName] = 0) do={\r\
  93.    \n    :set hostName [\$normalizeHostname name=\$leaseActMAC];\r\
  94.    \n  };\r\
  95.    \n\r\
  96.    \n# Getting the domain name from DHCP server. If a domain name is not\r\
  97.    \n# specified will use hostname only\r\
  98.    \n  /ip dhcp-server network {\r\
  99.    \n    :local domainName [get [:pick [find \$leaseActIP in address] 0] doma\
  100.    in];\r\
  101.    \n    :if ([:len \$domainName] > 0) do={\r\
  102.    \n#     Append domain name to the hostname\r\
  103.    \n      :set hostName (\$hostName . \".\" . \$domainName);\r\
  104.    \n    };\r\
  105.    \n  };\r\
  106.    \n\r\
  107.    \n  :do {\r\
  108.    \n    /ip dns static {\r\
  109.    \n      add name=\$hostName address=\$leaseActIP ttl=\$dnsTTL comment=\$to\
  110.    ken;\r\
  111.    \n    };\r\
  112.    \n  } on-error={\r\
  113.    \n    :log error \"Fail to add DNS entry: \$hostname -> \$leaseActIP (\$le\
  114.    aseActMAC)\";\r\
  115.    \n  };\r\
  116.    \n} else={\r\
  117.    \n  /ip dns static remove [find comment=\$token];\r\
  118.    \n};" name=dhcp1
  119. add add-arp=yes address-pool=dhcp_pool2 interface=bridge.2 name=dhcp2
  120. /ppp profile
  121. set *0 change-tcp-mss=no
  122. /routing table
  123. add fib name=tovpn
  124. /routing bgp template
  125. set default disabled=no routing-table=main
  126. add as=64999 disabled=no name=antifilter output.network=bgp-networks \
  127.     .no-client-to-client-reflection=yes router-id=46.72.222.7 routing-table=\
  128.     main
  129. /snmp community
  130. set [ find default=yes ] addresses=95.142.47.131/32
  131. /system logging action
  132. add disk-file-count=10 disk-file-name=usb1-part1/logs/info-log- \
  133.     disk-lines-per-file=5000 name=USBinfo target=disk
  134. /user group
  135. add name=prometheus policy="local,telnet,ssh,ftp,reboot,read,write,policy,test\
  136.    ,winbox,password,web,sniff,sensitive,api,romon,rest-api"
  137. /interface bridge filter
  138. add action=drop chain=output mac-protocol=ip out-interface=ether2 \
  139.     packet-type=multicast
  140. /interface bridge port
  141. add bridge=bridge-lan interface=LAN-LIST internal-path-cost=10 path-cost=10
  142. /ip neighbor discovery-settings
  143. set protocol=""
  144. /interface bridge vlan
  145. add bridge=bridge-lan tagged=bridge-lan,ether5 vlan-ids=1002
  146. /interface detect-internet
  147. set lan-interface-list=LAN-LIST wan-interface-list=WAN-LIST
  148. /interface list member
  149. add interface=ether2 list=LAN-LIST
  150. add interface=ether3 list=LAN-LIST
  151. add interface=vrn.tv list=WAN-LIST
  152. add interface=bridge-lan list=LAN-LIST
  153. add interface=ether1 list=WAN-LIST
  154. add interface=ether5 list=LAN-LIST
  155. add interface=wireguard2 list=LAN-LIST
  156. add interface=wireguard-alpina list=LAN-LIST
  157. add interface=wireguard2ccc list=LAN-LIST
  158. add interface=WB list=LAN-LIST
  159. /interface wireguard peers
  160. add allowed-address=0.0.0.0/0 endpoint-address=ru2.wg.finevpn.org \
  161.     endpoint-port=993 interface=wireguard2 persistent-keepalive=21s \
  162.     public-key="WMo4krc0Wsi/Pz9rPBQLL38Os8erB+DfSKN4rteUCUU="
  163. add allowed-address=10.10.24.0/30,192.168.240.0/24 endpoint-address=\
  164.     178.210.48.232 endpoint-port=13331 interface=wireguard-alpina \
  165.     persistent-keepalive=5h47m44s public-key=\
  166.     "1IxAnKghKVR2Q9x0nBBnZx38Ve9LD7Cv6Iif2Cb2Ih0="
  167. add allowed-address=\
  168.     10.0.0.0/8,192.168.254.38/32,192.168.254.227/32,192.168.254.250/32 \
  169.     comment=wildberries endpoint-address=wg.wb.ru endpoint-port=443 \
  170.     interface=WB persistent-keepalive=15s preshared-key=\
  171.     "mBOt3pKkHwuG/q+E5eY2te1G1eYxYiz4yk7mJm/6LBM=" public-key=\
  172.     "5rZ+nLz9+O874sw/rgUX3G/0qLiKseYpniUDqC4KYBI="
  173. add allowed-address=10.100.100.3/24 interface=WireguardHome \
  174.     persistent-keepalive=21s public-key=\
  175.     "qHDLG+wVopUbLqjjVPxTa1zdABtu9DH5z4N1z5HTkx0="
  176. add allowed-address=10.100.100.0/24 disabled=yes interface=WireguardHome \
  177.     persistent-keepalive=21s public-key=\
  178.     "+83afkd7kpwKED1qYe1vOBhHtorFjCxm4MFInDtcRnU="
  179. add allowed-address=10.10.10.0/23,192.168.1.0/24 endpoint-address=\
  180.     vusc.softether.net endpoint-port=13232 interface=wireguard2ccc \
  181.     persistent-keepalive=21s public-key=\
  182.     "s3vTV5fgdUbQdCAaxSMCg31QNKxcifNa3ayQAKcx618="
  183. /ip address
  184. add address=192.168.254.1/24 interface=bridge-lan network=192.168.254.0
  185. add address=10.22.138.251 interface=wireguard2 network=10.22.138.251
  186. add address=10.9.34.187/16 disabled=yes interface=wireguard2ccc network=\
  187.     10.9.0.0
  188. add address=10.10.10.2/23 interface=wireguard2ccc network=10.10.10.0
  189. add address=10.10.24.2/30 interface=wireguard-alpina network=10.10.24.0
  190. add address=10.20.100.109 interface=WB network=10.20.100.109
  191. add address=10.100.100.1/24 interface=WireguardHome network=10.100.100.0
  192. add address=192.168.154.1/24 interface=bridge.2 network=192.168.154.0
  193. /ip dhcp-client
  194. add disabled=yes interface=ether1 use-peer-dns=no
  195. /ip dhcp-server alert
  196. add disabled=no interface=bridge-lan
  197. /ip dhcp-server lease
  198. add address=192.168.254.13 client-id=SubWoofer comment="hostname=SubWoofer" \
  199.     mac-address=10:D5:61:D4:70:B6 server=dhcp1
  200. add address=192.168.254.10 client-id=Bathroom1 comment="hostname=Bathroom1" \
  201.     mac-address=10:D5:61:D4:7F:CC server=dhcp1
  202. add address=192.168.254.11 client-id=Bathroom2 comment="hostname=Bathroom2" \
  203.     mac-address=10:D5:61:D4:79:07 server=dhcp1
  204. add address=192.168.254.118 client-id=ZigBee-Gateway comment=\
  205.     "hostname=ZigBee-Gateway" mac-address=10:D5:61:20:4A:03 server=dhcp1
  206. add address=192.168.254.16 client-id=ff:6e:5e:65:a8:0:3:0:1:b8:87:6e:5e:65:a8 \
  207.     mac-address=B8:87:6E:5E:65:A8 server=dhcp1
  208. add address=192.168.254.12 client-id=Bathroom3 comment="hostname=Bathroom3" \
  209.     mac-address=10:D5:61:D4:84:74 server=dhcp1
  210. add address=192.168.254.15 client-id=1:ac:64:cf:a7:b0:4d comment=\
  211.     "hostname=MiRobot" mac-address=AC:64:CF:A7:B0:4D server=dhcp1
  212. add address=192.168.254.3 client-id=1:8:55:31:e4:7d:23 mac-address=\
  213.     08:55:31:E4:7D:23 server=dhcp1
  214. add address=192.168.254.2 client-id=1:ac:15:a2:2:b1:34 comment=\
  215.     "hostname=TL-SG108E" mac-address=AC:15:A2:02:B1:34 server=dhcp1
  216. add address=192.168.254.14 client-id=ff:6e:18:66:1b:0:3:0:1:b8:87:6e:18:66:1b \
  217.     mac-address=B8:87:6E:18:66:1B server=dhcp1
  218. add address=192.168.254.17 client-id=1:6c:d:c4:f4:ca:14 comment=\
  219.     "hostname=MITV" mac-address=6C:0D:C4:F4:CA:14 server=dhcp1
  220. add address=192.168.254.20 client-id=SmartSocketTV comment=\
  221.     "hostname=SmartSocketTV" mac-address=1C:90:FF:59:A4:06 server=dhcp1
  222. add address=192.168.254.18 client-id=SmartSocketWC comment=\
  223.     "hostname=SmartSocketWC" mac-address=1C:90:FF:5A:77:82 server=dhcp1
  224. add address=192.168.254.38 comment="hostname=LieT-PC" mac-address=\
  225.     9C:6B:00:16:C1:CF server=dhcp1
  226. add address=192.168.254.5 client-id=1:d8:38:d:3c:d6:30 comment=\
  227.     "hostname=Wi-Fi AP" mac-address=D8:38:0D:3C:D6:30 server=dhcp1
  228. add address=192.168.154.26 client-id=Gree comment=AC mac-address=\
  229.     78:0F:77:30:C9:DD server=dhcp2
  230. add address=192.168.254.29 client-id=1:c2:40:f9:ef:3c:1c comment=\
  231.     "hostname=HonorView20" mac-address=C2:40:F9:EF:3C:1C server=dhcp1
  232. add address=192.168.254.27 client-id=1:c8:4d:44:20:1c:b7 comment=\
  233.     "hostname=MiBox" mac-address=C8:4D:44:20:1C:B7 server=dhcp1
  234. add address=192.168.254.250 client-id=\
  235.     ff:8a:e0:28:80:0:2:0:0:ab:11:a2:be:d1:6b:a7:81:9c:1d comment=\
  236.     "hostname=rockpi" mac-address=00:E0:4C:03:01:57 server=dhcp1
  237. add address=192.168.254.54 comment="hostname=HUMIDIFIER" mac-address=\
  238.     EC:4D:3E:83:C6:C7 server=dhcp1
  239. add address=192.168.254.56 comment="hostname=Humidity_sensor_bathroom" \
  240.     mac-address=FC:67:1F:E3:74:3A server=dhcp1
  241. add address=192.168.154.49 client-id=1:c0:84:7d:1f:3a:46 comment=\
  242.     "hostname=Yandex.StationRED" mac-address=C0:84:7D:1F:3A:46 server=dhcp2
  243. add address=192.168.254.35 client-id=1:4c:ab:4f:c6:2b:6c comment=\
  244.     "hostname=iPhone-Anna" mac-address=4C:AB:4F:C6:2B:6C server=dhcp1
  245. add address=192.168.254.227 client-id=1:5c:ed:f4:a0:17:80 comment=\
  246.     "hostname=LieT-S22" mac-address=5C:ED:F4:A0:17:80 server=dhcp1
  247. add address=192.168.154.4 comment="hostname=HUMIDIFIER2" mac-address=\
  248.     7C:C2:94:26:96:E5 server=dhcp2
  249. add address=192.168.154.8 comment="hostname=HUMIDIFIER" mac-address=\
  250.     EC:4D:3E:83:C6:C7 server=dhcp2
  251. add address=192.168.154.10 client-id=\
  252.     ff:6e:18:66:1b:0:1:0:1:2d:20:2e:59:b8:87:6e:18:66:1b mac-address=\
  253.     B8:87:6E:18:66:1B server=dhcp2
  254. add address=192.168.154.13 client-id=\
  255.     ff:6e:5e:65:a8:0:1:0:1:c7:92:bc:8b:b8:87:6e:5e:65:a8 mac-address=\
  256.     B8:87:6E:5E:65:A8 server=dhcp2
  257. /ip dhcp-server network
  258. add address=192.168.154.0/24 dns-server=192.168.254.250 gateway=192.168.154.1 \
  259.     netmask=24
  260. add address=192.168.254.0/24 dns-server=192.168.254.250 gateway=192.168.254.1 \
  261.     ntp-server=192.168.254.1
  262. /ip dns
  263. set cache-max-ttl=1s cache-size=1024KiB max-concurrent-queries=1000 \
  264.     max-concurrent-tcp-sessions=700 max-udp-packet-size=1800 \
  265.     query-server-timeout=1s query-total-timeout=3s servers=192.168.254.250 \
  266.     use-doh-server=https://main.mentat.su/dns-query verify-doh-cert=yes
  267. /ip dns static
  268. add forward-to=10.15.12.200 regexp="^.*(\\.|^)wb\\.ru\\.\?\$" type=FWD
  269. add address=93.115.24.204 comment=\
  270.     "https://dns.comss.one/dns-query 93.115.24.204 93.115.24.205" name=\
  271.     dns.comss.one
  272. add address=93.115.24.205 disabled=yes name=dns.comss.one
  273. add address=45.91.92.121 disabled=yes name=doh-ch.blahdns.com
  274. add address=45.90.28.199 comment=\
  275.     https://dns.nextdns.io/cdd1f6/Mikrotik%20hAP3 disabled=yes name=\
  276.     dns.nextdns.io
  277. add address=45.90.30.199 disabled=yes name=dns.nextdns.io
  278. add address=2a07:a8c0:: disabled=yes name=dns.nextdns.io type=AAAA
  279. add address=2a07:a8c1:: disabled=yes name=dns.nextdns.io type=AAAA
  280. add address=185.199.111.153 disabled=yes name=lampa.mx
  281. add address=94.140.14.49 comment=https://72984969.d.adguard-dns.com/dns-query \
  282.     disabled=yes name=72984969.d.adguard-dns.com
  283. add address=94.140.14.59 comment=https://72984969.d.adguard-dns.com/dns-query \
  284.     disabled=yes name=72984969.d.adguard-dns.com
  285. add comment=OpenNIC disabled=yes forward-to=\
  286.     185.121.177.177,169.239.202.202,2a05:dfc7:5::53::1,2a05:dfc7:5::5353::1 \
  287.     regexp=".*(\\.bbs|\\.chan|\\.cyb|\\.dyn|\\.geek|\\.gopher|\\.indy|\\.libre\
  288.    |\\.neo|\\.null|\\.o)\$" type=FWD
  289. add comment=OpenNIC forward-to=\
  290.     185.121.177.177,169.239.202.202,2a05:dfc7:5::53::1,2a05:dfc7:5::5353::1 \
  291.     regexp=".*(\\.oss|\\.oz|\\.parody|\\.pirate|\\.opennic.glue|\\.dns\\.openn\
  292.    ic\\.glue)\$" type=FWD
  293. add address=192.168.254.250 comment=\
  294.     "managed by dhcp-to-dns, macaddress=00:E0:4C:03:01:57, server=dhcp1" \
  295.     name=00-E0-4C-03-01-57.dune.local ttl=5m
  296. add cname=00-E0-4C-03-01-57.dune.local comment=\
  297.     "managed by dhcp-to-dns, macaddress=00:E0:4C:03:01:57, server=dhcp1" \
  298.     name=rockpi.dune.local ttl=5m type=CNAME
  299. add address=192.168.254.2 comment=\
  300.     "managed by dhcp-to-dns, macaddress=AC:15:A2:02:B1:34, server=dhcp1" \
  301.     name=AC-15-A2-02-B1-34.dune.local ttl=5m
  302. add cname=AC-15-A2-02-B1-34.dune.local comment=\
  303.     "managed by dhcp-to-dns, macaddress=AC:15:A2:02:B1:34, server=dhcp1" \
  304.     name=TL-SG108E.dune.local ttl=5m type=CNAME
  305. add address=192.168.254.13 comment=\
  306.     "managed by dhcp-to-dns, macaddress=10:D5:61:D4:70:B6, server=dhcp1" \
  307.     name=10-D5-61-D4-70-B6.dune.local ttl=5m
  308. add cname=10-D5-61-D4-70-B6.dune.local comment=\
  309.     "managed by dhcp-to-dns, macaddress=10:D5:61:D4:70:B6, server=dhcp1" \
  310.     name=SubWoofer.dune.local ttl=5m type=CNAME
  311. add address=192.168.254.51 comment=\
  312.     "managed by dhcp-to-dns, macaddress=1C:90:FF:58:97:A6, server=dhcp1" \
  313.     name=1C-90-FF-58-97-A6.dune.local ttl=5m
  314. add cname=1C-90-FF-58-97-A6.dune.local comment=\
  315.     "managed by dhcp-to-dns, macaddress=1C:90:FF:58:97:A6, server=dhcp1" \
  316.     name=wlan0.dune.local ttl=5m type=CNAME
  317. add address=192.168.154.2 comment=\
  318.     "managed by dhcp-to-dns, macaddress=1C:90:FF:59:A4:06, server=dhcp2" \
  319.     name=1C-90-FF-59-A4-06.dune.local ttl=5m
  320. add address=192.168.154.3 comment=\
  321.     "managed by dhcp-to-dns, macaddress=10:D5:61:D4:79:07, server=dhcp2" \
  322.     name=10-D5-61-D4-79-07.dune.local ttl=5m
  323. add address=192.168.154.4 comment=\
  324.     "managed by dhcp-to-dns, macaddress=7C:C2:94:26:96:E5, server=dhcp2" \
  325.     name=7C-C2-94-26-96-E5.dune.local ttl=5m
  326. add address=192.168.154.5 comment=\
  327.     "managed by dhcp-to-dns, macaddress=10:D5:61:D4:84:74, server=dhcp2" \
  328.     name=10-D5-61-D4-84-74.dune.local ttl=5m
  329. add address=192.168.154.7 comment=\
  330.     "managed by dhcp-to-dns, macaddress=10:D5:61:D4:7F:CC, server=dhcp2" \
  331.     name=10-D5-61-D4-7F-CC.dune.local ttl=5m
  332. add address=192.168.154.8 comment=\
  333.     "managed by dhcp-to-dns, macaddress=EC:4D:3E:83:C6:C7, server=dhcp2" \
  334.     name=EC-4D-3E-83-C6-C7.dune.local ttl=5m
  335. add address=192.168.154.9 comment=\
  336.     "managed by dhcp-to-dns, macaddress=FC:67:1F:5A:FB:4E, server=dhcp2" \
  337.     name=FC-67-1F-5A-FB-4E.dune.local ttl=5m
  338. add address=192.168.154.10 comment=\
  339.     "managed by dhcp-to-dns, macaddress=B8:87:6E:18:66:1B, server=dhcp2" \
  340.     name=B8-87-6E-18-66-1B.dune.local ttl=5m
  341. add cname=B8-87-6E-18-66-1B.dune.local comment=\
  342.     "managed by dhcp-to-dns, macaddress=B8:87:6E:18:66:1B, server=dhcp2" \
  343.     name=yandex-mini2.dune.local ttl=5m type=CNAME
  344. add address=192.168.254.38 comment=\
  345.     "managed by dhcp-to-dns, macaddress=9C:6B:00:16:C1:CF, server=dhcp1" \
  346.     name=9C-6B-00-16-C1-CF.dune.local ttl=5m
  347. add cname=9C-6B-00-16-C1-CF.dune.local comment=\
  348.     "managed by dhcp-to-dns, macaddress=9C:6B:00:16:C1:CF, server=dhcp1" \
  349.     name=LieT-PC.dune.local ttl=5m type=CNAME
  350. add cname=7C-C2-94-26-96-E5.dune.local comment=\
  351.     "managed by dhcp-to-dns, macaddress=7C:C2:94:26:96:E5, server=dhcp2" \
  352.     name=HUMIDIFIER2.dune.local ttl=5m type=CNAME
  353. add cname=EC-4D-3E-83-C6-C7.dune.local comment=\
  354.     "managed by dhcp-to-dns, macaddress=EC:4D:3E:83:C6:C7, server=dhcp2" \
  355.     name=HUMIDIFIER.dune.local ttl=5m type=CNAME
  356. add address=192.168.154.49 comment=\
  357.     "managed by dhcp-to-dns, macaddress=C0:84:7D:1F:3A:46, server=dhcp2" \
  358.     name=C0-84-7D-1F-3A-46.dune.local ttl=5m
  359. add cname=C0-84-7D-1F-3A-46.dune.local comment=\
  360.     "managed by dhcp-to-dns, macaddress=C0:84:7D:1F:3A:46, server=dhcp2" \
  361.     name=Yandex.StationRED.dune.local ttl=5m type=CNAME
  362. add address=192.168.254.5 comment=\
  363.     "managed by dhcp-to-dns, macaddress=D8:38:0D:3C:D6:30, server=dhcp1" \
  364.     name=D8-38-0D-3C-D6-30.dune.local ttl=5m
  365. add cname=D8-38-0D-3C-D6-30.dune.local comment=\
  366.     "managed by dhcp-to-dns, macaddress=D8:38:0D:3C:D6:30, server=dhcp1" \
  367.     name=Wi-FiAP.dune.local ttl=5m type=CNAME
  368. add address=192.168.254.28 comment=\
  369.     "managed by dhcp-to-dns, macaddress=78:4F:43:43:FF:96, server=dhcp1" \
  370.     name=78-4F-43-43-FF-96.dune.local ttl=5m
  371. add cname=78-4F-43-43-FF-96.dune.local comment=\
  372.     "managed by dhcp-to-dns, macaddress=78:4F:43:43:FF:96, server=dhcp1" \
  373.     name=iPhone-Mihail.dune.local ttl=5m type=CNAME
  374. add address=192.168.254.35 comment=\
  375.     "managed by dhcp-to-dns, macaddress=4C:AB:4F:C6:2B:6C, server=dhcp1" \
  376.     name=4C-AB-4F-C6-2B-6C.dune.local ttl=5m
  377. add cname=4C-AB-4F-C6-2B-6C.dune.local comment=\
  378.     "managed by dhcp-to-dns, macaddress=4C:AB:4F:C6:2B:6C, server=dhcp1" \
  379.     name=iPhone-Anna.dune.local ttl=5m type=CNAME
  380. add address=192.168.154.13 comment=\
  381.     "managed by dhcp-to-dns, macaddress=B8:87:6E:5E:65:A8, server=dhcp2" \
  382.     name=B8-87-6E-5E-65-A8.dune.local ttl=5m
  383. add cname=B8-87-6E-5E-65-A8.dune.local comment=\
  384.     "managed by dhcp-to-dns, macaddress=B8:87:6E:5E:65:A8, server=dhcp2" \
  385.     name=Yandex-Station-gen2.dune.local ttl=5m type=CNAME
  386. add address=192.168.154.6 comment=\
  387.     "managed by dhcp-to-dns, macaddress=3A:C9:E8:0D:A7:5D, server=dhcp2" \
  388.     name=3A-C9-E8-0D-A7-5D.dune.local ttl=5m
  389. add cname=3A-C9-E8-0D-A7-5D.dune.local comment=\
  390.     "managed by dhcp-to-dns, macaddress=3A:C9:E8:0D:A7:5D, server=dhcp2" \
  391.     name=LieT-S22.dune.local ttl=5m type=CNAME
  392. add address=192.168.254.17 comment=\
  393.     "managed by dhcp-to-dns, macaddress=6C:0D:C4:F4:CA:14, server=dhcp1" \
  394.     name=6C-0D-C4-F4-CA-14.dune.local ttl=5m
  395. add cname=6C-0D-C4-F4-CA-14.dune.local comment=\
  396.     "managed by dhcp-to-dns, macaddress=6C:0D:C4:F4:CA:14, server=dhcp1" \
  397.     name=MITV.dune.local ttl=5m type=CNAME
  398. add comment="--- dhcp-to-dns above ---" disabled=yes name=- type=NXDOMAIN
  399. add address=104.20.91.49 disabled=yes name=auth.adguard.com
  400. add address=95.142.47.131 comment=https://main.mentat.su/dns-query name=\
  401.     monitoring.mentat.su
  402. add address=192.168.254.250 name=main.mentat.su
  403. add address=1.1.1.1 name=dns.cloudflare.com
  404. add address=1.0.0.1 name=dns.cloudflare.com
  405. add address=2606:4700:4700::1111 comment=https://1.1.1.1/dns-query name=\
  406.     dns.cloudflare.com type=AAAA
  407. add address=2606:4700:4700::1001 name=dns.cloudflare.com type=AAAA
  408. add address=10.15.12.100 comment=111 disabled=yes regexp=".*.wb\\.ru\$"
  409. add disabled=yes forward-to=10.15.12.200 match-subdomain=yes name=wb.ru type=\
  410.     FWD
  411. add address=8.8.8.8 name=dns.google
  412. add address=91.230.107.85 name=wg.wb.ru
  413. add forward-to=10.15.12.200 regexp=".*\\.wb.\\ru" type=FWD
  414. add forward-to=10.15.12.200 regexp=" \\.wb\\.ru\$" type=FWD
  415. add forward-to=10.15.12.200 regexp=".*wb\\.ru" type=FWD
  416. add address=192.168.254.26 comment=dhcp1-78:0F:77:30:C9:DD name=BL-30-c9-dd \
  417.     ttl=15m
  418. add address=192.168.254.38 comment=dhcp1-9C:6B:00:16:C1:CF name=LieT-PC ttl=\
  419.     15m
  420. add address=192.168.254.2 comment=dhcp1-AC:15:A2:02:B1:34 name=TL-SG108E ttl=\
  421.     15m
  422. add address=192.168.254.5 comment=dhcp1-D8:38:0D:3C:D6:30 name=\
  423.     linux-30d63c0d38d8 ttl=15m
  424. add address=192.168.254.28 comment=dhcp1-78:4F:43:43:FF:96 name=iPhone-Mihail \
  425.     ttl=15m
  426. add address=192.168.254.250 comment=dhcp1-00:E0:4C:03:01:57 name=rockpi ttl=\
  427.     15m
  428. add address=192.168.254.51 comment=dhcp1-1C:90:FF:58:97:A6 name=wlan0 ttl=15m
  429. add address=192.168.254.35 comment=dhcp1-4C:AB:4F:C6:2B:6C name=iPhone-Anna \
  430.     ttl=15m
  431. add address=192.168.254.13 comment=dhcp1-10:D5:61:D4:70:B6 name=wlan0 ttl=15m
  432. add address=192.168.254.17 comment=dhcp1-6C:0D:C4:F4:CA:14 name=MITV ttl=15m
  433. /ip firewall address-list
  434. add address=192.168.254.0/24 list=LOCAL_LAN
  435. add address=atredes.rostelekom.xyz list=Route2Force_vrn.tv
  436. add address=192.168.254.20 list=S22
  437. add address=192.168.254.21 list=S22
  438. add address=192.168.240.0/24 list=ALLOWED_NETWORKS
  439. add address=192.168.1.0/24 list=ALLOWED_NETWORKS
  440. add address=10.10.10.0/30 list=ALLOWED_NETWORKS
  441. add address=10.20.89.70 list=ALLOWED_NETWORKS
  442. add address=10.10.24.0/30 list=ALLOWED_NETWORKS
  443. add address=192.168.254.0/24 list=LAN+WIFI
  444. add address=192.168.3.0/24 list=LAN+WIFI
  445. add address=192.168.254.250 list=2-WB
  446. add address=192.168.254.38 list=2-WB
  447. add address=192.168.254.227 list=2-WB
  448. add address=93.189.48.0/21 list=Tele2
  449. add address=176.59.0.0/19 list=Tele2
  450. add address=217.169.82.0/23 list=Tele2
  451. add address=217.169.84.0/22 list=Tele2
  452. add address=217.169.88.0/21 list=Tele2
  453. add address=10.15.12.100 list=ExcludeDNSForward
  454. add address=0.0.0.0/8 comment=RFC6890 list=not_in_internet
  455. add address=172.16.0.0/12 comment=RFC6890 list=not_in_internet
  456. add address=192.168.0.0/16 comment=RFC6890 list=not_in_internet
  457. add address=10.0.0.0/8 comment=RFC6890 list=not_in_internet
  458. add address=169.254.0.0/16 comment=RFC6890 list=not_in_internet
  459. add address=127.0.0.0/8 comment=RFC6890 list=not_in_internet
  460. add address=224.0.0.0/4 comment=Multicast list=not_in_internet
  461. add address=198.18.0.0/15 comment=RFC6890 list=not_in_internet
  462. add address=192.0.0.0/24 comment=RFC6890 list=not_in_internet
  463. add address=192.0.2.0/24 comment=RFC6890 list=not_in_internet
  464. add address=198.51.100.0/24 comment=RFC6890 list=not_in_internet
  465. add address=203.0.113.0/24 comment=RFC6890 list=not_in_internet
  466. add address=100.64.0.0/10 comment=RFC6890 list=not_in_internet
  467. add address=240.0.0.0/4 comment=RFC6890 list=not_in_internet
  468. add address=192.88.99.0/24 comment="6to4 relay Anycast [RFC 3068]" list=\
  469.     not_in_internet
  470. add address=192.168.154.0/24 list=LOCAL_LAN
  471. /ip firewall filter
  472. add action=drop chain=input comment=Invalid-DROP connection-state=invalid \
  473.     log-prefix=Invalid
  474. add action=drop chain=forward comment=\
  475.     "Drop packets from LAN that do not have LAN IP" in-interface=bridge-lan \
  476.     log=yes log-prefix=LAN_!LAN src-address-list=!LOCAL_LAN
  477. add action=drop chain=forward comment=\
  478.     "Drop incoming packets that are not NAT`ted" connection-nat-state=!dstnat \
  479.    connection-state=new in-interface=vrn.tv log=yes log-prefix=!NAT
  480. add action=drop chain=forward comment=\
  481.    "Drop incoming from internet which is not public IP" in-interface=vrn.tv \
  482.    log=yes log-prefix=!public src-address-list=not_in_internet
  483. add action=fasttrack-connection chain=forward comment="defconf: fasttrack" \
  484.    connection-state=established,related hw-offload=yes in-interface=\
  485.    bridge-lan out-interface-list=WAN-LIST
  486. add action=fasttrack-connection chain=forward comment=\
  487.    "111111111defconf: fasttrack" connection-state=established,related \
  488.    hw-offload=yes in-interface=bridge.2 out-interface-list=WAN-LIST
  489. add action=fasttrack-connection chain=forward comment="defconf: fasttrack" \
  490.    connection-mark=no-mark connection-state=established,related dst-port=!53 \
  491.    hw-offload=yes in-interface-list=WAN-LIST out-interface=bridge-lan \
  492.    protocol=udp
  493. add action=fasttrack-connection chain=forward comment=\
  494.    "111111defconf: fasttrack" connection-mark=no-mark connection-state=\
  495.    established,related dst-port=!53 hw-offload=yes in-interface-list=\
  496.    WAN-LIST out-interface=bridge.2 protocol=udp
  497. add action=accept chain=input comment="allow wireguard" dst-port=13256 \
  498.    protocol=udp
  499. add action=accept chain=forward dst-address-list=LOCAL_LAN src-address-list=\
  500.    LOCAL_LAN
  501. add action=drop chain=output disabled=yes log-prefix=RST protocol=tcp \
  502.    tcp-flags=rst
  503. add action=drop chain=input comment="dns block" dst-port=53,853,5353 \
  504.    log-prefix="DNS BLOCK" protocol=udp src-address-list=!LOCAL_LAN
  505. add action=accept chain=input comment="Accept All DEBUG" disabled=yes \
  506.    log-prefix="ALLOW ALL DEBUG"
  507. add action=accept chain=forward comment="Accept All DEBUG" disabled=yes \
  508.    log-prefix="ALLOW ALL DEBUG"
  509. add action=accept chain=input dst-address=10.10.10.0/30 log-prefix=CCC!
  510. add action=accept chain=input dst-address=192.168.154.0/24 log-prefix=\
  511.    CC23232C!
  512. add action=accept chain=input dst-address=10.100.100.0/24 log-prefix=CCC! \
  513.    protocol=udp
  514. add action=accept chain=input comment="DISABLE 14/02" in-interface=\
  515.    wireguard-alpina log=yes log-prefix=alpina
  516. add action=accept chain=input comment="DISABLE 14/02" in-interface=\
  517.    wireguard2ccc log=yes log-prefix=alpina
  518. add action=drop chain=input dst-port=53 in-interface-list=WAN-LIST log=yes \
  519.    log-prefix=DROP_DNS_WEB protocol=udp src-address-list=!LOCAL_LAN
  520. add action=reject chain=forward disabled=yes in-interface=bridge-lan log=yes \
  521.    log-prefix=DROP_NOT_INCOMING_FROM_LAN reject-with=\
  522.    icmp-network-unreachable src-address-list=!LAN+WIFI
  523. add action=accept chain=input connection-state=established,related,untracked \
  524.    in-interface-list=WAN-LIST
  525. add action=accept chain=forward comment=\
  526.    "1.1. Forward and Input Established and Related connections" \
  527.    connection-state=established,related,untracked in-interface-list=WAN-LIST
  528. add action=accept chain=input comment="Allow IGMP" in-interface-list=WAN-LIST \
  529.    protocol=igmp
  530. add action=accept chain=input comment="Allow LAN Traffic" in-interface-list=\
  531.    LAN-LIST
  532. add action=accept chain=input disabled=yes dst-port=53 in-interface-list=\
  533.    LAN-LIST protocol=udp
  534. add action=accept chain=input comment=\
  535.    "Allow Discover in LAN,DISABLE 14/02 zero trafic" disabled=yes \
  536.    in-interface-list=LAN-LIST port=5678 protocol=udp
  537. add action=accept chain=input comment="Allow SNMP" dst-port=161 \
  538.    in-interface-list=WAN-LIST log-prefix=SNMPF protocol=udp
  539. add action=accept chain=input comment="Allow API" dst-port=8728 \
  540.    in-interface-list=WAN-LIST log-prefix="API Prometheus" protocol=tcp \
  541.    src-address=95.142.47.131
  542. add action=accept chain=forward comment=WG dst-port=13256 in-interface-list=\
  543.    WAN-LIST log-prefix=WG protocol=udp src-address=0.0.0.0
  544. add action=accept chain=input comment="Access Normal Ping" in-interface-list=\
  545.    WAN-LIST limit=50/5s,2:packet protocol=icmp
  546. add action=add-src-to-address-list address-list="Hacker Scanners" \
  547.    address-list-timeout=4w2d chain=input comment="Port Scanners" \
  548.    in-interface-list=WAN-LIST protocol=tcp psd=21,3s,3,1
  549. add action=add-src-to-address-list address-list="Hacker Scanners" \
  550.    address-list-timeout=4w2d chain=input comment="NMAP FIN Stealth scan" \
  551.    in-interface-list=WAN-LIST protocol=tcp tcp-flags=\
  552.    fin,!syn,!rst,!psh,!ack,!urg
  553. add action=add-src-to-address-list address-list="Hacker Scanners" \
  554.    address-list-timeout=4w2d chain=input comment="SYN/FIN scan" \
  555.    in-interface-list=WAN-LIST protocol=tcp tcp-flags=fin,syn
  556. add action=add-src-to-address-list address-list="Hacker Scanners" \
  557.    address-list-timeout=4w2d chain=input comment="SYN/RST scan" \
  558.    in-interface-list=WAN-LIST protocol=tcp tcp-flags=syn,rst
  559. add action=add-src-to-address-list address-list="Hacker Scanners" \
  560.    address-list-timeout=4w2d chain=input comment="FIN/PSH/URG scan" \
  561.    in-interface-list=WAN-LIST protocol=tcp tcp-flags=\
  562.    fin,psh,urg,!syn,!rst,!ack
  563. add action=add-src-to-address-list address-list="Hacker Scanners" \
  564.    address-list-timeout=4w2d chain=input comment="ALL/ALL scan" \
  565.    in-interface-list=WAN-LIST protocol=tcp tcp-flags=fin,syn,rst,psh,ack,urg
  566. add action=add-src-to-address-list address-list="Hacker Scanners" \
  567.    address-list-timeout=4w2d chain=input comment="NMAP NULL scan" \
  568.    in-interface-list=WAN-LIST protocol=tcp tcp-flags=\
  569.    !fin,!syn,!rst,!psh,!ack,!urg
  570. add action=add-src-to-address-list address-list="Honeypot Hacker" \
  571.    address-list-timeout=4w2d chain=input comment=\
  572.    "block honeypot ssh rdp winbox" connection-state=new dst-port=\
  573.    22,3389,8291,25,21,8728 in-interface-list=WAN-LIST protocol=tcp
  574. add action=drop chain=input comment="drop 8.217.255.5" src-address=\
  575.    8.217.255.5
  576. add action=drop chain=forward comment="drop 8.217.255.5" src-address=\
  577.    8.217.255.5
  578. add action=drop chain=input comment="Drop All Other" disabled=yes \
  579.    in-interface-list=WAN-LIST log-prefix=DEF_DROP
  580. /ip firewall mangle
  581. add action=change-mss chain=forward disabled=yes log=yes log-prefix=\
  582.    CHANGE-MSS-OUT new-mss=clamp-to-pmtu out-interface-list=WAN-LIST \
  583.    passthrough=yes protocol=tcp tcp-flags=syn tcp-mss=1300-65535
  584. add action=change-mss chain=forward new-mss=1420 out-interface-list=WAN-LIST \
  585.    passthrough=yes protocol=tcp tcp-flags=syn tcp-mss=1421-65535
  586. add action=change-mss chain=forward in-interface-list=WAN-LIST log-prefix=\
  587.    CHANGE-MSS-OUT new-mss=clamp-to-pmtu passthrough=no protocol=tcp \
  588.    tcp-flags=syn tcp-mss=1300-65535
  589. add action=mark-connection chain=prerouting comment=DNS-Mark \
  590.    connection-state=new disabled=yes dst-port=53,853,5353 \
  591.    new-connection-mark=via-dns passthrough=yes protocol=tcp src-address=\
  592.    192.168.254.0/24
  593. add action=mark-connection chain=prerouting connection-state=new disabled=yes \
  594.    dst-port=53,853,5353 new-connection-mark=via-dns passthrough=yes \
  595.    protocol=udp src-address=192.168.254.0/24
  596. add action=change-mss chain=forward disabled=yes new-mss=1400 out-interface=\
  597.    WB passthrough=yes protocol=tcp tcp-flags=syn
  598. /ip firewall nat
  599. add action=masquerade chain=srcnat comment=TELEKOM-SERVICE dst-address=\
  600.    !192.168.254.0/24 log-prefix=1 out-interface=vrn.tv src-address=\
  601.    192.168.254.0/24 to-addresses=185.23.83.133
  602. add action=masquerade chain=srcnat dst-port=!53,853,5353 log-prefix=\
  603.    sdsdsdddsdd protocol=udp src-address=192.168.154.0/24
  604. add action=masquerade chain=srcnat dst-port=!53,853,5353 log-prefix=\
  605.    sdsdsdddsdd protocol=tcp src-address=192.168.154.0/24
  606. add action=dst-nat chain=dstnat comment=piholeNAT1 dst-port=53,853,5353 \
  607.    log-prefix="DNS forward" protocol=udp src-address=192.168.154.0/24 \
  608.    to-addresses=192.168.254.250
  609. add action=dst-nat chain=dstnat comment=piholeNAT1 dst-port=53,853,5353 \
  610.    log-prefix="DNS forward" protocol=tcp src-address=192.168.154.0/24 \
  611.    to-addresses=192.168.254.250
  612. add action=masquerade chain=srcnat dst-address=192.168.154.0/24 log-prefix=\
  613.    !!!!192.168.154.4 out-interface=bridge.2 src-address=192.168.254.250
  614. add action=masquerade chain=srcnat disabled=yes dst-address=192.168.154.8 \
  615.    log=yes log-prefix=!!!!192.168.154.8 out-interface=bridge.2 src-address=\
  616.    192.168.254.250
  617. add action=masquerade chain=srcnat comment=TELEKOM-SERVICE-IOT dst-address=\
  618.    !192.168.154.0/24 log-prefix=IOT out-interface=vrn.tv src-address=\
  619.    192.168.154.0/24 to-addresses=185.23.83.133
  620. add action=dst-nat chain=dstnat comment=piholeNAT2 disabled=yes dst-address=\
  621.    !192.168.254.250 dst-port=53,853,5353 protocol=tcp src-address=\
  622.    !192.168.254.250 to-addresses=192.168.254.250
  623. add action=masquerade chain=srcnat comment=piholeNAT3 disabled=yes \
  624.    dst-address=192.168.254.250 dst-port=53,853,5353 protocol=udp \
  625.    src-address=192.168.254.0/24
  626. add action=masquerade chain=srcnat comment=piholeNAT4 disabled=yes \
  627.    dst-address=192.168.254.250 dst-port=53,853,5353 protocol=tcp \
  628.    src-address=192.168.254.0/24
  629. add action=src-nat chain=srcnat comment=MEGAFON disabled=yes dst-address=\
  630.    !192.168.254.0/24 log-prefix=1 out-interface=ether1 src-address=\
  631.    192.168.254.0/24 to-addresses=46.72.222.7
  632. add action=masquerade chain=srcnat log-prefix=!!! out-interface=wireguard2 \
  633.    src-address=192.168.254.0/24
  634. add action=masquerade chain=srcnat out-interface=wireguard2ccc src-address=\
  635.    192.168.254.0/24
  636. add action=src-nat chain=srcnat comment=MAIN_SRCNAT disabled=yes log=yes \
  637.    out-interface=wireguard-alpina to-addresses=10.10.24.1
  638. add action=masquerade chain=srcnat comment=WB log-prefix=2 out-interface=WB \
  639.    src-address-list=2-WB
  640. add action=src-nat chain=srcnat comment="NAT 2 CCC" out-interface=\
  641.    wireguard2ccc src-address-list=LOCAL_LAN to-addresses=10.10.10.2
  642. add action=masquerade chain=srcnat comment="ALPINA CCC" log-prefix=1 \
  643.    out-interface=wireguard-alpina src-address=192.168.254.0/24
  644. add action=masquerade chain=srcnat comment=" CCC" log-prefix=1 out-interface=\
  645.    wireguard2ccc src-address=192.168.254.0/24
  646. add action=masquerade chain=srcnat comment="MASQL CCC" dst-address=\
  647.    10.10.10.0/23 dst-address-list="" log=yes log-prefix=1
  648. add action=dst-nat chain=dstnat comment=DNS-QUIC-S22 disabled=yes \
  649.    dst-address=185.23.83.133 dst-port=853 log=yes log-prefix=S22 protocol=\
  650.    tcp to-addresses=192.168.254.250 to-ports=853
  651. add action=masquerade chain=srcnat disabled=yes out-interface=vrn.tv \
  652.    src-address=192.168.254.0/24
  653. add action=src-nat chain=srcnat src-address=10.2.0.2 to-addresses=\
  654.    192.168.254.1
  655. add action=redirect chain=dstnat comment="Make Mikrotik preferred dns server" \
  656.    disabled=yes dst-port=53,853,5353 in-interface=bridge-lan log-prefix=\
  657.    DNS_FWD_UDP protocol=udp to-addresses=192.168.254.1 to-ports=53
  658. add action=redirect chain=dstnat comment="Make Mikrotik preferred dns server" \
  659.    disabled=yes dst-port=53,853,5353 in-interface=bridge-lan log-prefix=\
  660.    DNS_FWD_TCP protocol=tcp src-address-list=!S22 to-addresses=192.168.254.1 \
  661.    to-ports=53
  662. add action=dst-nat chain=dstnat dst-address=185.23.83.133 dst-port=8729 \
  663.    in-interface-list=WAN-LIST log-prefix=AP-API protocol=tcp to-addresses=\
  664.    192.168.254.19 to-ports=8728
  665. add action=dst-nat chain=dstnat comment=Prometheus2Router dst-address=\
  666.    185.23.83.133 dst-port=8729 in-interface-list=WAN-LIST log-prefix=AP-API \
  667.    protocol=tcp to-addresses=192.168.254.1 to-ports=8728
  668. add action=dst-nat chain=dstnat dst-address=185.23.83.133 dst-port=9221 \
  669.    protocol=tcp to-addresses=192.168.254.250 to-ports=9100
  670. add action=dst-nat chain=dstnat dst-port=53,853,5353 in-interface-list=\
  671.    !WAN-LIST protocol=udp src-address-list=!LOCAL_LAN to-addresses=\
  672.    192.168.254.250 to-ports=853
  673. add action=dst-nat chain=dstnat comment=----------- dst-address=185.23.83.133 \
  674.    dst-port=14620 protocol=tcp to-addresses=192.168.254.23 to-ports=14620
  675. add action=dst-nat chain=dstnat comment=adguard dst-address=185.23.83.133 \
  676.    dst-port=9617 protocol=tcp to-addresses=192.168.254.250 to-ports=9617
  677. add action=dst-nat chain=dstnat comment=bb-exporter dst-address=185.23.83.133 \
  678.    dst-port=9515 protocol=tcp to-addresses=192.168.254.23 to-ports=9115
  679. add action=dst-nat chain=dstnat comment=adguard disabled=yes dst-address=\
  680.    185.23.83.133 dst-port=3344 protocol=tcp to-addresses=192.168.254.23 \
  681.    to-ports=443
  682. add action=dst-nat chain=dstnat comment=DNS-QUIC-S22 dst-address=\
  683.    185.23.83.133 dst-port=53,853,5353 log-prefix=vps protocol=udp \
  684.    src-address=95.142.47.131 to-addresses=192.168.254.250 to-ports=53
  685. add action=dst-nat chain=dstnat comment="ZABBIX PC" dst-address=185.23.83.133 \
  686.    dst-port=12350 log-prefix=zabbix-ps protocol=tcp src-address=\
  687.    95.142.47.131 to-addresses=192.168.254.38 to-ports=10050
  688. add action=dst-nat chain=dstnat comment=DNS_REDIRECT disabled=yes \
  689.    dst-address=!10.15.12.100 dst-port=53 protocol=udp to-addresses=\
  690.    192.168.254.250 to-ports=53
  691. add action=dst-nat chain=dstnat comment=DNS_REDIRECT disabled=yes dst-port=53 \
  692.    protocol=tcp to-addresses=192.168.254.250 to-ports=53
  693. add action=dst-nat chain=dstnat comment=DNS_REDIRECT disabled=yes dst-port=\
  694.    853 protocol=udp to-addresses=192.168.254.250 to-ports=853
  695. add action=dst-nat chain=dstnat comment=DNS_REDIRECT disabled=yes dst-port=\
  696.    5353 protocol=tcp to-addresses=192.168.254.250 to-ports=5353
  697. /ip firewall raw
  698. add action=drop chain=prerouting in-interface=vrn.tv src-address-list=\
  699.    "Honeypot Hacker"
  700. add action=drop chain=prerouting in-interface=vrn.tv src-address-list=\
  701.    "Hacker Scanners"
  702. add action=drop chain=prerouting dst-port=137,138,139 in-interface-list=\
  703.    WAN-LIST protocol=udp
  704. /ip firewall service-port
  705. set ftp disabled=yes
  706. /ip route
  707. add blackhole dst-address=172.16.0.0/12
  708. add blackhole dst-address=192.168.0.0/16
  709. add disabled=no distance=1 dst-address=45.90.28.199/32 gateway=vrn.tv \
  710.    pref-src="" routing-table=main scope=30 suppress-hw-offload=no \
  711.    target-scope=10
  712. add disabled=no distance=1 dst-address=5.61.54.61/32 gateway=vrn.tv pref-src=\
  713.    "" routing-table=main scope=30 suppress-hw-offload=yes target-scope=10
  714. add comment=Adguard disabled=no distance=1 dst-address=104.20.90.0/23 \
  715.    gateway=vrn.tv pref-src="" routing-table=main scope=30 \
  716.    suppress-hw-offload=no target-scope=10
  717. add comment=LAN->CCC disabled=no distance=1 dst-address=192.168.1.0/24 \
  718.    gateway=10.10.10.1 pref-src="" routing-table=main scope=30 \
  719.    suppress-hw-offload=no target-scope=10
  720. add disabled=no distance=1 dst-address=10.10.240.0/30 gateway=\
  721.    wireguard-alpina pref-src="" routing-table=main scope=30 \
  722.    suppress-hw-offload=no target-scope=10
  723. add comment=LAN->Alpina disabled=no distance=1 dst-address=192.168.240.0/24 \
  724.    gateway=10.10.24.1 pref-src="" routing-table=main scope=30 \
  725.    suppress-hw-offload=no target-scope=10
  726. add comment=10.0.0.0/8 disabled=no distance=1 dst-address=10.15.12.100/32 \
  727.    gateway=WB pref-src="" routing-table=main scope=30 suppress-hw-offload=no \
  728.    target-scope=10
  729. add comment=Sber disabled=no distance=1 dst-address=91.206.30.0/24 gateway=\
  730.    vrn.tv pref-src="" routing-table=main scope=30 suppress-hw-offload=no \
  731.    target-scope=10
  732. add disabled=no distance=20 dst-address=46.19.138.67/32 gateway=wireguard2 \
  733.    routing-table=main scope=40 suppress-hw-offload=no target-scope=30
  734. add disabled=no distance=20 dst-address=185.88.180.0/23 gateway=wireguard2 \
  735.    routing-table=main scope=40 suppress-hw-offload=no target-scope=30
  736. add disabled=no distance=1 dst-address=10.15.12.0/24 gateway=WB pref-src="" \
  737.    routing-table=main scope=30 suppress-hw-offload=no target-scope=10
  738. add disabled=no distance=3 dst-address=185.88.181.0/28 gateway=wireguard2 \
  739.    pref-src="" routing-table=main scope=40 suppress-hw-offload=no \
  740.    target-scope=30
  741. add comment="==Wildberries site route" disabled=no distance=1 dst-address=\
  742.    185.138.254.1/32 gateway=vrn.tv pref-src="" routing-table=main scope=30 \
  743.    suppress-hw-offload=no target-scope=10
  744. add comment="==Wildberries site route" disabled=no distance=1 dst-address=\
  745.    185.138.252.1/32 gateway=vrn.tv pref-src="" routing-table=main scope=30 \
  746.    suppress-hw-offload=no target-scope=10
  747. add comment="==Wildberries site route" disabled=no distance=1 dst-address=\
  748.    185.138.253.1/32 gateway=vrn.tv pref-src="" routing-table=main scope=30 \
  749.    suppress-hw-offload=no target-scope=10
  750. add disabled=no dst-address=10.10.20.0/24 gateway=WB routing-table=main \
  751.    suppress-hw-offload=no
  752. add disabled=no dst-address=10.20.0.0/14 gateway=WB routing-table=main \
  753.    suppress-hw-offload=no
  754. add disabled=no dst-address=10.36.0.0/16 gateway=WB routing-table=main \
  755.    suppress-hw-offload=no
  756. add disabled=no dst-address=10.37.0.0/16 gateway=WB routing-table=main \
  757.    suppress-hw-offload=no
  758. add disabled=no dst-address=10.168.0.0/14 gateway=WB routing-table=main \
  759.    suppress-hw-offload=no
  760. add comment=edge-chat.instagram.com disabled=no distance=20 dst-address=\
  761.    31.13.81.0/24 gateway=wireguard2 routing-table=main scope=40 \
  762.    suppress-hw-offload=no target-scope=30
  763. add disabled=no distance=1 dst-address=10.42.224.39/20 gateway=WB pref-src="" \
  764.    routing-table=main scope=30 suppress-hw-offload=no target-scope=10
  765. add comment=WB-SD disabled=no distance=1 dst-address=10.15.103.0/24 gateway=\
  766.    WB pref-src="" routing-table=main scope=30 suppress-hw-offload=no \
  767.    target-scope=10
  768. add comment=WB-SD disabled=no distance=1 dst-address=10.15.104.0/24 gateway=\
  769.    WB pref-src="" routing-table=main scope=30 suppress-hw-offload=no \
  770.    target-scope=10
  771. add disabled=no distance=20 dst-address=184.51.224.0/20 gateway=wireguard2 \
  772.    routing-table=main scope=40 suppress-hw-offload=no target-scope=30
  773. add comment=WB-SD disabled=no distance=1 dst-address=10.15.102.0/24 gateway=\
  774.    WB pref-src="" routing-table=main scope=30 suppress-hw-offload=no \
  775.    target-scope=10
  776. add comment=Inst disabled=no distance=20 dst-address=157.240.205.0/24 \
  777.    gateway=wireguard2 routing-table=main scope=40 suppress-hw-offload=no \
  778.    target-scope=30
  779. add comment=LAN->iLO-CCC disabled=no distance=1 dst-address=192.168.5.0/24 \
  780.    gateway=10.10.10.1 pref-src="" routing-table=main scope=30 \
  781.    suppress-hw-offload=no target-scope=10
  782. /ip service
  783. set telnet disabled=yes
  784. set ftp disabled=yes
  785. set www disabled=yes
  786. set ssh port=25
  787. /routing bgp connection
  788. add as=64999 disabled=yes hold-time=4m input.filter=any-list_network \
  789.    .ignore-as-path-len=yes keepalive-time=1m local.address=185.23.83.133 \
  790.    .role=ebgp multihop=yes name=antifilter.network remote.address=\
  791.    51.75.66.20/32 .as=65444 routing-table=main
  792. add as=64514 disabled=no hold-time=4m input.accept-communities="" \
  793.    .accept-ext-communities="" .accept-large-communities="" .filter=\
  794.    any-list_download .ignore-as-path-len=yes keepalive-time=1m \
  795.    local.address=192.168.254.1 .role=ebgp multihop=yes name=\
  796.    antifilter.download remote.address=45.154.73.71/32 .as=65432 \
  797.    routing-table=main
  798. /routing filter community-ext-list
  799. add communities=soo:65432:500 list=my
  800. /routing filter community-large-list
  801. add communities=65432:500:0 disabled=no list=set1
  802. /routing filter community-list
  803. add communities=65432:500 disabled=no list=test
  804. add communities=65444:700 disabled=no list=bgp_antifilter.network
  805. add communities=65432:100,65432:300,65432:500 disabled=no list=\
  806.    bgp_antifilter.download
  807. /routing filter rule
  808. add chain=discard disabled=yes rule="reject;"
  809. add chain=antifilter.network_filter disabled=no rule="set gw *0xc; accept"
  810. add chain=test disabled=no rule="if ( bgp-communities includes 65444:700) {set\
  811.    \_gw *0xc;accept;} else { reject; }"
  812. add chain=any-list_network disabled=no rule="if ( bgp-communities any-list bgp\
  813.    _antifilter.network ) {set gw *0xc; accept;}else {reject;}"
  814. add chain=any-list_download disabled=no rule="if ( bgp-communities any-list bg\
  815.    p_antifilter.download ) {set gw *0xc; accept;} else {reject;}"
  816. /snmp
  817. set enabled=yes engine-id-suffix=F34E0F2D4E20 trap-generators=interfaces \
  818.    trap-target=95.142.47.131 trap-version=2
  819. /system clock
  820. set time-zone-name=Europe/Moscow
  821. /system logging
  822. set 0 action=USBinfo
  823. add disabled=yes topics=bgp,debug
  824. add disabled=yes prefix="DNS DEBUG" topics=debug,dns,info
  825. add disabled=yes topics=ipsec,debug
  826. add action=USBinfo disabled=yes topics=dhcp,ddns
  827. /system note
  828. set show-at-login=no
  829. /system ntp client
  830. set enabled=yes
  831. /system ntp server
  832. set broadcast=yes enabled=yes manycast=yes multicast=yes
  833. /system ntp client servers
  834. add address=0.ru.pool.ntp.org
  835. /system scheduler
  836. add name=global-scripts on-event=\
  837.    "/system/script { run global-config; run global-functions; }" policy=\
  838.    ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \
  839.    start-time=startup
  840. add interval=1d name=ScriptInstallUpdate on-event=\
  841.    ":global ScriptInstallUpdate; \$ScriptInstallUpdate;" policy=\
  842.    ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \
  843.    start-time=startup
  844. add interval=1h name=check-routeros-update on-event=\
  845.    "/system/script/run check-routeros-update;" policy=\
  846.    ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \
  847.    start-date=2023-01-28 start-time=11:19:15
  848. add interval=5m name=dhcp-to-dns on-event="/system/script/run dhcp-to-dns;" \
  849.    policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \
  850.    start-date=2023-01-28 start-time=11:19:59
  851. add interval=1d name=WorkUp on-event=WB_Up policy=\
  852.    ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \
  853.    start-date=2023-03-24 start-time=09:30:00
  854. add interval=1d name=WorkDown on-event=WB_Up policy=\
  855.    ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \
  856.    start-date=2023-03-24 start-time=20:30:00
  857. add interval=30s name=dns_monitor on-event="/system/script/run dns;" policy=\
  858.    ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \
  859.    start-date=2023-07-01 start-time=14:36:04
  860. /system script
  861. add dont-require-permissions=no name=erase-antiblock-updated owner=liet \
  862.    policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \
  863.    source="{\r\
  864.    \n:for i from=1 to=700 do={\r\
  865.    \n:put \"remove \$i\"\r\
  866.    \n/ip firewall address-list remove [/ip fi address-list find where (list=a\
  867.    ntiblock-updated and address~\"^\$i\\\\..*\")]\r\
  868.    \n:delay 0.1\r\
  869.    \n}\r\
  870.    \n}"
  871. add dont-require-permissions=no name=antiblock owner=liet policy=\
  872.    read,write,policy,test source=":do {\r\
  873.    \n\r\
  874.    \n    :local retryflag true;\r\
  875.    \n    :local maxretry 3;\r\
  876.    \n    :local delay 120s;\r\
  877.    \n    :local url \"https://antifilter.network/download/ipsmart.lst\";\r\
  878.    \n    :local listname \"antiblock\";\r\
  879.    \n\r\
  880.    \n    :for retry from=1 to=\$maxretry step=1 do={\r\
  881.    \n\r\
  882.    \n        :if (retryflag) do={\r\
  883.    \n\r\
  884.    \n            :set \$retryflag false;\r\
  885.    \n            :set \$counter 0;\r\
  886.    \n\r\
  887.    \n            :if (retry > 1) do={\r\
  888.    \n                :delay \$delay;\r\
  889.    \n            };\r\
  890.    \n\r\
  891.    \n            :do {\r\
  892.    \n                /ip firewall address-list remove [find where list=(\$lis\
  893.    tname.\"-updated\")];\r\
  894.    \n            } on-error={};\r\
  895.    \n\r\
  896.    \n            :do {\r\
  897.    \n                /ip firewall address-list add list=(\$listname.\"-update\
  898.    d\") address=antifilter.download comment=\"antifilter.download\";\r\
  899.    \n            } on-error={};\r\
  900.    \n\r\
  901.    \n            :local filesize ([/tool fetch url=\$url keep-result=no as-va\
  902.    lue]->\"total\");\r\
  903.    \n            :local chunksize 64000;\r\
  904.    \n            :local start 0;\r\
  905.    \n            :local end (\$chunksize - 1);\r\
  906.    \n            :local chunks (\$filesize / (\$chunksize / 1024));\r\
  907.    \n            :local lastchunk (\$filesize % (\$chunksize / 1024));\r\
  908.    \n\r\
  909.    \n            :if (\$lastchunk > 0) do={\r\
  910.    \n                :set \$chunks (\$chunks + 1);\r\
  911.    \n            };\r\
  912.    \n\r\
  913.    \n            :for chunk from=1 to=\$chunks step=1 do={\r\
  914.    \n\r\
  915.    \n                :local comparesize ([/tool fetch url=\$url keep-result=n\
  916.    o as-value]->\"total\");\r\
  917.    \n\r\
  918.    \n                :if (\$comparesize = \$filesize) do={\r\
  919.    \n                    :set \$data ([:tool fetch url=\$url http-header-fiel\
  920.    d=\"Range: bytes=\$start-\$end\" output=user as-value]->\"data\");\r\
  921.    \n                } else={\r\
  922.    \n                    :set \$data [:toarray \"\"];\r\
  923.    \n                    :set \$retryflag true;\r\
  924.    \n                };\r\
  925.    \n\r\
  926.    \n                :local regexp \"^((25[0-5]|(2[0-4]|[01]\?[0-9]\?)[0-9])\
  927.    \\\\.){3}(25[0-5]|(2[0-4]|[01]\?[0-9]\?)[0-9])(\\\\/(3[0-2]|[0-2]\?[0-9]))\
  928.    {0,1}\\\$\";\r\
  929.    \n\r\
  930.    \n                :if (\$start > 0) do={\r\
  931.    \n                    :set \$data [:pick \$data ([:find \$data \"\\n\"]+1)\
  932.    \_[:len \$data]];\r\
  933.    \n                };\r\
  934.    \n                \r\
  935.    \n                :while ([:len \$data]!=0) do={\r\
  936.    \n                    :local line [:pick \$data 0 [:find \$data \"\\n\"]];\
  937.    \r\
  938.    \n\r\
  939.    \n                    :if ( \$line ~ \$regexp ) do={    \r\
  940.    \n                        :do {\r\
  941.    \n                            /ip firewall address-list add list=(\$listna\
  942.    me.\"-updated\") address=\$line;\r\
  943.    \n                            :set \$counter (\$counter + 1);\r\
  944.    \n                        } on-error={};        \r\
  945.    \n                    };\r\
  946.    \n\r\
  947.    \n                    :set \$data [:pick \$data ([:find \$data \"\\n\"]+1)\
  948.    \_[:len \$data]];\r\
  949.    \n\r\
  950.    \n                    :if ([:len \$data] < 256) do={\r\
  951.    \n                        :set \$data [:toarray \"\"];\r\
  952.    \n                    };\r\
  953.    \n                };\r\
  954.    \n\r\
  955.    \n                :set \$start ((\$start-512) + \$chunksize); \r\
  956.    \n                :set \$end ((\$end-512) + \$chunksize); \r\
  957.    \n            \r\
  958.    \n            };\r\
  959.    \n        \r\
  960.    \n        };\r\
  961.    \n\r\
  962.    \n    };\r\
  963.    \n\r\
  964.    \n    :if (\$counter > 0) do={\r\
  965.    \n        :do {\r\
  966.    \n            /ip firewall address-list remove [find where list=\$listname\
  967.    ];\r\
  968.    \n        } on-error={};\r\
  969.    \n\r\
  970.    \n        :do {\r\
  971.    \n            :foreach address in=[/ip firewall address-list find list=(\$\
  972.    listname.\"-updated\")] do={\r\
  973.    \n                :do {\r\
  974.    \n                    /ip firewall address-list set list=\$listname \$addr\
  975.    ess;\r\
  976.    \n                } on-error={};\r\
  977.    \n            };\r\
  978.    \n        } on-error={};\r\
  979.    \n    };\r\
  980.    \n\r\
  981.    \n} on-error={};"
  982. add dont-require-permissions=no name=erase_antiblock owner=liet policy=\
  983.    ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="{\
  984.    \r\
  985.    \n:for i from=1 to=700 do={\r\
  986.    \n:put \"remove \$i\"\r\
  987.    \n/ip firewall address-list remove [/ip fi address-list find where (list=a\
  988.    ntiblock and address~\"^\$i\\\\..*\")]\r\
  989.    \n:delay 0.1\r\
  990.    \n}\r\
  991.    \n}"
  992. add dont-require-permissions=no name=global-config owner=global-config \
  993.    policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \
  994.    source="#!rsc by RouterOS\
  995.    \n# RouterOS script: global-config\
  996.    \n# Copyright (c) 2013-2024 Christian Hesse <mail@eworm.de>\
  997.    \n# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md\
  998.    \n#\
  999.    \n# global configuration\
  1000.    \n# https://git.eworm.de/cgit/routeros-scripts/about/\
  1001.    \n\
  1002.    \n# Set this to 'true' to disable news and change notifications.\
  1003.    \n:global NoNewsAndChangesNotification false;\
  1004.    \n\
  1005.    \n# Add extra text (or emojis) in notification tags.\
  1006.    \n:global IdentityExtra \"\";\
  1007.    \n\
  1008.    \n# This is used in DNS scripts ('ipsec-to-dns' and fallback in 'dhcp-to-d\
  1009.    ns')\
  1010.    \n# and backup scripts for file names.\
  1011.    \n:global Domain \"example.com\";\
  1012.    \n\
  1013.    \n# You can send e-mail notifications. Configure the system's mail setting\
  1014.    s\
  1015.    \n# (/tool/e-mail), then install the module:\
  1016.    \n# \$ScriptInstallUpdate mod/notification-email\
  1017.    \n# The to-address needs to be filled; cc-address can be empty, one addres\
  1018.    s\
  1019.    \n# or a comma separated list of addresses.\
  1020.    \n:global EmailGeneralTo \"\";\
  1021.    \n:global EmailGeneralCc \"\";\
  1022.    \n#:global EmailGeneralTo \"mail@example.com\";\
  1023.    \n#:global EmailGeneralCc \"another@example.com,third@example.com\";\
  1024.    \n\
  1025.    \n# You can send Telegram notifications. Register a bot\
  1026.    \n# and add the token and chat ids here, then install the module:\
  1027.    \n# \$ScriptInstallUpdate mod/notification-telegram\
  1028.    \n:global TelegramTokenId \"\";\
  1029.    \n:global TelegramChatId \"\";\
  1030.    \n#:global TelegramTokenId \"123456:ABCDEF-GHI\";\
  1031.    \n#:global TelegramChatId \"12345678\";\
  1032.    \n# Using telegram-chat you have to define trusted chat ids (not group ids\
  1033.    !)\
  1034.    \n# or user names. Groups allow to chat with devices simultaneously.\
  1035.    \n#:global TelegramChatIdsTrusted {\
  1036.    \n#  \"12345678\";\
  1037.    \n#  \"example_user\";\
  1038.    \n#};\
  1039.    \n:global TelegramChatGroups \"(all)\";\
  1040.    \n#:global TelegramChatGroups \"(all|home|office)\";\
  1041.    \n\
  1042.    \n# You can send Matrix notifications. Configure these settings and\
  1043.    \n# install the module:\
  1044.    \n# \$ScriptInstallUpdate mod/notification-matrix\
  1045.    \n:global MatrixHomeServer \"\";\
  1046.    \n:global MatrixAccessToken \"\";\
  1047.    \n:global MatrixRoom \"\";\
  1048.    \n#:global MatrixHomeServer \"matrix.org\";\
  1049.    \n#:global MatrixAccessToken \"123456ABCDEFGHI...\";\
  1050.    \n#:global MatrixRoom \"!example:matrix.org\";\
  1051.    \n\
  1052.    \n# You can send Ntfy notifications. Configure these settings and\
  1053.    \n# install the module:\
  1054.    \n# \$ScriptInstallUpdate mod/notification-ntfy\
  1055.    \n:global NtfyServer \"ntfy.sh\";\
  1056.    \n:global NtfyTopic \"\";\
  1057.    \n\
  1058.    \n# It is possible to override e-mail, Telegram, Matrix and Ntfy setting\
  1059.    \n# for every script. This is done in arrays, where 'Override' is appended\
  1060.    \n# to the variable name, like this:\
  1061.    \n#:global EmailGeneralToOverride {\
  1062.    \n#  \"check-certificates\"=\"override@example.com\";\
  1063.    \n#  \"backup-email\"=\"backup@example.com\";\
  1064.    \n#}\
  1065.    \n\
  1066.    \n# Toggle this to disable symbols in notifications.\
  1067.    \n:global NotificationsWithSymbols true;\
  1068.    \n# Toggle this to disable color output in terminal/cli.\
  1069.    \n:global TerminalColorOutput true;\
  1070.    \n\
  1071.    \n# This defines what backups to generate and what password to use.\
  1072.    \n:global BackupSendBinary false;\
  1073.    \n:global BackupSendExport true;\
  1074.    \n:global BackupSendGlobalConfig true;\
  1075.    \n:global BackupPassword \"v3ry-s3cr3t\";\
  1076.    \n:global BackupRandomDelay 0;\
  1077.    \n# These credentials are used to upload backup and config export files.\
  1078.    \n# SFTP authentication is tricky, you may have to limit authentication\
  1079.    \n# methods for your SSH server.\
  1080.    \n:global BackupUploadUrl \"sftp://example.com/backup/\";\
  1081.    \n:global BackupUploadUser \"mikrotik\";\
  1082.    \n:global BackupUploadPass \"v3ry-s3cr3t\";\
  1083.    \n\
  1084.    \n# This defines the settings for firewall address-lists (fw-addr-lists).\
  1085.    \n:global FwAddrLists {\
  1086.    \n#  \"allow\"={\
  1087.    \n#    { url=\"https://eworm.de/ros/fw-addr-lists/allow\";\
  1088.    \n#      cert=\"E1\"; timeout=1w };\
  1089.    \n#  };\
  1090.    \n  \"block\"={\
  1091.    \n#    { url=\"https://eworm.de/ros/fw-addr-lists/block\";\
  1092.    \n#      cert=\"E1\" };\
  1093.    \n    { url=\"https://feodotracker.abuse.ch/downloads/ipblocklist_recommen\
  1094.    ded.txt\";\
  1095.    \n      cert=\"GlobalSign Atlas R3 DV TLS CA 2022 Q3\" };\
  1096.    \n    { url=\"https://sslbl.abuse.ch/blacklist/sslipblacklist.txt\";\
  1097.    \n      cert=\"GlobalSign Atlas R3 DV TLS CA 2022 Q3\" };\
  1098.    \n    { url=\"https://www.dshield.org/block.txt\"; cidr=\"/24\";\
  1099.    \n      cert=\"R3\" };\
  1100.    \n#    { url=\"https://www.spamhaus.org/drop/drop.txt\";\
  1101.    \n#      cert=\"Cloudflare Inc ECC CA-3\" };\
  1102.    \n#    { url=\"https://www.spamhaus.org/drop/edrop.txt\";\
  1103.    \n#      cert=\"Cloudflare Inc ECC CA-3\" };\
  1104.    \n  };\
  1105.    \n};\
  1106.    \n:global FwAddrListTimeOut 1d;\
  1107.    \n\
  1108.    \n# This defines what log messages to filter or include by topic or messag\
  1109.    e\
  1110.    \n# text. Regular expressions are supported. Do *NOT* set an empty string,\
  1111.    \n# that will filter or include everything!\
  1112.    \n# These are filters, so excluding messages from forwarding.\
  1113.    \n:global LogForwardFilter \"(debug|info|packet|raw)\";\
  1114.    \n:global LogForwardFilterMessage [];\
  1115.    \n#:global LogForwardFilterMessage \"message text\";\
  1116.    \n#:global LogForwardFilterMessage \"(message text|another text|...)\";\
  1117.    \n# ... and another setting with reverse logic. This includes messages eve\
  1118.    n\
  1119.    \n# if filtered above.\
  1120.    \n:global LogForwardInclude [];\
  1121.    \n:global LogForwardIncludeMessage [];\
  1122.    \n#:global LogForwardInclude \"account\";\
  1123.    \n#:global LogForwardIncludeMessage \"message text\";\
  1124.    \n\
  1125.    \n# Specify an address to enable auto update to version assumed safe.\
  1126.    \n# The configured channel (bugfix, current, release-candidate) is appende\
  1127.    d.\
  1128.    \n:global SafeUpdateUrl \"\";\
  1129.    \n#:global SafeUpdateUrl \"https://example.com/ros/safe-update/\";\
  1130.    \n# Allow to install patch updates automatically.\
  1131.    \n:global SafeUpdatePatch false;\
  1132.    \n# Allow to install updates automatically if seen in neighbor list.\
  1133.    \n:global SafeUpdateNeighbor false;\
  1134.    \n:global SafeUpdateNeighborIdentity \"\";\
  1135.    \n# Install *ALL* updates automatically!\
  1136.    \n# Set to all upper-case \"Yes, please!\" to enable.\
  1137.    \n:global SafeUpdateAll \"no\";\
  1138.    \n\
  1139.    \n# These thresholds control when to send health notification\
  1140.    \n# on temperature and voltage.\
  1141.    \n:global CheckHealthTemperature {\
  1142.    \n  temperature=50;\
  1143.    \n  cpu-temperature=70;\
  1144.    \n  board-temperature1=50;\
  1145.    \n  board-temperature2=50;\
  1146.    \n};\
  1147.    \n# This is deviation on recovery threshold against notification flooding.\
  1148.    \n:global CheckHealthTemperatureDeviation 3;\
  1149.    \n:global CheckHealthVoltageLow 115;\
  1150.    \n:global CheckHealthVoltagePercent 10;\
  1151.    \n\
  1152.    \n# Access-list entries matching this comment are updated\
  1153.    \n# with daily pseudo-random PSK.\
  1154.    \n:global DailyPskMatchComment \"Daily PSK\";\
  1155.    \n:global DailyPskQrCodeUrl \"https://www.eworm.de/cgi-bin/cqrlogo-wifi.cg\
  1156.    i\";\
  1157.    \n:global DailyPskSecrets {\
  1158.    \n  { \"Abusive\"; \"Aggressive\"; \"Bored\"; \"Chemical\"; \"Cold\";\
  1159.    \n    \"Cruel\"; \"Curved\"; \"Delightful\"; \"Discreet\"; \"Elite\";\
  1160.    \n    \"Evasive\"; \"Faded\"; \"Flat\"; \"Future\"; \"Grandiose\";\
  1161.    \n    \"Hanging\"; \"Humorous\"; \"Interesting\"; \"Magenta\";\
  1162.    \n    \"Magnificent\"; \"Numerous\"; \"Optimal\"; \"Pathetic\";\
  1163.    \n    \"Possessive\"; \"Remarkable\"; \"Rightful\"; \"Ruthless\";\
  1164.    \n    \"Stale\"; \"Unusual\"; \"Useless\"; \"Various\" };\
  1165.    \n  { \"Adhesive\"; \"Amusing\"; \"Astonishing\"; \"Frantic\";\
  1166.    \n    \"Kindhearted\"; \"Limping\"; \"Roasted\"; \"Robust\";\
  1167.    \n    \"Staking\"; \"Thundering\"; \"Ultra\"; \"Unreal\" };\
  1168.    \n  { \"Belief\"; \"Button\"; \"Curtain\"; \"Edge\"; \"Jewel\";\
  1169.    \n    \"String\"; \"Whistle\" }\
  1170.    \n};\
  1171.    \n\
  1172.    \n# Specify how to assemble DNS names in ipsec-to-dns.\
  1173.    \n:global HostNameInZone true;\
  1174.    \n:global PrefixInZone true;\
  1175.    \n\
  1176.    \n# Run different commands with multiple mode-button presses.\
  1177.    \n:global ModeButton {\
  1178.    \n  1=\"/system/script/run leds-toggle-mode;\";\
  1179.    \n  2=\":global Identity; :global SendNotification; :global SymbolForNotif\
  1180.    ication; \\\$SendNotification ([ \\\$SymbolForNotification \\\"earth\\\" ]\
  1181.    \_. \\\"Hello...\\\") (\\\"Hello world, \\\" . \\\$Identity . \\\" calling\
  1182.    !\\\");\";\
  1183.    \n  3=\"/system/shutdown;\";\
  1184.    \n  4=\"/system/reboot;\";\
  1185.    \n  5=\":global BridgePortVlan; \\\$BridgePortVlan alt;\";\
  1186.    \n# add more here...\
  1187.    \n};\
  1188.    \n# This led gives visual feedback if type is 'on' or 'off'.\
  1189.    \n:global ModeButtonLED \"user-led\";\
  1190.    \n\
  1191.    \n# Run commands on SMS action.\
  1192.    \n:global SmsAction {\
  1193.    \n  bridge-port-vlan-alt=\":global BridgePortVlan; \\\$BridgePortVlan alt;\
  1194.    \";\
  1195.    \n  reboot=\"/system/reboot;\";\
  1196.    \n  shutdown=\"/system/shutdown;\";\
  1197.    \n# add more here...\
  1198.    \n};\
  1199.    \n\
  1200.    \n# Run commands by hooking into SMS forward.\
  1201.    \n:global SmsForwardHooks {\
  1202.    \n  { match=\"magic string\";\
  1203.    \n    allowed-number=\"12345678\";\
  1204.    \n    command=\"/system/script/run ...\" };\
  1205.    \n# add more here...\
  1206.    \n};\
  1207.    \n\
  1208.    \n# This is the address used to send gps data to.\
  1209.    \n:global GpsTrackUrl \"https://example.com/index.php\";\
  1210.    \n\
  1211.    \n# This is the base url to fetch scripts from.\
  1212.    \n:global ScriptUpdatesBaseUrl \"https://git.eworm.de/cgit/routeros-script\
  1213.    s/plain/\";\
  1214.    \n# alternative urls - main: stable code - next: currently in development\
  1215.    \n#:global ScriptUpdatesBaseUrl \"https://raw.githubusercontent.com/eworm-\
  1216.    de/routeros-scripts/main/\";\
  1217.    \n#:global ScriptUpdatesBaseUrl \"https://raw.githubusercontent.com/eworm-\
  1218.    de/routeros-scripts/next/\";\
  1219.    \n#:global ScriptUpdatesBaseUrl \"https://gitlab.com/eworm-de/routeros-scr\
  1220.    ipts/raw/main/\";\
  1221.    \n#:global ScriptUpdatesBaseUrl \"https://gitlab.com/eworm-de/routeros-scr\
  1222.    ipts/raw/next/\";\
  1223.    \n:global ScriptUpdatesUrlSuffix \"\";\
  1224.    \n# use next branch with default url (git.eworm.de)\
  1225.    \n#:global ScriptUpdatesUrlSuffix \"\?h=next\";\
  1226.    \n\
  1227.    \n# Use this for defaults with \$ScriptRunOnce\
  1228.    \n# Install module with:\
  1229.    \n# \$ScriptInstallUpdate mod/scriptrunonce\
  1230.    \n:global ScriptRunOnceBaseUrl \"\";\
  1231.    \n:global ScriptRunOnceUrlSuffix \"\";\
  1232.    \n\
  1233.    \n# This project is developed in private spare time and usage is free of c\
  1234.    harge\
  1235.    \n# for you. If you like the scripts and think this is of value for you or\
  1236.    \_your\
  1237.    \n# business please consider a donation:\
  1238.    \n# https://git.eworm.de/cgit/routeros-scripts/about/#donate\
  1239.    \n# Enable this to silence donation hint.\
  1240.    \n:global IDonate false;\
  1241.    \n\
  1242.    \n# Use this for certificate auto-renew\
  1243.    \n:global CertRenewUrl \"\";\
  1244.    \n#:global CertRenewUrl \"https://example.com/certificates/\";\
  1245.    \n:global CertRenewTime 3w;\
  1246.    \n:global CertRenewPass {\
  1247.    \n  \"v3ry-s3cr3t\";\
  1248.    \n  \"4n0th3r-s3cr3t\";\
  1249.    \n};\
  1250.    \n:global CertWarnTime 2w;\
  1251.    \n:global CertIssuedExportPass {\
  1252.    \n  \"cert1-cn\"=\"v3ry-s3cr3t\";\
  1253.    \n  \"cert2-cn\"=\"4n0th3r-s3cr3t\";\
  1254.    \n};\
  1255.    \n\
  1256.    \n# load custom settings from overlay\
  1257.    \n# Warning: Do *NOT* copy this code to overlay!\
  1258.    \n:do {\
  1259.    \n  /system/script/run global-config-overlay;\
  1260.    \n} on-error={\
  1261.    \n  :log error (\"Loading configuration from overlay failed!\");\
  1262.    \n}\
  1263.    \n"
  1264. add dont-require-permissions=no name=global-config-overlay owner=liet-phone \
  1265.    policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \
  1266.    source="# Overlay for global configuration by RouterOS Scripts\
  1267.    \n# Copyright (c) 2013-2023 Christian Hesse <mail@eworm.de>\
  1268.    \n# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md\
  1269.    \n#\
  1270.    \n# global configuration, custom overlay\
  1271.    \n# https://git.eworm.de/cgit/routeros-scripts/about/\
  1272.    \n\
  1273.    \n# Copy relevant configuration from global-config, paste and modify it he\
  1274.    re.\
  1275.    \n:global Domain \"dune.local\";\
  1276.    \n:global HostNameInZone true;\
  1277.    \n:global PrefixInZone false;\
  1278.    \n:global ServerNameInZone false;\
  1279.    \n\
  1280.    \n\
  1281.    \n# End of global-config-overlay\
  1282.    \n"
  1283. add dont-require-permissions=no name=global-functions owner=global-functions \
  1284.    policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \
  1285.    source="#!rsc by RouterOS\
  1286.    \n# RouterOS script: global-functions\
  1287.    \n# Copyright (c) 2013-2024 Christian Hesse <mail@eworm.de>\
  1288.    \n#                         Michael Gisbers <michael@gisbers.de>\
  1289.    \n# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md\
  1290.    \n#\
  1291.    \n# requires RouterOS, version=7.10beta5\
  1292.    \n#\
  1293.    \n# global functions\
  1294.    \n# https://git.eworm.de/cgit/routeros-scripts/about/\
  1295.    \n\
  1296.    \n:local 0 \"global-functions\";\
  1297.    \n\
  1298.    \n# expected configuration version\
  1299.    \n:global ExpectedConfigVersion 116;\
  1300.    \n\
  1301.    \n# global variables not to be changed by user\
  1302.    \n:global GlobalFunctionsReady false;\
  1303.    \n:global FetchUserAgent (\"User-Agent: Mikrotik/\" . [ /system/resource/g\
  1304.    et version ] . \" Fetch\");\
  1305.    \n:global Identity [ /system/identity/get name ];\
  1306.    \n\
  1307.    \n# global functions\
  1308.    \n:global AlignRight;\
  1309.    \n:global CertificateAvailable;\
  1310.    \n:global CertificateDownload;\
  1311.    \n:global CertificateNameByCN;\
  1312.    \n:global CharacterMultiply;\
  1313.    \n:global CharacterReplace;\
  1314.    \n:global CleanFilePath;\
  1315.    \n:global DeviceInfo;\
  1316.    \n:global Dos2Unix;\
  1317.    \n:global DownloadPackage;\
  1318.    \n:global EitherOr;\
  1319.    \n:global EscapeForRegEx;\
  1320.    \n:global FormatLine;\
  1321.    \n:global FormatMultiLines;\
  1322.    \n:global GetMacVendor;\
  1323.    \n:global GetRandom20CharAlNum;\
  1324.    \n:global GetRandom20CharHex;\
  1325.    \n:global GetRandomNumber;\
  1326.    \n:global Grep;\
  1327.    \n:global HexToNum;\
  1328.    \n:global HumanReadableNum;\
  1329.    \n:global IfThenElse;\
  1330.    \n:global IsDefaultRouteReachable;\
  1331.    \n:global IsDNSResolving;\
  1332.    \n:global IsFullyConnected;\
  1333.    \n:global IsMacLocallyAdministered;\
  1334.    \n:global IsTimeSync;\
  1335.    \n:global LogPrintExit2;\
  1336.    \n:global LogPrintOnce;\
  1337.    \n:global MAX;\
  1338.    \n:global MIN;\
  1339.    \n:global MkDir;\
  1340.    \n:global NotificationFunctions;\
  1341.    \n:global ParseDate;\
  1342.    \n:global ParseJson;\
  1343.    \n:global ParseKeyValueStore;\
  1344.    \n:global PrettyPrint;\
  1345.    \n:global RandomDelay;\
  1346.    \n:global RequiredRouterOS;\
  1347.    \n:global ScriptFromTerminal;\
  1348.    \n:global ScriptInstallUpdate;\
  1349.    \n:global ScriptLock;\
  1350.    \n:global SendNotification;\
  1351.    \n:global SendNotification2;\
  1352.    \n:global SymbolByUnicodeName;\
  1353.    \n:global SymbolForNotification;\
  1354.    \n:global Unix2Dos;\
  1355.    \n:global UrlEncode;\
  1356.    \n:global ValidateSyntax;\
  1357.    \n:global VersionToNum;\
  1358.    \n:global WaitDefaultRouteReachable;\
  1359.    \n:global WaitDNSResolving;\
  1360.    \n:global WaitForFile;\
  1361.    \n:global WaitFullyConnected;\
  1362.    \n:global WaitTimeSync;\
  1363.    \n\
  1364.    \n# align string to the right\
  1365.    \n:global AlignRight do={\
  1366.    \n  :local Input [ :tostr \$1 ];\
  1367.    \n  :local Len   [ :tonum \$2 ];\
  1368.    \n\
  1369.    \n  :global CharacterMultiply;\
  1370.    \n  :global EitherOr;\
  1371.    \n\
  1372.    \n  :set Len [ \$EitherOr \$Len 8 ];\
  1373.    \n  :local Spaces [ \$CharacterMultiply \" \" \$Len ];\
  1374.    \n\
  1375.    \n  :return ([ :pick \$Spaces 0 (\$Len - [ :len \$Input ]) ] . \$Input);\
  1376.    \n}\
  1377.    \n\
  1378.    \n# check and download required certificate\
  1379.    \n:set CertificateAvailable do={\
  1380.    \n  :local CommonName [ :tostr \$1 ];\
  1381.    \n\
  1382.    \n  :global CertificateDownload;\
  1383.    \n  :global LogPrintExit2;\
  1384.    \n  :global ParseKeyValueStore;\
  1385.    \n\
  1386.    \n  :if ([ /system/resource/get free-hdd-space ] < 8388608 && \\\
  1387.    \n       [ /certificate/settings/get crl-download ] = true && \\\
  1388.    \n       [ /certificate/settings/get crl-store ] = \"system\") do={\
  1389.    \n    \$LogPrintExit2 warning \$0 (\"This system has low free flash space \
  1390.    but \" . \\\
  1391.    \n      \"is configured to download certificate CRLs to system!\") false;\
  1392.    \n  }\
  1393.    \n\
  1394.    \n  :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] = 0\
  1395.    ) do={\
  1396.    \n    \$LogPrintExit2 info \$0 (\"Certificate with CommonName \\\"\" . \$C\
  1397.    ommonName . \"\\\" not available.\") false;\
  1398.    \n    :if ([ \$CertificateDownload \$CommonName ] = false) do={\
  1399.    \n      :return false;\
  1400.    \n    }\
  1401.    \n  }\
  1402.    \n\
  1403.    \n  :local CertVal [ /certificate/get [ find where common-name=\$CommonNam\
  1404.    e ] ];\
  1405.    \n  :while ((\$CertVal->\"akid\") != \"\" && (\$CertVal->\"akid\") != (\$C\
  1406.    ertVal->\"skid\")) do={\
  1407.    \n    :if ([ :len [ /certificate/find where skid=(\$CertVal->\"akid\") ] ]\
  1408.    \_= 0) do={\
  1409.    \n      \$LogPrintExit2 info \$0 (\"Certificate chain for \\\"\" . \$Commo\
  1410.    nName . \\\
  1411.    \n        \"\\\" is incomplete, missing \\\"\" . ([ \$ParseKeyValueStore (\
  1412.    \$CertVal->\"issuer\") ]->\"CN\") . \"\\\".\") false;\
  1413.    \n      :if ([ \$CertificateDownload \$CommonName ] = false) do={\
  1414.    \n        :return false;\
  1415.    \n      }\
  1416.    \n    }\
  1417.    \n    :set CertVal [ /certificate/get [ find where skid=(\$CertVal->\"akid\
  1418.    \") ] ];\
  1419.    \n  }\
  1420.    \n  :return true;\
  1421.    \n}\
  1422.    \n\
  1423.    \n# download and import certificate\
  1424.    \n:set CertificateDownload do={\
  1425.    \n  :local CommonName [ :tostr \$1 ];\
  1426.    \n\
  1427.    \n  :global FetchUserAgent;\
  1428.    \n  :global ScriptUpdatesBaseUrl;\
  1429.    \n  :global ScriptUpdatesUrlSuffix;\
  1430.    \n\
  1431.    \n  :global CertificateNameByCN;\
  1432.    \n  :global LogPrintExit2;\
  1433.    \n  :global UrlEncode;\
  1434.    \n  :global WaitForFile;\
  1435.    \n\
  1436.    \n  \$LogPrintExit2 info \$0 (\"Downloading and importing certificate with\
  1437.    \_\" . \\\
  1438.    \n      \"CommonName \\\"\" . \$CommonName . \"\\\".\") false;\
  1439.    \n  :do {\
  1440.    \n    :local LocalFileName (\$CommonName . \".pem\");\
  1441.    \n    :local UrlFileName ([ \$UrlEncode \$CommonName ] . \".pem\");\
  1442.    \n    /tool/fetch check-certificate=yes-without-crl http-header-field=({ \
  1443.    \$FetchUserAgent }) \\\
  1444.    \n      (\$ScriptUpdatesBaseUrl . \"certs/\" . \$UrlFileName . \$ScriptUpd\
  1445.    atesUrlSuffix) \\\
  1446.    \n      dst-path=\$LocalFileName as-value;\
  1447.    \n    \$WaitForFile \$LocalFileName;\
  1448.    \n    /certificate/import file-name=\$LocalFileName passphrase=\"\" as-val\
  1449.    ue;\
  1450.    \n    :delay 1s;\
  1451.    \n    /file/remove \$LocalFileName;\
  1452.    \n\
  1453.    \n    :foreach Cert in=[ /certificate/find where name~(\"^\" . \$LocalFile\
  1454.    Name . \"_[0-9]+\\\$\") ] do={\
  1455.    \n      \$CertificateNameByCN [ /certificate/get \$Cert common-name ];\
  1456.    \n    }\
  1457.    \n  } on-error={\
  1458.    \n    \$LogPrintExit2 warning \$0 (\"Failed importing certificate with \" \
  1459.    . \\\
  1460.    \n        \"CommonName \\\"\" . \$CommonName . \"\\\"!\") false;\
  1461.    \n    :return false;\
  1462.    \n  }\
  1463.    \n  :return true;\
  1464.    \n}\
  1465.    \n\
  1466.    \n# name a certificate by its common-name\
  1467.    \n:set CertificateNameByCN do={\
  1468.    \n  :local CommonName [ :tostr \$1 ];\
  1469.    \n\
  1470.    \n  :global CharacterReplace;\
  1471.    \n\
  1472.    \n  :local Cert [ /certificate/find where common-name=\$CommonName ];\
  1473.    \n  /certificate/set \$Cert \\\
  1474.    \n    name=[ \$CharacterReplace [ \$CharacterReplace [ \$CharacterReplace \
  1475.    \$CommonName \"'\" \"-\" ] \" \" \"-\" ] \"---\" \"-\" ];\
  1476.    \n}\
  1477.    \n\
  1478.    \n# multiply given character(s)\
  1479.    \n:set CharacterMultiply do={\
  1480.    \n  :local Return \"\";\
  1481.    \n  :for I from=1 to=\$2 do={\
  1482.    \n    :set Return (\$Return . \$1);\
  1483.    \n  }\
  1484.    \n  :return \$Return;\
  1485.    \n}\
  1486.    \n\
  1487.    \n# character replace\
  1488.    \n:set CharacterReplace do={\
  1489.    \n  :local String [ :tostr \$1 ];\
  1490.    \n  :local ReplaceFrom [ :tostr \$2 ];\
  1491.    \n  :local ReplaceWith [ :tostr \$3 ];\
  1492.    \n  :local Return \"\";\
  1493.    \n\
  1494.    \n  :if (\$ReplaceFrom = \"\") do={\
  1495.    \n    :return \$String;\
  1496.    \n  }\
  1497.    \n\
  1498.    \n  :while ([ :typeof [ :find \$String \$ReplaceFrom ] ] != \"nil\") do={\
  1499.    \n    :local Pos [ :find \$String \$ReplaceFrom ];\
  1500.    \n    :set Return (\$Return . [ :pick \$String 0 \$Pos ] . \$ReplaceWith);\
  1501.    \n    :set String [ :pick \$String (\$Pos + [ :len \$ReplaceFrom ]) [ :len\
  1502.    \_\$String ] ];\
  1503.    \n  }\
  1504.    \n\
  1505.    \n  :return (\$Return . \$String);\
  1506.    \n}\
  1507.    \n\
  1508.    \n# clean file path\
  1509.    \n:set CleanFilePath do={\
  1510.    \n  :local Path [ :tostr \$1 ];\
  1511.    \n\
  1512.    \n  :global CharacterReplace;\
  1513.    \n\
  1514.    \n  :while (\$Path ~ \"//\") do={\
  1515.    \n    :set \$Path [ \$CharacterReplace \$Path \"//\" \"/\" ];\
  1516.    \n  }\
  1517.    \n  :if ([ :pick \$Path 0 ] = \"/\") do={\
  1518.    \n    :set Path [ :pick \$Path 1 [ :len \$Path ] ];\
  1519.    \n  }\
  1520.    \n  :if ([ :pick \$Path ([ :len \$Path ] - 1) ] = \"/\") do={\
  1521.    \n    :set Path [ :pick \$Path 0 ([ :len \$Path ] - 1) ];\
  1522.    \n  }\
  1523.    \n\
  1524.    \n  :return \$Path;\
  1525.    \n}\
  1526.    \n\
  1527.    \n# get readable device info\
  1528.    \n:set DeviceInfo do={\
  1529.    \n  :global ExpectedConfigVersion;\
  1530.    \n  :global Identity;\
  1531.    \n\
  1532.    \n  :global IfThenElse;\
  1533.    \n  :global FormatLine;\
  1534.    \n\
  1535.    \n  :local License [ /system/license/get ];\
  1536.    \n  :local Resource [ /system/resource/get ];\
  1537.    \n  :local RouterBoard;\
  1538.    \n  :do {\
  1539.    \n    :set RouterBoard [[ :parse \"/system/routerboard/get\" ]];\
  1540.    \n  } on-error={ }\
  1541.    \n  :local Snmp [ /snmp/get ];\
  1542.    \n  :local Update [ /system/package/update/get ];\
  1543.    \n\
  1544.    \n  :return ( \\\
  1545.    \n    [ \$FormatLine \"Hostname\" \$Identity ] . \"\\n\" . \\\
  1546.    \n    [ \$IfThenElse ([ :len (\$Snmp->\"location\") ] > 0) \\\
  1547.    \n      ([ \$FormatLine \"Location\" (\$Snmp->\"location\") ] . \"\\n\") ]\
  1548.    \_. \\\
  1549.    \n    [ \$IfThenElse ([ :len (\$Snmp->\"contact\") ] > 0) \\\
  1550.    \n      ([ \$FormatLine \"Contact\" (\$Snmp->\"contact\") ] . \"\\n\") ] .\
  1551.    \_\\\
  1552.    \n    [ \$FormatLine \"Board name\" (\$Resource->\"board-name\") ] . \"\\n\
  1553.    \" . \\\
  1554.    \n    [ \$FormatLine \"Architecture\" (\$Resource->\"architecture-name\") \
  1555.    ] . \"\\n\" . \\\
  1556.    \n    [ \$IfThenElse (\$RouterBoard->\"routerboard\" = true) \\\
  1557.    \n      ([ \$FormatLine \"Model\" (\$RouterBoard->\"model\") ] . \\\
  1558.    \n       [ \$IfThenElse ([ :len (\$RouterBoard->\"revision\") ] > 0) \\\
  1559.    \n           (\" \" . \$RouterBoard->\"revision\") ] . \"\\n\" . \\\
  1560.    \n       [ \$FormatLine \"Serial number\" (\$RouterBoard->\"serial-number\
  1561.    \") ] . \"\\n\") ] . \\\
  1562.    \n    [ \$IfThenElse ([ :len (\$License->\"level\") ] > 0) \\\
  1563.    \n      ([ \$FormatLine \"License\" (\$License->\"level\") ] . \"\\n\") ] \
  1564.    . \\\
  1565.    \n    \"RouterOS:\\n\" . \\\
  1566.    \n    [ \$FormatLine \"    Channel\" (\$Update->\"channel\") ] . \"\\n\" .\
  1567.    \_\\\
  1568.    \n    [ \$FormatLine \"    Installed\" (\$Update->\"installed-version\") ]\
  1569.    \_. \"\\n\" . \\\
  1570.    \n    [ \$IfThenElse ([ :typeof (\$Update->\"latest-version\") ] != \"noth\
  1571.    ing\" && \\\
  1572.    \n        \$Update->\"installed-version\" != \$Update->\"latest-version\")\
  1573.    \_\\\
  1574.    \n      ([ \$FormatLine \"    Available\" (\$Update->\"latest-version\") ]\
  1575.    \_. \"\\n\") ] . \\\
  1576.    \n    [ \$IfThenElse (\$RouterBoard->\"routerboard\" = true && \\\
  1577.    \n        \$RouterBoard->\"current-firmware\" != \$RouterBoard->\"upgrade-\
  1578.    firmware\") \\\
  1579.    \n      ([ \$FormatLine \"    Firmware\" (\$RouterBoard->\"current-firmwar\
  1580.    e\") ] . \"\\n\") ] . \\\
  1581.    \n    \"RouterOS-Scripts:\\n\" . \\\
  1582.    \n    [ \$FormatLine \"    Version\" \$ExpectedConfigVersion ]);\
  1583.    \n}\
  1584.    \n\
  1585.    \n# convert line endings, DOS -> UNIX\
  1586.    \n:set Dos2Unix do={\
  1587.    \n  :local Input [ :tostr \$1 ];\
  1588.    \n\
  1589.    \n  :global CharacterReplace;\
  1590.    \n\
  1591.    \n  :return [ \$CharacterReplace \$Input (\"\\r\\n\") (\"\\n\") ];\
  1592.    \n}\
  1593.    \n\
  1594.    \n# download package from upgrade server\
  1595.    \n:set DownloadPackage do={\
  1596.    \n  :local PkgName [ :tostr \$1 ];\
  1597.    \n  :local PkgVer  [ :tostr \$2 ];\
  1598.    \n  :local PkgArch [ :tostr \$3 ];\
  1599.    \n  :local PkgDir  [ :tostr \$4 ];\
  1600.    \n\
  1601.    \n  :global CertificateAvailable;\
  1602.    \n  :global CleanFilePath;\
  1603.    \n  :global LogPrintExit2;\
  1604.    \n  :global MkDir;\
  1605.    \n  :global WaitForFile;\
  1606.    \n\
  1607.    \n  :if ([ :len \$PkgName ] = 0) do={ :return false; }\
  1608.    \n  :if ([ :len \$PkgVer  ] = 0) do={ :set PkgVer  [ /system/package/updat\
  1609.    e/get installed-version ]; }\
  1610.    \n  :if ([ :len \$PkgArch ] = 0) do={ :set PkgArch [ /system/resource/get \
  1611.    architecture-name ]; }\
  1612.    \n\
  1613.    \n  :if (\$PkgName = \"system\") do={ :set PkgName \"routeros\"; }\
  1614.    \n\
  1615.    \n  :local PkgFile (\$PkgName . \"-\" . \$PkgVer . \"-\" . \$PkgArch . \".\
  1616.    npk\");\
  1617.    \n  :if (\$PkgArch = \"x86_64\") do={ :set PkgFile (\$PkgName . \"-\" . \$\
  1618.    PkgVer . \".npk\"); }\
  1619.    \n  :local PkgDest [ \$CleanFilePath (\$PkgDir . \"/\" . \$PkgFile) ];\
  1620.    \n\
  1621.    \n  :if ([ \$MkDir \$PkgDir ] = false) do={\
  1622.    \n    \$LogPrintExit2 warning \$0 (\"Failed creating directory, not downlo\
  1623.    ading package.\") false;\
  1624.    \n    :return false;\
  1625.    \n  }\
  1626.    \n\
  1627.    \n  :if ([ :len [ /file/find where name=\$PkgDest type=\"package\" ] ] > 0\
  1628.    ) do={\
  1629.    \n    \$LogPrintExit2 info \$0 (\"Package file \" . \$PkgName . \" already\
  1630.    \_exists.\") false;\
  1631.    \n    :return true;\
  1632.    \n  }\
  1633.    \n\
  1634.    \n  :if ([ \$CertificateAvailable \"R3\" ] = false) do={\
  1635.    \n    \$LogPrintExit2 error \$0 (\"Downloading required certificate failed\
  1636.    .\") true;\
  1637.    \n  }\
  1638.    \n\
  1639.    \n  :local Url (\"https://upgrade.mikrotik.com/routeros/\" . \$PkgVer . \"\
  1640.    /\" . \$PkgFile);\
  1641.    \n  \$LogPrintExit2 info \$0 (\"Downloading package file '\" . \$PkgName .\
  1642.    \_\"'...\") false;\
  1643.    \n  \$LogPrintExit2 debug \$0 (\"... from url: \" . \$Url) false;\
  1644.    \n  :local Retry 3;\
  1645.    \n  :while (\$Retry > 0) do={\
  1646.    \n    :do {\
  1647.    \n      /tool/fetch check-certificate=yes-without-crl \$Url dst-path=\$Pkg\
  1648.    Dest;\
  1649.    \n      \$WaitForFile \$PkgDest;\
  1650.    \n\
  1651.    \n      :if ([ /file/get [ find where name=\$PkgDest ] type ] = \"package\
  1652.    \") do={\
  1653.    \n        :return true;\
  1654.    \n      }\
  1655.    \n    } on-error={\
  1656.    \n      \$LogPrintExit2 debug \$0 (\"Downloading package file failed.\") f\
  1657.    alse;\
  1658.    \n    }\
  1659.    \n\
  1660.    \n    /file/remove [ find where name=\$PkgDest ];\
  1661.    \n    :set Retry (\$Retry - 1);\
  1662.    \n  }\
  1663.    \n\
  1664.    \n  \$LogPrintExit2 warning \$0 (\"Downloading package file '\" . \$PkgNam\
  1665.    e . \"' failed.\") false;\
  1666.    \n  :return false;\
  1667.    \n}\
  1668.    \n\
  1669.    \n# return either first (if \"true\") or second\
  1670.    \n:set EitherOr do={\
  1671.    \n  :global IfThenElse;\
  1672.    \n\
  1673.    \n  :if ([ :typeof \$1 ] = \"num\") do={\
  1674.    \n    :return [ \$IfThenElse (\$1 != 0) \$1 \$2 ];\
  1675.    \n  }\
  1676.    \n  :if ([ :typeof \$1 ] = \"time\") do={\
  1677.    \n    :return [ \$IfThenElse (\$1 > 0s) \$1 \$2 ];\
  1678.    \n  }\
  1679.    \n  :return [ \$IfThenElse ([ :len [ :tostr \$1 ] ] > 0) \$1 \$2 ];\
  1680.    \n}\
  1681.    \n\
  1682.    \n# escape for regular expression\
  1683.    \n:set EscapeForRegEx do={\
  1684.    \n  :local Input [ :tostr \$1 ];\
  1685.    \n\
  1686.    \n  :if ([ :len \$Input ] = 0) do={\
  1687.    \n    :return \"\";\
  1688.    \n  }\
  1689.    \n\
  1690.    \n  :local Return \"\";\
  1691.    \n  :local Chars (\"^.[]\\\$()|*+\?{}\\\\\");\
  1692.    \n\
  1693.    \n  :for I from=0 to=([ :len \$Input ] - 1) do={\
  1694.    \n    :local Char [ :pick \$Input \$I ];\
  1695.    \n    :if ([ :find \$Chars \$Char ]) do={\
  1696.    \n      :set Char (\"\\\\\" . \$Char);\
  1697.    \n    }\
  1698.    \n    :set Return (\$Return . \$Char);\
  1699.    \n  }\
  1700.    \n\
  1701.    \n  :return \$Return;\
  1702.    \n}\
  1703.    \n\
  1704.    \n# format a line for output\
  1705.    \n:set FormatLine do={\
  1706.    \n  :local Key    [ :tostr \$1 ];\
  1707.    \n  :local Value  [ :tostr \$2 ];\
  1708.    \n  :local Indent [ :tonum \$3 ];\
  1709.    \n  :local Spaces;\
  1710.    \n  :local Return \"\";\
  1711.    \n\
  1712.    \n  :global CharacterMultiply;\
  1713.    \n  :global EitherOr;\
  1714.    \n\
  1715.    \n  :set Indent [ \$EitherOr \$Indent 16 ];\
  1716.    \n  :local Spaces [ \$CharacterMultiply \" \" \$Indent ];\
  1717.    \n\
  1718.    \n  :if ([ :len \$Key ] > 0) do={ :set Return (\$Key . \":\"); }\
  1719.    \n  :if ([ :len \$Key ] > (\$Indent - 2)) do={\
  1720.    \n    :set Return (\$Return . \"\\n\" . [ :pick \$Spaces 0 \$Indent ] . \$\
  1721.    Value);\
  1722.    \n  } else={\
  1723.    \n    :set Return (\$Return . [ :pick \$Spaces 0 (\$Indent - [ :len \$Retu\
  1724.    rn ]) ] . \$Value);\
  1725.    \n  }\
  1726.    \n\
  1727.    \n  :return \$Return;\
  1728.    \n}\
  1729.    \n\
  1730.    \n# format multiple lines for output\
  1731.    \n:set FormatMultiLines do={\
  1732.    \n  :local Key    [ :tostr   \$1 ];\
  1733.    \n  :local Values [ :toarray \$2 ];\
  1734.    \n  :local Indent [ :tonum   \$3 ];\
  1735.    \n  :local Return;\
  1736.    \n\
  1737.    \n  :global FormatLine;\
  1738.    \n\
  1739.    \n  :set Return [ \$FormatLine \$Key (\$Values->0) \$Indent ];\
  1740.    \n  :foreach Value in=[ :pick \$Values 1 [ :len \$Values ] ] do={\
  1741.    \n    :set Return (\$Return . \"\\n\" . [ \$FormatLine \"\" \$Value \$Inde\
  1742.    nt ]);\
  1743.    \n  }\
  1744.    \n\
  1745.    \n  :return \$Return;\
  1746.    \n}\
  1747.    \n\
  1748.    \n# get MAC vendor\
  1749.    \n:set GetMacVendor do={\
  1750.    \n  :local Mac [ :tostr \$1 ];\
  1751.    \n\
  1752.    \n  :global CertificateAvailable;\
  1753.    \n  :global IsMacLocallyAdministered;\
  1754.    \n  :global LogPrintExit2;\
  1755.    \n\
  1756.    \n  :if ([ \$IsMacLocallyAdministered \$Mac ] = true) do={\
  1757.    \n    :return \"locally administered\";\
  1758.    \n  }\
  1759.    \n\
  1760.    \n  :do {\
  1761.    \n    :if ([ \$CertificateAvailable \"GTS CA 1P5\" ] = false) do={\
  1762.    \n      \$LogPrintExit2 warning \$0 (\"Downloading required certificate fa\
  1763.    iled.\") true;\
  1764.    \n    }\
  1765.    \n    :local Vendor ([ /tool/fetch check-certificate=yes-without-crl \\\
  1766.    \n        (\"https://api.macvendors.com/\" . [ :pick \$Mac 0 8 ]) output=u\
  1767.    ser as-value ]->\"data\");\
  1768.    \n    :return \$Vendor;\
  1769.    \n  } on-error={\
  1770.    \n    :do {\
  1771.    \n      /tool/fetch check-certificate=yes-without-crl (\"https://api.macve\
  1772.    ndors.com/\") \\\
  1773.    \n        output=none as-value;\
  1774.    \n      \$LogPrintExit2 debug \$0 (\"The mac vendor is not known in databa\
  1775.    se.\") false;\
  1776.    \n    } on-error={\
  1777.    \n      \$LogPrintExit2 warning \$0 (\"Failed getting mac vendor.\") false\
  1778.    ;\
  1779.    \n    }\
  1780.    \n    :return \"unknown vendor\";\
  1781.    \n  }\
  1782.    \n}\
  1783.    \n\
  1784.    \n# generate random 20 chars alphabetical (A-Z & a-z) and numerical (0-9)\
  1785.    \n:set GetRandom20CharAlNum do={\
  1786.    \n  :global EitherOr;\
  1787.    \n\
  1788.    \n  :return [ :rndstr length=[ \$EitherOr [ :tonum \$1 ] 20 ] from=\"ABCDE\
  1789.    FGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\" ];\
  1790.    \n}\
  1791.    \n\
  1792.    \n# generate random 20 chars hex (0-9 and a-f)\
  1793.    \n:set GetRandom20CharHex do={\
  1794.    \n  :global EitherOr;\
  1795.    \n\
  1796.    \n  :return [ :rndstr length=[ \$EitherOr [ :tonum \$1 ] 20 ] from=\"01234\
  1797.    56789abcdef\" ];\
  1798.    \n}\
  1799.    \n\
  1800.    \n# generate random number\
  1801.    \n:set GetRandomNumber do={\
  1802.    \n  :global EitherOr;\
  1803.    \n\
  1804.    \n  :return [ :rndnum from=0 to=[ \$EitherOr [ :tonum \$1 ] 4294967295 ] ]\
  1805.    ;\
  1806.    \n}\
  1807.    \n\
  1808.    \n# return first line that matches a pattern\
  1809.    \n:set Grep do={\
  1810.    \n  :local Input  ([ :tostr \$1 ] . \"\\n\");\
  1811.    \n  :local Pattern [ :tostr \$2 ];\
  1812.    \n\
  1813.    \n  :if ([ :typeof [ :find \$Input \$Pattern ] ] = \"nil\") do={\
  1814.    \n    :return [];\
  1815.    \n  }\
  1816.    \n\
  1817.    \n  :do {\
  1818.    \n    :local Line [ :pick \$Input 0 [ :find \$Input \"\\n\" ] ];\
  1819.    \n    :if ([ :typeof [ :find \$Line \$Pattern ] ] = \"num\") do={\
  1820.    \n      :return \$Line;\
  1821.    \n    }\
  1822.    \n    :set Input [ :pick \$Input ([ :find \$Input \"\\n\" ] + 1) [ :len \$\
  1823.    Input ] ];\
  1824.    \n  } while=([ :len \$Input ] > 0);\
  1825.    \n\
  1826.    \n  :return [];\
  1827.    \n}\
  1828.    \n\
  1829.    \n# convert from hex (string) to num\
  1830.    \n:set HexToNum do={\
  1831.    \n  :local Input [ :tostr \$1 ];\
  1832.    \n  :local Hex \"0123456789abcdef0123456789ABCDEF\";\
  1833.    \n  :local Multi 1;\
  1834.    \n  :local Return 0;\
  1835.    \n\
  1836.    \n  :for I from=([ :len \$Input ] - 1) to=0 do={\
  1837.    \n    :set Return (\$Return + (([ :find \$Hex [ :pick \$Input \$I ] ] % 16\
  1838.    ) * \$Multi));\
  1839.    \n    :set Multi (\$Multi * 16);\
  1840.    \n  }\
  1841.    \n\
  1842.    \n  :return \$Return;\
  1843.    \n}\
  1844.    \n\
  1845.    \n# return human readable number\
  1846.    \n:global HumanReadableNum do={\
  1847.    \n  :local Input [ :tonum \$1 ];\
  1848.    \n  :local Base  [ :tonum \$2 ];\
  1849.    \n\
  1850.    \n  :global EitherOr;\
  1851.    \n\
  1852.    \n  :local Prefix \"kMGTPE\";\
  1853.    \n  :local Pow 1;\
  1854.    \n\
  1855.    \n  :set Base [ \$EitherOr \$Base 1024 ];\
  1856.    \n\
  1857.    \n  :if (\$Input < \$Base) do={\
  1858.    \n    :return \$Input;\
  1859.    \n  }\
  1860.    \n\
  1861.    \n  :for I from=0 to=[ :len \$Prefix ] do={\
  1862.    \n    :set Pow (\$Pow * \$Base);\
  1863.    \n    :if (\$Input / \$Base < \$Pow) do={\
  1864.    \n      :set Prefix [ :pick \$Prefix \$I ];\
  1865.    \n      :local Tmp1 (\$Input * 100 / \$Pow);\
  1866.    \n      :local Tmp2 (\$Tmp1 / 100);\
  1867.    \n      :if (\$Tmp2 >= 100) do={\
  1868.    \n        :return (\$Tmp2 . \$Prefix);\
  1869.    \n      }\
  1870.    \n      :return (\$Tmp2 . \".\" . [ :pick \$Tmp1 [ :len \$Tmp2 ] ([ :len \
  1871.    \$Tmp1 ] - [ :len \$Tmp2 ] + 1) ] . \$Prefix);\
  1872.    \n    }\
  1873.    \n  }\
  1874.    \n}\
  1875.    \n\
  1876.    \n# mimic conditional/ternary operator (condition \? consequent : alternat\
  1877.    ive)\
  1878.    \n:set IfThenElse do={\
  1879.    \n  :if ([ :tostr \$1 ] = \"true\" || [ :tobool \$1 ] = true) do={\
  1880.    \n    :return \$2;\
  1881.    \n  }\
  1882.    \n  :return \$3;\
  1883.    \n}\
  1884.    \n\
  1885.    \n# check if default route is reachable\
  1886.    \n:set IsDefaultRouteReachable do={\
  1887.    \n  :if ([ :len [ /ip/route/find where dst-address=0.0.0.0/0 active routin\
  1888.    g-table=main ] ] > 0) do={\
  1889.    \n    :return true;\
  1890.    \n  }\
  1891.    \n  :return false;\
  1892.    \n}\
  1893.    \n\
  1894.    \n# check if DNS is resolving\
  1895.    \n:set IsDNSResolving do={\
  1896.    \n  :global CharacterReplace;\
  1897.    \n\
  1898.    \n  :do {\
  1899.    \n    :resolve \"low-ttl.eworm.de\";\
  1900.    \n  } on-error={\
  1901.    \n    :return false;\
  1902.    \n  }\
  1903.    \n  :return true;\
  1904.    \n}\
  1905.    \n\
  1906.    \n# check if system is is fully connected (default route reachable, DNS re\
  1907.    solving, time sync)\
  1908.    \n:set IsFullyConnected do={\
  1909.    \n  :global IsDefaultRouteReachable;\
  1910.    \n  :global IsDNSResolving;\
  1911.    \n  :global IsTimeSync;\
  1912.    \n\
  1913.    \n  :if ([ \$IsDefaultRouteReachable ] = false) do={\
  1914.    \n    :return false;\
  1915.    \n  }\
  1916.    \n  :if ([ \$IsDNSResolving ] = false) do={\
  1917.    \n    :return false;\
  1918.    \n  }\
  1919.    \n  :if ([ \$IsTimeSync ] = false) do={\
  1920.    \n    :return false;\
  1921.    \n  }\
  1922.    \n  :return true;\
  1923.    \n}\
  1924.    \n\
  1925.    \n# check if mac address is locally administered\
  1926.    \n:set IsMacLocallyAdministered do={\
  1927.    \n  :if ([ :tonum (\"0x\" . [ :pick \$1 0 [ :find \$1 \":\" ] ]) ] & 2 = 2\
  1928.    ) do={\
  1929.    \n    :return true;\
  1930.    \n  }\
  1931.    \n  :return false;\
  1932.    \n}\
  1933.    \n\
  1934.    \n# check if system time is sync\
  1935.    \n:set IsTimeSync do={\
  1936.    \n  :global IsTimeSyncCached;\
  1937.    \n  :global IsTimeSyncResetNtp;\
  1938.    \n\
  1939.    \n  :global LogPrintExit2;\
  1940.    \n\
  1941.    \n  :if (\$IsTimeSyncCached = true) do={\
  1942.    \n    :return true;\
  1943.    \n  }\
  1944.    \n\
  1945.    \n  :if ([ /system/ntp/client/get enabled ] = true) do={\
  1946.    \n    :if ([ /system/ntp/client/get status ] = \"synchronized\") do={\
  1947.    \n      :set IsTimeSyncCached true;\
  1948.    \n      :return true;\
  1949.    \n    }\
  1950.    \n\
  1951.    \n    :if ([ :typeof \$IsTimeSyncResetNtp ] = \"nothing\") do={\
  1952.    \n      :set IsTimeSyncResetNtp 0s;\
  1953.    \n    }\
  1954.    \n    :local Uptime [ /system/resource/get uptime ];\
  1955.    \n    :if (\$Uptime - \$IsTimeSyncResetNtp < 3m) do={\
  1956.    \n      :return false;\
  1957.    \n    }\
  1958.    \n\
  1959.    \n    :set IsTimeSyncResetNtp \$Uptime;\
  1960.    \n    /system/ntp/client/set enabled=no;\
  1961.    \n    :delay 20ms;\
  1962.    \n    /system/ntp/client/set enabled=yes;\
  1963.    \n    :return false;\
  1964.    \n  }\
  1965.    \n\
  1966.    \n  :if ([ /system/license/get ]->\"level\" = \"free\" || \\\
  1967.    \n       [ /system/resource/get ]->\"board-name\" = \"x86\") do={\
  1968.    \n    \$LogPrintExit2 debug \$0 (\"No ntp client configured, relying on RT\
  1969.    C for CHR free license and x86.\") false;\
  1970.    \n    :return true;\
  1971.    \n  }\
  1972.    \n\
  1973.    \n  :if ([ /ip/cloud/get update-time ] = true) do={\
  1974.    \n    :if ([ :typeof [ /ip/cloud/get public-address ] ] = \"ip\") do={\
  1975.    \n      :set IsTimeSyncCached true;\
  1976.    \n      :return true;\
  1977.    \n    }\
  1978.    \n    :return false;\
  1979.    \n  }\
  1980.    \n\
  1981.    \n  \$LogPrintExit2 debug \$0 (\"No time source configured! Returning grac\
  1982.    efully...\") false;\
  1983.    \n  :return true;\
  1984.    \n}\
  1985.    \n\
  1986.    \n# log and print with same text, optionally exit\
  1987.    \n:set LogPrintExit2 do={\
  1988.    \n  :local Severity [ :tostr \$1 ];\
  1989.    \n  :local Name     [ :tostr \$2 ];\
  1990.    \n  :local Message  [ :tostr \$3 ];\
  1991.    \n  :local Exit     [ :tostr \$4 ];\
  1992.    \n\
  1993.    \n  :global PrintDebug;\
  1994.    \n  :global PrintDebugOverride;\
  1995.    \n\
  1996.    \n  :global EitherOr;\
  1997.    \n\
  1998.    \n  :local Debug [ \$EitherOr (\$PrintDebugOverride->\$Name) \$PrintDebug \
  1999.    ];\
  2000.    \n\
  2001.    \n  :local PrintSeverity do={\
  2002.    \n    :global TerminalColorOutput;\
  2003.    \n\
  2004.    \n    :if (\$TerminalColorOutput != true) do={\
  2005.    \n      :return \$1;\
  2006.    \n    }\
  2007.    \n\
  2008.    \n    :local Color { debug=96; info=97; warning=93; error=91 };\
  2009.    \n    :return (\"\\1B[\" . \$Color->\$1 . \"m\" . \$1 . \"\\1B[0m\");\
  2010.    \n  }\
  2011.    \n\
  2012.    \n  :local Log ([ \$EitherOr \$Name \"<unknown>\" ] . \": \" . \$Message);\
  2013.    \n  :if (\$Severity ~ (\"^(debug|error|info)\\\$\")) do={\
  2014.    \n    :if (\$Severity = \"debug\") do={ :log debug \$Log; }\
  2015.    \n    :if (\$Severity = \"error\") do={ :log error \$Log; }\
  2016.    \n    :if (\$Severity = \"info\" ) do={ :log info  \$Log; }\
  2017.    \n  } else={\
  2018.    \n    :log warning \$Log;\
  2019.    \n    :set Severity \"warning\";\
  2020.    \n  }\
  2021.    \n\
  2022.    \n  :if (\$Severity != \"debug\" || \$Debug = true) do={\
  2023.    \n    :put ([ \$PrintSeverity \$Severity ] . \": \" . \$Message);\
  2024.    \n  }\
  2025.    \n\
  2026.    \n  :if (\$Exit = \"true\") do={\
  2027.    \n    :error (\"Hard error to exit.\");\
  2028.    \n  }\
  2029.    \n}\
  2030.    \n\
  2031.    \n# log and print, once until reboot\
  2032.    \n:set LogPrintOnce do={\
  2033.    \n  :local Severity [ :tostr \$1 ];\
  2034.    \n  :local Name     [ :tostr \$2 ];\
  2035.    \n  :local Message  [ :tostr \$3 ];\
  2036.    \n\
  2037.    \n  :global LogPrintExit2;\
  2038.    \n\
  2039.    \n  :global LogPrintOnceMessages;\
  2040.    \n\
  2041.    \n  :if ([ :typeof \$LogPrintOnceMessages ] = \"nothing\") do={\
  2042.    \n    :set LogPrintOnceMessages ({});\
  2043.    \n  }\
  2044.    \n\
  2045.    \n  :if (\$LogPrintOnceMessages->\$Message = 1) do={\
  2046.    \n    :return true;\
  2047.    \n  }\
  2048.    \n\
  2049.    \n  :set (\$LogPrintOnceMessages->\$Message) 1;\
  2050.    \n  \$LogPrintExit2 \$Severity \$Name \$Message false;\
  2051.    \n}\
  2052.    \n\
  2053.    \n# get max value\
  2054.    \n:set MAX do={\
  2055.    \n  :if (\$1 > \$2) do={ :return \$1; }\
  2056.    \n  :return \$2;\
  2057.    \n}\
  2058.    \n\
  2059.    \n# get min value\
  2060.    \n:set MIN do={\
  2061.    \n  :if (\$1 < \$2) do={ :return \$1; }\
  2062.    \n  :return \$2;\
  2063.    \n}\
  2064.    \n\
  2065.    \n# create directory\
  2066.    \n:set MkDir do={\
  2067.    \n  :local Path [ :tostr \$1 ];\
  2068.    \n\
  2069.    \n  :global CharacterReplace;\
  2070.    \n  :global CleanFilePath;\
  2071.    \n  :global GetRandom20CharAlNum;\
  2072.    \n  :global LogPrintExit2;\
  2073.    \n  :global WaitForFile;\
  2074.    \n\
  2075.    \n  :local MkTmpfs do={\
  2076.    \n    :global LogPrintExit2;\
  2077.    \n    :global WaitForFile;\
  2078.    \n\
  2079.    \n    :if ([ :len [ /disk/find where slot=tmpfs type=tmpfs ] ] = 1) do={\
  2080.    \n      :return true;\
  2081.    \n    }\
  2082.    \n\
  2083.    \n    \$LogPrintExit2 info \$0 (\"Creating disk of type tmpfs.\") false;\
  2084.    \n    /file/remove [ find where name=\"tmpfs\" type=\"directory\" ];\
  2085.    \n    :do {\
  2086.    \n      /disk/add slot=tmpfs type=tmpfs tmpfs-max-size=([ /system/resource\
  2087.    /get total-memory ] / 3);\
  2088.    \n      \$WaitForFile \"tmpfs\";\
  2089.    \n    } on-error={\
  2090.    \n      \$LogPrintExit2 warning \$0 (\"Creating disk of type tmpfs failed!\
  2091.    \") false;\
  2092.    \n      :return false;\
  2093.    \n    }\
  2094.    \n    :return true;\
  2095.    \n  }\
  2096.    \n\
  2097.    \n  :set Path [ \$CleanFilePath \$Path ];\
  2098.    \n\
  2099.    \n  :if (\$Path = \"\") do={\
  2100.    \n    :return true;\
  2101.    \n  }\
  2102.    \n\
  2103.    \n  :if ([ :len [ /file/find where name=\$Path type=\"directory\" ] ] = 1)\
  2104.    \_do={\
  2105.    \n    :return true;\
  2106.    \n  }\
  2107.    \n\
  2108.    \n  :if ([ :pick \$Path 0 5 ] = \"tmpfs\") do={\
  2109.    \n    :if ([ \$MkTmpfs ] = false) do={\
  2110.    \n      :return false;\
  2111.    \n    }\
  2112.    \n  }\
  2113.    \n\
  2114.    \n  :do {\
  2115.    \n    :local File (\$Path . \"/file\");\
  2116.    \n    /file/add name=\$File;\
  2117.    \n    \$WaitForFile \$File;\
  2118.    \n    /file/remove \$File;\
  2119.    \n  } on-error={\
  2120.    \n    \$LogPrintExit2 warning \$0 (\"Making directory '\" . \$Path . \"' f\
  2121.    ailed!\") false;\
  2122.    \n    :return false;\
  2123.    \n  }\
  2124.    \n\
  2125.    \n  :return true;\
  2126.    \n}\
  2127.    \n\
  2128.    \n# prepare NotificationFunctions array\
  2129.    \n:if ([ :typeof \$NotificationFunctions ] != \"array\") do={\
  2130.    \n  :set NotificationFunctions ({});\
  2131.    \n}\
  2132.    \n\
  2133.    \n# parse the date and return a named array\
  2134.    \n:set ParseDate do={\
  2135.    \n  :local Date [ :tostr \$1 ];\
  2136.    \n\
  2137.    \n  :return ({ \"year\"=[ :tonum [ :pick \$Date 0 4 ] ];\
  2138.    \n            \"month\"=[ :tonum [ :pick \$Date 5 7 ] ];\
  2139.    \n              \"day\"=[ :tonum [ :pick \$Date 8 10 ] ] });\
  2140.    \n}\
  2141.    \n\
  2142.    \n# parse JSON into array\
  2143.    \n# Warning: This is not a complete parser!\
  2144.    \n:set ParseJson do={\
  2145.    \n  :local Input [ :tostr \$1 ];\
  2146.    \n\
  2147.    \n  :local InLen;\
  2148.    \n  :local Return ({});\
  2149.    \n  :local Skip 0;\
  2150.    \n\
  2151.    \n  :if ([ :pick \$Input 0 ] = \"{\") do={\
  2152.    \n    :set Input [ :pick \$Input 1 ([ :len \$Input ] - 1) ];\
  2153.    \n  }\
  2154.    \n  :set Input [ :toarray \$Input ];\
  2155.    \n  :set InLen [ :len \$Input ];\
  2156.    \n\
  2157.    \n  :for I from=0 to=\$InLen do={\
  2158.    \n    :if (\$Skip > 0 || \$Input->\$I = \"\\n\" || \$Input->\$I = \"\\r\\n\
  2159.    \") do={\
  2160.    \n      :if (\$Skip > 0) do={\
  2161.    \n        :set \$Skip (\$Skip - 1);\
  2162.    \n      }\
  2163.    \n    } else={\
  2164.    \n      :local Done false;\
  2165.    \n      :local Key (\$Input->\$I);\
  2166.    \n      :local Val1 (\$Input->(\$I + 1));\
  2167.    \n      :local Val2 (\$Input->(\$I + 2));\
  2168.    \n      :if (\$Val1 = \":\") do={\
  2169.    \n        :set Skip 2;\
  2170.    \n        :set (\$Return->\$Key) \$Val2;\
  2171.    \n        :set Done true;\
  2172.    \n      }\
  2173.    \n      :if (\$Done = false && \$Val1 = \":[\") do={\
  2174.    \n        :local Last false;\
  2175.    \n        :set Skip 1;\
  2176.    \n        :set (\$Return->\$Key) ({});\
  2177.    \n        :do {\
  2178.    \n          :set Skip (\$Skip + 1);\
  2179.    \n          :local ValX (\$Input->(\$I + \$Skip));\
  2180.    \n          :if ([ :pick \$ValX ([ :len \$ValX ] - 1) ] = \"]\") do={\
  2181.    \n            :set Last true;\
  2182.    \n            :set ValX [ :pick \$ValX 0 ([ :len \$ValX ] - 1) ];\
  2183.    \n          }\
  2184.    \n          :set (\$Return->\$Key) ((\$Return->\$Key), \$ValX);\
  2185.    \n        } while=(\$Last = false && \$I + \$Skip < \$InLen);\
  2186.    \n        :set Done true;\
  2187.    \n      }\
  2188.    \n      :if (\$Done = false && \$Val1 = \":[]\") do={\
  2189.    \n        :set Skip 1;\
  2190.    \n        :set (\$Return->\$Key) ({});\
  2191.    \n        :set Done true;\
  2192.    \n      }\
  2193.    \n      :if (\$Done = false) do={\
  2194.    \n        :set Skip 1;\
  2195.    \n        :set (\$Return->\$Key) [ :pick \$Val1 1 [ :len \$Val1 ] ];\
  2196.    \n      }\
  2197.    \n    }\
  2198.    \n  }\
  2199.    \n\
  2200.    \n  :return \$Return;\
  2201.    \n}\
  2202.    \n\
  2203.    \n# parse key value store\
  2204.    \n:set ParseKeyValueStore do={\
  2205.    \n  :local Source \$1;\
  2206.    \n  :if ([ :typeof \$Source ] != \"array\") do={\
  2207.    \n    :set Source [ :tostr \$1 ];\
  2208.    \n  }\
  2209.    \n  :local Result ({});\
  2210.    \n  :foreach KeyValue in=[ :toarray \$Source ] do={\
  2211.    \n    :if ([ :find \$KeyValue \"=\" ]) do={\
  2212.    \n      :set (\$Result->[ :pick \$KeyValue 0 [ :find \$KeyValue \"=\" ] ])\
  2213.    \_\\\
  2214.    \n        [ :pick \$KeyValue ([ :find \$KeyValue \"=\" ] + 1) [ :len \$Key\
  2215.    Value ] ];\
  2216.    \n    } else={\
  2217.    \n      :set (\$Result->\$KeyValue) true;\
  2218.    \n    }\
  2219.    \n  }\
  2220.    \n  :return \$Result;\
  2221.    \n}\
  2222.    \n\
  2223.    \n# print lines with trailing carriage return\
  2224.    \n:set PrettyPrint do={\
  2225.    \n  :local Input [ :tostr \$1 ];\
  2226.    \n\
  2227.    \n  :global Unix2Dos;\
  2228.    \n\
  2229.    \n  :put [ \$Unix2Dos \$Input ];\
  2230.    \n}\
  2231.    \n\
  2232.    \n# delay a random amount of seconds\
  2233.    \n:set RandomDelay do={\
  2234.    \n  :global EitherOr;\
  2235.    \n  :global GetRandomNumber;\
  2236.    \n\
  2237.    \n  :delay ([ \$GetRandomNumber \$1 ] . [ \$EitherOr \$2 \"s\" ]);\
  2238.    \n}\
  2239.    \n\
  2240.    \n# check for required RouterOS version\
  2241.    \n:set RequiredRouterOS do={\
  2242.    \n  :local Caller   [ :tostr \$1 ];\
  2243.    \n  :local Required [ :tostr \$2 ];\
  2244.    \n  :local Warn     [ :tostr \$3 ];\
  2245.    \n\
  2246.    \n  :global IfThenElse;\
  2247.    \n  :global LogPrintExit2;\
  2248.    \n  :global VersionToNum;\
  2249.    \n\
  2250.    \n  :if (!(\$Required ~ \"^\\\\d+\\\\.\\\\d+((alpha|beta|rc|\\\\.)\\\\d+|)\
  2251.    \\\$\")) do={\
  2252.    \n    \$LogPrintExit2 error \$0 (\"No valid RouterOS version: \" . \$Requi\
  2253.    red) false;\
  2254.    \n    :return false;\
  2255.    \n  }\
  2256.    \n\
  2257.    \n  :if ([ \$VersionToNum \$Required ] > [ \$VersionToNum [ /system/packag\
  2258.    e/update/get installed-version ] ]) do={\
  2259.    \n    :if (\$Warn = \"true\") do={\
  2260.    \n      \$LogPrintExit2 warning \$0 (\"This \" . [ \$IfThenElse ([ :pick \
  2261.    \$Caller 0 ] = (\"\\\$\")) \"function\" \"script\" ] . \\\
  2262.    \n        \" '\" . \$Caller . \"' (at least specific functionality) requir\
  2263.    es RouterOS \" . \$Required . \". Please update!\") false;\
  2264.    \n    }\
  2265.    \n    :return false;\
  2266.    \n  }\
  2267.    \n  :return true;\
  2268.    \n}\
  2269.    \n\
  2270.    \n# check if script is run from terminal\
  2271.    \n:set ScriptFromTerminal do={\
  2272.    \n  :local Script [ :tostr \$1 ];\
  2273.    \n\
  2274.    \n  :global LogPrintExit2;\
  2275.    \n\
  2276.    \n  :foreach Job in=[ /system/script/job/find where script=\$Script ] do={\
  2277.    \n    :set Job [ /system/script/job/get \$Job ];\
  2278.    \n    :while ([ :typeof (\$Job->\"parent\") ] = \"id\") do={\
  2279.    \n      :set Job [ /system/script/job/get [ find where .id=(\$Job->\"paren\
  2280.    t\") ] ];\
  2281.    \n    }\
  2282.    \n    :if ((\$Job->\"type\") = \"login\") do={\
  2283.    \n      \$LogPrintExit2 debug \$0 (\"Script \" . \$Script . \" started fro\
  2284.    m terminal.\") false;\
  2285.    \n      :return true;\
  2286.    \n    }\
  2287.    \n  }\
  2288.    \n  \$LogPrintExit2 debug \$0 (\"Script \" . \$Script . \" NOT started fro\
  2289.    m terminal.\") false;\
  2290.    \n\
  2291.    \n  :return false;\
  2292.    \n}\
  2293.    \n\
  2294.    \n# install new scripts, update existing scripts\
  2295.    \n:set ScriptInstallUpdate do={\
  2296.    \n  :local Scripts    [ :toarray \$1 ];\
  2297.    \n  :local NewComment [ :tostr   \$2 ];\
  2298.    \n\
  2299.    \n  :global ExpectedConfigVersion;\
  2300.    \n  :global FetchUserAgent;\
  2301.    \n  :global Identity;\
  2302.    \n  :global IDonate;\
  2303.    \n  :global NoNewsAndChangesNotification;\
  2304.    \n  :global ScriptUpdatesBaseUrl;\
  2305.    \n  :global ScriptUpdatesUrlSuffix;\
  2306.    \n\
  2307.    \n  :global CertificateAvailable;\
  2308.    \n  :global EitherOr;\
  2309.    \n  :global Grep;\
  2310.    \n  :global IfThenElse;\
  2311.    \n  :global LogPrintExit2;\
  2312.    \n  :global ParseKeyValueStore;\
  2313.    \n  :global RequiredRouterOS;\
  2314.    \n  :global SendNotification2;\
  2315.    \n  :global SymbolForNotification;\
  2316.    \n  :global ValidateSyntax;\
  2317.    \n\
  2318.    \n  :if ([ \$CertificateAvailable \"E1\" ] = false) do={\
  2319.    \n    \$LogPrintExit2 warning \$0 (\"Downloading certificate failed, tryin\
  2320.    g without.\") false;\
  2321.    \n  }\
  2322.    \n\
  2323.    \n  :foreach Script in=\$Scripts do={\
  2324.    \n    :if ([ :len [ /system/script/find where name=\$Script ] ] = 0) do={\
  2325.    \n      \$LogPrintExit2 info \$0 (\"Adding new script: \" . \$Script) fals\
  2326.    e;\
  2327.    \n      /system/script/add name=\$Script owner=\$Script source=\"#!rsc by \
  2328.    RouterOS\\n\" comment=\$NewComment;\
  2329.    \n    }\
  2330.    \n  }\
  2331.    \n\
  2332.    \n  :local ExpectedConfigVersionBefore \$ExpectedConfigVersion;\
  2333.    \n  :local ReloadGlobalFunctions false;\
  2334.    \n  :local ReloadGlobalConfig false;\
  2335.    \n\
  2336.    \n  :foreach Script in=[ /system/script/find where source~\"^#!rsc by Rout\
  2337.    erOS\\r\?\\n\" ] do={\
  2338.    \n    :local ScriptVal [ /system/script/get \$Script ];\
  2339.    \n    :local ScriptInfo [ \$ParseKeyValueStore (\$ScriptVal->\"comment\") \
  2340.    ];\
  2341.    \n    :local SourceNew;\
  2342.    \n\
  2343.    \n    :foreach Scheduler in=[ /system/scheduler/find where on-event~(\"\\\
  2344.    \\b\" . \$ScriptVal->\"name\" . \"\\\\b\") ] do={\
  2345.    \n      :local SchedulerVal [ /system/scheduler/get \$Scheduler ];\
  2346.    \n      :if (\$ScriptVal->\"policy\" != \$SchedulerVal->\"policy\") do={\
  2347.    \n        \$LogPrintExit2 warning \$0 (\"Policies differ for script '\" . \
  2348.    \$ScriptVal->\"name\" . \\\
  2349.    \n          \"' and its scheduler '\" . \$SchedulerVal->\"name\" . \"'!\")\
  2350.    \_false;\
  2351.    \n      }\
  2352.    \n    }\
  2353.    \n\
  2354.    \n    :if (!(\$ScriptInfo->\"ignore\" = true)) do={\
  2355.    \n      :do {\
  2356.    \n        :local BaseUrl [ \$EitherOr (\$ScriptInfo->\"base-url\") \$Scrip\
  2357.    tUpdatesBaseUrl ];\
  2358.    \n        :local UrlSuffix [ \$EitherOr (\$ScriptInfo->\"url-suffix\") \$S\
  2359.    criptUpdatesUrlSuffix ];\
  2360.    \n        :local Url (\$BaseUrl . \$ScriptVal->\"name\" . \".rsc\" . \$Url\
  2361.    Suffix);\
  2362.    \n        \$LogPrintExit2 debug \$0 (\"Fetching script '\" . \$ScriptVal->\
  2363.    \"name\" . \"' from url: \" . \$Url) false;\
  2364.    \n        :local Result [ /tool/fetch check-certificate=yes-without-crl \\\
  2365.    \n          http-header-field=({ \$FetchUserAgent }) \$Url output=user as-\
  2366.    value ];\
  2367.    \n        :if (\$Result->\"status\" = \"finished\") do={\
  2368.    \n          :set SourceNew (\$Result->\"data\");\
  2369.    \n        }\
  2370.    \n      } on-error={\
  2371.    \n        :if (\$ScriptVal->\"source\" = \"#!rsc by RouterOS\\n\") do={\
  2372.    \n          \$LogPrintExit2 warning \$0 (\"Failed fetching script '\" . \$\
  2373.    ScriptVal->\"name\" . \\\
  2374.    \n            \"', removing dummy. Typo on installation\?\") false;\
  2375.    \n          /system/script/remove \$Script;\
  2376.    \n        } else={\
  2377.    \n          \$LogPrintExit2 warning \$0 (\"Failed fetching script '\" . \$\
  2378.    ScriptVal->\"name\" . \"'!\") false;\
  2379.    \n        }\
  2380.    \n      }\
  2381.    \n    }\
  2382.    \n\
  2383.    \n    :if ([ :len \$SourceNew ] > 0) do={\
  2384.    \n      :if (\$SourceNew != \$ScriptVal->\"source\") do={\
  2385.    \n        :if ([ :pick \$SourceNew 0 18 ] = \"#!rsc by RouterOS\\n\") do={\
  2386.    \n          :local Required ([ \$ParseKeyValueStore [ \$Grep \$SourceNew (\
  2387.    \"\\23 requires RouterOS, \") ] ]->\"version\");\
  2388.    \n          :if ([ \$RequiredRouterOS \$0 [ \$EitherOr \$Required \"0.0\" \
  2389.    ] false ] = true) do={\
  2390.    \n            :if ([ \$ValidateSyntax \$SourceNew ] = true) do={\
  2391.    \n              \$LogPrintExit2 info \$0 (\"Updating script: \" . \$Script\
  2392.    Val->\"name\") false;\
  2393.    \n              /system/script/set owner=(\$ScriptVal->\"name\") source=\$\
  2394.    SourceNew \$Script;\
  2395.    \n              :if (\$ScriptVal->\"name\" = \"global-config\") do={\
  2396.    \n                :set ReloadGlobalConfig true;\
  2397.    \n              }\
  2398.    \n              :if (\$ScriptVal->\"name\" = \"global-functions\" || \$Scr\
  2399.    iptVal->\"name\" ~ (\"^mod/.\")) do={\
  2400.    \n                :set ReloadGlobalFunctions true;\
  2401.    \n              }\
  2402.    \n            } else={\
  2403.    \n              \$LogPrintExit2 warning \$0 (\"Syntax validation for scrip\
  2404.    t '\" . \$ScriptVal->\"name\" . \\\
  2405.    \n                \"' failed! Ignoring!\") false;\
  2406.    \n            }\
  2407.    \n          } else={\
  2408.    \n            \$LogPrintExit2 warning \$0 (\"The script '\" . \$ScriptVal-\
  2409.    >\"name\" . \"' requires RouterOS \" . \\\
  2410.    \n              \$Required . \", which is not met by your installation. Ig\
  2411.    noring!\") false;\
  2412.    \n          }\
  2413.    \n        } else={\
  2414.    \n          \$LogPrintExit2 warning \$0 (\"Looks like new script '\" . \$S\
  2415.    criptVal->\"name\" . \\\
  2416.    \n            \"' is not valid (missing shebang). Ignoring!\") false;\
  2417.    \n        }\
  2418.    \n      } else={\
  2419.    \n        \$LogPrintExit2 debug \$0 (\"Script '\" .  \$ScriptVal->\"name\"\
  2420.    \_. \"' did not change.\") false;\
  2421.    \n      }\
  2422.    \n    } else={\
  2423.    \n      \$LogPrintExit2 debug \$0 (\"No update for script '\" . \$ScriptVa\
  2424.    l->\"name\" . \"'.\") false;\
  2425.    \n    }\
  2426.    \n  }\
  2427.    \n\
  2428.    \n  :if (\$ReloadGlobalFunctions = true) do={\
  2429.    \n    \$LogPrintExit2 info \$0 (\"Reloading global functions.\") false;\
  2430.    \n    :do {\
  2431.    \n      /system/script/run global-functions;\
  2432.    \n    } on-error={\
  2433.    \n      \$LogPrintExit2 error \$0 (\"Reloading global functions failed!\")\
  2434.    \_false;\
  2435.    \n    }\
  2436.    \n  }\
  2437.    \n\
  2438.    \n  :if (\$ReloadGlobalConfig = true) do={\
  2439.    \n    \$LogPrintExit2 info \$0 (\"Reloading global configuration.\") false\
  2440.    ;\
  2441.    \n    :do {\
  2442.    \n      /system/script/run global-config;\
  2443.    \n    } on-error={\
  2444.    \n      \$LogPrintExit2 error \$0 (\"Reloading global configuration failed\
  2445.    !\" . \\\
  2446.    \n        \" Syntax error or missing overlay\?\") false;\
  2447.    \n    }\
  2448.    \n  }\
  2449.    \n\
  2450.    \n  :if (\$ExpectedConfigVersionBefore > \$ExpectedConfigVersion) do={\
  2451.    \n    \$LogPrintExit2 warning \$0 (\"The configuration version decreased f\
  2452.    rom \" . \\\
  2453.    \n      \$ExpectedConfigVersionBefore . \" to \" . \$ExpectedConfigVersion\
  2454.    \_. \\\
  2455.    \n      \". Installed an older version\?\") false;\
  2456.    \n  }\
  2457.    \n\
  2458.    \n  :if (\$ExpectedConfigVersionBefore < \$ExpectedConfigVersion) do={\
  2459.    \n    :global GlobalConfigChanges;\
  2460.    \n    :global GlobalConfigMigration;\
  2461.    \n    :local ChangeLogCode;\
  2462.    \n\
  2463.    \n    :do {\
  2464.    \n      :local Url (\$ScriptUpdatesBaseUrl . \"news-and-changes.rsc\" . \$\
  2465.    ScriptUpdatesUrlSuffix);\
  2466.    \n      \$LogPrintExit2 debug \$0 (\"Fetching news, changes and migration:\
  2467.    \_\" . \$Url) false;\
  2468.    \n      :local Result [ /tool/fetch check-certificate=yes-without-crl \\\
  2469.    \n        http-header-field=({ \$FetchUserAgent }) \$Url output=user as-va\
  2470.    lue ];\
  2471.    \n      :if (\$Result->\"status\" = \"finished\") do={\
  2472.    \n        :set ChangeLogCode (\$Result->\"data\");\
  2473.    \n      }\
  2474.    \n    } on-error={\
  2475.    \n      \$LogPrintExit2 warning \$0 (\"Failed fetching news, changes and m\
  2476.    igration!\") false;\
  2477.    \n    }\
  2478.    \n\
  2479.    \n    :if ([ :len \$ChangeLogCode ] > 0) do={\
  2480.    \n      :if ([ \$ValidateSyntax \$ChangeLogCode ] = true) do={\
  2481.    \n        :do {\
  2482.    \n          [ :parse \$ChangeLogCode ];\
  2483.    \n        } on-error={\
  2484.    \n          \$LogPrintExit2 warning \$0 (\"The changelog failed to run!\")\
  2485.    \_false;\
  2486.    \n        }\
  2487.    \n      } else={\
  2488.    \n        \$LogPrintExit2 warning \$0 (\"The changelog failed syntax valid\
  2489.    ation!\") false;\
  2490.    \n      }\
  2491.    \n    }\
  2492.    \n\
  2493.    \n    :if ([ :len \$GlobalConfigMigration ] > 0) do={\
  2494.    \n      :for I from=(\$ExpectedConfigVersionBefore + 1) to=\$ExpectedConfi\
  2495.    gVersion do={\
  2496.    \n        :local Migration (\$GlobalConfigMigration->[ :tostr \$I ]);\
  2497.    \n        :if ([ :typeof \$Migration ] = \"str\") do={\
  2498.    \n          :if ([ \$ValidateSyntax \$Migration ] = true) do={\
  2499.    \n            \$LogPrintExit2 info \$0 (\"Applying migration for change \"\
  2500.    \_. \$I . \": \" . \$Migration) false;\
  2501.    \n            :do {\
  2502.    \n              [ :parse \$Migration ];\
  2503.    \n            } on-error={\
  2504.    \n              \$LogPrintExit2 warning \$0 (\"Migration code for change \
  2505.    \" . \$I . \" failed to run!\") false;\
  2506.    \n            }\
  2507.    \n          } else={\
  2508.    \n            \$LogPrintExit2 warning \$0 (\"Migration code for change \" \
  2509.    . \$I . \" failed syntax validation!\") false;\
  2510.    \n          }\
  2511.    \n        }\
  2512.    \n      }\
  2513.    \n    }\
  2514.    \n\
  2515.    \n    :local NotificationMessage (\"The configuration version on \" . \$Id\
  2516.    entity . \" increased \" . \\\
  2517.    \n       \"to \" . \$ExpectedConfigVersion . \", current configuration may\
  2518.    \_need modification. \" . \\\
  2519.    \n       \"Please review and update global-config-overlay, then re-run glo\
  2520.    bal-config.\");\
  2521.    \n    \$LogPrintExit2 info \$0 (\$NotificationMessage) false;\
  2522.    \n\
  2523.    \n    :if ([ :len \$GlobalConfigChanges ] > 0) do={\
  2524.    \n      :set NotificationMessage (\$NotificationMessage . \"\\n\\nChanges:\
  2525.    \");\
  2526.    \n      :for I from=(\$ExpectedConfigVersionBefore + 1) to=\$ExpectedConfi\
  2527.    gVersion do={\
  2528.    \n        :local Change (\$GlobalConfigChanges->[ :tostr \$I ]);\
  2529.    \n        :set NotificationMessage (\$NotificationMessage . \"\\n \" . \\\
  2530.    \n            [ \$SymbolForNotification \"pushpin\" \"*\" ] . \$Change);\
  2531.    \n        \$LogPrintExit2 info \$0 (\"Change \" . \$I . \": \" . \$Change)\
  2532.    \_false;\
  2533.    \n      }\
  2534.    \n    } else={\
  2535.    \n      :set NotificationMessage (\$NotificationMessage . \"\\n\\nNews and\
  2536.    \_changes are not available.\");\
  2537.    \n    }\
  2538.    \n\
  2539.    \n    :if (\$NoNewsAndChangesNotification != true) do={\
  2540.    \n      :local Link;\
  2541.    \n      :if (\$IDonate != true) do={\
  2542.    \n        :set NotificationMessage (\$NotificationMessage . \\\
  2543.    \n          \"\\n\\n==== donation hint ====\\n\" . \\\
  2544.    \n          \"This project is developed in private spare time and usage is\
  2545.    \_\" . \\\
  2546.    \n          \"free of charge for you. If you like the scripts and think th\
  2547.    is is \" . \\\
  2548.    \n          \"of value for you or your business please consider a donation\
  2549.    .\");\
  2550.    \n        :set Link \"https://git.eworm.de/cgit/routeros-scripts/about/#do\
  2551.    nate\";\
  2552.    \n      }\
  2553.    \n\
  2554.    \n      \$SendNotification2 ({ origin=\$0; \\\
  2555.    \n        subject=([ \$SymbolForNotification \"pushpin\" ] . \"News and co\
  2556.    nfiguration changes\"); \\\
  2557.    \n        message=\$NotificationMessage; link=\$Link });\
  2558.    \n    }\
  2559.    \n\
  2560.    \n    :set GlobalConfigChanges;\
  2561.    \n    :set GlobalConfigMigration;\
  2562.    \n  }\
  2563.    \n}\
  2564.    \n\
  2565.    \n# lock script against multiple invocation\
  2566.    \n:set ScriptLock do={\
  2567.    \n  :local Script   [ :tostr \$1 ];\
  2568.    \n  :local DoReturn \$2;\
  2569.    \n  :local WaitMax  ([ :tonum \$3 ] * 10);\
  2570.    \n\
  2571.    \n  :global GetRandom20CharAlNum;\
  2572.    \n  :global IfThenElse;\
  2573.    \n  :global LogPrintExit2;\
  2574.    \n\
  2575.    \n  :global ScriptLockOrder;\
  2576.    \n  :if ([ :typeof \$ScriptLockOrder ] = \"nothing\") do={\
  2577.    \n    :set ScriptLockOrder ({});\
  2578.    \n  }\
  2579.    \n  :if ([ :typeof (\$ScriptLockOrder->\$Script) ] = \"nothing\") do={\
  2580.    \n    :set (\$ScriptLockOrder->\$Script) ({});\
  2581.    \n  }\
  2582.    \n\
  2583.    \n  :local JobCount do={\
  2584.    \n    :local Script [ :tostr \$1 ];\
  2585.    \n\
  2586.    \n    :return [ :len [ /system/script/job/find where script=\$Script ] ];\
  2587.    \n  }\
  2588.    \n\
  2589.    \n  :local TicketCount do={\
  2590.    \n    :local Script [ :tostr \$1 ];\
  2591.    \n\
  2592.    \n    :global ScriptLockOrder;\
  2593.    \n\
  2594.    \n    :local Count 0;\
  2595.    \n    :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\
  2596.    \n      :if ([ :typeof \$Ticket ] != \"nothing\") do={\
  2597.    \n        :set Count (\$Count + 1);\
  2598.    \n      }\
  2599.    \n    }\
  2600.    \n    :return \$Count;\
  2601.    \n  }\
  2602.    \n\
  2603.    \n  :local IsFirstTicket do={\
  2604.    \n    :local Script [ :tostr \$1 ];\
  2605.    \n    :local Check  [ :tostr \$2 ];\
  2606.    \n\
  2607.    \n    :global ScriptLockOrder;\
  2608.    \n\
  2609.    \n    :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\
  2610.    \n      :if (\$Ticket = \$Check) do={ :return true; }\
  2611.    \n      :if ([ :typeof \$Ticket ] != \"nothing\" && \$Ticket != \$Check) d\
  2612.    o={ :return false; }\
  2613.    \n    }\
  2614.    \n    :return false;\
  2615.    \n  }\
  2616.    \n\
  2617.    \n  :local AddTicket do={\
  2618.    \n    :local Script [ :tostr \$1 ];\
  2619.    \n    :local Add    [ :tostr \$2 ];\
  2620.    \n\
  2621.    \n    :global ScriptLockOrder;\
  2622.    \n\
  2623.    \n    :while (true) do={\
  2624.    \n      :local Pos [ :len (\$ScriptLockOrder->\$Script) ];\
  2625.    \n      :set (\$ScriptLockOrder->\$Script->\$Pos) \$Add;\
  2626.    \n      :delay 10ms;\
  2627.    \n      :if ((\$ScriptLockOrder->\$Script->\$Pos) = \$Add) do={ :return tr\
  2628.    ue; }\
  2629.    \n    }\
  2630.    \n  }\
  2631.    \n\
  2632.    \n  :local RemoveTicket do={\
  2633.    \n    :local Script [ :tostr \$1 ];\
  2634.    \n    :local Remove [ :tostr \$2 ];\
  2635.    \n\
  2636.    \n    :global ScriptLockOrder;\
  2637.    \n\
  2638.    \n    :foreach Id,Ticket in=(\$ScriptLockOrder->\$Script) do={\
  2639.    \n      :while ((\$ScriptLockOrder->\$Script->\$Id) = \$Remove) do={\
  2640.    \n        :set (\$ScriptLockOrder->\$Script->\$Id);\
  2641.    \n        :delay 10ms;\
  2642.    \n      }\
  2643.    \n    }\
  2644.    \n  }\
  2645.    \n\
  2646.    \n  :local CleanupTickets do={\
  2647.    \n    :local Script [ :tostr \$1 ];\
  2648.    \n\
  2649.    \n    :global ScriptLockOrder;\
  2650.    \n\
  2651.    \n    :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\
  2652.    \n      :if ([ :typeof \$Ticket ] != \"nothing\") do={\
  2653.    \n        :return false;\
  2654.    \n      }\
  2655.    \n    }\
  2656.    \n\
  2657.    \n    :set (\$ScriptLockOrder->\$Script) ({});\
  2658.    \n  }\
  2659.    \n\
  2660.    \n  :if ([ :len [ /system/script/find where name=\$Script ] ] = 0) do={\
  2661.    \n    \$LogPrintExit2 error \$0 (\"A script named '\" . \$Script . \"' doe\
  2662.    s not exist!\") true;\
  2663.    \n  }\
  2664.    \n\
  2665.    \n  :if ([ \$JobCount \$Script ] = 0) do={\
  2666.    \n    \$LogPrintExit2 error \$0 (\"No script '\" . \$Script . \"' is runni\
  2667.    ng!\") true;\
  2668.    \n  }\
  2669.    \n\
  2670.    \n  :if ([ \$TicketCount \$Script ] >= [ \$JobCount \$Script ]) do={\
  2671.    \n    \$LogPrintExit2 error \$0 (\"More tickets than running scripts '\" .\
  2672.    \_\$Script . \"', resetting!\") false;\
  2673.    \n    :set (\$ScriptLockOrder->\$Script) ({});\
  2674.    \n    /system/script/job/remove [ find where script=\$Script ];\
  2675.    \n  }\
  2676.    \n\
  2677.    \n  :local MyTicket [ \$GetRandom20CharAlNum 6 ];\
  2678.    \n  \$AddTicket \$Script \$MyTicket;\
  2679.    \n\
  2680.    \n  :local WaitCount 0;\
  2681.    \n  :while (\$WaitMax > \$WaitCount && ([ \$IsFirstTicket \$Script \$MyTic\
  2682.    ket ] = false || [ \$TicketCount \$Script ] < [ \$JobCount \$Script ])) do\
  2683.    ={\
  2684.    \n    :set WaitCount (\$WaitCount + 1);\
  2685.    \n    :delay 100ms;\
  2686.    \n  }\
  2687.    \n\
  2688.    \n  :if ([ \$IsFirstTicket \$Script \$MyTicket ] = true && [ \$TicketCount\
  2689.    \_\$Script ] = [ \$JobCount \$Script ]) do={\
  2690.    \n    \$RemoveTicket \$Script \$MyTicket;\
  2691.    \n    \$CleanupTickets \$Script;\
  2692.    \n    :return false;\
  2693.    \n  }\
  2694.    \n\
  2695.    \n  \$RemoveTicket \$Script \$MyTicket;\
  2696.    \n  \$LogPrintExit2 info \$0 (\"Script '\" . \$Script . \"' started more t\
  2697.    han once\" . [ \$IfThenElse (\$WaitCount > 0) \\\
  2698.    \n    \" and timed out waiting for lock\" \"\" ] . \"... Aborting.\") [ \$\
  2699.    IfThenElse (\$DoReturn = true) false true ];\
  2700.    \n  :return true;\
  2701.    \n}\
  2702.    \n\
  2703.    \n# send notification via NotificationFunctions - expects at least two str\
  2704.    ing arguments\
  2705.    \n:set SendNotification do={\
  2706.    \n  :global SendNotification2;\
  2707.    \n\
  2708.    \n  \$SendNotification2 ({ subject=\$1; message=\$2; link=\$3; silent=\$4 \
  2709.    });\
  2710.    \n}\
  2711.    \n\
  2712.    \n# send notification via NotificationFunctions - expects one array argume\
  2713.    nt\
  2714.    \n:set SendNotification2 do={\
  2715.    \n  :local Notification \$1;\
  2716.    \n\
  2717.    \n  :global NotificationFunctions;\
  2718.    \n\
  2719.    \n  :foreach FunctionName,Discard in=\$NotificationFunctions do={\
  2720.    \n    (\$NotificationFunctions->\$FunctionName) \\\
  2721.    \n      (\"\\\$NotificationFunctions->\\\"\" . \$FunctionName . \"\\\"\") \
  2722.    \\\
  2723.    \n      \$Notification;\
  2724.    \n  }\
  2725.    \n}\
  2726.    \n\
  2727.    \n# return UTF-8 symbol for unicode name\
  2728.    \n:set SymbolByUnicodeName do={\
  2729.    \n  :local Symbols {\
  2730.    \n    \"abacus\"=\"\\F0\\9F\\A7\\AE\";\
  2731.    \n    \"alarm-clock\"=\"\\E2\\8F\\B0\";\
  2732.    \n    \"arrow-down\"=\"\\E2\\AC\\87\";\
  2733.    \n    \"arrow-up\"=\"\\E2\\AC\\86\";\
  2734.    \n    \"calendar\"=\"\\F0\\9F\\93\\85\";\
  2735.    \n    \"card-file-box\"=\"\\F0\\9F\\97\\83\";\
  2736.    \n    \"chart-decreasing\"=\"\\F0\\9F\\93\\89\";\
  2737.    \n    \"chart-increasing\"=\"\\F0\\9F\\93\\88\";\
  2738.    \n    \"cloud\"=\"\\E2\\98\\81\";\
  2739.    \n    \"cross-mark\"=\"\\E2\\9D\\8C\";\
  2740.    \n    \"earth\"=\"\\F0\\9F\\8C\\8D\";\
  2741.    \n    \"fire\"=\"\\F0\\9F\\94\\A5\";\
  2742.    \n    \"floppy-disk\"=\"\\F0\\9F\\92\\BE\";\
  2743.    \n    \"heart\"=\"\\E2\\99\\A5\";\
  2744.    \n    \"high-voltage-sign\"=\"\\E2\\9A\\A1\";\
  2745.    \n    \"incoming-envelope\"=\"\\F0\\9F\\93\\A8\";\
  2746.    \n    \"information\"=\"\\E2\\84\\B9\";\
  2747.    \n    \"large-orange-circle\"=\"\\F0\\9F\\9F\\A0\";\
  2748.    \n    \"large-red-circle\"=\"\\F0\\9F\\94\\B4\";\
  2749.    \n    \"link\"=\"\\F0\\9F\\94\\97\";\
  2750.    \n    \"lock-with-ink-pen\"=\"\\F0\\9F\\94\\8F\";\
  2751.    \n    \"memo\"=\"\\F0\\9F\\93\\9D\";\
  2752.    \n    \"mobile-phone\"=\"\\F0\\9F\\93\\B1\";\
  2753.    \n    \"pushpin\"=\"\\F0\\9F\\93\\8C\";\
  2754.    \n    \"scissors\"=\"\\E2\\9C\\82\";\
  2755.    \n    \"sparkles\"=\"\\E2\\9C\\A8\";\
  2756.    \n    \"speech-balloon\"=\"\\F0\\9F\\92\\AC\";\
  2757.    \n    \"star\"=\"\\E2\\AD\\90\";\
  2758.    \n    \"warning-sign\"=\"\\E2\\9A\\A0\";\
  2759.    \n    \"white-heavy-check-mark\"=\"\\E2\\9C\\85\"\
  2760.    \n  }\
  2761.    \n\
  2762.    \n  :return ((\$Symbols->\$1) . \"\\EF\\B8\\8F\");\
  2763.    \n}\
  2764.    \n\
  2765.    \n# return symbol for notification\
  2766.    \n:set SymbolForNotification do={\
  2767.    \n  :global NotificationsWithSymbols;\
  2768.    \n  :global SymbolByUnicodeName;\
  2769.    \n  :global IfThenElse;\
  2770.    \n\
  2771.    \n  :if (\$NotificationsWithSymbols != true) do={\
  2772.    \n    :return [ \$IfThenElse ([ :len \$2 ] > 0) ([ :tostr \$2 ] . \" \") \
  2773.    \"\" ];\
  2774.    \n  }\
  2775.    \n  :local Return \"\";\
  2776.    \n  :foreach Symbol in=[ :toarray \$1 ] do={\
  2777.    \n    :set Return (\$Return . [ \$SymbolByUnicodeName \$Symbol ]);\
  2778.    \n  }\
  2779.    \n  :return (\$Return . \" \");\
  2780.    \n}\
  2781.    \n\
  2782.    \n# convert line endings, UNIX -> DOS\
  2783.    \n:set Unix2Dos do={\
  2784.    \n  :local Input [ :tostr \$1 ];\
  2785.    \n\
  2786.    \n  :global CharacterReplace;\
  2787.    \n\
  2788.    \n  :return [ \$CharacterReplace [ \$CharacterReplace \$Input \\\
  2789.    \n    (\"\\n\") (\"\\r\\n\") ] (\"\\r\\r\\n\") (\"\\r\\n\") ];\
  2790.    \n}\
  2791.    \n\
  2792.    \n# url encoding\
  2793.    \n:set UrlEncode do={\
  2794.    \n  :local Input [ :tostr \$1 ];\
  2795.    \n\
  2796.    \n  :if ([ :len \$Input ] = 0) do={\
  2797.    \n    :return \"\";\
  2798.    \n  }\
  2799.    \n\
  2800.    \n  :local Return \"\";\
  2801.    \n  :local Chars (\"\\n\\r !\\\"#\\\$%&'()*+,:;<=>\?@[\\\\]^`{|}~\");\
  2802.    \n  :local Subs { \"%0A\"; \"%0D\"; \"%20\"; \"%21\"; \"%22\"; \"%23\"; \"\
  2803.    %24\"; \"%25\"; \"%26\"; \"%27\";\
  2804.    \n         \"%28\"; \"%29\"; \"%2A\"; \"%2B\"; \"%2C\"; \"%3A\"; \"%3B\"; \
  2805.    \"%3C\"; \"%3D\"; \"%3E\"; \"%3F\";\
  2806.    \n         \"%40\"; \"%5B\"; \"%5C\"; \"%5D\"; \"%5E\"; \"%60\"; \"%7B\"; \
  2807.    \"%7C\"; \"%7D\"; \"%7E\" };\
  2808.    \n\
  2809.    \n  :for I from=0 to=([ :len \$Input ] - 1) do={\
  2810.    \n    :local Char [ :pick \$Input \$I ];\
  2811.    \n    :local Replace [ :find \$Chars \$Char ];\
  2812.    \n\
  2813.    \n    :if ([ :typeof \$Replace ] = \"num\") do={\
  2814.    \n      :set Char (\$Subs->\$Replace);\
  2815.    \n    }\
  2816.    \n    :set Return (\$Return . \$Char);\
  2817.    \n  }\
  2818.    \n\
  2819.    \n  :return \$Return;\
  2820.    \n}\
  2821.    \n\
  2822.    \n# basic syntax validation\
  2823.    \n:set ValidateSyntax do={\
  2824.    \n  :local Code [ :tostr \$1 ];\
  2825.    \n\
  2826.    \n  :do {\
  2827.    \n    [ :parse (\":local Validate do={\\n\" . \$Code . \"\\n}\") ];\
  2828.    \n  } on-error={\
  2829.    \n    :return false;\
  2830.    \n  }\
  2831.    \n  :return true;\
  2832.    \n}\
  2833.    \n\
  2834.    \n# convert version string to numeric value\
  2835.    \n:set VersionToNum do={\
  2836.    \n  :local Input [ :tostr \$1 ];\
  2837.    \n  :local Multi 0x1000000;\
  2838.    \n  :local Return 0;\
  2839.    \n\
  2840.    \n  :global CharacterReplace;\
  2841.    \n\
  2842.    \n  :set Input [ \$CharacterReplace \$Input \".\" \",\" ];\
  2843.    \n  :foreach I in={ \"alpha\"; \"beta\"; \"rc\" } do={\
  2844.    \n    :set Input [ \$CharacterReplace \$Input \$I (\",\" . \$I . \",\") ];\
  2845.    \n  }\
  2846.    \n\
  2847.    \n  :foreach Value in=([ :toarray \$Input ], 0) do={\
  2848.    \n    :local Num [ :tonum \$Value ];\
  2849.    \n    :if (\$Multi = 0x100) do={\
  2850.    \n      :if ([ :typeof \$Num ] = \"num\") do={\
  2851.    \n        :set Return (\$Return + 0xff00);\
  2852.    \n        :set Multi (\$Multi / 0x100);\
  2853.    \n      } else={\
  2854.    \n        :if (\$Value = \"alpha\") do={ :set Return (\$Return + 0x3f00); \
  2855.    }\
  2856.    \n        :if (\$Value = \"beta\") do={ :set Return (\$Return + 0x5f00); }\
  2857.    \n        :if (\$Value = \"rc\") do={ :set Return (\$Return + 0x7f00); }\
  2858.    \n      }\
  2859.    \n    }\
  2860.    \n    :if ([ :typeof \$Num ] = \"num\") do={ :set Return (\$Return + (\$Va\
  2861.    lue * \$Multi)); }\
  2862.    \n    :set Multi (\$Multi / 0x100);\
  2863.    \n  }\
  2864.    \n\
  2865.    \n  :return \$Return;\
  2866.    \n}\
  2867.    \n\
  2868.    \n# wait for default route to be reachable\
  2869.    \n:set WaitDefaultRouteReachable do={\
  2870.    \n  :global IsDefaultRouteReachable;\
  2871.    \n\
  2872.    \n  :while ([ \$IsDefaultRouteReachable ] = false) do={\
  2873.    \n    :delay 1s;\
  2874.    \n  }\
  2875.    \n}\
  2876.    \n\
  2877.    \n# wait for DNS to resolve\
  2878.    \n:set WaitDNSResolving do={\
  2879.    \n  :global IsDNSResolving;\
  2880.    \n\
  2881.    \n  :while ([ \$IsDNSResolving ] = false) do={\
  2882.    \n    :delay 1s;\
  2883.    \n  }\
  2884.    \n}\
  2885.    \n\
  2886.    \n# wait for file to be available\
  2887.    \n:set WaitForFile do={\
  2888.    \n  :local FileName [ :tostr  \$1 ];\
  2889.    \n  :local WaitTime [ :totime \$2 ];\
  2890.    \n\
  2891.    \n  :global CleanFilePath;\
  2892.    \n  :global EitherOr;\
  2893.    \n\
  2894.    \n  :set FileName [ \$CleanFilePath \$FileName ];\
  2895.    \n  :local I 1;\
  2896.    \n  :local Delay ([ :totime [ \$EitherOr \$WaitTime 2s ] ] / 20);\
  2897.    \n\
  2898.    \n  :while ([ :len [ /file/find where name=\$FileName ] ] = 0) do={\
  2899.    \n    :if (\$I >= 20) do={\
  2900.    \n      :return false;\
  2901.    \n    }\
  2902.    \n    :delay \$Delay;\
  2903.    \n    :set I (\$I + 1);\
  2904.    \n  }\
  2905.    \n  :return true;\
  2906.    \n}\
  2907.    \n\
  2908.    \n# wait to be fully connected (default route is reachable, time is sync, \
  2909.    DNS resolves)\
  2910.    \n:set WaitFullyConnected do={\
  2911.    \n  :global WaitDefaultRouteReachable;\
  2912.    \n  :global WaitDNSResolving;\
  2913.    \n  :global WaitTimeSync;\
  2914.    \n\
  2915.    \n  \$WaitDefaultRouteReachable;\
  2916.    \n  \$WaitTimeSync;\
  2917.    \n  \$WaitDNSResolving;\
  2918.    \n}\
  2919.    \n\
  2920.    \n# wait for time to become synced\
  2921.    \n:set WaitTimeSync do={\
  2922.    \n  :global IsTimeSync;\
  2923.    \n\
  2924.    \n  :while ([ \$IsTimeSync ] = false) do={\
  2925.    \n    :delay 1s;\
  2926.    \n  }\
  2927.    \n}\
  2928.    \n\
  2929.    \n# load modules\
  2930.    \n:foreach Script in=[ /system/script/find where name ~ \"^mod/.\" ] do={\
  2931.    \n  :local ScriptVal [ /system/script/get \$Script ];\
  2932.    \n  :if ([ \$ValidateSyntax (\$ScriptVal->\"source\") ] = true) do={\
  2933.    \n    :do {\
  2934.    \n      /system/script/run \$Script;\
  2935.    \n    } on-error={\
  2936.    \n      \$LogPrintExit2 error \$0 (\"Module '\" . \$ScriptVal->\"name\" . \
  2937.    \"' failed to run.\") false;\
  2938.    \n    }\
  2939.    \n  } else={\
  2940.    \n    \$LogPrintExit2 error \$0 (\"Module '\" . \$ScriptVal->\"name\" . \"\
  2941.    ' failed syntax validation, skipping.\") false;\
  2942.    \n  }\
  2943.    \n}\
  2944.    \n\
  2945.    \n# signal we are ready\
  2946.    \n:set GlobalFunctionsReady true;\
  2947.    \n"
  2948. add dont-require-permissions=no name=check-certificates owner=\
  2949.     check-certificates policy=\
  2950.     ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\
  2951.    !rsc by RouterOS\
  2952.    \n# RouterOS script: check-certificates\
  2953.    \n# Copyright (c) 2013-2024 Christian Hesse <mail@eworm.de>\
  2954.    \n# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md\
  2955.    \n#\
  2956.    \n# check for certificate validity\
  2957.    \n# https://git.eworm.de/cgit/routeros-scripts/about/doc/check-certificate\
  2958.    s.md\
  2959.    \n\
  2960.    \n:local 0 \"check-certificates\";\
  2961.    \n:global GlobalFunctionsReady;\
  2962.    \n:while (\$GlobalFunctionsReady != true) do={ :delay 500ms; }\
  2963.    \n\
  2964.    \n:global CertRenewTime;\
  2965.    \n:global CertRenewUrl;\
  2966.    \n:global CertWarnTime;\
  2967.    \n:global Identity;\
  2968.    \n\
  2969.    \n:global CertificateAvailable\
  2970.    \n:global EscapeForRegEx;\
  2971.    \n:global IfThenElse;\
  2972.    \n:global LogPrintExit2;\
  2973.    \n:global ParseKeyValueStore;\
  2974.    \n:global ScriptLock;\
  2975.    \n:global SendNotification2;\
  2976.    \n:global SymbolForNotification;\
  2977.    \n:global UrlEncode;\
  2978.    \n:global WaitFullyConnected;\
  2979.    \n\
  2980.    \n:local CheckCertificatesDownloadImport do={\
  2981.    \n  :local Name [ :tostr \$1 ];\
  2982.    \n\
  2983.    \n  :global CertRenewUrl;\
  2984.    \n  :global CertRenewPass;\
  2985.    \n\
  2986.    \n  :global CertificateNameByCN;\
  2987.    \n  :global EscapeForRegEx;\
  2988.    \n  :global LogPrintExit2;\
  2989.    \n  :global UrlEncode;\
  2990.    \n  :global WaitForFile;\
  2991.    \n\
  2992.    \n  :local Return false;\
  2993.    \n\
  2994.    \n  :foreach Type in={ \".pem\"; \".p12\" } do={\
  2995.    \n    :local CertFileName ([ \$UrlEncode \$Name ] . \$Type);\
  2996.    \n    :do {\
  2997.    \n      /tool/fetch check-certificate=yes-without-crl \\\
  2998.    \n          (\$CertRenewUrl . \$CertFileName) dst-path=\$CertFileName as-v\
  2999.    alue;\
  3000.    \n      \$WaitForFile \$CertFileName;\
  3001.    \n\
  3002.    \n      :local DecryptionFailed true;\
  3003.    \n      :foreach PassPhrase in=\$CertRenewPass do={\
  3004.    \n        :local Result [ /certificate/import file-name=\$CertFileName pas\
  3005.    sphrase=\$PassPhrase as-value ];\
  3006.    \n        :if (\$Result->\"decryption-failures\" = 0) do={\
  3007.    \n          :set DecryptionFailed false;\
  3008.    \n        }\
  3009.    \n      }\
  3010.    \n      /file/remove [ find where name=\$CertFileName ];\
  3011.    \n\
  3012.    \n      :if (\$DecryptionFailed = true) do={\
  3013.    \n        \$LogPrintExit2 warning \$0 (\"Decryption failed for certificate\
  3014.    \_file \" . \$CertFileName) false;\
  3015.    \n      }\
  3016.    \n\
  3017.    \n      :foreach CertInChain in=[ /certificate/find where name~(\"^\" . [ \
  3018.    \$EscapeForRegEx \$CertFileName ] . \"_[0-9]+\\\$\") \\\
  3019.    \n          common-name!=\$Name !(subject-alt-name~(\"(^|\\\\W)(DNS|IP):\"\
  3020.    \_. [ \$EscapeForRegEx \$Name ] . \"(\\\\W|\\\$)\")) !(common-name=[]) ] d\
  3021.    o={\
  3022.    \n        \$CertificateNameByCN [ /certificate/get \$CertInChain common-na\
  3023.    me ];\
  3024.    \n      }\
  3025.    \n\
  3026.    \n      :set Return true;\
  3027.    \n    } on-error={\
  3028.    \n      \$LogPrintExit2 debug \$0 (\"Could not download certificate file \
  3029.    \" . \$CertFileName) false;\
  3030.    \n    }\
  3031.    \n  }\
  3032.    \n\
  3033.    \n  :return \$Return;\
  3034.    \n}\
  3035.    \n\
  3036.    \n:local FormatInfo do={\
  3037.    \n  :local Cert \$1;\
  3038.    \n\
  3039.    \n  :global FormatLine;\
  3040.    \n  :global FormatMultiLines;\
  3041.    \n  :global IfThenElse;\
  3042.    \n\
  3043.    \n  :local FormatExpire do={\
  3044.    \n    :global CharacterReplace;\
  3045.    \n    :return [ \$CharacterReplace [ \$CharacterReplace [ :tostr \$1 ] \"w\
  3046.    \" \"w \" ] \"d\" \"d \" ];\
  3047.    \n  }\
  3048.    \n\
  3049.    \n  :local FormatCertChain do={\
  3050.    \n    :local Cert \$1;\
  3051.    \n\
  3052.    \n    :global EitherOr;\
  3053.    \n    :global ParseKeyValueStore;\
  3054.    \n\
  3055.    \n    :local CertVal [ /certificate/get \$Cert ];\
  3056.    \n    :local Return \"\";\
  3057.    \n\
  3058.    \n    :for I from=0 to=5 do={\
  3059.    \n      :set Return (\$Return . [ \$EitherOr ([ \$ParseKeyValueStore (\$Ce\
  3060.    rtVal->\"issuer\") ]->\"CN\") \\\
  3061.    \n        ([ \$ParseKeyValueStore ((\$CertVal->\"issuer\")->0) ]->\"CN\") \
  3062.    ]);\
  3063.    \n      :set CertVal [ /certificate/get [ find where skid=(\$CertVal->\"ak\
  3064.    id\") ] ];\
  3065.    \n      :if ((\$CertVal->\"akid\") = \"\" || (\$CertVal->\"akid\") = (\$Ce\
  3066.    rtVal->\"skid\")) do={\
  3067.    \n        :return \$Return;\
  3068.    \n      }\
  3069.    \n      :set Return (\$Return . \" -> \");\
  3070.    \n    }\
  3071.    \n    :return (\$Return . \"...\");\
  3072.    \n  }\
  3073.    \n\
  3074.    \n  :local CertVal [ /certificate/get \$Cert ];\
  3075.    \n\
  3076.    \n  :return ( \\\
  3077.    \n    [ \$FormatLine \"Name\" (\$CertVal->\"name\") ] . \"\\n\" . \\\
  3078.    \n    [ \$IfThenElse ([ :len (\$CertVal->\"common-name\") ] > 0) ([ \$Form\
  3079.    atLine \"CommonName\" (\$CertVal->\"common-name\") ] . \"\\n\") ] . \\\
  3080.    \n    [ \$IfThenElse ([ :len (\$CertVal->\"subject-alt-name\") ] > 0) ([ \
  3081.    \$FormatMultiLines \"SubjectAltNames\" (\$CertVal->\"subject-alt-name\") ]\
  3082.    \_. \"\\n\") ] . \\\
  3083.    \n    [ \$FormatLine \"Private key\" [ \$IfThenElse ((\$CertVal->\"private\
  3084.    -key\") = true) \"available\" \"missing\" ] ] . \"\\n\" . \\\
  3085.    \n    [ \$FormatLine \"Fingerprint\" (\$CertVal->\"fingerprint\") ] . \"\\\
  3086.    n\" . \\\
  3087.    \n    [ \$IfThenElse ([ :len (\$CertVal->\"ca\") ] > 0) [ \$FormatLine \"I\
  3088.    ssuer\" (\$CertVal->\"ca\") ] [ \$FormatLine \"Issuer chain\" [ \$FormatCe\
  3089.    rtChain \$Cert ] ] ] . \"\\n\" . \\\
  3090.    \n    \"Validity:\\n\" . \\\
  3091.    \n    [ \$FormatLine \"    from\" (\$CertVal->\"invalid-before\") ] . \"\\\
  3092.    n\" . \\\
  3093.    \n    [ \$FormatLine \"    to\" (\$CertVal->\"invalid-after\") ] . \"\\n\"\
  3094.    \_. \\\
  3095.    \n    [ \$FormatLine \"Expires in\" [ \$IfThenElse ((\$CertVal->\"expired\
  3096.    \") = true) \"expired\" [ \$FormatExpire (\$CertVal->\"expires-after\") ] \
  3097.    ] ]);\
  3098.    \n}\
  3099.    \n\
  3100.    \n\$ScriptLock \$0;\
  3101.    \n\$WaitFullyConnected;\
  3102.    \n\
  3103.    \n:foreach Cert in=[ /certificate/find where !revoked !ca !scep-url expire\
  3104.    s-after<\$CertRenewTime ] do={\
  3105.    \n  :local CertVal [ /certificate/get \$Cert ];\
  3106.    \n  :local CertNew;\
  3107.    \n  :local LastName;\
  3108.    \n\
  3109.    \n  :do {\
  3110.    \n    :if ([ :len \$CertRenewUrl ] = 0) do={\
  3111.    \n      \$LogPrintExit2 info \$0 (\"No CertRenewUrl given.\") true;\
  3112.    \n    }\
  3113.    \n    \$LogPrintExit2 info \$0 (\"Attempting to renew certificate \" . (\$\
  3114.    CertVal->\"name\") . \".\") false;\
  3115.    \n\
  3116.    \n    :local ImportSuccess false;\
  3117.    \n    :set LastName (\$CertVal->\"common-name\");\
  3118.    \n    :set ImportSuccess [ \$CheckCertificatesDownloadImport \$LastName ];\
  3119.    \n    :foreach SAN in=(\$CertVal->\"subject-alt-name\") do={\
  3120.    \n      :if (\$ImportSuccess = false) do={\
  3121.    \n        :set LastName [ :pick \$SAN ([ :find \$SAN \":\" ] + 1) [ :len \
  3122.    \$SAN ] ];\
  3123.    \n        :set ImportSuccess [ \$CheckCertificatesDownloadImport \$LastNam\
  3124.    e ];\
  3125.    \n      }\
  3126.    \n    }\
  3127.    \n\
  3128.    \n    :if ([ :len (\$CertVal->\"fingerprint\") ] > 0 && \$CertVal->\"finge\
  3129.    rprint\" != [ /certificate/get \$Cert fingerprint ]) do={\
  3130.    \n      \$LogPrintExit2 debug \$0 (\"Certificate '\" . \$CertVal->\"name\"\
  3131.    \_. \"' was updated in place.\") false;\
  3132.    \n      :set CertVal [ /certificate/get \$Cert ];\
  3133.    \n    } else={\
  3134.    \n      \$LogPrintExit2 debug \$0 (\"Certificate '\" . \$CertVal->\"name\"\
  3135.    \_. \"' was not updated, but replaced.\") false;\
  3136.    \n\
  3137.    \n      :set CertNew [ /certificate/find where name~(\"^\" . [ \$EscapeFor\
  3138.    RegEx [ \$UrlEncode \$LastName ] ] . \"\\\\.(p12|pem)_[0-9]+\\\$\") \\\
  3139.    \n        (common-name=(\$CertVal->\"common-name\") or subject-alt-name~(\
  3140.    \"(^|\\\\W)(DNS|IP):\" . [ \$EscapeForRegEx \$LastName ] . \"(\\\\W|\\\$)\
  3141.    \")) \\\
  3142.    \n        fingerprint!=[ :tostr (\$CertVal->\"fingerprint\") ] expires-aft\
  3143.    er>\$CertRenewTime ];\
  3144.    \n      :local CertNewVal [ /certificate/get \$CertNew ];\
  3145.    \n\
  3146.    \n      :if ([ \$CertificateAvailable ([ \$ParseKeyValueStore (\$CertNewVa\
  3147.    l->\"issuer\") ]->\"CN\") ] = false) do={\
  3148.    \n        \$LogPrintExit2 warning \$0 (\"The certificate chain is not avai\
  3149.    lable!\") false;\
  3150.    \n      }\
  3151.    \n\
  3152.    \n      :if ((\$CertVal->\"private-key\") = true && (\$CertVal->\"private-\
  3153.    key\") != (\$CertNewVal->\"private-key\")) do={\
  3154.    \n        /certificate/remove \$CertNew;\
  3155.    \n        \$LogPrintExit2 warning \$0 (\"Old certificate '\" . (\$CertVal-\
  3156.    >\"name\") . \"' has a private key, new certificate does not. Aborting ren\
  3157.    ew.\") true;\
  3158.    \n      }\
  3159.    \n\
  3160.    \n      /ip/service/set certificate=(\$CertNewVal->\"name\") [ find where \
  3161.    certificate=(\$CertVal->\"name\") ];\
  3162.    \n\
  3163.    \n      /ip/ipsec/identity/set certificate=(\$CertNewVal->\"name\") [ find\
  3164.    \_where certificate=(\$CertVal->\"name\") ];\
  3165.    \n      /ip/ipsec/identity/set remote-certificate=(\$CertNewVal->\"name\")\
  3166.    \_[ find where remote-certificate=(\$CertVal->\"name\") ];\
  3167.    \n\
  3168.    \n      /ip/hotspot/profile/set ssl-certificate=(\$CertNewVal->\"name\") [\
  3169.    \_find where ssl-certificate=(\$CertVal->\"name\") ];\
  3170.    \n\
  3171.    \n      /certificate/remove \$Cert;\
  3172.    \n      /certificate/set \$CertNew name=(\$CertVal->\"name\");\
  3173.    \n      :set CertNewVal;\
  3174.    \n      :set CertVal [ /certificate/get \$CertNew ];\
  3175.    \n    }\
  3176.    \n\
  3177.    \n    \$SendNotification2 ({ origin=\$0; silent=true; \\\
  3178.    \n      subject=([ \$SymbolForNotification \"lock-with-ink-pen\" ] . \"Cer\
  3179.    tificate renewed: \" . (\$CertVal->\"name\")); \\\
  3180.    \n      message=(\"A certificate on \" . \$Identity . \" has been renewed.\
  3181.    \\n\\n\" . [ \$FormatInfo \$CertNew ]) });\
  3182.    \n    \$LogPrintExit2 info \$0 (\"The certificate \" . (\$CertVal->\"name\
  3183.    \") . \" has been renewed.\") false;\
  3184.    \n  } on-error={\
  3185.    \n    \$LogPrintExit2 debug \$0 (\"Could not renew certificate \" . (\$Cer\
  3186.    tVal->\"name\") . \".\") false;\
  3187.    \n  }\
  3188.    \n}\
  3189.    \n\
  3190.    \n:foreach Cert in=[ /certificate/find where !revoked !scep-url !(expires-\
  3191.    after=[]) \\\
  3192.    \n                   expires-after<\$CertWarnTime !(fingerprint=[]) ] do={\
  3193.    \n  :local CertVal [ /certificate/get \$Cert ];\
  3194.    \n\
  3195.    \n  :if ([ :len [ /certificate/scep-server/find where ca-cert=(\$CertVal->\
  3196.    \"ca\") ] ] > 0) do={\
  3197.    \n    \$LogPrintExit2 debug \$0 (\"Certificate \\\"\" . (\$CertVal->\"name\
  3198.    \") . \"\\\" is handled by SCEP, skipping.\") false;\
  3199.    \n  } else={\
  3200.    \n    :local State [ \$IfThenElse ((\$CertVal->\"expired\") = true) \"expi\
  3201.    red\" \"is about to expire\" ];\
  3202.    \n\
  3203.    \n    \$SendNotification2 ({ origin=\$0; \\\
  3204.    \n      subject=([ \$SymbolForNotification \"warning-sign\" ] . \"Certific\
  3205.    ate warning: \" . (\$CertVal->\"name\")); \\\
  3206.    \n      message=(\"A certificate on \" . \$Identity . \" \" . \$State . \"\
  3207.    .\\n\\n\" . [ \$FormatInfo \$Cert ]) });\
  3208.    \n    \$LogPrintExit2 info \$0 (\"The certificate \" . (\$CertVal->\"name\
  3209.    \") . \" \" . \$State . \\\
  3210.    \n        \", it is invalid after \" . (\$CertVal->\"invalid-after\") . \"\
  3211.    .\") false;\
  3212.    \n  }\
  3213.    \n}\
  3214.    \n"
  3215. add dont-require-permissions=no name=check-routeros-update owner=\
  3216.     check-routeros-update policy=\
  3217.     ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\
  3218.    !rsc by RouterOS\
  3219.    \n# RouterOS script: check-routeros-update\
  3220.    \n# Copyright (c) 2013-2024 Christian Hesse <mail@eworm.de>\
  3221.    \n# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md\
  3222.    \n#\
  3223.    \n# check for RouterOS update, send notification and/or install\
  3224.    \n# https://git.eworm.de/cgit/routeros-scripts/about/doc/check-routeros-up\
  3225.    date.md\
  3226.    \n\
  3227.    \n:local 0 \"check-routeros-update\";\
  3228.    \n:global GlobalFunctionsReady;\
  3229.    \n:while (\$GlobalFunctionsReady != true) do={ :delay 500ms; }\
  3230.    \n\
  3231.    \n:global Identity;\
  3232.    \n:global SafeUpdateAll;\
  3233.    \n:global SafeUpdateNeighbor;\
  3234.    \n:global SafeUpdateNeighborIdentity;\
  3235.    \n:global SafeUpdatePatch;\
  3236.    \n:global SafeUpdateUrl;\
  3237.    \n:global SentRouterosUpdateNotification;\
  3238.    \n\
  3239.    \n:global DeviceInfo;\
  3240.    \n:global EscapeForRegEx;\
  3241.    \n:global LogPrintExit2;\
  3242.    \n:global ScriptFromTerminal;\
  3243.    \n:global ScriptLock;\
  3244.    \n:global SendNotification2;\
  3245.    \n:global SymbolForNotification;\
  3246.    \n:global VersionToNum;\
  3247.    \n:global WaitFullyConnected;\
  3248.    \n\
  3249.    \n:local DoUpdate do={\
  3250.    \n  :if ([ :len [ /system/script/find where name=\"packages-update\" ] ] >\
  3251.    \_0) do={\
  3252.    \n    /system/script/run packages-update;\
  3253.    \n  } else={\
  3254.    \n    /system/package/update/install without-paging;\
  3255.    \n  }\
  3256.    \n  :error \"Waiting for system to reboot.\";\
  3257.    \n}\
  3258.    \n\
  3259.    \n\$ScriptLock \$0;\
  3260.    \n\
  3261.    \n\$WaitFullyConnected;\
  3262.    \n\
  3263.    \n:if ([ :len [ /system/scheduler/find where name=\"_RebootForUpdate\" ] ]\
  3264.    \_> 0) do={\
  3265.    \n  :error \"A reboot for update is already scheduled.\";\
  3266.    \n}\
  3267.    \n\
  3268.    \n\$LogPrintExit2 debug \$0 (\"Checking for updates...\") false;\
  3269.    \n/system/package/update/check-for-updates without-paging as-value;\
  3270.    \n:local Update [ /system/package/update/get ];\
  3271.    \n\
  3272.    \n:if ([ \$ScriptFromTerminal \$0 ] = true && (\$Update->\"installed-versi\
  3273.    on\") = (\$Update->\"latest-version\")) do={\
  3274.    \n  \$LogPrintExit2 info \$0 (\"System is already up to date.\") true;\
  3275.    \n}\
  3276.    \n\
  3277.    \n:local NumInstalled [ \$VersionToNum (\$Update->\"installed-version\") ]\
  3278.    ;\
  3279.    \n:local NumLatest [ \$VersionToNum (\$Update->\"latest-version\") ];\
  3280.    \n:local Link (\"https://mikrotik.com/download/changelogs/\" . \$Update->\
  3281.    \"channel\" . \"-release-tree\");\
  3282.    \n\
  3283.    \n:if (\$NumLatest < 117505792) do={\
  3284.    \n  \$LogPrintExit2 info \$0 (\"The version '\" . (\$Update->\"latest-vers\
  3285.    ion\") . \"' is not a valid version.\") true;\
  3286.    \n}\
  3287.    \n\
  3288.    \n:if (\$NumInstalled < \$NumLatest) do={\
  3289.    \n  :if (\$SafeUpdateAll ~ \"^YES,\? \?PLEASE!\?\\\$\") do={\
  3290.    \n    \$LogPrintExit2 info \$0 (\"Installing ALL versions automatically, i\
  3291.    ncluding \" . \\\
  3292.    \n      \$Update->\"latest-version\" . \"...\") false;\
  3293.    \n    \$SendNotification2 ({ origin=\$0; \\\
  3294.    \n      subject=([ \$SymbolForNotification \"sparkles\" ] . \"RouterOS upd\
  3295.    ate: \" . \$Update->\"latest-version\"); \\\
  3296.    \n      message=(\"Installing ALL versions automatically, including \" . \
  3297.    \$Update->\"latest-version\" . \\\
  3298.    \n        \"... Updating on \" . \$Identity . \"...\"); link=\$Link; silen\
  3299.    t=true });\
  3300.    \n    \$DoUpdate;\
  3301.    \n  }\
  3302.    \n\
  3303.    \n  :if (\$SafeUpdatePatch = true && (\$NumInstalled & 0xffff0000) = (\$Nu\
  3304.    mLatest & 0xffff0000)) do={\
  3305.    \n    \$LogPrintExit2 info \$0 (\"Version \" . \$Update->\"latest-version\
  3306.    \" . \" is a patch release, updating...\") false;\
  3307.    \n    \$SendNotification2 ({ origin=\$0; \\\
  3308.    \n      subject=([ \$SymbolForNotification \"sparkles\" ] . \"RouterOS upd\
  3309.    ate: \" . \$Update->\"latest-version\"); \\\
  3310.    \n      message=(\"Version \" . \$Update->\"latest-version\" . \" is a pat\
  3311.    ch update for \" . \$Update->\"channel\" . \\\
  3312.    \n        \", updating on \" . \$Identity . \"...\"); link=\$Link; silent=\
  3313.    true });\
  3314.    \n    \$DoUpdate;\
  3315.    \n  }\
  3316.    \n\
  3317.    \n  :if (\$SafeUpdateNeighbor = true) do={\
  3318.    \n    :local Neighbors [ /ip/neighbor/find where platform=\"MikroTik\" ide\
  3319.    ntity~\$SafeUpdateNeighborIdentity \\\
  3320.    \n       version~(\"^\" . [ \$EscapeForRegEx (\$Update->\"latest-version\"\
  3321.    ) ] . \"\\\\b\") ];\
  3322.    \n    :if ([ :len \$Neighbors ] > 0) do={\
  3323.    \n      :local Neighbor [ /ip/neighbor/get (\$Neighbors->0) identity ];\
  3324.    \n      \$LogPrintExit2 info \$0 (\"Seen a neighbor (\" . \$Neighbor . \")\
  3325.    \_running version \" . \\\
  3326.    \n        \$Update->\"latest-version\" . \" from \" . \$Update->\"channel\
  3327.    \" . \", updating...\") false;\
  3328.    \n      \$SendNotification2 ({ origin=\$0; \\\
  3329.    \n        subject=([ \$SymbolForNotification \"sparkles\" ] . \"RouterOS u\
  3330.    pdate: \" . \$Update->\"latest-version\"); \\\
  3331.    \n        message=(\"Seen a neighbor (\" . \$Neighbor . \") running versio\
  3332.    n \" . \$Update->\"latest-version\" . \\\
  3333.    \n          \" from \" . \$Update->\"channel\" . \", updating on \" . \$Id\
  3334.    entity . \"...\"); link=\$Link; silent=true });\
  3335.    \n      \$DoUpdate;\
  3336.    \n    }\
  3337.    \n  }\
  3338.    \n\
  3339.    \n  :if ([ :len \$SafeUpdateUrl ] > 0) do={\
  3340.    \n    :local Result;\
  3341.    \n    :do {\
  3342.    \n      :set Result [ /tool/fetch check-certificate=yes-without-crl \\\
  3343.    \n          (\$SafeUpdateUrl . \$Update->\"channel\" . \"\?installed=\" . \
  3344.    \$Update->\"installed-version\" . \\\
  3345.    \n          \"&latest=\" . \$Update->\"latest-version\") output=user as-va\
  3346.    lue ];\
  3347.    \n    } on-error={\
  3348.    \n      \$LogPrintExit2 warning \$0 (\"Failed receiving safe version for \
  3349.    \" . \$Update->\"channel\" . \".\") false;\
  3350.    \n    }\
  3351.    \n    :if (\$Result->\"status\" = \"finished\" && \$Result->\"data\" = \$U\
  3352.    pdate->\"latest-version\") do={\
  3353.    \n      \$LogPrintExit2 info \$0 (\"Version \" . \$Update->\"latest-versio\
  3354.    n\" . \" is considered safe, updating...\") false;\
  3355.    \n      \$SendNotification2 ({ origin=\$0; \\\
  3356.    \n        subject=([ \$SymbolForNotification \"sparkles\" ] . \"RouterOS u\
  3357.    pdate: \" . \$Update->\"latest-version\"); \\\
  3358.    \n        message=(\"Version \" . \$Update->\"latest-version\" . \" is con\
  3359.    sidered safe for \" . \$Update->\"channel\" . \\\
  3360.    \n          \", updating on \" . \$Identity . \"...\"); link=\$Link; silen\
  3361.    t=true });\
  3362.    \n      \$DoUpdate;\
  3363.    \n    }\
  3364.    \n  }\
  3365.    \n\
  3366.    \n  :if ([ \$ScriptFromTerminal \$0 ] = true) do={\
  3367.    \n    :put (\"Do you want to install RouterOS version \" . \$Update->\"lat\
  3368.    est-version\" . \"\? [y/N]\");\
  3369.    \n    :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={\
  3370.    \n      \$DoUpdate;\
  3371.    \n    } else={\
  3372.    \n      :put \"Canceled...\";\
  3373.    \n    }\
  3374.    \n  }\
  3375.    \n\
  3376.    \n  :if (\$SentRouterosUpdateNotification = \$Update->\"latest-version\") \
  3377.    do={\
  3378.    \n    \$LogPrintExit2 info \$0 (\"Already sent the RouterOS update notific\
  3379.    ation for version \" . \\\
  3380.    \n        \$Update->\"latest-version\" . \".\") true;\
  3381.    \n  }\
  3382.    \n\
  3383.    \n  \$SendNotification2 ({ origin=\$0; \\\
  3384.    \n    subject=([ \$SymbolForNotification \"sparkles\" ] . \"RouterOS updat\
  3385.    e: \" . \$Update->\"latest-version\"); \\\
  3386.    \n    message=(\"A new RouterOS version \" . (\$Update->\"latest-version\"\
  3387.    ) . \\\
  3388.    \n      \" is available for \" . \$Identity . \".\\n\\n\" . \\\
  3389.    \n      [ \$DeviceInfo ]); link=\$Link; silent=true });\
  3390.    \n  :set SentRouterosUpdateNotification (\$Update->\"latest-version\");\
  3391.    \n}\
  3392.    \n\
  3393.    \n:if (\$NumInstalled > \$NumLatest) do={\
  3394.    \n  :if (\$SentRouterosUpdateNotification = \$Update->\"latest-version\") \
  3395.    do={\
  3396.    \n    \$LogPrintExit2 info \$0 (\"Already sent the RouterOS downgrade noti\
  3397.    fication for version \" . \\\
  3398.    \n        \$Update->\"latest-version\" . \".\") true;\
  3399.    \n  }\
  3400.    \n\
  3401.    \n  \$SendNotification2 ({ origin=\$0; \\\
  3402.    \n    subject=([ \$SymbolForNotification \"warning-sign\" ] . \"RouterOS v\
  3403.    ersion: \" . \$Update->\"latest-version\"); \\\
  3404.    \n    message=(\"A different RouterOS version \" . (\$Update->\"latest-ver\
  3405.    sion\") . \\\
  3406.    \n      \" is available for \" . \$Identity . \", but it is a downgrade.\\\
  3407.    n\\n\" . \\\
  3408.    \n      [ \$DeviceInfo ]); link=\$Link; silent=true });\
  3409.    \n  \$LogPrintExit2 info \$0 (\"A different RouterOS version \" . (\$Updat\
  3410.    e->\"latest-version\") . \\\
  3411.    \n    \" is available for downgrade.\") false;\
  3412.    \n  :set SentRouterosUpdateNotification (\$Update->\"latest-version\");\
  3413.    \n}\
  3414.    \n"
  3415. add dont-require-permissions=no name=dhcp-to-dns owner=dhcp-to-dns policy=\
  3416.     ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\
  3417.    !rsc by RouterOS\
  3418.    \n# RouterOS script: dhcp-to-dns\
  3419.    \n# Copyright (c) 2013-2024 Christian Hesse <mail@eworm.de>\
  3420.    \n# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md\
  3421.    \n#\
  3422.    \n# provides: lease-script, order=20\
  3423.    \n#\
  3424.    \n# check DHCP leases and add/remove/update DNS entries\
  3425.    \n# https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-to-dns.md\
  3426.    \n\
  3427.    \n:local 0 \"dhcp-to-dns\";\
  3428.    \n:global GlobalFunctionsReady;\
  3429.    \n:while (\$GlobalFunctionsReady != true) do={ :delay 500ms; }\
  3430.    \n\
  3431.    \n:global Domain;\
  3432.    \n:global Identity;\
  3433.    \n\
  3434.    \n:global CharacterReplace;\
  3435.    \n:global EitherOr;\
  3436.    \n:global IfThenElse;\
  3437.    \n:global LogPrintExit2;\
  3438.    \n:global LogPrintOnce;\
  3439.    \n:global ParseKeyValueStore;\
  3440.    \n:global ScriptLock;\
  3441.    \n\
  3442.    \n\$ScriptLock \$0 false 10;\
  3443.    \n\
  3444.    \n:local Ttl 5m;\
  3445.    \n:local CommentPrefix (\"managed by \" . \$0);\
  3446.    \n:local CommentString (\"--- \" . \$0 . \" above ---\");\
  3447.    \n\
  3448.    \n:if ([ :len [ /ip/dns/static/find where (name=\$CommentString or (commen\
  3449.    t=\$CommentString and name=-)) type=NXDOMAIN disabled ] ] = 0) do={\
  3450.    \n  /ip/dns/static/add name=\$CommentString type=NXDOMAIN disabled=yes;\
  3451.    \n  \$LogPrintExit2 warning \$0 (\"Added disabled static dns record with n\
  3452.    ame '\" . \$CommentString . \"'.\") false;\
  3453.    \n}\
  3454.    \n:local PlaceBefore ([ /ip/dns/static/find where (name=\$CommentString or\
  3455.    \_(comment=\$CommentString and name=-)) type=NXDOMAIN disabled ]->0);\
  3456.    \n\
  3457.    \n:foreach DnsRecord in=[ /ip/dns/static/find where comment~(\"^\" . \$Com\
  3458.    mentPrefix . \"\\\\b\") (!type or type=A) ] do={\
  3459.    \n  :local DnsRecordVal [ /ip/dns/static/get \$DnsRecord ];\
  3460.    \n  :local DnsRecordInfo [ \$ParseKeyValueStore (\$DnsRecordVal->\"comment\
  3461.    \") ];\
  3462.    \n  :local MacInServer (\$DnsRecordInfo->\"macaddress\" . \" in \" . \$Dns\
  3463.    RecordInfo->\"server\");\
  3464.    \n\
  3465.    \n  :if ([ :len [ /ip/dhcp-server/lease/find where active-mac-address=(\$D\
  3466.    nsRecordInfo->\"macaddress\") \\\
  3467.    \n       active-address=(\$DnsRecordVal->\"address\") server=(\$DnsRecordI\
  3468.    nfo->\"server\") status=bound ] ] > 0) do={\
  3469.    \n    \$LogPrintExit2 debug \$0 (\"Lease for \" . \$MacInServer . \" (\" .\
  3470.    \_\$DnsRecordVal->\"name\" . \") still exists. Not deleting record.\") fal\
  3471.    se;\
  3472.    \n  } else={\
  3473.    \n    :local Found false;\
  3474.    \n    \$LogPrintExit2 info \$0 (\"Lease expired for \" . \$MacInServer . \
  3475.    \", deleting record (\" . \$DnsRecordVal->\"name\" . \").\") false;\
  3476.    \n    /ip/dns/static/remove \$DnsRecord;\
  3477.    \n    /ip/dns/static/remove [ find where type=CNAME comment=(\$DnsRecordVa\
  3478.    l->\"comment\") ];\
  3479.    \n  }\
  3480.    \n}\
  3481.    \n\
  3482.    \n:foreach Lease in=[ /ip/dhcp-server/lease/find where status=bound ] do={\
  3483.    \n  :local LeaseVal;\
  3484.    \n  :do {\
  3485.    \n    :set LeaseVal [ /ip/dhcp-server/lease/get \$Lease ];\
  3486.    \n    :if ([ :len [ /ip/dhcp-server/lease/find where active-mac-address=(\
  3487.    \$LeaseVal->\"active-mac-address\") status=bound ] ] > 1) do={\
  3488.    \n      \$LogPrintOnce info \$0 (\"Multiple bound leases found for mac-add\
  3489.    ress \" . (\$LeaseVal->\"active-mac-address\") . \"!\");\
  3490.    \n    }\
  3491.    \n  } on-error={\
  3492.    \n    \$LogPrintExit2 debug \$0 (\"A lease just vanished, ignoring.\") fal\
  3493.    se;\
  3494.    \n  }\
  3495.    \n\
  3496.    \n  :if ([ :len (\$LeaseVal->\"active-address\") ] > 0) do={\
  3497.    \n    :local Comment (\$CommentPrefix . \", macaddress=\" . \$LeaseVal->\"\
  3498.    active-mac-address\" . \", server=\" . \$LeaseVal->\"server\");\
  3499.    \n    :local MacDash [ \$CharacterReplace (\$LeaseVal->\"active-mac-addres\
  3500.    s\") \":\" \"-\" ];\
  3501.    \n    :local HostName [ \$CharacterReplace [ \$EitherOr ([ \$ParseKeyValue\
  3502.    Store (\$LeaseVal->\"comment\") ]->\"hostname\") (\$LeaseVal->\"host-name\
  3503.    \") ] \" \" \"\" ];\
  3504.    \n    :local Network [ /ip/dhcp-server/network/find where (\$LeaseVal->\"a\
  3505.    ctive-address\") in address ];\
  3506.    \n    :local NetworkVal;\
  3507.    \n    :if ([ :len \$Network ] > 0) do={\
  3508.    \n      :set NetworkVal [ /ip/dhcp-server/network/get (\$Network->0) ];\
  3509.    \n    }\
  3510.    \n    :local NetworkInfo [ \$ParseKeyValueStore (\$NetworkVal->\"comment\"\
  3511.    ) ];\
  3512.    \n    :local NetDomain ([ \$IfThenElse ([ :len (\$NetworkInfo->\"name-extr\
  3513.    a\") ] > 0) (\$NetworkInfo->\"name-extra\" . \".\") ] . \\\
  3514.    \n      [ \$EitherOr [ \$EitherOr (\$NetworkInfo->\"domain\") (\$NetworkVa\
  3515.    l->\"domain\") ] \$Domain ]);\
  3516.    \n    :local FullA (\$MacDash . \".\" . \$NetDomain);\
  3517.    \n    :local FullCN (\$HostName . \".\" . \$NetDomain);\
  3518.    \n    :local MacInServer (\$LeaseVal->\"active-mac-address\" . \" in \" . \
  3519.    \$LeaseVal->\"server\");\
  3520.    \n\
  3521.    \n    :local DnsRecord [ /ip/dns/static/find where comment=\$Comment (!typ\
  3522.    e or type=A) ];\
  3523.    \n    :if ([ :len \$DnsRecord ] > 0) do={\
  3524.    \n      :local DnsRecordVal [ /ip/dns/static/get \$DnsRecord ];\
  3525.    \n\
  3526.    \n      :if (\$DnsRecordVal->\"address\" = \$LeaseVal->\"active-address\" \
  3527.    && \$DnsRecordVal->\"name\" = \$FullA) do={\
  3528.    \n        \$LogPrintExit2 debug \$0 (\"The A record for \" . \$MacInServer\
  3529.    \_. \" (\" . \$FullA . \") does not need updating.\") false;\
  3530.    \n      } else={\
  3531.    \n        \$LogPrintExit2 info \$0 (\"Updating A record for \" . \$MacInSe\
  3532.    rver . \" (\" . \$FullA . \" -> \" . \$LeaseVal->\"active-address\" . \").\
  3533.    \") false;\
  3534.    \n        /ip/dns/static/set address=(\$LeaseVal->\"active-address\") name\
  3535.    =\$FullA \$DnsRecord;\
  3536.    \n      }\
  3537.    \n\
  3538.    \n      :local CName [ /ip/dns/static/find where comment=\$Comment type=CN\
  3539.    AME ];\
  3540.    \n      :if ([ :len \$CName ] > 0) do={\
  3541.    \n        :local CNameVal [ /ip/dns/static/get \$CName ];\
  3542.    \n        :if (\$CNameVal->\"name\" != \$FullCN || \$CNameVal->\"cname\" !\
  3543.    = \$FullA) do={\
  3544.    \n          \$LogPrintExit2 info \$0 (\"Deleting CNAME record with wrong d\
  3545.    ata for \" . \$MacInServer . \".\") false;\
  3546.    \n          /ip/dns/static/remove \$CName;\
  3547.    \n        }\
  3548.    \n      }\
  3549.    \n      :if ([ :len \$HostName ] > 0 && [ :len [ /ip/dns/static/find where\
  3550.    \_name=\$FullCN type=CNAME ] ] = 0) do={\
  3551.    \n        \$LogPrintExit2 info \$0 (\"Adding CNAME record for \" . \$MacIn\
  3552.    Server . \" (\" . \$FullCN . \" -> \" . \$FullA . \").\") false;\
  3553.    \n        /ip/dns/static/add name=\$FullCN type=CNAME cname=\$FullA ttl=\$\
  3554.    Ttl comment=\$Comment place-before=\$PlaceBefore;\
  3555.    \n      }\
  3556.    \n\
  3557.    \n    } else={\
  3558.    \n      \$LogPrintExit2 info \$0 (\"Adding A record for \" . \$MacInServer\
  3559.    \_. \" (\" . \$FullA . \" -> \" . \$LeaseVal->\"active-address\" . \").\")\
  3560.    \_false;\
  3561.    \n      /ip/dns/static/add name=\$FullA type=A address=(\$LeaseVal->\"acti\
  3562.    ve-address\") ttl=\$Ttl comment=\$Comment place-before=\$PlaceBefore;\
  3563.    \n      :if ([ :len \$HostName ] > 0 && [ :len [ /ip/dns/static/find where\
  3564.    \_name=\$FullCN type=CNAME ] ] = 0) do={\
  3565.    \n        \$LogPrintExit2 info \$0 (\"Adding CNAME record for \" . \$MacIn\
  3566.    Server . \" (\" . \$FullCN . \" -> \" . \$FullA . \").\") false;\
  3567.    \n        /ip/dns/static/add name=\$FullCN type=CNAME cname=\$FullA ttl=\$\
  3568.    Ttl comment=\$Comment place-before=\$PlaceBefore;\
  3569.    \n      }\
  3570.    \n    }\
  3571.    \n\
  3572.    \n    :if ([ :len [ /ip/dns/static/find where name=\$FullA (!type or type=\
  3573.    A) ] ] > 1) do={\
  3574.    \n      \$LogPrintOnce warning \$0 (\"The name '\" . \$FullA . \"' appeare\
  3575.    d in more than one A record!\");\
  3576.    \n    }\
  3577.    \n  } else={\
  3578.    \n    \$LogPrintExit2 debug \$0 (\"No address available... Ignoring.\") fa\
  3579.    lse;\
  3580.    \n  }\
  3581.    \n}\
  3582.    \n"
  3583. add dont-require-permissions=no name=lease-script owner=lease-script policy=\
  3584.     ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\
  3585.    !rsc by RouterOS\
  3586.    \n# RouterOS script: lease-script\
  3587.    \n# Copyright (c) 2013-2024 Christian Hesse <mail@eworm.de>\
  3588.    \n# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md\
  3589.    \n#\
  3590.    \n# run scripts on DHCP lease\
  3591.    \n# https://git.eworm.de/cgit/routeros-scripts/about/doc/lease-script.md\
  3592.    \n\
  3593.    \n:local 0 \"lease-script\";\
  3594.    \n:global GlobalFunctionsReady;\
  3595.    \n:while (\$GlobalFunctionsReady != true) do={ :delay 500ms; }\
  3596.    \n\
  3597.    \n:global Grep;\
  3598.    \n:global IfThenElse;\
  3599.    \n:global LogPrintExit2;\
  3600.    \n:global ParseKeyValueStore;\
  3601.    \n:global ScriptLock;\
  3602.    \n\
  3603.    \n:if ([ :typeof \$leaseActIP ] = \"nothing\" || \\\
  3604.    \n     [ :typeof \$leaseActMAC ] = \"nothing\" || \\\
  3605.    \n     [ :typeof \$leaseServerName ] = \"nothing\" || \\\
  3606.    \n     [ :typeof \$leaseBound ] = \"nothing\") do={\
  3607.    \n  \$LogPrintExit2 error \$0 (\"This script is supposed to run from ip dh\
  3608.    cp-server.\") true;\
  3609.    \n}\
  3610.    \n\
  3611.    \n\$LogPrintExit2 debug \$0 (\"DHCP Server \" . \$leaseServerName . \" \" \
  3612.    . [ \$IfThenElse (\$leaseBound = 0) \\\
  3613.    \n  \"de\" \"\" ] . \"assigned lease \" . \$leaseActIP . \" to \" . \$leas\
  3614.    eActMAC) false;\
  3615.    \n\
  3616.    \n\$ScriptLock \$0 false 10;\
  3617.    \n\
  3618.    \n:if ([ :len [ /system/script/job/find where script=\$0 ] ] > 1) do={\
  3619.    \n  \$LogPrintExit2 debug \$0 (\"More invocations are waiting, exiting ear\
  3620.    ly.\") true;\
  3621.    \n}\
  3622.    \n\
  3623.    \n:local RunOrder ({});\
  3624.    \n:foreach Script in=[ /system/script/find where source~(\"\\n# provides: \
  3625.    lease-script\\\\b\") ] do={\
  3626.    \n  :local ScriptVal [ /system/script/get \$Script ];\
  3627.    \n  :local Store [ \$ParseKeyValueStore [ \$Grep (\$ScriptVal->\"source\")\
  3628.    \_(\"\\23 provides: lease-script, \") ] ];\
  3629.    \n\
  3630.    \n  :set (\$RunOrder->(\$Store->\"order\" . \"-\" . \$ScriptVal->\"name\")\
  3631.    ) (\$ScriptVal->\"name\");\
  3632.    \n}\
  3633.    \n\
  3634.    \n:foreach Order,Script in=\$RunOrder do={\
  3635.    \n  :do {\
  3636.    \n    \$LogPrintExit2 debug \$0 (\"Running script with order \" . \$Order \
  3637.    . \": \" . \$Script) false;\
  3638.    \n    /system/script/run \$Script;\
  3639.    \n  } on-error={\
  3640.    \n    \$LogPrintExit2 warning \$0 (\"Running script '\" . \$Script . \"' f\
  3641.    ailed!\") false;\
  3642.    \n  }\
  3643.    \n}\
  3644.    \n"
  3645. add dont-require-permissions=no name=WB_Up owner=liet policy=\
  3646.     ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="/\
  3647.    interface/wireguard/peers/enable  [find where comment name=wildberries]"
  3648. add dont-require-permissions=no name=WB_Down owner=liet policy=\
  3649.     ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="/\
  3650.    interface/wireguard/peers/disable  [find where comment name=wildberries]"
  3651. add dont-require-permissions=no name=Speedtest owner=liet-phone policy=\
  3652.     read,write,test,password source=":local txAvg 0 :local rxAvg 0 :local ts [\
  3653.    /system clock get time] :set ts ([:pick \$ts 0 2].[:pick \$ts 3 5].[:pick \
  3654.    \$ts 6 8]) :local ds [/system clock get date] :set ds ([:pick \$ds 7 11].[\
  3655.    :pick \$ds 0 3].[:pick \$ds 4 6]) tool bandwidth-test protocol=tcp directi\
  3656.    on=transmit address=ip_bandsw_test_server duration=5s do={ :set txAvg (\$\
  3657.    \"tx-total-average\" / 1048576 ); } tool bandwidth-test protocol=tcp direc\
  3658.    tion=receive address=ip_bandsw_test_server duration=5s do={ :set rxAvg (\$\
  3659.    \"rx-total-average\" / 1048576 ); } :local ContentsFile [/file get isp-qua\
  3660.    lity.txt contents]; /file set isp-quality.txt contents=\"\$ContentsFile\\n\
  3661.    \$ds-\$ts tx: \$txAvg Mbps - rx: \$rxAvg Mbps\""
  3662. add dont-require-permissions=no name=steedtest owner=liet-phone policy=\
  3663.     read,write,policy,test,password source=":local txAvg 0 :local rxAvg 0 :loc\
  3664.    al ts [/system clock get time] :set ts ([:pick \$ts 0 2].[:pick \$ts 3 5].\
  3665.    [:pick \$ts 6 8]) :local ds [/system clock get date] :set ds ([:pick \$ds \
  3666.    7 11].[:pick \$ds 0 3].[:pick \$ds 4 6]) tool bandwidth-test protocol=tcp \
  3667.    direction=transmit address=ip_bandsw_test_server duration=5s do={ :set txA\
  3668.    vg (\$\"tx-total-average\" / 1048576 ); } tool bandwidth-test protocol=tcp\
  3669.    \_direction=receive address=ip_bandsw_test_server duration=5s do={ :set rx\
  3670.    Avg (\$\"rx-total-average\" / 1048576 ); } :local ContentsFile [/file get \
  3671.    isp-quality.txt contents]; /file set isp-quality.txt contents=\"\$Contents\
  3672.    File\\n\$ds-\$ts tx: \$txAvg Mbps - rx: \$rxAvg Mbps\""
  3673. add dont-require-permissions=no name=speedtest owner=liet-phone policy=\
  3674.     ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\
  3675.    local txAvg 0\
  3676.    \n:local rxAvg 0\
  3677.    \n\
  3678.    \n:local ts [/system clock get time]\
  3679.    \n:set ts ([:pick \$ts 0 2].[:pick \$ts 3 5].[:pick \$ts 6 8])\
  3680.    \n\
  3681.    \n:local ds [/system clock get date]\
  3682.    \n:set ds ([:pick \$ds 7 11].[:pick \$ds 0 3].[:pick \$ds 4 6])\
  3683.    \n\
  3684.    \ntool bandwidth-test protocol=tcp direction=transmit address=ip_bandsw_te\
  3685.    st_server duration=5s do={\
  3686.    \n:set txAvg (\$\"tx-total-average\" / 1048576 );\
  3687.    \n}\
  3688.    \n\
  3689.    \ntool bandwidth-test protocol=tcp direction=receive address=ip_bandsw_tes\
  3690.    t_server duration=5s do={\
  3691.    \n:set rxAvg (\$\"rx-total-average\" / 1048576 );\
  3692.    \n}\
  3693.    \n\
  3694.    \n:local ContentsFile [/file get isp-quality.txt contents];\
  3695.    \n/file set isp-quality.txt contents=\"\$ContentsFile\\n\$ds-\$ts tx: \$tx\
  3696.    Avg Mbps - rx: \$rxAvg Mbps\""
  3697. add dont-require-permissions=no name=script1 owner=liet-phone policy=\
  3698.     ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="{\
  3699.    \n:local minimalMtu 1600\
  3700.    \n\
  3701.    \n:local mtuCheck do={\
  3702.    \n  :if ([/interface get \$1 l2mtu] < \$2) do={\
  3703.    \n    :put (\"Interface \" . [/interface get \$1 name] . \" has MTU under \
  3704.    \" . \$2)\
  3705.    \n  }\
  3706.    \n}\
  3707.    \n\
  3708.    \n# ethernet\
  3709.    \n:foreach i in=[/interface ethernet find running] do={\
  3710.    \n  \$mtuCheck \$i \$minimalMtu\
  3711.    \n}\
  3712.    \n\
  3713.    \n# wireless\
  3714.    \n:foreach i in=[/interface wireless find disabled=no] do={\
  3715.    \n  \$mtuCheck \$i \$minimalMtu\
  3716.    \n}\
  3717.    \n}"
  3718. add dont-require-permissions=no name=script2 owner=liet-phone policy=\
  3719.     ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="{\
  3720.    \n:local minimalMtu 1600\
  3721.    \n\
  3722.    \n:local mtuCheck do={\
  3723.    \n  :if ([/interface get \$1 l2mtu] < \$2) do={\
  3724.    \n    :put (\"Interface \" . [/interface get \$1 name] . \" has MTU under \
  3725.    \" . \$2)\
  3726.    \n  }\
  3727.    \n}\
  3728.    \n\
  3729.    \n# ethernet\
  3730.    \n:foreach i in=[/interface ethernet find running] do={\
  3731.    \n  \$mtuCheck \$i \$minimalMtu\
  3732.    \n}\
  3733.    \n\
  3734.    \n# wireless\
  3735.    \n:foreach i in=[/interface wireless find disabled=no] do={\
  3736.    \n  \$mtuCheck \$i \$minimalMtu\
  3737.    \n}\
  3738.    \n}"
  3739. add dont-require-permissions=no name=dhcp2dns.rsc owner=liet policy=\
  3740.     ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\
  3741.    local DHCPtag   \"#*# Created by DHCP2DNS #*#\"\r\
  3742.    \n:local LogPrefix \"DHCP2DNS (\$leaseServerName)\"\r\
  3743.    \n\r\
  3744.    \n###\r\
  3745.    \n# Functions\r\
  3746.    \n\r\
  3747.    \n# remove \\0 and spaces from string passed as inStr=<string>\r\
  3748.    \n:local trimString do=\\\r\
  3749.    \n{\r\
  3750.    \n  :local outStr\r\
  3751.    \n  :for i from=0 to=([:len \$inStr] - 1) do=\\\r\
  3752.    \n  {\r\
  3753.    \n    :local tmp [:pick \$inStr \$i];\r\
  3754.    \n    :if ((\$tmp !=\" \") and (\$tmp !=\"\\00\")) do=\\\r\
  3755.    \n    {\r\
  3756.    \n      :set outStr (\$outStr . \$tmp)\r\
  3757.    \n    }\r\
  3758.    \n  }\r\
  3759.    \n  :return \$outStr\r\
  3760.    \n}\r\
  3761.    \n\r\
  3762.    \n# \"a.b.c.d\" -> \"a-b-c-d\" for IP addresses used as replacement for mi\
  3763.    ssing host names\r\
  3764.    \n:local ip2Host do=\\\r\
  3765.    \n{\r\
  3766.    \n  :local outStr\r\
  3767.    \n  :for i from=0 to=([:len \$inStr] - 1) do=\\\r\
  3768.    \n  {\r\
  3769.    \n    :local tmp [:pick \$inStr \$i];\r\
  3770.    \n    :if (\$tmp =\".\") do=\\\r\
  3771.    \n    {\r\
  3772.    \n      :set tmp \"-\"\r\
  3773.    \n    }\r\
  3774.    \n    :set outStr (\$outStr . \$tmp)\r\
  3775.    \n  }\r\
  3776.    \n  :return \$outStr\r\
  3777.    \n}\r\
  3778.    \n\r\
  3779.    \n###\r\
  3780.    \n# Script entry point\r\
  3781.    \n#\r\
  3782.    \n# Expected environment variables:\r\
  3783.    \n# leaseBound         1 = lease bound, 0 = lease removed\r\
  3784.    \n# leaseServerName    Name of DHCP server\r\
  3785.    \n# leaseActIP         IP address of DHCP client\r\
  3786.    \n\r\
  3787.    \n:if ( [ :len \$leaseActIP ] <= 0 ) do=\\\r\
  3788.    \n{\r\
  3789.    \n  :log error \"\$LogPrefix: empty lease address\"\r\
  3790.    \n  :error \"empty lease address\"\r\
  3791.    \n}\r\
  3792.    \n\r\
  3793.    \n:if ( \$leaseBound = 1 ) do=\\\r\
  3794.    \n{\r\
  3795.    \n  # new DHCP lease added\r\
  3796.    \n  \r\
  3797.    \n  /ip dhcp-server\r\
  3798.    \n  :local ttl [ get [ find name=\$leaseServerName ] lease-time ]\r\
  3799.    \n  network \r\
  3800.    \n  :local domain [ get [ find \$leaseActIP in address ] domain ]\r\
  3801.    \n  :set domain [ \$trimString inStr=\$domain ]\r\
  3802.    \n\r\
  3803.    \n  .. lease\r\
  3804.    \n  :local leaseId [ find address=\$leaseActIP ]\r\
  3805.    \n\r\
  3806.    \n  # Check for multiple active leases for the same IP address. It's weird\
  3807.    \_and it shouldn't be, but just in case.\r\
  3808.    \n  :if ( [ :len \$leaseId ] != 1) do=\\\r\
  3809.    \n  {\r\
  3810.    \n    :log warning \"\$LogPrefix: Multiple active DHCP leases for '\$lease\
  3811.    ActIP' (\?\?\?)\"\r\
  3812.    \n    :error \"Multiple active DHCP leases for '\$leaseActIP' (\?\?\?)\"\r\
  3813.    \n  }  \r\
  3814.    \n  :local hostname [ get \$leaseId host-name ]\r\
  3815.    \n  :set hostname [ \$trimString inStr=\$hostname ]\r\
  3816.    \n\r\
  3817.    \n  :if ( [ :len \$hostname ] <= 0 ) do=\\\r\
  3818.    \n  {\r\
  3819.    \n    :set hostname [ \$ip2Host inStr=\$leaseActIP ]\r\
  3820.    \n    :log info \"\$LogPrefix: Empty hostname for '\$leaseActIP', using ge\
  3821.    nerated host name '\$hostname'\"\r\
  3822.    \n  }\r\
  3823.    \n  :if ( [ :len \$domain ] <= 0 ) do=\\\r\
  3824.    \n  {\r\
  3825.    \n    :log warning \"\$LogPrefix: Empty domainname for '\$leaseActIP', can\
  3826.    not create static DNS name\"\r\
  3827.    \n    :error \"Empty domainname for '\$leaseActIP'\"\r\
  3828.    \n  }\r\
  3829.    \n\r\
  3830.    \n  :local fqdn (\$hostname . \".\" .  \$domain)\r\
  3831.    \n\r\
  3832.    \n  /ip dns static\r\
  3833.    \n  :if ( [ :len [ find name=\$fqdn and address=\$leaseActIP and disabled=\
  3834.    no ] ] = 0 ) do=\\\r\
  3835.    \n  {\r\
  3836.    \n    add address=\$leaseActIP name=\$fqdn ttl=\$ttl comment=\$DHCPtag dis\
  3837.    abled=no\r\
  3838.    \n    :log info \"\$LogPrefix: Static domain name '\$fqdn' created for '\$\
  3839.    leaseActIP' with ttl '\$ttl'\"\r\
  3840.    \n  }\\\r\
  3841.    \n  else=\\\r\
  3842.    \n  {\r\
  3843.    \n    :log warning \"\$LogPrefix: '\$fqdn' already exists, cannot create s\
  3844.    tatic DNS name for '\$leaseActIP'\"\r\
  3845.    \n    :error \"\$LogPrefix: '\$fqdn' already exists\"\r\
  3846.    \n  }\r\
  3847.    \n}\\\r\
  3848.    \nelse=\\\r\
  3849.    \n{\r\
  3850.    \n  # DHCP lease removed\r\
  3851.    \n\r\
  3852.    \n  /ip dns static\r\
  3853.    \n  :local dnsDhcpId\r\
  3854.    \n  :set dnsDhcpId [ find address=\$leaseActIP and comment=\$DHCPtag ]\r\
  3855.    \n  :if ( [ :len \$dnsDhcpId ] > 0 ) do=\\\r\
  3856.    \n  {\r\
  3857.    \n    remove \$dnsDhcpId\r\
  3858.    \n    :log info \"\$LogPrefix: Static DNS name(s) for '\$leaseActIP' remov\
  3859.    ed\"\r\
  3860.    \n  }\r\
  3861.    \n}"
  3862. add dont-require-permissions=no name=dhcp2 owner=liet policy=\
  3863.     ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\
  3864.    \_MikroTik (RouterOS) script for automatically setting DNS records\r\
  3865.    \n\r\
  3866.    \n# for clients when they obtain a DHCP lease.\r\
  3867.    \n\r\
  3868.    \n#\r\
  3869.    \n\r\
  3870.    \n# author SmartFinn <https://gist.github.com/SmartFinn>\r\
  3871.    \n\r\
  3872.    \n# based on https://github.com/karrots/ROS-DDNS\r\
  3873.    \n\r\
  3874.    \n:local domain;\r\
  3875.    \n\r\
  3876.    \n:local fqdn;\r\
  3877.    \n\r\
  3878.    \n:local hostname;\r\
  3879.    \n\r\
  3880.    \n:local safeHostname;\r\
  3881.    \n\r\
  3882.    \n:local token \"\$leaseServerName-\$leaseActMAC\";\r\
  3883.    \n\r\
  3884.    \n:local ttl [/ip dhcp-server get \$leaseServerName lease-time];\r\
  3885.    \n\r\
  3886.    \n# Getting the domain name from DHCP server. If a domain name is not\r\
  3887.    \n\r\
  3888.    \n# specified will use hostname only\r\
  3889.    \n\r\
  3890.    \n/ip dhcp-server network {\r\
  3891.    \n\r\
  3892.    \n:do {\r\
  3893.    \n\r\
  3894.    \n:set domain [get [find where (\$leaseActIP in address)] domain];\r\
  3895.    \n\r\
  3896.    \n# Add a dot before domain name\r\
  3897.    \n\r\
  3898.    \n:set domain (\".\" . \$domain);\r\
  3899.    \n\r\
  3900.    \n} on-error={\r\
  3901.    \n\r\
  3902.    \n:set domain \"\";\r\
  3903.    \n\r\
  3904.    \n};\r\
  3905.    \n\r\
  3906.    \n};\r\
  3907.    \n\r\
  3908.    \n:if (\$leaseBound = 1) do={\r\
  3909.    \n\r\
  3910.    \n:log debug \"\$leaseServerName: Processing bound lease \$leaseActMAC (\$\
  3911.    leaseActIP)\";\r\
  3912.    \n\r\
  3913.    \n/ip dhcp-server lease {\r\
  3914.    \n\r\
  3915.    \n:set hostname [get [find active-mac-address=\$leaseActMAC] host-name];\r\
  3916.    \n\r\
  3917.    \n};\r\
  3918.    \n\r\
  3919.    \n# Delete unallowed chars from the hostname\r\
  3920.    \n\r\
  3921.    \n:for i from=0 to=([:len \$hostname]-1) do={\r\
  3922.    \n\r\
  3923.    \n:local char [:pick \$hostname \$i];\r\
  3924.    \n\r\
  3925.    \n:if (\$char~\"[a-zA-Z0-9-]\") do={\r\
  3926.    \n\r\
  3927.    \n:set safeHostname (\$safeHostname . \$char);\r\
  3928.    \n\r\
  3929.    \n};\r\
  3930.    \n\r\
  3931.    \n};\r\
  3932.    \n\r\
  3933.    \n:if ([:len \$safeHostname] > 0) do={\r\
  3934.    \n\r\
  3935.    \n:set fqdn (\$safeHostname . \$domain);\r\
  3936.    \n\r\
  3937.    \n/ip dns static {\r\
  3938.    \n\r\
  3939.    \n:local itemId [find name=\$fqdn];\r\
  3940.    \n\r\
  3941.    \n:if (\$itemId != \"\") do={\r\
  3942.    \n\r\
  3943.    \n# This DNS entry already exists\r\
  3944.    \n\r\
  3945.    \n:if ([get \$itemId comment] = \$token) do={\r\
  3946.    \n\r\
  3947.    \n:if ([get \$itemId address] != \$leaseActIP) do={\r\
  3948.    \n\r\
  3949.    \nset \$itemId address=\$leaseActIP ttl=\$ttl;\r\
  3950.    \n\r\
  3951.    \n:log info \"Update DNS entry: \$fqdn -> \$leaseActIP (\$leaseActMAC)\";\
  3952.    \r\
  3953.    \n\r\
  3954.    \n};\r\
  3955.    \n\r\
  3956.    \n} else={\r\
  3957.    \n\r\
  3958.    \n:log warning \"Cannot to add DNS entry. \$fqdn already exists\";\r\
  3959.    \n\r\
  3960.    \n};\r\
  3961.    \n\r\
  3962.    \n} else={\r\
  3963.    \n\r\
  3964.    \n# Add DNS entry if it does not exist\r\
  3965.    \n\r\
  3966.    \nadd name=\$fqdn address=\$leaseActIP ttl=\$ttl comment=\$token;\r\
  3967.    \n\r\
  3968.    \n:log info \"Add DNS entry: \$fqdn -> \$leaseActIP (\$leaseActMAC)\";\r\
  3969.    \n\r\
  3970.    \n};\r\
  3971.    \n\r\
  3972.    \n};\r\
  3973.    \n\r\
  3974.    \n};\r\
  3975.    \n\r\
  3976.    \n} else={\r\
  3977.    \n\r\
  3978.    \n# Remove entry when lease expires (\$leaseBound=0)\r\
  3979.    \n\r\
  3980.    \n:log debug \"\$leaseServerName: Processing deassigned lease \$leaseActMA\
  3981.    C (\$leaseActIP)\";\r\
  3982.    \n\r\
  3983.    \n/ip dns static {\r\
  3984.    \n\r\
  3985.    \n:local itemId [find comment=\$token];\r\
  3986.    \n\r\
  3987.    \n:if (\$itemId != \"\") do={\r\
  3988.    \n\r\
  3989.    \n:set fqdn ([get \$itemId name]);\r\
  3990.    \n\r\
  3991.    \nremove \$itemId;\r\
  3992.    \n\r\
  3993.    \n:log info \"Remove DNS entry: \$fqdn -> \$leaseActIP (\$leaseActMAC)\";\
  3994.    \r\
  3995.    \n\r\
  3996.    \n};\r\
  3997.    \n\r\
  3998.    \n};\r\
  3999.    \n\r\
  4000.    \n};"
  4001. add dont-require-permissions=no name=resetDhcpToStaticDns owner=liet policy=\
  4002.     ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="\
  4003.    \n\
  4004.    \n:local DHCPtag\
  4005.    \n:local topdomain;\
  4006.    \n:local hostname;\
  4007.    \n:local hostip;\
  4008.    \n:local skip;\
  4009.    \n:local protected;\
  4010.    \n:local ttl\
  4011.    \n:local leaseServerName\
  4012.    \n\
  4013.    \n:set DHCPtag \"#DHCP\"\
  4014.    \n:set leaseServerName \"defconf\"\
  4015.    \n:set topdomain \"put_your_top_domain_here.\"\
  4016.    \n\
  4017.    \n/ip dhcp-server\
  4018.    \n:set ttl [ get [ find name=\$leaseServerName ] lease-time ]\
  4019.    \n  \
  4020.    \n\
  4021.    \n/ip dhcp-server lease;\
  4022.    \n:foreach i in=[find where status=\"bound\"] do={\
  4023.    \n  /ip dhcp-server lease;\
  4024.    \n  :if ([:len [get \$i host-name]] > 0) do={\
  4025.    \n    :set hostname ([get \$i host-name] . \".\" . \$topdomain);\
  4026.    \n    :set hostip [get \$i address];\
  4027.    \n    /ip dns static;\
  4028.    \n# Remove if DNS entry already exist\
  4029.    \n:set protected false;\
  4030.    \n:set skip false;\
  4031.    \n    :foreach di in [find] do={\
  4032.    \n      :if ([get \$di name] = \$hostname) do={\
  4033.    \n:if ([get \$di comment] = \$DHCPtag) do={\
  4034.    \n:if ([get \$di address] = \$hostip) do={\
  4035.    \n:put (\"Unchanged: \" . \$hostname . \" : \" . \$hostip);\
  4036.    \n:set skip true;\
  4037.    \n} else={\
  4038.    \n:put (\"Removing: \" . \$hostname . \" : \" . \$hostip);\
  4039.    \n}\
  4040.    \nremove \$di;\
  4041.    \n} else={\
  4042.    \n:set protected true;\
  4043.    \n:put (\"Protected: \" . \$hostname . \" : \" . \$hostip);\
  4044.    \n}\
  4045.    \n      }\
  4046.    \n    }\
  4047.    \n:if (!\$skip && !\$protected) do={\
  4048.    \n# Add DNS entry\
  4049.    \n:put (\"Adding: \" . \$hostname . \" : \" . \$hostip);\
  4050.    \n/ip dns static add name=\$hostname address=\$hostip ttl=\$ttl comment=\$\
  4051.    DHCPtag;\
  4052.    \n}\
  4053.    \n  }\
  4054.    \n}\
  4055.    \n\
  4056.    \n"
  4057. add dont-require-permissions=no name=st owner=liet policy=\
  4058.     ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\
  4059.    log info \"------------ BW-TEST Starts--------------\";\r\
  4060.    \n\r\
  4061.    \n:local luser \"BW Test Server USER\";\r\
  4062.    \n:local lpass \"BW TEST Server PASSWORD\";\r\
  4063.    \n:local Addr  \"BW TEST Server IP ADDRESS\";\r\
  4064.    \n\r\
  4065.    \n:local avrRX 0;\r\
  4066.    \n:local avrTX 0;\r\
  4067.    \n\r\
  4068.    \n\r\
  4069.    \n# DOWNLOAD TEST\r\
  4070.    \n:log info \"----> Measuring RX (30 seg)........\";\r\
  4071.    \n:do {/tool\r\
  4072.    \n   bandwidth-test duration=30s user=\$luser password=\$lpass protocol=tc\
  4073.    p address=\$Addr direction=receive do={\r\
  4074.    \n     :set \$avrRX (\"rx-total-average: \" . (\$\"rx-total-average\" / 10\
  4075.    48576) . \".\" . (\$\"rx-total-average\" % (1048576) / 1024) . \" Mbps\" )\
  4076.    ;\r\
  4077.    \n   }\r\
  4078.    \n} on-error={:log error message=\"RX script failed\"}\r\
  4079.    \n\r\
  4080.    \n:delay 2s;\r\
  4081.    \n\r\
  4082.    \n# UPLOAD TEST\r\
  4083.    \n:log info \"----> Measuring TX (30 seg) ........\";\r\
  4084.    \n:do {/tool\r\
  4085.    \n  bandwidth-test duration=30s user=\$luser password=\$lpass protocol=tcp\
  4086.    \_address=\$Addr direction=transmit do={\r\
  4087.    \n     :set \$avrTX (\"tx-total-average: \" . (\$\"tx-total-average\" / 10\
  4088.    48576) . \".\" . (\$\"tx-total-average\" % (1048576) / 1024) . \" Mbps\" )\
  4089.    ;\r\
  4090.    \n  }\r\
  4091.    \n} on-error={:log error message=\"TX script failed\"}\r\
  4092.    \n\r\
  4093.    \n:log info message=\$avrRX;\r\
  4094.    \n:log info message=\$avrTX;\r\
  4095.    \n:log info \"-------- End of  BW-TEST------------\";\r\
  4096.    \n\r\
  4097.    \n\r\
  4098.    \n################# SAVING RESULTS WITH DATE ######################\r\
  4099.    \n:local filename2 \"LOG_BW_TEST.txt\"\r\
  4100.    \n:local ds [/system clock get date];\r\
  4101.    \n:local months (\"jan\",\"feb\",\"mar\",\"apr\",\"may\",\"jun\",\"jul\",\
  4102.    \"aug\",\"sep\",\"oct\",\"nov\",\"dec\");\r\
  4103.    \n:local month [ :pick \$ds 0 3 ];\r\
  4104.    \n:local mm ([ :find \$months \$month -1 ] + 1);\r\
  4105.    \n:if (\$mm < 10) do={ :set mm (\"0\" . \$mm); };\r\
  4106.    \n:set ds ([:pick \$ds 7 11] . \$mm . [:pick \$ds 4 6]);\r\
  4107.    \n\r\
  4108.    \n:if  ( [:len [/file find name=\$filename2]] = 0) do={\r\
  4109.    \n:log info \"Log file does not exist. Creating a new one.....\";\r\
  4110.    \n/file print file=\$filename2 where name=\"\";\r\
  4111.    \n}\r\
  4112.    \n\r\
  4113.    \n:log info \"Adding result to the end of the lof file......\";\r\
  4114.    \n/file set \$filename2 contents=([get \$filename2 contents]  .\"\\n\".\$d\
  4115.    s.\"-->\" . \$avrRX);\r\
  4116.    \n/file set \$filename2 contents=([get \$filename2 contents] .\"    \". \$\
  4117.    avrTX);\r\
  4118.    \n}"
  4119. add dont-require-permissions=no name=dns owner=liet policy=\
  4120.     ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\
  4121.    \_set variables\r\
  4122.    \n:local primaryDNS \"192.168.254.250\";\r\
  4123.    \n:local fallbackDNS \"1.1.1.1\";\r\
  4124.    \n:local currentDNS;\r\
  4125.    \n:set \$currentDNS [/ip dns get servers];\r\
  4126.    \n#:log warning \"What I got is: \$currentDNS\"\r\
  4127.    \n#:log warning \"What I want to see is: \$primaryDNS\"\r\
  4128.    \n:do {\r\
  4129.    \n:put [resolve google.com server=\$primaryDNS];\r\
  4130.    \nif (\$currentDNS!=\$primaryDNS) do={\r\
  4131.    \n:log warning \"DNS Failover: Switching to primaryDNS\";\r\
  4132.    \n/ip dns set servers \$primaryDNS\r\
  4133.    \nip/dns/set allow-remote-requests=no;\r\
  4134.    \n/ip/dns/set use-doh-server=\"https://main.mentat.su/dns-query\";\r\
  4135.    \n/ip dhcp-server network set 0 dns-server=192.168.254.250;\r\
  4136.    \n} else={}\r\
  4137.    \n} on-error={ :set \$currentDNS [/ip dns get servers];\r\
  4138.    \nif (\$currentDNS!=\$fallbackDNS) do={\r\
  4139.    \n:log error \"DNS Failover: Switching to FallbackDNS\";\r\
  4140.    \n/ip dns set servers \$fallbackDNS\r\
  4141.    \n/ip dhcp-server network set 0 dns-server=1.1.1.1;\r\
  4142.    \n/ip/dns/set allow-remote-requests=yes;\r\
  4143.    \n/ip/dns/set use-doh-server=\"https://8.8.8.8/dns-query\";\r\
  4144.    \n} else={:log info \"Using Failover DNS, Primary Unavailable\"}\r\
  4145.    \n}\r\
  4146.    \n#try to reach google through the primaryDNS\r\
  4147.    \n#if it works and we are on a different DNS, set the DNS server to the pr\
  4148.    imaryDNS\r\
  4149.    \n#if it works and we are already on the primaryDNS, do nothing\r\
  4150.    \n#if we can't reach google and we aren't already on our FallbackDNS, swit\
  4151.    ch to fallback\r\
  4152.    \n#if we can't reach google through primaryDNS and we are on the fallback,\
  4153.    \_log that primaryDNS is unavailable"
  4154. /tool graphing interface
  4155. add
  4156. /tool graphing resource
  4157. add
  4158. /tool netwatch
  4159. add disabled=no down-script="" host=192.168.254.250 http-codes="" \
  4160.     test-script="" type=simple up-script=""
  4161.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement