diff options
Diffstat (limited to 'vendor/github.com/hashicorp/memberlist')
-rw-r--r-- | vendor/github.com/hashicorp/memberlist/config.go | 18 | ||||
-rw-r--r-- | vendor/github.com/hashicorp/memberlist/memberlist_test.go | 129 | ||||
-rw-r--r-- | vendor/github.com/hashicorp/memberlist/net.go | 17 | ||||
-rw-r--r-- | vendor/github.com/hashicorp/memberlist/state_test.go | 2 |
4 files changed, 156 insertions, 10 deletions
diff --git a/vendor/github.com/hashicorp/memberlist/config.go b/vendor/github.com/hashicorp/memberlist/config.go index 2f43d14cb..5cad4ed54 100644 --- a/vendor/github.com/hashicorp/memberlist/config.go +++ b/vendor/github.com/hashicorp/memberlist/config.go @@ -141,6 +141,16 @@ type Config struct { GossipNodes int GossipToTheDeadTime time.Duration + // GossipVerifyIncoming controls whether to enforce encryption for incoming + // gossip. It is used for upshifting from unencrypted to encrypted gossip on + // a running cluster. + GossipVerifyIncoming bool + + // GossipVerifyOutgoing controls whether to enforce encryption for outgoing + // gossip. It is used for upshifting from unencrypted to encrypted gossip on + // a running cluster. + GossipVerifyOutgoing bool + // EnableCompression is used to control message compression. This can // be used to reduce bandwidth usage at the cost of slightly more CPU // utilization. This is only available starting at protocol version 1. @@ -233,9 +243,11 @@ func DefaultLANConfig() *Config { DisableTcpPings: false, // TCP pings are safe, even with mixed versions AwarenessMaxMultiplier: 8, // Probe interval backs off to 8 seconds - GossipNodes: 3, // Gossip to 3 nodes - GossipInterval: 200 * time.Millisecond, // Gossip more rapidly - GossipToTheDeadTime: 30 * time.Second, // Same as push/pull + GossipNodes: 3, // Gossip to 3 nodes + GossipInterval: 200 * time.Millisecond, // Gossip more rapidly + GossipToTheDeadTime: 30 * time.Second, // Same as push/pull + GossipVerifyIncoming: true, + GossipVerifyOutgoing: true, EnableCompression: true, // Enable compression by default diff --git a/vendor/github.com/hashicorp/memberlist/memberlist_test.go b/vendor/github.com/hashicorp/memberlist/memberlist_test.go index ff03ab3e4..964112dfd 100644 --- a/vendor/github.com/hashicorp/memberlist/memberlist_test.go +++ b/vendor/github.com/hashicorp/memberlist/memberlist_test.go @@ -326,6 +326,12 @@ func TestMemberList_ResolveAddr(t *testing.T) { if _, err := m.resolveAddr("[2001:db8:a0b:12f0::1]:80"); err != nil { t.Fatalf("Could not understand hostname port combo: %s", err) } + if _, err := m.resolveAddr("127.0.0.1"); err != nil { + t.Fatalf("Could not understand IPv4 only %s", err) + } + if _, err := m.resolveAddr("[2001:db8:a0b:12f0::1]"); err != nil { + t.Fatalf("Could not understand IPv6 only %s", err) + } } type dnsHandler struct { @@ -1315,6 +1321,129 @@ func TestMemberlist_PingDelegate(t *testing.T) { } } +func TestMemberlist_EncryptedGossipTransition(t *testing.T) { + m1 := GetMemberlist(t) + m1.setAlive() + m1.schedule() + defer m1.Shutdown() + + // Create a second node with the first stage of gossip transition settings + conf2 := DefaultLANConfig() + addr2 := getBindAddr() + conf2.Name = addr2.String() + conf2.BindAddr = addr2.String() + conf2.BindPort = m1.config.BindPort + conf2.GossipInterval = time.Millisecond + conf2.SecretKey = []byte("Hi16ZXu2lNCRVwtr20khAg==") + conf2.GossipVerifyIncoming = false + conf2.GossipVerifyOutgoing = false + + m2, err := Create(conf2) + if err != nil { + t.Fatalf("unexpected err: %s", err) + } + defer m2.Shutdown() + + // Join the second node. m1 has no encryption while m2 has encryption configured and + // can receive encrypted gossip, but will not encrypt outgoing gossip. + num, err := m2.Join([]string{m1.config.BindAddr}) + if num != 1 { + t.Fatalf("unexpected 1: %d", num) + } + if err != nil { + t.Fatalf("unexpected err: %s", err) + } + + // Check the hosts + if len(m2.Members()) != 2 { + t.Fatalf("should have 2 nodes! %v", m2.Members()) + } + if m2.estNumNodes() != 2 { + t.Fatalf("should have 2 nodes! %v", m2.Members()) + } + + // Leave with the first node + m1.Leave(time.Second) + + // Wait for leave + time.Sleep(10 * time.Millisecond) + + // Create a third node that has the second stage of gossip transition settings + conf3 := DefaultLANConfig() + addr3 := getBindAddr() + conf3.Name = addr3.String() + conf3.BindAddr = addr3.String() + conf3.BindPort = m1.config.BindPort + conf3.GossipInterval = time.Millisecond + conf3.SecretKey = conf2.SecretKey + conf3.GossipVerifyIncoming = false + + m3, err := Create(conf3) + if err != nil { + t.Fatalf("unexpected err: %s", err) + } + defer m3.Shutdown() + + // Join the third node to the second node. At this step, both nodes have encryption + // configured but only m3 is sending encrypted gossip. + num, err = m3.Join([]string{m2.config.BindAddr}) + if num != 1 { + t.Fatalf("unexpected 1: %d", num) + } + if err != nil { + t.Fatalf("unexpected err: %s", err) + } + + // Check the hosts + if len(m3.Members()) != 2 { + t.Fatalf("should have 2 nodes! %v", m3.Members()) + + } + if m3.estNumNodes() != 2 { + t.Fatalf("should have 2 nodes! %v", m3.Members()) + } + + // Leave with the second node + m2.Leave(time.Second) + + // Wait for leave + time.Sleep(10 * time.Millisecond) + + // Create a fourth node that has the second stage of gossip transition settings + conf4 := DefaultLANConfig() + addr4 := getBindAddr() + conf4.Name = addr4.String() + conf4.BindAddr = addr4.String() + conf4.BindPort = m3.config.BindPort + conf4.GossipInterval = time.Millisecond + conf4.SecretKey = conf2.SecretKey + + m4, err := Create(conf4) + if err != nil { + t.Fatalf("unexpected err: %s", err) + } + defer m4.Shutdown() + + // Join the fourth node to the third node. At this step, both m3 and m4 are speaking + // encrypted gossip and m3 is still accepting insecure gossip. + num, err = m4.Join([]string{m3.config.BindAddr}) + if num != 1 { + t.Fatalf("unexpected 1: %d", num) + } + if err != nil { + t.Fatalf("unexpected err: %s", err) + } + + // Check the hosts + if len(m4.Members()) != 2 { + t.Fatalf("should have 2 nodes! %v", m4.Members()) + + } + if m4.estNumNodes() != 2 { + t.Fatalf("should have 2 nodes! %v", m4.Members()) + } +} + // Consul bug, rapid restart (before failure detection), // with an updated meta data. Should be at incarnation 1 for // both. diff --git a/vendor/github.com/hashicorp/memberlist/net.go b/vendor/github.com/hashicorp/memberlist/net.go index e0036d01d..65a60159d 100644 --- a/vendor/github.com/hashicorp/memberlist/net.go +++ b/vendor/github.com/hashicorp/memberlist/net.go @@ -283,8 +283,13 @@ func (m *Memberlist) ingestPacket(buf []byte, from net.Addr, timestamp time.Time // Decrypt the payload plain, err := decryptPayload(m.config.Keyring.GetKeys(), buf, nil) if err != nil { - m.logger.Printf("[ERR] memberlist: Decrypt packet failed: %v %s", err, LogAddress(from)) - return + if !m.config.GossipVerifyIncoming { + // Treat the message as plaintext + plain = buf + } else { + m.logger.Printf("[ERR] memberlist: Decrypt packet failed: %v %s", err, LogAddress(from)) + return + } } // Continue processing the plaintext buffer @@ -557,7 +562,7 @@ func (m *Memberlist) encodeAndSendMsg(addr string, msgType messageType, msg inte func (m *Memberlist) sendMsg(addr string, msg []byte) error { // Check if we can piggy back any messages bytesAvail := m.config.UDPBufferSize - len(msg) - compoundHeaderOverhead - if m.config.EncryptionEnabled() { + if m.config.EncryptionEnabled() && m.config.GossipVerifyOutgoing { bytesAvail -= encryptOverhead(m.encryptionVersion()) } extra := m.getBroadcasts(compoundOverhead, bytesAvail) @@ -621,7 +626,7 @@ func (m *Memberlist) rawSendMsgPacket(addr string, node *Node, msg []byte) error } // Check if we have encryption enabled - if m.config.EncryptionEnabled() { + if m.config.EncryptionEnabled() && m.config.GossipVerifyOutgoing { // Encrypt the payload var buf bytes.Buffer primaryKey := m.config.Keyring.GetPrimaryKey() @@ -652,7 +657,7 @@ func (m *Memberlist) rawSendMsgStream(conn net.Conn, sendBuf []byte) error { } // Check if encryption is enabled - if m.config.EncryptionEnabled() { + if m.config.EncryptionEnabled() && m.config.GossipVerifyOutgoing { crypt, err := m.encryptLocalState(sendBuf) if err != nil { m.logger.Printf("[ERROR] memberlist: Failed to encrypt local state: %v", err) @@ -876,7 +881,7 @@ func (m *Memberlist) readStream(conn net.Conn) (messageType, io.Reader, *codec.D // Reset message type and bufConn msgType = messageType(plain[0]) bufConn = bytes.NewReader(plain[1:]) - } else if m.config.EncryptionEnabled() { + } else if m.config.EncryptionEnabled() && m.config.GossipVerifyIncoming { return 0, nil, nil, fmt.Errorf("Encryption is configured but remote state is not encrypted") } diff --git a/vendor/github.com/hashicorp/memberlist/state_test.go b/vendor/github.com/hashicorp/memberlist/state_test.go index 8b9c8aaf7..71e93ca4e 100644 --- a/vendor/github.com/hashicorp/memberlist/state_test.go +++ b/vendor/github.com/hashicorp/memberlist/state_test.go @@ -669,7 +669,7 @@ func TestMemberList_ProbeNode_Awareness_MissedNack(t *testing.T) { // We should have gotten dinged for the missed nack. time.Sleep(probeTimeMax) - if score := m1.GetHealthScore(); score != 2 { + if score := m1.GetHealthScore(); score != 1 { t.Fatalf("bad: %d", score) } } |