package peer import ( "encoding/binary" "fmt" "log" "net" "net/netip" "time" "golang.zx2c4.com/wireguard/wgctrl/wgtypes" ) func RunMCReader(g Globals, hp *HolePunch, netName string) { for { if err := runMCReaderInner(g, hp, netName); err != nil { log.Printf("[MCReader] %v", err) } time.Sleep(broadcastErrorTimeoutInterval) } } func runMCReaderInner(g Globals, hp *HolePunch, netName string) error { conn, err := net.ListenMulticastUDP("udp", nil, multicastAddr) if err != nil { return fmt.Errorf("bind: %w", err) } defer conn.Close() buf := make([]byte, 64) for { conn.SetReadDeadline(time.Now().Add(32 * time.Second)) n, src, err := conn.ReadFromUDPAddrPort(buf) if err != nil { return fmt.Errorf("read: %w", err) } if n != beaconLen { continue } handleBeacon(g, hp, netName, buf[:n], src) } } func handleBeacon(g Globals, hp *HolePunch, netName string, beacon []byte, src netip.AddrPort) { peerIPByte := beacon[0] if peerIPByte == g.LocalPeerIP { return } pubKey, err := wgtypes.NewKey(beacon[1:33]) if err != nil { return } // Skip relay peers: probing would replace their /24 AllowedIPs with empty. if state, err := loadNetworkState(netName); err == nil { if p := state.Peers[peerIPByte]; p != nil && p.Relay { return } } wgPort := binary.BigEndian.Uint16(beacon[33:35]) endpoint := netip.AddrPortFrom(src.Addr().Unmap(), wgPort) hp.OnEndpointLearned(peerIPByte, pubKey, endpoint, false) }