From cc19c7801fd5c0382951c5d1d7773632c38918c0 Mon Sep 17 00:00:00 2001 From: Raphael Fakhri <153192858+RaphaelFakhri@users.noreply.github.com> Date: Sat, 24 Oct 2026 15:59:13 +0000 Subject: [PATCH] cmd/tailcat: accept a bare IPv6 address in socks --listen The socks --listen flag documents that a bare address means an OS-assigned port, but normalizeListenAddrPort appended ":0" to an unbracketed IPv6 address, so --listen=::1 became "::1:0" and the proxy exited with "too many colons in address". Join a bare IP address with port 0 via net.JoinHostPort, which brackets IPv6. --- cmd/tailcat/socks_test.go | 10 ++++++++++ cmd/tailcat/tailcat.go | 6 +++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/cmd/tailcat/socks_test.go b/cmd/tailcat/socks_test.go index bb288ff48..a3d5a2b3f 100644 --- a/cmd/tailcat/socks_test.go +++ b/cmd/tailcat/socks_test.go @@ -203,6 +203,16 @@ func TestNormalizeListenAddrPort(t *testing.T) { input: "[2001:db8::1]", want: "[2001:db8::1]:0", }, + { + name: "omit port with unbracketed IPv6 address", + input: "::1", + want: "[::1]:0", + }, + { + name: "omit port with unbracketed IPv6 unspecified address", + input: "::", + want: "[::]:0", + }, { name: "others", input: "foo", diff --git a/cmd/tailcat/tailcat.go b/cmd/tailcat/tailcat.go index 31d0ab4ec..7bb847262 100644 --- a/cmd/tailcat/tailcat.go +++ b/cmd/tailcat/tailcat.go @@ -999,8 +999,12 @@ func normalizeListenAddrPort(s string) string { return net.JoinHostPort(host, port) } else if port, err := strconv.ParseUint(s, 10, 16); err == nil { return net.JoinHostPort("127.0.0.1", strconv.Itoa(int(port))) + } else if _, err := netip.ParseAddr(s); err == nil { + // A bare IP address. JoinHostPort brackets an IPv6 address + // such as "::1", which appending ":0" would leave ambiguous. + return net.JoinHostPort(s, "0") } - // Assume it's a hostname or IP without a port. + // Assume it's a hostname without a port. return s + ":0" }