From a85e847b4b0bf8f131b2267a6484d02704920cef Mon Sep 17 00:00:00 2001 From: vados-dev Date: Mon, 29 Jun 2026 09:02:38 +0300 Subject: [PATCH] Backup for MikroGig created successfully at Jun 29 09:02:38. --- .../20260629/20260629090234-Binary.backup | Bin 0 -> 177026 bytes MikroGig/20260629/20260629090234-Config.rsc | 2776 +++++++++++++ .../20260629/20260629090234-Diff-Config.rsc | 14 + .../20260629/20260629084007-Config.rsc | 3692 +++++++++++++++++ MikroMaster/tmp/Diff-Config.rsc | 35 - 5 files changed, 6482 insertions(+), 35 deletions(-) create mode 100644 MikroGig/20260629/20260629090234-Binary.backup create mode 100644 MikroGig/20260629/20260629090234-Config.rsc create mode 100644 MikroGig/history/20260629/20260629090234-Diff-Config.rsc create mode 100644 MikroMaster/20260629/20260629084007-Config.rsc delete mode 100644 MikroMaster/tmp/Diff-Config.rsc diff --git a/MikroGig/20260629/20260629090234-Binary.backup b/MikroGig/20260629/20260629090234-Binary.backup new file mode 100644 index 0000000000000000000000000000000000000000..6b9c3738e0acf46e9b2b162efa4e96b78c0a5b8b GIT binary patch literal 177026 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\"data\");\r\ + \n#:global NewScript (a);\r\ + \n#:global ScriptInstallUpdate; \$ScriptInstallUpdate;\r\ + \n#\r\ + \n# For run from terminal:\r\ + \n#/system/script/add name=AM-setup owner=AM-Setup source=([/tool/fetch ch\ + eck-certificate=yes-without-crl \"https://ros.vados.ru/AM-setup.rsc\" outp\ + ut=user as-value ]->\"data\");\r\ + \n#\r\ + \n\r\ + \n: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/702/b3f31455\";\r\ + \n:global CommitTAG \"unknown\";\r\ + \n:global CommitInfo \"Autocommit in repo: ros.vados.ru, generated by owne\ + r: root, in 07:15:04 28.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" +/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 +# killed due to out of memory +add cpu-list=cpu1,cpu3 domain-name=vados.ru envlists=awgui-env file=\ + usb1/tmp/awg2-webui.tar hostname=mikronuc interface=veth-awg layer-dir=\ + /usb1/docker logging=yes memory-high=12.0MiB memory-max=16.0MiB name=\ + awg2-webui root-dir=/usb1/awg-webui shm-size=8.0MiB start-on-boot=yes \ + tmpfs=/tmpfs:512.0MiB:01000 +/container config +set layer-dir=/usb1/docker memory-high=2048.0KiB memory-max=2048.0KiB \ + registry-url=https://registry-1.docker.io tmpdir=/tmp username=amsternl +/container envs +add key=AWG_ENDPOINT list=awgui-env value=10.30.30.10:443 +add key=SECRET_KEY list=awgui-env value=RanDomSecret32SymboLs2325272931q +add key=WEB_PASS list=awgui-env value=zoomzoomrulezz +add key=WEB_USER list=awgui-env value=vados +/disk settings +set auto-media-interface=lo +/interface bridge port +add bridge=Bridge-LAN interface=ether1 +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=*D interface=*C +add bridge=*F interface=*E +add bridge=*11 interface=*10 +add bridge=*13 interface=*12 +add bridge=*15 interface=*14 +add bridge=br-awg interface=veth-awg +/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=static internet-interface-list=Internet \ + lan-interface-list=LAN wan-interface-list=WAN +/interface list member +add interface=ether2 list=LAN +add interface=ether3 list=LAN +add interface=ether4 list=LAN +add interface=ether5 list=LAN +add interface=wlan2 list=LAN +add interface=wlan1 list=LAN +add interface=ether1 list=Internet +add interface=Bridge-LAN list=LAN +/interface wireless cap +# +set bridge=Bridge-LAN caps-man-addresses=10.30.30.10 \ + caps-man-certificate-common-names=CAPsMAN-51B25E507D07 certificate=\ + CAP-18FD746E5814 discovery-interfaces=Bridge-LAN enabled=yes interfaces=\ + wlan1,wlan2 lock-to-caps-man=yes +/ip address +add address=10.30.30.86/24 interface=ether1 network=10.30.30.0 +add address=10.9.9.1/24 interface=br-awg network=10.9.9.0 +/ip dns +set allow-remote-requests=yes servers=10.30.30.33,109.107.177.79 +/ip firewall nat +add action=masquerade chain=srcnat src-address=10.9.9.0/24 +# in/out-interface matcher not possible when interface (ether1) is slave - use master instead (Bridge-LAN) +add action=dst-nat chain=dstnat dst-port=443 in-interface=ether1 protocol=udp \ + to-addresses=10.9.9.2 to-ports=55055 +# in/out-interface matcher not possible when interface (ether1) is slave - use master instead (Bridge-LAN) +add action=dst-nat chain=dstnat dst-port=9443 in-interface=ether1 protocol=\ + tcp to-addresses=10.9.9.2 to-ports=443 +/ip firewall service-port +set ftp disabled=yes +set tftp disabled=yes +set irc disabled=no +set sip disabled=yes +set pptp disabled=yes +set rtsp disabled=no +/ip hotspot walled-garden +add server=*1 +add server=*1 +/ip ipsec settings +set accounting=no +/ip ipsec policy +set 0 disabled=yes dst-address=0.0.0.0/0 src-address=0.0.0.0/0 +/ip ipsec profile +set [ find default=yes ] dpd-interval=2m dpd-maximum-failures=5 +/ip proxy +set cache-administrator="" max-cache-size=none port=80,443 src-address=\ + 0.0.0.0 +/ip route +add check-gateway=ping disabled=no distance=2 dst-address=0.0.0.0/0 gateway=\ + ether1 routing-table=main scope=30 target-scope=10 +/ip service +set ftp disabled=yes +set telnet disabled=yes +set ssh address=10.30.30.0/24 port=2222 +set winbox address=10.30.30.0/24 +set api address=10.30.30.0/24 disabled=yes +set api-ssl address=10.30.30.0/24 disabled=yes +set www-ssl port=18443 +set www address=10.30.30.0/24 disabled=yes port=18880 +/ip service webserver +set graphs-plain=no rest-plain=no webfig-plain=no +/ip ssh +set forwarding-enabled=both publickey-authentication-options=verify-required \ + strong-crypto=yes +/ip upnp +set enabled=yes +/ip upnp interfaces +add interface=Bridge-LAN type=internal +add forced-ip=109.107.177.79 interface=*A type=external +add interface=lo type=internal +add interface=wlan2 type=internal +add interface=wlan1 type=internal +/ipv6 nd +set [ find default=yes ] advertise-dns=yes +/system clock +set time-zone-name=Europe/Amsterdam +/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 +/tool e-mail +set certificate-verification=no from=MikroVados port=587 \ + server=smtp.mail.me.com tls=starttls user=vadossio@icloud.com diff --git a/MikroGig/history/20260629/20260629090234-Diff-Config.rsc b/MikroGig/history/20260629/20260629090234-Diff-Config.rsc new file mode 100644 index 0000000..c91095f --- /dev/null +++ b/MikroGig/history/20260629/20260629090234-Diff-Config.rsc @@ -0,0 +1,14 @@ +12,14c12,13 +< # channel: 2422/20-Ce/gn(17dBm), SSID: vados, local forwarding +< set [ find default-name=wlan2 ] country=belarus disabled=no mode=ap-bridge \ +< name=wlan1 ssid=vados wps-mode=disabled +--- +> set [ find default-name=wlan2 ] country=belarus mode=ap-bridge name=wlan1 \ +> ssid=vados wps-mode=disabled +16,18c15,16 +< # channel: 5200/20-eCee/ac/P(20dBm), SSID: vados5g, local forwarding +< set [ find default-name=wlan1 ] country=belarus disabled=no mode=ap-bridge \ +< name=wlan2 ssid=vados5g wps-mode=disabled +--- +> set [ find default-name=wlan1 ] country=belarus mode=ap-bridge name=wlan2 \ +> ssid=vados5g wps-mode=disabled diff --git a/MikroMaster/20260629/20260629084007-Config.rsc b/MikroMaster/20260629/20260629084007-Config.rsc new file mode 100644 index 0000000..0183a94 --- /dev/null +++ b/MikroMaster/20260629/20260629084007-Config.rsc @@ -0,0 +1,3692 @@ +# 2026-06-29 08:40:12 by RouterOS 7.23.1 +# software id = A8L5-07YF +# +# model = RB952Ui-5ac2nD +# serial number = D3D50CEDCD38 +/interface bridge +add admin-mac=48:8F:5A:8E:1A:BF auto-mac=no dhcpv6-agent-circuit-id=\ + "\$(INTERFACE):\$(VID)" dhcpv6-agent-remote-id="\$(BRIDGEMAC)" name=\ + Bridge-LAN port-cost-mode=short +/interface ethernet +set [ find default-name=ether1 ] comment="WAN - Unet" loop-protect=off name=\ + "ether1 - Unet" rx-flow-control=auto tx-flow-control=auto +set [ find default-name=ether2 ] comment=LAN-2 +set [ find default-name=ether3 ] advertise="10M-baseT-half,10M-baseT-full,100M\ + -baseT-half,100M-baseT-full,1G-baseT-full,1G-baseX" comment=LAN-3 +set [ find default-name=ether4 ] comment=LAN-4 +set [ find default-name=ether5 ] advertise="10M-baseT-half,10M-baseT-full,100M\ + -baseT-half,100M-baseT-full,1G-baseT-full,1G-baseX" comment=LAN-5 \ + loop-protect=on poe-out=off rx-flow-control=auto tx-flow-control=auto +/interface wireless +# managed by CAPsMAN +# channel: 2422/20-Ce/gn(18dBm), SSID: vados, local forwarding +set [ find default-name=wlan1 ] country=belarus disabled=no mode=ap-bridge \ + ssid=vados wireless-protocol=802.11 +# managed by CAPsMAN +# channel: 5200/20-eCee/ac/P(21dBm), SSID: vados5g, local forwarding +set [ find default-name=wlan2 ] country=belarus disabled=no mode=ap-bridge \ + ssid=vados5g wireless-protocol=802.11 +/interface wireguard +add comment=WG listen-port=13231 mtu=1320 name=WG +/interface list +add include=static name=LAN +add name=Internet +add include=Internet name=WAN +/interface wireless security-profiles +set [ find default=yes ] authentication-types=wpa-psk,wpa2-psk mode=\ + dynamic-keys supplicant-identity=MikroTik +/iot wiliot servers +set *1 address=mqtt.us-east-2.prod.wiliot.cloud name="Wiliot US East" +/ip dhcp-server option +add code=12 name=HostName +add code=119 force=yes name=domain-search-list value="0x03'WORKGROUP'0x00" +/ip dhcp-server option sets +add name=HP1505n options=HostName +add name=StartLife1 options=HostName +add name=amsterDev options=HostName +add name=MiTV options=HostName +add name=miller options=HostName +add name=amster options=HostName +add name=garage options=HostName +add name=domain-search-set options=domain-search-list +add name=VADOS-LEN options=HostName +add name=VADOS-NUC options=HostName +add name=MikroNUC options=HostName +add name=master options=HostName +add name=MikroYellow options=HostName +add name="=\"Client ID\"" options=HostName +add name=iVados options=HostName +/ip dns forwarders +add dns-servers=1.0.0.1,1.1.1.1 name=blsp.at verify-doh-cert=no +add comment=Kra dns-servers=1.0.0.1,1.1.1.1 name=slon2.to verify-doh-cert=no +add dns-servers=1.1.1.1,1.0.0.1 name=slon3.at verify-doh-cert=no +add dns-servers=1.0.0.1,1.1.1.1 name=slon3.cc verify-doh-cert=no +add dns-servers=1.1.1.1,1.0.0.1 name=bs2web.at verify-doh-cert=no +add dns-servers=1.1.1.1,1.0.0.1 name=bs2best.at verify-doh-cert=no +add dns-servers=1.0.0.1,1.1.1.1 name=psrms.is verify-doh-cert=no +/ip ipsec proposal +set [ find default=yes ] disabled=yes +/ip pool +add name=dhcp ranges=10.30.30.83-10.30.30.254 +/ip dhcp-server +add add-arp=yes address-pool=dhcp always-broadcast=yes bootp-support=none \ + dhcp-option-set=domain-search-set interface=Bridge-LAN lease-time=10m \ + name=masterDHCP server-address=10.30.30.81 +/ip smb users +set [ find default=yes ] disabled=yes +add disabled=yes name=vados +/ipv6 dhcp-client option +add code=119 name=domain-search-list value="0x03'WORKGROUP'0x00" +add code=12 name=HostName value="\$(HOSTNAME)" +add code=61 name=DUID value=0x00030001488f5a8e1abc +add code=61 name=clientid +/ipv6 dhcp-server option +add code=119 name=domain-search-list value="0x03'WORKGROUP'0x00" +add code=12 name=HostName value="\$(HOSTNAME)" +add code=61 name=CLIENT_DUID +add code=61 name=CLIENT_MAC +/ppp profile +set *FFFFFFFE use-upnp=no +/routing bgp template +set default disabled=no output.network=bgp-networks +/routing table +add disabled=no fib name=To-VPN +/system logging action +add email-start-tls=yes email-to=vados@vados.ru name=email target=email +/system script +add dont-require-permissions=no name=fetchCustom owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + global GlobalScriptsUrl \"https://ros.vados.ru/\";\r\ + \n\r\ + \n#/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@1\ + 0.30.30.86.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.86.pub\";\ + \n\r\ + \n#:local Script AM-setup\ + \n;\r\ + \n#/system/script/add name=\$Script owner=\$Script source=([ /tool/fetch c\ + heck-certificate=yes-without-crl url=(\$GlobalScriptsUrl . \$Script . \".r\ + sc\") output=user as-value ]->\"data\");\r\ + \n\ + \n#/usb1/mikro_bak_rsa.pub\ + \n\ + \n\r\ + \n#\ + \n\r\ + \n#/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@1\ + 0.30.30.10.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.10.pub\";\ + \n\r\ + \n#\r\ + \n\ + \n#root.mnuc.backuper\ + \n\ + \n\r\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@10\ + .30.30.81.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.81.pub\";\r\ + \n\ + \n#:local Script AM-GlobalConfig;\ + \n\r\ + \n#/system/script/add name=\$Script owner=\$Script source=([ /tool/fetch c\ + heck-certificate=yes-without-crl url=(\$GlobalScriptsUrl . \$Script . \".r\ + sc\") output=user as-value ]->\"data\");\r\ + \n\ + \n#/usb1/mikro_bak_rsa.pub\ + \n#:local FetchFile AM-DOHCert.rsc\ + \n\ + \n\r\ + \n\r\ + \n#\ + \n:global MkDir;\ + \n\r\ + \n\ + \n#:local FetchFile Binary.backup\ + \n:local localDir \"\";\ + \n\ + \n\r\ + \n#\$MkDir \$localDir;\r\ + \n\ + \n#\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \$FetchFile) dst-path=(\ + \$localDir . \$FetchFile);\r\ + \n" +add comment="Global Config Script" dont-require-permissions=no name=\ + AM-GlobalConfig owner=AM-GlobalConfig policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\r\ + \n# RouterOS script: AM-GlobalConfig\r\ + \n# Script comment: Global Config Script\r\ + \n# Copyright (c) 2007-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# Warning: Dont touch this line!\r\ + \n:global Identity [/system/identity/get name];\r\ + \n:global GlobalConfReady false;\r\ + \n#\r\ + \n#\r\ + \n# Global Url For Amster scripts to fetch\r\ + \n# most be defined in AM-Init-Script or AM-setup scripts\r\ + \n:global GlobalScriptsUrl \"https://ros.vados.ru/\";\r\ + \n:global ScriptsUrlSuffix (a);\r\ + \n:global CheckSumsVerify true;\r\ + \n\r\ + \n:global ScriptUpdatesCRLF true;\r\ + \n:global CommentsInScripts true;\r\ + \n\r\ + \n# Debug output:\r\ + \n:global PrintDebug true; #false;\r\ + \n\r\ + \n# Debug output for specific script:\r\ + \n#:set (\$PrintDebugOverride->\"AM-GlobalFunc\") true;\r\ + \n\r\ + \n# Debug logs\r\ + \n# Other actions (disk, email, remote or support) can be used as well.\r\ + \n# I do not recommend using echo - use debug output instead (https://rsc.\ + eworm.de/main/DEBUG.html#debug-output).\r\ + \n#/system/logging/add topics=script,debug action=memory;\r\ + \n\r\ + \n:global MikrotikUpgradeUrl \"https://upgrade.mikrotik.com/routeros\";\r\ + \n:global Domain \"WORKGROUP\";\r\ + \n\r\ + \n:global EmailGeneralTo \"vados@vados.ru\";\r\ + \n#:global EmailGeneralCc \"\";\r\ + \n\r\ + \n# \$ScriptInstallUpdate mod/notification-telegram\r\ + \n:global TelegramTokenId \"8390868324:AAG3_d1hfVR2M6pGAgDK6ZvhOe4J97nyopw\ + \";\r\ + \n:global TelegramChatId \"-1003631309063\"; #\"454403445\";\r\ + \n# Use this to send notifications to a specific topic in group.\r\ + \n#:global TelegramThreadId \"30\";\r\ + \n# Using telegram-chat you have to define trusted chat ids (not group ids\ + !)\r\ + \n# or user names. Groups allow to chat with devices simultaneously.\r\ + \n:global TelegramChatIdsTrusted {\r\ + \n \"454403445\"\r\ + \n \"-1003631309063\"\r\ + \n \"-5124482807\"\r\ + \n \"1087968824\";\r\ + \n};\r\ + \n# \"-5294757340\";\r\ + \n\r\ + \n:global TelegramChatGroups \"(all)\";\r\ + \n#:global TelegramChatGroups \"(all|home|office)\";\r\ + \n\r\ + \n:global NotificationFunctions {\r\ + \n \"email\"\r\ + \n \"telegram\";\r\ + \n};\r\ + \n# Toggle this to disable symbols in notifications.\r\ + \n:global NotificationsWithSymbols true;\r\ + \n:global TerminalColorOutput true;\r\ + \n\r\ + \n:global DetectIpAddrDefault \"https://ipv4.mikrotik.ovh/\";\r\ + \n:global DetectIpAddrFallback \"https://api.ipify.org/\";\r\ + \n\r\ + \n## Update channel. Possible values: stable, long-term, testing, developm\ + ent\r\ + \n:global updateChannel \"stable\";\r\ + \n\r\ + \n:global CertRenewUrl (\$GlobalScriptsUrl . \"certs/\" . \$Identity . \"/\ + \");\r\ + \n:global CertRenewTime 2w;\r\ + \n:global CertRenewPass (a); #{\r\ + \n# \"\";\r\ + \n# \"v3ry-s3cr3t\";\r\ + \n# \"4n0th3r-s3cr3t\";\r\ + \n#};\r\ + \n:global CertWarnTime 1w;\r\ + \n:global CertIssuedExportPass (a); # {\r\ + \n# \"\";\r\ + \n# \"cert1-cn\"=\"v3ry-s3cr3t\";\r\ + \n# \"cert2-cn\"=\"4n0th3r-s3cr3t\";\r\ + \n#};\r\ + \n\r\ + \n# Script BackupAndUpdate mode, possible values: backup,\r\ + \n# updateOnce - Update once as \"osnotify\" and back \"osnotify\" mode (i\ + n terminal run :set OSUpdateMode updateOnce; \$OSUpdateMode;). \r\ + \n# osupdate - Update if available and creates backups before/after update\ + \_(ignores `forceBackup`)\r\ + \n# Set `forceBackup` to true to always create backups, even\ + \_without updates\r\ + \n# osnotify - Set `forceBackup` to always create backups on every run\r\ + \n:global DevInfoIncludeIP true;\r\ + \n:global BackupAndUpdateMode \"osnotify\"\r\ + \n\r\ + \n:global forceBackup true;\r\ + \n:global BackupPassword \"Peskar55\";\r\ + \n\r\ + \n# SFTP Backup Variables\r\ + \n:global BackupRandomDelay 0;\r\ + \n:global BackupUploadUrl \"sftp://amster.vados.ru/upload/\";\r\ + \n:global BackupUploadUser \$Identity;\r\ + \n:global BackupUploadPass \"root.mnuc.backuper\";\r\ + \n\r\ + \n:global BackupSendBinary true;\r\ + \n:global BackupSendExport true;\r\ + \n:global BackupSendGlobalConfig true;\r\ + \n:global BackupSendScripts true;\r\ + \n\r\ + \n# Remove local file after uploading if no errors\r\ + \n:global BackupRmLocal true;\r\ + \n\r\ + \n# Local Backups Root Directory \r\ + \n:global BackupLocalRoot \"tmpfs\";\r\ + \n\r\ + \n# Encrypt Backup\r\ + \n:global BackupEncrypt true;\r\ + \n\r\ + \n# Sensitive information in Backups\r\ + \n:global BackupSens true;\r\ + \n\r\ + \n# User Export\r\ + \n:global BackupUser true;\r\ + \n\r\ + \n# License Export (not for CHR, will silently skip)\r\ + \n:global BackupLicense false;\r\ + \n\r\ + \n# SSH Keys\r\ + \n:global BackupSshKeys true;\r\ + \n\r\ + \n# Certificate Export\r\ + \n:global BackupCerts true;\r\ + \n\r\ + \n# Certificate Password\r\ + \n:global BackupCertsPasswd \"\";\r\ + \n\r\ + \n# User-Manager Export\r\ + \n:global BackupUserMan false;\r\ + \n\r\ + \n# The Dude Export\r\ + \n:global BackupDude false;\r\ + \n\r\ + \n# User Files to export, comma-separated string or array of strings\r\ + \n# User Files are not removed on backup\r\ + \n# Any directory paths will be removed (/ -> _) on remote file\r\ + \n# Nonpresent files are silently skipped\r\ + \n:global BackupUserList \"autosupout.rif,autosupout.old.rif\";\r\ + \n\r\ + \n# load functions and any custom scripts\r\ + \n# [ /system/script/find where name=\"global-config-ov\ + erlay\" ], \\\r\ + \n# [ /system/script/find where name~\"^global-config-o\ + verlay\\\\.d/.\" ]\r\ + \n#\r\ + \n#:foreach Script in=([ /system/script/find where name=\"Amster-TGglobalV\ + ars\" ], [ /system/script/find where name=\"Amster-TGglobalFunc\" ]) do={\ + \r\ + \n# :onerror Err {\r\ + \n# /system/script/run \$Script;\r\ + \n# } do={\r\ + \n# :log error (\"Loading configuration from configs and functions\"\ + \_. [ /system/script/get \$Script name ] . \" failed: \" . \$Err);\r\ + \n# }\r\ + \n#}\r\ + \n#:log info \"\\ndevMode = \$devMode\";\r\ + \n#:log info \"\\ndevRunning = \$devRunning\";\r\ + \n:foreach Script in=[ /system/script/find where source~\"^#!rsc by Vados \ + GlobalRUN\\r\?\\n\" ] do={\r\ + \n :onerror Err {\r\ + \n /system/script/run \$Script;\r\ + \n } do={\r\ + \n :log error (\"Run script \" . [ /system/script/get \$Script name \ + ] . \" width marker \\\" GlobalRUN\\\" failed: \" . \$Err);\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n# signal we are ready\r\ + \n:set GlobalConfReady true;\r\ + \n:while (\$GlobalConfReady != true) do={:delay 500ms};\r\ + \n" +add comment="Global functions" dont-require-permissions=no name=AM-GlobalFunc \ + owner=AM-GlobalFunc policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\r\ + \n# RouterOS script: AM-GglobalFunc\r\ + \n# Script comment: Global functions\r\ + \n# Copyright (c) 2005-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version=7.19\r\ + \n# requires device-mode, fetch, scheduler\r\ + \n:local ExitOK false;\r\ + \n:local ScriptName [ :jobname ];\r\ + \n#:global checkRunJob \$SriptName;\r\ + \n#:global fixCRLF;\r\ + \n#:if (\$fixCRLF != false) do={\r\ + \n#:foreach fixScript in=([ /system/script/find where name~\"*\" ]) do={/s\ + ystem/script/set source=[ :tocrlf [ get \$fixScript source ] ] \$fixScript\ + }\r\ + \n#:if (\$fixCRLF != \"LF\") do={ /system/script/set source=[ :tocrlf [ g\ + et \$fixScript source ] ] \$fixScript};};\r\ + \n#}\r\ + \n:global GlobalFuncReady false;\r\ + \n\r\ + \n# Git commit id & info, expected configuration version\r\ + \n:global CommitId \"main/720/6faffeff\";\r\ + \n:global CommitTAG \"unknown\";\r\ + \n:global CommitInfo \"Autocommit in repo: ros.vados.ru, generated by owne\ + r: root, in 02:10:04 29.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=\ + "Lookup IP addresses for RKN list and add them to firewall address-list" \ + dont-require-permissions=no name=AM-RKN-dnsLookup owner=AM-RKN-dnsLookup \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + source="#!rsc by Vados\r\ + \n# RouterOS script: AM-RKN-dnsLookup\r\ + \n# Script comment: Lookup IP addresses for RKN list and add them to firew\ + all address-list\r\ + \n# Copyright (c) 2007-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version=7.19\r\ + \n# requires device-mode, fetch\r\ + \n#\r\ + \n# Script description: This script is intended to be run periodically, e.\ + g. once a day, to update the IP addresses in the firewall address-list bas\ + ed on the RKN list.\r\ + \n# It resolves the domain names in the RKN list and a\ + dds the corresponding IP addresses to the specified firewall address-list.\ + \r\ + \n# The script also handles CNAME records by following\ + \_them until it finds A records.\r\ + \n# Usage:\r\ + \n# /system/script { run AM-RKN-dnsLookup; }\r\ + \n:local ScriptName [ :jobname ];\r\ + \n\r\ + \n:global dnsLookupReady false;\r\ + \n:if ([:typeof \$dnsLookupReady] != \"boolean\") do={ :set dnsLookupReady\ + \_true; }\r\ + \nwhile (!\$dnsLookupReady) do={ :nothing; }\r\ + \n:set dnsLookupReady false;\r\ + \n\r\ + \n:local arrRKN {\r\ + \n \"telegra.ph\"\r\ + \n \"grani.ru\"\r\ + \n \"xhamster.com\"\r\ + \n \"lostfilm.tv\"\r\ + \n \"rutracker.org\"\r\ + \n \"lurkmore.to\"\r\ + \n \"dou.ua\"\r\ + \n \"youporn.com\"\r\ + \n \"pornolab.net\"\r\ + \n \"crimerussia.com\"\r\ + \n \"telegram.org\"\r\ + \n \"api.telegram.org\"\r\ + \n \"facebook.com\"\r\ + \n \"instagram.com\"\r\ + \n \"x.com\"\r\ + \n \"twitter.com\"\r\ + \n \"youtube.com\"\r\ + \n \"googleapis.com\"\r\ + \n \"youtu.be\"\r\ + \n \"googlevideo.com\"\r\ + \n \"gstatic.com\"\r\ + \n \"googleusercontent.com\"\r\ + \n \"nhacmp3youtube.com\"\r\ + \n \"telegram.me\"\r\ + \n \"t.me\";}\r\ + \n\r\ + \n:local ListRKN \"RKN-dnsLookup\";\r\ + \n:local ListComment (\"ListRKN managed by \" . \$ScriptName);\r\ + \n:foreach aListItem in=[/ip/firewall/address-list find list=\$ListRKN] do\ + ={\r\ + \n /ip firewall address-list remove \$aListItem;\r\ + \n}\r\ + \n:foreach aItem in=\$arrRKN do={\r\ + \n# :do {\r\ + \n :retry delay=500ms max=5 on-error={:log error \"dns resolve fail\ + ure [ \$aItem - resolve ip ]\"} command={:resolve \$aItem}\r\ + \n# } on-error={\r\ + \n# :log error \"dns resolve failure [ \$arItem - resolve ip ]\";\r\ + \n# }\r\ + \n :foreach dnsRecord in=[/ip dns cache all find where (name=\$aItem)] \ + do={\r\ + \n :if ([/ip dns cache all get \$dnsRecord type]=\"A\") do={\r\ + \n :local newAddress [/ip dns cache all get \$dnsRecord data];\ + \r\ + \n :do {\r\ + \n /ip firewall address-list add list=\$ListRKN address=\$newA\ + ddress comment=\$aItem;\r\ + \n :log warning \"Successfully adding ip to list A record: \ + \$dnsRecord, address: \$newAddress domain: \$aItem\";\r\ + \n } on-error={\r\ + \n :log error \"error when adding ip to list A record: \$dn\ + sRecord, address: \$newAddress domain: \$aItem\";\r\ + \n }\r\ + \n }\r\ + \n :if ([/ip dns cache all get \$dnsRecord type]=\"CNAME\") do={\r\ + \n :local cname;\r\ + \n :local nextCname;\r\ + \n :local cnameAddress;\r\ + \n :set cname [/ip dns cache all find where (name=\$aItem && ty\ + pe=\"CNAME\")];\r\ + \n :set nextCname [/ip dns cache all find where (name=[/ip dns \ + cache all get \$cname data] && type=\"CNAME\")];\r\ + \n :while (\$nextCname != \"\") do={\r\ + \n :set cname \$nextCname;\r\ + \n :set nextCname [/ip dns cache all find where (name=[/ip \ + dns cache all get \$cname data] && type=\"CNAME\")];\r\ + \n }\r\ + \n :foreach aRecord in=[/ip dns cache all find where (name=[/ip\ + \_dns cache all get \$cname data] && type=\"A\")] do={\r\ + \n :do {\r\ + \n :set cnameAddress [/ip dns cache all get \$aRecord d\ + ata];\r\ + \n /ip firewall address-list add list=\$ListRKN address\ + =\$cnameAddress comment=\$aItem;\r\ + \n :log warning \"Succesfully adding ip to list CNAME r\ + ecord: \$cname, A record: \$aRecord, address: \$newAddress, from domain: \ + \$aItem.\";\r\ + \n# /ip firewall raw add action=add-dst-to-address-list\ + \_address-list=\$ListRKN address-list-timeout=none-dynamic chain=preroutin\ + g comment=\$aItem content=\$aItem;\r\ + \n } on-error={\r\ + \n :log error \"error when adding ip to list CNAME reco\ + rd: \$cname, A record: \$aRecord, address: \$newAddress, from domain: \$aI\ + tem.\";\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:if ([ :len [ /system/scheduler/find where name=\$ScriptName ] ] = 0) do\ + ={\r\ + \n :log error (\$ScriptName . \"System Scheduler for script: \" . \$Scri\ + ptName . \" is NOT SET! Fix It Now!\");\r\ + \n /system/scheduler/add name=\$ScriptName on-event=\"/system/script { \ + run \$ScriptName; }\" comment=\"Update RKN DNS Looup\" interval=00:30:00 p\ + olicy=\"ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon\"\ + \_start-time=startup;\r\ + \n }\r\ + \n:set dnsLookupReady true;\r\ + \ndelay 2s; \r\ + \n:global dnsLookupReady (a);\r\ + \n" +add dont-require-permissions=no name="renameLists " owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + local oldName \"Test\";\ + \n:local newName \"Test-IP\";\ + \n/ip firewall address-list\ + \n:foreach i in=[find list=\$oldName] do={\ + \nset \$i list=\$newName;\ + \n}\ + \n" +add dont-require-permissions=no name=IPv6-Settings owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + #############Script Settings##################\ + \n\ + \n:local \"IF-TUN\" \"6to4-tun\"\ + \n:local \"IF-LOC\" \"Bridge-LAN\"\ + \n:local \"POOL-6TO4\" \"poolV6-local\"\ + \n:local \"force-update\" false\ + \n############ use then static ip #######################\ + \n:local \"lease-address\" [/ip address get [find interface=\$\"IF-LOC\"] \ + address]\ + \n#:local \"interface\" \"ext\"\ + \n:local bound 0\ + \n\ + \n###############################################\ + \n\ + \n:local 6to4prefix do={\ + \n :global dec2hex\ + \n :local ipv4 \$1\ + \n :local ipv6 \"2002:\"\ + \n :for i from=0 to=2 step=1 do={ \ + \n :if ( \$i = 2) do={\ + \n :set ipv6 (\$ipv6.\":\")\ + \n }\ + \n :local fp [:find \$ipv4 \".\"]\ + \n :if ( \$fp > 0 ) do={\ + \n :set ipv6 (\$ipv6.[\$dec2hex [:pick \$ipv4 0 \$fp]])\ + \n :set ipv4 [:pick \$ipv4 (\$fp + 1 ) [:len \$ipv4]]\ + \n }\ + \n }\ + \n :return (\$ipv6.[\$dec2hex \$ipv4])\ + \n}\ + \n:local \"str_replace\" do={\ + \n :local \"str-pos\" [:find \$1 \$2]\ + \n :local \"str-len\" [:len \$2]\ + \n :local str \"\"\ + \n :local rest \$1\ + \n :while (\$\"str-pos\" >= 0) do={\ + \n :local t [:pick \$rest 0 \$\"str-pos\"]\ + \n :if ( \$4 > 0 ) do={\ + \n :for i from=1 to=(\$4 - [:len \$t]) step=1 do={\ + \n :set str (\$str.\$5)\ + \n }\ + \n }\ + \n :set str (\$str.\$t.\$3)\ + \n :set rest [:pick \$rest (\$\"str-pos\"+\$\"str-len\") [:len \$re\ + st]]\ + \n :set \"str-pos\" [:find \$rest \$2]\ + \n }\ + \n :return (\$str.\$rest)\ + \n}\ + \n\ + \n:if (\$bound=1) do={\ + \n :local t [:find \$\"lease-address\" \"/\"]\ + \n\ + \n :if ( \$t >= 0 ) do={\ + \n :set \"lease-address\" [:pick \$\"lease-address\" 0 \$t]\ + \n }\ + \n\ + \n :if ( [/interface 6to4 print count-only where name=\$\"IF-TUN\"] = 0\ + ) do={\ + \n /interface 6to4 add !keepalive local-address=\$\"lease-address\"\ + \_mtu=1280 name=\$\"IF-TUN\" remote-address=10.30.30.0\ + \n :set \"force-update\" true\ + \n }\ + \n\ + \n :local \"IPv4-TUN\" [/interface 6to4 get [find name=\$\"IF-TUN\"] lo\ + cal-address];\ + \n\ + \n :if ( \$\"lease-address\" != \$\"IPv4-TUN\" || \$\"force-update\" = \ + true) do={\ + \n /interface 6to4 set [find name=\$\"IF-TUN\"] local-address=\$\"l\ + ease-address\"\ + \n /ipv6 address remove [find interface=\$\"IF-TUN\"]\ + \n /ipv6 address remove [find interface=\$\"IF-LOC\"]\ + \n /ipv6 route remove [find gateway ~ \$\"IF-TUN\" and dst-address=\ + \"::/0\"]\ + \n :local \"pool-prefix\" [\$6to4prefix \$\"lease-address\"]\ + \n :if ( [/ipv6 pool print count-only where name=\$\"POOL-6TO4\"] =\ + \_0) do={ \ + \n /ipv6 pool add name=\$\"POOL-6TO4\" prefix=(\$\"pool-prefix\ + \".\":1::/64\") prefix-length=64\ + \n } else={\ + \n /ipv6 pool set [/ipv6 pool find where name=\$\"POOL-6TO4\"] \ + prefix=(\$\"pool-prefix\".\":1::/64\")\ + \n }\ + \n /ipv6 address add address=(\$\"pool-prefix\".\"::\".[\$MAC2EUI64\ + \_[/interface get [find name=\$\"interface\"] mac-address]].\"/3\") interf\ + ace=\$\"IF-TUN\" advertise=no\ + \n /ipv6 address add eui-64=yes from-pool=\$\"POOL-6TO4\" interface\ + =\$\"IF-LOC\" advertise=yes\ + \n /ipv6 route add dst-address=::/0 gateway=(\"::10.30.30.81%\".\$\ + \"IF-TUN\")\ + \n :local t [/ipv6 address get [find interface=\$\"IF-LOC\"] addres\ + s]\ + \n :set t [:pick \$t 0 [:find \$t \"/\"]]\ + \n :if ( [/ipv6 dhcp-server option print count-only where name=DNS]\ + \_= 0) do={\ + \n /ipv6 dhcp-server option add code=23 name=DNS value=(\"0x\".\ + [\$\"str_replace\" \$t \":\" \"\" 4 \"0\"])\ + \n } else={\ + \n /ipv6 dhcp-server option set [/ipv6 dhcp-server option find \ + where name=DNS] value=(\"0x\".[\$\"str_replace\" \$t \":\" \"\" 4 \"0\"])\ + \n }\ + \n :if ( [/ipv6 dhcp-server print count-only where interface=\$\"IF\ + -LOC\"] = 0) do={\ + \n /ipv6 dhcp-server add address-pool=\$\"POOL-6TO4\" dhcp-opti\ + on=DNS interface=\$\"IF-LOC\" lease-time=1d name=\$\"IF-LOC\"\ + \n }\ + \n :if ( [ipv6 nd print count-only where interface=\$\"IF-LOC\"] = \ + 0) do={\ + \n /ipv6 nd add advertise-dns=no interface=\$\"IF-LOC\" other-c\ + onfiguration=yes\ + \n }\ + \n }\ + \n}" +add dont-require-permissions=no name=IPv6-GlobalFunc owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + global MAC2EUI64 do={\ + \n :local EUI64 \"\"\ + \n :local MAC \$1\ + \n :local HEX2DEC \"0123456789ABCDEF\"\ + \n :for i from=0 to=5 step=1 do={\ + \n :if ( \$i = 0 ) do={\ + \n :set EUI64 [:pick \$MAC 0]\ + \n :set EUI64 (\$EUI64.[:tostr [:pick \$\"HEX2DEC\" ([:find \$\ + \"HEX2DEC\" [:pick \$MAC 1]] ^ 2)]])\ + \n }\ + \n :if ( \$i = 1 || \$i = 3) do={\ + \n :set EUI64 (\$EUI64.\":\")\ + \n }\ + \n :if ( \$i = 2 ) do={\ + \n :set EUI64 (\$EUI64.\"FF:FE\")\ + \n }\ + \n :if ( [:find \$MAC \":\"] = 2 ) do={\ + \n :set MAC [:pick \$MAC 3 [:len \$MAC]]\ + \n :set EUI64 (\$EUI64.[:pick \$MAC 0 2])\ + \n }\ + \n }\ + \n :return (\$EUI64)\ + \n}\ + \n\ + \n:global dec2hex do={\ + \n :local hex \"\"\ + \n :local dec [:tonum \$1]\ + \n :for i from=0 to=4 step=4 do={\ + \n :set hex ([:pick \"0123456789ABCDEF\" ((\$dec>>\$i)&0xf) (((\$de\ + c>>\$i)&0xf)+1)].\$hex)\ + \n }\ + \n :return ([:tostr \$hex])\ + \n}" +/user group +add name=backup policy="ssh,read,write,policy,test,web,sniff,sensitive,api,res\ + t-api,!local,!telnet,!ftp,!reboot,!winbox,!password,!romon" +/ip smb +set enabled=no interfaces=lo +/interface bridge port +add bridge=Bridge-LAN interface=ether5 +add bridge=Bridge-LAN interface=ether2 +add bridge=Bridge-LAN interface=ether4 trusted=yes +add bridge=Bridge-LAN interface=ether3 +add bridge=Bridge-LAN interface=wlan2 +add bridge=Bridge-LAN interface=wlan1 +/interface bridge settings +set use-ip-firewall=yes +/ip firewall connection tracking +set udp-timeout=10s +/ip neighbor discovery-settings +set discover-interface-list=LAN lldp-med=no lldp-poe-power=no +/ip settings +set accept-redirects=yes ipv4-multipath-hash-policy=l4 max-neighbor-entries=\ + 8192 +/ipv6 settings +set disable-ipv6=yes disable-link-local-address=yes forward=no \ + max-neighbor-entries=8192 multipath-hash-policy=l4 +/interface detect-internet +set detect-interface-list=WAN internet-interface-list=Internet \ + lan-interface-list=LAN request-interval=1m wan-interface-list=WAN +/interface l2tp-server server +set authentication=mschap2 use-ipsec=yes +/interface list member +add interface=ether4 list=WAN +add interface="ether1 - Unet" list=Internet +add disabled=yes interface=WG list=WAN +add interface=Bridge-LAN list=LAN +/interface wireguard peers +add allowed-address=0.0.0.0/0 client-allowed-address=::/0 endpoint-address=\ + 109.107.177.79 endpoint-port=29185 interface=WG name=VDSina \ + persistent-keepalive=10s public-key=\ + "zuRsO+dL/j6awaBWZ/NgnHR+bCNUjRWbaHFpdzkNnw4=" +/interface wireless cap +# +set bridge=Bridge-LAN caps-man-addresses=10.30.30.10 \ + caps-man-certificate-common-names=CAPsMAN-51B25E507D07 certificate=\ + CAP-488F5A8E1ABC discovery-interfaces=Bridge-LAN enabled=yes interfaces=\ + wlan2,wlan1 lock-to-caps-man=yes +/ip address +add address=10.30.30.81/24 interface=Bridge-LAN network=10.30.30.0 +add address=10.8.0.2/24 interface=WG network=10.8.0.0 +/ip cloud +set update-time=no +/ip dhcp-client +add add-default-route=special-classless default-route-distance=2 \ + default-route-tables=main:2 dhcp-options=clientid,clientid_duid \ + interface="ether1 - Unet" name=client1 use-peer-dns=no use-peer-ntp=no +/ip dhcp-server config +set accounting=no +/ip dhcp-server lease +add address=10.30.30.101 client-id=1:48:8f:5a:8e:ee:a8 mac-address=\ + 48:8F:5A:8E:EE:A8 server=masterDHCP +add address=10.30.30.107 client-id=1:f0:de:f1:91:d:1e mac-address=\ + F0:DE:F1:91:0D:1E server=masterDHCP +add address=10.30.30.83 client-id=1:0:80:77:ec:43:86 mac-address=\ + 00:80:77:EC:43:86 server=masterDHCP +add address=10.30.30.70 dhcp-option=domain-search-list,HostName \ + dhcp-option-set=HP1505n mac-address=00:1E:0B:1A:88:8D server=masterDHCP +add address=10.30.30.50 client-id=1:4:7c:16:36:f5:37 mac-address=\ + 04:7C:16:36:F5:37 server=masterDHCP +add address=10.30.30.71 client-id=1:10:2d:41:2c:20:c2 mac-address=\ + 10:2D:41:2C:20:C2 server=masterDHCP +add address=10.30.30.61 client-id=1:10:8:c1:81:59:5f mac-address=\ + 10:08:C1:81:59:5F server=masterDHCP +add address=10.30.30.72 client-id=1:10:38:1f:d2:5f:13 mac-address=\ + 10:38:1F:D2:5F:13 server=masterDHCP +add address=10.30.30.99 client-id=1:10:b1:df:e9:d0:d5 mac-address=\ + 10:B1:DF:E9:D0:D5 server=masterDHCP +add address=10.30.30.111 client-id=1:fe:2:52:be:3f:16 mac-address=\ + FE:02:52:BE:3F:16 server=masterDHCP +add address=10.30.30.92 client-id=1:d4:6d:6d:fd:e5:49 mac-address=\ + D4:6D:6D:FD:E5:49 server=masterDHCP +add address=10.30.30.93 client-id=1:7e:8b:1e:cb:b8:cb mac-address=\ + CC:42:10:12:46:94 server=masterDHCP +add address=10.30.30.94 client-id=1:50:cc:f8:85:96:a mac-address=\ + 50:CC:F8:85:96:0A server=masterDHCP +add address=10.30.30.82 client-id=1:e4:18:6b:58:34:ab mac-address=\ + E4:18:6B:58:34:AB server=masterDHCP +add address=10.30.30.75 client-id=1:0:27:15:41:97:a9 mac-address=\ + 00:27:15:41:97:A9 server=masterDHCP +add address=10.30.30.77 dhcp-option=HostName dhcp-option-set=StartLife1 \ + mac-address=C4:82:E1:03:49:10 server=masterDHCP +add address=10.30.30.73 client-id=1:10:38:1f:82:81:f2 mac-address=\ + 10:38:1F:82:81:F2 server=masterDHCP +add address=10.30.30.95 client-id=1:88:ae:dd:60:39:54 dhcp-option=HostName \ + dhcp-option-set=VADOS-NUC mac-address=88:AE:DD:60:39:54 server=masterDHCP +add address=10.30.30.98 client-id=1:c8:5b:76:d8:cc:bf dhcp-option=HostName \ + dhcp-option-set=VADOS-LEN mac-address=C8:5B:76:D8:CC:BF server=masterDHCP +add address=10.30.30.96 client-id=iPhone mac-address=4A:91:ED:0E:1F:39 \ + server=masterDHCP +add address=10.30.30.74 client-id=MiTV dhcp-option=HostName dhcp-option-set=\ + MiTV mac-address=20:72:A9:D3:34:36 server=masterDHCP +add address=10.30.30.30 dhcp-option=HostName dhcp-option-set=miller \ + mac-address=F0:75:5D:1E:5F:71 server=masterDHCP +add address=10.30.30.100 client-id=iVados dhcp-option=HostName \ + dhcp-option-set=iVados mac-address=DE:4D:72:F3:1A:9F server=masterDHCP +add address=10.30.30.10 allow-dual-stack-queue=yes client-id=\ + ff:0:0:0:df:0:3:0:1:f0:75:5d:1e:5f:85 dhcp-option=HostName \ + dhcp-option-set=MikroNUC mac-address=F0:75:5D:1E:5F:85 server=masterDHCP \ + use-src-mac=yes +/ip dhcp-server network +add address=10.30.30.0/24 caps-manager=10.30.30.10 dhcp-option=\ + domain-search-list dhcp-option-set=domain-search-set dns-server=\ + 10.30.30.33,109.107.177.79 domain=WORKGROUP gateway=10.30.30.81 netmask=\ + 24 ntp-server=10.30.30.81,10.30.30.10 wins-server=10.30.30.95,10.30.30.98 +/ip dns +set allow-remote-requests=yes cache-max-ttl=1d doh-max-concurrent-queries=100 \ + doh-max-server-connections=20 servers=109.107.177.79,10.30.30.33,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 disabled=yes list=NoWG +add address=10.30.30.10 comment=MikroNUC disabled=yes list=NoWG +add address=89.110.101.17 comment=!!!VDSINA!!!! disabled=yes list=NoWG +add address=wg.vados.ru comment=VDSina-vpn list=VDSina +add address=80.85.244.9 list=TRUSTED +add address=disc801.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + disc801.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=185.71.70.78 disabled=yes list=TRUSTED +add address=176.53.203.171 disabled=yes list=TRUSTED +add address=176.53.203.170 disabled=yes list=TRUSTED +add address=176.53.202.194 disabled=yes list=TRUSTED +add address=89.110.101.17 comment="!!!VDSina Server!!!" list=NoVdsina +add address=dns.quad9.net comment=Quad9-dns disabled=yes list=Trusted-DNS +add address=dns.google comment=Google-dns list=Trusted-DNS +add address=security.cloudflare-dns.com comment=CloudFlare-dns list=\ + Trusted-DNS +add address=time.google.com comment=Google-time list=Trusted-NTP +add address=0.ru.pool.ntp.org comment=ru.pool.ntp.org disabled=yes list=\ + Trusted-NTP +add address=1.ru.pool.ntp.org disabled=yes list=Trusted-NTP +add address=2.ru.pool.ntp.org comment=2.ru.pool.ntp.org disabled=yes list=\ + Trusted-NTP +add address=3.ru.pool.ntp.org comment=3.ru.pool.ntp.org disabled=yes list=\ + Trusted-NTP +add address=cp.vdsina.com comment=VDSina-vpn list=VDSina +add address=vdsina.ru comment=VDSina-vpn list=VDSina +add address=ns.vados.ru comment=VDSina-vpn list=VDSina +add address=vdsina.com comment=VDSina-vpn list=VDSina +add address=cp.vdsina.ru comment=VDSina-vpn list=VDSina +add address=ns1.vdsina.ru comment=VDSina-vpn list=VDSina +add address=10.30.30.0/24 comment="Local Network" list=Local-Net +add address=10.8.0.0/24 comment="WireGuard Network" list=Local-Net +add address=146.120.64.208/29 comment="External Net" list=Unet +add address=esia.gosuslugi.ru comment=esia.gosuslugi.ru list=NoVdsina +add address=lk.gosuslugi.ru comment=lk.gosuslugi.ru list=NoVdsina +add address=trudvsem.ru comment=trudvsem.ru list=NoVdsina +add address=10.30.30.30 comment=miller disabled=yes list=NoWG +add address=10.30.30.33 comment="Direct connet to DNS servers" list=\ + Direct-DNS +add address=109.107.177.79 list=VPN-Server +add address=10.30.30.10 list=AWG-Proxy +/ip firewall filter +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=12h chain=input comment="block honeypot DNS" \ + connection-state=new dst-port=53 in-interface="ether1 - Unet" protocol=\ + udp src-address-list=!Trusted-DNS +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=4w2d chain=input connection-state=new dst-port=53 \ + in-interface="ether1 - Unet" protocol=tcp src-address-list=!Trusted-DNS +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=4w2d chain=input comment=\ + "block honeypot ssh rdp winbox" connection-state=new dst-port=22,8291 \ + in-interface="ether1 - Unet" protocol=tcp src-address-list=!TRUSTED +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=4w2d chain=input comment="block honeypot asterisk" \ + connection-state=new dst-port=5060 in-interface="ether1 - Unet" protocol=\ + udp +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=4w2d chain=input comment="block honeypot NTP" \ + connection-state=new dst-port=123 in-interface="ether1 - Unet" protocol=\ + udp +add action=fasttrack-connection chain=forward comment=\ + "FastTrack for non-VPN connections" connection-mark=!VPN_No_FastTrack \ + connection-state=established,related,new disabled=yes +add action=accept chain=input disabled=yes dst-port=29185 in-interface=\ + "ether1 - Unet" protocol=tcp +add action=accept chain=input disabled=yes dst-port=29185 in-interface=\ + "ether1 - Unet" protocol=udp +add action=accept chain=input comment="tcp Accept input DNS queries from LAN" \ + dst-port=53 protocol=tcp src-address=10.30.30.0/24 +add action=accept chain=input comment="udp Accept input DNS queries" \ + dst-port=53 protocol=udp src-address=10.30.30.0/24 +add action=accept chain=output comment="accept WireGuard" disabled=yes \ + dst-address-list=VPN-Server out-interface="ether1 - Unet" protocol=udp \ + src-port=13231 +add action=accept chain=output disabled=yes dst-address-list=VPN-Server \ + dst-port=29185 out-interface="ether1 - Unet" protocol=udp +add action=fasttrack-connection chain=forward comment="defconf: fasttrack" \ + connection-state=established,related,new disabled=yes routing-mark=\ + !To-VPN +add action=accept chain=output disabled=yes protocol=tcp src-port=443 +add action=accept chain=output disabled=yes src-address=127.0.0.1 +add action=accept chain=forward comment="defconf: accept in ipsec policy" \ + disabled=yes ipsec-policy=in,ipsec +add action=accept chain=forward comment="defconf: accept out ipsec policy" \ + disabled=yes ipsec-policy=out,ipsec +add action=accept chain=forward comment=\ + "defconf: accept established,related, untracked" connection-state=\ + established,related,untracked +add action=drop chain=forward comment="defconf: drop invalid" \ + connection-state=invalid in-interface="ether1 - Unet" src-address=\ + !10.30.30.0/24 +add action=drop chain=forward comment=\ + "defconf: drop all from WAN not DSTNATed" connection-nat-state=!dstnat \ + connection-state=new in-interface="ether1 - Unet" src-address-list=\ + !VDSina +add action=drop chain=forward comment=\ + "Filter Rule to block FB address LIST : )" disabled=yes dst-address-list=\ + facebook +add action=drop chain=forward comment=\ + "Filter Rule to block YOUTUBE address LIST : )" disabled=yes \ + dst-address-list=YouTube +add action=accept chain=input in-interface="ether1 - Unet" protocol=icmp \ + src-address-list=VDSina +add action=accept chain=input connection-state=established disabled=yes +add action=accept chain=input connection-state=related disabled=yes +/ip firewall mangle +add action=mark-routing chain=prerouting comment="Mark Routing main for NoWG" \ + disabled=yes new-routing-mark=main src-address-list=NoWG +add action=mark-routing chain=prerouting comment=\ + "Mark Routing main for NoVdsina" dst-address-list=NoVdsina \ + new-routing-mark=main src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=\ + "Mark Routing main for VDSina" dst-address-list=VPN-Server \ + new-routing-mark=main src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=\ + "Mark Routing main for MikroNuc" disabled=yes dst-address-list=AWG-Proxy \ + new-routing-mark=main src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=\ + "!!!ERROR Mark Routing main for Unet!!!" disabled=yes dst-address-list=\ + Unet new-routing-mark=main passthrough=no +add action=mark-routing chain=prerouting comment="Test-IP sites" disabled=yes \ + dst-address=!10.30.30.0/24 dst-address-list=Test-IP new-routing-mark=\ + To-VPN src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=FuckRKN disabled=yes \ + dst-address=!10.30.30.0/24 dst-address-list=RKN-dnsLookup \ + new-routing-mark=To-VPN passthrough=no src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment="AWG for All sites" \ + disabled=yes dst-address=!10.30.30.0/24 dst-address-list=!NoVdsina \ + new-routing-mark=*401 routing-mark=!main src-address=10.30.30.0/24 \ + src-address-list=!NoWG +add action=mark-routing chain=prerouting comment="VDSIna for All sites" \ + dst-address=!10.30.30.0/24 dst-address-list=!NoVdsina new-routing-mark=\ + To-VPN routing-mark=!main src-address=10.30.30.0/24 +add action=mark-connection chain=prerouting comment=\ + "Mark VPN connections to exclude from FastTrack" new-connection-mark=\ + VPN_No_FastTrack routing-mark=To-VPN +add action=change-mss chain=forward comment="MSS on WG" new-mss=1380 \ + out-interface=WG protocol=tcp routing-mark=To-VPN tcp-flags=syn tcp-mss=\ + 1381-65535 +add action=mark-routing chain=prerouting comment="VPN Network" dst-address=\ + 10.8.0.0/24 new-routing-mark=To-VPN src-address=10.30.30.0/24 +/ip firewall nat +add action=redirect chain=dstnat comment="udp Redirect DNS in NAT" disabled=\ + yes dst-port=53 protocol=udp src-address=10.30.30.0/24 src-address-list=\ + !NoWG to-addresses=10.30.30.33 to-ports=53 +add action=redirect chain=dstnat comment="tcp Redirect DNS in NAT" disabled=\ + yes dst-port=53 protocol=tcp src-address=10.30.30.0/24 src-address-list=\ + !NoWG to-addresses=10.30.30.33 to-ports=53 +add action=dst-nat chain=dstnat comment=\ + "53/tcp dst-nat to amster.loc. From VDSina Server" dst-port=53 \ + in-interface="ether1 - Unet" protocol=tcp src-address-list=VPN-Server \ + to-addresses=10.30.30.33 to-ports=53 +add action=dst-nat chain=dstnat comment=\ + "53/udp dst-nat to amster.loc. From VDSina Server" dst-port=53 protocol=\ + udp src-address-list=VPN-Server to-addresses=10.30.30.33 to-ports=53 +add action=dst-nat chain=dstnat disabled=yes dst-port=44333 in-interface=\ + "ether1 - Unet" protocol=udp src-address=!10.30.30.0/24 to-addresses=\ + 10.30.30.33 to-ports=44333 +add action=masquerade chain=srcnat comment="Default NAT" out-interface=\ + "ether1 - Unet" routing-mark=!To-VPN src-address=10.30.30.0/24 +add action=dst-nat chain=dstnat comment=amster.vados.ruhttps dst-port=443 \ + fragment=no in-interface="ether1 - Unet" protocol=tcp routing-mark=main \ + to-addresses=10.30.30.33 to-ports=443 +add action=dst-nat chain=dstnat comment="amster.vados.ru For Certbot HTTP" \ + dst-port=80 in-interface="ether1 - Unet" protocol=tcp to-addresses=\ + 10.30.30.33 to-ports=80 +add action=dst-nat chain=dstnat comment="amster.vados.ru 3x-ui" disabled=yes \ + dst-port=2904 in-interface="ether1 - Unet" protocol=tcp to-addresses=\ + 10.30.30.33 to-ports=2904 +add action=dst-nat chain=dstnat comment=reg.vados.ru disabled=yes dst-port=\ + 5000 in-interface="ether1 - Unet" protocol=tcp to-addresses=10.30.30.33 \ + to-ports=5000 +add action=dst-nat chain=dstnat comment="Docker swarm" disabled=yes dst-port=\ + 2377 in-interface="ether1 - Unet" protocol=tcp to-addresses=10.30.30.33 \ + to-ports=2377 +add action=dst-nat chain=dstnat comment=npm dst-port=81 in-interface=\ + "ether1 - Unet" protocol=tcp routing-mark=To-VPN to-addresses=10.30.30.33 \ + to-ports=81 +add action=dst-nat chain=dstnat comment=SSH dst-port=22 in-interface=\ + "ether1 - Unet" protocol=tcp src-address-list=TRUSTED to-addresses=\ + 10.30.30.33 to-ports=22 +add action=dst-nat chain=dstnat comment="portainer agent" disabled=yes \ + dst-port=2377 in-interface="ether1 - Unet" protocol=tcp to-addresses=\ + 10.30.30.33 to-ports=2377 +add action=dst-nat chain=dstnat disabled=yes dst-port=22 in-interface=\ + "ether1 - Unet" protocol=tcp routing-mark=!To-VPN to-addresses=\ + 10.30.30.33 to-ports=22 +add action=masquerade chain=srcnat comment=WG dst-address-list=!NoVdsina \ + out-interface=WG routing-mark=To-VPN src-address-list=!NoWG +add action=dst-nat chain=dstnat comment="Yandex.DNS Family" disabled=yes \ + dst-port=53 in-interface=Bridge-LAN protocol=udp src-address-list=KIDS \ + time=6h-15m,sun,mon,tue,wed,thu,fri,sat to-addresses=77.88.8.3 +add action=dst-nat chain=dstnat disabled=yes dst-port=53 in-interface=\ + Bridge-LAN protocol=tcp src-address-list=KIDS time=\ + 6h-15m,sun,mon,tue,wed,thu,fri,sat to-addresses=77.88.8.3 +/ip firewall raw +add action=drop chain=prerouting comment="Drop Honeypot Hackers" \ + in-interface="ether1 - Unet" src-address-list="Honeypot Hacker" +add action=accept chain=prerouting comment="Trusted DNS" disabled=yes \ + in-interface-list=WAN src-address-list=Trusted-DNS +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + extras.getpagespeed.com content=extras.getpagespeed.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=linux.duke.edu \ + content=linux.duke.edu disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=youtube.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + googleapis.com disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=ggpht.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=youtu.be \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=ytimg.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + googlevideo.com disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=gstatic.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + googleusercontent.com disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + nhacmp3youtube.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=rutube.ru \ + content=rutube.ru disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment="me.com raw" \ + content=me.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "icloud.com raw" content=icloud.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "smtp.mail.me.com raw" content=smtp.mail.me.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "smtp.mail.me.com.akadns.net raw" content=smtp.mail.me.com.akadns.net \ + disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "api.db-ip.com raw" content=api.db-ip.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + esia.gosuslugi.ru content=esia.gosuslugi.ru disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=gosuslugi.ru \ + content=gosuslugi.ru disabled=yes +/ip firewall service-port +set ftp disabled=yes +set tftp disabled=yes +set irc disabled=no +set sip disabled=yes +set pptp disabled=yes +set rtsp disabled=no +/ip ipsec settings +set accounting=no +/ip ipsec policy +set 0 disabled=yes dst-address=0.0.0.0/0 src-address=0.0.0.0/0 +/ip ipsec profile +set [ find default=yes ] dpd-interval=2m dpd-maximum-failures=5 +/ip proxy +set cache-administrator="" max-cache-size=none port=80,443 src-address=\ + 0.0.0.0 +/ip route +add check-gateway=none disabled=no distance=1 dst-address=0.0.0.0/0 gateway=\ + WG routing-table=To-VPN scope=30 target-scope=10 +/ip service +set ftp disabled=yes +set telnet disabled=yes +set reverse-proxy disabled=yes +set ssh address=10.30.30.0/24 port=2222 +set winbox address=10.30.30.0/24 +set api address=10.30.30.0/24 disabled=yes +set api-ssl address=10.30.30.0/24 disabled=yes +set www-ssl certificate=Root-YE port=18443 +set www address=10.30.30.0/24 disabled=yes port=18880 +/ip service webserver +set acme-plain=no crl-plain=no graphs-plain=no graphs-secure=no index-plain=\ + no index-secure=no rest-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 \ + strong-crypto=yes +/ip upnp +set enabled=yes +/ip upnp interfaces +add interface=Bridge-LAN type=internal +add forced-ip=146.120.64.211 interface="ether1 - Unet" type=external +add forced-ip=109.107.177.79 interface=*E type=external +add interface=lo type=internal +add interface=wlan2 type=internal +add interface=wlan1 type=internal +/ipv6 dhcp-client +add add-default-route=yes disabled=yes interface=*F rapid-commit=no request=\ + info use-interface-duid=yes validate-server-duid=no +/ipv6 dhcp-server option sets +add name=domain-search-set options=domain-search-list +add name="=\"Client ID\"" options=HostName +/ipv6 firewall address-list +add address=::/128 comment="defconf: unspecified address" list=bad_ipv6 +add address=::1/128 comment="defconf: lo" list=bad_ipv6 +add address=fec0::/10 comment="defconf: site-local" list=bad_ipv6 +add address=::ffff:0.0.0.0/96 comment="defconf: ipv4-mapped" list=bad_ipv6 +add address=::/96 comment="defconf: ipv4 compat" list=bad_ipv6 +add address=100::/64 comment="defconf: discard only " list=bad_ipv6 +add address=2001:db8::/32 comment="defconf: documentation" list=bad_ipv6 +add address=2001:10::/28 comment="defconf: ORCHID" list=bad_ipv6 +add address=3ffe::/16 comment="defconf: 6bone" list=bad_ipv6 +/ipv6 firewall filter +add action=accept chain=input comment=\ + "defconf: accept established,related,untracked" connection-state=\ + established,related,untracked +add action=drop chain=input comment="defconf: drop invalid" connection-state=\ + invalid +add action=accept chain=input comment="defconf: accept ICMPv6" protocol=\ + icmpv6 +add action=accept chain=input comment="defconf: accept UDP traceroute" \ + dst-port=33434-33534 protocol=udp +add action=accept chain=input comment=\ + "defconf: accept DHCPv6-Client prefix delegation." dst-port=546 protocol=\ + udp src-address=fe80::/10 +add action=accept chain=input comment="defconf: accept IKE" dst-port=500,4500 \ + protocol=udp +add action=accept chain=input comment="defconf: accept ipsec AH" protocol=\ + ipsec-ah +add action=accept chain=input comment="defconf: accept ipsec ESP" protocol=\ + ipsec-esp +add action=accept chain=input comment=\ + "defconf: accept all that matches ipsec policy" ipsec-policy=in,ipsec +add action=drop chain=input comment=\ + "defconf: drop everything else not coming from LAN" in-interface-list=\ + !LAN +add action=accept chain=forward comment=\ + "defconf: accept established,related,untracked" connection-state=\ + established,related,untracked +add action=drop chain=forward comment="defconf: drop invalid" \ + connection-state=invalid +add action=drop chain=forward comment=\ + "defconf: drop packets with bad src ipv6" src-address-list=bad_ipv6 +add action=drop chain=forward comment=\ + "defconf: drop packets with bad dst ipv6" dst-address-list=bad_ipv6 +add action=drop chain=forward comment="defconf: rfc4890 drop hop-limit=1" \ + hop-limit=equal:1 protocol=icmpv6 +add action=accept chain=forward comment="defconf: accept ICMPv6" protocol=\ + icmpv6 +add action=accept chain=forward comment="defconf: accept HIP" protocol=139 +add action=accept chain=forward comment="defconf: accept IKE" dst-port=\ + 500,4500 protocol=udp +add action=accept chain=forward comment="defconf: accept ipsec AH" protocol=\ + ipsec-ah +add action=accept chain=forward comment="defconf: accept ipsec ESP" protocol=\ + ipsec-esp +add action=accept chain=forward comment=\ + "defconf: accept all that matches ipsec policy" ipsec-policy=in,ipsec +add action=drop chain=forward comment=\ + "defconf: drop everything else not coming from LAN" in-interface-list=\ + !LAN +/ipv6 nd +set [ find default=yes ] advertise-dns=yes disabled=yes interface=Bridge-LAN \ + managed-address-configuration=yes other-configuration=yes pref64=::/64 +/ipv6 nd prefix +add autonomous=no disabled=yes interface=Bridge-LAN on-link=no prefix=none +/ipv6 nd prefix default +set dhcp6-pd-preferred=yes +/ipv6 nd proxy +add disabled=yes interface=lo +/ipv6 nd settings +set router-advertisement-route-distance=100 +/routing settings +set single-process=no +/system clock +set time-zone-name=Europe/Moscow +/system clock manual +set time-zone=+03:00 +/system identity +set name=MikroMaster +/system logging +add action=email disabled=yes regex="* added|changed|removed *" topics=\ + system,info +/system ntp client +set enabled=yes +/system ntp server +set enabled=yes manycast=yes multicast=yes use-local-clock=yes +/system ntp client servers +add address=0.ru.pool.ntp.org +add address=1.ru.pool.ntp.org +add address=2.ru.pool.ntp.org +add address=3.ru.pool.ntp.org +add address=time.google.com disabled=yes +/system package update +set check-certificate=yes-without-crl ip-version=ipv4 +/system scheduler +add comment="Every Day Set Global Environment Variables" name=AM-SetGlobalEnv \ + on-event="/system/script { run AM-GlobalConfig; run AM-GlobalFunc; }" \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-time=startup +add comment="Every Day Check For Update Scripts" interval=1d name=\ + AM-ScriptInstallUpdate on-event=\ + ":global ScriptInstallUpdate; \$ScriptInstallUpdate;" policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-time=startup +add comment="Update RKN DNS Looup" disabled=yes interval=20m name=\ + AM-RKN-dnsLookup on-event="/system/script { run AM-RKN-dnsLookup; }" \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-time=startup +/system watchdog +set watchdog-timer=no +/tool e-mail +set certificate-verification=no from=MikroVados port=587 \ + server=smtp.mail.me.com tls=starttls user=vadossio@icloud.com +/tool mac-server +set allowed-interface-list=LAN +/tool mac-server mac-winbox +set allowed-interface-list=LAN +/tool netwatch +add certificate=DigiCert-Global-Root-CA check-certificate=no comment="doh, doh\ + -url=https://security.cloudflare-dns.com/dns-query, notify, name=CloudFlar\ + e-doh IPv4 1" disabled=yes down-script="" host=1.1.1.1 http-codes="" \ + interval=10s name="CloudFlare-doh IPv4 1" port=443 test-script="" type=\ + https-get up-script="" +add check-certificate=no comment="doh-fallback, doh-url=https://security.cloud\ + flare-dns.com/dns-query, doh-cert=DigiCert Global Root CA, notify, name=Cl\ + oudFlare-doh IPv4" disabled=yes down-script="" host=1.0.0.1 http-codes="" \ + name="CloudFlare-doh IPv4" port=443 test-script="" type=https-get \ + up-script="" +add comment="dns, notify, name=Google-DNS IPv4" disabled=yes dns-server=\ + 8.8.8.8 down-script="" host=dns.google http-codes="" name=\ + "Google-DNS IPv4" test-script="" type=dns up-script="" +add certificate=GTS-Root-R4 check-certificate=yes comment="doh-fallback, doh-u\ + rl=https://dns.google/dns-query, doh-cert=GTS Root R1, notify, name=Google\ + -DOH IPv4" disabled=yes dns-server=8.8.4.4 down-script="" host=dns.google \ + http-codes="" name="Google-DOH IPv4" port=443 record-type=NS src-address=\ + "" test-script="" type=dns up-script="" +add comment="dns-fallback, notify, name=Cuad9-DOH IPv4" disabled=yes \ + dns-server=9.9.9.9 down-script="" host=dns9.quad9.net http-codes="" \ + interval=10s name="Cuad9-DOH IPv4" src-address=146.120.64.211 \ + test-script="" timeout=800ms type=dns up-script="" +add certificate=DigiCert-Assured-ID-Root-CA comment="doh-fallback, doh-url=htt\ + ps://dns.quad9.net/dns-query, name=Cuad9-DOH IPv4" disabled=yes \ + down-script="" host=149.112.112.112 http-codes="" interval=10s name=\ + "Cuad9-DOH IPv4" port=443 test-script="" type=https-get up-script="" +add comment="dns-fallback, notify, name=ns1.unet.ws" disabled=yes \ + down-script="" host=91.192.189.2 http-codes="" interval=10s name=\ + ns1.unet.ws test-script="" type=simple up-script="" +add check-certificate=yes comment=\ + "doh, doh-url=https://vds.vados.ru/vds-query, name=vds.vados.ru" \ + disabled=yes down-script="" host=109.107.177.79 http-codes="" name=\ + vds.vados.ru port=443 test-script="" type=https-get up-script="" +/user aaa +set accounting=no diff --git a/MikroMaster/tmp/Diff-Config.rsc b/MikroMaster/tmp/Diff-Config.rsc deleted file mode 100644 index 12be446..0000000 --- a/MikroMaster/tmp/Diff-Config.rsc +++ /dev/null @@ -1,35 +0,0 @@ -2617c2617 -< default-route-tables=main:2 dhcp-options=clientid,clientid_duid \ ---- -> default-route-tables=main:2 dhcp-options=clientid_duid,clientid \ -3270a3271,3272 -> add action=accept chain=input disabled=yes dst-port=18880 in-interface=\ -> Bridge-LAN protocol=tcp src-address=10.30.30.0/24 -3365c3367 -< VPN_No_FastTrack routing-mark=To-VPN ---- -> VPN_No_FastTrack routing-mark=*401 -3367c3369 -< out-interface=WG protocol=tcp routing-mark=To-VPN tcp-flags=syn tcp-mss=\ ---- -> out-interface=WG protocol=tcp routing-mark=main tcp-flags=syn tcp-mss=\ -3369,3370c3371,3372 -< add action=mark-routing chain=prerouting comment="VPN Network" dst-address=\ -< 10.8.0.0/24 new-routing-mark=To-VPN src-address=10.30.30.0/24 ---- -> add action=mark-routing chain=prerouting comment="VPN Network" disabled=yes \ -> dst-address=10.8.0.0/24 new-routing-mark=*401 src-address=10.30.30.0/24 -3371a3374,3379 -> add action=dst-nat chain=dstnat comment=amster.vados.ruhttps dst-port=443 \ -> fragment=no in-interface="ether1 - Unet" protocol=tcp routing-mark=main \ -> to-addresses=10.30.30.33 to-ports=443 -> add action=dst-nat chain=dstnat comment="amster.vados.ru For Certbot HTTP" \ -> dst-port=80 in-interface="ether1 - Unet" protocol=tcp to-addresses=\ -> 10.30.30.33 to-ports=80 -3390,3395d3397 -< add action=dst-nat chain=dstnat comment=amster.vados.ruhttps dst-port=443 \ -< fragment=no in-interface="ether1 - Unet" protocol=tcp routing-mark=main \ -< to-addresses=10.30.30.33 to-ports=443 -< add action=dst-nat chain=dstnat comment="amster.vados.ru For Certbot HTTP" \ -< dst-port=80 in-interface="ether1 - Unet" protocol=tcp to-addresses=\ -< 10.30.30.33 to-ports=80 -- 2.52.0