package peer import ( "errors" "log" "net/netip" "syscall" "time" "golang.zx2c4.com/wireguard/wgctrl/wgtypes" ) // devRetry calls fn up to 6 times with exponential backoff, retrying on EBUSY // (transient netlink contention during WireGuard handshake/rekey). Fatal on // any other error. func devRetry(vpnIP netip.Addr, op string, fn func() error) { const attempts = 6 timeout := 10 * time.Millisecond for i := range attempts { err := fn() if err == nil { return } if errors.Is(err, syscall.EBUSY) && i < attempts-1 { time.Sleep(timeout) timeout *= 2 continue } log.Fatalf("%s %v: %v", op, vpnIP, err) } } func (a *App) devPeers() []wgtypes.Peer { peers, err := a.dev.Peers() if err != nil { log.Fatalf("Failed to get peers %v: %v", a.vpnIP, err) } return peers } func (a *App) devAddPeer(p *Peer) { log.Printf("RELAYED: %s - %s ", p.Name, p.VPNIP.String()) devRetry(p.VPNIP, "AddPeer", func() error { return a.dev.AddPeer(p.PubKey()) }) p.State = StateRelayed } func (a *App) devAddDirect(p *Peer, endpoint netip.AddrPort) { log.Printf("DIRECT: %s - %s @ %s", p.Name, p.VPNIP.String(), endpoint.String()) devRetry(p.VPNIP, "AddDirect", func() error { return a.dev.AddDirect(p.PubKey(), endpoint, p.VPNIP) }) p.State = StateDirect } func (a *App) devSetRelay(p *Peer, endpoint netip.AddrPort) { log.Printf("RELAY: %s - %s @ %s", p.Name, p.VPNIP.String(), endpoint.String()) devRetry(p.VPNIP, "SetRelay", func() error { return a.dev.SetRelay(p.PubKey(), endpoint, a.vpnNet) }) p.State = StateDirect // Direct connection. The app marks peer as relay. } func (a *App) devPromote(p *Peer) { ep := p.WGEndpoint() if ep.IsValid() { log.Printf("PROMOTED: %s - %s @ %s", p.Name, p.VPNIP.String(), p.WGEndpoint().String()) } else { log.Printf("PROMOTED: %s - %s (no IP)", p.Name, p.VPNIP.String()) } devRetry(p.VPNIP, "Promote", func() error { return a.dev.Promote(p.PubKey(), p.VPNIP) }) p.State = StateDirect } func (a *App) devAddProbe(p *Peer, endpoint netip.AddrPort) { log.Printf("PROBE: %s - %s @ %s", p.Name, p.VPNIP.String(), endpoint.String()) devRetry(p.VPNIP, "AddProbe", func() error { return a.dev.AddProbe(p.PubKey(), endpoint) }) p.State = StateProbing } func (a *App) devRemove(p *Peer) { log.Printf("REMOVED: %s - %s", p.Name, p.VPNIP.String()) devRetry(p.VPNIP, "RemovePeer", func() error { return a.dev.RemovePeer(p.PubKey()) }) }