package peer import ( "fmt" "net/netip" "golang.zx2c4.com/wireguard/wgctrl/wgtypes" "vppn/m" "vppn/peer/multicast" "vppn/peer/wginterface" ) // New constructs an App, creates the WireGuard interface, and starts the // background goroutines (hub poller, multicast, control conn reader). // The caller should invoke Run() to start the event loop. func New( state LocalState, hubURL, apiKey string, ifaceName string, localDomain string, networkStatePath string, ) (*App, error) { a4 := state.VPNIP.As4() if err := wginterface.Create(ifaceName, a4[:], 24); err != nil { return nil, fmt.Errorf("create WG interface: %w", err) } dev, err := wginterface.Open(ifaceName) if err != nil { _ = wginterface.Delete(ifaceName) return nil, fmt.Errorf("open WG device: %w", err) } cc, err := newUDPControlConn(state.VPNIP, ControlPort) if err != nil { _ = dev.Close() _ = wginterface.Delete(ifaceName) return nil, fmt.Errorf("control conn: %w", err) } cleanup := func() { _ = cc.Close() _ = dev.Close() _ = wginterface.Delete(ifaceName) } if err := dev.Configure(state.PrivKey, int(state.WGPort)); err != nil { cleanup() return nil, fmt.Errorf("configure WG device: %w", err) } if state.IsRelay { if err := dev.EnableForwarding(); err != nil { cleanup() return nil, fmt.Errorf("enable forwarding: %w", err) } } pingCh := make(chan PingEvent) hubAddCh := make(chan m.Peer) hubRemoveCh := make(chan wgtypes.Key) multicastCh := make(chan multicast.Packet) poller, err := NewHubPoller( state.VPNIP, state.VPNNet, hubURL, apiKey, networkStatePath, hubAddCh, hubRemoveCh) if err != nil { cleanup() return nil, fmt.Errorf("hub poller: %w", err) } go cc.run(pingCh) go poller.Run() if !state.IsPublic { go multicast.Broadcast(state.VPNIP, state.PrivKey.PublicKey(), state.WGPort, &state.SignKey) go multicast.Receiver(state.VPNIP, multicastCh) } return &App{ vpnIP: state.VPNIP, vpnNet: state.VPNNet, privKey: state.PrivKey, pubKey: state.PrivKey.PublicKey(), isRelay: state.IsRelay, isPublic: state.IsPublic, localDomain: localDomain, dev: dev, controlConn: cc, peersByKey: make(map[wgtypes.Key]*Peer), peersByIP: make(map[netip.Addr]*Peer), scratch: make([]byte, scratchSize), hubAddCh: hubAddCh, hubRemoveCh: hubRemoveCh, pingCh: pingCh, multicastCh: multicastCh, }, nil }