From f6472ccd70751136ca3be95b5d86c283d659996c Mon Sep 17 00:00:00 2001 From: vados-dev Date: Sat, 4 Jul 2026 06:01:09 +0300 Subject: [PATCH] Backup for MikroGig created successfully at Jul 04 06:01:09. --- .../20260704/20260704060105-Binary.backup | Bin 0 -> 192639 bytes MikroGig/20260704/20260704060105-Config.rsc | 3336 +++++++++++++++ .../20260704/20260704060105-Diff-Config.rsc | 59 + .../20260703/20260703194002-Config.rsc | 3744 +++++++++++++++++ .../20260703/20260703224002-Config.rsc | 3744 +++++++++++++++++ 5 files changed, 10883 insertions(+) create mode 100644 MikroGig/20260704/20260704060105-Binary.backup create mode 100644 MikroGig/20260704/20260704060105-Config.rsc create mode 100644 MikroGig/history/20260704/20260704060105-Diff-Config.rsc create mode 100644 MikroMaster/20260703/20260703194002-Config.rsc create mode 100644 MikroMaster/20260703/20260703224002-Config.rsc diff --git a/MikroGig/20260704/20260704060105-Binary.backup b/MikroGig/20260704/20260704060105-Binary.backup new file mode 100644 index 0000000000000000000000000000000000000000..e90c3f1c9616d5222ee1e3e906366939450226be GIT binary patch literal 192639 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

* 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 literal 0 HcmV?d00001 diff --git a/MikroGig/20260704/20260704060105-Config.rsc b/MikroGig/20260704/20260704060105-Config.rsc new file mode 100644 index 0000000..979a6de --- /dev/null +++ b/MikroGig/20260704/20260704060105-Config.rsc @@ -0,0 +1,3336 @@ +# 2026-07-04 06:01:06 by RouterOS 7.23.1 +# software id = 2961-C4ZZ +# +# model = RBD52G-5HacD2HnD +# serial number = HCX084RAVFA +/interface bridge +add admin-mac=18:FD:74:6E:58:14 auto-mac=no name=Bridge-LAN port-cost-mode=\ + short +/interface wireless +# managed by CAPsMAN +set [ find default-name=wlan1 ] country=belarus mode=ap-bridge ssid=vados \ + wps-mode=disabled +# managed by CAPsMAN +set [ find default-name=wlan2 ] country=belarus mode=ap-bridge ssid=vados5g \ + wps-mode=disabled +/interface ethernet +set [ find default-name=ether1 ] mac-address=48:8F:5A:8E:1A:BC +/interface veth +add address=172.20.0.2/30 container-mac-address=00:00:00:00:00:00 dhcp=no \ + gateway=172.20.0.1 gateway6="" name=veth-awgVDSina +/interface wireguard +add disabled=yes listen-port=12430 mtu=1360 name=wg-awgVDSina +/disk +add mount-point-template="[tmpfs]" slot=ram tmpfs-max-size=64 type=tmpfs +/interface list +add name=WAN +add name=LAN +add exclude=LAN include=WAN name=Internet +/interface wireless security-profiles +set [ find default=yes ] supplicant-identity=MikroTik +/routing table +add disabled=no fib name=r_to_vpn +/system logging action +add email-start-tls=yes email-to=vados@vados.ru name=email target=email +/system script +add comment="Script for setup routeros script system" \ + dont-require-permissions=no name=AM-setup owner=AM-setup policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\r\ + \n# RouterOS script: AM-setup\r\ + \n# Script comment: Script for setup routeros script system\r\ + \n# Copyright (c) 2005-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version=7.19\r\ + \n# requires device-mode, fetch\r\ + \n#\r\ + \n# :local ScriptName [ :jobname ];\r\ + \n# Additional commands:\r\ + \n#\r\ + \n# For scripts:\r\ + \n#:global NewScript \"script_name\"; \r\ + \n#:global GlobalScriptsUrl \"https://ros.vados.ru/\";\r\ + \n#/system/script/add name=\$NewScript owner=\$NewScript source=([/tool/fe\ + tch check-certificate=yes-without-crl (\$GlobalScriptsUrl . \$ScriptAdd . \ + \".rsc\") output=user as-value ]->\"data\");\r\ + \n#:global NewScript (a);\r\ + \n#:global ScriptInstallUpdate; \$ScriptInstallUpdate;\r\ + \n#\r\ + \n# For run from terminal:\r\ + \n#/system/script/add name=AM-setup owner=AM-Setup source=([/tool/fetch ch\ + eck-certificate=yes-without-crl \"https://ros.vados.ru/AM-setup.rsc\" outp\ + ut=user as-value ]->\"data\");\r\ + \n#\r\ + \n\r\ + \n:global ScriptUpdatesCRLF \"LF\";\r\ + \n#:if (\$ScriptUpdatesCRLF != false) do={\r\ + \n# :foreach Script in=[ /system/script/find where source~\"^#!rsc by Vad\ + os\" ] do={\r\ + \n# if (\$ScriptUpdatesCRLF = true) do={\r\ + \n# /system/script/set source=[ :tocrlf [ get \$Script source ] ] \$S\ + cript;\r\ + \n# } else={\r\ + \n# /system/script/set source=[ :tolf [ get \$Script source ] ] \$Scr\ + ipt;\r\ + \n# }\r\ + \n# }\r\ + \n#}\r\ + \n\r\ + \n# /import verbose=no \$ScriptName\r\ + \n:global Identity [/system/identity/get name];\r\ + \n:global SetupScript [ :jobname ];\r\ + \n:global RemoveMe true;\r\ + \n:global RunOnce (a);\r\ + \n:global InitSetup true;\r\ + \n:global tmpfs false;\r\ + \n\r\ + \n{\r\ + \n :local RmMe [:tobool \$1];\r\ + \n\r\ + \n :global GlobalScriptsUrl;\r\ + \n :global SetupScript;\r\ + \n :global RemoveMe;\r\ + \n :global InitSetup;\r\ + \n :global tmpfs;\r\ + \n\r\ + \n :local UrlSuffix \$Identity;\r\ + \n :local UrlDir \"certs/\";\r\ + \n :local CertUrl (\$GlobalScriptsUrl . \$UrlDir . \$UrlSuffix .\"/\"); \ + \r\ + \n :local CertCommonName \"Root YE\";\r\ + \n :local CertFileName \"Root-YE.pem\";\r\ + \n :local CertFingerprint \"e14ffcad5b0025731006caa43a121a22d8e9700f4fb9c\ + f852f02a708aa5d5666\";\r\ + \n\r\ + \n :if (\$SetupScript = false) do={\r\ + \n :global SetupScript \"AM-setup\";\r\ + \n }\r\ + \n :if (\$RemoveMe != false) do={\r\ + \n :set RemoveMe true;\r\ + \n }\r\ + \n\r\ + \n :log warning (\"\\n\\\$GlobalScriptsUrl = \" . \$GlobalScriptsUrl);\r\ + \n \r\ + \n\r\ + \n :if (!(((\$CertSettings->\"builtin-trust-anchors\") = \"trusted\" ||\ + \_\\\r\ + \n (\$CertSettings->\"builtin-trust-store\") ~ \"fetch\" || \\\r\ + \n (\$CertSettings->\"builtin-trust-store\") = \"all\") && \\\r\ + \n [ :len [ /certificate/builtin/find where common-name=\$CertComm\ + onName ] ] > 0)) do={\r\ + \n :put \"Importing certificate...\";\r\ + \n /tool/fetch (\$CertUrl . \$CertFileName) dst-path=\$CertFileName\ + \_as-value;\r\ + \n :delay 1s;\r\ + \n /certificate/import file-name=\$CertFileName passphrase=\"\";\r\ + \n /certificate/set name=\"Root-YE\" [ find where common-name=\"Roo\ + t YE\" ];\r\ + \n :delay 1s;\r\ + \n };\r\ + \n :local CertSettings [ /certificate/settings/get ];\r\ + \n :if ([ :len [ /certificate/find where fingerprint=\$CertFingerprint ] \ + ] != 1) do={\r\ + \n :error \"Something is wrong with your certificates!\";\r\ + \n };\r\ + \n\r\ + \n:local MkTmpfs do={\r\ + \n :local TmpFs [ /disk/find where slot=tmpfs type=tmpfs ];\r\ + \n :if ([ :len \$TmpFs ] = 1) do={\r\ + \n :if ([ /disk/get \$TmpFs disabled ] = true) do={\r\ + \n :log info (\"The tmpfs is disabled, enabling.\");\r\ + \n /disk/enable \$TmpFs;\r\ + \n }\r\ + \n :return true;\r\ + \n }\r\ + \n :log info (\"Try to removing directory 'tmpfs'.\");\r\ + \n :do {\r\ + \n :retry {\r\ + \n /file/remove tmpfs;\r\ + \n :return true;\r\ + \n } delay=100ms max=10;\r\ + \n } on-error={ }\r\ + \n# \$RmDir \"tmpfs\";\r\ + \n :onerror Err {\r\ + \n /disk/add slot=tmpfs type=tmpfs tmpfs-max-size=([ /system/resource/g\ + et total-memory ] / 3);\r\ + \n :do {\r\ + \n :retry {\r\ + \n /file/get tmpfs;\r\ + \n :return true;\r\ + \n } delay=222ms max=10;\r\ + \n } on-error={ }\r\ + \n } do={\r\ + \n :log warning (\"Creating disk of type tmpfs failed: \" . \$Err);\r\ + \n :return false;\r\ + \n }\r\ + \n# :return true;\r\ + \n}\r\ + \n:if (\$tmpfs = true) do={\r\ + \n :put \"Tmpfs variable is true. Checking for tmpfs/scripts directory...\ + \";\r\ + \n :if ([/file find name=\"tmpfs/scripts\"] != \"\") do={\r\ + \n :log info (\$0 . \"Directory tmpfs/scripts exsist.\");\r\ + \n :return \$true;\r\ + \n } else={\r\ + \n :log warning (\$0 . \"Directory tmpfs/scripts does't exsist.\");\r\ + \n :if ([ \$MkTmpfs ] = false) do={\r\ + \n :log error (\$0 . \"Directory tmpfs is not created!\");\r\ + \n :return false;\r\ + \n } else={\r\ + \n :onerror Err {\r\ + \n /file/add type=\"directory\" name=/tmpfs/scripts;\r\ + \n :do {\r\ + \n :retry {\r\ + \n /file/get /tmpfs/scripts;\r\ + \n :return true;\r\ + \n } delay=100ms max=10;\r\ + \n } on-error={ }\r\ + \n } do={\r\ + \n :log warning (\$0 . \"Making directory 'scripts' failed: \" . \$\ + Err);\r\ + \n :return false;\r\ + \n }\r\ + \n# :return true;\r\ + \n# [ /file/get \$FileName ]\r\ + \n }\r\ + \n# :log error (\$0 . \"Directory tmpfs/scripts does not exsist. Remove\ + \_global variable tmpfs!\");\r\ + \n# :global tmpfs (a);\r\ + \n# return false;\r\ + \n }\r\ + \n}\r\ + \n :put \"Renaming AM-GlobalConfig, if exists...\";\r\ + \n :local ConfOldName (\"AM-GlobalConfig-\" . [ /system/clock/get date ] \ + . [ /system/clock/get time ] . \".rsc\");\r\ + \n /system/script/set name=\$ConfOldName [ find where name=\"AM-GlobalCon\ + fig\" ];\r\ + \n :foreach Script in={ \"AM-GlobalConfig\"; \"AM-GlobalFunc\" } do={\r\ + \n :put \"Installing \$Script...\";\r\ + \n /system/script/remove [ find where name=\$Script ];\r\ + \n /system/script/add name=\$Script owner=\$Script source=([ /tool/fetc\ + h check-certificate=yes-without-crl url=(\$GlobalScriptsUrl . \$Script . \ + \".rsc\") output=user as-value ]->\"data\");\r\ + \n \r\ + \n /system/script run \$Script;\r\ + \n :delay 2s;\r\ + \n };\r\ + \n\r\ + \n :local Script \"mod/AM-Certs-By-Ident\";\r\ + \n \r\ + \n :put \"Installing \$Script...\";\r\ + \n /system/script/remove [ find where name=\$Script ];\r\ + \n /system/script/add name=\$Script owner=\$Script source=([ /tool/fetch \ + check-certificate=yes-without-crl url=(\$GlobalScriptsUrl . \$Script . \".\ + rsc\") output=user as-value ]->\"data\");\r\ + \n /system/script run \$Script;\r\ + \n :global tmpAddCerts;\r\ + \n :while ([ \$tmpAddCerts ] = true) do={\r\ + \n :delay 1s;\r\ + \n }\r\ + \n :delay 1s;\r\ + \n :put \"Removing \$Script...\";\r\ + \n /system/script/remove [ find where name=\$Script ];\r\ + \n\r\ + \n :if ([ :len [ /certificate/find where fingerprint=\$CertFingerprint ] \ + ] > 0) do={\r\ + \n :put \"Renaming certificate by its common-name...\";\r\ + \n :global CertificateNameByCN;\r\ + \n \$CertificateNameByCN \$CertFingerprint;\r\ + \n };\r\ + \n\r\ + \n :if (\$RemoveMe = true) do={\r\ + \n :put \"Add Scheduler for remove this script...\";\r\ + \n :local OnEvent (\":delay 30s;\\n\" . \"/system/script/remove [ find \ + where name=\\\"\$SetupScript\\\" ];\\n\" . \\\r\ + \n \":delay 2s;\\n\" . \"/system/scheduler/remove [ find where name=\\\ + \"_RemoveSetup\\\" ];\\n\" . \\\r\ + \n \":delay 2s;\\n\" . \":global RemoveMe (a);\\n\");\r\ + \n :local Comment \"_RemoveSetup tmp scheduler for remove setup script.\ + \";\r\ + \n /system/scheduler/add name=\"_RemoveSetup\" comment=\$Comment start-\ + time=startup interval=30s on-event=\$OnEvent;\r\ + \n :log warning (\$0 . \"\\nI've done everything, and now I'm tired..\ + . I'm leaving.\\nThere will be an error below, this is normal.\");\r\ + \n }\r\ + \n :delay 1;\r\ + \n :put \"Loading configuration and functions...\";\r\ + \n :do { \r\ + \n :global ScriptInstallUpdate; \$ScriptInstallUpdate;\r\ + \n :put \"Normal removing temporary global environment variables.\";\ + \r\ + \n :global SetupScript (a);\r\ + \n :global InitSetup (a);\r\ + \n :global RemoveMe (a);\r\ + \n } on-error={\r\ + \n :local ErrorMsg \"Loading configuration and functions error!\";\r\ + \n :log error (\$0 . \$ErrorMsg . :error);\r\ + \n :error \$ErrorMsg;\r\ + \n }\r\ + \n}\r\ + \n" +add comment="Global Config Script" dont-require-permissions=no name=\ + AM-GlobalConfig owner=AM-GlobalConfig policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\r\ + \n# RouterOS script: AM-GlobalConfig\r\ + \n# Script comment: Global Config Script\r\ + \n# Copyright (c) 2007-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# Warning: Dont touch this line!\r\ + \n:global Identity [/system/identity/get name];\r\ + \n:global GlobalConfReady false;\r\ + \n#\r\ + \n#\r\ + \n# Global Url For Amster scripts to fetch\r\ + \n# most be defined in AM-Init-Script or AM-setup scripts\r\ + \n:global GlobalScriptsUrl \"https://ros.vados.ru/\";\r\ + \n:global ScriptsUrlSuffix (a);\r\ + \n:global CheckSumsVerify true;\r\ + \n\r\ + \n:global ScriptUpdatesCRLF true;\r\ + \n:global CommentsInScripts true;\r\ + \n\r\ + \n# Debug output:\r\ + \n:global PrintDebug true; #false;\r\ + \n\r\ + \n# Debug output for specific script:\r\ + \n#:set (\$PrintDebugOverride->\"AM-GlobalFunc\") true;\r\ + \n\r\ + \n# Debug logs\r\ + \n# Other actions (disk, email, remote or support) can be used as well.\r\ + \n# I do not recommend using echo - use debug output instead (https://rsc.\ + eworm.de/main/DEBUG.html#debug-output).\r\ + \n#/system/logging/add topics=script,debug action=memory;\r\ + \n\r\ + \n:global MikrotikUpgradeUrl \"https://upgrade.mikrotik.com/routeros\";\r\ + \n:global Domain \"WORKGROUP\";\r\ + \n\r\ + \n:global EmailGeneralTo \"vados@vados.ru\";\r\ + \n#:global EmailGeneralCc \"\";\r\ + \n\r\ + \n# \$ScriptInstallUpdate mod/notification-telegram\r\ + \n:global TelegramTokenId \"8390868324:AAG3_d1hfVR2M6pGAgDK6ZvhOe4J97nyopw\ + \";\r\ + \n:global TelegramChatId \"-1003631309063\"; #\"454403445\";\r\ + \n# Use this to send notifications to a specific topic in group.\r\ + \n#:global TelegramThreadId \"30\";\r\ + \n# Using telegram-chat you have to define trusted chat ids (not group ids\ + !)\r\ + \n# or user names. Groups allow to chat with devices simultaneously.\r\ + \n:global TelegramChatIdsTrusted {\r\ + \n \"454403445\"\r\ + \n \"-1003631309063\"\r\ + \n \"-5124482807\"\r\ + \n \"1087968824\";\r\ + \n};\r\ + \n# \"-5294757340\";\r\ + \n\r\ + \n:global TelegramChatGroups \"(all)\";\r\ + \n#:global TelegramChatGroups \"(all|home|office)\";\r\ + \n\r\ + \n:global NotificationFunctions {\r\ + \n \"email\"\r\ + \n \"telegram\";\r\ + \n};\r\ + \n# Toggle this to disable symbols in notifications.\r\ + \n:global NotificationsWithSymbols true;\r\ + \n:global TerminalColorOutput true;\r\ + \n\r\ + \n:global DetectIpAddrDefault \"https://ipv4.mikrotik.ovh/\";\r\ + \n:global DetectIpAddrFallback \"https://api.ipify.org/\";\r\ + \n\r\ + \n## Update channel. Possible values: stable, long-term, testing, developm\ + ent\r\ + \n:global updateChannel \"stable\";\r\ + \n\r\ + \n:global CertRenewUrl (\$GlobalScriptsUrl . \"certs/\" . \$Identity . \"/\ + \");\r\ + \n:global CertRenewTime 2w;\r\ + \n:global CertRenewPass (a); #{\r\ + \n# \"\";\r\ + \n# \"v3ry-s3cr3t\";\r\ + \n# \"4n0th3r-s3cr3t\";\r\ + \n#};\r\ + \n:global CertWarnTime 1w;\r\ + \n:global CertIssuedExportPass (a); # {\r\ + \n# \"\";\r\ + \n# \"cert1-cn\"=\"v3ry-s3cr3t\";\r\ + \n# \"cert2-cn\"=\"4n0th3r-s3cr3t\";\r\ + \n#};\r\ + \n\r\ + \n# Script BackupAndUpdate mode, possible values: backup,\r\ + \n# updateOnce - Update once as \"osnotify\" and back \"osnotify\" mode (i\ + n terminal run :set OSUpdateMode updateOnce; \$OSUpdateMode;). \r\ + \n# osupdate - Update if available and creates backups before/after update\ + \_(ignores `forceBackup`)\r\ + \n# Set `forceBackup` to true to always create backups, even\ + \_without updates\r\ + \n# osnotify - Set `forceBackup` to always create backups on every run\r\ + \n:global DevInfoIncludeIP true;\r\ + \n:global BackupAndUpdateMode \"osnotify\"\r\ + \n\r\ + \n:global forceBackup true;\r\ + \n:global BackupPassword \"Peskar55\";\r\ + \n\r\ + \n# SFTP Backup Variables\r\ + \n:global BackupRandomDelay 0;\r\ + \n:global BackupUploadUrl \"sftp://amster.vados.ru/upload/\";\r\ + \n:global BackupUploadUser \$Identity;\r\ + \n:global BackupUploadPass \"root.mnuc.backuper\";\r\ + \n\r\ + \n:global BackupSendBinary true;\r\ + \n:global BackupSendExport true;\r\ + \n:global BackupSendGlobalConfig true;\r\ + \n:global BackupSendScripts true;\r\ + \n\r\ + \n# Remove local file after uploading if no errors\r\ + \n:global BackupRmLocal true;\r\ + \n\r\ + \n# Local Backups Root Directory \r\ + \n:global BackupLocalRoot \"tmpfs\";\r\ + \n\r\ + \n# Encrypt Backup\r\ + \n:global BackupEncrypt true;\r\ + \n\r\ + \n# Sensitive information in Backups\r\ + \n:global BackupSens true;\r\ + \n\r\ + \n# User Export\r\ + \n:global BackupUser true;\r\ + \n\r\ + \n# License Export (not for CHR, will silently skip)\r\ + \n:global BackupLicense false;\r\ + \n\r\ + \n# SSH Keys\r\ + \n:global BackupSshKeys true;\r\ + \n\r\ + \n# Certificate Export\r\ + \n:global BackupCerts true;\r\ + \n\r\ + \n# Certificate Password\r\ + \n:global BackupCertsPasswd \"\";\r\ + \n\r\ + \n# User-Manager Export\r\ + \n:global BackupUserMan false;\r\ + \n\r\ + \n# The Dude Export\r\ + \n:global BackupDude false;\r\ + \n\r\ + \n# User Files to export, comma-separated string or array of strings\r\ + \n# User Files are not removed on backup\r\ + \n# Any directory paths will be removed (/ -> _) on remote file\r\ + \n# Nonpresent files are silently skipped\r\ + \n:global BackupUserList \"autosupout.rif,autosupout.old.rif\";\r\ + \n\r\ + \n# load functions and any custom scripts\r\ + \n# [ /system/script/find where name=\"global-config-ov\ + erlay\" ], \\\r\ + \n# [ /system/script/find where name~\"^global-config-o\ + verlay\\\\.d/.\" ]\r\ + \n#\r\ + \n#:foreach Script in=([ /system/script/find where name=\"Amster-TGglobalV\ + ars\" ], [ /system/script/find where name=\"Amster-TGglobalFunc\" ]) do={\ + \r\ + \n# :onerror Err {\r\ + \n# /system/script/run \$Script;\r\ + \n# } do={\r\ + \n# :log error (\"Loading configuration from configs and functions\"\ + \_. [ /system/script/get \$Script name ] . \" failed: \" . \$Err);\r\ + \n# }\r\ + \n#}\r\ + \n#:log info \"\\ndevMode = \$devMode\";\r\ + \n#:log info \"\\ndevRunning = \$devRunning\";\r\ + \n:foreach Script in=[ /system/script/find where source~\"^#!rsc by Vados \ + GlobalRUN\\r\?\\n\" ] do={\r\ + \n :onerror Err {\r\ + \n /system/script/run \$Script;\r\ + \n } do={\r\ + \n :log error (\"Run script \" . [ /system/script/get \$Script name \ + ] . \" width marker \\\" GlobalRUN\\\" failed: \" . \$Err);\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n# signal we are ready\r\ + \n:set GlobalConfReady true;\r\ + \n:while (\$GlobalConfReady != true) do={:delay 500ms};\r\ + \n" +add comment="Global functions" dont-require-permissions=no name=AM-GlobalFunc \ + owner=AM-GlobalFunc policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\r\ + \n# RouterOS script: AM-GglobalFunc\r\ + \n# Script comment: Global functions\r\ + \n# Copyright (c) 2005-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version=7.19\r\ + \n# requires device-mode, fetch, scheduler\r\ + \n:local ExitOK false;\r\ + \n:local ScriptName [ :jobname ];\r\ + \n#:global checkRunJob \$SriptName;\r\ + \n#:global fixCRLF;\r\ + \n#:if (\$fixCRLF != false) do={\r\ + \n#:foreach fixScript in=([ /system/script/find where name~\"*\" ]) do={/s\ + ystem/script/set source=[ :tocrlf [ get \$fixScript source ] ] \$fixScript\ + }\r\ + \n#:if (\$fixCRLF != \"LF\") do={ /system/script/set source=[ :tocrlf [ g\ + et \$fixScript source ] ] \$fixScript};};\r\ + \n#}\r\ + \n:global GlobalFuncReady false;\r\ + \n\r\ + \n# Git commit id & info, expected configuration version\r\ + \n:global CommitId \"main/728/bebacfc7\";\r\ + \n:global CommitTAG \"unknown\";\r\ + \n:global CommitInfo \"Autocommit in repo: ros.vados.ru, generated by owne\ + r: root, in 11:00:05 30.06.2026.\";\r\ + \n\r\ + \n# The variables are received right here.\r\ + \n:global GlobalConfVersion 140;\r\ + \n\r\ + \n:global SumsDirAndFileName \"tmp/checksums.json\";\r\ + \n\r\ + \n:global Identity [/system/identity/get name];\r\ + \n:global IdentityShort [:pick \$Identity 0 18];\r\ + \n\r\ + \n:global devBoardName [/system/resource/get board-name];\r\ + \n:global devMode [/system/device-mode/get mode];\r\ + \n:global devCurArch [/system/resource/get architecture-name];\r\ + \n:global devCurVersion [/system/resource/get version];\r\ + \n\r\ + \n# Variables defined in AM-GlobalConfig.rsc\r\ + \n:global TerminalColorOutput;\r\ + \n:global CommentsInScripts;\r\ + \n:global DetectIpAddrDefault;\r\ + \n:global DetectIpAddrFallback;\r\ + \n:global updateChannel;\r\ + \n:global Domain;\r\ + \n:global EmailGeneralTo;\r\ + \n:global BackupAndUpdateMode;\r\ + \n\r\ + \n# Single functions, without nested functions.\r\ + \n:global MiniDateTimeStamp;\r\ + \n:global MicroDateTimeStamp;\r\ + \n\r\ + \n# Include globals \$PrintDebug and \$PrintDebugOverride\r\ + \n:global LogPrint;\r\ + \n\r\ + \n# DeviceInfo and Updates\r\ + \n:global IsCheckUpdates;\r\ + \n:global WaitCheckUpdates;\r\ + \n:global GetPubIp;\r\ + \n\r\ + \n:global GetArrDeviceInfo;\r\ + \n:global WaitArrDeviceInfo;\r\ + \n\r\ + \n:global devModel;\r\ + \n:global devRunningMode;\r\ + \n\r\ + \n:global devRbRevision;\r\ + \n:global devRbSerialNumber;\r\ + \n:global devRbVerAvail;\r\ + \n\r\ + \n:global runningChannelVersion;\r\ + \n:global runningChannel;\r\ + \n:global runningVersion;\r\ + \n\r\ + \n:global devBuildTime;\r\ + \n:global ROsVerAvail;\r\ + \n:global PkgUpdStatus;\r\ + \n:global currentUpdateChannel;\r\ + \n\r\ + \n:global ScriptInstallUpdate;\r\ + \n\r\ + \n:global DeviceInfo;\r\ + \n\r\ + \n:global OldMode;\r\ + \n\r\ + \n:global ParseKeyValueStore;\r\ + \n:global RandomDelay;\r\ + \n:global GetRandomNumber;\r\ + \n:global EscapeForRegEx;\r\ + \n:global CharacterMultiply;\r\ + \n:global CharacterReplace;\r\ + \n:global CleanFilePath;\r\ + \n:global CleanName;\r\ + \n\r\ + \n:global CommitBrief;\r\ + \n\r\ + \n:global EitherOr;\r\ + \n:global FormatLine;\r\ + \n:global GetRandom20CharAlNum;\r\ + \n:global GetRandom20CharHex;\r\ + \n:global GetRandomNumber;\r\ + \n:global Grep;\r\ + \n:global IfThenElse;\r\ + \n:global MAX;\r\ + \n:global MIN;\r\ + \n:global HumanReadableNum;\r\ + \n\r\ + \n:global IsFullyConnected;\r\ + \n:global IsDNSResolving;\r\ + \n:global IsTimeSync;\r\ + \n:global IsTimeSyncCached;\r\ + \n:global IsTimeSyncResetNtp;\r\ + \n\r\ + \n:global MkDir;\r\ + \n:global RmDir;\r\ + \n:global RmFile;\r\ + \n:global FileGet;\r\ + \n:global Unix2Dos;\r\ + \n:global UrlEncode;\r\ + \n:global WaitForFile;\r\ + \n:global ScriptLock;\r\ + \n:global SendTelegram;\r\ + \n:global NotificationFunctions;\r\ + \n:global SendNotification;\r\ + \n:global SendNotification2;\r\ + \n:global SymbolForNotification;\r\ + \n:global SymbolByUnicodeName;\r\ + \n:global ValidateSyntax;\r\ + \n:global CheckSumsVerify;\r\ + \n:global GlobalConfChanges;\r\ + \n:global GlobalConfMigration;\r\ + \n:global VersionToNum;\r\ + \n:global RequiredRouterOS;\r\ + \n:global ExitError;\r\ + \n:global ExitOnError;\r\ + \n\r\ + \n:global FetchHugeFiles;\r\ + \n:global FetchUserAgentStr;\r\ + \n:global FileExists;\r\ + \n:global CertificateAvailable;\r\ + \n:global CertificateDownload;\r\ + \n:global CertificateNameByCN;\r\ + \n:global CharacterMultiply;\r\ + \n\r\ + \n:global InspectVar;\r\ + \n:global InspectVarRet;\r\ + \n:global ParseCustom;\r\ + \n\r\ + \n:set IsCheckUpdates do={\r\ + \n :local isInfo [:tobool \$1];\r\ + \n :global updateChannel;\r\ + \n :global PkgUpdStatus;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n :global arrDeviceInfo;\r\ + \n :log info (\$0 . \" \\\$isInfo = \" . \$isInfo); \r\ + \n :local CurrentChannel [ /system/package/update/get channel ];\r\ + \n :if ([ :len \$updateChannel ] > 0 && \$CurrentChannel != \$updateChann\ + el) do={\r\ + \n :retry command={/system/package/update set channel=\$updateChannel} \ + \_delay=300ms max=5 on-error={};\r\ + \n :log info (\$0 . \" Set updates channel to: \$updateChannel\");\r\ + \n }\r\ + \n :local Update [ /system/package/update/get ];\r\ + \n :local Channel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set currentUpdateChannel \$Channel;\r\ + \n :log info (\$0 . \" Update Channel: \" . \$Channel . \".\");\r\ + \n :local StatusPkg \"undefined\";\r\ + \n :log info (\$0 . \" Checking for updates...\");\r\ + \n :retry command={:set \$StatusPkg ([/system/package/update/check-for-up\ + dates without-paging as-value]->\"status\")} \\\r\ + \n delay=300ms max=5 on-error={};\r\ + \n :log info (\$0 . \" \\\$StatusPkg = \" . \$StatusPkg);\r\ + \n :if (\$StatusPkg = \"New version is available\") do={ :set PkgUpdStatu\ + s true; } else={ :set PkgUpdStatus false; }\r\ + \n :set ROsVerAvail [ :tostr [ /system/package/update/get latest-version \ + ] ];\r\ + \n :log info (\$0 . \" \\\$PkgUpdStatus = \" . \$PkgUpdStatus);\r\ + \n :if (\$isInfo != false || \$PkgUpdStatus = true) do={\r\ + \n :log info (\$0 . \" \\\$PkgUpdStatus = \" . \$PkgUpdStatus);\r\ + \n :if ([ :typeof \$arrDeviceInfo ] != \"array\") do={\r\ + \n :set arrDeviceInfo [:toarray \$arrDeviceInfo];\r\ + \n }\r\ + \n :retry command={:set (\$arrDeviceInfo->\"devUpdates\") [ /system/pac\ + kage/update/get ]} delay=500ms max=5 on-error={:log error (\"Error\")};\r\ + \n :return true;\r\ + \n } else={\r\ + \n :return \$PkgUpdStatus;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set WaitCheckUpdates do={\r\ + \n :global IsCheckUpdates;\r\ + \n :global PkgUpdStatus;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n :global arrDeviceInfo;\r\ + \n :local Status \"\";\r\ + \n :local Update;\r\ + \n :local WaitCount 0;\r\ + \n :if ([ \$IsCheckUpdates true ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n :set Status [ :tostr [ /system/package/update/get status ] ];\r\ + \n :while ((\$Status = \"\" || \$Status = \"finding out latest version...\ + \") && \$WaitCount < 60) do={\r\ + \n :delay 1s;\r\ + \n :set WaitCount (\$WaitCount + 1);\r\ + \n :set Status [ :tostr [ /system/package/update/get status ] ];\r\ + \n }\r\ + \n :set Update [ /system/package/update/get ];\r\ + \n :set currentUpdateChannel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set ROsVerAvail [ :tostr (\$Update->\"latest-version\") ];\r\ + \n :if ((\$Update->\"status\") = \"New version is available\") do={\r\ + \n :set PkgUpdStatus true;\r\ + \n } else={\r\ + \n :set PkgUpdStatus false;\r\ + \n }\r\ + \n :if ([ :typeof \$arrDeviceInfo ] != \"array\") do={\r\ + \n :set arrDeviceInfo [:toarray \$arrDeviceInfo];\r\ + \n }\r\ + \n :set (\$arrDeviceInfo->\"devUpdates\") \$Update;\r\ + \n :if (\$Status = \"\" || \$Status = \"finding out latest version...\") \ + do={\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set WaitArrDeviceInfo do={\r\ + \n :global GetArrDeviceInfo;\r\ + \n :while ([ \$GetArrDeviceInfo ] = false) do={\r\ + \n :delay 1s;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set GetArrDeviceInfo do={\r\ + \n :global LogPrint;\r\ + \n :global arrDeviceInfo;\r\ + \n :global devBoardName;\r\ + \n :global devModel;\r\ + \n :global devRunning;\r\ + \n :global devCurArch;\r\ + \n :global devRbRevision;\r\ + \n :global devRbSerialNumber;\r\ + \n :global devBuildTime;\r\ + \n :global runningChannelVersion;\r\ + \n :global runningChannel;\r\ + \n :global runningVersion;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n\r\ + \n :local DeviceInfo;\r\ + \n :local Resource [/system/resource/get];\r\ + \n :local Update [ /system/package/update/get ];\r\ + \n :local VersionString [ :tostr (\$Resource->\"version\") ];\r\ + \n :local ChannelStart [ :find \$VersionString \" (\" ];\r\ + \n :local RouterBoard;\r\ + \n :local IsRouterBoard false;\r\ + \n :local RunningMode \"\";\r\ + \n\r\ + \n :set devCurArch [ :tostr (\$Resource->\"architecture-name\") ];\r\ + \n :set devBuildTime [ :tostr (\$Resource->\"build-time\") ];\r\ + \n :set runningChannelVersion \$VersionString;\r\ + \n :set runningVersion \$VersionString;\r\ + \n :set runningChannel \"\";\r\ + \n\r\ + \n :if ([ :typeof \$ChannelStart ] = \"num\" && \$ChannelStart >= 0) do=\ + {\r\ + \n :set runningVersion [ :pick \$VersionString 0 \$ChannelStart ];\r\ + \n :local ChannelRest [ :pick \$VersionString (\$ChannelStart + 2) [ :\ + len \$VersionString ] ];\r\ + \n :local ChannelEnd [ :find \$ChannelRest \")\" ];\r\ + \n :if ([ :typeof \$ChannelEnd ] = \"num\" && \$ChannelEnd >= 0) do={\ + \r\ + \n :set runningChannel [ :pick \$ChannelRest 0 \$ChannelEnd ];\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :if ([:pick \$devBoardName 0 3] != \"CHR\" or [:pick \$devBoardName 0\ + \_3] != \"x86\") do={\r\ + \n :do {\r\ + \n :set RouterBoard [[ :parse \"/system/routerboard/get\" ]];\r\ + \n# :set RouterBoard [ /system/routerboard/get ];\r\ + \n :if ((\$RouterBoard->\"routerboard\") = true) do={\r\ + \n :set IsRouterBoard true;\r\ + \n }\r\ + \n } on-error={}\r\ + \n }\r\ + \n\r\ + \n :do {\r\ + \n :set RunningMode [ /system/device-mode/get mode ];\r\ + \n } on-error={\r\ + \n :do {\r\ + \n :set RunningMode [ /system/device-mode/get running ];\r\ + \n } on-error={\r\ + \n :set RunningMode \"\";\r\ + \n }\r\ + \n }\r\ + \n :set devRunning \$RunningMode;\r\ + \n\r\ + \n :if (\$IsRouterBoard = true) do={\r\ + \n :set devModel [ :tostr (\$RouterBoard->\"model\") ];\r\ + \n :set devRbRevision [ :tostr (\$RouterBoard->\"revision\") ];\r\ + \n :set devRbSerialNumber [ :tostr (\$RouterBoard->\"serial-number\") \ + ];\r\ + \n } else={\r\ + \n :set devModel \$devBoardName;\r\ + \n :set devRbRevision \"\";\r\ + \n :set devRbSerialNumber \"\";\r\ + \n }\r\ + \n\r\ + \n :set currentUpdateChannel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set ROsVerAvail [ :tostr (\$Update->\"latest-version\") ];\r\ + \n\r\ + \n :set (\$DeviceInfo->\"board-name\") \$devBoardName;\r\ + \n :set (\$DeviceInfo->\"architecture-name\") \$devCurArch;\r\ + \n :set (\$DeviceInfo->\"model\") \$devModel;\r\ + \n :set (\$DeviceInfo->\"revision\") \$devRbRevision;\r\ + \n :set (\$DeviceInfo->\"serial-number\") \$devRbSerialNumber;\r\ + \n :set (\$DeviceInfo->\"running-mode\") \$devRunning;\r\ + \n :set (\$DeviceInfo->\"build-time\") \$devBuildTime;\r\ + \n :set (\$DeviceInfo->\"running-channel-version\") \$runningChannelVers\ + ion;\r\ + \n :set (\$DeviceInfo->\"running-version\") \$runningVersion;\r\ + \n :set (\$DeviceInfo->\"running-channel\") \$runningChannel;\r\ + \n :set (\$DeviceInfo->\"routerboard\") \$IsRouterBoard;\r\ + \n :set (\$DeviceInfo->\"current-firmware\") [ :tostr (\$RouterBoard->\"\ + current-firmware\") ];\r\ + \n :set (\$DeviceInfo->\"upgrade-firmware\") [ :tostr (\$RouterBoard->\"\ + upgrade-firmware\") ];\r\ + \n :set (\$DeviceInfo->\"package-channel\") \$currentUpdateChannel;\r\ + \n :set (\$DeviceInfo->\"installed-version\") [ :tostr (\$Update->\"inst\ + alled-version\") ];\r\ + \n :set (\$DeviceInfo->\"latest-version\") \$ROsVerAvail;\r\ + \n :set (\$DeviceInfo->\"update-status\") [ :tostr (\$Update->\"status\"\ + ) ];\r\ + \n\r\ + \n :set arrDeviceInfo \$DeviceInfo;\r\ + \n :return \$DeviceInfo;\r\ + \n}\r\ + \n\r\ + \n:set DeviceInfo do={\r\ + \n :global GetArrDeviceInfo;\r\ + \n :global GlobalConfVersion;\r\ + \n :global Identity;\r\ + \n :global IfThenElse;\r\ + \n :global FormatLine;\r\ + \n :global CommitBrief;\r\ + \n\r\ + \n :local License [/system/license/get];\r\ + \n :local Snmp [ /snmp/get ];\r\ + \n :local Info [ \$GetArrDeviceInfo ];\r\ + \n\r\ + \n :if ([ :typeof \$Info ] != \"array\") do={\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :return ( \\\r\ + \n [ \$FormatLine \"Hostname\" \$Identity ] . \"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$Snmp->\"location\") ] > 0) \\\r\ + \n ([ \$FormatLine \"Location\" (\$Snmp->\"location\") ] . \"\\n\") ]\ + \_. \\\r\ + \n [ \$IfThenElse ([ :len (\$Snmp->\"contact\") ] > 0) \\\r\ + \n ([ \$FormatLine \"Contact\" (\$Snmp->\"contact\") ] . \"\\n\") ] .\ + \_\\\r\ + \n \"Hardware:\\n\" . \\\r\ + \n [ \$FormatLine \" Board\" (\$Info->\"board-name\") ] . \"\\n\" . \ + \\\r\ + \n [ \$FormatLine \" Arch\" (\$Info->\"architecture-name\") ] . \"\\\ + n\" . \\\r\ + \n [ \$FormatLine \" Model\" (\$Info->\"model\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"revision\") ] > 0) \\\r\ + \n (\" \" . (\$Info->\"revision\")) ] . \"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"serial-number\") ] > 0) \\\r\ + \n ([ \$FormatLine \" Serial\" (\$Info->\"serial-number\") ] . \"\ + \\n\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$License->\"nlevel\") ] > 0) \\\r\ + \n ([ \$FormatLine \" License\" (\"level \" . (\$License->\"nlevel\ + \")) ] . \"\\n\") ] . \\\r\ + \n \"RouterOS:\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$License->\"level\") ] > 0) \\\r\ + \n ([ \$FormatLine \" License\" (\"level \" . (\$License->\"level\ + \")) ] . \"\\n\") ] . \\\r\ + \n [ \$FormatLine \" Channel\" (\$Info->\"package-channel\") ] . \"\ + \\n\" . \\\r\ + \n [ \$FormatLine \" Installed\" (\$Info->\"installed-version\") ] .\ + \_\"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"running-channel\") ] > 0) \\\r\ + \n ([ \$FormatLine \" Running\" ((\$Info->\"running-version\") . \ + \" (\" . (\$Info->\"running-channel\") . \")\") ] . \"\\n\") \\\r\ + \n ([ \$FormatLine \" Running\" (\$Info->\"running-version\") ] . \ + \"\\n\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"latest-version\") ] > 0 && \\\r\ + \n (\$Info->\"installed-version\") != (\$Info->\"latest-version\"))\ + \_\\\r\ + \n ([ \$FormatLine \" Available\" (\$Info->\"latest-version\") ] .\ + \_\"\\n\") ] . \\\r\ + \n [ \$IfThenElse ((\$Info->\"routerboard\") = true && \\\r\ + \n (\$Info->\"current-firmware\") != (\$Info->\"upgrade-firmware\")\ + ) \\\r\ + \n ([ \$FormatLine \" Firmware\" ((\$Info->\"current-firmware\") .\ + \_\" -> \" . (\$Info->\"upgrade-firmware\")) ] . \"\\n\") ] . \\\r\ + \n \"RouterOS-Scripts:\\n\" . \\\r\ + \n [ \$FormatLine \" Commit\" [ \$CommitBrief ] ] . \"\\n\" . \\\r\ + \n [ \$FormatLine \" Version\" \$GlobalConfVersion ]);\r\ + \n}\r\ + \n\r\ + \n:if ([ :typeof \$NotificationFunctions ] != \"array\") do={:set Notifica\ + tionFunctions ({})}\r\ + \n\r\ + \n:set GetRandom20CharAlNum do={\r\ + \n :global EitherOr;\r\ + \n :return [ :rndstr length=[ \$EitherOr [ :tonum \$1 ] 20 ] from=\"ABCDE\ + FGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\" ];\r\ + \n}\r\ + \n\r\ + \n:set GetRandom20CharHex do={:global EitherOr; :return [ :rndstr length=[\ + \_\$EitherOr [ :tonum \$1 ] 20 ] from=\"0123456789abcdef\" ]; }\r\ + \n:set GetRandomNumber do={:global EitherOr; :return [ :rndnum from=0 to=[\ + \_\$EitherOr [ :tonum \$1 ] 4294967295 ] ]; }\r\ + \n\r\ + \n:global checkRunJob;\r\ + \n:set checkRunJob do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :global ScriptLock; \r\ + \n :if ([ \$ScriptLock \$Script ] = false) do={:return false}\r\ + \n :foreach Job in=[ /system/script/job/find where script=\$Script ] do={\ + :set Job [ /system/script/job/get \$Job ];\r\ + \n :while ([ :typeof (\$Job->\"parent\") ] = \"id\") do={:set Job [ /sy\ + stem/script/job/get [ find where .id=(\$Job->\"parent\") ] ]}\r\ + \n :if ((\$Job->\"type\") = \"login\") do={:return true};}; :return fa\ + lse; \r\ + \n}\r\ + \n\r\ + \n:set InspectVar do={\r\ + \n :global InspectVarRet;\r\ + \n :put [ :tocrlf [ \$InspectVarRet \$1 ] ];\r\ + \n}\r\ + \n\r\ + \n:set CommitBrief do={\r\ + \n :global CommitId;\r\ + \n :global CommitInfo;\r\ + \n :if (\$CommitId = \"unknown\") do={\r\ + \n :return \"unknown\";\r\ + \n }\r\ + \n :return (\$CommitInfo . \"/\" . [ :pick \$CommitId 0 8 ]);\r\ + \n}\r\ + \n\r\ + \n:set InspectVarRet do={\r\ + \n :local Input \$1;\r\ + \n :local Level (0 + [ :tonum \$2 ]);\r\ + \n :global CharacterReplace;\r\ + \n :global IfThenElse;\r\ + \n :global InspectVarRet;\r\ + \n :local IndentReturn do={\r\ + \n :local Prefix [ :tostr \$1 ];\r\ + \n :local Value [ :tostr \$2 ];\r\ + \n :local Level [ :tonum \$3 ];\r\ + \n :global CharacterMultiply;\r\ + \n :return ([ \$CharacterMultiply \" \" (\$Level * 2) ] . \"-\" . \$Pre\ + fix . \"-> \" . \$Value);\r\ + \n }\r\ + \n :local TypeOf [ :typeof \$Input ];\r\ + \n :local Len [ :len \$Input ];\r\ + \n :local Return [ \$IndentReturn \"type\" \$TypeOf \$Level ];\r\ + \n :if (\$TypeOf = \"array\") do={\r\ + \n :foreach Key,Value in=\$Input do={\r\ + \n :set \$Return (\$Return . \"\\n\" . \\\r\ + \n [ \$IndentReturn \"key\" \$Key (\$Level + 1) ] . \"\\n\" . \\\r\ + \n [ \$InspectVarRet \$Value (\$Level + 2) ]);\r\ + \n }\r\ + \n } else={\r\ + \n :if (\$TypeOf = \"str\") do={\r\ + \n :set \$Return (\$Return . \"\\n\" . \\\r\ + \n [ \$IndentReturn \"len\" \$Len \$Level ]);\r\ + \n :if ([ :typeof [ :find \$Input (\"\\r\") ] ] = \"num\") do={\r\ + \n :set Input [ \$CharacterReplace \$Input (\"\\r\") \"\" ];\r\ + \n }\r\ + \n :if ([ :typeof [ :find \$Input (\"\\n\") ] ] = \"num\") do={\r\ + \n :set Input [ \$CharacterReplace \$Input (\"\\n\") \" \" ];\r\ + \n }\r\ + \n }\r\ + \n :if (\$TypeOf != \"nothing\") do={\r\ + \n :set \$Return (\$Return . \"\\n\" . \\\r\ + \n [ \$IndentReturn \"value\" [ \$IfThenElse ([ :len \$Input ] > 80)\ + \_\\\r\ + \n ([ :pick \$Input 0 77 ] . \"...\") \$Input ] \$Level ]);\r\ + \n }\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set GetPubIp do={\r\ + \n :global DetectIpAddrDefault;\r\ + \n :global DetectIpAddrFallback;\r\ + \n\r\ + \n :local PubIpAddr false;\r\ + \n :local Url \$DetectIpAddrDefault;\r\ + \n :local JobName [ :jobname ];\r\ + \n\r\ + \n :do {\r\ + \n :log debug (\$0 . \" Trying to detect public IP using default serv\ + ice: \" . \$Url . \"...\");\r\ + \n :retry command={:set PubIpAddr ([ /tool/fetch http-method=\"get\"\ + \_check-certificate=yes-without-crl \$Url output=user as-value ]->\"data\"\ + )} \\\r\ + \n delay=50ms max=5 on-error={:log error (\$JobName . \" Failed to \ + detect public IP using default service: \" . \$Url . \".\")}\r\ + \n } on-error={\r\ + \n :log error (\$0 . \" Failed to detect public IP using default serv\ + ice: \" . \$Url . \".\");\r\ + \n :set Url \$DetectIpAddrFallBack;\r\ + \n :log debug (\$0 . \" Trying to detect public IP using fallback ser\ + vice: \" . \$Url . \"...\");\r\ + \n :retry command={:set PubIpAddr ([ /tool/fetch http-method=\"get\"\ + \_check-certificate=yes-without-crl \$Url output=user as-value ]->\"data\"\ + )} \\\r\ + \n delay=200ms max=5 on-error={:log error (\$JobName . \" Failed to\ + \_detect public IP using fallback service: \" . \$Url . \".\")}\r\ + \n };\r\ + \n :local IpLen ([ :len \$PubIpAddr ] -1);\r\ + \n :if (\$PubIpAddr = false) do={:set PubIpAddr \"not-detected\"} else=\ + {:set PubIpAddr [:pick \$PubIpAddr 0 \$IpLen]}\r\ + \n :return \$PubIpAddr;\r\ + \n}\r\ + \n\r\ + \n:set FormatLine do={\r\ + \n :local Key [ :tostr \$1 ];\r\ + \n :local Value [ :tostr \$2 ];\r\ + \n :local Indent [ :tonum \$3 ];\r\ + \n :local Spaces;\r\ + \n :local Return \"\";\r\ + \n :global CharacterMultiply;\r\ + \n :global EitherOr;\r\ + \n :set Indent [ \$EitherOr \$Indent 16 ];\r\ + \n :local Spaces [ \$CharacterMultiply \" \" \$Indent ];\r\ + \n :if ([ :len \$Key ] > 0) do={ :set Return (\$Key . \":\")}\r\ + \n :if ([ :len \$Key ] > (\$Indent - 2)) do={:set Return (\$Return . \"\\\ + n\" . [ :pick \$Spaces 0 \$Indent ] . \$Value);\r\ + \n } else={:set Return (\$Return . [ :pick \$Spaces 0 (\$Indent - [ :len \ + \$Return ]) ] . \$Value)}\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set ParseCustom do={\r\ + \n :local Str [ :tostr \$1 ];\r\ + \n :local Start [:find [ \$Str ] [:tostr \$2]];\r\ + \n :local End [ :tostr \$3 ];\r\ + \n :local Num [ :tonum \$4 ];\r\ + \n :local Return;\r\ + \n :if ([:len \$Num] = 0) do={:set Num \"0\"}\r\ + \n :local rest [:pick \$Str (\$Start+\$Num) [:len \$Str]]; \r\ + \n :if ([:len \$End ] = 0) do={:set Return [:pick \$Str \$Num \$Start]} e\ + lse={\r\ + \n :set End [:find \$rest \$End];\r\ + \n :set Return [:pick \$rest 0 \$End];\r\ + \n }\r\ + \n:return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set LogPrint do={\r\ + \n :local Severity [ :tostr \$1 ];\r\ + \n :local Name [ :tostr \$2 ];\r\ + \n :local Message [ :tostr \$3 ];\r\ + \n :global PrintDebug;\r\ + \n :global PrintDebugOverride;\r\ + \n :global EitherOr;\r\ + \n :local Debug [ \$EitherOr (\$PrintDebugOverride->\$Name) \$PrintDebug \ + ];\r\ + \n :local PrintSeverity do={\r\ + \n :global TerminalColorOutput;\r\ + \n :if (\$TerminalColorOutput != true) do={:return \$1}\r\ + \n :local Color { debug=96; info=97; warning=93; error=91 };\r\ + \n :return (\"\\1B[\" . \$Color->\$1 . \"m\" . \$1 . \"\\1B[0m\");\r\ + \n}\r\ + \n :local Log ([ \$EitherOr \$Name \"\" ] . \": \" . \$Message);\ + \r\ + \n :if (\$Severity ~ (\"^(custom|debug|error|info)\\\$\")) do={\r\ + \n :if (\$Severity = \"debug\") do={:log debug \$Log}\r\ + \n :if (\$Severity = \"error\") do={:log error \$Log}\r\ + \n :if (\$Severity = \"info\" ) do={:log info \$Log}\r\ + \n } else={:log warning \$Log; :set Severity \"warning\"}\r\ + \n :if (\$Severity != \"debug\" || \$Debug = true) do={:put ([ \$PrintSev\ + erity \$Severity ] . \": \" . \$Message)}\r\ + \n}\r\ + \n\r\ + \n:set CertificateAvailable do={\r\ + \n :local CommonName [ :tostr \$1 ];\r\ + \n :local UseFor [ :tostr \$2 ];\r\ + \n\r\ + \n :global CertificateDownload;\r\ + \n :global ParseKeyValueStore;\r\ + \n\r\ + \n :if ([ :len \$UseFor ] = 0) do={\r\ + \n :log warning (\$0 . \"The intended use is undefined!\");\r\ + \n :set UseFor \"undefined\";\r\ + \n }\r\ + \n :if ([ /system/resource/get free-hdd-space ] < 8388608 && \\\r\ + \n [ /certificate/settings/get crl-download ] = true && \\\r\ + \n [ /certificate/settings/get crl-store ] = \"system\") do={\r\ + \n :log warning (\$0 . \"This system has low free flash space but \" . \ + \\\r\ + \n \"is configured to download certificate CRLs to system!\");\r\ + \n }\r\ + \n :if ([ :len \$CommonName ] = 0) do={\r\ + \n :log warning (\$0 . \"No CommonName given!\");\r\ + \n :return false;\r\ + \n }\r\ + \n :local CertSettings [ /certificate/settings/get ];\r\ + \n :if (((\$CertSettings->\"builtin-trust-anchors\") = \"trusted\" || \\\ + \r\ + \n (\$CertSettings->\"builtin-trust-store\") ~ \$UseFor || \\\r\ + \n (\$CertSettings->\"builtin-trust-store\") = \"all\") && \\\r\ + \n [ :len [ /certificate/builtin/find where common-name=\$CommonName\ + \_] ] > 0) do={\r\ + \n :return true;\r\ + \n }\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] = 0\ + ) do={\r\ + \n :log info (\$0 . \"Certificate with CommonName '\" . \$CommonName . \ + \"' not available.\");\r\ + \n :if ([ \$CertificateDownload \$CommonName ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] > 1\ + ) do={\r\ + \n :log info (\$0 . \"There are \" . \$CertCount . \" Certificates with\ + \_CommonName '\" . \$CommonName . \"'. Should be ok.\");\r\ + \n :return true;\r\ + \n }\r\ + \n :local CertVal [ /certificate/get [ find where common-name=\$CommonNam\ + e ] ];\r\ + \n :while ((\$CertVal->\"akid\") != \"\" && (\$CertVal->\"akid\") != (\$C\ + ertVal->\"skid\")) do={\r\ + \n :if ([ :len [ /certificate/find where skid=(\$CertVal->\"akid\") ] ]\ + \_= 0) do={\r\ + \n :local IssuerCN ([ \$ParseKeyValueStore (\$CertVal->\"issuer\") ]-\ + >\"CN\");\r\ + \n :log info (\$0 . \"Certificate chain for '\" . \$CommonName . \"' \ + is incomplete, missing '\" . \$IssuerCN . \"'.\");\r\ + \n :if ([ \$CertificateDownload \$IssuerCN ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n :set CertVal [ /certificate/get [ find where skid=(\$CertVal->\"akid\ + \") ] ];\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set CertificateDownload do={\r\ + \n :local CommonName [ :tostr \$1 ];\r\ + \n :global ScriptUpdatesBaseUrl;\r\ + \n :global ScriptUpdatesUrlSuffix;\r\ + \n :global CertificateNameByCN;\r\ + \n :global CleanName;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global RmFile;\r\ + \n :global WaitForFile;\r\ + \n\r\ + \n :log info (\$0 . \"Downloading and importing certificate with \" . \\\ + \r\ + \n \"CommonName '\" . \$CommonName . \"'.\");\r\ + \n :local FileName ([ \$CleanName \$CommonName ] . \".pem\");\r\ + \n :do {\r\ + \n /tool/fetch check-certificate=yes-without-crl mode=https http-header\ + -field=({ [ \$FetchUserAgentStr \$0 ] }) \\\r\ + \n (\$ScriptUpdatesBaseUrl . \"certs/\" . \$FileName . \$ScriptUpdate\ + sUrlSuffix) \\\r\ + \n dst-path=\$FileName as-value;\r\ + \n \$WaitForFile \$FileName;\r\ + \n } on-error={\r\ + \n :log warning (\$0 . \" Failed downloading certificate with CommonNam\ + e '\" . \$CommonName . \\\r\ + \n \"' from repository! Trying fallback to mkcert.org...\");\r\ + \n :do {\r\ + \n :local CertSettings [ /certificate/settings/get ];\r\ + \n :if ([ :len [ /certificate/find where common-name=\"ISRG Root X1\"\ + \_] ] = 0 && \\\r\ + \n !(((\$CertSettings->\"builtin-trust-anchors\") = \"trusted\" \ + || \\\r\ + \n (\$CertSettings->\"builtin-trust-store\") ~ \"fetch\" || \ + \\\r\ + \n (\$CertSettings->\"builtin-trust-store\") = \"all\") && \\\ + \r\ + \n [ :len [ /certificate/builtin/find where common-name=\"ISRG\ + \_Root X1\" ] ] > 0)) do={\r\ + \n :log error (\$0 . \" Required certificate is not available.\");\ + \r\ + \n :return false;\r\ + \n }\r\ + \n /tool/fetch check-certificate=yes-without-crl mode=https http-head\ + er-field=({ [ \$FetchUserAgentStr \$0 ] }) \\\r\ + \n url=\"https://mkcert.org/generate/\" http-data=[ :serialize to=jso\ + n ({ \$CommonName }) ] \\\r\ + \n dst-path=\$FileName as-value;\r\ + \n \$WaitForFile \$FileName;\r\ + \n :if ([ /file/get \$FileName size ] = 0) do={\r\ + \n \$RmFile \$FileName;\r\ + \n :error false;\r\ + \n }\r\ + \n } on-error={\r\ + \n :log error (\$0 . \" Failed downloading certificate with CommonNam\ + e '\" . \$CommonName . \"'!\");\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n /certificate/import file-name=\$FileName passphrase=\"\" as-value;\r\ + \n :delay 1s;\r\ + \n \$RmFile \$FileName;\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] = 0\ + ) do={\r\ + \n /certificate/remove [ find where name~(\"^\" . \$FileName . \"_[0-9]\ + +\\\$\") ];\r\ + \n :log warning (\$0 . \" Certificate with CommonName '\" . \$CommonNam\ + e . \"' still unavailable!\");\r\ + \n :return false;\r\ + \n }\r\ + \n :foreach Cert in=[ /certificate/find where name~(\"^\" . \$FileName . \ + \"_[0-9]+\\\$\") ] do={\r\ + \n \$CertificateNameByCN [ /certificate/get \$Cert common-name ];\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set CertificateNameByCN do={\r\ + \n :local Match [ :tostr \$1 ];\r\ + \n :global CleanName;\r\ + \n :local Cert ([ /certificate/find where (common-name=\$Match or fingerp\ + rint=\$Match or name=\$Match) ]->0);\r\ + \n :if ([ :len \$Cert ] = 0) do={\r\ + \n :log warning (\$0 .\" No matching certificate found.\");\r\ + \n :return false;\r\ + \n }\r\ + \n :local CommonName [ /certificate/get \$Cert common-name ];\r\ + \n /certificate/set \$Cert name=[ \$CleanName \$CommonName ];\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set CharacterMultiply do={\r\ + \n :local Str [ :tostr \$1 ];\r\ + \n :local Num [ :tonum \$2 ];\r\ + \n :if (\$Num = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :for I from=1 to=\$Num do={:set Return (\$Return . \$Str)}\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set FileExists do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :local Type [ :tostr \$2 ];\r\ + \n :global FileGet;\r\ + \n :local FileVal [ \$FileGet \$FileName ];\r\ + \n :if (\$FileVal = false) do={ :return false; }\r\ + \n :if ([ :len (\$FileVal->\"size\") ] = 0) do={ :return false; }\r\ + \n :if ([ :len \$Type ] = 0 || \$FileVal->\"type\" = \$Type) do={ :return\ + \_true; }\r\ + \n :return false;\r\ + \n}\r\ + \n\r\ + \n:set Grep do={\r\ + \n :local Input ([ :tostr \$1 ] . \"\\n\");\r\ + \n :local Pattern [ :tostr \$2 ];\r\ + \n :if ([ :typeof [ :find \$Input \$Pattern ] ] = \"nil\") do={:return []\ + }\r\ + \n :do {\r\ + \n :local Line [ :pick \$Input 0 [ :find \$Input \"\\n\" ] ];\r\ + \n :if ([ :typeof [ :find \$Line \$Pattern ] ] = \"num\") do={:return \ + \$Line}\r\ + \n :set Input [ :pick \$Input ([ :find \$Input \"\\n\" ] + 1) [ :len \$\ + Input ] ];\r\ + \n } while=([ :len \$Input ] > 0);\r\ + \n :return [];\r\ + \n}\r\ + \n\r\ + \n:set HumanReadableNum do={\r\ + \n :local Input [ :tonum \$1 ];\r\ + \n :local Base [ :tonum \$2 ];\r\ + \n :global EitherOr;\r\ + \n :global IfThenElse;\r\ + \n :local Prefix \"kMGTPE\";\r\ + \n :local Pow 1;\r\ + \n :set Base [ \$EitherOr \$Base 1024 ];\r\ + \n :local Bin [ \$IfThenElse (\$Base = 1024) \"i\" \"\" ];\r\ + \n :if (\$Input < \$Base) do={:return \$Input}\r\ + \n :for I from=0 to=[ :len \$Prefix ] do={\r\ + \n :set Pow (\$Pow * \$Base);\r\ + \n :if (\$Input / \$Base < \$Pow) do={\r\ + \n :set Prefix [ :pick \$Prefix \$I ];\r\ + \n :local Tmp1 (\$Input * 100 / \$Pow);\r\ + \n :local Tmp2 (\$Tmp1 / 100);\r\ + \n :if (\$Tmp2 >= 100) do={:return (\$Tmp2 . \$Prefix . \$Bin)}\r\ + \n :return (\$Tmp2 . \".\" . \\\r\ + \n [ :pick \$Tmp1 [ :len \$Tmp2 ] ([ :len \$Tmp1 ] - [ :len \$Tmp\ + 2 ] + 1) ] . \\\r\ + \n \$Prefix . \$Bin);\r\ + \n }\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set CleanFilePath do={\r\ + \n :local Path [ :tostr \$1 ];\r\ + \n :global CharacterReplace;\r\ + \n :while (\$Path ~ \"//\") do={ :set \$Path [ \$CharacterReplace \$Path \ + \"//\" \"/\" ]; }\r\ + \n :if ([ :pick \$Path 0 ] = \"/\") do={ :set Path [ :pick \$Path 1 [ :le\ + n \$Path ] ]; }\r\ + \n :if ([ :pick \$Path ([ :len \$Path ] - 1) ] = \"/\") do={ :set Path [ \ + :pick \$Path 0 ([ :len \$Path ] - 1) ]; }\r\ + \n :return \$Path;\r\ + \n}\r\ + \n\r\ + \n:set CleanName do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :local Return \"\";\r\ + \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ + \n :local Char [ :pick \$Input \$I ];\r\ + \n :if ([ :typeof [ find \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr\ + stuvwxyz0123456789\" \$Char ] ] = \"nil\") do={\r\ + \n :do {:if ([ :len \$Return ] = 0) do={:error true};\r\ + \n :if ([ :pick \$Return ([ :len \$Return ] - 1) ] = \"-\") do={:er\ + ror true}; :set Char \"-\"} on-error={:set Char \"\"}; \r\ + \n };\r\ + \n :set Return (\$Return . \$Char)};\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set RandomDelay do={\r\ + \n :local Time [ :tonum \$1 ];\r\ + \n :local Unit [ :tostr \$2 ];\r\ + \n :global EitherOr;\r\ + \n :global GetRandomNumber;\r\ + \n :global MAX;\r\ + \n :if (\$Time = 0) do={:return false}\r\ + \n :delay ([ \$MAX 10 [ \$GetRandomNumber ([ :tonsec [ :totime (\$Time . \ + [ \$EitherOr \$Unit \"s\" ]) ] ] / 1000000) ] ] . \"ms\");\r\ + \n}\r\ + \n\r\ + \n:set EscapeForRegEx do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :if ([ :len \$Input ] = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :local Chars (\"^.[]\\\$()|*+\?{}\\\\\");\r\ + \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ + \n :local Char [ :pick \$Input \$I ];\r\ + \n :if ([ :find \$Chars \$Char ]) do={:set Char (\"\\\\\" . \$Char)}\r\ + \n :set Return (\$Return . \$Char);\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set ExitError do={\r\ + \n :local ExitOK [ :tostr \$1 ];\r\ + \n :local Name [ :tostr \$2 ];\r\ + \n :local Error [ :tostr \$3 ];\r\ + \n :global IfThenElse;\r\ + \n :if (\$ExitOK = \"false\") do={\r\ + \n :log error (\$Name [ \$IfThenElse ([ :pick \$Name 0 1 ] = \"\\\$\") \ + \\\r\ + \n \"Function\" \"Script\" ] . \" '\" . \$Name . \"' exited with er\ + ror\" . \\\r\ + \n [ \$IfThenElse (!(\$Error ~ \"^(|true|false)\\\$\")) (\": \" . \ + \$Error) \".\" ]);\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set ExitOnError do={\r\ + \n :local Name [ :tostr \$1 ];\r\ + \n :local Error [ :tostr \$2 ];\r\ + \n :global IfThenElse;\r\ + \n :log error (\$Name . \" \" . [ \$IfThenElse ([ :pick \$Name 0 1 ] = \"\ + \\\$\") \\\r\ + \n \"Function\" \"Script\" ] . \" '\" . \$Name . \"' exited with erro\ + r\" . \\\r\ + \n [ \$IfThenElse (!(\$Error ~ \"^(|true|false)\\\$\")) (\": \" . \$E\ + rror) \".\" ]);\r\ + \n}\r\ + \n\r\ + \n:set MiniDateTimeStamp do={\r\ + \n :local mikro [ :tobool \$1 ];\r\ + \n /system/clock;\r\ + \n :local vdate [get date];\r\ + \n :local vtime [get time];\r\ + \n :local vdoff [:toarray \"0,4,5,7,8,10\"];\r\ + \n :local MM [:pick \$vdate (\$vdoff->2) (\$vdoff->3)];\r\ + \n :local M [:tonum \$MM];\r\ + \n :if (\$vdate ~ \".../../....\") do={\r\ + \n :set vdoff [:toarray \"7,11,1,3,4,6\"];\r\ + \n :set M ([:find \"xxanebarprayunulugepctovecANEBARPRAYUNULUGE\ + PCTOVEC\" [:pick \$vdate (\$vdoff->2) (\$vdoff->3)] -1] / 2);\r\ + \n :if (\$M>12) do={:set M (\$M - 12)}\r\ + \n :set MM [:pick (100 + \$M) 1 3];\r\ + \n }\r\ + \n :local yyyy [:pick \$vdate (\$vdoff->0) (\$vdoff->1)];\r\ + \n :local dd [:pick \$vdate (\$vdoff->4) (\$vdoff->5)];\r\ + \n :local HH [:pick \$vtime 0 2];\r\ + \n :local mm [:pick \$vtime 3 5];\r\ + \n :local ss [:pick \$vtime 6 8];\r\ + \n :local Return;\r\ + \n :if (\$mikro = true) do={\r\ + \n :set Return ([:pick \$yyyy 2 4] . [:pick \$dd 0 1] . [:pick \$HH 0\ + \_1] . [:pick \$mm 3 4] . [:pick \$ss 6 7]);\r\ + \n } else={\r\ + \n :set Return ([\$yyyy] . [\$MM] . [\$dd] . [\$HH] . [\$mm] . [\$ss]);\ + \r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set WaitForFile do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :local WaitTime [ :totime \$2 ];\r\ + \n :global CleanFilePath;\r\ + \n :global EitherOr;\r\ + \n :global MAX;\r\ + \n :set FileName [ \$CleanFilePath \$FileName ];\r\ + \n :local Delay ([ \$MAX [ \$EitherOr \$WaitTime 2s ] 100ms ] / 9);\r\ + \n :do {\r\ + \n :retry {\r\ + \n /file/get \$FileName;\r\ + \n :return true;\r\ + \n } delay=\$Delay max=10;\r\ + \n } on-error={ }\r\ + \n :while ([ :len [ /file/find where name=\$FileName ] ] > 0) do={\r\ + \n :do {\r\ + \n /file/get \$FileName;\r\ + \n :return true;\r\ + \n } on-error={ }\r\ + \n :delay \$Delay;\r\ + \n :set Delay (\$Delay * 3 / 2);\r\ + \n }\r\ + \n :return false;\r\ + \n}\r\ + \n\r\ + \n:set FileGet do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :global WaitForFile;\r\ + \n :if ([ \$WaitForFile \$FileName 0s ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n :local FileVal false;\r\ + \n :do {\r\ + \n :set FileVal [ /file/get \$FileName ];\r\ + \n } on-error={ }\r\ + \n :return \$FileVal;\r\ + \n}\r\ + \n\r\ + \n:set RmDir do={\r\ + \n :local DirName [ :tostr \$1 ];\r\ + \n :global FileGet;\r\ + \n :log debug (\$0 . \" Removing directory: \". \$DirName);\r\ + \n :local DirVal [ \$FileGet \$DirName ];\r\ + \n :if (\$DirVal = false) do={\r\ + \n :log debug (\$0 . \" ... which does not exist.\");\r\ + \n :return true;\r\ + \n };\r\ + \n :if (\$DirVal->\"type\" != \"directory\") do={\r\ + \n :log error (\$0 . \" Directory '\" . \$DirName . \"' is not a direct\ + ory.\");\r\ + \n :return false;\r\ + \n };\r\ + \n :onerror Err {\r\ + \n /file/remove \$DirName;\r\ + \n } do={\r\ + \n :log error (\$0 . \" Removing directory '\" . \$DirName . \"' failed\ + : \" . \$Err);\r\ + \n :return false;\r\ + \n };\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set RmFile do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :global FileGet;\r\ + \n :log debug (\$0 . \" Removing file: \". \$FileName);\r\ + \n :local FileVal [ \$FileGet \$FileName ];\r\ + \n :if (\$FileVal = false) do={\r\ + \n :log debug (\$0 . \" ... which does not exist.\");\r\ + \n :return true;\r\ + \n }\r\ + \n :if (\$FileVal->\"type\" = \"directory\" || \$FileVal->\"type\" = \"di\ + sk\") do={\r\ + \n :log error (\$0 . \" File '\" . \$FileName . \"' is not a file.\");\ + \r\ + \n :return false;\r\ + \n }\r\ + \n :onerror Err {\r\ + \n /file/remove \$FileName;\r\ + \n } do={\r\ + \n :log error (\$0 . \" Removing file '\" . \$FileName . \"' failed: \"\ + \_. \$Err); :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set MkDir do={\r\ + \n :local Path [ :tostr \$1 ];\r\ + \n :global CleanFilePath;\r\ + \n :global FileGet;\r\ + \n :global RmDir;\r\ + \n :global WaitForFile;\r\ + \n\r\ + \n :local MkTmpfs do={\r\ + \n :global WaitForFile;\r\ + \n :local TmpFs [ /disk/find where slot=tmpfs type=tmpfs ];\r\ + \n :if ([ :len \$TmpFs ] = 1) do={\r\ + \n :if ([ /disk/get \$TmpFs disabled ] = true) do={\r\ + \n :log info (\$0 . \" The tmpfs is disabled, enabling.\");\r\ + \n /disk/enable \$TmpFs;\r\ + \n }\r\ + \n :return true;\r\ + \n }\r\ + \n :log info (\$0 . \" Creating disk of type tmpfs.\");\r\ + \n \$RmDir \"tmpfs\";\r\ + \n :onerror Err {\r\ + \n /disk/add slot=tmpfs type=tmpfs tmpfs-max-size=([ /system/resource\ + /get total-memory ] / 3);\r\ + \n \$WaitForFile \"tmpfs\";\r\ + \n } do={\r\ + \n :log warning (\$0 . \" Creating disk of type tmpfs failed: \" . \$\ + Err);\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n }\r\ + \n :set Path [ \$CleanFilePath \$Path ];\r\ + \n :if (\$Path = \"\") do={\r\ + \n :return true;\r\ + \n }\r\ + \n :log debug (\$0 . \" Making directory: \" . \$Path);\r\ + \n :local PathVal [ \$FileGet \$Path ];\r\ + \n :if (\$PathVal->\"type\" = \"directory\") do={\r\ + \n :log debug (\$0 . \" ... which already exists.\");\r\ + \n :return true;\r\ + \n }\r\ + \n :if ([ :pick \$Path 0 5 ] = \"tmpfs\") do={\r\ + \n :if ([ \$MkTmpfs ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n :onerror Err {\r\ + \n /file/add type=\"directory\" name=\$Path;\r\ + \n \$WaitForFile \$Path;\r\ + \n } do={\r\ + \n :log warning (\$0 . \" Making directory '\" . \$Path . \"' failed: \ + \" . \$Err);\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set MAX do={:if (\$1 > \$2) do={:return \$1}\r\ + \n :return \$2;\r\ + \n}\r\ + \n:set MIN do={:if (\$1 < \$2) do={:return \$1}\r\ + \n :return \$2;\r\ + \n}\r\ + \n\r\ + \n:set CharacterMultiply do={\r\ + \n :local Str [ :tostr \$1 ];\r\ + \n :local Num [ :tonum \$2 ];\r\ + \n :if (\$Num = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :for I from=1 to=\$Num do={:set Return (\$Return . \$Str)}\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set CharacterReplace do={\r\ + \n :local String [ :tostr \$1 ];\r\ + \n :local ReplaceFrom [ :tostr \$2 ];\r\ + \n :local ReplaceWith [ :tostr \$3 ];\r\ + \n :local Return \"\";\r\ + \n :if (\$ReplaceFrom = \"\") do={:return \$String}\r\ + \n :while ([ :typeof [ :find \$String \$ReplaceFrom ] ] != \"nil\") do={\ + \r\ + \n :local Pos [ :find \$String \$ReplaceFrom ];\r\ + \n :set Return (\$Return . [ :pick \$String 0 \$Pos ] . \$ReplaceWith);\ + \r\ + \n :set String [ :pick \$String (\$Pos + [ :len \$ReplaceFrom ]) [ :len\ + \_\$String ] ];\r\ + \n }\r\ + \n :return (\$Return . \$String);\r\ + \n}\r\ + \n\r\ + \n:set IfThenElse do={\r\ + \n :if ([ :tostr \$1 ] = \"true\" || [ :tobool \$1 ] = true) do={:return \ + \$2};\r\ + \n :return \$3;\r\ + \n}\r\ + \n\r\ + \n:set EitherOr do={\r\ + \n :global IfThenElse;\r\ + \n :if ([ :typeof \$1 ] = \"num\") do={:return [ \$IfThenElse (\$1 != 0) \ + \$1 \$2 ]}\r\ + \n :if ([ :typeof \$1 ] = \"time\") do={:return [ \$IfThenElse (\$1 > 0s)\ + \_\$1 \$2 ]}\r\ + \n# this works for boolean values, literal ones with parentheses\r\ + \n :return [ \$IfThenElse ([ :len [ :tostr \$1 ] ] > 0) \$1 \$2 ];\r\ + \n}\r\ + \n\r\ + \n:set ParseKeyValueStore do={\r\ + \n :local Source \$1;\r\ + \n :if ([ :pick \$Source 0 1 ] = \"{\") do={\r\ + \n :do {\r\ + \n :return [ :deserialize from=json \$Source ];\r\ + \n } on-error={ }\r\ + \n } \r\ + \n :if ([ :typeof \$Source ] != \"array\") do={:set Source [ :tostr \$1 ]\ + }\r\ + \n :local Result ({});\r\ + \n :foreach KeyValue in=[ :toarray \$Source ] do={\r\ + \n :if ([ :find \$KeyValue \"=\" ]) do={\r\ + \n :local Key [ :pick \$KeyValue 0 [ :find \$KeyValue \"=\" ] ];\r\ + \n :local Value [ :pick \$KeyValue ([ :find \$KeyValue \"=\" ] + 1) [\ + \_:len \$KeyValue ] ];\r\ + \n :if (\$Value=\"true\") do={:set Value true}\r\ + \n :if (\$Value=\"false\") do={:set Value false}\r\ + \n :set (\$Result->\$Key) \$Value;\r\ + \n } else={:set (\$Result->\$KeyValue) true}\r\ + \n }\r\ + \n :return \$Result;\r\ + \n}\r\ + \n:set RequiredRouterOS do={\r\ + \n :local Caller [ :tostr \$1 ];\r\ + \n :local Required [ :tostr \$2 ];\r\ + \n :local Warn [ :tostr \$3 ];\r\ + \n :global IfThenElse;\r\ + \n :global VersionToNum;\r\ + \n :if (!(\$Required ~ \"^\\\\d+\\\\.\\\\d+((alpha|beta|rc|\\\\.)\\\\d+|)\ + \\\$\")) do={\r\ + \n :log error (\$0 . \" No valid RouterOS version: \" . \$Required);\r\ + \n :return false;\r\ + \n }\r\ + \n :if ([ \$VersionToNum \$Required ] > [ \$VersionToNum [ /system/packag\ + e/update/get installed-version ] ]) do={\r\ + \n :if (\$Warn = \"true\") do={\r\ + \n :log warning (\$0 . \" This \" . [ \$IfThenElse ([ :pick \$Caller \ + 0 ] = (\"\\\$\")) \"function\" \"script\" ] . \\\r\ + \n \" '\" . \$Caller . \"' (at least specific functionality) requir\ + es RouterOS \" . \$Required . \". Please update!\");\r\ + \n }\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set ValidateSyntax do={\r\ + \n :local Code [ :tostr \$1 ];\r\ + \n :global LogPrint;\r\ + \n :onerror Err {\r\ + \n [ :parse (\":local Validate do={\\n\" . \$Code . \"\\n}\") ];\r\ + \n } do={\r\ + \n \$LogPrint debug \$0 (\"Valdation failed: \" . \$Err);\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set VersionToNum do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :local Multi 0x1000000;\r\ + \n :local Return 0;\r\ + \n :global CharacterReplace;\r\ + \n :set Input [ \$CharacterReplace \$Input \".\" \",\" ];\r\ + \n :foreach I in={ \"zero\"; \"alpha\"; \"beta\"; \"rc\" } do={\r\ + \n :set Input [ \$CharacterReplace \$Input \$I (\",\" . \$I . \",\") ];\ + \r\ + \n }\r\ + \n :foreach Value in=([ :toarray \$Input ], 0) do={\r\ + \n :local Num [ :tonum \$Value ];\r\ + \n :if (\$Multi = 0x100) do={\r\ + \n :if ([ :typeof \$Num ] = \"num\") do={\r\ + \n :set Return (\$Return + 0xff00);\r\ + \n :set Multi (\$Multi / 0x100);\r\ + \n } else={\r\ + \n :if (\$Value = \"zero\") do={ }\r\ + \n :if (\$Value = \"alpha\") do={ :set Return (\$Return + 0x3f00); \ + }\r\ + \n :if (\$Value = \"beta\") do={ :set Return (\$Return + 0x5f00); }\ + \r\ + \n :if (\$Value = \"rc\") do={ :set Return (\$Return + 0x7f00); }\r\ + \n }\r\ + \n }\r\ + \n :if ([ :typeof \$Num ] = \"num\") do={ :set Return (\$Return + (\$Va\ + lue * \$Multi)); }\r\ + \n :set Multi (\$Multi / 0x100);\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set ScriptLock do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local WaitMax [ :totime \$2 ];\r\ + \n :global GetRandom20CharAlNum;\r\ + \n :global IfThenElse;\r\ + \n :global ScriptLockOrder;\r\ + \n :if ([ :typeof \$ScriptLockOrder ] = \"nothing\") do={\r\ + \n :set ScriptLockOrder ({});\r\ + \n }\r\ + \n :if ([ :typeof (\$ScriptLockOrder->\$Script) ] = \"nothing\") do={\r\ + \n :set (\$ScriptLockOrder->\$Script) ({});\r\ + \n }\r\ + \n :local JobCount do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :return [ :len [ /system/script/job/find where script=\$Script ] ];\ + \r\ + \n }\r\ + \n :local TicketCount do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :local Count 0;\r\ + \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :if ([ :typeof \$Ticket ] != \"nothing\") do={:set Count (\$Count \ + + 1)}\r\ + \n }\r\ + \n :return \$Count;\r\ + \n }\r\ + \n :local IsFirstTicket do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local Check [ :tostr \$2 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :if (\$Ticket = \$Check) do={:return true}\r\ + \n :if ([ :typeof \$Ticket ] != \"nothing\" && \$Ticket != \$Check) d\ + o={:return false}\r\ + \n }\r\ + \n :return false;\r\ + \n }\r\ + \n :local AddTicket do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local Add [ :tostr \$2 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :while (true) do={\r\ + \n :local Pos [ :len (\$ScriptLockOrder->\$Script) ];\r\ + \n :set (\$ScriptLockOrder->\$Script->\$Pos) \$Add;\r\ + \n :delay 10ms;\r\ + \n :if ((\$ScriptLockOrder->\$Script->\$Pos) = \$Add) do={:return tru\ + e}\r\ + \n }\r\ + \n }\r\ + \n :local RemoveTicket do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local Remove [ :tostr \$2 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :foreach Id,Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :while ((\$ScriptLockOrder->\$Script->\$Id) = \$Remove) do={\r\ + \n :set (\$ScriptLockOrder->\$Script->\$Id);\r\ + \n :delay 10ms;\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n :local CleanupTickets do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :if ([ :typeof \$Ticket ] != \"nothing\") do={:return false}\r\ + \n }\r\ + \n :set (\$ScriptLockOrder->\$Script) ({});\r\ + \n }\r\ + \n :if ([ :typeof \$WaitMax ] = \"nil\" ) do={:set WaitMax 0s}\r\ + \n :if ([ :len [ /system/script/find where name=\$Script ] ] = 0) do={\r\ + \n :log error (\$0 . \" A script named '\" . \$Script . \"' does not ex\ + ist!\");\r\ + \n :error false;\r\ + \n }\r\ + \n :if ([ \$JobCount \$Script ] = 0) do={\r\ + \n \$LogPrint error \$0 (\"No script '\" . \$Script . \"' is running!\"\ + );\r\ + \n :error false;\r\ + \n }\r\ + \n :if ([ \$TicketCount \$Script ] >= [ \$JobCount \$Script ]) do={\r\ + \n :log error (\$0 . \" More tickets than running scripts '\" . \$Scrip\ + t . \"', resetting!\");\r\ + \n :set (\$ScriptLockOrder->\$Script) ({});\r\ + \n /system/script/job/remove [ find where script=\$Script ];\r\ + \n }\r\ + \n :local MyTicket [ \$GetRandom20CharAlNum 6 ];\r\ + \n \$AddTicket \$Script \$MyTicket;\r\ + \n :local WaitInterval (\$WaitMax / 20);\r\ + \n :local WaitTime \$WaitMax;\r\ + \n :while (\$WaitTime > 0 && \\\r\ + \n ([ \$IsFirstTicket \$Script \$MyTicket ] = false || \\\r\ + \n [ \$TicketCount \$Script ] < [ \$JobCount \$Script ])) do={\r\ + \n :set WaitTime (\$WaitTime - \$WaitInterval);\r\ + \n :delay \$WaitInterval;\r\ + \n }\r\ + \n :if ([ \$IsFirstTicket \$Script \$MyTicket ] = true && \\\r\ + \n [ \$TicketCount \$Script ] = [ \$JobCount \$Script ]) do={\r\ + \n \$RemoveTicket \$Script \$MyTicket;\r\ + \n \$CleanupTickets \$Script;\r\ + \n :return true;\r\ + \n }\r\ + \n \$RemoveTicket \$Script \$MyTicket;\r\ + \n \$LogPrint debug \$0 (\"Script '\" . \$Script . \"' started more than \ + once\" . \\\r\ + \n [ \$IfThenElse (\$WaitTime < \$WaitMax) \" and timed out waiting for\ + \_lock\" \"\" ] . \"...\");\r\ + \n :return false;\r\ + \n}\r\ + \n\r\ + \n:set SendNotification do={ :onerror Err {\r\ + \n :global SendNotification2;\r\ + \n \$SendNotification2 ({ origin=\$0; subject=\$1; message=\$2; link=\$3;\ + \_silent=\$4 });\r\ + \n} do={:global ExitOnError; \$ExitOnError \$0 \$Err}\r\ + \n}\r\ + \n\r\ + \n:set SendNotification2 do={\r\ + \n :local Notification \$1;\r\ + \n :global NotificationFunctions;\r\ + \n :foreach FunctionName,Discard in=\$NotificationFunctions do={\r\ + \n (\$NotificationFunctions->\$FunctionName) (\"\\\$NotificationFunctio\ + ns->\\\"\" . \$FunctionName . \"\\\"\") \$Notification;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set SymbolByUnicodeName do={\r\ + \n :local Name [ :tostr \$1 ];\r\ + \n :global EitherOr;\r\ + \n :global SymbolsExtra;\r\ + \n :local Symbols ({\r\ + \n \"abacus\"=\"\\F0\\9F\\A7\\AE\";\r\ + \n \"alarm-clock\"=\"\\E2\\8F\\B0\";\r\ + \n \"arrow-down\"=\"\\E2\\AC\\87\";\r\ + \n \"arrow-up\"=\"\\E2\\AC\\86\";\r\ + \n \"calendar\"=\"\\F0\\9F\\93\\85\";\r\ + \n \"card-file-box\"=\"\\F0\\9F\\97\\83\";\r\ + \n \"chart-decreasing\"=\"\\F0\\9F\\93\\89\";\r\ + \n \"chart-increasing\"=\"\\F0\\9F\\93\\88\";\r\ + \n \"cloud\"=\"\\E2\\98\\81\";\r\ + \n \"cross-mark\"=\"\\E2\\9D\\8C\";\r\ + \n \"earth\"=\"\\F0\\9F\\8C\\8D\";\r\ + \n \"fire\"=\"\\F0\\9F\\94\\A5\";\r\ + \n \"floppy-disk\"=\"\\F0\\9F\\92\\BE\";\r\ + \n \"gear\"=\"\\E2\\9A\\99\";\r\ + \n \"heart\"=\"\\E2\\99\\A5\";\r\ + \n \"high-voltage-sign\"=\"\\E2\\9A\\A1\";\r\ + \n \"incoming-envelope\"=\"\\F0\\9F\\93\\A8\";\r\ + \n \"information\"=\"\\E2\\84\\B9\";\r\ + \n \"large-orange-circle\"=\"\\F0\\9F\\9F\\A0\";\r\ + \n \"large-red-circle\"=\"\\F0\\9F\\94\\B4\";\r\ + \n \"link\"=\"\\F0\\9F\\94\\97\";\r\ + \n \"lock-with-ink-pen\"=\"\\F0\\9F\\94\\8F\";\r\ + \n \"memo\"=\"\\F0\\9F\\93\\9D\";\r\ + \n \"mobile-phone\"=\"\\F0\\9F\\93\\B1\";\r\ + \n \"pushpin\"=\"\\F0\\9F\\93\\8C\";\r\ + \n \"scissors\"=\"\\E2\\9C\\82\";\r\ + \n \"scroll\"=\"\\F0\\9F\\93\\9C\";\r\ + \n \"smiley-partying-face\"=\"\\F0\\9F\\A5\\B3\";\r\ + \n \"smiley-smiling-face\"=\"\\E2\\98\\BA\";\r\ + \n \"smiley-winking-face-with-tongue\"=\"\\F0\\9F\\98\\9C\";\r\ + \n \"sparkles\"=\"\\E2\\9C\\A8\";\r\ + \n \"speech-balloon\"=\"\\F0\\9F\\92\\AC\";\r\ + \n \"star\"=\"\\E2\\AD\\90\";\r\ + \n \"warning-sign\"=\"\\E2\\9A\\A0\";\r\ + \n \"white-heavy-check-mark\"=\"\\E2\\9C\\85\"\r\ + \n }, \$SymbolsExtra);\r\ + \n :local Magic [ :pick [ /system/clock/get date ] 4 10 ];\r\ + \n :local Special {\r\ + \n \"information-04-01\"=\"\\F0\\9F\\9A\\BB\";\r\ + \n \"large-orange-circle-04-01\"=\"\\F0\\9F\\8D\\8A\";\r\ + \n \"large-orange-circle-10-31\"=\"\\F0\\9F\\8E\\83\";\r\ + \n \"large-red-circle-04-01\"=\"\\F0\\9F\\8D\\92\" };\r\ + \n :if ([ :len (\$Symbols->\$Name) ] = 0) do={\r\ + \n :log warning (\$0 . \"No symbol available for name '\" . \$Name . \"\ + '!\");\r\ + \n :return \"\";\r\ + \n }\r\ + \n :return ([ \$EitherOr (\$Special->(\$Name . \$Magic)) (\$Symbols->\$Na\ + me) ] . \"\\EF\\B8\\8F\");\r\ + \n}\r\ + \n\r\ + \n:set SymbolForNotification do={\r\ + \n :global NotificationsWithSymbols;\r\ + \n :global SymbolByUnicodeName;\r\ + \n :global IfThenElse;\r\ + \n :if (\$NotificationsWithSymbols != true) do={:return [ \$IfThenElse ([\ + \_:len \$2 ] > 0) ([ :tostr \$2 ] . \" \") \"\" ]}\r\ + \n :local Return \"\";\r\ + \n :foreach Symbol in=[ :toarray \$1 ] do={:set Return (\$Return . [ \$Sy\ + mbolByUnicodeName \$Symbol ])}\r\ + \n :return (\$Return . \" \");\r\ + \n}\r\ + \n\r\ + \n:set Unix2Dos do={:return [ :tocrlf [ :tostr \$1 ] ]}\r\ + \n:set UrlEncode do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :if ([ :len \$Input ] = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :local Chars (\"\\n\\r !\\\"#\\\$%&'()*+,:;<=>\?@[\\\\]^`{|}~\");\r\ + \n :local Subs { \"%0A\"; \"%0D\"; \"%20\"; \"%21\"; \"%22\"; \"%23\"; \"\ + %24\"; \"%25\"; \"%26\"; \"%27\";\r\ + \n \"%28\"; \"%29\"; \"%2A\"; \"%2B\"; \"%2C\"; \"%3A\"; \"%3B\"; \ + \"%3C\"; \"%3D\"; \"%3E\"; \"%3F\";\r\ + \n \"%40\"; \"%5B\"; \"%5C\"; \"%5D\"; \"%5E\"; \"%60\"; \"%7B\"; \ + \"%7C\"; \"%7D\"; \"%7E\" };\r\ + \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ + \n :local Char [ :pick \$Input \$I ];\r\ + \n :local Replace [ :find \$Chars \$Char ];\r\ + \n :if ([ :typeof \$Replace ] = \"num\") do={:set Char (\$Subs->\$Repla\ + ce)}\r\ + \n :set Return (\$Return . \$Char);\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set IsDNSResolving do={\r\ + \n :do {:resolve \"api.telegram.org\"} on-error={:return false}\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set IsFullyConnected do={\r\ + \n :global IsDNSResolving;\r\ + \n :global IsTimeSync;\r\ + \n :if ([ \$IsDNSResolving ] = false) do={:return false};\r\ + \n :if ([ \$IsTimeSync ] = false) do={:return false};\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set IsTimeSync do={\r\ + \n :global IsTimeSyncCached;\r\ + \n :global IsTimeSyncResetNtp;\r\ + \n :if (\$IsTimeSyncCached = true) do={:return true}\r\ + \n :if ([ /system/ntp/client/get enabled ] = true) do={\r\ + \n :if ([ /system/ntp/client/get status ] = \"synchronized\") do={\r\ + \n :set IsTimeSyncCached true;\r\ + \n :return true;\r\ + \n }\r\ + \n :local Uptime [ /system/resource/get uptime ];\r\ + \n :if ([ :typeof \$IsTimeSyncResetNtp ] = \"nothing\") do={\r\ + \n :set IsTimeSyncResetNtp \$Uptime;\r\ + \n }\r\ + \n :if (\$Uptime - \$IsTimeSyncResetNtp < 3m) do={:return false}\r\ + \n :log warning \"\$0 The ntp client is configured, but did not sync.\"\ + ;\r\ + \n :set IsTimeSyncResetNtp \$Uptime;\r\ + \n /system/ntp/client/set enabled=no;\r\ + \n :delay 20ms;\r\ + \n /system/ntp/client/set enabled=yes;\r\ + \n :return false;\r\ + \n }\r\ + \n :if ([ /system/license/get ]->\"level\" = \"free\" || \\\r\ + \n [ /system/resource/get ]->\"board-name\" = \"x86\") do={\r\ + \n :log debug \"\$0 No ntp client configured, relying on RTC for CHR fr\ + ee license and x86.\";\r\ + \n :return true;\r\ + \n }\r\ + \n :if ([ /ip/cloud/get update-time ] = true) do={\r\ + \n :if ([ :typeof [ /ip/cloud/get public-address ] ] = \"ip\") do={\r\ + \n :set IsTimeSyncCached true;\r\ + \n :return true;\r\ + \n }\r\ + \n :return false;\r\ + \n }\r\ + \n :log debug \"\$0 No time source configured! Returning gracefully...\";\ + \r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set FetchHugeFiles do={\r\ + \n :local ScriptName [ :tostr \$1 ];\r\ + \n :local Url [ :tostr \$2 ];\r\ + \n :local CheckCert [ :tostr \$3 ];\r\ + \n\r\ + \n :global CleanName;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global GetRandom20CharAlNum;\r\ + \n :global IfThenElse;\r\ + \n :global LogPrint;\r\ + \n :global MkDir;\r\ + \n :global RmDir;\r\ + \n :global RmFile;\r\ + \n :global WaitForFile;\r\ + \n\r\ + \n :set CheckCert [ \$IfThenElse (\$CheckCert = \"false\") \"no\" \"yes-w\ + ithout-crl\" ];\r\ + \n\r\ + \n :local DirName (\"tmpfs/\" . [ \$CleanName \$ScriptName ]);\r\ + \n :if ([ \$MkDir \$DirName ] = false) do={\r\ + \n \$LogPrint error \$0 (\"Failed creating directory!\");\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :local FileName (\$DirName . \"/\" . [ \$CleanName \$0 ] . \"-\" . [ \ + \$GetRandom20CharAlNum ]);\r\ + \n :onerror Err {\r\ + \n /tool/fetch check-certificate=\$CheckCert \$Url dst-path=\$FileName \ + \\\r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$ScriptName ] }) as-va\ + lue;\r\ + \n } do={\r\ + \n :if ([ \$WaitForFile \$FileName 500ms ] = true) do={\r\ + \n \$RmFile \$FileName;\r\ + \n }\r\ + \n \$LogPrint debug \$0 (\"Failed downloading from \" . \$Url . \" - \"\ + \_. \$Err);\r\ + \n \$RmDir \$DirName;\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :if ([ \$WaitForFile \$FileName 5s ] = false) do={\r\ + \n \$LogPrint debug \$0 (\"The file downloaded from \" . \$Url . \" did\ + \_not show up.\");\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :local FileSize [ /file/get \$FileName size ];\r\ + \n :local Return \"\";\r\ + \n :local VarSize 0;\r\ + \n :while (\$VarSize != \$FileSize) do={\r\ + \n :set Return (\$Return . ([ /file/read offset=\$VarSize chunk-size=32\ + 768 file=\$FileName as-value ]->\"data\"));\r\ + \n :set FileSize [ /file/get \$FileName size ];\r\ + \n :set VarSize [ :len \$Return ];\r\ + \n :if (\$VarSize > \$FileSize) do={\r\ + \n :delay 100ms;\r\ + \n }\r\ + \n }\r\ + \n \$RmDir \$DirName;\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set FetchUserAgentStr do={\r\ + \n :local Caller [ :tostr \$1 ];\r\ + \n :global GlobalScriptsUrl;\r\ + \n :global CommitBrief;\r\ + \n :global IfThenElse;\r\ + \n :local Resource [ /system/resource/get ];\r\ + \n :return (\"User-Agent: Mikrotik/\" . \$Resource->\"version\" . \" \" .\ + \_\$Resource->\"architecture-name\" . \\\r\ + \n \" \" . \$Caller . \"/Fetch (\" . \$GlobalScriptsUrl . \"; \" . [ \$\ + CommitBrief ] . \")\");\r\ + \n}\r\ + \n\r\ + \n:set ScriptInstallUpdate do={ :onerror Err {\r\ + \n :local Scripts [ :toarray \$1 ];\r\ + \n :local NewComment [ :tostr \$2 ];\r\ + \n :global InitSetup;\r\ + \n\r\ + \n :global CommitId;\r\ + \n :global ScriptUpdatesCRLF;\r\ + \n :global GlobalConfVersion;\r\ + \n :global Identity;\r\ + \n :global CertificateAvailable;\r\ + \n :global CheckSumsVerify;\r\ + \n :global GlobalScriptsUrl;\r\ + \n :global SumsDirAndFileName;\r\ + \n :global GlobalScriptsUrlSuffix;\r\ + \n :global EitherOr;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global Grep;\r\ + \n :global IfThenElse;\r\ + \n :global LogPrint;\r\ + \n :global ParseKeyValueStore;\r\ + \n :global RequiredRouterOS;\r\ + \n :global SendNotification2;\r\ + \n :global SymbolForNotification;\r\ + \n :global ValidateSyntax;\r\ + \n :global CommentsInScripts;\r\ + \n\r\ + \n :if ([ \$CertificateAvailable \"Root YE\" \"fetch\" ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Downloading certificate failed, trying wit\ + hout.\");\r\ + \n }\r\ + \n\r\ + \n :foreach Script in=\$Scripts do={\r\ + \n :if ([ :len [ /system/script/find where name=\$Script ] ] = 0) do={\ + \r\ + \n \$LogPrint info \$0 (\"Adding new script: \" . \$Script);\r\ + \n /system/script/add name=\$Script owner=\$Script source=\"#!rsc by \ + Vados\\n\" comment=\$NewComment;\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :local CommitIdBefore \$CommitId;\r\ + \n :local GlobalConfVersionBefore \$GlobalConfVersion;\r\ + \n :local ReloadGlobal false;\r\ + \n :local DeviceMode [ /system/device-mode/get ];\r\ + \n\r\ + \n :if (\$CheckSumsVerify = true) do={\r\ + \n :local CheckSums ({});\r\ + \n :do {\r\ + \n :local Url (\$GlobalScriptsUrl . \$SumsDirAndFileName . \$GlobalScr\ + iptsUrlSuffix);\r\ + \n \$LogPrint debug \$0 (\"Fetching checksums from url: \" . \$Url);\ + \r\ + \n :set CheckSums [ :deserialize from=json ([ /tool/fetch check-certi\ + ficate=yes-without-crl \\\r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$0 ] }) \$Url output\ + =user as-value ]->\"data\") ];\r\ + \n } on-error={ \$LogPrint warning \$0 (\"Err = \" . \$Err); }\r\ + \n }\r\ + \n\r\ + \n :foreach Script in=[ /system/script/find where source~\"^#!rsc by Vado\ + s\" ] do={\r\ + \n :local ScriptVal [ /system/script/get \$Script ];\r\ + \n :local ScriptInfo [ \$ParseKeyValueStore (\$ScriptVal->\"comment\") \ + ];\r\ + \n :local SourceNew;\r\ + \n\r\ + \n :foreach Scheduler in=[ /system/scheduler/find where on-event~(\"\\\ + \\b\" . \$ScriptVal->\"name\" . \"\\\\b\") ] do={\r\ + \n :local SchedulerVal [ /system/scheduler/get \$Scheduler ];\r\ + \n :if (\$ScriptVal->\"policy\" != \$SchedulerVal->\"policy\") do={\r\ + \n \$LogPrint warning \$0 (\"Policies differ for script '\" . \$Scr\ + iptVal->\"name\" . \"' and its scheduler '\" . \$SchedulerVal->\"name\" . \ + \"'!\");\r\ + \n }\r\ + \n }\r\ + \n :do {\r\ + \n :if (\$ScriptInfo->\"ignore\" = true) do={\r\ + \n \$LogPrint debug \$0 (\"Ignoring script '\" . \$ScriptVal->\"nam\ + e\" . \"', as requested.\");\r\ + \n :error true;\r\ + \n }\r\ + \n :if (\$CheckSumsVerify = true) do={\r\ + \n :local CheckSum (\$CheckSums->(\$ScriptVal->\"name\"));\r\ + \n :if ([ :len (\$ScriptInfo->\"base-url\") ] = 0 && [ :len (\$Scri\ + ptInfo->\"url-suffix\") ] = 0 && \\\r\ + \n [ :convert transform=md5 to=hex [ :tolf (\$ScriptVal->\"sou\ + rce\") ] ] = \$CheckSum) do={\r\ + \n \$LogPrint debug \$0 (\"Checksum for script '\" . \$ScriptVal-\ + >\"name\" . \"' matches, ignoring.\");\r\ + \n :error true;\r\ + \n }\r\ + \n }\r\ + \n :if ([ :len (\$ScriptInfo->\"certificate\") ] > 0) do={\r\ + \n :if ([ \$CertificateAvailable (\$ScriptInfo->\"certificate\") \"\ + fetch\" ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Downloading certificate failed, tryi\ + ng without.\");\r\ + \n }\r\ + \n }\r\ + \n :onerror Err {\r\ + \n :local BaseUrl [ \$EitherOr (\$ScriptInfo->\"base-url\") \$Globa\ + lScriptsUrl ];\r\ + \n :local UrlSuffix [ \$EitherOr (\$ScriptInfo->\"url-suffix\") \$G\ + lobalScriptsUrlSuffix ];\r\ + \n :local Url (\$BaseUrl . \$ScriptVal->\"name\" . \".rsc\" . \$Url\ + Suffix);\r\ + \n \$LogPrint warning \$0 (\"Fetching script '\" . (\$ScriptVal->\"\ + name\") . \"' from url: \" . \$Url);\r\ + \n :local Result [ /tool/fetch check-certificate=yes-without-crl \\\ + \r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$0 ] }) \$Url outp\ + ut=user as-value ];\r\ + \n :if (\$Result->\"status\" = \"finished\") do={\r\ + \n :set SourceNew [ :tolf (\$Result->\"data\") ];\r\ + \n } \r\ + \n } do={\r\ + \n \$LogPrint warning \$0 (\"Failed fetching script '\" . \$ScriptV\ + al->\"name\" . \"': \" . \$Err);\r\ + \n :if (\$Err != \"Fetch failed with status 404\") do={\r\ + \n :error false;\r\ + \n }\r\ + \n :if (\$ScriptVal->\"source\" = \"#!rsc by Vados\") do={\r\ + \n \$LogPrint warning \$0 (\"Removing dummy. Typo on installation\ + \?\");\r\ + \n /system/script/remove \$Script;\r\ + \n :error false;\r\ + \n }\r\ + \n :if (\$CheckSumsVerify = true) do={\r\ + \n :if ([ :len (\$ScriptInfo->\"base-url\") ] = 0 && [ :len (\$Sc\ + riptInfo->\"url-suffix\") ] = 0 && \\\r\ + \n [ :len \$CheckSum ] = 0) do={\r\ + \n \$LogPrint warning \$0 (\"Added the script manually\? Skip u\ + pdates with 'ignore=true' in comment.\");\r\ + \n }\r\ + \n }\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :if ([ :len \$SourceNew ] = 0) do={\r\ + \n \$LogPrint debug \$0 (\"No update for script '\" . (\$ScriptVal-\ + >\"name\") . \"'.\");\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :local SourceCRLF [ :tocrlf \$SourceNew ];\r\ + \n :if (\$InitSetup != true && ((\$ScriptVal->\"name\") != \"AM-Globa\ + lConfig\" || (\$ScriptVal->\"name\") != \"AM-GlobalFunc\")) do={\r\ + \n :if (\$SourceNew = (\$ScriptVal->\"source\") || \$SourceCRLF = (\ + \$ScriptVal->\"source\")) do={\r\ + \n \$LogPrint debug \$0 (\"Script '\" . (\$ScriptVal->\"name\") \ + . \"' source did not change. End of lines set to CRLF.\");\r\ + \n if (\$ScriptUpdatesCRLF = false) do={\r\ + \n :put [ :tolf \$SourceNew ];\r\ + \n \$LogPrint debug \$0 (\"Script '\" . (\$ScriptVal->\"name\"\ + ) . \"' source update end of lines to LF.\");\r\ + \n }\r\ + \n :error false;\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :if ([ :pick \$SourceNew 0 14 ] != \"#!rsc by Vados\") do={\r\ + \n \$LogPrint warning \$0 (\"Looks like new script '\" . \$ScriptVa\ + l->\"name\" . \"' is not valid (missing shebang = '\$shebang') Ignoring!\"\ + );\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :if (\$CommentsInScripts = true) do={\r\ + \n :local CommentLine [ \$Grep \$SourceNew (\"\\23 Script comment:\ + \_\") ];\r\ + \n :if ([ :len \$CommentLine ] = 0) do={\r\ + \n \$LogPrint debug \$0 (\"The search in new script '\" . (\$Scr\ + iptVal->\"name\") . \"' for comment in script body, is not found result Ig\ + noring!\");\r\ + \n :error false;\r\ + \n } else={\r\ + \n :if ([ :len (\$ScriptVal->\"comment\")] = 0 || [ :len (\$Scri\ + ptVal->\"comment\")] != [ :pick \$CommentLine ([ :find \$CommentLine \":\"\ + ] + 2) [ :len \$CommentLine] ]) do={\r\ + \n \$LogPrint debug \$0 (\"Exsiting comment for script '\" . (\ + \$ScriptVal->\"name\") . \"' is '\" . (\$ScriptVal->\"comment\") . \"'.\")\ + ;\r\ + \n :set (\$ScriptVal->\"comment\") [ :pick \$CommentLine ([ :f\ + ind \$CommentLine \":\"] + 2) [ :len \$CommentLine] ];\r\ + \n \$LogPrint debug \$0 (\"New comment (\" . (\$ScriptVal->\"c\ + omment\") . \") for script '\" . (\$ScriptVal->\"name\") . \"' has been ad\ + ded!\");\r\ + \n } else={\r\ + \n \$LogPrint debug \$0 (\"Comment for script '\" . (\$ScriptV\ + al->\"name\") . \"' did not change.\");\r\ + \n :error false;\r\ + \n }\r\ + \n } \r\ + \n }\r\ + \n\r\ + \n :local RequiredROS ([ \$ParseKeyValueStore [ \$Grep \$SourceNew (\ + \"\\23 requires RouterOS, \") ] ]->version);\r\ + \n :if ([ \$RequiredRouterOS \$0 [ \$EitherOr \$RequiredROS \"0.0\" ]\ + \_false ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"The script '\" . (\$ScriptVal->\"name\ + \") . \"' requires RouterOS \" . \\\r\ + \n \$RequiredROS . \", which is not met by your installation. I\ + gnoring!\");\r\ + \n :error false;\r\ + \n }\r\ + \n :local RequiredDM [ \$ParseKeyValueStore [ \$Grep \$SourceNew (\"\ + \\23 requires device-mode, \") ] ];\r\ + \n :local MissingDM ({});\r\ + \n :foreach Feature,Value in=\$RequiredDM do={\r\ + \n :if ([ :typeof (\$DeviceMode->\$Feature) ] = \"bool\" && (\$Devi\ + ceMode->\$Feature) = false) do={\r\ + \n :set MissingDM (\$MissingDM, \$Feature);\r\ + \n }\r\ + \n }\r\ + \n :if ([ :len \$MissingDM ] > 0) do={\r\ + \n \$LogPrint warning \$0 (\"The script '\" . (\$ScriptVal->\"name\ + \") . \"' requires disabled \" . \\\r\ + \n \"device-mode features (\" . [ :tostr \$MissingDM ] . \"). I\ + gnoring!\");\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :if ([ \$ValidateSyntax \$SourceNew ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Syntax validation for script '\" . (\$\ + ScriptVal->\"name\") . \"' failed! Ignoring!\");\r\ + \n :error false;\r\ + \n }\r\ + \n \r\ + \n :log info (\"Updating script: \" . (\$ScriptVal->\"name\") . \" Sc\ + ript comment: \" . (\$ScriptVal->\"comment\"));\r\ + \n\r\ + \n /system/script/set owner=(\$ScriptVal->\"name\") comment=(\$Script\ + Val->\"comment\") \\\r\ + \n source=[ \$IfThenElse (\$ScriptUpdatesCRLF = true) \$SourceCRL\ + F \$SourceNew ] \$Script;\r\ + \n :if (\$ScriptVal->\"name\" = \"AM-GlobalConfig\" || \\\r\ + \n \$ScriptVal->\"name\" = \"AM-GlobalFunc\" || \\\r\ + \n \$ScriptVal->\"name\" ~ (\"^(AM-GlobalFunc\\\\.d|mod)/.\")) d\ + o={\r\ + \n :set ReloadGlobal true;\r\ + \n }\r\ + \n } on-error={ }\r\ + \n }\r\ + \n :if (\$ReloadGlobal = true) do={\r\ + \n \$LogPrint info \$0 (\"Reloading global configuration and functions.\ + \");\r\ + \n :onerror Err {\r\ + \n :global InitSetup (a);\r\ + \n /system/script {run AM-GlobalConfig; run AM-GlobalFunc;};\r\ + \n } do={\$LogPrint error \$0 (\"Reloading global configuration and fun\ + ctions failed! \" . \$Err)}\r\ + \n }\r\ + \n :if (\$GlobalConfVersionBefore > \$GlobalConfVersion) do={\r\ + \n \$LogPrint warning \$0 (\"The configuration version decreased from \ + \" . \\\r\ + \n \$GlobalConfVersionBefore . \" to \" . \$GlobalConfVersion . \\\r\ + \n \". Installed an older version\?\");\r\ + \n }\r\ + \n :if (\$GlobalConfVersionBefore < \$GlobalConfVersion) do={\r\ + \n :global GlobalConfChanges;\r\ + \n :global GlobalConfMigration;\r\ + \n :local ChangeLogCode;\r\ + \n :if ([ :len \$ChangeLogCode ] > 0) do={\r\ + \n :if ([ \$ValidateSyntax \$ChangeLogCode ] = true) do={\r\ + \n :onerror Err {\r\ + \n [ :parse \$ChangeLogCode ];\r\ + \n } do={\$LogPrint warning \$0 (\"The changelog failed to run: \" \ + . \$Err)}\r\ + \n } else={\$LogPrint warning \$0 (\"The changelog failed syntax vali\ + dation!\")}\r\ + \n }\r\ + \n :if ([ :len \$GlobalConfMigration ] > 0) do={\r\ + \n :for I from=(\$GlobalConfVersionBefore + 1) to=\$GlobalConfVersion\ + \_do={\r\ + \n :local Migration (\$GlobalConfMigration->[ :tostr \$I ]);\r\ + \n :do {\r\ + \n :if ([ :typeof \$Migration ] != \"str\") do={\r\ + \n \$LogPrint debug \$0 (\"Migration code for change \" . \$I .\ + \_\" is not available.\");\r\ + \n :error false;\r\ + \n }\r\ + \n :if ([ \$ValidateSyntax \$Migration ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Migration code for change \" . \$I\ + \_. \" failed syntax validation!\");\r\ + \n :error false}\r\ + \n \$LogPrint info \$0 (\"Applying migration for change \" . \$I \ + . \": \" . \$Migration);\r\ + \n :onerror Err {\r\ + \n [ :parse \$Migration ];\r\ + \n } do={\$LogPrint warning \$0 (\"Migration code for change \" .\ + \_\$I . \" failed to run: \" . \$Err)}\r\ + \n } on-error={ }\r\ + \n }\r\ + \n }\r\ + \n :local NotificationMessage (\"The configuration version on \" . \$Id\ + entity . \" increased \" . \\\r\ + \n \"to \" . \$GlobalConfVersion . \", current configuration may nee\ + d modification. \" . \\\r\ + \n \"Please review and update global-config-overlay, then re-run glo\ + bal-config.\");\r\ + \n \$LogPrint info \$0 (\$NotificationMessage);\r\ + \n :if ([ :len \$GlobalConfChanges ] > 0) do={\r\ + \n :set NotificationMessage (\$NotificationMessage . \"\\n\\nChanges:\ + \");\r\ + \n :for I from=(\$GlobalConfVersionBefore + 1) to=\$GlobalConfVersion\ + \_do={\r\ + \n :local Change (\$GlobalConfChanges->[ :tostr \$I ]);\r\ + \n :set NotificationMessage (\$NotificationMessage . \"\\n \" . \\\ + \r\ + \n [ \$SymbolForNotification \"pushpin\" \"*\" ] . \$Change);\r\ + \n \$LogPrint info \$0 (\"Change \" . \$I . \": \" . \$Change);\r\ + \n }\r\ + \n } else={\r\ + \n :set NotificationMessage (\$NotificationMessage . \"\\n\\nNews and\ + \_changes are not available.\");\r\ + \n\r\ + \n }\r\ + \n\r\ + \n :if ([ :len \$GlobalConfChanges ] > 0) do={ :set GlobalConfChanges; \ + } else={ :global GlobalConfChanges (a); }\r\ + \n :if ([ :len \$GlobalConfMigration ] > 0) do={ :set GlobalConfMigrati\ + on; } else={ :global GlobalConfMigration (a); }\r\ + \n }\r\ + \n} do={\r\ + \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ + \n} }\r\ + \n\r\ + \n# load modules\r\ + \n:foreach Script in=[ /system/script/find where name ~ \"^(global-functio\ + ns\\\\.d|mod)/.\" ] do={\r\ + \n :local ScriptVal [ /system/script/get \$Script ];\r\ + \n :if ([ \$ValidateSyntax (\$ScriptVal->\"source\") ] = true) do={\r\ + \n :onerror Err {\r\ + \n /system/script/run \$Script;\r\ + \n } do={\r\ + \n \$LogPrint error \$0 (\"Module '\" . \$ScriptVal->\"name\" . \"' f\ + ailed to run: \" . \$Err);\r\ + \n }\r\ + \n } else={\r\ + \n \$LogPrint error \$0 (\"Module '\" . \$ScriptVal->\"name\" . \"' fai\ + led syntax validation, skipping.\");\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n# Add and fix global scheduler\r\ + \n:put \"Add or/and fix Global scheduler...\";\r\ + \n:local OnEvent \"/system/script { run AM-GlobalConfig; run AM-GlobalFunc\ + ; }\";\r\ + \n:local Comment \"Every Day Set Global Environment Variables\";\r\ + \n:if ([ :len [ /system/scheduler/find where name=\"AM-SetGlobalEnv\" ] ] \ + = 0) do={\r\ + \n /system/scheduler/add name=\"AM-SetGlobalEnv\" comment=\$Comment on-ev\ + ent=\$OnEvent start-time=startup;\r\ + \n}\r\ + \n:if ([ /system/scheduler/get \"AM-SetGlobalEnv\" comment ] != \$Comment)\ + \_do={\r\ + \n /system/scheduler/set \"AM-SetGlobalEnv\" comment=\$Comment;\r\ + \n}\r\ + \n:if ([ /system/scheduler/get \"AM-SetGlobalEnv\" on-event ] != \$OnEvent\ + ) do={\r\ + \n /system/scheduler/set \"AM-SetGlobalEnv\" on-event=\$OnEvent;\r\ + \n}\r\ + \n# Add Update Script scheduler\r\ + \n:put \"Add or/and fix Update Script scheduler\";\r\ + \n:set OnEvent \":global ScriptInstallUpdate; \\\$ScriptInstallUpdate;\";\ + \r\ + \n:set Comment \"Every Day Check For Update Scripts\";\r\ + \n:if ([ :len [ /system/scheduler/find where name=\"AM-ScriptInstallUpdate\ + \" ] ] = 0) do={\r\ + \n/system/scheduler/add name=\"AM-ScriptInstallUpdate\" comment=\$Comment \ + start-time=startup interval=1d on-event=\$OnEvent;\r\ + \n}\r\ + \n\r\ + \n:onerror Err {\r\ + \n :global GlobalConfReady;\r\ + \n :retry { :if (\$GlobalConfReady != true) do={ :error (\"Global configs\ + \_not ready.\"); }; } delay=100ms max=5;\r\ + \n\r\ + \n:log warning (\"This script \$ScriptName Loaded \" . \\\r\ + \n [ \$IfThenElse (\$CommitId != \"unknown\") ([ \$CommitBrief ] . \" \ + \") ] . \\\r\ + \n \"on \" . \$devBoardName . \"\\nRouterOS: \" . \$devCurVersion . \"\ + \\nArchitecture: \" . \$devCurArch . \"\\nIdentity: \" . \$Identity);\r\ + \n # signal we are ready\r\ + \n:set GlobalFuncReady true;\r\ + \n:set ExitOK true;\r\ + \n\r\ + \n:log info (\$0 . \"Global configs ready!\");\r\ + \n} do={\r\ + \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ + \n}\r\ + \n" +add comment="Download custom Certificates By Routers Identity " \ + dont-require-permissions=no name=mod/AM-Certs-By-Ident owner=\ + mod/AM-Certs-By-Ident policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\r\ + \n# RouterOS script: AM-Certs-By-Ident\r\ + \n# Script comment: Download custom Certificates By Routers Identity \r\ + \n# Copyright (c) 2005-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version=7.19\r\ + \n# requires device-mode, fetch\r\ + \n#\r\ + \n#:local ScriptName [ :jobname ];\r\ + \n#\r\ + \n# CloudFlare\r\ + \n#/tool/fetch mode=https url=https://cacerts.digicert.com/DigiCertGlobalR\ + ootCA.crt.pem;\r\ + \n#/certificate/import file-name=DigiCertGlobalRootCA.crt.pem passphrase=\ + \"\";\r\ + \n#/tool/ fetch mode=https url=https://cacerts.digicert.com/DigiCertGlobal\ + G2TLSRSASHA2562020CA1-1.crt.pem;\r\ + \n#/certificate/import file-name=DigiCertGlobalG2TLSRSASHA2562020CA1-1.crt\ + .pem passphrase=\"\";\r\ + \n# Quad9\r\ + \n#/tool/fetch mode=https url=\"https://cacerts.digicert.com/DigiCertGloba\ + lG3TLSECCSHA3842020CA1-1.crt.pem\"\r\ + \n#/certificate/import file-name=DigiCertGlobalG3TLSECCSHA3842020CA1-1.crt\ + .pem passphrase=\"\";\r\ + \n:global tmpAddCerts true; \r\ + \n\r\ + \n:global GlobalScriptsUrl;\r\ + \n:local UrlSuffix [/system/identity/get name];\r\ + \n:local UrlDir \"certs/\";\r\ + \n:local CertUrl (\$GlobalScriptsUrl . \$UrlDir . \$UrlSuffix .\"/\");\r\ + \n\r\ + \n:log error \$CertUrl;\r\ + \n\r\ + \n:local CertName \"DigiCert-Global-Root-CA.pem\";\r\ + \n/tool/fetch mode=https url=(\$CertUrl . \$CertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"DigiCert-Global-Root-CA\" [ find where common-na\ + me=\"DigiCert Global Root CA\" ];\r\ + \n\r\ + \n:set CertName \"DigiCert-Assured-ID-Root-CA.pem\";\r\ + \n/tool/fetch mode=https url=(\$CertUrl . \$CertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"DigiCert-Assured-ID-Root-CA\" [ find where commo\ + n-name=\"DigiCert Assured ID Root CA\" ];\r\ + \n\r\ + \n:set CertName \"DigiCert-Assured-ID-Root-G2.pem\";\r\ + \n/tool/fetch mode=https url=(\$CertUrl . \$CertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"DigiCert-Assured-ID-Root-G2\" [ find where commo\ + n-name=\"DigiCert Assured ID Root G3\" ];\r\ + \n\r\ + \n:set CertName \"DigiCert-Assured-ID-Root-G3.pem\";\r\ + \n/tool/fetch mode=https url=(\$CertUrl . \$CertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"DigiCert-Assured-ID-Root-G3\" [ find where commo\ + n-name=\"DigiCert Assured ID Root G3\" ];\r\ + \n\r\ + \n:set CertName \"DigiCert-Global-G2-TLS-RSA-SHA256-2020-CA1.pem\";\r\ + \n/tool/fetch mode=https url=(\$CertUrl . \$CertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"DigiCert-Global-G2-TLS-RSA-SHA256-2020-CA1\" [ f\ + ind where common-name=\"DigiCert Global G2 TLS RSA SHA256 2020 CA1\" ];\r\ + \n\r\ + \n:set CertName \"DigiCert-Global-G3-TLS-ECC-SHA384-2020-CA1.pem\";\r\ + \n/tool/fetch mode=https url=(\$CertUrl . \$CertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"DigiCert-Global-G3-TLS-ECC-SHA384-2020-CA1\" [ f\ + ind where common-name=\"DigiCert Global G3 TLS ECC SHA384 2020 CA1\" ];\r\ + \n\r\ + \n:set CertName \"DigiCert-Global-Root-G2.pem\";\r\ + \n/tool/fetch mode=https url=(\$CertUrl . \$CertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"DigiCert-Global-Root-G2\" [ find where common-na\ + me=\"DigiCert Global Root G2\" ];\r\ + \n\r\ + \n:set CertName \"DigiCert-Global-Root-G3.pem\";\r\ + \n/tool/fetch mode=https url=(\$CertUrl . \$CertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"DigiCert-Global-Root-G3\" [ find where common-na\ + me=\"DigiCert Global Root G3\" ];\r\ + \n\r\ + \n:set CertName \"DigiCert-TLS-ECC-P384-Root-G5.pem\";\r\ + \n/tool/fetch mode=https url=(\$CertUrl . \$CertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"DigiCert-TLS-ECC-P384-Root-G5\" [ find where com\ + mon-name=\"DigiCert TLS ECC P384 Root G5\" ];\r\ + \n\r\ + \n:set CertName \"DigiCert-TLS-RSA4096-Root-G5.pem\";\r\ + \n/tool/fetch mode=https url=(\$CertUrl . \$CertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"DigiCert-TLS-RSA4096-Root-G5\" [ find where comm\ + on-name=\"DigiCert TLS RSA4096 Root G5\" ];\r\ + \n\r\ + \n:set CertName \"DigiCert-Trusted-Root-G4.pem\";\r\ + \n/tool/fetch mode=https url=(\$CertUrl . \$CertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"DigiCert-Trusted-Root-G4\" [ find where common-n\ + ame=\"DigiCert Trusted Root G4\" ];\r\ + \n\r\ + \n:set CertName \"GTS-Root-R4.pem\";\r\ + \n/tool/fetch mode=https url=(\$CertUrl . \$CertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"GTS-Root-R4\" [ find where common-name=\"GTS Roo\ + t R4\" ];\r\ + \n\r\ + \n:set CertName \"Go-Daddy-Root-Certificate-Authority-G2.pem\";\r\ + \n/tool/fetch mode=https url=(\$CertUrl . \$CertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"Go-Daddy-Root-Certificate-Authority-G2\" [ find \ + where common-name=\"Go Daddy Root Certificate Authority - G2\" ];\r\ + \n\r\ + \n:set CertName \"ISRG-Root-X1.pem\";\r\ + \n/tool/fetch mode=https url=(\$CertUrl . \$CertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"ISRG-Root-X1\" [ find where common-name=\"ISRG R\ + oot X1\" ];\r\ + \n\r\ + \n:set CertName \"Root-YE.pem\";\r\ + \n/tool/fetch mode=https url=(\$CertUrl . \$CertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"Root-YE\" [ find where common-name=\"Root YE\" ]\ + ;\r\ + \n\r\ + \n:set CertName \"Starfield-Root-Certificate-Authority-G2.pem\";\r\ + \n/tool/fetch mode=https url=(\$CertUrl . \$CertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"Starfield-Root-Certificate-Authority-G2\" [ find\ + \_where common-name=\"Starfield Root Certificate Authority - G2\" ];\r\ + \n\r\ + \n:set CertName \"USERTrust-RSA-Certification-Authority.pem\";\r\ + \n/tool/fetch mode=https url=(\$CertUrl . \$CertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"USERTrust-RSA-Certification-Authority\" [ find w\ + here common-name=\"USERTrust RSA Certification Authority\" ];\r\ + \n\r\ + \n:global tmpAddCerts (a);\r\ + \n\r\ + \n#/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n#/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n#:set CertName \"GTS-Root-RX.pem\";\r\ + \n#/tool/fetch mode=https url=(\$AmScriptsUrl . \"certs/\" . \$CertName);\ + \r\ + \n#/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n#internet\r\ + \n#/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n#:set CertName \"ISRG-Root-X2.pem\";\r\ + \n#/tool/fetch mode=https url=(\$AmScriptsUrl . \"certs/\" . \$CertName);\ + \r\ + \n#/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n\r\ + \n\r\ + \n#/ip/dns/set allow-remote-requests=yes doh-max-concurrent-queries=100 do\ + h-max-server-connections=20 use-doh-server=https://security.cloudflare-dns\ + .com/dns-query verify-doh-cert=yes;\r\ + \n#/ip/dns/static remove [find where address=1.1.1.1];\r\ + \n#/ip/dns/static add address=1.1.1.1 name=security.cloudflare-dns.com com\ + ment=\"cloudflare-dns IPv4 1\";\r\ + \n#/ip/dns/ static remove [find where address=1.0.0.1];\r\ + \n#/ip/dns/static add address=1.0.0.1 name=security.cloudflare-dns.com com\ + ment=\"cloudflare-dns IPv4 2\"\r\ + \n#/ip dns static add address=2606:4700:4700::1111 name=security.cloudflar\ + e-dns.com type=AAAA\r\ + \n#/ip dns static add address=2606:4700:4700::1001 name=security.cloudflar\ + e-dns.com type=AAAA\r\ + \n#/ip/dns set servers=\"1.0.0.1, 8.8.4.4\";\r\ + \n#/ip/dns set servers=\"\";" +add dont-require-permissions=no name=fetchCustom owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="\ + \r\ + \n:global GlobalScriptsUrl;\r\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@10\ + .30.30.86.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.86.pub\";\ + \n" +add dont-require-permissions=no name=awg2-webui owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + :put \"Download image, and save him to usb1/tmp\"\ + \n#/tool/fetch url=\"https://ros.vados.ru/docker/awg2-webui-arm.tar\" dst-\ + path=usb1/tmp/awg2-webui.tar\ + \n\ + \n:put \"1. Create veth interface\"\ + \n/interface veth add name=veth-awg address=10.9.9.2/24 gateway=10.9.9.1\ + \n\ + \n:put \"2. Create bridge and add veth\"\ + \n/interface bridge add name=br-awg\ + \n/interface bridge port add bridge=br-awg interface=veth-awg\ + \n\ + \n:put \"3. Assign IP to bridge\"\ + \n/ip address add address=10.9.9.1/24 interface=br-awg\ + \n\ + \n:put \"4. NAT: masquerade container traffic\"\ + \n/ip firewall nat add chain=srcnat src-address=10.9.9.0/24 action=masquer\ + ade\ + \n\ + \n:put \"5. Port forward: UDP 443 \? container (AmneziaWG QUIC mimicry)\"\ + \n/ip firewall nat add chain=dstnat protocol=udp dst-port=443 \\\ + \n action=dst-nat to-addresses=10.9.9.2 to-ports=55055 in-interface=eth\ + er1\ + \n\ + \n:put \"6. Port forward: HTTPS 9443 \? container Web UI\"\ + \n/ip firewall nat add chain=dstnat protocol=tcp dst-port=9443 \\\ + \n action=dst-nat to-addresses=10.9.9.2 to-ports=443 in-interface=ether\ + 1\ + \n\ + \n:put \"Create environment list..\"\ + \n/container envs add list=awgui-env key=WEB_USER value=vados\ + \n/container envs add list=awgui-env key=WEB_PASS value=zoomzoomrulezz\ + \n/container envs add list=awgui-env key=SECRET_KEY value=RanDomSecret32Sy\ + mboLs2325272931q\ + \n/container envs add list=awgui-env key=AWG_ENDPOINT value=10.30.30.10:44\ + 3\ + \n\ + \n:put \"Load and start container...\"\ + \n/container add file=usb1/tmp/awg2-webui.tar interface=veth-awg hostname=\ + awg2-webui \\\ + \nroot-dir=usb1/awg2-webui envlist=awgui-env start-on-boot=yes logging=yes\ + \_shm-size=4M\ + \n\ + \n:put \"Start...\"\ + \n/container start 0\ + \n\ + \n:put \"Verify...\"\ + \n/container print\ + \n\ + \n:put \"Should show: status=running\"\ + \n\ + \n/log print where topics~\"container\"\ + \n\ + \n:put \"Should show: AWG started, nginx running\"\ + \n" +add comment=Generator dont-require-permissions=no name=AWG-VDSina owner=vados \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + source="# ============================================================\r\ + \n# AWG Proxy -- MikroTik RouterOS (protocol: v2)\r\ + \n# 2026-06-30 22:08:12\r\ + \n# ============================================================\r\ + \n\r\ + \n# 0. Check prerequisites\r\ + \n:if ([:len [/system/package/find where name=\"container\" disabled=no]] \ + = 0) do={\r\ + \n :put \"Container package is not installed or disabled. Install it and \ + reboot.\"\r\ + \n :error \"Usage: /system/device-mode/update container=yes\"\r\ + \n}\r\ + \n\r\ + \n# Auto-detect storage\r\ + \n:global awgDisk \"disk1\"\r\ + \n{\r\ + \n :local usbFree 0\r\ + \n :do { :set usbFree [/disk/get [find where mount-point=\"usb1\"] free] \ + } on-error={}\r\ + \n :if (\$usbFree > 0) do={\r\ + \n :set awgDisk \"usb1\"\r\ + \n :put (\"Using USB: usb1 (\" . (\$usbFree / 1048576) . \" MB free)\")\ + \r\ + \n } else={\r\ + \n :if ([:len [/disk/find where slot=\"usb1\"]] > 0) do={\r\ + \n :put \"USB found but not mounted. Format as ext4\?\"\r\ + \n :put \"Press 'y' to confirm:\"\r\ + \n :local key [/terminal/inkey timeout=30]\r\ + \n :if (\$key = 121 || \$key = 89) do={\r\ + \n /disk/format-drive usb1 file-system=ext4 label=usb1\r\ + \n :delay 3s\r\ + \n :do { :set usbFree [/disk/get [find where mount-point=\"usb1\"] \ + free] } on-error={}\r\ + \n :if (\$usbFree > 0) do={\r\ + \n :set awgDisk \"usb1\"\r\ + \n } else={ :put \"Format failed, using disk1\" }\r\ + \n } else={ :put \"Using disk1\" }\r\ + \n } else={ :put \"No USB, using disk1\" }\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n# 1. Uninstall script\r\ + \n/system/script/add name=awg-VDSina-uninstall comment=awg-VDSina source={\ + \r\ + \n :put \"Uninstallimg AmneziaWG...\"\r\ + \n :log info \"Uninstallimg AmneziaWG...\"\r\ + \n :local prevDNS \"\"\r\ + \n :do { :set prevDNS [/container/envs/get [find where list=\"awg-VDSina-\ + env\" key=\"AWG_PREV_DNS\"] value] } on-error={}\r\ + \n :local storageDisk \"disk1\"\r\ + \n :do { :set storageDisk [/container/envs/get [find where list=\"awg-VDS\ + ina-env\" key=\"AWG_STORAGE\"] value] } on-error={}\r\ + \n :local prevTmpdir \"\"\r\ + \n :if (\$storageDisk != \"disk1\") do={\r\ + \n :do { :set prevTmpdir [/container/envs/get [find where list=\"awg-VD\ + Sina-env\" key=\"AWG_PREV_TMPDIR\"] value] } on-error={}\r\ + \n }\r\ + \n /ip/route/remove [find where comment=awg-VDSina-tunnel]\r\ + \n /ip/route/remove [find where comment=awg-VDSina-dns]\r\ + \n /container/stop [find where interface=veth-awg-VDSina]\r\ + \n :delay 7s\r\ + \n /container/remove [find where interface=veth-awg-VDSina]\r\ + \n /container/envs/remove [find where list=\"awg-VDSina-env\"]\r\ + \n :if (\$prevDNS != \"\") do={\r\ + \n :do { /ip/dns/set servers=\"\$prevDNS\" } on-error={}\r\ + \n :put (\"DNS restored to: \$prevDNS\")\r\ + \n }\r\ + \n :if (\$storageDisk != \"disk1\") do={\r\ + \n /container/config set tmpdir=\$prevTmpdir\r\ + \n :put (\"Container tmpdir restored to: \$prevTmpdir\")\r\ + \n }\r\ + \n /ip/firewall/nat/remove [find where out-interface=\"wg-awg-VDSina\"]\r\ + \n /ip/firewall/nat/remove [find where src-address=\"172.19.75.208/30\"]\ + \r\ + \n /ip/address/remove [find where address=\"172.19.75.209/30\"]\r\ + \n /interface/veth/remove [find where name=\"veth-awg-VDSina\"]\r\ + \n /interface/wireguard/peers/remove [find where interface=\"wg-awg-VDSin\ + a\"]\r\ + \n /ip/address/remove [find where interface=\"wg-awg-VDSina\"]\r\ + \n /interface/wireguard/remove [find where name=\"wg-awg-VDSina\"]\r\ + \n :do { /file/remove [find where name~\"awg-VDSina.+tar\"] } on-error={}\ + \r\ + \n :do { /file/remove [find where name=(\$storageDisk . \"/awg-VDSina\")]\ + \_} on-error={}\r\ + \n :do { /file/remove [find where name=(\$storageDisk . \"/ru_ranges_time\ + out.rsc\")] } on-error={}\r\ + \n :if (\$storageDisk != \"disk1\") do={\r\ + \n :do { /file/remove [find where name~(\$storageDisk . \"/pull\")] } o\ + n-error={}\r\ + \n }\r\ + \n :put \"Uninstall AmneziaWG Proxy complete!\"\r\ + \n :log info \"Uninstall AmneziaWG Proxy complete!\"\r\ + \n /system/script/remove [find where name=awg-VDSina-uninstall]\r\ + \n}\r\ + \n\r\ + \n# 2. Network infrastructure\r\ + \n/interface/veth/add name=veth-awg-VDSina address=172.19.75.210/30 gatewa\ + y=172.19.75.209\r\ + \n/ip/address/add address=172.19.75.209/30 interface=veth-awg-VDSina\r\ + \n/ip/firewall/nat/add chain=srcnat action=masquerade src-address=172.19.7\ + 5.208/30\r\ + \n\r\ + \n# 3. WireGuard interface (MikroTik derives the public key automatically)\ + \r\ + \n/interface/wireguard/add name=wg-awg-VDSina private-key=\"4CHyNhbOs923/E\ + yNDguMXJXdghL2I3UyzXPwrANVgHs=\" listen-port=14710 disabled=yes\r\ + \n/interface/wireguard/peers/add interface=wg-awg-VDSina public-key=\"o5Ig\ + Cl1/G6xbl6j7sPaP4ZNYREeYOmqZjKbm+v0b9jU=\" preshared-key=\"RNvF7T1cg5tyXcY\ + QnD9N5BEp6e20vVJQTv0GMjyvHU0=\" endpoint-address=172.19.75.210 endpoint-po\ + rt=51820 allowed-address=0.0.0.0/0 persistent-keepalive=10\r\ + \n/ip/address/add address=10.9.0.3/32 interface=wg-awg-VDSina\r\ + \n\r\ + \n# 4. Container environment variables\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_LISTEN value=\":44044\"\ + \r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_REMOTE value=\"109.107.1\ + 77.79:55055\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_JC value=\"9\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_JMIN value=\"105\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_JMAX value=\"920\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_S1 value=\"90\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_S2 value=\"136\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_H1 value=\"472437748-472\ + 438637\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_H2 value=\"707808381-707\ + 809250\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_H3 value=\"1609078552-16\ + 09079495\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_H4 value=\"1012329484-10\ + 12329741\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_SERVER_PUB value=\"o5IgC\ + l1/G6xbl6j7sPaP4ZNYREeYOmqZjKbm+v0b9jU=\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_CLIENT_PUB value=[/inter\ + face/wireguard/get [find name=wg-awg-VDSina] public-key]\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_S3 value=\"45\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_S4 value=\"27\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_I1 value=\"\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_I2 value=\"\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_I3 value=\"\ + \"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_I4 value=\"\"\ + \r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_I5 value=\"\"\r\ + \n\r\ + \n# 5. DNS\r\ + \n{ :local rawDNS [/ip/dns/get servers]; :local prevDNS \"\"; :foreach s i\ + n=[:toarray \$rawDNS] do={ :if ([:len \$prevDNS] > 0) do={ :set prevDNS \"\ + \$prevDNS,\$s\" } else={ :set prevDNS \$s } }; /container/envs/add list=aw\ + g-VDSina-env key=AWG_PREV_DNS value=\"\$prevDNS\" }\r\ + \n# NOTE: replaces existing DNS configuration\r\ + \n/ip/dns/set servers=8.8.8.8\r\ + \n#/ip/route/add dst-address=109.107.177.79/32 gateway=wg-awg-VDSina dista\ + nce=1 comment=awg-VDSina-dns\r\ + \n\r\ + \n# 6. Download, create and start container\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_STORAGE value=\$awgDisk\ + \r\ + \n:if (\$awgDisk != \"disk1\") do={\r\ + \n :local tmpPath (\$awgDisk . \"/pull\")\r\ + \n /container/envs/add list=awg-VDSina-env key=AWG_PREV_TMPDIR value=[/co\ + ntainer/config/get tmpdir]\r\ + \n /container/config set tmpdir=\$tmpPath memory-high=200M\r\ + \n}\r\ + \n{\r\ + \n :local arch [/system/resource/get architecture-name]\r\ + \n :local ver [/system/resource/get version]\r\ + \n :local dotPos [:find \$ver \".\"]\r\ + \n :local rest [:pick \$ver (\$dotPos + 1) [:len \$ver]]\r\ + \n :local endPos [:find \$rest \".\"]\r\ + \n :if ([:typeof \$endPos] = \"nil\") do={ :set endPos [:find \$rest \" \ + \"] }\r\ + \n :local minor [:tonum [:pick \$rest 0 \$endPos]]\r\ + \n :local suffix \"\"\r\ + \n :if (\$minor <= 20) do={ :set suffix \"-7.20-Docker\" }\r\ + \n :local file \"\"\r\ + \n :if (\$arch = \"arm64\") do={ :set file (\"awg-proxy-arm64\" . \$suffi\ + x . \".tar.gz\") }\r\ + \n :if (\$arch = \"arm\") do={ :set file (\"awg-proxy-arm\" . \$suffix . \ + \".tar.gz\") }\r\ + \n :if (\$arch ~ \"x86\") do={ :set file (\"awg-proxy-amd64\" . \$suffix \ + . \".tar.gz\") }\r\ + \n :if (\$file = \"\") do={ :error \"Unsupported architecture: \$arch\" }\ + \r\ + \n :local url \"https://github.com/timbrs/amneziawg-mikrotik-c/releases/l\ + atest/download/\$file\"\r\ + \n :local filePath \$file\r\ + \n :if (\$awgDisk != \"disk1\") do={\r\ + \n :set filePath (\$awgDisk . \"/pull/\" . \$file)\r\ + \n :do { /file/make-directory (\$awgDisk . \"/pull\") } on-error={}\r\ + \n }\r\ + \n :if ([:len [/file/find where name=\$filePath]] = 0) do={\r\ + \n :local freeStorage 0\r\ + \n :if (\$awgDisk = \"disk1\") do={\r\ + \n :set freeStorage [/system/resource/get free-hdd-space]\r\ + \n } else={\r\ + \n :do { :set freeStorage [/disk/get [find where mount-point=\$awgDis\ + k] free] } on-error={}\r\ + \n }\r\ + \n :if (\$freeStorage < 262144) do={\r\ + \n :put (\"WARNING: Low disk space (\" . (\$freeStorage / 1024) . \"K\ + B free). Need at least 256KB.\")\r\ + \n :put \"See: https://github.com/timbrs/amneziawg-mikrotik-c#insuffi\ + cient-disk-space\"\r\ + \n :error \"Insufficient disk space\"\r\ + \n }\r\ + \n :put (\"Fetching: \$url -> \" . \$filePath)\r\ + \n /tool/fetch url=\$url dst-path=\$filePath http-max-redirect-count=10\ + \r\ + \n } else={\r\ + \n :put (\"File already exists: \" . \$filePath)\r\ + \n }\r\ + \n :local rootDir (\$awgDisk . \"/awg-VDSina\")\r\ + \n /container/add file=\$filePath interface=veth-awg-VDSina envlist=awg-V\ + DSina-env hostname=awg-VDSina root-dir=\$rootDir logging=no start-on-boot=\ + yes comment=awg-VDSina\r\ + \n :if (\$minor > 20) do={ [:parse \"/container/set [find where interface\ + =veth-awg-VDSina] shm-size=4M\"] }\r\ + \n /file/remove \$filePath\r\ + \n :local freeMem [/system/resource/get free-memory]\r\ + \n :if (\$freeMem < 16777216) do={\r\ + \n :put (\"WARNING: Low memory (\" . (\$freeMem / 1048576) . \"MB free)\ + . 16MB+ recommended.\")\r\ + \n }\r\ + \n /container/start [find where interface=veth-awg-VDSina]\r\ + \n :do { /file/remove [find where name=\"console-dump.txt\"] } on-error={\ + }\r\ + \n :put \"Waiting for container to start...\"\r\ + \n :delay 5s\r\ + \n /interface/wireguard/enable wg-awg-VDSina\r\ + \n :put \"WireGuard interface enabled\"\r\ + \n :put \"Installation complete!\"\r\ + \n :put \"Ping test: 109.107.177.79 via AmneziaWG tunnel. repeat 10 times\ + \"\r\ + \n /ping 109.107.177.79 count=10 interval=1\r\ + \n :put \"\"\r\ + \n :put \"======= NEXT STEPS =======\"\r\ + \n :put \"\"\r\ + \n :put \"Route specific traffic through the AmneziaWG tunnel:\"\r\ + \n :put \"\"\r\ + \n :put \" Route a single host:\"\r\ + \n :put \" /ip/route/add dst-address=8.8.8.8/32 gateway=wg-awg-VDSina \ + comment=awg-VDSina-tunnel\"\r\ + \n :put \"\"\r\ + \n :put \" Route a subnet:\"\r\ + \n :put \" /ip/route/add dst-address=100.0.0.0/8 gateway=wg-awg-VDSina\ + \_comment=awg-VDSina-tunnel\"\r\ + \n :put \"\"\r\ + \n :put \" Remove a route:\"\r\ + \n :put \" /ip/route/remove [find where comment=awg-VDSina-tunnel dst-\ + address=8.8.8.8/32]\"\r\ + \n :put \"\"\r\ + \n :put \" Show all tunnel routes:\"\r\ + \n :put \" /ip/route/print where comment=awg-VDSina-tunnel\"\r\ + \n :put \"\"\r\ + \n :put \" Uninstall:\"\r\ + \n :put \" /system/script/run awg-VDSina-uninstall\"\r\ + \n :put \"=========================\"\r\ + \n}\r\ + \n\r\ + \n# 7. Verification\r\ + \n# /container/print\r\ + \n# /interface/wireguard/print\r\ + \n# /interface/wireguard/peers/print\r\ + \n" +add comment=awgVDSina dont-require-permissions=no name=awgVDSina-uninstall \ + owner=Manager policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="\ + \r\ + \n :put \"Uninstalling AmneziaWG...\"\r\ + \n :log info \"Uninstalling AmneziaWG...\"\r\ + \n /ip/route/remove [find where comment=awgVDSina-tunnel]\r\ + \n :do { /tool/netwatch/remove [find where comment=Monitor-AWGVDSINA] } o\ + n-error={}\r\ + \n :do { /ip/route/remove [find where comment=Monitor-AWGVDSINA] } on-err\ + or={}\r\ + \n /container/stop [find where interface=veth-awgVDSina]\r\ + \n :delay 7s\r\ + \n /interface/list/member/remove [find where interface=wg-awgVDSina]\r\ + \n /container/remove [find where interface=veth-awgVDSina]\r\ + \n /container/envs/remove [find where list=\"awgVDSina-env\"]\r\ + \n /ip/firewall/nat/remove [find where out-interface=\"wg-awgVDSina\"]\r\ + \n /ip/address/remove [find where address=\"172.20.0.1/30\"]\r\ + \n /interface/veth/remove [find where name=\"veth-awgVDSina\"]\r\ + \n /interface/wireguard/peers/remove [find where interface=\"wg-awgVDSina\ + \"]\r\ + \n /ip/address/remove [find where interface=\"wg-awgVDSina\"]\r\ + \n /interface/wireguard/remove [find where name=\"wg-awgVDSina\"]\r\ + \n :do { /file/remove [find where name~\"awgVDSina.+tar\"] } on-error={}\ + \r\ + \n :do { /file/remove [find where name=\"disk1/awgVDSina\"] } on-error={}\ + \r\ + \n :put \"Uninstall AmneziaWG Proxy complete!\"\r\ + \n :log info \"Uninstall AmneziaWG Proxy complete!\"\r\ + \n /system/script/remove [find where name=awgVDSina-uninstall]\r\ + \n" +/user group +add name=backup policy="telnet,ssh,ftp,read,write,policy,test,sniff,sensitive,\ + !local,!reboot,!winbox,!password,!web,!api,!romon,!rest-api" +/container config +set layer-dir=/usb1/docker memory-high=200.0MiB memory-max=2048.0KiB \ + registry-url=https://registry-1.docker.io tmpdir=/usb1/pull username=\ + amsternl +/disk settings +set auto-media-interface=lo +/interface bridge port +add bridge=Bridge-LAN interface=ether2 +add bridge=Bridge-LAN interface=ether3 +add bridge=Bridge-LAN interface=ether4 +add bridge=Bridge-LAN interface=ether5 +add bridge=Bridge-LAN interface=wlan2 +add bridge=Bridge-LAN interface=wlan1 +add bridge=Bridge-LAN interface=ether1 +/ip neighbor discovery-settings +set discover-interface-list=Internet +/ipv6 settings +set allow-fast-path=no disable-ipv6=yes disable-link-local-address=yes \ + forward=no +/interface detect-internet +set detect-interface-list=WAN internet-interface-list=Internet \ + lan-interface-list=LAN wan-interface-list=WAN +/interface list member +add interface=ether2 list=LAN +add interface=ether3 list=LAN +add interface=ether4 list=LAN +add interface=ether5 list=LAN +add interface=wlan2 list=LAN +add interface=wlan1 list=LAN +add interface=ether1 list=Internet +add interface=Bridge-LAN list=LAN +/interface wireguard peers +add allowed-address=0.0.0.0/0,::/0 endpoint-address=172.20.0.2 endpoint-port=\ + 51820 interface=wg-awgVDSina name=awgVDSina persistent-keepalive=27s \ + public-key="o5IgCl1/G6xbl6j7sPaP4ZNYREeYOmqZjKbm+v0b9jU=" +/interface wireless cap +# +set bridge=Bridge-LAN caps-man-addresses=10.30.30.10 \ + caps-man-certificate-common-names=CAPsMAN-51B25E507D07 certificate=\ + CAP-18FD746E5814 discovery-interfaces=Bridge-LAN enabled=yes interfaces=\ + wlan1,wlan2 lock-to-caps-man=yes +/ip address +add address=10.30.30.86/24 interface=Bridge-LAN network=10.30.30.0 +add address=172.20.0.1/30 interface=veth-awgVDSina network=172.20.0.0 +add address=10.9.0.2 interface=wg-awgVDSina network=10.9.0.2 +/ip dns +set allow-remote-requests=yes servers=8.8.8.8 +/ip firewall nat +add action=masquerade chain=srcnat src-address=10.9.9.0/24 +# in/out-interface matcher not possible when interface (ether1) is slave - use master instead (Bridge-LAN) +add action=dst-nat chain=dstnat dst-port=443 in-interface=ether1 protocol=udp \ + to-addresses=10.9.9.2 to-ports=55055 +# in/out-interface matcher not possible when interface (ether1) is slave - use master instead (Bridge-LAN) +add action=dst-nat chain=dstnat dst-port=9443 in-interface=ether1 protocol=\ + tcp to-addresses=10.9.9.2 to-ports=443 +/ip firewall service-port +set ftp disabled=yes +set tftp disabled=yes +set irc disabled=no +set sip disabled=yes +set pptp disabled=yes +set rtsp disabled=no +/ip hotspot walled-garden +add server=*1 +add server=*1 +/ip ipsec settings +set accounting=no +/ip ipsec policy +set 0 disabled=yes dst-address=0.0.0.0/0 src-address=0.0.0.0/0 +/ip ipsec profile +set [ find default=yes ] dpd-interval=2m dpd-maximum-failures=5 +/ip proxy +set cache-administrator="" max-cache-size=none port=80,443 src-address=\ + 0.0.0.0 +/ip route +add check-gateway=ping disabled=no distance=2 dst-address=0.0.0.0/0 gateway=\ + 10.30.30.81 routing-table=main scope=30 target-scope=10 +add comment=Monitor-AWGVDSINA distance=1 dst-address=9.9.9.9/32 gateway=\ + wg-awgVDSina +/ip service +set ftp disabled=yes +set telnet disabled=yes +set ssh address=10.30.30.0/24 port=2222 +set winbox address=10.30.30.0/24 +set api address=10.30.30.0/24 disabled=yes +set api-ssl address=10.30.30.0/24 disabled=yes +set www-ssl port=18443 +set www address=10.30.30.0/24 disabled=yes port=18880 +/ip service webserver +set graphs-plain=no rest-plain=no webfig-plain=no +/ip ssh +set forwarding-enabled=both publickey-authentication-options=verify-required \ + strong-crypto=yes +/ip upnp +set enabled=yes +/ip upnp interfaces +add interface=Bridge-LAN type=internal +add forced-ip=109.107.177.79 interface=veth-awgVDSina type=external +add interface=lo type=internal +add interface=wlan2 type=internal +add interface=wlan1 type=internal +/ipv6 nd +set [ find default=yes ] advertise-dns=yes +/system clock +set time-zone-name=Europe/Moscow +/system clock manual +set time-zone=+03:00 +/system identity +set name=MikroGig +/system logging +add action=email disabled=yes regex="* added|changed|removed *" topics=\ + system,info +/system ntp client +set enabled=yes +/system ntp server +set enabled=yes manycast=yes multicast=yes use-local-clock=yes +/system ntp client servers +add address=10.30.30.81 +add address=10.30.30.10 +add address=0.ru.pool.ntp.org +add address=1.ru.pool.ntp.org +add address=2.ru.pool.ntp.org +add address=3.ru.pool.ntp.org +add address=time.google.com disabled=yes +/system scheduler +add comment="Every Day Set Global Environment Variables" name=AM-SetGlobalEnv \ + on-event="/system/script { run AM-GlobalConfig; run AM-GlobalFunc; }" \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-time=startup +add comment="Every Day Check For Update Scripts" interval=1d name=\ + AM-ScriptInstallUpdate on-event=\ + ":global ScriptInstallUpdate; \$ScriptInstallUpdate;" policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-time=startup +add comment=Generator name=awg-VDSina on-event="# ============================\ + ================================\r\ + \n# AWG Proxy -- MikroTik RouterOS (protocol: v2)\r\ + \n# 2026-07-01 00:03:43\r\ + \n# ============================================================\r\ + \n\r\ + \n# 0. Check prerequisites\r\ + \n:if ([:len [/system/package/find where name=\"container\" disabled=no]] \ + = 0) do={\r\ + \n :put \"Container package is not installed or disabled. Install it and \ + reboot.\"\r\ + \n :error \"Usage: /system/device-mode/update container=yes\"\r\ + \n}\r\ + \n\r\ + \n# Auto-detect storage\r\ + \n:global awgDisk \"disk1\"\r\ + \n{\r\ + \n :local usbFree 0\r\ + \n :do { :set usbFree [/disk/get [find where mount-point=\"usb1\"] free] \ + } on-error={}\r\ + \n :if (\$usbFree > 0) do={\r\ + \n :set awgDisk \"usb1\"\r\ + \n :put (\"Using USB: usb1 (\" . (\$usbFree / 1048576) . \" MB free)\")\ + \r\ + \n } else={\r\ + \n :if ([:len [/disk/find where slot=\"usb1\"]] > 0) do={\r\ + \n :put \"USB found but not mounted. Format as ext4\?\"\r\ + \n :put \"Press 'y' to confirm:\"\r\ + \n :local key [/terminal/inkey timeout=30]\r\ + \n :if (\$key = 121 || \$key = 89) do={\r\ + \n /disk/format-drive usb1 file-system=ext4 label=usb1\r\ + \n :delay 3s\r\ + \n :do { :set usbFree [/disk/get [find where mount-point=\"usb1\"] \ + free] } on-error={}\r\ + \n :if (\$usbFree > 0) do={\r\ + \n :set awgDisk \"usb1\"\r\ + \n } else={ :put \"Format failed, using disk1\" }\r\ + \n } else={ :put \"Using disk1\" }\r\ + \n } else={ :put \"No USB, using disk1\" }\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n# 1. Uninstall script\r\ + \n/system/script/add name=awg-VDSina-uninstall comment=awg-VDSina source={\ + \r\ + \n :put \"Uninstallimg AmneziaWG...\"\r\ + \n :log info \"Uninstallimg AmneziaWG...\"\r\ + \n :local prevDNS \"\"\r\ + \n :do { :set prevDNS [/container/envs/get [find where list=\"awg-VDSina-\ + env\" key=\"AWG_PREV_DNS\"] value] } on-error={}\r\ + \n :local storageDisk \"disk1\"\r\ + \n :do { :set storageDisk [/container/envs/get [find where list=\"awg-VDS\ + ina-env\" key=\"AWG_STORAGE\"] value] } on-error={}\r\ + \n :local prevTmpdir \"\"\r\ + \n :if (\$storageDisk != \"disk1\") do={\r\ + \n :do { :set prevTmpdir [/container/envs/get [find where list=\"awg-VD\ + Sina-env\" key=\"AWG_PREV_TMPDIR\"] value] } on-error={}\r\ + \n }\r\ + \n /ip/route/remove [find where comment=awg-VDSina-tunnel]\r\ + \n /ip/route/remove [find where comment=awg-VDSina-dns]\r\ + \n /container/stop [find where interface=veth-awg-VDSina]\r\ + \n :delay 7s\r\ + \n /container/remove [find where interface=veth-awg-VDSina]\r\ + \n /container/envs/remove [find where list=\"awg-VDSina-env\"]\r\ + \n :if (\$prevDNS != \"\") do={\r\ + \n :do { /ip/dns/set servers=\"\$prevDNS\" } on-error={}\r\ + \n :put (\"DNS restored to: \$prevDNS\")\r\ + \n }\r\ + \n :if (\$storageDisk != \"disk1\") do={\r\ + \n /container/config set tmpdir=\$prevTmpdir\r\ + \n :put (\"Container tmpdir restored to: \$prevTmpdir\")\r\ + \n }\r\ + \n /ip/firewall/nat/remove [find where out-interface=\"wg-awg-VDSina\"]\r\ + \n /ip/firewall/nat/remove [find where src-address=\"172.19.75.208/30\"]\ + \r\ + \n /ip/address/remove [find where address=\"172.19.75.209/30\"]\r\ + \n /interface/veth/remove [find where name=\"veth-awg-VDSina\"]\r\ + \n /interface/wireguard/peers/remove [find where interface=\"wg-awg-VDSin\ + a\"]\r\ + \n /ip/address/remove [find where interface=\"wg-awg-VDSina\"]\r\ + \n /interface/wireguard/remove [find where name=\"wg-awg-VDSina\"]\r\ + \n :do { /file/remove [find where name~\"awg-VDSina.+tar\"] } on-error={}\ + \r\ + \n :do { /file/remove [find where name=(\$storageDisk . \"/awg-VDSina\")]\ + \_} on-error={}\r\ + \n :do { /file/remove [find where name=(\$storageDisk . \"/ru_ranges_time\ + out.rsc\")] } on-error={}\r\ + \n :if (\$storageDisk != \"disk1\") do={\r\ + \n :do { /file/remove [find where name~(\$storageDisk . \"/pull\")] } o\ + n-error={}\r\ + \n }\r\ + \n :put \"Uninstall AmneziaWG Proxy complete!\"\r\ + \n :log info \"Uninstall AmneziaWG Proxy complete!\"\r\ + \n /system/script/remove [find where name=awg-VDSina-uninstall]\r\ + \n}\r\ + \n\r\ + \n# 2. Network infrastructure\r\ + \n/interface/veth/add name=veth-awg-VDSina address=172.19.75.210/30 gatewa\ + y=172.19.75.209\r\ + \n/ip/address/add address=172.19.75.209/30 interface=veth-awg-VDSina\r\ + \n/ip/firewall/nat/add chain=srcnat action=masquerade src-address=172.19.7\ + 5.208/30\r\ + \n\r\ + \n# 3. WireGuard interface (MikroTik derives the public key automatically)\ + \r\ + \n/interface/wireguard/add name=wg-awg-VDSina private-key=\"QCMsDU98Gm+nhn\ + kYRcAN/dyczDYHOLsX3PfBRFjWBF4=\" listen-port=14710 disabled=yes\r\ + \n/interface/wireguard/peers/add interface=wg-awg-VDSina public-key=\"o5Ig\ + Cl1/G6xbl6j7sPaP4ZNYREeYOmqZjKbm+v0b9jU=\" preshared-key=\"b39T9K2/LR8vNtY\ + AZw+sLRze6yGlS3EaZhAa7wiFB20=\" endpoint-address=172.19.75.210 endpoint-po\ + rt=51820 allowed-address=0.0.0.0/0 persistent-keepalive=10\r\ + \n/ip/address/add address=10.9.0.2/32 interface=wg-awg-VDSina\r\ + \n\r\ + \n# 4. Container environment variables\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_LISTEN value=\":51820\"\ + \r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_REMOTE value=\"109.107.1\ + 77.79:55055\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_JC value=\"9\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_JMIN value=\"105\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_JMAX value=\"920\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_S1 value=\"90\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_S2 value=\"136\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_H1 value=\"472437748-472\ + 438637\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_H2 value=\"707808381-707\ + 809250\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_H3 value=\"1609078552-16\ + 09079495\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_H4 value=\"1012329484-10\ + 12329741\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_SERVER_PUB value=\"o5IgC\ + l1/G6xbl6j7sPaP4ZNYREeYOmqZjKbm+v0b9jU=\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_CLIENT_PUB value=[/inter\ + face/wireguard/get [find name=wg-awg-VDSina] public-key]\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_S3 value=\"45\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_S4 value=\"27\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_I1 value=\"\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_I2 value=\"\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_I3 value=\"\ + \"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_I4 value=\"\"\ + \r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_I5 value=\"\"\r\ + \n\r\ + \n# 5. DNS\r\ + \n{ :local rawDNS [/ip/dns/get servers]; :local prevDNS \"\"; :foreach s i\ + n=[:toarray \$rawDNS] do={ :if ([:len \$prevDNS] > 0) do={ :set prevDNS \"\ + \$prevDNS,\$s\" } else={ :set prevDNS \$s } }; /container/envs/add list=aw\ + g-VDSina-env key=AWG_PREV_DNS value=\"\$prevDNS\" }\r\ + \n# NOTE: replaces existing DNS configuration\r\ + \n/ip/dns/set servers=109.107.177.79\r\ + \n/ip/route/add dst-address=109.107.177.79/32 gateway=wg-awg-VDSina distan\ + ce=1 comment=awg-VDSina-dns\r\ + \n\r\ + \n# 6. Download, create and start container\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_STORAGE value=\$awgDisk\ + \r\ + \n:if (\$awgDisk != \"disk1\") do={\r\ + \n :local tmpPath (\$awgDisk . \"/pull\")\r\ + \n /container/envs/add list=awg-VDSina-env key=AWG_PREV_TMPDIR value=[/co\ + ntainer/config/get tmpdir]\r\ + \n /container/config set tmpdir=\$tmpPath memory-high=200M\r\ + \n}\r\ + \n{\r\ + \n :local arch [/system/resource/get architecture-name]\r\ + \n :local ver [/system/resource/get version]\r\ + \n :local dotPos [:find \$ver \".\"]\r\ + \n :local rest [:pick \$ver (\$dotPos + 1) [:len \$ver]]\r\ + \n :local endPos [:find \$rest \".\"]\r\ + \n :if ([:typeof \$endPos] = \"nil\") do={ :set endPos [:find \$rest \" \ + \"] }\r\ + \n :local minor [:tonum [:pick \$rest 0 \$endPos]]\r\ + \n :local suffix \"\"\r\ + \n :if (\$minor <= 20) do={ :set suffix \"-7.20-Docker\" }\r\ + \n :local file \"\"\r\ + \n :if (\$arch = \"arm64\") do={ :set file (\"awg-proxy-arm64\" . \$suffi\ + x . \".tar.gz\") }\r\ + \n :if (\$arch = \"arm\") do={ :set file (\"awg-proxy-arm\" . \$suffix . \ + \".tar.gz\") }\r\ + \n :if (\$arch ~ \"x86\") do={ :set file (\"awg-proxy-amd64\" . \$suffix \ + . \".tar.gz\") }\r\ + \n :if (\$file = \"\") do={ :error \"Unsupported architecture: \$arch\" }\ + \r\ + \n :local url \"https://github.com/timbrs/amneziawg-mikrotik-c/releases/l\ + atest/download/\$file\"\r\ + \n :local filePath \$file\r\ + \n :if (\$awgDisk != \"disk1\") do={\r\ + \n :set filePath (\$awgDisk . \"/pull/\" . \$file)\r\ + \n :do { /file/make-directory (\$awgDisk . \"/pull\") } on-error={}\r\ + \n }\r\ + \n :if ([:len [/file/find where name=\$filePath]] = 0) do={\r\ + \n :local freeStorage 0\r\ + \n :if (\$awgDisk = \"disk1\") do={\r\ + \n :set freeStorage [/system/resource/get free-hdd-space]\r\ + \n } else={\r\ + \n :do { :set freeStorage [/disk/get [find where mount-point=\$awgDis\ + k] free] } on-error={}\r\ + \n }\r\ + \n :if (\$freeStorage < 262144) do={\r\ + \n :put (\"WARNING: Low disk space (\" . (\$freeStorage / 1024) . \"K\ + B free). Need at least 256KB.\")\r\ + \n :put \"See: https://github.com/timbrs/amneziawg-mikrotik-c#insuffi\ + cient-disk-space\"\r\ + \n :error \"Insufficient disk space\"\r\ + \n }\r\ + \n :put (\"Fetching: \$url -> \" . \$filePath)\r\ + \n /tool/fetch url=\$url dst-path=\$filePath http-max-redirect-count=10\ + \r\ + \n } else={\r\ + \n :put (\"File already exists: \" . \$filePath)\r\ + \n }\r\ + \n :local rootDir (\$awgDisk . \"/awg-VDSina\")\r\ + \n /container/add file=\$filePath interface=veth-awg-VDSina envlist=awg-V\ + DSina-env hostname=awg-VDSina root-dir=\$rootDir logging=no start-on-boot=\ + yes comment=awg-VDSina\r\ + \n :if (\$minor > 20) do={ [:parse \"/container/set [find where interface\ + =veth-awg-VDSina] shm-size=4M\"] }\r\ + \n /file/remove \$filePath\r\ + \n :local freeMem [/system/resource/get free-memory]\r\ + \n :if (\$freeMem < 16777216) do={\r\ + \n :put (\"WARNING: Low memory (\" . (\$freeMem / 1048576) . \"MB free)\ + . 16MB+ recommended.\")\r\ + \n }\r\ + \n /container/start [find where interface=veth-awg-VDSina]\r\ + \n :do { /file/remove [find where name=\"console-dump.txt\"] } on-error={\ + }\r\ + \n :put \"Waiting for container to start...\"\r\ + \n :delay 5s\r\ + \n /interface/wireguard/enable wg-awg-VDSina\r\ + \n :put \"WireGuard interface enabled\"\r\ + \n :put \"Installation complete!\"\r\ + \n :put \"Ping test: 109.107.177.79 via AmneziaWG tunnel. repeat 10 times\ + \"\r\ + \n /ping 109.107.177.79 count=10 interval=1\r\ + \n :put \"\"\r\ + \n :put \"======= NEXT STEPS =======\"\r\ + \n :put \"\"\r\ + \n :put \"Route specific traffic through the AmneziaWG tunnel:\"\r\ + \n :put \"\"\r\ + \n :put \" Route a single host:\"\r\ + \n :put \" /ip/route/add dst-address=8.8.8.8/32 gateway=wg-awg-VDSina \ + comment=awg-VDSina-tunnel\"\r\ + \n :put \"\"\r\ + \n :put \" Route a subnet:\"\r\ + \n :put \" /ip/route/add dst-address=100.0.0.0/8 gateway=wg-awg-VDSina\ + \_comment=awg-VDSina-tunnel\"\r\ + \n :put \"\"\r\ + \n :put \" Remove a route:\"\r\ + \n :put \" /ip/route/remove [find where comment=awg-VDSina-tunnel dst-\ + address=8.8.8.8/32]\"\r\ + \n :put \"\"\r\ + \n :put \" Show all tunnel routes:\"\r\ + \n :put \" /ip/route/print where comment=awg-VDSina-tunnel\"\r\ + \n :put \"\"\r\ + \n :put \" Uninstall:\"\r\ + \n :put \" /system/script/run awg-VDSina-uninstall\"\r\ + \n :put \"=========================\"\r\ + \n}\r\ + \n\r\ + \n# 7. Verification\r\ + \n# /container/print\r\ + \n# /interface/wireguard/print\r\ + \n# /interface/wireguard/peers/print\r\ + \n" policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-date=2026-07-01 start-time=02:03:59 +/tool e-mail +set certificate-verification=no from=MikroVados port=587 \ + server=smtp.mail.me.com tls=starttls user=vadossio@icloud.com +/tool netwatch +add comment=Monitor-AWGVDSINA down-script=\ + "/ip route disable [find comment=\"Route-AWGVDSINA\"]" host=9.9.9.9 \ + interval=10s packet-count=5 thr-avg=0ms thr-loss-count=4 timeout=5s type=\ + icmp up-script="/ip route enable [find comment=\"Route-AWGVDSINA\"]" diff --git a/MikroGig/history/20260704/20260704060105-Diff-Config.rsc b/MikroGig/history/20260704/20260704060105-Diff-Config.rsc new file mode 100644 index 0000000..298c839 --- /dev/null +++ b/MikroGig/history/20260704/20260704060105-Diff-Config.rsc @@ -0,0 +1,59 @@ +18,22d17 +< /interface veth +< add address=172.20.0.2/30 container-mac-address=00:00:00:00:00:00 dhcp=no \ +< gateway=172.20.0.1 gateway6="" name=veth-awgVDSina +< /interface wireguard +< add disabled=yes listen-port=12430 mtu=1360 name=wg-awgVDSina +2893,2923d2887 +< add comment=awgVDSina dont-require-permissions=no name=awgVDSina-uninstall \ +< owner=Manager policy=\ +< ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="\ +< \r\ +< \n :put \"Uninstalling AmneziaWG...\"\r\ +< \n :log info \"Uninstalling AmneziaWG...\"\r\ +< \n /ip/route/remove [find where comment=awgVDSina-tunnel]\r\ +< \n :do { /tool/netwatch/remove [find where comment=Monitor-AWGVDSINA] } o\ +< n-error={}\r\ +< \n :do { /ip/route/remove [find where comment=Monitor-AWGVDSINA] } on-err\ +< or={}\r\ +< \n /container/stop [find where interface=veth-awgVDSina]\r\ +< \n :delay 7s\r\ +< \n /interface/list/member/remove [find where interface=wg-awgVDSina]\r\ +< \n /container/remove [find where interface=veth-awgVDSina]\r\ +< \n /container/envs/remove [find where list=\"awgVDSina-env\"]\r\ +< \n /ip/firewall/nat/remove [find where out-interface=\"wg-awgVDSina\"]\r\ +< \n /ip/address/remove [find where address=\"172.20.0.1/30\"]\r\ +< \n /interface/veth/remove [find where name=\"veth-awgVDSina\"]\r\ +< \n /interface/wireguard/peers/remove [find where interface=\"wg-awgVDSina\ +< \"]\r\ +< \n /ip/address/remove [find where interface=\"wg-awgVDSina\"]\r\ +< \n /interface/wireguard/remove [find where name=\"wg-awgVDSina\"]\r\ +< \n :do { /file/remove [find where name~\"awgVDSina.+tar\"] } on-error={}\ +< \r\ +< \n :do { /file/remove [find where name=\"disk1/awgVDSina\"] } on-error={}\ +< \r\ +< \n :put \"Uninstall AmneziaWG Proxy complete!\"\r\ +< \n :log info \"Uninstall AmneziaWG Proxy complete!\"\r\ +< \n /system/script/remove [find where name=awgVDSina-uninstall]\r\ +< \n" +2958,2961d2921 +< /interface wireguard peers +< add allowed-address=0.0.0.0/0,::/0 endpoint-address=172.20.0.2 endpoint-port=\ +< 51820 interface=wg-awgVDSina name=awgVDSina persistent-keepalive=27s \ +< public-key="o5IgCl1/G6xbl6j7sPaP4ZNYREeYOmqZjKbm+v0b9jU=" +2970,2971d2929 +< add address=172.20.0.1/30 interface=veth-awgVDSina network=172.20.0.0 +< add address=10.9.0.2 interface=wg-awgVDSina network=10.9.0.2 +3004,3005d2961 +< add comment=Monitor-AWGVDSINA distance=1 dst-address=9.9.9.9/32 gateway=\ +< wg-awgVDSina +3024c2980 +< add forced-ip=109.107.177.79 interface=veth-awgVDSina type=external +--- +> add forced-ip=109.107.177.79 interface=*A type=external +3332,3336d3287 +< /tool netwatch +< add comment=Monitor-AWGVDSINA down-script=\ +< "/ip route disable [find comment=\"Route-AWGVDSINA\"]" host=9.9.9.9 \ +< interval=10s packet-count=5 thr-avg=0ms thr-loss-count=4 timeout=5s type=\ +< icmp up-script="/ip route enable [find comment=\"Route-AWGVDSINA\"]" diff --git a/MikroMaster/20260703/20260703194002-Config.rsc b/MikroMaster/20260703/20260703194002-Config.rsc new file mode 100644 index 0000000..d1297b9 --- /dev/null +++ b/MikroMaster/20260703/20260703194002-Config.rsc @@ -0,0 +1,3744 @@ +# 2026-07-03 19:40:05 by RouterOS 7.23.1 +# software id = A8L5-07YF +# +# model = RB952Ui-5ac2nD +# serial number = D3D50CEDCD38 +/interface bridge +add admin-mac=48:8F:5A:8E:1A:BF auto-mac=no dhcpv6-agent-circuit-id=\ + "\$(INTERFACE):\$(VID)" dhcpv6-agent-remote-id="\$(BRIDGEMAC)" name=\ + Bridge-LAN port-cost-mode=short +/interface ethernet +set [ find default-name=ether1 ] comment="WAN - Unet" loop-protect=off name=\ + "ether1 - Unet" rx-flow-control=auto tx-flow-control=auto +set [ find default-name=ether2 ] comment=LAN-2 +set [ find default-name=ether3 ] advertise="10M-baseT-half,10M-baseT-full,100M\ + -baseT-half,100M-baseT-full,1G-baseT-full,1G-baseX" comment=LAN-3 +set [ find default-name=ether4 ] comment=LAN-4 +set [ find default-name=ether5 ] advertise="10M-baseT-half,10M-baseT-full,100M\ + -baseT-half,100M-baseT-full,1G-baseT-full,1G-baseX" comment=LAN-5 \ + loop-protect=on poe-out=off rx-flow-control=auto tx-flow-control=auto +/interface wireless +# managed by CAPsMAN +set [ find default-name=wlan1 ] country=belarus mode=ap-bridge ssid=vados \ + wireless-protocol=802.11 +# managed by CAPsMAN +set [ find default-name=wlan2 ] country=belarus mode=ap-bridge ssid=vados5g \ + wireless-protocol=802.11 +/interface wireguard +add disabled=yes listen-port=33033 mtu=1360 name=NUC +add comment=WG disabled=yes listen-port=13231 mtu=1320 name=WG +add listen-port=21641 mtu=1420 name=wg-VDSina +/interface list +add include=static name=LAN +add name=Internet +add include=Internet name=WAN +/interface wireless security-profiles +set [ find default=yes ] authentication-types=wpa-psk,wpa2-psk mode=\ + dynamic-keys supplicant-identity=MikroTik +/iot wiliot servers +set *1 address=mqtt.us-east-2.prod.wiliot.cloud name="Wiliot US East" +/ip dhcp-server option +add code=12 name=HostName +add code=119 force=yes name=domain-search-list value="0x03'WORKGROUP'0x00" +/ip dhcp-server option sets +add name=HP1505n options=HostName +add name=StartLife1 options=HostName +add name=amsterDev options=HostName +add name=MiTV options=HostName +add name=miller options=HostName +add name=amster options=HostName +add name=garage options=HostName +add name=domain-search-set options=domain-search-list +add name=VADOS-LEN options=HostName +add name=VADOS-NUC options=HostName +add name=MikroNUC options=HostName +add name=master options=HostName +add name=MikroYellow options=HostName +add name="=\"Client ID\"" options=HostName +add name=iVados options=HostName +/ip dns forwarders +add disabled=yes dns-servers=1.0.0.1,1.1.1.1 name=blsp.at verify-doh-cert=no +add comment=Kra disabled=yes dns-servers=1.0.0.1,1.1.1.1 name=slon2.to \ + verify-doh-cert=no +add disabled=yes dns-servers=1.1.1.1,1.0.0.1 name=slon3.at verify-doh-cert=no +add disabled=yes dns-servers=1.0.0.1,1.1.1.1 name=slon3.cc verify-doh-cert=no +add disabled=yes dns-servers=1.1.1.1,1.0.0.1 name=bs2web.at verify-doh-cert=\ + no +add disabled=yes dns-servers=1.1.1.1,1.0.0.1 name=bs2best.at verify-doh-cert=\ + no +add disabled=yes dns-servers=1.0.0.1,1.1.1.1 name=psrms.is verify-doh-cert=no +/ip ipsec proposal +set [ find default=yes ] disabled=yes +/ip pool +add name=dhcp ranges=10.30.30.83-10.30.30.254 +/ip dhcp-server +add add-arp=yes address-pool=dhcp always-broadcast=yes bootp-support=none \ + dhcp-option-set=domain-search-set interface=Bridge-LAN lease-time=10m \ + name=masterDHCP server-address=10.30.30.81 +/ip smb users +set [ find default=yes ] disabled=yes +add disabled=yes name=vados +/ipv6 dhcp-client option +add code=119 name=domain-search-list value="0x03'WORKGROUP'0x00" +add code=12 name=HostName value="\$(HOSTNAME)" +add code=61 name=DUID value=0x00030001488f5a8e1abc +add code=61 name=clientid +/ipv6 dhcp-server option +add code=119 name=domain-search-list value="0x03'WORKGROUP'0x00" +add code=12 name=HostName value="\$(HOSTNAME)" +add code=61 name=CLIENT_DUID +add code=61 name=CLIENT_MAC +/ppp profile +set *FFFFFFFE use-upnp=no +/routing bgp template +set default disabled=no output.network=bgp-networks +/routing table +add disabled=no fib name=To-VPN +add disabled=no fib name=r_to_vpn +/system logging action +add email-start-tls=yes email-to=vados@vados.ru name=email target=email +/system script +add dont-require-permissions=no name=fetchCustom owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + global GlobalScriptsUrl \"https://ros.vados.ru/\";\r\ + \n\r\ + \n#/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@1\ + 0.30.30.86.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.86.pub\";\ + \n\r\ + \n#:local Script AM-setup\ + \n;\r\ + \n#/system/script/add name=\$Script owner=\$Script source=([ /tool/fetch c\ + heck-certificate=yes-without-crl url=(\$GlobalScriptsUrl . \$Script . \".r\ + sc\") output=user as-value ]->\"data\");\r\ + \n\ + \n#/usb1/mikro_bak_rsa.pub\ + \n\ + \n\r\ + \n#\ + \n\r\ + \n#/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@1\ + 0.30.30.10.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.10.pub\";\ + \n\r\ + \n#\r\ + \n\ + \n#root.mnuc.backuper\ + \n\ + \n\r\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@10\ + .30.30.81.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.81.pub\";\r\ + \n\ + \n#:local Script AM-GlobalConfig;\ + \n\r\ + \n#/system/script/add name=\$Script owner=\$Script source=([ /tool/fetch c\ + heck-certificate=yes-without-crl url=(\$GlobalScriptsUrl . \$Script . \".r\ + sc\") output=user as-value ]->\"data\");\r\ + \n\ + \n#/usb1/mikro_bak_rsa.pub\ + \n#:local FetchFile AM-DOHCert.rsc\ + \n\ + \n\r\ + \n\r\ + \n#\ + \n:global MkDir;\ + \n\r\ + \n\ + \n#:local FetchFile Binary.backup\ + \n:local localDir \"\";\ + \n\ + \n\r\ + \n#\$MkDir \$localDir;\r\ + \n\ + \n#\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \$FetchFile) dst-path=(\ + \$localDir . \$FetchFile);\r\ + \n" +add comment="Global Config Script" dont-require-permissions=no name=\ + AM-GlobalConfig owner=AM-GlobalConfig policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\r\ + \n# RouterOS script: AM-GlobalConfig\r\ + \n# Script comment: Global Config Script\r\ + \n# Copyright (c) 2007-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# Warning: Dont touch this line!\r\ + \n:global Identity [/system/identity/get name];\r\ + \n:global GlobalConfReady false;\r\ + \n#\r\ + \n#\r\ + \n# Global Url For Amster scripts to fetch\r\ + \n# most be defined in AM-Init-Script or AM-setup scripts\r\ + \n:global GlobalScriptsUrl \"https://ros.vados.ru/\";\r\ + \n:global ScriptsUrlSuffix (a);\r\ + \n:global CheckSumsVerify true;\r\ + \n\r\ + \n:global ScriptUpdatesCRLF true;\r\ + \n:global CommentsInScripts true;\r\ + \n\r\ + \n# Debug output:\r\ + \n:global PrintDebug true; #false;\r\ + \n\r\ + \n# Debug output for specific script:\r\ + \n#:set (\$PrintDebugOverride->\"AM-GlobalFunc\") true;\r\ + \n\r\ + \n# Debug logs\r\ + \n# Other actions (disk, email, remote or support) can be used as well.\r\ + \n# I do not recommend using echo - use debug output instead (https://rsc.\ + eworm.de/main/DEBUG.html#debug-output).\r\ + \n#/system/logging/add topics=script,debug action=memory;\r\ + \n\r\ + \n:global MikrotikUpgradeUrl \"https://upgrade.mikrotik.com/routeros\";\r\ + \n:global Domain \"WORKGROUP\";\r\ + \n\r\ + \n:global EmailGeneralTo \"vados@vados.ru\";\r\ + \n#:global EmailGeneralCc \"\";\r\ + \n\r\ + \n# \$ScriptInstallUpdate mod/notification-telegram\r\ + \n:global TelegramTokenId \"8390868324:AAG3_d1hfVR2M6pGAgDK6ZvhOe4J97nyopw\ + \";\r\ + \n:global TelegramChatId \"-1003631309063\"; #\"454403445\";\r\ + \n# Use this to send notifications to a specific topic in group.\r\ + \n#:global TelegramThreadId \"30\";\r\ + \n# Using telegram-chat you have to define trusted chat ids (not group ids\ + !)\r\ + \n# or user names. Groups allow to chat with devices simultaneously.\r\ + \n:global TelegramChatIdsTrusted {\r\ + \n \"454403445\"\r\ + \n \"-1003631309063\"\r\ + \n \"-5124482807\"\r\ + \n \"1087968824\";\r\ + \n};\r\ + \n# \"-5294757340\";\r\ + \n\r\ + \n:global TelegramChatGroups \"(all)\";\r\ + \n#:global TelegramChatGroups \"(all|home|office)\";\r\ + \n\r\ + \n:global NotificationFunctions {\r\ + \n \"email\"\r\ + \n \"telegram\";\r\ + \n};\r\ + \n# Toggle this to disable symbols in notifications.\r\ + \n:global NotificationsWithSymbols true;\r\ + \n:global TerminalColorOutput true;\r\ + \n\r\ + \n:global DetectIpAddrDefault \"https://ipv4.mikrotik.ovh/\";\r\ + \n:global DetectIpAddrFallback \"https://api.ipify.org/\";\r\ + \n\r\ + \n## Update channel. Possible values: stable, long-term, testing, developm\ + ent\r\ + \n:global updateChannel \"stable\";\r\ + \n\r\ + \n:global CertRenewUrl (\$GlobalScriptsUrl . \"certs/\" . \$Identity . \"/\ + \");\r\ + \n:global CertRenewTime 2w;\r\ + \n:global CertRenewPass (a); #{\r\ + \n# \"\";\r\ + \n# \"v3ry-s3cr3t\";\r\ + \n# \"4n0th3r-s3cr3t\";\r\ + \n#};\r\ + \n:global CertWarnTime 1w;\r\ + \n:global CertIssuedExportPass (a); # {\r\ + \n# \"\";\r\ + \n# \"cert1-cn\"=\"v3ry-s3cr3t\";\r\ + \n# \"cert2-cn\"=\"4n0th3r-s3cr3t\";\r\ + \n#};\r\ + \n\r\ + \n# Script BackupAndUpdate mode, possible values: backup,\r\ + \n# updateOnce - Update once as \"osnotify\" and back \"osnotify\" mode (i\ + n terminal run :set OSUpdateMode updateOnce; \$OSUpdateMode;). \r\ + \n# osupdate - Update if available and creates backups before/after update\ + \_(ignores `forceBackup`)\r\ + \n# Set `forceBackup` to true to always create backups, even\ + \_without updates\r\ + \n# osnotify - Set `forceBackup` to always create backups on every run\r\ + \n:global DevInfoIncludeIP true;\r\ + \n:global BackupAndUpdateMode \"osnotify\"\r\ + \n\r\ + \n:global forceBackup true;\r\ + \n:global BackupPassword \"Peskar55\";\r\ + \n\r\ + \n# SFTP Backup Variables\r\ + \n:global BackupRandomDelay 0;\r\ + \n:global BackupUploadUrl \"sftp://amster.vados.ru/upload/\";\r\ + \n:global BackupUploadUser \$Identity;\r\ + \n:global BackupUploadPass \"root.mnuc.backuper\";\r\ + \n\r\ + \n:global BackupSendBinary true;\r\ + \n:global BackupSendExport true;\r\ + \n:global BackupSendGlobalConfig true;\r\ + \n:global BackupSendScripts true;\r\ + \n\r\ + \n# Remove local file after uploading if no errors\r\ + \n:global BackupRmLocal true;\r\ + \n\r\ + \n# Local Backups Root Directory \r\ + \n:global BackupLocalRoot \"tmpfs\";\r\ + \n\r\ + \n# Encrypt Backup\r\ + \n:global BackupEncrypt true;\r\ + \n\r\ + \n# Sensitive information in Backups\r\ + \n:global BackupSens true;\r\ + \n\r\ + \n# User Export\r\ + \n:global BackupUser true;\r\ + \n\r\ + \n# License Export (not for CHR, will silently skip)\r\ + \n:global BackupLicense false;\r\ + \n\r\ + \n# SSH Keys\r\ + \n:global BackupSshKeys true;\r\ + \n\r\ + \n# Certificate Export\r\ + \n:global BackupCerts true;\r\ + \n\r\ + \n# Certificate Password\r\ + \n:global BackupCertsPasswd \"\";\r\ + \n\r\ + \n# User-Manager Export\r\ + \n:global BackupUserMan false;\r\ + \n\r\ + \n# The Dude Export\r\ + \n:global BackupDude false;\r\ + \n\r\ + \n# User Files to export, comma-separated string or array of strings\r\ + \n# User Files are not removed on backup\r\ + \n# Any directory paths will be removed (/ -> _) on remote file\r\ + \n# Nonpresent files are silently skipped\r\ + \n:global BackupUserList \"autosupout.rif,autosupout.old.rif\";\r\ + \n\r\ + \n# load functions and any custom scripts\r\ + \n# [ /system/script/find where name=\"global-config-ov\ + erlay\" ], \\\r\ + \n# [ /system/script/find where name~\"^global-config-o\ + verlay\\\\.d/.\" ]\r\ + \n#\r\ + \n#:foreach Script in=([ /system/script/find where name=\"Amster-TGglobalV\ + ars\" ], [ /system/script/find where name=\"Amster-TGglobalFunc\" ]) do={\ + \r\ + \n# :onerror Err {\r\ + \n# /system/script/run \$Script;\r\ + \n# } do={\r\ + \n# :log error (\"Loading configuration from configs and functions\"\ + \_. [ /system/script/get \$Script name ] . \" failed: \" . \$Err);\r\ + \n# }\r\ + \n#}\r\ + \n#:log info \"\\ndevMode = \$devMode\";\r\ + \n#:log info \"\\ndevRunning = \$devRunning\";\r\ + \n:foreach Script in=[ /system/script/find where source~\"^#!rsc by Vados \ + GlobalRUN\\r\?\\n\" ] do={\r\ + \n :onerror Err {\r\ + \n /system/script/run \$Script;\r\ + \n } do={\r\ + \n :log error (\"Run script \" . [ /system/script/get \$Script name \ + ] . \" width marker \\\" GlobalRUN\\\" failed: \" . \$Err);\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n# signal we are ready\r\ + \n:set GlobalConfReady true;\r\ + \n:while (\$GlobalConfReady != true) do={:delay 500ms};\r\ + \n" +add comment="Global functions" dont-require-permissions=no name=AM-GlobalFunc \ + owner=AM-GlobalFunc policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\r\ + \n# RouterOS script: AM-GglobalFunc\r\ + \n# Script comment: Global functions\r\ + \n# Copyright (c) 2005-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version=7.19\r\ + \n# requires device-mode, fetch, scheduler\r\ + \n:local ExitOK false;\r\ + \n:local ScriptName [ :jobname ];\r\ + \n#:global checkRunJob \$SriptName;\r\ + \n#:global fixCRLF;\r\ + \n#:if (\$fixCRLF != false) do={\r\ + \n#:foreach fixScript in=([ /system/script/find where name~\"*\" ]) do={/s\ + ystem/script/set source=[ :tocrlf [ get \$fixScript source ] ] \$fixScript\ + }\r\ + \n#:if (\$fixCRLF != \"LF\") do={ /system/script/set source=[ :tocrlf [ g\ + et \$fixScript source ] ] \$fixScript};};\r\ + \n#}\r\ + \n:global GlobalFuncReady false;\r\ + \n\r\ + \n# Git commit id & info, expected configuration version\r\ + \n:global CommitId \"main/729/f42d43ae\";\r\ + \n:global CommitTAG \"unknown\";\r\ + \n:global CommitInfo \"Autocommit in repo: ros.vados.ru, generated by owne\ + r: root, in 00:05:03 01.07.2026.\";\r\ + \n\r\ + \n# The variables are received right here.\r\ + \n:global GlobalConfVersion 140;\r\ + \n\r\ + \n:global SumsDirAndFileName \"tmp/checksums.json\";\r\ + \n\r\ + \n:global Identity [/system/identity/get name];\r\ + \n:global IdentityShort [:pick \$Identity 0 18];\r\ + \n\r\ + \n:global devBoardName [/system/resource/get board-name];\r\ + \n:global devMode [/system/device-mode/get mode];\r\ + \n:global devCurArch [/system/resource/get architecture-name];\r\ + \n:global devCurVersion [/system/resource/get version];\r\ + \n\r\ + \n# Variables defined in AM-GlobalConfig.rsc\r\ + \n:global TerminalColorOutput;\r\ + \n:global CommentsInScripts;\r\ + \n:global DetectIpAddrDefault;\r\ + \n:global DetectIpAddrFallback;\r\ + \n:global updateChannel;\r\ + \n:global Domain;\r\ + \n:global EmailGeneralTo;\r\ + \n:global BackupAndUpdateMode;\r\ + \n\r\ + \n# Single functions, without nested functions.\r\ + \n:global MiniDateTimeStamp;\r\ + \n:global MicroDateTimeStamp;\r\ + \n\r\ + \n# Include globals \$PrintDebug and \$PrintDebugOverride\r\ + \n:global LogPrint;\r\ + \n\r\ + \n# DeviceInfo and Updates\r\ + \n:global IsCheckUpdates;\r\ + \n:global WaitCheckUpdates;\r\ + \n:global GetPubIp;\r\ + \n\r\ + \n:global GetArrDeviceInfo;\r\ + \n:global WaitArrDeviceInfo;\r\ + \n\r\ + \n:global devModel;\r\ + \n:global devRunningMode;\r\ + \n\r\ + \n:global devRbRevision;\r\ + \n:global devRbSerialNumber;\r\ + \n:global devRbVerAvail;\r\ + \n\r\ + \n:global runningChannelVersion;\r\ + \n:global runningChannel;\r\ + \n:global runningVersion;\r\ + \n\r\ + \n:global devBuildTime;\r\ + \n:global ROsVerAvail;\r\ + \n:global PkgUpdStatus;\r\ + \n:global currentUpdateChannel;\r\ + \n\r\ + \n:global ScriptInstallUpdate;\r\ + \n\r\ + \n:global DeviceInfo;\r\ + \n\r\ + \n:global OldMode;\r\ + \n\r\ + \n:global ParseKeyValueStore;\r\ + \n:global RandomDelay;\r\ + \n:global GetRandomNumber;\r\ + \n:global EscapeForRegEx;\r\ + \n:global CharacterMultiply;\r\ + \n:global CharacterReplace;\r\ + \n:global CleanFilePath;\r\ + \n:global CleanName;\r\ + \n\r\ + \n:global CommitBrief;\r\ + \n\r\ + \n:global EitherOr;\r\ + \n:global FormatLine;\r\ + \n:global GetRandom20CharAlNum;\r\ + \n:global GetRandom20CharHex;\r\ + \n:global GetRandomNumber;\r\ + \n:global Grep;\r\ + \n:global IfThenElse;\r\ + \n:global MAX;\r\ + \n:global MIN;\r\ + \n:global HumanReadableNum;\r\ + \n\r\ + \n:global IsFullyConnected;\r\ + \n:global IsDNSResolving;\r\ + \n:global IsTimeSync;\r\ + \n:global IsTimeSyncCached;\r\ + \n:global IsTimeSyncResetNtp;\r\ + \n\r\ + \n:global MkDir;\r\ + \n:global RmDir;\r\ + \n:global RmFile;\r\ + \n:global FileGet;\r\ + \n:global Unix2Dos;\r\ + \n:global UrlEncode;\r\ + \n:global WaitForFile;\r\ + \n:global ScriptLock;\r\ + \n:global SendTelegram;\r\ + \n:global NotificationFunctions;\r\ + \n:global SendNotification;\r\ + \n:global SendNotification2;\r\ + \n:global SymbolForNotification;\r\ + \n:global SymbolByUnicodeName;\r\ + \n:global ValidateSyntax;\r\ + \n:global CheckSumsVerify;\r\ + \n:global GlobalConfChanges;\r\ + \n:global GlobalConfMigration;\r\ + \n:global VersionToNum;\r\ + \n:global RequiredRouterOS;\r\ + \n:global ExitError;\r\ + \n:global ExitOnError;\r\ + \n\r\ + \n:global FetchHugeFiles;\r\ + \n:global FetchUserAgentStr;\r\ + \n:global FileExists;\r\ + \n:global CertificateAvailable;\r\ + \n:global CertificateDownload;\r\ + \n:global CertificateNameByCN;\r\ + \n:global CharacterMultiply;\r\ + \n\r\ + \n:global InspectVar;\r\ + \n:global InspectVarRet;\r\ + \n:global ParseCustom;\r\ + \n\r\ + \n:set IsCheckUpdates do={\r\ + \n :local isInfo [:tobool \$1];\r\ + \n :global updateChannel;\r\ + \n :global PkgUpdStatus;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n :global arrDeviceInfo;\r\ + \n :log info (\$0 . \" \\\$isInfo = \" . \$isInfo); \r\ + \n :local CurrentChannel [ /system/package/update/get channel ];\r\ + \n :if ([ :len \$updateChannel ] > 0 && \$CurrentChannel != \$updateChann\ + el) do={\r\ + \n :retry command={/system/package/update set channel=\$updateChannel} \ + \_delay=300ms max=5 on-error={};\r\ + \n :log info (\$0 . \" Set updates channel to: \$updateChannel\");\r\ + \n }\r\ + \n :local Update [ /system/package/update/get ];\r\ + \n :local Channel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set currentUpdateChannel \$Channel;\r\ + \n :log info (\$0 . \" Update Channel: \" . \$Channel . \".\");\r\ + \n :local StatusPkg \"undefined\";\r\ + \n :log info (\$0 . \" Checking for updates...\");\r\ + \n :retry command={:set \$StatusPkg ([/system/package/update/check-for-up\ + dates without-paging as-value]->\"status\")} \\\r\ + \n delay=300ms max=5 on-error={};\r\ + \n :log info (\$0 . \" \\\$StatusPkg = \" . \$StatusPkg);\r\ + \n :if (\$StatusPkg = \"New version is available\") do={ :set PkgUpdStatu\ + s true; } else={ :set PkgUpdStatus false; }\r\ + \n :set ROsVerAvail [ :tostr [ /system/package/update/get latest-version \ + ] ];\r\ + \n :log info (\$0 . \" \\\$PkgUpdStatus = \" . \$PkgUpdStatus);\r\ + \n :if (\$isInfo != false || \$PkgUpdStatus = true) do={\r\ + \n :log info (\$0 . \" \\\$PkgUpdStatus = \" . \$PkgUpdStatus);\r\ + \n :if ([ :typeof \$arrDeviceInfo ] != \"array\") do={\r\ + \n :set arrDeviceInfo [:toarray \$arrDeviceInfo];\r\ + \n }\r\ + \n :retry command={:set (\$arrDeviceInfo->\"devUpdates\") [ /system/pac\ + kage/update/get ]} delay=500ms max=5 on-error={:log error (\"Error\")};\r\ + \n :return true;\r\ + \n } else={\r\ + \n :return \$PkgUpdStatus;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set WaitCheckUpdates do={\r\ + \n :global IsCheckUpdates;\r\ + \n :global PkgUpdStatus;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n :global arrDeviceInfo;\r\ + \n :local Status \"\";\r\ + \n :local Update;\r\ + \n :local WaitCount 0;\r\ + \n :if ([ \$IsCheckUpdates true ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n :set Status [ :tostr [ /system/package/update/get status ] ];\r\ + \n :while ((\$Status = \"\" || \$Status = \"finding out latest version...\ + \") && \$WaitCount < 60) do={\r\ + \n :delay 1s;\r\ + \n :set WaitCount (\$WaitCount + 1);\r\ + \n :set Status [ :tostr [ /system/package/update/get status ] ];\r\ + \n }\r\ + \n :set Update [ /system/package/update/get ];\r\ + \n :set currentUpdateChannel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set ROsVerAvail [ :tostr (\$Update->\"latest-version\") ];\r\ + \n :if ((\$Update->\"status\") = \"New version is available\") do={\r\ + \n :set PkgUpdStatus true;\r\ + \n } else={\r\ + \n :set PkgUpdStatus false;\r\ + \n }\r\ + \n :if ([ :typeof \$arrDeviceInfo ] != \"array\") do={\r\ + \n :set arrDeviceInfo [:toarray \$arrDeviceInfo];\r\ + \n }\r\ + \n :set (\$arrDeviceInfo->\"devUpdates\") \$Update;\r\ + \n :if (\$Status = \"\" || \$Status = \"finding out latest version...\") \ + do={\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set WaitArrDeviceInfo do={\r\ + \n :global GetArrDeviceInfo;\r\ + \n :while ([ \$GetArrDeviceInfo ] = false) do={\r\ + \n :delay 1s;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set GetArrDeviceInfo do={\r\ + \n :global LogPrint;\r\ + \n :global arrDeviceInfo;\r\ + \n :global devBoardName;\r\ + \n :global devModel;\r\ + \n :global devRunning;\r\ + \n :global devCurArch;\r\ + \n :global devRbRevision;\r\ + \n :global devRbSerialNumber;\r\ + \n :global devBuildTime;\r\ + \n :global runningChannelVersion;\r\ + \n :global runningChannel;\r\ + \n :global runningVersion;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n\r\ + \n :local DeviceInfo;\r\ + \n :local Resource [/system/resource/get];\r\ + \n :local Update [ /system/package/update/get ];\r\ + \n :local VersionString [ :tostr (\$Resource->\"version\") ];\r\ + \n :local ChannelStart [ :find \$VersionString \" (\" ];\r\ + \n :local RouterBoard;\r\ + \n :local IsRouterBoard false;\r\ + \n :local RunningMode \"\";\r\ + \n\r\ + \n :set devCurArch [ :tostr (\$Resource->\"architecture-name\") ];\r\ + \n :set devBuildTime [ :tostr (\$Resource->\"build-time\") ];\r\ + \n :set runningChannelVersion \$VersionString;\r\ + \n :set runningVersion \$VersionString;\r\ + \n :set runningChannel \"\";\r\ + \n\r\ + \n :if ([ :typeof \$ChannelStart ] = \"num\" && \$ChannelStart >= 0) do=\ + {\r\ + \n :set runningVersion [ :pick \$VersionString 0 \$ChannelStart ];\r\ + \n :local ChannelRest [ :pick \$VersionString (\$ChannelStart + 2) [ :\ + len \$VersionString ] ];\r\ + \n :local ChannelEnd [ :find \$ChannelRest \")\" ];\r\ + \n :if ([ :typeof \$ChannelEnd ] = \"num\" && \$ChannelEnd >= 0) do={\ + \r\ + \n :set runningChannel [ :pick \$ChannelRest 0 \$ChannelEnd ];\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :if ([:pick \$devBoardName 0 3] != \"CHR\" or [:pick \$devBoardName 0\ + \_3] != \"x86\") do={\r\ + \n :do {\r\ + \n :set RouterBoard [[ :parse \"/system/routerboard/get\" ]];\r\ + \n# :set RouterBoard [ /system/routerboard/get ];\r\ + \n :if ((\$RouterBoard->\"routerboard\") = true) do={\r\ + \n :set IsRouterBoard true;\r\ + \n }\r\ + \n } on-error={}\r\ + \n }\r\ + \n\r\ + \n :do {\r\ + \n :set RunningMode [ /system/device-mode/get mode ];\r\ + \n } on-error={\r\ + \n :do {\r\ + \n :set RunningMode [ /system/device-mode/get running ];\r\ + \n } on-error={\r\ + \n :set RunningMode \"\";\r\ + \n }\r\ + \n }\r\ + \n :set devRunning \$RunningMode;\r\ + \n\r\ + \n :if (\$IsRouterBoard = true) do={\r\ + \n :set devModel [ :tostr (\$RouterBoard->\"model\") ];\r\ + \n :set devRbRevision [ :tostr (\$RouterBoard->\"revision\") ];\r\ + \n :set devRbSerialNumber [ :tostr (\$RouterBoard->\"serial-number\") \ + ];\r\ + \n } else={\r\ + \n :set devModel \$devBoardName;\r\ + \n :set devRbRevision \"\";\r\ + \n :set devRbSerialNumber \"\";\r\ + \n }\r\ + \n\r\ + \n :set currentUpdateChannel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set ROsVerAvail [ :tostr (\$Update->\"latest-version\") ];\r\ + \n\r\ + \n :set (\$DeviceInfo->\"board-name\") \$devBoardName;\r\ + \n :set (\$DeviceInfo->\"architecture-name\") \$devCurArch;\r\ + \n :set (\$DeviceInfo->\"model\") \$devModel;\r\ + \n :set (\$DeviceInfo->\"revision\") \$devRbRevision;\r\ + \n :set (\$DeviceInfo->\"serial-number\") \$devRbSerialNumber;\r\ + \n :set (\$DeviceInfo->\"running-mode\") \$devRunning;\r\ + \n :set (\$DeviceInfo->\"build-time\") \$devBuildTime;\r\ + \n :set (\$DeviceInfo->\"running-channel-version\") \$runningChannelVers\ + ion;\r\ + \n :set (\$DeviceInfo->\"running-version\") \$runningVersion;\r\ + \n :set (\$DeviceInfo->\"running-channel\") \$runningChannel;\r\ + \n :set (\$DeviceInfo->\"routerboard\") \$IsRouterBoard;\r\ + \n :set (\$DeviceInfo->\"current-firmware\") [ :tostr (\$RouterBoard->\"\ + current-firmware\") ];\r\ + \n :set (\$DeviceInfo->\"upgrade-firmware\") [ :tostr (\$RouterBoard->\"\ + upgrade-firmware\") ];\r\ + \n :set (\$DeviceInfo->\"package-channel\") \$currentUpdateChannel;\r\ + \n :set (\$DeviceInfo->\"installed-version\") [ :tostr (\$Update->\"inst\ + alled-version\") ];\r\ + \n :set (\$DeviceInfo->\"latest-version\") \$ROsVerAvail;\r\ + \n :set (\$DeviceInfo->\"update-status\") [ :tostr (\$Update->\"status\"\ + ) ];\r\ + \n\r\ + \n :set arrDeviceInfo \$DeviceInfo;\r\ + \n :return \$DeviceInfo;\r\ + \n}\r\ + \n\r\ + \n:set DeviceInfo do={\r\ + \n :global GetArrDeviceInfo;\r\ + \n :global GlobalConfVersion;\r\ + \n :global Identity;\r\ + \n :global IfThenElse;\r\ + \n :global FormatLine;\r\ + \n :global CommitBrief;\r\ + \n\r\ + \n :local License [/system/license/get];\r\ + \n :local Snmp [ /snmp/get ];\r\ + \n :local Info [ \$GetArrDeviceInfo ];\r\ + \n\r\ + \n :if ([ :typeof \$Info ] != \"array\") do={\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :return ( \\\r\ + \n [ \$FormatLine \"Hostname\" \$Identity ] . \"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$Snmp->\"location\") ] > 0) \\\r\ + \n ([ \$FormatLine \"Location\" (\$Snmp->\"location\") ] . \"\\n\") ]\ + \_. \\\r\ + \n [ \$IfThenElse ([ :len (\$Snmp->\"contact\") ] > 0) \\\r\ + \n ([ \$FormatLine \"Contact\" (\$Snmp->\"contact\") ] . \"\\n\") ] .\ + \_\\\r\ + \n \"Hardware:\\n\" . \\\r\ + \n [ \$FormatLine \" Board\" (\$Info->\"board-name\") ] . \"\\n\" . \ + \\\r\ + \n [ \$FormatLine \" Arch\" (\$Info->\"architecture-name\") ] . \"\\\ + n\" . \\\r\ + \n [ \$FormatLine \" Model\" (\$Info->\"model\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"revision\") ] > 0) \\\r\ + \n (\" \" . (\$Info->\"revision\")) ] . \"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"serial-number\") ] > 0) \\\r\ + \n ([ \$FormatLine \" Serial\" (\$Info->\"serial-number\") ] . \"\ + \\n\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$License->\"nlevel\") ] > 0) \\\r\ + \n ([ \$FormatLine \" License\" (\"level \" . (\$License->\"nlevel\ + \")) ] . \"\\n\") ] . \\\r\ + \n \"RouterOS:\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$License->\"level\") ] > 0) \\\r\ + \n ([ \$FormatLine \" License\" (\"level \" . (\$License->\"level\ + \")) ] . \"\\n\") ] . \\\r\ + \n [ \$FormatLine \" Channel\" (\$Info->\"package-channel\") ] . \"\ + \\n\" . \\\r\ + \n [ \$FormatLine \" Installed\" (\$Info->\"installed-version\") ] .\ + \_\"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"running-channel\") ] > 0) \\\r\ + \n ([ \$FormatLine \" Running\" ((\$Info->\"running-version\") . \ + \" (\" . (\$Info->\"running-channel\") . \")\") ] . \"\\n\") \\\r\ + \n ([ \$FormatLine \" Running\" (\$Info->\"running-version\") ] . \ + \"\\n\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"latest-version\") ] > 0 && \\\r\ + \n (\$Info->\"installed-version\") != (\$Info->\"latest-version\"))\ + \_\\\r\ + \n ([ \$FormatLine \" Available\" (\$Info->\"latest-version\") ] .\ + \_\"\\n\") ] . \\\r\ + \n [ \$IfThenElse ((\$Info->\"routerboard\") = true && \\\r\ + \n (\$Info->\"current-firmware\") != (\$Info->\"upgrade-firmware\")\ + ) \\\r\ + \n ([ \$FormatLine \" Firmware\" ((\$Info->\"current-firmware\") .\ + \_\" -> \" . (\$Info->\"upgrade-firmware\")) ] . \"\\n\") ] . \\\r\ + \n \"RouterOS-Scripts:\\n\" . \\\r\ + \n [ \$FormatLine \" Commit\" [ \$CommitBrief ] ] . \"\\n\" . \\\r\ + \n [ \$FormatLine \" Version\" \$GlobalConfVersion ]);\r\ + \n}\r\ + \n\r\ + \n:if ([ :typeof \$NotificationFunctions ] != \"array\") do={:set Notifica\ + tionFunctions ({})}\r\ + \n\r\ + \n:set GetRandom20CharAlNum do={\r\ + \n :global EitherOr;\r\ + \n :return [ :rndstr length=[ \$EitherOr [ :tonum \$1 ] 20 ] from=\"ABCDE\ + FGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\" ];\r\ + \n}\r\ + \n\r\ + \n:set GetRandom20CharHex do={:global EitherOr; :return [ :rndstr length=[\ + \_\$EitherOr [ :tonum \$1 ] 20 ] from=\"0123456789abcdef\" ]; }\r\ + \n:set GetRandomNumber do={:global EitherOr; :return [ :rndnum from=0 to=[\ + \_\$EitherOr [ :tonum \$1 ] 4294967295 ] ]; }\r\ + \n\r\ + \n:global checkRunJob;\r\ + \n:set checkRunJob do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :global ScriptLock; \r\ + \n :if ([ \$ScriptLock \$Script ] = false) do={:return false}\r\ + \n :foreach Job in=[ /system/script/job/find where script=\$Script ] do={\ + :set Job [ /system/script/job/get \$Job ];\r\ + \n :while ([ :typeof (\$Job->\"parent\") ] = \"id\") do={:set Job [ /sy\ + stem/script/job/get [ find where .id=(\$Job->\"parent\") ] ]}\r\ + \n :if ((\$Job->\"type\") = \"login\") do={:return true};}; :return fa\ + lse; \r\ + \n}\r\ + \n\r\ + \n:set InspectVar do={\r\ + \n :global InspectVarRet;\r\ + \n :put [ :tocrlf [ \$InspectVarRet \$1 ] ];\r\ + \n}\r\ + \n\r\ + \n:set CommitBrief do={\r\ + \n :global CommitId;\r\ + \n :global CommitInfo;\r\ + \n :if (\$CommitId = \"unknown\") do={\r\ + \n :return \"unknown\";\r\ + \n }\r\ + \n :return (\$CommitInfo . \"/\" . [ :pick \$CommitId 0 8 ]);\r\ + \n}\r\ + \n\r\ + \n:set InspectVarRet do={\r\ + \n :local Input \$1;\r\ + \n :local Level (0 + [ :tonum \$2 ]);\r\ + \n :global CharacterReplace;\r\ + \n :global IfThenElse;\r\ + \n :global InspectVarRet;\r\ + \n :local IndentReturn do={\r\ + \n :local Prefix [ :tostr \$1 ];\r\ + \n :local Value [ :tostr \$2 ];\r\ + \n :local Level [ :tonum \$3 ];\r\ + \n :global CharacterMultiply;\r\ + \n :return ([ \$CharacterMultiply \" \" (\$Level * 2) ] . \"-\" . \$Pre\ + fix . \"-> \" . \$Value);\r\ + \n }\r\ + \n :local TypeOf [ :typeof \$Input ];\r\ + \n :local Len [ :len \$Input ];\r\ + \n :local Return [ \$IndentReturn \"type\" \$TypeOf \$Level ];\r\ + \n :if (\$TypeOf = \"array\") do={\r\ + \n :foreach Key,Value in=\$Input do={\r\ + \n :set \$Return (\$Return . \"\\n\" . \\\r\ + \n [ \$IndentReturn \"key\" \$Key (\$Level + 1) ] . \"\\n\" . \\\r\ + \n [ \$InspectVarRet \$Value (\$Level + 2) ]);\r\ + \n }\r\ + \n } else={\r\ + \n :if (\$TypeOf = \"str\") do={\r\ + \n :set \$Return (\$Return . \"\\n\" . \\\r\ + \n [ \$IndentReturn \"len\" \$Len \$Level ]);\r\ + \n :if ([ :typeof [ :find \$Input (\"\\r\") ] ] = \"num\") do={\r\ + \n :set Input [ \$CharacterReplace \$Input (\"\\r\") \"\" ];\r\ + \n }\r\ + \n :if ([ :typeof [ :find \$Input (\"\\n\") ] ] = \"num\") do={\r\ + \n :set Input [ \$CharacterReplace \$Input (\"\\n\") \" \" ];\r\ + \n }\r\ + \n }\r\ + \n :if (\$TypeOf != \"nothing\") do={\r\ + \n :set \$Return (\$Return . \"\\n\" . \\\r\ + \n [ \$IndentReturn \"value\" [ \$IfThenElse ([ :len \$Input ] > 80)\ + \_\\\r\ + \n ([ :pick \$Input 0 77 ] . \"...\") \$Input ] \$Level ]);\r\ + \n }\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set GetPubIp do={\r\ + \n :global DetectIpAddrDefault;\r\ + \n :global DetectIpAddrFallback;\r\ + \n\r\ + \n :local PubIpAddr false;\r\ + \n :local Url \$DetectIpAddrDefault;\r\ + \n :local JobName [ :jobname ];\r\ + \n\r\ + \n :do {\r\ + \n :log debug (\$0 . \" Trying to detect public IP using default serv\ + ice: \" . \$Url . \"...\");\r\ + \n :retry command={:set PubIpAddr ([ /tool/fetch http-method=\"get\"\ + \_check-certificate=yes-without-crl \$Url output=user as-value ]->\"data\"\ + )} \\\r\ + \n delay=50ms max=5 on-error={:log error (\$JobName . \" Failed to \ + detect public IP using default service: \" . \$Url . \".\")}\r\ + \n } on-error={\r\ + \n :log error (\$0 . \" Failed to detect public IP using default serv\ + ice: \" . \$Url . \".\");\r\ + \n :set Url \$DetectIpAddrFallBack;\r\ + \n :log debug (\$0 . \" Trying to detect public IP using fallback ser\ + vice: \" . \$Url . \"...\");\r\ + \n :retry command={:set PubIpAddr ([ /tool/fetch http-method=\"get\"\ + \_check-certificate=yes-without-crl \$Url output=user as-value ]->\"data\"\ + )} \\\r\ + \n delay=200ms max=5 on-error={:log error (\$JobName . \" Failed to\ + \_detect public IP using fallback service: \" . \$Url . \".\")}\r\ + \n };\r\ + \n :local IpLen ([ :len \$PubIpAddr ] -1);\r\ + \n :if (\$PubIpAddr = false) do={:set PubIpAddr \"not-detected\"} else=\ + {:set PubIpAddr [:pick \$PubIpAddr 0 \$IpLen]}\r\ + \n :return \$PubIpAddr;\r\ + \n}\r\ + \n\r\ + \n:set FormatLine do={\r\ + \n :local Key [ :tostr \$1 ];\r\ + \n :local Value [ :tostr \$2 ];\r\ + \n :local Indent [ :tonum \$3 ];\r\ + \n :local Spaces;\r\ + \n :local Return \"\";\r\ + \n :global CharacterMultiply;\r\ + \n :global EitherOr;\r\ + \n :set Indent [ \$EitherOr \$Indent 16 ];\r\ + \n :local Spaces [ \$CharacterMultiply \" \" \$Indent ];\r\ + \n :if ([ :len \$Key ] > 0) do={ :set Return (\$Key . \":\")}\r\ + \n :if ([ :len \$Key ] > (\$Indent - 2)) do={:set Return (\$Return . \"\\\ + n\" . [ :pick \$Spaces 0 \$Indent ] . \$Value);\r\ + \n } else={:set Return (\$Return . [ :pick \$Spaces 0 (\$Indent - [ :len \ + \$Return ]) ] . \$Value)}\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set ParseCustom do={\r\ + \n :local Str [ :tostr \$1 ];\r\ + \n :local Start [:find [ \$Str ] [:tostr \$2]];\r\ + \n :local End [ :tostr \$3 ];\r\ + \n :local Num [ :tonum \$4 ];\r\ + \n :local Return;\r\ + \n :if ([:len \$Num] = 0) do={:set Num \"0\"}\r\ + \n :local rest [:pick \$Str (\$Start+\$Num) [:len \$Str]]; \r\ + \n :if ([:len \$End ] = 0) do={:set Return [:pick \$Str \$Num \$Start]} e\ + lse={\r\ + \n :set End [:find \$rest \$End];\r\ + \n :set Return [:pick \$rest 0 \$End];\r\ + \n }\r\ + \n:return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set LogPrint do={\r\ + \n :local Severity [ :tostr \$1 ];\r\ + \n :local Name [ :tostr \$2 ];\r\ + \n :local Message [ :tostr \$3 ];\r\ + \n :global PrintDebug;\r\ + \n :global PrintDebugOverride;\r\ + \n :global EitherOr;\r\ + \n :local Debug [ \$EitherOr (\$PrintDebugOverride->\$Name) \$PrintDebug \ + ];\r\ + \n :local PrintSeverity do={\r\ + \n :global TerminalColorOutput;\r\ + \n :if (\$TerminalColorOutput != true) do={:return \$1}\r\ + \n :local Color { debug=96; info=97; warning=93; error=91 };\r\ + \n :return (\"\\1B[\" . \$Color->\$1 . \"m\" . \$1 . \"\\1B[0m\");\r\ + \n}\r\ + \n :local Log ([ \$EitherOr \$Name \"\" ] . \": \" . \$Message);\ + \r\ + \n :if (\$Severity ~ (\"^(custom|debug|error|info)\\\$\")) do={\r\ + \n :if (\$Severity = \"debug\") do={:log debug \$Log}\r\ + \n :if (\$Severity = \"error\") do={:log error \$Log}\r\ + \n :if (\$Severity = \"info\" ) do={:log info \$Log}\r\ + \n } else={:log warning \$Log; :set Severity \"warning\"}\r\ + \n :if (\$Severity != \"debug\" || \$Debug = true) do={:put ([ \$PrintSev\ + erity \$Severity ] . \": \" . \$Message)}\r\ + \n}\r\ + \n\r\ + \n:set CertificateAvailable do={\r\ + \n :local CommonName [ :tostr \$1 ];\r\ + \n :local UseFor [ :tostr \$2 ];\r\ + \n\r\ + \n :global CertificateDownload;\r\ + \n :global ParseKeyValueStore;\r\ + \n\r\ + \n :if ([ :len \$UseFor ] = 0) do={\r\ + \n :log warning (\$0 . \"The intended use is undefined!\");\r\ + \n :set UseFor \"undefined\";\r\ + \n }\r\ + \n :if ([ /system/resource/get free-hdd-space ] < 8388608 && \\\r\ + \n [ /certificate/settings/get crl-download ] = true && \\\r\ + \n [ /certificate/settings/get crl-store ] = \"system\") do={\r\ + \n :log warning (\$0 . \"This system has low free flash space but \" . \ + \\\r\ + \n \"is configured to download certificate CRLs to system!\");\r\ + \n }\r\ + \n :if ([ :len \$CommonName ] = 0) do={\r\ + \n :log warning (\$0 . \"No CommonName given!\");\r\ + \n :return false;\r\ + \n }\r\ + \n :local CertSettings [ /certificate/settings/get ];\r\ + \n :if (((\$CertSettings->\"builtin-trust-anchors\") = \"trusted\" || \\\ + \r\ + \n (\$CertSettings->\"builtin-trust-store\") ~ \$UseFor || \\\r\ + \n (\$CertSettings->\"builtin-trust-store\") = \"all\") && \\\r\ + \n [ :len [ /certificate/builtin/find where common-name=\$CommonName\ + \_] ] > 0) do={\r\ + \n :return true;\r\ + \n }\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] = 0\ + ) do={\r\ + \n :log info (\$0 . \"Certificate with CommonName '\" . \$CommonName . \ + \"' not available.\");\r\ + \n :if ([ \$CertificateDownload \$CommonName ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] > 1\ + ) do={\r\ + \n :log info (\$0 . \"There are \" . \$CertCount . \" Certificates with\ + \_CommonName '\" . \$CommonName . \"'. Should be ok.\");\r\ + \n :return true;\r\ + \n }\r\ + \n :local CertVal [ /certificate/get [ find where common-name=\$CommonNam\ + e ] ];\r\ + \n :while ((\$CertVal->\"akid\") != \"\" && (\$CertVal->\"akid\") != (\$C\ + ertVal->\"skid\")) do={\r\ + \n :if ([ :len [ /certificate/find where skid=(\$CertVal->\"akid\") ] ]\ + \_= 0) do={\r\ + \n :local IssuerCN ([ \$ParseKeyValueStore (\$CertVal->\"issuer\") ]-\ + >\"CN\");\r\ + \n :log info (\$0 . \"Certificate chain for '\" . \$CommonName . \"' \ + is incomplete, missing '\" . \$IssuerCN . \"'.\");\r\ + \n :if ([ \$CertificateDownload \$IssuerCN ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n :set CertVal [ /certificate/get [ find where skid=(\$CertVal->\"akid\ + \") ] ];\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set CertificateDownload do={\r\ + \n :local CommonName [ :tostr \$1 ];\r\ + \n :global ScriptUpdatesBaseUrl;\r\ + \n :global ScriptUpdatesUrlSuffix;\r\ + \n :global CertificateNameByCN;\r\ + \n :global CleanName;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global RmFile;\r\ + \n :global WaitForFile;\r\ + \n\r\ + \n :log info (\$0 . \"Downloading and importing certificate with \" . \\\ + \r\ + \n \"CommonName '\" . \$CommonName . \"'.\");\r\ + \n :local FileName ([ \$CleanName \$CommonName ] . \".pem\");\r\ + \n :do {\r\ + \n /tool/fetch check-certificate=yes-without-crl mode=https http-header\ + -field=({ [ \$FetchUserAgentStr \$0 ] }) \\\r\ + \n (\$ScriptUpdatesBaseUrl . \"certs/\" . \$FileName . \$ScriptUpdate\ + sUrlSuffix) \\\r\ + \n dst-path=\$FileName as-value;\r\ + \n \$WaitForFile \$FileName;\r\ + \n } on-error={\r\ + \n :log warning (\$0 . \" Failed downloading certificate with CommonNam\ + e '\" . \$CommonName . \\\r\ + \n \"' from repository! Trying fallback to mkcert.org...\");\r\ + \n :do {\r\ + \n :local CertSettings [ /certificate/settings/get ];\r\ + \n :if ([ :len [ /certificate/find where common-name=\"ISRG Root X1\"\ + \_] ] = 0 && \\\r\ + \n !(((\$CertSettings->\"builtin-trust-anchors\") = \"trusted\" \ + || \\\r\ + \n (\$CertSettings->\"builtin-trust-store\") ~ \"fetch\" || \ + \\\r\ + \n (\$CertSettings->\"builtin-trust-store\") = \"all\") && \\\ + \r\ + \n [ :len [ /certificate/builtin/find where common-name=\"ISRG\ + \_Root X1\" ] ] > 0)) do={\r\ + \n :log error (\$0 . \" Required certificate is not available.\");\ + \r\ + \n :return false;\r\ + \n }\r\ + \n /tool/fetch check-certificate=yes-without-crl mode=https http-head\ + er-field=({ [ \$FetchUserAgentStr \$0 ] }) \\\r\ + \n url=\"https://mkcert.org/generate/\" http-data=[ :serialize to=jso\ + n ({ \$CommonName }) ] \\\r\ + \n dst-path=\$FileName as-value;\r\ + \n \$WaitForFile \$FileName;\r\ + \n :if ([ /file/get \$FileName size ] = 0) do={\r\ + \n \$RmFile \$FileName;\r\ + \n :error false;\r\ + \n }\r\ + \n } on-error={\r\ + \n :log error (\$0 . \" Failed downloading certificate with CommonNam\ + e '\" . \$CommonName . \"'!\");\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n /certificate/import file-name=\$FileName passphrase=\"\" as-value;\r\ + \n :delay 1s;\r\ + \n \$RmFile \$FileName;\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] = 0\ + ) do={\r\ + \n /certificate/remove [ find where name~(\"^\" . \$FileName . \"_[0-9]\ + +\\\$\") ];\r\ + \n :log warning (\$0 . \" Certificate with CommonName '\" . \$CommonNam\ + e . \"' still unavailable!\");\r\ + \n :return false;\r\ + \n }\r\ + \n :foreach Cert in=[ /certificate/find where name~(\"^\" . \$FileName . \ + \"_[0-9]+\\\$\") ] do={\r\ + \n \$CertificateNameByCN [ /certificate/get \$Cert common-name ];\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set CertificateNameByCN do={\r\ + \n :local Match [ :tostr \$1 ];\r\ + \n :global CleanName;\r\ + \n :local Cert ([ /certificate/find where (common-name=\$Match or fingerp\ + rint=\$Match or name=\$Match) ]->0);\r\ + \n :if ([ :len \$Cert ] = 0) do={\r\ + \n :log warning (\$0 .\" No matching certificate found.\");\r\ + \n :return false;\r\ + \n }\r\ + \n :local CommonName [ /certificate/get \$Cert common-name ];\r\ + \n /certificate/set \$Cert name=[ \$CleanName \$CommonName ];\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set CharacterMultiply do={\r\ + \n :local Str [ :tostr \$1 ];\r\ + \n :local Num [ :tonum \$2 ];\r\ + \n :if (\$Num = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :for I from=1 to=\$Num do={:set Return (\$Return . \$Str)}\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set FileExists do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :local Type [ :tostr \$2 ];\r\ + \n :global FileGet;\r\ + \n :local FileVal [ \$FileGet \$FileName ];\r\ + \n :if (\$FileVal = false) do={ :return false; }\r\ + \n :if ([ :len (\$FileVal->\"size\") ] = 0) do={ :return false; }\r\ + \n :if ([ :len \$Type ] = 0 || \$FileVal->\"type\" = \$Type) do={ :return\ + \_true; }\r\ + \n :return false;\r\ + \n}\r\ + \n\r\ + \n:set Grep do={\r\ + \n :local Input ([ :tostr \$1 ] . \"\\n\");\r\ + \n :local Pattern [ :tostr \$2 ];\r\ + \n :if ([ :typeof [ :find \$Input \$Pattern ] ] = \"nil\") do={:return []\ + }\r\ + \n :do {\r\ + \n :local Line [ :pick \$Input 0 [ :find \$Input \"\\n\" ] ];\r\ + \n :if ([ :typeof [ :find \$Line \$Pattern ] ] = \"num\") do={:return \ + \$Line}\r\ + \n :set Input [ :pick \$Input ([ :find \$Input \"\\n\" ] + 1) [ :len \$\ + Input ] ];\r\ + \n } while=([ :len \$Input ] > 0);\r\ + \n :return [];\r\ + \n}\r\ + \n\r\ + \n:set HumanReadableNum do={\r\ + \n :local Input [ :tonum \$1 ];\r\ + \n :local Base [ :tonum \$2 ];\r\ + \n :global EitherOr;\r\ + \n :global IfThenElse;\r\ + \n :local Prefix \"kMGTPE\";\r\ + \n :local Pow 1;\r\ + \n :set Base [ \$EitherOr \$Base 1024 ];\r\ + \n :local Bin [ \$IfThenElse (\$Base = 1024) \"i\" \"\" ];\r\ + \n :if (\$Input < \$Base) do={:return \$Input}\r\ + \n :for I from=0 to=[ :len \$Prefix ] do={\r\ + \n :set Pow (\$Pow * \$Base);\r\ + \n :if (\$Input / \$Base < \$Pow) do={\r\ + \n :set Prefix [ :pick \$Prefix \$I ];\r\ + \n :local Tmp1 (\$Input * 100 / \$Pow);\r\ + \n :local Tmp2 (\$Tmp1 / 100);\r\ + \n :if (\$Tmp2 >= 100) do={:return (\$Tmp2 . \$Prefix . \$Bin)}\r\ + \n :return (\$Tmp2 . \".\" . \\\r\ + \n [ :pick \$Tmp1 [ :len \$Tmp2 ] ([ :len \$Tmp1 ] - [ :len \$Tmp\ + 2 ] + 1) ] . \\\r\ + \n \$Prefix . \$Bin);\r\ + \n }\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set CleanFilePath do={\r\ + \n :local Path [ :tostr \$1 ];\r\ + \n :global CharacterReplace;\r\ + \n :while (\$Path ~ \"//\") do={ :set \$Path [ \$CharacterReplace \$Path \ + \"//\" \"/\" ]; }\r\ + \n :if ([ :pick \$Path 0 ] = \"/\") do={ :set Path [ :pick \$Path 1 [ :le\ + n \$Path ] ]; }\r\ + \n :if ([ :pick \$Path ([ :len \$Path ] - 1) ] = \"/\") do={ :set Path [ \ + :pick \$Path 0 ([ :len \$Path ] - 1) ]; }\r\ + \n :return \$Path;\r\ + \n}\r\ + \n\r\ + \n:set CleanName do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :local Return \"\";\r\ + \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ + \n :local Char [ :pick \$Input \$I ];\r\ + \n :if ([ :typeof [ find \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr\ + stuvwxyz0123456789\" \$Char ] ] = \"nil\") do={\r\ + \n :do {:if ([ :len \$Return ] = 0) do={:error true};\r\ + \n :if ([ :pick \$Return ([ :len \$Return ] - 1) ] = \"-\") do={:er\ + ror true}; :set Char \"-\"} on-error={:set Char \"\"}; \r\ + \n };\r\ + \n :set Return (\$Return . \$Char)};\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set RandomDelay do={\r\ + \n :local Time [ :tonum \$1 ];\r\ + \n :local Unit [ :tostr \$2 ];\r\ + \n :global EitherOr;\r\ + \n :global GetRandomNumber;\r\ + \n :global MAX;\r\ + \n :if (\$Time = 0) do={:return false}\r\ + \n :delay ([ \$MAX 10 [ \$GetRandomNumber ([ :tonsec [ :totime (\$Time . \ + [ \$EitherOr \$Unit \"s\" ]) ] ] / 1000000) ] ] . \"ms\");\r\ + \n}\r\ + \n\r\ + \n:set EscapeForRegEx do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :if ([ :len \$Input ] = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :local Chars (\"^.[]\\\$()|*+\?{}\\\\\");\r\ + \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ + \n :local Char [ :pick \$Input \$I ];\r\ + \n :if ([ :find \$Chars \$Char ]) do={:set Char (\"\\\\\" . \$Char)}\r\ + \n :set Return (\$Return . \$Char);\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set ExitError do={\r\ + \n :local ExitOK [ :tostr \$1 ];\r\ + \n :local Name [ :tostr \$2 ];\r\ + \n :local Error [ :tostr \$3 ];\r\ + \n :global IfThenElse;\r\ + \n :if (\$ExitOK = \"false\") do={\r\ + \n :log error (\$Name [ \$IfThenElse ([ :pick \$Name 0 1 ] = \"\\\$\") \ + \\\r\ + \n \"Function\" \"Script\" ] . \" '\" . \$Name . \"' exited with er\ + ror\" . \\\r\ + \n [ \$IfThenElse (!(\$Error ~ \"^(|true|false)\\\$\")) (\": \" . \ + \$Error) \".\" ]);\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set ExitOnError do={\r\ + \n :local Name [ :tostr \$1 ];\r\ + \n :local Error [ :tostr \$2 ];\r\ + \n :global IfThenElse;\r\ + \n :log error (\$Name . \" \" . [ \$IfThenElse ([ :pick \$Name 0 1 ] = \"\ + \\\$\") \\\r\ + \n \"Function\" \"Script\" ] . \" '\" . \$Name . \"' exited with erro\ + r\" . \\\r\ + \n [ \$IfThenElse (!(\$Error ~ \"^(|true|false)\\\$\")) (\": \" . \$E\ + rror) \".\" ]);\r\ + \n}\r\ + \n\r\ + \n:set MiniDateTimeStamp do={\r\ + \n :local mikro [ :tobool \$1 ];\r\ + \n /system/clock;\r\ + \n :local vdate [get date];\r\ + \n :local vtime [get time];\r\ + \n :local vdoff [:toarray \"0,4,5,7,8,10\"];\r\ + \n :local MM [:pick \$vdate (\$vdoff->2) (\$vdoff->3)];\r\ + \n :local M [:tonum \$MM];\r\ + \n :if (\$vdate ~ \".../../....\") do={\r\ + \n :set vdoff [:toarray \"7,11,1,3,4,6\"];\r\ + \n :set M ([:find \"xxanebarprayunulugepctovecANEBARPRAYUNULUGE\ + PCTOVEC\" [:pick \$vdate (\$vdoff->2) (\$vdoff->3)] -1] / 2);\r\ + \n :if (\$M>12) do={:set M (\$M - 12)}\r\ + \n :set MM [:pick (100 + \$M) 1 3];\r\ + \n }\r\ + \n :local yyyy [:pick \$vdate (\$vdoff->0) (\$vdoff->1)];\r\ + \n :local dd [:pick \$vdate (\$vdoff->4) (\$vdoff->5)];\r\ + \n :local HH [:pick \$vtime 0 2];\r\ + \n :local mm [:pick \$vtime 3 5];\r\ + \n :local ss [:pick \$vtime 6 8];\r\ + \n :local Return;\r\ + \n :if (\$mikro = true) do={\r\ + \n :set Return ([:pick \$yyyy 2 4] . [:pick \$dd 0 1] . [:pick \$HH 0\ + \_1] . [:pick \$mm 3 4] . [:pick \$ss 6 7]);\r\ + \n } else={\r\ + \n :set Return ([\$yyyy] . [\$MM] . [\$dd] . [\$HH] . [\$mm] . [\$ss]);\ + \r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set WaitForFile do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :local WaitTime [ :totime \$2 ];\r\ + \n :global CleanFilePath;\r\ + \n :global EitherOr;\r\ + \n :global MAX;\r\ + \n :set FileName [ \$CleanFilePath \$FileName ];\r\ + \n :local Delay ([ \$MAX [ \$EitherOr \$WaitTime 2s ] 100ms ] / 9);\r\ + \n :do {\r\ + \n :retry {\r\ + \n /file/get \$FileName;\r\ + \n :return true;\r\ + \n } delay=\$Delay max=10;\r\ + \n } on-error={ }\r\ + \n :while ([ :len [ /file/find where name=\$FileName ] ] > 0) do={\r\ + \n :do {\r\ + \n /file/get \$FileName;\r\ + \n :return true;\r\ + \n } on-error={ }\r\ + \n :delay \$Delay;\r\ + \n :set Delay (\$Delay * 3 / 2);\r\ + \n }\r\ + \n :return false;\r\ + \n}\r\ + \n\r\ + \n:set FileGet do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :global WaitForFile;\r\ + \n :if ([ \$WaitForFile \$FileName 0s ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n :local FileVal false;\r\ + \n :do {\r\ + \n :set FileVal [ /file/get \$FileName ];\r\ + \n } on-error={ }\r\ + \n :return \$FileVal;\r\ + \n}\r\ + \n\r\ + \n:set RmDir do={\r\ + \n :local DirName [ :tostr \$1 ];\r\ + \n :global FileGet;\r\ + \n :log debug (\$0 . \" Removing directory: \". \$DirName);\r\ + \n :local DirVal [ \$FileGet \$DirName ];\r\ + \n :if (\$DirVal = false) do={\r\ + \n :log debug (\$0 . \" ... which does not exist.\");\r\ + \n :return true;\r\ + \n };\r\ + \n :if (\$DirVal->\"type\" != \"directory\") do={\r\ + \n :log error (\$0 . \" Directory '\" . \$DirName . \"' is not a direct\ + ory.\");\r\ + \n :return false;\r\ + \n };\r\ + \n :onerror Err {\r\ + \n /file/remove \$DirName;\r\ + \n } do={\r\ + \n :log error (\$0 . \" Removing directory '\" . \$DirName . \"' failed\ + : \" . \$Err);\r\ + \n :return false;\r\ + \n };\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set RmFile do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :global FileGet;\r\ + \n :log debug (\$0 . \" Removing file: \". \$FileName);\r\ + \n :local FileVal [ \$FileGet \$FileName ];\r\ + \n :if (\$FileVal = false) do={\r\ + \n :log debug (\$0 . \" ... which does not exist.\");\r\ + \n :return true;\r\ + \n }\r\ + \n :if (\$FileVal->\"type\" = \"directory\" || \$FileVal->\"type\" = \"di\ + sk\") do={\r\ + \n :log error (\$0 . \" File '\" . \$FileName . \"' is not a file.\");\ + \r\ + \n :return false;\r\ + \n }\r\ + \n :onerror Err {\r\ + \n /file/remove \$FileName;\r\ + \n } do={\r\ + \n :log error (\$0 . \" Removing file '\" . \$FileName . \"' failed: \"\ + \_. \$Err); :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set MkDir do={\r\ + \n :local Path [ :tostr \$1 ];\r\ + \n :global CleanFilePath;\r\ + \n :global FileGet;\r\ + \n :global RmDir;\r\ + \n :global WaitForFile;\r\ + \n\r\ + \n :local MkTmpfs do={\r\ + \n :global WaitForFile;\r\ + \n :local TmpFs [ /disk/find where slot=tmpfs type=tmpfs ];\r\ + \n :if ([ :len \$TmpFs ] = 1) do={\r\ + \n :if ([ /disk/get \$TmpFs disabled ] = true) do={\r\ + \n :log info (\$0 . \" The tmpfs is disabled, enabling.\");\r\ + \n /disk/enable \$TmpFs;\r\ + \n }\r\ + \n :return true;\r\ + \n }\r\ + \n :log info (\$0 . \" Creating disk of type tmpfs.\");\r\ + \n \$RmDir \"tmpfs\";\r\ + \n :onerror Err {\r\ + \n /disk/add slot=tmpfs type=tmpfs tmpfs-max-size=([ /system/resource\ + /get total-memory ] / 3);\r\ + \n \$WaitForFile \"tmpfs\";\r\ + \n } do={\r\ + \n :log warning (\$0 . \" Creating disk of type tmpfs failed: \" . \$\ + Err);\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n }\r\ + \n :set Path [ \$CleanFilePath \$Path ];\r\ + \n :if (\$Path = \"\") do={\r\ + \n :return true;\r\ + \n }\r\ + \n :log debug (\$0 . \" Making directory: \" . \$Path);\r\ + \n :local PathVal [ \$FileGet \$Path ];\r\ + \n :if (\$PathVal->\"type\" = \"directory\") do={\r\ + \n :log debug (\$0 . \" ... which already exists.\");\r\ + \n :return true;\r\ + \n }\r\ + \n :if ([ :pick \$Path 0 5 ] = \"tmpfs\") do={\r\ + \n :if ([ \$MkTmpfs ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n :onerror Err {\r\ + \n /file/add type=\"directory\" name=\$Path;\r\ + \n \$WaitForFile \$Path;\r\ + \n } do={\r\ + \n :log warning (\$0 . \" Making directory '\" . \$Path . \"' failed: \ + \" . \$Err);\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set MAX do={:if (\$1 > \$2) do={:return \$1}\r\ + \n :return \$2;\r\ + \n}\r\ + \n:set MIN do={:if (\$1 < \$2) do={:return \$1}\r\ + \n :return \$2;\r\ + \n}\r\ + \n\r\ + \n:set CharacterMultiply do={\r\ + \n :local Str [ :tostr \$1 ];\r\ + \n :local Num [ :tonum \$2 ];\r\ + \n :if (\$Num = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :for I from=1 to=\$Num do={:set Return (\$Return . \$Str)}\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set CharacterReplace do={\r\ + \n :local String [ :tostr \$1 ];\r\ + \n :local ReplaceFrom [ :tostr \$2 ];\r\ + \n :local ReplaceWith [ :tostr \$3 ];\r\ + \n :local Return \"\";\r\ + \n :if (\$ReplaceFrom = \"\") do={:return \$String}\r\ + \n :while ([ :typeof [ :find \$String \$ReplaceFrom ] ] != \"nil\") do={\ + \r\ + \n :local Pos [ :find \$String \$ReplaceFrom ];\r\ + \n :set Return (\$Return . [ :pick \$String 0 \$Pos ] . \$ReplaceWith);\ + \r\ + \n :set String [ :pick \$String (\$Pos + [ :len \$ReplaceFrom ]) [ :len\ + \_\$String ] ];\r\ + \n }\r\ + \n :return (\$Return . \$String);\r\ + \n}\r\ + \n\r\ + \n:set IfThenElse do={\r\ + \n :if ([ :tostr \$1 ] = \"true\" || [ :tobool \$1 ] = true) do={:return \ + \$2};\r\ + \n :return \$3;\r\ + \n}\r\ + \n\r\ + \n:set EitherOr do={\r\ + \n :global IfThenElse;\r\ + \n :if ([ :typeof \$1 ] = \"num\") do={:return [ \$IfThenElse (\$1 != 0) \ + \$1 \$2 ]}\r\ + \n :if ([ :typeof \$1 ] = \"time\") do={:return [ \$IfThenElse (\$1 > 0s)\ + \_\$1 \$2 ]}\r\ + \n# this works for boolean values, literal ones with parentheses\r\ + \n :return [ \$IfThenElse ([ :len [ :tostr \$1 ] ] > 0) \$1 \$2 ];\r\ + \n}\r\ + \n\r\ + \n:set ParseKeyValueStore do={\r\ + \n :local Source \$1;\r\ + \n :if ([ :pick \$Source 0 1 ] = \"{\") do={\r\ + \n :do {\r\ + \n :return [ :deserialize from=json \$Source ];\r\ + \n } on-error={ }\r\ + \n } \r\ + \n :if ([ :typeof \$Source ] != \"array\") do={:set Source [ :tostr \$1 ]\ + }\r\ + \n :local Result ({});\r\ + \n :foreach KeyValue in=[ :toarray \$Source ] do={\r\ + \n :if ([ :find \$KeyValue \"=\" ]) do={\r\ + \n :local Key [ :pick \$KeyValue 0 [ :find \$KeyValue \"=\" ] ];\r\ + \n :local Value [ :pick \$KeyValue ([ :find \$KeyValue \"=\" ] + 1) [\ + \_:len \$KeyValue ] ];\r\ + \n :if (\$Value=\"true\") do={:set Value true}\r\ + \n :if (\$Value=\"false\") do={:set Value false}\r\ + \n :set (\$Result->\$Key) \$Value;\r\ + \n } else={:set (\$Result->\$KeyValue) true}\r\ + \n }\r\ + \n :return \$Result;\r\ + \n}\r\ + \n:set RequiredRouterOS do={\r\ + \n :local Caller [ :tostr \$1 ];\r\ + \n :local Required [ :tostr \$2 ];\r\ + \n :local Warn [ :tostr \$3 ];\r\ + \n :global IfThenElse;\r\ + \n :global VersionToNum;\r\ + \n :if (!(\$Required ~ \"^\\\\d+\\\\.\\\\d+((alpha|beta|rc|\\\\.)\\\\d+|)\ + \\\$\")) do={\r\ + \n :log error (\$0 . \" No valid RouterOS version: \" . \$Required);\r\ + \n :return false;\r\ + \n }\r\ + \n :if ([ \$VersionToNum \$Required ] > [ \$VersionToNum [ /system/packag\ + e/update/get installed-version ] ]) do={\r\ + \n :if (\$Warn = \"true\") do={\r\ + \n :log warning (\$0 . \" This \" . [ \$IfThenElse ([ :pick \$Caller \ + 0 ] = (\"\\\$\")) \"function\" \"script\" ] . \\\r\ + \n \" '\" . \$Caller . \"' (at least specific functionality) requir\ + es RouterOS \" . \$Required . \". Please update!\");\r\ + \n }\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set ValidateSyntax do={\r\ + \n :local Code [ :tostr \$1 ];\r\ + \n :global LogPrint;\r\ + \n :onerror Err {\r\ + \n [ :parse (\":local Validate do={\\n\" . \$Code . \"\\n}\") ];\r\ + \n } do={\r\ + \n \$LogPrint debug \$0 (\"Valdation failed: \" . \$Err);\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set VersionToNum do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :local Multi 0x1000000;\r\ + \n :local Return 0;\r\ + \n :global CharacterReplace;\r\ + \n :set Input [ \$CharacterReplace \$Input \".\" \",\" ];\r\ + \n :foreach I in={ \"zero\"; \"alpha\"; \"beta\"; \"rc\" } do={\r\ + \n :set Input [ \$CharacterReplace \$Input \$I (\",\" . \$I . \",\") ];\ + \r\ + \n }\r\ + \n :foreach Value in=([ :toarray \$Input ], 0) do={\r\ + \n :local Num [ :tonum \$Value ];\r\ + \n :if (\$Multi = 0x100) do={\r\ + \n :if ([ :typeof \$Num ] = \"num\") do={\r\ + \n :set Return (\$Return + 0xff00);\r\ + \n :set Multi (\$Multi / 0x100);\r\ + \n } else={\r\ + \n :if (\$Value = \"zero\") do={ }\r\ + \n :if (\$Value = \"alpha\") do={ :set Return (\$Return + 0x3f00); \ + }\r\ + \n :if (\$Value = \"beta\") do={ :set Return (\$Return + 0x5f00); }\ + \r\ + \n :if (\$Value = \"rc\") do={ :set Return (\$Return + 0x7f00); }\r\ + \n }\r\ + \n }\r\ + \n :if ([ :typeof \$Num ] = \"num\") do={ :set Return (\$Return + (\$Va\ + lue * \$Multi)); }\r\ + \n :set Multi (\$Multi / 0x100);\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set ScriptLock do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local WaitMax [ :totime \$2 ];\r\ + \n :global GetRandom20CharAlNum;\r\ + \n :global IfThenElse;\r\ + \n :global ScriptLockOrder;\r\ + \n :if ([ :typeof \$ScriptLockOrder ] = \"nothing\") do={\r\ + \n :set ScriptLockOrder ({});\r\ + \n }\r\ + \n :if ([ :typeof (\$ScriptLockOrder->\$Script) ] = \"nothing\") do={\r\ + \n :set (\$ScriptLockOrder->\$Script) ({});\r\ + \n }\r\ + \n :local JobCount do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :return [ :len [ /system/script/job/find where script=\$Script ] ];\ + \r\ + \n }\r\ + \n :local TicketCount do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :local Count 0;\r\ + \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :if ([ :typeof \$Ticket ] != \"nothing\") do={:set Count (\$Count \ + + 1)}\r\ + \n }\r\ + \n :return \$Count;\r\ + \n }\r\ + \n :local IsFirstTicket do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local Check [ :tostr \$2 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :if (\$Ticket = \$Check) do={:return true}\r\ + \n :if ([ :typeof \$Ticket ] != \"nothing\" && \$Ticket != \$Check) d\ + o={:return false}\r\ + \n }\r\ + \n :return false;\r\ + \n }\r\ + \n :local AddTicket do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local Add [ :tostr \$2 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :while (true) do={\r\ + \n :local Pos [ :len (\$ScriptLockOrder->\$Script) ];\r\ + \n :set (\$ScriptLockOrder->\$Script->\$Pos) \$Add;\r\ + \n :delay 10ms;\r\ + \n :if ((\$ScriptLockOrder->\$Script->\$Pos) = \$Add) do={:return tru\ + e}\r\ + \n }\r\ + \n }\r\ + \n :local RemoveTicket do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local Remove [ :tostr \$2 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :foreach Id,Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :while ((\$ScriptLockOrder->\$Script->\$Id) = \$Remove) do={\r\ + \n :set (\$ScriptLockOrder->\$Script->\$Id);\r\ + \n :delay 10ms;\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n :local CleanupTickets do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :if ([ :typeof \$Ticket ] != \"nothing\") do={:return false}\r\ + \n }\r\ + \n :set (\$ScriptLockOrder->\$Script) ({});\r\ + \n }\r\ + \n :if ([ :typeof \$WaitMax ] = \"nil\" ) do={:set WaitMax 0s}\r\ + \n :if ([ :len [ /system/script/find where name=\$Script ] ] = 0) do={\r\ + \n :log error (\$0 . \" A script named '\" . \$Script . \"' does not ex\ + ist!\");\r\ + \n :error false;\r\ + \n }\r\ + \n :if ([ \$JobCount \$Script ] = 0) do={\r\ + \n \$LogPrint error \$0 (\"No script '\" . \$Script . \"' is running!\"\ + );\r\ + \n :error false;\r\ + \n }\r\ + \n :if ([ \$TicketCount \$Script ] >= [ \$JobCount \$Script ]) do={\r\ + \n :log error (\$0 . \" More tickets than running scripts '\" . \$Scrip\ + t . \"', resetting!\");\r\ + \n :set (\$ScriptLockOrder->\$Script) ({});\r\ + \n /system/script/job/remove [ find where script=\$Script ];\r\ + \n }\r\ + \n :local MyTicket [ \$GetRandom20CharAlNum 6 ];\r\ + \n \$AddTicket \$Script \$MyTicket;\r\ + \n :local WaitInterval (\$WaitMax / 20);\r\ + \n :local WaitTime \$WaitMax;\r\ + \n :while (\$WaitTime > 0 && \\\r\ + \n ([ \$IsFirstTicket \$Script \$MyTicket ] = false || \\\r\ + \n [ \$TicketCount \$Script ] < [ \$JobCount \$Script ])) do={\r\ + \n :set WaitTime (\$WaitTime - \$WaitInterval);\r\ + \n :delay \$WaitInterval;\r\ + \n }\r\ + \n :if ([ \$IsFirstTicket \$Script \$MyTicket ] = true && \\\r\ + \n [ \$TicketCount \$Script ] = [ \$JobCount \$Script ]) do={\r\ + \n \$RemoveTicket \$Script \$MyTicket;\r\ + \n \$CleanupTickets \$Script;\r\ + \n :return true;\r\ + \n }\r\ + \n \$RemoveTicket \$Script \$MyTicket;\r\ + \n \$LogPrint debug \$0 (\"Script '\" . \$Script . \"' started more than \ + once\" . \\\r\ + \n [ \$IfThenElse (\$WaitTime < \$WaitMax) \" and timed out waiting for\ + \_lock\" \"\" ] . \"...\");\r\ + \n :return false;\r\ + \n}\r\ + \n\r\ + \n:set SendNotification do={ :onerror Err {\r\ + \n :global SendNotification2;\r\ + \n \$SendNotification2 ({ origin=\$0; subject=\$1; message=\$2; link=\$3;\ + \_silent=\$4 });\r\ + \n} do={:global ExitOnError; \$ExitOnError \$0 \$Err}\r\ + \n}\r\ + \n\r\ + \n:set SendNotification2 do={\r\ + \n :local Notification \$1;\r\ + \n :global NotificationFunctions;\r\ + \n :foreach FunctionName,Discard in=\$NotificationFunctions do={\r\ + \n (\$NotificationFunctions->\$FunctionName) (\"\\\$NotificationFunctio\ + ns->\\\"\" . \$FunctionName . \"\\\"\") \$Notification;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set SymbolByUnicodeName do={\r\ + \n :local Name [ :tostr \$1 ];\r\ + \n :global EitherOr;\r\ + \n :global SymbolsExtra;\r\ + \n :local Symbols ({\r\ + \n \"abacus\"=\"\\F0\\9F\\A7\\AE\";\r\ + \n \"alarm-clock\"=\"\\E2\\8F\\B0\";\r\ + \n \"arrow-down\"=\"\\E2\\AC\\87\";\r\ + \n \"arrow-up\"=\"\\E2\\AC\\86\";\r\ + \n \"calendar\"=\"\\F0\\9F\\93\\85\";\r\ + \n \"card-file-box\"=\"\\F0\\9F\\97\\83\";\r\ + \n \"chart-decreasing\"=\"\\F0\\9F\\93\\89\";\r\ + \n \"chart-increasing\"=\"\\F0\\9F\\93\\88\";\r\ + \n \"cloud\"=\"\\E2\\98\\81\";\r\ + \n \"cross-mark\"=\"\\E2\\9D\\8C\";\r\ + \n \"earth\"=\"\\F0\\9F\\8C\\8D\";\r\ + \n \"fire\"=\"\\F0\\9F\\94\\A5\";\r\ + \n \"floppy-disk\"=\"\\F0\\9F\\92\\BE\";\r\ + \n \"gear\"=\"\\E2\\9A\\99\";\r\ + \n \"heart\"=\"\\E2\\99\\A5\";\r\ + \n \"high-voltage-sign\"=\"\\E2\\9A\\A1\";\r\ + \n \"incoming-envelope\"=\"\\F0\\9F\\93\\A8\";\r\ + \n \"information\"=\"\\E2\\84\\B9\";\r\ + \n \"large-orange-circle\"=\"\\F0\\9F\\9F\\A0\";\r\ + \n \"large-red-circle\"=\"\\F0\\9F\\94\\B4\";\r\ + \n \"link\"=\"\\F0\\9F\\94\\97\";\r\ + \n \"lock-with-ink-pen\"=\"\\F0\\9F\\94\\8F\";\r\ + \n \"memo\"=\"\\F0\\9F\\93\\9D\";\r\ + \n \"mobile-phone\"=\"\\F0\\9F\\93\\B1\";\r\ + \n \"pushpin\"=\"\\F0\\9F\\93\\8C\";\r\ + \n \"scissors\"=\"\\E2\\9C\\82\";\r\ + \n \"scroll\"=\"\\F0\\9F\\93\\9C\";\r\ + \n \"smiley-partying-face\"=\"\\F0\\9F\\A5\\B3\";\r\ + \n \"smiley-smiling-face\"=\"\\E2\\98\\BA\";\r\ + \n \"smiley-winking-face-with-tongue\"=\"\\F0\\9F\\98\\9C\";\r\ + \n \"sparkles\"=\"\\E2\\9C\\A8\";\r\ + \n \"speech-balloon\"=\"\\F0\\9F\\92\\AC\";\r\ + \n \"star\"=\"\\E2\\AD\\90\";\r\ + \n \"warning-sign\"=\"\\E2\\9A\\A0\";\r\ + \n \"white-heavy-check-mark\"=\"\\E2\\9C\\85\"\r\ + \n }, \$SymbolsExtra);\r\ + \n :local Magic [ :pick [ /system/clock/get date ] 4 10 ];\r\ + \n :local Special {\r\ + \n \"information-04-01\"=\"\\F0\\9F\\9A\\BB\";\r\ + \n \"large-orange-circle-04-01\"=\"\\F0\\9F\\8D\\8A\";\r\ + \n \"large-orange-circle-10-31\"=\"\\F0\\9F\\8E\\83\";\r\ + \n \"large-red-circle-04-01\"=\"\\F0\\9F\\8D\\92\" };\r\ + \n :if ([ :len (\$Symbols->\$Name) ] = 0) do={\r\ + \n :log warning (\$0 . \"No symbol available for name '\" . \$Name . \"\ + '!\");\r\ + \n :return \"\";\r\ + \n }\r\ + \n :return ([ \$EitherOr (\$Special->(\$Name . \$Magic)) (\$Symbols->\$Na\ + me) ] . \"\\EF\\B8\\8F\");\r\ + \n}\r\ + \n\r\ + \n:set SymbolForNotification do={\r\ + \n :global NotificationsWithSymbols;\r\ + \n :global SymbolByUnicodeName;\r\ + \n :global IfThenElse;\r\ + \n :if (\$NotificationsWithSymbols != true) do={:return [ \$IfThenElse ([\ + \_:len \$2 ] > 0) ([ :tostr \$2 ] . \" \") \"\" ]}\r\ + \n :local Return \"\";\r\ + \n :foreach Symbol in=[ :toarray \$1 ] do={:set Return (\$Return . [ \$Sy\ + mbolByUnicodeName \$Symbol ])}\r\ + \n :return (\$Return . \" \");\r\ + \n}\r\ + \n\r\ + \n:set Unix2Dos do={:return [ :tocrlf [ :tostr \$1 ] ]}\r\ + \n:set UrlEncode do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :if ([ :len \$Input ] = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :local Chars (\"\\n\\r !\\\"#\\\$%&'()*+,:;<=>\?@[\\\\]^`{|}~\");\r\ + \n :local Subs { \"%0A\"; \"%0D\"; \"%20\"; \"%21\"; \"%22\"; \"%23\"; \"\ + %24\"; \"%25\"; \"%26\"; \"%27\";\r\ + \n \"%28\"; \"%29\"; \"%2A\"; \"%2B\"; \"%2C\"; \"%3A\"; \"%3B\"; \ + \"%3C\"; \"%3D\"; \"%3E\"; \"%3F\";\r\ + \n \"%40\"; \"%5B\"; \"%5C\"; \"%5D\"; \"%5E\"; \"%60\"; \"%7B\"; \ + \"%7C\"; \"%7D\"; \"%7E\" };\r\ + \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ + \n :local Char [ :pick \$Input \$I ];\r\ + \n :local Replace [ :find \$Chars \$Char ];\r\ + \n :if ([ :typeof \$Replace ] = \"num\") do={:set Char (\$Subs->\$Repla\ + ce)}\r\ + \n :set Return (\$Return . \$Char);\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set IsDNSResolving do={\r\ + \n :do {:resolve \"api.telegram.org\"} on-error={:return false}\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set IsFullyConnected do={\r\ + \n :global IsDNSResolving;\r\ + \n :global IsTimeSync;\r\ + \n :if ([ \$IsDNSResolving ] = false) do={:return false};\r\ + \n :if ([ \$IsTimeSync ] = false) do={:return false};\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set IsTimeSync do={\r\ + \n :global IsTimeSyncCached;\r\ + \n :global IsTimeSyncResetNtp;\r\ + \n :if (\$IsTimeSyncCached = true) do={:return true}\r\ + \n :if ([ /system/ntp/client/get enabled ] = true) do={\r\ + \n :if ([ /system/ntp/client/get status ] = \"synchronized\") do={\r\ + \n :set IsTimeSyncCached true;\r\ + \n :return true;\r\ + \n }\r\ + \n :local Uptime [ /system/resource/get uptime ];\r\ + \n :if ([ :typeof \$IsTimeSyncResetNtp ] = \"nothing\") do={\r\ + \n :set IsTimeSyncResetNtp \$Uptime;\r\ + \n }\r\ + \n :if (\$Uptime - \$IsTimeSyncResetNtp < 3m) do={:return false}\r\ + \n :log warning \"\$0 The ntp client is configured, but did not sync.\"\ + ;\r\ + \n :set IsTimeSyncResetNtp \$Uptime;\r\ + \n /system/ntp/client/set enabled=no;\r\ + \n :delay 20ms;\r\ + \n /system/ntp/client/set enabled=yes;\r\ + \n :return false;\r\ + \n }\r\ + \n :if ([ /system/license/get ]->\"level\" = \"free\" || \\\r\ + \n [ /system/resource/get ]->\"board-name\" = \"x86\") do={\r\ + \n :log debug \"\$0 No ntp client configured, relying on RTC for CHR fr\ + ee license and x86.\";\r\ + \n :return true;\r\ + \n }\r\ + \n :if ([ /ip/cloud/get update-time ] = true) do={\r\ + \n :if ([ :typeof [ /ip/cloud/get public-address ] ] = \"ip\") do={\r\ + \n :set IsTimeSyncCached true;\r\ + \n :return true;\r\ + \n }\r\ + \n :return false;\r\ + \n }\r\ + \n :log debug \"\$0 No time source configured! Returning gracefully...\";\ + \r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set FetchHugeFiles do={\r\ + \n :local ScriptName [ :tostr \$1 ];\r\ + \n :local Url [ :tostr \$2 ];\r\ + \n :local CheckCert [ :tostr \$3 ];\r\ + \n\r\ + \n :global CleanName;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global GetRandom20CharAlNum;\r\ + \n :global IfThenElse;\r\ + \n :global LogPrint;\r\ + \n :global MkDir;\r\ + \n :global RmDir;\r\ + \n :global RmFile;\r\ + \n :global WaitForFile;\r\ + \n\r\ + \n :set CheckCert [ \$IfThenElse (\$CheckCert = \"false\") \"no\" \"yes-w\ + ithout-crl\" ];\r\ + \n\r\ + \n :local DirName (\"tmpfs/\" . [ \$CleanName \$ScriptName ]);\r\ + \n :if ([ \$MkDir \$DirName ] = false) do={\r\ + \n \$LogPrint error \$0 (\"Failed creating directory!\");\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :local FileName (\$DirName . \"/\" . [ \$CleanName \$0 ] . \"-\" . [ \ + \$GetRandom20CharAlNum ]);\r\ + \n :onerror Err {\r\ + \n /tool/fetch check-certificate=\$CheckCert \$Url dst-path=\$FileName \ + \\\r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$ScriptName ] }) as-va\ + lue;\r\ + \n } do={\r\ + \n :if ([ \$WaitForFile \$FileName 500ms ] = true) do={\r\ + \n \$RmFile \$FileName;\r\ + \n }\r\ + \n \$LogPrint debug \$0 (\"Failed downloading from \" . \$Url . \" - \"\ + \_. \$Err);\r\ + \n \$RmDir \$DirName;\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :if ([ \$WaitForFile \$FileName 5s ] = false) do={\r\ + \n \$LogPrint debug \$0 (\"The file downloaded from \" . \$Url . \" did\ + \_not show up.\");\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :local FileSize [ /file/get \$FileName size ];\r\ + \n :local Return \"\";\r\ + \n :local VarSize 0;\r\ + \n :while (\$VarSize != \$FileSize) do={\r\ + \n :set Return (\$Return . ([ /file/read offset=\$VarSize chunk-size=32\ + 768 file=\$FileName as-value ]->\"data\"));\r\ + \n :set FileSize [ /file/get \$FileName size ];\r\ + \n :set VarSize [ :len \$Return ];\r\ + \n :if (\$VarSize > \$FileSize) do={\r\ + \n :delay 100ms;\r\ + \n }\r\ + \n }\r\ + \n \$RmDir \$DirName;\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set FetchUserAgentStr do={\r\ + \n :local Caller [ :tostr \$1 ];\r\ + \n :global GlobalScriptsUrl;\r\ + \n :global CommitBrief;\r\ + \n :global IfThenElse;\r\ + \n :local Resource [ /system/resource/get ];\r\ + \n :return (\"User-Agent: Mikrotik/\" . \$Resource->\"version\" . \" \" .\ + \_\$Resource->\"architecture-name\" . \\\r\ + \n \" \" . \$Caller . \"/Fetch (\" . \$GlobalScriptsUrl . \"; \" . [ \$\ + CommitBrief ] . \")\");\r\ + \n}\r\ + \n\r\ + \n:set ScriptInstallUpdate do={ :onerror Err {\r\ + \n :local Scripts [ :toarray \$1 ];\r\ + \n :local NewComment [ :tostr \$2 ];\r\ + \n :global InitSetup;\r\ + \n\r\ + \n :global CommitId;\r\ + \n :global ScriptUpdatesCRLF;\r\ + \n :global GlobalConfVersion;\r\ + \n :global Identity;\r\ + \n :global CertificateAvailable;\r\ + \n :global CheckSumsVerify;\r\ + \n :global GlobalScriptsUrl;\r\ + \n :global SumsDirAndFileName;\r\ + \n :global GlobalScriptsUrlSuffix;\r\ + \n :global EitherOr;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global Grep;\r\ + \n :global IfThenElse;\r\ + \n :global LogPrint;\r\ + \n :global ParseKeyValueStore;\r\ + \n :global RequiredRouterOS;\r\ + \n :global SendNotification2;\r\ + \n :global SymbolForNotification;\r\ + \n :global ValidateSyntax;\r\ + \n :global CommentsInScripts;\r\ + \n\r\ + \n :if ([ \$CertificateAvailable \"Root YE\" \"fetch\" ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Downloading certificate failed, trying wit\ + hout.\");\r\ + \n }\r\ + \n\r\ + \n :foreach Script in=\$Scripts do={\r\ + \n :if ([ :len [ /system/script/find where name=\$Script ] ] = 0) do={\ + \r\ + \n \$LogPrint info \$0 (\"Adding new script: \" . \$Script);\r\ + \n /system/script/add name=\$Script owner=\$Script source=\"#!rsc by \ + Vados\\n\" comment=\$NewComment;\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :local CommitIdBefore \$CommitId;\r\ + \n :local GlobalConfVersionBefore \$GlobalConfVersion;\r\ + \n :local ReloadGlobal false;\r\ + \n :local DeviceMode [ /system/device-mode/get ];\r\ + \n\r\ + \n :if (\$CheckSumsVerify = true) do={\r\ + \n :local CheckSums ({});\r\ + \n :do {\r\ + \n :local Url (\$GlobalScriptsUrl . \$SumsDirAndFileName . \$GlobalScr\ + iptsUrlSuffix);\r\ + \n \$LogPrint debug \$0 (\"Fetching checksums from url: \" . \$Url);\ + \r\ + \n :set CheckSums [ :deserialize from=json ([ /tool/fetch check-certi\ + ficate=yes-without-crl \\\r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$0 ] }) \$Url output\ + =user as-value ]->\"data\") ];\r\ + \n } on-error={ \$LogPrint warning \$0 (\"Err = \" . \$Err); }\r\ + \n }\r\ + \n\r\ + \n :foreach Script in=[ /system/script/find where source~\"^#!rsc by Vado\ + s\" ] do={\r\ + \n :local ScriptVal [ /system/script/get \$Script ];\r\ + \n :local ScriptInfo [ \$ParseKeyValueStore (\$ScriptVal->\"comment\") \ + ];\r\ + \n :local SourceNew;\r\ + \n\r\ + \n :foreach Scheduler in=[ /system/scheduler/find where on-event~(\"\\\ + \\b\" . \$ScriptVal->\"name\" . \"\\\\b\") ] do={\r\ + \n :local SchedulerVal [ /system/scheduler/get \$Scheduler ];\r\ + \n :if (\$ScriptVal->\"policy\" != \$SchedulerVal->\"policy\") do={\r\ + \n \$LogPrint warning \$0 (\"Policies differ for script '\" . \$Scr\ + iptVal->\"name\" . \"' and its scheduler '\" . \$SchedulerVal->\"name\" . \ + \"'!\");\r\ + \n }\r\ + \n }\r\ + \n :do {\r\ + \n :if (\$ScriptInfo->\"ignore\" = true) do={\r\ + \n \$LogPrint debug \$0 (\"Ignoring script '\" . \$ScriptVal->\"nam\ + e\" . \"', as requested.\");\r\ + \n :error true;\r\ + \n }\r\ + \n :if (\$CheckSumsVerify = true) do={\r\ + \n :local CheckSum (\$CheckSums->(\$ScriptVal->\"name\"));\r\ + \n :if ([ :len (\$ScriptInfo->\"base-url\") ] = 0 && [ :len (\$Scri\ + ptInfo->\"url-suffix\") ] = 0 && \\\r\ + \n [ :convert transform=md5 to=hex [ :tolf (\$ScriptVal->\"sou\ + rce\") ] ] = \$CheckSum) do={\r\ + \n \$LogPrint debug \$0 (\"Checksum for script '\" . \$ScriptVal-\ + >\"name\" . \"' matches, ignoring.\");\r\ + \n :error true;\r\ + \n }\r\ + \n }\r\ + \n :if ([ :len (\$ScriptInfo->\"certificate\") ] > 0) do={\r\ + \n :if ([ \$CertificateAvailable (\$ScriptInfo->\"certificate\") \"\ + fetch\" ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Downloading certificate failed, tryi\ + ng without.\");\r\ + \n }\r\ + \n }\r\ + \n :onerror Err {\r\ + \n :local BaseUrl [ \$EitherOr (\$ScriptInfo->\"base-url\") \$Globa\ + lScriptsUrl ];\r\ + \n :local UrlSuffix [ \$EitherOr (\$ScriptInfo->\"url-suffix\") \$G\ + lobalScriptsUrlSuffix ];\r\ + \n :local Url (\$BaseUrl . \$ScriptVal->\"name\" . \".rsc\" . \$Url\ + Suffix);\r\ + \n \$LogPrint warning \$0 (\"Fetching script '\" . (\$ScriptVal->\"\ + name\") . \"' from url: \" . \$Url);\r\ + \n :local Result [ /tool/fetch check-certificate=yes-without-crl \\\ + \r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$0 ] }) \$Url outp\ + ut=user as-value ];\r\ + \n :if (\$Result->\"status\" = \"finished\") do={\r\ + \n :set SourceNew [ :tolf (\$Result->\"data\") ];\r\ + \n } \r\ + \n } do={\r\ + \n \$LogPrint warning \$0 (\"Failed fetching script '\" . \$ScriptV\ + al->\"name\" . \"': \" . \$Err);\r\ + \n :if (\$Err != \"Fetch failed with status 404\") do={\r\ + \n :error false;\r\ + \n }\r\ + \n :if (\$ScriptVal->\"source\" = \"#!rsc by Vados\") do={\r\ + \n \$LogPrint warning \$0 (\"Removing dummy. Typo on installation\ + \?\");\r\ + \n /system/script/remove \$Script;\r\ + \n :error false;\r\ + \n }\r\ + \n :if (\$CheckSumsVerify = true) do={\r\ + \n :if ([ :len (\$ScriptInfo->\"base-url\") ] = 0 && [ :len (\$Sc\ + riptInfo->\"url-suffix\") ] = 0 && \\\r\ + \n [ :len \$CheckSum ] = 0) do={\r\ + \n \$LogPrint warning \$0 (\"Added the script manually\? Skip u\ + pdates with 'ignore=true' in comment.\");\r\ + \n }\r\ + \n }\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :if ([ :len \$SourceNew ] = 0) do={\r\ + \n \$LogPrint debug \$0 (\"No update for script '\" . (\$ScriptVal-\ + >\"name\") . \"'.\");\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :local SourceCRLF [ :tocrlf \$SourceNew ];\r\ + \n :if (\$InitSetup != true && ((\$ScriptVal->\"name\") != \"AM-Globa\ + lConfig\" || (\$ScriptVal->\"name\") != \"AM-GlobalFunc\")) do={\r\ + \n :if (\$SourceNew = (\$ScriptVal->\"source\") || \$SourceCRLF = (\ + \$ScriptVal->\"source\")) do={\r\ + \n \$LogPrint debug \$0 (\"Script '\" . (\$ScriptVal->\"name\") \ + . \"' source did not change. End of lines set to CRLF.\");\r\ + \n if (\$ScriptUpdatesCRLF = false) do={\r\ + \n :put [ :tolf \$SourceNew ];\r\ + \n \$LogPrint debug \$0 (\"Script '\" . (\$ScriptVal->\"name\"\ + ) . \"' source update end of lines to LF.\");\r\ + \n }\r\ + \n :error false;\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :if ([ :pick \$SourceNew 0 14 ] != \"#!rsc by Vados\") do={\r\ + \n \$LogPrint warning \$0 (\"Looks like new script '\" . \$ScriptVa\ + l->\"name\" . \"' is not valid (missing shebang = '\$shebang') Ignoring!\"\ + );\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :if (\$CommentsInScripts = true) do={\r\ + \n :local CommentLine [ \$Grep \$SourceNew (\"\\23 Script comment:\ + \_\") ];\r\ + \n :if ([ :len \$CommentLine ] = 0) do={\r\ + \n \$LogPrint debug \$0 (\"The search in new script '\" . (\$Scr\ + iptVal->\"name\") . \"' for comment in script body, is not found result Ig\ + noring!\");\r\ + \n :error false;\r\ + \n } else={\r\ + \n :if ([ :len (\$ScriptVal->\"comment\")] = 0 || [ :len (\$Scri\ + ptVal->\"comment\")] != [ :pick \$CommentLine ([ :find \$CommentLine \":\"\ + ] + 2) [ :len \$CommentLine] ]) do={\r\ + \n \$LogPrint debug \$0 (\"Exsiting comment for script '\" . (\ + \$ScriptVal->\"name\") . \"' is '\" . (\$ScriptVal->\"comment\") . \"'.\")\ + ;\r\ + \n :set (\$ScriptVal->\"comment\") [ :pick \$CommentLine ([ :f\ + ind \$CommentLine \":\"] + 2) [ :len \$CommentLine] ];\r\ + \n \$LogPrint debug \$0 (\"New comment (\" . (\$ScriptVal->\"c\ + omment\") . \") for script '\" . (\$ScriptVal->\"name\") . \"' has been ad\ + ded!\");\r\ + \n } else={\r\ + \n \$LogPrint debug \$0 (\"Comment for script '\" . (\$ScriptV\ + al->\"name\") . \"' did not change.\");\r\ + \n :error false;\r\ + \n }\r\ + \n } \r\ + \n }\r\ + \n\r\ + \n :local RequiredROS ([ \$ParseKeyValueStore [ \$Grep \$SourceNew (\ + \"\\23 requires RouterOS, \") ] ]->version);\r\ + \n :if ([ \$RequiredRouterOS \$0 [ \$EitherOr \$RequiredROS \"0.0\" ]\ + \_false ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"The script '\" . (\$ScriptVal->\"name\ + \") . \"' requires RouterOS \" . \\\r\ + \n \$RequiredROS . \", which is not met by your installation. I\ + gnoring!\");\r\ + \n :error false;\r\ + \n }\r\ + \n :local RequiredDM [ \$ParseKeyValueStore [ \$Grep \$SourceNew (\"\ + \\23 requires device-mode, \") ] ];\r\ + \n :local MissingDM ({});\r\ + \n :foreach Feature,Value in=\$RequiredDM do={\r\ + \n :if ([ :typeof (\$DeviceMode->\$Feature) ] = \"bool\" && (\$Devi\ + ceMode->\$Feature) = false) do={\r\ + \n :set MissingDM (\$MissingDM, \$Feature);\r\ + \n }\r\ + \n }\r\ + \n :if ([ :len \$MissingDM ] > 0) do={\r\ + \n \$LogPrint warning \$0 (\"The script '\" . (\$ScriptVal->\"name\ + \") . \"' requires disabled \" . \\\r\ + \n \"device-mode features (\" . [ :tostr \$MissingDM ] . \"). I\ + gnoring!\");\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :if ([ \$ValidateSyntax \$SourceNew ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Syntax validation for script '\" . (\$\ + ScriptVal->\"name\") . \"' failed! Ignoring!\");\r\ + \n :error false;\r\ + \n }\r\ + \n \r\ + \n :log info (\"Updating script: \" . (\$ScriptVal->\"name\") . \" Sc\ + ript comment: \" . (\$ScriptVal->\"comment\"));\r\ + \n\r\ + \n /system/script/set owner=(\$ScriptVal->\"name\") comment=(\$Script\ + Val->\"comment\") \\\r\ + \n source=[ \$IfThenElse (\$ScriptUpdatesCRLF = true) \$SourceCRL\ + F \$SourceNew ] \$Script;\r\ + \n :if (\$ScriptVal->\"name\" = \"AM-GlobalConfig\" || \\\r\ + \n \$ScriptVal->\"name\" = \"AM-GlobalFunc\" || \\\r\ + \n \$ScriptVal->\"name\" ~ (\"^(AM-GlobalFunc\\\\.d|mod)/.\")) d\ + o={\r\ + \n :set ReloadGlobal true;\r\ + \n }\r\ + \n } on-error={ }\r\ + \n }\r\ + \n :if (\$ReloadGlobal = true) do={\r\ + \n \$LogPrint info \$0 (\"Reloading global configuration and functions.\ + \");\r\ + \n :onerror Err {\r\ + \n :global InitSetup (a);\r\ + \n /system/script {run AM-GlobalConfig; run AM-GlobalFunc;};\r\ + \n } do={\$LogPrint error \$0 (\"Reloading global configuration and fun\ + ctions failed! \" . \$Err)}\r\ + \n }\r\ + \n :if (\$GlobalConfVersionBefore > \$GlobalConfVersion) do={\r\ + \n \$LogPrint warning \$0 (\"The configuration version decreased from \ + \" . \\\r\ + \n \$GlobalConfVersionBefore . \" to \" . \$GlobalConfVersion . \\\r\ + \n \". Installed an older version\?\");\r\ + \n }\r\ + \n :if (\$GlobalConfVersionBefore < \$GlobalConfVersion) do={\r\ + \n :global GlobalConfChanges;\r\ + \n :global GlobalConfMigration;\r\ + \n :local ChangeLogCode;\r\ + \n :if ([ :len \$ChangeLogCode ] > 0) do={\r\ + \n :if ([ \$ValidateSyntax \$ChangeLogCode ] = true) do={\r\ + \n :onerror Err {\r\ + \n [ :parse \$ChangeLogCode ];\r\ + \n } do={\$LogPrint warning \$0 (\"The changelog failed to run: \" \ + . \$Err)}\r\ + \n } else={\$LogPrint warning \$0 (\"The changelog failed syntax vali\ + dation!\")}\r\ + \n }\r\ + \n :if ([ :len \$GlobalConfMigration ] > 0) do={\r\ + \n :for I from=(\$GlobalConfVersionBefore + 1) to=\$GlobalConfVersion\ + \_do={\r\ + \n :local Migration (\$GlobalConfMigration->[ :tostr \$I ]);\r\ + \n :do {\r\ + \n :if ([ :typeof \$Migration ] != \"str\") do={\r\ + \n \$LogPrint debug \$0 (\"Migration code for change \" . \$I .\ + \_\" is not available.\");\r\ + \n :error false;\r\ + \n }\r\ + \n :if ([ \$ValidateSyntax \$Migration ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Migration code for change \" . \$I\ + \_. \" failed syntax validation!\");\r\ + \n :error false}\r\ + \n \$LogPrint info \$0 (\"Applying migration for change \" . \$I \ + . \": \" . \$Migration);\r\ + \n :onerror Err {\r\ + \n [ :parse \$Migration ];\r\ + \n } do={\$LogPrint warning \$0 (\"Migration code for change \" .\ + \_\$I . \" failed to run: \" . \$Err)}\r\ + \n } on-error={ }\r\ + \n }\r\ + \n }\r\ + \n :local NotificationMessage (\"The configuration version on \" . \$Id\ + entity . \" increased \" . \\\r\ + \n \"to \" . \$GlobalConfVersion . \", current configuration may nee\ + d modification. \" . \\\r\ + \n \"Please review and update global-config-overlay, then re-run glo\ + bal-config.\");\r\ + \n \$LogPrint info \$0 (\$NotificationMessage);\r\ + \n :if ([ :len \$GlobalConfChanges ] > 0) do={\r\ + \n :set NotificationMessage (\$NotificationMessage . \"\\n\\nChanges:\ + \");\r\ + \n :for I from=(\$GlobalConfVersionBefore + 1) to=\$GlobalConfVersion\ + \_do={\r\ + \n :local Change (\$GlobalConfChanges->[ :tostr \$I ]);\r\ + \n :set NotificationMessage (\$NotificationMessage . \"\\n \" . \\\ + \r\ + \n [ \$SymbolForNotification \"pushpin\" \"*\" ] . \$Change);\r\ + \n \$LogPrint info \$0 (\"Change \" . \$I . \": \" . \$Change);\r\ + \n }\r\ + \n } else={\r\ + \n :set NotificationMessage (\$NotificationMessage . \"\\n\\nNews and\ + \_changes are not available.\");\r\ + \n\r\ + \n }\r\ + \n\r\ + \n :if ([ :len \$GlobalConfChanges ] > 0) do={ :set GlobalConfChanges; \ + } else={ :global GlobalConfChanges (a); }\r\ + \n :if ([ :len \$GlobalConfMigration ] > 0) do={ :set GlobalConfMigrati\ + on; } else={ :global GlobalConfMigration (a); }\r\ + \n }\r\ + \n} do={\r\ + \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ + \n} }\r\ + \n\r\ + \n# load modules\r\ + \n:foreach Script in=[ /system/script/find where name ~ \"^(global-functio\ + ns\\\\.d|mod)/.\" ] do={\r\ + \n :local ScriptVal [ /system/script/get \$Script ];\r\ + \n :if ([ \$ValidateSyntax (\$ScriptVal->\"source\") ] = true) do={\r\ + \n :onerror Err {\r\ + \n /system/script/run \$Script;\r\ + \n } do={\r\ + \n \$LogPrint error \$0 (\"Module '\" . \$ScriptVal->\"name\" . \"' f\ + ailed to run: \" . \$Err);\r\ + \n }\r\ + \n } else={\r\ + \n \$LogPrint error \$0 (\"Module '\" . \$ScriptVal->\"name\" . \"' fai\ + led syntax validation, skipping.\");\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n# Add and fix global scheduler\r\ + \n:put \"Add or/and fix Global scheduler...\";\r\ + \n:local OnEvent \"/system/script { run AM-GlobalConfig; run AM-GlobalFunc\ + ; }\";\r\ + \n:local Comment \"Every Day Set Global Environment Variables\";\r\ + \n:if ([ :len [ /system/scheduler/find where name=\"AM-SetGlobalEnv\" ] ] \ + = 0) do={\r\ + \n /system/scheduler/add name=\"AM-SetGlobalEnv\" comment=\$Comment on-ev\ + ent=\$OnEvent start-time=startup;\r\ + \n}\r\ + \n:if ([ /system/scheduler/get \"AM-SetGlobalEnv\" comment ] != \$Comment)\ + \_do={\r\ + \n /system/scheduler/set \"AM-SetGlobalEnv\" comment=\$Comment;\r\ + \n}\r\ + \n:if ([ /system/scheduler/get \"AM-SetGlobalEnv\" on-event ] != \$OnEvent\ + ) do={\r\ + \n /system/scheduler/set \"AM-SetGlobalEnv\" on-event=\$OnEvent;\r\ + \n}\r\ + \n# Add Update Script scheduler\r\ + \n:put \"Add or/and fix Update Script scheduler\";\r\ + \n:set OnEvent \":global ScriptInstallUpdate; \\\$ScriptInstallUpdate;\";\ + \r\ + \n:set Comment \"Every Day Check For Update Scripts\";\r\ + \n:if ([ :len [ /system/scheduler/find where name=\"AM-ScriptInstallUpdate\ + \" ] ] = 0) do={\r\ + \n/system/scheduler/add name=\"AM-ScriptInstallUpdate\" comment=\$Comment \ + start-time=startup interval=1d on-event=\$OnEvent;\r\ + \n}\r\ + \n\r\ + \n:onerror Err {\r\ + \n :global GlobalConfReady;\r\ + \n :retry { :if (\$GlobalConfReady != true) do={ :error (\"Global configs\ + \_not ready.\"); }; } delay=100ms max=5;\r\ + \n\r\ + \n:log warning (\"This script \$ScriptName Loaded \" . \\\r\ + \n [ \$IfThenElse (\$CommitId != \"unknown\") ([ \$CommitBrief ] . \" \ + \") ] . \\\r\ + \n \"on \" . \$devBoardName . \"\\nRouterOS: \" . \$devCurVersion . \"\ + \\nArchitecture: \" . \$devCurArch . \"\\nIdentity: \" . \$Identity);\r\ + \n # signal we are ready\r\ + \n:set GlobalFuncReady true;\r\ + \n:set ExitOK true;\r\ + \n\r\ + \n:log info (\$0 . \"Global configs ready!\");\r\ + \n} do={\r\ + \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ + \n}\r\ + \n" +add comment=\ + "Lookup IP addresses for RKN list and add them to firewall address-list" \ + dont-require-permissions=no name=AM-RKN-dnsLookup owner=AM-RKN-dnsLookup \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + source="#!rsc by Vados\r\ + \n# RouterOS script: AM-RKN-dnsLookup\r\ + \n# Script comment: Lookup IP addresses for RKN list and add them to firew\ + all address-list\r\ + \n# Copyright (c) 2007-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version=7.19\r\ + \n# requires device-mode, fetch\r\ + \n#\r\ + \n# Script description: This script is intended to be run periodically, e.\ + g. once a day, to update the IP addresses in the firewall address-list bas\ + ed on the RKN list.\r\ + \n# It resolves the domain names in the RKN list and a\ + dds the corresponding IP addresses to the specified firewall address-list.\ + \r\ + \n# The script also handles CNAME records by following\ + \_them until it finds A records.\r\ + \n# Usage:\r\ + \n# /system/script { run AM-RKN-dnsLookup; }\r\ + \n:local ScriptName [ :jobname ];\r\ + \n\r\ + \n:global dnsLookupReady false;\r\ + \n:if ([:typeof \$dnsLookupReady] != \"boolean\") do={ :set dnsLookupReady\ + \_true; }\r\ + \nwhile (!\$dnsLookupReady) do={ :nothing; }\r\ + \n:set dnsLookupReady false;\r\ + \n\r\ + \n:local arrRKN {\r\ + \n \"telegra.ph\"\r\ + \n \"grani.ru\"\r\ + \n \"xhamster.com\"\r\ + \n \"lostfilm.tv\"\r\ + \n \"rutracker.org\"\r\ + \n \"lurkmore.to\"\r\ + \n \"dou.ua\"\r\ + \n \"youporn.com\"\r\ + \n \"pornolab.net\"\r\ + \n \"crimerussia.com\"\r\ + \n \"telegram.org\"\r\ + \n \"api.telegram.org\"\r\ + \n \"facebook.com\"\r\ + \n \"instagram.com\"\r\ + \n \"x.com\"\r\ + \n \"twitter.com\"\r\ + \n \"youtube.com\"\r\ + \n \"googleapis.com\"\r\ + \n \"youtu.be\"\r\ + \n \"googlevideo.com\"\r\ + \n \"gstatic.com\"\r\ + \n \"googleusercontent.com\"\r\ + \n \"nhacmp3youtube.com\"\r\ + \n \"telegram.me\"\r\ + \n \"t.me\";}\r\ + \n\r\ + \n:local ListRKN \"RKN-dnsLookup\";\r\ + \n:local ListComment (\"ListRKN managed by \" . \$ScriptName);\r\ + \n:foreach aListItem in=[/ip/firewall/address-list find list=\$ListRKN] do\ + ={\r\ + \n /ip firewall address-list remove \$aListItem;\r\ + \n}\r\ + \n:foreach aItem in=\$arrRKN do={\r\ + \n# :do {\r\ + \n :retry delay=500ms max=5 on-error={:log error \"dns resolve fail\ + ure [ \$aItem - resolve ip ]\"} command={:resolve \$aItem}\r\ + \n# } on-error={\r\ + \n# :log error \"dns resolve failure [ \$arItem - resolve ip ]\";\r\ + \n# }\r\ + \n :foreach dnsRecord in=[/ip dns cache all find where (name=\$aItem)] \ + do={\r\ + \n :if ([/ip dns cache all get \$dnsRecord type]=\"A\") do={\r\ + \n :local newAddress [/ip dns cache all get \$dnsRecord data];\ + \r\ + \n :do {\r\ + \n /ip firewall address-list add list=\$ListRKN address=\$newA\ + ddress comment=\$aItem;\r\ + \n :log warning \"Successfully adding ip to list A record: \ + \$dnsRecord, address: \$newAddress domain: \$aItem\";\r\ + \n } on-error={\r\ + \n :log error \"error when adding ip to list A record: \$dn\ + sRecord, address: \$newAddress domain: \$aItem\";\r\ + \n }\r\ + \n }\r\ + \n :if ([/ip dns cache all get \$dnsRecord type]=\"CNAME\") do={\r\ + \n :local cname;\r\ + \n :local nextCname;\r\ + \n :local cnameAddress;\r\ + \n :set cname [/ip dns cache all find where (name=\$aItem && ty\ + pe=\"CNAME\")];\r\ + \n :set nextCname [/ip dns cache all find where (name=[/ip dns \ + cache all get \$cname data] && type=\"CNAME\")];\r\ + \n :while (\$nextCname != \"\") do={\r\ + \n :set cname \$nextCname;\r\ + \n :set nextCname [/ip dns cache all find where (name=[/ip \ + dns cache all get \$cname data] && type=\"CNAME\")];\r\ + \n }\r\ + \n :foreach aRecord in=[/ip dns cache all find where (name=[/ip\ + \_dns cache all get \$cname data] && type=\"A\")] do={\r\ + \n :do {\r\ + \n :set cnameAddress [/ip dns cache all get \$aRecord d\ + ata];\r\ + \n /ip firewall address-list add list=\$ListRKN address\ + =\$cnameAddress comment=\$aItem;\r\ + \n :log warning \"Succesfully adding ip to list CNAME r\ + ecord: \$cname, A record: \$aRecord, address: \$newAddress, from domain: \ + \$aItem.\";\r\ + \n# /ip firewall raw add action=add-dst-to-address-list\ + \_address-list=\$ListRKN address-list-timeout=none-dynamic chain=preroutin\ + g comment=\$aItem content=\$aItem;\r\ + \n } on-error={\r\ + \n :log error \"error when adding ip to list CNAME reco\ + rd: \$cname, A record: \$aRecord, address: \$newAddress, from domain: \$aI\ + tem.\";\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:if ([ :len [ /system/scheduler/find where name=\$ScriptName ] ] = 0) do\ + ={\r\ + \n :log error (\$ScriptName . \"System Scheduler for script: \" . \$Scri\ + ptName . \" is NOT SET! Fix It Now!\");\r\ + \n /system/scheduler/add name=\$ScriptName on-event=\"/system/script { \ + run \$ScriptName; }\" comment=\"Update RKN DNS Looup\" interval=00:30:00 p\ + olicy=\"ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon\"\ + \_start-time=startup;\r\ + \n }\r\ + \n:set dnsLookupReady true;\r\ + \ndelay 2s; \r\ + \n:global dnsLookupReady (a);\r\ + \n" +add dont-require-permissions=no name="renameLists " owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + local oldName \"Test\";\ + \n:local newName \"Test-IP\";\ + \n/ip firewall address-list\ + \n:foreach i in=[find list=\$oldName] do={\ + \nset \$i list=\$newName;\ + \n}\ + \n" +add dont-require-permissions=no name=IPv6-Settings owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + #############Script Settings##################\ + \n\ + \n:local \"IF-TUN\" \"6to4-tun\"\ + \n:local \"IF-LOC\" \"Bridge-LAN\"\ + \n:local \"POOL-6TO4\" \"poolV6-local\"\ + \n:local \"force-update\" false\ + \n############ use then static ip #######################\ + \n:local \"lease-address\" [/ip address get [find interface=\$\"IF-LOC\"] \ + address]\ + \n#:local \"interface\" \"ext\"\ + \n:local bound 0\ + \n\ + \n###############################################\ + \n\ + \n:local 6to4prefix do={\ + \n :global dec2hex\ + \n :local ipv4 \$1\ + \n :local ipv6 \"2002:\"\ + \n :for i from=0 to=2 step=1 do={ \ + \n :if ( \$i = 2) do={\ + \n :set ipv6 (\$ipv6.\":\")\ + \n }\ + \n :local fp [:find \$ipv4 \".\"]\ + \n :if ( \$fp > 0 ) do={\ + \n :set ipv6 (\$ipv6.[\$dec2hex [:pick \$ipv4 0 \$fp]])\ + \n :set ipv4 [:pick \$ipv4 (\$fp + 1 ) [:len \$ipv4]]\ + \n }\ + \n }\ + \n :return (\$ipv6.[\$dec2hex \$ipv4])\ + \n}\ + \n:local \"str_replace\" do={\ + \n :local \"str-pos\" [:find \$1 \$2]\ + \n :local \"str-len\" [:len \$2]\ + \n :local str \"\"\ + \n :local rest \$1\ + \n :while (\$\"str-pos\" >= 0) do={\ + \n :local t [:pick \$rest 0 \$\"str-pos\"]\ + \n :if ( \$4 > 0 ) do={\ + \n :for i from=1 to=(\$4 - [:len \$t]) step=1 do={\ + \n :set str (\$str.\$5)\ + \n }\ + \n }\ + \n :set str (\$str.\$t.\$3)\ + \n :set rest [:pick \$rest (\$\"str-pos\"+\$\"str-len\") [:len \$re\ + st]]\ + \n :set \"str-pos\" [:find \$rest \$2]\ + \n }\ + \n :return (\$str.\$rest)\ + \n}\ + \n\ + \n:if (\$bound=1) do={\ + \n :local t [:find \$\"lease-address\" \"/\"]\ + \n\ + \n :if ( \$t >= 0 ) do={\ + \n :set \"lease-address\" [:pick \$\"lease-address\" 0 \$t]\ + \n }\ + \n\ + \n :if ( [/interface 6to4 print count-only where name=\$\"IF-TUN\"] = 0\ + ) do={\ + \n /interface 6to4 add !keepalive local-address=\$\"lease-address\"\ + \_mtu=1280 name=\$\"IF-TUN\" remote-address=10.30.30.0\ + \n :set \"force-update\" true\ + \n }\ + \n\ + \n :local \"IPv4-TUN\" [/interface 6to4 get [find name=\$\"IF-TUN\"] lo\ + cal-address];\ + \n\ + \n :if ( \$\"lease-address\" != \$\"IPv4-TUN\" || \$\"force-update\" = \ + true) do={\ + \n /interface 6to4 set [find name=\$\"IF-TUN\"] local-address=\$\"l\ + ease-address\"\ + \n /ipv6 address remove [find interface=\$\"IF-TUN\"]\ + \n /ipv6 address remove [find interface=\$\"IF-LOC\"]\ + \n /ipv6 route remove [find gateway ~ \$\"IF-TUN\" and dst-address=\ + \"::/0\"]\ + \n :local \"pool-prefix\" [\$6to4prefix \$\"lease-address\"]\ + \n :if ( [/ipv6 pool print count-only where name=\$\"POOL-6TO4\"] =\ + \_0) do={ \ + \n /ipv6 pool add name=\$\"POOL-6TO4\" prefix=(\$\"pool-prefix\ + \".\":1::/64\") prefix-length=64\ + \n } else={\ + \n /ipv6 pool set [/ipv6 pool find where name=\$\"POOL-6TO4\"] \ + prefix=(\$\"pool-prefix\".\":1::/64\")\ + \n }\ + \n /ipv6 address add address=(\$\"pool-prefix\".\"::\".[\$MAC2EUI64\ + \_[/interface get [find name=\$\"interface\"] mac-address]].\"/3\") interf\ + ace=\$\"IF-TUN\" advertise=no\ + \n /ipv6 address add eui-64=yes from-pool=\$\"POOL-6TO4\" interface\ + =\$\"IF-LOC\" advertise=yes\ + \n /ipv6 route add dst-address=::/0 gateway=(\"::10.30.30.81%\".\$\ + \"IF-TUN\")\ + \n :local t [/ipv6 address get [find interface=\$\"IF-LOC\"] addres\ + s]\ + \n :set t [:pick \$t 0 [:find \$t \"/\"]]\ + \n :if ( [/ipv6 dhcp-server option print count-only where name=DNS]\ + \_= 0) do={\ + \n /ipv6 dhcp-server option add code=23 name=DNS value=(\"0x\".\ + [\$\"str_replace\" \$t \":\" \"\" 4 \"0\"])\ + \n } else={\ + \n /ipv6 dhcp-server option set [/ipv6 dhcp-server option find \ + where name=DNS] value=(\"0x\".[\$\"str_replace\" \$t \":\" \"\" 4 \"0\"])\ + \n }\ + \n :if ( [/ipv6 dhcp-server print count-only where interface=\$\"IF\ + -LOC\"] = 0) do={\ + \n /ipv6 dhcp-server add address-pool=\$\"POOL-6TO4\" dhcp-opti\ + on=DNS interface=\$\"IF-LOC\" lease-time=1d name=\$\"IF-LOC\"\ + \n }\ + \n :if ( [ipv6 nd print count-only where interface=\$\"IF-LOC\"] = \ + 0) do={\ + \n /ipv6 nd add advertise-dns=no interface=\$\"IF-LOC\" other-c\ + onfiguration=yes\ + \n }\ + \n }\ + \n}" +add dont-require-permissions=no name=IPv6-GlobalFunc owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + global MAC2EUI64 do={\ + \n :local EUI64 \"\"\ + \n :local MAC \$1\ + \n :local HEX2DEC \"0123456789ABCDEF\"\ + \n :for i from=0 to=5 step=1 do={\ + \n :if ( \$i = 0 ) do={\ + \n :set EUI64 [:pick \$MAC 0]\ + \n :set EUI64 (\$EUI64.[:tostr [:pick \$\"HEX2DEC\" ([:find \$\ + \"HEX2DEC\" [:pick \$MAC 1]] ^ 2)]])\ + \n }\ + \n :if ( \$i = 1 || \$i = 3) do={\ + \n :set EUI64 (\$EUI64.\":\")\ + \n }\ + \n :if ( \$i = 2 ) do={\ + \n :set EUI64 (\$EUI64.\"FF:FE\")\ + \n }\ + \n :if ( [:find \$MAC \":\"] = 2 ) do={\ + \n :set MAC [:pick \$MAC 3 [:len \$MAC]]\ + \n :set EUI64 (\$EUI64.[:pick \$MAC 0 2])\ + \n }\ + \n }\ + \n :return (\$EUI64)\ + \n}\ + \n\ + \n:global dec2hex do={\ + \n :local hex \"\"\ + \n :local dec [:tonum \$1]\ + \n :for i from=0 to=4 step=4 do={\ + \n :set hex ([:pick \"0123456789ABCDEF\" ((\$dec>>\$i)&0xf) (((\$de\ + c>>\$i)&0xf)+1)].\$hex)\ + \n }\ + \n :return ([:tostr \$hex])\ + \n}" +add comment=Generator dont-require-permissions=no name=proxySet owner=vados \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + source="# 2. WireGuard interface\r\ + \n/interface/wireguard/add name=wg-VDSina private-key=\"4CHyNhbOs923/EyNDg\ + uMXJXdghL2I3UyzXPwrANVgHs=\" listen-port=21641\r\ + \n/interface/wireguard/peers/add interface=wg-VDSina public-key=\"o5IgCl1/\ + G6xbl6j7sPaP4ZNYREeYOmqZjKbm+v0b9jU=\" preshared-key=\"RNvF7T1cg5tyXcYQnD9\ + N5BEp6e20vVJQTv0GMjyvHU0=\" endpoint-address=10.30.30.33 endpoint-port=518\ + 20 allowed-address=0.0.0.0/0 persistent-keepalive=11\r\ + \n/ip/address/add address=10.9.0.3/32 interface=wg-VDSina\r\ + \n\r\ + \n# 3. DNS\r\ + \n{ :local rawDNS [/ip/dns/get servers]; :local prevDNS \"\"; :foreach s i\ + n=[:toarray \$rawDNS] do={ :if ([:len \$prevDNS] > 0) do={ :set prevDNS \"\ + \$prevDNS,\$s\" } else={ :set prevDNS \$s } }; /system/script/add name=VDS\ + ina-prev-dns comment=\"\$prevDNS\" source=\"\" }\r\ + \n/ip/dns/set servers=8.8.4.4\r\ + \n/ip/route/add dst-address=8.8.4.4/32 gateway=wg-VDSina distance=1 commen\ + t=VDSina-dns\r\ + \n\r\ + \n# 4. Enable WireGuard\r\ + \n/interface/wireguard/enable wg-VDSina\r\ + \n" +/user group +add name=backup policy="ssh,read,write,policy,test,web,sniff,sensitive,api,res\ + t-api,!local,!telnet,!ftp,!reboot,!winbox,!password,!romon" +/ip smb +set enabled=no interfaces=lo +/interface bridge port +add bridge=Bridge-LAN interface=ether5 +add bridge=Bridge-LAN interface=ether2 +add bridge=Bridge-LAN interface=ether4 trusted=yes +add bridge=Bridge-LAN interface=ether3 +add bridge=Bridge-LAN interface=wlan2 +add bridge=Bridge-LAN interface=wlan1 +/interface bridge settings +set use-ip-firewall=yes +/ip firewall connection tracking +set udp-timeout=10s +/ip neighbor discovery-settings +set discover-interface-list=LAN lldp-med=no lldp-poe-power=no +/ip settings +set accept-redirects=yes ipv4-multipath-hash-policy=l4 max-neighbor-entries=\ + 8192 +/ipv6 settings +set disable-ipv6=yes disable-link-local-address=yes forward=no \ + max-neighbor-entries=8192 multipath-hash-policy=l4 +/interface detect-internet +set detect-interface-list=WAN internet-interface-list=Internet \ + lan-interface-list=LAN request-interval=1m wan-interface-list=WAN +/interface l2tp-server server +set authentication=mschap2 use-ipsec=yes +/interface list member +add interface="ether1 - Unet" list=Internet +add interface=WG list=WAN +add interface=Bridge-LAN list=LAN +add interface="ether1 - Unet" list=WAN +/interface wireguard peers +add allowed-address=0.0.0.0/0 client-allowed-address=::/0 disabled=yes \ + endpoint-address=109.107.177.79 endpoint-port=29185 interface=WG name=\ + VDSina persistent-keepalive=10s public-key=\ + "zuRsO+dL/j6awaBWZ/NgnHR+bCNUjRWbaHFpdzkNnw4=" +add allowed-address=10.10.0.1/24 client-address=10.10.0.2/32 \ + client-allowed-address=0.0.0.0/0 client-dns=8.8.8.8 client-endpoint=\ + 10.30.30.81 client-keepalive=10s client-listen-port=22022 disabled=yes \ + endpoint-address=10.30.30.10 endpoint-port=22022 interface=NUC name=\ + MicroNuc persistent-keepalive=10s public-key=\ + "oieVxNCDa4G5LU2QVH+s4AXwapSmdiDvVVhBS/FPdTA=" responder=yes +add allowed-address=0.0.0.0/0 client-allowed-address=::/0 endpoint-address=\ + 10.30.30.33 endpoint-port=44044 interface=wg-VDSina name=peer11 \ + persistent-keepalive=11s public-key=\ + "o5IgCl1/G6xbl6j7sPaP4ZNYREeYOmqZjKbm+v0b9jU=" +/interface wireless cap +# +set bridge=Bridge-LAN caps-man-addresses=10.30.30.10 \ + caps-man-certificate-common-names=CAPsMAN-51B25E507D07 certificate=\ + CAP-488F5A8E1ABC discovery-interfaces=Bridge-LAN enabled=yes interfaces=\ + wlan2,wlan1 lock-to-caps-man=yes +/ip address +add address=10.30.30.81/24 interface=Bridge-LAN network=10.30.30.0 +add address=10.8.0.2/24 disabled=yes interface=WG network=10.8.0.0 +add address=10.9.0.3 interface=wg-VDSina network=10.9.0.3 +/ip cloud +set update-time=no +/ip dhcp-client +add add-default-route=special-classless default-route-distance=2 \ + default-route-tables=main:2 dhcp-options=clientid,clientid_duid \ + interface="ether1 - Unet" name=client1 use-peer-dns=no use-peer-ntp=no +/ip dhcp-server config +set accounting=no +/ip dhcp-server lease +add address=10.30.30.101 client-id=1:48:8f:5a:8e:ee:a8 mac-address=\ + 48:8F:5A:8E:EE:A8 server=masterDHCP +add address=10.30.30.107 client-id=1:f0:de:f1:91:d:1e mac-address=\ + F0:DE:F1:91:0D:1E server=masterDHCP +add address=10.30.30.83 client-id=1:0:80:77:ec:43:86 mac-address=\ + 00:80:77:EC:43:86 server=masterDHCP +add address=10.30.30.70 dhcp-option=domain-search-list,HostName \ + dhcp-option-set=HP1505n mac-address=00:1E:0B:1A:88:8D server=masterDHCP +add address=10.30.30.50 client-id=1:4:7c:16:36:f5:37 mac-address=\ + 04:7C:16:36:F5:37 server=masterDHCP +add address=10.30.30.71 client-id=1:10:2d:41:2c:20:c2 mac-address=\ + 10:2D:41:2C:20:C2 server=masterDHCP +add address=10.30.30.61 client-id=1:10:8:c1:81:59:5f mac-address=\ + 10:08:C1:81:59:5F server=masterDHCP +add address=10.30.30.72 client-id=1:10:38:1f:d2:5f:13 mac-address=\ + 10:38:1F:D2:5F:13 server=masterDHCP +add address=10.30.30.99 client-id=1:10:b1:df:e9:d0:d5 mac-address=\ + 10:B1:DF:E9:D0:D5 server=masterDHCP +add address=10.30.30.111 client-id=1:fe:2:52:be:3f:16 mac-address=\ + FE:02:52:BE:3F:16 server=masterDHCP +add address=10.30.30.92 client-id=1:d4:6d:6d:fd:e5:49 mac-address=\ + D4:6D:6D:FD:E5:49 server=masterDHCP +add address=10.30.30.93 client-id=1:7e:8b:1e:cb:b8:cb mac-address=\ + CC:42:10:12:46:94 server=masterDHCP +add address=10.30.30.94 client-id=1:50:cc:f8:85:96:a mac-address=\ + 50:CC:F8:85:96:0A server=masterDHCP +add address=10.30.30.82 client-id=1:e4:18:6b:58:34:ab mac-address=\ + E4:18:6B:58:34:AB server=masterDHCP +add address=10.30.30.75 client-id=1:0:27:15:41:97:a9 mac-address=\ + 00:27:15:41:97:A9 server=masterDHCP +add address=10.30.30.77 dhcp-option=HostName dhcp-option-set=StartLife1 \ + mac-address=C4:82:E1:03:49:10 server=masterDHCP +add address=10.30.30.73 client-id=1:10:38:1f:82:81:f2 mac-address=\ + 10:38:1F:82:81:F2 server=masterDHCP +add address=10.30.30.95 client-id=1:88:ae:dd:60:39:54 dhcp-option=HostName \ + dhcp-option-set=VADOS-NUC mac-address=88:AE:DD:60:39:54 server=masterDHCP +add address=10.30.30.98 client-id=1:c8:5b:76:d8:cc:bf dhcp-option=HostName \ + dhcp-option-set=VADOS-LEN mac-address=C8:5B:76:D8:CC:BF server=masterDHCP +add address=10.30.30.96 client-id=iPhone mac-address=4A:91:ED:0E:1F:39 \ + server=masterDHCP +add address=10.30.30.74 client-id=MiTV dhcp-option=HostName dhcp-option-set=\ + MiTV mac-address=20:72:A9:D3:34:36 server=masterDHCP +add address=10.30.30.30 dhcp-option=HostName dhcp-option-set=miller \ + mac-address=F0:75:5D:1E:5F:71 server=masterDHCP +add address=10.30.30.100 client-id=iVados dhcp-option=HostName \ + dhcp-option-set=iVados mac-address=DE:4D:72:F3:1A:9F server=masterDHCP +add address=10.30.30.10 allow-dual-stack-queue=yes client-id=\ + ff:0:0:0:df:0:3:0:1:f0:75:5d:1e:5f:85 dhcp-option=HostName \ + dhcp-option-set=MikroNUC mac-address=F0:75:5D:1E:5F:85 server=masterDHCP \ + use-src-mac=yes +/ip dhcp-server network +add address=10.30.30.0/24 caps-manager=10.30.30.10 dhcp-option=\ + domain-search-list dhcp-option-set=domain-search-set dns-server=\ + 10.30.30.33,109.107.177.79 domain=WORKGROUP gateway=10.30.30.81 netmask=\ + 24 ntp-server=10.30.30.81,10.30.30.10 wins-server=10.30.30.95,10.30.30.98 +/ip dns +set allow-remote-requests=yes cache-max-ttl=1d doh-max-concurrent-queries=100 \ + doh-max-server-connections=20 servers=8.8.4.4 verify-doh-cert=yes +/ip dns static +add address=109.107.177.79 comment="VDSina Server DNS" name=ns1.vados.ru \ + type=A +add address=109.107.177.79 name=vds.vados.ru type=A +add comment="Local DNS server for vados.ru" disabled=yes ns=10.30.30.81 \ + regexp=*.vados.ru type=NS +add comment="*.vados.ru Regexp" disabled=yes forward-to=10.30.30.81 regexp=\ + "\".*\\\\.vados\\\\.ru\"" type=FWD +add comment="*.30.30.10.in-addr.arpa Regexp" disabled=yes forward-to=\ + 10.30.30.81 regexp="\".*\\\\.30\\\\.30\\\\.10\\\\.in-addr\\\\.arpa" type=\ + FWD +add address=10.30.30.81 comment=NS.vados.ru.local disabled=yes name=\ + ns.vados.ru.local type=A +add comment="DNS ns.vados.ru.local" disabled=yes match-subdomain=yes name=\ + vados.ru ns=ns.vados.ru.local type=NS +add address=10.30.30.33 comment=reg.vados.ru name=reg.vados.ru type=A +add address=8.8.8.8 comment="Google-dns IPv4 1" match-subdomain=yes name=\ + dns.google type=A +add address=8.8.4.4 comment="Google-dns IPv4 2" name=dns.google type=A +add address=10.30.30.33 comment=AMSTER name=amster.vados.ru type=A +add address=10.30.30.33 name=ros.vados.ru type=A +add address=10.30.30.95 name=vados-nuc type=A +add address=10.30.30.33 name=amster-nuc type=A +add address=10.30.30.33 name=amster type=A +add address=10.30.30.33 name=amster-reg type=A +add address=10.30.30.33 disabled=yes name=mng.vados.ru type=A +add address=10.30.30.33 name=mgr.vados.ru type=A +add address=10.30.30.33 name=prt.vados.ru type=A +add address=10.30.30.33 disabled=yes match-subdomain=yes name=\ + mikrots.vados.ru type=A +add address=10.30.30.30 comment=MILLER name=miller.vados.ru type=A +add address=10.30.30.30 name=MILLER-LEN type=A +add address=10.30.30.30 name=miller type=A +add address=1.0.0.1 comment="CloudFlare-doh IPv4 2" disabled=yes name=\ + security.cloudflare-dns.com type=A +add address=1.1.1.1 comment="CloudFlare-doh IPv4 1" disabled=yes name=\ + security.cloudflare-dns.com type=A +add address=9.9.9.9 comment="Cuad9-dns IPv4 1" disabled=yes name=\ + dns.quad9.net type=A +add address=149.112.112.112 comment="Cuad9-dns IPv4 2" disabled=yes name=\ + dns.quad9.net type=A +add address=195.133.25.16 comment="DNS Comss" disabled=yes name=dns.comss.one \ + type=A +add address=10.30.30.81 comment=LocalNet name=MikroVados type=A +add address=10.30.30.10 name=MikroNUC type=A +add address=10.30.30.86 disabled=yes name=MikroYellow type=A +add address=10.30.30.85 disabled=yes name=MikroMic type=A +add address=10.30.30.95 name=VADOS-NUC type=A +add address=10.30.30.98 name=VADOS-LEN type=A +add address=91.192.189.2 comment=Unet-DNS disabled=yes name=ns1.unet.ws type=\ + A +add address=10.30.30.20 disabled=yes name=garage type=A +/ip firewall address-list +add address=91.215.120.206 list=TRUSTED +add address=185.71.70.78 disabled=yes list=TRUSTED +add address=176.53.203.171 disabled=yes list=TRUSTED +add address=176.53.203.170 disabled=yes list=TRUSTED +add address=176.53.202.194 disabled=yes list=TRUSTED +add address=8.8.4.0/24 list=YouTube +add address=8.8.8.0/24 list=YouTube +add address=8.34.208.0/20 list=YouTube +add address=8.35.192.0/20 list=YouTube +add address=23.236.48.0/20 list=YouTube +add address=23.251.128.0/19 list=YouTube +add address=34.0.0.0/15 list=YouTube +add address=34.2.0.0/16 list=YouTube +add address=34.3.0.0/23 list=YouTube +add address=34.3.3.0/24 list=YouTube +add address=34.3.4.0/24 list=YouTube +add address=34.3.8.0/21 list=YouTube +add address=34.3.16.0/20 list=YouTube +add address=34.3.32.0/19 list=YouTube +add address=34.3.64.0/18 list=YouTube +add address=34.4.0.0/14 list=YouTube +add address=34.8.0.0/13 list=YouTube +add address=34.16.0.0/12 list=YouTube +add address=34.32.0.0/11 list=YouTube +add address=34.64.0.0/10 list=YouTube +add address=34.128.0.0/10 list=YouTube +add address=35.184.0.0/13 list=YouTube +add address=35.192.0.0/14 list=YouTube +add address=35.196.0.0/15 list=YouTube +add address=35.198.0.0/16 list=YouTube +add address=35.199.0.0/17 list=YouTube +add address=35.199.128.0/18 list=YouTube +add address=35.200.0.0/13 list=YouTube +add address=35.208.0.0/12 list=YouTube +add address=35.224.0.0/12 list=YouTube +add address=35.240.0.0/13 list=YouTube +add address=57.140.192.0/18 list=YouTube +add address=64.15.112.0/20 list=YouTube +add address=64.233.160.0/19 list=YouTube +add address=66.22.228.0/23 list=YouTube +add address=66.102.0.0/20 list=YouTube +add address=66.249.64.0/19 list=YouTube +add address=70.32.128.0/19 list=YouTube +add address=72.14.192.0/18 list=YouTube +add address=74.125.0.0/16 list=YouTube +add address=104.154.0.0/15 list=YouTube +add address=104.196.0.0/14 list=YouTube +add address=104.237.160.0/19 list=YouTube +add address=107.167.160.0/19 list=YouTube +add address=107.178.192.0/18 list=YouTube +add address=108.59.80.0/20 list=YouTube +add address=108.170.192.0/18 list=YouTube +add address=108.177.0.0/17 list=YouTube +add address=130.211.0.0/16 list=YouTube +add address=136.22.160.0/20 list=YouTube +add address=136.22.176.0/21 list=YouTube +add address=136.22.184.0/23 list=YouTube +add address=136.22.186.0/24 list=YouTube +add address=142.250.0.0/15 list=YouTube +add address=146.148.0.0/17 list=YouTube +add address=152.65.208.0/22 list=YouTube +add address=152.65.214.0/23 list=YouTube +add address=152.65.218.0/23 list=YouTube +add address=152.65.222.0/23 list=YouTube +add address=152.65.224.0/19 list=YouTube +add address=162.120.128.0/17 list=YouTube +add address=162.216.148.0/22 list=YouTube +add address=162.222.176.0/21 list=YouTube +add address=172.110.32.0/21 list=YouTube +add address=172.217.0.0/16 list=YouTube +add address=172.253.0.0/16 list=YouTube +add address=173.194.0.0/16 list=YouTube +add address=173.255.112.0/20 list=YouTube +add address=192.158.28.0/22 list=YouTube +add address=192.178.0.0/15 list=YouTube +add address=193.186.4.0/24 list=YouTube +add address=199.36.154.0/23 list=YouTube +add address=199.36.156.0/24 list=YouTube +add address=199.192.112.0/22 list=YouTube +add address=199.223.232.0/21 list=YouTube +add address=207.223.160.0/20 list=YouTube +add address=208.65.152.0/22 list=YouTube +add address=208.68.108.0/22 list=YouTube +add address=208.81.188.0/22 list=YouTube +add address=208.117.224.0/19 list=YouTube +add address=209.85.128.0/17 list=YouTube +add address=216.58.192.0/19 list=YouTube +add address=216.73.80.0/20 list=YouTube +add address=216.239.32.0/19 list=YouTube +add address=2ip.ru list=Test-IP +add address=wg.vados.ru comment=VDSIna list=TRUSTED +add address=10.8.0.0/24 comment="WG VDSIna" disabled=yes list=TRUSTED +add address=ikus.pesc.ru comment=ikus.pesc.ru list=NoVdsina +add address=love.ru comment=love.ru list=NoVdsina +add address=gosuslugi.ru comment=gosuslugi.ru list=NoVdsina +add address=pochta.ru comment=pochta.ru list=NoVdsina +add address=vdsina.com list=NoVdsina +add address=vdsina.ru list=NoVdsina +add address=youla.ru list=NoVdsina +add address=kupiprodai.ru list=NoVdsina +add address=myip.ru list=Test-IP +add address=geoip.co list=NoVdsina +add address=comp-lenta.ru list=NoVdsina +add address=128.85.102.70 comment=update.microsoft.com list=\ + windowsupdateslist +add address=wu-b-net.trafficmanager.net. comment=\ + ctldl.windowsupdate.com.delivery.microsoft.com list=windowsupdateslist +add address=ctldl.windowsupdate.com.delivery.microsoft.com. comment=\ + ctldl.windowsupdate.com list=windowsupdateslist +add address=redir.update.msft.com.trafficmanager.net. comment=\ + update.microsoft.com list=windowsupdateslist +add address=geo.prod.do.dsp.trafficmanager.net. comment=\ + geo.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=13.74.139.29 comment=array605.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=kv801.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + kv801.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=e12437.d.akamaiedge.net. comment=\ + kv801.prod.do.dsp.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=displaycatalog-rp.md.mp.microsoft.com.akadns.net. comment=\ + displaycatalog.mp.microsoft.com list=windowsupdateslist +add address=rp-consumer-prod-displaycatalog-geomap.trafficmanager.net. \ + comment=displaycatalog-rp.md.mp.microsoft.com.akadns.net list=\ + windowsupdateslist +add address=sls.update.microsoft.com. comment=slscr.update.microsoft.com \ + list=windowsupdateslist +add address=glb.sls.prod.dcat.dsp.trafficmanager.net. comment=\ + sls.update.microsoft.com list=windowsupdateslist +add address=fe3.delivery.mp.microsoft.com. comment=\ + fe3cr.delivery.mp.microsoft.com list=windowsupdateslist +add address=glb.cws.prod.dcat.dsp.trafficmanager.net. comment=\ + fe3.delivery.mp.microsoft.com list=windowsupdateslist +add address=fe2cr.update.msft.com.trafficmanager.net. comment=\ + fe2cr.update.microsoft.com list=windowsupdateslist +add address=download.windowsupdate.com.delivery.microsoft.com. comment=\ + download.windowsupdate.com list=windowsupdateslist +add address=wu-f-net.trafficmanager.net. comment=\ + download.windowsupdate.com.delivery.microsoft.com list=windowsupdateslist +add address=tsfe.trafficmanager.net. comment=\ + tsfe.trafficshaping.dsp.mp.microsoft.com list=windowsupdateslist +add address=edge.ds-c7110-microsoft.global.dns.qwilted-cds.cqloud.com. \ + comment=9.au.download.windowsupdate.com list=windowsupdateslist +add address=52.158.227.125 comment=array812.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=au.download.windowsupdate.com.delivery.microsoft.com. comment=\ + au.download.windowsupdate.com list=windowsupdateslist +add address=a767.dspw65.akamai.net. comment=\ + download.windowsupdate.com.edgesuite.net list=windowsupdateslist +add address=52.151.58.88 comment=array810.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=consumer-licensing-aks2aks.md.mp.microsoft.com.akadns.net. \ + comment=licensing.mp.microsoft.com list=windowsupdateslist +add address=licensing-prod-frontdoor-geomap.trafficmanager.net. comment=\ + consumer-licensing-aks2aks.md.mp.microsoft.com.akadns.net list=\ + windowsupdateslist +add address=star.f.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedge.f.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=cdp-f-nlu-net.trafficmanager.net. comment=\ + star.f.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=star.b.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedge.b.tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=cdp-f-tlu-net.trafficmanager.net. comment=\ + star.b.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=storeedgefd.xbetservices.akadns.net. comment=\ + storeedgefd.dsx.mp.microsoft.com list=windowsupdateslist +add address=\ + storeedgefd.dsx.mp.microsoft.com.edgekey.net.globalredir.akadns.net. \ + comment=storeedgefd.dsx.mp.microsoft.com.edgekey.net list=\ + windowsupdateslist +add address=e16646.dscg.akamaiedge.net. comment=\ + storeedgefd.dsx.mp.microsoft.com.edgekey.net.globalredir.akadns.net list=\ + windowsupdateslist +add address=40.69.76.189 comment=array621.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=bg.microsoft.map.fastly.net. comment=\ + 3.au.download.windowsupdate.com list=windowsupdateslist +add list=windowsupdateslist +add address=40.69.75.33 comment=array613.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=star.sf.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedgeextensions.sf.tlu.dl.delivery.mp.microsoft.com list=\ + windowsupdateslist +add address=cdp-f-ssl-tlu-net.trafficmanager.net. comment=\ + star.sf.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=a2033.dscd.akamai.net. comment=\ + star.sb.tlu.dl.delivery.mp.microsoft.com.edgesuite.net list=\ + windowsupdateslist +add address=13.74.138.242 comment=array602.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=dl.delivery.mp.microsoft.com.delivery.microsoft.com. comment=\ + dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=dcat-f-nlu-net.trafficmanager.net. comment=\ + dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=1d.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=1D.tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=dcat-b-tlu-net.trafficmanager.net. comment=\ + 1d.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=a122.dscg3.akamai.net. comment=\ + tlu.dl.delivery.mp.microsoft.com.edgesuite.net list=windowsupdateslist +add address=geover.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + geover.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=e10370.d.akamaiedge.net. comment=\ + geover.prod.do.dsp.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=52.232.182.21 comment=array511.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.70.77.95 comment=array519.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=a1683.dscd.akamai.net. comment=\ + dl.delivery.mp.microsoft.com-c.edgesuite.net list=windowsupdateslist +add address=consumer-collections-aks2eap.md.mp.microsoft.com.akadns.net. \ + comment=collections.mp.microsoft.com list=windowsupdateslist +add address=a1847.dscd.akamai.net. comment=\ + wildcard.f.tlu.dl.delivery.mp.microsoft.com.edgesuite.net list=\ + windowsupdateslist +add address=13.74.142.6 comment=array607.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=au.download.windowsupdate.com.edgesuite.net. comment=\ + 2.au.download.windowsupdate.com list=windowsupdateslist +add address=a767.dscg3.akamai.net. comment=\ + au.download.windowsupdate.com.edgesuite.net list=windowsupdateslist +add address=52.156.123.84 comment=array818.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.69.78.254 comment=array610.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=4.au.download.windowsupdate.com.delivery.microsoft.com. comment=\ + 4.au.download.windowsupdate.com list=windowsupdateslist +add address=cl-glcb907925.gcdn.co. comment=\ + 4.au.download.windowsupdate.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=52.167.167.111 comment=array510.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=40.69.70.43 comment=array623.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=tsfe.trafficshaping.dsp.mp.microsoft.com.delivery.microsoft.com. \ + comment=tsfe.trafficshaping.dsp.mp.microsoft.com list=windowsupdateslist +add address=ts-frontend.trafficmanager.net. comment=\ + tsfe.trafficshaping.dsp.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=40.69.75.248 comment=array616.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.69.74.84 comment=array615.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=sds.trafficmanager.net. comment=software-download.microsoft.com \ + list=windowsupdateslist +add address=40.69.74.80 comment=array611.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.175.242.182 comment=array804.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=dlc-shim.trafficmanager.net. comment=download.microsoft.com list=\ + windowsupdateslist +add address=e12671.dscd.akamaiedge.net. comment=\ + download.microsoft.com.edgekey.net list=windowsupdateslist +add address=20.187.55.34 comment=array808.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.167.231 comment=array513.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=52.167.222.13 comment=array518.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=kv601.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + kv601.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=e12358.d.akamaiedge.net. comment=\ + kv601.prod.do.dsp.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. comment=\ + tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=dcat-f-tlu-net.trafficmanager.net. comment=\ + tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=a1856.dspw65.akamai.net. comment=\ + tlu.dl.delivery.mp.microsoft.com-c.edgesuite.net list=windowsupdateslist +add address=52.167.164.252 comment=array506.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=13.74.137.54 comment=array601.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=kv501.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + kv501.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=collections-prod-frontdoor-geomap.trafficmanager.net. comment=\ + consumer-collections-aks2eap.md.mp.microsoft.com.akadns.net list=\ + windowsupdateslist +add address=52.167.160.173 comment=array509.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=40.70.77.148 comment=array516.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.200.126 comment=array507.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=52.167.167.59 comment=array508.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.69.76.172 comment=array620.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=smtp.mail.me.com comment=smtp.mail.me.com list=NoVdsina +add address=40.70.76.5 comment=array514.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.186.119 comment=array618.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.177.176.186 comment=array520.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=40.70.76.27 comment=array515.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.160.43 comment=array503.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.110 comment=array817.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.142.8 comment=array614.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.138.254 comment=array603.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.167.96 comment=array501.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.69.76.215 comment=array622.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.143.200 comment=array606.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.111 comment=array818.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.112 comment=array819.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.137.53 comment=array608.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.98 comment=array805.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.96 comment=array803.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.104 comment=array811.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.101 comment=array808.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.99 comment=array806.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.17 comment=array802.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.97 comment=array804.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.103 comment=array810.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.16 comment=array801.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.70.77.177 comment=array517.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.164.84 comment=array512.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.105 comment=array812.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.107 comment=array814.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.232.161.82 comment=array502.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.108 comment=array815.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.161.91 comment=array505.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.102 comment=array809.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.109 comment=array816.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.106 comment=array813.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.117 comment=array622.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.107 comment=array612.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.108 comment=array613.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.105 comment=array610.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.113 comment=array618.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.116 comment=array621.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.98 comment=array603.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.114 comment=array619.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.111 comment=array616.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.97 comment=array602.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.106 comment=array611.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.110 comment=array615.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.119 comment=array624.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.135 comment=array514.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.97 comment=array503.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.99 comment=array604.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.61 comment=array504.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.131 comment=array510.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.132 comment=array511.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.96 comment=array601.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.104 comment=array609.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.138 comment=array517.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.60 comment=array501.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.139 comment=array518.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.118 comment=array623.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.113 comment=array820.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.103 comment=array608.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.100 comment=array807.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.129 comment=array508.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.134 comment=array513.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.62 comment=array505.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.137 comment=array516.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.101 comment=array606.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.96 comment=array502.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.130 comment=array509.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.112 comment=array617.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.100 comment=array605.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.115 comment=array620.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.136 comment=array515.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=purchase.md.mp.microsoft.com.akadns.net. comment=\ + purchase.mp.microsoft.com list=windowsupdateslist +add address=e110219.a.akamaiedge.net. comment=\ + purchase.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=72.153.5.140 comment=array519.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.141 list=windowsupdateslist +add address=72.153.5.63 comment=array506.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.128 comment=array507.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.102 comment=array607.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=storesdk.xbetservices.akadns.net. comment=\ + storesdk.dsx.mp.microsoft.com list=windowsupdateslist +add address=e16646.g.akamaiedge.net. comment=\ + storesdk.dsx.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=software-download.microsoft.com.delivery.microsoft.com. comment=\ + software-download.microsoft.com list=windowsupdateslist +add address=download.prss.microsoft.com.akamaized.net. comment=\ + software-download.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.109 comment=array614.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.133 comment=array512.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=213.180.192.0/19 comment=YandexDisk list=NoVdsina +add address=87.250.250.50 comment=YandexDisk list=NoVdsina +add address=consumer-prod-bcfd-v7-afd.trafficmanager.net. comment=\ + displaycatalog.mp.microsoft.com list=windowsupdateslist +add address=purchase-europeeap.md.mp.microsoft.com.akadns.net. comment=\ + purchase.md.mp.microsoft.com.akadns.net list=windowsupdateslist +add address=ne-az-conspurchase-mp.trafficmanager.net. comment=\ + purchase-europeeap.md.mp.microsoft.com.akadns.net list=windowsupdateslist +add address=storeedgefd.dsx.mp.microsoft.com.edgekey.net. comment=\ + cdn.storeedgefd.dsx.mp.microsoft.com list=windowsupdateslist +add address=star.f.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedge.f.tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=a1996.dscd.akamai.net. comment=\ + wildcard.f.dl.delivery.mp.microsoft.com.edgesuite.net list=\ + windowsupdateslist +add address=cp801.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + cp801.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=glb.tas02.sls-prod.dcat.dsp.mp.microsoft.com. comment=\ + tas02.sls.update.microsoft.com list=windowsupdateslist +add address=cp601.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + cp601.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=star.sb.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedgeextensions.sb.tlu.dl.delivery.mp.microsoft.com list=\ + windowsupdateslist +add address=star.sf.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedge.sf.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=cdp-f-ssl-nlu-net.trafficmanager.net. comment=\ + star.sf.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=tm-pifd-prod-gbl-weight.trafficmanager.net. comment=\ + paymentinstruments.mp.microsoft.com list=windowsupdateslist +add address=10.30.30.33 comment=amster list=NoWG +add address=10.30.30.10 comment=MikroNUC disabled=yes list=NoWG +add address=89.110.101.17 comment=!!!VDSINA!!!! disabled=yes list=NoWG +add address=wg.vados.ru comment=VDSina-vpn list=VDSina +add address=80.85.244.9 list=TRUSTED +add address=disc801.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + disc801.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=185.71.70.78 disabled=yes list=TRUSTED +add address=176.53.203.171 disabled=yes list=TRUSTED +add address=176.53.203.170 disabled=yes list=TRUSTED +add address=176.53.202.194 disabled=yes list=TRUSTED +add address=89.110.101.17 comment="!!!VDSina Server!!!" list=NoVdsina +add address=dns.quad9.net comment=Quad9-dns disabled=yes list=Trusted-DNS +add address=dns.google comment=Google-dns list=Trusted-DNS +add address=security.cloudflare-dns.com comment=CloudFlare-dns list=\ + Trusted-DNS +add address=time.google.com comment=Google-time list=Trusted-NTP +add address=0.ru.pool.ntp.org comment=ru.pool.ntp.org disabled=yes list=\ + Trusted-NTP +add address=1.ru.pool.ntp.org disabled=yes list=Trusted-NTP +add address=2.ru.pool.ntp.org comment=2.ru.pool.ntp.org disabled=yes list=\ + Trusted-NTP +add address=3.ru.pool.ntp.org comment=3.ru.pool.ntp.org disabled=yes list=\ + Trusted-NTP +add address=cp.vdsina.com comment=VDSina-vpn list=VDSina +add address=vdsina.ru comment=VDSina-vpn list=VDSina +add address=ns.vados.ru comment=VDSina-vpn list=VDSina +add address=vdsina.com comment=VDSina-vpn list=VDSina +add address=cp.vdsina.ru comment=VDSina-vpn list=VDSina +add address=ns1.vdsina.ru comment=VDSina-vpn list=VDSina +add address=10.30.30.0/24 comment="Local Network" list=Local-Net +add address=10.8.0.0/24 comment="WireGuard Network" list=Local-Net +add address=146.120.64.208/29 comment="External Net" list=Unet +add address=esia.gosuslugi.ru comment=esia.gosuslugi.ru list=NoVdsina +add address=lk.gosuslugi.ru comment=lk.gosuslugi.ru list=NoVdsina +add address=trudvsem.ru comment=trudvsem.ru list=NoVdsina +add address=10.30.30.30 comment=miller disabled=yes list=NoWG +add address=10.30.30.33 comment="Direct connet to DNS servers" list=\ + Direct-DNS +add address=109.107.177.79 list=VPN-Server +add address=10.30.30.10 list=AWG-Proxy +add address=10.0.0.0/8 list=RFC1918 +add address=172.16.0.0/12 list=RFC1918 +add address=192.168.0.0/16 list=RFC1918 +add address=8.8.4.4 list=to_vpn +/ip firewall filter +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=12h chain=input comment="block honeypot DNS" \ + connection-state=new dst-port=53 in-interface="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 dst-port=29185 in-interface="ether1 - Unet" \ + protocol=tcp +add action=accept chain=input dst-port=29185 in-interface="ether1 - Unet" \ + protocol=udp +add action=accept chain=input comment="tcp Accept input DNS queries from LAN" \ + dst-port=53 protocol=tcp src-address=10.30.30.0/24 +add action=accept chain=input comment="udp Accept input DNS queries" \ + dst-port=53 protocol=udp src-address=10.30.30.0/24 +add action=accept chain=output comment="accept WireGuard" disabled=yes \ + dst-address-list=VPN-Server out-interface="ether1 - Unet" protocol=udp \ + src-port=13231 +add action=accept chain=output disabled=yes dst-address-list=VPN-Server \ + dst-port=29185 out-interface="ether1 - Unet" protocol=udp +add action=fasttrack-connection chain=forward comment="defconf: fasttrack" \ + connection-state=established,related,new disabled=yes routing-mark=\ + !To-VPN +add action=accept chain=output disabled=yes protocol=tcp src-port=443 +add action=accept chain=output disabled=yes src-address=127.0.0.1 +add action=accept chain=forward comment="defconf: accept in ipsec policy" \ + disabled=yes ipsec-policy=in,ipsec +add action=accept chain=forward comment="defconf: accept out ipsec policy" \ + disabled=yes ipsec-policy=out,ipsec +add action=accept chain=forward comment=\ + "defconf: accept established,related, untracked" connection-state=\ + established,related,untracked +add action=drop chain=forward comment="defconf: drop invalid" \ + connection-state=invalid in-interface="ether1 - Unet" src-address=\ + !10.30.30.0/24 +add action=drop chain=forward comment=\ + "defconf: drop all from WAN not DSTNATed" connection-nat-state=!dstnat \ + connection-state=new in-interface="ether1 - Unet" src-address-list=\ + !VDSina +add action=accept chain=input in-interface="ether1 - Unet" protocol=icmp \ + src-address-list=VDSina +add action=accept chain=input connection-state=established +add action=accept chain=input connection-state=related +/ip firewall mangle +add action=accept chain=prerouting comment=RFC1918 dst-address-list=RFC1918 \ + in-interface-list=!WAN +add action=mark-connection chain=prerouting comment=\ + "Transit for address-list \"to_vpn\"" connection-mark=no-mark \ + dst-address-list=to_vpn in-interface-list=!WAN new-connection-mark=\ + to-vpn-conn +add action=mark-routing chain=prerouting comment=\ + "Find routing over table r_to_vpn" connection-mark=to-vpn-conn \ + in-interface-list=!WAN new-routing-mark=r_to_vpn +add action=mark-connection chain=output comment="For this router" \ + connection-mark=no-mark dst-address-list=to_vpn new-connection-mark=\ + to-vpn-conn-local +add action=mark-routing chain=output comment="For this router" \ + connection-mark=to-vpn-conn-local new-routing-mark=r_to_vpn +add action=mark-routing chain=prerouting comment="Mark Routing main for NoWG" \ + disabled=yes new-routing-mark=main src-address-list=NoWG +add action=mark-routing chain=prerouting comment=\ + "Mark Routing main for NoVdsina" disabled=yes dst-address-list=NoVdsina \ + new-routing-mark=main src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=\ + "Mark Routing main for VDSina" disabled=yes dst-address-list=VPN-Server \ + new-routing-mark=main src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=\ + "Mark Routing main for MikroNuc" disabled=yes dst-address-list=AWG-Proxy \ + new-routing-mark=main src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=\ + "!!!ERROR Mark Routing main for Unet!!!" disabled=yes dst-address-list=\ + Unet new-routing-mark=main passthrough=no +add action=mark-routing chain=prerouting comment="Test-IP sites" disabled=yes \ + dst-address=!10.30.30.0/24 dst-address-list=Test-IP new-routing-mark=\ + To-VPN src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=FuckRKN disabled=yes \ + dst-address=!10.30.30.0/24 dst-address-list=RKN-dnsLookup \ + new-routing-mark=To-VPN passthrough=no src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment="VDSIna for All sites" \ + disabled=yes dst-address-list=!NoVdsina new-routing-mark=To-VPN \ + routing-mark=!main src-address=10.30.30.0/24 src-address-list=!NoWG +add action=change-mss chain=forward comment="MSS on WG" disabled=yes new-mss=\ + 1380 out-interface=WG protocol=tcp routing-mark=To-VPN tcp-flags=syn \ + tcp-mss=1381-65535 +add action=mark-connection chain=prerouting comment=\ + "Mark VPN connections to exclude from FastTrack" disabled=yes \ + new-connection-mark=VPN_No_FastTrack routing-mark=To-VPN +add action=mark-routing chain=prerouting comment="VPN Network" disabled=yes \ + dst-address=10.8.0.0/24 new-routing-mark=To-VPN src-address=10.30.30.0/24 +/ip firewall nat +add action=redirect chain=dstnat comment="udp Redirect DNS in NAT" disabled=\ + yes dst-port=53 protocol=udp src-address=10.30.30.0/24 src-address-list=\ + !NoWG to-addresses=10.30.30.33 to-ports=53 +add action=redirect chain=dstnat comment="tcp Redirect DNS in NAT" disabled=\ + yes dst-port=53 protocol=tcp src-address=10.30.30.0/24 src-address-list=\ + !NoWG to-addresses=10.30.30.33 to-ports=53 +add action=dst-nat chain=dstnat comment=\ + "53/tcp dst-nat to amster.loc. From VDSina Server" dst-port=53 \ + in-interface="ether1 - Unet" protocol=tcp src-address-list=VPN-Server \ + to-addresses=10.30.30.33 to-ports=53 +add action=dst-nat chain=dstnat comment=\ + "53/udp dst-nat to amster.loc. From VDSina Server" dst-port=53 protocol=\ + udp src-address-list=VPN-Server to-addresses=10.30.30.33 to-ports=53 +add action=dst-nat chain=dstnat disabled=yes dst-port=44333 in-interface=\ + "ether1 - Unet" protocol=udp src-address=!10.30.30.0/24 to-addresses=\ + 10.30.30.33 to-ports=44333 +add action=masquerade chain=srcnat comment="Default NAT" out-interface=\ + "ether1 - Unet" routing-mark=!To-VPN src-address=10.30.30.0/24 +add action=dst-nat chain=dstnat dst-port=44044 in-interface="ether1 - Unet" \ + protocol=udp src-address=109.107.177.79 to-addresses=10.30.30.33 \ + to-ports=44044 +add action=dst-nat chain=dstnat comment=amster.vados.ruhttps dst-port=443 \ + fragment=no in-interface="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=masquerade chain=srcnat comment=\ + "Nat Addresses for routing mark r_to_vpn" routing-mark=r_to_vpn +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 disabled=yes dst-address-list=\ + !NoVdsina out-interface=WG routing-mark=To-VPN src-address-list=!NoWG +add action=dst-nat chain=dstnat comment="Yandex.DNS Family" disabled=yes \ + dst-port=53 in-interface=Bridge-LAN protocol=udp src-address-list=KIDS \ + time=6h-15m,sun,mon,tue,wed,thu,fri,sat to-addresses=77.88.8.3 +add action=dst-nat chain=dstnat disabled=yes dst-port=53 in-interface=\ + Bridge-LAN protocol=tcp src-address-list=KIDS time=\ + 6h-15m,sun,mon,tue,wed,thu,fri,sat to-addresses=77.88.8.3 +/ip firewall raw +add action=drop chain=prerouting comment="Drop Honeypot Hackers" \ + in-interface="ether1 - Unet" src-address-list="Honeypot Hacker" +add action=accept chain=prerouting comment="Trusted DNS" disabled=yes \ + in-interface-list=WAN src-address-list=Trusted-DNS +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + extras.getpagespeed.com content=extras.getpagespeed.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=linux.duke.edu \ + content=linux.duke.edu disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=youtube.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + googleapis.com disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=ggpht.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=youtu.be \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=ytimg.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + googlevideo.com disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=gstatic.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + googleusercontent.com disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + nhacmp3youtube.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=rutube.ru \ + content=rutube.ru disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment="me.com raw" \ + content=me.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "icloud.com raw" content=icloud.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "smtp.mail.me.com raw" content=smtp.mail.me.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "smtp.mail.me.com.akadns.net raw" content=smtp.mail.me.com.akadns.net \ + disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "api.db-ip.com raw" content=api.db-ip.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + esia.gosuslugi.ru content=esia.gosuslugi.ru disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=gosuslugi.ru \ + content=gosuslugi.ru disabled=yes +/ip firewall service-port +set ftp disabled=yes +set tftp disabled=yes +set irc disabled=no +set sip disabled=yes +set pptp disabled=yes +set rtsp disabled=no +/ip ipsec settings +set accounting=no +/ip ipsec policy +set 0 disabled=yes dst-address=0.0.0.0/0 src-address=0.0.0.0/0 +/ip ipsec profile +set [ find default=yes ] dpd-interval=2m dpd-maximum-failures=5 +/ip proxy +set cache-administrator="" max-cache-size=none port=80,443 src-address=\ + 0.0.0.0 +/ip route +add check-gateway=none disabled=yes distance=1 dst-address=0.0.0.0/0 gateway=\ + WG routing-table=To-VPN scope=30 target-scope=10 +add disabled=yes distance=1 dst-address=0.0.0.0/0 gateway=10.30.30.33 \ + routing-table=r_to_vpn scope=30 target-scope=10 +add comment=VDSina-dns distance=1 dst-address=8.8.4.4/32 gateway=wg-VDSina +/ip service +set ftp disabled=yes +set telnet disabled=yes +set reverse-proxy disabled=yes +set ssh address=10.30.30.0/24 port=2222 +set winbox address=10.30.30.0/24 +set api address=10.30.30.0/24 +set api-ssl address=10.30.30.0/24 disabled=yes +set www-ssl certificate=Root-YE port=18443 +set www address=10.30.30.0/24 disabled=yes port=18880 +/ip service webserver +set acme-plain=no crl-plain=no graphs-plain=no graphs-secure=no index-plain=\ + no index-secure=no rest-secure=no scep-plain=no webfig-plain=no \ + webfig-secure=no +/ip ssh +set forwarding-enabled=both publickey-authentication-options=verify-required +/ip upnp +set enabled=yes +/ip upnp interfaces +add interface=Bridge-LAN type=internal +add forced-ip=146.120.64.211 interface="ether1 - Unet" type=external +add forced-ip=109.107.177.79 interface=*E type=external +add interface=lo type=internal +add interface=wlan2 type=internal +add interface=wlan1 type=internal +/ipv6 dhcp-client +add add-default-route=yes disabled=yes interface=*F rapid-commit=no request=\ + info use-interface-duid=yes validate-server-duid=no +/ipv6 dhcp-server option sets +add name=domain-search-set options=domain-search-list +add name="=\"Client ID\"" options=HostName +/ipv6 firewall address-list +add address=::/128 comment="defconf: unspecified address" list=bad_ipv6 +add address=::1/128 comment="defconf: lo" list=bad_ipv6 +add address=fec0::/10 comment="defconf: site-local" list=bad_ipv6 +add address=::ffff:0.0.0.0/96 comment="defconf: ipv4-mapped" list=bad_ipv6 +add address=::/96 comment="defconf: ipv4 compat" list=bad_ipv6 +add address=100::/64 comment="defconf: discard only " list=bad_ipv6 +add address=2001:db8::/32 comment="defconf: documentation" list=bad_ipv6 +add address=2001:10::/28 comment="defconf: ORCHID" list=bad_ipv6 +add address=3ffe::/16 comment="defconf: 6bone" list=bad_ipv6 +/ipv6 firewall filter +add action=accept chain=input comment=\ + "defconf: accept established,related,untracked" connection-state=\ + established,related,untracked +add action=drop chain=input comment="defconf: drop invalid" connection-state=\ + invalid +add action=accept chain=input comment="defconf: accept ICMPv6" protocol=\ + icmpv6 +add action=accept chain=input comment="defconf: accept UDP traceroute" \ + dst-port=33434-33534 protocol=udp +add action=accept chain=input comment=\ + "defconf: accept DHCPv6-Client prefix delegation." dst-port=546 protocol=\ + udp src-address=fe80::/10 +add action=accept chain=input comment="defconf: accept IKE" dst-port=500,4500 \ + protocol=udp +add action=accept chain=input comment="defconf: accept ipsec AH" protocol=\ + ipsec-ah +add action=accept chain=input comment="defconf: accept ipsec ESP" protocol=\ + ipsec-esp +add action=accept chain=input comment=\ + "defconf: accept all that matches ipsec policy" ipsec-policy=in,ipsec +add action=drop chain=input comment=\ + "defconf: drop everything else not coming from LAN" in-interface-list=\ + !LAN +add action=accept chain=forward comment=\ + "defconf: accept established,related,untracked" connection-state=\ + established,related,untracked +add action=drop chain=forward comment="defconf: drop invalid" \ + connection-state=invalid +add action=drop chain=forward comment=\ + "defconf: drop packets with bad src ipv6" src-address-list=bad_ipv6 +add action=drop chain=forward comment=\ + "defconf: drop packets with bad dst ipv6" dst-address-list=bad_ipv6 +add action=drop chain=forward comment="defconf: rfc4890 drop hop-limit=1" \ + hop-limit=equal:1 protocol=icmpv6 +add action=accept chain=forward comment="defconf: accept ICMPv6" protocol=\ + icmpv6 +add action=accept chain=forward comment="defconf: accept HIP" protocol=139 +add action=accept chain=forward comment="defconf: accept IKE" dst-port=\ + 500,4500 protocol=udp +add action=accept chain=forward comment="defconf: accept ipsec AH" protocol=\ + ipsec-ah +add action=accept chain=forward comment="defconf: accept ipsec ESP" protocol=\ + ipsec-esp +add action=accept chain=forward comment=\ + "defconf: accept all that matches ipsec policy" ipsec-policy=in,ipsec +add action=drop chain=forward comment=\ + "defconf: drop everything else not coming from LAN" in-interface-list=\ + !LAN +/ipv6 nd +set [ find default=yes ] advertise-dns=yes disabled=yes interface=Bridge-LAN \ + managed-address-configuration=yes other-configuration=yes pref64=::/64 +/ipv6 nd prefix +add autonomous=no disabled=yes interface=Bridge-LAN on-link=no prefix=none +/ipv6 nd prefix default +set dhcp6-pd-preferred=yes +/ipv6 nd proxy +add disabled=yes interface=lo +/ipv6 nd settings +set router-advertisement-route-distance=100 +/routing settings +set single-process=no +/system clock +set time-zone-name=Europe/Moscow +/system clock manual +set time-zone=+03:00 +/system identity +set name=MikroMaster +/system logging +add action=email disabled=yes regex="* added|changed|removed *" topics=\ + system,info +/system ntp client +set enabled=yes +/system ntp server +set enabled=yes manycast=yes multicast=yes use-local-clock=yes +/system ntp client servers +add address=0.ru.pool.ntp.org +add address=1.ru.pool.ntp.org +add address=2.ru.pool.ntp.org +add address=3.ru.pool.ntp.org +add address=time.google.com disabled=yes +/system package update +set check-certificate=yes-without-crl ip-version=ipv4 +/system scheduler +add comment="Every Day Set Global Environment Variables" name=AM-SetGlobalEnv \ + on-event="/system/script { run AM-GlobalConfig; run AM-GlobalFunc; }" \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-time=startup +add comment="Every Day Check For Update Scripts" interval=1d name=\ + AM-ScriptInstallUpdate on-event=\ + ":global ScriptInstallUpdate; \$ScriptInstallUpdate;" policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-time=startup +add comment="Update RKN DNS Looup" disabled=yes interval=20m name=\ + AM-RKN-dnsLookup on-event="/system/script { run AM-RKN-dnsLookup; }" \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-time=startup +/system watchdog +set watchdog-timer=no +/tool e-mail +set certificate-verification=no from=MikroVados port=587 \ + server=smtp.mail.me.com tls=starttls user=vadossio@icloud.com +/tool mac-server +set allowed-interface-list=LAN +/tool mac-server mac-winbox +set allowed-interface-list=LAN +/tool netwatch +add certificate=DigiCert-Global-Root-CA check-certificate=no comment="doh, doh\ + -url=https://security.cloudflare-dns.com/dns-query, notify, name=CloudFlar\ + e-doh IPv4 1" disabled=yes down-script="" host=1.1.1.1 http-codes="" \ + interval=10s name="CloudFlare-doh IPv4 1" port=443 test-script="" type=\ + https-get up-script="" +add check-certificate=no comment="doh-fallback, doh-url=https://security.cloud\ + flare-dns.com/dns-query, doh-cert=DigiCert Global Root CA, notify, name=Cl\ + oudFlare-doh IPv4" disabled=yes down-script="" host=1.0.0.1 http-codes="" \ + name="CloudFlare-doh IPv4" port=443 test-script="" type=https-get \ + up-script="" +add comment="dns, notify, name=Google-DNS IPv4" disabled=yes dns-server=\ + 8.8.8.8 down-script="" host=dns.google http-codes="" name=\ + "Google-DNS IPv4" test-script="" type=dns up-script="" +add certificate=GTS-Root-R4 check-certificate=yes comment="doh-fallback, doh-u\ + rl=https://dns.google/dns-query, doh-cert=GTS Root R1, notify, name=Google\ + -DOH IPv4" disabled=yes dns-server=8.8.4.4 down-script="" host=dns.google \ + http-codes="" name="Google-DOH IPv4" port=443 record-type=NS src-address=\ + "" test-script="" type=dns up-script="" +add comment="dns-fallback, notify, name=Cuad9-DOH IPv4" disabled=yes \ + dns-server=9.9.9.9 down-script="" host=dns9.quad9.net http-codes="" \ + interval=10s name="Cuad9-DOH IPv4" src-address=146.120.64.211 \ + test-script="" timeout=800ms type=dns up-script="" +add certificate=DigiCert-Assured-ID-Root-CA comment="doh-fallback, doh-url=htt\ + ps://dns.quad9.net/dns-query, name=Cuad9-DOH IPv4" disabled=yes \ + down-script="" host=149.112.112.112 http-codes="" interval=10s name=\ + "Cuad9-DOH IPv4" port=443 test-script="" type=https-get up-script="" +add comment="dns-fallback, notify, name=ns1.unet.ws" disabled=yes \ + down-script="" host=91.192.189.2 http-codes="" interval=10s name=\ + ns1.unet.ws test-script="" type=simple up-script="" +add check-certificate=yes comment=\ + "doh, doh-url=https://vds.vados.ru/vds-query, name=vds.vados.ru" \ + disabled=yes down-script="" host=109.107.177.79 http-codes="" name=\ + vds.vados.ru port=443 test-script="" type=https-get up-script="" +/user aaa +set accounting=no diff --git a/MikroMaster/20260703/20260703224002-Config.rsc b/MikroMaster/20260703/20260703224002-Config.rsc new file mode 100644 index 0000000..6a44aac --- /dev/null +++ b/MikroMaster/20260703/20260703224002-Config.rsc @@ -0,0 +1,3744 @@ +# 2026-07-03 22:40:05 by RouterOS 7.23.1 +# software id = A8L5-07YF +# +# model = RB952Ui-5ac2nD +# serial number = D3D50CEDCD38 +/interface bridge +add admin-mac=48:8F:5A:8E:1A:BF auto-mac=no dhcpv6-agent-circuit-id=\ + "\$(INTERFACE):\$(VID)" dhcpv6-agent-remote-id="\$(BRIDGEMAC)" name=\ + Bridge-LAN port-cost-mode=short +/interface ethernet +set [ find default-name=ether1 ] comment="WAN - Unet" loop-protect=off name=\ + "ether1 - Unet" rx-flow-control=auto tx-flow-control=auto +set [ find default-name=ether2 ] comment=LAN-2 +set [ find default-name=ether3 ] advertise="10M-baseT-half,10M-baseT-full,100M\ + -baseT-half,100M-baseT-full,1G-baseT-full,1G-baseX" comment=LAN-3 +set [ find default-name=ether4 ] comment=LAN-4 +set [ find default-name=ether5 ] advertise="10M-baseT-half,10M-baseT-full,100M\ + -baseT-half,100M-baseT-full,1G-baseT-full,1G-baseX" comment=LAN-5 \ + loop-protect=on poe-out=off rx-flow-control=auto tx-flow-control=auto +/interface wireless +# managed by CAPsMAN +set [ find default-name=wlan1 ] country=belarus mode=ap-bridge ssid=vados \ + wireless-protocol=802.11 +# managed by CAPsMAN +set [ find default-name=wlan2 ] country=belarus mode=ap-bridge ssid=vados5g \ + wireless-protocol=802.11 +/interface wireguard +add disabled=yes listen-port=33033 mtu=1360 name=NUC +add comment=WG disabled=yes listen-port=13231 mtu=1320 name=WG +add disabled=yes listen-port=21641 mtu=1420 name=wg-VDSina +/interface list +add include=static name=LAN +add name=Internet +add include=Internet name=WAN +/interface wireless security-profiles +set [ find default=yes ] authentication-types=wpa-psk,wpa2-psk mode=\ + dynamic-keys supplicant-identity=MikroTik +/iot wiliot servers +set *1 address=mqtt.us-east-2.prod.wiliot.cloud name="Wiliot US East" +/ip dhcp-server option +add code=12 name=HostName +add code=119 force=yes name=domain-search-list value="0x03'WORKGROUP'0x00" +/ip dhcp-server option sets +add name=HP1505n options=HostName +add name=StartLife1 options=HostName +add name=amsterDev options=HostName +add name=MiTV options=HostName +add name=miller options=HostName +add name=amster options=HostName +add name=garage options=HostName +add name=domain-search-set options=domain-search-list +add name=VADOS-LEN options=HostName +add name=VADOS-NUC options=HostName +add name=MikroNUC options=HostName +add name=master options=HostName +add name=MikroYellow options=HostName +add name="=\"Client ID\"" options=HostName +add name=iVados options=HostName +/ip dns forwarders +add disabled=yes dns-servers=1.0.0.1,1.1.1.1 name=blsp.at verify-doh-cert=no +add comment=Kra disabled=yes dns-servers=1.0.0.1,1.1.1.1 name=slon2.to \ + verify-doh-cert=no +add disabled=yes dns-servers=1.1.1.1,1.0.0.1 name=slon3.at verify-doh-cert=no +add disabled=yes dns-servers=1.0.0.1,1.1.1.1 name=slon3.cc verify-doh-cert=no +add disabled=yes dns-servers=1.1.1.1,1.0.0.1 name=bs2web.at verify-doh-cert=\ + no +add disabled=yes dns-servers=1.1.1.1,1.0.0.1 name=bs2best.at verify-doh-cert=\ + no +add disabled=yes dns-servers=1.0.0.1,1.1.1.1 name=psrms.is verify-doh-cert=no +/ip ipsec proposal +set [ find default=yes ] disabled=yes +/ip pool +add name=dhcp ranges=10.30.30.83-10.30.30.254 +/ip dhcp-server +add add-arp=yes address-pool=dhcp always-broadcast=yes bootp-support=none \ + dhcp-option-set=domain-search-set interface=Bridge-LAN lease-time=10m \ + name=masterDHCP server-address=10.30.30.81 +/ip smb users +set [ find default=yes ] disabled=yes +add disabled=yes name=vados +/ipv6 dhcp-client option +add code=119 name=domain-search-list value="0x03'WORKGROUP'0x00" +add code=12 name=HostName value="\$(HOSTNAME)" +add code=61 name=DUID value=0x00030001488f5a8e1abc +add code=61 name=clientid +/ipv6 dhcp-server option +add code=119 name=domain-search-list value="0x03'WORKGROUP'0x00" +add code=12 name=HostName value="\$(HOSTNAME)" +add code=61 name=CLIENT_DUID +add code=61 name=CLIENT_MAC +/ppp profile +set *FFFFFFFE use-upnp=no +/routing bgp template +set default disabled=no output.network=bgp-networks +/routing table +add disabled=no fib name=To-VPN +add disabled=no fib name=r_to_vpn +/system logging action +add email-start-tls=yes email-to=vados@vados.ru name=email target=email +/system script +add dont-require-permissions=no name=fetchCustom owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + global GlobalScriptsUrl \"https://ros.vados.ru/\";\r\ + \n\r\ + \n#/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@1\ + 0.30.30.86.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.86.pub\";\ + \n\r\ + \n#:local Script AM-setup\ + \n;\r\ + \n#/system/script/add name=\$Script owner=\$Script source=([ /tool/fetch c\ + heck-certificate=yes-without-crl url=(\$GlobalScriptsUrl . \$Script . \".r\ + sc\") output=user as-value ]->\"data\");\r\ + \n\ + \n#/usb1/mikro_bak_rsa.pub\ + \n\ + \n\r\ + \n#\ + \n\r\ + \n#/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@1\ + 0.30.30.10.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.10.pub\";\ + \n\r\ + \n#\r\ + \n\ + \n#root.mnuc.backuper\ + \n\ + \n\r\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@10\ + .30.30.81.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.81.pub\";\r\ + \n\ + \n#:local Script AM-GlobalConfig;\ + \n\r\ + \n#/system/script/add name=\$Script owner=\$Script source=([ /tool/fetch c\ + heck-certificate=yes-without-crl url=(\$GlobalScriptsUrl . \$Script . \".r\ + sc\") output=user as-value ]->\"data\");\r\ + \n\ + \n#/usb1/mikro_bak_rsa.pub\ + \n#:local FetchFile AM-DOHCert.rsc\ + \n\ + \n\r\ + \n\r\ + \n#\ + \n:global MkDir;\ + \n\r\ + \n\ + \n#:local FetchFile Binary.backup\ + \n:local localDir \"\";\ + \n\ + \n\r\ + \n#\$MkDir \$localDir;\r\ + \n\ + \n#\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \$FetchFile) dst-path=(\ + \$localDir . \$FetchFile);\r\ + \n" +add comment="Global Config Script" dont-require-permissions=no name=\ + AM-GlobalConfig owner=AM-GlobalConfig policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\r\ + \n# RouterOS script: AM-GlobalConfig\r\ + \n# Script comment: Global Config Script\r\ + \n# Copyright (c) 2007-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# Warning: Dont touch this line!\r\ + \n:global Identity [/system/identity/get name];\r\ + \n:global GlobalConfReady false;\r\ + \n#\r\ + \n#\r\ + \n# Global Url For Amster scripts to fetch\r\ + \n# most be defined in AM-Init-Script or AM-setup scripts\r\ + \n:global GlobalScriptsUrl \"https://ros.vados.ru/\";\r\ + \n:global ScriptsUrlSuffix (a);\r\ + \n:global CheckSumsVerify true;\r\ + \n\r\ + \n:global ScriptUpdatesCRLF true;\r\ + \n:global CommentsInScripts true;\r\ + \n\r\ + \n# Debug output:\r\ + \n:global PrintDebug true; #false;\r\ + \n\r\ + \n# Debug output for specific script:\r\ + \n#:set (\$PrintDebugOverride->\"AM-GlobalFunc\") true;\r\ + \n\r\ + \n# Debug logs\r\ + \n# Other actions (disk, email, remote or support) can be used as well.\r\ + \n# I do not recommend using echo - use debug output instead (https://rsc.\ + eworm.de/main/DEBUG.html#debug-output).\r\ + \n#/system/logging/add topics=script,debug action=memory;\r\ + \n\r\ + \n:global MikrotikUpgradeUrl \"https://upgrade.mikrotik.com/routeros\";\r\ + \n:global Domain \"WORKGROUP\";\r\ + \n\r\ + \n:global EmailGeneralTo \"vados@vados.ru\";\r\ + \n#:global EmailGeneralCc \"\";\r\ + \n\r\ + \n# \$ScriptInstallUpdate mod/notification-telegram\r\ + \n:global TelegramTokenId \"8390868324:AAG3_d1hfVR2M6pGAgDK6ZvhOe4J97nyopw\ + \";\r\ + \n:global TelegramChatId \"-1003631309063\"; #\"454403445\";\r\ + \n# Use this to send notifications to a specific topic in group.\r\ + \n#:global TelegramThreadId \"30\";\r\ + \n# Using telegram-chat you have to define trusted chat ids (not group ids\ + !)\r\ + \n# or user names. Groups allow to chat with devices simultaneously.\r\ + \n:global TelegramChatIdsTrusted {\r\ + \n \"454403445\"\r\ + \n \"-1003631309063\"\r\ + \n \"-5124482807\"\r\ + \n \"1087968824\";\r\ + \n};\r\ + \n# \"-5294757340\";\r\ + \n\r\ + \n:global TelegramChatGroups \"(all)\";\r\ + \n#:global TelegramChatGroups \"(all|home|office)\";\r\ + \n\r\ + \n:global NotificationFunctions {\r\ + \n \"email\"\r\ + \n \"telegram\";\r\ + \n};\r\ + \n# Toggle this to disable symbols in notifications.\r\ + \n:global NotificationsWithSymbols true;\r\ + \n:global TerminalColorOutput true;\r\ + \n\r\ + \n:global DetectIpAddrDefault \"https://ipv4.mikrotik.ovh/\";\r\ + \n:global DetectIpAddrFallback \"https://api.ipify.org/\";\r\ + \n\r\ + \n## Update channel. Possible values: stable, long-term, testing, developm\ + ent\r\ + \n:global updateChannel \"stable\";\r\ + \n\r\ + \n:global CertRenewUrl (\$GlobalScriptsUrl . \"certs/\" . \$Identity . \"/\ + \");\r\ + \n:global CertRenewTime 2w;\r\ + \n:global CertRenewPass (a); #{\r\ + \n# \"\";\r\ + \n# \"v3ry-s3cr3t\";\r\ + \n# \"4n0th3r-s3cr3t\";\r\ + \n#};\r\ + \n:global CertWarnTime 1w;\r\ + \n:global CertIssuedExportPass (a); # {\r\ + \n# \"\";\r\ + \n# \"cert1-cn\"=\"v3ry-s3cr3t\";\r\ + \n# \"cert2-cn\"=\"4n0th3r-s3cr3t\";\r\ + \n#};\r\ + \n\r\ + \n# Script BackupAndUpdate mode, possible values: backup,\r\ + \n# updateOnce - Update once as \"osnotify\" and back \"osnotify\" mode (i\ + n terminal run :set OSUpdateMode updateOnce; \$OSUpdateMode;). \r\ + \n# osupdate - Update if available and creates backups before/after update\ + \_(ignores `forceBackup`)\r\ + \n# Set `forceBackup` to true to always create backups, even\ + \_without updates\r\ + \n# osnotify - Set `forceBackup` to always create backups on every run\r\ + \n:global DevInfoIncludeIP true;\r\ + \n:global BackupAndUpdateMode \"osnotify\"\r\ + \n\r\ + \n:global forceBackup true;\r\ + \n:global BackupPassword \"Peskar55\";\r\ + \n\r\ + \n# SFTP Backup Variables\r\ + \n:global BackupRandomDelay 0;\r\ + \n:global BackupUploadUrl \"sftp://amster.vados.ru/upload/\";\r\ + \n:global BackupUploadUser \$Identity;\r\ + \n:global BackupUploadPass \"root.mnuc.backuper\";\r\ + \n\r\ + \n:global BackupSendBinary true;\r\ + \n:global BackupSendExport true;\r\ + \n:global BackupSendGlobalConfig true;\r\ + \n:global BackupSendScripts true;\r\ + \n\r\ + \n# Remove local file after uploading if no errors\r\ + \n:global BackupRmLocal true;\r\ + \n\r\ + \n# Local Backups Root Directory \r\ + \n:global BackupLocalRoot \"tmpfs\";\r\ + \n\r\ + \n# Encrypt Backup\r\ + \n:global BackupEncrypt true;\r\ + \n\r\ + \n# Sensitive information in Backups\r\ + \n:global BackupSens true;\r\ + \n\r\ + \n# User Export\r\ + \n:global BackupUser true;\r\ + \n\r\ + \n# License Export (not for CHR, will silently skip)\r\ + \n:global BackupLicense false;\r\ + \n\r\ + \n# SSH Keys\r\ + \n:global BackupSshKeys true;\r\ + \n\r\ + \n# Certificate Export\r\ + \n:global BackupCerts true;\r\ + \n\r\ + \n# Certificate Password\r\ + \n:global BackupCertsPasswd \"\";\r\ + \n\r\ + \n# User-Manager Export\r\ + \n:global BackupUserMan false;\r\ + \n\r\ + \n# The Dude Export\r\ + \n:global BackupDude false;\r\ + \n\r\ + \n# User Files to export, comma-separated string or array of strings\r\ + \n# User Files are not removed on backup\r\ + \n# Any directory paths will be removed (/ -> _) on remote file\r\ + \n# Nonpresent files are silently skipped\r\ + \n:global BackupUserList \"autosupout.rif,autosupout.old.rif\";\r\ + \n\r\ + \n# load functions and any custom scripts\r\ + \n# [ /system/script/find where name=\"global-config-ov\ + erlay\" ], \\\r\ + \n# [ /system/script/find where name~\"^global-config-o\ + verlay\\\\.d/.\" ]\r\ + \n#\r\ + \n#:foreach Script in=([ /system/script/find where name=\"Amster-TGglobalV\ + ars\" ], [ /system/script/find where name=\"Amster-TGglobalFunc\" ]) do={\ + \r\ + \n# :onerror Err {\r\ + \n# /system/script/run \$Script;\r\ + \n# } do={\r\ + \n# :log error (\"Loading configuration from configs and functions\"\ + \_. [ /system/script/get \$Script name ] . \" failed: \" . \$Err);\r\ + \n# }\r\ + \n#}\r\ + \n#:log info \"\\ndevMode = \$devMode\";\r\ + \n#:log info \"\\ndevRunning = \$devRunning\";\r\ + \n:foreach Script in=[ /system/script/find where source~\"^#!rsc by Vados \ + GlobalRUN\\r\?\\n\" ] do={\r\ + \n :onerror Err {\r\ + \n /system/script/run \$Script;\r\ + \n } do={\r\ + \n :log error (\"Run script \" . [ /system/script/get \$Script name \ + ] . \" width marker \\\" GlobalRUN\\\" failed: \" . \$Err);\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n# signal we are ready\r\ + \n:set GlobalConfReady true;\r\ + \n:while (\$GlobalConfReady != true) do={:delay 500ms};\r\ + \n" +add comment="Global functions" dont-require-permissions=no name=AM-GlobalFunc \ + owner=AM-GlobalFunc policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\r\ + \n# RouterOS script: AM-GglobalFunc\r\ + \n# Script comment: Global functions\r\ + \n# Copyright (c) 2005-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version=7.19\r\ + \n# requires device-mode, fetch, scheduler\r\ + \n:local ExitOK false;\r\ + \n:local ScriptName [ :jobname ];\r\ + \n#:global checkRunJob \$SriptName;\r\ + \n#:global fixCRLF;\r\ + \n#:if (\$fixCRLF != false) do={\r\ + \n#:foreach fixScript in=([ /system/script/find where name~\"*\" ]) do={/s\ + ystem/script/set source=[ :tocrlf [ get \$fixScript source ] ] \$fixScript\ + }\r\ + \n#:if (\$fixCRLF != \"LF\") do={ /system/script/set source=[ :tocrlf [ g\ + et \$fixScript source ] ] \$fixScript};};\r\ + \n#}\r\ + \n:global GlobalFuncReady false;\r\ + \n\r\ + \n# Git commit id & info, expected configuration version\r\ + \n:global CommitId \"main/729/f42d43ae\";\r\ + \n:global CommitTAG \"unknown\";\r\ + \n:global CommitInfo \"Autocommit in repo: ros.vados.ru, generated by owne\ + r: root, in 00:05:03 01.07.2026.\";\r\ + \n\r\ + \n# The variables are received right here.\r\ + \n:global GlobalConfVersion 140;\r\ + \n\r\ + \n:global SumsDirAndFileName \"tmp/checksums.json\";\r\ + \n\r\ + \n:global Identity [/system/identity/get name];\r\ + \n:global IdentityShort [:pick \$Identity 0 18];\r\ + \n\r\ + \n:global devBoardName [/system/resource/get board-name];\r\ + \n:global devMode [/system/device-mode/get mode];\r\ + \n:global devCurArch [/system/resource/get architecture-name];\r\ + \n:global devCurVersion [/system/resource/get version];\r\ + \n\r\ + \n# Variables defined in AM-GlobalConfig.rsc\r\ + \n:global TerminalColorOutput;\r\ + \n:global CommentsInScripts;\r\ + \n:global DetectIpAddrDefault;\r\ + \n:global DetectIpAddrFallback;\r\ + \n:global updateChannel;\r\ + \n:global Domain;\r\ + \n:global EmailGeneralTo;\r\ + \n:global BackupAndUpdateMode;\r\ + \n\r\ + \n# Single functions, without nested functions.\r\ + \n:global MiniDateTimeStamp;\r\ + \n:global MicroDateTimeStamp;\r\ + \n\r\ + \n# Include globals \$PrintDebug and \$PrintDebugOverride\r\ + \n:global LogPrint;\r\ + \n\r\ + \n# DeviceInfo and Updates\r\ + \n:global IsCheckUpdates;\r\ + \n:global WaitCheckUpdates;\r\ + \n:global GetPubIp;\r\ + \n\r\ + \n:global GetArrDeviceInfo;\r\ + \n:global WaitArrDeviceInfo;\r\ + \n\r\ + \n:global devModel;\r\ + \n:global devRunningMode;\r\ + \n\r\ + \n:global devRbRevision;\r\ + \n:global devRbSerialNumber;\r\ + \n:global devRbVerAvail;\r\ + \n\r\ + \n:global runningChannelVersion;\r\ + \n:global runningChannel;\r\ + \n:global runningVersion;\r\ + \n\r\ + \n:global devBuildTime;\r\ + \n:global ROsVerAvail;\r\ + \n:global PkgUpdStatus;\r\ + \n:global currentUpdateChannel;\r\ + \n\r\ + \n:global ScriptInstallUpdate;\r\ + \n\r\ + \n:global DeviceInfo;\r\ + \n\r\ + \n:global OldMode;\r\ + \n\r\ + \n:global ParseKeyValueStore;\r\ + \n:global RandomDelay;\r\ + \n:global GetRandomNumber;\r\ + \n:global EscapeForRegEx;\r\ + \n:global CharacterMultiply;\r\ + \n:global CharacterReplace;\r\ + \n:global CleanFilePath;\r\ + \n:global CleanName;\r\ + \n\r\ + \n:global CommitBrief;\r\ + \n\r\ + \n:global EitherOr;\r\ + \n:global FormatLine;\r\ + \n:global GetRandom20CharAlNum;\r\ + \n:global GetRandom20CharHex;\r\ + \n:global GetRandomNumber;\r\ + \n:global Grep;\r\ + \n:global IfThenElse;\r\ + \n:global MAX;\r\ + \n:global MIN;\r\ + \n:global HumanReadableNum;\r\ + \n\r\ + \n:global IsFullyConnected;\r\ + \n:global IsDNSResolving;\r\ + \n:global IsTimeSync;\r\ + \n:global IsTimeSyncCached;\r\ + \n:global IsTimeSyncResetNtp;\r\ + \n\r\ + \n:global MkDir;\r\ + \n:global RmDir;\r\ + \n:global RmFile;\r\ + \n:global FileGet;\r\ + \n:global Unix2Dos;\r\ + \n:global UrlEncode;\r\ + \n:global WaitForFile;\r\ + \n:global ScriptLock;\r\ + \n:global SendTelegram;\r\ + \n:global NotificationFunctions;\r\ + \n:global SendNotification;\r\ + \n:global SendNotification2;\r\ + \n:global SymbolForNotification;\r\ + \n:global SymbolByUnicodeName;\r\ + \n:global ValidateSyntax;\r\ + \n:global CheckSumsVerify;\r\ + \n:global GlobalConfChanges;\r\ + \n:global GlobalConfMigration;\r\ + \n:global VersionToNum;\r\ + \n:global RequiredRouterOS;\r\ + \n:global ExitError;\r\ + \n:global ExitOnError;\r\ + \n\r\ + \n:global FetchHugeFiles;\r\ + \n:global FetchUserAgentStr;\r\ + \n:global FileExists;\r\ + \n:global CertificateAvailable;\r\ + \n:global CertificateDownload;\r\ + \n:global CertificateNameByCN;\r\ + \n:global CharacterMultiply;\r\ + \n\r\ + \n:global InspectVar;\r\ + \n:global InspectVarRet;\r\ + \n:global ParseCustom;\r\ + \n\r\ + \n:set IsCheckUpdates do={\r\ + \n :local isInfo [:tobool \$1];\r\ + \n :global updateChannel;\r\ + \n :global PkgUpdStatus;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n :global arrDeviceInfo;\r\ + \n :log info (\$0 . \" \\\$isInfo = \" . \$isInfo); \r\ + \n :local CurrentChannel [ /system/package/update/get channel ];\r\ + \n :if ([ :len \$updateChannel ] > 0 && \$CurrentChannel != \$updateChann\ + el) do={\r\ + \n :retry command={/system/package/update set channel=\$updateChannel} \ + \_delay=300ms max=5 on-error={};\r\ + \n :log info (\$0 . \" Set updates channel to: \$updateChannel\");\r\ + \n }\r\ + \n :local Update [ /system/package/update/get ];\r\ + \n :local Channel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set currentUpdateChannel \$Channel;\r\ + \n :log info (\$0 . \" Update Channel: \" . \$Channel . \".\");\r\ + \n :local StatusPkg \"undefined\";\r\ + \n :log info (\$0 . \" Checking for updates...\");\r\ + \n :retry command={:set \$StatusPkg ([/system/package/update/check-for-up\ + dates without-paging as-value]->\"status\")} \\\r\ + \n delay=300ms max=5 on-error={};\r\ + \n :log info (\$0 . \" \\\$StatusPkg = \" . \$StatusPkg);\r\ + \n :if (\$StatusPkg = \"New version is available\") do={ :set PkgUpdStatu\ + s true; } else={ :set PkgUpdStatus false; }\r\ + \n :set ROsVerAvail [ :tostr [ /system/package/update/get latest-version \ + ] ];\r\ + \n :log info (\$0 . \" \\\$PkgUpdStatus = \" . \$PkgUpdStatus);\r\ + \n :if (\$isInfo != false || \$PkgUpdStatus = true) do={\r\ + \n :log info (\$0 . \" \\\$PkgUpdStatus = \" . \$PkgUpdStatus);\r\ + \n :if ([ :typeof \$arrDeviceInfo ] != \"array\") do={\r\ + \n :set arrDeviceInfo [:toarray \$arrDeviceInfo];\r\ + \n }\r\ + \n :retry command={:set (\$arrDeviceInfo->\"devUpdates\") [ /system/pac\ + kage/update/get ]} delay=500ms max=5 on-error={:log error (\"Error\")};\r\ + \n :return true;\r\ + \n } else={\r\ + \n :return \$PkgUpdStatus;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set WaitCheckUpdates do={\r\ + \n :global IsCheckUpdates;\r\ + \n :global PkgUpdStatus;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n :global arrDeviceInfo;\r\ + \n :local Status \"\";\r\ + \n :local Update;\r\ + \n :local WaitCount 0;\r\ + \n :if ([ \$IsCheckUpdates true ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n :set Status [ :tostr [ /system/package/update/get status ] ];\r\ + \n :while ((\$Status = \"\" || \$Status = \"finding out latest version...\ + \") && \$WaitCount < 60) do={\r\ + \n :delay 1s;\r\ + \n :set WaitCount (\$WaitCount + 1);\r\ + \n :set Status [ :tostr [ /system/package/update/get status ] ];\r\ + \n }\r\ + \n :set Update [ /system/package/update/get ];\r\ + \n :set currentUpdateChannel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set ROsVerAvail [ :tostr (\$Update->\"latest-version\") ];\r\ + \n :if ((\$Update->\"status\") = \"New version is available\") do={\r\ + \n :set PkgUpdStatus true;\r\ + \n } else={\r\ + \n :set PkgUpdStatus false;\r\ + \n }\r\ + \n :if ([ :typeof \$arrDeviceInfo ] != \"array\") do={\r\ + \n :set arrDeviceInfo [:toarray \$arrDeviceInfo];\r\ + \n }\r\ + \n :set (\$arrDeviceInfo->\"devUpdates\") \$Update;\r\ + \n :if (\$Status = \"\" || \$Status = \"finding out latest version...\") \ + do={\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set WaitArrDeviceInfo do={\r\ + \n :global GetArrDeviceInfo;\r\ + \n :while ([ \$GetArrDeviceInfo ] = false) do={\r\ + \n :delay 1s;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set GetArrDeviceInfo do={\r\ + \n :global LogPrint;\r\ + \n :global arrDeviceInfo;\r\ + \n :global devBoardName;\r\ + \n :global devModel;\r\ + \n :global devRunning;\r\ + \n :global devCurArch;\r\ + \n :global devRbRevision;\r\ + \n :global devRbSerialNumber;\r\ + \n :global devBuildTime;\r\ + \n :global runningChannelVersion;\r\ + \n :global runningChannel;\r\ + \n :global runningVersion;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n\r\ + \n :local DeviceInfo;\r\ + \n :local Resource [/system/resource/get];\r\ + \n :local Update [ /system/package/update/get ];\r\ + \n :local VersionString [ :tostr (\$Resource->\"version\") ];\r\ + \n :local ChannelStart [ :find \$VersionString \" (\" ];\r\ + \n :local RouterBoard;\r\ + \n :local IsRouterBoard false;\r\ + \n :local RunningMode \"\";\r\ + \n\r\ + \n :set devCurArch [ :tostr (\$Resource->\"architecture-name\") ];\r\ + \n :set devBuildTime [ :tostr (\$Resource->\"build-time\") ];\r\ + \n :set runningChannelVersion \$VersionString;\r\ + \n :set runningVersion \$VersionString;\r\ + \n :set runningChannel \"\";\r\ + \n\r\ + \n :if ([ :typeof \$ChannelStart ] = \"num\" && \$ChannelStart >= 0) do=\ + {\r\ + \n :set runningVersion [ :pick \$VersionString 0 \$ChannelStart ];\r\ + \n :local ChannelRest [ :pick \$VersionString (\$ChannelStart + 2) [ :\ + len \$VersionString ] ];\r\ + \n :local ChannelEnd [ :find \$ChannelRest \")\" ];\r\ + \n :if ([ :typeof \$ChannelEnd ] = \"num\" && \$ChannelEnd >= 0) do={\ + \r\ + \n :set runningChannel [ :pick \$ChannelRest 0 \$ChannelEnd ];\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :if ([:pick \$devBoardName 0 3] != \"CHR\" or [:pick \$devBoardName 0\ + \_3] != \"x86\") do={\r\ + \n :do {\r\ + \n :set RouterBoard [[ :parse \"/system/routerboard/get\" ]];\r\ + \n# :set RouterBoard [ /system/routerboard/get ];\r\ + \n :if ((\$RouterBoard->\"routerboard\") = true) do={\r\ + \n :set IsRouterBoard true;\r\ + \n }\r\ + \n } on-error={}\r\ + \n }\r\ + \n\r\ + \n :do {\r\ + \n :set RunningMode [ /system/device-mode/get mode ];\r\ + \n } on-error={\r\ + \n :do {\r\ + \n :set RunningMode [ /system/device-mode/get running ];\r\ + \n } on-error={\r\ + \n :set RunningMode \"\";\r\ + \n }\r\ + \n }\r\ + \n :set devRunning \$RunningMode;\r\ + \n\r\ + \n :if (\$IsRouterBoard = true) do={\r\ + \n :set devModel [ :tostr (\$RouterBoard->\"model\") ];\r\ + \n :set devRbRevision [ :tostr (\$RouterBoard->\"revision\") ];\r\ + \n :set devRbSerialNumber [ :tostr (\$RouterBoard->\"serial-number\") \ + ];\r\ + \n } else={\r\ + \n :set devModel \$devBoardName;\r\ + \n :set devRbRevision \"\";\r\ + \n :set devRbSerialNumber \"\";\r\ + \n }\r\ + \n\r\ + \n :set currentUpdateChannel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set ROsVerAvail [ :tostr (\$Update->\"latest-version\") ];\r\ + \n\r\ + \n :set (\$DeviceInfo->\"board-name\") \$devBoardName;\r\ + \n :set (\$DeviceInfo->\"architecture-name\") \$devCurArch;\r\ + \n :set (\$DeviceInfo->\"model\") \$devModel;\r\ + \n :set (\$DeviceInfo->\"revision\") \$devRbRevision;\r\ + \n :set (\$DeviceInfo->\"serial-number\") \$devRbSerialNumber;\r\ + \n :set (\$DeviceInfo->\"running-mode\") \$devRunning;\r\ + \n :set (\$DeviceInfo->\"build-time\") \$devBuildTime;\r\ + \n :set (\$DeviceInfo->\"running-channel-version\") \$runningChannelVers\ + ion;\r\ + \n :set (\$DeviceInfo->\"running-version\") \$runningVersion;\r\ + \n :set (\$DeviceInfo->\"running-channel\") \$runningChannel;\r\ + \n :set (\$DeviceInfo->\"routerboard\") \$IsRouterBoard;\r\ + \n :set (\$DeviceInfo->\"current-firmware\") [ :tostr (\$RouterBoard->\"\ + current-firmware\") ];\r\ + \n :set (\$DeviceInfo->\"upgrade-firmware\") [ :tostr (\$RouterBoard->\"\ + upgrade-firmware\") ];\r\ + \n :set (\$DeviceInfo->\"package-channel\") \$currentUpdateChannel;\r\ + \n :set (\$DeviceInfo->\"installed-version\") [ :tostr (\$Update->\"inst\ + alled-version\") ];\r\ + \n :set (\$DeviceInfo->\"latest-version\") \$ROsVerAvail;\r\ + \n :set (\$DeviceInfo->\"update-status\") [ :tostr (\$Update->\"status\"\ + ) ];\r\ + \n\r\ + \n :set arrDeviceInfo \$DeviceInfo;\r\ + \n :return \$DeviceInfo;\r\ + \n}\r\ + \n\r\ + \n:set DeviceInfo do={\r\ + \n :global GetArrDeviceInfo;\r\ + \n :global GlobalConfVersion;\r\ + \n :global Identity;\r\ + \n :global IfThenElse;\r\ + \n :global FormatLine;\r\ + \n :global CommitBrief;\r\ + \n\r\ + \n :local License [/system/license/get];\r\ + \n :local Snmp [ /snmp/get ];\r\ + \n :local Info [ \$GetArrDeviceInfo ];\r\ + \n\r\ + \n :if ([ :typeof \$Info ] != \"array\") do={\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :return ( \\\r\ + \n [ \$FormatLine \"Hostname\" \$Identity ] . \"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$Snmp->\"location\") ] > 0) \\\r\ + \n ([ \$FormatLine \"Location\" (\$Snmp->\"location\") ] . \"\\n\") ]\ + \_. \\\r\ + \n [ \$IfThenElse ([ :len (\$Snmp->\"contact\") ] > 0) \\\r\ + \n ([ \$FormatLine \"Contact\" (\$Snmp->\"contact\") ] . \"\\n\") ] .\ + \_\\\r\ + \n \"Hardware:\\n\" . \\\r\ + \n [ \$FormatLine \" Board\" (\$Info->\"board-name\") ] . \"\\n\" . \ + \\\r\ + \n [ \$FormatLine \" Arch\" (\$Info->\"architecture-name\") ] . \"\\\ + n\" . \\\r\ + \n [ \$FormatLine \" Model\" (\$Info->\"model\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"revision\") ] > 0) \\\r\ + \n (\" \" . (\$Info->\"revision\")) ] . \"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"serial-number\") ] > 0) \\\r\ + \n ([ \$FormatLine \" Serial\" (\$Info->\"serial-number\") ] . \"\ + \\n\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$License->\"nlevel\") ] > 0) \\\r\ + \n ([ \$FormatLine \" License\" (\"level \" . (\$License->\"nlevel\ + \")) ] . \"\\n\") ] . \\\r\ + \n \"RouterOS:\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$License->\"level\") ] > 0) \\\r\ + \n ([ \$FormatLine \" License\" (\"level \" . (\$License->\"level\ + \")) ] . \"\\n\") ] . \\\r\ + \n [ \$FormatLine \" Channel\" (\$Info->\"package-channel\") ] . \"\ + \\n\" . \\\r\ + \n [ \$FormatLine \" Installed\" (\$Info->\"installed-version\") ] .\ + \_\"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"running-channel\") ] > 0) \\\r\ + \n ([ \$FormatLine \" Running\" ((\$Info->\"running-version\") . \ + \" (\" . (\$Info->\"running-channel\") . \")\") ] . \"\\n\") \\\r\ + \n ([ \$FormatLine \" Running\" (\$Info->\"running-version\") ] . \ + \"\\n\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"latest-version\") ] > 0 && \\\r\ + \n (\$Info->\"installed-version\") != (\$Info->\"latest-version\"))\ + \_\\\r\ + \n ([ \$FormatLine \" Available\" (\$Info->\"latest-version\") ] .\ + \_\"\\n\") ] . \\\r\ + \n [ \$IfThenElse ((\$Info->\"routerboard\") = true && \\\r\ + \n (\$Info->\"current-firmware\") != (\$Info->\"upgrade-firmware\")\ + ) \\\r\ + \n ([ \$FormatLine \" Firmware\" ((\$Info->\"current-firmware\") .\ + \_\" -> \" . (\$Info->\"upgrade-firmware\")) ] . \"\\n\") ] . \\\r\ + \n \"RouterOS-Scripts:\\n\" . \\\r\ + \n [ \$FormatLine \" Commit\" [ \$CommitBrief ] ] . \"\\n\" . \\\r\ + \n [ \$FormatLine \" Version\" \$GlobalConfVersion ]);\r\ + \n}\r\ + \n\r\ + \n:if ([ :typeof \$NotificationFunctions ] != \"array\") do={:set Notifica\ + tionFunctions ({})}\r\ + \n\r\ + \n:set GetRandom20CharAlNum do={\r\ + \n :global EitherOr;\r\ + \n :return [ :rndstr length=[ \$EitherOr [ :tonum \$1 ] 20 ] from=\"ABCDE\ + FGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\" ];\r\ + \n}\r\ + \n\r\ + \n:set GetRandom20CharHex do={:global EitherOr; :return [ :rndstr length=[\ + \_\$EitherOr [ :tonum \$1 ] 20 ] from=\"0123456789abcdef\" ]; }\r\ + \n:set GetRandomNumber do={:global EitherOr; :return [ :rndnum from=0 to=[\ + \_\$EitherOr [ :tonum \$1 ] 4294967295 ] ]; }\r\ + \n\r\ + \n:global checkRunJob;\r\ + \n:set checkRunJob do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :global ScriptLock; \r\ + \n :if ([ \$ScriptLock \$Script ] = false) do={:return false}\r\ + \n :foreach Job in=[ /system/script/job/find where script=\$Script ] do={\ + :set Job [ /system/script/job/get \$Job ];\r\ + \n :while ([ :typeof (\$Job->\"parent\") ] = \"id\") do={:set Job [ /sy\ + stem/script/job/get [ find where .id=(\$Job->\"parent\") ] ]}\r\ + \n :if ((\$Job->\"type\") = \"login\") do={:return true};}; :return fa\ + lse; \r\ + \n}\r\ + \n\r\ + \n:set InspectVar do={\r\ + \n :global InspectVarRet;\r\ + \n :put [ :tocrlf [ \$InspectVarRet \$1 ] ];\r\ + \n}\r\ + \n\r\ + \n:set CommitBrief do={\r\ + \n :global CommitId;\r\ + \n :global CommitInfo;\r\ + \n :if (\$CommitId = \"unknown\") do={\r\ + \n :return \"unknown\";\r\ + \n }\r\ + \n :return (\$CommitInfo . \"/\" . [ :pick \$CommitId 0 8 ]);\r\ + \n}\r\ + \n\r\ + \n:set InspectVarRet do={\r\ + \n :local Input \$1;\r\ + \n :local Level (0 + [ :tonum \$2 ]);\r\ + \n :global CharacterReplace;\r\ + \n :global IfThenElse;\r\ + \n :global InspectVarRet;\r\ + \n :local IndentReturn do={\r\ + \n :local Prefix [ :tostr \$1 ];\r\ + \n :local Value [ :tostr \$2 ];\r\ + \n :local Level [ :tonum \$3 ];\r\ + \n :global CharacterMultiply;\r\ + \n :return ([ \$CharacterMultiply \" \" (\$Level * 2) ] . \"-\" . \$Pre\ + fix . \"-> \" . \$Value);\r\ + \n }\r\ + \n :local TypeOf [ :typeof \$Input ];\r\ + \n :local Len [ :len \$Input ];\r\ + \n :local Return [ \$IndentReturn \"type\" \$TypeOf \$Level ];\r\ + \n :if (\$TypeOf = \"array\") do={\r\ + \n :foreach Key,Value in=\$Input do={\r\ + \n :set \$Return (\$Return . \"\\n\" . \\\r\ + \n [ \$IndentReturn \"key\" \$Key (\$Level + 1) ] . \"\\n\" . \\\r\ + \n [ \$InspectVarRet \$Value (\$Level + 2) ]);\r\ + \n }\r\ + \n } else={\r\ + \n :if (\$TypeOf = \"str\") do={\r\ + \n :set \$Return (\$Return . \"\\n\" . \\\r\ + \n [ \$IndentReturn \"len\" \$Len \$Level ]);\r\ + \n :if ([ :typeof [ :find \$Input (\"\\r\") ] ] = \"num\") do={\r\ + \n :set Input [ \$CharacterReplace \$Input (\"\\r\") \"\" ];\r\ + \n }\r\ + \n :if ([ :typeof [ :find \$Input (\"\\n\") ] ] = \"num\") do={\r\ + \n :set Input [ \$CharacterReplace \$Input (\"\\n\") \" \" ];\r\ + \n }\r\ + \n }\r\ + \n :if (\$TypeOf != \"nothing\") do={\r\ + \n :set \$Return (\$Return . \"\\n\" . \\\r\ + \n [ \$IndentReturn \"value\" [ \$IfThenElse ([ :len \$Input ] > 80)\ + \_\\\r\ + \n ([ :pick \$Input 0 77 ] . \"...\") \$Input ] \$Level ]);\r\ + \n }\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set GetPubIp do={\r\ + \n :global DetectIpAddrDefault;\r\ + \n :global DetectIpAddrFallback;\r\ + \n\r\ + \n :local PubIpAddr false;\r\ + \n :local Url \$DetectIpAddrDefault;\r\ + \n :local JobName [ :jobname ];\r\ + \n\r\ + \n :do {\r\ + \n :log debug (\$0 . \" Trying to detect public IP using default serv\ + ice: \" . \$Url . \"...\");\r\ + \n :retry command={:set PubIpAddr ([ /tool/fetch http-method=\"get\"\ + \_check-certificate=yes-without-crl \$Url output=user as-value ]->\"data\"\ + )} \\\r\ + \n delay=50ms max=5 on-error={:log error (\$JobName . \" Failed to \ + detect public IP using default service: \" . \$Url . \".\")}\r\ + \n } on-error={\r\ + \n :log error (\$0 . \" Failed to detect public IP using default serv\ + ice: \" . \$Url . \".\");\r\ + \n :set Url \$DetectIpAddrFallBack;\r\ + \n :log debug (\$0 . \" Trying to detect public IP using fallback ser\ + vice: \" . \$Url . \"...\");\r\ + \n :retry command={:set PubIpAddr ([ /tool/fetch http-method=\"get\"\ + \_check-certificate=yes-without-crl \$Url output=user as-value ]->\"data\"\ + )} \\\r\ + \n delay=200ms max=5 on-error={:log error (\$JobName . \" Failed to\ + \_detect public IP using fallback service: \" . \$Url . \".\")}\r\ + \n };\r\ + \n :local IpLen ([ :len \$PubIpAddr ] -1);\r\ + \n :if (\$PubIpAddr = false) do={:set PubIpAddr \"not-detected\"} else=\ + {:set PubIpAddr [:pick \$PubIpAddr 0 \$IpLen]}\r\ + \n :return \$PubIpAddr;\r\ + \n}\r\ + \n\r\ + \n:set FormatLine do={\r\ + \n :local Key [ :tostr \$1 ];\r\ + \n :local Value [ :tostr \$2 ];\r\ + \n :local Indent [ :tonum \$3 ];\r\ + \n :local Spaces;\r\ + \n :local Return \"\";\r\ + \n :global CharacterMultiply;\r\ + \n :global EitherOr;\r\ + \n :set Indent [ \$EitherOr \$Indent 16 ];\r\ + \n :local Spaces [ \$CharacterMultiply \" \" \$Indent ];\r\ + \n :if ([ :len \$Key ] > 0) do={ :set Return (\$Key . \":\")}\r\ + \n :if ([ :len \$Key ] > (\$Indent - 2)) do={:set Return (\$Return . \"\\\ + n\" . [ :pick \$Spaces 0 \$Indent ] . \$Value);\r\ + \n } else={:set Return (\$Return . [ :pick \$Spaces 0 (\$Indent - [ :len \ + \$Return ]) ] . \$Value)}\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set ParseCustom do={\r\ + \n :local Str [ :tostr \$1 ];\r\ + \n :local Start [:find [ \$Str ] [:tostr \$2]];\r\ + \n :local End [ :tostr \$3 ];\r\ + \n :local Num [ :tonum \$4 ];\r\ + \n :local Return;\r\ + \n :if ([:len \$Num] = 0) do={:set Num \"0\"}\r\ + \n :local rest [:pick \$Str (\$Start+\$Num) [:len \$Str]]; \r\ + \n :if ([:len \$End ] = 0) do={:set Return [:pick \$Str \$Num \$Start]} e\ + lse={\r\ + \n :set End [:find \$rest \$End];\r\ + \n :set Return [:pick \$rest 0 \$End];\r\ + \n }\r\ + \n:return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set LogPrint do={\r\ + \n :local Severity [ :tostr \$1 ];\r\ + \n :local Name [ :tostr \$2 ];\r\ + \n :local Message [ :tostr \$3 ];\r\ + \n :global PrintDebug;\r\ + \n :global PrintDebugOverride;\r\ + \n :global EitherOr;\r\ + \n :local Debug [ \$EitherOr (\$PrintDebugOverride->\$Name) \$PrintDebug \ + ];\r\ + \n :local PrintSeverity do={\r\ + \n :global TerminalColorOutput;\r\ + \n :if (\$TerminalColorOutput != true) do={:return \$1}\r\ + \n :local Color { debug=96; info=97; warning=93; error=91 };\r\ + \n :return (\"\\1B[\" . \$Color->\$1 . \"m\" . \$1 . \"\\1B[0m\");\r\ + \n}\r\ + \n :local Log ([ \$EitherOr \$Name \"\" ] . \": \" . \$Message);\ + \r\ + \n :if (\$Severity ~ (\"^(custom|debug|error|info)\\\$\")) do={\r\ + \n :if (\$Severity = \"debug\") do={:log debug \$Log}\r\ + \n :if (\$Severity = \"error\") do={:log error \$Log}\r\ + \n :if (\$Severity = \"info\" ) do={:log info \$Log}\r\ + \n } else={:log warning \$Log; :set Severity \"warning\"}\r\ + \n :if (\$Severity != \"debug\" || \$Debug = true) do={:put ([ \$PrintSev\ + erity \$Severity ] . \": \" . \$Message)}\r\ + \n}\r\ + \n\r\ + \n:set CertificateAvailable do={\r\ + \n :local CommonName [ :tostr \$1 ];\r\ + \n :local UseFor [ :tostr \$2 ];\r\ + \n\r\ + \n :global CertificateDownload;\r\ + \n :global ParseKeyValueStore;\r\ + \n\r\ + \n :if ([ :len \$UseFor ] = 0) do={\r\ + \n :log warning (\$0 . \"The intended use is undefined!\");\r\ + \n :set UseFor \"undefined\";\r\ + \n }\r\ + \n :if ([ /system/resource/get free-hdd-space ] < 8388608 && \\\r\ + \n [ /certificate/settings/get crl-download ] = true && \\\r\ + \n [ /certificate/settings/get crl-store ] = \"system\") do={\r\ + \n :log warning (\$0 . \"This system has low free flash space but \" . \ + \\\r\ + \n \"is configured to download certificate CRLs to system!\");\r\ + \n }\r\ + \n :if ([ :len \$CommonName ] = 0) do={\r\ + \n :log warning (\$0 . \"No CommonName given!\");\r\ + \n :return false;\r\ + \n }\r\ + \n :local CertSettings [ /certificate/settings/get ];\r\ + \n :if (((\$CertSettings->\"builtin-trust-anchors\") = \"trusted\" || \\\ + \r\ + \n (\$CertSettings->\"builtin-trust-store\") ~ \$UseFor || \\\r\ + \n (\$CertSettings->\"builtin-trust-store\") = \"all\") && \\\r\ + \n [ :len [ /certificate/builtin/find where common-name=\$CommonName\ + \_] ] > 0) do={\r\ + \n :return true;\r\ + \n }\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] = 0\ + ) do={\r\ + \n :log info (\$0 . \"Certificate with CommonName '\" . \$CommonName . \ + \"' not available.\");\r\ + \n :if ([ \$CertificateDownload \$CommonName ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] > 1\ + ) do={\r\ + \n :log info (\$0 . \"There are \" . \$CertCount . \" Certificates with\ + \_CommonName '\" . \$CommonName . \"'. Should be ok.\");\r\ + \n :return true;\r\ + \n }\r\ + \n :local CertVal [ /certificate/get [ find where common-name=\$CommonNam\ + e ] ];\r\ + \n :while ((\$CertVal->\"akid\") != \"\" && (\$CertVal->\"akid\") != (\$C\ + ertVal->\"skid\")) do={\r\ + \n :if ([ :len [ /certificate/find where skid=(\$CertVal->\"akid\") ] ]\ + \_= 0) do={\r\ + \n :local IssuerCN ([ \$ParseKeyValueStore (\$CertVal->\"issuer\") ]-\ + >\"CN\");\r\ + \n :log info (\$0 . \"Certificate chain for '\" . \$CommonName . \"' \ + is incomplete, missing '\" . \$IssuerCN . \"'.\");\r\ + \n :if ([ \$CertificateDownload \$IssuerCN ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n :set CertVal [ /certificate/get [ find where skid=(\$CertVal->\"akid\ + \") ] ];\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set CertificateDownload do={\r\ + \n :local CommonName [ :tostr \$1 ];\r\ + \n :global ScriptUpdatesBaseUrl;\r\ + \n :global ScriptUpdatesUrlSuffix;\r\ + \n :global CertificateNameByCN;\r\ + \n :global CleanName;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global RmFile;\r\ + \n :global WaitForFile;\r\ + \n\r\ + \n :log info (\$0 . \"Downloading and importing certificate with \" . \\\ + \r\ + \n \"CommonName '\" . \$CommonName . \"'.\");\r\ + \n :local FileName ([ \$CleanName \$CommonName ] . \".pem\");\r\ + \n :do {\r\ + \n /tool/fetch check-certificate=yes-without-crl mode=https http-header\ + -field=({ [ \$FetchUserAgentStr \$0 ] }) \\\r\ + \n (\$ScriptUpdatesBaseUrl . \"certs/\" . \$FileName . \$ScriptUpdate\ + sUrlSuffix) \\\r\ + \n dst-path=\$FileName as-value;\r\ + \n \$WaitForFile \$FileName;\r\ + \n } on-error={\r\ + \n :log warning (\$0 . \" Failed downloading certificate with CommonNam\ + e '\" . \$CommonName . \\\r\ + \n \"' from repository! Trying fallback to mkcert.org...\");\r\ + \n :do {\r\ + \n :local CertSettings [ /certificate/settings/get ];\r\ + \n :if ([ :len [ /certificate/find where common-name=\"ISRG Root X1\"\ + \_] ] = 0 && \\\r\ + \n !(((\$CertSettings->\"builtin-trust-anchors\") = \"trusted\" \ + || \\\r\ + \n (\$CertSettings->\"builtin-trust-store\") ~ \"fetch\" || \ + \\\r\ + \n (\$CertSettings->\"builtin-trust-store\") = \"all\") && \\\ + \r\ + \n [ :len [ /certificate/builtin/find where common-name=\"ISRG\ + \_Root X1\" ] ] > 0)) do={\r\ + \n :log error (\$0 . \" Required certificate is not available.\");\ + \r\ + \n :return false;\r\ + \n }\r\ + \n /tool/fetch check-certificate=yes-without-crl mode=https http-head\ + er-field=({ [ \$FetchUserAgentStr \$0 ] }) \\\r\ + \n url=\"https://mkcert.org/generate/\" http-data=[ :serialize to=jso\ + n ({ \$CommonName }) ] \\\r\ + \n dst-path=\$FileName as-value;\r\ + \n \$WaitForFile \$FileName;\r\ + \n :if ([ /file/get \$FileName size ] = 0) do={\r\ + \n \$RmFile \$FileName;\r\ + \n :error false;\r\ + \n }\r\ + \n } on-error={\r\ + \n :log error (\$0 . \" Failed downloading certificate with CommonNam\ + e '\" . \$CommonName . \"'!\");\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n /certificate/import file-name=\$FileName passphrase=\"\" as-value;\r\ + \n :delay 1s;\r\ + \n \$RmFile \$FileName;\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] = 0\ + ) do={\r\ + \n /certificate/remove [ find where name~(\"^\" . \$FileName . \"_[0-9]\ + +\\\$\") ];\r\ + \n :log warning (\$0 . \" Certificate with CommonName '\" . \$CommonNam\ + e . \"' still unavailable!\");\r\ + \n :return false;\r\ + \n }\r\ + \n :foreach Cert in=[ /certificate/find where name~(\"^\" . \$FileName . \ + \"_[0-9]+\\\$\") ] do={\r\ + \n \$CertificateNameByCN [ /certificate/get \$Cert common-name ];\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set CertificateNameByCN do={\r\ + \n :local Match [ :tostr \$1 ];\r\ + \n :global CleanName;\r\ + \n :local Cert ([ /certificate/find where (common-name=\$Match or fingerp\ + rint=\$Match or name=\$Match) ]->0);\r\ + \n :if ([ :len \$Cert ] = 0) do={\r\ + \n :log warning (\$0 .\" No matching certificate found.\");\r\ + \n :return false;\r\ + \n }\r\ + \n :local CommonName [ /certificate/get \$Cert common-name ];\r\ + \n /certificate/set \$Cert name=[ \$CleanName \$CommonName ];\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set CharacterMultiply do={\r\ + \n :local Str [ :tostr \$1 ];\r\ + \n :local Num [ :tonum \$2 ];\r\ + \n :if (\$Num = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :for I from=1 to=\$Num do={:set Return (\$Return . \$Str)}\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set FileExists do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :local Type [ :tostr \$2 ];\r\ + \n :global FileGet;\r\ + \n :local FileVal [ \$FileGet \$FileName ];\r\ + \n :if (\$FileVal = false) do={ :return false; }\r\ + \n :if ([ :len (\$FileVal->\"size\") ] = 0) do={ :return false; }\r\ + \n :if ([ :len \$Type ] = 0 || \$FileVal->\"type\" = \$Type) do={ :return\ + \_true; }\r\ + \n :return false;\r\ + \n}\r\ + \n\r\ + \n:set Grep do={\r\ + \n :local Input ([ :tostr \$1 ] . \"\\n\");\r\ + \n :local Pattern [ :tostr \$2 ];\r\ + \n :if ([ :typeof [ :find \$Input \$Pattern ] ] = \"nil\") do={:return []\ + }\r\ + \n :do {\r\ + \n :local Line [ :pick \$Input 0 [ :find \$Input \"\\n\" ] ];\r\ + \n :if ([ :typeof [ :find \$Line \$Pattern ] ] = \"num\") do={:return \ + \$Line}\r\ + \n :set Input [ :pick \$Input ([ :find \$Input \"\\n\" ] + 1) [ :len \$\ + Input ] ];\r\ + \n } while=([ :len \$Input ] > 0);\r\ + \n :return [];\r\ + \n}\r\ + \n\r\ + \n:set HumanReadableNum do={\r\ + \n :local Input [ :tonum \$1 ];\r\ + \n :local Base [ :tonum \$2 ];\r\ + \n :global EitherOr;\r\ + \n :global IfThenElse;\r\ + \n :local Prefix \"kMGTPE\";\r\ + \n :local Pow 1;\r\ + \n :set Base [ \$EitherOr \$Base 1024 ];\r\ + \n :local Bin [ \$IfThenElse (\$Base = 1024) \"i\" \"\" ];\r\ + \n :if (\$Input < \$Base) do={:return \$Input}\r\ + \n :for I from=0 to=[ :len \$Prefix ] do={\r\ + \n :set Pow (\$Pow * \$Base);\r\ + \n :if (\$Input / \$Base < \$Pow) do={\r\ + \n :set Prefix [ :pick \$Prefix \$I ];\r\ + \n :local Tmp1 (\$Input * 100 / \$Pow);\r\ + \n :local Tmp2 (\$Tmp1 / 100);\r\ + \n :if (\$Tmp2 >= 100) do={:return (\$Tmp2 . \$Prefix . \$Bin)}\r\ + \n :return (\$Tmp2 . \".\" . \\\r\ + \n [ :pick \$Tmp1 [ :len \$Tmp2 ] ([ :len \$Tmp1 ] - [ :len \$Tmp\ + 2 ] + 1) ] . \\\r\ + \n \$Prefix . \$Bin);\r\ + \n }\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set CleanFilePath do={\r\ + \n :local Path [ :tostr \$1 ];\r\ + \n :global CharacterReplace;\r\ + \n :while (\$Path ~ \"//\") do={ :set \$Path [ \$CharacterReplace \$Path \ + \"//\" \"/\" ]; }\r\ + \n :if ([ :pick \$Path 0 ] = \"/\") do={ :set Path [ :pick \$Path 1 [ :le\ + n \$Path ] ]; }\r\ + \n :if ([ :pick \$Path ([ :len \$Path ] - 1) ] = \"/\") do={ :set Path [ \ + :pick \$Path 0 ([ :len \$Path ] - 1) ]; }\r\ + \n :return \$Path;\r\ + \n}\r\ + \n\r\ + \n:set CleanName do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :local Return \"\";\r\ + \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ + \n :local Char [ :pick \$Input \$I ];\r\ + \n :if ([ :typeof [ find \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr\ + stuvwxyz0123456789\" \$Char ] ] = \"nil\") do={\r\ + \n :do {:if ([ :len \$Return ] = 0) do={:error true};\r\ + \n :if ([ :pick \$Return ([ :len \$Return ] - 1) ] = \"-\") do={:er\ + ror true}; :set Char \"-\"} on-error={:set Char \"\"}; \r\ + \n };\r\ + \n :set Return (\$Return . \$Char)};\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set RandomDelay do={\r\ + \n :local Time [ :tonum \$1 ];\r\ + \n :local Unit [ :tostr \$2 ];\r\ + \n :global EitherOr;\r\ + \n :global GetRandomNumber;\r\ + \n :global MAX;\r\ + \n :if (\$Time = 0) do={:return false}\r\ + \n :delay ([ \$MAX 10 [ \$GetRandomNumber ([ :tonsec [ :totime (\$Time . \ + [ \$EitherOr \$Unit \"s\" ]) ] ] / 1000000) ] ] . \"ms\");\r\ + \n}\r\ + \n\r\ + \n:set EscapeForRegEx do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :if ([ :len \$Input ] = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :local Chars (\"^.[]\\\$()|*+\?{}\\\\\");\r\ + \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ + \n :local Char [ :pick \$Input \$I ];\r\ + \n :if ([ :find \$Chars \$Char ]) do={:set Char (\"\\\\\" . \$Char)}\r\ + \n :set Return (\$Return . \$Char);\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set ExitError do={\r\ + \n :local ExitOK [ :tostr \$1 ];\r\ + \n :local Name [ :tostr \$2 ];\r\ + \n :local Error [ :tostr \$3 ];\r\ + \n :global IfThenElse;\r\ + \n :if (\$ExitOK = \"false\") do={\r\ + \n :log error (\$Name [ \$IfThenElse ([ :pick \$Name 0 1 ] = \"\\\$\") \ + \\\r\ + \n \"Function\" \"Script\" ] . \" '\" . \$Name . \"' exited with er\ + ror\" . \\\r\ + \n [ \$IfThenElse (!(\$Error ~ \"^(|true|false)\\\$\")) (\": \" . \ + \$Error) \".\" ]);\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set ExitOnError do={\r\ + \n :local Name [ :tostr \$1 ];\r\ + \n :local Error [ :tostr \$2 ];\r\ + \n :global IfThenElse;\r\ + \n :log error (\$Name . \" \" . [ \$IfThenElse ([ :pick \$Name 0 1 ] = \"\ + \\\$\") \\\r\ + \n \"Function\" \"Script\" ] . \" '\" . \$Name . \"' exited with erro\ + r\" . \\\r\ + \n [ \$IfThenElse (!(\$Error ~ \"^(|true|false)\\\$\")) (\": \" . \$E\ + rror) \".\" ]);\r\ + \n}\r\ + \n\r\ + \n:set MiniDateTimeStamp do={\r\ + \n :local mikro [ :tobool \$1 ];\r\ + \n /system/clock;\r\ + \n :local vdate [get date];\r\ + \n :local vtime [get time];\r\ + \n :local vdoff [:toarray \"0,4,5,7,8,10\"];\r\ + \n :local MM [:pick \$vdate (\$vdoff->2) (\$vdoff->3)];\r\ + \n :local M [:tonum \$MM];\r\ + \n :if (\$vdate ~ \".../../....\") do={\r\ + \n :set vdoff [:toarray \"7,11,1,3,4,6\"];\r\ + \n :set M ([:find \"xxanebarprayunulugepctovecANEBARPRAYUNULUGE\ + PCTOVEC\" [:pick \$vdate (\$vdoff->2) (\$vdoff->3)] -1] / 2);\r\ + \n :if (\$M>12) do={:set M (\$M - 12)}\r\ + \n :set MM [:pick (100 + \$M) 1 3];\r\ + \n }\r\ + \n :local yyyy [:pick \$vdate (\$vdoff->0) (\$vdoff->1)];\r\ + \n :local dd [:pick \$vdate (\$vdoff->4) (\$vdoff->5)];\r\ + \n :local HH [:pick \$vtime 0 2];\r\ + \n :local mm [:pick \$vtime 3 5];\r\ + \n :local ss [:pick \$vtime 6 8];\r\ + \n :local Return;\r\ + \n :if (\$mikro = true) do={\r\ + \n :set Return ([:pick \$yyyy 2 4] . [:pick \$dd 0 1] . [:pick \$HH 0\ + \_1] . [:pick \$mm 3 4] . [:pick \$ss 6 7]);\r\ + \n } else={\r\ + \n :set Return ([\$yyyy] . [\$MM] . [\$dd] . [\$HH] . [\$mm] . [\$ss]);\ + \r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set WaitForFile do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :local WaitTime [ :totime \$2 ];\r\ + \n :global CleanFilePath;\r\ + \n :global EitherOr;\r\ + \n :global MAX;\r\ + \n :set FileName [ \$CleanFilePath \$FileName ];\r\ + \n :local Delay ([ \$MAX [ \$EitherOr \$WaitTime 2s ] 100ms ] / 9);\r\ + \n :do {\r\ + \n :retry {\r\ + \n /file/get \$FileName;\r\ + \n :return true;\r\ + \n } delay=\$Delay max=10;\r\ + \n } on-error={ }\r\ + \n :while ([ :len [ /file/find where name=\$FileName ] ] > 0) do={\r\ + \n :do {\r\ + \n /file/get \$FileName;\r\ + \n :return true;\r\ + \n } on-error={ }\r\ + \n :delay \$Delay;\r\ + \n :set Delay (\$Delay * 3 / 2);\r\ + \n }\r\ + \n :return false;\r\ + \n}\r\ + \n\r\ + \n:set FileGet do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :global WaitForFile;\r\ + \n :if ([ \$WaitForFile \$FileName 0s ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n :local FileVal false;\r\ + \n :do {\r\ + \n :set FileVal [ /file/get \$FileName ];\r\ + \n } on-error={ }\r\ + \n :return \$FileVal;\r\ + \n}\r\ + \n\r\ + \n:set RmDir do={\r\ + \n :local DirName [ :tostr \$1 ];\r\ + \n :global FileGet;\r\ + \n :log debug (\$0 . \" Removing directory: \". \$DirName);\r\ + \n :local DirVal [ \$FileGet \$DirName ];\r\ + \n :if (\$DirVal = false) do={\r\ + \n :log debug (\$0 . \" ... which does not exist.\");\r\ + \n :return true;\r\ + \n };\r\ + \n :if (\$DirVal->\"type\" != \"directory\") do={\r\ + \n :log error (\$0 . \" Directory '\" . \$DirName . \"' is not a direct\ + ory.\");\r\ + \n :return false;\r\ + \n };\r\ + \n :onerror Err {\r\ + \n /file/remove \$DirName;\r\ + \n } do={\r\ + \n :log error (\$0 . \" Removing directory '\" . \$DirName . \"' failed\ + : \" . \$Err);\r\ + \n :return false;\r\ + \n };\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set RmFile do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :global FileGet;\r\ + \n :log debug (\$0 . \" Removing file: \". \$FileName);\r\ + \n :local FileVal [ \$FileGet \$FileName ];\r\ + \n :if (\$FileVal = false) do={\r\ + \n :log debug (\$0 . \" ... which does not exist.\");\r\ + \n :return true;\r\ + \n }\r\ + \n :if (\$FileVal->\"type\" = \"directory\" || \$FileVal->\"type\" = \"di\ + sk\") do={\r\ + \n :log error (\$0 . \" File '\" . \$FileName . \"' is not a file.\");\ + \r\ + \n :return false;\r\ + \n }\r\ + \n :onerror Err {\r\ + \n /file/remove \$FileName;\r\ + \n } do={\r\ + \n :log error (\$0 . \" Removing file '\" . \$FileName . \"' failed: \"\ + \_. \$Err); :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set MkDir do={\r\ + \n :local Path [ :tostr \$1 ];\r\ + \n :global CleanFilePath;\r\ + \n :global FileGet;\r\ + \n :global RmDir;\r\ + \n :global WaitForFile;\r\ + \n\r\ + \n :local MkTmpfs do={\r\ + \n :global WaitForFile;\r\ + \n :local TmpFs [ /disk/find where slot=tmpfs type=tmpfs ];\r\ + \n :if ([ :len \$TmpFs ] = 1) do={\r\ + \n :if ([ /disk/get \$TmpFs disabled ] = true) do={\r\ + \n :log info (\$0 . \" The tmpfs is disabled, enabling.\");\r\ + \n /disk/enable \$TmpFs;\r\ + \n }\r\ + \n :return true;\r\ + \n }\r\ + \n :log info (\$0 . \" Creating disk of type tmpfs.\");\r\ + \n \$RmDir \"tmpfs\";\r\ + \n :onerror Err {\r\ + \n /disk/add slot=tmpfs type=tmpfs tmpfs-max-size=([ /system/resource\ + /get total-memory ] / 3);\r\ + \n \$WaitForFile \"tmpfs\";\r\ + \n } do={\r\ + \n :log warning (\$0 . \" Creating disk of type tmpfs failed: \" . \$\ + Err);\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n }\r\ + \n :set Path [ \$CleanFilePath \$Path ];\r\ + \n :if (\$Path = \"\") do={\r\ + \n :return true;\r\ + \n }\r\ + \n :log debug (\$0 . \" Making directory: \" . \$Path);\r\ + \n :local PathVal [ \$FileGet \$Path ];\r\ + \n :if (\$PathVal->\"type\" = \"directory\") do={\r\ + \n :log debug (\$0 . \" ... which already exists.\");\r\ + \n :return true;\r\ + \n }\r\ + \n :if ([ :pick \$Path 0 5 ] = \"tmpfs\") do={\r\ + \n :if ([ \$MkTmpfs ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n :onerror Err {\r\ + \n /file/add type=\"directory\" name=\$Path;\r\ + \n \$WaitForFile \$Path;\r\ + \n } do={\r\ + \n :log warning (\$0 . \" Making directory '\" . \$Path . \"' failed: \ + \" . \$Err);\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set MAX do={:if (\$1 > \$2) do={:return \$1}\r\ + \n :return \$2;\r\ + \n}\r\ + \n:set MIN do={:if (\$1 < \$2) do={:return \$1}\r\ + \n :return \$2;\r\ + \n}\r\ + \n\r\ + \n:set CharacterMultiply do={\r\ + \n :local Str [ :tostr \$1 ];\r\ + \n :local Num [ :tonum \$2 ];\r\ + \n :if (\$Num = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :for I from=1 to=\$Num do={:set Return (\$Return . \$Str)}\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set CharacterReplace do={\r\ + \n :local String [ :tostr \$1 ];\r\ + \n :local ReplaceFrom [ :tostr \$2 ];\r\ + \n :local ReplaceWith [ :tostr \$3 ];\r\ + \n :local Return \"\";\r\ + \n :if (\$ReplaceFrom = \"\") do={:return \$String}\r\ + \n :while ([ :typeof [ :find \$String \$ReplaceFrom ] ] != \"nil\") do={\ + \r\ + \n :local Pos [ :find \$String \$ReplaceFrom ];\r\ + \n :set Return (\$Return . [ :pick \$String 0 \$Pos ] . \$ReplaceWith);\ + \r\ + \n :set String [ :pick \$String (\$Pos + [ :len \$ReplaceFrom ]) [ :len\ + \_\$String ] ];\r\ + \n }\r\ + \n :return (\$Return . \$String);\r\ + \n}\r\ + \n\r\ + \n:set IfThenElse do={\r\ + \n :if ([ :tostr \$1 ] = \"true\" || [ :tobool \$1 ] = true) do={:return \ + \$2};\r\ + \n :return \$3;\r\ + \n}\r\ + \n\r\ + \n:set EitherOr do={\r\ + \n :global IfThenElse;\r\ + \n :if ([ :typeof \$1 ] = \"num\") do={:return [ \$IfThenElse (\$1 != 0) \ + \$1 \$2 ]}\r\ + \n :if ([ :typeof \$1 ] = \"time\") do={:return [ \$IfThenElse (\$1 > 0s)\ + \_\$1 \$2 ]}\r\ + \n# this works for boolean values, literal ones with parentheses\r\ + \n :return [ \$IfThenElse ([ :len [ :tostr \$1 ] ] > 0) \$1 \$2 ];\r\ + \n}\r\ + \n\r\ + \n:set ParseKeyValueStore do={\r\ + \n :local Source \$1;\r\ + \n :if ([ :pick \$Source 0 1 ] = \"{\") do={\r\ + \n :do {\r\ + \n :return [ :deserialize from=json \$Source ];\r\ + \n } on-error={ }\r\ + \n } \r\ + \n :if ([ :typeof \$Source ] != \"array\") do={:set Source [ :tostr \$1 ]\ + }\r\ + \n :local Result ({});\r\ + \n :foreach KeyValue in=[ :toarray \$Source ] do={\r\ + \n :if ([ :find \$KeyValue \"=\" ]) do={\r\ + \n :local Key [ :pick \$KeyValue 0 [ :find \$KeyValue \"=\" ] ];\r\ + \n :local Value [ :pick \$KeyValue ([ :find \$KeyValue \"=\" ] + 1) [\ + \_:len \$KeyValue ] ];\r\ + \n :if (\$Value=\"true\") do={:set Value true}\r\ + \n :if (\$Value=\"false\") do={:set Value false}\r\ + \n :set (\$Result->\$Key) \$Value;\r\ + \n } else={:set (\$Result->\$KeyValue) true}\r\ + \n }\r\ + \n :return \$Result;\r\ + \n}\r\ + \n:set RequiredRouterOS do={\r\ + \n :local Caller [ :tostr \$1 ];\r\ + \n :local Required [ :tostr \$2 ];\r\ + \n :local Warn [ :tostr \$3 ];\r\ + \n :global IfThenElse;\r\ + \n :global VersionToNum;\r\ + \n :if (!(\$Required ~ \"^\\\\d+\\\\.\\\\d+((alpha|beta|rc|\\\\.)\\\\d+|)\ + \\\$\")) do={\r\ + \n :log error (\$0 . \" No valid RouterOS version: \" . \$Required);\r\ + \n :return false;\r\ + \n }\r\ + \n :if ([ \$VersionToNum \$Required ] > [ \$VersionToNum [ /system/packag\ + e/update/get installed-version ] ]) do={\r\ + \n :if (\$Warn = \"true\") do={\r\ + \n :log warning (\$0 . \" This \" . [ \$IfThenElse ([ :pick \$Caller \ + 0 ] = (\"\\\$\")) \"function\" \"script\" ] . \\\r\ + \n \" '\" . \$Caller . \"' (at least specific functionality) requir\ + es RouterOS \" . \$Required . \". Please update!\");\r\ + \n }\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set ValidateSyntax do={\r\ + \n :local Code [ :tostr \$1 ];\r\ + \n :global LogPrint;\r\ + \n :onerror Err {\r\ + \n [ :parse (\":local Validate do={\\n\" . \$Code . \"\\n}\") ];\r\ + \n } do={\r\ + \n \$LogPrint debug \$0 (\"Valdation failed: \" . \$Err);\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set VersionToNum do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :local Multi 0x1000000;\r\ + \n :local Return 0;\r\ + \n :global CharacterReplace;\r\ + \n :set Input [ \$CharacterReplace \$Input \".\" \",\" ];\r\ + \n :foreach I in={ \"zero\"; \"alpha\"; \"beta\"; \"rc\" } do={\r\ + \n :set Input [ \$CharacterReplace \$Input \$I (\",\" . \$I . \",\") ];\ + \r\ + \n }\r\ + \n :foreach Value in=([ :toarray \$Input ], 0) do={\r\ + \n :local Num [ :tonum \$Value ];\r\ + \n :if (\$Multi = 0x100) do={\r\ + \n :if ([ :typeof \$Num ] = \"num\") do={\r\ + \n :set Return (\$Return + 0xff00);\r\ + \n :set Multi (\$Multi / 0x100);\r\ + \n } else={\r\ + \n :if (\$Value = \"zero\") do={ }\r\ + \n :if (\$Value = \"alpha\") do={ :set Return (\$Return + 0x3f00); \ + }\r\ + \n :if (\$Value = \"beta\") do={ :set Return (\$Return + 0x5f00); }\ + \r\ + \n :if (\$Value = \"rc\") do={ :set Return (\$Return + 0x7f00); }\r\ + \n }\r\ + \n }\r\ + \n :if ([ :typeof \$Num ] = \"num\") do={ :set Return (\$Return + (\$Va\ + lue * \$Multi)); }\r\ + \n :set Multi (\$Multi / 0x100);\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set ScriptLock do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local WaitMax [ :totime \$2 ];\r\ + \n :global GetRandom20CharAlNum;\r\ + \n :global IfThenElse;\r\ + \n :global ScriptLockOrder;\r\ + \n :if ([ :typeof \$ScriptLockOrder ] = \"nothing\") do={\r\ + \n :set ScriptLockOrder ({});\r\ + \n }\r\ + \n :if ([ :typeof (\$ScriptLockOrder->\$Script) ] = \"nothing\") do={\r\ + \n :set (\$ScriptLockOrder->\$Script) ({});\r\ + \n }\r\ + \n :local JobCount do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :return [ :len [ /system/script/job/find where script=\$Script ] ];\ + \r\ + \n }\r\ + \n :local TicketCount do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :local Count 0;\r\ + \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :if ([ :typeof \$Ticket ] != \"nothing\") do={:set Count (\$Count \ + + 1)}\r\ + \n }\r\ + \n :return \$Count;\r\ + \n }\r\ + \n :local IsFirstTicket do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local Check [ :tostr \$2 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :if (\$Ticket = \$Check) do={:return true}\r\ + \n :if ([ :typeof \$Ticket ] != \"nothing\" && \$Ticket != \$Check) d\ + o={:return false}\r\ + \n }\r\ + \n :return false;\r\ + \n }\r\ + \n :local AddTicket do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local Add [ :tostr \$2 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :while (true) do={\r\ + \n :local Pos [ :len (\$ScriptLockOrder->\$Script) ];\r\ + \n :set (\$ScriptLockOrder->\$Script->\$Pos) \$Add;\r\ + \n :delay 10ms;\r\ + \n :if ((\$ScriptLockOrder->\$Script->\$Pos) = \$Add) do={:return tru\ + e}\r\ + \n }\r\ + \n }\r\ + \n :local RemoveTicket do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local Remove [ :tostr \$2 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :foreach Id,Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :while ((\$ScriptLockOrder->\$Script->\$Id) = \$Remove) do={\r\ + \n :set (\$ScriptLockOrder->\$Script->\$Id);\r\ + \n :delay 10ms;\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n :local CleanupTickets do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :if ([ :typeof \$Ticket ] != \"nothing\") do={:return false}\r\ + \n }\r\ + \n :set (\$ScriptLockOrder->\$Script) ({});\r\ + \n }\r\ + \n :if ([ :typeof \$WaitMax ] = \"nil\" ) do={:set WaitMax 0s}\r\ + \n :if ([ :len [ /system/script/find where name=\$Script ] ] = 0) do={\r\ + \n :log error (\$0 . \" A script named '\" . \$Script . \"' does not ex\ + ist!\");\r\ + \n :error false;\r\ + \n }\r\ + \n :if ([ \$JobCount \$Script ] = 0) do={\r\ + \n \$LogPrint error \$0 (\"No script '\" . \$Script . \"' is running!\"\ + );\r\ + \n :error false;\r\ + \n }\r\ + \n :if ([ \$TicketCount \$Script ] >= [ \$JobCount \$Script ]) do={\r\ + \n :log error (\$0 . \" More tickets than running scripts '\" . \$Scrip\ + t . \"', resetting!\");\r\ + \n :set (\$ScriptLockOrder->\$Script) ({});\r\ + \n /system/script/job/remove [ find where script=\$Script ];\r\ + \n }\r\ + \n :local MyTicket [ \$GetRandom20CharAlNum 6 ];\r\ + \n \$AddTicket \$Script \$MyTicket;\r\ + \n :local WaitInterval (\$WaitMax / 20);\r\ + \n :local WaitTime \$WaitMax;\r\ + \n :while (\$WaitTime > 0 && \\\r\ + \n ([ \$IsFirstTicket \$Script \$MyTicket ] = false || \\\r\ + \n [ \$TicketCount \$Script ] < [ \$JobCount \$Script ])) do={\r\ + \n :set WaitTime (\$WaitTime - \$WaitInterval);\r\ + \n :delay \$WaitInterval;\r\ + \n }\r\ + \n :if ([ \$IsFirstTicket \$Script \$MyTicket ] = true && \\\r\ + \n [ \$TicketCount \$Script ] = [ \$JobCount \$Script ]) do={\r\ + \n \$RemoveTicket \$Script \$MyTicket;\r\ + \n \$CleanupTickets \$Script;\r\ + \n :return true;\r\ + \n }\r\ + \n \$RemoveTicket \$Script \$MyTicket;\r\ + \n \$LogPrint debug \$0 (\"Script '\" . \$Script . \"' started more than \ + once\" . \\\r\ + \n [ \$IfThenElse (\$WaitTime < \$WaitMax) \" and timed out waiting for\ + \_lock\" \"\" ] . \"...\");\r\ + \n :return false;\r\ + \n}\r\ + \n\r\ + \n:set SendNotification do={ :onerror Err {\r\ + \n :global SendNotification2;\r\ + \n \$SendNotification2 ({ origin=\$0; subject=\$1; message=\$2; link=\$3;\ + \_silent=\$4 });\r\ + \n} do={:global ExitOnError; \$ExitOnError \$0 \$Err}\r\ + \n}\r\ + \n\r\ + \n:set SendNotification2 do={\r\ + \n :local Notification \$1;\r\ + \n :global NotificationFunctions;\r\ + \n :foreach FunctionName,Discard in=\$NotificationFunctions do={\r\ + \n (\$NotificationFunctions->\$FunctionName) (\"\\\$NotificationFunctio\ + ns->\\\"\" . \$FunctionName . \"\\\"\") \$Notification;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set SymbolByUnicodeName do={\r\ + \n :local Name [ :tostr \$1 ];\r\ + \n :global EitherOr;\r\ + \n :global SymbolsExtra;\r\ + \n :local Symbols ({\r\ + \n \"abacus\"=\"\\F0\\9F\\A7\\AE\";\r\ + \n \"alarm-clock\"=\"\\E2\\8F\\B0\";\r\ + \n \"arrow-down\"=\"\\E2\\AC\\87\";\r\ + \n \"arrow-up\"=\"\\E2\\AC\\86\";\r\ + \n \"calendar\"=\"\\F0\\9F\\93\\85\";\r\ + \n \"card-file-box\"=\"\\F0\\9F\\97\\83\";\r\ + \n \"chart-decreasing\"=\"\\F0\\9F\\93\\89\";\r\ + \n \"chart-increasing\"=\"\\F0\\9F\\93\\88\";\r\ + \n \"cloud\"=\"\\E2\\98\\81\";\r\ + \n \"cross-mark\"=\"\\E2\\9D\\8C\";\r\ + \n \"earth\"=\"\\F0\\9F\\8C\\8D\";\r\ + \n \"fire\"=\"\\F0\\9F\\94\\A5\";\r\ + \n \"floppy-disk\"=\"\\F0\\9F\\92\\BE\";\r\ + \n \"gear\"=\"\\E2\\9A\\99\";\r\ + \n \"heart\"=\"\\E2\\99\\A5\";\r\ + \n \"high-voltage-sign\"=\"\\E2\\9A\\A1\";\r\ + \n \"incoming-envelope\"=\"\\F0\\9F\\93\\A8\";\r\ + \n \"information\"=\"\\E2\\84\\B9\";\r\ + \n \"large-orange-circle\"=\"\\F0\\9F\\9F\\A0\";\r\ + \n \"large-red-circle\"=\"\\F0\\9F\\94\\B4\";\r\ + \n \"link\"=\"\\F0\\9F\\94\\97\";\r\ + \n \"lock-with-ink-pen\"=\"\\F0\\9F\\94\\8F\";\r\ + \n \"memo\"=\"\\F0\\9F\\93\\9D\";\r\ + \n \"mobile-phone\"=\"\\F0\\9F\\93\\B1\";\r\ + \n \"pushpin\"=\"\\F0\\9F\\93\\8C\";\r\ + \n \"scissors\"=\"\\E2\\9C\\82\";\r\ + \n \"scroll\"=\"\\F0\\9F\\93\\9C\";\r\ + \n \"smiley-partying-face\"=\"\\F0\\9F\\A5\\B3\";\r\ + \n \"smiley-smiling-face\"=\"\\E2\\98\\BA\";\r\ + \n \"smiley-winking-face-with-tongue\"=\"\\F0\\9F\\98\\9C\";\r\ + \n \"sparkles\"=\"\\E2\\9C\\A8\";\r\ + \n \"speech-balloon\"=\"\\F0\\9F\\92\\AC\";\r\ + \n \"star\"=\"\\E2\\AD\\90\";\r\ + \n \"warning-sign\"=\"\\E2\\9A\\A0\";\r\ + \n \"white-heavy-check-mark\"=\"\\E2\\9C\\85\"\r\ + \n }, \$SymbolsExtra);\r\ + \n :local Magic [ :pick [ /system/clock/get date ] 4 10 ];\r\ + \n :local Special {\r\ + \n \"information-04-01\"=\"\\F0\\9F\\9A\\BB\";\r\ + \n \"large-orange-circle-04-01\"=\"\\F0\\9F\\8D\\8A\";\r\ + \n \"large-orange-circle-10-31\"=\"\\F0\\9F\\8E\\83\";\r\ + \n \"large-red-circle-04-01\"=\"\\F0\\9F\\8D\\92\" };\r\ + \n :if ([ :len (\$Symbols->\$Name) ] = 0) do={\r\ + \n :log warning (\$0 . \"No symbol available for name '\" . \$Name . \"\ + '!\");\r\ + \n :return \"\";\r\ + \n }\r\ + \n :return ([ \$EitherOr (\$Special->(\$Name . \$Magic)) (\$Symbols->\$Na\ + me) ] . \"\\EF\\B8\\8F\");\r\ + \n}\r\ + \n\r\ + \n:set SymbolForNotification do={\r\ + \n :global NotificationsWithSymbols;\r\ + \n :global SymbolByUnicodeName;\r\ + \n :global IfThenElse;\r\ + \n :if (\$NotificationsWithSymbols != true) do={:return [ \$IfThenElse ([\ + \_:len \$2 ] > 0) ([ :tostr \$2 ] . \" \") \"\" ]}\r\ + \n :local Return \"\";\r\ + \n :foreach Symbol in=[ :toarray \$1 ] do={:set Return (\$Return . [ \$Sy\ + mbolByUnicodeName \$Symbol ])}\r\ + \n :return (\$Return . \" \");\r\ + \n}\r\ + \n\r\ + \n:set Unix2Dos do={:return [ :tocrlf [ :tostr \$1 ] ]}\r\ + \n:set UrlEncode do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :if ([ :len \$Input ] = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :local Chars (\"\\n\\r !\\\"#\\\$%&'()*+,:;<=>\?@[\\\\]^`{|}~\");\r\ + \n :local Subs { \"%0A\"; \"%0D\"; \"%20\"; \"%21\"; \"%22\"; \"%23\"; \"\ + %24\"; \"%25\"; \"%26\"; \"%27\";\r\ + \n \"%28\"; \"%29\"; \"%2A\"; \"%2B\"; \"%2C\"; \"%3A\"; \"%3B\"; \ + \"%3C\"; \"%3D\"; \"%3E\"; \"%3F\";\r\ + \n \"%40\"; \"%5B\"; \"%5C\"; \"%5D\"; \"%5E\"; \"%60\"; \"%7B\"; \ + \"%7C\"; \"%7D\"; \"%7E\" };\r\ + \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ + \n :local Char [ :pick \$Input \$I ];\r\ + \n :local Replace [ :find \$Chars \$Char ];\r\ + \n :if ([ :typeof \$Replace ] = \"num\") do={:set Char (\$Subs->\$Repla\ + ce)}\r\ + \n :set Return (\$Return . \$Char);\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set IsDNSResolving do={\r\ + \n :do {:resolve \"api.telegram.org\"} on-error={:return false}\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set IsFullyConnected do={\r\ + \n :global IsDNSResolving;\r\ + \n :global IsTimeSync;\r\ + \n :if ([ \$IsDNSResolving ] = false) do={:return false};\r\ + \n :if ([ \$IsTimeSync ] = false) do={:return false};\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set IsTimeSync do={\r\ + \n :global IsTimeSyncCached;\r\ + \n :global IsTimeSyncResetNtp;\r\ + \n :if (\$IsTimeSyncCached = true) do={:return true}\r\ + \n :if ([ /system/ntp/client/get enabled ] = true) do={\r\ + \n :if ([ /system/ntp/client/get status ] = \"synchronized\") do={\r\ + \n :set IsTimeSyncCached true;\r\ + \n :return true;\r\ + \n }\r\ + \n :local Uptime [ /system/resource/get uptime ];\r\ + \n :if ([ :typeof \$IsTimeSyncResetNtp ] = \"nothing\") do={\r\ + \n :set IsTimeSyncResetNtp \$Uptime;\r\ + \n }\r\ + \n :if (\$Uptime - \$IsTimeSyncResetNtp < 3m) do={:return false}\r\ + \n :log warning \"\$0 The ntp client is configured, but did not sync.\"\ + ;\r\ + \n :set IsTimeSyncResetNtp \$Uptime;\r\ + \n /system/ntp/client/set enabled=no;\r\ + \n :delay 20ms;\r\ + \n /system/ntp/client/set enabled=yes;\r\ + \n :return false;\r\ + \n }\r\ + \n :if ([ /system/license/get ]->\"level\" = \"free\" || \\\r\ + \n [ /system/resource/get ]->\"board-name\" = \"x86\") do={\r\ + \n :log debug \"\$0 No ntp client configured, relying on RTC for CHR fr\ + ee license and x86.\";\r\ + \n :return true;\r\ + \n }\r\ + \n :if ([ /ip/cloud/get update-time ] = true) do={\r\ + \n :if ([ :typeof [ /ip/cloud/get public-address ] ] = \"ip\") do={\r\ + \n :set IsTimeSyncCached true;\r\ + \n :return true;\r\ + \n }\r\ + \n :return false;\r\ + \n }\r\ + \n :log debug \"\$0 No time source configured! Returning gracefully...\";\ + \r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set FetchHugeFiles do={\r\ + \n :local ScriptName [ :tostr \$1 ];\r\ + \n :local Url [ :tostr \$2 ];\r\ + \n :local CheckCert [ :tostr \$3 ];\r\ + \n\r\ + \n :global CleanName;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global GetRandom20CharAlNum;\r\ + \n :global IfThenElse;\r\ + \n :global LogPrint;\r\ + \n :global MkDir;\r\ + \n :global RmDir;\r\ + \n :global RmFile;\r\ + \n :global WaitForFile;\r\ + \n\r\ + \n :set CheckCert [ \$IfThenElse (\$CheckCert = \"false\") \"no\" \"yes-w\ + ithout-crl\" ];\r\ + \n\r\ + \n :local DirName (\"tmpfs/\" . [ \$CleanName \$ScriptName ]);\r\ + \n :if ([ \$MkDir \$DirName ] = false) do={\r\ + \n \$LogPrint error \$0 (\"Failed creating directory!\");\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :local FileName (\$DirName . \"/\" . [ \$CleanName \$0 ] . \"-\" . [ \ + \$GetRandom20CharAlNum ]);\r\ + \n :onerror Err {\r\ + \n /tool/fetch check-certificate=\$CheckCert \$Url dst-path=\$FileName \ + \\\r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$ScriptName ] }) as-va\ + lue;\r\ + \n } do={\r\ + \n :if ([ \$WaitForFile \$FileName 500ms ] = true) do={\r\ + \n \$RmFile \$FileName;\r\ + \n }\r\ + \n \$LogPrint debug \$0 (\"Failed downloading from \" . \$Url . \" - \"\ + \_. \$Err);\r\ + \n \$RmDir \$DirName;\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :if ([ \$WaitForFile \$FileName 5s ] = false) do={\r\ + \n \$LogPrint debug \$0 (\"The file downloaded from \" . \$Url . \" did\ + \_not show up.\");\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :local FileSize [ /file/get \$FileName size ];\r\ + \n :local Return \"\";\r\ + \n :local VarSize 0;\r\ + \n :while (\$VarSize != \$FileSize) do={\r\ + \n :set Return (\$Return . ([ /file/read offset=\$VarSize chunk-size=32\ + 768 file=\$FileName as-value ]->\"data\"));\r\ + \n :set FileSize [ /file/get \$FileName size ];\r\ + \n :set VarSize [ :len \$Return ];\r\ + \n :if (\$VarSize > \$FileSize) do={\r\ + \n :delay 100ms;\r\ + \n }\r\ + \n }\r\ + \n \$RmDir \$DirName;\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set FetchUserAgentStr do={\r\ + \n :local Caller [ :tostr \$1 ];\r\ + \n :global GlobalScriptsUrl;\r\ + \n :global CommitBrief;\r\ + \n :global IfThenElse;\r\ + \n :local Resource [ /system/resource/get ];\r\ + \n :return (\"User-Agent: Mikrotik/\" . \$Resource->\"version\" . \" \" .\ + \_\$Resource->\"architecture-name\" . \\\r\ + \n \" \" . \$Caller . \"/Fetch (\" . \$GlobalScriptsUrl . \"; \" . [ \$\ + CommitBrief ] . \")\");\r\ + \n}\r\ + \n\r\ + \n:set ScriptInstallUpdate do={ :onerror Err {\r\ + \n :local Scripts [ :toarray \$1 ];\r\ + \n :local NewComment [ :tostr \$2 ];\r\ + \n :global InitSetup;\r\ + \n\r\ + \n :global CommitId;\r\ + \n :global ScriptUpdatesCRLF;\r\ + \n :global GlobalConfVersion;\r\ + \n :global Identity;\r\ + \n :global CertificateAvailable;\r\ + \n :global CheckSumsVerify;\r\ + \n :global GlobalScriptsUrl;\r\ + \n :global SumsDirAndFileName;\r\ + \n :global GlobalScriptsUrlSuffix;\r\ + \n :global EitherOr;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global Grep;\r\ + \n :global IfThenElse;\r\ + \n :global LogPrint;\r\ + \n :global ParseKeyValueStore;\r\ + \n :global RequiredRouterOS;\r\ + \n :global SendNotification2;\r\ + \n :global SymbolForNotification;\r\ + \n :global ValidateSyntax;\r\ + \n :global CommentsInScripts;\r\ + \n\r\ + \n :if ([ \$CertificateAvailable \"Root YE\" \"fetch\" ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Downloading certificate failed, trying wit\ + hout.\");\r\ + \n }\r\ + \n\r\ + \n :foreach Script in=\$Scripts do={\r\ + \n :if ([ :len [ /system/script/find where name=\$Script ] ] = 0) do={\ + \r\ + \n \$LogPrint info \$0 (\"Adding new script: \" . \$Script);\r\ + \n /system/script/add name=\$Script owner=\$Script source=\"#!rsc by \ + Vados\\n\" comment=\$NewComment;\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :local CommitIdBefore \$CommitId;\r\ + \n :local GlobalConfVersionBefore \$GlobalConfVersion;\r\ + \n :local ReloadGlobal false;\r\ + \n :local DeviceMode [ /system/device-mode/get ];\r\ + \n\r\ + \n :if (\$CheckSumsVerify = true) do={\r\ + \n :local CheckSums ({});\r\ + \n :do {\r\ + \n :local Url (\$GlobalScriptsUrl . \$SumsDirAndFileName . \$GlobalScr\ + iptsUrlSuffix);\r\ + \n \$LogPrint debug \$0 (\"Fetching checksums from url: \" . \$Url);\ + \r\ + \n :set CheckSums [ :deserialize from=json ([ /tool/fetch check-certi\ + ficate=yes-without-crl \\\r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$0 ] }) \$Url output\ + =user as-value ]->\"data\") ];\r\ + \n } on-error={ \$LogPrint warning \$0 (\"Err = \" . \$Err); }\r\ + \n }\r\ + \n\r\ + \n :foreach Script in=[ /system/script/find where source~\"^#!rsc by Vado\ + s\" ] do={\r\ + \n :local ScriptVal [ /system/script/get \$Script ];\r\ + \n :local ScriptInfo [ \$ParseKeyValueStore (\$ScriptVal->\"comment\") \ + ];\r\ + \n :local SourceNew;\r\ + \n\r\ + \n :foreach Scheduler in=[ /system/scheduler/find where on-event~(\"\\\ + \\b\" . \$ScriptVal->\"name\" . \"\\\\b\") ] do={\r\ + \n :local SchedulerVal [ /system/scheduler/get \$Scheduler ];\r\ + \n :if (\$ScriptVal->\"policy\" != \$SchedulerVal->\"policy\") do={\r\ + \n \$LogPrint warning \$0 (\"Policies differ for script '\" . \$Scr\ + iptVal->\"name\" . \"' and its scheduler '\" . \$SchedulerVal->\"name\" . \ + \"'!\");\r\ + \n }\r\ + \n }\r\ + \n :do {\r\ + \n :if (\$ScriptInfo->\"ignore\" = true) do={\r\ + \n \$LogPrint debug \$0 (\"Ignoring script '\" . \$ScriptVal->\"nam\ + e\" . \"', as requested.\");\r\ + \n :error true;\r\ + \n }\r\ + \n :if (\$CheckSumsVerify = true) do={\r\ + \n :local CheckSum (\$CheckSums->(\$ScriptVal->\"name\"));\r\ + \n :if ([ :len (\$ScriptInfo->\"base-url\") ] = 0 && [ :len (\$Scri\ + ptInfo->\"url-suffix\") ] = 0 && \\\r\ + \n [ :convert transform=md5 to=hex [ :tolf (\$ScriptVal->\"sou\ + rce\") ] ] = \$CheckSum) do={\r\ + \n \$LogPrint debug \$0 (\"Checksum for script '\" . \$ScriptVal-\ + >\"name\" . \"' matches, ignoring.\");\r\ + \n :error true;\r\ + \n }\r\ + \n }\r\ + \n :if ([ :len (\$ScriptInfo->\"certificate\") ] > 0) do={\r\ + \n :if ([ \$CertificateAvailable (\$ScriptInfo->\"certificate\") \"\ + fetch\" ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Downloading certificate failed, tryi\ + ng without.\");\r\ + \n }\r\ + \n }\r\ + \n :onerror Err {\r\ + \n :local BaseUrl [ \$EitherOr (\$ScriptInfo->\"base-url\") \$Globa\ + lScriptsUrl ];\r\ + \n :local UrlSuffix [ \$EitherOr (\$ScriptInfo->\"url-suffix\") \$G\ + lobalScriptsUrlSuffix ];\r\ + \n :local Url (\$BaseUrl . \$ScriptVal->\"name\" . \".rsc\" . \$Url\ + Suffix);\r\ + \n \$LogPrint warning \$0 (\"Fetching script '\" . (\$ScriptVal->\"\ + name\") . \"' from url: \" . \$Url);\r\ + \n :local Result [ /tool/fetch check-certificate=yes-without-crl \\\ + \r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$0 ] }) \$Url outp\ + ut=user as-value ];\r\ + \n :if (\$Result->\"status\" = \"finished\") do={\r\ + \n :set SourceNew [ :tolf (\$Result->\"data\") ];\r\ + \n } \r\ + \n } do={\r\ + \n \$LogPrint warning \$0 (\"Failed fetching script '\" . \$ScriptV\ + al->\"name\" . \"': \" . \$Err);\r\ + \n :if (\$Err != \"Fetch failed with status 404\") do={\r\ + \n :error false;\r\ + \n }\r\ + \n :if (\$ScriptVal->\"source\" = \"#!rsc by Vados\") do={\r\ + \n \$LogPrint warning \$0 (\"Removing dummy. Typo on installation\ + \?\");\r\ + \n /system/script/remove \$Script;\r\ + \n :error false;\r\ + \n }\r\ + \n :if (\$CheckSumsVerify = true) do={\r\ + \n :if ([ :len (\$ScriptInfo->\"base-url\") ] = 0 && [ :len (\$Sc\ + riptInfo->\"url-suffix\") ] = 0 && \\\r\ + \n [ :len \$CheckSum ] = 0) do={\r\ + \n \$LogPrint warning \$0 (\"Added the script manually\? Skip u\ + pdates with 'ignore=true' in comment.\");\r\ + \n }\r\ + \n }\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :if ([ :len \$SourceNew ] = 0) do={\r\ + \n \$LogPrint debug \$0 (\"No update for script '\" . (\$ScriptVal-\ + >\"name\") . \"'.\");\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :local SourceCRLF [ :tocrlf \$SourceNew ];\r\ + \n :if (\$InitSetup != true && ((\$ScriptVal->\"name\") != \"AM-Globa\ + lConfig\" || (\$ScriptVal->\"name\") != \"AM-GlobalFunc\")) do={\r\ + \n :if (\$SourceNew = (\$ScriptVal->\"source\") || \$SourceCRLF = (\ + \$ScriptVal->\"source\")) do={\r\ + \n \$LogPrint debug \$0 (\"Script '\" . (\$ScriptVal->\"name\") \ + . \"' source did not change. End of lines set to CRLF.\");\r\ + \n if (\$ScriptUpdatesCRLF = false) do={\r\ + \n :put [ :tolf \$SourceNew ];\r\ + \n \$LogPrint debug \$0 (\"Script '\" . (\$ScriptVal->\"name\"\ + ) . \"' source update end of lines to LF.\");\r\ + \n }\r\ + \n :error false;\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :if ([ :pick \$SourceNew 0 14 ] != \"#!rsc by Vados\") do={\r\ + \n \$LogPrint warning \$0 (\"Looks like new script '\" . \$ScriptVa\ + l->\"name\" . \"' is not valid (missing shebang = '\$shebang') Ignoring!\"\ + );\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :if (\$CommentsInScripts = true) do={\r\ + \n :local CommentLine [ \$Grep \$SourceNew (\"\\23 Script comment:\ + \_\") ];\r\ + \n :if ([ :len \$CommentLine ] = 0) do={\r\ + \n \$LogPrint debug \$0 (\"The search in new script '\" . (\$Scr\ + iptVal->\"name\") . \"' for comment in script body, is not found result Ig\ + noring!\");\r\ + \n :error false;\r\ + \n } else={\r\ + \n :if ([ :len (\$ScriptVal->\"comment\")] = 0 || [ :len (\$Scri\ + ptVal->\"comment\")] != [ :pick \$CommentLine ([ :find \$CommentLine \":\"\ + ] + 2) [ :len \$CommentLine] ]) do={\r\ + \n \$LogPrint debug \$0 (\"Exsiting comment for script '\" . (\ + \$ScriptVal->\"name\") . \"' is '\" . (\$ScriptVal->\"comment\") . \"'.\")\ + ;\r\ + \n :set (\$ScriptVal->\"comment\") [ :pick \$CommentLine ([ :f\ + ind \$CommentLine \":\"] + 2) [ :len \$CommentLine] ];\r\ + \n \$LogPrint debug \$0 (\"New comment (\" . (\$ScriptVal->\"c\ + omment\") . \") for script '\" . (\$ScriptVal->\"name\") . \"' has been ad\ + ded!\");\r\ + \n } else={\r\ + \n \$LogPrint debug \$0 (\"Comment for script '\" . (\$ScriptV\ + al->\"name\") . \"' did not change.\");\r\ + \n :error false;\r\ + \n }\r\ + \n } \r\ + \n }\r\ + \n\r\ + \n :local RequiredROS ([ \$ParseKeyValueStore [ \$Grep \$SourceNew (\ + \"\\23 requires RouterOS, \") ] ]->version);\r\ + \n :if ([ \$RequiredRouterOS \$0 [ \$EitherOr \$RequiredROS \"0.0\" ]\ + \_false ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"The script '\" . (\$ScriptVal->\"name\ + \") . \"' requires RouterOS \" . \\\r\ + \n \$RequiredROS . \", which is not met by your installation. I\ + gnoring!\");\r\ + \n :error false;\r\ + \n }\r\ + \n :local RequiredDM [ \$ParseKeyValueStore [ \$Grep \$SourceNew (\"\ + \\23 requires device-mode, \") ] ];\r\ + \n :local MissingDM ({});\r\ + \n :foreach Feature,Value in=\$RequiredDM do={\r\ + \n :if ([ :typeof (\$DeviceMode->\$Feature) ] = \"bool\" && (\$Devi\ + ceMode->\$Feature) = false) do={\r\ + \n :set MissingDM (\$MissingDM, \$Feature);\r\ + \n }\r\ + \n }\r\ + \n :if ([ :len \$MissingDM ] > 0) do={\r\ + \n \$LogPrint warning \$0 (\"The script '\" . (\$ScriptVal->\"name\ + \") . \"' requires disabled \" . \\\r\ + \n \"device-mode features (\" . [ :tostr \$MissingDM ] . \"). I\ + gnoring!\");\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :if ([ \$ValidateSyntax \$SourceNew ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Syntax validation for script '\" . (\$\ + ScriptVal->\"name\") . \"' failed! Ignoring!\");\r\ + \n :error false;\r\ + \n }\r\ + \n \r\ + \n :log info (\"Updating script: \" . (\$ScriptVal->\"name\") . \" Sc\ + ript comment: \" . (\$ScriptVal->\"comment\"));\r\ + \n\r\ + \n /system/script/set owner=(\$ScriptVal->\"name\") comment=(\$Script\ + Val->\"comment\") \\\r\ + \n source=[ \$IfThenElse (\$ScriptUpdatesCRLF = true) \$SourceCRL\ + F \$SourceNew ] \$Script;\r\ + \n :if (\$ScriptVal->\"name\" = \"AM-GlobalConfig\" || \\\r\ + \n \$ScriptVal->\"name\" = \"AM-GlobalFunc\" || \\\r\ + \n \$ScriptVal->\"name\" ~ (\"^(AM-GlobalFunc\\\\.d|mod)/.\")) d\ + o={\r\ + \n :set ReloadGlobal true;\r\ + \n }\r\ + \n } on-error={ }\r\ + \n }\r\ + \n :if (\$ReloadGlobal = true) do={\r\ + \n \$LogPrint info \$0 (\"Reloading global configuration and functions.\ + \");\r\ + \n :onerror Err {\r\ + \n :global InitSetup (a);\r\ + \n /system/script {run AM-GlobalConfig; run AM-GlobalFunc;};\r\ + \n } do={\$LogPrint error \$0 (\"Reloading global configuration and fun\ + ctions failed! \" . \$Err)}\r\ + \n }\r\ + \n :if (\$GlobalConfVersionBefore > \$GlobalConfVersion) do={\r\ + \n \$LogPrint warning \$0 (\"The configuration version decreased from \ + \" . \\\r\ + \n \$GlobalConfVersionBefore . \" to \" . \$GlobalConfVersion . \\\r\ + \n \". Installed an older version\?\");\r\ + \n }\r\ + \n :if (\$GlobalConfVersionBefore < \$GlobalConfVersion) do={\r\ + \n :global GlobalConfChanges;\r\ + \n :global GlobalConfMigration;\r\ + \n :local ChangeLogCode;\r\ + \n :if ([ :len \$ChangeLogCode ] > 0) do={\r\ + \n :if ([ \$ValidateSyntax \$ChangeLogCode ] = true) do={\r\ + \n :onerror Err {\r\ + \n [ :parse \$ChangeLogCode ];\r\ + \n } do={\$LogPrint warning \$0 (\"The changelog failed to run: \" \ + . \$Err)}\r\ + \n } else={\$LogPrint warning \$0 (\"The changelog failed syntax vali\ + dation!\")}\r\ + \n }\r\ + \n :if ([ :len \$GlobalConfMigration ] > 0) do={\r\ + \n :for I from=(\$GlobalConfVersionBefore + 1) to=\$GlobalConfVersion\ + \_do={\r\ + \n :local Migration (\$GlobalConfMigration->[ :tostr \$I ]);\r\ + \n :do {\r\ + \n :if ([ :typeof \$Migration ] != \"str\") do={\r\ + \n \$LogPrint debug \$0 (\"Migration code for change \" . \$I .\ + \_\" is not available.\");\r\ + \n :error false;\r\ + \n }\r\ + \n :if ([ \$ValidateSyntax \$Migration ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Migration code for change \" . \$I\ + \_. \" failed syntax validation!\");\r\ + \n :error false}\r\ + \n \$LogPrint info \$0 (\"Applying migration for change \" . \$I \ + . \": \" . \$Migration);\r\ + \n :onerror Err {\r\ + \n [ :parse \$Migration ];\r\ + \n } do={\$LogPrint warning \$0 (\"Migration code for change \" .\ + \_\$I . \" failed to run: \" . \$Err)}\r\ + \n } on-error={ }\r\ + \n }\r\ + \n }\r\ + \n :local NotificationMessage (\"The configuration version on \" . \$Id\ + entity . \" increased \" . \\\r\ + \n \"to \" . \$GlobalConfVersion . \", current configuration may nee\ + d modification. \" . \\\r\ + \n \"Please review and update global-config-overlay, then re-run glo\ + bal-config.\");\r\ + \n \$LogPrint info \$0 (\$NotificationMessage);\r\ + \n :if ([ :len \$GlobalConfChanges ] > 0) do={\r\ + \n :set NotificationMessage (\$NotificationMessage . \"\\n\\nChanges:\ + \");\r\ + \n :for I from=(\$GlobalConfVersionBefore + 1) to=\$GlobalConfVersion\ + \_do={\r\ + \n :local Change (\$GlobalConfChanges->[ :tostr \$I ]);\r\ + \n :set NotificationMessage (\$NotificationMessage . \"\\n \" . \\\ + \r\ + \n [ \$SymbolForNotification \"pushpin\" \"*\" ] . \$Change);\r\ + \n \$LogPrint info \$0 (\"Change \" . \$I . \": \" . \$Change);\r\ + \n }\r\ + \n } else={\r\ + \n :set NotificationMessage (\$NotificationMessage . \"\\n\\nNews and\ + \_changes are not available.\");\r\ + \n\r\ + \n }\r\ + \n\r\ + \n :if ([ :len \$GlobalConfChanges ] > 0) do={ :set GlobalConfChanges; \ + } else={ :global GlobalConfChanges (a); }\r\ + \n :if ([ :len \$GlobalConfMigration ] > 0) do={ :set GlobalConfMigrati\ + on; } else={ :global GlobalConfMigration (a); }\r\ + \n }\r\ + \n} do={\r\ + \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ + \n} }\r\ + \n\r\ + \n# load modules\r\ + \n:foreach Script in=[ /system/script/find where name ~ \"^(global-functio\ + ns\\\\.d|mod)/.\" ] do={\r\ + \n :local ScriptVal [ /system/script/get \$Script ];\r\ + \n :if ([ \$ValidateSyntax (\$ScriptVal->\"source\") ] = true) do={\r\ + \n :onerror Err {\r\ + \n /system/script/run \$Script;\r\ + \n } do={\r\ + \n \$LogPrint error \$0 (\"Module '\" . \$ScriptVal->\"name\" . \"' f\ + ailed to run: \" . \$Err);\r\ + \n }\r\ + \n } else={\r\ + \n \$LogPrint error \$0 (\"Module '\" . \$ScriptVal->\"name\" . \"' fai\ + led syntax validation, skipping.\");\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n# Add and fix global scheduler\r\ + \n:put \"Add or/and fix Global scheduler...\";\r\ + \n:local OnEvent \"/system/script { run AM-GlobalConfig; run AM-GlobalFunc\ + ; }\";\r\ + \n:local Comment \"Every Day Set Global Environment Variables\";\r\ + \n:if ([ :len [ /system/scheduler/find where name=\"AM-SetGlobalEnv\" ] ] \ + = 0) do={\r\ + \n /system/scheduler/add name=\"AM-SetGlobalEnv\" comment=\$Comment on-ev\ + ent=\$OnEvent start-time=startup;\r\ + \n}\r\ + \n:if ([ /system/scheduler/get \"AM-SetGlobalEnv\" comment ] != \$Comment)\ + \_do={\r\ + \n /system/scheduler/set \"AM-SetGlobalEnv\" comment=\$Comment;\r\ + \n}\r\ + \n:if ([ /system/scheduler/get \"AM-SetGlobalEnv\" on-event ] != \$OnEvent\ + ) do={\r\ + \n /system/scheduler/set \"AM-SetGlobalEnv\" on-event=\$OnEvent;\r\ + \n}\r\ + \n# Add Update Script scheduler\r\ + \n:put \"Add or/and fix Update Script scheduler\";\r\ + \n:set OnEvent \":global ScriptInstallUpdate; \\\$ScriptInstallUpdate;\";\ + \r\ + \n:set Comment \"Every Day Check For Update Scripts\";\r\ + \n:if ([ :len [ /system/scheduler/find where name=\"AM-ScriptInstallUpdate\ + \" ] ] = 0) do={\r\ + \n/system/scheduler/add name=\"AM-ScriptInstallUpdate\" comment=\$Comment \ + start-time=startup interval=1d on-event=\$OnEvent;\r\ + \n}\r\ + \n\r\ + \n:onerror Err {\r\ + \n :global GlobalConfReady;\r\ + \n :retry { :if (\$GlobalConfReady != true) do={ :error (\"Global configs\ + \_not ready.\"); }; } delay=100ms max=5;\r\ + \n\r\ + \n:log warning (\"This script \$ScriptName Loaded \" . \\\r\ + \n [ \$IfThenElse (\$CommitId != \"unknown\") ([ \$CommitBrief ] . \" \ + \") ] . \\\r\ + \n \"on \" . \$devBoardName . \"\\nRouterOS: \" . \$devCurVersion . \"\ + \\nArchitecture: \" . \$devCurArch . \"\\nIdentity: \" . \$Identity);\r\ + \n # signal we are ready\r\ + \n:set GlobalFuncReady true;\r\ + \n:set ExitOK true;\r\ + \n\r\ + \n:log info (\$0 . \"Global configs ready!\");\r\ + \n} do={\r\ + \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ + \n}\r\ + \n" +add comment=\ + "Lookup IP addresses for RKN list and add them to firewall address-list" \ + dont-require-permissions=no name=AM-RKN-dnsLookup owner=AM-RKN-dnsLookup \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + source="#!rsc by Vados\r\ + \n# RouterOS script: AM-RKN-dnsLookup\r\ + \n# Script comment: Lookup IP addresses for RKN list and add them to firew\ + all address-list\r\ + \n# Copyright (c) 2007-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version=7.19\r\ + \n# requires device-mode, fetch\r\ + \n#\r\ + \n# Script description: This script is intended to be run periodically, e.\ + g. once a day, to update the IP addresses in the firewall address-list bas\ + ed on the RKN list.\r\ + \n# It resolves the domain names in the RKN list and a\ + dds the corresponding IP addresses to the specified firewall address-list.\ + \r\ + \n# The script also handles CNAME records by following\ + \_them until it finds A records.\r\ + \n# Usage:\r\ + \n# /system/script { run AM-RKN-dnsLookup; }\r\ + \n:local ScriptName [ :jobname ];\r\ + \n\r\ + \n:global dnsLookupReady false;\r\ + \n:if ([:typeof \$dnsLookupReady] != \"boolean\") do={ :set dnsLookupReady\ + \_true; }\r\ + \nwhile (!\$dnsLookupReady) do={ :nothing; }\r\ + \n:set dnsLookupReady false;\r\ + \n\r\ + \n:local arrRKN {\r\ + \n \"telegra.ph\"\r\ + \n \"grani.ru\"\r\ + \n \"xhamster.com\"\r\ + \n \"lostfilm.tv\"\r\ + \n \"rutracker.org\"\r\ + \n \"lurkmore.to\"\r\ + \n \"dou.ua\"\r\ + \n \"youporn.com\"\r\ + \n \"pornolab.net\"\r\ + \n \"crimerussia.com\"\r\ + \n \"telegram.org\"\r\ + \n \"api.telegram.org\"\r\ + \n \"facebook.com\"\r\ + \n \"instagram.com\"\r\ + \n \"x.com\"\r\ + \n \"twitter.com\"\r\ + \n \"youtube.com\"\r\ + \n \"googleapis.com\"\r\ + \n \"youtu.be\"\r\ + \n \"googlevideo.com\"\r\ + \n \"gstatic.com\"\r\ + \n \"googleusercontent.com\"\r\ + \n \"nhacmp3youtube.com\"\r\ + \n \"telegram.me\"\r\ + \n \"t.me\";}\r\ + \n\r\ + \n:local ListRKN \"RKN-dnsLookup\";\r\ + \n:local ListComment (\"ListRKN managed by \" . \$ScriptName);\r\ + \n:foreach aListItem in=[/ip/firewall/address-list find list=\$ListRKN] do\ + ={\r\ + \n /ip firewall address-list remove \$aListItem;\r\ + \n}\r\ + \n:foreach aItem in=\$arrRKN do={\r\ + \n# :do {\r\ + \n :retry delay=500ms max=5 on-error={:log error \"dns resolve fail\ + ure [ \$aItem - resolve ip ]\"} command={:resolve \$aItem}\r\ + \n# } on-error={\r\ + \n# :log error \"dns resolve failure [ \$arItem - resolve ip ]\";\r\ + \n# }\r\ + \n :foreach dnsRecord in=[/ip dns cache all find where (name=\$aItem)] \ + do={\r\ + \n :if ([/ip dns cache all get \$dnsRecord type]=\"A\") do={\r\ + \n :local newAddress [/ip dns cache all get \$dnsRecord data];\ + \r\ + \n :do {\r\ + \n /ip firewall address-list add list=\$ListRKN address=\$newA\ + ddress comment=\$aItem;\r\ + \n :log warning \"Successfully adding ip to list A record: \ + \$dnsRecord, address: \$newAddress domain: \$aItem\";\r\ + \n } on-error={\r\ + \n :log error \"error when adding ip to list A record: \$dn\ + sRecord, address: \$newAddress domain: \$aItem\";\r\ + \n }\r\ + \n }\r\ + \n :if ([/ip dns cache all get \$dnsRecord type]=\"CNAME\") do={\r\ + \n :local cname;\r\ + \n :local nextCname;\r\ + \n :local cnameAddress;\r\ + \n :set cname [/ip dns cache all find where (name=\$aItem && ty\ + pe=\"CNAME\")];\r\ + \n :set nextCname [/ip dns cache all find where (name=[/ip dns \ + cache all get \$cname data] && type=\"CNAME\")];\r\ + \n :while (\$nextCname != \"\") do={\r\ + \n :set cname \$nextCname;\r\ + \n :set nextCname [/ip dns cache all find where (name=[/ip \ + dns cache all get \$cname data] && type=\"CNAME\")];\r\ + \n }\r\ + \n :foreach aRecord in=[/ip dns cache all find where (name=[/ip\ + \_dns cache all get \$cname data] && type=\"A\")] do={\r\ + \n :do {\r\ + \n :set cnameAddress [/ip dns cache all get \$aRecord d\ + ata];\r\ + \n /ip firewall address-list add list=\$ListRKN address\ + =\$cnameAddress comment=\$aItem;\r\ + \n :log warning \"Succesfully adding ip to list CNAME r\ + ecord: \$cname, A record: \$aRecord, address: \$newAddress, from domain: \ + \$aItem.\";\r\ + \n# /ip firewall raw add action=add-dst-to-address-list\ + \_address-list=\$ListRKN address-list-timeout=none-dynamic chain=preroutin\ + g comment=\$aItem content=\$aItem;\r\ + \n } on-error={\r\ + \n :log error \"error when adding ip to list CNAME reco\ + rd: \$cname, A record: \$aRecord, address: \$newAddress, from domain: \$aI\ + tem.\";\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:if ([ :len [ /system/scheduler/find where name=\$ScriptName ] ] = 0) do\ + ={\r\ + \n :log error (\$ScriptName . \"System Scheduler for script: \" . \$Scri\ + ptName . \" is NOT SET! Fix It Now!\");\r\ + \n /system/scheduler/add name=\$ScriptName on-event=\"/system/script { \ + run \$ScriptName; }\" comment=\"Update RKN DNS Looup\" interval=00:30:00 p\ + olicy=\"ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon\"\ + \_start-time=startup;\r\ + \n }\r\ + \n:set dnsLookupReady true;\r\ + \ndelay 2s; \r\ + \n:global dnsLookupReady (a);\r\ + \n" +add dont-require-permissions=no name="renameLists " owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + local oldName \"Test\";\ + \n:local newName \"Test-IP\";\ + \n/ip firewall address-list\ + \n:foreach i in=[find list=\$oldName] do={\ + \nset \$i list=\$newName;\ + \n}\ + \n" +add dont-require-permissions=no name=IPv6-Settings owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + #############Script Settings##################\ + \n\ + \n:local \"IF-TUN\" \"6to4-tun\"\ + \n:local \"IF-LOC\" \"Bridge-LAN\"\ + \n:local \"POOL-6TO4\" \"poolV6-local\"\ + \n:local \"force-update\" false\ + \n############ use then static ip #######################\ + \n:local \"lease-address\" [/ip address get [find interface=\$\"IF-LOC\"] \ + address]\ + \n#:local \"interface\" \"ext\"\ + \n:local bound 0\ + \n\ + \n###############################################\ + \n\ + \n:local 6to4prefix do={\ + \n :global dec2hex\ + \n :local ipv4 \$1\ + \n :local ipv6 \"2002:\"\ + \n :for i from=0 to=2 step=1 do={ \ + \n :if ( \$i = 2) do={\ + \n :set ipv6 (\$ipv6.\":\")\ + \n }\ + \n :local fp [:find \$ipv4 \".\"]\ + \n :if ( \$fp > 0 ) do={\ + \n :set ipv6 (\$ipv6.[\$dec2hex [:pick \$ipv4 0 \$fp]])\ + \n :set ipv4 [:pick \$ipv4 (\$fp + 1 ) [:len \$ipv4]]\ + \n }\ + \n }\ + \n :return (\$ipv6.[\$dec2hex \$ipv4])\ + \n}\ + \n:local \"str_replace\" do={\ + \n :local \"str-pos\" [:find \$1 \$2]\ + \n :local \"str-len\" [:len \$2]\ + \n :local str \"\"\ + \n :local rest \$1\ + \n :while (\$\"str-pos\" >= 0) do={\ + \n :local t [:pick \$rest 0 \$\"str-pos\"]\ + \n :if ( \$4 > 0 ) do={\ + \n :for i from=1 to=(\$4 - [:len \$t]) step=1 do={\ + \n :set str (\$str.\$5)\ + \n }\ + \n }\ + \n :set str (\$str.\$t.\$3)\ + \n :set rest [:pick \$rest (\$\"str-pos\"+\$\"str-len\") [:len \$re\ + st]]\ + \n :set \"str-pos\" [:find \$rest \$2]\ + \n }\ + \n :return (\$str.\$rest)\ + \n}\ + \n\ + \n:if (\$bound=1) do={\ + \n :local t [:find \$\"lease-address\" \"/\"]\ + \n\ + \n :if ( \$t >= 0 ) do={\ + \n :set \"lease-address\" [:pick \$\"lease-address\" 0 \$t]\ + \n }\ + \n\ + \n :if ( [/interface 6to4 print count-only where name=\$\"IF-TUN\"] = 0\ + ) do={\ + \n /interface 6to4 add !keepalive local-address=\$\"lease-address\"\ + \_mtu=1280 name=\$\"IF-TUN\" remote-address=10.30.30.0\ + \n :set \"force-update\" true\ + \n }\ + \n\ + \n :local \"IPv4-TUN\" [/interface 6to4 get [find name=\$\"IF-TUN\"] lo\ + cal-address];\ + \n\ + \n :if ( \$\"lease-address\" != \$\"IPv4-TUN\" || \$\"force-update\" = \ + true) do={\ + \n /interface 6to4 set [find name=\$\"IF-TUN\"] local-address=\$\"l\ + ease-address\"\ + \n /ipv6 address remove [find interface=\$\"IF-TUN\"]\ + \n /ipv6 address remove [find interface=\$\"IF-LOC\"]\ + \n /ipv6 route remove [find gateway ~ \$\"IF-TUN\" and dst-address=\ + \"::/0\"]\ + \n :local \"pool-prefix\" [\$6to4prefix \$\"lease-address\"]\ + \n :if ( [/ipv6 pool print count-only where name=\$\"POOL-6TO4\"] =\ + \_0) do={ \ + \n /ipv6 pool add name=\$\"POOL-6TO4\" prefix=(\$\"pool-prefix\ + \".\":1::/64\") prefix-length=64\ + \n } else={\ + \n /ipv6 pool set [/ipv6 pool find where name=\$\"POOL-6TO4\"] \ + prefix=(\$\"pool-prefix\".\":1::/64\")\ + \n }\ + \n /ipv6 address add address=(\$\"pool-prefix\".\"::\".[\$MAC2EUI64\ + \_[/interface get [find name=\$\"interface\"] mac-address]].\"/3\") interf\ + ace=\$\"IF-TUN\" advertise=no\ + \n /ipv6 address add eui-64=yes from-pool=\$\"POOL-6TO4\" interface\ + =\$\"IF-LOC\" advertise=yes\ + \n /ipv6 route add dst-address=::/0 gateway=(\"::10.30.30.81%\".\$\ + \"IF-TUN\")\ + \n :local t [/ipv6 address get [find interface=\$\"IF-LOC\"] addres\ + s]\ + \n :set t [:pick \$t 0 [:find \$t \"/\"]]\ + \n :if ( [/ipv6 dhcp-server option print count-only where name=DNS]\ + \_= 0) do={\ + \n /ipv6 dhcp-server option add code=23 name=DNS value=(\"0x\".\ + [\$\"str_replace\" \$t \":\" \"\" 4 \"0\"])\ + \n } else={\ + \n /ipv6 dhcp-server option set [/ipv6 dhcp-server option find \ + where name=DNS] value=(\"0x\".[\$\"str_replace\" \$t \":\" \"\" 4 \"0\"])\ + \n }\ + \n :if ( [/ipv6 dhcp-server print count-only where interface=\$\"IF\ + -LOC\"] = 0) do={\ + \n /ipv6 dhcp-server add address-pool=\$\"POOL-6TO4\" dhcp-opti\ + on=DNS interface=\$\"IF-LOC\" lease-time=1d name=\$\"IF-LOC\"\ + \n }\ + \n :if ( [ipv6 nd print count-only where interface=\$\"IF-LOC\"] = \ + 0) do={\ + \n /ipv6 nd add advertise-dns=no interface=\$\"IF-LOC\" other-c\ + onfiguration=yes\ + \n }\ + \n }\ + \n}" +add dont-require-permissions=no name=IPv6-GlobalFunc owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + global MAC2EUI64 do={\ + \n :local EUI64 \"\"\ + \n :local MAC \$1\ + \n :local HEX2DEC \"0123456789ABCDEF\"\ + \n :for i from=0 to=5 step=1 do={\ + \n :if ( \$i = 0 ) do={\ + \n :set EUI64 [:pick \$MAC 0]\ + \n :set EUI64 (\$EUI64.[:tostr [:pick \$\"HEX2DEC\" ([:find \$\ + \"HEX2DEC\" [:pick \$MAC 1]] ^ 2)]])\ + \n }\ + \n :if ( \$i = 1 || \$i = 3) do={\ + \n :set EUI64 (\$EUI64.\":\")\ + \n }\ + \n :if ( \$i = 2 ) do={\ + \n :set EUI64 (\$EUI64.\"FF:FE\")\ + \n }\ + \n :if ( [:find \$MAC \":\"] = 2 ) do={\ + \n :set MAC [:pick \$MAC 3 [:len \$MAC]]\ + \n :set EUI64 (\$EUI64.[:pick \$MAC 0 2])\ + \n }\ + \n }\ + \n :return (\$EUI64)\ + \n}\ + \n\ + \n:global dec2hex do={\ + \n :local hex \"\"\ + \n :local dec [:tonum \$1]\ + \n :for i from=0 to=4 step=4 do={\ + \n :set hex ([:pick \"0123456789ABCDEF\" ((\$dec>>\$i)&0xf) (((\$de\ + c>>\$i)&0xf)+1)].\$hex)\ + \n }\ + \n :return ([:tostr \$hex])\ + \n}" +add comment=Generator dont-require-permissions=no name=proxySet owner=vados \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + source="# 2. WireGuard interface\r\ + \n/interface/wireguard/add name=wg-VDSina private-key=\"4CHyNhbOs923/EyNDg\ + uMXJXdghL2I3UyzXPwrANVgHs=\" listen-port=21641\r\ + \n/interface/wireguard/peers/add interface=wg-VDSina public-key=\"o5IgCl1/\ + G6xbl6j7sPaP4ZNYREeYOmqZjKbm+v0b9jU=\" preshared-key=\"RNvF7T1cg5tyXcYQnD9\ + N5BEp6e20vVJQTv0GMjyvHU0=\" endpoint-address=10.30.30.33 endpoint-port=518\ + 20 allowed-address=0.0.0.0/0 persistent-keepalive=11\r\ + \n/ip/address/add address=10.9.0.3/32 interface=wg-VDSina\r\ + \n\r\ + \n# 3. DNS\r\ + \n{ :local rawDNS [/ip/dns/get servers]; :local prevDNS \"\"; :foreach s i\ + n=[:toarray \$rawDNS] do={ :if ([:len \$prevDNS] > 0) do={ :set prevDNS \"\ + \$prevDNS,\$s\" } else={ :set prevDNS \$s } }; /system/script/add name=VDS\ + ina-prev-dns comment=\"\$prevDNS\" source=\"\" }\r\ + \n/ip/dns/set servers=8.8.4.4\r\ + \n/ip/route/add dst-address=8.8.4.4/32 gateway=wg-VDSina distance=1 commen\ + t=VDSina-dns\r\ + \n\r\ + \n# 4. Enable WireGuard\r\ + \n/interface/wireguard/enable wg-VDSina\r\ + \n" +/user group +add name=backup policy="ssh,read,write,policy,test,web,sniff,sensitive,api,res\ + t-api,!local,!telnet,!ftp,!reboot,!winbox,!password,!romon" +/ip smb +set enabled=no interfaces=lo +/interface bridge port +add bridge=Bridge-LAN interface=ether5 +add bridge=Bridge-LAN interface=ether2 +add bridge=Bridge-LAN interface=ether4 trusted=yes +add bridge=Bridge-LAN interface=ether3 +add bridge=Bridge-LAN interface=wlan2 +add bridge=Bridge-LAN interface=wlan1 +/interface bridge settings +set use-ip-firewall=yes +/ip firewall connection tracking +set udp-timeout=10s +/ip neighbor discovery-settings +set discover-interface-list=LAN lldp-med=no lldp-poe-power=no +/ip settings +set accept-redirects=yes ipv4-multipath-hash-policy=l4 max-neighbor-entries=\ + 8192 +/ipv6 settings +set disable-ipv6=yes disable-link-local-address=yes forward=no \ + max-neighbor-entries=8192 multipath-hash-policy=l4 +/interface detect-internet +set detect-interface-list=WAN internet-interface-list=Internet \ + lan-interface-list=LAN request-interval=1m wan-interface-list=WAN +/interface l2tp-server server +set authentication=mschap2 use-ipsec=yes +/interface list member +add interface="ether1 - Unet" list=Internet +add interface=WG list=WAN +add interface=Bridge-LAN list=LAN +add interface="ether1 - Unet" list=WAN +/interface wireguard peers +add allowed-address=0.0.0.0/0 client-allowed-address=::/0 disabled=yes \ + endpoint-address=109.107.177.79 endpoint-port=29185 interface=WG name=\ + VDSina persistent-keepalive=10s public-key=\ + "zuRsO+dL/j6awaBWZ/NgnHR+bCNUjRWbaHFpdzkNnw4=" +add allowed-address=10.10.0.1/24 client-address=10.10.0.2/32 \ + client-allowed-address=0.0.0.0/0 client-dns=8.8.8.8 client-endpoint=\ + 10.30.30.81 client-keepalive=10s client-listen-port=22022 disabled=yes \ + endpoint-address=10.30.30.10 endpoint-port=22022 interface=NUC name=\ + MicroNuc persistent-keepalive=10s public-key=\ + "oieVxNCDa4G5LU2QVH+s4AXwapSmdiDvVVhBS/FPdTA=" responder=yes +add allowed-address=0.0.0.0/0 client-allowed-address=::/0 disabled=yes \ + endpoint-address=10.30.30.33 endpoint-port=44044 interface=wg-VDSina \ + name=peer11 persistent-keepalive=11s public-key=\ + "o5IgCl1/G6xbl6j7sPaP4ZNYREeYOmqZjKbm+v0b9jU=" +/interface wireless cap +# +set bridge=Bridge-LAN caps-man-addresses=10.30.30.10 \ + caps-man-certificate-common-names=CAPsMAN-51B25E507D07 certificate=\ + CAP-488F5A8E1ABC discovery-interfaces=Bridge-LAN enabled=yes interfaces=\ + wlan2,wlan1 lock-to-caps-man=yes +/ip address +add address=10.30.30.81/24 interface=Bridge-LAN network=10.30.30.0 +add address=10.8.0.2/24 disabled=yes interface=WG network=10.8.0.0 +add address=10.9.0.3 disabled=yes interface=wg-VDSina network=10.9.0.3 +/ip cloud +set update-time=no +/ip dhcp-client +add add-default-route=special-classless default-route-distance=2 \ + default-route-tables=main:2 dhcp-options=clientid,clientid_duid \ + interface="ether1 - Unet" name=client1 use-peer-dns=no use-peer-ntp=no +/ip dhcp-server config +set accounting=no +/ip dhcp-server lease +add address=10.30.30.101 client-id=1:48:8f:5a:8e:ee:a8 mac-address=\ + 48:8F:5A:8E:EE:A8 server=masterDHCP +add address=10.30.30.107 client-id=1:f0:de:f1:91:d:1e mac-address=\ + F0:DE:F1:91:0D:1E server=masterDHCP +add address=10.30.30.83 client-id=1:0:80:77:ec:43:86 mac-address=\ + 00:80:77:EC:43:86 server=masterDHCP +add address=10.30.30.70 dhcp-option=domain-search-list,HostName \ + dhcp-option-set=HP1505n mac-address=00:1E:0B:1A:88:8D server=masterDHCP +add address=10.30.30.50 client-id=1:4:7c:16:36:f5:37 mac-address=\ + 04:7C:16:36:F5:37 server=masterDHCP +add address=10.30.30.71 client-id=1:10:2d:41:2c:20:c2 mac-address=\ + 10:2D:41:2C:20:C2 server=masterDHCP +add address=10.30.30.61 client-id=1:10:8:c1:81:59:5f mac-address=\ + 10:08:C1:81:59:5F server=masterDHCP +add address=10.30.30.72 client-id=1:10:38:1f:d2:5f:13 mac-address=\ + 10:38:1F:D2:5F:13 server=masterDHCP +add address=10.30.30.99 client-id=1:10:b1:df:e9:d0:d5 mac-address=\ + 10:B1:DF:E9:D0:D5 server=masterDHCP +add address=10.30.30.111 client-id=1:fe:2:52:be:3f:16 mac-address=\ + FE:02:52:BE:3F:16 server=masterDHCP +add address=10.30.30.92 client-id=1:d4:6d:6d:fd:e5:49 mac-address=\ + D4:6D:6D:FD:E5:49 server=masterDHCP +add address=10.30.30.93 client-id=1:7e:8b:1e:cb:b8:cb mac-address=\ + CC:42:10:12:46:94 server=masterDHCP +add address=10.30.30.94 client-id=1:50:cc:f8:85:96:a mac-address=\ + 50:CC:F8:85:96:0A server=masterDHCP +add address=10.30.30.82 client-id=1:e4:18:6b:58:34:ab mac-address=\ + E4:18:6B:58:34:AB server=masterDHCP +add address=10.30.30.75 client-id=1:0:27:15:41:97:a9 mac-address=\ + 00:27:15:41:97:A9 server=masterDHCP +add address=10.30.30.77 dhcp-option=HostName dhcp-option-set=StartLife1 \ + mac-address=C4:82:E1:03:49:10 server=masterDHCP +add address=10.30.30.73 client-id=1:10:38:1f:82:81:f2 mac-address=\ + 10:38:1F:82:81:F2 server=masterDHCP +add address=10.30.30.95 client-id=1:88:ae:dd:60:39:54 dhcp-option=HostName \ + dhcp-option-set=VADOS-NUC mac-address=88:AE:DD:60:39:54 server=masterDHCP +add address=10.30.30.98 client-id=1:c8:5b:76:d8:cc:bf dhcp-option=HostName \ + dhcp-option-set=VADOS-LEN mac-address=C8:5B:76:D8:CC:BF server=masterDHCP +add address=10.30.30.96 client-id=iPhone mac-address=4A:91:ED:0E:1F:39 \ + server=masterDHCP +add address=10.30.30.74 client-id=MiTV dhcp-option=HostName dhcp-option-set=\ + MiTV mac-address=20:72:A9:D3:34:36 server=masterDHCP +add address=10.30.30.30 dhcp-option=HostName dhcp-option-set=miller \ + mac-address=F0:75:5D:1E:5F:71 server=masterDHCP +add address=10.30.30.100 client-id=iVados dhcp-option=HostName \ + dhcp-option-set=iVados mac-address=DE:4D:72:F3:1A:9F server=masterDHCP +add address=10.30.30.10 allow-dual-stack-queue=yes client-id=\ + ff:0:0:0:df:0:3:0:1:f0:75:5d:1e:5f:85 dhcp-option=HostName \ + dhcp-option-set=MikroNUC mac-address=F0:75:5D:1E:5F:85 server=masterDHCP \ + use-src-mac=yes +/ip dhcp-server network +add address=10.30.30.0/24 caps-manager=10.30.30.10 dhcp-option=\ + domain-search-list dhcp-option-set=domain-search-set dns-server=\ + 10.30.30.33,109.107.177.79 domain=WORKGROUP gateway=10.30.30.81 netmask=\ + 24 ntp-server=10.30.30.81,10.30.30.10 wins-server=10.30.30.95,10.30.30.98 +/ip dns +set allow-remote-requests=yes cache-max-ttl=1d doh-max-concurrent-queries=100 \ + doh-max-server-connections=20 servers=8.8.4.4 verify-doh-cert=yes +/ip dns static +add address=109.107.177.79 comment="VDSina Server DNS" name=ns1.vados.ru \ + type=A +add address=109.107.177.79 name=vds.vados.ru type=A +add comment="Local DNS server for vados.ru" disabled=yes ns=10.30.30.81 \ + regexp=*.vados.ru type=NS +add comment="*.vados.ru Regexp" disabled=yes forward-to=10.30.30.81 regexp=\ + "\".*\\\\.vados\\\\.ru\"" type=FWD +add comment="*.30.30.10.in-addr.arpa Regexp" disabled=yes forward-to=\ + 10.30.30.81 regexp="\".*\\\\.30\\\\.30\\\\.10\\\\.in-addr\\\\.arpa" type=\ + FWD +add address=10.30.30.81 comment=NS.vados.ru.local disabled=yes name=\ + ns.vados.ru.local type=A +add comment="DNS ns.vados.ru.local" disabled=yes match-subdomain=yes name=\ + vados.ru ns=ns.vados.ru.local type=NS +add address=10.30.30.33 comment=reg.vados.ru name=reg.vados.ru type=A +add address=8.8.8.8 comment="Google-dns IPv4 1" match-subdomain=yes name=\ + dns.google type=A +add address=8.8.4.4 comment="Google-dns IPv4 2" name=dns.google type=A +add address=10.30.30.33 comment=AMSTER name=amster.vados.ru type=A +add address=10.30.30.33 name=ros.vados.ru type=A +add address=10.30.30.95 name=vados-nuc type=A +add address=10.30.30.33 name=amster-nuc type=A +add address=10.30.30.33 name=amster type=A +add address=10.30.30.33 name=amster-reg type=A +add address=10.30.30.33 disabled=yes name=mng.vados.ru type=A +add address=10.30.30.33 name=mgr.vados.ru type=A +add address=10.30.30.33 name=prt.vados.ru type=A +add address=10.30.30.33 disabled=yes match-subdomain=yes name=\ + mikrots.vados.ru type=A +add address=10.30.30.30 comment=MILLER name=miller.vados.ru type=A +add address=10.30.30.30 name=MILLER-LEN type=A +add address=10.30.30.30 name=miller type=A +add address=1.0.0.1 comment="CloudFlare-doh IPv4 2" disabled=yes name=\ + security.cloudflare-dns.com type=A +add address=1.1.1.1 comment="CloudFlare-doh IPv4 1" disabled=yes name=\ + security.cloudflare-dns.com type=A +add address=9.9.9.9 comment="Cuad9-dns IPv4 1" disabled=yes name=\ + dns.quad9.net type=A +add address=149.112.112.112 comment="Cuad9-dns IPv4 2" disabled=yes name=\ + dns.quad9.net type=A +add address=195.133.25.16 comment="DNS Comss" disabled=yes name=dns.comss.one \ + type=A +add address=10.30.30.81 comment=LocalNet name=MikroVados type=A +add address=10.30.30.10 name=MikroNUC type=A +add address=10.30.30.86 disabled=yes name=MikroYellow type=A +add address=10.30.30.85 disabled=yes name=MikroMic type=A +add address=10.30.30.95 name=VADOS-NUC type=A +add address=10.30.30.98 name=VADOS-LEN type=A +add address=91.192.189.2 comment=Unet-DNS disabled=yes name=ns1.unet.ws type=\ + A +add address=10.30.30.20 disabled=yes name=garage type=A +/ip firewall address-list +add address=91.215.120.206 list=TRUSTED +add address=185.71.70.78 disabled=yes list=TRUSTED +add address=176.53.203.171 disabled=yes list=TRUSTED +add address=176.53.203.170 disabled=yes list=TRUSTED +add address=176.53.202.194 disabled=yes list=TRUSTED +add address=8.8.4.0/24 list=YouTube +add address=8.8.8.0/24 list=YouTube +add address=8.34.208.0/20 list=YouTube +add address=8.35.192.0/20 list=YouTube +add address=23.236.48.0/20 list=YouTube +add address=23.251.128.0/19 list=YouTube +add address=34.0.0.0/15 list=YouTube +add address=34.2.0.0/16 list=YouTube +add address=34.3.0.0/23 list=YouTube +add address=34.3.3.0/24 list=YouTube +add address=34.3.4.0/24 list=YouTube +add address=34.3.8.0/21 list=YouTube +add address=34.3.16.0/20 list=YouTube +add address=34.3.32.0/19 list=YouTube +add address=34.3.64.0/18 list=YouTube +add address=34.4.0.0/14 list=YouTube +add address=34.8.0.0/13 list=YouTube +add address=34.16.0.0/12 list=YouTube +add address=34.32.0.0/11 list=YouTube +add address=34.64.0.0/10 list=YouTube +add address=34.128.0.0/10 list=YouTube +add address=35.184.0.0/13 list=YouTube +add address=35.192.0.0/14 list=YouTube +add address=35.196.0.0/15 list=YouTube +add address=35.198.0.0/16 list=YouTube +add address=35.199.0.0/17 list=YouTube +add address=35.199.128.0/18 list=YouTube +add address=35.200.0.0/13 list=YouTube +add address=35.208.0.0/12 list=YouTube +add address=35.224.0.0/12 list=YouTube +add address=35.240.0.0/13 list=YouTube +add address=57.140.192.0/18 list=YouTube +add address=64.15.112.0/20 list=YouTube +add address=64.233.160.0/19 list=YouTube +add address=66.22.228.0/23 list=YouTube +add address=66.102.0.0/20 list=YouTube +add address=66.249.64.0/19 list=YouTube +add address=70.32.128.0/19 list=YouTube +add address=72.14.192.0/18 list=YouTube +add address=74.125.0.0/16 list=YouTube +add address=104.154.0.0/15 list=YouTube +add address=104.196.0.0/14 list=YouTube +add address=104.237.160.0/19 list=YouTube +add address=107.167.160.0/19 list=YouTube +add address=107.178.192.0/18 list=YouTube +add address=108.59.80.0/20 list=YouTube +add address=108.170.192.0/18 list=YouTube +add address=108.177.0.0/17 list=YouTube +add address=130.211.0.0/16 list=YouTube +add address=136.22.160.0/20 list=YouTube +add address=136.22.176.0/21 list=YouTube +add address=136.22.184.0/23 list=YouTube +add address=136.22.186.0/24 list=YouTube +add address=142.250.0.0/15 list=YouTube +add address=146.148.0.0/17 list=YouTube +add address=152.65.208.0/22 list=YouTube +add address=152.65.214.0/23 list=YouTube +add address=152.65.218.0/23 list=YouTube +add address=152.65.222.0/23 list=YouTube +add address=152.65.224.0/19 list=YouTube +add address=162.120.128.0/17 list=YouTube +add address=162.216.148.0/22 list=YouTube +add address=162.222.176.0/21 list=YouTube +add address=172.110.32.0/21 list=YouTube +add address=172.217.0.0/16 list=YouTube +add address=172.253.0.0/16 list=YouTube +add address=173.194.0.0/16 list=YouTube +add address=173.255.112.0/20 list=YouTube +add address=192.158.28.0/22 list=YouTube +add address=192.178.0.0/15 list=YouTube +add address=193.186.4.0/24 list=YouTube +add address=199.36.154.0/23 list=YouTube +add address=199.36.156.0/24 list=YouTube +add address=199.192.112.0/22 list=YouTube +add address=199.223.232.0/21 list=YouTube +add address=207.223.160.0/20 list=YouTube +add address=208.65.152.0/22 list=YouTube +add address=208.68.108.0/22 list=YouTube +add address=208.81.188.0/22 list=YouTube +add address=208.117.224.0/19 list=YouTube +add address=209.85.128.0/17 list=YouTube +add address=216.58.192.0/19 list=YouTube +add address=216.73.80.0/20 list=YouTube +add address=216.239.32.0/19 list=YouTube +add address=2ip.ru list=Test-IP +add address=wg.vados.ru comment=VDSIna list=TRUSTED +add address=10.8.0.0/24 comment="WG VDSIna" disabled=yes list=TRUSTED +add address=ikus.pesc.ru comment=ikus.pesc.ru list=NoVdsina +add address=love.ru comment=love.ru list=NoVdsina +add address=gosuslugi.ru comment=gosuslugi.ru list=NoVdsina +add address=pochta.ru comment=pochta.ru list=NoVdsina +add address=vdsina.com list=NoVdsina +add address=vdsina.ru list=NoVdsina +add address=youla.ru list=NoVdsina +add address=kupiprodai.ru list=NoVdsina +add address=myip.ru list=Test-IP +add address=geoip.co list=NoVdsina +add address=comp-lenta.ru list=NoVdsina +add address=128.85.102.70 comment=update.microsoft.com list=\ + windowsupdateslist +add address=wu-b-net.trafficmanager.net. comment=\ + ctldl.windowsupdate.com.delivery.microsoft.com list=windowsupdateslist +add address=ctldl.windowsupdate.com.delivery.microsoft.com. comment=\ + ctldl.windowsupdate.com list=windowsupdateslist +add address=redir.update.msft.com.trafficmanager.net. comment=\ + update.microsoft.com list=windowsupdateslist +add address=geo.prod.do.dsp.trafficmanager.net. comment=\ + geo.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=13.74.139.29 comment=array605.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=kv801.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + kv801.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=e12437.d.akamaiedge.net. comment=\ + kv801.prod.do.dsp.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=displaycatalog-rp.md.mp.microsoft.com.akadns.net. comment=\ + displaycatalog.mp.microsoft.com list=windowsupdateslist +add address=rp-consumer-prod-displaycatalog-geomap.trafficmanager.net. \ + comment=displaycatalog-rp.md.mp.microsoft.com.akadns.net list=\ + windowsupdateslist +add address=sls.update.microsoft.com. comment=slscr.update.microsoft.com \ + list=windowsupdateslist +add address=glb.sls.prod.dcat.dsp.trafficmanager.net. comment=\ + sls.update.microsoft.com list=windowsupdateslist +add address=fe3.delivery.mp.microsoft.com. comment=\ + fe3cr.delivery.mp.microsoft.com list=windowsupdateslist +add address=glb.cws.prod.dcat.dsp.trafficmanager.net. comment=\ + fe3.delivery.mp.microsoft.com list=windowsupdateslist +add address=fe2cr.update.msft.com.trafficmanager.net. comment=\ + fe2cr.update.microsoft.com list=windowsupdateslist +add address=download.windowsupdate.com.delivery.microsoft.com. comment=\ + download.windowsupdate.com list=windowsupdateslist +add address=wu-f-net.trafficmanager.net. comment=\ + download.windowsupdate.com.delivery.microsoft.com list=windowsupdateslist +add address=tsfe.trafficmanager.net. comment=\ + tsfe.trafficshaping.dsp.mp.microsoft.com list=windowsupdateslist +add address=edge.ds-c7110-microsoft.global.dns.qwilted-cds.cqloud.com. \ + comment=9.au.download.windowsupdate.com list=windowsupdateslist +add address=52.158.227.125 comment=array812.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=au.download.windowsupdate.com.delivery.microsoft.com. comment=\ + au.download.windowsupdate.com list=windowsupdateslist +add address=a767.dspw65.akamai.net. comment=\ + download.windowsupdate.com.edgesuite.net list=windowsupdateslist +add address=52.151.58.88 comment=array810.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=consumer-licensing-aks2aks.md.mp.microsoft.com.akadns.net. \ + comment=licensing.mp.microsoft.com list=windowsupdateslist +add address=licensing-prod-frontdoor-geomap.trafficmanager.net. comment=\ + consumer-licensing-aks2aks.md.mp.microsoft.com.akadns.net list=\ + windowsupdateslist +add address=star.f.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedge.f.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=cdp-f-nlu-net.trafficmanager.net. comment=\ + star.f.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=star.b.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedge.b.tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=cdp-f-tlu-net.trafficmanager.net. comment=\ + star.b.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=storeedgefd.xbetservices.akadns.net. comment=\ + storeedgefd.dsx.mp.microsoft.com list=windowsupdateslist +add address=\ + storeedgefd.dsx.mp.microsoft.com.edgekey.net.globalredir.akadns.net. \ + comment=storeedgefd.dsx.mp.microsoft.com.edgekey.net list=\ + windowsupdateslist +add address=e16646.dscg.akamaiedge.net. comment=\ + storeedgefd.dsx.mp.microsoft.com.edgekey.net.globalredir.akadns.net list=\ + windowsupdateslist +add address=40.69.76.189 comment=array621.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=bg.microsoft.map.fastly.net. comment=\ + 3.au.download.windowsupdate.com list=windowsupdateslist +add list=windowsupdateslist +add address=40.69.75.33 comment=array613.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=star.sf.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedgeextensions.sf.tlu.dl.delivery.mp.microsoft.com list=\ + windowsupdateslist +add address=cdp-f-ssl-tlu-net.trafficmanager.net. comment=\ + star.sf.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=a2033.dscd.akamai.net. comment=\ + star.sb.tlu.dl.delivery.mp.microsoft.com.edgesuite.net list=\ + windowsupdateslist +add address=13.74.138.242 comment=array602.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=dl.delivery.mp.microsoft.com.delivery.microsoft.com. comment=\ + dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=dcat-f-nlu-net.trafficmanager.net. comment=\ + dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=1d.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=1D.tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=dcat-b-tlu-net.trafficmanager.net. comment=\ + 1d.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=a122.dscg3.akamai.net. comment=\ + tlu.dl.delivery.mp.microsoft.com.edgesuite.net list=windowsupdateslist +add address=geover.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + geover.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=e10370.d.akamaiedge.net. comment=\ + geover.prod.do.dsp.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=52.232.182.21 comment=array511.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.70.77.95 comment=array519.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=a1683.dscd.akamai.net. comment=\ + dl.delivery.mp.microsoft.com-c.edgesuite.net list=windowsupdateslist +add address=consumer-collections-aks2eap.md.mp.microsoft.com.akadns.net. \ + comment=collections.mp.microsoft.com list=windowsupdateslist +add address=a1847.dscd.akamai.net. comment=\ + wildcard.f.tlu.dl.delivery.mp.microsoft.com.edgesuite.net list=\ + windowsupdateslist +add address=13.74.142.6 comment=array607.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=au.download.windowsupdate.com.edgesuite.net. comment=\ + 2.au.download.windowsupdate.com list=windowsupdateslist +add address=a767.dscg3.akamai.net. comment=\ + au.download.windowsupdate.com.edgesuite.net list=windowsupdateslist +add address=52.156.123.84 comment=array818.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.69.78.254 comment=array610.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=4.au.download.windowsupdate.com.delivery.microsoft.com. comment=\ + 4.au.download.windowsupdate.com list=windowsupdateslist +add address=cl-glcb907925.gcdn.co. comment=\ + 4.au.download.windowsupdate.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=52.167.167.111 comment=array510.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=40.69.70.43 comment=array623.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=tsfe.trafficshaping.dsp.mp.microsoft.com.delivery.microsoft.com. \ + comment=tsfe.trafficshaping.dsp.mp.microsoft.com list=windowsupdateslist +add address=ts-frontend.trafficmanager.net. comment=\ + tsfe.trafficshaping.dsp.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=40.69.75.248 comment=array616.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.69.74.84 comment=array615.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=sds.trafficmanager.net. comment=software-download.microsoft.com \ + list=windowsupdateslist +add address=40.69.74.80 comment=array611.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.175.242.182 comment=array804.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=dlc-shim.trafficmanager.net. comment=download.microsoft.com list=\ + windowsupdateslist +add address=e12671.dscd.akamaiedge.net. comment=\ + download.microsoft.com.edgekey.net list=windowsupdateslist +add address=20.187.55.34 comment=array808.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.167.231 comment=array513.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=52.167.222.13 comment=array518.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=kv601.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + kv601.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=e12358.d.akamaiedge.net. comment=\ + kv601.prod.do.dsp.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. comment=\ + tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=dcat-f-tlu-net.trafficmanager.net. comment=\ + tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=a1856.dspw65.akamai.net. comment=\ + tlu.dl.delivery.mp.microsoft.com-c.edgesuite.net list=windowsupdateslist +add address=52.167.164.252 comment=array506.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=13.74.137.54 comment=array601.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=kv501.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + kv501.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=collections-prod-frontdoor-geomap.trafficmanager.net. comment=\ + consumer-collections-aks2eap.md.mp.microsoft.com.akadns.net list=\ + windowsupdateslist +add address=52.167.160.173 comment=array509.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=40.70.77.148 comment=array516.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.200.126 comment=array507.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=52.167.167.59 comment=array508.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.69.76.172 comment=array620.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=smtp.mail.me.com comment=smtp.mail.me.com list=NoVdsina +add address=40.70.76.5 comment=array514.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.186.119 comment=array618.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.177.176.186 comment=array520.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=40.70.76.27 comment=array515.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.160.43 comment=array503.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.110 comment=array817.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.142.8 comment=array614.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.138.254 comment=array603.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.167.96 comment=array501.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.69.76.215 comment=array622.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.143.200 comment=array606.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.111 comment=array818.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.112 comment=array819.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.137.53 comment=array608.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.98 comment=array805.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.96 comment=array803.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.104 comment=array811.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.101 comment=array808.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.99 comment=array806.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.17 comment=array802.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.97 comment=array804.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.103 comment=array810.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.16 comment=array801.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.70.77.177 comment=array517.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.164.84 comment=array512.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.105 comment=array812.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.107 comment=array814.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.232.161.82 comment=array502.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.108 comment=array815.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.161.91 comment=array505.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.102 comment=array809.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.109 comment=array816.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.106 comment=array813.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.117 comment=array622.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.107 comment=array612.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.108 comment=array613.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.105 comment=array610.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.113 comment=array618.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.116 comment=array621.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.98 comment=array603.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.114 comment=array619.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.111 comment=array616.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.97 comment=array602.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.106 comment=array611.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.110 comment=array615.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.119 comment=array624.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.135 comment=array514.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.97 comment=array503.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.99 comment=array604.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.61 comment=array504.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.131 comment=array510.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.132 comment=array511.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.96 comment=array601.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.104 comment=array609.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.138 comment=array517.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.60 comment=array501.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.139 comment=array518.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.118 comment=array623.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.113 comment=array820.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.103 comment=array608.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.100 comment=array807.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.129 comment=array508.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.134 comment=array513.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.62 comment=array505.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.137 comment=array516.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.101 comment=array606.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.96 comment=array502.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.130 comment=array509.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.112 comment=array617.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.100 comment=array605.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.115 comment=array620.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.136 comment=array515.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=purchase.md.mp.microsoft.com.akadns.net. comment=\ + purchase.mp.microsoft.com list=windowsupdateslist +add address=e110219.a.akamaiedge.net. comment=\ + purchase.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=72.153.5.140 comment=array519.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.141 list=windowsupdateslist +add address=72.153.5.63 comment=array506.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.128 comment=array507.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.102 comment=array607.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=storesdk.xbetservices.akadns.net. comment=\ + storesdk.dsx.mp.microsoft.com list=windowsupdateslist +add address=e16646.g.akamaiedge.net. comment=\ + storesdk.dsx.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=software-download.microsoft.com.delivery.microsoft.com. comment=\ + software-download.microsoft.com list=windowsupdateslist +add address=download.prss.microsoft.com.akamaized.net. comment=\ + software-download.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.109 comment=array614.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.133 comment=array512.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=213.180.192.0/19 comment=YandexDisk list=NoVdsina +add address=87.250.250.50 comment=YandexDisk list=NoVdsina +add address=consumer-prod-bcfd-v7-afd.trafficmanager.net. comment=\ + displaycatalog.mp.microsoft.com list=windowsupdateslist +add address=purchase-europeeap.md.mp.microsoft.com.akadns.net. comment=\ + purchase.md.mp.microsoft.com.akadns.net list=windowsupdateslist +add address=ne-az-conspurchase-mp.trafficmanager.net. comment=\ + purchase-europeeap.md.mp.microsoft.com.akadns.net list=windowsupdateslist +add address=storeedgefd.dsx.mp.microsoft.com.edgekey.net. comment=\ + cdn.storeedgefd.dsx.mp.microsoft.com list=windowsupdateslist +add address=star.f.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedge.f.tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=a1996.dscd.akamai.net. comment=\ + wildcard.f.dl.delivery.mp.microsoft.com.edgesuite.net list=\ + windowsupdateslist +add address=cp801.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + cp801.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=glb.tas02.sls-prod.dcat.dsp.mp.microsoft.com. comment=\ + tas02.sls.update.microsoft.com list=windowsupdateslist +add address=cp601.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + cp601.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=star.sb.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedgeextensions.sb.tlu.dl.delivery.mp.microsoft.com list=\ + windowsupdateslist +add address=star.sf.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedge.sf.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=cdp-f-ssl-nlu-net.trafficmanager.net. comment=\ + star.sf.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=tm-pifd-prod-gbl-weight.trafficmanager.net. comment=\ + paymentinstruments.mp.microsoft.com list=windowsupdateslist +add address=10.30.30.33 comment=amster list=NoWG +add address=10.30.30.10 comment=MikroNUC disabled=yes list=NoWG +add address=89.110.101.17 comment=!!!VDSINA!!!! disabled=yes list=NoWG +add address=wg.vados.ru comment=VDSina-vpn list=VDSina +add address=80.85.244.9 list=TRUSTED +add address=disc801.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + disc801.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=185.71.70.78 disabled=yes list=TRUSTED +add address=176.53.203.171 disabled=yes list=TRUSTED +add address=176.53.203.170 disabled=yes list=TRUSTED +add address=176.53.202.194 disabled=yes list=TRUSTED +add address=89.110.101.17 comment="!!!VDSina Server!!!" list=NoVdsina +add address=dns.quad9.net comment=Quad9-dns disabled=yes list=Trusted-DNS +add address=dns.google comment=Google-dns list=Trusted-DNS +add address=security.cloudflare-dns.com comment=CloudFlare-dns list=\ + Trusted-DNS +add address=time.google.com comment=Google-time list=Trusted-NTP +add address=0.ru.pool.ntp.org comment=ru.pool.ntp.org disabled=yes list=\ + Trusted-NTP +add address=1.ru.pool.ntp.org disabled=yes list=Trusted-NTP +add address=2.ru.pool.ntp.org comment=2.ru.pool.ntp.org disabled=yes list=\ + Trusted-NTP +add address=3.ru.pool.ntp.org comment=3.ru.pool.ntp.org disabled=yes list=\ + Trusted-NTP +add address=cp.vdsina.com comment=VDSina-vpn list=VDSina +add address=vdsina.ru comment=VDSina-vpn list=VDSina +add address=ns.vados.ru comment=VDSina-vpn list=VDSina +add address=vdsina.com comment=VDSina-vpn list=VDSina +add address=cp.vdsina.ru comment=VDSina-vpn list=VDSina +add address=ns1.vdsina.ru comment=VDSina-vpn list=VDSina +add address=10.30.30.0/24 comment="Local Network" list=Local-Net +add address=10.8.0.0/24 comment="WireGuard Network" list=Local-Net +add address=146.120.64.208/29 comment="External Net" list=Unet +add address=esia.gosuslugi.ru comment=esia.gosuslugi.ru list=NoVdsina +add address=lk.gosuslugi.ru comment=lk.gosuslugi.ru list=NoVdsina +add address=trudvsem.ru comment=trudvsem.ru list=NoVdsina +add address=10.30.30.30 comment=miller disabled=yes list=NoWG +add address=10.30.30.33 comment="Direct connet to DNS servers" list=\ + Direct-DNS +add address=109.107.177.79 list=VPN-Server +add address=10.30.30.10 list=AWG-Proxy +add address=10.0.0.0/8 list=RFC1918 +add address=172.16.0.0/12 list=RFC1918 +add address=192.168.0.0/16 list=RFC1918 +add address=8.8.4.4 list=to_vpn +/ip firewall filter +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=12h chain=input comment="block honeypot DNS" \ + connection-state=new dst-port=53 in-interface="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 dst-port=29185 in-interface="ether1 - Unet" \ + protocol=tcp +add action=accept chain=input dst-port=29185 in-interface="ether1 - Unet" \ + protocol=udp +add action=accept chain=input comment="tcp Accept input DNS queries from LAN" \ + dst-port=53 protocol=tcp src-address=10.30.30.0/24 +add action=accept chain=input comment="udp Accept input DNS queries" \ + dst-port=53 protocol=udp src-address=10.30.30.0/24 +add action=accept chain=output comment="accept WireGuard" disabled=yes \ + dst-address-list=VPN-Server out-interface="ether1 - Unet" protocol=udp \ + src-port=13231 +add action=accept chain=output disabled=yes dst-address-list=VPN-Server \ + dst-port=29185 out-interface="ether1 - Unet" protocol=udp +add action=fasttrack-connection chain=forward comment="defconf: fasttrack" \ + connection-state=established,related,new disabled=yes routing-mark=\ + !To-VPN +add action=accept chain=output disabled=yes protocol=tcp src-port=443 +add action=accept chain=output disabled=yes src-address=127.0.0.1 +add action=accept chain=forward comment="defconf: accept in ipsec policy" \ + disabled=yes ipsec-policy=in,ipsec +add action=accept chain=forward comment="defconf: accept out ipsec policy" \ + disabled=yes ipsec-policy=out,ipsec +add action=accept chain=forward comment=\ + "defconf: accept established,related, untracked" connection-state=\ + established,related,untracked +add action=drop chain=forward comment="defconf: drop invalid" \ + connection-state=invalid in-interface="ether1 - Unet" src-address=\ + !10.30.30.0/24 +add action=drop chain=forward comment=\ + "defconf: drop all from WAN not DSTNATed" connection-nat-state=!dstnat \ + connection-state=new in-interface="ether1 - Unet" src-address-list=\ + !VDSina +add action=accept chain=input in-interface="ether1 - Unet" protocol=icmp \ + src-address-list=VDSina +add action=accept chain=input connection-state=established +add action=accept chain=input connection-state=related +/ip firewall mangle +add action=accept chain=prerouting comment=RFC1918 dst-address-list=RFC1918 \ + in-interface-list=!WAN +add action=mark-connection chain=prerouting comment=\ + "Transit for address-list \"to_vpn\"" connection-mark=no-mark \ + dst-address-list=to_vpn in-interface-list=!WAN new-connection-mark=\ + to-vpn-conn +add action=mark-routing chain=prerouting comment=\ + "Find routing over table r_to_vpn" connection-mark=to-vpn-conn \ + in-interface-list=!WAN new-routing-mark=r_to_vpn +add action=mark-connection chain=output comment="For this router" \ + connection-mark=no-mark dst-address-list=to_vpn new-connection-mark=\ + to-vpn-conn-local +add action=mark-routing chain=output comment="For this router" \ + connection-mark=to-vpn-conn-local new-routing-mark=r_to_vpn +add action=mark-routing chain=prerouting comment="Mark Routing main for NoWG" \ + disabled=yes new-routing-mark=main src-address-list=NoWG +add action=mark-routing chain=prerouting comment=\ + "Mark Routing main for NoVdsina" disabled=yes dst-address-list=NoVdsina \ + new-routing-mark=main src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=\ + "Mark Routing main for VDSina" disabled=yes dst-address-list=VPN-Server \ + new-routing-mark=main src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=\ + "Mark Routing main for MikroNuc" disabled=yes dst-address-list=AWG-Proxy \ + new-routing-mark=main src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=\ + "!!!ERROR Mark Routing main for Unet!!!" disabled=yes dst-address-list=\ + Unet new-routing-mark=main passthrough=no +add action=mark-routing chain=prerouting comment="Test-IP sites" disabled=yes \ + dst-address=!10.30.30.0/24 dst-address-list=Test-IP new-routing-mark=\ + To-VPN src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=FuckRKN disabled=yes \ + dst-address=!10.30.30.0/24 dst-address-list=RKN-dnsLookup \ + new-routing-mark=To-VPN passthrough=no src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment="VDSIna for All sites" \ + disabled=yes dst-address-list=!NoVdsina new-routing-mark=To-VPN \ + routing-mark=!main src-address=10.30.30.0/24 src-address-list=!NoWG +add action=change-mss chain=forward comment="MSS on WG" disabled=yes new-mss=\ + 1380 out-interface=WG protocol=tcp routing-mark=To-VPN tcp-flags=syn \ + tcp-mss=1381-65535 +add action=mark-connection chain=prerouting comment=\ + "Mark VPN connections to exclude from FastTrack" disabled=yes \ + new-connection-mark=VPN_No_FastTrack routing-mark=To-VPN +add action=mark-routing chain=prerouting comment="VPN Network" disabled=yes \ + dst-address=10.8.0.0/24 new-routing-mark=To-VPN src-address=10.30.30.0/24 +/ip firewall nat +add action=redirect chain=dstnat comment="udp Redirect DNS in NAT" disabled=\ + yes dst-port=53 protocol=udp src-address=10.30.30.0/24 src-address-list=\ + !NoWG to-addresses=10.30.30.33 to-ports=53 +add action=redirect chain=dstnat comment="tcp Redirect DNS in NAT" disabled=\ + yes dst-port=53 protocol=tcp src-address=10.30.30.0/24 src-address-list=\ + !NoWG to-addresses=10.30.30.33 to-ports=53 +add action=dst-nat chain=dstnat comment=\ + "53/tcp dst-nat to amster.loc. From VDSina Server" dst-port=53 \ + in-interface="ether1 - Unet" protocol=tcp src-address-list=VPN-Server \ + to-addresses=10.30.30.33 to-ports=53 +add action=dst-nat chain=dstnat comment=\ + "53/udp dst-nat to amster.loc. From VDSina Server" dst-port=53 protocol=\ + udp src-address-list=VPN-Server to-addresses=10.30.30.33 to-ports=53 +add action=dst-nat chain=dstnat disabled=yes dst-port=44333 in-interface=\ + "ether1 - Unet" protocol=udp src-address=!10.30.30.0/24 to-addresses=\ + 10.30.30.33 to-ports=44333 +add action=masquerade chain=srcnat comment="Default NAT" out-interface=\ + "ether1 - Unet" routing-mark=!To-VPN src-address=10.30.30.0/24 +add action=dst-nat chain=dstnat dst-port=44044 in-interface="ether1 - Unet" \ + protocol=udp src-address=109.107.177.79 to-addresses=10.30.30.33 \ + to-ports=44044 +add action=dst-nat chain=dstnat comment=amster.vados.ruhttps dst-port=443 \ + fragment=no in-interface="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=masquerade chain=srcnat comment=\ + "Nat Addresses for routing mark r_to_vpn" routing-mark=r_to_vpn +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 disabled=yes dst-address-list=\ + !NoVdsina out-interface=WG routing-mark=To-VPN src-address-list=!NoWG +add action=dst-nat chain=dstnat comment="Yandex.DNS Family" disabled=yes \ + dst-port=53 in-interface=Bridge-LAN protocol=udp src-address-list=KIDS \ + time=6h-15m,sun,mon,tue,wed,thu,fri,sat to-addresses=77.88.8.3 +add action=dst-nat chain=dstnat disabled=yes dst-port=53 in-interface=\ + Bridge-LAN protocol=tcp src-address-list=KIDS time=\ + 6h-15m,sun,mon,tue,wed,thu,fri,sat to-addresses=77.88.8.3 +/ip firewall raw +add action=drop chain=prerouting comment="Drop Honeypot Hackers" \ + in-interface="ether1 - Unet" src-address-list="Honeypot Hacker" +add action=accept chain=prerouting comment="Trusted DNS" disabled=yes \ + in-interface-list=WAN src-address-list=Trusted-DNS +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + extras.getpagespeed.com content=extras.getpagespeed.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=linux.duke.edu \ + content=linux.duke.edu disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=youtube.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + googleapis.com disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=ggpht.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=youtu.be \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=ytimg.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + googlevideo.com disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=gstatic.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + googleusercontent.com disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + nhacmp3youtube.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=rutube.ru \ + content=rutube.ru disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment="me.com raw" \ + content=me.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "icloud.com raw" content=icloud.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "smtp.mail.me.com raw" content=smtp.mail.me.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "smtp.mail.me.com.akadns.net raw" content=smtp.mail.me.com.akadns.net \ + disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "api.db-ip.com raw" content=api.db-ip.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + esia.gosuslugi.ru content=esia.gosuslugi.ru disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=gosuslugi.ru \ + content=gosuslugi.ru disabled=yes +/ip firewall service-port +set ftp disabled=yes +set tftp disabled=yes +set irc disabled=no +set sip disabled=yes +set pptp disabled=yes +set rtsp disabled=no +/ip ipsec settings +set accounting=no +/ip ipsec policy +set 0 disabled=yes dst-address=0.0.0.0/0 src-address=0.0.0.0/0 +/ip ipsec profile +set [ find default=yes ] dpd-interval=2m dpd-maximum-failures=5 +/ip proxy +set cache-administrator="" max-cache-size=none port=80,443 src-address=\ + 0.0.0.0 +/ip route +add check-gateway=none disabled=yes distance=1 dst-address=0.0.0.0/0 gateway=\ + WG routing-table=To-VPN scope=30 target-scope=10 +add disabled=yes distance=1 dst-address=0.0.0.0/0 gateway=10.30.30.33 \ + routing-table=r_to_vpn scope=30 target-scope=10 +add comment=VDSina-dns distance=1 dst-address=8.8.4.4/32 gateway=wg-VDSina +/ip service +set ftp disabled=yes +set telnet disabled=yes +set reverse-proxy disabled=yes +set ssh address=10.30.30.0/24 port=2222 +set winbox address=10.30.30.0/24 +set api address=10.30.30.0/24 +set api-ssl address=10.30.30.0/24 disabled=yes +set www-ssl certificate=Root-YE port=18443 +set www address=10.30.30.0/24 disabled=yes port=18880 +/ip service webserver +set acme-plain=no crl-plain=no graphs-plain=no graphs-secure=no index-plain=\ + no index-secure=no rest-secure=no scep-plain=no webfig-plain=no \ + webfig-secure=no +/ip ssh +set forwarding-enabled=both publickey-authentication-options=verify-required +/ip upnp +set enabled=yes +/ip upnp interfaces +add interface=Bridge-LAN type=internal +add forced-ip=146.120.64.211 interface="ether1 - Unet" type=external +add forced-ip=109.107.177.79 interface=*E type=external +add interface=lo type=internal +add interface=wlan2 type=internal +add interface=wlan1 type=internal +/ipv6 dhcp-client +add add-default-route=yes disabled=yes interface=*F rapid-commit=no request=\ + info use-interface-duid=yes validate-server-duid=no +/ipv6 dhcp-server option sets +add name=domain-search-set options=domain-search-list +add name="=\"Client ID\"" options=HostName +/ipv6 firewall address-list +add address=::/128 comment="defconf: unspecified address" list=bad_ipv6 +add address=::1/128 comment="defconf: lo" list=bad_ipv6 +add address=fec0::/10 comment="defconf: site-local" list=bad_ipv6 +add address=::ffff:0.0.0.0/96 comment="defconf: ipv4-mapped" list=bad_ipv6 +add address=::/96 comment="defconf: ipv4 compat" list=bad_ipv6 +add address=100::/64 comment="defconf: discard only " list=bad_ipv6 +add address=2001:db8::/32 comment="defconf: documentation" list=bad_ipv6 +add address=2001:10::/28 comment="defconf: ORCHID" list=bad_ipv6 +add address=3ffe::/16 comment="defconf: 6bone" list=bad_ipv6 +/ipv6 firewall filter +add action=accept chain=input comment=\ + "defconf: accept established,related,untracked" connection-state=\ + established,related,untracked +add action=drop chain=input comment="defconf: drop invalid" connection-state=\ + invalid +add action=accept chain=input comment="defconf: accept ICMPv6" protocol=\ + icmpv6 +add action=accept chain=input comment="defconf: accept UDP traceroute" \ + dst-port=33434-33534 protocol=udp +add action=accept chain=input comment=\ + "defconf: accept DHCPv6-Client prefix delegation." dst-port=546 protocol=\ + udp src-address=fe80::/10 +add action=accept chain=input comment="defconf: accept IKE" dst-port=500,4500 \ + protocol=udp +add action=accept chain=input comment="defconf: accept ipsec AH" protocol=\ + ipsec-ah +add action=accept chain=input comment="defconf: accept ipsec ESP" protocol=\ + ipsec-esp +add action=accept chain=input comment=\ + "defconf: accept all that matches ipsec policy" ipsec-policy=in,ipsec +add action=drop chain=input comment=\ + "defconf: drop everything else not coming from LAN" in-interface-list=\ + !LAN +add action=accept chain=forward comment=\ + "defconf: accept established,related,untracked" connection-state=\ + established,related,untracked +add action=drop chain=forward comment="defconf: drop invalid" \ + connection-state=invalid +add action=drop chain=forward comment=\ + "defconf: drop packets with bad src ipv6" src-address-list=bad_ipv6 +add action=drop chain=forward comment=\ + "defconf: drop packets with bad dst ipv6" dst-address-list=bad_ipv6 +add action=drop chain=forward comment="defconf: rfc4890 drop hop-limit=1" \ + hop-limit=equal:1 protocol=icmpv6 +add action=accept chain=forward comment="defconf: accept ICMPv6" protocol=\ + icmpv6 +add action=accept chain=forward comment="defconf: accept HIP" protocol=139 +add action=accept chain=forward comment="defconf: accept IKE" dst-port=\ + 500,4500 protocol=udp +add action=accept chain=forward comment="defconf: accept ipsec AH" protocol=\ + ipsec-ah +add action=accept chain=forward comment="defconf: accept ipsec ESP" protocol=\ + ipsec-esp +add action=accept chain=forward comment=\ + "defconf: accept all that matches ipsec policy" ipsec-policy=in,ipsec +add action=drop chain=forward comment=\ + "defconf: drop everything else not coming from LAN" in-interface-list=\ + !LAN +/ipv6 nd +set [ find default=yes ] advertise-dns=yes disabled=yes interface=Bridge-LAN \ + managed-address-configuration=yes other-configuration=yes pref64=::/64 +/ipv6 nd prefix +add autonomous=no disabled=yes interface=Bridge-LAN on-link=no prefix=none +/ipv6 nd prefix default +set dhcp6-pd-preferred=yes +/ipv6 nd proxy +add disabled=yes interface=lo +/ipv6 nd settings +set router-advertisement-route-distance=100 +/routing settings +set single-process=no +/system clock +set time-zone-name=Europe/Moscow +/system clock manual +set time-zone=+03:00 +/system identity +set name=MikroMaster +/system logging +add action=email disabled=yes regex="* added|changed|removed *" topics=\ + system,info +/system ntp client +set enabled=yes +/system ntp server +set enabled=yes manycast=yes multicast=yes use-local-clock=yes +/system ntp client servers +add address=0.ru.pool.ntp.org +add address=1.ru.pool.ntp.org +add address=2.ru.pool.ntp.org +add address=3.ru.pool.ntp.org +add address=time.google.com disabled=yes +/system package update +set check-certificate=yes-without-crl ip-version=ipv4 +/system scheduler +add comment="Every Day Set Global Environment Variables" name=AM-SetGlobalEnv \ + on-event="/system/script { run AM-GlobalConfig; run AM-GlobalFunc; }" \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-time=startup +add comment="Every Day Check For Update Scripts" interval=1d name=\ + AM-ScriptInstallUpdate on-event=\ + ":global ScriptInstallUpdate; \$ScriptInstallUpdate;" policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-time=startup +add comment="Update RKN DNS Looup" disabled=yes interval=20m name=\ + AM-RKN-dnsLookup on-event="/system/script { run AM-RKN-dnsLookup; }" \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-time=startup +/system watchdog +set watchdog-timer=no +/tool e-mail +set certificate-verification=no from=MikroVados port=587 \ + server=smtp.mail.me.com tls=starttls user=vadossio@icloud.com +/tool mac-server +set allowed-interface-list=LAN +/tool mac-server mac-winbox +set allowed-interface-list=LAN +/tool netwatch +add certificate=DigiCert-Global-Root-CA check-certificate=no comment="doh, doh\ + -url=https://security.cloudflare-dns.com/dns-query, notify, name=CloudFlar\ + e-doh IPv4 1" disabled=yes down-script="" host=1.1.1.1 http-codes="" \ + interval=10s name="CloudFlare-doh IPv4 1" port=443 test-script="" type=\ + https-get up-script="" +add check-certificate=no comment="doh-fallback, doh-url=https://security.cloud\ + flare-dns.com/dns-query, doh-cert=DigiCert Global Root CA, notify, name=Cl\ + oudFlare-doh IPv4" disabled=yes down-script="" host=1.0.0.1 http-codes="" \ + name="CloudFlare-doh IPv4" port=443 test-script="" type=https-get \ + up-script="" +add comment="dns, notify, name=Google-DNS IPv4" disabled=yes dns-server=\ + 8.8.8.8 down-script="" host=dns.google http-codes="" name=\ + "Google-DNS IPv4" test-script="" type=dns up-script="" +add certificate=GTS-Root-R4 check-certificate=yes comment="doh-fallback, doh-u\ + rl=https://dns.google/dns-query, doh-cert=GTS Root R1, notify, name=Google\ + -DOH IPv4" disabled=yes dns-server=8.8.4.4 down-script="" host=dns.google \ + http-codes="" name="Google-DOH IPv4" port=443 record-type=NS src-address=\ + "" test-script="" type=dns up-script="" +add comment="dns-fallback, notify, name=Cuad9-DOH IPv4" disabled=yes \ + dns-server=9.9.9.9 down-script="" host=dns9.quad9.net http-codes="" \ + interval=10s name="Cuad9-DOH IPv4" src-address=146.120.64.211 \ + test-script="" timeout=800ms type=dns up-script="" +add certificate=DigiCert-Assured-ID-Root-CA comment="doh-fallback, doh-url=htt\ + ps://dns.quad9.net/dns-query, name=Cuad9-DOH IPv4" disabled=yes \ + down-script="" host=149.112.112.112 http-codes="" interval=10s name=\ + "Cuad9-DOH IPv4" port=443 test-script="" type=https-get up-script="" +add comment="dns-fallback, notify, name=ns1.unet.ws" disabled=yes \ + down-script="" host=91.192.189.2 http-codes="" interval=10s name=\ + ns1.unet.ws test-script="" type=simple up-script="" +add check-certificate=yes comment=\ + "doh, doh-url=https://vds.vados.ru/vds-query, name=vds.vados.ru" \ + disabled=yes down-script="" host=109.107.177.79 http-codes="" name=\ + vds.vados.ru port=443 test-script="" type=https-get up-script="" +/user aaa +set accounting=no -- 2.52.0