#!/usr/bin/env python3 import paramiko import mysql.connector from mysql.connector import Error from datetime import datetime, timedelta import logging import re from dotenv import load_dotenv import os # Carica le variabili d'ambiente load_dotenv() # Configurazione del logging logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s') # Configurazione del database db_config = { 'user': os.getenv('DB_USER'), 'password': os.getenv('DB_PASSWORD'), 'host': os.getenv('DB_HOST'), 'database': os.getenv('DB_NAME'), } def connect_to_database(): try: logging.info('πŸ”— Connessione al database...') db = mysql.connector.connect(**db_config) logging.info('βœ… Connessione al database riuscita.') return db except Error as e: logging.error(f'❌ Errore di connessione al database: {e}') exit(1) def get_routers(cursor): try: logging.info('πŸ“‘ Recupero dell\'elenco dei router dal database...') cursor.execute("SELECT * FROM routers") routers = cursor.fetchall() if not routers: logging.warning('⚠️ Nessun router trovato nel database.') exit(0) logging.info(f'βœ… Trovati {len(routers)} router nel database.') return routers except Error as e: logging.error(f'❌ Errore nel recupero dei router: {e}') exit(1) def connect_to_router(router_host, ssh_username, ssh_password): try: logging.info(f'πŸ” Connessione al router {router_host} via SSH...') ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh.connect(router_host, username=ssh_username, password=ssh_password, timeout=10) logging.info(f'βœ… Connessione SSH al router {router_host} riuscita.') return ssh except paramiko.ssh_exception.AuthenticationException as e: logging.error(f'πŸ”’ Autenticazione fallita per il router {router_host}: {e}') except paramiko.ssh_exception.SSHException as e: logging.error(f'πŸ“‘ Errore SSH con il router {router_host}: {e}') except Exception as e: logging.error(f'❌ Errore nella connessione al router {router_host}: {e}') return None def get_address_list(ssh, list_name): try: command = f"/ip firewall address-list print where list={list_name}" logging.info(f'βš™οΈ Esecuzione del comando sul router: {command}') stdin, stdout, stderr = ssh.exec_command(command) output = stdout.read().decode('utf-8', errors='ignore') error_output = stderr.read().decode('utf-8', errors='ignore') if error_output: logging.error(f'❌ Errore durante l\'esecuzione del comando: {error_output}') return [] logging.debug(f'πŸ“‹ Output del comando "{command}":\n{output}') return parse_address_list_output(output) except Exception as e: logging.error(f'❌ Errore nella get_address_list per {list_name}: {e}') return [] def add_ip_to_list(ssh, ip_address, list_name, timeout=None): """ πŸ†• Aggiunge un IP alla address-list del router MikroTik πŸ• Supporta timeout automatico per ddos_detect_v03 e whitelist (60 minuti) """ try: # πŸ†• Timeout automatico per ddos_detect_v03 E whitelist if list_name == 'ddos_detect_v03': timeout = '1h' # 60 minuti per IP DDoS detection logging.info(f'⏰ Applicando timeout 60min per {ip_address} in {list_name}') elif list_name == 'whitelist': timeout = '1h' # πŸ†• 60 minuti anche per whitelist (sicurezza) logging.info(f'⏰ Applicando timeout 60min per {ip_address} in whitelist (sicurezza)') # Costruzione comando con o senza timeout if timeout: command = f'/ip firewall address-list add list={list_name} address={ip_address} timeout={timeout} comment="Added by DDoS System - {datetime.now().strftime("%Y-%m-%d %H:%M")} - Timeout: {timeout}"' else: command = f'/ip firewall address-list add list={list_name} address={ip_address} comment="Added by DDoS System - {datetime.now().strftime("%Y-%m-%d %H:%M")}"' logging.info(f'βž• Aggiungendo {ip_address} alla lista {list_name}{"" if not timeout else f" con timeout {timeout}"}...') stdin, stdout, stderr = ssh.exec_command(command) error_output = stderr.read().decode('utf-8', errors='ignore') if error_output and 'already exists' not in error_output.lower(): logging.error(f'❌ Errore aggiungendo {ip_address} a {list_name}: {error_output}') return False elif 'already exists' in error_output.lower(): logging.debug(f'ℹ️ IP {ip_address} giΓ  presente in {list_name}') return True if timeout: logging.info(f'βœ… IP {ip_address} aggiunto alla lista {list_name} con timeout {timeout}') else: logging.info(f'βœ… IP {ip_address} aggiunto alla lista {list_name}') return True except Exception as e: logging.error(f'❌ Errore nella funzione add_ip_to_list: {e}') return False def parse_address_list_output(output): ips = [] lines = output.strip().split('\n') current_comment = '' for line in lines: line = line.strip() logging.debug(f'πŸ“ Linea analizzata: {line}') # Salta le linee vuote if not line: continue # Salta le linee non pertinenti if line.startswith('Flags:') or line.startswith('Columns:') or line.startswith('#'): continue # Se la linea inizia con ';;;', Γ¨ un commento if line.startswith(';;;'): current_comment = line[4:].strip() continue # Se la linea inizia con un numero, Γ¨ un entry if re.match(r'^\d', line): parts = line.split() idx = 0 if len(parts) < 3: # Controllo minimo campi richiesti continue index = parts[idx] idx += 1 # Controlla se il prossimo elemento Γ¨ un flag flags = '' if idx < len(parts) and re.match(r'^[A-Z]+$', parts[idx]): flags = parts[idx] idx += 1 # Nome della lista if idx < len(parts): list_name = parts[idx] idx += 1 else: list_name = '' # Indirizzo IP if idx < len(parts): ip_address = parts[idx] idx += 1 else: ip_address = '' # Creazione dell'entry solo se abbiamo dati validi if list_name and ip_address: entry = { 'list_name': list_name, 'ip_address': ip_address, 'comment': current_comment } ips.append(entry) logging.debug(f'βœ… Aggiunta entry: {entry}') # Reset del commento corrente current_comment = '' else: # Linea non riconosciuta logging.warning(f'⚠️ Linea non riconosciuta: {line}') logging.debug(f'πŸ“Š IP estratti: {len(ips)} entries') return ips def insert_ips_into_database(cursor, db, router_id, ips): if not ips: logging.info(f'ℹ️ Nessun IP da inserire per router ID {router_id}') return inserted_count = 0 updated_count = 0 for ip in ips: try: cursor.execute(""" INSERT INTO router_data (router_id, list_name, ip_address, comment) VALUES (%s, %s, %s, %s) ON DUPLICATE KEY UPDATE comment=%s, retrieved_at=%s """, (router_id, ip['list_name'], ip['ip_address'], ip['comment'], ip['comment'], datetime.now())) if cursor.rowcount == 1: inserted_count += 1 elif cursor.rowcount == 2: updated_count += 1 db.commit() logging.debug(f'πŸ’Ύ Processato IP {ip["ip_address"]} nella lista {ip["list_name"]} per router ID {router_id}') except mysql.connector.Error as err: logging.error(f"❌ Errore nell'inserimento di {ip['ip_address']}: {err}") logging.info(f'πŸ“Š Router ID {router_id}: {inserted_count} IP inseriti, {updated_count} IP aggiornati') def cleanup_old_ips(cursor, db): """ πŸ†• Rimuove gli IP piΓΉ vecchi delle soglie specificate πŸ“Š AGGIORNATO: ddos_detect_v03 da ip_list, ddos2/ddos3-attackers da router_data """ cleanup_stats = {} try: logging.info('🧹 === PULIZIA DATABASE ===') # πŸ†• Pulizia tabella ip_list (solo ddos_detect_v03) logging.info('πŸ“‹ Pulizia tabella ip_list...') list_name = 'ddos_detect_v03' days = 7 logging.info(f'🧹 Pulizia lista {list_name} da ip_list (>{days} giorni)...') # Prima conta quanti record verranno eliminati cursor.execute(""" SELECT COUNT(*) as count FROM ip_list WHERE list_name = %s AND retrieved_at < DATE_SUB(NOW(), INTERVAL %s DAY) """, (list_name, days)) count_result = cursor.fetchone() records_to_delete = count_result['count'] if count_result else 0 if records_to_delete == 0: logging.info(f'ℹ️ Nessun record da eliminare per {list_name} in ip_list') cleanup_stats[f'{list_name}_ip_list'] = 0 else: # Esegui la pulizia cursor.execute(""" DELETE FROM ip_list WHERE list_name = %s AND retrieved_at < DATE_SUB(NOW(), INTERVAL %s DAY) """, (list_name, days)) deleted_count = cursor.rowcount cleanup_stats[f'{list_name}_ip_list'] = deleted_count logging.info(f'βœ… ip_list {list_name}: eliminati {deleted_count} record piΓΉ vecchi di {days} giorni') # πŸ†• Pulizia tabella router_data (ddos2-attackers e ddos3-attackers) logging.info('🎯 Pulizia tabella router_data...') router_data_policies = [ ('ddos2-attackers', 15), # Lista attackers livello 2 ('ddos3-attackers', 20) # Lista attackers livello 3 ] for list_name, days in router_data_policies: logging.info(f'🧹 Pulizia lista {list_name} da router_data (>{days} giorni)...') # Prima conta quanti record verranno eliminati cursor.execute(""" SELECT COUNT(*) as count FROM router_data WHERE list_name = %s AND retrieved_at < DATE_SUB(NOW(), INTERVAL %s DAY) """, (list_name, days)) count_result = cursor.fetchone() records_to_delete = count_result['count'] if count_result else 0 if records_to_delete == 0: logging.info(f'ℹ️ Nessun record da eliminare per {list_name} in router_data') cleanup_stats[f'{list_name}_router_data'] = 0 else: # Esegui la pulizia cursor.execute(""" DELETE FROM router_data WHERE list_name = %s AND retrieved_at < DATE_SUB(NOW(), INTERVAL %s DAY) """, (list_name, days)) deleted_count = cursor.rowcount cleanup_stats[f'{list_name}_router_data'] = deleted_count logging.info(f'βœ… router_data {list_name}: eliminati {deleted_count} record piΓΉ vecchi di {days} giorni') db.commit() # Statistiche finali total_deleted = sum(cleanup_stats.values()) logging.info(f'🎯 Pulizia completata: {total_deleted} record totali eliminati') for key, count in cleanup_stats.items(): if count > 0: logging.info(f' └─ {key}: {count} record eliminati') except Error as e: logging.error(f"❌ Errore durante la pulizia degli IP vecchi: {e}") db.rollback() def check_expired_ips_on_router(ssh, router_host): """ πŸ†• Verifica IP scaduti sul router e fornisce statistiche πŸ“Š AGGIORNATO: liste corrette senza ddos_ia """ try: logging.info(f'πŸ• Verifica IP scaduti sul router {router_host}...') # πŸ†• Lista delle liste da controllare (senza ddos_ia) lists_to_check = ['ddos_detect_v03', 'ddos2-attackers', 'ddos3-attackers', 'whitelist'] total_active_ips = 0 timeout_stats = {} for list_name in lists_to_check: current_ips = get_address_list(ssh, list_name) count = len([ip for ip in current_ips if 'ip_address' in ip]) total_active_ips += count timeout_stats[list_name] = count if count > 0: logging.info(f'πŸ“Š Lista {list_name}: {count} IP attivi') logging.info(f'🎯 Router {router_host}: {total_active_ips} IP totali attivi') # Log specifico per ddos_detect_v03 con timeout if timeout_stats.get('ddos_detect_v03', 0) > 0: logging.info(f'⏰ Lista ddos_detect_v03: {timeout_stats["ddos_detect_v03"]} IP con timeout 60min attivi') return timeout_stats except Exception as e: logging.error(f'❌ Errore verifica IP scaduti su router {router_host}: {e}') return {} def check_global_whitelist_conflicts(cursor, db): """ πŸ†• Controlla e risolve conflitti tra whitelistGlobale e ddos_detect_v03 """ try: logging.info('πŸ›‘οΈ === CONTROLLO WHITELIST GLOBALE ===') # Trova IP che sono sia in whitelist globale che in ddos_detect_v03 cursor.execute(""" SELECT DISTINCT w.ip_address, w.comment, w.reason FROM whitelistGlobale w INNER JOIN ip_list i ON w.ip_address = i.ip_address WHERE w.active = 1 AND i.list_name = 'ddos_detect_v03' """) conflicts = cursor.fetchall() if not conflicts: logging.info('βœ… Nessun conflitto trovato tra whitelist globale e ddos_detect_v03') return logging.info(f'⚠️ Trovati {len(conflicts)} IP in conflitto da risolvere') resolved_count = 0 for conflict in conflicts: ip_address = conflict['ip_address'] comment = conflict['comment'] or 'Whitelist globale' reason = conflict['reason'] or 'Risoluzione automatica conflitto' # Rimuovi da ddos_detect_v03 cursor.execute(""" DELETE FROM ip_list WHERE ip_address = %s AND list_name = 'ddos_detect_v03' """, (ip_address,)) if cursor.rowcount > 0: resolved_count += 1 logging.info(f'βœ… Rimosso {ip_address} da ddos_detect_v03 (motivo: {reason})') db.commit() logging.info(f'🎯 Risolti {resolved_count} conflitti whitelist vs blacklist') except Error as e: logging.error(f"❌ Errore controllo whitelist globale: {e}") db.rollback() def sync_global_whitelist_to_routers(cursor, db, ssh, router_host): """ πŸ†• Sincronizza whitelistGlobale con tutti i router πŸ• AGGIORNATO: applica timeout 60min anche alla whitelist per sicurezza """ try: logging.info(f'🌐 Sincronizzazione whitelist globale per router {router_host}...') # Recupera IP attivi dalla whitelist globale cursor.execute(""" SELECT ip_address, comment, reason, last_sync FROM whitelistGlobale WHERE active = 1 ORDER BY created_at DESC """) global_whitelist = cursor.fetchall() if not global_whitelist: logging.info(f'ℹ️ Nessun IP nella whitelist globale') return 0, 0 logging.info(f'πŸ“‹ Trovati {len(global_whitelist)} IP nella whitelist globale') # Ottieni whitelist corrente dal router current_whitelist = get_address_list(ssh, 'whitelist') current_whitelist_set = {entry['ip_address'] for entry in current_whitelist if 'ip_address' in entry} added_count = 0 updated_count = 0 timeout_applied = 0 for entry in global_whitelist: ip_address = entry['ip_address'] comment = entry['comment'] or 'Whitelist globale' reason = entry['reason'] or 'IP fidato globale' if ip_address not in current_whitelist_set: # πŸ†• Aggiungi alla whitelist del router CON TIMEOUT 60min if add_ip_to_list(ssh, ip_address, 'whitelist'): # Timeout automatico applicato added_count += 1 timeout_applied += 1 # πŸ†• Conta timeout whitelist # Aggiorna last_sync cursor.execute(""" UPDATE whitelistGlobale SET last_sync = NOW() WHERE ip_address = %s """, (ip_address,)) updated_count += 1 logging.info(f'βœ… IP {ip_address} aggiunto alla whitelist router {router_host} con timeout 60min') else: logging.debug(f'βž– IP {ip_address} giΓ  presente nella whitelist router {router_host}') if updated_count > 0: db.commit() logging.info(f'🌐 Whitelist globale router {router_host}: {added_count} IP aggiunti, {timeout_applied} timeout applicati') return added_count, timeout_applied except Error as e: logging.error(f"❌ Errore sincronizzazione whitelist globale router {router_host}: {e}") return 0, 0 def sync_ip_list_to_routers(cursor, db, ssh, router_id, router_host): """ πŸ†• Sincronizza SOLO ddos_detect_v03 dalla tabella ip_list con il router πŸ“Š AGGIORNATO: controlla whitelist globale prima di bloccare IP """ try: # πŸ†• Query ottimizzata per SOLO ddos_detect_v03 ESCLUDENDO whitelist globale logging.info(f'πŸ“Š Recupero IP ddos_detect_v03 (esclusi whitelist globale) per router {router_host}...') cursor.execute(""" SELECT i.list_name, i.ip_address, i.retrieved_at FROM ip_list i LEFT JOIN whitelistGlobale w ON i.ip_address = w.ip_address AND w.active = 1 WHERE i.list_name = 'ddos_detect_v03' AND i.retrieved_at > DATE_SUB(NOW(), INTERVAL 3 DAY) AND w.ip_address IS NULL -- πŸ†• Escludi IP in whitelist globale ORDER BY i.retrieved_at DESC LIMIT 3000 """) ip_list_entries = cursor.fetchall() if not ip_list_entries: logging.info(f'ℹ️ Nessun IP ddos_detect_v03 da bloccare (whitelist globale applicata)') return logging.info(f'πŸ“‹ Trovati {len(ip_list_entries)} IP ddos_detect_v03 da sincronizzare (dopo filtro whitelist)') # Ottieni la lista corrente dal router current_ips = get_address_list(ssh, 'ddos_detect_v03') current_ips_set = {entry['ip_address'] for entry in current_ips if 'ip_address' in entry} # πŸ†• Ottieni anche whitelist corrente per doppio controllo current_whitelist = get_address_list(ssh, 'whitelist') current_whitelist_set = {entry['ip_address'] for entry in current_whitelist if 'ip_address' in entry} added_count = 0 timeout_applied = 0 skipped_whitelist = 0 # Processa solo ddos_detect_v03 for entry in ip_list_entries: ip_address = entry['ip_address'] # πŸ†• Doppio controllo: non bloccare IP in whitelist router if ip_address in current_whitelist_set: skipped_whitelist += 1 logging.debug(f'πŸ›‘οΈ IP {ip_address} saltato - presente in whitelist router') continue if ip_address not in current_ips_set: if add_ip_to_list(ssh, ip_address, 'ddos_detect_v03'): # Timeout automatico applicato added_count += 1 timeout_applied += 1 else: logging.warning(f'⚠️ Fallita aggiunta {ip_address} a ddos_detect_v03') else: logging.debug(f'βž– IP {ip_address} giΓ  presente in ddos_detect_v03') # Statistiche logging.info(f'βœ… Lista ddos_detect_v03: aggiunti {added_count} nuovi IP') logging.info(f'⏰ Timeout 60min applicati: {timeout_applied} IP in ddos_detect_v03') if skipped_whitelist > 0: logging.info(f'πŸ›‘οΈ IP saltati per whitelist: {skipped_whitelist}') logging.info(f'🎯 Sincronizzazione ddos_detect_v03 completata su router {router_host}') except Error as e: logging.error(f"❌ Errore durante la sincronizzazione ddos_detect_v03 con router {router_host}: {e}") def sync_router_data_to_routers(cursor, db, ssh, router_id, router_host): """ πŸ†• Sincronizza ddos2-attackers, ddos3-attackers e whitelist dalla tabella router_data πŸ“Š AGGIORNATO: gestione specifica per router e whitelist CON TIMEOUT """ try: logging.info(f'🎯 Sincronizzazione dati router_data per router {router_host} (ID: {router_id})...') # πŸ†• Query per ddos2-attackers e ddos3-attackers specifici del router cursor.execute(""" SELECT list_name, ip_address, retrieved_at, whitelist, added_to_router FROM router_data WHERE router_id = %s AND list_name IN ('ddos2-attackers', 'ddos3-attackers') AND retrieved_at > DATE_SUB(NOW(), INTERVAL 7 DAY) ORDER BY retrieved_at DESC LIMIT 2000 """, (router_id,)) router_entries = cursor.fetchall() total_added = 0 whitelist_timeout_applied = 0 if not router_entries: logging.info(f'ℹ️ Nessun dato ddos2/ddos3-attackers recente per router {router_host}') else: logging.info(f'πŸ“‹ Trovati {len(router_entries)} record ddos2/ddos3-attackers per router {router_host}') # Raggruppa per lista lists_data = {} whitelist_ips = [] for entry in router_entries: list_name = entry['list_name'] ip_address = entry['ip_address'] is_whitelist = entry['whitelist'] == 1 if is_whitelist: whitelist_ips.append(entry) else: if list_name not in lists_data: lists_data[list_name] = [] lists_data[list_name].append(ip_address) # Processa liste ddos2/ddos3-attackers (SENZA timeout) for list_name, ip_addresses in lists_data.items(): logging.info(f'πŸ”„ Sincronizzazione lista {list_name} ({len(ip_addresses)} IP) per router {router_host}...') # Ottieni lista corrente dal router current_ips = get_address_list(ssh, list_name) current_ips_set = {entry['ip_address'] for entry in current_ips if 'ip_address' in entry} added_count = 0 for ip_address in ip_addresses: if ip_address not in current_ips_set: if add_ip_to_list(ssh, ip_address, list_name): # Nessun timeout per queste liste added_count += 1 total_added += 1 if added_count > 0: logging.info(f'βœ… Lista {list_name}: aggiunti {added_count} IP per router {router_host}') # πŸ†• Gestione whitelist specifica CON TIMEOUT if whitelist_ips: logging.info(f'πŸ›‘οΈ Elaborazione {len(whitelist_ips)} IP per whitelist router {router_host} (CON TIMEOUT)...') whitelist_added = 0 # Ottieni whitelist corrente current_whitelist = get_address_list(ssh, 'whitelist') current_whitelist_set = {entry['ip_address'] for entry in current_whitelist if 'ip_address' in entry} for entry in whitelist_ips: ip_address = entry['ip_address'] if ip_address not in current_whitelist_set: if add_ip_to_list(ssh, ip_address, 'whitelist'): # πŸ†• CON TIMEOUT 60min # Aggiorna il database: marca come aggiunto al router cursor.execute(""" UPDATE router_data SET added_to_router = 1 WHERE ip_address = %s AND router_id = %s AND whitelist = 1 """, (ip_address, router_id)) db.commit() whitelist_added += 1 whitelist_timeout_applied += 1 # πŸ†• Conta timeout whitelist logging.info(f'βœ… IP {ip_address} aggiunto alla whitelist router {router_host} con timeout 60min') logging.info(f'πŸ›‘οΈ Whitelist router {router_host}: aggiunti {whitelist_added} IP con timeout') logging.info(f'🎯 Sincronizzazione router_data completata: {total_added} IP ddos2/ddos3-attackers aggiunti') # πŸ†• Gestione IP whitelist non ancora aggiunti (query separata per performance) cursor.execute(""" SELECT ip_address FROM router_data WHERE whitelist = 1 AND router_id = %s AND added_to_router = 0 AND retrieved_at > DATE_SUB(NOW(), INTERVAL 7 DAY) """, (router_id,)) pending_whitelist = cursor.fetchall() if pending_whitelist: logging.info(f'πŸ›‘οΈ Trovati {len(pending_whitelist)} IP whitelist pending per router {router_host}...') current_whitelist = get_address_list(ssh, 'whitelist') current_whitelist_set = {entry['ip_address'] for entry in current_whitelist if 'ip_address' in entry} added_whitelist = 0 for ip_entry in pending_whitelist: ip_address = ip_entry['ip_address'] if ip_address not in current_whitelist_set: if add_ip_to_list(ssh, ip_address, 'whitelist'): # πŸ†• CON TIMEOUT 60min cursor.execute(""" UPDATE router_data SET added_to_router = 1 WHERE ip_address = %s AND router_id = %s AND whitelist = 1 """, (ip_address, router_id)) db.commit() added_whitelist += 1 whitelist_timeout_applied += 1 # πŸ†• Conta timeout if added_whitelist > 0: logging.info(f'πŸ›‘οΈ Whitelist pending router {router_host}: aggiunti {added_whitelist} IP con timeout') return whitelist_timeout_applied except Error as e: logging.error(f"❌ Errore durante la sincronizzazione router_data per router {router_host}: {e}") return 0 def main(): logging.info('πŸš€ === AVVIO SISTEMA CONTROLLO ROUTER MIKROTIK ===') db = connect_to_database() cursor = db.cursor(dictionary=True) try: # πŸ†• FASE 0: Controllo whitelist globale e risoluzione conflitti logging.info('πŸ›‘οΈ === FASE 0: CONTROLLO WHITELIST GLOBALE ===') check_global_whitelist_conflicts(cursor, db) # πŸ†• Pulizia IP vecchi (ora gestisce correttamente le tabelle separate) logging.info('🧹 === FASE 1: PULIZIA IP OBSOLETI ===') cleanup_old_ips(cursor, db) # Recupera i router dal database logging.info('πŸ“‘ === FASE 2: RECUPERO ROUTER ===') routers = get_routers(cursor) logging.info('πŸ”„ === FASE 3: SINCRONIZZAZIONE ROUTER ===') successful_syncs = 0 failed_syncs = 0 total_ddos_timeouts = 0 total_whitelist_timeouts = 0 for router in routers: router_id = router['id'] router_host = router['ip_address'] ssh_username = router['ssh_username'] ssh_password = router['ssh_password'] logging.info(f'🎯 Elaborazione router {router_host} (ID: {router_id})...') ssh = connect_to_router(router_host, ssh_username, ssh_password) if ssh is None: failed_syncs += 1 logging.error(f'❌ Saltato router {router_host} - connessione fallita') continue try: # πŸ†• Verifica IP scaduti prima della sincronizzazione current_stats = check_expired_ips_on_router(ssh, router_host) # πŸ†• 0. Sincronizza whitelist globale (PRIMA di tutto) CON TIMEOUT global_added, global_timeouts = sync_global_whitelist_to_routers(cursor, db, ssh, router_host) total_whitelist_timeouts += global_timeouts # 1. Sincronizza ddos_detect_v03 da ip_list (con filtro whitelist globale) sync_ip_list_to_routers(cursor, db, ssh, router_id, router_host) # 2. Sincronizza ddos2-attackers, ddos3-attackers e whitelist da router_data router_whitelist_timeouts = sync_router_data_to_routers(cursor, db, ssh, router_id, router_host) total_whitelist_timeouts += router_whitelist_timeouts # πŸ†• Verifica finale per statistiche timeout final_stats = check_expired_ips_on_router(ssh, router_host) ddos_v03_count = final_stats.get('ddos_detect_v03', 0) if ddos_v03_count > 0: total_ddos_timeouts += ddos_v03_count successful_syncs += 1 logging.info(f'βœ… Router {router_host} sincronizzato con successo') except Exception as e: failed_syncs += 1 logging.error(f'❌ Errore durante elaborazione router {router_host}: {e}') finally: ssh.close() logging.info(f'πŸ” Connessione SSH al router {router_host} chiusa.') # Statistiche finali logging.info('πŸ“Š === STATISTICHE FINALI ===') logging.info(f'βœ… Router sincronizzati con successo: {successful_syncs}') logging.info(f'❌ Router falliti: {failed_syncs}') logging.info(f'πŸ“‘ Router totali processati: {len(routers)}') logging.info(f'⏰ IP ddos_detect_v03 con timeout 60min attivi: {total_ddos_timeouts}') logging.info(f'πŸ›‘οΈ IP whitelist con timeout 60min applicati: {total_whitelist_timeouts}') logging.info('🎯 Gestione automatica whitelist tramite campo router_data.whitelist=1') logging.info('πŸ›‘οΈ Protezione automatica whitelist globale applicata') logging.info('⏰ NUOVO: Timeout 60min applicato anche alla whitelist per maggiore sicurezza') except Exception as e: logging.error(f'❌ Errore critico nel main: {e}') finally: cursor.close() db.close() logging.info('πŸ”— Connessione al database chiusa.') logging.info('🏁 === FINE ESECUZIONE SISTEMA CONTROLLO ROUTER ===') if __name__ == '__main__': main()