Fix DNS forward/cache path for relay-driven poisoning - #21853
Open
Pushpenderrathore wants to merge 1 commit into
Open
Fix DNS forward/cache path for relay-driven poisoning#21853Pushpenderrathore wants to merge 1 commit into
Pushpenderrathore wants to merge 1 commit into
Conversation
Three issues surfaced while running the DNS server under the Kerberos relay coercion workflow (identified during jheysel's ESC8 testing): - Rex::Proto::DNS::Cache#cache_record raised on any forwarded record whose name did not match MATCH_HOSTNAME, killing the dispatch thread. Skip the non-cacheable record instead. - Server#default_dispatch_request duplicated the request with Dnsruby::Message#dup, which is shallow, so req.question and forward.question shared one Array. Deleting a cache-served question from the forwarded packet also emptied the original request's question list. Give forward its own copy. - The response was built by mutating the decoded request's @answer via instance_variable_set and re-encoding it, which appended the answer bytes past the packet end so clients decoded zero answers ("bad DNS packet" on Windows). Build a fresh Dnsruby::Message for the response instead. Also handle the udp recvfrom returning an explicit source port so the reply goes back to the right host/port across socket variants. Adds regression specs for the shallow-dup question handling and the answer-encoding fix.
Pushpenderrathore
force-pushed
the
fix/dns-forward-cache-relay-poisoning
branch
from
August 31, 2026 19:33
40fbf90 to
b0d920f
Compare
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Fixes DNS forwarding, caching, response encoding, and UDP reply addressing for relay-driven poisoning.
Changes:
- Skips invalid-hostname cache records.
- Safely separates forwarded questions and rebuilds DNS responses.
- Supports alternate UDP
recvfromreturn shapes.
Impact Analysis:
- Blast radius: Medium; affects default DNS forwarding and UDP listeners.
- Data and contract effects: Changes DNS response construction and cache behavior; RD is not currently preserved.
- Rollback and test focus: Reversible; validate DNS flags, cache rejection, and both UDP address formats.
File summaries
| File | Description |
|---|---|
lib/rex/proto/dns/cache.rb |
Skips non-cacheable hostnames. |
lib/rex/proto/dns/server.rb |
Fixes forwarding, response encoding, and UDP source handling. |
spec/lib/rex/proto/dns/server_spec.rb |
Adds forwarding and encoding regressions. |
Review details
- Files reviewed: 3/3 changed files
- Comments generated: 3
- Review effort level: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
59
to
+60
| unless record.name.to_s.match(MATCH_HOSTNAME) | ||
| raise "Invalid record for cache entry (invalid hostname) - #{record.inspect}" | ||
| return # skip non-cacheable record: " - #{record.inspect}" |
Comment on lines
+226
to
+230
| buf, addr, source_port = self.udp_sock.recvfrom(65535) | ||
| if source_port | ||
| host, port = addr, source_port | ||
| else | ||
| host, port = addr[3], addr[1] |
Comment on lines
+188
to
+191
| resp = Dnsruby::Message.new | ||
| resp.header.id = req.header.id | ||
| resp.header.qr = true | ||
| resp.header.ra = req.header.rd |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Three fixes to the core
Rex::Proto::DNSforward/cache path that surface once the DNS server is used as a selective poisoner in front of a real upstream resolver (the Kerberos relay coercion workflow in #21693). Identified during @jheysel-r7's ESC8 relay testing.Each is small and independent:
Cache#cache_recordcrashed on non-cacheable forwarded records. Real upstream responses carry records whose names do not matchMATCH_HOSTNAME; caching them raised and killed the dispatch thread. Skip the record instead of raising.Shallow
dupshared the question array.Dnsruby::Message#dupis shallow, soreq.questionandforward.questionreferenced the sameArray. Deleting a cache-served question from the forwarded packet also emptied the original request's question list, so the echoed response lost its questions.forwardnow gets its own copy.Mutating a decoded request's
@answerproduced a malformed packet. Building the reply byinstance_variable_set(:@answer, ...)on the decoded request and re-encoding appended the answer bytes after the packet end, so clients decoded zero answers (surfaces as "Bad DNS packet" on Windows). The response is now built as a freshDnsruby::Message.Also handles
udp_sock.recvfromreturning an explicit source port so the reply is addressed to the right host/port across socket variants.Verification
Both non-obvious bugs (2 and 3) were confirmed empirically against the pinned
dnsrubybefore and after the fix, and are covered by new regression specs.The existing coverage from #21784 (empty-forward response) still passes.
Related