mirror of
https://github.com/slackhq/nebula.git
synced 2024-09-20 06:46:11 +08:00
304b12f63f
We have a few small race conditions with creating the HostInfo.ConnectionState since we add the host info to the pendingHostMap before we set this field. We can make everything a lot easier if we just add an "init" function so that we can set this field in the hostinfo before we add it to the hostmap.
256 lines
7.9 KiB
Go
256 lines
7.9 KiB
Go
package nebula
|
|
|
|
import (
|
|
"context"
|
|
"crypto/ed25519"
|
|
"crypto/rand"
|
|
"net"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/flynn/noise"
|
|
"github.com/slackhq/nebula/cert"
|
|
"github.com/slackhq/nebula/iputil"
|
|
"github.com/slackhq/nebula/udp"
|
|
"github.com/slackhq/nebula/util"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
var vpnIp iputil.VpnIp
|
|
|
|
func Test_NewConnectionManagerTest(t *testing.T) {
|
|
l := util.NewTestLogger()
|
|
//_, 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 = iputil.Ip2VpnIp(net.ParseIP("172.1.1.2"))
|
|
preferredRanges := []*net.IPNet{localrange}
|
|
|
|
// Very incomplete mock objects
|
|
hostMap := NewHostMap(l, "test", vpncidr, preferredRanges)
|
|
cs := &CertState{
|
|
rawCertificate: []byte{},
|
|
privateKey: []byte{},
|
|
certificate: &cert.NebulaCertificate{},
|
|
rawCertificateNoKey: []byte{},
|
|
}
|
|
|
|
lh := NewLightHouse(l, false, &net.IPNet{IP: net.IP{0, 0, 0, 0}, Mask: net.IPMask{0, 0, 0, 0}}, []iputil.VpnIp{}, 1000, 0, &udp.Conn{}, false, 1, false)
|
|
ifce := &Interface{
|
|
hostMap: hostMap,
|
|
inside: &Tun{},
|
|
outside: &udp.Conn{},
|
|
certState: cs,
|
|
firewall: &Firewall{},
|
|
lightHouse: lh,
|
|
handshakeManager: NewHandshakeManager(l, vpncidr, preferredRanges, hostMap, lh, &udp.Conn{}, defaultHandshakeConfig),
|
|
l: l,
|
|
}
|
|
now := time.Now()
|
|
|
|
// Create manager
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
nc := newConnectionManager(ctx, l, 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, nil)
|
|
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) {
|
|
l := util.NewTestLogger()
|
|
//_, 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(l, "test", vpncidr, preferredRanges)
|
|
cs := &CertState{
|
|
rawCertificate: []byte{},
|
|
privateKey: []byte{},
|
|
certificate: &cert.NebulaCertificate{},
|
|
rawCertificateNoKey: []byte{},
|
|
}
|
|
|
|
lh := NewLightHouse(l, false, &net.IPNet{IP: net.IP{0, 0, 0, 0}, Mask: net.IPMask{0, 0, 0, 0}}, []iputil.VpnIp{}, 1000, 0, &udp.Conn{}, false, 1, false)
|
|
ifce := &Interface{
|
|
hostMap: hostMap,
|
|
inside: &Tun{},
|
|
outside: &udp.Conn{},
|
|
certState: cs,
|
|
firewall: &Firewall{},
|
|
lightHouse: lh,
|
|
handshakeManager: NewHandshakeManager(l, vpncidr, preferredRanges, hostMap, lh, &udp.Conn{}, defaultHandshakeConfig),
|
|
l: l,
|
|
}
|
|
now := time.Now()
|
|
|
|
// Create manager
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
nc := newConnectionManager(ctx, l, 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, nil)
|
|
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)
|
|
|
|
}
|
|
|
|
// Check if we can disconnect the peer.
|
|
// Validate if the peer's certificate is invalid (expired, etc.)
|
|
// Disconnect only if disconnectInvalid: true is set.
|
|
func Test_NewConnectionManagerTest_DisconnectInvalid(t *testing.T) {
|
|
now := time.Now()
|
|
l := util.NewTestLogger()
|
|
ipNet := net.IPNet{
|
|
IP: net.IPv4(172, 1, 1, 2),
|
|
Mask: net.IPMask{255, 255, 255, 0},
|
|
}
|
|
_, vpncidr, _ := net.ParseCIDR("172.1.1.1/24")
|
|
_, localrange, _ := net.ParseCIDR("10.1.1.1/24")
|
|
preferredRanges := []*net.IPNet{localrange}
|
|
hostMap := NewHostMap(l, "test", vpncidr, preferredRanges)
|
|
|
|
// Generate keys for CA and peer's cert.
|
|
pubCA, privCA, _ := ed25519.GenerateKey(rand.Reader)
|
|
caCert := cert.NebulaCertificate{
|
|
Details: cert.NebulaCertificateDetails{
|
|
Name: "ca",
|
|
NotBefore: now,
|
|
NotAfter: now.Add(1 * time.Hour),
|
|
IsCA: true,
|
|
PublicKey: pubCA,
|
|
},
|
|
}
|
|
caCert.Sign(privCA)
|
|
ncp := &cert.NebulaCAPool{
|
|
CAs: cert.NewCAPool().CAs,
|
|
}
|
|
ncp.CAs["ca"] = &caCert
|
|
|
|
pubCrt, _, _ := ed25519.GenerateKey(rand.Reader)
|
|
peerCert := cert.NebulaCertificate{
|
|
Details: cert.NebulaCertificateDetails{
|
|
Name: "host",
|
|
Ips: []*net.IPNet{&ipNet},
|
|
Subnets: []*net.IPNet{},
|
|
NotBefore: now,
|
|
NotAfter: now.Add(60 * time.Second),
|
|
PublicKey: pubCrt,
|
|
IsCA: false,
|
|
Issuer: "ca",
|
|
},
|
|
}
|
|
peerCert.Sign(privCA)
|
|
|
|
cs := &CertState{
|
|
rawCertificate: []byte{},
|
|
privateKey: []byte{},
|
|
certificate: &cert.NebulaCertificate{},
|
|
rawCertificateNoKey: []byte{},
|
|
}
|
|
|
|
lh := NewLightHouse(l, false, &net.IPNet{IP: net.IP{0, 0, 0, 0}, Mask: net.IPMask{0, 0, 0, 0}}, []iputil.VpnIp{}, 1000, 0, &udp.Conn{}, false, 1, false)
|
|
ifce := &Interface{
|
|
hostMap: hostMap,
|
|
inside: &Tun{},
|
|
outside: &udp.Conn{},
|
|
certState: cs,
|
|
firewall: &Firewall{},
|
|
lightHouse: lh,
|
|
handshakeManager: NewHandshakeManager(l, vpncidr, preferredRanges, hostMap, lh, &udp.Conn{}, defaultHandshakeConfig),
|
|
l: l,
|
|
disconnectInvalid: true,
|
|
caPool: ncp,
|
|
}
|
|
|
|
// Create manager
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
nc := newConnectionManager(ctx, l, ifce, 5, 10)
|
|
ifce.connectionManager = nc
|
|
hostinfo, _ := nc.hostMap.AddVpnIp(vpnIp, nil)
|
|
hostinfo.ConnectionState = &ConnectionState{
|
|
certState: cs,
|
|
peerCert: &peerCert,
|
|
H: &noise.HandshakeState{},
|
|
}
|
|
|
|
// Move ahead 45s.
|
|
// Check if to disconnect with invalid certificate.
|
|
// Should be alive.
|
|
nextTick := now.Add(45 * time.Second)
|
|
destroyed := nc.handleInvalidCertificate(nextTick, vpnIp, hostinfo)
|
|
assert.False(t, destroyed)
|
|
|
|
// Move ahead 61s.
|
|
// Check if to disconnect with invalid certificate.
|
|
// Should be disconnected.
|
|
nextTick = now.Add(61 * time.Second)
|
|
destroyed = nc.handleInvalidCertificate(nextTick, vpnIp, hostinfo)
|
|
assert.True(t, destroyed)
|
|
}
|