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
Sandboxed commands previously ran as `sudo -u _greywall`, breaking user
identity (home dir, SSH keys, git config). Now uses `sudo -u #<uid> -g
_greywall` so the process keeps the real user's identity while pf
matches
on EGID for traffic routing.
Key changes:
- pf rules use `group <GID>` instead of `user _greywall`
- GID resolved dynamically at daemon startup (not hardcoded, since macOS
system groups like com.apple.access_ssh may claim preferred IDs)
- Sudoers rule installed at /etc/sudoers.d/greywall (validated with
visudo)
- Invoking user added to _greywall group via dscl (not dseditgroup,
which
clobbers group attributes)
- tun2socks device discovery scans both stdout and stderr (fixes 10s
timeout caused by STACK message going to stdout)
- Always-on daemon logging for session create/destroy events