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
PingInterval = 8 * time.Second
TimeoutInterval = 30 * time.Second
probeTimeout = 30 * time.Second
)
// 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
}
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) {
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
if !peer.IsPublic {
if a.relay != nil {
a.devAddRelayed(peer, a.relay.VPNIP)
} else {
a.devAddPeer(peer)
}
if a.forwarder != nil && endpoint.IsValid() {
a.forwarder.SetEndpoint(peer.VPNIP.As4()[3], endpoint)
}
@@ -86,13 +90,23 @@ func (a *App) switchActiveRelay() {
}
if best == nil {
log.Printf("no relay available")
return
}
} else {
a.devSetRelay(best, best.PreferredEndpoint())
a.relay = best
}
for _, p := range a.peersByKey {
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 {
if v4.IsValid() {
return v4

View File

@@ -54,5 +54,7 @@ func (a *App) addProbe(peer *Peer, v4, v6 netip.AddrPort) {
return
}
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"
"vppn/peer/control"
"vppn/peer/wginterface"
)
func (a *App) onTick() {
@@ -29,16 +28,27 @@ func (a *App) onTick() {
switch p.State {
case StateProbing:
// Promote probing peers to direct once alive (direct path confirmed
// working).
if time.Since(p.LastHandshakeTime()) < wginterface.SessionTimeout {
a.devAddDirect(p, p.WGEndpoint())
if p.Up() {
// Direct handshake succeeded; WG entry already correct.
p.State = StateDirect
} 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:
// 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() {
a.devAddProbe(p, p.WGEndpoint())
if a.relay != nil {
a.devAddRelayed(p, a.relay.VPNIP)
} else {
a.devAddPeer(p)
}
}
}
}