116 lines
2.3 KiB
Go
116 lines
2.3 KiB
Go
package peer
|
|
|
|
import (
|
|
"log"
|
|
"math"
|
|
"net/netip"
|
|
"time"
|
|
|
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
|
|
|
"vppn/peer/control"
|
|
)
|
|
|
|
func (a *App) onAddPeer(p HubPeer) {
|
|
a.onRemovePeer(p.PubKey)
|
|
|
|
peer := &Peer{
|
|
wgPeer: wgtypes.Peer{PublicKey: p.PubKey},
|
|
VPNIP: p.VPNIP,
|
|
Name: p.Name,
|
|
IsRelay: p.IsRelay,
|
|
IsPublic: p.IsPublic,
|
|
Endpoint4: p.EndpointV4,
|
|
Endpoint6: p.EndpointV6,
|
|
RTT: time.Duration(math.MaxInt64) * time.Nanosecond,
|
|
Role: roleFor(a.isPublic, a.vpnIP, p),
|
|
SignPubKey: p.SignPubKey,
|
|
}
|
|
|
|
endpoint := peer.PreferredEndpoint()
|
|
if peer.IsPublic && !endpoint.IsValid() {
|
|
// The peer is misconfigured.
|
|
// TODO: Log here.
|
|
return
|
|
}
|
|
|
|
a.peersByKey[p.PubKey] = peer
|
|
a.peersByIP[peer.VPNIP] = peer
|
|
defer a.updateHosts()
|
|
|
|
if !peer.IsPublic {
|
|
if a.isPublic {
|
|
// Public nodes accept traffic from non-public peers as soon as they
|
|
// initiate a handshake. Set /32 AllowedIPs now; WireGuard learns the
|
|
// endpoint from the incoming handshake automatically.
|
|
a.devPromote(peer)
|
|
} else {
|
|
a.devAddPeer(peer)
|
|
}
|
|
return
|
|
}
|
|
|
|
a.devAddDirect(peer, endpoint)
|
|
}
|
|
|
|
func (a *App) onRemovePeer(key wgtypes.Key) {
|
|
peer, exists := a.peersByKey[key]
|
|
if !exists {
|
|
return
|
|
}
|
|
a.devRemove(peer)
|
|
delete(a.peersByKey, key)
|
|
delete(a.peersByIP, peer.VPNIP)
|
|
a.updateHosts()
|
|
|
|
if peer == a.relay {
|
|
a.relay = nil
|
|
a.switchActiveRelay()
|
|
}
|
|
}
|
|
|
|
// switchActiveRelay promotes the lowest-latency relay peer to active.
|
|
func (a *App) switchActiveRelay() {
|
|
if a.relay != nil {
|
|
// If we have a relay, it's public, so should go back to being a direct
|
|
// peer - this will convert it's /24 to a /32.
|
|
a.devAddDirect(a.relay, a.relay.PreferredEndpoint())
|
|
a.relay = nil
|
|
}
|
|
|
|
var best *Peer
|
|
for _, p := range a.peersByKey {
|
|
if !p.CanRelay() {
|
|
continue
|
|
}
|
|
|
|
if best == nil || p.RTT < best.RTT {
|
|
best = p
|
|
}
|
|
}
|
|
if best == nil {
|
|
log.Printf("no relay available")
|
|
return
|
|
}
|
|
|
|
a.devSetRelay(best, best.PreferredEndpoint())
|
|
a.relay = best
|
|
}
|
|
|
|
func preferredEndpoint(v4, v6 netip.AddrPort) netip.AddrPort {
|
|
if v4.IsValid() {
|
|
return v4
|
|
}
|
|
return v6
|
|
}
|
|
|
|
func roleFor(selfIsPublic bool, selfIP netip.Addr, p HubPeer) control.Role {
|
|
if !selfIsPublic && p.IsPublic {
|
|
return control.Client
|
|
}
|
|
if selfIsPublic && !p.IsPublic {
|
|
return control.Server
|
|
}
|
|
return control.RoleFor(selfIP, p.VPNIP)
|
|
}
|