WIP
This commit is contained in:
157
peer/peer.go
157
peer/peer.go
@@ -3,11 +3,8 @@ package peer
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"math"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/netip"
|
||||
"net/url"
|
||||
@@ -15,14 +12,17 @@ import (
|
||||
"vppn/m"
|
||||
|
||||
"git.crumpington.com/lib/go/flock"
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
)
|
||||
|
||||
type peerMain struct {
|
||||
Globals
|
||||
ifReader *IFReader
|
||||
connReader *ConnReader
|
||||
hubPoller *HubPoller
|
||||
lockFile *os.File
|
||||
netName string
|
||||
holePunch *HolePunch
|
||||
controlServer *ControlServer
|
||||
endpointReporter *EndpointReporter // non-nil on relay peers only
|
||||
hubPoller *HubPoller
|
||||
lockFile *os.File
|
||||
}
|
||||
|
||||
func newPeerMain(args mainArgs) *peerMain {
|
||||
@@ -59,89 +59,104 @@ func newPeerMain(args mainArgs) *peerMain {
|
||||
log.Fatalf("Failed to load network state: %v", err)
|
||||
}
|
||||
|
||||
startupCount, err := loadStartupCount(args.NetName)
|
||||
wgPrivKey, err := wgtypes.ParseKey(config.WGPrivKey)
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
log.Fatalf("Failed to load startup count: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if startupCount.Count == math.MaxUint16 {
|
||||
log.Fatalf("Startup counter overflow.")
|
||||
}
|
||||
startupCount.Count += 1
|
||||
|
||||
if err := storeStartupCount(args.NetName, startupCount); err != nil {
|
||||
log.Fatalf("Failed to write startup count: %v", err)
|
||||
}
|
||||
|
||||
iface, err := openInterface(config.Network, config.LocalPeerIP, args.NetName)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to open interface: %v", err)
|
||||
log.Fatalf("Failed to parse WireGuard private key: %v", err)
|
||||
}
|
||||
|
||||
localPeer := state.Peers[config.LocalPeerIP]
|
||||
var listenPort int
|
||||
if localPeer != nil {
|
||||
listenPort = int(localPeer.Port1)
|
||||
}
|
||||
|
||||
myAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf(":%d", localPeer.Port))
|
||||
vpnIP := netip.AddrFrom4([4]byte{
|
||||
config.Network[0],
|
||||
config.Network[1],
|
||||
config.Network[2],
|
||||
config.LocalPeerIP,
|
||||
})
|
||||
|
||||
wgClient, err := createWGDevice(args.NetName, wgPrivKey, listenPort, vpnIP, config.Network)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to resolve UDP address: %v", err)
|
||||
log.Fatalf("Failed to create WireGuard device: %v", err)
|
||||
}
|
||||
|
||||
logf("Listening on %v...", myAddr)
|
||||
conn, err := net.ListenUDP("udp", myAddr)
|
||||
for _, p := range state.Peers {
|
||||
if p == nil || !p.Relay || p.PeerIP == config.LocalPeerIP {
|
||||
continue
|
||||
}
|
||||
if len(p.WGPubKey) != wgtypes.KeyLen || len(p.PublicIP1) == 0 || p.Port1 == 0 {
|
||||
continue
|
||||
}
|
||||
relayPubKey, err := wgtypes.NewKey(p.WGPubKey)
|
||||
if err != nil {
|
||||
logf("Invalid relay WG key: %v", err)
|
||||
continue
|
||||
}
|
||||
relayIP, ok := netip.AddrFromSlice(p.PublicIP1)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
relayEndpoint := netip.AddrPortFrom(relayIP.Unmap(), p.Port1)
|
||||
if err := applyBaseConfig(wgClient, args.NetName, relayPubKey, relayEndpoint, config.Network); err != nil {
|
||||
logf("Failed to apply relay base config: %v", err)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
g := NewGlobals(config, netip.AddrPort{})
|
||||
g.WGPrivKey = wgPrivKey
|
||||
g.WGClient = wgClient
|
||||
g.WGDevName = args.NetName
|
||||
|
||||
holePunch := NewHolePunch(g)
|
||||
|
||||
controlServer, err := NewControlServer(g, holePunch, args.NetName)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to open UDP port: %v", err)
|
||||
log.Fatalf("Failed to create control server: %v", err)
|
||||
}
|
||||
|
||||
conn.SetReadBuffer(1024 * 1024 * 8)
|
||||
conn.SetWriteBuffer(1024 * 1024 * 8)
|
||||
|
||||
var localAddr netip.AddrPort
|
||||
ip, localAddrValid := netip.AddrFromSlice(localPeer.PublicIP)
|
||||
if localAddrValid {
|
||||
localAddr = netip.AddrPortFrom(ip, localPeer.Port)
|
||||
var endpointReporter *EndpointReporter
|
||||
if localPeer != nil && localPeer.Relay {
|
||||
if err := enableForwarding(args.NetName); err != nil {
|
||||
log.Fatalf("Failed to enable IP forwarding: %v", err)
|
||||
}
|
||||
endpointReporter = NewEndpointReporter(g, controlServer, args.NetName)
|
||||
}
|
||||
|
||||
g := NewGlobals(config, startupCount, localAddr, conn, iface)
|
||||
|
||||
hubPoller, err := NewHubPoller(g, args.NetName, args.HubAddress, args.APIKey)
|
||||
hubPoller, err := NewHubPoller(g, holePunch, args.NetName, args.HubAddress, args.APIKey)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create hub poller: %v", err)
|
||||
}
|
||||
|
||||
// Start status server.
|
||||
go runStatusServer(g, statusSocketPath(args.NetName))
|
||||
|
||||
return &peerMain{
|
||||
Globals: g,
|
||||
ifReader: NewIFReader(g),
|
||||
connReader: NewConnReader(g, conn),
|
||||
hubPoller: hubPoller,
|
||||
lockFile: lockFile,
|
||||
Globals: g,
|
||||
netName: args.NetName,
|
||||
holePunch: holePunch,
|
||||
controlServer: controlServer,
|
||||
endpointReporter: endpointReporter,
|
||||
hubPoller: hubPoller,
|
||||
lockFile: lockFile,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *peerMain) Run() {
|
||||
for i := range p.RemotePeers {
|
||||
remote := p.RemotePeers[i].Load()
|
||||
go newRemoteFSM(remote).Run()
|
||||
go p.controlServer.Run()
|
||||
if p.endpointReporter != nil {
|
||||
go p.endpointReporter.Run()
|
||||
}
|
||||
|
||||
go p.ifReader.Run()
|
||||
go p.connReader.Run()
|
||||
|
||||
if !p.LocalAddrValid {
|
||||
go RunMCWriter(p.LocalPeerIP, p.PrivSignKey)
|
||||
go RunMCReader(p.Globals)
|
||||
}
|
||||
|
||||
go RunMCWriter(p.Globals)
|
||||
go RunMCReader(p.Globals, p.holePunch, p.netName)
|
||||
go p.hubPoller.Run()
|
||||
|
||||
select {}
|
||||
}
|
||||
|
||||
func initPeerWithHub(args mainArgs) {
|
||||
keys := generateKeys()
|
||||
privKey := generateWGKey()
|
||||
pubKey := privKey.PublicKey()
|
||||
|
||||
initURL, err := url.Parse(args.HubAddress)
|
||||
if err != nil {
|
||||
@@ -150,8 +165,7 @@ func initPeerWithHub(args mainArgs) {
|
||||
initURL.Path = "/peer/init/"
|
||||
|
||||
initArgs := m.PeerInitArgs{
|
||||
EncPubKey: keys.PubKey,
|
||||
PubSignKey: keys.PubSignKey,
|
||||
WGPubKey: pubKey[:],
|
||||
}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
@@ -176,18 +190,23 @@ func initPeerWithHub(args mainArgs) {
|
||||
log.Fatalf("Failed to read response body: %v", err)
|
||||
}
|
||||
|
||||
if resp.StatusCode == http.StatusConflict {
|
||||
log.Fatalf("WireGuard key already registered (HTTP 409). Delete and re-create the peer to re-register.")
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
log.Fatalf("Hub returned unexpected status %d: %s", resp.StatusCode, data)
|
||||
}
|
||||
|
||||
initResp := m.PeerInitResp{}
|
||||
if err := json.Unmarshal(data, &initResp); err != nil {
|
||||
log.Fatalf("Failed to parse configuration: %v\n%s", err, data)
|
||||
}
|
||||
|
||||
config := LocalConfig{}
|
||||
config.LocalPeerIP = initResp.PeerIP
|
||||
config.Network = initResp.Network
|
||||
config.PubKey = keys.PubKey
|
||||
config.PrivKey = keys.PrivKey
|
||||
config.PubSignKey = keys.PubSignKey
|
||||
config.PrivSignKey = keys.PrivSignKey
|
||||
config := LocalConfig{
|
||||
LocalPeerIP: initResp.PeerIP,
|
||||
Network: initResp.Network,
|
||||
WGPrivKey: privKey.String(),
|
||||
}
|
||||
|
||||
if err := storeNetworkState(args.NetName, initResp.NetworkState); err != nil {
|
||||
log.Fatalf("Failed to store network state: %v", err)
|
||||
|
||||
Reference in New Issue
Block a user