fix: always answer QU questions when the exact same packet is receive… · python-zeroconf/python-zeroconf@74d7ba1

@@ -37,19 +37,17 @@

3737

)

38383939

from ._cache import DNSCache, _UniqueRecordsType

40-

from ._dns import DNSAddress, DNSNsec, DNSPointer, DNSQuestion, DNSRecord, DNSRRSet

40+

from ._dns import DNSAddress, DNSPointer, DNSQuestion, DNSRecord, DNSRRSet

4141

from ._history import QuestionHistory

4242

from ._logger import log

4343

from ._protocol.incoming import DNSIncoming

4444

from ._protocol.outgoing import DNSOutgoing

45-

from ._services.info import ServiceInfo

4645

from ._services.registry import ServiceRegistry

4746

from ._updates import RecordUpdate, RecordUpdateListener

4847

from ._utils.time import current_time_millis, millis_to_seconds

4948

from .const import (

5049

_ADDRESS_RECORD_TYPES,

5150

_CLASS_IN,

52-

_CLASS_UNIQUE,

5351

_DNS_OTHER_TTL,

5452

_DNS_PTR_MIN_TTL,

5553

_FLAGS_AA,

@@ -90,15 +88,6 @@ class AnswerGroup(NamedTuple):

9088

answers: _AnswerWithAdditionalsType

9189929093-

def construct_nsec_record(name: str, types: List[int], now: float) -> DNSNsec:

94-

"""Construct an NSEC record for name and a list of dns types.

95-96-

This function should only be used for SRV/A/AAAA records

97-

which have a TTL of _DNS_OTHER_TTL

98-

"""

99-

return DNSNsec(name, _TYPE_NSEC, _CLASS_IN | _CLASS_UNIQUE, _DNS_OTHER_TTL, name, types, created=now)

100-101-10291

def construct_outgoing_multicast_answers(answers: _AnswerWithAdditionalsType) -> DNSOutgoing:

10392

"""Add answers and additionals to a DNSOutgoing."""

10493

out = DNSOutgoing(_FLAGS_QR_RESPONSE | _FLAGS_AA, multicast=True)

@@ -217,20 +206,6 @@ def _has_mcast_record_in_last_second(self, record: DNSRecord) -> bool:

217206

return bool(maybe_entry and self._now - maybe_entry.created < _ONE_SECOND)

218207219208220-

def _get_address_and_nsec_records(service: ServiceInfo, now: float) -> Set[DNSRecord]:

221-

"""Build a set of address records and NSEC records for non-present record types."""

222-

seen_types: Set[int] = set()

223-

records: Set[DNSRecord] = set()

224-

for dns_address in service.dns_addresses(created=now):

225-

seen_types.add(dns_address.type)

226-

records.add(dns_address)

227-

missing_types: Set[int] = _ADDRESS_RECORD_TYPES - seen_types

228-

if missing_types:

229-

assert service.server is not None, "Service server must be set for NSEC record."

230-

records.add(construct_nsec_record(service.server, list(missing_types), now))

231-

return records

232-233-234209

class QueryHandler:

235210

"""Query the ServiceRegistry."""

236211

@@ -264,9 +239,10 @@ def _add_pointer_answers(

264239

dns_pointer = service.dns_pointer(created=now)

265240

if known_answers.suppresses(dns_pointer):

266241

continue

267-

additionals: Set[DNSRecord] = {service.dns_service(created=now), service.dns_text(created=now)}

268-

additionals |= _get_address_and_nsec_records(service, now)

269-

answer_set[dns_pointer] = additionals

242+

answer_set[dns_pointer] = {

243+

service.dns_service(created=now),

244+

service.dns_text(created=now),

245+

} | service.get_address_and_nsec_records(created=now)

270246271247

def _add_address_answers(

272248

self,

@@ -291,12 +267,12 @@ def _add_address_answers(

291267

if answers:

292268

if missing_types:

293269

assert service.server is not None, "Service server must be set for NSEC record."

294-

additionals.add(construct_nsec_record(service.server, list(missing_types), now))

270+

additionals.add(service.dns_nsec(list(missing_types), created=now))

295271

for answer in answers:

296272

answer_set[answer] = additionals

297273

elif type_ in missing_types:

298274

assert service.server is not None, "Service server must be set for NSEC record."

299-

answer_set[construct_nsec_record(service.server, list(missing_types), now)] = set()

275+

answer_set[service.dns_nsec(list(missing_types), created=now)] = set()

300276301277

def _answer_question(

302278

self,

@@ -327,7 +303,7 @@ def _answer_question(

327303

# https://tools.ietf.org/html/rfc6763#section-12.2.

328304

dns_service = service.dns_service(created=now)

329305

if not known_answers.suppresses(dns_service):

330-

answer_set[dns_service] = _get_address_and_nsec_records(service, now)

306+

answer_set[dns_service] = service.get_address_and_nsec_records(created=now)

331307

if type_ in (_TYPE_TXT, _TYPE_ANY):

332308

dns_text = service.dns_text(created=now)

333309

if not known_answers.suppresses(dns_text):

@@ -496,7 +472,7 @@ def async_add_listener(

496472

its update_record method called when information is available to

497473

answer the question(s).

498474499-

This function is not threadsafe and must be called in the eventloop.

475+

This function is not thread-safe and must be called in the eventloop.

500476

"""

501477

if not isinstance(listener, RecordUpdateListener):

502478

log.error( # type: ignore[unreachable]