fix(wifi): check _setup_iptables_redirect return; fix hostapd LED SSID; teardown on exception

- Both AP startup paths (hostapd and nmcli) now check the bool returned by
  _setup_iptables_redirect() and treat False as a hard failure: the hostapd
  path stops hostapd/dnsmasq and returns an error tuple; the nmcli path brings
  down and deletes the LEDMatrix-Setup-AP profile and clears the LED message

- _enable_ap_mode_hostapd's LED message now calls _validate_ap_config() to get
  the same sanitized SSID that _create_hostapd_config() uses, so the displayed
  name always matches the AP actually broadcast by hostapd

- _setup_iptables_redirect's outer except block now calls
  _teardown_iptables_redirect() before returning False so partial iptables/
  ip_forward state is always cleaned up on unexpected exceptions; cleanup
  exceptions are caught and logged separately

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Chuck
2026-05-01 09:10:00 -04:00
parent 9490cf6023
commit 3f66d15af7

View File

@@ -788,6 +788,10 @@ class WiFiManager:
return True
except Exception as e:
logger.warning(f"Could not set up iptables redirect: {e}")
try:
self._teardown_iptables_redirect()
except Exception as cleanup_e:
logger.warning(f"Cleanup after iptables redirect exception also failed: {cleanup_e}")
return False
def _teardown_iptables_redirect(self) -> None:
@@ -1824,10 +1828,17 @@ class WiFiManager:
return False, f"Failed to start dnsmasq: {result.stderr}"
# Set up iptables port forwarding (port 80 → 5000) and save ip_forward state
self._setup_iptables_redirect()
if not self._setup_iptables_redirect():
logger.error("Captive-portal redirect setup failed; stopping AP services")
subprocess.run(["sudo", "systemctl", "stop", HOSTAPD_SERVICE],
capture_output=True, timeout=10)
subprocess.run(["sudo", "systemctl", "stop", DNSMASQ_SERVICE],
capture_output=True, timeout=10)
return False, "AP started but captive-portal redirect setup failed"
logger.info("AP mode enabled successfully")
ap_ssid = self.config.get("ap_ssid", DEFAULT_AP_SSID)
# Use the validated SSID so the displayed name matches what hostapd broadcast
ap_ssid, _ = self._validate_ap_config()
self._show_led_message(
f"WiFi Setup\n{ap_ssid}\nNo password\n192.168.4.1:5000", duration=10
)
@@ -1917,7 +1928,14 @@ class WiFiManager:
# NM's ipv4.method=shared manages ip_forward automatically, so we only
# need to add the iptables port-redirect rules for the captive portal.
self._setup_iptables_redirect()
if not self._setup_iptables_redirect():
logger.error("Captive-portal redirect setup failed; rolling back AP profile")
subprocess.run(["nmcli", "connection", "down", "LEDMatrix-Setup-AP"],
capture_output=True, timeout=10)
subprocess.run(["nmcli", "connection", "delete", "LEDMatrix-Setup-AP"],
capture_output=True, timeout=10)
self._clear_led_message()
return False, "AP started but captive-portal redirect setup failed"
# Verify the AP is actually running
status = self._get_ap_status_nmcli()