feat: bind to localhost by default, --host for opt-in#53
Merged
Conversation
…lpers Prepare for binding listeners to localhost by default. The helpers added here are the building blocks; the parser, CLI flag, and embedded default config are wired up in follow-up commits. - applyDefaultHost rewrites bare ":PORT" / "PORT" addrs by prepending a default host; explicit hosts are preserved so operator overrides win. - walkAddresses applies the helper across services / metrics / profiling. - ParseHostFlag validates the --host flag, accepting IP literals only. Tests cover IPv4, IPv6, unix sockets, empty input, and bracket handling.
Plumbs the resolved bind host (CLI flag > YAML host: > 127.0.0.1) through parser.Parse so service / metrics / profiling addresses written as a bare port get rewritten before listeners are constructed. Explicit hosts are left alone so operator overrides keep winning. The expanded parser_test.go runs a full YAML roundtrip and confirms net.Listen with the normalized address actually produces a loopback (or unspecified, with --host 0.0.0.0) socket on the test platform.
…RN on unspecified bind
- main.go registers --host as a top-level serve flag; rejects hostnames
(IP literal only) so operators don't have to wonder which resolved
address the listener picked.
- program.go applies the resolved host to the dashboard address (read
through viper) and to the profiling fallback (":6060"), since those
paths sit outside the parser's cfg.Services walk.
- warnIfUnspecifiedBind logs a single warning at startup whenever the
resolved host is 0.0.0.0 / ::, so the choice is visible in logs.
- greyproxy.yml (the embedded default) now sets host: 127.0.0.1 explicitly. - docs/configuration.md gains a Bind Interface section explaining the precedence order (flag > YAML > built-in default). - docs/cli-reference.md documents --host and notes installed services bind to loopback (operators edit the unit/plist for LAN exposure). - SECURITY.md replaces the stock GitHub template with a Default Security Posture section listing the four ports + how to opt into a wider bind.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #52.
Summary
127.0.0.1. Today greyproxy binds the dashboard, HTTP/SOCKS5/DNS proxies, metrics, and profiling all to0.0.0.0because the addresses in the embedded config are bare:PORTstrings.--host <ip>flag ongreyproxy serveand a top-levelhost:YAML field, IP literal only (hostnames rejected with a clear error).127.0.0.1. Addresses with an explicit host (0.0.0.0:43080,192.168.1.10:43080,[::1]:43080) are left alone so operator intent wins.0.0.0.0/::), so the choice is visible in logs.SECURITY.mdreplaced (it was the stock GitHub template) with a Default Security Posture section listing the four ports + the opt-in path.What changed where
internal/gostx/config/parsing/parser/host.go,host_test.gointernal/gostx/config/parsing/parser/parser.go,internal/gostx/config/config.gocmd/greyproxy/main.go,cmd/greyproxy/program.gogreyproxy.ymldocs/configuration.md,docs/cli-reference.md,SECURITY.mdGreywall companion compatibility
Read the greywall source to verify nothing breaks:
bwrap --unshare-netplus a socat bridge that targetsTCP:127.0.0.1:<port>on the host (internal/sandbox/linux.go:354-357). Exactly what greyproxy will be listening on after this PR. ✅sandbox-execrules uselocalhost:<port>; getaddrinfo resolves to127.0.0.1(and::1). TCP paths are fine because Happy Eyeballs falls back from::1to127.0.0.1on connection refused. UDP DNS is the one edge case — if macOS getaddrinfo hands back::1first and socat doesn't iterate, queries vanish. In practice macOS default gai.conf prefers IPv4 for loopback, so this rarely fires.Recommended follow-up (separate, in the greywall repo, not this PR): change greywall's defaults from
localhost:<port>to127.0.0.1:<port>to eliminate the IPv6 ambiguity entirely.Test plan
go test ./...— all green (the newinternal/gostx/config/parsing/parsertests cover the helper, parser roundtrip, realnet.Listenbehaviour, and--hostflag validation).go vet ./...— clean.go build ./cmd/greyproxy, ran with a custom config,lsof -nP -iTCP -sTCP:LISTENconfirms listeners on127.0.0.1:<port>(not*:<port>).greyproxy serve --host 0.0.0.0— WARN linebinding listeners to all interfaces (host=0.0.0.0)...fires, listeners bind everywhere.greyproxy serve --host bogus— exits 2 with--host: host requires a literal IP address, got "bogus".greyproxy serve -O yaml— resolved config shows all four service addrs prefixed with127.0.0.1:.greywall run -- dig example.com— to catch the IPv6 DNS edge case if it ever surfaces in practice.Breaking change notes
This is a behaviour change for anyone who was reaching the dashboard or proxy ports from another host with the default config. To restore the old behaviour, either:
--host 0.0.0.0togreyproxy serve, orhost: 0.0.0.0at the top of the config file.Release notes should call this out.