package peer import ( "log" "net/netip" "time" "vppn/peer/control" "vppn/peer/wginterface" ) func (a *App) onTick() { wgPeers := a.devPeers() now := time.Now().UnixNano() for _, wgPeer := range wgPeers { p, ok := a.peersByKey[wgPeer.PublicKey] if !ok { log.Printf("Wireguard peer not known. Removing: %v", wgPeer.PublicKey) a.devRemove(&Peer{wgPeer: wgPeer}) continue } p.wgPeer = wgPeer // Log endpoint changes. if ep := p.WGEndpoint(); ep != p.EndpointWG { log.Printf("Client %s %s endpoint: %s -> %s", p.Name, p.VPNIP, p.EndpointWG, ep) p.EndpointWG = ep } // Send pings to peers where we're the client. if p.Role == control.Client { a.sendPing(p, now) } switch p.State { case StateRelayed: // If we have an ep to probe, add it. if ep := p.PreferredEndpoint(); ep.IsValid() { p.ProbeStart = time.Now() a.devAddProbe(p, ep) } case StateProbing: if time.Since(p.LastHandshakeTime()) < 2*wginterface.ProbeKeepalive { // Promote probing peers to direct once alive (direct path confirmed // working). a.devPromote(p) } else if ep := p.PreferredEndpoint(); ep.IsValid() && ep != p.WGEndpoint() { // Update the probe address if it's changed. a.devAddProbe(p, ep) } else if time.Since(p.ProbeStart) > 8*wginterface.ProbeKeepalive { // Give up probing if we haven't been able to handshake. p.EndpointV4 = netip.AddrPort{} p.EndpointV6 = netip.AddrPort{} p.EndpointLAN = netip.AddrPort{} a.devAddPeer(p) } case StateDirect: if p.IsPublic || a.isPublic || p.Up() { break } // 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) } } // Ensure we have a live relay (if we're not public). if !a.isPublic && (a.relay == nil || !a.relay.Up()) { a.switchActiveRelay() } }