diff --git a/handshake_manager.go b/handshake_manager.go index 1cad4a01..ff427719 100644 --- a/handshake_manager.go +++ b/handshake_manager.go @@ -495,6 +495,13 @@ var ( // ErrLocalIndexCollision if we already have an entry in the main or pending // hostmap for the hostinfo.localIndexId. func (hm *HandshakeManager) CheckAndComplete(hostinfo *HostInfo, handshakePacket uint8, f *Interface) (*HostInfo, error) { + return hm.checkAndComplete(hostinfo, handshakePacket, f, false) +} + +// checkAndComplete is CheckAndComplete. committed means the initiator has shown it +// uses this tunnel, as a hybrid msg3 does, so an existing tunnel is replaced even +// when its handshake is newer. +func (hm *HandshakeManager) checkAndComplete(hostinfo *HostInfo, handshakePacket uint8, f *Interface, committed bool) (*HostInfo, error) { hm.mainHostMap.Lock() defer hm.mainHostMap.Unlock() hm.Lock() @@ -511,7 +518,7 @@ func (hm *HandshakeManager) CheckAndComplete(hostinfo *HostInfo, handshakePacket } // Is this a newer handshake? - if existingHostInfo.lastHandshakeTime >= hostinfo.lastHandshakeTime && !existingHostInfo.ConnectionState.initiator { + if !committed && existingHostInfo.lastHandshakeTime >= hostinfo.lastHandshakeTime && !existingHostInfo.ConnectionState.initiator { return existingHostInfo, ErrExistingHostInfo } diff --git a/handshake_manager_hybrid.go b/handshake_manager_hybrid.go index 3b59b9b6..8ffed3f9 100644 --- a/handshake_manager_hybrid.go +++ b/handshake_manager_hybrid.go @@ -214,7 +214,10 @@ func (hm *HandshakeManager) completeHybridResponder(via ViaSender, hh *Handshake remoteCert := result.RemoteCert hostinfo.buildNetworks(f.myVpnNetworksTable, remoteCert.Certificate) - existing, err := hm.CheckAndComplete(hostinfo, handshakePacketStage0, f) + // The initiator only sends msg3 once it settled on this handshake, so this + // tunnel wins even over a newer one: a classical attempt that crossed it, say, + // which the initiator has already given up on. + existing, err := hm.checkAndComplete(hostinfo, handshakePacketStage0, f, true) if err != nil { hm.handleCheckAndCompleteError(err, existing, hostinfo, via, machine.Subtype(), 0) return