Skip to content

Commit 97e0b66

Browse files
authored
Handle duplicate goodbye answers in the same packet (#928)
- Solves an exception being thrown when we tried to remove the known answer from the cache when the second goodbye answer in the same packet was processed - We previously swallowed all exceptions on cache removal so this was not visible until 0.32.x which removed the broad exception catch Fixes #926
1 parent 73e3d18 commit 97e0b66

2 files changed

Lines changed: 34 additions & 2 deletions

File tree

tests/test_handlers.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1122,3 +1122,35 @@ async def test_guard_against_low_ptr_ttl():
11221122
assert incoming_answer_normal.ttl == const._DNS_OTHER_TTL
11231123
assert zc.cache.async_get_unique(good_bye_answer) is None
11241124
await aiozc.async_close()
1125+
1126+
1127+
@pytest.mark.asyncio
1128+
async def test_duplicate_goodbye_answers_in_packet():
1129+
"""Ensure we do not throw an exception when there are duplicate goodbye records in a packet."""
1130+
aiozc = AsyncZeroconf(interfaces=['127.0.0.1'])
1131+
zc = aiozc.zeroconf
1132+
answer_with_normal_ttl = r.DNSPointer(
1133+
"myservicelow_tcp._tcp.local.",
1134+
const._TYPE_PTR,
1135+
const._CLASS_IN | const._CLASS_UNIQUE,
1136+
const._DNS_OTHER_TTL,
1137+
'host.local.',
1138+
)
1139+
good_bye_answer = r.DNSPointer(
1140+
"myservicelow_tcp._tcp.local.",
1141+
const._TYPE_PTR,
1142+
const._CLASS_IN | const._CLASS_UNIQUE,
1143+
0,
1144+
'host.local.',
1145+
)
1146+
response = r.DNSOutgoing(const._FLAGS_QR_RESPONSE)
1147+
response.add_answer_at_time(answer_with_normal_ttl, 0)
1148+
incoming = r.DNSIncoming(response.packets()[0])
1149+
zc.record_manager.async_updates_from_response(incoming)
1150+
1151+
response = r.DNSOutgoing(const._FLAGS_QR_RESPONSE)
1152+
response.add_answer_at_time(good_bye_answer, 0)
1153+
response.add_answer_at_time(good_bye_answer, 0)
1154+
incoming = r.DNSIncoming(response.packets()[0])
1155+
zc.record_manager.async_updates_from_response(incoming)
1156+
await aiozc.async_close()

zeroconf/_handlers.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,7 @@ def async_updates_from_response(self, msg: DNSIncoming) -> None:
331331
updates: List[RecordUpdate] = []
332332
address_adds: List[DNSAddress] = []
333333
other_adds: List[DNSRecord] = []
334-
removes: List[DNSRecord] = []
334+
removes: Set[DNSRecord] = set()
335335
now = msg.now
336336
unique_types: Set[Tuple[str, int, int]] = set()
337337

@@ -355,7 +355,7 @@ def async_updates_from_response(self, msg: DNSIncoming) -> None:
355355
# expired and exists in the cache
356356
elif maybe_entry is not None:
357357
updates.append(RecordUpdate(record, maybe_entry))
358-
removes.append(record)
358+
removes.add(record)
359359

360360
if unique_types:
361361
self._async_mark_unique_cached_records_older_than_1s_to_expire(unique_types, msg.answers, now)

0 commit comments

Comments
 (0)