add configuration options for HandshakeManager (#179)

This change exposes the current constants we have defined for the handshake
manager as configuration options. This will allow us to test and tweak
with different intervals and wait rotations.

    # Handshake Manger Settings
    handshakes:
      # Total time to try a handshake = sequence of `try_interval * retries`
      # With 100ms interval and 20 retries it is 23.5 seconds
      try_interval: 100ms
      retries: 20

      # wait_rotation is the number of handshake attempts to do before starting to try non-local IP addresses
      wait_rotation: 5
This commit is contained in:
Wade Simmons 2020-02-21 16:25:11 -05:00 committed by GitHub
parent df69371620
commit 179a369130
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 61 additions and 29 deletions

View File

@ -36,7 +36,7 @@ func Test_NewConnectionManagerTest(t *testing.T) {
certState: cs, certState: cs,
firewall: &Firewall{}, firewall: &Firewall{},
lightHouse: lh, lightHouse: lh,
handshakeManager: NewHandshakeManager(vpncidr, preferredRanges, hostMap, lh, &udpConn{}), handshakeManager: NewHandshakeManager(vpncidr, preferredRanges, hostMap, lh, &udpConn{}, defaultHandshakeConfig),
} }
now := time.Now() now := time.Now()
@ -99,7 +99,7 @@ func Test_NewConnectionManagerTest2(t *testing.T) {
certState: cs, certState: cs,
firewall: &Firewall{}, firewall: &Firewall{},
lightHouse: lh, lightHouse: lh,
handshakeManager: NewHandshakeManager(vpncidr, preferredRanges, hostMap, lh, &udpConn{}), handshakeManager: NewHandshakeManager(vpncidr, preferredRanges, hostMap, lh, &udpConn{}, defaultHandshakeConfig),
} }
now := time.Now() now := time.Now()

View File

@ -139,6 +139,15 @@ logging:
#subsystem: nebula #subsystem: nebula
#interval: 10s #interval: 10s
# Handshake Manger Settings
#handshakes:
# Total time to try a handshake = sequence of `try_interval * retries`
# With 100ms interval and 20 retries it is 23.5 seconds
#try_interval: 100ms
#retries: 20
# wait_rotation is the number of handshake attempts to do before starting to try non-local IP addresses
#wait_rotation: 5
# Nebula security group configuration # Nebula security group configuration
firewall: firewall:
conntrack: conntrack:

View File

