From 2cb786a492b6e2e0cd69bad5d7f31860482af08b Mon Sep 17 00:00:00 2001 From: vados-dev Date: Mon, 4 May 2026 08:20:19 +0300 Subject: [PATCH] Backup for MikroMaster created successfully at May 04 08:20:19. --- .../20260504/20260504082001-Binary.backup | Bin 0 -> 177885 bytes .../20260504/20260504082001-Config.rsc | 1674 +++++++++++ .../20260504/20260504082001-Diff-Config.rsc | 2647 +++++++++++++++++ 3 files changed, 4321 insertions(+) create mode 100644 MikroMaster/20260504/20260504082001-Binary.backup create mode 100644 MikroMaster/20260504/20260504082001-Config.rsc create mode 100644 MikroMaster/history/20260504/20260504082001-Diff-Config.rsc diff --git a/MikroMaster/20260504/20260504082001-Binary.backup b/MikroMaster/20260504/20260504082001-Binary.backup new file mode 100644 index 0000000000000000000000000000000000000000..e18b78f17d370e57e840ed22d4b58537d4b02e7f GIT binary patch literal 177885 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%0D}A>YGH7m(y8Y zn&ztyoGi=g%BT4Hq;4C2u|l(!Wtj$FfxJKR*VL|wJ}x(Zg_>9UuTrjU9@3R7>Slp--kiOb9!+;ywvowg5khk<^YFBh(Mow=Nf@uI_jCc-<)sJ0qH1>2%P&IE7*ODSjrv*eMn)-zS3(9A_k9 z*||~8HKbmW1DN_ICzp|0nB!D+MwpYreovZn{2${i$s>XmU0cg!^5z)6*~;YnfgD8f zqg>e9iYEjM$m4Q)qU<=jrX6^HVa+tWmv9HEo*2boNL&zYB;JCJ- z6?{~*`)X9lsq;0E(-V$v=d4ODQQ)OwPR|F1j+OB8W?zv99_|cRDH#QaV(%gYf6OM1 z`femD%vfI6G>s%dbrqA6T0WQcYbQh&5#D|lAp(8JDVnBV17M29JG$=o9q@$wV83-k zU=b>iQOhA>;N85ARUaZXXO!2|aDPZJhs^7_F%rgwEss7lT{j$`7ZfR0-Zg#1S1@@Y zowLc{oJWj}b@ArWMPx)Ju0+TcoU74)Noto|En}&Ku3?!>sDPIeLJKtl4H^hTClpv- z3UtYw0aWCavRT97(=Y-avJSg;#z{D(;ZZYRDpZ;WSo7^TMmp#FzTn~qR@FLW&tE#% z()nCv@&E#eY0tdo=MP<=2zG2M*qDORX%n{H7awJSIZ#X{aLXt11s@t}BgImsAE{pO zLZb_*#NX%jXe^b$j&Z@DT>9lObP1-2K<|mfg;L(lB`nQxtPxvte91h^tyc^`3LXO& z-r4!1Sky-zn&!3D4~L2o?hS+rn(k`@c_2~J^syN76-rJ{mxdcqG2SZ2Y&M-l);3Fi zBNhX%N_5)MtwcfdQ^?RIGKDP16sC=_r;R}#gl6HGRs=;%!pPc&<0RZleZrQPK%!jH zONAL(0fqrXAe{iC$zbpU$qJgD7}gxa?>}V?ak^~P^ov6i&dF<66p(O+9;f@m3)^E?b#_f0oMefa9s;pFIkfl9KyRD%L$}|T+UV}l}HcUenl5{ zkcOf7VeZnF#bt6_TeA|mV#YU!yicg?sx?L}zc2!WKt8Ic6V9l3mBoO5j4>+RQ=qm~YRyfvy_bK}BR6v#24+dU=x2a{MO1M`{K(q8sJiYJ4Q\"data\");\ + \n#/usb1/mikro_bak_rsa.pub\ + \n\ + \n#\ + \n#/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@1\ + 0.30.30.10.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.10.pub\";\ + \n#\ + \n#root.mnuc.backuper\ + \n\ + \n#/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@1\ + 0.30.30.81.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.81.pub\";\ + \n#:local Script AM-GlobalConfig;\ + \n#/system/script/add name=\$Script owner=\$Script source=([ /tool/fetch c\ + heck-certificate=yes-without-crl url=(\$GlobalScriptsUrl . \$Script . \".r\ + sc\") output=user as-value ]->\"data\");\ + \n#/usb1/mikro_bak_rsa.pub\ + \n#:local FetchFile AM-DOHCert.rsc\ + \n\ + \n:global GlobalScriptsUrl \"https://ros.vados.ru/tmp/\";\ + \n:global MkDir;\ + \n\ + \n:local FetchFile Binary.backup\ + \n:local localDir \"\";\ + \n\ + \n#\$MkDir \$localDir;\ + \n\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \$FetchFile) dst-path=(\ + \$localDir . \$FetchFile);" +add comment="Example add WU servers to AddrList" dont-require-permissions=no \ + name=WU-add-to-list owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + \_Script to add target web sites DNS IP addresses into address list\r\ + \n# Tested with Mikrotik 6.4x\r\ + \n# Syed Jahanzaib / aacable@hotmail.com\r\ + \n# List name\r\ + \n:local LISTNAME \"windowsupdateslist\"\r\ + \n# Web site names which will be added in address list\r\ + \n:local TARGET1 \"update.microsoft.com\"\r\ + \n:local TARGET2 \"download.windowsupdate.com\"\r\ + \n:local TARGET3 \"download.microsoft.com\"\r\ + \n:local TARGET4 \"windowsupdate.com\"\r\ + \n:local TARGET5 \"ntservicepack.microsoft.com\"\r\ + \n:local TARGET6 \"wustat.windows.com\"\r\ + \n:local TARGET7 \"stats.microsoft.com\"\r\ + \n:local TARGET8 \"mp.microsoft.com\"\r\ + \n:local TARGET9 \"ws.microsoft.com\"\r\ + \n:local TARGET10 \"sls.update.microsoft.com.akadns.net\"\r\ + \n:local TARGET11 \"vortex.data.microsoft.com\"\r\ + \n:local TARGET12 \"vortex-win.data.microsoft.com\"\r\ + \n:local TARGET13 \"fe2.update.microsoft.com.akadns.net\"\r\ + \n:local TARGET14 \"statsfe2.update.microsoft.com.akadns.net\"\r\ + \n \r\ + \n# 1st time runner, check if address list is not created previously and a\ + dd entries in it for 1st time usage\r\ + \n:if ( [/ip firewall address-list find where list=\$LISTNAME] = \"\") do=\ + {\r\ + \n:log warning \"No address list for \$TARGET1 found ! creating and adding\ + \_resolved entry for 1st time usage ... zaib\"\r\ + \n \r\ + \n:local FirstAddr [resolve \$TARGET1];\r\ + \n\r\ + \n/ip firewall address-list add address=\$FirstAddr list=\$LISTNAME commen\ + t=\$TARGET1;\r\ + \n} else={\r\ + \n:log warning \"Previous List for \$LISTNAME found ! moving forward and c\ + hecking if DNS entries can be added in it ...\"\r\ + \n}\r\ + \n \r\ + \n# Check DNS entries and collect matching names\r\ + \n:foreach i in=[/ip dns cache find name~\"(\$TARGET1|\$TARGET2|\$TARGET3|\ + \$TARGET4|\$TARGET5|\$TARGET6|\$TARGET7|\$TARGET8|\$TARGET9|\$TARGET10|\$T\ + ARGET11|\$TARGET12|\$TARGET13|\$TARGET14)\" && \$type ~ \"^(A|CNAME)\\\$\"\ + \_] do={\r\ + \n \r\ + \n# Get IP Address from the names and hold it in temporary buffer\r\ + \n:local Buffer [/ip dns cache get \$i data];\r\ + \ndelay delay-time=10ms\r\ + \n \r\ + \n# Check if entry is already not exists, then OK, otherwise ignore duplic\ + ation\r\ + \n:if ( [/ip firewall address-list find where address=\$Buffer] = \"\") do\ + ={\r\ + \n \r\ + \n# Fetch DNS names for the entries\r\ + \n:local sitednsname [/ip dns cache get \$i name] ;\r\ + \n \r\ + \n# Print name in LOG window\r\ + \n:log info (\"added entry: \$sitednsname \$Buffer\");\r\ + \n \r\ + \n# Add IP addresses and there names to the address list\r\ + \n/ip firewall address-list add address=\$Buffer list=\$LISTNAME comment=\ + \$sitednsname;\r\ + \n}\r\ + \n}" +add comment="Add Hosts DNS names to NoWG addres list" \ + dont-require-permissions=no name=Add2vdsina owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + \_Script to add target web sites DNS IP addresses into address list\r\ + \n# Tested with Mikrotik 6.4x\r\ + \n# \r\ + \n# List name\r\ + \n:local LISTNAME \"NoWG\"\r\ + \n#\r\ + \n# Web site names which will be added in address list\r\ + \n:local TARGET1 \"comp-lenta.ru\"\r\ + \n:local TARGET2 \"ok.ru\"\r\ + \n:local TARGET3 \"vk.com\"\r\ + \n#:local TARGET4 \"smtp.mail.me.com\"\r\ + \n#:local TARGET4 \"windowsupdate.com\"\r\ + \n#:local TARGET5 \"ntservicepack.microsoft.com\"\r\ + \n#:local TARGET6 \"wustat.windows.com\"\r\ + \n#:local TARGET7 \"stats.microsoft.com\"\r\ + \n#:local TARGET8 \"mp.microsoft.com\"\r\ + \n#:local TARGET9 \"ws.microsoft.com\"\r\ + \n#:local TARGET10 \"sls.update.microsoft.com.akadns.net\"\r\ + \n#:local TARGET11 \"vortex.data.microsoft.com\"\r\ + \n#:local TARGET12 \"vortex-win.data.microsoft.com\"\r\ + \n#:local TARGET13 \"fe2.update.microsoft.com.akadns.net\"\r\ + \n#:local TARGET14 \"statsfe2.update.microsoft.com.akadns.net\"\r\ + \n \r\ + \n# 1st time runner, check if address list is not created previously and a\ + dd entries in it for 1st time usage\r\ + \n:if ( [/ip firewall address-list find where list=\$LISTNAME] = \"\") do=\ + {\r\ + \n:log warning \"No address list for \$TARGET1 found ! creating and adding\ + \_resolved entry for 1st time usage ... zaib\"\r\ + \n\r\ + \n:local FirstAddr [resolve \$TARGET1];\r\ + \n\r\ + \n/ip firewall address-list add address=\$FirstAddr list=\$LISTNAME commen\ + t=\$TARGET1;\r\ + \n\r\ + \n} else={\r\ + \n:log warning \"Previous List for \$LISTNAME found ! moving forward and c\ + hecking if DNS entries can be added in it ...\"\r\ + \n}\r\ + \n\r\ + \n# Check DNS entries and collect matching names\r\ + \n:foreach i in=[/ip dns cache find name~\"(\$TARGET1|\$TARGET2|\$TARGET3|\ + \$TARGET4)\" && \$type ~ \"^(A|CNAME)\\\$\" ] do={\r\ + \n\r\ + \n:log info (\"start entry: \$c \$sitednsname \$Buffer\");\r\ + \n\r\ + \n# Get IP Address from the names and hold it in temporary buffer\r\ + \n:local Buffer [/ip dns cache get \$i data];\r\ + \ndelay delay-time=10ms\r\ + \n:log info (\"1: \$Buffer\"); \r\ + \n\r\ + \n# Check if entry is already not exists, then OK, otherwise ignore duplic\ + ation\r\ + \n:if ( [/ip firewall address-list find where address=\$Buffer] = \"\") do\ + ={\r\ + \n\r\ + \n:log info (\"2: \$Buffer\"); \r\ + \n \r\ + \n# Fetch DNS names for the entries\r\ + \n:local sitednsname [/ip dns cache get \$i name] ;\r\ + \n \r\ + \n# Print name in LOG window\r\ + \n:log info (\"added entry: \$i \$sitednsname \$Buffer\");\r\ + \n \r\ + \n# Add IP addresses and there names to the address list\r\ + \n/ip firewall address-list add address=\$Buffer list=\$LISTNAME comment=\ + \$sitednsname;\r\ + \n}\r\ + \n}" +add comment="Flush DNS Cache" dont-require-permissions=no name=\ + DNS_Flush_Cache owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=\ + "/ip dns cache flush" +add comment="Certificates CloudFlare, Quad9 " dont-require-permissions=no \ + name=Update-Certificates owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + \_CloudFlare\r\ + \n#/tool/fetch mode=https url=https://cacerts.digicert.com/DigiCertGlobalR\ + ootCA.crt.pem;\r\ + \n#/certificate/import file-name=DigiCertGlobalRootCA.crt.pem passphrase=\ + \"\";\r\ + \n#/tool/ fetch mode=https url=https://cacerts.digicert.com/DigiCertGlobal\ + G2TLSRSASHA2562020CA1-1.crt.pem;\r\ + \n#/certificate/import file-name=DigiCertGlobalG2TLSRSASHA2562020CA1-1.crt\ + .pem passphrase=\"\";\r\ + \n# Quad9\r\ + \n#/tool/fetch mode=https url=\"https://cacerts.digicert.com/DigiCertGloba\ + lG3TLSECCSHA3842020CA1-1.crt.pem\"\r\ + \n#/certificate/import file-name=DigiCertGlobalG3TLSECCSHA3842020CA1-1.crt\ + .pem passphrase=\"\";\r\ + \n\r\ + \n:global GlobalScriptsUrl;\r\ + \n#google\r\ + \n:local CertName \"DigiCert-Global-Root-CA.pem\";\r\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \"certs/Master/\" . \$C\ + ertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"DigiCert-Global-Root-CA\" [ find where common-na\ + me=\"DigiCert Global Root CA\" ];\r\ + \n\r\ + \n:set CertName \"DigiCert-Assured-ID-Root-CA.pem\";\r\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \"certs/Master/\" . \$C\ + ertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"DigiCert-Assured-ID-Root-CA\" [ find where commo\ + n-name=\"DigiCert Assured ID Root CA\" ];\r\ + \n\r\ + \n:set CertName \"DigiCert-Assured-ID-Root-G2.pem\";\r\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \"certs/Master/\" . \$C\ + ertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"DigiCert-Assured-ID-Root-G2\" [ find where commo\ + n-name=\"DigiCert Assured ID Root G3\" ];\r\ + \n\r\ + \n:set CertName \"DigiCert-Assured-ID-Root-G3.pem\";\r\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \"certs/Master/\" . \$C\ + ertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"DigiCert-Assured-ID-Root-G3\" [ find where commo\ + n-name=\"DigiCert Assured ID Root G3\" ];\r\ + \n\r\ + \n:set CertName \"DigiCert-Global-G2-TLS-RSA-SHA256-2020-CA1.pem\";\r\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \"certs/Master/\" . \$C\ + ertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"DigiCert-Global-G2-TLS-RSA-SHA256-2020-CA1\" [ f\ + ind where common-name=\"DigiCert Global G2 TLS RSA SHA256 2020 CA1\" ];\r\ + \n\r\ + \n:set CertName \"DigiCert-Global-G3-TLS-ECC-SHA384-2020-CA1.pem\";\r\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \"certs/Master/\" . \$C\ + ertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"DigiCert-Global-G3-TLS-ECC-SHA384-2020-CA1\" [ f\ + ind where common-name=\"DigiCert Global G3 TLS ECC SHA384 2020 CA1\" ];\r\ + \n\r\ + \n:set CertName \"DigiCert-Global-Root-G2.pem\";\r\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \"certs/Master/\" . \$C\ + ertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"DigiCert-Global-Root-G2\" [ find where common-na\ + me=\"DigiCert Global Root G2\" ];\r\ + \n\r\ + \n:set CertName \"DigiCert-Global-Root-G3.pem\";\r\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \"certs/Master/\" . \$C\ + ertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"DigiCert-Global-Root-G3\" [ find where common-na\ + me=\"DigiCert Global Root G3\" ];\r\ + \n\r\ + \n:set CertName \"DigiCert-TLS-ECC-P384-Root-G5.pem\";\r\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \"certs/Master/\" . \$C\ + ertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"DigiCert-TLS-ECC-P384-Root-G5\" [ find where com\ + mon-name=\"DigiCert TLS ECC P384 Root G5\" ];\r\ + \n\r\ + \n:set CertName \"DigiCert-TLS-RSA4096-Root-G5.pem\";\r\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \"certs/Master/\" . \$C\ + ertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"DigiCert-TLS-RSA4096-Root-G5\" [ find where comm\ + on-name=\"DigiCert TLS RSA4096 Root G5\" ];\r\ + \n\r\ + \n:set CertName \"DigiCert-Trusted-Root-G4.pem\";\r\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \"certs/Master/\" . \$C\ + ertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"DigiCert-Trusted-Root-G4\" [ find where common-n\ + ame=\"DigiCert Trusted Root G4\" ];\r\ + \n\r\ + \n:set CertName \"GTS-Root-R4.pem\";\r\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \"certs/Master/\" . \$C\ + ertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"GTS-Root-R4\" [ find where common-name=\"GTS Roo\ + t R4\" ];\r\ + \n\r\ + \n:set CertName \"Go-Daddy-Root-Certificate-Authority-G2.pem\";\r\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \"certs/Master/\" . \$C\ + ertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"Go-Daddy-Root-Certificate-Authority-G2\" [ find \ + where common-name=\"Go Daddy Root Certificate Authority - G2\" ];\r\ + \n\r\ + \n:set CertName \"ISRG-Root-X1.pem\";\r\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \"certs/Master/\" . \$C\ + ertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"ISRG-Root-X1\" [ find where common-name=\"ISRG R\ + oot X1\" ];\r\ + \n\r\ + \n:set CertName \"Root-YE.pem\";\r\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \"certs/Master/\" . \$C\ + ertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"Root-YE\" [ find where common-name=\"Root YE\" ]\ + ;\r\ + \n\r\ + \n:set CertName \"Starfield-Root-Certificate-Authority-G2.pem\";\r\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \"certs/Master/\" . \$C\ + ertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"Starfield-Root-Certificate-Authority-G2\" [ find\ + \_where common-name=\"Starfield Root Certificate Authority - G2\" ];\r\ + \n\r\ + \n:set CertName \"USERTrust-RSA-Certification-Authority.pem\";\r\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \"certs/Master/\" . \$C\ + ertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"USERTrust-RSA-Certification-Authority\" [ find w\ + here common-name=\"USERTrust RSA Certification Authority\" ];\r\ + \n\r\ + \n#/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n#/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n#:set CertName \"GTS-Root-RX.pem\";\r\ + \n#/tool/fetch mode=https url=(\$AmScriptsUrl . \"certs/\" . \$CertName);\ + \r\ + \n#/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n#internet\r\ + \n#/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n#:set CertName \"ISRG-Root-X2.pem\";\r\ + \n#/tool/fetch mode=https url=(\$AmScriptsUrl . \"certs/\" . \$CertName);\ + \r\ + \n#/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n\r\ + \n\r\ + \n#/ip/dns/set allow-remote-requests=yes doh-max-concurrent-queries=100 do\ + h-max-server-connections=20 use-doh-server=https://security.cloudflare-dns\ + .com/dns-query verify-doh-cert=yes;\r\ + \n#/ip/dns/static remove [find where address=1.1.1.1];\r\ + \n#/ip/dns/static add address=1.1.1.1 name=security.cloudflare-dns.com com\ + ment=\"cloudflare-dns IPv4 1\";\r\ + \n#/ip/dns/ static remove [find where address=1.0.0.1];\r\ + \n#/ip/dns/static add address=1.0.0.1 name=security.cloudflare-dns.com com\ + ment=\"cloudflare-dns IPv4 2\"\r\ + \n#/ip dns static add address=2606:4700:4700::1111 name=security.cloudflar\ + e-dns.com type=AAAA\r\ + \n#/ip dns static add address=2606:4700:4700::1001 name=security.cloudflar\ + e-dns.com type=AAAA\r\ + \n#/ip/dns set servers=\"1.0.0.1, 8.8.4.4\";\r\ + \n#/ip/dns set servers=\"\";" +add dont-require-permissions=no name=script1 owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="/\ + tool/netwatch/add comment=\"doh-fallback, doh-url=https://security.cloudfl\ + are-dns.com/dns-query, doh-cert=DigiCert Global Root CA, notify, name=Clou\ + dFlare-doh IPv4 1\" host=1.1.1.1;\r\ + \n/tool/netwatch/add comment=\"doh, doh-url=https://security.cloudflare-dn\ + s.com/dns-query, doh-cert=DigiCert Global Root CA, notify, name=CloudFlare\ + -doh IPv4 2\" host=1.0.0.1;\r\ + \n/tool/netwatch/add comment=\"doh-fallback, dns-fallback, doh-url=https:/\ + /dns.google/dns-query, doh-cert=DigiCert Global Root G2, notify, name=Goog\ + le-doh IPv4 1\" host=8.8.8.8;\r\ + \n/tool/netwatch/add comment=\"doh-fallback, dns-fallback, doh-url=https:/\ + /dns.google/dns-query, doh-cert=DigiCert Global Root G2, notify, name=Goog\ + le-doh IPv4 2\" host=8.8.4.4;\r\ + \n/tool/netwatch/add comment=\"doh-fallback, dns-fallback, doh-url=https:/\ + /dns.quad9.net/dns-query, doh-cert=DigiCert Global Root G3, notify, name=C\ + uad9-doh IPv4 1\" host=9.9.9.9;\r\ + \n/tool/netwatch/add comment=\"doh-fallback, dns-fallback, doh-url=https:/\ + /dns.quad9.net/dns-query, doh-cert=DigiCert Global Root G3, notify, name=C\ + uad9-doh IPv4 2\" host=149.112.112.112;\r\ + \n\r\ + \n/tool/netwatch/add comment=\"dns, notify, name=ns1.unet.ws\" host=91.192\ + .189.2;" +add dont-require-permissions=no name=script2 owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + \r\ + \n\r\ + \n:global InspectVar;\r\ + \n#:global RouterBoard;\r\ + \n#:do {:set RouterBoard [[ :parse \"/system/routerboard/get\" ]]} on-erro\ + r={}\r\ + \n#:global Resources;\r\ + \n#:do {:set Resources [[ :parse \"/system/resource/get\" ]]} on-error={}\ + \r\ + \n\r\ + \n#:global Updates;\r\ + \n#:do {:set Updates [[ :parse \"/system/package/update/get\" ]]} on-error\ + ={}\r\ + \n\r\ + \n#:global PkgUpdStatus \"undefined\";\r\ + \n#:local Update [/system/package/update/get];\r\ + \n#:retry command={:set PkgUpdStatus (\$Update->\"status\")} delay=200ms m\ + ax=5 on-error={};\r\ + \n\r\ + \n#:log warning [\$InspectVar \$RouterBoard];\r\ + \n#:put [\$InspectVar \$RouterBoard];\r\ + \n\r\ + \n#:retry command={/system/package/update check-for-updates without-paging\ + \_as-value} delay=300ms max=5 on-error={};\r\ + \n\r\ + \n#:global arrDeviceInfo ({});\r\ + \n#:local arrDeviceInfo ({\"section\":{\"key\":\"\"; \"value\":\"\";};});\ + \r\ + \n#:set (\$arrDeviceInfo->\"RouterBoard\") [[ :parse \"/system/routerboard\ + /get\" ]];\r\ + \n#:retry command={:set (\$arrDeviceInfo->\"Updates\") [[ :parse \"/system\ + /package/update/get\" ]]} delay=500ms max=5 on-error={:log error (\"Error\ + \")};\r\ + \n# [:toarray {\"section\"={\"key\"=\"\"; \"value\"=\"\";} }];\r\ + \n# [:toarray \"\"];\r\ + \n:local arrDeviceInfo ({});\r\ + \n\r\ + \n:set (\$arrDeviceInfo->\"devUpdates\") {\"channel\"; \"stable\";};\r\ + \n#:do {:set (arrDeviceInfo->\"Updates\") [[ :parse \"/system/package/upda\ + te/get\" ]]} on-error={:log error (\$error)}\r\ + \n\$InspectVar \$arrDeviceInfo;\r\ + \n" +/user group +add name=backup policy="telnet,ssh,ftp,read,write,policy,test,sniff,sensitive,\ + !local,!reboot,!winbox,!password,!web,!api,!romon,!rest-api" +/interface bridge +add admin-mac=48:8F:5A:8E:1A:BC auto-mac=no mlag-peer-port="ether1 - Unet" \ + name=Bridge-LAN port-cost-mode=short +/interface wireless +# managed by CAPsMAN +# channel: 2422/20-Ce/gn(18dBm), SSID: vados, local forwarding +set [ find default-name=wlan1 ] ampdu-priorities=0,1,2,3,4,5,6,7 band=\ + 2ghz-b/g/n basic-rates-a/g=\ + 6Mbps,9Mbps,12Mbps,18Mbps,24Mbps,36Mbps,48Mbps,54Mbps basic-rates-b=\ + 1Mbps,2Mbps,5.5Mbps,11Mbps channel-width=20/40mhz-XX country=belarus \ + disabled=no frequency=auto hw-protection-mode=rts-cts mode=ap-bridge \ + rate-set=configured skip-dfs-channels=10min-cac ssid=vados \ + wds-default-bridge=Bridge-LAN wds-mode=dynamic-mesh wireless-protocol=\ + 802.11 wmm-support=enabled wps-mode=disabled +# managed by CAPsMAN +# channel: 5260/20-Ceee/ac/DP(18dBm), SSID: vados5g, local forwarding +set [ find default-name=wlan2 ] ampdu-priorities=0,1,2,3,4,5,6,7 band=\ + 5ghz-a/n/ac basic-rates-a/g=\ + 6Mbps,9Mbps,12Mbps,18Mbps,24Mbps,36Mbps,48Mbps,54Mbps channel-width=\ + 20/40/80mhz-XXXX country=belarus disabled=no frequency=auto \ + hw-protection-mode=rts-cts mode=ap-bridge rate-set=configured \ + skip-dfs-channels=10min-cac ssid=vados5g wds-default-bridge=Bridge-LAN \ + wds-mode=dynamic-mesh wireless-protocol=802.11 wmm-support=enabled \ + wps-mode=disabled +/interface wireless nstreme +# managed by CAPsMAN +# channel: 2422/20-Ce/gn(18dBm), SSID: vados, local forwarding +set wlan1 enable-nstreme=yes +# managed by CAPsMAN +# channel: 5260/20-Ceee/ac/DP(18dBm), SSID: vados5g, local forwarding +set wlan2 enable-nstreme=yes +/caps-man manager +set enabled=yes +/caps-man provisioning +add action=create-dynamic-enabled hw-supported-modes=gn master-configuration=\ + cfg-2ghz name-format=prefix-identity name-prefix=2ghz +add action=create-dynamic-enabled hw-supported-modes=ac master-configuration=\ + cfg-5ghz-ac name-format=prefix-identity name-prefix=5ghz-ac +add action=create-dynamic-enabled hw-supported-modes=an master-configuration=\ + cfg-5ghz-an name-format=prefix-identity name-prefix=5ghz-an +/certificate settings +set builtin-trust-store="ipsec,wpa-eap,capsman,fetch,sstp,ovpn,radius,userman,\ + openflow,tr069,dot1x,dns,www,api,reverse-proxy" crl-store=system +/interface bridge port +add bridge=Bridge-LAN disabled=yes interface="ether1 - Unet" +add bridge=Bridge-LAN interface=ether2 +add bridge=Bridge-LAN interface=ether3 +add bridge=Bridge-LAN interface=ether4 +add bridge=Bridge-LAN interface=ether5 +add bridge=Bridge-LAN interface=wlan2 +add bridge=Bridge-LAN interface=wlan1 +/ip firewall connection tracking +set udp-timeout=10s +/ip neighbor discovery-settings +set discover-interface-list=LAN +/ip settings +set max-neighbor-entries=8192 secure-redirects=no +/ipv6 settings +set allow-fast-path=no disable-ipv6=yes disable-link-local-address=yes \ + forward=no max-neighbor-entries=8192 +/interface detect-internet +set detect-interface-list=WAN internet-interface-list=WAN lan-interface-list=\ + LAN wan-interface-list=WAN +/interface l2tp-server server +set authentication=mschap2 use-ipsec=yes +/interface list member +add interface="ether1 - Unet" list=WAN +add interface=Bridge-LAN list=LAN +/interface ovpn-server server +add auth=sha1,md5 mac-address=FE:82:A5:78:8E:84 name=ovpn-server1 +/interface wifi configuration +add channel=2G-AX datapath=xs-DataPath disabled=no mode=ap name=2G-AX \ + security=sec2g security.ft=yes .ft-over-ds=yes ssid=vados +add channel=2G-N datapath=xs-DataPath disabled=no mode=ap name=2G-N security=\ + sec2g security.ft=yes .ft-over-ds=yes ssid=vados +add channel=5G-AC datapath=xs-DataPath disabled=no mode=ap name=5G-AC \ + security=sec5G security.authentication-types="" .ft=yes .ft-over-ds=yes \ + ssid=vados +add channel=2G-G datapath=xs-DataPath disabled=no mode=ap name=2G-G security=\ + sec2g security.authentication-types="" .ft=yes .ft-over-ds=yes ssid=vados +/interface wifi datapath +add bridge=Bridge-LAN disabled=no interface-list=all name=xs-DataPath +/interface wireguard peers +add allowed-address=10.8.0.2/32,0.0.0.0/0 client-allowed-address=0.0.0.0/0 \ + endpoint-address=89.110.101.17 endpoint-port=29185 interface=WG name=\ + MikroVados persistent-keepalive=10s public-key=\ + "64Y25EUZQQt8EIeAJYD8qWt+te8qvGEepnswdBgmzlY=" +/interface wireless cap +# +set bridge=Bridge-LAN caps-man-addresses=10.30.30.10 \ + caps-man-certificate-common-names=CAPsMAN-51B25E507D07 certificate=\ + CAP-488F5A8E1ABC discovery-interfaces=ether2 enabled=yes interfaces=\ + wlan1,wlan2 lock-to-caps-man=yes +/ip address +add address=10.30.30.81/24 interface=Bridge-LAN network=10.30.30.0 +add address=10.8.0.2/24 interface=WG network=10.8.0.0 +/ip dhcp-client +add add-default-route=special-classless default-route-distance=2 \ + default-route-tables=main interface="ether1 - Unet" name=client1 \ + use-peer-dns=no +/ip dhcp-server +add add-arp=yes address-pool=dhcp always-broadcast=yes bootp-support=none \ + dhcp-option-set=domain-search-set interface=Bridge-LAN lease-time=10m \ + name=masterDHCP server-address=10.30.30.81 +/ip dhcp-server config +set accounting=no +/ip dhcp-server lease +add address=10.30.30.101 client-id=1:48:8f:5a:8e:ee:a8 mac-address=\ + 48:8F:5A:8E:EE:A8 server=masterDHCP +add address=10.30.30.107 client-id=1:f0:de:f1:91:d:1e mac-address=\ + F0:DE:F1:91:0D:1E server=masterDHCP +add address=10.30.30.83 client-id=1:0:80:77:ec:43:86 mac-address=\ + 00:80:77:EC:43:86 server=masterDHCP +add address=10.30.30.70 dhcp-option=domain-search-list,HostName \ + dhcp-option-set=HP1505n mac-address=00:1E:0B:1A:88:8D server=masterDHCP +add address=10.30.30.50 client-id=1:4:7c:16:36:f5:37 mac-address=\ + 04:7C:16:36:F5:37 server=masterDHCP +add address=10.30.30.71 client-id=1:10:2d:41:2c:20:c2 mac-address=\ + 10:2D:41:2C:20:C2 server=masterDHCP +add address=10.30.30.61 client-id=1:10:8:c1:81:59:5f mac-address=\ + 10:08:C1:81:59:5F server=masterDHCP +add address=10.30.30.72 client-id=1:10:38:1f:d2:5f:13 mac-address=\ + 10:38:1F:D2:5F:13 server=masterDHCP +add address=10.30.30.99 client-id=1:10:b1:df:e9:d0:d5 mac-address=\ + 10:B1:DF:E9:D0:D5 server=masterDHCP +add address=10.30.30.111 client-id=1:fe:2:52:be:3f:16 mac-address=\ + FE:02:52:BE:3F:16 server=masterDHCP +add address=10.30.30.92 client-id=1:d4:6d:6d:fd:e5:49 mac-address=\ + D4:6D:6D:FD:E5:49 server=masterDHCP +add address=10.30.30.93 client-id=1:7e:8b:1e:cb:b8:cb mac-address=\ + CC:42:10:12:46:94 server=masterDHCP +add address=10.30.30.94 client-id=1:50:cc:f8:85:96:a mac-address=\ + 50:CC:F8:85:96:0A server=masterDHCP +add address=10.30.30.82 client-id=1:e4:18:6b:58:34:ab mac-address=\ + E4:18:6B:58:34:AB server=masterDHCP +add address=10.30.30.75 client-id=1:0:27:15:41:97:a9 mac-address=\ + 00:27:15:41:97:A9 server=masterDHCP +add address=10.30.30.77 dhcp-option=HostName dhcp-option-set=StartLife1 \ + mac-address=C4:82:E1:03:49:10 server=masterDHCP +add address=10.30.30.73 client-id=1:10:38:1f:82:81:f2 mac-address=\ + 10:38:1F:82:81:F2 server=masterDHCP +add address=10.30.30.95 client-id=1:88:ae:dd:60:39:54 dhcp-option=HostName \ + dhcp-option-set=VADOS-NUC mac-address=88:AE:DD:60:39:54 server=masterDHCP +add address=10.30.30.98 client-id=1:c8:5b:76:d8:cc:bf dhcp-option=HostName \ + dhcp-option-set=VADOS-LEN mac-address=C8:5B:76:D8:CC:BF server=masterDHCP +add address=10.30.30.96 client-id=iPhone mac-address=4A:91:ED:0E:1F:39 \ + server=masterDHCP +add address=10.30.30.74 client-id=MiTV dhcp-option=HostName dhcp-option-set=\ + MiTV mac-address=20:72:A9:D3:34:36 server=masterDHCP +add address=10.30.30.30 dhcp-option=HostName dhcp-option-set=miller \ + mac-address=F0:75:5D:1E:5F:71 server=masterDHCP +add address=10.30.30.100 client-id=iVados dhcp-option=HostName \ + dhcp-option-set="=\"Client ID\"" mac-address=DE:4D:72:F3:1A:9F server=\ + masterDHCP +/ip dhcp-server network +add address=10.30.30.0/24 caps-manager=10.30.30.10 dhcp-option=\ + domain-search-list dhcp-option-set=domain-search-set dns-server=\ + 10.30.30.81 domain=WORKGROUP gateway=10.30.30.81 netmask=24 ntp-server=\ + 10.30.30.81,10.30.30.10 wins-server=10.30.30.95,10.30.30.98 +/ip dns +set allow-remote-requests=yes cache-max-ttl=1d doh-max-concurrent-queries=100 \ + doh-max-server-connections=20 servers=8.8.8.8,8.8.4.4 verify-doh-cert=yes +/ip dns static +add address=10.30.30.33 name=ros.vados.ru type=A +add address=10.30.30.95 name=vados-nuc type=A +add address=10.30.30.33 name=amster-nuc type=A +add address=10.30.30.33 comment=AMSTER name=amster.vados.ru type=A +add address=10.30.30.33 name=amster type=A +add address=10.30.30.33 name=amster-reg type=A +add address=10.30.30.33 name=mng.vados.ru type=A +add address=10.30.30.33 name=mgr.vados.ru type=A +add address=10.30.30.33 name=prt.vados.ru type=A +add address=10.30.30.33 name=reg.vados.ru type=A +add address=10.30.30.33 match-subdomain=yes name=mikrots.vados.ru type=A +add address=10.30.30.33 name=oxidized.vados.ru type=A +add address=8.8.4.4 comment="Google-dns IPv4 2" name=dns.google type=A +add address=8.8.8.8 comment="Google-dns IPv4 1" name=dns.google type=A +add address=10.30.30.30 comment=MILLER name=miller.vados.ru type=A +add address=10.30.30.30 name=MILLER-LEN type=A +add address=10.30.30.30 name=miller type=A +add address=1.0.0.1 comment="CloudFlare-doh IPv4 2" name=\ + security.cloudflare-dns.com type=A +add address=1.1.1.1 comment="CloudFlare-doh IPv4 1" name=\ + security.cloudflare-dns.com type=A +add address=9.9.9.9 comment="Cuad9-dns IPv4 1" disabled=yes name=\ + dns.quad9.net type=A +add address=149.112.112.112 comment="Cuad9-dns IPv4 2" name=dns.quad9.net \ + type=A +add address=91.192.189.2 comment=Unet-DNS disabled=yes name=ns1.unet.ws type=\ + A +add address=10.30.30.81 comment=LocalNet name=MikroVados type=A +add address=10.30.30.10 name=MikroNUC type=A +add address=10.30.30.86 name=MikroYellow type=A +add address=10.30.30.85 name=MikroMic type=A +add address=10.30.30.95 name=VADOS-NUC type=A +add address=10.30.30.98 name=VADOS-LEN type=A +add address=10.30.30.20 name=garage type=A +add address=9.9.9.9 comment="Cuad9-dns IPv4 1" disabled=yes name=\ + dns.quad9.net type=A +add address=91.192.189.2 comment=Unet-DNS disabled=yes name=ns1.unet.ws type=\ + A +/ip firewall address-list +add address=91.215.120.206 list=TRUSTED +add address=185.71.70.78 disabled=yes list=TRUSTED +add address=176.53.203.171 disabled=yes list=TRUSTED +add address=176.53.203.170 disabled=yes list=TRUSTED +add address=176.53.202.194 disabled=yes list=TRUSTED +add address=10.30.30.100-255 list=KIDS +add address=8.8.4.0/24 list=YouTube +add address=8.8.8.0/24 list=YouTube +add address=8.34.208.0/20 list=YouTube +add address=8.35.192.0/20 list=YouTube +add address=23.236.48.0/20 list=YouTube +add address=23.251.128.0/19 list=YouTube +add address=34.0.0.0/15 list=YouTube +add address=34.2.0.0/16 list=YouTube +add address=34.3.0.0/23 list=YouTube +add address=34.3.3.0/24 list=YouTube +add address=34.3.4.0/24 list=YouTube +add address=34.3.8.0/21 list=YouTube +add address=34.3.16.0/20 list=YouTube +add address=34.3.32.0/19 list=YouTube +add address=34.3.64.0/18 list=YouTube +add address=34.4.0.0/14 list=YouTube +add address=34.8.0.0/13 list=YouTube +add address=34.16.0.0/12 list=YouTube +add address=34.32.0.0/11 list=YouTube +add address=34.64.0.0/10 list=YouTube +add address=34.128.0.0/10 list=YouTube +add address=35.184.0.0/13 list=YouTube +add address=35.192.0.0/14 list=YouTube +add address=35.196.0.0/15 list=YouTube +add address=35.198.0.0/16 list=YouTube +add address=35.199.0.0/17 list=YouTube +add address=35.199.128.0/18 list=YouTube +add address=35.200.0.0/13 list=YouTube +add address=35.208.0.0/12 list=YouTube +add address=35.224.0.0/12 list=YouTube +add address=35.240.0.0/13 list=YouTube +add address=57.140.192.0/18 list=YouTube +add address=64.15.112.0/20 list=YouTube +add address=64.233.160.0/19 list=YouTube +add address=66.22.228.0/23 list=YouTube +add address=66.102.0.0/20 list=YouTube +add address=66.249.64.0/19 list=YouTube +add address=70.32.128.0/19 list=YouTube +add address=72.14.192.0/18 list=YouTube +add address=74.125.0.0/16 list=YouTube +add address=104.154.0.0/15 list=YouTube +add address=104.196.0.0/14 list=YouTube +add address=104.237.160.0/19 list=YouTube +add address=107.167.160.0/19 list=YouTube +add address=107.178.192.0/18 list=YouTube +add address=108.59.80.0/20 list=YouTube +add address=108.170.192.0/18 list=YouTube +add address=108.177.0.0/17 list=YouTube +add address=130.211.0.0/16 list=YouTube +add address=136.22.160.0/20 list=YouTube +add address=136.22.176.0/21 list=YouTube +add address=136.22.184.0/23 list=YouTube +add address=136.22.186.0/24 list=YouTube +add address=142.250.0.0/15 list=YouTube +add address=146.148.0.0/17 list=YouTube +add address=152.65.208.0/22 list=YouTube +add address=152.65.214.0/23 list=YouTube +add address=152.65.218.0/23 list=YouTube +add address=152.65.222.0/23 list=YouTube +add address=152.65.224.0/19 list=YouTube +add address=162.120.128.0/17 list=YouTube +add address=162.216.148.0/22 list=YouTube +add address=162.222.176.0/21 list=YouTube +add address=172.110.32.0/21 list=YouTube +add address=172.217.0.0/16 list=YouTube +add address=172.253.0.0/16 list=YouTube +add address=173.194.0.0/16 list=YouTube +add address=173.255.112.0/20 list=YouTube +add address=192.158.28.0/22 list=YouTube +add address=192.178.0.0/15 list=YouTube +add address=193.186.4.0/24 list=YouTube +add address=199.36.154.0/23 list=YouTube +add address=199.36.156.0/24 list=YouTube +add address=199.192.112.0/22 list=YouTube +add address=199.223.232.0/21 list=YouTube +add address=207.223.160.0/20 list=YouTube +add address=208.65.152.0/22 list=YouTube +add address=208.68.108.0/22 list=YouTube +add address=208.81.188.0/22 list=YouTube +add address=208.117.224.0/19 list=YouTube +add address=209.85.128.0/17 list=YouTube +add address=216.58.192.0/19 list=YouTube +add address=216.73.80.0/20 list=YouTube +add address=216.239.32.0/19 list=YouTube +add address=2ip.ru list=Test +add address=157.240.247.174 list=Instagram +add address=46.53.178.107 list=Instagram +add address=179.60.195.174 list=Instagram +add address=157.240.205.174 list=Instagram +add address=31.13.24.0/21 list=Instagram +add address=31.13.64.0/18 list=Instagram +add address=45.64.40.0/22 list=Instagram +add address=66.220.144.0/20 list=Instagram +add address=69.63.176.0/20 list=Instagram +add address=69.171.224.0/19 list=Instagram +add address=74.119.76.0/22 list=Instagram +add address=103.4.96.0/22 list=Instagram +add address=129.134.0.0/16 list=Instagram +add address=157.240.0.0/16 list=Instagram +add address=173.252.64.0/18 list=Instagram +add address=179.60.192.0/22 list=Instagram +add address=185.60.216.0/22 list=Instagram +add address=204.15.20.0/22 list=Instagram +add address=157.240.200.63 list=Instagram +add address=185.60.219.63 list=Instagram +add address=129.134.31.12 list=Instagram +add address=66.81.203.132 list=Instagram +add address=185.89.218.12 list=Instagram +add address=31.13.66.63 list=Instagram +add address=84.15.65.162 list=Instagram +add address=68.66.224.28 list=Instagram +add address=157.240.253.63 list=Instagram +add address=83.174.11.224 list=Instagram +add address=157.240.9.52 list=Instagram +add address=157.240.252.174 list=Instagram +add address=157.240.195.63 list=Instagram +add address=31.13.71.52 list=Instagram +add address=57.144.110.192 list=Instagram +add address=157.240.252.17 list=Instagram +add address=84.15.66.97 list=Instagram +add address=217.168.6.33 list=Instagram +add address=31.13.83.52 list=Instagram +add address=157.240.241.63 list=Instagram +add address=129.134.30.12 list=Instagram +add address=185.89.219.12 list=Instagram +add address=157.240.252.10 list=Instagram +add address=157.240.201.63 list=Instagram +add address=66.81.203.197 list=Instagram +add address=179.60.195.52 list=Instagram +add address=66.81.203.7 list=Instagram +add address=216.40.34.41 list=Instagram +add address=157.240.202.63 list=Instagram +add address=157.240.229.63 list=Instagram +add address=157.240.252.63 list=Instagram +add address=31.13.72.53 list=Instagram +add address=124.108.16.224 list=Instagram +add address=157.240.205.63 list=Instagram +add address=92.46.37.96 list=Instagram +add address=157.240.247.63 list=Instagram +add address=157.240.234.63 list=Instagram +add address=157.240.235.63 list=Instagram +add address=87.245.208.97 list=Instagram +add address=216.58.192.0/19 list=Instagram +add address=209.85.128.0/17 list=Instagram +add address=198.105.240.0/20 list=Instagram +add address=173.194.0.0/16 list=Instagram +add address=172.217.0.0/16 list=Instagram +add address=142.250.0.0/15 list=Instagram +add address=108.177.0.0/17 list=Instagram +add address=87.245.197.140 list=Instagram +add address=74.125.0.0/16 list=Instagram +add address=64.233.160.0/19 list=Instagram +add address=157.240.0.1 list=Instagram +add address=157.240.238.63 list=Instagram +add address=157.240.238.174 list=Instagram +add address=157.240.0.63 list=Instagram +add address=157.240.224.63 list=Instagram +add address=157.240.224.174 list=Instagram +add address=157.240.251.36 list=Instagram +add address=157.240.253.12 list=Instagram +add address=157.240.253.35 list=Instagram +add address=157.240.238.13 list=Instagram +add address=157.240.238.56 list=Instagram +add address=157.240.238.175 list=Instagram +add address=57.144.112.141 list=Instagram +add address=157.240.251.60 list=Instagram +add address=157.240.251.128 list=Instagram +add address=157.240.238.5 list=Instagram +add address=157.240.253.13 list=Instagram +add address=157.240.253.5 list=Instagram +add address=157.240.238.2 list=Instagram +add address=157.240.238.37 list=Instagram +add address=157.240.251.5 list=Instagram +add address=157.240.251.34 list=Instagram +add address=57.144.112.1 list=Instagram +add address=157.240.238.54 list=Instagram +add address=129.134.26.123 list=Instagram +add address=157.240.252.3 list=Instagram +add address=31.13.84.4 list=Instagram +add address=157.240.224.12 list=Instagram +add address=157.240.238.4 list=Instagram +add address=157.240.0.13 list=Instagram +add address=3.33.139.32 list=Instagram +add address=157.240.0.35 list=Instagram +add address=157.240.238.14 list=Instagram +add address=157.240.238.60 list=Instagram +add address=57.144.112.145 list=Instagram +add address=157.240.251.35 list=Instagram +add address=151.101.84.159 list=Twitter +add address=pbs.twimg.com list=Twitter +add address=89.110.101.17 comment=VDSIna list=TRUSTED +add address=10.8.0.0/24 comment="WG VDSIna" list=TRUSTED +add address=ikus.pesc.ru comment=ikus.pesc.ru list=NoVdsina +add address=love.ru comment=love.ru list=NoVdsina +add address=gosuslugi.ru comment=gosuslugi.ru list=NoVdsina +add address=pochta.ru comment=pochta.ru list=NoVdsina +add address=vdsina.com list=NoVdsina +add address=vdsina.ru list=NoVdsina +add address=youla.ru list=NoVdsina +add address=kupiprodai.ru list=NoVdsina +add address=myip.ru list=Test +add address=geoip.co list=NoVdsina +add address=x.com list=Twitter +add address=facebook.com list=facebook +add address=fbcd.net list=facebook +add address=comp-lenta.ru list=NoVdsina +add address=128.85.102.70 comment=update.microsoft.com list=\ + windowsupdateslist +add address=wu-b-net.trafficmanager.net. comment=\ + ctldl.windowsupdate.com.delivery.microsoft.com list=windowsupdateslist +add address=ctldl.windowsupdate.com.delivery.microsoft.com. comment=\ + ctldl.windowsupdate.com list=windowsupdateslist +add address=redir.update.msft.com.trafficmanager.net. comment=\ + update.microsoft.com list=windowsupdateslist +add address=geo.prod.do.dsp.trafficmanager.net. comment=\ + geo.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=13.74.139.29 comment=array605.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=kv801.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + kv801.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=e12437.d.akamaiedge.net. comment=\ + kv801.prod.do.dsp.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=displaycatalog-rp.md.mp.microsoft.com.akadns.net. comment=\ + displaycatalog.mp.microsoft.com list=windowsupdateslist +add address=rp-consumer-prod-displaycatalog-geomap.trafficmanager.net. \ + comment=displaycatalog-rp.md.mp.microsoft.com.akadns.net list=\ + windowsupdateslist +add address=sls.update.microsoft.com. comment=slscr.update.microsoft.com \ + list=windowsupdateslist +add address=glb.sls.prod.dcat.dsp.trafficmanager.net. comment=\ + sls.update.microsoft.com list=windowsupdateslist +add address=fe3.delivery.mp.microsoft.com. comment=\ + fe3cr.delivery.mp.microsoft.com list=windowsupdateslist +add address=glb.cws.prod.dcat.dsp.trafficmanager.net. comment=\ + fe3.delivery.mp.microsoft.com list=windowsupdateslist +add address=fe2cr.update.msft.com.trafficmanager.net. comment=\ + fe2cr.update.microsoft.com list=windowsupdateslist +add address=download.windowsupdate.com.delivery.microsoft.com. comment=\ + download.windowsupdate.com list=windowsupdateslist +add address=wu-f-net.trafficmanager.net. comment=\ + download.windowsupdate.com.delivery.microsoft.com list=windowsupdateslist +add address=tsfe.trafficmanager.net. comment=\ + tsfe.trafficshaping.dsp.mp.microsoft.com list=windowsupdateslist +add address=edge.ds-c7110-microsoft.global.dns.qwilted-cds.cqloud.com. \ + comment=9.au.download.windowsupdate.com list=windowsupdateslist +add address=52.158.227.125 comment=array812.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=au.download.windowsupdate.com.delivery.microsoft.com. comment=\ + au.download.windowsupdate.com list=windowsupdateslist +add address=a767.dspw65.akamai.net. comment=\ + download.windowsupdate.com.edgesuite.net list=windowsupdateslist +add address=52.151.58.88 comment=array810.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=consumer-licensing-aks2aks.md.mp.microsoft.com.akadns.net. \ + comment=licensing.mp.microsoft.com list=windowsupdateslist +add address=licensing-prod-frontdoor-geomap.trafficmanager.net. comment=\ + consumer-licensing-aks2aks.md.mp.microsoft.com.akadns.net list=\ + windowsupdateslist +add address=star.f.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedge.f.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=cdp-f-nlu-net.trafficmanager.net. comment=\ + star.f.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=star.b.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedge.b.tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=cdp-f-tlu-net.trafficmanager.net. comment=\ + star.b.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=storeedgefd.xbetservices.akadns.net. comment=\ + storeedgefd.dsx.mp.microsoft.com list=windowsupdateslist +add address=\ + storeedgefd.dsx.mp.microsoft.com.edgekey.net.globalredir.akadns.net. \ + comment=storeedgefd.dsx.mp.microsoft.com.edgekey.net list=\ + windowsupdateslist +add address=e16646.dscg.akamaiedge.net. comment=\ + storeedgefd.dsx.mp.microsoft.com.edgekey.net.globalredir.akadns.net list=\ + windowsupdateslist +add address=40.69.76.189 comment=array621.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=bg.microsoft.map.fastly.net. comment=\ + 3.au.download.windowsupdate.com list=windowsupdateslist +add list=windowsupdateslist +add address=40.69.75.33 comment=array613.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=star.sf.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedgeextensions.sf.tlu.dl.delivery.mp.microsoft.com list=\ + windowsupdateslist +add address=cdp-f-ssl-tlu-net.trafficmanager.net. comment=\ + star.sf.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=a2033.dscd.akamai.net. comment=\ + star.sb.tlu.dl.delivery.mp.microsoft.com.edgesuite.net list=\ + windowsupdateslist +add address=13.74.138.242 comment=array602.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=dl.delivery.mp.microsoft.com.delivery.microsoft.com. comment=\ + dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=dcat-f-nlu-net.trafficmanager.net. comment=\ + dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=1d.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=1D.tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=dcat-b-tlu-net.trafficmanager.net. comment=\ + 1d.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=a122.dscg3.akamai.net. comment=\ + tlu.dl.delivery.mp.microsoft.com.edgesuite.net list=windowsupdateslist +add address=geover.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + geover.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=e10370.d.akamaiedge.net. comment=\ + geover.prod.do.dsp.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=52.232.182.21 comment=array511.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.70.77.95 comment=array519.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=a1683.dscd.akamai.net. comment=\ + dl.delivery.mp.microsoft.com-c.edgesuite.net list=windowsupdateslist +add address=consumer-collections-aks2eap.md.mp.microsoft.com.akadns.net. \ + comment=collections.mp.microsoft.com list=windowsupdateslist +add address=a1847.dscd.akamai.net. comment=\ + wildcard.f.tlu.dl.delivery.mp.microsoft.com.edgesuite.net list=\ + windowsupdateslist +add address=13.74.142.6 comment=array607.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=au.download.windowsupdate.com.edgesuite.net. comment=\ + 2.au.download.windowsupdate.com list=windowsupdateslist +add address=a767.dscg3.akamai.net. comment=\ + au.download.windowsupdate.com.edgesuite.net list=windowsupdateslist +add address=52.156.123.84 comment=array818.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.69.78.254 comment=array610.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=4.au.download.windowsupdate.com.delivery.microsoft.com. comment=\ + 4.au.download.windowsupdate.com list=windowsupdateslist +add address=cl-glcb907925.gcdn.co. comment=\ + 4.au.download.windowsupdate.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=52.167.167.111 comment=array510.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=40.69.70.43 comment=array623.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=tsfe.trafficshaping.dsp.mp.microsoft.com.delivery.microsoft.com. \ + comment=tsfe.trafficshaping.dsp.mp.microsoft.com list=windowsupdateslist +add address=ts-frontend.trafficmanager.net. comment=\ + tsfe.trafficshaping.dsp.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=40.69.75.248 comment=array616.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.69.74.84 comment=array615.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=sds.trafficmanager.net. comment=software-download.microsoft.com \ + list=windowsupdateslist +add address=40.69.74.80 comment=array611.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.175.242.182 comment=array804.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=dlc-shim.trafficmanager.net. comment=download.microsoft.com list=\ + windowsupdateslist +add address=e12671.dscd.akamaiedge.net. comment=\ + download.microsoft.com.edgekey.net list=windowsupdateslist +add address=20.187.55.34 comment=array808.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.167.231 comment=array513.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=52.167.222.13 comment=array518.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=kv601.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + kv601.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=e12358.d.akamaiedge.net. comment=\ + kv601.prod.do.dsp.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. comment=\ + tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=dcat-f-tlu-net.trafficmanager.net. comment=\ + tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=a1856.dspw65.akamai.net. comment=\ + tlu.dl.delivery.mp.microsoft.com-c.edgesuite.net list=windowsupdateslist +add address=52.167.164.252 comment=array506.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=13.74.137.54 comment=array601.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=kv501.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + kv501.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=collections-prod-frontdoor-geomap.trafficmanager.net. comment=\ + consumer-collections-aks2eap.md.mp.microsoft.com.akadns.net list=\ + windowsupdateslist +add address=52.167.160.173 comment=array509.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=40.70.77.148 comment=array516.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.200.126 comment=array507.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=52.167.167.59 comment=array508.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.69.76.172 comment=array620.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=82.202.162.184 comment=comp-lenta.ru list=NoWG +add address=smtp.mail.me.com.akadns.net. comment=smtp.mail.me.com list=NoWG +add address=17.57.155.37 comment=smtp.mail.me.com.akadns.net list=NoWG +add address=smtp.mail.me.com comment=smtp.mail.me.com list=NoVdsina +add address=40.70.76.5 comment=array514.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.186.119 comment=array618.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.177.176.186 comment=array520.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=40.70.76.27 comment=array515.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.160.43 comment=array503.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.110 comment=array817.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.142.8 comment=array614.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.138.254 comment=array603.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.167.96 comment=array501.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.69.76.215 comment=array622.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.143.200 comment=array606.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.111 comment=array818.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.112 comment=array819.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.137.53 comment=array608.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.98 comment=array805.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.96 comment=array803.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.104 comment=array811.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.101 comment=array808.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.99 comment=array806.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.17 comment=array802.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.97 comment=array804.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.103 comment=array810.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.16 comment=array801.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.70.77.177 comment=array517.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.164.84 comment=array512.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.105 comment=array812.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.107 comment=array814.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.232.161.82 comment=array502.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.108 comment=array815.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.161.91 comment=array505.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.102 comment=array809.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.109 comment=array816.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.106 comment=array813.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.117 comment=array622.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.107 comment=array612.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.108 comment=array613.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.105 comment=array610.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.113 comment=array618.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.116 comment=array621.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.98 comment=array603.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.114 comment=array619.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.111 comment=array616.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.97 comment=array602.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.106 comment=array611.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.110 comment=array615.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.119 comment=array624.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.135 comment=array514.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.97 comment=array503.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.99 comment=array604.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.61 comment=array504.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.131 comment=array510.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.132 comment=array511.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.96 comment=array601.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.104 comment=array609.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.138 comment=array517.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.60 comment=array501.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.139 comment=array518.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.118 comment=array623.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.113 comment=array820.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.103 comment=array608.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.100 comment=array807.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.129 comment=array508.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.134 comment=array513.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.62 comment=array505.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.137 comment=array516.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.101 comment=array606.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.96 comment=array502.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.130 comment=array509.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.112 comment=array617.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.100 comment=array605.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.115 comment=array620.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.136 comment=array515.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=purchase.md.mp.microsoft.com.akadns.net. comment=\ + purchase.mp.microsoft.com list=windowsupdateslist +add address=e110219.a.akamaiedge.net. comment=\ + purchase.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=72.153.5.140 comment=array519.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.141 list=windowsupdateslist +add address=72.153.5.63 comment=array506.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.128 comment=array507.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.102 comment=array607.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=storesdk.xbetservices.akadns.net. comment=\ + storesdk.dsx.mp.microsoft.com list=windowsupdateslist +add address=e16646.g.akamaiedge.net. comment=\ + storesdk.dsx.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=software-download.microsoft.com.delivery.microsoft.com. comment=\ + software-download.microsoft.com list=windowsupdateslist +add address=download.prss.microsoft.com.akamaized.net. comment=\ + software-download.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.109 comment=array614.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.133 comment=array512.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=213.180.192.0/19 comment=YandexDisk list=NoVdsina +add address=87.250.250.50 comment=YandexDisk list=NoVdsina +add address=consumer-prod-bcfd-v7-afd.trafficmanager.net. comment=\ + displaycatalog.mp.microsoft.com list=windowsupdateslist +add address=purchase-europeeap.md.mp.microsoft.com.akadns.net. comment=\ + purchase.md.mp.microsoft.com.akadns.net list=windowsupdateslist +add address=ne-az-conspurchase-mp.trafficmanager.net. comment=\ + purchase-europeeap.md.mp.microsoft.com.akadns.net list=windowsupdateslist +add address=storeedgefd.dsx.mp.microsoft.com.edgekey.net. comment=\ + cdn.storeedgefd.dsx.mp.microsoft.com list=windowsupdateslist +add address=star.f.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedge.f.tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=a1996.dscd.akamai.net. comment=\ + wildcard.f.dl.delivery.mp.microsoft.com.edgesuite.net list=\ + windowsupdateslist +add address=cp801.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + cp801.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=glb.tas02.sls-prod.dcat.dsp.mp.microsoft.com. comment=\ + tas02.sls.update.microsoft.com list=windowsupdateslist +add address=cp601.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + cp601.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=star.sb.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedgeextensions.sb.tlu.dl.delivery.mp.microsoft.com list=\ + windowsupdateslist +add address=star.sf.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedge.sf.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=cdp-f-ssl-nlu-net.trafficmanager.net. comment=\ + star.sf.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=tm-pifd-prod-gbl-weight.trafficmanager.net. comment=\ + paymentinstruments.mp.microsoft.com list=windowsupdateslist +add address=10.30.30.33 comment=NUC disabled=yes list=NoWG +add address=10.30.30.10 comment=MikroNUC list=NoWG +add address=89.110.101.17 comment=!!!VDSINA!!!! list=NoWG +add address=89.110.101.17 list=VPN-Server +add address=80.85.244.9 list=TRUSTED +add address=8.8.8.8 list=TRUSTED +add address=8.8.4.4 list=TRUSTED +add address=disc801.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + disc801.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=185.71.70.78 disabled=yes list=TRUSTED +add address=176.53.203.171 disabled=yes list=TRUSTED +add address=176.53.203.170 disabled=yes list=TRUSTED +add address=176.53.202.194 disabled=yes list=TRUSTED +add address=89.110.101.17 comment="!!!VDSina Server!!!" disabled=yes list=\ + NoVdsina +/ip firewall filter +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=12h chain=input comment="block honeypot DNS" \ + connection-state=new dst-port=53 in-interface="ether1 - Unet" protocol=\ + udp +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=4w2d chain=input connection-state=new dst-port=53 \ + in-interface="ether1 - Unet" protocol=tcp +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=4w2d chain=input comment=\ + "block honeypot ssh rdp winbox" connection-state=new dst-port=\ + 22,8291,2222 in-interface="ether1 - Unet" protocol=tcp src-address-list=\ + !TRUSTED +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=4w2d chain=input comment="block honeypot asterisk" \ + connection-state=new dst-port=5060 in-interface="ether1 - Unet" protocol=\ + udp +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=5d chain=input comment="block honeypot NTP" \ + connection-state=new dst-port=123 in-interface="ether1 - Unet" protocol=\ + udp src-address=!10.30.30.0/24 +add action=accept chain=input comment=\ + "accept NTP clients on local area network" dst-port=123 in-interface=\ + Bridge-LAN in-interface-list=LAN protocol=udp +add action=accept chain=input comment="accept WireGuard" dst-port=13231 \ + in-interface="ether1 - Unet" protocol=udp src-address-list=VPN-Server +add action=accept chain=input disabled=yes dst-port=443 in-interface=\ + "ether1 - Unet" protocol=tcp +add action=accept chain=output disabled=yes protocol=tcp src-port=443 +add action=fasttrack-connection chain=forward comment=\ + "FastTrack for non-VPN connections" connection-mark=!VPN_No_FastTrack \ + connection-state=established,related,new disabled=yes +add action=fasttrack-connection chain=forward comment="defconf: fasttrack" \ + connection-state=established,related,new disabled=yes routing-mark=\ + !To-VPN +add action=accept chain=input comment=\ + "defconf: accept established,related,untracked" connection-state=\ + established,related,untracked +add action=drop chain=input comment="defconf: drop invalid" connection-state=\ + invalid +add action=accept chain=input comment="defconf: accept ICMP" disabled=yes \ + protocol=icmp +add action=accept chain=input comment=\ + "defconf: accept to local loopback (for CAPsMAN)" disabled=yes \ + dst-address=127.0.0.1 +add action=accept chain=output disabled=yes src-address=127.0.0.1 +add action=accept chain=forward comment="defconf: accept in ipsec policy" \ + ipsec-policy=in,ipsec +add action=accept chain=forward comment="defconf: accept out ipsec policy" \ + ipsec-policy=out,ipsec +add action=accept chain=forward comment=\ + "defconf: accept established,related, untracked" connection-state=\ + established,related,untracked +add action=drop chain=forward comment="defconf: drop invalid" \ + connection-state=invalid +add action=drop chain=forward comment=\ + "defconf: drop all from WAN not DSTNATed" connection-nat-state=!dstnat \ + connection-state=new in-interface="ether1 - Unet" +add action=accept chain=input connection-state=established disabled=yes +add action=accept chain=input connection-state=related disabled=yes +add action=drop chain=input disabled=yes in-interface-list=!LAN +add action=drop chain=forward comment=\ + "Filter Rule to block FB address LIST : )" disabled=yes dst-address-list=\ + facebook +add action=drop chain=forward comment=\ + "Filter Rule to block YOUTUBE address LIST : )" disabled=yes \ + dst-address-list=YouTube +/ip firewall mangle +add action=mark-connection chain=prerouting comment=\ + "Mark VPN connections to exclude from FastTrack" in-interface=WG \ + log-prefix=Mark-VPN-FT new-connection-mark=VPN_No_FastTrack +add action=mark-routing chain=prerouting comment="Test sites" disabled=yes \ + dst-address=!10.30.30.0/24 dst-address-list=Test new-routing-mark=To-VPN \ + passthrough=no src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=Instagram dst-address=\ + !10.30.30.0/24 dst-address-list=Instagram new-routing-mark=To-VPN \ + src-address=10.30.30.0/24 src-address-list=!NoWG +add action=mark-routing chain=prerouting comment=Twitter dst-address=\ + !10.30.30.0/24 dst-address-list=Twitter new-routing-mark=To-VPN \ + src-address=10.30.30.0/24 src-address-list=!NoWG +add action=mark-routing chain=prerouting comment=YouTube dst-address=\ + !10.30.30.0/24 dst-address-list=YouTube new-routing-mark=To-VPN \ + src-address=10.30.30.0/24 src-address-list=!NoWG +add action=mark-routing chain=prerouting comment=facebook dst-address=\ + !10.30.30.0/24 dst-address-list=facebook new-routing-mark=To-VPN \ + src-address=10.30.30.0/24 src-address-list=!NoWG +add action=mark-routing chain=prerouting comment="VDSIna for All sites" \ + dst-address=!10.30.30.0/24 dst-address-list=!NoVdsina log-prefix=VPN-all \ + new-routing-mark=To-VPN src-address=10.30.30.0/24 src-address-list=!NoWG +add action=change-mss chain=forward comment="MSS on WG" new-mss=1380 \ + out-interface=WG protocol=tcp tcp-flags=syn tcp-mss=1381-65535 +add action=mark-routing chain=prerouting comment="VPN Network" dst-address=\ + 10.8.0.0/24 dst-address-list=!NoVdsina log=yes log-prefix=VPN-Net \ + new-routing-mark=To-VPN src-address=10.30.30.0/24 src-address-list=!NoWG +/ip firewall nat +add action=redirect chain=dstnat comment=\ + "FORCE DNS TO LOCAL MIKROTIK DNS SERVER" dst-port=53 protocol=tcp \ + src-address=10.30.30.0/24 to-ports=53 +add action=redirect chain=dstnat dst-port=53 protocol=udp src-address=\ + 10.30.30.0/24 to-ports=53 +add action=masquerade chain=srcnat comment=WG dst-address-list=!NoVdsina \ + in-interface=Bridge-LAN log-prefix=WG-nat out-interface=WG routing-mark=\ + To-VPN +add action=masquerade chain=srcnat comment="masquerade Default" ipsec-policy=\ + out,none out-interface="ether1 - Unet" routing-mark=!To-VPN +add action=dst-nat chain=dstnat comment=npm dst-port=81 in-interface=\ + "ether1 - Unet" protocol=tcp to-addresses=10.30.30.33 to-ports=81 +add action=dst-nat chain=dstnat comment=amster.vados.ruhttps disabled=yes \ + dst-port=443 in-interface="ether1 - Unet" protocol=tcp to-addresses=\ + 10.30.30.33 to-ports=443 +add action=dst-nat chain=dstnat comment="amster.vados.ru For Certbot HTTP" \ + dst-port=80 in-interface="ether1 - Unet" protocol=tcp to-addresses=\ + 10.30.30.33 to-ports=80 +add action=dst-nat chain=dstnat dst-port=80 in-interface="ether1 - Unet" \ + protocol=tcp to-addresses=10.30.30.33 to-ports=80 +add action=dst-nat chain=dstnat comment="Yandex.DNS Family" disabled=yes \ + dst-port=53 in-interface=Bridge-LAN protocol=udp src-address-list=KIDS \ + time=6h-15m,sun,mon,tue,wed,thu,fri,sat to-addresses=77.88.8.3 +add action=dst-nat chain=dstnat disabled=yes dst-port=53 in-interface=\ + Bridge-LAN protocol=tcp src-address-list=KIDS time=\ + 6h-15m,sun,mon,tue,wed,thu,fri,sat to-addresses=77.88.8.3 +/ip firewall raw +add action=drop chain=prerouting comment="Drop Honeypot Hackers" \ + in-interface="ether1 - Unet" src-address-list="Honeypot Hacker" +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + extras.getpagespeed.com content=extras.getpagespeed.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=linux.duke.edu \ + content=linux.duke.edu disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=vk.com \ + content=vk.com +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=ok.ru content=\ + ok.ru +add action=add-dst-to-address-list address-list=Instagram \ + address-list-timeout=none-dynamic chain=prerouting comment=Instagram \ + content=instagram.com +add action=add-dst-to-address-list address-list=Twitter address-list-timeout=\ + none-dynamic chain=prerouting comment=Twitter content=twimg.com +add action=add-dst-to-address-list address-list=Twitter address-list-timeout=\ + none-dynamic chain=prerouting content=x.com +add action=add-dst-to-address-list address-list=Twitter address-list-timeout=\ + none-dynamic chain=prerouting content=twitter.com +add action=add-dst-to-address-list address-list=YouTube address-list-timeout=\ + none-dynamic chain=prerouting comment=YouTube content=youtube.com +add action=add-dst-to-address-list address-list=YouTube address-list-timeout=\ + none-dynamic chain=prerouting content=googleapis.com +add action=add-dst-to-address-list address-list=YouTube address-list-timeout=\ + none-dynamic chain=prerouting content=ggpht.com +add action=add-dst-to-address-list address-list=YouTube address-list-timeout=\ + none-dynamic chain=prerouting content=youtu.be +add action=add-dst-to-address-list address-list=YouTube address-list-timeout=\ + none-dynamic chain=prerouting content=ytimg.com +add action=add-dst-to-address-list address-list=YouTube address-list-timeout=\ + none-dynamic chain=prerouting content=googlevideo.com +add action=add-dst-to-address-list address-list=YouTube address-list-timeout=\ + none-dynamic chain=prerouting content=gstatic.com +add action=add-dst-to-address-list address-list=YouTube address-list-timeout=\ + none-dynamic chain=prerouting content=googleusercontent.com +add action=add-dst-to-address-list address-list=YouTube address-list-timeout=\ + none-dynamic chain=prerouting content=nhacmp3youtube.com +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=rutube.ru \ + content=rutube.ru +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=me.com \ + content=me.com +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=icloud.com \ + content=icloud.com +add action=add-dst-to-address-list address-list=facebook \ + address-list-timeout=none-dynamic chain=prerouting comment=facebook \ + content=fbcd.net +add action=add-dst-to-address-list address-list=facebook \ + address-list-timeout=none-dynamic chain=prerouting content=facebook.com +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=comp-lenta.ru \ + content=comp-lenta.ru +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + smtp.mail.me.com content=smtp.mail.me.com log=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=gov.ru \ + content=gov.ru +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + r78.fssp.gov.ru content=r78.fssp.gov.ru +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=api.db-ip.com \ + content=api.db-ip.com +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + api.telegram.org content=api.telegram.org +/ip firewall service-port +set ftp disabled=yes +set tftp disabled=yes +set irc disabled=no +set sip disabled=yes +set pptp disabled=yes +set rtsp disabled=no +/ip hotspot user profile +set [ find default=yes ] address-pool=dhcp +/ip hotspot walled-garden +add server=*1 +add server=*1 +/ip ipsec settings +set accounting=no +/ip ipsec policy +set 0 disabled=yes dst-address=0.0.0.0/0 src-address=0.0.0.0/0 +/ip ipsec profile +set [ find default=yes ] dpd-interval=2m dpd-maximum-failures=5 +/ip proxy +set cache-administrator="" max-cache-size=none port=80,443 src-address=\ + 0.0.0.0 +/ip route +add disabled=no distance=3 dst-address=192.168.0.0/24 gateway=l2tp-vpn +add disabled=no distance=4 dst-address=192.168.5.0/24 gateway=l2tp-vpn +add disabled=no distance=3 dst-address=192.168.0.0/24 gateway=l2tp-vpn +add disabled=no distance=4 dst-address=192.168.5.0/24 gateway=l2tp-vpn +add disabled=no distance=1 dst-address=0.0.0.0/0 gateway=WG routing-table=\ + To-VPN scope=30 target-scope=10 +/ip service +set ftp disabled=yes +set telnet disabled=yes +set reverse-proxy disabled=yes +set ssh address=10.30.30.0/24 port=2222 +set winbox address=10.30.30.0/24 +set api address=10.30.30.0/24 disabled=yes +set api-ssl address=10.30.30.0/24 disabled=yes +set www-ssl port=18443 +set www address=10.30.30.0/24 disabled=yes port=18880 +/ip service webserver +set graphs-plain=no rest-plain=no webfig-plain=no +/ip ssh +set forwarding-enabled=both publickey-authentication-options=verify-required \ + strong-crypto=yes +/ip upnp +set enabled=yes +/ip upnp interfaces +add interface=Bridge-LAN type=internal +add interface="ether1 - Unet" type=external +/snmp community +set [ find default=yes ] addresses=10.30.30.0/24 read-access=no security=\ + private +/system clock +set time-zone-autodetect=no time-zone-name=Europe/Moscow +/system clock manual +set time-zone=+03:00 +/system identity +set name=MikroMaster +/system logging +add action=email disabled=yes regex="* added|changed|removed *" topics=\ + system,info +/system ntp client +set enabled=yes +/system ntp server +set enabled=yes manycast=yes multicast=yes use-local-clock=yes +/system ntp client servers +add address=0.ru.pool.ntp.org +add address=1.ru.pool.ntp.org +add address=2.ru.pool.ntp.org +add address=3.ru.pool.ntp.org +add address=time.google.com disabled=yes +/system scheduler +add comment="Setup Global Environment for scripts" name=AM-SetGlobalEnv \ + on-event="/system/script { run AM-GlobalConfig; run AM-GlobalFunc; }" \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-time=startup +add comment="Every Day Check For Update Scripts" interval=1d name=\ + AM-ScriptInstallUpdate on-event=\ + ":global ScriptInstallUpdate; \$ScriptInstallUpdate;" policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-time=startup +add comment="Windows Update script" disabled=yes interval=2d5m name=\ + WU-script-run-schedule on-event=WU-add-to-list policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-date=2014-02-11 start-time=00:00:00 +add comment="Backup Every Week" disabled=yes interval=1w name=BackupEveryWeek \ + on-event=BackupAndUpdate policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-date=2025-07-07 start-time=03:41:27 +add comment="DoH Cache Flush" disabled=yes interval=1d name="DNS Cache Flush" \ + on-event=DNS_Flush_Cache policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-date=2019-12-06 start-time=05:30:00 +add comment="Create mkdir function on startup" disabled=yes name=\ + create_mkdir_function_on_startup on-event=\ + "/system script run create_mkdir_function;" policy=read,write,policy,test \ + start-time=startup +add comment="Scheduler for Update Certificates CloudFlare Quad9" disabled=yes \ + interval=1w name="Update Certificates CloudFlare Quad9" on-event=\ + "/system/script { run Update-Certificates; }" policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-date=2025-11-28 start-time=05:45:40 +add comment="Scheduler for Amster-Backup-UpdateEmail" disabled=yes interval=\ + 1w name=Amster-Backup-UpdateEmail on-event=\ + "/system/script { run Amster-Backup-UpdateEmail; }" policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-date=2026-02-13 start-time=03:41:27 +/system watchdog +set watchdog-timer=no +/tool e-mail +set certificate-verification=no from=MikroVados port=587 \ + server=smtp.mail.me.com tls=starttls user=vadossio@icloud.com +/tool mac-server +set allowed-interface-list=LAN +/tool mac-server mac-winbox +set allowed-interface-list=LAN +/tool netwatch +add comment="doh, doh-url=https://security.cloudflare-dns.com/dns-query, notif\ + y, name=CloudFlare-doh IPv4 1" disabled=yes down-script="" host=1.1.1.1 \ + http-codes="" test-script="" type=simple up-script="" +add check-certificate=no comment="doh-fallback, doh-url=https://security.cloud\ + flare-dns.com/dns-query, doh-cert=DigiCert Global Root CA, notify, name=Cl\ + oudFlare-doh IPv4" disabled=yes down-script="" host=1.0.0.1 http-codes="" \ + port=443 test-script="" type=simple up-script="" +add comment="dns-fallback, notify, name=Google-DNS IPv4" disabled=yes \ + down-script="" host=8.8.8.8 http-codes="" test-script="" type=simple \ + up-script="" +add comment="doh-fallback, doh-url=https://dns.google/dns-query, doh-cert=GTS \ + Root R1, notify, name=Google-DOH IPv4" disabled=yes down-script="" host=\ + 8.8.4.4 http-codes="" test-script="" type=simple up-script="" +add comment="dns, notify, name=Cuad9-DOH IPv4" disabled=yes down-script="" \ + host=9.9.9.9 http-codes="" test-script="" type=simple up-script="" +add comment="doh-fallback, doh-url=https://dns.quad9.net/dns-query, name=Cuad9\ + -DOH IPv4" disabled=yes down-script="" host=149.112.112.112 http-codes="" \ + test-script="" type=simple up-script="" +add comment="dns-fallback, notify, name=ns1.unet.ws" disabled=yes \ + down-script="" host=91.192.189.2 http-codes="" test-script="" type=simple \ + up-script="" +/tool sniffer +set filter-interface=Bridge-LAN filter-src-ip-address=10.30.30.50/32 +/user aaa +set accounting=no diff --git a/MikroMaster/history/20260504/20260504082001-Diff-Config.rsc b/MikroMaster/history/20260504/20260504082001-Diff-Config.rsc new file mode 100644 index 0000000..7e5cfbc --- /dev/null +++ b/MikroMaster/history/20260504/20260504082001-Diff-Config.rsc @@ -0,0 +1,2647 @@ +134a135,2480 +> add comment="Script for setup routeros script system" \ +> dont-require-permissions=no name=AM-setup owner=AM-setup policy=\ +> ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ +> !rsc by Vados\r\ +> \n# RouterOS script: AM-setup\r\ +> \n# Script comment: Script for setup routeros script system\r\ +> \n# Copyright (c) 2005-2026 Vados \r\ +> \n#\r\ +> \n#\r\ +> \n# requires RouterOS, version=7.19\r\ +> \n# requires device-mode, fetch\r\ +> \n#\r\ +> \n# :local ScriptName [ :jobname ];\r\ +> \n# Additional commands:\r\ +> \n#\r\ +> \n# For scripts:\r\ +> \n#:global NewScript \"script_name\"; \r\ +> \n#:global GlobalScriptsUrl \"https://ros.vados.ru/\";\r\ +> \n#/system/script/add name=\$NewScript owner=\$NewScript source=([/tool/fe\ +> tch check-certificate=yes-without-crl (\$GlobalScriptsUrl . \$ScriptAdd . \ +> \".rsc\") output=user as-value ]->\"data\");\r\ +> \n#:global NewScript (a);\r\ +> \n#:global ScriptInstallUpdate; \$ScriptInstallUpdate;\r\ +> \n#\r\ +> \n# For run from terminal:\r\ +> \n#/system/script/add name=AM-setup owner=AM-Setup source=([/tool/fetch ch\ +> eck-certificate=yes-without-crl \"https://ros.vados.ru/AM-setup.rsc\" outp\ +> ut=user as-value ]->\"data\");\r\ +> \n#\r\ +> \n\r\ +> \n:global ScriptUpdatesCRLF \"LF\";\r\ +> \n#:if (\$ScriptUpdatesCRLF != false) do={\r\ +> \n# :foreach Script in=[ /system/script/find where source~\"^#!rsc by Vad\ +> os\" ] do={\r\ +> \n# if (\$ScriptUpdatesCRLF = true) do={\r\ +> \n# /system/script/set source=[ :tocrlf [ get \$Script source ] ] \$S\ +> cript;\r\ +> \n# } else={\r\ +> \n# /system/script/set source=[ :tolf [ get \$Script source ] ] \$Scr\ +> ipt;\r\ +> \n# }\r\ +> \n# }\r\ +> \n#}\r\ +> \n\r\ +> \n# /import verbose=no \$ScriptName\r\ +> \n:global SetupScript [ :jobname ];\r\ +> \n:global RemoveMe;\r\ +> \n:global RunOnce;\r\ +> \n:global InitSetup true;\r\ +> \n:global tmpfs true;\r\ +> \n\r\ +> \n{\r\ +> \n :local RmMe [:tobool \$1];\r\ +> \n\r\ +> \n :global GlobalScriptsUrl;\r\ +> \n :global SetupScript;\r\ +> \n :global RemoveMe;\r\ +> \n :global InitSetup;\r\ +> \n :global tmpfs;\r\ +> \n \r\ +> \n :local CertCommonName \"Root YE\";\r\ +> \n :local CertFileName \"Root-YE.pem\";\r\ +> \n :local CertFingerprint \"e14ffcad5b0025731006caa43a121a22d8e9700f4fb9c\ +> f852f02a708aa5d5666\";\r\ +> \n\r\ +> \n :if (\$SetupScript = false) do={\r\ +> \n :global SetupScript \"AM-setup\";\r\ +> \n }\r\ +> \n :if (\$RemoveMe != false) do={\r\ +> \n :set RemoveMe true;\r\ +> \n }\r\ +> \n\r\ +> \n :log warning (\"\\n\\\$GlobalScriptsUrl = \" . \$GlobalScriptsUrl);\r\ +> \n \r\ +> \n :local CertSettings [ /certificate/settings/get ];\r\ +> \n :if (!(((\$CertSettings->\"builtin-trust-anchors\") = \"trusted\" || \ +> \\\r\ +> \n (\$CertSettings->\"builtin-trust-store\") ~ \"fetch\" || \\\r\ +> \n (\$CertSettings->\"builtin-trust-store\") = \"all\") && \\\r\ +> \n [ :len [ /certificate/builtin/find where common-name=\$CertComm\ +> onName ] ] > 0)) do={\r\ +> \n :put \"Importing certificate...\";\r\ +> \n \r\ +> \n /tool/fetch (\$GlobalScriptsUrl . \"certs/\" . \$CertFileName) dst-p\ +> ath=\$CertFileName as-value;\r\ +> \n :delay 1s;\r\ +> \n /certificate/import file-name=\$CertFileName passphrase=\"\";\r\ +> \n :if ([ :len [ /certificate/find where fingerprint=\$CertFingerprint \ +> ] ] != 1) do={\r\ +> \n :error \"Something is wrong with your certificates!\";\r\ +> \n };\r\ +> \n :delay 1s;\r\ +> \n };\r\ +> \n\r\ +> \n:local MkTmpfs do={\r\ +> \n :local TmpFs [ /disk/find where slot=tmpfs type=tmpfs ];\r\ +> \n :if ([ :len \$TmpFs ] = 1) do={\r\ +> \n :if ([ /disk/get \$TmpFs disabled ] = true) do={\r\ +> \n :log info (\"The tmpfs is disabled, enabling.\");\r\ +> \n /disk/enable \$TmpFs;\r\ +> \n }\r\ +> \n :return true;\r\ +> \n }\r\ +> \n :log info (\"Try to removing directory 'tmpfs'.\");\r\ +> \n :do {\r\ +> \n :retry {\r\ +> \n /file/remove tmpfs;\r\ +> \n :return true;\r\ +> \n } delay=100ms max=10;\r\ +> \n } on-error={ }\r\ +> \n# \$RmDir \"tmpfs\";\r\ +> \n :onerror Err {\r\ +> \n /disk/add slot=tmpfs type=tmpfs tmpfs-max-size=([ /system/resource/g\ +> et total-memory ] / 3);\r\ +> \n :do {\r\ +> \n :retry {\r\ +> \n /file/get tmpfs;\r\ +> \n :return true;\r\ +> \n } delay=222ms max=10;\r\ +> \n } on-error={ }\r\ +> \n } do={\r\ +> \n :log warning (\"Creating disk of type tmpfs failed: \" . \$Err);\r\ +> \n :return false;\r\ +> \n }\r\ +> \n# :return true;\r\ +> \n}\r\ +> \n:if (\$tmpfs = true) do={\r\ +> \n :put \"Tmpfs variable is true. Checking for tmpfs/scripts directory...\ +> \";\r\ +> \n :if ([/file find name=\"tmpfs/scripts\"] != \"\") do={\r\ +> \n :log info (\$0 . \"Directory tmpfs/scripts exsist.\");\r\ +> \n :return \$true;\r\ +> \n } else={\r\ +> \n :log warning (\$0 . \"Directory tmpfs/scripts does't exsist.\");\r\ +> \n :if ([ \$MkTmpfs ] = false) do={\r\ +> \n :log error (\$0 . \"Directory tmpfs is not created!\");\r\ +> \n :return false;\r\ +> \n } else={\r\ +> \n :onerror Err {\r\ +> \n /file/add type=\"directory\" name=/tmpfs/scripts;\r\ +> \n :do {\r\ +> \n :retry {\r\ +> \n /file/get /tmpfs/scripts;\r\ +> \n :return true;\r\ +> \n } delay=100ms max=10;\r\ +> \n } on-error={ }\r\ +> \n } do={\r\ +> \n :log warning (\$0 . \"Making directory 'scripts' failed: \" . \$\ +> Err);\r\ +> \n :return false;\r\ +> \n }\r\ +> \n# :return true;\r\ +> \n# [ /file/get \$FileName ]\r\ +> \n }\r\ +> \n# :log error (\$0 . \"Directory tmpfs/scripts does not exsist. Remove\ +> \_global variable tmpfs!\");\r\ +> \n# :global tmpfs (a);\r\ +> \n# return false;\r\ +> \n }\r\ +> \n}\r\ +> \n :put \"Renaming AM-GlobalConfig, if exists...\";\r\ +> \n :local ConfOldName (\"AM-GlobalConfig-\" . [ /system/clock/get date ] \ +> . [ /system/clock/get time ] . \".rsc\");\r\ +> \n /system/script/set name=\$ConfOldName [ find where name=\"AM-GlobalCon\ +> fig\" ];\r\ +> \n :foreach Script in={ \"AM-GlobalConfig\"; \"AM-GlobalFunc\" } do={\r\ +> \n :put \"Installing \$Script...\";\r\ +> \n /system/script/remove [ find where name=\$Script ];\r\ +> \n /system/script/add name=\$Script owner=\$Script source=([ /tool/fetc\ +> h check-certificate=yes-without-crl url=(\$GlobalScriptsUrl . \$Script . \ +> \".rsc\") output=user as-value ]->\"data\");\r\ +> \n \r\ +> \n /system/script run \$Script;\r\ +> \n :delay 2s;\r\ +> \n };\r\ +> \n\r\ +> \n :if ([ :len [ /certificate/find where fingerprint=\$CertFingerprint ] \ +> ] > 0) do={\r\ +> \n :put \"Renaming certificate by its common-name...\";\r\ +> \n :global CertificateNameByCN;\r\ +> \n \$CertificateNameByCN \$CertFingerprint;\r\ +> \n };\r\ +> \n\r\ +> \n :if (\$RemoveMe = true) do={\r\ +> \n :put \"Add Scheduler for remove this script...\";\r\ +> \n :local OnEvent (\":delay 30s;\\n\" . \"/system/script/remove [ find \ +> where name=\\\"\$SetupScript\\\" ];\\n\" . \\\r\ +> \n \":delay 2s;\\n\" . \"/system/scheduler/remove [ find where name=\\\ +> \"_RemoveSetup\\\" ];\\n\" . \\\r\ +> \n \":delay 2s;\\n\" . \":global RemoveMe (a);\\n\");\r\ +> \n :local Comment \"_RemoveSetup tmp scheduler for remove setup script.\ +> \";\r\ +> \n /system/scheduler/add name=\"_RemoveSetup\" comment=\$Comment start-\ +> time=startup interval=30s on-event=\$OnEvent;\r\ +> \n :log warning (\$0 . \"\\nI've done everything, and now I'm tired..\ +> . I'm leaving.\\nThere will be an error below, this is normal.\");\r\ +> \n }\r\ +> \n :delay 1;\r\ +> \n :put \"Loading configuration and functions...\";\r\ +> \n :do { \r\ +> \n :global ScriptInstallUpdate; \$ScriptInstallUpdate;\r\ +> \n :put \"Normal removing temporary global environment variables.\";\ +> \r\ +> \n :global SetupScript (a);\r\ +> \n :global InitSetup (a);\r\ +> \n :global RemoveMe (a);\r\ +> \n } on-error={\r\ +> \n :local ErrorMsg \"Loading configuration and functions error!\";\r\ +> \n :log error (\$0 . \$ErrorMsg . :error);\r\ +> \n :error \$ErrorMsg;\r\ +> \n }\r\ +> \n}\r\ +> \n" +> add comment="Global Config Script" dont-require-permissions=no name=\ +> AM-GlobalConfig owner=AM-GlobalConfig policy=\ +> ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ +> !rsc by Vados\r\ +> \n# RouterOS script: AM-GlobalConfig\r\ +> \n# Script comment: Global Config Script\r\ +> \n# Copyright (c) 2007-2026 Vados \r\ +> \n#\r\ +> \n#\r\ +> \n# Warning: Dont touch this line!\r\ +> \n:global Identity [ /system identity get name ];\r\ +> \n:global GlobalConfReady false;\r\ +> \n#\r\ +> \n#\r\ +> \n# Global Url For Amster scripts to fetch\r\ +> \n# most be defined in AM-Init-Script or AM-setup scripts\r\ +> \n:global GlobalScriptsUrl \"https://ros.vados.ru/\";\r\ +> \n:global ScriptsUrlSuffix \"\";\r\ +> \n:global CheckSumsVerify true;\r\ +> \n\r\ +> \n:global ScriptUpdatesCRLF true;\r\ +> \n:global CommentsInScripts true;\r\ +> \n\r\ +> \n# Debug output:\r\ +> \n:global PrintDebug true; #false;\r\ +> \n\r\ +> \n# Debug output for specific script:\r\ +> \n#:set (\$PrintDebugOverride->\"AM-GlobalFunc\") true;\r\ +> \n\r\ +> \n# Debug logs\r\ +> \n# Other actions (disk, email, remote or support) can be used as well.\r\ +> \n# I do not recommend using echo - use debug output instead (https://rsc.\ +> eworm.de/main/DEBUG.html#debug-output).\r\ +> \n#/system/logging/add topics=script,debug action=memory;\r\ +> \n\r\ +> \n:global MikrotikUpgradeUrl \"https://upgrade.mikrotik.com/routeros\";\r\ +> \n:global Domain \"WORKGROUP\";\r\ +> \n\r\ +> \n:global EmailGeneralTo \"vados@vados.ru\";\r\ +> \n#:global EmailGeneralCc \"\";\r\ +> \n\r\ +> \n# \$ScriptInstallUpdate mod/notification-telegram\r\ +> \n:global TelegramTokenId \"8390868324:AAG3_d1hfVR2M6pGAgDK6ZvhOe4J97nyopw\ +> \";\r\ +> \n:global TelegramChatId \"-1003631309063\"; #\"454403445\";\r\ +> \n# Use this to send notifications to a specific topic in group.\r\ +> \n#:global TelegramThreadId \"30\";\r\ +> \n# Using telegram-chat you have to define trusted chat ids (not group ids\ +> !)\r\ +> \n# or user names. Groups allow to chat with devices simultaneously.\r\ +> \n:global TelegramChatIdsTrusted {\r\ +> \n \"454403445\"\r\ +> \n \"-1003631309063\"\r\ +> \n \"-5124482807\"\r\ +> \n \"1087968824\";\r\ +> \n};\r\ +> \n# \"-5294757340\";\r\ +> \n\r\ +> \n:global TelegramChatGroups \"(all)\";\r\ +> \n#:global TelegramChatGroups \"(all|home|office)\";\r\ +> \n\r\ +> \n:global NotificationFunctions {\r\ +> \n \"email\"\r\ +> \n \"telegram\";\r\ +> \n};\r\ +> \n# Toggle this to disable symbols in notifications.\r\ +> \n:global NotificationsWithSymbols true;\r\ +> \n:global TerminalColorOutput true;\r\ +> \n\r\ +> \n:global DetectIpAddrDefault \"https://ipv4.mikrotik.ovh/\";\r\ +> \n:global DetectIpAddrFallback \"https://api.ipify.org/\";\r\ +> \n\r\ +> \n## Update channel. Possible values: stable, long-term, testing, developm\ +> ent\r\ +> \n:global updateChannel \"stable\";\r\ +> \n\r\ +> \n:global CertRenewUrl (\$GlobalScriptsUrl . \"certs/\" . \$Identity . \"/\ +> \");\r\ +> \n:global CertRenewTime 2w;\r\ +> \n:global CertRenewPass {\r\ +> \n \"\";\r\ +> \n# \"v3ry-s3cr3t\";\r\ +> \n# \"4n0th3r-s3cr3t\";\r\ +> \n};\r\ +> \n:global CertWarnTime 1w;\r\ +> \n:global CertIssuedExportPass {\r\ +> \n \"\";\r\ +> \n# \"cert1-cn\"=\"v3ry-s3cr3t\";\r\ +> \n# \"cert2-cn\"=\"4n0th3r-s3cr3t\";\r\ +> \n};\r\ +> \n\r\ +> \n# Script BackupAndUpdate mode, possible values: backup,\r\ +> \n# updateOnce - Update once as \"osnotify\" and back \"osnotify\" mode (i\ +> n terminal run :set OSUpdateMode updateOnce; \$OSUpdateMode;). \r\ +> \n# osupdate - Update if available and creates backups before/after update\ +> \_(ignores `forceBackup`)\r\ +> \n# Set `forceBackup` to true to always create backups, even\ +> \_without updates\r\ +> \n# osnotify - Set `forceBackup` to always create backups on every run\r\ +> \n:global DevInfoIncludeIP true;\r\ +> \n:global BackupAndUpdateMode \"osnotify\"\r\ +> \n\r\ +> \n:global forceBackup true;\r\ +> \n:global BackupPassword \"Peskar55\";\r\ +> \n\r\ +> \n# SFTP Backup Variables\r\ +> \n:global BackupRandomDelay 0;\r\ +> \n:global BackupUploadUrl \"sftp://amster.vados.ru/upload/\";\r\ +> \n:global BackupUploadUser \$Identity;\r\ +> \n:global BackupUploadPass \"root.mnuc.backuper\";\r\ +> \n\r\ +> \n:global BackupSendBinary true;\r\ +> \n:global BackupSendExport true;\r\ +> \n:global BackupSendGlobalConfig true;\r\ +> \n:global BackupSendScripts true;\r\ +> \n\r\ +> \n# Remove local file after uploading if no errors\r\ +> \n:global BackupRmLocal true;\r\ +> \n\r\ +> \n# Local Backups Root Directory \r\ +> \n:global BackupLocalRoot \"tmpfs\";\r\ +> \n\r\ +> \n# Encrypt Backup\r\ +> \n:global BackupEncrypt true;\r\ +> \n\r\ +> \n# Sensitive information in Backups\r\ +> \n:global BackupSens true;\r\ +> \n\r\ +> \n# User Export\r\ +> \n:global BackupUser true;\r\ +> \n\r\ +> \n# License Export (not for CHR, will silently skip)\r\ +> \n:global BackupLicense false;\r\ +> \n\r\ +> \n# SSH Keys\r\ +> \n:global BackupSshKeys true;\r\ +> \n\r\ +> \n# Certificate Export\r\ +> \n:global BackupCerts true;\r\ +> \n\r\ +> \n# Certificate Password\r\ +> \n:global BackupCertsPasswd \"\";\r\ +> \n\r\ +> \n# User-Manager Export\r\ +> \n:global BackupUserMan false;\r\ +> \n\r\ +> \n# The Dude Export\r\ +> \n:global BackupDude false;\r\ +> \n\r\ +> \n# User Files to export, comma-separated string or array of strings\r\ +> \n# User Files are not removed on backup\r\ +> \n# Any directory paths will be removed (/ -> _) on remote file\r\ +> \n# Nonpresent files are silently skipped\r\ +> \n:global BackupUserList \"autosupout.rif,autosupout.old.rif\";\r\ +> \n\r\ +> \n# load functions and any custom scripts\r\ +> \n# [ /system/script/find where name=\"global-config-ov\ +> erlay\" ], \\\r\ +> \n# [ /system/script/find where name~\"^global-config-o\ +> verlay\\\\.d/.\" ]\r\ +> \n#\r\ +> \n#:foreach Script in=([ /system/script/find where name=\"Amster-TGglobalV\ +> ars\" ], [ /system/script/find where name=\"Amster-TGglobalFunc\" ]) do={\ +> \r\ +> \n# :onerror Err {\r\ +> \n# /system/script/run \$Script;\r\ +> \n# } do={\r\ +> \n# :log error (\"Loading configuration from configs and functions\"\ +> \_. [ /system/script/get \$Script name ] . \" failed: \" . \$Err);\r\ +> \n# }\r\ +> \n#}\r\ +> \n#:log info \"\\ndevMode = \$devMode\";\r\ +> \n#:log info \"\\ndevRunning = \$devRunning\";\r\ +> \n:foreach Script in=[ /system/script/find where source~\"^#!rsc by Vados \ +> GlobalRUN\\r\?\\n\" ] do={\r\ +> \n :onerror Err {\r\ +> \n /system/script/run \$Script;\r\ +> \n } do={\r\ +> \n :log error (\"Run script \" . [ /system/script/get \$Script name \ +> ] . \" width marker \\\" GlobalRUN\\\" failed: \" . \$Err);\r\ +> \n }\r\ +> \n}\r\ +> \n\r\ +> \n# signal we are ready\r\ +> \n:set GlobalConfReady true;\r\ +> \n:while (\$GlobalConfReady != true) do={:delay 500ms};\r\ +> \n" +> add comment="Global functions" dont-require-permissions=no name=AM-GlobalFunc \ +> owner=AM-GlobalFunc policy=\ +> ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ +> !rsc by Vados\r\ +> \n# RouterOS script: AM-GglobalFunc\r\ +> \n# Script comment: Global functions\r\ +> \n# Copyright (c) 2005-2026 Vados \r\ +> \n#\r\ +> \n#\r\ +> \n# requires RouterOS, version=7.19\r\ +> \n# requires device-mode, fetch, scheduler\r\ +> \n:local ExitOK false;\r\ +> \n:local ScriptName [ :jobname ];\r\ +> \n#:global checkRunJob \$SriptName;\r\ +> \n#:global fixCRLF;\r\ +> \n#:if (\$fixCRLF != false) do={\r\ +> \n#:foreach fixScript in=([ /system/script/find where name~\"*\" ]) do={/s\ +> ystem/script/set source=[ :tocrlf [ get \$fixScript source ] ] \$fixScript\ +> }\r\ +> \n#:if (\$fixCRLF != \"LF\") do={ /system/script/set source=[ :tocrlf [ g\ +> et \$fixScript source ] ] \$fixScript};};\r\ +> \n#}\r\ +> \n:global GlobalFuncReady false;\r\ +> \n\r\ +> \n# Git commit id & info, expected configuration version\r\ +> \n:global CommitId \"main/368/b69ddb1c\";\r\ +> \n:global CommitTAG \"unknown\";\r\ +> \n:global CommitInfo \"Autocommit in repo: ros.vados.ru, generated by owne\ +> r: root, in 09:35:02 01.05.2026.\";\r\ +> \n\r\ +> \n# The variables are received right here.\r\ +> \n:global GlobalConfVersion 138;\r\ +> \n\r\ +> \n:global SumsDirAndFileName \"tmp/checksums.json\";\r\ +> \n\r\ +> \n:global Identity [/system/identity/get name];\r\ +> \n:global IdentityShort [:pick \$Identity 0 18];\r\ +> \n\r\ +> \n:global devBoardName [/system/resource/get board-name];\r\ +> \n:global devMode [/system/device-mode/get mode];\r\ +> \n:global devCurArch [/system/resource/get architecture-name];\r\ +> \n:global devCurVersion [/system/resource/get version];\r\ +> \n\r\ +> \n# Variables defined in AM-GlobalConfig.rsc\r\ +> \n:global TerminalColorOutput;\r\ +> \n:global CommentsInScripts;\r\ +> \n:global DetectIpAddrDefault;\r\ +> \n:global DetectIpAddrFallback;\r\ +> \n:global updateChannel;\r\ +> \n:global Domain;\r\ +> \n:global EmailGeneralTo;\r\ +> \n:global BackupAndUpdateMode;\r\ +> \n\r\ +> \n# Single functions, without nested functions.\r\ +> \n:global GlobalEnvRemove;\r\ +> \n:global MiniDateTimeStamp;\r\ +> \n\r\ +> \n# Include globals \$PrintDebug and \$PrintDebugOverride\r\ +> \n:global LogPrint;\r\ +> \n\r\ +> \n# DeviceInfo and Updates\r\ +> \n:global IsCheckUpdates;\r\ +> \n:global WaitCheckUpdates;\r\ +> \n:global GetPubIp;\r\ +> \n\r\ +> \n:global GetArrDeviceInfo;\r\ +> \n:global WaitArrDeviceInfo;\r\ +> \n\r\ +> \n:global devModel;\r\ +> \n:global devRunningMode;\r\ +> \n\r\ +> \n:global devRbRevision;\r\ +> \n:global devRbSerialNumber;\r\ +> \n:global devRbVerAvail;\r\ +> \n\r\ +> \n:global runningChannelVersion;\r\ +> \n:global runningChannel;\r\ +> \n:global runningVersion;\r\ +> \n\r\ +> \n:global devBuildTime;\r\ +> \n:global ROsVerAvail;\r\ +> \n:global PkgUpdStatus;\r\ +> \n:global currentUpdateChannel;\r\ +> \n\r\ +> \n:global ScriptInstallUpdate;\r\ +> \n\r\ +> \n:global DeviceInfo;\r\ +> \n\r\ +> \n:global OldMode;\r\ +> \n\r\ +> \n:global ParseKeyValueStore;\r\ +> \n:global RandomDelay;\r\ +> \n:global GetRandomNumber;\r\ +> \n:global EscapeForRegEx;\r\ +> \n:global ExitError;\r\ +> \n:global CharacterMultiply;\r\ +> \n:global CharacterReplace;\r\ +> \n:global CleanFilePath;\r\ +> \n:global CleanName;\r\ +> \n\r\ +> \n:global CommitBrief;\r\ +> \n\r\ +> \n:global EitherOr;\r\ +> \n:global FormatLine;\r\ +> \n:global GetRandom20CharAlNum;\r\ +> \n:global Grep;\r\ +> \n:global IfThenElse;\r\ +> \n:global MAX;\r\ +> \n:global MIN;\r\ +> \n:global HumanReadableNum;\r\ +> \n\r\ +> \n:global IsFullyConnected;\r\ +> \n:global IsDNSResolving;\r\ +> \n:global IsTimeSync;\r\ +> \n:global IsTimeSyncCached;\r\ +> \n:global IsTimeSyncResetNtp;\r\ +> \n\r\ +> \n:global WaitDNSResolving;\r\ +> \n:global WaitFullyConnected;\r\ +> \n:global WaitTimeSync;\r\ +> \n:global MkDir;\r\ +> \n:global RmDir;\r\ +> \n:global RmFile;\r\ +> \n:global FileGet;\r\ +> \n:global Unix2Dos;\r\ +> \n:global UrlEncode;\r\ +> \n:global WaitForFile;\r\ +> \n:global ScriptLock;\r\ +> \n:global SendTelegram;\r\ +> \n:global NotificationFunctions;\r\ +> \n:global SendNotification;\r\ +> \n:global SendNotification2;\r\ +> \n:global SymbolForNotification;\r\ +> \n:global SymbolByUnicodeName;\r\ +> \n:global ValidateSyntax;\r\ +> \n:global CheckSumsVerify;\r\ +> \n:global GlobalConfChanges;\r\ +> \n:global GlobalConfMigration;\r\ +> \n:global VersionToNum;\r\ +> \n:global RequiredRouterOS;\r\ +> \n:global FetchLargeFiles;\r\ +> \n:global FetchUserAgentStr;\r\ +> \n:global CertificateAvailable;\r\ +> \n:global CertificateDownload;\r\ +> \n:global CertificateNameByCN;\r\ +> \n:global CharacterMultiply;\r\ +> \n\r\ +> \n:global InspectVar;\r\ +> \n:global InspectVarRet;\r\ +> \n:global ParseCustom;\r\ +> \n\r\ +> \n:set IsCheckUpdates do={\r\ +> \n :local isInfo [:tobool \$1];\r\ +> \n :global LogPrint;\r\ +> \n :global updateChannel;\r\ +> \n :global PkgUpdStatus;\r\ +> \n :global currentUpdateChannel;\r\ +> \n :global ROsVerAvail;\r\ +> \n :global arrDeviceInfo;\r\ +> \n \$LogPrint debug \$0 (\"\\\$isInfo = \" . \$isInfo); \r\ +> \n :local CurrentChannel [ /system/package/update/get channel ];\r\ +> \n :if ([ :len \$updateChannel ] > 0 && \$CurrentChannel != \$updateChann\ +> el) do={\r\ +> \n :retry command={/system/package/update set channel=\$updateChannel} \ +> \_delay=300ms max=5 on-error={};\r\ +> \n \$LogPrint debug \$0 (\"Set updates channel to: \$updateChannel\");\ +> \r\ +> \n }\r\ +> \n\r\ +> \n :local Update [ /system/package/update/get ];\r\ +> \n :local Channel [ :tostr (\$Update->\"channel\") ];\r\ +> \n :set currentUpdateChannel \$Channel;\r\ +> \n \$LogPrint debug \$0 (\"Update Channel: \" . \$Channel . \".\");\r\ +> \n\r\ +> \n\r\ +> \n :local StatusPkg \"undefined\";\r\ +> \n \$LogPrint debug \$0 (\"Checking for updates...\");\r\ +> \n :retry command={:set \$StatusPkg ([/system/package/update/check-for-up\ +> dates without-paging as-value]->\"status\")} \\\r\ +> \n delay=300ms max=5 on-error={};\r\ +> \n \$LogPrint debug \$0 (\"\\\$StatusPkg = \" . \$StatusPkg);\r\ +> \n :if (\$StatusPkg = \"New version is available\") do={ :set PkgUpdStatu\ +> s true; } else={ :set PkgUpdStatus false; }\r\ +> \n :set ROsVerAvail [ :tostr [ /system/package/update/get latest-version \ +> ] ];\r\ +> \n \$LogPrint debug \$0 (\"\\\$PkgUpdStatus = \" . \$PkgUpdStatus);\r\ +> \n :if (\$isInfo != false || \$PkgUpdStatus = true) do={\r\ +> \n \$LogPrint debug \$0 (\"\\\$PkgUpdStatus = \" . \$PkgUpdStatus);\r\ +> \n :if ([ :typeof \$arrDeviceInfo ] != \"array\") do={\r\ +> \n :set arrDeviceInfo [:toarray \$arrDeviceInfo];\r\ +> \n }\r\ +> \n :retry command={:set (\$arrDeviceInfo->\"devUpdates\") [ /system/pac\ +> kage/update/get ]} delay=500ms max=5 on-error={:log error (\"Error\")};\r\ +> \n :return true;\r\ +> \n } else={\r\ +> \n :return \$PkgUpdStatus;\r\ +> \n }\r\ +> \n}\r\ +> \n\r\ +> \n:set WaitCheckUpdates do={\r\ +> \n :global IsCheckUpdates;\r\ +> \n :global PkgUpdStatus;\r\ +> \n :global currentUpdateChannel;\r\ +> \n :global ROsVerAvail;\r\ +> \n :global arrDeviceInfo;\r\ +> \n\r\ +> \n :local Status \"\";\r\ +> \n :local Update;\r\ +> \n :local WaitCount 0;\r\ +> \n\r\ +> \n :if ([ \$IsCheckUpdates true ] = false) do={\r\ +> \n :return false;\r\ +> \n }\r\ +> \n\r\ +> \n :set Status [ :tostr [ /system/package/update/get status ] ];\r\ +> \n :while ((\$Status = \"\" || \$Status = \"finding out latest version...\ +> \") && \$WaitCount < 60) do={\r\ +> \n :delay 1s;\r\ +> \n :set WaitCount (\$WaitCount + 1);\r\ +> \n :set Status [ :tostr [ /system/package/update/get status ] ];\r\ +> \n }\r\ +> \n\r\ +> \n :set Update [ /system/package/update/get ];\r\ +> \n :set currentUpdateChannel [ :tostr (\$Update->\"channel\") ];\r\ +> \n :set ROsVerAvail [ :tostr (\$Update->\"latest-version\") ];\r\ +> \n :if ((\$Update->\"status\") = \"New version is available\") do={\r\ +> \n :set PkgUpdStatus true;\r\ +> \n } else={\r\ +> \n :set PkgUpdStatus false;\r\ +> \n }\r\ +> \n :if ([ :typeof \$arrDeviceInfo ] != \"array\") do={\r\ +> \n :set arrDeviceInfo [:toarray \$arrDeviceInfo];\r\ +> \n }\r\ +> \n :set (\$arrDeviceInfo->\"devUpdates\") \$Update;\r\ +> \n\r\ +> \n :if (\$Status = \"\" || \$Status = \"finding out latest version...\") \ +> do={\r\ +> \n :return false;\r\ +> \n }\r\ +> \n :return true;\r\ +> \n}\r\ +> \n\r\ +> \n:set WaitArrDeviceInfo do={\r\ +> \n :global GetArrDeviceInfo;\r\ +> \n :while ([ \$GetArrDeviceInfo ] = false) do={\r\ +> \n :delay 1s;\r\ +> \n }\r\ +> \n}\r\ +> \n\r\ +> \n:set GetArrDeviceInfo do={\r\ +> \n :global LogPrint;\r\ +> \n :global arrDeviceInfo;\r\ +> \n\r\ +> \n :global devBoardName;\r\ +> \n :global devModel;\r\ +> \n :global devRunning;\r\ +> \n :global devCurArch;\r\ +> \n :global devRbRevision;\r\ +> \n :global devRbSerialNumber;\r\ +> \n :global devBuildTime;\r\ +> \n :global runningChannelVersion;\r\ +> \n :global runningChannel;\r\ +> \n :global runningVersion;\r\ +> \n :global currentUpdateChannel;\r\ +> \n :global ROsVerAvail;\r\ +> \n\r\ +> \n :local DeviceInfo;\r\ +> \n :local Resource [/system/resource/get];\r\ +> \n :local Update [ /system/package/update/get ];\r\ +> \n :local VersionString [ :tostr (\$Resource->\"version\") ];\r\ +> \n :local ChannelStart [ :find \$VersionString \" (\" ];\r\ +> \n :local RouterBoard;\r\ +> \n :local IsRouterBoard false;\r\ +> \n :local RunningMode \"\";\r\ +> \n\r\ +> \n :set devCurArch [ :tostr (\$Resource->\"architecture-name\") ];\r\ +> \n :set devBuildTime [ :tostr (\$Resource->\"build-time\") ];\r\ +> \n :set runningChannelVersion \$VersionString;\r\ +> \n :set runningVersion \$VersionString;\r\ +> \n :set runningChannel \"\";\r\ +> \n\r\ +> \n :if ([ :typeof \$ChannelStart ] = \"num\" && \$ChannelStart >= 0) do=\ +> {\r\ +> \n :set runningVersion [ :pick \$VersionString 0 \$ChannelStart ];\r\ +> \n :local ChannelRest [ :pick \$VersionString (\$ChannelStart + 2) [ :\ +> len \$VersionString ] ];\r\ +> \n :local ChannelEnd [ :find \$ChannelRest \")\" ];\r\ +> \n :if ([ :typeof \$ChannelEnd ] = \"num\" && \$ChannelEnd >= 0) do={\ +> \r\ +> \n :set runningChannel [ :pick \$ChannelRest 0 \$ChannelEnd ];\r\ +> \n }\r\ +> \n }\r\ +> \n\r\ +> \n :if ([:pick \$devBoardName 0 3] != \"CHR\" or [:pick \$devBoardName 0\ +> \_3] != \"x86\") do={\r\ +> \n :do {\r\ +> \n :set RouterBoard [[ :parse \"/system/routerboard/get\" ]];\r\ +> \n# :set RouterBoard [ /system/routerboard/get ];\r\ +> \n :if ((\$RouterBoard->\"routerboard\") = true) do={\r\ +> \n :set IsRouterBoard true;\r\ +> \n }\r\ +> \n } on-error={}\r\ +> \n }\r\ +> \n\r\ +> \n :do {\r\ +> \n :set RunningMode [ /system/device-mode/get mode ];\r\ +> \n } on-error={\r\ +> \n :do {\r\ +> \n :set RunningMode [ /system/device-mode/get running ];\r\ +> \n } on-error={\r\ +> \n :set RunningMode \"\";\r\ +> \n }\r\ +> \n }\r\ +> \n :set devRunning \$RunningMode;\r\ +> \n\r\ +> \n :if (\$IsRouterBoard = true) do={\r\ +> \n :set devModel [ :tostr (\$RouterBoard->\"model\") ];\r\ +> \n :set devRbRevision [ :tostr (\$RouterBoard->\"revision\") ];\r\ +> \n :set devRbSerialNumber [ :tostr (\$RouterBoard->\"serial-number\") \ +> ];\r\ +> \n } else={\r\ +> \n :set devModel \$devBoardName;\r\ +> \n :set devRbRevision \"\";\r\ +> \n :set devRbSerialNumber \"\";\r\ +> \n }\r\ +> \n\r\ +> \n :set currentUpdateChannel [ :tostr (\$Update->\"channel\") ];\r\ +> \n :set ROsVerAvail [ :tostr (\$Update->\"latest-version\") ];\r\ +> \n\r\ +> \n :set (\$DeviceInfo->\"board-name\") \$devBoardName;\r\ +> \n :set (\$DeviceInfo->\"architecture-name\") \$devCurArch;\r\ +> \n :set (\$DeviceInfo->\"model\") \$devModel;\r\ +> \n :set (\$DeviceInfo->\"revision\") \$devRbRevision;\r\ +> \n :set (\$DeviceInfo->\"serial-number\") \$devRbSerialNumber;\r\ +> \n :set (\$DeviceInfo->\"running-mode\") \$devRunning;\r\ +> \n :set (\$DeviceInfo->\"build-time\") \$devBuildTime;\r\ +> \n :set (\$DeviceInfo->\"running-channel-version\") \$runningChannelVers\ +> ion;\r\ +> \n :set (\$DeviceInfo->\"running-version\") \$runningVersion;\r\ +> \n :set (\$DeviceInfo->\"running-channel\") \$runningChannel;\r\ +> \n :set (\$DeviceInfo->\"routerboard\") \$IsRouterBoard;\r\ +> \n :set (\$DeviceInfo->\"current-firmware\") [ :tostr (\$RouterBoard->\"\ +> current-firmware\") ];\r\ +> \n :set (\$DeviceInfo->\"upgrade-firmware\") [ :tostr (\$RouterBoard->\"\ +> upgrade-firmware\") ];\r\ +> \n :set (\$DeviceInfo->\"package-channel\") \$currentUpdateChannel;\r\ +> \n :set (\$DeviceInfo->\"installed-version\") [ :tostr (\$Update->\"inst\ +> alled-version\") ];\r\ +> \n :set (\$DeviceInfo->\"latest-version\") \$ROsVerAvail;\r\ +> \n :set (\$DeviceInfo->\"update-status\") [ :tostr (\$Update->\"status\"\ +> ) ];\r\ +> \n\r\ +> \n :set arrDeviceInfo \$DeviceInfo;\r\ +> \n :return \$DeviceInfo;\r\ +> \n}\r\ +> \n\r\ +> \n:set DeviceInfo do={\r\ +> \n :global GetArrDeviceInfo;\r\ +> \n :global GlobalConfVersion;\r\ +> \n :global Identity;\r\ +> \n :global IfThenElse;\r\ +> \n :global FormatLine;\r\ +> \n :global CommitBrief;\r\ +> \n\r\ +> \n :local License [/system/license/get];\r\ +> \n :local Snmp [ /snmp/get ];\r\ +> \n :local Info [ \$GetArrDeviceInfo ];\r\ +> \n\r\ +> \n :if ([ :typeof \$Info ] != \"array\") do={\r\ +> \n :return false;\r\ +> \n }\r\ +> \n\r\ +> \n :return ( \\\r\ +> \n [ \$FormatLine \"Hostname\" \$Identity ] . \"\\n\" . \\\r\ +> \n [ \$IfThenElse ([ :len (\$Snmp->\"location\") ] > 0) \\\r\ +> \n ([ \$FormatLine \"Location\" (\$Snmp->\"location\") ] . \"\\n\") ]\ +> \_. \\\r\ +> \n [ \$IfThenElse ([ :len (\$Snmp->\"contact\") ] > 0) \\\r\ +> \n ([ \$FormatLine \"Contact\" (\$Snmp->\"contact\") ] . \"\\n\") ] .\ +> \_\\\r\ +> \n \"Hardware:\\n\" . \\\r\ +> \n [ \$FormatLine \" Board\" (\$Info->\"board-name\") ] . \"\\n\" . \ +> \\\r\ +> \n [ \$FormatLine \" Arch\" (\$Info->\"architecture-name\") ] . \"\\\ +> n\" . \\\r\ +> \n [ \$FormatLine \" Model\" (\$Info->\"model\") ] . \\\r\ +> \n [ \$IfThenElse ([ :len (\$Info->\"revision\") ] > 0) \\\r\ +> \n (\" \" . (\$Info->\"revision\")) ] . \"\\n\" . \\\r\ +> \n [ \$IfThenElse ([ :len (\$Info->\"serial-number\") ] > 0) \\\r\ +> \n ([ \$FormatLine \" Serial\" (\$Info->\"serial-number\") ] . \"\ +> \\n\") ] . \\\r\ +> \n [ \$IfThenElse ([ :len (\$License->\"nlevel\") ] > 0) \\\r\ +> \n ([ \$FormatLine \" License\" (\"level \" . (\$License->\"nlevel\ +> \")) ] . \"\\n\") ] . \\\r\ +> \n \"RouterOS:\\n\" . \\\r\ +> \n [ \$IfThenElse ([ :len (\$License->\"level\") ] > 0) \\\r\ +> \n ([ \$FormatLine \" License\" (\"level \" . (\$License->\"level\ +> \")) ] . \"\\n\") ] . \\\r\ +> \n [ \$FormatLine \" Channel\" (\$Info->\"package-channel\") ] . \"\ +> \\n\" . \\\r\ +> \n [ \$FormatLine \" Installed\" (\$Info->\"installed-version\") ] .\ +> \_\"\\n\" . \\\r\ +> \n [ \$IfThenElse ([ :len (\$Info->\"running-channel\") ] > 0) \\\r\ +> \n ([ \$FormatLine \" Running\" ((\$Info->\"running-version\") . \ +> \" (\" . (\$Info->\"running-channel\") . \")\") ] . \"\\n\") \\\r\ +> \n ([ \$FormatLine \" Running\" (\$Info->\"running-version\") ] . \ +> \"\\n\") ] . \\\r\ +> \n [ \$IfThenElse ([ :len (\$Info->\"latest-version\") ] > 0 && \\\r\ +> \n (\$Info->\"installed-version\") != (\$Info->\"latest-version\"))\ +> \_\\\r\ +> \n ([ \$FormatLine \" Available\" (\$Info->\"latest-version\") ] .\ +> \_\"\\n\") ] . \\\r\ +> \n [ \$IfThenElse ((\$Info->\"routerboard\") = true && \\\r\ +> \n (\$Info->\"current-firmware\") != (\$Info->\"upgrade-firmware\")\ +> ) \\\r\ +> \n ([ \$FormatLine \" Firmware\" ((\$Info->\"current-firmware\") .\ +> \_\" -> \" . (\$Info->\"upgrade-firmware\")) ] . \"\\n\") ] . \\\r\ +> \n \"RouterOS-Scripts:\\n\" . \\\r\ +> \n [ \$FormatLine \" Commit\" [ \$CommitBrief ] ] . \"\\n\" . \\\r\ +> \n [ \$FormatLine \" Version\" \$GlobalConfVersion ]);\r\ +> \n}\r\ +> \n\r\ +> \n:if ([ :typeof \$NotificationFunctions ] != \"array\") do={:set Notifica\ +> tionFunctions ({})}\r\ +> \n:set GetRandom20CharAlNum do={\r\ +> \n :global EitherOr;\r\ +> \n :return [ :rndstr length=[ \$EitherOr [ :tonum \$1 ] 20 ] from=\"ABCDE\ +> FGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\" ];\r\ +> \n}\r\ +> \n\r\ +> \n:global checkRunJob;\r\ +> \n:set checkRunJob do={\r\ +> \n :local Script [ :tostr \$1 ];\r\ +> \n :global ScriptLock; \r\ +> \n :if ([ \$ScriptLock \$Script ] = false) do={:return false}\r\ +> \n :foreach Job in=[ /system/script/job/find where script=\$Script ] do={\ +> :set Job [ /system/script/job/get \$Job ];\r\ +> \n :while ([ :typeof (\$Job->\"parent\") ] = \"id\") do={:set Job [ /sy\ +> stem/script/job/get [ find where .id=(\$Job->\"parent\") ] ]}\r\ +> \n :if ((\$Job->\"type\") = \"login\") do={:return true};}; :return fa\ +> lse; \r\ +> \n}\r\ +> \n\r\ +> \n:set InspectVar do={\r\ +> \n :global InspectVarRet;\r\ +> \n :put [ :tocrlf [ \$InspectVarRet \$1 ] ];\r\ +> \n}\r\ +> \n\r\ +> \n:set CommitBrief do={\r\ +> \n :global CommitId;\r\ +> \n :global CommitInfo;\r\ +> \n :if (\$CommitId = \"unknown\") do={\r\ +> \n :return \"unknown\";\r\ +> \n }\r\ +> \n :return (\$CommitInfo . \"/\" . [ :pick \$CommitId 0 8 ]);\r\ +> \n}\r\ +> \n\r\ +> \n:set InspectVarRet do={\r\ +> \n :local Input \$1;\r\ +> \n :local Level (0 + [ :tonum \$2 ]);\r\ +> \n :global CharacterReplace;\r\ +> \n :global IfThenElse;\r\ +> \n :global InspectVarRet;\r\ +> \n :local IndentReturn do={\r\ +> \n :local Prefix [ :tostr \$1 ];\r\ +> \n :local Value [ :tostr \$2 ];\r\ +> \n :local Level [ :tonum \$3 ];\r\ +> \n :global CharacterMultiply;\r\ +> \n :return ([ \$CharacterMultiply \" \" (\$Level * 2) ] . \"-\" . \$Pre\ +> fix . \"-> \" . \$Value);\r\ +> \n }\r\ +> \n :local TypeOf [ :typeof \$Input ];\r\ +> \n :local Len [ :len \$Input ];\r\ +> \n :local Return [ \$IndentReturn \"type\" \$TypeOf \$Level ];\r\ +> \n :if (\$TypeOf = \"array\") do={\r\ +> \n :foreach Key,Value in=\$Input do={\r\ +> \n :set \$Return (\$Return . \"\\n\" . \\\r\ +> \n [ \$IndentReturn \"key\" \$Key (\$Level + 1) ] . \"\\n\" . \\\r\ +> \n [ \$InspectVarRet \$Value (\$Level + 2) ]);\r\ +> \n }\r\ +> \n } else={\r\ +> \n :if (\$TypeOf = \"str\") do={\r\ +> \n :set \$Return (\$Return . \"\\n\" . \\\r\ +> \n [ \$IndentReturn \"len\" \$Len \$Level ]);\r\ +> \n :if ([ :typeof [ :find \$Input (\"\\r\") ] ] = \"num\") do={\r\ +> \n :set Input [ \$CharacterReplace \$Input (\"\\r\") \"\" ];\r\ +> \n }\r\ +> \n :if ([ :typeof [ :find \$Input (\"\\n\") ] ] = \"num\") do={\r\ +> \n :set Input [ \$CharacterReplace \$Input (\"\\n\") \" \" ];\r\ +> \n }\r\ +> \n }\r\ +> \n :if (\$TypeOf != \"nothing\") do={\r\ +> \n :set \$Return (\$Return . \"\\n\" . \\\r\ +> \n [ \$IndentReturn \"value\" [ \$IfThenElse ([ :len \$Input ] > 80)\ +> \_\\\r\ +> \n ([ :pick \$Input 0 77 ] . \"...\") \$Input ] \$Level ]);\r\ +> \n }\r\ +> \n }\r\ +> \n :return \$Return;\r\ +> \n}\r\ +> \n\r\ +> \n# !!! The function is not ready !!!\r\ +> \n:global FetchHttpInfo do={\r\ +> \n :local Mac [ :tostr \$1 ];\r\ +> \n :global CertificateAvailable;\r\ +> \n :global IsMacLocallyAdministered;\r\ +> \n :global LogPrint;\r\ +> \n :local Url \"https://api.macvendors.com/\";\r\ +> \n :if ([ \$IsMacLocallyAdministered \$Mac ] = true) do={:return \"locall\ +> y administered\";}\r\ +> \n :do {\r\ +> \n :if ([ \$CertificateAvailable \"GTS Root R4\" \"fetch\" ] = false) d\ +> o={\r\ +> \n \$LogPrint warning \$0 (\"Downloading required certificate failed.\ +> \");\r\ +> \n :error false;\r\ +> \n }\r\ +> \n :local Vendor ([ /tool/fetch \r\ +> \n (\$Url . [ :pick \$Mac 0 8 ]) output=user as-value ]->\"data\");\r\ +> \n :return \$Vendor;\r\ +> \n } on-error={\r\ +> \n :onerror Err {\r\ +> \n /tool/fetch check-certificate=yes-without-crl (\$Url) output=none \ +> as-value;\r\ +> \n \$LogPrint debug \$0 (\"The mac vendor is not known in database.\"\ +> );\r\ +> \n } do={ \$LogPrint warning \$0 (\"Failed getting mac vendor: \" . \$E\ +> rr); }\r\ +> \n :return \"unknown vendor\";\r\ +> \n }\r\ +> \n}\r\ +> \n\r\ +> \n:set GetPubIp do={\r\ +> \n :global DetectIpAddrDefault;\r\ +> \n :global DetectIpAddrFallback;\r\ +> \n\r\ +> \n :local PubIpAddr false;\r\ +> \n :local Url \$DetectIpAddrDefault;\r\ +> \n :local JobName [ :jobname ];\r\ +> \n\r\ +> \n :do {\r\ +> \n :log debug (\$0 . \" Trying to detect public IP using default serv\ +> ice: \" . \$Url . \"...\");\r\ +> \n :retry command={:set PubIpAddr ([ /tool/fetch http-method=\"get\"\ +> \_check-certificate=yes-without-crl \$Url output=user as-value ]->\"data\"\ +> )} \\\r\ +> \n delay=50ms max=5 on-error={:log error (\$JobName . \" Failed to \ +> detect public IP using default service: \" . \$Url . \".\")}\r\ +> \n } on-error={\r\ +> \n :log error (\$0 . \" Failed to detect public IP using default serv\ +> ice: \" . \$Url . \".\");\r\ +> \n :set Url \$DetectIpAddrFallBack;\r\ +> \n :log debug (\$0 . \" Trying to detect public IP using fallback ser\ +> vice: \" . \$Url . \"...\");\r\ +> \n :retry command={:set PubIpAddr ([ /tool/fetch http-method=\"get\"\ +> \_check-certificate=yes-without-crl \$Url output=user as-value ]->\"data\"\ +> )} \\\r\ +> \n delay=200ms max=5 on-error={:log error (\$JobName . \" Failed to\ +> \_detect public IP using fallback service: \" . \$Url . \".\")}\r\ +> \n };\r\ +> \n :local IpLen ([ :len \$PubIpAddr ] -1);\r\ +> \n :if (\$PubIpAddr = false) do={:set PubIpAddr \"not-detected\"} else=\ +> {:set PubIpAddr [:pick \$PubIpAddr 0 \$IpLen]}\r\ +> \n :return \$PubIpAddr;\r\ +> \n}\r\ +> \n\r\ +> \n:set FormatLine do={\r\ +> \n :local Key [ :tostr \$1 ];\r\ +> \n :local Value [ :tostr \$2 ];\r\ +> \n :local Indent [ :tonum \$3 ];\r\ +> \n :local Spaces;\r\ +> \n :local Return \"\";\r\ +> \n :global CharacterMultiply;\r\ +> \n :global EitherOr;\r\ +> \n :set Indent [ \$EitherOr \$Indent 16 ];\r\ +> \n :local Spaces [ \$CharacterMultiply \" \" \$Indent ];\r\ +> \n :if ([ :len \$Key ] > 0) do={ :set Return (\$Key . \":\")}\r\ +> \n :if ([ :len \$Key ] > (\$Indent - 2)) do={:set Return (\$Return . \"\\\ +> n\" . [ :pick \$Spaces 0 \$Indent ] . \$Value);\r\ +> \n } else={:set Return (\$Return . [ :pick \$Spaces 0 (\$Indent - [ :len \ +> \$Return ]) ] . \$Value)}\r\ +> \n :return \$Return;\r\ +> \n}\r\ +> \n\r\ +> \n:set ParseCustom do={\r\ +> \n :local Str [ :tostr \$1 ];\r\ +> \n :local Start [:find [ \$Str ] [:tostr \$2]];\r\ +> \n :local End [ :tostr \$3 ];\r\ +> \n :local Num [ :tonum \$4 ];\r\ +> \n :local Return;\r\ +> \n :if ([:len \$Num] = 0) do={:set Num \"0\"}\r\ +> \n :local rest [:pick \$Str (\$Start+\$Num) [:len \$Str]]; \r\ +> \n :if ([:len \$End ] = 0) do={:set Return [:pick \$Str \$Num \$Start]} e\ +> lse={\r\ +> \n :set End [:find \$rest \$End];\r\ +> \n :set Return [:pick \$rest 0 \$End];\r\ +> \n }\r\ +> \n:return \$Return;\r\ +> \n}\r\ +> \n\r\ +> \n:set LogPrint do={\r\ +> \n :local Severity [ :tostr \$1 ];\r\ +> \n :local Name [ :tostr \$2 ];\r\ +> \n :local Message [ :tostr \$3 ];\r\ +> \n :global PrintDebug;\r\ +> \n :global PrintDebugOverride;\r\ +> \n :global EitherOr;\r\ +> \n :local Debug [ \$EitherOr (\$PrintDebugOverride->\$Name) \$PrintDebug \ +> ];\r\ +> \n :local PrintSeverity do={\r\ +> \n :global TerminalColorOutput;\r\ +> \n :if (\$TerminalColorOutput != true) do={:return \$1}\r\ +> \n :local Color { debug=96; info=97; warning=93; error=91 };\r\ +> \n :return (\"\\1B[\" . \$Color->\$1 . \"m\" . \$1 . \"\\1B[0m\");\r\ +> \n}\r\ +> \n :local Log ([ \$EitherOr \$Name \"\" ] . \": \" . \$Message);\ +> \r\ +> \n :if (\$Severity ~ (\"^(custom|debug|error|info)\\\$\")) do={\r\ +> \n :if (\$Severity = \"debug\") do={:log debug \$Log}\r\ +> \n :if (\$Severity = \"error\") do={:log error \$Log}\r\ +> \n :if (\$Severity = \"info\" ) do={:log info \$Log}\r\ +> \n } else={:log warning \$Log; :set Severity \"warning\"}\r\ +> \n :if (\$Severity != \"debug\" || \$Debug = true) do={:put ([ \$PrintSev\ +> erity \$Severity ] . \": \" . \$Message)}\r\ +> \n}\r\ +> \n\r\ +> \n# check and download required certificate\r\ +> \n# Usage: \$CertificateAvailable \"Common Name\" \"intended use for certi\ +> ficate (e.g. \"fetch\", \"tls\", \"all\", \"undefined\")\"\r\ +> \n:set CertificateAvailable do={\r\ +> \n :local CommonName [ :tostr \$1 ];\r\ +> \n :local UseFor [ :tostr \$2 ];\r\ +> \n\r\ +> \n :global CertificateDownload;\r\ +> \n :global ParseKeyValueStore;\r\ +> \n\r\ +> \n :if ([ :len \$UseFor ] = 0) do={\r\ +> \n :log warning (\$0 . \"The intended use is undefined!\");\r\ +> \n :set UseFor \"undefined\";\r\ +> \n }\r\ +> \n :if ([ /system/resource/get free-hdd-space ] < 8388608 && \\\r\ +> \n [ /certificate/settings/get crl-download ] = true && \\\r\ +> \n [ /certificate/settings/get crl-store ] = \"system\") do={\r\ +> \n :log warning (\$0 . \"This system has low free flash space but \" . \ +> \\\r\ +> \n \"is configured to download certificate CRLs to system!\");\r\ +> \n }\r\ +> \n :if ([ :len \$CommonName ] = 0) do={\r\ +> \n :log warning (\$0 . \"No CommonName given!\");\r\ +> \n :return false;\r\ +> \n }\r\ +> \n :local CertSettings [ /certificate/settings/get ];\r\ +> \n :if (((\$CertSettings->\"builtin-trust-anchors\") = \"trusted\" || \\\ +> \r\ +> \n (\$CertSettings->\"builtin-trust-store\") ~ \$UseFor || \\\r\ +> \n (\$CertSettings->\"builtin-trust-store\") = \"all\") && \\\r\ +> \n [ :len [ /certificate/builtin/find where common-name=\$CommonName\ +> \_] ] > 0) do={\r\ +> \n :return true;\r\ +> \n }\r\ +> \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] = 0\ +> ) do={\r\ +> \n :log info (\$0 . \"Certificate with CommonName '\" . \$CommonName . \ +> \"' not available.\");\r\ +> \n :if ([ \$CertificateDownload \$CommonName ] = false) do={\r\ +> \n :return false;\r\ +> \n }\r\ +> \n }\r\ +> \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] > 1\ +> ) do={\r\ +> \n :log info (\$0 . \"There are \" . \$CertCount . \" Certificates with\ +> \_CommonName '\" . \$CommonName . \"'. Should be ok.\");\r\ +> \n :return true;\r\ +> \n }\r\ +> \n :local CertVal [ /certificate/get [ find where common-name=\$CommonNam\ +> e ] ];\r\ +> \n :while ((\$CertVal->\"akid\") != \"\" && (\$CertVal->\"akid\") != (\$C\ +> ertVal->\"skid\")) do={\r\ +> \n :if ([ :len [ /certificate/find where skid=(\$CertVal->\"akid\") ] ]\ +> \_= 0) do={\r\ +> \n :local IssuerCN ([ \$ParseKeyValueStore (\$CertVal->\"issuer\") ]-\ +> >\"CN\");\r\ +> \n :log info (\$0 . \"Certificate chain for '\" . \$CommonName . \"' \ +> is incomplete, missing '\" . \$IssuerCN . \"'.\");\r\ +> \n :if ([ \$CertificateDownload \$IssuerCN ] = false) do={\r\ +> \n :return false;\r\ +> \n }\r\ +> \n }\r\ +> \n :set CertVal [ /certificate/get [ find where skid=(\$CertVal->\"akid\ +> \") ] ];\r\ +> \n }\r\ +> \n :return true;\r\ +> \n}\r\ +> \n\r\ +> \n# download and import certificate\r\ +> \n# Usage: \$CertificateDownload \"Common Name\"\r\ +> \n:set CertificateDownload do={\r\ +> \n :local CommonName [ :tostr \$1 ];\r\ +> \n :global ScriptUpdatesBaseUrl;\r\ +> \n :global ScriptUpdatesUrlSuffix;\r\ +> \n :global CertificateNameByCN;\r\ +> \n :global CleanName;\r\ +> \n :global FetchUserAgentStr;\r\ +> \n :global RmFile;\r\ +> \n :global WaitForFile;\r\ +> \n\r\ +> \n :log info (\$0 . \"Downloading and importing certificate with \" . \\\ +> \r\ +> \n \"CommonName '\" . \$CommonName . \"'.\");\r\ +> \n :local FileName ([ \$CleanName \$CommonName ] . \".pem\");\r\ +> \n :do {\r\ +> \n /tool/fetch check-certificate=yes-without-crl http-header-field=({ [\ +> \_\$FetchUserAgentStr \$0 ] }) \\\r\ +> \n (\$ScriptUpdatesBaseUrl . \"certs/\" . \$FileName . \$ScriptUpdate\ +> sUrlSuffix) \\\r\ +> \n dst-path=\$FileName as-value;\r\ +> \n \$WaitForFile \$FileName;\r\ +> \n } on-error={\r\ +> \n :log warning (\$0 . \" Failed downloading certificate with CommonNam\ +> e '\" . \$CommonName . \\\r\ +> \n \"' from repository! Trying fallback to mkcert.org...\");\r\ +> \n :do {\r\ +> \n :local CertSettings [ /certificate/settings/get ];\r\ +> \n :if ([ :len [ /certificate/find where common-name=\"ISRG Root X1\"\ +> \_] ] = 0 && \\\r\ +> \n !(((\$CertSettings->\"builtin-trust-anchors\") = \"trusted\" \ +> || \\\r\ +> \n (\$CertSettings->\"builtin-trust-store\") ~ \"fetch\" || \ +> \\\r\ +> \n (\$CertSettings->\"builtin-trust-store\") = \"all\") && \\\ +> \r\ +> \n [ :len [ /certificate/builtin/find where common-name=\"ISRG\ +> \_Root X1\" ] ] > 0)) do={\r\ +> \n :log error (\$0 . \" Required certificate is not available.\");\ +> \r\ +> \n :return false;\r\ +> \n }\r\ +> \n /tool/fetch check-certificate=yes-without-crl http-header-field=({\ +> \_[ \$FetchUserAgentStr \$0 ] }) \\\r\ +> \n \"https://mkcert.org/generate/\" http-data=[ :serialize to=json \ +> ({ \$CommonName }) ] \\\r\ +> \n dst-path=\$FileName as-value;\r\ +> \n \$WaitForFile \$FileName;\r\ +> \n :if ([ /file/get \$FileName size ] = 0) do={\r\ +> \n \$RmFile \$FileName;\r\ +> \n :error false;\r\ +> \n }\r\ +> \n } on-error={\r\ +> \n :log warning (\$0 . \" Failed downloading certificate with CommonN\ +> ame '\" . \$CommonName . \"'!\");\r\ +> \n :return false;\r\ +> \n }\r\ +> \n }\r\ +> \n /certificate/import file-name=\$FileName passphrase=\"\" as-value;\r\ +> \n :delay 1s;\r\ +> \n \$RmFile \$FileName;\r\ +> \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] = 0\ +> ) do={\r\ +> \n /certificate/remove [ find where name~(\"^\" . \$FileName . \"_[0-9]\ +> +\\\$\") ];\r\ +> \n :log warning (\$0 . \" Certificate with CommonName '\" . \$CommonNam\ +> e . \"' still unavailable!\");\r\ +> \n :return false;\r\ +> \n }\r\ +> \n :foreach Cert in=[ /certificate/find where name~(\"^\" . \$FileName . \ +> \"_[0-9]+\\\$\") ] do={\r\ +> \n \$CertificateNameByCN [ /certificate/get \$Cert common-name ];\r\ +> \n }\r\ +> \n :return true;\r\ +> \n}\r\ +> \n\r\ +> \n# name a certificate by its common-name\r\ +> \n# Usage: \$CertificateNameByCN \"Common Name\"\r\ +> \n:set CertificateNameByCN do={\r\ +> \n :local Match [ :tostr \$1 ];\r\ +> \n :global CleanName;\r\ +> \n :local Cert ([ /certificate/find where (common-name=\$Match or fingerp\ +> rint=\$Match or name=\$Match) ]->0);\r\ +> \n :if ([ :len \$Cert ] = 0) do={\r\ +> \n :log warning (\$0 .\" No matching certificate found.\");\r\ +> \n :return false;\r\ +> \n }\r\ +> \n :local CommonName [ /certificate/get \$Cert common-name ];\r\ +> \n /certificate/set \$Cert name=[ \$CleanName \$CommonName ];\r\ +> \n :return true;\r\ +> \n}\r\ +> \n\r\ +> \n:set CharacterMultiply do={\r\ +> \n :local Str [ :tostr \$1 ];\r\ +> \n :local Num [ :tonum \$2 ];\r\ +> \n :if (\$Num = 0) do={:return \"\"}\r\ +> \n :local Return \"\";\r\ +> \n :for I from=1 to=\$Num do={:set Return (\$Return . \$Str)}\r\ +> \n :return \$Return;\r\ +> \n}\r\ +> \n\r\ +> \n:set FetchUserAgentStr do={\r\ +> \n :local Caller [ :tostr \$1 ];\r\ +> \n :global IfThenElse;\r\ +> \n :local Resource [ /system/resource/get ];\r\ +> \n :return (\"User-Agent: Mikrotik/\" . \$Resource->\"version\" . \" \" .\ +> \_\$Resource->\"architecture-name\" . \\\r\ +> \n \" \" . \$Caller . \"/Fetch (https://amster.vados.ru/; main/3419/3ee\ +> 19780)\");\r\ +> \n}\r\ +> \n\r\ +> \n:set Grep do={\r\ +> \n :local Input ([ :tostr \$1 ] . \"\\n\");\r\ +> \n :local Pattern [ :tostr \$2 ];\r\ +> \n :if ([ :typeof [ :find \$Input \$Pattern ] ] = \"nil\") do={:return []\ +> }\r\ +> \n :do {\r\ +> \n :local Line [ :pick \$Input 0 [ :find \$Input \"\\n\" ] ];\r\ +> \n :if ([ :typeof [ :find \$Line \$Pattern ] ] = \"num\") do={:return \ +> \$Line}\r\ +> \n :set Input [ :pick \$Input ([ :find \$Input \"\\n\" ] + 1) [ :len \$\ +> Input ] ];\r\ +> \n } while=([ :len \$Input ] > 0);\r\ +> \n :return [];\r\ +> \n}\r\ +> \n\r\ +> \n:set HumanReadableNum do={\r\ +> \n :local Input [ :tonum \$1 ];\r\ +> \n :local Base [ :tonum \$2 ];\r\ +> \n :global EitherOr;\r\ +> \n :global IfThenElse;\r\ +> \n :local Prefix \"kMGTPE\";\r\ +> \n :local Pow 1;\r\ +> \n :set Base [ \$EitherOr \$Base 1024 ];\r\ +> \n :local Bin [ \$IfThenElse (\$Base = 1024) \"i\" \"\" ];\r\ +> \n :if (\$Input < \$Base) do={:return \$Input}\r\ +> \n :for I from=0 to=[ :len \$Prefix ] do={\r\ +> \n :set Pow (\$Pow * \$Base);\r\ +> \n :if (\$Input / \$Base < \$Pow) do={\r\ +> \n :set Prefix [ :pick \$Prefix \$I ];\r\ +> \n :local Tmp1 (\$Input * 100 / \$Pow);\r\ +> \n :local Tmp2 (\$Tmp1 / 100);\r\ +> \n :if (\$Tmp2 >= 100) do={:return (\$Tmp2 . \$Prefix . \$Bin)}\r\ +> \n :return (\$Tmp2 . \".\" . \\\r\ +> \n [ :pick \$Tmp1 [ :len \$Tmp2 ] ([ :len \$Tmp1 ] - [ :len \$Tmp\ +> 2 ] + 1) ] . \\\r\ +> \n \$Prefix . \$Bin);\r\ +> \n }\r\ +> \n }\r\ +> \n}\r\ +> \n\r\ +> \n:set CleanName do={\r\ +> \n :local Input [ :tostr \$1 ];\r\ +> \n :local Return \"\";\r\ +> \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ +> \n :local Char [ :pick \$Input \$I ];\r\ +> \n :if ([ :typeof [ find \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr\ +> stuvwxyz0123456789\" \$Char ] ] = \"nil\") do={\r\ +> \n :do {:if ([ :len \$Return ] = 0) do={:error true};\r\ +> \n :if ([ :pick \$Return ([ :len \$Return ] - 1) ] = \"-\") do={:er\ +> ror true}; :set Char \"-\"} on-error={:set Char \"\"}; \r\ +> \n };\r\ +> \n :set Return (\$Return . \$Char)};\r\ +> \n :return \$Return;\r\ +> \n}\r\ +> \n\r\ +> \n:set GetRandomNumber do={\r\ +> \n :global EitherOr;\r\ +> \n :return [ :rndnum from=0 to=[ \$EitherOr [ :tonum \$1 ] 4294967295 ] ]\ +> \r\ +> \n}\r\ +> \n\r\ +> \n:set RandomDelay do={\r\ +> \n :local Time [ :tonum \$1 ];\r\ +> \n :local Unit [ :tostr \$2 ];\r\ +> \n :global EitherOr;\r\ +> \n :global GetRandomNumber;\r\ +> \n :global MAX;\r\ +> \n :if (\$Time = 0) do={:return false}\r\ +> \n :delay ([ \$MAX 10 [ \$GetRandomNumber ([ :tonsec [ :totime (\$Time . \ +> [ \$EitherOr \$Unit \"s\" ]) ] ] / 1000000) ] ] . \"ms\");\r\ +> \n}\r\ +> \n\r\ +> \n:set EscapeForRegEx do={\r\ +> \n :local Input [ :tostr \$1 ];\r\ +> \n :if ([ :len \$Input ] = 0) do={:return \"\"}\r\ +> \n :local Return \"\";\r\ +> \n :local Chars (\"^.[]\\\$()|*+\?{}\\\\\");\r\ +> \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ +> \n :local Char [ :pick \$Input \$I ];\r\ +> \n :if ([ :find \$Chars \$Char ]) do={:set Char (\"\\\\\" . \$Char)}\r\ +> \n :set Return (\$Return . \$Char);\r\ +> \n }\r\ +> \n :return \$Return;\r\ +> \n}\r\ +> \n\r\ +> \n:set ExitError do={\r\ +> \n :local ExitOK [ :tostr \$1 ];\r\ +> \n :local Name [ :tostr \$2 ];\r\ +> \n :local Error [ :tostr \$3 ];\r\ +> \n :global IfThenElse;\r\ +> \n :if (\$ExitOK = \"false\") do={\r\ +> \n :log error (\$Name [ \$IfThenElse ([ :pick \$Name 0 1 ] = \"\\\$\") \ +> \\\r\ +> \n \"Function\" \"Script\" ] . \" '\" . \$Name . \"' exited with er\ +> ror\" . \\\r\ +> \n [ \$IfThenElse (!(\$Error ~ \"^(|true|false)\\\$\")) (\": \" . \ +> \$Error) \".\" ]);\r\ +> \n }\r\ +> \n}\r\ +> \n\r\ +> \n:set MiniDateTimeStamp do={\r\ +> \n /system/clock;\r\ +> \n :local vdate [get date];\r\ +> \n :local vtime [get time];\r\ +> \n :local vdoff [:toarray \"0,4,5,7,8,10\"];\r\ +> \n :local MM [:pick \$vdate (\$vdoff->2) (\$vdoff->3)];\r\ +> \n :local M [:tonum \$MM];\r\ +> \n :if (\$vdate ~ \".../../....\") do={\r\ +> \n :set vdoff [:toarray \"7,11,1,3,4,6\"];\r\ +> \n :set M ([:find \"xxanebarprayunulugepctovecANEBARPRAYUNULUGE\ +> PCTOVEC\" [:pick \$vdate (\$vdoff->2) (\$vdoff->3)] -1] / 2);\r\ +> \n :if (\$M>12) do={:set M (\$M - 12)}\r\ +> \n :set MM [:pick (100 + \$M) 1 3];\r\ +> \n }\r\ +> \n :local yyyy [:pick \$vdate (\$vdoff->0) (\$vdoff->1)];\r\ +> \n :local dd [:pick \$vdate (\$vdoff->4) (\$vdoff->5)];\r\ +> \n :local HH [:pick \$vtime 0 2];\r\ +> \n :local mm [:pick \$vtime 3 5];\r\ +> \n :local ss [:pick \$vtime 6 8];\r\ +> \n :return ([\$yyyy] . [\$MM] . [\$dd] . [\$HH] . [\$mm] . [\$ss]);\r\ +> \n}\r\ +> \n\r\ +> \n:set WaitForFile do={\r\ +> \n :local FileName [ :tostr \$1 ];\r\ +> \n :local WaitTime [ :totime \$2 ];\r\ +> \n :global CleanFilePath;\r\ +> \n :global EitherOr;\r\ +> \n :global MAX;\r\ +> \n :set FileName [ \$CleanFilePath \$FileName ];\r\ +> \n :local Delay ([ \$MAX [ \$EitherOr \$WaitTime 2s ] 100ms ] / 9);\r\ +> \n :do {\r\ +> \n :retry {\r\ +> \n /file/get \$FileName;\r\ +> \n :return true;\r\ +> \n } delay=\$Delay max=10;\r\ +> \n } on-error={ }\r\ +> \n :while ([ :len [ /file/find where name=\$FileName ] ] > 0) do={\r\ +> \n :do {\r\ +> \n /file/get \$FileName;\r\ +> \n :return true;\r\ +> \n } on-error={ }\r\ +> \n :delay \$Delay;\r\ +> \n :set Delay (\$Delay * 3 / 2);\r\ +> \n }\r\ +> \n :return false;\r\ +> \n}\r\ +> \n\r\ +> \n:set FileGet do={\r\ +> \n :local FileName [ :tostr \$1 ];\r\ +> \n :global WaitForFile;\r\ +> \n :if ([ \$WaitForFile \$FileName 0s ] = false) do={:return false}\r\ +> \n :local FileVal false;\r\ +> \n :do {:set FileVal [ /file/get \$FileName ];\r\ +> \n } on-error={ }\r\ +> \n :return \$FileVal;\r\ +> \n}\r\ +> \n\r\ +> \n:set RmDir do={\r\ +> \n :local DirName [ :tostr \$1 ];\r\ +> \n :global FileGet;\r\ +> \n :global LogPrint;\r\ +> \n \$LogPrint debug \$0 (\"Removing directory: \". \$DirName);\r\ +> \n :local DirVal [ \$FileGet \$DirName ];\r\ +> \n :if (\$DirVal = false) do={\$LogPrint debug \$0 (\"... which does not \ +> exist.\"); :return true};\r\ +> \n :if (\$DirVal->\"type\" != \"directory\") do={\$LogPrint error \$0 (\"\ +> Directory '\" . \$DirName . \"' is not a directory.\"); :return false};\r\ +> \n :onerror Err {/file/remove \$DirName} do={\$LogPrint error \$0 (\"Remo\ +> ving directory '\" . \$DirName . \"' failed: \" . \$Err); :return false};\ +> \r\ +> \n :return true;\r\ +> \n}\r\ +> \n\r\ +> \n:set RmFile do={\r\ +> \n :local FileName [ :tostr \$1 ];\r\ +> \n :global FileGet;\r\ +> \n :global LogPrint;\r\ +> \n \$LogPrint debug \$0 (\"Removing file: \". \$FileName);\r\ +> \n :local FileVal [ \$FileGet \$FileName ];\r\ +> \n :if (\$FileVal = false) do={\$LogPrint debug \$0 (\"... which does not\ +> \_exist.\"); :return true}\r\ +> \n :if (\$FileVal->\"type\" = \"directory\" || \$FileVal->\"type\" = \"di\ +> sk\") do={\r\ +> \n \$LogPrint error \$0 (\"File '\" . \$FileName . \"' is not a file.\"\ +> ); :return false}\r\ +> \n :onerror Err {\r\ +> \n /file/remove \$FileName;\r\ +> \n } do={\$LogPrint error \$0 (\"Removing file '\" . \$FileName . \"' fai\ +> led: \" . \$Err); :return false}\r\ +> \n :return true;\r\ +> \n}\r\ +> \n\r\ +> \n:set MkDir do={\r\ +> \n :local Path [ :tostr \$1 ];\r\ +> \n :global CleanFilePath;\r\ +> \n :global FileGet;\r\ +> \n :global RmDir;\r\ +> \n :global WaitForFile;\r\ +> \n :global LogPrint;\r\ +> \n :local MkTmpfs do={\r\ +> \n :global WaitForFile;\r\ +> \n :local TmpFs [ /disk/find where slot=tmpfs type=tmpfs ];\r\ +> \n :if ([ :len \$TmpFs ] = 1) do={\r\ +> \n :if ([ /disk/get \$TmpFs disabled ] = true) do={\r\ +> \n \$LogPrint info \$0 (\"The tmpfs is disabled, enabling.\");\r\ +> \n /disk/enable \$TmpFs;\r\ +> \n }\r\ +> \n :return true;\r\ +> \n }\r\ +> \n \$LogPrint info \$0 (\"Creating disk of type tmpfs.\");\r\ +> \n \$RmDir \"tmpfs\";\r\ +> \n :onerror Err {\r\ +> \n /disk/add slot=tmpfs type=tmpfs tmpfs-max-size=([ /system/resource\ +> /get total-memory ] / 3);\r\ +> \n \$WaitForFile \"tmpfs\";\r\ +> \n } do={\r\ +> \n \$LogPrint warning \$0 (\"Creating disk of type tmpfs failed: \" .\ +> \_\$Err);\r\ +> \n :return false;\r\ +> \n }\r\ +> \n :return true;\r\ +> \n }\r\ +> \n :set Path [ \$CleanFilePath \$Path ];\r\ +> \n :if (\$Path = \"\") do={\r\ +> \n :return true;\r\ +> \n }\r\ +> \n \$LogPrint debug \$0 (\"Making directory: \" . \$Path);\r\ +> \n :local PathVal [ \$FileGet \$Path ];\r\ +> \n :if (\$PathVal->\"type\" = \"directory\") do={\r\ +> \n \$LogPrint debug \$0 (\"... which already exists.\");\r\ +> \n :return true;\r\ +> \n }\r\ +> \n :if ([ :pick \$Path 0 5 ] = \"tmpfs\") do={\r\ +> \n :if ([ \$MkTmpfs ] = false) do={\r\ +> \n :return false;\r\ +> \n }\r\ +> \n }\r\ +> \n :onerror Err {\r\ +> \n /file/add type=\"directory\" name=\$Path;\r\ +> \n \$WaitForFile \$Path;\r\ +> \n } do={\r\ +> \n \$LogPrint warning \$0 (\"Making directory '\" . \$Path . \"' failed\ +> : \" . \$Err);\r\ +> \n :return false;\r\ +> \n }\r\ +> \n :return true;\r\ +> \n}\r\ +> \n\r\ +> \n:set MAX do={:if (\$1 > \$2) do={:return \$1}\r\ +> \n :return \$2;\r\ +> \n}\r\ +> \n:set MIN do={:if (\$1 < \$2) do={:return \$1}\r\ +> \n :return \$2;\r\ +> \n}\r\ +> \n\r\ +> \n:set CharacterMultiply do={\r\ +> \n :local Str [ :tostr \$1 ];\r\ +> \n :local Num [ :tonum \$2 ];\r\ +> \n :if (\$Num = 0) do={:return \"\"}\r\ +> \n :local Return \"\";\r\ +> \n :for I from=1 to=\$Num do={:set Return (\$Return . \$Str)}\r\ +> \n :return \$Return;\r\ +> \n}\r\ +> \n\r\ +> \n:set CharacterReplace do={\r\ +> \n :local String [ :tostr \$1 ];\r\ +> \n :local ReplaceFrom [ :tostr \$2 ];\r\ +> \n :local ReplaceWith [ :tostr \$3 ];\r\ +> \n :local Return \"\";\r\ +> \n :if (\$ReplaceFrom = \"\") do={:return \$String}\r\ +> \n :while ([ :typeof [ :find \$String \$ReplaceFrom ] ] != \"nil\") do={\ +> \r\ +> \n :local Pos [ :find \$String \$ReplaceFrom ];\r\ +> \n :set Return (\$Return . [ :pick \$String 0 \$Pos ] . \$ReplaceWith);\ +> \r\ +> \n :set String [ :pick \$String (\$Pos + [ :len \$ReplaceFrom ]) [ :len\ +> \_\$String ] ];\r\ +> \n }\r\ +> \n :return (\$Return . \$String);\r\ +> \n}\r\ +> \n\r\ +> \n:set CleanFilePath do={\r\ +> \n :local Path [ :tostr \$1 ];\r\ +> \n :global CharacterReplace;\r\ +> \n :while (\$Path ~ \"//\") do={:set \$Path [ \$CharacterReplace \$Path \ +> \"//\" \"/\" ]};\r\ +> \n :if ([ :pick \$Path 0 ] = \"/\") do={:set Path [ :pick \$Path 1 [ :len\ +> \_\$Path ] ]};\r\ +> \n :if ([ :pick \$Path ([ :len \$Path ] - 1) ] = \"/\") do={:set Path [ :\ +> pick \$Path 0 ([ :len \$Path ] - 1) ]};\r\ +> \n :return \$Path;\r\ +> \n}\r\ +> \n\r\ +> \n:set IfThenElse do={\r\ +> \n :if ([ :tostr \$1 ] = \"true\" || [ :tobool \$1 ] = true) do={:return \ +> \$2};\r\ +> \n :return \$3;\r\ +> \n}\r\ +> \n\r\ +> \n:set EitherOr do={\r\ +> \n :global IfThenElse;\r\ +> \n :if ([ :typeof \$1 ] = \"num\") do={:return [ \$IfThenElse (\$1 != 0) \ +> \$1 \$2 ]}\r\ +> \n :if ([ :typeof \$1 ] = \"time\") do={:return [ \$IfThenElse (\$1 > 0s)\ +> \_\$1 \$2 ]}\r\ +> \n# this works for boolean values, literal ones with parentheses\r\ +> \n :return [ \$IfThenElse ([ :len [ :tostr \$1 ] ] > 0) \$1 \$2 ];\r\ +> \n}\r\ +> \n\r\ +> \n:set ParseKeyValueStore do={\r\ +> \n :local Source \$1;\r\ +> \n :if ([ :pick \$Source 0 1 ] = \"{\") do={\r\ +> \n :do {\r\ +> \n :return [ :deserialize from=json \$Source ];\r\ +> \n } on-error={ }\r\ +> \n } \r\ +> \n :if ([ :typeof \$Source ] != \"array\") do={:set Source [ :tostr \$1 ]\ +> }\r\ +> \n :local Result ({});\r\ +> \n :foreach KeyValue in=[ :toarray \$Source ] do={\r\ +> \n :if ([ :find \$KeyValue \"=\" ]) do={\r\ +> \n :local Key [ :pick \$KeyValue 0 [ :find \$KeyValue \"=\" ] ];\r\ +> \n :local Value [ :pick \$KeyValue ([ :find \$KeyValue \"=\" ] + 1) [\ +> \_:len \$KeyValue ] ];\r\ +> \n :if (\$Value=\"true\") do={:set Value true}\r\ +> \n :if (\$Value=\"false\") do={:set Value false}\r\ +> \n :set (\$Result->\$Key) \$Value;\r\ +> \n } else={:set (\$Result->\$KeyValue) true}\r\ +> \n }\r\ +> \n :return \$Result;\r\ +> \n}\r\ +> \n:set RequiredRouterOS do={\r\ +> \n :local Caller [ :tostr \$1 ];\r\ +> \n :local Required [ :tostr \$2 ];\r\ +> \n :local Warn [ :tostr \$3 ];\r\ +> \n :global IfThenElse;\r\ +> \n :global LogPrint;\r\ +> \n :global VersionToNum;\r\ +> \n :if (!(\$Required ~ \"^\\\\d+\\\\.\\\\d+((alpha|beta|rc|\\\\.)\\\\d+|)\ +> \\\$\")) do={\r\ +> \n \$LogPrint error \$0 (\"No valid RouterOS version: \" . \$Required);\ +> \r\ +> \n :return false;\r\ +> \n }\r\ +> \n :if ([ \$VersionToNum \$Required ] > [ \$VersionToNum [ /system/packag\ +> e/update/get installed-version ] ]) do={\r\ +> \n :if (\$Warn = \"true\") do={\r\ +> \n \$LogPrint warning \$0 (\"This \" . [ \$IfThenElse ([ :pick \$Call\ +> er 0 ] = (\"\\\$\")) \"function\" \"script\" ] . \\\r\ +> \n \" '\" . \$Caller . \"' (at least specific functionality) requir\ +> es RouterOS \" . \$Required . \". Please update!\");\r\ +> \n }\r\ +> \n :return false;\r\ +> \n }\r\ +> \n :return true;\r\ +> \n}\r\ +> \n:set VersionToNum do={\r\ +> \n :local Input [ :tostr \$1 ];\r\ +> \n :local Multi 0x1000000;\r\ +> \n :local Return 0;\r\ +> \n :global CharacterReplace;\r\ +> \n :set Input [ \$CharacterReplace \$Input \".\" \",\" ];\r\ +> \n :foreach I in={ \"zero\"; \"alpha\"; \"beta\"; \"rc\" } do={\r\ +> \n :set Input [ \$CharacterReplace \$Input \$I (\",\" . \$I . \",\") ];\ +> \r\ +> \n }\r\ +> \n :foreach Value in=([ :toarray \$Input ], 0) do={\r\ +> \n :local Num [ :tonum \$Value ];\r\ +> \n :if (\$Multi = 0x100) do={\r\ +> \n :if ([ :typeof \$Num ] = \"num\") do={\r\ +> \n :set Return (\$Return + 0xff00);\r\ +> \n :set Multi (\$Multi / 0x100);\r\ +> \n } else={\r\ +> \n :if (\$Value = \"zero\") do={ }\r\ +> \n :if (\$Value = \"alpha\") do={ :set Return (\$Return + 0x3f00); \ +> }\r\ +> \n :if (\$Value = \"beta\") do={ :set Return (\$Return + 0x5f00); }\ +> \r\ +> \n :if (\$Value = \"rc\") do={ :set Return (\$Return + 0x7f00); }\r\ +> \n }\r\ +> \n }\r\ +> \n :if ([ :typeof \$Num ] = \"num\") do={ :set Return (\$Return + (\$Va\ +> lue * \$Multi)); }\r\ +> \n :set Multi (\$Multi / 0x100);\r\ +> \n }\r\ +> \n :return \$Return;\r\ +> \n}\r\ +> \n:set ScriptLock do={\r\ +> \n :local Script [ :tostr \$1 ];\r\ +> \n :local WaitMax [ :totime \$2 ];\r\ +> \n :global GetRandom20CharAlNum;\r\ +> \n :global IfThenElse;\r\ +> \n :global LogPrint;\r\ +> \n :global ScriptLockOrder;\r\ +> \n :if ([ :typeof \$ScriptLockOrder ] = \"nothing\") do={\r\ +> \n :set ScriptLockOrder ({});\r\ +> \n }\r\ +> \n :if ([ :typeof (\$ScriptLockOrder->\$Script) ] = \"nothing\") do={\r\ +> \n :set (\$ScriptLockOrder->\$Script) ({});\r\ +> \n }\r\ +> \n :local JobCount do={\r\ +> \n :local Script [ :tostr \$1 ];\r\ +> \n :return [ :len [ /system/script/job/find where script=\$Script ] ];\ +> \r\ +> \n }\r\ +> \n :local TicketCount do={\r\ +> \n :local Script [ :tostr \$1 ];\r\ +> \n :global ScriptLockOrder;\r\ +> \n :local Count 0;\r\ +> \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ +> \n :if ([ :typeof \$Ticket ] != \"nothing\") do={:set Count (\$Count \ +> + 1)}\r\ +> \n }\r\ +> \n :return \$Count;\r\ +> \n }\r\ +> \n :local IsFirstTicket do={\r\ +> \n :local Script [ :tostr \$1 ];\r\ +> \n :local Check [ :tostr \$2 ];\r\ +> \n :global ScriptLockOrder;\r\ +> \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ +> \n :if (\$Ticket = \$Check) do={:return true}\r\ +> \n :if ([ :typeof \$Ticket ] != \"nothing\" && \$Ticket != \$Check) d\ +> o={:return false}\r\ +> \n }\r\ +> \n :return false;\r\ +> \n }\r\ +> \n :local AddTicket do={\r\ +> \n :local Script [ :tostr \$1 ];\r\ +> \n :local Add [ :tostr \$2 ];\r\ +> \n :global ScriptLockOrder;\r\ +> \n :while (true) do={\r\ +> \n :local Pos [ :len (\$ScriptLockOrder->\$Script) ];\r\ +> \n :set (\$ScriptLockOrder->\$Script->\$Pos) \$Add;\r\ +> \n :delay 10ms;\r\ +> \n :if ((\$ScriptLockOrder->\$Script->\$Pos) = \$Add) do={:return tru\ +> e}\r\ +> \n }\r\ +> \n }\r\ +> \n :local RemoveTicket do={\r\ +> \n :local Script [ :tostr \$1 ];\r\ +> \n :local Remove [ :tostr \$2 ];\r\ +> \n :global ScriptLockOrder;\r\ +> \n :foreach Id,Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ +> \n :while ((\$ScriptLockOrder->\$Script->\$Id) = \$Remove) do={\r\ +> \n :set (\$ScriptLockOrder->\$Script->\$Id);\r\ +> \n :delay 10ms;\r\ +> \n }\r\ +> \n }\r\ +> \n }\r\ +> \n :local CleanupTickets do={\r\ +> \n :local Script [ :tostr \$1 ];\r\ +> \n :global ScriptLockOrder;\r\ +> \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ +> \n :if ([ :typeof \$Ticket ] != \"nothing\") do={:return false}\r\ +> \n }\r\ +> \n :set (\$ScriptLockOrder->\$Script) ({});\r\ +> \n }\r\ +> \n :if ([ :typeof \$WaitMax ] = \"nil\" ) do={:set WaitMax 0s}\r\ +> \n :if ([ :len [ /system/script/find where name=\$Script ] ] = 0) do={\r\ +> \n \$LogPrint error \$0 (\"A script named '\" . \$Script . \"' does not\ +> \_exist!\");\r\ +> \n :error false;\r\ +> \n }\r\ +> \n :if ([ \$JobCount \$Script ] = 0) do={\r\ +> \n \$LogPrint error \$0 (\"No script '\" . \$Script . \"' is running!\"\ +> );\r\ +> \n :error false;\r\ +> \n }\r\ +> \n :if ([ \$TicketCount \$Script ] >= [ \$JobCount \$Script ]) do={\r\ +> \n \$LogPrint error \$0 (\"More tickets than running scripts '\" . \$Sc\ +> ript . \"', resetting!\");\r\ +> \n :set (\$ScriptLockOrder->\$Script) ({});\r\ +> \n /system/script/job/remove [ find where script=\$Script ];\r\ +> \n }\r\ +> \n :local MyTicket [ \$GetRandom20CharAlNum 6 ];\r\ +> \n \$AddTicket \$Script \$MyTicket;\r\ +> \n :local WaitInterval (\$WaitMax / 20);\r\ +> \n :local WaitTime \$WaitMax;\r\ +> \n :while (\$WaitTime > 0 && \\\r\ +> \n ([ \$IsFirstTicket \$Script \$MyTicket ] = false || \\\r\ +> \n [ \$TicketCount \$Script ] < [ \$JobCount \$Script ])) do={\r\ +> \n :set WaitTime (\$WaitTime - \$WaitInterval);\r\ +> \n :delay \$WaitInterval;\r\ +> \n }\r\ +> \n :if ([ \$IsFirstTicket \$Script \$MyTicket ] = true && \\\r\ +> \n [ \$TicketCount \$Script ] = [ \$JobCount \$Script ]) do={\r\ +> \n \$RemoveTicket \$Script \$MyTicket;\r\ +> \n \$CleanupTickets \$Script;\r\ +> \n :return true;\r\ +> \n }\r\ +> \n \$RemoveTicket \$Script \$MyTicket;\r\ +> \n \$LogPrint debug \$0 (\"Script '\" . \$Script . \"' started more than \ +> once\" . \\\r\ +> \n [ \$IfThenElse (\$WaitTime < \$WaitMax) \" and timed out waiting for\ +> \_lock\" \"\" ] . \"...\");\r\ +> \n :return false;\r\ +> \n}\r\ +> \n:set SendNotification do={ :onerror Err {\r\ +> \n :global SendNotification2;\r\ +> \n \$SendNotification2 ({ origin=\$0; subject=\$1; message=\$2; link=\$3;\ +> \_silent=\$4 });\r\ +> \n} do={:global ExitOnError; \$ExitOnError \$0 \$Err}\r\ +> \n}\r\ +> \n:set SendNotification2 do={\r\ +> \n :local Notification \$1;\r\ +> \n :global NotificationFunctions;\r\ +> \n :foreach FunctionName,Discard in=\$NotificationFunctions do={\r\ +> \n (\$NotificationFunctions->\$FunctionName) (\"\\\$NotificationFunctio\ +> ns->\\\"\" . \$FunctionName . \"\\\"\") \$Notification;\r\ +> \n }\r\ +> \n}\r\ +> \n:set SymbolByUnicodeName do={\r\ +> \n :local Name [ :tostr \$1 ];\r\ +> \n :global EitherOr;\r\ +> \n :global LogPrint;\r\ +> \n :global SymbolsExtra;\r\ +> \n :local Symbols ({\r\ +> \n \"abacus\"=\"\\F0\\9F\\A7\\AE\";\r\ +> \n \"alarm-clock\"=\"\\E2\\8F\\B0\";\r\ +> \n \"arrow-down\"=\"\\E2\\AC\\87\";\r\ +> \n \"arrow-up\"=\"\\E2\\AC\\86\";\r\ +> \n \"calendar\"=\"\\F0\\9F\\93\\85\";\r\ +> \n \"card-file-box\"=\"\\F0\\9F\\97\\83\";\r\ +> \n \"chart-decreasing\"=\"\\F0\\9F\\93\\89\";\r\ +> \n \"chart-increasing\"=\"\\F0\\9F\\93\\88\";\r\ +> \n \"cloud\"=\"\\E2\\98\\81\";\r\ +> \n \"cross-mark\"=\"\\E2\\9D\\8C\";\r\ +> \n \"earth\"=\"\\F0\\9F\\8C\\8D\";\r\ +> \n \"fire\"=\"\\F0\\9F\\94\\A5\";\r\ +> \n \"floppy-disk\"=\"\\F0\\9F\\92\\BE\";\r\ +> \n \"gear\"=\"\\E2\\9A\\99\";\r\ +> \n \"heart\"=\"\\E2\\99\\A5\";\r\ +> \n \"high-voltage-sign\"=\"\\E2\\9A\\A1\";\r\ +> \n \"incoming-envelope\"=\"\\F0\\9F\\93\\A8\";\r\ +> \n \"information\"=\"\\E2\\84\\B9\";\r\ +> \n \"large-orange-circle\"=\"\\F0\\9F\\9F\\A0\";\r\ +> \n \"large-red-circle\"=\"\\F0\\9F\\94\\B4\";\r\ +> \n \"link\"=\"\\F0\\9F\\94\\97\";\r\ +> \n \"lock-with-ink-pen\"=\"\\F0\\9F\\94\\8F\";\r\ +> \n \"memo\"=\"\\F0\\9F\\93\\9D\";\r\ +> \n \"mobile-phone\"=\"\\F0\\9F\\93\\B1\";\r\ +> \n \"pushpin\"=\"\\F0\\9F\\93\\8C\";\r\ +> \n \"scissors\"=\"\\E2\\9C\\82\";\r\ +> \n \"scroll\"=\"\\F0\\9F\\93\\9C\";\r\ +> \n \"smiley-partying-face\"=\"\\F0\\9F\\A5\\B3\";\r\ +> \n \"smiley-smiling-face\"=\"\\E2\\98\\BA\";\r\ +> \n \"smiley-winking-face-with-tongue\"=\"\\F0\\9F\\98\\9C\";\r\ +> \n \"sparkles\"=\"\\E2\\9C\\A8\";\r\ +> \n \"speech-balloon\"=\"\\F0\\9F\\92\\AC\";\r\ +> \n \"star\"=\"\\E2\\AD\\90\";\r\ +> \n \"warning-sign\"=\"\\E2\\9A\\A0\";\r\ +> \n \"white-heavy-check-mark\"=\"\\E2\\9C\\85\"\r\ +> \n }, \$SymbolsExtra);\r\ +> \n :local Magic [ :pick [ /system/clock/get date ] 4 10 ];\r\ +> \n :local Special {\r\ +> \n \"information-04-01\"=\"\\F0\\9F\\9A\\BB\";\r\ +> \n \"large-orange-circle-04-01\"=\"\\F0\\9F\\8D\\8A\";\r\ +> \n \"large-orange-circle-10-31\"=\"\\F0\\9F\\8E\\83\";\r\ +> \n \"large-red-circle-04-01\"=\"\\F0\\9F\\8D\\92\" };\r\ +> \n :if ([ :len (\$Symbols->\$Name) ] = 0) do={\r\ +> \n \$LogPrint warning \$0 (\"No symbol available for name '\" . \$Name \ +> . \"'!\");\r\ +> \n :return \"\";\r\ +> \n }\r\ +> \n :return ([ \$EitherOr (\$Special->(\$Name . \$Magic)) (\$Symbols->\$Na\ +> me) ] . \"\\EF\\B8\\8F\");\r\ +> \n}\r\ +> \n:set SymbolForNotification do={\r\ +> \n :global NotificationsWithSymbols;\r\ +> \n :global SymbolByUnicodeName;\r\ +> \n :global IfThenElse;\r\ +> \n :if (\$NotificationsWithSymbols != true) do={:return [ \$IfThenElse ([\ +> \_:len \$2 ] > 0) ([ :tostr \$2 ] . \" \") \"\" ]}\r\ +> \n :local Return \"\";\r\ +> \n :foreach Symbol in=[ :toarray \$1 ] do={:set Return (\$Return . [ \$Sy\ +> mbolByUnicodeName \$Symbol ])}\r\ +> \n :return (\$Return . \" \");\r\ +> \n}\r\ +> \n:set Unix2Dos do={:return [ :tocrlf [ :tostr \$1 ] ]}\r\ +> \n:set UrlEncode do={\r\ +> \n :local Input [ :tostr \$1 ];\r\ +> \n :if ([ :len \$Input ] = 0) do={:return \"\"}\r\ +> \n :local Return \"\";\r\ +> \n :local Chars (\"\\n\\r !\\\"#\\\$%&'()*+,:;<=>\?@[\\\\]^`{|}~\");\r\ +> \n :local Subs { \"%0A\"; \"%0D\"; \"%20\"; \"%21\"; \"%22\"; \"%23\"; \"\ +> %24\"; \"%25\"; \"%26\"; \"%27\";\r\ +> \n \"%28\"; \"%29\"; \"%2A\"; \"%2B\"; \"%2C\"; \"%3A\"; \"%3B\"; \ +> \"%3C\"; \"%3D\"; \"%3E\"; \"%3F\";\r\ +> \n \"%40\"; \"%5B\"; \"%5C\"; \"%5D\"; \"%5E\"; \"%60\"; \"%7B\"; \ +> \"%7C\"; \"%7D\"; \"%7E\" };\r\ +> \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ +> \n :local Char [ :pick \$Input \$I ];\r\ +> \n :local Replace [ :find \$Chars \$Char ];\r\ +> \n :if ([ :typeof \$Replace ] = \"num\") do={:set Char (\$Subs->\$Repla\ +> ce)}\r\ +> \n :set Return (\$Return . \$Char);\r\ +> \n }\r\ +> \n :return \$Return;\r\ +> \n}\r\ +> \n:set ValidateSyntax do={\r\ +> \n :local Code [ :tostr \$1 ];\r\ +> \n :global LogPrint;\r\ +> \n :onerror Err {\r\ +> \n [ :parse (\":local Validate do={\\n\" . \$Code . \"\\n}\") ];\r\ +> \n } do={\r\ +> \n \$LogPrint debug \$0 (\"Valdation failed: \" . \$Err);\r\ +> \n :return false;\r\ +> \n }\r\ +> \n :return true;\r\ +> \n}\r\ +> \n:set IsDNSResolving do={\r\ +> \n :do {:resolve \"api.telegram.org\"} on-error={:return false}\r\ +> \n :return true;\r\ +> \n}\r\ +> \n:set IsFullyConnected do={\r\ +> \n :global IsDNSResolving;\r\ +> \n :global IsTimeSync;\r\ +> \n :if ([ \$IsDNSResolving ] = false) do={:return false};\r\ +> \n :if ([ \$IsTimeSync ] = false) do={:return false};\r\ +> \n :return true;\r\ +> \n}\r\ +> \n:set IsTimeSync do={\r\ +> \n :global IsTimeSyncCached;\r\ +> \n :global IsTimeSyncResetNtp;\r\ +> \n :if (\$IsTimeSyncCached = true) do={:return true}\r\ +> \n :if ([ /system/ntp/client/get enabled ] = true) do={\r\ +> \n :if ([ /system/ntp/client/get status ] = \"synchronized\") do={\r\ +> \n :set IsTimeSyncCached true;\r\ +> \n :return true;\r\ +> \n }\r\ +> \n :local Uptime [ /system/resource/get uptime ];\r\ +> \n :if ([ :typeof \$IsTimeSyncResetNtp ] = \"nothing\") do={\r\ +> \n :set IsTimeSyncResetNtp \$Uptime;\r\ +> \n }\r\ +> \n :if (\$Uptime - \$IsTimeSyncResetNtp < 3m) do={:return false}\r\ +> \n :log warning \"\$0 The ntp client is configured, but did not sync.\"\ +> ;\r\ +> \n :set IsTimeSyncResetNtp \$Uptime;\r\ +> \n /system/ntp/client/set enabled=no;\r\ +> \n :delay 20ms;\r\ +> \n /system/ntp/client/set enabled=yes;\r\ +> \n :return false;\r\ +> \n }\r\ +> \n :if ([ /system/license/get ]->\"level\" = \"free\" || \\\r\ +> \n [ /system/resource/get ]->\"board-name\" = \"x86\") do={\r\ +> \n :log debug \"\$0 No ntp client configured, relying on RTC for CHR fr\ +> ee license and x86.\";\r\ +> \n :return true;\r\ +> \n }\r\ +> \n :if ([ /ip/cloud/get update-time ] = true) do={\r\ +> \n :if ([ :typeof [ /ip/cloud/get public-address ] ] = \"ip\") do={\r\ +> \n :set IsTimeSyncCached true;\r\ +> \n :return true;\r\ +> \n }\r\ +> \n :return false;\r\ +> \n }\r\ +> \n :log debug \"\$0 No time source configured! Returning gracefully...\";\ +> \r\ +> \n :return true;\r\ +> \n}\r\ +> \n\r\ +> \n# read parts of a large file\r\ +> \n:set FetchLargeFiles do={\r\ +> \n :local ScriptName [:tostr \$1];\r\ +> \n :local fetchUrl [:tostr \$2];\r\ +> \n :local CheckCert [:tostr \$3];\r\ +> \n :local fetchMode [:tostr \$4];\r\ +> \n :local fetchMethod [:tostr \$5];\r\ +> \n :local FetchString \"undefined\";\r\ +> \n \r\ +> \n :global CleanName;\r\ +> \n :global FetchUserAgentStr;\r\ +> \n :global GetRandom20CharAlNum;\r\ +> \n :global IfThenElse;\r\ +> \n :global LogPrint;\r\ +> \n :global MkDir;\r\ +> \n :global RmDir;\r\ +> \n :global RmFile;\r\ +> \n :global WaitForFile;\r\ +> \n\r\ +> \n :set CheckCert [ \$IfThenElse (\$CheckCert = \"false\") \"no\" \"yes-w\ +> ithout-crl\" ];\r\ +> \n #:set fetchMode [ \$IfThenElse (\$fetchMode != \"false\") [:tostr (\"m\ +> ode=\" . \$fetchMode)] ];\r\ +> \n #:set fetchMethod [\$IfThenElse (\$fetchMethod != \"false\") [:tostr (\ +> \"http-method=\\\"\" . \$fetchMethod . \"\\\"\") ]];\r\ +> \n \r\ +> \n :local DirName (\"tmpfs/\" . [ \$CleanName \$ScriptName ]);\r\ +> \n :if ([ \$MkDir \$DirName ] = false) do={\r\ +> \n \$LogPrint error \$0 (\"Failed creating directory!\");\r\ +> \n :return false;\r\ +> \n }\r\ +> \n :local FileName (\$DirName . \"/\" . [ \$CleanName \$0 ] . \"-\" . [ \ +> \$GetRandom20CharAlNum ]);\r\ +> \n #/tool/fetch check-certificate=\$CheckCert \$Url dst-path=\$FileName h\ +> ttp-header-field=({ [ \$FetchUserAgentStr \$ScriptName ] }) as-value;\r\ +> \n #:log warning (\"\\\$fUrl =\" . \$2 . ({[ \$fMode ]}));\r\ +> \n :onerror Err {\r\ +> \n :set FetchString (\"/tool/fetch \" . \\\r\ +> \n [\$IfThenElse ([\$fetchMethod] != \"false\") (\"http-method=\\\"\"\ +> \_. \$fetchMethod . \"\\\" \")] . \\\r\ +> \n \"check-certificate=\" . \$CheckCert . \" url=(\\\"\" . \$fetchUrl\ +> \_. \"\\\") \" . \\\r\ +> \n [\$IfThenElse ([\$fetchMode] != \"false\") (\"mode=\" . \$fetchMod\ +> e . \" \")] . \\\r\ +> \n http-header-field=({ [ \$FetchUserAgentStr \$ScriptName ] }) as-va\ +> lue);\r\ +> \n :log warning (\"\\\$FetchSring = \" . \$FetchString);\r\ +> \n :put [\$FetchString];\r\ +> \n #:put [/tool/fetch \$fetchMode check-certificate=\$CheckCert url=(\$\ +> fetchUrl) dst-path=(\$FileName) http-header-field=({ [ \$FetchUserAgentStr\ +> \_\$ScriptName ] }) as-value];\r\ +> \n } do={\r\ +> \n :if ([ \$WaitForFile \$FileName 500ms ] = true) do={\r\ +> \n \$RmFile \$FileName;\r\ +> \n }\r\ +> \n \$LogPrint debug \$0 (\"Failed downloading from \" . \$fetchUrl . \"\ +> \_- \" . \$Err);\r\ +> \n \$RmDir \$DirName;\r\ +> \n :return false;\r\ +> \n }\r\ +> \n :if ([ \$WaitForFile \$FileName 5s ] = false) do={\r\ +> \n \$LogPrint debug \$0 (\"The file downloaded from \" . \$fetchUrl . \ +> \" did not show up.\");\r\ +> \n :return false;\r\ +> \n }\r\ +> \n :local FileSize [ /file/get \$FileName size ];\r\ +> \n :local Return \"\";\r\ +> \n :local VarSize 0;\r\ +> \n :while (\$VarSize != \$FileSize) do={\r\ +> \n :set Return (\$Return . ([ /file/read offset=\$VarSize chunk-size=32\ +> 768 file=\$FileName as-value ]->\"data\"));\r\ +> \n :set FileSize [ /file/get \$FileName size ];\r\ +> \n :set VarSize [ :len \$Return ];\r\ +> \n :if (\$VarSize > \$FileSize) do={\r\ +> \n :delay 100ms;\r\ +> \n }\r\ +> \n }\r\ +> \n \$RmDir \$DirName;\r\ +> \n :return \$Return;\r\ +> \n}\r\ +> \n\r\ +> \n:set ScriptInstallUpdate do={ :onerror Err {\r\ +> \n :local Scripts [ :toarray \$1 ];\r\ +> \n :local NewComment [ :tostr \$2 ];\r\ +> \n :global InitSetup;\r\ +> \n\r\ +> \n :global CommitId;\r\ +> \n :global ScriptUpdatesCRLF;\r\ +> \n :global GlobalConfVersion;\r\ +> \n :global Identity;\r\ +> \n :global CertificateAvailable;\r\ +> \n :global CheckSumsVerify;\r\ +> \n :global GlobalScriptsUrl;\r\ +> \n :global SumsDirAndFileName;\r\ +> \n :global GlobalScriptsUrlSuffix;\r\ +> \n :global EitherOr;\r\ +> \n :global FetchUserAgentStr;\r\ +> \n :global Grep;\r\ +> \n :global IfThenElse;\r\ +> \n :global LogPrint;\r\ +> \n :global ParseKeyValueStore;\r\ +> \n :global RequiredRouterOS;\r\ +> \n :global SendNotification2;\r\ +> \n :global SymbolForNotification;\r\ +> \n :global ValidateSyntax;\r\ +> \n :global CommentsInScripts;\r\ +> \n\r\ +> \n :if ([ \$CertificateAvailable \"Root YE\" \"fetch\" ] = false) do={\r\ +> \n \$LogPrint warning \$0 (\"Downloading certificate failed, trying wit\ +> hout.\");\r\ +> \n }\r\ +> \n\r\ +> \n :foreach Script in=\$Scripts do={\r\ +> \n :if ([ :len [ /system/script/find where name=\$Script ] ] = 0) do={\ +> \r\ +> \n \$LogPrint info \$0 (\"Adding new script: \" . \$Script);\r\ +> \n /system/script/add name=\$Script owner=\$Script source=\"#!rsc by \ +> Vados\\n\" comment=\$NewComment;\r\ +> \n }\r\ +> \n }\r\ +> \n\r\ +> \n :local CommitIdBefore \$CommitId;\r\ +> \n :local GlobalConfVersionBefore \$GlobalConfVersion;\r\ +> \n :local ReloadGlobal false;\r\ +> \n :local DeviceMode [ /system/device-mode/get ];\r\ +> \n\r\ +> \n :if (\$CheckSumsVerify = true) do={\r\ +> \n :local CheckSums ({});\r\ +> \n :do {\r\ +> \n :local Url (\$GlobalScriptsUrl . \$SumsDirAndFileName . \$GlobalScr\ +> iptsUrlSuffix);\r\ +> \n \$LogPrint debug \$0 (\"Fetching checksums from url: \" . \$Url);\ +> \r\ +> \n :set CheckSums [ :deserialize from=json ([ /tool/fetch check-certi\ +> ficate=yes-without-crl \\\r\ +> \n http-header-field=({ [ \$FetchUserAgentStr \$0 ] }) \$Url output\ +> =user as-value ]->\"data\") ];\r\ +> \n } on-error={ \$LogPrint warning \$0 (\"Err = \" . \$Err); }\r\ +> \n }\r\ +> \n\r\ +> \n :foreach Script in=[ /system/script/find where source~\"^#!rsc by Vado\ +> s\" ] do={\r\ +> \n :local ScriptVal [ /system/script/get \$Script ];\r\ +> \n :local ScriptInfo [ \$ParseKeyValueStore (\$ScriptVal->\"comment\") \ +> ];\r\ +> \n :local SourceNew;\r\ +> \n\r\ +> \n :foreach Scheduler in=[ /system/scheduler/find where on-event~(\"\\\ +> \\b\" . \$ScriptVal->\"name\" . \"\\\\b\") ] do={\r\ +> \n :local SchedulerVal [ /system/scheduler/get \$Scheduler ];\r\ +> \n :if (\$ScriptVal->\"policy\" != \$SchedulerVal->\"policy\") do={\r\ +> \n \$LogPrint warning \$0 (\"Policies differ for script '\" . \$Scr\ +> iptVal->\"name\" . \"' and its scheduler '\" . \$SchedulerVal->\"name\" . \ +> \"'!\");\r\ +> \n }\r\ +> \n }\r\ +> \n :do {\r\ +> \n :if (\$ScriptInfo->\"ignore\" = true) do={\r\ +> \n \$LogPrint debug \$0 (\"Ignoring script '\" . \$ScriptVal->\"nam\ +> e\" . \"', as requested.\");\r\ +> \n :error true;\r\ +> \n }\r\ +> \n :if (\$CheckSumsVerify = true) do={\r\ +> \n :local CheckSum (\$CheckSums->(\$ScriptVal->\"name\"));\r\ +> \n :if ([ :len (\$ScriptInfo->\"base-url\") ] = 0 && [ :len (\$Scri\ +> ptInfo->\"url-suffix\") ] = 0 && \\\r\ +> \n [ :convert transform=md5 to=hex [ :tolf (\$ScriptVal->\"sou\ +> rce\") ] ] = \$CheckSum) do={\r\ +> \n \$LogPrint debug \$0 (\"Checksum for script '\" . \$ScriptVal-\ +> >\"name\" . \"' matches, ignoring.\");\r\ +> \n :error true;\r\ +> \n }\r\ +> \n }\r\ +> \n :if ([ :len (\$ScriptInfo->\"certificate\") ] > 0) do={\r\ +> \n :if ([ \$CertificateAvailable (\$ScriptInfo->\"certificate\") \"\ +> fetch\" ] = false) do={\r\ +> \n \$LogPrint warning \$0 (\"Downloading certificate failed, tryi\ +> ng without.\");\r\ +> \n }\r\ +> \n }\r\ +> \n :onerror Err {\r\ +> \n :local BaseUrl [ \$EitherOr (\$ScriptInfo->\"base-url\") \$Globa\ +> lScriptsUrl ];\r\ +> \n :local UrlSuffix [ \$EitherOr (\$ScriptInfo->\"url-suffix\") \$G\ +> lobalScriptsUrlSuffix ];\r\ +> \n :local Url (\$BaseUrl . \$ScriptVal->\"name\" . \".rsc\" . \$Url\ +> Suffix);\r\ +> \n \$LogPrint warning \$0 (\"Fetching script '\" . (\$ScriptVal->\"\ +> name\") . \"' from url: \" . \$Url);\r\ +> \n :local Result [ /tool/fetch check-certificate=yes-without-crl \\\ +> \r\ +> \n http-header-field=({ [ \$FetchUserAgentStr \$0 ] }) \$Url outp\ +> ut=user as-value ];\r\ +> \n :if (\$Result->\"status\" = \"finished\") do={\r\ +> \n :set SourceNew [ :tolf (\$Result->\"data\") ];\r\ +> \n } \r\ +> \n } do={\r\ +> \n \$LogPrint warning \$0 (\"Failed fetching script '\" . \$ScriptV\ +> al->\"name\" . \"': \" . \$Err);\r\ +> \n :if (\$Err != \"Fetch failed with status 404\") do={\r\ +> \n :error false;\r\ +> \n }\r\ +> \n :if (\$ScriptVal->\"source\" = \"#!rsc by Vados\") do={\r\ +> \n \$LogPrint warning \$0 (\"Removing dummy. Typo on installation\ +> \?\");\r\ +> \n /system/script/remove \$Script;\r\ +> \n :error false;\r\ +> \n }\r\ +> \n :if (\$CheckSumsVerify = true) do={\r\ +> \n :if ([ :len (\$ScriptInfo->\"base-url\") ] = 0 && [ :len (\$Sc\ +> riptInfo->\"url-suffix\") ] = 0 && \\\r\ +> \n [ :len \$CheckSum ] = 0) do={\r\ +> \n \$LogPrint warning \$0 (\"Added the script manually\? Skip u\ +> pdates with 'ignore=true' in comment.\");\r\ +> \n }\r\ +> \n }\r\ +> \n :error false;\r\ +> \n }\r\ +> \n\r\ +> \n :if ([ :len \$SourceNew ] = 0) do={\r\ +> \n \$LogPrint debug \$0 (\"No update for script '\" . (\$ScriptVal-\ +> >\"name\") . \"'.\");\r\ +> \n :error false;\r\ +> \n }\r\ +> \n\r\ +> \n :local SourceCRLF [ :tocrlf \$SourceNew ];\r\ +> \n :if (\$InitSetup != true && ((\$ScriptVal->\"name\") != \"AM-Globa\ +> lConfig\" || (\$ScriptVal->\"name\") != \"AM-GlobalFunc\")) do={\r\ +> \n :if (\$SourceNew = (\$ScriptVal->\"source\") || \$SourceCRLF = (\ +> \$ScriptVal->\"source\")) do={\r\ +> \n \$LogPrint debug \$0 (\"Script '\" . (\$ScriptVal->\"name\") \ +> . \"' source did not change. End of lines set to CRLF.\");\r\ +> \n if (\$ScriptUpdatesCRLF = false) do={\r\ +> \n :put [ :tolf \$SourceNew ];\r\ +> \n \$LogPrint debug \$0 (\"Script '\" . (\$ScriptVal->\"name\"\ +> ) . \"' source update end of lines to LF.\");\r\ +> \n }\r\ +> \n :error false;\r\ +> \n }\r\ +> \n }\r\ +> \n\r\ +> \n :if ([ :pick \$SourceNew 0 14 ] != \"#!rsc by Vados\") do={\r\ +> \n \$LogPrint warning \$0 (\"Looks like new script '\" . \$ScriptVa\ +> l->\"name\" . \"' is not valid (missing shebang = '\$shebang') Ignoring!\"\ +> );\r\ +> \n :error false;\r\ +> \n }\r\ +> \n\r\ +> \n :if (\$CommentsInScripts = true) do={\r\ +> \n :local CommentLine [ \$Grep \$SourceNew (\"\\23 Script comment:\ +> \_\") ];\r\ +> \n :if ([ :len \$CommentLine ] = 0) do={\r\ +> \n \$LogPrint debug \$0 (\"The search in new script '\" . (\$Scr\ +> iptVal->\"name\") . \"' for comment in script body, is not found result Ig\ +> noring!\");\r\ +> \n :error false;\r\ +> \n } else={\r\ +> \n :if ([ :len (\$ScriptVal->\"comment\")] = 0 || [ :len (\$Scri\ +> ptVal->\"comment\")] != [ :pick \$CommentLine ([ :find \$CommentLine \":\"\ +> ] + 2) [ :len \$CommentLine] ]) do={\r\ +> \n \$LogPrint debug \$0 (\"Exsiting comment for script '\" . (\ +> \$ScriptVal->\"name\") . \"' is '\" . (\$ScriptVal->\"comment\") . \"'.\")\ +> ;\r\ +> \n :set (\$ScriptVal->\"comment\") [ :pick \$CommentLine ([ :f\ +> ind \$CommentLine \":\"] + 2) [ :len \$CommentLine] ];\r\ +> \n \$LogPrint debug \$0 (\"New comment (\" . (\$ScriptVal->\"c\ +> omment\") . \") for script '\" . (\$ScriptVal->\"name\") . \"' has been ad\ +> ded!\");\r\ +> \n } else={\r\ +> \n \$LogPrint debug \$0 (\"Comment for script '\" . (\$ScriptV\ +> al->\"name\") . \"' did not change.\");\r\ +> \n :error false;\r\ +> \n }\r\ +> \n } \r\ +> \n }\r\ +> \n\r\ +> \n :local RequiredROS ([ \$ParseKeyValueStore [ \$Grep \$SourceNew (\ +> \"\\23 requires RouterOS, \") ] ]->version);\r\ +> \n :if ([ \$RequiredRouterOS \$0 [ \$EitherOr \$RequiredROS \"0.0\" ]\ +> \_false ] = false) do={\r\ +> \n \$LogPrint warning \$0 (\"The script '\" . (\$ScriptVal->\"name\ +> \") . \"' requires RouterOS \" . \\\r\ +> \n \$RequiredROS . \", which is not met by your installation. I\ +> gnoring!\");\r\ +> \n :error false;\r\ +> \n }\r\ +> \n :local RequiredDM [ \$ParseKeyValueStore [ \$Grep \$SourceNew (\"\ +> \\23 requires device-mode, \") ] ];\r\ +> \n :local MissingDM ({});\r\ +> \n :foreach Feature,Value in=\$RequiredDM do={\r\ +> \n :if ([ :typeof (\$DeviceMode->\$Feature) ] = \"bool\" && (\$Devi\ +> ceMode->\$Feature) = false) do={\r\ +> \n :set MissingDM (\$MissingDM, \$Feature);\r\ +> \n }\r\ +> \n }\r\ +> \n :if ([ :len \$MissingDM ] > 0) do={\r\ +> \n \$LogPrint warning \$0 (\"The script '\" . (\$ScriptVal->\"name\ +> \") . \"' requires disabled \" . \\\r\ +> \n \"device-mode features (\" . [ :tostr \$MissingDM ] . \"). I\ +> gnoring!\");\r\ +> \n :error false;\r\ +> \n }\r\ +> \n\r\ +> \n :if ([ \$ValidateSyntax \$SourceNew ] = false) do={\r\ +> \n \$LogPrint warning \$0 (\"Syntax validation for script '\" . (\$\ +> ScriptVal->\"name\") . \"' failed! Ignoring!\");\r\ +> \n :error false;\r\ +> \n }\r\ +> \n \r\ +> \n :log info (\"Updating script: \" . (\$ScriptVal->\"name\") . \" Sc\ +> ript comment: \" . (\$ScriptVal->\"comment\"));\r\ +> \n\r\ +> \n /system/script/set owner=(\$ScriptVal->\"name\") comment=(\$Script\ +> Val->\"comment\") \\\r\ +> \n source=[ \$IfThenElse (\$ScriptUpdatesCRLF = true) \$SourceCRL\ +> F \$SourceNew ] \$Script;\r\ +> \n :if (\$ScriptVal->\"name\" = \"AM-GlobalConfig\" || \\\r\ +> \n \$ScriptVal->\"name\" = \"AM-GlobalFunc\" || \\\r\ +> \n \$ScriptVal->\"name\" ~ (\"^(AM-GlobalFunc\\\\.d|mod)/.\")) d\ +> o={\r\ +> \n :set ReloadGlobal true;\r\ +> \n }\r\ +> \n } on-error={ }\r\ +> \n }\r\ +> \n :if (\$ReloadGlobal = true) do={\r\ +> \n \$LogPrint info \$0 (\"Reloading global configuration and functions.\ +> \");\r\ +> \n :onerror Err {\r\ +> \n :global InitSetup (a);\r\ +> \n /system/script {run AM-GlobalConfig; run AM-GlobalFunc;};\r\ +> \n } do={\$LogPrint error \$0 (\"Reloading global configuration and fun\ +> ctions failed! \" . \$Err)}\r\ +> \n }\r\ +> \n :if (\$GlobalConfVersionBefore > \$GlobalConfVersion) do={\r\ +> \n \$LogPrint warning \$0 (\"The configuration version decreased from \ +> \" . \\\r\ +> \n \$GlobalConfVersionBefore . \" to \" . \$GlobalConfVersion . \\\r\ +> \n \". Installed an older version\?\");\r\ +> \n }\r\ +> \n :if (\$GlobalConfVersionBefore < \$GlobalConfVersion) do={\r\ +> \n :global GlobalConfChanges;\r\ +> \n :global GlobalConfMigration;\r\ +> \n :local ChangeLogCode;\r\ +> \n :if ([ :len \$ChangeLogCode ] > 0) do={\r\ +> \n :if ([ \$ValidateSyntax \$ChangeLogCode ] = true) do={\r\ +> \n :onerror Err {\r\ +> \n [ :parse \$ChangeLogCode ];\r\ +> \n } do={\$LogPrint warning \$0 (\"The changelog failed to run: \" \ +> . \$Err)}\r\ +> \n } else={\$LogPrint warning \$0 (\"The changelog failed syntax vali\ +> dation!\")}\r\ +> \n }\r\ +> \n :if ([ :len \$GlobalConfMigration ] > 0) do={\r\ +> \n :for I from=(\$GlobalConfVersionBefore + 1) to=\$GlobalConfVersion\ +> \_do={\r\ +> \n :local Migration (\$GlobalConfMigration->[ :tostr \$I ]);\r\ +> \n :do {\r\ +> \n :if ([ :typeof \$Migration ] != \"str\") do={\r\ +> \n \$LogPrint debug \$0 (\"Migration code for change \" . \$I .\ +> \_\" is not available.\");\r\ +> \n :error false;\r\ +> \n }\r\ +> \n :if ([ \$ValidateSyntax \$Migration ] = false) do={\r\ +> \n \$LogPrint warning \$0 (\"Migration code for change \" . \$I\ +> \_. \" failed syntax validation!\");\r\ +> \n :error false}\r\ +> \n \$LogPrint info \$0 (\"Applying migration for change \" . \$I \ +> . \": \" . \$Migration);\r\ +> \n :onerror Err {\r\ +> \n [ :parse \$Migration ];\r\ +> \n } do={\$LogPrint warning \$0 (\"Migration code for change \" .\ +> \_\$I . \" failed to run: \" . \$Err)}\r\ +> \n } on-error={ }\r\ +> \n }\r\ +> \n }\r\ +> \n :local NotificationMessage (\"The configuration version on \" . \$Id\ +> entity . \" increased \" . \\\r\ +> \n \"to \" . \$GlobalConfVersion . \", current configuration may nee\ +> d modification. \" . \\\r\ +> \n \"Please review and update global-config-overlay, then re-run glo\ +> bal-config.\");\r\ +> \n \$LogPrint info \$0 (\$NotificationMessage);\r\ +> \n :if ([ :len \$GlobalConfChanges ] > 0) do={\r\ +> \n :set NotificationMessage (\$NotificationMessage . \"\\n\\nChanges:\ +> \");\r\ +> \n :for I from=(\$GlobalConfVersionBefore + 1) to=\$GlobalConfVersion\ +> \_do={\r\ +> \n :local Change (\$GlobalConfChanges->[ :tostr \$I ]);\r\ +> \n :set NotificationMessage (\$NotificationMessage . \"\\n \" . \\\ +> \r\ +> \n [ \$SymbolForNotification \"pushpin\" \"*\" ] . \$Change);\r\ +> \n \$LogPrint info \$0 (\"Change \" . \$I . \": \" . \$Change);\r\ +> \n }\r\ +> \n } else={:set NotificationMessage (\$NotificationMessage . \"\\n\\nNe\ +> ws and changes are not available.\")}\r\ +> \n\r\ +> \n :set GlobalConfChanges;\r\ +> \n :set GlobalConfMigration;\r\ +> \n }\r\ +> \n} do={:global ExitOnError; \$ExitOnError \$0 \$Err}\r\ +> \n}\r\ +> \n\r\ +> \n# Global Environment clear. Use: \"\$GlobalEnvRemove True;\".\r\ +> \n:set GlobalEnvRemove do={\r\ +> \n :local doRmEnv [ :tostr \$1 ];\r\ +> \n :global GlobalScriptsUrl;\r\ +> \n :local ScriptsUrl;\r\ +> \n :global LogPrint;\r\ +> \n :if (\$doRmEnv != \"True\") do={\r\ +> \n \$LogPrint error \"GlobalEnvRemove\" (\"This script is needed \\\"T\ +> rue\\\" for confirm to remove global environment variables!\");\r\ +> \n :return [];\r\ +> \n :error true; \r\ +> \n } else={\r\ +> \n :set ScriptsUrl \$GlobalScriptsUrl;\r\ +> \n :delay 5;\r\ +> \n :foreach var in=[/system/script/environment print as-value] do={/sy\ +> stem/script/environment remove (\$var->\".id\")}\r\ +> \n :delay 5;\r\ +> \n :global GlobalScriptsUrl \$ScriptsUrl;\r\ +> \n \$LogPrint warning \"GlobalEnvRemove\" (\"Done!\");\r\ +> \n :return [];\r\ +> \n :error false;\r\ +> \n }\r\ +> \n}\r\ +> \n\r\ +> \n# Add and fix global scheduler\r\ +> \n:put \"Add or/and fix Global scheduler...\";\r\ +> \n:local OnEvent \"/system/script { run AM-GlobalConfig; run AM-GlobalFunc\ +> ; }\";\r\ +> \n:local Comment \"Setup Global Environment for scripts\";\r\ +> \n:if ([ :len [ /system/scheduler/find where name=\"AM-SetGlobalEnv\" ] ] \ +> = 0) do={\r\ +> \n /system/scheduler/add name=\"AM-SetGlobalEnv\" comment=\$Comment on-ev\ +> ent=\$OnEvent start-time=startup;\r\ +> \n}\r\ +> \n:if ([ /system/scheduler/get \"AM-SetGlobalEnv\" comment ] != \$Comment)\ +> \_do={\r\ +> \n /system/scheduler/set \"AM-SetGlobalEnv\" comment=\$Comment;\r\ +> \n}\r\ +> \n:if ([ /system/scheduler/get \"AM-SetGlobalEnv\" on-event ] != \$OnEvent\ +> ) do={\r\ +> \n /system/scheduler/set \"AM-SetGlobalEnv\" on-event=\$OnEvent;\r\ +> \n}\r\ +> \n# Add Update Script scheduler\r\ +> \n:put \"Add or/and fix Update Script scheduler\";\r\ +> \n:set OnEvent \":global ScriptInstallUpdate; \\\$ScriptInstallUpdate;\";\ +> \r\ +> \n:set Comment \"Every Day Check For Update Scripts\";\r\ +> \n:if ([ :len [ /system/scheduler/find where name=\"AM-ScriptInstallUpdate\ +> \" ] ] = 0) do={\r\ +> \n/system/scheduler/add name=\"AM-ScriptInstallUpdate\" comment=\$Comment \ +> start-time=startup interval=1d on-event=\$OnEvent;\r\ +> \n}\r\ +> \n\r\ +> \n#:local Resource [ /system/resource/get ];\r\ +> \n#:log info (\$ScriptName . \" Loaded on \" . \$Resource->\"board-name\" \ +> . \" with RouterOS \" . \$Resource->\"version\" . \" and Architecture \" .\ +> \".\");\r\ +> \n\r\ +> \n:onerror Err {\r\ +> \n :global GlobalConfReady;\r\ +> \n :retry { :if (\$GlobalConfReady != true) do={ :error (\"Global configs\ +> \_not ready.\"); }; } delay=100ms max=5;\r\ +> \n\r\ +> \n# signal we are ready\r\ +> \n:set GlobalFuncReady true;\r\ +> \n:set ExitOK true;\r\ +> \n:log warning (\"This script \$ScriptName Loaded \" . \\\r\ +> \n [ \$IfThenElse (\$CommitId != \"unknown\") ([ \$CommitBrief ] . \" \ +> \") ] . \\\r\ +> \n \"on \" . \$devBoardName . \"\\nRouterOS: \" . \$devCurVersion . \"\ +> \\nArchitecture: \" . \$devCurArch . \"\\nIdentity: \" . \$Identity);\r\ +> \n} do={:global ExitOnError; \$ExitOnError \$0 \$Err;}\r\ +> \n\r\ +> \n#} do={:global ExitError; \$ExitError \$ExitOK [ :jobname ] \$Err}\r\ +> \n# log the successful load of the script, or an error if it failed\r\ +> \n#:if ([\$GlobalFuncReady] = true && [\$GlobalConfReady] = true) do={\r\ +> \n" +510a2857,3155 +> \n" +> add comment="download, import and update firewall address-lists" \ +> dont-require-permissions=no name=AM-FwAddrLists owner=AM-FwAddrLists \ +> policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ +> source="#!rsc by Vados\r\ +> \n# RouterOS script: AM-FwAddrLists\r\ +> \n# Script comment: download, import and update firewall address-lists\r\ +> \n# Copyright (c) 2007-2026 Vados \r\ +> \n#\r\ +> \n#\r\ +> \n# requires RouterOS, version=7.19\r\ +> \n# https://ros.vados.ru/doc/fw-addr-lists.md\r\ +> \n:local ExitOK false;\r\ +> \n:onerror Err {\r\ +> \n :global GlobalConfReady; :global GlobalFuncReady;\r\ +> \n :retry { :if (\$GlobalConfReady != true || \$GlobalFuncReady != true) \ +> \\\r\ +> \n do={ :error (\"Global config and/or functions not ready.\"); }; } \ +> delay=500ms max=50;\r\ +> \n :local ScriptName [ :jobname ];\r\ +> \n\r\ +> \n :global GlobalScriptsUrl;\r\ +> \n :local FwAddrListsUrl (\$GlobalScriptsUrl . \"fw-addr-lists.d/\");\r\ +> \n :local FwAddrListsIndexUrl (\$FwAddrListsUrl . \"index\");\r\ +> \n :local FwAddrListTimeOut 1d;\r\ +> \n\r\ +> \n :global CertificateAvailable;\r\ +> \n :global EitherOr;\r\ +> \n :global FetchHuge;\r\ +> \n :global HumanReadableNum;\r\ +> \n :global IfThenElse;\r\ +> \n :global LogPrint;\r\ +> \n\r\ +> \n :global NetMask4;\r\ +> \n :global NetMask6;\r\ +> \n :global ScriptLock;\r\ +> \n \r\ +> \n :local FindDelim do={\r\ +> \n :local ValidChars \"0123456789.:/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghi\ +> jklmnopqrstuvwxyz-\";\r\ +> \n :for I from=0 to=([ :len \$1 ] - 1) do={\r\ +> \n :if ([ :typeof [ :find \$ValidChars [ :pick \$1 \$I ] ] ] != \"num\ +> \") do={\r\ +> \n :return \$I;\r\ +> \n }\r\ +> \n }\r\ +> \n }\r\ +> \n\r\ +> \n :local GetBranch do={\r\ +> \n :global EitherOr;\r\ +> \n :return [ :pick [ :convert transform=md5 to=hex [ :pick \$1 0 [ \$Ei\ +> therOr [ :find \$1 \"/\" ] [ :len \$1 ] ] ] ] 0 2 ];\r\ +> \n }\r\ +> \n \r\ +> \n :if ([ \$ScriptLock \$ScriptName ] = false) do={\r\ +> \n :set ExitOK true;\r\ +> \n :error false;\r\ +> \n }\r\ +> \n\r\ +> \n :if ([ :len [ /log/find where topics=({\"script\"; \"warning\"}) \\\r\ +> \n message=(\"\\\$LogPrint: The message is already in log, scripting \ +> subsystem may have crashed before!\") ] ] > 0) do={\r\ +> \n :log warning (\$ScriptName . \" Scripting subsystem may have crashed\ +> , possibly caused by us. Delaying!\");\r\ +> \n :delay 5m;\r\ +> \n }\r\ +> \n\r\ +> \n :local ListComment (\"managed by \" . \$ScriptName);\r\ +> \n :local FwAddrListsIndex false;\r\ +> \n\r\ +> \n :for I from=1 to=5 do={\r\ +> \n :if (\$FwAddrListsIndex = false) do={\r\ +> \n :set FwAddrListsIndex [ :tolf [ \$FetchHuge \$ScriptName \$FwAddrL\ +> istsIndexUrl false ] ];\r\ +> \n :if (\$FwAddrListsIndex = false && \$I < 5) do={\r\ +> \n :log warning (\$ScriptName . \" Failed downloading address-list \ +> index, \" . \$I . \". try from: \" . \$FwAddrListsIndexUrl);\r\ +> \n :delay ((\$I * \$I) . \"s\");\r\ +> \n }\r\ +> \n }\r\ +> \n }\r\ +> \n :if (\$FwAddrListsIndex = false) do={\r\ +> \n :log warning (\$ScriptName . \" Failed downloading address-list inde\ +> x from: \" . \$FwAddrListsIndexUrl);\r\ +> \n :set FwAddrListsIndex \"\";\r\ +> \n }\r\ +> \n\r\ +> \n :foreach FwListFile in=[ :deserialize \$FwAddrListsIndex delimiter=\"\ +> \\n\" from=dsv options=dsv.plain ] do={\r\ +> \n :local FwListName (\$FwListFile->0);\r\ +> \n :local Delim [ \$FindDelim \$FwListName ];\r\ +> \n :if (\$Delim = 0) do={ :set FwListName \"\"; };\r\ +> \n :if ([ :len \$FwListName ] = 0) do={ :error true; }\r\ +> \n :set FwListName [ :pick \$FwListName 0 \$Delim ];\r\ +> \n\r\ +> \n :local FwListUrl (\$FwAddrListsUrl . \$FwListName);\r\ +> \n :local CntAdd 0;\r\ +> \n :local CntRenew 0;\r\ +> \n :local CntRemove 0;\r\ +> \n :local IPv4Addresses ({});\r\ +> \n :local IPv6Addresses ({});\r\ +> \n :local Failure false;\r\ +> \n :local Data false;\r\ +> \n :local TimeOut \$FwAddrListTimeOut;\r\ +> \n\r\ +> \n :for I from=1 to=5 do={\r\ +> \n :if (\$Data = false) do={\r\ +> \n :set Data [ :tolf [ \$FetchHuge \$ScriptName \$FwListUrl false ]\ +> \_];\r\ +> \n :if (\$Data = false && \$I < 5) do={\r\ +> \n :log warning (\$ScriptName . \" Failed downloading for list '\ +> \" . \$FwListName . \"', \" . \$I . \". try from: \" . \$FwListUrl);\r\ +> \n :delay ((\$I * \$I) . \"s\");\r\ +> \n }\r\ +> \n }\r\ +> \n }\r\ +> \n\r\ +> \n :if (\$Data = false) do={\r\ +> \n :set Data \"\";\r\ +> \n :set Failure true;\r\ +> \n :log warning (\$ScriptName . \" Failed downloading for list '\" . \ +> \$FwListName . \"' from: \" . \$FwListUrl);\r\ +> \n } else={\r\ +> \n :log debug (\$ScriptName . \" Downloaded \" . [ \$HumanReadableNum\ +> \_[ :len \$Data ] 1024 ] . \"B for list '\" . \$FwListName . \"' from: \" \ +> . \$FwListUrl);\r\ +> \n }\r\ +> \n\r\ +> \n :foreach Line in=[ :deserialize \$Data delimiter=\"\\n\" from=dsv op\ +> tions=dsv.plain ] do={\r\ +> \n :set Line (\$Line->0);\r\ +> \n :local Delim [ \$FindDelim \$Line ];\r\ +> \n :if (\$Delim = 0) do={ :set Line \"\"; };\r\ +> \n :if ([ :len \$Line ] = 0) do={ :error true; }\r\ +> \n :local Address;\r\ +> \n :if ([ :pick \$Line 0 1 ] = \"{\" && [ :pick \$Line ([ :len \$Line\ +> \_] - 1) ] = \"}\") do={\r\ +> \n :do {\r\ +> \n :set Address [ :tostr ([ :deserialize from=json \$Line ]->\"ci\ +> dr\") ];\r\ +> \n } on-error={ }\r\ +> \n } else={\r\ +> \n :set Address [ :pick \$Line 0 [ \$FindDelim \$Line ] ];\r\ +> \n }\r\ +> \n :do {\r\ +> \n :local Branch;\r\ +> \n :if (\$Address ~ \"^[0-9]{1,3}\\\\.[0-9]{1,3}\\\\.[0-9]{1,3}\\\\\ +> .[0-9]{1,3}(/[0-9]{1,2})\?\\\$\") do={\r\ +> \n :local Net \$Address;\r\ +> \n :local CIDR 32;\r\ +> \n :local Slash [ :find \$Address \"/\" ];\r\ +> \n :if ([ :typeof \$Slash ] = \"num\") do={\r\ +> \n :set Net [ :toip [ :pick \$Address 0 \$Slash ] ]\r\ +> \n :set CIDR [ :pick \$Address (\$Slash + 1) [ :len \$Address ]\ +> \_];\r\ +> \n :set Address [ :tostr (([ :toip \$Net ] & [ \$NetMask4 \$CID\ +> R ]) . [ \$IfThenElse (\$CIDR < 32) (\"/\" . \$CIDR) ]) ];\r\ +> \n }\r\ +> \n :set Branch [ \$GetBranch \$Address ];\r\ +> \n :if ([ :typeof (\$IPv4Addresses->\$Branch) ] != \"array\") do=\ +> { :set (\$IPv4Addresses->\$Branch) ({}) };\r\ +> \n :set (\$IPv4Addresses->\$Branch->\$Address) \$TimeOut;\r\ +> \n :error true;\r\ +> \n }\r\ +> \n :if (\$Address ~ \"^[0-9a-zA-Z]*:[0-9a-zA-Z:\\\\.]+(/[0-9]{1,3})\ +> \?\\\$\") do={\r\ +> \n :local Net \$Address;\r\ +> \n :local CIDR 128;\r\ +> \n :local Slash [ :find \$Address \"/\" ];\r\ +> \n :if ([ :typeof \$Slash ] = \"num\") do={\r\ +> \n :set Net [ :toip6 [ :pick \$Address 0 \$Slash ] ]\r\ +> \n :set CIDR [ :pick \$Address (\$Slash + 1) [ :len \$Address ]\ +> \_];\r\ +> \n }\r\ +> \n :set Address (([ :toip6 \$Net ] & [ \$NetMask6 \$CIDR ]) . \"/\ +> \" . \$CIDR);\r\ +> \n :set Branch [ \$GetBranch \$Address ];\r\ +> \n :if ([ :typeof (\$IPv6Addresses->\$Branch) ] != \"array\") do=\ +> { :set (\$IPv6Addresses->\$Branch) ({}) };\r\ +> \n :set (\$IPv6Addresses->\$Branch->\$Address) \$TimeOut;\r\ +> \n :error true;\r\ +> \n }\r\ +> \n :if (\$Address ~ \"^[\\\\.a-zA-Z0-9-]+\\\\.[a-zA-Z]{2,}\\\$\") d\ +> o={\r\ +> \n :set Branch [ \$GetBranch \$Address ];\r\ +> \n :if ([ :typeof (\$IPv4Addresses->\$Branch) ] != \"array\") do=\ +> { :set (\$IPv4Addresses->\$Branch) ({}) };\r\ +> \n :if ([ :typeof (\$IPv6Addresses->\$Branch) ] != \"array\") do=\ +> { :set (\$IPv6Addresses->\$Branch) ({}) };\r\ +> \n :set (\$IPv4Addresses->\$Branch->\$Address) \$TimeOut;\r\ +> \n :set (\$IPv6Addresses->\$Branch->\$Address) \$TimeOut;\r\ +> \n :error true;\r\ +> \n }\r\ +> \n } on-error={:log error (\$ScriptName . \" Failed parsing address: \ +> \" . \$Line->0);}\r\ +> \n }\r\ +> \n\r\ +> \n :foreach Entry in=[ /ip/firewall/address-list/find where \\\r\ +> \n list=\$FwListName comment=\$ListComment ] do={\r\ +> \n :local Address [ /ip/firewall/address-list/get \$Entry address ];\ +> \r\ +> \n :local Branch [ \$GetBranch \$Address ];\r\ +> \n :local TimeOut (\$IPv4Addresses->\$Branch->\$Address);\r\ +> \n :if ([ :typeof \$TimeOut ] = \"time\") do={\r\ +> \n :log debug (\$ScriptName . \" Renewing IPv4 address \" . \$Addre\ +> ss . \\\r\ +> \n \" in list '\" . \$FwListName . \"' with \" . \$TimeOut . \"\ +> .\");\r\ +> \n /ip/firewall/address-list/set \$Entry timeout=\$TimeOut;\r\ +> \n :set (\$IPv4Addresses->\$Branch->\$Address);\r\ +> \n :set CntRenew (\$CntRenew + 1);\r\ +> \n } else={\r\ +> \n :if (\$Failure = false) do={\r\ +> \n :log debug (\$ScriptName . \" Removing IPv4 address \" . \$Add\ +> ress . \\\r\ +> \n \" from list '\" . \$FwListName . \".\");\r\ +> \n /ip/firewall/address-list/remove \$Entry;\r\ +> \n :set CntRemove (\$CntRemove + 1);\r\ +> \n }\r\ +> \n }\r\ +> \n }\r\ +> \n\r\ +> \n :foreach Entry in=[ /ipv6/firewall/address-list/find where \\\r\ +> \n list=\$FwListName comment=\$ListComment ] do={\r\ +> \n :local Address [ /ipv6/firewall/address-list/get \$Entry address ]\ +> ;\r\ +> \n :local Branch [ \$GetBranch \$Address ];\r\ +> \n :local TimeOut (\$IPv6Addresses->\$Branch->\$Address);\r\ +> \n :if ([ :typeof \$TimeOut ] = \"time\") do={\r\ +> \n :log debug (\$ScriptName . \" Renewing IPv6 address \" . \$Addre\ +> ss . \\\r\ +> \n \" in list '\" . \$FwListName . \"' with \" . \$TimeOut . \"\ +> .\");\r\ +> \n /ipv6/firewall/address-list/set \$Entry timeout=\$TimeOut;\r\ +> \n :set (\$IPv6Addresses->\$Branch->\$Address);\r\ +> \n :set CntRenew (\$CntRenew + 1);\r\ +> \n } else={\r\ +> \n :if (\$Failure = false) do={\r\ +> \n :log debug (\$ScriptName . \" Removing IPv6 address \" . \$Add\ +> ress . \\\r\ +> \n \" from list '\" . \$FwListName .\".\");\r\ +> \n /ipv6/firewall/address-list/remove \$Entry;\r\ +> \n :set CntRemove (\$CntRemove + 1);\r\ +> \n }\r\ +> \n }\r\ +> \n }\r\ +> \n\r\ +> \n :foreach BranchName,Branch in=\$IPv4Addresses do={\r\ +> \n :log debug (\$ScriptName . \" Handling branch: \" . \$BranchName);\ +> \r\ +> \n :foreach Address,Timeout in=\$Branch do={\r\ +> \n :log debug (\$ScriptName . \" Adding IPv4 address \" . \$Address\ +> \_. \\\r\ +> \n \" to list '\" . \$FwListName . \"' with \" . \$Timeout . \"\ +> .\");\r\ +> \n :onerror Err {\r\ +> \n /ip/firewall/address-list/add list=\$FwListName comment=\$List\ +> Comment \\\r\ +> \n address=\$Address timeout=\$Timeout;\r\ +> \n :set CntAdd (\$CntAdd + 1);\r\ +> \n } do={\r\ +> \n :log warning (\$ScriptName . \" Failed to add IPv4 address \" \ +> . \$Address . \\\r\ +> \n \" to list '\" . \$FwListName . \"': \" . \$Err);\r\ +> \n }\r\ +> \n }\r\ +> \n }\r\ +> \n\r\ +> \n :foreach BranchName,Branch in=\$IPv6Addresses do={\r\ +> \n :log debug (\$ScriptName . \" Handling branch: \" . \$BranchName);\ +> \r\ +> \n :foreach Address,Timeout in=\$Branch do={\r\ +> \n :log debug (\$ScriptName . \" Adding IPv6 address \" . \$Address\ +> \_. \\\r\ +> \n \" to list '\" . \$FwListName . \"' with \" . \$Timeout . \"\ +> .\");\r\ +> \n :onerror Err {\r\ +> \n /ipv6/firewall/address-list/add list=\$FwListName comment=\$Li\ +> stComment \\\r\ +> \n address=\$Address timeout=\$Timeout;\r\ +> \n :set CntAdd (\$CntAdd + 1);\r\ +> \n } do={\r\ +> \n :log warning (\$ScriptName . \" Failed to add IPv6 address \" \ +> . \$Address . \\\r\ +> \n \" to list '\" . \$FwListName . \"': \" . \$Err);\r\ +> \n }\r\ +> \n }\r\ +> \n }\r\ +> \n\r\ +> \n :log info (\$ScriptName . \" list: \" . \$FwListName . \\\r\ +> \n \" (\" . [ \$HumanReadableNum (\$CntAdd + \$CntRenew) 1000 ] . \ +> \")\" . \\\r\ +> \n \" -- added: \" . [ \$HumanReadableNum \$CntAdd 1000 ] . \\\r\ +> \n \" - renewed: \" . [ \$HumanReadableNum \$CntRenew 1000 ] . \\\r\ +> \n \" - removed: \" . [ \$HumanReadableNum \$CntRemove 1000 ]);\r\ +> \n }\r\ +> \n} do={\r\ +> \n :global ExitError; \$ExitError \$ExitOK [ :jobname ] \$Err;\r\ +> \n}\r\ -- 2.52.0