fix(toolbox): #ads surfaces the DNS-layer blocking (the real ad-blocker)
Some checks are pending
License Headers / check (push) Waiting to run

'Pubs bloquées: 0' was misleading — ad-blocking moved to the DNS layer
(secubox-adblock-sync #740: Unbound sinkholes 757,946 ad/tracker domains via
always_nxdomain), so ads die BEFORE reaching the engine → the engine's 204
counter reads ~0. /admin/ad-stats now includes dns_sinkhole (from ad-guard
sinkhole-status.json) and the #ads tab leads with a '🛡️ Blocage DNS' card
(domains + rules + sources), relabels the engine card '204 moteur MITM'. Live gk2.
This commit is contained in:
CyberMind-FR 2026-07-04 15:35:04 +02:00
parent 2f798859cc
commit 7c45bd2eaa
2 changed files with 36 additions and 1 deletions

View File

@ -3229,6 +3229,23 @@ async def admin_ad_stats(hours: int = 24) -> dict:
except Exception:
nd = 0
out["network_drops"] = nd
# DNS-layer ad-blocking (secubox-adblock-sync #740): the Unbound sinkhole
# kills most ads BEFORE they reach the engine, so total_blocked (204s) reads
# low/0. Surface the real DNS blocking so the tab isn't misleading — "0
# engine blocks" ≠ "no ad-blocking".
try:
import json as _json
s = _json.loads(Path("/var/lib/secubox/ad-guard/sinkhole-status.json").read_text())
comp = s.get("compile", {}) or {}
out["dns_sinkhole"] = {
"enabled": bool(s.get("enabled")),
"domains": int(s.get("blocked", 0) or 0),
"net_rules": int(comp.get("net_rules", 0) or 0),
"cosmetic_domains": int(comp.get("cosmetic_domains", 0) or 0),
"sources": sorted((comp.get("sources") or {}).keys()),
}
except Exception:
out["dns_sinkhole"] = {"enabled": None}
return out

View File

@ -177,8 +177,13 @@
<button onclick="loadAds()">🔁 Refresh</button>
</div>
<div id="ads-section" class="grid">
<div class="card" style="grid-column:1/-1;border-left:3px solid var(--matrix-green,#00ff41)">
<h2>🛡️ Blocage DNS (couche principale)</h2>
<div class="kv" id="ads-dns"><span class="k">loading…</span><span class="v"></span></div>
<p style="font-size:.72rem;color:var(--p31-dim,#888);margin-top:.4rem">La plupart des pubs sont tuées ICI, au DNS, avant d'atteindre le moteur MITM — le compteur « 204 » ci-dessous ne mesure QUE ce qui passe le DNS.</p>
</div>
<div class="card" style="grid-column:1/-1">
<h2>🛑 Trackers & pubs bloqués (24h)</h2>
<h2>🛑 Bloqués par le moteur MITM (204, 24h)</h2>
<div class="kv" id="ads-kpi"><span class="k">loading…</span><span class="v"></span></div>
</div>
<div class="card" style="grid-column:1/-1">
@ -631,6 +636,19 @@ async function loadAds() {
const kpi = document.getElementById('ads-kpi');
const esc = s => String(s).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
if (!d || d.__error) { kpi.innerHTML = `<span class="k">err</span><span class="v">${(d&&d.__error)||'no data'}</span>`; return; }
// #ads — DNS-layer blocking (the real ad-blocker; engine 204s are secondary)
const dns = d.dns_sinkhole || {};
const dnsEl = document.getElementById('ads-dns');
if (dnsEl) {
dnsEl.innerHTML = dns.enabled
? `<span class="k">État</span> <span class="v" style="color:var(--matrix-green,#00ff41)">🟢 actif</span>`
+ ` <span class="k">Domaines pub/tracker sinkholés</span> <span class="v">${(dns.domains||0).toLocaleString('fr-FR')}</span>`
+ ` <span class="k">Règles réseau</span> <span class="v">${(dns.net_rules||0).toLocaleString('fr-FR')}</span>`
+ ` <span class="k">Sources</span> <span class="v">${(dns.sources||[]).join(', ')||'—'}</span>`
: (dns.enabled === false
? `<span class="k">État</span> <span class="v" style="color:var(--cinnabar,#e63946)">⚪ désactivé</span>`
: `<span class="k">État</span> <span class="v">indisponible</span>`);
}
kpi.innerHTML = `<span class="k">Pubs bloquées (204)</span> <span class="v">${d.total_blocked||0}</span>`
+ ` <span class="k">Trackers détectés</span> <span class="v">${d.trackers_seen||0}</span>`
+ ` <span class="k">Pages nettoyées</span> <span class="v">${d.pages_cleaned||0}</span>`