package peer import ( "net/netip" "time" "golang.zx2c4.com/wireguard/wgctrl/wgtypes" "vppn/peer/control" "vppn/peer/wginterface" ) type PeerState string const ( StateRelayed = PeerState("RELAY") StateProbing = PeerState("PROBE") StateDirect = PeerState("DIRECT") ) 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. 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. func (p *Peer) PubKey() wgtypes.Key { return p.wgPeer.PublicKey } func (p *Peer) WGEndpoint() netip.AddrPort { ep := p.wgPeer.Endpoint if ep == nil { return netip.AddrPort{} } addr, ok := netip.AddrFromSlice(ep.IP) if !ok { return netip.AddrPort{} } return netip.AddrPortFrom(addr.Unmap(), uint16(ep.Port)) } func (p *Peer) LastHandshakeTime() time.Time { return p.wgPeer.LastHandshakeTime } func (p *Peer) Up() bool { return time.Since(p.wgPeer.LastHandshakeTime) < wginterface.SessionTimeout } func (p *Peer) CanRelay() bool { return p.IsRelay && p.Up() } func (p *Peer) PreferredEndpoint() netip.AddrPort { 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) { if v4.IsValid() { p.EndpointV4 = v4 } if v6.IsValid() { p.EndpointV6 = v6 } }