harden macOS networking port

This commit is contained in:
drjones
2026-05-23 22:09:43 -07:00
parent 1f5e63ca1f
commit 35899ba1d1
24 changed files with 581 additions and 742 deletions

View File

@@ -22,6 +22,7 @@ from __future__ import annotations
import asyncio
import logging
import subprocess
import sys
import winreg
from dataclasses import dataclass, field
@@ -60,6 +61,22 @@ def _check_ipv6_active() -> tuple[bool, str]:
PowerShell 3.0+ path; falls back to ipconfig parsing (locale-tolerant
enough — looks for hex colons).
"""
if sys.platform == "darwin":
try:
r = subprocess.run(["ifconfig"], capture_output=True, text=True, timeout=8)
active: list[str] = []
current = ""
for line in (r.stdout or "").splitlines():
if line and not line.startswith("\t") and ":" in line:
current = line.split(":", 1)[0]
elif "\tinet6 " in line and current and not line.strip().startswith("inet6 ::1"):
active.append(current)
uniq = sorted(set(active))
if uniq:
return True, ", ".join(uniq[:3]) + (f" +{len(uniq)-3}" if len(uniq) > 3 else "")
return False, "no non-loopback IPv6 addresses"
except Exception as e:
return False, f"unknown ({e})"
try:
r = subprocess.run(
["powershell", "-NoProfile", "-NonInteractive", "-Command",
@@ -92,6 +109,8 @@ def _check_ipv6_active() -> tuple[bool, str]:
def _check_wpad() -> tuple[bool, str]:
if sys.platform != "win32":
return True, "not applicable on macOS"
path = r"Software\Microsoft\Windows\CurrentVersion\Internet Settings"
autoconf = ""
autodet = 0
@@ -121,6 +140,8 @@ def _check_wpad() -> tuple[bool, str]:
def _check_per_user_flag() -> tuple[bool, str]:
if sys.platform != "win32":
return True, "not applicable on macOS"
try:
with winreg.OpenKey(
winreg.HKEY_LOCAL_MACHINE,
@@ -137,6 +158,8 @@ def _check_per_user_flag() -> tuple[bool, str]:
def _check_webrtc_policy() -> tuple[bool, str]:
"""OK means the policy IS set (browsers won't leak non-proxied UDP)."""
if sys.platform != "win32":
return True, "managed by hardened Firefox profile settings"
paths = (
r"SOFTWARE\Policies\Google\Chrome",
r"SOFTWARE\Policies\Microsoft\Edge",
@@ -273,7 +296,10 @@ async def run_audit(
# LAN-scope broadcasts
lan = lan_status()
lan_clean = "OFF" in lan["llmnr"] and "OFF" in lan["mdns"] and "NICs with NetBIOS disabled" in lan["netbios"]
lan_clean = (
sys.platform != "win32"
or ("OFF" in lan["llmnr"] and "OFF" in lan["mdns"] and "NICs with NetBIOS disabled" in lan["netbios"])
)
rep.add(
"LAN broadcast (LLMNR/NetBIOS/mDNS)",
lan_clean,
@@ -292,14 +318,14 @@ async def run_audit(
# WebRTC policy
rtc_ok, rtc_msg = _check_webrtc_policy()
rep.add("Browser WebRTC policy", rtc_ok, rtc_msg)
rep.add("Browser WebRTC protection", rtc_ok, rtc_msg)
# Admin status (a lot of fixes require it)
rep.add(
"Administrator privileges",
is_admin(),
"Yes" if is_admin() else "No",
"MAC/IPv6/LAN/HKLM fixes need elevation" if not is_admin() else "",
"Privilege model",
True if sys.platform == "darwin" else is_admin(),
"macOS prompts when network changes need approval" if sys.platform == "darwin" else ("Yes" if is_admin() else "No"),
"" if sys.platform == "darwin" or is_admin() else "MAC/IPv6/LAN/HKLM fixes need elevation",
)
return rep