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:
@@ -295,19 +295,27 @@ func (s *Server) handleCreateSession(req Request) Response {
|
||||
return Response{OK: false, Error: fmt.Sprintf("failed to start tunnel: %v", err)}
|
||||
}
|
||||
|
||||
// Step 2: Create DNS relay if dns_addr is provided.
|
||||
var dr *DNSRelay
|
||||
if req.DNSAddr != "" {
|
||||
var err error
|
||||
dr, err = NewDNSRelay(dnsRelayIP+":"+dnsRelayPort, req.DNSAddr, s.debug)
|
||||
if err != nil {
|
||||
_ = tm.Stop() // best-effort cleanup
|
||||
return Response{OK: false, Error: fmt.Sprintf("failed to create DNS relay: %v", err)}
|
||||
// Step 2: Create DNS relay. pf rules always redirect DNS (UDP:53) from
|
||||
// the sandbox group to the relay address, so we must always start the
|
||||
// relay when a proxy session is active. If no explicit DNS address was
|
||||
// provided, default to the proxy's DNS resolver.
|
||||
dnsTarget := req.DNSAddr
|
||||
if dnsTarget == "" {
|
||||
dnsTarget = defaultDNSTarget
|
||||
Logf("No dns_addr provided, defaulting DNS relay upstream to %s", dnsTarget)
|
||||
}
|
||||
dr, err := NewDNSRelay(dnsRelayIP+":"+dnsRelayPort, dnsTarget, s.debug)
|
||||
if err != nil {
|
||||
if stopErr := tm.Stop(); stopErr != nil {
|
||||
Logf("Warning: failed to stop tunnel during cleanup: %v", stopErr)
|
||||
}
|
||||
if err := dr.Start(); err != nil {
|
||||
_ = tm.Stop() // best-effort cleanup
|
||||
return Response{OK: false, Error: fmt.Sprintf("failed to start DNS relay: %v", err)}
|
||||
return Response{OK: false, Error: fmt.Sprintf("failed to create DNS relay: %v", err)}
|
||||
}
|
||||
if err := dr.Start(); err != nil {
|
||||
if stopErr := tm.Stop(); stopErr != nil {
|
||||
Logf("Warning: failed to stop tunnel during cleanup: %v", stopErr)
|
||||
}
|
||||
return Response{OK: false, Error: fmt.Sprintf("failed to start DNS relay: %v", err)}
|
||||
}
|
||||
|
||||
// Step 3: Resolve the sandbox group GID. pfctl in the LaunchDaemon
|
||||
@@ -318,9 +326,7 @@ func (s *Server) handleCreateSession(req Request) Response {
|
||||
grp, err := user.LookupGroup(SandboxGroupName)
|
||||
if err != nil {
|
||||
_ = tm.Stop()
|
||||
if dr != nil {
|
||||
dr.Stop()
|
||||
}
|
||||
dr.Stop()
|
||||
return Response{OK: false, Error: fmt.Sprintf("failed to resolve group %s: %v", SandboxGroupName, err)}
|
||||
}
|
||||
sandboxGID = grp.Gid
|
||||
@@ -328,9 +334,7 @@ func (s *Server) handleCreateSession(req Request) Response {
|
||||
}
|
||||
Logf("Loading pf rules for group %s (GID %s)", SandboxGroupName, sandboxGID)
|
||||
if err := tm.LoadPFRules(sandboxGID); err != nil {
|
||||
if dr != nil {
|
||||
dr.Stop()
|
||||
}
|
||||
dr.Stop()
|
||||
_ = tm.Stop() // best-effort cleanup
|
||||
return Response{OK: false, Error: fmt.Sprintf("failed to load pf rules: %v", err)}
|
||||
}
|
||||
@@ -338,9 +342,7 @@ func (s *Server) handleCreateSession(req Request) Response {
|
||||
// Step 4: Generate session ID and store.
|
||||
sessionID, err := generateSessionID()
|
||||
if err != nil {
|
||||
if dr != nil {
|
||||
dr.Stop()
|
||||
}
|
||||
dr.Stop()
|
||||
_ = tm.UnloadPFRules() // best-effort cleanup
|
||||
_ = tm.Stop() // best-effort cleanup
|
||||
return Response{OK: false, Error: fmt.Sprintf("failed to generate session ID: %v", err)}
|
||||
@@ -349,7 +351,7 @@ func (s *Server) handleCreateSession(req Request) Response {
|
||||
session := &Session{
|
||||
ID: sessionID,
|
||||
ProxyURL: req.ProxyURL,
|
||||
DNSAddr: req.DNSAddr,
|
||||
DNSAddr: dnsTarget,
|
||||
CreatedAt: time.Now(),
|
||||
}
|
||||
s.sessions[sessionID] = session
|
||||
|
||||
Reference in New Issue
Block a user