diff --git a/python_ml/main.py b/python_ml/main.py index 4b868c3..6201f44 100644 --- a/python_ml/main.py +++ b/python_ml/main.py @@ -111,6 +111,10 @@ class UnblockIPRequest(BaseModel): ip_address: str list_name: str = "ddos_blocked" +class BlockAllCriticalRequest(BaseModel): + min_score: float = 80.0 + list_name: str = "ddos_blocked" + # API Endpoints @@ -499,6 +503,94 @@ async def block_ip(request: BlockIPRequest): except Exception as e: raise HTTPException(status_code=500, detail=str(e)) +@app.post("/block-all-critical") +async def block_all_critical(request: BlockAllCriticalRequest): + """Blocca tutti gli IP critici non ancora bloccati sui router""" + try: + conn = get_db_connection() + cursor = conn.cursor(cursor_factory=RealDictCursor) + + cursor.execute("SELECT * FROM routers WHERE enabled = true") + routers = cursor.fetchall() + + if not routers: + raise HTTPException(status_code=400, detail="Nessun router configurato") + + cursor.execute(""" + SELECT DISTINCT source_ip, MAX(CAST(risk_score AS FLOAT)) as max_score, + MAX(anomaly_type) as anomaly_type + FROM detections + WHERE CAST(risk_score AS FLOAT) >= %s + AND blocked = false + AND source_ip NOT IN ( + SELECT ip_address FROM whitelist WHERE active = true + ) + GROUP BY source_ip + ORDER BY max_score DESC + """, (request.min_score,)) + + unblocked_ips = cursor.fetchall() + + if not unblocked_ips: + cursor.close() + conn.close() + return { + "message": "Nessun IP critico da bloccare", + "blocked": 0, + "total_critical": 0, + "skipped_whitelisted": 0 + } + + blocked_count = 0 + failed_count = 0 + results_detail = [] + + for ip_row in unblocked_ips: + ip = ip_row['source_ip'] + score = ip_row['max_score'] + anomaly = ip_row['anomaly_type'] + + try: + block_results = await mikrotik_manager.block_ip_on_all_routers( + routers, + ip, + list_name=request.list_name, + comment=f"IDS bulk-block: {anomaly} (score: {score:.0f})" + ) + + if any(block_results.values()): + cursor.execute(""" + UPDATE detections + SET blocked = true, blocked_at = NOW() + WHERE source_ip = %s AND blocked = false + """, (ip,)) + blocked_count += 1 + results_detail.append({"ip": ip, "score": score, "status": "blocked"}) + else: + failed_count += 1 + results_detail.append({"ip": ip, "score": score, "status": "failed"}) + + except Exception as e: + failed_count += 1 + results_detail.append({"ip": ip, "score": score, "status": f"error: {str(e)}"}) + + conn.commit() + cursor.close() + conn.close() + + return { + "message": f"Blocco massivo completato: {blocked_count} IP bloccati, {failed_count} falliti", + "blocked": blocked_count, + "failed": failed_count, + "total_critical": len(unblocked_ips), + "details": results_detail[:50] + } + + except HTTPException: + raise + except Exception as e: + raise HTTPException(status_code=500, detail=str(e)) + @app.post("/unblock-ip") async def unblock_ip(request: UnblockIPRequest): """Sblocca un IP da tutti i router""" diff --git a/server/routes.ts b/server/routes.ts index b2d795a..9973681 100644 --- a/server/routes.ts +++ b/server/routes.ts @@ -622,6 +622,42 @@ export async function registerRoutes(app: Express): Promise { } }); + app.post("/api/ml/block-all-critical", async (req, res) => { + try { + const { min_score = 80 } = req.body; + + const controller = new AbortController(); + const timeout = setTimeout(() => controller.abort(), 300000); // 5 min timeout + + const response = await fetch(`${ML_BACKEND_URL}/block-all-critical`, { + method: "POST", + headers: getMLBackendHeaders(), + body: JSON.stringify({ min_score }), + signal: controller.signal, + }); + + clearTimeout(timeout); + + if (!response.ok) { + const errorData = await response.json().catch(() => ({})); + return res.status(response.status).json({ + error: errorData.detail || "Block all critical failed", + }); + } + + const data = await response.json(); + res.json(data); + } catch (error: any) { + if (error.name === 'AbortError') { + return res.status(504).json({ error: "Timeout - operazione troppo lunga" }); + } + if (error.code === 'ECONNREFUSED') { + return res.status(503).json({ error: "ML backend non disponibile" }); + } + res.status(500).json({ error: error.message || "Errore blocco massivo" }); + } + }); + app.get("/api/ml/stats", async (req, res) => { try { const controller = new AbortController();