Add diagnostic and setup commands so users can verify their environment
and install greyproxy without leaving greywall:
- `greywall check`: shows version, platform deps, security features,
and greyproxy installation/running status (absorbs old --version output)
- `greywall setup`: downloads greyproxy from GitHub releases and shells
out to `greyproxy install`, or auto-starts if already installed
- `--version` simplified to single-line output for scripting
New `internal/proxy/` package handles greyproxy detection (LookPath +
/api/health endpoint), GitHub release fetching, tar.gz extraction,
and service lifecycle management.
The Landlock wrapper re-executes the greywall binary inside the sandbox
with --landlock-apply. When greywall is run from a path outside the CWD
(e.g., ~/bin/greywall from /home/user/project), the binary doesn't exist
inside the sandbox because only system paths and CWD are mounted. This
adds a --ro-bind for the greywall executable so the wrapper always works
regardless of where the binary is located.
intermediaryDirs() was called with the full path including the leaf
component, causing --dir to be emitted for files like ~/.npmrc. This
created a directory at that path, making the subsequent --ro-bind fail
with "Can't create file at ...: Is a directory".
Now checks isDirectory() and uses filepath.Dir() for file paths so
intermediary dirs are only created up to the parent.
- Deny-by-default filesystem isolation for Linux (Landlock) and macOS (Seatbelt)
- Prevent learning mode from collapsing read paths to $HOME
- Add Linux deny-by-default lessons to experience docs
Show installed dependencies, security features, and transparent proxy
availability when running --version. Detect AppArmor
unprivileged_userns restriction on Ubuntu 24.04+ and suggest the fix.
Document the RTM_NEWADDR issue in experience.md.
The DnsBridge socat relay was forwarding queries via TCP, but the
GreyHaven DNS service (gost) only listens on UDP, causing DNS
resolution failures ("Could not resolve host") inside the sandbox.
Skip --new-session in learning mode so interactive programs can access
/dev/tty, and run strace in the foreground to preserve terminal stdin.
Also skip template generation when the traced command exits non-zero,
since the strace trace would be incomplete.
Default proxy to socks5://localhost:42052 and DNS to localhost:42053
when neither CLI flags nor config file specify them. This makes greywall
work out of the box with GreyHaven without requiring --proxy or --dns.
Also show both proxy and DNS in debug output on manager initialization.
Learning mode (--learning) traces filesystem access with strace and
generates minimal sandbox config templates. A background monitor kills
strace when the main command exits so long-lived child processes (LSP
servers, file watchers) don't cause hangs.
Other changes:
- Add 'greywall templates list/show' subcommand
- Add --template flag to load specific learned templates
- Fix DNS relay: use TCP DNS (options use-vc) instead of broken UDP
relay through tun2socks
- Filter O_DIRECTORY opens from learned read paths
- Add docs/experience.md with development notes
Rebrand the project from Fence to Greywall, the sandboxing layer of the
GreyHaven platform. This updates:
- Go module path to gitea.app.monadical.io/monadical/greywall
- Binary name, CLI help text, and all usage examples
- Config paths (~/.config/greywall/greywall.json), env vars (GREYWALL_*)
- Log prefixes ([greywall:*]), temp file prefixes (greywall-*)
- All documentation, scripts, CI workflows, and example files
- README rewritten with GreyHaven branding and Fence attribution
Directory/file renames: cmd/fence → cmd/greywall, pkg/fence → pkg/greywall,
docs/why-fence.md → docs/why-greywall.md, example JSON files, and banner.
Three issues prevented transparent proxying from working end-to-end:
1. bwrap dropped CAP_NET_ADMIN before exec, so ip tuntap/link commands
failed inside the sandbox. Add --cap-add CAP_NET_ADMIN and
CAP_NET_BIND_SERVICE when transparent proxy is active.
2. tun2socks only offered SOCKS5 no-auth (method 0x00), but many proxies
(e.g. gost) require username/password auth (method 0x02). Pass through
credentials from the proxy URL so tun2socks offers both auth methods.
3. DNS resolution failed because UDP DNS needs SOCKS5 UDP ASSOCIATE which
most proxies don't support. Add --dns flag and DnsBridge that routes
DNS queries from the sandbox through a Unix socket to a host-side DNS
server. Falls back to TCP relay through the tunnel when no --dns is set.
Also brings up loopback interface (ip link set lo up) inside the network
namespace so socat can bind to 127.0.0.1.
Remove the built-in HTTP/SOCKS5 proxy servers and domain allowlist/denylist
system. Instead, use tun2socks with a TUN device inside the network namespace
to transparently route all TCP/UDP traffic through an external SOCKS5 proxy.
This enables truly transparent proxying where any binary (Go, static, etc.)
has its traffic routed through the proxy without needing to respect
HTTP_PROXY/ALL_PROXY environment variables. The external proxy handles its
own filtering.
Key changes:
- NetworkConfig: remove AllowedDomains/DeniedDomains/proxy ports, add ProxyURL
- Delete internal/proxy/, internal/templates/, internal/importer/
- Embed tun2socks binary (downloaded at build time via Makefile)
- Replace LinuxBridge with ProxyBridge (single Unix socket to external proxy)
- Inner script sets up TUN device + tun2socks inside network namespace
- Falls back to env-var proxying when TUN is unavailable
- macOS: best-effort env-var proxying to external SOCKS5 proxy
- CLI: remove --template/import, add --proxy flag
- Feature detection: add ip/tun/tun2socks status to --linux-features
The glob expansion using **/pattern patterns caused full filesystem walks
of the current directory for each pattern (~15 patterns = ~15 walks).
This caused hangs in directories with many files (e.g., node_modules).
The concrete paths from getMandatoryDenyPaths() are sufficient for bwrap's
--ro-bind protections. Landlock (applied via wrapper) provides additional
recursive protection.
Fixes#27