feat: introduce DNS intercept mode infrastructure

Add --intercept-mode flag (dns/hard/off) with configuration support,
recovery bypass for captive portals, probe-based interception
verification, VPN DNS coexistence in the proxy layer, and IPv6
loopback listener guard.

Remove standalone mDNSResponder hack files — the port 53 binding
logic is now handled within the intercept mode infrastructure.

Squashed from intercept mode development on v1.0 branch (#497).
This commit is contained in:
Codescribe
2026-03-03 02:06:49 -05:00
committed by Cuong Manh Le
parent 12715e6f24
commit 1e8240bd1c
17 changed files with 1813 additions and 291 deletions
+73
View File
@@ -234,6 +234,79 @@ type publicResponse struct {
server string
}
// OsResolverNameservers returns the current OS resolver nameservers (host:port format).
// Returns nil if the OS resolver has not been initialized.
func OsResolverNameservers() []string {
resolverMutex.Lock()
r := or
resolverMutex.Unlock()
if r == nil {
return nil
}
var nss []string
if lan := r.lanServers.Load(); lan != nil {
nss = append(nss, *lan...)
}
if pub := r.publicServers.Load(); pub != nil {
nss = append(nss, *pub...)
}
return nss
}
// AppendOsResolverNameservers adds additional nameservers to the existing OS resolver
// without reinitializing it. This is used for late-arriving nameservers such as AD
// domain controller IPs discovered via background retry.
// Returns true if nameservers were actually added.
func AppendOsResolverNameservers(servers []string) bool {
if len(servers) == 0 {
return false
}
resolverMutex.Lock()
defer resolverMutex.Unlock()
if or == nil {
return false
}
// Collect existing nameservers to avoid duplicates.
existing := make(map[string]bool)
if lan := or.lanServers.Load(); lan != nil {
for _, s := range *lan {
existing[s] = true
}
}
if pub := or.publicServers.Load(); pub != nil {
for _, s := range *pub {
existing[s] = true
}
}
var added bool
for _, s := range servers {
// Normalize to host:port format.
if _, _, err := net.SplitHostPort(s); err != nil {
s = net.JoinHostPort(s, "53")
}
if existing[s] {
continue
}
existing[s] = true
added = true
ip, _, _ := net.SplitHostPort(s)
addr, _ := netip.ParseAddr(ip)
if isLanAddr(addr) {
lan := or.lanServers.Load()
newLan := append(append([]string{}, (*lan)...), s)
or.lanServers.Store(&newLan)
} else {
pub := or.publicServers.Load()
newPub := append(append([]string{}, (*pub)...), s)
or.publicServers.Store(&newPub)
}
}
return added
}
// SetDefaultLocalIPv4 updates the stored local IPv4.
func SetDefaultLocalIPv4(ip net.IP) {
Log(context.Background(), ProxyLogger.Load().Debug(), "SetDefaultLocalIPv4: %s", ip)