mirror of
https://github.com/slackhq/nebula.git
synced 2025-01-11 20:08:12 +00:00
d604270966
This change fixes all of the known data races that `make smoke-docker-race` finds, except for one. Most of these races are around the handshake phase for a hostinfo, so we add a RWLock to the hostinfo and Lock during each of the handshake stages. Some of the other races are around consistently using `atomic` around the `messageCounter` field. To make this harder to mess up, I have renamed the field to `atomicMessageCounter` (I also removed the unnecessary extra pointer deference as we can just point directly to the struct field). The last remaining data race is around reading `ConnectionInfo.ready`, which is a boolean that is only written to once when the handshake has finished. Due to it being in the hot path for packets and the rare case that this could actually be an issue, holding off on fixing that one for now. here is the results of `make smoke-docker-race`: before: lighthouse1: Found 2 data race(s) host2: Found 36 data race(s) host3: Found 17 data race(s) host4: Found 31 data race(s) after: host2: Found 1 data race(s) host4: Found 1 data race(s) Fixes: #147 Fixes: #226 Fixes: #283 Fixes: #316
146 lines
4.5 KiB
Go
146 lines
4.5 KiB
Go
package nebula
|
|
|
|
import (
|
|
"net"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/flynn/noise"
|
|
"github.com/slackhq/nebula/cert"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
var vpnIP uint32
|
|
|
|
func Test_NewConnectionManagerTest(t *testing.T) {
|
|
//_, tuncidr, _ := net.ParseCIDR("1.1.1.1/24")
|
|
_, vpncidr, _ := net.ParseCIDR("172.1.1.1/24")
|
|
_, localrange, _ := net.ParseCIDR("10.1.1.1/24")
|
|
vpnIP = ip2int(net.ParseIP("172.1.1.2"))
|
|
preferredRanges := []*net.IPNet{localrange}
|
|
|
|
// Very incomplete mock objects
|
|
hostMap := NewHostMap("test", vpncidr, preferredRanges)
|
|
cs := &CertState{
|
|
rawCertificate: []byte{},
|
|
privateKey: []byte{},
|
|
certificate: &cert.NebulaCertificate{},
|
|
rawCertificateNoKey: []byte{},
|
|
}
|
|
|
|
lh := NewLightHouse(false, 0, []uint32{}, 1000, 0, &udpConn{}, false, 1, false)
|
|
ifce := &Interface{
|
|
hostMap: hostMap,
|
|
inside: &Tun{},
|
|
outside: &udpConn{},
|
|
certState: cs,
|
|
firewall: &Firewall{},
|
|
lightHouse: lh,
|
|
handshakeManager: NewHandshakeManager(vpncidr, preferredRanges, hostMap, lh, &udpConn{}, defaultHandshakeConfig),
|
|
}
|
|
now := time.Now()
|
|
|
|
// Create manager
|
|
nc := newConnectionManager(ifce, 5, 10)
|
|
p := []byte("")
|
|
nb := make([]byte, 12, 12)
|
|
out := make([]byte, mtu)
|
|
nc.HandleMonitorTick(now, p, nb, out)
|
|
// Add an ip we have established a connection w/ to hostmap
|
|
hostinfo := nc.hostMap.AddVpnIP(vpnIP)
|
|
hostinfo.ConnectionState = &ConnectionState{
|
|
certState: cs,
|
|
H: &noise.HandshakeState{},
|
|
}
|
|
|
|
// We saw traffic out to vpnIP
|
|
nc.Out(vpnIP)
|
|
assert.NotContains(t, nc.pendingDeletion, vpnIP)
|
|
assert.Contains(t, nc.hostMap.Hosts, vpnIP)
|
|
// Move ahead 5s. Nothing should happen
|
|
next_tick := now.Add(5 * time.Second)
|
|
nc.HandleMonitorTick(next_tick, p, nb, out)
|
|
nc.HandleDeletionTick(next_tick)
|
|
// Move ahead 6s. We haven't heard back
|
|
next_tick = now.Add(6 * time.Second)
|
|
nc.HandleMonitorTick(next_tick, p, nb, out)
|
|
nc.HandleDeletionTick(next_tick)
|
|
// This host should now be up for deletion
|
|
assert.Contains(t, nc.pendingDeletion, vpnIP)
|
|
assert.Contains(t, nc.hostMap.Hosts, vpnIP)
|
|
// Move ahead some more
|
|
next_tick = now.Add(45 * time.Second)
|
|
nc.HandleMonitorTick(next_tick, p, nb, out)
|
|
nc.HandleDeletionTick(next_tick)
|
|
// The host should be evicted
|
|
assert.NotContains(t, nc.pendingDeletion, vpnIP)
|
|
assert.NotContains(t, nc.hostMap.Hosts, vpnIP)
|
|
|
|
}
|
|
|
|
func Test_NewConnectionManagerTest2(t *testing.T) {
|
|
//_, tuncidr, _ := net.ParseCIDR("1.1.1.1/24")
|
|
_, vpncidr, _ := net.ParseCIDR("172.1.1.1/24")
|
|
_, localrange, _ := net.ParseCIDR("10.1.1.1/24")
|
|
preferredRanges := []*net.IPNet{localrange}
|
|
|
|
// Very incomplete mock objects
|
|
hostMap := NewHostMap("test", vpncidr, preferredRanges)
|
|
cs := &CertState{
|
|
rawCertificate: []byte{},
|
|
privateKey: []byte{},
|
|
certificate: &cert.NebulaCertificate{},
|
|
rawCertificateNoKey: []byte{},
|
|
}
|
|
|
|
lh := NewLightHouse(false, 0, []uint32{}, 1000, 0, &udpConn{}, false, 1, false)
|
|
ifce := &Interface{
|
|
hostMap: hostMap,
|
|
inside: &Tun{},
|
|
outside: &udpConn{},
|
|
certState: cs,
|
|
firewall: &Firewall{},
|
|
lightHouse: lh,
|
|
handshakeManager: NewHandshakeManager(vpncidr, preferredRanges, hostMap, lh, &udpConn{}, defaultHandshakeConfig),
|
|
}
|
|
now := time.Now()
|
|
|
|
// Create manager
|
|
nc := newConnectionManager(ifce, 5, 10)
|
|
p := []byte("")
|
|
nb := make([]byte, 12, 12)
|
|
out := make([]byte, mtu)
|
|
nc.HandleMonitorTick(now, p, nb, out)
|
|
// Add an ip we have established a connection w/ to hostmap
|
|
hostinfo := nc.hostMap.AddVpnIP(vpnIP)
|
|
hostinfo.ConnectionState = &ConnectionState{
|
|
certState: cs,
|
|
H: &noise.HandshakeState{},
|
|
}
|
|
|
|
// We saw traffic out to vpnIP
|
|
nc.Out(vpnIP)
|
|
assert.NotContains(t, nc.pendingDeletion, vpnIP)
|
|
assert.Contains(t, nc.hostMap.Hosts, vpnIP)
|
|
// Move ahead 5s. Nothing should happen
|
|
next_tick := now.Add(5 * time.Second)
|
|
nc.HandleMonitorTick(next_tick, p, nb, out)
|
|
nc.HandleDeletionTick(next_tick)
|
|
// Move ahead 6s. We haven't heard back
|
|
next_tick = now.Add(6 * time.Second)
|
|
nc.HandleMonitorTick(next_tick, p, nb, out)
|
|
nc.HandleDeletionTick(next_tick)
|
|
// This host should now be up for deletion
|
|
assert.Contains(t, nc.pendingDeletion, vpnIP)
|
|
assert.Contains(t, nc.hostMap.Hosts, vpnIP)
|
|
// We heard back this time
|
|
nc.In(vpnIP)
|
|
// Move ahead some more
|
|
next_tick = now.Add(45 * time.Second)
|
|
nc.HandleMonitorTick(next_tick, p, nb, out)
|
|
nc.HandleDeletionTick(next_tick)
|
|
// The host should be evicted
|
|
assert.NotContains(t, nc.pendingDeletion, vpnIP)
|
|
assert.Contains(t, nc.hostMap.Hosts, vpnIP)
|
|
|
|
}
|