package multicast import ( "encoding/binary" "net/netip" "golang.org/x/crypto/nacl/sign" ) const ( BufferSize = packetSize + SignedPacketSize SignedPacketSize = packetSize + signSize packetSize = 43 signSize = 64 ) // Layout: // // [0] final octet of the sender's VPN IP // [1:33] WG public key // [33:35] WG listen port (big-endian uint16) // [35:43] send time, Unix seconds (big-endian int64) — freshness/replay gate type Packet struct { PeerIP byte // Final octet of the sender's VPN IP. WGPubKey [32]byte // WG public key. WGPort uint16 // WG listen port. Timestamp int64 // Unix timestamp. Src netip.Addr // Source of packet. Signed []byte // Raw signed message for verification (incoming packet). } // marshal the packet into a buffer with prefixed signature. func (p Packet) marshal(buf []byte, signKey *[64]byte) []byte { buf[0] = p.PeerIP copy(buf[1:33], p.WGPubKey[:]) binary.BigEndian.PutUint16(buf[33:35], p.WGPort) binary.BigEndian.PutUint64(buf[35:43], uint64(p.Timestamp)) return sign.Sign(buf[packetSize:packetSize], buf[:packetSize], signKey) } func (p Packet) Verify(buf []byte, pubKey *[32]byte) bool { _, ok := sign.Open(buf, p.Signed, pubKey) return ok } func unmarshal(signed []byte) (p Packet) { buf := signed[signSize:] p.PeerIP = buf[0] copy(p.WGPubKey[:], buf[1:33]) p.WGPort = binary.BigEndian.Uint16(buf[33:35]) p.Timestamp = int64(binary.BigEndian.Uint64(buf[35:43])) p.Signed = signed return }