From 6f1a1ec72d75703b72ee58efdff18cdc42e01a51 Mon Sep 17 00:00:00 2001 From: vados-dev Date: Mon, 17 Aug 2026 00:00:03 +0300 Subject: [PATCH] Backup for MikroNUC created successfully at Aug 17 00:00:03. --- .../20260817/20260817000001-Binary.backup | Bin 0 -> 450286 bytes MikroNUC/20260817/20260817000001-Config.rsc | 6005 +++++++++++++++++ .../20260817/20260817000001-Diff-Config.rsc | 511 ++ 3 files changed, 6516 insertions(+) create mode 100644 MikroNUC/20260817/20260817000001-Binary.backup create mode 100644 MikroNUC/20260817/20260817000001-Config.rsc create mode 100644 MikroNUC/history/20260817/20260817000001-Diff-Config.rsc diff --git a/MikroNUC/20260817/20260817000001-Binary.backup b/MikroNUC/20260817/20260817000001-Binary.backup new file mode 100644 index 0000000000000000000000000000000000000000..ae6f2efb29a89ce9fbf33d1df0ac66228d90abb5 GIT binary patch literal 450286 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

c%;rmgZoVYh9H&Mlnf6&3Pfv=2 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

ZdX(f@ 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 literal 0 HcmV?d00001 diff --git a/MikroNUC/20260817/20260817000001-Config.rsc b/MikroNUC/20260817/20260817000001-Config.rsc new file mode 100644 index 0000000..ea66455 --- /dev/null +++ b/MikroNUC/20260817/20260817000001-Config.rsc @@ -0,0 +1,6005 @@ +# 2026-08-17 00:00:01 by RouterOS 7.23.3 +# 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-LAN +add name=internal protocol-mode=none +/interface ethernet +set [ find default-name=ether1 ] disable-running-check=no +/interface veth +add address="" container-mac-address=24:21:2C:26:EA:2F dhcp=yes gateway="" \ + gateway6="" mac-address=24:21:2C:26:EA:2E name=veth-app-HA-otbr-matter +add address=172.18.0.86/24 container-mac-address=32:18:2B:C3:9B:3C dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=32:18:2B:C3:9B:3B name=\ + veth-app-adventurelog +add address=172.18.0.87/24 container-mac-address=2A:04:D2:E3:35:2A dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=2A:04:D2:E3:35:29 name=\ + veth-app-babybuddy +add address=172.18.0.88/24 container-mac-address=20:C4:8E:BC:AE:EF dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=20:C4:8E:BC:AE:EE name=\ + veth-app-backrest +add address=172.18.0.89/24 container-mac-address=54:12:68:AB:5B:26 dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=54:12:68:AB:5B:25 name=\ + veth-app-birdnet-go +add address="" container-mac-address=4E:75:8A:1C:DE:61 dhcp=yes gateway="" \ + gateway6="" mac-address=4E:75:8A:1C:DE:60 name=veth-app-caddy +add address=172.18.0.90/24 container-mac-address=62:1C:85:A6:26:74 dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=62:1C:85:A6:26:73 name=\ + veth-app-calibre-web +add address="" container-mac-address=40:14:50:A7:E9:C4 dhcp=yes gateway="" \ + gateway6="" mac-address=40:14:50:A7:E9:C3 name=veth-app-chr +add address=172.18.0.91/24 container-mac-address=54:CB:C8:FC:9C:6F dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=54:CB:C8:FC:9C:6E name=\ + veth-app-cinny +add address=172.18.0.92/24 container-mac-address=32:3C:0A:F0:FF:88 dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=32:3C:0A:F0:FF:87 name=\ + veth-app-cloudflared +add address=172.18.0.93/24 container-mac-address=58:C2:AD:23:FF:E7 dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=58:C2:AD:23:FF:E6 name=\ + veth-app-code-server +add address=172.18.0.94/24 container-mac-address=14:48:58:EE:E4:8B dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=14:48:58:EE:E4:8A name=\ + veth-app-conduit +add address=172.18.0.95/24 container-mac-address=3A:99:FA:FF:15:95 dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=3A:99:FA:FF:15:94 name=\ + veth-app-convertx +add address=172.18.0.96/24 container-mac-address=62:92:21:8E:8E:03 dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=62:92:21:8E:8E:02 name=\ + veth-app-copyparty +add address=172.18.0.97/24 container-mac-address=2A:89:3C:4D:E5:1E dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=2A:89:3C:4D:E5:1D name=\ + veth-app-cryptpad +add address=172.18.0.98/24 container-mac-address=70:56:46:13:D6:4F dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=70:56:46:13:D6:4E name=\ + veth-app-diagrams-net +add address="" container-mac-address=2E:D7:EB:FC:51:2C dhcp=yes gateway="" \ + gateway6="" mac-address=2E:D7:EB:FC:51:2B name=\ + veth-app-docker-with-dockge +add address="" container-mac-address=28:C0:33:81:C4:4C dhcp=yes gateway="" \ + gateway6="" mac-address=28:C0:33:81:C4:4B name=\ + veth-app-docker-with-komodo +add address="" container-mac-address=4E:72:F4:F2:52:B4 dhcp=yes gateway="" \ + gateway6="" mac-address=4E:72:F4:F2:52:B3 name=\ + veth-app-docker-with-portainer +add address=172.18.0.99/24 container-mac-address=70:99:0A:31:E2:F3 dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=70:99:0A:31:E2:F2 name=\ + veth-app-docmost +add address=172.18.0.100/24 container-mac-address=22:D4:32:5A:AB:E0 dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=22:D4:32:5A:AB:DF name=\ + veth-app-elasticsearch +add address=172.18.0.101/24 container-mac-address=4E:72:06:FE:0F:28 dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=4E:72:06:FE:0F:27 name=\ + veth-app-element +add address=172.18.0.102/24 container-mac-address=0A:01:AC:C9:52:D0 dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=0A:01:AC:C9:52:CF name=\ + veth-app-excalidraw +add address=172.18.0.103/24 container-mac-address=7E:3A:4A:57:F5:D8 dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=7E:3A:4A:57:F5:D7 name=\ + veth-app-filegator +add address=172.18.0.104/24 container-mac-address=7C:41:9F:5F:C9:C9 dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=7C:41:9F:5F:C9:C8 name=\ + veth-app-firefox +add address=172.18.0.105/24 container-mac-address=64:60:0E:54:3E:C4 dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=64:60:0E:54:3E:C3 name=\ + veth-app-forgejo +add address=172.18.0.106/24 container-mac-address=28:37:D4:22:97:F8 dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=28:37:D4:22:97:F7 name=\ + veth-app-fossil +add address=172.18.0.107/24 container-mac-address=00:BE:C5:23:83:99 dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=00:BE:C5:23:83:98 name=\ + veth-app-frigate +add address=172.18.0.108/24 container-mac-address=00:BB:5E:9E:F7:FF dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=00:BB:5E:9E:F7:FE name=\ + veth-app-gitea +add address=172.18.0.109/24 container-mac-address=1A:F3:AB:12:62:80 dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=1A:F3:AB:12:62:7F name=\ + veth-app-gitlab +add address=172.18.0.110/24 container-mac-address=46:05:FE:7A:8A:7E dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=46:05:FE:7A:8A:7D name=\ + veth-app-grafana +add address=172.18.0.111/24 container-mac-address=6E:37:1F:80:A4:A5 dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=6E:37:1F:80:A4:A4 name=\ + veth-app-hedgedoc +add address="" container-mac-address=5E:EE:57:7D:C7:DF dhcp=yes gateway="" \ + gateway6="" mac-address=5E:EE:57:7D:C7:DE name=veth-app-home-assistant +add address=172.18.0.112/24 container-mac-address=3A:54:03:A1:C3:BA dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=3A:54:03:A1:C3:B9 name=\ + veth-app-immich +add address=172.18.0.113/24 container-mac-address=26:1B:92:7A:72:88 dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=26:1B:92:7A:72:87 name=\ + veth-app-influxdb +add address=172.18.0.114/24 container-mac-address=16:EF:0A:15:4A:BC dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=16:EF:0A:15:4A:BB name=\ + veth-app-jackett +add address="" container-mac-address=2A:F7:1E:48:28:87 dhcp=yes gateway="" \ + gateway6="" mac-address=2A:F7:1E:48:28:86 name=veth-app-jellyfin +add address=172.18.0.115/24 container-mac-address=12:3D:1F:EF:9D:A9 dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=12:3D:1F:EF:9D:A8 name=\ + veth-app-jupyter-notebook +add address=172.18.0.116/24 container-mac-address=22:A5:A5:D3:63:73 dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=22:A5:A5:D3:63:72 name=\ + veth-app-kimai +add address=172.18.0.117/24 container-mac-address=52:37:2A:CB:98:E3 dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=52:37:2A:CB:98:E2 name=\ + veth-app-librenms +add address=172.18.0.118/24 container-mac-address=74:27:EB:64:C4:00 dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=74:27:EB:64:C3:FF name=\ + veth-app-librespeed +add address=172.18.0.119/24 container-mac-address=72:14:76:F1:35:9D dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=72:14:76:F1:35:9C name=\ + veth-app-lidarr +add address=172.18.0.120/24 container-mac-address=5A:62:24:8B:E2:21 dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=5A:62:24:8B:E2:20 name=\ + veth-app-livebook +add address=172.18.0.121/24 container-mac-address=32:92:78:E7:B8:D3 dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=32:92:78:E7:B8:D2 name=\ + veth-app-mediamanager +add address=172.18.0.122/24 container-mac-address=02:6B:AD:29:37:B9 dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=02:6B:AD:29:37:B8 name=\ + veth-app-memos +add address=172.18.0.123/24 container-mac-address=36:FE:52:AE:FA:7A dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=36:FE:52:AE:FA:79 name=\ + veth-app-metube +add address=172.18.0.124/24 container-mac-address=38:37:B0:03:D3:3B dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=38:37:B0:03:D3:3A name=\ + veth-app-mikrodash +add address=172.18.0.125/24 container-mac-address=6C:B5:19:41:15:1B dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=6C:B5:19:41:15:1A name=\ + veth-app-minio +add address=172.18.0.126/24 container-mac-address=58:FF:FD:1A:7D:CC dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=58:FF:FD:1A:7D:CB name=\ + veth-app-mosquitto +add address=172.18.0.127/24 container-mac-address=46:3F:8B:34:11:42 dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=46:3F:8B:34:11:41 name=\ + veth-app-myip +add address=172.18.0.128/24 container-mac-address=7A:DE:37:D7:8F:34 dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=7A:DE:37:D7:8F:33 name=\ + veth-app-n8n +add address=172.18.0.129/24 container-mac-address=58:F7:71:2B:7D:AF dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=58:F7:71:2B:7D:AE name=\ + veth-app-netbox +add address=172.18.0.130/24 container-mac-address=14:49:0C:95:C7:2F dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=14:49:0C:95:C7:2E name=\ + veth-app-nextcloud +add address=172.18.0.131/24 container-mac-address=2C:AF:0D:A3:A4:C0 dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=2C:AF:0D:A3:A4:BF name=\ + veth-app-nextcloud-whiteboard +add address=172.18.0.132/24 container-mac-address=5C:8A:C9:60:8A:0C dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=5C:8A:C9:60:8A:0B name=\ + veth-app-nocodb +add address=172.18.0.133/24 container-mac-address=26:FF:3E:D9:92:3C dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=26:FF:3E:D9:92:3B name=\ + veth-app-nodered +add address=172.18.0.134/24 container-mac-address=5E:04:3F:C8:9F:DC dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=5E:04:3F:C8:9F:DB name=\ + veth-app-ntfy +add address=172.18.0.135/24 container-mac-address=04:FD:C7:24:B9:83 dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=04:FD:C7:24:B9:82 name=\ + veth-app-nzbget +add address=172.18.0.136/24 container-mac-address=70:D6:AD:D5:83:6C dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=70:D6:AD:D5:83:6B name=\ + veth-app-odoo +add address=172.18.0.137/24 container-mac-address=6C:78:81:2F:C7:E1 dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=6C:78:81:2F:C7:E0 name=\ + veth-app-onlyoffice-docs +add address=172.18.0.138/24 container-mac-address=14:2C:6B:CD:38:F8 dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=14:2C:6B:CD:38:F7 name=\ + veth-app-openwebrx +add address=172.18.0.139/24 container-mac-address=12:80:BF:18:9C:2D dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=12:80:BF:18:9C:2C name=\ + veth-app-openwebui-ollama +add address="" container-mac-address=7C:A9:C1:01:00:A8 dhcp=yes gateway="" \ + gateway6="" mac-address=7C:A9:C1:01:00:A7 name=veth-app-otbr +add address=172.18.0.140/24 container-mac-address=3C:3C:83:78:99:9C dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=3C:3C:83:78:99:9B name=\ + veth-app-paperless-ngx +add address=172.18.0.141/24 container-mac-address=14:7D:DE:0A:7D:3E dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=14:7D:DE:0A:7D:3D name=\ + veth-app-partdb +add address=172.18.0.142/24 container-mac-address=42:51:A4:56:2C:01 dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=42:51:A4:56:2C:00 name=\ + veth-app-pihole +add address="" container-mac-address=62:F7:54:A9:35:2F dhcp=yes gateway="" \ + gateway6="" mac-address=62:F7:54:A9:35:2E name=veth-app-plex +add address=172.18.0.143/24 container-mac-address=1E:DF:41:E5:CA:54 dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=1E:DF:41:E5:CA:53 name=\ + veth-app-pmacct-netflow +add address=172.18.0.144/24 container-mac-address=5C:CB:E9:A8:2E:9D dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=5C:CB:E9:A8:2E:9C name=\ + veth-app-prowlarr +add address=172.18.0.145/24 container-mac-address=1A:7F:F4:E3:00:EC dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=1A:7F:F4:E3:00:EB name=\ + veth-app-radarr +add address=172.18.0.146/24 container-mac-address=0E:5D:27:64:6B:9A dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=0E:5D:27:64:6B:99 name=\ + veth-app-redlib +add address=172.18.0.147/24 container-mac-address=70:53:0A:7B:9C:DE dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=70:53:0A:7B:9C:DD name=\ + veth-app-restic-server +add address=172.18.0.148/24 container-mac-address=16:EA:91:AD:90:65 dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=16:EA:91:AD:90:64 name=\ + veth-app-roundcube +add address=172.18.0.149/24 container-mac-address=76:7F:C7:2F:83:4D dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=76:7F:C7:2F:83:4C name=\ + veth-app-searxng +add address=172.18.0.150/24 container-mac-address=5A:29:98:DD:76:93 dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=5A:29:98:DD:76:92 name=\ + veth-app-smokeping +add address=172.18.0.151/24 container-mac-address=5C:46:75:4E:9D:CA dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=5C:46:75:4E:9D:C9 name=\ + veth-app-snipeit +add address=172.18.0.152/24 container-mac-address=7C:51:1E:41:F3:4B dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=7C:51:1E:41:F3:4A name=\ + veth-app-solr +add address=172.18.0.153/24 container-mac-address=44:F8:FA:B3:FD:85 dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=44:F8:FA:B3:FD:84 name=\ + veth-app-sonarr +add address=172.18.0.154/24 container-mac-address=2C:6E:24:20:9D:76 dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=2C:6E:24:20:9D:75 name=\ + veth-app-sonatype-nexus +add address=172.18.0.155/24 container-mac-address=42:15:B0:E1:D2:12 dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=42:15:B0:E1:D2:11 name=\ + veth-app-stalwart +add address="" container-mac-address=1C:25:DA:CC:A8:50 dhcp=yes gateway="" \ + gateway6="" mac-address=1C:25:DA:CC:A8:4F name=veth-app-syncthing +add address="" container-mac-address=5C:9F:57:A2:76:0A dhcp=yes gateway="" \ + gateway6="" mac-address=5C:9F:57:A2:76:09 name=veth-app-transmission +add address=172.18.0.156/24 container-mac-address=6E:8D:8A:28:07:6B dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=6E:8D:8A:28:07:6A name=\ + veth-app-trip +add address="" container-mac-address=20:F1:91:9F:FA:E0 dhcp=yes gateway="" \ + gateway6="" mac-address=20:F1:91:9F:FA:DF name=veth-app-upsnap +add address=172.18.0.157/24 container-mac-address=7C:10:8F:BB:A4:42 dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=7C:10:8F:BB:A4:41 name=\ + veth-app-uptime-kuma +add address=172.18.0.158/24 container-mac-address=12:E4:E5:5E:C3:00 dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=12:E4:E5:5E:C2:FF name=\ + veth-app-urbackup-client +add address=172.18.0.159/24 container-mac-address=54:09:04:00:DB:55 dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=54:09:04:00:DB:54 name=\ + veth-app-urbackup-server +add address=172.18.0.160/24 container-mac-address=1A:4E:86:63:C7:BD dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=1A:4E:86:63:C7:BC name=\ + veth-app-vaultwarden +add address=172.18.0.161/24 container-mac-address=0C:8F:A2:49:05:F4 dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=0C:8F:A2:49:05:F3 name=\ + veth-app-victoria-logs +add address=172.18.0.162/24 container-mac-address=20:77:3C:61:F3:94 dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=20:77:3C:61:F3:93 name=\ + veth-app-victoria-metrics +add address=172.18.0.163/24 container-mac-address=6E:B1:F6:2A:2B:BB dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=6E:B1:F6:2A:2B:BA name=\ + veth-app-viseron +add address=172.18.0.164/24 container-mac-address=30:25:73:ED:93:7D dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=30:25:73:ED:93:7C name=\ + veth-app-wallabag +add address=172.18.0.165/24 container-mac-address=7E:43:A5:4C:F8:CC dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=7E:43:A5:4C:F8:CB name=\ + veth-app-warracker +add address=172.18.0.166/24 container-mac-address=5E:78:97:44:FF:BB dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=5E:78:97:44:FF:BA name=\ + veth-app-wbo +add address=172.18.0.167/24 container-mac-address=06:96:D9:F1:19:7F dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=06:96:D9:F1:19:7E name=\ + veth-app-webtop +add address=172.18.0.168/24 container-mac-address=1E:FE:CB:5B:B0:4C dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=1E:FE:CB:5B:B0:4B name=\ + veth-app-wordpress +add address=172.18.0.169/24 container-mac-address=34:67:6E:5B:7D:E7 dhcp=no \ + gateway=172.18.0.1 gateway6="" mac-address=34:67:6E:5B:7D:E6 name=\ + veth-app-zabbix +/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 +/disk +add file-path=/sata1/swap file-size=2046.9MiB slot=file-sata1-swap swap=yes \ + type=file +add slot=ram tmpfs-max-size=100000000 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 +/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/729/f42d43ae\";\r\ + \n:global CommitTAG \"unknown\";\r\ + \n:global CommitInfo \"Autocommit in repo: ros.vados.ru, generated by owne\ + r: root, in 00:05:03 01.07.2026.\";\r\ + \n\r\ + \n# The variables are received right here.\r\ + \n:global GlobalConfVersion 140;\r\ + \n\r\ + \n:global SumsDirAndFileName \"tmp/checksums.json\";\r\ + \n\r\ + \n:global Identity [/system/identity/get name];\r\ + \n:global IdentityShort [:pick \$Identity 0 18];\r\ + \n\r\ + \n:global devBoardName [/system/resource/get board-name];\r\ + \n:global devMode [/system/device-mode/get mode];\r\ + \n:global devCurArch [/system/resource/get architecture-name];\r\ + \n:global devCurVersion [/system/resource/get version];\r\ + \n\r\ + \n# Variables defined in AM-GlobalConfig.rsc\r\ + \n:global TerminalColorOutput;\r\ + \n:global CommentsInScripts;\r\ + \n:global DetectIpAddrDefault;\r\ + \n:global DetectIpAddrFallback;\r\ + \n:global updateChannel;\r\ + \n:global Domain;\r\ + \n:global EmailGeneralTo;\r\ + \n:global BackupAndUpdateMode;\r\ + \n\r\ + \n# Single functions, without nested functions.\r\ + \n:global MiniDateTimeStamp;\r\ + \n:global MicroDateTimeStamp;\r\ + \n\r\ + \n# Include globals \$PrintDebug and \$PrintDebugOverride\r\ + \n:global LogPrint;\r\ + \n\r\ + \n# DeviceInfo and Updates\r\ + \n:global IsCheckUpdates;\r\ + \n:global WaitCheckUpdates;\r\ + \n:global GetPubIp;\r\ + \n\r\ + \n:global GetArrDeviceInfo;\r\ + \n:global WaitArrDeviceInfo;\r\ + \n\r\ + \n:global devModel;\r\ + \n:global devRunningMode;\r\ + \n\r\ + \n:global devRbRevision;\r\ + \n:global devRbSerialNumber;\r\ + \n:global devRbVerAvail;\r\ + \n\r\ + \n:global runningChannelVersion;\r\ + \n:global runningChannel;\r\ + \n:global runningVersion;\r\ + \n\r\ + \n:global devBuildTime;\r\ + \n:global ROsVerAvail;\r\ + \n:global PkgUpdStatus;\r\ + \n:global currentUpdateChannel;\r\ + \n\r\ + \n:global ScriptInstallUpdate;\r\ + \n\r\ + \n:global DeviceInfo;\r\ + \n\r\ + \n:global OldMode;\r\ + \n\r\ + \n:global ParseKeyValueStore;\r\ + \n:global RandomDelay;\r\ + \n:global GetRandomNumber;\r\ + \n:global EscapeForRegEx;\r\ + \n:global CharacterMultiply;\r\ + \n:global CharacterReplace;\r\ + \n:global CleanFilePath;\r\ + \n:global CleanName;\r\ + \n\r\ + \n:global CommitBrief;\r\ + \n\r\ + \n:global EitherOr;\r\ + \n:global FormatLine;\r\ + \n:global GetRandom20CharAlNum;\r\ + \n:global GetRandom20CharHex;\r\ + \n:global GetRandomNumber;\r\ + \n:global Grep;\r\ + \n:global IfThenElse;\r\ + \n:global MAX;\r\ + \n:global MIN;\r\ + \n:global HumanReadableNum;\r\ + \n\r\ + \n:global IsFullyConnected;\r\ + \n:global IsDNSResolving;\r\ + \n:global IsTimeSync;\r\ + \n:global IsTimeSyncCached;\r\ + \n:global IsTimeSyncResetNtp;\r\ + \n\r\ + \n:global MkDir;\r\ + \n:global RmDir;\r\ + \n:global RmFile;\r\ + \n:global FileGet;\r\ + \n:global Unix2Dos;\r\ + \n:global UrlEncode;\r\ + \n:global WaitForFile;\r\ + \n:global ScriptLock;\r\ + \n:global SendTelegram;\r\ + \n:global NotificationFunctions;\r\ + \n:global SendNotification;\r\ + \n:global SendNotification2;\r\ + \n:global SymbolForNotification;\r\ + \n:global SymbolByUnicodeName;\r\ + \n:global ValidateSyntax;\r\ + \n:global CheckSumsVerify;\r\ + \n:global GlobalConfChanges;\r\ + \n:global GlobalConfMigration;\r\ + \n:global VersionToNum;\r\ + \n:global RequiredRouterOS;\r\ + \n:global ExitError;\r\ + \n:global ExitOnError;\r\ + \n\r\ + \n:global FetchHugeFiles;\r\ + \n:global FetchUserAgentStr;\r\ + \n:global FileExists;\r\ + \n:global CertificateAvailable;\r\ + \n:global CertificateDownload;\r\ + \n:global CertificateNameByCN;\r\ + \n:global CharacterMultiply;\r\ + \n\r\ + \n:global InspectVar;\r\ + \n:global InspectVarRet;\r\ + \n:global ParseCustom;\r\ + \n\r\ + \n:set IsCheckUpdates do={\r\ + \n :local isInfo [:tobool \$1];\r\ + \n :global updateChannel;\r\ + \n :global PkgUpdStatus;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n :global arrDeviceInfo;\r\ + \n :log info (\$0 . \" \\\$isInfo = \" . \$isInfo); \r\ + \n :local CurrentChannel [ /system/package/update/get channel ];\r\ + \n :if ([ :len \$updateChannel ] > 0 && \$CurrentChannel != \$updateChann\ + el) do={\r\ + \n :retry command={/system/package/update set channel=\$updateChannel} \ + \_delay=300ms max=5 on-error={};\r\ + \n :log info (\$0 . \" Set updates channel to: \$updateChannel\");\r\ + \n }\r\ + \n :local Update [ /system/package/update/get ];\r\ + \n :local Channel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set currentUpdateChannel \$Channel;\r\ + \n :log info (\$0 . \" Update Channel: \" . \$Channel . \".\");\r\ + \n :local StatusPkg \"undefined\";\r\ + \n :log info (\$0 . \" Checking for updates...\");\r\ + \n :retry command={:set \$StatusPkg ([/system/package/update/check-for-up\ + dates without-paging as-value]->\"status\")} \\\r\ + \n delay=300ms max=5 on-error={};\r\ + \n :log info (\$0 . \" \\\$StatusPkg = \" . \$StatusPkg);\r\ + \n :if (\$StatusPkg = \"New version is available\") do={ :set PkgUpdStatu\ + s true; } else={ :set PkgUpdStatus false; }\r\ + \n :set ROsVerAvail [ :tostr [ /system/package/update/get latest-version \ + ] ];\r\ + \n :log info (\$0 . \" \\\$PkgUpdStatus = \" . \$PkgUpdStatus);\r\ + \n :if (\$isInfo != false || \$PkgUpdStatus = true) do={\r\ + \n :log info (\$0 . \" \\\$PkgUpdStatus = \" . \$PkgUpdStatus);\r\ + \n :if ([ :typeof \$arrDeviceInfo ] != \"array\") do={\r\ + \n :set arrDeviceInfo [:toarray \$arrDeviceInfo];\r\ + \n }\r\ + \n :retry command={:set (\$arrDeviceInfo->\"devUpdates\") [ /system/pac\ + kage/update/get ]} delay=500ms max=5 on-error={:log error (\"Error\")};\r\ + \n :return true;\r\ + \n } else={\r\ + \n :return \$PkgUpdStatus;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set WaitCheckUpdates do={\r\ + \n :global IsCheckUpdates;\r\ + \n :global PkgUpdStatus;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n :global arrDeviceInfo;\r\ + \n :local Status \"\";\r\ + \n :local Update;\r\ + \n :local WaitCount 0;\r\ + \n :if ([ \$IsCheckUpdates true ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n :set Status [ :tostr [ /system/package/update/get status ] ];\r\ + \n :while ((\$Status = \"\" || \$Status = \"finding out latest version...\ + \") && \$WaitCount < 60) do={\r\ + \n :delay 1s;\r\ + \n :set WaitCount (\$WaitCount + 1);\r\ + \n :set Status [ :tostr [ /system/package/update/get status ] ];\r\ + \n }\r\ + \n :set Update [ /system/package/update/get ];\r\ + \n :set currentUpdateChannel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set ROsVerAvail [ :tostr (\$Update->\"latest-version\") ];\r\ + \n :if ((\$Update->\"status\") = \"New version is available\") do={\r\ + \n :set PkgUpdStatus true;\r\ + \n } else={\r\ + \n :set PkgUpdStatus false;\r\ + \n }\r\ + \n :if ([ :typeof \$arrDeviceInfo ] != \"array\") do={\r\ + \n :set arrDeviceInfo [:toarray \$arrDeviceInfo];\r\ + \n }\r\ + \n :set (\$arrDeviceInfo->\"devUpdates\") \$Update;\r\ + \n :if (\$Status = \"\" || \$Status = \"finding out latest version...\") \ + do={\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set WaitArrDeviceInfo do={\r\ + \n :global GetArrDeviceInfo;\r\ + \n :while ([ \$GetArrDeviceInfo ] = false) do={\r\ + \n :delay 1s;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set GetArrDeviceInfo do={\r\ + \n :global LogPrint;\r\ + \n :global arrDeviceInfo;\r\ + \n :global devBoardName;\r\ + \n :global devModel;\r\ + \n :global devRunning;\r\ + \n :global devCurArch;\r\ + \n :global devRbRevision;\r\ + \n :global devRbSerialNumber;\r\ + \n :global devBuildTime;\r\ + \n :global runningChannelVersion;\r\ + \n :global runningChannel;\r\ + \n :global runningVersion;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n\r\ + \n :local DeviceInfo;\r\ + \n :local Resource [/system/resource/get];\r\ + \n :local Update [ /system/package/update/get ];\r\ + \n :local VersionString [ :tostr (\$Resource->\"version\") ];\r\ + \n :local ChannelStart [ :find \$VersionString \" (\" ];\r\ + \n :local RouterBoard;\r\ + \n :local IsRouterBoard false;\r\ + \n :local RunningMode \"\";\r\ + \n\r\ + \n :set devCurArch [ :tostr (\$Resource->\"architecture-name\") ];\r\ + \n :set devBuildTime [ :tostr (\$Resource->\"build-time\") ];\r\ + \n :set runningChannelVersion \$VersionString;\r\ + \n :set runningVersion \$VersionString;\r\ + \n :set runningChannel \"\";\r\ + \n\r\ + \n :if ([ :typeof \$ChannelStart ] = \"num\" && \$ChannelStart >= 0) do=\ + {\r\ + \n :set runningVersion [ :pick \$VersionString 0 \$ChannelStart ];\r\ + \n :local ChannelRest [ :pick \$VersionString (\$ChannelStart + 2) [ :\ + len \$VersionString ] ];\r\ + \n :local ChannelEnd [ :find \$ChannelRest \")\" ];\r\ + \n :if ([ :typeof \$ChannelEnd ] = \"num\" && \$ChannelEnd >= 0) do={\ + \r\ + \n :set runningChannel [ :pick \$ChannelRest 0 \$ChannelEnd ];\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :if ([:pick \$devBoardName 0 3] != \"CHR\" or [:pick \$devBoardName 0\ + \_3] != \"x86\") do={\r\ + \n :do {\r\ + \n :set RouterBoard [[ :parse \"/system/routerboard/get\" ]];\r\ + \n# :set RouterBoard [ /system/routerboard/get ];\r\ + \n :if ((\$RouterBoard->\"routerboard\") = true) do={\r\ + \n :set IsRouterBoard true;\r\ + \n }\r\ + \n } on-error={}\r\ + \n }\r\ + \n\r\ + \n :do {\r\ + \n :set RunningMode [ /system/device-mode/get mode ];\r\ + \n } on-error={\r\ + \n :do {\r\ + \n :set RunningMode [ /system/device-mode/get running ];\r\ + \n } on-error={\r\ + \n :set RunningMode \"\";\r\ + \n }\r\ + \n }\r\ + \n :set devRunning \$RunningMode;\r\ + \n\r\ + \n :if (\$IsRouterBoard = true) do={\r\ + \n :set devModel [ :tostr (\$RouterBoard->\"model\") ];\r\ + \n :set devRbRevision [ :tostr (\$RouterBoard->\"revision\") ];\r\ + \n :set devRbSerialNumber [ :tostr (\$RouterBoard->\"serial-number\") \ + ];\r\ + \n } else={\r\ + \n :set devModel \$devBoardName;\r\ + \n :set devRbRevision \"\";\r\ + \n :set devRbSerialNumber \"\";\r\ + \n }\r\ + \n\r\ + \n :set currentUpdateChannel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set ROsVerAvail [ :tostr (\$Update->\"latest-version\") ];\r\ + \n\r\ + \n :set (\$DeviceInfo->\"board-name\") \$devBoardName;\r\ + \n :set (\$DeviceInfo->\"architecture-name\") \$devCurArch;\r\ + \n :set (\$DeviceInfo->\"model\") \$devModel;\r\ + \n :set (\$DeviceInfo->\"revision\") \$devRbRevision;\r\ + \n :set (\$DeviceInfo->\"serial-number\") \$devRbSerialNumber;\r\ + \n :set (\$DeviceInfo->\"running-mode\") \$devRunning;\r\ + \n :set (\$DeviceInfo->\"build-time\") \$devBuildTime;\r\ + \n :set (\$DeviceInfo->\"running-channel-version\") \$runningChannelVers\ + ion;\r\ + \n :set (\$DeviceInfo->\"running-version\") \$runningVersion;\r\ + \n :set (\$DeviceInfo->\"running-channel\") \$runningChannel;\r\ + \n :set (\$DeviceInfo->\"routerboard\") \$IsRouterBoard;\r\ + \n :set (\$DeviceInfo->\"current-firmware\") [ :tostr (\$RouterBoard->\"\ + current-firmware\") ];\r\ + \n :set (\$DeviceInfo->\"upgrade-firmware\") [ :tostr (\$RouterBoard->\"\ + upgrade-firmware\") ];\r\ + \n :set (\$DeviceInfo->\"package-channel\") \$currentUpdateChannel;\r\ + \n :set (\$DeviceInfo->\"installed-version\") [ :tostr (\$Update->\"inst\ + alled-version\") ];\r\ + \n :set (\$DeviceInfo->\"latest-version\") \$ROsVerAvail;\r\ + \n :set (\$DeviceInfo->\"update-status\") [ :tostr (\$Update->\"status\"\ + ) ];\r\ + \n\r\ + \n :set arrDeviceInfo \$DeviceInfo;\r\ + \n :return \$DeviceInfo;\r\ + \n}\r\ + \n\r\ + \n:set DeviceInfo do={\r\ + \n :global GetArrDeviceInfo;\r\ + \n :global GlobalConfVersion;\r\ + \n :global Identity;\r\ + \n :global IfThenElse;\r\ + \n :global FormatLine;\r\ + \n :global CommitBrief;\r\ + \n\r\ + \n :local License [/system/license/get];\r\ + \n :local Snmp [ /snmp/get ];\r\ + \n :local Info [ \$GetArrDeviceInfo ];\r\ + \n\r\ + \n :if ([ :typeof \$Info ] != \"array\") do={\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :return ( \\\r\ + \n [ \$FormatLine \"Hostname\" \$Identity ] . \"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$Snmp->\"location\") ] > 0) \\\r\ + \n ([ \$FormatLine \"Location\" (\$Snmp->\"location\") ] . \"\\n\") ]\ + \_. \\\r\ + \n [ \$IfThenElse ([ :len (\$Snmp->\"contact\") ] > 0) \\\r\ + \n ([ \$FormatLine \"Contact\" (\$Snmp->\"contact\") ] . \"\\n\") ] .\ + \_\\\r\ + \n \"Hardware:\\n\" . \\\r\ + \n [ \$FormatLine \" Board\" (\$Info->\"board-name\") ] . \"\\n\" . \ + \\\r\ + \n [ \$FormatLine \" Arch\" (\$Info->\"architecture-name\") ] . \"\\\ + n\" . \\\r\ + \n [ \$FormatLine \" Model\" (\$Info->\"model\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"revision\") ] > 0) \\\r\ + \n (\" \" . (\$Info->\"revision\")) ] . \"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"serial-number\") ] > 0) \\\r\ + \n ([ \$FormatLine \" Serial\" (\$Info->\"serial-number\") ] . \"\ + \\n\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$License->\"nlevel\") ] > 0) \\\r\ + \n ([ \$FormatLine \" License\" (\"level \" . (\$License->\"nlevel\ + \")) ] . \"\\n\") ] . \\\r\ + \n \"RouterOS:\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$License->\"level\") ] > 0) \\\r\ + \n ([ \$FormatLine \" License\" (\"level \" . (\$License->\"level\ + \")) ] . \"\\n\") ] . \\\r\ + \n [ \$FormatLine \" Channel\" (\$Info->\"package-channel\") ] . \"\ + \\n\" . \\\r\ + \n [ \$FormatLine \" Installed\" (\$Info->\"installed-version\") ] .\ + \_\"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"running-channel\") ] > 0) \\\r\ + \n ([ \$FormatLine \" Running\" ((\$Info->\"running-version\") . \ + \" (\" . (\$Info->\"running-channel\") . \")\") ] . \"\\n\") \\\r\ + \n ([ \$FormatLine \" Running\" (\$Info->\"running-version\") ] . \ + \"\\n\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"latest-version\") ] > 0 && \\\r\ + \n (\$Info->\"installed-version\") != (\$Info->\"latest-version\"))\ + \_\\\r\ + \n ([ \$FormatLine \" Available\" (\$Info->\"latest-version\") ] .\ + \_\"\\n\") ] . \\\r\ + \n [ \$IfThenElse ((\$Info->\"routerboard\") = true && \\\r\ + \n (\$Info->\"current-firmware\") != (\$Info->\"upgrade-firmware\")\ + ) \\\r\ + \n ([ \$FormatLine \" Firmware\" ((\$Info->\"current-firmware\") .\ + \_\" -> \" . (\$Info->\"upgrade-firmware\")) ] . \"\\n\") ] . \\\r\ + \n \"RouterOS-Scripts:\\n\" . \\\r\ + \n [ \$FormatLine \" Commit\" [ \$CommitBrief ] ] . \"\\n\" . \\\r\ + \n [ \$FormatLine \" Version\" \$GlobalConfVersion ]);\r\ + \n}\r\ + \n\r\ + \n:if ([ :typeof \$NotificationFunctions ] != \"array\") do={:set Notifica\ + tionFunctions ({})}\r\ + \n\r\ + \n:set GetRandom20CharAlNum do={\r\ + \n :global EitherOr;\r\ + \n :return [ :rndstr length=[ \$EitherOr [ :tonum \$1 ] 20 ] from=\"ABCDE\ + FGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\" ];\r\ + \n}\r\ + \n\r\ + \n:set GetRandom20CharHex do={:global EitherOr; :return [ :rndstr length=[\ + \_\$EitherOr [ :tonum \$1 ] 20 ] from=\"0123456789abcdef\" ]; }\r\ + \n:set GetRandomNumber do={:global EitherOr; :return [ :rndnum from=0 to=[\ + \_\$EitherOr [ :tonum \$1 ] 4294967295 ] ]; }\r\ + \n\r\ + \n:global checkRunJob;\r\ + \n:set checkRunJob do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :global ScriptLock; \r\ + \n :if ([ \$ScriptLock \$Script ] = false) do={:return false}\r\ + \n :foreach Job in=[ /system/script/job/find where script=\$Script ] do={\ + :set Job [ /system/script/job/get \$Job ];\r\ + \n :while ([ :typeof (\$Job->\"parent\") ] = \"id\") do={:set Job [ /sy\ + stem/script/job/get [ find where .id=(\$Job->\"parent\") ] ]}\r\ + \n :if ((\$Job->\"type\") = \"login\") do={:return true};}; :return fa\ + lse; \r\ + \n}\r\ + \n\r\ + \n:set InspectVar do={\r\ + \n :global InspectVarRet;\r\ + \n :put [ :tocrlf [ \$InspectVarRet \$1 ] ];\r\ + \n}\r\ + \n\r\ + \n:set CommitBrief do={\r\ + \n :global CommitId;\r\ + \n :global CommitInfo;\r\ + \n :if (\$CommitId = \"unknown\") do={\r\ + \n :return \"unknown\";\r\ + \n }\r\ + \n :return (\$CommitInfo . \"/\" . [ :pick \$CommitId 0 8 ]);\r\ + \n}\r\ + \n\r\ + \n:set InspectVarRet do={\r\ + \n :local Input \$1;\r\ + \n :local Level (0 + [ :tonum \$2 ]);\r\ + \n :global CharacterReplace;\r\ + \n :global IfThenElse;\r\ + \n :global InspectVarRet;\r\ + \n :local IndentReturn do={\r\ + \n :local Prefix [ :tostr \$1 ];\r\ + \n :local Value [ :tostr \$2 ];\r\ + \n :local Level [ :tonum \$3 ];\r\ + \n :global CharacterMultiply;\r\ + \n :return ([ \$CharacterMultiply \" \" (\$Level * 2) ] . \"-\" . \$Pre\ + fix . \"-> \" . \$Value);\r\ + \n }\r\ + \n :local TypeOf [ :typeof \$Input ];\r\ + \n :local Len [ :len \$Input ];\r\ + \n :local Return [ \$IndentReturn \"type\" \$TypeOf \$Level ];\r\ + \n :if (\$TypeOf = \"array\") do={\r\ + \n :foreach Key,Value in=\$Input do={\r\ + \n :set \$Return (\$Return . \"\\n\" . \\\r\ + \n [ \$IndentReturn \"key\" \$Key (\$Level + 1) ] . \"\\n\" . \\\r\ + \n [ \$InspectVarRet \$Value (\$Level + 2) ]);\r\ + \n }\r\ + \n } else={\r\ + \n :if (\$TypeOf = \"str\") do={\r\ + \n :set \$Return (\$Return . \"\\n\" . \\\r\ + \n [ \$IndentReturn \"len\" \$Len \$Level ]);\r\ + \n :if ([ :typeof [ :find \$Input (\"\\r\") ] ] = \"num\") do={\r\ + \n :set Input [ \$CharacterReplace \$Input (\"\\r\") \"\" ];\r\ + \n }\r\ + \n :if ([ :typeof [ :find \$Input (\"\\n\") ] ] = \"num\") do={\r\ + \n :set Input [ \$CharacterReplace \$Input (\"\\n\") \" \" ];\r\ + \n }\r\ + \n }\r\ + \n :if (\$TypeOf != \"nothing\") do={\r\ + \n :set \$Return (\$Return . \"\\n\" . \\\r\ + \n [ \$IndentReturn \"value\" [ \$IfThenElse ([ :len \$Input ] > 80)\ + \_\\\r\ + \n ([ :pick \$Input 0 77 ] . \"...\") \$Input ] \$Level ]);\r\ + \n }\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set GetPubIp do={\r\ + \n :global DetectIpAddrDefault;\r\ + \n :global DetectIpAddrFallback;\r\ + \n\r\ + \n :local PubIpAddr false;\r\ + \n :local Url \$DetectIpAddrDefault;\r\ + \n :local JobName [ :jobname ];\r\ + \n\r\ + \n :do {\r\ + \n :log debug (\$0 . \" Trying to detect public IP using default serv\ + ice: \" . \$Url . \"...\");\r\ + \n :retry command={:set PubIpAddr ([ /tool/fetch http-method=\"get\"\ + \_check-certificate=yes-without-crl \$Url output=user as-value ]->\"data\"\ + )} \\\r\ + \n delay=50ms max=5 on-error={:log error (\$JobName . \" Failed to \ + detect public IP using default service: \" . \$Url . \".\")}\r\ + \n } on-error={\r\ + \n :log error (\$0 . \" Failed to detect public IP using default serv\ + ice: \" . \$Url . \".\");\r\ + \n :set Url \$DetectIpAddrFallBack;\r\ + \n :log debug (\$0 . \" Trying to detect public IP using fallback ser\ + vice: \" . \$Url . \"...\");\r\ + \n :retry command={:set PubIpAddr ([ /tool/fetch http-method=\"get\"\ + \_check-certificate=yes-without-crl \$Url output=user as-value ]->\"data\"\ + )} \\\r\ + \n delay=200ms max=5 on-error={:log error (\$JobName . \" Failed to\ + \_detect public IP using fallback service: \" . \$Url . \".\")}\r\ + \n };\r\ + \n :local IpLen ([ :len \$PubIpAddr ] -1);\r\ + \n :if (\$PubIpAddr = false) do={:set PubIpAddr \"not-detected\"} else=\ + {:set PubIpAddr [:pick \$PubIpAddr 0 \$IpLen]}\r\ + \n :return \$PubIpAddr;\r\ + \n}\r\ + \n\r\ + \n:set FormatLine do={\r\ + \n :local Key [ :tostr \$1 ];\r\ + \n :local Value [ :tostr \$2 ];\r\ + \n :local Indent [ :tonum \$3 ];\r\ + \n :local Spaces;\r\ + \n :local Return \"\";\r\ + \n :global CharacterMultiply;\r\ + \n :global EitherOr;\r\ + \n :set Indent [ \$EitherOr \$Indent 16 ];\r\ + \n :local Spaces [ \$CharacterMultiply \" \" \$Indent ];\r\ + \n :if ([ :len \$Key ] > 0) do={ :set Return (\$Key . \":\")}\r\ + \n :if ([ :len \$Key ] > (\$Indent - 2)) do={:set Return (\$Return . \"\\\ + n\" . [ :pick \$Spaces 0 \$Indent ] . \$Value);\r\ + \n } else={:set Return (\$Return . [ :pick \$Spaces 0 (\$Indent - [ :len \ + \$Return ]) ] . \$Value)}\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set ParseCustom do={\r\ + \n :local Str [ :tostr \$1 ];\r\ + \n :local Start [:find [ \$Str ] [:tostr \$2]];\r\ + \n :local End [ :tostr \$3 ];\r\ + \n :local Num [ :tonum \$4 ];\r\ + \n :local Return;\r\ + \n :if ([:len \$Num] = 0) do={:set Num \"0\"}\r\ + \n :local rest [:pick \$Str (\$Start+\$Num) [:len \$Str]]; \r\ + \n :if ([:len \$End ] = 0) do={:set Return [:pick \$Str \$Num \$Start]} e\ + lse={\r\ + \n :set End [:find \$rest \$End];\r\ + \n :set Return [:pick \$rest 0 \$End];\r\ + \n }\r\ + \n:return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set LogPrint do={\r\ + \n :local Severity [ :tostr \$1 ];\r\ + \n :local Name [ :tostr \$2 ];\r\ + \n :local Message [ :tostr \$3 ];\r\ + \n :global PrintDebug;\r\ + \n :global PrintDebugOverride;\r\ + \n :global EitherOr;\r\ + \n :local Debug [ \$EitherOr (\$PrintDebugOverride->\$Name) \$PrintDebug \ + ];\r\ + \n :local PrintSeverity do={\r\ + \n :global TerminalColorOutput;\r\ + \n :if (\$TerminalColorOutput != true) do={:return \$1}\r\ + \n :local Color { debug=96; info=97; warning=93; error=91 };\r\ + \n :return (\"\\1B[\" . \$Color->\$1 . \"m\" . \$1 . \"\\1B[0m\");\r\ + \n}\r\ + \n :local Log ([ \$EitherOr \$Name \"\" ] . \": \" . \$Message);\ + \r\ + \n :if (\$Severity ~ (\"^(custom|debug|error|info)\\\$\")) do={\r\ + \n :if (\$Severity = \"debug\") do={:log debug \$Log}\r\ + \n :if (\$Severity = \"error\") do={:log error \$Log}\r\ + \n :if (\$Severity = \"info\" ) do={:log info \$Log}\r\ + \n } else={:log warning \$Log; :set Severity \"warning\"}\r\ + \n :if (\$Severity != \"debug\" || \$Debug = true) do={:put ([ \$PrintSev\ + erity \$Severity ] . \": \" . \$Message)}\r\ + \n}\r\ + \n\r\ + \n:set CertificateAvailable do={\r\ + \n :local CommonName [ :tostr \$1 ];\r\ + \n :local UseFor [ :tostr \$2 ];\r\ + \n\r\ + \n :global CertificateDownload;\r\ + \n :global ParseKeyValueStore;\r\ + \n\r\ + \n :if ([ :len \$UseFor ] = 0) do={\r\ + \n :log warning (\$0 . \"The intended use is undefined!\");\r\ + \n :set UseFor \"undefined\";\r\ + \n }\r\ + \n :if ([ /system/resource/get free-hdd-space ] < 8388608 && \\\r\ + \n [ /certificate/settings/get crl-download ] = true && \\\r\ + \n [ /certificate/settings/get crl-store ] = \"system\") do={\r\ + \n :log warning (\$0 . \"This system has low free flash space but \" . \ + \\\r\ + \n \"is configured to download certificate CRLs to system!\");\r\ + \n }\r\ + \n :if ([ :len \$CommonName ] = 0) do={\r\ + \n :log warning (\$0 . \"No CommonName given!\");\r\ + \n :return false;\r\ + \n }\r\ + \n :local CertSettings [ /certificate/settings/get ];\r\ + \n :if (((\$CertSettings->\"builtin-trust-anchors\") = \"trusted\" || \\\ + \r\ + \n (\$CertSettings->\"builtin-trust-store\") ~ \$UseFor || \\\r\ + \n (\$CertSettings->\"builtin-trust-store\") = \"all\") && \\\r\ + \n [ :len [ /certificate/builtin/find where common-name=\$CommonName\ + \_] ] > 0) do={\r\ + \n :return true;\r\ + \n }\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] = 0\ + ) do={\r\ + \n :log info (\$0 . \"Certificate with CommonName '\" . \$CommonName . \ + \"' not available.\");\r\ + \n :if ([ \$CertificateDownload \$CommonName ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] > 1\ + ) do={\r\ + \n :log info (\$0 . \"There are \" . \$CertCount . \" Certificates with\ + \_CommonName '\" . \$CommonName . \"'. Should be ok.\");\r\ + \n :return true;\r\ + \n }\r\ + \n :local CertVal [ /certificate/get [ find where common-name=\$CommonNam\ + e ] ];\r\ + \n :while ((\$CertVal->\"akid\") != \"\" && (\$CertVal->\"akid\") != (\$C\ + ertVal->\"skid\")) do={\r\ + \n :if ([ :len [ /certificate/find where skid=(\$CertVal->\"akid\") ] ]\ + \_= 0) do={\r\ + \n :local IssuerCN ([ \$ParseKeyValueStore (\$CertVal->\"issuer\") ]-\ + >\"CN\");\r\ + \n :log info (\$0 . \"Certificate chain for '\" . \$CommonName . \"' \ + is incomplete, missing '\" . \$IssuerCN . \"'.\");\r\ + \n :if ([ \$CertificateDownload \$IssuerCN ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n :set CertVal [ /certificate/get [ find where skid=(\$CertVal->\"akid\ + \") ] ];\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set CertificateDownload do={\r\ + \n :local CommonName [ :tostr \$1 ];\r\ + \n :global ScriptUpdatesBaseUrl;\r\ + \n :global ScriptUpdatesUrlSuffix;\r\ + \n :global CertificateNameByCN;\r\ + \n :global CleanName;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global RmFile;\r\ + \n :global WaitForFile;\r\ + \n\r\ + \n :log info (\$0 . \"Downloading and importing certificate with \" . \\\ + \r\ + \n \"CommonName '\" . \$CommonName . \"'.\");\r\ + \n :local FileName ([ \$CleanName \$CommonName ] . \".pem\");\r\ + \n :do {\r\ + \n /tool/fetch check-certificate=yes-without-crl mode=https http-header\ + -field=({ [ \$FetchUserAgentStr \$0 ] }) \\\r\ + \n (\$ScriptUpdatesBaseUrl . \"certs/\" . \$FileName . \$ScriptUpdate\ + sUrlSuffix) \\\r\ + \n dst-path=\$FileName as-value;\r\ + \n \$WaitForFile \$FileName;\r\ + \n } on-error={\r\ + \n :log warning (\$0 . \" Failed downloading certificate with CommonNam\ + e '\" . \$CommonName . \\\r\ + \n \"' from repository! Trying fallback to mkcert.org...\");\r\ + \n :do {\r\ + \n :local CertSettings [ /certificate/settings/get ];\r\ + \n :if ([ :len [ /certificate/find where common-name=\"ISRG Root X1\"\ + \_] ] = 0 && \\\r\ + \n !(((\$CertSettings->\"builtin-trust-anchors\") = \"trusted\" \ + || \\\r\ + \n (\$CertSettings->\"builtin-trust-store\") ~ \"fetch\" || \ + \\\r\ + \n (\$CertSettings->\"builtin-trust-store\") = \"all\") && \\\ + \r\ + \n [ :len [ /certificate/builtin/find where common-name=\"ISRG\ + \_Root X1\" ] ] > 0)) do={\r\ + \n :log error (\$0 . \" Required certificate is not available.\");\ + \r\ + \n :return false;\r\ + \n }\r\ + \n /tool/fetch check-certificate=yes-without-crl mode=https http-head\ + er-field=({ [ \$FetchUserAgentStr \$0 ] }) \\\r\ + \n url=\"https://mkcert.org/generate/\" http-data=[ :serialize to=jso\ + n ({ \$CommonName }) ] \\\r\ + \n dst-path=\$FileName as-value;\r\ + \n \$WaitForFile \$FileName;\r\ + \n :if ([ /file/get \$FileName size ] = 0) do={\r\ + \n \$RmFile \$FileName;\r\ + \n :error false;\r\ + \n }\r\ + \n } on-error={\r\ + \n :log error (\$0 . \" Failed downloading certificate with CommonNam\ + e '\" . \$CommonName . \"'!\");\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n /certificate/import file-name=\$FileName passphrase=\"\" as-value;\r\ + \n :delay 1s;\r\ + \n \$RmFile \$FileName;\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] = 0\ + ) do={\r\ + \n /certificate/remove [ find where name~(\"^\" . \$FileName . \"_[0-9]\ + +\\\$\") ];\r\ + \n :log warning (\$0 . \" Certificate with CommonName '\" . \$CommonNam\ + e . \"' still unavailable!\");\r\ + \n :return false;\r\ + \n }\r\ + \n :foreach Cert in=[ /certificate/find where name~(\"^\" . \$FileName . \ + \"_[0-9]+\\\$\") ] do={\r\ + \n \$CertificateNameByCN [ /certificate/get \$Cert common-name ];\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set CertificateNameByCN do={\r\ + \n :local Match [ :tostr \$1 ];\r\ + \n :global CleanName;\r\ + \n :local Cert ([ /certificate/find where (common-name=\$Match or fingerp\ + rint=\$Match or name=\$Match) ]->0);\r\ + \n :if ([ :len \$Cert ] = 0) do={\r\ + \n :log warning (\$0 .\" No matching certificate found.\");\r\ + \n :return false;\r\ + \n }\r\ + \n :local CommonName [ /certificate/get \$Cert common-name ];\r\ + \n /certificate/set \$Cert name=[ \$CleanName \$CommonName ];\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set CharacterMultiply do={\r\ + \n :local Str [ :tostr \$1 ];\r\ + \n :local Num [ :tonum \$2 ];\r\ + \n :if (\$Num = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :for I from=1 to=\$Num do={:set Return (\$Return . \$Str)}\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set FileExists do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :local Type [ :tostr \$2 ];\r\ + \n :global FileGet;\r\ + \n :local FileVal [ \$FileGet \$FileName ];\r\ + \n :if (\$FileVal = false) do={ :return false; }\r\ + \n :if ([ :len (\$FileVal->\"size\") ] = 0) do={ :return false; }\r\ + \n :if ([ :len \$Type ] = 0 || \$FileVal->\"type\" = \$Type) do={ :return\ + \_true; }\r\ + \n :return false;\r\ + \n}\r\ + \n\r\ + \n:set Grep do={\r\ + \n :local Input ([ :tostr \$1 ] . \"\\n\");\r\ + \n :local Pattern [ :tostr \$2 ];\r\ + \n :if ([ :typeof [ :find \$Input \$Pattern ] ] = \"nil\") do={:return []\ + }\r\ + \n :do {\r\ + \n :local Line [ :pick \$Input 0 [ :find \$Input \"\\n\" ] ];\r\ + \n :if ([ :typeof [ :find \$Line \$Pattern ] ] = \"num\") do={:return \ + \$Line}\r\ + \n :set Input [ :pick \$Input ([ :find \$Input \"\\n\" ] + 1) [ :len \$\ + Input ] ];\r\ + \n } while=([ :len \$Input ] > 0);\r\ + \n :return [];\r\ + \n}\r\ + \n\r\ + \n:set HumanReadableNum do={\r\ + \n :local Input [ :tonum \$1 ];\r\ + \n :local Base [ :tonum \$2 ];\r\ + \n :global EitherOr;\r\ + \n :global IfThenElse;\r\ + \n :local Prefix \"kMGTPE\";\r\ + \n :local Pow 1;\r\ + \n :set Base [ \$EitherOr \$Base 1024 ];\r\ + \n :local Bin [ \$IfThenElse (\$Base = 1024) \"i\" \"\" ];\r\ + \n :if (\$Input < \$Base) do={:return \$Input}\r\ + \n :for I from=0 to=[ :len \$Prefix ] do={\r\ + \n :set Pow (\$Pow * \$Base);\r\ + \n :if (\$Input / \$Base < \$Pow) do={\r\ + \n :set Prefix [ :pick \$Prefix \$I ];\r\ + \n :local Tmp1 (\$Input * 100 / \$Pow);\r\ + \n :local Tmp2 (\$Tmp1 / 100);\r\ + \n :if (\$Tmp2 >= 100) do={:return (\$Tmp2 . \$Prefix . \$Bin)}\r\ + \n :return (\$Tmp2 . \".\" . \\\r\ + \n [ :pick \$Tmp1 [ :len \$Tmp2 ] ([ :len \$Tmp1 ] - [ :len \$Tmp\ + 2 ] + 1) ] . \\\r\ + \n \$Prefix . \$Bin);\r\ + \n }\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set CleanFilePath do={\r\ + \n :local Path [ :tostr \$1 ];\r\ + \n :global CharacterReplace;\r\ + \n :while (\$Path ~ \"//\") do={ :set \$Path [ \$CharacterReplace \$Path \ + \"//\" \"/\" ]; }\r\ + \n :if ([ :pick \$Path 0 ] = \"/\") do={ :set Path [ :pick \$Path 1 [ :le\ + n \$Path ] ]; }\r\ + \n :if ([ :pick \$Path ([ :len \$Path ] - 1) ] = \"/\") do={ :set Path [ \ + :pick \$Path 0 ([ :len \$Path ] - 1) ]; }\r\ + \n :return \$Path;\r\ + \n}\r\ + \n\r\ + \n:set CleanName do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :local Return \"\";\r\ + \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ + \n :local Char [ :pick \$Input \$I ];\r\ + \n :if ([ :typeof [ find \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr\ + stuvwxyz0123456789\" \$Char ] ] = \"nil\") do={\r\ + \n :do {:if ([ :len \$Return ] = 0) do={:error true};\r\ + \n :if ([ :pick \$Return ([ :len \$Return ] - 1) ] = \"-\") do={:er\ + ror true}; :set Char \"-\"} on-error={:set Char \"\"}; \r\ + \n };\r\ + \n :set Return (\$Return . \$Char)};\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set RandomDelay do={\r\ + \n :local Time [ :tonum \$1 ];\r\ + \n :local Unit [ :tostr \$2 ];\r\ + \n :global EitherOr;\r\ + \n :global GetRandomNumber;\r\ + \n :global MAX;\r\ + \n :if (\$Time = 0) do={:return false}\r\ + \n :delay ([ \$MAX 10 [ \$GetRandomNumber ([ :tonsec [ :totime (\$Time . \ + [ \$EitherOr \$Unit \"s\" ]) ] ] / 1000000) ] ] . \"ms\");\r\ + \n}\r\ + \n\r\ + \n:set EscapeForRegEx do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :if ([ :len \$Input ] = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :local Chars (\"^.[]\\\$()|*+\?{}\\\\\");\r\ + \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ + \n :local Char [ :pick \$Input \$I ];\r\ + \n :if ([ :find \$Chars \$Char ]) do={:set Char (\"\\\\\" . \$Char)}\r\ + \n :set Return (\$Return . \$Char);\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set ExitError do={\r\ + \n :local ExitOK [ :tostr \$1 ];\r\ + \n :local Name [ :tostr \$2 ];\r\ + \n :local Error [ :tostr \$3 ];\r\ + \n :global IfThenElse;\r\ + \n :if (\$ExitOK = \"false\") do={\r\ + \n :log error (\$Name [ \$IfThenElse ([ :pick \$Name 0 1 ] = \"\\\$\") \ + \\\r\ + \n \"Function\" \"Script\" ] . \" '\" . \$Name . \"' exited with er\ + ror\" . \\\r\ + \n [ \$IfThenElse (!(\$Error ~ \"^(|true|false)\\\$\")) (\": \" . \ + \$Error) \".\" ]);\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set ExitOnError do={\r\ + \n :local Name [ :tostr \$1 ];\r\ + \n :local Error [ :tostr \$2 ];\r\ + \n :global IfThenElse;\r\ + \n :log error (\$Name . \" \" . [ \$IfThenElse ([ :pick \$Name 0 1 ] = \"\ + \\\$\") \\\r\ + \n \"Function\" \"Script\" ] . \" '\" . \$Name . \"' exited with erro\ + r\" . \\\r\ + \n [ \$IfThenElse (!(\$Error ~ \"^(|true|false)\\\$\")) (\": \" . \$E\ + rror) \".\" ]);\r\ + \n}\r\ + \n\r\ + \n:set MiniDateTimeStamp do={\r\ + \n :local mikro [ :tobool \$1 ];\r\ + \n /system/clock;\r\ + \n :local vdate [get date];\r\ + \n :local vtime [get time];\r\ + \n :local vdoff [:toarray \"0,4,5,7,8,10\"];\r\ + \n :local MM [:pick \$vdate (\$vdoff->2) (\$vdoff->3)];\r\ + \n :local M [:tonum \$MM];\r\ + \n :if (\$vdate ~ \".../../....\") do={\r\ + \n :set vdoff [:toarray \"7,11,1,3,4,6\"];\r\ + \n :set M ([:find \"xxanebarprayunulugepctovecANEBARPRAYUNULUGE\ + PCTOVEC\" [:pick \$vdate (\$vdoff->2) (\$vdoff->3)] -1] / 2);\r\ + \n :if (\$M>12) do={:set M (\$M - 12)}\r\ + \n :set MM [:pick (100 + \$M) 1 3];\r\ + \n }\r\ + \n :local yyyy [:pick \$vdate (\$vdoff->0) (\$vdoff->1)];\r\ + \n :local dd [:pick \$vdate (\$vdoff->4) (\$vdoff->5)];\r\ + \n :local HH [:pick \$vtime 0 2];\r\ + \n :local mm [:pick \$vtime 3 5];\r\ + \n :local ss [:pick \$vtime 6 8];\r\ + \n :local Return;\r\ + \n :if (\$mikro = true) do={\r\ + \n :set Return ([:pick \$yyyy 2 4] . [:pick \$dd 0 1] . [:pick \$HH 0\ + \_1] . [:pick \$mm 3 4] . [:pick \$ss 6 7]);\r\ + \n } else={\r\ + \n :set Return ([\$yyyy] . [\$MM] . [\$dd] . [\$HH] . [\$mm] . [\$ss]);\ + \r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set WaitForFile do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :local WaitTime [ :totime \$2 ];\r\ + \n :global CleanFilePath;\r\ + \n :global EitherOr;\r\ + \n :global MAX;\r\ + \n :set FileName [ \$CleanFilePath \$FileName ];\r\ + \n :local Delay ([ \$MAX [ \$EitherOr \$WaitTime 2s ] 100ms ] / 9);\r\ + \n :do {\r\ + \n :retry {\r\ + \n /file/get \$FileName;\r\ + \n :return true;\r\ + \n } delay=\$Delay max=10;\r\ + \n } on-error={ }\r\ + \n :while ([ :len [ /file/find where name=\$FileName ] ] > 0) do={\r\ + \n :do {\r\ + \n /file/get \$FileName;\r\ + \n :return true;\r\ + \n } on-error={ }\r\ + \n :delay \$Delay;\r\ + \n :set Delay (\$Delay * 3 / 2);\r\ + \n }\r\ + \n :return false;\r\ + \n}\r\ + \n\r\ + \n:set FileGet do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :global WaitForFile;\r\ + \n :if ([ \$WaitForFile \$FileName 0s ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n :local FileVal false;\r\ + \n :do {\r\ + \n :set FileVal [ /file/get \$FileName ];\r\ + \n } on-error={ }\r\ + \n :return \$FileVal;\r\ + \n}\r\ + \n\r\ + \n:set RmDir do={\r\ + \n :local DirName [ :tostr \$1 ];\r\ + \n :global FileGet;\r\ + \n :log debug (\$0 . \" Removing directory: \". \$DirName);\r\ + \n :local DirVal [ \$FileGet \$DirName ];\r\ + \n :if (\$DirVal = false) do={\r\ + \n :log debug (\$0 . \" ... which does not exist.\");\r\ + \n :return true;\r\ + \n };\r\ + \n :if (\$DirVal->\"type\" != \"directory\") do={\r\ + \n :log error (\$0 . \" Directory '\" . \$DirName . \"' is not a direct\ + ory.\");\r\ + \n :return false;\r\ + \n };\r\ + \n :onerror Err {\r\ + \n /file/remove \$DirName;\r\ + \n } do={\r\ + \n :log error (\$0 . \" Removing directory '\" . \$DirName . \"' failed\ + : \" . \$Err);\r\ + \n :return false;\r\ + \n };\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set RmFile do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :global FileGet;\r\ + \n :log debug (\$0 . \" Removing file: \". \$FileName);\r\ + \n :local FileVal [ \$FileGet \$FileName ];\r\ + \n :if (\$FileVal = false) do={\r\ + \n :log debug (\$0 . \" ... which does not exist.\");\r\ + \n :return true;\r\ + \n }\r\ + \n :if (\$FileVal->\"type\" = \"directory\" || \$FileVal->\"type\" = \"di\ + sk\") do={\r\ + \n :log error (\$0 . \" File '\" . \$FileName . \"' is not a file.\");\ + \r\ + \n :return false;\r\ + \n }\r\ + \n :onerror Err {\r\ + \n /file/remove \$FileName;\r\ + \n } do={\r\ + \n :log error (\$0 . \" Removing file '\" . \$FileName . \"' failed: \"\ + \_. \$Err); :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set MkDir do={\r\ + \n :local Path [ :tostr \$1 ];\r\ + \n :global CleanFilePath;\r\ + \n :global FileGet;\r\ + \n :global RmDir;\r\ + \n :global WaitForFile;\r\ + \n\r\ + \n :local MkTmpfs do={\r\ + \n :global WaitForFile;\r\ + \n :local TmpFs [ /disk/find where slot=tmpfs type=tmpfs ];\r\ + \n :if ([ :len \$TmpFs ] = 1) do={\r\ + \n :if ([ /disk/get \$TmpFs disabled ] = true) do={\r\ + \n :log info (\$0 . \" The tmpfs is disabled, enabling.\");\r\ + \n /disk/enable \$TmpFs;\r\ + \n }\r\ + \n :return true;\r\ + \n }\r\ + \n :log info (\$0 . \" Creating disk of type tmpfs.\");\r\ + \n \$RmDir \"tmpfs\";\r\ + \n :onerror Err {\r\ + \n /disk/add slot=tmpfs type=tmpfs tmpfs-max-size=([ /system/resource\ + /get total-memory ] / 3);\r\ + \n \$WaitForFile \"tmpfs\";\r\ + \n } do={\r\ + \n :log warning (\$0 . \" Creating disk of type tmpfs failed: \" . \$\ + Err);\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n }\r\ + \n :set Path [ \$CleanFilePath \$Path ];\r\ + \n :if (\$Path = \"\") do={\r\ + \n :return true;\r\ + \n }\r\ + \n :log debug (\$0 . \" Making directory: \" . \$Path);\r\ + \n :local PathVal [ \$FileGet \$Path ];\r\ + \n :if (\$PathVal->\"type\" = \"directory\") do={\r\ + \n :log debug (\$0 . \" ... which already exists.\");\r\ + \n :return true;\r\ + \n }\r\ + \n :if ([ :pick \$Path 0 5 ] = \"tmpfs\") do={\r\ + \n :if ([ \$MkTmpfs ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n :onerror Err {\r\ + \n /file/add type=\"directory\" name=\$Path;\r\ + \n \$WaitForFile \$Path;\r\ + \n } do={\r\ + \n :log warning (\$0 . \" Making directory '\" . \$Path . \"' failed: \ + \" . \$Err);\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set MAX do={:if (\$1 > \$2) do={:return \$1}\r\ + \n :return \$2;\r\ + \n}\r\ + \n:set MIN do={:if (\$1 < \$2) do={:return \$1}\r\ + \n :return \$2;\r\ + \n}\r\ + \n\r\ + \n:set CharacterMultiply do={\r\ + \n :local Str [ :tostr \$1 ];\r\ + \n :local Num [ :tonum \$2 ];\r\ + \n :if (\$Num = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :for I from=1 to=\$Num do={:set Return (\$Return . \$Str)}\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set CharacterReplace do={\r\ + \n :local String [ :tostr \$1 ];\r\ + \n :local ReplaceFrom [ :tostr \$2 ];\r\ + \n :local ReplaceWith [ :tostr \$3 ];\r\ + \n :local Return \"\";\r\ + \n :if (\$ReplaceFrom = \"\") do={:return \$String}\r\ + \n :while ([ :typeof [ :find \$String \$ReplaceFrom ] ] != \"nil\") do={\ + \r\ + \n :local Pos [ :find \$String \$ReplaceFrom ];\r\ + \n :set Return (\$Return . [ :pick \$String 0 \$Pos ] . \$ReplaceWith);\ + \r\ + \n :set String [ :pick \$String (\$Pos + [ :len \$ReplaceFrom ]) [ :len\ + \_\$String ] ];\r\ + \n }\r\ + \n :return (\$Return . \$String);\r\ + \n}\r\ + \n\r\ + \n:set IfThenElse do={\r\ + \n :if ([ :tostr \$1 ] = \"true\" || [ :tobool \$1 ] = true) do={:return \ + \$2};\r\ + \n :return \$3;\r\ + \n}\r\ + \n\r\ + \n:set EitherOr do={\r\ + \n :global IfThenElse;\r\ + \n :if ([ :typeof \$1 ] = \"num\") do={:return [ \$IfThenElse (\$1 != 0) \ + \$1 \$2 ]}\r\ + \n :if ([ :typeof \$1 ] = \"time\") do={:return [ \$IfThenElse (\$1 > 0s)\ + \_\$1 \$2 ]}\r\ + \n# this works for boolean values, literal ones with parentheses\r\ + \n :return [ \$IfThenElse ([ :len [ :tostr \$1 ] ] > 0) \$1 \$2 ];\r\ + \n}\r\ + \n\r\ + \n:set ParseKeyValueStore do={\r\ + \n :local Source \$1;\r\ + \n :if ([ :pick \$Source 0 1 ] = \"{\") do={\r\ + \n :do {\r\ + \n :return [ :deserialize from=json \$Source ];\r\ + \n } on-error={ }\r\ + \n } \r\ + \n :if ([ :typeof \$Source ] != \"array\") do={:set Source [ :tostr \$1 ]\ + }\r\ + \n :local Result ({});\r\ + \n :foreach KeyValue in=[ :toarray \$Source ] do={\r\ + \n :if ([ :find \$KeyValue \"=\" ]) do={\r\ + \n :local Key [ :pick \$KeyValue 0 [ :find \$KeyValue \"=\" ] ];\r\ + \n :local Value [ :pick \$KeyValue ([ :find \$KeyValue \"=\" ] + 1) [\ + \_:len \$KeyValue ] ];\r\ + \n :if (\$Value=\"true\") do={:set Value true}\r\ + \n :if (\$Value=\"false\") do={:set Value false}\r\ + \n :set (\$Result->\$Key) \$Value;\r\ + \n } else={:set (\$Result->\$KeyValue) true}\r\ + \n }\r\ + \n :return \$Result;\r\ + \n}\r\ + \n:set RequiredRouterOS do={\r\ + \n :local Caller [ :tostr \$1 ];\r\ + \n :local Required [ :tostr \$2 ];\r\ + \n :local Warn [ :tostr \$3 ];\r\ + \n :global IfThenElse;\r\ + \n :global VersionToNum;\r\ + \n :if (!(\$Required ~ \"^\\\\d+\\\\.\\\\d+((alpha|beta|rc|\\\\.)\\\\d+|)\ + \\\$\")) do={\r\ + \n :log error (\$0 . \" No valid RouterOS version: \" . \$Required);\r\ + \n :return false;\r\ + \n }\r\ + \n :if ([ \$VersionToNum \$Required ] > [ \$VersionToNum [ /system/packag\ + e/update/get installed-version ] ]) do={\r\ + \n :if (\$Warn = \"true\") do={\r\ + \n :log warning (\$0 . \" This \" . [ \$IfThenElse ([ :pick \$Caller \ + 0 ] = (\"\\\$\")) \"function\" \"script\" ] . \\\r\ + \n \" '\" . \$Caller . \"' (at least specific functionality) requir\ + es RouterOS \" . \$Required . \". Please update!\");\r\ + \n }\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set ValidateSyntax do={\r\ + \n :local Code [ :tostr \$1 ];\r\ + \n :global LogPrint;\r\ + \n :onerror Err {\r\ + \n [ :parse (\":local Validate do={\\n\" . \$Code . \"\\n}\") ];\r\ + \n } do={\r\ + \n \$LogPrint debug \$0 (\"Valdation failed: \" . \$Err);\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set VersionToNum do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :local Multi 0x1000000;\r\ + \n :local Return 0;\r\ + \n :global CharacterReplace;\r\ + \n :set Input [ \$CharacterReplace \$Input \".\" \",\" ];\r\ + \n :foreach I in={ \"zero\"; \"alpha\"; \"beta\"; \"rc\" } do={\r\ + \n :set Input [ \$CharacterReplace \$Input \$I (\",\" . \$I . \",\") ];\ + \r\ + \n }\r\ + \n :foreach Value in=([ :toarray \$Input ], 0) do={\r\ + \n :local Num [ :tonum \$Value ];\r\ + \n :if (\$Multi = 0x100) do={\r\ + \n :if ([ :typeof \$Num ] = \"num\") do={\r\ + \n :set Return (\$Return + 0xff00);\r\ + \n :set Multi (\$Multi / 0x100);\r\ + \n } else={\r\ + \n :if (\$Value = \"zero\") do={ }\r\ + \n :if (\$Value = \"alpha\") do={ :set Return (\$Return + 0x3f00); \ + }\r\ + \n :if (\$Value = \"beta\") do={ :set Return (\$Return + 0x5f00); }\ + \r\ + \n :if (\$Value = \"rc\") do={ :set Return (\$Return + 0x7f00); }\r\ + \n }\r\ + \n }\r\ + \n :if ([ :typeof \$Num ] = \"num\") do={ :set Return (\$Return + (\$Va\ + lue * \$Multi)); }\r\ + \n :set Multi (\$Multi / 0x100);\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set ScriptLock do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local WaitMax [ :totime \$2 ];\r\ + \n :global GetRandom20CharAlNum;\r\ + \n :global IfThenElse;\r\ + \n :global ScriptLockOrder;\r\ + \n :if ([ :typeof \$ScriptLockOrder ] = \"nothing\") do={\r\ + \n :set ScriptLockOrder ({});\r\ + \n }\r\ + \n :if ([ :typeof (\$ScriptLockOrder->\$Script) ] = \"nothing\") do={\r\ + \n :set (\$ScriptLockOrder->\$Script) ({});\r\ + \n }\r\ + \n :local JobCount do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :return [ :len [ /system/script/job/find where script=\$Script ] ];\ + \r\ + \n }\r\ + \n :local TicketCount do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :local Count 0;\r\ + \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :if ([ :typeof \$Ticket ] != \"nothing\") do={:set Count (\$Count \ + + 1)}\r\ + \n }\r\ + \n :return \$Count;\r\ + \n }\r\ + \n :local IsFirstTicket do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local Check [ :tostr \$2 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :if (\$Ticket = \$Check) do={:return true}\r\ + \n :if ([ :typeof \$Ticket ] != \"nothing\" && \$Ticket != \$Check) d\ + o={:return false}\r\ + \n }\r\ + \n :return false;\r\ + \n }\r\ + \n :local AddTicket do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local Add [ :tostr \$2 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :while (true) do={\r\ + \n :local Pos [ :len (\$ScriptLockOrder->\$Script) ];\r\ + \n :set (\$ScriptLockOrder->\$Script->\$Pos) \$Add;\r\ + \n :delay 10ms;\r\ + \n :if ((\$ScriptLockOrder->\$Script->\$Pos) = \$Add) do={:return tru\ + e}\r\ + \n }\r\ + \n }\r\ + \n :local RemoveTicket do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local Remove [ :tostr \$2 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :foreach Id,Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :while ((\$ScriptLockOrder->\$Script->\$Id) = \$Remove) do={\r\ + \n :set (\$ScriptLockOrder->\$Script->\$Id);\r\ + \n :delay 10ms;\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n :local CleanupTickets do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :if ([ :typeof \$Ticket ] != \"nothing\") do={:return false}\r\ + \n }\r\ + \n :set (\$ScriptLockOrder->\$Script) ({});\r\ + \n }\r\ + \n :if ([ :typeof \$WaitMax ] = \"nil\" ) do={:set WaitMax 0s}\r\ + \n :if ([ :len [ /system/script/find where name=\$Script ] ] = 0) do={\r\ + \n :log error (\$0 . \" A script named '\" . \$Script . \"' does not ex\ + ist!\");\r\ + \n :error false;\r\ + \n }\r\ + \n :if ([ \$JobCount \$Script ] = 0) do={\r\ + \n \$LogPrint error \$0 (\"No script '\" . \$Script . \"' is running!\"\ + );\r\ + \n :error false;\r\ + \n }\r\ + \n :if ([ \$TicketCount \$Script ] >= [ \$JobCount \$Script ]) do={\r\ + \n :log error (\$0 . \" More tickets than running scripts '\" . \$Scrip\ + t . \"', resetting!\");\r\ + \n :set (\$ScriptLockOrder->\$Script) ({});\r\ + \n /system/script/job/remove [ find where script=\$Script ];\r\ + \n }\r\ + \n :local MyTicket [ \$GetRandom20CharAlNum 6 ];\r\ + \n \$AddTicket \$Script \$MyTicket;\r\ + \n :local WaitInterval (\$WaitMax / 20);\r\ + \n :local WaitTime \$WaitMax;\r\ + \n :while (\$WaitTime > 0 && \\\r\ + \n ([ \$IsFirstTicket \$Script \$MyTicket ] = false || \\\r\ + \n [ \$TicketCount \$Script ] < [ \$JobCount \$Script ])) do={\r\ + \n :set WaitTime (\$WaitTime - \$WaitInterval);\r\ + \n :delay \$WaitInterval;\r\ + \n }\r\ + \n :if ([ \$IsFirstTicket \$Script \$MyTicket ] = true && \\\r\ + \n [ \$TicketCount \$Script ] = [ \$JobCount \$Script ]) do={\r\ + \n \$RemoveTicket \$Script \$MyTicket;\r\ + \n \$CleanupTickets \$Script;\r\ + \n :return true;\r\ + \n }\r\ + \n \$RemoveTicket \$Script \$MyTicket;\r\ + \n \$LogPrint debug \$0 (\"Script '\" . \$Script . \"' started more than \ + once\" . \\\r\ + \n [ \$IfThenElse (\$WaitTime < \$WaitMax) \" and timed out waiting for\ + \_lock\" \"\" ] . \"...\");\r\ + \n :return false;\r\ + \n}\r\ + \n\r\ + \n:set SendNotification do={ :onerror Err {\r\ + \n :global SendNotification2;\r\ + \n \$SendNotification2 ({ origin=\$0; subject=\$1; message=\$2; link=\$3;\ + \_silent=\$4 });\r\ + \n} do={:global ExitOnError; \$ExitOnError \$0 \$Err}\r\ + \n}\r\ + \n\r\ + \n:set SendNotification2 do={\r\ + \n :local Notification \$1;\r\ + \n :global NotificationFunctions;\r\ + \n :foreach FunctionName,Discard in=\$NotificationFunctions do={\r\ + \n (\$NotificationFunctions->\$FunctionName) (\"\\\$NotificationFunctio\ + ns->\\\"\" . \$FunctionName . \"\\\"\") \$Notification;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set SymbolByUnicodeName do={\r\ + \n :local Name [ :tostr \$1 ];\r\ + \n :global EitherOr;\r\ + \n :global SymbolsExtra;\r\ + \n :local Symbols ({\r\ + \n \"abacus\"=\"\\F0\\9F\\A7\\AE\";\r\ + \n \"alarm-clock\"=\"\\E2\\8F\\B0\";\r\ + \n \"arrow-down\"=\"\\E2\\AC\\87\";\r\ + \n \"arrow-up\"=\"\\E2\\AC\\86\";\r\ + \n \"calendar\"=\"\\F0\\9F\\93\\85\";\r\ + \n \"card-file-box\"=\"\\F0\\9F\\97\\83\";\r\ + \n \"chart-decreasing\"=\"\\F0\\9F\\93\\89\";\r\ + \n \"chart-increasing\"=\"\\F0\\9F\\93\\88\";\r\ + \n \"cloud\"=\"\\E2\\98\\81\";\r\ + \n \"cross-mark\"=\"\\E2\\9D\\8C\";\r\ + \n \"earth\"=\"\\F0\\9F\\8C\\8D\";\r\ + \n \"fire\"=\"\\F0\\9F\\94\\A5\";\r\ + \n \"floppy-disk\"=\"\\F0\\9F\\92\\BE\";\r\ + \n \"gear\"=\"\\E2\\9A\\99\";\r\ + \n \"heart\"=\"\\E2\\99\\A5\";\r\ + \n \"high-voltage-sign\"=\"\\E2\\9A\\A1\";\r\ + \n \"incoming-envelope\"=\"\\F0\\9F\\93\\A8\";\r\ + \n \"information\"=\"\\E2\\84\\B9\";\r\ + \n \"large-orange-circle\"=\"\\F0\\9F\\9F\\A0\";\r\ + \n \"large-red-circle\"=\"\\F0\\9F\\94\\B4\";\r\ + \n \"link\"=\"\\F0\\9F\\94\\97\";\r\ + \n \"lock-with-ink-pen\"=\"\\F0\\9F\\94\\8F\";\r\ + \n \"memo\"=\"\\F0\\9F\\93\\9D\";\r\ + \n \"mobile-phone\"=\"\\F0\\9F\\93\\B1\";\r\ + \n \"pushpin\"=\"\\F0\\9F\\93\\8C\";\r\ + \n \"scissors\"=\"\\E2\\9C\\82\";\r\ + \n \"scroll\"=\"\\F0\\9F\\93\\9C\";\r\ + \n \"smiley-partying-face\"=\"\\F0\\9F\\A5\\B3\";\r\ + \n \"smiley-smiling-face\"=\"\\E2\\98\\BA\";\r\ + \n \"smiley-winking-face-with-tongue\"=\"\\F0\\9F\\98\\9C\";\r\ + \n \"sparkles\"=\"\\E2\\9C\\A8\";\r\ + \n \"speech-balloon\"=\"\\F0\\9F\\92\\AC\";\r\ + \n \"star\"=\"\\E2\\AD\\90\";\r\ + \n \"warning-sign\"=\"\\E2\\9A\\A0\";\r\ + \n \"white-heavy-check-mark\"=\"\\E2\\9C\\85\"\r\ + \n }, \$SymbolsExtra);\r\ + \n :local Magic [ :pick [ /system/clock/get date ] 4 10 ];\r\ + \n :local Special {\r\ + \n \"information-04-01\"=\"\\F0\\9F\\9A\\BB\";\r\ + \n \"large-orange-circle-04-01\"=\"\\F0\\9F\\8D\\8A\";\r\ + \n \"large-orange-circle-10-31\"=\"\\F0\\9F\\8E\\83\";\r\ + \n \"large-red-circle-04-01\"=\"\\F0\\9F\\8D\\92\" };\r\ + \n :if ([ :len (\$Symbols->\$Name) ] = 0) do={\r\ + \n :log warning (\$0 . \"No symbol available for name '\" . \$Name . \"\ + '!\");\r\ + \n :return \"\";\r\ + \n }\r\ + \n :return ([ \$EitherOr (\$Special->(\$Name . \$Magic)) (\$Symbols->\$Na\ + me) ] . \"\\EF\\B8\\8F\");\r\ + \n}\r\ + \n\r\ + \n:set SymbolForNotification do={\r\ + \n :global NotificationsWithSymbols;\r\ + \n :global SymbolByUnicodeName;\r\ + \n :global IfThenElse;\r\ + \n :if (\$NotificationsWithSymbols != true) do={:return [ \$IfThenElse ([\ + \_:len \$2 ] > 0) ([ :tostr \$2 ] . \" \") \"\" ]}\r\ + \n :local Return \"\";\r\ + \n :foreach Symbol in=[ :toarray \$1 ] do={:set Return (\$Return . [ \$Sy\ + mbolByUnicodeName \$Symbol ])}\r\ + \n :return (\$Return . \" \");\r\ + \n}\r\ + \n\r\ + \n:set Unix2Dos do={:return [ :tocrlf [ :tostr \$1 ] ]}\r\ + \n:set UrlEncode do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :if ([ :len \$Input ] = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :local Chars (\"\\n\\r !\\\"#\\\$%&'()*+,:;<=>\?@[\\\\]^`{|}~\");\r\ + \n :local Subs { \"%0A\"; \"%0D\"; \"%20\"; \"%21\"; \"%22\"; \"%23\"; \"\ + %24\"; \"%25\"; \"%26\"; \"%27\";\r\ + \n \"%28\"; \"%29\"; \"%2A\"; \"%2B\"; \"%2C\"; \"%3A\"; \"%3B\"; \ + \"%3C\"; \"%3D\"; \"%3E\"; \"%3F\";\r\ + \n \"%40\"; \"%5B\"; \"%5C\"; \"%5D\"; \"%5E\"; \"%60\"; \"%7B\"; \ + \"%7C\"; \"%7D\"; \"%7E\" };\r\ + \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ + \n :local Char [ :pick \$Input \$I ];\r\ + \n :local Replace [ :find \$Chars \$Char ];\r\ + \n :if ([ :typeof \$Replace ] = \"num\") do={:set Char (\$Subs->\$Repla\ + ce)}\r\ + \n :set Return (\$Return . \$Char);\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set IsDNSResolving do={\r\ + \n :do {:resolve \"api.telegram.org\"} on-error={:return false}\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set IsFullyConnected do={\r\ + \n :global IsDNSResolving;\r\ + \n :global IsTimeSync;\r\ + \n :if ([ \$IsDNSResolving ] = false) do={:return false};\r\ + \n :if ([ \$IsTimeSync ] = false) do={:return false};\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set IsTimeSync do={\r\ + \n :global IsTimeSyncCached;\r\ + \n :global IsTimeSyncResetNtp;\r\ + \n :if (\$IsTimeSyncCached = true) do={:return true}\r\ + \n :if ([ /system/ntp/client/get enabled ] = true) do={\r\ + \n :if ([ /system/ntp/client/get status ] = \"synchronized\") do={\r\ + \n :set IsTimeSyncCached true;\r\ + \n :return true;\r\ + \n }\r\ + \n :local Uptime [ /system/resource/get uptime ];\r\ + \n :if ([ :typeof \$IsTimeSyncResetNtp ] = \"nothing\") do={\r\ + \n :set IsTimeSyncResetNtp \$Uptime;\r\ + \n }\r\ + \n :if (\$Uptime - \$IsTimeSyncResetNtp < 3m) do={:return false}\r\ + \n :log warning \"\$0 The ntp client is configured, but did not sync.\"\ + ;\r\ + \n :set IsTimeSyncResetNtp \$Uptime;\r\ + \n /system/ntp/client/set enabled=no;\r\ + \n :delay 20ms;\r\ + \n /system/ntp/client/set enabled=yes;\r\ + \n :return false;\r\ + \n }\r\ + \n :if ([ /system/license/get ]->\"level\" = \"free\" || \\\r\ + \n [ /system/resource/get ]->\"board-name\" = \"x86\") do={\r\ + \n :log debug \"\$0 No ntp client configured, relying on RTC for CHR fr\ + ee license and x86.\";\r\ + \n :return true;\r\ + \n }\r\ + \n :if ([ /ip/cloud/get update-time ] = true) do={\r\ + \n :if ([ :typeof [ /ip/cloud/get public-address ] ] = \"ip\") do={\r\ + \n :set IsTimeSyncCached true;\r\ + \n :return true;\r\ + \n }\r\ + \n :return false;\r\ + \n }\r\ + \n :log debug \"\$0 No time source configured! Returning gracefully...\";\ + \r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set FetchHugeFiles do={\r\ + \n :local ScriptName [ :tostr \$1 ];\r\ + \n :local Url [ :tostr \$2 ];\r\ + \n :local CheckCert [ :tostr \$3 ];\r\ + \n\r\ + \n :global CleanName;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global GetRandom20CharAlNum;\r\ + \n :global IfThenElse;\r\ + \n :global LogPrint;\r\ + \n :global MkDir;\r\ + \n :global RmDir;\r\ + \n :global RmFile;\r\ + \n :global WaitForFile;\r\ + \n\r\ + \n :set CheckCert [ \$IfThenElse (\$CheckCert = \"false\") \"no\" \"yes-w\ + ithout-crl\" ];\r\ + \n\r\ + \n :local DirName (\"tmpfs/\" . [ \$CleanName \$ScriptName ]);\r\ + \n :if ([ \$MkDir \$DirName ] = false) do={\r\ + \n \$LogPrint error \$0 (\"Failed creating directory!\");\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :local FileName (\$DirName . \"/\" . [ \$CleanName \$0 ] . \"-\" . [ \ + \$GetRandom20CharAlNum ]);\r\ + \n :onerror Err {\r\ + \n /tool/fetch check-certificate=\$CheckCert \$Url dst-path=\$FileName \ + \\\r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$ScriptName ] }) as-va\ + lue;\r\ + \n } do={\r\ + \n :if ([ \$WaitForFile \$FileName 500ms ] = true) do={\r\ + \n \$RmFile \$FileName;\r\ + \n }\r\ + \n \$LogPrint debug \$0 (\"Failed downloading from \" . \$Url . \" - \"\ + \_. \$Err);\r\ + \n \$RmDir \$DirName;\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :if ([ \$WaitForFile \$FileName 5s ] = false) do={\r\ + \n \$LogPrint debug \$0 (\"The file downloaded from \" . \$Url . \" did\ + \_not show up.\");\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :local FileSize [ /file/get \$FileName size ];\r\ + \n :local Return \"\";\r\ + \n :local VarSize 0;\r\ + \n :while (\$VarSize != \$FileSize) do={\r\ + \n :set Return (\$Return . ([ /file/read offset=\$VarSize chunk-size=32\ + 768 file=\$FileName as-value ]->\"data\"));\r\ + \n :set FileSize [ /file/get \$FileName size ];\r\ + \n :set VarSize [ :len \$Return ];\r\ + \n :if (\$VarSize > \$FileSize) do={\r\ + \n :delay 100ms;\r\ + \n }\r\ + \n }\r\ + \n \$RmDir \$DirName;\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set FetchUserAgentStr do={\r\ + \n :local Caller [ :tostr \$1 ];\r\ + \n :global GlobalScriptsUrl;\r\ + \n :global CommitBrief;\r\ + \n :global IfThenElse;\r\ + \n :local Resource [ /system/resource/get ];\r\ + \n :return (\"User-Agent: Mikrotik/\" . \$Resource->\"version\" . \" \" .\ + \_\$Resource->\"architecture-name\" . \\\r\ + \n \" \" . \$Caller . \"/Fetch (\" . \$GlobalScriptsUrl . \"; \" . [ \$\ + CommitBrief ] . \")\");\r\ + \n}\r\ + \n\r\ + \n:set ScriptInstallUpdate do={ :onerror Err {\r\ + \n :local Scripts [ :toarray \$1 ];\r\ + \n :local NewComment [ :tostr \$2 ];\r\ + \n :global InitSetup;\r\ + \n\r\ + \n :global CommitId;\r\ + \n :global ScriptUpdatesCRLF;\r\ + \n :global GlobalConfVersion;\r\ + \n :global Identity;\r\ + \n :global CertificateAvailable;\r\ + \n :global CheckSumsVerify;\r\ + \n :global GlobalScriptsUrl;\r\ + \n :global SumsDirAndFileName;\r\ + \n :global GlobalScriptsUrlSuffix;\r\ + \n :global EitherOr;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global Grep;\r\ + \n :global IfThenElse;\r\ + \n :global LogPrint;\r\ + \n :global ParseKeyValueStore;\r\ + \n :global RequiredRouterOS;\r\ + \n :global SendNotification2;\r\ + \n :global SymbolForNotification;\r\ + \n :global ValidateSyntax;\r\ + \n :global CommentsInScripts;\r\ + \n\r\ + \n :if ([ \$CertificateAvailable \"Root YE\" \"fetch\" ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Downloading certificate failed, trying wit\ + hout.\");\r\ + \n }\r\ + \n\r\ + \n :foreach Script in=\$Scripts do={\r\ + \n :if ([ :len [ /system/script/find where name=\$Script ] ] = 0) do={\ + \r\ + \n \$LogPrint info \$0 (\"Adding new script: \" . \$Script);\r\ + \n /system/script/add name=\$Script owner=\$Script source=\"#!rsc by \ + Vados\\n\" comment=\$NewComment;\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :local CommitIdBefore \$CommitId;\r\ + \n :local GlobalConfVersionBefore \$GlobalConfVersion;\r\ + \n :local ReloadGlobal false;\r\ + \n :local DeviceMode [ /system/device-mode/get ];\r\ + \n\r\ + \n :if (\$CheckSumsVerify = true) do={\r\ + \n :local CheckSums ({});\r\ + \n :do {\r\ + \n :local Url (\$GlobalScriptsUrl . \$SumsDirAndFileName . \$GlobalScr\ + iptsUrlSuffix);\r\ + \n \$LogPrint debug \$0 (\"Fetching checksums from url: \" . \$Url);\ + \r\ + \n :set CheckSums [ :deserialize from=json ([ /tool/fetch check-certi\ + ficate=yes-without-crl \\\r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$0 ] }) \$Url output\ + =user as-value ]->\"data\") ];\r\ + \n } on-error={ \$LogPrint warning \$0 (\"Err = \" . \$Err); }\r\ + \n }\r\ + \n\r\ + \n :foreach Script in=[ /system/script/find where source~\"^#!rsc by Vado\ + s\" ] do={\r\ + \n :local ScriptVal [ /system/script/get \$Script ];\r\ + \n :local ScriptInfo [ \$ParseKeyValueStore (\$ScriptVal->\"comment\") \ + ];\r\ + \n :local SourceNew;\r\ + \n\r\ + \n :foreach Scheduler in=[ /system/scheduler/find where on-event~(\"\\\ + \\b\" . \$ScriptVal->\"name\" . \"\\\\b\") ] do={\r\ + \n :local SchedulerVal [ /system/scheduler/get \$Scheduler ];\r\ + \n :if (\$ScriptVal->\"policy\" != \$SchedulerVal->\"policy\") do={\r\ + \n \$LogPrint warning \$0 (\"Policies differ for script '\" . \$Scr\ + iptVal->\"name\" . \"' and its scheduler '\" . \$SchedulerVal->\"name\" . \ + \"'!\");\r\ + \n }\r\ + \n }\r\ + \n :do {\r\ + \n :if (\$ScriptInfo->\"ignore\" = true) do={\r\ + \n \$LogPrint debug \$0 (\"Ignoring script '\" . \$ScriptVal->\"nam\ + e\" . \"', as requested.\");\r\ + \n :error true;\r\ + \n }\r\ + \n :if (\$CheckSumsVerify = true) do={\r\ + \n :local CheckSum (\$CheckSums->(\$ScriptVal->\"name\"));\r\ + \n :if ([ :len (\$ScriptInfo->\"base-url\") ] = 0 && [ :len (\$Scri\ + ptInfo->\"url-suffix\") ] = 0 && \\\r\ + \n [ :convert transform=md5 to=hex [ :tolf (\$ScriptVal->\"sou\ + rce\") ] ] = \$CheckSum) do={\r\ + \n \$LogPrint debug \$0 (\"Checksum for script '\" . \$ScriptVal-\ + >\"name\" . \"' matches, ignoring.\");\r\ + \n :error true;\r\ + \n }\r\ + \n }\r\ + \n :if ([ :len (\$ScriptInfo->\"certificate\") ] > 0) do={\r\ + \n :if ([ \$CertificateAvailable (\$ScriptInfo->\"certificate\") \"\ + fetch\" ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Downloading certificate failed, tryi\ + ng without.\");\r\ + \n }\r\ + \n }\r\ + \n :onerror Err {\r\ + \n :local BaseUrl [ \$EitherOr (\$ScriptInfo->\"base-url\") \$Globa\ + lScriptsUrl ];\r\ + \n :local UrlSuffix [ \$EitherOr (\$ScriptInfo->\"url-suffix\") \$G\ + lobalScriptsUrlSuffix ];\r\ + \n :local Url (\$BaseUrl . \$ScriptVal->\"name\" . \".rsc\" . \$Url\ + Suffix);\r\ + \n \$LogPrint warning \$0 (\"Fetching script '\" . (\$ScriptVal->\"\ + name\") . \"' from url: \" . \$Url);\r\ + \n :local Result [ /tool/fetch check-certificate=yes-without-crl \\\ + \r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$0 ] }) \$Url outp\ + ut=user as-value ];\r\ + \n :if (\$Result->\"status\" = \"finished\") do={\r\ + \n :set SourceNew [ :tolf (\$Result->\"data\") ];\r\ + \n } \r\ + \n } do={\r\ + \n \$LogPrint warning \$0 (\"Failed fetching script '\" . \$ScriptV\ + al->\"name\" . \"': \" . \$Err);\r\ + \n :if (\$Err != \"Fetch failed with status 404\") do={\r\ + \n :error false;\r\ + \n }\r\ + \n :if (\$ScriptVal->\"source\" = \"#!rsc by Vados\") do={\r\ + \n \$LogPrint warning \$0 (\"Removing dummy. Typo on installation\ + \?\");\r\ + \n /system/script/remove \$Script;\r\ + \n :error false;\r\ + \n }\r\ + \n :if (\$CheckSumsVerify = true) do={\r\ + \n :if ([ :len (\$ScriptInfo->\"base-url\") ] = 0 && [ :len (\$Sc\ + riptInfo->\"url-suffix\") ] = 0 && \\\r\ + \n [ :len \$CheckSum ] = 0) do={\r\ + \n \$LogPrint warning \$0 (\"Added the script manually\? Skip u\ + pdates with 'ignore=true' in comment.\");\r\ + \n }\r\ + \n }\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :if ([ :len \$SourceNew ] = 0) do={\r\ + \n \$LogPrint debug \$0 (\"No update for script '\" . (\$ScriptVal-\ + >\"name\") . \"'.\");\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :local SourceCRLF [ :tocrlf \$SourceNew ];\r\ + \n :if (\$InitSetup != true && ((\$ScriptVal->\"name\") != \"AM-Globa\ + lConfig\" || (\$ScriptVal->\"name\") != \"AM-GlobalFunc\")) do={\r\ + \n :if (\$SourceNew = (\$ScriptVal->\"source\") || \$SourceCRLF = (\ + \$ScriptVal->\"source\")) do={\r\ + \n \$LogPrint debug \$0 (\"Script '\" . (\$ScriptVal->\"name\") \ + . \"' source did not change. End of lines set to CRLF.\");\r\ + \n if (\$ScriptUpdatesCRLF = false) do={\r\ + \n :put [ :tolf \$SourceNew ];\r\ + \n \$LogPrint debug \$0 (\"Script '\" . (\$ScriptVal->\"name\"\ + ) . \"' source update end of lines to LF.\");\r\ + \n }\r\ + \n :error false;\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :if ([ :pick \$SourceNew 0 14 ] != \"#!rsc by Vados\") do={\r\ + \n \$LogPrint warning \$0 (\"Looks like new script '\" . \$ScriptVa\ + l->\"name\" . \"' is not valid (missing shebang = '\$shebang') Ignoring!\"\ + );\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :if (\$CommentsInScripts = true) do={\r\ + \n :local CommentLine [ \$Grep \$SourceNew (\"\\23 Script comment:\ + \_\") ];\r\ + \n :if ([ :len \$CommentLine ] = 0) do={\r\ + \n \$LogPrint debug \$0 (\"The search in new script '\" . (\$Scr\ + iptVal->\"name\") . \"' for comment in script body, is not found result Ig\ + noring!\");\r\ + \n :error false;\r\ + \n } else={\r\ + \n :if ([ :len (\$ScriptVal->\"comment\")] = 0 || [ :len (\$Scri\ + ptVal->\"comment\")] != [ :pick \$CommentLine ([ :find \$CommentLine \":\"\ + ] + 2) [ :len \$CommentLine] ]) do={\r\ + \n \$LogPrint debug \$0 (\"Exsiting comment for script '\" . (\ + \$ScriptVal->\"name\") . \"' is '\" . (\$ScriptVal->\"comment\") . \"'.\")\ + ;\r\ + \n :set (\$ScriptVal->\"comment\") [ :pick \$CommentLine ([ :f\ + ind \$CommentLine \":\"] + 2) [ :len \$CommentLine] ];\r\ + \n \$LogPrint debug \$0 (\"New comment (\" . (\$ScriptVal->\"c\ + omment\") . \") for script '\" . (\$ScriptVal->\"name\") . \"' has been ad\ + ded!\");\r\ + \n } else={\r\ + \n \$LogPrint debug \$0 (\"Comment for script '\" . (\$ScriptV\ + al->\"name\") . \"' did not change.\");\r\ + \n :error false;\r\ + \n }\r\ + \n } \r\ + \n }\r\ + \n\r\ + \n :local RequiredROS ([ \$ParseKeyValueStore [ \$Grep \$SourceNew (\ + \"\\23 requires RouterOS, \") ] ]->version);\r\ + \n :if ([ \$RequiredRouterOS \$0 [ \$EitherOr \$RequiredROS \"0.0\" ]\ + \_false ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"The script '\" . (\$ScriptVal->\"name\ + \") . \"' requires RouterOS \" . \\\r\ + \n \$RequiredROS . \", which is not met by your installation. I\ + gnoring!\");\r\ + \n :error false;\r\ + \n }\r\ + \n :local RequiredDM [ \$ParseKeyValueStore [ \$Grep \$SourceNew (\"\ + \\23 requires device-mode, \") ] ];\r\ + \n :local MissingDM ({});\r\ + \n :foreach Feature,Value in=\$RequiredDM do={\r\ + \n :if ([ :typeof (\$DeviceMode->\$Feature) ] = \"bool\" && (\$Devi\ + ceMode->\$Feature) = false) do={\r\ + \n :set MissingDM (\$MissingDM, \$Feature);\r\ + \n }\r\ + \n }\r\ + \n :if ([ :len \$MissingDM ] > 0) do={\r\ + \n \$LogPrint warning \$0 (\"The script '\" . (\$ScriptVal->\"name\ + \") . \"' requires disabled \" . \\\r\ + \n \"device-mode features (\" . [ :tostr \$MissingDM ] . \"). I\ + gnoring!\");\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :if ([ \$ValidateSyntax \$SourceNew ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Syntax validation for script '\" . (\$\ + ScriptVal->\"name\") . \"' failed! Ignoring!\");\r\ + \n :error false;\r\ + \n }\r\ + \n \r\ + \n :log info (\"Updating script: \" . (\$ScriptVal->\"name\") . \" Sc\ + ript comment: \" . (\$ScriptVal->\"comment\"));\r\ + \n\r\ + \n /system/script/set owner=(\$ScriptVal->\"name\") comment=(\$Script\ + Val->\"comment\") \\\r\ + \n source=[ \$IfThenElse (\$ScriptUpdatesCRLF = true) \$SourceCRL\ + F \$SourceNew ] \$Script;\r\ + \n :if (\$ScriptVal->\"name\" = \"AM-GlobalConfig\" || \\\r\ + \n \$ScriptVal->\"name\" = \"AM-GlobalFunc\" || \\\r\ + \n \$ScriptVal->\"name\" ~ (\"^(AM-GlobalFunc\\\\.d|mod)/.\")) d\ + o={\r\ + \n :set ReloadGlobal true;\r\ + \n }\r\ + \n } on-error={ }\r\ + \n }\r\ + \n :if (\$ReloadGlobal = true) do={\r\ + \n \$LogPrint info \$0 (\"Reloading global configuration and functions.\ + \");\r\ + \n :onerror Err {\r\ + \n :global InitSetup (a);\r\ + \n /system/script {run AM-GlobalConfig; run AM-GlobalFunc;};\r\ + \n } do={\$LogPrint error \$0 (\"Reloading global configuration and fun\ + ctions failed! \" . \$Err)}\r\ + \n }\r\ + \n :if (\$GlobalConfVersionBefore > \$GlobalConfVersion) do={\r\ + \n \$LogPrint warning \$0 (\"The configuration version decreased from \ + \" . \\\r\ + \n \$GlobalConfVersionBefore . \" to \" . \$GlobalConfVersion . \\\r\ + \n \". Installed an older version\?\");\r\ + \n }\r\ + \n :if (\$GlobalConfVersionBefore < \$GlobalConfVersion) do={\r\ + \n :global GlobalConfChanges;\r\ + \n :global GlobalConfMigration;\r\ + \n :local ChangeLogCode;\r\ + \n :if ([ :len \$ChangeLogCode ] > 0) do={\r\ + \n :if ([ \$ValidateSyntax \$ChangeLogCode ] = true) do={\r\ + \n :onerror Err {\r\ + \n [ :parse \$ChangeLogCode ];\r\ + \n } do={\$LogPrint warning \$0 (\"The changelog failed to run: \" \ + . \$Err)}\r\ + \n } else={\$LogPrint warning \$0 (\"The changelog failed syntax vali\ + dation!\")}\r\ + \n }\r\ + \n :if ([ :len \$GlobalConfMigration ] > 0) do={\r\ + \n :for I from=(\$GlobalConfVersionBefore + 1) to=\$GlobalConfVersion\ + \_do={\r\ + \n :local Migration (\$GlobalConfMigration->[ :tostr \$I ]);\r\ + \n :do {\r\ + \n :if ([ :typeof \$Migration ] != \"str\") do={\r\ + \n \$LogPrint debug \$0 (\"Migration code for change \" . \$I .\ + \_\" is not available.\");\r\ + \n :error false;\r\ + \n }\r\ + \n :if ([ \$ValidateSyntax \$Migration ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Migration code for change \" . \$I\ + \_. \" failed syntax validation!\");\r\ + \n :error false}\r\ + \n \$LogPrint info \$0 (\"Applying migration for change \" . \$I \ + . \": \" . \$Migration);\r\ + \n :onerror Err {\r\ + \n [ :parse \$Migration ];\r\ + \n } do={\$LogPrint warning \$0 (\"Migration code for change \" .\ + \_\$I . \" failed to run: \" . \$Err)}\r\ + \n } on-error={ }\r\ + \n }\r\ + \n }\r\ + \n :local NotificationMessage (\"The configuration version on \" . \$Id\ + entity . \" increased \" . \\\r\ + \n \"to \" . \$GlobalConfVersion . \", current configuration may nee\ + d modification. \" . \\\r\ + \n \"Please review and update global-config-overlay, then re-run glo\ + bal-config.\");\r\ + \n \$LogPrint info \$0 (\$NotificationMessage);\r\ + \n :if ([ :len \$GlobalConfChanges ] > 0) do={\r\ + \n :set NotificationMessage (\$NotificationMessage . \"\\n\\nChanges:\ + \");\r\ + \n :for I from=(\$GlobalConfVersionBefore + 1) to=\$GlobalConfVersion\ + \_do={\r\ + \n :local Change (\$GlobalConfChanges->[ :tostr \$I ]);\r\ + \n :set NotificationMessage (\$NotificationMessage . \"\\n \" . \\\ + \r\ + \n [ \$SymbolForNotification \"pushpin\" \"*\" ] . \$Change);\r\ + \n \$LogPrint info \$0 (\"Change \" . \$I . \": \" . \$Change);\r\ + \n }\r\ + \n } else={\r\ + \n :set NotificationMessage (\$NotificationMessage . \"\\n\\nNews and\ + \_changes are not available.\");\r\ + \n\r\ + \n }\r\ + \n\r\ + \n :if ([ :len \$GlobalConfChanges ] > 0) do={ :set GlobalConfChanges; \ + } else={ :global GlobalConfChanges (a); }\r\ + \n :if ([ :len \$GlobalConfMigration ] > 0) do={ :set GlobalConfMigrati\ + on; } else={ :global GlobalConfMigration (a); }\r\ + \n }\r\ + \n} do={\r\ + \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ + \n} }\r\ + \n\r\ + \n# load modules\r\ + \n:foreach Script in=[ /system/script/find where name ~ \"^(global-functio\ + ns\\\\.d|mod)/.\" ] do={\r\ + \n :local ScriptVal [ /system/script/get \$Script ];\r\ + \n :if ([ \$ValidateSyntax (\$ScriptVal->\"source\") ] = true) do={\r\ + \n :onerror Err {\r\ + \n /system/script/run \$Script;\r\ + \n } do={\r\ + \n \$LogPrint error \$0 (\"Module '\" . \$ScriptVal->\"name\" . \"' f\ + ailed to run: \" . \$Err);\r\ + \n }\r\ + \n } else={\r\ + \n \$LogPrint error \$0 (\"Module '\" . \$ScriptVal->\"name\" . \"' fai\ + led syntax validation, skipping.\");\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n# Add and fix global scheduler\r\ + \n:put \"Add or/and fix Global scheduler...\";\r\ + \n:local OnEvent \"/system/script { run AM-GlobalConfig; run AM-GlobalFunc\ + ; }\";\r\ + \n:local Comment \"Every Day Set Global Environment Variables\";\r\ + \n:if ([ :len [ /system/scheduler/find where name=\"AM-SetGlobalEnv\" ] ] \ + = 0) do={\r\ + \n /system/scheduler/add name=\"AM-SetGlobalEnv\" comment=\$Comment on-ev\ + ent=\$OnEvent start-time=startup;\r\ + \n}\r\ + \n:if ([ /system/scheduler/get \"AM-SetGlobalEnv\" comment ] != \$Comment)\ + \_do={\r\ + \n /system/scheduler/set \"AM-SetGlobalEnv\" comment=\$Comment;\r\ + \n}\r\ + \n:if ([ /system/scheduler/get \"AM-SetGlobalEnv\" on-event ] != \$OnEvent\ + ) do={\r\ + \n /system/scheduler/set \"AM-SetGlobalEnv\" on-event=\$OnEvent;\r\ + \n}\r\ + \n# Add Update Script scheduler\r\ + \n:put \"Add or/and fix Update Script scheduler\";\r\ + \n:set OnEvent \":global ScriptInstallUpdate; \\\$ScriptInstallUpdate;\";\ + \r\ + \n:set Comment \"Every Day Check For Update Scripts\";\r\ + \n:if ([ :len [ /system/scheduler/find where name=\"AM-ScriptInstallUpdate\ + \" ] ] = 0) do={\r\ + \n/system/scheduler/add name=\"AM-ScriptInstallUpdate\" comment=\$Comment \ + start-time=startup interval=1d on-event=\$OnEvent;\r\ + \n}\r\ + \n\r\ + \n:onerror Err {\r\ + \n :global GlobalConfReady;\r\ + \n :retry { :if (\$GlobalConfReady != true) do={ :error (\"Global configs\ + \_not ready.\"); }; } delay=100ms max=5;\r\ + \n\r\ + \n:log warning (\"This script \$ScriptName Loaded \" . \\\r\ + \n [ \$IfThenElse (\$CommitId != \"unknown\") ([ \$CommitBrief ] . \" \ + \") ] . \\\r\ + \n \"on \" . \$devBoardName . \"\\nRouterOS: \" . \$devCurVersion . \"\ + \\nArchitecture: \" . \$devCurArch . \"\\nIdentity: \" . \$Identity);\r\ + \n # signal we are ready\r\ + \n:set GlobalFuncReady true;\r\ + \n:set ExitOK true;\r\ + \n\r\ + \n:log info (\$0 . \"Global configs ready!\");\r\ + \n} do={\r\ + \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ + \n}\r\ + \n" +add dont-require-permissions=no name=fetchCustom owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + \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#\r\ + \n\ + \n#root.mnuc.backuper\ + \n\ + \n\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\";\ + \n\r\ + \n\r\ + \n#:local Script AM-GlobalConfig;\r\ + \n\ + \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\");\ + \n\r\ + \n#/usb1/mikro_bak_rsa.pub\r\ + \n\r\ + \n\ + \n#:local FetchFile AM-DOHCert.rsc\ + \n\ + \n\r\ + \n\r\ + \n:global GlobalScriptsUrl \"https://ros.vados.ru/tmp/\";\r\ + \n\ + \n:global MkDir;\ + \n\r\ + \n\ + \n:local FetchFile Manager@id_rsa.pub\ + \n:local localDir \"/\";\r\ + \n\r\ + \n\ + \n\ + \n\$MkDir \$localDir;\ + \n\ + \n\r\ + \n\r\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \$FetchFile) dst-path=(\ + \$localDir . \$FetchFile);\ + \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=awg-env owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="/\ + container/envs/add list=awg-proxy-env key=AWG_LISTEN value=\":55055\"\ + \n/container/envs/add list=awg-proxy-env key=AWG_REMOTE value=\"109.107.17\ + 7.79:55055\"\ + \n/container/envs/add list=awg-proxy-env key=AWG_JC value=\"9\"\ + \n/container/envs/add list=awg-proxy-env key=AWG_JMIN value=\"105\"\ + \n/container/envs/add list=awg-proxy-env key=AWG_JMAX value=\"920\"\ + \n/container/envs/add list=awg-proxy-env key=AWG_S1 value=\"90\"\ + \n/container/envs/add list=awg-proxy-env key=AWG_S2 value=\"136\"\ + \n/container/envs/add list=awg-proxy-env key=AWG_S3 value=\"45\"\ + \n/container/envs/add list=awg-proxy-env key=AWG_S4 value=\"27\"\ + \n/container/envs/add list=awg-proxy-env key=AWG_H1 value=\"472437748-4724\ + 38637\"\ + \n/container/envs/add list=awg-proxy-env key=AWG_H2 value=\"707808381-7078\ + 09250\"\ + \n/container/envs/add list=awg-proxy-env key=AWG_H3 value=\"1609078552-160\ + 9079495\"\ + \n/container/envs/add list=awg-proxy-env key=AWG_H4 value=\"1012329484-101\ + 2329741\"\ + \n/container/envs/add list=awg-proxy-env key=AWG_I1 value=\"\"\ + \n/container/envs/add list=awg-proxy-env key=AWG_I2 value=\"\"\ + \n/container/envs/add list=awg-proxy-env key=AWG_I3 value=\"\ + \"\ + \n/container/envs/add list=awg-proxy-env key=AWG_I4 value=\"\"\ + \n/container/envs/add list=awg-proxy-env key=AWG_I5 value=\"\"\ + \n/container/envs/add list=awg-proxy-env key=AWG_SERVER_PUB value=\"o5IgCl\ + 1/G6xbl6j7sPaP4ZNYREeYOmqZjKbm+v0b9jU=\"\ + \n/container/envs/add list=awg-proxy-env key=AWG_CLIENT_PUB value=[/interf\ + ace/wireguard/get [find name=wg-awg-proxy] public-key]" +add dont-require-permissions=no name=awg-container-add owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="/\ + container/add file=sata1/tmp/awg-proxy-amd64.tar.gz interface=veth-awg-pro\ + xy envlist=awg-proxy-env \\\ + \n hostname=awg-proxy root-dir=sata1/awg-proxy logging=yes shm-size=4M \ + start-on-boot=yes\ + \n/container/start [find where tag~\"awg-proxy\"]" +add dont-require-permissions=yes name=awg2-webui owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + put \"Download image, and save him to usb1/tmp\"\ + \n/tool/fetch url=\"https://ros.vados.ru/docker/awg2-webui-chr.tar\" dst-p\ + ath=sata1/tmp/awg2-webui.tar\ + \n\ + \n:put \"1. Create veth interface\"\ + \n/interface veth add name=veth-awg address=10.9.9.2/24 gateway=10.9.9.1\ + \n\ + \n:put \"2. Create bridge and add veth\"\ + \n/interface bridge add name=br-awg\ + \n/interface bridge port add bridge=br-awg interface=veth-awg\ + \n\ + \n:put \"3. Assign IP to bridge\"\ + \n/ip address add address=10.9.9.1/24 interface=br-awg\ + \n\ + \n:put \"4. NAT: masquerade container traffic\"\ + \n/ip firewall nat add chain=srcnat src-address=10.9.9.0/24 action=masquer\ + ade\ + \n\ + \n:put \"5. Port forward: UDP 443 \? container (AmneziaWG QUIC mimicry)\"\ + \n/ip firewall nat add chain=dstnat protocol=udp dst-port=443 action=dst-n\ + at to-addresses=10.9.9.2 to-ports=55055 in-interface=ether1\ + \n\ + \n:put \"6. Port forward: HTTPS 9443 \? container Web UI\"\ + \n/ip firewall nat add chain=dstnat protocol=tcp dst-port=9443 action=dst-\ + nat to-addresses=10.9.9.2 to-ports=443 in-interface=ether1\ + \n\ + \n:put \"Create environment list..\"\ + \n/container envs add list=awgui-env key=WEB_USER value=vados\ + \n/container envs add list=awgui-env key=WEB_PASS value=zoomzoomrulezz\ + \n/container envs add list=awgui-env key=SECRET_KEY value=RanDomSecret32Sy\ + mboLs2325272931q\ + \n/container envs add list=awgui-env key=AWG_ENDPOINT value=10.30.30.10:44\ + 3\ + \n\ + \n:put \"Load and start container...\"\ + \n/container add file=sata1/tmp/awg2-webui.tar interface=veth-awg hostname\ + =awg2-webui \\\ + \nroot-dir=sata1/awg2-webui layer-dir=sata1/docker/awg2-webu/ envlist=awgu\ + i-env start-on-boot=yes logging=yes shm-size=4M\ + \n\ + \n:put \"Start...\"\ + \n/container start 0\ + \n\ + \n:put \"Verify...\"\ + \n/container print\ + \n\ + \n:put \"Should show: status=running\"\ + \n\ + \n/log print where topics~\"container\"\ + \n\ + \n:put \"Should show: AWG started, nginx running\"\ + \n" +add dont-require-permissions=no name=awg-proxy-go-Client owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="\ + \n:put \"[::::::::::::::: START :::::::::::::::]\"\ + \n:put \"\"\ + \n:put \"Add ram disk tmpfs\"\ + \n#/disk add type=tmpfs tmpfs-max-size=100M slot=ram\ + \n\ + \n:put \"veth and network:\"\ + \n /interface/bridge add name=docker port-cost-mode=short\ + \n /ip/address/add address=192.168.100.1/24 interface=docker\ + \n\ + \n /interface/veth add address=192.168.100.3/24 gateway=192.168.100.1 name\ + =awg-proxy-go-client\ + \n /interface/bridge/port add bridge=docker interface=awg-proxy-go-client\ + \n\ + \n:put \"add config-client.json\"\ + \n/file/add name=sata1/mounts/awg-proxy-go/config-client.json\ + \n/container/mounts/add src=sata1/mounts/awg-proxy-go/config-client.json d\ + st=/app/config.json list=awgcfg-client\ + \n\ + \n#:put \"Download image, and save him to sata1/tmp/awgproxy-0.0.1-0034-am\ + d64.tar.gz\"\ + \n#/tool/fetch url=\"https://ros.vados.ru/amneziawg/img/awgproxy-0.0.1-003\ + 4-amd64.tar.gz\" dst-#path=\"tmp/awgproxy-0.0.1-0034-amd64.tar.gz\"\ + \n\ + \n:put \"Add container\"\ + \n/container/add file=\"usb1/dst/awgproxy-0.0.1-0036-amd64.tar\" interface\ + =awg-proxy-go-client hostname=awg-proxy-go-client root-dir=sata1/awg-proxy\ + -client logging=yes start-on-boot=yes workdir=sata1/docker/ name=\"awg-pro\ + xy-go-client\" mountlists=awgcfg-client\ + \n\ + \n:put \"Start container\"\ + \n#/container/start awg-proxy-go-client\ + \n\ + \n:put \"Add user:\"\ + \n /user/add address=192.168.100.2 group=write name=awg-proxy-go password=\ + peskar55\ + \n\ + \n:put \"Add forwarding port web-ui\"\ + \n /ip firewall nat add action=dst-nat chain=dstnat dst-port=8089 in-inter\ + face=ether1 protocol=tcp to-addresses=192.168.100.3 to-port=8088\ + \n\ + \n:put \"Add native WireGuard-server wg-awg, add address.\"\ + \n /interface/wireguard/add name=wg-awg-client\ + \n /ip/address/add address=172.17.0.1/24 interface=wg-awg-client\ + \n\ + \n:put \"\"\ + \n:put \"[::::::::::::::: END :::::::::::::::]\"\ + \n" +add comment=awg2wg dont-require-permissions=no name=awg2wg-uninstall owner=\ + Manager policy=ftp,read,write,policy source="\r\ + \n :put \"Uninstalling AmneziaWG...\"\r\ + \n :log info \"Uninstalling AmneziaWG...\"\r\ + \n /ip/route/remove [find where comment=awg2wg-tunnel]\r\ + \n :do { /tool/netwatch/remove [find where comment=Monitor-AWG2WG] } on-e\ + rror={}\r\ + \n :do { /ip/route/remove [find where comment=Monitor-AWG2WG] } on-error=\ + {}\r\ + \n /container/stop [find where interface=veth-awg2wg]\r\ + \n :delay 7s\r\ + \n /interface/list/member/remove [find where interface=wg-awg2wg]\r\ + \n /container/remove [find where interface=veth-awg2wg]\r\ + \n /container/envs/remove [find where list=\"awg2wg-env\"]\r\ + \n /ip/firewall/nat/remove [find where out-interface=\"wg-awg2wg\"]\r\ + \n /ip/address/remove [find where address=\"172.20.0.1/30\"]\r\ + \n /interface/veth/remove [find where name=\"veth-awg2wg\"]\r\ + \n /interface/wireguard/peers/remove [find where interface=\"wg-awg2wg\"]\ + \r\ + \n /ip/address/remove [find where interface=\"wg-awg2wg\"]\r\ + \n /interface/wireguard/remove [find where name=\"wg-awg2wg\"]\r\ + \n :do { /file/remove [find where name~\"awg2wg.+tar\"] } on-error={}\r\ + \n :do { /file/remove [find where name=\"disk1/awg2wg\"] } on-error={}\r\ + \n :put \"Uninstall AmneziaWG Proxy complete!\"\r\ + \n :log info \"Uninstall AmneziaWG Proxy complete!\"\r\ + \n /system/script/remove [find where name=awg2wg-uninstall]\r\ + \n" +add dont-require-permissions=no name=amneziawg-mikrotik-c owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="\ + \n:global GlobalScriptsUrl \"https://ros.vados.ru/\";\ + \n:global imagesPath \"amneziawg/img/\";\ + \n:local Image \"awg-proxy-amd64-7.20-Docker.tar.gz\";\ + \n\ + \n:global DstDir \"sata1/dst/\";\ + \n\ + \n:local Url=(\$GlobalScriptsUrl . \$ImagesPath . \$Image);\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n" +add comment=Generator dont-require-permissions=no name=awg-VDSina owner=vados \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + source="# ============================================================\ + \n# AWG Proxy -- MikroTik RouterOS (protocol: v2)\ + \n# 2026-06-30 22:08:12\ + \n# ============================================================\ + \n\ + \n# 0. Check prerequisites\ + \n:if ([:len [/system/package/find where name=\"container\" disabled=no]] \ + = 0) do={\ + \n :put \"Container package is not installed or disabled. Install it and \ + reboot.\"\ + \n :error \"Usage: /system/device-mode/update container=yes\"\ + \n}\ + \n\ + \n# Auto-detect storage\ + \n:global awgDisk \"disk1\"\ + \n{\ + \n :local usbFree 0\ + \n :do { :set usbFree [/disk/get [find where mount-point=\"usb1\"] free] \ + } on-error={}\ + \n :if (\$usbFree > 0) do={\ + \n :set awgDisk \"usb1\"\ + \n :put (\"Using USB: usb1 (\" . (\$usbFree / 1048576) . \" MB free)\")\ + \n } else={\ + \n :if ([:len [/disk/find where slot=\"usb1\"]] > 0) do={\ + \n :put \"USB found but not mounted. Format as ext4\?\"\ + \n :put \"Press 'y' to confirm:\"\ + \n :local key [/terminal/inkey timeout=30]\ + \n :if (\$key = 121 || \$key = 89) do={\ + \n /disk/format-drive usb1 file-system=ext4 label=usb1\ + \n :delay 3s\ + \n :do { :set usbFree [/disk/get [find where mount-point=\"usb1\"] \ + free] } on-error={}\ + \n :if (\$usbFree > 0) do={\ + \n :set awgDisk \"usb1\"\ + \n } else={ :put \"Format failed, using disk1\" }\ + \n } else={ :put \"Using disk1\" }\ + \n } else={ :put \"No USB, using disk1\" }\ + \n }\ + \n}\ + \n\ + \n# 1. Uninstall script\ + \n/system/script/add name=awg-VDSina-uninstall comment=awg-VDSina source={\ + \n :put \"Uninstallimg AmneziaWG...\"\ + \n :log info \"Uninstallimg AmneziaWG...\"\ + \n :local prevDNS \"\"\ + \n :do { :set prevDNS [/container/envs/get [find where list=\"awg-VDSina-\ + env\" key=\"AWG_PREV_DNS\"] value] } on-error={}\ + \n :local storageDisk \"disk1\"\ + \n :do { :set storageDisk [/container/envs/get [find where list=\"awg-VDS\ + ina-env\" key=\"AWG_STORAGE\"] value] } on-error={}\ + \n :local prevTmpdir \"\"\ + \n :if (\$storageDisk != \"disk1\") do={\ + \n :do { :set prevTmpdir [/container/envs/get [find where list=\"awg-VD\ + Sina-env\" key=\"AWG_PREV_TMPDIR\"] value] } on-error={}\ + \n }\ + \n /ip/route/remove [find where comment=awg-VDSina-tunnel]\ + \n /ip/route/remove [find where comment=awg-VDSina-dns]\ + \n /container/stop [find where interface=veth-awg-VDSina]\ + \n :delay 7s\ + \n /container/remove [find where interface=veth-awg-VDSina]\ + \n /container/envs/remove [find where list=\"awg-VDSina-env\"]\ + \n :if (\$prevDNS != \"\") do={\ + \n :do { /ip/dns/set servers=\"\$prevDNS\" } on-error={}\ + \n :put (\"DNS restored to: \$prevDNS\")\ + \n }\ + \n :if (\$storageDisk != \"disk1\") do={\ + \n /container/config set tmpdir=\$prevTmpdir\ + \n :put (\"Container tmpdir restored to: \$prevTmpdir\")\ + \n }\ + \n /ip/firewall/nat/remove [find where out-interface=\"wg-awg-VDSina\"]\ + \n /ip/firewall/nat/remove [find where src-address=\"172.19.75.208/30\"]\ + \n /ip/address/remove [find where address=\"172.19.75.209/30\"]\ + \n /interface/veth/remove [find where name=\"veth-awg-VDSina\"]\ + \n /interface/wireguard/peers/remove [find where interface=\"wg-awg-VDSin\ + a\"]\ + \n /ip/address/remove [find where interface=\"wg-awg-VDSina\"]\ + \n /interface/wireguard/remove [find where name=\"wg-awg-VDSina\"]\ + \n :do { /file/remove [find where name~\"awg-VDSina.+tar\"] } on-error={}\ + \n :do { /file/remove [find where name=(\$storageDisk . \"/awg-VDSina\")]\ + \_} on-error={}\ + \n :do { /file/remove [find where name=(\$storageDisk . \"/ru_ranges_time\ + out.rsc\")] } on-error={}\ + \n :if (\$storageDisk != \"disk1\") do={\ + \n :do { /file/remove [find where name~(\$storageDisk . \"/pull\")] } o\ + n-error={}\ + \n }\ + \n :put \"Uninstall AmneziaWG Proxy complete!\"\ + \n :log info \"Uninstall AmneziaWG Proxy complete!\"\ + \n /system/script/remove [find where name=awg-VDSina-uninstall]\ + \n}\ + \n\ + \n# 2. Network infrastructure\ + \n/interface/veth/add name=veth-awg-VDSina address=172.19.75.210/30 gatewa\ + y=172.19.75.209\ + \n/ip/address/add address=172.19.75.209/30 interface=veth-awg-VDSina\ + \n/ip/firewall/nat/add chain=srcnat action=masquerade src-address=172.19.7\ + 5.208/30\ + \n\ + \n# 3. WireGuard interface (MikroTik derives the public key automatically)\ + \n/interface/wireguard/add name=wg-awg-VDSina private-key=\"4CHyNhbOs923/E\ + yNDguMXJXdghL2I3UyzXPwrANVgHs=\" listen-port=14710 disabled=yes\ + \n/interface/wireguard/peers/add interface=wg-awg-VDSina public-key=\"o5Ig\ + Cl1/G6xbl6j7sPaP4ZNYREeYOmqZjKbm+v0b9jU=\" preshared-key=\"RNvF7T1cg5tyXcY\ + QnD9N5BEp6e20vVJQTv0GMjyvHU0=\" endpoint-address=172.19.75.210 endpoint-po\ + rt=51820 allowed-address=0.0.0.0/0 persistent-keepalive=10\ + \n/ip/address/add address=10.9.0.3/32 interface=wg-awg-VDSina\ + \n\ + \n# 4. Container environment variables\ + \n/container/envs/add list=awg-VDSina-env key=AWG_LISTEN value=\":51820\"\ + \n/container/envs/add list=awg-VDSina-env key=AWG_REMOTE value=\"109.107.1\ + 77.79:55055\"\ + \n/container/envs/add list=awg-VDSina-env key=AWG_JC value=\"9\"\ + \n/container/envs/add list=awg-VDSina-env key=AWG_JMIN value=\"105\"\ + \n/container/envs/add list=awg-VDSina-env key=AWG_JMAX value=\"920\"\ + \n/container/envs/add list=awg-VDSina-env key=AWG_S1 value=\"90\"\ + \n/container/envs/add list=awg-VDSina-env key=AWG_S2 value=\"136\"\ + \n/container/envs/add list=awg-VDSina-env key=AWG_H1 value=\"472437748-472\ + 438637\"\ + \n/container/envs/add list=awg-VDSina-env key=AWG_H2 value=\"707808381-707\ + 809250\"\ + \n/container/envs/add list=awg-VDSina-env key=AWG_H3 value=\"1609078552-16\ + 09079495\"\ + \n/container/envs/add list=awg-VDSina-env key=AWG_H4 value=\"1012329484-10\ + 12329741\"\ + \n/container/envs/add list=awg-VDSina-env key=AWG_SERVER_PUB value=\"o5IgC\ + l1/G6xbl6j7sPaP4ZNYREeYOmqZjKbm+v0b9jU=\"\ + \n/container/envs/add list=awg-VDSina-env key=AWG_CLIENT_PUB value=[/inter\ + face/wireguard/get [find name=wg-awg-VDSina] public-key]\ + \n/container/envs/add list=awg-VDSina-env key=AWG_S3 value=\"45\"\ + \n/container/envs/add list=awg-VDSina-env key=AWG_S4 value=\"27\"\ + \n/container/envs/add list=awg-VDSina-env key=AWG_I1 value=\"\"\ + \n/container/envs/add list=awg-VDSina-env key=AWG_I2 value=\"\"\ + \n/container/envs/add list=awg-VDSina-env key=AWG_I3 value=\"\ + \"\ + \n/container/envs/add list=awg-VDSina-env key=AWG_I4 value=\"\"\ + \n/container/envs/add list=awg-VDSina-env key=AWG_I5 value=\"\"\ + \n\ + \n# 5. DNS\ + \n{ :local rawDNS [/ip/dns/get servers]; :local prevDNS \"\"; :foreach s i\ + n=[:toarray \$rawDNS] do={ :if ([:len \$prevDNS] > 0) do={ :set prevDNS \"\ + \$prevDNS,\$s\" } else={ :set prevDNS \$s } }; /container/envs/add list=aw\ + g-VDSina-env key=AWG_PREV_DNS value=\"\$prevDNS\" }\ + \n# NOTE: replaces existing DNS configuration\ + \n/ip/dns/set servers=109.107.177.79\ + \n/ip/route/add dst-address=109.107.177.79/32 gateway=wg-awg-VDSina distan\ + ce=1 comment=awg-VDSina-dns\ + \n\ + \n# 6. Download, create and start container\ + \n/container/envs/add list=awg-VDSina-env key=AWG_STORAGE value=\$awgDisk\ + \n:if (\$awgDisk != \"disk1\") do={\ + \n :local tmpPath (\$awgDisk . \"/pull\")\ + \n /container/envs/add list=awg-VDSina-env key=AWG_PREV_TMPDIR value=[/co\ + ntainer/config/get tmpdir]\ + \n /container/config set tmpdir=\$tmpPath memory-high=200M\ + \n}\ + \n{\ + \n :local arch [/system/resource/get architecture-name]\ + \n :local ver [/system/resource/get version]\ + \n :local dotPos [:find \$ver \".\"]\ + \n :local rest [:pick \$ver (\$dotPos + 1) [:len \$ver]]\ + \n :local endPos [:find \$rest \".\"]\ + \n :if ([:typeof \$endPos] = \"nil\") do={ :set endPos [:find \$rest \" \ + \"] }\ + \n :local minor [:tonum [:pick \$rest 0 \$endPos]]\ + \n :local suffix \"\"\ + \n :if (\$minor <= 20) do={ :set suffix \"-7.20-Docker\" }\ + \n :local file \"\"\ + \n :if (\$arch = \"arm64\") do={ :set file (\"awg-proxy-arm64\" . \$suffi\ + x . \".tar.gz\") }\ + \n :if (\$arch = \"arm\") do={ :set file (\"awg-proxy-arm\" . \$suffix . \ + \".tar.gz\") }\ + \n :if (\$arch ~ \"x86\") do={ :set file (\"awg-proxy-amd64\" . \$suffix \ + . \".tar.gz\") }\ + \n :if (\$file = \"\") do={ :error \"Unsupported architecture: \$arch\" }\ + \n :local url \"https://github.com/timbrs/amneziawg-mikrotik-c/releases/l\ + atest/download/\$file\"\ + \n :local filePath \$file\ + \n :if (\$awgDisk != \"disk1\") do={\ + \n :set filePath (\$awgDisk . \"/pull/\" . \$file)\ + \n :do { /file/make-directory (\$awgDisk . \"/pull\") } on-error={}\ + \n }\ + \n :if ([:len [/file/find where name=\$filePath]] = 0) do={\ + \n :local freeStorage 0\ + \n :if (\$awgDisk = \"disk1\") do={\ + \n :set freeStorage [/system/resource/get free-hdd-space]\ + \n } else={\ + \n :do { :set freeStorage [/disk/get [find where mount-point=\$awgDis\ + k] free] } on-error={}\ + \n }\ + \n :if (\$freeStorage < 262144) do={\ + \n :put (\"WARNING: Low disk space (\" . (\$freeStorage / 1024) . \"K\ + B free). Need at least 256KB.\")\ + \n :put \"See: https://github.com/timbrs/amneziawg-mikrotik-c#insuffi\ + cient-disk-space\"\ + \n :error \"Insufficient disk space\"\ + \n }\ + \n :put (\"Fetching: \$url -> \" . \$filePath)\ + \n /tool/fetch url=\$url dst-path=\$filePath http-max-redirect-count=10\ + \n } else={\ + \n :put (\"File already exists: \" . \$filePath)\ + \n }\ + \n :local rootDir (\$awgDisk . \"/awg-VDSina\")\ + \n /container/add file=\$filePath interface=veth-awg-VDSina envlist=awg-V\ + DSina-env hostname=awg-VDSina root-dir=\$rootDir logging=no start-on-boot=\ + yes comment=awg-VDSina\ + \n :if (\$minor > 20) do={ [:parse \"/container/set [find where interface\ + =veth-awg-VDSina] shm-size=4M\"] }\ + \n /file/remove \$filePath\ + \n :local freeMem [/system/resource/get free-memory]\ + \n :if (\$freeMem < 16777216) do={\ + \n :put (\"WARNING: Low memory (\" . (\$freeMem / 1048576) . \"MB free)\ + . 16MB+ recommended.\")\ + \n }\ + \n /container/start [find where interface=veth-awg-VDSina]\ + \n :do { /file/remove [find where name=\"console-dump.txt\"] } on-error={\ + }\ + \n :put \"Waiting for container to start...\"\ + \n :delay 5s\ + \n /interface/wireguard/enable wg-awg-VDSina\ + \n :put \"WireGuard interface enabled\"\ + \n :put \"Installation complete!\"\ + \n :put \"Ping test: 109.107.177.79 via AmneziaWG tunnel. repeat 10 times\ + \"\ + \n /ping 109.107.177.79 count=10 interval=1\ + \n :put \"\"\ + \n :put \"======= NEXT STEPS =======\"\ + \n :put \"\"\ + \n :put \"Route specific traffic through the AmneziaWG tunnel:\"\ + \n :put \"\"\ + \n :put \" Route a single host:\"\ + \n :put \" /ip/route/add dst-address=8.8.8.8/32 gateway=wg-awg-VDSina \ + comment=awg-VDSina-tunnel\"\ + \n :put \"\"\ + \n :put \" Route a subnet:\"\ + \n :put \" /ip/route/add dst-address=100.0.0.0/8 gateway=wg-awg-VDSina\ + \_comment=awg-VDSina-tunnel\"\ + \n :put \"\"\ + \n :put \" Remove a route:\"\ + \n :put \" /ip/route/remove [find where comment=awg-VDSina-tunnel dst-\ + address=8.8.8.8/32]\"\ + \n :put \"\"\ + \n :put \" Show all tunnel routes:\"\ + \n :put \" /ip/route/print where comment=awg-VDSina-tunnel\"\ + \n :put \"\"\ + \n :put \" Uninstall:\"\ + \n :put \" /system/script/run awg-VDSina-uninstall\"\ + \n :put \"=========================\"\ + \n}\ + \n\ + \n# 7. Verification\ + \n# /container/print\ + \n# /interface/wireguard/print\ + \n# /interface/wireguard/peers/print\ + \n" +add comment="wg2awg GH repo in client mode" dont-require-permissions=no name=\ + "wg2awg client" owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="\ + \n:local Arch \"amd64\";\ + \n:local Version \"v0.0.1\";\ + \n:local Name wg2awg;\ + \n:local WorkDisk \"sata1\";\ + \n:local WorkDir (\$WorkDisk . \"/\" . \$Name);\ + \n:local Bridge (\"Bridge-\" . \$Name);\ + \n:local VetchMTU \"1280\";\ + \n:local Vetch (\"vetch-\" . \$Name);\ + \n:local VetchNet \"10.9.0.0\";\ + \n:local VetchGate \"10.9.0.1\";\ + \n:local VetchAddr \"10.9.0.3/32\";\ + \n:local Env (\$Name . \"-env\");\ + \n:local ConfDir (\"/etc/\" . \$Name . \"/\");\ + \n:local ConfFile (\$Name . \".conf\");\ + \n:local Mounts (\$WorkDisk . \"/mounts/\" . \$Name . \"/\");\ + \n:local RootDir (\$WorkDisk . \"/\" . \$Name);\ + \n:local Registry \"https://registry-1.docker.io\";\ + \n:local FetchFile (\$Name . \"-\" . \$Arch . \"-oci.tar\");\ + \n:local FetchUrl (\"https://github.com/vados-dev/wg2awg/releases/download\ + /\" . \$Version . \"/\" . \$FetchFile);\ + \n:local FetchDir (\$WorkDisk . \"/dst/\");\ + \n:local AwgListen \":44044\";\ + \n:local AwgRemote \"109.107.177.79\";\ + \n\ + \n#:put \"\"\ + \n#put \"Add ram disk tmpfs\"\ + \n#/disk add type=tmpfs tmpfs-max-size=100M slot=ram\ + \n\ + \n\ + \n:log warning \"[::::::::::::::: START :::::::::::::::]\"\ + \n:log warning \"Add veth and nat...\";\ + \n\ + \n/interface/veth/add name=\$Vetch address=\$VetchAddr gateway=\$VetchGate\ + ;\ + \n\ + \n:do {\ + \n:log warning (\"Remove interface: name=\" . \$Vetch . \", address=\" . \ + \$VetchAddr . \", gateway=\" . \$VetchGate);\ + \n/interface/veth/remove [find name=\$Vetch];\ + \n:log warning (\"Add interface: name=\" . \$Vetch . \", address=\" . \$Ve\ + tchAddr . \", gateway=\" . \$VetchGate);\ + \n/interface/veth/add name=\$Vetch address=\$VetchAddr gateway=\$VetchGate\ + ;\ + \n:log warning (\"Remove ip address: address=\" . \$VetchGate . \", interf\ + ace=\" . \$Vetch);\ + \n/ip/address/remove [find address=\$VetchGate interface=\$Vetch];\ + \n:log warning (\"Add ip address: address=\" . \$VetchGate . \", interface\ + =\" . \$Vetch);\ + \n/ip/address/add address=\$VetchGate interface=\$Vetch;\ + \n:log warning (\"Remove firewall nat rule: chain=srcnat action=masquerade\ + \_src-address=\" . \$VetchNet . \"/24\");\ + \n/ip/firewall/nat/remove [find chain=srcnat action=masquerade src-address\ + =(\$VetchNet . \"/24\")];\ + \n:log warning (\"Add firewall nat rule: chain=srcnat action=masquerade sr\ + c-address=\" . \$VetchNet . \"/24\");\ + \n/ip/firewall/nat/add chain=srcnat action=masquerade src-address=(\$VethN\ + et . \"/24\");\ + \n} on-error={}\ + \n\ + \n#:do {\ + \n#/file add type=directory name=\$Mounts\ + \n#} on-error={}\ + \n\ + \n\ + \n:do {\ + \n:log warning (\"Remove WorkDir: \" . \$WorkDir . \"...\");\ + \n/file remove [find name=\$WorkDir];\ + \n:log warning (\"Add WorkDir: \" . \$WorkDir . \"...\");\ + \n/file add type=directory name=\$WorkDir;\ + \n:log warning (\"Remove config file \" . \$Mounts . \$ConfFile . \"...\")\ + ;\ + \n/file remove [find name=(\$Mounts . \$ConfFile)];\ + \n:log warning (\"Add config file \" . \$Mounts . \$ConfFile . \"...\");\ + \n/file add type=file name=(\$Mounts . \$ConfFile) contents=\"[Interface]\ + \nPrivateKey = 4CHyNhbOs923/EyNDguMXJXdghL2I3UyzXPwrANVgHs=\ + \nAddress = \$VetchAddr\ + \nMTU = \$VetchMTU\ + \nDNS = 109.107.177.79\ + \nPreUp = ip route add 109.107.177.79/32 via \$VetchGate dev \$Vetch\ + \nPostDown = ip route del 109.107.177.79/32 via \$VetchGate dev \$Vetch\ + \nJc = 9\ + \nJmin = 105\ + \nJmax = 920\ + \nS1 = 90\ + \nS2 = 136\ + \nS3 = 45\ + \nS4 = 27\ + \nH1 = 472437748-472438637\ + \nH2 = 707808381-707809250\ + \nH3 = 1609078552-1609079495\ + \nH4 = 1012329484-1012329741\ + \nI1 = <\ + r 4>\ + \nI2 = \ + \nI3 = \ + \nI4 = \ + \nI5 = \ + \n\ + \n[Peer]\ + \nPublicKey = o5IgCl1/G6xbl6j7sPaP4ZNYREeYOmqZjKbm+v0b9jU=\ + \nAllowedIPs = 0.0.0.0/0\ + \nEndpoint = \$AwgRemote\ + \nPersistentKeepalive = 10\ + \nPresharedKey = RNvF7T1cg5tyXcYQnD9N5BEp6e20vVJQTv0GMjyvHU0=\";\ + \n} on-error={}\ + \n\ + \n\ + \n:do {\ + \n:log warning (\"Remove mounts list \$Env...\");\ + \n/container/mounts/remove [find list=\$Env];\ + \n:log warning (\"Add mounts list \$Env...\");\ + \n/container/mounts/add src=(\$Mounts . \$ConfFile) dst=(\$ConfDir . \$Con\ + fFile) list=\$Env mode=ro;\ + \n:log warning (\"Remove Environment keys.\");\ + \n/container/envs/remove [find list=\$Env];\ + \n:log warning (\"Add Environment keys.\");\ + \n/container/envs/add list=\$Env key=AWG_CONFIG value=(\$ConfDir . \$ConfF\ + ile);\ + \n/container/envs/add list=\$Env key=AWG_LISTEN value=\$AwgListen\ + \n/container/envs/add list=\$Env key=AWG_REMOTE value=\$AwgRemote\ + \n/container/envs/add list=\$Env key=AWG_MODE value=client\ + \n} on-error={}\ + \n\ + \n:do {\ + \n:log warning (\"Remove \" . \$WorkDisk . \"/tmp\");\ + \n/file remove [find name=(\$WorkDisk . \"/tmp\")];\ + \n:log warning (\"Add \" . \$WorkDisk . \"/tmp\");\ + \n/file add type=directory name=(\$WorkDisk . \"/tmp\");\ + \n:log warning (\"Container add tmpdir \" . \$WorkDisk . \"/tmp\");\ + \n/container config set tmpdir=(\$WorkDisk . \"/tmp\");\ + \n} on-error={}\ + \n\ + \n:do {\ + \n:log warning (\"Remove \" . \$FetchDir . \$FetchFile . \".\");\ + \n/file remove [find name=(\$FetchDir . \$FetchFile)];\ + \n:log warning (\"Download image from \" . \$FetchUrl . \" and save him to\ + \_\" . \$FetchDir . \$FetchFile . \".\");\ + \n/tool/fetch url=\$FetchUrl dst-path=(\$FetchDir . \$FetchFile);\ + \n} on-error={}\ + \n\ + \n#:log warning (\"Container set registry \" . \$Registry . \" tmpdir= \" \ + . \$WorkDisk . \"/tmp\");\ + \n#/container/config/set registry-url=\$Registry tmpdir=(\$WorkDisk . \"/t\ + mp\");\ + \n\ + \n#:do {\ + \n:log warning (\"Container add width: file=\" . \$FetchDir . \$FetchFile \ + . \", interface=\" . \$Vetch . \", hostname=\" . \$Name . \", mountlists=\ + \" . \$Env . \", envlist=\" . \$Env . \", root-dir=\" . \$RootDir . \", wo\ + rkdir=\" . \$WorkDir . \", name=\" . \$Name . \", logging=yes, start-on-bo\ + ot=yes\");\ + \n/container/add file=(\$FetchDir . \$FetchFile) interface=\$Vetch hostnam\ + e=\$Name mountlists=\$Env envlist=\$Env root-dir=\$RootDir workdir=\$WorkD\ + ir name=\$Name logging=yes start-on-boot=yes;\ + \n#} on-error={}\ + \n\ + \n\ + \n#/container/start [find where interface=\$Vetch];\ + \n\ + \n#/interface/bridge add name=\$Bridge port-cost-mode=short;\ + \n#/ip/address/add address=192.168.100.1/24 interface=\$Bridge;\ + \n\ + \n#/interface/veth add address=192.168.100.3/24 gateway=192.168.100.1 name\ + =awg-proxy-go-client\ + \n#/interface/bridge/port add bridge=docker interface=awg-proxy-go-client\ + \n\ + \n#:put \"add config-client.json\"\ + \n#/file/add name=sata1/mounts/awg-proxy-go/config-client.json\ + \n#/container/mounts/add src=sata1/mounts/awg-proxy-go/config-client.json \ + dst=/app/config.json list=awgcfg-client\ + \n\ + \n#:put \"Download image, and save him to sata1/tmp/awgproxy-0.0.1-0034-am\ + d64.tar.gz\"\ + \n#/tool/fetch url=\"https://ros.vados.ru/amneziawg/img/awgproxy-0.0.1-003\ + 4-amd64.tar.gz\" dst-#path=\"tmp/awgproxy-0.0.1-0034-amd64.tar.gz\"\ + \n\ + \n#:put \"Add container\"\ + \n#/container/add file=\"usb1/dst/awgproxy-0.0.1-0036-amd64.tar\" interfac\ + e=awg-proxy-go-client hostname=awg-proxy-go-client root-dir=sata1/awg-prox\ + y-client logging=yes start-on-boot=yes workdir=sata1/docker/ name=\"awg-pr\ + oxy-go-client\" mountlists=awgcfg-client\ + \n\ + \n#:put \"Start container\"\ + \n#/container/start awg-proxy-go-client\ + \n\ + \n#:put \"Add user:\"\ + \n#/user/add address=192.168.100.2 group=write name=awg-proxy-go password=\ + peskar55\ + \n\ + \n#:put \"Add forwarding port web-ui\"\ + \n#/ip firewall nat add action=dst-nat chain=dstnat dst-port=8089 in-inter\ + face=ether1 protocol=tcp to-addresses=192.168.100.3 to-port=8088\ + \n\ + \n#:put \"Add native WireGuard-server wg-awg, add address.\"\ + \n#/interface/wireguard/add name=wg-awg-client\ + \n#/ip/address/add address=172.17.0.1/24 interface=wg-awg-client\ + \n\ + \n:put \"\"\ + \n:put \"[::::::::::::::: END :::::::::::::::]\"\ + \n" +add dont-require-permissions=no name=tmp_print owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="/\ + interface/wireguard/add name=wg-VDSina private-key=\"4CHyNhbOs923/EyNDguMX\ + JXdghL2I3UyzXPwrANVgHs=\" listen-port=21641 \ + \n :put \"======= AWG PROXY SETUP =======\"\ + \n :put \"\"\ + \n :put \"Run awg-proxy on your external device (10.30.30.33).\"\ + \n :put \"\"\ + \n :put \"1. Download the binary for your platform:\"\ + \n :put \" Linux arm64: https://github.com/timbrs/amneziawg-mikrotik-c/\ + releases/latest/download/awg-proxy-linux-arm64\"\ + \n :put \" Linux arm: https://github.com/timbrs/amneziawg-mikrotik-c/\ + releases/latest/download/awg-proxy-linux-arm\"\ + \n :put \" Linux amd64: https://github.com/timbrs/amneziawg-mikrotik-c/\ + releases/latest/download/awg-proxy-linux-amd64\"\ + \n :put \"\"\ + \n :put \"2. Set environment variables and run:\"\ + \n :put \"export AWG_LISTEN=\\\":51820\\\"\"\ + \n :put \"export AWG_REMOTE=\\\"109.107.177.79:55055\\\"\"\ + \n :put \"export AWG_JC=\\\"9\\\"\"\ + \n :put \"export AWG_JMIN=\\\"105\\\"\"\ + \n :put \"export AWG_JMAX=\\\"920\\\"\"\ + \n :put \"export AWG_S1=\\\"90\\\"\"\ + \n :put \"export AWG_S2=\\\"136\\\"\"\ + \n :put \"export AWG_H1=\\\"472437748-472438637\\\"\"\ + \n :put \"export AWG_H2=\\\"707808381-707809250\\\"\"\ + \n :put \"export AWG_H3=\\\"1609078552-1609079495\\\"\"\ + \n :put \"export AWG_H4=\\\"1012329484-1012329741\\\"\"\ + \n :put \"export AWG_SERVER_PUB=\\\"o5IgCl1/G6xbl6j7sPaP4ZNYREeYOmqZjKbm+\ + v0b9jU=\\\"\"\ + \n :put (\"export AWG_CLIENT_PUB=\\\"\" . [/interface/wireguard/get [find\ + \_name=wg-VDSina] public-key] . \"\\\"\")\ + \n :put \"export AWG_S3=\\\"45\\\"\"\ + \n :put \"export AWG_S4=\\\"27\\\"\"\ + \n :put \"export AWG_I1=\\\"\\\"\"\ + \n :put \"export AWG_I2=\\\"\\\"\"\ + \n :put \"export AWG_I3=\\\"\\\"\"\ + \n :put \"export AWG_I4=\\\"\\\"\"\ + \n :put \"export AWG_I5=\\\"\\\"\"\ + \n :put \"\"\ + \n :put \"chmod +x awg-proxy-linux-* && ./awg-proxy-linux-\"\ + \n :put \"\"\ + \n :put \"3. (Optional) Create a systemd service for auto-start.\"\ + \n :put \"\"\ + \n :put \"Route specific traffic through the AmneziaWG tunnel:\"\ + \n :put \"\"\ + \n :put \" Route a single host:\"\ + \n :put \" /ip/route/add dst-address=8.8.8.8/32 gateway=wg-VDSina comm\ + ent=VDSina-tunnel\"\ + \n :put \"\"\ + \n :put \" Route a subnet:\"\ + \n :put \" /ip/route/add dst-address=100.0.0.0/8 gateway=wg-VDSina com\ + ment=VDSina-tunnel\"\ + \n :put \"\"\ + \n :put \" Remove a route:\"\ + \n :put \" /ip/route/remove [find where comment=VDSina-tunnel dst-addr\ + ess=8.8.8.8/32]\"\ + \n :put \"\"\ + \n :put \" Show all tunnel routes:\"\ + \n :put \" /ip/route/print where comment=VDSina-tunnel\"\ + \n :put \"\"\ + \n :put \" Uninstall:\"\ + \n :put \" /system/script/run VDSina-uninstall\"\ + \n :put \"================================\"" +/user group +add name=backup policy="telnet,ssh,ftp,read,write,policy,test,sniff,sensitive,\ + !local,!reboot,!winbox,!password,!web,!api,!romon,!rest-api" +add name=manager policy="local,ssh,ftp,read,write,policy,api,rest-api,!telnet,\ + !reboot,!test,!winbox,!password,!web,!sniff,!sensitive,!romon" +/app +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set HA-otbr-matter disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set adventurelog disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set babybuddy disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set backrest disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set birdnet-go disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set caddy disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set calibre-web disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set chr disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set cinny disabled=no firewall-redirects=8094:80:tcp:web +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set cloudflared disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set code-server disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set conduit disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set convertx disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set copyparty disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set cryptpad disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set diagrams-net disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set docker-with-dockge disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set docker-with-komodo disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set docker-with-portainer disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set docmost disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set elasticsearch disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set element disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set excalidraw disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set filegator disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set firefox disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set forgejo disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set fossil disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set frigate disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set gitea disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set gitlab disabled=no +set goaway container-command-lines=goaway:none:docker.io/pommee/goaway:latest +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set grafana disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set hedgedoc disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set home-assistant container-command-lines=\ + home-assistant:none:lscr.io/linuxserver/homeassistant disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set immich disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set influxdb disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set jackett disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set jellyfin disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set jupyter-notebook disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set kimai disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set librenms disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set librespeed disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set lidarr disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set livebook disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set mediamanager disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set memos disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set metube disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set mikrodash disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set minio disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set mosquitto disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set myip disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set n8n disabled=no firewall-redirects=5678:5678:tcp:web +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set netbox disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +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" disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set nextcloud-whiteboard disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set nocodb disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set nodered disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set ntfy disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set nzbget disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set odoo disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set onlyoffice-docs disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set openwebrx disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set openwebui-ollama disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set otbr disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set paperless-ngx disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set partdb disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set pihole disabled=no environment="pihole:FTLCONF_dns_listeningMode=all,pihol\ + e:FTLCONF_webserver_api_password=password" +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set plex disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set pmacct-netflow disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set prowlarr disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set radarr disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set redlib disabled=no firewall-redirects=8087:8080:tcp:web +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set restic-server disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set roundcube disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set searxng disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set smokeping disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set snipeit disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set solr container-command-lines=solr:none:docker.io/solr:latest disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set sonarr disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set sonatype-nexus disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set stalwart disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set syncthing disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set transmission disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set trip disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set upsnap disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set uptime-kuma container-command-lines=\ + uptime-kuma:none:docker.io/louislam/uptime-kuma:1 disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set urbackup-client disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set urbackup-server disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set vaultwarden disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set victoria-logs disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set victoria-metrics disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set viseron disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set wallabag disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set warracker disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set wbo disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set webtop disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set wordpress disabled=no +# certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +set zabbix disabled=no +/app settings +set auto-update=yes disk=*7 lan-bridge=Bridge-LAN registry-mirrors="https://re\ + g.vados.ru/:https://reg.vados.ru/,https://registry-1.docker.io:https://reg\ + istry-1.docker.io,https://ghcr.io:https://ghcr.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 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 +/caps-man datapath +add bridge=*3 client-to-client-forwarding=yes local-forwarding=yes name=\ + xs-DataPath +add bridge=*3 client-to-client-forwarding=yes local-forwarding=yes name=\ + DataPath +/caps-man manager +set ca-certificate=CAPsMAN-CA-ABE2F4E9EE17 certificate=CAPsMAN-ABE2F4E9EE17 \ + 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=all crl-use=yes +/container config +set layer-dir=/sata1/docker/layers memory-high=200.0MiB memory-max=4096.0MiB \ + registry-url=https://registry-1.docker.io tmpdir=/sata1/tmp username=\ + amsternl +/container envs +add key=AWG_CONFIG list=wg2awg-env value=/etc/wg2awg/wg2awg.conf +add key=AWG_LISTEN list=wg2awg-env value=:44044 +add key=AWG_MODE list=wg2awg-env value=client +add key=AWG_REMOTE list=wg2awg-env value=109.107.177.79 +/container mounts +add dst=/etc/wg2awg/wg2awg.conf list=wg2awg-env mode=ro src=\ + /sata1/mounts/wg2awg/wg2awg.conf +/ip smb +set enabled=no +/interface bridge port +add bridge=Bridge-LAN interface=LAN +/ipv6 settings +set allow-fast-path=no disable-ipv6=yes disable-link-local-address=yes +/interface detect-internet +set detect-interface-list=WAN internet-interface-list=Internet \ + lan-interface-list=LAN wan-interface-list=WAN +/interface list member +add interface=ether1 list=WAN +add interface=Bridge-LAN list=LAN +/interface wifi cap +set discovery-interfaces=*DF +/interface wifi capsman +set ca-certificate=*13 certificate=*14 enabled=yes interfaces=Bridge-LAN \ + package-path=/tmpfs/capsman-packages require-peer-certificate=no \ + upgrade-policy=none +/ip address +add address=10.30.30.10/24 interface=Bridge-LAN network=10.30.30.0 +/ip dhcp-client +add disabled=yes interface=ether1 name=client1 +/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=*3 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.33,109.107.177.79 \ + verify-doh-cert=yes +/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=none disabled=no distance=1 dst-address=0.0.0.0/0 gateway=\ + 10.30.30.81 routing-table=main scope=30 target-scope=10 +/ip service +set ftp disabled=yes +set reverse-proxy disabled=yes +set ssh port=2222 +set www-ssl port=4443 +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-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=*3 type=external +add interface=*B5 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 +/special-login +add port=serial0 +/system clock +set 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 package update +set check-certificate=yes-without-crl ip-version=ipv4 +/system scheduler +add comment="Every Day Set Global Environment Variables" disabled=yes 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" disabled=yes 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" disabled=yes 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" disabled=yes 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." \ + disabled=yes 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-25 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 +/user aaa +set accounting=no diff --git a/MikroNUC/history/20260817/20260817000001-Diff-Config.rsc b/MikroNUC/history/20260817/20260817000001-Diff-Config.rsc new file mode 100644 index 0000000..85f193b --- /dev/null +++ b/MikroNUC/history/20260817/20260817000001-Diff-Config.rsc @@ -0,0 +1,511 @@ +25d24 +< add name=internal protocol-mode=none +28,309d26 +< /interface veth +< add address="" container-mac-address=24:21:2C:26:EA:2F dhcp=yes gateway="" \ +< gateway6="" mac-address=24:21:2C:26:EA:2E name=veth-app-HA-otbr-matter +< add address=172.18.0.86/24 container-mac-address=32:18:2B:C3:9B:3C dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=32:18:2B:C3:9B:3B name=\ +< veth-app-adventurelog +< add address=172.18.0.87/24 container-mac-address=2A:04:D2:E3:35:2A dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=2A:04:D2:E3:35:29 name=\ +< veth-app-babybuddy +< add address=172.18.0.88/24 container-mac-address=20:C4:8E:BC:AE:EF dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=20:C4:8E:BC:AE:EE name=\ +< veth-app-backrest +< add address=172.18.0.89/24 container-mac-address=54:12:68:AB:5B:26 dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=54:12:68:AB:5B:25 name=\ +< veth-app-birdnet-go +< add address="" container-mac-address=4E:75:8A:1C:DE:61 dhcp=yes gateway="" \ +< gateway6="" mac-address=4E:75:8A:1C:DE:60 name=veth-app-caddy +< add address=172.18.0.90/24 container-mac-address=62:1C:85:A6:26:74 dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=62:1C:85:A6:26:73 name=\ +< veth-app-calibre-web +< add address="" container-mac-address=40:14:50:A7:E9:C4 dhcp=yes gateway="" \ +< gateway6="" mac-address=40:14:50:A7:E9:C3 name=veth-app-chr +< add address=172.18.0.91/24 container-mac-address=54:CB:C8:FC:9C:6F dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=54:CB:C8:FC:9C:6E name=\ +< veth-app-cinny +< add address=172.18.0.92/24 container-mac-address=32:3C:0A:F0:FF:88 dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=32:3C:0A:F0:FF:87 name=\ +< veth-app-cloudflared +< add address=172.18.0.93/24 container-mac-address=58:C2:AD:23:FF:E7 dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=58:C2:AD:23:FF:E6 name=\ +< veth-app-code-server +< add address=172.18.0.94/24 container-mac-address=14:48:58:EE:E4:8B dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=14:48:58:EE:E4:8A name=\ +< veth-app-conduit +< add address=172.18.0.95/24 container-mac-address=3A:99:FA:FF:15:95 dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=3A:99:FA:FF:15:94 name=\ +< veth-app-convertx +< add address=172.18.0.96/24 container-mac-address=62:92:21:8E:8E:03 dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=62:92:21:8E:8E:02 name=\ +< veth-app-copyparty +< add address=172.18.0.97/24 container-mac-address=2A:89:3C:4D:E5:1E dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=2A:89:3C:4D:E5:1D name=\ +< veth-app-cryptpad +< add address=172.18.0.98/24 container-mac-address=70:56:46:13:D6:4F dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=70:56:46:13:D6:4E name=\ +< veth-app-diagrams-net +< add address="" container-mac-address=2E:D7:EB:FC:51:2C dhcp=yes gateway="" \ +< gateway6="" mac-address=2E:D7:EB:FC:51:2B name=\ +< veth-app-docker-with-dockge +< add address="" container-mac-address=28:C0:33:81:C4:4C dhcp=yes gateway="" \ +< gateway6="" mac-address=28:C0:33:81:C4:4B name=\ +< veth-app-docker-with-komodo +< add address="" container-mac-address=4E:72:F4:F2:52:B4 dhcp=yes gateway="" \ +< gateway6="" mac-address=4E:72:F4:F2:52:B3 name=\ +< veth-app-docker-with-portainer +< add address=172.18.0.99/24 container-mac-address=70:99:0A:31:E2:F3 dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=70:99:0A:31:E2:F2 name=\ +< veth-app-docmost +< add address=172.18.0.100/24 container-mac-address=22:D4:32:5A:AB:E0 dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=22:D4:32:5A:AB:DF name=\ +< veth-app-elasticsearch +< add address=172.18.0.101/24 container-mac-address=4E:72:06:FE:0F:28 dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=4E:72:06:FE:0F:27 name=\ +< veth-app-element +< add address=172.18.0.102/24 container-mac-address=0A:01:AC:C9:52:D0 dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=0A:01:AC:C9:52:CF name=\ +< veth-app-excalidraw +< add address=172.18.0.103/24 container-mac-address=7E:3A:4A:57:F5:D8 dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=7E:3A:4A:57:F5:D7 name=\ +< veth-app-filegator +< add address=172.18.0.104/24 container-mac-address=7C:41:9F:5F:C9:C9 dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=7C:41:9F:5F:C9:C8 name=\ +< veth-app-firefox +< add address=172.18.0.105/24 container-mac-address=64:60:0E:54:3E:C4 dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=64:60:0E:54:3E:C3 name=\ +< veth-app-forgejo +< add address=172.18.0.106/24 container-mac-address=28:37:D4:22:97:F8 dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=28:37:D4:22:97:F7 name=\ +< veth-app-fossil +< add address=172.18.0.107/24 container-mac-address=00:BE:C5:23:83:99 dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=00:BE:C5:23:83:98 name=\ +< veth-app-frigate +< add address=172.18.0.108/24 container-mac-address=00:BB:5E:9E:F7:FF dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=00:BB:5E:9E:F7:FE name=\ +< veth-app-gitea +< add address=172.18.0.109/24 container-mac-address=1A:F3:AB:12:62:80 dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=1A:F3:AB:12:62:7F name=\ +< veth-app-gitlab +< add address=172.18.0.110/24 container-mac-address=46:05:FE:7A:8A:7E dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=46:05:FE:7A:8A:7D name=\ +< veth-app-grafana +< add address=172.18.0.111/24 container-mac-address=6E:37:1F:80:A4:A5 dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=6E:37:1F:80:A4:A4 name=\ +< veth-app-hedgedoc +< add address="" container-mac-address=5E:EE:57:7D:C7:DF dhcp=yes gateway="" \ +< gateway6="" mac-address=5E:EE:57:7D:C7:DE name=veth-app-home-assistant +< add address=172.18.0.112/24 container-mac-address=3A:54:03:A1:C3:BA dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=3A:54:03:A1:C3:B9 name=\ +< veth-app-immich +< add address=172.18.0.113/24 container-mac-address=26:1B:92:7A:72:88 dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=26:1B:92:7A:72:87 name=\ +< veth-app-influxdb +< add address=172.18.0.114/24 container-mac-address=16:EF:0A:15:4A:BC dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=16:EF:0A:15:4A:BB name=\ +< veth-app-jackett +< add address="" container-mac-address=2A:F7:1E:48:28:87 dhcp=yes gateway="" \ +< gateway6="" mac-address=2A:F7:1E:48:28:86 name=veth-app-jellyfin +< add address=172.18.0.115/24 container-mac-address=12:3D:1F:EF:9D:A9 dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=12:3D:1F:EF:9D:A8 name=\ +< veth-app-jupyter-notebook +< add address=172.18.0.116/24 container-mac-address=22:A5:A5:D3:63:73 dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=22:A5:A5:D3:63:72 name=\ +< veth-app-kimai +< add address=172.18.0.117/24 container-mac-address=52:37:2A:CB:98:E3 dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=52:37:2A:CB:98:E2 name=\ +< veth-app-librenms +< add address=172.18.0.118/24 container-mac-address=74:27:EB:64:C4:00 dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=74:27:EB:64:C3:FF name=\ +< veth-app-librespeed +< add address=172.18.0.119/24 container-mac-address=72:14:76:F1:35:9D dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=72:14:76:F1:35:9C name=\ +< veth-app-lidarr +< add address=172.18.0.120/24 container-mac-address=5A:62:24:8B:E2:21 dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=5A:62:24:8B:E2:20 name=\ +< veth-app-livebook +< add address=172.18.0.121/24 container-mac-address=32:92:78:E7:B8:D3 dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=32:92:78:E7:B8:D2 name=\ +< veth-app-mediamanager +< add address=172.18.0.122/24 container-mac-address=02:6B:AD:29:37:B9 dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=02:6B:AD:29:37:B8 name=\ +< veth-app-memos +< add address=172.18.0.123/24 container-mac-address=36:FE:52:AE:FA:7A dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=36:FE:52:AE:FA:79 name=\ +< veth-app-metube +< add address=172.18.0.124/24 container-mac-address=38:37:B0:03:D3:3B dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=38:37:B0:03:D3:3A name=\ +< veth-app-mikrodash +< add address=172.18.0.125/24 container-mac-address=6C:B5:19:41:15:1B dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=6C:B5:19:41:15:1A name=\ +< veth-app-minio +< add address=172.18.0.126/24 container-mac-address=58:FF:FD:1A:7D:CC dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=58:FF:FD:1A:7D:CB name=\ +< veth-app-mosquitto +< add address=172.18.0.127/24 container-mac-address=46:3F:8B:34:11:42 dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=46:3F:8B:34:11:41 name=\ +< veth-app-myip +< add address=172.18.0.128/24 container-mac-address=7A:DE:37:D7:8F:34 dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=7A:DE:37:D7:8F:33 name=\ +< veth-app-n8n +< add address=172.18.0.129/24 container-mac-address=58:F7:71:2B:7D:AF dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=58:F7:71:2B:7D:AE name=\ +< veth-app-netbox +< add address=172.18.0.130/24 container-mac-address=14:49:0C:95:C7:2F dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=14:49:0C:95:C7:2E name=\ +< veth-app-nextcloud +< add address=172.18.0.131/24 container-mac-address=2C:AF:0D:A3:A4:C0 dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=2C:AF:0D:A3:A4:BF name=\ +< veth-app-nextcloud-whiteboard +< add address=172.18.0.132/24 container-mac-address=5C:8A:C9:60:8A:0C dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=5C:8A:C9:60:8A:0B name=\ +< veth-app-nocodb +< add address=172.18.0.133/24 container-mac-address=26:FF:3E:D9:92:3C dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=26:FF:3E:D9:92:3B name=\ +< veth-app-nodered +< add address=172.18.0.134/24 container-mac-address=5E:04:3F:C8:9F:DC dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=5E:04:3F:C8:9F:DB name=\ +< veth-app-ntfy +< add address=172.18.0.135/24 container-mac-address=04:FD:C7:24:B9:83 dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=04:FD:C7:24:B9:82 name=\ +< veth-app-nzbget +< add address=172.18.0.136/24 container-mac-address=70:D6:AD:D5:83:6C dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=70:D6:AD:D5:83:6B name=\ +< veth-app-odoo +< add address=172.18.0.137/24 container-mac-address=6C:78:81:2F:C7:E1 dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=6C:78:81:2F:C7:E0 name=\ +< veth-app-onlyoffice-docs +< add address=172.18.0.138/24 container-mac-address=14:2C:6B:CD:38:F8 dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=14:2C:6B:CD:38:F7 name=\ +< veth-app-openwebrx +< add address=172.18.0.139/24 container-mac-address=12:80:BF:18:9C:2D dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=12:80:BF:18:9C:2C name=\ +< veth-app-openwebui-ollama +< add address="" container-mac-address=7C:A9:C1:01:00:A8 dhcp=yes gateway="" \ +< gateway6="" mac-address=7C:A9:C1:01:00:A7 name=veth-app-otbr +< add address=172.18.0.140/24 container-mac-address=3C:3C:83:78:99:9C dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=3C:3C:83:78:99:9B name=\ +< veth-app-paperless-ngx +< add address=172.18.0.141/24 container-mac-address=14:7D:DE:0A:7D:3E dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=14:7D:DE:0A:7D:3D name=\ +< veth-app-partdb +< add address=172.18.0.142/24 container-mac-address=42:51:A4:56:2C:01 dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=42:51:A4:56:2C:00 name=\ +< veth-app-pihole +< add address="" container-mac-address=62:F7:54:A9:35:2F dhcp=yes gateway="" \ +< gateway6="" mac-address=62:F7:54:A9:35:2E name=veth-app-plex +< add address=172.18.0.143/24 container-mac-address=1E:DF:41:E5:CA:54 dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=1E:DF:41:E5:CA:53 name=\ +< veth-app-pmacct-netflow +< add address=172.18.0.144/24 container-mac-address=5C:CB:E9:A8:2E:9D dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=5C:CB:E9:A8:2E:9C name=\ +< veth-app-prowlarr +< add address=172.18.0.145/24 container-mac-address=1A:7F:F4:E3:00:EC dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=1A:7F:F4:E3:00:EB name=\ +< veth-app-radarr +< add address=172.18.0.146/24 container-mac-address=0E:5D:27:64:6B:9A dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=0E:5D:27:64:6B:99 name=\ +< veth-app-redlib +< add address=172.18.0.147/24 container-mac-address=70:53:0A:7B:9C:DE dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=70:53:0A:7B:9C:DD name=\ +< veth-app-restic-server +< add address=172.18.0.148/24 container-mac-address=16:EA:91:AD:90:65 dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=16:EA:91:AD:90:64 name=\ +< veth-app-roundcube +< add address=172.18.0.149/24 container-mac-address=76:7F:C7:2F:83:4D dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=76:7F:C7:2F:83:4C name=\ +< veth-app-searxng +< add address=172.18.0.150/24 container-mac-address=5A:29:98:DD:76:93 dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=5A:29:98:DD:76:92 name=\ +< veth-app-smokeping +< add address=172.18.0.151/24 container-mac-address=5C:46:75:4E:9D:CA dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=5C:46:75:4E:9D:C9 name=\ +< veth-app-snipeit +< add address=172.18.0.152/24 container-mac-address=7C:51:1E:41:F3:4B dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=7C:51:1E:41:F3:4A name=\ +< veth-app-solr +< add address=172.18.0.153/24 container-mac-address=44:F8:FA:B3:FD:85 dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=44:F8:FA:B3:FD:84 name=\ +< veth-app-sonarr +< add address=172.18.0.154/24 container-mac-address=2C:6E:24:20:9D:76 dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=2C:6E:24:20:9D:75 name=\ +< veth-app-sonatype-nexus +< add address=172.18.0.155/24 container-mac-address=42:15:B0:E1:D2:12 dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=42:15:B0:E1:D2:11 name=\ +< veth-app-stalwart +< add address="" container-mac-address=1C:25:DA:CC:A8:50 dhcp=yes gateway="" \ +< gateway6="" mac-address=1C:25:DA:CC:A8:4F name=veth-app-syncthing +< add address="" container-mac-address=5C:9F:57:A2:76:0A dhcp=yes gateway="" \ +< gateway6="" mac-address=5C:9F:57:A2:76:09 name=veth-app-transmission +< add address=172.18.0.156/24 container-mac-address=6E:8D:8A:28:07:6B dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=6E:8D:8A:28:07:6A name=\ +< veth-app-trip +< add address="" container-mac-address=20:F1:91:9F:FA:E0 dhcp=yes gateway="" \ +< gateway6="" mac-address=20:F1:91:9F:FA:DF name=veth-app-upsnap +< add address=172.18.0.157/24 container-mac-address=7C:10:8F:BB:A4:42 dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=7C:10:8F:BB:A4:41 name=\ +< veth-app-uptime-kuma +< add address=172.18.0.158/24 container-mac-address=12:E4:E5:5E:C3:00 dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=12:E4:E5:5E:C2:FF name=\ +< veth-app-urbackup-client +< add address=172.18.0.159/24 container-mac-address=54:09:04:00:DB:55 dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=54:09:04:00:DB:54 name=\ +< veth-app-urbackup-server +< add address=172.18.0.160/24 container-mac-address=1A:4E:86:63:C7:BD dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=1A:4E:86:63:C7:BC name=\ +< veth-app-vaultwarden +< add address=172.18.0.161/24 container-mac-address=0C:8F:A2:49:05:F4 dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=0C:8F:A2:49:05:F3 name=\ +< veth-app-victoria-logs +< add address=172.18.0.162/24 container-mac-address=20:77:3C:61:F3:94 dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=20:77:3C:61:F3:93 name=\ +< veth-app-victoria-metrics +< add address=172.18.0.163/24 container-mac-address=6E:B1:F6:2A:2B:BB dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=6E:B1:F6:2A:2B:BA name=\ +< veth-app-viseron +< add address=172.18.0.164/24 container-mac-address=30:25:73:ED:93:7D dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=30:25:73:ED:93:7C name=\ +< veth-app-wallabag +< add address=172.18.0.165/24 container-mac-address=7E:43:A5:4C:F8:CC dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=7E:43:A5:4C:F8:CB name=\ +< veth-app-warracker +< add address=172.18.0.166/24 container-mac-address=5E:78:97:44:FF:BB dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=5E:78:97:44:FF:BA name=\ +< veth-app-wbo +< add address=172.18.0.167/24 container-mac-address=06:96:D9:F1:19:7F dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=06:96:D9:F1:19:7E name=\ +< veth-app-webtop +< add address=172.18.0.168/24 container-mac-address=1E:FE:CB:5B:B0:4C dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=1E:FE:CB:5B:B0:4B name=\ +< veth-app-wordpress +< add address=172.18.0.169/24 container-mac-address=34:67:6E:5B:7D:E7 dhcp=no \ +< gateway=172.18.0.1 gateway6="" mac-address=34:67:6E:5B:7D:E6 name=\ +< veth-app-zabbix +316,317d32 +< add file-path=/sata1/swap file-size=2046.9MiB slot=file-sata1-swap swap=yes \ +< type=file +5625,5684c5340 +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set HA-otbr-matter disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set adventurelog disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set babybuddy disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set backrest disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set birdnet-go disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set caddy disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set calibre-web disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set chr disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set cinny disabled=no firewall-redirects=8094:80:tcp:web +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set cloudflared disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set code-server disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set conduit disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set convertx disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set copyparty disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set cryptpad disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set diagrams-net disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set docker-with-dockge disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set docker-with-komodo disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set docker-with-portainer disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set docmost disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set elasticsearch disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set element disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set excalidraw disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set filegator disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set firefox disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set forgejo disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set fossil disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set frigate disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set gitea disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set gitlab disabled=no +--- +> set cinny firewall-redirects=8094:80:tcp:web +5686,5690d5341 +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set grafana disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set hedgedoc disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +5692,5731c5343,5344 +< home-assistant:none:lscr.io/linuxserver/homeassistant disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set immich disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set influxdb disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set jackett disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set jellyfin disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set jupyter-notebook disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set kimai disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set librenms disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set librespeed disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set lidarr disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set livebook disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set mediamanager disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set memos disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set metube disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set mikrodash disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set minio disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set mosquitto disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set myip disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set n8n disabled=no firewall-redirects=5678:5678:tcp:web +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set netbox disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +--- +> home-assistant:none:lscr.io/linuxserver/homeassistant +> set n8n firewall-redirects=5678:5678:tcp:web +5735,5799c5348,5352 +< ache" disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set nextcloud-whiteboard disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set nocodb disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set nodered disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set ntfy disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set nzbget disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set odoo disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set onlyoffice-docs disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set openwebrx disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set openwebui-ollama disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set otbr disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set paperless-ngx disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set partdb disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set pihole disabled=no environment="pihole:FTLCONF_dns_listeningMode=all,pihol\ +< e:FTLCONF_webserver_api_password=password" +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set plex disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set pmacct-netflow disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set prowlarr disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set radarr disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set redlib disabled=no firewall-redirects=8087:8080:tcp:web +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set restic-server disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set roundcube disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set searxng disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set smokeping disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set snipeit disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set solr container-command-lines=solr:none:docker.io/solr:latest disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set sonarr disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set sonatype-nexus disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set stalwart disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set syncthing disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set transmission disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set trip disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set upsnap disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +--- +> 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 +5801,5825c5354 +< uptime-kuma:none:docker.io/louislam/uptime-kuma:1 disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set urbackup-client disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set urbackup-server disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set vaultwarden disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set victoria-logs disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set victoria-metrics disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set viseron disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set wallabag disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set warracker disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set wbo disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set webtop disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set wordpress disabled=no +< # certificate: connecting to https://acme-v02.api.letsencrypt.org/directory +< set zabbix disabled=no +--- +> uptime-kuma:none:docker.io/louislam/uptime-kuma:1 +5827,5829c5356,5357 +< set auto-update=yes disk=*7 lan-bridge=Bridge-LAN registry-mirrors="https://re\ +< g.vados.ru/:https://reg.vados.ru/,https://registry-1.docker.io:https://reg\ +< istry-1.docker.io,https://ghcr.io:https://ghcr.io" +--- +> set auto-update=yes disk=*7 lan-bridge=*3 registry-mirrors="https://reg.vados.\ +> ru:5000/:https://reg.vados.ru/,https://registry-1.docker.io" +5875,5876d5402 +< /certificate settings +< set builtin-trust-store=all crl-use=yes -- 2.52.0