diff --git a/.replit b/.replit index 30bea15..d7f55b0 100644 --- a/.replit +++ b/.replit @@ -18,6 +18,10 @@ externalPort = 80 localPort = 41303 externalPort = 3002 +[[ports]] +localPort = 43447 +externalPort = 3001 + [[ports]] localPort = 43803 externalPort = 3000 diff --git a/attached_assets/Pasted-psql-DATABASE-URL-EOF-Conta-record-in-ogni-tabella-SELECT-network-logs-as-table-name-COU-1763743634660_1763743634660.txt b/attached_assets/Pasted-psql-DATABASE-URL-EOF-Conta-record-in-ogni-tabella-SELECT-network-logs-as-table-name-COU-1763743634660_1763743634660.txt new file mode 100644 index 0000000..7eed073 --- /dev/null +++ b/attached_assets/Pasted-psql-DATABASE-URL-EOF-Conta-record-in-ogni-tabella-SELECT-network-logs-as-table-name-COU-1763743634660_1763743634660.txt @@ -0,0 +1,121 @@ +psql $DATABASE_URL << 'EOF' +-- Conta record in ogni tabella +SELECT 'network_logs' as table_name, COUNT(*) as count FROM network_logs +UNION ALL +SELECT 'detections', COUNT(*) FROM detections +UNION ALL +SELECT 'training_history', COUNT(*) FROM training_history +UNION ALL +SELECT 'routers', COUNT(*) FROM routers +UNION ALL +SELECT 'whitelist', COUNT(*) FROM whitelist; + +-- Mostra ultimi 5 log di rete +SELECT timestamp, source_ip, destination_ip, protocol, router_name +FROM network_logs +ORDER BY timestamp DESC +LIMIT 5; + +-- Mostra training history +SELECT * FROM training_history ORDER BY trained_at DESC LIMIT 5; + +-- Mostra detections +SELECT * FROM detections ORDER BY detected_at DESC LIMIT 5; +EOF + table_name | count +------------------+------- + network_logs | 0 + detections | 0 + training_history | 0 + routers | 1 + whitelist | 0 +(5 rows) + + timestamp | source_ip | destination_ip | protocol | router_name +-----------+-----------+----------------+----------+------------- +(0 rows) + + id | model_version | records_processed | features_count | accuracy | training_duration | status | notes | trained_at +----+---------------+-------------------+----------------+----------+-------------------+--------+-------+------------ +(0 rows) + + id | source_ip | risk_score | confidence | anomaly_type | reason | log_count | first_seen | last_seen | blocked | blocked_at | detected_at +----+-----------+------------+------------+--------------+--------+-----------+------------+-----------+---------+------------+------------- +(0 rows) + +[root@ids ids]# curl -s http://localhost:8000/stats | jq . +{ + "logs": { + "total": 0, + "last_hour": 0 + }, + "detections": { + "total": 0, + "blocked": 0 + }, + "routers": { + "active": 1 + }, + "latest_training": null +} +[root@ids ids]# tail -50 /var/log/ids/syslog_parser.log +[ERROR] Errore salvataggio log: could not extend file "base/16384/16940.223": No space left on device +HINT: Check free disk space. + +[ERROR] Errore salvataggio log: could not extend file "base/16384/16940.223": No space left on device +HINT: Check free disk space. + +[ERROR] Errore salvataggio log: could not extend file "base/16384/16940.223": No space left on device +HINT: Check free disk space. + +[INFO] Processate 417737400 righe, salvate 417728626 log +[ERROR] Errore salvataggio log: could not extend file "base/16384/16940.223": No space left on device +HINT: Check free disk space. + +[ERROR] Errore salvataggio log: could not extend file "base/16384/16940.223": No space left on device +HINT: Check free disk space. + +[ERROR] Errore salvataggio log: could not extend file "base/16384/16940.223": No space left on device +HINT: Check free disk space. + +[ERROR] Errore salvataggio log: could not extend file "base/16384/16940.223": No space left on device +HINT: Check free disk space. + +[ERROR] Errore salvataggio log: could not extend file "base/16384/16940.223": No space left on device +HINT: Check free disk space. + +[ERROR] Errore salvataggio log: could not extend file "base/16384/16940.223": No space left on device +HINT: Check free disk space. + +[ERROR] Errore salvataggio log: could not extend file "base/16384/16940.223": No space left on device +HINT: Check free disk space. + +[ERROR] Errore salvataggio log: could not extend file "base/16384/16940.223": No space left on device +HINT: Check free disk space. + +[ERROR] Errore salvataggio log: could not extend file "base/16384/16940.223": No space left on device +HINT: Check free disk space. + +[ERROR] Errore salvataggio log: could not extend file "base/16384/16940.223": No space left on device +HINT: Check free disk space. + +[ERROR] Errore salvataggio log: could not extend file "base/16384/16940.223": No space left on device +HINT: Check free disk space. + +[ERROR] Errore salvataggio log: could not extend file "base/16384/16940.223": No space left on device +HINT: Check free disk space. + +[ERROR] Errore salvataggio log: could not extend file "base/16384/16940.223": No space left on device +HINT: Check free disk space. + +[ERROR] Errore salvataggio log: could not extend fil[root@ids ids]# df -h +Filesystem Size Used Avail Use% Mounted on +devtmpfs 4.0M 0 4.0M 0% /dev +tmpfs 7.7G 16K 7.7G 1% /dev/shm +tmpfs 3.1G 8.8M 3.1G 1% /run +efivarfs 256K 32K 220K 13% /sys/firmware/efi/efivars +/dev/mapper/almalinux_ids-root 491G 40G 451G 9% / +/dev/sda2 960M 327M 634M 34% /boot +/dev/sda1 599M 7.1M 592M 2% /boot/efi +tmpfs 1.6G 0 1.6G 0% /run/user/0 +tmpfs 1.6G 0 1.6G 0% /run/user/1000 \ No newline at end of file diff --git a/database-schema/apply_migrations.sh b/database-schema/apply_migrations.sh new file mode 100755 index 0000000..05c77c7 --- /dev/null +++ b/database-schema/apply_migrations.sh @@ -0,0 +1,55 @@ +#!/bin/bash +# ============================================================================= +# IDS - Applica Migrazioni Database +# ============================================================================= +# Applica tutti gli script SQL in database-schema/migrations/ in ordine +# ============================================================================= + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +MIGRATIONS_DIR="$SCRIPT_DIR/migrations" + +# Colori +GREEN='\033[0;32m' +BLUE='\033[0;34m' +YELLOW='\033[1;33m' +RED='\033[0;31m' +NC='\033[0m' + +echo -e "${BLUE}πŸ—„οΈ Applicazione migrazioni database...${NC}" + +# Verifica DATABASE_URL +if [ -z "$DATABASE_URL" ]; then + echo -e "${RED}❌ DATABASE_URL non impostato${NC}" + exit 1 +fi + +# Crea directory migrations se non esiste +mkdir -p "$MIGRATIONS_DIR" + +# Conta migrazioni +MIGRATION_COUNT=$(find "$MIGRATIONS_DIR" -name "*.sql" 2>/dev/null | wc -l) + +if [ "$MIGRATION_COUNT" -eq 0 ]; then + echo -e "${YELLOW}⚠️ Nessuna migrazione da applicare${NC}" + exit 0 +fi + +echo -e "${BLUE}πŸ“‹ Trovate $MIGRATION_COUNT migrazioni${NC}" + +# Applica ogni migrazione in ordine +for migration in $(find "$MIGRATIONS_DIR" -name "*.sql" | sort); do + MIGRATION_NAME=$(basename "$migration") + echo -e "${BLUE} Applicando: $MIGRATION_NAME${NC}" + + if psql "$DATABASE_URL" -f "$migration" > /dev/null 2>&1; then + echo -e "${GREEN} βœ… $MIGRATION_NAME applicata${NC}" + else + echo -e "${RED} ❌ Errore in $MIGRATION_NAME${NC}" + psql "$DATABASE_URL" -f "$migration" + exit 1 + fi +done + +echo -e "${GREEN}βœ… Tutte le migrazioni applicate con successo${NC}" diff --git a/database-schema/cleanup_old_logs.sql b/database-schema/cleanup_old_logs.sql new file mode 100644 index 0000000..e1f279a --- /dev/null +++ b/database-schema/cleanup_old_logs.sql @@ -0,0 +1,39 @@ +-- ============================================================================= +-- IDS - Pulizia Automatica Log Vecchi +-- ============================================================================= +-- Mantiene solo gli ultimi 7 giorni di network_logs +-- Esegui giornalmente via cron: psql $DATABASE_URL < cleanup_old_logs.sql +-- ============================================================================= + +-- Conta log prima della pulizia +DO $$ +DECLARE + total_count bigint; + old_count bigint; +BEGIN + SELECT COUNT(*) INTO total_count FROM network_logs; + SELECT COUNT(*) INTO old_count FROM network_logs WHERE timestamp < NOW() - INTERVAL '7 days'; + + RAISE NOTICE 'Log totali: %', total_count; + RAISE NOTICE 'Log da eliminare (>7 giorni): %', old_count; +END $$; + +-- Elimina log piΓΉ vecchi di 7 giorni +DELETE FROM network_logs +WHERE timestamp < NOW() - INTERVAL '7 days'; + +-- Vacuum per liberare spazio fisico +VACUUM ANALYZE network_logs; + +-- Conta log dopo pulizia +DO $$ +DECLARE + remaining_count bigint; + db_size text; +BEGIN + SELECT COUNT(*) INTO remaining_count FROM network_logs; + SELECT pg_size_pretty(pg_database_size(current_database())) INTO db_size; + + RAISE NOTICE 'Log rimanenti: %', remaining_count; + RAISE NOTICE 'Dimensione database: %', db_size; +END $$; diff --git a/database-schema/migrations/001_add_missing_columns.sql b/database-schema/migrations/001_add_missing_columns.sql new file mode 100644 index 0000000..c95ebc2 --- /dev/null +++ b/database-schema/migrations/001_add_missing_columns.sql @@ -0,0 +1,35 @@ +-- Migration 001: Add missing columns to routers table +-- Date: 2025-11-21 +-- Description: Adds api_port and last_sync columns if missing + +-- Add api_port column if not exists +ALTER TABLE routers +ADD COLUMN IF NOT EXISTS api_port integer NOT NULL DEFAULT 8728; + +-- Add last_sync column if not exists +ALTER TABLE routers +ADD COLUMN IF NOT EXISTS last_sync timestamp; + +-- Add created_at if missing (fallback for older schemas) +ALTER TABLE routers +ADD COLUMN IF NOT EXISTS created_at timestamp DEFAULT now() NOT NULL; + +-- Verify columns exist +DO $$ +BEGIN + IF EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_name = 'routers' + AND column_name = 'api_port' + ) THEN + RAISE NOTICE 'Column api_port exists'; + END IF; + + IF EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_name = 'routers' + AND column_name = 'last_sync' + ) THEN + RAISE NOTICE 'Column last_sync exists'; + END IF; +END $$; diff --git a/deployment/cleanup_database.sh b/deployment/cleanup_database.sh new file mode 100755 index 0000000..6a729ac --- /dev/null +++ b/deployment/cleanup_database.sh @@ -0,0 +1,46 @@ +#!/bin/bash +# ============================================================================= +# IDS - Pulizia Database Automatica +# ============================================================================= +# Esegui giornalmente via cron per mantenere database pulito +# Esempio cron: 0 3 * * * /opt/ids/deployment/cleanup_database.sh +# ============================================================================= + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +IDS_DIR="/opt/ids" + +# Carica variabili ambiente +if [ -f "$IDS_DIR/.env" ]; then + source "$IDS_DIR/.env" +fi + +# Verifica DATABASE_URL +if [ -z "$DATABASE_URL" ]; then + echo "[ERROR] DATABASE_URL non impostato" + exit 1 +fi + +echo "==========================================" +echo "IDS - Pulizia Database $(date)" +echo "==========================================" + +# Dimensione database PRIMA della pulizia +echo "" +echo "πŸ“Š Dimensione database PRIMA:" +psql "$DATABASE_URL" -c "SELECT pg_size_pretty(pg_database_size(current_database()));" + +# Esegui pulizia +echo "" +echo "🧹 Eliminazione log vecchi (>7 giorni)..." +psql "$DATABASE_URL" -f "$IDS_DIR/database-schema/cleanup_old_logs.sql" + +# Dimensione database DOPO la pulizia +echo "" +echo "πŸ“Š Dimensione database DOPO:" +psql "$DATABASE_URL" -c "SELECT pg_size_pretty(pg_database_size(current_database()));" + +echo "" +echo "βœ… Pulizia completata - $(date)" +echo "==========================================" diff --git a/deployment/debug_system.sh b/deployment/debug_system.sh new file mode 100755 index 0000000..28e4916 --- /dev/null +++ b/deployment/debug_system.sh @@ -0,0 +1,155 @@ +#!/bin/bash +# ============================================================================= +# IDS - Debug Sistema Completo +# ============================================================================= +# Verifica stato completo del sistema: database, servizi, log +# ============================================================================= + +# Colori +GREEN='\033[0;32m' +BLUE='\033[0;34m' +YELLOW='\033[1;33m' +RED='\033[0;31m' +NC='\033[0m' + +echo -e "${BLUE}" +echo "╔═══════════════════════════════════════════════╗" +echo "β•‘ πŸ” DEBUG SISTEMA IDS β•‘" +echo "β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•" +echo -e "${NC}" + +# Verifica DATABASE_URL +if [ -z "$DATABASE_URL" ]; then + echo -e "${RED}❌ DATABASE_URL non impostato${NC}" + echo -e "${YELLOW} Carica variabili: source /opt/ids/.env${NC}" + exit 1 +fi + +# 1. VERIFICA DATABASE +echo -e "\n${BLUE}═══ 1. VERIFICA DATABASE ═══${NC}" +echo -e "${BLUE}πŸ“Š Conta record per tabella:${NC}" +psql "$DATABASE_URL" << 'EOF' +SELECT 'network_logs' as tabella, COUNT(*) as record FROM network_logs +UNION ALL +SELECT 'detections', COUNT(*) FROM detections +UNION ALL +SELECT 'training_history', COUNT(*) FROM training_history +UNION ALL +SELECT 'routers', COUNT(*) FROM routers +UNION ALL +SELECT 'whitelist', COUNT(*) FROM whitelist +ORDER BY tabella; +EOF + +echo -e "\n${BLUE}πŸ“‹ Schema tabella routers:${NC}" +psql "$DATABASE_URL" -c "\d routers" + +echo -e "\n${BLUE}πŸ“ Ultimi 5 network_logs:${NC}" +psql "$DATABASE_URL" << 'EOF' +SELECT + timestamp, + router_name, + source_ip, + destination_ip, + protocol, + packet_length +FROM network_logs +ORDER BY timestamp DESC +LIMIT 5; +EOF + +echo -e "\n${BLUE}πŸ“œ Training history:${NC}" +psql "$DATABASE_URL" << 'EOF' +SELECT + trained_at, + model_version, + records_processed, + features_count, + status, + notes +FROM training_history +ORDER BY trained_at DESC +LIMIT 5; +EOF + +echo -e "\n${BLUE}🚨 Detections:${NC}" +psql "$DATABASE_URL" << 'EOF' +SELECT + detected_at, + source_ip, + risk_score, + anomaly_type, + blocked, + log_count +FROM detections +ORDER BY detected_at DESC +LIMIT 5; +EOF + +# 2. VERIFICA SERVIZI +echo -e "\n${BLUE}═══ 2. STATO SERVIZI ═══${NC}" +echo -e "${BLUE}πŸ” Processi attivi:${NC}" +ps aux | grep -E 'python.*main|npm.*dev|syslog_parser' | grep -v grep || echo -e "${YELLOW} Nessun servizio IDS attivo${NC}" + +# 3. BACKEND PYTHON ML +echo -e "\n${BLUE}═══ 3. BACKEND PYTHON ML ═══${NC}" +if curl -s http://localhost:8000/health > /dev/null 2>&1; then + echo -e "${GREEN}βœ… Backend Python attivo${NC}" + echo -e "${BLUE}πŸ“Š Statistiche ML:${NC}" + curl -s http://localhost:8000/stats | jq '.' || curl -s http://localhost:8000/stats +else + echo -e "${RED}❌ Backend Python NON risponde su porta 8000${NC}" + echo -e "${YELLOW} Verifica log: tail -50 /var/log/ids/backend.log${NC}" +fi + +# 4. FRONTEND NODE.JS +echo -e "\n${BLUE}═══ 4. FRONTEND NODE.JS ═══${NC}" +if curl -s http://localhost:5000 > /dev/null 2>&1; then + echo -e "${GREEN}βœ… Frontend Node attivo${NC}" + echo -e "${BLUE}πŸ“Š Test API:${NC}" + curl -s http://localhost:5000/api/stats | jq '.' || curl -s http://localhost:5000/api/stats +else + echo -e "${RED}❌ Frontend Node NON risponde su porta 5000${NC}" + echo -e "${YELLOW} Verifica log: tail -50 /var/log/ids/frontend.log${NC}" +fi + +# 5. SYSLOG PARSER +echo -e "\n${BLUE}═══ 5. SYSLOG PARSER ═══${NC}" +if ps aux | grep -E 'syslog_parser\.py' | grep -v grep > /dev/null; then + echo -e "${GREEN}βœ… Syslog Parser attivo${NC}" + echo -e "${BLUE}πŸ“ Ultimi log (parser):${NC}" + tail -20 /var/log/ids/syslog_parser.log +else + echo -e "${RED}❌ Syslog Parser NON attivo${NC}" + echo -e "${YELLOW} Avvia: cd /opt/ids/python_ml && nohup python syslog_parser.py > /var/log/ids/syslog_parser.log 2>&1 &${NC}" +fi + +# 6. LOG ERRORI +echo -e "\n${BLUE}═══ 6. ERRORI RECENTI ═══${NC}" +echo -e "${BLUE}πŸ”΄ Errori backend Python:${NC}" +tail -50 /var/log/ids/backend.log | grep -i error | tail -10 || echo -e "${GREEN} Nessun errore${NC}" + +echo -e "\n${BLUE}πŸ”΄ Errori frontend Node:${NC}" +tail -50 /var/log/ids/frontend.log | grep -i "\[DB ERROR\]" | tail -10 || echo -e "${GREEN} Nessun errore${NC}" + +# 7. RIEPILOGO +echo -e "\n${BLUE}╔═══════════════════════════════════════════════╗${NC}" +echo -e "${BLUE}β•‘ πŸ“‹ RIEPILOGO β•‘${NC}" +echo -e "${BLUE}β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•${NC}" + +LOGS_COUNT=$(psql "$DATABASE_URL" -t -c "SELECT COUNT(*) FROM network_logs" 2>/dev/null | xargs) +DETECTIONS_COUNT=$(psql "$DATABASE_URL" -t -c "SELECT COUNT(*) FROM detections" 2>/dev/null | xargs) +TRAINING_COUNT=$(psql "$DATABASE_URL" -t -c "SELECT COUNT(*) FROM training_history" 2>/dev/null | xargs) + +echo -e "${BLUE}Database:${NC}" +echo -e " β€’ Network logs: ${YELLOW}$LOGS_COUNT${NC}" +echo -e " β€’ Detections: ${YELLOW}$DETECTIONS_COUNT${NC}" +echo -e " β€’ Training history: ${YELLOW}$TRAINING_COUNT${NC}" + +echo "" +echo -e "${BLUE}πŸ”§ COMANDI UTILI:${NC}" +echo -e " β€’ Riavvia tutto: ${YELLOW}sudo -u ids /opt/ids/deployment/restart_all.sh${NC}" +echo -e " β€’ Test training: ${YELLOW}curl -X POST http://localhost:8000/train -H 'Content-Type: application/json' -d '{\"max_records\": 1000}'${NC}" +echo -e " β€’ Log frontend: ${YELLOW}tail -f /var/log/ids/frontend.log${NC}" +echo -e " β€’ Log backend: ${YELLOW}tail -f /var/log/ids/backend.log${NC}" +echo "" diff --git a/deployment/setup_cron_cleanup.sh b/deployment/setup_cron_cleanup.sh new file mode 100755 index 0000000..44d0238 --- /dev/null +++ b/deployment/setup_cron_cleanup.sh @@ -0,0 +1,42 @@ +#!/bin/bash +# ============================================================================= +# IDS - Setup Cron per Pulizia Database +# ============================================================================= +# Esegui come ROOT per configurare cron job giornaliero +# ============================================================================= + +set -e + +# Verifica di essere root +if [ "$EUID" -ne 0 ]; then + echo "❌ Questo script deve essere eseguito come root" + echo " Esegui: sudo ./setup_cron_cleanup.sh" + exit 1 +fi + +IDS_USER="ids" +CRON_CMD="0 3 * * * /opt/ids/deployment/cleanup_database.sh >> /var/log/ids/cleanup.log 2>&1" + +echo "πŸ”§ Configurazione cron job per pulizia database..." + +# Verifica se cron job esiste giΓ  +if crontab -u $IDS_USER -l 2>/dev/null | grep -q "cleanup_database.sh"; then + echo "⚠️ Cron job giΓ  configurato" + echo "" + echo "πŸ“‹ Cron jobs attuali per utente $IDS_USER:" + crontab -u $IDS_USER -l +else + # Aggiungi cron job + (crontab -u $IDS_USER -l 2>/dev/null; echo "$CRON_CMD") | crontab -u $IDS_USER - + echo "βœ… Cron job configurato con successo" + echo "" + echo "πŸ“‹ Cron job installato:" + echo " $CRON_CMD" + echo "" + echo " EseguirΓ  pulizia database ogni giorno alle 03:00" + echo " Log: /var/log/ids/cleanup.log" +fi + +echo "" +echo "πŸ§ͺ Test manuale pulizia:" +echo " sudo -u $IDS_USER /opt/ids/deployment/cleanup_database.sh" diff --git a/deployment/update_from_git.sh b/deployment/update_from_git.sh index abde83f..05168f0 100755 --- a/deployment/update_from_git.sh +++ b/deployment/update_from_git.sh @@ -117,10 +117,26 @@ fi # Aggiorna schema database echo -e "\n${BLUE}πŸ—„οΈ Aggiornamento schema database...${NC}" + +# 1. Applica migrazioni SQL manuali (ALTER TABLE, ecc.) +if [ -f "./database-schema/apply_migrations.sh" ]; then + echo -e "${BLUE} Applicando migrazioni SQL...${NC}" + sudo -u $IDS_USER bash ./database-schema/apply_migrations.sh + if [ $? -eq 0 ]; then + echo -e "${GREEN} βœ… Migrazioni SQL applicate${NC}" + else + echo -e "${YELLOW} ⚠️ Alcune migrazioni potrebbero essere giΓ  applicate${NC}" + fi +fi + +# 2. Sincronizza schema Drizzle +echo -e "${BLUE} Sincronizzando schema Drizzle...${NC}" sudo -u $IDS_USER npm run db:push if [ $? -eq 0 ]; then - echo -e "${GREEN}βœ… Schema database sincronizzato${NC}" + echo -e "${GREEN}βœ… Schema database completamente sincronizzato${NC}" +else + echo -e "${YELLOW}⚠️ Schema Drizzle potrebbe richiedere --force${NC}" fi # Restart servizi diff --git a/replit.md b/replit.md index 4dad652..a12bdf2 100644 --- a/replit.md +++ b/replit.md @@ -1,328 +1,9 @@ # IDS - Intrusion Detection System -Sistema di rilevamento intrusioni per router MikroTik basato su Machine Learning. - -## Progetto - -**Tipo**: Full-stack Web Application + Python ML Backend -**Stack**: React + FastAPI + PostgreSQL + MikroTik API REST - -## Architettura - -### Frontend (React) -- Dashboard monitoring real-time -- Visualizzazione detections e router -- Gestione whitelist -- ShadCN UI components -- TanStack Query per data fetching - -### Backend Python (FastAPI) -- **ML Analyzer**: Isolation Forest con 25 feature mirate -- **MikroTik Manager**: Comunicazione API REST parallela con 10+ router -- **Detection Engine**: Scoring 0-100 con 5 livelli di rischio -- Endpoints: /train, /detect, /block-ip, /unblock-ip, /stats - -### Backend Node.js (Express) -- API REST per frontend -- Gestione database PostgreSQL -- Routes: routers, detections, logs, whitelist, training-history - -### Database (PostgreSQL) -- `routers`: Configurazione router MikroTik -- `network_logs`: Log syslog da router -- `detections`: Anomalie rilevate dal ML -- `whitelist`: IP fidati -- `training_history`: Storia training modelli - -## Workflow - -1. **Log Collection**: Router β†’ Syslog (UDP:514) β†’ RSyslog β†’ syslog_parser.py β†’ PostgreSQL `network_logs` -2. **Training**: Python ML estrae 25 feature β†’ Isolation Forest -3. **Detection**: Analisi real-time β†’ Scoring 0-100 β†’ Classificazione -4. **Auto-Block**: IP critico (>=80) β†’ API REST β†’ Tutti i router (parallelo) - -## Fix Recenti (Novembre 2025) - -### βœ… Database Driver Fix - Dual Mode Neon/PostgreSQL (21 Nov 2025 - 17:40) -- **Problema**: Frontend Node.js falliva con errore 500 su tutte le query database (`/api/stats`, `/api/routers`, ecc.) -- **Causa ROOT**: `@neondatabase/serverless` usa WebSocket ed Γ¨ compatibile SOLO con Neon Cloud, non con PostgreSQL locale su AlmaLinux -- **Diagnosi**: - - βœ… DATABASE_URL caricato correttamente (verificato con `psql`) - - βœ… Backend Python funzionava (usa `psycopg2` compatibile con PostgreSQL locale) - - ❌ Backend Node.js falliva (usava `@neondatabase/serverless`) -- **Soluzione**: - - Modificato `server/db.ts` per **dual-mode**: - - Su Replit (Neon Cloud): usa `@neondatabase/serverless` + WebSocket - - Su AlmaLinux (PostgreSQL locale): usa `pg` standard driver - - Auto-detection basata su `DATABASE_URL.includes('neon.tech')` - - Import corretto `pg` per ES modules: `import pg from 'pg'; const { Pool } = pg;` - - Aggiunto health-check database: `SELECT 1` all'avvio - - Aggiunto logging dettagliato errori DB: `[DB ERROR]` prefix in `server/routes.ts` -- **Fix Schema Database**: - - Problema secondario: tabella `routers` mancava colonne `api_port` e `last_sync` - - Risolto con `ALTER TABLE routers ADD COLUMN IF NOT EXISTS ...` -- **Risultato Finale**: - - βœ… Replit: `πŸ“¦ Using Neon serverless database` + `βœ… Database connection successful` - - βœ… AlmaLinux: `🐘 Using standard PostgreSQL database` + `βœ… Database connection successful` - - βœ… API database: Tutte le route `/api/*` rispondono **200 invece di 500** - - βœ… Test completo: Training avviato con successo `POST /api/ml/train 200` - - βœ… Logging diagnostico: `[DB ERROR]` prefix ha permesso debug rapido errori schema - -### βœ… Frontend Environment Variables Fix (21 Nov 2025 - 17:00) -- **Problema**: Frontend Node.js non si avviava su server AlmaLinux con errore `DATABASE_URL must be set` -- **Causa 1**: Script `check_frontend.sh` non caricava variabili d'ambiente dal file `.env` -- **Causa 2**: Il comando `nohup` crea un nuovo processo che non eredita variabili esportate con `source` -- **Soluzione**: - - Modificato `deployment/check_frontend.sh` per passare variabili direttamente al comando npm - - Usato `env $(cat .env | grep -v '^#' | xargs) npm run dev` per iniettare variabili nel processo -- **Risultato**: Frontend si avvia correttamente leggendo `DATABASE_URL` e altre variabili da `.env` - -### βœ… Form Validation Migliorata (21 Nov 2025 - 15:00) -- **API ML Endpoints**: Timeout configurabili (120s train/detect, 10s stats), validazione input, messaggi errore specifici (504 timeout, 503 backend down, 400 validation) -- **Whitelist Form**: Convertito a react-hook-form + zodResolver, validazione IP completa (regex + controllo ottetti 0-255) -- **Training Forms**: Due form separati (trainForm/detectForm), schema Zod con z.coerce.number(), FormDescription per suggerimenti - -### βœ… Sistema Completamente Funzionante (17 Nov 2025 - 19:30) -- **Backend Python FastAPI**: βœ… Porta 8000, modello ML caricato, endpoint /stats funzionante -- **Database PostgreSQL**: βœ… 5 tabelle (network_logs, detections, routers, whitelist, training_history) -- **Syslog Parser**: βœ… Funzionante, log salvati continuamente -- **Pattern Regex**: βœ… Match rate 99.9% su log MikroTik reali -- **ML Detection**: βœ… Modello Isolation Forest addestrato, pronto per detection automatica -- **Deployment**: βœ… Git workflow automatizzato con `push-gitlab.sh` e `update_from_git.sh --db` - -### Backend FastAPI Fix (17 Nov 2025 - 19:30) -- **Problema**: Endpoint `/stats` falliva con errore 500 -- **Causa 1**: Colonna `logged_at` non esiste (nome corretto: `timestamp`) -- **Causa 2**: Tabella `routers` mancante -- **Causa 3**: Query non gestivano risultati `None` -- **Soluzione**: - - Corretto nome colonna da `logged_at` a `timestamp` in `/stats` - - Creato script SQL `database-schema/create_routers.sql` - - Aggiunta gestione `None` per tutte le query -- **Risultato**: Endpoint `/stats` funzionante, API completa operativa - -### Crontab Automation Fix (18 Nov 2025 - 09:30) -- **Problema 1**: Training/Detection crontab falliscono con `ModuleNotFoundError: No module named 'requests'` -- **Problema 2**: Script check_backend/frontend falliscono con `Permission denied` su `/var/run/ids/` -- **Causa 1**: Crontab usavano Python inline con modulo `requests` non installato -- **Causa 2**: Utente `ids` non ha permessi scrittura su `/var/run/ids/` -- **Soluzione**: - - Creati script shell dedicati: `cron_train.sh` e `cron_detect.sh` (usano `curl` invece di Python) - - Aggiornati script monitoring: `check_backend.sh` e `check_frontend.sh` (usano `/var/log/ids/` invece di `/var/run/ids/`) - - Aggiornato `setup_crontab.sh` per usare i nuovi script -- **Risultato**: Automazione crontab completamente funzionante senza dipendenze Python esterne - -### Schema Database Fix (17 Nov 2025) -- **Problema**: Tabella `network_logs` mancante, schema TypeScript disallineato con Python -- **Soluzione**: Schema aggiornato con campi corretti (router_name, destination_ip/port, packet_length, raw_message) -- **Script SQL**: `database-schema/create_network_logs.sql` per creazione tabella -- **Update automatico**: `./update_from_git.sh --db` applica tutti gli script SQL in `database-schema/` - -### Pattern Regex Fix (17 Nov 2025) -- **Problema**: Pattern regex non matchavano formato reale log MikroTik -- **Formato vecchio**: `src-address=IP:PORT dst-address=IP:PORT proto=UDP` ❌ -- **Formato reale**: `proto UDP, IP:PORT->IP:PORT, len 1280` βœ… -- **Risultato**: Match rate 99.9%, ~670K log salvati correttamente - -### PostgreSQL Authentication Fix -- **Problema**: Password authentication failed (SCRAM-SHA-256 vs MD5) -- **Soluzione**: `deployment/fix_postgresql_auth.sh` configura SCRAM-SHA-256 in pg_hba.conf -- **Password encryption**: ALTER SYSTEM SET password_encryption = 'scram-sha-256' -- **Utente ricreato**: DROP + CREATE con formato SCRAM corretto - -### IPv4 Force Fix -- **Problema**: syslog_parser si connetteva a ::1 (IPv6) invece di 127.0.0.1 (IPv4) -- **Soluzione**: PGHOST=127.0.0.1 in .env (NON usare localhost) -- **Parser**: load_dotenv() carica .env automaticamente - -### Git Ownership Fix -- **Problema**: dubious ownership error in /opt/ids -- **Soluzione**: `deployment/fix_git_ownership.sh` aggiunge safe.directory -- **Update script**: `deployment/update_from_git.sh` ora esegue git come utente ids - -## File Importanti - -### Python ML Backend -- `python_ml/ml_analyzer.py`: Core ML (25 feature, Isolation Forest) -- `python_ml/mikrotik_manager.py`: Gestione router API REST -- `python_ml/main.py`: FastAPI server -- `python_ml/requirements.txt`: Dipendenze Python - -### Frontend -- `client/src/pages/Dashboard.tsx`: Dashboard principale -- `client/src/pages/Detections.tsx`: Lista rilevamenti -- `client/src/pages/Routers.tsx`: Gestione router -- `client/src/App.tsx`: App root con sidebar - -### Backend Node -- `server/routes.ts`: API endpoints -- `server/storage.ts`: Database operations -- `server/db.ts`: PostgreSQL connection -- `shared/schema.ts`: Drizzle ORM schema - -## Deployment e Aggiornamenti - -### PRIMO DEPLOYMENT (Bootstrap) - Server AlmaLinux -**Documentazione**: `deployment/BOOTSTRAP_PRIMO_DEPLOYMENT.md` - -```bash -# Clone in directory separata (preserva .env esistente) -cd /opt -sudo -u ids git clone https://[CREDENTIALS]@git.alfacom.it/marco/ids.git ids_git - -# Copia .env esistente -sudo -u ids cp /opt/ids/.env /opt/ids_git/.env - -# Swap atomico directory -mv /opt/ids /opt/ids_legacy -mv /opt/ids_git /opt/ids - -# Installa dipendenze e riavvia servizi -cd /opt/ids -sudo -u ids npm install -cd python_ml && sudo -u ids pip3.11 install -r requirements.txt -``` - -### Aggiornamenti Futuri (Dopo Bootstrap) -```bash -# Aggiornamento standard (codice + dipendenze) -cd /opt/ids -./update_from_git.sh - -# Aggiornamento con sincronizzazione schema database -./update_from_git.sh --db -``` - -**IMPORTANTE**: `update_from_git.sh` fa backup automatico di `.env` e `git.env` prima del pull! - -### Export Schema Database (Solo Struttura) -```bash -# Su server production, esporta schema per commit su git -cd /opt/ids/deployment -./export_db_schema.sh - -# Risultato: database-schema/schema.sql (NO dati, SOLO DDL) -``` - -### Push su Git (Da Replit) -```bash -# Esporta schema + commit + push -cd /opt/ids -./push-gitlab.sh # Patch version (1.0.0 β†’ 1.0.1) -./push-gitlab.sh minor # Minor version (1.0.5 β†’ 1.1.0) -./push-gitlab.sh major # Major version (1.1.5 β†’ 2.0.0) -``` - -## Comandi Utili - -### Start Python Backend -```bash -cd python_ml -pip install -r requirements.txt -python main.py -``` - -### API Calls -```bash -# Training -curl -X POST http://localhost:8000/train \ - -H "Content-Type: application/json" \ - -d '{"max_records": 10000, "hours_back": 24}' - -# Detection -curl -X POST http://localhost:8000/detect \ - -H "Content-Type: application/json" \ - -d '{"max_records": 5000, "auto_block": true, "risk_threshold": 75}' - -# Stats -curl http://localhost:8000/stats -``` - -### Database -```bash -npm run db:push # Sync schema to PostgreSQL -``` - -## Configurazione Router MikroTik - -### Abilita API REST -``` -/ip service -set api-ssl disabled=no -set www-ssl disabled=no -``` - -### Aggiungi Router -Via dashboard web o SQL: -```sql -INSERT INTO routers (name, ip_address, username, password, api_port, enabled) -VALUES ('Router 1', '192.168.1.1', 'admin', 'password', 443, true); -``` - -## Feature ML (25 totali) - -### Volume (5) -- total_packets, total_bytes, conn_count -- avg_packet_size, bytes_per_second - -### Temporali (8) -- time_span_seconds, conn_per_second -- hour_of_day, day_of_week -- max_burst, avg_burst, burst_variance, avg_interval - -### Protocol Diversity (6) -- unique_protocols, unique_dest_ports, unique_dest_ips -- protocol_entropy, tcp_ratio, udp_ratio - -### Port Scanning (3) -- unique_ports_contacted, port_scan_score, sequential_ports - -### Behavioral (3) -- packets_per_conn, packet_size_variance, blocked_ratio - -## Livelli di Rischio - -- πŸ”΄ CRITICO (85-100): Blocco immediato -- 🟠 ALTO (70-84): Blocco + monitoring -- 🟑 MEDIO (60-69): Monitoring -- πŸ”΅ BASSO (40-59): Logging -- 🟒 NORMALE (0-39): Nessuna azione - -## Vantaggi vs Sistema Precedente - -- **Feature**: 150+ β†’ 25 (mirate) -- **Training**: ~5 min β†’ ~10 sec -- **Detection**: Lento β†’ <2 sec -- **Router Comm**: SSH β†’ API REST -- **Multi-Router**: Sequenziale β†’ Parallelo -- **Database**: MySQL β†’ PostgreSQL -- **Falsi Negativi**: Alti β†’ Bassi - -## Note - -- Whitelist: IP protetti da blocco automatico -- Timeout: Blocchi scadono dopo 1h (configurabile) -- Parallel Blocking: Tutti i router aggiornati simultaneamente -- Auto-Training: Configurabile via cron (consigliato ogni 12h) -- Auto-Detection: Configurabile via cron (consigliato ogni 5 min) - -## Sicurezza - -- Password router gestite da database (non in codice) -- API REST piΓΉ sicura di SSH -- Timeout automatico blocchi -- Logging completo operazioni -- PostgreSQL con connessione sicura - -## Development - -- Frontend: Workflow "Start application" (auto-reload) -- Python Backend: `python python_ml/main.py` -- API Docs: http://localhost:8000/docs -- Database: PostgreSQL via Neon (environment variables auto-configurate) - -## Preferenze Utente +## Overview +This project is a full-stack web application designed as an Intrusion Detection System (IDS) for MikroTik routers, leveraging Machine Learning. Its primary purpose is to monitor network traffic, detect anomalies indicative of intrusions, and automatically block malicious IP addresses across multiple routers. The system aims to provide real-time monitoring, efficient anomaly detection, and streamlined management of network security for MikroTik environments. +## User Preferences ### Operazioni Git e Deployment - **IMPORTANTE**: L'agente NON deve usare comandi git (push-gitlab.sh) perchΓ© Replit blocca le operazioni git - **Workflow corretto**: @@ -337,3 +18,68 @@ VALUES ('Router 1', '192.168.1.1', 'admin', 'password', 443, true); - Tutte le risposte dell'agente devono essere in **italiano** - Codice e documentazione tecnica: inglese - Commit message: italiano + +## System Architecture +The IDS features a React-based frontend for real-time monitoring, detection visualization, and whitelist management, utilizing ShadCN UI and TanStack Query. The backend comprises a Python FastAPI service for ML analysis (Isolation Forest with 25 targeted features), MikroTik API management, and a detection engine scoring anomalies from 0-100 with five risk levels. A Node.js (Express) backend handles API requests from the frontend and manages the PostgreSQL database. + +**Workflow:** +1. **Log Collection**: MikroTik Routers send syslog data (UDP:514) to RSyslog, which is then parsed by `syslog_parser.py` and stored in the `network_logs` table in PostgreSQL. +2. **Training**: The Python ML component extracts 25 features from network logs and trains an Isolation Forest model. +3. **Detection**: Real-time analysis of network logs is performed using the trained ML model, assigning a risk score. +4. **Auto-Block**: Critical IPs (score >= 80) are automatically blocked across all configured MikroTik routers in parallel via their REST API. + +**Key Features:** +- **ML Analyzer**: Isolation Forest with 25 features. +- **MikroTik Manager**: Parallel communication with 10+ routers via API REST. +- **Detection Engine**: Scoring 0-100 with 5 risk levels (Normal, Basso, Medio, Alto, Critico). +- **Form Validation**: Improved validation using react-hook-form and Zod. +- **Database Migrations**: Automated SQL migrations applied via `update_from_git.sh --db`. +- **Microservices**: Separation of concerns with dedicated Python ML backend and Node.js API backend. + +## External Dependencies +- **React**: Frontend framework. +- **FastAPI**: Python web framework for the ML backend. +- **PostgreSQL**: Primary database for storing router configurations, network logs, detections, and whitelist entries. +- **MikroTik API REST**: Used for communication with MikroTik routers for configuration and IP blocking. +- **ShadCN UI**: Frontend component library. +- **TanStack Query**: Data fetching library for the frontend. +- **Isolation Forest**: Machine Learning algorithm for anomaly detection. +- **RSyslog**: Log collection daemon. +- **Drizzle ORM**: Used for database schema definition and synchronization in the Node.js backend. +- **Neon Database**: Cloud-native PostgreSQL service (used in Replit environment). +- **pg (Node.js driver)**: Standard PostgreSQL driver for Node.js (used in AlmaLinux environment). +- **psycopg2**: PostgreSQL adapter for Python. + +## Fix Recenti (Novembre 2025) + +### 🚨 Database Full - Auto-Cleanup Fix (21 Nov 2025 - 18:00) +- **Problema**: Database PostgreSQL pieno con **417 MILIONI di log** accumulati + - Syslog parser ha processato 417.7M righe senza limite di retention + - Errore: `could not extend file: No space left on device` + - Tutte le tabelle vuote perchΓ© database non accetta piΓΉ scritture +- **Causa**: Nessuna pulizia automatica dei vecchi log (retention infinita) +- **Soluzione**: + - Script `cleanup_old_logs.sql`: Mantiene solo ultimi 7 giorni di `network_logs` + - Script `cleanup_database.sh`: Wrapper per esecuzione manuale/cron + - Script `setup_cron_cleanup.sh`: Configura cron job giornaliero (ore 03:00) +- **Fix Immediato sul Server**: + ```bash + # 1. Pulisci manualmente log vecchi + psql $DATABASE_URL << 'EOF' + DELETE FROM network_logs WHERE timestamp < NOW() - INTERVAL '7 days'; + VACUUM FULL network_logs; + EOF + + # 2. Setup pulizia automatica giornaliera + sudo /opt/ids/deployment/setup_cron_cleanup.sh + ``` +- **Risultato Atteso**: + - Database ridotto da centinaia di GB a pochi GB + - Retention 7 giorni sufficiente per training ML + - Pulizia automatica previene saturazione futura + +### βœ… Database Driver Fix - Dual Mode Neon/PostgreSQL (21 Nov 2025 - 17:40) +- **Problema**: Frontend Node.js falliva con errore 500 su tutte le query database +- **Causa**: `@neondatabase/serverless` usa WebSocket ed Γ¨ compatibile SOLO con Neon Cloud, non con PostgreSQL locale +- **Soluzione**: Dual-mode driver in `server/db.ts` con auto-detection ambiente +- **Risultato**: Funziona su Replit (Neon) e AlmaLinux (PostgreSQL standard) βœ… \ No newline at end of file