From 9059eded3ee61f8b201e63f852862b449d424efd Mon Sep 17 00:00:00 2001 From: vados-dev Date: Fri, 3 Jul 2026 16:20:45 +0300 Subject: [PATCH] Backup for MikroGig created successfully at Jul 03 16:20:45. --- .../20260703/20260703162040-Binary.backup | Bin 0 -> 189910 bytes MikroGig/20260703/20260703162040-Config.rsc | 3287 +++++++++++++++ .../20260703/20260703162040-Diff-Config.rsc | 122 + .../20260703/20260703152002-Config.rsc | 3700 +++++++++++++++++ .../20260703/20260703160002-Config.rsc | 3687 ++++++++++++++++ 5 files changed, 10796 insertions(+) create mode 100644 MikroGig/20260703/20260703162040-Binary.backup create mode 100644 MikroGig/20260703/20260703162040-Config.rsc create mode 100644 MikroGig/history/20260703/20260703162040-Diff-Config.rsc create mode 100644 MikroMaster/20260703/20260703152002-Config.rsc create mode 100644 MikroMaster/20260703/20260703160002-Config.rsc diff --git a/MikroGig/20260703/20260703162040-Binary.backup b/MikroGig/20260703/20260703162040-Binary.backup new file mode 100644 index 0000000000000000000000000000000000000000..23b782b116b25a1aa8acbedfe838c9dc73ff26fd GIT binary patch literal 189910 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

