Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 62 additions & 42 deletions src/zeroconf/_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
_CHECK_TIME,
_CLASS_IN,
_CLASS_UNIQUE,
_DUPLICATE_QUESTION_INTERVAL,
_FLAGS_AA,
_FLAGS_QR_QUERY,
_FLAGS_QR_RESPONSE,
Expand Down Expand Up @@ -263,22 +264,16 @@ def __init__(self, zc: 'Zeroconf') -> None:
self.sock_description: Optional[str] = None
self._deferred: Dict[str, List[DNSIncoming]] = {}
self._timers: Dict[str, asyncio.TimerHandle] = {}
self.last_incoming_message: Optional[DNSIncoming] = None
super().__init__()

def suppress_duplicate_packet(self, data: bytes, now: float) -> bool:
"""Suppress duplicate packet if the last one was the same in the last second."""
if self.data == data and (now - 1000) < self.last_time:
return True
self.data = data
self.last_time = now
return False

def datagram_received(
self, data: bytes, addrs: Union[Tuple[str, int], Tuple[str, int, int, int]]
) -> None:
assert self.transport is not None
v6_flow_scope: Union[Tuple[()], Tuple[int, int]] = ()
data_len = len(data)
debug = log.isEnabledFor(logging.DEBUG)

if len(addrs) == 2:
# https://github.com/python/mypy/issues/1178
Expand All @@ -287,53 +282,78 @@ def datagram_received(
else:
# https://github.com/python/mypy/issues/1178
addr, port, flow, scope = addrs # type: ignore
log.debug('IPv6 scope_id %d associated to the receiving interface', scope)
if debug:
log.debug('IPv6 scope_id %d associated to the receiving interface', scope)
v6_flow_scope = (flow, scope)

now = current_time_millis()
if self.suppress_duplicate_packet(data, now):
# Guard against duplicate packets
log.debug(
'Ignoring duplicate message received from %r:%r [socket %s] (%d bytes) as [%r]',
addr,
port,
self.sock_description,
data_len,
data,
)
if data_len < 12:
if debug:
log.debug(
'Ignoring message from %r:%r [socket %s] (%d bytes) as too short',
addr,
port,
self.sock_description,
data_len,
)
return

if data_len > _MAX_MSG_ABSOLUTE:
# Guard against oversized packets to ensure bad implementations cannot overwhelm
# the system.
log.debug(
"Discarding incoming packet with length %s, which is larger "
"than the absolute maximum size of %s",
data_len,
_MAX_MSG_ABSOLUTE,
)
if debug:
log.debug(
"Discarding incoming packet with length %s, which is larger "
"than the absolute maximum size of %s",
data_len,
_MAX_MSG_ABSOLUTE,
)
return

last_incoming_message = self.last_incoming_message
if (
data == self.data
and last_incoming_message is not None
and self.last_time > now - _DUPLICATE_QUESTION_INTERVAL
and not any(question.unicast for question in last_incoming_message.questions)
):
# We got the same packet and there are no QU questions in the packet
if debug:
log.debug(
'Ignoring message from %r:%r [socket %s] (%d bytes) as a duplicate',
addr,
port,
self.sock_description,
data_len,
)
return

msg = DNSIncoming(data, (addr, port), scope, now)
self.last_incoming_message = msg
self.data = data
self.last_time = now

if msg.valid:
log.debug(
'Received from %r:%r [socket %s]: %r (%d bytes) as [%r]',
addr,
port,
self.sock_description,
msg,
data_len,
data,
)
if debug:
log.debug(
'Received from %r:%r [socket %s]: %r (%d bytes) as [%r]',
addr,
port,
self.sock_description,
msg,
data_len,
data,
)
else:
log.debug(
'Received from %r:%r [socket %s]: (%d bytes) [%r]',
addr,
port,
self.sock_description,
data_len,
data,
)
if debug:
log.debug(
'Received from %r:%r [socket %s]: (%d bytes) [%r]',
addr,
port,
self.sock_description,
data_len,
data,
)
return

if not msg.is_query():
Expand Down