89 lines
2.0 KiB
Go
89 lines
2.0 KiB
Go
package peer
|
|
|
|
import (
|
|
"log"
|
|
"net/netip"
|
|
"time"
|
|
|
|
"golang.zx2c4.com/wireguard/wgctrl"
|
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
|
)
|
|
|
|
const reporterInterval = 5 * time.Second
|
|
|
|
// EndpointReporter runs on relay peers only. It polls wgctrl every 5s and,
|
|
// for each peer whose LastHandshakeTime has changed, sends MsgYourEndpoint to
|
|
// that peer's VPN IP so it learns its own external WG endpoint.
|
|
type EndpointReporter struct {
|
|
client *wgctrl.Client
|
|
devName string
|
|
network []byte
|
|
netName string
|
|
control *ControlServer
|
|
lastTimes map[wgtypes.Key]time.Time
|
|
}
|
|
|
|
func NewEndpointReporter(g Globals, cs *ControlServer, netName string) *EndpointReporter {
|
|
return &EndpointReporter{
|
|
client: g.WGClient,
|
|
devName: g.WGDevName,
|
|
network: g.Network,
|
|
netName: netName,
|
|
control: cs,
|
|
lastTimes: make(map[wgtypes.Key]time.Time),
|
|
}
|
|
}
|
|
|
|
func (er *EndpointReporter) Run() {
|
|
for range time.Tick(reporterInterval) {
|
|
er.poll()
|
|
}
|
|
}
|
|
|
|
func (er *EndpointReporter) poll() {
|
|
dev, err := er.client.Device(er.devName)
|
|
if err != nil {
|
|
log.Printf("[EndpointReporter] get device: %v", err)
|
|
return
|
|
}
|
|
|
|
state, err := loadNetworkState(er.netName)
|
|
if err != nil {
|
|
log.Printf("[EndpointReporter] load state: %v", err)
|
|
return
|
|
}
|
|
|
|
// Build WGPubKey → VPN IP byte index from current network state.
|
|
keyToIP := make(map[wgtypes.Key]byte, len(dev.Peers))
|
|
for _, p := range state.Peers {
|
|
if p == nil || len(p.WGPubKey) != wgtypes.KeyLen {
|
|
continue
|
|
}
|
|
key, err := wgtypes.NewKey(p.WGPubKey)
|
|
if err == nil {
|
|
keyToIP[key] = p.PeerIP
|
|
}
|
|
}
|
|
|
|
for _, p := range dev.Peers {
|
|
if p.Endpoint == nil || p.LastHandshakeTime.IsZero() {
|
|
continue
|
|
}
|
|
if p.LastHandshakeTime == er.lastTimes[p.PublicKey] {
|
|
continue
|
|
}
|
|
|
|
peerIPByte, ok := keyToIP[p.PublicKey]
|
|
if !ok {
|
|
continue
|
|
}
|
|
|
|
er.lastTimes[p.PublicKey] = p.LastHandshakeTime
|
|
|
|
peerVPNIP := netip.AddrFrom4([4]byte{
|
|
er.network[0], er.network[1], er.network[2], peerIPByte,
|
|
})
|
|
er.control.SendYourEndpoint(peerVPNIP, p.Endpoint.AddrPort())
|
|
}
|
|
}
|