From 988b7472d6069e4dec862c903d338f460a0c7be1 Mon Sep 17 00:00:00 2001 From: vados-dev Date: Wed, 15 Jul 2026 06:21:19 +0300 Subject: [PATCH] Backup for MikroGig created successfully at Jul 15 06:21:19. --- .../20260715/20260715062115-Binary.backup | Bin 0 -> 194200 bytes MikroGig/20260715/20260715062115-Config.rsc | 3337 ++++++++++++++ .../20260715/20260715062115-Diff-Config.rsc | 4 + .../20260714/20260714234001-Config.rsc | 3821 +++++++++++++++++ 4 files changed, 7162 insertions(+) create mode 100644 MikroGig/20260715/20260715062115-Binary.backup create mode 100644 MikroGig/20260715/20260715062115-Config.rsc create mode 100644 MikroGig/history/20260715/20260715062115-Diff-Config.rsc create mode 100644 MikroMaster/20260714/20260714234001-Config.rsc diff --git a/MikroGig/20260715/20260715062115-Binary.backup b/MikroGig/20260715/20260715062115-Binary.backup new file mode 100644 index 0000000000000000000000000000000000000000..760ab99812feeb7ee58d22124646678c0a1fcabc GIT binary patch literal 194200 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 tttZlNbJ;UjW;g$a!8\"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" +add comment=awgVDSina dont-require-permissions=no name=awgVDSina-uninstall \ + owner=Manager policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="\ + \r\ + \n :put \"Uninstalling AmneziaWG...\"\r\ + \n :log info \"Uninstalling AmneziaWG...\"\r\ + \n /ip/route/remove [find where comment=awgVDSina-tunnel]\r\ + \n :do { /tool/netwatch/remove [find where comment=Monitor-AWGVDSINA] } o\ + n-error={}\r\ + \n :do { /ip/route/remove [find where comment=Monitor-AWGVDSINA] } on-err\ + or={}\r\ + \n /container/stop [find where interface=veth-awgVDSina]\r\ + \n :delay 7s\r\ + \n /interface/list/member/remove [find where interface=wg-awgVDSina]\r\ + \n /container/remove [find where interface=veth-awgVDSina]\r\ + \n /container/envs/remove [find where list=\"awgVDSina-env\"]\r\ + \n /ip/firewall/nat/remove [find where out-interface=\"wg-awgVDSina\"]\r\ + \n /ip/address/remove [find where address=\"172.20.0.1/30\"]\r\ + \n /interface/veth/remove [find where name=\"veth-awgVDSina\"]\r\ + \n /interface/wireguard/peers/remove [find where interface=\"wg-awgVDSina\ + \"]\r\ + \n /ip/address/remove [find where interface=\"wg-awgVDSina\"]\r\ + \n /interface/wireguard/remove [find where name=\"wg-awgVDSina\"]\r\ + \n :do { /file/remove [find where name~\"awgVDSina.+tar\"] } on-error={}\ + \r\ + \n :do { /file/remove [find where name=\"disk1/awgVDSina\"] } on-error={}\ + \r\ + \n :put \"Uninstall AmneziaWG Proxy complete!\"\r\ + \n :log info \"Uninstall AmneziaWG Proxy complete!\"\r\ + \n /system/script/remove [find where name=awgVDSina-uninstall]\r\ + \n" +/user group +add name=backup policy="telnet,ssh,ftp,read,write,policy,test,sniff,sensitive,\ + !local,!reboot,!winbox,!password,!web,!api,!romon,!rest-api" +/container config +set layer-dir=/usb1/docker memory-high=200.0MiB memory-max=2048.0KiB \ + registry-url=https://registry-1.docker.io tmpdir=/usb1/pull username=\ + amsternl +/disk settings +set auto-media-interface=lo +/interface bridge port +add bridge=Bridge-LAN interface=ether2 +add bridge=Bridge-LAN interface=ether3 +add bridge=Bridge-LAN interface=ether4 +add bridge=Bridge-LAN interface=ether5 +add bridge=Bridge-LAN interface=wlan2 +add bridge=Bridge-LAN interface=wlan1 +add bridge=Bridge-LAN interface=ether1 +/ip neighbor discovery-settings +set discover-interface-list=Internet +/ipv6 settings +set allow-fast-path=no disable-ipv6=yes disable-link-local-address=yes \ + forward=no +/interface detect-internet +set detect-interface-list=WAN internet-interface-list=Internet \ + lan-interface-list=LAN wan-interface-list=WAN +/interface list member +add interface=ether2 list=LAN +add interface=ether3 list=LAN +add interface=ether4 list=LAN +add interface=ether5 list=LAN +add interface=wlan2 list=LAN +add interface=wlan1 list=LAN +add interface=ether1 list=Internet +add interface=Bridge-LAN list=LAN +/interface wireguard peers +add allowed-address=0.0.0.0/0,::/0 disabled=yes endpoint-address=172.20.0.2 \ + endpoint-port=51820 interface=wg-awgVDSina name=awgVDSina \ + persistent-keepalive=27s public-key=\ + "o5IgCl1/G6xbl6j7sPaP4ZNYREeYOmqZjKbm+v0b9jU=" +/interface wireless cap +# +set bridge=Bridge-LAN caps-man-addresses=10.30.30.10 \ + caps-man-certificate-common-names=CAPsMAN-51B25E507D07 certificate=\ + CAP-18FD746E5814 discovery-interfaces=Bridge-LAN enabled=yes interfaces=\ + wlan1,wlan2 lock-to-caps-man=yes +/ip address +add address=10.30.30.86/24 interface=Bridge-LAN network=10.30.30.0 +add address=172.20.0.1/30 interface=veth-awgVDSina network=172.20.0.0 +add address=10.9.0.2 interface=wg-awgVDSina network=10.9.0.2 +/ip dns +set allow-remote-requests=yes servers=8.8.8.8 +/ip firewall nat +add action=masquerade chain=srcnat src-address=10.9.9.0/24 +add action=dst-nat chain=dstnat disabled=yes dst-port=443 in-interface=ether1 \ + protocol=udp to-addresses=10.9.9.2 to-ports=55055 +add action=dst-nat chain=dstnat disabled=yes dst-port=9443 in-interface=\ + ether1 protocol=tcp to-addresses=10.9.9.2 to-ports=443 +/ip firewall service-port +set ftp disabled=yes +set tftp disabled=yes +set irc disabled=no +set sip disabled=yes +set pptp disabled=yes +set rtsp disabled=no +/ip hotspot walled-garden +add server=*1 +add server=*1 +/ip ipsec settings +set accounting=no +/ip ipsec policy +set 0 disabled=yes dst-address=0.0.0.0/0 src-address=0.0.0.0/0 +/ip ipsec profile +set [ find default=yes ] dpd-interval=2m dpd-maximum-failures=5 +/ip proxy +set cache-administrator="" max-cache-size=none port=80,443 src-address=\ + 0.0.0.0 +/ip route +add check-gateway=ping disabled=no distance=2 dst-address=0.0.0.0/0 gateway=\ + 10.30.30.81 routing-table=main scope=30 target-scope=10 +add comment=Monitor-AWGVDSINA distance=1 dst-address=9.9.9.9/32 gateway=\ + wg-awgVDSina +/ip service +set ftp disabled=yes +set telnet disabled=yes +set ssh address=10.30.30.0/24 port=2222 +set winbox address=10.30.30.0/24 +set api address=10.30.30.0/24 disabled=yes +set api-ssl address=10.30.30.0/24 disabled=yes +set www-ssl port=18443 +set www address=10.30.30.0/24 disabled=yes port=18880 +/ip service webserver +set graphs-plain=no rest-plain=no webfig-plain=no +/ip ssh +set forwarding-enabled=both publickey-authentication-options=verify-required \ + strong-crypto=yes +/ip upnp +set enabled=yes +/ip upnp interfaces +add interface=Bridge-LAN type=internal +add forced-ip=109.107.177.79 interface=veth-awgVDSina type=external +add interface=lo type=internal +add interface=wlan2 type=internal +add interface=wlan1 type=internal +/ipv6 nd +set [ find default=yes ] advertise-dns=yes +/system clock +set time-zone-name=Europe/Moscow +/system clock manual +set time-zone=+03:00 +/system identity +set name=MikroGig +/system logging +add action=email disabled=yes regex="* added|changed|removed *" topics=\ + system,info +/system ntp client +set enabled=yes +/system ntp server +set enabled=yes manycast=yes multicast=yes use-local-clock=yes +/system ntp client servers +add address=10.30.30.81 +add address=10.30.30.10 +add address=0.ru.pool.ntp.org +add address=1.ru.pool.ntp.org +add address=2.ru.pool.ntp.org +add address=3.ru.pool.ntp.org +add address=time.google.com disabled=yes +/system scheduler +add comment="Every Day Set Global Environment Variables" name=AM-SetGlobalEnv \ + on-event="/system/script { run AM-GlobalConfig; run AM-GlobalFunc; }" \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-time=startup +add comment="Every Day Check For Update Scripts" interval=1d name=\ + AM-ScriptInstallUpdate on-event=\ + ":global ScriptInstallUpdate; \$ScriptInstallUpdate;" policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-time=startup +add comment=Generator name=awg-VDSina on-event="# ============================\ + ================================\r\ + \n# AWG Proxy -- MikroTik RouterOS (protocol: v2)\r\ + \n# 2026-07-01 00:03:43\r\ + \n# ============================================================\r\ + \n\r\ + \n# 0. Check prerequisites\r\ + \n:if ([:len [/system/package/find where name=\"container\" disabled=no]] \ + = 0) do={\r\ + \n :put \"Container package is not installed or disabled. Install it and \ + reboot.\"\r\ + \n :error \"Usage: /system/device-mode/update container=yes\"\r\ + \n}\r\ + \n\r\ + \n# Auto-detect storage\r\ + \n:global awgDisk \"disk1\"\r\ + \n{\r\ + \n :local usbFree 0\r\ + \n :do { :set usbFree [/disk/get [find where mount-point=\"usb1\"] free] \ + } on-error={}\r\ + \n :if (\$usbFree > 0) do={\r\ + \n :set awgDisk \"usb1\"\r\ + \n :put (\"Using USB: usb1 (\" . (\$usbFree / 1048576) . \" MB free)\")\ + \r\ + \n } else={\r\ + \n :if ([:len [/disk/find where slot=\"usb1\"]] > 0) do={\r\ + \n :put \"USB found but not mounted. Format as ext4\?\"\r\ + \n :put \"Press 'y' to confirm:\"\r\ + \n :local key [/terminal/inkey timeout=30]\r\ + \n :if (\$key = 121 || \$key = 89) do={\r\ + \n /disk/format-drive usb1 file-system=ext4 label=usb1\r\ + \n :delay 3s\r\ + \n :do { :set usbFree [/disk/get [find where mount-point=\"usb1\"] \ + free] } on-error={}\r\ + \n :if (\$usbFree > 0) do={\r\ + \n :set awgDisk \"usb1\"\r\ + \n } else={ :put \"Format failed, using disk1\" }\r\ + \n } else={ :put \"Using disk1\" }\r\ + \n } else={ :put \"No USB, using disk1\" }\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n# 1. Uninstall script\r\ + \n/system/script/add name=awg-VDSina-uninstall comment=awg-VDSina source={\ + \r\ + \n :put \"Uninstallimg AmneziaWG...\"\r\ + \n :log info \"Uninstallimg AmneziaWG...\"\r\ + \n :local prevDNS \"\"\r\ + \n :do { :set prevDNS [/container/envs/get [find where list=\"awg-VDSina-\ + env\" key=\"AWG_PREV_DNS\"] value] } on-error={}\r\ + \n :local storageDisk \"disk1\"\r\ + \n :do { :set storageDisk [/container/envs/get [find where list=\"awg-VDS\ + ina-env\" key=\"AWG_STORAGE\"] value] } on-error={}\r\ + \n :local prevTmpdir \"\"\r\ + \n :if (\$storageDisk != \"disk1\") do={\r\ + \n :do { :set prevTmpdir [/container/envs/get [find where list=\"awg-VD\ + Sina-env\" key=\"AWG_PREV_TMPDIR\"] value] } on-error={}\r\ + \n }\r\ + \n /ip/route/remove [find where comment=awg-VDSina-tunnel]\r\ + \n /ip/route/remove [find where comment=awg-VDSina-dns]\r\ + \n /container/stop [find where interface=veth-awg-VDSina]\r\ + \n :delay 7s\r\ + \n /container/remove [find where interface=veth-awg-VDSina]\r\ + \n /container/envs/remove [find where list=\"awg-VDSina-env\"]\r\ + \n :if (\$prevDNS != \"\") do={\r\ + \n :do { /ip/dns/set servers=\"\$prevDNS\" } on-error={}\r\ + \n :put (\"DNS restored to: \$prevDNS\")\r\ + \n }\r\ + \n :if (\$storageDisk != \"disk1\") do={\r\ + \n /container/config set tmpdir=\$prevTmpdir\r\ + \n :put (\"Container tmpdir restored to: \$prevTmpdir\")\r\ + \n }\r\ + \n /ip/firewall/nat/remove [find where out-interface=\"wg-awg-VDSina\"]\r\ + \n /ip/firewall/nat/remove [find where src-address=\"172.19.75.208/30\"]\ + \r\ + \n /ip/address/remove [find where address=\"172.19.75.209/30\"]\r\ + \n /interface/veth/remove [find where name=\"veth-awg-VDSina\"]\r\ + \n /interface/wireguard/peers/remove [find where interface=\"wg-awg-VDSin\ + a\"]\r\ + \n /ip/address/remove [find where interface=\"wg-awg-VDSina\"]\r\ + \n /interface/wireguard/remove [find where name=\"wg-awg-VDSina\"]\r\ + \n :do { /file/remove [find where name~\"awg-VDSina.+tar\"] } on-error={}\ + \r\ + \n :do { /file/remove [find where name=(\$storageDisk . \"/awg-VDSina\")]\ + \_} on-error={}\r\ + \n :do { /file/remove [find where name=(\$storageDisk . \"/ru_ranges_time\ + out.rsc\")] } on-error={}\r\ + \n :if (\$storageDisk != \"disk1\") do={\r\ + \n :do { /file/remove [find where name~(\$storageDisk . \"/pull\")] } o\ + n-error={}\r\ + \n }\r\ + \n :put \"Uninstall AmneziaWG Proxy complete!\"\r\ + \n :log info \"Uninstall AmneziaWG Proxy complete!\"\r\ + \n /system/script/remove [find where name=awg-VDSina-uninstall]\r\ + \n}\r\ + \n\r\ + \n# 2. Network infrastructure\r\ + \n/interface/veth/add name=veth-awg-VDSina address=172.19.75.210/30 gatewa\ + y=172.19.75.209\r\ + \n/ip/address/add address=172.19.75.209/30 interface=veth-awg-VDSina\r\ + \n/ip/firewall/nat/add chain=srcnat action=masquerade src-address=172.19.7\ + 5.208/30\r\ + \n\r\ + \n# 3. WireGuard interface (MikroTik derives the public key automatically)\ + \r\ + \n/interface/wireguard/add name=wg-awg-VDSina private-key=\"QCMsDU98Gm+nhn\ + kYRcAN/dyczDYHOLsX3PfBRFjWBF4=\" listen-port=14710 disabled=yes\r\ + \n/interface/wireguard/peers/add interface=wg-awg-VDSina public-key=\"o5Ig\ + Cl1/G6xbl6j7sPaP4ZNYREeYOmqZjKbm+v0b9jU=\" preshared-key=\"b39T9K2/LR8vNtY\ + AZw+sLRze6yGlS3EaZhAa7wiFB20=\" endpoint-address=172.19.75.210 endpoint-po\ + rt=51820 allowed-address=0.0.0.0/0 persistent-keepalive=10\r\ + \n/ip/address/add address=10.9.0.2/32 interface=wg-awg-VDSina\r\ + \n\r\ + \n# 4. Container environment variables\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_LISTEN value=\":51820\"\ + \r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_REMOTE value=\"109.107.1\ + 77.79:55055\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_JC value=\"9\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_JMIN value=\"105\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_JMAX value=\"920\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_S1 value=\"90\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_S2 value=\"136\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_H1 value=\"472437748-472\ + 438637\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_H2 value=\"707808381-707\ + 809250\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_H3 value=\"1609078552-16\ + 09079495\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_H4 value=\"1012329484-10\ + 12329741\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_SERVER_PUB value=\"o5IgC\ + l1/G6xbl6j7sPaP4ZNYREeYOmqZjKbm+v0b9jU=\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_CLIENT_PUB value=[/inter\ + face/wireguard/get [find name=wg-awg-VDSina] public-key]\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_S3 value=\"45\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_S4 value=\"27\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_I1 value=\"\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_I2 value=\"\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_I3 value=\"\ + \"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_I4 value=\"\"\ + \r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_I5 value=\"\"\r\ + \n\r\ + \n# 5. DNS\r\ + \n{ :local rawDNS [/ip/dns/get servers]; :local prevDNS \"\"; :foreach s i\ + n=[:toarray \$rawDNS] do={ :if ([:len \$prevDNS] > 0) do={ :set prevDNS \"\ + \$prevDNS,\$s\" } else={ :set prevDNS \$s } }; /container/envs/add list=aw\ + g-VDSina-env key=AWG_PREV_DNS value=\"\$prevDNS\" }\r\ + \n# NOTE: replaces existing DNS configuration\r\ + \n/ip/dns/set servers=109.107.177.79\r\ + \n/ip/route/add dst-address=109.107.177.79/32 gateway=wg-awg-VDSina distan\ + ce=1 comment=awg-VDSina-dns\r\ + \n\r\ + \n# 6. Download, create and start container\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_STORAGE value=\$awgDisk\ + \r\ + \n:if (\$awgDisk != \"disk1\") do={\r\ + \n :local tmpPath (\$awgDisk . \"/pull\")\r\ + \n /container/envs/add list=awg-VDSina-env key=AWG_PREV_TMPDIR value=[/co\ + ntainer/config/get tmpdir]\r\ + \n /container/config set tmpdir=\$tmpPath memory-high=200M\r\ + \n}\r\ + \n{\r\ + \n :local arch [/system/resource/get architecture-name]\r\ + \n :local ver [/system/resource/get version]\r\ + \n :local dotPos [:find \$ver \".\"]\r\ + \n :local rest [:pick \$ver (\$dotPos + 1) [:len \$ver]]\r\ + \n :local endPos [:find \$rest \".\"]\r\ + \n :if ([:typeof \$endPos] = \"nil\") do={ :set endPos [:find \$rest \" \ + \"] }\r\ + \n :local minor [:tonum [:pick \$rest 0 \$endPos]]\r\ + \n :local suffix \"\"\r\ + \n :if (\$minor <= 20) do={ :set suffix \"-7.20-Docker\" }\r\ + \n :local file \"\"\r\ + \n :if (\$arch = \"arm64\") do={ :set file (\"awg-proxy-arm64\" . \$suffi\ + x . \".tar.gz\") }\r\ + \n :if (\$arch = \"arm\") do={ :set file (\"awg-proxy-arm\" . \$suffix . \ + \".tar.gz\") }\r\ + \n :if (\$arch ~ \"x86\") do={ :set file (\"awg-proxy-amd64\" . \$suffix \ + . \".tar.gz\") }\r\ + \n :if (\$file = \"\") do={ :error \"Unsupported architecture: \$arch\" }\ + \r\ + \n :local url \"https://github.com/timbrs/amneziawg-mikrotik-c/releases/l\ + atest/download/\$file\"\r\ + \n :local filePath \$file\r\ + \n :if (\$awgDisk != \"disk1\") do={\r\ + \n :set filePath (\$awgDisk . \"/pull/\" . \$file)\r\ + \n :do { /file/make-directory (\$awgDisk . \"/pull\") } on-error={}\r\ + \n }\r\ + \n :if ([:len [/file/find where name=\$filePath]] = 0) do={\r\ + \n :local freeStorage 0\r\ + \n :if (\$awgDisk = \"disk1\") do={\r\ + \n :set freeStorage [/system/resource/get free-hdd-space]\r\ + \n } else={\r\ + \n :do { :set freeStorage [/disk/get [find where mount-point=\$awgDis\ + k] free] } on-error={}\r\ + \n }\r\ + \n :if (\$freeStorage < 262144) do={\r\ + \n :put (\"WARNING: Low disk space (\" . (\$freeStorage / 1024) . \"K\ + B free). Need at least 256KB.\")\r\ + \n :put \"See: https://github.com/timbrs/amneziawg-mikrotik-c#insuffi\ + cient-disk-space\"\r\ + \n :error \"Insufficient disk space\"\r\ + \n }\r\ + \n :put (\"Fetching: \$url -> \" . \$filePath)\r\ + \n /tool/fetch url=\$url dst-path=\$filePath http-max-redirect-count=10\ + \r\ + \n } else={\r\ + \n :put (\"File already exists: \" . \$filePath)\r\ + \n }\r\ + \n :local rootDir (\$awgDisk . \"/awg-VDSina\")\r\ + \n /container/add file=\$filePath interface=veth-awg-VDSina envlist=awg-V\ + DSina-env hostname=awg-VDSina root-dir=\$rootDir logging=no start-on-boot=\ + yes comment=awg-VDSina\r\ + \n :if (\$minor > 20) do={ [:parse \"/container/set [find where interface\ + =veth-awg-VDSina] shm-size=4M\"] }\r\ + \n /file/remove \$filePath\r\ + \n :local freeMem [/system/resource/get free-memory]\r\ + \n :if (\$freeMem < 16777216) do={\r\ + \n :put (\"WARNING: Low memory (\" . (\$freeMem / 1048576) . \"MB free)\ + . 16MB+ recommended.\")\r\ + \n }\r\ + \n /container/start [find where interface=veth-awg-VDSina]\r\ + \n :do { /file/remove [find where name=\"console-dump.txt\"] } on-error={\ + }\r\ + \n :put \"Waiting for container to start...\"\r\ + \n :delay 5s\r\ + \n /interface/wireguard/enable wg-awg-VDSina\r\ + \n :put \"WireGuard interface enabled\"\r\ + \n :put \"Installation complete!\"\r\ + \n :put \"Ping test: 109.107.177.79 via AmneziaWG tunnel. repeat 10 times\ + \"\r\ + \n /ping 109.107.177.79 count=10 interval=1\r\ + \n :put \"\"\r\ + \n :put \"======= NEXT STEPS =======\"\r\ + \n :put \"\"\r\ + \n :put \"Route specific traffic through the AmneziaWG tunnel:\"\r\ + \n :put \"\"\r\ + \n :put \" Route a single host:\"\r\ + \n :put \" /ip/route/add dst-address=8.8.8.8/32 gateway=wg-awg-VDSina \ + comment=awg-VDSina-tunnel\"\r\ + \n :put \"\"\r\ + \n :put \" Route a subnet:\"\r\ + \n :put \" /ip/route/add dst-address=100.0.0.0/8 gateway=wg-awg-VDSina\ + \_comment=awg-VDSina-tunnel\"\r\ + \n :put \"\"\r\ + \n :put \" Remove a route:\"\r\ + \n :put \" /ip/route/remove [find where comment=awg-VDSina-tunnel dst-\ + address=8.8.8.8/32]\"\r\ + \n :put \"\"\r\ + \n :put \" Show all tunnel routes:\"\r\ + \n :put \" /ip/route/print where comment=awg-VDSina-tunnel\"\r\ + \n :put \"\"\r\ + \n :put \" Uninstall:\"\r\ + \n :put \" /system/script/run awg-VDSina-uninstall\"\r\ + \n :put \"=========================\"\r\ + \n}\r\ + \n\r\ + \n# 7. Verification\r\ + \n# /container/print\r\ + \n# /interface/wireguard/print\r\ + \n# /interface/wireguard/peers/print\r\ + \n" policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-date=2026-07-01 start-time=02:03:59 +/tool e-mail +set certificate-verification=no from=MikroVados port=587 \ + server=smtp.mail.me.com tls=starttls user=vadossio@icloud.com +/tool netwatch +add comment=Monitor-AWGVDSINA down-script=\ + "/ip route disable [find comment=\"Route-AWGVDSINA\"]" host=9.9.9.9 \ + interval=10s packet-count=5 thr-avg=0ms thr-loss-count=4 timeout=5s type=\ + icmp up-script="/ip route enable [find comment=\"Route-AWGVDSINA\"]" diff --git a/MikroGig/history/20260715/20260715062115-Diff-Config.rsc b/MikroGig/history/20260715/20260715062115-Diff-Config.rsc new file mode 100644 index 0000000..1d29d96 --- /dev/null +++ b/MikroGig/history/20260715/20260715062115-Diff-Config.rsc @@ -0,0 +1,4 @@ +15c15 +< # channel: 5200/20-eCee/ac/P(20dBm), SSID: vados5g, local forwarding +--- +> # channel: 5260/20-Ceee/ac/DP(17dBm), SSID: vados5g, local forwarding diff --git a/MikroMaster/20260714/20260714234001-Config.rsc b/MikroMaster/20260714/20260714234001-Config.rsc new file mode 100644 index 0000000..e013733 --- /dev/null +++ b/MikroMaster/20260714/20260714234001-Config.rsc @@ -0,0 +1,3821 @@ +# 2026-07-14 23:40:04 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 ] advertise="10M-baseT-half,10M-baseT-full,100M\ + -baseT-half,100M-baseT-full,1G-baseT-full,1G-baseX" comment=Unet-cable \ + loop-protect=on name=Unet-ether1 rx-flow-control=auto tx-flow-control=\ + auto +set [ find default-name=ether2 ] comment=LAN-2 +set [ find default-name=ether3 ] advertise="10M-baseT-half,10M-baseT-full,100M\ + -baseT-half,100M-baseT-full,1G-baseT-full,1G-baseX" comment=LAN-3 +set [ find default-name=ether4 ] comment=LAN-4 +set [ find default-name=ether5 ] advertise="10M-baseT-half,10M-baseT-full,100M\ + -baseT-half,100M-baseT-full,1G-baseT-full,1G-baseX" comment=LAN-5 \ + loop-protect=on poe-out=off rx-flow-control=auto tx-flow-control=auto +/interface wireless +set [ find default-name=wlan1 ] country=belarus disabled=no mode=ap-bridge \ + ssid=vados wireless-protocol=802.11 +set [ find default-name=wlan2 ] country=belarus disabled=no mode=ap-bridge \ + ssid=vados5g wireless-protocol=802.11 +/interface wireguard +add comment=WG disabled=yes listen-port=13231 mtu=1360 name=WG +add comment="WG interface for Amnezia route" disabled=yes listen-port=33033 \ + mtu=1360 name=wg-nuc +/interface list +add include=static name=LAN +add name=Internet +/interface wireless security-profiles +set [ find default=yes ] authentication-types=wpa-psk,wpa2-psk mode=\ + dynamic-keys supplicant-identity=MikroTik +/iot wiliot servers +set *1 address=mqtt.us-east-2.prod.wiliot.cloud name="Wiliot US East" +/ip dhcp-server option +add code=12 name=HostName +add code=119 force=yes name=domain-search-list value="0x03'WORKGROUP'0x00" +/ip dhcp-server option sets +add name=HP1505n options=HostName +add name=StartLife1 options=HostName +add name=amsterDev options=HostName +add name=MiTV options=HostName +add name=miller options=HostName +add name=amster options=HostName +add name=garage options=HostName +add name=domain-search-set options=domain-search-list +add name=VADOS-LEN options=HostName +add name=VADOS-NUC options=HostName +add name=MikroNUC options=HostName +add name=master options=HostName +add name=MikroYellow options=HostName +add name="=\"Client ID\"" options=HostName +add name=iVados options=HostName +/ip dns forwarders +add disabled=yes dns-servers=1.0.0.1,1.1.1.1 name=blsp.at verify-doh-cert=no +add comment=Kra disabled=yes dns-servers=1.0.0.1,1.1.1.1 name=slon2.to \ + verify-doh-cert=no +add disabled=yes dns-servers=1.1.1.1,1.0.0.1 name=slon3.at verify-doh-cert=no +add disabled=yes dns-servers=1.0.0.1,1.1.1.1 name=slon3.cc verify-doh-cert=no +add disabled=yes dns-servers=1.1.1.1,1.0.0.1 name=bs2web.at verify-doh-cert=\ + no +add disabled=yes dns-servers=1.1.1.1,1.0.0.1 name=bs2best.at verify-doh-cert=\ + no +add disabled=yes dns-servers=1.0.0.1,1.1.1.1 name=psrms.is verify-doh-cert=no +/ip ipsec proposal +set [ find default=yes ] disabled=yes +/ip pool +add name=dhcp ranges=10.30.30.83-10.30.30.254 +/ip dhcp-server +add add-arp=yes address-pool=dhcp always-broadcast=yes bootp-support=none \ + dhcp-option-set=domain-search-set interface=Bridge-LAN lease-time=10m \ + name=masterDHCP server-address=10.30.30.81 +/ip smb users +set [ find default=yes ] disabled=yes +add disabled=yes name=vados +/ipv6 dhcp-client option +add code=119 name=domain-search-list value="0x03'WORKGROUP'0x00" +add code=12 name=HostName value="\$(HOSTNAME)" +add code=61 name=DUID value=0x00030001488f5a8e1abc +add code=61 name=clientid +/ipv6 dhcp-server option +add code=119 name=domain-search-list value="0x03'WORKGROUP'0x00" +add code=12 name=HostName value="\$(HOSTNAME)" +add code=61 name=CLIENT_DUID +add code=61 name=CLIENT_MAC +/ppp profile +set *FFFFFFFE use-upnp=no +/routing bgp template +set default disabled=no output.network=bgp-networks +/routing table +add disabled=no fib name=To-VPN +add disabled=yes name=r_to_vpn +/system logging action +add email-start-tls=yes email-to=vados@vados.ru name=email target=email +/system script +add dont-require-permissions=no name=fetchCustom owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + global GlobalScriptsUrl \"https://ros.vados.ru/\";\r\ + \n\r\ + \n#/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@1\ + 0.30.30.86.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.86.pub\";\ + \n\r\ + \n#:local Script AM-setup\ + \n;\r\ + \n#/system/script/add name=\$Script owner=\$Script source=([ /tool/fetch c\ + heck-certificate=yes-without-crl url=(\$GlobalScriptsUrl . \$Script . \".r\ + sc\") output=user as-value ]->\"data\");\r\ + \n\ + \n#/usb1/mikro_bak_rsa.pub\ + \n\ + \n\r\ + \n#\ + \n\r\ + \n#/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@1\ + 0.30.30.10.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.10.pub\";\ + \n\r\ + \n#\r\ + \n\ + \n#root.mnuc.backuper\ + \n\ + \n\r\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@10\ + .30.30.81.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.81.pub\";\r\ + \n\ + \n#:local Script AM-GlobalConfig;\ + \n\r\ + \n#/system/script/add name=\$Script owner=\$Script source=([ /tool/fetch c\ + heck-certificate=yes-without-crl url=(\$GlobalScriptsUrl . \$Script . \".r\ + sc\") output=user as-value ]->\"data\");\r\ + \n\ + \n#/usb1/mikro_bak_rsa.pub\ + \n#:local FetchFile AM-DOHCert.rsc\ + \n\ + \n\r\ + \n\r\ + \n#\ + \n:global MkDir;\ + \n\r\ + \n\ + \n#:local FetchFile Binary.backup\ + \n:local localDir \"\";\ + \n\ + \n\r\ + \n#\$MkDir \$localDir;\r\ + \n\ + \n#\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \$FetchFile) dst-path=(\ + \$localDir . \$FetchFile);\r\ + \n" +add comment="Global Config Script" dont-require-permissions=no name=\ + AM-GlobalConfig owner=AM-GlobalConfig policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\r\ + \n# RouterOS script: AM-GlobalConfig\r\ + \n# Script comment: Global Config Script\r\ + \n# Copyright (c) 2007-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# Warning: Dont touch this line!\r\ + \n:global Identity [/system/identity/get name];\r\ + \n:global GlobalConfReady false;\r\ + \n#\r\ + \n#\r\ + \n# Global Url For Amster scripts to fetch\r\ + \n# most be defined in AM-Init-Script or AM-setup scripts\r\ + \n:global GlobalScriptsUrl \"https://ros.vados.ru/\";\r\ + \n:global ScriptsUrlSuffix (a);\r\ + \n:global CheckSumsVerify true;\r\ + \n\r\ + \n:global ScriptUpdatesCRLF true;\r\ + \n:global CommentsInScripts true;\r\ + \n\r\ + \n# Debug output:\r\ + \n:global PrintDebug true; #false;\r\ + \n\r\ + \n# Debug output for specific script:\r\ + \n#:set (\$PrintDebugOverride->\"AM-GlobalFunc\") true;\r\ + \n\r\ + \n# Debug logs\r\ + \n# Other actions (disk, email, remote or support) can be used as well.\r\ + \n# I do not recommend using echo - use debug output instead (https://rsc.\ + eworm.de/main/DEBUG.html#debug-output).\r\ + \n#/system/logging/add topics=script,debug action=memory;\r\ + \n\r\ + \n:global MikrotikUpgradeUrl \"https://upgrade.mikrotik.com/routeros\";\r\ + \n:global Domain \"WORKGROUP\";\r\ + \n\r\ + \n:global EmailGeneralTo \"vados@vados.ru\";\r\ + \n#:global EmailGeneralCc \"\";\r\ + \n\r\ + \n# \$ScriptInstallUpdate mod/notification-telegram\r\ + \n:global TelegramTokenId \"8390868324:AAG3_d1hfVR2M6pGAgDK6ZvhOe4J97nyopw\ + \";\r\ + \n:global TelegramChatId \"-1003631309063\"; #\"454403445\";\r\ + \n# Use this to send notifications to a specific topic in group.\r\ + \n#:global TelegramThreadId \"30\";\r\ + \n# Using telegram-chat you have to define trusted chat ids (not group ids\ + !)\r\ + \n# or user names. Groups allow to chat with devices simultaneously.\r\ + \n:global TelegramChatIdsTrusted {\r\ + \n \"454403445\"\r\ + \n \"-1003631309063\"\r\ + \n \"-5124482807\"\r\ + \n \"1087968824\";\r\ + \n};\r\ + \n# \"-5294757340\";\r\ + \n\r\ + \n:global TelegramChatGroups \"(all)\";\r\ + \n#:global TelegramChatGroups \"(all|home|office)\";\r\ + \n\r\ + \n:global NotificationFunctions {\r\ + \n \"email\"\r\ + \n \"telegram\";\r\ + \n};\r\ + \n# Toggle this to disable symbols in notifications.\r\ + \n:global NotificationsWithSymbols true;\r\ + \n:global TerminalColorOutput true;\r\ + \n\r\ + \n:global DetectIpAddrDefault \"https://ipv4.mikrotik.ovh/\";\r\ + \n:global DetectIpAddrFallback \"https://api.ipify.org/\";\r\ + \n\r\ + \n## Update channel. Possible values: stable, long-term, testing, developm\ + ent\r\ + \n:global updateChannel \"stable\";\r\ + \n\r\ + \n:global CertRenewUrl (\$GlobalScriptsUrl . \"certs/\" . \$Identity . \"/\ + \");\r\ + \n:global CertRenewTime 2w;\r\ + \n:global CertRenewPass (a); #{\r\ + \n# \"\";\r\ + \n# \"v3ry-s3cr3t\";\r\ + \n# \"4n0th3r-s3cr3t\";\r\ + \n#};\r\ + \n:global CertWarnTime 1w;\r\ + \n:global CertIssuedExportPass (a); # {\r\ + \n# \"\";\r\ + \n# \"cert1-cn\"=\"v3ry-s3cr3t\";\r\ + \n# \"cert2-cn\"=\"4n0th3r-s3cr3t\";\r\ + \n#};\r\ + \n\r\ + \n# Script BackupAndUpdate mode, possible values: backup,\r\ + \n# updateOnce - Update once as \"osnotify\" and back \"osnotify\" mode (i\ + n terminal run :set OSUpdateMode updateOnce; \$OSUpdateMode;). \r\ + \n# osupdate - Update if available and creates backups before/after update\ + \_(ignores `forceBackup`)\r\ + \n# Set `forceBackup` to true to always create backups, even\ + \_without updates\r\ + \n# osnotify - Set `forceBackup` to always create backups on every run\r\ + \n:global DevInfoIncludeIP true;\r\ + \n:global BackupAndUpdateMode \"osnotify\"\r\ + \n\r\ + \n:global forceBackup true;\r\ + \n:global BackupPassword \"Peskar55\";\r\ + \n\r\ + \n# SFTP Backup Variables\r\ + \n:global BackupRandomDelay 0;\r\ + \n:global BackupUploadUrl \"sftp://amster.vados.ru/upload/\";\r\ + \n:global BackupUploadUser \$Identity;\r\ + \n:global BackupUploadPass \"root.mnuc.backuper\";\r\ + \n\r\ + \n:global BackupSendBinary true;\r\ + \n:global BackupSendExport true;\r\ + \n:global BackupSendGlobalConfig true;\r\ + \n:global BackupSendScripts true;\r\ + \n\r\ + \n# Remove local file after uploading if no errors\r\ + \n:global BackupRmLocal true;\r\ + \n\r\ + \n# Local Backups Root Directory \r\ + \n:global BackupLocalRoot \"tmpfs\";\r\ + \n\r\ + \n# Encrypt Backup\r\ + \n:global BackupEncrypt true;\r\ + \n\r\ + \n# Sensitive information in Backups\r\ + \n:global BackupSens true;\r\ + \n\r\ + \n# User Export\r\ + \n:global BackupUser true;\r\ + \n\r\ + \n# License Export (not for CHR, will silently skip)\r\ + \n:global BackupLicense false;\r\ + \n\r\ + \n# SSH Keys\r\ + \n:global BackupSshKeys true;\r\ + \n\r\ + \n# Certificate Export\r\ + \n:global BackupCerts true;\r\ + \n\r\ + \n# Certificate Password\r\ + \n:global BackupCertsPasswd \"\";\r\ + \n\r\ + \n# User-Manager Export\r\ + \n:global BackupUserMan false;\r\ + \n\r\ + \n# The Dude Export\r\ + \n:global BackupDude false;\r\ + \n\r\ + \n# User Files to export, comma-separated string or array of strings\r\ + \n# User Files are not removed on backup\r\ + \n# Any directory paths will be removed (/ -> _) on remote file\r\ + \n# Nonpresent files are silently skipped\r\ + \n:global BackupUserList \"autosupout.rif,autosupout.old.rif\";\r\ + \n\r\ + \n# load functions and any custom scripts\r\ + \n# [ /system/script/find where name=\"global-config-ov\ + erlay\" ], \\\r\ + \n# [ /system/script/find where name~\"^global-config-o\ + verlay\\\\.d/.\" ]\r\ + \n#\r\ + \n#:foreach Script in=([ /system/script/find where name=\"Amster-TGglobalV\ + ars\" ], [ /system/script/find where name=\"Amster-TGglobalFunc\" ]) do={\ + \r\ + \n# :onerror Err {\r\ + \n# /system/script/run \$Script;\r\ + \n# } do={\r\ + \n# :log error (\"Loading configuration from configs and functions\"\ + \_. [ /system/script/get \$Script name ] . \" failed: \" . \$Err);\r\ + \n# }\r\ + \n#}\r\ + \n#:log info \"\\ndevMode = \$devMode\";\r\ + \n#:log info \"\\ndevRunning = \$devRunning\";\r\ + \n:foreach Script in=[ /system/script/find where source~\"^#!rsc by Vados \ + GlobalRUN\\r\?\\n\" ] do={\r\ + \n :onerror Err {\r\ + \n /system/script/run \$Script;\r\ + \n } do={\r\ + \n :log error (\"Run script \" . [ /system/script/get \$Script name \ + ] . \" width marker \\\" GlobalRUN\\\" failed: \" . \$Err);\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n# signal we are ready\r\ + \n:set GlobalConfReady true;\r\ + \n:while (\$GlobalConfReady != true) do={:delay 500ms};\r\ + \n" +add comment="Global functions" dont-require-permissions=no name=AM-GlobalFunc \ + owner=AM-GlobalFunc policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\r\ + \n# RouterOS script: AM-GglobalFunc\r\ + \n# Script comment: Global functions\r\ + \n# Copyright (c) 2005-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version=7.19\r\ + \n# requires device-mode, fetch, scheduler\r\ + \n:local ExitOK false;\r\ + \n:local ScriptName [ :jobname ];\r\ + \n#:global checkRunJob \$SriptName;\r\ + \n#:global fixCRLF;\r\ + \n#:if (\$fixCRLF != false) do={\r\ + \n#:foreach fixScript in=([ /system/script/find where name~\"*\" ]) do={/s\ + ystem/script/set source=[ :tocrlf [ get \$fixScript source ] ] \$fixScript\ + }\r\ + \n#:if (\$fixCRLF != \"LF\") do={ /system/script/set source=[ :tocrlf [ g\ + et \$fixScript source ] ] \$fixScript};};\r\ + \n#}\r\ + \n:global GlobalFuncReady false;\r\ + \n\r\ + \n# Git commit id & info, expected configuration version\r\ + \n:global CommitId \"main/729/f42d43ae\";\r\ + \n:global CommitTAG \"unknown\";\r\ + \n:global CommitInfo \"Autocommit in repo: ros.vados.ru, generated by owne\ + r: root, in 00:05:03 01.07.2026.\";\r\ + \n\r\ + \n# The variables are received right here.\r\ + \n:global GlobalConfVersion 140;\r\ + \n\r\ + \n:global SumsDirAndFileName \"tmp/checksums.json\";\r\ + \n\r\ + \n:global Identity [/system/identity/get name];\r\ + \n:global IdentityShort [:pick \$Identity 0 18];\r\ + \n\r\ + \n:global devBoardName [/system/resource/get board-name];\r\ + \n:global devMode [/system/device-mode/get mode];\r\ + \n:global devCurArch [/system/resource/get architecture-name];\r\ + \n:global devCurVersion [/system/resource/get version];\r\ + \n\r\ + \n# Variables defined in AM-GlobalConfig.rsc\r\ + \n:global TerminalColorOutput;\r\ + \n:global CommentsInScripts;\r\ + \n:global DetectIpAddrDefault;\r\ + \n:global DetectIpAddrFallback;\r\ + \n:global updateChannel;\r\ + \n:global Domain;\r\ + \n:global EmailGeneralTo;\r\ + \n:global BackupAndUpdateMode;\r\ + \n\r\ + \n# Single functions, without nested functions.\r\ + \n:global MiniDateTimeStamp;\r\ + \n:global MicroDateTimeStamp;\r\ + \n\r\ + \n# Include globals \$PrintDebug and \$PrintDebugOverride\r\ + \n:global LogPrint;\r\ + \n\r\ + \n# DeviceInfo and Updates\r\ + \n:global IsCheckUpdates;\r\ + \n:global WaitCheckUpdates;\r\ + \n:global GetPubIp;\r\ + \n\r\ + \n:global GetArrDeviceInfo;\r\ + \n:global WaitArrDeviceInfo;\r\ + \n\r\ + \n:global devModel;\r\ + \n:global devRunningMode;\r\ + \n\r\ + \n:global devRbRevision;\r\ + \n:global devRbSerialNumber;\r\ + \n:global devRbVerAvail;\r\ + \n\r\ + \n:global runningChannelVersion;\r\ + \n:global runningChannel;\r\ + \n:global runningVersion;\r\ + \n\r\ + \n:global devBuildTime;\r\ + \n:global ROsVerAvail;\r\ + \n:global PkgUpdStatus;\r\ + \n:global currentUpdateChannel;\r\ + \n\r\ + \n:global ScriptInstallUpdate;\r\ + \n\r\ + \n:global DeviceInfo;\r\ + \n\r\ + \n:global OldMode;\r\ + \n\r\ + \n:global ParseKeyValueStore;\r\ + \n:global RandomDelay;\r\ + \n:global GetRandomNumber;\r\ + \n:global EscapeForRegEx;\r\ + \n:global CharacterMultiply;\r\ + \n:global CharacterReplace;\r\ + \n:global CleanFilePath;\r\ + \n:global CleanName;\r\ + \n\r\ + \n:global CommitBrief;\r\ + \n\r\ + \n:global EitherOr;\r\ + \n:global FormatLine;\r\ + \n:global GetRandom20CharAlNum;\r\ + \n:global GetRandom20CharHex;\r\ + \n:global GetRandomNumber;\r\ + \n:global Grep;\r\ + \n:global IfThenElse;\r\ + \n:global MAX;\r\ + \n:global MIN;\r\ + \n:global HumanReadableNum;\r\ + \n\r\ + \n:global IsFullyConnected;\r\ + \n:global IsDNSResolving;\r\ + \n:global IsTimeSync;\r\ + \n:global IsTimeSyncCached;\r\ + \n:global IsTimeSyncResetNtp;\r\ + \n\r\ + \n:global MkDir;\r\ + \n:global RmDir;\r\ + \n:global RmFile;\r\ + \n:global FileGet;\r\ + \n:global Unix2Dos;\r\ + \n:global UrlEncode;\r\ + \n:global WaitForFile;\r\ + \n:global ScriptLock;\r\ + \n:global SendTelegram;\r\ + \n:global NotificationFunctions;\r\ + \n:global SendNotification;\r\ + \n:global SendNotification2;\r\ + \n:global SymbolForNotification;\r\ + \n:global SymbolByUnicodeName;\r\ + \n:global ValidateSyntax;\r\ + \n:global CheckSumsVerify;\r\ + \n:global GlobalConfChanges;\r\ + \n:global GlobalConfMigration;\r\ + \n:global VersionToNum;\r\ + \n:global RequiredRouterOS;\r\ + \n:global ExitError;\r\ + \n:global ExitOnError;\r\ + \n\r\ + \n:global FetchHugeFiles;\r\ + \n:global FetchUserAgentStr;\r\ + \n:global FileExists;\r\ + \n:global CertificateAvailable;\r\ + \n:global CertificateDownload;\r\ + \n:global CertificateNameByCN;\r\ + \n:global CharacterMultiply;\r\ + \n\r\ + \n:global InspectVar;\r\ + \n:global InspectVarRet;\r\ + \n:global ParseCustom;\r\ + \n\r\ + \n:set IsCheckUpdates do={\r\ + \n :local isInfo [:tobool \$1];\r\ + \n :global updateChannel;\r\ + \n :global PkgUpdStatus;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n :global arrDeviceInfo;\r\ + \n :log info (\$0 . \" \\\$isInfo = \" . \$isInfo); \r\ + \n :local CurrentChannel [ /system/package/update/get channel ];\r\ + \n :if ([ :len \$updateChannel ] > 0 && \$CurrentChannel != \$updateChann\ + el) do={\r\ + \n :retry command={/system/package/update set channel=\$updateChannel} \ + \_delay=300ms max=5 on-error={};\r\ + \n :log info (\$0 . \" Set updates channel to: \$updateChannel\");\r\ + \n }\r\ + \n :local Update [ /system/package/update/get ];\r\ + \n :local Channel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set currentUpdateChannel \$Channel;\r\ + \n :log info (\$0 . \" Update Channel: \" . \$Channel . \".\");\r\ + \n :local StatusPkg \"undefined\";\r\ + \n :log info (\$0 . \" Checking for updates...\");\r\ + \n :retry command={:set \$StatusPkg ([/system/package/update/check-for-up\ + dates without-paging as-value]->\"status\")} \\\r\ + \n delay=300ms max=5 on-error={};\r\ + \n :log info (\$0 . \" \\\$StatusPkg = \" . \$StatusPkg);\r\ + \n :if (\$StatusPkg = \"New version is available\") do={ :set PkgUpdStatu\ + s true; } else={ :set PkgUpdStatus false; }\r\ + \n :set ROsVerAvail [ :tostr [ /system/package/update/get latest-version \ + ] ];\r\ + \n :log info (\$0 . \" \\\$PkgUpdStatus = \" . \$PkgUpdStatus);\r\ + \n :if (\$isInfo != false || \$PkgUpdStatus = true) do={\r\ + \n :log info (\$0 . \" \\\$PkgUpdStatus = \" . \$PkgUpdStatus);\r\ + \n :if ([ :typeof \$arrDeviceInfo ] != \"array\") do={\r\ + \n :set arrDeviceInfo [:toarray \$arrDeviceInfo];\r\ + \n }\r\ + \n :retry command={:set (\$arrDeviceInfo->\"devUpdates\") [ /system/pac\ + kage/update/get ]} delay=500ms max=5 on-error={:log error (\"Error\")};\r\ + \n :return true;\r\ + \n } else={\r\ + \n :return \$PkgUpdStatus;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set WaitCheckUpdates do={\r\ + \n :global IsCheckUpdates;\r\ + \n :global PkgUpdStatus;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n :global arrDeviceInfo;\r\ + \n :local Status \"\";\r\ + \n :local Update;\r\ + \n :local WaitCount 0;\r\ + \n :if ([ \$IsCheckUpdates true ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n :set Status [ :tostr [ /system/package/update/get status ] ];\r\ + \n :while ((\$Status = \"\" || \$Status = \"finding out latest version...\ + \") && \$WaitCount < 60) do={\r\ + \n :delay 1s;\r\ + \n :set WaitCount (\$WaitCount + 1);\r\ + \n :set Status [ :tostr [ /system/package/update/get status ] ];\r\ + \n }\r\ + \n :set Update [ /system/package/update/get ];\r\ + \n :set currentUpdateChannel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set ROsVerAvail [ :tostr (\$Update->\"latest-version\") ];\r\ + \n :if ((\$Update->\"status\") = \"New version is available\") do={\r\ + \n :set PkgUpdStatus true;\r\ + \n } else={\r\ + \n :set PkgUpdStatus false;\r\ + \n }\r\ + \n :if ([ :typeof \$arrDeviceInfo ] != \"array\") do={\r\ + \n :set arrDeviceInfo [:toarray \$arrDeviceInfo];\r\ + \n }\r\ + \n :set (\$arrDeviceInfo->\"devUpdates\") \$Update;\r\ + \n :if (\$Status = \"\" || \$Status = \"finding out latest version...\") \ + do={\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set WaitArrDeviceInfo do={\r\ + \n :global GetArrDeviceInfo;\r\ + \n :while ([ \$GetArrDeviceInfo ] = false) do={\r\ + \n :delay 1s;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set GetArrDeviceInfo do={\r\ + \n :global LogPrint;\r\ + \n :global arrDeviceInfo;\r\ + \n :global devBoardName;\r\ + \n :global devModel;\r\ + \n :global devRunning;\r\ + \n :global devCurArch;\r\ + \n :global devRbRevision;\r\ + \n :global devRbSerialNumber;\r\ + \n :global devBuildTime;\r\ + \n :global runningChannelVersion;\r\ + \n :global runningChannel;\r\ + \n :global runningVersion;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n\r\ + \n :local DeviceInfo;\r\ + \n :local Resource [/system/resource/get];\r\ + \n :local Update [ /system/package/update/get ];\r\ + \n :local VersionString [ :tostr (\$Resource->\"version\") ];\r\ + \n :local ChannelStart [ :find \$VersionString \" (\" ];\r\ + \n :local RouterBoard;\r\ + \n :local IsRouterBoard false;\r\ + \n :local RunningMode \"\";\r\ + \n\r\ + \n :set devCurArch [ :tostr (\$Resource->\"architecture-name\") ];\r\ + \n :set devBuildTime [ :tostr (\$Resource->\"build-time\") ];\r\ + \n :set runningChannelVersion \$VersionString;\r\ + \n :set runningVersion \$VersionString;\r\ + \n :set runningChannel \"\";\r\ + \n\r\ + \n :if ([ :typeof \$ChannelStart ] = \"num\" && \$ChannelStart >= 0) do=\ + {\r\ + \n :set runningVersion [ :pick \$VersionString 0 \$ChannelStart ];\r\ + \n :local ChannelRest [ :pick \$VersionString (\$ChannelStart + 2) [ :\ + len \$VersionString ] ];\r\ + \n :local ChannelEnd [ :find \$ChannelRest \")\" ];\r\ + \n :if ([ :typeof \$ChannelEnd ] = \"num\" && \$ChannelEnd >= 0) do={\ + \r\ + \n :set runningChannel [ :pick \$ChannelRest 0 \$ChannelEnd ];\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :if ([:pick \$devBoardName 0 3] != \"CHR\" or [:pick \$devBoardName 0\ + \_3] != \"x86\") do={\r\ + \n :do {\r\ + \n :set RouterBoard [[ :parse \"/system/routerboard/get\" ]];\r\ + \n# :set RouterBoard [ /system/routerboard/get ];\r\ + \n :if ((\$RouterBoard->\"routerboard\") = true) do={\r\ + \n :set IsRouterBoard true;\r\ + \n }\r\ + \n } on-error={}\r\ + \n }\r\ + \n\r\ + \n :do {\r\ + \n :set RunningMode [ /system/device-mode/get mode ];\r\ + \n } on-error={\r\ + \n :do {\r\ + \n :set RunningMode [ /system/device-mode/get running ];\r\ + \n } on-error={\r\ + \n :set RunningMode \"\";\r\ + \n }\r\ + \n }\r\ + \n :set devRunning \$RunningMode;\r\ + \n\r\ + \n :if (\$IsRouterBoard = true) do={\r\ + \n :set devModel [ :tostr (\$RouterBoard->\"model\") ];\r\ + \n :set devRbRevision [ :tostr (\$RouterBoard->\"revision\") ];\r\ + \n :set devRbSerialNumber [ :tostr (\$RouterBoard->\"serial-number\") \ + ];\r\ + \n } else={\r\ + \n :set devModel \$devBoardName;\r\ + \n :set devRbRevision \"\";\r\ + \n :set devRbSerialNumber \"\";\r\ + \n }\r\ + \n\r\ + \n :set currentUpdateChannel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set ROsVerAvail [ :tostr (\$Update->\"latest-version\") ];\r\ + \n\r\ + \n :set (\$DeviceInfo->\"board-name\") \$devBoardName;\r\ + \n :set (\$DeviceInfo->\"architecture-name\") \$devCurArch;\r\ + \n :set (\$DeviceInfo->\"model\") \$devModel;\r\ + \n :set (\$DeviceInfo->\"revision\") \$devRbRevision;\r\ + \n :set (\$DeviceInfo->\"serial-number\") \$devRbSerialNumber;\r\ + \n :set (\$DeviceInfo->\"running-mode\") \$devRunning;\r\ + \n :set (\$DeviceInfo->\"build-time\") \$devBuildTime;\r\ + \n :set (\$DeviceInfo->\"running-channel-version\") \$runningChannelVers\ + ion;\r\ + \n :set (\$DeviceInfo->\"running-version\") \$runningVersion;\r\ + \n :set (\$DeviceInfo->\"running-channel\") \$runningChannel;\r\ + \n :set (\$DeviceInfo->\"routerboard\") \$IsRouterBoard;\r\ + \n :set (\$DeviceInfo->\"current-firmware\") [ :tostr (\$RouterBoard->\"\ + current-firmware\") ];\r\ + \n :set (\$DeviceInfo->\"upgrade-firmware\") [ :tostr (\$RouterBoard->\"\ + upgrade-firmware\") ];\r\ + \n :set (\$DeviceInfo->\"package-channel\") \$currentUpdateChannel;\r\ + \n :set (\$DeviceInfo->\"installed-version\") [ :tostr (\$Update->\"inst\ + alled-version\") ];\r\ + \n :set (\$DeviceInfo->\"latest-version\") \$ROsVerAvail;\r\ + \n :set (\$DeviceInfo->\"update-status\") [ :tostr (\$Update->\"status\"\ + ) ];\r\ + \n\r\ + \n :set arrDeviceInfo \$DeviceInfo;\r\ + \n :return \$DeviceInfo;\r\ + \n}\r\ + \n\r\ + \n:set DeviceInfo do={\r\ + \n :global GetArrDeviceInfo;\r\ + \n :global GlobalConfVersion;\r\ + \n :global Identity;\r\ + \n :global IfThenElse;\r\ + \n :global FormatLine;\r\ + \n :global CommitBrief;\r\ + \n\r\ + \n :local License [/system/license/get];\r\ + \n :local Snmp [ /snmp/get ];\r\ + \n :local Info [ \$GetArrDeviceInfo ];\r\ + \n\r\ + \n :if ([ :typeof \$Info ] != \"array\") do={\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :return ( \\\r\ + \n [ \$FormatLine \"Hostname\" \$Identity ] . \"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$Snmp->\"location\") ] > 0) \\\r\ + \n ([ \$FormatLine \"Location\" (\$Snmp->\"location\") ] . \"\\n\") ]\ + \_. \\\r\ + \n [ \$IfThenElse ([ :len (\$Snmp->\"contact\") ] > 0) \\\r\ + \n ([ \$FormatLine \"Contact\" (\$Snmp->\"contact\") ] . \"\\n\") ] .\ + \_\\\r\ + \n \"Hardware:\\n\" . \\\r\ + \n [ \$FormatLine \" Board\" (\$Info->\"board-name\") ] . \"\\n\" . \ + \\\r\ + \n [ \$FormatLine \" Arch\" (\$Info->\"architecture-name\") ] . \"\\\ + n\" . \\\r\ + \n [ \$FormatLine \" Model\" (\$Info->\"model\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"revision\") ] > 0) \\\r\ + \n (\" \" . (\$Info->\"revision\")) ] . \"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"serial-number\") ] > 0) \\\r\ + \n ([ \$FormatLine \" Serial\" (\$Info->\"serial-number\") ] . \"\ + \\n\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$License->\"nlevel\") ] > 0) \\\r\ + \n ([ \$FormatLine \" License\" (\"level \" . (\$License->\"nlevel\ + \")) ] . \"\\n\") ] . \\\r\ + \n \"RouterOS:\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$License->\"level\") ] > 0) \\\r\ + \n ([ \$FormatLine \" License\" (\"level \" . (\$License->\"level\ + \")) ] . \"\\n\") ] . \\\r\ + \n [ \$FormatLine \" Channel\" (\$Info->\"package-channel\") ] . \"\ + \\n\" . \\\r\ + \n [ \$FormatLine \" Installed\" (\$Info->\"installed-version\") ] .\ + \_\"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"running-channel\") ] > 0) \\\r\ + \n ([ \$FormatLine \" Running\" ((\$Info->\"running-version\") . \ + \" (\" . (\$Info->\"running-channel\") . \")\") ] . \"\\n\") \\\r\ + \n ([ \$FormatLine \" Running\" (\$Info->\"running-version\") ] . \ + \"\\n\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"latest-version\") ] > 0 && \\\r\ + \n (\$Info->\"installed-version\") != (\$Info->\"latest-version\"))\ + \_\\\r\ + \n ([ \$FormatLine \" Available\" (\$Info->\"latest-version\") ] .\ + \_\"\\n\") ] . \\\r\ + \n [ \$IfThenElse ((\$Info->\"routerboard\") = true && \\\r\ + \n (\$Info->\"current-firmware\") != (\$Info->\"upgrade-firmware\")\ + ) \\\r\ + \n ([ \$FormatLine \" Firmware\" ((\$Info->\"current-firmware\") .\ + \_\" -> \" . (\$Info->\"upgrade-firmware\")) ] . \"\\n\") ] . \\\r\ + \n \"RouterOS-Scripts:\\n\" . \\\r\ + \n [ \$FormatLine \" Commit\" [ \$CommitBrief ] ] . \"\\n\" . \\\r\ + \n [ \$FormatLine \" Version\" \$GlobalConfVersion ]);\r\ + \n}\r\ + \n\r\ + \n:if ([ :typeof \$NotificationFunctions ] != \"array\") do={:set Notifica\ + tionFunctions ({})}\r\ + \n\r\ + \n:set GetRandom20CharAlNum do={\r\ + \n :global EitherOr;\r\ + \n :return [ :rndstr length=[ \$EitherOr [ :tonum \$1 ] 20 ] from=\"ABCDE\ + FGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\" ];\r\ + \n}\r\ + \n\r\ + \n:set GetRandom20CharHex do={:global EitherOr; :return [ :rndstr length=[\ + \_\$EitherOr [ :tonum \$1 ] 20 ] from=\"0123456789abcdef\" ]; }\r\ + \n:set GetRandomNumber do={:global EitherOr; :return [ :rndnum from=0 to=[\ + \_\$EitherOr [ :tonum \$1 ] 4294967295 ] ]; }\r\ + \n\r\ + \n:global checkRunJob;\r\ + \n:set checkRunJob do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :global ScriptLock; \r\ + \n :if ([ \$ScriptLock \$Script ] = false) do={:return false}\r\ + \n :foreach Job in=[ /system/script/job/find where script=\$Script ] do={\ + :set Job [ /system/script/job/get \$Job ];\r\ + \n :while ([ :typeof (\$Job->\"parent\") ] = \"id\") do={:set Job [ /sy\ + stem/script/job/get [ find where .id=(\$Job->\"parent\") ] ]}\r\ + \n :if ((\$Job->\"type\") = \"login\") do={:return true};}; :return fa\ + lse; \r\ + \n}\r\ + \n\r\ + \n:set InspectVar do={\r\ + \n :global InspectVarRet;\r\ + \n :put [ :tocrlf [ \$InspectVarRet \$1 ] ];\r\ + \n}\r\ + \n\r\ + \n:set CommitBrief do={\r\ + \n :global CommitId;\r\ + \n :global CommitInfo;\r\ + \n :if (\$CommitId = \"unknown\") do={\r\ + \n :return \"unknown\";\r\ + \n }\r\ + \n :return (\$CommitInfo . \"/\" . [ :pick \$CommitId 0 8 ]);\r\ + \n}\r\ + \n\r\ + \n:set InspectVarRet do={\r\ + \n :local Input \$1;\r\ + \n :local Level (0 + [ :tonum \$2 ]);\r\ + \n :global CharacterReplace;\r\ + \n :global IfThenElse;\r\ + \n :global InspectVarRet;\r\ + \n :local IndentReturn do={\r\ + \n :local Prefix [ :tostr \$1 ];\r\ + \n :local Value [ :tostr \$2 ];\r\ + \n :local Level [ :tonum \$3 ];\r\ + \n :global CharacterMultiply;\r\ + \n :return ([ \$CharacterMultiply \" \" (\$Level * 2) ] . \"-\" . \$Pre\ + fix . \"-> \" . \$Value);\r\ + \n }\r\ + \n :local TypeOf [ :typeof \$Input ];\r\ + \n :local Len [ :len \$Input ];\r\ + \n :local Return [ \$IndentReturn \"type\" \$TypeOf \$Level ];\r\ + \n :if (\$TypeOf = \"array\") do={\r\ + \n :foreach Key,Value in=\$Input do={\r\ + \n :set \$Return (\$Return . \"\\n\" . \\\r\ + \n [ \$IndentReturn \"key\" \$Key (\$Level + 1) ] . \"\\n\" . \\\r\ + \n [ \$InspectVarRet \$Value (\$Level + 2) ]);\r\ + \n }\r\ + \n } else={\r\ + \n :if (\$TypeOf = \"str\") do={\r\ + \n :set \$Return (\$Return . \"\\n\" . \\\r\ + \n [ \$IndentReturn \"len\" \$Len \$Level ]);\r\ + \n :if ([ :typeof [ :find \$Input (\"\\r\") ] ] = \"num\") do={\r\ + \n :set Input [ \$CharacterReplace \$Input (\"\\r\") \"\" ];\r\ + \n }\r\ + \n :if ([ :typeof [ :find \$Input (\"\\n\") ] ] = \"num\") do={\r\ + \n :set Input [ \$CharacterReplace \$Input (\"\\n\") \" \" ];\r\ + \n }\r\ + \n }\r\ + \n :if (\$TypeOf != \"nothing\") do={\r\ + \n :set \$Return (\$Return . \"\\n\" . \\\r\ + \n [ \$IndentReturn \"value\" [ \$IfThenElse ([ :len \$Input ] > 80)\ + \_\\\r\ + \n ([ :pick \$Input 0 77 ] . \"...\") \$Input ] \$Level ]);\r\ + \n }\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set GetPubIp do={\r\ + \n :global DetectIpAddrDefault;\r\ + \n :global DetectIpAddrFallback;\r\ + \n\r\ + \n :local PubIpAddr false;\r\ + \n :local Url \$DetectIpAddrDefault;\r\ + \n :local JobName [ :jobname ];\r\ + \n\r\ + \n :do {\r\ + \n :log debug (\$0 . \" Trying to detect public IP using default serv\ + ice: \" . \$Url . \"...\");\r\ + \n :retry command={:set PubIpAddr ([ /tool/fetch http-method=\"get\"\ + \_check-certificate=yes-without-crl \$Url output=user as-value ]->\"data\"\ + )} \\\r\ + \n delay=50ms max=5 on-error={:log error (\$JobName . \" Failed to \ + detect public IP using default service: \" . \$Url . \".\")}\r\ + \n } on-error={\r\ + \n :log error (\$0 . \" Failed to detect public IP using default serv\ + ice: \" . \$Url . \".\");\r\ + \n :set Url \$DetectIpAddrFallBack;\r\ + \n :log debug (\$0 . \" Trying to detect public IP using fallback ser\ + vice: \" . \$Url . \"...\");\r\ + \n :retry command={:set PubIpAddr ([ /tool/fetch http-method=\"get\"\ + \_check-certificate=yes-without-crl \$Url output=user as-value ]->\"data\"\ + )} \\\r\ + \n delay=200ms max=5 on-error={:log error (\$JobName . \" Failed to\ + \_detect public IP using fallback service: \" . \$Url . \".\")}\r\ + \n };\r\ + \n :local IpLen ([ :len \$PubIpAddr ] -1);\r\ + \n :if (\$PubIpAddr = false) do={:set PubIpAddr \"not-detected\"} else=\ + {:set PubIpAddr [:pick \$PubIpAddr 0 \$IpLen]}\r\ + \n :return \$PubIpAddr;\r\ + \n}\r\ + \n\r\ + \n:set FormatLine do={\r\ + \n :local Key [ :tostr \$1 ];\r\ + \n :local Value [ :tostr \$2 ];\r\ + \n :local Indent [ :tonum \$3 ];\r\ + \n :local Spaces;\r\ + \n :local Return \"\";\r\ + \n :global CharacterMultiply;\r\ + \n :global EitherOr;\r\ + \n :set Indent [ \$EitherOr \$Indent 16 ];\r\ + \n :local Spaces [ \$CharacterMultiply \" \" \$Indent ];\r\ + \n :if ([ :len \$Key ] > 0) do={ :set Return (\$Key . \":\")}\r\ + \n :if ([ :len \$Key ] > (\$Indent - 2)) do={:set Return (\$Return . \"\\\ + n\" . [ :pick \$Spaces 0 \$Indent ] . \$Value);\r\ + \n } else={:set Return (\$Return . [ :pick \$Spaces 0 (\$Indent - [ :len \ + \$Return ]) ] . \$Value)}\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set ParseCustom do={\r\ + \n :local Str [ :tostr \$1 ];\r\ + \n :local Start [:find [ \$Str ] [:tostr \$2]];\r\ + \n :local End [ :tostr \$3 ];\r\ + \n :local Num [ :tonum \$4 ];\r\ + \n :local Return;\r\ + \n :if ([:len \$Num] = 0) do={:set Num \"0\"}\r\ + \n :local rest [:pick \$Str (\$Start+\$Num) [:len \$Str]]; \r\ + \n :if ([:len \$End ] = 0) do={:set Return [:pick \$Str \$Num \$Start]} e\ + lse={\r\ + \n :set End [:find \$rest \$End];\r\ + \n :set Return [:pick \$rest 0 \$End];\r\ + \n }\r\ + \n:return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set LogPrint do={\r\ + \n :local Severity [ :tostr \$1 ];\r\ + \n :local Name [ :tostr \$2 ];\r\ + \n :local Message [ :tostr \$3 ];\r\ + \n :global PrintDebug;\r\ + \n :global PrintDebugOverride;\r\ + \n :global EitherOr;\r\ + \n :local Debug [ \$EitherOr (\$PrintDebugOverride->\$Name) \$PrintDebug \ + ];\r\ + \n :local PrintSeverity do={\r\ + \n :global TerminalColorOutput;\r\ + \n :if (\$TerminalColorOutput != true) do={:return \$1}\r\ + \n :local Color { debug=96; info=97; warning=93; error=91 };\r\ + \n :return (\"\\1B[\" . \$Color->\$1 . \"m\" . \$1 . \"\\1B[0m\");\r\ + \n}\r\ + \n :local Log ([ \$EitherOr \$Name \"\" ] . \": \" . \$Message);\ + \r\ + \n :if (\$Severity ~ (\"^(custom|debug|error|info)\\\$\")) do={\r\ + \n :if (\$Severity = \"debug\") do={:log debug \$Log}\r\ + \n :if (\$Severity = \"error\") do={:log error \$Log}\r\ + \n :if (\$Severity = \"info\" ) do={:log info \$Log}\r\ + \n } else={:log warning \$Log; :set Severity \"warning\"}\r\ + \n :if (\$Severity != \"debug\" || \$Debug = true) do={:put ([ \$PrintSev\ + erity \$Severity ] . \": \" . \$Message)}\r\ + \n}\r\ + \n\r\ + \n:set CertificateAvailable do={\r\ + \n :local CommonName [ :tostr \$1 ];\r\ + \n :local UseFor [ :tostr \$2 ];\r\ + \n\r\ + \n :global CertificateDownload;\r\ + \n :global ParseKeyValueStore;\r\ + \n\r\ + \n :if ([ :len \$UseFor ] = 0) do={\r\ + \n :log warning (\$0 . \"The intended use is undefined!\");\r\ + \n :set UseFor \"undefined\";\r\ + \n }\r\ + \n :if ([ /system/resource/get free-hdd-space ] < 8388608 && \\\r\ + \n [ /certificate/settings/get crl-download ] = true && \\\r\ + \n [ /certificate/settings/get crl-store ] = \"system\") do={\r\ + \n :log warning (\$0 . \"This system has low free flash space but \" . \ + \\\r\ + \n \"is configured to download certificate CRLs to system!\");\r\ + \n }\r\ + \n :if ([ :len \$CommonName ] = 0) do={\r\ + \n :log warning (\$0 . \"No CommonName given!\");\r\ + \n :return false;\r\ + \n }\r\ + \n :local CertSettings [ /certificate/settings/get ];\r\ + \n :if (((\$CertSettings->\"builtin-trust-anchors\") = \"trusted\" || \\\ + \r\ + \n (\$CertSettings->\"builtin-trust-store\") ~ \$UseFor || \\\r\ + \n (\$CertSettings->\"builtin-trust-store\") = \"all\") && \\\r\ + \n [ :len [ /certificate/builtin/find where common-name=\$CommonName\ + \_] ] > 0) do={\r\ + \n :return true;\r\ + \n }\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] = 0\ + ) do={\r\ + \n :log info (\$0 . \"Certificate with CommonName '\" . \$CommonName . \ + \"' not available.\");\r\ + \n :if ([ \$CertificateDownload \$CommonName ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] > 1\ + ) do={\r\ + \n :log info (\$0 . \"There are \" . \$CertCount . \" Certificates with\ + \_CommonName '\" . \$CommonName . \"'. Should be ok.\");\r\ + \n :return true;\r\ + \n }\r\ + \n :local CertVal [ /certificate/get [ find where common-name=\$CommonNam\ + e ] ];\r\ + \n :while ((\$CertVal->\"akid\") != \"\" && (\$CertVal->\"akid\") != (\$C\ + ertVal->\"skid\")) do={\r\ + \n :if ([ :len [ /certificate/find where skid=(\$CertVal->\"akid\") ] ]\ + \_= 0) do={\r\ + \n :local IssuerCN ([ \$ParseKeyValueStore (\$CertVal->\"issuer\") ]-\ + >\"CN\");\r\ + \n :log info (\$0 . \"Certificate chain for '\" . \$CommonName . \"' \ + is incomplete, missing '\" . \$IssuerCN . \"'.\");\r\ + \n :if ([ \$CertificateDownload \$IssuerCN ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n :set CertVal [ /certificate/get [ find where skid=(\$CertVal->\"akid\ + \") ] ];\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set CertificateDownload do={\r\ + \n :local CommonName [ :tostr \$1 ];\r\ + \n :global ScriptUpdatesBaseUrl;\r\ + \n :global ScriptUpdatesUrlSuffix;\r\ + \n :global CertificateNameByCN;\r\ + \n :global CleanName;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global RmFile;\r\ + \n :global WaitForFile;\r\ + \n\r\ + \n :log info (\$0 . \"Downloading and importing certificate with \" . \\\ + \r\ + \n \"CommonName '\" . \$CommonName . \"'.\");\r\ + \n :local FileName ([ \$CleanName \$CommonName ] . \".pem\");\r\ + \n :do {\r\ + \n /tool/fetch check-certificate=yes-without-crl mode=https http-header\ + -field=({ [ \$FetchUserAgentStr \$0 ] }) \\\r\ + \n (\$ScriptUpdatesBaseUrl . \"certs/\" . \$FileName . \$ScriptUpdate\ + sUrlSuffix) \\\r\ + \n dst-path=\$FileName as-value;\r\ + \n \$WaitForFile \$FileName;\r\ + \n } on-error={\r\ + \n :log warning (\$0 . \" Failed downloading certificate with CommonNam\ + e '\" . \$CommonName . \\\r\ + \n \"' from repository! Trying fallback to mkcert.org...\");\r\ + \n :do {\r\ + \n :local CertSettings [ /certificate/settings/get ];\r\ + \n :if ([ :len [ /certificate/find where common-name=\"ISRG Root X1\"\ + \_] ] = 0 && \\\r\ + \n !(((\$CertSettings->\"builtin-trust-anchors\") = \"trusted\" \ + || \\\r\ + \n (\$CertSettings->\"builtin-trust-store\") ~ \"fetch\" || \ + \\\r\ + \n (\$CertSettings->\"builtin-trust-store\") = \"all\") && \\\ + \r\ + \n [ :len [ /certificate/builtin/find where common-name=\"ISRG\ + \_Root X1\" ] ] > 0)) do={\r\ + \n :log error (\$0 . \" Required certificate is not available.\");\ + \r\ + \n :return false;\r\ + \n }\r\ + \n /tool/fetch check-certificate=yes-without-crl mode=https http-head\ + er-field=({ [ \$FetchUserAgentStr \$0 ] }) \\\r\ + \n url=\"https://mkcert.org/generate/\" http-data=[ :serialize to=jso\ + n ({ \$CommonName }) ] \\\r\ + \n dst-path=\$FileName as-value;\r\ + \n \$WaitForFile \$FileName;\r\ + \n :if ([ /file/get \$FileName size ] = 0) do={\r\ + \n \$RmFile \$FileName;\r\ + \n :error false;\r\ + \n }\r\ + \n } on-error={\r\ + \n :log error (\$0 . \" Failed downloading certificate with CommonNam\ + e '\" . \$CommonName . \"'!\");\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n /certificate/import file-name=\$FileName passphrase=\"\" as-value;\r\ + \n :delay 1s;\r\ + \n \$RmFile \$FileName;\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] = 0\ + ) do={\r\ + \n /certificate/remove [ find where name~(\"^\" . \$FileName . \"_[0-9]\ + +\\\$\") ];\r\ + \n :log warning (\$0 . \" Certificate with CommonName '\" . \$CommonNam\ + e . \"' still unavailable!\");\r\ + \n :return false;\r\ + \n }\r\ + \n :foreach Cert in=[ /certificate/find where name~(\"^\" . \$FileName . \ + \"_[0-9]+\\\$\") ] do={\r\ + \n \$CertificateNameByCN [ /certificate/get \$Cert common-name ];\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set CertificateNameByCN do={\r\ + \n :local Match [ :tostr \$1 ];\r\ + \n :global CleanName;\r\ + \n :local Cert ([ /certificate/find where (common-name=\$Match or fingerp\ + rint=\$Match or name=\$Match) ]->0);\r\ + \n :if ([ :len \$Cert ] = 0) do={\r\ + \n :log warning (\$0 .\" No matching certificate found.\");\r\ + \n :return false;\r\ + \n }\r\ + \n :local CommonName [ /certificate/get \$Cert common-name ];\r\ + \n /certificate/set \$Cert name=[ \$CleanName \$CommonName ];\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set CharacterMultiply do={\r\ + \n :local Str [ :tostr \$1 ];\r\ + \n :local Num [ :tonum \$2 ];\r\ + \n :if (\$Num = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :for I from=1 to=\$Num do={:set Return (\$Return . \$Str)}\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set FileExists do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :local Type [ :tostr \$2 ];\r\ + \n :global FileGet;\r\ + \n :local FileVal [ \$FileGet \$FileName ];\r\ + \n :if (\$FileVal = false) do={ :return false; }\r\ + \n :if ([ :len (\$FileVal->\"size\") ] = 0) do={ :return false; }\r\ + \n :if ([ :len \$Type ] = 0 || \$FileVal->\"type\" = \$Type) do={ :return\ + \_true; }\r\ + \n :return false;\r\ + \n}\r\ + \n\r\ + \n:set Grep do={\r\ + \n :local Input ([ :tostr \$1 ] . \"\\n\");\r\ + \n :local Pattern [ :tostr \$2 ];\r\ + \n :if ([ :typeof [ :find \$Input \$Pattern ] ] = \"nil\") do={:return []\ + }\r\ + \n :do {\r\ + \n :local Line [ :pick \$Input 0 [ :find \$Input \"\\n\" ] ];\r\ + \n :if ([ :typeof [ :find \$Line \$Pattern ] ] = \"num\") do={:return \ + \$Line}\r\ + \n :set Input [ :pick \$Input ([ :find \$Input \"\\n\" ] + 1) [ :len \$\ + Input ] ];\r\ + \n } while=([ :len \$Input ] > 0);\r\ + \n :return [];\r\ + \n}\r\ + \n\r\ + \n:set HumanReadableNum do={\r\ + \n :local Input [ :tonum \$1 ];\r\ + \n :local Base [ :tonum \$2 ];\r\ + \n :global EitherOr;\r\ + \n :global IfThenElse;\r\ + \n :local Prefix \"kMGTPE\";\r\ + \n :local Pow 1;\r\ + \n :set Base [ \$EitherOr \$Base 1024 ];\r\ + \n :local Bin [ \$IfThenElse (\$Base = 1024) \"i\" \"\" ];\r\ + \n :if (\$Input < \$Base) do={:return \$Input}\r\ + \n :for I from=0 to=[ :len \$Prefix ] do={\r\ + \n :set Pow (\$Pow * \$Base);\r\ + \n :if (\$Input / \$Base < \$Pow) do={\r\ + \n :set Prefix [ :pick \$Prefix \$I ];\r\ + \n :local Tmp1 (\$Input * 100 / \$Pow);\r\ + \n :local Tmp2 (\$Tmp1 / 100);\r\ + \n :if (\$Tmp2 >= 100) do={:return (\$Tmp2 . \$Prefix . \$Bin)}\r\ + \n :return (\$Tmp2 . \".\" . \\\r\ + \n [ :pick \$Tmp1 [ :len \$Tmp2 ] ([ :len \$Tmp1 ] - [ :len \$Tmp\ + 2 ] + 1) ] . \\\r\ + \n \$Prefix . \$Bin);\r\ + \n }\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set CleanFilePath do={\r\ + \n :local Path [ :tostr \$1 ];\r\ + \n :global CharacterReplace;\r\ + \n :while (\$Path ~ \"//\") do={ :set \$Path [ \$CharacterReplace \$Path \ + \"//\" \"/\" ]; }\r\ + \n :if ([ :pick \$Path 0 ] = \"/\") do={ :set Path [ :pick \$Path 1 [ :le\ + n \$Path ] ]; }\r\ + \n :if ([ :pick \$Path ([ :len \$Path ] - 1) ] = \"/\") do={ :set Path [ \ + :pick \$Path 0 ([ :len \$Path ] - 1) ]; }\r\ + \n :return \$Path;\r\ + \n}\r\ + \n\r\ + \n:set CleanName do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :local Return \"\";\r\ + \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ + \n :local Char [ :pick \$Input \$I ];\r\ + \n :if ([ :typeof [ find \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr\ + stuvwxyz0123456789\" \$Char ] ] = \"nil\") do={\r\ + \n :do {:if ([ :len \$Return ] = 0) do={:error true};\r\ + \n :if ([ :pick \$Return ([ :len \$Return ] - 1) ] = \"-\") do={:er\ + ror true}; :set Char \"-\"} on-error={:set Char \"\"}; \r\ + \n };\r\ + \n :set Return (\$Return . \$Char)};\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set RandomDelay do={\r\ + \n :local Time [ :tonum \$1 ];\r\ + \n :local Unit [ :tostr \$2 ];\r\ + \n :global EitherOr;\r\ + \n :global GetRandomNumber;\r\ + \n :global MAX;\r\ + \n :if (\$Time = 0) do={:return false}\r\ + \n :delay ([ \$MAX 10 [ \$GetRandomNumber ([ :tonsec [ :totime (\$Time . \ + [ \$EitherOr \$Unit \"s\" ]) ] ] / 1000000) ] ] . \"ms\");\r\ + \n}\r\ + \n\r\ + \n:set EscapeForRegEx do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :if ([ :len \$Input ] = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :local Chars (\"^.[]\\\$()|*+\?{}\\\\\");\r\ + \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ + \n :local Char [ :pick \$Input \$I ];\r\ + \n :if ([ :find \$Chars \$Char ]) do={:set Char (\"\\\\\" . \$Char)}\r\ + \n :set Return (\$Return . \$Char);\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set ExitError do={\r\ + \n :local ExitOK [ :tostr \$1 ];\r\ + \n :local Name [ :tostr \$2 ];\r\ + \n :local Error [ :tostr \$3 ];\r\ + \n :global IfThenElse;\r\ + \n :if (\$ExitOK = \"false\") do={\r\ + \n :log error (\$Name [ \$IfThenElse ([ :pick \$Name 0 1 ] = \"\\\$\") \ + \\\r\ + \n \"Function\" \"Script\" ] . \" '\" . \$Name . \"' exited with er\ + ror\" . \\\r\ + \n [ \$IfThenElse (!(\$Error ~ \"^(|true|false)\\\$\")) (\": \" . \ + \$Error) \".\" ]);\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set ExitOnError do={\r\ + \n :local Name [ :tostr \$1 ];\r\ + \n :local Error [ :tostr \$2 ];\r\ + \n :global IfThenElse;\r\ + \n :log error (\$Name . \" \" . [ \$IfThenElse ([ :pick \$Name 0 1 ] = \"\ + \\\$\") \\\r\ + \n \"Function\" \"Script\" ] . \" '\" . \$Name . \"' exited with erro\ + r\" . \\\r\ + \n [ \$IfThenElse (!(\$Error ~ \"^(|true|false)\\\$\")) (\": \" . \$E\ + rror) \".\" ]);\r\ + \n}\r\ + \n\r\ + \n:set MiniDateTimeStamp do={\r\ + \n :local mikro [ :tobool \$1 ];\r\ + \n /system/clock;\r\ + \n :local vdate [get date];\r\ + \n :local vtime [get time];\r\ + \n :local vdoff [:toarray \"0,4,5,7,8,10\"];\r\ + \n :local MM [:pick \$vdate (\$vdoff->2) (\$vdoff->3)];\r\ + \n :local M [:tonum \$MM];\r\ + \n :if (\$vdate ~ \".../../....\") do={\r\ + \n :set vdoff [:toarray \"7,11,1,3,4,6\"];\r\ + \n :set M ([:find \"xxanebarprayunulugepctovecANEBARPRAYUNULUGE\ + PCTOVEC\" [:pick \$vdate (\$vdoff->2) (\$vdoff->3)] -1] / 2);\r\ + \n :if (\$M>12) do={:set M (\$M - 12)}\r\ + \n :set MM [:pick (100 + \$M) 1 3];\r\ + \n }\r\ + \n :local yyyy [:pick \$vdate (\$vdoff->0) (\$vdoff->1)];\r\ + \n :local dd [:pick \$vdate (\$vdoff->4) (\$vdoff->5)];\r\ + \n :local HH [:pick \$vtime 0 2];\r\ + \n :local mm [:pick \$vtime 3 5];\r\ + \n :local ss [:pick \$vtime 6 8];\r\ + \n :local Return;\r\ + \n :if (\$mikro = true) do={\r\ + \n :set Return ([:pick \$yyyy 2 4] . [:pick \$dd 0 1] . [:pick \$HH 0\ + \_1] . [:pick \$mm 3 4] . [:pick \$ss 6 7]);\r\ + \n } else={\r\ + \n :set Return ([\$yyyy] . [\$MM] . [\$dd] . [\$HH] . [\$mm] . [\$ss]);\ + \r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set WaitForFile do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :local WaitTime [ :totime \$2 ];\r\ + \n :global CleanFilePath;\r\ + \n :global EitherOr;\r\ + \n :global MAX;\r\ + \n :set FileName [ \$CleanFilePath \$FileName ];\r\ + \n :local Delay ([ \$MAX [ \$EitherOr \$WaitTime 2s ] 100ms ] / 9);\r\ + \n :do {\r\ + \n :retry {\r\ + \n /file/get \$FileName;\r\ + \n :return true;\r\ + \n } delay=\$Delay max=10;\r\ + \n } on-error={ }\r\ + \n :while ([ :len [ /file/find where name=\$FileName ] ] > 0) do={\r\ + \n :do {\r\ + \n /file/get \$FileName;\r\ + \n :return true;\r\ + \n } on-error={ }\r\ + \n :delay \$Delay;\r\ + \n :set Delay (\$Delay * 3 / 2);\r\ + \n }\r\ + \n :return false;\r\ + \n}\r\ + \n\r\ + \n:set FileGet do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :global WaitForFile;\r\ + \n :if ([ \$WaitForFile \$FileName 0s ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n :local FileVal false;\r\ + \n :do {\r\ + \n :set FileVal [ /file/get \$FileName ];\r\ + \n } on-error={ }\r\ + \n :return \$FileVal;\r\ + \n}\r\ + \n\r\ + \n:set RmDir do={\r\ + \n :local DirName [ :tostr \$1 ];\r\ + \n :global FileGet;\r\ + \n :log debug (\$0 . \" Removing directory: \". \$DirName);\r\ + \n :local DirVal [ \$FileGet \$DirName ];\r\ + \n :if (\$DirVal = false) do={\r\ + \n :log debug (\$0 . \" ... which does not exist.\");\r\ + \n :return true;\r\ + \n };\r\ + \n :if (\$DirVal->\"type\" != \"directory\") do={\r\ + \n :log error (\$0 . \" Directory '\" . \$DirName . \"' is not a direct\ + ory.\");\r\ + \n :return false;\r\ + \n };\r\ + \n :onerror Err {\r\ + \n /file/remove \$DirName;\r\ + \n } do={\r\ + \n :log error (\$0 . \" Removing directory '\" . \$DirName . \"' failed\ + : \" . \$Err);\r\ + \n :return false;\r\ + \n };\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set RmFile do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :global FileGet;\r\ + \n :log debug (\$0 . \" Removing file: \". \$FileName);\r\ + \n :local FileVal [ \$FileGet \$FileName ];\r\ + \n :if (\$FileVal = false) do={\r\ + \n :log debug (\$0 . \" ... which does not exist.\");\r\ + \n :return true;\r\ + \n }\r\ + \n :if (\$FileVal->\"type\" = \"directory\" || \$FileVal->\"type\" = \"di\ + sk\") do={\r\ + \n :log error (\$0 . \" File '\" . \$FileName . \"' is not a file.\");\ + \r\ + \n :return false;\r\ + \n }\r\ + \n :onerror Err {\r\ + \n /file/remove \$FileName;\r\ + \n } do={\r\ + \n :log error (\$0 . \" Removing file '\" . \$FileName . \"' failed: \"\ + \_. \$Err); :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set MkDir do={\r\ + \n :local Path [ :tostr \$1 ];\r\ + \n :global CleanFilePath;\r\ + \n :global FileGet;\r\ + \n :global RmDir;\r\ + \n :global WaitForFile;\r\ + \n\r\ + \n :local MkTmpfs do={\r\ + \n :global WaitForFile;\r\ + \n :local TmpFs [ /disk/find where slot=tmpfs type=tmpfs ];\r\ + \n :if ([ :len \$TmpFs ] = 1) do={\r\ + \n :if ([ /disk/get \$TmpFs disabled ] = true) do={\r\ + \n :log info (\$0 . \" The tmpfs is disabled, enabling.\");\r\ + \n /disk/enable \$TmpFs;\r\ + \n }\r\ + \n :return true;\r\ + \n }\r\ + \n :log info (\$0 . \" Creating disk of type tmpfs.\");\r\ + \n \$RmDir \"tmpfs\";\r\ + \n :onerror Err {\r\ + \n /disk/add slot=tmpfs type=tmpfs tmpfs-max-size=([ /system/resource\ + /get total-memory ] / 3);\r\ + \n \$WaitForFile \"tmpfs\";\r\ + \n } do={\r\ + \n :log warning (\$0 . \" Creating disk of type tmpfs failed: \" . \$\ + Err);\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n }\r\ + \n :set Path [ \$CleanFilePath \$Path ];\r\ + \n :if (\$Path = \"\") do={\r\ + \n :return true;\r\ + \n }\r\ + \n :log debug (\$0 . \" Making directory: \" . \$Path);\r\ + \n :local PathVal [ \$FileGet \$Path ];\r\ + \n :if (\$PathVal->\"type\" = \"directory\") do={\r\ + \n :log debug (\$0 . \" ... which already exists.\");\r\ + \n :return true;\r\ + \n }\r\ + \n :if ([ :pick \$Path 0 5 ] = \"tmpfs\") do={\r\ + \n :if ([ \$MkTmpfs ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n :onerror Err {\r\ + \n /file/add type=\"directory\" name=\$Path;\r\ + \n \$WaitForFile \$Path;\r\ + \n } do={\r\ + \n :log warning (\$0 . \" Making directory '\" . \$Path . \"' failed: \ + \" . \$Err);\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set MAX do={:if (\$1 > \$2) do={:return \$1}\r\ + \n :return \$2;\r\ + \n}\r\ + \n:set MIN do={:if (\$1 < \$2) do={:return \$1}\r\ + \n :return \$2;\r\ + \n}\r\ + \n\r\ + \n:set CharacterMultiply do={\r\ + \n :local Str [ :tostr \$1 ];\r\ + \n :local Num [ :tonum \$2 ];\r\ + \n :if (\$Num = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :for I from=1 to=\$Num do={:set Return (\$Return . \$Str)}\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set CharacterReplace do={\r\ + \n :local String [ :tostr \$1 ];\r\ + \n :local ReplaceFrom [ :tostr \$2 ];\r\ + \n :local ReplaceWith [ :tostr \$3 ];\r\ + \n :local Return \"\";\r\ + \n :if (\$ReplaceFrom = \"\") do={:return \$String}\r\ + \n :while ([ :typeof [ :find \$String \$ReplaceFrom ] ] != \"nil\") do={\ + \r\ + \n :local Pos [ :find \$String \$ReplaceFrom ];\r\ + \n :set Return (\$Return . [ :pick \$String 0 \$Pos ] . \$ReplaceWith);\ + \r\ + \n :set String [ :pick \$String (\$Pos + [ :len \$ReplaceFrom ]) [ :len\ + \_\$String ] ];\r\ + \n }\r\ + \n :return (\$Return . \$String);\r\ + \n}\r\ + \n\r\ + \n:set IfThenElse do={\r\ + \n :if ([ :tostr \$1 ] = \"true\" || [ :tobool \$1 ] = true) do={:return \ + \$2};\r\ + \n :return \$3;\r\ + \n}\r\ + \n\r\ + \n:set EitherOr do={\r\ + \n :global IfThenElse;\r\ + \n :if ([ :typeof \$1 ] = \"num\") do={:return [ \$IfThenElse (\$1 != 0) \ + \$1 \$2 ]}\r\ + \n :if ([ :typeof \$1 ] = \"time\") do={:return [ \$IfThenElse (\$1 > 0s)\ + \_\$1 \$2 ]}\r\ + \n# this works for boolean values, literal ones with parentheses\r\ + \n :return [ \$IfThenElse ([ :len [ :tostr \$1 ] ] > 0) \$1 \$2 ];\r\ + \n}\r\ + \n\r\ + \n:set ParseKeyValueStore do={\r\ + \n :local Source \$1;\r\ + \n :if ([ :pick \$Source 0 1 ] = \"{\") do={\r\ + \n :do {\r\ + \n :return [ :deserialize from=json \$Source ];\r\ + \n } on-error={ }\r\ + \n } \r\ + \n :if ([ :typeof \$Source ] != \"array\") do={:set Source [ :tostr \$1 ]\ + }\r\ + \n :local Result ({});\r\ + \n :foreach KeyValue in=[ :toarray \$Source ] do={\r\ + \n :if ([ :find \$KeyValue \"=\" ]) do={\r\ + \n :local Key [ :pick \$KeyValue 0 [ :find \$KeyValue \"=\" ] ];\r\ + \n :local Value [ :pick \$KeyValue ([ :find \$KeyValue \"=\" ] + 1) [\ + \_:len \$KeyValue ] ];\r\ + \n :if (\$Value=\"true\") do={:set Value true}\r\ + \n :if (\$Value=\"false\") do={:set Value false}\r\ + \n :set (\$Result->\$Key) \$Value;\r\ + \n } else={:set (\$Result->\$KeyValue) true}\r\ + \n }\r\ + \n :return \$Result;\r\ + \n}\r\ + \n:set RequiredRouterOS do={\r\ + \n :local Caller [ :tostr \$1 ];\r\ + \n :local Required [ :tostr \$2 ];\r\ + \n :local Warn [ :tostr \$3 ];\r\ + \n :global IfThenElse;\r\ + \n :global VersionToNum;\r\ + \n :if (!(\$Required ~ \"^\\\\d+\\\\.\\\\d+((alpha|beta|rc|\\\\.)\\\\d+|)\ + \\\$\")) do={\r\ + \n :log error (\$0 . \" No valid RouterOS version: \" . \$Required);\r\ + \n :return false;\r\ + \n }\r\ + \n :if ([ \$VersionToNum \$Required ] > [ \$VersionToNum [ /system/packag\ + e/update/get installed-version ] ]) do={\r\ + \n :if (\$Warn = \"true\") do={\r\ + \n :log warning (\$0 . \" This \" . [ \$IfThenElse ([ :pick \$Caller \ + 0 ] = (\"\\\$\")) \"function\" \"script\" ] . \\\r\ + \n \" '\" . \$Caller . \"' (at least specific functionality) requir\ + es RouterOS \" . \$Required . \". Please update!\");\r\ + \n }\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set ValidateSyntax do={\r\ + \n :local Code [ :tostr \$1 ];\r\ + \n :global LogPrint;\r\ + \n :onerror Err {\r\ + \n [ :parse (\":local Validate do={\\n\" . \$Code . \"\\n}\") ];\r\ + \n } do={\r\ + \n \$LogPrint debug \$0 (\"Valdation failed: \" . \$Err);\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set VersionToNum do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :local Multi 0x1000000;\r\ + \n :local Return 0;\r\ + \n :global CharacterReplace;\r\ + \n :set Input [ \$CharacterReplace \$Input \".\" \",\" ];\r\ + \n :foreach I in={ \"zero\"; \"alpha\"; \"beta\"; \"rc\" } do={\r\ + \n :set Input [ \$CharacterReplace \$Input \$I (\",\" . \$I . \",\") ];\ + \r\ + \n }\r\ + \n :foreach Value in=([ :toarray \$Input ], 0) do={\r\ + \n :local Num [ :tonum \$Value ];\r\ + \n :if (\$Multi = 0x100) do={\r\ + \n :if ([ :typeof \$Num ] = \"num\") do={\r\ + \n :set Return (\$Return + 0xff00);\r\ + \n :set Multi (\$Multi / 0x100);\r\ + \n } else={\r\ + \n :if (\$Value = \"zero\") do={ }\r\ + \n :if (\$Value = \"alpha\") do={ :set Return (\$Return + 0x3f00); \ + }\r\ + \n :if (\$Value = \"beta\") do={ :set Return (\$Return + 0x5f00); }\ + \r\ + \n :if (\$Value = \"rc\") do={ :set Return (\$Return + 0x7f00); }\r\ + \n }\r\ + \n }\r\ + \n :if ([ :typeof \$Num ] = \"num\") do={ :set Return (\$Return + (\$Va\ + lue * \$Multi)); }\r\ + \n :set Multi (\$Multi / 0x100);\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set ScriptLock do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local WaitMax [ :totime \$2 ];\r\ + \n :global GetRandom20CharAlNum;\r\ + \n :global IfThenElse;\r\ + \n :global ScriptLockOrder;\r\ + \n :if ([ :typeof \$ScriptLockOrder ] = \"nothing\") do={\r\ + \n :set ScriptLockOrder ({});\r\ + \n }\r\ + \n :if ([ :typeof (\$ScriptLockOrder->\$Script) ] = \"nothing\") do={\r\ + \n :set (\$ScriptLockOrder->\$Script) ({});\r\ + \n }\r\ + \n :local JobCount do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :return [ :len [ /system/script/job/find where script=\$Script ] ];\ + \r\ + \n }\r\ + \n :local TicketCount do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :local Count 0;\r\ + \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :if ([ :typeof \$Ticket ] != \"nothing\") do={:set Count (\$Count \ + + 1)}\r\ + \n }\r\ + \n :return \$Count;\r\ + \n }\r\ + \n :local IsFirstTicket do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local Check [ :tostr \$2 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :if (\$Ticket = \$Check) do={:return true}\r\ + \n :if ([ :typeof \$Ticket ] != \"nothing\" && \$Ticket != \$Check) d\ + o={:return false}\r\ + \n }\r\ + \n :return false;\r\ + \n }\r\ + \n :local AddTicket do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local Add [ :tostr \$2 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :while (true) do={\r\ + \n :local Pos [ :len (\$ScriptLockOrder->\$Script) ];\r\ + \n :set (\$ScriptLockOrder->\$Script->\$Pos) \$Add;\r\ + \n :delay 10ms;\r\ + \n :if ((\$ScriptLockOrder->\$Script->\$Pos) = \$Add) do={:return tru\ + e}\r\ + \n }\r\ + \n }\r\ + \n :local RemoveTicket do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local Remove [ :tostr \$2 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :foreach Id,Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :while ((\$ScriptLockOrder->\$Script->\$Id) = \$Remove) do={\r\ + \n :set (\$ScriptLockOrder->\$Script->\$Id);\r\ + \n :delay 10ms;\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n :local CleanupTickets do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :if ([ :typeof \$Ticket ] != \"nothing\") do={:return false}\r\ + \n }\r\ + \n :set (\$ScriptLockOrder->\$Script) ({});\r\ + \n }\r\ + \n :if ([ :typeof \$WaitMax ] = \"nil\" ) do={:set WaitMax 0s}\r\ + \n :if ([ :len [ /system/script/find where name=\$Script ] ] = 0) do={\r\ + \n :log error (\$0 . \" A script named '\" . \$Script . \"' does not ex\ + ist!\");\r\ + \n :error false;\r\ + \n }\r\ + \n :if ([ \$JobCount \$Script ] = 0) do={\r\ + \n \$LogPrint error \$0 (\"No script '\" . \$Script . \"' is running!\"\ + );\r\ + \n :error false;\r\ + \n }\r\ + \n :if ([ \$TicketCount \$Script ] >= [ \$JobCount \$Script ]) do={\r\ + \n :log error (\$0 . \" More tickets than running scripts '\" . \$Scrip\ + t . \"', resetting!\");\r\ + \n :set (\$ScriptLockOrder->\$Script) ({});\r\ + \n /system/script/job/remove [ find where script=\$Script ];\r\ + \n }\r\ + \n :local MyTicket [ \$GetRandom20CharAlNum 6 ];\r\ + \n \$AddTicket \$Script \$MyTicket;\r\ + \n :local WaitInterval (\$WaitMax / 20);\r\ + \n :local WaitTime \$WaitMax;\r\ + \n :while (\$WaitTime > 0 && \\\r\ + \n ([ \$IsFirstTicket \$Script \$MyTicket ] = false || \\\r\ + \n [ \$TicketCount \$Script ] < [ \$JobCount \$Script ])) do={\r\ + \n :set WaitTime (\$WaitTime - \$WaitInterval);\r\ + \n :delay \$WaitInterval;\r\ + \n }\r\ + \n :if ([ \$IsFirstTicket \$Script \$MyTicket ] = true && \\\r\ + \n [ \$TicketCount \$Script ] = [ \$JobCount \$Script ]) do={\r\ + \n \$RemoveTicket \$Script \$MyTicket;\r\ + \n \$CleanupTickets \$Script;\r\ + \n :return true;\r\ + \n }\r\ + \n \$RemoveTicket \$Script \$MyTicket;\r\ + \n \$LogPrint debug \$0 (\"Script '\" . \$Script . \"' started more than \ + once\" . \\\r\ + \n [ \$IfThenElse (\$WaitTime < \$WaitMax) \" and timed out waiting for\ + \_lock\" \"\" ] . \"...\");\r\ + \n :return false;\r\ + \n}\r\ + \n\r\ + \n:set SendNotification do={ :onerror Err {\r\ + \n :global SendNotification2;\r\ + \n \$SendNotification2 ({ origin=\$0; subject=\$1; message=\$2; link=\$3;\ + \_silent=\$4 });\r\ + \n} do={:global ExitOnError; \$ExitOnError \$0 \$Err}\r\ + \n}\r\ + \n\r\ + \n:set SendNotification2 do={\r\ + \n :local Notification \$1;\r\ + \n :global NotificationFunctions;\r\ + \n :foreach FunctionName,Discard in=\$NotificationFunctions do={\r\ + \n (\$NotificationFunctions->\$FunctionName) (\"\\\$NotificationFunctio\ + ns->\\\"\" . \$FunctionName . \"\\\"\") \$Notification;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set SymbolByUnicodeName do={\r\ + \n :local Name [ :tostr \$1 ];\r\ + \n :global EitherOr;\r\ + \n :global SymbolsExtra;\r\ + \n :local Symbols ({\r\ + \n \"abacus\"=\"\\F0\\9F\\A7\\AE\";\r\ + \n \"alarm-clock\"=\"\\E2\\8F\\B0\";\r\ + \n \"arrow-down\"=\"\\E2\\AC\\87\";\r\ + \n \"arrow-up\"=\"\\E2\\AC\\86\";\r\ + \n \"calendar\"=\"\\F0\\9F\\93\\85\";\r\ + \n \"card-file-box\"=\"\\F0\\9F\\97\\83\";\r\ + \n \"chart-decreasing\"=\"\\F0\\9F\\93\\89\";\r\ + \n \"chart-increasing\"=\"\\F0\\9F\\93\\88\";\r\ + \n \"cloud\"=\"\\E2\\98\\81\";\r\ + \n \"cross-mark\"=\"\\E2\\9D\\8C\";\r\ + \n \"earth\"=\"\\F0\\9F\\8C\\8D\";\r\ + \n \"fire\"=\"\\F0\\9F\\94\\A5\";\r\ + \n \"floppy-disk\"=\"\\F0\\9F\\92\\BE\";\r\ + \n \"gear\"=\"\\E2\\9A\\99\";\r\ + \n \"heart\"=\"\\E2\\99\\A5\";\r\ + \n \"high-voltage-sign\"=\"\\E2\\9A\\A1\";\r\ + \n \"incoming-envelope\"=\"\\F0\\9F\\93\\A8\";\r\ + \n \"information\"=\"\\E2\\84\\B9\";\r\ + \n \"large-orange-circle\"=\"\\F0\\9F\\9F\\A0\";\r\ + \n \"large-red-circle\"=\"\\F0\\9F\\94\\B4\";\r\ + \n \"link\"=\"\\F0\\9F\\94\\97\";\r\ + \n \"lock-with-ink-pen\"=\"\\F0\\9F\\94\\8F\";\r\ + \n \"memo\"=\"\\F0\\9F\\93\\9D\";\r\ + \n \"mobile-phone\"=\"\\F0\\9F\\93\\B1\";\r\ + \n \"pushpin\"=\"\\F0\\9F\\93\\8C\";\r\ + \n \"scissors\"=\"\\E2\\9C\\82\";\r\ + \n \"scroll\"=\"\\F0\\9F\\93\\9C\";\r\ + \n \"smiley-partying-face\"=\"\\F0\\9F\\A5\\B3\";\r\ + \n \"smiley-smiling-face\"=\"\\E2\\98\\BA\";\r\ + \n \"smiley-winking-face-with-tongue\"=\"\\F0\\9F\\98\\9C\";\r\ + \n \"sparkles\"=\"\\E2\\9C\\A8\";\r\ + \n \"speech-balloon\"=\"\\F0\\9F\\92\\AC\";\r\ + \n \"star\"=\"\\E2\\AD\\90\";\r\ + \n \"warning-sign\"=\"\\E2\\9A\\A0\";\r\ + \n \"white-heavy-check-mark\"=\"\\E2\\9C\\85\"\r\ + \n }, \$SymbolsExtra);\r\ + \n :local Magic [ :pick [ /system/clock/get date ] 4 10 ];\r\ + \n :local Special {\r\ + \n \"information-04-01\"=\"\\F0\\9F\\9A\\BB\";\r\ + \n \"large-orange-circle-04-01\"=\"\\F0\\9F\\8D\\8A\";\r\ + \n \"large-orange-circle-10-31\"=\"\\F0\\9F\\8E\\83\";\r\ + \n \"large-red-circle-04-01\"=\"\\F0\\9F\\8D\\92\" };\r\ + \n :if ([ :len (\$Symbols->\$Name) ] = 0) do={\r\ + \n :log warning (\$0 . \"No symbol available for name '\" . \$Name . \"\ + '!\");\r\ + \n :return \"\";\r\ + \n }\r\ + \n :return ([ \$EitherOr (\$Special->(\$Name . \$Magic)) (\$Symbols->\$Na\ + me) ] . \"\\EF\\B8\\8F\");\r\ + \n}\r\ + \n\r\ + \n:set SymbolForNotification do={\r\ + \n :global NotificationsWithSymbols;\r\ + \n :global SymbolByUnicodeName;\r\ + \n :global IfThenElse;\r\ + \n :if (\$NotificationsWithSymbols != true) do={:return [ \$IfThenElse ([\ + \_:len \$2 ] > 0) ([ :tostr \$2 ] . \" \") \"\" ]}\r\ + \n :local Return \"\";\r\ + \n :foreach Symbol in=[ :toarray \$1 ] do={:set Return (\$Return . [ \$Sy\ + mbolByUnicodeName \$Symbol ])}\r\ + \n :return (\$Return . \" \");\r\ + \n}\r\ + \n\r\ + \n:set Unix2Dos do={:return [ :tocrlf [ :tostr \$1 ] ]}\r\ + \n:set UrlEncode do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :if ([ :len \$Input ] = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :local Chars (\"\\n\\r !\\\"#\\\$%&'()*+,:;<=>\?@[\\\\]^`{|}~\");\r\ + \n :local Subs { \"%0A\"; \"%0D\"; \"%20\"; \"%21\"; \"%22\"; \"%23\"; \"\ + %24\"; \"%25\"; \"%26\"; \"%27\";\r\ + \n \"%28\"; \"%29\"; \"%2A\"; \"%2B\"; \"%2C\"; \"%3A\"; \"%3B\"; \ + \"%3C\"; \"%3D\"; \"%3E\"; \"%3F\";\r\ + \n \"%40\"; \"%5B\"; \"%5C\"; \"%5D\"; \"%5E\"; \"%60\"; \"%7B\"; \ + \"%7C\"; \"%7D\"; \"%7E\" };\r\ + \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ + \n :local Char [ :pick \$Input \$I ];\r\ + \n :local Replace [ :find \$Chars \$Char ];\r\ + \n :if ([ :typeof \$Replace ] = \"num\") do={:set Char (\$Subs->\$Repla\ + ce)}\r\ + \n :set Return (\$Return . \$Char);\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set IsDNSResolving do={\r\ + \n :do {:resolve \"api.telegram.org\"} on-error={:return false}\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set IsFullyConnected do={\r\ + \n :global IsDNSResolving;\r\ + \n :global IsTimeSync;\r\ + \n :if ([ \$IsDNSResolving ] = false) do={:return false};\r\ + \n :if ([ \$IsTimeSync ] = false) do={:return false};\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set IsTimeSync do={\r\ + \n :global IsTimeSyncCached;\r\ + \n :global IsTimeSyncResetNtp;\r\ + \n :if (\$IsTimeSyncCached = true) do={:return true}\r\ + \n :if ([ /system/ntp/client/get enabled ] = true) do={\r\ + \n :if ([ /system/ntp/client/get status ] = \"synchronized\") do={\r\ + \n :set IsTimeSyncCached true;\r\ + \n :return true;\r\ + \n }\r\ + \n :local Uptime [ /system/resource/get uptime ];\r\ + \n :if ([ :typeof \$IsTimeSyncResetNtp ] = \"nothing\") do={\r\ + \n :set IsTimeSyncResetNtp \$Uptime;\r\ + \n }\r\ + \n :if (\$Uptime - \$IsTimeSyncResetNtp < 3m) do={:return false}\r\ + \n :log warning \"\$0 The ntp client is configured, but did not sync.\"\ + ;\r\ + \n :set IsTimeSyncResetNtp \$Uptime;\r\ + \n /system/ntp/client/set enabled=no;\r\ + \n :delay 20ms;\r\ + \n /system/ntp/client/set enabled=yes;\r\ + \n :return false;\r\ + \n }\r\ + \n :if ([ /system/license/get ]->\"level\" = \"free\" || \\\r\ + \n [ /system/resource/get ]->\"board-name\" = \"x86\") do={\r\ + \n :log debug \"\$0 No ntp client configured, relying on RTC for CHR fr\ + ee license and x86.\";\r\ + \n :return true;\r\ + \n }\r\ + \n :if ([ /ip/cloud/get update-time ] = true) do={\r\ + \n :if ([ :typeof [ /ip/cloud/get public-address ] ] = \"ip\") do={\r\ + \n :set IsTimeSyncCached true;\r\ + \n :return true;\r\ + \n }\r\ + \n :return false;\r\ + \n }\r\ + \n :log debug \"\$0 No time source configured! Returning gracefully...\";\ + \r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set FetchHugeFiles do={\r\ + \n :local ScriptName [ :tostr \$1 ];\r\ + \n :local Url [ :tostr \$2 ];\r\ + \n :local CheckCert [ :tostr \$3 ];\r\ + \n\r\ + \n :global CleanName;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global GetRandom20CharAlNum;\r\ + \n :global IfThenElse;\r\ + \n :global LogPrint;\r\ + \n :global MkDir;\r\ + \n :global RmDir;\r\ + \n :global RmFile;\r\ + \n :global WaitForFile;\r\ + \n\r\ + \n :set CheckCert [ \$IfThenElse (\$CheckCert = \"false\") \"no\" \"yes-w\ + ithout-crl\" ];\r\ + \n\r\ + \n :local DirName (\"tmpfs/\" . [ \$CleanName \$ScriptName ]);\r\ + \n :if ([ \$MkDir \$DirName ] = false) do={\r\ + \n \$LogPrint error \$0 (\"Failed creating directory!\");\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :local FileName (\$DirName . \"/\" . [ \$CleanName \$0 ] . \"-\" . [ \ + \$GetRandom20CharAlNum ]);\r\ + \n :onerror Err {\r\ + \n /tool/fetch check-certificate=\$CheckCert \$Url dst-path=\$FileName \ + \\\r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$ScriptName ] }) as-va\ + lue;\r\ + \n } do={\r\ + \n :if ([ \$WaitForFile \$FileName 500ms ] = true) do={\r\ + \n \$RmFile \$FileName;\r\ + \n }\r\ + \n \$LogPrint debug \$0 (\"Failed downloading from \" . \$Url . \" - \"\ + \_. \$Err);\r\ + \n \$RmDir \$DirName;\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :if ([ \$WaitForFile \$FileName 5s ] = false) do={\r\ + \n \$LogPrint debug \$0 (\"The file downloaded from \" . \$Url . \" did\ + \_not show up.\");\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :local FileSize [ /file/get \$FileName size ];\r\ + \n :local Return \"\";\r\ + \n :local VarSize 0;\r\ + \n :while (\$VarSize != \$FileSize) do={\r\ + \n :set Return (\$Return . ([ /file/read offset=\$VarSize chunk-size=32\ + 768 file=\$FileName as-value ]->\"data\"));\r\ + \n :set FileSize [ /file/get \$FileName size ];\r\ + \n :set VarSize [ :len \$Return ];\r\ + \n :if (\$VarSize > \$FileSize) do={\r\ + \n :delay 100ms;\r\ + \n }\r\ + \n }\r\ + \n \$RmDir \$DirName;\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set FetchUserAgentStr do={\r\ + \n :local Caller [ :tostr \$1 ];\r\ + \n :global GlobalScriptsUrl;\r\ + \n :global CommitBrief;\r\ + \n :global IfThenElse;\r\ + \n :local Resource [ /system/resource/get ];\r\ + \n :return (\"User-Agent: Mikrotik/\" . \$Resource->\"version\" . \" \" .\ + \_\$Resource->\"architecture-name\" . \\\r\ + \n \" \" . \$Caller . \"/Fetch (\" . \$GlobalScriptsUrl . \"; \" . [ \$\ + CommitBrief ] . \")\");\r\ + \n}\r\ + \n\r\ + \n:set ScriptInstallUpdate do={ :onerror Err {\r\ + \n :local Scripts [ :toarray \$1 ];\r\ + \n :local NewComment [ :tostr \$2 ];\r\ + \n :global InitSetup;\r\ + \n\r\ + \n :global CommitId;\r\ + \n :global ScriptUpdatesCRLF;\r\ + \n :global GlobalConfVersion;\r\ + \n :global Identity;\r\ + \n :global CertificateAvailable;\r\ + \n :global CheckSumsVerify;\r\ + \n :global GlobalScriptsUrl;\r\ + \n :global SumsDirAndFileName;\r\ + \n :global GlobalScriptsUrlSuffix;\r\ + \n :global EitherOr;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global Grep;\r\ + \n :global IfThenElse;\r\ + \n :global LogPrint;\r\ + \n :global ParseKeyValueStore;\r\ + \n :global RequiredRouterOS;\r\ + \n :global SendNotification2;\r\ + \n :global SymbolForNotification;\r\ + \n :global ValidateSyntax;\r\ + \n :global CommentsInScripts;\r\ + \n\r\ + \n :if ([ \$CertificateAvailable \"Root YE\" \"fetch\" ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Downloading certificate failed, trying wit\ + hout.\");\r\ + \n }\r\ + \n\r\ + \n :foreach Script in=\$Scripts do={\r\ + \n :if ([ :len [ /system/script/find where name=\$Script ] ] = 0) do={\ + \r\ + \n \$LogPrint info \$0 (\"Adding new script: \" . \$Script);\r\ + \n /system/script/add name=\$Script owner=\$Script source=\"#!rsc by \ + Vados\\n\" comment=\$NewComment;\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :local CommitIdBefore \$CommitId;\r\ + \n :local GlobalConfVersionBefore \$GlobalConfVersion;\r\ + \n :local ReloadGlobal false;\r\ + \n :local DeviceMode [ /system/device-mode/get ];\r\ + \n\r\ + \n :if (\$CheckSumsVerify = true) do={\r\ + \n :local CheckSums ({});\r\ + \n :do {\r\ + \n :local Url (\$GlobalScriptsUrl . \$SumsDirAndFileName . \$GlobalScr\ + iptsUrlSuffix);\r\ + \n \$LogPrint debug \$0 (\"Fetching checksums from url: \" . \$Url);\ + \r\ + \n :set CheckSums [ :deserialize from=json ([ /tool/fetch check-certi\ + ficate=yes-without-crl \\\r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$0 ] }) \$Url output\ + =user as-value ]->\"data\") ];\r\ + \n } on-error={ \$LogPrint warning \$0 (\"Err = \" . \$Err); }\r\ + \n }\r\ + \n\r\ + \n :foreach Script in=[ /system/script/find where source~\"^#!rsc by Vado\ + s\" ] do={\r\ + \n :local ScriptVal [ /system/script/get \$Script ];\r\ + \n :local ScriptInfo [ \$ParseKeyValueStore (\$ScriptVal->\"comment\") \ + ];\r\ + \n :local SourceNew;\r\ + \n\r\ + \n :foreach Scheduler in=[ /system/scheduler/find where on-event~(\"\\\ + \\b\" . \$ScriptVal->\"name\" . \"\\\\b\") ] do={\r\ + \n :local SchedulerVal [ /system/scheduler/get \$Scheduler ];\r\ + \n :if (\$ScriptVal->\"policy\" != \$SchedulerVal->\"policy\") do={\r\ + \n \$LogPrint warning \$0 (\"Policies differ for script '\" . \$Scr\ + iptVal->\"name\" . \"' and its scheduler '\" . \$SchedulerVal->\"name\" . \ + \"'!\");\r\ + \n }\r\ + \n }\r\ + \n :do {\r\ + \n :if (\$ScriptInfo->\"ignore\" = true) do={\r\ + \n \$LogPrint debug \$0 (\"Ignoring script '\" . \$ScriptVal->\"nam\ + e\" . \"', as requested.\");\r\ + \n :error true;\r\ + \n }\r\ + \n :if (\$CheckSumsVerify = true) do={\r\ + \n :local CheckSum (\$CheckSums->(\$ScriptVal->\"name\"));\r\ + \n :if ([ :len (\$ScriptInfo->\"base-url\") ] = 0 && [ :len (\$Scri\ + ptInfo->\"url-suffix\") ] = 0 && \\\r\ + \n [ :convert transform=md5 to=hex [ :tolf (\$ScriptVal->\"sou\ + rce\") ] ] = \$CheckSum) do={\r\ + \n \$LogPrint debug \$0 (\"Checksum for script '\" . \$ScriptVal-\ + >\"name\" . \"' matches, ignoring.\");\r\ + \n :error true;\r\ + \n }\r\ + \n }\r\ + \n :if ([ :len (\$ScriptInfo->\"certificate\") ] > 0) do={\r\ + \n :if ([ \$CertificateAvailable (\$ScriptInfo->\"certificate\") \"\ + fetch\" ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Downloading certificate failed, tryi\ + ng without.\");\r\ + \n }\r\ + \n }\r\ + \n :onerror Err {\r\ + \n :local BaseUrl [ \$EitherOr (\$ScriptInfo->\"base-url\") \$Globa\ + lScriptsUrl ];\r\ + \n :local UrlSuffix [ \$EitherOr (\$ScriptInfo->\"url-suffix\") \$G\ + lobalScriptsUrlSuffix ];\r\ + \n :local Url (\$BaseUrl . \$ScriptVal->\"name\" . \".rsc\" . \$Url\ + Suffix);\r\ + \n \$LogPrint warning \$0 (\"Fetching script '\" . (\$ScriptVal->\"\ + name\") . \"' from url: \" . \$Url);\r\ + \n :local Result [ /tool/fetch check-certificate=yes-without-crl \\\ + \r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$0 ] }) \$Url outp\ + ut=user as-value ];\r\ + \n :if (\$Result->\"status\" = \"finished\") do={\r\ + \n :set SourceNew [ :tolf (\$Result->\"data\") ];\r\ + \n } \r\ + \n } do={\r\ + \n \$LogPrint warning \$0 (\"Failed fetching script '\" . \$ScriptV\ + al->\"name\" . \"': \" . \$Err);\r\ + \n :if (\$Err != \"Fetch failed with status 404\") do={\r\ + \n :error false;\r\ + \n }\r\ + \n :if (\$ScriptVal->\"source\" = \"#!rsc by Vados\") do={\r\ + \n \$LogPrint warning \$0 (\"Removing dummy. Typo on installation\ + \?\");\r\ + \n /system/script/remove \$Script;\r\ + \n :error false;\r\ + \n }\r\ + \n :if (\$CheckSumsVerify = true) do={\r\ + \n :if ([ :len (\$ScriptInfo->\"base-url\") ] = 0 && [ :len (\$Sc\ + riptInfo->\"url-suffix\") ] = 0 && \\\r\ + \n [ :len \$CheckSum ] = 0) do={\r\ + \n \$LogPrint warning \$0 (\"Added the script manually\? Skip u\ + pdates with 'ignore=true' in comment.\");\r\ + \n }\r\ + \n }\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :if ([ :len \$SourceNew ] = 0) do={\r\ + \n \$LogPrint debug \$0 (\"No update for script '\" . (\$ScriptVal-\ + >\"name\") . \"'.\");\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :local SourceCRLF [ :tocrlf \$SourceNew ];\r\ + \n :if (\$InitSetup != true && ((\$ScriptVal->\"name\") != \"AM-Globa\ + lConfig\" || (\$ScriptVal->\"name\") != \"AM-GlobalFunc\")) do={\r\ + \n :if (\$SourceNew = (\$ScriptVal->\"source\") || \$SourceCRLF = (\ + \$ScriptVal->\"source\")) do={\r\ + \n \$LogPrint debug \$0 (\"Script '\" . (\$ScriptVal->\"name\") \ + . \"' source did not change. End of lines set to CRLF.\");\r\ + \n if (\$ScriptUpdatesCRLF = false) do={\r\ + \n :put [ :tolf \$SourceNew ];\r\ + \n \$LogPrint debug \$0 (\"Script '\" . (\$ScriptVal->\"name\"\ + ) . \"' source update end of lines to LF.\");\r\ + \n }\r\ + \n :error false;\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :if ([ :pick \$SourceNew 0 14 ] != \"#!rsc by Vados\") do={\r\ + \n \$LogPrint warning \$0 (\"Looks like new script '\" . \$ScriptVa\ + l->\"name\" . \"' is not valid (missing shebang = '\$shebang') Ignoring!\"\ + );\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :if (\$CommentsInScripts = true) do={\r\ + \n :local CommentLine [ \$Grep \$SourceNew (\"\\23 Script comment:\ + \_\") ];\r\ + \n :if ([ :len \$CommentLine ] = 0) do={\r\ + \n \$LogPrint debug \$0 (\"The search in new script '\" . (\$Scr\ + iptVal->\"name\") . \"' for comment in script body, is not found result Ig\ + noring!\");\r\ + \n :error false;\r\ + \n } else={\r\ + \n :if ([ :len (\$ScriptVal->\"comment\")] = 0 || [ :len (\$Scri\ + ptVal->\"comment\")] != [ :pick \$CommentLine ([ :find \$CommentLine \":\"\ + ] + 2) [ :len \$CommentLine] ]) do={\r\ + \n \$LogPrint debug \$0 (\"Exsiting comment for script '\" . (\ + \$ScriptVal->\"name\") . \"' is '\" . (\$ScriptVal->\"comment\") . \"'.\")\ + ;\r\ + \n :set (\$ScriptVal->\"comment\") [ :pick \$CommentLine ([ :f\ + ind \$CommentLine \":\"] + 2) [ :len \$CommentLine] ];\r\ + \n \$LogPrint debug \$0 (\"New comment (\" . (\$ScriptVal->\"c\ + omment\") . \") for script '\" . (\$ScriptVal->\"name\") . \"' has been ad\ + ded!\");\r\ + \n } else={\r\ + \n \$LogPrint debug \$0 (\"Comment for script '\" . (\$ScriptV\ + al->\"name\") . \"' did not change.\");\r\ + \n :error false;\r\ + \n }\r\ + \n } \r\ + \n }\r\ + \n\r\ + \n :local RequiredROS ([ \$ParseKeyValueStore [ \$Grep \$SourceNew (\ + \"\\23 requires RouterOS, \") ] ]->version);\r\ + \n :if ([ \$RequiredRouterOS \$0 [ \$EitherOr \$RequiredROS \"0.0\" ]\ + \_false ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"The script '\" . (\$ScriptVal->\"name\ + \") . \"' requires RouterOS \" . \\\r\ + \n \$RequiredROS . \", which is not met by your installation. I\ + gnoring!\");\r\ + \n :error false;\r\ + \n }\r\ + \n :local RequiredDM [ \$ParseKeyValueStore [ \$Grep \$SourceNew (\"\ + \\23 requires device-mode, \") ] ];\r\ + \n :local MissingDM ({});\r\ + \n :foreach Feature,Value in=\$RequiredDM do={\r\ + \n :if ([ :typeof (\$DeviceMode->\$Feature) ] = \"bool\" && (\$Devi\ + ceMode->\$Feature) = false) do={\r\ + \n :set MissingDM (\$MissingDM, \$Feature);\r\ + \n }\r\ + \n }\r\ + \n :if ([ :len \$MissingDM ] > 0) do={\r\ + \n \$LogPrint warning \$0 (\"The script '\" . (\$ScriptVal->\"name\ + \") . \"' requires disabled \" . \\\r\ + \n \"device-mode features (\" . [ :tostr \$MissingDM ] . \"). I\ + gnoring!\");\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :if ([ \$ValidateSyntax \$SourceNew ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Syntax validation for script '\" . (\$\ + ScriptVal->\"name\") . \"' failed! Ignoring!\");\r\ + \n :error false;\r\ + \n }\r\ + \n \r\ + \n :log info (\"Updating script: \" . (\$ScriptVal->\"name\") . \" Sc\ + ript comment: \" . (\$ScriptVal->\"comment\"));\r\ + \n\r\ + \n /system/script/set owner=(\$ScriptVal->\"name\") comment=(\$Script\ + Val->\"comment\") \\\r\ + \n source=[ \$IfThenElse (\$ScriptUpdatesCRLF = true) \$SourceCRL\ + F \$SourceNew ] \$Script;\r\ + \n :if (\$ScriptVal->\"name\" = \"AM-GlobalConfig\" || \\\r\ + \n \$ScriptVal->\"name\" = \"AM-GlobalFunc\" || \\\r\ + \n \$ScriptVal->\"name\" ~ (\"^(AM-GlobalFunc\\\\.d|mod)/.\")) d\ + o={\r\ + \n :set ReloadGlobal true;\r\ + \n }\r\ + \n } on-error={ }\r\ + \n }\r\ + \n :if (\$ReloadGlobal = true) do={\r\ + \n \$LogPrint info \$0 (\"Reloading global configuration and functions.\ + \");\r\ + \n :onerror Err {\r\ + \n :global InitSetup (a);\r\ + \n /system/script {run AM-GlobalConfig; run AM-GlobalFunc;};\r\ + \n } do={\$LogPrint error \$0 (\"Reloading global configuration and fun\ + ctions failed! \" . \$Err)}\r\ + \n }\r\ + \n :if (\$GlobalConfVersionBefore > \$GlobalConfVersion) do={\r\ + \n \$LogPrint warning \$0 (\"The configuration version decreased from \ + \" . \\\r\ + \n \$GlobalConfVersionBefore . \" to \" . \$GlobalConfVersion . \\\r\ + \n \". Installed an older version\?\");\r\ + \n }\r\ + \n :if (\$GlobalConfVersionBefore < \$GlobalConfVersion) do={\r\ + \n :global GlobalConfChanges;\r\ + \n :global GlobalConfMigration;\r\ + \n :local ChangeLogCode;\r\ + \n :if ([ :len \$ChangeLogCode ] > 0) do={\r\ + \n :if ([ \$ValidateSyntax \$ChangeLogCode ] = true) do={\r\ + \n :onerror Err {\r\ + \n [ :parse \$ChangeLogCode ];\r\ + \n } do={\$LogPrint warning \$0 (\"The changelog failed to run: \" \ + . \$Err)}\r\ + \n } else={\$LogPrint warning \$0 (\"The changelog failed syntax vali\ + dation!\")}\r\ + \n }\r\ + \n :if ([ :len \$GlobalConfMigration ] > 0) do={\r\ + \n :for I from=(\$GlobalConfVersionBefore + 1) to=\$GlobalConfVersion\ + \_do={\r\ + \n :local Migration (\$GlobalConfMigration->[ :tostr \$I ]);\r\ + \n :do {\r\ + \n :if ([ :typeof \$Migration ] != \"str\") do={\r\ + \n \$LogPrint debug \$0 (\"Migration code for change \" . \$I .\ + \_\" is not available.\");\r\ + \n :error false;\r\ + \n }\r\ + \n :if ([ \$ValidateSyntax \$Migration ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Migration code for change \" . \$I\ + \_. \" failed syntax validation!\");\r\ + \n :error false}\r\ + \n \$LogPrint info \$0 (\"Applying migration for change \" . \$I \ + . \": \" . \$Migration);\r\ + \n :onerror Err {\r\ + \n [ :parse \$Migration ];\r\ + \n } do={\$LogPrint warning \$0 (\"Migration code for change \" .\ + \_\$I . \" failed to run: \" . \$Err)}\r\ + \n } on-error={ }\r\ + \n }\r\ + \n }\r\ + \n :local NotificationMessage (\"The configuration version on \" . \$Id\ + entity . \" increased \" . \\\r\ + \n \"to \" . \$GlobalConfVersion . \", current configuration may nee\ + d modification. \" . \\\r\ + \n \"Please review and update global-config-overlay, then re-run glo\ + bal-config.\");\r\ + \n \$LogPrint info \$0 (\$NotificationMessage);\r\ + \n :if ([ :len \$GlobalConfChanges ] > 0) do={\r\ + \n :set NotificationMessage (\$NotificationMessage . \"\\n\\nChanges:\ + \");\r\ + \n :for I from=(\$GlobalConfVersionBefore + 1) to=\$GlobalConfVersion\ + \_do={\r\ + \n :local Change (\$GlobalConfChanges->[ :tostr \$I ]);\r\ + \n :set NotificationMessage (\$NotificationMessage . \"\\n \" . \\\ + \r\ + \n [ \$SymbolForNotification \"pushpin\" \"*\" ] . \$Change);\r\ + \n \$LogPrint info \$0 (\"Change \" . \$I . \": \" . \$Change);\r\ + \n }\r\ + \n } else={\r\ + \n :set NotificationMessage (\$NotificationMessage . \"\\n\\nNews and\ + \_changes are not available.\");\r\ + \n\r\ + \n }\r\ + \n\r\ + \n :if ([ :len \$GlobalConfChanges ] > 0) do={ :set GlobalConfChanges; \ + } else={ :global GlobalConfChanges (a); }\r\ + \n :if ([ :len \$GlobalConfMigration ] > 0) do={ :set GlobalConfMigrati\ + on; } else={ :global GlobalConfMigration (a); }\r\ + \n }\r\ + \n} do={\r\ + \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ + \n} }\r\ + \n\r\ + \n# load modules\r\ + \n:foreach Script in=[ /system/script/find where name ~ \"^(global-functio\ + ns\\\\.d|mod)/.\" ] do={\r\ + \n :local ScriptVal [ /system/script/get \$Script ];\r\ + \n :if ([ \$ValidateSyntax (\$ScriptVal->\"source\") ] = true) do={\r\ + \n :onerror Err {\r\ + \n /system/script/run \$Script;\r\ + \n } do={\r\ + \n \$LogPrint error \$0 (\"Module '\" . \$ScriptVal->\"name\" . \"' f\ + ailed to run: \" . \$Err);\r\ + \n }\r\ + \n } else={\r\ + \n \$LogPrint error \$0 (\"Module '\" . \$ScriptVal->\"name\" . \"' fai\ + led syntax validation, skipping.\");\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n# Add and fix global scheduler\r\ + \n:put \"Add or/and fix Global scheduler...\";\r\ + \n:local OnEvent \"/system/script { run AM-GlobalConfig; run AM-GlobalFunc\ + ; }\";\r\ + \n:local Comment \"Every Day Set Global Environment Variables\";\r\ + \n:if ([ :len [ /system/scheduler/find where name=\"AM-SetGlobalEnv\" ] ] \ + = 0) do={\r\ + \n /system/scheduler/add name=\"AM-SetGlobalEnv\" comment=\$Comment on-ev\ + ent=\$OnEvent start-time=startup;\r\ + \n}\r\ + \n:if ([ /system/scheduler/get \"AM-SetGlobalEnv\" comment ] != \$Comment)\ + \_do={\r\ + \n /system/scheduler/set \"AM-SetGlobalEnv\" comment=\$Comment;\r\ + \n}\r\ + \n:if ([ /system/scheduler/get \"AM-SetGlobalEnv\" on-event ] != \$OnEvent\ + ) do={\r\ + \n /system/scheduler/set \"AM-SetGlobalEnv\" on-event=\$OnEvent;\r\ + \n}\r\ + \n# Add Update Script scheduler\r\ + \n:put \"Add or/and fix Update Script scheduler\";\r\ + \n:set OnEvent \":global ScriptInstallUpdate; \\\$ScriptInstallUpdate;\";\ + \r\ + \n:set Comment \"Every Day Check For Update Scripts\";\r\ + \n:if ([ :len [ /system/scheduler/find where name=\"AM-ScriptInstallUpdate\ + \" ] ] = 0) do={\r\ + \n/system/scheduler/add name=\"AM-ScriptInstallUpdate\" comment=\$Comment \ + start-time=startup interval=1d on-event=\$OnEvent;\r\ + \n}\r\ + \n\r\ + \n:onerror Err {\r\ + \n :global GlobalConfReady;\r\ + \n :retry { :if (\$GlobalConfReady != true) do={ :error (\"Global configs\ + \_not ready.\"); }; } delay=100ms max=5;\r\ + \n\r\ + \n:log warning (\"This script \$ScriptName Loaded \" . \\\r\ + \n [ \$IfThenElse (\$CommitId != \"unknown\") ([ \$CommitBrief ] . \" \ + \") ] . \\\r\ + \n \"on \" . \$devBoardName . \"\\nRouterOS: \" . \$devCurVersion . \"\ + \\nArchitecture: \" . \$devCurArch . \"\\nIdentity: \" . \$Identity);\r\ + \n # signal we are ready\r\ + \n:set GlobalFuncReady true;\r\ + \n:set ExitOK true;\r\ + \n\r\ + \n:log info (\$0 . \"Global configs ready!\");\r\ + \n} do={\r\ + \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ + \n}\r\ + \n" +add comment=\ + "Lookup IP addresses for RKN list and add them to firewall address-list" \ + dont-require-permissions=no name=AM-RKN-dnsLookup owner=AM-RKN-dnsLookup \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + source="#!rsc by Vados\r\ + \n# RouterOS script: AM-RKN-dnsLookup\r\ + \n# Script comment: Lookup IP addresses for RKN list and add them to firew\ + all address-list\r\ + \n# Copyright (c) 2007-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version=7.19\r\ + \n# requires device-mode, fetch\r\ + \n#\r\ + \n# Script description: This script is intended to be run periodically, e.\ + g. once a day, to update the IP addresses in the firewall address-list bas\ + ed on the RKN list.\r\ + \n# It resolves the domain names in the RKN list and a\ + dds the corresponding IP addresses to the specified firewall address-list.\ + \r\ + \n# The script also handles CNAME records by following\ + \_them until it finds A records.\r\ + \n# Usage:\r\ + \n# /system/script { run AM-RKN-dnsLookup; }\r\ + \n:local ScriptName [ :jobname ];\r\ + \n\r\ + \n:global dnsLookupReady false;\r\ + \n:if ([:typeof \$dnsLookupReady] != \"boolean\") do={ :set dnsLookupReady\ + \_true; }\r\ + \nwhile (!\$dnsLookupReady) do={ :nothing; }\r\ + \n:set dnsLookupReady false;\r\ + \n\r\ + \n:local arrRKN {\r\ + \n \"telegra.ph\"\r\ + \n \"grani.ru\"\r\ + \n \"xhamster.com\"\r\ + \n \"lostfilm.tv\"\r\ + \n \"rutracker.org\"\r\ + \n \"lurkmore.to\"\r\ + \n \"dou.ua\"\r\ + \n \"youporn.com\"\r\ + \n \"pornolab.net\"\r\ + \n \"crimerussia.com\"\r\ + \n \"telegram.org\"\r\ + \n \"api.telegram.org\"\r\ + \n \"facebook.com\"\r\ + \n \"instagram.com\"\r\ + \n \"x.com\"\r\ + \n \"twitter.com\"\r\ + \n \"youtube.com\"\r\ + \n \"googleapis.com\"\r\ + \n \"youtu.be\"\r\ + \n \"googlevideo.com\"\r\ + \n \"gstatic.com\"\r\ + \n \"googleusercontent.com\"\r\ + \n \"nhacmp3youtube.com\"\r\ + \n \"telegram.me\"\r\ + \n \"t.me\";}\r\ + \n\r\ + \n:local ListRKN \"RKN-dnsLookup\";\r\ + \n:local ListComment (\"ListRKN managed by \" . \$ScriptName);\r\ + \n:foreach aListItem in=[/ip/firewall/address-list find list=\$ListRKN] do\ + ={\r\ + \n /ip firewall address-list remove \$aListItem;\r\ + \n}\r\ + \n:foreach aItem in=\$arrRKN do={\r\ + \n# :do {\r\ + \n :retry delay=500ms max=5 on-error={:log error \"dns resolve fail\ + ure [ \$aItem - resolve ip ]\"} command={:resolve \$aItem}\r\ + \n# } on-error={\r\ + \n# :log error \"dns resolve failure [ \$arItem - resolve ip ]\";\r\ + \n# }\r\ + \n :foreach dnsRecord in=[/ip dns cache all find where (name=\$aItem)] \ + do={\r\ + \n :if ([/ip dns cache all get \$dnsRecord type]=\"A\") do={\r\ + \n :local newAddress [/ip dns cache all get \$dnsRecord data];\ + \r\ + \n :do {\r\ + \n /ip firewall address-list add list=\$ListRKN address=\$newA\ + ddress comment=\$aItem;\r\ + \n :log warning \"Successfully adding ip to list A record: \ + \$dnsRecord, address: \$newAddress domain: \$aItem\";\r\ + \n } on-error={\r\ + \n :log error \"error when adding ip to list A record: \$dn\ + sRecord, address: \$newAddress domain: \$aItem\";\r\ + \n }\r\ + \n }\r\ + \n :if ([/ip dns cache all get \$dnsRecord type]=\"CNAME\") do={\r\ + \n :local cname;\r\ + \n :local nextCname;\r\ + \n :local cnameAddress;\r\ + \n :set cname [/ip dns cache all find where (name=\$aItem && ty\ + pe=\"CNAME\")];\r\ + \n :set nextCname [/ip dns cache all find where (name=[/ip dns \ + cache all get \$cname data] && type=\"CNAME\")];\r\ + \n :while (\$nextCname != \"\") do={\r\ + \n :set cname \$nextCname;\r\ + \n :set nextCname [/ip dns cache all find where (name=[/ip \ + dns cache all get \$cname data] && type=\"CNAME\")];\r\ + \n }\r\ + \n :foreach aRecord in=[/ip dns cache all find where (name=[/ip\ + \_dns cache all get \$cname data] && type=\"A\")] do={\r\ + \n :do {\r\ + \n :set cnameAddress [/ip dns cache all get \$aRecord d\ + ata];\r\ + \n /ip firewall address-list add list=\$ListRKN address\ + =\$cnameAddress comment=\$aItem;\r\ + \n :log warning \"Succesfully adding ip to list CNAME r\ + ecord: \$cname, A record: \$aRecord, address: \$newAddress, from domain: \ + \$aItem.\";\r\ + \n# /ip firewall raw add action=add-dst-to-address-list\ + \_address-list=\$ListRKN address-list-timeout=none-dynamic chain=preroutin\ + g comment=\$aItem content=\$aItem;\r\ + \n } on-error={\r\ + \n :log error \"error when adding ip to list CNAME reco\ + rd: \$cname, A record: \$aRecord, address: \$newAddress, from domain: \$aI\ + tem.\";\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:if ([ :len [ /system/scheduler/find where name=\$ScriptName ] ] = 0) do\ + ={\r\ + \n :log error (\$ScriptName . \"System Scheduler for script: \" . \$Scri\ + ptName . \" is NOT SET! Fix It Now!\");\r\ + \n /system/scheduler/add name=\$ScriptName on-event=\"/system/script { \ + run \$ScriptName; }\" comment=\"Update RKN DNS Looup\" interval=00:30:00 p\ + olicy=\"ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon\"\ + \_start-time=startup;\r\ + \n }\r\ + \n:set dnsLookupReady true;\r\ + \ndelay 2s; \r\ + \n:global dnsLookupReady (a);\r\ + \n" +add dont-require-permissions=no name="renameLists " owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + local oldName \"Test\";\ + \n:local newName \"Test-IP\";\ + \n/ip firewall address-list\ + \n:foreach i in=[find list=\$oldName] do={\ + \nset \$i list=\$newName;\ + \n}\ + \n" +add dont-require-permissions=no name=IPv6-Settings owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + #############Script Settings##################\ + \n\ + \n:local \"IF-TUN\" \"6to4-tun\"\ + \n:local \"IF-LOC\" \"Bridge-LAN\"\ + \n:local \"POOL-6TO4\" \"poolV6-local\"\ + \n:local \"force-update\" false\ + \n############ use then static ip #######################\ + \n:local \"lease-address\" [/ip address get [find interface=\$\"IF-LOC\"] \ + address]\ + \n#:local \"interface\" \"ext\"\ + \n:local bound 0\ + \n\ + \n###############################################\ + \n\ + \n:local 6to4prefix do={\ + \n :global dec2hex\ + \n :local ipv4 \$1\ + \n :local ipv6 \"2002:\"\ + \n :for i from=0 to=2 step=1 do={ \ + \n :if ( \$i = 2) do={\ + \n :set ipv6 (\$ipv6.\":\")\ + \n }\ + \n :local fp [:find \$ipv4 \".\"]\ + \n :if ( \$fp > 0 ) do={\ + \n :set ipv6 (\$ipv6.[\$dec2hex [:pick \$ipv4 0 \$fp]])\ + \n :set ipv4 [:pick \$ipv4 (\$fp + 1 ) [:len \$ipv4]]\ + \n }\ + \n }\ + \n :return (\$ipv6.[\$dec2hex \$ipv4])\ + \n}\ + \n:local \"str_replace\" do={\ + \n :local \"str-pos\" [:find \$1 \$2]\ + \n :local \"str-len\" [:len \$2]\ + \n :local str \"\"\ + \n :local rest \$1\ + \n :while (\$\"str-pos\" >= 0) do={\ + \n :local t [:pick \$rest 0 \$\"str-pos\"]\ + \n :if ( \$4 > 0 ) do={\ + \n :for i from=1 to=(\$4 - [:len \$t]) step=1 do={\ + \n :set str (\$str.\$5)\ + \n }\ + \n }\ + \n :set str (\$str.\$t.\$3)\ + \n :set rest [:pick \$rest (\$\"str-pos\"+\$\"str-len\") [:len \$re\ + st]]\ + \n :set \"str-pos\" [:find \$rest \$2]\ + \n }\ + \n :return (\$str.\$rest)\ + \n}\ + \n\ + \n:if (\$bound=1) do={\ + \n :local t [:find \$\"lease-address\" \"/\"]\ + \n\ + \n :if ( \$t >= 0 ) do={\ + \n :set \"lease-address\" [:pick \$\"lease-address\" 0 \$t]\ + \n }\ + \n\ + \n :if ( [/interface 6to4 print count-only where name=\$\"IF-TUN\"] = 0\ + ) do={\ + \n /interface 6to4 add !keepalive local-address=\$\"lease-address\"\ + \_mtu=1280 name=\$\"IF-TUN\" remote-address=10.30.30.0\ + \n :set \"force-update\" true\ + \n }\ + \n\ + \n :local \"IPv4-TUN\" [/interface 6to4 get [find name=\$\"IF-TUN\"] lo\ + cal-address];\ + \n\ + \n :if ( \$\"lease-address\" != \$\"IPv4-TUN\" || \$\"force-update\" = \ + true) do={\ + \n /interface 6to4 set [find name=\$\"IF-TUN\"] local-address=\$\"l\ + ease-address\"\ + \n /ipv6 address remove [find interface=\$\"IF-TUN\"]\ + \n /ipv6 address remove [find interface=\$\"IF-LOC\"]\ + \n /ipv6 route remove [find gateway ~ \$\"IF-TUN\" and dst-address=\ + \"::/0\"]\ + \n :local \"pool-prefix\" [\$6to4prefix \$\"lease-address\"]\ + \n :if ( [/ipv6 pool print count-only where name=\$\"POOL-6TO4\"] =\ + \_0) do={ \ + \n /ipv6 pool add name=\$\"POOL-6TO4\" prefix=(\$\"pool-prefix\ + \".\":1::/64\") prefix-length=64\ + \n } else={\ + \n /ipv6 pool set [/ipv6 pool find where name=\$\"POOL-6TO4\"] \ + prefix=(\$\"pool-prefix\".\":1::/64\")\ + \n }\ + \n /ipv6 address add address=(\$\"pool-prefix\".\"::\".[\$MAC2EUI64\ + \_[/interface get [find name=\$\"interface\"] mac-address]].\"/3\") interf\ + ace=\$\"IF-TUN\" advertise=no\ + \n /ipv6 address add eui-64=yes from-pool=\$\"POOL-6TO4\" interface\ + =\$\"IF-LOC\" advertise=yes\ + \n /ipv6 route add dst-address=::/0 gateway=(\"::10.30.30.81%\".\$\ + \"IF-TUN\")\ + \n :local t [/ipv6 address get [find interface=\$\"IF-LOC\"] addres\ + s]\ + \n :set t [:pick \$t 0 [:find \$t \"/\"]]\ + \n :if ( [/ipv6 dhcp-server option print count-only where name=DNS]\ + \_= 0) do={\ + \n /ipv6 dhcp-server option add code=23 name=DNS value=(\"0x\".\ + [\$\"str_replace\" \$t \":\" \"\" 4 \"0\"])\ + \n } else={\ + \n /ipv6 dhcp-server option set [/ipv6 dhcp-server option find \ + where name=DNS] value=(\"0x\".[\$\"str_replace\" \$t \":\" \"\" 4 \"0\"])\ + \n }\ + \n :if ( [/ipv6 dhcp-server print count-only where interface=\$\"IF\ + -LOC\"] = 0) do={\ + \n /ipv6 dhcp-server add address-pool=\$\"POOL-6TO4\" dhcp-opti\ + on=DNS interface=\$\"IF-LOC\" lease-time=1d name=\$\"IF-LOC\"\ + \n }\ + \n :if ( [ipv6 nd print count-only where interface=\$\"IF-LOC\"] = \ + 0) do={\ + \n /ipv6 nd add advertise-dns=no interface=\$\"IF-LOC\" other-c\ + onfiguration=yes\ + \n }\ + \n }\ + \n}" +add dont-require-permissions=no name=IPv6-GlobalFunc owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + global MAC2EUI64 do={\ + \n :local EUI64 \"\"\ + \n :local MAC \$1\ + \n :local HEX2DEC \"0123456789ABCDEF\"\ + \n :for i from=0 to=5 step=1 do={\ + \n :if ( \$i = 0 ) do={\ + \n :set EUI64 [:pick \$MAC 0]\ + \n :set EUI64 (\$EUI64.[:tostr [:pick \$\"HEX2DEC\" ([:find \$\ + \"HEX2DEC\" [:pick \$MAC 1]] ^ 2)]])\ + \n }\ + \n :if ( \$i = 1 || \$i = 3) do={\ + \n :set EUI64 (\$EUI64.\":\")\ + \n }\ + \n :if ( \$i = 2 ) do={\ + \n :set EUI64 (\$EUI64.\"FF:FE\")\ + \n }\ + \n :if ( [:find \$MAC \":\"] = 2 ) do={\ + \n :set MAC [:pick \$MAC 3 [:len \$MAC]]\ + \n :set EUI64 (\$EUI64.[:pick \$MAC 0 2])\ + \n }\ + \n }\ + \n :return (\$EUI64)\ + \n}\ + \n\ + \n:global dec2hex do={\ + \n :local hex \"\"\ + \n :local dec [:tonum \$1]\ + \n :for i from=0 to=4 step=4 do={\ + \n :set hex ([:pick \"0123456789ABCDEF\" ((\$dec>>\$i)&0xf) (((\$de\ + c>>\$i)&0xf)+1)].\$hex)\ + \n }\ + \n :return ([:tostr \$hex])\ + \n}" +add comment=Generator dont-require-permissions=no name=proxySet owner=vados \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + source="# 2. WireGuard interface\r\ + \n/interface/wireguard/add name=wg-VDSina private-key=\"4CHyNhbOs923/EyNDg\ + uMXJXdghL2I3UyzXPwrANVgHs=\" listen-port=21641\r\ + \n/interface/wireguard/peers/add interface=wg-VDSina public-key=\"o5IgCl1/\ + G6xbl6j7sPaP4ZNYREeYOmqZjKbm+v0b9jU=\" preshared-key=\"RNvF7T1cg5tyXcYQnD9\ + N5BEp6e20vVJQTv0GMjyvHU0=\" endpoint-address=10.30.30.33 endpoint-port=518\ + 20 allowed-address=0.0.0.0/0 persistent-keepalive=11\r\ + \n/ip/address/add address=10.9.0.3/32 interface=wg-VDSina\r\ + \n\r\ + \n# 3. DNS\r\ + \n{ :local rawDNS [/ip/dns/get servers]; :local prevDNS \"\"; :foreach s i\ + n=[:toarray \$rawDNS] do={ :if ([:len \$prevDNS] > 0) do={ :set prevDNS \"\ + \$prevDNS,\$s\" } else={ :set prevDNS \$s } }; /system/script/add name=VDS\ + ina-prev-dns comment=\"\$prevDNS\" source=\"\" }\r\ + \n/ip/dns/set servers=8.8.4.4\r\ + \n/ip/route/add dst-address=8.8.4.4/32 gateway=wg-VDSina distance=1 commen\ + t=VDSina-dns\r\ + \n\r\ + \n# 4. Enable WireGuard\r\ + \n/interface/wireguard/enable wg-VDSina\r\ + \n" +add dont-require-permissions=no name=AM-Telegram-Send owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\ + \n# RouterOS script: AM-Telegram-Send\ + \n# Script comment: Mini script for send messages to admin Telegram chat\ + \n# Copyright (c) 2007-2026 Vados \ + \n#\ + \n#\ + \n# requires RouterOS, version=7.19\ + \n# requires device-mode, fetch\ + \n#\ + \n# Script description: \ + \n#\ + \n#\ + \n# Usage:\ + \n# /system/script { run AM-Telegram-Send \"Message here )))\"; }\ + \n\ + \n/system/script\ + \nadd name=telegram-send dont-require-permissions=no source={\ + \n :global TelegramTokenId;\ + \n :global TelegramChatId;\ + \n :local message [:tostr \$1];\ + \n :local identity [/system/identity/get name];\ + \n :local sendMsg (\"[\".\$identity.\"] \".\$message)\ + \n /tool/fetch url=(\"https://api.telegram.org/bot\".\$TelegramTokenId.\\\ + \n \"/sendMessage\\\?chat_id=\".\$TelegramChatId.\\\ + \n \"&text=\".\$sendMsg.\\\ + \n \"&parse_mode=HTML\") \\\ + \n mode=https keep-result=no\ + \n}" +add dont-require-permissions=no name=telegram-send owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="\ + \n :global TelegramTokenId;\ + \n :global TelegramChatId;\ + \n :local message [:tostr \$1];\ + \n :local identity [/system/identity/get name];\ + \n :local sendMsg (\"[\".\$identity.\"] \".\$message)\ + \n /tool/fetch url=(\"https://api.telegram.org/bot\".\$TelegramTokenId.\\\ + \n \"/sendMessage\\\?chat_id=\".\$TelegramChatId.\\\ + \n \"&text=\".\$sendMsg.\\\ + \n \"&parse_mode=HTML\") \\\ + \n mode=https keep-result=no\ + \n" +/user group +add name=backup policy="ssh,read,write,policy,test,web,sniff,sensitive,api,res\ + t-api,!local,!telnet,!ftp,!reboot,!winbox,!password,!romon" +/certificate settings +set builtin-trust-store=all crl-download=yes crl-store=system crl-use=yes +/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 +add bridge=Bridge-LAN disabled=yes interface=Unet-ether1 +/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=all 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 +add exclude=*2000016,LAN include=*2000017 name=WAN +/interface list member +add interface=lo list=LAN +add interface=Unet-ether1 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=0.0.0.0/0 client-allowed-address=::/0 disabled=yes \ + endpoint-address=10.30.30.33 endpoint-port=55055 interface=wg-nuc name=\ + NUC persistent-keepalive=11s public-key=\ + "+OvzAjLC45Td52hjkQPmpGvC3RGhZ+Q2CDMJ1U/D4Rw=" +/interface wireless cap +set bridge=Bridge-LAN caps-man-addresses=10.30.30.10 \ + caps-man-certificate-common-names=CAPsMAN-51B25E507D07 certificate=\ + CAP-488F5A8E1ABC discovery-interfaces=Bridge-LAN 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 +/ip cloud +set update-time=no +/ip dhcp-client +add add-default-route=special-classless comment=Unet-client \ + default-route-distance=2 default-route-tables=main:2 dhcp-options=\ + hostname,clientid_duid,clientid interface=Unet-ether1 name=UnetDHCP \ + use-peer-dns=no use-peer-ntp=no +/ip dhcp-server config +set accounting=no +/ip dhcp-server lease +add address=10.30.30.101 client-id=1:48:8f:5a:8e:ee:a8 mac-address=\ + 48:8F:5A:8E:EE:A8 server=masterDHCP +add address=10.30.30.107 client-id=1:f0:de:f1:91:d:1e mac-address=\ + F0:DE:F1:91:0D:1E server=masterDHCP +add address=10.30.30.83 client-id=1:0:80:77:ec:43:86 mac-address=\ + 00:80:77:EC:43:86 server=masterDHCP +add address=10.30.30.70 dhcp-option=domain-search-list,HostName \ + dhcp-option-set=HP1505n mac-address=00:1E:0B:1A:88:8D server=masterDHCP +add address=10.30.30.50 client-id=1:4:7c:16:36:f5:37 mac-address=\ + 04:7C:16:36:F5:37 server=masterDHCP +add address=10.30.30.71 client-id=1:10:2d:41:2c:20:c2 mac-address=\ + 10:2D:41:2C:20:C2 server=masterDHCP +add address=10.30.30.61 client-id=1:10:8:c1:81:59:5f mac-address=\ + 10:08:C1:81:59:5F server=masterDHCP +add address=10.30.30.72 client-id=1:10:38:1f:d2:5f:13 mac-address=\ + 10:38:1F:D2:5F:13 server=masterDHCP +add address=10.30.30.99 client-id=1:10:b1:df:e9:d0:d5 mac-address=\ + 10:B1:DF:E9:D0:D5 server=masterDHCP +add address=10.30.30.111 client-id=1:fe:2:52:be:3f:16 mac-address=\ + FE:02:52:BE:3F:16 server=masterDHCP +add address=10.30.30.92 client-id=1:d4:6d:6d:fd:e5:49 mac-address=\ + D4:6D:6D:FD:E5:49 server=masterDHCP +add address=10.30.30.93 client-id=1:7e:8b:1e:cb:b8:cb mac-address=\ + CC:42:10:12:46:94 server=masterDHCP +add address=10.30.30.94 client-id=1:50:cc:f8:85:96:a mac-address=\ + 50:CC:F8:85:96:0A server=masterDHCP +add address=10.30.30.82 client-id=1:e4:18:6b:58:34:ab mac-address=\ + E4:18:6B:58:34:AB server=masterDHCP +add address=10.30.30.75 client-id=1:0:27:15:41:97:a9 mac-address=\ + 00:27:15:41:97:A9 server=masterDHCP +add address=10.30.30.77 dhcp-option=HostName dhcp-option-set=StartLife1 \ + mac-address=C4:82:E1:03:49:10 server=masterDHCP +add address=10.30.30.73 client-id=1:10:38:1f:82:81:f2 mac-address=\ + 10:38:1F:82:81:F2 server=masterDHCP +add address=10.30.30.95 client-id=1:88:ae:dd:60:39:54 dhcp-option=HostName \ + dhcp-option-set=VADOS-NUC mac-address=88:AE:DD:60:39:54 server=masterDHCP +add address=10.30.30.98 client-id=1:c8:5b:76:d8:cc:bf dhcp-option=HostName \ + dhcp-option-set=VADOS-LEN mac-address=C8:5B:76:D8:CC:BF server=masterDHCP +add address=10.30.30.96 client-id=iPhone mac-address=4A:91:ED:0E:1F:39 \ + server=masterDHCP +add address=10.30.30.74 client-id=MiTV dhcp-option=HostName dhcp-option-set=\ + MiTV mac-address=20:72:A9:D3:34:36 server=masterDHCP +add address=10.30.30.30 dhcp-option=HostName dhcp-option-set=miller \ + mac-address=F0:75:5D:1E:5F:71 server=masterDHCP +add address=10.30.30.100 client-id=iVados dhcp-option=HostName \ + dhcp-option-set=iVados mac-address=DE:4D:72:F3:1A:9F server=masterDHCP +add address=10.30.30.10 allow-dual-stack-queue=yes client-id=\ + ff:0:0:0:df:0:3:0:1:f0:75:5d:1e:5f:85 dhcp-option=HostName \ + dhcp-option-set=MikroNUC mac-address=F0:75:5D:1E:5F:85 server=masterDHCP \ + use-src-mac=yes +/ip dhcp-server network +add address=0.0.0.0/24 caps-manager=10.30.30.10 dhcp-option=\ + domain-search-list dhcp-option-set=domain-search-set dns-server=0.0.0.0 \ + domain=WORKGROUP gateway=0.0.0.0 netmask=24 ntp-server=\ + 10.30.30.81,10.30.30.10 wins-server=10.30.30.95,10.30.30.98 +add address=10.30.30.0/24 dns-server=10.30.30.81 gateway=10.30.30.81 netmask=\ + 24 +/ip dns +set allow-remote-requests=yes cache-max-ttl=1d doh-max-concurrent-queries=100 \ + doh-max-server-connections=20 servers=10.30.30.33,109.107.177.79,8.8.4.4 \ + verify-doh-cert=yes +/ip dns static +add address=109.107.177.79 comment="VDSina Server DNS" name=ns1.vados.ru \ + type=A +add address=109.107.177.79 name=vds.vados.ru type=A +add comment="Local DNS server for vados.ru" disabled=yes ns=10.30.30.81 \ + regexp=*.vados.ru type=NS +add comment="*.vados.ru Regexp" disabled=yes forward-to=10.30.30.81 regexp=\ + "\".*\\\\.vados\\\\.ru\"" type=FWD +add comment="*.30.30.10.in-addr.arpa Regexp" disabled=yes forward-to=\ + 10.30.30.81 regexp="\".*\\\\.30\\\\.30\\\\.10\\\\.in-addr\\\\.arpa" type=\ + FWD +add address=10.30.30.81 comment=NS.vados.ru.local disabled=yes name=\ + ns.vados.ru.local type=A +add comment="DNS ns.vados.ru.local" disabled=yes match-subdomain=yes name=\ + vados.ru ns=ns.vados.ru.local type=NS +add address=10.30.30.33 comment=reg.vados.ru name=reg.vados.ru type=A +add address=8.8.8.8 comment="Google-dns IPv4 1" match-subdomain=yes name=\ + dns.google type=A +add address=8.8.4.4 comment="Google-dns IPv4 2" name=dns.google type=A +add address=10.30.30.33 comment=AMSTER name=amster.vados.ru type=A +add address=10.30.30.33 name=ros.vados.ru type=A +add address=10.30.30.95 name=vados-nuc type=A +add address=10.30.30.33 name=amster-nuc type=A +add address=10.30.30.33 name=amster type=A +add address=10.30.30.33 name=amster-reg type=A +add address=10.30.30.33 disabled=yes name=mng.vados.ru type=A +add address=10.30.30.33 name=mgr.vados.ru type=A +add address=10.30.30.33 name=prt.vados.ru type=A +add address=10.30.30.33 disabled=yes match-subdomain=yes name=\ + mikrots.vados.ru type=A +add address=10.30.30.30 comment=MILLER name=miller.vados.ru type=A +add address=10.30.30.30 name=MILLER-LEN type=A +add address=10.30.30.30 name=miller type=A +add address=1.0.0.1 comment="CloudFlare-doh IPv4 2" disabled=yes name=\ + security.cloudflare-dns.com type=A +add address=1.1.1.1 comment="CloudFlare-doh IPv4 1" disabled=yes name=\ + security.cloudflare-dns.com type=A +add address=9.9.9.9 comment="Cuad9-dns IPv4 1" disabled=yes name=\ + dns.quad9.net type=A +add address=149.112.112.112 comment="Cuad9-dns IPv4 2" disabled=yes name=\ + dns.quad9.net type=A +add address=195.133.25.16 comment="DNS Comss" disabled=yes name=dns.comss.one \ + type=A +add address=10.30.30.81 comment=LocalNet name=MikroVados type=A +add address=10.30.30.10 name=MikroNUC type=A +add address=10.30.30.86 disabled=yes name=MikroYellow type=A +add address=10.30.30.85 disabled=yes name=MikroMic type=A +add address=10.30.30.95 name=VADOS-NUC type=A +add address=10.30.30.98 name=VADOS-LEN type=A +add address=91.192.189.2 comment=Unet-DNS disabled=yes name=ns1.unet.ws type=\ + A +add address=10.30.30.20 disabled=yes name=garage type=A +/ip firewall address-list +add address=91.215.120.206 list=TRUSTED +add address=185.71.70.78 disabled=yes list=TRUSTED +add address=176.53.203.171 disabled=yes list=TRUSTED +add address=176.53.203.170 disabled=yes list=TRUSTED +add address=176.53.202.194 disabled=yes list=TRUSTED +add address=8.8.4.0/24 list=YouTube +add address=8.8.8.0/24 list=YouTube +add address=8.34.208.0/20 list=YouTube +add address=8.35.192.0/20 list=YouTube +add address=23.236.48.0/20 list=YouTube +add address=23.251.128.0/19 list=YouTube +add address=34.0.0.0/15 list=YouTube +add address=34.2.0.0/16 list=YouTube +add address=34.3.0.0/23 list=YouTube +add address=34.3.3.0/24 list=YouTube +add address=34.3.4.0/24 list=YouTube +add address=34.3.8.0/21 list=YouTube +add address=34.3.16.0/20 list=YouTube +add address=34.3.32.0/19 list=YouTube +add address=34.3.64.0/18 list=YouTube +add address=34.4.0.0/14 list=YouTube +add address=34.8.0.0/13 list=YouTube +add address=34.16.0.0/12 list=YouTube +add address=34.32.0.0/11 list=YouTube +add address=34.64.0.0/10 list=YouTube +add address=34.128.0.0/10 list=YouTube +add address=35.184.0.0/13 list=YouTube +add address=35.192.0.0/14 list=YouTube +add address=35.196.0.0/15 list=YouTube +add address=35.198.0.0/16 list=YouTube +add address=35.199.0.0/17 list=YouTube +add address=35.199.128.0/18 list=YouTube +add address=35.200.0.0/13 list=YouTube +add address=35.208.0.0/12 list=YouTube +add address=35.224.0.0/12 list=YouTube +add address=35.240.0.0/13 list=YouTube +add address=57.140.192.0/18 list=YouTube +add address=64.15.112.0/20 list=YouTube +add address=64.233.160.0/19 list=YouTube +add address=66.22.228.0/23 list=YouTube +add address=66.102.0.0/20 list=YouTube +add address=66.249.64.0/19 list=YouTube +add address=70.32.128.0/19 list=YouTube +add address=72.14.192.0/18 list=YouTube +add address=74.125.0.0/16 list=YouTube +add address=104.154.0.0/15 list=YouTube +add address=104.196.0.0/14 list=YouTube +add address=104.237.160.0/19 list=YouTube +add address=107.167.160.0/19 list=YouTube +add address=107.178.192.0/18 list=YouTube +add address=108.59.80.0/20 list=YouTube +add address=108.170.192.0/18 list=YouTube +add address=108.177.0.0/17 list=YouTube +add address=130.211.0.0/16 list=YouTube +add address=136.22.160.0/20 list=YouTube +add address=136.22.176.0/21 list=YouTube +add address=136.22.184.0/23 list=YouTube +add address=136.22.186.0/24 list=YouTube +add address=142.250.0.0/15 list=YouTube +add address=146.148.0.0/17 list=YouTube +add address=152.65.208.0/22 list=YouTube +add address=152.65.214.0/23 list=YouTube +add address=152.65.218.0/23 list=YouTube +add address=152.65.222.0/23 list=YouTube +add address=152.65.224.0/19 list=YouTube +add address=162.120.128.0/17 list=YouTube +add address=162.216.148.0/22 list=YouTube +add address=162.222.176.0/21 list=YouTube +add address=172.110.32.0/21 list=YouTube +add address=172.217.0.0/16 list=YouTube +add address=172.253.0.0/16 list=YouTube +add address=173.194.0.0/16 list=YouTube +add address=173.255.112.0/20 list=YouTube +add address=192.158.28.0/22 list=YouTube +add address=192.178.0.0/15 list=YouTube +add address=193.186.4.0/24 list=YouTube +add address=199.36.154.0/23 list=YouTube +add address=199.36.156.0/24 list=YouTube +add address=199.192.112.0/22 list=YouTube +add address=199.223.232.0/21 list=YouTube +add address=207.223.160.0/20 list=YouTube +add address=208.65.152.0/22 list=YouTube +add address=208.68.108.0/22 list=YouTube +add address=208.81.188.0/22 list=YouTube +add address=208.117.224.0/19 list=YouTube +add address=209.85.128.0/17 list=YouTube +add address=216.58.192.0/19 list=YouTube +add address=216.73.80.0/20 list=YouTube +add address=216.239.32.0/19 list=YouTube +add address=2ip.ru list=Test-IP +add address=wg.vados.ru comment=VDSIna list=TRUSTED +add address=10.8.0.0/24 comment="WG VDSIna" disabled=yes list=TRUSTED +add address=ikus.pesc.ru comment=ikus.pesc.ru list=NoVdsina +add address=love.ru comment=love.ru list=NoVdsina +add address=gosuslugi.ru comment=gosuslugi.ru list=NoVdsina +add address=pochta.ru comment=pochta.ru list=NoVdsina +add address=vdsina.com list=NoVdsina +add address=vdsina.ru list=NoVdsina +add address=youla.ru list=NoVdsina +add address=kupiprodai.ru list=NoVdsina +add address=myip.ru list=Test-IP +add address=geoip.co list=NoVdsina +add address=comp-lenta.ru list=NoVdsina +add address=128.85.102.70 comment=update.microsoft.com list=\ + windowsupdateslist +add address=wu-b-net.trafficmanager.net. comment=\ + ctldl.windowsupdate.com.delivery.microsoft.com list=windowsupdateslist +add address=ctldl.windowsupdate.com.delivery.microsoft.com. comment=\ + ctldl.windowsupdate.com list=windowsupdateslist +add address=redir.update.msft.com.trafficmanager.net. comment=\ + update.microsoft.com list=windowsupdateslist +add address=geo.prod.do.dsp.trafficmanager.net. comment=\ + geo.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=13.74.139.29 comment=array605.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=kv801.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + kv801.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=e12437.d.akamaiedge.net. comment=\ + kv801.prod.do.dsp.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=displaycatalog-rp.md.mp.microsoft.com.akadns.net. comment=\ + displaycatalog.mp.microsoft.com list=windowsupdateslist +add address=rp-consumer-prod-displaycatalog-geomap.trafficmanager.net. \ + comment=displaycatalog-rp.md.mp.microsoft.com.akadns.net list=\ + windowsupdateslist +add address=sls.update.microsoft.com. comment=slscr.update.microsoft.com \ + list=windowsupdateslist +add address=glb.sls.prod.dcat.dsp.trafficmanager.net. comment=\ + sls.update.microsoft.com list=windowsupdateslist +add address=fe3.delivery.mp.microsoft.com. comment=\ + fe3cr.delivery.mp.microsoft.com list=windowsupdateslist +add address=glb.cws.prod.dcat.dsp.trafficmanager.net. comment=\ + fe3.delivery.mp.microsoft.com list=windowsupdateslist +add address=fe2cr.update.msft.com.trafficmanager.net. comment=\ + fe2cr.update.microsoft.com list=windowsupdateslist +add address=download.windowsupdate.com.delivery.microsoft.com. comment=\ + download.windowsupdate.com list=windowsupdateslist +add address=wu-f-net.trafficmanager.net. comment=\ + download.windowsupdate.com.delivery.microsoft.com list=windowsupdateslist +add address=tsfe.trafficmanager.net. comment=\ + tsfe.trafficshaping.dsp.mp.microsoft.com list=windowsupdateslist +add address=edge.ds-c7110-microsoft.global.dns.qwilted-cds.cqloud.com. \ + comment=9.au.download.windowsupdate.com list=windowsupdateslist +add address=52.158.227.125 comment=array812.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=au.download.windowsupdate.com.delivery.microsoft.com. comment=\ + au.download.windowsupdate.com list=windowsupdateslist +add address=a767.dspw65.akamai.net. comment=\ + download.windowsupdate.com.edgesuite.net list=windowsupdateslist +add address=52.151.58.88 comment=array810.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=consumer-licensing-aks2aks.md.mp.microsoft.com.akadns.net. \ + comment=licensing.mp.microsoft.com list=windowsupdateslist +add address=licensing-prod-frontdoor-geomap.trafficmanager.net. comment=\ + consumer-licensing-aks2aks.md.mp.microsoft.com.akadns.net list=\ + windowsupdateslist +add address=star.f.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedge.f.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=cdp-f-nlu-net.trafficmanager.net. comment=\ + star.f.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=star.b.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedge.b.tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=cdp-f-tlu-net.trafficmanager.net. comment=\ + star.b.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=storeedgefd.xbetservices.akadns.net. comment=\ + storeedgefd.dsx.mp.microsoft.com list=windowsupdateslist +add address=\ + storeedgefd.dsx.mp.microsoft.com.edgekey.net.globalredir.akadns.net. \ + comment=storeedgefd.dsx.mp.microsoft.com.edgekey.net list=\ + windowsupdateslist +add address=e16646.dscg.akamaiedge.net. comment=\ + storeedgefd.dsx.mp.microsoft.com.edgekey.net.globalredir.akadns.net list=\ + windowsupdateslist +add address=40.69.76.189 comment=array621.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=bg.microsoft.map.fastly.net. comment=\ + 3.au.download.windowsupdate.com list=windowsupdateslist +add list=windowsupdateslist +add address=40.69.75.33 comment=array613.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=star.sf.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedgeextensions.sf.tlu.dl.delivery.mp.microsoft.com list=\ + windowsupdateslist +add address=cdp-f-ssl-tlu-net.trafficmanager.net. comment=\ + star.sf.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=a2033.dscd.akamai.net. comment=\ + star.sb.tlu.dl.delivery.mp.microsoft.com.edgesuite.net list=\ + windowsupdateslist +add address=13.74.138.242 comment=array602.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=dl.delivery.mp.microsoft.com.delivery.microsoft.com. comment=\ + dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=dcat-f-nlu-net.trafficmanager.net. comment=\ + dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=1d.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=1D.tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=dcat-b-tlu-net.trafficmanager.net. comment=\ + 1d.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=a122.dscg3.akamai.net. comment=\ + tlu.dl.delivery.mp.microsoft.com.edgesuite.net list=windowsupdateslist +add address=geover.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + geover.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=e10370.d.akamaiedge.net. comment=\ + geover.prod.do.dsp.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=52.232.182.21 comment=array511.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.70.77.95 comment=array519.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=a1683.dscd.akamai.net. comment=\ + dl.delivery.mp.microsoft.com-c.edgesuite.net list=windowsupdateslist +add address=consumer-collections-aks2eap.md.mp.microsoft.com.akadns.net. \ + comment=collections.mp.microsoft.com list=windowsupdateslist +add address=a1847.dscd.akamai.net. comment=\ + wildcard.f.tlu.dl.delivery.mp.microsoft.com.edgesuite.net list=\ + windowsupdateslist +add address=13.74.142.6 comment=array607.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=au.download.windowsupdate.com.edgesuite.net. comment=\ + 2.au.download.windowsupdate.com list=windowsupdateslist +add address=a767.dscg3.akamai.net. comment=\ + au.download.windowsupdate.com.edgesuite.net list=windowsupdateslist +add address=52.156.123.84 comment=array818.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.69.78.254 comment=array610.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=4.au.download.windowsupdate.com.delivery.microsoft.com. comment=\ + 4.au.download.windowsupdate.com list=windowsupdateslist +add address=cl-glcb907925.gcdn.co. comment=\ + 4.au.download.windowsupdate.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=52.167.167.111 comment=array510.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=40.69.70.43 comment=array623.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=tsfe.trafficshaping.dsp.mp.microsoft.com.delivery.microsoft.com. \ + comment=tsfe.trafficshaping.dsp.mp.microsoft.com list=windowsupdateslist +add address=ts-frontend.trafficmanager.net. comment=\ + tsfe.trafficshaping.dsp.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=40.69.75.248 comment=array616.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.69.74.84 comment=array615.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=sds.trafficmanager.net. comment=software-download.microsoft.com \ + list=windowsupdateslist +add address=40.69.74.80 comment=array611.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.175.242.182 comment=array804.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=dlc-shim.trafficmanager.net. comment=download.microsoft.com list=\ + windowsupdateslist +add address=e12671.dscd.akamaiedge.net. comment=\ + download.microsoft.com.edgekey.net list=windowsupdateslist +add address=20.187.55.34 comment=array808.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.167.231 comment=array513.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=52.167.222.13 comment=array518.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=kv601.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + kv601.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=e12358.d.akamaiedge.net. comment=\ + kv601.prod.do.dsp.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. comment=\ + tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=dcat-f-tlu-net.trafficmanager.net. comment=\ + tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=a1856.dspw65.akamai.net. comment=\ + tlu.dl.delivery.mp.microsoft.com-c.edgesuite.net list=windowsupdateslist +add address=52.167.164.252 comment=array506.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=13.74.137.54 comment=array601.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=kv501.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + kv501.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=collections-prod-frontdoor-geomap.trafficmanager.net. comment=\ + consumer-collections-aks2eap.md.mp.microsoft.com.akadns.net list=\ + windowsupdateslist +add address=52.167.160.173 comment=array509.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=40.70.77.148 comment=array516.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.200.126 comment=array507.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=52.167.167.59 comment=array508.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.69.76.172 comment=array620.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=smtp.mail.me.com comment=smtp.mail.me.com list=NoVdsina +add address=40.70.76.5 comment=array514.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.186.119 comment=array618.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.177.176.186 comment=array520.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=40.70.76.27 comment=array515.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.160.43 comment=array503.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.110 comment=array817.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.142.8 comment=array614.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.138.254 comment=array603.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.167.96 comment=array501.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.69.76.215 comment=array622.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.143.200 comment=array606.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.111 comment=array818.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.112 comment=array819.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.137.53 comment=array608.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.98 comment=array805.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.96 comment=array803.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.104 comment=array811.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.101 comment=array808.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.99 comment=array806.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.17 comment=array802.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.97 comment=array804.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.103 comment=array810.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.16 comment=array801.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.70.77.177 comment=array517.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.164.84 comment=array512.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.105 comment=array812.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.107 comment=array814.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.232.161.82 comment=array502.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.108 comment=array815.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.161.91 comment=array505.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.102 comment=array809.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.109 comment=array816.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.106 comment=array813.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.117 comment=array622.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.107 comment=array612.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.108 comment=array613.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.105 comment=array610.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.113 comment=array618.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.116 comment=array621.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.98 comment=array603.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.114 comment=array619.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.111 comment=array616.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.97 comment=array602.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.106 comment=array611.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.110 comment=array615.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.119 comment=array624.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.135 comment=array514.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.97 comment=array503.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.99 comment=array604.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.61 comment=array504.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.131 comment=array510.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.132 comment=array511.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.96 comment=array601.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.104 comment=array609.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.138 comment=array517.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.60 comment=array501.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.139 comment=array518.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.118 comment=array623.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.113 comment=array820.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.103 comment=array608.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.100 comment=array807.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.129 comment=array508.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.134 comment=array513.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.62 comment=array505.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.137 comment=array516.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.101 comment=array606.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.96 comment=array502.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.130 comment=array509.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.112 comment=array617.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.100 comment=array605.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.115 comment=array620.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.136 comment=array515.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=purchase.md.mp.microsoft.com.akadns.net. comment=\ + purchase.mp.microsoft.com list=windowsupdateslist +add address=e110219.a.akamaiedge.net. comment=\ + purchase.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=72.153.5.140 comment=array519.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.141 list=windowsupdateslist +add address=72.153.5.63 comment=array506.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.128 comment=array507.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.102 comment=array607.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=storesdk.xbetservices.akadns.net. comment=\ + storesdk.dsx.mp.microsoft.com list=windowsupdateslist +add address=e16646.g.akamaiedge.net. comment=\ + storesdk.dsx.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=software-download.microsoft.com.delivery.microsoft.com. comment=\ + software-download.microsoft.com list=windowsupdateslist +add address=download.prss.microsoft.com.akamaized.net. comment=\ + software-download.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.109 comment=array614.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.133 comment=array512.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=213.180.192.0/19 comment=YandexDisk list=NoVdsina +add address=87.250.250.50 comment=YandexDisk list=NoVdsina +add address=consumer-prod-bcfd-v7-afd.trafficmanager.net. comment=\ + displaycatalog.mp.microsoft.com list=windowsupdateslist +add address=purchase-europeeap.md.mp.microsoft.com.akadns.net. comment=\ + purchase.md.mp.microsoft.com.akadns.net list=windowsupdateslist +add address=ne-az-conspurchase-mp.trafficmanager.net. comment=\ + purchase-europeeap.md.mp.microsoft.com.akadns.net list=windowsupdateslist +add address=storeedgefd.dsx.mp.microsoft.com.edgekey.net. comment=\ + cdn.storeedgefd.dsx.mp.microsoft.com list=windowsupdateslist +add address=star.f.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedge.f.tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=a1996.dscd.akamai.net. comment=\ + wildcard.f.dl.delivery.mp.microsoft.com.edgesuite.net list=\ + windowsupdateslist +add address=cp801.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + cp801.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=glb.tas02.sls-prod.dcat.dsp.mp.microsoft.com. comment=\ + tas02.sls.update.microsoft.com list=windowsupdateslist +add address=cp601.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + cp601.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=star.sb.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedgeextensions.sb.tlu.dl.delivery.mp.microsoft.com list=\ + windowsupdateslist +add address=star.sf.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedge.sf.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=cdp-f-ssl-nlu-net.trafficmanager.net. comment=\ + star.sf.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=tm-pifd-prod-gbl-weight.trafficmanager.net. comment=\ + paymentinstruments.mp.microsoft.com list=windowsupdateslist +add address=10.30.30.33 comment=amster list=NoWG +add address=10.30.30.10 comment=MikroNUC disabled=yes list=NoWG +add address=89.110.101.17 comment=!!!VDSINA!!!! disabled=yes list=NoWG +add address=wg.vados.ru comment=VDSina-vpn list=VDSina +add address=80.85.244.9 list=TRUSTED +add address=disc801.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + disc801.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=185.71.70.78 disabled=yes list=TRUSTED +add address=176.53.203.171 disabled=yes list=TRUSTED +add address=176.53.203.170 disabled=yes list=TRUSTED +add address=176.53.202.194 disabled=yes list=TRUSTED +add address=89.110.101.17 comment="!!!VDSina Server!!!" list=NoVdsina +add address=dns.quad9.net comment=Quad9-dns disabled=yes list=Trusted-DNS +add address=dns.google comment=Google-dns list=Trusted-DNS +add address=security.cloudflare-dns.com comment=CloudFlare-dns list=\ + Trusted-DNS +add address=time.google.com comment=Google-time list=Trusted-NTP +add address=0.ru.pool.ntp.org comment=ru.pool.ntp.org disabled=yes list=\ + Trusted-NTP +add address=1.ru.pool.ntp.org disabled=yes list=Trusted-NTP +add address=2.ru.pool.ntp.org comment=2.ru.pool.ntp.org disabled=yes list=\ + Trusted-NTP +add address=3.ru.pool.ntp.org comment=3.ru.pool.ntp.org disabled=yes list=\ + Trusted-NTP +add address=cp.vdsina.com comment=VDSina-vpn list=VDSina +add address=vdsina.ru comment=VDSina-vpn list=VDSina +add address=ns.vados.ru comment=VDSina-vpn list=VDSina +add address=vdsina.com comment=VDSina-vpn list=VDSina +add address=cp.vdsina.ru comment=VDSina-vpn list=VDSina +add address=ns1.vdsina.ru comment=VDSina-vpn list=VDSina +add address=10.30.30.0/24 comment="Local Network" list=Local-Net +add address=10.8.0.0/24 comment="WireGuard Network" list=Local-Net +add address=146.120.64.208/29 comment="External Net" list=Unet +add address=esia.gosuslugi.ru comment=esia.gosuslugi.ru list=NoVdsina +add address=lk.gosuslugi.ru comment=lk.gosuslugi.ru list=NoVdsina +add address=trudvsem.ru comment=trudvsem.ru list=NoVdsina +add address=10.30.30.30 comment=miller disabled=yes list=NoWG +add address=10.30.30.33 comment="Direct connet to DNS servers" list=\ + Direct-DNS +add address=109.107.177.79 list=VPN-Server +add address=10.0.0.0/8 list=RFC1918 +add address=172.16.0.0/12 list=RFC1918 +add address=192.168.0.0/16 list=RFC1918 +add address=8.8.4.4 disabled=yes list=to_vpn +add address=myip.ru disabled=yes list=to_vpn +add address=10.30.30.98 disabled=yes list=to_vpn +/ip firewall filter +add action=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=output comment="accept WireGuard" disabled=yes \ + dst-address-list=VPN-Server out-interface=Unet-ether1 protocol=udp \ + src-port=13231 +add action=accept chain=output dst-address-list=VPN-Server dst-port=29185 \ + out-interface=Unet-ether1 protocol=udp +add action=fasttrack-connection chain=forward comment="defconf: fasttrack" \ + connection-state=established,related,new disabled=yes routing-mark=\ + !To-VPN +add action=accept chain=output disabled=yes protocol=tcp src-port=443 +add action=accept chain=output disabled=yes src-address=127.0.0.1 +add action=accept chain=forward comment="defconf: accept in ipsec policy" \ + disabled=yes ipsec-policy=in,ipsec +add action=accept chain=forward comment="defconf: accept out ipsec policy" \ + disabled=yes ipsec-policy=out,ipsec +add action=accept chain=forward comment=\ + "defconf: accept established,related, untracked" connection-state=\ + established,related,untracked disabled=yes +add action=drop chain=forward comment="defconf: drop invalid" \ + connection-state=invalid in-interface=Unet-ether1 src-address=\ + !10.30.30.0/24 +add action=drop chain=forward comment=\ + "defconf: drop all from WAN not DSTNATed" connection-nat-state=!dstnat \ + connection-state=new in-interface=Unet-ether1 src-address-list=!VDSina +add action=accept chain=input protocol=icmp +add action=accept chain=input connection-state=established +add action=accept chain=input connection-state=related +add action=drop chain=input in-interface-list=!LAN +/ip firewall mangle +add action=accept chain=prerouting comment=RFC1918 dst-address-list=RFC1918 \ + in-interface-list=!LAN +add action=mark-connection chain=prerouting comment=\ + "Mark connection \"no-mark\" to NoWG" disabled=yes new-connection-mark=\ + no-mark src-address-list=NoWG +add action=mark-connection chain=prerouting comment=\ + "Mark connection \"no-mark\" to NoVdsina" disabled=yes dst-address-list=\ + NoVdsina new-connection-mark=no-mark src-address=10.30.30.0/24 +add action=mark-connection chain=prerouting comment=\ + "Transit for address-list \"to_vpn\"" connection-mark=!no-mark disabled=\ + yes dst-address-list=to_vpn new-connection-mark=to-vpn-conn routing-mark=\ + To-VPN +add action=mark-routing chain=prerouting comment=\ + "Find routing over table r_to_vpn" connection-mark=to-vpn-conn disabled=\ + yes in-interface-list=!LAN new-routing-mark=*401 +add action=mark-connection chain=prerouting comment=\ + "Mark connection \"no-mark\" to VDSina" disabled=yes dst-address-list=\ + VPN-Server new-connection-mark=no-mark passthrough=no src-address=\ + 10.30.30.0/24 +add action=mark-connection chain=prerouting comment=\ + "Mark Routing main for MikroNuc" disabled=yes dst-address-list=AWG-Proxy \ + new-connection-mark=no-mark 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=change-mss chain=forward comment="MSS on WG (1380)" \ + connection-mark=!no-mark disabled=yes dst-address=!10.30.30.0/24 new-mss=\ + 1380 out-interface=WG protocol=tcp routing-mark=To-VPN src-address=\ + 10.30.30.0/24 tcp-flags=syn tcp-mss=1381-65535 +add action=mark-routing chain=prerouting comment="WG for all" \ + connection-mark=!no-mark disabled=yes dst-address=!10.30.30.0/24 \ + dst-address-list=!NoVdsina new-routing-mark=To-VPN 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" connection-mark=!no-mark \ + disabled=yes dst-address-list=!NoVdsina new-connection-mark=\ + VPN_No_FastTrack routing-mark=To-VPN src-address=10.30.30.0/24 \ + src-address-list=!NoWG +add action=mark-routing chain=prerouting comment="VPN Network" disabled=yes \ + dst-address=10.8.0.0/24 new-routing-mark=To-VPN src-address=10.30.30.0/24 +add action=mark-connection chain=output comment="For this router" \ + connection-mark=no-mark disabled=yes dst-address-list=to_vpn \ + new-connection-mark=to-vpn-conn-local +add action=mark-routing chain=output comment="For this router" \ + connection-mark=to-vpn-conn-local disabled=yes new-routing-mark=*401 +/ip firewall nat +add action=redirect chain=dstnat comment="udp Redirect DNS in NAT" disabled=\ + yes dst-port=53 protocol=udp src-address=10.30.30.0/24 src-address-list=\ + !NoWG to-addresses=10.30.30.33 to-ports=53 +add action=redirect chain=dstnat comment="tcp Redirect DNS in NAT" disabled=\ + yes dst-port=53 protocol=tcp src-address=10.30.30.0/24 src-address-list=\ + !NoWG to-addresses=10.30.30.33 to-ports=53 +add action=masquerade chain=srcnat comment=\ + "Nat Addresses for routing mark r_to_vpn" disabled=yes routing-mark=*401 +add action=dst-nat chain=dstnat comment=\ + "53/tcp dst-nat to amster.loc. From VDSina Server" dst-port=53 \ + in-interface=Unet-ether1 protocol=tcp src-address-list=VPN-Server \ + to-addresses=10.30.30.33 to-ports=53 +add action=dst-nat chain=dstnat comment=\ + "53/udp dst-nat to amster.loc. From VDSina Server" dst-port=53 protocol=\ + udp src-address-list=VPN-Server to-addresses=10.30.30.33 to-ports=53 +add action=dst-nat chain=dstnat disabled=yes dst-port=44333 in-interface=\ + Unet-ether1 protocol=udp src-address=!10.30.30.0/24 to-addresses=\ + 10.30.30.33 to-ports=44333 +add action=masquerade chain=srcnat comment=WG disabled=yes dst-address=\ + !10.30.30.0/24 dst-address-list=!NoVdsina out-interface=WG routing-mark=\ + To-VPN src-address=10.30.30.0/24 src-address-list=!NoWG +add action=masquerade chain=srcnat comment="Default NAT" dst-address=\ + !10.30.30.0/24 out-interface=Unet-ether1 routing-mark=!To-VPN \ + src-address=10.30.30.0/24 +add action=dst-nat chain=dstnat disabled=yes dst-port=44044 in-interface=\ + Unet-ether1 protocol=udp src-address=109.107.177.79 to-addresses=\ + 10.30.30.33 to-ports=44044 +add action=dst-nat chain=dstnat comment=amster.vados.ruhttps dst-port=443 \ + fragment=no in-interface=Unet-ether1 protocol=tcp routing-mark=main \ + to-addresses=10.30.30.33 to-ports=443 +add action=dst-nat chain=dstnat comment="amster.vados.ru For Certbot HTTP" \ + dst-port=80 in-interface=Unet-ether1 protocol=tcp to-addresses=\ + 10.30.30.33 to-ports=80 +add action=dst-nat chain=dstnat comment="amster.vados.ru 3x-ui" disabled=yes \ + dst-port=2904 in-interface=Unet-ether1 protocol=tcp to-addresses=\ + 10.30.30.33 to-ports=2904 +add action=dst-nat chain=dstnat comment=reg.vados.ru disabled=yes dst-port=\ + 5000 in-interface=Unet-ether1 protocol=tcp to-addresses=10.30.30.33 \ + to-ports=5000 +add action=dst-nat chain=dstnat comment="Docker swarm" disabled=yes dst-port=\ + 2377 in-interface=Unet-ether1 protocol=tcp to-addresses=10.30.30.33 \ + to-ports=2377 +add action=dst-nat chain=dstnat comment=npm dst-port=81 in-interface=\ + Unet-ether1 protocol=tcp routing-mark=To-VPN to-addresses=10.30.30.33 \ + to-ports=81 +add action=dst-nat chain=dstnat comment=SSH dst-port=22 in-interface=\ + Unet-ether1 protocol=tcp src-address-list=TRUSTED to-addresses=\ + 10.30.30.33 to-ports=22 +add action=dst-nat chain=dstnat comment="portainer agent" disabled=yes \ + dst-port=2377 in-interface=Unet-ether1 protocol=tcp to-addresses=\ + 10.30.30.33 to-ports=2377 +add action=dst-nat chain=dstnat disabled=yes dst-port=22 in-interface=\ + Unet-ether1 protocol=tcp routing-mark=!To-VPN to-addresses=10.30.30.33 \ + to-ports=22 +add action=dst-nat chain=dstnat comment="Yandex.DNS Family" disabled=yes \ + dst-port=53 in-interface=Bridge-LAN protocol=udp src-address-list=KIDS \ + time=6h-15m,sun,mon,tue,wed,thu,fri,sat to-addresses=77.88.8.3 +add action=dst-nat chain=dstnat disabled=yes dst-port=53 in-interface=\ + Bridge-LAN protocol=tcp src-address-list=KIDS time=\ + 6h-15m,sun,mon,tue,wed,thu,fri,sat to-addresses=77.88.8.3 +/ip firewall raw +add action=drop chain=prerouting comment="Drop Honeypot Hackers" \ + in-interface=Unet-ether1 src-address-list="Honeypot Hacker" +add action=accept chain=prerouting comment="Trusted DNS" disabled=yes \ + in-interface-list=*2000012 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 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 www disabled=yes port=8080 +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=*15 port=18443 +/ip service webserver +set acme-plain=no crl-plain=no graphs-plain=no graphs-secure=no index-plain=\ + no index-secure=no rest-plain=no rest-secure=no scep-plain=no \ + webfig-plain=no webfig-secure=no +/ip ssh +set forwarding-enabled=both publickey-authentication-options=verify-required +/ip upnp +set enabled=yes +/ip upnp interfaces +add interface=Bridge-LAN type=internal +add forced-ip=146.120.64.211 interface=Unet-ether1 type=external +add forced-ip=109.107.177.79 interface=*E type=external +add interface=lo type=internal +add interface=wlan2 type=internal +add interface=wlan1 type=internal +/ipv6 dhcp-client +add add-default-route=yes disabled=yes interface=*F rapid-commit=no request=\ + info use-interface-duid=yes validate-server-duid=no +/ipv6 dhcp-server option sets +add name=domain-search-set options=domain-search-list +add name="=\"Client ID\"" options=HostName +/ipv6 firewall address-list +add address=::/128 comment="defconf: unspecified address" list=bad_ipv6 +add address=::1/128 comment="defconf: lo" list=bad_ipv6 +add address=fec0::/10 comment="defconf: site-local" list=bad_ipv6 +add address=::ffff:0.0.0.0/96 comment="defconf: ipv4-mapped" list=bad_ipv6 +add address=::/96 comment="defconf: ipv4 compat" list=bad_ipv6 +add address=100::/64 comment="defconf: discard only " list=bad_ipv6 +add address=2001:db8::/32 comment="defconf: documentation" list=bad_ipv6 +add address=2001:10::/28 comment="defconf: ORCHID" list=bad_ipv6 +add address=3ffe::/16 comment="defconf: 6bone" list=bad_ipv6 +/ipv6 firewall filter +add action=accept chain=input comment=\ + "defconf: accept established,related,untracked" connection-state=\ + established,related,untracked +add action=drop chain=input comment="defconf: drop invalid" connection-state=\ + invalid +add action=accept chain=input comment="defconf: accept ICMPv6" protocol=\ + icmpv6 +add action=accept chain=input comment="defconf: accept UDP traceroute" \ + dst-port=33434-33534 protocol=udp +add action=accept chain=input comment=\ + "defconf: accept DHCPv6-Client prefix delegation." dst-port=546 protocol=\ + udp src-address=fe80::/10 +add action=accept chain=input comment="defconf: accept IKE" dst-port=500,4500 \ + protocol=udp +add action=accept chain=input comment="defconf: accept ipsec AH" protocol=\ + ipsec-ah +add action=accept chain=input comment="defconf: accept ipsec ESP" protocol=\ + ipsec-esp +add action=accept chain=input comment=\ + "defconf: accept all that matches ipsec policy" ipsec-policy=in,ipsec +add action=drop chain=input comment=\ + "defconf: drop everything else not coming from LAN" in-interface-list=\ + !LAN +add action=accept chain=forward comment=\ + "defconf: accept established,related,untracked" connection-state=\ + established,related,untracked +add action=drop chain=forward comment="defconf: drop invalid" \ + connection-state=invalid +add action=drop chain=forward comment=\ + "defconf: drop packets with bad src ipv6" src-address-list=bad_ipv6 +add action=drop chain=forward comment=\ + "defconf: drop packets with bad dst ipv6" dst-address-list=bad_ipv6 +add action=drop chain=forward comment="defconf: rfc4890 drop hop-limit=1" \ + hop-limit=equal:1 protocol=icmpv6 +add action=accept chain=forward comment="defconf: accept ICMPv6" protocol=\ + icmpv6 +add action=accept chain=forward comment="defconf: accept HIP" protocol=139 +add action=accept chain=forward comment="defconf: accept IKE" dst-port=\ + 500,4500 protocol=udp +add action=accept chain=forward comment="defconf: accept ipsec AH" protocol=\ + ipsec-ah +add action=accept chain=forward comment="defconf: accept ipsec ESP" protocol=\ + ipsec-esp +add action=accept chain=forward comment=\ + "defconf: accept all that matches ipsec policy" ipsec-policy=in,ipsec +add action=drop chain=forward comment=\ + "defconf: drop everything else not coming from LAN" in-interface-list=\ + !LAN +/ipv6 nd +set [ find default=yes ] advertise-dns=yes disabled=yes interface=Bridge-LAN \ + managed-address-configuration=yes other-configuration=yes pref64=::/64 +/ipv6 nd prefix +add autonomous=no disabled=yes interface=Bridge-LAN on-link=no prefix=none +/ipv6 nd prefix default +set dhcp6-pd-preferred=yes +/ipv6 nd proxy +add disabled=yes interface=lo +/ipv6 nd settings +set router-advertisement-route-distance=100 +/routing settings +set single-process=no +/system clock +set time-zone-name=Europe/Moscow +/system clock manual +set time-zone=+03:00 +/system identity +set name=MikroMaster +/system logging +add action=email disabled=yes regex="* added|changed|removed *" topics=\ + system,info +/system ntp client +set enabled=yes +/system ntp server +set enabled=yes manycast=yes multicast=yes use-local-clock=yes +/system ntp client servers +add address=0.ru.pool.ntp.org +add address=1.ru.pool.ntp.org +add address=2.ru.pool.ntp.org +add address=3.ru.pool.ntp.org +add address=time.google.com +/system package update +set check-certificate=yes-without-crl ip-version=ipv4 +/system scheduler +add comment="Every Day Set Global Environment Variables" name=AM-SetGlobalEnv \ + on-event="/system/script { run AM-GlobalConfig; run AM-GlobalFunc; }" \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-time=startup +add comment="Every Day Check For Update Scripts" interval=1d name=\ + AM-ScriptInstallUpdate on-event=\ + ":global ScriptInstallUpdate; \$ScriptInstallUpdate;" policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-time=startup +add comment="Update RKN DNS Looup" disabled=yes interval=20m name=\ + AM-RKN-dnsLookup on-event="/system/script { run AM-RKN-dnsLookup; }" \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-time=startup +/system watchdog +set watchdog-timer=no +/tool e-mail +set certificate-verification=no from=MikroVados port=587 \ + server=smtp.mail.me.com tls=starttls user=vadossio@icloud.com +/tool mac-server +set allowed-interface-list=LAN +/tool mac-server mac-winbox +set allowed-interface-list=LAN +/tool netwatch +add certificate=DigiCert-Global-Root-CA check-certificate=no comment="doh, doh\ + -url=https://security.cloudflare-dns.com/dns-query, notify, name=CloudFlar\ + e-doh IPv4 1" disabled=yes down-script="" host=1.1.1.1 http-codes="" \ + interval=10s name="CloudFlare-doh IPv4 1" port=443 test-script="" type=\ + https-get up-script="" +add check-certificate=no comment="doh-fallback, doh-url=https://security.cloud\ + flare-dns.com/dns-query, doh-cert=DigiCert Global Root CA, notify, name=Cl\ + oudFlare-doh IPv4" disabled=yes down-script="" host=1.0.0.1 http-codes="" \ + name="CloudFlare-doh IPv4" port=443 test-script="" type=https-get \ + up-script="" +add comment="dns, notify, name=Google-DNS IPv4" disabled=yes dns-server=\ + 8.8.8.8 down-script="" host=dns.google http-codes="" name=\ + "Google-DNS IPv4" test-script="" type=dns up-script="" +add certificate=GTS-Root-R4 check-certificate=yes comment="doh-fallback, doh-u\ + rl=https://dns.google/dns-query, doh-cert=GTS Root R1, notify, name=Google\ + -DOH IPv4" disabled=yes dns-server=8.8.4.4 down-script="" host=dns.google \ + http-codes="" name="Google-DOH IPv4" port=443 record-type=NS src-address=\ + "" test-script="" type=dns up-script="" +add comment="dns-fallback, notify, name=Cuad9-DOH IPv4" disabled=yes \ + dns-server=9.9.9.9 down-script="" host=dns9.quad9.net http-codes="" \ + interval=10s name="Cuad9-DOH IPv4" src-address=146.120.64.211 \ + test-script="" timeout=800ms type=dns up-script="" +add certificate=DigiCert-Assured-ID-Root-CA comment="doh-fallback, doh-url=htt\ + ps://dns.quad9.net/dns-query, name=Cuad9-DOH IPv4" disabled=yes \ + down-script="" host=149.112.112.112 http-codes="" interval=10s name=\ + "Cuad9-DOH IPv4" port=443 test-script="" type=https-get up-script="" +add comment="dns-fallback, notify, name=ns1.unet.ws" disabled=yes \ + down-script="" host=91.192.189.2 http-codes="" interval=10s name=\ + ns1.unet.ws test-script="" type=simple up-script="" +add check-certificate=yes comment=\ + "doh, doh-url=https://vds.vados.ru/vds-query, name=vds.vados.ru" \ + disabled=yes down-script="" host=109.107.177.79 http-codes="" name=\ + vds.vados.ru port=443 test-script="" type=https-get up-script="" +add comment="WireGuard NAT " disabled=yes down-script="/log info \"[WG-Monitor\ + ] WireGuard is NOT running - reverting rules\"\ + \n/ip firewall nat remove [find comment=\"Redirect to Router\"]\ + \n/ip dns set servers=8.8.8.8\ + \n/ip dns cache flush\ + \n/ip route remove [find comment=\"wg-auto-route\"]\ + \n" host=10.8.0.1 http-codes="" interval=15s name=WG test-script="" \ + timeout=5s type=simple up-script="/log info \"[WG-Monitor] WireGuard is RU\ + NNING - applying rules\";\ + \n:local routeFile \"ips.txt\";\ + \n:local routeDefAddr \"0.0.0.0/0\";\ + \n:local routeGateway \"10.8.0.1\";\ + \n:local routeIF \"WG\";\ + \n:local routeTable \"To-VPN\";\ + \n:local routeComment \"wg-auto-route\";\ + \n/ip dns cache flush;\ + \n:if ([:len [/ip firewall nat find comment=\"Redirect to Router\"]] > 0) \ + do={\ + \n /ip firewall nat remove [find comment=\"Redirect to Router\"];\ + \n}\ + \n/ip firewall nat add action=redirect chain=dstnat src-address-list=\"Red\ + irectDNS\" dst-port=53 protocol=udp comment=\"Redirect to Router\";\ + \n/ip dns set servers=\$routeGateway;\ + \n:local content [/file get \$routeFile contents];\ + \n:if ([:len \$content] > 0) do={\ + \n :local line \"\";\ + \n :for i from=0 to=([:len \$content] - 1) do={\ + \n :local char [:pick \$content \$i];\ + \n :if (\$char != \"\\r\" && \$char != \"\\n\") do={\ + \n :set line (\$line . \$char);\ + \n } else={\ + \n :if ([:len \$line] > 5) do={\ + \n :do { /ip route add disabled=no dst-address=\$routeDefAd\ + dr gateway=\$routeIF distance=1 scope=30 target-scope=10 routing-table=\$r\ + outeTable comment=\$routeComment check-gateway=none } on-error={}\ + \n }\ + \n :set line \"\";\ + \n }\ + \n }\ + \n :if ([:len \$line] > 5) do={\ + \n# :do { /ip route add dst-address=\$line gateway=\$routeGateway \ + distance=1 comment=\$routeComment } on-error={}\ + \n :do { /ip route add disabled=no dst-address=\$routeDefAddr ga\ + teway=\$routeIF distance=1 scope=30 target-scope=10 routing-table=\$routeT\ + able comment=\$routeComment check-gateway=none } on-error={}\ + \n }\ + \n}\ + \n:local dotPos [:find \$routeGateway \".\"];\ + \n:if (\$dotPos != \"\") do={\ + \n :local firstOctet [:pick \$routeGateway 0 \$dotPos];\ + \n :local derivedDstAddress (\$firstOctet . \".30.0.0/15\");\ + \n :do { /ip route add dst-address=\$derivedDstAddress gateway=\$routeG\ + ateway distance=1 comment=\$routeComment } on-error={}\ + \n}\ + \n\ + \n" +add comment=WG-Default disabled=yes down-script=\ + "/ip route disable [find comment=\"WG-Default\"];" host=10.8.0.1 \ + interval=15s name=WG packet-count=20 test-script="" thr-loss-count=5 \ + type=icmp up-script="/ip route enable [find comment=\"WG-Default\"];" +/user aaa +set accounting=no -- 2.52.0