fix: use socks5h:// for macOS daemon DNS resolution through proxy

macOS getaddrinfo() uses mDNSResponder via Mach IPC and does NOT fall
back to direct UDP DNS when those services are blocked — it simply
fails with EAI_NONAME. This made DNS resolution fail for all sandboxed
processes in daemon mode.

Switch to setting ALL_PROXY=socks5h:// env var so proxy-aware apps
(curl, git, etc.) resolve hostnames through the SOCKS5 proxy. The "h"
suffix means "resolve hostname at proxy side". Only ALL_PROXY is set
(not HTTP_PROXY) to avoid breaking apps like Bun/Node.js.

Other changes:
- Revert opendirectoryd.libinfo and configd mach service blocks
- Exclude loopback (127.0.0.0/8) from pf TCP route-to to prevent
  double-proxying when ALL_PROXY connects directly to local proxy
- Always create DNS relay with default upstream (127.0.0.1:42053)
- Use always-on logging in DNS relay (not debug-only)
- Force IPv4 (udp4) for DNS relay upstream connections
- Log tunnel cleanup errors instead of silently discarding them
This commit is contained in:
2026-03-02 12:04:36 -06:00
parent 796c22f736
commit 20ee23c1c3
4 changed files with 68 additions and 65 deletions

View File

@@ -5,7 +5,6 @@ package daemon
import (
"fmt"
"net"
"os"
"sync"
"time"
)
@@ -77,9 +76,7 @@ func (d *DNSRelay) ListenAddr() string {
// listening socket and spawns a goroutine per query to forward it to the
// upstream DNS server and relay the response back.
func (d *DNSRelay) Start() error {
if d.debug {
fmt.Fprintf(os.Stderr, "[greywall:dns-relay] Listening on %s, forwarding to %s\n", d.listenAddr, d.targetAddr)
}
Logf("DNS relay listening on %s, forwarding to %s", d.listenAddr, d.targetAddr)
d.wg.Add(1)
go d.readLoop()
@@ -94,9 +91,7 @@ func (d *DNSRelay) Stop() {
_ = d.udpConn.Close()
d.wg.Wait()
if d.debug {
fmt.Fprintf(os.Stderr, "[greywall:dns-relay] Stopped\n")
}
Logf("DNS relay stopped")
}
// readLoop is the main loop that reads incoming DNS queries from the listening socket.
@@ -112,7 +107,7 @@ func (d *DNSRelay) readLoop() {
// Shutting down, expected error from closed socket.
return
default:
fmt.Fprintf(os.Stderr, "[greywall:dns-relay] Read error: %v\n", err)
Logf("DNS relay: read error: %v", err)
continue
}
}
@@ -136,36 +131,33 @@ func (d *DNSRelay) readLoop() {
func (d *DNSRelay) handleQuery(query []byte, clientAddr *net.UDPAddr) {
defer d.wg.Done()
if d.debug {
fmt.Fprintf(os.Stderr, "[greywall:dns-relay] Query from %s (%d bytes)\n", clientAddr, len(query))
}
Logf("DNS relay: query from %s (%d bytes)", clientAddr, len(query))
// Create a dedicated UDP connection to the upstream DNS server.
upstreamConn, err := net.Dial("udp", d.targetAddr)
// Use "udp4" to force IPv4, since the upstream may only listen on 127.0.0.1.
upstreamConn, err := net.Dial("udp4", d.targetAddr)
if err != nil {
fmt.Fprintf(os.Stderr, "[greywall:dns-relay] Failed to connect to upstream %s: %v\n", d.targetAddr, err)
Logf("DNS relay: failed to connect to upstream %s: %v", d.targetAddr, err)
return
}
defer upstreamConn.Close() //nolint:errcheck // best-effort cleanup of per-query UDP connection
// Send the query to the upstream server.
if _, err := upstreamConn.Write(query); err != nil {
fmt.Fprintf(os.Stderr, "[greywall:dns-relay] Failed to send query to upstream: %v\n", err)
Logf("DNS relay: failed to send query to upstream: %v", err)
return
}
// Wait for the response with a timeout.
if err := upstreamConn.SetReadDeadline(time.Now().Add(upstreamTimeout)); err != nil {
fmt.Fprintf(os.Stderr, "[greywall:dns-relay] Failed to set read deadline: %v\n", err)
Logf("DNS relay: failed to set read deadline: %v", err)
return
}
resp := make([]byte, maxDNSPacketSize)
n, err := upstreamConn.Read(resp)
if err != nil {
if d.debug {
fmt.Fprintf(os.Stderr, "[greywall:dns-relay] Upstream response error: %v\n", err)
}
Logf("DNS relay: upstream response error from %s: %v", d.targetAddr, err)
return
}
@@ -176,11 +168,9 @@ func (d *DNSRelay) handleQuery(query []byte, clientAddr *net.UDPAddr) {
case <-d.done:
return
default:
fmt.Fprintf(os.Stderr, "[greywall:dns-relay] Failed to send response to %s: %v\n", clientAddr, err)
Logf("DNS relay: failed to send response to %s: %v", clientAddr, err)
}
}
if d.debug {
fmt.Fprintf(os.Stderr, "[greywall:dns-relay] Response to %s (%d bytes)\n", clientAddr, n)
}
Logf("DNS relay: response to %s (%d bytes)", clientAddr, n)
}