148 lines
3.5 KiB
Go
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,
|
||
|
|
}
|
||
|
|
}
|