handshake: update to preferred remote (#532)
If we receive a handshake packet for a tunnel that has already been completed, check to see if the new remote is preferred. If so, update to the preferred remote and send a test packet to influence the other side to do the same.
This commit is contained in:
parent
afda79feac
commit
ae5505bc74
|
@ -200,6 +200,20 @@ func ixHandshakeStage1(f *Interface, addr *udpAddr, packet []byte, h *Header) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
switch err {
|
switch err {
|
||||||
case ErrAlreadySeen:
|
case ErrAlreadySeen:
|
||||||
|
// Update remote if preferred (Note we have to switch to locking
|
||||||
|
// the existing hostinfo, and then switch back so the defer Unlock
|
||||||
|
// higher in this function still works)
|
||||||
|
hostinfo.Unlock()
|
||||||
|
existing.Lock()
|
||||||
|
// Update remote if preferred
|
||||||
|
if existing.SetRemoteIfPreferred(f.hostMap, addr) {
|
||||||
|
// Send a test packet to ensure the other side has also switched to
|
||||||
|
// the preferred remote
|
||||||
|
f.SendMessageToVpnIp(test, testRequest, vpnIP, []byte(""), make([]byte, 12, 12), make([]byte, mtu))
|
||||||
|
}
|
||||||
|
existing.Unlock()
|
||||||
|
hostinfo.Lock()
|
||||||
|
|
||||||
msg = existing.HandshakePacket[2]
|
msg = existing.HandshakePacket[2]
|
||||||
f.messageMetrics.Tx(handshake, NebulaMessageSubType(msg[1]), 1)
|
f.messageMetrics.Tx(handshake, NebulaMessageSubType(msg[1]), 1)
|
||||||
err := f.outside.WriteTo(msg, addr)
|
err := f.outside.WriteTo(msg, addr)
|
||||||
|
@ -305,7 +319,12 @@ func ixHandshakeStage2(f *Interface, addr *udpAddr, hostinfo *HostInfo, packet [
|
||||||
WithField("handshake", m{"stage": 2, "style": "ix_psk0"}).WithField("header", h).
|
WithField("handshake", m{"stage": 2, "style": "ix_psk0"}).WithField("header", h).
|
||||||
Info("Handshake is already complete")
|
Info("Handshake is already complete")
|
||||||
|
|
||||||
//TODO: evaluate addr for preference, if we handshook with a less preferred addr we can correct quickly here
|
// Update remote if preferred
|
||||||
|
if hostinfo.SetRemoteIfPreferred(f.hostMap, addr) {
|
||||||
|
// Send a test packet to ensure the other side has also switched to
|
||||||
|
// the preferred remote
|
||||||
|
f.SendMessageToVpnIp(test, testRequest, hostinfo.hostId, []byte(""), make([]byte, 12, 12), make([]byte, mtu))
|
||||||
|
}
|
||||||
|
|
||||||
// We already have a complete tunnel, there is nothing that can be done by processing further stage 1 packets
|
// We already have a complete tunnel, there is nothing that can be done by processing further stage 1 packets
|
||||||
return false
|
return false
|
||||||
|
|
36
hostmap.go
36
hostmap.go
|
@ -507,6 +507,42 @@ func (i *HostInfo) SetRemote(remote *udpAddr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetRemoteIfPreferred returns true if the remote was changed. The lastRoam
|
||||||
|
// time on the HostInfo will also be updated.
|
||||||
|
func (i *HostInfo) SetRemoteIfPreferred(hm *HostMap, newRemote *udpAddr) bool {
|
||||||
|
currentRemote := i.remote
|
||||||
|
if currentRemote == nil {
|
||||||
|
i.SetRemote(newRemote)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: We do this loop here instead of calling `isPreferred` in
|
||||||
|
// remote_list.go so that we only have to loop over preferredRanges once.
|
||||||
|
newIsPreferred := false
|
||||||
|
for _, l := range hm.preferredRanges {
|
||||||
|
// return early if we are already on a preferred remote
|
||||||
|
if l.Contains(currentRemote.IP) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if l.Contains(newRemote.IP) {
|
||||||
|
newIsPreferred = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if newIsPreferred {
|
||||||
|
// Consider this a roaming event
|
||||||
|
i.lastRoam = time.Now()
|
||||||
|
i.lastRoamRemote = currentRemote.Copy()
|
||||||
|
|
||||||
|
i.SetRemote(newRemote)
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func (i *HostInfo) ClearConnectionState() {
|
func (i *HostInfo) ClearConnectionState() {
|
||||||
i.ConnectionState = nil
|
i.ConnectionState = nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue