Skip to content

Add fallback handling for non-DNS UDP traffic - #199

Open
Mygod wants to merge 2 commits into
masterking32:mainfrom
Mygod:agent/udp-fallback
Open

Add fallback handling for non-DNS UDP traffic#199
Mygod wants to merge 2 commits into
masterking32:mainfrom
Mygod:agent/udp-fallback

Conversation

@Mygod

@Mygod Mygod commented Jul 22, 2026

Copy link
Copy Markdown

Motivation

MasterDnsVPN normally handles DNS tunnel traffic on UDP port 53. Some deployments also need to expose other UDP protocols through that same public port, where binding a separate listener or opening another port may not be possible.

Fallback handling lets the existing listener demultiplex traffic: structurally valid DNS remains with MasterDnsVPN, while other UDP datagrams are forwarded to a configured service. This allows multiple protocols to share UDP port 53.

Summary

  • Add an optional FALLBACK = "HOST:PORT" server setting for forwarding raw non-DNS UDP datagrams.
  • Classify only structurally complete DNS datagrams as DNS traffic.
  • Maintain sticky routing state per source address.
  • Forward upstream traffic asynchronously through a bounded queue so backpressure cannot block DNS ingress or shutdown.
  • Prevent fallback targets that resolve back to the listener.
  • Document configuration, routing behavior, resource limits, and failure semantics.

Routing behavior

When fallback is enabled, a previously unknown non-DNS source is forwarded immediately and remains assigned to fallback. A source already classified as DNS switches after 16 consecutive non-DNS datagrams. A valid DNS datagram resets that streak.

Peer classification and fallback sessions expire after 180 seconds without activity.

Queued DNS replies are protected by per-peer routing epochs and a write barrier, preventing stale DNS responses from overtaking a transition into fallback mode.

When FALLBACK is unset, existing server behavior is preserved.

Validation

  • go test ./...
  • go vet ./...
  • go test -race ./internal/config ./internal/dnsparser
  • go test -race ./internal/udpserver -run 'Test(DNSWorkerFallback|DNSWorkerDropsQueuedReplyAfterFallbackTransition|DNSWorkerWithoutFallback|UDPFallback|FallbackTargetsListener)' -count=20

@Mygod
Mygod marked this pull request as ready for review July 22, 2026 18:38
@masterking32
masterking32 requested a review from Copilot July 23, 2026 04:39

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR adds an optional UDP “fallback” path to the server’s UDP/53 listener so that structurally complete DNS datagrams continue through the normal DNS tunnel handling, while non-DNS datagrams can be forwarded to a configured upstream HOST:PORT with per-source sticky routing and bounded async forwarding.

Changes:

  • Introduces FALLBACK = "HOST:PORT" server config + validation, and updates docs across READMEs and the sample TOML.
  • Adds a new UDP fallback session manager with idle expiry, sticky routing, epoch-based DNS reply gating, and bounded upstream send queue.
  • Adds strict DNS datagram parsing (ParseDNSDatagramLite) used for routing decisions, plus extensive unit/integration tests for fallback behavior.

Reviewed changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
server_config.toml.simple Documents the optional FALLBACK setting and behavior notes.
README.MD Adds FALLBACK documentation and clarifies packet sizing requirements with fallback.
README_ZH.MD Adds Chinese documentation for FALLBACK.
README_RU.MD Adds Russian documentation for FALLBACK.
README_IT.MD Adds Italian documentation for FALLBACK.
README_FA.MD Adds Persian documentation for FALLBACK.
README_ES.MD Adds Spanish documentation for FALLBACK.
internal/udpserver/udp_fallback.go Implements fallback routing state, per-peer sessions, bounded queues, expiry, and write barriers/epochs.
internal/udpserver/udp_fallback_test.go Unit tests for fallback manager routing, epochs, cleanup, and backpressure/shutdown behavior.
internal/udpserver/server.go Wires fallback into server startup/shutdown, forces single reader for ordered classification, and adds loop-prevention check.
internal/udpserver/server_runtime.go Integrates fallback classification into ingress, adds epoch-gated DNS reply writes, and refactors parsing/handling paths.
internal/udpserver/server_ingress.go Refactors ingress handling to accept a parsed packet + parse error and drops non-request datagrams.
internal/udpserver/server_ingress_test.go Adds coverage ensuring non-request/structurally incomplete DNS-shaped datagrams are dropped.
internal/udpserver/server_fallback_test.go Adds integration-style tests validating end-to-end demux behavior and loop-prevention logic.
internal/dnsparser/response.go Splits message-vs-request header plausibility checks and tightens header validation.
internal/dnsparser/parser.go Adds ParseDNSDatagramLite and strengthens name parsing (pointer validation, wire-length limits).
internal/dnsparser/parser_lite_test.go Adds extensive tests for complete-message requirements and rejection cases.
internal/config/server.go Adds FALLBACK to config schema, defaulting, and validation (HOST:PORT, port bounds, no unspecified IPs).
internal/config/server_test.go Adds tests for CLI flag binding, config loading, and validation for FALLBACK.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/udpserver/server_runtime.go Outdated
Comment on lines +285 to +291
func (s *Server) safeHandlePacket(packet []byte) []byte {
parsed, parseErr, ok := s.safeParseDNSDatagram(packet)
if !ok {
return nil
}
return s.safeHandleParsedPacket(packet, parsed, parseErr)
}
Comment on lines +434 to +437
interfaceAddrs, err := net.InterfaceAddrs()
if err != nil {
return false
}

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated no new comments.

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