Files
olm/DNS_PROXY_README.md
Owen e3623fd756 loser to workinr?
Former-commit-id: 04f7778765
2025-11-21 14:17:23 -05:00

7.4 KiB

Virtual DNS Proxy Implementation

Overview

This implementation adds a high-performance virtual DNS proxy that intercepts DNS queries destined for 10.30.30.30:53 before they reach the WireGuard tunnel. The proxy processes DNS queries using a gvisor netstack and forwards them to upstream DNS servers, bypassing the VPN tunnel entirely.

Architecture

Components

  1. FilteredDevice (olm/device_filter.go)

    • Wraps the TUN device with packet filtering capabilities
    • Provides fast packet inspection without deep packet processing
    • Supports multiple filtering rules that can be added/removed dynamically
    • Optimized for performance - only extracts destination IP on fast path
  2. DNSProxy (olm/dns_proxy.go)

    • Uses gvisor netstack to handle DNS protocol processing
    • Listens on 10.30.30.30:53 within its own network stack
    • Forwards queries to Google DNS (8.8.8.8, 8.8.4.4)
    • Writes responses directly back to the TUN device, bypassing WireGuard

Packet Flow

┌─────────────────────────────────────────────────────────────┐
│                        Application                          │
└──────────────────────┬──────────────────────────────────────┘
                       │ DNS Query to 10.30.30.30:53
                       ▼
┌─────────────────────────────────────────────────────────────┐
│                      TUN Interface                          │
└──────────────────────┬──────────────────────────────────────┘
                       │
                       ▼
┌─────────────────────────────────────────────────────────────┐
│                   FilteredDevice (Read)                     │
│  - Fast IP extraction                                       │
│  - Rule matching (10.30.30.30)                              │
└──────────────┬──────────────────────────────────────────────┘
               │                                   
    ┌──────────┴──────────┐
    │                     │
    ▼                     ▼
┌─────────┐         ┌─────────────────────────┐
│DNS Proxy│         │   WireGuard Device      │
│Netstack │         │   (other traffic)       │
└────┬────┘         └─────────────────────────┘
     │
     │ Forward to 8.8.8.8
     ▼
┌─────────────┐
│   Internet  │
│ (Direct)    │
└──────┬──────┘
       │ DNS Response
       ▼
┌─────────────────────────────────────────────────────────────┐
│            DNSProxy writes directly to TUN                  │
└──────────────────────┬──────────────────────────────────────┘
                       │
                       ▼
┌─────────────────────────────────────────────────────────────┐
│                      Application                            │
└─────────────────────────────────────────────────────────────┘

Performance Considerations

Fast Path Optimization

  1. Minimal Packet Inspection

    • Only extracts destination IP (bytes 16-19 for IPv4, 24-39 for IPv6)
    • No deep packet inspection unless packet matches a rule
    • Zero-copy operations where possible
  2. Rule Matching

    • Simple IP comparison (not prefix matching for rules)
    • Linear scan of rules (fast for small number of rules)
    • Read-lock only for rule access
  3. Packet Processing

    • Filtered packets are removed from the slice in-place
    • Non-matching packets passed through with minimal overhead
    • No memory allocation for packets that don't match rules

Memory Efficiency

  • Packet copies are only made when absolutely necessary
  • gvisor netstack uses buffer pooling internally
  • DNS proxy uses a separate goroutine for response handling

Usage

Configuration

The DNS proxy is automatically started when the tunnel is created. By default:

  • DNS proxy IP: 10.30.30.30
  • DNS port: 53
  • Upstream DNS: 8.8.8.8 (primary), 8.8.4.4 (fallback)

Testing

To test the DNS proxy, configure your DNS settings to use 10.30.30.30:

# Using dig
dig @10.30.30.30 google.com

# Using nslookup
nslookup google.com 10.30.30.30

Extensibility

The FilteredDevice architecture is designed to be extensible:

Adding New Services

To add a new service (e.g., HTTP proxy on 10.30.30.31):

  1. Create a new service similar to DNSProxy
  2. Register a filter rule with filteredDev.AddRule()
  3. Process packets in your handler
  4. Write responses back to the TUN device

Example:

// In your service
func (s *MyService) handlePacket(packet []byte) bool {
    // Parse packet
    // Process request
    // Write response to TUN device
    s.tunDevice.Write([][]byte{response}, 0)
    return true // Drop from normal path
}

// During initialization
filteredDev.AddRule(myServiceIP, myService.handlePacket)

Adding Filtering Rules

Rules can be added/removed dynamically:

// Add a rule
filteredDev.AddRule(netip.MustParseAddr("10.30.30.40"), handleSpecialIP)

// Remove a rule
filteredDev.RemoveRule(netip.MustParseAddr("10.30.30.40"))

Implementation Details

Why Direct TUN Write?

The DNS proxy writes responses directly back to the TUN device instead of going through the filter because:

  1. Responses should go to the host, not through WireGuard
  2. Avoids infinite loops (response → filter → DNS proxy → ...)
  3. Better performance (one less layer)

Thread Safety

  • FilteredDevice uses RWMutex for rule access (read-heavy workload)
  • DNSProxy goroutines are properly synchronized
  • TUN device write operations are thread-safe

Error Handling

  • Failed DNS queries fall back to secondary DNS server
  • Malformed packets are logged but don't crash the proxy
  • Context cancellation ensures clean shutdown

Future Enhancements

Potential improvements:

  1. DNS caching to reduce upstream queries
  2. DNS-over-HTTPS (DoH) support
  3. Custom DNS filtering/blocking
  4. Metrics and monitoring
  5. IPv6 support for DNS proxy
  6. Multiple upstream DNS servers with health checking
  7. HTTP/HTTPS proxy on different IPs
  8. SOCKS5 proxy support