Compare commits
No commits in common. "main" and "v1.0.114" have entirely different histories.
@ -1,57 +0,0 @@
|
|||||||
echo "=== TEST PORTA 5000 ===" && curl -s -o /dev/null -w "HTTP %{http_code}\n" http://localhost:5000/api/health && echo "=== TEST AUTO-BLOCK MANUALE ===" && sudo -u ids /opt/ids/python_ml/venv/bin/python3 /opt/ids/python_ml/auto_block.py 2>&1 && echo "=== STATO TUTTI I SERVIZI ===" && systemctl status ids-backend ids-ml-backend ids-syslog-parser ids-auto-block.timer --no-pager -l
|
|
||||||
=== TEST PORTA 5000 ===
|
|
||||||
HTTP 200
|
|
||||||
=== TEST AUTO-BLOCK MANUALE ===
|
|
||||||
[2026-02-17 08:51:22] Starting auto-block cycle...
|
|
||||||
[2026-02-17 08:51:22] Step 1: Detection ML...
|
|
||||||
[2026-02-17 08:51:22] Detection completata: 0 anomalie rilevate
|
|
||||||
[2026-02-17 08:51:22] Step 2: Blocco IP critici sui router...
|
|
||||||
[2026-02-17 08:51:22] 24 IP bloccati sui router, 0 falliti, 0 gia' bloccati
|
|
||||||
=== STATO TUTTI I SERVIZI ===
|
|
||||||
● ids-backend.service - IDS Node.js Backend (Express API + Frontend)
|
|
||||||
Loaded: loaded (/etc/systemd/system/ids-backend.service; enabled; preset: disabled)
|
|
||||||
Active: active (running) since Tue 2026-02-17 08:51:09 CET; 57s ago
|
|
||||||
Process: 31307 ExecStartPre=/bin/bash -c test -f /opt/ids/dist/index.js || (echo "ERRORE: dist/index.js non trovato - eseguire npm run build" && exit 1) (code=exited, status=0/SUCCESS)
|
|
||||||
Main PID: 31308 (node)
|
|
||||||
Tasks: 11 (limit: 100409)
|
|
||||||
Memory: 59.1M (max: 1.0G available: 964.8M)
|
|
||||||
CPU: 1.669s
|
|
||||||
CGroup: /system.slice/ids-backend.service
|
|
||||||
└─31308 node dist/index.js
|
|
||||||
|
|
||||||
Feb 17 08:51:09 ids.alfacom.it systemd[1]: Starting IDS Node.js Backend (Express API + Frontend)...
|
|
||||||
Feb 17 08:51:09 ids.alfacom.it systemd[1]: Started IDS Node.js Backend (Express API + Frontend).
|
|
||||||
|
|
||||||
● ids-ml-backend.service - IDS ML Backend (FastAPI)
|
|
||||||
Loaded: loaded (/etc/systemd/system/ids-ml-backend.service; enabled; preset: disabled)
|
|
||||||
Active: active (running) since Tue 2026-02-17 08:50:14 CET; 1min 51s ago
|
|
||||||
Main PID: 31127 (python3)
|
|
||||||
Tasks: 26 (limit: 100409)
|
|
||||||
Memory: 256.8M (max: 2.0G available: 1.7G)
|
|
||||||
CPU: 4.073s
|
|
||||||
CGroup: /system.slice/ids-ml-backend.service
|
|
||||||
└─31127 /opt/ids/python_ml/venv/bin/python3 main.py
|
|
||||||
|
|
||||||
Feb 17 08:50:14 ids.alfacom.it systemd[1]: Started IDS ML Backend (FastAPI).
|
|
||||||
|
|
||||||
● ids-syslog-parser.service - IDS Syslog Parser (Network Logs Processor)
|
|
||||||
Loaded: loaded (/etc/systemd/system/ids-syslog-parser.service; enabled; preset: disabled)
|
|
||||||
Active: active (running) since Mon 2026-02-16 12:18:52 CET; 20h ago
|
|
||||||
Main PID: 1069 (python3)
|
|
||||||
Tasks: 1 (limit: 100409)
|
|
||||||
Memory: 9.7M (max: 1.0G available: 1014.2M)
|
|
||||||
CPU: 1h 59min 34.854s
|
|
||||||
CGroup: /system.slice/ids-syslog-parser.service
|
|
||||||
└─1069 /opt/ids/python_ml/venv/bin/python3 syslog_parser.py
|
|
||||||
|
|
||||||
Feb 16 12:18:52 ids.alfacom.it systemd[1]: Started IDS Syslog Parser (Network Logs Processor).
|
|
||||||
|
|
||||||
● ids-auto-block.timer - IDS Auto-Blocking Timer - Run every 5 minutes
|
|
||||||
Loaded: loaded (/etc/systemd/system/ids-auto-block.timer; enabled; preset: disabled)
|
|
||||||
Active: active (running) since Mon 2026-02-16 19:24:04 CET; 13h ago
|
|
||||||
Until: Mon 2026-02-16 19:24:04 CET; 13h ago
|
|
||||||
Trigger: n/a
|
|
||||||
Triggers: ● ids-auto-block.service
|
|
||||||
Docs: https://github.com/yourusername/ids
|
|
||||||
|
|
||||||
Feb 16 19:24:04 ids.alfacom.it systemd[1]: Started IDS Auto-Blocking Timer - Run every 5 minutes.
|
|
||||||
@ -1,85 +0,0 @@
|
|||||||
tail -f /var/log/ids/backend.log
|
|
||||||
9:21:00 AM [express] GET /api/detections 304 in 19ms :: {"detections":[{"id":"fcde52d3-0ae4-4904-a7c…
|
|
||||||
9:21:01 AM [express] GET /api/services/status 200 in 29ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:21:02 AM [express] GET /api/routers 200 in 3ms :: [{"id":"c6904896-59dc-4060-952f-0e55df7dee4a","n…
|
|
||||||
9:21:12 AM [express] PUT /api/routers/c6904896-59dc-4060-952f-0e55df7dee4a 200 in 8ms :: {"id":"c690…
|
|
||||||
9:21:12 AM [express] GET /api/routers 304 in 2ms :: [{"id":"c6904896-59dc-4060-952f-0e55df7dee4a","n…
|
|
||||||
9:22:16 AM [express] POST /api/ml/block-all-critical 200 in 99ms :: {"message":"Nessun IP critico da…
|
|
||||||
9:24:17 AM [express] POST /api/ml/block-all-critical 200 in 75ms :: {"message":"Nessun IP critico da…
|
|
||||||
Using standard PostgreSQL database
|
|
||||||
9:26:18 AM [express] serving on port 5000
|
|
||||||
✅ Database connection successful
|
|
||||||
9:28:19 AM [express] POST /api/ml/block-all-critical 200 in 93ms :: {"message":"Nessun IP critico da…
|
|
||||||
9:30:19 AM [express] POST /api/ml/block-all-critical 200 in 82ms :: {"message":"Nessun IP critico da…
|
|
||||||
9:30:25 AM [express] GET /api/training-history 200 in 6ms :: [{"id":"7570df54-8169-4fb2-abdc-e9c1bfa…
|
|
||||||
9:30:29 AM [express] GET /api/detections 200 in 24ms :: {"detections":[{"id":"fcde52d3-0ae4-4904-a7c…
|
|
||||||
9:30:29 AM [express] GET /api/whitelist 200 in 259ms :: {"items":[{"id":"49b5b9a9-4683-452c-a784-fc5…
|
|
||||||
9:30:37 AM [express] GET /api/services/status 200 in 22ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:30:39 AM [express] POST /api/services/ids-syslog-parser/start 500 in 22ms :: {"error":"Service con…
|
|
||||||
9:30:42 AM [express] GET /api/services/status 200 in 21ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:30:47 AM [express] GET /api/services/status 200 in 18ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:30:52 AM [express] GET /api/services/status 200 in 17ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:30:57 AM [express] GET /api/services/status 200 in 17ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:31:02 AM [express] GET /api/services/status 200 in 17ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:31:07 AM [express] GET /api/services/status 200 in 23ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:31:12 AM [express] GET /api/services/status 200 in 18ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:31:16 AM [express] GET /api/services/status 200 in 18ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:31:21 AM [express] GET /api/services/status 200 in 17ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:31:26 AM [express] GET /api/services/status 200 in 17ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:31:27 AM [express] GET /api/detections 304 in 11ms :: {"detections":[{"id":"fcde52d3-0ae4-4904-a7c…
|
|
||||||
9:31:27 AM [express] GET /api/whitelist 200 in 229ms :: {"items":[{"id":"91108765-7ef6-4e49-87d8-319…
|
|
||||||
9:31:30 AM [express] GET /api/public-lists 200 in 5ms :: [{"id":"2a835798-02a7-4129-a528-d39a026ad15…
|
|
||||||
9:31:32 AM [express] GET /api/services/status 200 in 19ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:31:37 AM [express] GET /api/services/status 200 in 20ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:31:42 AM [express] GET /api/services/status 200 in 19ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:31:47 AM [express] GET /api/services/status 200 in 18ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:31:52 AM [express] GET /api/services/status 200 in 17ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:31:57 AM [express] GET /api/services/status 200 in 21ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:32:02 AM [express] GET /api/services/status 200 in 18ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:32:07 AM [express] GET /api/services/status 200 in 24ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:32:12 AM [express] GET /api/services/status 200 in 24ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:32:17 AM [express] GET /api/services/status 200 in 23ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:32:25 AM [express] GET /api/services/status 200 in 2875ms :: {"services":{"mlBackend":{"name":"ML …
|
|
||||||
[BLOCK-ALL] Avvio blocco massivo: 11/11 IP con score >= 80 su 2 router
|
|
||||||
[BULK-BLOCK] Starting: 11 IPs on 2 routers (10.20.30.100, 185.203.24.2)
|
|
||||||
[BULK-BLOCK] Router 185.203.24.2: 124 IPs already in list (50ms)
|
|
||||||
9:32:30 AM [express] GET /api/services/status 200 in 31ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:32:35 AM [express] GET /api/services/status 200 in 31ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:32:40 AM [express] GET /api/services/status 200 in 46ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:32:46 AM [express] GET /api/services/status 200 in 75ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
[MIKROTIK] Failed to get address-list from 10.20.30.100: This operation was aborted
|
|
||||||
[BULK-BLOCK] Router 10.20.30.100: 0 IPs already in list (20004ms)
|
|
||||||
[BULK-BLOCK] 0 already blocked, 11 new to block
|
|
||||||
9:32:51 AM [express] GET /api/services/status 200 in 40ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8002ms for IP 87.17.182.32: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 185.98.164.31: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 109.115.163.146: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8002ms for IP 2.118.225.238: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 74.125.99.38: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 192.178.112.96: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 74.125.111.102: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 212.14.142.214: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8000ms for IP 89.96.215.146: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 172.217.39.230: This operation was aborted
|
|
||||||
9:32:56 AM [express] GET /api/services/status 200 in 44ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:33:01 AM [express] GET /api/services/status 200 in 46ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8002ms for IP 104.19.148.8: This operation was aborted
|
|
||||||
[BULK-BLOCK] Progress: 11/11
|
|
||||||
[BULK-BLOCK] Router 10.20.30.100: 0 blocked, 11 failed, 0 skipped
|
|
||||||
[BULK-BLOCK] Router 185.203.24.2: 11 blocked, 0 failed, 0 skipped
|
|
||||||
[BULK-BLOCK] Done: 11 blocked, 0 failed, 0 skipped
|
|
||||||
[BLOCK-ALL] Database aggiornato: 11 IP marcati come bloccati
|
|
||||||
9:33:03 AM [express] POST /api/ml/block-all-critical 200 in 36137ms :: {"message":"Blocco massivo co…
|
|
||||||
9:33:07 AM [express] GET /api/services/status 200 in 1125ms :: {"services":{"mlBackend":{"name":"ML …
|
|
||||||
9:33:12 AM [express] GET /api/services/status 200 in 40ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:33:17 AM [express] GET /api/services/status 200 in 56ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:33:22 AM [express] GET /api/services/status 200 in 58ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:33:27 AM [express] GET /api/services/status 200 in 57ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:33:32 AM [express] GET /api/services/status 200 in 57ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:33:37 AM [express] GET /api/services/status 200 in 52ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:33:42 AM [express] GET /api/services/status 200 in 77ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:33:48 AM [express] GET /api/services/status 200 in 50ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:33:53 AM [express] GET /api/services/status 200 in 72ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:33:58 AM [express] GET /api/services/status 200 in 69ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:34:03 AM [express] GET /api/services/status 200 in 64ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:34:08 AM [express] GET /api/services/status 200 in 79ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
@ -1,224 +0,0 @@
|
|||||||
tail -f /var/log/ids/backend.log
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8000ms for IP 188.8.66.34: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 151.101.193.229: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 109.205.211.40: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 151.59.33.110: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8002ms for IP 151.73.209.26: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 79.8.248.29: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 217.202.28.18: This operation was aborted
|
|
||||||
Using standard PostgreSQL database
|
|
||||||
9:13:09 AM [express] serving on port 5000
|
|
||||||
✅ Database connection successful
|
|
||||||
[BLOCK-ALL] Avvio blocco massivo: 100/100 IP con score >= 80 su 2 router
|
|
||||||
[BULK-BLOCK] Starting: 100 IPs on 2 routers (10.20.30.100, 185.203.24.2)
|
|
||||||
[BULK-BLOCK] Router 185.203.24.2: 74 IPs already in list (38ms)
|
|
||||||
9:14:15 AM [express] GET /api/detections 200 in 17ms :: {"detections":[{"id":"fcde52d3-0ae4-4904-a7c…
|
|
||||||
9:14:15 AM [express] GET /api/services/status 200 in 42ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:14:20 AM [express] GET /api/detections 200 in 19ms :: {"detections":[{"id":"fcde52d3-0ae4-4904-a7c…
|
|
||||||
9:14:20 AM [express] GET /api/services/status 200 in 20ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:14:25 AM [express] GET /api/detections 200 in 7ms :: {"detections":[{"id":"fcde52d3-0ae4-4904-a7cf…
|
|
||||||
9:14:25 AM [express] GET /api/whitelist 200 in 222ms :: {"items":[{"id":"4b7a60b4-b47c-431e-8efa-864…
|
|
||||||
[MIKROTIK] Failed to get address-list from 10.20.30.100: This operation was aborted
|
|
||||||
[BULK-BLOCK] Router 10.20.30.100: 0 IPs already in list (20004ms)
|
|
||||||
[BULK-BLOCK] 0 already blocked, 100 new to block
|
|
||||||
9:14:35 AM [express] GET /api/detections 200 in 8ms :: {"detections":[{"id":"fcde52d3-0ae4-4904-a7cf…
|
|
||||||
9:14:39 AM [express] GET /api/training-history 200 in 5ms :: [{"id":"4306f5a1-b30b-4241-97d9-6b6a1e2…
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8003ms for IP 151.73.24.49: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 104.16.248.249: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 77.39.130.185: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8002ms for IP 104.16.249.249: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8002ms for IP 104.18.36.146: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8003ms for IP 193.205.185.20: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8003ms for IP 50.93.53.165: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8004ms for IP 91.208.175.82: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8004ms for IP 74.0.42.209: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8005ms for IP 79.6.115.203: This operation was aborted
|
|
||||||
9:14:50 AM [express] GET /api/detections 200 in 31ms :: {"detections":[{"id":"fcde52d3-0ae4-4904-a7c…
|
|
||||||
9:14:50 AM [express] GET /api/whitelist 200 in 246ms :: {"items":[{"id":"49b5b9a9-4683-452c-a784-fc5…
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8002ms for IP 142.250.181.168: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8002ms for IP 195.32.127.72: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8002ms for IP 93.150.41.42: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 212.183.171.12: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8003ms for IP 78.134.17.204: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8002ms for IP 62.94.77.251: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8003ms for IP 151.73.24.107: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8003ms for IP 74.125.45.108: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8003ms for IP 2.42.47.211: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8004ms for IP 89.97.31.234: This operation was aborted
|
|
||||||
9:14:52 AM [express] GET /api/dashboard/live 200 in 12ms :: {"totalPackets":75520962,"attackPackets"…
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8002ms for IP 31.197.212.130: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8002ms for IP 44.197.141.31: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8002ms for IP 146.75.61.140: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8002ms for IP 93.150.200.81: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8002ms for IP 101.56.92.15: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8003ms for IP 2.33.192.82: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8003ms for IP 151.41.104.237: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8003ms for IP 77.39.220.111: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8003ms for IP 185.96.131.245: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8004ms for IP 142.250.181.164: This operation was aborted
|
|
||||||
9:15:00 AM [express] GET /api/routers 200 in 16ms :: [{"id":"c6904896-59dc-4060-952f-0e55df7dee4a","…
|
|
||||||
9:15:00 AM [express] GET /api/detections 200 in 24ms :: {"detections":[{"id":"fcde52d3-0ae4-4904-a7c…
|
|
||||||
9:15:00 AM [express] GET /api/services/status 200 in 28ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:15:05 AM [express] GET /api/detections 200 in 11ms :: {"detections":[{"id":"fcde52d3-0ae4-4904-a7c…
|
|
||||||
9:15:05 AM [express] GET /api/services/status 200 in 18ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:15:06 AM [express] GET /api/stats 200 in 5385ms :: {"routers":{"total":2,"enabled":2},"detections"…
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 45.146.216.240: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 62.112.11.234: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8002ms for IP 51.159.85.76: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 188.8.66.34: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8002ms for IP 151.101.193.229: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 109.205.211.40: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8003ms for IP 151.59.33.110: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8003ms for IP 151.73.209.26: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8003ms for IP 79.8.248.29: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8003ms for IP 217.202.28.18: This operation was aborted
|
|
||||||
[ANALYTICS QUERY] {
|
|
||||||
startDate: '2026-01-18T08:15:10.899Z',
|
|
||||||
endDate: '2026-02-17T08:15:10.899Z',
|
|
||||||
hourly: true,
|
|
||||||
hourCondition: 'NOT NULL'
|
|
||||||
}
|
|
||||||
[ANALYTICS RESULTS] 41 records found
|
|
||||||
[ANALYTICS SAMPLE] {
|
|
||||||
id: 'b3216c05-7f95-4ba9-a5fb-b37461441401',
|
|
||||||
date: 2026-02-16T00:00:00.000Z,
|
|
||||||
hour: 23,
|
|
||||||
totalPackets: 10463767,
|
|
||||||
totalBytes: 13102201398,
|
|
||||||
uniqueIps: 25472,
|
|
||||||
normalPackets: 10463767,
|
|
||||||
normalBytes: 13102201398,
|
|
||||||
normalUniqueIps: 25472,
|
|
||||||
topNormalIps: '[{"ip": "88.39.149.52", "packets": 3744014, "bytes": 5747025096, "country": null}, {"ip": "79.11.175.156", "packets": 1279527, "bytes": 1892212998, "country": null}, {"ip": "95.229.133.69", "packets": 1188856, "bytes": 1758976078, "country": null}, {"ip": "188.12.75.242", "packets": 1168922, "bytes": 1729133469, "country": null}, {"ip": "95.229.85.134", "packets": 1151191, "bytes": 1703382127, "country": null}, {"ip": "74.125.45.108", "packets": 108382, "bytes": 13501983, "country": "United States"}, {"ip": "185.243.5.22", "packets": 87376, "bytes": 38384352, "country": null}, {"ip": "104.16.248.249", "packets": 72117, "bytes": 40864635, "country": "Canada"}, {"ip": "8.8.8.8", "packets": 66005, "bytes": 18862021, "country": "United States"}, {"ip": "95.110.183.67", "packets": 51456, "bytes": 2281666, "country": "Italy"}]',
|
|
||||||
attackPackets: 0,
|
|
||||||
attackBytes: 0,
|
|
||||||
attackUniqueIps: 0,
|
|
||||||
attacksByCountry: '{}',
|
|
||||||
attacksByType: '{}',
|
|
||||||
topAttackers: '[]',
|
|
||||||
trafficByCountry: '{"Canada": {"normal": 81941, "attacks": 0}, "The Netherlands": {"normal": 49409, "attacks": 0}, "Singapore": {"normal": 61, "attacks": 0}, "Germany": {"normal": 339, "attacks": 0}, "United States":
|
|
||||||
{"normal": 385230, "attacks": 0}, "Italy": {"normal": 73801, "attacks": 0}, "Netherlands": {"normal": 19928, "attacks": 0}}',
|
|
||||||
createdAt: 2026-02-17T00:05:00.185Z
|
|
||||||
}
|
|
||||||
9:15:10 AM [express] GET /api/analytics/recent 200 in 16ms :: [{"id":"b3216c05-7f95-4ba9-a5fb-b37461…
|
|
||||||
9:15:12 AM [express] GET /api/training-history 200 in 3ms :: [{"id":"4306f5a1-b30b-4241-97d9-6b6a1e2…
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 7968ms for IP 151.73.139.162: HTTP 401: {"error":401,"message":"Unauthorized"}
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 7969ms for IP 217.28.70.122: HTTP 401: {"error":401,"message":"Unauthorized"}
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 7971ms for IP 79.9.120.141: HTTP 401: {"error":401,"message":"Unauthorized"}
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 7971ms for IP 52.123.129.14: HTTP 401: {"error":401,"message":"Unauthorized"}
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 7970ms for IP 157.240.231.35: HTTP 401: {"error":401,"message":"Unauthorized"}
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 7975ms for IP 46.229.84.162: HTTP 401: {"error":401,"message":"Unauthorized"}
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 7973ms for IP 178.248.182.171: HTTP 401: {"error":401,"message":"Unauthorized"}
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 7974ms for IP 93.43.107.86: HTTP 401: {"error":401,"message":"Unauthorized"}
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 7974ms for IP 178.248.51.104: HTTP 401: {"error":401,"message":"Unauthorized"}
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 7977ms for IP 93.51.52.251: HTTP 401: {"error":401,"message":"Unauthorized"}
|
|
||||||
[BULK-BLOCK] Progress: 50/100
|
|
||||||
9:15:19 AM [express] GET /api/ml/stats 200 in 6466ms :: {"logs":{"total":126216346,"last_hour":0},"d…
|
|
||||||
9:15:22 AM [express] POST /api/ml/train 200 in 10ms :: {"message":"Training avviato in background","…
|
|
||||||
9:15:22 AM [express] GET /api/training-history 304 in 3ms :: [{"id":"4306f5a1-b30b-4241-97d9-6b6a1e2…
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 85.44.118.45: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 2.228.8.122: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8000ms for IP 188.217.110.96: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 151.84.198.239: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8002ms for IP 93.54.65.87: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8002ms for IP 213.82.166.186: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8002ms for IP 23.216.150.137: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8002ms for IP 185.110.20.185: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8002ms for IP 95.100.171.8: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8002ms for IP 79.11.222.236: This operation was aborted
|
|
||||||
9:15:28 AM [express] GET /api/ml/stats 304 in 6490ms :: {"logs":{"total":126216346,"last_hour":0},"d…
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 85.35.59.252: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 79.10.32.9: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 79.13.197.84: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 94.85.21.211: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 213.215.214.82: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 185.82.114.4: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 5.158.71.206: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 94.34.87.184: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 93.67.251.46: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 31.7.147.21: This operation was aborted
|
|
||||||
9:15:32 AM [express] GET /api/training-history 304 in 15ms :: [{"id":"4306f5a1-b30b-4241-97d9-6b6a1e…
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 91.187.197.104: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 172.217.38.150: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 217.141.0.110: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 172.217.38.157: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 140.82.121.3: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 95.255.202.79: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 151.58.132.84: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 82.55.154.58: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 62.98.165.6: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 95.110.183.67: This operation was aborted
|
|
||||||
9:15:42 AM [express] GET /api/training-history 304 in 16ms :: [{"id":"4306f5a1-b30b-4241-97d9-6b6a1e…
|
|
||||||
9:15:45 AM [express] GET /api/ml/stats 304 in 7198ms :: {"logs":{"total":126216346,"last_hour":0},"d…
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 93.40.225.146: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 216.128.11.53: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 95.230.242.4: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 2.118.179.69: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8002ms for IP 188.8.204.7: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 185.168.176.197: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8002ms for IP 93.64.198.214: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 217.202.56.187: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8002ms for IP 5.63.174.25: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 151.64.151.157: This operation was aborted
|
|
||||||
9:15:52 AM [express] GET /api/training-history 304 in 17ms :: [{"id":"4306f5a1-b30b-4241-97d9-6b6a1e…
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 79.2.176.5: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 82.192.139.100: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 93.40.226.33: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 93.146.168.160: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 94.101.59.182: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 185.104.127.31: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 31.197.212.236: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8000ms for IP 79.3.132.252: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 172.217.38.148: This operation was aborted
|
|
||||||
[BULK-BLOCK] SLOW: Router 10.20.30.100 took 8001ms for IP 172.217.38.151: This operation was aborted
|
|
||||||
[BULK-BLOCK] Progress: 100/100
|
|
||||||
[BULK-BLOCK] Router 10.20.30.100: 0 blocked, 100 failed, 0 skipped
|
|
||||||
[BULK-BLOCK] Router 185.203.24.2: 50 blocked, 0 failed, 50 skipped
|
|
||||||
[BULK-BLOCK] Done: 100 blocked, 0 failed, 0 skipped
|
|
||||||
[BLOCK-ALL] Database aggiornato: 100 IP marcati come bloccati
|
|
||||||
9:15:55 AM [express] POST /api/ml/block-all-critical 200 in 100172ms :: {"message":"Blocco massivo c…
|
|
||||||
9:16:02 AM [express] GET /api/training-history 304 in 2ms :: [{"id":"4306f5a1-b30b-4241-97d9-6b6a1e2…
|
|
||||||
9:16:02 AM [express] GET /api/ml/stats 200 in 6527ms :: {"logs":{"total":126216346,"last_hour":0},"d…
|
|
||||||
9:16:12 AM [express] GET /api/training-history 304 in 13ms :: [{"id":"4306f5a1-b30b-4241-97d9-6b6a1e…
|
|
||||||
9:16:19 AM [express] GET /api/ml/stats 304 in 6558ms :: {"logs":{"total":126216346,"last_hour":0},"d…
|
|
||||||
9:16:19 AM [express] POST /api/ml/block-all-critical 200 in 76ms :: {"message":"Nessun IP critico da…
|
|
||||||
9:16:22 AM [express] GET /api/training-history 304 in 3ms :: [{"id":"4306f5a1-b30b-4241-97d9-6b6a1e2…
|
|
||||||
9:16:29 AM [express] GET /api/training-history 304 in 3ms :: [{"id":"4306f5a1-b30b-4241-97d9-6b6a1e2…
|
|
||||||
9:16:35 AM [express] GET /api/ml/stats 304 in 6623ms :: {"logs":{"total":126216346,"last_hour":0},"d…
|
|
||||||
9:16:39 AM [express] GET /api/training-history 304 in 13ms :: [{"id":"4306f5a1-b30b-4241-97d9-6b6a1e…
|
|
||||||
9:16:49 AM [express] GET /api/training-history 304 in 14ms :: [{"id":"4306f5a1-b30b-4241-97d9-6b6a1e…
|
|
||||||
9:16:59 AM [express] GET /api/training-history 304 in 15ms :: [{"id":"4306f5a1-b30b-4241-97d9-6b6a1e…
|
|
||||||
[ML Stats] Fallback to database - ML Backend error: This operation was aborted
|
|
||||||
9:17:06 AM [express] GET /api/ml/stats 200 in 20345ms :: {"source":"database_fallback","ml_backend_s…
|
|
||||||
9:17:08 AM [express] GET /api/detections 200 in 21ms :: {"detections":[{"id":"fcde52d3-0ae4-4904-a7c…
|
|
||||||
9:17:08 AM [express] GET /api/routers 200 in 21ms :: [{"id":"c6904896-59dc-4060-952f-0e55df7dee4a","…
|
|
||||||
9:17:13 AM [express] GET /api/services/status 200 in 5007ms :: {"services":{"mlBackend":{"name":"ML …
|
|
||||||
9:17:13 AM [express] GET /api/detections 304 in 8ms :: {"detections":[{"id":"fcde52d3-0ae4-4904-a7cf…
|
|
||||||
9:17:14 AM [express] GET /api/stats 200 in 5393ms :: {"routers":{"total":2,"enabled":2},"detections"…
|
|
||||||
9:17:18 AM [express] GET /api/detections 304 in 7ms :: {"detections":[{"id":"fcde52d3-0ae4-4904-a7cf…
|
|
||||||
9:17:23 AM [express] GET /api/services/status 304 in 5006ms :: {"services":{"mlBackend":{"name":"ML …
|
|
||||||
9:17:23 AM [express] GET /api/detections 304 in 7ms :: {"detections":[{"id":"fcde52d3-0ae4-4904-a7cf…
|
|
||||||
9:17:28 AM [express] GET /api/services/status 200 in 85ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:17:28 AM [express] GET /api/detections 304 in 8ms :: {"detections":[{"id":"fcde52d3-0ae4-4904-a7cf…
|
|
||||||
9:17:29 AM [express] GET /api/stats 304 in 5314ms :: {"routers":{"total":2,"enabled":2},"detections"…
|
|
||||||
9:17:33 AM [express] GET /api/services/status 200 in 29ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:17:33 AM [express] GET /api/detections 304 in 7ms :: {"detections":[{"id":"fcde52d3-0ae4-4904-a7cf…
|
|
||||||
9:17:38 AM [express] GET /api/services/status 200 in 53ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:17:39 AM [express] GET /api/detections 304 in 7ms :: {"detections":[{"id":"fcde52d3-0ae4-4904-a7cf…
|
|
||||||
9:17:43 AM [express] GET /api/services/status 200 in 70ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:17:44 AM [express] GET /api/detections 304 in 8ms :: {"detections":[{"id":"fcde52d3-0ae4-4904-a7cf…
|
|
||||||
9:17:44 AM [express] GET /api/stats 304 in 5395ms :: {"routers":{"total":2,"enabled":2},"detections"…
|
|
||||||
9:17:49 AM [express] GET /api/services/status 200 in 47ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:17:49 AM [express] GET /api/detections 304 in 7ms :: {"detections":[{"id":"fcde52d3-0ae4-4904-a7cf…
|
|
||||||
9:17:54 AM [express] GET /api/detections 304 in 12ms :: {"detections":[{"id":"fcde52d3-0ae4-4904-a7c…
|
|
||||||
9:17:54 AM [express] GET /api/services/status 200 in 61ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:17:59 AM [express] GET /api/detections 304 in 11ms :: {"detections":[{"id":"fcde52d3-0ae4-4904-a7c…
|
|
||||||
9:17:59 AM [express] GET /api/services/status 200 in 30ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:18:00 AM [express] GET /api/stats 304 in 5405ms :: {"routers":{"total":2,"enabled":2},"detections"…
|
|
||||||
9:18:04 AM [express] GET /api/detections 304 in 7ms :: {"detections":[{"id":"fcde52d3-0ae4-4904-a7cf…
|
|
||||||
9:18:04 AM [express] GET /api/services/status 200 in 64ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:18:09 AM [express] GET /api/detections 304 in 8ms :: {"detections":[{"id":"fcde52d3-0ae4-4904-a7cf…
|
|
||||||
9:18:09 AM [express] GET /api/services/status 200 in 21ms :: {"services":{"mlBackend":{"name":"ML Ba…
|
|
||||||
9:18:14 AM [express] GET /api/detections 304 in 21ms :: {"detections":[{"id":"fcde52d3-0ae4-4904-a7c…
|
|
||||||
9:18:15 AM [express] GET /api/stats 304 in 5344ms :: {"routers":{"total":2,"enabled":2},"detections"…
|
|
||||||
|
|
||||||
@ -1,41 +0,0 @@
|
|||||||
Cerca il watchdog che riavvia il backend
|
|
||||||
grep -r "Backend Python NON attivo" /opt/ids/ --include="*.sh"
|
|
||||||
grep -r "Backend Python NON attivo" /etc/cron* /var/spool/cron/
|
|
||||||
|
|
||||||
# Verifica cron jobs attivi
|
|
||||||
crontab -l
|
|
||||||
crontab -l -u ids
|
|
||||||
|
|
||||||
# Verifica timer systemd
|
|
||||||
systemctl list-timers --all | grep ids
|
|
||||||
/opt/ids/deployment/check_backend.sh: echo "[$(date)] Backend Python NON attivo, riavvio..." >> "$LOG_FILE"
|
|
||||||
# ============================================
|
|
||||||
# SISTEMA IDS - CONFIGURAZIONE AUTOMATICA
|
|
||||||
# ============================================
|
|
||||||
|
|
||||||
# Training ML ogni 12 ore (alle 00:00 e 12:00)
|
|
||||||
0 */12 * * * /opt/ids/deployment/cron_train.sh
|
|
||||||
|
|
||||||
# Detection automatica ogni 5 minuti
|
|
||||||
*/3 * * * * /opt/ids/deployment/cron_detect.sh
|
|
||||||
|
|
||||||
# Verifica processo backend Python ogni 5 minuti (riavvia se non attivo)
|
|
||||||
*/5 * * * * /opt/ids/deployment/check_backend.sh >> /var/log/ids/cron.log 2>&1
|
|
||||||
|
|
||||||
# Verifica processo frontend ogni 5 minuti (riavvia se non attivo)
|
|
||||||
*/5 * * * * /opt/ids/deployment/check_frontend.sh >> /var/log/ids/cron.log 2>&1
|
|
||||||
|
|
||||||
# Pulizia log settimanale (ogni domenica alle 02:00)
|
|
||||||
0 2 * * 0 find /var/log/ids -name "*.log" -size +100M -exec truncate -s 50M {} \; >> /var/log/ids/cron.log 2>&1
|
|
||||||
|
|
||||||
# Restart completo del sistema ogni settimana (domenica alle 03:00)
|
|
||||||
0 3 * * 0 /opt/ids/deployment/restart_all.sh >> /var/log/ids/cron.log 2>&1
|
|
||||||
|
|
||||||
# Backup database giornaliero (alle 04:00)
|
|
||||||
0 4 * * * /opt/ids/deployment/backup_db.sh >> /var/log/ids/cron.log 2>&1
|
|
||||||
0 3 * * * /opt/ids/deployment/cleanup_database.sh >> /var/log/ids/cleanup.log 2>&1
|
|
||||||
Mon 2026-02-16 13:05:00 CET 4min 9s left Mon 2026-02-16 12:05:00 CET 55min ago ids-analytics-aggregator.timer ids-analytics-aggregator.service
|
|
||||||
Mon 2026-02-16 13:14:33 CET 13min left Mon 2026-02-16 12:13:57 CET 46min ago ids-cleanup.timer ids-cleanup.service
|
|
||||||
Mon 2026-02-23 03:00:00 CET 6 days left Mon 2026-02-16 03:00:00 CET 10h ago ids-ml-training.timer ids-ml-training.service
|
|
||||||
- - Mon 2026-02-16 12:48:47 CET 12min ago ids-auto-block.timer ids-auto-block.service
|
|
||||||
- - Mon 2026-02-16 13:00:01 CET 48s ago ids-list-fetcher.timer ids-list-fetcher.service
|
|
||||||
@ -1,158 +0,0 @@
|
|||||||
echo "=== 1. STATO SERVIZI ===" && systemctl status ids-backend ids-ml-backend ids-syslog-parser ids-analytics ids-auto-block.timer ids-auto-block.service --no-pager -l 2>&1 | tail -80 && echo "=== 2. LOG
|
|
||||||
NODE.JS ===" && journalctl -u ids-backend --no-pager -n 50 && echo "=== 3. LOG ML ===" && journalctl -u ids-ml-backend --no-pager -n 50 && echo "=== 4. LOG AUTO-BLOCK ===" && journalctl -u ids-auto-block --no-pager -n 50 && echo "=== 5. LOG SYSLOG ===" && journalctl -u ids-syslog-parser --no-pager -n 30 && echo "=== 6. PORTE ===" && ss -tlnp | grep -E '3001|5001|514' && echo "=== 7. PROCESSI ===" && ps aux | grep -E 'node|python|uvicorn' | grep -v grep && echo "=== 8. DISCO/MEMORIA ===" && df -h / && free -h && echo "=== 9. TEST CONNESSIONE ===" && curl -s -o /dev/null -w "%{http_code} - Node.js backend\n" http://localhost:3001/api/health && curl -s -o /dev/null -w "%{http_code} - ML backend\n" http://localhost:5001/health && echo "=== 10. LOG DB ===" && sudo -u ids psql -d ids_db -c "SELECT COUNT(*) as logs_last_30min FROM network_logs WHERE timestamp > NOW() - INTERVAL '30 minutes';"
|
|
||||||
=== 1. STATO SERVIZI ===
|
|
||||||
Unit ids-backend.service could not be found.
|
|
||||||
Unit ids-analytics.service could not be found.
|
|
||||||
● ids-ml-backend.service - IDS ML Backend (FastAPI)
|
|
||||||
Loaded: loaded (/etc/systemd/system/ids-ml-backend.service; enabled; preset: disabled)
|
|
||||||
Active: active (running) since Mon 2026-02-16 19:29:06 CET; 13h ago
|
|
||||||
Main PID: 17629 (python3)
|
|
||||||
Tasks: 26 (limit: 100409)
|
|
||||||
Memory: 75.8M (max: 2.0G available: 1.9G)
|
|
||||||
CPU: 40.396s
|
|
||||||
CGroup: /system.slice/ids-ml-backend.service
|
|
||||||
└─17629 /opt/ids/python_ml/venv/bin/python3 main.py
|
|
||||||
|
|
||||||
Feb 16 19:29:06 ids.alfacom.it systemd[1]: Started IDS ML Backend (FastAPI).
|
|
||||||
|
|
||||||
● ids-syslog-parser.service - IDS Syslog Parser (Network Logs Processor)
|
|
||||||
Loaded: loaded (/etc/systemd/system/ids-syslog-parser.service; enabled; preset: disabled)
|
|
||||||
Active: active (running) since Mon 2026-02-16 12:18:52 CET; 20h ago
|
|
||||||
Main PID: 1069 (python3)
|
|
||||||
Tasks: 1 (limit: 100409)
|
|
||||||
Memory: 9.7M (max: 1.0G available: 1014.2M)
|
|
||||||
CPU: 1h 59min 34.173s
|
|
||||||
CGroup: /system.slice/ids-syslog-parser.service
|
|
||||||
└─1069 /opt/ids/python_ml/venv/bin/python3 syslog_parser.py
|
|
||||||
|
|
||||||
Feb 16 12:18:52 ids.alfacom.it systemd[1]: Started IDS Syslog Parser (Network Logs Processor).
|
|
||||||
|
|
||||||
● ids-auto-block.timer - IDS Auto-Blocking Timer - Run every 5 minutes
|
|
||||||
Loaded: loaded (/etc/systemd/system/ids-auto-block.timer; enabled; preset: disabled)
|
|
||||||
Active: active (running) since Mon 2026-02-16 19:24:04 CET; 13h ago
|
|
||||||
Until: Mon 2026-02-16 19:24:04 CET; 13h ago
|
|
||||||
Trigger: n/a
|
|
||||||
Triggers: ● ids-auto-block.service
|
|
||||||
Docs: https://github.com/yourusername/ids
|
|
||||||
|
|
||||||
Feb 16 19:24:04 ids.alfacom.it systemd[1]: Started IDS Auto-Blocking Timer - Run every 5 minutes.
|
|
||||||
|
|
||||||
● ids-auto-block.service - IDS Auto-Blocking Service - Detect and Block Malicious IPs
|
|
||||||
Loaded: loaded (/etc/systemd/system/ids-auto-block.service; disabled; preset: disabled)
|
|
||||||
Active: activating (start) since Tue 2026-02-17 08:33:33 CET; 3min 14s ago
|
|
||||||
TriggeredBy: ● ids-auto-block.timer
|
|
||||||
Main PID: 30644 (python3)
|
|
||||||
Tasks: 1 (limit: 100409)
|
|
||||||
Memory: 14.7M
|
|
||||||
CPU: 148ms
|
|
||||||
CGroup: /system.slice/ids-auto-block.service
|
|
||||||
└─30644 /opt/ids/python_ml/venv/bin/python3 /opt/ids/python_ml/auto_block.py
|
|
||||||
|
|
||||||
Feb 17 08:33:33 ids.alfacom.it systemd[1]: Starting IDS Auto-Blocking Service - Detect and Block Malicious IPs...
|
|
||||||
=== 2. LOG NODE.JS ===
|
|
||||||
-- No entries --
|
|
||||||
=== 3. LOG ML ===
|
|
||||||
Feb 16 15:51:21 ids.alfacom.it systemd[1]: ids-ml-backend.service: Killing process 12676 (n/a) with signal SIGKILL.
|
|
||||||
Feb 16 15:51:21 ids.alfacom.it systemd[1]: ids-ml-backend.service: Killing process 12677 (n/a) with signal SIGKILL.
|
|
||||||
Feb 16 15:51:21 ids.alfacom.it systemd[1]: ids-ml-backend.service: Killing process 12681 (n/a) with signal SIGKILL.
|
|
||||||
Feb 16 15:51:21 ids.alfacom.it systemd[1]: ids-ml-backend.service: Killing process 12682 (n/a) with signal SIGKILL.
|
|
||||||
Feb 16 15:51:21 ids.alfacom.it systemd[1]: ids-ml-backend.service: Killing process 12684 (python3) with signal SIGKILL.
|
|
||||||
Feb 16 15:51:21 ids.alfacom.it systemd[1]: ids-ml-backend.service: Main process exited, code=killed, status=9/KILL
|
|
||||||
Feb 16 15:51:21 ids.alfacom.it systemd[1]: ids-ml-backend.service: Failed with result 'timeout'.
|
|
||||||
Feb 16 15:51:21 ids.alfacom.it systemd[1]: Stopped IDS ML Backend (FastAPI).
|
|
||||||
Feb 16 15:51:21 ids.alfacom.it systemd[1]: ids-ml-backend.service: Consumed 9.526s CPU time.
|
|
||||||
Feb 16 15:51:26 ids.alfacom.it systemd[1]: Started IDS ML Backend (FastAPI).
|
|
||||||
Feb 16 16:50:11 ids.alfacom.it systemd[1]: Stopping IDS ML Backend (FastAPI)...
|
|
||||||
Feb 16 16:51:41 ids.alfacom.it systemd[1]: ids-ml-backend.service: State 'stop-sigterm' timed out. Killing.
|
|
||||||
Feb 16 16:51:41 ids.alfacom.it systemd[1]: ids-ml-backend.service: Killing process 13099 (python3) with signal SIGKILL.
|
|
||||||
Feb 16 16:51:41 ids.alfacom.it systemd[1]: ids-ml-backend.service: Killing process 13102 (python3) with signal SIGKILL.
|
|
||||||
Feb 16 16:51:41 ids.alfacom.it systemd[1]: ids-ml-backend.service: Killing process 13103 (n/a) with signal SIGKILL.
|
|
||||||
Feb 16 16:51:41 ids.alfacom.it systemd[1]: ids-ml-backend.service: Killing process 13110 (n/a) with signal SIGKILL.
|
|
||||||
Feb 16 16:51:41 ids.alfacom.it systemd[1]: ids-ml-backend.service: Killing process 13112 (n/a) with signal SIGKILL.
|
|
||||||
Feb 16 16:51:41 ids.alfacom.it systemd[1]: ids-ml-backend.service: Killing process 13116 (n/a) with signal SIGKILL.
|
|
||||||
Feb 16 16:51:41 ids.alfacom.it systemd[1]: ids-ml-backend.service: Killing process 13117 (python3) with signal SIGKILL.
|
|
||||||
Feb 16 16:51:41 ids.alfacom.it systemd[1]: ids-ml-backend.service: Killing process 13122 (python3) with signal SIGKILL.
|
|
||||||
Feb 16 16:51:41 ids.alfacom.it systemd[1]: ids-ml-backend.service: Killing process 13125 (n/a) with signal SIGKILL.
|
|
||||||
Feb 16 16:51:41 ids.alfacom.it systemd[1]: ids-ml-backend.service: Main process exited, code=killed, status=9/KILL
|
|
||||||
Feb 16 16:51:41 ids.alfacom.it systemd[1]: ids-ml-backend.service: Failed with result 'timeout'.
|
|
||||||
Feb 16 16:51:41 ids.alfacom.it systemd[1]: Stopped IDS ML Backend (FastAPI).
|
|
||||||
Feb 16 16:51:41 ids.alfacom.it systemd[1]: ids-ml-backend.service: Consumed 15.919s CPU time.
|
|
||||||
Feb 16 16:51:46 ids.alfacom.it systemd[1]: Started IDS ML Backend (FastAPI).
|
|
||||||
Feb 16 19:27:20 ids.alfacom.it systemd[1]: Stopping IDS ML Backend (FastAPI)...
|
|
||||||
Feb 16 19:28:50 ids.alfacom.it systemd[1]: ids-ml-backend.service: State 'stop-sigterm' timed out. Killing.
|
|
||||||
Feb 16 19:28:50 ids.alfacom.it systemd[1]: ids-ml-backend.service: Killing process 14614 (python3) with signal SIGKILL.
|
|
||||||
Feb 16 19:28:50 ids.alfacom.it systemd[1]: ids-ml-backend.service: Killing process 14619 (python3) with signal SIGKILL.
|
|
||||||
Feb 16 19:28:50 ids.alfacom.it systemd[1]: ids-ml-backend.service: Killing process 14626 (python3) with signal SIGKILL.
|
|
||||||
Feb 16 19:28:50 ids.alfacom.it systemd[1]: ids-ml-backend.service: Killing process 14675 (n/a) with signal SIGKILL.
|
|
||||||
Feb 16 19:28:50 ids.alfacom.it systemd[1]: ids-ml-backend.service: Killing process 14676 (python3) with signal SIGKILL.
|
|
||||||
Feb 16 19:28:50 ids.alfacom.it systemd[1]: ids-ml-backend.service: Killing process 14677 (python3) with signal SIGKILL.
|
|
||||||
Feb 16 19:28:50 ids.alfacom.it systemd[1]: ids-ml-backend.service: Killing process 14678 (python3) with signal SIGKILL.
|
|
||||||
Feb 16 19:28:50 ids.alfacom.it systemd[1]: ids-ml-backend.service: Killing process 14679 (python3) with signal SIGKILL.
|
|
||||||
Feb 16 19:28:50 ids.alfacom.it systemd[1]: ids-ml-backend.service: Killing process 14680 (python3) with signal SIGKILL.
|
|
||||||
Feb 16 19:28:50 ids.alfacom.it systemd[1]: ids-ml-backend.service: Killing process 14681 (python3) with signal SIGKILL.
|
|
||||||
Feb 16 19:28:50 ids.alfacom.it systemd[1]: ids-ml-backend.service: Killing process 14682 (python3) with signal SIGKILL.
|
|
||||||
Feb 16 19:28:50 ids.alfacom.it systemd[1]: ids-ml-backend.service: Killing process 14683 (python3) with signal SIGKILL.
|
|
||||||
Feb 16 19:28:50 ids.alfacom.it systemd[1]: ids-ml-backend.service: Main process exited, code=killed, status=9/KILL
|
|
||||||
Feb 16 19:28:50 ids.alfacom.it systemd[1]: ids-ml-backend.service: Failed with result 'timeout'.
|
|
||||||
Feb 16 19:28:50 ids.alfacom.it systemd[1]: Stopped IDS ML Backend (FastAPI).
|
|
||||||
Feb 16 19:28:50 ids.alfacom.it systemd[1]: ids-ml-backend.service: Consumed 15.247s CPU time.
|
|
||||||
Feb 16 19:28:50 ids.alfacom.it systemd[1]: Started IDS ML Backend (FastAPI).
|
|
||||||
Feb 16 19:29:00 ids.alfacom.it systemd[1]: Stopping IDS ML Backend (FastAPI)...
|
|
||||||
Feb 16 19:29:01 ids.alfacom.it systemd[1]: ids-ml-backend.service: Deactivated successfully.
|
|
||||||
Feb 16 19:29:01 ids.alfacom.it systemd[1]: Stopped IDS ML Backend (FastAPI).
|
|
||||||
Feb 16 19:29:01 ids.alfacom.it systemd[1]: ids-ml-backend.service: Consumed 4.113s CPU time.
|
|
||||||
Feb 16 19:29:06 ids.alfacom.it systemd[1]: Started IDS ML Backend (FastAPI).
|
|
||||||
=== 4. LOG AUTO-BLOCK ===
|
|
||||||
Feb 17 07:45:29 ids.alfacom.it systemd[1]: Failed to start IDS Auto-Blocking Service - Detect and Block Malicious IPs.
|
|
||||||
Feb 17 07:45:29 ids.alfacom.it systemd[1]: Starting IDS Auto-Blocking Service - Detect and Block Malicious IPs...
|
|
||||||
Feb 17 07:49:30 ids.alfacom.it systemd[1]: ids-auto-block.service: Main process exited, code=exited, status=1/FAILURE
|
|
||||||
Feb 17 07:49:30 ids.alfacom.it systemd[1]: ids-auto-block.service: Failed with result 'exit-code'.
|
|
||||||
Feb 17 07:49:30 ids.alfacom.it systemd[1]: Failed to start IDS Auto-Blocking Service - Detect and Block Malicious IPs.
|
|
||||||
Feb 17 07:49:30 ids.alfacom.it systemd[1]: Starting IDS Auto-Blocking Service - Detect and Block Malicious IPs...
|
|
||||||
Feb 17 07:53:30 ids.alfacom.it systemd[1]: ids-auto-block.service: Main process exited, code=exited, status=1/FAILURE
|
|
||||||
Feb 17 07:53:30 ids.alfacom.it systemd[1]: ids-auto-block.service: Failed with result 'exit-code'.
|
|
||||||
Feb 17 07:53:30 ids.alfacom.it systemd[1]: Failed to start IDS Auto-Blocking Service - Detect and Block Malicious IPs.
|
|
||||||
Feb 17 07:53:30 ids.alfacom.it systemd[1]: Starting IDS Auto-Blocking Service - Detect and Block Malicious IPs...
|
|
||||||
Feb 17 07:57:30 ids.alfacom.it systemd[1]: ids-auto-block.service: Main process exited, code=exited, status=1/FAILURE
|
|
||||||
Feb 17 07:57:30 ids.alfacom.it systemd[1]: ids-auto-block.service: Failed with result 'exit-code'.
|
|
||||||
Feb 17 07:57:30 ids.alfacom.it systemd[1]: Failed to start IDS Auto-Blocking Service - Detect and Block Malicious IPs.
|
|
||||||
Feb 17 07:57:30 ids.alfacom.it systemd[1]: Starting IDS Auto-Blocking Service - Detect and Block Malicious IPs...
|
|
||||||
Feb 17 08:01:31 ids.alfacom.it systemd[1]: ids-auto-block.service: Main process exited, code=exited, status=1/FAILURE
|
|
||||||
Feb 17 08:01:31 ids.alfacom.it systemd[1]: ids-auto-block.service: Failed with result 'exit-code'.
|
|
||||||
Feb 17 08:01:31 ids.alfacom.it systemd[1]: Failed to start IDS Auto-Blocking Service - Detect and Block Malicious IPs.
|
|
||||||
Feb 17 08:01:31 ids.alfacom.it systemd[1]: Starting IDS Auto-Blocking Service - Detect and Block Malicious IPs...
|
|
||||||
Feb 17 08:05:31 ids.alfacom.it systemd[1]: ids-auto-block.service: Main process exited, code=exited, status=1/FAILURE
|
|
||||||
Feb 17 08:05:31 ids.alfacom.it systemd[1]: ids-auto-block.service: Failed with result 'exit-code'.
|
|
||||||
Feb 17 08:05:31 ids.alfacom.it systemd[1]: Failed to start IDS Auto-Blocking Service - Detect and Block Malicious IPs.
|
|
||||||
Feb 17 08:05:31 ids.alfacom.it systemd[1]: Starting IDS Auto-Blocking Service - Detect and Block Malicious IPs...
|
|
||||||
Feb 17 08:09:31 ids.alfacom.it systemd[1]: ids-auto-block.service: Main process exited, code=exited, status=1/FAILURE
|
|
||||||
Feb 17 08:09:31 ids.alfacom.it systemd[1]: ids-auto-block.service: Failed with result 'exit-code'.
|
|
||||||
Feb 17 08:09:31 ids.alfacom.it systemd[1]: Failed to start IDS Auto-Blocking Service - Detect and Block Malicious IPs.
|
|
||||||
Feb 17 08:09:31 ids.alfacom.it systemd[1]: Starting IDS Auto-Blocking Service - Detect and Block Malicious IPs...
|
|
||||||
Feb 17 08:13:32 ids.alfacom.it systemd[1]: ids-auto-block.service: Main process exited, code=exited, status=1/FAILURE
|
|
||||||
Feb 17 08:13:32 ids.alfacom.it systemd[1]: ids-auto-block.service: Failed with result 'exit-code'.
|
|
||||||
Feb 17 08:13:32 ids.alfacom.it systemd[1]: Failed to start IDS Auto-Blocking Service - Detect and Block Malicious IPs.
|
|
||||||
Feb 17 08:13:32 ids.alfacom.it systemd[1]: Starting IDS Auto-Blocking Service - Detect and Block Malicious IPs...
|
|
||||||
Feb 17 08:17:32 ids.alfacom.it systemd[1]: ids-auto-block.service: Main process exited, code=exited, status=1/FAILURE
|
|
||||||
Feb 17 08:17:32 ids.alfacom.it systemd[1]: ids-auto-block.service: Failed with result 'exit-code'.
|
|
||||||
Feb 17 08:17:32 ids.alfacom.it systemd[1]: Failed to start IDS Auto-Blocking Service - Detect and Block Malicious IPs.
|
|
||||||
Feb 17 08:17:32 ids.alfacom.it systemd[1]: Starting IDS Auto-Blocking Service - Detect and Block Malicious IPs...
|
|
||||||
Feb 17 08:21:32 ids.alfacom.it systemd[1]: ids-auto-block.service: Main process exited, code=exited, status=1/FAILURE
|
|
||||||
Feb 17 08:21:32 ids.alfacom.it systemd[1]: ids-auto-block.service: Failed with result 'exit-code'.
|
|
||||||
Feb 17 08:21:32 ids.alfacom.it systemd[1]: Failed to start IDS Auto-Blocking Service - Detect and Block Malicious IPs.
|
|
||||||
Feb 17 08:21:32 ids.alfacom.it systemd[1]: Starting IDS Auto-Blocking Service - Detect and Block Malicious IPs...
|
|
||||||
Feb 17 08:25:33 ids.alfacom.it systemd[1]: ids-auto-block.service: Main process exited, code=exited, status=1/FAILURE
|
|
||||||
Feb 17 08:25:33 ids.alfacom.it systemd[1]: ids-auto-block.service: Failed with result 'exit-code'.
|
|
||||||
Feb 17 08:25:33 ids.alfacom.it systemd[1]: Failed to start IDS Auto-Blocking Service - Detect and Block Malicious IPs.
|
|
||||||
Feb 17 08:25:33 ids.alfacom.it systemd[1]: Starting IDS Auto-Blocking Service - Detect and Block Malicious IPs...
|
|
||||||
Feb 17 08:29:33 ids.alfacom.it systemd[1]: ids-auto-block.service: Main process exited, code=exited, status=1/FAILURE
|
|
||||||
Feb 17 08:29:33 ids.alfacom.it systemd[1]: ids-auto-block.service: Failed with result 'exit-code'.
|
|
||||||
Feb 17 08:29:33 ids.alfacom.it systemd[1]: Failed to start IDS Auto-Blocking Service - Detect and Block Malicious IPs.
|
|
||||||
Feb 17 08:29:33 ids.alfacom.it systemd[1]: Starting IDS Auto-Blocking Service - Detect and Block Malicious IPs...
|
|
||||||
Feb 17 08:33:33 ids.alfacom.it systemd[1]: ids-auto-block.service: Main process exited, code=exited, status=1/FAILURE
|
|
||||||
Feb 17 08:33:33 ids.alfacom.it systemd[1]: ids-auto-block.service: Failed with result 'exit-code'.
|
|
||||||
Feb 17 08:33:33 ids.alfacom.it systemd[1]: Failed to start IDS Auto-Blocking Service - Detect and Block Malicious IPs.
|
|
||||||
Feb 17 08:33:33 ids.alfacom.it systemd[1]: Starting IDS Auto-Blocking Service - Detect and Block Malicious IPs...
|
|
||||||
=== 5. LOG SYSLOG ===
|
|
||||||
Feb 16 12:18:52 ids.alfacom.it systemd[1]: Started IDS Syslog Parser (Network Logs Processor).
|
|
||||||
=== 6. PORTE ===
|
|
||||||
@ -1,110 +0,0 @@
|
|||||||
echo "=== VERIFICA BACKEND NODE.JS ===" && ls -la /etc/systemd/system/ids-*.service /etc/systemd/system/ids-*.timer && echo "=== FILE SERVICE DISPONIBILI ===" && cat /etc/systemd/system/ids-backend.service 2>&1 || echo "FILE NON TROVATO" && echo "=== NGINX/REVERSE PROXY ===" && ss -tlnp | grep -E '80|443|3001|5001' && echo "=== TEST PORTA 3001 ===" && curl -v --connect-timeout 5 http://localhost:3001/api/health 2>&1 && echo "=== COME VIENE AVVIATO NODE.JS ===" && ps aux | grep -i node | grep -v grep && echo "=== PM2 STATUS ===" && pm2 list 2>&1 || echo "PM2 non installato" && echo "=== CONTENUTO /opt/ids/ ===" && ls -la /opt/ids/ && echo "=== PACKAGE.JSON ===" && cat /opt/ids/package.json 2>&1 | head -30 && echo "=== AUTO_BLOCK OUTPUT DETTAGLIATO ===" && sudo -u ids /opt/ids/python_ml/venv/bin/python3 /opt/ids/python_ml/auto_block.py 2>&1
|
|
||||||
=== VERIFICA BACKEND NODE.JS ===
|
|
||||||
-rw-r--r--. 1 root root 473 Feb 16 15:52 /etc/systemd/system/ids-analytics-aggregator.service
|
|
||||||
-rw-r--r--. 1 root root 339 Feb 16 15:52 /etc/systemd/system/ids-analytics-aggregator.timer
|
|
||||||
-rw-r--r--. 1 root root 674 Feb 16 19:23 /etc/systemd/system/ids-auto-block.service
|
|
||||||
-rw-r--r--. 1 root root 457 Feb 14 11:42 /etc/systemd/system/ids-auto-block.timer
|
|
||||||
-rw-r--r--. 1 root root 550 Nov 25 11:47 /etc/systemd/system/ids-cleanup.service
|
|
||||||
-rw-r--r--. 1 root root 440 Nov 25 11:47 /etc/systemd/system/ids-cleanup.timer
|
|
||||||
-rw-r--r--. 1 root root 623 Nov 27 19:29 /etc/systemd/system/ids-list-fetcher.service
|
|
||||||
-rw-r--r--. 1 root root 246 Nov 27 19:29 /etc/systemd/system/ids-list-fetcher.timer
|
|
||||||
-rw-r--r--. 1 root root 675 Nov 24 12:12 /etc/systemd/system/ids-ml-backend.service
|
|
||||||
-rw-r--r--. 1 root root 620 Nov 24 19:19 /etc/systemd/system/ids-ml-training.service
|
|
||||||
-rw-r--r--. 1 root root 398 Nov 24 19:19 /etc/systemd/system/ids-ml-training.timer
|
|
||||||
-rw-r--r--. 1 root root 727 Nov 24 12:12 /etc/systemd/system/ids-syslog-parser.service
|
|
||||||
=== FILE SERVICE DISPONIBILI ===
|
|
||||||
cat: /etc/systemd/system/ids-backend.service: No such file or directory
|
|
||||||
FILE NON TROVATO
|
|
||||||
=== NGINX/REVERSE PROXY ===
|
|
||||||
LISTEN 1107 2048 0.0.0.0:8000 0.0.0.0:* users:(("python3",pid=17629,fd=12))
|
|
||||||
=== TEST PORTA 3001 ===
|
|
||||||
* Trying ::1:3001...
|
|
||||||
* connect to ::1 port 3001 failed: Connection refused
|
|
||||||
* Trying 127.0.0.1:3001...
|
|
||||||
* connect to 127.0.0.1 port 3001 failed: Connection refused
|
|
||||||
* Failed to connect to localhost port 3001: Connection refused
|
|
||||||
* Closing connection 0
|
|
||||||
curl: (7) Failed to connect to localhost port 3001: Connection refused
|
|
||||||
PM2 non installato
|
|
||||||
=== CONTENUTO /opt/ids/ ===
|
|
||||||
total 608
|
|
||||||
drwxr-xr-x. 14 ids ids 4096 Feb 16 19:28 .
|
|
||||||
drwxr-xr-x. 3 root root 43 Nov 17 18:20 ..
|
|
||||||
-rw-------. 1 ids ids 508 Feb 16 19:28 .env
|
|
||||||
-rw-r-----. 1 root root 508 Feb 16 19:28 .env.backup
|
|
||||||
-rw-r--r--. 1 ids ids 446 Nov 17 18:23 .env.example
|
|
||||||
drwxr-xr-x. 8 ids ids 4096 Feb 16 19:28 .git
|
|
||||||
-rw-r--r--. 1 ids ids 686 Nov 17 18:23 .gitignore
|
|
||||||
-rw-r--r--. 1 ids ids 801 Jan 2 12:50 .replit
|
|
||||||
-rw-r--r--. 1 ids ids 6264 Nov 17 17:08 GUIDA_INSTALLAZIONE.md
|
|
||||||
-rw-r--r--. 1 ids ids 44765 Feb 16 08:50 IDS_Conformita_ISO27001.docx
|
|
||||||
-rw-r--r--. 1 ids ids 7595 Nov 25 19:14 MIKROTIK_API_FIX.md
|
|
||||||
-rw-r--r--. 1 ids ids 8452 Nov 17 16:40 README.md
|
|
||||||
-rw-r--r--. 1 ids ids 9092 Nov 17 16:40 RISPOSTA_DEPLOYMENT.md
|
|
||||||
drwxr-xr-x. 2 ids ids 12288 Feb 16 16:49 attached_assets
|
|
||||||
drwxr-xr-x. 2 ids ids 4096 Feb 17 04:00 backups
|
|
||||||
drwxr-xr-x. 4 ids ids 49 Nov 17 16:40 client
|
|
||||||
-rw-r--r--. 1 ids ids 459 Nov 17 16:40 components.json
|
|
||||||
drwxr-xr-x. 3 ids ids 4096 Feb 16 19:28 database-schema
|
|
||||||
-rwxr-xr-x. 1 ids ids 10264 Nov 17 18:23 deploy-to-gitlab.sh
|
|
||||||
drwxr-xr-x. 7 ids ids 4096 Feb 16 19:28 deployment
|
|
||||||
-rw-r--r--. 1 ids ids 3165 Nov 17 16:40 design_guidelines.md
|
|
||||||
drwxr-xr-x. 3 root root 36 Nov 24 11:05 dist
|
|
||||||
-rw-r--r--. 1 ids ids 325 Nov 17 16:40 drizzle.config.ts
|
|
||||||
drwxr-xr-x. 4 ids ids 4096 Nov 17 16:40 extracted_idf
|
|
||||||
-rw-r--r--. 1 ids ids 28609 Feb 16 08:50 generate_iso27001_doc.py
|
|
||||||
-rw-r--r--. 1 ids ids 1033 Nov 17 17:08 git.env.example
|
|
||||||
-rw-r--r--. 1 ids ids 96 Nov 26 11:14 main.py
|
|
||||||
drwxr-xr-x. 328 ids ids 12288 Feb 16 19:28 node_modules
|
|
||||||
-rw-r--r--. 1 ids ids 299523 Feb 16 19:28 package-lock.json
|
|
||||||
-rw-r--r--. 1 ids ids 3696 Nov 17 16:40 package.json
|
|
||||||
-rw-r--r--. 1 ids ids 80 Nov 17 16:40 postcss.config.js
|
|
||||||
-rwxr-xr-x. 1 ids ids 2496 Nov 17 16:40 push-gitlab.sh
|
|
||||||
-rw-r--r--. 1 ids ids 191 Feb 16 08:50 pyproject.toml
|
|
||||||
drwxr-xr-x. 7 ids ids 4096 Feb 16 16:49 python_ml
|
|
||||||
-rw-r--r--. 1 ids ids 5796 Feb 16 12:33 replit.md
|
|
||||||
drwxr-xr-x. 2 ids ids 104 Feb 16 12:55 server
|
|
||||||
drwxr-xr-x. 2 ids ids 23 Jan 2 15:50 shared
|
|
||||||
-rw-r--r--. 1 ids ids 4050 Nov 17 16:40 tailwind.config.ts
|
|
||||||
-rw-r--r--. 1 ids ids 657 Nov 17 16:40 tsconfig.json
|
|
||||||
-rw-r--r--. 1 ids ids 37505 Feb 16 08:50 uv.lock
|
|
||||||
-rw-r--r--. 1 ids ids 7329 Feb 16 19:28 version.json
|
|
||||||
-rw-r--r--. 1 ids ids 1080 Nov 17 16:40 vite.config.ts
|
|
||||||
=== PACKAGE.JSON ===
|
|
||||||
{
|
|
||||||
"name": "rest-express",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"type": "module",
|
|
||||||
"license": "MIT",
|
|
||||||
"scripts": {
|
|
||||||
"dev": "NODE_ENV=development tsx server/index.ts",
|
|
||||||
"build": "vite build && esbuild server/index.ts --platform=node --packages=external --bundle --format=esm --outdir=dist",
|
|
||||||
"start": "NODE_ENV=production node dist/index.js",
|
|
||||||
"check": "tsc",
|
|
||||||
"db:push": "drizzle-kit push"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@hookform/resolvers": "^3.10.0",
|
|
||||||
"@jridgewell/trace-mapping": "^0.3.25",
|
|
||||||
"@neondatabase/serverless": "^0.10.4",
|
|
||||||
"@radix-ui/react-accordion": "^1.2.4",
|
|
||||||
"@radix-ui/react-alert-dialog": "^1.1.7",
|
|
||||||
"@radix-ui/react-aspect-ratio": "^1.1.3",
|
|
||||||
"@radix-ui/react-avatar": "^1.1.4",
|
|
||||||
"@radix-ui/react-checkbox": "^1.1.5",
|
|
||||||
"@radix-ui/react-collapsible": "^1.1.4",
|
|
||||||
"@radix-ui/react-context-menu": "^2.2.7",
|
|
||||||
"@radix-ui/react-dialog": "^1.1.7",
|
|
||||||
"@radix-ui/react-dropdown-menu": "^2.1.7",
|
|
||||||
"@radix-ui/react-hover-card": "^1.1.7",
|
|
||||||
"@radix-ui/react-label": "^2.1.3",
|
|
||||||
"@radix-ui/react-menubar": "^1.1.7",
|
|
||||||
"@radix-ui/react-navigation-menu": "^1.2.6",
|
|
||||||
"@radix-ui/react-popover": "^1.1.7",
|
|
||||||
=== AUTO_BLOCK OUTPUT DETTAGLIATO ===
|
|
||||||
[2026-02-17 08:38:05] Starting auto-block cycle...
|
|
||||||
[2026-02-17 08:38:05] Step 1: Detection ML...
|
|
||||||
[2026-02-17 08:38:05] ML Detection timeout, skip (blocco IP esistenti continua)
|
|
||||||
[2026-02-17 08:38:05] Step 2: Blocco IP critici sui router...
|
|
||||||
[2026-02-17 08:38:05] ERRORE: Timeout blocco IP (120s)
|
|
||||||
[root@ids ~]#
|
|
||||||
@ -1,77 +0,0 @@
|
|||||||
journalctl -u ids-analytics-aggregator.timer -f
|
|
||||||
Feb 16 12:18:50 ids.alfacom.it systemd[1]: Started IDS Analytics Aggregation Timer - Runs every hour.
|
|
||||||
Feb 16 12:40:08 ids.alfacom.it systemd[1]: ids-analytics-aggregator.timer: Deactivated successfully.
|
|
||||||
Feb 16 12:40:08 ids.alfacom.it systemd[1]: Stopped IDS Analytics Aggregation Timer - Runs every hour.
|
|
||||||
Feb 16 12:40:08 ids.alfacom.it systemd[1]: Stopping IDS Analytics Aggregation Timer - Runs every hour...
|
|
||||||
Feb 16 12:40:08 ids.alfacom.it systemd[1]: Started IDS Analytics Aggregation Timer - Runs every hour.
|
|
||||||
^C
|
|
||||||
[root@ids ids]# systemctl status ids-ml-backend
|
|
||||||
● ids-ml-backend.service - IDS ML Backend (FastAPI)
|
|
||||||
Loaded: loaded (/etc/systemd/system/ids-ml-backend.service; enabled; preset: disabled)
|
|
||||||
Active: active (running) since Mon 2026-02-16 15:51:26 CET; 9min ago
|
|
||||||
Main PID: 13099 (python3)
|
|
||||||
Tasks: 26 (limit: 100409)
|
|
||||||
Memory: 402.9M (max: 2.0G available: 1.6G)
|
|
||||||
CPU: 15.905s
|
|
||||||
CGroup: /system.slice/ids-ml-backend.service
|
|
||||||
└─13099 /opt/ids/python_ml/venv/bin/python3 main.py
|
|
||||||
|
|
||||||
Feb 16 15:51:26 ids.alfacom.it systemd[1]: Started IDS ML Backend (FastAPI).
|
|
||||||
[root@ids ids]# cat /var/log/ids/backend.log | tail -20
|
|
||||||
[Mon Feb 16 15:40:04 CET 2026] Backend riavviato con PID: 12165
|
|
||||||
INFO: Started server process [12165]
|
|
||||||
INFO: Waiting for application startup.
|
|
||||||
INFO: Application startup complete.
|
|
||||||
ERROR: [Errno 98] error while attempting to bind on address ('0.0.0.0', 8000): address already in use
|
|
||||||
INFO: Waiting for application shutdown.
|
|
||||||
INFO: Application shutdown complete.
|
|
||||||
[WARNING] Extended Isolation Forest not available, using standard IF
|
|
||||||
[ML] Using Hybrid ML Detector (Extended Isolation Forest + Feature Selection)
|
|
||||||
[HYBRID] Ensemble classifier loaded
|
|
||||||
[HYBRID] Models loaded (version: latest)
|
|
||||||
[HYBRID] Selected features: 18/25
|
|
||||||
[HYBRID] Mode: Hybrid (IF + Ensemble)
|
|
||||||
[ML] ✓ Hybrid detector models loaded and ready
|
|
||||||
Starting IDS API on http://0.0.0.0:8000
|
|
||||||
Docs available at http://0.0.0.0:8000/docs
|
|
||||||
[Mon Feb 16 15:45:01 CET 2026] Backend Python NON attivo, riavvio via systemctl...
|
|
||||||
[Mon Feb 16 15:45:04 CET 2026] ERRORE: Backend non si è avviato. Controlla: journalctl -u ids-ml-backend
|
|
||||||
[Mon Feb 16 15:50:01 CET 2026] Backend Python NON attivo, riavvio via systemctl...
|
|
||||||
[Mon Feb 16 15:50:04 CET 2026] ERRORE: Backend non si è avviato. Controlla: journalctl -u ids-ml-backend
|
|
||||||
[root@ids ids]# systemctl status ids-auto-block
|
|
||||||
journalctl -u ids-auto-block --no-pager | tail -20
|
|
||||||
× ids-auto-block.service - IDS Auto-Blocking Service - Detect and Block Malicious IPs
|
|
||||||
Loaded: loaded (/etc/systemd/system/ids-auto-block.service; disabled; preset: disabled)
|
|
||||||
Active: failed (Result: signal) since Mon 2026-02-16 12:47:58 CET; 3h 13min ago
|
|
||||||
TriggeredBy: ○ ids-auto-block.timer
|
|
||||||
Docs: https://github.com/yourusername/ids
|
|
||||||
Main PID: 2896 (code=killed, signal=TERM)
|
|
||||||
CPU: 155ms
|
|
||||||
|
|
||||||
Feb 16 12:46:47 ids.alfacom.it systemd[1]: Starting IDS Auto-Blocking Service - Detect and Block Malicious IPs...
|
|
||||||
Feb 16 12:47:58 ids.alfacom.it systemd[1]: ids-auto-block.service: Main process exited, code=killed, status=15/TERM
|
|
||||||
Feb 16 12:47:58 ids.alfacom.it systemd[1]: ids-auto-block.service: Failed with result 'signal'.
|
|
||||||
Feb 16 12:47:58 ids.alfacom.it systemd[1]: Stopped IDS Auto-Blocking Service - Detect and Block Malicious IPs.
|
|
||||||
Feb 16 12:38:46 ids.alfacom.it systemd[1]: Starting IDS Auto-Blocking Service - Detect and Block Malicious IPs...
|
|
||||||
Feb 16 12:40:46 ids.alfacom.it systemd[1]: ids-auto-block.service: Main process exited, code=exited, status=1/FAILURE
|
|
||||||
Feb 16 12:40:46 ids.alfacom.it systemd[1]: ids-auto-block.service: Failed with result 'exit-code'.
|
|
||||||
Feb 16 12:40:46 ids.alfacom.it systemd[1]: Failed to start IDS Auto-Blocking Service - Detect and Block Malicious IPs.
|
|
||||||
Feb 16 12:40:46 ids.alfacom.it systemd[1]: Starting IDS Auto-Blocking Service - Detect and Block Malicious IPs...
|
|
||||||
Feb 16 12:42:46 ids.alfacom.it systemd[1]: ids-auto-block.service: Main process exited, code=exited, status=1/FAILURE
|
|
||||||
Feb 16 12:42:46 ids.alfacom.it systemd[1]: ids-auto-block.service: Failed with result 'exit-code'.
|
|
||||||
Feb 16 12:42:46 ids.alfacom.it systemd[1]: Failed to start IDS Auto-Blocking Service - Detect and Block Malicious IPs.
|
|
||||||
Feb 16 12:42:46 ids.alfacom.it systemd[1]: Starting IDS Auto-Blocking Service - Detect and Block Malicious IPs...
|
|
||||||
Feb 16 12:44:47 ids.alfacom.it systemd[1]: ids-auto-block.service: Main process exited, code=exited, status=1/FAILURE
|
|
||||||
Feb 16 12:44:47 ids.alfacom.it systemd[1]: ids-auto-block.service: Failed with result 'exit-code'.
|
|
||||||
Feb 16 12:44:47 ids.alfacom.it systemd[1]: Failed to start IDS Auto-Blocking Service - Detect and Block Malicious IPs.
|
|
||||||
Feb 16 12:44:47 ids.alfacom.it systemd[1]: Starting IDS Auto-Blocking Service - Detect and Block Malicious IPs...
|
|
||||||
Feb 16 12:46:47 ids.alfacom.it systemd[1]: ids-auto-block.service: Main process exited, code=exited, status=1/FAILURE
|
|
||||||
Feb 16 12:46:47 ids.alfacom.it systemd[1]: ids-auto-block.service: Failed with result 'exit-code'.
|
|
||||||
Feb 16 12:46:47 ids.alfacom.it systemd[1]: Failed to start IDS Auto-Blocking Service - Detect and Block Malicious IPs.
|
|
||||||
Feb 16 12:46:47 ids.alfacom.it systemd[1]: Starting IDS Auto-Blocking Service - Detect and Block Malicious IPs...
|
|
||||||
Feb 16 12:47:58 ids.alfacom.it systemd[1]: ids-auto-block.service: Main process exited, code=killed, status=15/TERM
|
|
||||||
Feb 16 12:47:58 ids.alfacom.it systemd[1]: ids-auto-block.service: Failed with result 'signal'.
|
|
||||||
Feb 16 12:47:58 ids.alfacom.it systemd[1]: Stopped IDS Auto-Blocking Service - Detect and Block Malicious IPs.
|
|
||||||
[root@ids ids]# curl -X POST http://localhost:5000/api/ml/block-all-critical \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d '{"min_score": 80, "limit": 200}'
|
|
||||||
@ -1,57 +0,0 @@
|
|||||||
sudo /opt/ids/deployment/setup_analytics_timer.sh
|
|
||||||
╔═══════════════════════════════════════════════╗
|
|
||||||
║ IDS Analytics Timer Setup ║
|
|
||||||
╚═══════════════════════════════════════════════╝
|
|
||||||
|
|
||||||
Copia file systemd...
|
|
||||||
Reload systemd daemon...
|
|
||||||
⚙ Enable e start timer...
|
|
||||||
|
|
||||||
Stato timer:
|
|
||||||
● ids-analytics-aggregator.timer - IDS Analytics Aggregation Timer - Runs every hour
|
|
||||||
Loaded: loaded (/etc/systemd/system/ids-analytics-aggregator.timer; enabled; preset: disabled)
|
|
||||||
Active: active (waiting) since Mon 2026-02-16 12:40:08 CET; 3h 12min ago
|
|
||||||
Until: Mon 2026-02-16 12:40:08 CET; 3h 12min ago
|
|
||||||
Trigger: Mon 2026-02-16 16:05:00 CET; 12min left
|
|
||||||
Triggers: ● ids-analytics-aggregator.service
|
|
||||||
|
|
||||||
Feb 16 12:40:08 ids.alfacom.it systemd[1]: Stopped IDS Analytics Aggregation Timer - Runs every hour.
|
|
||||||
Feb 16 12:40:08 ids.alfacom.it systemd[1]: Stopping IDS Analytics Aggregation Timer - Runs every hour...
|
|
||||||
Feb 16 12:40:08 ids.alfacom.it systemd[1]: Started IDS Analytics Aggregation Timer - Runs every hour.
|
|
||||||
|
|
||||||
Prossime esecuzioni:
|
|
||||||
NEXT LEFT LAST PASSED UNIT ACTIVATES
|
|
||||||
Mon 2026-02-16 16:05:00 CET 12min left Mon 2026-02-16 15:05:00 CET 47min ago ids-analytics-aggregator.timer ids-analytics-aggregator.service
|
|
||||||
|
|
||||||
1 timers listed.
|
|
||||||
Pass --all to see loaded but inactive timers, too.
|
|
||||||
|
|
||||||
╔═══════════════════════════════════════════════╗
|
|
||||||
║ ✅ ANALYTICS TIMER CONFIGURATO ║
|
|
||||||
╚═══════════════════════════════════════════════╝
|
|
||||||
|
|
||||||
📝 Comandi utili:
|
|
||||||
Stato timer: sudo systemctl status ids-analytics-aggregator.timer
|
|
||||||
Prossime run: sudo systemctl list-timers
|
|
||||||
Log aggregazione: sudo journalctl -u ids-analytics-aggregator -f
|
|
||||||
Test manuale: sudo systemctl start ids-analytics-aggregator
|
|
||||||
|
|
||||||
[root@ids ids]# systemctl status ids-analytics-aggregator.timer
|
|
||||||
● ids-analytics-aggregator.timer - IDS Analytics Aggregation Timer - Runs every hour
|
|
||||||
Loaded: loaded (/etc/systemd/system/ids-analytics-aggregator.timer; enabled; preset: disabled)
|
|
||||||
Active: active (waiting) since Mon 2026-02-16 12:40:08 CET; 3h 12min ago
|
|
||||||
Until: Mon 2026-02-16 12:40:08 CET; 3h 12min ago
|
|
||||||
Trigger: Mon 2026-02-16 16:05:00 CET; 11min left
|
|
||||||
Triggers: ● ids-analytics-aggregator.service
|
|
||||||
|
|
||||||
Feb 16 12:40:08 ids.alfacom.it systemd[1]: Stopped IDS Analytics Aggregation Timer - Runs every hour.
|
|
||||||
Feb 16 12:40:08 ids.alfacom.it systemd[1]: Stopping IDS Analytics Aggregation Timer - Runs every hour...
|
|
||||||
Feb 16 12:40:08 ids.alfacom.it systemd[1]: Started IDS Analytics Aggregation Timer - Runs every hour.
|
|
||||||
[root@ids ids]# cd /opt/ids && ./deployment/run_analytics.sh
|
|
||||||
Usage: ./deployment/run_analytics.sh {hourly|daily}
|
|
||||||
[root@ids ids]# cd /opt/ids && ./deployment/run_analytics.sh {1}
|
|
||||||
Errore: modo deve essere 'hourly' o 'daily'
|
|
||||||
[root@ids ids]# cd /opt/ids && ./deployment/run_analytics.sh {hourly}
|
|
||||||
Errore: modo deve essere 'hourly' o 'daily'
|
|
||||||
[root@ids ids]# cd /opt/ids && ./deployment/run_analytics.sh {hourly=1}
|
|
||||||
Errore: modo deve essere 'hourly' o 'daily'
|
|
||||||
@ -1,59 +0,0 @@
|
|||||||
systemctl stop ids-ml-backend
|
|
||||||
[root@ids ~]# systemctl start ids-ml-backend
|
|
||||||
[root@ids ~]# systemctl status ids-ml-backend
|
|
||||||
● ids-ml-backend.service - IDS ML Backend (FastAPI)
|
|
||||||
Loaded: loaded (/etc/systemd/system/ids-ml-backend.service; enabled; preset: disabled)
|
|
||||||
Active: active (running) since Mon 2026-02-16 12:59:19 CET; 4s ago
|
|
||||||
Main PID: 3600 (python3)
|
|
||||||
Tasks: 26 (limit: 100409)
|
|
||||||
Memory: 157.6M (max: 2.0G available: 1.8G)
|
|
||||||
CPU: 3.936s
|
|
||||||
CGroup: /system.slice/ids-ml-backend.service
|
|
||||||
└─3600 /opt/ids/python_ml/venv/bin/python3 main.py
|
|
||||||
|
|
||||||
Feb 16 12:59:19 ids.alfacom.it systemd[1]: Started IDS ML Backend (FastAPI).
|
|
||||||
[root@ids ~]# cat /etc/systemd/system/ids-ml-backend.service
|
|
||||||
[Unit]
|
|
||||||
Description=IDS ML Backend (FastAPI)
|
|
||||||
After=network.target postgresql-16.service
|
|
||||||
Wants=postgresql-16.service
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=simple
|
|
||||||
User=ids
|
|
||||||
Group=ids
|
|
||||||
WorkingDirectory=/opt/ids/python_ml
|
|
||||||
EnvironmentFile=/opt/ids/.env
|
|
||||||
|
|
||||||
# Comando esecuzione (usa virtual environment)
|
|
||||||
ExecStart=/opt/ids/python_ml/venv/bin/python3 main.py
|
|
||||||
|
|
||||||
# Restart automatico sempre (non solo on-failure)
|
|
||||||
Restart=always
|
|
||||||
RestartSec=10
|
|
||||||
StartLimitInterval=300
|
|
||||||
StartLimitBurst=5
|
|
||||||
|
|
||||||
# Limiti risorse
|
|
||||||
LimitNOFILE=65536
|
|
||||||
MemoryMax=2G
|
|
||||||
|
|
||||||
# Logging
|
|
||||||
StandardOutput=append:/var/log/ids/ml_backend.log
|
|
||||||
StandardError=append:/var/log/ids/ml_backend.log
|
|
||||||
SyslogIdentifier=ids-ml-backend
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
[root@ids ~]# tail -f /var/log/ids/backend.log
|
|
||||||
🚀 Starting IDS API on http://0.0.0.0:8000
|
|
||||||
📚 Docs available at http://0.0.0.0:8000/docs
|
|
||||||
[Mon Feb 16 12:56:12 CET 2026] Backend Python NON attivo, riavvio...
|
|
||||||
[Mon Feb 16 12:56:14 CET 2026] Backend riavviato con PID: 3453
|
|
||||||
Traceback (most recent call last):
|
|
||||||
File "/opt/ids/python_ml/main.py", line 21, in <module>
|
|
||||||
from ml_hybrid_detector import MLHybridDetector
|
|
||||||
File "/opt/ids/python_ml/ml_hybrid_detector.py", line 13, in <module>
|
|
||||||
from xgboost import XGBClassifier
|
|
||||||
ModuleNotFoundError: No module named 'xgboost'
|
|
||||||
|
|
||||||
@ -2,21 +2,25 @@ import { useQuery, useMutation } from "@tanstack/react-query";
|
|||||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Activity, Brain, Database, FileText, Terminal, RefreshCw, Play, Square, RotateCw, Shield, Trash2, ListChecks, GraduationCap, Server, Clock, Timer } from "lucide-react";
|
import { Activity, Brain, Database, FileText, Terminal, RefreshCw, AlertCircle, Play, Square, RotateCw } from "lucide-react";
|
||||||
|
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
||||||
import { useToast } from "@/hooks/use-toast";
|
import { useToast } from "@/hooks/use-toast";
|
||||||
import { queryClient, apiRequest } from "@/lib/queryClient";
|
import { queryClient, apiRequest } from "@/lib/queryClient";
|
||||||
|
|
||||||
interface ServiceStatus {
|
interface ServiceStatus {
|
||||||
name: string;
|
name: string;
|
||||||
status: string;
|
status: "running" | "idle" | "offline" | "error" | "unknown";
|
||||||
healthy: boolean;
|
healthy: boolean;
|
||||||
details: any;
|
details: any;
|
||||||
systemdUnit: string;
|
|
||||||
type: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ServicesStatusResponse {
|
interface ServicesStatusResponse {
|
||||||
services: Record<string, ServiceStatus>;
|
services: {
|
||||||
|
mlBackend: ServiceStatus;
|
||||||
|
database: ServiceStatus;
|
||||||
|
syslogParser: ServiceStatus;
|
||||||
|
analyticsAggregator: ServiceStatus;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function ServicesPage() {
|
export default function ServicesPage() {
|
||||||
@ -24,9 +28,10 @@ export default function ServicesPage() {
|
|||||||
|
|
||||||
const { data: servicesStatus, isLoading, refetch } = useQuery<ServicesStatusResponse>({
|
const { data: servicesStatus, isLoading, refetch } = useQuery<ServicesStatusResponse>({
|
||||||
queryKey: ["/api/services/status"],
|
queryKey: ["/api/services/status"],
|
||||||
refetchInterval: 5000,
|
refetchInterval: 5000, // Refresh every 5s
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Mutation for service control
|
||||||
const serviceControlMutation = useMutation({
|
const serviceControlMutation = useMutation({
|
||||||
mutationFn: async ({ service, action }: { service: string; action: string }) => {
|
mutationFn: async ({ service, action }: { service: string; action: string }) => {
|
||||||
return apiRequest("POST", `/api/services/${service}/${action}`);
|
return apiRequest("POST", `/api/services/${service}/${action}`);
|
||||||
@ -34,8 +39,9 @@ export default function ServicesPage() {
|
|||||||
onSuccess: (data, variables) => {
|
onSuccess: (data, variables) => {
|
||||||
toast({
|
toast({
|
||||||
title: "Operazione completata",
|
title: "Operazione completata",
|
||||||
description: `Servizio ${variables.service}: ${variables.action} eseguito`,
|
description: `Servizio ${variables.service}: ${variables.action} eseguito con successo`,
|
||||||
});
|
});
|
||||||
|
// Refresh status after 2 seconds
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
queryClient.invalidateQueries({ queryKey: ["/api/services/status"] });
|
queryClient.invalidateQueries({ queryKey: ["/api/services/status"] });
|
||||||
}, 2000);
|
}, 2000);
|
||||||
@ -53,260 +59,39 @@ export default function ServicesPage() {
|
|||||||
serviceControlMutation.mutate({ service, action });
|
serviceControlMutation.mutate({ service, action });
|
||||||
};
|
};
|
||||||
|
|
||||||
const getStatusBadge = (service: ServiceStatus, key: string) => {
|
const getStatusBadge = (service: ServiceStatus) => {
|
||||||
if (service.healthy) {
|
if (service.healthy) {
|
||||||
return <Badge variant="default" className="bg-green-600" data-testid={`badge-status-${key}-healthy`}>Online</Badge>;
|
return <Badge variant="default" className="bg-green-600" data-testid={`badge-status-healthy`}>Online</Badge>;
|
||||||
}
|
}
|
||||||
if (service.status === 'idle') {
|
if (service.status === 'idle') {
|
||||||
return <Badge variant="secondary" data-testid={`badge-status-${key}-idle`}>In Attesa</Badge>;
|
return <Badge variant="secondary" data-testid={`badge-status-idle`}>In Attesa</Badge>;
|
||||||
}
|
}
|
||||||
if (service.status === 'offline') {
|
if (service.status === 'offline') {
|
||||||
return <Badge variant="destructive" data-testid={`badge-status-${key}-offline`}>Offline</Badge>;
|
return <Badge variant="destructive" data-testid={`badge-status-offline`}>Offline</Badge>;
|
||||||
}
|
}
|
||||||
if (service.status === 'error') {
|
if (service.status === 'error') {
|
||||||
return <Badge variant="destructive" data-testid={`badge-status-${key}-error`}>Errore</Badge>;
|
return <Badge variant="destructive" data-testid={`badge-status-error`}>Errore</Badge>;
|
||||||
}
|
}
|
||||||
return <Badge variant="outline" data-testid={`badge-status-${key}-unknown`}>Sconosciuto</Badge>;
|
return <Badge variant="outline" data-testid={`badge-status-unknown`}>Sconosciuto</Badge>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getStatusIndicator = (service: ServiceStatus) => {
|
const getStatusIndicator = (service: ServiceStatus) => {
|
||||||
if (service.healthy) {
|
if (service.healthy) {
|
||||||
return <div className="h-3 w-3 rounded-full bg-green-500 shrink-0" />;
|
return <div className="h-3 w-3 rounded-full bg-green-500" />;
|
||||||
}
|
}
|
||||||
if (service.status === 'idle') {
|
if (service.status === 'idle') {
|
||||||
return <div className="h-3 w-3 rounded-full bg-yellow-500 shrink-0" />;
|
return <div className="h-3 w-3 rounded-full bg-yellow-500" />;
|
||||||
}
|
}
|
||||||
return <div className="h-3 w-3 rounded-full bg-red-500 shrink-0" />;
|
return <div className="h-3 w-3 rounded-full bg-red-500" />;
|
||||||
};
|
|
||||||
|
|
||||||
const getServiceIcon = (key: string) => {
|
|
||||||
const icons: Record<string, any> = {
|
|
||||||
nodeBackend: Server,
|
|
||||||
mlBackend: Brain,
|
|
||||||
database: Database,
|
|
||||||
syslogParser: FileText,
|
|
||||||
analyticsAggregator: Activity,
|
|
||||||
autoBlock: Shield,
|
|
||||||
cleanup: Trash2,
|
|
||||||
listFetcher: ListChecks,
|
|
||||||
mlTraining: GraduationCap,
|
|
||||||
};
|
|
||||||
const Icon = icons[key] || Activity;
|
|
||||||
return <Icon className="h-5 w-5" />;
|
|
||||||
};
|
|
||||||
|
|
||||||
const controllableServices = [
|
|
||||||
"ids-ml-backend", "ids-syslog-parser", "ids-backend",
|
|
||||||
"ids-analytics-aggregator", "ids-auto-block", "ids-cleanup",
|
|
||||||
"ids-list-fetcher", "ids-ml-training"
|
|
||||||
];
|
|
||||||
|
|
||||||
const getLogCommand = (key: string): string | null => {
|
|
||||||
const logs: Record<string, string> = {
|
|
||||||
nodeBackend: "tail -f /var/log/ids/backend.log",
|
|
||||||
mlBackend: "journalctl -u ids-ml-backend -f",
|
|
||||||
database: "sudo journalctl -u postgresql-16 -f",
|
|
||||||
syslogParser: "tail -f /var/log/ids/syslog_parser.log",
|
|
||||||
analyticsAggregator: "journalctl -u ids-analytics-aggregator -f",
|
|
||||||
autoBlock: "journalctl -u ids-auto-block -f",
|
|
||||||
cleanup: "journalctl -u ids-cleanup -f",
|
|
||||||
listFetcher: "journalctl -u ids-list-fetcher -f",
|
|
||||||
mlTraining: "journalctl -u ids-ml-training -f",
|
|
||||||
};
|
|
||||||
return logs[key] || null;
|
|
||||||
};
|
|
||||||
|
|
||||||
const renderDetailRow = (label: string, value: any, variant?: "default" | "destructive" | "secondary" | "outline") => {
|
|
||||||
if (value === undefined || value === null) return null;
|
|
||||||
return (
|
|
||||||
<div className="flex items-center justify-between gap-2 flex-wrap">
|
|
||||||
<span className="text-sm text-muted-foreground">{label}:</span>
|
|
||||||
{variant ? (
|
|
||||||
<Badge variant={variant} className="text-xs">{String(value)}</Badge>
|
|
||||||
) : (
|
|
||||||
<span className="text-sm font-mono">{String(value)}</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const renderServiceDetails = (key: string, service: ServiceStatus) => {
|
|
||||||
const d = service.details;
|
|
||||||
if (!d) return null;
|
|
||||||
|
|
||||||
switch (key) {
|
|
||||||
case "nodeBackend":
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{renderDetailRow("Porta", d.port)}
|
|
||||||
{renderDetailRow("Uptime", d.uptime)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
case "mlBackend":
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{d.modelLoaded !== undefined && renderDetailRow("Modello ML", d.modelLoaded ? "Caricato" : "Non Caricato", d.modelLoaded ? "default" : "secondary")}
|
|
||||||
{d.error && renderDetailRow("Errore", d.error, "destructive")}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
case "database":
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{d.connected && renderDetailRow("Connessione", "Attiva", "default")}
|
|
||||||
{d.error && renderDetailRow("Errore", d.error, "destructive")}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
case "syslogParser":
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{d.recentLogs30min !== undefined && renderDetailRow("Log ultimi 30min", d.recentLogs30min.toLocaleString())}
|
|
||||||
{d.lastLog && renderDetailRow("Ultimo log", typeof d.lastLog === 'string' ? d.lastLog : new Date(d.lastLog).toLocaleString('it-IT'))}
|
|
||||||
{d.warning && renderDetailRow("Avviso", d.warning, "destructive")}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
case "analyticsAggregator":
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{d.lastRun && renderDetailRow("Ultima esecuzione", new Date(d.lastRun).toLocaleString('it-IT'))}
|
|
||||||
{d.hoursSinceLastRun && renderDetailRow("Ore dall'ultimo run", d.hoursSinceLastRun + "h", parseFloat(d.hoursSinceLastRun) < 2 ? "default" : "destructive")}
|
|
||||||
{d.warning && renderDetailRow("Avviso", d.warning, "destructive")}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
case "autoBlock":
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{renderDetailRow("Blocchi ultimi 10min", d.recentBlocks10min)}
|
|
||||||
{renderDetailRow("Totale bloccati", d.totalBlocked)}
|
|
||||||
{d.lastBlock && renderDetailRow("Ultimo blocco", typeof d.lastBlock === 'string' && d.lastBlock !== 'Mai' ? new Date(d.lastBlock).toLocaleString('it-IT') : d.lastBlock)}
|
|
||||||
{renderDetailRow("Intervallo", d.interval)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
case "cleanup":
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{renderDetailRow("Detection vecchie (>48h)", d.oldDetections48h, d.oldDetections48h > 0 ? "destructive" : "default")}
|
|
||||||
{renderDetailRow("Detection totali", d.totalDetections)}
|
|
||||||
{renderDetailRow("Intervallo", d.interval)}
|
|
||||||
{d.warning && renderDetailRow("Avviso", d.warning, "destructive")}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
case "listFetcher":
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{renderDetailRow("Liste totali", d.totalLists)}
|
|
||||||
{renderDetailRow("Liste attive", d.enabledLists)}
|
|
||||||
{d.lastFetched && renderDetailRow("Ultimo fetch", typeof d.lastFetched === 'string' && d.lastFetched !== 'Mai' ? new Date(d.lastFetched).toLocaleString('it-IT') : d.lastFetched)}
|
|
||||||
{d.hoursSinceLastFetch && renderDetailRow("Ore dall'ultimo fetch", d.hoursSinceLastFetch + "h", parseFloat(d.hoursSinceLastFetch) < 1 ? "default" : "destructive")}
|
|
||||||
{renderDetailRow("Intervallo", d.interval)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
case "mlTraining":
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{d.lastTraining && renderDetailRow("Ultimo training", typeof d.lastTraining === 'string' && d.lastTraining !== 'Mai' ? new Date(d.lastTraining).toLocaleString('it-IT') : d.lastTraining)}
|
|
||||||
{d.daysSinceLastTraining && renderDetailRow("Giorni dall'ultimo", d.daysSinceLastTraining, parseFloat(d.daysSinceLastTraining) < 8 ? "default" : "destructive")}
|
|
||||||
{d.lastStatus && renderDetailRow("Stato ultimo training", d.lastStatus, d.lastStatus === 'completed' ? "default" : "destructive")}
|
|
||||||
{d.lastModel && renderDetailRow("Modello", d.lastModel)}
|
|
||||||
{d.recordsProcessed && renderDetailRow("Record processati", d.recordsProcessed.toLocaleString())}
|
|
||||||
{renderDetailRow("Intervallo", d.interval)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
default:
|
|
||||||
return d.error ? renderDetailRow("Errore", d.error, "destructive") : null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const coreServices = ["nodeBackend", "mlBackend", "database", "syslogParser"];
|
|
||||||
const timerServices = ["autoBlock", "analyticsAggregator", "cleanup", "listFetcher", "mlTraining"];
|
|
||||||
|
|
||||||
const renderServiceCard = (key: string, service: ServiceStatus) => {
|
|
||||||
const isControllable = controllableServices.includes(service.systemdUnit);
|
|
||||||
const isTimer = service.type === "timer";
|
|
||||||
const logCmd = getLogCommand(key);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Card key={key} data-testid={`card-service-${key}`}>
|
|
||||||
<CardHeader className="flex flex-row items-center justify-between gap-2 space-y-0 pb-2">
|
|
||||||
<CardTitle className="flex items-center gap-2 text-base">
|
|
||||||
{getServiceIcon(key)}
|
|
||||||
<span className="truncate">{service.name}</span>
|
|
||||||
</CardTitle>
|
|
||||||
<div className="flex items-center gap-2 shrink-0">
|
|
||||||
{isTimer && <Timer className="h-4 w-4 text-muted-foreground" />}
|
|
||||||
{getStatusIndicator(service)}
|
|
||||||
</div>
|
|
||||||
</CardHeader>
|
|
||||||
<CardContent className="space-y-3">
|
|
||||||
<div className="flex items-center justify-between gap-2">
|
|
||||||
<span className="text-sm text-muted-foreground">Stato:</span>
|
|
||||||
{getStatusBadge(service, key)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex items-center justify-between gap-2">
|
|
||||||
<span className="text-sm text-muted-foreground">Systemd:</span>
|
|
||||||
<Badge variant="outline" className="text-xs font-mono">
|
|
||||||
{service.systemdUnit}{isTimer ? '.timer' : '.service'}
|
|
||||||
</Badge>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{renderServiceDetails(key, service)}
|
|
||||||
|
|
||||||
{isControllable && (
|
|
||||||
<div className="space-y-2 pt-2 border-t">
|
|
||||||
<p className="text-xs font-medium text-muted-foreground">Controlli:</p>
|
|
||||||
<div className="flex gap-2 flex-wrap">
|
|
||||||
<Button
|
|
||||||
size="sm"
|
|
||||||
variant="outline"
|
|
||||||
onClick={() => handleServiceAction(service.systemdUnit, "restart")}
|
|
||||||
disabled={serviceControlMutation.isPending}
|
|
||||||
data-testid={`button-restart-${key}`}
|
|
||||||
>
|
|
||||||
<RotateCw className="h-3 w-3 mr-1" />
|
|
||||||
Restart
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
size="sm"
|
|
||||||
variant="outline"
|
|
||||||
onClick={() => handleServiceAction(service.systemdUnit, "start")}
|
|
||||||
disabled={serviceControlMutation.isPending || service.status === 'running'}
|
|
||||||
data-testid={`button-start-${key}`}
|
|
||||||
>
|
|
||||||
<Play className="h-3 w-3 mr-1" />
|
|
||||||
Start
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
size="sm"
|
|
||||||
variant="outline"
|
|
||||||
onClick={() => handleServiceAction(service.systemdUnit, "stop")}
|
|
||||||
disabled={serviceControlMutation.isPending || service.status === 'offline'}
|
|
||||||
data-testid={`button-stop-${key}`}
|
|
||||||
>
|
|
||||||
<Square className="h-3 w-3 mr-1" />
|
|
||||||
Stop
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{logCmd && (
|
|
||||||
<div className="p-2 bg-muted rounded-md">
|
|
||||||
<p className="text-xs font-medium text-muted-foreground mb-1">Log:</p>
|
|
||||||
<code className="text-xs font-mono break-all" data-testid={`code-log-${key}`}>{logCmd}</code>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-6 p-6" data-testid="page-services">
|
<div className="flex flex-col gap-6 p-6" data-testid="page-services">
|
||||||
<div className="flex items-center justify-between gap-4 flex-wrap">
|
<div className="flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
<h1 className="text-3xl font-semibold" data-testid="text-services-title">Gestione Servizi</h1>
|
<h1 className="text-3xl font-semibold" data-testid="text-services-title">Gestione Servizi</h1>
|
||||||
<p className="text-muted-foreground" data-testid="text-services-subtitle">
|
<p className="text-muted-foreground" data-testid="text-services-subtitle">
|
||||||
Monitoraggio e controllo di tutti i servizi IDS
|
Monitoraggio e controllo dei servizi IDS
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<Button onClick={() => refetch()} variant="outline" data-testid="button-refresh">
|
<Button onClick={() => refetch()} variant="outline" data-testid="button-refresh">
|
||||||
@ -315,40 +100,303 @@ export default function ServicesPage() {
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{isLoading && (
|
<Alert data-testid="alert-server-instructions">
|
||||||
<div className="text-center py-8 text-muted-foreground">Caricamento stato servizi...</div>
|
<AlertCircle className="h-4 w-4" />
|
||||||
)}
|
<AlertTitle>Gestione Servizi Systemd</AlertTitle>
|
||||||
|
<AlertDescription>
|
||||||
|
I servizi IDS sono gestiti da systemd sul server AlmaLinux.
|
||||||
|
Usa i pulsanti qui sotto per controllarli oppure esegui i comandi systemctl direttamente sul server.
|
||||||
|
</AlertDescription>
|
||||||
|
</Alert>
|
||||||
|
|
||||||
{servicesStatus && (
|
{/* Services Grid */}
|
||||||
<>
|
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||||||
<div>
|
{/* ML Backend Service */}
|
||||||
<h2 className="text-lg font-semibold mb-3 flex items-center gap-2">
|
<Card data-testid="card-ml-backend-service">
|
||||||
<Server className="h-5 w-5" />
|
<CardHeader>
|
||||||
Servizi Core
|
<CardTitle className="flex items-center gap-2 text-lg">
|
||||||
</h2>
|
<Brain className="h-5 w-5" />
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 gap-4">
|
ML Backend Python
|
||||||
{coreServices.map((key) => {
|
{servicesStatus && getStatusIndicator(servicesStatus.services.mlBackend)}
|
||||||
const service = (servicesStatus.services as any)[key];
|
</CardTitle>
|
||||||
return service ? renderServiceCard(key, service) : null;
|
</CardHeader>
|
||||||
})}
|
<CardContent className="space-y-4">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<span className="text-sm text-muted-foreground">Stato:</span>
|
||||||
|
{servicesStatus && getStatusBadge(servicesStatus.services.mlBackend)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
{servicesStatus?.services.mlBackend.details?.modelLoaded !== undefined && (
|
||||||
<h2 className="text-lg font-semibold mb-3 flex items-center gap-2">
|
<div className="flex items-center justify-between">
|
||||||
<Clock className="h-5 w-5" />
|
<span className="text-sm text-muted-foreground">Modello ML:</span>
|
||||||
Timer Systemd (Attivita Periodiche)
|
<Badge variant={servicesStatus.services.mlBackend.details.modelLoaded ? "default" : "secondary"}>
|
||||||
</h2>
|
{servicesStatus.services.mlBackend.details.modelLoaded ? "Caricato" : "Non Caricato"}
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4">
|
</Badge>
|
||||||
{timerServices.map((key) => {
|
</div>
|
||||||
const service = (servicesStatus.services as any)[key];
|
)}
|
||||||
return service ? renderServiceCard(key, service) : null;
|
|
||||||
})}
|
{/* Service Controls */}
|
||||||
|
<div className="mt-4 space-y-2">
|
||||||
|
<p className="text-xs font-medium mb-2">Controlli Servizio:</p>
|
||||||
|
<div className="flex gap-2 flex-wrap">
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
variant="outline"
|
||||||
|
onClick={() => handleServiceAction("ids-ml-backend", "start")}
|
||||||
|
disabled={serviceControlMutation.isPending || servicesStatus?.services.mlBackend.status === 'running'}
|
||||||
|
data-testid="button-start-ml"
|
||||||
|
>
|
||||||
|
<Play className="h-3 w-3 mr-1" />
|
||||||
|
Start
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
variant="outline"
|
||||||
|
onClick={() => handleServiceAction("ids-ml-backend", "stop")}
|
||||||
|
disabled={serviceControlMutation.isPending || servicesStatus?.services.mlBackend.status === 'offline'}
|
||||||
|
data-testid="button-stop-ml"
|
||||||
|
>
|
||||||
|
<Square className="h-3 w-3 mr-1" />
|
||||||
|
Stop
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
variant="outline"
|
||||||
|
onClick={() => handleServiceAction("ids-ml-backend", "restart")}
|
||||||
|
disabled={serviceControlMutation.isPending}
|
||||||
|
data-testid="button-restart-ml"
|
||||||
|
>
|
||||||
|
<RotateCw className="h-3 w-3 mr-1" />
|
||||||
|
Restart
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
|
{/* Manual Commands (fallback) */}
|
||||||
|
<div className="mt-4 p-3 bg-muted rounded-lg">
|
||||||
|
<p className="text-xs font-medium mb-2">Comando systemctl (sul server):</p>
|
||||||
|
<code className="text-xs bg-background p-2 rounded block font-mono" data-testid="code-systemctl-ml">
|
||||||
|
sudo systemctl {servicesStatus?.services.mlBackend.status === 'offline' ? 'start' : 'restart'} ids-ml-backend
|
||||||
|
</code>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-4 p-3 bg-muted rounded-lg">
|
||||||
|
<p className="text-xs font-medium mb-2">Log:</p>
|
||||||
|
<code className="text-xs bg-background p-2 rounded block font-mono" data-testid="code-log-ml">
|
||||||
|
tail -f /var/log/ids/backend.log
|
||||||
|
</code>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
{/* Database Service */}
|
||||||
|
<Card data-testid="card-database-service">
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle className="flex items-center gap-2 text-lg">
|
||||||
|
<Database className="h-5 w-5" />
|
||||||
|
PostgreSQL Database
|
||||||
|
{servicesStatus && getStatusIndicator(servicesStatus.services.database)}
|
||||||
|
</CardTitle>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="space-y-4">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<span className="text-sm text-muted-foreground">Stato:</span>
|
||||||
|
{servicesStatus && getStatusBadge(servicesStatus.services.database)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{servicesStatus?.services.database.status === 'running' && (
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<span className="text-sm text-muted-foreground">Connessione:</span>
|
||||||
|
<Badge variant="default" className="bg-green-600">Connesso</Badge>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="mt-4 p-3 bg-muted rounded-lg">
|
||||||
|
<p className="text-xs font-medium mb-2">Verifica status:</p>
|
||||||
|
<code className="text-xs bg-background p-2 rounded block font-mono" data-testid="code-status-db">
|
||||||
|
systemctl status postgresql-16
|
||||||
|
</code>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{servicesStatus?.services.database.status === 'error' && (
|
||||||
|
<div className="mt-4 p-3 bg-muted rounded-lg">
|
||||||
|
<p className="text-xs font-medium mb-2">Riavvia database:</p>
|
||||||
|
<code className="text-xs bg-background p-2 rounded block font-mono" data-testid="code-restart-db">
|
||||||
|
sudo systemctl restart postgresql-16
|
||||||
|
</code>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="mt-4 p-3 bg-muted rounded-lg">
|
||||||
|
<p className="text-xs font-medium mb-2">Log:</p>
|
||||||
|
<code className="text-xs bg-background p-2 rounded block font-mono" data-testid="code-log-db">
|
||||||
|
sudo journalctl -u postgresql-16 -f
|
||||||
|
</code>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
{/* Syslog Parser Service */}
|
||||||
|
<Card data-testid="card-syslog-parser-service">
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle className="flex items-center gap-2 text-lg">
|
||||||
|
<FileText className="h-5 w-5" />
|
||||||
|
Syslog Parser
|
||||||
|
{servicesStatus && getStatusIndicator(servicesStatus.services.syslogParser)}
|
||||||
|
</CardTitle>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="space-y-4">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<span className="text-sm text-muted-foreground">Stato:</span>
|
||||||
|
{servicesStatus && getStatusBadge(servicesStatus.services.syslogParser)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{servicesStatus?.services.syslogParser.details?.pid && (
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<span className="text-sm text-muted-foreground">PID Processo:</span>
|
||||||
|
<Badge variant="outline" className="font-mono">
|
||||||
|
{servicesStatus.services.syslogParser.details.pid}
|
||||||
|
</Badge>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{servicesStatus?.services.syslogParser.details?.systemd_unit && (
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<span className="text-sm text-muted-foreground">Systemd Unit:</span>
|
||||||
|
<Badge variant="outline" className="font-mono text-xs">
|
||||||
|
{servicesStatus.services.syslogParser.details.systemd_unit}
|
||||||
|
</Badge>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Service Controls */}
|
||||||
|
<div className="mt-4 space-y-2">
|
||||||
|
<p className="text-xs font-medium mb-2">Controlli Servizio:</p>
|
||||||
|
<div className="flex gap-2 flex-wrap">
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
variant="outline"
|
||||||
|
onClick={() => handleServiceAction("ids-syslog-parser", "start")}
|
||||||
|
disabled={serviceControlMutation.isPending || servicesStatus?.services.syslogParser.status === 'running'}
|
||||||
|
data-testid="button-start-parser"
|
||||||
|
>
|
||||||
|
<Play className="h-3 w-3 mr-1" />
|
||||||
|
Start
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
variant="outline"
|
||||||
|
onClick={() => handleServiceAction("ids-syslog-parser", "stop")}
|
||||||
|
disabled={serviceControlMutation.isPending || servicesStatus?.services.syslogParser.status === 'offline'}
|
||||||
|
data-testid="button-stop-parser"
|
||||||
|
>
|
||||||
|
<Square className="h-3 w-3 mr-1" />
|
||||||
|
Stop
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
variant="outline"
|
||||||
|
onClick={() => handleServiceAction("ids-syslog-parser", "restart")}
|
||||||
|
disabled={serviceControlMutation.isPending}
|
||||||
|
data-testid="button-restart-parser"
|
||||||
|
>
|
||||||
|
<RotateCw className="h-3 w-3 mr-1" />
|
||||||
|
Restart
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Manual Commands (fallback) */}
|
||||||
|
<div className="mt-4 p-3 bg-muted rounded-lg">
|
||||||
|
<p className="text-xs font-medium mb-2">Comando systemctl (sul server):</p>
|
||||||
|
<code className="text-xs bg-background p-2 rounded block font-mono" data-testid="code-systemctl-parser">
|
||||||
|
sudo systemctl {servicesStatus?.services.syslogParser.status === 'offline' ? 'start' : 'restart'} ids-syslog-parser
|
||||||
|
</code>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-4 p-3 bg-muted rounded-lg">
|
||||||
|
<p className="text-xs font-medium mb-2">Log:</p>
|
||||||
|
<code className="text-xs bg-background p-2 rounded block font-mono" data-testid="code-log-parser">
|
||||||
|
tail -f /var/log/ids/syslog_parser.log
|
||||||
|
</code>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
{/* Analytics Aggregator Service */}
|
||||||
|
<Card data-testid="card-analytics-aggregator-service">
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle className="flex items-center gap-2 text-lg">
|
||||||
|
<Activity className="h-5 w-5" />
|
||||||
|
Analytics Aggregator
|
||||||
|
{servicesStatus && getStatusIndicator(servicesStatus.services.analyticsAggregator)}
|
||||||
|
</CardTitle>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="space-y-4">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<span className="text-sm text-muted-foreground">Stato:</span>
|
||||||
|
{servicesStatus && getStatusBadge(servicesStatus.services.analyticsAggregator)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{servicesStatus?.services.analyticsAggregator.details?.lastRun && (
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<span className="text-sm text-muted-foreground">Ultima Aggregazione:</span>
|
||||||
|
<Badge variant="outline" className="text-xs">
|
||||||
|
{new Date(servicesStatus.services.analyticsAggregator.details.lastRun).toLocaleString('it-IT')}
|
||||||
|
</Badge>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{servicesStatus?.services.analyticsAggregator.details?.hoursSinceLastRun && (
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<span className="text-sm text-muted-foreground">Ore dall'ultimo run:</span>
|
||||||
|
<Badge variant={parseFloat(servicesStatus.services.analyticsAggregator.details.hoursSinceLastRun) < 2 ? "default" : "destructive"}>
|
||||||
|
{servicesStatus.services.analyticsAggregator.details.hoursSinceLastRun}h
|
||||||
|
</Badge>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* CRITICAL ALERT: Aggregator idle for too long */}
|
||||||
|
{servicesStatus?.services.analyticsAggregator.details?.hoursSinceLastRun &&
|
||||||
|
parseFloat(servicesStatus.services.analyticsAggregator.details.hoursSinceLastRun) > 2 && (
|
||||||
|
<Alert variant="destructive" className="mt-2" data-testid="alert-aggregator-idle">
|
||||||
|
<AlertCircle className="h-4 w-4" />
|
||||||
|
<AlertTitle className="text-sm font-semibold">⚠️ Timer Systemd Non Attivo</AlertTitle>
|
||||||
|
<AlertDescription className="text-xs mt-1">
|
||||||
|
<p className="mb-2">L'aggregatore non esegue da {servicesStatus.services.analyticsAggregator.details.hoursSinceLastRun}h! Dashboard e Analytics bloccati.</p>
|
||||||
|
<p className="font-semibold">Soluzione Immediata (sul server):</p>
|
||||||
|
<code className="block bg-destructive-foreground/10 p-2 rounded mt-1 font-mono text-xs">
|
||||||
|
sudo /opt/ids/deployment/setup_analytics_timer.sh
|
||||||
|
</code>
|
||||||
|
</AlertDescription>
|
||||||
|
</Alert>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="mt-4 p-3 bg-muted rounded-lg">
|
||||||
|
<p className="text-xs font-medium mb-2">Verifica timer:</p>
|
||||||
|
<code className="text-xs bg-background p-2 rounded block font-mono" data-testid="code-status-aggregator">
|
||||||
|
systemctl status ids-analytics-aggregator.timer
|
||||||
|
</code>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-4 p-3 bg-muted rounded-lg">
|
||||||
|
<p className="text-xs font-medium mb-2">Avvia aggregazione manualmente:</p>
|
||||||
|
<code className="text-xs bg-background p-2 rounded block font-mono" data-testid="code-run-aggregator">
|
||||||
|
cd /opt/ids && ./deployment/run_analytics.sh
|
||||||
|
</code>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-4 p-3 bg-muted rounded-lg">
|
||||||
|
<p className="text-xs font-medium mb-2">Log:</p>
|
||||||
|
<code className="text-xs bg-background p-2 rounded block font-mono" data-testid="code-log-aggregator">
|
||||||
|
journalctl -u ids-analytics-aggregator.timer -f
|
||||||
|
</code>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Additional Commands */}
|
||||||
<Card data-testid="card-additional-commands">
|
<Card data-testid="card-additional-commands">
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle className="flex items-center gap-2">
|
<CardTitle className="flex items-center gap-2">
|
||||||
@ -358,27 +406,30 @@ export default function ServicesPage() {
|
|||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="space-y-4">
|
<CardContent className="space-y-4">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm font-medium mb-2">Stato di tutti i servizi IDS:</p>
|
<p className="text-sm font-medium mb-2">Verifica tutti i processi IDS attivi:</p>
|
||||||
<code className="text-xs bg-muted p-2 rounded-md block font-mono" data-testid="code-all-services">
|
<code className="text-xs bg-muted p-2 rounded block font-mono" data-testid="code-check-processes">
|
||||||
systemctl list-units 'ids-*' --all
|
ps aux | grep -E "python.*(main|syslog_parser)" | grep -v grep
|
||||||
</code>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<p className="text-sm font-medium mb-2">Stato di tutti i timer IDS:</p>
|
|
||||||
<code className="text-xs bg-muted p-2 rounded-md block font-mono" data-testid="code-all-timers">
|
|
||||||
systemctl list-timers 'ids-*' --all
|
|
||||||
</code>
|
</code>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm font-medium mb-2">Verifica log RSyslog (ricezione log MikroTik):</p>
|
<p className="text-sm font-medium mb-2">Verifica log RSyslog (ricezione log MikroTik):</p>
|
||||||
<code className="text-xs bg-muted p-2 rounded-md block font-mono" data-testid="code-check-rsyslog">
|
<code className="text-xs bg-muted p-2 rounded block font-mono" data-testid="code-check-rsyslog">
|
||||||
tail -f /var/log/mikrotik/raw.log
|
tail -f /var/log/mikrotik/raw.log
|
||||||
</code>
|
</code>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm font-medium mb-2">Verifica processi IDS attivi:</p>
|
<p className="text-sm font-medium mb-2">Esegui training manuale ML:</p>
|
||||||
<code className="text-xs bg-muted p-2 rounded-md block font-mono" data-testid="code-check-processes">
|
<code className="text-xs bg-muted p-2 rounded block font-mono" data-testid="code-manual-training">
|
||||||
ps aux | grep -E "python.*(main|syslog_parser)" | grep -v grep
|
curl -X POST http://localhost:8000/train -H "Content-Type: application/json" -d '{"max_records": 10000, "hours_back": 24}'
|
||||||
|
</code>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p className="text-sm font-medium mb-2">Verifica storico training nel database:</p>
|
||||||
|
<code className="text-xs bg-muted p-2 rounded block font-mono" data-testid="code-check-training">
|
||||||
|
psql $DATABASE_URL -c "SELECT * FROM training_history ORDER BY trained_at DESC LIMIT 5;"
|
||||||
</code>
|
</code>
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
-- PostgreSQL database dump
|
-- PostgreSQL database dump
|
||||||
--
|
--
|
||||||
|
|
||||||
\restrict QQPZgpukcxzRMKOdS5xNsXDiphiHLW5uAuhQxN7luRJ2u8BkVkDOz1h9Un2BrJ0
|
\restrict IQNXQ3AdZIKCf43dmd4ux9afKlXfTublRgIkiThbrdwGm8ObGL1XepBpgAQJoeC
|
||||||
|
|
||||||
-- Dumped from database version 16.11 (df20cf9)
|
-- Dumped from database version 16.11 (df20cf9)
|
||||||
-- Dumped by pg_dump version 16.10
|
-- Dumped by pg_dump version 16.10
|
||||||
@ -387,5 +387,5 @@ ALTER TABLE ONLY public.public_blacklist_ips
|
|||||||
-- PostgreSQL database dump complete
|
-- PostgreSQL database dump complete
|
||||||
--
|
--
|
||||||
|
|
||||||
\unrestrict QQPZgpukcxzRMKOdS5xNsXDiphiHLW5uAuhQxN7luRJ2u8BkVkDOz1h9Un2BrJ0
|
\unrestrict IQNXQ3AdZIKCf43dmd4ux9afKlXfTublRgIkiThbrdwGm8ObGL1XepBpgAQJoeC
|
||||||
|
|
||||||
|
|||||||
@ -1,39 +1,34 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# =========================================================
|
# =========================================================
|
||||||
# CHECK BACKEND - Verifica e riavvia backend Python se necessario
|
# CHECK BACKEND - Verifica e riavvia backend Python se necessario
|
||||||
# Usa systemctl per gestire il servizio (con virtual environment)
|
|
||||||
# Nota: questo script può girare come root o come user ids
|
|
||||||
# =========================================================
|
# =========================================================
|
||||||
|
|
||||||
|
PROCESS_NAME="python3.11 python_ml/main.py"
|
||||||
|
PID_FILE="/var/log/ids/backend.pid"
|
||||||
LOG_FILE="/var/log/ids/backend.log"
|
LOG_FILE="/var/log/ids/backend.log"
|
||||||
|
WORK_DIR="/opt/ids"
|
||||||
|
|
||||||
mkdir -p /var/log/ids
|
mkdir -p /var/log/ids
|
||||||
|
|
||||||
# Check if systemd service is active
|
# Check if backend is running
|
||||||
if systemctl is-active --quiet ids-ml-backend; then
|
if pgrep -f "$PROCESS_NAME" > /dev/null; then
|
||||||
|
# Backend running, update PID
|
||||||
|
pgrep -f "$PROCESS_NAME" > "$PID_FILE"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
|
||||||
|
|
||||||
# Verifica anche se il processo Python è attivo (fallback)
|
|
||||||
if pgrep -f "python.*main.py" > /dev/null; then
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "[$(date)] Backend Python NON attivo, riavvio..." >> "$LOG_FILE"
|
|
||||||
|
|
||||||
# Prova prima con systemctl (funziona se eseguito come root o con sudo configurato)
|
|
||||||
if [ "$(id -u)" -eq 0 ]; then
|
|
||||||
systemctl restart ids-ml-backend
|
|
||||||
else
|
else
|
||||||
# Se non siamo root, prova con sudo (richiede sudoers configurato)
|
echo "[$(date)] Backend Python NON attivo, riavvio..." >> "$LOG_FILE"
|
||||||
sudo systemctl restart ids-ml-backend 2>/dev/null
|
|
||||||
fi
|
# Kill any orphaned Python processes
|
||||||
|
pkill -f "python_ml/main.py" 2>/dev/null
|
||||||
# Wait for startup
|
|
||||||
sleep 5
|
# Wait a moment
|
||||||
|
sleep 2
|
||||||
if systemctl is-active --quiet ids-ml-backend || pgrep -f "python.*main.py" > /dev/null; then
|
|
||||||
echo "[$(date)] Backend riavviato con successo" >> "$LOG_FILE"
|
# Start backend
|
||||||
else
|
cd "$WORK_DIR/python_ml"
|
||||||
echo "[$(date)] ERRORE: Backend non si è avviato. Controlla: journalctl -u ids-ml-backend" >> "$LOG_FILE"
|
nohup /usr/bin/python3.11 main.py >> "$LOG_FILE" 2>&1 &
|
||||||
|
NEW_PID=$!
|
||||||
|
echo $NEW_PID > "$PID_FILE"
|
||||||
|
|
||||||
|
echo "[$(date)] Backend riavviato con PID: $NEW_PID" >> "$LOG_FILE"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@ -1,23 +1,41 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# =========================================================
|
# =========================================================
|
||||||
# CHECK FRONTEND - Verifica se backend Node.js e' attivo
|
# CHECK FRONTEND - Verifica e riavvia frontend Node.js se necessario
|
||||||
# =========================================================
|
# =========================================================
|
||||||
|
|
||||||
LOG_FILE="/var/log/ids/backend.log"
|
PROCESS_NAME="npm run dev"
|
||||||
|
PID_FILE="/var/log/ids/frontend.pid"
|
||||||
|
LOG_FILE="/var/log/ids/frontend.log"
|
||||||
|
WORK_DIR="/opt/ids"
|
||||||
|
|
||||||
mkdir -p /var/log/ids
|
mkdir -p /var/log/ids
|
||||||
|
|
||||||
if systemctl is-active --quiet ids-backend.service 2>/dev/null; then
|
# Check if frontend is running
|
||||||
|
if pgrep -f "vite" > /dev/null; then
|
||||||
|
# Frontend running, update PID
|
||||||
|
pgrep -f "vite" > "$PID_FILE"
|
||||||
exit 0
|
exit 0
|
||||||
else
|
else
|
||||||
echo "[$(date)] Backend Node.js NON attivo" >> "$LOG_FILE"
|
echo "[$(date)] Frontend Node NON attivo, riavvio..." >> "$LOG_FILE"
|
||||||
systemctl start ids-backend.service 2>> "$LOG_FILE" || true
|
|
||||||
|
# Kill any orphaned Node processes
|
||||||
sleep 3
|
pkill -f "vite" 2>/dev/null
|
||||||
|
pkill -f "npm run dev" 2>/dev/null
|
||||||
if systemctl is-active --quiet ids-backend.service 2>/dev/null; then
|
|
||||||
echo "[$(date)] Backend riavviato con successo via systemd" >> "$LOG_FILE"
|
# Wait a moment
|
||||||
|
sleep 2
|
||||||
|
|
||||||
|
# Start frontend with environment variables from .env
|
||||||
|
cd "$WORK_DIR"
|
||||||
|
if [ -f "$WORK_DIR/.env" ]; then
|
||||||
|
# Load .env and start npm with those variables
|
||||||
|
nohup env $(cat "$WORK_DIR/.env" | grep -v '^#' | xargs) npm run dev >> "$LOG_FILE" 2>&1 &
|
||||||
else
|
else
|
||||||
echo "[$(date)] ERRORE: Backend non si e' avviato - verificare con: journalctl -u ids-backend -n 20" >> "$LOG_FILE"
|
# Fallback: start without .env (will use system env vars)
|
||||||
|
nohup npm run dev >> "$LOG_FILE" 2>&1 &
|
||||||
fi
|
fi
|
||||||
|
NEW_PID=$!
|
||||||
|
echo $NEW_PID > "$PID_FILE"
|
||||||
|
|
||||||
|
echo "[$(date)] Frontend riavviato con PID: $NEW_PID" >> "$LOG_FILE"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@ -18,49 +18,43 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|||||||
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "Installing systemd service files..."
|
echo "📋 Installing systemd service files..."
|
||||||
|
|
||||||
# Copy service files
|
# Copy service files
|
||||||
cp "$PROJECT_ROOT/deployment/systemd/ids-backend.service" /etc/systemd/system/
|
|
||||||
cp "$PROJECT_ROOT/deployment/systemd/ids-ml-backend.service" /etc/systemd/system/
|
cp "$PROJECT_ROOT/deployment/systemd/ids-ml-backend.service" /etc/systemd/system/
|
||||||
cp "$PROJECT_ROOT/deployment/systemd/ids-syslog-parser.service" /etc/systemd/system/
|
cp "$PROJECT_ROOT/deployment/systemd/ids-syslog-parser.service" /etc/systemd/system/
|
||||||
cp "$PROJECT_ROOT/deployment/systemd/ids-auto-block.service" /etc/systemd/system/
|
|
||||||
|
|
||||||
# Ensure correct permissions
|
# Ensure correct permissions
|
||||||
chmod 644 /etc/systemd/system/ids-backend.service
|
|
||||||
chmod 644 /etc/systemd/system/ids-ml-backend.service
|
chmod 644 /etc/systemd/system/ids-ml-backend.service
|
||||||
chmod 644 /etc/systemd/system/ids-syslog-parser.service
|
chmod 644 /etc/systemd/system/ids-syslog-parser.service
|
||||||
chmod 644 /etc/systemd/system/ids-auto-block.service
|
|
||||||
|
|
||||||
echo "Service files copied to /etc/systemd/system/"
|
echo "✅ Service files copied to /etc/systemd/system/"
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "Reloading systemd daemon..."
|
echo "🔄 Reloading systemd daemon..."
|
||||||
systemctl daemon-reload
|
systemctl daemon-reload
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "Enabling services to start on boot..."
|
echo "🔧 Enabling services to start on boot..."
|
||||||
systemctl enable ids-backend.service
|
|
||||||
systemctl enable ids-ml-backend.service
|
systemctl enable ids-ml-backend.service
|
||||||
systemctl enable ids-syslog-parser.service
|
systemctl enable ids-syslog-parser.service
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "========================================="
|
echo "========================================="
|
||||||
echo "Installation Complete!"
|
echo "✅ Installation Complete!"
|
||||||
echo "========================================="
|
echo "========================================="
|
||||||
echo ""
|
echo ""
|
||||||
echo "Next steps:"
|
echo "Next steps:"
|
||||||
echo ""
|
echo ""
|
||||||
echo "1. Start the services:"
|
echo "1. Start the services:"
|
||||||
echo " sudo systemctl start ids-backend"
|
|
||||||
echo " sudo systemctl start ids-ml-backend"
|
echo " sudo systemctl start ids-ml-backend"
|
||||||
echo " sudo systemctl start ids-syslog-parser"
|
echo " sudo systemctl start ids-syslog-parser"
|
||||||
echo ""
|
echo ""
|
||||||
echo "2. Check status:"
|
echo "2. Check status:"
|
||||||
echo " sudo systemctl status ids-backend ids-ml-backend ids-syslog-parser"
|
echo " sudo systemctl status ids-ml-backend"
|
||||||
|
echo " sudo systemctl status ids-syslog-parser"
|
||||||
echo ""
|
echo ""
|
||||||
echo "3. View logs:"
|
echo "3. View logs:"
|
||||||
echo " tail -f /var/log/ids/backend.log"
|
|
||||||
echo " tail -f /var/log/ids/ml_backend.log"
|
echo " tail -f /var/log/ids/ml_backend.log"
|
||||||
echo " tail -f /var/log/ids/syslog_parser.log"
|
echo " tail -f /var/log/ids/syslog_parser.log"
|
||||||
echo ""
|
echo ""
|
||||||
|
|||||||
@ -1,20 +1,17 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# =========================================================
|
# =========================================================
|
||||||
# RESTART ALL - Riavvio completo sistema IDS
|
# RESTART ALL - Riavvio completo sistema IDS
|
||||||
# Usa systemctl per ML Backend, processo diretto per frontend
|
|
||||||
# =========================================================
|
# =========================================================
|
||||||
|
|
||||||
LOG_FILE="/var/log/ids/cron.log"
|
LOG_FILE="/var/log/ids/cron.log"
|
||||||
|
|
||||||
echo "$(date): === RESTART SETTIMANALE SISTEMA IDS ===" >> "$LOG_FILE"
|
echo "$(date): === RESTART SETTIMANALE SISTEMA IDS ===" >> "$LOG_FILE"
|
||||||
|
|
||||||
# Stop ML Backend via systemctl
|
# Stop all services
|
||||||
echo "$(date): Arresto servizi..." >> "$LOG_FILE"
|
echo "$(date): Arresto servizi..." >> "$LOG_FILE"
|
||||||
systemctl stop ids-ml-backend 2>/dev/null
|
pkill -f "python_ml/main.py"
|
||||||
|
pkill -f "vite"
|
||||||
# Stop frontend processes
|
pkill -f "npm run dev"
|
||||||
pkill -f "vite" 2>/dev/null
|
|
||||||
pkill -f "npm run dev" 2>/dev/null
|
|
||||||
|
|
||||||
sleep 5
|
sleep 5
|
||||||
|
|
||||||
@ -23,26 +20,10 @@ echo "$(date): Pulizia file temporanei..." >> "$LOG_FILE"
|
|||||||
rm -f /var/log/ids/*.pid
|
rm -f /var/log/ids/*.pid
|
||||||
find /tmp -name "ids_*" -mtime +7 -delete 2>/dev/null
|
find /tmp -name "ids_*" -mtime +7 -delete 2>/dev/null
|
||||||
|
|
||||||
# Restart ML Backend via systemctl
|
# Restart services
|
||||||
echo "$(date): Riavvio servizi..." >> "$LOG_FILE"
|
echo "$(date): Riavvio servizi..." >> "$LOG_FILE"
|
||||||
systemctl start ids-ml-backend
|
/opt/ids/deployment/check_backend.sh >> "$LOG_FILE" 2>&1
|
||||||
sleep 3
|
sleep 3
|
||||||
|
|
||||||
# Restart frontend via check script
|
|
||||||
/opt/ids/deployment/check_frontend.sh >> "$LOG_FILE" 2>&1
|
/opt/ids/deployment/check_frontend.sh >> "$LOG_FILE" 2>&1
|
||||||
|
|
||||||
# Verify ML Backend
|
|
||||||
if systemctl is-active --quiet ids-ml-backend; then
|
|
||||||
echo "$(date): ML Backend avviato con successo" >> "$LOG_FILE"
|
|
||||||
else
|
|
||||||
echo "$(date): ERRORE: ML Backend non si è avviato" >> "$LOG_FILE"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Verify Frontend
|
|
||||||
if pgrep -f "vite" > /dev/null; then
|
|
||||||
echo "$(date): Frontend avviato con successo" >> "$LOG_FILE"
|
|
||||||
else
|
|
||||||
echo "$(date): ERRORE: Frontend non si è avviato" >> "$LOG_FILE"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "$(date): Restart completato!" >> "$LOG_FILE"
|
echo "$(date): Restart completato!" >> "$LOG_FILE"
|
||||||
|
|||||||
@ -1,56 +1,58 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
#
|
#
|
||||||
# Restart IDS Frontend (Node.js/Express)
|
# Restart IDS Frontend (Node.js/Express/Vite)
|
||||||
# Utility per restart manuale del server frontend via systemd
|
# Utility per restart manuale del server frontend
|
||||||
#
|
#
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
echo "Restart Backend Node.js via systemd..."
|
echo "🔄 Restart Frontend Node.js..."
|
||||||
|
|
||||||
# Stop servizio
|
# Kill AGGRESSIVO di tutti i processi Node/Vite
|
||||||
echo "Stopping ids-backend..."
|
echo "⏸️ Stopping all Node/Vite processes..."
|
||||||
sudo systemctl stop ids-backend.service 2>/dev/null || true
|
pkill -9 -f "node.*tsx" 2>/dev/null || true
|
||||||
|
pkill -9 -f "vite" 2>/dev/null || true
|
||||||
|
pkill -9 -f "npm run dev" 2>/dev/null || true
|
||||||
sleep 2
|
sleep 2
|
||||||
|
|
||||||
# Kill eventuali processi orfani sulla porta 5000
|
# Kill processo sulla porta 5000 (se esiste)
|
||||||
echo "Liberando porta 5000..."
|
echo "🔍 Liberando porta 5000..."
|
||||||
lsof -ti:5000 | xargs kill -9 2>/dev/null || true
|
lsof -ti:5000 | xargs kill -9 2>/dev/null || true
|
||||||
sleep 1
|
sleep 1
|
||||||
|
|
||||||
# Verifica porta libera
|
# Verifica porta LIBERA
|
||||||
if lsof -Pi :5000 -sTCP:LISTEN -t >/dev/null 2>&1; then
|
if lsof -Pi :5000 -sTCP:LISTEN -t >/dev/null 2>&1; then
|
||||||
echo "ERRORE: Porta 5000 ancora occupata!"
|
echo "❌ ERRORE: Porta 5000 ancora occupata!"
|
||||||
echo "Processi sulla porta:"
|
echo "Processi sulla porta:"
|
||||||
lsof -i:5000
|
lsof -i:5000
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Porta 5000 libera"
|
echo "✅ Porta 5000 libera"
|
||||||
|
|
||||||
# Start servizio
|
# Restart usando check_frontend.sh
|
||||||
echo "Starting ids-backend..."
|
echo "🚀 Starting frontend..."
|
||||||
sudo systemctl start ids-backend.service
|
/opt/ids/deployment/check_frontend.sh
|
||||||
|
|
||||||
# Attendi avvio completo
|
# Attendi avvio completo
|
||||||
sleep 5
|
sleep 5
|
||||||
|
|
||||||
# Verifica avvio
|
# Verifica avvio
|
||||||
if systemctl is-active --quiet ids-backend.service; then
|
if pgrep -f "vite" > /dev/null; then
|
||||||
echo "Backend avviato con successo"
|
PID=$(pgrep -f "vite")
|
||||||
echo "Server disponibile su: http://localhost:5000"
|
echo "✅ Frontend avviato con PID: $PID"
|
||||||
|
echo "📡 Server disponibile su: http://localhost:5000"
|
||||||
|
|
||||||
# Test rapido
|
# Test rapido
|
||||||
sleep 2
|
sleep 2
|
||||||
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:5000/ 2>/dev/null || echo "000")
|
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:5000/ 2>/dev/null || echo "000")
|
||||||
if [ "$HTTP_CODE" = "200" ]; then
|
if [ "$HTTP_CODE" = "200" ]; then
|
||||||
echo "HTTP test OK (200)"
|
echo "✅ HTTP test OK (200)"
|
||||||
else
|
else
|
||||||
echo "HTTP test: $HTTP_CODE (potrebbe essere in fase di avvio)"
|
echo "⚠️ HTTP test: $HTTP_CODE"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo "ERRORE: Backend non avviato!"
|
echo "❌ Errore: Frontend non avviato!"
|
||||||
echo "Controlla log: journalctl -u ids-backend -n 20"
|
echo "📋 Controlla log: tail -f /var/log/ids/frontend.log"
|
||||||
sudo journalctl -u ids-backend -n 20 --no-pager
|
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
[Unit]
|
[Unit]
|
||||||
Description=IDS Auto-Blocking Service - Detect and Block Malicious IPs
|
Description=IDS Auto-Blocking Service - Detect and Block Malicious IPs
|
||||||
After=network.target postgresql-16.service
|
Documentation=https://github.com/yourusername/ids
|
||||||
Wants=ids-ml-backend.service
|
After=network.target ids-ml-backend.service postgresql-16.service
|
||||||
|
Requires=ids-ml-backend.service
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=oneshot
|
Type=oneshot
|
||||||
@ -22,8 +23,8 @@ SyslogIdentifier=ids-auto-block
|
|||||||
NoNewPrivileges=true
|
NoNewPrivileges=true
|
||||||
PrivateTmp=true
|
PrivateTmp=true
|
||||||
|
|
||||||
# Timeout: max 8 minuti per detection+blocking
|
# Timeout: max 3 minuti per detection+blocking
|
||||||
TimeoutStartSec=480
|
TimeoutStartSec=180
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
|
|||||||
@ -1,32 +0,0 @@
|
|||||||
[Unit]
|
|
||||||
Description=IDS Node.js Backend (Express API + Frontend)
|
|
||||||
After=network.target postgresql-16.service
|
|
||||||
Wants=postgresql-16.service
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=simple
|
|
||||||
User=ids
|
|
||||||
Group=ids
|
|
||||||
WorkingDirectory=/opt/ids
|
|
||||||
EnvironmentFile=/opt/ids/.env
|
|
||||||
Environment=NODE_ENV=production
|
|
||||||
Environment=PORT=5000
|
|
||||||
Environment=PATH=/usr/local/bin:/usr/bin:/bin
|
|
||||||
|
|
||||||
ExecStartPre=/bin/bash -c 'test -f /opt/ids/dist/index.js || (echo "ERRORE: dist/index.js non trovato - eseguire npm run build" && exit 1)'
|
|
||||||
ExecStart=/usr/bin/env node dist/index.js
|
|
||||||
|
|
||||||
Restart=always
|
|
||||||
RestartSec=5
|
|
||||||
StartLimitInterval=300
|
|
||||||
StartLimitBurst=10
|
|
||||||
|
|
||||||
LimitNOFILE=65536
|
|
||||||
MemoryMax=1G
|
|
||||||
|
|
||||||
StandardOutput=append:/var/log/ids/backend.log
|
|
||||||
StandardError=append:/var/log/ids/backend.log
|
|
||||||
SyslogIdentifier=ids-backend
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
@ -3,92 +3,59 @@
|
|||||||
IDS Auto-Blocking Script
|
IDS Auto-Blocking Script
|
||||||
Rileva e blocca automaticamente IP con risk_score >= 80
|
Rileva e blocca automaticamente IP con risk_score >= 80
|
||||||
Eseguito periodicamente da systemd timer (ogni 5 minuti)
|
Eseguito periodicamente da systemd timer (ogni 5 minuti)
|
||||||
|
|
||||||
Flusso:
|
|
||||||
1. Chiama Node.js /api/ml/detect per eseguire detection ML
|
|
||||||
2. Chiama Node.js /api/ml/block-all-critical per bloccare IP critici sui router
|
|
||||||
"""
|
"""
|
||||||
import requests
|
import requests
|
||||||
import sys
|
import sys
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
NODE_API_URL = "http://localhost:5000"
|
|
||||||
ML_API_URL = "http://localhost:8000"
|
ML_API_URL = "http://localhost:8000"
|
||||||
|
|
||||||
def auto_block():
|
def auto_block():
|
||||||
"""Esegue detection e blocking automatico degli IP critici"""
|
"""Esegue detection e blocking automatico degli IP critici"""
|
||||||
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||||
print(f"[{timestamp}] Starting auto-block cycle...")
|
print(f"[{timestamp}] 🔍 Starting auto-block detection...")
|
||||||
|
|
||||||
# Step 1: Esegui detection via ML Backend (se disponibile)
|
|
||||||
try:
|
try:
|
||||||
print(f"[{timestamp}] Step 1: Detection ML...")
|
# Chiama endpoint ML /detect con auto_block=true
|
||||||
response = requests.post(
|
response = requests.post(
|
||||||
f"{ML_API_URL}/detect",
|
f"{ML_API_URL}/detect",
|
||||||
json={
|
json={
|
||||||
"max_records": 50000,
|
"max_records": 5000, # Analizza ultimi 5000 log
|
||||||
"hours_back": 1.0,
|
"hours_back": 1.0, # Ultima ora
|
||||||
"risk_threshold": 75.0,
|
"risk_threshold": 80.0, # Solo IP critici (score >= 80)
|
||||||
"auto_block": False
|
"auto_block": True # BLOCCA AUTOMATICAMENTE
|
||||||
},
|
},
|
||||||
timeout=120
|
timeout=120 # 2 minuti timeout
|
||||||
)
|
)
|
||||||
|
|
||||||
if response.status_code == 200:
|
if response.status_code == 200:
|
||||||
data = response.json()
|
data = response.json()
|
||||||
detections = len(data.get("detections", []))
|
detections = len(data.get("detections", []))
|
||||||
print(f"[{timestamp}] Detection completata: {detections} anomalie rilevate")
|
|
||||||
else:
|
|
||||||
print(f"[{timestamp}] Detection API error: HTTP {response.status_code}")
|
|
||||||
|
|
||||||
except requests.exceptions.ConnectionError:
|
|
||||||
print(f"[{timestamp}] ML Backend non raggiungibile, skip detection (blocco IP esistenti continua)")
|
|
||||||
except requests.exceptions.Timeout:
|
|
||||||
print(f"[{timestamp}] ML Detection timeout, skip (blocco IP esistenti continua)")
|
|
||||||
except Exception as e:
|
|
||||||
print(f"[{timestamp}] Detection error: {e}")
|
|
||||||
|
|
||||||
# Step 2: Blocca IP critici (score >= 80) via Node.js
|
|
||||||
try:
|
|
||||||
print(f"[{timestamp}] Step 2: Blocco IP critici sui router...")
|
|
||||||
response = requests.post(
|
|
||||||
f"{NODE_API_URL}/api/ml/block-all-critical",
|
|
||||||
json={
|
|
||||||
"min_score": 80,
|
|
||||||
"limit": 200,
|
|
||||||
"list_name": "ddos_blocked"
|
|
||||||
},
|
|
||||||
timeout=300
|
|
||||||
)
|
|
||||||
|
|
||||||
if response.status_code == 200:
|
|
||||||
data = response.json()
|
|
||||||
blocked = data.get("blocked", 0)
|
blocked = data.get("blocked", 0)
|
||||||
failed = data.get("failed", 0)
|
|
||||||
skipped = data.get("skipped", 0)
|
|
||||||
remaining = data.get("remaining", 0)
|
|
||||||
|
|
||||||
if blocked > 0:
|
if blocked > 0:
|
||||||
print(f"[{timestamp}] {blocked} IP bloccati sui router, {failed} falliti, {skipped} gia' bloccati")
|
print(f"✓ Detection completata: {detections} anomalie rilevate, {blocked} IP bloccati")
|
||||||
else:
|
else:
|
||||||
print(f"[{timestamp}] Nessun nuovo IP da bloccare ({skipped} gia' bloccati)")
|
print(f"✓ Detection completata: {detections} anomalie rilevate, nessun nuovo IP da bloccare")
|
||||||
|
|
||||||
if remaining > 0:
|
|
||||||
print(f"[{timestamp}] Rimangono {remaining} IP critici da bloccare")
|
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
else:
|
else:
|
||||||
print(f"[{timestamp}] Block API error: HTTP {response.status_code} - {response.text[:200]}")
|
print(f"✗ API error: HTTP {response.status_code}")
|
||||||
|
print(f" Response: {response.text}")
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
except requests.exceptions.ConnectionError:
|
except requests.exceptions.ConnectionError:
|
||||||
print(f"[{timestamp}] ERRORE: Node.js backend non raggiungibile su {NODE_API_URL}")
|
print("✗ ERRORE: ML Backend non raggiungibile su http://localhost:8000")
|
||||||
|
print(" Verifica che ids-ml-backend.service sia attivo:")
|
||||||
|
print(" sudo systemctl status ids-ml-backend")
|
||||||
return 1
|
return 1
|
||||||
except requests.exceptions.Timeout:
|
except requests.exceptions.Timeout:
|
||||||
print(f"[{timestamp}] ERRORE: Timeout blocco IP (300s)")
|
print("✗ ERRORE: Timeout dopo 120 secondi. Detection troppo lenta?")
|
||||||
return 1
|
return 1
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"[{timestamp}] ERRORE imprevisto: {type(e).__name__}: {e}")
|
print(f"✗ ERRORE imprevisto: {type(e).__name__}: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
@ -1,5 +1,3 @@
|
|||||||
const VERBOSE = process.env.MIKROTIK_DEBUG === '1' || process.env.MIKROTIK_DEBUG === 'true';
|
|
||||||
|
|
||||||
interface RouterConfig {
|
interface RouterConfig {
|
||||||
id: string;
|
id: string;
|
||||||
ipAddress: string;
|
ipAddress: string;
|
||||||
@ -22,13 +20,12 @@ async function mikrotikRequest(
|
|||||||
method: string,
|
method: string,
|
||||||
path: string,
|
path: string,
|
||||||
body?: any,
|
body?: any,
|
||||||
timeoutMs: number = 8000
|
timeoutMs: number = 10000
|
||||||
): Promise<{ status: number; data: any }> {
|
): Promise<{ status: number; data: any }> {
|
||||||
const useHttps = router.apiPort === 443;
|
const useHttps = router.apiPort === 443;
|
||||||
const protocol = useHttps ? "https" : "http";
|
const protocol = useHttps ? "https" : "http";
|
||||||
const url = `${protocol}://${router.ipAddress}:${router.apiPort}${path}`;
|
const url = `${protocol}://${router.ipAddress}:${router.apiPort}${path}`;
|
||||||
const auth = Buffer.from(`${router.username}:${router.password}`).toString("base64");
|
const auth = Buffer.from(`${router.username}:${router.password}`).toString("base64");
|
||||||
const startTime = Date.now();
|
|
||||||
|
|
||||||
const origTlsReject = process.env.NODE_TLS_REJECT_UNAUTHORIZED;
|
const origTlsReject = process.env.NODE_TLS_REJECT_UNAUTHORIZED;
|
||||||
if (useHttps) {
|
if (useHttps) {
|
||||||
@ -63,24 +60,9 @@ async function mikrotikRequest(
|
|||||||
data = text;
|
data = text;
|
||||||
}
|
}
|
||||||
|
|
||||||
const elapsed = Date.now() - startTime;
|
|
||||||
if (VERBOSE) {
|
|
||||||
const bodyStr = body ? ` body=${JSON.stringify(body)}` : '';
|
|
||||||
const dataPreview = typeof data === 'string' ? data.substring(0, 200) : JSON.stringify(data).substring(0, 200);
|
|
||||||
console.log(`[MIKROTIK] ${method} ${url} => HTTP ${response.status} (${elapsed}ms)${bodyStr} response=${dataPreview}`);
|
|
||||||
} else if (response.status >= 400) {
|
|
||||||
const dataPreview = typeof data === 'string' ? data.substring(0, 100) : JSON.stringify(data).substring(0, 100);
|
|
||||||
console.warn(`[MIKROTIK] ${method} ${router.ipAddress}${path} => HTTP ${response.status} (${elapsed}ms) err=${dataPreview}`);
|
|
||||||
} else if (elapsed > 5000) {
|
|
||||||
console.warn(`[MIKROTIK] SLOW: ${method} ${router.ipAddress}${path} => HTTP ${response.status} (${elapsed}ms)`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return { status: response.status, data };
|
return { status: response.status, data };
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
const elapsed = Date.now() - startTime;
|
|
||||||
const errMsg = error.name === 'AbortError' ? `TIMEOUT after ${timeoutMs}ms` : error.message;
|
|
||||||
console.error(`[MIKROTIK] ${method} ${url} => ERRORE: ${errMsg} (${elapsed}ms)`);
|
|
||||||
if (useHttps && origTlsReject !== undefined) {
|
if (useHttps && origTlsReject !== undefined) {
|
||||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = origTlsReject;
|
process.env.NODE_TLS_REJECT_UNAUTHORIZED = origTlsReject;
|
||||||
} else if (useHttps) {
|
} else if (useHttps) {
|
||||||
@ -112,26 +94,19 @@ export async function getExistingBlockedIps(
|
|||||||
listName: string = "ddos_blocked"
|
listName: string = "ddos_blocked"
|
||||||
): Promise<Set<string>> {
|
): Promise<Set<string>> {
|
||||||
try {
|
try {
|
||||||
if (VERBOSE) console.log(`[MIKROTIK] Fetching address-list da router ${router.ipAddress} (list=${listName}, timeout=20s)...`);
|
|
||||||
const { status, data } = await mikrotikRequest(router, "GET", "/rest/ip/firewall/address-list", undefined, 20000);
|
const { status, data } = await mikrotikRequest(router, "GET", "/rest/ip/firewall/address-list", undefined, 20000);
|
||||||
if (status === 200 && Array.isArray(data)) {
|
if (status === 200 && Array.isArray(data)) {
|
||||||
const ips = new Set<string>();
|
const ips = new Set<string>();
|
||||||
const allLists = new Map<string, number>();
|
|
||||||
for (const entry of data) {
|
for (const entry of data) {
|
||||||
const count = allLists.get(entry.list) || 0;
|
|
||||||
allLists.set(entry.list, count + 1);
|
|
||||||
if (entry.list === listName) {
|
if (entry.list === listName) {
|
||||||
ips.add(entry.address);
|
ips.add(entry.address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const listsInfo = Array.from(allLists.entries()).map(([name, count]) => `${name}:${count}`).join(', ');
|
|
||||||
console.log(`[MIKROTIK] Router ${router.ipAddress}: ${data.length} entries totali (${listsInfo}), ${ips.size} in list "${listName}"`);
|
|
||||||
return ips;
|
return ips;
|
||||||
}
|
}
|
||||||
console.warn(`[MIKROTIK] Router ${router.ipAddress}: risposta inattesa status=${status}, data non e' array`);
|
|
||||||
return new Set();
|
return new Set();
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
console.error(`[MIKROTIK] Router ${router.ipAddress}: ERRORE fetch address-list: ${e.message}`);
|
console.error(`[MIKROTIK] Failed to get address-list from ${router.ipAddress}: ${e.message}`);
|
||||||
return new Set();
|
return new Set();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -152,53 +127,41 @@ export async function addToAddressList(
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (status === 200 || status === 201) {
|
if (status === 200 || status === 201) {
|
||||||
if (VERBOSE) console.log(`[BLOCK] OK: ${ipAddress} aggiunto su router ${router.ipAddress} (HTTP ${status})`);
|
|
||||||
return { routerIp: router.ipAddress, success: true };
|
return { routerIp: router.ipAddress, success: true };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status === 400 || status === 409) {
|
if (status === 400 || status === 409) {
|
||||||
const text = typeof data === "string" ? data.toLowerCase() : JSON.stringify(data).toLowerCase();
|
const text = typeof data === "string" ? data.toLowerCase() : JSON.stringify(data).toLowerCase();
|
||||||
if (text.includes("already") || text.includes("exists") || text.includes("duplicate") || text.includes("failure: already")) {
|
if (text.includes("already") || text.includes("exists") || text.includes("duplicate") || text.includes("failure: already")) {
|
||||||
if (VERBOSE) console.log(`[BLOCK] SKIP: ${ipAddress} gia' presente su router ${router.ipAddress} (HTTP ${status})`);
|
|
||||||
return { routerIp: router.ipAddress, success: true, alreadyExists: true };
|
return { routerIp: router.ipAddress, success: true, alreadyExists: true };
|
||||||
}
|
}
|
||||||
console.warn(`[BLOCK] VERIFICA: ${ipAddress} su router ${router.ipAddress} HTTP ${status} risposta="${text.substring(0, 150)}", verifico lista...`);
|
|
||||||
try {
|
try {
|
||||||
const verifyResult = await mikrotikRequest(router, "GET", "/rest/ip/firewall/address-list");
|
const verifyResult = await mikrotikRequest(router, "GET", "/rest/ip/firewall/address-list");
|
||||||
if (verifyResult.status === 200 && Array.isArray(verifyResult.data)) {
|
if (verifyResult.status === 200 && Array.isArray(verifyResult.data)) {
|
||||||
for (const entry of verifyResult.data) {
|
for (const entry of verifyResult.data) {
|
||||||
if (entry.address === ipAddress && entry.list === listName) {
|
if (entry.address === ipAddress && entry.list === listName) {
|
||||||
console.log(`[BLOCK] CONFERMATO: ${ipAddress} trovato nella lista di router ${router.ipAddress} dopo verifica`);
|
|
||||||
return { routerIp: router.ipAddress, success: true, alreadyExists: true };
|
return { routerIp: router.ipAddress, success: true, alreadyExists: true };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (verifyErr: any) {
|
} catch {}
|
||||||
console.error(`[BLOCK] ERRORE verifica: ${ipAddress} su router ${router.ipAddress}: ${verifyErr.message}`);
|
|
||||||
}
|
|
||||||
const errMsg = `HTTP ${status}: ${typeof data === "string" ? data : JSON.stringify(data)}`;
|
|
||||||
console.error(`[BLOCK] FALLITO: ${ipAddress} su router ${router.ipAddress}: ${errMsg}`);
|
|
||||||
return {
|
return {
|
||||||
routerIp: router.ipAddress,
|
routerIp: router.ipAddress,
|
||||||
success: false,
|
success: false,
|
||||||
error: errMsg,
|
error: `HTTP ${status}: ${typeof data === "string" ? data : JSON.stringify(data)}`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const errMsg = `HTTP ${status}: ${typeof data === "string" ? data : JSON.stringify(data)}`;
|
|
||||||
console.error(`[BLOCK] FALLITO: ${ipAddress} su router ${router.ipAddress}: ${errMsg}`);
|
|
||||||
return {
|
return {
|
||||||
routerIp: router.ipAddress,
|
routerIp: router.ipAddress,
|
||||||
success: false,
|
success: false,
|
||||||
error: errMsg,
|
error: `HTTP ${status}: ${typeof data === "string" ? data : JSON.stringify(data)}`,
|
||||||
};
|
};
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
const errMsg = error.name === 'AbortError' ? `TIMEOUT (8s)` : (error.message || "Connection failed");
|
|
||||||
console.error(`[BLOCK] ERRORE: ${ipAddress} su router ${router.ipAddress}: ${errMsg}`);
|
|
||||||
return {
|
return {
|
||||||
routerIp: router.ipAddress,
|
routerIp: router.ipAddress,
|
||||||
success: false,
|
success: false,
|
||||||
error: errMsg,
|
error: error.message || "Connection failed",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -209,10 +172,8 @@ export async function removeFromAddressList(
|
|||||||
listName: string = "ddos_blocked"
|
listName: string = "ddos_blocked"
|
||||||
): Promise<BlockResult> {
|
): Promise<BlockResult> {
|
||||||
try {
|
try {
|
||||||
if (VERBOSE) console.log(`[UNBLOCK] Rimozione ${ipAddress} da router ${router.ipAddress} (list=${listName})...`);
|
|
||||||
const { status, data } = await mikrotikRequest(router, "GET", "/rest/ip/firewall/address-list");
|
const { status, data } = await mikrotikRequest(router, "GET", "/rest/ip/firewall/address-list");
|
||||||
if (status !== 200 || !Array.isArray(data)) {
|
if (status !== 200 || !Array.isArray(data)) {
|
||||||
console.error(`[UNBLOCK] ERRORE: impossibile leggere address-list da router ${router.ipAddress}: HTTP ${status}`);
|
|
||||||
return { routerIp: router.ipAddress, success: false, error: "Failed to read address list" };
|
return { routerIp: router.ipAddress, success: false, error: "Failed to read address list" };
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,18 +182,14 @@ export async function removeFromAddressList(
|
|||||||
const entryId = entry[".id"];
|
const entryId = entry[".id"];
|
||||||
const delResult = await mikrotikRequest(router, "DELETE", `/rest/ip/firewall/address-list/${entryId}`);
|
const delResult = await mikrotikRequest(router, "DELETE", `/rest/ip/firewall/address-list/${entryId}`);
|
||||||
if (delResult.status === 200 || delResult.status === 204) {
|
if (delResult.status === 200 || delResult.status === 204) {
|
||||||
console.log(`[UNBLOCK] OK: ${ipAddress} rimosso da router ${router.ipAddress}`);
|
|
||||||
return { routerIp: router.ipAddress, success: true };
|
return { routerIp: router.ipAddress, success: true };
|
||||||
}
|
}
|
||||||
console.error(`[UNBLOCK] FALLITO: eliminazione ${ipAddress} da router ${router.ipAddress}: HTTP ${delResult.status}`);
|
|
||||||
return { routerIp: router.ipAddress, success: false, error: `Delete failed: ${delResult.status}` };
|
return { routerIp: router.ipAddress, success: false, error: `Delete failed: ${delResult.status}` };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (VERBOSE) console.log(`[UNBLOCK] ${ipAddress} non trovato su router ${router.ipAddress} (gia' assente)`);
|
|
||||||
return { routerIp: router.ipAddress, success: true };
|
return { routerIp: router.ipAddress, success: true };
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error(`[UNBLOCK] ERRORE: ${ipAddress} su router ${router.ipAddress}: ${error.message}`);
|
|
||||||
return { routerIp: router.ipAddress, success: false, error: error.message };
|
return { routerIp: router.ipAddress, success: false, error: error.message };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -282,21 +239,14 @@ export async function bulkBlockIps(
|
|||||||
return { blocked: 0, failed: 0, skipped: 0, details: [] };
|
return { blocked: 0, failed: 0, skipped: 0, details: [] };
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`[BULK-BLOCK] Starting: ${ipList.length} IPs on ${enabled.length} routers (${enabled.map(r => r.ipAddress).join(', ')})`);
|
console.log(`[BULK-BLOCK] Starting: ${ipList.length} IPs on ${enabled.length} routers`);
|
||||||
|
|
||||||
const routerStatus = new Map<string, { ok: number; fail: number; skip: number }>();
|
|
||||||
for (const r of enabled) {
|
|
||||||
routerStatus.set(r.ipAddress, { ok: 0, fail: 0, skip: 0 });
|
|
||||||
}
|
|
||||||
|
|
||||||
const existingCache = new Map<string, Set<string>>();
|
const existingCache = new Map<string, Set<string>>();
|
||||||
await Promise.allSettled(
|
await Promise.allSettled(
|
||||||
enabled.map(async (router) => {
|
enabled.map(async (router) => {
|
||||||
const start = Date.now();
|
|
||||||
const existing = await getExistingBlockedIps(router, listName);
|
const existing = await getExistingBlockedIps(router, listName);
|
||||||
const elapsed = Date.now() - start;
|
|
||||||
existingCache.set(router.ipAddress, existing);
|
existingCache.set(router.ipAddress, existing);
|
||||||
console.log(`[BULK-BLOCK] Router ${router.ipAddress}: ${existing.size} IPs already in list (${elapsed}ms)`);
|
console.log(`[BULK-BLOCK] Router ${router.ipAddress}: ${existing.size} IPs already in list`);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -324,72 +274,36 @@ export async function bulkBlockIps(
|
|||||||
let blocked = 0;
|
let blocked = 0;
|
||||||
let failed = 0;
|
let failed = 0;
|
||||||
const details: Array<{ ip: string; status: string }> = [];
|
const details: Array<{ ip: string; status: string }> = [];
|
||||||
const partialIps: string[] = [];
|
|
||||||
const failedIps: string[] = [];
|
|
||||||
|
|
||||||
async function processIp(ip: string) {
|
async function processIp(ip: string) {
|
||||||
const routerResults = await Promise.allSettled(
|
const routerResults = await Promise.allSettled(
|
||||||
enabled.map(async (router) => {
|
enabled.map(async (router) => {
|
||||||
const existing = existingCache.get(router.ipAddress) || new Set();
|
const existing = existingCache.get(router.ipAddress) || new Set();
|
||||||
if (existing.has(ip)) {
|
if (existing.has(ip)) return true;
|
||||||
const st = routerStatus.get(router.ipAddress);
|
|
||||||
if (st) st.skip++;
|
|
||||||
return { success: true, skipped: true, routerIp: router.ipAddress };
|
|
||||||
}
|
|
||||||
const start = Date.now();
|
|
||||||
const result = await addToAddressList(router, ip, listName, `${commentPrefix} ${ip}`, timeoutDuration);
|
const result = await addToAddressList(router, ip, listName, `${commentPrefix} ${ip}`, timeoutDuration);
|
||||||
const elapsed = Date.now() - start;
|
return result.success;
|
||||||
const st = routerStatus.get(router.ipAddress);
|
|
||||||
if (result.success) {
|
|
||||||
if (st) st.ok++;
|
|
||||||
} else {
|
|
||||||
if (st) st.fail++;
|
|
||||||
}
|
|
||||||
return { success: result.success, skipped: false, routerIp: router.ipAddress, elapsed, error: result.error };
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const perRouterDetail = routerResults.map((r) => {
|
|
||||||
if (r.status === 'fulfilled') {
|
|
||||||
const v = r.value;
|
|
||||||
if (v.skipped) return `${v.routerIp}:SKIP`;
|
|
||||||
if (v.success) return `${v.routerIp}:OK(${v.elapsed}ms)`;
|
|
||||||
return `${v.routerIp}:FAIL(${v.elapsed}ms,${v.error})`;
|
|
||||||
}
|
|
||||||
return 'REJECTED';
|
|
||||||
}).join(' | ');
|
|
||||||
|
|
||||||
const anySuccess = routerResults.some(
|
const anySuccess = routerResults.some(
|
||||||
(r) => r.status === "fulfilled" && r.value.success
|
(r) => r.status === "fulfilled" && r.value === true
|
||||||
);
|
|
||||||
const allSuccess = routerResults.every(
|
|
||||||
(r) => r.status === "fulfilled" && r.value.success
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (anySuccess) {
|
if (anySuccess) {
|
||||||
blocked++;
|
blocked++;
|
||||||
details.push({ ip, status: "blocked" });
|
details.push({ ip, status: "blocked" });
|
||||||
if (!allSuccess) {
|
|
||||||
partialIps.push(ip);
|
|
||||||
if (VERBOSE) console.warn(`[BULK-BLOCK] PARZIALE: IP ${ip}: ${perRouterDetail}`);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
failed++;
|
failed++;
|
||||||
failedIps.push(ip);
|
|
||||||
details.push({ ip, status: "failed" });
|
details.push({ ip, status: "failed" });
|
||||||
if (VERBOSE) console.error(`[BULK-BLOCK] FALLITO: IP ${ip}: ${perRouterDetail}`);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const bulkStart = Date.now();
|
|
||||||
for (let i = 0; i < newIps.length; i += concurrency) {
|
for (let i = 0; i < newIps.length; i += concurrency) {
|
||||||
const batch = newIps.slice(i, i + concurrency);
|
const batch = newIps.slice(i, i + concurrency);
|
||||||
await Promise.allSettled(batch.map((ip) => processIp(ip)));
|
await Promise.allSettled(batch.map((ip) => processIp(ip)));
|
||||||
|
|
||||||
const progress = Math.min(i + concurrency, newIps.length);
|
if ((i + concurrency) % 50 === 0 || i + concurrency >= newIps.length) {
|
||||||
if (progress === newIps.length || progress % 50 === 0) {
|
console.log(`[BULK-BLOCK] Progress: ${Math.min(i + concurrency, newIps.length)}/${newIps.length}`);
|
||||||
const elapsed = ((Date.now() - bulkStart) / 1000).toFixed(1);
|
|
||||||
console.log(`[BULK-BLOCK] Progress: ${progress}/${newIps.length} (${elapsed}s, ${blocked} ok, ${failed} fail)`);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -397,17 +311,7 @@ export async function bulkBlockIps(
|
|||||||
details.push({ ip, status: "already_blocked" });
|
details.push({ ip, status: "already_blocked" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const totalElapsed = ((Date.now() - bulkStart) / 1000).toFixed(1);
|
console.log(`[BULK-BLOCK] Done: ${blocked} blocked, ${failed} failed, ${skippedIps.length} skipped`);
|
||||||
routerStatus.forEach((st, routerIp) => {
|
|
||||||
console.log(`[BULK-BLOCK] Router ${routerIp}: ${st.ok} blocked, ${st.fail} failed, ${st.skip} skipped`);
|
|
||||||
});
|
|
||||||
console.log(`[BULK-BLOCK] Completato in ${totalElapsed}s: ${blocked} blocked, ${failed} failed, ${skippedIps.length} already_blocked, ${partialIps.length} parziali`);
|
|
||||||
if (failedIps.length > 0) {
|
|
||||||
console.error(`[BULK-BLOCK] IP non bloccati su nessun router (${failedIps.length}): ${failedIps.slice(0, 20).join(', ')}${failedIps.length > 20 ? '...' : ''}`);
|
|
||||||
}
|
|
||||||
if (partialIps.length > 0) {
|
|
||||||
console.warn(`[BULK-BLOCK] IP bloccati solo parzialmente (${partialIps.length}): ${partialIps.slice(0, 20).join(', ')}${partialIps.length > 20 ? '...' : ''}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return { blocked, failed, skipped: skippedIps.length, details };
|
return { blocked, failed, skipped: skippedIps.length, details };
|
||||||
}
|
}
|
||||||
|
|||||||
202
server/routes.ts
202
server/routes.ts
@ -672,8 +672,7 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ipList = rows.map((r: any) => r.source_ip);
|
const ipList = rows.map((r: any) => r.source_ip);
|
||||||
const routerInfo = enabledRouters.map((r: any) => `${r.name || r.ipAddress}(${r.ipAddress}:${r.apiPort})`).join(', ');
|
console.log(`[BLOCK-ALL] Avvio blocco massivo: ${ipList.length}/${totalUnblocked} IP con score >= ${min_score} su ${enabledRouters.length} router`);
|
||||||
console.log(`[BLOCK-ALL] Avvio blocco massivo: ${ipList.length}/${totalUnblocked} IP con score >= ${min_score} su ${enabledRouters.length} router: ${routerInfo}`);
|
|
||||||
|
|
||||||
const result = await bulkBlockIps(
|
const result = await bulkBlockIps(
|
||||||
enabledRouters as any,
|
enabledRouters as any,
|
||||||
@ -780,43 +779,39 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
|||||||
// Services monitoring
|
// Services monitoring
|
||||||
app.get("/api/services/status", async (req, res) => {
|
app.get("/api/services/status", async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const mkService = (name: string) => ({ name, status: "unknown" as string, healthy: false, details: null as any, systemdUnit: "" as string, type: "service" as string });
|
|
||||||
|
|
||||||
const services = {
|
const services = {
|
||||||
nodeBackend: { ...mkService("Node.js Backend"), systemdUnit: "ids-backend", type: "service" },
|
mlBackend: { name: "ML Backend Python", status: "unknown", healthy: false, details: null as any },
|
||||||
mlBackend: { ...mkService("ML Backend Python"), systemdUnit: "ids-ml-backend", type: "service" },
|
database: { name: "PostgreSQL Database", status: "unknown", healthy: false, details: null as any },
|
||||||
database: { ...mkService("PostgreSQL Database"), systemdUnit: "postgresql-16", type: "service" },
|
syslogParser: { name: "Syslog Parser", status: "unknown", healthy: false, details: null as any },
|
||||||
syslogParser: { ...mkService("Syslog Parser"), systemdUnit: "ids-syslog-parser", type: "service" },
|
analyticsAggregator: { name: "Analytics Aggregator Timer", status: "unknown", healthy: false, details: null as any },
|
||||||
analyticsAggregator: { ...mkService("Analytics Aggregator"), systemdUnit: "ids-analytics-aggregator", type: "timer" },
|
|
||||||
autoBlock: { ...mkService("Auto Block"), systemdUnit: "ids-auto-block", type: "timer" },
|
|
||||||
cleanup: { ...mkService("Cleanup Detections"), systemdUnit: "ids-cleanup", type: "timer" },
|
|
||||||
listFetcher: { ...mkService("Public Lists Fetcher"), systemdUnit: "ids-list-fetcher", type: "timer" },
|
|
||||||
mlTraining: { ...mkService("ML Training Settimanale"), systemdUnit: "ids-ml-training", type: "timer" },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Node.js Backend - always running if this endpoint responds
|
|
||||||
services.nodeBackend.status = "running";
|
|
||||||
services.nodeBackend.healthy = true;
|
|
||||||
services.nodeBackend.details = { port: 5000, uptime: process.uptime().toFixed(0) + "s" };
|
|
||||||
|
|
||||||
// Check ML Backend Python
|
// Check ML Backend Python
|
||||||
try {
|
try {
|
||||||
const controller = new AbortController();
|
const controller = new AbortController();
|
||||||
const timeout = setTimeout(() => controller.abort(), 5000);
|
const timeout = setTimeout(() => controller.abort(), 5000);
|
||||||
const response = await fetch(`${ML_BACKEND_URL}/health`, { signal: controller.signal });
|
|
||||||
|
const response = await fetch(`${ML_BACKEND_URL}/health`, {
|
||||||
|
signal: controller.signal,
|
||||||
|
});
|
||||||
|
|
||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
services.mlBackend.status = "running";
|
services.mlBackend.status = "running";
|
||||||
services.mlBackend.healthy = true;
|
services.mlBackend.healthy = true;
|
||||||
services.mlBackend.details = { modelLoaded: data.ml_model === "loaded", timestamp: data.timestamp };
|
services.mlBackend.details = {
|
||||||
|
modelLoaded: data.ml_model === "loaded",
|
||||||
|
timestamp: data.timestamp,
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
services.mlBackend.status = "error";
|
services.mlBackend.status = "error";
|
||||||
services.mlBackend.details = { error: `HTTP ${response.status}` };
|
services.mlBackend.details = { error: `HTTP ${response.status}` };
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
services.mlBackend.status = "offline";
|
services.mlBackend.status = "offline";
|
||||||
services.mlBackend.details = { error: error.code === 'ECONNREFUSED' ? "Connessione rifiutata" : error.message };
|
services.mlBackend.details = { error: error.code === 'ECONNREFUSED' ? "Connection refused" : error.message };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check Database
|
// Check Database
|
||||||
@ -832,156 +827,87 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
|||||||
services.database.details = { error: error.message };
|
services.database.details = { error: error.message };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check Syslog Parser via database
|
// Check Syslog Parser via database (independent of ML Backend)
|
||||||
try {
|
try {
|
||||||
const recentLogsResult = await db.execute(
|
const recentLogsResult = await db.execute(
|
||||||
sql`SELECT COUNT(*) as count, MAX(timestamp) as last_log FROM network_logs WHERE timestamp > NOW() - INTERVAL '30 minutes'`
|
sql`SELECT COUNT(*) as count, MAX(timestamp) as last_log
|
||||||
|
FROM network_logs
|
||||||
|
WHERE timestamp > NOW() - INTERVAL '30 minutes'`
|
||||||
);
|
);
|
||||||
const logRows = (recentLogsResult as any).rows || recentLogsResult;
|
const logRows = (recentLogsResult as any).rows || recentLogsResult;
|
||||||
const recentLogCount = parseInt(logRows[0]?.count || "0");
|
const recentLogCount = parseInt(logRows[0]?.count || "0");
|
||||||
const lastLogTime = logRows[0]?.last_log;
|
const lastLogTime = logRows[0]?.last_log;
|
||||||
|
|
||||||
if (recentLogCount > 0) {
|
if (recentLogCount > 0) {
|
||||||
services.syslogParser.status = "running";
|
services.syslogParser.status = "running";
|
||||||
services.syslogParser.healthy = true;
|
services.syslogParser.healthy = true;
|
||||||
services.syslogParser.details = { recentLogs30min: recentLogCount, lastLog: lastLogTime };
|
services.syslogParser.details = {
|
||||||
|
recentLogs30min: recentLogCount,
|
||||||
|
lastLog: lastLogTime,
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
const lastLogEverResult = await db.execute(sql`SELECT MAX(timestamp) as last_log FROM network_logs`);
|
const lastLogEverResult = await db.execute(
|
||||||
|
sql`SELECT MAX(timestamp) as last_log FROM network_logs`
|
||||||
|
);
|
||||||
const lastLogEverRows = (lastLogEverResult as any).rows || lastLogEverResult;
|
const lastLogEverRows = (lastLogEverResult as any).rows || lastLogEverResult;
|
||||||
|
const lastLogEver = lastLogEverRows[0]?.last_log;
|
||||||
|
|
||||||
services.syslogParser.status = "offline";
|
services.syslogParser.status = "offline";
|
||||||
services.syslogParser.healthy = false;
|
services.syslogParser.healthy = false;
|
||||||
services.syslogParser.details = { recentLogs30min: 0, lastLog: lastLogEverRows[0]?.last_log || "Mai", warning: "Nessun log negli ultimi 30 minuti" };
|
services.syslogParser.details = {
|
||||||
|
recentLogs30min: 0,
|
||||||
|
lastLog: lastLogEver || "Never",
|
||||||
|
warning: "No logs received in last 30 minutes",
|
||||||
|
};
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
services.syslogParser.status = "error";
|
services.syslogParser.status = "error";
|
||||||
|
services.syslogParser.healthy = false;
|
||||||
services.syslogParser.details = { error: error.message };
|
services.syslogParser.details = { error: error.message };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check Analytics Aggregator (via last record timestamp)
|
// Check Analytics Aggregator (via last record timestamp)
|
||||||
try {
|
try {
|
||||||
const latestAnalytics = await db.select().from(networkAnalytics).orderBy(desc(networkAnalytics.date), desc(networkAnalytics.hour)).limit(1);
|
const latestAnalytics = await db
|
||||||
|
.select()
|
||||||
|
.from(networkAnalytics)
|
||||||
|
.orderBy(desc(networkAnalytics.date), desc(networkAnalytics.hour))
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
if (latestAnalytics.length > 0) {
|
if (latestAnalytics.length > 0) {
|
||||||
const lastRun = new Date(latestAnalytics[0].date);
|
const lastRun = new Date(latestAnalytics[0].date);
|
||||||
const hoursSince = (Date.now() - lastRun.getTime()) / (1000 * 60 * 60);
|
const lastTimestamp = lastRun.toISOString();
|
||||||
if (hoursSince < 2) {
|
const hoursSinceLastRun = (Date.now() - lastRun.getTime()) / (1000 * 60 * 60);
|
||||||
|
|
||||||
|
if (hoursSinceLastRun < 2) {
|
||||||
services.analyticsAggregator.status = "running";
|
services.analyticsAggregator.status = "running";
|
||||||
services.analyticsAggregator.healthy = true;
|
services.analyticsAggregator.healthy = true;
|
||||||
services.analyticsAggregator.details = { lastRun: latestAnalytics[0].date, hoursSinceLastRun: hoursSince.toFixed(1) };
|
services.analyticsAggregator.details = {
|
||||||
|
lastRun: latestAnalytics[0].date,
|
||||||
|
lastTimestamp,
|
||||||
|
hoursSinceLastRun: hoursSinceLastRun.toFixed(1),
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
services.analyticsAggregator.status = "idle";
|
services.analyticsAggregator.status = "idle";
|
||||||
services.analyticsAggregator.details = { lastRun: latestAnalytics[0].date, hoursSinceLastRun: hoursSince.toFixed(1), warning: "Nessuna aggregazione nelle ultime 2 ore" };
|
services.analyticsAggregator.healthy = false;
|
||||||
|
services.analyticsAggregator.details = {
|
||||||
|
lastRun: latestAnalytics[0].date,
|
||||||
|
lastTimestamp,
|
||||||
|
hoursSinceLastRun: hoursSinceLastRun.toFixed(1),
|
||||||
|
warning: "No aggregation in last 2 hours",
|
||||||
|
};
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
services.analyticsAggregator.status = "idle";
|
services.analyticsAggregator.status = "idle";
|
||||||
services.analyticsAggregator.details = { error: "Nessun dato analytics trovato" };
|
services.analyticsAggregator.healthy = false;
|
||||||
|
services.analyticsAggregator.details = { error: "No analytics data found" };
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
services.analyticsAggregator.status = "error";
|
services.analyticsAggregator.status = "error";
|
||||||
|
services.analyticsAggregator.healthy = false;
|
||||||
services.analyticsAggregator.details = { error: error.message };
|
services.analyticsAggregator.details = { error: error.message };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check Auto Block (via recent blocked detections)
|
|
||||||
try {
|
|
||||||
const recentBlockResult = await db.execute(
|
|
||||||
sql`SELECT COUNT(*) as count, MAX(detected_at) as last_block FROM detections WHERE blocked = true AND detected_at > NOW() - INTERVAL '10 minutes'`
|
|
||||||
);
|
|
||||||
const blockRows = (recentBlockResult as any).rows || recentBlockResult;
|
|
||||||
const recentBlocks = parseInt(blockRows[0]?.count || "0");
|
|
||||||
const lastBlock = blockRows[0]?.last_block;
|
|
||||||
|
|
||||||
const totalBlockedResult = await db.execute(sql`SELECT COUNT(*) as count FROM detections WHERE blocked = true`);
|
|
||||||
const totalBlockedRows = (totalBlockedResult as any).rows || totalBlockedResult;
|
|
||||||
const totalBlocked = parseInt(totalBlockedRows[0]?.count || "0");
|
|
||||||
|
|
||||||
services.autoBlock.status = recentBlocks > 0 ? "running" : "idle";
|
|
||||||
services.autoBlock.healthy = true;
|
|
||||||
services.autoBlock.details = {
|
|
||||||
recentBlocks10min: recentBlocks,
|
|
||||||
totalBlocked,
|
|
||||||
lastBlock: lastBlock || "Mai",
|
|
||||||
interval: "ogni 5 minuti"
|
|
||||||
};
|
|
||||||
} catch (error: any) {
|
|
||||||
services.autoBlock.status = "error";
|
|
||||||
services.autoBlock.details = { error: error.message };
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check Cleanup (via absence of old detections)
|
|
||||||
try {
|
|
||||||
const oldDetResult = await db.execute(
|
|
||||||
sql`SELECT COUNT(*) as count FROM detections WHERE detected_at < NOW() - INTERVAL '48 hours'`
|
|
||||||
);
|
|
||||||
const oldRows = (oldDetResult as any).rows || oldDetResult;
|
|
||||||
const oldDetections = parseInt(oldRows[0]?.count || "0");
|
|
||||||
|
|
||||||
const totalDetResult = await db.execute(sql`SELECT COUNT(*) as count FROM detections`);
|
|
||||||
const totalRows = (totalDetResult as any).rows || totalDetResult;
|
|
||||||
const totalDetections = parseInt(totalRows[0]?.count || "0");
|
|
||||||
|
|
||||||
services.cleanup.status = oldDetections === 0 ? "running" : "idle";
|
|
||||||
services.cleanup.healthy = oldDetections === 0;
|
|
||||||
services.cleanup.details = {
|
|
||||||
oldDetections48h: oldDetections,
|
|
||||||
totalDetections,
|
|
||||||
interval: "ogni ora",
|
|
||||||
warning: oldDetections > 0 ? `${oldDetections} detection vecchie non ancora pulite` : undefined
|
|
||||||
};
|
|
||||||
} catch (error: any) {
|
|
||||||
services.cleanup.status = "error";
|
|
||||||
services.cleanup.details = { error: error.message };
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check List Fetcher (via public lists last_updated)
|
|
||||||
try {
|
|
||||||
const listsResult = await db.execute(
|
|
||||||
sql`SELECT COUNT(*) as total,
|
|
||||||
COUNT(*) FILTER (WHERE enabled = true) as enabled,
|
|
||||||
MAX(last_fetch) as last_fetch
|
|
||||||
FROM public_lists`
|
|
||||||
);
|
|
||||||
const listRows = (listsResult as any).rows || listsResult;
|
|
||||||
const totalLists = parseInt(listRows[0]?.total || "0");
|
|
||||||
const enabledLists = parseInt(listRows[0]?.enabled || "0");
|
|
||||||
const lastFetched = listRows[0]?.last_fetch;
|
|
||||||
|
|
||||||
if (lastFetched) {
|
|
||||||
const hoursSince = (Date.now() - new Date(lastFetched).getTime()) / (1000 * 60 * 60);
|
|
||||||
services.listFetcher.status = hoursSince < 1 ? "running" : "idle";
|
|
||||||
services.listFetcher.healthy = hoursSince < 1;
|
|
||||||
services.listFetcher.details = { totalLists, enabledLists, lastFetched, hoursSinceLastFetch: hoursSince.toFixed(1), interval: "ogni 10 minuti" };
|
|
||||||
} else {
|
|
||||||
services.listFetcher.status = "idle";
|
|
||||||
services.listFetcher.details = { totalLists, enabledLists, lastFetched: "Mai", interval: "ogni 10 minuti" };
|
|
||||||
}
|
|
||||||
} catch (error: any) {
|
|
||||||
services.listFetcher.status = "error";
|
|
||||||
services.listFetcher.details = { error: error.message };
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check ML Training (via training history)
|
|
||||||
try {
|
|
||||||
const latestTraining = await db.select().from(trainingHistory).orderBy(desc(trainingHistory.trainedAt)).limit(1);
|
|
||||||
if (latestTraining.length > 0) {
|
|
||||||
const lastTrainDate = new Date(latestTraining[0].trainedAt);
|
|
||||||
const daysSince = (Date.now() - lastTrainDate.getTime()) / (1000 * 60 * 60 * 24);
|
|
||||||
services.mlTraining.status = daysSince < 8 ? "running" : "idle";
|
|
||||||
services.mlTraining.healthy = daysSince < 8;
|
|
||||||
services.mlTraining.details = {
|
|
||||||
lastTraining: latestTraining[0].trainedAt,
|
|
||||||
daysSinceLastTraining: daysSince.toFixed(1),
|
|
||||||
lastStatus: latestTraining[0].status,
|
|
||||||
lastModel: latestTraining[0].modelVersion,
|
|
||||||
recordsProcessed: latestTraining[0].recordsProcessed,
|
|
||||||
interval: "settimanale"
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
services.mlTraining.status = "idle";
|
|
||||||
services.mlTraining.details = { lastTraining: "Mai", interval: "settimanale" };
|
|
||||||
}
|
|
||||||
} catch (error: any) {
|
|
||||||
services.mlTraining.status = "error";
|
|
||||||
services.mlTraining.details = { error: error.message };
|
|
||||||
}
|
|
||||||
|
|
||||||
res.json({ services });
|
res.json({ services });
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
res.status(500).json({ error: "Failed to check services status" });
|
res.status(500).json({ error: "Failed to check services status" });
|
||||||
@ -989,11 +915,7 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Service Control Endpoints (Secured - only allow specific systemd operations)
|
// Service Control Endpoints (Secured - only allow specific systemd operations)
|
||||||
const ALLOWED_SERVICES = [
|
const ALLOWED_SERVICES = ["ids-ml-backend", "ids-syslog-parser"];
|
||||||
"ids-ml-backend", "ids-syslog-parser", "ids-backend",
|
|
||||||
"ids-analytics-aggregator", "ids-auto-block", "ids-cleanup",
|
|
||||||
"ids-list-fetcher", "ids-ml-training"
|
|
||||||
];
|
|
||||||
const ALLOWED_ACTIONS = ["start", "stop", "restart", "status"];
|
const ALLOWED_ACTIONS = ["start", "stop", "restart", "status"];
|
||||||
|
|
||||||
app.post("/api/services/:service/:action", async (req, res) => {
|
app.post("/api/services/:service/:action", async (req, res) => {
|
||||||
|
|||||||
100
version.json
100
version.json
@ -1,55 +1,7 @@
|
|||||||
{
|
{
|
||||||
"version": "1.0.122",
|
"version": "1.0.114",
|
||||||
"lastUpdate": "2026-02-17T09:13:40.571Z",
|
"lastUpdate": "2026-02-16T11:54:24.557Z",
|
||||||
"changelog": [
|
"changelog": [
|
||||||
{
|
|
||||||
"version": "1.0.122",
|
|
||||||
"date": "2026-02-17",
|
|
||||||
"type": "patch",
|
|
||||||
"description": "Deployment automatico v1.0.122"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"version": "1.0.121",
|
|
||||||
"date": "2026-02-17",
|
|
||||||
"type": "patch",
|
|
||||||
"description": "Deployment automatico v1.0.121"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"version": "1.0.120",
|
|
||||||
"date": "2026-02-17",
|
|
||||||
"type": "patch",
|
|
||||||
"description": "Deployment automatico v1.0.120"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"version": "1.0.119",
|
|
||||||
"date": "2026-02-17",
|
|
||||||
"type": "patch",
|
|
||||||
"description": "Deployment automatico v1.0.119"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"version": "1.0.118",
|
|
||||||
"date": "2026-02-16",
|
|
||||||
"type": "patch",
|
|
||||||
"description": "Deployment automatico v1.0.118"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"version": "1.0.117",
|
|
||||||
"date": "2026-02-16",
|
|
||||||
"type": "patch",
|
|
||||||
"description": "Deployment automatico v1.0.117"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"version": "1.0.116",
|
|
||||||
"date": "2026-02-16",
|
|
||||||
"type": "patch",
|
|
||||||
"description": "Deployment automatico v1.0.116"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"version": "1.0.115",
|
|
||||||
"date": "2026-02-16",
|
|
||||||
"type": "patch",
|
|
||||||
"description": "Deployment automatico v1.0.115"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"version": "1.0.114",
|
"version": "1.0.114",
|
||||||
"date": "2026-02-16",
|
"date": "2026-02-16",
|
||||||
@ -301,6 +253,54 @@
|
|||||||
"date": "2025-11-25",
|
"date": "2025-11-25",
|
||||||
"type": "patch",
|
"type": "patch",
|
||||||
"description": "Deployment automatico v1.0.73"
|
"description": "Deployment automatico v1.0.73"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "1.0.72",
|
||||||
|
"date": "2025-11-25",
|
||||||
|
"type": "patch",
|
||||||
|
"description": "Deployment automatico v1.0.72"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "1.0.71",
|
||||||
|
"date": "2025-11-25",
|
||||||
|
"type": "patch",
|
||||||
|
"description": "Deployment automatico v1.0.71"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "1.0.70",
|
||||||
|
"date": "2025-11-25",
|
||||||
|
"type": "patch",
|
||||||
|
"description": "Deployment automatico v1.0.70"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "1.0.69",
|
||||||
|
"date": "2025-11-25",
|
||||||
|
"type": "patch",
|
||||||
|
"description": "Deployment automatico v1.0.69"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "1.0.68",
|
||||||
|
"date": "2025-11-24",
|
||||||
|
"type": "patch",
|
||||||
|
"description": "Deployment automatico v1.0.68"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "1.0.67",
|
||||||
|
"date": "2025-11-24",
|
||||||
|
"type": "patch",
|
||||||
|
"description": "Deployment automatico v1.0.67"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "1.0.66",
|
||||||
|
"date": "2025-11-24",
|
||||||
|
"type": "patch",
|
||||||
|
"description": "Deployment automatico v1.0.66"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "1.0.65",
|
||||||
|
"date": "2025-11-24",
|
||||||
|
"type": "patch",
|
||||||
|
"description": "Deployment automatico v1.0.65"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user