This commit is contained in:
jdl
2026-06-09 07:40:06 +02:00
parent 3968fd8f16
commit 1c304767b8
5 changed files with 46 additions and 12 deletions

View File

@@ -19,6 +19,7 @@ const (
ControlPort = 4561 ControlPort = 4561
PingInterval = 8 * time.Second PingInterval = 8 * time.Second
TimeoutInterval = 30 * time.Second TimeoutInterval = 30 * time.Second
probeTimeout = 30 * time.Second
) )
// HubPeer is a peer entry as reported by the hub poller. // HubPeer is a peer entry as reported by the hub poller.

View File

@@ -47,6 +47,13 @@ func (a *App) devAddDirect(p *Peer, endpoint netip.AddrPort) {
p.State = StateDirect p.State = StateDirect
} }
func (a *App) devAddRelayed(p *Peer, relayVPNIP netip.Addr) {
port := ForwarderBasePort + uint16(p.VPNIP.As4()[3])
endpoint := netip.AddrPortFrom(relayVPNIP, port)
devRetry(p.VPNIP, "AddRelayed", func() error { return a.dev.AddDirect(p.PubKey(), endpoint, p.VPNIP) })
p.State = StateRelayed
}
func (a *App) devSetRelay(p *Peer, endpoint netip.AddrPort) { func (a *App) devSetRelay(p *Peer, endpoint netip.AddrPort) {
devRetry(p.VPNIP, "SetRelay", func() error { return a.dev.SetRelay(p.PubKey(), endpoint, a.vpnNet) }) devRetry(p.VPNIP, "SetRelay", func() error { return a.dev.SetRelay(p.PubKey(), endpoint, a.vpnNet) })
} }

View File

@@ -37,7 +37,11 @@ func (a *App) onAddPeer(p HubPeer) {
a.peersByIP[peer.VPNIP] = peer a.peersByIP[peer.VPNIP] = peer
if !peer.IsPublic { if !peer.IsPublic {
a.devAddPeer(peer) if a.relay != nil {
a.devAddRelayed(peer, a.relay.VPNIP)
} else {
a.devAddPeer(peer)
}
if a.forwarder != nil && endpoint.IsValid() { if a.forwarder != nil && endpoint.IsValid() {
a.forwarder.SetEndpoint(peer.VPNIP.As4()[3], endpoint) a.forwarder.SetEndpoint(peer.VPNIP.As4()[3], endpoint)
} }
@@ -86,11 +90,21 @@ func (a *App) switchActiveRelay() {
} }
if best == nil { if best == nil {
log.Printf("no relay available") log.Printf("no relay available")
return } else {
a.devSetRelay(best, best.PreferredEndpoint())
a.relay = best
} }
a.devSetRelay(best, best.PreferredEndpoint()) for _, p := range a.peersByKey {
a.relay = best if p.State != StateRelayed {
continue
}
if best != nil {
a.devAddRelayed(p, best.VPNIP)
} else {
a.devAddPeer(p)
}
}
} }
func preferredEndpoint(v4, v6 netip.AddrPort) netip.AddrPort { func preferredEndpoint(v4, v6 netip.AddrPort) netip.AddrPort {

View File

@@ -54,5 +54,7 @@ func (a *App) addProbe(peer *Peer, v4, v6 netip.AddrPort) {
return return
} }
peer.UpdateEndpoints(v4, v6) peer.UpdateEndpoints(v4, v6)
a.devAddProbe(peer, endpoint) a.devAddDirect(peer, endpoint)
peer.State = StateProbing
peer.probeDeadline = time.Now().Add(probeTimeout)
} }

View File

@@ -5,7 +5,6 @@ import (
"time" "time"
"vppn/peer/control" "vppn/peer/control"
"vppn/peer/wginterface"
) )
func (a *App) onTick() { func (a *App) onTick() {
@@ -29,16 +28,27 @@ func (a *App) onTick() {
switch p.State { switch p.State {
case StateProbing: case StateProbing:
// Promote probing peers to direct once alive (direct path confirmed if p.Up() {
// working). // Direct handshake succeeded; WG entry already correct.
if time.Since(p.LastHandshakeTime()) < wginterface.SessionTimeout { p.State = StateDirect
a.devAddDirect(p, p.WGEndpoint()) } else if time.Now().After(p.probeDeadline) {
// Probe timed out — revert to relay.
if a.relay != nil {
a.devAddRelayed(p, a.relay.VPNIP)
} else {
a.devAddPeer(p)
}
} }
case StateDirect: case StateDirect:
// Demote stale non-public direct peers back to probing. // Demotion skips StateProbing — only probe when there is positive
// evidence of a direct path (ping or multicast beacon).
if !p.IsPublic && !p.Up() { if !p.IsPublic && !p.Up() {
a.devAddProbe(p, p.WGEndpoint()) if a.relay != nil {
a.devAddRelayed(p, a.relay.VPNIP)
} else {
a.devAddPeer(p)
}
} }
} }
} }