util: do not bind outbound dials to a loopback -ip.bind (#12198)

`weed server -ip.bind=127.0.0.1` keeps every listener local, but the
same address became the source of outbound connections, so the filer
dialled its remote mount from 127.0.0.1 and failed with "connect:
invalid argument". A loopback source cannot reach off the host; leave
the source to the OS, as for a wildcard bind.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
multivac61andClaude Opus 5.5 authored and GitHub committed 2026-10-29 01:35:00 -07:00
1 parent 43626431c3
commit d21a1eda54
2 files changed
+9 -3

No files matched your search

+5 -3
View File
@@ -20,8 +20,10 @@ var (
)
// SetOutboundLocalIP records ip as the source address for outbound TCP
// connections. An empty, wildcard (0.0.0.0 / ::), or unparseable value leaves
// the source address to the OS.
// connections. An empty, wildcard (0.0.0.0 / ::), loopback, or unparseable
// value leaves the source address to the OS: a loopback source cannot reach
// anything off the host, so `-ip.bind=127.0.0.1` (listen locally only) would
// otherwise break every dial to a remote S3 endpoint or peer.
//
// The first call wins. `weed server` applies the top-level -ip.bind before its
// embedded master/volume/filer/s3/... start, so a component's own (possibly
@@ -32,7 +34,7 @@ func SetOutboundLocalIP(ip string) {
return
}
parsed := net.ParseIP(ip)
if parsed == nil || parsed.IsUnspecified() {
if parsed == nil || parsed.IsUnspecified() || parsed.IsLoopback() {
return
}
outboundLocalAddr.Store(&net.TCPAddr{IP: parsed})
+4
View File
@@ -24,6 +24,10 @@ func TestSetOutboundLocalIP(t *testing.T) {
{"empty", "", ""},
{"wildcard v4", "0.0.0.0", ""},
{"wildcard v6", "::", ""},
// A loopback source cannot reach anything off the host, so binding to
// one would break every dial to a remote endpoint (S3, peers).
{"loopback v4", "127.0.0.1", ""},
{"loopback v6", "::1", ""},
{"garbage", "not-an-ip", ""},
}
for _, tc := range cases {