Skip to content

Commit c2219aa

Browse files
frenckclaudeedenhaus
authored
Handle invalid IP addresses in ip_bans.yaml gracefully (home-assistant#157232)
Co-authored-by: Claude <[email protected]> Co-authored-by: Robert Resch <[email protected]>
1 parent 2cd0637 commit c2219aa

File tree

2 files changed

+58
-0
lines changed

2 files changed

+58
-0
lines changed

homeassistant/components/http/ban.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,9 @@ async def async_load(self) -> None:
233233
except vol.Invalid as err:
234234
_LOGGER.error("Failed to load IP ban %s: %s", ip_info, err)
235235
continue
236+
except ValueError:
237+
_LOGGER.error("Failed to load IP ban: invalid IP address %s", ip_ban)
238+
continue
236239

237240
self.ip_bans_lookup = ip_bans_lookup
238241

tests/components/http/test_ban.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from http import HTTPStatus
44
from ipaddress import ip_address
5+
import logging
56
import os
67
from unittest.mock import AsyncMock, Mock, mock_open, patch
78

@@ -113,6 +114,60 @@ async def test_access_from_banned_ip_with_partially_broken_yaml_file(
113114
assert "Failed to load IP ban" in caplog.text
114115

115116

117+
async def test_access_from_banned_ip_with_invalid_ip_entry(
118+
hass: HomeAssistant,
119+
aiohttp_client: ClientSessionGenerator,
120+
caplog: pytest.LogCaptureFixture,
121+
) -> None:
122+
"""Test that invalid IP addresses in ban file are skipped gracefully.
123+
124+
An invalid IP entry (e.g., with typo like "Eo128.199.160.243") should
125+
be logged as an error and skipped, allowing valid bans to still load.
126+
The test ensures that valid IPs after invalid ones are still processed.
127+
"""
128+
app = web.Application()
129+
app[KEY_HASS] = hass
130+
setup_bans(hass, app, 5)
131+
set_real_ip = mock_real_ip(app)
132+
133+
# Invalid IPs interspersed between valid ones to ensure continue works
134+
data = {
135+
"Eo128.199.160.243": {"banned_at": "2024-07-06T14:07:46"},
136+
BANNED_IPS[0]: {"banned_at": "2016-11-16T19:20:03"},
137+
"invalidip": {"banned_at": "2024-07-06T14:07:46"},
138+
BANNED_IPS[1]: {"banned_at": "2016-11-16T19:20:03"},
139+
}
140+
141+
with patch(
142+
"homeassistant.components.http.ban.load_yaml_config_file",
143+
return_value=data,
144+
):
145+
client = await aiohttp_client(app)
146+
147+
# Verify exactly 2 valid IPs were loaded (invalid ones skipped)
148+
manager = app[KEY_BAN_MANAGER]
149+
assert len(manager.ip_bans_lookup) == len(BANNED_IPS)
150+
151+
# Valid banned IPs should still be blocked (even though they came after invalid ones)
152+
for remote_addr in BANNED_IPS:
153+
set_real_ip(remote_addr)
154+
resp = await client.get("/")
155+
assert resp.status == HTTPStatus.FORBIDDEN
156+
157+
# Non-banned IP should have access
158+
set_real_ip("192.168.1.1")
159+
resp = await client.get("/")
160+
assert resp.status == HTTPStatus.NOT_FOUND
161+
162+
# Check that both invalid IP entries were logged
163+
for ip in ("Eo128.199.160.243", "invalidip"):
164+
assert (
165+
"homeassistant.components.http.ban",
166+
logging.ERROR,
167+
f"Failed to load IP ban: invalid IP address {ip}",
168+
) in caplog.record_tuples
169+
170+
116171
async def test_no_ip_bans_file(
117172
hass: HomeAssistant, aiohttp_client: ClientSessionGenerator
118173
) -> None:

0 commit comments

Comments
 (0)