//go:build ignore package peer import ( "encoding/json" "io" "log" "net/http" "net/netip" "net/url" "time" "vppn/m" "golang.zx2c4.com/wireguard/wgctrl/wgtypes" ) type HubPoller struct { client *http.Client req *http.Request versions [256]int64 netName string } func NewHubPoller( netName, hubURL, apiKey string, ) (*HubPoller, error) { u, err := url.Parse(hubURL) if err != nil { return nil, err } u.Path = "/peer/fetch-state/" client := &http.Client{Timeout: 8 * time.Second} req := &http.Request{ Method: http.MethodGet, URL: u, Header: http.Header{}, } req.SetBasicAuth("", apiKey) return &HubPoller{ Globals: g, holePunch: hp, client: client, req: req, netName: netName, }, nil } func (hp *HubPoller) logf(s string, args ...any) { log.Printf("[HubPoller] "+s, args...) } func (hp *HubPoller) Run() { state, err := loadNetworkState(hp.netName) if err != nil { hp.logf("Failed to load network state: %v", err) hp.logf("Polling hub...") hp.pollHub() } else { hp.applyNetworkState(state) } for range time.Tick(64 * time.Second) { hp.pollHub() } } func (hp *HubPoller) pollHub() { var state m.NetworkState resp, err := hp.client.Do(hp.req) if err != nil { hp.logf("Failed to fetch peer state: %v", err) return } body, err := io.ReadAll(resp.Body) _ = resp.Body.Close() if err != nil { hp.logf("Failed to read body from hub: %v", err) return } if err := json.Unmarshal(body, &state); err != nil { hp.logf("Failed to unmarshal response from hub: %v\n%s", err, body) return } if err := storeNetworkState(hp.netName, state); err != nil { hp.logf("Failed to store network state: %v", err) } hp.applyNetworkState(state) } func (hp *HubPoller) applyNetworkState(state m.NetworkState) { for i, peer := range state.Peers { if i == int(hp.LocalPeerIP) { continue } if peer != nil && peer.Version == hp.versions[i] { continue } hp.applyPeerConfig(peer) if peer != nil { hp.versions[i] = peer.Version } } } func (hp *HubPoller) applyPeerConfig(peer *m.Peer) { if peer == nil || len(peer.WGPubKey) != wgtypes.KeyLen { return } if len(peer.Addr4) == 0 || peer.Port == 0 { return } pubKey, err := wgtypes.NewKey(peer.WGPubKey) if err != nil { hp.logf("Invalid WG key for peer %d: %v", peer.PeerIP, err) return } ip, ok := netip.AddrFromSlice(peer.Addr4) if !ok { hp.logf("Invalid public IP for peer %d", peer.PeerIP) return } endpoint := netip.AddrPortFrom(ip.Unmap(), peer.Port) if peer.Relay { if err := applyBaseConfig(hp.WGClient, hp.WGDevName, pubKey, endpoint, hp.Network); err != nil { hp.logf("Failed to update relay config: %v", err) } return } if hp.holePunch != nil { hp.holePunch.OnEndpointLearned(peer.PeerIP, pubKey, endpoint, true) } }