fix(config_flow): always retry historically-confirmed DTLS ports (#192)

The liveness sweep's ICMP-based verdict isn't trustworthy on every network
path -- a segregated-VLAN report showed it calling three closed ports live
while missing the one port a concurrent nmap scan found genuinely
open|filtered, which also happened to be one of our two historically
confirmed DTLS ports. Rather than trust a "not live" verdict against that
prior, always give PREFERRED_PROBE_PORTS a real handshake attempt even when
the sweep excludes them, bounded to at most those two extra attempts.

This is a stop-gap for the reported failure mode, not a full fix for the
sweep's underlying unreliability -- left a comment on the issue with the
diagnosis and flagged the sweep itself for a deeper redesign.
This commit is contained in:
Marc Billow committed 2026-07-29 12:53:56 +00:00
1 parent 7fe9e2a975
commit e8df8f7b0c
2 files changed
+43 -1

No files matched your search

+32
View File
@@ -105,6 +105,38 @@ def test_find_live_ports_detects_silent_port(socket_enabled) -> None:
assert result == [live_port]
def test_find_live_ports_rescues_preferred_ports_the_sweep_missed(
socket_enabled,
) -> None:
"""Issue #192: a segregated VLAN made the ICMP-based sweep call three
closed ports live while missing the one port (49154, a historically
confirmed DTLS port) that nmap showed as genuinely open|filtered. The
sweep's verdict on a preferred port shouldn't be trusted blindly --
it must always come back as a candidate even if the sweep marked it
dead, so the config flow gets a real handshake attempt against it."""
import socket
from custom_components.localthings.config_flow import _find_live_ports
# Bind and immediately close a socket on 49154 so loopback refuses
# datagrams to it -- standing in for the sweep wrongly ruling out a
# port we have strong prior evidence for.
reserved = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
reserved.bind(('127.0.0.1', 49154))
reserved.close()
live_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
live_sock.bind(('127.0.0.1', 0))
live_port = live_sock.getsockname()[1]
try:
result = _find_live_ports('127.0.0.1', [49154, live_port], 0.8)
finally:
live_sock.close()
assert set(result) == {49154, live_port}
async def test_probe_uses_discovered_low_port(hass: HomeAssistant, monkeypatch) -> None:
"""A device that only answers on 49153 — outside the historical
49154/49155 pair — is found by the liveness sweep and its port is stored