mirror of
https://github.com/Control-D-Inc/ctrld.git
synced 2026-04-20 00:36:37 +02:00
fix: block IPv6 DNS in intercept mode, remove raw socket approach
IPv6 DNS interception on macOS is not feasible with current pf capabilities.
The kernel rejects sendmsg from [::1] to global unicast (EINVAL), nat on lo0
doesn't fire for route-to'd packets, raw sockets bypass routing but pf doesn't
match them against rdr state, and DIOCNATLOOK can't be used because bind()
fails for non-local addresses.
Replace all IPv6 interception code with a simple pf block rule:
block out quick on ! lo0 inet6 proto { udp, tcp } from any to any port 53
macOS automatically retries DNS over IPv4 when IPv6 is blocked.
Changes:
- Remove rawipv6_darwin.go and rawipv6_other.go
- Remove [::1] listener spawn on macOS (needLocalIPv6Listener returns false)
- Remove IPv6 rdr, route-to, pass, and reply-to pf rules
- Add block rule for all outbound IPv6 DNS
- Update docs/pf-dns-intercept.md with what was tried and why it failed
This commit is contained in:
committed by
Cuong Manh Le
parent
c55e2a722c
commit
3f59cdad1a
+8
-15
@@ -211,11 +211,7 @@ func (p *prog) serveDNS(listenerNum string) error {
|
||||
proto := proto
|
||||
if needLocalIPv6Listener(p.cfg.Service.InterceptMode) {
|
||||
g.Go(func() error {
|
||||
var ipv6Handler dns.Handler = handler
|
||||
if proto == "udp" {
|
||||
ipv6Handler = wrapIPv6Handler(handler)
|
||||
}
|
||||
s, errCh := runDNSServer(net.JoinHostPort("::1", strconv.Itoa(listenerConfig.Port)), proto, ipv6Handler)
|
||||
s, errCh := runDNSServer(net.JoinHostPort("::1", strconv.Itoa(listenerConfig.Port)), proto, handler)
|
||||
defer s.Shutdown()
|
||||
select {
|
||||
case <-p.stopCh:
|
||||
@@ -907,16 +903,13 @@ func needLocalIPv6Listener(interceptMode string) bool {
|
||||
mainLog.Load().Debug().Msg("IPv6 listener: enabled (Windows)")
|
||||
return true
|
||||
}
|
||||
// On macOS in intercept mode, pf can't redirect IPv6 DNS to an IPv4 listener (cross-AF rdr
|
||||
// not supported), and blocking IPv6 DNS causes ~1s timeouts (BSD doesn't deliver ICMP errors
|
||||
// to unconnected UDP sockets). Listening on [::1] lets us intercept IPv6 DNS directly.
|
||||
//
|
||||
// NOTE: We accept the intercept mode string as a parameter instead of reading the global
|
||||
// dnsIntercept bool, because dnsIntercept is derived later in prog.run() — after the
|
||||
// listener goroutines are already spawned. Same pattern as the port 5354 fallback fix (MR !860).
|
||||
if (interceptMode == "dns" || interceptMode == "hard") && runtime.GOOS == "darwin" {
|
||||
mainLog.Load().Debug().Msg("IPv6 listener: enabled (macOS intercept mode)")
|
||||
return true
|
||||
// macOS: IPv6 DNS is blocked at the pf level (not intercepted). The [::1] listener
|
||||
// is not needed — macOS falls back to IPv4 DNS automatically. See #507 and
|
||||
// docs/pf-dns-intercept.md for why IPv6 interception on macOS is not feasible
|
||||
// (sendmsg EINVAL from ::1 to global unicast, nat-on-lo0 doesn't fire for route-to).
|
||||
if runtime.GOOS == "darwin" {
|
||||
mainLog.Load().Debug().Msg("IPv6 listener: not needed (macOS — IPv6 DNS blocked at pf, fallback to IPv4)")
|
||||
return false
|
||||
}
|
||||
mainLog.Load().Debug().Str("os", runtime.GOOS).Str("interceptMode", interceptMode).Msg("IPv6 listener: not needed")
|
||||
return false
|
||||
|
||||
Reference in New Issue
Block a user