From 6ad5bd5eb225aea662a64e287cc9ddab11a5abb5 Mon Sep 17 00:00:00 2001 From: vados-dev Date: Sun, 12 Jul 2026 21:01:54 +0300 Subject: [PATCH] Backup for MikroGig created successfully at Jul 12 21:01:54. --- .../20260712/20260712210151-Binary.backup | Bin 0 -> 194200 bytes .../20260712/20260712210151-Config.rsc | 1324 +++++- .../20260712/20260712210151-Diff-Config.rsc | 4 + .../20260712/20260712194001-Config.rsc | 3843 +++++++++++++++++ .../20260712/20260712200002-Config.rsc | 3841 ++++++++++++++++ 5 files changed, 8880 insertions(+), 132 deletions(-) create mode 100644 MikroGig/20260712/20260712210151-Binary.backup rename MikroMaster/tmp/Config.rsc => MikroGig/20260712/20260712210151-Config.rsc (60%) create mode 100644 MikroGig/history/20260712/20260712210151-Diff-Config.rsc create mode 100644 MikroMaster/20260712/20260712194001-Config.rsc create mode 100644 MikroMaster/20260712/20260712200002-Config.rsc diff --git a/MikroGig/20260712/20260712210151-Binary.backup b/MikroGig/20260712/20260712210151-Binary.backup new file mode 100644 index 0000000000000000000000000000000000000000..b1a92bbdbc1904bd9ce6ded8833d3d2120341910 GIT binary patch literal 194200 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\"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#/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@1\ - 0.30.30.86.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.86.pub\";\ + \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#:local Script AM-setup\ - \n;\r\ - \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\");\r\ - \n\ - \n#/usb1/mikro_bak_rsa.pub\ - \n\ + \n# /import verbose=no \$ScriptName\r\ + \n:global Identity [/system/identity/get name];\r\ + \n:global SetupScript [ :jobname ];\r\ + \n:global RemoveMe true;\r\ + \n:global RunOnce (a);\r\ + \n:global InitSetup true;\r\ + \n:global tmpfs false;\r\ \n\r\ - \n#\ + \n{\r\ + \n :local RmMe [:tobool \$1];\r\ \n\r\ - \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 :global GlobalScriptsUrl;\r\ + \n :global SetupScript;\r\ + \n :global RemoveMe;\r\ + \n :global InitSetup;\r\ + \n :global tmpfs;\r\ \n\r\ - \n#\r\ - \n\ - \n#root.mnuc.backuper\ - \n\ + \n :local UrlSuffix \$Identity;\r\ + \n :local UrlDir \"certs/\";\r\ + \n :local CertUrl (\$GlobalScriptsUrl . \$UrlDir . \$UrlSuffix .\"/\"); \ + \r\ + \n :local CertCommonName \"Root YE\";\r\ + \n :local CertFileName \"Root-YE.pem\";\r\ + \n :local CertFingerprint \"e14ffcad5b0025731006caa43a121a22d8e9700f4fb9c\ + f852f02a708aa5d5666\";\r\ \n\r\ - \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@10\ - .30.30.81.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.81.pub\";\r\ - \n\ - \n#:local Script AM-GlobalConfig;\ + \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#/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\");\r\ - \n\ - \n#/usb1/mikro_bak_rsa.pub\ - \n#:local FetchFile AM-DOHCert.rsc\ - \n\ + \n :log warning (\"\\n\\\$GlobalScriptsUrl = \" . \$GlobalScriptsUrl);\r\ + \n \r\ \n\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 /tool/fetch (\$CertUrl . \$CertFileName) dst-path=\$CertFileName\ + \_as-value;\r\ + \n :delay 1s;\r\ + \n /certificate/import file-name=\$CertFileName passphrase=\"\";\r\ + \n /certificate/set name=\"Root-YE\" [ find where common-name=\"Roo\ + t YE\" ];\r\ + \n :delay 1s;\r\ + \n };\r\ + \n :local CertSettings [ /certificate/settings/get ];\r\ + \n :if ([ :len [ /certificate/find where fingerprint=\$CertFingerprint ] \ + ] != 1) do={\r\ + \n :error \"Something is wrong with your certificates!\";\r\ + \n };\r\ \n\r\ - \n#\ - \n:global MkDir;\ + \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\ - \n#:local FetchFile Binary.backup\ - \n:local localDir \"\";\ - \n\ + \n :local Script \"mod/AM-Certs-By-Ident\";\r\ + \n \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/fetch \ + check-certificate=yes-without-crl url=(\$GlobalScriptsUrl . \$Script . \".\ + rsc\") output=user as-value ]->\"data\");\r\ + \n /system/script run \$Script;\r\ + \n :global tmpAddCerts;\r\ + \n :while ([ \$tmpAddCerts ] = true) do={\r\ + \n :delay 1s;\r\ + \n }\r\ + \n :delay 1s;\r\ + \n :put \"Removing \$Script...\";\r\ + \n /system/script/remove [ find where name=\$Script ];\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#\$MkDir \$localDir;\r\ - \n\ - \n#\ - \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \$FetchFile) dst-path=(\ - \$localDir . \$FetchFile);\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=\ @@ -367,10 +483,10 @@ add comment="Global functions" dont-require-permissions=no name=AM-GlobalFunc \ \n:global GlobalFuncReady false;\r\ \n\r\ \n# Git commit id & info, expected configuration version\r\ - \n:global CommitId \"main/729/f42d43ae\";\r\ + \n:global CommitId \"main/728/bebacfc7\";\r\ \n:global CommitTAG \"unknown\";\r\ \n:global CommitInfo \"Autocommit in repo: ros.vados.ru, generated by owne\ - r: root, in 00:05:03 01.07.2026.\";\r\ + r: root, in 11:00:05 30.06.2026.\";\r\ \n\r\ \n# The variables are received right here.\r\ \n:global GlobalConfVersion 140;\r\ @@ -2275,3 +2391,947 @@ add comment="Global functions" dont-require-permissions=no name=AM-GlobalFunc \ \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ \n}\r\ \n" +add comment="Download custom Certificates By Routers Identity " \ + dont-require-permissions=no name=mod/AM-Certs-By-Ident owner=\ + mod/AM-Certs-By-Ident policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\r\ + \n# RouterOS script: AM-Certs-By-Ident\r\ + \n# Script comment: Download custom Certificates By Routers Identity \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#\r\ + \n# 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:global tmpAddCerts true; \r\ + \n\r\ + \n:global GlobalScriptsUrl;\r\ + \n:local UrlSuffix [/system/identity/get name];\r\ + \n:local UrlDir \"certs/\";\r\ + \n:local CertUrl (\$GlobalScriptsUrl . \$UrlDir . \$UrlSuffix .\"/\");\r\ + \n\r\ + \n:log error \$CertUrl;\r\ + \n\r\ + \n:local CertName \"DigiCert-Global-Root-CA.pem\";\r\ + \n/tool/fetch mode=https url=(\$CertUrl . \$CertName);\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=(\$CertUrl . \$CertName);\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=(\$CertUrl . \$CertName);\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=(\$CertUrl . \$CertName);\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=(\$CertUrl . \$CertName);\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=(\$CertUrl . \$CertName);\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=(\$CertUrl . \$CertName);\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=(\$CertUrl . \$CertName);\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=(\$CertUrl . \$CertName);\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=(\$CertUrl . \$CertName);\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=(\$CertUrl . \$CertName);\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=(\$CertUrl . \$CertName);\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=(\$CertUrl . \$CertName);\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=(\$CertUrl . \$CertName);\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=(\$CertUrl . \$CertName);\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=(\$CertUrl . \$CertName);\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=(\$CertUrl . \$CertName);\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:global tmpAddCerts (a);\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=fetchCustom owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="\ + \r\ + \n:global GlobalScriptsUrl;\r\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@10\ + .30.30.86.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.86.pub\";\ + \n" +add dont-require-permissions=no name=awg2-webui owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + :put \"Download image, and save him to usb1/tmp\"\ + \n#/tool/fetch url=\"https://ros.vados.ru/docker/awg2-webui-arm.tar\" dst-\ + path=usb1/tmp/awg2-webui.tar\ + \n\ + \n:put \"1. Create veth interface\"\ + \n/interface veth add name=veth-awg address=10.9.9.2/24 gateway=10.9.9.1\ + \n\ + \n:put \"2. Create bridge and add veth\"\ + \n/interface bridge add name=br-awg\ + \n/interface bridge port add bridge=br-awg interface=veth-awg\ + \n\ + \n:put \"3. Assign IP to bridge\"\ + \n/ip address add address=10.9.9.1/24 interface=br-awg\ + \n\ + \n:put \"4. NAT: masquerade container traffic\"\ + \n/ip firewall nat add chain=srcnat src-address=10.9.9.0/24 action=masquer\ + ade\ + \n\ + \n:put \"5. Port forward: UDP 443 \? container (AmneziaWG QUIC mimicry)\"\ + \n/ip firewall nat add chain=dstnat protocol=udp dst-port=443 \\\ + \n action=dst-nat to-addresses=10.9.9.2 to-ports=55055 in-interface=eth\ + er1\ + \n\ + \n:put \"6. Port forward: HTTPS 9443 \? container Web UI\"\ + \n/ip firewall nat add chain=dstnat protocol=tcp dst-port=9443 \\\ + \n action=dst-nat to-addresses=10.9.9.2 to-ports=443 in-interface=ether\ + 1\ + \n\ + \n:put \"Create environment list..\"\ + \n/container envs add list=awgui-env key=WEB_USER value=vados\ + \n/container envs add list=awgui-env key=WEB_PASS value=zoomzoomrulezz\ + \n/container envs add list=awgui-env key=SECRET_KEY value=RanDomSecret32Sy\ + mboLs2325272931q\ + \n/container envs add list=awgui-env key=AWG_ENDPOINT value=10.30.30.10:44\ + 3\ + \n\ + \n:put \"Load and start container...\"\ + \n/container add file=usb1/tmp/awg2-webui.tar interface=veth-awg hostname=\ + awg2-webui \\\ + \nroot-dir=usb1/awg2-webui envlist=awgui-env start-on-boot=yes logging=yes\ + \_shm-size=4M\ + \n\ + \n:put \"Start...\"\ + \n/container start 0\ + \n\ + \n:put \"Verify...\"\ + \n/container print\ + \n\ + \n:put \"Should show: status=running\"\ + \n\ + \n/log print where topics~\"container\"\ + \n\ + \n:put \"Should show: AWG started, nginx running\"\ + \n" +add comment=Generator dont-require-permissions=no name=AWG-VDSina owner=vados \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + source="# ============================================================\r\ + \n# AWG Proxy -- MikroTik RouterOS (protocol: v2)\r\ + \n# 2026-06-30 22:08:12\r\ + \n# ============================================================\r\ + \n\r\ + \n# 0. Check prerequisites\r\ + \n:if ([:len [/system/package/find where name=\"container\" disabled=no]] \ + = 0) do={\r\ + \n :put \"Container package is not installed or disabled. Install it and \ + reboot.\"\r\ + \n :error \"Usage: /system/device-mode/update container=yes\"\r\ + \n}\r\ + \n\r\ + \n# Auto-detect storage\r\ + \n:global awgDisk \"disk1\"\r\ + \n{\r\ + \n :local usbFree 0\r\ + \n :do { :set usbFree [/disk/get [find where mount-point=\"usb1\"] free] \ + } on-error={}\r\ + \n :if (\$usbFree > 0) do={\r\ + \n :set awgDisk \"usb1\"\r\ + \n :put (\"Using USB: usb1 (\" . (\$usbFree / 1048576) . \" MB free)\")\ + \r\ + \n } else={\r\ + \n :if ([:len [/disk/find where slot=\"usb1\"]] > 0) do={\r\ + \n :put \"USB found but not mounted. Format as ext4\?\"\r\ + \n :put \"Press 'y' to confirm:\"\r\ + \n :local key [/terminal/inkey timeout=30]\r\ + \n :if (\$key = 121 || \$key = 89) do={\r\ + \n /disk/format-drive usb1 file-system=ext4 label=usb1\r\ + \n :delay 3s\r\ + \n :do { :set usbFree [/disk/get [find where mount-point=\"usb1\"] \ + free] } on-error={}\r\ + \n :if (\$usbFree > 0) do={\r\ + \n :set awgDisk \"usb1\"\r\ + \n } else={ :put \"Format failed, using disk1\" }\r\ + \n } else={ :put \"Using disk1\" }\r\ + \n } else={ :put \"No USB, using disk1\" }\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n# 1. Uninstall script\r\ + \n/system/script/add name=awg-VDSina-uninstall comment=awg-VDSina source={\ + \r\ + \n :put \"Uninstallimg AmneziaWG...\"\r\ + \n :log info \"Uninstallimg AmneziaWG...\"\r\ + \n :local prevDNS \"\"\r\ + \n :do { :set prevDNS [/container/envs/get [find where list=\"awg-VDSina-\ + env\" key=\"AWG_PREV_DNS\"] value] } on-error={}\r\ + \n :local storageDisk \"disk1\"\r\ + \n :do { :set storageDisk [/container/envs/get [find where list=\"awg-VDS\ + ina-env\" key=\"AWG_STORAGE\"] value] } on-error={}\r\ + \n :local prevTmpdir \"\"\r\ + \n :if (\$storageDisk != \"disk1\") do={\r\ + \n :do { :set prevTmpdir [/container/envs/get [find where list=\"awg-VD\ + Sina-env\" key=\"AWG_PREV_TMPDIR\"] value] } on-error={}\r\ + \n }\r\ + \n /ip/route/remove [find where comment=awg-VDSina-tunnel]\r\ + \n /ip/route/remove [find where comment=awg-VDSina-dns]\r\ + \n /container/stop [find where interface=veth-awg-VDSina]\r\ + \n :delay 7s\r\ + \n /container/remove [find where interface=veth-awg-VDSina]\r\ + \n /container/envs/remove [find where list=\"awg-VDSina-env\"]\r\ + \n :if (\$prevDNS != \"\") do={\r\ + \n :do { /ip/dns/set servers=\"\$prevDNS\" } on-error={}\r\ + \n :put (\"DNS restored to: \$prevDNS\")\r\ + \n }\r\ + \n :if (\$storageDisk != \"disk1\") do={\r\ + \n /container/config set tmpdir=\$prevTmpdir\r\ + \n :put (\"Container tmpdir restored to: \$prevTmpdir\")\r\ + \n }\r\ + \n /ip/firewall/nat/remove [find where out-interface=\"wg-awg-VDSina\"]\r\ + \n /ip/firewall/nat/remove [find where src-address=\"172.19.75.208/30\"]\ + \r\ + \n /ip/address/remove [find where address=\"172.19.75.209/30\"]\r\ + \n /interface/veth/remove [find where name=\"veth-awg-VDSina\"]\r\ + \n /interface/wireguard/peers/remove [find where interface=\"wg-awg-VDSin\ + a\"]\r\ + \n /ip/address/remove [find where interface=\"wg-awg-VDSina\"]\r\ + \n /interface/wireguard/remove [find where name=\"wg-awg-VDSina\"]\r\ + \n :do { /file/remove [find where name~\"awg-VDSina.+tar\"] } on-error={}\ + \r\ + \n :do { /file/remove [find where name=(\$storageDisk . \"/awg-VDSina\")]\ + \_} on-error={}\r\ + \n :do { /file/remove [find where name=(\$storageDisk . \"/ru_ranges_time\ + out.rsc\")] } on-error={}\r\ + \n :if (\$storageDisk != \"disk1\") do={\r\ + \n :do { /file/remove [find where name~(\$storageDisk . \"/pull\")] } o\ + n-error={}\r\ + \n }\r\ + \n :put \"Uninstall AmneziaWG Proxy complete!\"\r\ + \n :log info \"Uninstall AmneziaWG Proxy complete!\"\r\ + \n /system/script/remove [find where name=awg-VDSina-uninstall]\r\ + \n}\r\ + \n\r\ + \n# 2. Network infrastructure\r\ + \n/interface/veth/add name=veth-awg-VDSina address=172.19.75.210/30 gatewa\ + y=172.19.75.209\r\ + \n/ip/address/add address=172.19.75.209/30 interface=veth-awg-VDSina\r\ + \n/ip/firewall/nat/add chain=srcnat action=masquerade src-address=172.19.7\ + 5.208/30\r\ + \n\r\ + \n# 3. WireGuard interface (MikroTik derives the public key automatically)\ + \r\ + \n/interface/wireguard/add name=wg-awg-VDSina private-key=\"4CHyNhbOs923/E\ + yNDguMXJXdghL2I3UyzXPwrANVgHs=\" listen-port=14710 disabled=yes\r\ + \n/interface/wireguard/peers/add interface=wg-awg-VDSina public-key=\"o5Ig\ + Cl1/G6xbl6j7sPaP4ZNYREeYOmqZjKbm+v0b9jU=\" preshared-key=\"RNvF7T1cg5tyXcY\ + QnD9N5BEp6e20vVJQTv0GMjyvHU0=\" endpoint-address=172.19.75.210 endpoint-po\ + rt=51820 allowed-address=0.0.0.0/0 persistent-keepalive=10\r\ + \n/ip/address/add address=10.9.0.3/32 interface=wg-awg-VDSina\r\ + \n\r\ + \n# 4. Container environment variables\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_LISTEN value=\":44044\"\ + \r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_REMOTE value=\"109.107.1\ + 77.79:55055\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_JC value=\"9\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_JMIN value=\"105\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_JMAX value=\"920\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_S1 value=\"90\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_S2 value=\"136\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_H1 value=\"472437748-472\ + 438637\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_H2 value=\"707808381-707\ + 809250\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_H3 value=\"1609078552-16\ + 09079495\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_H4 value=\"1012329484-10\ + 12329741\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_SERVER_PUB value=\"o5IgC\ + l1/G6xbl6j7sPaP4ZNYREeYOmqZjKbm+v0b9jU=\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_CLIENT_PUB value=[/inter\ + face/wireguard/get [find name=wg-awg-VDSina] public-key]\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_S3 value=\"45\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_S4 value=\"27\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_I1 value=\"\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_I2 value=\"\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_I3 value=\"\ + \"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_I4 value=\"\"\ + \r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_I5 value=\"\"\r\ + \n\r\ + \n# 5. DNS\r\ + \n{ :local rawDNS [/ip/dns/get servers]; :local prevDNS \"\"; :foreach s i\ + n=[:toarray \$rawDNS] do={ :if ([:len \$prevDNS] > 0) do={ :set prevDNS \"\ + \$prevDNS,\$s\" } else={ :set prevDNS \$s } }; /container/envs/add list=aw\ + g-VDSina-env key=AWG_PREV_DNS value=\"\$prevDNS\" }\r\ + \n# NOTE: replaces existing DNS configuration\r\ + \n/ip/dns/set servers=8.8.8.8\r\ + \n#/ip/route/add dst-address=109.107.177.79/32 gateway=wg-awg-VDSina dista\ + nce=1 comment=awg-VDSina-dns\r\ + \n\r\ + \n# 6. Download, create and start container\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_STORAGE value=\$awgDisk\ + \r\ + \n:if (\$awgDisk != \"disk1\") do={\r\ + \n :local tmpPath (\$awgDisk . \"/pull\")\r\ + \n /container/envs/add list=awg-VDSina-env key=AWG_PREV_TMPDIR value=[/co\ + ntainer/config/get tmpdir]\r\ + \n /container/config set tmpdir=\$tmpPath memory-high=200M\r\ + \n}\r\ + \n{\r\ + \n :local arch [/system/resource/get architecture-name]\r\ + \n :local ver [/system/resource/get version]\r\ + \n :local dotPos [:find \$ver \".\"]\r\ + \n :local rest [:pick \$ver (\$dotPos + 1) [:len \$ver]]\r\ + \n :local endPos [:find \$rest \".\"]\r\ + \n :if ([:typeof \$endPos] = \"nil\") do={ :set endPos [:find \$rest \" \ + \"] }\r\ + \n :local minor [:tonum [:pick \$rest 0 \$endPos]]\r\ + \n :local suffix \"\"\r\ + \n :if (\$minor <= 20) do={ :set suffix \"-7.20-Docker\" }\r\ + \n :local file \"\"\r\ + \n :if (\$arch = \"arm64\") do={ :set file (\"awg-proxy-arm64\" . \$suffi\ + x . \".tar.gz\") }\r\ + \n :if (\$arch = \"arm\") do={ :set file (\"awg-proxy-arm\" . \$suffix . \ + \".tar.gz\") }\r\ + \n :if (\$arch ~ \"x86\") do={ :set file (\"awg-proxy-amd64\" . \$suffix \ + . \".tar.gz\") }\r\ + \n :if (\$file = \"\") do={ :error \"Unsupported architecture: \$arch\" }\ + \r\ + \n :local url \"https://github.com/timbrs/amneziawg-mikrotik-c/releases/l\ + atest/download/\$file\"\r\ + \n :local filePath \$file\r\ + \n :if (\$awgDisk != \"disk1\") do={\r\ + \n :set filePath (\$awgDisk . \"/pull/\" . \$file)\r\ + \n :do { /file/make-directory (\$awgDisk . \"/pull\") } on-error={}\r\ + \n }\r\ + \n :if ([:len [/file/find where name=\$filePath]] = 0) do={\r\ + \n :local freeStorage 0\r\ + \n :if (\$awgDisk = \"disk1\") do={\r\ + \n :set freeStorage [/system/resource/get free-hdd-space]\r\ + \n } else={\r\ + \n :do { :set freeStorage [/disk/get [find where mount-point=\$awgDis\ + k] free] } on-error={}\r\ + \n }\r\ + \n :if (\$freeStorage < 262144) do={\r\ + \n :put (\"WARNING: Low disk space (\" . (\$freeStorage / 1024) . \"K\ + B free). Need at least 256KB.\")\r\ + \n :put \"See: https://github.com/timbrs/amneziawg-mikrotik-c#insuffi\ + cient-disk-space\"\r\ + \n :error \"Insufficient disk space\"\r\ + \n }\r\ + \n :put (\"Fetching: \$url -> \" . \$filePath)\r\ + \n /tool/fetch url=\$url dst-path=\$filePath http-max-redirect-count=10\ + \r\ + \n } else={\r\ + \n :put (\"File already exists: \" . \$filePath)\r\ + \n }\r\ + \n :local rootDir (\$awgDisk . \"/awg-VDSina\")\r\ + \n /container/add file=\$filePath interface=veth-awg-VDSina envlist=awg-V\ + DSina-env hostname=awg-VDSina root-dir=\$rootDir logging=no start-on-boot=\ + yes comment=awg-VDSina\r\ + \n :if (\$minor > 20) do={ [:parse \"/container/set [find where interface\ + =veth-awg-VDSina] shm-size=4M\"] }\r\ + \n /file/remove \$filePath\r\ + \n :local freeMem [/system/resource/get free-memory]\r\ + \n :if (\$freeMem < 16777216) do={\r\ + \n :put (\"WARNING: Low memory (\" . (\$freeMem / 1048576) . \"MB free)\ + . 16MB+ recommended.\")\r\ + \n }\r\ + \n /container/start [find where interface=veth-awg-VDSina]\r\ + \n :do { /file/remove [find where name=\"console-dump.txt\"] } on-error={\ + }\r\ + \n :put \"Waiting for container to start...\"\r\ + \n :delay 5s\r\ + \n /interface/wireguard/enable wg-awg-VDSina\r\ + \n :put \"WireGuard interface enabled\"\r\ + \n :put \"Installation complete!\"\r\ + \n :put \"Ping test: 109.107.177.79 via AmneziaWG tunnel. repeat 10 times\ + \"\r\ + \n /ping 109.107.177.79 count=10 interval=1\r\ + \n :put \"\"\r\ + \n :put \"======= NEXT STEPS =======\"\r\ + \n :put \"\"\r\ + \n :put \"Route specific traffic through the AmneziaWG tunnel:\"\r\ + \n :put \"\"\r\ + \n :put \" Route a single host:\"\r\ + \n :put \" /ip/route/add dst-address=8.8.8.8/32 gateway=wg-awg-VDSina \ + comment=awg-VDSina-tunnel\"\r\ + \n :put \"\"\r\ + \n :put \" Route a subnet:\"\r\ + \n :put \" /ip/route/add dst-address=100.0.0.0/8 gateway=wg-awg-VDSina\ + \_comment=awg-VDSina-tunnel\"\r\ + \n :put \"\"\r\ + \n :put \" Remove a route:\"\r\ + \n :put \" /ip/route/remove [find where comment=awg-VDSina-tunnel dst-\ + address=8.8.8.8/32]\"\r\ + \n :put \"\"\r\ + \n :put \" Show all tunnel routes:\"\r\ + \n :put \" /ip/route/print where comment=awg-VDSina-tunnel\"\r\ + \n :put \"\"\r\ + \n :put \" Uninstall:\"\r\ + \n :put \" /system/script/run awg-VDSina-uninstall\"\r\ + \n :put \"=========================\"\r\ + \n}\r\ + \n\r\ + \n# 7. Verification\r\ + \n# /container/print\r\ + \n# /interface/wireguard/print\r\ + \n# /interface/wireguard/peers/print\r\ + \n" +add comment=awgVDSina dont-require-permissions=no name=awgVDSina-uninstall \ + owner=Manager policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="\ + \r\ + \n :put \"Uninstalling AmneziaWG...\"\r\ + \n :log info \"Uninstalling AmneziaWG...\"\r\ + \n /ip/route/remove [find where comment=awgVDSina-tunnel]\r\ + \n :do { /tool/netwatch/remove [find where comment=Monitor-AWGVDSINA] } o\ + n-error={}\r\ + \n :do { /ip/route/remove [find where comment=Monitor-AWGVDSINA] } on-err\ + or={}\r\ + \n /container/stop [find where interface=veth-awgVDSina]\r\ + \n :delay 7s\r\ + \n /interface/list/member/remove [find where interface=wg-awgVDSina]\r\ + \n /container/remove [find where interface=veth-awgVDSina]\r\ + \n /container/envs/remove [find where list=\"awgVDSina-env\"]\r\ + \n /ip/firewall/nat/remove [find where out-interface=\"wg-awgVDSina\"]\r\ + \n /ip/address/remove [find where address=\"172.20.0.1/30\"]\r\ + \n /interface/veth/remove [find where name=\"veth-awgVDSina\"]\r\ + \n /interface/wireguard/peers/remove [find where interface=\"wg-awgVDSina\ + \"]\r\ + \n /ip/address/remove [find where interface=\"wg-awgVDSina\"]\r\ + \n /interface/wireguard/remove [find where name=\"wg-awgVDSina\"]\r\ + \n :do { /file/remove [find where name~\"awgVDSina.+tar\"] } on-error={}\ + \r\ + \n :do { /file/remove [find where name=\"disk1/awgVDSina\"] } on-error={}\ + \r\ + \n :put \"Uninstall AmneziaWG Proxy complete!\"\r\ + \n :log info \"Uninstall AmneziaWG Proxy complete!\"\r\ + \n /system/script/remove [find where name=awgVDSina-uninstall]\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" +/container config +set layer-dir=/usb1/docker memory-high=200.0MiB memory-max=2048.0KiB \ + registry-url=https://registry-1.docker.io tmpdir=/usb1/pull username=\ + amsternl +/disk settings +set auto-media-interface=lo +/interface bridge port +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 +add bridge=Bridge-LAN interface=ether1 +/ip neighbor discovery-settings +set discover-interface-list=Internet +/ipv6 settings +set allow-fast-path=no disable-ipv6=yes disable-link-local-address=yes \ + forward=no +/interface detect-internet +set detect-interface-list=WAN internet-interface-list=Internet \ + lan-interface-list=LAN wan-interface-list=WAN +/interface list member +add interface=ether2 list=LAN +add interface=ether3 list=LAN +add interface=ether4 list=LAN +add interface=ether5 list=LAN +add interface=wlan2 list=LAN +add interface=wlan1 list=LAN +add interface=ether1 list=Internet +add interface=Bridge-LAN list=LAN +/interface wireguard peers +add allowed-address=0.0.0.0/0,::/0 disabled=yes endpoint-address=172.20.0.2 \ + endpoint-port=51820 interface=wg-awgVDSina name=awgVDSina \ + persistent-keepalive=27s public-key=\ + "o5IgCl1/G6xbl6j7sPaP4ZNYREeYOmqZjKbm+v0b9jU=" +/interface wireless cap +# +set bridge=Bridge-LAN caps-man-addresses=10.30.30.10 \ + caps-man-certificate-common-names=CAPsMAN-51B25E507D07 certificate=\ + CAP-18FD746E5814 discovery-interfaces=Bridge-LAN enabled=yes interfaces=\ + wlan1,wlan2 lock-to-caps-man=yes +/ip address +add address=10.30.30.86/24 interface=Bridge-LAN network=10.30.30.0 +add address=172.20.0.1/30 interface=veth-awgVDSina network=172.20.0.0 +add address=10.9.0.2 interface=wg-awgVDSina network=10.9.0.2 +/ip dns +set allow-remote-requests=yes servers=8.8.8.8 +/ip firewall nat +add action=masquerade chain=srcnat src-address=10.9.9.0/24 +add action=dst-nat chain=dstnat disabled=yes dst-port=443 in-interface=ether1 \ + protocol=udp to-addresses=10.9.9.2 to-ports=55055 +add action=dst-nat chain=dstnat disabled=yes dst-port=9443 in-interface=\ + ether1 protocol=tcp to-addresses=10.9.9.2 to-ports=443 +/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 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 check-gateway=ping disabled=no distance=2 dst-address=0.0.0.0/0 gateway=\ + 10.30.30.81 routing-table=main scope=30 target-scope=10 +add comment=Monitor-AWGVDSINA distance=1 dst-address=9.9.9.9/32 gateway=\ + wg-awgVDSina +/ip service +set ftp disabled=yes +set telnet 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 forced-ip=109.107.177.79 interface=veth-awgVDSina type=external +add interface=lo type=internal +add interface=wlan2 type=internal +add interface=wlan1 type=internal +/ipv6 nd +set [ find default=yes ] advertise-dns=yes +/system clock +set time-zone-name=Europe/Moscow +/system clock manual +set time-zone=+03:00 +/system identity +set name=MikroGig +/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=10.30.30.81 +add address=10.30.30.10 +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="Every Day Set Global Environment Variables" 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=Generator name=awg-VDSina on-event="# ============================\ + ================================\r\ + \n# AWG Proxy -- MikroTik RouterOS (protocol: v2)\r\ + \n# 2026-07-01 00:03:43\r\ + \n# ============================================================\r\ + \n\r\ + \n# 0. Check prerequisites\r\ + \n:if ([:len [/system/package/find where name=\"container\" disabled=no]] \ + = 0) do={\r\ + \n :put \"Container package is not installed or disabled. Install it and \ + reboot.\"\r\ + \n :error \"Usage: /system/device-mode/update container=yes\"\r\ + \n}\r\ + \n\r\ + \n# Auto-detect storage\r\ + \n:global awgDisk \"disk1\"\r\ + \n{\r\ + \n :local usbFree 0\r\ + \n :do { :set usbFree [/disk/get [find where mount-point=\"usb1\"] free] \ + } on-error={}\r\ + \n :if (\$usbFree > 0) do={\r\ + \n :set awgDisk \"usb1\"\r\ + \n :put (\"Using USB: usb1 (\" . (\$usbFree / 1048576) . \" MB free)\")\ + \r\ + \n } else={\r\ + \n :if ([:len [/disk/find where slot=\"usb1\"]] > 0) do={\r\ + \n :put \"USB found but not mounted. Format as ext4\?\"\r\ + \n :put \"Press 'y' to confirm:\"\r\ + \n :local key [/terminal/inkey timeout=30]\r\ + \n :if (\$key = 121 || \$key = 89) do={\r\ + \n /disk/format-drive usb1 file-system=ext4 label=usb1\r\ + \n :delay 3s\r\ + \n :do { :set usbFree [/disk/get [find where mount-point=\"usb1\"] \ + free] } on-error={}\r\ + \n :if (\$usbFree > 0) do={\r\ + \n :set awgDisk \"usb1\"\r\ + \n } else={ :put \"Format failed, using disk1\" }\r\ + \n } else={ :put \"Using disk1\" }\r\ + \n } else={ :put \"No USB, using disk1\" }\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n# 1. Uninstall script\r\ + \n/system/script/add name=awg-VDSina-uninstall comment=awg-VDSina source={\ + \r\ + \n :put \"Uninstallimg AmneziaWG...\"\r\ + \n :log info \"Uninstallimg AmneziaWG...\"\r\ + \n :local prevDNS \"\"\r\ + \n :do { :set prevDNS [/container/envs/get [find where list=\"awg-VDSina-\ + env\" key=\"AWG_PREV_DNS\"] value] } on-error={}\r\ + \n :local storageDisk \"disk1\"\r\ + \n :do { :set storageDisk [/container/envs/get [find where list=\"awg-VDS\ + ina-env\" key=\"AWG_STORAGE\"] value] } on-error={}\r\ + \n :local prevTmpdir \"\"\r\ + \n :if (\$storageDisk != \"disk1\") do={\r\ + \n :do { :set prevTmpdir [/container/envs/get [find where list=\"awg-VD\ + Sina-env\" key=\"AWG_PREV_TMPDIR\"] value] } on-error={}\r\ + \n }\r\ + \n /ip/route/remove [find where comment=awg-VDSina-tunnel]\r\ + \n /ip/route/remove [find where comment=awg-VDSina-dns]\r\ + \n /container/stop [find where interface=veth-awg-VDSina]\r\ + \n :delay 7s\r\ + \n /container/remove [find where interface=veth-awg-VDSina]\r\ + \n /container/envs/remove [find where list=\"awg-VDSina-env\"]\r\ + \n :if (\$prevDNS != \"\") do={\r\ + \n :do { /ip/dns/set servers=\"\$prevDNS\" } on-error={}\r\ + \n :put (\"DNS restored to: \$prevDNS\")\r\ + \n }\r\ + \n :if (\$storageDisk != \"disk1\") do={\r\ + \n /container/config set tmpdir=\$prevTmpdir\r\ + \n :put (\"Container tmpdir restored to: \$prevTmpdir\")\r\ + \n }\r\ + \n /ip/firewall/nat/remove [find where out-interface=\"wg-awg-VDSina\"]\r\ + \n /ip/firewall/nat/remove [find where src-address=\"172.19.75.208/30\"]\ + \r\ + \n /ip/address/remove [find where address=\"172.19.75.209/30\"]\r\ + \n /interface/veth/remove [find where name=\"veth-awg-VDSina\"]\r\ + \n /interface/wireguard/peers/remove [find where interface=\"wg-awg-VDSin\ + a\"]\r\ + \n /ip/address/remove [find where interface=\"wg-awg-VDSina\"]\r\ + \n /interface/wireguard/remove [find where name=\"wg-awg-VDSina\"]\r\ + \n :do { /file/remove [find where name~\"awg-VDSina.+tar\"] } on-error={}\ + \r\ + \n :do { /file/remove [find where name=(\$storageDisk . \"/awg-VDSina\")]\ + \_} on-error={}\r\ + \n :do { /file/remove [find where name=(\$storageDisk . \"/ru_ranges_time\ + out.rsc\")] } on-error={}\r\ + \n :if (\$storageDisk != \"disk1\") do={\r\ + \n :do { /file/remove [find where name~(\$storageDisk . \"/pull\")] } o\ + n-error={}\r\ + \n }\r\ + \n :put \"Uninstall AmneziaWG Proxy complete!\"\r\ + \n :log info \"Uninstall AmneziaWG Proxy complete!\"\r\ + \n /system/script/remove [find where name=awg-VDSina-uninstall]\r\ + \n}\r\ + \n\r\ + \n# 2. Network infrastructure\r\ + \n/interface/veth/add name=veth-awg-VDSina address=172.19.75.210/30 gatewa\ + y=172.19.75.209\r\ + \n/ip/address/add address=172.19.75.209/30 interface=veth-awg-VDSina\r\ + \n/ip/firewall/nat/add chain=srcnat action=masquerade src-address=172.19.7\ + 5.208/30\r\ + \n\r\ + \n# 3. WireGuard interface (MikroTik derives the public key automatically)\ + \r\ + \n/interface/wireguard/add name=wg-awg-VDSina private-key=\"QCMsDU98Gm+nhn\ + kYRcAN/dyczDYHOLsX3PfBRFjWBF4=\" listen-port=14710 disabled=yes\r\ + \n/interface/wireguard/peers/add interface=wg-awg-VDSina public-key=\"o5Ig\ + Cl1/G6xbl6j7sPaP4ZNYREeYOmqZjKbm+v0b9jU=\" preshared-key=\"b39T9K2/LR8vNtY\ + AZw+sLRze6yGlS3EaZhAa7wiFB20=\" endpoint-address=172.19.75.210 endpoint-po\ + rt=51820 allowed-address=0.0.0.0/0 persistent-keepalive=10\r\ + \n/ip/address/add address=10.9.0.2/32 interface=wg-awg-VDSina\r\ + \n\r\ + \n# 4. Container environment variables\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_LISTEN value=\":51820\"\ + \r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_REMOTE value=\"109.107.1\ + 77.79:55055\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_JC value=\"9\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_JMIN value=\"105\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_JMAX value=\"920\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_S1 value=\"90\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_S2 value=\"136\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_H1 value=\"472437748-472\ + 438637\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_H2 value=\"707808381-707\ + 809250\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_H3 value=\"1609078552-16\ + 09079495\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_H4 value=\"1012329484-10\ + 12329741\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_SERVER_PUB value=\"o5IgC\ + l1/G6xbl6j7sPaP4ZNYREeYOmqZjKbm+v0b9jU=\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_CLIENT_PUB value=[/inter\ + face/wireguard/get [find name=wg-awg-VDSina] public-key]\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_S3 value=\"45\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_S4 value=\"27\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_I1 value=\"\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_I2 value=\"\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_I3 value=\"\ + \"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_I4 value=\"\"\ + \r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_I5 value=\"\"\r\ + \n\r\ + \n# 5. DNS\r\ + \n{ :local rawDNS [/ip/dns/get servers]; :local prevDNS \"\"; :foreach s i\ + n=[:toarray \$rawDNS] do={ :if ([:len \$prevDNS] > 0) do={ :set prevDNS \"\ + \$prevDNS,\$s\" } else={ :set prevDNS \$s } }; /container/envs/add list=aw\ + g-VDSina-env key=AWG_PREV_DNS value=\"\$prevDNS\" }\r\ + \n# NOTE: replaces existing DNS configuration\r\ + \n/ip/dns/set servers=109.107.177.79\r\ + \n/ip/route/add dst-address=109.107.177.79/32 gateway=wg-awg-VDSina distan\ + ce=1 comment=awg-VDSina-dns\r\ + \n\r\ + \n# 6. Download, create and start container\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_STORAGE value=\$awgDisk\ + \r\ + \n:if (\$awgDisk != \"disk1\") do={\r\ + \n :local tmpPath (\$awgDisk . \"/pull\")\r\ + \n /container/envs/add list=awg-VDSina-env key=AWG_PREV_TMPDIR value=[/co\ + ntainer/config/get tmpdir]\r\ + \n /container/config set tmpdir=\$tmpPath memory-high=200M\r\ + \n}\r\ + \n{\r\ + \n :local arch [/system/resource/get architecture-name]\r\ + \n :local ver [/system/resource/get version]\r\ + \n :local dotPos [:find \$ver \".\"]\r\ + \n :local rest [:pick \$ver (\$dotPos + 1) [:len \$ver]]\r\ + \n :local endPos [:find \$rest \".\"]\r\ + \n :if ([:typeof \$endPos] = \"nil\") do={ :set endPos [:find \$rest \" \ + \"] }\r\ + \n :local minor [:tonum [:pick \$rest 0 \$endPos]]\r\ + \n :local suffix \"\"\r\ + \n :if (\$minor <= 20) do={ :set suffix \"-7.20-Docker\" }\r\ + \n :local file \"\"\r\ + \n :if (\$arch = \"arm64\") do={ :set file (\"awg-proxy-arm64\" . \$suffi\ + x . \".tar.gz\") }\r\ + \n :if (\$arch = \"arm\") do={ :set file (\"awg-proxy-arm\" . \$suffix . \ + \".tar.gz\") }\r\ + \n :if (\$arch ~ \"x86\") do={ :set file (\"awg-proxy-amd64\" . \$suffix \ + . \".tar.gz\") }\r\ + \n :if (\$file = \"\") do={ :error \"Unsupported architecture: \$arch\" }\ + \r\ + \n :local url \"https://github.com/timbrs/amneziawg-mikrotik-c/releases/l\ + atest/download/\$file\"\r\ + \n :local filePath \$file\r\ + \n :if (\$awgDisk != \"disk1\") do={\r\ + \n :set filePath (\$awgDisk . \"/pull/\" . \$file)\r\ + \n :do { /file/make-directory (\$awgDisk . \"/pull\") } on-error={}\r\ + \n }\r\ + \n :if ([:len [/file/find where name=\$filePath]] = 0) do={\r\ + \n :local freeStorage 0\r\ + \n :if (\$awgDisk = \"disk1\") do={\r\ + \n :set freeStorage [/system/resource/get free-hdd-space]\r\ + \n } else={\r\ + \n :do { :set freeStorage [/disk/get [find where mount-point=\$awgDis\ + k] free] } on-error={}\r\ + \n }\r\ + \n :if (\$freeStorage < 262144) do={\r\ + \n :put (\"WARNING: Low disk space (\" . (\$freeStorage / 1024) . \"K\ + B free). Need at least 256KB.\")\r\ + \n :put \"See: https://github.com/timbrs/amneziawg-mikrotik-c#insuffi\ + cient-disk-space\"\r\ + \n :error \"Insufficient disk space\"\r\ + \n }\r\ + \n :put (\"Fetching: \$url -> \" . \$filePath)\r\ + \n /tool/fetch url=\$url dst-path=\$filePath http-max-redirect-count=10\ + \r\ + \n } else={\r\ + \n :put (\"File already exists: \" . \$filePath)\r\ + \n }\r\ + \n :local rootDir (\$awgDisk . \"/awg-VDSina\")\r\ + \n /container/add file=\$filePath interface=veth-awg-VDSina envlist=awg-V\ + DSina-env hostname=awg-VDSina root-dir=\$rootDir logging=no start-on-boot=\ + yes comment=awg-VDSina\r\ + \n :if (\$minor > 20) do={ [:parse \"/container/set [find where interface\ + =veth-awg-VDSina] shm-size=4M\"] }\r\ + \n /file/remove \$filePath\r\ + \n :local freeMem [/system/resource/get free-memory]\r\ + \n :if (\$freeMem < 16777216) do={\r\ + \n :put (\"WARNING: Low memory (\" . (\$freeMem / 1048576) . \"MB free)\ + . 16MB+ recommended.\")\r\ + \n }\r\ + \n /container/start [find where interface=veth-awg-VDSina]\r\ + \n :do { /file/remove [find where name=\"console-dump.txt\"] } on-error={\ + }\r\ + \n :put \"Waiting for container to start...\"\r\ + \n :delay 5s\r\ + \n /interface/wireguard/enable wg-awg-VDSina\r\ + \n :put \"WireGuard interface enabled\"\r\ + \n :put \"Installation complete!\"\r\ + \n :put \"Ping test: 109.107.177.79 via AmneziaWG tunnel. repeat 10 times\ + \"\r\ + \n /ping 109.107.177.79 count=10 interval=1\r\ + \n :put \"\"\r\ + \n :put \"======= NEXT STEPS =======\"\r\ + \n :put \"\"\r\ + \n :put \"Route specific traffic through the AmneziaWG tunnel:\"\r\ + \n :put \"\"\r\ + \n :put \" Route a single host:\"\r\ + \n :put \" /ip/route/add dst-address=8.8.8.8/32 gateway=wg-awg-VDSina \ + comment=awg-VDSina-tunnel\"\r\ + \n :put \"\"\r\ + \n :put \" Route a subnet:\"\r\ + \n :put \" /ip/route/add dst-address=100.0.0.0/8 gateway=wg-awg-VDSina\ + \_comment=awg-VDSina-tunnel\"\r\ + \n :put \"\"\r\ + \n :put \" Remove a route:\"\r\ + \n :put \" /ip/route/remove [find where comment=awg-VDSina-tunnel dst-\ + address=8.8.8.8/32]\"\r\ + \n :put \"\"\r\ + \n :put \" Show all tunnel routes:\"\r\ + \n :put \" /ip/route/print where comment=awg-VDSina-tunnel\"\r\ + \n :put \"\"\r\ + \n :put \" Uninstall:\"\r\ + \n :put \" /system/script/run awg-VDSina-uninstall\"\r\ + \n :put \"=========================\"\r\ + \n}\r\ + \n\r\ + \n# 7. Verification\r\ + \n# /container/print\r\ + \n# /interface/wireguard/print\r\ + \n# /interface/wireguard/peers/print\r\ + \n" policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-date=2026-07-01 start-time=02:03:59 +/tool e-mail +set certificate-verification=no from=MikroVados port=587 \ + server=smtp.mail.me.com tls=starttls user=vadossio@icloud.com +/tool netwatch +add comment=Monitor-AWGVDSINA down-script=\ + "/ip route disable [find comment=\"Route-AWGVDSINA\"]" host=9.9.9.9 \ + interval=10s packet-count=5 thr-avg=0ms thr-loss-count=4 timeout=5s type=\ + icmp up-script="/ip route enable [find comment=\"Route-AWGVDSINA\"]" diff --git a/MikroGig/history/20260712/20260712210151-Diff-Config.rsc b/MikroGig/history/20260712/20260712210151-Diff-Config.rsc new file mode 100644 index 0000000..7700481 --- /dev/null +++ b/MikroGig/history/20260712/20260712210151-Diff-Config.rsc @@ -0,0 +1,4 @@ +11c11 +< # channel: 2442/20-Ce/gn(17dBm), SSID: vados, local forwarding +--- +> # channel: 2422/20-Ce/gn(17dBm), SSID: vados, local forwarding diff --git a/MikroMaster/20260712/20260712194001-Config.rsc b/MikroMaster/20260712/20260712194001-Config.rsc new file mode 100644 index 0000000..2f80244 --- /dev/null +++ b/MikroMaster/20260712/20260712194001-Config.rsc @@ -0,0 +1,3843 @@ +# 2026-07-12 19:40:06 by RouterOS 7.23.1 +# software id = A8L5-07YF +# +# model = RB952Ui-5ac2nD +# serial number = D3D50CEDCD38 +/interface bridge +add admin-mac=48:8F:5A:8E:1A:BF auto-mac=no dhcpv6-agent-circuit-id=\ + "\$(INTERFACE):\$(VID)" dhcpv6-agent-remote-id="\$(BRIDGEMAC)" name=\ + Bridge-LAN port-cost-mode=short +/interface ethernet +set [ find default-name=ether1 ] comment=Unet-cable loop-protect=off name=\ + Unet-ether1 rx-flow-control=auto tx-flow-control=auto +set [ find default-name=ether2 ] comment=LAN-2 +set [ find default-name=ether3 ] advertise="10M-baseT-half,10M-baseT-full,100M\ + -baseT-half,100M-baseT-full,1G-baseT-full,1G-baseX" comment=LAN-3 +set [ find default-name=ether4 ] comment=LAN-4 +set [ find default-name=ether5 ] advertise="10M-baseT-half,10M-baseT-full,100M\ + -baseT-half,100M-baseT-full,1G-baseT-full,1G-baseX" comment=LAN-5 \ + loop-protect=on poe-out=off rx-flow-control=auto tx-flow-control=auto +/interface wireless +# managed by CAPsMAN +# channel: 2422/20-Ce/gn(18dBm), SSID: vados, local forwarding +set [ find default-name=wlan1 ] country=belarus disabled=no mode=ap-bridge \ + ssid=vados wireless-protocol=802.11 +# managed by CAPsMAN +# channel: 5200/20-eCee/ac/P(21dBm), SSID: vados5g, local forwarding +set [ find default-name=wlan2 ] country=belarus disabled=no mode=ap-bridge \ + ssid=vados5g wireless-protocol=802.11 +/interface wireguard +add comment=WG listen-port=13231 mtu=1320 name=WG +add comment="WG interface for Amnezia route" disabled=yes listen-port=33033 \ + mtu=1360 name=wg-nuc +/interface list +add include=static name=LAN +add name=Internet +add include=Internet name=WAN +/interface wireless security-profiles +set [ find default=yes ] authentication-types=wpa-psk,wpa2-psk mode=\ + dynamic-keys supplicant-identity=MikroTik +/iot wiliot servers +set *1 address=mqtt.us-east-2.prod.wiliot.cloud name="Wiliot US East" +/ip dhcp-server option +add code=12 name=HostName +add code=119 force=yes name=domain-search-list value="0x03'WORKGROUP'0x00" +/ip dhcp-server option sets +add name=HP1505n options=HostName +add name=StartLife1 options=HostName +add name=amsterDev options=HostName +add name=MiTV options=HostName +add name=miller options=HostName +add name=amster options=HostName +add name=garage options=HostName +add name=domain-search-set options=domain-search-list +add name=VADOS-LEN options=HostName +add name=VADOS-NUC options=HostName +add name=MikroNUC options=HostName +add name=master options=HostName +add name=MikroYellow options=HostName +add name="=\"Client ID\"" options=HostName +add name=iVados options=HostName +/ip dns forwarders +add disabled=yes dns-servers=1.0.0.1,1.1.1.1 name=blsp.at verify-doh-cert=no +add comment=Kra disabled=yes dns-servers=1.0.0.1,1.1.1.1 name=slon2.to \ + verify-doh-cert=no +add disabled=yes dns-servers=1.1.1.1,1.0.0.1 name=slon3.at verify-doh-cert=no +add disabled=yes dns-servers=1.0.0.1,1.1.1.1 name=slon3.cc verify-doh-cert=no +add disabled=yes dns-servers=1.1.1.1,1.0.0.1 name=bs2web.at verify-doh-cert=\ + no +add disabled=yes dns-servers=1.1.1.1,1.0.0.1 name=bs2best.at verify-doh-cert=\ + no +add disabled=yes dns-servers=1.0.0.1,1.1.1.1 name=psrms.is verify-doh-cert=no +#error exporting "/ip/ipsec/policy/group" (timeout) +/ip ipsec proposal +set [ find default=yes ] disabled=yes +/ip pool +add name=dhcp ranges=10.30.30.83-10.30.30.254 +/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 smb users +set [ find default=yes ] disabled=yes +add disabled=yes name=vados +/ipv6 dhcp-client option +add code=119 name=domain-search-list value="0x03'WORKGROUP'0x00" +add code=12 name=HostName value="\$(HOSTNAME)" +add code=61 name=DUID value=0x00030001488f5a8e1abc +add code=61 name=clientid +/ipv6 dhcp-server option +add code=119 name=domain-search-list value="0x03'WORKGROUP'0x00" +add code=12 name=HostName value="\$(HOSTNAME)" +add code=61 name=CLIENT_DUID +add code=61 name=CLIENT_MAC +/ppp profile +set *FFFFFFFE use-upnp=no +/routing bgp template +set default disabled=no output.network=bgp-networks +/routing table +add disabled=no fib name=To-VPN +add disabled=no fib name=r_to_vpn +/system logging action +add email-start-tls=yes email-to=vados@vados.ru name=email target=email +/system script +add dont-require-permissions=no name=fetchCustom owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + global GlobalScriptsUrl \"https://ros.vados.ru/\";\r\ + \n\r\ + \n#/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@1\ + 0.30.30.86.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.86.pub\";\ + \n\r\ + \n#:local Script AM-setup\ + \n;\r\ + \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\");\r\ + \n\ + \n#/usb1/mikro_bak_rsa.pub\ + \n\ + \n\r\ + \n#\ + \n\r\ + \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\r\ + \n#\r\ + \n\ + \n#root.mnuc.backuper\ + \n\ + \n\r\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@10\ + .30.30.81.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.81.pub\";\r\ + \n\ + \n#:local Script AM-GlobalConfig;\ + \n\r\ + \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\");\r\ + \n\ + \n#/usb1/mikro_bak_rsa.pub\ + \n#:local FetchFile AM-DOHCert.rsc\ + \n\ + \n\r\ + \n\r\ + \n#\ + \n:global MkDir;\ + \n\r\ + \n\ + \n#:local FetchFile Binary.backup\ + \n:local localDir \"\";\ + \n\ + \n\r\ + \n#\$MkDir \$localDir;\r\ + \n\ + \n#\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \$FetchFile) dst-path=(\ + \$localDir . \$FetchFile);\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 (a);\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 (a); #{\r\ + \n# \"\";\r\ + \n# \"v3ry-s3cr3t\";\r\ + \n# \"4n0th3r-s3cr3t\";\r\ + \n#};\r\ + \n:global CertWarnTime 1w;\r\ + \n:global CertIssuedExportPass (a); # {\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/729/f42d43ae\";\r\ + \n:global CommitTAG \"unknown\";\r\ + \n:global CommitInfo \"Autocommit in repo: ros.vados.ru, generated by owne\ + r: root, in 00:05:03 01.07.2026.\";\r\ + \n\r\ + \n# The variables are received right here.\r\ + \n:global GlobalConfVersion 140;\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 MiniDateTimeStamp;\r\ + \n:global MicroDateTimeStamp;\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 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 GetRandom20CharHex;\r\ + \n:global GetRandomNumber;\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 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 ExitError;\r\ + \n:global ExitOnError;\r\ + \n\r\ + \n:global FetchHugeFiles;\r\ + \n:global FetchUserAgentStr;\r\ + \n:global FileExists;\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 updateChannel;\r\ + \n :global PkgUpdStatus;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n :global arrDeviceInfo;\r\ + \n :log info (\$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 :log info (\$0 . \" Set updates channel to: \$updateChannel\");\r\ + \n }\r\ + \n :local Update [ /system/package/update/get ];\r\ + \n :local Channel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set currentUpdateChannel \$Channel;\r\ + \n :log info (\$0 . \" Update Channel: \" . \$Channel . \".\");\r\ + \n :local StatusPkg \"undefined\";\r\ + \n :log info (\$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 :log info (\$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 :log info (\$0 . \" \\\$PkgUpdStatus = \" . \$PkgUpdStatus);\r\ + \n :if (\$isInfo != false || \$PkgUpdStatus = true) do={\r\ + \n :log info (\$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 :local Status \"\";\r\ + \n :local Update;\r\ + \n :local WaitCount 0;\r\ + \n :if ([ \$IsCheckUpdates true ] = false) do={\r\ + \n :return false;\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 :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 :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 :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\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:set GetRandom20CharHex do={:global EitherOr; :return [ :rndstr length=[\ + \_\$EitherOr [ :tonum \$1 ] 20 ] from=\"0123456789abcdef\" ]; }\r\ + \n:set GetRandomNumber do={:global EitherOr; :return [ :rndnum from=0 to=[\ + \_\$EitherOr [ :tonum \$1 ] 4294967295 ] ]; }\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: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: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: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 mode=https 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 mode=https http-head\ + er-field=({ [ \$FetchUserAgentStr \$0 ] }) \\\r\ + \n url=\"https://mkcert.org/generate/\" http-data=[ :serialize to=jso\ + n ({ \$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 error (\$0 . \" Failed downloading certificate with CommonNam\ + e '\" . \$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: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 FileExists do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :local Type [ :tostr \$2 ];\r\ + \n :global FileGet;\r\ + \n :local FileVal [ \$FileGet \$FileName ];\r\ + \n :if (\$FileVal = false) do={ :return false; }\r\ + \n :if ([ :len (\$FileVal->\"size\") ] = 0) do={ :return false; }\r\ + \n :if ([ :len \$Type ] = 0 || \$FileVal->\"type\" = \$Type) do={ :return\ + \_true; }\r\ + \n :return false;\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 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 [ :le\ + n \$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 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 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 ExitOnError do={\r\ + \n :local Name [ :tostr \$1 ];\r\ + \n :local Error [ :tostr \$2 ];\r\ + \n :global IfThenElse;\r\ + \n :log error (\$Name . \" \" . [ \$IfThenElse ([ :pick \$Name 0 1 ] = \"\ + \\\$\") \\\r\ + \n \"Function\" \"Script\" ] . \" '\" . \$Name . \"' exited with erro\ + r\" . \\\r\ + \n [ \$IfThenElse (!(\$Error ~ \"^(|true|false)\\\$\")) (\": \" . \$E\ + rror) \".\" ]);\r\ + \n}\r\ + \n\r\ + \n:set MiniDateTimeStamp do={\r\ + \n :local mikro [ :tobool \$1 ];\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 :local Return;\r\ + \n :if (\$mikro = true) do={\r\ + \n :set Return ([:pick \$yyyy 2 4] . [:pick \$dd 0 1] . [:pick \$HH 0\ + \_1] . [:pick \$mm 3 4] . [:pick \$ss 6 7]);\r\ + \n } else={\r\ + \n :set Return ([\$yyyy] . [\$MM] . [\$dd] . [\$HH] . [\$mm] . [\$ss]);\ + \r\ + \n }\r\ + \n :return \$Return;\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={\r\ + \n :return false;\r\ + \n }\r\ + \n :local FileVal false;\r\ + \n :do {\r\ + \n :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 :log debug (\$0 . \" Removing directory: \". \$DirName);\r\ + \n :local DirVal [ \$FileGet \$DirName ];\r\ + \n :if (\$DirVal = false) do={\r\ + \n :log debug (\$0 . \" ... which does not exist.\");\r\ + \n :return true;\r\ + \n };\r\ + \n :if (\$DirVal->\"type\" != \"directory\") do={\r\ + \n :log error (\$0 . \" Directory '\" . \$DirName . \"' is not a direct\ + ory.\");\r\ + \n :return false;\r\ + \n };\r\ + \n :onerror Err {\r\ + \n /file/remove \$DirName;\r\ + \n } do={\r\ + \n :log error (\$0 . \" Removing directory '\" . \$DirName . \"' failed\ + : \" . \$Err);\r\ + \n :return false;\r\ + \n };\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 :log debug (\$0 . \" Removing file: \". \$FileName);\r\ + \n :local FileVal [ \$FileGet \$FileName ];\r\ + \n :if (\$FileVal = false) do={\r\ + \n :log debug (\$0 . \" ... which does not exist.\");\r\ + \n :return true;\r\ + \n }\r\ + \n :if (\$FileVal->\"type\" = \"directory\" || \$FileVal->\"type\" = \"di\ + sk\") do={\r\ + \n :log error (\$0 . \" File '\" . \$FileName . \"' is not a file.\");\ + \r\ + \n :return false;\r\ + \n }\r\ + \n :onerror Err {\r\ + \n /file/remove \$FileName;\r\ + \n } do={\r\ + \n :log error (\$0 . \" Removing file '\" . \$FileName . \"' failed: \"\ + \_. \$Err); :return false;\r\ + \n }\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\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 :log info (\$0 . \" The tmpfs is disabled, enabling.\");\r\ + \n /disk/enable \$TmpFs;\r\ + \n }\r\ + \n :return true;\r\ + \n }\r\ + \n :log 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 :log 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 :log debug (\$0 . \" Making directory: \" . \$Path);\r\ + \n :local PathVal [ \$FileGet \$Path ];\r\ + \n :if (\$PathVal->\"type\" = \"directory\") do={\r\ + \n :log 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 :log 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 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 VersionToNum;\r\ + \n :if (!(\$Required ~ \"^\\\\d+\\\\.\\\\d+((alpha|beta|rc|\\\\.)\\\\d+|)\ + \\\$\")) do={\r\ + \n :log 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 :log warning (\$0 . \" This \" . [ \$IfThenElse ([ :pick \$Caller \ + 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\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\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\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 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 :log error (\$0 . \" A script named '\" . \$Script . \"' does not ex\ + ist!\");\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 :log error (\$0 . \" More tickets than running scripts '\" . \$Scrip\ + t . \"', 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\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\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\r\ + \n:set SymbolByUnicodeName do={\r\ + \n :local Name [ :tostr \$1 ];\r\ + \n :global EitherOr;\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 :log 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\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\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\r\ + \n:set IsDNSResolving do={\r\ + \n :do {:resolve \"api.telegram.org\"} on-error={:return false}\r\ + \n :return true;\r\ + \n}\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\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:set FetchHugeFiles do={\r\ + \n :local ScriptName [ :tostr \$1 ];\r\ + \n :local Url [ :tostr \$2 ];\r\ + \n :local CheckCert [ :tostr \$3 ];\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\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\r\ + \n :local FileName (\$DirName . \"/\" . [ \$CleanName \$0 ] . \"-\" . [ \ + \$GetRandom20CharAlNum ]);\r\ + \n :onerror Err {\r\ + \n /tool/fetch check-certificate=\$CheckCert \$Url dst-path=\$FileName \ + \\\r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$ScriptName ] }) as-va\ + lue;\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 \" . \$Url . \" - \"\ + \_. \$Err);\r\ + \n \$RmDir \$DirName;\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :if ([ \$WaitForFile \$FileName 5s ] = false) do={\r\ + \n \$LogPrint debug \$0 (\"The file downloaded from \" . \$Url . \" did\ + \_not show up.\");\r\ + \n :return false;\r\ + \n }\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 FetchUserAgentStr do={\r\ + \n :local Caller [ :tostr \$1 ];\r\ + \n :global GlobalScriptsUrl;\r\ + \n :global CommitBrief;\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 (\" . \$GlobalScriptsUrl . \"; \" . [ \$\ + CommitBrief ] . \")\");\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={\r\ + \n :set NotificationMessage (\$NotificationMessage . \"\\n\\nNews and\ + \_changes are not available.\");\r\ + \n\r\ + \n }\r\ + \n\r\ + \n :if ([ :len \$GlobalConfChanges ] > 0) do={ :set GlobalConfChanges; \ + } else={ :global GlobalConfChanges (a); }\r\ + \n :if ([ :len \$GlobalConfMigration ] > 0) do={ :set GlobalConfMigrati\ + on; } else={ :global GlobalConfMigration (a); }\r\ + \n }\r\ + \n} do={\r\ + \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ + \n} }\r\ + \n\r\ + \n# load modules\r\ + \n:foreach Script in=[ /system/script/find where name ~ \"^(global-functio\ + ns\\\\.d|mod)/.\" ] do={\r\ + \n :local ScriptVal [ /system/script/get \$Script ];\r\ + \n :if ([ \$ValidateSyntax (\$ScriptVal->\"source\") ] = true) do={\r\ + \n :onerror Err {\r\ + \n /system/script/run \$Script;\r\ + \n } do={\r\ + \n \$LogPrint error \$0 (\"Module '\" . \$ScriptVal->\"name\" . \"' f\ + ailed to run: \" . \$Err);\r\ + \n }\r\ + \n } else={\r\ + \n \$LogPrint error \$0 (\"Module '\" . \$ScriptVal->\"name\" . \"' fai\ + led syntax validation, skipping.\");\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 \"Every Day Set Global Environment Variables\";\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: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:log warning (\"This script \$ScriptName Loaded \" . \\\r\ + \n [ \$IfThenElse (\$CommitId != \"unknown\") ([ \$CommitBrief ] . \" \ + \") ] . \\\r\ + \n \"on \" . \$devBoardName . \"\\nRouterOS: \" . \$devCurVersion . \"\ + \\nArchitecture: \" . \$devCurArch . \"\\nIdentity: \" . \$Identity);\r\ + \n # signal we are ready\r\ + \n:set GlobalFuncReady true;\r\ + \n:set ExitOK true;\r\ + \n\r\ + \n:log info (\$0 . \"Global configs ready!\");\r\ + \n} do={\r\ + \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ + \n}\r\ + \n" +add comment=\ + "Lookup IP addresses for RKN list and add them to firewall address-list" \ + dont-require-permissions=no name=AM-RKN-dnsLookup owner=AM-RKN-dnsLookup \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + source="#!rsc by Vados\r\ + \n# RouterOS script: AM-RKN-dnsLookup\r\ + \n# Script comment: Lookup IP addresses for RKN list and add them to firew\ + all address-list\r\ + \n# Copyright (c) 2007-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version=7.19\r\ + \n# requires device-mode, fetch\r\ + \n#\r\ + \n# Script description: This script is intended to be run periodically, e.\ + g. once a day, to update the IP addresses in the firewall address-list bas\ + ed on the RKN list.\r\ + \n# It resolves the domain names in the RKN list and a\ + dds the corresponding IP addresses to the specified firewall address-list.\ + \r\ + \n# The script also handles CNAME records by following\ + \_them until it finds A records.\r\ + \n# Usage:\r\ + \n# /system/script { run AM-RKN-dnsLookup; }\r\ + \n:local ScriptName [ :jobname ];\r\ + \n\r\ + \n:global dnsLookupReady false;\r\ + \n:if ([:typeof \$dnsLookupReady] != \"boolean\") do={ :set dnsLookupReady\ + \_true; }\r\ + \nwhile (!\$dnsLookupReady) do={ :nothing; }\r\ + \n:set dnsLookupReady false;\r\ + \n\r\ + \n:local arrRKN {\r\ + \n \"telegra.ph\"\r\ + \n \"grani.ru\"\r\ + \n \"xhamster.com\"\r\ + \n \"lostfilm.tv\"\r\ + \n \"rutracker.org\"\r\ + \n \"lurkmore.to\"\r\ + \n \"dou.ua\"\r\ + \n \"youporn.com\"\r\ + \n \"pornolab.net\"\r\ + \n \"crimerussia.com\"\r\ + \n \"telegram.org\"\r\ + \n \"api.telegram.org\"\r\ + \n \"facebook.com\"\r\ + \n \"instagram.com\"\r\ + \n \"x.com\"\r\ + \n \"twitter.com\"\r\ + \n \"youtube.com\"\r\ + \n \"googleapis.com\"\r\ + \n \"youtu.be\"\r\ + \n \"googlevideo.com\"\r\ + \n \"gstatic.com\"\r\ + \n \"googleusercontent.com\"\r\ + \n \"nhacmp3youtube.com\"\r\ + \n \"telegram.me\"\r\ + \n \"t.me\";}\r\ + \n\r\ + \n:local ListRKN \"RKN-dnsLookup\";\r\ + \n:local ListComment (\"ListRKN managed by \" . \$ScriptName);\r\ + \n:foreach aListItem in=[/ip/firewall/address-list find list=\$ListRKN] do\ + ={\r\ + \n /ip firewall address-list remove \$aListItem;\r\ + \n}\r\ + \n:foreach aItem in=\$arrRKN do={\r\ + \n# :do {\r\ + \n :retry delay=500ms max=5 on-error={:log error \"dns resolve fail\ + ure [ \$aItem - resolve ip ]\"} command={:resolve \$aItem}\r\ + \n# } on-error={\r\ + \n# :log error \"dns resolve failure [ \$arItem - resolve ip ]\";\r\ + \n# }\r\ + \n :foreach dnsRecord in=[/ip dns cache all find where (name=\$aItem)] \ + do={\r\ + \n :if ([/ip dns cache all get \$dnsRecord type]=\"A\") do={\r\ + \n :local newAddress [/ip dns cache all get \$dnsRecord data];\ + \r\ + \n :do {\r\ + \n /ip firewall address-list add list=\$ListRKN address=\$newA\ + ddress comment=\$aItem;\r\ + \n :log warning \"Successfully adding ip to list A record: \ + \$dnsRecord, address: \$newAddress domain: \$aItem\";\r\ + \n } on-error={\r\ + \n :log error \"error when adding ip to list A record: \$dn\ + sRecord, address: \$newAddress domain: \$aItem\";\r\ + \n }\r\ + \n }\r\ + \n :if ([/ip dns cache all get \$dnsRecord type]=\"CNAME\") do={\r\ + \n :local cname;\r\ + \n :local nextCname;\r\ + \n :local cnameAddress;\r\ + \n :set cname [/ip dns cache all find where (name=\$aItem && ty\ + pe=\"CNAME\")];\r\ + \n :set nextCname [/ip dns cache all find where (name=[/ip dns \ + cache all get \$cname data] && type=\"CNAME\")];\r\ + \n :while (\$nextCname != \"\") do={\r\ + \n :set cname \$nextCname;\r\ + \n :set nextCname [/ip dns cache all find where (name=[/ip \ + dns cache all get \$cname data] && type=\"CNAME\")];\r\ + \n }\r\ + \n :foreach aRecord in=[/ip dns cache all find where (name=[/ip\ + \_dns cache all get \$cname data] && type=\"A\")] do={\r\ + \n :do {\r\ + \n :set cnameAddress [/ip dns cache all get \$aRecord d\ + ata];\r\ + \n /ip firewall address-list add list=\$ListRKN address\ + =\$cnameAddress comment=\$aItem;\r\ + \n :log warning \"Succesfully adding ip to list CNAME r\ + ecord: \$cname, A record: \$aRecord, address: \$newAddress, from domain: \ + \$aItem.\";\r\ + \n# /ip firewall raw add action=add-dst-to-address-list\ + \_address-list=\$ListRKN address-list-timeout=none-dynamic chain=preroutin\ + g comment=\$aItem content=\$aItem;\r\ + \n } on-error={\r\ + \n :log error \"error when adding ip to list CNAME reco\ + rd: \$cname, A record: \$aRecord, address: \$newAddress, from domain: \$aI\ + tem.\";\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:if ([ :len [ /system/scheduler/find where name=\$ScriptName ] ] = 0) do\ + ={\r\ + \n :log error (\$ScriptName . \"System Scheduler for script: \" . \$Scri\ + ptName . \" is NOT SET! Fix It Now!\");\r\ + \n /system/scheduler/add name=\$ScriptName on-event=\"/system/script { \ + run \$ScriptName; }\" comment=\"Update RKN DNS Looup\" interval=00:30:00 p\ + olicy=\"ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon\"\ + \_start-time=startup;\r\ + \n }\r\ + \n:set dnsLookupReady true;\r\ + \ndelay 2s; \r\ + \n:global dnsLookupReady (a);\r\ + \n" +add dont-require-permissions=no name="renameLists " owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + local oldName \"Test\";\ + \n:local newName \"Test-IP\";\ + \n/ip firewall address-list\ + \n:foreach i in=[find list=\$oldName] do={\ + \nset \$i list=\$newName;\ + \n}\ + \n" +add dont-require-permissions=no name=IPv6-Settings owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + #############Script Settings##################\ + \n\ + \n:local \"IF-TUN\" \"6to4-tun\"\ + \n:local \"IF-LOC\" \"Bridge-LAN\"\ + \n:local \"POOL-6TO4\" \"poolV6-local\"\ + \n:local \"force-update\" false\ + \n############ use then static ip #######################\ + \n:local \"lease-address\" [/ip address get [find interface=\$\"IF-LOC\"] \ + address]\ + \n#:local \"interface\" \"ext\"\ + \n:local bound 0\ + \n\ + \n###############################################\ + \n\ + \n:local 6to4prefix do={\ + \n :global dec2hex\ + \n :local ipv4 \$1\ + \n :local ipv6 \"2002:\"\ + \n :for i from=0 to=2 step=1 do={ \ + \n :if ( \$i = 2) do={\ + \n :set ipv6 (\$ipv6.\":\")\ + \n }\ + \n :local fp [:find \$ipv4 \".\"]\ + \n :if ( \$fp > 0 ) do={\ + \n :set ipv6 (\$ipv6.[\$dec2hex [:pick \$ipv4 0 \$fp]])\ + \n :set ipv4 [:pick \$ipv4 (\$fp + 1 ) [:len \$ipv4]]\ + \n }\ + \n }\ + \n :return (\$ipv6.[\$dec2hex \$ipv4])\ + \n}\ + \n:local \"str_replace\" do={\ + \n :local \"str-pos\" [:find \$1 \$2]\ + \n :local \"str-len\" [:len \$2]\ + \n :local str \"\"\ + \n :local rest \$1\ + \n :while (\$\"str-pos\" >= 0) do={\ + \n :local t [:pick \$rest 0 \$\"str-pos\"]\ + \n :if ( \$4 > 0 ) do={\ + \n :for i from=1 to=(\$4 - [:len \$t]) step=1 do={\ + \n :set str (\$str.\$5)\ + \n }\ + \n }\ + \n :set str (\$str.\$t.\$3)\ + \n :set rest [:pick \$rest (\$\"str-pos\"+\$\"str-len\") [:len \$re\ + st]]\ + \n :set \"str-pos\" [:find \$rest \$2]\ + \n }\ + \n :return (\$str.\$rest)\ + \n}\ + \n\ + \n:if (\$bound=1) do={\ + \n :local t [:find \$\"lease-address\" \"/\"]\ + \n\ + \n :if ( \$t >= 0 ) do={\ + \n :set \"lease-address\" [:pick \$\"lease-address\" 0 \$t]\ + \n }\ + \n\ + \n :if ( [/interface 6to4 print count-only where name=\$\"IF-TUN\"] = 0\ + ) do={\ + \n /interface 6to4 add !keepalive local-address=\$\"lease-address\"\ + \_mtu=1280 name=\$\"IF-TUN\" remote-address=10.30.30.0\ + \n :set \"force-update\" true\ + \n }\ + \n\ + \n :local \"IPv4-TUN\" [/interface 6to4 get [find name=\$\"IF-TUN\"] lo\ + cal-address];\ + \n\ + \n :if ( \$\"lease-address\" != \$\"IPv4-TUN\" || \$\"force-update\" = \ + true) do={\ + \n /interface 6to4 set [find name=\$\"IF-TUN\"] local-address=\$\"l\ + ease-address\"\ + \n /ipv6 address remove [find interface=\$\"IF-TUN\"]\ + \n /ipv6 address remove [find interface=\$\"IF-LOC\"]\ + \n /ipv6 route remove [find gateway ~ \$\"IF-TUN\" and dst-address=\ + \"::/0\"]\ + \n :local \"pool-prefix\" [\$6to4prefix \$\"lease-address\"]\ + \n :if ( [/ipv6 pool print count-only where name=\$\"POOL-6TO4\"] =\ + \_0) do={ \ + \n /ipv6 pool add name=\$\"POOL-6TO4\" prefix=(\$\"pool-prefix\ + \".\":1::/64\") prefix-length=64\ + \n } else={\ + \n /ipv6 pool set [/ipv6 pool find where name=\$\"POOL-6TO4\"] \ + prefix=(\$\"pool-prefix\".\":1::/64\")\ + \n }\ + \n /ipv6 address add address=(\$\"pool-prefix\".\"::\".[\$MAC2EUI64\ + \_[/interface get [find name=\$\"interface\"] mac-address]].\"/3\") interf\ + ace=\$\"IF-TUN\" advertise=no\ + \n /ipv6 address add eui-64=yes from-pool=\$\"POOL-6TO4\" interface\ + =\$\"IF-LOC\" advertise=yes\ + \n /ipv6 route add dst-address=::/0 gateway=(\"::10.30.30.81%\".\$\ + \"IF-TUN\")\ + \n :local t [/ipv6 address get [find interface=\$\"IF-LOC\"] addres\ + s]\ + \n :set t [:pick \$t 0 [:find \$t \"/\"]]\ + \n :if ( [/ipv6 dhcp-server option print count-only where name=DNS]\ + \_= 0) do={\ + \n /ipv6 dhcp-server option add code=23 name=DNS value=(\"0x\".\ + [\$\"str_replace\" \$t \":\" \"\" 4 \"0\"])\ + \n } else={\ + \n /ipv6 dhcp-server option set [/ipv6 dhcp-server option find \ + where name=DNS] value=(\"0x\".[\$\"str_replace\" \$t \":\" \"\" 4 \"0\"])\ + \n }\ + \n :if ( [/ipv6 dhcp-server print count-only where interface=\$\"IF\ + -LOC\"] = 0) do={\ + \n /ipv6 dhcp-server add address-pool=\$\"POOL-6TO4\" dhcp-opti\ + on=DNS interface=\$\"IF-LOC\" lease-time=1d name=\$\"IF-LOC\"\ + \n }\ + \n :if ( [ipv6 nd print count-only where interface=\$\"IF-LOC\"] = \ + 0) do={\ + \n /ipv6 nd add advertise-dns=no interface=\$\"IF-LOC\" other-c\ + onfiguration=yes\ + \n }\ + \n }\ + \n}" +add dont-require-permissions=no name=IPv6-GlobalFunc owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + global MAC2EUI64 do={\ + \n :local EUI64 \"\"\ + \n :local MAC \$1\ + \n :local HEX2DEC \"0123456789ABCDEF\"\ + \n :for i from=0 to=5 step=1 do={\ + \n :if ( \$i = 0 ) do={\ + \n :set EUI64 [:pick \$MAC 0]\ + \n :set EUI64 (\$EUI64.[:tostr [:pick \$\"HEX2DEC\" ([:find \$\ + \"HEX2DEC\" [:pick \$MAC 1]] ^ 2)]])\ + \n }\ + \n :if ( \$i = 1 || \$i = 3) do={\ + \n :set EUI64 (\$EUI64.\":\")\ + \n }\ + \n :if ( \$i = 2 ) do={\ + \n :set EUI64 (\$EUI64.\"FF:FE\")\ + \n }\ + \n :if ( [:find \$MAC \":\"] = 2 ) do={\ + \n :set MAC [:pick \$MAC 3 [:len \$MAC]]\ + \n :set EUI64 (\$EUI64.[:pick \$MAC 0 2])\ + \n }\ + \n }\ + \n :return (\$EUI64)\ + \n}\ + \n\ + \n:global dec2hex do={\ + \n :local hex \"\"\ + \n :local dec [:tonum \$1]\ + \n :for i from=0 to=4 step=4 do={\ + \n :set hex ([:pick \"0123456789ABCDEF\" ((\$dec>>\$i)&0xf) (((\$de\ + c>>\$i)&0xf)+1)].\$hex)\ + \n }\ + \n :return ([:tostr \$hex])\ + \n}" +add comment=Generator dont-require-permissions=no name=proxySet owner=vados \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + source="# 2. WireGuard interface\r\ + \n/interface/wireguard/add name=wg-VDSina private-key=\"4CHyNhbOs923/EyNDg\ + uMXJXdghL2I3UyzXPwrANVgHs=\" listen-port=21641\r\ + \n/interface/wireguard/peers/add interface=wg-VDSina public-key=\"o5IgCl1/\ + G6xbl6j7sPaP4ZNYREeYOmqZjKbm+v0b9jU=\" preshared-key=\"RNvF7T1cg5tyXcYQnD9\ + N5BEp6e20vVJQTv0GMjyvHU0=\" endpoint-address=10.30.30.33 endpoint-port=518\ + 20 allowed-address=0.0.0.0/0 persistent-keepalive=11\r\ + \n/ip/address/add address=10.9.0.3/32 interface=wg-VDSina\r\ + \n\r\ + \n# 3. DNS\r\ + \n{ :local rawDNS [/ip/dns/get servers]; :local prevDNS \"\"; :foreach s i\ + n=[:toarray \$rawDNS] do={ :if ([:len \$prevDNS] > 0) do={ :set prevDNS \"\ + \$prevDNS,\$s\" } else={ :set prevDNS \$s } }; /system/script/add name=VDS\ + ina-prev-dns comment=\"\$prevDNS\" source=\"\" }\r\ + \n/ip/dns/set servers=8.8.4.4\r\ + \n/ip/route/add dst-address=8.8.4.4/32 gateway=wg-VDSina distance=1 commen\ + t=VDSina-dns\r\ + \n\r\ + \n# 4. Enable WireGuard\r\ + \n/interface/wireguard/enable wg-VDSina\r\ + \n" +add dont-require-permissions=no name=AM-Telegram-Send owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\ + \n# RouterOS script: AM-Telegram-Send\ + \n# Script comment: Mini script for send messages to admin Telegram chat\ + \n# Copyright (c) 2007-2026 Vados \ + \n#\ + \n#\ + \n# requires RouterOS, version=7.19\ + \n# requires device-mode, fetch\ + \n#\ + \n# Script description: \ + \n#\ + \n#\ + \n# Usage:\ + \n# /system/script { run AM-Telegram-Send \"Message here )))\"; }\ + \n\ + \n/system/script\ + \nadd name=telegram-send dont-require-permissions=no source={\ + \n :global TelegramTokenId;\ + \n :global TelegramChatId;\ + \n :local message [:tostr \$1];\ + \n :local identity [/system/identity/get name];\ + \n :local sendMsg (\"[\".\$identity.\"] \".\$message)\ + \n /tool/fetch url=(\"https://api.telegram.org/bot\".\$TelegramTokenId.\\\ + \n \"/sendMessage\\\?chat_id=\".\$TelegramChatId.\\\ + \n \"&text=\".\$sendMsg.\\\ + \n \"&parse_mode=HTML\") \\\ + \n mode=https keep-result=no\ + \n}" +add dont-require-permissions=no name=telegram-send owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="\ + \n :global TelegramTokenId;\ + \n :global TelegramChatId;\ + \n :local message [:tostr \$1];\ + \n :local identity [/system/identity/get name];\ + \n :local sendMsg (\"[\".\$identity.\"] \".\$message)\ + \n /tool/fetch url=(\"https://api.telegram.org/bot\".\$TelegramTokenId.\\\ + \n \"/sendMessage\\\?chat_id=\".\$TelegramChatId.\\\ + \n \"&text=\".\$sendMsg.\\\ + \n \"&parse_mode=HTML\") \\\ + \n mode=https keep-result=no\ + \n" +/user group +add name=backup policy="ssh,read,write,policy,test,web,sniff,sensitive,api,res\ + t-api,!local,!telnet,!ftp,!reboot,!winbox,!password,!romon" +/ip smb +set enabled=no interfaces=lo +/interface bridge port +add bridge=Bridge-LAN interface=ether5 +add bridge=Bridge-LAN interface=ether2 +add bridge=Bridge-LAN interface=ether4 trusted=yes +add bridge=Bridge-LAN interface=ether3 +add bridge=Bridge-LAN interface=wlan2 +add bridge=Bridge-LAN interface=wlan1 +/interface bridge settings +set use-ip-firewall=yes +/ip firewall connection tracking +set udp-timeout=10s +/ip neighbor discovery-settings +set discover-interface-list=LAN lldp-med=no lldp-poe-power=no +/ip settings +set accept-redirects=yes ipv4-multipath-hash-policy=l4 max-neighbor-entries=\ + 8192 +/ipv6 settings +set disable-ipv6=yes disable-link-local-address=yes forward=no \ + max-neighbor-entries=8192 multipath-hash-policy=l4 +/interface detect-internet +set detect-interface-list=WAN internet-interface-list=Internet \ + lan-interface-list=LAN request-interval=1m wan-interface-list=WAN +/interface l2tp-server server +set authentication=mschap2 use-ipsec=yes +/interface list member +add interface=Unet-ether1 list=Internet +add interface=WG list=WAN +add interface=Bridge-LAN list=LAN +add interface=Unet-ether1 list=WAN +/interface wireguard peers +add allowed-address=0.0.0.0/0 client-allowed-address=::/0 endpoint-address=\ + 109.107.177.79 endpoint-port=29185 interface=WG name=VDSina \ + persistent-keepalive=10s public-key=\ + "zuRsO+dL/j6awaBWZ/NgnHR+bCNUjRWbaHFpdzkNnw4=" +add allowed-address=0.0.0.0/0 client-allowed-address=::/0 disabled=yes \ + endpoint-address=10.30.30.33 endpoint-port=55055 interface=wg-nuc name=\ + NUC persistent-keepalive=11s public-key=\ + "+OvzAjLC45Td52hjkQPmpGvC3RGhZ+Q2CDMJ1U/D4Rw=" +/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=Bridge-LAN enabled=yes interfaces=\ + wlan2,wlan1 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 +add address=192.168.33.2/24 disabled=yes interface=wg-nuc network=\ + 192.168.33.0 +/ip cloud +set update-time=no +/ip dhcp-client +add add-default-route=special-classless check-gateway=arp comment=Unet-client \ + default-route-distance=2 default-route-tables=main:2 dhcp-options=\ + hostname,clientid_duid interface=Unet-ether1 name=UnetDHCP use-peer-dns=\ + no use-peer-ntp=no +/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=iVados mac-address=DE:4D:72:F3:1A:9F server=masterDHCP +add address=10.30.30.10 allow-dual-stack-queue=yes client-id=\ + ff:0:0:0:df:0:3:0:1:f0:75:5d:1e:5f:85 dhcp-option=HostName \ + dhcp-option-set=MikroNUC mac-address=F0:75:5D:1E:5F:85 server=masterDHCP \ + use-src-mac=yes +/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.33,109.107.177.79 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 verify-doh-cert=yes +/ip dns static +add address=109.107.177.79 comment="VDSina Server DNS" name=ns1.vados.ru \ + type=A +add address=109.107.177.79 name=vds.vados.ru type=A +add comment="Local DNS server for vados.ru" disabled=yes ns=10.30.30.81 \ + regexp=*.vados.ru type=NS +add comment="*.vados.ru Regexp" disabled=yes forward-to=10.30.30.81 regexp=\ + "\".*\\\\.vados\\\\.ru\"" type=FWD +add comment="*.30.30.10.in-addr.arpa Regexp" disabled=yes forward-to=\ + 10.30.30.81 regexp="\".*\\\\.30\\\\.30\\\\.10\\\\.in-addr\\\\.arpa" type=\ + FWD +add address=10.30.30.81 comment=NS.vados.ru.local disabled=yes name=\ + ns.vados.ru.local type=A +add comment="DNS ns.vados.ru.local" disabled=yes match-subdomain=yes name=\ + vados.ru ns=ns.vados.ru.local type=NS +add address=10.30.30.33 comment=reg.vados.ru name=reg.vados.ru type=A +add address=8.8.8.8 comment="Google-dns IPv4 1" match-subdomain=yes name=\ + dns.google type=A +add address=8.8.4.4 comment="Google-dns IPv4 2" name=dns.google type=A +add address=10.30.30.33 comment=AMSTER name=amster.vados.ru type=A +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 name=amster type=A +add address=10.30.30.33 name=amster-reg type=A +add address=10.30.30.33 disabled=yes 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 disabled=yes match-subdomain=yes name=\ + mikrots.vados.ru 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" disabled=yes name=\ + security.cloudflare-dns.com type=A +add address=1.1.1.1 comment="CloudFlare-doh IPv4 1" disabled=yes 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" disabled=yes name=\ + dns.quad9.net type=A +add address=195.133.25.16 comment="DNS Comss" disabled=yes name=dns.comss.one \ + 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 disabled=yes name=MikroYellow type=A +add address=10.30.30.85 disabled=yes 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=91.192.189.2 comment=Unet-DNS disabled=yes name=ns1.unet.ws type=\ + A +add address=10.30.30.20 disabled=yes name=garage 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=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-IP +add address=wg.vados.ru comment=VDSIna list=TRUSTED +add address=10.8.0.0/24 comment="WG VDSIna" disabled=yes 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-IP +add address=geoip.co list=NoVdsina +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=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=amster list=NoWG +add address=10.30.30.10 comment=MikroNUC disabled=yes list=NoWG +add address=89.110.101.17 comment=!!!VDSINA!!!! disabled=yes list=NoWG +add address=wg.vados.ru comment=VDSina-vpn list=VDSina +add address=80.85.244.9 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!!!" list=NoVdsina +add address=dns.quad9.net comment=Quad9-dns disabled=yes list=Trusted-DNS +add address=dns.google comment=Google-dns list=Trusted-DNS +add address=security.cloudflare-dns.com comment=CloudFlare-dns list=\ + Trusted-DNS +add address=time.google.com comment=Google-time list=Trusted-NTP +add address=0.ru.pool.ntp.org comment=ru.pool.ntp.org disabled=yes list=\ + Trusted-NTP +add address=1.ru.pool.ntp.org disabled=yes list=Trusted-NTP +add address=2.ru.pool.ntp.org comment=2.ru.pool.ntp.org disabled=yes list=\ + Trusted-NTP +add address=3.ru.pool.ntp.org comment=3.ru.pool.ntp.org disabled=yes list=\ + Trusted-NTP +add address=cp.vdsina.com comment=VDSina-vpn list=VDSina +add address=vdsina.ru comment=VDSina-vpn list=VDSina +add address=ns.vados.ru comment=VDSina-vpn list=VDSina +add address=vdsina.com comment=VDSina-vpn list=VDSina +add address=cp.vdsina.ru comment=VDSina-vpn list=VDSina +add address=ns1.vdsina.ru comment=VDSina-vpn list=VDSina +add address=10.30.30.0/24 comment="Local Network" list=Local-Net +add address=10.8.0.0/24 comment="WireGuard Network" list=Local-Net +add address=146.120.64.208/29 comment="External Net" list=Unet +add address=esia.gosuslugi.ru comment=esia.gosuslugi.ru list=NoVdsina +add address=lk.gosuslugi.ru comment=lk.gosuslugi.ru list=NoVdsina +add address=trudvsem.ru comment=trudvsem.ru list=NoVdsina +add address=10.30.30.30 comment=miller disabled=yes list=NoWG +add address=10.30.30.33 comment="Direct connet to DNS servers" list=\ + Direct-DNS +add address=109.107.177.79 list=VPN-Server +add address=10.0.0.0/8 list=RFC1918 +add address=172.16.0.0/12 list=RFC1918 +add address=192.168.0.0/16 list=RFC1918 +add address=8.8.4.4 disabled=yes list=to_vpn +add address=myip.ru disabled=yes list=to_vpn +add address=10.30.30.98 disabled=yes list=to_vpn +/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=Unet-ether1 protocol=udp \ + src-address-list=!Trusted-DNS +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=Unet-ether1 protocol=tcp src-address-list=!Trusted-DNS +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 \ + in-interface=Unet-ether1 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=Unet-ether1 protocol=udp +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=4w2d chain=input comment="block honeypot NTP" \ + connection-state=new dst-port=123 in-interface=Unet-ether1 protocol=udp +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=accept chain=input dst-port=29185 in-interface=Unet-ether1 \ + protocol=tcp +add action=accept chain=input dst-port=29185 in-interface=Unet-ether1 \ + protocol=udp +add action=accept chain=input comment="tcp Accept input DNS queries from LAN" \ + dst-port=53 protocol=tcp src-address=10.30.30.0/24 +add action=accept chain=input comment="udp Accept input DNS queries" \ + dst-port=53 protocol=udp src-address=10.30.30.0/24 +add action=accept chain=output comment="accept WireGuard" disabled=yes \ + dst-address-list=VPN-Server out-interface=Unet-ether1 protocol=udp \ + src-port=13231 +add action=accept chain=output disabled=yes dst-address-list=VPN-Server \ + dst-port=29185 out-interface=Unet-ether1 protocol=udp +add action=fasttrack-connection chain=forward comment="defconf: fasttrack" \ + connection-state=established,related,new disabled=yes routing-mark=\ + !To-VPN +add action=accept chain=output disabled=yes protocol=tcp src-port=443 +add action=accept chain=output disabled=yes src-address=127.0.0.1 +add action=accept chain=forward comment="defconf: accept in ipsec policy" \ + disabled=yes ipsec-policy=in,ipsec +add action=accept chain=forward comment="defconf: accept out ipsec policy" \ + disabled=yes ipsec-policy=out,ipsec +add action=accept chain=forward comment=\ + "defconf: accept established,related, untracked" connection-state=\ + established,related,untracked disabled=yes +add action=drop chain=forward comment="defconf: drop invalid" \ + connection-state=invalid in-interface=Unet-ether1 src-address=\ + !10.30.30.0/24 +add action=drop chain=forward comment=\ + "defconf: drop all from WAN not DSTNATed" connection-nat-state=!dstnat \ + connection-state=new in-interface=Unet-ether1 src-address-list=!VDSina +add action=accept chain=input in-interface=Unet-ether1 protocol=icmp \ + src-address-list=VDSina +add action=accept chain=input connection-state=established +add action=accept chain=input connection-state=related +/ip firewall mangle +add action=accept chain=prerouting comment=RFC1918 dst-address-list=RFC1918 \ + in-interface-list=!WAN +add action=mark-routing chain=prerouting comment="Mark Routing main for NoWG" \ + new-routing-mark=main passthrough=no src-address-list=NoWG +add action=mark-routing chain=prerouting comment=\ + "Mark Routing main for NoVdsina" disabled=yes dst-address-list=NoVdsina \ + new-routing-mark=main passthrough=no src-address=10.30.30.0/24 +add action=mark-connection chain=prerouting comment=\ + "Transit for address-list \"to_vpn\"" connection-mark=no-mark disabled=\ + yes dst-address-list=to_vpn in-interface-list=!WAN new-connection-mark=\ + to-vpn-conn routing-mark=!main +add action=mark-routing chain=prerouting comment=\ + "Find routing over table r_to_vpn" connection-mark=to-vpn-conn disabled=\ + yes in-interface-list=!WAN new-routing-mark=r_to_vpn +add action=mark-routing chain=prerouting comment=\ + "Mark Routing main for VDSina" dst-address-list=VPN-Server \ + new-routing-mark=main passthrough=no src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=\ + "Mark Routing main for MikroNuc" disabled=yes dst-address-list=AWG-Proxy \ + new-routing-mark=main src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=\ + "!!!ERROR Mark Routing main for Unet!!!" disabled=yes dst-address-list=\ + Unet new-routing-mark=main passthrough=no +add action=mark-routing chain=prerouting comment="Test-IP sites" disabled=yes \ + dst-address=!10.30.30.0/24 dst-address-list=Test-IP new-routing-mark=\ + To-VPN src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=FuckRKN disabled=yes \ + dst-address=!10.30.30.0/24 dst-address-list=RKN-dnsLookup \ + new-routing-mark=To-VPN passthrough=no src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment="WG for all" \ + dst-address-list=!NoVdsina new-routing-mark=To-VPN src-address=\ + 10.30.30.0/24 +add action=change-mss chain=forward comment="MSS on WG" new-mss=1380 \ + out-interface=WG protocol=tcp routing-mark=To-VPN tcp-flags=syn tcp-mss=\ + 1381-65535 +add action=mark-connection chain=prerouting comment=\ + "Mark VPN connections to exclude from FastTrack" disabled=yes \ + new-connection-mark=VPN_No_FastTrack routing-mark=To-VPN +add action=mark-routing chain=prerouting comment="VPN Network" disabled=yes \ + dst-address=10.8.0.0/24 new-routing-mark=To-VPN src-address=10.30.30.0/24 +add action=mark-connection chain=output comment="For this router" \ + connection-mark=no-mark disabled=yes dst-address-list=to_vpn \ + new-connection-mark=to-vpn-conn-local +add action=mark-routing chain=output comment="For this router" \ + connection-mark=to-vpn-conn-local disabled=yes new-routing-mark=r_to_vpn +/ip firewall nat +add action=redirect chain=dstnat comment="udp Redirect DNS in NAT" disabled=\ + yes dst-port=53 protocol=udp src-address=10.30.30.0/24 src-address-list=\ + !NoWG to-addresses=10.30.30.33 to-ports=53 +add action=redirect chain=dstnat comment="tcp Redirect DNS in NAT" disabled=\ + yes dst-port=53 protocol=tcp src-address=10.30.30.0/24 src-address-list=\ + !NoWG to-addresses=10.30.30.33 to-ports=53 +add action=masquerade chain=srcnat comment=\ + "Nat Addresses for routing mark r_to_vpn" disabled=yes routing-mark=\ + r_to_vpn +add action=dst-nat chain=dstnat comment=\ + "53/tcp dst-nat to amster.loc. From VDSina Server" dst-port=53 \ + in-interface=Unet-ether1 protocol=tcp src-address-list=VPN-Server \ + to-addresses=10.30.30.33 to-ports=53 +add action=dst-nat chain=dstnat comment=\ + "53/udp dst-nat to amster.loc. From VDSina Server" dst-port=53 protocol=\ + udp src-address-list=VPN-Server to-addresses=10.30.30.33 to-ports=53 +add action=dst-nat chain=dstnat disabled=yes dst-port=44333 in-interface=\ + Unet-ether1 protocol=udp src-address=!10.30.30.0/24 to-addresses=\ + 10.30.30.33 to-ports=44333 +add action=masquerade chain=srcnat comment=WG dst-address-list=!NoVdsina \ + routing-mark=To-VPN +add action=masquerade chain=srcnat comment="Default NAT" out-interface=\ + Unet-ether1 routing-mark=!To-VPN src-address=10.30.30.0/24 +add action=dst-nat chain=dstnat dst-port=44044 in-interface=Unet-ether1 \ + protocol=udp src-address=109.107.177.79 to-addresses=10.30.30.33 \ + to-ports=44044 +add action=dst-nat chain=dstnat comment=amster.vados.ruhttps dst-port=443 \ + fragment=no in-interface=Unet-ether1 protocol=tcp routing-mark=main \ + 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=Unet-ether1 protocol=tcp to-addresses=\ + 10.30.30.33 to-ports=80 +add action=dst-nat chain=dstnat comment="amster.vados.ru 3x-ui" disabled=yes \ + dst-port=2904 in-interface=Unet-ether1 protocol=tcp to-addresses=\ + 10.30.30.33 to-ports=2904 +add action=dst-nat chain=dstnat comment=reg.vados.ru disabled=yes dst-port=\ + 5000 in-interface=Unet-ether1 protocol=tcp to-addresses=10.30.30.33 \ + to-ports=5000 +add action=dst-nat chain=dstnat comment="Docker swarm" disabled=yes dst-port=\ + 2377 in-interface=Unet-ether1 protocol=tcp to-addresses=10.30.30.33 \ + to-ports=2377 +add action=dst-nat chain=dstnat comment=npm dst-port=81 in-interface=\ + Unet-ether1 protocol=tcp routing-mark=To-VPN to-addresses=10.30.30.33 \ + to-ports=81 +add action=dst-nat chain=dstnat comment=SSH dst-port=22 in-interface=\ + Unet-ether1 protocol=tcp src-address-list=TRUSTED to-addresses=\ + 10.30.30.33 to-ports=22 +add action=dst-nat chain=dstnat comment="portainer agent" disabled=yes \ + dst-port=2377 in-interface=Unet-ether1 protocol=tcp to-addresses=\ + 10.30.30.33 to-ports=2377 +add action=dst-nat chain=dstnat disabled=yes dst-port=22 in-interface=\ + Unet-ether1 protocol=tcp routing-mark=!To-VPN to-addresses=10.30.30.33 \ + to-ports=22 +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=Unet-ether1 src-address-list="Honeypot Hacker" +add action=accept chain=prerouting comment="Trusted DNS" disabled=yes \ + in-interface-list=WAN src-address-list=Trusted-DNS +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=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=youtube.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + googleapis.com disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=ggpht.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=youtu.be \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=ytimg.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + googlevideo.com disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=gstatic.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + googleusercontent.com disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + nhacmp3youtube.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=rutube.ru \ + content=rutube.ru disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment="me.com raw" \ + content=me.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "icloud.com raw" content=icloud.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "smtp.mail.me.com raw" content=smtp.mail.me.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "smtp.mail.me.com.akadns.net raw" content=smtp.mail.me.com.akadns.net \ + disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "api.db-ip.com raw" content=api.db-ip.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + esia.gosuslugi.ru content=esia.gosuslugi.ru disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=gosuslugi.ru \ + content=gosuslugi.ru disabled=yes +/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 +#error exporting "/ip/ipsec/key/psk" (timeout) +/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 check-gateway=none comment=WG-Default 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 +set api-ssl address=10.30.30.0/24 disabled=yes +set www-ssl certificate=Root-YE port=18443 +set www address=10.30.30.0/24 disabled=yes port=18880 +/ip service webserver +set acme-plain=no crl-plain=no graphs-plain=no graphs-secure=no index-plain=\ + no index-secure=no rest-secure=no scep-plain=no webfig-plain=no \ + webfig-secure=no +/ip ssh +set forwarding-enabled=both publickey-authentication-options=verify-required +/ip upnp +set enabled=yes +/ip upnp interfaces +add interface=Bridge-LAN type=internal +add forced-ip=146.120.64.211 interface=Unet-ether1 type=external +add forced-ip=109.107.177.79 interface=*E type=external +add interface=lo type=internal +add interface=wlan2 type=internal +add interface=wlan1 type=internal +/ipv6 dhcp-client +add add-default-route=yes disabled=yes interface=*F rapid-commit=no request=\ + info use-interface-duid=yes validate-server-duid=no +/ipv6 dhcp-server option sets +add name=domain-search-set options=domain-search-list +add name="=\"Client ID\"" options=HostName +/ipv6 firewall address-list +add address=::/128 comment="defconf: unspecified address" list=bad_ipv6 +add address=::1/128 comment="defconf: lo" list=bad_ipv6 +add address=fec0::/10 comment="defconf: site-local" list=bad_ipv6 +add address=::ffff:0.0.0.0/96 comment="defconf: ipv4-mapped" list=bad_ipv6 +add address=::/96 comment="defconf: ipv4 compat" list=bad_ipv6 +add address=100::/64 comment="defconf: discard only " list=bad_ipv6 +add address=2001:db8::/32 comment="defconf: documentation" list=bad_ipv6 +add address=2001:10::/28 comment="defconf: ORCHID" list=bad_ipv6 +add address=3ffe::/16 comment="defconf: 6bone" list=bad_ipv6 +/ipv6 firewall filter +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 ICMPv6" protocol=\ + icmpv6 +add action=accept chain=input comment="defconf: accept UDP traceroute" \ + dst-port=33434-33534 protocol=udp +add action=accept chain=input comment=\ + "defconf: accept DHCPv6-Client prefix delegation." dst-port=546 protocol=\ + udp src-address=fe80::/10 +add action=accept chain=input comment="defconf: accept IKE" dst-port=500,4500 \ + protocol=udp +add action=accept chain=input comment="defconf: accept ipsec AH" protocol=\ + ipsec-ah +add action=accept chain=input comment="defconf: accept ipsec ESP" protocol=\ + ipsec-esp +add action=accept chain=input comment=\ + "defconf: accept all that matches ipsec policy" ipsec-policy=in,ipsec +add action=drop chain=input comment=\ + "defconf: drop everything else not coming from LAN" in-interface-list=\ + !LAN +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 packets with bad src ipv6" src-address-list=bad_ipv6 +add action=drop chain=forward comment=\ + "defconf: drop packets with bad dst ipv6" dst-address-list=bad_ipv6 +add action=drop chain=forward comment="defconf: rfc4890 drop hop-limit=1" \ + hop-limit=equal:1 protocol=icmpv6 +add action=accept chain=forward comment="defconf: accept ICMPv6" protocol=\ + icmpv6 +add action=accept chain=forward comment="defconf: accept HIP" protocol=139 +add action=accept chain=forward comment="defconf: accept IKE" dst-port=\ + 500,4500 protocol=udp +add action=accept chain=forward comment="defconf: accept ipsec AH" protocol=\ + ipsec-ah +add action=accept chain=forward comment="defconf: accept ipsec ESP" protocol=\ + ipsec-esp +add action=accept chain=forward comment=\ + "defconf: accept all that matches ipsec policy" ipsec-policy=in,ipsec +add action=drop chain=forward comment=\ + "defconf: drop everything else not coming from LAN" in-interface-list=\ + !LAN +/ipv6 nd +set [ find default=yes ] advertise-dns=yes disabled=yes interface=Bridge-LAN \ + managed-address-configuration=yes other-configuration=yes pref64=::/64 +/ipv6 nd prefix +add autonomous=no disabled=yes interface=Bridge-LAN on-link=no prefix=none +/ipv6 nd prefix default +set dhcp6-pd-preferred=yes +/ipv6 nd proxy +add disabled=yes interface=lo +/ipv6 nd settings +set router-advertisement-route-distance=100 +/routing settings +set single-process=no +/system clock +set 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 package update +set check-certificate=yes-without-crl ip-version=ipv4 +/system scheduler +add comment="Every Day Set Global Environment Variables" 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="Update RKN DNS Looup" disabled=yes interval=20m name=\ + AM-RKN-dnsLookup on-event="/system/script { run AM-RKN-dnsLookup; }" \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-time=startup +/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 certificate=DigiCert-Global-Root-CA check-certificate=no comment="doh, doh\ + -url=https://security.cloudflare-dns.com/dns-query, notify, name=CloudFlar\ + e-doh IPv4 1" disabled=yes down-script="" host=1.1.1.1 http-codes="" \ + interval=10s name="CloudFlare-doh IPv4 1" port=443 test-script="" type=\ + https-get 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="" \ + name="CloudFlare-doh IPv4" port=443 test-script="" type=https-get \ + up-script="" +add comment="dns, notify, name=Google-DNS IPv4" disabled=yes dns-server=\ + 8.8.8.8 down-script="" host=dns.google http-codes="" name=\ + "Google-DNS IPv4" test-script="" type=dns up-script="" +add certificate=GTS-Root-R4 check-certificate=yes comment="doh-fallback, doh-u\ + rl=https://dns.google/dns-query, doh-cert=GTS Root R1, notify, name=Google\ + -DOH IPv4" disabled=yes dns-server=8.8.4.4 down-script="" host=dns.google \ + http-codes="" name="Google-DOH IPv4" port=443 record-type=NS src-address=\ + "" test-script="" type=dns up-script="" +add comment="dns-fallback, notify, name=Cuad9-DOH IPv4" disabled=yes \ + dns-server=9.9.9.9 down-script="" host=dns9.quad9.net http-codes="" \ + interval=10s name="Cuad9-DOH IPv4" src-address=146.120.64.211 \ + test-script="" timeout=800ms type=dns up-script="" +add certificate=DigiCert-Assured-ID-Root-CA comment="doh-fallback, doh-url=htt\ + ps://dns.quad9.net/dns-query, name=Cuad9-DOH IPv4" disabled=yes \ + down-script="" host=149.112.112.112 http-codes="" interval=10s name=\ + "Cuad9-DOH IPv4" port=443 test-script="" type=https-get up-script="" +add comment="dns-fallback, notify, name=ns1.unet.ws" disabled=yes \ + down-script="" host=91.192.189.2 http-codes="" interval=10s name=\ + ns1.unet.ws test-script="" type=simple up-script="" +add check-certificate=yes comment=\ + "doh, doh-url=https://vds.vados.ru/vds-query, name=vds.vados.ru" \ + disabled=yes down-script="" host=109.107.177.79 http-codes="" name=\ + vds.vados.ru port=443 test-script="" type=https-get up-script="" +add comment="WireGuard NAT " disabled=yes down-script="/log info \"[WG-Monitor\ + ] WireGuard is NOT running - reverting rules\"\ + \n/ip firewall nat remove [find comment=\"Redirect to Router\"]\ + \n/ip dns set servers=8.8.8.8\ + \n/ip dns cache flush\ + \n/ip route remove [find comment=\"wg-auto-route\"]\ + \n" host=10.8.0.1 http-codes="" interval=15s name=WG test-script="" \ + timeout=5s type=simple up-script="/log info \"[WG-Monitor] WireGuard is RU\ + NNING - applying rules\";\ + \n:local routeFile \"ips.txt\";\ + \n:local routeDefAddr \"0.0.0.0/0\";\ + \n:local routeGateway \"10.8.0.1\";\ + \n:local routeIF \"WG\";\ + \n:local routeTable \"To-VPN\";\ + \n:local routeComment \"wg-auto-route\";\ + \n/ip dns cache flush;\ + \n:if ([:len [/ip firewall nat find comment=\"Redirect to Router\"]] > 0) \ + do={\ + \n /ip firewall nat remove [find comment=\"Redirect to Router\"];\ + \n}\ + \n/ip firewall nat add action=redirect chain=dstnat src-address-list=\"Red\ + irectDNS\" dst-port=53 protocol=udp comment=\"Redirect to Router\";\ + \n/ip dns set servers=\$routeGateway;\ + \n:local content [/file get \$routeFile contents];\ + \n:if ([:len \$content] > 0) do={\ + \n :local line \"\";\ + \n :for i from=0 to=([:len \$content] - 1) do={\ + \n :local char [:pick \$content \$i];\ + \n :if (\$char != \"\\r\" && \$char != \"\\n\") do={\ + \n :set line (\$line . \$char);\ + \n } else={\ + \n :if ([:len \$line] > 5) do={\ + \n :do { /ip route add disabled=no dst-address=\$routeDefAd\ + dr gateway=\$routeIF distance=1 scope=30 target-scope=10 routing-table=\$r\ + outeTable comment=\$routeComment check-gateway=none } on-error={}\ + \n }\ + \n :set line \"\";\ + \n }\ + \n }\ + \n :if ([:len \$line] > 5) do={\ + \n# :do { /ip route add dst-address=\$line gateway=\$routeGateway \ + distance=1 comment=\$routeComment } on-error={}\ + \n :do { /ip route add disabled=no dst-address=\$routeDefAddr ga\ + teway=\$routeIF distance=1 scope=30 target-scope=10 routing-table=\$routeT\ + able comment=\$routeComment check-gateway=none } on-error={}\ + \n }\ + \n}\ + \n:local dotPos [:find \$routeGateway \".\"];\ + \n:if (\$dotPos != \"\") do={\ + \n :local firstOctet [:pick \$routeGateway 0 \$dotPos];\ + \n :local derivedDstAddress (\$firstOctet . \".30.0.0/15\");\ + \n :do { /ip route add dst-address=\$derivedDstAddress gateway=\$routeG\ + ateway distance=1 comment=\$routeComment } on-error={}\ + \n}\ + \n\ + \n" +add comment=WG-Default disabled=yes down-script=\ + "/ip route disable [find comment=\"WG-Default\"];" host=10.8.0.1 \ + interval=15s name=WG packet-count=20 test-script="" thr-loss-count=5 \ + type=icmp up-script="/ip route enable [find comment=\"WG-Default\"];" +/user aaa +set accounting=no diff --git a/MikroMaster/20260712/20260712200002-Config.rsc b/MikroMaster/20260712/20260712200002-Config.rsc new file mode 100644 index 0000000..6dce7f8 --- /dev/null +++ b/MikroMaster/20260712/20260712200002-Config.rsc @@ -0,0 +1,3841 @@ +# 2026-07-12 20:00:06 by RouterOS 7.23.1 +# software id = A8L5-07YF +# +# model = RB952Ui-5ac2nD +# serial number = D3D50CEDCD38 +/interface bridge +add admin-mac=48:8F:5A:8E:1A:BF auto-mac=no dhcpv6-agent-circuit-id=\ + "\$(INTERFACE):\$(VID)" dhcpv6-agent-remote-id="\$(BRIDGEMAC)" name=\ + Bridge-LAN port-cost-mode=short +/interface ethernet +set [ find default-name=ether1 ] comment=Unet-cable loop-protect=off name=\ + Unet-ether1 rx-flow-control=auto tx-flow-control=auto +set [ find default-name=ether2 ] comment=LAN-2 +set [ find default-name=ether3 ] advertise="10M-baseT-half,10M-baseT-full,100M\ + -baseT-half,100M-baseT-full,1G-baseT-full,1G-baseX" comment=LAN-3 +set [ find default-name=ether4 ] comment=LAN-4 +set [ find default-name=ether5 ] advertise="10M-baseT-half,10M-baseT-full,100M\ + -baseT-half,100M-baseT-full,1G-baseT-full,1G-baseX" comment=LAN-5 \ + loop-protect=on poe-out=off rx-flow-control=auto tx-flow-control=auto +/interface wireless +# managed by CAPsMAN +# channel: 2422/20-Ce/gn(18dBm), SSID: vados, local forwarding +set [ find default-name=wlan1 ] country=belarus disabled=no mode=ap-bridge \ + ssid=vados wireless-protocol=802.11 +# managed by CAPsMAN +# channel: 5200/20-eCee/ac/P(21dBm), SSID: vados5g, local forwarding +set [ find default-name=wlan2 ] country=belarus disabled=no mode=ap-bridge \ + ssid=vados5g wireless-protocol=802.11 +/interface wireguard +add comment=WG listen-port=13231 mtu=1320 name=WG +add comment="WG interface for Amnezia route" disabled=yes listen-port=33033 \ + mtu=1360 name=wg-nuc +/interface list +add include=static name=LAN +add name=Internet +add include=Internet name=WAN +/interface wireless security-profiles +set [ find default=yes ] authentication-types=wpa-psk,wpa2-psk mode=\ + dynamic-keys supplicant-identity=MikroTik +/iot wiliot servers +set *1 address=mqtt.us-east-2.prod.wiliot.cloud name="Wiliot US East" +/ip dhcp-server option +add code=12 name=HostName +add code=119 force=yes name=domain-search-list value="0x03'WORKGROUP'0x00" +/ip dhcp-server option sets +add name=HP1505n options=HostName +add name=StartLife1 options=HostName +add name=amsterDev options=HostName +add name=MiTV options=HostName +add name=miller options=HostName +add name=amster options=HostName +add name=garage options=HostName +add name=domain-search-set options=domain-search-list +add name=VADOS-LEN options=HostName +add name=VADOS-NUC options=HostName +add name=MikroNUC options=HostName +add name=master options=HostName +add name=MikroYellow options=HostName +add name="=\"Client ID\"" options=HostName +add name=iVados options=HostName +/ip dns forwarders +add disabled=yes dns-servers=1.0.0.1,1.1.1.1 name=blsp.at verify-doh-cert=no +add comment=Kra disabled=yes dns-servers=1.0.0.1,1.1.1.1 name=slon2.to \ + verify-doh-cert=no +add disabled=yes dns-servers=1.1.1.1,1.0.0.1 name=slon3.at verify-doh-cert=no +add disabled=yes dns-servers=1.0.0.1,1.1.1.1 name=slon3.cc verify-doh-cert=no +add disabled=yes dns-servers=1.1.1.1,1.0.0.1 name=bs2web.at verify-doh-cert=\ + no +add disabled=yes dns-servers=1.1.1.1,1.0.0.1 name=bs2best.at verify-doh-cert=\ + no +add disabled=yes dns-servers=1.0.0.1,1.1.1.1 name=psrms.is verify-doh-cert=no +/ip ipsec proposal +set [ find default=yes ] disabled=yes +/ip pool +add name=dhcp ranges=10.30.30.83-10.30.30.254 +/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 smb users +set [ find default=yes ] disabled=yes +add disabled=yes name=vados +/ipv6 dhcp-client option +add code=119 name=domain-search-list value="0x03'WORKGROUP'0x00" +add code=12 name=HostName value="\$(HOSTNAME)" +add code=61 name=DUID value=0x00030001488f5a8e1abc +add code=61 name=clientid +/ipv6 dhcp-server option +add code=119 name=domain-search-list value="0x03'WORKGROUP'0x00" +add code=12 name=HostName value="\$(HOSTNAME)" +add code=61 name=CLIENT_DUID +add code=61 name=CLIENT_MAC +/ppp profile +set *FFFFFFFE use-upnp=no +/routing bgp template +set default disabled=no output.network=bgp-networks +/routing table +add disabled=no fib name=To-VPN +add disabled=no fib name=r_to_vpn +/system logging action +add email-start-tls=yes email-to=vados@vados.ru name=email target=email +/system script +add dont-require-permissions=no name=fetchCustom owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + global GlobalScriptsUrl \"https://ros.vados.ru/\";\r\ + \n\r\ + \n#/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@1\ + 0.30.30.86.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.86.pub\";\ + \n\r\ + \n#:local Script AM-setup\ + \n;\r\ + \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\");\r\ + \n\ + \n#/usb1/mikro_bak_rsa.pub\ + \n\ + \n\r\ + \n#\ + \n\r\ + \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\r\ + \n#\r\ + \n\ + \n#root.mnuc.backuper\ + \n\ + \n\r\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@10\ + .30.30.81.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.81.pub\";\r\ + \n\ + \n#:local Script AM-GlobalConfig;\ + \n\r\ + \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\");\r\ + \n\ + \n#/usb1/mikro_bak_rsa.pub\ + \n#:local FetchFile AM-DOHCert.rsc\ + \n\ + \n\r\ + \n\r\ + \n#\ + \n:global MkDir;\ + \n\r\ + \n\ + \n#:local FetchFile Binary.backup\ + \n:local localDir \"\";\ + \n\ + \n\r\ + \n#\$MkDir \$localDir;\r\ + \n\ + \n#\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \$FetchFile) dst-path=(\ + \$localDir . \$FetchFile);\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 (a);\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 (a); #{\r\ + \n# \"\";\r\ + \n# \"v3ry-s3cr3t\";\r\ + \n# \"4n0th3r-s3cr3t\";\r\ + \n#};\r\ + \n:global CertWarnTime 1w;\r\ + \n:global CertIssuedExportPass (a); # {\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/729/f42d43ae\";\r\ + \n:global CommitTAG \"unknown\";\r\ + \n:global CommitInfo \"Autocommit in repo: ros.vados.ru, generated by owne\ + r: root, in 00:05:03 01.07.2026.\";\r\ + \n\r\ + \n# The variables are received right here.\r\ + \n:global GlobalConfVersion 140;\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 MiniDateTimeStamp;\r\ + \n:global MicroDateTimeStamp;\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 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 GetRandom20CharHex;\r\ + \n:global GetRandomNumber;\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 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 ExitError;\r\ + \n:global ExitOnError;\r\ + \n\r\ + \n:global FetchHugeFiles;\r\ + \n:global FetchUserAgentStr;\r\ + \n:global FileExists;\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 updateChannel;\r\ + \n :global PkgUpdStatus;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n :global arrDeviceInfo;\r\ + \n :log info (\$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 :log info (\$0 . \" Set updates channel to: \$updateChannel\");\r\ + \n }\r\ + \n :local Update [ /system/package/update/get ];\r\ + \n :local Channel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set currentUpdateChannel \$Channel;\r\ + \n :log info (\$0 . \" Update Channel: \" . \$Channel . \".\");\r\ + \n :local StatusPkg \"undefined\";\r\ + \n :log info (\$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 :log info (\$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 :log info (\$0 . \" \\\$PkgUpdStatus = \" . \$PkgUpdStatus);\r\ + \n :if (\$isInfo != false || \$PkgUpdStatus = true) do={\r\ + \n :log info (\$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 :local Status \"\";\r\ + \n :local Update;\r\ + \n :local WaitCount 0;\r\ + \n :if ([ \$IsCheckUpdates true ] = false) do={\r\ + \n :return false;\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 :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 :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 :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\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:set GetRandom20CharHex do={:global EitherOr; :return [ :rndstr length=[\ + \_\$EitherOr [ :tonum \$1 ] 20 ] from=\"0123456789abcdef\" ]; }\r\ + \n:set GetRandomNumber do={:global EitherOr; :return [ :rndnum from=0 to=[\ + \_\$EitherOr [ :tonum \$1 ] 4294967295 ] ]; }\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: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: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: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 mode=https 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 mode=https http-head\ + er-field=({ [ \$FetchUserAgentStr \$0 ] }) \\\r\ + \n url=\"https://mkcert.org/generate/\" http-data=[ :serialize to=jso\ + n ({ \$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 error (\$0 . \" Failed downloading certificate with CommonNam\ + e '\" . \$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: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 FileExists do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :local Type [ :tostr \$2 ];\r\ + \n :global FileGet;\r\ + \n :local FileVal [ \$FileGet \$FileName ];\r\ + \n :if (\$FileVal = false) do={ :return false; }\r\ + \n :if ([ :len (\$FileVal->\"size\") ] = 0) do={ :return false; }\r\ + \n :if ([ :len \$Type ] = 0 || \$FileVal->\"type\" = \$Type) do={ :return\ + \_true; }\r\ + \n :return false;\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 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 [ :le\ + n \$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 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 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 ExitOnError do={\r\ + \n :local Name [ :tostr \$1 ];\r\ + \n :local Error [ :tostr \$2 ];\r\ + \n :global IfThenElse;\r\ + \n :log error (\$Name . \" \" . [ \$IfThenElse ([ :pick \$Name 0 1 ] = \"\ + \\\$\") \\\r\ + \n \"Function\" \"Script\" ] . \" '\" . \$Name . \"' exited with erro\ + r\" . \\\r\ + \n [ \$IfThenElse (!(\$Error ~ \"^(|true|false)\\\$\")) (\": \" . \$E\ + rror) \".\" ]);\r\ + \n}\r\ + \n\r\ + \n:set MiniDateTimeStamp do={\r\ + \n :local mikro [ :tobool \$1 ];\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 :local Return;\r\ + \n :if (\$mikro = true) do={\r\ + \n :set Return ([:pick \$yyyy 2 4] . [:pick \$dd 0 1] . [:pick \$HH 0\ + \_1] . [:pick \$mm 3 4] . [:pick \$ss 6 7]);\r\ + \n } else={\r\ + \n :set Return ([\$yyyy] . [\$MM] . [\$dd] . [\$HH] . [\$mm] . [\$ss]);\ + \r\ + \n }\r\ + \n :return \$Return;\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={\r\ + \n :return false;\r\ + \n }\r\ + \n :local FileVal false;\r\ + \n :do {\r\ + \n :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 :log debug (\$0 . \" Removing directory: \". \$DirName);\r\ + \n :local DirVal [ \$FileGet \$DirName ];\r\ + \n :if (\$DirVal = false) do={\r\ + \n :log debug (\$0 . \" ... which does not exist.\");\r\ + \n :return true;\r\ + \n };\r\ + \n :if (\$DirVal->\"type\" != \"directory\") do={\r\ + \n :log error (\$0 . \" Directory '\" . \$DirName . \"' is not a direct\ + ory.\");\r\ + \n :return false;\r\ + \n };\r\ + \n :onerror Err {\r\ + \n /file/remove \$DirName;\r\ + \n } do={\r\ + \n :log error (\$0 . \" Removing directory '\" . \$DirName . \"' failed\ + : \" . \$Err);\r\ + \n :return false;\r\ + \n };\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 :log debug (\$0 . \" Removing file: \". \$FileName);\r\ + \n :local FileVal [ \$FileGet \$FileName ];\r\ + \n :if (\$FileVal = false) do={\r\ + \n :log debug (\$0 . \" ... which does not exist.\");\r\ + \n :return true;\r\ + \n }\r\ + \n :if (\$FileVal->\"type\" = \"directory\" || \$FileVal->\"type\" = \"di\ + sk\") do={\r\ + \n :log error (\$0 . \" File '\" . \$FileName . \"' is not a file.\");\ + \r\ + \n :return false;\r\ + \n }\r\ + \n :onerror Err {\r\ + \n /file/remove \$FileName;\r\ + \n } do={\r\ + \n :log error (\$0 . \" Removing file '\" . \$FileName . \"' failed: \"\ + \_. \$Err); :return false;\r\ + \n }\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\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 :log info (\$0 . \" The tmpfs is disabled, enabling.\");\r\ + \n /disk/enable \$TmpFs;\r\ + \n }\r\ + \n :return true;\r\ + \n }\r\ + \n :log 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 :log 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 :log debug (\$0 . \" Making directory: \" . \$Path);\r\ + \n :local PathVal [ \$FileGet \$Path ];\r\ + \n :if (\$PathVal->\"type\" = \"directory\") do={\r\ + \n :log 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 :log 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 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 VersionToNum;\r\ + \n :if (!(\$Required ~ \"^\\\\d+\\\\.\\\\d+((alpha|beta|rc|\\\\.)\\\\d+|)\ + \\\$\")) do={\r\ + \n :log 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 :log warning (\$0 . \" This \" . [ \$IfThenElse ([ :pick \$Caller \ + 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\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\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\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 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 :log error (\$0 . \" A script named '\" . \$Script . \"' does not ex\ + ist!\");\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 :log error (\$0 . \" More tickets than running scripts '\" . \$Scrip\ + t . \"', 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\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\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\r\ + \n:set SymbolByUnicodeName do={\r\ + \n :local Name [ :tostr \$1 ];\r\ + \n :global EitherOr;\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 :log 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\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\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\r\ + \n:set IsDNSResolving do={\r\ + \n :do {:resolve \"api.telegram.org\"} on-error={:return false}\r\ + \n :return true;\r\ + \n}\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\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:set FetchHugeFiles do={\r\ + \n :local ScriptName [ :tostr \$1 ];\r\ + \n :local Url [ :tostr \$2 ];\r\ + \n :local CheckCert [ :tostr \$3 ];\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\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\r\ + \n :local FileName (\$DirName . \"/\" . [ \$CleanName \$0 ] . \"-\" . [ \ + \$GetRandom20CharAlNum ]);\r\ + \n :onerror Err {\r\ + \n /tool/fetch check-certificate=\$CheckCert \$Url dst-path=\$FileName \ + \\\r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$ScriptName ] }) as-va\ + lue;\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 \" . \$Url . \" - \"\ + \_. \$Err);\r\ + \n \$RmDir \$DirName;\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :if ([ \$WaitForFile \$FileName 5s ] = false) do={\r\ + \n \$LogPrint debug \$0 (\"The file downloaded from \" . \$Url . \" did\ + \_not show up.\");\r\ + \n :return false;\r\ + \n }\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 FetchUserAgentStr do={\r\ + \n :local Caller [ :tostr \$1 ];\r\ + \n :global GlobalScriptsUrl;\r\ + \n :global CommitBrief;\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 (\" . \$GlobalScriptsUrl . \"; \" . [ \$\ + CommitBrief ] . \")\");\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={\r\ + \n :set NotificationMessage (\$NotificationMessage . \"\\n\\nNews and\ + \_changes are not available.\");\r\ + \n\r\ + \n }\r\ + \n\r\ + \n :if ([ :len \$GlobalConfChanges ] > 0) do={ :set GlobalConfChanges; \ + } else={ :global GlobalConfChanges (a); }\r\ + \n :if ([ :len \$GlobalConfMigration ] > 0) do={ :set GlobalConfMigrati\ + on; } else={ :global GlobalConfMigration (a); }\r\ + \n }\r\ + \n} do={\r\ + \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ + \n} }\r\ + \n\r\ + \n# load modules\r\ + \n:foreach Script in=[ /system/script/find where name ~ \"^(global-functio\ + ns\\\\.d|mod)/.\" ] do={\r\ + \n :local ScriptVal [ /system/script/get \$Script ];\r\ + \n :if ([ \$ValidateSyntax (\$ScriptVal->\"source\") ] = true) do={\r\ + \n :onerror Err {\r\ + \n /system/script/run \$Script;\r\ + \n } do={\r\ + \n \$LogPrint error \$0 (\"Module '\" . \$ScriptVal->\"name\" . \"' f\ + ailed to run: \" . \$Err);\r\ + \n }\r\ + \n } else={\r\ + \n \$LogPrint error \$0 (\"Module '\" . \$ScriptVal->\"name\" . \"' fai\ + led syntax validation, skipping.\");\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 \"Every Day Set Global Environment Variables\";\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: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:log warning (\"This script \$ScriptName Loaded \" . \\\r\ + \n [ \$IfThenElse (\$CommitId != \"unknown\") ([ \$CommitBrief ] . \" \ + \") ] . \\\r\ + \n \"on \" . \$devBoardName . \"\\nRouterOS: \" . \$devCurVersion . \"\ + \\nArchitecture: \" . \$devCurArch . \"\\nIdentity: \" . \$Identity);\r\ + \n # signal we are ready\r\ + \n:set GlobalFuncReady true;\r\ + \n:set ExitOK true;\r\ + \n\r\ + \n:log info (\$0 . \"Global configs ready!\");\r\ + \n} do={\r\ + \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ + \n}\r\ + \n" +add comment=\ + "Lookup IP addresses for RKN list and add them to firewall address-list" \ + dont-require-permissions=no name=AM-RKN-dnsLookup owner=AM-RKN-dnsLookup \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + source="#!rsc by Vados\r\ + \n# RouterOS script: AM-RKN-dnsLookup\r\ + \n# Script comment: Lookup IP addresses for RKN list and add them to firew\ + all address-list\r\ + \n# Copyright (c) 2007-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version=7.19\r\ + \n# requires device-mode, fetch\r\ + \n#\r\ + \n# Script description: This script is intended to be run periodically, e.\ + g. once a day, to update the IP addresses in the firewall address-list bas\ + ed on the RKN list.\r\ + \n# It resolves the domain names in the RKN list and a\ + dds the corresponding IP addresses to the specified firewall address-list.\ + \r\ + \n# The script also handles CNAME records by following\ + \_them until it finds A records.\r\ + \n# Usage:\r\ + \n# /system/script { run AM-RKN-dnsLookup; }\r\ + \n:local ScriptName [ :jobname ];\r\ + \n\r\ + \n:global dnsLookupReady false;\r\ + \n:if ([:typeof \$dnsLookupReady] != \"boolean\") do={ :set dnsLookupReady\ + \_true; }\r\ + \nwhile (!\$dnsLookupReady) do={ :nothing; }\r\ + \n:set dnsLookupReady false;\r\ + \n\r\ + \n:local arrRKN {\r\ + \n \"telegra.ph\"\r\ + \n \"grani.ru\"\r\ + \n \"xhamster.com\"\r\ + \n \"lostfilm.tv\"\r\ + \n \"rutracker.org\"\r\ + \n \"lurkmore.to\"\r\ + \n \"dou.ua\"\r\ + \n \"youporn.com\"\r\ + \n \"pornolab.net\"\r\ + \n \"crimerussia.com\"\r\ + \n \"telegram.org\"\r\ + \n \"api.telegram.org\"\r\ + \n \"facebook.com\"\r\ + \n \"instagram.com\"\r\ + \n \"x.com\"\r\ + \n \"twitter.com\"\r\ + \n \"youtube.com\"\r\ + \n \"googleapis.com\"\r\ + \n \"youtu.be\"\r\ + \n \"googlevideo.com\"\r\ + \n \"gstatic.com\"\r\ + \n \"googleusercontent.com\"\r\ + \n \"nhacmp3youtube.com\"\r\ + \n \"telegram.me\"\r\ + \n \"t.me\";}\r\ + \n\r\ + \n:local ListRKN \"RKN-dnsLookup\";\r\ + \n:local ListComment (\"ListRKN managed by \" . \$ScriptName);\r\ + \n:foreach aListItem in=[/ip/firewall/address-list find list=\$ListRKN] do\ + ={\r\ + \n /ip firewall address-list remove \$aListItem;\r\ + \n}\r\ + \n:foreach aItem in=\$arrRKN do={\r\ + \n# :do {\r\ + \n :retry delay=500ms max=5 on-error={:log error \"dns resolve fail\ + ure [ \$aItem - resolve ip ]\"} command={:resolve \$aItem}\r\ + \n# } on-error={\r\ + \n# :log error \"dns resolve failure [ \$arItem - resolve ip ]\";\r\ + \n# }\r\ + \n :foreach dnsRecord in=[/ip dns cache all find where (name=\$aItem)] \ + do={\r\ + \n :if ([/ip dns cache all get \$dnsRecord type]=\"A\") do={\r\ + \n :local newAddress [/ip dns cache all get \$dnsRecord data];\ + \r\ + \n :do {\r\ + \n /ip firewall address-list add list=\$ListRKN address=\$newA\ + ddress comment=\$aItem;\r\ + \n :log warning \"Successfully adding ip to list A record: \ + \$dnsRecord, address: \$newAddress domain: \$aItem\";\r\ + \n } on-error={\r\ + \n :log error \"error when adding ip to list A record: \$dn\ + sRecord, address: \$newAddress domain: \$aItem\";\r\ + \n }\r\ + \n }\r\ + \n :if ([/ip dns cache all get \$dnsRecord type]=\"CNAME\") do={\r\ + \n :local cname;\r\ + \n :local nextCname;\r\ + \n :local cnameAddress;\r\ + \n :set cname [/ip dns cache all find where (name=\$aItem && ty\ + pe=\"CNAME\")];\r\ + \n :set nextCname [/ip dns cache all find where (name=[/ip dns \ + cache all get \$cname data] && type=\"CNAME\")];\r\ + \n :while (\$nextCname != \"\") do={\r\ + \n :set cname \$nextCname;\r\ + \n :set nextCname [/ip dns cache all find where (name=[/ip \ + dns cache all get \$cname data] && type=\"CNAME\")];\r\ + \n }\r\ + \n :foreach aRecord in=[/ip dns cache all find where (name=[/ip\ + \_dns cache all get \$cname data] && type=\"A\")] do={\r\ + \n :do {\r\ + \n :set cnameAddress [/ip dns cache all get \$aRecord d\ + ata];\r\ + \n /ip firewall address-list add list=\$ListRKN address\ + =\$cnameAddress comment=\$aItem;\r\ + \n :log warning \"Succesfully adding ip to list CNAME r\ + ecord: \$cname, A record: \$aRecord, address: \$newAddress, from domain: \ + \$aItem.\";\r\ + \n# /ip firewall raw add action=add-dst-to-address-list\ + \_address-list=\$ListRKN address-list-timeout=none-dynamic chain=preroutin\ + g comment=\$aItem content=\$aItem;\r\ + \n } on-error={\r\ + \n :log error \"error when adding ip to list CNAME reco\ + rd: \$cname, A record: \$aRecord, address: \$newAddress, from domain: \$aI\ + tem.\";\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:if ([ :len [ /system/scheduler/find where name=\$ScriptName ] ] = 0) do\ + ={\r\ + \n :log error (\$ScriptName . \"System Scheduler for script: \" . \$Scri\ + ptName . \" is NOT SET! Fix It Now!\");\r\ + \n /system/scheduler/add name=\$ScriptName on-event=\"/system/script { \ + run \$ScriptName; }\" comment=\"Update RKN DNS Looup\" interval=00:30:00 p\ + olicy=\"ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon\"\ + \_start-time=startup;\r\ + \n }\r\ + \n:set dnsLookupReady true;\r\ + \ndelay 2s; \r\ + \n:global dnsLookupReady (a);\r\ + \n" +add dont-require-permissions=no name="renameLists " owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + local oldName \"Test\";\ + \n:local newName \"Test-IP\";\ + \n/ip firewall address-list\ + \n:foreach i in=[find list=\$oldName] do={\ + \nset \$i list=\$newName;\ + \n}\ + \n" +add dont-require-permissions=no name=IPv6-Settings owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + #############Script Settings##################\ + \n\ + \n:local \"IF-TUN\" \"6to4-tun\"\ + \n:local \"IF-LOC\" \"Bridge-LAN\"\ + \n:local \"POOL-6TO4\" \"poolV6-local\"\ + \n:local \"force-update\" false\ + \n############ use then static ip #######################\ + \n:local \"lease-address\" [/ip address get [find interface=\$\"IF-LOC\"] \ + address]\ + \n#:local \"interface\" \"ext\"\ + \n:local bound 0\ + \n\ + \n###############################################\ + \n\ + \n:local 6to4prefix do={\ + \n :global dec2hex\ + \n :local ipv4 \$1\ + \n :local ipv6 \"2002:\"\ + \n :for i from=0 to=2 step=1 do={ \ + \n :if ( \$i = 2) do={\ + \n :set ipv6 (\$ipv6.\":\")\ + \n }\ + \n :local fp [:find \$ipv4 \".\"]\ + \n :if ( \$fp > 0 ) do={\ + \n :set ipv6 (\$ipv6.[\$dec2hex [:pick \$ipv4 0 \$fp]])\ + \n :set ipv4 [:pick \$ipv4 (\$fp + 1 ) [:len \$ipv4]]\ + \n }\ + \n }\ + \n :return (\$ipv6.[\$dec2hex \$ipv4])\ + \n}\ + \n:local \"str_replace\" do={\ + \n :local \"str-pos\" [:find \$1 \$2]\ + \n :local \"str-len\" [:len \$2]\ + \n :local str \"\"\ + \n :local rest \$1\ + \n :while (\$\"str-pos\" >= 0) do={\ + \n :local t [:pick \$rest 0 \$\"str-pos\"]\ + \n :if ( \$4 > 0 ) do={\ + \n :for i from=1 to=(\$4 - [:len \$t]) step=1 do={\ + \n :set str (\$str.\$5)\ + \n }\ + \n }\ + \n :set str (\$str.\$t.\$3)\ + \n :set rest [:pick \$rest (\$\"str-pos\"+\$\"str-len\") [:len \$re\ + st]]\ + \n :set \"str-pos\" [:find \$rest \$2]\ + \n }\ + \n :return (\$str.\$rest)\ + \n}\ + \n\ + \n:if (\$bound=1) do={\ + \n :local t [:find \$\"lease-address\" \"/\"]\ + \n\ + \n :if ( \$t >= 0 ) do={\ + \n :set \"lease-address\" [:pick \$\"lease-address\" 0 \$t]\ + \n }\ + \n\ + \n :if ( [/interface 6to4 print count-only where name=\$\"IF-TUN\"] = 0\ + ) do={\ + \n /interface 6to4 add !keepalive local-address=\$\"lease-address\"\ + \_mtu=1280 name=\$\"IF-TUN\" remote-address=10.30.30.0\ + \n :set \"force-update\" true\ + \n }\ + \n\ + \n :local \"IPv4-TUN\" [/interface 6to4 get [find name=\$\"IF-TUN\"] lo\ + cal-address];\ + \n\ + \n :if ( \$\"lease-address\" != \$\"IPv4-TUN\" || \$\"force-update\" = \ + true) do={\ + \n /interface 6to4 set [find name=\$\"IF-TUN\"] local-address=\$\"l\ + ease-address\"\ + \n /ipv6 address remove [find interface=\$\"IF-TUN\"]\ + \n /ipv6 address remove [find interface=\$\"IF-LOC\"]\ + \n /ipv6 route remove [find gateway ~ \$\"IF-TUN\" and dst-address=\ + \"::/0\"]\ + \n :local \"pool-prefix\" [\$6to4prefix \$\"lease-address\"]\ + \n :if ( [/ipv6 pool print count-only where name=\$\"POOL-6TO4\"] =\ + \_0) do={ \ + \n /ipv6 pool add name=\$\"POOL-6TO4\" prefix=(\$\"pool-prefix\ + \".\":1::/64\") prefix-length=64\ + \n } else={\ + \n /ipv6 pool set [/ipv6 pool find where name=\$\"POOL-6TO4\"] \ + prefix=(\$\"pool-prefix\".\":1::/64\")\ + \n }\ + \n /ipv6 address add address=(\$\"pool-prefix\".\"::\".[\$MAC2EUI64\ + \_[/interface get [find name=\$\"interface\"] mac-address]].\"/3\") interf\ + ace=\$\"IF-TUN\" advertise=no\ + \n /ipv6 address add eui-64=yes from-pool=\$\"POOL-6TO4\" interface\ + =\$\"IF-LOC\" advertise=yes\ + \n /ipv6 route add dst-address=::/0 gateway=(\"::10.30.30.81%\".\$\ + \"IF-TUN\")\ + \n :local t [/ipv6 address get [find interface=\$\"IF-LOC\"] addres\ + s]\ + \n :set t [:pick \$t 0 [:find \$t \"/\"]]\ + \n :if ( [/ipv6 dhcp-server option print count-only where name=DNS]\ + \_= 0) do={\ + \n /ipv6 dhcp-server option add code=23 name=DNS value=(\"0x\".\ + [\$\"str_replace\" \$t \":\" \"\" 4 \"0\"])\ + \n } else={\ + \n /ipv6 dhcp-server option set [/ipv6 dhcp-server option find \ + where name=DNS] value=(\"0x\".[\$\"str_replace\" \$t \":\" \"\" 4 \"0\"])\ + \n }\ + \n :if ( [/ipv6 dhcp-server print count-only where interface=\$\"IF\ + -LOC\"] = 0) do={\ + \n /ipv6 dhcp-server add address-pool=\$\"POOL-6TO4\" dhcp-opti\ + on=DNS interface=\$\"IF-LOC\" lease-time=1d name=\$\"IF-LOC\"\ + \n }\ + \n :if ( [ipv6 nd print count-only where interface=\$\"IF-LOC\"] = \ + 0) do={\ + \n /ipv6 nd add advertise-dns=no interface=\$\"IF-LOC\" other-c\ + onfiguration=yes\ + \n }\ + \n }\ + \n}" +add dont-require-permissions=no name=IPv6-GlobalFunc owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + global MAC2EUI64 do={\ + \n :local EUI64 \"\"\ + \n :local MAC \$1\ + \n :local HEX2DEC \"0123456789ABCDEF\"\ + \n :for i from=0 to=5 step=1 do={\ + \n :if ( \$i = 0 ) do={\ + \n :set EUI64 [:pick \$MAC 0]\ + \n :set EUI64 (\$EUI64.[:tostr [:pick \$\"HEX2DEC\" ([:find \$\ + \"HEX2DEC\" [:pick \$MAC 1]] ^ 2)]])\ + \n }\ + \n :if ( \$i = 1 || \$i = 3) do={\ + \n :set EUI64 (\$EUI64.\":\")\ + \n }\ + \n :if ( \$i = 2 ) do={\ + \n :set EUI64 (\$EUI64.\"FF:FE\")\ + \n }\ + \n :if ( [:find \$MAC \":\"] = 2 ) do={\ + \n :set MAC [:pick \$MAC 3 [:len \$MAC]]\ + \n :set EUI64 (\$EUI64.[:pick \$MAC 0 2])\ + \n }\ + \n }\ + \n :return (\$EUI64)\ + \n}\ + \n\ + \n:global dec2hex do={\ + \n :local hex \"\"\ + \n :local dec [:tonum \$1]\ + \n :for i from=0 to=4 step=4 do={\ + \n :set hex ([:pick \"0123456789ABCDEF\" ((\$dec>>\$i)&0xf) (((\$de\ + c>>\$i)&0xf)+1)].\$hex)\ + \n }\ + \n :return ([:tostr \$hex])\ + \n}" +add comment=Generator dont-require-permissions=no name=proxySet owner=vados \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + source="# 2. WireGuard interface\r\ + \n/interface/wireguard/add name=wg-VDSina private-key=\"4CHyNhbOs923/EyNDg\ + uMXJXdghL2I3UyzXPwrANVgHs=\" listen-port=21641\r\ + \n/interface/wireguard/peers/add interface=wg-VDSina public-key=\"o5IgCl1/\ + G6xbl6j7sPaP4ZNYREeYOmqZjKbm+v0b9jU=\" preshared-key=\"RNvF7T1cg5tyXcYQnD9\ + N5BEp6e20vVJQTv0GMjyvHU0=\" endpoint-address=10.30.30.33 endpoint-port=518\ + 20 allowed-address=0.0.0.0/0 persistent-keepalive=11\r\ + \n/ip/address/add address=10.9.0.3/32 interface=wg-VDSina\r\ + \n\r\ + \n# 3. DNS\r\ + \n{ :local rawDNS [/ip/dns/get servers]; :local prevDNS \"\"; :foreach s i\ + n=[:toarray \$rawDNS] do={ :if ([:len \$prevDNS] > 0) do={ :set prevDNS \"\ + \$prevDNS,\$s\" } else={ :set prevDNS \$s } }; /system/script/add name=VDS\ + ina-prev-dns comment=\"\$prevDNS\" source=\"\" }\r\ + \n/ip/dns/set servers=8.8.4.4\r\ + \n/ip/route/add dst-address=8.8.4.4/32 gateway=wg-VDSina distance=1 commen\ + t=VDSina-dns\r\ + \n\r\ + \n# 4. Enable WireGuard\r\ + \n/interface/wireguard/enable wg-VDSina\r\ + \n" +add dont-require-permissions=no name=AM-Telegram-Send owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\ + \n# RouterOS script: AM-Telegram-Send\ + \n# Script comment: Mini script for send messages to admin Telegram chat\ + \n# Copyright (c) 2007-2026 Vados \ + \n#\ + \n#\ + \n# requires RouterOS, version=7.19\ + \n# requires device-mode, fetch\ + \n#\ + \n# Script description: \ + \n#\ + \n#\ + \n# Usage:\ + \n# /system/script { run AM-Telegram-Send \"Message here )))\"; }\ + \n\ + \n/system/script\ + \nadd name=telegram-send dont-require-permissions=no source={\ + \n :global TelegramTokenId;\ + \n :global TelegramChatId;\ + \n :local message [:tostr \$1];\ + \n :local identity [/system/identity/get name];\ + \n :local sendMsg (\"[\".\$identity.\"] \".\$message)\ + \n /tool/fetch url=(\"https://api.telegram.org/bot\".\$TelegramTokenId.\\\ + \n \"/sendMessage\\\?chat_id=\".\$TelegramChatId.\\\ + \n \"&text=\".\$sendMsg.\\\ + \n \"&parse_mode=HTML\") \\\ + \n mode=https keep-result=no\ + \n}" +add dont-require-permissions=no name=telegram-send owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="\ + \n :global TelegramTokenId;\ + \n :global TelegramChatId;\ + \n :local message [:tostr \$1];\ + \n :local identity [/system/identity/get name];\ + \n :local sendMsg (\"[\".\$identity.\"] \".\$message)\ + \n /tool/fetch url=(\"https://api.telegram.org/bot\".\$TelegramTokenId.\\\ + \n \"/sendMessage\\\?chat_id=\".\$TelegramChatId.\\\ + \n \"&text=\".\$sendMsg.\\\ + \n \"&parse_mode=HTML\") \\\ + \n mode=https keep-result=no\ + \n" +/user group +add name=backup policy="ssh,read,write,policy,test,web,sniff,sensitive,api,res\ + t-api,!local,!telnet,!ftp,!reboot,!winbox,!password,!romon" +/ip smb +set enabled=no interfaces=lo +/interface bridge port +add bridge=Bridge-LAN interface=ether5 +add bridge=Bridge-LAN interface=ether2 +add bridge=Bridge-LAN interface=ether4 trusted=yes +add bridge=Bridge-LAN interface=ether3 +add bridge=Bridge-LAN interface=wlan2 +add bridge=Bridge-LAN interface=wlan1 +/interface bridge settings +set use-ip-firewall=yes +/ip firewall connection tracking +set udp-timeout=10s +/ip neighbor discovery-settings +set discover-interface-list=LAN lldp-med=no lldp-poe-power=no +/ip settings +set accept-redirects=yes ipv4-multipath-hash-policy=l4 max-neighbor-entries=\ + 8192 +/ipv6 settings +set disable-ipv6=yes disable-link-local-address=yes forward=no \ + max-neighbor-entries=8192 multipath-hash-policy=l4 +/interface detect-internet +set detect-interface-list=WAN internet-interface-list=Internet \ + lan-interface-list=LAN request-interval=1m wan-interface-list=WAN +/interface l2tp-server server +set authentication=mschap2 use-ipsec=yes +/interface list member +add interface=Unet-ether1 list=Internet +add interface=WG list=WAN +add interface=Bridge-LAN list=LAN +add interface=Unet-ether1 list=WAN +/interface wireguard peers +add allowed-address=0.0.0.0/0 client-allowed-address=::/0 endpoint-address=\ + 109.107.177.79 endpoint-port=29185 interface=WG name=VDSina \ + persistent-keepalive=10s public-key=\ + "zuRsO+dL/j6awaBWZ/NgnHR+bCNUjRWbaHFpdzkNnw4=" +add allowed-address=0.0.0.0/0 client-allowed-address=::/0 disabled=yes \ + endpoint-address=10.30.30.33 endpoint-port=55055 interface=wg-nuc name=\ + NUC persistent-keepalive=11s public-key=\ + "+OvzAjLC45Td52hjkQPmpGvC3RGhZ+Q2CDMJ1U/D4Rw=" +/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=Bridge-LAN enabled=yes interfaces=\ + wlan2,wlan1 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 +add address=192.168.33.2/24 disabled=yes interface=wg-nuc network=\ + 192.168.33.0 +/ip cloud +set update-time=no +/ip dhcp-client +add add-default-route=special-classless check-gateway=arp comment=Unet-client \ + default-route-distance=2 default-route-tables=main:2 dhcp-options=\ + hostname,clientid_duid interface=Unet-ether1 name=UnetDHCP use-peer-dns=\ + no use-peer-ntp=no +/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=iVados mac-address=DE:4D:72:F3:1A:9F server=masterDHCP +add address=10.30.30.10 allow-dual-stack-queue=yes client-id=\ + ff:0:0:0:df:0:3:0:1:f0:75:5d:1e:5f:85 dhcp-option=HostName \ + dhcp-option-set=MikroNUC mac-address=F0:75:5D:1E:5F:85 server=masterDHCP \ + use-src-mac=yes +/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.33,109.107.177.79 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 verify-doh-cert=yes +/ip dns static +add address=109.107.177.79 comment="VDSina Server DNS" name=ns1.vados.ru \ + type=A +add address=109.107.177.79 name=vds.vados.ru type=A +add comment="Local DNS server for vados.ru" disabled=yes ns=10.30.30.81 \ + regexp=*.vados.ru type=NS +add comment="*.vados.ru Regexp" disabled=yes forward-to=10.30.30.81 regexp=\ + "\".*\\\\.vados\\\\.ru\"" type=FWD +add comment="*.30.30.10.in-addr.arpa Regexp" disabled=yes forward-to=\ + 10.30.30.81 regexp="\".*\\\\.30\\\\.30\\\\.10\\\\.in-addr\\\\.arpa" type=\ + FWD +add address=10.30.30.81 comment=NS.vados.ru.local disabled=yes name=\ + ns.vados.ru.local type=A +add comment="DNS ns.vados.ru.local" disabled=yes match-subdomain=yes name=\ + vados.ru ns=ns.vados.ru.local type=NS +add address=10.30.30.33 comment=reg.vados.ru name=reg.vados.ru type=A +add address=8.8.8.8 comment="Google-dns IPv4 1" match-subdomain=yes name=\ + dns.google type=A +add address=8.8.4.4 comment="Google-dns IPv4 2" name=dns.google type=A +add address=10.30.30.33 comment=AMSTER name=amster.vados.ru type=A +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 name=amster type=A +add address=10.30.30.33 name=amster-reg type=A +add address=10.30.30.33 disabled=yes 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 disabled=yes match-subdomain=yes name=\ + mikrots.vados.ru 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" disabled=yes name=\ + security.cloudflare-dns.com type=A +add address=1.1.1.1 comment="CloudFlare-doh IPv4 1" disabled=yes 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" disabled=yes name=\ + dns.quad9.net type=A +add address=195.133.25.16 comment="DNS Comss" disabled=yes name=dns.comss.one \ + 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 disabled=yes name=MikroYellow type=A +add address=10.30.30.85 disabled=yes 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=91.192.189.2 comment=Unet-DNS disabled=yes name=ns1.unet.ws type=\ + A +add address=10.30.30.20 disabled=yes name=garage 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=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-IP +add address=wg.vados.ru comment=VDSIna list=TRUSTED +add address=10.8.0.0/24 comment="WG VDSIna" disabled=yes 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-IP +add address=geoip.co list=NoVdsina +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=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=amster list=NoWG +add address=10.30.30.10 comment=MikroNUC disabled=yes list=NoWG +add address=89.110.101.17 comment=!!!VDSINA!!!! disabled=yes list=NoWG +add address=wg.vados.ru comment=VDSina-vpn list=VDSina +add address=80.85.244.9 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!!!" list=NoVdsina +add address=dns.quad9.net comment=Quad9-dns disabled=yes list=Trusted-DNS +add address=dns.google comment=Google-dns list=Trusted-DNS +add address=security.cloudflare-dns.com comment=CloudFlare-dns list=\ + Trusted-DNS +add address=time.google.com comment=Google-time list=Trusted-NTP +add address=0.ru.pool.ntp.org comment=ru.pool.ntp.org disabled=yes list=\ + Trusted-NTP +add address=1.ru.pool.ntp.org disabled=yes list=Trusted-NTP +add address=2.ru.pool.ntp.org comment=2.ru.pool.ntp.org disabled=yes list=\ + Trusted-NTP +add address=3.ru.pool.ntp.org comment=3.ru.pool.ntp.org disabled=yes list=\ + Trusted-NTP +add address=cp.vdsina.com comment=VDSina-vpn list=VDSina +add address=vdsina.ru comment=VDSina-vpn list=VDSina +add address=ns.vados.ru comment=VDSina-vpn list=VDSina +add address=vdsina.com comment=VDSina-vpn list=VDSina +add address=cp.vdsina.ru comment=VDSina-vpn list=VDSina +add address=ns1.vdsina.ru comment=VDSina-vpn list=VDSina +add address=10.30.30.0/24 comment="Local Network" list=Local-Net +add address=10.8.0.0/24 comment="WireGuard Network" list=Local-Net +add address=146.120.64.208/29 comment="External Net" list=Unet +add address=esia.gosuslugi.ru comment=esia.gosuslugi.ru list=NoVdsina +add address=lk.gosuslugi.ru comment=lk.gosuslugi.ru list=NoVdsina +add address=trudvsem.ru comment=trudvsem.ru list=NoVdsina +add address=10.30.30.30 comment=miller disabled=yes list=NoWG +add address=10.30.30.33 comment="Direct connet to DNS servers" list=\ + Direct-DNS +add address=109.107.177.79 list=VPN-Server +add address=10.0.0.0/8 list=RFC1918 +add address=172.16.0.0/12 list=RFC1918 +add address=192.168.0.0/16 list=RFC1918 +add address=8.8.4.4 disabled=yes list=to_vpn +add address=myip.ru disabled=yes list=to_vpn +add address=10.30.30.98 disabled=yes list=to_vpn +/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=Unet-ether1 protocol=udp \ + src-address-list=!Trusted-DNS +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=Unet-ether1 protocol=tcp src-address-list=!Trusted-DNS +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 \ + in-interface=Unet-ether1 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=Unet-ether1 protocol=udp +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=4w2d chain=input comment="block honeypot NTP" \ + connection-state=new dst-port=123 in-interface=Unet-ether1 protocol=udp +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=accept chain=input dst-port=29185 in-interface=Unet-ether1 \ + protocol=tcp +add action=accept chain=input dst-port=29185 in-interface=Unet-ether1 \ + protocol=udp +add action=accept chain=input comment="tcp Accept input DNS queries from LAN" \ + dst-port=53 protocol=tcp src-address=10.30.30.0/24 +add action=accept chain=input comment="udp Accept input DNS queries" \ + dst-port=53 protocol=udp src-address=10.30.30.0/24 +add action=accept chain=output comment="accept WireGuard" disabled=yes \ + dst-address-list=VPN-Server out-interface=Unet-ether1 protocol=udp \ + src-port=13231 +add action=accept chain=output disabled=yes dst-address-list=VPN-Server \ + dst-port=29185 out-interface=Unet-ether1 protocol=udp +add action=fasttrack-connection chain=forward comment="defconf: fasttrack" \ + connection-state=established,related,new disabled=yes routing-mark=\ + !To-VPN +add action=accept chain=output disabled=yes protocol=tcp src-port=443 +add action=accept chain=output disabled=yes src-address=127.0.0.1 +add action=accept chain=forward comment="defconf: accept in ipsec policy" \ + disabled=yes ipsec-policy=in,ipsec +add action=accept chain=forward comment="defconf: accept out ipsec policy" \ + disabled=yes ipsec-policy=out,ipsec +add action=accept chain=forward comment=\ + "defconf: accept established,related, untracked" connection-state=\ + established,related,untracked disabled=yes +add action=drop chain=forward comment="defconf: drop invalid" \ + connection-state=invalid in-interface=Unet-ether1 src-address=\ + !10.30.30.0/24 +add action=drop chain=forward comment=\ + "defconf: drop all from WAN not DSTNATed" connection-nat-state=!dstnat \ + connection-state=new in-interface=Unet-ether1 src-address-list=!VDSina +add action=accept chain=input in-interface=Unet-ether1 protocol=icmp \ + src-address-list=VDSina +add action=accept chain=input connection-state=established +add action=accept chain=input connection-state=related +/ip firewall mangle +add action=accept chain=prerouting comment=RFC1918 dst-address-list=RFC1918 \ + in-interface-list=!WAN +add action=mark-routing chain=prerouting comment="Mark Routing main for NoWG" \ + new-routing-mark=main passthrough=no src-address-list=NoWG +add action=mark-routing chain=prerouting comment=\ + "Mark Routing main for NoVdsina" disabled=yes dst-address-list=NoVdsina \ + new-routing-mark=main passthrough=no src-address=10.30.30.0/24 +add action=mark-connection chain=prerouting comment=\ + "Transit for address-list \"to_vpn\"" connection-mark=no-mark disabled=\ + yes dst-address-list=to_vpn in-interface-list=!WAN new-connection-mark=\ + to-vpn-conn routing-mark=!main +add action=mark-routing chain=prerouting comment=\ + "Find routing over table r_to_vpn" connection-mark=to-vpn-conn disabled=\ + yes in-interface-list=!WAN new-routing-mark=r_to_vpn +add action=mark-routing chain=prerouting comment=\ + "Mark Routing main for VDSina" dst-address-list=VPN-Server \ + new-routing-mark=main passthrough=no src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=\ + "Mark Routing main for MikroNuc" disabled=yes dst-address-list=AWG-Proxy \ + new-routing-mark=main src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=\ + "!!!ERROR Mark Routing main for Unet!!!" disabled=yes dst-address-list=\ + Unet new-routing-mark=main passthrough=no +add action=mark-routing chain=prerouting comment="Test-IP sites" disabled=yes \ + dst-address=!10.30.30.0/24 dst-address-list=Test-IP new-routing-mark=\ + To-VPN src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=FuckRKN disabled=yes \ + dst-address=!10.30.30.0/24 dst-address-list=RKN-dnsLookup \ + new-routing-mark=To-VPN passthrough=no src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment="WG for all" \ + dst-address-list=!NoVdsina new-routing-mark=To-VPN src-address=\ + 10.30.30.0/24 +add action=change-mss chain=forward comment="MSS on WG" new-mss=1380 \ + out-interface=WG protocol=tcp routing-mark=To-VPN tcp-flags=syn tcp-mss=\ + 1381-65535 +add action=mark-connection chain=prerouting comment=\ + "Mark VPN connections to exclude from FastTrack" disabled=yes \ + new-connection-mark=VPN_No_FastTrack routing-mark=To-VPN +add action=mark-routing chain=prerouting comment="VPN Network" disabled=yes \ + dst-address=10.8.0.0/24 new-routing-mark=To-VPN src-address=10.30.30.0/24 +add action=mark-connection chain=output comment="For this router" \ + connection-mark=no-mark disabled=yes dst-address-list=to_vpn \ + new-connection-mark=to-vpn-conn-local +add action=mark-routing chain=output comment="For this router" \ + connection-mark=to-vpn-conn-local disabled=yes new-routing-mark=r_to_vpn +/ip firewall nat +add action=redirect chain=dstnat comment="udp Redirect DNS in NAT" disabled=\ + yes dst-port=53 protocol=udp src-address=10.30.30.0/24 src-address-list=\ + !NoWG to-addresses=10.30.30.33 to-ports=53 +add action=redirect chain=dstnat comment="tcp Redirect DNS in NAT" disabled=\ + yes dst-port=53 protocol=tcp src-address=10.30.30.0/24 src-address-list=\ + !NoWG to-addresses=10.30.30.33 to-ports=53 +add action=masquerade chain=srcnat comment=\ + "Nat Addresses for routing mark r_to_vpn" disabled=yes routing-mark=\ + r_to_vpn +add action=dst-nat chain=dstnat comment=\ + "53/tcp dst-nat to amster.loc. From VDSina Server" dst-port=53 \ + in-interface=Unet-ether1 protocol=tcp src-address-list=VPN-Server \ + to-addresses=10.30.30.33 to-ports=53 +add action=dst-nat chain=dstnat comment=\ + "53/udp dst-nat to amster.loc. From VDSina Server" dst-port=53 protocol=\ + udp src-address-list=VPN-Server to-addresses=10.30.30.33 to-ports=53 +add action=dst-nat chain=dstnat disabled=yes dst-port=44333 in-interface=\ + Unet-ether1 protocol=udp src-address=!10.30.30.0/24 to-addresses=\ + 10.30.30.33 to-ports=44333 +add action=masquerade chain=srcnat comment=WG dst-address-list=!NoVdsina \ + routing-mark=To-VPN +add action=masquerade chain=srcnat comment="Default NAT" out-interface=\ + Unet-ether1 routing-mark=!To-VPN src-address=10.30.30.0/24 +add action=dst-nat chain=dstnat dst-port=44044 in-interface=Unet-ether1 \ + protocol=udp src-address=109.107.177.79 to-addresses=10.30.30.33 \ + to-ports=44044 +add action=dst-nat chain=dstnat comment=amster.vados.ruhttps dst-port=443 \ + fragment=no in-interface=Unet-ether1 protocol=tcp routing-mark=main \ + 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=Unet-ether1 protocol=tcp to-addresses=\ + 10.30.30.33 to-ports=80 +add action=dst-nat chain=dstnat comment="amster.vados.ru 3x-ui" disabled=yes \ + dst-port=2904 in-interface=Unet-ether1 protocol=tcp to-addresses=\ + 10.30.30.33 to-ports=2904 +add action=dst-nat chain=dstnat comment=reg.vados.ru disabled=yes dst-port=\ + 5000 in-interface=Unet-ether1 protocol=tcp to-addresses=10.30.30.33 \ + to-ports=5000 +add action=dst-nat chain=dstnat comment="Docker swarm" disabled=yes dst-port=\ + 2377 in-interface=Unet-ether1 protocol=tcp to-addresses=10.30.30.33 \ + to-ports=2377 +add action=dst-nat chain=dstnat comment=npm dst-port=81 in-interface=\ + Unet-ether1 protocol=tcp routing-mark=To-VPN to-addresses=10.30.30.33 \ + to-ports=81 +add action=dst-nat chain=dstnat comment=SSH dst-port=22 in-interface=\ + Unet-ether1 protocol=tcp src-address-list=TRUSTED to-addresses=\ + 10.30.30.33 to-ports=22 +add action=dst-nat chain=dstnat comment="portainer agent" disabled=yes \ + dst-port=2377 in-interface=Unet-ether1 protocol=tcp to-addresses=\ + 10.30.30.33 to-ports=2377 +add action=dst-nat chain=dstnat disabled=yes dst-port=22 in-interface=\ + Unet-ether1 protocol=tcp routing-mark=!To-VPN to-addresses=10.30.30.33 \ + to-ports=22 +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=Unet-ether1 src-address-list="Honeypot Hacker" +add action=accept chain=prerouting comment="Trusted DNS" disabled=yes \ + in-interface-list=WAN src-address-list=Trusted-DNS +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=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=youtube.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + googleapis.com disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=ggpht.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=youtu.be \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=ytimg.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + googlevideo.com disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=gstatic.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + googleusercontent.com disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + nhacmp3youtube.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=rutube.ru \ + content=rutube.ru disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment="me.com raw" \ + content=me.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "icloud.com raw" content=icloud.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "smtp.mail.me.com raw" content=smtp.mail.me.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "smtp.mail.me.com.akadns.net raw" content=smtp.mail.me.com.akadns.net \ + disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "api.db-ip.com raw" content=api.db-ip.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + esia.gosuslugi.ru content=esia.gosuslugi.ru disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=gosuslugi.ru \ + content=gosuslugi.ru disabled=yes +/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 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 check-gateway=none comment=WG-Default 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 +set api-ssl address=10.30.30.0/24 disabled=yes +set www-ssl certificate=Root-YE port=18443 +set www address=10.30.30.0/24 disabled=yes port=18880 +/ip service webserver +set acme-plain=no crl-plain=no graphs-plain=no graphs-secure=no index-plain=\ + no index-secure=no rest-secure=no scep-plain=no webfig-plain=no \ + webfig-secure=no +/ip ssh +set forwarding-enabled=both publickey-authentication-options=verify-required +/ip upnp +set enabled=yes +/ip upnp interfaces +add interface=Bridge-LAN type=internal +add forced-ip=146.120.64.211 interface=Unet-ether1 type=external +add forced-ip=109.107.177.79 interface=*E type=external +add interface=lo type=internal +add interface=wlan2 type=internal +add interface=wlan1 type=internal +/ipv6 dhcp-client +add add-default-route=yes disabled=yes interface=*F rapid-commit=no request=\ + info use-interface-duid=yes validate-server-duid=no +/ipv6 dhcp-server option sets +add name=domain-search-set options=domain-search-list +add name="=\"Client ID\"" options=HostName +/ipv6 firewall address-list +add address=::/128 comment="defconf: unspecified address" list=bad_ipv6 +add address=::1/128 comment="defconf: lo" list=bad_ipv6 +add address=fec0::/10 comment="defconf: site-local" list=bad_ipv6 +add address=::ffff:0.0.0.0/96 comment="defconf: ipv4-mapped" list=bad_ipv6 +add address=::/96 comment="defconf: ipv4 compat" list=bad_ipv6 +add address=100::/64 comment="defconf: discard only " list=bad_ipv6 +add address=2001:db8::/32 comment="defconf: documentation" list=bad_ipv6 +add address=2001:10::/28 comment="defconf: ORCHID" list=bad_ipv6 +add address=3ffe::/16 comment="defconf: 6bone" list=bad_ipv6 +/ipv6 firewall filter +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 ICMPv6" protocol=\ + icmpv6 +add action=accept chain=input comment="defconf: accept UDP traceroute" \ + dst-port=33434-33534 protocol=udp +add action=accept chain=input comment=\ + "defconf: accept DHCPv6-Client prefix delegation." dst-port=546 protocol=\ + udp src-address=fe80::/10 +add action=accept chain=input comment="defconf: accept IKE" dst-port=500,4500 \ + protocol=udp +add action=accept chain=input comment="defconf: accept ipsec AH" protocol=\ + ipsec-ah +add action=accept chain=input comment="defconf: accept ipsec ESP" protocol=\ + ipsec-esp +add action=accept chain=input comment=\ + "defconf: accept all that matches ipsec policy" ipsec-policy=in,ipsec +add action=drop chain=input comment=\ + "defconf: drop everything else not coming from LAN" in-interface-list=\ + !LAN +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 packets with bad src ipv6" src-address-list=bad_ipv6 +add action=drop chain=forward comment=\ + "defconf: drop packets with bad dst ipv6" dst-address-list=bad_ipv6 +add action=drop chain=forward comment="defconf: rfc4890 drop hop-limit=1" \ + hop-limit=equal:1 protocol=icmpv6 +add action=accept chain=forward comment="defconf: accept ICMPv6" protocol=\ + icmpv6 +add action=accept chain=forward comment="defconf: accept HIP" protocol=139 +add action=accept chain=forward comment="defconf: accept IKE" dst-port=\ + 500,4500 protocol=udp +add action=accept chain=forward comment="defconf: accept ipsec AH" protocol=\ + ipsec-ah +add action=accept chain=forward comment="defconf: accept ipsec ESP" protocol=\ + ipsec-esp +add action=accept chain=forward comment=\ + "defconf: accept all that matches ipsec policy" ipsec-policy=in,ipsec +add action=drop chain=forward comment=\ + "defconf: drop everything else not coming from LAN" in-interface-list=\ + !LAN +/ipv6 nd +set [ find default=yes ] advertise-dns=yes disabled=yes interface=Bridge-LAN \ + managed-address-configuration=yes other-configuration=yes pref64=::/64 +/ipv6 nd prefix +add autonomous=no disabled=yes interface=Bridge-LAN on-link=no prefix=none +/ipv6 nd prefix default +set dhcp6-pd-preferred=yes +/ipv6 nd proxy +add disabled=yes interface=lo +/ipv6 nd settings +set router-advertisement-route-distance=100 +/routing settings +set single-process=no +/system clock +set 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 package update +set check-certificate=yes-without-crl ip-version=ipv4 +/system scheduler +add comment="Every Day Set Global Environment Variables" 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="Update RKN DNS Looup" disabled=yes interval=20m name=\ + AM-RKN-dnsLookup on-event="/system/script { run AM-RKN-dnsLookup; }" \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-time=startup +/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 certificate=DigiCert-Global-Root-CA check-certificate=no comment="doh, doh\ + -url=https://security.cloudflare-dns.com/dns-query, notify, name=CloudFlar\ + e-doh IPv4 1" disabled=yes down-script="" host=1.1.1.1 http-codes="" \ + interval=10s name="CloudFlare-doh IPv4 1" port=443 test-script="" type=\ + https-get 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="" \ + name="CloudFlare-doh IPv4" port=443 test-script="" type=https-get \ + up-script="" +add comment="dns, notify, name=Google-DNS IPv4" disabled=yes dns-server=\ + 8.8.8.8 down-script="" host=dns.google http-codes="" name=\ + "Google-DNS IPv4" test-script="" type=dns up-script="" +add certificate=GTS-Root-R4 check-certificate=yes comment="doh-fallback, doh-u\ + rl=https://dns.google/dns-query, doh-cert=GTS Root R1, notify, name=Google\ + -DOH IPv4" disabled=yes dns-server=8.8.4.4 down-script="" host=dns.google \ + http-codes="" name="Google-DOH IPv4" port=443 record-type=NS src-address=\ + "" test-script="" type=dns up-script="" +add comment="dns-fallback, notify, name=Cuad9-DOH IPv4" disabled=yes \ + dns-server=9.9.9.9 down-script="" host=dns9.quad9.net http-codes="" \ + interval=10s name="Cuad9-DOH IPv4" src-address=146.120.64.211 \ + test-script="" timeout=800ms type=dns up-script="" +add certificate=DigiCert-Assured-ID-Root-CA comment="doh-fallback, doh-url=htt\ + ps://dns.quad9.net/dns-query, name=Cuad9-DOH IPv4" disabled=yes \ + down-script="" host=149.112.112.112 http-codes="" interval=10s name=\ + "Cuad9-DOH IPv4" port=443 test-script="" type=https-get up-script="" +add comment="dns-fallback, notify, name=ns1.unet.ws" disabled=yes \ + down-script="" host=91.192.189.2 http-codes="" interval=10s name=\ + ns1.unet.ws test-script="" type=simple up-script="" +add check-certificate=yes comment=\ + "doh, doh-url=https://vds.vados.ru/vds-query, name=vds.vados.ru" \ + disabled=yes down-script="" host=109.107.177.79 http-codes="" name=\ + vds.vados.ru port=443 test-script="" type=https-get up-script="" +add comment="WireGuard NAT " disabled=yes down-script="/log info \"[WG-Monitor\ + ] WireGuard is NOT running - reverting rules\"\ + \n/ip firewall nat remove [find comment=\"Redirect to Router\"]\ + \n/ip dns set servers=8.8.8.8\ + \n/ip dns cache flush\ + \n/ip route remove [find comment=\"wg-auto-route\"]\ + \n" host=10.8.0.1 http-codes="" interval=15s name=WG test-script="" \ + timeout=5s type=simple up-script="/log info \"[WG-Monitor] WireGuard is RU\ + NNING - applying rules\";\ + \n:local routeFile \"ips.txt\";\ + \n:local routeDefAddr \"0.0.0.0/0\";\ + \n:local routeGateway \"10.8.0.1\";\ + \n:local routeIF \"WG\";\ + \n:local routeTable \"To-VPN\";\ + \n:local routeComment \"wg-auto-route\";\ + \n/ip dns cache flush;\ + \n:if ([:len [/ip firewall nat find comment=\"Redirect to Router\"]] > 0) \ + do={\ + \n /ip firewall nat remove [find comment=\"Redirect to Router\"];\ + \n}\ + \n/ip firewall nat add action=redirect chain=dstnat src-address-list=\"Red\ + irectDNS\" dst-port=53 protocol=udp comment=\"Redirect to Router\";\ + \n/ip dns set servers=\$routeGateway;\ + \n:local content [/file get \$routeFile contents];\ + \n:if ([:len \$content] > 0) do={\ + \n :local line \"\";\ + \n :for i from=0 to=([:len \$content] - 1) do={\ + \n :local char [:pick \$content \$i];\ + \n :if (\$char != \"\\r\" && \$char != \"\\n\") do={\ + \n :set line (\$line . \$char);\ + \n } else={\ + \n :if ([:len \$line] > 5) do={\ + \n :do { /ip route add disabled=no dst-address=\$routeDefAd\ + dr gateway=\$routeIF distance=1 scope=30 target-scope=10 routing-table=\$r\ + outeTable comment=\$routeComment check-gateway=none } on-error={}\ + \n }\ + \n :set line \"\";\ + \n }\ + \n }\ + \n :if ([:len \$line] > 5) do={\ + \n# :do { /ip route add dst-address=\$line gateway=\$routeGateway \ + distance=1 comment=\$routeComment } on-error={}\ + \n :do { /ip route add disabled=no dst-address=\$routeDefAddr ga\ + teway=\$routeIF distance=1 scope=30 target-scope=10 routing-table=\$routeT\ + able comment=\$routeComment check-gateway=none } on-error={}\ + \n }\ + \n}\ + \n:local dotPos [:find \$routeGateway \".\"];\ + \n:if (\$dotPos != \"\") do={\ + \n :local firstOctet [:pick \$routeGateway 0 \$dotPos];\ + \n :local derivedDstAddress (\$firstOctet . \".30.0.0/15\");\ + \n :do { /ip route add dst-address=\$derivedDstAddress gateway=\$routeG\ + ateway distance=1 comment=\$routeComment } on-error={}\ + \n}\ + \n\ + \n" +add comment=WG-Default disabled=yes down-script=\ + "/ip route disable [find comment=\"WG-Default\"];" host=10.8.0.1 \ + interval=15s name=WG packet-count=20 test-script="" thr-loss-count=5 \ + type=icmp up-script="/ip route enable [find comment=\"WG-Default\"];" +/user aaa +set accounting=no -- 2.52.0