R7M@{!JWY(X)PhTlQwhf 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 TCH1w1Jzjthc7okY3rF6fRxRT= literal 0 HcmV?d00001 diff --git a/MikroGig/20260703/20260703162040-Config.rsc b/MikroGig/20260703/20260703162040-Config.rsc new file mode 100644 index 0000000..5c61cd4 --- /dev/null +++ b/MikroGig/20260703/20260703162040-Config.rsc @@ -0,0 +1,3287 @@ +# 2026-07-03 16:20:41 by RouterOS 7.23.1 +# software id = 2961-C4ZZ +# +# model = RBD52G-5HacD2HnD +# serial number = HCX084RAVFA +/interface bridge +add admin-mac=18:FD:74:6E:58:14 auto-mac=no name=Bridge-LAN port-cost-mode=\ + short +/interface wireless +# managed by CAPsMAN +set [ find default-name=wlan1 ] country=belarus mode=ap-bridge ssid=vados \ + wps-mode=disabled +# managed by CAPsMAN +set [ find default-name=wlan2 ] country=belarus mode=ap-bridge ssid=vados5g \ + wps-mode=disabled +/interface ethernet +set [ find default-name=ether1 ] mac-address=48:8F:5A:8E:1A:BC +/disk +add mount-point-template="[tmpfs]" slot=ram tmpfs-max-size=64 type=tmpfs +/interface list +add name=WAN +add name=LAN +add exclude=LAN include=WAN name=Internet +/interface wireless security-profiles +set [ find default=yes ] supplicant-identity=MikroTik +/routing table +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 comment="Script for setup routeros script system" \ + dont-require-permissions=no name=AM-setup owner=AM-setup policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\r\ + \n# RouterOS script: AM-setup\r\ + \n# Script comment: Script for setup routeros script system\r\ + \n# Copyright (c) 2005-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version=7.19\r\ + \n# requires device-mode, fetch\r\ + \n#\r\ + \n# :local ScriptName [ :jobname ];\r\ + \n# Additional commands:\r\ + \n#\r\ + \n# For scripts:\r\ + \n#:global NewScript \"script_name\"; \r\ + \n#:global GlobalScriptsUrl \"https://ros.vados.ru/\";\r\ + \n#/system/script/add name=\$NewScript owner=\$NewScript source=([/tool/fe\ + tch check-certificate=yes-without-crl (\$GlobalScriptsUrl . \$ScriptAdd . \ + \".rsc\") output=user as-value ]->\"data\");\r\ + \n#:global NewScript (a);\r\ + \n#:global ScriptInstallUpdate; \$ScriptInstallUpdate;\r\ + \n#\r\ + \n# For run from terminal:\r\ + \n#/system/script/add name=AM-setup owner=AM-Setup source=([/tool/fetch ch\ + eck-certificate=yes-without-crl \"https://ros.vados.ru/AM-setup.rsc\" outp\ + ut=user as-value ]->\"data\");\r\ + \n#\r\ + \n\r\ + \n:global ScriptUpdatesCRLF \"LF\";\r\ + \n#:if (\$ScriptUpdatesCRLF != false) do={\r\ + \n# :foreach Script in=[ /system/script/find where source~\"^#!rsc by Vad\ + os\" ] do={\r\ + \n# if (\$ScriptUpdatesCRLF = true) do={\r\ + \n# /system/script/set source=[ :tocrlf [ get \$Script source ] ] \$S\ + cript;\r\ + \n# } else={\r\ + \n# /system/script/set source=[ :tolf [ get \$Script source ] ] \$Scr\ + ipt;\r\ + \n# }\r\ + \n# }\r\ + \n#}\r\ + \n\r\ + \n# /import verbose=no \$ScriptName\r\ + \n:global 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{\r\ + \n :local RmMe [:tobool \$1];\r\ + \n\r\ + \n :global GlobalScriptsUrl;\r\ + \n :global SetupScript;\r\ + \n :global RemoveMe;\r\ + \n :global InitSetup;\r\ + \n :global tmpfs;\r\ + \n\r\ + \n :local 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 :if (\$SetupScript = false) do={\r\ + \n :global SetupScript \"AM-setup\";\r\ + \n }\r\ + \n :if (\$RemoveMe != false) do={\r\ + \n :set RemoveMe true;\r\ + \n }\r\ + \n\r\ + \n :log warning (\"\\n\\\$GlobalScriptsUrl = \" . \$GlobalScriptsUrl);\r\ + \n \r\ + \n\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: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 :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 :if (\$RemoveMe = true) do={\r\ + \n :put \"Add Scheduler for remove this script...\";\r\ + \n :local OnEvent (\":delay 30s;\\n\" . \"/system/script/remove [ find \ + where name=\\\"\$SetupScript\\\" ];\\n\" . \\\r\ + \n \":delay 2s;\\n\" . \"/system/scheduler/remove [ find where name=\\\ + \"_RemoveSetup\\\" ];\\n\" . \\\r\ + \n \":delay 2s;\\n\" . \":global RemoveMe (a);\\n\");\r\ + \n :local Comment \"_RemoveSetup tmp scheduler for remove setup script.\ + \";\r\ + \n /system/scheduler/add name=\"_RemoveSetup\" comment=\$Comment start-\ + time=startup interval=30s on-event=\$OnEvent;\r\ + \n :log warning (\$0 . \"\\nI've done everything, and now I'm tired..\ + . I'm leaving.\\nThere will be an error below, this is normal.\");\r\ + \n }\r\ + \n :delay 1;\r\ + \n :put \"Loading configuration and functions...\";\r\ + \n :do { \r\ + \n :global ScriptInstallUpdate; \$ScriptInstallUpdate;\r\ + \n :put \"Normal removing temporary global environment variables.\";\ + \r\ + \n :global SetupScript (a);\r\ + \n :global InitSetup (a);\r\ + \n :global RemoveMe (a);\r\ + \n } on-error={\r\ + \n :local ErrorMsg \"Loading configuration and functions error!\";\r\ + \n :log error (\$0 . \$ErrorMsg . :error);\r\ + \n :error \$ErrorMsg;\r\ + \n }\r\ + \n}\r\ + \n" +add comment="Global Config Script" dont-require-permissions=no name=\ + AM-GlobalConfig owner=AM-GlobalConfig policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\r\ + \n# RouterOS script: AM-GlobalConfig\r\ + \n# Script comment: Global Config Script\r\ + \n# Copyright (c) 2007-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# Warning: Dont touch this line!\r\ + \n:global Identity [/system/identity/get name];\r\ + \n:global GlobalConfReady false;\r\ + \n#\r\ + \n#\r\ + \n# Global Url For Amster scripts to fetch\r\ + \n# most be defined in AM-Init-Script or AM-setup scripts\r\ + \n:global GlobalScriptsUrl \"https://ros.vados.ru/\";\r\ + \n:global ScriptsUrlSuffix (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/728/bebacfc7\";\r\ + \n:global CommitTAG \"unknown\";\r\ + \n:global CommitInfo \"Autocommit in repo: ros.vados.ru, generated by owne\ + 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\ + \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="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" +/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 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 +/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 +# in/out-interface matcher not possible when interface (ether1) is slave - use master instead (Bridge-LAN) +add action=dst-nat chain=dstnat dst-port=443 in-interface=ether1 protocol=udp \ + to-addresses=10.9.9.2 to-ports=55055 +# in/out-interface matcher not possible when interface (ether1) is slave - use master instead (Bridge-LAN) +add action=dst-nat chain=dstnat 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 +/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=*A 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 diff --git a/MikroGig/history/20260703/20260703162040-Diff-Config.rsc b/MikroGig/history/20260703/20260703162040-Diff-Config.rsc new file mode 100644 index 0000000..48edd71 --- /dev/null +++ b/MikroGig/history/20260703/20260703162040-Diff-Config.rsc @@ -0,0 +1,122 @@ +11,12c11,12 +< set [ find default-name=wlan1 ] country=belarus mode=ap-bridge ssid=vados \ +< wps-mode=disabled +--- +> set [ find default-name=wlan2 ] country=belarus mode=ap-bridge name=wlan1 \ +> ssid=vados wps-mode=disabled +14,15c14,15 +< set [ find default-name=wlan2 ] country=belarus mode=ap-bridge ssid=vados5g \ +< wps-mode=disabled +--- +> set [ find default-name=wlan1 ] country=belarus mode=ap-bridge name=wlan2 \ +> ssid=vados5g wps-mode=disabled +17a18,23 +> /interface veth +> add address=172.19.75.210/30 container-mac-address=26:CC:65:F9:9A:4B dhcp=no \ +> gateway=172.19.75.209 gateway6="" mac-address=26:CC:65:F9:9A:4A name=\ +> veth-awg-VDSina +> /interface wireguard +> add listen-port=14710 mtu=1420 name=wg-awg-VDSina +2887a2894,2947 +> add comment=awg-VDSina dont-require-permissions=no name=awg-VDSina-uninstall \ +> owner=vados policy=\ +> ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon 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" +2890a2951,2955 +> /container +> add comment=awg-VDSina envlists=awg-VDSina-env file=\ +> usb1/pull/awg-proxy-arm.tar.gz hostname=awg-VDSina interface=\ +> veth-awg-VDSina layer-dir=/usb1/docker name=awg-proxy-arm root-dir=\ +> /usb1/awg-VDSina shm-size=4096.0KiB start-on-boot=yes +2894a2960,2986 +> /container envs +> add key=AWG_CLIENT_PUB list=awg-VDSina-env value=\ +> "NAonhRSuFIrFpNKTs5X32ItcvFuO1kiJUigQZb95YlE=" +> add key=AWG_H1 list=awg-VDSina-env value=472437748-472438637 +> add key=AWG_H2 list=awg-VDSina-env value=707808381-707809250 +> add key=AWG_H3 list=awg-VDSina-env value=1609078552-1609079495 +> add key=AWG_H4 list=awg-VDSina-env value=1012329484-1012329741 +> add key=AWG_I1 list=awg-VDSina-env value=\ +> "" +> add key=AWG_I2 list=awg-VDSina-env value="" +> add key=AWG_I3 list=awg-VDSina-env value="" +> add key=AWG_I4 list=awg-VDSina-env value="" +> add key=AWG_I5 list=awg-VDSina-env value="" +> add key=AWG_JC list=awg-VDSina-env value=9 +> add key=AWG_JMAX list=awg-VDSina-env value=920 +> add key=AWG_JMIN list=awg-VDSina-env value=105 +> add key=AWG_LISTEN list=awg-VDSina-env value=:44044 +> add key=AWG_PREV_DNS list=awg-VDSina-env value=8.8.8.8 +> add key=AWG_PREV_TMPDIR list=awg-VDSina-env value=/usb1/pull +> add key=AWG_REMOTE list=awg-VDSina-env value=109.107.177.79:55055 +> add key=AWG_S1 list=awg-VDSina-env value=90 +> add key=AWG_S2 list=awg-VDSina-env value=136 +> add key=AWG_S3 list=awg-VDSina-env value=45 +> add key=AWG_S4 list=awg-VDSina-env value=27 +> add key=AWG_SERVER_PUB list=awg-VDSina-env value=\ +> "o5IgCl1/G6xbl6j7sPaP4ZNYREeYOmqZjKbm+v0b9jU=" +> add key=AWG_STORAGE list=awg-VDSina-env value=usb1 +2921a3014,3017 +> /interface wireguard peers +> add allowed-address=0.0.0.0/0 endpoint-address=172.19.75.210 endpoint-port=\ +> 51820 interface=wg-awg-VDSina name=peer8 persistent-keepalive=10s \ +> public-key="o5IgCl1/G6xbl6j7sPaP4ZNYREeYOmqZjKbm+v0b9jU=" +2929a3026,3027 +> add address=172.19.75.209/30 interface=veth-awg-VDSina network=172.19.75.208 +> add address=10.9.0.3 interface=wg-awg-VDSina network=10.9.0.3 +2939a3038 +> add action=masquerade chain=srcnat src-address=172.19.75.208/30 +2987c3086 +< set time-zone-name=Europe/Moscow +--- +> set time-zone-name=Europe/Amsterdam diff --git a/MikroMaster/20260703/20260703152002-Config.rsc b/MikroMaster/20260703/20260703152002-Config.rsc new file mode 100644 index 0000000..19f1807 --- /dev/null +++ b/MikroMaster/20260703/20260703152002-Config.rsc @@ -0,0 +1,3700 @@ +# 2026-07-03 15:20: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="WAN - Unet" loop-protect=off name=\ + "ether1 - Unet" 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 +set [ find default-name=wlan1 ] country=belarus mode=ap-bridge ssid=vados \ + wireless-protocol=802.11 +# managed by CAPsMAN +set [ find default-name=wlan2 ] country=belarus mode=ap-bridge ssid=vados5g \ + wireless-protocol=802.11 +/interface wireguard +add disabled=yes listen-port=33033 mtu=1360 name=NUC +add comment=WG listen-port=13231 mtu=1320 name=WG +/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 +/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}" +/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=static 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=ether4 list=WAN +add interface="ether1 - Unet" list=Internet +add interface=WG list=WAN +add interface=Bridge-LAN list=LAN +/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=10.10.0.1/24 client-address=10.10.0.2/32 \ + client-allowed-address=0.0.0.0/0 client-dns=8.8.8.8 client-endpoint=\ + 10.30.30.81 client-keepalive=10s client-listen-port=22022 disabled=yes \ + endpoint-address=10.30.30.10 endpoint-port=22022 interface=NUC name=\ + MicroNuc persistent-keepalive=10s public-key=\ + "oieVxNCDa4G5LU2QVH+s4AXwapSmdiDvVVhBS/FPdTA=" responder=yes +/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=10.10.0.1/30 disabled=yes interface=NUC network=10.10.0.0 +/ip cloud +set update-time=no +/ip dhcp-client +add add-default-route=special-classless default-route-distance=2 \ + default-route-tables=main:1 dhcp-options=clientid,clientid_duid \ + interface="ether1 - Unet" name=client1 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.4.4,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 disabled=yes 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.30.30.10 list=AWG-Proxy +/ip firewall filter +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=12h chain=input comment="block honeypot DNS" \ + connection-state=new dst-port=53 in-interface="ether1 - Unet" protocol=\ + udp 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="ether1 - Unet" 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="ether1 - Unet" protocol=tcp src-address-list=!TRUSTED +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=4w2d chain=input comment="block honeypot asterisk" \ + connection-state=new dst-port=5060 in-interface="ether1 - Unet" protocol=\ + udp +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=4w2d chain=input comment="block honeypot NTP" \ + connection-state=new dst-port=123 in-interface="ether1 - Unet" 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 disabled=yes dst-port=29185 in-interface=\ + "ether1 - Unet" protocol=tcp +add action=accept chain=input disabled=yes dst-port=29185 in-interface=\ + "ether1 - Unet" 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="ether1 - Unet" protocol=udp \ + src-port=13231 +add action=accept chain=output disabled=yes dst-address-list=VPN-Server \ + dst-port=29185 out-interface="ether1 - Unet" 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 +add action=drop chain=forward comment="defconf: drop invalid" \ + connection-state=invalid in-interface="ether1 - Unet" 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="ether1 - Unet" src-address-list=\ + !VDSina +add action=drop chain=forward comment=\ + "Filter Rule to block FB address LIST : )" disabled=yes dst-address-list=\ + facebook +add action=drop chain=forward comment=\ + "Filter Rule to block YOUTUBE address LIST : )" disabled=yes \ + dst-address-list=YouTube +add action=accept chain=input in-interface="ether1 - Unet" protocol=icmp \ + src-address-list=VDSina +add action=accept chain=input connection-state=established disabled=yes +add action=accept chain=input connection-state=related disabled=yes +/ip firewall mangle +add action=mark-routing chain=prerouting comment="Mark Routing main for NoWG" \ + new-routing-mark=main src-address-list=NoWG +add action=mark-routing chain=prerouting comment=\ + "Mark Routing main for NoVdsina" dst-address-list=NoVdsina \ + new-routing-mark=main src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=\ + "Mark Routing main for VDSina" dst-address-list=VPN-Server \ + new-routing-mark=main 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="AWG for All sites" \ + disabled=yes dst-address=!10.30.30.0/24 dst-address-list=!NoVdsina \ + new-routing-mark=*401 routing-mark=!main src-address=10.30.30.0/24 \ + src-address-list=!NoWG +add action=mark-routing chain=prerouting comment="VDSIna for All sites" \ + dst-address=!10.30.30.0/24 dst-address-list=!NoVdsina new-routing-mark=\ + To-VPN routing-mark=!main src-address=10.30.30.0/24 src-address-list=\ + !NoWG +add action=mark-connection chain=prerouting comment=\ + "Mark VPN connections to exclude from FastTrack" new-connection-mark=\ + VPN_No_FastTrack routing-mark=To-VPN +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-routing chain=prerouting comment="VPN Network" dst-address=\ + 10.8.0.0/24 new-routing-mark=To-VPN src-address=10.30.30.0/24 +/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=dst-nat chain=dstnat comment=\ + "53/tcp dst-nat to amster.loc. From VDSina Server" dst-port=53 \ + in-interface="ether1 - Unet" 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=\ + "ether1 - Unet" protocol=udp src-address=!10.30.30.0/24 to-addresses=\ + 10.30.30.33 to-ports=44333 +add action=masquerade chain=srcnat comment="Default NAT" out-interface=\ + "ether1 - Unet" routing-mark=!To-VPN src-address=10.30.30.0/24 +add action=dst-nat chain=dstnat comment=amster.vados.ruhttps dst-port=443 \ + fragment=no in-interface="ether1 - Unet" 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="ether1 - Unet" 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="ether1 - Unet" 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="ether1 - Unet" 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="ether1 - Unet" protocol=tcp to-addresses=10.30.30.33 \ + to-ports=2377 +add action=dst-nat chain=dstnat comment=npm dst-port=81 in-interface=\ + "ether1 - Unet" 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=\ + "ether1 - Unet" 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="ether1 - Unet" protocol=tcp to-addresses=\ + 10.30.30.33 to-ports=2377 +add action=dst-nat chain=dstnat disabled=yes dst-port=22 in-interface=\ + "ether1 - Unet" protocol=tcp routing-mark=!To-VPN to-addresses=\ + 10.30.30.33 to-ports=22 +add action=masquerade chain=srcnat comment=WG dst-address-list=!NoVdsina \ + out-interface=WG routing-mark=To-VPN src-address-list=!NoWG +add action=dst-nat chain=dstnat comment="Yandex.DNS Family" disabled=yes \ + dst-port=53 in-interface=Bridge-LAN protocol=udp src-address-list=KIDS \ + time=6h-15m,sun,mon,tue,wed,thu,fri,sat to-addresses=77.88.8.3 +add action=dst-nat chain=dstnat disabled=yes dst-port=53 in-interface=\ + Bridge-LAN protocol=tcp src-address-list=KIDS time=\ + 6h-15m,sun,mon,tue,wed,thu,fri,sat to-addresses=77.88.8.3 +/ip firewall raw +add action=drop chain=prerouting comment="Drop Honeypot Hackers" \ + in-interface="ether1 - Unet" src-address-list="Honeypot Hacker" +add action=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 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="ether1 - Unet" 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="" +/user aaa +set accounting=no diff --git a/MikroMaster/20260703/20260703160002-Config.rsc b/MikroMaster/20260703/20260703160002-Config.rsc new file mode 100644 index 0000000..be0fd25 --- /dev/null +++ b/MikroMaster/20260703/20260703160002-Config.rsc @@ -0,0 +1,3687 @@ +# 2026-07-03 16:00:05 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="WAN - Unet" loop-protect=off name=\ + "ether1 - Unet" 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 +set [ find default-name=wlan1 ] country=belarus mode=ap-bridge ssid=vados \ + wireless-protocol=802.11 +# managed by CAPsMAN +set [ find default-name=wlan2 ] country=belarus mode=ap-bridge ssid=vados5g \ + wireless-protocol=802.11 +/interface wireguard +add disabled=yes listen-port=33033 mtu=1360 name=NUC +add comment=WG disabled=yes listen-port=13231 mtu=1320 name=WG +/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 +/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}" +/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="ether1 - Unet" list=Internet +add interface=WG list=WAN +add interface=Bridge-LAN list=LAN +/interface wireguard peers +add allowed-address=0.0.0.0/0 client-allowed-address=::/0 disabled=yes \ + 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=10.10.0.1/24 client-address=10.10.0.2/32 \ + client-allowed-address=0.0.0.0/0 client-dns=8.8.8.8 client-endpoint=\ + 10.30.30.81 client-keepalive=10s client-listen-port=22022 disabled=yes \ + endpoint-address=10.30.30.10 endpoint-port=22022 interface=NUC name=\ + MicroNuc persistent-keepalive=10s public-key=\ + "oieVxNCDa4G5LU2QVH+s4AXwapSmdiDvVVhBS/FPdTA=" responder=yes +/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 disabled=yes interface=WG network=10.8.0.0 +/ip cloud +set update-time=no +/ip dhcp-client +add add-default-route=special-classless default-route-distance=2 \ + default-route-tables=main:2 dhcp-options=clientid,clientid_duid \ + interface="ether1 - Unet" name=client1 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.4.4,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.30.30.10 list=AWG-Proxy +/ip firewall filter +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=12h chain=input comment="block honeypot DNS" \ + connection-state=new dst-port=53 in-interface="ether1 - Unet" protocol=\ + udp 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="ether1 - Unet" 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="ether1 - Unet" protocol=tcp src-address-list=!TRUSTED +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=4w2d chain=input comment="block honeypot asterisk" \ + connection-state=new dst-port=5060 in-interface="ether1 - Unet" protocol=\ + udp +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=4w2d chain=input comment="block honeypot NTP" \ + connection-state=new dst-port=123 in-interface="ether1 - Unet" protocol=\ + udp +add action=fasttrack-connection chain=forward comment=\ + "FastTrack for non-VPN connections" connection-mark=!VPN_No_FastTrack \ + connection-state=established,related,new +add action=accept chain=input dst-port=29185 in-interface="ether1 - Unet" \ + protocol=tcp +add action=accept chain=input dst-port=29185 in-interface="ether1 - Unet" \ + 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="ether1 - Unet" protocol=udp \ + src-port=13231 +add action=accept chain=output disabled=yes dst-address-list=VPN-Server \ + dst-port=29185 out-interface="ether1 - Unet" 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 +add action=drop chain=forward comment="defconf: drop invalid" \ + connection-state=invalid in-interface="ether1 - Unet" 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="ether1 - Unet" src-address-list=\ + !VDSina +add action=accept chain=input in-interface="ether1 - Unet" 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=mark-routing chain=prerouting comment="Mark Routing main for NoWG" \ + disabled=yes new-routing-mark=main 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 src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=\ + "Mark Routing main for VDSina" disabled=yes dst-address-list=VPN-Server \ + new-routing-mark=main 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="VDSIna for All sites" \ + disabled=yes dst-address-list=!NoVdsina new-routing-mark=To-VPN \ + routing-mark=!main src-address=10.30.30.0/24 src-address-list=!NoWG +add action=change-mss chain=forward comment="MSS on WG" disabled=yes 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 +/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=dst-nat chain=dstnat comment=\ + "53/tcp dst-nat to amster.loc. From VDSina Server" dst-port=53 \ + in-interface="ether1 - Unet" 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=\ + "ether1 - Unet" protocol=udp src-address=!10.30.30.0/24 to-addresses=\ + 10.30.30.33 to-ports=44333 +add action=masquerade chain=srcnat comment="Default NAT" out-interface=\ + "ether1 - Unet" routing-mark=!To-VPN src-address=10.30.30.0/24 +add action=dst-nat chain=dstnat comment=amster.vados.ruhttps dst-port=443 \ + fragment=no in-interface="ether1 - Unet" 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="ether1 - Unet" 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="ether1 - Unet" 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="ether1 - Unet" 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="ether1 - Unet" protocol=tcp to-addresses=10.30.30.33 \ + to-ports=2377 +add action=dst-nat chain=dstnat comment=npm dst-port=81 in-interface=\ + "ether1 - Unet" 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=\ + "ether1 - Unet" 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="ether1 - Unet" protocol=tcp to-addresses=\ + 10.30.30.33 to-ports=2377 +add action=dst-nat chain=dstnat disabled=yes dst-port=22 in-interface=\ + "ether1 - Unet" protocol=tcp routing-mark=!To-VPN to-addresses=\ + 10.30.30.33 to-ports=22 +add action=masquerade chain=srcnat comment=WG dst-address-list=!NoVdsina \ + out-interface=WG routing-mark=To-VPN src-address-list=!NoWG +add action=dst-nat chain=dstnat comment="Yandex.DNS Family" disabled=yes \ + dst-port=53 in-interface=Bridge-LAN protocol=udp src-address-list=KIDS \ + time=6h-15m,sun,mon,tue,wed,thu,fri,sat to-addresses=77.88.8.3 +add action=dst-nat chain=dstnat disabled=yes dst-port=53 in-interface=\ + Bridge-LAN protocol=tcp src-address-list=KIDS time=\ + 6h-15m,sun,mon,tue,wed,thu,fri,sat to-addresses=77.88.8.3 +/ip firewall raw +add action=drop chain=prerouting comment="Drop Honeypot Hackers" \ + in-interface="ether1 - Unet" src-address-list="Honeypot Hacker" +add action=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 disabled=yes 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="ether1 - Unet" 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="" +/user aaa +set accounting=no -- 2.52.0