Skip to content

Honor raise_on_serial_went_backwards on both inbound_xfr paths - #1298

Merged
rthalley merged 1 commit into
rthalley:mainfrom
dylanpulver:fix-inbound-xfr-serial-flag
Aug 31, 2026
Merged

Honor raise_on_serial_went_backwards on both inbound_xfr paths#1298
rthalley merged 1 commit into
rthalley:mainfrom
dylanpulver:fix-inbound-xfr-serial-flag

Conversation

@dylanpulver

Copy link
Copy Markdown
Contributor

inbound_xfr() has two socket paths, and each implementation forwards
raise_on_serial_went_backwards on only one of them — opposite ones.
dns.query.inbound_xfr() passes it on the TCP path but not the UDP one
(query.py:1725); dns.asyncquery.inbound_xfr() does the reverse
(asyncquery.py:962). For the async version that is the default path, since
udp_mode defaults to UDPMode.NEVER, so the option never takes effect there.

Against a nanonameserver answering an IXFR with an older serial, with the option
set to False:

sync async
TCP (NEVER) honored raises
UDP (TRY_FIRST) raises honored

Both failing cells raise dns.xfr.SerialWentBackwards. Left at its default the
control raises everywhere, as it should.

_inbound_xfr()'s = True default is what made both misses silent rather than
errors, so it is dropped too — it is private and all five call sites now pass
the flag. pyright and ty then catch an omission at the sync call sites; the
async ones keep an existing blanket # pyright: ignore (unrelated -> Any
complaint) and stay unprotected. Happy to drop this part if you prefer the
default.

Tests parametrize both udp_mode values across sync, asyncio and trio, and
assert both directions. Three of the six fail with the source reverted; the rest
cover the paths that were already correct.

No whatsnew entry: the parameter is unreleased and the existing bullet already
describes the behavior this makes true.

1347 passed / 123 skipped, up from 1341 / 123 on main; black, ruff,
pyright and ty clean.

dns.query.inbound_xfr() forwarded the flag on its TCP path but not its
UDP one, and dns.asyncquery.inbound_xfr() did the opposite, so each
implementation honored the option on exactly one of its two paths.  For
the async version that is the default path, since udp_mode defaults to
UDPMode.NEVER.

_inbound_xfr()'s default for the parameter is dropped as well: it is
private, all five call sites now pass the flag, and the default is what
turned the two missed call sites into silent no-ops rather than errors.
@rthalley

Copy link
Copy Markdown
Owner

Thanks!

@rthalley
rthalley merged commit bc3009d into rthalley:main Aug 31, 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