Skip to content

Bring async receive_udp ignore_errors in line with the sync one - #1297

Merged
rthalley merged 1 commit into
rthalley:mainfrom
dylanpulver:fix-async-ignore-errors-parity
Aug 29, 2026
Merged

Bring async receive_udp ignore_errors in line with the sync one#1297
rthalley merged 1 commit into
rthalley:mainfrom
dylanpulver:fix-async-ignore-errors-parity

Conversation

@dylanpulver

Copy link
Copy Markdown
Contributor

Differential fuzz of dns.query against dns.asyncquery over 400 response datagrams: 120 diverged, every one with ignore_errors=True. A control restricted to well-formed wire gave 0/400 before and after.

Two datagrams into each twin: a valid header plus trailing junk, then a clean NXDOMAIN response.

sync  dns.query.receive_udp      -> rcode=NXDOMAIN errors=0 datagrams_read=2
async dns.asyncquery.receive_udp -> rcode=SERVFAIL errors=1 datagrams_read=1

The sync twin discards the unparsable datagram and keeps listening, as its docstring promises ("ignore format errors or response mismatches and keep listening for a valid response"), which the async docstring defers to. The async twin returns it with the parse errors recorded.

Blame puts both bodies at f66e25b (2024-02-09). dns/asyncquery.py:161 is 864308a (#1248), which added continue_on_error=ignore_errors to the async twin only; dns/query.py was not touched.

Do53Nameserver.query and .async_query both pass ignore_errors=True for UDP, so dns.resolver and dns.asyncresolver disagree on a damaged or injected response. Nothing in dnspython reads Message.errors, so a salvaged message reaches the resolver looking clean.

After the change the same fuzz gives 0 across four seeds.

The receive_tcp hunk is separable: #1248 also gave the async receive_tcp an ignore_errors parameter the sync one lacks and no caller passes. Neither has shipped in a release.

test_unparsable_wire_is_skipped_not_salvaged is added to both suites. The async one fails without the source change; the sync one passes either way and pins the authoritative behaviour.

ignore_errors means "discard the datagram and keep listening for a valid
response", but dns.asyncquery.receive_udp() passed continue_on_error to
from_wire(), so a datagram with a valid header and an unparsable body was
returned with its errors recorded instead of being skipped.

Also removes the ignore_errors parameter added to
dns.asyncquery.receive_tcp() at the same time; dns.query.receive_tcp()
has no such parameter and nothing passes it.
@rthalley

Copy link
Copy Markdown
Owner

Oops! Thanks for the fix!

@rthalley
rthalley merged commit 90add95 into rthalley:main Aug 29, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants