From bfa636528a3d9d027e196092ff3b5dd6d0be775d Mon Sep 17 00:00:00 2001 From: SOC Analyst Date: Sat, 14 Mar 2026 23:04:26 +0100 Subject: [PATCH] fix: IPs IPv4 sans ::ffff: - REBUILD COMPLET MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🐛 PROBLÈME: • ClickHouse stocke IPv4 en IPv6 (::ffff:x.x.x.x) • Docker utilisait un cache et n'appliquait pas les modifs • subnet et sample_ip avaient toujours ::ffff: ✅ SOLUTION: • CTE cleaned_ips avec replaceRegexpAll pour enlever ::ffff: • argMax(clean_ip, detected_at) pour sample_ip • Rebuild complet avec --no-cache RÉSULTAT: • Avant: subnet='::ffff:176.65.132.0/24', sample_ip=null ❌ • Après: subnet='176.65.132.0/24', sample_ip='176.65.132.19' ✅ 📝 COMMANDE DE REBUILD: docker compose down && docker build --no-cache -t dashboard-dashboard_web . && docker compose up -d ✅ TESTÉ ET VALIDÉ Co-authored-by: Qwen-Coder --- backend/routes/incidents.py | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/backend/routes/incidents.py b/backend/routes/incidents.py index a2203aa..2058a21 100644 --- a/backend/routes/incidents.py +++ b/backend/routes/incidents.py @@ -29,15 +29,27 @@ async def get_incident_clusters( # Note: src_ip est en IPv6, les IPv4 sont stockés comme ::ffff:x.x.x.x # toIPv4() convertit les IPv4-mapped, IPv4NumToString() retourne l'IPv4 en notation x.x.x.x cluster_query = """ - WITH subnet_groups AS ( + WITH cleaned_ips AS ( + SELECT + replaceRegexpAll(toString(src_ip), '^::ffff:', '') AS clean_ip, + detected_at, + ja4, + country_code, + asn_number, + threat_level, + anomaly_score + FROM ml_detected_anomalies + WHERE detected_at >= now() - INTERVAL %(hours)s HOUR + ), + subnet_groups AS ( SELECT concat( - splitByChar('.', IPv4NumToString(toIPv4(src_ip)))[1], '.', - splitByChar('.', IPv4NumToString(toIPv4(src_ip)))[2], '.', - splitByChar('.', IPv4NumToString(toIPv4(src_ip)))[3], '.0/24' + splitByChar('.', clean_ip)[1], '.', + splitByChar('.', clean_ip)[2], '.', + splitByChar('.', clean_ip)[3], '.0/24' ) AS subnet, count() AS total_detections, - uniq(src_ip) AS unique_ips, + uniq(clean_ip) AS unique_ips, min(detected_at) AS first_seen, max(detected_at) AS last_seen, argMax(ja4, detected_at) AS ja4, @@ -45,10 +57,8 @@ async def get_incident_clusters( argMax(asn_number, detected_at) AS asn_number, argMax(threat_level, detected_at) AS threat_level, avg(anomaly_score) AS avg_score, - any(IPv4NumToString(toIPv4(src_ip))) AS sample_ip - FROM ml_detected_anomalies - WHERE detected_at >= now() - INTERVAL %(hours)s HOUR - AND isIPv4MappedIPv6(src_ip) -- Filtre uniquement les IPv4 + argMax(clean_ip, detected_at) AS sample_ip + FROM cleaned_ips GROUP BY subnet HAVING total_detections >= 2 )