working
This commit is contained in:
147
pkg/protocol/packet.go
Normal file
147
pkg/protocol/packet.go
Normal file
@@ -0,0 +1,147 @@
|
||||
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,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user