diff --git a/homeassistant/components/dhcp/__init__.py b/homeassistant/components/dhcp/__init__.py index 2afe53422fb..b8a12a937e3 100644 --- a/homeassistant/components/dhcp/__init__.py +++ b/homeassistant/components/dhcp/__init__.py @@ -9,7 +9,6 @@ from dataclasses import dataclass from datetime import timedelta from fnmatch import translate from functools import lru_cache -from ipaddress import ip_address as make_ip_address import logging import os import re @@ -22,6 +21,7 @@ from aiodiscover.discovery import ( IP_ADDRESS as DISCOVERY_IP_ADDRESS, MAC_ADDRESS as DISCOVERY_MAC_ADDRESS, ) +from cached_ipaddress import cached_ip_addresses from scapy.config import conf from scapy.error import Scapy_Exception @@ -153,7 +153,10 @@ class WatcherBase(ABC): self, ip_address: str, hostname: str, mac_address: str ) -> None: """Process a client.""" - made_ip_address = make_ip_address(ip_address) + if (made_ip_address := cached_ip_addresses(ip_address)) is None: + # Ignore invalid addresses + _LOGGER.debug("Ignoring invalid IP Address: %s", ip_address) + return if ( made_ip_address.is_link_local diff --git a/homeassistant/components/dhcp/manifest.json b/homeassistant/components/dhcp/manifest.json index db6e5948196..f190f0ab10e 100644 --- a/homeassistant/components/dhcp/manifest.json +++ b/homeassistant/components/dhcp/manifest.json @@ -7,5 +7,9 @@ "iot_class": "local_push", "loggers": ["aiodiscover", "dnspython", "pyroute2", "scapy"], "quality_scale": "internal", - "requirements": ["scapy==2.5.0", "aiodiscover==1.6.0"] + "requirements": [ + "scapy==2.5.0", + "aiodiscover==1.6.0", + "cached_ipaddress==0.3.0" + ] } diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index 721801c176d..3f95e36a00b 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -16,6 +16,7 @@ bleak==0.21.1 bluetooth-adapters==0.16.2 bluetooth-auto-recovery==1.2.3 bluetooth-data-tools==1.19.0 +cached_ipaddress==0.3.0 certifi>=2021.5.30 ciso8601==2.3.0 cryptography==41.0.7 diff --git a/requirements_all.txt b/requirements_all.txt index af0b9d63679..530670b62bd 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -608,6 +608,9 @@ btsmarthub-devicelist==0.2.3 # homeassistant.components.buienradar buienradar==1.0.5 +# homeassistant.components.dhcp +cached_ipaddress==0.3.0 + # homeassistant.components.caldav caldav==1.3.8 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 7385ed2e953..665a4a5fa05 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -507,6 +507,9 @@ bthome-ble==3.3.1 # homeassistant.components.buienradar buienradar==1.0.5 +# homeassistant.components.dhcp +cached_ipaddress==0.3.0 + # homeassistant.components.caldav caldav==1.3.8 diff --git a/tests/components/dhcp/test_init.py b/tests/components/dhcp/test_init.py index 5013568ad39..a63300b1ea2 100644 --- a/tests/components/dhcp/test_init.py +++ b/tests/components/dhcp/test_init.py @@ -828,6 +828,36 @@ async def test_device_tracker_hostname_and_macaddress_after_start_hostname_missi assert len(mock_init.mock_calls) == 0 +async def test_device_tracker_invalid_ip_address( + hass: HomeAssistant, caplog: pytest.LogCaptureFixture +) -> None: + """Test an invalid ip address.""" + + with patch.object(hass.config_entries.flow, "async_init") as mock_init: + device_tracker_watcher = dhcp.DeviceTrackerWatcher( + hass, + {}, + [{"domain": "mock-domain", "hostname": "connect", "macaddress": "B8B7F1*"}], + ) + await device_tracker_watcher.async_start() + await hass.async_block_till_done() + hass.states.async_set( + "device_tracker.august_connect", + STATE_HOME, + { + ATTR_IP: "invalid", + ATTR_SOURCE_TYPE: SourceType.ROUTER, + ATTR_MAC: "B8:B7:F1:6D:B5:33", + }, + ) + await hass.async_block_till_done() + await device_tracker_watcher.async_stop() + await hass.async_block_till_done() + + assert "Ignoring invalid IP Address: invalid" in caplog.text + assert len(mock_init.mock_calls) == 0 + + async def test_device_tracker_ignore_self_assigned_ips_before_start( hass: HomeAssistant, ) -> None: