Skip to content

Conversation

@Skyline-23
Copy link

This pull request improves network interface detection and multicast socket setup for sandboxed platforms where
ifaddr may return no adapters. When adapters are present, behavior is unchanged. The fallback uses a dummy UDP
connect (no traffic sent) solely to learn the default local IPv4.

Network interface detection improvements

  • get_private_addresses now probes the default IPv4 via a dummy UDP connect when no adapters are reported, keeping
    loopback filtering rules.

Multicast socket setup enhancements

  • mcast_socket falls back to the probed default IPv4 for IP_MULTICAST_IF/IP_ADD_MEMBERSHIP, with a final 0.0.0.0
    membership attempt if probing fails.
  • Binding remains "", avoiding port conflicts while only multicast membership targets the detected address.

@Skyline-23 Skyline-23 force-pushed the master branch 5 times, most recently from f96f17a to 91a5489 Compare December 15, 2025 14:36
ifaddr may return no adapters in sandboxed environments, which prevents mDNS multicast membership and leads to empty scan results. Detect a default IPv4 via a dummy UDP connect and use it for IP_MULTICAST_IF/ADD_MEMBERSHIP while keeping the socket bind on an empty string to avoid conflicts. Reuse the same probe fallback in get_private_addresses so callers still obtain a usable IPv4 when adapter enumeration is empty.
Copilot AI review requested due to automatic review settings January 23, 2026 10:44
@Skyline-23
Copy link
Author

Applied fix to avoid public IP for route probe; pushed commit ae6e10e to Skyline-23:master.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Improves behavior on sandboxed platforms where ifaddr.get_adapters() can return no interfaces by probing the default local IPv4 via a dummy UDP connect and using it for interface selection and multicast membership.

Changes:

  • Add a default-route probe target constant and use a UDP “connect” to infer the default local IPv4 when adapters are unavailable.
  • Enhance mcast_socket to attempt multicast membership using the probed interface (and fall back to 0.0.0.0 membership if probing fails).
  • Add a get_private_addresses fallback path to return the probed IPv4 when no addresses were found.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +100 to +102
# Fallback when no adapters are reported (e.g. sandboxed platforms).
if not addresses:
try:
Copy link

Copilot AI Jan 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

get_private_addresses fallback runs whenever addresses is empty, which also covers cases where adapters exist but only have public IPv4s. That expands behavior beyond the PR description (“when no adapters are reported”) and changes previous semantics for public-only hosts. Consider storing adapters = get_adapters() and only running the UDP-probe fallback when not adapters (or when no IPv4 addresses were enumerated).

Copilot uses AI. Check for mistakes.
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as probe:
probe.connect(_DEFAULT_ROUTE_PROBE)
detected = IPv4Address(probe.getsockname()[0])
if include_loopback or not detected.is_loopback:
Copy link

Copilot AI Jan 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the get_private_addresses fallback, the detected address is appended without checking detected.is_private. This can cause the function to return a globally-routable IP, contradicting the docstring/previous behavior (only ipaddr.is_private values were returned). Apply the same is_private filter in the fallback path (while still honoring include_loopback).

Suggested change
if include_loopback or not detected.is_loopback:
if detected.is_private or (detected.is_loopback and include_loopback):

Copilot uses AI. Check for mistakes.
Comment on lines +54 to +58
# Fallback for sandboxed platforms where ifaddr finds no adapters:
# detect default IPv4 via a dummy UDP connect and use it for multicast join.
try:
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as probe:
probe.connect(_DEFAULT_ROUTE_PROBE)
Copy link

Copilot AI Jan 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The UDP “default route probe” logic is duplicated in both mcast_socket and get_private_addresses. To avoid the two call sites drifting (e.g., different exception handling or filtering), consider extracting a small helper like _get_default_ipv4() and reusing it in both places.

Copilot uses AI. Check for mistakes.
Comment on lines +100 to +104
# Fallback when no adapters are reported (e.g. sandboxed platforms).
if not addresses:
try:
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as probe:
probe.connect(_DEFAULT_ROUTE_PROBE)
Copy link

Copilot AI Jan 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This new fallback changes observable behavior when get_adapters() returns an empty list (existing unit test tests/support/test_net.py::test_no_address currently expects []). Add/update tests to mock the UDP probe socket (connect/getsockname) so the fallback is deterministic and validated (both success and OSError paths).

Copilot uses AI. Check for mistakes.
Comment on lines +108 to +109
except OSError:
pass
Copy link

Copilot AI Jan 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'except' clause does nothing but pass and there is no explanatory comment.

Suggested change
except OSError:
pass
except OSError as ex:
_LOGGER.debug(
"Unable to determine fallback local address via UDP probe: %s", ex
)

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants