diff --git a/CHANGELOG-3.6.md b/CHANGELOG-3.6.md index 03f13319f..2560e0578 100644 --- a/CHANGELOG-3.6.md +++ b/CHANGELOG-3.6.md @@ -41,6 +41,7 @@ See [code changes](https://github.com/etcd-io/etcd/compare/v3.5.0...v3.6.0). - Fix [Lease checkpoints don't prevent to reset ttl on leader change](https://github.com/etcd-io/etcd/pull/13508). - Fix [assertion failed due to tx closed when recovering v3 backend from a snapshot db](https://github.com/etcd-io/etcd/pull/13500) - Fix [A client can panic etcd by passing invalid utf-8 in the client-api-version header](https://github.com/etcd-io/etcd/pull/13560) +- Fix [etcd gateway doesn't format the endpoint of IPv6 address correctly](https://github.com/etcd-io/etcd/pull/13551) ### tools/benchmark diff --git a/server/proxy/tcpproxy/userspace.go b/server/proxy/tcpproxy/userspace.go index 81421bffa..4df69aca8 100644 --- a/server/proxy/tcpproxy/userspace.go +++ b/server/proxy/tcpproxy/userspace.go @@ -19,6 +19,7 @@ import ( "io" "math/rand" "net" + "strings" "sync" "time" @@ -69,13 +70,29 @@ type TCPProxy struct { pickCount int // for round robin } +// The parameter host is returned by net.SplitHostPort previously, +// so it must be a valid host. This function is only to check whether +// it's an IPv6 IP address. +func isIPv6(host string) bool { + return strings.IndexRune(host, ':') != -1 +} + +// A literal IPv6 address in hostport must be enclosed in square +// brackets, as in "[::1]:80", "[::1%lo0]:80". +func formatAddr(host string, port uint16) string { + if isIPv6(host) { + return fmt.Sprintf("[%s]:%d", host, port) + } + return fmt.Sprintf("%s:%d", host, port) +} + func (tp *TCPProxy) Run() error { tp.donec = make(chan struct{}) if tp.MonitorInterval == 0 { tp.MonitorInterval = 5 * time.Minute } for _, srv := range tp.Endpoints { - addr := fmt.Sprintf("%s:%d", srv.Target, srv.Port) + addr := formatAddr(srv.Target, srv.Port) tp.remotes = append(tp.remotes, &remote{srv: srv, addr: addr}) } diff --git a/server/proxy/tcpproxy/userspace_test.go b/server/proxy/tcpproxy/userspace_test.go index 2b98cd004..892e87eb8 100644 --- a/server/proxy/tcpproxy/userspace_test.go +++ b/server/proxy/tcpproxy/userspace_test.go @@ -129,3 +129,34 @@ func TestUserspaceProxyPriority(t *testing.T) { t.Errorf("got = %s, want %s", got, want) } } + +func TestFormatAddr(t *testing.T) { + addrs := []struct { + host string + port uint16 + expectedAddr string + }{ + { + "192.168.1.10", + 2379, + "192.168.1.10:2379", + }, + { + "::1", + 2379, + "[::1]:2379", + }, + { + "2001:db8::ff00:42:8329", + 80, + "[2001:db8::ff00:42:8329]:80", + }, + } + + for _, addr := range addrs { + actualAddr := formatAddr(addr.host, addr.port) + if actualAddr != addr.expectedAddr { + t.Errorf("actualAddr: %s, expectedAddr: %s", actualAddr, addr.expectedAddr) + } + } +}