|
@@ -65,7 +65,7 @@ type HandshakeManager struct {
|
|
|
lightHouse *LightHouse
|
|
lightHouse *LightHouse
|
|
|
outside udp.Conn
|
|
outside udp.Conn
|
|
|
config HandshakeConfig
|
|
config HandshakeConfig
|
|
|
- OutboundHandshakeTimer *LockingTimerWheel[netip.Addr]
|
|
|
|
|
|
|
+ OutboundHandshakeTimer *LockingTimerWheel[*HandshakeHostInfo]
|
|
|
messageMetrics *MessageMetrics
|
|
messageMetrics *MessageMetrics
|
|
|
metricInitiated metrics.Counter
|
|
metricInitiated metrics.Counter
|
|
|
metricTimedOut metrics.Counter
|
|
metricTimedOut metrics.Counter
|
|
@@ -81,6 +81,7 @@ type HandshakeHostInfo struct {
|
|
|
|
|
|
|
|
startTime time.Time // Time that we first started trying with this handshake
|
|
startTime time.Time // Time that we first started trying with this handshake
|
|
|
ready bool // Is the handshake ready
|
|
ready bool // Is the handshake ready
|
|
|
|
|
+ deleted bool // Has the handshake been removed from the pending maps, deleters hold the lock
|
|
|
initiatingVersionOverride cert.Version // Should we use a non-default cert version for this handshake?
|
|
initiatingVersionOverride cert.Version // Should we use a non-default cert version for this handshake?
|
|
|
counter int64 // How many attempts have we made so far
|
|
counter int64 // How many attempts have we made so far
|
|
|
lastRemotes []netip.AddrPort // Remotes that we sent to during the previous attempt
|
|
lastRemotes []netip.AddrPort // Remotes that we sent to during the previous attempt
|
|
@@ -125,7 +126,7 @@ func NewHandshakeManager(l *slog.Logger, mainHostMap *HostMap, lightHouse *Light
|
|
|
outside: outside,
|
|
outside: outside,
|
|
|
config: config,
|
|
config: config,
|
|
|
trigger: make(chan netip.Addr, config.triggerBuffer),
|
|
trigger: make(chan netip.Addr, config.triggerBuffer),
|
|
|
- OutboundHandshakeTimer: NewLockingTimerWheel[netip.Addr](config.tryInterval, hsTimeout(config.retries, config.tryInterval)),
|
|
|
|
|
|
|
+ OutboundHandshakeTimer: NewLockingTimerWheel[*HandshakeHostInfo](config.tryInterval, hsTimeout(config.retries, config.tryInterval)),
|
|
|
messageMetrics: config.messageMetrics,
|
|
messageMetrics: config.messageMetrics,
|
|
|
metricInitiated: metrics.GetOrRegisterCounter("handshake_manager.initiated", nil),
|
|
metricInitiated: metrics.GetOrRegisterCounter("handshake_manager.initiated", nil),
|
|
|
metricTimedOut: metrics.GetOrRegisterCounter("handshake_manager.timed_out", nil),
|
|
metricTimedOut: metrics.GetOrRegisterCounter("handshake_manager.timed_out", nil),
|
|
@@ -142,7 +143,9 @@ func (hm *HandshakeManager) Run(ctx context.Context) {
|
|
|
case <-ctx.Done():
|
|
case <-ctx.Done():
|
|
|
return
|
|
return
|
|
|
case vpnIP := <-hm.trigger:
|
|
case vpnIP := <-hm.trigger:
|
|
|
- hm.handleOutbound(vpnIP, true)
|
|
|
|
|
|
|
+ if hh := hm.queryVpnIp(vpnIP); hh != nil {
|
|
|
|
|
+ hm.handleOutbound(hh, true)
|
|
|
|
|
+ }
|
|
|
case now := <-clockSource.C:
|
|
case now := <-clockSource.C:
|
|
|
hm.NextOutboundHandshakeTimerTick(now)
|
|
hm.NextOutboundHandshakeTimerTick(now)
|
|
|
}
|
|
}
|
|
@@ -197,23 +200,25 @@ func (hm *HandshakeManager) HandleIncoming(via ViaSender, packet []byte, h *head
|
|
|
func (hm *HandshakeManager) NextOutboundHandshakeTimerTick(now time.Time) {
|
|
func (hm *HandshakeManager) NextOutboundHandshakeTimerTick(now time.Time) {
|
|
|
hm.OutboundHandshakeTimer.Advance(now)
|
|
hm.OutboundHandshakeTimer.Advance(now)
|
|
|
for {
|
|
for {
|
|
|
- vpnIp, has := hm.OutboundHandshakeTimer.Purge()
|
|
|
|
|
|
|
+ hh, has := hm.OutboundHandshakeTimer.Purge()
|
|
|
if !has {
|
|
if !has {
|
|
|
break
|
|
break
|
|
|
}
|
|
}
|
|
|
- hm.handleOutbound(vpnIp, false)
|
|
|
|
|
|
|
+ hm.handleOutbound(hh, false)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-func (hm *HandshakeManager) handleOutbound(vpnIp netip.Addr, lighthouseTriggered bool) {
|
|
|
|
|
- hh := hm.queryVpnIp(vpnIp)
|
|
|
|
|
- if hh == nil {
|
|
|
|
|
- return
|
|
|
|
|
- }
|
|
|
|
|
|
|
+func (hm *HandshakeManager) handleOutbound(hh *HandshakeHostInfo, lighthouseTriggered bool) {
|
|
|
hh.Lock()
|
|
hh.Lock()
|
|
|
defer hh.Unlock()
|
|
defer hh.Unlock()
|
|
|
|
|
|
|
|
|
|
+ // Timer entries outlive their handshake. A new handshake for the same vpn addr runs its own timer chain.
|
|
|
|
|
+ if hh.deleted {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
hostinfo := hh.hostinfo
|
|
hostinfo := hh.hostinfo
|
|
|
|
|
+ vpnIp := hostinfo.vpnAddrs[0]
|
|
|
// If we are out of time, clean up
|
|
// If we are out of time, clean up
|
|
|
if hh.counter >= hm.config.retries {
|
|
if hh.counter >= hm.config.retries {
|
|
|
fields := []any{
|
|
fields := []any{
|
|
@@ -239,10 +244,14 @@ func (hm *HandshakeManager) handleOutbound(vpnIp netip.Addr, lighthouseTriggered
|
|
|
// Increment the counter to increase our delay, linear backoff
|
|
// Increment the counter to increase our delay, linear backoff
|
|
|
hh.counter++
|
|
hh.counter++
|
|
|
|
|
|
|
|
|
|
+ // A lighthouse triggered attempt is still in the timer wheel, adding it again would start a second retry chain
|
|
|
|
|
+ if !lighthouseTriggered {
|
|
|
|
|
+ defer hm.OutboundHandshakeTimer.Add(hh, hm.config.tryInterval*time.Duration(hh.counter))
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
// Check if we have a handshake packet to transmit yet
|
|
// Check if we have a handshake packet to transmit yet
|
|
|
if !hh.ready {
|
|
if !hh.ready {
|
|
|
if !hm.buildStage0Packet(hh) {
|
|
if !hm.buildStage0Packet(hh) {
|
|
|
- hm.OutboundHandshakeTimer.Add(vpnIp, hm.config.tryInterval*time.Duration(hh.counter))
|
|
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -323,11 +332,6 @@ func (hm *HandshakeManager) handleOutbound(vpnIp netip.Addr, lighthouseTriggered
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
hm.f.relayManager.StartRelays(hm.f, vpnIp, hh, stage0)
|
|
hm.f.relayManager.StartRelays(hm.f, vpnIp, hh, stage0)
|
|
|
-
|
|
|
|
|
- // If a lighthouse triggered this attempt then we are still in the timer wheel and do not need to re-add
|
|
|
|
|
- if !lighthouseTriggered {
|
|
|
|
|
- hm.OutboundHandshakeTimer.Add(vpnIp, hm.config.tryInterval*time.Duration(hh.counter))
|
|
|
|
|
- }
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// GetOrHandshake will try to find a hostinfo with a fully formed tunnel or start a new handshake if one is not present
|
|
// GetOrHandshake will try to find a hostinfo with a fully formed tunnel or start a new handshake if one is not present
|
|
@@ -380,7 +384,7 @@ func (hm *HandshakeManager) StartHandshake(vpnAddr netip.Addr, cacheCb func(*Han
|
|
|
}
|
|
}
|
|
|
hm.vpnIps[vpnAddr] = hh
|
|
hm.vpnIps[vpnAddr] = hh
|
|
|
hm.metricInitiated.Inc(1)
|
|
hm.metricInitiated.Inc(1)
|
|
|
- hm.OutboundHandshakeTimer.Add(vpnAddr, hm.config.tryInterval)
|
|
|
|
|
|
|
+ hm.OutboundHandshakeTimer.Add(hh, hm.config.tryInterval)
|
|
|
|
|
|
|
|
if cacheCb != nil {
|
|
if cacheCb != nil {
|
|
|
cacheCb(hh)
|
|
cacheCb(hh)
|
|
@@ -532,6 +536,7 @@ func (hm *HandshakeManager) DeleteHostInfo(hostinfo *HostInfo) {
|
|
|
func (hm *HandshakeManager) unlockedDeleteHostInfo(hostinfo *HostInfo) {
|
|
func (hm *HandshakeManager) unlockedDeleteHostInfo(hostinfo *HostInfo) {
|
|
|
for _, addr := range hostinfo.vpnAddrs {
|
|
for _, addr := range hostinfo.vpnAddrs {
|
|
|
if cur, ok := hm.vpnIps[addr]; ok && cur.hostinfo == hostinfo {
|
|
if cur, ok := hm.vpnIps[addr]; ok && cur.hostinfo == hostinfo {
|
|
|
|
|
+ cur.deleted = true
|
|
|
delete(hm.vpnIps, addr)
|
|
delete(hm.vpnIps, addr)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|