diff --git a/peer/on_hub.go b/peer/on_hub.go index 677263f..ece81cf 100644 --- a/peer/on_hub.go +++ b/peer/on_hub.go @@ -95,14 +95,6 @@ func (a *App) switchActiveRelay() { a.relay = best } -func preferredEndpoint(v4, v6 netip.AddrPort) netip.AddrPort { - // We always prefer v4 since all peers can connect to IPv4 addresses. - if v4.IsValid() { - return v4 - } - return v6 -} - func roleFor(selfIsPublic bool, selfIP netip.Addr, peerIsPublic bool, peerVPNIP netip.Addr) control.Role { if !selfIsPublic && peerIsPublic { return control.Client diff --git a/peer/on_multicast.go b/peer/on_multicast.go index 0e05851..d1879c0 100644 --- a/peer/on_multicast.go +++ b/peer/on_multicast.go @@ -40,12 +40,5 @@ func (a *App) onMulticastDiscovery(pkt multicast.Packet) { return } - var v4, v6 netip.AddrPort - if pkt.Src.Is4() { - v4 = endpoint - } else { - v6 = endpoint - } - - a.addProbe(peer, v4, v6) + peer.EndpointLAN = endpoint } diff --git a/peer/on_ping.go b/peer/on_ping.go index 89f1193..0397d8d 100644 --- a/peer/on_ping.go +++ b/peer/on_ping.go @@ -2,7 +2,6 @@ package peer import ( "log" - "net/netip" "time" "vppn/peer/control" @@ -51,15 +50,4 @@ func (a *App) onPing(e PingEvent) { } return } - - a.addProbe(peer, e.ping.SrcV4, e.ping.SrcV6) -} - -func (a *App) addProbe(peer *Peer, v4, v6 netip.AddrPort) { - endpoint := preferredEndpoint(v4, v6) - if !endpoint.IsValid() || endpoint == peer.PreferredEndpoint() { - return - } - peer.UpdateEndpoints(v4, v6) - a.devAddProbe(peer, endpoint) } diff --git a/peer/on_tick.go b/peer/on_tick.go index 1eae224..e9a6b58 100644 --- a/peer/on_tick.go +++ b/peer/on_tick.go @@ -2,6 +2,7 @@ package peer import ( "log" + "net/netip" "time" "vppn/peer/control" @@ -28,6 +29,12 @@ func (a *App) onTick() { } switch p.State { + case StateRelayed: + // If we have an ep to probe, add it. + if ep := p.PreferredEndpoint(); ep.IsValid() { + a.devAddProbe(p, ep) + } + case StateProbing: // Promote probing peers to direct once alive (direct path confirmed // working). @@ -39,9 +46,13 @@ func (a *App) onTick() { if p.IsPublic || a.isPublic || p.Up() { break } - // Stale non-public direct peer: demote to probing so WireGuard - // resumes handshake attempts on the direct path. - a.devAddProbe(p, p.PreferredEndpoint()) + + // Stale non-public direct peer: demote to relayed and wait for new IP + // information. + p.EndpointV4 = netip.AddrPort{} + p.EndpointV6 = netip.AddrPort{} + p.EndpointLAN = netip.AddrPort{} + a.devAddPeer(p) } } diff --git a/peer/remote.go b/peer/remote.go index d3b889a..6e20cee 100644 --- a/peer/remote.go +++ b/peer/remote.go @@ -19,17 +19,18 @@ const ( ) type Peer struct { - wgPeer wgtypes.Peer - VPNIP netip.Addr // VPN IP address. - Name string // Human-readable DNS label. - IsRelay bool // Peer is a relay. - IsPublic bool // Peer has a public IP. - EndpointV4 netip.AddrPort // Reported IPv4 endpoint. - EndpointV6 netip.AddrPort // Reported IPv6 endpoint. - RTT time.Duration // Round-trip time. - State PeerState // Current routing state; updated on each devXxx call. - Role control.Role // Client initiates pings; server responds. - SignPubKey [32]byte // nacl/sign public key for verifying multicast beacons. + wgPeer wgtypes.Peer + VPNIP netip.Addr // VPN IP address. + Name string // Human-readable DNS label. + IsRelay bool // Peer is a relay. + IsPublic bool // Peer has a public IP. + EndpointV4 netip.AddrPort // Reported IPv4 endpoint. + EndpointV6 netip.AddrPort // Reported IPv6 endpoint. + EndpointLAN netip.AddrPort // Discovered via multicast. + RTT time.Duration // Round-trip time. + State PeerState // Current routing state; updated on each devXxx call. + Role control.Role // Client initiates pings; server responds. + SignPubKey [32]byte // nacl/sign public key for verifying multicast beacons. } // PubKey is the wireguard public key. @@ -62,7 +63,13 @@ func (p *Peer) CanRelay() bool { } func (p *Peer) PreferredEndpoint() netip.AddrPort { - return preferredEndpoint(p.EndpointV4, p.EndpointV6) + if p.EndpointLAN.IsValid() { + return p.EndpointLAN + } else if p.EndpointV4.IsValid() { + return p.EndpointV4 + } else { + return p.EndpointV6 + } } func (p *Peer) UpdateEndpoints(v4, v6 netip.AddrPort) {