From 7790d915c88cfbdf5be59a1b56329d4aa1cf7200 Mon Sep 17 00:00:00 2001 From: vados-dev Date: Sat, 20 Jun 2026 00:40:03 +0300 Subject: [PATCH] Backup for MikroNUC created successfully at Jun 20 00:40:03. --- .../20260619/20260619150002-Config.rsc | 3679 +++++++++++++ .../20260619/20260619162002-Config.rsc | 3679 +++++++++++++ .../20260619/20260619222002-Config.rsc | 3679 +++++++++++++ .../20260620/20260620004001-Binary.backup | Bin 0 -> 363887 bytes MikroNUC/20260620/20260620004001-Config.rsc | 4880 +++++++++++++++++ .../20260620/20260620004001-Diff-Config.rsc | 3 + 6 files changed, 15920 insertions(+) create mode 100644 MikroMaster/20260619/20260619150002-Config.rsc create mode 100644 MikroMaster/20260619/20260619162002-Config.rsc create mode 100644 MikroMaster/20260619/20260619222002-Config.rsc create mode 100644 MikroNUC/20260620/20260620004001-Binary.backup create mode 100644 MikroNUC/20260620/20260620004001-Config.rsc create mode 100644 MikroNUC/history/20260620/20260620004001-Diff-Config.rsc diff --git a/MikroMaster/20260619/20260619150002-Config.rsc b/MikroMaster/20260619/20260619150002-Config.rsc new file mode 100644 index 0000000..0ec9fe5 --- /dev/null +++ b/MikroMaster/20260619/20260619150002-Config.rsc @@ -0,0 +1,3679 @@ +# 2026-06-19 15:00:04 by RouterOS 7.23.1 +# software id = A8L5-07YF +# +# model = RB952Ui-5ac2nD +# serial number = D3D50CEDCD38 +/interface bridge +add admin-mac=48:8F:5A:8E:1A:BF auto-mac=no dhcpv6-agent-circuit-id=\ + "\$(INTERFACE):\$(VID)" dhcpv6-agent-remote-id="\$(BRIDGEMAC)" name=\ + Bridge-LAN port-cost-mode=short +/interface ethernet +set [ find default-name=ether1 ] comment="WAN - Unet" loop-protect=off name=\ + "ether1 - Unet" rx-flow-control=auto tx-flow-control=auto +set [ find default-name=ether2 ] comment=LAN-2 +set [ find default-name=ether3 ] advertise="10M-baseT-half,10M-baseT-full,100M\ + -baseT-half,100M-baseT-full,1G-baseT-full,1G-baseX" comment=LAN-3 +set [ find default-name=ether4 ] comment=LAN-4 +set [ find default-name=ether5 ] advertise="10M-baseT-half,10M-baseT-full,100M\ + -baseT-half,100M-baseT-full,1G-baseT-full,1G-baseX" comment=LAN-5 \ + loop-protect=on poe-out=off rx-flow-control=auto tx-flow-control=auto +/interface wireless +# managed by CAPsMAN +# channel: 2442/20-Ce/gn(18dBm), SSID: vados, local forwarding +set [ find default-name=wlan1 ] country=belarus disabled=no mode=ap-bridge \ + ssid=vados wireless-protocol=802.11 +# managed by CAPsMAN +# channel: 5200/20-eCee/ac/P(21dBm), SSID: vados5g, local forwarding +set [ find default-name=wlan2 ] country=belarus disabled=no mode=ap-bridge \ + ssid=vados5g wireless-protocol=802.11 +/interface wireguard +add comment=WG disabled=yes listen-port=13231 mtu=1320 name=WG +/interface list +add include=static name=LAN +add name=Internet +add include=Internet name=WAN +/interface wireless security-profiles +set [ find default=yes ] authentication-types=wpa-psk,wpa2-psk mode=\ + dynamic-keys supplicant-identity=MikroTik +/ip dhcp-server option +add code=12 name=HostName +add code=119 force=yes name=domain-search-list value="0x03'WORKGROUP'0x00" +/ip dhcp-server option sets +add name=HP1505n options=HostName +add name=StartLife1 options=HostName +add name=amsterDev options=HostName +add name=MiTV options=HostName +add name=miller options=HostName +add name=amster options=HostName +add name=garage options=HostName +add name=domain-search-set options=domain-search-list +add name=VADOS-LEN options=HostName +add name=VADOS-NUC options=HostName +add name=MikroNUC options=HostName +add name=master options=HostName +add name=MikroYellow options=HostName +add name="=\"Client ID\"" options=HostName +add name=iVados options=HostName +/ip dns forwarders +add dns-servers=1.1.1.1,1.0.0.1 name=blsp.at verify-doh-cert=no +add comment=Kra dns-servers=1.0.0.1,1.1.1.1 name=slon2.to verify-doh-cert=no +add dns-servers=1.1.1.1,1.0.0.1 name=slon3.at verify-doh-cert=no +add dns-servers=1.0.0.1,1.1.1.1 name=slon3.cc verify-doh-cert=no +add dns-servers=1.1.1.1,1.0.0.1 name=bs2web.at verify-doh-cert=no +add dns-servers=1.1.1.1,1.0.0.1 name=bs2best.at verify-doh-cert=no +add dns-servers=1.0.0.1,1.1.1.1 name=psrms.is verify-doh-cert=no +/ip ipsec proposal +set [ find default=yes ] disabled=yes +/ip pool +add name=dhcp ranges=10.30.30.83-10.30.30.254 +/ip dhcp-server +add add-arp=yes address-pool=dhcp always-broadcast=yes bootp-support=none \ + dhcp-option-set=domain-search-set interface=Bridge-LAN lease-time=10m \ + name=masterDHCP server-address=10.30.30.81 +/ip smb users +set [ find default=yes ] disabled=yes +add disabled=yes name=vados +/ipv6 dhcp-client option +add code=119 name=domain-search-list value="0x03'WORKGROUP'0x00" +add code=12 name=HostName value="\$(HOSTNAME)" +add code=61 name=DUID value=0x00030001488f5a8e1abc +add code=61 name=clientid +/ipv6 dhcp-server option +add code=119 name=domain-search-list value="0x03'WORKGROUP'0x00" +add code=12 name=HostName value="\$(HOSTNAME)" +add code=61 name=CLIENT_DUID +add code=61 name=CLIENT_MAC +/ppp profile +set *FFFFFFFE use-upnp=no +/routing bgp template +set default disabled=no output.network=bgp-networks +/routing table +add disabled=no fib name=To-VPN +/system logging action +add email-start-tls=yes email-to=vados@vados.ru name=email target=email +/system script +add dont-require-permissions=no name=fetchCustom owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + global GlobalScriptsUrl \"https://ros.vados.ru/\";\r\ + \n\r\ + \n#/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@1\ + 0.30.30.86.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.86.pub\";\ + \n\r\ + \n#:local Script AM-setup\ + \n;\r\ + \n#/system/script/add name=\$Script owner=\$Script source=([ /tool/fetch c\ + heck-certificate=yes-without-crl url=(\$GlobalScriptsUrl . \$Script . \".r\ + sc\") output=user as-value ]->\"data\");\r\ + \n\ + \n#/usb1/mikro_bak_rsa.pub\ + \n\ + \n\r\ + \n#\ + \n\r\ + \n#/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@1\ + 0.30.30.10.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.10.pub\";\ + \n\r\ + \n#\r\ + \n\ + \n#root.mnuc.backuper\ + \n\ + \n\r\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@10\ + .30.30.81.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.81.pub\";\r\ + \n\ + \n#:local Script AM-GlobalConfig;\ + \n\r\ + \n#/system/script/add name=\$Script owner=\$Script source=([ /tool/fetch c\ + heck-certificate=yes-without-crl url=(\$GlobalScriptsUrl . \$Script . \".r\ + sc\") output=user as-value ]->\"data\");\r\ + \n\ + \n#/usb1/mikro_bak_rsa.pub\ + \n#:local FetchFile AM-DOHCert.rsc\ + \n\ + \n\r\ + \n\r\ + \n#\ + \n:global MkDir;\ + \n\r\ + \n\ + \n#:local FetchFile Binary.backup\ + \n:local localDir \"\";\ + \n\ + \n\r\ + \n#\$MkDir \$localDir;\r\ + \n\ + \n#\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \$FetchFile) dst-path=(\ + \$localDir . \$FetchFile);\r\ + \n" +add comment="Global Config Script" dont-require-permissions=no name=\ + AM-GlobalConfig owner=AM-GlobalConfig policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\r\ + \n# RouterOS script: AM-GlobalConfig\r\ + \n# Script comment: Global Config Script\r\ + \n# Copyright (c) 2007-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# Warning: Dont touch this line!\r\ + \n:global Identity [/system/identity/get name];\r\ + \n:global GlobalConfReady false;\r\ + \n#\r\ + \n#\r\ + \n# Global Url For Amster scripts to fetch\r\ + \n# most be defined in AM-Init-Script or AM-setup scripts\r\ + \n:global GlobalScriptsUrl \"https://ros.vados.ru/\";\r\ + \n:global ScriptsUrlSuffix (a);\r\ + \n:global CheckSumsVerify true;\r\ + \n\r\ + \n:global ScriptUpdatesCRLF true;\r\ + \n:global CommentsInScripts true;\r\ + \n\r\ + \n# Debug output:\r\ + \n:global PrintDebug true; #false;\r\ + \n\r\ + \n# Debug output for specific script:\r\ + \n#:set (\$PrintDebugOverride->\"AM-GlobalFunc\") true;\r\ + \n\r\ + \n# Debug logs\r\ + \n# Other actions (disk, email, remote or support) can be used as well.\r\ + \n# I do not recommend using echo - use debug output instead (https://rsc.\ + eworm.de/main/DEBUG.html#debug-output).\r\ + \n#/system/logging/add topics=script,debug action=memory;\r\ + \n\r\ + \n:global MikrotikUpgradeUrl \"https://upgrade.mikrotik.com/routeros\";\r\ + \n:global Domain \"WORKGROUP\";\r\ + \n\r\ + \n:global EmailGeneralTo \"vados@vados.ru\";\r\ + \n#:global EmailGeneralCc \"\";\r\ + \n\r\ + \n# \$ScriptInstallUpdate mod/notification-telegram\r\ + \n:global TelegramTokenId \"8390868324:AAG3_d1hfVR2M6pGAgDK6ZvhOe4J97nyopw\ + \";\r\ + \n:global TelegramChatId \"-1003631309063\"; #\"454403445\";\r\ + \n# Use this to send notifications to a specific topic in group.\r\ + \n#:global TelegramThreadId \"30\";\r\ + \n# Using telegram-chat you have to define trusted chat ids (not group ids\ + !)\r\ + \n# or user names. Groups allow to chat with devices simultaneously.\r\ + \n:global TelegramChatIdsTrusted {\r\ + \n \"454403445\"\r\ + \n \"-1003631309063\"\r\ + \n \"-5124482807\"\r\ + \n \"1087968824\";\r\ + \n};\r\ + \n# \"-5294757340\";\r\ + \n\r\ + \n:global TelegramChatGroups \"(all)\";\r\ + \n#:global TelegramChatGroups \"(all|home|office)\";\r\ + \n\r\ + \n:global NotificationFunctions {\r\ + \n \"email\"\r\ + \n \"telegram\";\r\ + \n};\r\ + \n# Toggle this to disable symbols in notifications.\r\ + \n:global NotificationsWithSymbols true;\r\ + \n:global TerminalColorOutput true;\r\ + \n\r\ + \n:global DetectIpAddrDefault \"https://ipv4.mikrotik.ovh/\";\r\ + \n:global DetectIpAddrFallback \"https://api.ipify.org/\";\r\ + \n\r\ + \n## Update channel. Possible values: stable, long-term, testing, developm\ + ent\r\ + \n:global updateChannel \"stable\";\r\ + \n\r\ + \n:global CertRenewUrl (\$GlobalScriptsUrl . \"certs/\" . \$Identity . \"/\ + \");\r\ + \n:global CertRenewTime 2w;\r\ + \n:global CertRenewPass (a); #{\r\ + \n# \"\";\r\ + \n# \"v3ry-s3cr3t\";\r\ + \n# \"4n0th3r-s3cr3t\";\r\ + \n#};\r\ + \n:global CertWarnTime 1w;\r\ + \n:global CertIssuedExportPass (a); # {\r\ + \n# \"\";\r\ + \n# \"cert1-cn\"=\"v3ry-s3cr3t\";\r\ + \n# \"cert2-cn\"=\"4n0th3r-s3cr3t\";\r\ + \n#};\r\ + \n\r\ + \n# Script BackupAndUpdate mode, possible values: backup,\r\ + \n# updateOnce - Update once as \"osnotify\" and back \"osnotify\" mode (i\ + n terminal run :set OSUpdateMode updateOnce; \$OSUpdateMode;). \r\ + \n# osupdate - Update if available and creates backups before/after update\ + \_(ignores `forceBackup`)\r\ + \n# Set `forceBackup` to true to always create backups, even\ + \_without updates\r\ + \n# osnotify - Set `forceBackup` to always create backups on every run\r\ + \n:global DevInfoIncludeIP true;\r\ + \n:global BackupAndUpdateMode \"osnotify\"\r\ + \n\r\ + \n:global forceBackup true;\r\ + \n:global BackupPassword \"Peskar55\";\r\ + \n\r\ + \n# SFTP Backup Variables\r\ + \n:global BackupRandomDelay 0;\r\ + \n:global BackupUploadUrl \"sftp://amster.vados.ru/upload/\";\r\ + \n:global BackupUploadUser \$Identity;\r\ + \n:global BackupUploadPass \"root.mnuc.backuper\";\r\ + \n\r\ + \n:global BackupSendBinary true;\r\ + \n:global BackupSendExport true;\r\ + \n:global BackupSendGlobalConfig true;\r\ + \n:global BackupSendScripts true;\r\ + \n\r\ + \n# Remove local file after uploading if no errors\r\ + \n:global BackupRmLocal true;\r\ + \n\r\ + \n# Local Backups Root Directory \r\ + \n:global BackupLocalRoot \"tmpfs\";\r\ + \n\r\ + \n# Encrypt Backup\r\ + \n:global BackupEncrypt true;\r\ + \n\r\ + \n# Sensitive information in Backups\r\ + \n:global BackupSens true;\r\ + \n\r\ + \n# User Export\r\ + \n:global BackupUser true;\r\ + \n\r\ + \n# License Export (not for CHR, will silently skip)\r\ + \n:global BackupLicense false;\r\ + \n\r\ + \n# SSH Keys\r\ + \n:global BackupSshKeys true;\r\ + \n\r\ + \n# Certificate Export\r\ + \n:global BackupCerts true;\r\ + \n\r\ + \n# Certificate Password\r\ + \n:global BackupCertsPasswd \"\";\r\ + \n\r\ + \n# User-Manager Export\r\ + \n:global BackupUserMan false;\r\ + \n\r\ + \n# The Dude Export\r\ + \n:global BackupDude false;\r\ + \n\r\ + \n# User Files to export, comma-separated string or array of strings\r\ + \n# User Files are not removed on backup\r\ + \n# Any directory paths will be removed (/ -> _) on remote file\r\ + \n# Nonpresent files are silently skipped\r\ + \n:global BackupUserList \"autosupout.rif,autosupout.old.rif\";\r\ + \n\r\ + \n# load functions and any custom scripts\r\ + \n# [ /system/script/find where name=\"global-config-ov\ + erlay\" ], \\\r\ + \n# [ /system/script/find where name~\"^global-config-o\ + verlay\\\\.d/.\" ]\r\ + \n#\r\ + \n#:foreach Script in=([ /system/script/find where name=\"Amster-TGglobalV\ + ars\" ], [ /system/script/find where name=\"Amster-TGglobalFunc\" ]) do={\ + \r\ + \n# :onerror Err {\r\ + \n# /system/script/run \$Script;\r\ + \n# } do={\r\ + \n# :log error (\"Loading configuration from configs and functions\"\ + \_. [ /system/script/get \$Script name ] . \" failed: \" . \$Err);\r\ + \n# }\r\ + \n#}\r\ + \n#:log info \"\\ndevMode = \$devMode\";\r\ + \n#:log info \"\\ndevRunning = \$devRunning\";\r\ + \n:foreach Script in=[ /system/script/find where source~\"^#!rsc by Vados \ + GlobalRUN\\r\?\\n\" ] do={\r\ + \n :onerror Err {\r\ + \n /system/script/run \$Script;\r\ + \n } do={\r\ + \n :log error (\"Run script \" . [ /system/script/get \$Script name \ + ] . \" width marker \\\" GlobalRUN\\\" failed: \" . \$Err);\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n# signal we are ready\r\ + \n:set GlobalConfReady true;\r\ + \n:while (\$GlobalConfReady != true) do={:delay 500ms};\r\ + \n" +add comment="Global functions" dont-require-permissions=no name=AM-GlobalFunc \ + owner=AM-GlobalFunc policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\r\ + \n# RouterOS script: AM-GglobalFunc\r\ + \n# Script comment: Global functions\r\ + \n# Copyright (c) 2005-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version=7.19\r\ + \n# requires device-mode, fetch, scheduler\r\ + \n:local ExitOK false;\r\ + \n:local ScriptName [ :jobname ];\r\ + \n#:global checkRunJob \$SriptName;\r\ + \n#:global fixCRLF;\r\ + \n#:if (\$fixCRLF != false) do={\r\ + \n#:foreach fixScript in=([ /system/script/find where name~\"*\" ]) do={/s\ + ystem/script/set source=[ :tocrlf [ get \$fixScript source ] ] \$fixScript\ + }\r\ + \n#:if (\$fixCRLF != \"LF\") do={ /system/script/set source=[ :tocrlf [ g\ + et \$fixScript source ] ] \$fixScript};};\r\ + \n#}\r\ + \n:global GlobalFuncReady false;\r\ + \n\r\ + \n# Git commit id & info, expected configuration version\r\ + \n:global CommitId \"main/694/a1b071a6\";\r\ + \n:global CommitTAG \"unknown\";\r\ + \n:global CommitInfo \"Autocommit in repo: ros.vados.ru, generated by owne\ + r: root, in 13:30:04 15.06.2026.\";\r\ + \n\r\ + \n# The variables are received right here.\r\ + \n:global GlobalConfVersion 140;\r\ + \n\r\ + \n:global SumsDirAndFileName \"tmp/checksums.json\";\r\ + \n\r\ + \n:global Identity [/system/identity/get name];\r\ + \n:global IdentityShort [:pick \$Identity 0 18];\r\ + \n\r\ + \n:global devBoardName [/system/resource/get board-name];\r\ + \n:global devMode [/system/device-mode/get mode];\r\ + \n:global devCurArch [/system/resource/get architecture-name];\r\ + \n:global devCurVersion [/system/resource/get version];\r\ + \n\r\ + \n# Variables defined in AM-GlobalConfig.rsc\r\ + \n:global TerminalColorOutput;\r\ + \n:global CommentsInScripts;\r\ + \n:global DetectIpAddrDefault;\r\ + \n:global DetectIpAddrFallback;\r\ + \n:global updateChannel;\r\ + \n:global Domain;\r\ + \n:global EmailGeneralTo;\r\ + \n:global BackupAndUpdateMode;\r\ + \n\r\ + \n# Single functions, without nested functions.\r\ + \n:global MiniDateTimeStamp;\r\ + \n:global MicroDateTimeStamp;\r\ + \n\r\ + \n# Include globals \$PrintDebug and \$PrintDebugOverride\r\ + \n:global LogPrint;\r\ + \n\r\ + \n# DeviceInfo and Updates\r\ + \n:global IsCheckUpdates;\r\ + \n:global WaitCheckUpdates;\r\ + \n:global GetPubIp;\r\ + \n\r\ + \n:global GetArrDeviceInfo;\r\ + \n:global WaitArrDeviceInfo;\r\ + \n\r\ + \n:global devModel;\r\ + \n:global devRunningMode;\r\ + \n\r\ + \n:global devRbRevision;\r\ + \n:global devRbSerialNumber;\r\ + \n:global devRbVerAvail;\r\ + \n\r\ + \n:global runningChannelVersion;\r\ + \n:global runningChannel;\r\ + \n:global runningVersion;\r\ + \n\r\ + \n:global devBuildTime;\r\ + \n:global ROsVerAvail;\r\ + \n:global PkgUpdStatus;\r\ + \n:global currentUpdateChannel;\r\ + \n\r\ + \n:global ScriptInstallUpdate;\r\ + \n\r\ + \n:global DeviceInfo;\r\ + \n\r\ + \n:global OldMode;\r\ + \n\r\ + \n:global ParseKeyValueStore;\r\ + \n:global RandomDelay;\r\ + \n:global GetRandomNumber;\r\ + \n:global EscapeForRegEx;\r\ + \n:global CharacterMultiply;\r\ + \n:global CharacterReplace;\r\ + \n:global CleanFilePath;\r\ + \n:global CleanName;\r\ + \n\r\ + \n:global CommitBrief;\r\ + \n\r\ + \n:global EitherOr;\r\ + \n:global FormatLine;\r\ + \n:global GetRandom20CharAlNum;\r\ + \n:global GetRandom20CharHex;\r\ + \n:global GetRandomNumber;\r\ + \n:global Grep;\r\ + \n:global IfThenElse;\r\ + \n:global MAX;\r\ + \n:global MIN;\r\ + \n:global HumanReadableNum;\r\ + \n\r\ + \n:global IsFullyConnected;\r\ + \n:global IsDNSResolving;\r\ + \n:global IsTimeSync;\r\ + \n:global IsTimeSyncCached;\r\ + \n:global IsTimeSyncResetNtp;\r\ + \n\r\ + \n:global MkDir;\r\ + \n:global RmDir;\r\ + \n:global RmFile;\r\ + \n:global FileGet;\r\ + \n:global Unix2Dos;\r\ + \n:global UrlEncode;\r\ + \n:global WaitForFile;\r\ + \n:global ScriptLock;\r\ + \n:global SendTelegram;\r\ + \n:global NotificationFunctions;\r\ + \n:global SendNotification;\r\ + \n:global SendNotification2;\r\ + \n:global SymbolForNotification;\r\ + \n:global SymbolByUnicodeName;\r\ + \n:global ValidateSyntax;\r\ + \n:global CheckSumsVerify;\r\ + \n:global GlobalConfChanges;\r\ + \n:global GlobalConfMigration;\r\ + \n:global VersionToNum;\r\ + \n:global RequiredRouterOS;\r\ + \n:global ExitError;\r\ + \n:global ExitOnError;\r\ + \n\r\ + \n:global FetchHugeFiles;\r\ + \n:global FetchUserAgentStr;\r\ + \n:global FileExists;\r\ + \n:global CertificateAvailable;\r\ + \n:global CertificateDownload;\r\ + \n:global CertificateNameByCN;\r\ + \n:global CharacterMultiply;\r\ + \n\r\ + \n:global InspectVar;\r\ + \n:global InspectVarRet;\r\ + \n:global ParseCustom;\r\ + \n\r\ + \n:set IsCheckUpdates do={\r\ + \n :local isInfo [:tobool \$1];\r\ + \n :global updateChannel;\r\ + \n :global PkgUpdStatus;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n :global arrDeviceInfo;\r\ + \n :log info (\$0 . \" \\\$isInfo = \" . \$isInfo); \r\ + \n :local CurrentChannel [ /system/package/update/get channel ];\r\ + \n :if ([ :len \$updateChannel ] > 0 && \$CurrentChannel != \$updateChann\ + el) do={\r\ + \n :retry command={/system/package/update set channel=\$updateChannel} \ + \_delay=300ms max=5 on-error={};\r\ + \n :log info (\$0 . \" Set updates channel to: \$updateChannel\");\r\ + \n }\r\ + \n :local Update [ /system/package/update/get ];\r\ + \n :local Channel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set currentUpdateChannel \$Channel;\r\ + \n :log info (\$0 . \" Update Channel: \" . \$Channel . \".\");\r\ + \n :local StatusPkg \"undefined\";\r\ + \n :log info (\$0 . \" Checking for updates...\");\r\ + \n :retry command={:set \$StatusPkg ([/system/package/update/check-for-up\ + dates without-paging as-value]->\"status\")} \\\r\ + \n delay=300ms max=5 on-error={};\r\ + \n :log info (\$0 . \" \\\$StatusPkg = \" . \$StatusPkg);\r\ + \n :if (\$StatusPkg = \"New version is available\") do={ :set PkgUpdStatu\ + s true; } else={ :set PkgUpdStatus false; }\r\ + \n :set ROsVerAvail [ :tostr [ /system/package/update/get latest-version \ + ] ];\r\ + \n :log info (\$0 . \" \\\$PkgUpdStatus = \" . \$PkgUpdStatus);\r\ + \n :if (\$isInfo != false || \$PkgUpdStatus = true) do={\r\ + \n :log info (\$0 . \" \\\$PkgUpdStatus = \" . \$PkgUpdStatus);\r\ + \n :if ([ :typeof \$arrDeviceInfo ] != \"array\") do={\r\ + \n :set arrDeviceInfo [:toarray \$arrDeviceInfo];\r\ + \n }\r\ + \n :retry command={:set (\$arrDeviceInfo->\"devUpdates\") [ /system/pac\ + kage/update/get ]} delay=500ms max=5 on-error={:log error (\"Error\")};\r\ + \n :return true;\r\ + \n } else={\r\ + \n :return \$PkgUpdStatus;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set WaitCheckUpdates do={\r\ + \n :global IsCheckUpdates;\r\ + \n :global PkgUpdStatus;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n :global arrDeviceInfo;\r\ + \n :local Status \"\";\r\ + \n :local Update;\r\ + \n :local WaitCount 0;\r\ + \n :if ([ \$IsCheckUpdates true ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n :set Status [ :tostr [ /system/package/update/get status ] ];\r\ + \n :while ((\$Status = \"\" || \$Status = \"finding out latest version...\ + \") && \$WaitCount < 60) do={\r\ + \n :delay 1s;\r\ + \n :set WaitCount (\$WaitCount + 1);\r\ + \n :set Status [ :tostr [ /system/package/update/get status ] ];\r\ + \n }\r\ + \n :set Update [ /system/package/update/get ];\r\ + \n :set currentUpdateChannel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set ROsVerAvail [ :tostr (\$Update->\"latest-version\") ];\r\ + \n :if ((\$Update->\"status\") = \"New version is available\") do={\r\ + \n :set PkgUpdStatus true;\r\ + \n } else={\r\ + \n :set PkgUpdStatus false;\r\ + \n }\r\ + \n :if ([ :typeof \$arrDeviceInfo ] != \"array\") do={\r\ + \n :set arrDeviceInfo [:toarray \$arrDeviceInfo];\r\ + \n }\r\ + \n :set (\$arrDeviceInfo->\"devUpdates\") \$Update;\r\ + \n :if (\$Status = \"\" || \$Status = \"finding out latest version...\") \ + do={\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set WaitArrDeviceInfo do={\r\ + \n :global GetArrDeviceInfo;\r\ + \n :while ([ \$GetArrDeviceInfo ] = false) do={\r\ + \n :delay 1s;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set GetArrDeviceInfo do={\r\ + \n :global LogPrint;\r\ + \n :global arrDeviceInfo;\r\ + \n :global devBoardName;\r\ + \n :global devModel;\r\ + \n :global devRunning;\r\ + \n :global devCurArch;\r\ + \n :global devRbRevision;\r\ + \n :global devRbSerialNumber;\r\ + \n :global devBuildTime;\r\ + \n :global runningChannelVersion;\r\ + \n :global runningChannel;\r\ + \n :global runningVersion;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n\r\ + \n :local DeviceInfo;\r\ + \n :local Resource [/system/resource/get];\r\ + \n :local Update [ /system/package/update/get ];\r\ + \n :local VersionString [ :tostr (\$Resource->\"version\") ];\r\ + \n :local ChannelStart [ :find \$VersionString \" (\" ];\r\ + \n :local RouterBoard;\r\ + \n :local IsRouterBoard false;\r\ + \n :local RunningMode \"\";\r\ + \n\r\ + \n :set devCurArch [ :tostr (\$Resource->\"architecture-name\") ];\r\ + \n :set devBuildTime [ :tostr (\$Resource->\"build-time\") ];\r\ + \n :set runningChannelVersion \$VersionString;\r\ + \n :set runningVersion \$VersionString;\r\ + \n :set runningChannel \"\";\r\ + \n\r\ + \n :if ([ :typeof \$ChannelStart ] = \"num\" && \$ChannelStart >= 0) do=\ + {\r\ + \n :set runningVersion [ :pick \$VersionString 0 \$ChannelStart ];\r\ + \n :local ChannelRest [ :pick \$VersionString (\$ChannelStart + 2) [ :\ + len \$VersionString ] ];\r\ + \n :local ChannelEnd [ :find \$ChannelRest \")\" ];\r\ + \n :if ([ :typeof \$ChannelEnd ] = \"num\" && \$ChannelEnd >= 0) do={\ + \r\ + \n :set runningChannel [ :pick \$ChannelRest 0 \$ChannelEnd ];\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :if ([:pick \$devBoardName 0 3] != \"CHR\" or [:pick \$devBoardName 0\ + \_3] != \"x86\") do={\r\ + \n :do {\r\ + \n :set RouterBoard [[ :parse \"/system/routerboard/get\" ]];\r\ + \n# :set RouterBoard [ /system/routerboard/get ];\r\ + \n :if ((\$RouterBoard->\"routerboard\") = true) do={\r\ + \n :set IsRouterBoard true;\r\ + \n }\r\ + \n } on-error={}\r\ + \n }\r\ + \n\r\ + \n :do {\r\ + \n :set RunningMode [ /system/device-mode/get mode ];\r\ + \n } on-error={\r\ + \n :do {\r\ + \n :set RunningMode [ /system/device-mode/get running ];\r\ + \n } on-error={\r\ + \n :set RunningMode \"\";\r\ + \n }\r\ + \n }\r\ + \n :set devRunning \$RunningMode;\r\ + \n\r\ + \n :if (\$IsRouterBoard = true) do={\r\ + \n :set devModel [ :tostr (\$RouterBoard->\"model\") ];\r\ + \n :set devRbRevision [ :tostr (\$RouterBoard->\"revision\") ];\r\ + \n :set devRbSerialNumber [ :tostr (\$RouterBoard->\"serial-number\") \ + ];\r\ + \n } else={\r\ + \n :set devModel \$devBoardName;\r\ + \n :set devRbRevision \"\";\r\ + \n :set devRbSerialNumber \"\";\r\ + \n }\r\ + \n\r\ + \n :set currentUpdateChannel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set ROsVerAvail [ :tostr (\$Update->\"latest-version\") ];\r\ + \n\r\ + \n :set (\$DeviceInfo->\"board-name\") \$devBoardName;\r\ + \n :set (\$DeviceInfo->\"architecture-name\") \$devCurArch;\r\ + \n :set (\$DeviceInfo->\"model\") \$devModel;\r\ + \n :set (\$DeviceInfo->\"revision\") \$devRbRevision;\r\ + \n :set (\$DeviceInfo->\"serial-number\") \$devRbSerialNumber;\r\ + \n :set (\$DeviceInfo->\"running-mode\") \$devRunning;\r\ + \n :set (\$DeviceInfo->\"build-time\") \$devBuildTime;\r\ + \n :set (\$DeviceInfo->\"running-channel-version\") \$runningChannelVers\ + ion;\r\ + \n :set (\$DeviceInfo->\"running-version\") \$runningVersion;\r\ + \n :set (\$DeviceInfo->\"running-channel\") \$runningChannel;\r\ + \n :set (\$DeviceInfo->\"routerboard\") \$IsRouterBoard;\r\ + \n :set (\$DeviceInfo->\"current-firmware\") [ :tostr (\$RouterBoard->\"\ + current-firmware\") ];\r\ + \n :set (\$DeviceInfo->\"upgrade-firmware\") [ :tostr (\$RouterBoard->\"\ + upgrade-firmware\") ];\r\ + \n :set (\$DeviceInfo->\"package-channel\") \$currentUpdateChannel;\r\ + \n :set (\$DeviceInfo->\"installed-version\") [ :tostr (\$Update->\"inst\ + alled-version\") ];\r\ + \n :set (\$DeviceInfo->\"latest-version\") \$ROsVerAvail;\r\ + \n :set (\$DeviceInfo->\"update-status\") [ :tostr (\$Update->\"status\"\ + ) ];\r\ + \n\r\ + \n :set arrDeviceInfo \$DeviceInfo;\r\ + \n :return \$DeviceInfo;\r\ + \n}\r\ + \n\r\ + \n:set DeviceInfo do={\r\ + \n :global GetArrDeviceInfo;\r\ + \n :global GlobalConfVersion;\r\ + \n :global Identity;\r\ + \n :global IfThenElse;\r\ + \n :global FormatLine;\r\ + \n :global CommitBrief;\r\ + \n\r\ + \n :local License [/system/license/get];\r\ + \n :local Snmp [ /snmp/get ];\r\ + \n :local Info [ \$GetArrDeviceInfo ];\r\ + \n\r\ + \n :if ([ :typeof \$Info ] != \"array\") do={\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :return ( \\\r\ + \n [ \$FormatLine \"Hostname\" \$Identity ] . \"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$Snmp->\"location\") ] > 0) \\\r\ + \n ([ \$FormatLine \"Location\" (\$Snmp->\"location\") ] . \"\\n\") ]\ + \_. \\\r\ + \n [ \$IfThenElse ([ :len (\$Snmp->\"contact\") ] > 0) \\\r\ + \n ([ \$FormatLine \"Contact\" (\$Snmp->\"contact\") ] . \"\\n\") ] .\ + \_\\\r\ + \n \"Hardware:\\n\" . \\\r\ + \n [ \$FormatLine \" Board\" (\$Info->\"board-name\") ] . \"\\n\" . \ + \\\r\ + \n [ \$FormatLine \" Arch\" (\$Info->\"architecture-name\") ] . \"\\\ + n\" . \\\r\ + \n [ \$FormatLine \" Model\" (\$Info->\"model\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"revision\") ] > 0) \\\r\ + \n (\" \" . (\$Info->\"revision\")) ] . \"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"serial-number\") ] > 0) \\\r\ + \n ([ \$FormatLine \" Serial\" (\$Info->\"serial-number\") ] . \"\ + \\n\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$License->\"nlevel\") ] > 0) \\\r\ + \n ([ \$FormatLine \" License\" (\"level \" . (\$License->\"nlevel\ + \")) ] . \"\\n\") ] . \\\r\ + \n \"RouterOS:\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$License->\"level\") ] > 0) \\\r\ + \n ([ \$FormatLine \" License\" (\"level \" . (\$License->\"level\ + \")) ] . \"\\n\") ] . \\\r\ + \n [ \$FormatLine \" Channel\" (\$Info->\"package-channel\") ] . \"\ + \\n\" . \\\r\ + \n [ \$FormatLine \" Installed\" (\$Info->\"installed-version\") ] .\ + \_\"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"running-channel\") ] > 0) \\\r\ + \n ([ \$FormatLine \" Running\" ((\$Info->\"running-version\") . \ + \" (\" . (\$Info->\"running-channel\") . \")\") ] . \"\\n\") \\\r\ + \n ([ \$FormatLine \" Running\" (\$Info->\"running-version\") ] . \ + \"\\n\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"latest-version\") ] > 0 && \\\r\ + \n (\$Info->\"installed-version\") != (\$Info->\"latest-version\"))\ + \_\\\r\ + \n ([ \$FormatLine \" Available\" (\$Info->\"latest-version\") ] .\ + \_\"\\n\") ] . \\\r\ + \n [ \$IfThenElse ((\$Info->\"routerboard\") = true && \\\r\ + \n (\$Info->\"current-firmware\") != (\$Info->\"upgrade-firmware\")\ + ) \\\r\ + \n ([ \$FormatLine \" Firmware\" ((\$Info->\"current-firmware\") .\ + \_\" -> \" . (\$Info->\"upgrade-firmware\")) ] . \"\\n\") ] . \\\r\ + \n \"RouterOS-Scripts:\\n\" . \\\r\ + \n [ \$FormatLine \" Commit\" [ \$CommitBrief ] ] . \"\\n\" . \\\r\ + \n [ \$FormatLine \" Version\" \$GlobalConfVersion ]);\r\ + \n}\r\ + \n\r\ + \n:if ([ :typeof \$NotificationFunctions ] != \"array\") do={:set Notifica\ + tionFunctions ({})}\r\ + \n\r\ + \n:set GetRandom20CharAlNum do={\r\ + \n :global EitherOr;\r\ + \n :return [ :rndstr length=[ \$EitherOr [ :tonum \$1 ] 20 ] from=\"ABCDE\ + FGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\" ];\r\ + \n}\r\ + \n\r\ + \n:set GetRandom20CharHex do={:global EitherOr; :return [ :rndstr length=[\ + \_\$EitherOr [ :tonum \$1 ] 20 ] from=\"0123456789abcdef\" ]; }\r\ + \n:set GetRandomNumber do={:global EitherOr; :return [ :rndnum from=0 to=[\ + \_\$EitherOr [ :tonum \$1 ] 4294967295 ] ]; }\r\ + \n\r\ + \n:global checkRunJob;\r\ + \n:set checkRunJob do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :global ScriptLock; \r\ + \n :if ([ \$ScriptLock \$Script ] = false) do={:return false}\r\ + \n :foreach Job in=[ /system/script/job/find where script=\$Script ] do={\ + :set Job [ /system/script/job/get \$Job ];\r\ + \n :while ([ :typeof (\$Job->\"parent\") ] = \"id\") do={:set Job [ /sy\ + stem/script/job/get [ find where .id=(\$Job->\"parent\") ] ]}\r\ + \n :if ((\$Job->\"type\") = \"login\") do={:return true};}; :return fa\ + lse; \r\ + \n}\r\ + \n\r\ + \n:set InspectVar do={\r\ + \n :global InspectVarRet;\r\ + \n :put [ :tocrlf [ \$InspectVarRet \$1 ] ];\r\ + \n}\r\ + \n\r\ + \n:set CommitBrief do={\r\ + \n :global CommitId;\r\ + \n :global CommitInfo;\r\ + \n :if (\$CommitId = \"unknown\") do={\r\ + \n :return \"unknown\";\r\ + \n }\r\ + \n :return (\$CommitInfo . \"/\" . [ :pick \$CommitId 0 8 ]);\r\ + \n}\r\ + \n\r\ + \n:set InspectVarRet do={\r\ + \n :local Input \$1;\r\ + \n :local Level (0 + [ :tonum \$2 ]);\r\ + \n :global CharacterReplace;\r\ + \n :global IfThenElse;\r\ + \n :global InspectVarRet;\r\ + \n :local IndentReturn do={\r\ + \n :local Prefix [ :tostr \$1 ];\r\ + \n :local Value [ :tostr \$2 ];\r\ + \n :local Level [ :tonum \$3 ];\r\ + \n :global CharacterMultiply;\r\ + \n :return ([ \$CharacterMultiply \" \" (\$Level * 2) ] . \"-\" . \$Pre\ + fix . \"-> \" . \$Value);\r\ + \n }\r\ + \n :local TypeOf [ :typeof \$Input ];\r\ + \n :local Len [ :len \$Input ];\r\ + \n :local Return [ \$IndentReturn \"type\" \$TypeOf \$Level ];\r\ + \n :if (\$TypeOf = \"array\") do={\r\ + \n :foreach Key,Value in=\$Input do={\r\ + \n :set \$Return (\$Return . \"\\n\" . \\\r\ + \n [ \$IndentReturn \"key\" \$Key (\$Level + 1) ] . \"\\n\" . \\\r\ + \n [ \$InspectVarRet \$Value (\$Level + 2) ]);\r\ + \n }\r\ + \n } else={\r\ + \n :if (\$TypeOf = \"str\") do={\r\ + \n :set \$Return (\$Return . \"\\n\" . \\\r\ + \n [ \$IndentReturn \"len\" \$Len \$Level ]);\r\ + \n :if ([ :typeof [ :find \$Input (\"\\r\") ] ] = \"num\") do={\r\ + \n :set Input [ \$CharacterReplace \$Input (\"\\r\") \"\" ];\r\ + \n }\r\ + \n :if ([ :typeof [ :find \$Input (\"\\n\") ] ] = \"num\") do={\r\ + \n :set Input [ \$CharacterReplace \$Input (\"\\n\") \" \" ];\r\ + \n }\r\ + \n }\r\ + \n :if (\$TypeOf != \"nothing\") do={\r\ + \n :set \$Return (\$Return . \"\\n\" . \\\r\ + \n [ \$IndentReturn \"value\" [ \$IfThenElse ([ :len \$Input ] > 80)\ + \_\\\r\ + \n ([ :pick \$Input 0 77 ] . \"...\") \$Input ] \$Level ]);\r\ + \n }\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set GetPubIp do={\r\ + \n :global DetectIpAddrDefault;\r\ + \n :global DetectIpAddrFallback;\r\ + \n\r\ + \n :local PubIpAddr false;\r\ + \n :local Url \$DetectIpAddrDefault;\r\ + \n :local JobName [ :jobname ];\r\ + \n\r\ + \n :do {\r\ + \n :log debug (\$0 . \" Trying to detect public IP using default serv\ + ice: \" . \$Url . \"...\");\r\ + \n :retry command={:set PubIpAddr ([ /tool/fetch http-method=\"get\"\ + \_check-certificate=yes-without-crl \$Url output=user as-value ]->\"data\"\ + )} \\\r\ + \n delay=50ms max=5 on-error={:log error (\$JobName . \" Failed to \ + detect public IP using default service: \" . \$Url . \".\")}\r\ + \n } on-error={\r\ + \n :log error (\$0 . \" Failed to detect public IP using default serv\ + ice: \" . \$Url . \".\");\r\ + \n :set Url \$DetectIpAddrFallBack;\r\ + \n :log debug (\$0 . \" Trying to detect public IP using fallback ser\ + vice: \" . \$Url . \"...\");\r\ + \n :retry command={:set PubIpAddr ([ /tool/fetch http-method=\"get\"\ + \_check-certificate=yes-without-crl \$Url output=user as-value ]->\"data\"\ + )} \\\r\ + \n delay=200ms max=5 on-error={:log error (\$JobName . \" Failed to\ + \_detect public IP using fallback service: \" . \$Url . \".\")}\r\ + \n };\r\ + \n :local IpLen ([ :len \$PubIpAddr ] -1);\r\ + \n :if (\$PubIpAddr = false) do={:set PubIpAddr \"not-detected\"} else=\ + {:set PubIpAddr [:pick \$PubIpAddr 0 \$IpLen]}\r\ + \n :return \$PubIpAddr;\r\ + \n}\r\ + \n\r\ + \n:set FormatLine do={\r\ + \n :local Key [ :tostr \$1 ];\r\ + \n :local Value [ :tostr \$2 ];\r\ + \n :local Indent [ :tonum \$3 ];\r\ + \n :local Spaces;\r\ + \n :local Return \"\";\r\ + \n :global CharacterMultiply;\r\ + \n :global EitherOr;\r\ + \n :set Indent [ \$EitherOr \$Indent 16 ];\r\ + \n :local Spaces [ \$CharacterMultiply \" \" \$Indent ];\r\ + \n :if ([ :len \$Key ] > 0) do={ :set Return (\$Key . \":\")}\r\ + \n :if ([ :len \$Key ] > (\$Indent - 2)) do={:set Return (\$Return . \"\\\ + n\" . [ :pick \$Spaces 0 \$Indent ] . \$Value);\r\ + \n } else={:set Return (\$Return . [ :pick \$Spaces 0 (\$Indent - [ :len \ + \$Return ]) ] . \$Value)}\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set ParseCustom do={\r\ + \n :local Str [ :tostr \$1 ];\r\ + \n :local Start [:find [ \$Str ] [:tostr \$2]];\r\ + \n :local End [ :tostr \$3 ];\r\ + \n :local Num [ :tonum \$4 ];\r\ + \n :local Return;\r\ + \n :if ([:len \$Num] = 0) do={:set Num \"0\"}\r\ + \n :local rest [:pick \$Str (\$Start+\$Num) [:len \$Str]]; \r\ + \n :if ([:len \$End ] = 0) do={:set Return [:pick \$Str \$Num \$Start]} e\ + lse={\r\ + \n :set End [:find \$rest \$End];\r\ + \n :set Return [:pick \$rest 0 \$End];\r\ + \n }\r\ + \n:return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set LogPrint do={\r\ + \n :local Severity [ :tostr \$1 ];\r\ + \n :local Name [ :tostr \$2 ];\r\ + \n :local Message [ :tostr \$3 ];\r\ + \n :global PrintDebug;\r\ + \n :global PrintDebugOverride;\r\ + \n :global EitherOr;\r\ + \n :local Debug [ \$EitherOr (\$PrintDebugOverride->\$Name) \$PrintDebug \ + ];\r\ + \n :local PrintSeverity do={\r\ + \n :global TerminalColorOutput;\r\ + \n :if (\$TerminalColorOutput != true) do={:return \$1}\r\ + \n :local Color { debug=96; info=97; warning=93; error=91 };\r\ + \n :return (\"\\1B[\" . \$Color->\$1 . \"m\" . \$1 . \"\\1B[0m\");\r\ + \n}\r\ + \n :local Log ([ \$EitherOr \$Name \"\" ] . \": \" . \$Message);\ + \r\ + \n :if (\$Severity ~ (\"^(custom|debug|error|info)\\\$\")) do={\r\ + \n :if (\$Severity = \"debug\") do={:log debug \$Log}\r\ + \n :if (\$Severity = \"error\") do={:log error \$Log}\r\ + \n :if (\$Severity = \"info\" ) do={:log info \$Log}\r\ + \n } else={:log warning \$Log; :set Severity \"warning\"}\r\ + \n :if (\$Severity != \"debug\" || \$Debug = true) do={:put ([ \$PrintSev\ + erity \$Severity ] . \": \" . \$Message)}\r\ + \n}\r\ + \n\r\ + \n:set CertificateAvailable do={\r\ + \n :local CommonName [ :tostr \$1 ];\r\ + \n :local UseFor [ :tostr \$2 ];\r\ + \n\r\ + \n :global CertificateDownload;\r\ + \n :global ParseKeyValueStore;\r\ + \n\r\ + \n :if ([ :len \$UseFor ] = 0) do={\r\ + \n :log warning (\$0 . \"The intended use is undefined!\");\r\ + \n :set UseFor \"undefined\";\r\ + \n }\r\ + \n :if ([ /system/resource/get free-hdd-space ] < 8388608 && \\\r\ + \n [ /certificate/settings/get crl-download ] = true && \\\r\ + \n [ /certificate/settings/get crl-store ] = \"system\") do={\r\ + \n :log warning (\$0 . \"This system has low free flash space but \" . \ + \\\r\ + \n \"is configured to download certificate CRLs to system!\");\r\ + \n }\r\ + \n :if ([ :len \$CommonName ] = 0) do={\r\ + \n :log warning (\$0 . \"No CommonName given!\");\r\ + \n :return false;\r\ + \n }\r\ + \n :local CertSettings [ /certificate/settings/get ];\r\ + \n :if (((\$CertSettings->\"builtin-trust-anchors\") = \"trusted\" || \\\ + \r\ + \n (\$CertSettings->\"builtin-trust-store\") ~ \$UseFor || \\\r\ + \n (\$CertSettings->\"builtin-trust-store\") = \"all\") && \\\r\ + \n [ :len [ /certificate/builtin/find where common-name=\$CommonName\ + \_] ] > 0) do={\r\ + \n :return true;\r\ + \n }\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] = 0\ + ) do={\r\ + \n :log info (\$0 . \"Certificate with CommonName '\" . \$CommonName . \ + \"' not available.\");\r\ + \n :if ([ \$CertificateDownload \$CommonName ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] > 1\ + ) do={\r\ + \n :log info (\$0 . \"There are \" . \$CertCount . \" Certificates with\ + \_CommonName '\" . \$CommonName . \"'. Should be ok.\");\r\ + \n :return true;\r\ + \n }\r\ + \n :local CertVal [ /certificate/get [ find where common-name=\$CommonNam\ + e ] ];\r\ + \n :while ((\$CertVal->\"akid\") != \"\" && (\$CertVal->\"akid\") != (\$C\ + ertVal->\"skid\")) do={\r\ + \n :if ([ :len [ /certificate/find where skid=(\$CertVal->\"akid\") ] ]\ + \_= 0) do={\r\ + \n :local IssuerCN ([ \$ParseKeyValueStore (\$CertVal->\"issuer\") ]-\ + >\"CN\");\r\ + \n :log info (\$0 . \"Certificate chain for '\" . \$CommonName . \"' \ + is incomplete, missing '\" . \$IssuerCN . \"'.\");\r\ + \n :if ([ \$CertificateDownload \$IssuerCN ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n :set CertVal [ /certificate/get [ find where skid=(\$CertVal->\"akid\ + \") ] ];\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set CertificateDownload do={\r\ + \n :local CommonName [ :tostr \$1 ];\r\ + \n :global ScriptUpdatesBaseUrl;\r\ + \n :global ScriptUpdatesUrlSuffix;\r\ + \n :global CertificateNameByCN;\r\ + \n :global CleanName;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global RmFile;\r\ + \n :global WaitForFile;\r\ + \n\r\ + \n :log info (\$0 . \"Downloading and importing certificate with \" . \\\ + \r\ + \n \"CommonName '\" . \$CommonName . \"'.\");\r\ + \n :local FileName ([ \$CleanName \$CommonName ] . \".pem\");\r\ + \n :do {\r\ + \n /tool/fetch check-certificate=yes-without-crl mode=https http-header\ + -field=({ [ \$FetchUserAgentStr \$0 ] }) \\\r\ + \n (\$ScriptUpdatesBaseUrl . \"certs/\" . \$FileName . \$ScriptUpdate\ + sUrlSuffix) \\\r\ + \n dst-path=\$FileName as-value;\r\ + \n \$WaitForFile \$FileName;\r\ + \n } on-error={\r\ + \n :log warning (\$0 . \" Failed downloading certificate with CommonNam\ + e '\" . \$CommonName . \\\r\ + \n \"' from repository! Trying fallback to mkcert.org...\");\r\ + \n :do {\r\ + \n :local CertSettings [ /certificate/settings/get ];\r\ + \n :if ([ :len [ /certificate/find where common-name=\"ISRG Root X1\"\ + \_] ] = 0 && \\\r\ + \n !(((\$CertSettings->\"builtin-trust-anchors\") = \"trusted\" \ + || \\\r\ + \n (\$CertSettings->\"builtin-trust-store\") ~ \"fetch\" || \ + \\\r\ + \n (\$CertSettings->\"builtin-trust-store\") = \"all\") && \\\ + \r\ + \n [ :len [ /certificate/builtin/find where common-name=\"ISRG\ + \_Root X1\" ] ] > 0)) do={\r\ + \n :log error (\$0 . \" Required certificate is not available.\");\ + \r\ + \n :return false;\r\ + \n }\r\ + \n /tool/fetch check-certificate=yes-without-crl mode=https http-head\ + er-field=({ [ \$FetchUserAgentStr \$0 ] }) \\\r\ + \n url=\"https://mkcert.org/generate/\" http-data=[ :serialize to=jso\ + n ({ \$CommonName }) ] \\\r\ + \n dst-path=\$FileName as-value;\r\ + \n \$WaitForFile \$FileName;\r\ + \n :if ([ /file/get \$FileName size ] = 0) do={\r\ + \n \$RmFile \$FileName;\r\ + \n :error false;\r\ + \n }\r\ + \n } on-error={\r\ + \n :log error (\$0 . \" Failed downloading certificate with CommonNam\ + e '\" . \$CommonName . \"'!\");\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n /certificate/import file-name=\$FileName passphrase=\"\" as-value;\r\ + \n :delay 1s;\r\ + \n \$RmFile \$FileName;\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] = 0\ + ) do={\r\ + \n /certificate/remove [ find where name~(\"^\" . \$FileName . \"_[0-9]\ + +\\\$\") ];\r\ + \n :log warning (\$0 . \" Certificate with CommonName '\" . \$CommonNam\ + e . \"' still unavailable!\");\r\ + \n :return false;\r\ + \n }\r\ + \n :foreach Cert in=[ /certificate/find where name~(\"^\" . \$FileName . \ + \"_[0-9]+\\\$\") ] do={\r\ + \n \$CertificateNameByCN [ /certificate/get \$Cert common-name ];\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set CertificateNameByCN do={\r\ + \n :local Match [ :tostr \$1 ];\r\ + \n :global CleanName;\r\ + \n :local Cert ([ /certificate/find where (common-name=\$Match or fingerp\ + rint=\$Match or name=\$Match) ]->0);\r\ + \n :if ([ :len \$Cert ] = 0) do={\r\ + \n :log warning (\$0 .\" No matching certificate found.\");\r\ + \n :return false;\r\ + \n }\r\ + \n :local CommonName [ /certificate/get \$Cert common-name ];\r\ + \n /certificate/set \$Cert name=[ \$CleanName \$CommonName ];\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set CharacterMultiply do={\r\ + \n :local Str [ :tostr \$1 ];\r\ + \n :local Num [ :tonum \$2 ];\r\ + \n :if (\$Num = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :for I from=1 to=\$Num do={:set Return (\$Return . \$Str)}\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set FileExists do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :local Type [ :tostr \$2 ];\r\ + \n :global FileGet;\r\ + \n :local FileVal [ \$FileGet \$FileName ];\r\ + \n :if (\$FileVal = false) do={ :return false; }\r\ + \n :if ([ :len (\$FileVal->\"size\") ] = 0) do={ :return false; }\r\ + \n :if ([ :len \$Type ] = 0 || \$FileVal->\"type\" = \$Type) do={ :return\ + \_true; }\r\ + \n :return false;\r\ + \n}\r\ + \n\r\ + \n:set Grep do={\r\ + \n :local Input ([ :tostr \$1 ] . \"\\n\");\r\ + \n :local Pattern [ :tostr \$2 ];\r\ + \n :if ([ :typeof [ :find \$Input \$Pattern ] ] = \"nil\") do={:return []\ + }\r\ + \n :do {\r\ + \n :local Line [ :pick \$Input 0 [ :find \$Input \"\\n\" ] ];\r\ + \n :if ([ :typeof [ :find \$Line \$Pattern ] ] = \"num\") do={:return \ + \$Line}\r\ + \n :set Input [ :pick \$Input ([ :find \$Input \"\\n\" ] + 1) [ :len \$\ + Input ] ];\r\ + \n } while=([ :len \$Input ] > 0);\r\ + \n :return [];\r\ + \n}\r\ + \n\r\ + \n:set HumanReadableNum do={\r\ + \n :local Input [ :tonum \$1 ];\r\ + \n :local Base [ :tonum \$2 ];\r\ + \n :global EitherOr;\r\ + \n :global IfThenElse;\r\ + \n :local Prefix \"kMGTPE\";\r\ + \n :local Pow 1;\r\ + \n :set Base [ \$EitherOr \$Base 1024 ];\r\ + \n :local Bin [ \$IfThenElse (\$Base = 1024) \"i\" \"\" ];\r\ + \n :if (\$Input < \$Base) do={:return \$Input}\r\ + \n :for I from=0 to=[ :len \$Prefix ] do={\r\ + \n :set Pow (\$Pow * \$Base);\r\ + \n :if (\$Input / \$Base < \$Pow) do={\r\ + \n :set Prefix [ :pick \$Prefix \$I ];\r\ + \n :local Tmp1 (\$Input * 100 / \$Pow);\r\ + \n :local Tmp2 (\$Tmp1 / 100);\r\ + \n :if (\$Tmp2 >= 100) do={:return (\$Tmp2 . \$Prefix . \$Bin)}\r\ + \n :return (\$Tmp2 . \".\" . \\\r\ + \n [ :pick \$Tmp1 [ :len \$Tmp2 ] ([ :len \$Tmp1 ] - [ :len \$Tmp\ + 2 ] + 1) ] . \\\r\ + \n \$Prefix . \$Bin);\r\ + \n }\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set CleanFilePath do={\r\ + \n :local Path [ :tostr \$1 ];\r\ + \n :global CharacterReplace;\r\ + \n :while (\$Path ~ \"//\") do={ :set \$Path [ \$CharacterReplace \$Path \ + \"//\" \"/\" ]; }\r\ + \n :if ([ :pick \$Path 0 ] = \"/\") do={ :set Path [ :pick \$Path 1 [ :le\ + n \$Path ] ]; }\r\ + \n :if ([ :pick \$Path ([ :len \$Path ] - 1) ] = \"/\") do={ :set Path [ \ + :pick \$Path 0 ([ :len \$Path ] - 1) ]; }\r\ + \n :return \$Path;\r\ + \n}\r\ + \n\r\ + \n:set CleanName do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :local Return \"\";\r\ + \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ + \n :local Char [ :pick \$Input \$I ];\r\ + \n :if ([ :typeof [ find \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr\ + stuvwxyz0123456789\" \$Char ] ] = \"nil\") do={\r\ + \n :do {:if ([ :len \$Return ] = 0) do={:error true};\r\ + \n :if ([ :pick \$Return ([ :len \$Return ] - 1) ] = \"-\") do={:er\ + ror true}; :set Char \"-\"} on-error={:set Char \"\"}; \r\ + \n };\r\ + \n :set Return (\$Return . \$Char)};\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set RandomDelay do={\r\ + \n :local Time [ :tonum \$1 ];\r\ + \n :local Unit [ :tostr \$2 ];\r\ + \n :global EitherOr;\r\ + \n :global GetRandomNumber;\r\ + \n :global MAX;\r\ + \n :if (\$Time = 0) do={:return false}\r\ + \n :delay ([ \$MAX 10 [ \$GetRandomNumber ([ :tonsec [ :totime (\$Time . \ + [ \$EitherOr \$Unit \"s\" ]) ] ] / 1000000) ] ] . \"ms\");\r\ + \n}\r\ + \n\r\ + \n:set EscapeForRegEx do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :if ([ :len \$Input ] = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :local Chars (\"^.[]\\\$()|*+\?{}\\\\\");\r\ + \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ + \n :local Char [ :pick \$Input \$I ];\r\ + \n :if ([ :find \$Chars \$Char ]) do={:set Char (\"\\\\\" . \$Char)}\r\ + \n :set Return (\$Return . \$Char);\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set ExitError do={\r\ + \n :local ExitOK [ :tostr \$1 ];\r\ + \n :local Name [ :tostr \$2 ];\r\ + \n :local Error [ :tostr \$3 ];\r\ + \n :global IfThenElse;\r\ + \n :if (\$ExitOK = \"false\") do={\r\ + \n :log error (\$Name [ \$IfThenElse ([ :pick \$Name 0 1 ] = \"\\\$\") \ + \\\r\ + \n \"Function\" \"Script\" ] . \" '\" . \$Name . \"' exited with er\ + ror\" . \\\r\ + \n [ \$IfThenElse (!(\$Error ~ \"^(|true|false)\\\$\")) (\": \" . \ + \$Error) \".\" ]);\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set ExitOnError do={\r\ + \n :local Name [ :tostr \$1 ];\r\ + \n :local Error [ :tostr \$2 ];\r\ + \n :global IfThenElse;\r\ + \n :log error (\$Name . \" \" . [ \$IfThenElse ([ :pick \$Name 0 1 ] = \"\ + \\\$\") \\\r\ + \n \"Function\" \"Script\" ] . \" '\" . \$Name . \"' exited with erro\ + r\" . \\\r\ + \n [ \$IfThenElse (!(\$Error ~ \"^(|true|false)\\\$\")) (\": \" . \$E\ + rror) \".\" ]);\r\ + \n}\r\ + \n\r\ + \n:set MiniDateTimeStamp do={\r\ + \n :local mikro [ :tobool \$1 ];\r\ + \n /system/clock;\r\ + \n :local vdate [get date];\r\ + \n :local vtime [get time];\r\ + \n :local vdoff [:toarray \"0,4,5,7,8,10\"];\r\ + \n :local MM [:pick \$vdate (\$vdoff->2) (\$vdoff->3)];\r\ + \n :local M [:tonum \$MM];\r\ + \n :if (\$vdate ~ \".../../....\") do={\r\ + \n :set vdoff [:toarray \"7,11,1,3,4,6\"];\r\ + \n :set M ([:find \"xxanebarprayunulugepctovecANEBARPRAYUNULUGE\ + PCTOVEC\" [:pick \$vdate (\$vdoff->2) (\$vdoff->3)] -1] / 2);\r\ + \n :if (\$M>12) do={:set M (\$M - 12)}\r\ + \n :set MM [:pick (100 + \$M) 1 3];\r\ + \n }\r\ + \n :local yyyy [:pick \$vdate (\$vdoff->0) (\$vdoff->1)];\r\ + \n :local dd [:pick \$vdate (\$vdoff->4) (\$vdoff->5)];\r\ + \n :local HH [:pick \$vtime 0 2];\r\ + \n :local mm [:pick \$vtime 3 5];\r\ + \n :local ss [:pick \$vtime 6 8];\r\ + \n :local Return;\r\ + \n :if (\$mikro = true) do={\r\ + \n :set Return ([:pick \$yyyy 2 4] . [:pick \$dd 0 1] . [:pick \$HH 0\ + \_1] . [:pick \$mm 3 4] . [:pick \$ss 6 7]);\r\ + \n } else={\r\ + \n :set Return ([\$yyyy] . [\$MM] . [\$dd] . [\$HH] . [\$mm] . [\$ss]);\ + \r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set WaitForFile do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :local WaitTime [ :totime \$2 ];\r\ + \n :global CleanFilePath;\r\ + \n :global EitherOr;\r\ + \n :global MAX;\r\ + \n :set FileName [ \$CleanFilePath \$FileName ];\r\ + \n :local Delay ([ \$MAX [ \$EitherOr \$WaitTime 2s ] 100ms ] / 9);\r\ + \n :do {\r\ + \n :retry {\r\ + \n /file/get \$FileName;\r\ + \n :return true;\r\ + \n } delay=\$Delay max=10;\r\ + \n } on-error={ }\r\ + \n :while ([ :len [ /file/find where name=\$FileName ] ] > 0) do={\r\ + \n :do {\r\ + \n /file/get \$FileName;\r\ + \n :return true;\r\ + \n } on-error={ }\r\ + \n :delay \$Delay;\r\ + \n :set Delay (\$Delay * 3 / 2);\r\ + \n }\r\ + \n :return false;\r\ + \n}\r\ + \n\r\ + \n:set FileGet do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :global WaitForFile;\r\ + \n :if ([ \$WaitForFile \$FileName 0s ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n :local FileVal false;\r\ + \n :do {\r\ + \n :set FileVal [ /file/get \$FileName ];\r\ + \n } on-error={ }\r\ + \n :return \$FileVal;\r\ + \n}\r\ + \n\r\ + \n:set RmDir do={\r\ + \n :local DirName [ :tostr \$1 ];\r\ + \n :global FileGet;\r\ + \n :log debug (\$0 . \" Removing directory: \". \$DirName);\r\ + \n :local DirVal [ \$FileGet \$DirName ];\r\ + \n :if (\$DirVal = false) do={\r\ + \n :log debug (\$0 . \" ... which does not exist.\");\r\ + \n :return true;\r\ + \n };\r\ + \n :if (\$DirVal->\"type\" != \"directory\") do={\r\ + \n :log error (\$0 . \" Directory '\" . \$DirName . \"' is not a direct\ + ory.\");\r\ + \n :return false;\r\ + \n };\r\ + \n :onerror Err {\r\ + \n /file/remove \$DirName;\r\ + \n } do={\r\ + \n :log error (\$0 . \" Removing directory '\" . \$DirName . \"' failed\ + : \" . \$Err);\r\ + \n :return false;\r\ + \n };\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set RmFile do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :global FileGet;\r\ + \n :log debug (\$0 . \" Removing file: \". \$FileName);\r\ + \n :local FileVal [ \$FileGet \$FileName ];\r\ + \n :if (\$FileVal = false) do={\r\ + \n :log debug (\$0 . \" ... which does not exist.\");\r\ + \n :return true;\r\ + \n }\r\ + \n :if (\$FileVal->\"type\" = \"directory\" || \$FileVal->\"type\" = \"di\ + sk\") do={\r\ + \n :log error (\$0 . \" File '\" . \$FileName . \"' is not a file.\");\ + \r\ + \n :return false;\r\ + \n }\r\ + \n :onerror Err {\r\ + \n /file/remove \$FileName;\r\ + \n } do={\r\ + \n :log error (\$0 . \" Removing file '\" . \$FileName . \"' failed: \"\ + \_. \$Err); :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set MkDir do={\r\ + \n :local Path [ :tostr \$1 ];\r\ + \n :global CleanFilePath;\r\ + \n :global FileGet;\r\ + \n :global RmDir;\r\ + \n :global WaitForFile;\r\ + \n\r\ + \n :local MkTmpfs do={\r\ + \n :global WaitForFile;\r\ + \n :local TmpFs [ /disk/find where slot=tmpfs type=tmpfs ];\r\ + \n :if ([ :len \$TmpFs ] = 1) do={\r\ + \n :if ([ /disk/get \$TmpFs disabled ] = true) do={\r\ + \n :log info (\$0 . \" The tmpfs is disabled, enabling.\");\r\ + \n /disk/enable \$TmpFs;\r\ + \n }\r\ + \n :return true;\r\ + \n }\r\ + \n :log info (\$0 . \" Creating disk of type tmpfs.\");\r\ + \n \$RmDir \"tmpfs\";\r\ + \n :onerror Err {\r\ + \n /disk/add slot=tmpfs type=tmpfs tmpfs-max-size=([ /system/resource\ + /get total-memory ] / 3);\r\ + \n \$WaitForFile \"tmpfs\";\r\ + \n } do={\r\ + \n :log warning (\$0 . \" Creating disk of type tmpfs failed: \" . \$\ + Err);\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n }\r\ + \n :set Path [ \$CleanFilePath \$Path ];\r\ + \n :if (\$Path = \"\") do={\r\ + \n :return true;\r\ + \n }\r\ + \n :log debug (\$0 . \" Making directory: \" . \$Path);\r\ + \n :local PathVal [ \$FileGet \$Path ];\r\ + \n :if (\$PathVal->\"type\" = \"directory\") do={\r\ + \n :log debug (\$0 . \" ... which already exists.\");\r\ + \n :return true;\r\ + \n }\r\ + \n :if ([ :pick \$Path 0 5 ] = \"tmpfs\") do={\r\ + \n :if ([ \$MkTmpfs ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n :onerror Err {\r\ + \n /file/add type=\"directory\" name=\$Path;\r\ + \n \$WaitForFile \$Path;\r\ + \n } do={\r\ + \n :log warning (\$0 . \" Making directory '\" . \$Path . \"' failed: \ + \" . \$Err);\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set MAX do={:if (\$1 > \$2) do={:return \$1}\r\ + \n :return \$2;\r\ + \n}\r\ + \n:set MIN do={:if (\$1 < \$2) do={:return \$1}\r\ + \n :return \$2;\r\ + \n}\r\ + \n\r\ + \n:set CharacterMultiply do={\r\ + \n :local Str [ :tostr \$1 ];\r\ + \n :local Num [ :tonum \$2 ];\r\ + \n :if (\$Num = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :for I from=1 to=\$Num do={:set Return (\$Return . \$Str)}\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set CharacterReplace do={\r\ + \n :local String [ :tostr \$1 ];\r\ + \n :local ReplaceFrom [ :tostr \$2 ];\r\ + \n :local ReplaceWith [ :tostr \$3 ];\r\ + \n :local Return \"\";\r\ + \n :if (\$ReplaceFrom = \"\") do={:return \$String}\r\ + \n :while ([ :typeof [ :find \$String \$ReplaceFrom ] ] != \"nil\") do={\ + \r\ + \n :local Pos [ :find \$String \$ReplaceFrom ];\r\ + \n :set Return (\$Return . [ :pick \$String 0 \$Pos ] . \$ReplaceWith);\ + \r\ + \n :set String [ :pick \$String (\$Pos + [ :len \$ReplaceFrom ]) [ :len\ + \_\$String ] ];\r\ + \n }\r\ + \n :return (\$Return . \$String);\r\ + \n}\r\ + \n\r\ + \n:set IfThenElse do={\r\ + \n :if ([ :tostr \$1 ] = \"true\" || [ :tobool \$1 ] = true) do={:return \ + \$2};\r\ + \n :return \$3;\r\ + \n}\r\ + \n\r\ + \n:set EitherOr do={\r\ + \n :global IfThenElse;\r\ + \n :if ([ :typeof \$1 ] = \"num\") do={:return [ \$IfThenElse (\$1 != 0) \ + \$1 \$2 ]}\r\ + \n :if ([ :typeof \$1 ] = \"time\") do={:return [ \$IfThenElse (\$1 > 0s)\ + \_\$1 \$2 ]}\r\ + \n# this works for boolean values, literal ones with parentheses\r\ + \n :return [ \$IfThenElse ([ :len [ :tostr \$1 ] ] > 0) \$1 \$2 ];\r\ + \n}\r\ + \n\r\ + \n:set ParseKeyValueStore do={\r\ + \n :local Source \$1;\r\ + \n :if ([ :pick \$Source 0 1 ] = \"{\") do={\r\ + \n :do {\r\ + \n :return [ :deserialize from=json \$Source ];\r\ + \n } on-error={ }\r\ + \n } \r\ + \n :if ([ :typeof \$Source ] != \"array\") do={:set Source [ :tostr \$1 ]\ + }\r\ + \n :local Result ({});\r\ + \n :foreach KeyValue in=[ :toarray \$Source ] do={\r\ + \n :if ([ :find \$KeyValue \"=\" ]) do={\r\ + \n :local Key [ :pick \$KeyValue 0 [ :find \$KeyValue \"=\" ] ];\r\ + \n :local Value [ :pick \$KeyValue ([ :find \$KeyValue \"=\" ] + 1) [\ + \_:len \$KeyValue ] ];\r\ + \n :if (\$Value=\"true\") do={:set Value true}\r\ + \n :if (\$Value=\"false\") do={:set Value false}\r\ + \n :set (\$Result->\$Key) \$Value;\r\ + \n } else={:set (\$Result->\$KeyValue) true}\r\ + \n }\r\ + \n :return \$Result;\r\ + \n}\r\ + \n:set RequiredRouterOS do={\r\ + \n :local Caller [ :tostr \$1 ];\r\ + \n :local Required [ :tostr \$2 ];\r\ + \n :local Warn [ :tostr \$3 ];\r\ + \n :global IfThenElse;\r\ + \n :global VersionToNum;\r\ + \n :if (!(\$Required ~ \"^\\\\d+\\\\.\\\\d+((alpha|beta|rc|\\\\.)\\\\d+|)\ + \\\$\")) do={\r\ + \n :log error (\$0 . \" No valid RouterOS version: \" . \$Required);\r\ + \n :return false;\r\ + \n }\r\ + \n :if ([ \$VersionToNum \$Required ] > [ \$VersionToNum [ /system/packag\ + e/update/get installed-version ] ]) do={\r\ + \n :if (\$Warn = \"true\") do={\r\ + \n :log warning (\$0 . \" This \" . [ \$IfThenElse ([ :pick \$Caller \ + 0 ] = (\"\\\$\")) \"function\" \"script\" ] . \\\r\ + \n \" '\" . \$Caller . \"' (at least specific functionality) requir\ + es RouterOS \" . \$Required . \". Please update!\");\r\ + \n }\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set ValidateSyntax do={\r\ + \n :local Code [ :tostr \$1 ];\r\ + \n :global LogPrint;\r\ + \n :onerror Err {\r\ + \n [ :parse (\":local Validate do={\\n\" . \$Code . \"\\n}\") ];\r\ + \n } do={\r\ + \n \$LogPrint debug \$0 (\"Valdation failed: \" . \$Err);\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set VersionToNum do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :local Multi 0x1000000;\r\ + \n :local Return 0;\r\ + \n :global CharacterReplace;\r\ + \n :set Input [ \$CharacterReplace \$Input \".\" \",\" ];\r\ + \n :foreach I in={ \"zero\"; \"alpha\"; \"beta\"; \"rc\" } do={\r\ + \n :set Input [ \$CharacterReplace \$Input \$I (\",\" . \$I . \",\") ];\ + \r\ + \n }\r\ + \n :foreach Value in=([ :toarray \$Input ], 0) do={\r\ + \n :local Num [ :tonum \$Value ];\r\ + \n :if (\$Multi = 0x100) do={\r\ + \n :if ([ :typeof \$Num ] = \"num\") do={\r\ + \n :set Return (\$Return + 0xff00);\r\ + \n :set Multi (\$Multi / 0x100);\r\ + \n } else={\r\ + \n :if (\$Value = \"zero\") do={ }\r\ + \n :if (\$Value = \"alpha\") do={ :set Return (\$Return + 0x3f00); \ + }\r\ + \n :if (\$Value = \"beta\") do={ :set Return (\$Return + 0x5f00); }\ + \r\ + \n :if (\$Value = \"rc\") do={ :set Return (\$Return + 0x7f00); }\r\ + \n }\r\ + \n }\r\ + \n :if ([ :typeof \$Num ] = \"num\") do={ :set Return (\$Return + (\$Va\ + lue * \$Multi)); }\r\ + \n :set Multi (\$Multi / 0x100);\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set ScriptLock do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local WaitMax [ :totime \$2 ];\r\ + \n :global GetRandom20CharAlNum;\r\ + \n :global IfThenElse;\r\ + \n :global ScriptLockOrder;\r\ + \n :if ([ :typeof \$ScriptLockOrder ] = \"nothing\") do={\r\ + \n :set ScriptLockOrder ({});\r\ + \n }\r\ + \n :if ([ :typeof (\$ScriptLockOrder->\$Script) ] = \"nothing\") do={\r\ + \n :set (\$ScriptLockOrder->\$Script) ({});\r\ + \n }\r\ + \n :local JobCount do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :return [ :len [ /system/script/job/find where script=\$Script ] ];\ + \r\ + \n }\r\ + \n :local TicketCount do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :local Count 0;\r\ + \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :if ([ :typeof \$Ticket ] != \"nothing\") do={:set Count (\$Count \ + + 1)}\r\ + \n }\r\ + \n :return \$Count;\r\ + \n }\r\ + \n :local IsFirstTicket do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local Check [ :tostr \$2 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :if (\$Ticket = \$Check) do={:return true}\r\ + \n :if ([ :typeof \$Ticket ] != \"nothing\" && \$Ticket != \$Check) d\ + o={:return false}\r\ + \n }\r\ + \n :return false;\r\ + \n }\r\ + \n :local AddTicket do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local Add [ :tostr \$2 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :while (true) do={\r\ + \n :local Pos [ :len (\$ScriptLockOrder->\$Script) ];\r\ + \n :set (\$ScriptLockOrder->\$Script->\$Pos) \$Add;\r\ + \n :delay 10ms;\r\ + \n :if ((\$ScriptLockOrder->\$Script->\$Pos) = \$Add) do={:return tru\ + e}\r\ + \n }\r\ + \n }\r\ + \n :local RemoveTicket do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local Remove [ :tostr \$2 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :foreach Id,Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :while ((\$ScriptLockOrder->\$Script->\$Id) = \$Remove) do={\r\ + \n :set (\$ScriptLockOrder->\$Script->\$Id);\r\ + \n :delay 10ms;\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n :local CleanupTickets do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :if ([ :typeof \$Ticket ] != \"nothing\") do={:return false}\r\ + \n }\r\ + \n :set (\$ScriptLockOrder->\$Script) ({});\r\ + \n }\r\ + \n :if ([ :typeof \$WaitMax ] = \"nil\" ) do={:set WaitMax 0s}\r\ + \n :if ([ :len [ /system/script/find where name=\$Script ] ] = 0) do={\r\ + \n :log error (\$0 . \" A script named '\" . \$Script . \"' does not ex\ + ist!\");\r\ + \n :error false;\r\ + \n }\r\ + \n :if ([ \$JobCount \$Script ] = 0) do={\r\ + \n \$LogPrint error \$0 (\"No script '\" . \$Script . \"' is running!\"\ + );\r\ + \n :error false;\r\ + \n }\r\ + \n :if ([ \$TicketCount \$Script ] >= [ \$JobCount \$Script ]) do={\r\ + \n :log error (\$0 . \" More tickets than running scripts '\" . \$Scrip\ + t . \"', resetting!\");\r\ + \n :set (\$ScriptLockOrder->\$Script) ({});\r\ + \n /system/script/job/remove [ find where script=\$Script ];\r\ + \n }\r\ + \n :local MyTicket [ \$GetRandom20CharAlNum 6 ];\r\ + \n \$AddTicket \$Script \$MyTicket;\r\ + \n :local WaitInterval (\$WaitMax / 20);\r\ + \n :local WaitTime \$WaitMax;\r\ + \n :while (\$WaitTime > 0 && \\\r\ + \n ([ \$IsFirstTicket \$Script \$MyTicket ] = false || \\\r\ + \n [ \$TicketCount \$Script ] < [ \$JobCount \$Script ])) do={\r\ + \n :set WaitTime (\$WaitTime - \$WaitInterval);\r\ + \n :delay \$WaitInterval;\r\ + \n }\r\ + \n :if ([ \$IsFirstTicket \$Script \$MyTicket ] = true && \\\r\ + \n [ \$TicketCount \$Script ] = [ \$JobCount \$Script ]) do={\r\ + \n \$RemoveTicket \$Script \$MyTicket;\r\ + \n \$CleanupTickets \$Script;\r\ + \n :return true;\r\ + \n }\r\ + \n \$RemoveTicket \$Script \$MyTicket;\r\ + \n \$LogPrint debug \$0 (\"Script '\" . \$Script . \"' started more than \ + once\" . \\\r\ + \n [ \$IfThenElse (\$WaitTime < \$WaitMax) \" and timed out waiting for\ + \_lock\" \"\" ] . \"...\");\r\ + \n :return false;\r\ + \n}\r\ + \n\r\ + \n:set SendNotification do={ :onerror Err {\r\ + \n :global SendNotification2;\r\ + \n \$SendNotification2 ({ origin=\$0; subject=\$1; message=\$2; link=\$3;\ + \_silent=\$4 });\r\ + \n} do={:global ExitOnError; \$ExitOnError \$0 \$Err}\r\ + \n}\r\ + \n\r\ + \n:set SendNotification2 do={\r\ + \n :local Notification \$1;\r\ + \n :global NotificationFunctions;\r\ + \n :foreach FunctionName,Discard in=\$NotificationFunctions do={\r\ + \n (\$NotificationFunctions->\$FunctionName) (\"\\\$NotificationFunctio\ + ns->\\\"\" . \$FunctionName . \"\\\"\") \$Notification;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set SymbolByUnicodeName do={\r\ + \n :local Name [ :tostr \$1 ];\r\ + \n :global EitherOr;\r\ + \n :global SymbolsExtra;\r\ + \n :local Symbols ({\r\ + \n \"abacus\"=\"\\F0\\9F\\A7\\AE\";\r\ + \n \"alarm-clock\"=\"\\E2\\8F\\B0\";\r\ + \n \"arrow-down\"=\"\\E2\\AC\\87\";\r\ + \n \"arrow-up\"=\"\\E2\\AC\\86\";\r\ + \n \"calendar\"=\"\\F0\\9F\\93\\85\";\r\ + \n \"card-file-box\"=\"\\F0\\9F\\97\\83\";\r\ + \n \"chart-decreasing\"=\"\\F0\\9F\\93\\89\";\r\ + \n \"chart-increasing\"=\"\\F0\\9F\\93\\88\";\r\ + \n \"cloud\"=\"\\E2\\98\\81\";\r\ + \n \"cross-mark\"=\"\\E2\\9D\\8C\";\r\ + \n \"earth\"=\"\\F0\\9F\\8C\\8D\";\r\ + \n \"fire\"=\"\\F0\\9F\\94\\A5\";\r\ + \n \"floppy-disk\"=\"\\F0\\9F\\92\\BE\";\r\ + \n \"gear\"=\"\\E2\\9A\\99\";\r\ + \n \"heart\"=\"\\E2\\99\\A5\";\r\ + \n \"high-voltage-sign\"=\"\\E2\\9A\\A1\";\r\ + \n \"incoming-envelope\"=\"\\F0\\9F\\93\\A8\";\r\ + \n \"information\"=\"\\E2\\84\\B9\";\r\ + \n \"large-orange-circle\"=\"\\F0\\9F\\9F\\A0\";\r\ + \n \"large-red-circle\"=\"\\F0\\9F\\94\\B4\";\r\ + \n \"link\"=\"\\F0\\9F\\94\\97\";\r\ + \n \"lock-with-ink-pen\"=\"\\F0\\9F\\94\\8F\";\r\ + \n \"memo\"=\"\\F0\\9F\\93\\9D\";\r\ + \n \"mobile-phone\"=\"\\F0\\9F\\93\\B1\";\r\ + \n \"pushpin\"=\"\\F0\\9F\\93\\8C\";\r\ + \n \"scissors\"=\"\\E2\\9C\\82\";\r\ + \n \"scroll\"=\"\\F0\\9F\\93\\9C\";\r\ + \n \"smiley-partying-face\"=\"\\F0\\9F\\A5\\B3\";\r\ + \n \"smiley-smiling-face\"=\"\\E2\\98\\BA\";\r\ + \n \"smiley-winking-face-with-tongue\"=\"\\F0\\9F\\98\\9C\";\r\ + \n \"sparkles\"=\"\\E2\\9C\\A8\";\r\ + \n \"speech-balloon\"=\"\\F0\\9F\\92\\AC\";\r\ + \n \"star\"=\"\\E2\\AD\\90\";\r\ + \n \"warning-sign\"=\"\\E2\\9A\\A0\";\r\ + \n \"white-heavy-check-mark\"=\"\\E2\\9C\\85\"\r\ + \n }, \$SymbolsExtra);\r\ + \n :local Magic [ :pick [ /system/clock/get date ] 4 10 ];\r\ + \n :local Special {\r\ + \n \"information-04-01\"=\"\\F0\\9F\\9A\\BB\";\r\ + \n \"large-orange-circle-04-01\"=\"\\F0\\9F\\8D\\8A\";\r\ + \n \"large-orange-circle-10-31\"=\"\\F0\\9F\\8E\\83\";\r\ + \n \"large-red-circle-04-01\"=\"\\F0\\9F\\8D\\92\" };\r\ + \n :if ([ :len (\$Symbols->\$Name) ] = 0) do={\r\ + \n :log warning (\$0 . \"No symbol available for name '\" . \$Name . \"\ + '!\");\r\ + \n :return \"\";\r\ + \n }\r\ + \n :return ([ \$EitherOr (\$Special->(\$Name . \$Magic)) (\$Symbols->\$Na\ + me) ] . \"\\EF\\B8\\8F\");\r\ + \n}\r\ + \n\r\ + \n:set SymbolForNotification do={\r\ + \n :global NotificationsWithSymbols;\r\ + \n :global SymbolByUnicodeName;\r\ + \n :global IfThenElse;\r\ + \n :if (\$NotificationsWithSymbols != true) do={:return [ \$IfThenElse ([\ + \_:len \$2 ] > 0) ([ :tostr \$2 ] . \" \") \"\" ]}\r\ + \n :local Return \"\";\r\ + \n :foreach Symbol in=[ :toarray \$1 ] do={:set Return (\$Return . [ \$Sy\ + mbolByUnicodeName \$Symbol ])}\r\ + \n :return (\$Return . \" \");\r\ + \n}\r\ + \n\r\ + \n:set Unix2Dos do={:return [ :tocrlf [ :tostr \$1 ] ]}\r\ + \n:set UrlEncode do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :if ([ :len \$Input ] = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :local Chars (\"\\n\\r !\\\"#\\\$%&'()*+,:;<=>\?@[\\\\]^`{|}~\");\r\ + \n :local Subs { \"%0A\"; \"%0D\"; \"%20\"; \"%21\"; \"%22\"; \"%23\"; \"\ + %24\"; \"%25\"; \"%26\"; \"%27\";\r\ + \n \"%28\"; \"%29\"; \"%2A\"; \"%2B\"; \"%2C\"; \"%3A\"; \"%3B\"; \ + \"%3C\"; \"%3D\"; \"%3E\"; \"%3F\";\r\ + \n \"%40\"; \"%5B\"; \"%5C\"; \"%5D\"; \"%5E\"; \"%60\"; \"%7B\"; \ + \"%7C\"; \"%7D\"; \"%7E\" };\r\ + \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ + \n :local Char [ :pick \$Input \$I ];\r\ + \n :local Replace [ :find \$Chars \$Char ];\r\ + \n :if ([ :typeof \$Replace ] = \"num\") do={:set Char (\$Subs->\$Repla\ + ce)}\r\ + \n :set Return (\$Return . \$Char);\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set IsDNSResolving do={\r\ + \n :do {:resolve \"api.telegram.org\"} on-error={:return false}\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set IsFullyConnected do={\r\ + \n :global IsDNSResolving;\r\ + \n :global IsTimeSync;\r\ + \n :if ([ \$IsDNSResolving ] = false) do={:return false};\r\ + \n :if ([ \$IsTimeSync ] = false) do={:return false};\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set IsTimeSync do={\r\ + \n :global IsTimeSyncCached;\r\ + \n :global IsTimeSyncResetNtp;\r\ + \n :if (\$IsTimeSyncCached = true) do={:return true}\r\ + \n :if ([ /system/ntp/client/get enabled ] = true) do={\r\ + \n :if ([ /system/ntp/client/get status ] = \"synchronized\") do={\r\ + \n :set IsTimeSyncCached true;\r\ + \n :return true;\r\ + \n }\r\ + \n :local Uptime [ /system/resource/get uptime ];\r\ + \n :if ([ :typeof \$IsTimeSyncResetNtp ] = \"nothing\") do={\r\ + \n :set IsTimeSyncResetNtp \$Uptime;\r\ + \n }\r\ + \n :if (\$Uptime - \$IsTimeSyncResetNtp < 3m) do={:return false}\r\ + \n :log warning \"\$0 The ntp client is configured, but did not sync.\"\ + ;\r\ + \n :set IsTimeSyncResetNtp \$Uptime;\r\ + \n /system/ntp/client/set enabled=no;\r\ + \n :delay 20ms;\r\ + \n /system/ntp/client/set enabled=yes;\r\ + \n :return false;\r\ + \n }\r\ + \n :if ([ /system/license/get ]->\"level\" = \"free\" || \\\r\ + \n [ /system/resource/get ]->\"board-name\" = \"x86\") do={\r\ + \n :log debug \"\$0 No ntp client configured, relying on RTC for CHR fr\ + ee license and x86.\";\r\ + \n :return true;\r\ + \n }\r\ + \n :if ([ /ip/cloud/get update-time ] = true) do={\r\ + \n :if ([ :typeof [ /ip/cloud/get public-address ] ] = \"ip\") do={\r\ + \n :set IsTimeSyncCached true;\r\ + \n :return true;\r\ + \n }\r\ + \n :return false;\r\ + \n }\r\ + \n :log debug \"\$0 No time source configured! Returning gracefully...\";\ + \r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set FetchHugeFiles do={\r\ + \n :local ScriptName [ :tostr \$1 ];\r\ + \n :local Url [ :tostr \$2 ];\r\ + \n :local CheckCert [ :tostr \$3 ];\r\ + \n\r\ + \n :global CleanName;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global GetRandom20CharAlNum;\r\ + \n :global IfThenElse;\r\ + \n :global LogPrint;\r\ + \n :global MkDir;\r\ + \n :global RmDir;\r\ + \n :global RmFile;\r\ + \n :global WaitForFile;\r\ + \n\r\ + \n :set CheckCert [ \$IfThenElse (\$CheckCert = \"false\") \"no\" \"yes-w\ + ithout-crl\" ];\r\ + \n\r\ + \n :local DirName (\"tmpfs/\" . [ \$CleanName \$ScriptName ]);\r\ + \n :if ([ \$MkDir \$DirName ] = false) do={\r\ + \n \$LogPrint error \$0 (\"Failed creating directory!\");\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :local FileName (\$DirName . \"/\" . [ \$CleanName \$0 ] . \"-\" . [ \ + \$GetRandom20CharAlNum ]);\r\ + \n :onerror Err {\r\ + \n /tool/fetch check-certificate=\$CheckCert \$Url dst-path=\$FileName \ + \\\r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$ScriptName ] }) as-va\ + lue;\r\ + \n } do={\r\ + \n :if ([ \$WaitForFile \$FileName 500ms ] = true) do={\r\ + \n \$RmFile \$FileName;\r\ + \n }\r\ + \n \$LogPrint debug \$0 (\"Failed downloading from \" . \$Url . \" - \"\ + \_. \$Err);\r\ + \n \$RmDir \$DirName;\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :if ([ \$WaitForFile \$FileName 5s ] = false) do={\r\ + \n \$LogPrint debug \$0 (\"The file downloaded from \" . \$Url . \" did\ + \_not show up.\");\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :local FileSize [ /file/get \$FileName size ];\r\ + \n :local Return \"\";\r\ + \n :local VarSize 0;\r\ + \n :while (\$VarSize != \$FileSize) do={\r\ + \n :set Return (\$Return . ([ /file/read offset=\$VarSize chunk-size=32\ + 768 file=\$FileName as-value ]->\"data\"));\r\ + \n :set FileSize [ /file/get \$FileName size ];\r\ + \n :set VarSize [ :len \$Return ];\r\ + \n :if (\$VarSize > \$FileSize) do={\r\ + \n :delay 100ms;\r\ + \n }\r\ + \n }\r\ + \n \$RmDir \$DirName;\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set FetchUserAgentStr do={\r\ + \n :local Caller [ :tostr \$1 ];\r\ + \n :global GlobalScriptsUrl;\r\ + \n :global CommitBrief;\r\ + \n :global IfThenElse;\r\ + \n :local Resource [ /system/resource/get ];\r\ + \n :return (\"User-Agent: Mikrotik/\" . \$Resource->\"version\" . \" \" .\ + \_\$Resource->\"architecture-name\" . \\\r\ + \n \" \" . \$Caller . \"/Fetch (\" . \$GlobalScriptsUrl . \"; \" . [ \$\ + CommitBrief ] . \")\");\r\ + \n}\r\ + \n\r\ + \n:set ScriptInstallUpdate do={ :onerror Err {\r\ + \n :local Scripts [ :toarray \$1 ];\r\ + \n :local NewComment [ :tostr \$2 ];\r\ + \n :global InitSetup;\r\ + \n\r\ + \n :global CommitId;\r\ + \n :global ScriptUpdatesCRLF;\r\ + \n :global GlobalConfVersion;\r\ + \n :global Identity;\r\ + \n :global CertificateAvailable;\r\ + \n :global CheckSumsVerify;\r\ + \n :global GlobalScriptsUrl;\r\ + \n :global SumsDirAndFileName;\r\ + \n :global GlobalScriptsUrlSuffix;\r\ + \n :global EitherOr;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global Grep;\r\ + \n :global IfThenElse;\r\ + \n :global LogPrint;\r\ + \n :global ParseKeyValueStore;\r\ + \n :global RequiredRouterOS;\r\ + \n :global SendNotification2;\r\ + \n :global SymbolForNotification;\r\ + \n :global ValidateSyntax;\r\ + \n :global CommentsInScripts;\r\ + \n\r\ + \n :if ([ \$CertificateAvailable \"Root YE\" \"fetch\" ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Downloading certificate failed, trying wit\ + hout.\");\r\ + \n }\r\ + \n\r\ + \n :foreach Script in=\$Scripts do={\r\ + \n :if ([ :len [ /system/script/find where name=\$Script ] ] = 0) do={\ + \r\ + \n \$LogPrint info \$0 (\"Adding new script: \" . \$Script);\r\ + \n /system/script/add name=\$Script owner=\$Script source=\"#!rsc by \ + Vados\\n\" comment=\$NewComment;\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :local CommitIdBefore \$CommitId;\r\ + \n :local GlobalConfVersionBefore \$GlobalConfVersion;\r\ + \n :local ReloadGlobal false;\r\ + \n :local DeviceMode [ /system/device-mode/get ];\r\ + \n\r\ + \n :if (\$CheckSumsVerify = true) do={\r\ + \n :local CheckSums ({});\r\ + \n :do {\r\ + \n :local Url (\$GlobalScriptsUrl . \$SumsDirAndFileName . \$GlobalScr\ + iptsUrlSuffix);\r\ + \n \$LogPrint debug \$0 (\"Fetching checksums from url: \" . \$Url);\ + \r\ + \n :set CheckSums [ :deserialize from=json ([ /tool/fetch check-certi\ + ficate=yes-without-crl \\\r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$0 ] }) \$Url output\ + =user as-value ]->\"data\") ];\r\ + \n } on-error={ \$LogPrint warning \$0 (\"Err = \" . \$Err); }\r\ + \n }\r\ + \n\r\ + \n :foreach Script in=[ /system/script/find where source~\"^#!rsc by Vado\ + s\" ] do={\r\ + \n :local ScriptVal [ /system/script/get \$Script ];\r\ + \n :local ScriptInfo [ \$ParseKeyValueStore (\$ScriptVal->\"comment\") \ + ];\r\ + \n :local SourceNew;\r\ + \n\r\ + \n :foreach Scheduler in=[ /system/scheduler/find where on-event~(\"\\\ + \\b\" . \$ScriptVal->\"name\" . \"\\\\b\") ] do={\r\ + \n :local SchedulerVal [ /system/scheduler/get \$Scheduler ];\r\ + \n :if (\$ScriptVal->\"policy\" != \$SchedulerVal->\"policy\") do={\r\ + \n \$LogPrint warning \$0 (\"Policies differ for script '\" . \$Scr\ + iptVal->\"name\" . \"' and its scheduler '\" . \$SchedulerVal->\"name\" . \ + \"'!\");\r\ + \n }\r\ + \n }\r\ + \n :do {\r\ + \n :if (\$ScriptInfo->\"ignore\" = true) do={\r\ + \n \$LogPrint debug \$0 (\"Ignoring script '\" . \$ScriptVal->\"nam\ + e\" . \"', as requested.\");\r\ + \n :error true;\r\ + \n }\r\ + \n :if (\$CheckSumsVerify = true) do={\r\ + \n :local CheckSum (\$CheckSums->(\$ScriptVal->\"name\"));\r\ + \n :if ([ :len (\$ScriptInfo->\"base-url\") ] = 0 && [ :len (\$Scri\ + ptInfo->\"url-suffix\") ] = 0 && \\\r\ + \n [ :convert transform=md5 to=hex [ :tolf (\$ScriptVal->\"sou\ + rce\") ] ] = \$CheckSum) do={\r\ + \n \$LogPrint debug \$0 (\"Checksum for script '\" . \$ScriptVal-\ + >\"name\" . \"' matches, ignoring.\");\r\ + \n :error true;\r\ + \n }\r\ + \n }\r\ + \n :if ([ :len (\$ScriptInfo->\"certificate\") ] > 0) do={\r\ + \n :if ([ \$CertificateAvailable (\$ScriptInfo->\"certificate\") \"\ + fetch\" ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Downloading certificate failed, tryi\ + ng without.\");\r\ + \n }\r\ + \n }\r\ + \n :onerror Err {\r\ + \n :local BaseUrl [ \$EitherOr (\$ScriptInfo->\"base-url\") \$Globa\ + lScriptsUrl ];\r\ + \n :local UrlSuffix [ \$EitherOr (\$ScriptInfo->\"url-suffix\") \$G\ + lobalScriptsUrlSuffix ];\r\ + \n :local Url (\$BaseUrl . \$ScriptVal->\"name\" . \".rsc\" . \$Url\ + Suffix);\r\ + \n \$LogPrint warning \$0 (\"Fetching script '\" . (\$ScriptVal->\"\ + name\") . \"' from url: \" . \$Url);\r\ + \n :local Result [ /tool/fetch check-certificate=yes-without-crl \\\ + \r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$0 ] }) \$Url outp\ + ut=user as-value ];\r\ + \n :if (\$Result->\"status\" = \"finished\") do={\r\ + \n :set SourceNew [ :tolf (\$Result->\"data\") ];\r\ + \n } \r\ + \n } do={\r\ + \n \$LogPrint warning \$0 (\"Failed fetching script '\" . \$ScriptV\ + al->\"name\" . \"': \" . \$Err);\r\ + \n :if (\$Err != \"Fetch failed with status 404\") do={\r\ + \n :error false;\r\ + \n }\r\ + \n :if (\$ScriptVal->\"source\" = \"#!rsc by Vados\") do={\r\ + \n \$LogPrint warning \$0 (\"Removing dummy. Typo on installation\ + \?\");\r\ + \n /system/script/remove \$Script;\r\ + \n :error false;\r\ + \n }\r\ + \n :if (\$CheckSumsVerify = true) do={\r\ + \n :if ([ :len (\$ScriptInfo->\"base-url\") ] = 0 && [ :len (\$Sc\ + riptInfo->\"url-suffix\") ] = 0 && \\\r\ + \n [ :len \$CheckSum ] = 0) do={\r\ + \n \$LogPrint warning \$0 (\"Added the script manually\? Skip u\ + pdates with 'ignore=true' in comment.\");\r\ + \n }\r\ + \n }\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :if ([ :len \$SourceNew ] = 0) do={\r\ + \n \$LogPrint debug \$0 (\"No update for script '\" . (\$ScriptVal-\ + >\"name\") . \"'.\");\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :local SourceCRLF [ :tocrlf \$SourceNew ];\r\ + \n :if (\$InitSetup != true && ((\$ScriptVal->\"name\") != \"AM-Globa\ + lConfig\" || (\$ScriptVal->\"name\") != \"AM-GlobalFunc\")) do={\r\ + \n :if (\$SourceNew = (\$ScriptVal->\"source\") || \$SourceCRLF = (\ + \$ScriptVal->\"source\")) do={\r\ + \n \$LogPrint debug \$0 (\"Script '\" . (\$ScriptVal->\"name\") \ + . \"' source did not change. End of lines set to CRLF.\");\r\ + \n if (\$ScriptUpdatesCRLF = false) do={\r\ + \n :put [ :tolf \$SourceNew ];\r\ + \n \$LogPrint debug \$0 (\"Script '\" . (\$ScriptVal->\"name\"\ + ) . \"' source update end of lines to LF.\");\r\ + \n }\r\ + \n :error false;\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :if ([ :pick \$SourceNew 0 14 ] != \"#!rsc by Vados\") do={\r\ + \n \$LogPrint warning \$0 (\"Looks like new script '\" . \$ScriptVa\ + l->\"name\" . \"' is not valid (missing shebang = '\$shebang') Ignoring!\"\ + );\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :if (\$CommentsInScripts = true) do={\r\ + \n :local CommentLine [ \$Grep \$SourceNew (\"\\23 Script comment:\ + \_\") ];\r\ + \n :if ([ :len \$CommentLine ] = 0) do={\r\ + \n \$LogPrint debug \$0 (\"The search in new script '\" . (\$Scr\ + iptVal->\"name\") . \"' for comment in script body, is not found result Ig\ + noring!\");\r\ + \n :error false;\r\ + \n } else={\r\ + \n :if ([ :len (\$ScriptVal->\"comment\")] = 0 || [ :len (\$Scri\ + ptVal->\"comment\")] != [ :pick \$CommentLine ([ :find \$CommentLine \":\"\ + ] + 2) [ :len \$CommentLine] ]) do={\r\ + \n \$LogPrint debug \$0 (\"Exsiting comment for script '\" . (\ + \$ScriptVal->\"name\") . \"' is '\" . (\$ScriptVal->\"comment\") . \"'.\")\ + ;\r\ + \n :set (\$ScriptVal->\"comment\") [ :pick \$CommentLine ([ :f\ + ind \$CommentLine \":\"] + 2) [ :len \$CommentLine] ];\r\ + \n \$LogPrint debug \$0 (\"New comment (\" . (\$ScriptVal->\"c\ + omment\") . \") for script '\" . (\$ScriptVal->\"name\") . \"' has been ad\ + ded!\");\r\ + \n } else={\r\ + \n \$LogPrint debug \$0 (\"Comment for script '\" . (\$ScriptV\ + al->\"name\") . \"' did not change.\");\r\ + \n :error false;\r\ + \n }\r\ + \n } \r\ + \n }\r\ + \n\r\ + \n :local RequiredROS ([ \$ParseKeyValueStore [ \$Grep \$SourceNew (\ + \"\\23 requires RouterOS, \") ] ]->version);\r\ + \n :if ([ \$RequiredRouterOS \$0 [ \$EitherOr \$RequiredROS \"0.0\" ]\ + \_false ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"The script '\" . (\$ScriptVal->\"name\ + \") . \"' requires RouterOS \" . \\\r\ + \n \$RequiredROS . \", which is not met by your installation. I\ + gnoring!\");\r\ + \n :error false;\r\ + \n }\r\ + \n :local RequiredDM [ \$ParseKeyValueStore [ \$Grep \$SourceNew (\"\ + \\23 requires device-mode, \") ] ];\r\ + \n :local MissingDM ({});\r\ + \n :foreach Feature,Value in=\$RequiredDM do={\r\ + \n :if ([ :typeof (\$DeviceMode->\$Feature) ] = \"bool\" && (\$Devi\ + ceMode->\$Feature) = false) do={\r\ + \n :set MissingDM (\$MissingDM, \$Feature);\r\ + \n }\r\ + \n }\r\ + \n :if ([ :len \$MissingDM ] > 0) do={\r\ + \n \$LogPrint warning \$0 (\"The script '\" . (\$ScriptVal->\"name\ + \") . \"' requires disabled \" . \\\r\ + \n \"device-mode features (\" . [ :tostr \$MissingDM ] . \"). I\ + gnoring!\");\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :if ([ \$ValidateSyntax \$SourceNew ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Syntax validation for script '\" . (\$\ + ScriptVal->\"name\") . \"' failed! Ignoring!\");\r\ + \n :error false;\r\ + \n }\r\ + \n \r\ + \n :log info (\"Updating script: \" . (\$ScriptVal->\"name\") . \" Sc\ + ript comment: \" . (\$ScriptVal->\"comment\"));\r\ + \n\r\ + \n /system/script/set owner=(\$ScriptVal->\"name\") comment=(\$Script\ + Val->\"comment\") \\\r\ + \n source=[ \$IfThenElse (\$ScriptUpdatesCRLF = true) \$SourceCRL\ + F \$SourceNew ] \$Script;\r\ + \n :if (\$ScriptVal->\"name\" = \"AM-GlobalConfig\" || \\\r\ + \n \$ScriptVal->\"name\" = \"AM-GlobalFunc\" || \\\r\ + \n \$ScriptVal->\"name\" ~ (\"^(AM-GlobalFunc\\\\.d|mod)/.\")) d\ + o={\r\ + \n :set ReloadGlobal true;\r\ + \n }\r\ + \n } on-error={ }\r\ + \n }\r\ + \n :if (\$ReloadGlobal = true) do={\r\ + \n \$LogPrint info \$0 (\"Reloading global configuration and functions.\ + \");\r\ + \n :onerror Err {\r\ + \n :global InitSetup (a);\r\ + \n /system/script {run AM-GlobalConfig; run AM-GlobalFunc;};\r\ + \n } do={\$LogPrint error \$0 (\"Reloading global configuration and fun\ + ctions failed! \" . \$Err)}\r\ + \n }\r\ + \n :if (\$GlobalConfVersionBefore > \$GlobalConfVersion) do={\r\ + \n \$LogPrint warning \$0 (\"The configuration version decreased from \ + \" . \\\r\ + \n \$GlobalConfVersionBefore . \" to \" . \$GlobalConfVersion . \\\r\ + \n \". Installed an older version\?\");\r\ + \n }\r\ + \n :if (\$GlobalConfVersionBefore < \$GlobalConfVersion) do={\r\ + \n :global GlobalConfChanges;\r\ + \n :global GlobalConfMigration;\r\ + \n :local ChangeLogCode;\r\ + \n :if ([ :len \$ChangeLogCode ] > 0) do={\r\ + \n :if ([ \$ValidateSyntax \$ChangeLogCode ] = true) do={\r\ + \n :onerror Err {\r\ + \n [ :parse \$ChangeLogCode ];\r\ + \n } do={\$LogPrint warning \$0 (\"The changelog failed to run: \" \ + . \$Err)}\r\ + \n } else={\$LogPrint warning \$0 (\"The changelog failed syntax vali\ + dation!\")}\r\ + \n }\r\ + \n :if ([ :len \$GlobalConfMigration ] > 0) do={\r\ + \n :for I from=(\$GlobalConfVersionBefore + 1) to=\$GlobalConfVersion\ + \_do={\r\ + \n :local Migration (\$GlobalConfMigration->[ :tostr \$I ]);\r\ + \n :do {\r\ + \n :if ([ :typeof \$Migration ] != \"str\") do={\r\ + \n \$LogPrint debug \$0 (\"Migration code for change \" . \$I .\ + \_\" is not available.\");\r\ + \n :error false;\r\ + \n }\r\ + \n :if ([ \$ValidateSyntax \$Migration ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Migration code for change \" . \$I\ + \_. \" failed syntax validation!\");\r\ + \n :error false}\r\ + \n \$LogPrint info \$0 (\"Applying migration for change \" . \$I \ + . \": \" . \$Migration);\r\ + \n :onerror Err {\r\ + \n [ :parse \$Migration ];\r\ + \n } do={\$LogPrint warning \$0 (\"Migration code for change \" .\ + \_\$I . \" failed to run: \" . \$Err)}\r\ + \n } on-error={ }\r\ + \n }\r\ + \n }\r\ + \n :local NotificationMessage (\"The configuration version on \" . \$Id\ + entity . \" increased \" . \\\r\ + \n \"to \" . \$GlobalConfVersion . \", current configuration may nee\ + d modification. \" . \\\r\ + \n \"Please review and update global-config-overlay, then re-run glo\ + bal-config.\");\r\ + \n \$LogPrint info \$0 (\$NotificationMessage);\r\ + \n :if ([ :len \$GlobalConfChanges ] > 0) do={\r\ + \n :set NotificationMessage (\$NotificationMessage . \"\\n\\nChanges:\ + \");\r\ + \n :for I from=(\$GlobalConfVersionBefore + 1) to=\$GlobalConfVersion\ + \_do={\r\ + \n :local Change (\$GlobalConfChanges->[ :tostr \$I ]);\r\ + \n :set NotificationMessage (\$NotificationMessage . \"\\n \" . \\\ + \r\ + \n [ \$SymbolForNotification \"pushpin\" \"*\" ] . \$Change);\r\ + \n \$LogPrint info \$0 (\"Change \" . \$I . \": \" . \$Change);\r\ + \n }\r\ + \n } else={\r\ + \n :set NotificationMessage (\$NotificationMessage . \"\\n\\nNews and\ + \_changes are not available.\");\r\ + \n\r\ + \n }\r\ + \n\r\ + \n :if ([ :len \$GlobalConfChanges ] > 0) do={ :set GlobalConfChanges; \ + } else={ :global GlobalConfChanges (a); }\r\ + \n :if ([ :len \$GlobalConfMigration ] > 0) do={ :set GlobalConfMigrati\ + on; } else={ :global GlobalConfMigration (a); }\r\ + \n }\r\ + \n} do={\r\ + \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ + \n} }\r\ + \n\r\ + \n# load modules\r\ + \n:foreach Script in=[ /system/script/find where name ~ \"^(global-functio\ + ns\\\\.d|mod)/.\" ] do={\r\ + \n :local ScriptVal [ /system/script/get \$Script ];\r\ + \n :if ([ \$ValidateSyntax (\$ScriptVal->\"source\") ] = true) do={\r\ + \n :onerror Err {\r\ + \n /system/script/run \$Script;\r\ + \n } do={\r\ + \n \$LogPrint error \$0 (\"Module '\" . \$ScriptVal->\"name\" . \"' f\ + ailed to run: \" . \$Err);\r\ + \n }\r\ + \n } else={\r\ + \n \$LogPrint error \$0 (\"Module '\" . \$ScriptVal->\"name\" . \"' fai\ + led syntax validation, skipping.\");\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n# Add and fix global scheduler\r\ + \n:put \"Add or/and fix Global scheduler...\";\r\ + \n:local OnEvent \"/system/script { run AM-GlobalConfig; run AM-GlobalFunc\ + ; }\";\r\ + \n:local Comment \"Every Day Set Global Environment Variables\";\r\ + \n:if ([ :len [ /system/scheduler/find where name=\"AM-SetGlobalEnv\" ] ] \ + = 0) do={\r\ + \n /system/scheduler/add name=\"AM-SetGlobalEnv\" comment=\$Comment on-ev\ + ent=\$OnEvent start-time=startup;\r\ + \n}\r\ + \n:if ([ /system/scheduler/get \"AM-SetGlobalEnv\" comment ] != \$Comment)\ + \_do={\r\ + \n /system/scheduler/set \"AM-SetGlobalEnv\" comment=\$Comment;\r\ + \n}\r\ + \n:if ([ /system/scheduler/get \"AM-SetGlobalEnv\" on-event ] != \$OnEvent\ + ) do={\r\ + \n /system/scheduler/set \"AM-SetGlobalEnv\" on-event=\$OnEvent;\r\ + \n}\r\ + \n# Add Update Script scheduler\r\ + \n:put \"Add or/and fix Update Script scheduler\";\r\ + \n:set OnEvent \":global ScriptInstallUpdate; \\\$ScriptInstallUpdate;\";\ + \r\ + \n:set Comment \"Every Day Check For Update Scripts\";\r\ + \n:if ([ :len [ /system/scheduler/find where name=\"AM-ScriptInstallUpdate\ + \" ] ] = 0) do={\r\ + \n/system/scheduler/add name=\"AM-ScriptInstallUpdate\" comment=\$Comment \ + start-time=startup interval=1d on-event=\$OnEvent;\r\ + \n}\r\ + \n\r\ + \n:onerror Err {\r\ + \n :global GlobalConfReady;\r\ + \n :retry { :if (\$GlobalConfReady != true) do={ :error (\"Global configs\ + \_not ready.\"); }; } delay=100ms max=5;\r\ + \n\r\ + \n:log warning (\"This script \$ScriptName Loaded \" . \\\r\ + \n [ \$IfThenElse (\$CommitId != \"unknown\") ([ \$CommitBrief ] . \" \ + \") ] . \\\r\ + \n \"on \" . \$devBoardName . \"\\nRouterOS: \" . \$devCurVersion . \"\ + \\nArchitecture: \" . \$devCurArch . \"\\nIdentity: \" . \$Identity);\r\ + \n # signal we are ready\r\ + \n:set GlobalFuncReady true;\r\ + \n:set ExitOK true;\r\ + \n\r\ + \n:log info (\$0 . \"Global configs ready!\");\r\ + \n} do={\r\ + \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ + \n}\r\ + \n" +add comment=\ + "Lookup IP addresses for RKN list and add them to firewall address-list" \ + dont-require-permissions=no name=AM-RKN-dnsLookup owner=AM-RKN-dnsLookup \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + source="#!rsc by Vados\r\ + \n# RouterOS script: AM-RKN-dnsLookup\r\ + \n# Script comment: Lookup IP addresses for RKN list and add them to firew\ + all address-list\r\ + \n# Copyright (c) 2007-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version=7.19\r\ + \n# requires device-mode, fetch\r\ + \n#\r\ + \n# Script description: This script is intended to be run periodically, e.\ + g. once a day, to update the IP addresses in the firewall address-list bas\ + ed on the RKN list.\r\ + \n# It resolves the domain names in the RKN list and a\ + dds the corresponding IP addresses to the specified firewall address-list.\ + \r\ + \n# The script also handles CNAME records by following\ + \_them until it finds A records.\r\ + \n# Usage:\r\ + \n# /system/script { run AM-RKN-dnsLookup; }\r\ + \n:local ScriptName [ :jobname ];\r\ + \n\r\ + \n:global dnsLookupReady false;\r\ + \n:if ([:typeof \$dnsLookupReady] != \"boolean\") do={ :set dnsLookupReady\ + \_true; }\r\ + \nwhile (!\$dnsLookupReady) do={ :nothing; }\r\ + \n:set dnsLookupReady false;\r\ + \n\r\ + \n:local arrRKN {\r\ + \n \"telegra.ph\"\r\ + \n \"grani.ru\"\r\ + \n \"xhamster.com\"\r\ + \n \"lostfilm.tv\"\r\ + \n \"rutracker.org\"\r\ + \n \"lurkmore.to\"\r\ + \n \"dou.ua\"\r\ + \n \"youporn.com\"\r\ + \n \"pornolab.net\"\r\ + \n \"crimerussia.com\"\r\ + \n \"telegram.org\"\r\ + \n \"api.telegram.org\"\r\ + \n \"facebook.com\"\r\ + \n \"instagram.com\"\r\ + \n \"x.com\"\r\ + \n \"twitter.com\"\r\ + \n \"youtube.com\"\r\ + \n \"googleapis.com\"\r\ + \n \"youtu.be\"\r\ + \n \"googlevideo.com\"\r\ + \n \"gstatic.com\"\r\ + \n \"googleusercontent.com\"\r\ + \n \"nhacmp3youtube.com\"\r\ + \n \"telegram.me\"\r\ + \n \"t.me\";}\r\ + \n\r\ + \n:local ListRKN \"RKN-dnsLookup\";\r\ + \n:local ListComment (\"ListRKN managed by \" . \$ScriptName);\r\ + \n:foreach aListItem in=[/ip/firewall/address-list find list=\$ListRKN] do\ + ={\r\ + \n /ip firewall address-list remove \$aListItem;\r\ + \n}\r\ + \n:foreach aItem in=\$arrRKN do={\r\ + \n# :do {\r\ + \n :retry delay=500ms max=5 on-error={:log error \"dns resolve fail\ + ure [ \$aItem - resolve ip ]\"} command={:resolve \$aItem}\r\ + \n# } on-error={\r\ + \n# :log error \"dns resolve failure [ \$arItem - resolve ip ]\";\r\ + \n# }\r\ + \n :foreach dnsRecord in=[/ip dns cache all find where (name=\$aItem)] \ + do={\r\ + \n :if ([/ip dns cache all get \$dnsRecord type]=\"A\") do={\r\ + \n :local newAddress [/ip dns cache all get \$dnsRecord data];\ + \r\ + \n :do {\r\ + \n /ip firewall address-list add list=\$ListRKN address=\$newA\ + ddress comment=\$aItem;\r\ + \n :log warning \"Successfully adding ip to list A record: \ + \$dnsRecord, address: \$newAddress domain: \$aItem\";\r\ + \n } on-error={\r\ + \n :log error \"error when adding ip to list A record: \$dn\ + sRecord, address: \$newAddress domain: \$aItem\";\r\ + \n }\r\ + \n }\r\ + \n :if ([/ip dns cache all get \$dnsRecord type]=\"CNAME\") do={\r\ + \n :local cname;\r\ + \n :local nextCname;\r\ + \n :local cnameAddress;\r\ + \n :set cname [/ip dns cache all find where (name=\$aItem && ty\ + pe=\"CNAME\")];\r\ + \n :set nextCname [/ip dns cache all find where (name=[/ip dns \ + cache all get \$cname data] && type=\"CNAME\")];\r\ + \n :while (\$nextCname != \"\") do={\r\ + \n :set cname \$nextCname;\r\ + \n :set nextCname [/ip dns cache all find where (name=[/ip \ + dns cache all get \$cname data] && type=\"CNAME\")];\r\ + \n }\r\ + \n :foreach aRecord in=[/ip dns cache all find where (name=[/ip\ + \_dns cache all get \$cname data] && type=\"A\")] do={\r\ + \n :do {\r\ + \n :set cnameAddress [/ip dns cache all get \$aRecord d\ + ata];\r\ + \n /ip firewall address-list add list=\$ListRKN address\ + =\$cnameAddress comment=\$aItem;\r\ + \n :log warning \"Succesfully adding ip to list CNAME r\ + ecord: \$cname, A record: \$aRecord, address: \$newAddress, from domain: \ + \$aItem.\";\r\ + \n# /ip firewall raw add action=add-dst-to-address-list\ + \_address-list=\$ListRKN address-list-timeout=none-dynamic chain=preroutin\ + g comment=\$aItem content=\$aItem;\r\ + \n } on-error={\r\ + \n :log error \"error when adding ip to list CNAME reco\ + rd: \$cname, A record: \$aRecord, address: \$newAddress, from domain: \$aI\ + tem.\";\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:if ([ :len [ /system/scheduler/find where name=\$ScriptName ] ] = 0) do\ + ={\r\ + \n :log error (\$ScriptName . \"System Scheduler for script: \" . \$Scri\ + ptName . \" is NOT SET! Fix It Now!\");\r\ + \n /system/scheduler/add name=\$ScriptName on-event=\"/system/script { \ + run \$ScriptName; }\" comment=\"Update RKN DNS Looup\" interval=00:30:00 p\ + olicy=\"ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon\"\ + \_start-time=startup;\r\ + \n }\r\ + \n:set dnsLookupReady true;\r\ + \ndelay 2s; \r\ + \n:global dnsLookupReady (a);\r\ + \n" +add dont-require-permissions=no name="renameLists " owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + local oldName \"Test\";\ + \n:local newName \"Test-IP\";\ + \n/ip firewall address-list\ + \n:foreach i in=[find list=\$oldName] do={\ + \nset \$i list=\$newName;\ + \n}\ + \n" +add dont-require-permissions=no name=IPv6-Settings owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + #############Script Settings##################\ + \n\ + \n:local \"IF-TUN\" \"6to4-tun\"\ + \n:local \"IF-LOC\" \"Bridge-LAN\"\ + \n:local \"POOL-6TO4\" \"poolV6-local\"\ + \n:local \"force-update\" false\ + \n############ use then static ip #######################\ + \n:local \"lease-address\" [/ip address get [find interface=\$\"IF-LOC\"] \ + address]\ + \n#:local \"interface\" \"ext\"\ + \n:local bound 0\ + \n\ + \n###############################################\ + \n\ + \n:local 6to4prefix do={\ + \n :global dec2hex\ + \n :local ipv4 \$1\ + \n :local ipv6 \"2002:\"\ + \n :for i from=0 to=2 step=1 do={ \ + \n :if ( \$i = 2) do={\ + \n :set ipv6 (\$ipv6.\":\")\ + \n }\ + \n :local fp [:find \$ipv4 \".\"]\ + \n :if ( \$fp > 0 ) do={\ + \n :set ipv6 (\$ipv6.[\$dec2hex [:pick \$ipv4 0 \$fp]])\ + \n :set ipv4 [:pick \$ipv4 (\$fp + 1 ) [:len \$ipv4]]\ + \n }\ + \n }\ + \n :return (\$ipv6.[\$dec2hex \$ipv4])\ + \n}\ + \n:local \"str_replace\" do={\ + \n :local \"str-pos\" [:find \$1 \$2]\ + \n :local \"str-len\" [:len \$2]\ + \n :local str \"\"\ + \n :local rest \$1\ + \n :while (\$\"str-pos\" >= 0) do={\ + \n :local t [:pick \$rest 0 \$\"str-pos\"]\ + \n :if ( \$4 > 0 ) do={\ + \n :for i from=1 to=(\$4 - [:len \$t]) step=1 do={\ + \n :set str (\$str.\$5)\ + \n }\ + \n }\ + \n :set str (\$str.\$t.\$3)\ + \n :set rest [:pick \$rest (\$\"str-pos\"+\$\"str-len\") [:len \$re\ + st]]\ + \n :set \"str-pos\" [:find \$rest \$2]\ + \n }\ + \n :return (\$str.\$rest)\ + \n}\ + \n\ + \n:if (\$bound=1) do={\ + \n :local t [:find \$\"lease-address\" \"/\"]\ + \n\ + \n :if ( \$t >= 0 ) do={\ + \n :set \"lease-address\" [:pick \$\"lease-address\" 0 \$t]\ + \n }\ + \n\ + \n :if ( [/interface 6to4 print count-only where name=\$\"IF-TUN\"] = 0\ + ) do={\ + \n /interface 6to4 add !keepalive local-address=\$\"lease-address\"\ + \_mtu=1280 name=\$\"IF-TUN\" remote-address=10.30.30.0\ + \n :set \"force-update\" true\ + \n }\ + \n\ + \n :local \"IPv4-TUN\" [/interface 6to4 get [find name=\$\"IF-TUN\"] lo\ + cal-address];\ + \n\ + \n :if ( \$\"lease-address\" != \$\"IPv4-TUN\" || \$\"force-update\" = \ + true) do={\ + \n /interface 6to4 set [find name=\$\"IF-TUN\"] local-address=\$\"l\ + ease-address\"\ + \n /ipv6 address remove [find interface=\$\"IF-TUN\"]\ + \n /ipv6 address remove [find interface=\$\"IF-LOC\"]\ + \n /ipv6 route remove [find gateway ~ \$\"IF-TUN\" and dst-address=\ + \"::/0\"]\ + \n :local \"pool-prefix\" [\$6to4prefix \$\"lease-address\"]\ + \n :if ( [/ipv6 pool print count-only where name=\$\"POOL-6TO4\"] =\ + \_0) do={ \ + \n /ipv6 pool add name=\$\"POOL-6TO4\" prefix=(\$\"pool-prefix\ + \".\":1::/64\") prefix-length=64\ + \n } else={\ + \n /ipv6 pool set [/ipv6 pool find where name=\$\"POOL-6TO4\"] \ + prefix=(\$\"pool-prefix\".\":1::/64\")\ + \n }\ + \n /ipv6 address add address=(\$\"pool-prefix\".\"::\".[\$MAC2EUI64\ + \_[/interface get [find name=\$\"interface\"] mac-address]].\"/3\") interf\ + ace=\$\"IF-TUN\" advertise=no\ + \n /ipv6 address add eui-64=yes from-pool=\$\"POOL-6TO4\" interface\ + =\$\"IF-LOC\" advertise=yes\ + \n /ipv6 route add dst-address=::/0 gateway=(\"::10.30.30.81%\".\$\ + \"IF-TUN\")\ + \n :local t [/ipv6 address get [find interface=\$\"IF-LOC\"] addres\ + s]\ + \n :set t [:pick \$t 0 [:find \$t \"/\"]]\ + \n :if ( [/ipv6 dhcp-server option print count-only where name=DNS]\ + \_= 0) do={\ + \n /ipv6 dhcp-server option add code=23 name=DNS value=(\"0x\".\ + [\$\"str_replace\" \$t \":\" \"\" 4 \"0\"])\ + \n } else={\ + \n /ipv6 dhcp-server option set [/ipv6 dhcp-server option find \ + where name=DNS] value=(\"0x\".[\$\"str_replace\" \$t \":\" \"\" 4 \"0\"])\ + \n }\ + \n :if ( [/ipv6 dhcp-server print count-only where interface=\$\"IF\ + -LOC\"] = 0) do={\ + \n /ipv6 dhcp-server add address-pool=\$\"POOL-6TO4\" dhcp-opti\ + on=DNS interface=\$\"IF-LOC\" lease-time=1d name=\$\"IF-LOC\"\ + \n }\ + \n :if ( [ipv6 nd print count-only where interface=\$\"IF-LOC\"] = \ + 0) do={\ + \n /ipv6 nd add advertise-dns=no interface=\$\"IF-LOC\" other-c\ + onfiguration=yes\ + \n }\ + \n }\ + \n}" +add dont-require-permissions=no name=IPv6-GlobalFunc owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + global MAC2EUI64 do={\ + \n :local EUI64 \"\"\ + \n :local MAC \$1\ + \n :local HEX2DEC \"0123456789ABCDEF\"\ + \n :for i from=0 to=5 step=1 do={\ + \n :if ( \$i = 0 ) do={\ + \n :set EUI64 [:pick \$MAC 0]\ + \n :set EUI64 (\$EUI64.[:tostr [:pick \$\"HEX2DEC\" ([:find \$\ + \"HEX2DEC\" [:pick \$MAC 1]] ^ 2)]])\ + \n }\ + \n :if ( \$i = 1 || \$i = 3) do={\ + \n :set EUI64 (\$EUI64.\":\")\ + \n }\ + \n :if ( \$i = 2 ) do={\ + \n :set EUI64 (\$EUI64.\"FF:FE\")\ + \n }\ + \n :if ( [:find \$MAC \":\"] = 2 ) do={\ + \n :set MAC [:pick \$MAC 3 [:len \$MAC]]\ + \n :set EUI64 (\$EUI64.[:pick \$MAC 0 2])\ + \n }\ + \n }\ + \n :return (\$EUI64)\ + \n}\ + \n\ + \n:global dec2hex do={\ + \n :local hex \"\"\ + \n :local dec [:tonum \$1]\ + \n :for i from=0 to=4 step=4 do={\ + \n :set hex ([:pick \"0123456789ABCDEF\" ((\$dec>>\$i)&0xf) (((\$de\ + c>>\$i)&0xf)+1)].\$hex)\ + \n }\ + \n :return ([:tostr \$hex])\ + \n}" +/user group +add name=backup policy="ssh,read,write,policy,test,web,sniff,sensitive,api,res\ + t-api,!local,!telnet,!ftp,!reboot,!winbox,!password,!romon" +/ip smb +set enabled=no interfaces=lo +/interface bridge port +add bridge=Bridge-LAN interface=ether5 +add bridge=Bridge-LAN interface=ether2 +add bridge=Bridge-LAN interface=ether4 trusted=yes +add bridge=Bridge-LAN interface=ether3 +add bridge=Bridge-LAN interface=wlan2 +add bridge=Bridge-LAN interface=wlan1 +/interface bridge settings +# ipv6 neighbor configuration has changed, please restart the device in order to apply the new settings +set use-ip-firewall=yes +/ip firewall connection tracking +# ipv6 neighbor configuration has changed, please restart the device in order to apply the new settings +set udp-timeout=10s +/ip neighbor discovery-settings +# ipv6 neighbor configuration has changed, please restart the device in order to apply the new settings +set discover-interface-list=LAN lldp-med=no lldp-poe-power=no +/ip settings +# ipv6 neighbor configuration has changed, please restart the device in order to apply the new settings +set accept-redirects=yes ipv4-multipath-hash-policy=l4 max-neighbor-entries=\ + 8192 +/ipv6 settings +# ipv6 neighbor configuration has changed, please restart the device in order to apply the new settings +set disable-ipv6=yes disable-link-local-address=yes forward=no \ + max-neighbor-entries=8192 multipath-hash-policy=l4 +/interface detect-internet +set detect-interface-list=static internet-interface-list=Internet \ + lan-interface-list=LAN request-interval=1m wan-interface-list=WAN +/interface l2tp-server server +set authentication=mschap2 use-ipsec=yes +/interface list member +add interface=Bridge-LAN list=LAN +add interface="ether1 - Unet" list=Internet +add interface=WG 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=" +/interface wireless cap +# +set bridge=Bridge-LAN caps-man-addresses=10.30.30.10 \ + caps-man-certificate-common-names=CAPsMAN-51B25E507D07 certificate=\ + CAP-488F5A8E1ABC discovery-interfaces=Bridge-LAN enabled=yes interfaces=\ + wlan2,wlan1 lock-to-caps-man=yes +/ip address +add address=10.30.30.81/24 interface=Bridge-LAN network=10.30.30.0 +add address=10.8.0.2/24 disabled=yes interface=WG network=10.8.0.0 +/ip cloud +set update-time=no +/ip dhcp-client +add add-default-route=special-classless default-route-distance=2 \ + default-route-tables=main:2 dhcp-options=clientid,clientid_duid \ + interface="ether1 - Unet" name=client1 use-peer-dns=no use-peer-ntp=no +/ip dhcp-server config +set accounting=no +/ip dhcp-server lease +add address=10.30.30.101 client-id=1:48:8f:5a:8e:ee:a8 mac-address=\ + 48:8F:5A:8E:EE:A8 server=masterDHCP +add address=10.30.30.107 client-id=1:f0:de:f1:91:d:1e mac-address=\ + F0:DE:F1:91:0D:1E server=masterDHCP +add address=10.30.30.83 client-id=1:0:80:77:ec:43:86 mac-address=\ + 00:80:77:EC:43:86 server=masterDHCP +add address=10.30.30.70 dhcp-option=domain-search-list,HostName \ + dhcp-option-set=HP1505n mac-address=00:1E:0B:1A:88:8D server=masterDHCP +add address=10.30.30.50 client-id=1:4:7c:16:36:f5:37 mac-address=\ + 04:7C:16:36:F5:37 server=masterDHCP +add address=10.30.30.71 client-id=1:10:2d:41:2c:20:c2 mac-address=\ + 10:2D:41:2C:20:C2 server=masterDHCP +add address=10.30.30.61 client-id=1:10:8:c1:81:59:5f mac-address=\ + 10:08:C1:81:59:5F server=masterDHCP +add address=10.30.30.72 client-id=1:10:38:1f:d2:5f:13 mac-address=\ + 10:38:1F:D2:5F:13 server=masterDHCP +add address=10.30.30.99 client-id=1:10:b1:df:e9:d0:d5 mac-address=\ + 10:B1:DF:E9:D0:D5 server=masterDHCP +add address=10.30.30.111 client-id=1:fe:2:52:be:3f:16 mac-address=\ + FE:02:52:BE:3F:16 server=masterDHCP +add address=10.30.30.92 client-id=1:d4:6d:6d:fd:e5:49 mac-address=\ + D4:6D:6D:FD:E5:49 server=masterDHCP +add address=10.30.30.93 client-id=1:7e:8b:1e:cb:b8:cb mac-address=\ + CC:42:10:12:46:94 server=masterDHCP +add address=10.30.30.94 client-id=1:50:cc:f8:85:96:a mac-address=\ + 50:CC:F8:85:96:0A server=masterDHCP +add address=10.30.30.82 client-id=1:e4:18:6b:58:34:ab mac-address=\ + E4:18:6B:58:34:AB server=masterDHCP +add address=10.30.30.75 client-id=1:0:27:15:41:97:a9 mac-address=\ + 00:27:15:41:97:A9 server=masterDHCP +add address=10.30.30.77 dhcp-option=HostName dhcp-option-set=StartLife1 \ + mac-address=C4:82:E1:03:49:10 server=masterDHCP +add address=10.30.30.73 client-id=1:10:38:1f:82:81:f2 mac-address=\ + 10:38:1F:82:81:F2 server=masterDHCP +add address=10.30.30.95 client-id=1:88:ae:dd:60:39:54 dhcp-option=HostName \ + dhcp-option-set=VADOS-NUC mac-address=88:AE:DD:60:39:54 server=masterDHCP +add address=10.30.30.98 client-id=1:c8:5b:76:d8:cc:bf dhcp-option=HostName \ + dhcp-option-set=VADOS-LEN mac-address=C8:5B:76:D8:CC:BF server=masterDHCP +add address=10.30.30.96 client-id=iPhone mac-address=4A:91:ED:0E:1F:39 \ + server=masterDHCP +add address=10.30.30.74 client-id=MiTV dhcp-option=HostName dhcp-option-set=\ + MiTV mac-address=20:72:A9:D3:34:36 server=masterDHCP +add address=10.30.30.30 dhcp-option=HostName dhcp-option-set=miller \ + mac-address=F0:75:5D:1E:5F:71 server=masterDHCP +add address=10.30.30.100 client-id=iVados dhcp-option=HostName \ + dhcp-option-set=iVados mac-address=DE:4D:72:F3:1A:9F server=masterDHCP +/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.81 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=1.0.0.1,8.8.4.4 verify-doh-cert=yes +/ip dns static +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 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 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 name=MikroYellow type=A +add address=10.30.30.85 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 name=garage type=A +/ip firewall address-list +add address=91.215.120.206 list=TRUSTED +add address=185.71.70.78 disabled=yes list=TRUSTED +add address=176.53.203.171 disabled=yes list=TRUSTED +add address=176.53.203.170 disabled=yes list=TRUSTED +add address=176.53.202.194 disabled=yes list=TRUSTED +add address=8.8.4.0/24 list=YouTube +add address=8.8.8.0/24 list=YouTube +add address=8.34.208.0/20 list=YouTube +add address=8.35.192.0/20 list=YouTube +add address=23.236.48.0/20 list=YouTube +add address=23.251.128.0/19 list=YouTube +add address=34.0.0.0/15 list=YouTube +add address=34.2.0.0/16 list=YouTube +add address=34.3.0.0/23 list=YouTube +add address=34.3.3.0/24 list=YouTube +add address=34.3.4.0/24 list=YouTube +add address=34.3.8.0/21 list=YouTube +add address=34.3.16.0/20 list=YouTube +add address=34.3.32.0/19 list=YouTube +add address=34.3.64.0/18 list=YouTube +add address=34.4.0.0/14 list=YouTube +add address=34.8.0.0/13 list=YouTube +add address=34.16.0.0/12 list=YouTube +add address=34.32.0.0/11 list=YouTube +add address=34.64.0.0/10 list=YouTube +add address=34.128.0.0/10 list=YouTube +add address=35.184.0.0/13 list=YouTube +add address=35.192.0.0/14 list=YouTube +add address=35.196.0.0/15 list=YouTube +add address=35.198.0.0/16 list=YouTube +add address=35.199.0.0/17 list=YouTube +add address=35.199.128.0/18 list=YouTube +add address=35.200.0.0/13 list=YouTube +add address=35.208.0.0/12 list=YouTube +add address=35.224.0.0/12 list=YouTube +add address=35.240.0.0/13 list=YouTube +add address=57.140.192.0/18 list=YouTube +add address=64.15.112.0/20 list=YouTube +add address=64.233.160.0/19 list=YouTube +add address=66.22.228.0/23 list=YouTube +add address=66.102.0.0/20 list=YouTube +add address=66.249.64.0/19 list=YouTube +add address=70.32.128.0/19 list=YouTube +add address=72.14.192.0/18 list=YouTube +add address=74.125.0.0/16 list=YouTube +add address=104.154.0.0/15 list=YouTube +add address=104.196.0.0/14 list=YouTube +add address=104.237.160.0/19 list=YouTube +add address=107.167.160.0/19 list=YouTube +add address=107.178.192.0/18 list=YouTube +add address=108.59.80.0/20 list=YouTube +add address=108.170.192.0/18 list=YouTube +add address=108.177.0.0/17 list=YouTube +add address=130.211.0.0/16 list=YouTube +add address=136.22.160.0/20 list=YouTube +add address=136.22.176.0/21 list=YouTube +add address=136.22.184.0/23 list=YouTube +add address=136.22.186.0/24 list=YouTube +add address=142.250.0.0/15 list=YouTube +add address=146.148.0.0/17 list=YouTube +add address=152.65.208.0/22 list=YouTube +add address=152.65.214.0/23 list=YouTube +add address=152.65.218.0/23 list=YouTube +add address=152.65.222.0/23 list=YouTube +add address=152.65.224.0/19 list=YouTube +add address=162.120.128.0/17 list=YouTube +add address=162.216.148.0/22 list=YouTube +add address=162.222.176.0/21 list=YouTube +add address=172.110.32.0/21 list=YouTube +add address=172.217.0.0/16 list=YouTube +add address=172.253.0.0/16 list=YouTube +add address=173.194.0.0/16 list=YouTube +add address=173.255.112.0/20 list=YouTube +add address=192.158.28.0/22 list=YouTube +add address=192.178.0.0/15 list=YouTube +add address=193.186.4.0/24 list=YouTube +add address=199.36.154.0/23 list=YouTube +add address=199.36.156.0/24 list=YouTube +add address=199.192.112.0/22 list=YouTube +add address=199.223.232.0/21 list=YouTube +add address=207.223.160.0/20 list=YouTube +add address=208.65.152.0/22 list=YouTube +add address=208.68.108.0/22 list=YouTube +add address=208.81.188.0/22 list=YouTube +add address=208.117.224.0/19 list=YouTube +add address=209.85.128.0/17 list=YouTube +add address=216.58.192.0/19 list=YouTube +add address=216.73.80.0/20 list=YouTube +add address=216.239.32.0/19 list=YouTube +add address=2ip.ru list=Test-IP +add address=wg.vados.ru comment=VDSIna list=TRUSTED +add address=10.8.0.0/24 comment="WG VDSIna" disabled=yes list=TRUSTED +add address=ikus.pesc.ru comment=ikus.pesc.ru list=NoVdsina +add address=love.ru comment=love.ru list=NoVdsina +add address=gosuslugi.ru comment=gosuslugi.ru list=NoVdsina +add address=pochta.ru comment=pochta.ru list=NoVdsina +add address=vdsina.com list=NoVdsina +add address=vdsina.ru list=NoVdsina +add address=youla.ru list=NoVdsina +add address=kupiprodai.ru list=NoVdsina +add address=myip.ru list=Test-IP +add address=geoip.co list=NoVdsina +add address=comp-lenta.ru list=NoVdsina +add address=128.85.102.70 comment=update.microsoft.com list=\ + windowsupdateslist +add address=wu-b-net.trafficmanager.net. comment=\ + ctldl.windowsupdate.com.delivery.microsoft.com list=windowsupdateslist +add address=ctldl.windowsupdate.com.delivery.microsoft.com. comment=\ + ctldl.windowsupdate.com list=windowsupdateslist +add address=redir.update.msft.com.trafficmanager.net. comment=\ + update.microsoft.com list=windowsupdateslist +add address=geo.prod.do.dsp.trafficmanager.net. comment=\ + geo.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=13.74.139.29 comment=array605.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=kv801.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + kv801.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=e12437.d.akamaiedge.net. comment=\ + kv801.prod.do.dsp.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=displaycatalog-rp.md.mp.microsoft.com.akadns.net. comment=\ + displaycatalog.mp.microsoft.com list=windowsupdateslist +add address=rp-consumer-prod-displaycatalog-geomap.trafficmanager.net. \ + comment=displaycatalog-rp.md.mp.microsoft.com.akadns.net list=\ + windowsupdateslist +add address=sls.update.microsoft.com. comment=slscr.update.microsoft.com \ + list=windowsupdateslist +add address=glb.sls.prod.dcat.dsp.trafficmanager.net. comment=\ + sls.update.microsoft.com list=windowsupdateslist +add address=fe3.delivery.mp.microsoft.com. comment=\ + fe3cr.delivery.mp.microsoft.com list=windowsupdateslist +add address=glb.cws.prod.dcat.dsp.trafficmanager.net. comment=\ + fe3.delivery.mp.microsoft.com list=windowsupdateslist +add address=fe2cr.update.msft.com.trafficmanager.net. comment=\ + fe2cr.update.microsoft.com list=windowsupdateslist +add address=download.windowsupdate.com.delivery.microsoft.com. comment=\ + download.windowsupdate.com list=windowsupdateslist +add address=wu-f-net.trafficmanager.net. comment=\ + download.windowsupdate.com.delivery.microsoft.com list=windowsupdateslist +add address=tsfe.trafficmanager.net. comment=\ + tsfe.trafficshaping.dsp.mp.microsoft.com list=windowsupdateslist +add address=edge.ds-c7110-microsoft.global.dns.qwilted-cds.cqloud.com. \ + comment=9.au.download.windowsupdate.com list=windowsupdateslist +add address=52.158.227.125 comment=array812.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=au.download.windowsupdate.com.delivery.microsoft.com. comment=\ + au.download.windowsupdate.com list=windowsupdateslist +add address=a767.dspw65.akamai.net. comment=\ + download.windowsupdate.com.edgesuite.net list=windowsupdateslist +add address=52.151.58.88 comment=array810.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=consumer-licensing-aks2aks.md.mp.microsoft.com.akadns.net. \ + comment=licensing.mp.microsoft.com list=windowsupdateslist +add address=licensing-prod-frontdoor-geomap.trafficmanager.net. comment=\ + consumer-licensing-aks2aks.md.mp.microsoft.com.akadns.net list=\ + windowsupdateslist +add address=star.f.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedge.f.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=cdp-f-nlu-net.trafficmanager.net. comment=\ + star.f.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=star.b.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedge.b.tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=cdp-f-tlu-net.trafficmanager.net. comment=\ + star.b.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=storeedgefd.xbetservices.akadns.net. comment=\ + storeedgefd.dsx.mp.microsoft.com list=windowsupdateslist +add address=\ + storeedgefd.dsx.mp.microsoft.com.edgekey.net.globalredir.akadns.net. \ + comment=storeedgefd.dsx.mp.microsoft.com.edgekey.net list=\ + windowsupdateslist +add address=e16646.dscg.akamaiedge.net. comment=\ + storeedgefd.dsx.mp.microsoft.com.edgekey.net.globalredir.akadns.net list=\ + windowsupdateslist +add address=40.69.76.189 comment=array621.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=bg.microsoft.map.fastly.net. comment=\ + 3.au.download.windowsupdate.com list=windowsupdateslist +add list=windowsupdateslist +add address=40.69.75.33 comment=array613.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=star.sf.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedgeextensions.sf.tlu.dl.delivery.mp.microsoft.com list=\ + windowsupdateslist +add address=cdp-f-ssl-tlu-net.trafficmanager.net. comment=\ + star.sf.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=a2033.dscd.akamai.net. comment=\ + star.sb.tlu.dl.delivery.mp.microsoft.com.edgesuite.net list=\ + windowsupdateslist +add address=13.74.138.242 comment=array602.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=dl.delivery.mp.microsoft.com.delivery.microsoft.com. comment=\ + dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=dcat-f-nlu-net.trafficmanager.net. comment=\ + dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=1d.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=1D.tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=dcat-b-tlu-net.trafficmanager.net. comment=\ + 1d.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=a122.dscg3.akamai.net. comment=\ + tlu.dl.delivery.mp.microsoft.com.edgesuite.net list=windowsupdateslist +add address=geover.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + geover.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=e10370.d.akamaiedge.net. comment=\ + geover.prod.do.dsp.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=52.232.182.21 comment=array511.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.70.77.95 comment=array519.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=a1683.dscd.akamai.net. comment=\ + dl.delivery.mp.microsoft.com-c.edgesuite.net list=windowsupdateslist +add address=consumer-collections-aks2eap.md.mp.microsoft.com.akadns.net. \ + comment=collections.mp.microsoft.com list=windowsupdateslist +add address=a1847.dscd.akamai.net. comment=\ + wildcard.f.tlu.dl.delivery.mp.microsoft.com.edgesuite.net list=\ + windowsupdateslist +add address=13.74.142.6 comment=array607.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=au.download.windowsupdate.com.edgesuite.net. comment=\ + 2.au.download.windowsupdate.com list=windowsupdateslist +add address=a767.dscg3.akamai.net. comment=\ + au.download.windowsupdate.com.edgesuite.net list=windowsupdateslist +add address=52.156.123.84 comment=array818.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.69.78.254 comment=array610.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=4.au.download.windowsupdate.com.delivery.microsoft.com. comment=\ + 4.au.download.windowsupdate.com list=windowsupdateslist +add address=cl-glcb907925.gcdn.co. comment=\ + 4.au.download.windowsupdate.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=52.167.167.111 comment=array510.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=40.69.70.43 comment=array623.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=tsfe.trafficshaping.dsp.mp.microsoft.com.delivery.microsoft.com. \ + comment=tsfe.trafficshaping.dsp.mp.microsoft.com list=windowsupdateslist +add address=ts-frontend.trafficmanager.net. comment=\ + tsfe.trafficshaping.dsp.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=40.69.75.248 comment=array616.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.69.74.84 comment=array615.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=sds.trafficmanager.net. comment=software-download.microsoft.com \ + list=windowsupdateslist +add address=40.69.74.80 comment=array611.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.175.242.182 comment=array804.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=dlc-shim.trafficmanager.net. comment=download.microsoft.com list=\ + windowsupdateslist +add address=e12671.dscd.akamaiedge.net. comment=\ + download.microsoft.com.edgekey.net list=windowsupdateslist +add address=20.187.55.34 comment=array808.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.167.231 comment=array513.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=52.167.222.13 comment=array518.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=kv601.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + kv601.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=e12358.d.akamaiedge.net. comment=\ + kv601.prod.do.dsp.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. comment=\ + tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=dcat-f-tlu-net.trafficmanager.net. comment=\ + tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=a1856.dspw65.akamai.net. comment=\ + tlu.dl.delivery.mp.microsoft.com-c.edgesuite.net list=windowsupdateslist +add address=52.167.164.252 comment=array506.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=13.74.137.54 comment=array601.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=kv501.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + kv501.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=collections-prod-frontdoor-geomap.trafficmanager.net. comment=\ + consumer-collections-aks2eap.md.mp.microsoft.com.akadns.net list=\ + windowsupdateslist +add address=52.167.160.173 comment=array509.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=40.70.77.148 comment=array516.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.200.126 comment=array507.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=52.167.167.59 comment=array508.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.69.76.172 comment=array620.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=smtp.mail.me.com comment=smtp.mail.me.com list=NoVdsina +add address=40.70.76.5 comment=array514.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.186.119 comment=array618.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.177.176.186 comment=array520.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=40.70.76.27 comment=array515.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.160.43 comment=array503.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.110 comment=array817.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.142.8 comment=array614.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.138.254 comment=array603.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.167.96 comment=array501.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.69.76.215 comment=array622.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.143.200 comment=array606.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.111 comment=array818.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.112 comment=array819.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.137.53 comment=array608.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.98 comment=array805.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.96 comment=array803.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.104 comment=array811.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.101 comment=array808.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.99 comment=array806.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.17 comment=array802.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.97 comment=array804.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.103 comment=array810.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.16 comment=array801.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.70.77.177 comment=array517.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.164.84 comment=array512.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.105 comment=array812.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.107 comment=array814.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.232.161.82 comment=array502.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.108 comment=array815.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.161.91 comment=array505.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.102 comment=array809.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.109 comment=array816.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.106 comment=array813.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.117 comment=array622.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.107 comment=array612.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.108 comment=array613.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.105 comment=array610.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.113 comment=array618.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.116 comment=array621.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.98 comment=array603.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.114 comment=array619.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.111 comment=array616.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.97 comment=array602.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.106 comment=array611.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.110 comment=array615.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.119 comment=array624.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.135 comment=array514.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.97 comment=array503.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.99 comment=array604.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.61 comment=array504.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.131 comment=array510.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.132 comment=array511.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.96 comment=array601.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.104 comment=array609.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.138 comment=array517.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.60 comment=array501.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.139 comment=array518.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.118 comment=array623.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.113 comment=array820.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.103 comment=array608.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.100 comment=array807.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.129 comment=array508.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.134 comment=array513.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.62 comment=array505.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.137 comment=array516.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.101 comment=array606.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.96 comment=array502.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.130 comment=array509.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.112 comment=array617.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.100 comment=array605.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.115 comment=array620.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.136 comment=array515.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=purchase.md.mp.microsoft.com.akadns.net. comment=\ + purchase.mp.microsoft.com list=windowsupdateslist +add address=e110219.a.akamaiedge.net. comment=\ + purchase.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=72.153.5.140 comment=array519.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.141 list=windowsupdateslist +add address=72.153.5.63 comment=array506.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.128 comment=array507.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.102 comment=array607.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=storesdk.xbetservices.akadns.net. comment=\ + storesdk.dsx.mp.microsoft.com list=windowsupdateslist +add address=e16646.g.akamaiedge.net. comment=\ + storesdk.dsx.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=software-download.microsoft.com.delivery.microsoft.com. comment=\ + software-download.microsoft.com list=windowsupdateslist +add address=download.prss.microsoft.com.akamaized.net. comment=\ + software-download.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.109 comment=array614.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.133 comment=array512.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=213.180.192.0/19 comment=YandexDisk list=NoVdsina +add address=87.250.250.50 comment=YandexDisk list=NoVdsina +add address=consumer-prod-bcfd-v7-afd.trafficmanager.net. comment=\ + displaycatalog.mp.microsoft.com list=windowsupdateslist +add address=purchase-europeeap.md.mp.microsoft.com.akadns.net. comment=\ + purchase.md.mp.microsoft.com.akadns.net list=windowsupdateslist +add address=ne-az-conspurchase-mp.trafficmanager.net. comment=\ + purchase-europeeap.md.mp.microsoft.com.akadns.net list=windowsupdateslist +add address=storeedgefd.dsx.mp.microsoft.com.edgekey.net. comment=\ + cdn.storeedgefd.dsx.mp.microsoft.com list=windowsupdateslist +add address=star.f.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedge.f.tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=a1996.dscd.akamai.net. comment=\ + wildcard.f.dl.delivery.mp.microsoft.com.edgesuite.net list=\ + windowsupdateslist +add address=cp801.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + cp801.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=glb.tas02.sls-prod.dcat.dsp.mp.microsoft.com. comment=\ + tas02.sls.update.microsoft.com list=windowsupdateslist +add address=cp601.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + cp601.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=star.sb.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedgeextensions.sb.tlu.dl.delivery.mp.microsoft.com list=\ + windowsupdateslist +add address=star.sf.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedge.sf.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=cdp-f-ssl-nlu-net.trafficmanager.net. comment=\ + star.sf.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=tm-pifd-prod-gbl-weight.trafficmanager.net. comment=\ + paymentinstruments.mp.microsoft.com list=windowsupdateslist +add address=10.30.30.33 comment=amster disabled=yes list=NoWG +add address=10.30.30.10 comment=MikroNUC disabled=yes list=NoWG +add address=89.110.101.17 comment=!!!VDSINA!!!! disabled=yes list=NoWG +add address=wg.vados.ru comment=VDSina-vpn list=VDSina +add address=80.85.244.9 list=TRUSTED +add address=disc801.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + disc801.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=185.71.70.78 disabled=yes list=TRUSTED +add address=176.53.203.171 disabled=yes list=TRUSTED +add address=176.53.203.170 disabled=yes list=TRUSTED +add address=176.53.202.194 disabled=yes list=TRUSTED +add address=89.110.101.17 comment="!!!VDSina Server!!!" list=NoVdsina +add address=dns.quad9.net comment=Quad9-dns disabled=yes list=Trusted-DNS +add address=dns.google comment=Google-dns list=Trusted-DNS +add address=security.cloudflare-dns.com comment=CloudFlare-dns list=\ + Trusted-DNS +add address=time.google.com comment=Google-time list=Trusted-NTP +add address=0.ru.pool.ntp.org comment=ru.pool.ntp.org disabled=yes list=\ + Trusted-NTP +add address=1.ru.pool.ntp.org disabled=yes list=Trusted-NTP +add address=2.ru.pool.ntp.org comment=2.ru.pool.ntp.org disabled=yes list=\ + Trusted-NTP +add address=3.ru.pool.ntp.org comment=3.ru.pool.ntp.org disabled=yes list=\ + Trusted-NTP +add address=cp.vdsina.com comment=VDSina-vpn list=VDSina +add address=vdsina.ru comment=VDSina-vpn list=VDSina +add address=ns.vados.ru comment=VDSina-vpn list=VDSina +add address=vdsina.com comment=VDSina-vpn list=VDSina +add address=cp.vdsina.ru comment=VDSina-vpn list=VDSina +add address=ns1.vdsina.ru comment=VDSina-vpn list=VDSina +add address=10.30.30.0/24 comment="Local Network" list=Local-Net +add address=10.8.0.0/24 comment="WireGuard Network" list=Local-Net +add address=146.120.64.208/29 comment="External Net" list=Unet +add address=esia.gosuslugi.ru comment=esia.gosuslugi.ru list=NoVdsina +add address=lk.gosuslugi.ru comment=lk.gosuslugi.ru list=NoVdsina +add address=trudvsem.ru comment=trudvsem.ru list=NoVdsina +add address=10.30.30.30 comment=miller disabled=yes list=NoWG +add address=10.30.30.33 comment="Direct connet to DNS servers" list=\ + Direct-DNS +add address=wg.vados.ru list=VPN-Server +/ip firewall filter +add action=accept chain=input dst-port=18880 in-interface=Bridge-LAN \ + protocol=tcp src-address=10.30.30.0/24 +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=12h chain=input comment="block honeypot DNS" \ + connection-state=new dst-port=53 in-interface="ether1 - Unet" protocol=\ + udp src-address-list=!Trusted-DNS +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=4w2d chain=input connection-state=new dst-port=53 \ + in-interface="ether1 - Unet" protocol=tcp src-address-list=!Trusted-DNS +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=4w2d chain=input comment=\ + "block honeypot ssh rdp winbox" connection-state=new dst-port=22,8291 \ + in-interface="ether1 - Unet" protocol=tcp src-address-list=!TRUSTED +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=4w2d chain=input comment="block honeypot asterisk" \ + connection-state=new dst-port=5060 in-interface="ether1 - Unet" protocol=\ + udp +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=4w2d chain=input comment="block honeypot NTP" \ + connection-state=new dst-port=123 in-interface="ether1 - Unet" protocol=\ + udp +add action=fasttrack-connection chain=forward comment=\ + "FastTrack for non-VPN connections" connection-mark=!VPN_No_FastTrack \ + connection-state=established,related,new disabled=yes +add action=accept chain=input disabled=yes dst-port=29185 in-interface=\ + "ether1 - Unet" protocol=tcp +add action=accept chain=input disabled=yes dst-port=29185 in-interface=\ + "ether1 - Unet" protocol=udp +add action=accept chain=input comment="tcp Accept input DNS queries from LAN" \ + dst-port=53 in-interface=Bridge-LAN protocol=tcp src-address=\ + 10.30.30.0/24 +add action=accept chain=input comment="udp Accept input DNS queries" \ + dst-port=53 in-interface=Bridge-LAN protocol=udp src-address=\ + 10.30.30.0/24 +add action=accept chain=output comment="accept WireGuard" dst-address-list=\ + VPN-Server out-interface="ether1 - Unet" protocol=udp src-port=13231 +add action=accept chain=output dst-address-list=VPN-Server dst-port=29185 \ + out-interface="ether1 - Unet" protocol=udp +add action=fasttrack-connection chain=forward comment="defconf: fasttrack" \ + connection-state=established,related,new disabled=yes routing-mark=\ + !To-VPN +add action=accept chain=output disabled=yes protocol=tcp src-port=443 +add action=accept chain=output disabled=yes src-address=127.0.0.1 +add action=accept chain=forward comment="defconf: accept in ipsec policy" \ + disabled=yes ipsec-policy=in,ipsec +add action=accept chain=forward comment="defconf: accept out ipsec policy" \ + disabled=yes ipsec-policy=out,ipsec +add action=accept chain=forward comment=\ + "defconf: accept established,related, untracked" connection-state=\ + established,related,untracked +add action=drop chain=forward comment="defconf: drop invalid" \ + connection-state=invalid in-interface="ether1 - Unet" src-address=\ + !10.30.30.0/24 +add action=drop chain=forward comment=\ + "defconf: drop all from WAN not DSTNATed" connection-nat-state=!dstnat \ + connection-state=new in-interface="ether1 - Unet" src-address-list=\ + !VDSina +add action=drop chain=forward comment=\ + "Filter Rule to block FB address LIST : )" disabled=yes dst-address-list=\ + facebook +add action=drop chain=forward comment=\ + "Filter Rule to block YOUTUBE address LIST : )" disabled=yes \ + dst-address-list=YouTube +add action=accept chain=input protocol=icmp src-address-list=VDSina +add action=accept chain=input connection-state=established +add action=accept chain=input connection-state=related in-interface-list=\ + *2000014 +add action=drop chain=input in-interface=!Bridge-LAN +/ip firewall mangle +add action=mark-routing chain=prerouting comment=\ + "Mark Routing main for NoVdsina" dst-address-list=NoVdsina \ + new-routing-mark=main passthrough=no src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=\ + "Mark Routing main for VDSina" dst-address-list=VPN-Server \ + new-routing-mark=main src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=\ + "!!!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="Mark Routing main for NoWG" \ + new-routing-mark=main passthrough=no src-address=10.30.30.0/24 \ + src-address-list=NoWG +add action=mark-routing chain=prerouting comment="VDSIna for All sites" \ + dst-address=!10.30.30.0/24 dst-address-list=!NoVdsina new-routing-mark=\ + To-VPN src-address=10.30.30.0/24 src-address-list=!NoWG +add action=mark-connection chain=prerouting comment=\ + "Mark VPN connections to exclude from FastTrack" new-connection-mark=\ + VPN_No_FastTrack routing-mark=To-VPN +add action=change-mss chain=forward comment="MSS on WG" new-mss=1380 \ + out-interface=WG protocol=tcp routing-mark=To-VPN tcp-flags=syn tcp-mss=\ + 1381-65535 +add action=mark-routing chain=prerouting comment="VPN Network" dst-address=\ + 10.8.0.0/24 new-routing-mark=To-VPN src-address=10.30.30.0/24 +/ip firewall nat +add action=redirect chain=dstnat comment="udp Redirect DNS in NAT" disabled=\ + yes dst-port=53 protocol=udp src-address=10.30.30.0/24 to-addresses=\ + 10.30.30.81 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 to-addresses=\ + 10.30.30.81 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" dst-address=\ + !10.30.30.0/24 out-interface="ether1 - Unet" src-address=10.30.30.0/24 +add action=dst-nat chain=dstnat comment=amster.vados.ruhttps dst-port=443 \ + fragment=no in-interface="ether1 - Unet" protocol=tcp src-address=\ + !10.30.30.0/24 to-addresses=10.30.30.33 to-ports=443 +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="amster.vados.ru For Certbot HTTP" \ + dst-port=80 in-interface="ether1 - Unet" protocol=tcp to-addresses=\ + 10.30.30.33 to-ports=80 +add action=dst-nat chain=dstnat comment=npm dst-port=81 in-interface=\ + "ether1 - Unet" protocol=tcp routing-mark=To-VPN to-addresses=10.30.30.33 \ + to-ports=81 +add action=dst-nat chain=dstnat comment=SSH dst-port=22 in-interface=\ + "ether1 - Unet" protocol=tcp src-address-list=TRUSTED to-addresses=\ + 10.30.30.33 to-ports=22 +add action=dst-nat chain=dstnat comment="portainer agent" disabled=yes \ + dst-port=2377 in-interface="ether1 - Unet" protocol=tcp to-addresses=\ + 10.30.30.33 to-ports=2377 +add action=dst-nat chain=dstnat disabled=yes dst-port=22 in-interface=\ + "ether1 - Unet" protocol=tcp routing-mark=!To-VPN to-addresses=\ + 10.30.30.33 to-ports=22 +add action=masquerade chain=srcnat comment=WG dst-address-list=!NoVdsina \ + out-interface=WG routing-mark=To-VPN src-address-list=!NoWG +add action=dst-nat chain=dstnat comment="Yandex.DNS Family" disabled=yes \ + dst-port=53 in-interface=Bridge-LAN protocol=udp src-address-list=KIDS \ + time=6h-15m,sun,mon,tue,wed,thu,fri,sat to-addresses=77.88.8.3 +add action=dst-nat chain=dstnat disabled=yes dst-port=53 in-interface=\ + Bridge-LAN protocol=tcp src-address-list=KIDS time=\ + 6h-15m,sun,mon,tue,wed,thu,fri,sat to-addresses=77.88.8.3 +/ip firewall raw +add action=drop chain=prerouting comment="Drop Honeypot Hackers" \ + in-interface="ether1 - Unet" src-address-list="Honeypot Hacker" +add action=accept chain=prerouting comment="Trusted DNS" disabled=yes \ + in-interface-list=WAN src-address-list=Trusted-DNS +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + extras.getpagespeed.com content=extras.getpagespeed.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=linux.duke.edu \ + content=linux.duke.edu disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=youtube.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + googleapis.com disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=ggpht.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=youtu.be \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=ytimg.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + googlevideo.com disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=gstatic.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + googleusercontent.com disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + nhacmp3youtube.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=rutube.ru \ + content=rutube.ru disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment="me.com raw" \ + content=me.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "icloud.com raw" content=icloud.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "smtp.mail.me.com raw" content=smtp.mail.me.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "smtp.mail.me.com.akadns.net raw" content=smtp.mail.me.com.akadns.net \ + disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "api.db-ip.com raw" content=api.db-ip.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + esia.gosuslugi.ru content=esia.gosuslugi.ru disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=gosuslugi.ru \ + content=gosuslugi.ru disabled=yes +/ip firewall service-port +set ftp disabled=yes +set tftp disabled=yes +set irc disabled=no +set sip disabled=yes +set pptp disabled=yes +set rtsp disabled=no +/ip ipsec settings +set accounting=no +/ip ipsec policy +set 0 disabled=yes dst-address=0.0.0.0/0 src-address=0.0.0.0/0 +/ip ipsec profile +set [ find default=yes ] dpd-interval=2m dpd-maximum-failures=5 +/ip proxy +set cache-administrator="" max-cache-size=none port=80,443 src-address=\ + 0.0.0.0 +/ip route +add check-gateway=none disabled=yes distance=1 dst-address=0.0.0.0/0 gateway=\ + WG routing-table=To-VPN scope=30 target-scope=10 +/ip service +set ftp disabled=yes +set telnet disabled=yes +set reverse-proxy disabled=yes +set ssh address=10.30.30.0/24 port=2222 +set winbox address=10.30.30.0/24 +set api address=10.30.30.0/24 disabled=yes +set api-ssl address=10.30.30.0/24 disabled=yes +set www-ssl certificate=Root-YE port=18443 +set www address=10.30.30.0/24 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 \ + strong-crypto=yes +/ip upnp +set enabled=yes +/ip upnp interfaces +add interface=Bridge-LAN type=internal +add forced-ip=146.120.64.211 interface="ether1 - Unet" type=external +add forced-ip=109.107.177.79 interface=*E type=external +add interface=lo type=internal +add interface=wlan2 type=internal +add interface=wlan1 type=internal +/ipv6 dhcp-client +add add-default-route=yes disabled=yes interface=*F rapid-commit=no request=\ + info use-interface-duid=yes validate-server-duid=no +/ipv6 dhcp-server option sets +add name=domain-search-set options=domain-search-list +add name="=\"Client ID\"" options=HostName +/ipv6 firewall address-list +add address=::/128 comment="defconf: unspecified address" list=bad_ipv6 +add address=::1/128 comment="defconf: lo" list=bad_ipv6 +add address=fec0::/10 comment="defconf: site-local" list=bad_ipv6 +add address=::ffff:0.0.0.0/96 comment="defconf: ipv4-mapped" list=bad_ipv6 +add address=::/96 comment="defconf: ipv4 compat" list=bad_ipv6 +add address=100::/64 comment="defconf: discard only " list=bad_ipv6 +add address=2001:db8::/32 comment="defconf: documentation" list=bad_ipv6 +add address=2001:10::/28 comment="defconf: ORCHID" list=bad_ipv6 +add address=3ffe::/16 comment="defconf: 6bone" list=bad_ipv6 +/ipv6 firewall filter +add action=accept chain=input comment=\ + "defconf: accept established,related,untracked" connection-state=\ + established,related,untracked +add action=drop chain=input comment="defconf: drop invalid" connection-state=\ + invalid +add action=accept chain=input comment="defconf: accept ICMPv6" protocol=\ + icmpv6 +add action=accept chain=input comment="defconf: accept UDP traceroute" \ + dst-port=33434-33534 protocol=udp +add action=accept chain=input comment=\ + "defconf: accept DHCPv6-Client prefix delegation." dst-port=546 protocol=\ + udp src-address=fe80::/10 +add action=accept chain=input comment="defconf: accept IKE" dst-port=500,4500 \ + protocol=udp +add action=accept chain=input comment="defconf: accept ipsec AH" protocol=\ + ipsec-ah +add action=accept chain=input comment="defconf: accept ipsec ESP" protocol=\ + ipsec-esp +add action=accept chain=input comment=\ + "defconf: accept all that matches ipsec policy" ipsec-policy=in,ipsec +add action=drop chain=input comment=\ + "defconf: drop everything else not coming from LAN" in-interface-list=\ + !LAN +add action=accept chain=forward comment=\ + "defconf: accept established,related,untracked" connection-state=\ + established,related,untracked +add action=drop chain=forward comment="defconf: drop invalid" \ + connection-state=invalid +add action=drop chain=forward comment=\ + "defconf: drop packets with bad src ipv6" src-address-list=bad_ipv6 +add action=drop chain=forward comment=\ + "defconf: drop packets with bad dst ipv6" dst-address-list=bad_ipv6 +add action=drop chain=forward comment="defconf: rfc4890 drop hop-limit=1" \ + hop-limit=equal:1 protocol=icmpv6 +add action=accept chain=forward comment="defconf: accept ICMPv6" protocol=\ + icmpv6 +add action=accept chain=forward comment="defconf: accept HIP" protocol=139 +add action=accept chain=forward comment="defconf: accept IKE" dst-port=\ + 500,4500 protocol=udp +add action=accept chain=forward comment="defconf: accept ipsec AH" protocol=\ + ipsec-ah +add action=accept chain=forward comment="defconf: accept ipsec ESP" protocol=\ + ipsec-esp +add action=accept chain=forward comment=\ + "defconf: accept all that matches ipsec policy" ipsec-policy=in,ipsec +add action=drop chain=forward comment=\ + "defconf: drop everything else not coming from LAN" in-interface-list=\ + !LAN +/ipv6 nd +set [ find default=yes ] advertise-dns=yes disabled=yes interface=Bridge-LAN \ + managed-address-configuration=yes other-configuration=yes pref64=::/64 +/ipv6 nd prefix +add autonomous=no disabled=yes interface=Bridge-LAN on-link=no prefix=none +/ipv6 nd prefix default +set dhcp6-pd-preferred=yes +/ipv6 nd proxy +add disabled=yes interface=lo +/ipv6 nd settings +set router-advertisement-route-distance=100 +/routing bfd configuration +add addresses=10.8.0.0/24 disabled=no forbid-bfd=yes interfaces=*E min-rx=\ + 200ms min-tx=200ms multiplier=5 vrf=main +/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 +/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/20260619/20260619162002-Config.rsc b/MikroMaster/20260619/20260619162002-Config.rsc new file mode 100644 index 0000000..e625142 --- /dev/null +++ b/MikroMaster/20260619/20260619162002-Config.rsc @@ -0,0 +1,3679 @@ +# 2026-06-19 16:20:04 by RouterOS 7.23.1 +# software id = A8L5-07YF +# +# model = RB952Ui-5ac2nD +# serial number = D3D50CEDCD38 +/interface bridge +add admin-mac=48:8F:5A:8E:1A:BF auto-mac=no dhcpv6-agent-circuit-id=\ + "\$(INTERFACE):\$(VID)" dhcpv6-agent-remote-id="\$(BRIDGEMAC)" name=\ + Bridge-LAN port-cost-mode=short +/interface ethernet +set [ find default-name=ether1 ] comment="WAN - Unet" loop-protect=off name=\ + "ether1 - Unet" rx-flow-control=auto tx-flow-control=auto +set [ find default-name=ether2 ] comment=LAN-2 +set [ find default-name=ether3 ] advertise="10M-baseT-half,10M-baseT-full,100M\ + -baseT-half,100M-baseT-full,1G-baseT-full,1G-baseX" comment=LAN-3 +set [ find default-name=ether4 ] comment=LAN-4 +set [ find default-name=ether5 ] advertise="10M-baseT-half,10M-baseT-full,100M\ + -baseT-half,100M-baseT-full,1G-baseT-full,1G-baseX" comment=LAN-5 \ + loop-protect=on poe-out=off rx-flow-control=auto tx-flow-control=auto +/interface wireless +# managed by CAPsMAN +# channel: 2442/20-Ce/gn(18dBm), SSID: vados, local forwarding +set [ find default-name=wlan1 ] country=belarus disabled=no mode=ap-bridge \ + ssid=vados wireless-protocol=802.11 +# managed by CAPsMAN +# channel: 5200/20-eCee/ac/P(21dBm), SSID: vados5g, local forwarding +set [ find default-name=wlan2 ] country=belarus disabled=no mode=ap-bridge \ + ssid=vados5g wireless-protocol=802.11 +/interface wireguard +add comment=WG disabled=yes listen-port=13231 mtu=1320 name=WG +/interface list +add include=static name=LAN +add name=Internet +add include=Internet name=WAN +/interface wireless security-profiles +set [ find default=yes ] authentication-types=wpa-psk,wpa2-psk mode=\ + dynamic-keys supplicant-identity=MikroTik +/ip dhcp-server option +add code=12 name=HostName +add code=119 force=yes name=domain-search-list value="0x03'WORKGROUP'0x00" +/ip dhcp-server option sets +add name=HP1505n options=HostName +add name=StartLife1 options=HostName +add name=amsterDev options=HostName +add name=MiTV options=HostName +add name=miller options=HostName +add name=amster options=HostName +add name=garage options=HostName +add name=domain-search-set options=domain-search-list +add name=VADOS-LEN options=HostName +add name=VADOS-NUC options=HostName +add name=MikroNUC options=HostName +add name=master options=HostName +add name=MikroYellow options=HostName +add name="=\"Client ID\"" options=HostName +add name=iVados options=HostName +/ip dns forwarders +add dns-servers=1.1.1.1,1.0.0.1 name=blsp.at verify-doh-cert=no +add comment=Kra dns-servers=1.0.0.1,1.1.1.1 name=slon2.to verify-doh-cert=no +add dns-servers=1.1.1.1,1.0.0.1 name=slon3.at verify-doh-cert=no +add dns-servers=1.0.0.1,1.1.1.1 name=slon3.cc verify-doh-cert=no +add dns-servers=1.1.1.1,1.0.0.1 name=bs2web.at verify-doh-cert=no +add dns-servers=1.1.1.1,1.0.0.1 name=bs2best.at verify-doh-cert=no +add dns-servers=1.0.0.1,1.1.1.1 name=psrms.is verify-doh-cert=no +/ip ipsec proposal +set [ find default=yes ] disabled=yes +/ip pool +add name=dhcp ranges=10.30.30.83-10.30.30.254 +/ip dhcp-server +add add-arp=yes address-pool=dhcp always-broadcast=yes bootp-support=none \ + dhcp-option-set=domain-search-set interface=Bridge-LAN lease-time=10m \ + name=masterDHCP server-address=10.30.30.81 +/ip smb users +set [ find default=yes ] disabled=yes +add disabled=yes name=vados +/ipv6 dhcp-client option +add code=119 name=domain-search-list value="0x03'WORKGROUP'0x00" +add code=12 name=HostName value="\$(HOSTNAME)" +add code=61 name=DUID value=0x00030001488f5a8e1abc +add code=61 name=clientid +/ipv6 dhcp-server option +add code=119 name=domain-search-list value="0x03'WORKGROUP'0x00" +add code=12 name=HostName value="\$(HOSTNAME)" +add code=61 name=CLIENT_DUID +add code=61 name=CLIENT_MAC +/ppp profile +set *FFFFFFFE use-upnp=no +/routing bgp template +set default disabled=no output.network=bgp-networks +/routing table +add disabled=no fib name=To-VPN +/system logging action +add email-start-tls=yes email-to=vados@vados.ru name=email target=email +/system script +add dont-require-permissions=no name=fetchCustom owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + global GlobalScriptsUrl \"https://ros.vados.ru/\";\r\ + \n\r\ + \n#/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@1\ + 0.30.30.86.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.86.pub\";\ + \n\r\ + \n#:local Script AM-setup\ + \n;\r\ + \n#/system/script/add name=\$Script owner=\$Script source=([ /tool/fetch c\ + heck-certificate=yes-without-crl url=(\$GlobalScriptsUrl . \$Script . \".r\ + sc\") output=user as-value ]->\"data\");\r\ + \n\ + \n#/usb1/mikro_bak_rsa.pub\ + \n\ + \n\r\ + \n#\ + \n\r\ + \n#/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@1\ + 0.30.30.10.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.10.pub\";\ + \n\r\ + \n#\r\ + \n\ + \n#root.mnuc.backuper\ + \n\ + \n\r\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@10\ + .30.30.81.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.81.pub\";\r\ + \n\ + \n#:local Script AM-GlobalConfig;\ + \n\r\ + \n#/system/script/add name=\$Script owner=\$Script source=([ /tool/fetch c\ + heck-certificate=yes-without-crl url=(\$GlobalScriptsUrl . \$Script . \".r\ + sc\") output=user as-value ]->\"data\");\r\ + \n\ + \n#/usb1/mikro_bak_rsa.pub\ + \n#:local FetchFile AM-DOHCert.rsc\ + \n\ + \n\r\ + \n\r\ + \n#\ + \n:global MkDir;\ + \n\r\ + \n\ + \n#:local FetchFile Binary.backup\ + \n:local localDir \"\";\ + \n\ + \n\r\ + \n#\$MkDir \$localDir;\r\ + \n\ + \n#\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \$FetchFile) dst-path=(\ + \$localDir . \$FetchFile);\r\ + \n" +add comment="Global Config Script" dont-require-permissions=no name=\ + AM-GlobalConfig owner=AM-GlobalConfig policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\r\ + \n# RouterOS script: AM-GlobalConfig\r\ + \n# Script comment: Global Config Script\r\ + \n# Copyright (c) 2007-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# Warning: Dont touch this line!\r\ + \n:global Identity [/system/identity/get name];\r\ + \n:global GlobalConfReady false;\r\ + \n#\r\ + \n#\r\ + \n# Global Url For Amster scripts to fetch\r\ + \n# most be defined in AM-Init-Script or AM-setup scripts\r\ + \n:global GlobalScriptsUrl \"https://ros.vados.ru/\";\r\ + \n:global ScriptsUrlSuffix (a);\r\ + \n:global CheckSumsVerify true;\r\ + \n\r\ + \n:global ScriptUpdatesCRLF true;\r\ + \n:global CommentsInScripts true;\r\ + \n\r\ + \n# Debug output:\r\ + \n:global PrintDebug true; #false;\r\ + \n\r\ + \n# Debug output for specific script:\r\ + \n#:set (\$PrintDebugOverride->\"AM-GlobalFunc\") true;\r\ + \n\r\ + \n# Debug logs\r\ + \n# Other actions (disk, email, remote or support) can be used as well.\r\ + \n# I do not recommend using echo - use debug output instead (https://rsc.\ + eworm.de/main/DEBUG.html#debug-output).\r\ + \n#/system/logging/add topics=script,debug action=memory;\r\ + \n\r\ + \n:global MikrotikUpgradeUrl \"https://upgrade.mikrotik.com/routeros\";\r\ + \n:global Domain \"WORKGROUP\";\r\ + \n\r\ + \n:global EmailGeneralTo \"vados@vados.ru\";\r\ + \n#:global EmailGeneralCc \"\";\r\ + \n\r\ + \n# \$ScriptInstallUpdate mod/notification-telegram\r\ + \n:global TelegramTokenId \"8390868324:AAG3_d1hfVR2M6pGAgDK6ZvhOe4J97nyopw\ + \";\r\ + \n:global TelegramChatId \"-1003631309063\"; #\"454403445\";\r\ + \n# Use this to send notifications to a specific topic in group.\r\ + \n#:global TelegramThreadId \"30\";\r\ + \n# Using telegram-chat you have to define trusted chat ids (not group ids\ + !)\r\ + \n# or user names. Groups allow to chat with devices simultaneously.\r\ + \n:global TelegramChatIdsTrusted {\r\ + \n \"454403445\"\r\ + \n \"-1003631309063\"\r\ + \n \"-5124482807\"\r\ + \n \"1087968824\";\r\ + \n};\r\ + \n# \"-5294757340\";\r\ + \n\r\ + \n:global TelegramChatGroups \"(all)\";\r\ + \n#:global TelegramChatGroups \"(all|home|office)\";\r\ + \n\r\ + \n:global NotificationFunctions {\r\ + \n \"email\"\r\ + \n \"telegram\";\r\ + \n};\r\ + \n# Toggle this to disable symbols in notifications.\r\ + \n:global NotificationsWithSymbols true;\r\ + \n:global TerminalColorOutput true;\r\ + \n\r\ + \n:global DetectIpAddrDefault \"https://ipv4.mikrotik.ovh/\";\r\ + \n:global DetectIpAddrFallback \"https://api.ipify.org/\";\r\ + \n\r\ + \n## Update channel. Possible values: stable, long-term, testing, developm\ + ent\r\ + \n:global updateChannel \"stable\";\r\ + \n\r\ + \n:global CertRenewUrl (\$GlobalScriptsUrl . \"certs/\" . \$Identity . \"/\ + \");\r\ + \n:global CertRenewTime 2w;\r\ + \n:global CertRenewPass (a); #{\r\ + \n# \"\";\r\ + \n# \"v3ry-s3cr3t\";\r\ + \n# \"4n0th3r-s3cr3t\";\r\ + \n#};\r\ + \n:global CertWarnTime 1w;\r\ + \n:global CertIssuedExportPass (a); # {\r\ + \n# \"\";\r\ + \n# \"cert1-cn\"=\"v3ry-s3cr3t\";\r\ + \n# \"cert2-cn\"=\"4n0th3r-s3cr3t\";\r\ + \n#};\r\ + \n\r\ + \n# Script BackupAndUpdate mode, possible values: backup,\r\ + \n# updateOnce - Update once as \"osnotify\" and back \"osnotify\" mode (i\ + n terminal run :set OSUpdateMode updateOnce; \$OSUpdateMode;). \r\ + \n# osupdate - Update if available and creates backups before/after update\ + \_(ignores `forceBackup`)\r\ + \n# Set `forceBackup` to true to always create backups, even\ + \_without updates\r\ + \n# osnotify - Set `forceBackup` to always create backups on every run\r\ + \n:global DevInfoIncludeIP true;\r\ + \n:global BackupAndUpdateMode \"osnotify\"\r\ + \n\r\ + \n:global forceBackup true;\r\ + \n:global BackupPassword \"Peskar55\";\r\ + \n\r\ + \n# SFTP Backup Variables\r\ + \n:global BackupRandomDelay 0;\r\ + \n:global BackupUploadUrl \"sftp://amster.vados.ru/upload/\";\r\ + \n:global BackupUploadUser \$Identity;\r\ + \n:global BackupUploadPass \"root.mnuc.backuper\";\r\ + \n\r\ + \n:global BackupSendBinary true;\r\ + \n:global BackupSendExport true;\r\ + \n:global BackupSendGlobalConfig true;\r\ + \n:global BackupSendScripts true;\r\ + \n\r\ + \n# Remove local file after uploading if no errors\r\ + \n:global BackupRmLocal true;\r\ + \n\r\ + \n# Local Backups Root Directory \r\ + \n:global BackupLocalRoot \"tmpfs\";\r\ + \n\r\ + \n# Encrypt Backup\r\ + \n:global BackupEncrypt true;\r\ + \n\r\ + \n# Sensitive information in Backups\r\ + \n:global BackupSens true;\r\ + \n\r\ + \n# User Export\r\ + \n:global BackupUser true;\r\ + \n\r\ + \n# License Export (not for CHR, will silently skip)\r\ + \n:global BackupLicense false;\r\ + \n\r\ + \n# SSH Keys\r\ + \n:global BackupSshKeys true;\r\ + \n\r\ + \n# Certificate Export\r\ + \n:global BackupCerts true;\r\ + \n\r\ + \n# Certificate Password\r\ + \n:global BackupCertsPasswd \"\";\r\ + \n\r\ + \n# User-Manager Export\r\ + \n:global BackupUserMan false;\r\ + \n\r\ + \n# The Dude Export\r\ + \n:global BackupDude false;\r\ + \n\r\ + \n# User Files to export, comma-separated string or array of strings\r\ + \n# User Files are not removed on backup\r\ + \n# Any directory paths will be removed (/ -> _) on remote file\r\ + \n# Nonpresent files are silently skipped\r\ + \n:global BackupUserList \"autosupout.rif,autosupout.old.rif\";\r\ + \n\r\ + \n# load functions and any custom scripts\r\ + \n# [ /system/script/find where name=\"global-config-ov\ + erlay\" ], \\\r\ + \n# [ /system/script/find where name~\"^global-config-o\ + verlay\\\\.d/.\" ]\r\ + \n#\r\ + \n#:foreach Script in=([ /system/script/find where name=\"Amster-TGglobalV\ + ars\" ], [ /system/script/find where name=\"Amster-TGglobalFunc\" ]) do={\ + \r\ + \n# :onerror Err {\r\ + \n# /system/script/run \$Script;\r\ + \n# } do={\r\ + \n# :log error (\"Loading configuration from configs and functions\"\ + \_. [ /system/script/get \$Script name ] . \" failed: \" . \$Err);\r\ + \n# }\r\ + \n#}\r\ + \n#:log info \"\\ndevMode = \$devMode\";\r\ + \n#:log info \"\\ndevRunning = \$devRunning\";\r\ + \n:foreach Script in=[ /system/script/find where source~\"^#!rsc by Vados \ + GlobalRUN\\r\?\\n\" ] do={\r\ + \n :onerror Err {\r\ + \n /system/script/run \$Script;\r\ + \n } do={\r\ + \n :log error (\"Run script \" . [ /system/script/get \$Script name \ + ] . \" width marker \\\" GlobalRUN\\\" failed: \" . \$Err);\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n# signal we are ready\r\ + \n:set GlobalConfReady true;\r\ + \n:while (\$GlobalConfReady != true) do={:delay 500ms};\r\ + \n" +add comment="Global functions" dont-require-permissions=no name=AM-GlobalFunc \ + owner=AM-GlobalFunc policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\r\ + \n# RouterOS script: AM-GglobalFunc\r\ + \n# Script comment: Global functions\r\ + \n# Copyright (c) 2005-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version=7.19\r\ + \n# requires device-mode, fetch, scheduler\r\ + \n:local ExitOK false;\r\ + \n:local ScriptName [ :jobname ];\r\ + \n#:global checkRunJob \$SriptName;\r\ + \n#:global fixCRLF;\r\ + \n#:if (\$fixCRLF != false) do={\r\ + \n#:foreach fixScript in=([ /system/script/find where name~\"*\" ]) do={/s\ + ystem/script/set source=[ :tocrlf [ get \$fixScript source ] ] \$fixScript\ + }\r\ + \n#:if (\$fixCRLF != \"LF\") do={ /system/script/set source=[ :tocrlf [ g\ + et \$fixScript source ] ] \$fixScript};};\r\ + \n#}\r\ + \n:global GlobalFuncReady false;\r\ + \n\r\ + \n# Git commit id & info, expected configuration version\r\ + \n:global CommitId \"main/694/a1b071a6\";\r\ + \n:global CommitTAG \"unknown\";\r\ + \n:global CommitInfo \"Autocommit in repo: ros.vados.ru, generated by owne\ + r: root, in 13:30:04 15.06.2026.\";\r\ + \n\r\ + \n# The variables are received right here.\r\ + \n:global GlobalConfVersion 140;\r\ + \n\r\ + \n:global SumsDirAndFileName \"tmp/checksums.json\";\r\ + \n\r\ + \n:global Identity [/system/identity/get name];\r\ + \n:global IdentityShort [:pick \$Identity 0 18];\r\ + \n\r\ + \n:global devBoardName [/system/resource/get board-name];\r\ + \n:global devMode [/system/device-mode/get mode];\r\ + \n:global devCurArch [/system/resource/get architecture-name];\r\ + \n:global devCurVersion [/system/resource/get version];\r\ + \n\r\ + \n# Variables defined in AM-GlobalConfig.rsc\r\ + \n:global TerminalColorOutput;\r\ + \n:global CommentsInScripts;\r\ + \n:global DetectIpAddrDefault;\r\ + \n:global DetectIpAddrFallback;\r\ + \n:global updateChannel;\r\ + \n:global Domain;\r\ + \n:global EmailGeneralTo;\r\ + \n:global BackupAndUpdateMode;\r\ + \n\r\ + \n# Single functions, without nested functions.\r\ + \n:global MiniDateTimeStamp;\r\ + \n:global MicroDateTimeStamp;\r\ + \n\r\ + \n# Include globals \$PrintDebug and \$PrintDebugOverride\r\ + \n:global LogPrint;\r\ + \n\r\ + \n# DeviceInfo and Updates\r\ + \n:global IsCheckUpdates;\r\ + \n:global WaitCheckUpdates;\r\ + \n:global GetPubIp;\r\ + \n\r\ + \n:global GetArrDeviceInfo;\r\ + \n:global WaitArrDeviceInfo;\r\ + \n\r\ + \n:global devModel;\r\ + \n:global devRunningMode;\r\ + \n\r\ + \n:global devRbRevision;\r\ + \n:global devRbSerialNumber;\r\ + \n:global devRbVerAvail;\r\ + \n\r\ + \n:global runningChannelVersion;\r\ + \n:global runningChannel;\r\ + \n:global runningVersion;\r\ + \n\r\ + \n:global devBuildTime;\r\ + \n:global ROsVerAvail;\r\ + \n:global PkgUpdStatus;\r\ + \n:global currentUpdateChannel;\r\ + \n\r\ + \n:global ScriptInstallUpdate;\r\ + \n\r\ + \n:global DeviceInfo;\r\ + \n\r\ + \n:global OldMode;\r\ + \n\r\ + \n:global ParseKeyValueStore;\r\ + \n:global RandomDelay;\r\ + \n:global GetRandomNumber;\r\ + \n:global EscapeForRegEx;\r\ + \n:global CharacterMultiply;\r\ + \n:global CharacterReplace;\r\ + \n:global CleanFilePath;\r\ + \n:global CleanName;\r\ + \n\r\ + \n:global CommitBrief;\r\ + \n\r\ + \n:global EitherOr;\r\ + \n:global FormatLine;\r\ + \n:global GetRandom20CharAlNum;\r\ + \n:global GetRandom20CharHex;\r\ + \n:global GetRandomNumber;\r\ + \n:global Grep;\r\ + \n:global IfThenElse;\r\ + \n:global MAX;\r\ + \n:global MIN;\r\ + \n:global HumanReadableNum;\r\ + \n\r\ + \n:global IsFullyConnected;\r\ + \n:global IsDNSResolving;\r\ + \n:global IsTimeSync;\r\ + \n:global IsTimeSyncCached;\r\ + \n:global IsTimeSyncResetNtp;\r\ + \n\r\ + \n:global MkDir;\r\ + \n:global RmDir;\r\ + \n:global RmFile;\r\ + \n:global FileGet;\r\ + \n:global Unix2Dos;\r\ + \n:global UrlEncode;\r\ + \n:global WaitForFile;\r\ + \n:global ScriptLock;\r\ + \n:global SendTelegram;\r\ + \n:global NotificationFunctions;\r\ + \n:global SendNotification;\r\ + \n:global SendNotification2;\r\ + \n:global SymbolForNotification;\r\ + \n:global SymbolByUnicodeName;\r\ + \n:global ValidateSyntax;\r\ + \n:global CheckSumsVerify;\r\ + \n:global GlobalConfChanges;\r\ + \n:global GlobalConfMigration;\r\ + \n:global VersionToNum;\r\ + \n:global RequiredRouterOS;\r\ + \n:global ExitError;\r\ + \n:global ExitOnError;\r\ + \n\r\ + \n:global FetchHugeFiles;\r\ + \n:global FetchUserAgentStr;\r\ + \n:global FileExists;\r\ + \n:global CertificateAvailable;\r\ + \n:global CertificateDownload;\r\ + \n:global CertificateNameByCN;\r\ + \n:global CharacterMultiply;\r\ + \n\r\ + \n:global InspectVar;\r\ + \n:global InspectVarRet;\r\ + \n:global ParseCustom;\r\ + \n\r\ + \n:set IsCheckUpdates do={\r\ + \n :local isInfo [:tobool \$1];\r\ + \n :global updateChannel;\r\ + \n :global PkgUpdStatus;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n :global arrDeviceInfo;\r\ + \n :log info (\$0 . \" \\\$isInfo = \" . \$isInfo); \r\ + \n :local CurrentChannel [ /system/package/update/get channel ];\r\ + \n :if ([ :len \$updateChannel ] > 0 && \$CurrentChannel != \$updateChann\ + el) do={\r\ + \n :retry command={/system/package/update set channel=\$updateChannel} \ + \_delay=300ms max=5 on-error={};\r\ + \n :log info (\$0 . \" Set updates channel to: \$updateChannel\");\r\ + \n }\r\ + \n :local Update [ /system/package/update/get ];\r\ + \n :local Channel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set currentUpdateChannel \$Channel;\r\ + \n :log info (\$0 . \" Update Channel: \" . \$Channel . \".\");\r\ + \n :local StatusPkg \"undefined\";\r\ + \n :log info (\$0 . \" Checking for updates...\");\r\ + \n :retry command={:set \$StatusPkg ([/system/package/update/check-for-up\ + dates without-paging as-value]->\"status\")} \\\r\ + \n delay=300ms max=5 on-error={};\r\ + \n :log info (\$0 . \" \\\$StatusPkg = \" . \$StatusPkg);\r\ + \n :if (\$StatusPkg = \"New version is available\") do={ :set PkgUpdStatu\ + s true; } else={ :set PkgUpdStatus false; }\r\ + \n :set ROsVerAvail [ :tostr [ /system/package/update/get latest-version \ + ] ];\r\ + \n :log info (\$0 . \" \\\$PkgUpdStatus = \" . \$PkgUpdStatus);\r\ + \n :if (\$isInfo != false || \$PkgUpdStatus = true) do={\r\ + \n :log info (\$0 . \" \\\$PkgUpdStatus = \" . \$PkgUpdStatus);\r\ + \n :if ([ :typeof \$arrDeviceInfo ] != \"array\") do={\r\ + \n :set arrDeviceInfo [:toarray \$arrDeviceInfo];\r\ + \n }\r\ + \n :retry command={:set (\$arrDeviceInfo->\"devUpdates\") [ /system/pac\ + kage/update/get ]} delay=500ms max=5 on-error={:log error (\"Error\")};\r\ + \n :return true;\r\ + \n } else={\r\ + \n :return \$PkgUpdStatus;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set WaitCheckUpdates do={\r\ + \n :global IsCheckUpdates;\r\ + \n :global PkgUpdStatus;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n :global arrDeviceInfo;\r\ + \n :local Status \"\";\r\ + \n :local Update;\r\ + \n :local WaitCount 0;\r\ + \n :if ([ \$IsCheckUpdates true ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n :set Status [ :tostr [ /system/package/update/get status ] ];\r\ + \n :while ((\$Status = \"\" || \$Status = \"finding out latest version...\ + \") && \$WaitCount < 60) do={\r\ + \n :delay 1s;\r\ + \n :set WaitCount (\$WaitCount + 1);\r\ + \n :set Status [ :tostr [ /system/package/update/get status ] ];\r\ + \n }\r\ + \n :set Update [ /system/package/update/get ];\r\ + \n :set currentUpdateChannel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set ROsVerAvail [ :tostr (\$Update->\"latest-version\") ];\r\ + \n :if ((\$Update->\"status\") = \"New version is available\") do={\r\ + \n :set PkgUpdStatus true;\r\ + \n } else={\r\ + \n :set PkgUpdStatus false;\r\ + \n }\r\ + \n :if ([ :typeof \$arrDeviceInfo ] != \"array\") do={\r\ + \n :set arrDeviceInfo [:toarray \$arrDeviceInfo];\r\ + \n }\r\ + \n :set (\$arrDeviceInfo->\"devUpdates\") \$Update;\r\ + \n :if (\$Status = \"\" || \$Status = \"finding out latest version...\") \ + do={\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set WaitArrDeviceInfo do={\r\ + \n :global GetArrDeviceInfo;\r\ + \n :while ([ \$GetArrDeviceInfo ] = false) do={\r\ + \n :delay 1s;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set GetArrDeviceInfo do={\r\ + \n :global LogPrint;\r\ + \n :global arrDeviceInfo;\r\ + \n :global devBoardName;\r\ + \n :global devModel;\r\ + \n :global devRunning;\r\ + \n :global devCurArch;\r\ + \n :global devRbRevision;\r\ + \n :global devRbSerialNumber;\r\ + \n :global devBuildTime;\r\ + \n :global runningChannelVersion;\r\ + \n :global runningChannel;\r\ + \n :global runningVersion;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n\r\ + \n :local DeviceInfo;\r\ + \n :local Resource [/system/resource/get];\r\ + \n :local Update [ /system/package/update/get ];\r\ + \n :local VersionString [ :tostr (\$Resource->\"version\") ];\r\ + \n :local ChannelStart [ :find \$VersionString \" (\" ];\r\ + \n :local RouterBoard;\r\ + \n :local IsRouterBoard false;\r\ + \n :local RunningMode \"\";\r\ + \n\r\ + \n :set devCurArch [ :tostr (\$Resource->\"architecture-name\") ];\r\ + \n :set devBuildTime [ :tostr (\$Resource->\"build-time\") ];\r\ + \n :set runningChannelVersion \$VersionString;\r\ + \n :set runningVersion \$VersionString;\r\ + \n :set runningChannel \"\";\r\ + \n\r\ + \n :if ([ :typeof \$ChannelStart ] = \"num\" && \$ChannelStart >= 0) do=\ + {\r\ + \n :set runningVersion [ :pick \$VersionString 0 \$ChannelStart ];\r\ + \n :local ChannelRest [ :pick \$VersionString (\$ChannelStart + 2) [ :\ + len \$VersionString ] ];\r\ + \n :local ChannelEnd [ :find \$ChannelRest \")\" ];\r\ + \n :if ([ :typeof \$ChannelEnd ] = \"num\" && \$ChannelEnd >= 0) do={\ + \r\ + \n :set runningChannel [ :pick \$ChannelRest 0 \$ChannelEnd ];\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :if ([:pick \$devBoardName 0 3] != \"CHR\" or [:pick \$devBoardName 0\ + \_3] != \"x86\") do={\r\ + \n :do {\r\ + \n :set RouterBoard [[ :parse \"/system/routerboard/get\" ]];\r\ + \n# :set RouterBoard [ /system/routerboard/get ];\r\ + \n :if ((\$RouterBoard->\"routerboard\") = true) do={\r\ + \n :set IsRouterBoard true;\r\ + \n }\r\ + \n } on-error={}\r\ + \n }\r\ + \n\r\ + \n :do {\r\ + \n :set RunningMode [ /system/device-mode/get mode ];\r\ + \n } on-error={\r\ + \n :do {\r\ + \n :set RunningMode [ /system/device-mode/get running ];\r\ + \n } on-error={\r\ + \n :set RunningMode \"\";\r\ + \n }\r\ + \n }\r\ + \n :set devRunning \$RunningMode;\r\ + \n\r\ + \n :if (\$IsRouterBoard = true) do={\r\ + \n :set devModel [ :tostr (\$RouterBoard->\"model\") ];\r\ + \n :set devRbRevision [ :tostr (\$RouterBoard->\"revision\") ];\r\ + \n :set devRbSerialNumber [ :tostr (\$RouterBoard->\"serial-number\") \ + ];\r\ + \n } else={\r\ + \n :set devModel \$devBoardName;\r\ + \n :set devRbRevision \"\";\r\ + \n :set devRbSerialNumber \"\";\r\ + \n }\r\ + \n\r\ + \n :set currentUpdateChannel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set ROsVerAvail [ :tostr (\$Update->\"latest-version\") ];\r\ + \n\r\ + \n :set (\$DeviceInfo->\"board-name\") \$devBoardName;\r\ + \n :set (\$DeviceInfo->\"architecture-name\") \$devCurArch;\r\ + \n :set (\$DeviceInfo->\"model\") \$devModel;\r\ + \n :set (\$DeviceInfo->\"revision\") \$devRbRevision;\r\ + \n :set (\$DeviceInfo->\"serial-number\") \$devRbSerialNumber;\r\ + \n :set (\$DeviceInfo->\"running-mode\") \$devRunning;\r\ + \n :set (\$DeviceInfo->\"build-time\") \$devBuildTime;\r\ + \n :set (\$DeviceInfo->\"running-channel-version\") \$runningChannelVers\ + ion;\r\ + \n :set (\$DeviceInfo->\"running-version\") \$runningVersion;\r\ + \n :set (\$DeviceInfo->\"running-channel\") \$runningChannel;\r\ + \n :set (\$DeviceInfo->\"routerboard\") \$IsRouterBoard;\r\ + \n :set (\$DeviceInfo->\"current-firmware\") [ :tostr (\$RouterBoard->\"\ + current-firmware\") ];\r\ + \n :set (\$DeviceInfo->\"upgrade-firmware\") [ :tostr (\$RouterBoard->\"\ + upgrade-firmware\") ];\r\ + \n :set (\$DeviceInfo->\"package-channel\") \$currentUpdateChannel;\r\ + \n :set (\$DeviceInfo->\"installed-version\") [ :tostr (\$Update->\"inst\ + alled-version\") ];\r\ + \n :set (\$DeviceInfo->\"latest-version\") \$ROsVerAvail;\r\ + \n :set (\$DeviceInfo->\"update-status\") [ :tostr (\$Update->\"status\"\ + ) ];\r\ + \n\r\ + \n :set arrDeviceInfo \$DeviceInfo;\r\ + \n :return \$DeviceInfo;\r\ + \n}\r\ + \n\r\ + \n:set DeviceInfo do={\r\ + \n :global GetArrDeviceInfo;\r\ + \n :global GlobalConfVersion;\r\ + \n :global Identity;\r\ + \n :global IfThenElse;\r\ + \n :global FormatLine;\r\ + \n :global CommitBrief;\r\ + \n\r\ + \n :local License [/system/license/get];\r\ + \n :local Snmp [ /snmp/get ];\r\ + \n :local Info [ \$GetArrDeviceInfo ];\r\ + \n\r\ + \n :if ([ :typeof \$Info ] != \"array\") do={\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :return ( \\\r\ + \n [ \$FormatLine \"Hostname\" \$Identity ] . \"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$Snmp->\"location\") ] > 0) \\\r\ + \n ([ \$FormatLine \"Location\" (\$Snmp->\"location\") ] . \"\\n\") ]\ + \_. \\\r\ + \n [ \$IfThenElse ([ :len (\$Snmp->\"contact\") ] > 0) \\\r\ + \n ([ \$FormatLine \"Contact\" (\$Snmp->\"contact\") ] . \"\\n\") ] .\ + \_\\\r\ + \n \"Hardware:\\n\" . \\\r\ + \n [ \$FormatLine \" Board\" (\$Info->\"board-name\") ] . \"\\n\" . \ + \\\r\ + \n [ \$FormatLine \" Arch\" (\$Info->\"architecture-name\") ] . \"\\\ + n\" . \\\r\ + \n [ \$FormatLine \" Model\" (\$Info->\"model\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"revision\") ] > 0) \\\r\ + \n (\" \" . (\$Info->\"revision\")) ] . \"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"serial-number\") ] > 0) \\\r\ + \n ([ \$FormatLine \" Serial\" (\$Info->\"serial-number\") ] . \"\ + \\n\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$License->\"nlevel\") ] > 0) \\\r\ + \n ([ \$FormatLine \" License\" (\"level \" . (\$License->\"nlevel\ + \")) ] . \"\\n\") ] . \\\r\ + \n \"RouterOS:\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$License->\"level\") ] > 0) \\\r\ + \n ([ \$FormatLine \" License\" (\"level \" . (\$License->\"level\ + \")) ] . \"\\n\") ] . \\\r\ + \n [ \$FormatLine \" Channel\" (\$Info->\"package-channel\") ] . \"\ + \\n\" . \\\r\ + \n [ \$FormatLine \" Installed\" (\$Info->\"installed-version\") ] .\ + \_\"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"running-channel\") ] > 0) \\\r\ + \n ([ \$FormatLine \" Running\" ((\$Info->\"running-version\") . \ + \" (\" . (\$Info->\"running-channel\") . \")\") ] . \"\\n\") \\\r\ + \n ([ \$FormatLine \" Running\" (\$Info->\"running-version\") ] . \ + \"\\n\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"latest-version\") ] > 0 && \\\r\ + \n (\$Info->\"installed-version\") != (\$Info->\"latest-version\"))\ + \_\\\r\ + \n ([ \$FormatLine \" Available\" (\$Info->\"latest-version\") ] .\ + \_\"\\n\") ] . \\\r\ + \n [ \$IfThenElse ((\$Info->\"routerboard\") = true && \\\r\ + \n (\$Info->\"current-firmware\") != (\$Info->\"upgrade-firmware\")\ + ) \\\r\ + \n ([ \$FormatLine \" Firmware\" ((\$Info->\"current-firmware\") .\ + \_\" -> \" . (\$Info->\"upgrade-firmware\")) ] . \"\\n\") ] . \\\r\ + \n \"RouterOS-Scripts:\\n\" . \\\r\ + \n [ \$FormatLine \" Commit\" [ \$CommitBrief ] ] . \"\\n\" . \\\r\ + \n [ \$FormatLine \" Version\" \$GlobalConfVersion ]);\r\ + \n}\r\ + \n\r\ + \n:if ([ :typeof \$NotificationFunctions ] != \"array\") do={:set Notifica\ + tionFunctions ({})}\r\ + \n\r\ + \n:set GetRandom20CharAlNum do={\r\ + \n :global EitherOr;\r\ + \n :return [ :rndstr length=[ \$EitherOr [ :tonum \$1 ] 20 ] from=\"ABCDE\ + FGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\" ];\r\ + \n}\r\ + \n\r\ + \n:set GetRandom20CharHex do={:global EitherOr; :return [ :rndstr length=[\ + \_\$EitherOr [ :tonum \$1 ] 20 ] from=\"0123456789abcdef\" ]; }\r\ + \n:set GetRandomNumber do={:global EitherOr; :return [ :rndnum from=0 to=[\ + \_\$EitherOr [ :tonum \$1 ] 4294967295 ] ]; }\r\ + \n\r\ + \n:global checkRunJob;\r\ + \n:set checkRunJob do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :global ScriptLock; \r\ + \n :if ([ \$ScriptLock \$Script ] = false) do={:return false}\r\ + \n :foreach Job in=[ /system/script/job/find where script=\$Script ] do={\ + :set Job [ /system/script/job/get \$Job ];\r\ + \n :while ([ :typeof (\$Job->\"parent\") ] = \"id\") do={:set Job [ /sy\ + stem/script/job/get [ find where .id=(\$Job->\"parent\") ] ]}\r\ + \n :if ((\$Job->\"type\") = \"login\") do={:return true};}; :return fa\ + lse; \r\ + \n}\r\ + \n\r\ + \n:set InspectVar do={\r\ + \n :global InspectVarRet;\r\ + \n :put [ :tocrlf [ \$InspectVarRet \$1 ] ];\r\ + \n}\r\ + \n\r\ + \n:set CommitBrief do={\r\ + \n :global CommitId;\r\ + \n :global CommitInfo;\r\ + \n :if (\$CommitId = \"unknown\") do={\r\ + \n :return \"unknown\";\r\ + \n }\r\ + \n :return (\$CommitInfo . \"/\" . [ :pick \$CommitId 0 8 ]);\r\ + \n}\r\ + \n\r\ + \n:set InspectVarRet do={\r\ + \n :local Input \$1;\r\ + \n :local Level (0 + [ :tonum \$2 ]);\r\ + \n :global CharacterReplace;\r\ + \n :global IfThenElse;\r\ + \n :global InspectVarRet;\r\ + \n :local IndentReturn do={\r\ + \n :local Prefix [ :tostr \$1 ];\r\ + \n :local Value [ :tostr \$2 ];\r\ + \n :local Level [ :tonum \$3 ];\r\ + \n :global CharacterMultiply;\r\ + \n :return ([ \$CharacterMultiply \" \" (\$Level * 2) ] . \"-\" . \$Pre\ + fix . \"-> \" . \$Value);\r\ + \n }\r\ + \n :local TypeOf [ :typeof \$Input ];\r\ + \n :local Len [ :len \$Input ];\r\ + \n :local Return [ \$IndentReturn \"type\" \$TypeOf \$Level ];\r\ + \n :if (\$TypeOf = \"array\") do={\r\ + \n :foreach Key,Value in=\$Input do={\r\ + \n :set \$Return (\$Return . \"\\n\" . \\\r\ + \n [ \$IndentReturn \"key\" \$Key (\$Level + 1) ] . \"\\n\" . \\\r\ + \n [ \$InspectVarRet \$Value (\$Level + 2) ]);\r\ + \n }\r\ + \n } else={\r\ + \n :if (\$TypeOf = \"str\") do={\r\ + \n :set \$Return (\$Return . \"\\n\" . \\\r\ + \n [ \$IndentReturn \"len\" \$Len \$Level ]);\r\ + \n :if ([ :typeof [ :find \$Input (\"\\r\") ] ] = \"num\") do={\r\ + \n :set Input [ \$CharacterReplace \$Input (\"\\r\") \"\" ];\r\ + \n }\r\ + \n :if ([ :typeof [ :find \$Input (\"\\n\") ] ] = \"num\") do={\r\ + \n :set Input [ \$CharacterReplace \$Input (\"\\n\") \" \" ];\r\ + \n }\r\ + \n }\r\ + \n :if (\$TypeOf != \"nothing\") do={\r\ + \n :set \$Return (\$Return . \"\\n\" . \\\r\ + \n [ \$IndentReturn \"value\" [ \$IfThenElse ([ :len \$Input ] > 80)\ + \_\\\r\ + \n ([ :pick \$Input 0 77 ] . \"...\") \$Input ] \$Level ]);\r\ + \n }\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set GetPubIp do={\r\ + \n :global DetectIpAddrDefault;\r\ + \n :global DetectIpAddrFallback;\r\ + \n\r\ + \n :local PubIpAddr false;\r\ + \n :local Url \$DetectIpAddrDefault;\r\ + \n :local JobName [ :jobname ];\r\ + \n\r\ + \n :do {\r\ + \n :log debug (\$0 . \" Trying to detect public IP using default serv\ + ice: \" . \$Url . \"...\");\r\ + \n :retry command={:set PubIpAddr ([ /tool/fetch http-method=\"get\"\ + \_check-certificate=yes-without-crl \$Url output=user as-value ]->\"data\"\ + )} \\\r\ + \n delay=50ms max=5 on-error={:log error (\$JobName . \" Failed to \ + detect public IP using default service: \" . \$Url . \".\")}\r\ + \n } on-error={\r\ + \n :log error (\$0 . \" Failed to detect public IP using default serv\ + ice: \" . \$Url . \".\");\r\ + \n :set Url \$DetectIpAddrFallBack;\r\ + \n :log debug (\$0 . \" Trying to detect public IP using fallback ser\ + vice: \" . \$Url . \"...\");\r\ + \n :retry command={:set PubIpAddr ([ /tool/fetch http-method=\"get\"\ + \_check-certificate=yes-without-crl \$Url output=user as-value ]->\"data\"\ + )} \\\r\ + \n delay=200ms max=5 on-error={:log error (\$JobName . \" Failed to\ + \_detect public IP using fallback service: \" . \$Url . \".\")}\r\ + \n };\r\ + \n :local IpLen ([ :len \$PubIpAddr ] -1);\r\ + \n :if (\$PubIpAddr = false) do={:set PubIpAddr \"not-detected\"} else=\ + {:set PubIpAddr [:pick \$PubIpAddr 0 \$IpLen]}\r\ + \n :return \$PubIpAddr;\r\ + \n}\r\ + \n\r\ + \n:set FormatLine do={\r\ + \n :local Key [ :tostr \$1 ];\r\ + \n :local Value [ :tostr \$2 ];\r\ + \n :local Indent [ :tonum \$3 ];\r\ + \n :local Spaces;\r\ + \n :local Return \"\";\r\ + \n :global CharacterMultiply;\r\ + \n :global EitherOr;\r\ + \n :set Indent [ \$EitherOr \$Indent 16 ];\r\ + \n :local Spaces [ \$CharacterMultiply \" \" \$Indent ];\r\ + \n :if ([ :len \$Key ] > 0) do={ :set Return (\$Key . \":\")}\r\ + \n :if ([ :len \$Key ] > (\$Indent - 2)) do={:set Return (\$Return . \"\\\ + n\" . [ :pick \$Spaces 0 \$Indent ] . \$Value);\r\ + \n } else={:set Return (\$Return . [ :pick \$Spaces 0 (\$Indent - [ :len \ + \$Return ]) ] . \$Value)}\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set ParseCustom do={\r\ + \n :local Str [ :tostr \$1 ];\r\ + \n :local Start [:find [ \$Str ] [:tostr \$2]];\r\ + \n :local End [ :tostr \$3 ];\r\ + \n :local Num [ :tonum \$4 ];\r\ + \n :local Return;\r\ + \n :if ([:len \$Num] = 0) do={:set Num \"0\"}\r\ + \n :local rest [:pick \$Str (\$Start+\$Num) [:len \$Str]]; \r\ + \n :if ([:len \$End ] = 0) do={:set Return [:pick \$Str \$Num \$Start]} e\ + lse={\r\ + \n :set End [:find \$rest \$End];\r\ + \n :set Return [:pick \$rest 0 \$End];\r\ + \n }\r\ + \n:return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set LogPrint do={\r\ + \n :local Severity [ :tostr \$1 ];\r\ + \n :local Name [ :tostr \$2 ];\r\ + \n :local Message [ :tostr \$3 ];\r\ + \n :global PrintDebug;\r\ + \n :global PrintDebugOverride;\r\ + \n :global EitherOr;\r\ + \n :local Debug [ \$EitherOr (\$PrintDebugOverride->\$Name) \$PrintDebug \ + ];\r\ + \n :local PrintSeverity do={\r\ + \n :global TerminalColorOutput;\r\ + \n :if (\$TerminalColorOutput != true) do={:return \$1}\r\ + \n :local Color { debug=96; info=97; warning=93; error=91 };\r\ + \n :return (\"\\1B[\" . \$Color->\$1 . \"m\" . \$1 . \"\\1B[0m\");\r\ + \n}\r\ + \n :local Log ([ \$EitherOr \$Name \"\" ] . \": \" . \$Message);\ + \r\ + \n :if (\$Severity ~ (\"^(custom|debug|error|info)\\\$\")) do={\r\ + \n :if (\$Severity = \"debug\") do={:log debug \$Log}\r\ + \n :if (\$Severity = \"error\") do={:log error \$Log}\r\ + \n :if (\$Severity = \"info\" ) do={:log info \$Log}\r\ + \n } else={:log warning \$Log; :set Severity \"warning\"}\r\ + \n :if (\$Severity != \"debug\" || \$Debug = true) do={:put ([ \$PrintSev\ + erity \$Severity ] . \": \" . \$Message)}\r\ + \n}\r\ + \n\r\ + \n:set CertificateAvailable do={\r\ + \n :local CommonName [ :tostr \$1 ];\r\ + \n :local UseFor [ :tostr \$2 ];\r\ + \n\r\ + \n :global CertificateDownload;\r\ + \n :global ParseKeyValueStore;\r\ + \n\r\ + \n :if ([ :len \$UseFor ] = 0) do={\r\ + \n :log warning (\$0 . \"The intended use is undefined!\");\r\ + \n :set UseFor \"undefined\";\r\ + \n }\r\ + \n :if ([ /system/resource/get free-hdd-space ] < 8388608 && \\\r\ + \n [ /certificate/settings/get crl-download ] = true && \\\r\ + \n [ /certificate/settings/get crl-store ] = \"system\") do={\r\ + \n :log warning (\$0 . \"This system has low free flash space but \" . \ + \\\r\ + \n \"is configured to download certificate CRLs to system!\");\r\ + \n }\r\ + \n :if ([ :len \$CommonName ] = 0) do={\r\ + \n :log warning (\$0 . \"No CommonName given!\");\r\ + \n :return false;\r\ + \n }\r\ + \n :local CertSettings [ /certificate/settings/get ];\r\ + \n :if (((\$CertSettings->\"builtin-trust-anchors\") = \"trusted\" || \\\ + \r\ + \n (\$CertSettings->\"builtin-trust-store\") ~ \$UseFor || \\\r\ + \n (\$CertSettings->\"builtin-trust-store\") = \"all\") && \\\r\ + \n [ :len [ /certificate/builtin/find where common-name=\$CommonName\ + \_] ] > 0) do={\r\ + \n :return true;\r\ + \n }\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] = 0\ + ) do={\r\ + \n :log info (\$0 . \"Certificate with CommonName '\" . \$CommonName . \ + \"' not available.\");\r\ + \n :if ([ \$CertificateDownload \$CommonName ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] > 1\ + ) do={\r\ + \n :log info (\$0 . \"There are \" . \$CertCount . \" Certificates with\ + \_CommonName '\" . \$CommonName . \"'. Should be ok.\");\r\ + \n :return true;\r\ + \n }\r\ + \n :local CertVal [ /certificate/get [ find where common-name=\$CommonNam\ + e ] ];\r\ + \n :while ((\$CertVal->\"akid\") != \"\" && (\$CertVal->\"akid\") != (\$C\ + ertVal->\"skid\")) do={\r\ + \n :if ([ :len [ /certificate/find where skid=(\$CertVal->\"akid\") ] ]\ + \_= 0) do={\r\ + \n :local IssuerCN ([ \$ParseKeyValueStore (\$CertVal->\"issuer\") ]-\ + >\"CN\");\r\ + \n :log info (\$0 . \"Certificate chain for '\" . \$CommonName . \"' \ + is incomplete, missing '\" . \$IssuerCN . \"'.\");\r\ + \n :if ([ \$CertificateDownload \$IssuerCN ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n :set CertVal [ /certificate/get [ find where skid=(\$CertVal->\"akid\ + \") ] ];\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set CertificateDownload do={\r\ + \n :local CommonName [ :tostr \$1 ];\r\ + \n :global ScriptUpdatesBaseUrl;\r\ + \n :global ScriptUpdatesUrlSuffix;\r\ + \n :global CertificateNameByCN;\r\ + \n :global CleanName;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global RmFile;\r\ + \n :global WaitForFile;\r\ + \n\r\ + \n :log info (\$0 . \"Downloading and importing certificate with \" . \\\ + \r\ + \n \"CommonName '\" . \$CommonName . \"'.\");\r\ + \n :local FileName ([ \$CleanName \$CommonName ] . \".pem\");\r\ + \n :do {\r\ + \n /tool/fetch check-certificate=yes-without-crl mode=https http-header\ + -field=({ [ \$FetchUserAgentStr \$0 ] }) \\\r\ + \n (\$ScriptUpdatesBaseUrl . \"certs/\" . \$FileName . \$ScriptUpdate\ + sUrlSuffix) \\\r\ + \n dst-path=\$FileName as-value;\r\ + \n \$WaitForFile \$FileName;\r\ + \n } on-error={\r\ + \n :log warning (\$0 . \" Failed downloading certificate with CommonNam\ + e '\" . \$CommonName . \\\r\ + \n \"' from repository! Trying fallback to mkcert.org...\");\r\ + \n :do {\r\ + \n :local CertSettings [ /certificate/settings/get ];\r\ + \n :if ([ :len [ /certificate/find where common-name=\"ISRG Root X1\"\ + \_] ] = 0 && \\\r\ + \n !(((\$CertSettings->\"builtin-trust-anchors\") = \"trusted\" \ + || \\\r\ + \n (\$CertSettings->\"builtin-trust-store\") ~ \"fetch\" || \ + \\\r\ + \n (\$CertSettings->\"builtin-trust-store\") = \"all\") && \\\ + \r\ + \n [ :len [ /certificate/builtin/find where common-name=\"ISRG\ + \_Root X1\" ] ] > 0)) do={\r\ + \n :log error (\$0 . \" Required certificate is not available.\");\ + \r\ + \n :return false;\r\ + \n }\r\ + \n /tool/fetch check-certificate=yes-without-crl mode=https http-head\ + er-field=({ [ \$FetchUserAgentStr \$0 ] }) \\\r\ + \n url=\"https://mkcert.org/generate/\" http-data=[ :serialize to=jso\ + n ({ \$CommonName }) ] \\\r\ + \n dst-path=\$FileName as-value;\r\ + \n \$WaitForFile \$FileName;\r\ + \n :if ([ /file/get \$FileName size ] = 0) do={\r\ + \n \$RmFile \$FileName;\r\ + \n :error false;\r\ + \n }\r\ + \n } on-error={\r\ + \n :log error (\$0 . \" Failed downloading certificate with CommonNam\ + e '\" . \$CommonName . \"'!\");\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n /certificate/import file-name=\$FileName passphrase=\"\" as-value;\r\ + \n :delay 1s;\r\ + \n \$RmFile \$FileName;\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] = 0\ + ) do={\r\ + \n /certificate/remove [ find where name~(\"^\" . \$FileName . \"_[0-9]\ + +\\\$\") ];\r\ + \n :log warning (\$0 . \" Certificate with CommonName '\" . \$CommonNam\ + e . \"' still unavailable!\");\r\ + \n :return false;\r\ + \n }\r\ + \n :foreach Cert in=[ /certificate/find where name~(\"^\" . \$FileName . \ + \"_[0-9]+\\\$\") ] do={\r\ + \n \$CertificateNameByCN [ /certificate/get \$Cert common-name ];\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set CertificateNameByCN do={\r\ + \n :local Match [ :tostr \$1 ];\r\ + \n :global CleanName;\r\ + \n :local Cert ([ /certificate/find where (common-name=\$Match or fingerp\ + rint=\$Match or name=\$Match) ]->0);\r\ + \n :if ([ :len \$Cert ] = 0) do={\r\ + \n :log warning (\$0 .\" No matching certificate found.\");\r\ + \n :return false;\r\ + \n }\r\ + \n :local CommonName [ /certificate/get \$Cert common-name ];\r\ + \n /certificate/set \$Cert name=[ \$CleanName \$CommonName ];\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set CharacterMultiply do={\r\ + \n :local Str [ :tostr \$1 ];\r\ + \n :local Num [ :tonum \$2 ];\r\ + \n :if (\$Num = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :for I from=1 to=\$Num do={:set Return (\$Return . \$Str)}\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set FileExists do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :local Type [ :tostr \$2 ];\r\ + \n :global FileGet;\r\ + \n :local FileVal [ \$FileGet \$FileName ];\r\ + \n :if (\$FileVal = false) do={ :return false; }\r\ + \n :if ([ :len (\$FileVal->\"size\") ] = 0) do={ :return false; }\r\ + \n :if ([ :len \$Type ] = 0 || \$FileVal->\"type\" = \$Type) do={ :return\ + \_true; }\r\ + \n :return false;\r\ + \n}\r\ + \n\r\ + \n:set Grep do={\r\ + \n :local Input ([ :tostr \$1 ] . \"\\n\");\r\ + \n :local Pattern [ :tostr \$2 ];\r\ + \n :if ([ :typeof [ :find \$Input \$Pattern ] ] = \"nil\") do={:return []\ + }\r\ + \n :do {\r\ + \n :local Line [ :pick \$Input 0 [ :find \$Input \"\\n\" ] ];\r\ + \n :if ([ :typeof [ :find \$Line \$Pattern ] ] = \"num\") do={:return \ + \$Line}\r\ + \n :set Input [ :pick \$Input ([ :find \$Input \"\\n\" ] + 1) [ :len \$\ + Input ] ];\r\ + \n } while=([ :len \$Input ] > 0);\r\ + \n :return [];\r\ + \n}\r\ + \n\r\ + \n:set HumanReadableNum do={\r\ + \n :local Input [ :tonum \$1 ];\r\ + \n :local Base [ :tonum \$2 ];\r\ + \n :global EitherOr;\r\ + \n :global IfThenElse;\r\ + \n :local Prefix \"kMGTPE\";\r\ + \n :local Pow 1;\r\ + \n :set Base [ \$EitherOr \$Base 1024 ];\r\ + \n :local Bin [ \$IfThenElse (\$Base = 1024) \"i\" \"\" ];\r\ + \n :if (\$Input < \$Base) do={:return \$Input}\r\ + \n :for I from=0 to=[ :len \$Prefix ] do={\r\ + \n :set Pow (\$Pow * \$Base);\r\ + \n :if (\$Input / \$Base < \$Pow) do={\r\ + \n :set Prefix [ :pick \$Prefix \$I ];\r\ + \n :local Tmp1 (\$Input * 100 / \$Pow);\r\ + \n :local Tmp2 (\$Tmp1 / 100);\r\ + \n :if (\$Tmp2 >= 100) do={:return (\$Tmp2 . \$Prefix . \$Bin)}\r\ + \n :return (\$Tmp2 . \".\" . \\\r\ + \n [ :pick \$Tmp1 [ :len \$Tmp2 ] ([ :len \$Tmp1 ] - [ :len \$Tmp\ + 2 ] + 1) ] . \\\r\ + \n \$Prefix . \$Bin);\r\ + \n }\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set CleanFilePath do={\r\ + \n :local Path [ :tostr \$1 ];\r\ + \n :global CharacterReplace;\r\ + \n :while (\$Path ~ \"//\") do={ :set \$Path [ \$CharacterReplace \$Path \ + \"//\" \"/\" ]; }\r\ + \n :if ([ :pick \$Path 0 ] = \"/\") do={ :set Path [ :pick \$Path 1 [ :le\ + n \$Path ] ]; }\r\ + \n :if ([ :pick \$Path ([ :len \$Path ] - 1) ] = \"/\") do={ :set Path [ \ + :pick \$Path 0 ([ :len \$Path ] - 1) ]; }\r\ + \n :return \$Path;\r\ + \n}\r\ + \n\r\ + \n:set CleanName do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :local Return \"\";\r\ + \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ + \n :local Char [ :pick \$Input \$I ];\r\ + \n :if ([ :typeof [ find \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr\ + stuvwxyz0123456789\" \$Char ] ] = \"nil\") do={\r\ + \n :do {:if ([ :len \$Return ] = 0) do={:error true};\r\ + \n :if ([ :pick \$Return ([ :len \$Return ] - 1) ] = \"-\") do={:er\ + ror true}; :set Char \"-\"} on-error={:set Char \"\"}; \r\ + \n };\r\ + \n :set Return (\$Return . \$Char)};\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set RandomDelay do={\r\ + \n :local Time [ :tonum \$1 ];\r\ + \n :local Unit [ :tostr \$2 ];\r\ + \n :global EitherOr;\r\ + \n :global GetRandomNumber;\r\ + \n :global MAX;\r\ + \n :if (\$Time = 0) do={:return false}\r\ + \n :delay ([ \$MAX 10 [ \$GetRandomNumber ([ :tonsec [ :totime (\$Time . \ + [ \$EitherOr \$Unit \"s\" ]) ] ] / 1000000) ] ] . \"ms\");\r\ + \n}\r\ + \n\r\ + \n:set EscapeForRegEx do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :if ([ :len \$Input ] = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :local Chars (\"^.[]\\\$()|*+\?{}\\\\\");\r\ + \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ + \n :local Char [ :pick \$Input \$I ];\r\ + \n :if ([ :find \$Chars \$Char ]) do={:set Char (\"\\\\\" . \$Char)}\r\ + \n :set Return (\$Return . \$Char);\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set ExitError do={\r\ + \n :local ExitOK [ :tostr \$1 ];\r\ + \n :local Name [ :tostr \$2 ];\r\ + \n :local Error [ :tostr \$3 ];\r\ + \n :global IfThenElse;\r\ + \n :if (\$ExitOK = \"false\") do={\r\ + \n :log error (\$Name [ \$IfThenElse ([ :pick \$Name 0 1 ] = \"\\\$\") \ + \\\r\ + \n \"Function\" \"Script\" ] . \" '\" . \$Name . \"' exited with er\ + ror\" . \\\r\ + \n [ \$IfThenElse (!(\$Error ~ \"^(|true|false)\\\$\")) (\": \" . \ + \$Error) \".\" ]);\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set ExitOnError do={\r\ + \n :local Name [ :tostr \$1 ];\r\ + \n :local Error [ :tostr \$2 ];\r\ + \n :global IfThenElse;\r\ + \n :log error (\$Name . \" \" . [ \$IfThenElse ([ :pick \$Name 0 1 ] = \"\ + \\\$\") \\\r\ + \n \"Function\" \"Script\" ] . \" '\" . \$Name . \"' exited with erro\ + r\" . \\\r\ + \n [ \$IfThenElse (!(\$Error ~ \"^(|true|false)\\\$\")) (\": \" . \$E\ + rror) \".\" ]);\r\ + \n}\r\ + \n\r\ + \n:set MiniDateTimeStamp do={\r\ + \n :local mikro [ :tobool \$1 ];\r\ + \n /system/clock;\r\ + \n :local vdate [get date];\r\ + \n :local vtime [get time];\r\ + \n :local vdoff [:toarray \"0,4,5,7,8,10\"];\r\ + \n :local MM [:pick \$vdate (\$vdoff->2) (\$vdoff->3)];\r\ + \n :local M [:tonum \$MM];\r\ + \n :if (\$vdate ~ \".../../....\") do={\r\ + \n :set vdoff [:toarray \"7,11,1,3,4,6\"];\r\ + \n :set M ([:find \"xxanebarprayunulugepctovecANEBARPRAYUNULUGE\ + PCTOVEC\" [:pick \$vdate (\$vdoff->2) (\$vdoff->3)] -1] / 2);\r\ + \n :if (\$M>12) do={:set M (\$M - 12)}\r\ + \n :set MM [:pick (100 + \$M) 1 3];\r\ + \n }\r\ + \n :local yyyy [:pick \$vdate (\$vdoff->0) (\$vdoff->1)];\r\ + \n :local dd [:pick \$vdate (\$vdoff->4) (\$vdoff->5)];\r\ + \n :local HH [:pick \$vtime 0 2];\r\ + \n :local mm [:pick \$vtime 3 5];\r\ + \n :local ss [:pick \$vtime 6 8];\r\ + \n :local Return;\r\ + \n :if (\$mikro = true) do={\r\ + \n :set Return ([:pick \$yyyy 2 4] . [:pick \$dd 0 1] . [:pick \$HH 0\ + \_1] . [:pick \$mm 3 4] . [:pick \$ss 6 7]);\r\ + \n } else={\r\ + \n :set Return ([\$yyyy] . [\$MM] . [\$dd] . [\$HH] . [\$mm] . [\$ss]);\ + \r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set WaitForFile do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :local WaitTime [ :totime \$2 ];\r\ + \n :global CleanFilePath;\r\ + \n :global EitherOr;\r\ + \n :global MAX;\r\ + \n :set FileName [ \$CleanFilePath \$FileName ];\r\ + \n :local Delay ([ \$MAX [ \$EitherOr \$WaitTime 2s ] 100ms ] / 9);\r\ + \n :do {\r\ + \n :retry {\r\ + \n /file/get \$FileName;\r\ + \n :return true;\r\ + \n } delay=\$Delay max=10;\r\ + \n } on-error={ }\r\ + \n :while ([ :len [ /file/find where name=\$FileName ] ] > 0) do={\r\ + \n :do {\r\ + \n /file/get \$FileName;\r\ + \n :return true;\r\ + \n } on-error={ }\r\ + \n :delay \$Delay;\r\ + \n :set Delay (\$Delay * 3 / 2);\r\ + \n }\r\ + \n :return false;\r\ + \n}\r\ + \n\r\ + \n:set FileGet do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :global WaitForFile;\r\ + \n :if ([ \$WaitForFile \$FileName 0s ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n :local FileVal false;\r\ + \n :do {\r\ + \n :set FileVal [ /file/get \$FileName ];\r\ + \n } on-error={ }\r\ + \n :return \$FileVal;\r\ + \n}\r\ + \n\r\ + \n:set RmDir do={\r\ + \n :local DirName [ :tostr \$1 ];\r\ + \n :global FileGet;\r\ + \n :log debug (\$0 . \" Removing directory: \". \$DirName);\r\ + \n :local DirVal [ \$FileGet \$DirName ];\r\ + \n :if (\$DirVal = false) do={\r\ + \n :log debug (\$0 . \" ... which does not exist.\");\r\ + \n :return true;\r\ + \n };\r\ + \n :if (\$DirVal->\"type\" != \"directory\") do={\r\ + \n :log error (\$0 . \" Directory '\" . \$DirName . \"' is not a direct\ + ory.\");\r\ + \n :return false;\r\ + \n };\r\ + \n :onerror Err {\r\ + \n /file/remove \$DirName;\r\ + \n } do={\r\ + \n :log error (\$0 . \" Removing directory '\" . \$DirName . \"' failed\ + : \" . \$Err);\r\ + \n :return false;\r\ + \n };\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set RmFile do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :global FileGet;\r\ + \n :log debug (\$0 . \" Removing file: \". \$FileName);\r\ + \n :local FileVal [ \$FileGet \$FileName ];\r\ + \n :if (\$FileVal = false) do={\r\ + \n :log debug (\$0 . \" ... which does not exist.\");\r\ + \n :return true;\r\ + \n }\r\ + \n :if (\$FileVal->\"type\" = \"directory\" || \$FileVal->\"type\" = \"di\ + sk\") do={\r\ + \n :log error (\$0 . \" File '\" . \$FileName . \"' is not a file.\");\ + \r\ + \n :return false;\r\ + \n }\r\ + \n :onerror Err {\r\ + \n /file/remove \$FileName;\r\ + \n } do={\r\ + \n :log error (\$0 . \" Removing file '\" . \$FileName . \"' failed: \"\ + \_. \$Err); :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set MkDir do={\r\ + \n :local Path [ :tostr \$1 ];\r\ + \n :global CleanFilePath;\r\ + \n :global FileGet;\r\ + \n :global RmDir;\r\ + \n :global WaitForFile;\r\ + \n\r\ + \n :local MkTmpfs do={\r\ + \n :global WaitForFile;\r\ + \n :local TmpFs [ /disk/find where slot=tmpfs type=tmpfs ];\r\ + \n :if ([ :len \$TmpFs ] = 1) do={\r\ + \n :if ([ /disk/get \$TmpFs disabled ] = true) do={\r\ + \n :log info (\$0 . \" The tmpfs is disabled, enabling.\");\r\ + \n /disk/enable \$TmpFs;\r\ + \n }\r\ + \n :return true;\r\ + \n }\r\ + \n :log info (\$0 . \" Creating disk of type tmpfs.\");\r\ + \n \$RmDir \"tmpfs\";\r\ + \n :onerror Err {\r\ + \n /disk/add slot=tmpfs type=tmpfs tmpfs-max-size=([ /system/resource\ + /get total-memory ] / 3);\r\ + \n \$WaitForFile \"tmpfs\";\r\ + \n } do={\r\ + \n :log warning (\$0 . \" Creating disk of type tmpfs failed: \" . \$\ + Err);\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n }\r\ + \n :set Path [ \$CleanFilePath \$Path ];\r\ + \n :if (\$Path = \"\") do={\r\ + \n :return true;\r\ + \n }\r\ + \n :log debug (\$0 . \" Making directory: \" . \$Path);\r\ + \n :local PathVal [ \$FileGet \$Path ];\r\ + \n :if (\$PathVal->\"type\" = \"directory\") do={\r\ + \n :log debug (\$0 . \" ... which already exists.\");\r\ + \n :return true;\r\ + \n }\r\ + \n :if ([ :pick \$Path 0 5 ] = \"tmpfs\") do={\r\ + \n :if ([ \$MkTmpfs ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n :onerror Err {\r\ + \n /file/add type=\"directory\" name=\$Path;\r\ + \n \$WaitForFile \$Path;\r\ + \n } do={\r\ + \n :log warning (\$0 . \" Making directory '\" . \$Path . \"' failed: \ + \" . \$Err);\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set MAX do={:if (\$1 > \$2) do={:return \$1}\r\ + \n :return \$2;\r\ + \n}\r\ + \n:set MIN do={:if (\$1 < \$2) do={:return \$1}\r\ + \n :return \$2;\r\ + \n}\r\ + \n\r\ + \n:set CharacterMultiply do={\r\ + \n :local Str [ :tostr \$1 ];\r\ + \n :local Num [ :tonum \$2 ];\r\ + \n :if (\$Num = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :for I from=1 to=\$Num do={:set Return (\$Return . \$Str)}\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set CharacterReplace do={\r\ + \n :local String [ :tostr \$1 ];\r\ + \n :local ReplaceFrom [ :tostr \$2 ];\r\ + \n :local ReplaceWith [ :tostr \$3 ];\r\ + \n :local Return \"\";\r\ + \n :if (\$ReplaceFrom = \"\") do={:return \$String}\r\ + \n :while ([ :typeof [ :find \$String \$ReplaceFrom ] ] != \"nil\") do={\ + \r\ + \n :local Pos [ :find \$String \$ReplaceFrom ];\r\ + \n :set Return (\$Return . [ :pick \$String 0 \$Pos ] . \$ReplaceWith);\ + \r\ + \n :set String [ :pick \$String (\$Pos + [ :len \$ReplaceFrom ]) [ :len\ + \_\$String ] ];\r\ + \n }\r\ + \n :return (\$Return . \$String);\r\ + \n}\r\ + \n\r\ + \n:set IfThenElse do={\r\ + \n :if ([ :tostr \$1 ] = \"true\" || [ :tobool \$1 ] = true) do={:return \ + \$2};\r\ + \n :return \$3;\r\ + \n}\r\ + \n\r\ + \n:set EitherOr do={\r\ + \n :global IfThenElse;\r\ + \n :if ([ :typeof \$1 ] = \"num\") do={:return [ \$IfThenElse (\$1 != 0) \ + \$1 \$2 ]}\r\ + \n :if ([ :typeof \$1 ] = \"time\") do={:return [ \$IfThenElse (\$1 > 0s)\ + \_\$1 \$2 ]}\r\ + \n# this works for boolean values, literal ones with parentheses\r\ + \n :return [ \$IfThenElse ([ :len [ :tostr \$1 ] ] > 0) \$1 \$2 ];\r\ + \n}\r\ + \n\r\ + \n:set ParseKeyValueStore do={\r\ + \n :local Source \$1;\r\ + \n :if ([ :pick \$Source 0 1 ] = \"{\") do={\r\ + \n :do {\r\ + \n :return [ :deserialize from=json \$Source ];\r\ + \n } on-error={ }\r\ + \n } \r\ + \n :if ([ :typeof \$Source ] != \"array\") do={:set Source [ :tostr \$1 ]\ + }\r\ + \n :local Result ({});\r\ + \n :foreach KeyValue in=[ :toarray \$Source ] do={\r\ + \n :if ([ :find \$KeyValue \"=\" ]) do={\r\ + \n :local Key [ :pick \$KeyValue 0 [ :find \$KeyValue \"=\" ] ];\r\ + \n :local Value [ :pick \$KeyValue ([ :find \$KeyValue \"=\" ] + 1) [\ + \_:len \$KeyValue ] ];\r\ + \n :if (\$Value=\"true\") do={:set Value true}\r\ + \n :if (\$Value=\"false\") do={:set Value false}\r\ + \n :set (\$Result->\$Key) \$Value;\r\ + \n } else={:set (\$Result->\$KeyValue) true}\r\ + \n }\r\ + \n :return \$Result;\r\ + \n}\r\ + \n:set RequiredRouterOS do={\r\ + \n :local Caller [ :tostr \$1 ];\r\ + \n :local Required [ :tostr \$2 ];\r\ + \n :local Warn [ :tostr \$3 ];\r\ + \n :global IfThenElse;\r\ + \n :global VersionToNum;\r\ + \n :if (!(\$Required ~ \"^\\\\d+\\\\.\\\\d+((alpha|beta|rc|\\\\.)\\\\d+|)\ + \\\$\")) do={\r\ + \n :log error (\$0 . \" No valid RouterOS version: \" . \$Required);\r\ + \n :return false;\r\ + \n }\r\ + \n :if ([ \$VersionToNum \$Required ] > [ \$VersionToNum [ /system/packag\ + e/update/get installed-version ] ]) do={\r\ + \n :if (\$Warn = \"true\") do={\r\ + \n :log warning (\$0 . \" This \" . [ \$IfThenElse ([ :pick \$Caller \ + 0 ] = (\"\\\$\")) \"function\" \"script\" ] . \\\r\ + \n \" '\" . \$Caller . \"' (at least specific functionality) requir\ + es RouterOS \" . \$Required . \". Please update!\");\r\ + \n }\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set ValidateSyntax do={\r\ + \n :local Code [ :tostr \$1 ];\r\ + \n :global LogPrint;\r\ + \n :onerror Err {\r\ + \n [ :parse (\":local Validate do={\\n\" . \$Code . \"\\n}\") ];\r\ + \n } do={\r\ + \n \$LogPrint debug \$0 (\"Valdation failed: \" . \$Err);\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set VersionToNum do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :local Multi 0x1000000;\r\ + \n :local Return 0;\r\ + \n :global CharacterReplace;\r\ + \n :set Input [ \$CharacterReplace \$Input \".\" \",\" ];\r\ + \n :foreach I in={ \"zero\"; \"alpha\"; \"beta\"; \"rc\" } do={\r\ + \n :set Input [ \$CharacterReplace \$Input \$I (\",\" . \$I . \",\") ];\ + \r\ + \n }\r\ + \n :foreach Value in=([ :toarray \$Input ], 0) do={\r\ + \n :local Num [ :tonum \$Value ];\r\ + \n :if (\$Multi = 0x100) do={\r\ + \n :if ([ :typeof \$Num ] = \"num\") do={\r\ + \n :set Return (\$Return + 0xff00);\r\ + \n :set Multi (\$Multi / 0x100);\r\ + \n } else={\r\ + \n :if (\$Value = \"zero\") do={ }\r\ + \n :if (\$Value = \"alpha\") do={ :set Return (\$Return + 0x3f00); \ + }\r\ + \n :if (\$Value = \"beta\") do={ :set Return (\$Return + 0x5f00); }\ + \r\ + \n :if (\$Value = \"rc\") do={ :set Return (\$Return + 0x7f00); }\r\ + \n }\r\ + \n }\r\ + \n :if ([ :typeof \$Num ] = \"num\") do={ :set Return (\$Return + (\$Va\ + lue * \$Multi)); }\r\ + \n :set Multi (\$Multi / 0x100);\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set ScriptLock do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local WaitMax [ :totime \$2 ];\r\ + \n :global GetRandom20CharAlNum;\r\ + \n :global IfThenElse;\r\ + \n :global ScriptLockOrder;\r\ + \n :if ([ :typeof \$ScriptLockOrder ] = \"nothing\") do={\r\ + \n :set ScriptLockOrder ({});\r\ + \n }\r\ + \n :if ([ :typeof (\$ScriptLockOrder->\$Script) ] = \"nothing\") do={\r\ + \n :set (\$ScriptLockOrder->\$Script) ({});\r\ + \n }\r\ + \n :local JobCount do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :return [ :len [ /system/script/job/find where script=\$Script ] ];\ + \r\ + \n }\r\ + \n :local TicketCount do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :local Count 0;\r\ + \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :if ([ :typeof \$Ticket ] != \"nothing\") do={:set Count (\$Count \ + + 1)}\r\ + \n }\r\ + \n :return \$Count;\r\ + \n }\r\ + \n :local IsFirstTicket do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local Check [ :tostr \$2 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :if (\$Ticket = \$Check) do={:return true}\r\ + \n :if ([ :typeof \$Ticket ] != \"nothing\" && \$Ticket != \$Check) d\ + o={:return false}\r\ + \n }\r\ + \n :return false;\r\ + \n }\r\ + \n :local AddTicket do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local Add [ :tostr \$2 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :while (true) do={\r\ + \n :local Pos [ :len (\$ScriptLockOrder->\$Script) ];\r\ + \n :set (\$ScriptLockOrder->\$Script->\$Pos) \$Add;\r\ + \n :delay 10ms;\r\ + \n :if ((\$ScriptLockOrder->\$Script->\$Pos) = \$Add) do={:return tru\ + e}\r\ + \n }\r\ + \n }\r\ + \n :local RemoveTicket do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local Remove [ :tostr \$2 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :foreach Id,Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :while ((\$ScriptLockOrder->\$Script->\$Id) = \$Remove) do={\r\ + \n :set (\$ScriptLockOrder->\$Script->\$Id);\r\ + \n :delay 10ms;\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n :local CleanupTickets do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :if ([ :typeof \$Ticket ] != \"nothing\") do={:return false}\r\ + \n }\r\ + \n :set (\$ScriptLockOrder->\$Script) ({});\r\ + \n }\r\ + \n :if ([ :typeof \$WaitMax ] = \"nil\" ) do={:set WaitMax 0s}\r\ + \n :if ([ :len [ /system/script/find where name=\$Script ] ] = 0) do={\r\ + \n :log error (\$0 . \" A script named '\" . \$Script . \"' does not ex\ + ist!\");\r\ + \n :error false;\r\ + \n }\r\ + \n :if ([ \$JobCount \$Script ] = 0) do={\r\ + \n \$LogPrint error \$0 (\"No script '\" . \$Script . \"' is running!\"\ + );\r\ + \n :error false;\r\ + \n }\r\ + \n :if ([ \$TicketCount \$Script ] >= [ \$JobCount \$Script ]) do={\r\ + \n :log error (\$0 . \" More tickets than running scripts '\" . \$Scrip\ + t . \"', resetting!\");\r\ + \n :set (\$ScriptLockOrder->\$Script) ({});\r\ + \n /system/script/job/remove [ find where script=\$Script ];\r\ + \n }\r\ + \n :local MyTicket [ \$GetRandom20CharAlNum 6 ];\r\ + \n \$AddTicket \$Script \$MyTicket;\r\ + \n :local WaitInterval (\$WaitMax / 20);\r\ + \n :local WaitTime \$WaitMax;\r\ + \n :while (\$WaitTime > 0 && \\\r\ + \n ([ \$IsFirstTicket \$Script \$MyTicket ] = false || \\\r\ + \n [ \$TicketCount \$Script ] < [ \$JobCount \$Script ])) do={\r\ + \n :set WaitTime (\$WaitTime - \$WaitInterval);\r\ + \n :delay \$WaitInterval;\r\ + \n }\r\ + \n :if ([ \$IsFirstTicket \$Script \$MyTicket ] = true && \\\r\ + \n [ \$TicketCount \$Script ] = [ \$JobCount \$Script ]) do={\r\ + \n \$RemoveTicket \$Script \$MyTicket;\r\ + \n \$CleanupTickets \$Script;\r\ + \n :return true;\r\ + \n }\r\ + \n \$RemoveTicket \$Script \$MyTicket;\r\ + \n \$LogPrint debug \$0 (\"Script '\" . \$Script . \"' started more than \ + once\" . \\\r\ + \n [ \$IfThenElse (\$WaitTime < \$WaitMax) \" and timed out waiting for\ + \_lock\" \"\" ] . \"...\");\r\ + \n :return false;\r\ + \n}\r\ + \n\r\ + \n:set SendNotification do={ :onerror Err {\r\ + \n :global SendNotification2;\r\ + \n \$SendNotification2 ({ origin=\$0; subject=\$1; message=\$2; link=\$3;\ + \_silent=\$4 });\r\ + \n} do={:global ExitOnError; \$ExitOnError \$0 \$Err}\r\ + \n}\r\ + \n\r\ + \n:set SendNotification2 do={\r\ + \n :local Notification \$1;\r\ + \n :global NotificationFunctions;\r\ + \n :foreach FunctionName,Discard in=\$NotificationFunctions do={\r\ + \n (\$NotificationFunctions->\$FunctionName) (\"\\\$NotificationFunctio\ + ns->\\\"\" . \$FunctionName . \"\\\"\") \$Notification;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set SymbolByUnicodeName do={\r\ + \n :local Name [ :tostr \$1 ];\r\ + \n :global EitherOr;\r\ + \n :global SymbolsExtra;\r\ + \n :local Symbols ({\r\ + \n \"abacus\"=\"\\F0\\9F\\A7\\AE\";\r\ + \n \"alarm-clock\"=\"\\E2\\8F\\B0\";\r\ + \n \"arrow-down\"=\"\\E2\\AC\\87\";\r\ + \n \"arrow-up\"=\"\\E2\\AC\\86\";\r\ + \n \"calendar\"=\"\\F0\\9F\\93\\85\";\r\ + \n \"card-file-box\"=\"\\F0\\9F\\97\\83\";\r\ + \n \"chart-decreasing\"=\"\\F0\\9F\\93\\89\";\r\ + \n \"chart-increasing\"=\"\\F0\\9F\\93\\88\";\r\ + \n \"cloud\"=\"\\E2\\98\\81\";\r\ + \n \"cross-mark\"=\"\\E2\\9D\\8C\";\r\ + \n \"earth\"=\"\\F0\\9F\\8C\\8D\";\r\ + \n \"fire\"=\"\\F0\\9F\\94\\A5\";\r\ + \n \"floppy-disk\"=\"\\F0\\9F\\92\\BE\";\r\ + \n \"gear\"=\"\\E2\\9A\\99\";\r\ + \n \"heart\"=\"\\E2\\99\\A5\";\r\ + \n \"high-voltage-sign\"=\"\\E2\\9A\\A1\";\r\ + \n \"incoming-envelope\"=\"\\F0\\9F\\93\\A8\";\r\ + \n \"information\"=\"\\E2\\84\\B9\";\r\ + \n \"large-orange-circle\"=\"\\F0\\9F\\9F\\A0\";\r\ + \n \"large-red-circle\"=\"\\F0\\9F\\94\\B4\";\r\ + \n \"link\"=\"\\F0\\9F\\94\\97\";\r\ + \n \"lock-with-ink-pen\"=\"\\F0\\9F\\94\\8F\";\r\ + \n \"memo\"=\"\\F0\\9F\\93\\9D\";\r\ + \n \"mobile-phone\"=\"\\F0\\9F\\93\\B1\";\r\ + \n \"pushpin\"=\"\\F0\\9F\\93\\8C\";\r\ + \n \"scissors\"=\"\\E2\\9C\\82\";\r\ + \n \"scroll\"=\"\\F0\\9F\\93\\9C\";\r\ + \n \"smiley-partying-face\"=\"\\F0\\9F\\A5\\B3\";\r\ + \n \"smiley-smiling-face\"=\"\\E2\\98\\BA\";\r\ + \n \"smiley-winking-face-with-tongue\"=\"\\F0\\9F\\98\\9C\";\r\ + \n \"sparkles\"=\"\\E2\\9C\\A8\";\r\ + \n \"speech-balloon\"=\"\\F0\\9F\\92\\AC\";\r\ + \n \"star\"=\"\\E2\\AD\\90\";\r\ + \n \"warning-sign\"=\"\\E2\\9A\\A0\";\r\ + \n \"white-heavy-check-mark\"=\"\\E2\\9C\\85\"\r\ + \n }, \$SymbolsExtra);\r\ + \n :local Magic [ :pick [ /system/clock/get date ] 4 10 ];\r\ + \n :local Special {\r\ + \n \"information-04-01\"=\"\\F0\\9F\\9A\\BB\";\r\ + \n \"large-orange-circle-04-01\"=\"\\F0\\9F\\8D\\8A\";\r\ + \n \"large-orange-circle-10-31\"=\"\\F0\\9F\\8E\\83\";\r\ + \n \"large-red-circle-04-01\"=\"\\F0\\9F\\8D\\92\" };\r\ + \n :if ([ :len (\$Symbols->\$Name) ] = 0) do={\r\ + \n :log warning (\$0 . \"No symbol available for name '\" . \$Name . \"\ + '!\");\r\ + \n :return \"\";\r\ + \n }\r\ + \n :return ([ \$EitherOr (\$Special->(\$Name . \$Magic)) (\$Symbols->\$Na\ + me) ] . \"\\EF\\B8\\8F\");\r\ + \n}\r\ + \n\r\ + \n:set SymbolForNotification do={\r\ + \n :global NotificationsWithSymbols;\r\ + \n :global SymbolByUnicodeName;\r\ + \n :global IfThenElse;\r\ + \n :if (\$NotificationsWithSymbols != true) do={:return [ \$IfThenElse ([\ + \_:len \$2 ] > 0) ([ :tostr \$2 ] . \" \") \"\" ]}\r\ + \n :local Return \"\";\r\ + \n :foreach Symbol in=[ :toarray \$1 ] do={:set Return (\$Return . [ \$Sy\ + mbolByUnicodeName \$Symbol ])}\r\ + \n :return (\$Return . \" \");\r\ + \n}\r\ + \n\r\ + \n:set Unix2Dos do={:return [ :tocrlf [ :tostr \$1 ] ]}\r\ + \n:set UrlEncode do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :if ([ :len \$Input ] = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :local Chars (\"\\n\\r !\\\"#\\\$%&'()*+,:;<=>\?@[\\\\]^`{|}~\");\r\ + \n :local Subs { \"%0A\"; \"%0D\"; \"%20\"; \"%21\"; \"%22\"; \"%23\"; \"\ + %24\"; \"%25\"; \"%26\"; \"%27\";\r\ + \n \"%28\"; \"%29\"; \"%2A\"; \"%2B\"; \"%2C\"; \"%3A\"; \"%3B\"; \ + \"%3C\"; \"%3D\"; \"%3E\"; \"%3F\";\r\ + \n \"%40\"; \"%5B\"; \"%5C\"; \"%5D\"; \"%5E\"; \"%60\"; \"%7B\"; \ + \"%7C\"; \"%7D\"; \"%7E\" };\r\ + \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ + \n :local Char [ :pick \$Input \$I ];\r\ + \n :local Replace [ :find \$Chars \$Char ];\r\ + \n :if ([ :typeof \$Replace ] = \"num\") do={:set Char (\$Subs->\$Repla\ + ce)}\r\ + \n :set Return (\$Return . \$Char);\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set IsDNSResolving do={\r\ + \n :do {:resolve \"api.telegram.org\"} on-error={:return false}\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set IsFullyConnected do={\r\ + \n :global IsDNSResolving;\r\ + \n :global IsTimeSync;\r\ + \n :if ([ \$IsDNSResolving ] = false) do={:return false};\r\ + \n :if ([ \$IsTimeSync ] = false) do={:return false};\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set IsTimeSync do={\r\ + \n :global IsTimeSyncCached;\r\ + \n :global IsTimeSyncResetNtp;\r\ + \n :if (\$IsTimeSyncCached = true) do={:return true}\r\ + \n :if ([ /system/ntp/client/get enabled ] = true) do={\r\ + \n :if ([ /system/ntp/client/get status ] = \"synchronized\") do={\r\ + \n :set IsTimeSyncCached true;\r\ + \n :return true;\r\ + \n }\r\ + \n :local Uptime [ /system/resource/get uptime ];\r\ + \n :if ([ :typeof \$IsTimeSyncResetNtp ] = \"nothing\") do={\r\ + \n :set IsTimeSyncResetNtp \$Uptime;\r\ + \n }\r\ + \n :if (\$Uptime - \$IsTimeSyncResetNtp < 3m) do={:return false}\r\ + \n :log warning \"\$0 The ntp client is configured, but did not sync.\"\ + ;\r\ + \n :set IsTimeSyncResetNtp \$Uptime;\r\ + \n /system/ntp/client/set enabled=no;\r\ + \n :delay 20ms;\r\ + \n /system/ntp/client/set enabled=yes;\r\ + \n :return false;\r\ + \n }\r\ + \n :if ([ /system/license/get ]->\"level\" = \"free\" || \\\r\ + \n [ /system/resource/get ]->\"board-name\" = \"x86\") do={\r\ + \n :log debug \"\$0 No ntp client configured, relying on RTC for CHR fr\ + ee license and x86.\";\r\ + \n :return true;\r\ + \n }\r\ + \n :if ([ /ip/cloud/get update-time ] = true) do={\r\ + \n :if ([ :typeof [ /ip/cloud/get public-address ] ] = \"ip\") do={\r\ + \n :set IsTimeSyncCached true;\r\ + \n :return true;\r\ + \n }\r\ + \n :return false;\r\ + \n }\r\ + \n :log debug \"\$0 No time source configured! Returning gracefully...\";\ + \r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set FetchHugeFiles do={\r\ + \n :local ScriptName [ :tostr \$1 ];\r\ + \n :local Url [ :tostr \$2 ];\r\ + \n :local CheckCert [ :tostr \$3 ];\r\ + \n\r\ + \n :global CleanName;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global GetRandom20CharAlNum;\r\ + \n :global IfThenElse;\r\ + \n :global LogPrint;\r\ + \n :global MkDir;\r\ + \n :global RmDir;\r\ + \n :global RmFile;\r\ + \n :global WaitForFile;\r\ + \n\r\ + \n :set CheckCert [ \$IfThenElse (\$CheckCert = \"false\") \"no\" \"yes-w\ + ithout-crl\" ];\r\ + \n\r\ + \n :local DirName (\"tmpfs/\" . [ \$CleanName \$ScriptName ]);\r\ + \n :if ([ \$MkDir \$DirName ] = false) do={\r\ + \n \$LogPrint error \$0 (\"Failed creating directory!\");\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :local FileName (\$DirName . \"/\" . [ \$CleanName \$0 ] . \"-\" . [ \ + \$GetRandom20CharAlNum ]);\r\ + \n :onerror Err {\r\ + \n /tool/fetch check-certificate=\$CheckCert \$Url dst-path=\$FileName \ + \\\r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$ScriptName ] }) as-va\ + lue;\r\ + \n } do={\r\ + \n :if ([ \$WaitForFile \$FileName 500ms ] = true) do={\r\ + \n \$RmFile \$FileName;\r\ + \n }\r\ + \n \$LogPrint debug \$0 (\"Failed downloading from \" . \$Url . \" - \"\ + \_. \$Err);\r\ + \n \$RmDir \$DirName;\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :if ([ \$WaitForFile \$FileName 5s ] = false) do={\r\ + \n \$LogPrint debug \$0 (\"The file downloaded from \" . \$Url . \" did\ + \_not show up.\");\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :local FileSize [ /file/get \$FileName size ];\r\ + \n :local Return \"\";\r\ + \n :local VarSize 0;\r\ + \n :while (\$VarSize != \$FileSize) do={\r\ + \n :set Return (\$Return . ([ /file/read offset=\$VarSize chunk-size=32\ + 768 file=\$FileName as-value ]->\"data\"));\r\ + \n :set FileSize [ /file/get \$FileName size ];\r\ + \n :set VarSize [ :len \$Return ];\r\ + \n :if (\$VarSize > \$FileSize) do={\r\ + \n :delay 100ms;\r\ + \n }\r\ + \n }\r\ + \n \$RmDir \$DirName;\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set FetchUserAgentStr do={\r\ + \n :local Caller [ :tostr \$1 ];\r\ + \n :global GlobalScriptsUrl;\r\ + \n :global CommitBrief;\r\ + \n :global IfThenElse;\r\ + \n :local Resource [ /system/resource/get ];\r\ + \n :return (\"User-Agent: Mikrotik/\" . \$Resource->\"version\" . \" \" .\ + \_\$Resource->\"architecture-name\" . \\\r\ + \n \" \" . \$Caller . \"/Fetch (\" . \$GlobalScriptsUrl . \"; \" . [ \$\ + CommitBrief ] . \")\");\r\ + \n}\r\ + \n\r\ + \n:set ScriptInstallUpdate do={ :onerror Err {\r\ + \n :local Scripts [ :toarray \$1 ];\r\ + \n :local NewComment [ :tostr \$2 ];\r\ + \n :global InitSetup;\r\ + \n\r\ + \n :global CommitId;\r\ + \n :global ScriptUpdatesCRLF;\r\ + \n :global GlobalConfVersion;\r\ + \n :global Identity;\r\ + \n :global CertificateAvailable;\r\ + \n :global CheckSumsVerify;\r\ + \n :global GlobalScriptsUrl;\r\ + \n :global SumsDirAndFileName;\r\ + \n :global GlobalScriptsUrlSuffix;\r\ + \n :global EitherOr;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global Grep;\r\ + \n :global IfThenElse;\r\ + \n :global LogPrint;\r\ + \n :global ParseKeyValueStore;\r\ + \n :global RequiredRouterOS;\r\ + \n :global SendNotification2;\r\ + \n :global SymbolForNotification;\r\ + \n :global ValidateSyntax;\r\ + \n :global CommentsInScripts;\r\ + \n\r\ + \n :if ([ \$CertificateAvailable \"Root YE\" \"fetch\" ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Downloading certificate failed, trying wit\ + hout.\");\r\ + \n }\r\ + \n\r\ + \n :foreach Script in=\$Scripts do={\r\ + \n :if ([ :len [ /system/script/find where name=\$Script ] ] = 0) do={\ + \r\ + \n \$LogPrint info \$0 (\"Adding new script: \" . \$Script);\r\ + \n /system/script/add name=\$Script owner=\$Script source=\"#!rsc by \ + Vados\\n\" comment=\$NewComment;\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :local CommitIdBefore \$CommitId;\r\ + \n :local GlobalConfVersionBefore \$GlobalConfVersion;\r\ + \n :local ReloadGlobal false;\r\ + \n :local DeviceMode [ /system/device-mode/get ];\r\ + \n\r\ + \n :if (\$CheckSumsVerify = true) do={\r\ + \n :local CheckSums ({});\r\ + \n :do {\r\ + \n :local Url (\$GlobalScriptsUrl . \$SumsDirAndFileName . \$GlobalScr\ + iptsUrlSuffix);\r\ + \n \$LogPrint debug \$0 (\"Fetching checksums from url: \" . \$Url);\ + \r\ + \n :set CheckSums [ :deserialize from=json ([ /tool/fetch check-certi\ + ficate=yes-without-crl \\\r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$0 ] }) \$Url output\ + =user as-value ]->\"data\") ];\r\ + \n } on-error={ \$LogPrint warning \$0 (\"Err = \" . \$Err); }\r\ + \n }\r\ + \n\r\ + \n :foreach Script in=[ /system/script/find where source~\"^#!rsc by Vado\ + s\" ] do={\r\ + \n :local ScriptVal [ /system/script/get \$Script ];\r\ + \n :local ScriptInfo [ \$ParseKeyValueStore (\$ScriptVal->\"comment\") \ + ];\r\ + \n :local SourceNew;\r\ + \n\r\ + \n :foreach Scheduler in=[ /system/scheduler/find where on-event~(\"\\\ + \\b\" . \$ScriptVal->\"name\" . \"\\\\b\") ] do={\r\ + \n :local SchedulerVal [ /system/scheduler/get \$Scheduler ];\r\ + \n :if (\$ScriptVal->\"policy\" != \$SchedulerVal->\"policy\") do={\r\ + \n \$LogPrint warning \$0 (\"Policies differ for script '\" . \$Scr\ + iptVal->\"name\" . \"' and its scheduler '\" . \$SchedulerVal->\"name\" . \ + \"'!\");\r\ + \n }\r\ + \n }\r\ + \n :do {\r\ + \n :if (\$ScriptInfo->\"ignore\" = true) do={\r\ + \n \$LogPrint debug \$0 (\"Ignoring script '\" . \$ScriptVal->\"nam\ + e\" . \"', as requested.\");\r\ + \n :error true;\r\ + \n }\r\ + \n :if (\$CheckSumsVerify = true) do={\r\ + \n :local CheckSum (\$CheckSums->(\$ScriptVal->\"name\"));\r\ + \n :if ([ :len (\$ScriptInfo->\"base-url\") ] = 0 && [ :len (\$Scri\ + ptInfo->\"url-suffix\") ] = 0 && \\\r\ + \n [ :convert transform=md5 to=hex [ :tolf (\$ScriptVal->\"sou\ + rce\") ] ] = \$CheckSum) do={\r\ + \n \$LogPrint debug \$0 (\"Checksum for script '\" . \$ScriptVal-\ + >\"name\" . \"' matches, ignoring.\");\r\ + \n :error true;\r\ + \n }\r\ + \n }\r\ + \n :if ([ :len (\$ScriptInfo->\"certificate\") ] > 0) do={\r\ + \n :if ([ \$CertificateAvailable (\$ScriptInfo->\"certificate\") \"\ + fetch\" ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Downloading certificate failed, tryi\ + ng without.\");\r\ + \n }\r\ + \n }\r\ + \n :onerror Err {\r\ + \n :local BaseUrl [ \$EitherOr (\$ScriptInfo->\"base-url\") \$Globa\ + lScriptsUrl ];\r\ + \n :local UrlSuffix [ \$EitherOr (\$ScriptInfo->\"url-suffix\") \$G\ + lobalScriptsUrlSuffix ];\r\ + \n :local Url (\$BaseUrl . \$ScriptVal->\"name\" . \".rsc\" . \$Url\ + Suffix);\r\ + \n \$LogPrint warning \$0 (\"Fetching script '\" . (\$ScriptVal->\"\ + name\") . \"' from url: \" . \$Url);\r\ + \n :local Result [ /tool/fetch check-certificate=yes-without-crl \\\ + \r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$0 ] }) \$Url outp\ + ut=user as-value ];\r\ + \n :if (\$Result->\"status\" = \"finished\") do={\r\ + \n :set SourceNew [ :tolf (\$Result->\"data\") ];\r\ + \n } \r\ + \n } do={\r\ + \n \$LogPrint warning \$0 (\"Failed fetching script '\" . \$ScriptV\ + al->\"name\" . \"': \" . \$Err);\r\ + \n :if (\$Err != \"Fetch failed with status 404\") do={\r\ + \n :error false;\r\ + \n }\r\ + \n :if (\$ScriptVal->\"source\" = \"#!rsc by Vados\") do={\r\ + \n \$LogPrint warning \$0 (\"Removing dummy. Typo on installation\ + \?\");\r\ + \n /system/script/remove \$Script;\r\ + \n :error false;\r\ + \n }\r\ + \n :if (\$CheckSumsVerify = true) do={\r\ + \n :if ([ :len (\$ScriptInfo->\"base-url\") ] = 0 && [ :len (\$Sc\ + riptInfo->\"url-suffix\") ] = 0 && \\\r\ + \n [ :len \$CheckSum ] = 0) do={\r\ + \n \$LogPrint warning \$0 (\"Added the script manually\? Skip u\ + pdates with 'ignore=true' in comment.\");\r\ + \n }\r\ + \n }\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :if ([ :len \$SourceNew ] = 0) do={\r\ + \n \$LogPrint debug \$0 (\"No update for script '\" . (\$ScriptVal-\ + >\"name\") . \"'.\");\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :local SourceCRLF [ :tocrlf \$SourceNew ];\r\ + \n :if (\$InitSetup != true && ((\$ScriptVal->\"name\") != \"AM-Globa\ + lConfig\" || (\$ScriptVal->\"name\") != \"AM-GlobalFunc\")) do={\r\ + \n :if (\$SourceNew = (\$ScriptVal->\"source\") || \$SourceCRLF = (\ + \$ScriptVal->\"source\")) do={\r\ + \n \$LogPrint debug \$0 (\"Script '\" . (\$ScriptVal->\"name\") \ + . \"' source did not change. End of lines set to CRLF.\");\r\ + \n if (\$ScriptUpdatesCRLF = false) do={\r\ + \n :put [ :tolf \$SourceNew ];\r\ + \n \$LogPrint debug \$0 (\"Script '\" . (\$ScriptVal->\"name\"\ + ) . \"' source update end of lines to LF.\");\r\ + \n }\r\ + \n :error false;\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :if ([ :pick \$SourceNew 0 14 ] != \"#!rsc by Vados\") do={\r\ + \n \$LogPrint warning \$0 (\"Looks like new script '\" . \$ScriptVa\ + l->\"name\" . \"' is not valid (missing shebang = '\$shebang') Ignoring!\"\ + );\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :if (\$CommentsInScripts = true) do={\r\ + \n :local CommentLine [ \$Grep \$SourceNew (\"\\23 Script comment:\ + \_\") ];\r\ + \n :if ([ :len \$CommentLine ] = 0) do={\r\ + \n \$LogPrint debug \$0 (\"The search in new script '\" . (\$Scr\ + iptVal->\"name\") . \"' for comment in script body, is not found result Ig\ + noring!\");\r\ + \n :error false;\r\ + \n } else={\r\ + \n :if ([ :len (\$ScriptVal->\"comment\")] = 0 || [ :len (\$Scri\ + ptVal->\"comment\")] != [ :pick \$CommentLine ([ :find \$CommentLine \":\"\ + ] + 2) [ :len \$CommentLine] ]) do={\r\ + \n \$LogPrint debug \$0 (\"Exsiting comment for script '\" . (\ + \$ScriptVal->\"name\") . \"' is '\" . (\$ScriptVal->\"comment\") . \"'.\")\ + ;\r\ + \n :set (\$ScriptVal->\"comment\") [ :pick \$CommentLine ([ :f\ + ind \$CommentLine \":\"] + 2) [ :len \$CommentLine] ];\r\ + \n \$LogPrint debug \$0 (\"New comment (\" . (\$ScriptVal->\"c\ + omment\") . \") for script '\" . (\$ScriptVal->\"name\") . \"' has been ad\ + ded!\");\r\ + \n } else={\r\ + \n \$LogPrint debug \$0 (\"Comment for script '\" . (\$ScriptV\ + al->\"name\") . \"' did not change.\");\r\ + \n :error false;\r\ + \n }\r\ + \n } \r\ + \n }\r\ + \n\r\ + \n :local RequiredROS ([ \$ParseKeyValueStore [ \$Grep \$SourceNew (\ + \"\\23 requires RouterOS, \") ] ]->version);\r\ + \n :if ([ \$RequiredRouterOS \$0 [ \$EitherOr \$RequiredROS \"0.0\" ]\ + \_false ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"The script '\" . (\$ScriptVal->\"name\ + \") . \"' requires RouterOS \" . \\\r\ + \n \$RequiredROS . \", which is not met by your installation. I\ + gnoring!\");\r\ + \n :error false;\r\ + \n }\r\ + \n :local RequiredDM [ \$ParseKeyValueStore [ \$Grep \$SourceNew (\"\ + \\23 requires device-mode, \") ] ];\r\ + \n :local MissingDM ({});\r\ + \n :foreach Feature,Value in=\$RequiredDM do={\r\ + \n :if ([ :typeof (\$DeviceMode->\$Feature) ] = \"bool\" && (\$Devi\ + ceMode->\$Feature) = false) do={\r\ + \n :set MissingDM (\$MissingDM, \$Feature);\r\ + \n }\r\ + \n }\r\ + \n :if ([ :len \$MissingDM ] > 0) do={\r\ + \n \$LogPrint warning \$0 (\"The script '\" . (\$ScriptVal->\"name\ + \") . \"' requires disabled \" . \\\r\ + \n \"device-mode features (\" . [ :tostr \$MissingDM ] . \"). I\ + gnoring!\");\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :if ([ \$ValidateSyntax \$SourceNew ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Syntax validation for script '\" . (\$\ + ScriptVal->\"name\") . \"' failed! Ignoring!\");\r\ + \n :error false;\r\ + \n }\r\ + \n \r\ + \n :log info (\"Updating script: \" . (\$ScriptVal->\"name\") . \" Sc\ + ript comment: \" . (\$ScriptVal->\"comment\"));\r\ + \n\r\ + \n /system/script/set owner=(\$ScriptVal->\"name\") comment=(\$Script\ + Val->\"comment\") \\\r\ + \n source=[ \$IfThenElse (\$ScriptUpdatesCRLF = true) \$SourceCRL\ + F \$SourceNew ] \$Script;\r\ + \n :if (\$ScriptVal->\"name\" = \"AM-GlobalConfig\" || \\\r\ + \n \$ScriptVal->\"name\" = \"AM-GlobalFunc\" || \\\r\ + \n \$ScriptVal->\"name\" ~ (\"^(AM-GlobalFunc\\\\.d|mod)/.\")) d\ + o={\r\ + \n :set ReloadGlobal true;\r\ + \n }\r\ + \n } on-error={ }\r\ + \n }\r\ + \n :if (\$ReloadGlobal = true) do={\r\ + \n \$LogPrint info \$0 (\"Reloading global configuration and functions.\ + \");\r\ + \n :onerror Err {\r\ + \n :global InitSetup (a);\r\ + \n /system/script {run AM-GlobalConfig; run AM-GlobalFunc;};\r\ + \n } do={\$LogPrint error \$0 (\"Reloading global configuration and fun\ + ctions failed! \" . \$Err)}\r\ + \n }\r\ + \n :if (\$GlobalConfVersionBefore > \$GlobalConfVersion) do={\r\ + \n \$LogPrint warning \$0 (\"The configuration version decreased from \ + \" . \\\r\ + \n \$GlobalConfVersionBefore . \" to \" . \$GlobalConfVersion . \\\r\ + \n \". Installed an older version\?\");\r\ + \n }\r\ + \n :if (\$GlobalConfVersionBefore < \$GlobalConfVersion) do={\r\ + \n :global GlobalConfChanges;\r\ + \n :global GlobalConfMigration;\r\ + \n :local ChangeLogCode;\r\ + \n :if ([ :len \$ChangeLogCode ] > 0) do={\r\ + \n :if ([ \$ValidateSyntax \$ChangeLogCode ] = true) do={\r\ + \n :onerror Err {\r\ + \n [ :parse \$ChangeLogCode ];\r\ + \n } do={\$LogPrint warning \$0 (\"The changelog failed to run: \" \ + . \$Err)}\r\ + \n } else={\$LogPrint warning \$0 (\"The changelog failed syntax vali\ + dation!\")}\r\ + \n }\r\ + \n :if ([ :len \$GlobalConfMigration ] > 0) do={\r\ + \n :for I from=(\$GlobalConfVersionBefore + 1) to=\$GlobalConfVersion\ + \_do={\r\ + \n :local Migration (\$GlobalConfMigration->[ :tostr \$I ]);\r\ + \n :do {\r\ + \n :if ([ :typeof \$Migration ] != \"str\") do={\r\ + \n \$LogPrint debug \$0 (\"Migration code for change \" . \$I .\ + \_\" is not available.\");\r\ + \n :error false;\r\ + \n }\r\ + \n :if ([ \$ValidateSyntax \$Migration ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Migration code for change \" . \$I\ + \_. \" failed syntax validation!\");\r\ + \n :error false}\r\ + \n \$LogPrint info \$0 (\"Applying migration for change \" . \$I \ + . \": \" . \$Migration);\r\ + \n :onerror Err {\r\ + \n [ :parse \$Migration ];\r\ + \n } do={\$LogPrint warning \$0 (\"Migration code for change \" .\ + \_\$I . \" failed to run: \" . \$Err)}\r\ + \n } on-error={ }\r\ + \n }\r\ + \n }\r\ + \n :local NotificationMessage (\"The configuration version on \" . \$Id\ + entity . \" increased \" . \\\r\ + \n \"to \" . \$GlobalConfVersion . \", current configuration may nee\ + d modification. \" . \\\r\ + \n \"Please review and update global-config-overlay, then re-run glo\ + bal-config.\");\r\ + \n \$LogPrint info \$0 (\$NotificationMessage);\r\ + \n :if ([ :len \$GlobalConfChanges ] > 0) do={\r\ + \n :set NotificationMessage (\$NotificationMessage . \"\\n\\nChanges:\ + \");\r\ + \n :for I from=(\$GlobalConfVersionBefore + 1) to=\$GlobalConfVersion\ + \_do={\r\ + \n :local Change (\$GlobalConfChanges->[ :tostr \$I ]);\r\ + \n :set NotificationMessage (\$NotificationMessage . \"\\n \" . \\\ + \r\ + \n [ \$SymbolForNotification \"pushpin\" \"*\" ] . \$Change);\r\ + \n \$LogPrint info \$0 (\"Change \" . \$I . \": \" . \$Change);\r\ + \n }\r\ + \n } else={\r\ + \n :set NotificationMessage (\$NotificationMessage . \"\\n\\nNews and\ + \_changes are not available.\");\r\ + \n\r\ + \n }\r\ + \n\r\ + \n :if ([ :len \$GlobalConfChanges ] > 0) do={ :set GlobalConfChanges; \ + } else={ :global GlobalConfChanges (a); }\r\ + \n :if ([ :len \$GlobalConfMigration ] > 0) do={ :set GlobalConfMigrati\ + on; } else={ :global GlobalConfMigration (a); }\r\ + \n }\r\ + \n} do={\r\ + \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ + \n} }\r\ + \n\r\ + \n# load modules\r\ + \n:foreach Script in=[ /system/script/find where name ~ \"^(global-functio\ + ns\\\\.d|mod)/.\" ] do={\r\ + \n :local ScriptVal [ /system/script/get \$Script ];\r\ + \n :if ([ \$ValidateSyntax (\$ScriptVal->\"source\") ] = true) do={\r\ + \n :onerror Err {\r\ + \n /system/script/run \$Script;\r\ + \n } do={\r\ + \n \$LogPrint error \$0 (\"Module '\" . \$ScriptVal->\"name\" . \"' f\ + ailed to run: \" . \$Err);\r\ + \n }\r\ + \n } else={\r\ + \n \$LogPrint error \$0 (\"Module '\" . \$ScriptVal->\"name\" . \"' fai\ + led syntax validation, skipping.\");\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n# Add and fix global scheduler\r\ + \n:put \"Add or/and fix Global scheduler...\";\r\ + \n:local OnEvent \"/system/script { run AM-GlobalConfig; run AM-GlobalFunc\ + ; }\";\r\ + \n:local Comment \"Every Day Set Global Environment Variables\";\r\ + \n:if ([ :len [ /system/scheduler/find where name=\"AM-SetGlobalEnv\" ] ] \ + = 0) do={\r\ + \n /system/scheduler/add name=\"AM-SetGlobalEnv\" comment=\$Comment on-ev\ + ent=\$OnEvent start-time=startup;\r\ + \n}\r\ + \n:if ([ /system/scheduler/get \"AM-SetGlobalEnv\" comment ] != \$Comment)\ + \_do={\r\ + \n /system/scheduler/set \"AM-SetGlobalEnv\" comment=\$Comment;\r\ + \n}\r\ + \n:if ([ /system/scheduler/get \"AM-SetGlobalEnv\" on-event ] != \$OnEvent\ + ) do={\r\ + \n /system/scheduler/set \"AM-SetGlobalEnv\" on-event=\$OnEvent;\r\ + \n}\r\ + \n# Add Update Script scheduler\r\ + \n:put \"Add or/and fix Update Script scheduler\";\r\ + \n:set OnEvent \":global ScriptInstallUpdate; \\\$ScriptInstallUpdate;\";\ + \r\ + \n:set Comment \"Every Day Check For Update Scripts\";\r\ + \n:if ([ :len [ /system/scheduler/find where name=\"AM-ScriptInstallUpdate\ + \" ] ] = 0) do={\r\ + \n/system/scheduler/add name=\"AM-ScriptInstallUpdate\" comment=\$Comment \ + start-time=startup interval=1d on-event=\$OnEvent;\r\ + \n}\r\ + \n\r\ + \n:onerror Err {\r\ + \n :global GlobalConfReady;\r\ + \n :retry { :if (\$GlobalConfReady != true) do={ :error (\"Global configs\ + \_not ready.\"); }; } delay=100ms max=5;\r\ + \n\r\ + \n:log warning (\"This script \$ScriptName Loaded \" . \\\r\ + \n [ \$IfThenElse (\$CommitId != \"unknown\") ([ \$CommitBrief ] . \" \ + \") ] . \\\r\ + \n \"on \" . \$devBoardName . \"\\nRouterOS: \" . \$devCurVersion . \"\ + \\nArchitecture: \" . \$devCurArch . \"\\nIdentity: \" . \$Identity);\r\ + \n # signal we are ready\r\ + \n:set GlobalFuncReady true;\r\ + \n:set ExitOK true;\r\ + \n\r\ + \n:log info (\$0 . \"Global configs ready!\");\r\ + \n} do={\r\ + \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ + \n}\r\ + \n" +add comment=\ + "Lookup IP addresses for RKN list and add them to firewall address-list" \ + dont-require-permissions=no name=AM-RKN-dnsLookup owner=AM-RKN-dnsLookup \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + source="#!rsc by Vados\r\ + \n# RouterOS script: AM-RKN-dnsLookup\r\ + \n# Script comment: Lookup IP addresses for RKN list and add them to firew\ + all address-list\r\ + \n# Copyright (c) 2007-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version=7.19\r\ + \n# requires device-mode, fetch\r\ + \n#\r\ + \n# Script description: This script is intended to be run periodically, e.\ + g. once a day, to update the IP addresses in the firewall address-list bas\ + ed on the RKN list.\r\ + \n# It resolves the domain names in the RKN list and a\ + dds the corresponding IP addresses to the specified firewall address-list.\ + \r\ + \n# The script also handles CNAME records by following\ + \_them until it finds A records.\r\ + \n# Usage:\r\ + \n# /system/script { run AM-RKN-dnsLookup; }\r\ + \n:local ScriptName [ :jobname ];\r\ + \n\r\ + \n:global dnsLookupReady false;\r\ + \n:if ([:typeof \$dnsLookupReady] != \"boolean\") do={ :set dnsLookupReady\ + \_true; }\r\ + \nwhile (!\$dnsLookupReady) do={ :nothing; }\r\ + \n:set dnsLookupReady false;\r\ + \n\r\ + \n:local arrRKN {\r\ + \n \"telegra.ph\"\r\ + \n \"grani.ru\"\r\ + \n \"xhamster.com\"\r\ + \n \"lostfilm.tv\"\r\ + \n \"rutracker.org\"\r\ + \n \"lurkmore.to\"\r\ + \n \"dou.ua\"\r\ + \n \"youporn.com\"\r\ + \n \"pornolab.net\"\r\ + \n \"crimerussia.com\"\r\ + \n \"telegram.org\"\r\ + \n \"api.telegram.org\"\r\ + \n \"facebook.com\"\r\ + \n \"instagram.com\"\r\ + \n \"x.com\"\r\ + \n \"twitter.com\"\r\ + \n \"youtube.com\"\r\ + \n \"googleapis.com\"\r\ + \n \"youtu.be\"\r\ + \n \"googlevideo.com\"\r\ + \n \"gstatic.com\"\r\ + \n \"googleusercontent.com\"\r\ + \n \"nhacmp3youtube.com\"\r\ + \n \"telegram.me\"\r\ + \n \"t.me\";}\r\ + \n\r\ + \n:local ListRKN \"RKN-dnsLookup\";\r\ + \n:local ListComment (\"ListRKN managed by \" . \$ScriptName);\r\ + \n:foreach aListItem in=[/ip/firewall/address-list find list=\$ListRKN] do\ + ={\r\ + \n /ip firewall address-list remove \$aListItem;\r\ + \n}\r\ + \n:foreach aItem in=\$arrRKN do={\r\ + \n# :do {\r\ + \n :retry delay=500ms max=5 on-error={:log error \"dns resolve fail\ + ure [ \$aItem - resolve ip ]\"} command={:resolve \$aItem}\r\ + \n# } on-error={\r\ + \n# :log error \"dns resolve failure [ \$arItem - resolve ip ]\";\r\ + \n# }\r\ + \n :foreach dnsRecord in=[/ip dns cache all find where (name=\$aItem)] \ + do={\r\ + \n :if ([/ip dns cache all get \$dnsRecord type]=\"A\") do={\r\ + \n :local newAddress [/ip dns cache all get \$dnsRecord data];\ + \r\ + \n :do {\r\ + \n /ip firewall address-list add list=\$ListRKN address=\$newA\ + ddress comment=\$aItem;\r\ + \n :log warning \"Successfully adding ip to list A record: \ + \$dnsRecord, address: \$newAddress domain: \$aItem\";\r\ + \n } on-error={\r\ + \n :log error \"error when adding ip to list A record: \$dn\ + sRecord, address: \$newAddress domain: \$aItem\";\r\ + \n }\r\ + \n }\r\ + \n :if ([/ip dns cache all get \$dnsRecord type]=\"CNAME\") do={\r\ + \n :local cname;\r\ + \n :local nextCname;\r\ + \n :local cnameAddress;\r\ + \n :set cname [/ip dns cache all find where (name=\$aItem && ty\ + pe=\"CNAME\")];\r\ + \n :set nextCname [/ip dns cache all find where (name=[/ip dns \ + cache all get \$cname data] && type=\"CNAME\")];\r\ + \n :while (\$nextCname != \"\") do={\r\ + \n :set cname \$nextCname;\r\ + \n :set nextCname [/ip dns cache all find where (name=[/ip \ + dns cache all get \$cname data] && type=\"CNAME\")];\r\ + \n }\r\ + \n :foreach aRecord in=[/ip dns cache all find where (name=[/ip\ + \_dns cache all get \$cname data] && type=\"A\")] do={\r\ + \n :do {\r\ + \n :set cnameAddress [/ip dns cache all get \$aRecord d\ + ata];\r\ + \n /ip firewall address-list add list=\$ListRKN address\ + =\$cnameAddress comment=\$aItem;\r\ + \n :log warning \"Succesfully adding ip to list CNAME r\ + ecord: \$cname, A record: \$aRecord, address: \$newAddress, from domain: \ + \$aItem.\";\r\ + \n# /ip firewall raw add action=add-dst-to-address-list\ + \_address-list=\$ListRKN address-list-timeout=none-dynamic chain=preroutin\ + g comment=\$aItem content=\$aItem;\r\ + \n } on-error={\r\ + \n :log error \"error when adding ip to list CNAME reco\ + rd: \$cname, A record: \$aRecord, address: \$newAddress, from domain: \$aI\ + tem.\";\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:if ([ :len [ /system/scheduler/find where name=\$ScriptName ] ] = 0) do\ + ={\r\ + \n :log error (\$ScriptName . \"System Scheduler for script: \" . \$Scri\ + ptName . \" is NOT SET! Fix It Now!\");\r\ + \n /system/scheduler/add name=\$ScriptName on-event=\"/system/script { \ + run \$ScriptName; }\" comment=\"Update RKN DNS Looup\" interval=00:30:00 p\ + olicy=\"ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon\"\ + \_start-time=startup;\r\ + \n }\r\ + \n:set dnsLookupReady true;\r\ + \ndelay 2s; \r\ + \n:global dnsLookupReady (a);\r\ + \n" +add dont-require-permissions=no name="renameLists " owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + local oldName \"Test\";\ + \n:local newName \"Test-IP\";\ + \n/ip firewall address-list\ + \n:foreach i in=[find list=\$oldName] do={\ + \nset \$i list=\$newName;\ + \n}\ + \n" +add dont-require-permissions=no name=IPv6-Settings owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + #############Script Settings##################\ + \n\ + \n:local \"IF-TUN\" \"6to4-tun\"\ + \n:local \"IF-LOC\" \"Bridge-LAN\"\ + \n:local \"POOL-6TO4\" \"poolV6-local\"\ + \n:local \"force-update\" false\ + \n############ use then static ip #######################\ + \n:local \"lease-address\" [/ip address get [find interface=\$\"IF-LOC\"] \ + address]\ + \n#:local \"interface\" \"ext\"\ + \n:local bound 0\ + \n\ + \n###############################################\ + \n\ + \n:local 6to4prefix do={\ + \n :global dec2hex\ + \n :local ipv4 \$1\ + \n :local ipv6 \"2002:\"\ + \n :for i from=0 to=2 step=1 do={ \ + \n :if ( \$i = 2) do={\ + \n :set ipv6 (\$ipv6.\":\")\ + \n }\ + \n :local fp [:find \$ipv4 \".\"]\ + \n :if ( \$fp > 0 ) do={\ + \n :set ipv6 (\$ipv6.[\$dec2hex [:pick \$ipv4 0 \$fp]])\ + \n :set ipv4 [:pick \$ipv4 (\$fp + 1 ) [:len \$ipv4]]\ + \n }\ + \n }\ + \n :return (\$ipv6.[\$dec2hex \$ipv4])\ + \n}\ + \n:local \"str_replace\" do={\ + \n :local \"str-pos\" [:find \$1 \$2]\ + \n :local \"str-len\" [:len \$2]\ + \n :local str \"\"\ + \n :local rest \$1\ + \n :while (\$\"str-pos\" >= 0) do={\ + \n :local t [:pick \$rest 0 \$\"str-pos\"]\ + \n :if ( \$4 > 0 ) do={\ + \n :for i from=1 to=(\$4 - [:len \$t]) step=1 do={\ + \n :set str (\$str.\$5)\ + \n }\ + \n }\ + \n :set str (\$str.\$t.\$3)\ + \n :set rest [:pick \$rest (\$\"str-pos\"+\$\"str-len\") [:len \$re\ + st]]\ + \n :set \"str-pos\" [:find \$rest \$2]\ + \n }\ + \n :return (\$str.\$rest)\ + \n}\ + \n\ + \n:if (\$bound=1) do={\ + \n :local t [:find \$\"lease-address\" \"/\"]\ + \n\ + \n :if ( \$t >= 0 ) do={\ + \n :set \"lease-address\" [:pick \$\"lease-address\" 0 \$t]\ + \n }\ + \n\ + \n :if ( [/interface 6to4 print count-only where name=\$\"IF-TUN\"] = 0\ + ) do={\ + \n /interface 6to4 add !keepalive local-address=\$\"lease-address\"\ + \_mtu=1280 name=\$\"IF-TUN\" remote-address=10.30.30.0\ + \n :set \"force-update\" true\ + \n }\ + \n\ + \n :local \"IPv4-TUN\" [/interface 6to4 get [find name=\$\"IF-TUN\"] lo\ + cal-address];\ + \n\ + \n :if ( \$\"lease-address\" != \$\"IPv4-TUN\" || \$\"force-update\" = \ + true) do={\ + \n /interface 6to4 set [find name=\$\"IF-TUN\"] local-address=\$\"l\ + ease-address\"\ + \n /ipv6 address remove [find interface=\$\"IF-TUN\"]\ + \n /ipv6 address remove [find interface=\$\"IF-LOC\"]\ + \n /ipv6 route remove [find gateway ~ \$\"IF-TUN\" and dst-address=\ + \"::/0\"]\ + \n :local \"pool-prefix\" [\$6to4prefix \$\"lease-address\"]\ + \n :if ( [/ipv6 pool print count-only where name=\$\"POOL-6TO4\"] =\ + \_0) do={ \ + \n /ipv6 pool add name=\$\"POOL-6TO4\" prefix=(\$\"pool-prefix\ + \".\":1::/64\") prefix-length=64\ + \n } else={\ + \n /ipv6 pool set [/ipv6 pool find where name=\$\"POOL-6TO4\"] \ + prefix=(\$\"pool-prefix\".\":1::/64\")\ + \n }\ + \n /ipv6 address add address=(\$\"pool-prefix\".\"::\".[\$MAC2EUI64\ + \_[/interface get [find name=\$\"interface\"] mac-address]].\"/3\") interf\ + ace=\$\"IF-TUN\" advertise=no\ + \n /ipv6 address add eui-64=yes from-pool=\$\"POOL-6TO4\" interface\ + =\$\"IF-LOC\" advertise=yes\ + \n /ipv6 route add dst-address=::/0 gateway=(\"::10.30.30.81%\".\$\ + \"IF-TUN\")\ + \n :local t [/ipv6 address get [find interface=\$\"IF-LOC\"] addres\ + s]\ + \n :set t [:pick \$t 0 [:find \$t \"/\"]]\ + \n :if ( [/ipv6 dhcp-server option print count-only where name=DNS]\ + \_= 0) do={\ + \n /ipv6 dhcp-server option add code=23 name=DNS value=(\"0x\".\ + [\$\"str_replace\" \$t \":\" \"\" 4 \"0\"])\ + \n } else={\ + \n /ipv6 dhcp-server option set [/ipv6 dhcp-server option find \ + where name=DNS] value=(\"0x\".[\$\"str_replace\" \$t \":\" \"\" 4 \"0\"])\ + \n }\ + \n :if ( [/ipv6 dhcp-server print count-only where interface=\$\"IF\ + -LOC\"] = 0) do={\ + \n /ipv6 dhcp-server add address-pool=\$\"POOL-6TO4\" dhcp-opti\ + on=DNS interface=\$\"IF-LOC\" lease-time=1d name=\$\"IF-LOC\"\ + \n }\ + \n :if ( [ipv6 nd print count-only where interface=\$\"IF-LOC\"] = \ + 0) do={\ + \n /ipv6 nd add advertise-dns=no interface=\$\"IF-LOC\" other-c\ + onfiguration=yes\ + \n }\ + \n }\ + \n}" +add dont-require-permissions=no name=IPv6-GlobalFunc owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + global MAC2EUI64 do={\ + \n :local EUI64 \"\"\ + \n :local MAC \$1\ + \n :local HEX2DEC \"0123456789ABCDEF\"\ + \n :for i from=0 to=5 step=1 do={\ + \n :if ( \$i = 0 ) do={\ + \n :set EUI64 [:pick \$MAC 0]\ + \n :set EUI64 (\$EUI64.[:tostr [:pick \$\"HEX2DEC\" ([:find \$\ + \"HEX2DEC\" [:pick \$MAC 1]] ^ 2)]])\ + \n }\ + \n :if ( \$i = 1 || \$i = 3) do={\ + \n :set EUI64 (\$EUI64.\":\")\ + \n }\ + \n :if ( \$i = 2 ) do={\ + \n :set EUI64 (\$EUI64.\"FF:FE\")\ + \n }\ + \n :if ( [:find \$MAC \":\"] = 2 ) do={\ + \n :set MAC [:pick \$MAC 3 [:len \$MAC]]\ + \n :set EUI64 (\$EUI64.[:pick \$MAC 0 2])\ + \n }\ + \n }\ + \n :return (\$EUI64)\ + \n}\ + \n\ + \n:global dec2hex do={\ + \n :local hex \"\"\ + \n :local dec [:tonum \$1]\ + \n :for i from=0 to=4 step=4 do={\ + \n :set hex ([:pick \"0123456789ABCDEF\" ((\$dec>>\$i)&0xf) (((\$de\ + c>>\$i)&0xf)+1)].\$hex)\ + \n }\ + \n :return ([:tostr \$hex])\ + \n}" +/user group +add name=backup policy="ssh,read,write,policy,test,web,sniff,sensitive,api,res\ + t-api,!local,!telnet,!ftp,!reboot,!winbox,!password,!romon" +/ip smb +set enabled=no interfaces=lo +/interface bridge port +add bridge=Bridge-LAN interface=ether5 +add bridge=Bridge-LAN interface=ether2 +add bridge=Bridge-LAN interface=ether4 trusted=yes +add bridge=Bridge-LAN interface=ether3 +add bridge=Bridge-LAN interface=wlan2 +add bridge=Bridge-LAN interface=wlan1 +/interface bridge settings +# ipv6 neighbor configuration has changed, please restart the device in order to apply the new settings +set use-ip-firewall=yes +/ip firewall connection tracking +# ipv6 neighbor configuration has changed, please restart the device in order to apply the new settings +set udp-timeout=10s +/ip neighbor discovery-settings +# ipv6 neighbor configuration has changed, please restart the device in order to apply the new settings +set discover-interface-list=LAN lldp-med=no lldp-poe-power=no +/ip settings +# ipv6 neighbor configuration has changed, please restart the device in order to apply the new settings +set accept-redirects=yes ipv4-multipath-hash-policy=l4 max-neighbor-entries=\ + 8192 +/ipv6 settings +# ipv6 neighbor configuration has changed, please restart the device in order to apply the new settings +set disable-ipv6=yes disable-link-local-address=yes forward=no \ + max-neighbor-entries=8192 multipath-hash-policy=l4 +/interface detect-internet +set detect-interface-list=static internet-interface-list=Internet \ + lan-interface-list=LAN request-interval=1m wan-interface-list=WAN +/interface l2tp-server server +set authentication=mschap2 use-ipsec=yes +/interface list member +add interface=Bridge-LAN list=LAN +add interface="ether1 - Unet" list=Internet +add interface=WG 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=" +/interface wireless cap +# +set bridge=Bridge-LAN caps-man-addresses=10.30.30.10 \ + caps-man-certificate-common-names=CAPsMAN-51B25E507D07 certificate=\ + CAP-488F5A8E1ABC discovery-interfaces=Bridge-LAN enabled=yes interfaces=\ + wlan2,wlan1 lock-to-caps-man=yes +/ip address +add address=10.30.30.81/24 interface=Bridge-LAN network=10.30.30.0 +add address=10.8.0.2/24 disabled=yes interface=WG network=10.8.0.0 +/ip cloud +set update-time=no +/ip dhcp-client +add add-default-route=special-classless default-route-distance=2 \ + default-route-tables=main:2 dhcp-options=clientid,clientid_duid \ + interface="ether1 - Unet" name=client1 use-peer-dns=no use-peer-ntp=no +/ip dhcp-server config +set accounting=no +/ip dhcp-server lease +add address=10.30.30.101 client-id=1:48:8f:5a:8e:ee:a8 mac-address=\ + 48:8F:5A:8E:EE:A8 server=masterDHCP +add address=10.30.30.107 client-id=1:f0:de:f1:91:d:1e mac-address=\ + F0:DE:F1:91:0D:1E server=masterDHCP +add address=10.30.30.83 client-id=1:0:80:77:ec:43:86 mac-address=\ + 00:80:77:EC:43:86 server=masterDHCP +add address=10.30.30.70 dhcp-option=domain-search-list,HostName \ + dhcp-option-set=HP1505n mac-address=00:1E:0B:1A:88:8D server=masterDHCP +add address=10.30.30.50 client-id=1:4:7c:16:36:f5:37 mac-address=\ + 04:7C:16:36:F5:37 server=masterDHCP +add address=10.30.30.71 client-id=1:10:2d:41:2c:20:c2 mac-address=\ + 10:2D:41:2C:20:C2 server=masterDHCP +add address=10.30.30.61 client-id=1:10:8:c1:81:59:5f mac-address=\ + 10:08:C1:81:59:5F server=masterDHCP +add address=10.30.30.72 client-id=1:10:38:1f:d2:5f:13 mac-address=\ + 10:38:1F:D2:5F:13 server=masterDHCP +add address=10.30.30.99 client-id=1:10:b1:df:e9:d0:d5 mac-address=\ + 10:B1:DF:E9:D0:D5 server=masterDHCP +add address=10.30.30.111 client-id=1:fe:2:52:be:3f:16 mac-address=\ + FE:02:52:BE:3F:16 server=masterDHCP +add address=10.30.30.92 client-id=1:d4:6d:6d:fd:e5:49 mac-address=\ + D4:6D:6D:FD:E5:49 server=masterDHCP +add address=10.30.30.93 client-id=1:7e:8b:1e:cb:b8:cb mac-address=\ + CC:42:10:12:46:94 server=masterDHCP +add address=10.30.30.94 client-id=1:50:cc:f8:85:96:a mac-address=\ + 50:CC:F8:85:96:0A server=masterDHCP +add address=10.30.30.82 client-id=1:e4:18:6b:58:34:ab mac-address=\ + E4:18:6B:58:34:AB server=masterDHCP +add address=10.30.30.75 client-id=1:0:27:15:41:97:a9 mac-address=\ + 00:27:15:41:97:A9 server=masterDHCP +add address=10.30.30.77 dhcp-option=HostName dhcp-option-set=StartLife1 \ + mac-address=C4:82:E1:03:49:10 server=masterDHCP +add address=10.30.30.73 client-id=1:10:38:1f:82:81:f2 mac-address=\ + 10:38:1F:82:81:F2 server=masterDHCP +add address=10.30.30.95 client-id=1:88:ae:dd:60:39:54 dhcp-option=HostName \ + dhcp-option-set=VADOS-NUC mac-address=88:AE:DD:60:39:54 server=masterDHCP +add address=10.30.30.98 client-id=1:c8:5b:76:d8:cc:bf dhcp-option=HostName \ + dhcp-option-set=VADOS-LEN mac-address=C8:5B:76:D8:CC:BF server=masterDHCP +add address=10.30.30.96 client-id=iPhone mac-address=4A:91:ED:0E:1F:39 \ + server=masterDHCP +add address=10.30.30.74 client-id=MiTV dhcp-option=HostName dhcp-option-set=\ + MiTV mac-address=20:72:A9:D3:34:36 server=masterDHCP +add address=10.30.30.30 dhcp-option=HostName dhcp-option-set=miller \ + mac-address=F0:75:5D:1E:5F:71 server=masterDHCP +add address=10.30.30.100 client-id=iVados dhcp-option=HostName \ + dhcp-option-set=iVados mac-address=DE:4D:72:F3:1A:9F server=masterDHCP +/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.81 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=1.0.0.1,8.8.4.4 verify-doh-cert=yes +/ip dns static +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 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 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 name=MikroYellow type=A +add address=10.30.30.85 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 name=garage type=A +/ip firewall address-list +add address=91.215.120.206 list=TRUSTED +add address=185.71.70.78 disabled=yes list=TRUSTED +add address=176.53.203.171 disabled=yes list=TRUSTED +add address=176.53.203.170 disabled=yes list=TRUSTED +add address=176.53.202.194 disabled=yes list=TRUSTED +add address=8.8.4.0/24 list=YouTube +add address=8.8.8.0/24 list=YouTube +add address=8.34.208.0/20 list=YouTube +add address=8.35.192.0/20 list=YouTube +add address=23.236.48.0/20 list=YouTube +add address=23.251.128.0/19 list=YouTube +add address=34.0.0.0/15 list=YouTube +add address=34.2.0.0/16 list=YouTube +add address=34.3.0.0/23 list=YouTube +add address=34.3.3.0/24 list=YouTube +add address=34.3.4.0/24 list=YouTube +add address=34.3.8.0/21 list=YouTube +add address=34.3.16.0/20 list=YouTube +add address=34.3.32.0/19 list=YouTube +add address=34.3.64.0/18 list=YouTube +add address=34.4.0.0/14 list=YouTube +add address=34.8.0.0/13 list=YouTube +add address=34.16.0.0/12 list=YouTube +add address=34.32.0.0/11 list=YouTube +add address=34.64.0.0/10 list=YouTube +add address=34.128.0.0/10 list=YouTube +add address=35.184.0.0/13 list=YouTube +add address=35.192.0.0/14 list=YouTube +add address=35.196.0.0/15 list=YouTube +add address=35.198.0.0/16 list=YouTube +add address=35.199.0.0/17 list=YouTube +add address=35.199.128.0/18 list=YouTube +add address=35.200.0.0/13 list=YouTube +add address=35.208.0.0/12 list=YouTube +add address=35.224.0.0/12 list=YouTube +add address=35.240.0.0/13 list=YouTube +add address=57.140.192.0/18 list=YouTube +add address=64.15.112.0/20 list=YouTube +add address=64.233.160.0/19 list=YouTube +add address=66.22.228.0/23 list=YouTube +add address=66.102.0.0/20 list=YouTube +add address=66.249.64.0/19 list=YouTube +add address=70.32.128.0/19 list=YouTube +add address=72.14.192.0/18 list=YouTube +add address=74.125.0.0/16 list=YouTube +add address=104.154.0.0/15 list=YouTube +add address=104.196.0.0/14 list=YouTube +add address=104.237.160.0/19 list=YouTube +add address=107.167.160.0/19 list=YouTube +add address=107.178.192.0/18 list=YouTube +add address=108.59.80.0/20 list=YouTube +add address=108.170.192.0/18 list=YouTube +add address=108.177.0.0/17 list=YouTube +add address=130.211.0.0/16 list=YouTube +add address=136.22.160.0/20 list=YouTube +add address=136.22.176.0/21 list=YouTube +add address=136.22.184.0/23 list=YouTube +add address=136.22.186.0/24 list=YouTube +add address=142.250.0.0/15 list=YouTube +add address=146.148.0.0/17 list=YouTube +add address=152.65.208.0/22 list=YouTube +add address=152.65.214.0/23 list=YouTube +add address=152.65.218.0/23 list=YouTube +add address=152.65.222.0/23 list=YouTube +add address=152.65.224.0/19 list=YouTube +add address=162.120.128.0/17 list=YouTube +add address=162.216.148.0/22 list=YouTube +add address=162.222.176.0/21 list=YouTube +add address=172.110.32.0/21 list=YouTube +add address=172.217.0.0/16 list=YouTube +add address=172.253.0.0/16 list=YouTube +add address=173.194.0.0/16 list=YouTube +add address=173.255.112.0/20 list=YouTube +add address=192.158.28.0/22 list=YouTube +add address=192.178.0.0/15 list=YouTube +add address=193.186.4.0/24 list=YouTube +add address=199.36.154.0/23 list=YouTube +add address=199.36.156.0/24 list=YouTube +add address=199.192.112.0/22 list=YouTube +add address=199.223.232.0/21 list=YouTube +add address=207.223.160.0/20 list=YouTube +add address=208.65.152.0/22 list=YouTube +add address=208.68.108.0/22 list=YouTube +add address=208.81.188.0/22 list=YouTube +add address=208.117.224.0/19 list=YouTube +add address=209.85.128.0/17 list=YouTube +add address=216.58.192.0/19 list=YouTube +add address=216.73.80.0/20 list=YouTube +add address=216.239.32.0/19 list=YouTube +add address=2ip.ru list=Test-IP +add address=wg.vados.ru comment=VDSIna list=TRUSTED +add address=10.8.0.0/24 comment="WG VDSIna" disabled=yes list=TRUSTED +add address=ikus.pesc.ru comment=ikus.pesc.ru list=NoVdsina +add address=love.ru comment=love.ru list=NoVdsina +add address=gosuslugi.ru comment=gosuslugi.ru list=NoVdsina +add address=pochta.ru comment=pochta.ru list=NoVdsina +add address=vdsina.com list=NoVdsina +add address=vdsina.ru list=NoVdsina +add address=youla.ru list=NoVdsina +add address=kupiprodai.ru list=NoVdsina +add address=myip.ru list=Test-IP +add address=geoip.co list=NoVdsina +add address=comp-lenta.ru list=NoVdsina +add address=128.85.102.70 comment=update.microsoft.com list=\ + windowsupdateslist +add address=wu-b-net.trafficmanager.net. comment=\ + ctldl.windowsupdate.com.delivery.microsoft.com list=windowsupdateslist +add address=ctldl.windowsupdate.com.delivery.microsoft.com. comment=\ + ctldl.windowsupdate.com list=windowsupdateslist +add address=redir.update.msft.com.trafficmanager.net. comment=\ + update.microsoft.com list=windowsupdateslist +add address=geo.prod.do.dsp.trafficmanager.net. comment=\ + geo.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=13.74.139.29 comment=array605.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=kv801.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + kv801.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=e12437.d.akamaiedge.net. comment=\ + kv801.prod.do.dsp.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=displaycatalog-rp.md.mp.microsoft.com.akadns.net. comment=\ + displaycatalog.mp.microsoft.com list=windowsupdateslist +add address=rp-consumer-prod-displaycatalog-geomap.trafficmanager.net. \ + comment=displaycatalog-rp.md.mp.microsoft.com.akadns.net list=\ + windowsupdateslist +add address=sls.update.microsoft.com. comment=slscr.update.microsoft.com \ + list=windowsupdateslist +add address=glb.sls.prod.dcat.dsp.trafficmanager.net. comment=\ + sls.update.microsoft.com list=windowsupdateslist +add address=fe3.delivery.mp.microsoft.com. comment=\ + fe3cr.delivery.mp.microsoft.com list=windowsupdateslist +add address=glb.cws.prod.dcat.dsp.trafficmanager.net. comment=\ + fe3.delivery.mp.microsoft.com list=windowsupdateslist +add address=fe2cr.update.msft.com.trafficmanager.net. comment=\ + fe2cr.update.microsoft.com list=windowsupdateslist +add address=download.windowsupdate.com.delivery.microsoft.com. comment=\ + download.windowsupdate.com list=windowsupdateslist +add address=wu-f-net.trafficmanager.net. comment=\ + download.windowsupdate.com.delivery.microsoft.com list=windowsupdateslist +add address=tsfe.trafficmanager.net. comment=\ + tsfe.trafficshaping.dsp.mp.microsoft.com list=windowsupdateslist +add address=edge.ds-c7110-microsoft.global.dns.qwilted-cds.cqloud.com. \ + comment=9.au.download.windowsupdate.com list=windowsupdateslist +add address=52.158.227.125 comment=array812.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=au.download.windowsupdate.com.delivery.microsoft.com. comment=\ + au.download.windowsupdate.com list=windowsupdateslist +add address=a767.dspw65.akamai.net. comment=\ + download.windowsupdate.com.edgesuite.net list=windowsupdateslist +add address=52.151.58.88 comment=array810.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=consumer-licensing-aks2aks.md.mp.microsoft.com.akadns.net. \ + comment=licensing.mp.microsoft.com list=windowsupdateslist +add address=licensing-prod-frontdoor-geomap.trafficmanager.net. comment=\ + consumer-licensing-aks2aks.md.mp.microsoft.com.akadns.net list=\ + windowsupdateslist +add address=star.f.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedge.f.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=cdp-f-nlu-net.trafficmanager.net. comment=\ + star.f.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=star.b.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedge.b.tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=cdp-f-tlu-net.trafficmanager.net. comment=\ + star.b.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=storeedgefd.xbetservices.akadns.net. comment=\ + storeedgefd.dsx.mp.microsoft.com list=windowsupdateslist +add address=\ + storeedgefd.dsx.mp.microsoft.com.edgekey.net.globalredir.akadns.net. \ + comment=storeedgefd.dsx.mp.microsoft.com.edgekey.net list=\ + windowsupdateslist +add address=e16646.dscg.akamaiedge.net. comment=\ + storeedgefd.dsx.mp.microsoft.com.edgekey.net.globalredir.akadns.net list=\ + windowsupdateslist +add address=40.69.76.189 comment=array621.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=bg.microsoft.map.fastly.net. comment=\ + 3.au.download.windowsupdate.com list=windowsupdateslist +add list=windowsupdateslist +add address=40.69.75.33 comment=array613.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=star.sf.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedgeextensions.sf.tlu.dl.delivery.mp.microsoft.com list=\ + windowsupdateslist +add address=cdp-f-ssl-tlu-net.trafficmanager.net. comment=\ + star.sf.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=a2033.dscd.akamai.net. comment=\ + star.sb.tlu.dl.delivery.mp.microsoft.com.edgesuite.net list=\ + windowsupdateslist +add address=13.74.138.242 comment=array602.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=dl.delivery.mp.microsoft.com.delivery.microsoft.com. comment=\ + dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=dcat-f-nlu-net.trafficmanager.net. comment=\ + dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=1d.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=1D.tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=dcat-b-tlu-net.trafficmanager.net. comment=\ + 1d.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=a122.dscg3.akamai.net. comment=\ + tlu.dl.delivery.mp.microsoft.com.edgesuite.net list=windowsupdateslist +add address=geover.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + geover.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=e10370.d.akamaiedge.net. comment=\ + geover.prod.do.dsp.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=52.232.182.21 comment=array511.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.70.77.95 comment=array519.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=a1683.dscd.akamai.net. comment=\ + dl.delivery.mp.microsoft.com-c.edgesuite.net list=windowsupdateslist +add address=consumer-collections-aks2eap.md.mp.microsoft.com.akadns.net. \ + comment=collections.mp.microsoft.com list=windowsupdateslist +add address=a1847.dscd.akamai.net. comment=\ + wildcard.f.tlu.dl.delivery.mp.microsoft.com.edgesuite.net list=\ + windowsupdateslist +add address=13.74.142.6 comment=array607.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=au.download.windowsupdate.com.edgesuite.net. comment=\ + 2.au.download.windowsupdate.com list=windowsupdateslist +add address=a767.dscg3.akamai.net. comment=\ + au.download.windowsupdate.com.edgesuite.net list=windowsupdateslist +add address=52.156.123.84 comment=array818.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.69.78.254 comment=array610.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=4.au.download.windowsupdate.com.delivery.microsoft.com. comment=\ + 4.au.download.windowsupdate.com list=windowsupdateslist +add address=cl-glcb907925.gcdn.co. comment=\ + 4.au.download.windowsupdate.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=52.167.167.111 comment=array510.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=40.69.70.43 comment=array623.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=tsfe.trafficshaping.dsp.mp.microsoft.com.delivery.microsoft.com. \ + comment=tsfe.trafficshaping.dsp.mp.microsoft.com list=windowsupdateslist +add address=ts-frontend.trafficmanager.net. comment=\ + tsfe.trafficshaping.dsp.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=40.69.75.248 comment=array616.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.69.74.84 comment=array615.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=sds.trafficmanager.net. comment=software-download.microsoft.com \ + list=windowsupdateslist +add address=40.69.74.80 comment=array611.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.175.242.182 comment=array804.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=dlc-shim.trafficmanager.net. comment=download.microsoft.com list=\ + windowsupdateslist +add address=e12671.dscd.akamaiedge.net. comment=\ + download.microsoft.com.edgekey.net list=windowsupdateslist +add address=20.187.55.34 comment=array808.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.167.231 comment=array513.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=52.167.222.13 comment=array518.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=kv601.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + kv601.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=e12358.d.akamaiedge.net. comment=\ + kv601.prod.do.dsp.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. comment=\ + tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=dcat-f-tlu-net.trafficmanager.net. comment=\ + tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=a1856.dspw65.akamai.net. comment=\ + tlu.dl.delivery.mp.microsoft.com-c.edgesuite.net list=windowsupdateslist +add address=52.167.164.252 comment=array506.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=13.74.137.54 comment=array601.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=kv501.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + kv501.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=collections-prod-frontdoor-geomap.trafficmanager.net. comment=\ + consumer-collections-aks2eap.md.mp.microsoft.com.akadns.net list=\ + windowsupdateslist +add address=52.167.160.173 comment=array509.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=40.70.77.148 comment=array516.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.200.126 comment=array507.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=52.167.167.59 comment=array508.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.69.76.172 comment=array620.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=smtp.mail.me.com comment=smtp.mail.me.com list=NoVdsina +add address=40.70.76.5 comment=array514.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.186.119 comment=array618.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.177.176.186 comment=array520.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=40.70.76.27 comment=array515.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.160.43 comment=array503.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.110 comment=array817.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.142.8 comment=array614.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.138.254 comment=array603.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.167.96 comment=array501.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.69.76.215 comment=array622.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.143.200 comment=array606.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.111 comment=array818.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.112 comment=array819.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.137.53 comment=array608.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.98 comment=array805.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.96 comment=array803.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.104 comment=array811.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.101 comment=array808.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.99 comment=array806.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.17 comment=array802.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.97 comment=array804.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.103 comment=array810.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.16 comment=array801.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.70.77.177 comment=array517.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.164.84 comment=array512.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.105 comment=array812.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.107 comment=array814.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.232.161.82 comment=array502.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.108 comment=array815.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.161.91 comment=array505.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.102 comment=array809.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.109 comment=array816.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.106 comment=array813.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.117 comment=array622.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.107 comment=array612.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.108 comment=array613.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.105 comment=array610.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.113 comment=array618.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.116 comment=array621.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.98 comment=array603.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.114 comment=array619.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.111 comment=array616.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.97 comment=array602.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.106 comment=array611.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.110 comment=array615.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.119 comment=array624.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.135 comment=array514.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.97 comment=array503.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.99 comment=array604.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.61 comment=array504.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.131 comment=array510.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.132 comment=array511.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.96 comment=array601.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.104 comment=array609.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.138 comment=array517.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.60 comment=array501.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.139 comment=array518.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.118 comment=array623.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.113 comment=array820.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.103 comment=array608.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.100 comment=array807.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.129 comment=array508.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.134 comment=array513.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.62 comment=array505.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.137 comment=array516.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.101 comment=array606.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.96 comment=array502.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.130 comment=array509.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.112 comment=array617.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.100 comment=array605.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.115 comment=array620.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.136 comment=array515.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=purchase.md.mp.microsoft.com.akadns.net. comment=\ + purchase.mp.microsoft.com list=windowsupdateslist +add address=e110219.a.akamaiedge.net. comment=\ + purchase.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=72.153.5.140 comment=array519.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.141 list=windowsupdateslist +add address=72.153.5.63 comment=array506.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.128 comment=array507.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.102 comment=array607.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=storesdk.xbetservices.akadns.net. comment=\ + storesdk.dsx.mp.microsoft.com list=windowsupdateslist +add address=e16646.g.akamaiedge.net. comment=\ + storesdk.dsx.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=software-download.microsoft.com.delivery.microsoft.com. comment=\ + software-download.microsoft.com list=windowsupdateslist +add address=download.prss.microsoft.com.akamaized.net. comment=\ + software-download.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.109 comment=array614.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.133 comment=array512.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=213.180.192.0/19 comment=YandexDisk list=NoVdsina +add address=87.250.250.50 comment=YandexDisk list=NoVdsina +add address=consumer-prod-bcfd-v7-afd.trafficmanager.net. comment=\ + displaycatalog.mp.microsoft.com list=windowsupdateslist +add address=purchase-europeeap.md.mp.microsoft.com.akadns.net. comment=\ + purchase.md.mp.microsoft.com.akadns.net list=windowsupdateslist +add address=ne-az-conspurchase-mp.trafficmanager.net. comment=\ + purchase-europeeap.md.mp.microsoft.com.akadns.net list=windowsupdateslist +add address=storeedgefd.dsx.mp.microsoft.com.edgekey.net. comment=\ + cdn.storeedgefd.dsx.mp.microsoft.com list=windowsupdateslist +add address=star.f.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedge.f.tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=a1996.dscd.akamai.net. comment=\ + wildcard.f.dl.delivery.mp.microsoft.com.edgesuite.net list=\ + windowsupdateslist +add address=cp801.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + cp801.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=glb.tas02.sls-prod.dcat.dsp.mp.microsoft.com. comment=\ + tas02.sls.update.microsoft.com list=windowsupdateslist +add address=cp601.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + cp601.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=star.sb.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedgeextensions.sb.tlu.dl.delivery.mp.microsoft.com list=\ + windowsupdateslist +add address=star.sf.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedge.sf.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=cdp-f-ssl-nlu-net.trafficmanager.net. comment=\ + star.sf.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=tm-pifd-prod-gbl-weight.trafficmanager.net. comment=\ + paymentinstruments.mp.microsoft.com list=windowsupdateslist +add address=10.30.30.33 comment=amster disabled=yes list=NoWG +add address=10.30.30.10 comment=MikroNUC disabled=yes list=NoWG +add address=89.110.101.17 comment=!!!VDSINA!!!! disabled=yes list=NoWG +add address=wg.vados.ru comment=VDSina-vpn list=VDSina +add address=80.85.244.9 list=TRUSTED +add address=disc801.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + disc801.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=185.71.70.78 disabled=yes list=TRUSTED +add address=176.53.203.171 disabled=yes list=TRUSTED +add address=176.53.203.170 disabled=yes list=TRUSTED +add address=176.53.202.194 disabled=yes list=TRUSTED +add address=89.110.101.17 comment="!!!VDSina Server!!!" list=NoVdsina +add address=dns.quad9.net comment=Quad9-dns disabled=yes list=Trusted-DNS +add address=dns.google comment=Google-dns list=Trusted-DNS +add address=security.cloudflare-dns.com comment=CloudFlare-dns list=\ + Trusted-DNS +add address=time.google.com comment=Google-time list=Trusted-NTP +add address=0.ru.pool.ntp.org comment=ru.pool.ntp.org disabled=yes list=\ + Trusted-NTP +add address=1.ru.pool.ntp.org disabled=yes list=Trusted-NTP +add address=2.ru.pool.ntp.org comment=2.ru.pool.ntp.org disabled=yes list=\ + Trusted-NTP +add address=3.ru.pool.ntp.org comment=3.ru.pool.ntp.org disabled=yes list=\ + Trusted-NTP +add address=cp.vdsina.com comment=VDSina-vpn list=VDSina +add address=vdsina.ru comment=VDSina-vpn list=VDSina +add address=ns.vados.ru comment=VDSina-vpn list=VDSina +add address=vdsina.com comment=VDSina-vpn list=VDSina +add address=cp.vdsina.ru comment=VDSina-vpn list=VDSina +add address=ns1.vdsina.ru comment=VDSina-vpn list=VDSina +add address=10.30.30.0/24 comment="Local Network" list=Local-Net +add address=10.8.0.0/24 comment="WireGuard Network" list=Local-Net +add address=146.120.64.208/29 comment="External Net" list=Unet +add address=esia.gosuslugi.ru comment=esia.gosuslugi.ru list=NoVdsina +add address=lk.gosuslugi.ru comment=lk.gosuslugi.ru list=NoVdsina +add address=trudvsem.ru comment=trudvsem.ru list=NoVdsina +add address=10.30.30.30 comment=miller disabled=yes list=NoWG +add address=10.30.30.33 comment="Direct connet to DNS servers" list=\ + Direct-DNS +add address=wg.vados.ru list=VPN-Server +/ip firewall filter +add action=accept chain=input dst-port=18880 in-interface=Bridge-LAN \ + protocol=tcp src-address=10.30.30.0/24 +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=12h chain=input comment="block honeypot DNS" \ + connection-state=new dst-port=53 in-interface="ether1 - Unet" protocol=\ + udp src-address-list=!Trusted-DNS +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=4w2d chain=input connection-state=new dst-port=53 \ + in-interface="ether1 - Unet" protocol=tcp src-address-list=!Trusted-DNS +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=4w2d chain=input comment=\ + "block honeypot ssh rdp winbox" connection-state=new dst-port=22,8291 \ + in-interface="ether1 - Unet" protocol=tcp src-address-list=!TRUSTED +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=4w2d chain=input comment="block honeypot asterisk" \ + connection-state=new dst-port=5060 in-interface="ether1 - Unet" protocol=\ + udp +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=4w2d chain=input comment="block honeypot NTP" \ + connection-state=new dst-port=123 in-interface="ether1 - Unet" protocol=\ + udp +add action=fasttrack-connection chain=forward comment=\ + "FastTrack for non-VPN connections" connection-mark=!VPN_No_FastTrack \ + connection-state=established,related,new disabled=yes +add action=accept chain=input disabled=yes dst-port=29185 in-interface=\ + "ether1 - Unet" protocol=tcp +add action=accept chain=input disabled=yes dst-port=29185 in-interface=\ + "ether1 - Unet" protocol=udp +add action=accept chain=input comment="tcp Accept input DNS queries from LAN" \ + dst-port=53 in-interface=Bridge-LAN protocol=tcp src-address=\ + 10.30.30.0/24 +add action=accept chain=input comment="udp Accept input DNS queries" \ + dst-port=53 in-interface=Bridge-LAN protocol=udp src-address=\ + 10.30.30.0/24 +add action=accept chain=output comment="accept WireGuard" dst-address-list=\ + VPN-Server out-interface="ether1 - Unet" protocol=udp src-port=13231 +add action=accept chain=output dst-address-list=VPN-Server dst-port=29185 \ + out-interface="ether1 - Unet" protocol=udp +add action=fasttrack-connection chain=forward comment="defconf: fasttrack" \ + connection-state=established,related,new disabled=yes routing-mark=\ + !To-VPN +add action=accept chain=output disabled=yes protocol=tcp src-port=443 +add action=accept chain=output disabled=yes src-address=127.0.0.1 +add action=accept chain=forward comment="defconf: accept in ipsec policy" \ + disabled=yes ipsec-policy=in,ipsec +add action=accept chain=forward comment="defconf: accept out ipsec policy" \ + disabled=yes ipsec-policy=out,ipsec +add action=accept chain=forward comment=\ + "defconf: accept established,related, untracked" connection-state=\ + established,related,untracked +add action=drop chain=forward comment="defconf: drop invalid" \ + connection-state=invalid in-interface="ether1 - Unet" src-address=\ + !10.30.30.0/24 +add action=drop chain=forward comment=\ + "defconf: drop all from WAN not DSTNATed" connection-nat-state=!dstnat \ + connection-state=new in-interface="ether1 - Unet" src-address-list=\ + !VDSina +add action=drop chain=forward comment=\ + "Filter Rule to block FB address LIST : )" disabled=yes dst-address-list=\ + facebook +add action=drop chain=forward comment=\ + "Filter Rule to block YOUTUBE address LIST : )" disabled=yes \ + dst-address-list=YouTube +add action=accept chain=input protocol=icmp src-address-list=VDSina +add action=accept chain=input connection-state=established +add action=accept chain=input connection-state=related in-interface-list=\ + *2000014 +add action=drop chain=input in-interface=!Bridge-LAN +/ip firewall mangle +add action=mark-routing chain=prerouting comment=\ + "Mark Routing main for NoVdsina" dst-address-list=NoVdsina \ + new-routing-mark=main passthrough=no src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=\ + "Mark Routing main for VDSina" dst-address-list=VPN-Server \ + new-routing-mark=main src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=\ + "!!!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="Mark Routing main for NoWG" \ + new-routing-mark=main passthrough=no src-address=10.30.30.0/24 \ + src-address-list=NoWG +add action=mark-routing chain=prerouting comment="VDSIna for All sites" \ + disabled=yes dst-address=!10.30.30.0/24 dst-address-list=!NoVdsina \ + new-routing-mark=To-VPN src-address=10.30.30.0/24 src-address-list=!NoWG +add action=mark-connection chain=prerouting comment=\ + "Mark VPN connections to exclude from FastTrack" disabled=yes \ + new-connection-mark=VPN_No_FastTrack routing-mark=To-VPN +add action=change-mss chain=forward comment="MSS on WG" new-mss=1380 \ + out-interface=WG protocol=tcp routing-mark=To-VPN tcp-flags=syn tcp-mss=\ + 1381-65535 +add action=mark-routing chain=prerouting comment="VPN Network" dst-address=\ + 10.8.0.0/24 new-routing-mark=To-VPN src-address=10.30.30.0/24 +/ip firewall nat +add action=redirect chain=dstnat comment="udp Redirect DNS in NAT" disabled=\ + yes dst-port=53 protocol=udp src-address=10.30.30.0/24 to-addresses=\ + 10.30.30.81 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 to-addresses=\ + 10.30.30.81 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" dst-address=\ + !10.30.30.0/24 out-interface="ether1 - Unet" src-address=10.30.30.0/24 +add action=dst-nat chain=dstnat comment=amster.vados.ruhttps dst-port=443 \ + fragment=no in-interface="ether1 - Unet" protocol=tcp src-address=\ + !10.30.30.0/24 to-addresses=10.30.30.33 to-ports=443 +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="amster.vados.ru For Certbot HTTP" \ + dst-port=80 in-interface="ether1 - Unet" protocol=tcp to-addresses=\ + 10.30.30.33 to-ports=80 +add action=dst-nat chain=dstnat comment=npm dst-port=81 in-interface=\ + "ether1 - Unet" protocol=tcp routing-mark=To-VPN to-addresses=10.30.30.33 \ + to-ports=81 +add action=dst-nat chain=dstnat comment=SSH dst-port=22 in-interface=\ + "ether1 - Unet" protocol=tcp src-address-list=TRUSTED to-addresses=\ + 10.30.30.33 to-ports=22 +add action=dst-nat chain=dstnat comment="portainer agent" disabled=yes \ + dst-port=2377 in-interface="ether1 - Unet" protocol=tcp to-addresses=\ + 10.30.30.33 to-ports=2377 +add action=dst-nat chain=dstnat disabled=yes dst-port=22 in-interface=\ + "ether1 - Unet" protocol=tcp routing-mark=!To-VPN to-addresses=\ + 10.30.30.33 to-ports=22 +add action=masquerade chain=srcnat comment=WG dst-address-list=!NoVdsina \ + out-interface=WG routing-mark=To-VPN src-address-list=!NoWG +add action=dst-nat chain=dstnat comment="Yandex.DNS Family" disabled=yes \ + dst-port=53 in-interface=Bridge-LAN protocol=udp src-address-list=KIDS \ + time=6h-15m,sun,mon,tue,wed,thu,fri,sat to-addresses=77.88.8.3 +add action=dst-nat chain=dstnat disabled=yes dst-port=53 in-interface=\ + Bridge-LAN protocol=tcp src-address-list=KIDS time=\ + 6h-15m,sun,mon,tue,wed,thu,fri,sat to-addresses=77.88.8.3 +/ip firewall raw +add action=drop chain=prerouting comment="Drop Honeypot Hackers" \ + in-interface="ether1 - Unet" src-address-list="Honeypot Hacker" +add action=accept chain=prerouting comment="Trusted DNS" disabled=yes \ + in-interface-list=WAN src-address-list=Trusted-DNS +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + extras.getpagespeed.com content=extras.getpagespeed.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=linux.duke.edu \ + content=linux.duke.edu disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=youtube.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + googleapis.com disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=ggpht.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=youtu.be \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=ytimg.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + googlevideo.com disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=gstatic.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + googleusercontent.com disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + nhacmp3youtube.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=rutube.ru \ + content=rutube.ru disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment="me.com raw" \ + content=me.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "icloud.com raw" content=icloud.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "smtp.mail.me.com raw" content=smtp.mail.me.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "smtp.mail.me.com.akadns.net raw" content=smtp.mail.me.com.akadns.net \ + disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "api.db-ip.com raw" content=api.db-ip.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + esia.gosuslugi.ru content=esia.gosuslugi.ru disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=gosuslugi.ru \ + content=gosuslugi.ru disabled=yes +/ip firewall service-port +set ftp disabled=yes +set tftp disabled=yes +set irc disabled=no +set sip disabled=yes +set pptp disabled=yes +set rtsp disabled=no +/ip ipsec settings +set accounting=no +/ip ipsec policy +set 0 disabled=yes dst-address=0.0.0.0/0 src-address=0.0.0.0/0 +/ip ipsec profile +set [ find default=yes ] dpd-interval=2m dpd-maximum-failures=5 +/ip proxy +set cache-administrator="" max-cache-size=none port=80,443 src-address=\ + 0.0.0.0 +/ip route +add check-gateway=none disabled=yes distance=1 dst-address=0.0.0.0/0 gateway=\ + WG routing-table=To-VPN scope=30 target-scope=10 +/ip service +set ftp disabled=yes +set telnet disabled=yes +set reverse-proxy disabled=yes +set ssh address=10.30.30.0/24 port=2222 +set winbox address=10.30.30.0/24 +set api address=10.30.30.0/24 disabled=yes +set api-ssl address=10.30.30.0/24 disabled=yes +set www-ssl certificate=Root-YE port=18443 +set www address=10.30.30.0/24 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 \ + strong-crypto=yes +/ip upnp +set enabled=yes +/ip upnp interfaces +add interface=Bridge-LAN type=internal +add forced-ip=146.120.64.211 interface="ether1 - Unet" type=external +add forced-ip=109.107.177.79 interface=*E type=external +add interface=lo type=internal +add interface=wlan2 type=internal +add interface=wlan1 type=internal +/ipv6 dhcp-client +add add-default-route=yes disabled=yes interface=*F rapid-commit=no request=\ + info use-interface-duid=yes validate-server-duid=no +/ipv6 dhcp-server option sets +add name=domain-search-set options=domain-search-list +add name="=\"Client ID\"" options=HostName +/ipv6 firewall address-list +add address=::/128 comment="defconf: unspecified address" list=bad_ipv6 +add address=::1/128 comment="defconf: lo" list=bad_ipv6 +add address=fec0::/10 comment="defconf: site-local" list=bad_ipv6 +add address=::ffff:0.0.0.0/96 comment="defconf: ipv4-mapped" list=bad_ipv6 +add address=::/96 comment="defconf: ipv4 compat" list=bad_ipv6 +add address=100::/64 comment="defconf: discard only " list=bad_ipv6 +add address=2001:db8::/32 comment="defconf: documentation" list=bad_ipv6 +add address=2001:10::/28 comment="defconf: ORCHID" list=bad_ipv6 +add address=3ffe::/16 comment="defconf: 6bone" list=bad_ipv6 +/ipv6 firewall filter +add action=accept chain=input comment=\ + "defconf: accept established,related,untracked" connection-state=\ + established,related,untracked +add action=drop chain=input comment="defconf: drop invalid" connection-state=\ + invalid +add action=accept chain=input comment="defconf: accept ICMPv6" protocol=\ + icmpv6 +add action=accept chain=input comment="defconf: accept UDP traceroute" \ + dst-port=33434-33534 protocol=udp +add action=accept chain=input comment=\ + "defconf: accept DHCPv6-Client prefix delegation." dst-port=546 protocol=\ + udp src-address=fe80::/10 +add action=accept chain=input comment="defconf: accept IKE" dst-port=500,4500 \ + protocol=udp +add action=accept chain=input comment="defconf: accept ipsec AH" protocol=\ + ipsec-ah +add action=accept chain=input comment="defconf: accept ipsec ESP" protocol=\ + ipsec-esp +add action=accept chain=input comment=\ + "defconf: accept all that matches ipsec policy" ipsec-policy=in,ipsec +add action=drop chain=input comment=\ + "defconf: drop everything else not coming from LAN" in-interface-list=\ + !LAN +add action=accept chain=forward comment=\ + "defconf: accept established,related,untracked" connection-state=\ + established,related,untracked +add action=drop chain=forward comment="defconf: drop invalid" \ + connection-state=invalid +add action=drop chain=forward comment=\ + "defconf: drop packets with bad src ipv6" src-address-list=bad_ipv6 +add action=drop chain=forward comment=\ + "defconf: drop packets with bad dst ipv6" dst-address-list=bad_ipv6 +add action=drop chain=forward comment="defconf: rfc4890 drop hop-limit=1" \ + hop-limit=equal:1 protocol=icmpv6 +add action=accept chain=forward comment="defconf: accept ICMPv6" protocol=\ + icmpv6 +add action=accept chain=forward comment="defconf: accept HIP" protocol=139 +add action=accept chain=forward comment="defconf: accept IKE" dst-port=\ + 500,4500 protocol=udp +add action=accept chain=forward comment="defconf: accept ipsec AH" protocol=\ + ipsec-ah +add action=accept chain=forward comment="defconf: accept ipsec ESP" protocol=\ + ipsec-esp +add action=accept chain=forward comment=\ + "defconf: accept all that matches ipsec policy" ipsec-policy=in,ipsec +add action=drop chain=forward comment=\ + "defconf: drop everything else not coming from LAN" in-interface-list=\ + !LAN +/ipv6 nd +set [ find default=yes ] advertise-dns=yes disabled=yes interface=Bridge-LAN \ + managed-address-configuration=yes other-configuration=yes pref64=::/64 +/ipv6 nd prefix +add autonomous=no disabled=yes interface=Bridge-LAN on-link=no prefix=none +/ipv6 nd prefix default +set dhcp6-pd-preferred=yes +/ipv6 nd proxy +add disabled=yes interface=lo +/ipv6 nd settings +set router-advertisement-route-distance=100 +/routing bfd configuration +add addresses=10.8.0.0/24 disabled=no forbid-bfd=yes interfaces=*E min-rx=\ + 200ms min-tx=200ms multiplier=5 vrf=main +/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 +/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/20260619/20260619222002-Config.rsc b/MikroMaster/20260619/20260619222002-Config.rsc new file mode 100644 index 0000000..08e421b --- /dev/null +++ b/MikroMaster/20260619/20260619222002-Config.rsc @@ -0,0 +1,3679 @@ +# 2026-06-19 22:20:04 by RouterOS 7.23.1 +# software id = A8L5-07YF +# +# model = RB952Ui-5ac2nD +# serial number = D3D50CEDCD38 +/interface bridge +add admin-mac=48:8F:5A:8E:1A:BF auto-mac=no dhcpv6-agent-circuit-id=\ + "\$(INTERFACE):\$(VID)" dhcpv6-agent-remote-id="\$(BRIDGEMAC)" name=\ + Bridge-LAN port-cost-mode=short +/interface ethernet +set [ find default-name=ether1 ] comment="WAN - Unet" loop-protect=off name=\ + "ether1 - Unet" rx-flow-control=auto tx-flow-control=auto +set [ find default-name=ether2 ] comment=LAN-2 +set [ find default-name=ether3 ] advertise="10M-baseT-half,10M-baseT-full,100M\ + -baseT-half,100M-baseT-full,1G-baseT-full,1G-baseX" comment=LAN-3 +set [ find default-name=ether4 ] comment=LAN-4 +set [ find default-name=ether5 ] advertise="10M-baseT-half,10M-baseT-full,100M\ + -baseT-half,100M-baseT-full,1G-baseT-full,1G-baseX" comment=LAN-5 \ + loop-protect=on poe-out=off rx-flow-control=auto tx-flow-control=auto +/interface wireless +# managed by CAPsMAN +# channel: 2442/20-Ce/gn(18dBm), SSID: vados, local forwarding +set [ find default-name=wlan1 ] country=belarus disabled=no mode=ap-bridge \ + ssid=vados wireless-protocol=802.11 +# managed by CAPsMAN +# channel: 5200/20-eCee/ac/P(21dBm), SSID: vados5g, local forwarding +set [ find default-name=wlan2 ] country=belarus disabled=no mode=ap-bridge \ + ssid=vados5g wireless-protocol=802.11 +/interface wireguard +add comment=WG listen-port=13231 mtu=1320 name=WG +/interface list +add include=static name=LAN +add name=Internet +add include=Internet name=WAN +/interface wireless security-profiles +set [ find default=yes ] authentication-types=wpa-psk,wpa2-psk mode=\ + dynamic-keys supplicant-identity=MikroTik +/ip dhcp-server option +add code=12 name=HostName +add code=119 force=yes name=domain-search-list value="0x03'WORKGROUP'0x00" +/ip dhcp-server option sets +add name=HP1505n options=HostName +add name=StartLife1 options=HostName +add name=amsterDev options=HostName +add name=MiTV options=HostName +add name=miller options=HostName +add name=amster options=HostName +add name=garage options=HostName +add name=domain-search-set options=domain-search-list +add name=VADOS-LEN options=HostName +add name=VADOS-NUC options=HostName +add name=MikroNUC options=HostName +add name=master options=HostName +add name=MikroYellow options=HostName +add name="=\"Client ID\"" options=HostName +add name=iVados options=HostName +/ip dns forwarders +add dns-servers=1.1.1.1,1.0.0.1 name=blsp.at verify-doh-cert=no +add comment=Kra dns-servers=1.0.0.1,1.1.1.1 name=slon2.to verify-doh-cert=no +add dns-servers=1.1.1.1,1.0.0.1 name=slon3.at verify-doh-cert=no +add dns-servers=1.0.0.1,1.1.1.1 name=slon3.cc verify-doh-cert=no +add dns-servers=1.1.1.1,1.0.0.1 name=bs2web.at verify-doh-cert=no +add dns-servers=1.1.1.1,1.0.0.1 name=bs2best.at verify-doh-cert=no +add dns-servers=1.0.0.1,1.1.1.1 name=psrms.is verify-doh-cert=no +/ip ipsec proposal +set [ find default=yes ] disabled=yes +/ip pool +add name=dhcp ranges=10.30.30.83-10.30.30.254 +/ip dhcp-server +add add-arp=yes address-pool=dhcp always-broadcast=yes bootp-support=none \ + dhcp-option-set=domain-search-set interface=Bridge-LAN lease-time=10m \ + name=masterDHCP server-address=10.30.30.81 +/ip smb users +set [ find default=yes ] disabled=yes +add disabled=yes name=vados +/ipv6 dhcp-client option +add code=119 name=domain-search-list value="0x03'WORKGROUP'0x00" +add code=12 name=HostName value="\$(HOSTNAME)" +add code=61 name=DUID value=0x00030001488f5a8e1abc +add code=61 name=clientid +/ipv6 dhcp-server option +add code=119 name=domain-search-list value="0x03'WORKGROUP'0x00" +add code=12 name=HostName value="\$(HOSTNAME)" +add code=61 name=CLIENT_DUID +add code=61 name=CLIENT_MAC +/ppp profile +set *FFFFFFFE use-upnp=no +/routing bgp template +set default disabled=no output.network=bgp-networks +/routing table +add disabled=no fib name=To-VPN +/system logging action +add email-start-tls=yes email-to=vados@vados.ru name=email target=email +/system script +add dont-require-permissions=no name=fetchCustom owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + global GlobalScriptsUrl \"https://ros.vados.ru/\";\r\ + \n\r\ + \n#/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@1\ + 0.30.30.86.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.86.pub\";\ + \n\r\ + \n#:local Script AM-setup\ + \n;\r\ + \n#/system/script/add name=\$Script owner=\$Script source=([ /tool/fetch c\ + heck-certificate=yes-without-crl url=(\$GlobalScriptsUrl . \$Script . \".r\ + sc\") output=user as-value ]->\"data\");\r\ + \n\ + \n#/usb1/mikro_bak_rsa.pub\ + \n\ + \n\r\ + \n#\ + \n\r\ + \n#/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@1\ + 0.30.30.10.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.10.pub\";\ + \n\r\ + \n#\r\ + \n\ + \n#root.mnuc.backuper\ + \n\ + \n\r\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@10\ + .30.30.81.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.81.pub\";\r\ + \n\ + \n#:local Script AM-GlobalConfig;\ + \n\r\ + \n#/system/script/add name=\$Script owner=\$Script source=([ /tool/fetch c\ + heck-certificate=yes-without-crl url=(\$GlobalScriptsUrl . \$Script . \".r\ + sc\") output=user as-value ]->\"data\");\r\ + \n\ + \n#/usb1/mikro_bak_rsa.pub\ + \n#:local FetchFile AM-DOHCert.rsc\ + \n\ + \n\r\ + \n\r\ + \n#\ + \n:global MkDir;\ + \n\r\ + \n\ + \n#:local FetchFile Binary.backup\ + \n:local localDir \"\";\ + \n\ + \n\r\ + \n#\$MkDir \$localDir;\r\ + \n\ + \n#\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \$FetchFile) dst-path=(\ + \$localDir . \$FetchFile);\r\ + \n" +add comment="Global Config Script" dont-require-permissions=no name=\ + AM-GlobalConfig owner=AM-GlobalConfig policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\r\ + \n# RouterOS script: AM-GlobalConfig\r\ + \n# Script comment: Global Config Script\r\ + \n# Copyright (c) 2007-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# Warning: Dont touch this line!\r\ + \n:global Identity [/system/identity/get name];\r\ + \n:global GlobalConfReady false;\r\ + \n#\r\ + \n#\r\ + \n# Global Url For Amster scripts to fetch\r\ + \n# most be defined in AM-Init-Script or AM-setup scripts\r\ + \n:global GlobalScriptsUrl \"https://ros.vados.ru/\";\r\ + \n:global ScriptsUrlSuffix (a);\r\ + \n:global CheckSumsVerify true;\r\ + \n\r\ + \n:global ScriptUpdatesCRLF true;\r\ + \n:global CommentsInScripts true;\r\ + \n\r\ + \n# Debug output:\r\ + \n:global PrintDebug true; #false;\r\ + \n\r\ + \n# Debug output for specific script:\r\ + \n#:set (\$PrintDebugOverride->\"AM-GlobalFunc\") true;\r\ + \n\r\ + \n# Debug logs\r\ + \n# Other actions (disk, email, remote or support) can be used as well.\r\ + \n# I do not recommend using echo - use debug output instead (https://rsc.\ + eworm.de/main/DEBUG.html#debug-output).\r\ + \n#/system/logging/add topics=script,debug action=memory;\r\ + \n\r\ + \n:global MikrotikUpgradeUrl \"https://upgrade.mikrotik.com/routeros\";\r\ + \n:global Domain \"WORKGROUP\";\r\ + \n\r\ + \n:global EmailGeneralTo \"vados@vados.ru\";\r\ + \n#:global EmailGeneralCc \"\";\r\ + \n\r\ + \n# \$ScriptInstallUpdate mod/notification-telegram\r\ + \n:global TelegramTokenId \"8390868324:AAG3_d1hfVR2M6pGAgDK6ZvhOe4J97nyopw\ + \";\r\ + \n:global TelegramChatId \"-1003631309063\"; #\"454403445\";\r\ + \n# Use this to send notifications to a specific topic in group.\r\ + \n#:global TelegramThreadId \"30\";\r\ + \n# Using telegram-chat you have to define trusted chat ids (not group ids\ + !)\r\ + \n# or user names. Groups allow to chat with devices simultaneously.\r\ + \n:global TelegramChatIdsTrusted {\r\ + \n \"454403445\"\r\ + \n \"-1003631309063\"\r\ + \n \"-5124482807\"\r\ + \n \"1087968824\";\r\ + \n};\r\ + \n# \"-5294757340\";\r\ + \n\r\ + \n:global TelegramChatGroups \"(all)\";\r\ + \n#:global TelegramChatGroups \"(all|home|office)\";\r\ + \n\r\ + \n:global NotificationFunctions {\r\ + \n \"email\"\r\ + \n \"telegram\";\r\ + \n};\r\ + \n# Toggle this to disable symbols in notifications.\r\ + \n:global NotificationsWithSymbols true;\r\ + \n:global TerminalColorOutput true;\r\ + \n\r\ + \n:global DetectIpAddrDefault \"https://ipv4.mikrotik.ovh/\";\r\ + \n:global DetectIpAddrFallback \"https://api.ipify.org/\";\r\ + \n\r\ + \n## Update channel. Possible values: stable, long-term, testing, developm\ + ent\r\ + \n:global updateChannel \"stable\";\r\ + \n\r\ + \n:global CertRenewUrl (\$GlobalScriptsUrl . \"certs/\" . \$Identity . \"/\ + \");\r\ + \n:global CertRenewTime 2w;\r\ + \n:global CertRenewPass (a); #{\r\ + \n# \"\";\r\ + \n# \"v3ry-s3cr3t\";\r\ + \n# \"4n0th3r-s3cr3t\";\r\ + \n#};\r\ + \n:global CertWarnTime 1w;\r\ + \n:global CertIssuedExportPass (a); # {\r\ + \n# \"\";\r\ + \n# \"cert1-cn\"=\"v3ry-s3cr3t\";\r\ + \n# \"cert2-cn\"=\"4n0th3r-s3cr3t\";\r\ + \n#};\r\ + \n\r\ + \n# Script BackupAndUpdate mode, possible values: backup,\r\ + \n# updateOnce - Update once as \"osnotify\" and back \"osnotify\" mode (i\ + n terminal run :set OSUpdateMode updateOnce; \$OSUpdateMode;). \r\ + \n# osupdate - Update if available and creates backups before/after update\ + \_(ignores `forceBackup`)\r\ + \n# Set `forceBackup` to true to always create backups, even\ + \_without updates\r\ + \n# osnotify - Set `forceBackup` to always create backups on every run\r\ + \n:global DevInfoIncludeIP true;\r\ + \n:global BackupAndUpdateMode \"osnotify\"\r\ + \n\r\ + \n:global forceBackup true;\r\ + \n:global BackupPassword \"Peskar55\";\r\ + \n\r\ + \n# SFTP Backup Variables\r\ + \n:global BackupRandomDelay 0;\r\ + \n:global BackupUploadUrl \"sftp://amster.vados.ru/upload/\";\r\ + \n:global BackupUploadUser \$Identity;\r\ + \n:global BackupUploadPass \"root.mnuc.backuper\";\r\ + \n\r\ + \n:global BackupSendBinary true;\r\ + \n:global BackupSendExport true;\r\ + \n:global BackupSendGlobalConfig true;\r\ + \n:global BackupSendScripts true;\r\ + \n\r\ + \n# Remove local file after uploading if no errors\r\ + \n:global BackupRmLocal true;\r\ + \n\r\ + \n# Local Backups Root Directory \r\ + \n:global BackupLocalRoot \"tmpfs\";\r\ + \n\r\ + \n# Encrypt Backup\r\ + \n:global BackupEncrypt true;\r\ + \n\r\ + \n# Sensitive information in Backups\r\ + \n:global BackupSens true;\r\ + \n\r\ + \n# User Export\r\ + \n:global BackupUser true;\r\ + \n\r\ + \n# License Export (not for CHR, will silently skip)\r\ + \n:global BackupLicense false;\r\ + \n\r\ + \n# SSH Keys\r\ + \n:global BackupSshKeys true;\r\ + \n\r\ + \n# Certificate Export\r\ + \n:global BackupCerts true;\r\ + \n\r\ + \n# Certificate Password\r\ + \n:global BackupCertsPasswd \"\";\r\ + \n\r\ + \n# User-Manager Export\r\ + \n:global BackupUserMan false;\r\ + \n\r\ + \n# The Dude Export\r\ + \n:global BackupDude false;\r\ + \n\r\ + \n# User Files to export, comma-separated string or array of strings\r\ + \n# User Files are not removed on backup\r\ + \n# Any directory paths will be removed (/ -> _) on remote file\r\ + \n# Nonpresent files are silently skipped\r\ + \n:global BackupUserList \"autosupout.rif,autosupout.old.rif\";\r\ + \n\r\ + \n# load functions and any custom scripts\r\ + \n# [ /system/script/find where name=\"global-config-ov\ + erlay\" ], \\\r\ + \n# [ /system/script/find where name~\"^global-config-o\ + verlay\\\\.d/.\" ]\r\ + \n#\r\ + \n#:foreach Script in=([ /system/script/find where name=\"Amster-TGglobalV\ + ars\" ], [ /system/script/find where name=\"Amster-TGglobalFunc\" ]) do={\ + \r\ + \n# :onerror Err {\r\ + \n# /system/script/run \$Script;\r\ + \n# } do={\r\ + \n# :log error (\"Loading configuration from configs and functions\"\ + \_. [ /system/script/get \$Script name ] . \" failed: \" . \$Err);\r\ + \n# }\r\ + \n#}\r\ + \n#:log info \"\\ndevMode = \$devMode\";\r\ + \n#:log info \"\\ndevRunning = \$devRunning\";\r\ + \n:foreach Script in=[ /system/script/find where source~\"^#!rsc by Vados \ + GlobalRUN\\r\?\\n\" ] do={\r\ + \n :onerror Err {\r\ + \n /system/script/run \$Script;\r\ + \n } do={\r\ + \n :log error (\"Run script \" . [ /system/script/get \$Script name \ + ] . \" width marker \\\" GlobalRUN\\\" failed: \" . \$Err);\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n# signal we are ready\r\ + \n:set GlobalConfReady true;\r\ + \n:while (\$GlobalConfReady != true) do={:delay 500ms};\r\ + \n" +add comment="Global functions" dont-require-permissions=no name=AM-GlobalFunc \ + owner=AM-GlobalFunc policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\r\ + \n# RouterOS script: AM-GglobalFunc\r\ + \n# Script comment: Global functions\r\ + \n# Copyright (c) 2005-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version=7.19\r\ + \n# requires device-mode, fetch, scheduler\r\ + \n:local ExitOK false;\r\ + \n:local ScriptName [ :jobname ];\r\ + \n#:global checkRunJob \$SriptName;\r\ + \n#:global fixCRLF;\r\ + \n#:if (\$fixCRLF != false) do={\r\ + \n#:foreach fixScript in=([ /system/script/find where name~\"*\" ]) do={/s\ + ystem/script/set source=[ :tocrlf [ get \$fixScript source ] ] \$fixScript\ + }\r\ + \n#:if (\$fixCRLF != \"LF\") do={ /system/script/set source=[ :tocrlf [ g\ + et \$fixScript source ] ] \$fixScript};};\r\ + \n#}\r\ + \n:global GlobalFuncReady false;\r\ + \n\r\ + \n# Git commit id & info, expected configuration version\r\ + \n:global CommitId \"main/694/a1b071a6\";\r\ + \n:global CommitTAG \"unknown\";\r\ + \n:global CommitInfo \"Autocommit in repo: ros.vados.ru, generated by owne\ + r: root, in 13:30:04 15.06.2026.\";\r\ + \n\r\ + \n# The variables are received right here.\r\ + \n:global GlobalConfVersion 140;\r\ + \n\r\ + \n:global SumsDirAndFileName \"tmp/checksums.json\";\r\ + \n\r\ + \n:global Identity [/system/identity/get name];\r\ + \n:global IdentityShort [:pick \$Identity 0 18];\r\ + \n\r\ + \n:global devBoardName [/system/resource/get board-name];\r\ + \n:global devMode [/system/device-mode/get mode];\r\ + \n:global devCurArch [/system/resource/get architecture-name];\r\ + \n:global devCurVersion [/system/resource/get version];\r\ + \n\r\ + \n# Variables defined in AM-GlobalConfig.rsc\r\ + \n:global TerminalColorOutput;\r\ + \n:global CommentsInScripts;\r\ + \n:global DetectIpAddrDefault;\r\ + \n:global DetectIpAddrFallback;\r\ + \n:global updateChannel;\r\ + \n:global Domain;\r\ + \n:global EmailGeneralTo;\r\ + \n:global BackupAndUpdateMode;\r\ + \n\r\ + \n# Single functions, without nested functions.\r\ + \n:global MiniDateTimeStamp;\r\ + \n:global MicroDateTimeStamp;\r\ + \n\r\ + \n# Include globals \$PrintDebug and \$PrintDebugOverride\r\ + \n:global LogPrint;\r\ + \n\r\ + \n# DeviceInfo and Updates\r\ + \n:global IsCheckUpdates;\r\ + \n:global WaitCheckUpdates;\r\ + \n:global GetPubIp;\r\ + \n\r\ + \n:global GetArrDeviceInfo;\r\ + \n:global WaitArrDeviceInfo;\r\ + \n\r\ + \n:global devModel;\r\ + \n:global devRunningMode;\r\ + \n\r\ + \n:global devRbRevision;\r\ + \n:global devRbSerialNumber;\r\ + \n:global devRbVerAvail;\r\ + \n\r\ + \n:global runningChannelVersion;\r\ + \n:global runningChannel;\r\ + \n:global runningVersion;\r\ + \n\r\ + \n:global devBuildTime;\r\ + \n:global ROsVerAvail;\r\ + \n:global PkgUpdStatus;\r\ + \n:global currentUpdateChannel;\r\ + \n\r\ + \n:global ScriptInstallUpdate;\r\ + \n\r\ + \n:global DeviceInfo;\r\ + \n\r\ + \n:global OldMode;\r\ + \n\r\ + \n:global ParseKeyValueStore;\r\ + \n:global RandomDelay;\r\ + \n:global GetRandomNumber;\r\ + \n:global EscapeForRegEx;\r\ + \n:global CharacterMultiply;\r\ + \n:global CharacterReplace;\r\ + \n:global CleanFilePath;\r\ + \n:global CleanName;\r\ + \n\r\ + \n:global CommitBrief;\r\ + \n\r\ + \n:global EitherOr;\r\ + \n:global FormatLine;\r\ + \n:global GetRandom20CharAlNum;\r\ + \n:global GetRandom20CharHex;\r\ + \n:global GetRandomNumber;\r\ + \n:global Grep;\r\ + \n:global IfThenElse;\r\ + \n:global MAX;\r\ + \n:global MIN;\r\ + \n:global HumanReadableNum;\r\ + \n\r\ + \n:global IsFullyConnected;\r\ + \n:global IsDNSResolving;\r\ + \n:global IsTimeSync;\r\ + \n:global IsTimeSyncCached;\r\ + \n:global IsTimeSyncResetNtp;\r\ + \n\r\ + \n:global MkDir;\r\ + \n:global RmDir;\r\ + \n:global RmFile;\r\ + \n:global FileGet;\r\ + \n:global Unix2Dos;\r\ + \n:global UrlEncode;\r\ + \n:global WaitForFile;\r\ + \n:global ScriptLock;\r\ + \n:global SendTelegram;\r\ + \n:global NotificationFunctions;\r\ + \n:global SendNotification;\r\ + \n:global SendNotification2;\r\ + \n:global SymbolForNotification;\r\ + \n:global SymbolByUnicodeName;\r\ + \n:global ValidateSyntax;\r\ + \n:global CheckSumsVerify;\r\ + \n:global GlobalConfChanges;\r\ + \n:global GlobalConfMigration;\r\ + \n:global VersionToNum;\r\ + \n:global RequiredRouterOS;\r\ + \n:global ExitError;\r\ + \n:global ExitOnError;\r\ + \n\r\ + \n:global FetchHugeFiles;\r\ + \n:global FetchUserAgentStr;\r\ + \n:global FileExists;\r\ + \n:global CertificateAvailable;\r\ + \n:global CertificateDownload;\r\ + \n:global CertificateNameByCN;\r\ + \n:global CharacterMultiply;\r\ + \n\r\ + \n:global InspectVar;\r\ + \n:global InspectVarRet;\r\ + \n:global ParseCustom;\r\ + \n\r\ + \n:set IsCheckUpdates do={\r\ + \n :local isInfo [:tobool \$1];\r\ + \n :global updateChannel;\r\ + \n :global PkgUpdStatus;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n :global arrDeviceInfo;\r\ + \n :log info (\$0 . \" \\\$isInfo = \" . \$isInfo); \r\ + \n :local CurrentChannel [ /system/package/update/get channel ];\r\ + \n :if ([ :len \$updateChannel ] > 0 && \$CurrentChannel != \$updateChann\ + el) do={\r\ + \n :retry command={/system/package/update set channel=\$updateChannel} \ + \_delay=300ms max=5 on-error={};\r\ + \n :log info (\$0 . \" Set updates channel to: \$updateChannel\");\r\ + \n }\r\ + \n :local Update [ /system/package/update/get ];\r\ + \n :local Channel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set currentUpdateChannel \$Channel;\r\ + \n :log info (\$0 . \" Update Channel: \" . \$Channel . \".\");\r\ + \n :local StatusPkg \"undefined\";\r\ + \n :log info (\$0 . \" Checking for updates...\");\r\ + \n :retry command={:set \$StatusPkg ([/system/package/update/check-for-up\ + dates without-paging as-value]->\"status\")} \\\r\ + \n delay=300ms max=5 on-error={};\r\ + \n :log info (\$0 . \" \\\$StatusPkg = \" . \$StatusPkg);\r\ + \n :if (\$StatusPkg = \"New version is available\") do={ :set PkgUpdStatu\ + s true; } else={ :set PkgUpdStatus false; }\r\ + \n :set ROsVerAvail [ :tostr [ /system/package/update/get latest-version \ + ] ];\r\ + \n :log info (\$0 . \" \\\$PkgUpdStatus = \" . \$PkgUpdStatus);\r\ + \n :if (\$isInfo != false || \$PkgUpdStatus = true) do={\r\ + \n :log info (\$0 . \" \\\$PkgUpdStatus = \" . \$PkgUpdStatus);\r\ + \n :if ([ :typeof \$arrDeviceInfo ] != \"array\") do={\r\ + \n :set arrDeviceInfo [:toarray \$arrDeviceInfo];\r\ + \n }\r\ + \n :retry command={:set (\$arrDeviceInfo->\"devUpdates\") [ /system/pac\ + kage/update/get ]} delay=500ms max=5 on-error={:log error (\"Error\")};\r\ + \n :return true;\r\ + \n } else={\r\ + \n :return \$PkgUpdStatus;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set WaitCheckUpdates do={\r\ + \n :global IsCheckUpdates;\r\ + \n :global PkgUpdStatus;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n :global arrDeviceInfo;\r\ + \n :local Status \"\";\r\ + \n :local Update;\r\ + \n :local WaitCount 0;\r\ + \n :if ([ \$IsCheckUpdates true ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n :set Status [ :tostr [ /system/package/update/get status ] ];\r\ + \n :while ((\$Status = \"\" || \$Status = \"finding out latest version...\ + \") && \$WaitCount < 60) do={\r\ + \n :delay 1s;\r\ + \n :set WaitCount (\$WaitCount + 1);\r\ + \n :set Status [ :tostr [ /system/package/update/get status ] ];\r\ + \n }\r\ + \n :set Update [ /system/package/update/get ];\r\ + \n :set currentUpdateChannel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set ROsVerAvail [ :tostr (\$Update->\"latest-version\") ];\r\ + \n :if ((\$Update->\"status\") = \"New version is available\") do={\r\ + \n :set PkgUpdStatus true;\r\ + \n } else={\r\ + \n :set PkgUpdStatus false;\r\ + \n }\r\ + \n :if ([ :typeof \$arrDeviceInfo ] != \"array\") do={\r\ + \n :set arrDeviceInfo [:toarray \$arrDeviceInfo];\r\ + \n }\r\ + \n :set (\$arrDeviceInfo->\"devUpdates\") \$Update;\r\ + \n :if (\$Status = \"\" || \$Status = \"finding out latest version...\") \ + do={\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set WaitArrDeviceInfo do={\r\ + \n :global GetArrDeviceInfo;\r\ + \n :while ([ \$GetArrDeviceInfo ] = false) do={\r\ + \n :delay 1s;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set GetArrDeviceInfo do={\r\ + \n :global LogPrint;\r\ + \n :global arrDeviceInfo;\r\ + \n :global devBoardName;\r\ + \n :global devModel;\r\ + \n :global devRunning;\r\ + \n :global devCurArch;\r\ + \n :global devRbRevision;\r\ + \n :global devRbSerialNumber;\r\ + \n :global devBuildTime;\r\ + \n :global runningChannelVersion;\r\ + \n :global runningChannel;\r\ + \n :global runningVersion;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n\r\ + \n :local DeviceInfo;\r\ + \n :local Resource [/system/resource/get];\r\ + \n :local Update [ /system/package/update/get ];\r\ + \n :local VersionString [ :tostr (\$Resource->\"version\") ];\r\ + \n :local ChannelStart [ :find \$VersionString \" (\" ];\r\ + \n :local RouterBoard;\r\ + \n :local IsRouterBoard false;\r\ + \n :local RunningMode \"\";\r\ + \n\r\ + \n :set devCurArch [ :tostr (\$Resource->\"architecture-name\") ];\r\ + \n :set devBuildTime [ :tostr (\$Resource->\"build-time\") ];\r\ + \n :set runningChannelVersion \$VersionString;\r\ + \n :set runningVersion \$VersionString;\r\ + \n :set runningChannel \"\";\r\ + \n\r\ + \n :if ([ :typeof \$ChannelStart ] = \"num\" && \$ChannelStart >= 0) do=\ + {\r\ + \n :set runningVersion [ :pick \$VersionString 0 \$ChannelStart ];\r\ + \n :local ChannelRest [ :pick \$VersionString (\$ChannelStart + 2) [ :\ + len \$VersionString ] ];\r\ + \n :local ChannelEnd [ :find \$ChannelRest \")\" ];\r\ + \n :if ([ :typeof \$ChannelEnd ] = \"num\" && \$ChannelEnd >= 0) do={\ + \r\ + \n :set runningChannel [ :pick \$ChannelRest 0 \$ChannelEnd ];\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :if ([:pick \$devBoardName 0 3] != \"CHR\" or [:pick \$devBoardName 0\ + \_3] != \"x86\") do={\r\ + \n :do {\r\ + \n :set RouterBoard [[ :parse \"/system/routerboard/get\" ]];\r\ + \n# :set RouterBoard [ /system/routerboard/get ];\r\ + \n :if ((\$RouterBoard->\"routerboard\") = true) do={\r\ + \n :set IsRouterBoard true;\r\ + \n }\r\ + \n } on-error={}\r\ + \n }\r\ + \n\r\ + \n :do {\r\ + \n :set RunningMode [ /system/device-mode/get mode ];\r\ + \n } on-error={\r\ + \n :do {\r\ + \n :set RunningMode [ /system/device-mode/get running ];\r\ + \n } on-error={\r\ + \n :set RunningMode \"\";\r\ + \n }\r\ + \n }\r\ + \n :set devRunning \$RunningMode;\r\ + \n\r\ + \n :if (\$IsRouterBoard = true) do={\r\ + \n :set devModel [ :tostr (\$RouterBoard->\"model\") ];\r\ + \n :set devRbRevision [ :tostr (\$RouterBoard->\"revision\") ];\r\ + \n :set devRbSerialNumber [ :tostr (\$RouterBoard->\"serial-number\") \ + ];\r\ + \n } else={\r\ + \n :set devModel \$devBoardName;\r\ + \n :set devRbRevision \"\";\r\ + \n :set devRbSerialNumber \"\";\r\ + \n }\r\ + \n\r\ + \n :set currentUpdateChannel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set ROsVerAvail [ :tostr (\$Update->\"latest-version\") ];\r\ + \n\r\ + \n :set (\$DeviceInfo->\"board-name\") \$devBoardName;\r\ + \n :set (\$DeviceInfo->\"architecture-name\") \$devCurArch;\r\ + \n :set (\$DeviceInfo->\"model\") \$devModel;\r\ + \n :set (\$DeviceInfo->\"revision\") \$devRbRevision;\r\ + \n :set (\$DeviceInfo->\"serial-number\") \$devRbSerialNumber;\r\ + \n :set (\$DeviceInfo->\"running-mode\") \$devRunning;\r\ + \n :set (\$DeviceInfo->\"build-time\") \$devBuildTime;\r\ + \n :set (\$DeviceInfo->\"running-channel-version\") \$runningChannelVers\ + ion;\r\ + \n :set (\$DeviceInfo->\"running-version\") \$runningVersion;\r\ + \n :set (\$DeviceInfo->\"running-channel\") \$runningChannel;\r\ + \n :set (\$DeviceInfo->\"routerboard\") \$IsRouterBoard;\r\ + \n :set (\$DeviceInfo->\"current-firmware\") [ :tostr (\$RouterBoard->\"\ + current-firmware\") ];\r\ + \n :set (\$DeviceInfo->\"upgrade-firmware\") [ :tostr (\$RouterBoard->\"\ + upgrade-firmware\") ];\r\ + \n :set (\$DeviceInfo->\"package-channel\") \$currentUpdateChannel;\r\ + \n :set (\$DeviceInfo->\"installed-version\") [ :tostr (\$Update->\"inst\ + alled-version\") ];\r\ + \n :set (\$DeviceInfo->\"latest-version\") \$ROsVerAvail;\r\ + \n :set (\$DeviceInfo->\"update-status\") [ :tostr (\$Update->\"status\"\ + ) ];\r\ + \n\r\ + \n :set arrDeviceInfo \$DeviceInfo;\r\ + \n :return \$DeviceInfo;\r\ + \n}\r\ + \n\r\ + \n:set DeviceInfo do={\r\ + \n :global GetArrDeviceInfo;\r\ + \n :global GlobalConfVersion;\r\ + \n :global Identity;\r\ + \n :global IfThenElse;\r\ + \n :global FormatLine;\r\ + \n :global CommitBrief;\r\ + \n\r\ + \n :local License [/system/license/get];\r\ + \n :local Snmp [ /snmp/get ];\r\ + \n :local Info [ \$GetArrDeviceInfo ];\r\ + \n\r\ + \n :if ([ :typeof \$Info ] != \"array\") do={\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :return ( \\\r\ + \n [ \$FormatLine \"Hostname\" \$Identity ] . \"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$Snmp->\"location\") ] > 0) \\\r\ + \n ([ \$FormatLine \"Location\" (\$Snmp->\"location\") ] . \"\\n\") ]\ + \_. \\\r\ + \n [ \$IfThenElse ([ :len (\$Snmp->\"contact\") ] > 0) \\\r\ + \n ([ \$FormatLine \"Contact\" (\$Snmp->\"contact\") ] . \"\\n\") ] .\ + \_\\\r\ + \n \"Hardware:\\n\" . \\\r\ + \n [ \$FormatLine \" Board\" (\$Info->\"board-name\") ] . \"\\n\" . \ + \\\r\ + \n [ \$FormatLine \" Arch\" (\$Info->\"architecture-name\") ] . \"\\\ + n\" . \\\r\ + \n [ \$FormatLine \" Model\" (\$Info->\"model\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"revision\") ] > 0) \\\r\ + \n (\" \" . (\$Info->\"revision\")) ] . \"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"serial-number\") ] > 0) \\\r\ + \n ([ \$FormatLine \" Serial\" (\$Info->\"serial-number\") ] . \"\ + \\n\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$License->\"nlevel\") ] > 0) \\\r\ + \n ([ \$FormatLine \" License\" (\"level \" . (\$License->\"nlevel\ + \")) ] . \"\\n\") ] . \\\r\ + \n \"RouterOS:\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$License->\"level\") ] > 0) \\\r\ + \n ([ \$FormatLine \" License\" (\"level \" . (\$License->\"level\ + \")) ] . \"\\n\") ] . \\\r\ + \n [ \$FormatLine \" Channel\" (\$Info->\"package-channel\") ] . \"\ + \\n\" . \\\r\ + \n [ \$FormatLine \" Installed\" (\$Info->\"installed-version\") ] .\ + \_\"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"running-channel\") ] > 0) \\\r\ + \n ([ \$FormatLine \" Running\" ((\$Info->\"running-version\") . \ + \" (\" . (\$Info->\"running-channel\") . \")\") ] . \"\\n\") \\\r\ + \n ([ \$FormatLine \" Running\" (\$Info->\"running-version\") ] . \ + \"\\n\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"latest-version\") ] > 0 && \\\r\ + \n (\$Info->\"installed-version\") != (\$Info->\"latest-version\"))\ + \_\\\r\ + \n ([ \$FormatLine \" Available\" (\$Info->\"latest-version\") ] .\ + \_\"\\n\") ] . \\\r\ + \n [ \$IfThenElse ((\$Info->\"routerboard\") = true && \\\r\ + \n (\$Info->\"current-firmware\") != (\$Info->\"upgrade-firmware\")\ + ) \\\r\ + \n ([ \$FormatLine \" Firmware\" ((\$Info->\"current-firmware\") .\ + \_\" -> \" . (\$Info->\"upgrade-firmware\")) ] . \"\\n\") ] . \\\r\ + \n \"RouterOS-Scripts:\\n\" . \\\r\ + \n [ \$FormatLine \" Commit\" [ \$CommitBrief ] ] . \"\\n\" . \\\r\ + \n [ \$FormatLine \" Version\" \$GlobalConfVersion ]);\r\ + \n}\r\ + \n\r\ + \n:if ([ :typeof \$NotificationFunctions ] != \"array\") do={:set Notifica\ + tionFunctions ({})}\r\ + \n\r\ + \n:set GetRandom20CharAlNum do={\r\ + \n :global EitherOr;\r\ + \n :return [ :rndstr length=[ \$EitherOr [ :tonum \$1 ] 20 ] from=\"ABCDE\ + FGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\" ];\r\ + \n}\r\ + \n\r\ + \n:set GetRandom20CharHex do={:global EitherOr; :return [ :rndstr length=[\ + \_\$EitherOr [ :tonum \$1 ] 20 ] from=\"0123456789abcdef\" ]; }\r\ + \n:set GetRandomNumber do={:global EitherOr; :return [ :rndnum from=0 to=[\ + \_\$EitherOr [ :tonum \$1 ] 4294967295 ] ]; }\r\ + \n\r\ + \n:global checkRunJob;\r\ + \n:set checkRunJob do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :global ScriptLock; \r\ + \n :if ([ \$ScriptLock \$Script ] = false) do={:return false}\r\ + \n :foreach Job in=[ /system/script/job/find where script=\$Script ] do={\ + :set Job [ /system/script/job/get \$Job ];\r\ + \n :while ([ :typeof (\$Job->\"parent\") ] = \"id\") do={:set Job [ /sy\ + stem/script/job/get [ find where .id=(\$Job->\"parent\") ] ]}\r\ + \n :if ((\$Job->\"type\") = \"login\") do={:return true};}; :return fa\ + lse; \r\ + \n}\r\ + \n\r\ + \n:set InspectVar do={\r\ + \n :global InspectVarRet;\r\ + \n :put [ :tocrlf [ \$InspectVarRet \$1 ] ];\r\ + \n}\r\ + \n\r\ + \n:set CommitBrief do={\r\ + \n :global CommitId;\r\ + \n :global CommitInfo;\r\ + \n :if (\$CommitId = \"unknown\") do={\r\ + \n :return \"unknown\";\r\ + \n }\r\ + \n :return (\$CommitInfo . \"/\" . [ :pick \$CommitId 0 8 ]);\r\ + \n}\r\ + \n\r\ + \n:set InspectVarRet do={\r\ + \n :local Input \$1;\r\ + \n :local Level (0 + [ :tonum \$2 ]);\r\ + \n :global CharacterReplace;\r\ + \n :global IfThenElse;\r\ + \n :global InspectVarRet;\r\ + \n :local IndentReturn do={\r\ + \n :local Prefix [ :tostr \$1 ];\r\ + \n :local Value [ :tostr \$2 ];\r\ + \n :local Level [ :tonum \$3 ];\r\ + \n :global CharacterMultiply;\r\ + \n :return ([ \$CharacterMultiply \" \" (\$Level * 2) ] . \"-\" . \$Pre\ + fix . \"-> \" . \$Value);\r\ + \n }\r\ + \n :local TypeOf [ :typeof \$Input ];\r\ + \n :local Len [ :len \$Input ];\r\ + \n :local Return [ \$IndentReturn \"type\" \$TypeOf \$Level ];\r\ + \n :if (\$TypeOf = \"array\") do={\r\ + \n :foreach Key,Value in=\$Input do={\r\ + \n :set \$Return (\$Return . \"\\n\" . \\\r\ + \n [ \$IndentReturn \"key\" \$Key (\$Level + 1) ] . \"\\n\" . \\\r\ + \n [ \$InspectVarRet \$Value (\$Level + 2) ]);\r\ + \n }\r\ + \n } else={\r\ + \n :if (\$TypeOf = \"str\") do={\r\ + \n :set \$Return (\$Return . \"\\n\" . \\\r\ + \n [ \$IndentReturn \"len\" \$Len \$Level ]);\r\ + \n :if ([ :typeof [ :find \$Input (\"\\r\") ] ] = \"num\") do={\r\ + \n :set Input [ \$CharacterReplace \$Input (\"\\r\") \"\" ];\r\ + \n }\r\ + \n :if ([ :typeof [ :find \$Input (\"\\n\") ] ] = \"num\") do={\r\ + \n :set Input [ \$CharacterReplace \$Input (\"\\n\") \" \" ];\r\ + \n }\r\ + \n }\r\ + \n :if (\$TypeOf != \"nothing\") do={\r\ + \n :set \$Return (\$Return . \"\\n\" . \\\r\ + \n [ \$IndentReturn \"value\" [ \$IfThenElse ([ :len \$Input ] > 80)\ + \_\\\r\ + \n ([ :pick \$Input 0 77 ] . \"...\") \$Input ] \$Level ]);\r\ + \n }\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set GetPubIp do={\r\ + \n :global DetectIpAddrDefault;\r\ + \n :global DetectIpAddrFallback;\r\ + \n\r\ + \n :local PubIpAddr false;\r\ + \n :local Url \$DetectIpAddrDefault;\r\ + \n :local JobName [ :jobname ];\r\ + \n\r\ + \n :do {\r\ + \n :log debug (\$0 . \" Trying to detect public IP using default serv\ + ice: \" . \$Url . \"...\");\r\ + \n :retry command={:set PubIpAddr ([ /tool/fetch http-method=\"get\"\ + \_check-certificate=yes-without-crl \$Url output=user as-value ]->\"data\"\ + )} \\\r\ + \n delay=50ms max=5 on-error={:log error (\$JobName . \" Failed to \ + detect public IP using default service: \" . \$Url . \".\")}\r\ + \n } on-error={\r\ + \n :log error (\$0 . \" Failed to detect public IP using default serv\ + ice: \" . \$Url . \".\");\r\ + \n :set Url \$DetectIpAddrFallBack;\r\ + \n :log debug (\$0 . \" Trying to detect public IP using fallback ser\ + vice: \" . \$Url . \"...\");\r\ + \n :retry command={:set PubIpAddr ([ /tool/fetch http-method=\"get\"\ + \_check-certificate=yes-without-crl \$Url output=user as-value ]->\"data\"\ + )} \\\r\ + \n delay=200ms max=5 on-error={:log error (\$JobName . \" Failed to\ + \_detect public IP using fallback service: \" . \$Url . \".\")}\r\ + \n };\r\ + \n :local IpLen ([ :len \$PubIpAddr ] -1);\r\ + \n :if (\$PubIpAddr = false) do={:set PubIpAddr \"not-detected\"} else=\ + {:set PubIpAddr [:pick \$PubIpAddr 0 \$IpLen]}\r\ + \n :return \$PubIpAddr;\r\ + \n}\r\ + \n\r\ + \n:set FormatLine do={\r\ + \n :local Key [ :tostr \$1 ];\r\ + \n :local Value [ :tostr \$2 ];\r\ + \n :local Indent [ :tonum \$3 ];\r\ + \n :local Spaces;\r\ + \n :local Return \"\";\r\ + \n :global CharacterMultiply;\r\ + \n :global EitherOr;\r\ + \n :set Indent [ \$EitherOr \$Indent 16 ];\r\ + \n :local Spaces [ \$CharacterMultiply \" \" \$Indent ];\r\ + \n :if ([ :len \$Key ] > 0) do={ :set Return (\$Key . \":\")}\r\ + \n :if ([ :len \$Key ] > (\$Indent - 2)) do={:set Return (\$Return . \"\\\ + n\" . [ :pick \$Spaces 0 \$Indent ] . \$Value);\r\ + \n } else={:set Return (\$Return . [ :pick \$Spaces 0 (\$Indent - [ :len \ + \$Return ]) ] . \$Value)}\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set ParseCustom do={\r\ + \n :local Str [ :tostr \$1 ];\r\ + \n :local Start [:find [ \$Str ] [:tostr \$2]];\r\ + \n :local End [ :tostr \$3 ];\r\ + \n :local Num [ :tonum \$4 ];\r\ + \n :local Return;\r\ + \n :if ([:len \$Num] = 0) do={:set Num \"0\"}\r\ + \n :local rest [:pick \$Str (\$Start+\$Num) [:len \$Str]]; \r\ + \n :if ([:len \$End ] = 0) do={:set Return [:pick \$Str \$Num \$Start]} e\ + lse={\r\ + \n :set End [:find \$rest \$End];\r\ + \n :set Return [:pick \$rest 0 \$End];\r\ + \n }\r\ + \n:return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set LogPrint do={\r\ + \n :local Severity [ :tostr \$1 ];\r\ + \n :local Name [ :tostr \$2 ];\r\ + \n :local Message [ :tostr \$3 ];\r\ + \n :global PrintDebug;\r\ + \n :global PrintDebugOverride;\r\ + \n :global EitherOr;\r\ + \n :local Debug [ \$EitherOr (\$PrintDebugOverride->\$Name) \$PrintDebug \ + ];\r\ + \n :local PrintSeverity do={\r\ + \n :global TerminalColorOutput;\r\ + \n :if (\$TerminalColorOutput != true) do={:return \$1}\r\ + \n :local Color { debug=96; info=97; warning=93; error=91 };\r\ + \n :return (\"\\1B[\" . \$Color->\$1 . \"m\" . \$1 . \"\\1B[0m\");\r\ + \n}\r\ + \n :local Log ([ \$EitherOr \$Name \"\" ] . \": \" . \$Message);\ + \r\ + \n :if (\$Severity ~ (\"^(custom|debug|error|info)\\\$\")) do={\r\ + \n :if (\$Severity = \"debug\") do={:log debug \$Log}\r\ + \n :if (\$Severity = \"error\") do={:log error \$Log}\r\ + \n :if (\$Severity = \"info\" ) do={:log info \$Log}\r\ + \n } else={:log warning \$Log; :set Severity \"warning\"}\r\ + \n :if (\$Severity != \"debug\" || \$Debug = true) do={:put ([ \$PrintSev\ + erity \$Severity ] . \": \" . \$Message)}\r\ + \n}\r\ + \n\r\ + \n:set CertificateAvailable do={\r\ + \n :local CommonName [ :tostr \$1 ];\r\ + \n :local UseFor [ :tostr \$2 ];\r\ + \n\r\ + \n :global CertificateDownload;\r\ + \n :global ParseKeyValueStore;\r\ + \n\r\ + \n :if ([ :len \$UseFor ] = 0) do={\r\ + \n :log warning (\$0 . \"The intended use is undefined!\");\r\ + \n :set UseFor \"undefined\";\r\ + \n }\r\ + \n :if ([ /system/resource/get free-hdd-space ] < 8388608 && \\\r\ + \n [ /certificate/settings/get crl-download ] = true && \\\r\ + \n [ /certificate/settings/get crl-store ] = \"system\") do={\r\ + \n :log warning (\$0 . \"This system has low free flash space but \" . \ + \\\r\ + \n \"is configured to download certificate CRLs to system!\");\r\ + \n }\r\ + \n :if ([ :len \$CommonName ] = 0) do={\r\ + \n :log warning (\$0 . \"No CommonName given!\");\r\ + \n :return false;\r\ + \n }\r\ + \n :local CertSettings [ /certificate/settings/get ];\r\ + \n :if (((\$CertSettings->\"builtin-trust-anchors\") = \"trusted\" || \\\ + \r\ + \n (\$CertSettings->\"builtin-trust-store\") ~ \$UseFor || \\\r\ + \n (\$CertSettings->\"builtin-trust-store\") = \"all\") && \\\r\ + \n [ :len [ /certificate/builtin/find where common-name=\$CommonName\ + \_] ] > 0) do={\r\ + \n :return true;\r\ + \n }\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] = 0\ + ) do={\r\ + \n :log info (\$0 . \"Certificate with CommonName '\" . \$CommonName . \ + \"' not available.\");\r\ + \n :if ([ \$CertificateDownload \$CommonName ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] > 1\ + ) do={\r\ + \n :log info (\$0 . \"There are \" . \$CertCount . \" Certificates with\ + \_CommonName '\" . \$CommonName . \"'. Should be ok.\");\r\ + \n :return true;\r\ + \n }\r\ + \n :local CertVal [ /certificate/get [ find where common-name=\$CommonNam\ + e ] ];\r\ + \n :while ((\$CertVal->\"akid\") != \"\" && (\$CertVal->\"akid\") != (\$C\ + ertVal->\"skid\")) do={\r\ + \n :if ([ :len [ /certificate/find where skid=(\$CertVal->\"akid\") ] ]\ + \_= 0) do={\r\ + \n :local IssuerCN ([ \$ParseKeyValueStore (\$CertVal->\"issuer\") ]-\ + >\"CN\");\r\ + \n :log info (\$0 . \"Certificate chain for '\" . \$CommonName . \"' \ + is incomplete, missing '\" . \$IssuerCN . \"'.\");\r\ + \n :if ([ \$CertificateDownload \$IssuerCN ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n :set CertVal [ /certificate/get [ find where skid=(\$CertVal->\"akid\ + \") ] ];\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set CertificateDownload do={\r\ + \n :local CommonName [ :tostr \$1 ];\r\ + \n :global ScriptUpdatesBaseUrl;\r\ + \n :global ScriptUpdatesUrlSuffix;\r\ + \n :global CertificateNameByCN;\r\ + \n :global CleanName;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global RmFile;\r\ + \n :global WaitForFile;\r\ + \n\r\ + \n :log info (\$0 . \"Downloading and importing certificate with \" . \\\ + \r\ + \n \"CommonName '\" . \$CommonName . \"'.\");\r\ + \n :local FileName ([ \$CleanName \$CommonName ] . \".pem\");\r\ + \n :do {\r\ + \n /tool/fetch check-certificate=yes-without-crl mode=https http-header\ + -field=({ [ \$FetchUserAgentStr \$0 ] }) \\\r\ + \n (\$ScriptUpdatesBaseUrl . \"certs/\" . \$FileName . \$ScriptUpdate\ + sUrlSuffix) \\\r\ + \n dst-path=\$FileName as-value;\r\ + \n \$WaitForFile \$FileName;\r\ + \n } on-error={\r\ + \n :log warning (\$0 . \" Failed downloading certificate with CommonNam\ + e '\" . \$CommonName . \\\r\ + \n \"' from repository! Trying fallback to mkcert.org...\");\r\ + \n :do {\r\ + \n :local CertSettings [ /certificate/settings/get ];\r\ + \n :if ([ :len [ /certificate/find where common-name=\"ISRG Root X1\"\ + \_] ] = 0 && \\\r\ + \n !(((\$CertSettings->\"builtin-trust-anchors\") = \"trusted\" \ + || \\\r\ + \n (\$CertSettings->\"builtin-trust-store\") ~ \"fetch\" || \ + \\\r\ + \n (\$CertSettings->\"builtin-trust-store\") = \"all\") && \\\ + \r\ + \n [ :len [ /certificate/builtin/find where common-name=\"ISRG\ + \_Root X1\" ] ] > 0)) do={\r\ + \n :log error (\$0 . \" Required certificate is not available.\");\ + \r\ + \n :return false;\r\ + \n }\r\ + \n /tool/fetch check-certificate=yes-without-crl mode=https http-head\ + er-field=({ [ \$FetchUserAgentStr \$0 ] }) \\\r\ + \n url=\"https://mkcert.org/generate/\" http-data=[ :serialize to=jso\ + n ({ \$CommonName }) ] \\\r\ + \n dst-path=\$FileName as-value;\r\ + \n \$WaitForFile \$FileName;\r\ + \n :if ([ /file/get \$FileName size ] = 0) do={\r\ + \n \$RmFile \$FileName;\r\ + \n :error false;\r\ + \n }\r\ + \n } on-error={\r\ + \n :log error (\$0 . \" Failed downloading certificate with CommonNam\ + e '\" . \$CommonName . \"'!\");\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n /certificate/import file-name=\$FileName passphrase=\"\" as-value;\r\ + \n :delay 1s;\r\ + \n \$RmFile \$FileName;\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] = 0\ + ) do={\r\ + \n /certificate/remove [ find where name~(\"^\" . \$FileName . \"_[0-9]\ + +\\\$\") ];\r\ + \n :log warning (\$0 . \" Certificate with CommonName '\" . \$CommonNam\ + e . \"' still unavailable!\");\r\ + \n :return false;\r\ + \n }\r\ + \n :foreach Cert in=[ /certificate/find where name~(\"^\" . \$FileName . \ + \"_[0-9]+\\\$\") ] do={\r\ + \n \$CertificateNameByCN [ /certificate/get \$Cert common-name ];\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set CertificateNameByCN do={\r\ + \n :local Match [ :tostr \$1 ];\r\ + \n :global CleanName;\r\ + \n :local Cert ([ /certificate/find where (common-name=\$Match or fingerp\ + rint=\$Match or name=\$Match) ]->0);\r\ + \n :if ([ :len \$Cert ] = 0) do={\r\ + \n :log warning (\$0 .\" No matching certificate found.\");\r\ + \n :return false;\r\ + \n }\r\ + \n :local CommonName [ /certificate/get \$Cert common-name ];\r\ + \n /certificate/set \$Cert name=[ \$CleanName \$CommonName ];\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set CharacterMultiply do={\r\ + \n :local Str [ :tostr \$1 ];\r\ + \n :local Num [ :tonum \$2 ];\r\ + \n :if (\$Num = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :for I from=1 to=\$Num do={:set Return (\$Return . \$Str)}\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set FileExists do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :local Type [ :tostr \$2 ];\r\ + \n :global FileGet;\r\ + \n :local FileVal [ \$FileGet \$FileName ];\r\ + \n :if (\$FileVal = false) do={ :return false; }\r\ + \n :if ([ :len (\$FileVal->\"size\") ] = 0) do={ :return false; }\r\ + \n :if ([ :len \$Type ] = 0 || \$FileVal->\"type\" = \$Type) do={ :return\ + \_true; }\r\ + \n :return false;\r\ + \n}\r\ + \n\r\ + \n:set Grep do={\r\ + \n :local Input ([ :tostr \$1 ] . \"\\n\");\r\ + \n :local Pattern [ :tostr \$2 ];\r\ + \n :if ([ :typeof [ :find \$Input \$Pattern ] ] = \"nil\") do={:return []\ + }\r\ + \n :do {\r\ + \n :local Line [ :pick \$Input 0 [ :find \$Input \"\\n\" ] ];\r\ + \n :if ([ :typeof [ :find \$Line \$Pattern ] ] = \"num\") do={:return \ + \$Line}\r\ + \n :set Input [ :pick \$Input ([ :find \$Input \"\\n\" ] + 1) [ :len \$\ + Input ] ];\r\ + \n } while=([ :len \$Input ] > 0);\r\ + \n :return [];\r\ + \n}\r\ + \n\r\ + \n:set HumanReadableNum do={\r\ + \n :local Input [ :tonum \$1 ];\r\ + \n :local Base [ :tonum \$2 ];\r\ + \n :global EitherOr;\r\ + \n :global IfThenElse;\r\ + \n :local Prefix \"kMGTPE\";\r\ + \n :local Pow 1;\r\ + \n :set Base [ \$EitherOr \$Base 1024 ];\r\ + \n :local Bin [ \$IfThenElse (\$Base = 1024) \"i\" \"\" ];\r\ + \n :if (\$Input < \$Base) do={:return \$Input}\r\ + \n :for I from=0 to=[ :len \$Prefix ] do={\r\ + \n :set Pow (\$Pow * \$Base);\r\ + \n :if (\$Input / \$Base < \$Pow) do={\r\ + \n :set Prefix [ :pick \$Prefix \$I ];\r\ + \n :local Tmp1 (\$Input * 100 / \$Pow);\r\ + \n :local Tmp2 (\$Tmp1 / 100);\r\ + \n :if (\$Tmp2 >= 100) do={:return (\$Tmp2 . \$Prefix . \$Bin)}\r\ + \n :return (\$Tmp2 . \".\" . \\\r\ + \n [ :pick \$Tmp1 [ :len \$Tmp2 ] ([ :len \$Tmp1 ] - [ :len \$Tmp\ + 2 ] + 1) ] . \\\r\ + \n \$Prefix . \$Bin);\r\ + \n }\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set CleanFilePath do={\r\ + \n :local Path [ :tostr \$1 ];\r\ + \n :global CharacterReplace;\r\ + \n :while (\$Path ~ \"//\") do={ :set \$Path [ \$CharacterReplace \$Path \ + \"//\" \"/\" ]; }\r\ + \n :if ([ :pick \$Path 0 ] = \"/\") do={ :set Path [ :pick \$Path 1 [ :le\ + n \$Path ] ]; }\r\ + \n :if ([ :pick \$Path ([ :len \$Path ] - 1) ] = \"/\") do={ :set Path [ \ + :pick \$Path 0 ([ :len \$Path ] - 1) ]; }\r\ + \n :return \$Path;\r\ + \n}\r\ + \n\r\ + \n:set CleanName do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :local Return \"\";\r\ + \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ + \n :local Char [ :pick \$Input \$I ];\r\ + \n :if ([ :typeof [ find \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr\ + stuvwxyz0123456789\" \$Char ] ] = \"nil\") do={\r\ + \n :do {:if ([ :len \$Return ] = 0) do={:error true};\r\ + \n :if ([ :pick \$Return ([ :len \$Return ] - 1) ] = \"-\") do={:er\ + ror true}; :set Char \"-\"} on-error={:set Char \"\"}; \r\ + \n };\r\ + \n :set Return (\$Return . \$Char)};\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set RandomDelay do={\r\ + \n :local Time [ :tonum \$1 ];\r\ + \n :local Unit [ :tostr \$2 ];\r\ + \n :global EitherOr;\r\ + \n :global GetRandomNumber;\r\ + \n :global MAX;\r\ + \n :if (\$Time = 0) do={:return false}\r\ + \n :delay ([ \$MAX 10 [ \$GetRandomNumber ([ :tonsec [ :totime (\$Time . \ + [ \$EitherOr \$Unit \"s\" ]) ] ] / 1000000) ] ] . \"ms\");\r\ + \n}\r\ + \n\r\ + \n:set EscapeForRegEx do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :if ([ :len \$Input ] = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :local Chars (\"^.[]\\\$()|*+\?{}\\\\\");\r\ + \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ + \n :local Char [ :pick \$Input \$I ];\r\ + \n :if ([ :find \$Chars \$Char ]) do={:set Char (\"\\\\\" . \$Char)}\r\ + \n :set Return (\$Return . \$Char);\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set ExitError do={\r\ + \n :local ExitOK [ :tostr \$1 ];\r\ + \n :local Name [ :tostr \$2 ];\r\ + \n :local Error [ :tostr \$3 ];\r\ + \n :global IfThenElse;\r\ + \n :if (\$ExitOK = \"false\") do={\r\ + \n :log error (\$Name [ \$IfThenElse ([ :pick \$Name 0 1 ] = \"\\\$\") \ + \\\r\ + \n \"Function\" \"Script\" ] . \" '\" . \$Name . \"' exited with er\ + ror\" . \\\r\ + \n [ \$IfThenElse (!(\$Error ~ \"^(|true|false)\\\$\")) (\": \" . \ + \$Error) \".\" ]);\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set ExitOnError do={\r\ + \n :local Name [ :tostr \$1 ];\r\ + \n :local Error [ :tostr \$2 ];\r\ + \n :global IfThenElse;\r\ + \n :log error (\$Name . \" \" . [ \$IfThenElse ([ :pick \$Name 0 1 ] = \"\ + \\\$\") \\\r\ + \n \"Function\" \"Script\" ] . \" '\" . \$Name . \"' exited with erro\ + r\" . \\\r\ + \n [ \$IfThenElse (!(\$Error ~ \"^(|true|false)\\\$\")) (\": \" . \$E\ + rror) \".\" ]);\r\ + \n}\r\ + \n\r\ + \n:set MiniDateTimeStamp do={\r\ + \n :local mikro [ :tobool \$1 ];\r\ + \n /system/clock;\r\ + \n :local vdate [get date];\r\ + \n :local vtime [get time];\r\ + \n :local vdoff [:toarray \"0,4,5,7,8,10\"];\r\ + \n :local MM [:pick \$vdate (\$vdoff->2) (\$vdoff->3)];\r\ + \n :local M [:tonum \$MM];\r\ + \n :if (\$vdate ~ \".../../....\") do={\r\ + \n :set vdoff [:toarray \"7,11,1,3,4,6\"];\r\ + \n :set M ([:find \"xxanebarprayunulugepctovecANEBARPRAYUNULUGE\ + PCTOVEC\" [:pick \$vdate (\$vdoff->2) (\$vdoff->3)] -1] / 2);\r\ + \n :if (\$M>12) do={:set M (\$M - 12)}\r\ + \n :set MM [:pick (100 + \$M) 1 3];\r\ + \n }\r\ + \n :local yyyy [:pick \$vdate (\$vdoff->0) (\$vdoff->1)];\r\ + \n :local dd [:pick \$vdate (\$vdoff->4) (\$vdoff->5)];\r\ + \n :local HH [:pick \$vtime 0 2];\r\ + \n :local mm [:pick \$vtime 3 5];\r\ + \n :local ss [:pick \$vtime 6 8];\r\ + \n :local Return;\r\ + \n :if (\$mikro = true) do={\r\ + \n :set Return ([:pick \$yyyy 2 4] . [:pick \$dd 0 1] . [:pick \$HH 0\ + \_1] . [:pick \$mm 3 4] . [:pick \$ss 6 7]);\r\ + \n } else={\r\ + \n :set Return ([\$yyyy] . [\$MM] . [\$dd] . [\$HH] . [\$mm] . [\$ss]);\ + \r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set WaitForFile do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :local WaitTime [ :totime \$2 ];\r\ + \n :global CleanFilePath;\r\ + \n :global EitherOr;\r\ + \n :global MAX;\r\ + \n :set FileName [ \$CleanFilePath \$FileName ];\r\ + \n :local Delay ([ \$MAX [ \$EitherOr \$WaitTime 2s ] 100ms ] / 9);\r\ + \n :do {\r\ + \n :retry {\r\ + \n /file/get \$FileName;\r\ + \n :return true;\r\ + \n } delay=\$Delay max=10;\r\ + \n } on-error={ }\r\ + \n :while ([ :len [ /file/find where name=\$FileName ] ] > 0) do={\r\ + \n :do {\r\ + \n /file/get \$FileName;\r\ + \n :return true;\r\ + \n } on-error={ }\r\ + \n :delay \$Delay;\r\ + \n :set Delay (\$Delay * 3 / 2);\r\ + \n }\r\ + \n :return false;\r\ + \n}\r\ + \n\r\ + \n:set FileGet do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :global WaitForFile;\r\ + \n :if ([ \$WaitForFile \$FileName 0s ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n :local FileVal false;\r\ + \n :do {\r\ + \n :set FileVal [ /file/get \$FileName ];\r\ + \n } on-error={ }\r\ + \n :return \$FileVal;\r\ + \n}\r\ + \n\r\ + \n:set RmDir do={\r\ + \n :local DirName [ :tostr \$1 ];\r\ + \n :global FileGet;\r\ + \n :log debug (\$0 . \" Removing directory: \". \$DirName);\r\ + \n :local DirVal [ \$FileGet \$DirName ];\r\ + \n :if (\$DirVal = false) do={\r\ + \n :log debug (\$0 . \" ... which does not exist.\");\r\ + \n :return true;\r\ + \n };\r\ + \n :if (\$DirVal->\"type\" != \"directory\") do={\r\ + \n :log error (\$0 . \" Directory '\" . \$DirName . \"' is not a direct\ + ory.\");\r\ + \n :return false;\r\ + \n };\r\ + \n :onerror Err {\r\ + \n /file/remove \$DirName;\r\ + \n } do={\r\ + \n :log error (\$0 . \" Removing directory '\" . \$DirName . \"' failed\ + : \" . \$Err);\r\ + \n :return false;\r\ + \n };\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set RmFile do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :global FileGet;\r\ + \n :log debug (\$0 . \" Removing file: \". \$FileName);\r\ + \n :local FileVal [ \$FileGet \$FileName ];\r\ + \n :if (\$FileVal = false) do={\r\ + \n :log debug (\$0 . \" ... which does not exist.\");\r\ + \n :return true;\r\ + \n }\r\ + \n :if (\$FileVal->\"type\" = \"directory\" || \$FileVal->\"type\" = \"di\ + sk\") do={\r\ + \n :log error (\$0 . \" File '\" . \$FileName . \"' is not a file.\");\ + \r\ + \n :return false;\r\ + \n }\r\ + \n :onerror Err {\r\ + \n /file/remove \$FileName;\r\ + \n } do={\r\ + \n :log error (\$0 . \" Removing file '\" . \$FileName . \"' failed: \"\ + \_. \$Err); :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set MkDir do={\r\ + \n :local Path [ :tostr \$1 ];\r\ + \n :global CleanFilePath;\r\ + \n :global FileGet;\r\ + \n :global RmDir;\r\ + \n :global WaitForFile;\r\ + \n\r\ + \n :local MkTmpfs do={\r\ + \n :global WaitForFile;\r\ + \n :local TmpFs [ /disk/find where slot=tmpfs type=tmpfs ];\r\ + \n :if ([ :len \$TmpFs ] = 1) do={\r\ + \n :if ([ /disk/get \$TmpFs disabled ] = true) do={\r\ + \n :log info (\$0 . \" The tmpfs is disabled, enabling.\");\r\ + \n /disk/enable \$TmpFs;\r\ + \n }\r\ + \n :return true;\r\ + \n }\r\ + \n :log info (\$0 . \" Creating disk of type tmpfs.\");\r\ + \n \$RmDir \"tmpfs\";\r\ + \n :onerror Err {\r\ + \n /disk/add slot=tmpfs type=tmpfs tmpfs-max-size=([ /system/resource\ + /get total-memory ] / 3);\r\ + \n \$WaitForFile \"tmpfs\";\r\ + \n } do={\r\ + \n :log warning (\$0 . \" Creating disk of type tmpfs failed: \" . \$\ + Err);\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n }\r\ + \n :set Path [ \$CleanFilePath \$Path ];\r\ + \n :if (\$Path = \"\") do={\r\ + \n :return true;\r\ + \n }\r\ + \n :log debug (\$0 . \" Making directory: \" . \$Path);\r\ + \n :local PathVal [ \$FileGet \$Path ];\r\ + \n :if (\$PathVal->\"type\" = \"directory\") do={\r\ + \n :log debug (\$0 . \" ... which already exists.\");\r\ + \n :return true;\r\ + \n }\r\ + \n :if ([ :pick \$Path 0 5 ] = \"tmpfs\") do={\r\ + \n :if ([ \$MkTmpfs ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n :onerror Err {\r\ + \n /file/add type=\"directory\" name=\$Path;\r\ + \n \$WaitForFile \$Path;\r\ + \n } do={\r\ + \n :log warning (\$0 . \" Making directory '\" . \$Path . \"' failed: \ + \" . \$Err);\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set MAX do={:if (\$1 > \$2) do={:return \$1}\r\ + \n :return \$2;\r\ + \n}\r\ + \n:set MIN do={:if (\$1 < \$2) do={:return \$1}\r\ + \n :return \$2;\r\ + \n}\r\ + \n\r\ + \n:set CharacterMultiply do={\r\ + \n :local Str [ :tostr \$1 ];\r\ + \n :local Num [ :tonum \$2 ];\r\ + \n :if (\$Num = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :for I from=1 to=\$Num do={:set Return (\$Return . \$Str)}\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set CharacterReplace do={\r\ + \n :local String [ :tostr \$1 ];\r\ + \n :local ReplaceFrom [ :tostr \$2 ];\r\ + \n :local ReplaceWith [ :tostr \$3 ];\r\ + \n :local Return \"\";\r\ + \n :if (\$ReplaceFrom = \"\") do={:return \$String}\r\ + \n :while ([ :typeof [ :find \$String \$ReplaceFrom ] ] != \"nil\") do={\ + \r\ + \n :local Pos [ :find \$String \$ReplaceFrom ];\r\ + \n :set Return (\$Return . [ :pick \$String 0 \$Pos ] . \$ReplaceWith);\ + \r\ + \n :set String [ :pick \$String (\$Pos + [ :len \$ReplaceFrom ]) [ :len\ + \_\$String ] ];\r\ + \n }\r\ + \n :return (\$Return . \$String);\r\ + \n}\r\ + \n\r\ + \n:set IfThenElse do={\r\ + \n :if ([ :tostr \$1 ] = \"true\" || [ :tobool \$1 ] = true) do={:return \ + \$2};\r\ + \n :return \$3;\r\ + \n}\r\ + \n\r\ + \n:set EitherOr do={\r\ + \n :global IfThenElse;\r\ + \n :if ([ :typeof \$1 ] = \"num\") do={:return [ \$IfThenElse (\$1 != 0) \ + \$1 \$2 ]}\r\ + \n :if ([ :typeof \$1 ] = \"time\") do={:return [ \$IfThenElse (\$1 > 0s)\ + \_\$1 \$2 ]}\r\ + \n# this works for boolean values, literal ones with parentheses\r\ + \n :return [ \$IfThenElse ([ :len [ :tostr \$1 ] ] > 0) \$1 \$2 ];\r\ + \n}\r\ + \n\r\ + \n:set ParseKeyValueStore do={\r\ + \n :local Source \$1;\r\ + \n :if ([ :pick \$Source 0 1 ] = \"{\") do={\r\ + \n :do {\r\ + \n :return [ :deserialize from=json \$Source ];\r\ + \n } on-error={ }\r\ + \n } \r\ + \n :if ([ :typeof \$Source ] != \"array\") do={:set Source [ :tostr \$1 ]\ + }\r\ + \n :local Result ({});\r\ + \n :foreach KeyValue in=[ :toarray \$Source ] do={\r\ + \n :if ([ :find \$KeyValue \"=\" ]) do={\r\ + \n :local Key [ :pick \$KeyValue 0 [ :find \$KeyValue \"=\" ] ];\r\ + \n :local Value [ :pick \$KeyValue ([ :find \$KeyValue \"=\" ] + 1) [\ + \_:len \$KeyValue ] ];\r\ + \n :if (\$Value=\"true\") do={:set Value true}\r\ + \n :if (\$Value=\"false\") do={:set Value false}\r\ + \n :set (\$Result->\$Key) \$Value;\r\ + \n } else={:set (\$Result->\$KeyValue) true}\r\ + \n }\r\ + \n :return \$Result;\r\ + \n}\r\ + \n:set RequiredRouterOS do={\r\ + \n :local Caller [ :tostr \$1 ];\r\ + \n :local Required [ :tostr \$2 ];\r\ + \n :local Warn [ :tostr \$3 ];\r\ + \n :global IfThenElse;\r\ + \n :global VersionToNum;\r\ + \n :if (!(\$Required ~ \"^\\\\d+\\\\.\\\\d+((alpha|beta|rc|\\\\.)\\\\d+|)\ + \\\$\")) do={\r\ + \n :log error (\$0 . \" No valid RouterOS version: \" . \$Required);\r\ + \n :return false;\r\ + \n }\r\ + \n :if ([ \$VersionToNum \$Required ] > [ \$VersionToNum [ /system/packag\ + e/update/get installed-version ] ]) do={\r\ + \n :if (\$Warn = \"true\") do={\r\ + \n :log warning (\$0 . \" This \" . [ \$IfThenElse ([ :pick \$Caller \ + 0 ] = (\"\\\$\")) \"function\" \"script\" ] . \\\r\ + \n \" '\" . \$Caller . \"' (at least specific functionality) requir\ + es RouterOS \" . \$Required . \". Please update!\");\r\ + \n }\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set ValidateSyntax do={\r\ + \n :local Code [ :tostr \$1 ];\r\ + \n :global LogPrint;\r\ + \n :onerror Err {\r\ + \n [ :parse (\":local Validate do={\\n\" . \$Code . \"\\n}\") ];\r\ + \n } do={\r\ + \n \$LogPrint debug \$0 (\"Valdation failed: \" . \$Err);\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set VersionToNum do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :local Multi 0x1000000;\r\ + \n :local Return 0;\r\ + \n :global CharacterReplace;\r\ + \n :set Input [ \$CharacterReplace \$Input \".\" \",\" ];\r\ + \n :foreach I in={ \"zero\"; \"alpha\"; \"beta\"; \"rc\" } do={\r\ + \n :set Input [ \$CharacterReplace \$Input \$I (\",\" . \$I . \",\") ];\ + \r\ + \n }\r\ + \n :foreach Value in=([ :toarray \$Input ], 0) do={\r\ + \n :local Num [ :tonum \$Value ];\r\ + \n :if (\$Multi = 0x100) do={\r\ + \n :if ([ :typeof \$Num ] = \"num\") do={\r\ + \n :set Return (\$Return + 0xff00);\r\ + \n :set Multi (\$Multi / 0x100);\r\ + \n } else={\r\ + \n :if (\$Value = \"zero\") do={ }\r\ + \n :if (\$Value = \"alpha\") do={ :set Return (\$Return + 0x3f00); \ + }\r\ + \n :if (\$Value = \"beta\") do={ :set Return (\$Return + 0x5f00); }\ + \r\ + \n :if (\$Value = \"rc\") do={ :set Return (\$Return + 0x7f00); }\r\ + \n }\r\ + \n }\r\ + \n :if ([ :typeof \$Num ] = \"num\") do={ :set Return (\$Return + (\$Va\ + lue * \$Multi)); }\r\ + \n :set Multi (\$Multi / 0x100);\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set ScriptLock do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local WaitMax [ :totime \$2 ];\r\ + \n :global GetRandom20CharAlNum;\r\ + \n :global IfThenElse;\r\ + \n :global ScriptLockOrder;\r\ + \n :if ([ :typeof \$ScriptLockOrder ] = \"nothing\") do={\r\ + \n :set ScriptLockOrder ({});\r\ + \n }\r\ + \n :if ([ :typeof (\$ScriptLockOrder->\$Script) ] = \"nothing\") do={\r\ + \n :set (\$ScriptLockOrder->\$Script) ({});\r\ + \n }\r\ + \n :local JobCount do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :return [ :len [ /system/script/job/find where script=\$Script ] ];\ + \r\ + \n }\r\ + \n :local TicketCount do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :local Count 0;\r\ + \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :if ([ :typeof \$Ticket ] != \"nothing\") do={:set Count (\$Count \ + + 1)}\r\ + \n }\r\ + \n :return \$Count;\r\ + \n }\r\ + \n :local IsFirstTicket do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local Check [ :tostr \$2 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :if (\$Ticket = \$Check) do={:return true}\r\ + \n :if ([ :typeof \$Ticket ] != \"nothing\" && \$Ticket != \$Check) d\ + o={:return false}\r\ + \n }\r\ + \n :return false;\r\ + \n }\r\ + \n :local AddTicket do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local Add [ :tostr \$2 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :while (true) do={\r\ + \n :local Pos [ :len (\$ScriptLockOrder->\$Script) ];\r\ + \n :set (\$ScriptLockOrder->\$Script->\$Pos) \$Add;\r\ + \n :delay 10ms;\r\ + \n :if ((\$ScriptLockOrder->\$Script->\$Pos) = \$Add) do={:return tru\ + e}\r\ + \n }\r\ + \n }\r\ + \n :local RemoveTicket do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local Remove [ :tostr \$2 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :foreach Id,Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :while ((\$ScriptLockOrder->\$Script->\$Id) = \$Remove) do={\r\ + \n :set (\$ScriptLockOrder->\$Script->\$Id);\r\ + \n :delay 10ms;\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n :local CleanupTickets do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :if ([ :typeof \$Ticket ] != \"nothing\") do={:return false}\r\ + \n }\r\ + \n :set (\$ScriptLockOrder->\$Script) ({});\r\ + \n }\r\ + \n :if ([ :typeof \$WaitMax ] = \"nil\" ) do={:set WaitMax 0s}\r\ + \n :if ([ :len [ /system/script/find where name=\$Script ] ] = 0) do={\r\ + \n :log error (\$0 . \" A script named '\" . \$Script . \"' does not ex\ + ist!\");\r\ + \n :error false;\r\ + \n }\r\ + \n :if ([ \$JobCount \$Script ] = 0) do={\r\ + \n \$LogPrint error \$0 (\"No script '\" . \$Script . \"' is running!\"\ + );\r\ + \n :error false;\r\ + \n }\r\ + \n :if ([ \$TicketCount \$Script ] >= [ \$JobCount \$Script ]) do={\r\ + \n :log error (\$0 . \" More tickets than running scripts '\" . \$Scrip\ + t . \"', resetting!\");\r\ + \n :set (\$ScriptLockOrder->\$Script) ({});\r\ + \n /system/script/job/remove [ find where script=\$Script ];\r\ + \n }\r\ + \n :local MyTicket [ \$GetRandom20CharAlNum 6 ];\r\ + \n \$AddTicket \$Script \$MyTicket;\r\ + \n :local WaitInterval (\$WaitMax / 20);\r\ + \n :local WaitTime \$WaitMax;\r\ + \n :while (\$WaitTime > 0 && \\\r\ + \n ([ \$IsFirstTicket \$Script \$MyTicket ] = false || \\\r\ + \n [ \$TicketCount \$Script ] < [ \$JobCount \$Script ])) do={\r\ + \n :set WaitTime (\$WaitTime - \$WaitInterval);\r\ + \n :delay \$WaitInterval;\r\ + \n }\r\ + \n :if ([ \$IsFirstTicket \$Script \$MyTicket ] = true && \\\r\ + \n [ \$TicketCount \$Script ] = [ \$JobCount \$Script ]) do={\r\ + \n \$RemoveTicket \$Script \$MyTicket;\r\ + \n \$CleanupTickets \$Script;\r\ + \n :return true;\r\ + \n }\r\ + \n \$RemoveTicket \$Script \$MyTicket;\r\ + \n \$LogPrint debug \$0 (\"Script '\" . \$Script . \"' started more than \ + once\" . \\\r\ + \n [ \$IfThenElse (\$WaitTime < \$WaitMax) \" and timed out waiting for\ + \_lock\" \"\" ] . \"...\");\r\ + \n :return false;\r\ + \n}\r\ + \n\r\ + \n:set SendNotification do={ :onerror Err {\r\ + \n :global SendNotification2;\r\ + \n \$SendNotification2 ({ origin=\$0; subject=\$1; message=\$2; link=\$3;\ + \_silent=\$4 });\r\ + \n} do={:global ExitOnError; \$ExitOnError \$0 \$Err}\r\ + \n}\r\ + \n\r\ + \n:set SendNotification2 do={\r\ + \n :local Notification \$1;\r\ + \n :global NotificationFunctions;\r\ + \n :foreach FunctionName,Discard in=\$NotificationFunctions do={\r\ + \n (\$NotificationFunctions->\$FunctionName) (\"\\\$NotificationFunctio\ + ns->\\\"\" . \$FunctionName . \"\\\"\") \$Notification;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set SymbolByUnicodeName do={\r\ + \n :local Name [ :tostr \$1 ];\r\ + \n :global EitherOr;\r\ + \n :global SymbolsExtra;\r\ + \n :local Symbols ({\r\ + \n \"abacus\"=\"\\F0\\9F\\A7\\AE\";\r\ + \n \"alarm-clock\"=\"\\E2\\8F\\B0\";\r\ + \n \"arrow-down\"=\"\\E2\\AC\\87\";\r\ + \n \"arrow-up\"=\"\\E2\\AC\\86\";\r\ + \n \"calendar\"=\"\\F0\\9F\\93\\85\";\r\ + \n \"card-file-box\"=\"\\F0\\9F\\97\\83\";\r\ + \n \"chart-decreasing\"=\"\\F0\\9F\\93\\89\";\r\ + \n \"chart-increasing\"=\"\\F0\\9F\\93\\88\";\r\ + \n \"cloud\"=\"\\E2\\98\\81\";\r\ + \n \"cross-mark\"=\"\\E2\\9D\\8C\";\r\ + \n \"earth\"=\"\\F0\\9F\\8C\\8D\";\r\ + \n \"fire\"=\"\\F0\\9F\\94\\A5\";\r\ + \n \"floppy-disk\"=\"\\F0\\9F\\92\\BE\";\r\ + \n \"gear\"=\"\\E2\\9A\\99\";\r\ + \n \"heart\"=\"\\E2\\99\\A5\";\r\ + \n \"high-voltage-sign\"=\"\\E2\\9A\\A1\";\r\ + \n \"incoming-envelope\"=\"\\F0\\9F\\93\\A8\";\r\ + \n \"information\"=\"\\E2\\84\\B9\";\r\ + \n \"large-orange-circle\"=\"\\F0\\9F\\9F\\A0\";\r\ + \n \"large-red-circle\"=\"\\F0\\9F\\94\\B4\";\r\ + \n \"link\"=\"\\F0\\9F\\94\\97\";\r\ + \n \"lock-with-ink-pen\"=\"\\F0\\9F\\94\\8F\";\r\ + \n \"memo\"=\"\\F0\\9F\\93\\9D\";\r\ + \n \"mobile-phone\"=\"\\F0\\9F\\93\\B1\";\r\ + \n \"pushpin\"=\"\\F0\\9F\\93\\8C\";\r\ + \n \"scissors\"=\"\\E2\\9C\\82\";\r\ + \n \"scroll\"=\"\\F0\\9F\\93\\9C\";\r\ + \n \"smiley-partying-face\"=\"\\F0\\9F\\A5\\B3\";\r\ + \n \"smiley-smiling-face\"=\"\\E2\\98\\BA\";\r\ + \n \"smiley-winking-face-with-tongue\"=\"\\F0\\9F\\98\\9C\";\r\ + \n \"sparkles\"=\"\\E2\\9C\\A8\";\r\ + \n \"speech-balloon\"=\"\\F0\\9F\\92\\AC\";\r\ + \n \"star\"=\"\\E2\\AD\\90\";\r\ + \n \"warning-sign\"=\"\\E2\\9A\\A0\";\r\ + \n \"white-heavy-check-mark\"=\"\\E2\\9C\\85\"\r\ + \n }, \$SymbolsExtra);\r\ + \n :local Magic [ :pick [ /system/clock/get date ] 4 10 ];\r\ + \n :local Special {\r\ + \n \"information-04-01\"=\"\\F0\\9F\\9A\\BB\";\r\ + \n \"large-orange-circle-04-01\"=\"\\F0\\9F\\8D\\8A\";\r\ + \n \"large-orange-circle-10-31\"=\"\\F0\\9F\\8E\\83\";\r\ + \n \"large-red-circle-04-01\"=\"\\F0\\9F\\8D\\92\" };\r\ + \n :if ([ :len (\$Symbols->\$Name) ] = 0) do={\r\ + \n :log warning (\$0 . \"No symbol available for name '\" . \$Name . \"\ + '!\");\r\ + \n :return \"\";\r\ + \n }\r\ + \n :return ([ \$EitherOr (\$Special->(\$Name . \$Magic)) (\$Symbols->\$Na\ + me) ] . \"\\EF\\B8\\8F\");\r\ + \n}\r\ + \n\r\ + \n:set SymbolForNotification do={\r\ + \n :global NotificationsWithSymbols;\r\ + \n :global SymbolByUnicodeName;\r\ + \n :global IfThenElse;\r\ + \n :if (\$NotificationsWithSymbols != true) do={:return [ \$IfThenElse ([\ + \_:len \$2 ] > 0) ([ :tostr \$2 ] . \" \") \"\" ]}\r\ + \n :local Return \"\";\r\ + \n :foreach Symbol in=[ :toarray \$1 ] do={:set Return (\$Return . [ \$Sy\ + mbolByUnicodeName \$Symbol ])}\r\ + \n :return (\$Return . \" \");\r\ + \n}\r\ + \n\r\ + \n:set Unix2Dos do={:return [ :tocrlf [ :tostr \$1 ] ]}\r\ + \n:set UrlEncode do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :if ([ :len \$Input ] = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :local Chars (\"\\n\\r !\\\"#\\\$%&'()*+,:;<=>\?@[\\\\]^`{|}~\");\r\ + \n :local Subs { \"%0A\"; \"%0D\"; \"%20\"; \"%21\"; \"%22\"; \"%23\"; \"\ + %24\"; \"%25\"; \"%26\"; \"%27\";\r\ + \n \"%28\"; \"%29\"; \"%2A\"; \"%2B\"; \"%2C\"; \"%3A\"; \"%3B\"; \ + \"%3C\"; \"%3D\"; \"%3E\"; \"%3F\";\r\ + \n \"%40\"; \"%5B\"; \"%5C\"; \"%5D\"; \"%5E\"; \"%60\"; \"%7B\"; \ + \"%7C\"; \"%7D\"; \"%7E\" };\r\ + \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ + \n :local Char [ :pick \$Input \$I ];\r\ + \n :local Replace [ :find \$Chars \$Char ];\r\ + \n :if ([ :typeof \$Replace ] = \"num\") do={:set Char (\$Subs->\$Repla\ + ce)}\r\ + \n :set Return (\$Return . \$Char);\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set IsDNSResolving do={\r\ + \n :do {:resolve \"api.telegram.org\"} on-error={:return false}\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set IsFullyConnected do={\r\ + \n :global IsDNSResolving;\r\ + \n :global IsTimeSync;\r\ + \n :if ([ \$IsDNSResolving ] = false) do={:return false};\r\ + \n :if ([ \$IsTimeSync ] = false) do={:return false};\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set IsTimeSync do={\r\ + \n :global IsTimeSyncCached;\r\ + \n :global IsTimeSyncResetNtp;\r\ + \n :if (\$IsTimeSyncCached = true) do={:return true}\r\ + \n :if ([ /system/ntp/client/get enabled ] = true) do={\r\ + \n :if ([ /system/ntp/client/get status ] = \"synchronized\") do={\r\ + \n :set IsTimeSyncCached true;\r\ + \n :return true;\r\ + \n }\r\ + \n :local Uptime [ /system/resource/get uptime ];\r\ + \n :if ([ :typeof \$IsTimeSyncResetNtp ] = \"nothing\") do={\r\ + \n :set IsTimeSyncResetNtp \$Uptime;\r\ + \n }\r\ + \n :if (\$Uptime - \$IsTimeSyncResetNtp < 3m) do={:return false}\r\ + \n :log warning \"\$0 The ntp client is configured, but did not sync.\"\ + ;\r\ + \n :set IsTimeSyncResetNtp \$Uptime;\r\ + \n /system/ntp/client/set enabled=no;\r\ + \n :delay 20ms;\r\ + \n /system/ntp/client/set enabled=yes;\r\ + \n :return false;\r\ + \n }\r\ + \n :if ([ /system/license/get ]->\"level\" = \"free\" || \\\r\ + \n [ /system/resource/get ]->\"board-name\" = \"x86\") do={\r\ + \n :log debug \"\$0 No ntp client configured, relying on RTC for CHR fr\ + ee license and x86.\";\r\ + \n :return true;\r\ + \n }\r\ + \n :if ([ /ip/cloud/get update-time ] = true) do={\r\ + \n :if ([ :typeof [ /ip/cloud/get public-address ] ] = \"ip\") do={\r\ + \n :set IsTimeSyncCached true;\r\ + \n :return true;\r\ + \n }\r\ + \n :return false;\r\ + \n }\r\ + \n :log debug \"\$0 No time source configured! Returning gracefully...\";\ + \r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set FetchHugeFiles do={\r\ + \n :local ScriptName [ :tostr \$1 ];\r\ + \n :local Url [ :tostr \$2 ];\r\ + \n :local CheckCert [ :tostr \$3 ];\r\ + \n\r\ + \n :global CleanName;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global GetRandom20CharAlNum;\r\ + \n :global IfThenElse;\r\ + \n :global LogPrint;\r\ + \n :global MkDir;\r\ + \n :global RmDir;\r\ + \n :global RmFile;\r\ + \n :global WaitForFile;\r\ + \n\r\ + \n :set CheckCert [ \$IfThenElse (\$CheckCert = \"false\") \"no\" \"yes-w\ + ithout-crl\" ];\r\ + \n\r\ + \n :local DirName (\"tmpfs/\" . [ \$CleanName \$ScriptName ]);\r\ + \n :if ([ \$MkDir \$DirName ] = false) do={\r\ + \n \$LogPrint error \$0 (\"Failed creating directory!\");\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :local FileName (\$DirName . \"/\" . [ \$CleanName \$0 ] . \"-\" . [ \ + \$GetRandom20CharAlNum ]);\r\ + \n :onerror Err {\r\ + \n /tool/fetch check-certificate=\$CheckCert \$Url dst-path=\$FileName \ + \\\r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$ScriptName ] }) as-va\ + lue;\r\ + \n } do={\r\ + \n :if ([ \$WaitForFile \$FileName 500ms ] = true) do={\r\ + \n \$RmFile \$FileName;\r\ + \n }\r\ + \n \$LogPrint debug \$0 (\"Failed downloading from \" . \$Url . \" - \"\ + \_. \$Err);\r\ + \n \$RmDir \$DirName;\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :if ([ \$WaitForFile \$FileName 5s ] = false) do={\r\ + \n \$LogPrint debug \$0 (\"The file downloaded from \" . \$Url . \" did\ + \_not show up.\");\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :local FileSize [ /file/get \$FileName size ];\r\ + \n :local Return \"\";\r\ + \n :local VarSize 0;\r\ + \n :while (\$VarSize != \$FileSize) do={\r\ + \n :set Return (\$Return . ([ /file/read offset=\$VarSize chunk-size=32\ + 768 file=\$FileName as-value ]->\"data\"));\r\ + \n :set FileSize [ /file/get \$FileName size ];\r\ + \n :set VarSize [ :len \$Return ];\r\ + \n :if (\$VarSize > \$FileSize) do={\r\ + \n :delay 100ms;\r\ + \n }\r\ + \n }\r\ + \n \$RmDir \$DirName;\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set FetchUserAgentStr do={\r\ + \n :local Caller [ :tostr \$1 ];\r\ + \n :global GlobalScriptsUrl;\r\ + \n :global CommitBrief;\r\ + \n :global IfThenElse;\r\ + \n :local Resource [ /system/resource/get ];\r\ + \n :return (\"User-Agent: Mikrotik/\" . \$Resource->\"version\" . \" \" .\ + \_\$Resource->\"architecture-name\" . \\\r\ + \n \" \" . \$Caller . \"/Fetch (\" . \$GlobalScriptsUrl . \"; \" . [ \$\ + CommitBrief ] . \")\");\r\ + \n}\r\ + \n\r\ + \n:set ScriptInstallUpdate do={ :onerror Err {\r\ + \n :local Scripts [ :toarray \$1 ];\r\ + \n :local NewComment [ :tostr \$2 ];\r\ + \n :global InitSetup;\r\ + \n\r\ + \n :global CommitId;\r\ + \n :global ScriptUpdatesCRLF;\r\ + \n :global GlobalConfVersion;\r\ + \n :global Identity;\r\ + \n :global CertificateAvailable;\r\ + \n :global CheckSumsVerify;\r\ + \n :global GlobalScriptsUrl;\r\ + \n :global SumsDirAndFileName;\r\ + \n :global GlobalScriptsUrlSuffix;\r\ + \n :global EitherOr;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global Grep;\r\ + \n :global IfThenElse;\r\ + \n :global LogPrint;\r\ + \n :global ParseKeyValueStore;\r\ + \n :global RequiredRouterOS;\r\ + \n :global SendNotification2;\r\ + \n :global SymbolForNotification;\r\ + \n :global ValidateSyntax;\r\ + \n :global CommentsInScripts;\r\ + \n\r\ + \n :if ([ \$CertificateAvailable \"Root YE\" \"fetch\" ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Downloading certificate failed, trying wit\ + hout.\");\r\ + \n }\r\ + \n\r\ + \n :foreach Script in=\$Scripts do={\r\ + \n :if ([ :len [ /system/script/find where name=\$Script ] ] = 0) do={\ + \r\ + \n \$LogPrint info \$0 (\"Adding new script: \" . \$Script);\r\ + \n /system/script/add name=\$Script owner=\$Script source=\"#!rsc by \ + Vados\\n\" comment=\$NewComment;\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :local CommitIdBefore \$CommitId;\r\ + \n :local GlobalConfVersionBefore \$GlobalConfVersion;\r\ + \n :local ReloadGlobal false;\r\ + \n :local DeviceMode [ /system/device-mode/get ];\r\ + \n\r\ + \n :if (\$CheckSumsVerify = true) do={\r\ + \n :local CheckSums ({});\r\ + \n :do {\r\ + \n :local Url (\$GlobalScriptsUrl . \$SumsDirAndFileName . \$GlobalScr\ + iptsUrlSuffix);\r\ + \n \$LogPrint debug \$0 (\"Fetching checksums from url: \" . \$Url);\ + \r\ + \n :set CheckSums [ :deserialize from=json ([ /tool/fetch check-certi\ + ficate=yes-without-crl \\\r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$0 ] }) \$Url output\ + =user as-value ]->\"data\") ];\r\ + \n } on-error={ \$LogPrint warning \$0 (\"Err = \" . \$Err); }\r\ + \n }\r\ + \n\r\ + \n :foreach Script in=[ /system/script/find where source~\"^#!rsc by Vado\ + s\" ] do={\r\ + \n :local ScriptVal [ /system/script/get \$Script ];\r\ + \n :local ScriptInfo [ \$ParseKeyValueStore (\$ScriptVal->\"comment\") \ + ];\r\ + \n :local SourceNew;\r\ + \n\r\ + \n :foreach Scheduler in=[ /system/scheduler/find where on-event~(\"\\\ + \\b\" . \$ScriptVal->\"name\" . \"\\\\b\") ] do={\r\ + \n :local SchedulerVal [ /system/scheduler/get \$Scheduler ];\r\ + \n :if (\$ScriptVal->\"policy\" != \$SchedulerVal->\"policy\") do={\r\ + \n \$LogPrint warning \$0 (\"Policies differ for script '\" . \$Scr\ + iptVal->\"name\" . \"' and its scheduler '\" . \$SchedulerVal->\"name\" . \ + \"'!\");\r\ + \n }\r\ + \n }\r\ + \n :do {\r\ + \n :if (\$ScriptInfo->\"ignore\" = true) do={\r\ + \n \$LogPrint debug \$0 (\"Ignoring script '\" . \$ScriptVal->\"nam\ + e\" . \"', as requested.\");\r\ + \n :error true;\r\ + \n }\r\ + \n :if (\$CheckSumsVerify = true) do={\r\ + \n :local CheckSum (\$CheckSums->(\$ScriptVal->\"name\"));\r\ + \n :if ([ :len (\$ScriptInfo->\"base-url\") ] = 0 && [ :len (\$Scri\ + ptInfo->\"url-suffix\") ] = 0 && \\\r\ + \n [ :convert transform=md5 to=hex [ :tolf (\$ScriptVal->\"sou\ + rce\") ] ] = \$CheckSum) do={\r\ + \n \$LogPrint debug \$0 (\"Checksum for script '\" . \$ScriptVal-\ + >\"name\" . \"' matches, ignoring.\");\r\ + \n :error true;\r\ + \n }\r\ + \n }\r\ + \n :if ([ :len (\$ScriptInfo->\"certificate\") ] > 0) do={\r\ + \n :if ([ \$CertificateAvailable (\$ScriptInfo->\"certificate\") \"\ + fetch\" ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Downloading certificate failed, tryi\ + ng without.\");\r\ + \n }\r\ + \n }\r\ + \n :onerror Err {\r\ + \n :local BaseUrl [ \$EitherOr (\$ScriptInfo->\"base-url\") \$Globa\ + lScriptsUrl ];\r\ + \n :local UrlSuffix [ \$EitherOr (\$ScriptInfo->\"url-suffix\") \$G\ + lobalScriptsUrlSuffix ];\r\ + \n :local Url (\$BaseUrl . \$ScriptVal->\"name\" . \".rsc\" . \$Url\ + Suffix);\r\ + \n \$LogPrint warning \$0 (\"Fetching script '\" . (\$ScriptVal->\"\ + name\") . \"' from url: \" . \$Url);\r\ + \n :local Result [ /tool/fetch check-certificate=yes-without-crl \\\ + \r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$0 ] }) \$Url outp\ + ut=user as-value ];\r\ + \n :if (\$Result->\"status\" = \"finished\") do={\r\ + \n :set SourceNew [ :tolf (\$Result->\"data\") ];\r\ + \n } \r\ + \n } do={\r\ + \n \$LogPrint warning \$0 (\"Failed fetching script '\" . \$ScriptV\ + al->\"name\" . \"': \" . \$Err);\r\ + \n :if (\$Err != \"Fetch failed with status 404\") do={\r\ + \n :error false;\r\ + \n }\r\ + \n :if (\$ScriptVal->\"source\" = \"#!rsc by Vados\") do={\r\ + \n \$LogPrint warning \$0 (\"Removing dummy. Typo on installation\ + \?\");\r\ + \n /system/script/remove \$Script;\r\ + \n :error false;\r\ + \n }\r\ + \n :if (\$CheckSumsVerify = true) do={\r\ + \n :if ([ :len (\$ScriptInfo->\"base-url\") ] = 0 && [ :len (\$Sc\ + riptInfo->\"url-suffix\") ] = 0 && \\\r\ + \n [ :len \$CheckSum ] = 0) do={\r\ + \n \$LogPrint warning \$0 (\"Added the script manually\? Skip u\ + pdates with 'ignore=true' in comment.\");\r\ + \n }\r\ + \n }\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :if ([ :len \$SourceNew ] = 0) do={\r\ + \n \$LogPrint debug \$0 (\"No update for script '\" . (\$ScriptVal-\ + >\"name\") . \"'.\");\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :local SourceCRLF [ :tocrlf \$SourceNew ];\r\ + \n :if (\$InitSetup != true && ((\$ScriptVal->\"name\") != \"AM-Globa\ + lConfig\" || (\$ScriptVal->\"name\") != \"AM-GlobalFunc\")) do={\r\ + \n :if (\$SourceNew = (\$ScriptVal->\"source\") || \$SourceCRLF = (\ + \$ScriptVal->\"source\")) do={\r\ + \n \$LogPrint debug \$0 (\"Script '\" . (\$ScriptVal->\"name\") \ + . \"' source did not change. End of lines set to CRLF.\");\r\ + \n if (\$ScriptUpdatesCRLF = false) do={\r\ + \n :put [ :tolf \$SourceNew ];\r\ + \n \$LogPrint debug \$0 (\"Script '\" . (\$ScriptVal->\"name\"\ + ) . \"' source update end of lines to LF.\");\r\ + \n }\r\ + \n :error false;\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :if ([ :pick \$SourceNew 0 14 ] != \"#!rsc by Vados\") do={\r\ + \n \$LogPrint warning \$0 (\"Looks like new script '\" . \$ScriptVa\ + l->\"name\" . \"' is not valid (missing shebang = '\$shebang') Ignoring!\"\ + );\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :if (\$CommentsInScripts = true) do={\r\ + \n :local CommentLine [ \$Grep \$SourceNew (\"\\23 Script comment:\ + \_\") ];\r\ + \n :if ([ :len \$CommentLine ] = 0) do={\r\ + \n \$LogPrint debug \$0 (\"The search in new script '\" . (\$Scr\ + iptVal->\"name\") . \"' for comment in script body, is not found result Ig\ + noring!\");\r\ + \n :error false;\r\ + \n } else={\r\ + \n :if ([ :len (\$ScriptVal->\"comment\")] = 0 || [ :len (\$Scri\ + ptVal->\"comment\")] != [ :pick \$CommentLine ([ :find \$CommentLine \":\"\ + ] + 2) [ :len \$CommentLine] ]) do={\r\ + \n \$LogPrint debug \$0 (\"Exsiting comment for script '\" . (\ + \$ScriptVal->\"name\") . \"' is '\" . (\$ScriptVal->\"comment\") . \"'.\")\ + ;\r\ + \n :set (\$ScriptVal->\"comment\") [ :pick \$CommentLine ([ :f\ + ind \$CommentLine \":\"] + 2) [ :len \$CommentLine] ];\r\ + \n \$LogPrint debug \$0 (\"New comment (\" . (\$ScriptVal->\"c\ + omment\") . \") for script '\" . (\$ScriptVal->\"name\") . \"' has been ad\ + ded!\");\r\ + \n } else={\r\ + \n \$LogPrint debug \$0 (\"Comment for script '\" . (\$ScriptV\ + al->\"name\") . \"' did not change.\");\r\ + \n :error false;\r\ + \n }\r\ + \n } \r\ + \n }\r\ + \n\r\ + \n :local RequiredROS ([ \$ParseKeyValueStore [ \$Grep \$SourceNew (\ + \"\\23 requires RouterOS, \") ] ]->version);\r\ + \n :if ([ \$RequiredRouterOS \$0 [ \$EitherOr \$RequiredROS \"0.0\" ]\ + \_false ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"The script '\" . (\$ScriptVal->\"name\ + \") . \"' requires RouterOS \" . \\\r\ + \n \$RequiredROS . \", which is not met by your installation. I\ + gnoring!\");\r\ + \n :error false;\r\ + \n }\r\ + \n :local RequiredDM [ \$ParseKeyValueStore [ \$Grep \$SourceNew (\"\ + \\23 requires device-mode, \") ] ];\r\ + \n :local MissingDM ({});\r\ + \n :foreach Feature,Value in=\$RequiredDM do={\r\ + \n :if ([ :typeof (\$DeviceMode->\$Feature) ] = \"bool\" && (\$Devi\ + ceMode->\$Feature) = false) do={\r\ + \n :set MissingDM (\$MissingDM, \$Feature);\r\ + \n }\r\ + \n }\r\ + \n :if ([ :len \$MissingDM ] > 0) do={\r\ + \n \$LogPrint warning \$0 (\"The script '\" . (\$ScriptVal->\"name\ + \") . \"' requires disabled \" . \\\r\ + \n \"device-mode features (\" . [ :tostr \$MissingDM ] . \"). I\ + gnoring!\");\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :if ([ \$ValidateSyntax \$SourceNew ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Syntax validation for script '\" . (\$\ + ScriptVal->\"name\") . \"' failed! Ignoring!\");\r\ + \n :error false;\r\ + \n }\r\ + \n \r\ + \n :log info (\"Updating script: \" . (\$ScriptVal->\"name\") . \" Sc\ + ript comment: \" . (\$ScriptVal->\"comment\"));\r\ + \n\r\ + \n /system/script/set owner=(\$ScriptVal->\"name\") comment=(\$Script\ + Val->\"comment\") \\\r\ + \n source=[ \$IfThenElse (\$ScriptUpdatesCRLF = true) \$SourceCRL\ + F \$SourceNew ] \$Script;\r\ + \n :if (\$ScriptVal->\"name\" = \"AM-GlobalConfig\" || \\\r\ + \n \$ScriptVal->\"name\" = \"AM-GlobalFunc\" || \\\r\ + \n \$ScriptVal->\"name\" ~ (\"^(AM-GlobalFunc\\\\.d|mod)/.\")) d\ + o={\r\ + \n :set ReloadGlobal true;\r\ + \n }\r\ + \n } on-error={ }\r\ + \n }\r\ + \n :if (\$ReloadGlobal = true) do={\r\ + \n \$LogPrint info \$0 (\"Reloading global configuration and functions.\ + \");\r\ + \n :onerror Err {\r\ + \n :global InitSetup (a);\r\ + \n /system/script {run AM-GlobalConfig; run AM-GlobalFunc;};\r\ + \n } do={\$LogPrint error \$0 (\"Reloading global configuration and fun\ + ctions failed! \" . \$Err)}\r\ + \n }\r\ + \n :if (\$GlobalConfVersionBefore > \$GlobalConfVersion) do={\r\ + \n \$LogPrint warning \$0 (\"The configuration version decreased from \ + \" . \\\r\ + \n \$GlobalConfVersionBefore . \" to \" . \$GlobalConfVersion . \\\r\ + \n \". Installed an older version\?\");\r\ + \n }\r\ + \n :if (\$GlobalConfVersionBefore < \$GlobalConfVersion) do={\r\ + \n :global GlobalConfChanges;\r\ + \n :global GlobalConfMigration;\r\ + \n :local ChangeLogCode;\r\ + \n :if ([ :len \$ChangeLogCode ] > 0) do={\r\ + \n :if ([ \$ValidateSyntax \$ChangeLogCode ] = true) do={\r\ + \n :onerror Err {\r\ + \n [ :parse \$ChangeLogCode ];\r\ + \n } do={\$LogPrint warning \$0 (\"The changelog failed to run: \" \ + . \$Err)}\r\ + \n } else={\$LogPrint warning \$0 (\"The changelog failed syntax vali\ + dation!\")}\r\ + \n }\r\ + \n :if ([ :len \$GlobalConfMigration ] > 0) do={\r\ + \n :for I from=(\$GlobalConfVersionBefore + 1) to=\$GlobalConfVersion\ + \_do={\r\ + \n :local Migration (\$GlobalConfMigration->[ :tostr \$I ]);\r\ + \n :do {\r\ + \n :if ([ :typeof \$Migration ] != \"str\") do={\r\ + \n \$LogPrint debug \$0 (\"Migration code for change \" . \$I .\ + \_\" is not available.\");\r\ + \n :error false;\r\ + \n }\r\ + \n :if ([ \$ValidateSyntax \$Migration ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Migration code for change \" . \$I\ + \_. \" failed syntax validation!\");\r\ + \n :error false}\r\ + \n \$LogPrint info \$0 (\"Applying migration for change \" . \$I \ + . \": \" . \$Migration);\r\ + \n :onerror Err {\r\ + \n [ :parse \$Migration ];\r\ + \n } do={\$LogPrint warning \$0 (\"Migration code for change \" .\ + \_\$I . \" failed to run: \" . \$Err)}\r\ + \n } on-error={ }\r\ + \n }\r\ + \n }\r\ + \n :local NotificationMessage (\"The configuration version on \" . \$Id\ + entity . \" increased \" . \\\r\ + \n \"to \" . \$GlobalConfVersion . \", current configuration may nee\ + d modification. \" . \\\r\ + \n \"Please review and update global-config-overlay, then re-run glo\ + bal-config.\");\r\ + \n \$LogPrint info \$0 (\$NotificationMessage);\r\ + \n :if ([ :len \$GlobalConfChanges ] > 0) do={\r\ + \n :set NotificationMessage (\$NotificationMessage . \"\\n\\nChanges:\ + \");\r\ + \n :for I from=(\$GlobalConfVersionBefore + 1) to=\$GlobalConfVersion\ + \_do={\r\ + \n :local Change (\$GlobalConfChanges->[ :tostr \$I ]);\r\ + \n :set NotificationMessage (\$NotificationMessage . \"\\n \" . \\\ + \r\ + \n [ \$SymbolForNotification \"pushpin\" \"*\" ] . \$Change);\r\ + \n \$LogPrint info \$0 (\"Change \" . \$I . \": \" . \$Change);\r\ + \n }\r\ + \n } else={\r\ + \n :set NotificationMessage (\$NotificationMessage . \"\\n\\nNews and\ + \_changes are not available.\");\r\ + \n\r\ + \n }\r\ + \n\r\ + \n :if ([ :len \$GlobalConfChanges ] > 0) do={ :set GlobalConfChanges; \ + } else={ :global GlobalConfChanges (a); }\r\ + \n :if ([ :len \$GlobalConfMigration ] > 0) do={ :set GlobalConfMigrati\ + on; } else={ :global GlobalConfMigration (a); }\r\ + \n }\r\ + \n} do={\r\ + \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ + \n} }\r\ + \n\r\ + \n# load modules\r\ + \n:foreach Script in=[ /system/script/find where name ~ \"^(global-functio\ + ns\\\\.d|mod)/.\" ] do={\r\ + \n :local ScriptVal [ /system/script/get \$Script ];\r\ + \n :if ([ \$ValidateSyntax (\$ScriptVal->\"source\") ] = true) do={\r\ + \n :onerror Err {\r\ + \n /system/script/run \$Script;\r\ + \n } do={\r\ + \n \$LogPrint error \$0 (\"Module '\" . \$ScriptVal->\"name\" . \"' f\ + ailed to run: \" . \$Err);\r\ + \n }\r\ + \n } else={\r\ + \n \$LogPrint error \$0 (\"Module '\" . \$ScriptVal->\"name\" . \"' fai\ + led syntax validation, skipping.\");\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n# Add and fix global scheduler\r\ + \n:put \"Add or/and fix Global scheduler...\";\r\ + \n:local OnEvent \"/system/script { run AM-GlobalConfig; run AM-GlobalFunc\ + ; }\";\r\ + \n:local Comment \"Every Day Set Global Environment Variables\";\r\ + \n:if ([ :len [ /system/scheduler/find where name=\"AM-SetGlobalEnv\" ] ] \ + = 0) do={\r\ + \n /system/scheduler/add name=\"AM-SetGlobalEnv\" comment=\$Comment on-ev\ + ent=\$OnEvent start-time=startup;\r\ + \n}\r\ + \n:if ([ /system/scheduler/get \"AM-SetGlobalEnv\" comment ] != \$Comment)\ + \_do={\r\ + \n /system/scheduler/set \"AM-SetGlobalEnv\" comment=\$Comment;\r\ + \n}\r\ + \n:if ([ /system/scheduler/get \"AM-SetGlobalEnv\" on-event ] != \$OnEvent\ + ) do={\r\ + \n /system/scheduler/set \"AM-SetGlobalEnv\" on-event=\$OnEvent;\r\ + \n}\r\ + \n# Add Update Script scheduler\r\ + \n:put \"Add or/and fix Update Script scheduler\";\r\ + \n:set OnEvent \":global ScriptInstallUpdate; \\\$ScriptInstallUpdate;\";\ + \r\ + \n:set Comment \"Every Day Check For Update Scripts\";\r\ + \n:if ([ :len [ /system/scheduler/find where name=\"AM-ScriptInstallUpdate\ + \" ] ] = 0) do={\r\ + \n/system/scheduler/add name=\"AM-ScriptInstallUpdate\" comment=\$Comment \ + start-time=startup interval=1d on-event=\$OnEvent;\r\ + \n}\r\ + \n\r\ + \n:onerror Err {\r\ + \n :global GlobalConfReady;\r\ + \n :retry { :if (\$GlobalConfReady != true) do={ :error (\"Global configs\ + \_not ready.\"); }; } delay=100ms max=5;\r\ + \n\r\ + \n:log warning (\"This script \$ScriptName Loaded \" . \\\r\ + \n [ \$IfThenElse (\$CommitId != \"unknown\") ([ \$CommitBrief ] . \" \ + \") ] . \\\r\ + \n \"on \" . \$devBoardName . \"\\nRouterOS: \" . \$devCurVersion . \"\ + \\nArchitecture: \" . \$devCurArch . \"\\nIdentity: \" . \$Identity);\r\ + \n # signal we are ready\r\ + \n:set GlobalFuncReady true;\r\ + \n:set ExitOK true;\r\ + \n\r\ + \n:log info (\$0 . \"Global configs ready!\");\r\ + \n} do={\r\ + \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ + \n}\r\ + \n" +add comment=\ + "Lookup IP addresses for RKN list and add them to firewall address-list" \ + dont-require-permissions=no name=AM-RKN-dnsLookup owner=AM-RKN-dnsLookup \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + source="#!rsc by Vados\r\ + \n# RouterOS script: AM-RKN-dnsLookup\r\ + \n# Script comment: Lookup IP addresses for RKN list and add them to firew\ + all address-list\r\ + \n# Copyright (c) 2007-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version=7.19\r\ + \n# requires device-mode, fetch\r\ + \n#\r\ + \n# Script description: This script is intended to be run periodically, e.\ + g. once a day, to update the IP addresses in the firewall address-list bas\ + ed on the RKN list.\r\ + \n# It resolves the domain names in the RKN list and a\ + dds the corresponding IP addresses to the specified firewall address-list.\ + \r\ + \n# The script also handles CNAME records by following\ + \_them until it finds A records.\r\ + \n# Usage:\r\ + \n# /system/script { run AM-RKN-dnsLookup; }\r\ + \n:local ScriptName [ :jobname ];\r\ + \n\r\ + \n:global dnsLookupReady false;\r\ + \n:if ([:typeof \$dnsLookupReady] != \"boolean\") do={ :set dnsLookupReady\ + \_true; }\r\ + \nwhile (!\$dnsLookupReady) do={ :nothing; }\r\ + \n:set dnsLookupReady false;\r\ + \n\r\ + \n:local arrRKN {\r\ + \n \"telegra.ph\"\r\ + \n \"grani.ru\"\r\ + \n \"xhamster.com\"\r\ + \n \"lostfilm.tv\"\r\ + \n \"rutracker.org\"\r\ + \n \"lurkmore.to\"\r\ + \n \"dou.ua\"\r\ + \n \"youporn.com\"\r\ + \n \"pornolab.net\"\r\ + \n \"crimerussia.com\"\r\ + \n \"telegram.org\"\r\ + \n \"api.telegram.org\"\r\ + \n \"facebook.com\"\r\ + \n \"instagram.com\"\r\ + \n \"x.com\"\r\ + \n \"twitter.com\"\r\ + \n \"youtube.com\"\r\ + \n \"googleapis.com\"\r\ + \n \"youtu.be\"\r\ + \n \"googlevideo.com\"\r\ + \n \"gstatic.com\"\r\ + \n \"googleusercontent.com\"\r\ + \n \"nhacmp3youtube.com\"\r\ + \n \"telegram.me\"\r\ + \n \"t.me\";}\r\ + \n\r\ + \n:local ListRKN \"RKN-dnsLookup\";\r\ + \n:local ListComment (\"ListRKN managed by \" . \$ScriptName);\r\ + \n:foreach aListItem in=[/ip/firewall/address-list find list=\$ListRKN] do\ + ={\r\ + \n /ip firewall address-list remove \$aListItem;\r\ + \n}\r\ + \n:foreach aItem in=\$arrRKN do={\r\ + \n# :do {\r\ + \n :retry delay=500ms max=5 on-error={:log error \"dns resolve fail\ + ure [ \$aItem - resolve ip ]\"} command={:resolve \$aItem}\r\ + \n# } on-error={\r\ + \n# :log error \"dns resolve failure [ \$arItem - resolve ip ]\";\r\ + \n# }\r\ + \n :foreach dnsRecord in=[/ip dns cache all find where (name=\$aItem)] \ + do={\r\ + \n :if ([/ip dns cache all get \$dnsRecord type]=\"A\") do={\r\ + \n :local newAddress [/ip dns cache all get \$dnsRecord data];\ + \r\ + \n :do {\r\ + \n /ip firewall address-list add list=\$ListRKN address=\$newA\ + ddress comment=\$aItem;\r\ + \n :log warning \"Successfully adding ip to list A record: \ + \$dnsRecord, address: \$newAddress domain: \$aItem\";\r\ + \n } on-error={\r\ + \n :log error \"error when adding ip to list A record: \$dn\ + sRecord, address: \$newAddress domain: \$aItem\";\r\ + \n }\r\ + \n }\r\ + \n :if ([/ip dns cache all get \$dnsRecord type]=\"CNAME\") do={\r\ + \n :local cname;\r\ + \n :local nextCname;\r\ + \n :local cnameAddress;\r\ + \n :set cname [/ip dns cache all find where (name=\$aItem && ty\ + pe=\"CNAME\")];\r\ + \n :set nextCname [/ip dns cache all find where (name=[/ip dns \ + cache all get \$cname data] && type=\"CNAME\")];\r\ + \n :while (\$nextCname != \"\") do={\r\ + \n :set cname \$nextCname;\r\ + \n :set nextCname [/ip dns cache all find where (name=[/ip \ + dns cache all get \$cname data] && type=\"CNAME\")];\r\ + \n }\r\ + \n :foreach aRecord in=[/ip dns cache all find where (name=[/ip\ + \_dns cache all get \$cname data] && type=\"A\")] do={\r\ + \n :do {\r\ + \n :set cnameAddress [/ip dns cache all get \$aRecord d\ + ata];\r\ + \n /ip firewall address-list add list=\$ListRKN address\ + =\$cnameAddress comment=\$aItem;\r\ + \n :log warning \"Succesfully adding ip to list CNAME r\ + ecord: \$cname, A record: \$aRecord, address: \$newAddress, from domain: \ + \$aItem.\";\r\ + \n# /ip firewall raw add action=add-dst-to-address-list\ + \_address-list=\$ListRKN address-list-timeout=none-dynamic chain=preroutin\ + g comment=\$aItem content=\$aItem;\r\ + \n } on-error={\r\ + \n :log error \"error when adding ip to list CNAME reco\ + rd: \$cname, A record: \$aRecord, address: \$newAddress, from domain: \$aI\ + tem.\";\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:if ([ :len [ /system/scheduler/find where name=\$ScriptName ] ] = 0) do\ + ={\r\ + \n :log error (\$ScriptName . \"System Scheduler for script: \" . \$Scri\ + ptName . \" is NOT SET! Fix It Now!\");\r\ + \n /system/scheduler/add name=\$ScriptName on-event=\"/system/script { \ + run \$ScriptName; }\" comment=\"Update RKN DNS Looup\" interval=00:30:00 p\ + olicy=\"ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon\"\ + \_start-time=startup;\r\ + \n }\r\ + \n:set dnsLookupReady true;\r\ + \ndelay 2s; \r\ + \n:global dnsLookupReady (a);\r\ + \n" +add dont-require-permissions=no name="renameLists " owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + local oldName \"Test\";\ + \n:local newName \"Test-IP\";\ + \n/ip firewall address-list\ + \n:foreach i in=[find list=\$oldName] do={\ + \nset \$i list=\$newName;\ + \n}\ + \n" +add dont-require-permissions=no name=IPv6-Settings owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + #############Script Settings##################\ + \n\ + \n:local \"IF-TUN\" \"6to4-tun\"\ + \n:local \"IF-LOC\" \"Bridge-LAN\"\ + \n:local \"POOL-6TO4\" \"poolV6-local\"\ + \n:local \"force-update\" false\ + \n############ use then static ip #######################\ + \n:local \"lease-address\" [/ip address get [find interface=\$\"IF-LOC\"] \ + address]\ + \n#:local \"interface\" \"ext\"\ + \n:local bound 0\ + \n\ + \n###############################################\ + \n\ + \n:local 6to4prefix do={\ + \n :global dec2hex\ + \n :local ipv4 \$1\ + \n :local ipv6 \"2002:\"\ + \n :for i from=0 to=2 step=1 do={ \ + \n :if ( \$i = 2) do={\ + \n :set ipv6 (\$ipv6.\":\")\ + \n }\ + \n :local fp [:find \$ipv4 \".\"]\ + \n :if ( \$fp > 0 ) do={\ + \n :set ipv6 (\$ipv6.[\$dec2hex [:pick \$ipv4 0 \$fp]])\ + \n :set ipv4 [:pick \$ipv4 (\$fp + 1 ) [:len \$ipv4]]\ + \n }\ + \n }\ + \n :return (\$ipv6.[\$dec2hex \$ipv4])\ + \n}\ + \n:local \"str_replace\" do={\ + \n :local \"str-pos\" [:find \$1 \$2]\ + \n :local \"str-len\" [:len \$2]\ + \n :local str \"\"\ + \n :local rest \$1\ + \n :while (\$\"str-pos\" >= 0) do={\ + \n :local t [:pick \$rest 0 \$\"str-pos\"]\ + \n :if ( \$4 > 0 ) do={\ + \n :for i from=1 to=(\$4 - [:len \$t]) step=1 do={\ + \n :set str (\$str.\$5)\ + \n }\ + \n }\ + \n :set str (\$str.\$t.\$3)\ + \n :set rest [:pick \$rest (\$\"str-pos\"+\$\"str-len\") [:len \$re\ + st]]\ + \n :set \"str-pos\" [:find \$rest \$2]\ + \n }\ + \n :return (\$str.\$rest)\ + \n}\ + \n\ + \n:if (\$bound=1) do={\ + \n :local t [:find \$\"lease-address\" \"/\"]\ + \n\ + \n :if ( \$t >= 0 ) do={\ + \n :set \"lease-address\" [:pick \$\"lease-address\" 0 \$t]\ + \n }\ + \n\ + \n :if ( [/interface 6to4 print count-only where name=\$\"IF-TUN\"] = 0\ + ) do={\ + \n /interface 6to4 add !keepalive local-address=\$\"lease-address\"\ + \_mtu=1280 name=\$\"IF-TUN\" remote-address=10.30.30.0\ + \n :set \"force-update\" true\ + \n }\ + \n\ + \n :local \"IPv4-TUN\" [/interface 6to4 get [find name=\$\"IF-TUN\"] lo\ + cal-address];\ + \n\ + \n :if ( \$\"lease-address\" != \$\"IPv4-TUN\" || \$\"force-update\" = \ + true) do={\ + \n /interface 6to4 set [find name=\$\"IF-TUN\"] local-address=\$\"l\ + ease-address\"\ + \n /ipv6 address remove [find interface=\$\"IF-TUN\"]\ + \n /ipv6 address remove [find interface=\$\"IF-LOC\"]\ + \n /ipv6 route remove [find gateway ~ \$\"IF-TUN\" and dst-address=\ + \"::/0\"]\ + \n :local \"pool-prefix\" [\$6to4prefix \$\"lease-address\"]\ + \n :if ( [/ipv6 pool print count-only where name=\$\"POOL-6TO4\"] =\ + \_0) do={ \ + \n /ipv6 pool add name=\$\"POOL-6TO4\" prefix=(\$\"pool-prefix\ + \".\":1::/64\") prefix-length=64\ + \n } else={\ + \n /ipv6 pool set [/ipv6 pool find where name=\$\"POOL-6TO4\"] \ + prefix=(\$\"pool-prefix\".\":1::/64\")\ + \n }\ + \n /ipv6 address add address=(\$\"pool-prefix\".\"::\".[\$MAC2EUI64\ + \_[/interface get [find name=\$\"interface\"] mac-address]].\"/3\") interf\ + ace=\$\"IF-TUN\" advertise=no\ + \n /ipv6 address add eui-64=yes from-pool=\$\"POOL-6TO4\" interface\ + =\$\"IF-LOC\" advertise=yes\ + \n /ipv6 route add dst-address=::/0 gateway=(\"::10.30.30.81%\".\$\ + \"IF-TUN\")\ + \n :local t [/ipv6 address get [find interface=\$\"IF-LOC\"] addres\ + s]\ + \n :set t [:pick \$t 0 [:find \$t \"/\"]]\ + \n :if ( [/ipv6 dhcp-server option print count-only where name=DNS]\ + \_= 0) do={\ + \n /ipv6 dhcp-server option add code=23 name=DNS value=(\"0x\".\ + [\$\"str_replace\" \$t \":\" \"\" 4 \"0\"])\ + \n } else={\ + \n /ipv6 dhcp-server option set [/ipv6 dhcp-server option find \ + where name=DNS] value=(\"0x\".[\$\"str_replace\" \$t \":\" \"\" 4 \"0\"])\ + \n }\ + \n :if ( [/ipv6 dhcp-server print count-only where interface=\$\"IF\ + -LOC\"] = 0) do={\ + \n /ipv6 dhcp-server add address-pool=\$\"POOL-6TO4\" dhcp-opti\ + on=DNS interface=\$\"IF-LOC\" lease-time=1d name=\$\"IF-LOC\"\ + \n }\ + \n :if ( [ipv6 nd print count-only where interface=\$\"IF-LOC\"] = \ + 0) do={\ + \n /ipv6 nd add advertise-dns=no interface=\$\"IF-LOC\" other-c\ + onfiguration=yes\ + \n }\ + \n }\ + \n}" +add dont-require-permissions=no name=IPv6-GlobalFunc owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + global MAC2EUI64 do={\ + \n :local EUI64 \"\"\ + \n :local MAC \$1\ + \n :local HEX2DEC \"0123456789ABCDEF\"\ + \n :for i from=0 to=5 step=1 do={\ + \n :if ( \$i = 0 ) do={\ + \n :set EUI64 [:pick \$MAC 0]\ + \n :set EUI64 (\$EUI64.[:tostr [:pick \$\"HEX2DEC\" ([:find \$\ + \"HEX2DEC\" [:pick \$MAC 1]] ^ 2)]])\ + \n }\ + \n :if ( \$i = 1 || \$i = 3) do={\ + \n :set EUI64 (\$EUI64.\":\")\ + \n }\ + \n :if ( \$i = 2 ) do={\ + \n :set EUI64 (\$EUI64.\"FF:FE\")\ + \n }\ + \n :if ( [:find \$MAC \":\"] = 2 ) do={\ + \n :set MAC [:pick \$MAC 3 [:len \$MAC]]\ + \n :set EUI64 (\$EUI64.[:pick \$MAC 0 2])\ + \n }\ + \n }\ + \n :return (\$EUI64)\ + \n}\ + \n\ + \n:global dec2hex do={\ + \n :local hex \"\"\ + \n :local dec [:tonum \$1]\ + \n :for i from=0 to=4 step=4 do={\ + \n :set hex ([:pick \"0123456789ABCDEF\" ((\$dec>>\$i)&0xf) (((\$de\ + c>>\$i)&0xf)+1)].\$hex)\ + \n }\ + \n :return ([:tostr \$hex])\ + \n}" +/user group +add name=backup policy="ssh,read,write,policy,test,web,sniff,sensitive,api,res\ + t-api,!local,!telnet,!ftp,!reboot,!winbox,!password,!romon" +/ip smb +set enabled=no interfaces=lo +/interface bridge port +add bridge=Bridge-LAN interface=ether5 +add bridge=Bridge-LAN interface=ether2 +add bridge=Bridge-LAN interface=ether4 trusted=yes +add bridge=Bridge-LAN interface=ether3 +add bridge=Bridge-LAN interface=wlan2 +add bridge=Bridge-LAN interface=wlan1 +/interface bridge settings +# ipv6 neighbor configuration has changed, please restart the device in order to apply the new settings +set use-ip-firewall=yes +/ip firewall connection tracking +# ipv6 neighbor configuration has changed, please restart the device in order to apply the new settings +set udp-timeout=10s +/ip neighbor discovery-settings +# ipv6 neighbor configuration has changed, please restart the device in order to apply the new settings +set discover-interface-list=LAN lldp-med=no lldp-poe-power=no +/ip settings +# ipv6 neighbor configuration has changed, please restart the device in order to apply the new settings +set accept-redirects=yes ipv4-multipath-hash-policy=l4 max-neighbor-entries=\ + 8192 +/ipv6 settings +# ipv6 neighbor configuration has changed, please restart the device in order to apply the new settings +set disable-ipv6=yes disable-link-local-address=yes forward=no \ + max-neighbor-entries=8192 multipath-hash-policy=l4 +/interface detect-internet +set detect-interface-list=static internet-interface-list=Internet \ + lan-interface-list=LAN request-interval=1m wan-interface-list=WAN +/interface l2tp-server server +set authentication=mschap2 use-ipsec=yes +/interface list member +add interface=Bridge-LAN list=LAN +add interface="ether1 - Unet" list=Internet +add interface=WG list=WAN +/interface wireguard peers +add allowed-address=0.0.0.0/0 client-allowed-address=::/0 endpoint-address=\ + 109.107.177.79 endpoint-port=29185 interface=WG name=VDSina \ + persistent-keepalive=10s public-key=\ + "zuRsO+dL/j6awaBWZ/NgnHR+bCNUjRWbaHFpdzkNnw4=" +/interface wireless cap +# +set bridge=Bridge-LAN caps-man-addresses=10.30.30.10 \ + caps-man-certificate-common-names=CAPsMAN-51B25E507D07 certificate=\ + CAP-488F5A8E1ABC discovery-interfaces=Bridge-LAN enabled=yes interfaces=\ + wlan2,wlan1 lock-to-caps-man=yes +/ip address +add address=10.30.30.81/24 interface=Bridge-LAN network=10.30.30.0 +add address=10.8.0.2/24 interface=WG network=10.8.0.0 +/ip cloud +set update-time=no +/ip dhcp-client +add add-default-route=special-classless default-route-distance=2 \ + default-route-tables=main:2 dhcp-options=clientid,clientid_duid \ + interface="ether1 - Unet" name=client1 use-peer-dns=no use-peer-ntp=no +/ip dhcp-server config +set accounting=no +/ip dhcp-server lease +add address=10.30.30.101 client-id=1:48:8f:5a:8e:ee:a8 mac-address=\ + 48:8F:5A:8E:EE:A8 server=masterDHCP +add address=10.30.30.107 client-id=1:f0:de:f1:91:d:1e mac-address=\ + F0:DE:F1:91:0D:1E server=masterDHCP +add address=10.30.30.83 client-id=1:0:80:77:ec:43:86 mac-address=\ + 00:80:77:EC:43:86 server=masterDHCP +add address=10.30.30.70 dhcp-option=domain-search-list,HostName \ + dhcp-option-set=HP1505n mac-address=00:1E:0B:1A:88:8D server=masterDHCP +add address=10.30.30.50 client-id=1:4:7c:16:36:f5:37 mac-address=\ + 04:7C:16:36:F5:37 server=masterDHCP +add address=10.30.30.71 client-id=1:10:2d:41:2c:20:c2 mac-address=\ + 10:2D:41:2C:20:C2 server=masterDHCP +add address=10.30.30.61 client-id=1:10:8:c1:81:59:5f mac-address=\ + 10:08:C1:81:59:5F server=masterDHCP +add address=10.30.30.72 client-id=1:10:38:1f:d2:5f:13 mac-address=\ + 10:38:1F:D2:5F:13 server=masterDHCP +add address=10.30.30.99 client-id=1:10:b1:df:e9:d0:d5 mac-address=\ + 10:B1:DF:E9:D0:D5 server=masterDHCP +add address=10.30.30.111 client-id=1:fe:2:52:be:3f:16 mac-address=\ + FE:02:52:BE:3F:16 server=masterDHCP +add address=10.30.30.92 client-id=1:d4:6d:6d:fd:e5:49 mac-address=\ + D4:6D:6D:FD:E5:49 server=masterDHCP +add address=10.30.30.93 client-id=1:7e:8b:1e:cb:b8:cb mac-address=\ + CC:42:10:12:46:94 server=masterDHCP +add address=10.30.30.94 client-id=1:50:cc:f8:85:96:a mac-address=\ + 50:CC:F8:85:96:0A server=masterDHCP +add address=10.30.30.82 client-id=1:e4:18:6b:58:34:ab mac-address=\ + E4:18:6B:58:34:AB server=masterDHCP +add address=10.30.30.75 client-id=1:0:27:15:41:97:a9 mac-address=\ + 00:27:15:41:97:A9 server=masterDHCP +add address=10.30.30.77 dhcp-option=HostName dhcp-option-set=StartLife1 \ + mac-address=C4:82:E1:03:49:10 server=masterDHCP +add address=10.30.30.73 client-id=1:10:38:1f:82:81:f2 mac-address=\ + 10:38:1F:82:81:F2 server=masterDHCP +add address=10.30.30.95 client-id=1:88:ae:dd:60:39:54 dhcp-option=HostName \ + dhcp-option-set=VADOS-NUC mac-address=88:AE:DD:60:39:54 server=masterDHCP +add address=10.30.30.98 client-id=1:c8:5b:76:d8:cc:bf dhcp-option=HostName \ + dhcp-option-set=VADOS-LEN mac-address=C8:5B:76:D8:CC:BF server=masterDHCP +add address=10.30.30.96 client-id=iPhone mac-address=4A:91:ED:0E:1F:39 \ + server=masterDHCP +add address=10.30.30.74 client-id=MiTV dhcp-option=HostName dhcp-option-set=\ + MiTV mac-address=20:72:A9:D3:34:36 server=masterDHCP +add address=10.30.30.30 dhcp-option=HostName dhcp-option-set=miller \ + mac-address=F0:75:5D:1E:5F:71 server=masterDHCP +add address=10.30.30.100 client-id=iVados dhcp-option=HostName \ + dhcp-option-set=iVados mac-address=DE:4D:72:F3:1A:9F server=masterDHCP +/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.81 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=1.0.0.1,8.8.4.4 verify-doh-cert=yes +/ip dns static +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 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 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 name=MikroYellow type=A +add address=10.30.30.85 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 name=garage type=A +/ip firewall address-list +add address=91.215.120.206 list=TRUSTED +add address=185.71.70.78 disabled=yes list=TRUSTED +add address=176.53.203.171 disabled=yes list=TRUSTED +add address=176.53.203.170 disabled=yes list=TRUSTED +add address=176.53.202.194 disabled=yes list=TRUSTED +add address=8.8.4.0/24 list=YouTube +add address=8.8.8.0/24 list=YouTube +add address=8.34.208.0/20 list=YouTube +add address=8.35.192.0/20 list=YouTube +add address=23.236.48.0/20 list=YouTube +add address=23.251.128.0/19 list=YouTube +add address=34.0.0.0/15 list=YouTube +add address=34.2.0.0/16 list=YouTube +add address=34.3.0.0/23 list=YouTube +add address=34.3.3.0/24 list=YouTube +add address=34.3.4.0/24 list=YouTube +add address=34.3.8.0/21 list=YouTube +add address=34.3.16.0/20 list=YouTube +add address=34.3.32.0/19 list=YouTube +add address=34.3.64.0/18 list=YouTube +add address=34.4.0.0/14 list=YouTube +add address=34.8.0.0/13 list=YouTube +add address=34.16.0.0/12 list=YouTube +add address=34.32.0.0/11 list=YouTube +add address=34.64.0.0/10 list=YouTube +add address=34.128.0.0/10 list=YouTube +add address=35.184.0.0/13 list=YouTube +add address=35.192.0.0/14 list=YouTube +add address=35.196.0.0/15 list=YouTube +add address=35.198.0.0/16 list=YouTube +add address=35.199.0.0/17 list=YouTube +add address=35.199.128.0/18 list=YouTube +add address=35.200.0.0/13 list=YouTube +add address=35.208.0.0/12 list=YouTube +add address=35.224.0.0/12 list=YouTube +add address=35.240.0.0/13 list=YouTube +add address=57.140.192.0/18 list=YouTube +add address=64.15.112.0/20 list=YouTube +add address=64.233.160.0/19 list=YouTube +add address=66.22.228.0/23 list=YouTube +add address=66.102.0.0/20 list=YouTube +add address=66.249.64.0/19 list=YouTube +add address=70.32.128.0/19 list=YouTube +add address=72.14.192.0/18 list=YouTube +add address=74.125.0.0/16 list=YouTube +add address=104.154.0.0/15 list=YouTube +add address=104.196.0.0/14 list=YouTube +add address=104.237.160.0/19 list=YouTube +add address=107.167.160.0/19 list=YouTube +add address=107.178.192.0/18 list=YouTube +add address=108.59.80.0/20 list=YouTube +add address=108.170.192.0/18 list=YouTube +add address=108.177.0.0/17 list=YouTube +add address=130.211.0.0/16 list=YouTube +add address=136.22.160.0/20 list=YouTube +add address=136.22.176.0/21 list=YouTube +add address=136.22.184.0/23 list=YouTube +add address=136.22.186.0/24 list=YouTube +add address=142.250.0.0/15 list=YouTube +add address=146.148.0.0/17 list=YouTube +add address=152.65.208.0/22 list=YouTube +add address=152.65.214.0/23 list=YouTube +add address=152.65.218.0/23 list=YouTube +add address=152.65.222.0/23 list=YouTube +add address=152.65.224.0/19 list=YouTube +add address=162.120.128.0/17 list=YouTube +add address=162.216.148.0/22 list=YouTube +add address=162.222.176.0/21 list=YouTube +add address=172.110.32.0/21 list=YouTube +add address=172.217.0.0/16 list=YouTube +add address=172.253.0.0/16 list=YouTube +add address=173.194.0.0/16 list=YouTube +add address=173.255.112.0/20 list=YouTube +add address=192.158.28.0/22 list=YouTube +add address=192.178.0.0/15 list=YouTube +add address=193.186.4.0/24 list=YouTube +add address=199.36.154.0/23 list=YouTube +add address=199.36.156.0/24 list=YouTube +add address=199.192.112.0/22 list=YouTube +add address=199.223.232.0/21 list=YouTube +add address=207.223.160.0/20 list=YouTube +add address=208.65.152.0/22 list=YouTube +add address=208.68.108.0/22 list=YouTube +add address=208.81.188.0/22 list=YouTube +add address=208.117.224.0/19 list=YouTube +add address=209.85.128.0/17 list=YouTube +add address=216.58.192.0/19 list=YouTube +add address=216.73.80.0/20 list=YouTube +add address=216.239.32.0/19 list=YouTube +add address=2ip.ru list=Test-IP +add address=wg.vados.ru comment=VDSIna list=TRUSTED +add address=10.8.0.0/24 comment="WG VDSIna" disabled=yes list=TRUSTED +add address=ikus.pesc.ru comment=ikus.pesc.ru list=NoVdsina +add address=love.ru comment=love.ru list=NoVdsina +add address=gosuslugi.ru comment=gosuslugi.ru list=NoVdsina +add address=pochta.ru comment=pochta.ru list=NoVdsina +add address=vdsina.com list=NoVdsina +add address=vdsina.ru list=NoVdsina +add address=youla.ru list=NoVdsina +add address=kupiprodai.ru list=NoVdsina +add address=myip.ru list=Test-IP +add address=geoip.co list=NoVdsina +add address=comp-lenta.ru list=NoVdsina +add address=128.85.102.70 comment=update.microsoft.com list=\ + windowsupdateslist +add address=wu-b-net.trafficmanager.net. comment=\ + ctldl.windowsupdate.com.delivery.microsoft.com list=windowsupdateslist +add address=ctldl.windowsupdate.com.delivery.microsoft.com. comment=\ + ctldl.windowsupdate.com list=windowsupdateslist +add address=redir.update.msft.com.trafficmanager.net. comment=\ + update.microsoft.com list=windowsupdateslist +add address=geo.prod.do.dsp.trafficmanager.net. comment=\ + geo.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=13.74.139.29 comment=array605.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=kv801.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + kv801.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=e12437.d.akamaiedge.net. comment=\ + kv801.prod.do.dsp.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=displaycatalog-rp.md.mp.microsoft.com.akadns.net. comment=\ + displaycatalog.mp.microsoft.com list=windowsupdateslist +add address=rp-consumer-prod-displaycatalog-geomap.trafficmanager.net. \ + comment=displaycatalog-rp.md.mp.microsoft.com.akadns.net list=\ + windowsupdateslist +add address=sls.update.microsoft.com. comment=slscr.update.microsoft.com \ + list=windowsupdateslist +add address=glb.sls.prod.dcat.dsp.trafficmanager.net. comment=\ + sls.update.microsoft.com list=windowsupdateslist +add address=fe3.delivery.mp.microsoft.com. comment=\ + fe3cr.delivery.mp.microsoft.com list=windowsupdateslist +add address=glb.cws.prod.dcat.dsp.trafficmanager.net. comment=\ + fe3.delivery.mp.microsoft.com list=windowsupdateslist +add address=fe2cr.update.msft.com.trafficmanager.net. comment=\ + fe2cr.update.microsoft.com list=windowsupdateslist +add address=download.windowsupdate.com.delivery.microsoft.com. comment=\ + download.windowsupdate.com list=windowsupdateslist +add address=wu-f-net.trafficmanager.net. comment=\ + download.windowsupdate.com.delivery.microsoft.com list=windowsupdateslist +add address=tsfe.trafficmanager.net. comment=\ + tsfe.trafficshaping.dsp.mp.microsoft.com list=windowsupdateslist +add address=edge.ds-c7110-microsoft.global.dns.qwilted-cds.cqloud.com. \ + comment=9.au.download.windowsupdate.com list=windowsupdateslist +add address=52.158.227.125 comment=array812.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=au.download.windowsupdate.com.delivery.microsoft.com. comment=\ + au.download.windowsupdate.com list=windowsupdateslist +add address=a767.dspw65.akamai.net. comment=\ + download.windowsupdate.com.edgesuite.net list=windowsupdateslist +add address=52.151.58.88 comment=array810.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=consumer-licensing-aks2aks.md.mp.microsoft.com.akadns.net. \ + comment=licensing.mp.microsoft.com list=windowsupdateslist +add address=licensing-prod-frontdoor-geomap.trafficmanager.net. comment=\ + consumer-licensing-aks2aks.md.mp.microsoft.com.akadns.net list=\ + windowsupdateslist +add address=star.f.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedge.f.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=cdp-f-nlu-net.trafficmanager.net. comment=\ + star.f.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=star.b.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedge.b.tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=cdp-f-tlu-net.trafficmanager.net. comment=\ + star.b.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=storeedgefd.xbetservices.akadns.net. comment=\ + storeedgefd.dsx.mp.microsoft.com list=windowsupdateslist +add address=\ + storeedgefd.dsx.mp.microsoft.com.edgekey.net.globalredir.akadns.net. \ + comment=storeedgefd.dsx.mp.microsoft.com.edgekey.net list=\ + windowsupdateslist +add address=e16646.dscg.akamaiedge.net. comment=\ + storeedgefd.dsx.mp.microsoft.com.edgekey.net.globalredir.akadns.net list=\ + windowsupdateslist +add address=40.69.76.189 comment=array621.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=bg.microsoft.map.fastly.net. comment=\ + 3.au.download.windowsupdate.com list=windowsupdateslist +add list=windowsupdateslist +add address=40.69.75.33 comment=array613.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=star.sf.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedgeextensions.sf.tlu.dl.delivery.mp.microsoft.com list=\ + windowsupdateslist +add address=cdp-f-ssl-tlu-net.trafficmanager.net. comment=\ + star.sf.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=a2033.dscd.akamai.net. comment=\ + star.sb.tlu.dl.delivery.mp.microsoft.com.edgesuite.net list=\ + windowsupdateslist +add address=13.74.138.242 comment=array602.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=dl.delivery.mp.microsoft.com.delivery.microsoft.com. comment=\ + dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=dcat-f-nlu-net.trafficmanager.net. comment=\ + dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=1d.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=1D.tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=dcat-b-tlu-net.trafficmanager.net. comment=\ + 1d.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=a122.dscg3.akamai.net. comment=\ + tlu.dl.delivery.mp.microsoft.com.edgesuite.net list=windowsupdateslist +add address=geover.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + geover.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=e10370.d.akamaiedge.net. comment=\ + geover.prod.do.dsp.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=52.232.182.21 comment=array511.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.70.77.95 comment=array519.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=a1683.dscd.akamai.net. comment=\ + dl.delivery.mp.microsoft.com-c.edgesuite.net list=windowsupdateslist +add address=consumer-collections-aks2eap.md.mp.microsoft.com.akadns.net. \ + comment=collections.mp.microsoft.com list=windowsupdateslist +add address=a1847.dscd.akamai.net. comment=\ + wildcard.f.tlu.dl.delivery.mp.microsoft.com.edgesuite.net list=\ + windowsupdateslist +add address=13.74.142.6 comment=array607.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=au.download.windowsupdate.com.edgesuite.net. comment=\ + 2.au.download.windowsupdate.com list=windowsupdateslist +add address=a767.dscg3.akamai.net. comment=\ + au.download.windowsupdate.com.edgesuite.net list=windowsupdateslist +add address=52.156.123.84 comment=array818.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.69.78.254 comment=array610.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=4.au.download.windowsupdate.com.delivery.microsoft.com. comment=\ + 4.au.download.windowsupdate.com list=windowsupdateslist +add address=cl-glcb907925.gcdn.co. comment=\ + 4.au.download.windowsupdate.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=52.167.167.111 comment=array510.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=40.69.70.43 comment=array623.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=tsfe.trafficshaping.dsp.mp.microsoft.com.delivery.microsoft.com. \ + comment=tsfe.trafficshaping.dsp.mp.microsoft.com list=windowsupdateslist +add address=ts-frontend.trafficmanager.net. comment=\ + tsfe.trafficshaping.dsp.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=40.69.75.248 comment=array616.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.69.74.84 comment=array615.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=sds.trafficmanager.net. comment=software-download.microsoft.com \ + list=windowsupdateslist +add address=40.69.74.80 comment=array611.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.175.242.182 comment=array804.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=dlc-shim.trafficmanager.net. comment=download.microsoft.com list=\ + windowsupdateslist +add address=e12671.dscd.akamaiedge.net. comment=\ + download.microsoft.com.edgekey.net list=windowsupdateslist +add address=20.187.55.34 comment=array808.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.167.231 comment=array513.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=52.167.222.13 comment=array518.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=kv601.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + kv601.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=e12358.d.akamaiedge.net. comment=\ + kv601.prod.do.dsp.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. comment=\ + tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=dcat-f-tlu-net.trafficmanager.net. comment=\ + tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=a1856.dspw65.akamai.net. comment=\ + tlu.dl.delivery.mp.microsoft.com-c.edgesuite.net list=windowsupdateslist +add address=52.167.164.252 comment=array506.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=13.74.137.54 comment=array601.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=kv501.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + kv501.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=collections-prod-frontdoor-geomap.trafficmanager.net. comment=\ + consumer-collections-aks2eap.md.mp.microsoft.com.akadns.net list=\ + windowsupdateslist +add address=52.167.160.173 comment=array509.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=40.70.77.148 comment=array516.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.200.126 comment=array507.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=52.167.167.59 comment=array508.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.69.76.172 comment=array620.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=smtp.mail.me.com comment=smtp.mail.me.com list=NoVdsina +add address=40.70.76.5 comment=array514.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.186.119 comment=array618.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.177.176.186 comment=array520.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=40.70.76.27 comment=array515.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.160.43 comment=array503.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.110 comment=array817.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.142.8 comment=array614.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.138.254 comment=array603.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.167.96 comment=array501.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.69.76.215 comment=array622.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.143.200 comment=array606.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.111 comment=array818.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.112 comment=array819.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.137.53 comment=array608.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.98 comment=array805.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.96 comment=array803.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.104 comment=array811.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.101 comment=array808.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.99 comment=array806.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.17 comment=array802.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.97 comment=array804.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.103 comment=array810.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.16 comment=array801.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.70.77.177 comment=array517.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.164.84 comment=array512.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.105 comment=array812.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.107 comment=array814.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.232.161.82 comment=array502.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.108 comment=array815.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.161.91 comment=array505.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.102 comment=array809.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.109 comment=array816.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.106 comment=array813.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.117 comment=array622.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.107 comment=array612.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.108 comment=array613.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.105 comment=array610.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.113 comment=array618.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.116 comment=array621.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.98 comment=array603.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.114 comment=array619.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.111 comment=array616.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.97 comment=array602.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.106 comment=array611.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.110 comment=array615.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.119 comment=array624.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.135 comment=array514.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.97 comment=array503.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.99 comment=array604.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.61 comment=array504.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.131 comment=array510.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.132 comment=array511.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.96 comment=array601.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.104 comment=array609.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.138 comment=array517.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.60 comment=array501.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.139 comment=array518.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.118 comment=array623.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.113 comment=array820.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.103 comment=array608.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.100 comment=array807.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.129 comment=array508.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.134 comment=array513.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.62 comment=array505.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.137 comment=array516.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.101 comment=array606.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.96 comment=array502.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.130 comment=array509.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.112 comment=array617.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.100 comment=array605.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.115 comment=array620.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.136 comment=array515.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=purchase.md.mp.microsoft.com.akadns.net. comment=\ + purchase.mp.microsoft.com list=windowsupdateslist +add address=e110219.a.akamaiedge.net. comment=\ + purchase.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=72.153.5.140 comment=array519.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.141 list=windowsupdateslist +add address=72.153.5.63 comment=array506.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.128 comment=array507.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.102 comment=array607.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=storesdk.xbetservices.akadns.net. comment=\ + storesdk.dsx.mp.microsoft.com list=windowsupdateslist +add address=e16646.g.akamaiedge.net. comment=\ + storesdk.dsx.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=software-download.microsoft.com.delivery.microsoft.com. comment=\ + software-download.microsoft.com list=windowsupdateslist +add address=download.prss.microsoft.com.akamaized.net. comment=\ + software-download.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.109 comment=array614.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.133 comment=array512.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=213.180.192.0/19 comment=YandexDisk list=NoVdsina +add address=87.250.250.50 comment=YandexDisk list=NoVdsina +add address=consumer-prod-bcfd-v7-afd.trafficmanager.net. comment=\ + displaycatalog.mp.microsoft.com list=windowsupdateslist +add address=purchase-europeeap.md.mp.microsoft.com.akadns.net. comment=\ + purchase.md.mp.microsoft.com.akadns.net list=windowsupdateslist +add address=ne-az-conspurchase-mp.trafficmanager.net. comment=\ + purchase-europeeap.md.mp.microsoft.com.akadns.net list=windowsupdateslist +add address=storeedgefd.dsx.mp.microsoft.com.edgekey.net. comment=\ + cdn.storeedgefd.dsx.mp.microsoft.com list=windowsupdateslist +add address=star.f.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedge.f.tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=a1996.dscd.akamai.net. comment=\ + wildcard.f.dl.delivery.mp.microsoft.com.edgesuite.net list=\ + windowsupdateslist +add address=cp801.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + cp801.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=glb.tas02.sls-prod.dcat.dsp.mp.microsoft.com. comment=\ + tas02.sls.update.microsoft.com list=windowsupdateslist +add address=cp601.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + cp601.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=star.sb.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedgeextensions.sb.tlu.dl.delivery.mp.microsoft.com list=\ + windowsupdateslist +add address=star.sf.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedge.sf.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=cdp-f-ssl-nlu-net.trafficmanager.net. comment=\ + star.sf.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=tm-pifd-prod-gbl-weight.trafficmanager.net. comment=\ + paymentinstruments.mp.microsoft.com list=windowsupdateslist +add address=10.30.30.33 comment=amster disabled=yes list=NoWG +add address=10.30.30.10 comment=MikroNUC disabled=yes list=NoWG +add address=89.110.101.17 comment=!!!VDSINA!!!! disabled=yes list=NoWG +add address=wg.vados.ru comment=VDSina-vpn list=VDSina +add address=80.85.244.9 list=TRUSTED +add address=disc801.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + disc801.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=185.71.70.78 disabled=yes list=TRUSTED +add address=176.53.203.171 disabled=yes list=TRUSTED +add address=176.53.203.170 disabled=yes list=TRUSTED +add address=176.53.202.194 disabled=yes list=TRUSTED +add address=89.110.101.17 comment="!!!VDSina Server!!!" list=NoVdsina +add address=dns.quad9.net comment=Quad9-dns disabled=yes list=Trusted-DNS +add address=dns.google comment=Google-dns list=Trusted-DNS +add address=security.cloudflare-dns.com comment=CloudFlare-dns list=\ + Trusted-DNS +add address=time.google.com comment=Google-time list=Trusted-NTP +add address=0.ru.pool.ntp.org comment=ru.pool.ntp.org disabled=yes list=\ + Trusted-NTP +add address=1.ru.pool.ntp.org disabled=yes list=Trusted-NTP +add address=2.ru.pool.ntp.org comment=2.ru.pool.ntp.org disabled=yes list=\ + Trusted-NTP +add address=3.ru.pool.ntp.org comment=3.ru.pool.ntp.org disabled=yes list=\ + Trusted-NTP +add address=cp.vdsina.com comment=VDSina-vpn list=VDSina +add address=vdsina.ru comment=VDSina-vpn list=VDSina +add address=ns.vados.ru comment=VDSina-vpn list=VDSina +add address=vdsina.com comment=VDSina-vpn list=VDSina +add address=cp.vdsina.ru comment=VDSina-vpn list=VDSina +add address=ns1.vdsina.ru comment=VDSina-vpn list=VDSina +add address=10.30.30.0/24 comment="Local Network" list=Local-Net +add address=10.8.0.0/24 comment="WireGuard Network" list=Local-Net +add address=146.120.64.208/29 comment="External Net" list=Unet +add address=esia.gosuslugi.ru comment=esia.gosuslugi.ru list=NoVdsina +add address=lk.gosuslugi.ru comment=lk.gosuslugi.ru list=NoVdsina +add address=trudvsem.ru comment=trudvsem.ru list=NoVdsina +add address=10.30.30.30 comment=miller disabled=yes list=NoWG +add address=10.30.30.33 comment="Direct connet to DNS servers" list=\ + Direct-DNS +add address=wg.vados.ru list=VPN-Server +/ip firewall filter +add action=accept chain=input dst-port=18880 in-interface=Bridge-LAN \ + protocol=tcp src-address=10.30.30.0/24 +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=12h chain=input comment="block honeypot DNS" \ + connection-state=new dst-port=53 in-interface="ether1 - Unet" protocol=\ + udp src-address-list=!Trusted-DNS +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=4w2d chain=input connection-state=new dst-port=53 \ + in-interface="ether1 - Unet" protocol=tcp src-address-list=!Trusted-DNS +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=4w2d chain=input comment=\ + "block honeypot ssh rdp winbox" connection-state=new dst-port=22,8291 \ + in-interface="ether1 - Unet" protocol=tcp src-address-list=!TRUSTED +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=4w2d chain=input comment="block honeypot asterisk" \ + connection-state=new dst-port=5060 in-interface="ether1 - Unet" protocol=\ + udp +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=4w2d chain=input comment="block honeypot NTP" \ + connection-state=new dst-port=123 in-interface="ether1 - Unet" protocol=\ + udp +add action=fasttrack-connection chain=forward comment=\ + "FastTrack for non-VPN connections" connection-mark=!VPN_No_FastTrack \ + connection-state=established,related,new disabled=yes +add action=accept chain=input disabled=yes dst-port=29185 in-interface=\ + "ether1 - Unet" protocol=tcp +add action=accept chain=input disabled=yes dst-port=29185 in-interface=\ + "ether1 - Unet" protocol=udp +add action=accept chain=input comment="tcp Accept input DNS queries from LAN" \ + dst-port=53 in-interface=Bridge-LAN protocol=tcp src-address=\ + 10.30.30.0/24 +add action=accept chain=input comment="udp Accept input DNS queries" \ + dst-port=53 in-interface=Bridge-LAN protocol=udp src-address=\ + 10.30.30.0/24 +add action=accept chain=output comment="accept WireGuard" dst-address-list=\ + VPN-Server out-interface="ether1 - Unet" protocol=udp src-port=13231 +add action=accept chain=output dst-address-list=VPN-Server dst-port=29185 \ + out-interface="ether1 - Unet" protocol=udp +add action=fasttrack-connection chain=forward comment="defconf: fasttrack" \ + connection-state=established,related,new disabled=yes routing-mark=\ + !To-VPN +add action=accept chain=output disabled=yes protocol=tcp src-port=443 +add action=accept chain=output disabled=yes src-address=127.0.0.1 +add action=accept chain=forward comment="defconf: accept in ipsec policy" \ + disabled=yes ipsec-policy=in,ipsec +add action=accept chain=forward comment="defconf: accept out ipsec policy" \ + disabled=yes ipsec-policy=out,ipsec +add action=accept chain=forward comment=\ + "defconf: accept established,related, untracked" connection-state=\ + established,related,untracked +add action=drop chain=forward comment="defconf: drop invalid" \ + connection-state=invalid in-interface="ether1 - Unet" src-address=\ + !10.30.30.0/24 +add action=drop chain=forward comment=\ + "defconf: drop all from WAN not DSTNATed" connection-nat-state=!dstnat \ + connection-state=new in-interface="ether1 - Unet" src-address-list=\ + !VDSina +add action=drop chain=forward comment=\ + "Filter Rule to block FB address LIST : )" disabled=yes dst-address-list=\ + facebook +add action=drop chain=forward comment=\ + "Filter Rule to block YOUTUBE address LIST : )" disabled=yes \ + dst-address-list=YouTube +add action=accept chain=input protocol=icmp src-address-list=VDSina +add action=accept chain=input connection-state=established +add action=accept chain=input connection-state=related in-interface-list=\ + *2000014 +add action=drop chain=input in-interface=!Bridge-LAN +/ip firewall mangle +add action=mark-routing chain=prerouting comment=\ + "Mark Routing main for NoVdsina" dst-address-list=NoVdsina \ + new-routing-mark=main passthrough=no src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=\ + "Mark Routing main for VDSina" dst-address-list=VPN-Server \ + new-routing-mark=main src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=\ + "!!!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="Mark Routing main for NoWG" \ + new-routing-mark=main passthrough=no src-address=10.30.30.0/24 \ + src-address-list=NoWG +add action=mark-routing chain=prerouting comment="VDSIna for All sites" \ + dst-address=!10.30.30.0/24 dst-address-list=!NoVdsina new-routing-mark=\ + To-VPN src-address=10.30.30.0/24 src-address-list=!NoWG +add action=mark-connection chain=prerouting comment=\ + "Mark VPN connections to exclude from FastTrack" new-connection-mark=\ + VPN_No_FastTrack routing-mark=To-VPN +add action=change-mss chain=forward comment="MSS on WG" new-mss=1380 \ + out-interface=WG protocol=tcp routing-mark=To-VPN tcp-flags=syn tcp-mss=\ + 1381-65535 +add action=mark-routing chain=prerouting comment="VPN Network" dst-address=\ + 10.8.0.0/24 new-routing-mark=To-VPN src-address=10.30.30.0/24 +/ip firewall nat +add action=redirect chain=dstnat comment="udp Redirect DNS in NAT" disabled=\ + yes dst-port=53 protocol=udp src-address=10.30.30.0/24 to-addresses=\ + 10.30.30.81 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 to-addresses=\ + 10.30.30.81 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" dst-address=\ + !10.30.30.0/24 out-interface="ether1 - Unet" src-address=10.30.30.0/24 +add action=dst-nat chain=dstnat comment=amster.vados.ruhttps dst-port=443 \ + fragment=no in-interface="ether1 - Unet" protocol=tcp src-address=\ + !10.30.30.0/24 to-addresses=10.30.30.33 to-ports=443 +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="amster.vados.ru For Certbot HTTP" \ + dst-port=80 in-interface="ether1 - Unet" protocol=tcp to-addresses=\ + 10.30.30.33 to-ports=80 +add action=dst-nat chain=dstnat comment=npm dst-port=81 in-interface=\ + "ether1 - Unet" protocol=tcp routing-mark=To-VPN to-addresses=10.30.30.33 \ + to-ports=81 +add action=dst-nat chain=dstnat comment=SSH dst-port=22 in-interface=\ + "ether1 - Unet" protocol=tcp src-address-list=TRUSTED to-addresses=\ + 10.30.30.33 to-ports=22 +add action=dst-nat chain=dstnat comment="portainer agent" disabled=yes \ + dst-port=2377 in-interface="ether1 - Unet" protocol=tcp to-addresses=\ + 10.30.30.33 to-ports=2377 +add action=dst-nat chain=dstnat disabled=yes dst-port=22 in-interface=\ + "ether1 - Unet" protocol=tcp routing-mark=!To-VPN to-addresses=\ + 10.30.30.33 to-ports=22 +add action=masquerade chain=srcnat comment=WG dst-address-list=!NoVdsina \ + out-interface=WG routing-mark=To-VPN src-address-list=!NoWG +add action=dst-nat chain=dstnat comment="Yandex.DNS Family" disabled=yes \ + dst-port=53 in-interface=Bridge-LAN protocol=udp src-address-list=KIDS \ + time=6h-15m,sun,mon,tue,wed,thu,fri,sat to-addresses=77.88.8.3 +add action=dst-nat chain=dstnat disabled=yes dst-port=53 in-interface=\ + Bridge-LAN protocol=tcp src-address-list=KIDS time=\ + 6h-15m,sun,mon,tue,wed,thu,fri,sat to-addresses=77.88.8.3 +/ip firewall raw +add action=drop chain=prerouting comment="Drop Honeypot Hackers" \ + in-interface="ether1 - Unet" src-address-list="Honeypot Hacker" +add action=accept chain=prerouting comment="Trusted DNS" disabled=yes \ + in-interface-list=WAN src-address-list=Trusted-DNS +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + extras.getpagespeed.com content=extras.getpagespeed.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=linux.duke.edu \ + content=linux.duke.edu disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=youtube.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + googleapis.com disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=ggpht.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=youtu.be \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=ytimg.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + googlevideo.com disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=gstatic.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + googleusercontent.com disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + nhacmp3youtube.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=rutube.ru \ + content=rutube.ru disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment="me.com raw" \ + content=me.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "icloud.com raw" content=icloud.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "smtp.mail.me.com raw" content=smtp.mail.me.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "smtp.mail.me.com.akadns.net raw" content=smtp.mail.me.com.akadns.net \ + disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "api.db-ip.com raw" content=api.db-ip.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + esia.gosuslugi.ru content=esia.gosuslugi.ru disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=gosuslugi.ru \ + content=gosuslugi.ru disabled=yes +/ip firewall service-port +set ftp disabled=yes +set tftp disabled=yes +set irc disabled=no +set sip disabled=yes +set pptp disabled=yes +set rtsp disabled=no +/ip ipsec settings +set accounting=no +/ip ipsec policy +set 0 disabled=yes dst-address=0.0.0.0/0 src-address=0.0.0.0/0 +/ip ipsec profile +set [ find default=yes ] dpd-interval=2m dpd-maximum-failures=5 +/ip proxy +set cache-administrator="" max-cache-size=none port=80,443 src-address=\ + 0.0.0.0 +/ip route +add check-gateway=none disabled=no distance=1 dst-address=0.0.0.0/0 gateway=\ + WG routing-table=To-VPN scope=30 target-scope=10 +/ip service +set ftp disabled=yes +set telnet disabled=yes +set reverse-proxy disabled=yes +set ssh address=10.30.30.0/24 port=2222 +set winbox address=10.30.30.0/24 +set api address=10.30.30.0/24 disabled=yes +set api-ssl address=10.30.30.0/24 disabled=yes +set www-ssl certificate=Root-YE port=18443 +set www address=10.30.30.0/24 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 \ + strong-crypto=yes +/ip upnp +set enabled=yes +/ip upnp interfaces +add interface=Bridge-LAN type=internal +add forced-ip=146.120.64.211 interface="ether1 - Unet" type=external +add forced-ip=109.107.177.79 interface=*E type=external +add interface=lo type=internal +add interface=wlan2 type=internal +add interface=wlan1 type=internal +/ipv6 dhcp-client +add add-default-route=yes disabled=yes interface=*F rapid-commit=no request=\ + info use-interface-duid=yes validate-server-duid=no +/ipv6 dhcp-server option sets +add name=domain-search-set options=domain-search-list +add name="=\"Client ID\"" options=HostName +/ipv6 firewall address-list +add address=::/128 comment="defconf: unspecified address" list=bad_ipv6 +add address=::1/128 comment="defconf: lo" list=bad_ipv6 +add address=fec0::/10 comment="defconf: site-local" list=bad_ipv6 +add address=::ffff:0.0.0.0/96 comment="defconf: ipv4-mapped" list=bad_ipv6 +add address=::/96 comment="defconf: ipv4 compat" list=bad_ipv6 +add address=100::/64 comment="defconf: discard only " list=bad_ipv6 +add address=2001:db8::/32 comment="defconf: documentation" list=bad_ipv6 +add address=2001:10::/28 comment="defconf: ORCHID" list=bad_ipv6 +add address=3ffe::/16 comment="defconf: 6bone" list=bad_ipv6 +/ipv6 firewall filter +add action=accept chain=input comment=\ + "defconf: accept established,related,untracked" connection-state=\ + established,related,untracked +add action=drop chain=input comment="defconf: drop invalid" connection-state=\ + invalid +add action=accept chain=input comment="defconf: accept ICMPv6" protocol=\ + icmpv6 +add action=accept chain=input comment="defconf: accept UDP traceroute" \ + dst-port=33434-33534 protocol=udp +add action=accept chain=input comment=\ + "defconf: accept DHCPv6-Client prefix delegation." dst-port=546 protocol=\ + udp src-address=fe80::/10 +add action=accept chain=input comment="defconf: accept IKE" dst-port=500,4500 \ + protocol=udp +add action=accept chain=input comment="defconf: accept ipsec AH" protocol=\ + ipsec-ah +add action=accept chain=input comment="defconf: accept ipsec ESP" protocol=\ + ipsec-esp +add action=accept chain=input comment=\ + "defconf: accept all that matches ipsec policy" ipsec-policy=in,ipsec +add action=drop chain=input comment=\ + "defconf: drop everything else not coming from LAN" in-interface-list=\ + !LAN +add action=accept chain=forward comment=\ + "defconf: accept established,related,untracked" connection-state=\ + established,related,untracked +add action=drop chain=forward comment="defconf: drop invalid" \ + connection-state=invalid +add action=drop chain=forward comment=\ + "defconf: drop packets with bad src ipv6" src-address-list=bad_ipv6 +add action=drop chain=forward comment=\ + "defconf: drop packets with bad dst ipv6" dst-address-list=bad_ipv6 +add action=drop chain=forward comment="defconf: rfc4890 drop hop-limit=1" \ + hop-limit=equal:1 protocol=icmpv6 +add action=accept chain=forward comment="defconf: accept ICMPv6" protocol=\ + icmpv6 +add action=accept chain=forward comment="defconf: accept HIP" protocol=139 +add action=accept chain=forward comment="defconf: accept IKE" dst-port=\ + 500,4500 protocol=udp +add action=accept chain=forward comment="defconf: accept ipsec AH" protocol=\ + ipsec-ah +add action=accept chain=forward comment="defconf: accept ipsec ESP" protocol=\ + ipsec-esp +add action=accept chain=forward comment=\ + "defconf: accept all that matches ipsec policy" ipsec-policy=in,ipsec +add action=drop chain=forward comment=\ + "defconf: drop everything else not coming from LAN" in-interface-list=\ + !LAN +/ipv6 nd +set [ find default=yes ] advertise-dns=yes disabled=yes interface=Bridge-LAN \ + managed-address-configuration=yes other-configuration=yes pref64=::/64 +/ipv6 nd prefix +add autonomous=no disabled=yes interface=Bridge-LAN on-link=no prefix=none +/ipv6 nd prefix default +set dhcp6-pd-preferred=yes +/ipv6 nd proxy +add disabled=yes interface=lo +/ipv6 nd settings +set router-advertisement-route-distance=100 +/routing bfd configuration +add addresses=10.8.0.0/24 disabled=no forbid-bfd=yes interfaces=*E min-rx=\ + 200ms min-tx=200ms multiplier=5 vrf=main +/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 +/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/MikroNUC/20260620/20260620004001-Binary.backup b/MikroNUC/20260620/20260620004001-Binary.backup new file mode 100644 index 0000000000000000000000000000000000000000..df451ed813291f79f06c252d2d3acffe611d1b9a GIT binary patch literal 363887 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 >^mQQ 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

I=3q?$fWEY$4#CbiX^i*mEyj3dmv|$Ir0yS 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

}9b)V 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 %gQ9^)k40o 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�W1VNXsej*&8DF*cEki9dsH$)SA|HOQ7V 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

YL<6;XqH+ z*O^hj4}}gINooP!Kp^DNWzQ9>0ng5K!LAqe=gi%8+b<_tGVZR;ilFuNA$DXA^(4HVHPXGOFM^Y~#%uyl#qf*g;Y`HHNUVNxny^LQYmc2<*E zxYw`RB?lBvEnXUY9}M=$6PxUVa|Q*H@AyTKSJxNJ3u89FWzG4 zA|F;6`!^P#Cznpjx(beuD6Oh}_2n>>kp{4{)g>mNz_2;+ZTvBbL( zUTi0nu(EMN0J~YUxtoG__h;BOF>`jq?zSoiqk=g*WMCyD8)2uGCNkuBgh7|I;hCNoS3m(NCF$Y<)2@!xcr6KU0$mgg= z4PTznEQwfKyEn34Ui+!u+~RUm1-)%;*`2%~H}KWc%8U`jV-52WUS+ARrgeAL@|Aen z&Oh65ON~s4Qj0WMLed@N#3?M;bl*1BQFwjCfA73{P77c?}r!r0@AZ4?bxS z5g{ih;-p?D@jlxV5SAW>!7ik%w=X>xTh7@o264Lq51GA0^wnuz>wy`ixz*L9>~_t? zxLKABfh~1WU*fITjGUf9$ZTP|78=M$6**Hc@r;io27j*Pjx=V+UKWNr)A_|&|EB|j z6CzvHJk(Q?u~$7Oyei)Ë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 literal 0 HcmV?d00001 diff --git a/MikroNUC/20260620/20260620004001-Config.rsc b/MikroNUC/20260620/20260620004001-Config.rsc new file mode 100644 index 0000000..5bf08d6 --- /dev/null +++ b/MikroNUC/20260620/20260620004001-Config.rsc @@ -0,0 +1,4880 @@ +# 2026-06-20 00:40:01 by RouterOS 7.23.1 +# system id = NmJcEM+8XAP +# +/caps-man channel +add band=2ghz-g/n extension-channel=disabled frequency=2422 name=2G-3 \ + reselect-interval=20m save-selected=yes +add band=5ghz-a/n/ac extension-channel=XXXX frequency=5660 name=5G-5660 \ + save-selected=yes +add band=5ghz-a/n/ac extension-channel=XXXXXXXX frequency=5160,5200,5280 \ + name=5G-5160-5280 reselect-interval=30m save-selected=yes +add band=5ghz-n/ac extension-channel=XXXX frequency=5180 name=5G-36 \ + reselect-interval=30m save-selected=yes +add band=5ghz-n/ac extension-channel=XXXX frequency=5200 name=5G-40 \ + reselect-interval=30m save-selected=yes +add band=5ghz-n/ac extension-channel=XXXX frequency=5220 name=5G-44 \ + reselect-interval=30m save-selected=yes +add band=5ghz-n/ac extension-channel=XXXX frequency=5240 name=5G-48 \ + reselect-interval=30m save-selected=yes +add band=2ghz-g/n extension-channel=disabled frequency=2442 name=2G-7 \ + reselect-interval=20m save-selected=yes +add band=2ghz-g/n extension-channel=disabled frequency=2462 name=2G-11 \ + reselect-interval=20m save-selected=yes +/interface bridge +add name=Bridge-DOC +add name=Bridge-LAN port-cost-mode=short +/interface ethernet +set [ find default-name=ether1 ] disable-running-check=no name=ether2 +/interface veth +add address=172.18.20.2/30 container-mac-address=00:00:00:00:00:00 dhcp=no \ + gateway=172.18.20.1 gateway6="" name=docker-awg-veth +add address=172.18.20.6/30 container-mac-address=00:00:00:00:00:00 dhcp=no \ + gateway=172.18.20.5 gateway6="" name=docker-xray-vless-veth +add address=10.10.10.10/24 container-mac-address=5C:26:FE:05:6F:12 dhcp=no \ + gateway=10.10.10.1 gateway6="" mac-address=5C:26:FE:05:6F:11 name=veth1 +/caps-man datapath +add bridge=Bridge-LAN client-to-client-forwarding=yes local-forwarding=yes \ + name=xs-DataPath +add bridge=Bridge-LAN client-to-client-forwarding=yes local-forwarding=yes \ + name=DataPath +/caps-man security +add authentication-types=wpa2-psk encryption=aes-ccm group-encryption=aes-ccm \ + group-key-update=30m name=xs-Sec +add authentication-types=wpa2-psk encryption=aes-ccm group-encryption=aes-ccm \ + group-key-update=30m name=WPA2 +/caps-man configuration +add channel.band=2ghz-b/g/n country=no_country_set datapath=xs-DataPath mode=\ + ap name=xs-2G rx-chains=0,1,2,3 security=xs-Sec ssid=vados tx-chains=\ + 0,1,2,3 +add channel.band=5ghz-a/n/ac country=no_country_set datapath=xs-DataPath \ + installation=any mode=ap name=xs-5G rx-chains=0,1,2,3 security=xs-Sec \ + ssid=vados5g tx-chains=0,1,2,3 +add channel.band=2ghz-b/g/n .control-channel-width=20mhz .extension-channel=\ + XX .frequency=2422,2442,2462 .reselect-interval=20m country=belarus \ + datapath=DataPath datapath.client-to-client-forwarding=yes \ + .local-forwarding=yes hw-protection-mode=rts-cts installation=any name=2G \ + rx-chains=0,1,2,3 security=WPA2 ssid=vados tx-chains=0,1,2,3 +add channel.band=5ghz-a/n/ac .control-channel-width=20mhz .extension-channel=\ + XXXX .frequency=5180,5200,5220,5240,5260 .reselect-interval=20m \ + .skip-dfs-channels=yes country=belarus datapath=DataPath \ + datapath.client-to-client-forwarding=yes .local-forwarding=yes \ + hw-protection-mode=rts-cts installation=any name=5G security=WPA2 ssid=\ + vados5g +/disk +add slot=ram tmpfs-max-size=100000000 type=tmpfs +add slot=tmpfs tmpfs-max-size=715827882 type=tmpfs +/interface list +add include=dynamic,static name=LAN +add exclude=LAN name=WAN +add exclude=LAN include=WAN name=Internet +/interface wireless security-profiles +set [ find default=yes ] supplicant-identity=MikroMIC +/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=P1505n 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 +/ip pool +add name=dhcp ranges=10.30.30.150-10.30.30.200 +/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 dont-require-permissions=no name=test owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + \r\ + \n#:local ScriptName [ :jobname ];\r\ + \n:local expSrc;\r\ + \n:local FileName;\r\ + \n:local FilePath;\r\ + \n:local DirPath \"tmpfs/\";\r\ + \n:global WaitForFile;\r\ + \n:global IfThenElse;\r\ + \n\r\ + \n:foreach Script in=([ /system/script find where name~\"Amster-GlobalConf\ + *\" ]) do={\r\ + \n:local ScriptVal [ /system/script/get \$Script ];\r\ + \n\r\ + \n:local expName [ (\$ScriptVal->\"name\") ];\r\ + \n#[/system/script get \$expScript name];\r\ + \n:delay 2s;\r\ + \n\r\ + \n:set expSrc [/system/script print where name=\$expName];\r\ + \n/system/script print where name=\$expName;\r\ + \n#[:put [/system/script get \$expScript source]];\r\ + \n:put [\$expSrc];\r\ + \n:delay 2s;\r\ + \n:set FileName \$expName;\r\ + \n:set FilePath (\$DirPath . \$FileName);\r\ + \n\r\ + \n#:log warning \"\\n----------------------\\n\\\$expSrc = \$expSrc\\n____\ + ______________________________\";\r\ + \n:log info \"\\n\\\$FileName = '\$FileName'\";\r\ + \n:log info \"\\n\\\$FilePath = \$FilePath\";\r\ + \n#:log warning {/system/script/get source=[/system/script/get \$expScript\ + \_source];};\r\ + \n\r\ + \n#\$[/system script get [/system script find name=\"\$FileName\"] source]\ + \r\ + \n\r\ + \n#:local gettingScript \"\$FileName\";\r\ + \n#:execute script=\"[[:parse \\\"[:parse { :put (\"\$[/system script get \ + [/system script find name=\$FileName] source]\"); } \\\"]]\"; \\\r\ + \n\r\ + \n#:execute script={:put \"[:parse \\\"[:parse [/system/script get [/syste\ + m/script find name=\$gettingScript] source];\\\"]]\";} \\\r\ + \n# file=(\$FilePath . \".rsc\\00\");\r\ + \n:do {\r\ + \n:local fName (\$FilePath . \".rsc\");\r\ + \n#:delay 3s;\r\ + \n#/file add name=\$fName;\r\ + \n:put [:tostr [\$expSrc]];\r\ + \n/file set \$fName contents=[:put [\$expSrc]];\r\ + \n:delay 3s;\r\ + \n\$WaitForFile \$fName;\r\ + \n(\$FilePath . \".rsc\");\r\ + \n#:delay 2s;\r\ + \n\r\ + \n} on-error={\r\ + \n:log error \"\\nERROR \\\$FilePath = \$FilePath\";\r\ + \n}\r\ + \n#\$WaitForFile (\$FilePath . \".rsc\");\r\ + \n#:execute script={ :put [/system/script get [:put \$FileName] source]; }\ + ;\r\ + \n#/system/script export \$Sscript file=\$FilePath;\r\ + \n#/system/script/export [:put [/system/script/get \$expScript source]] fi\ + le=\$FilePath;\r\ + \n#:execute script={ :put [/system/script/get \$expScript source]; } \\\r\ + \n\r\ + \n#:log warning \"\\n\\\$expScript = \$expScript\";\r\ + \n# \\\r\ + \n# file=(\$FilePath . \".rsc\\00\");\r\ + \n#script={:put [/system/script/get \$FileName source];} file=(\$FilePath\ + \_. \".rsc\\00\");\r\ + \n#/system script export \$src file=(\$FilePath . \$FileName);\r\ + \n}\r\ + \n\r\ + \n:log warning \"\\nComplete!\";\r\ + \n\r\ + \n # :execute script={ :put [ /system/script/get Amster-GlobalConfig sou\ + rce ]; } \\\r\ + \n # file=(\$FilePath . \".conf\\00\");\r\ + \n # \$WaitForFile (\$FilePath . \".conf\");\r\ + \n # :onerror Err {\r\ + \n # /tool/fetch upload=yes url=(\$BackupUploadUrl . \"/\" . \$FileName\ + \_. \".conf\") \\\r\ + \n # user=\$BackupUploadUser password=\$BackupUploadPass src-path=(\ + \$FilePath . \".conf\");\r\ + \n # :set ConfigFile [ /file/get (\$FilePath . \".conf\") ];\r\ + \n # :set (\$ConfigFile->\"name\") (\$FileName . \".conf\");\r\ + \n " +add dont-require-permissions=no name=test1 owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="\ + \r\ + \n#:local runningVer [:find [/system/resource/get version] \"(\"];\r\ + \n\r\ + \n:local runningChannel;\r\ + \n:local runningVersion;\r\ + \n:local ParseCustom;\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\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:global runningChannel [\$ParseCustom [/system/resource/get version] \"(\ + \" \")\" 1];\r\ + \n:log warning [\$runningChannel];\r\ + \n:set runningVersion [\$ParseCustom [/system/resource/get version] \" \" \ + \")\" 2];\r\ + \n:log warning [\$runningVersion];\r\ + \n\r\ + \n\r\ + \n\r\ + \n# :if ([:len \$open] = 0) do={\r\ + \n# :log error \"\$SMP Could not extract installed OS channel from vers\ + ion string: `\$runningOsAndChannel`.\";\r\ + \n# :error \"\$SMP error, check logs\";\r\ + \n# }\r\ + \n# :local rest [:pick \$runningOsAndChannel (\$open+1) [:len \$runningOs\ + AndChannel]];\r\ + \n# :local close [:find \$rest \")\"];\r\ + \n# :local channel [:pick \$rest 0 \$close];\r\ + \n# :return \$channel;\r\ + \n#}" +add dont-require-permissions=no name=01-Amster-Init-Script owner=vados \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + source="# Amster Initial Script\r\ + \n#\r\ + \n#:global GlobalEnvRemove true; /system/script {run Amster-GlobalEnvRemov\ + e; };\r\ + \n#:delay 1s;\r\ + \n:#global ReloadGlobal true; \r\ + \n\r\ + \n:global AmScriptsUrl \"https://ros.vados.ru/\";\r\ + \n:global defOwner \"vados\";\r\ + \n:global AmFirstRun;\r\ + \n\r\ + \n:set AmFirstRun do={\r\ + \n :global AmScriptsUrl;\r\ + \n :global defOwner;\r\ + \n #:global ParseKeyValueStore;\r\ + \n #:local AmUpdCRLF true;\r\ + \n #:local IfThenElse;\r\ + \n #:set IfThenElse do={:if ([ :tostr \$1 ] = \"true\" || [ :tobool \$1\ + \_] = true) do={:return \$2}; :return \$3}\r\ + \n #/certificate/settings/set builtin-trust-store=fetch;\r\ + \n #/tool/fetch \"\$scriptsUrl/certs/Root-YE.pem\" dst-path=\"root-ye.p\ + em\";\r\ + \n #/certificate/import file-name=\"root-ye.pem\" passphrase=\"\";\r\ + \n # For basic verification we rename the certificate and print it by f\ + ingerprint. Make sure exactly this one certificate (\"Root-YE\") is shown.\ + \r\ + \n #/certificate/set name=\"Root-YE\" [ find where common-name=\"Root Y\ + E\" ];\r\ + \n #/certificate/print proplist=name,fingerprint where fingerprint=\"e1\ + 4ffcad5b0025731006caa43a121a22d8e9700f4fb9cf852f02a708aa5d5666\";\r\ + \n #:log info \"\\nAmScriptsUrl = \$AmScriptsUrl\";\r\ + \n :local Scripts {\r\ + \n \"Amster-GlobalConfig\"\r\ + \n \"Amster-GlobalFunc\";\r\ + \n# \"Amster-SFTP-backup\"\r\ + \n# \"Amster-BkpEmail-and-upd\";\r\ + \n };\r\ + \n# /system/script/set owner=(\$ScriptVal->\"name\") \\\r\ + \n# source=[ \$IfThenElse (\$ScriptUpdatesCRLF = true) \$SourceCRLF \$S\ + ourceNew ] \$Script;\r\ + \n :foreach Script in=\$Scripts do={\r\ + \n :put \"Installing \$Script...\";\r\ + \n /system/script/remove [ find where name=\$Script ];\r\ + \n /system/script/add name=\$Script owner=\$defOwner source=([ /too\ + l/fetch (\"\$AmScriptsUrl\" . \$Script . \".rsc\") output=user as-value ]-\ + >\"data\");\r\ + \n /system/script/set source=[ :tocrlf [ get \$Script source ] ] \$\ + Script;\r\ + \n };\r\ + \n /system/script { run Amster-GlobalConfig; run Amster-GlobalFunc; }\r\ + \n}\r\ + \n:global AmUpdRun;\r\ + \n:set AmUpdRun do={\r\ + \n #:local UpdScript [ :tostr \$1 ];\r\ + \n #:global ParseKeyValueStore;\r\ + \n :global AmScriptsUrl;\r\ + \n :global defOwner;\r\ + \n :local Scripts {\r\ + \n# \"Amster-GlobalConfig\"\r\ + \n# \"Amster-GlobalFunc\"\r\ + \n# \"Amster-GlobalRemove\"\r\ + \n \"Amster-backup-SFTP\"\r\ + \n \"Amster-SFTP-backup\"\r\ + \n \"Amster-BkpEmail-and-upd\"\r\ + \n \"Amster-TG-Bot\"\r\ + \n \"Amster-TG-Notification\";\r\ + \n };\r\ + \n :foreach Script in=\$Scripts do={\r\ + \n :put \"updating \$Script...\";\r\ + \n /system/script/remove [ find where name=\$Script ];\r\ + \n /system/script/add name=\$Script owner=\$defOwner source=([ /too\ + l/fetch (\"\$AmScriptsUrl\" . \$Script . \".rsc\") output=user as-value ]-\ + >\"data\");\r\ + \n /system/script/set source=[ :tocrlf [ get \$Script source ] ] \$\ + Script;\r\ + \n };\r\ + \n# /system/script/add name=\$Script owner=\$AmOwner source=([ /tool/fe\ + tch check-certificate=yes-without-crl (\"\$AmScriptsUrl\" . \$Script . \".\ + rsc\") output=user as-value ]->\"data\"); };\r\ + \n}\r\ + \n\r\ + \n\$AmFirstRun;\r\ + \n#\$AmUpdRun;\r\ + \n\r\ + \n#\$setUpdExist;\r\ + \n#:global setUpdExist;\r\ + \n#:global ParseKeyValueStore;\r\ + \n#:set setUpdExist do={\r\ + \n#:do {\r\ + \n#:global ParseKeyValueStore;\r\ + \n# :foreach Script in=[ /system/script/find where source~\"^#!rsc by Vad\ + os\\r\?\\n#comment=*\" ] do={\r\ + \n# :local ScriptVal [ /system/script/get \$Script ];\r\ + \n# :local ScriptInfo [ \$ParseKeyValueStore (\$ScriptVal->\"#comment\"\ + ) ];\r\ + \n# :local scriptName (\$ScriptVal->\"name\");\r\ + \n#:log warning (\"\\n\\\$scriptName = \". \$scriptName);\r\ + \n#: log warning (\"\\n\\\$ScriptInfo = \". \$ScriptInfo);\r\ + \n# }\r\ + \n#} on-error={}\r\ + \n#}\r\ + \n#\$name;\$owner;\$policy;\$dont-require-permissions;\$last-started;\$run\ + -count;\$source;\$invalid;\$comment;\$.id;\$.nextid;\$.dead;\$.about;\r\ + \n#;(evl / (evl /docommand=;(evl / (evl /foreachcounter=\$Script;do=;(evl \ + / (evl /localname=\$ScriptVal;value=(evl (evl /system/script/getnumber=\$S\ + cript))) (evl /localname=\$ScriptInfo;value=(evl (<%% \$ParseKeyValueStore\ + \_(> \$ParseKeyValueStore);(-> \$ScriptVal comment)))) (evl /localname=\$s\ + criptName) (evl /setname=\$scriptName;value=(-> #\$ScriptVal name)) (evl /\ + log/errormessage=(. \r\ + \n# \$ ScriptInfo = \$ScriptInfo)));in=(evl (evl /system/script/findwhere\ + =\$name;\$owner;\$policy;\$dont-require-permissions;\$last-started;\$run-c\ + ount;\$source;\$invalid;\$comment;\$.id;\$.nextid;\$.dead;\$.about;(~ \$so\ + urce (. ^#!rsc by Vados \r\ + \n# \? \r\ + \n#));5))));on-error=;(evl /)))\r\ + \n" +add dont-require-permissions=no name="Download cAP's Packages" owner=vados \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + source="# +------------------------------+\r\ + \n# | |\r\ + \n# | Mikrotik RouterOS Scripts |\r\ + \n# | _Download cAP's Packages_ |\r\ + \n# | |\r\ + \n# +------------------------------+\r\ + \n# https://github.com/sebastian13/mikrotik-routeros-scripts\r\ + \n#\r\ + \n\r\ + \n# Set a directory path providing the required space\r\ + \n# Add a microSD card https://wiki.mikrotik.com/wiki/Manual:System/Disks\ + \r\ + \n# or setup a RAM-Disk via '/disk/add type=tmpfs tmpfs-max-size=20M slot=\ + ram'\r\ + \n:local dir \"/tmpfs/capsman-packages\";\r\ + \n\r\ + \n\r\ + \n# Set Package Path if required, set policy to none if using 'upgrade-cap\ + s' script\r\ + \n/interface/wifi/capsman/set package-path=\$dir upgrade-policy=none;\r\ + \n/caps-man/manager/set package-path=\$dir upgrade-policy=none;\r\ + \n#require-same-version;\r\ + \n\r\ + \n:local installed [/system package get value-name=version [find where nam\ + e=\"routeros\"]]\r\ + \n\r\ + \n# Delete old downloads\r\ + \n# /file/remove [ find type=package name~\"capsman*\" ]\r\ + \n\r\ + \n# Starting from RouterOS version 7.13, drivers for older wireless and 60\ + GHz interfaces are\r\ + \n# part of the separate \"wireless\" package. The existing \"wifiwave2\" \ + package has been divided\r\ + \n# into distinct packages: \"wifi-qcom\" and \"wifi-qcom-ac\".\r\ + \n# RouterOS >=7.12 is required to upgrade to 7.13.\r\ + \n# https://forum.mikrotik.com/viewtopic.php\?t=202423\r\ + \n\r\ + \n:foreach architecture in={ \"arm\";\r\ + \n# \"arm64\";\r\ + \n \"x86_64\";\r\ + \n \"mipsbe\"} do={\r\ + \n :foreach package in={ \"routeros\";\r\ + \n# \"wifi-qcom-ac\";\r\ + \n# \"wifi-qcom\";\r\ + \n \"container\";\r\ + \n \"wireless\"} do={ :do {\r\ + \n :put \"\"\r\ + \n :put \"Download \$package \$installed for \$architecture\"\r\ + \n /tool fetch mode=https \\\r\ + \n url=\"https://download.mikrotik.com/routeros/\$installed/\$packa\ + ge-\$installed-\$architecture.npk\" \\\r\ + \n dst-path=\"\$dir/\$package-\$installed-\$architecture.npk\"\r\ + \n } on-error={ :put \"Error downloading the file. On a 404, note t\ + hat the package may not exist for the specified architecture!\" }\r\ + \n }\r\ + \n}\r\ + \n" +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/694/a1b071a6\";\r\ + \n:global CommitTAG \"unknown\";\r\ + \n:global CommitInfo \"Autocommit in repo: ros.vados.ru, generated by owne\ + r: root, in 13:30:04 15.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 dont-require-permissions=no name=fetchCustom owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + \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\";\r\ + \n#\r\ + \n#root.mnuc.backuper\r\ + \n\r\ + \n#/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@1\ + 0.30.30.81.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.81.pub\";\r\ + \n#:local Script AM-GlobalConfig;\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#/usb1/mikro_bak_rsa.pub\r\ + \n#:local FetchFile AM-DOHCert.rsc\r\ + \n\r\ + \n:global GlobalScriptsUrl \"https://ros.vados.ru/tmp/\";\r\ + \n:global MkDir;\r\ + \n\r\ + \n:local FetchFile Binary.backup\r\ + \n:local localDir \"[usb1]/scripts/\";\r\ + \n\r\ + \n\$MkDir \$localDir;\r\ + \n\r\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \$FetchFile) dst-path=(\ + \$localDir . \$FetchFile);\r\ + \n" +add dont-require-permissions=yes name=MkTmpfs owner=vados policy=\ + ftp,read,write,policy,test,sniff,sensitive source=\ + ":global MkDir;\r\ + \n\r\ + \n\$MkDir /usb1/tmpfs;" +add dont-require-permissions=no name=CreateContainer owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + local contIF \"veth1\";\r\ + \n:local contIP \"10.10.10.10/24\";\r\ + \n:local contGW \"10.10.10.1\";\r\ + \n#/interface/veth/add name=\$contIF address=\$contIP gateway=\$contGW;\r\ + \n:local contBridgeIF \"Bridge-DOC\";\r\ + \n:local contBridgeIP \"10.10.10.1/24\";\r\ + \n/interface/bridge/add name=\$contBridgeIF;\r\ + \n/ip/address/add address=\$contBridgeIP interface=\$contBridgeIF;\r\ + \n/interface/bridge/port/add bridge=\$contBridgeIF interface=\$contIF;\r\ + \n/container/config/set ram-high=768M registry-url=https://registry-1.dock\ + er.io tmpdir=sata1/tmp\r\ + \n" +add dont-require-permissions=no name=carkeeperbot owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="/\ + container/mounts/add list=carkeeper_configs/.profile src=sata1/carkeeper/c\ + onfigs/.profile dst=/root/.ashrc;\r\ + \n/container/mounts/add list=carkeeper_configs/php.ini src=sata1/carkeeper\ + /configs/php.ini dst=/etc/php82/php.ini;\r\ + \n#/container/mounts/add list=carkeeper_configs src=sata1/carkeeper/config\ + s dst=/configs;\r\ + \n/container/mounts/add list=carkeeper_app src=sata1/carkeeper/app dst=/ap\ + p;\r\ + \n/container/mounts/add list=carkeeper_scripts src=sata1/carkeeper/scripts\ + \_dst=/scripts;\r\ + \n/container/mounts/add list=carkeeper_configs/sshd_config src=sata1/carke\ + eper/configs/sshd_config dst=/etc/ssh/sshd_config;\r\ + \n\r\ + \n/container/mounts/add list=carkeeper_tmp src=sata1/carkeeper/tmp dst=/va\ + r/tmp;\r\ + \n/container/mounts/add list=carkeeper_sync src=sata1/carkeeper/sync dst=/\ + var/sync;\r\ + \n" +add comment="Enable or disable ip addresses based on bridge port state" \ + dont-require-permissions=no name=mod/AM-IPbridge owner=mod/AM-IPbridge \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + source="#!rsc by Vados\r\ + \n# RouterOS script: mod/AM-IPbridge\r\ + \n# Script comment: Enable or disable ip addresses based on bridge port st\ + ate\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# Add this Script scheduler\r\ + \n:if ([ :len [ /system/scheduler/find where name=\$ScriptName ] ] = 0) do\ + ={\r\ + \n:log warning (\"SystemScheduler for script: \" . \$ScriptName . \" is NO\ + T SET! Fix It Now!\");\r\ + \n:local OnEvent \"/system/script/run \$ScriptName;\";\r\ + \n:local Comment \"Every Day Check For Fake Bridges\";\r\ + \n/system/scheduler/add name=\$ScriptName comment=\$Comment start-time=sta\ + rtup interval=1d on-event=\$OnEvent;\r\ + \n}\r\ + \n\r\ + \n:foreach Bridge in=[ /interface/bridge/find ] do={\r\ + \n :local BrName [ /interface/bridge/get \$Bridge name ];\r\ + \n :if ([ :len [ /interface/bridge/port/find where bridge=\$BrName ] ] > \ + 0) do={\r\ + \n :if ([ :len [ /interface/bridge/port/find where bridge=\$BrName and \ + inactive=no ] ] = 0) do={\r\ + \n /ip/address/disable [ find where !dynamic interface=\$BrName ];\r\ + \n } else={\r\ + \n /ip/address/enable [ find where !dynamic interface=\$BrName ];\r\ + \n }\r\ + \n }\r\ + \n}\r\ + \n" +add comment="Use Telegram to chat with your Router and send commands" \ + dont-require-permissions=no name=mod/AM-TG-Bot owner=mod/AM-TG-Bot \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + source="#!rsc by Vados\r\ + \n# RouterOS script: mod/AM-TG-Bot\r\ + \n# Script comment: Use Telegram to chat with your Router and send command\ + s\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:local ExitOK false;\r\ + \n:onerror Err {\r\ + \n :global GlobalConfReady; :global GlobalFuncReady;\r\ + \n :retry { :if (\$GlobalConfReady != true || \$GlobalFuncReady != true) \ + \\\r\ + \n do={ :error (\"Global config and/or functions not ready.\"); }; } \ + delay=500ms max=50;\r\ + \n :local ScriptName [ :jobname ];\r\ + \n\r\ + \n :global Identity;\r\ + \n :global TelegramChatActive;\r\ + \n :global TelegramChatGroups;\r\ + \n :global TelegramChatId;\r\ + \n :global TelegramChatIdsTrusted;\r\ + \n :global TelegramChatOffset;\r\ + \n :global TelegramChatRunTime;\r\ + \n :global TelegramMessageIDs;\r\ + \n :global TelegramRandomDelay;\r\ + \n :global TelegramTokenId;\r\ + \n\r\ + \n :global CertificateAvailable;\r\ + \n :global EitherOr;\r\ + \n :global EscapeForRegEx;\r\ + \n :global FileExists;\r\ + \n :global GetRandom20CharAlNum;\r\ + \n :global IfThenElse;\r\ + \n :global LogPrint;\r\ + \n :global LogPrintVerbose;\r\ + \n :global MAX;\r\ + \n :global MIN;\r\ + \n :global MkDir;\r\ + \n :global RandomDelay;\r\ + \n :global RmDir;\r\ + \n :global ScriptLock;\r\ + \n :global SendTelegram2;\r\ + \n :global SymbolForNotification;\r\ + \n :global ValidateSyntax;\r\ + \n :global WaitForFile;\r\ + \n :global WaitFullyConnected;\r\ + \n\r\ + \n :if ([ \$ScriptLock \$ScriptName ] = false) do={\r\ + \n :set ExitOK true;\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n \$WaitFullyConnected;\r\ + \n\r\ + \n :if ([ :len [ /system/scheduler/find where name=\$ScriptName ] ] = 0) \ + do={\r\ + \n /system/scheduler/add start-time=startup interval=30s name=\$ScriptN\ + ame on-event=\"/system/script/run \$ScriptName;\" comment=\"Telegram Chat \ + Bot\";\r\ + \n }\r\ + \n :if ([ :typeof \$TelegramChatOffset ] != \"array\") do={\r\ + \n :set TelegramChatOffset { 0; 0; 0 };\r\ + \n }\r\ + \n :if ([ :typeof \$TelegramRandomDelay ] != \"num\") do={\r\ + \n :set TelegramRandomDelay 0;\r\ + \n }\r\ + \n\r\ + \n :if ([ \$CertificateAvailable \"Go Daddy Root Certificate Authority - \ + G2\" \"fetch\" ] = false) do={\r\ + \n \$LogPrint warning \$ScriptName (\"Downloading required certificate \ + failed.\");\r\ + \n :set ExitOK true;\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n \$RandomDelay \$TelegramRandomDelay;\r\ + \n\r\ + \n :local Data false;\r\ + \n :for I from=1 to=4 do={\r\ + \n :if (\$Data = false) do={\r\ + \n :onerror Err {\r\ + \n :set Data ([ /tool/fetch check-certificate=yes-without-crl outpu\ + t=user \\\r\ + \n (\"https://api.telegram.org/bot\" . \$TelegramTokenId . \"/get\ + Updates\?offset=\" . \\\r\ + \n \$TelegramChatOffset->0 . \"&allowed_updates=%5B%22message%22%\ + 5D\") as-value ]->\"data\");\r\ + \n :set TelegramRandomDelay [ \$MAX 0 (\$TelegramRandomDelay - 1) ]\ + ;\r\ + \n } do={\r\ + \n :if (\$I < 4) do={\r\ + \n \$LogPrint debug \$ScriptName (\"Fetch failed, \" . \$I . \". \ + try: \" . \$Err);\r\ + \n :set TelegramRandomDelay [ \$MIN 15 (\$TelegramRandomDelay + 5\ + ) ];\r\ + \n :delay ((\$I * \$I) . \"s\");\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :if (\$Data = false) do={\r\ + \n \$LogPrint warning \$ScriptName (\"Failed getting updates.\");\r\ + \n :set ExitOK true;\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :local JSON [ :deserialize from=json value=\$Data ];\r\ + \n :local UpdateID 0;\r\ + \n :local Uptime [ /system/resource/get uptime ];\r\ + \n :foreach Update in=(\$JSON->\"result\") do={\r\ + \n :set UpdateID (\$Update->\"update_id\");\r\ + \n \$LogPrintVerbose debug \$ScriptName (\"Update \" . \$UpdateID . \":\ + \_\" . [ :serialize to=json \$Update ]);\r\ + \n\r\ + \n :local Message (\$Update->\"message\");\r\ + \n :local IsAnyReply ([ :typeof (\$Message->\"reply_to_message\") ] = \ + \"array\");\r\ + \n :local IsMyReply (\$TelegramMessageIDs->[ :tostr (\$Message->\"reply\ + _to_message\"->\"message_id\") ]);\r\ + \n :if ((\$IsMyReply = 1 || \$TelegramChatOffset->0 > 0 || \$Uptime > 5\ + m) && \$UpdateID >= \$TelegramChatOffset->2) do={\r\ + \n :local Trusted false;\r\ + \n :local Chat (\$Message->\"chat\");\r\ + \n :local From (\$Message->\"from\");\r\ + \n :local Command (\$Message->\"text\");\r\ + \n :local ThreadId [ \$IfThenElse (\$Message->\"is_topic_message\") (\ + \$Message->\"message_thread_id\") \"\" ];\r\ + \n\r\ + \n :foreach IdsTrusted in=(\$TelegramChatId, \$TelegramChatIdsTrusted\ + ) do={\r\ + \n :if (\$From->\"id\" = \$IdsTrusted || \\\r\ + \n \$From->\"username\" = \$IdsTrusted || \\\r\ + \n \$Chat->\"id\" = \$IdsTrusted) do={\r\ + \n :set Trusted true;\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :if (\$Trusted = true) do={\r\ + \n :local Done false;\r\ + \n :if (\$Command = \"\?\") do={\r\ + \n \$LogPrint info \$ScriptName (\"Sending notice for update \" .\ + \_\$UpdateID . \".\");\r\ + \n \$SendTelegram2 ({ origin=\$ScriptName; chatid=(\$Chat->\"id\"\ + ); silent=true; \\\r\ + \n replyto=(\$Message->\"message_id\"); threadid=\$ThreadId; \\\ + \r\ + \n subject=([ \$SymbolForNotification \"speech-balloon\" ] . \"\ + Telegram Chat\"); \\\r\ + \n message=([ \$IfThenElse ([ :len (\$From->\"first_name\") ] >\ + \_0) (\"Hello \" . (\$From->\"first_name\") . \"!\\n\\n\") ] . \\\r\ + \n \"Online\" . [ \$IfThenElse \$TelegramChatActive \" (and a\ + ctive!)\" ] . \", awaiting your commands!\") });\r\ + \n :set Done true;\r\ + \n }\r\ + \n :if (\$Done = false && [ :pick \$Command 0 1 ] = \"!\") do={\r\ + \n :if (\$Command ~ (\"^! *(\" . [ \$EscapeForRegEx \$Identity ] \ + . \"|@\" . \$TelegramChatGroups . \")\\\$\")) do={\r\ + \n :set TelegramChatActive true;\r\ + \n } else={\r\ + \n :set TelegramChatActive false;\r\ + \n }\r\ + \n \$LogPrint info \$ScriptName (\"Now \" . [ \$IfThenElse \$Tele\ + gramChatActive \"active\" \"passive\" ] . \\\r\ + \n \" from update \" . \$UpdateID . \"!\");\r\ + \n :set Done true;\r\ + \n }\r\ + \n :if (\$Done = false && (\$IsMyReply = 1 || (\$IsAnyReply = false\ + \_&& \\\r\ + \n \$TelegramChatActive = true)) && [ :len \$Command ] > 0) do\ + ={\r\ + \n :if ([ \$ValidateSyntax \$Command ] = true) do={\r\ + \n :local State \"\";\r\ + \n :local File (\"tmpfs/telegram-chat/\" . [ \$GetRandom20CharA\ + lNum 6 ]);\r\ + \n :if ([ \$MkDir \"tmpfs/telegram-chat\" ] = false) do={\r\ + \n \$LogPrint error \$ScriptName (\"Failed creating directory\ + !\");\r\ + \n :set ExitOK true;\r\ + \n :error false;\r\ + \n }\r\ + \n \$LogPrint info \$ScriptName (\"Running command from update \ + \" . \$UpdateID . \": \" . \$Command);\r\ + \n :execute script=(\":do {\\n\" . \$Command . \"\\n} on-error=\ + { /file/add name=\\\"\" . \$File . \".failed\\\" };\" . \\\r\ + \n \"/file/add name=\\\"\" . \$File . \".done\\\"\") file=(\$\ + File . \"\\00\");\r\ + \n :if ([ \$WaitForFile (\$File . \".done\") [ \$EitherOr \$Tel\ + egramChatRunTime 20s ] ] = false) do={\r\ + \n :set State ([ \$SymbolForNotification \"warning-sign\" ] .\ + \_\"The command did not finish, still running in background.\\n\\n\");\r\ + \n }\r\ + \n :if ([ \$FileExists (\$File . \".failed\") ] = true) do={\r\ + \n :set State ([ \$SymbolForNotification \"cross-mark\" ] . \ + \"The command failed with an error!\\n\\n\");\r\ + \n }\r\ + \n :local Content ([ /file/read chunk-size=32768 file=\$File as\ + -value ]->\"data\");\r\ + \n \$SendTelegram2 ({ origin=\$ScriptName; chatid=(\$Chat->\"id\ + \"); silent=true; \\\r\ + \n replyto=(\$Message->\"message_id\"); threadid=\$ThreadId; \ + \\\r\ + \n subject=([ \$SymbolForNotification \"speech-balloon\" ] . \ + \"Telegram Chat\"); \\\r\ + \n message=([ \$SymbolForNotification \"gear\" ] . \"Command:\ + \\n\" . \$Command . \"\\n\\n\" . \\\r\ + \n \$State . [ \$IfThenElse ([ :len \$Content ] > 0) \\\r\ + \n ([ \$SymbolForNotification \"memo\" ] . \"Output:\\n\" .\ + \_\$Content) \\\r\ + \n ([ \$SymbolForNotification \"memo\" ] . \"No output.\") \ + ]) });\r\ + \n \$RmDir \"tmpfs/telegram-chat\";\r\ + \n } else={\r\ + \n \$LogPrint info \$ScriptName (\"The command from update \" .\ + \_\$UpdateID . \" failed syntax validation!\");\r\ + \n \$SendTelegram2 ({ origin=\$ScriptName; chatid=(\$Chat->\"id\ + \"); silent=false; \\\r\ + \n replyto=(\$Message->\"message_id\"); threadid=\$ThreadId; \ + \\\r\ + \n subject=([ \$SymbolForNotification \"speech-balloon\" ] . \ + \"Telegram Chat\"); \\\r\ + \n message=([ \$SymbolForNotification \"gear\" ] . \"Command:\ + \\n\" . \$Command . \"\\n\\n\" . \\\r\ + \n [ \$SymbolForNotification \"cross-mark\" ] . \"The comma\ + nd failed syntax validation!\") });\r\ + \n }\r\ + \n }\r\ + \n } else={\r\ + \n :local MessageText (\"Received a message from untrusted contact \ + \" . \\\r\ + \n [ \$IfThenElse ([ :len (\$From->\"username\") ] = 0) \"without\ + \_username\" (\"'\" . \$From->\"username\" . \"'\") ] . \\\r\ + \n \" (ID \" . \$From->\"id\" . \") in update \" . \$UpdateID . \ + \"!\");\r\ + \n :if (\$Command ~ (\"^! *\" . [ \$EscapeForRegEx \$Identity ] . \ + \"\\\$\")) do={\r\ + \n \$LogPrint warning \$ScriptName \$MessageText;\r\ + \n \$SendTelegram2 ({ origin=\$ScriptName; chatid=(\$Chat->\"id\"\ + ); silent=false; \\\r\ + \n replyto=(\$Message->\"message_id\"); threadid=\$ThreadId; \\\ + \r\ + \n subject=([ \$SymbolForNotification \"speech-balloon\" ] . \"\ + Telegram Chat\"); \\\r\ + \n message=(\"You are not trusted.\") });\r\ + \n } else={\r\ + \n \$LogPrint info \$ScriptName \$MessageText;\r\ + \n }\r\ + \n }\r\ + \n } else={\r\ + \n \$LogPrint debug \$ScriptName (\"Already handled update \" . \$Upd\ + ateID . \".\");\r\ + \n }\r\ + \n }\r\ + \n :set TelegramChatOffset ([ :pick \$TelegramChatOffset 1 3 ], \\\r\ + \n [ \$IfThenElse (\$UpdateID >= \$TelegramChatOffset->2) (\$UpdateID +\ + \_1) (\$TelegramChatOffset->2) ]);\r\ + \n} do={\r\ + \n :global ExitError; \$ExitError \$ExitOK [ :jobname ] \$Err;\r\ + \n}\r\ + \n" +add comment="Script send Notifications in Telegram" dont-require-permissions=\ + no name=mod/AM-TG-Notifications owner=mod/AM-TG-Notifications policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\r\ + \n# RouterOS script: mod/AM-TG-Notifications\r\ + \n# Script comment: Script send Notifications in Telegram\r\ + \n# Copyright (c) 2007-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version=7.19\r\ + \n# requires device-mode, fetch, scheduler\r\ + \n:global FlushTelegramQueue;\r\ + \n:global GetTelegramChatId;\r\ + \n:global NotificationFunctions;\r\ + \n:global PurgeTelegramQueue;\r\ + \n:global SendTelegram;\r\ + \n:global SendTelegram2;\r\ + \n# flush telegram queue\r\ + \n:set FlushTelegramQueue do={ :onerror Err {\r\ + \n :global TelegramQueue;\r\ + \n :global TelegramMessageIDs;\r\ + \n :global CertificateAvailable;\r\ + \n :global IsFullyConnected;\r\ + \n :global LogPrint;\r\ + \n :if ([ \$IsFullyConnected ] = false) do={\r\ + \n \$LogPrint debug \$0 (\"System is not fully connected, not flushing.\ + \");\r\ + \n :return false;\r\ + \n }\r\ + \n :if ([ \$CertificateAvailable \"Go Daddy Root Certificate Authority - \ + G2\" \"fetch\" ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Downloading required certificate failed.\"\ + );\r\ + \n :return false;\r\ + \n }\r\ + \n :local AllDone true;\r\ + \n :local QueueLen [ :len \$TelegramQueue ];\r\ + \n :if ([ :len [ /system/scheduler/find where name=\"_FlushTelegramQueue\ + \" ] ] > 0 && \$QueueLen = 0) do={\r\ + \n \$LogPrint warning \$0 (\"Flushing Telegram messages from scheduler,\ + \_but queue is empty.\");\r\ + \n }\r\ + \n :foreach Id,Message in=\$TelegramQueue do={\r\ + \n :if ([ :typeof \$Message ] = \"array\" ) do={\r\ + \n :onerror Err {\r\ + \n :local Data ([ /tool/fetch check-certificate=yes-without-crl out\ + put=user http-method=post \\\r\ + \n (\"https://api.telegram.org/bot\" . (\$Message->\"tokenid\") .\ + \_\"/sendMessage\") \\\r\ + \n http-data=(\$Message->\"http-data\") as-value ]->\"data\");\r\ + \n :set (\$TelegramQueue->\$Id);\r\ + \n :set (\$TelegramMessageIDs->[ :tostr ([ :deserialize from=json v\ + alue=\$Data ]->\"result\"->\"message_id\") ]) 1;\r\ + \n } do={\r\ + \n \$LogPrint debug \$0 (\"Sending queued Telegram message failed: \ + \" . \$Err);\r\ + \n :set AllDone false;\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n :if (\$AllDone = true && \$QueueLen = [ :len \$TelegramQueue ]) do={\r\ + \n /system/scheduler/remove [ find where name=\"_FlushTelegramQueue\" ]\ + ;\r\ + \n :set TelegramQueue;\r\ + \n }\r\ + \n} do={\r\ + \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ + \n} }\r\ + \n# get the chat id\r\ + \n:set GetTelegramChatId do={ :onerror Err {\r\ + \n :global TelegramTokenId;\r\ + \n :global CertificateAvailable;\r\ + \n :global LogPrint;\r\ + \n :if ([ \$CertificateAvailable \"Go Daddy Root Certificate Authority - \ + G2\" \"fetch\" ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Downloading required certificate failed.\"\ + );\r\ + \n :return false;\r\ + \n }\r\ + \n :local Data;\r\ + \n :onerror Err {\r\ + \n :set Data ([ /tool/fetch check-certificate=yes-without-crl output=us\ + er \\\r\ + \n (\"https://api.telegram.org/bot\" . \$TelegramTokenId . \"/getUpd\ + ates\?offset=0\" . \\\r\ + \n \"&allowed_updates=%5B%22message%22%5D\") as-value ]->\"data\");\ + \r\ + \n } do={\r\ + \n \$LogPrint warning \$0 (\"Fetching data failed: \" . \$Err);\r\ + \n :return false;\r\ + \n }\r\ + \n :local JSON [ :deserialize from=json value=\$Data ];\r\ + \n :local Count [ :len (\$JSON->\"result\") ];\r\ + \n :if (\$Count = 0) do={\r\ + \n \$LogPrint info \$0 (\"No message received.\");\r\ + \n :return false;\r\ + \n }\r\ + \n :local Message (\$JSON->\"result\"->(\$Count - 1)->\"message\");\r\ + \n \$LogPrint info \$0 (\"The chat id is: \" . (\$Message->\"chat\"->\"id\ + \"));\r\ + \n :if ((\$Message->\"is_topic_message\") = true) do={\r\ + \n \$LogPrint info \$0 (\"The thread id is: \" . (\$Message->\"message_\ + thread_id\"));\r\ + \n }\r\ + \n} do={\r\ + \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ + \n} }\r\ + \n# send notification via telegram - expects one array argument\r\ + \n:set (\$NotificationFunctions->\"telegram\") do={\r\ + \n :local Notification \$1;\r\ + \n :global Identity;\r\ + \n :global IdentityExtra;\r\ + \n :global TelegramChatId;\r\ + \n :global TelegramChatIdOverride;\r\ + \n :global TelegramMessageIDs;\r\ + \n :global TelegramQueue;\r\ + \n :global TelegramThreadId;\r\ + \n :global TelegramThreadIdOverride;\r\ + \n :global TelegramTokenId;\r\ + \n :global TelegramTokenIdOverride;\r\ + \n :global CertificateAvailable;\r\ + \n :global CharacterReplace;\r\ + \n :global EitherOr;\r\ + \n :global IfThenElse;\r\ + \n :global LogPrint;\r\ + \n :global ProtocolStrip;\r\ + \n :global SymbolForNotification;\r\ + \n :global UrlEncode;\r\ + \n :local EscapeMD do={\r\ + \n :local Text [ :tostr \$1 ];\r\ + \n :local Mode [ :tostr \$2 ];\r\ + \n :local Excl [ :tostr \$3 ];\r\ + \n :global CharacterReplace;\r\ + \n :global IfThenElse;\r\ + \n :local Chars {\r\ + \n \"body\"={ \"\\\\\"; \"`\" };\r\ + \n \"plain\"={ \"_\"; \"*\"; \"[\"; \"]\"; \"(\"; \")\"; \"~\"; \"`\"\ + ; \">\";\r\ + \n \"#\"; \"+\"; \"-\"; \"=\"; \"|\"; \"{\"; \"}\"; \".\"; \ + \"!\" };\r\ + \n }\r\ + \n :foreach Char in=(\$Chars->\$Mode) do={\r\ + \n :if ([ :typeof [ :find \$Excl \$Char ] ] = \"nil\") do={\r\ + \n :set Text [ \$CharacterReplace \$Text \$Char (\"\\\\\" . \$Char)\ + \_];\r\ + \n }\r\ + \n }\r\ + \n :if (\$Mode = \"body\") do={:return (\"```\\n\" . \$Text . \"\\n```\ + \")}\r\ + \n :return \$Text;\r\ + \n }\r\ + \n :local ChatId [ \$EitherOr (\$Notification->\"chatid\") \\\r\ + \n [ \$EitherOr (\$TelegramChatIdOverride->(\$Notification->\"origin\")\ + ) \$TelegramChatId ] ];\r\ + \n :local ThreadId [ \$EitherOr (\$Notification->\"threadid\") \\\r\ + \n [ \$EitherOr (\$TelegramThreadIdOverride->(\$Notification->\"origin\ + \")) \\\r\ + \n [ \$IfThenElse ([ :len (\$TelegramChatIdOverride->(\$Notification->\ + \"origin\")) ] = 0) \$TelegramThreadId ] ] ];\r\ + \n :local TokenId [ \$EitherOr (\$TelegramTokenIdOverride->(\$Notificatio\ + n->\"origin\")) \$TelegramTokenId ];\r\ + \n :if ([ :len \$TokenId ] = 0 || [ :len \$ChatId ] = 0) do={:return fals\ + e}\r\ + \n :if ([ :typeof \$TelegramMessageIDs ] = \"nothing\") do={:set Telegram\ + MessageIDs ({})}\r\ + \n :local Truncated false;\r\ + \n :local Text (\"*__\" . [ \$EscapeMD (\"[\" . \$IdentityExtra . \$Ident\ + ity . \"] \" . \\\r\ + \n (\$Notification->\"subject\")) \"plain\" ] . \"__*\\n\\n\");\r\ + \n :local LenSubject [ :len \$Text ];\r\ + \n :local LenMessage [ :len (\$Notification->\"message\") ];\r\ + \n :local LenLink ([ :len (\$Notification->\"link\") ] * 2);\r\ + \n :local LenSum (\$LenSubject + \$LenMessage + \$LenLink);\r\ + \n :if (\$LenSum > 3968) do={\r\ + \n :set Text (\$Text . [ \$EscapeMD ([ :pick (\$Notification->\"message\ + \") 0 (3840 - \$LenSubject - \$LenLink) ] . \"...\") \"body\" ]);\r\ + \n :set Truncated true;\r\ + \n } else={:set Text (\$Text . [ \$EscapeMD (\$Notification->\"message\")\ + \_\"body\" ])}\r\ + \n :if (\$LenLink > 0) do={\r\ + \n :set Text (\$Text . \"\\n\" . [ \$SymbolForNotification \"link\" ] .\ + \_\\\r\ + \n \"[\" . [ \$EscapeMD [ \$ProtocolStrip (\$Notification->\"link\") \ + ] \"plain\" ] . \"]\" . \\\r\ + \n \"(\" . [ \$EscapeMD (\$Notification->\"link\") \"plain\" ] . \")\ + \");\r\ + \n }\r\ + \n :if (\$Truncated = true) do={\r\ + \n :set Text (\$Text . \"\\n\" . [ \$SymbolForNotification \"scissors\"\ + \_] . \\\r\ + \n [ \$EscapeMD (\"The message was too long and has been truncated, c\ + ut off _\" . \\\r\ + \n ((\$LenSum - [ :len \$Text ]) * 100 / \$LenSum) . \"%_!\") \"plain\ + \" \"_\" ]);\r\ + \n }\r\ + \n :local HTTPData (\"chat_id=\" . \$ChatId . \"&disable_notification=\" \ + . (\$Notification->\"silent\") . \\\r\ + \n \"&reply_to_message_id=\" . (\$Notification->\"replyto\") . \"&mes\ + sage_thread_id=\" . \$ThreadId . \\\r\ + \n \"&disable_web_page_preview=true&parse_mode=MarkdownV2\");\r\ + \n :onerror Err {\r\ + \n :if ([ \$CertificateAvailable \"Go Daddy Root Certificate Authority \ + - G2\" \"fetch\" ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Downloading required certificate failed.\ + \");\r\ + \n :error false;\r\ + \n }\r\ + \n :local Data ([ /tool/fetch check-certificate=yes-without-crl output=\ + user http-method=post \\\r\ + \n (\"https://api.telegram.org/bot\" . \$TokenId . \"/sendMessage\") \ + \\\r\ + \n http-data=(\$HTTPData . \"&text=\" . [ \$UrlEncode \$Text ]) as-va\ + lue ]->\"data\");\r\ + \n :set (\$TelegramMessageIDs->[ :tostr ([ :deserialize from=json value\ + =\$Data ]->\"result\"->\"message_id\") ]) 1;\r\ + \n } do={\r\ + \n \$LogPrint info \$0 (\"Failed sending Telegram notification: \" . \$\ + Err . \" - Queuing...\");\r\ + \n :if ([ :typeof \$TelegramQueue ] = \"nothing\") do={:set TelegramQue\ + ue ({})}\r\ + \n :set Text (\$Text . \"\\n\" . [ \$SymbolForNotification \"alarm-cloc\ + k\" ] . \\\r\ + \n [ \$EscapeMD (\"This message was queued since _\" . [ /system/cloc\ + k/get date ] . \\\r\ + \n \" \" . [ /system/clock/get time ] . \"_ and may be obsolete.\") \ + \"plain\" \"_\" ]);\r\ + \n :set (\$TelegramQueue->[ :len \$TelegramQueue ]) { tokenid=\$TokenId\ + ;\r\ + \n http-data=(\$HTTPData . \"&text=\" . [ \$UrlEncode \$Text ]) };\r\ + \n :if ([ :len [ /system/scheduler/find where name=\"_FlushTelegramQueu\ + e\" ] ] = 0) do={\r\ + \n /system/scheduler/add name=\"_FlushTelegramQueue\" interval=1m sta\ + rt-time=startup \\\r\ + \n on-event=(\":global FlushTelegramQueue; \\\$FlushTelegramQueue;\ + \");\r\ + \n }\r\ + \n }\r\ + \n}\r\ + \n# purge the Telegram queue\r\ + \n:set PurgeTelegramQueue do={\r\ + \n :global TelegramQueue;\r\ + \n /system/scheduler/remove [ find where name=\"_FlushTelegramQueue\" ];\ + \r\ + \n :set TelegramQueue;\r\ + \n}\r\ + \n# send notification via telegram - expects at least two string arguments\ + \r\ + \n:set SendTelegram do={ :onerror Err {\r\ + \n :global SendTelegram2;\r\ + \n \$SendTelegram2 ({ origin=\$0; subject=\$1; message=\$2; link=\$3; sil\ + ent=\$4 });\r\ + \n} do={\r\ + \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ + \n} }\r\ + \n# send notification via telegram - expects one array argument\r\ + \n:set SendTelegram2 do={\r\ + \n :local Notification \$1;\r\ + \n :global NotificationFunctions;\r\ + \n (\$NotificationFunctions->\"telegram\") (\"\\\$NotificationFunctions->\ + \\\"telegram\\\"\") \$Notification;\r\ + \n}\r\ + \n" +add dont-require-permissions=no name=testIfThenElseAndEitherOr owner=vados \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + source=":local ExitOK false;\r\ + \n:local ScriptName [ :jobname ];\r\ + \n\r\ + \n:local ExitError;\r\ + \n#:local IfThenElse;\r\ + \n#:local EitherOr;\r\ + \n\r\ + \n:local one 11;\r\ + \n:local two 8;\r\ + \n#:log warning ([ \$IfThenElse (\$one != 0) \$one \$two ]);\r\ + \n:local Test; # [ :totime \"22s\" ];\r\ + \n\r\ + \n:local IfThenElse do={:if ([ :tostr \$1 ] = \"true\" || [ :tobool \$1 ] \ + = true) do={:return \$2}; :return \$3;}\r\ + \n:local EitherOr do={\r\ + \n :if ([ :typeof \$1 ] = \"num\") do={:if ((\$1 != 0) = true) do={:retur\ + n \$1} else={:return \$2};}\r\ + \n :if ([ :typeof \$1 ] = \"time\") do={:if ((\$1 > 0s) = true) do={:retu\ + rn \$1} else={:return \$2};}\r\ + \n :if ([ :len [ :tostr \$1 ] ] > 0) do={:return \$1} else={:return \$2};\ + \r\ + \n}\r\ + \n\r\ + \n:log warning ([ \$IfThenElse (\$one != 0) \$one \$two ]);\r\ + \n\r\ + \n:set Test [ \$EitherOr \$Test \"\" ];\r\ + \n:log warning (\"\\\$ Test = \" . \$Test);\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 :local 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\r\ + \n#:log warning ([ \$IfThenElse (\$one != 0) \$one \$two ]);\r\ + \n\r\ + \n:set ExitOK true;\r\ + \n\$ExitError \$ExitOK \$ScriptName \"Err test custom\";" +add comment="Update and Backup send notification to EMail" \ + dont-require-permissions=no name=AM-Backup-UpdateEmail owner=\ + AM-Backup-UpdateEmail policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\r\ + \n# RouterOS script: AM-Backup-UpdateEmail\r\ + \n# Script comment: Update and Backup send notification to EMail\r\ + \n# Copyright (c) 2007-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version>=6.43.7\r\ + \n# requires device-mode, fetch\r\ + \n#\r\ + \n# Updated: 15/04/2025\r\ + \n# Website: https://github.com/beeyev\r\ + \n# Notification e-mail (Make sure you have configured Email settings in T\ + ools -> Email)\r\ + \n:local ExitOK false;\r\ + \n:onerror Err {\r\ + \n :global GlobalConfReady; :global GlobalFuncReady;\r\ + \n :retry { :if (\$GlobalConfReady != true || \$GlobalFuncReady != true) \ + \\\r\ + \n do={ :error (\"Global config and/or functions not ready.\"); }; } \ + delay=500ms max=50;\r\ + \n :local ScriptName [ :jobname ];\r\ + \n\r\ + \n:local IfThenElse do={:if ([ :tostr \$1 ] = \"true\" || [ :tobool \$1 ] \ + = true) do={:return \$2}; :return \$3;}\r\ + \n:local EitherOr do={\r\ + \n :if ([ :typeof \$1 ] = \"num\") do={:if ((\$1 != 0) = true) do={:retur\ + n \$1} else={:return \$2};}\r\ + \n :if ([ :typeof \$1 ] = \"time\") do={:if ((\$1 > 0s) = true) do={:retu\ + rn \$1} else={:return \$2};}\r\ + \n :if ([ :len [ :tostr \$1 ] ] > 0) do={:return \$1} else={:return \$2};\ + \r\ + \n}\r\ + \n:local ExitError do={\r\ + \n :local ExitOK [ :tostr \$1 ];\r\ + \n :local Name [ :tostr \$2 ];\r\ + \n :local Error [ :tostr \$3 ];\r\ + \n :if (\$ExitOK = \"false\") do={:log error (\$Name [ \$IfThenElse ([ :p\ + ick \$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:global LogPrint;\r\ + \n:global EditSchedulers;\r\ + \n:global DevInfoIncludeIP;\r\ + \n\r\ + \n:local SchedInterval \"7d\";\r\ + \n:local SchedStartTime \"03:41:27\";\r\ + \n:local SchedComment \"Every 7 Day Check For Update and Backup send notif\ + ication to EMail.\";\r\ + \n\r\ + \n# Function to add or edit schedulers for scripts, to ensure they are set\ + \_up correctly\r\ + \n# How to use:\r\ + \n# Call this function with the following parameters:\r\ + \n# 1. \$1 - Scheduler name (usually same as script name) [*]\r\ + \n# 2. \$2 - Interval (e.g. \"1d\" (default is \"1d\")) [**]\r\ + \n# 3. \$3 - Start Time (e.g. \"00:00:00\", default is current time) [**]\ + \r\ + \n# 4. \$4 - Comment (optional, default: \"Scheduler for script: \")\ + \_[**]\r\ + \n# 5. \$5 - On Event command (e.g. \"/system/script { run ; }\" (de\ + fault is \"/system/script { run \$SchedName; }\")) [**]\r\ + \n# 6. \$6 - Policy (e.g. \"ftp,reboot,read,write,policy,test,password,sni\ + ff,sensitive,romon\" (default is the same)) [**]\r\ + \n# 7. \$7 - Start Date (e.g. \"jan/01/1970\", default is current date) [*\ + *]\r\ + \n# Notes:\r\ + \n# * - Scheduler name is required, and is used to identify the scheduler\ + \_to create or edit. It is usually the same as the script name (\$ScriptNa\ + me).\r\ + \n# ** - If optional parameters are not provided, default values will be u\ + sed.\r\ + \n# This allows for quick setup with minimal parameters, while still \ + providing flexibility for customization.\r\ + \n# Example usage:\r\ + \n# :if ([ \$EditSchedulers \"my-script\" ] = false) do={:set ExitOK false\ + ; :error true;}\r\ + \n# :if ([ \$EditSchedulers \"my-script\" \"1d\" \"03:41:27\" \"My custom \ + scheduler comment\" false false \"jan/01/1970\" ] = false) do={:set ExitOK\ + \_false; :error true;}\r\ + \n\r\ + \n:set EditSchedulers do={\r\ + \n :local SchedName [ :tostr \$1 ];\r\ + \n :if ([ :len \$SchedName ] = 0) do={ :return false; }\r\ + \n :local Interval [ :tostr \$2 ];\r\ + \n :if ([ :len \$Interval ] = 0) do={ :set Interval \"1d\"; }\r\ + \n :local StartTime [ :tostr \$3 ];\r\ + \n :if ([ :len \$StartTime ] = 0) do={ :set StartTime [/system/clock/get \ + time]; }\r\ + \n :local Comment [ :tostr \$4 ];\r\ + \n :if ([ :len \$Comment ] = 0) do={ :set Comment \"Scheduler for script:\ + \_\$SchedName\"; }\r\ + \n :local OnEvent [ :tostr \$5 ];\r\ + \n :if ([ :len \$OnEvent ] = 0) do={ :set OnEvent \"/system/script { run \ + \$SchedName; }\"; }\r\ + \n :local Policy [ :tostr \$6 ];\r\ + \n :if ([ :len \$Policy ] = 0) do={ :set Policy \"ftp,reboot,read,write,p\ + olicy,test,password,sniff,sensitive,romon\"; }\r\ + \n :local StartDate [ :tostr \$7 ];\r\ + \n :if ([ :len \$StartDate ] = 0) do={ :set StartDate [/system/clock/get \ + date]; }\r\ + \n\r\ + \n :onerror Err {\r\ + \n # Check if scheduler exists, if not - create it\r\ + \n :if ([ :len [ /system/scheduler/find where name=\$SchedName ] ] = 0)\ + \_do={\r\ + \n :log warning (\$SchedName . \"System Scheduler for script: \" . \$\ + SchedName . \" is NOT SET! Fix It Now!\");\r\ + \n /system/scheduler/add comment=\$Comment interval=\$Interval name=\ + \$SchedName on-event=\$OnEvent policy=\$Policy start-date=\$StartDate star\ + t-time=\$StartTime;\r\ + \n }\r\ + \n # Check if scheduler parameters are correct, if not - fix them\r\ + \n :if ([ /system/scheduler/get \$SchedName comment ] != \$Comment) do=\ + {\r\ + \n /system/scheduler/set \$SchedName comment=\$Comment;\r\ + \n }\r\ + \n :if ([ /system/scheduler/get \$SchedName interval ] != \$Interval) d\ + o={\r\ + \n /system/scheduler/set \$SchedName interval=\$Interval;\r\ + \n }\r\ + \n :if ([ /system/scheduler/get \$SchedName on-event ] != \$OnEvent) do\ + ={\r\ + \n /system/scheduler/set \$SchedName on-event=\$OnEvent;\r\ + \n }\r\ + \n :if ([ /system/scheduler/get \$SchedName policy ] != \$Policy) do={\ + \r\ + \n /system/scheduler/set \$SchedName policy=\$Policy;\r\ + \n }\r\ + \n :if ([ /system/scheduler/get \$SchedName start-date ] != \$StartDate\ + ) do={\r\ + \n /system/scheduler/set \$SchedName start-date=\$StartDate;\r\ + \n }\r\ + \n :if ([ /system/scheduler/get \$SchedName start-time ] != \$StartTime\ + ) do={\r\ + \n /system/scheduler/set \$SchedName start-time=\$StartTime;\r\ + \n }\r\ + \n } do={:log error (\$SchedName . \"Failed to add/modify scheduler for '\ + \" . \$SchedName . \"' failed: \" . \$Err); :return false};\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:if ([ \$EditSchedulers \$ScriptName \$SchedInterval \$SchedStartTime \$\ + SchedComment ] = false) do={\r\ + \n :log error (\$ScriptName . \"Failed to add/modify scheduler for \" . \ + \$ScriptName . \"!\");\r\ + \n :set ExitOK true;\r\ + \n :error true;\r\ + \n}\r\ + \n\r\ + \n# Local Function CheckOSUpdateMode\r\ + \n:local CheckOSUpdateMode;\r\ + \n:set CheckOSUpdateMode do={\r\ + \n :local NewMode [ :tostr \$1 ];\r\ + \n :if ([ :len \$NewMode ] = 0) do={\r\ + \n :log error (\$0 . \"/nFunction /\$CheckOSUpdateMode received empty v\ + alue!\");\r\ + \n :return false;\r\ + \n :error true;\r\ + \n }\r\ + \n\r\ + \n :global BackupAndUpdateMode;\r\ + \n :global OldMode [ :tostr \$BackupAndUpdateMode ];\r\ + \n :if (\$NewMode != \$BackupAndUpdateMode && \$NewMode = \"updateOnce\")\ + \_do={\r\ + \n :set BackupAndUpdateMode [ :tostr \$NewMode ];\r\ + \n :log info (\$0 . \"/nOk. /\$BackupAndUpdateMode set to: '\" . \$NewM\ + ode . \"'.\\nYou're a good boy! ))\\nI'm launching the update in 5 seconds\ + .\");\r\ + \n :delay 5;\r\ + \n /system/script { run \$ScriptName; };\r\ + \n } else={\r\ + \n :log warning (\$0 . \"/nFunction /\$CheckOSUpdateMode received value: \ + '\" . \$NewMode . \"', but is may be only \\\"updateOnce\\\"!\");\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n :error false;\r\ + \n}\r\ + \n\r\ + \n# :if ([ :len [ /system/scheduler/find where name=\"running-from-backup\ + -partition\" ] ] > 0) do={\r\ + \n# \$LogPrint warning \$ScriptName (\"Running from backup partition, r\ + efusing to act.\");\r\ + \n# :set ExitOK true;\r\ + \n# :error false;\r\ + \n# }\r\ + \n\r\ + \n:global EmailGeneralTo;\r\ + \n:global BackupAndUpdateMode;\r\ + \n:global forceBackup;\r\ + \n:global BackupPassword;\r\ + \n:global BackupSens;\r\ + \n:global updateChannel;\r\ + \n\r\ + \n:global DevInfoIncludeIP;\r\ + \n\r\ + \n# Installs patch updates only (BackupAndUpdateMode = \"osupdate\").\r\ + \n# Works for `stable` and `long-term` channels.\r\ + \n# Updates only if MAJOR.MINOR match (e.g. 6.43.2 > 6.43.6 allowed, 6.44.\ + 1 skipped).\r\ + \n# Sends info if a newer (non-patch) version is found.\r\ + \n:local installOnlyPatchUpdates false;\r\ + \n:local scriptVersion \"26.04.30\";\r\ + \n:local copyrightUrl \"https://www.github.com/vados-dev/\";\r\ + \n#Script messages prefix\r\ + \n:local SMP \"BkpAndUpdate:\";\r\ + \n\r\ + \n:local exitErrorMessage \"\$SMP script stopped due to an error. Please c\ + heck logs for more details.\";\r\ + \n:log info \"\\n\\n\$SMP Script \\\"Mikrotik RouterOS automatic backup & \ + update\\\" v.\$scriptVersion started.\";\r\ + \n:log info \"\$SMP Script Mode: `\$BackupAndUpdateMode`, Update channel: \ + `\$updateChannel`, Force backup: `\$forceBackup`, Install only patch updat\ + es: `\$installOnlyPatchUpdates`\";\r\ + \n\r\ + \n## vv FUNCTIONS vv ##\r\ + \n:global WaitCheckUpdates; \$WaitCheckUpdates;\r\ + \n:global MiniDateTimeStamp;\r\ + \n:local MDTSFix [\$MiniDateTimeStamp];\r\ + \n:global Identity;\r\ + \n:global IdentityShort;\r\ + \n:global devBoardName;\r\ + \n:global runningVersion;\r\ + \n:global runningChannel;\r\ + \n:global devModel;\r\ + \n:global devRbSerialNumber;\r\ + \n:global ROsVerAvail;\r\ + \n:global PkgUpdStatus;\r\ + \n\r\ + \n# Checks if two RouterOS version strings differ only by the patch versio\ + n\r\ + \n# :put [\$FuncIsPatchUpdateOnly \"6.2.1\" \"6.2.4\"] # Output: true\r\ + \n# :put [\$FuncIsPatchUpdateOnly \"6.2.1\" \"6.3.1\"] # Output: false\r\ + \n:local FuncIsPatchUpdateOnly do={\r\ + \n :local ver1 \$1;\r\ + \n :local ver2 \$2;\r\ + \n # Extract the major and minor components from a version\r\ + \n :local extractMajorMinor do={\r\ + \n :local ver \$1;\r\ + \n :local dot1 [:find \$ver \".\"];\r\ + \n :if (\$dot1 = -1) do={:return \$ver}\r\ + \n :local major [:pick \$ver 0 \$dot1];\r\ + \n :local rest [:pick \$ver (\$dot1 + 1) [:len \$ver]];\r\ + \n :local dot2 [:find \$rest \".\"];\r\ + \n :local minor \$rest;\r\ + \n :if (\$dot2 >= 0) do={:set minor [:pick \$rest 0 \$dot2]}\r\ + \n :return (\$major . \".\" . \$minor);\r\ + \n }\r\ + \n\r\ + \n# Compare the major and minor components of both version strings\r\ + \n:if ([\$extractMajorMinor \$ver1] = [\$extractMajorMinor \$ver2]) do={:r\ + eturn true}\r\ + \n :return false;\r\ + \n}\r\ + \n# Creates backups and returns array of names\r\ + \n# Possible arguments:\r\ + \n# \$1 - file name, without extension\r\ + \n# \$2 - password (optional)\r\ + \n# \$3 - sensitive data in config (optional, default: false)\r\ + \n# Example:\r\ + \n#:put [\$FuncCreateBackups \$backupName]\r\ + \n:local FuncCreateBackups do={\r\ + \n :local backupName [ :tostr \$1 ];\r\ + \n :local BackPass \$2;\r\ + \n :local BackSens \$3;\r\ + \n\r\ + \n #Script messages prefix\r\ + \n :local SMP \"BkpAndUpdate:\";\r\ + \n :local exitErrorMessage \"\$SMP script stopped due to an error. Please\ + \_check logs for more details.\";\r\ + \n :log info (\"\$SMP global function `FuncCreateBackups` started, input:\ + \_`\$backupName`\");\r\ + \n\r\ + \n # validate required parameter: backupName\r\ + \n :if ([:typeof \$backupName] != \"str\" or [:len \$backupName] = 0) do=\ + {\r\ + \n :log error \"\$SMP parameter 'backupName' is required and must be a \ + non-empty string\";\r\ + \n# :log warning \"\$SMP parameter '\\\$backupName' is required and mus\ + t be a non-empty string.\\nI set '\\\$backupName' to 'default-backup'\";\r\ + \n# :set \$backupName \"default-backup\";\r\ + \n :error \$exitErrorMessage;\r\ + \n }\r\ + \n\r\ + \n :local backupFileSys \"\$backupName.backup\";\r\ + \n :local backupFileConfig \"\$backupName.rsc\";\r\ + \n :local backupNames {\$backupFileSys;\$backupFileConfig};\r\ + \n\r\ + \n ## Perform system backup\r\ + \n :if ([:len \$BackPass] = 0) do={\r\ + \n :log info (\"\$SMP starting backup without password, backup name: `\ + \$backupName`\");\r\ + \n /system backup save dont-encrypt=yes name=\$backupName;\r\ + \n } else={\r\ + \n :log info (\"\$SMP starting backup with password, backup name: `\$ba\ + ckupName`\");\r\ + \n /system backup save password=\$BackPass name=\$backupName;\r\ + \n }\r\ + \n :log info (\"\$SMP system backup created: `\$backupFileSys`\");\r\ + \n ## Export config file\r\ + \n :if (\$BackSens = true) do={\r\ + \n :log info (\"\$SMP starting export config with sensitive data, backu\ + p name: `\$backupName`\");\r\ + \n # Since RouterOS v7 it needs to be explicitly set that we want to ex\ + port sensitive data\r\ + \n :if ([:pick [/system resource get version] 0 1] < 7) do={\r\ + \n :execute \"/export compact terse file=\$backupName\";\r\ + \n } else={\r\ + \n :execute \"/export compact show-sensitive terse file=\$backupName\ + \";\r\ + \n }\r\ + \n } else={\r\ + \n :log info (\"\$SMP starting export config without sensitive data, ba\ + ckup name: `\$backupName`\");\r\ + \n /export compact hide-sensitive terse file=\$backupName;\r\ + \n }\r\ + \n :log info (\"\$SMP Config export complete: `\$backupFileConfig`\");\r\ + \n :log info (\"\$SMP Waiting a little to ensure backup files are written\ + \");\r\ + \n :delay 20;\r\ + \n :if ([:len [/file find name=\$backupFileSys]] > 0) do={\r\ + \n :log info (\"\$SMP system backup file successfully saved to the file\ + \_system: `\$backupFileSys`\");\r\ + \n } else={\r\ + \n :log error (\"\$SMP system backup was not created, file does not exi\ + st: `\$backupFileSys`\");\r\ + \n :error \$exitErrorMessage;\r\ + \n }\r\ + \n :if ([:len [/file find name=\$backupFileConfig]] > 0) do={\r\ + \n :log info (\"\$SMP config backup file successfully saved to the file\ + \_system: `\$backupFileConfig`\");\r\ + \n } else={\r\ + \n :log error (\"\$SMP config backup was not created, file does not exi\ + st: `\$backupFileConfig`\");\r\ + \n :error \$exitErrorMessage;\r\ + \n }\r\ + \n :log info (\"\$SMP global function `FuncCreateBackups` finished. Creat\ + ed backups, system: `\$backupFileSys`, config: `\$backupFileConfig`\")\r\ + \n :return \$backupNames;\r\ + \n}\r\ + \n# Sends an email\r\ + \n# Parameters:\r\ + \n# \$1 - to (email address)\r\ + \n# \$2 - subject\r\ + \n# \$3 - body\r\ + \n# \$4 - file attachments (optional; pass \"\" if not needed)\r\ + \n#\r\ + \n# Example:\r\ + \n# \$FuncSendEmailSafe \"admin@domain.com\" \"Backup Done\" \"Backup comp\ + lete.\" \"backup1.backup\"\r\ + \n:local FuncSendEmailSafe do={\r\ + \n :global EmailGeneralTo;\r\ + \n :local emailSubject \$2;\r\ + \n :local emailBody \$3;\r\ + \n :local emailAttachments \$4;\r\ + \n :local SMP \"Bkp&Upd:\";\r\ + \n :local exitErrorMessage \"\$SMP script stopped due to an error. Please\ + \_check logs for more details.\";\r\ + \n :log info \"\$SMP Attempting to send email to `\$EmailGeneralTo`\";\r\ + \n # SAFETY: wait for any previously queued email to finish\r\ + \n :local waitTimeoutPre 60;\r\ + \n :local waitCounterPre 0;\r\ + \n :while (([/tool e-mail get last-status] = \"resolving-dns\" or [/tool \ + e-mail get last-status] = \"in-progress\")) do={\r\ + \n :if (\$waitCounterPre >= \$waitTimeoutPre) do={\r\ + \n :log error \"\$SMP Email send aborted: previous send did not compl\ + ete after \$waitTimeoutPre seconds\";\r\ + \n :error \$exitErrorMessage;\r\ + \n }\r\ + \n :log info \"\$SMP Waiting for previous email to finish (status: \$[/\ + tool e-mail get last-status])...\";\r\ + \n :delay 1; \r\ + \n :set waitCounterPre (\$waitCounterPre + 1);\r\ + \n }\r\ + \n # Send the email\r\ + \n :do {\r\ + \n /tool e-mail send to=\$EmailGeneralTo subject=\$emailSubject body=\$\ + emailBody file=\$emailAttachments;\r\ + \n } on-error={\r\ + \n :log error \"\$SMP Email send command failed to execute. Check logs \ + and verify email settings.\";\r\ + \n :error \$exitErrorMessage;\r\ + \n }\r\ + \n # Wait for send status to change from \"in-progress\" / \"resolving-dn\ + s\"\r\ + \n :local waitTimeout 60;\r\ + \n :local waitCounter 0;\r\ + \n :local emailStatus \"\";\r\ + \n :log info \"\$SMP Waiting for email to be sent, timeout in `\$waitTime\ + out` seconds...\";\r\ + \n :while (\$waitCounter < \$waitTimeout) do={\r\ + \n :set emailStatus [/tool e-mail get last-status];\r\ + \n :if (\$emailStatus != \"in-progress\" and \$emailStatus != \"resolvi\ + ng-dns\") do={\r\ + \n :log info \"\$SMP Email send status received: \$emailStatus\";\r\ + \n # exit loop\r\ + \n :set waitCounter \$waitTimeout;\r\ + \n } else={:delay 1; :set waitCounter (\$waitCounter + 1)}\r\ + \n }\r\ + \n # Final decision based on last status\r\ + \n :if (\$emailStatus = \"succeeded\") do={\r\ + \n :log info \"\$SMP Email successfully sent to `\$EmailGeneralTo`\";\ + \r\ + \n } else={\r\ + \n :log error \"\$SMP Email failed to send. Status: `\$emailStatus`. Ch\ + eck logs for more details and verify email settings.\";\r\ + \n :error \$exitErrorMessage;\r\ + \n }\r\ + \n}\r\ + \n# Global variable to track current update step\r\ + \n# They need to be initialized here first to be available in the script\r\ + \n:global buGlobalVarTargetOsVersion;\r\ + \n:global buGlobalVarScriptStep;\r\ + \n:local scriptStep \$buGlobalVarScriptStep;\r\ + \n:do {\r\ + \n /system/script/environment remove buGlobalVarScriptStep;\r\ + \n} on-error={}\r\ + \n:if ([:len \$scriptStep] = 0) do={\r\ + \n :set scriptStep 1;\r\ + \n}\r\ + \n## ^^ FUNCTIONS ^^ ##\r\ + \n#\r\ + \n# Initial validation\r\ + \n## Check email settings\r\ + \n:if ([:len \$EmailGeneralTo] < 3) do={\r\ + \n :log error (\"\$SMP Parameter `\\\$EmailGeneralTo` is not set, or cont\ + ains invalid value. Script stopped.\");\r\ + \n :error \$exitErrorMessage;\r\ + \n}\r\ + \n# Values will be defined later in the script\r\ + \n:local emailServer \"\";\r\ + \n:local emailFromAddress [/tool e-mail get from];\r\ + \n:log info \"\$SMP Validating email settings...\";\r\ + \n:do {\r\ + \n :set emailServer [/tool e-mail get server];\r\ + \n} on-error={\r\ + \n # This is a workaround for the RouterOS v7.12 and older versions\r\ + \n :set emailServer [/tool e-mail get address];\r\ + \n}\r\ + \n:if (\$emailServer = \"0.0.0.0\") do={\r\ + \n :log error (\"\$SMP Email server address is not correct: `\$emailServe\ + r`, check `Tools -> Email`. Script stopped.\");\r\ + \n :error \$exitErrorMessage;\r\ + \n}\r\ + \n:if ([:len \$emailFromAddress] < 3) do={\r\ + \n :log error (\"\$SMP Email configuration FROM address is not correct: `\ + \$emailFromAddress`, check `Tools -> Email`. Script stopped.\");\r\ + \n :error \$exitErrorMessage;\r\ + \n}\r\ + \n# Script mode validation\r\ + \n:if (\$BackupAndUpdateMode != \"backup\" and \$BackupAndUpdateMode != \"\ + osupdate\" and \$BackupAndUpdateMode != \"updateOnce\" and \$BackupAndUpda\ + teMode != \"osnotify\") do={\r\ + \n :log error (\"\$SMP Script parameter `\\\$BackupAndUpdateMode` is not \ + set, or contains invalid value: `\$BackupAndUpdateMode`. Script stopped.\"\ + );\r\ + \n :error \$exitErrorMessage;\r\ + \n}\r\ + \n# Update channel validation\r\ + \n:if (\$updateChannel != \"stable\" and \$updateChannel != \"long-term\" \ + and \$updateChannel != \"testing\" and \$updateChannel != \"development\")\ + \_do={\r\ + \n :log error (\"\$SMP Script parameter `\\\$updateChannel` is not set, o\ + r contains invalid value: `\$updateChannel`. Script stopped.\");\r\ + \n :error \$exitErrorMessage;\r\ + \n}\r\ + \n# Verify if script is set to install patch updates and if the update cha\ + nnel is valid\r\ + \n:if ((\$BackupAndUpdateMode = \"osupdate\" or \$BackupAndUpdateMode = \"\ + updateOnce\") and \$installOnlyPatchUpdates = true) do={\r\ + \n :if (\$updateChannel != \"stable\" and \$updateChannel != \"long-term\ + \") do={\r\ + \n :log error (\"\$SMP Patch-only updates enabled, but update channel `\ + \$updateChannel` is invalid. Only `stable` and `long-term` are supported. \ + Script stopped\");\r\ + \n :error \$exitErrorMessage;\r\ + \n }\r\ + \n \r\ + \n :if (\$runningChannel != \"stable\" and \$runningChannel != \"long-ter\ + m\") do={\r\ + \n :log error (\"\$SMP Script is set to install only patch updates, but\ + \_the installed RouterOS version is not from `stable` or `long-term` chann\ + el: `\$runningChannel`. Script stopped\");\r\ + \n :error \$exitErrorMessage;\r\ + \n }\r\ + \n}\r\ + \n#\r\ + \n\r\ + \n:local rawTime [/system clock get time];\r\ + \n:local rawDate [/system clock get date];\r\ + \n\r\ + \n:local deviceOsVerAndChannelRunning [/system/resource/get version];\r\ + \n\r\ + \n:local backupNameTemplate (\"backup_v\" . \$runningVersion . \"_\" .\ + \_\$runningChannel . \"_\" . \$MDTSFix);\r\ + \n:local backupNameBeforeUpdate (\$backupNameTemplate . \"_before_update\"\ + );\r\ + \n:local backupNameAfterUpdate (\$backupNameTemplate . \"_after_update\")\ + ;\r\ + \n\r\ + \n## Email body template\r\ + \n:local mailSubjectPrefix \"\$SMP Device - `\$IdentityShort`\";\r\ + \n:local mailBodyCopyright \"Mikrotik RouterOS automatic backup & update \ + (ver. \$scriptVersion) \\n\$copyrightUrl\";\r\ + \n:local changelogUrl \"Check RouterOS changelog: https://mikrotik.com\ + /download/changelogs/\";\r\ + \n:local mailBodyDeviceInfo \"\";\r\ + \n:set mailBodyDeviceInfo (\$mailBodyDeviceInfo . \"Device information:\")\ + ;\r\ + \n:set mailBodyDeviceInfo (\$mailBodyDeviceInfo . \"\\n-------------------\ + --\");\r\ + \n:set mailBodyDeviceInfo (\$mailBodyDeviceInfo . \"\\nName: \$Identity\")\ + ;\r\ + \n:set mailBodyDeviceInfo (\$mailBodyDeviceInfo . \"\\nModel: \$devModel\"\ + );\r\ + \n:set mailBodyDeviceInfo (\$mailBodyDeviceInfo . \"\\nBoard: \$devBoardNa\ + me\");\r\ + \n:set mailBodyDeviceInfo (\$mailBodyDeviceInfo . \"\\nSerial number: \$de\ + vRbSerialNumber\");\r\ + \n:set mailBodyDeviceInfo (\$mailBodyDeviceInfo . \"\\nRouterOS version: v\ + \$deviceOsVerAndChannelRunning\");\r\ + \n:set mailBodyDeviceInfo (\$mailBodyDeviceInfo . \"\\nBuild time: \$[/sys\ + tem/resource/get build-time]\");\r\ + \n:set mailBodyDeviceInfo (\$mailBodyDeviceInfo . \"\\nRouterboard FW Avai\ + lable: \$ROsVerAvail\");\r\ + \n:set mailBodyDeviceInfo (\$mailBodyDeviceInfo . \"\\nDevice date-time: \ + \$rawDate \$rawTime (\$[/system/clock/get time-zone-name ])\");\r\ + \n:set mailBodyDeviceInfo (\$mailBodyDeviceInfo . \"\\nUptime: \$[/system/\ + resource/get uptime]\");\r\ + \n## IP address detection\r\ + \n:if ([ \$DevInfoIncludeIP ] = true) do={\r\ + \n :global GetPubIp;\r\ + \n :local PublicIpAddress [ \$GetPubIp ];\r\ + \n :set mailBodyDeviceInfo (\$mailBodyDeviceInfo . \"\\nPublic IP address\ + : \" . \$PublicIpAddress . \".\");\r\ + \n :log info \"\$SMP Public IP address detected: \$PublicIpAddress\";\r\ + \n} \r\ + \n\r\ + \n:local mailAttachments [:toarray \"\"];\r\ + \n:if (\$scriptStep = 1 or \$scriptStep = 3) do={\r\ + \n :if (\$scriptStep = 3) do={\r\ + \n :log info (\"\$SMP Waiting for one minute before continuing to the f\ + inal step.\");\r\ + \n :delay 1m;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n## STEP 1: Create backups, check for new RouterOS, and send email\r\ + \n## Steps 2\C3\A23 run only if auto-update is enabled and a new version i\ + s available\r\ + \n:if (\$scriptStep = 1) do={\r\ + \n :global BackupPassword;\r\ + \n :global BackupSens;\r\ + \n :local isNewOsUpdateAvailable false;\r\ + \n :local isLatestOsAlreadyInstalled true;\r\ + \n :local isOsNeedsToBeUpdated false;\r\ + \n :local isUpdateCheckSucceeded false;\r\ + \n :local isEmailNeedsToBeSent false;\r\ + \n :local mailSubjectPartAction \"\";\r\ + \n :local mailPtBodyAction \"\";\r\ + \n :local mailPtSubjectBackup \"\";\r\ + \n :local mailPtBodyBackup \"\";\r\ + \n # Checking for new version\r\ + \n :if (\$BackupAndUpdateMode = \"osupdate\" or \$BackupAndUpdateMode = \ + \"osnotify\" or \$BackupAndUpdateMode = \"updateOnce\") do={\r\ + \n :log info (\"\$SMP Setting update channel to `\$updateChannel`\");\r\ + \n /system/package/update/set channel=\$updateChannel;\r\ + \n :log info (\"\$SMP Checking for new RouterOS version. Current instal\ + led version is: `\$runningVersion`\");\r\ + \n \$LogPrint debug \$ScriptName (\"Checking for updates...\");\r\ + \n \r\ + \n# /system/package/update/check-for-updates without-paging as-value;\ + \r\ + \n# /system/package/update check-for-updates;\r\ + \n :delay 5s;\r\ + \n :set PkgUpdStatus [ /system/package/update/get status ];\r\ + \n :if (\$PkgUpdStatus = \"New version is available\") do={\r\ + \n :set ROsVerAvail [/system/package/update/get latest-version];\r\ + \n }\r\ + \n\r\ + \n :if (\$PkgUpdStatus = \"New version is available\") do={\r\ + \n :log info (\"\$SMP New RouterOS version is available: `\$ROsVerAva\ + il`\");\r\ + \n :set isNewOsUpdateAvailable true;\r\ + \n :set isLatestOsAlreadyInstalled false;\r\ + \n :set isUpdateCheckSucceeded true;\r\ + \n :set isEmailNeedsToBeSent true;\r\ + \n :set mailSubjectPartAction \"New RouterOS available\";\r\ + \n :set mailPtBodyAction \"New RouterOS version is available, curren\ + t version: v\$runningVersion, new version: v\$ROsVerAvail. \\n\$changelogU\ + rl\";\r\ + \n } else={\r\ + \n :if (\$PkgUpdStatus = \"System is already up to date\") do={\r\ + \n :log info (\"\$SMP No new RouterOS version is available, the lat\ + est version is already installed: `v\$runningVersion`\");\r\ + \n :set isUpdateCheckSucceeded true;\r\ + \n :set mailSubjectPartAction \"No os update available\";\r\ + \n :set mailPtBodyAction \"No new RouterOS version is available, t\ + he latest version is already installed: `v\$runningVersion`\";\r\ + \n } else={\r\ + \n :log error (\"\$SMP Failed to check for new RouterOS version. Pa\ + ckage check status: `\$PkgUpdStatus`\");\r\ + \n :set isEmailNeedsToBeSent true;\r\ + \n :set mailSubjectPartAction \"Error unable to check new os versio\ + n\";\r\ + \n :set mailPtBodyAction \"An error occurred while checking for a \ + new RouterOS version.\\nStatus returned: `\$PkgUpdStatus`\\n\\nPlease revi\ + ew the logs on the device for more details and verify internet connectivit\ + y.\";\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n # Checking if the script needs to install new os version\r\ + \n :if ((\$BackupAndUpdateMode = \"osupdate\" or \$BackupAndUpdateMode = \ + \"updateOnce\") and \$isNewOsUpdateAvailable = true) do={\r\ + \n :if (\$installOnlyPatchUpdates = true) do={\r\ + \n :if ([\$FuncIsPatchUpdateOnly \$runningVersion \$ROsVerAvail] = tr\ + ue) do={\r\ + \n :log info \"\$SMP New RouterOS version is available, and it is a\ + \_patch update. Current version: v\$runningVersion, new version: v\$ROsVer\ + Avail\";\r\ + \n :set isOsNeedsToBeUpdated true;\r\ + \n } else={\r\ + \n :log info \"\$SMP The script will not install this update, becau\ + se it is not a patch update. Current version: v\$runningVersion, new versi\ + on: v\$ROsVerAvail\";\r\ + \n :set mailPtBodyAction (\$mailPtBodyAction . \"\\nThis update wil\ + l not be installed, because the script is set to install only patch update\ + s.\");\r\ + \n }\r\ + \n } else={\r\ + \n :set isOsNeedsToBeUpdated true;\r\ + \n }\r\ + \n }\r\ + \n # Checking If the script needs to create a backup\r\ + \n :if (\$forceBackup = true or \$BackupAndUpdateMode = \"backup\" or \$i\ + sOsNeedsToBeUpdated = true) do={\r\ + \n :log info (\"\$SMP Starting backup process.\");\r\ + \n :set isEmailNeedsToBeSent true;\r\ + \n :local backupName \$backupNameTemplate;\r\ + \n # This means it's the first step where we create a backup before the\ + \_update process\r\ + \n :if (\$isOsNeedsToBeUpdated = true) do={\r\ + \n :set backupName \$backupNameBeforeUpdate;\r\ + \n #Email body if the purpose of the script is to update the device\r\ + \n :set mailSubjectPartAction \"Update preparation\";\r\ + \n :set mailPtBodyAction (\$mailPtBodyAction . \"\\nThe update proces\ + s for device '\$Identity' is scheduled to upgrade RouterOS from version v.\ + \$runningVersion to version v.\$ROsVerAvail (Update channel: \$updateChann\ + el)\");\r\ + \n :set mailPtBodyAction (\$mailPtBodyAction . \"\\nPlease note: The \ + update will proceed only after a successful backup.\");\r\ + \n :set mailPtBodyAction (\$mailPtBodyAction . \"\\nA final report wi\ + th detailed information will be sent once the update process is completed.\ + \");\r\ + \n :set mailPtBodyAction (\$mailPtBodyAction . \"\\nIf you do not rec\ + eive a second email within the next 10 minutes, there may be an issue. Ple\ + ase check your device logs for further information.\");\r\ + \n }\r\ + \n :do {\r\ + \n :set mailAttachments [\$FuncCreateBackups \$backupName \$BackupPas\ + sword \$BackupSens];\r\ + \n :set mailPtSubjectBackup \"Backup created\";\r\ + \n :set mailPtBodyBackup \"System backups have been successfully crea\ + ted and attached to this email.\";\r\ + \n } on-error={\r\ + \n :set isOsNeedsToBeUpdated false;\r\ + \n :set mailPtSubjectBackup \"Backup failed\";\r\ + \n :set mailPtBodyBackup \"The script failed to create backups. Pleas\ + e check device logs for more details.\";\r\ + \n :log warning \"\$SMP Backup creation failed. Update process will b\ + e canceled if automatic update is enabled\";\r\ + \n }\r\ + \n }\r\ + \n :if (\$isEmailNeedsToBeSent = true) do={\r\ + \n :log info \"\$SMP Preparing to send email...\";\r\ + \n :local mailStep1Subject \$mailSubjectPrefix;\r\ + \n :local mailStep1Body \"\";\r\ + \n # subject\r\ + \n :if (\$mailSubjectPartAction != \"\") do={:set mailStep1Subject (\$\ + mailStep1Subject . \" - \" . \$mailSubjectPartAction)}\r\ + \n :if (\$mailPtSubjectBackup != \"\") do={:set mailStep1Subject (\$ma\ + ilStep1Subject . \" - \" . \$mailPtSubjectBackup)}\r\ + \n # body\r\ + \n :if (\$mailPtBodyAction != \"\") do={:set mailStep1Body (\$mailStep1\ + Body . \$mailPtBodyAction . \"\\n\\n\")}\r\ + \n :if (\$mailPtBodyBackup != \"\") do={:set mailStep1Body (\$mailStep1\ + Body . \$mailPtBodyBackup . \"\\n\\n\")}\r\ + \n :set mailStep1Body (\$mailStep1Body . \$mailBodyDeviceInfo . \"\\n__\ + ________\\n\" . \$mailBodyCopyright);\r\ + \n :set mailStep1Body (\$mailStep1Body . \"\\n[*** TEST START ***]\\n\\\ + \$DeviceInfo: \" . [ \$DeviceInfo ] . \"\\n[*** TEST END ***]\\n\");\r\ + \n # Send email with backups\r\ + \n :do {\$FuncSendEmailSafe \$EmailGeneralTo \$mailStep1Subject \$mailS\ + tep1Body \$mailAttachments} on-error={\r\ + \n :set isOsNeedsToBeUpdated false;\r\ + \n :log error \"\$SMP The script will not proceed with the update pro\ + cess, because the email was not sent.\";\r\ + \n }\r\ + \n }\r\ + \n :if ([:len \$mailAttachments] > 0) do={\r\ + \n :log info \"\$SMP Cleaning up backup files from the file system...\"\ + ;\r\ + \n /file remove \$mailAttachments;\r\ + \n :delay 2s;\r\ + \n }\r\ + \n :if (\$isOsNeedsToBeUpdated = true) do={\r\ + \n :global OldMode;\r\ + \n :log info \"\$SMP everything is ready to install new RouterOS, going\ + \_to start the update process and reboot the device.\";\r\ + \n :do {\r\ + \n :local nextStep 2;\r\ + \n :if (\$isCloudHostedRouter = true) do={\r\ + \n :log info \"\$SMP The device is a cloud hosted router, the secon\ + d step updating the Routerboard firmware will be skipped.\";\r\ + \n :set nextStep 3;\r\ + \n }\r\ + \n :local scheduledCommand (\":delay 5s; /system/scheduler remove BKP\ + UPD-NEXT-BOOT-TASK; \\\r\ + \n :global buGlobalVarScriptStep \$nextStep; :global buGlobalVarTarg\ + etOsVersion \\\"\$ROsVerAvail\\\"; \\\r\ + \n :delay 10s; /system/script { run \$ScriptName; }\");\r\ + \n /system/scheduler add name=BKPUPD-NEXT-BOOT-TASK on-event=\$schedu\ + ledCommand start-time=startup interval=0;\r\ + \n /system/package/update install;\r\ + \n } on-error={\r\ + \n # Failed to install new os version, remove the task and variables\ + \r\ + \n :do {\r\ + \n /system/scheduler remove BKPUPD-NEXT-BOOT-TASK;\r\ + \n :set BackupAndUpdateMode \$OldMode;\r\ + \n :delay 2;\r\ + \n :do {\r\ + \n :global buGlobalVarTargetOsVersion (a);\r\ + \n } on-error={\r\ + \n :set \$mailSubjectPrefix (\$mailSubjectPrefix . \"ERROR Remove\ + \_global variable \\\$buGlobalVarTargetOsVersion failed!\");\r\ + \n }\r\ + \n# :if ([ :len \$OldMode ] > 0) do={\r\ + \n# :do {\r\ + \n# :global OldMode (a);\r\ + \n# } on-error={\r\ + \n# :set \$mailSubjectPrefix (\$mailSubjectPrefix . \" ERROR Re\ + move global variable \\\$OldMode failed!\");\r\ + \n# }\r\ + \n# }\r\ + \n } on-error={\r\ + \n :log error \"\$SMP Failed to install new RouterOS version. Pleas\ + e check device logs for more details. \\\r\ + \n \\nAnd Failed to remove task and variables! Check it!\";\r\ + \n :set \$mailSubjectPrefix (\$mailSubjectPrefix . \" ERROR Remove \ + task and global variables!\");\r\ + \n }\r\ + \n :log error \"\$SMP Failed to install new RouterOS version. Please \ + check device logs for more details.\";\r\ + \n :local mailUpdateErrorSubject (\$mailSubjectPrefix . \" - Update f\ + ailed\");\r\ + \n :local mailUpdateErrorBody \"The script was unable to install new \ + RouterOS version. Please check device logs for more details.\";\r\ + \n # Send email with error\r\ + \n \$FuncSendEmailSafe \$EmailGeneralTo \$mailUpdateErrorSubject \$ma\ + ilUpdateErrorBody \"\";\r\ + \n :error \$exitErrorMessage;\r\ + \n }\r\ + \n }\r\ + \n}\r\ + \n## STEP 2: (Post-reboot) Upgrade RouterBOARD firmware\r\ + \n## Runs only if auto-update is enabled and a new RouterOS version was fo\ + und\r\ + \n:if (\$scriptStep = 2) do={\r\ + \n :log info \"\$SMP The script is in the second step, updating Routerboa\ + rd firmware.\";\r\ + \n :log info \"\$SMP Upgrading routerboard firmware from v.\$deviceRbCurr\ + entFw to v.\$deviceRbUpgradeFw\";\r\ + \n /system routerboard upgrade;\r\ + \n :delay 2;\r\ + \n :log info \"\$SMP routerboard upgrade process was completed, going to \ + reboot in a moment!\";\r\ + \n ## Set task to send final report on the next boot\r\ + \n /system scheduler add name=BKPUPD-NEXT-BOOT-TASK on-event=\":delay 2; \ + :global buGlobalVarScriptStep 3; \\\r\ + \n :global buGlobalVarTargetOsVersion \\\"\$buGlobalVarTargetOsVersion\\\ + \"; :delay 10s; /system/script { run \$ScriptName; }; \\ \r\ + \n :delay 5s; /system/scheduler remove BKPUPD-NEXT-BOOT-TASK;\" start-ti\ + me=startup interval=0;\r\ + \n :delay 2;\r\ + \n /system reboot;\r\ + \n}\r\ + \n\r\ + \n## STEP 3: Final report (after second reboot, with delay).\r\ + \n## Runs only if auto-update is enabled and a new RouterOS version was fo\ + und.\r\ + \n:if (\$scriptStep = 3) do={\r\ + \n :log info (\"\$SMP The script is in the third step, sending final repo\ + rt.\");\r\ + \n :local targetOsVersion \$buGlobalVarTargetOsVersion;\r\ + \n :do {\r\ + \n# /system/script/environment remove [find name=\"buGlobalVarTargetOsV\ + ersion\"];\r\ + \n :global buGlobalVarTargetOsVersion (a);\r\ + \n } on-error={\r\ + \n :set \$mailSubjectPrefix (\$mailSubjectPrefix . \" ERROR Remove glob\ + al variable \\\$buGlobalVarTargetOsVersion failed!\");\r\ + \n }\r\ + \n\r\ + \n :if ([ :len \$OldMode ] != 0) do={\r\ + \n :do {\r\ + \n# /system/script/environment remove [find name=\"OldMode\"];\r\ + \n :global OldMode (a);\r\ + \n } on-error={\r\ + \n :set \$mailSubjectPrefix (\$mailSubjectPrefix . \" ERROR! Remove\ + \_global variable \\\$OldMode failed!\");\r\ + \n }\r\ + \n }\r\ + \n :if ([:len \$targetOsVersion] = 0) do={\r\ + \n :log warning \"\$SMP Something is wrong, the script was unable to ge\ + t the target updated OS version from the global variable.\";\r\ + \n }\r\ + \n :local mailStep3Subject \$mailSubjectPrefix;\r\ + \n :local mailStep3Body \"\";\r\ + \n :if (\$targetOsVersion = \$runningVersion) do={\r\ + \n :log info \"\$SMP Successfully verified new RouterOS version: target\ + : `\$targetOsVersion`, current: `\$runningVersion`\";\r\ + \n :set mailStep3Subject (\$mailStep3Subject . \" - Update completed - \ + Backup created\");\r\ + \n :set mailStep3Body (\$mailStep3Body . \"RouterOS and routerboard upg\ + rade process was completed\");\r\ + \n :set mailStep3Body (\$mailStep3Body . \"\\nNew RouterOS version: v.\ + \$targetOsVersion, routerboard firmware: v.\$deviceRbCurrentFw\");\r\ + \n :set mailStep3Body (\$mailStep3Body . \"\\n\$changelogUrl\\nBackups \ + of the upgraded system are in the attachment of this email.\\n\\n\$mailBod\ + yDeviceInfo\\n\\n\$mailBodyCopyright\");\r\ + \n :set mailAttachments [\$FuncCreateBackups \$backupNameAfterUpdate \$\ + BackupPassword \$BackupSens];\r\ + \n } else={\r\ + \n :log error \"\$SMP Failed to verify new RouterOS version: target: `\ + \$targetOsVersion`, current: `\$runningVersion`\";\r\ + \n :set mailStep3Subject (\$mailStep3Subject . \" - Update failed\");\r\ + \n :set mailStep3Body (\$mailStep3Body . \"The script was unable to ver\ + ify that the new RouterOS version was installed, target version: `\$target\ + OsVersion`, current version: `\$runningVersion`\\nCheck device logs for mo\ + re details.\\n\\n\$mailBodyDeviceInfo\\n\\n\$mailBodyCopyright\");\r\ + \n }\r\ + \n \$FuncSendEmailSafe \$EmailGeneralTo \$mailStep3Subject \$mailStep3Bod\ + y \$mailAttachments;\r\ + \n :if ([:len \$mailAttachments] > 0) do={\r\ + \n :log info \"\$SMP Cleaning up backup files from the file system...\"\ + ;\r\ + \n /file remove \$mailAttachments;\r\ + \n :delay 2;\r\ + \n }\r\ + \n :log info (\"\$SMP Final report email sent successfully, and the scrip\ + t has finished.\");\r\ + \n}\r\ + \n:log info (\"\$SMP the script has finished, script step: `\$scriptStep` \ + \\n\\n\");\r\ + \n\r\ + \n} do={:global ExitError; \$ExitError \$ExitOK [ :jobname ] \$Err}\r\ + \n" +add dont-require-permissions=no name=testGetPubIP owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + global DevInfoIncludeIP;\r\ + \n:global CharacterReplace;\r\ + \n:global EscapeForRegEx;\r\ + \n:global UrlEncode;\r\ + \n\r\ + \n:if ([ \$DevInfoIncludeIP ] = true) do={\r\ + \n :global GetPubIp;\r\ + \n :local Char (\"\\n\\r\");\r\ + \n :local PublicIpAddress [\$GetPubIp];\r\ + \n# :if ([ :pick \$PublicIpAddress ([ :len \$PublicIpAddress ] - 2) ] = \ + \"\\n\") do={:error true}; :set error falseon-error={:set PublicIpAddress \ + (\$PublicIpAddress . Char)};\r\ + \n#:if ([ :pick \$PublicIpAddress ([ :len \$PublicIpAddress ] - 1) ] = \"/\ + n\") do={\r\ + \n#:log warning \"N is = //n\"; \r\ + \n# :set PublicIpAddress [ \$CharacterReplace \$PublicIpAddress \$Char \"\ + \" ];\r\ + \n#}\r\ + \n# :set PublicIpAddress [ \$UrlEncode \$PublicIpAddress ];\r\ + \n#:local IpLen ([ :len \$PublicIpAddress ] -1);\r\ + \n#:set PublicIpAddress [:pick \$PublicIpAddress 0 \$IpLen];\r\ + \n :log warning \"Public IP address detected: \$PublicIpAddress , len = \ + \$IpLen\";\r\ + \n}\r\ + \n" +add comment="download, import and update firewall address-lists" \ + dont-require-permissions=no name=AM-FwAddrLists owner=AM-FwAddrLists \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + source="#!rsc by Vados\r\ + \n# RouterOS script: AM-FwAddrLists\r\ + \n# Script comment: download, import and update firewall address-lists\r\ + \n# Copyright (c) 2007-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version=7.19\r\ + \n# https://ros.vados.ru/doc/fw-addr-lists.md\r\ + \n:local ExitOK false;\r\ + \n:onerror Err {\r\ + \n :global GlobalConfReady; :global GlobalFuncReady;\r\ + \n :retry { :if (\$GlobalConfReady != true || \$GlobalFuncReady != true) \ + \\\r\ + \n do={ :error (\"Global config and/or functions not ready.\"); }; } \ + delay=500ms max=50;\r\ + \n :local ScriptName [ :jobname ];\r\ + \n\r\ + \n :global GlobalScriptsUrl;\r\ + \n :local ListsDirName (\"fw-addr-lists.d/\" . [ /system identity get nam\ + e ] . \"/\");\r\ + \n :local ListsUrl (\$GlobalScriptsUrl . \$ListsDirName);\r\ + \n :local ListsIndex \"index.lst\";\r\ + \n :local AddrListsTimeOut 1d;\r\ + \n :local CheckCerts false;\r\ + \n\r\ + \n :global CertificateAvailable;\r\ + \n :global EitherOr;\r\ + \n :global FetchHugeFiles;\r\ + \n :global HumanReadableNum;\r\ + \n :global IfThenElse;\r\ + \n :global LogPrint;\r\ + \n :global NetMask4;\r\ + \n :global NetMask6;\r\ + \n :global ScriptLock;\r\ + \n \r\ + \n :local FindDelim do={\r\ + \n :local ValidChars \"0123456789.:/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghi\ + jklmnopqrstuvwxyz-\";\r\ + \n :for I from=0 to=[ :len \$1 ] do={\r\ + \n :if ([ :typeof [ :find \$ValidChars [ :pick (\$1 . \" \") \$I ] ] \ + ] != \"num\") do={\r\ + \n :return \$I;\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :local GetBranch do={\r\ + \n :global EitherOr;\r\ + \n :return [ :pick [ :convert transform=md5 to=hex [ :pick \$1 0 [ \$Ei\ + therOr [ :find \$1 \"/\" ] [ :len \$1 ] ] ] ] 0 2 ];\r\ + \n }\r\ + \n \r\ + \n :if ([ \$ScriptLock \$ScriptName ] = false) do={\r\ + \n :set ExitOK true;\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :local ListComment (\"managed by \" . \$ScriptName);\r\ + \n :local Url (\$ListsUrl . \$ListsIndex);\r\ + \n :local tmpIndex false;\r\ + \n\r\ + \n :for I from=1 to=5 do={\r\ + \n :if (\$tmpIndex = false) do={\r\ + \n :set tmpIndex [ :tolf [ \$FetchHugeFiles \$ScriptName \$Url \$Chec\ + kCerts ] ];\r\ + \n :if (\$tmpIndex = false && \$I < 5) do={\r\ + \n :log warning (\$ScriptName . \" Failed downloading address-list \ + index, \" . \$I . \". try from: \" . \$Url);\r\ + \n :delay ((\$I * \$I) . \"s\");\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n :if (\$tmpIndex = false) do={\r\ + \n :log warning (\$ScriptName . \" Failed downloading address-list inde\ + x from: \" . \$Url);\r\ + \n :set tmpIndex \"\";\r\ + \n }\r\ + \n\r\ + \n :foreach List in=[ :deserialize \$tmpIndex delimiter=\"\\n\" from=dsv \ + options=dsv.plain ] do={\r\ + \n# :set List (\$List->0);\r\ + \n :local ListName;\r\ + \n :local Delim [ \$FindDelim \$List ];\r\ + \n :if (\$Delim = 0) do={ :set List \"\"; };\r\ + \n :log warning (\$ScriptName . \" Parsing address-list index entry: \"\ + \_. \$List);\r\ + \n :if ([ :len \$List ] = 0) do={\r\ + \n :log error (\$ScriptName . \" Failed parsing address-list index en\ + try: \" . \$List);\r\ + \n } else={\r\ + \n :set ListName [ :pick \$List 0 \$Delim ];\r\ + \n }\r\ + \n :log warning (\$ScriptName . \" Parsing address-list index entry: \"\ + \_. \$ListName . \" - Ok.\");\r\ + \n :local ListUrl (\$ListsUrl . \$ListName);\r\ + \n :local CntAdd 0;\r\ + \n :local CntRenew 0;\r\ + \n :local CntRemove 0;\r\ + \n :local IPv4Addresses ({});\r\ + \n :local IPv6Addresses ({});\r\ + \n :local Failure false;\r\ + \n :local Data false;\r\ + \n :local TimeOut \$AddrListTimeOut;\r\ + \n\r\ + \n :for I from=1 to=5 do={\r\ + \n :if (\$Data = false) do={\r\ + \n :set Data [ :tolf [ \$FetchHugeFiles \$ScriptName \$ListUrl \$Ch\ + eckCerts ] ];\r\ + \n :if (\$Data = false && \$I < 5) do={\r\ + \n :log warning (\$ScriptName . \" Failed downloading for list '\ + \" . \$ListName . \"', \" . \$I . \". try from: \" . \$ListUrl);\r\ + \n :delay ((\$I * \$I) . \"s\");\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :if (\$Data = false) do={\r\ + \n :set Data \"\";\r\ + \n :set Failure true;\r\ + \n :log warning (\$ScriptName . \" Failed downloading for list '\" . \ + \$ListName . \"' from: \" . \$ListUrl);\r\ + \n } else={\r\ + \n :log warning (\$ScriptName . \" Downloaded \" . [ \$HumanReadableN\ + um [ :len \$Data ] 1024 ] . \"B for list '\" . \$ListName . \"' from: \" .\ + \_\$ListUrl);\r\ + \n }\r\ + \n\r\ + \n :foreach Line in=[ :deserialize \$Data delimiter=\"\\n\" from=dsv op\ + tions=dsv.plain ] do={\r\ + \n :set Line (\$Line->0);\r\ + \n :local Address;\r\ + \n :if ([ :pick \$Line 0 1 ] = \"{\" && [ :pick \$Line ([ :len \$Line\ + \_] - 1) ] = \"}\") do={\r\ + \n :do {\r\ + \n :set Address [ :tostr ([ :deserialize from=json \$Line ]->\"ci\ + dr\") ];\r\ + \n } on-error={ }\r\ + \n } else={\r\ + \n :set Address ([ :pick \$Line 0 [ \$FindDelim \$Line ] ] . (\$L\ + ist->\"cidr\"));\r\ + \n }\r\ + \n :do {\r\ + \n :local Branch;\r\ + \n :if (\$Address ~ \"^[0-9]{1,3}\\\\.[0-9]{1,3}\\\\.[0-9]{1,3}\\\\\ + .[0-9]{1,3}(/[0-9]{1,2})\?\\\$\") do={\r\ + \n :local Net \$Address;\r\ + \n :local CIDR 32;\r\ + \n :local Slash [ :find \$Address \"/\" ];\r\ + \n :if ([ :typeof \$Slash ] = \"num\") do={\r\ + \n :set Net [ :toip [ :pick \$Address 0 \$Slash ] ]\r\ + \n :set CIDR [ :pick \$Address (\$Slash + 1) [ :len \$Address ]\ + \_];\r\ + \n :set Address [ :tostr (([ :toip \$Net ] & [ \$NetMask4 \$CID\ + R ]) . [ \$IfThenElse (\$CIDR < 32) (\"/\" . \$CIDR) ]) ];\r\ + \n }\r\ + \n :set Branch [ \$GetBranch \$Address ];\r\ + \n :set (\$IPv4Addresses->\$Branch->\$Address) \$TimeOut;\r\ + \n }\r\ + \n :if (\$Address ~ \"^[0-9a-zA-Z]*:[0-9a-zA-Z:\\\\.]+(/[0-9]{1,3})\ + \?\\\$\") do={\r\ + \n :local Net \$Address;\r\ + \n :local CIDR 128;\r\ + \n :local Slash [ :find \$Address \"/\" ];\r\ + \n :if ([ :typeof \$Slash ] = \"num\") do={\r\ + \n :set Net [ :toip6 [ :pick \$Address 0 \$Slash ] ]\r\ + \n :set CIDR [ :pick \$Address (\$Slash + 1) [ :len \$Address ]\ + \_];\r\ + \n }\r\ + \n :set Address (([ :toip6 \$Net ] & [ \$NetMask6 \$CIDR ]) . \"/\ + \" . \$CIDR);\r\ + \n :set Branch [ \$GetBranch \$Address ];\r\ + \n :set (\$IPv6Addresses->\$Branch->\$Address) \$TimeOut;\r\ + \n }\r\ + \n :if (\$Address ~ \"^[\\\\.a-zA-Z0-9-]+\\\\.[a-zA-Z]{2,}\\\$\") d\ + o={\r\ + \n :set Branch [ \$GetBranch \$Address ];\r\ + \n :set (\$IPv4Addresses->\$Branch->\$Address) \$TimeOut;\r\ + \n :set (\$IPv6Addresses->\$Branch->\$Address) \$TimeOut;\r\ + \n }\r\ + \n } on-error={ }\r\ + \n }\r\ + \n \r\ + \n\r\ + \n :foreach Entry in=[ /ip/firewall/address-list/find where \\\r\ + \n list=\$ListName comment=\$ListComment ] do={\r\ + \n :local Address [ /ip/firewall/address-list/get \$Entry address ];\ + \r\ + \n :local Branch [ \$GetBranch \$Address ];\r\ + \n :local TimeOut (\$IPv4Addresses->\$Branch->\$Address);\r\ + \n :if ([ :typeof \$TimeOut ] = \"time\") do={\r\ + \n :log warning (\$ScriptName . \" Renewing IPv4 address \" . \$Add\ + ress . \\\r\ + \n \" in list '\" . \$ListName . \"' with \" . \$TimeOut . \".\ + \");\r\ + \n /ip/firewall/address-list/set \$Entry timeout=\$TimeOut;\r\ + \n :set (\$IPv4Addresses->\$Branch->\$Address);\r\ + \n :set CntRenew (\$CntRenew + 1);\r\ + \n } else={\r\ + \n :if (\$Failure = false) do={\r\ + \n :log warning (\$ScriptName . \" Removing IPv4 address \" . \$A\ + ddress . \\\r\ + \n \" from list '\" . \$ListName . \".\");\r\ + \n /ip/firewall/address-list/remove \$Entry;\r\ + \n :set CntRemove (\$CntRemove + 1);\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :foreach Entry in=[ /ipv6/firewall/address-list/find where \\\r\ + \n list=\$ListName comment=\$ListComment ] do={\r\ + \n :local Address [ /ipv6/firewall/address-list/get \$Entry address ]\ + ;\r\ + \n :local Branch [ \$GetBranch \$Address ];\r\ + \n :local TimeOut (\$IPv6Addresses->\$Branch->\$Address);\r\ + \n :if ([ :typeof \$TimeOut ] = \"time\") do={\r\ + \n :log warning (\$ScriptName . \" Renewing IPv6 address \" . \$Add\ + ress . \\\r\ + \n \" in list '\" . \$ListName . \"' with \" . \$TimeOut . \".\ + \");\r\ + \n /ipv6/firewall/address-list/set \$Entry timeout=\$TimeOut;\r\ + \n :set (\$IPv6Addresses->\$Branch->\$Address);\r\ + \n :set CntRenew (\$CntRenew + 1);\r\ + \n } else={\r\ + \n :if (\$Failure = false) do={\r\ + \n :log warning (\$ScriptName . \" Removing IPv6 address \" . \$A\ + ddress . \\\r\ + \n \" from list '\" . \$ListName . \".\");\r\ + \n /ipv6/firewall/address-list/remove \$Entry;\r\ + \n :set CntRemove (\$CntRemove + 1);\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :foreach BranchName,Branch in=\$IPv4Addresses do={\r\ + \n :log warning (\$ScriptName . \" Handling branch: \" . \$BranchName\ + );\r\ + \n :foreach Address,Timeout in=\$Branch do={\r\ + \n :log warning (\$ScriptName . \" Adding IPv4 address \" . \$Addre\ + ss . \\\r\ + \n \" to list '\" . \$ListName . \"' with \" . \$Timeout . \".\ + \");\r\ + \n :onerror Err {\r\ + \n /ip/firewall/address-list/add list=\$ListName comment=\$ListCo\ + mment \\\r\ + \n address=\$Address timeout=\$Timeout;\r\ + \n :set CntAdd (\$CntAdd + 1);\r\ + \n } do={\r\ + \n :log warning (\$ScriptName . \" Failed to add IPv4 address \" \ + . \$Address . \\\r\ + \n \" to list '\" . \$ListName . \"': \" . \$Err);\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :foreach BranchName,Branch in=\$IPv6Addresses do={\r\ + \n :log warning (\$ScriptName . \" Handling branch: \" . \$BranchName\ + );\r\ + \n :foreach Address,Timeout in=\$Branch do={\r\ + \n :log warning (\$ScriptName . \" Adding IPv6 address \" . \$Addre\ + ss . \\\r\ + \n \" to list '\" . \$ListName . \"' with \" . \$Timeout . \".\ + \");\r\ + \n :onerror Err {\r\ + \n /ipv6/firewall/address-list/add list=\$ListName comment=\$List\ + Comment \\\r\ + \n address=\$Address timeout=\$Timeout;\r\ + \n :set CntAdd (\$CntAdd + 1);\r\ + \n } do={\r\ + \n :log warning (\$ScriptName . \" Failed to add IPv6 address \" \ + . \$Address . \\\r\ + \n \" to list '\" . \$ListName . \"': \" . \$Err);\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :log info (\$ScriptName . \" list: \" . \$ListName . \\\r\ + \n \" (\" . [ \$HumanReadableNum (\$CntAdd + \$CntRenew) 1000 ] . \ + \")\" . \\\r\ + \n \" -- added: \" . [ \$HumanReadableNum \$CntAdd 1000 ] . \\\r\ + \n \" - renewed: \" . [ \$HumanReadableNum \$CntRenew 1000 ] . \\\r\ + \n \" - removed: \" . [ \$HumanReadableNum \$CntRemove 1000 ]);\r\ + \n }\r\ + \n} do={\r\ + \n :global ExitError; \$ExitError \$ExitOK [ :jobname ] \$Err;\r\ + \n}\r\ + \n" +add dont-require-permissions=no name=AmneziaWG owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + /routing table \ + \n#add disabled=no fib name=r_to_vpn\ + \n#/ip firewall address-list\ + \n#add address=8.8.4.4 list=to_vpn\ + \n#/ip firewall address-list\ + \n#add address=10.0.0.0/8 list=RFC1918\ + \n#add address=172.16.0.0/12 list=RFC1918\ + \n#add address=192.168.0.0/16 list=RFC1918\ + \n#/interface/list/add name=WAN\ + \n#/interface/list/member/add list=WAN interface=ether1\ + \n\ + \n/ip firewall mangle\ + \nadd action=accept chain=prerouting dst-address-list=RFC1918 in-interface\ + -list=!WAN\ + \n/ip firewall mangle\ + \nadd action=mark-connection chain=prerouting connection-mark=no-mark dst-\ + address-list=to_vpn in-interface-list=!WAN \\\ + \n new-connection-mark=to-vpn-conn passthrough=yes\ + \n/ip firewall mangle\ + \nadd action=mark-routing chain=prerouting connection-mark=to-vpn-conn in-\ + interface-list=!WAN new-routing-mark=r_to_vpn \\\ + \n passthrough=yes\ + \n/ip firewall mangle\ + \nadd action=mark-connection chain=output connection-mark=no-mark \\\ + \n dst-address-list=to_vpn new-connection-mark=to-vpn-conn-local \\\ + \n passthrough=yes\ + \nadd action=mark-routing chain=output connection-mark=to-vpn-conn-local \ + \\\ + \n new-routing-mark=r_to_vpn passthrough=yes\ + \n\ + \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" +/app +set cinny firewall-redirects=8094:80:tcp:web +set goaway container-command-lines=goaway:none:docker.io/pommee/goaway:latest +set home-assistant container-command-lines=\ + home-assistant:none:lscr.io/linuxserver/homeassistant +set n8n firewall-redirects=5678:5678:tcp:web +set nextcloud container-command-lines="db:none:docker.io/postgres:17,redis:non\ + e:docker.io/valkey/valkey:/bin/sh -c 'valkey-server --port 6379 --appendon\ + ly yes --requirepass \$VALKEY_PASSWORD',server:none:docker.io/nextcloud:ap\ + ache" +set pihole environment="pihole:FTLCONF_dns_listeningMode=all,pihole:FTLCONF_we\ + bserver_api_password=password" +set redlib firewall-redirects=8087:8080:tcp:web +set solr container-command-lines=solr:none:docker.io/solr:latest +set uptime-kuma container-command-lines=\ + uptime-kuma:none:docker.io/louislam/uptime-kuma:1 +/app settings +set auto-update=yes disk=sata1 lan-bridge=Bridge-LAN registry-mirrors="https:/\ + /reg.vados.ru:5000/:https://reg.vados.ru/,https://registry-1.docker.io" +/caps-man aaa +set called-format=ssid +/caps-man access-list +add action=reject allow-signal-out-of-range=10s disabled=no interface=all \ + signal-range=-120..-80 ssid-regexp="" +add action=accept allow-signal-out-of-range=10s disabled=no interface=all \ + signal-range=-79..120 ssid-regexp="" +/caps-man manager +set ca-certificate=CAPsMAN-CA-51B25E507D07 certificate=CAPsMAN-51B25E507D07 \ + enabled=yes require-peer-certificate=yes +/caps-man manager interface +set [ find default=yes ] forbid=yes +add disabled=no interface=Bridge-LAN +/caps-man provisioning +add action=create-dynamic-enabled hw-supported-modes=g,gn,b \ + master-configuration=2G name-format=prefix-identity name-prefix=2G +add action=create-dynamic-enabled hw-supported-modes=an,ac,a \ + master-configuration=5G name-format=prefix-identity name-prefix=5G +add action=create-dynamic-enabled disabled=yes hw-supported-modes=ac,an,a \ + master-configuration=2G name-format=prefix-identity name-prefix=5ghz-ac +add action=create-dynamic-enabled disabled=yes hw-supported-modes=an \ + master-configuration=5G name-format=prefix-identity name-prefix=5ghz-an +/certificate settings +set builtin-trust-store=fetch crl-store=system +/container config +set layer-dir=/sata1 registry-url=https://reg.vados.ru tmpdir=/ramstorage \ + username=amster-dev +/container envs +add key=ENV list=carkeeperbot_envs value=/root/.ashrc +add key=PATH list=carkeeperbot_envs value=\ + /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +add key=PORT list=carkeeperbot_envs value="\${SSH_PORT}" +add key=SSH_PORT list=carkeeperbot_envs value=8222 +/container mounts +add dst=/etc/amnezia/amneziawg list=awg_conf src=/wg +add dst=/app list=carkeeper_app src=/sata1/carkeeper/app +add dst=/configs list=carkeeper_configs src=/sata1/carkeeper/configs +add dst=/root/.ashrc list=carkeeper_configs/.profile src=\ + /sata1/carkeeper/configs/.profile +add dst=/etc/php82/php.ini list=carkeeper_configs/php.ini src=\ + /sata1/carkeeper/configs/php.ini +add dst=/etc/ssh/sshd_config list=carkeeper_configs/sshd_config src=\ + /sata1/carkeeper/configs/sshd_config +add dst=/scripts list=carkeeper_scripts src=/sata1/carkeeper/scripts +add dst=/var/sync list=carkeeper_sync src=/sata1/carkeeper/sync +add dst=/var/tmp list=carkeeper_tmp src=/sata1/carkeeper/tmp +/interface bridge port +add bridge=Bridge-LAN interface=ether2 +add bridge=Bridge-DOC interface=veth1 +add bridge=Bridge-LAN interface=LAN +add bridge=Bridge-LAN interface=dynamic +/ipv6 settings +set disable-ipv6=yes disable-link-local-address=yes +/interface detect-internet +set detect-interface-list=all internet-interface-list=WAN lan-interface-list=\ + LAN wan-interface-list=WAN +/interface list member +add interface=Bridge-LAN list=WAN +add interface=lo list=LAN +/interface wifi capsman +set package-path=/tmpfs/capsman-packages upgrade-policy=none +/ip address +add address=10.30.30.10/24 interface=Bridge-LAN network=10.30.30.0 +add address=10.10.10.1/24 disabled=yes interface=Bridge-DOC network=\ + 10.10.10.0 +add address=172.18.20.5/30 disabled=yes interface=docker-xray-vless-veth \ + network=172.18.20.4 +add address=172.18.20.1/30 interface=docker-awg-veth network=172.18.20.0 +/ip dhcp-server +add add-arp=yes address-pool=dhcp always-broadcast=yes bootp-support=none \ + dhcp-option-set=domain-search-set disabled=yes interface=Bridge-LAN \ + lease-script=lease-script lease-time=10m name=nucDHCP server-address=\ + 10.30.30.10 +/ip dns +set allow-remote-requests=yes doh-max-concurrent-queries=100 \ + doh-max-server-connections=20 servers=10.30.30.81 verify-doh-cert=yes +/ip firewall address-list +add address=8.8.4.4 list=to_vpn +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 +/ip firewall filter +add action=accept chain=input +add action=accept chain=output +add action=accept chain=forward comment="Comment of the rule" disabled=yes +/ip firewall mangle +# docker-xray-vless-veth not ready +add action=change-mss chain=forward new-mss=1360 out-interface=\ + docker-xray-vless-veth protocol=tcp tcp-flags=syn tcp-mss=1420-65535 +add action=accept chain=prerouting dst-address-list=RFC1918 \ + in-interface-list=!WAN +add action=mark-connection chain=prerouting 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 connection-mark=to-vpn-conn \ + in-interface-list=!WAN new-routing-mark=r_to_vpn +add action=mark-connection chain=output connection-mark=no-mark \ + dst-address-list=to_vpn new-connection-mark=to-vpn-conn-local +add action=mark-routing chain=output connection-mark=to-vpn-conn-local \ + new-routing-mark=r_to_vpn +# docker-awg-veth not ready +add action=change-mss chain=forward new-mss=1360 out-interface=\ + docker-awg-veth protocol=tcp tcp-flags=syn tcp-mss=1420-65535 +/ip firewall nat +# docker-xray-vless-veth not ready +add action=masquerade chain=srcnat out-interface=docker-xray-vless-veth +# docker-awg-veth not ready +add action=masquerade chain=srcnat out-interface=docker-awg-veth +/ip firewall service-port +set ftp disabled=yes +set tftp disabled=yes +set sip disabled=yes +set pptp disabled=yes +set rtsp disabled=no +/ip route +add check-gateway=bfd disabled=no distance=1 dst-address=0.0.0.0/0 gateway=\ + 10.30.30.81 routing-table=main scope=30 target-scope=10 +add distance=1 dst-address=0.0.0.0/0 gateway=172.18.20.2 routing-table=\ + r_to_vpn +/ip service +set ftp disabled=yes +set www disabled=yes +set ssh port=2222 +set www-ssl port=4443 +set api disabled=yes +set api-ssl disabled=yes +/ip service webserver +set acme-plain=no crl-plain=no graphs-plain=no graphs-secure=no index-plain=\ + no index-secure=no rest-plain=no rest-secure=no scep-plain=no \ + webfig-plain=no webfig-secure=no +/ip ssh +set forwarding-enabled=both password-authentication=no \ + publickey-authentication-options=verify-required strong-crypto=yes +/ip upnp +set enabled=yes +/ip upnp interfaces +add interface=Bridge-LAN type=external +add interface=Bridge-DOC type=internal +/ipv6 firewall address-list +add address=2400:cb00::/32 list=CLOUDFLARE-IP-Address +add address=2606:4700::/32 list=CLOUDFLARE-IP-Address +add address=2803:f800::/32 list=CLOUDFLARE-IP-Address +add address=2405:b500::/32 list=CLOUDFLARE-IP-Address +add address=2405:8100::/32 list=CLOUDFLARE-IP-Address +add address=2a06:98c0::/29 list=CLOUDFLARE-IP-Address +add address=2c0f:f248::/32 list=CLOUDFLARE-IP-Address +/system clock +set time-zone-autodetect=no time-zone-name=Europe/Moscow +/system gps +set set-system-time=yes +/system identity +set name=MikroNUC +/system note +set show-at-login=no +/system ntp client +set enabled=yes +/system ntp server +set enabled=yes manycast=yes multicast=yes +/system ntp client servers +add address=10.30.30.81 +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 +/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="Every Day Check For Fake Bridges" interval=1d name=\ + mod/AM-IPbridge on-event="/system/script/run mod/AM-IPbridge;" policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-time=startup +add comment="Telegram Chat Bot" interval=30s name=mod/AM-TG-Bot on-event=\ + "/system/script/run mod/AM-TG-Bot;" policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-time=startup +add comment=\ + "Every 7 Day Check For Update and Backup send notification to EMail." \ + interval=1w name=AM-Backup-UpdateEmail on-event=\ + "/system/script { run AM-Backup-UpdateEmail; }" policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-date=2026-06-18 start-time=03:41:27 +/tool e-mail +set certificate-verification=no from=MikroNUC port=587 \ + server=smtp.mail.me.com tls=starttls user=vadossio@icloud.com +/tool netwatch +add disabled=yes down-script=\ + ":local msg \"Host MikroYellow is DOWN\";\r\ + \n\$TGSendMessage \$msg;" host=10.30.30.86 http-codes="" interval=10s \ + test-script="" type=simple up-script=\ + ":global TGSendMessage;\r\ + \n\$TGSendMessage \"Host MikroYellow is UP\";" +/user aaa +set accounting=no diff --git a/MikroNUC/history/20260620/20260620004001-Diff-Config.rsc b/MikroNUC/history/20260620/20260620004001-Diff-Config.rsc new file mode 100644 index 0000000..fbbc101 --- /dev/null +++ b/MikroNUC/history/20260620/20260620004001-Diff-Config.rsc @@ -0,0 +1,3 @@ +4829,4830d4828 +< /system gps +< set set-system-time=yes -- 2.52.0