Add LAN-broadcast lockdown, per-rotation MAC, leak audit panel
Tier-1 paranoid hardening: privacy_lan.py disables LLMNR/NetBIOS/mDNS with reversible snapshot; service rotates MAC on every chain rotation when enabled; leak_audit.py probes every leak surface (IP, DNS, IPv6, WPAD, GPO, ProxySettingsPerUser, LAN broadcast, VPN, WebRTC) and renders pass/fail in Privacy tab. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -36,6 +36,7 @@ from .firewall import (
|
||||
request_admin_relaunch,
|
||||
)
|
||||
from .dns_leak import check_dns_leak_hint, flush_dns_cache
|
||||
from .leak_audit import AuditReport, run_audit_sync
|
||||
from .browser_launcher import (
|
||||
BrowserConfig,
|
||||
BrowserSession,
|
||||
@@ -1083,10 +1084,12 @@ def main() -> None:
|
||||
"Applied on Start, restored on Stop. Admin required for MAC, hostname, IPv6, and WebRTC.",
|
||||
)
|
||||
mac_var = ctk.BooleanVar(value=s.mac_spoof_enabled)
|
||||
mac_rotate_var = ctk.BooleanVar(value=s.mac_rotate_on_chain_rotate)
|
||||
host_var = ctk.BooleanVar(value=s.spoof_hostname_enabled)
|
||||
dns_flush_var = ctk.BooleanVar(value=s.flush_dns_on_rotate)
|
||||
ipv6_var = ctk.BooleanVar(value=s.disable_ipv6_while_active)
|
||||
webrtc_var = ctk.BooleanVar(value=s.harden_webrtc_enabled)
|
||||
lan_var = ctk.BooleanVar(value=s.lan_lockdown_enabled)
|
||||
|
||||
def _priv_toggle(parent: Any, text: str, var: ctk.BooleanVar, tip: str = "") -> ctk.CTkCheckBox:
|
||||
cb = ctk.CTkCheckBox(
|
||||
@@ -1100,6 +1103,10 @@ def main() -> None:
|
||||
toggles_card, "Randomize MAC addresses on physical adapters", mac_var,
|
||||
"Changes NIC MAC values while chain runs (admin required).",
|
||||
)
|
||||
_priv_toggle(
|
||||
toggles_card, "Re-randomize MAC on EVERY chain rotation (paranoid)", mac_rotate_var,
|
||||
"Mutates MAC every time the chain rotates — prevents long-session correlation.",
|
||||
)
|
||||
_priv_toggle(
|
||||
toggles_card, "Spoof computer / NetBIOS hostname", host_var,
|
||||
"Temporarily renames machine identity while active (admin required).",
|
||||
@@ -1118,6 +1125,13 @@ def main() -> None:
|
||||
webrtc_var,
|
||||
"Applies Windows policy to block direct WebRTC UDP bypass in Chromium browsers.",
|
||||
)
|
||||
_priv_toggle(
|
||||
toggles_card,
|
||||
"LAN lockdown: kill LLMNR / NetBIOS / mDNS hostname broadcasts",
|
||||
lan_var,
|
||||
"Stops your machine from advertising its hostname on the local network "
|
||||
"(admin required, reversible on stop).",
|
||||
)
|
||||
|
||||
fp_card = _priv_section(
|
||||
"Device fingerprint",
|
||||
@@ -1163,6 +1177,65 @@ def main() -> None:
|
||||
_btn(dns_btn_row, "Flush DNS now", _manual_dns_flush, w=110, h=28,
|
||||
fg_color=DIM).pack(side="left")
|
||||
|
||||
audit_card = _priv_section(
|
||||
"Leak audit (mission-critical)",
|
||||
"Probes every leak surface: IP, DNS, IPv6, WPAD, Group Policy, "
|
||||
"ProxySettingsPerUser, LLMNR / NetBIOS / mDNS, VPN, WebRTC policy.",
|
||||
)
|
||||
audit_box = ctk.CTkTextbox(
|
||||
audit_card, height=220, font=("Consolas", 10),
|
||||
fg_color=BG, text_color=TEXT, scrollbar_button_color=ACCENT,
|
||||
)
|
||||
audit_box.pack(fill="x", padx=12, pady=(4, 4))
|
||||
audit_box.insert("end", "Click 'Run audit' to probe live leak status.")
|
||||
audit_status_lbl = ctk.CTkLabel(
|
||||
audit_card, text="", font=(FONT, 11, "bold"), text_color=TEXT2,
|
||||
)
|
||||
audit_status_lbl.pack(anchor="w", padx=12, pady=(0, 4))
|
||||
|
||||
def _render_audit(rep: AuditReport) -> None:
|
||||
audit_box.delete("1.0", "end")
|
||||
for f in rep.findings:
|
||||
mark = "OK " if f.ok else "LEAK"
|
||||
line = f"[{mark}] {f.name:<34} {f.value}"
|
||||
if f.note:
|
||||
line += f" — {f.note}"
|
||||
audit_box.insert("end", line + "\n")
|
||||
bad = sum(1 for f in rep.findings if not f.ok)
|
||||
if rep.overall_ok:
|
||||
audit_status_lbl.configure(
|
||||
text="CLEAN — no leaks detected on probed surfaces.", text_color=GREEN
|
||||
)
|
||||
else:
|
||||
audit_status_lbl.configure(
|
||||
text=f"{bad} leak(s) detected — see report above.", text_color=RED
|
||||
)
|
||||
|
||||
def _run_audit_async() -> None:
|
||||
audit_status_lbl.configure(text="Running audit…", text_color=YELLOW)
|
||||
audit_box.delete("1.0", "end")
|
||||
audit_box.insert("end", "Probing every leak surface in parallel…\n")
|
||||
|
||||
def work() -> None:
|
||||
try:
|
||||
rep = run_audit_sync(
|
||||
f"http://{svc.settings.listen_addr()}",
|
||||
svc.settings.ip_check_url,
|
||||
timeout_seconds=min(12.0, svc.settings.validation_timeout_seconds),
|
||||
)
|
||||
except Exception as e:
|
||||
root.after(0, lambda: audit_status_lbl.configure(
|
||||
text=f"Audit failed: {e}", text_color=RED))
|
||||
return
|
||||
root.after(0, lambda: _render_audit(rep))
|
||||
|
||||
threading.Thread(target=work, daemon=True).start()
|
||||
|
||||
audit_btn_row = ctk.CTkFrame(audit_card, fg_color="transparent")
|
||||
audit_btn_row.pack(fill="x", padx=12, pady=(0, 10))
|
||||
_btn(audit_btn_row, "Run audit", _run_audit_async, w=120, h=28,
|
||||
fg_color=ACCENT2, hover_color=ACCENT).pack(side="left", padx=(0, 8))
|
||||
|
||||
_btn(priv_scroll, "Save privacy settings", lambda: _save_settings(verbose=True),
|
||||
w=200, h=34, font=(FONT, 12)).pack(anchor="w", padx=8, pady=12)
|
||||
|
||||
@@ -1232,9 +1305,11 @@ def main() -> None:
|
||||
ks_var.set(True)
|
||||
dns_flush_var.set(True)
|
||||
mac_var.set(False)
|
||||
mac_rotate_var.set(False)
|
||||
host_var.set(False)
|
||||
ipv6_var.set(False)
|
||||
webrtc_var.set(True)
|
||||
lan_var.set(False)
|
||||
br_force_proxy_var.set(True)
|
||||
br_disable_webrtc_var.set(True)
|
||||
br_rfp_var.set(True)
|
||||
@@ -1300,10 +1375,12 @@ def main() -> None:
|
||||
sources=src_list or Settings().sources,
|
||||
ip_check_url=entries["check_url"].get().strip() or Settings().ip_check_url,
|
||||
mac_spoof_enabled=bool(mac_var.get()),
|
||||
mac_rotate_on_chain_rotate=bool(mac_rotate_var.get()),
|
||||
spoof_hostname_enabled=bool(host_var.get()),
|
||||
flush_dns_on_rotate=bool(dns_flush_var.get()),
|
||||
disable_ipv6_while_active=bool(ipv6_var.get()),
|
||||
harden_webrtc_enabled=bool(webrtc_var.get()),
|
||||
lan_lockdown_enabled=bool(lan_var.get()),
|
||||
firefox_path=firefox_path_var.get().strip(),
|
||||
firefox_profile_dir=firefox_profile_var.get().strip(),
|
||||
browser_clear_on_close=bool(br_clear_var.get()),
|
||||
|
||||
Reference in New Issue
Block a user