request_mac: Optional[bytes] = b"",
ignore_trailing: bool = False,
raise_on_truncation: bool = False,
+ ignore_errors: bool = False,
+ query: Optional[dns.message.Message] = None,
) -> Any:
"""Read a DNS message from a UDP socket.
"""
wire = b""
- while 1:
+ while True:
(wire, from_address) = await sock.recvfrom(65535, _timeout(expiration))
- if _matches_destination(
+ if not _matches_destination(
sock.family, from_address, destination, ignore_unexpected
):
- break
- received_time = time.time()
- r = dns.message.from_wire(
- wire,
- keyring=keyring,
- request_mac=request_mac,
- one_rr_per_rrset=one_rr_per_rrset,
- ignore_trailing=ignore_trailing,
- raise_on_truncation=raise_on_truncation,
- )
- return (r, received_time, from_address)
+ continue
+ received_time = time.time()
+ try:
+ r = dns.message.from_wire(
+ wire,
+ keyring=keyring,
+ request_mac=request_mac,
+ one_rr_per_rrset=one_rr_per_rrset,
+ ignore_trailing=ignore_trailing,
+ raise_on_truncation=raise_on_truncation,
+ )
+ except Exception:
+ if ignore_errors:
+ continue
+ else:
+ raise
+ if ignore_errors and query is not None and not query.is_response(r):
+ continue
+ return (r, received_time, from_address)
async def udp(
raise_on_truncation: bool = False,
sock: Optional[dns.asyncbackend.DatagramSocket] = None,
backend: Optional[dns.asyncbackend.Backend] = None,
+ ignore_errors: bool = False,
) -> dns.message.Message:
"""Return the response obtained after sending a query via UDP.
q.mac,
ignore_trailing,
raise_on_truncation,
+ ignore_errors,
+ q,
)
r.time = received_time - begin_time
- if not q.is_response(r):
+ # We don't need to check q.is_response() if we are in ignore_errors mode
+ # as receive_udp() will have checked it.
+ if not (ignore_errors or q.is_response(r)):
raise BadResponse
return r
udp_sock: Optional[dns.asyncbackend.DatagramSocket] = None,
tcp_sock: Optional[dns.asyncbackend.StreamSocket] = None,
backend: Optional[dns.asyncbackend.Backend] = None,
+ ignore_errors: bool = False,
) -> Tuple[dns.message.Message, bool]:
"""Return the response to the query, trying UDP first and falling back
to TCP if UDP results in a truncated response.
True,
udp_sock,
backend,
+ ignore_errors,
)
return (response, False)
except dns.message.Truncated:
request_mac: Optional[bytes] = b"",
ignore_trailing: bool = False,
raise_on_truncation: bool = False,
+ ignore_errors: bool = False,
+ query: Optional[dns.message.Message] = None,
) -> Any:
"""Read a DNS message from a UDP socket.
``(dns.message.Message, float, tuple)``
tuple of the received message, the received time, and the address where
the message arrived from.
+
+ *ignore_errors*, a ``bool``. If various format errors or response
+ mismatches occur, ignore them and keep listening for a valid response.
+ The default is ``False``.
+
+ *query*, a ``dns.message.Message`` or ``None``. If not ``None`` and
+ *ignore_errors* is ``True``, check that the received message is a response
+ to this query, and if not keep listening for a valid response.
"""
wire = b""
while True:
(wire, from_address) = _udp_recv(sock, 65535, expiration)
- if _matches_destination(
+ if not _matches_destination(
sock.family, from_address, destination, ignore_unexpected
):
- break
- received_time = time.time()
- r = dns.message.from_wire(
- wire,
- keyring=keyring,
- request_mac=request_mac,
- one_rr_per_rrset=one_rr_per_rrset,
- ignore_trailing=ignore_trailing,
- raise_on_truncation=raise_on_truncation,
- )
- if destination:
- return (r, received_time)
- else:
- return (r, received_time, from_address)
+ continue
+ received_time = time.time()
+ try:
+ r = dns.message.from_wire(
+ wire,
+ keyring=keyring,
+ request_mac=request_mac,
+ one_rr_per_rrset=one_rr_per_rrset,
+ ignore_trailing=ignore_trailing,
+ raise_on_truncation=raise_on_truncation,
+ )
+ except Exception:
+ if ignore_errors:
+ continue
+ else:
+ raise
+ if ignore_errors and query is not None and not query.is_response(r):
+ continue
+ if destination:
+ return (r, received_time)
+ else:
+ return (r, received_time, from_address)
def udp(
ignore_trailing: bool = False,
raise_on_truncation: bool = False,
sock: Optional[Any] = None,
+ ignore_errors: bool = False,
) -> dns.message.Message:
"""Return the response obtained after sending a query via UDP.
if a socket is provided, it must be a nonblocking datagram socket,
and the *source* and *source_port* are ignored.
+ *ignore_errors*, a ``bool``. If various format errors or response
+ mismatches occur, ignore them and keep listening for a valid response.
+ The default is ``False``.
+
Returns a ``dns.message.Message``.
"""
q.mac,
ignore_trailing,
raise_on_truncation,
+ ignore_errors,
+ q,
)
r.time = received_time - begin_time
- if not q.is_response(r):
+ # We don't need to check q.is_response() if we are in ignore_errors mode
+ # as receive_udp() will have checked it.
+ if not (ignore_errors or q.is_response(r)):
raise BadResponse
return r
assert (
ignore_trailing: bool = False,
udp_sock: Optional[Any] = None,
tcp_sock: Optional[Any] = None,
+ ignore_errors: bool = False,
) -> Tuple[dns.message.Message, bool]:
"""Return the response to the query, trying UDP first and falling back
to TCP if UDP results in a truncated response.
*q*, a ``dns.message.Message``, the query to send
- *where*, a ``str`` containing an IPv4 or IPv6 address, where
- to send the message.
+ *where*, a ``str`` containing an IPv4 or IPv6 address, where to send the message.
- *timeout*, a ``float`` or ``None``, the number of seconds to wait before the
- query times out. If ``None``, the default, wait forever.
+ *timeout*, a ``float`` or ``None``, the number of seconds to wait before the query
+ times out. If ``None``, the default, wait forever.
*port*, an ``int``, the port send the message to. The default is 53.
- *source*, a ``str`` containing an IPv4 or IPv6 address, specifying
- the source address. The default is the wildcard address.
+ *source*, a ``str`` containing an IPv4 or IPv6 address, specifying the source
+ address. The default is the wildcard address.
- *source_port*, an ``int``, the port from which to send the message.
- The default is 0.
+ *source_port*, an ``int``, the port from which to send the message. The default is
+ 0.
- *ignore_unexpected*, a ``bool``. If ``True``, ignore responses from
- unexpected sources.
+ *ignore_unexpected*, a ``bool``. If ``True``, ignore responses from unexpected
+ sources.
- *one_rr_per_rrset*, a ``bool``. If ``True``, put each RR into its own
- RRset.
+ *one_rr_per_rrset*, a ``bool``. If ``True``, put each RR into its own RRset.
- *ignore_trailing*, a ``bool``. If ``True``, ignore trailing
- junk at end of the received message.
+ *ignore_trailing*, a ``bool``. If ``True``, ignore trailing junk at end of the
+ received message.
- *udp_sock*, a ``socket.socket``, or ``None``, the socket to use for the
- UDP query. If ``None``, the default, a socket is created. Note that
- if a socket is provided, it must be a nonblocking datagram socket,
- and the *source* and *source_port* are ignored for the UDP query.
+ *udp_sock*, a ``socket.socket``, or ``None``, the socket to use for the UDP query.
+ If ``None``, the default, a socket is created. Note that if a socket is provided,
+ it must be a nonblocking datagram socket, and the *source* and *source_port* are
+ ignored for the UDP query.
*tcp_sock*, a ``socket.socket``, or ``None``, the connected socket to use for the
- TCP query. If ``None``, the default, a socket is created. Note that
- if a socket is provided, it must be a nonblocking connected stream
- socket, and *where*, *source* and *source_port* are ignored for the TCP
- query.
+ TCP query. If ``None``, the default, a socket is created. Note that if a socket is
+ provided, it must be a nonblocking connected stream socket, and *where*, *source*
+ and *source_port* are ignored for the TCP query.
+
+ *ignore_errors*, a ``bool``. If various format errors or response mismatches occur
+ while listening for UDP, ignore them and keep listening for a valid response. The
+ default is ``False``.
- Returns a (``dns.message.Message``, tcp) tuple where tcp is ``True``
- if and only if TCP was used.
+ Returns a (``dns.message.Message``, tcp) tuple where tcp is ``True`` if and only if
+ TCP was used.
"""
try:
response = udp(
ignore_trailing,
True,
udp_sock,
+ ignore_errors,
)
return (response, False)
except dns.message.Truncated: