Skip to content

Retry oversized UDP responses over TCP - #421

Open
allenflux wants to merge 2 commits into
dnsjava:masterfrom
allenflux:allenflux/fix-oversized-udp-fallback
Open

allenflux wants to merge 2 commits into
dnsjava:masterfrom
allenflux:allenflux/fix-oversized-udp-fallback

Conversation

@allenflux

Copy link
Copy Markdown

Fixes #418.

When a server returns a UDP response larger than the advertised payload size without setting TC, the receive buffer cuts it off and parsing fails before the resolver can retry over TCP. Read one additional byte, bounded by the DNS message limit, to distinguish an oversized response from a valid response that exactly fills the buffer. Parse an oversized response as truncated, then retain the existing ID, question, opcode and TSIG checks before using the TCP fallback. ignoreTruncation=true retains its existing receive and parsing behavior.

Validation on macOS arm64 / OpenJDK 21.0.12.1:

  • The two oversized regression cases fail on the original production code; all eight regression cases pass with the fix, including exact-capacity, ordinary malformed, wrong-ID, TC and ignore-truncation controls.
  • mvn -B -ntp -Dgpg.skip -DexcludedGroups=concurrency verify: 1789 tests, 0 failures/errors, 28 skipped; compatibility, Spotless and Checkstyle checks pass. The concurrency exclusion and signing skip match the project's JDK 21 CI settings. The existing baseline suite reports 1781 tests with the same 28 skips.
  • A local UDP/TCP stub returning 2741 bytes without TC now returns all 24 TXT records through TCP; the original code raises WireParseException without attempting TCP. The small UDP and forced-TCP controls remain successful, and ignore-truncation does not retry.

AI assistance: OpenAI Codex helped investigate, implement and validate this change.

Generated with OpenAI Codex
@codecov

codecov Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 89.47368% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 70.08%. Comparing base (26a8d85) to head (64a7851).
⚠️ Report is 60 commits behind head on master.

Files with missing lines Patch % Lines
src/main/java/org/xbill/DNS/Message.java 92.30% 0 Missing and 1 partial ⚠️
src/main/java/org/xbill/DNS/SimpleResolver.java 83.33% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##             master     #421      +/-   ##
============================================
+ Coverage     66.95%   70.08%   +3.13%     
- Complexity     3098     3282     +184     
============================================
  Files           198      198              
  Lines         13709    13727      +18     
  Branches       2142     2145       +3     
============================================
+ Hits           9179     9621     +442     
+ Misses         3949     3527     -422     
+ Partials        581      579       -2     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@sonarqubecloud

Copy link
Copy Markdown


verifyTSIG(query, response, in);
if (!tcp && !ignoreTruncation && response.getHeader().getFlag(Flags.TC)) {
if (!tcp && !ignoreTruncation && (oversized || response.getHeader().getFlag(Flags.TC))) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If TSIG is in use, this check is never reached. So we can:

  • Read everything we receive, regardless of what was specified in OPT. That would require growing the buffer on demand, we don't always want to allocate the max. message size.
  • Keep it like this and accept TSIG validation failures (because the answer IS invalid)
  • Retry with TCP regardless. Not really an option IMO, since this breaks the TSIG promise.

Message response;
try {
response = parseMessage(in);
response = parseMessage(in, oversized);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of modifying Message, parse only the header if the message is oversized for the name/id/dclass validation, then retry with TCP. Fewer modifications and avoids useless parsing.

This branch has not been deployed

No deployments
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.

SimpleResolver: UDP response larger than the EDNS buffer fails with WireParseException instead of falling back to TCP

2 participants