@ -13,36 +13,53 @@ import (
const ( const (
// Total time to try a handshake = sequence of HandshakeTryInterval * HandshakeRetries // Total time to try a handshake = sequence of HandshakeTryInterval * HandshakeRetries
// With 100ms interval and 20 retries is 23.5 seconds // With 100ms interval and 20 retries is 23.5 seconds
HandshakeTryInterval = time.Millisecond * 100 DefaultHandshakeTryInterval = time.Millisecond * 100
HandshakeRetries = 20 DefaultHandshakeRetries = 20
// HandshakeWaitRotation is the number of handshake attempts to do before starting to use other ips addresses // DefaultHandshakeWaitRotation is the number of handshake attempts to do before starting to use other ips addresses
HandshakeWaitRotation = 5 DefaultHandshakeWaitRotation = 5
) )
var (
defaultHandshakeConfig = HandshakeConfig{
tryInterval: DefaultHandshakeTryInterval,
retries: DefaultHandshakeRetries,
waitRotation: DefaultHandshakeWaitRotation,
}
)
type HandshakeConfig struct {
tryInterval time.Duration
retries int
waitRotation int
}
type HandshakeManager struct { type HandshakeManager struct {
pendingHostMap *HostMap pendingHostMap *HostMap
mainHostMap *HostMap mainHostMap *HostMap
lightHouse *LightHouse lightHouse *LightHouse
outside *udpConn outside *udpConn
config HandshakeConfig
OutboundHandshakeTimer *SystemTimerWheel OutboundHandshakeTimer *SystemTimerWheel
InboundHandshakeTimer *SystemTimerWheel InboundHandshakeTimer *SystemTimerWheel
} }
func NewHandshakeManager(tunCidr *net.IPNet, preferredRanges []*net.IPNet, mainHostMap *HostMap, lightHouse *LightHouse, outside *udpConn) *HandshakeManager { func NewHandshakeManager(tunCidr *net.IPNet, preferredRanges []*net.IPNet, mainHostMap *HostMap, lightHouse *LightHouse, outside *udpConn, config HandshakeConfig) *HandshakeManager {
return &HandshakeManager{ return &HandshakeManager{
pendingHostMap: NewHostMap("pending", tunCidr, preferredRanges), pendingHostMap: NewHostMap("pending", tunCidr, preferredRanges),
mainHostMap: mainHostMap, mainHostMap: mainHostMap,
lightHouse: lightHouse, lightHouse: lightHouse,
outside: outside, outside: outside,
OutboundHandshakeTimer: NewSystemTimerWheel(HandshakeTryInterval, HandshakeTryInterval*HandshakeRetries), config: config,
InboundHandshakeTimer: NewSystemTimerWheel(HandshakeTryInterval, HandshakeTryInterval*HandshakeRetries),
OutboundHandshakeTimer: NewSystemTimerWheel(config.tryInterval, config.tryInterval*time.Duration(config.retries)),
InboundHandshakeTimer: NewSystemTimerWheel(config.tryInterval, config.tryInterval*time.Duration(config.retries)),
} }
} }
func (c *HandshakeManager) Run(f EncWriter) { func (c *HandshakeManager) Run(f EncWriter) {
clockSource := time.Tick(HandshakeTryInterval) clockSource := time.Tick(c.config.tryInterval)
for now := range clockSource { for now := range clockSource {
c.NextOutboundHandshakeTimerTick(now, f) c.NextOutboundHandshakeTimerTick(now, f)
c.NextInboundHandshakeTimerTick(now) c.NextInboundHandshakeTimerTick(now)
@ -70,7 +87,7 @@ func (c *HandshakeManager) NextOutboundHandshakeTimerTick(now time.Time, f EncWr
// If we haven't finished the handshake and we haven't hit max retries, query // If we haven't finished the handshake and we haven't hit max retries, query
// lighthouse and then send the handshake packet again. // lighthouse and then send the handshake packet again.
if hostinfo.HandshakeCounter < HandshakeRetries && !hostinfo.HandshakeComplete { if hostinfo.HandshakeCounter < c.config.retries && !hostinfo.HandshakeComplete {
if hostinfo.remote == nil { if hostinfo.remote == nil {
// We continue to query the lighthouse because hosts may // We continue to query the lighthouse because hosts may
// come online during handshake retries. If the query // come online during handshake retries. If the query
@ -88,7 +105,7 @@ func (c *HandshakeManager) NextOutboundHandshakeTimerTick(now time.Time, f EncWr
// We want to use the "best" calculated ip for the first 5 attempts, after that we just blindly rotate through // We want to use the "best" calculated ip for the first 5 attempts, after that we just blindly rotate through
// all the others until we can stand up a connection. // all the others until we can stand up a connection.
if hostinfo.HandshakeCounter > HandshakeWaitRotation { if hostinfo.HandshakeCounter > c.config.waitRotation {
hostinfo.rotateRemote() hostinfo.rotateRemote()
} }
@ -114,7 +131,7 @@ func (c *HandshakeManager) NextOutboundHandshakeTimerTick(now time.Time, f EncWr
// Readd to the timer wheel so we continue trying wait HandshakeTryInterval * counter longer for next try // Readd to the timer wheel so we continue trying wait HandshakeTryInterval * counter longer for next try
//l.Infoln("Interval: ", HandshakeTryInterval*time.Duration(hostinfo.HandshakeCounter)) //l.Infoln("Interval: ", HandshakeTryInterval*time.Duration(hostinfo.HandshakeCounter))
c.OutboundHandshakeTimer.Add(vpnIP, HandshakeTryInterval*time.Duration(hostinfo.HandshakeCounter)) c.OutboundHandshakeTimer.Add(vpnIP, c.config.tryInterval*time.Duration(hostinfo.HandshakeCounter))
} else { } else {
c.pendingHostMap.DeleteVpnIP(vpnIP) c.pendingHostMap.DeleteVpnIP(vpnIP)
c.pendingHostMap.DeleteIndex(index) c.pendingHostMap.DeleteIndex(index)
@ -144,7 +161,7 @@ func (c *HandshakeManager) AddVpnIP(vpnIP uint32) *HostInfo {
hostinfo := c.pendingHostMap.AddVpnIP(vpnIP) hostinfo := c.pendingHostMap.AddVpnIP(vpnIP)
// We lock here and use an array to insert items to prevent locking the // We lock here and use an array to insert items to prevent locking the
// main receive thread for very long by waiting to add items to the pending map // main receive thread for very long by waiting to add items to the pending map
c.OutboundHandshakeTimer.Add(vpnIP, HandshakeTryInterval) c.OutboundHandshakeTimer.Add(vpnIP, c.config.tryInterval)
return hostinfo return hostinfo
} }

View File

@ -21,7 +21,7 @@ func Test_NewHandshakeManagerIndex(t *testing.T) {
preferredRanges := []*net.IPNet{localrange} preferredRanges := []*net.IPNet{localrange}
mainHM := NewHostMap("test", vpncidr, preferredRanges) mainHM := NewHostMap("test", vpncidr, preferredRanges)
blah := NewHandshakeManager(tuncidr, preferredRanges, mainHM, &LightHouse{}, &udpConn{}) blah := NewHandshakeManager(tuncidr, preferredRanges, mainHM, &LightHouse{}, &udpConn{}, defaultHandshakeConfig)
now := time.Now() now := time.Now()
blah.NextInboundHandshakeTimerTick(now) blah.NextInboundHandshakeTimerTick(now)
@ -37,8 +37,8 @@ func Test_NewHandshakeManagerIndex(t *testing.T) {
// Adding something to pending should not affect the main hostmap // Adding something to pending should not affect the main hostmap
assert.Len(t, mainHM.Indexes, 0) assert.Len(t, mainHM.Indexes, 0)
// Jump ahead 8 seconds // Jump ahead 8 seconds
for i := 1; i <= HandshakeRetries; i++ { for i := 1; i <= DefaultHandshakeRetries; i++ {
next_tick := now.Add(HandshakeTryInterval * time.Duration(i)) next_tick := now.Add(DefaultHandshakeTryInterval * time.Duration(i))
blah.NextInboundHandshakeTimerTick(next_tick) blah.NextInboundHandshakeTimerTick(next_tick)
} }
// Confirm they are still in the pending index list // Confirm they are still in the pending index list
@ -63,7 +63,7 @@ func Test_NewHandshakeManagerVpnIP(t *testing.T) {
mw := &mockEncWriter{} mw := &mockEncWriter{}
mainHM := NewHostMap("test", vpncidr, preferredRanges) mainHM := NewHostMap("test", vpncidr, preferredRanges)
blah := NewHandshakeManager(tuncidr, preferredRanges, mainHM, &LightHouse{}, &udpConn{}) blah := NewHandshakeManager(tuncidr, preferredRanges, mainHM, &LightHouse{}, &udpConn{}, defaultHandshakeConfig)
now := time.Now() now := time.Now()
blah.NextOutboundHandshakeTimerTick(now, mw) blah.NextOutboundHandshakeTimerTick(now, mw)
@ -81,8 +81,8 @@ func Test_NewHandshakeManagerVpnIP(t *testing.T) {
// Jump ahead `HandshakeRetries` ticks // Jump ahead `HandshakeRetries` ticks
cumulative := time.Duration(0) cumulative := time.Duration(0)
for i := 0; i <= HandshakeRetries+1; i++ { for i := 0; i <= DefaultHandshakeRetries+1; i++ {
cumulative += time.Duration(i)*HandshakeTryInterval + 1 cumulative += time.Duration(i)*DefaultHandshakeTryInterval + 1
next_tick := now.Add(cumulative) next_tick := now.Add(cumulative)
//l.Infoln(next_tick) //l.Infoln(next_tick)
blah.NextOutboundHandshakeTimerTick(next_tick, mw) blah.NextOutboundHandshakeTimerTick(next_tick, mw)
@ -93,7 +93,7 @@ func Test_NewHandshakeManagerVpnIP(t *testing.T) {
assert.Contains(t, blah.pendingHostMap.Hosts, uint32(v)) assert.Contains(t, blah.pendingHostMap.Hosts, uint32(v))
} }
// Jump ahead 1 more second // Jump ahead 1 more second
cumulative += time.Duration(HandshakeRetries+1) * HandshakeTryInterval cumulative += time.Duration(DefaultHandshakeRetries+1) * DefaultHandshakeTryInterval
next_tick := now.Add(cumulative) next_tick := now.Add(cumulative)
//l.Infoln(next_tick) //l.Infoln(next_tick)
blah.NextOutboundHandshakeTimerTick(next_tick, mw) blah.NextOutboundHandshakeTimerTick(next_tick, mw)
@ -112,7 +112,7 @@ func Test_NewHandshakeManagerVpnIPcleanup(t *testing.T) {
mw := &mockEncWriter{} mw := &mockEncWriter{}
mainHM := NewHostMap("test", vpncidr, preferredRanges) mainHM := NewHostMap("test", vpncidr, preferredRanges)
blah := NewHandshakeManager(tuncidr, preferredRanges, mainHM, &LightHouse{}, &udpConn{}) blah := NewHandshakeManager(tuncidr, preferredRanges, mainHM, &LightHouse{}, &udpConn{}, defaultHandshakeConfig)
now := time.Now() now := time.Now()
blah.NextOutboundHandshakeTimerTick(now, mw) blah.NextOutboundHandshakeTimerTick(now, mw)
@ -125,8 +125,8 @@ func Test_NewHandshakeManagerVpnIPcleanup(t *testing.T) {
// Jump ahead `HandshakeRetries` ticks. Eviction should happen in pending // Jump ahead `HandshakeRetries` ticks. Eviction should happen in pending
// but not main hostmap // but not main hostmap
cumulative := time.Duration(0) cumulative := time.Duration(0)
for i := 1; i <= HandshakeRetries+2; i++ { for i := 1; i <= DefaultHandshakeRetries+2; i++ {
cumulative += HandshakeTryInterval * time.Duration(i) cumulative += DefaultHandshakeTryInterval * time.Duration(i)
next_tick := now.Add(cumulative) next_tick := now.Add(cumulative)
blah.NextOutboundHandshakeTimerTick(next_tick, mw) blah.NextOutboundHandshakeTimerTick(next_tick, mw)
} }
@ -161,7 +161,7 @@ func Test_NewHandshakeManagerIndexcleanup(t *testing.T) {
preferredRanges := []*net.IPNet{localrange} preferredRanges := []*net.IPNet{localrange}
mainHM := NewHostMap("test", vpncidr, preferredRanges) mainHM := NewHostMap("test", vpncidr, preferredRanges)
blah := NewHandshakeManager(tuncidr, preferredRanges, mainHM, &LightHouse{}, &udpConn{}) blah := NewHandshakeManager(tuncidr, preferredRanges, mainHM, &LightHouse{}, &udpConn{}, defaultHandshakeConfig)
now := time.Now() now := time.Now()
blah.NextInboundHandshakeTimerTick(now) blah.NextInboundHandshakeTimerTick(now)
@ -171,12 +171,12 @@ func Test_NewHandshakeManagerIndexcleanup(t *testing.T) {
blah.pendingHostMap.AddVpnIPHostInfo(101010, hostinfo) blah.pendingHostMap.AddVpnIPHostInfo(101010, hostinfo)
assert.Contains(t, blah.pendingHostMap.Hosts, uint32(101010)) assert.Contains(t, blah.pendingHostMap.Hosts, uint32(101010))
for i := 1; i <= HandshakeRetries+2; i++ { for i := 1; i <= DefaultHandshakeRetries+2; i++ {
next_tick := now.Add(HandshakeTryInterval * time.Duration(i)) next_tick := now.Add(DefaultHandshakeTryInterval * time.Duration(i))
blah.NextInboundHandshakeTimerTick(next_tick) blah.NextInboundHandshakeTimerTick(next_tick)
} }
next_tick := now.Add(HandshakeTryInterval*HandshakeRetries + 3) next_tick := now.Add(DefaultHandshakeTryInterval*DefaultHandshakeRetries + 3)
blah.NextInboundHandshakeTimerTick(next_tick) blah.NextInboundHandshakeTimerTick(next_tick)
assert.NotContains(t, blah.pendingHostMap.Hosts, uint32(101010)) assert.NotContains(t, blah.pendingHostMap.Hosts, uint32(101010))
assert.NotContains(t, blah.pendingHostMap.Indexes, uint32(12341234)) assert.NotContains(t, blah.pendingHostMap.Indexes, uint32(12341234))

View File

@ -265,7 +265,13 @@ func Main(configPath string, configTest bool, buildVersion string) {
l.WithError(err).Error("Lighthouse unreachable") l.WithError(err).Error("Lighthouse unreachable")
} }
handshakeManager := NewHandshakeManager(tunCidr, preferredRanges, hostMap, lightHouse, udpServer) handshakeConfig := HandshakeConfig{
tryInterval: config.GetDuration("handshakes.try_interval", DefaultHandshakeTryInterval),
retries: config.GetInt("handshakes.retries", DefaultHandshakeRetries),
waitRotation: config.GetInt("handshakes.wait_rotation", DefaultHandshakeWaitRotation),
}
handshakeManager := NewHandshakeManager(tunCidr, preferredRanges, hostMap, lightHouse, udpServer, handshakeConfig)
//TODO: These will be reused for psk //TODO: These will be reused for psk
//handshakeMACKey := config.GetString("handshake_mac.key", "") //handshakeMACKey := config.GetString("handshake_mac.key", "")