Files
go-ts/pkg/protocol/packet.go
Jose Luis Montañes Ojados 47b8173045 working
2026-01-15 16:49:16 +01:00

148 lines
3.5 KiB
Go

package protocol
import (
"bytes"
"encoding/binary"
"errors"
)
// PacketType represents the type of a TeamSpeak 3 packet.
type PacketType uint8
const (
PacketTypeVoice PacketType = 0x00
PacketTypeVoiceWhisper PacketType = 0x01
PacketTypeCommand PacketType = 0x02
PacketTypeCommandLow PacketType = 0x03
PacketTypePing PacketType = 0x04
PacketTypePong PacketType = 0x05
PacketTypeAck PacketType = 0x06
PacketTypeAckLow PacketType = 0x07
PacketTypeInit1 PacketType = 0x08
)
// Packet Flags
const (
PacketFlagUnencrypted = 0x80
PacketFlagCompressed = 0x40
PacketFlagNewProtocol = 0x20
PacketFlagFragmented = 0x10
)
const (
HeaderSizeClientToServer = 13 // 8 MAC + 2 PID + 2 CID + 1 PT
HeaderSizeServerToClient = 11 // 8 MAC + 2 PID + 1 PT
MACSize = 8
)
// PacketHeader represents the common header fields.
type PacketHeader struct {
MAC [8]byte
PacketID uint16
ClientID uint16 // Only present in Client -> Server
Type uint8 // Contains PacketType and Flags
}
// Packet represents a parsed TeamSpeak 3 packet.
type Packet struct {
Header PacketHeader
Data []byte
}
func (h *PacketHeader) FlagUnencrypted() bool { return h.Type&PacketFlagUnencrypted != 0 }
func (h *PacketHeader) FlagCompressed() bool { return h.Type&PacketFlagCompressed != 0 }
func (h *PacketHeader) FlagNewProtocol() bool { return h.Type&PacketFlagNewProtocol != 0 }
func (h *PacketHeader) FlagFragmented() bool { return h.Type&PacketFlagFragmented != 0 }
func (h *PacketHeader) PacketType() PacketType { return PacketType(h.Type & 0x0F) }
// SetType sets the packet type and preserves flags
func (h *PacketHeader) SetType(pt PacketType) {
flags := h.Type & 0xF0
h.Type = flags | uint8(pt&0x0F)
}
// Encode writes the packet to a byte slice.
func (p *Packet) Encode(isClientToServer bool) ([]byte, error) {
buf := new(bytes.Buffer)
// MAC
buf.Write(p.Header.MAC[:])
// Packet ID
if err := binary.Write(buf, binary.BigEndian, p.Header.PacketID); err != nil {
return nil, err
}
// Client ID (only C->S)
if isClientToServer {
if err := binary.Write(buf, binary.BigEndian, p.Header.ClientID); err != nil {
return nil, err
}
}
// Packet Type
if err := binary.Write(buf, binary.BigEndian, p.Header.Type); err != nil {
return nil, err
}
// Data
buf.Write(p.Data)
return buf.Bytes(), nil
}
// Decode parses a packet from a byte slice.
func Decode(data []byte, isClientToServer bool) (*Packet, error) {
reader := bytes.NewReader(data)
p := &Packet{}
// Check minimum size
minSize := HeaderSizeServerToClient
if isClientToServer {
minSize = HeaderSizeClientToServer
}
if len(data) < minSize {
return nil, errors.New("packet too short")
}
// MAC
if _, err := reader.Read(p.Header.MAC[:]); err != nil {
return nil, err
}
// Packet ID
if err := binary.Read(reader, binary.BigEndian, &p.Header.PacketID); err != nil {
return nil, err
}
// Client ID (only C->S)
if isClientToServer {
if err := binary.Read(reader, binary.BigEndian, &p.Header.ClientID); err != nil {
return nil, err
}
}
// Packet Type
if err := binary.Read(reader, binary.BigEndian, &p.Header.Type); err != nil {
return nil, err
}
// Data
p.Data = make([]byte, reader.Len())
if _, err := reader.Read(p.Data); err != nil {
return nil, err
}
return p, nil
}
func NewPacket(pt PacketType, data []byte) *Packet {
return &Packet{
Header: PacketHeader{
Type: uint8(pt),
MAC: [8]byte{}, // Default empty MAC
},
Data: data,
}
}