Don't abort zeroconf discovery for IPv6-only devices (#66455)

This commit is contained in:
Joshua Roys 2022-02-13 16:24:23 -05:00 committed by GitHub
parent ffcac67d99
commit bc2cc42955
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 21 additions and 5 deletions

View file

@ -541,9 +541,9 @@ def info_from_service(service: AsyncServiceInfo) -> ZeroconfServiceInfo | None:
if isinstance(value, bytes): if isinstance(value, bytes):
properties[key] = value.decode("utf-8") properties[key] = value.decode("utf-8")
if not (addresses := service.addresses): if not (addresses := service.addresses or service.parsed_addresses()):
return None return None
if (host := _first_non_link_local_or_v6_address(addresses)) is None: if (host := _first_non_link_local_address(addresses)) is None:
return None return None
return ZeroconfServiceInfo( return ZeroconfServiceInfo(
@ -557,11 +557,18 @@ def info_from_service(service: AsyncServiceInfo) -> ZeroconfServiceInfo | None:
) )
def _first_non_link_local_or_v6_address(addresses: list[bytes]) -> str | None: def _first_non_link_local_address(
"""Return the first ipv6 or non-link local ipv4 address.""" addresses: list[bytes] | list[str],
) -> str | None:
"""Return the first ipv6 or non-link local ipv4 address, preferring IPv4."""
for address in addresses: for address in addresses:
ip_addr = ip_address(address) ip_addr = ip_address(address)
if not ip_addr.is_link_local or ip_addr.version == 6: if not ip_addr.is_link_local and ip_addr.version == 4:
return str(ip_addr)
# If we didn't find a good IPv4 address, check for IPv6 addresses.
for address in addresses:
ip_addr = ip_address(address)
if not ip_addr.is_link_local and ip_addr.version == 6:
return str(ip_addr) return str(ip_addr)
return None return None

View file

@ -780,6 +780,15 @@ async def test_info_from_service_prefers_ipv4(hass):
assert info.host == "192.168.66.12" assert info.host == "192.168.66.12"
async def test_info_from_service_can_return_ipv6(hass):
"""Test that IPv6-only devices can be discovered."""
service_type = "_test._tcp.local."
service_info = get_service_info_mock(service_type, f"test.{service_type}")
service_info.addresses = ["fd11:1111:1111:0:1234:1234:1234:1234"]
info = zeroconf.info_from_service(service_info)
assert info.host == "fd11:1111:1111:0:1234:1234:1234:1234"
async def test_get_instance(hass, mock_async_zeroconf): async def test_get_instance(hass, mock_async_zeroconf):
"""Test we get an instance.""" """Test we get an instance."""
assert await async_setup_component(hass, zeroconf.DOMAIN, {zeroconf.DOMAIN: {}}) assert await async_setup_component(hass, zeroconf.DOMAIN, {zeroconf.DOMAIN: {}})