package node import ( "errors" "net/netip" "time" "unsafe" ) var ( errMalformedPacket = errors.New("malformed packet") errUnknownPacketType = errors.New("unknown packet type") ) const ( packetTypeSyn = iota + 1 packetTypeSynAck packetTypeAck packetTypePing packetTypePong packetTypeRelayed ) // ---------------------------------------------------------------------------- type controlPacket struct { SrcIP byte RemoteAddr netip.AddrPort Payload any } func (p *controlPacket) ParsePayload(buf []byte) (err error) { switch buf[0] { case packetTypePing: p.Payload, err = parsePingPacket(buf) case packetTypePong: p.Payload, err = parsePongPacket(buf) case packetTypeSyn: p.Payload, err = parseSynPacket(buf) default: return errUnknownPacketType } return err } // ---------------------------------------------------------------------------- type synPacket struct { TraceID uint64 // TraceID to match response w/ request. SharedKey [32]byte // Our shared key. ServerAddr netip.AddrPort // The address we're sending to. Direct bool // True if this is request isn't relayed. } func (p synPacket) Marshal(buf []byte) []byte { return newBinWriter(buf). Byte(packetTypeSyn). Uint64(p.TraceID). SharedKey(p.SharedKey). AddrPort(p.ServerAddr). Bool(p.Direct). Build() } func parseSynPacket(buf []byte) (p synPacket, err error) { err = newBinReader(buf[1:]). Uint64(&p.TraceID). SharedKey(&p.SharedKey). AddrPort(&p.ServerAddr). Bool(&p.Direct). Error() return } // ---------------------------------------------------------------------------- type synAckPacket struct { TraceID uint64 } func (p synAckPacket) Marshal(buf []byte) []byte { return newBinWriter(buf). Byte(packetTypeSynAck). Uint64(p.TraceID). Build() } func parseSynAckPacket(buf []byte) (p synAckPacket, err error) { err = newBinReader(buf[1:]). Uint64(&p.TraceID). Error() return } // ---------------------------------------------------------------------------- type ackPacket struct { TraceID uint64 } func (p ackPacket) Marshal(buf []byte) []byte { return newBinWriter(buf). Byte(packetTypeSynAck). Uint64(p.TraceID). Build() } func parseAckPacket(buf []byte) (p ackPacket, err error) { err = newBinReader(buf[1:]). Uint64(&p.TraceID). Error() return } // ---------------------------------------------------------------------------- // A pingPacket is sent from a node acting as a client, to a node acting // as a server. It always contains the shared key the client is expecting // to use for data encryption with the server. type pingPacket struct { SentAt int64 // UnixMilli. // Not used. Use traceID. SharedKey [32]byte } func newPingPacket(sharedKey [32]byte) (pp pingPacket) { pp.SentAt = time.Now().UnixMilli() pp.SharedKey = sharedKey return } func (p pingPacket) Marshal(buf []byte) []byte { return newBinWriter(buf). Byte(packetTypePing). Int64(p.SentAt). SharedKey(p.SharedKey). Build() } func parsePingPacket(buf []byte) (p pingPacket, err error) { err = newBinReader(buf[1:]). Int64(&p.SentAt). SharedKey(&p.SharedKey). Error() return } // ---------------------------------------------------------------------------- // A pongPacket is sent by a node in a server role in response to a pingPacket. type pongPacket struct { SentAt int64 // UnixMilli. RecvdAt int64 // UnixMilli. } func newPongPacket(sentAt int64) (pp pongPacket) { pp.SentAt = sentAt pp.RecvdAt = time.Now().UnixMilli() return } func (p pongPacket) Marshal(buf []byte) []byte { buf = buf[:17] buf[0] = packetTypePong *(*uint64)(unsafe.Pointer(&buf[1])) = uint64(p.SentAt) *(*uint64)(unsafe.Pointer(&buf[9])) = uint64(p.RecvdAt) return buf } func parsePongPacket(buf []byte) (p pongPacket, err error) { if len(buf) != 17 { return p, errMalformedPacket } p.SentAt = *(*int64)(unsafe.Pointer(&buf[1])) p.RecvdAt = *(*int64)(unsafe.Pointer(&buf[9])) return }