From 8b85577eca083795b709d44b1ba97e500b031f3d Mon Sep 17 00:00:00 2001 From: Antoine U Date: Thu, 25 Jan 2024 20:36:45 +0100 Subject: [PATCH 1/4] fixes auto_join for mDNS provider --- vault/raft.go | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/vault/raft.go b/vault/raft.go index 585c0f08af3f..e8611296e871 100644 --- a/vault/raft.go +++ b/vault/raft.go @@ -8,8 +8,10 @@ import ( "encoding/base64" "errors" "fmt" + "net" "net/http" "net/url" + "strconv" "strings" "sync" "sync/atomic" @@ -1227,9 +1229,18 @@ func (c *Core) raftLeaderInfo(leaderInfo *raft.LeaderJoinInfo, disco *discover.D return nil, fmt.Errorf("failed to parse addresses from auto-join metadata: %w", err) } for _, ip := range clusterIPs { - if strings.Count(ip, ":") >= 2 && !strings.HasPrefix(ip, "[") { + if count := strings.Count(ip, ":"); count >= 2 && !strings.HasPrefix(ip, "[") { // An IPv6 address in implicit form, however we need it in explicit form to use in a URL. ip = fmt.Sprintf("[%s]", ip) + } else if count > 0 && !strings.HasSuffix(ip, "]") { + tmpIp, portStr, err := net.SplitHostPort(ip) + if err == nil { + ip = tmpIp + tmpPort, err := strconv.Atoi(portStr) + if err == nil { + port = uint(tmpPort) + } + } } u := fmt.Sprintf("%s://%s:%d", scheme, ip, port) info := *leaderInfo From 99652744b02b4a08ad1fd137ae510b340f2df5d4 Mon Sep 17 00:00:00 2001 From: Antoine U Date: Wed, 22 May 2024 17:14:44 +0200 Subject: [PATCH 2/4] adds a function to format addresses returned by go-discover --- vault/raft.go | 36 ++++++++++++++++++++---------------- vault/raft_test.go | 29 +++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 16 deletions(-) create mode 100644 vault/raft_test.go diff --git a/vault/raft.go b/vault/raft.go index 5c664c8decbd..2948d5e68beb 100644 --- a/vault/raft.go +++ b/vault/raft.go @@ -11,7 +11,6 @@ import ( "net" "net/http" "net/url" - "strconv" "strings" "sync" "sync/atomic" @@ -1226,26 +1225,15 @@ func (c *Core) raftLeaderInfo(leaderInfo *raft.LeaderJoinInfo, disco *discover.D // default to 8200 when no port is provided port = 8200 } - // Addrs returns either IPv4 or IPv6 address, without scheme or port + // Addrs returns either IPv4 or IPv6 address, without scheme and most of them without port + // IPv6 can be explicit such as "[::1]" or implicit "::1" clusterIPs, err := disco.Addrs(leaderInfo.AutoJoin, c.logger.StandardLogger(nil)) if err != nil { return nil, fmt.Errorf("failed to parse addresses from auto-join metadata: %w", err) } for _, ip := range clusterIPs { - if count := strings.Count(ip, ":"); count >= 2 && !strings.HasPrefix(ip, "[") { - // An IPv6 address in implicit form, however we need it in explicit form to use in a URL. - ip = fmt.Sprintf("[%s]", ip) - } else if count > 0 && !strings.HasSuffix(ip, "]") { - tmpIp, portStr, err := net.SplitHostPort(ip) - if err == nil { - ip = tmpIp - tmpPort, err := strconv.Atoi(portStr) - if err == nil { - port = uint(tmpPort) - } - } - } - u := fmt.Sprintf("%s://%s:%d", scheme, ip, port) + addr := formatDiscoveredAddr(ip, port) + u := fmt.Sprintf("%s://%s", scheme, addr) info := *leaderInfo info.LeaderAPIAddr = u ret = append(ret, &info) @@ -1467,3 +1455,19 @@ func newDiscover() (*discover.Discover, error) { discover.WithProviders(providers), ) } + +// formatAddr join ip and port if addr does not already contain a port +func formatDiscoveredAddr(addr string, defaultPort uint) string { + // addr is an implicit IPv6 address + if !strings.HasPrefix(addr, "[") && strings.Count(addr, ":") > 1 { + return fmt.Sprintf("[%s]:%d", addr, defaultPort) + } + ip, port, err := net.SplitHostPort(addr) + if err != nil { + return fmt.Sprintf("%s:%d", addr, defaultPort) + } + if strings.ContainsRune(ip, ':') { + ip = fmt.Sprintf("[%s]", ip) + } + return fmt.Sprintf("%s:%s", ip, port) +} diff --git a/vault/raft_test.go b/vault/raft_test.go new file mode 100644 index 000000000000..245d22fe2f68 --- /dev/null +++ b/vault/raft_test.go @@ -0,0 +1,29 @@ +package vault + +import ( + "testing" +) + +func TestFormatDiscoveredAddr(t *testing.T) { + type TestCase struct { + addr string + port uint + res string + } + cases := []TestCase{ + {addr: "127.0.0.1", port: uint(8200), res: "127.0.0.1:8200"}, + {addr: "192.168.137.1:8201", port: uint(8200), res: "192.168.137.1:8201"}, + {addr: "fe80::aa5e:45ff:fe54:c6ce", port: uint(8200), res: "[fe80::aa5e:45ff:fe54:c6ce]:8200"}, + {addr: "::1", port: uint(8200), res: "[::1]:8200"}, + {addr: "[::1]", port: uint(8200), res: "[::1]:8200"}, + {addr: "[::1]:8201", port: uint(8200), res: "[::1]:8201"}, + {addr: "[fe80::aa5e:45ff:fe54:c6ce]", port: uint(8200), res: "[fe80::aa5e:45ff:fe54:c6ce]:8200"}, + {addr: "[fe80::aa5e:45ff:fe54:c6ce]:8201", port: uint(8200), res: "[fe80::aa5e:45ff:fe54:c6ce]:8201"}, + } + for i, c := range cases { + res := formatDiscoveredAddr(c.addr, c.port) + if res != c.res { + t.Errorf("case %d result shoud be \"%s\" but is \"%s\"", i, c.res, res) + } + } +} From 7927b2c932c08f947c07625d98e8c927f18af495 Mon Sep 17 00:00:00 2001 From: Antoine U Date: Wed, 22 May 2024 17:24:45 +0200 Subject: [PATCH 3/4] adds copyright header in raft_rest.go --- vault/raft_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/vault/raft_test.go b/vault/raft_test.go index 245d22fe2f68..2aac0ba4eda5 100644 --- a/vault/raft_test.go +++ b/vault/raft_test.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + package vault import ( From 882300c46222aaf8a9a4fd712d275350c0acf5f0 Mon Sep 17 00:00:00 2001 From: Antoine U Date: Mon, 10 Jun 2024 11:29:43 +0200 Subject: [PATCH 4/4] Adds changelog file for PR #25080, godoc for TestFormatDiscoveredAddr --- changelog/25080.txt | 3 +++ vault/raft.go | 2 +- vault/raft_test.go | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 changelog/25080.txt diff --git a/changelog/25080.txt b/changelog/25080.txt new file mode 100644 index 000000000000..ad43618d8281 --- /dev/null +++ b/changelog/25080.txt @@ -0,0 +1,3 @@ +```release-note:bug +storage/raft: Fix auto_join not working with mDNS provider. +``` diff --git a/vault/raft.go b/vault/raft.go index c1e40e3db7e9..23fdb207fc08 100644 --- a/vault/raft.go +++ b/vault/raft.go @@ -1459,7 +1459,7 @@ func newDiscover() (*discover.Discover, error) { ) } -// formatAddr join ip and port if addr does not already contain a port +// formatDiscoveredAddr joins ip and port if addr does not already contain a port func formatDiscoveredAddr(addr string, defaultPort uint) string { // addr is an implicit IPv6 address if !strings.HasPrefix(addr, "[") && strings.Count(addr, ":") > 1 { diff --git a/vault/raft_test.go b/vault/raft_test.go index 2aac0ba4eda5..b5f54b590519 100644 --- a/vault/raft_test.go +++ b/vault/raft_test.go @@ -7,6 +7,7 @@ import ( "testing" ) +// TestFormatDiscoveredAddr validates that the string returned by formatDiscoveredAddr always respect the format `host:port`. func TestFormatDiscoveredAddr(t *testing.T) { type TestCase struct { addr string