110 lines
2.4 KiB
Go
110 lines
2.4 KiB
Go
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
|
|
}
|