420 lines
12 KiB
Go
420 lines
12 KiB
Go
|
|
package packets
|
||
|
|
|
||
|
|
import (
|
||
|
|
"bytes"
|
||
|
|
"cimeyclust.com/steel/pkg/utils"
|
||
|
|
"encoding/binary"
|
||
|
|
"fmt"
|
||
|
|
"net"
|
||
|
|
"sort"
|
||
|
|
)
|
||
|
|
|
||
|
|
const (
|
||
|
|
IDConnectedPing byte = 0x00
|
||
|
|
IDUnconnectedPing byte = 0x01
|
||
|
|
IDUnconnectedPingOpenConnections byte = 0x02
|
||
|
|
IDConnectedPong byte = 0x03
|
||
|
|
IDDetectLostConnections byte = 0x04
|
||
|
|
IDOpenConnectionRequest1 byte = 0x05
|
||
|
|
IDOpenConnectionReply1 byte = 0x06
|
||
|
|
IDOpenConnectionRequest2 byte = 0x07
|
||
|
|
IDOpenConnectionReply2 byte = 0x08
|
||
|
|
IDConnectionRequest byte = 0x09
|
||
|
|
IDConnectionRequestAccepted byte = 0x10
|
||
|
|
IDNewIncomingConnection byte = 0x13
|
||
|
|
IDDisconnectNotification byte = 0x15
|
||
|
|
|
||
|
|
IDIncompatibleProtocolVersion byte = 0x19
|
||
|
|
|
||
|
|
IDUnconnectedPong byte = 0x1c
|
||
|
|
)
|
||
|
|
|
||
|
|
// unconnectedMessageSequence is a sequence of bytes which is found in every unconnected message sent in
|
||
|
|
// RakNet.
|
||
|
|
var unconnectedMessageSequence = [16]byte{0x00, 0xff, 0xff, 0x00, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0x12, 0x34, 0x56, 0x78}
|
||
|
|
|
||
|
|
// writeAddr writes a UDP address to the buffer passed.
|
||
|
|
func writeAddr(buffer *bytes.Buffer, addr net.UDPAddr) {
|
||
|
|
var ver byte = 6
|
||
|
|
if addr.IP.To4() != nil {
|
||
|
|
ver = 4
|
||
|
|
}
|
||
|
|
if addr.IP == nil {
|
||
|
|
addr.IP = make([]byte, 16)
|
||
|
|
}
|
||
|
|
_ = buffer.WriteByte(ver)
|
||
|
|
if ver == 4 {
|
||
|
|
ipBytes := addr.IP.To4()
|
||
|
|
|
||
|
|
_ = buffer.WriteByte(^ipBytes[0])
|
||
|
|
_ = buffer.WriteByte(^ipBytes[1])
|
||
|
|
_ = buffer.WriteByte(^ipBytes[2])
|
||
|
|
_ = buffer.WriteByte(^ipBytes[3])
|
||
|
|
_ = binary.Write(buffer, binary.BigEndian, uint16(addr.Port))
|
||
|
|
} else {
|
||
|
|
_ = binary.Write(buffer, binary.LittleEndian, int16(23)) // syscall.AF_INET6 on Windows.
|
||
|
|
_ = binary.Write(buffer, binary.BigEndian, uint16(addr.Port))
|
||
|
|
// The IPv6 address is enclosed in two 0 integers.
|
||
|
|
_ = binary.Write(buffer, binary.BigEndian, int32(0))
|
||
|
|
_, _ = buffer.Write(addr.IP.To16())
|
||
|
|
_ = binary.Write(buffer, binary.BigEndian, int32(0))
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// readAddr decodes a RakNet address from the buffer passed. If not successful, an error is returned.
|
||
|
|
func readAddr(buffer *bytes.Buffer, addr *net.UDPAddr) error {
|
||
|
|
ver, err := buffer.ReadByte()
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
if ver == 4 {
|
||
|
|
ipBytes := make([]byte, 4)
|
||
|
|
if _, err := buffer.Read(ipBytes); err != nil {
|
||
|
|
return fmt.Errorf("error reading raknet address ipv4 bytes: %v", err)
|
||
|
|
}
|
||
|
|
// Construct an IPv4 out of the 4 bytes we just read.
|
||
|
|
addr.IP = net.IPv4((-ipBytes[0]-1)&0xff, (-ipBytes[1]-1)&0xff, (-ipBytes[2]-1)&0xff, (-ipBytes[3]-1)&0xff)
|
||
|
|
var port uint16
|
||
|
|
if err := binary.Read(buffer, binary.BigEndian, &port); err != nil {
|
||
|
|
return fmt.Errorf("error reading raknet address port: %v", err)
|
||
|
|
}
|
||
|
|
addr.Port = int(port)
|
||
|
|
} else {
|
||
|
|
buffer.Next(2)
|
||
|
|
var port uint16
|
||
|
|
if err := binary.Read(buffer, binary.LittleEndian, &port); err != nil {
|
||
|
|
return fmt.Errorf("error reading raknet address port: %v", err)
|
||
|
|
}
|
||
|
|
addr.Port = int(port)
|
||
|
|
buffer.Next(4)
|
||
|
|
addr.IP = make([]byte, 16)
|
||
|
|
if _, err := buffer.Read(addr.IP); err != nil {
|
||
|
|
return fmt.Errorf("error reading raknet address ipv6 bytes: %v", err)
|
||
|
|
}
|
||
|
|
buffer.Next(4)
|
||
|
|
}
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
const (
|
||
|
|
// BitFlagDatagram is set for every valid datagram. It is used to identify
|
||
|
|
// packets that are datagrams.
|
||
|
|
BitFlagDatagram = 0x80
|
||
|
|
// BitFlagACK is set for every ACK Packet.
|
||
|
|
BitFlagACK = 0x40
|
||
|
|
// BitFlagNACK is set for every NACK Packet.
|
||
|
|
BitFlagNACK = 0x20
|
||
|
|
// BitFlagNeedsBAndAS is set for every datagram with Packet data, but is not
|
||
|
|
// actually used.
|
||
|
|
BitFlagNeedsBAndAS = 0x04
|
||
|
|
)
|
||
|
|
|
||
|
|
// noinspection GoUnusedConst
|
||
|
|
const (
|
||
|
|
// ReliabilityUnreliable means that the Packet sent could arrive out of
|
||
|
|
// order, be duplicated, or just not arrive at all. It is usually used for
|
||
|
|
// high frequency packets of which the order does not matter.
|
||
|
|
// lint:ignore U1000 While this constant is unused, it is here for the sake
|
||
|
|
// of having all reliabilities documented.
|
||
|
|
ReliabilityUnreliable byte = iota
|
||
|
|
// ReliabilityUnreliableSequenced means that the Packet sent could be
|
||
|
|
// duplicated or not arrive at all, but ensures that it is always handled in
|
||
|
|
// the right order.
|
||
|
|
ReliabilityUnreliableSequenced
|
||
|
|
// ReliabilityReliable means that the Packet sent could not arrive, or
|
||
|
|
// arrive out of order, but ensures that the Packet is not duplicated.
|
||
|
|
ReliabilityReliable
|
||
|
|
// ReliabilityReliableOrdered means that every Packet sent arrives, arrives
|
||
|
|
// in the right order and is not duplicated.
|
||
|
|
ReliabilityReliableOrdered
|
||
|
|
// ReliabilityReliableSequenced means that the Packet sent could not arrive,
|
||
|
|
// but ensures that the Packet will be in the right order and not be
|
||
|
|
// duplicated.
|
||
|
|
ReliabilityReliableSequenced
|
||
|
|
|
||
|
|
// SplitFlag is set in the header if the Packet was split. If so, the
|
||
|
|
// encapsulation contains additional data about the fragment.
|
||
|
|
SplitFlag = 0x10
|
||
|
|
)
|
||
|
|
|
||
|
|
// Packet is an encapsulation around every Packet sent after the connection is
|
||
|
|
// established. It is
|
||
|
|
type Packet struct {
|
||
|
|
Reliability byte
|
||
|
|
|
||
|
|
Content []byte
|
||
|
|
MessageIndex utils.Uint24
|
||
|
|
sequenceIndex utils.Uint24
|
||
|
|
OrderIndex utils.Uint24
|
||
|
|
|
||
|
|
Split bool
|
||
|
|
SplitCount uint32
|
||
|
|
SplitIndex uint32
|
||
|
|
SplitID uint16
|
||
|
|
}
|
||
|
|
|
||
|
|
// Write writes the Packet and its Content to the buffer passed.
|
||
|
|
func (packet *Packet) Write(b *bytes.Buffer) {
|
||
|
|
header := packet.Reliability << 5
|
||
|
|
if packet.Split {
|
||
|
|
header |= SplitFlag
|
||
|
|
}
|
||
|
|
b.WriteByte(header)
|
||
|
|
_ = binary.Write(b, binary.BigEndian, uint16(len(packet.Content))<<3)
|
||
|
|
if packet.reliable() {
|
||
|
|
utils.WriteUint24(b, packet.MessageIndex)
|
||
|
|
}
|
||
|
|
if packet.sequenced() {
|
||
|
|
utils.WriteUint24(b, packet.sequenceIndex)
|
||
|
|
}
|
||
|
|
if packet.sequencedOrOrdered() {
|
||
|
|
utils.WriteUint24(b, packet.OrderIndex)
|
||
|
|
// Order channel, we don't care about this.
|
||
|
|
b.WriteByte(0)
|
||
|
|
}
|
||
|
|
if packet.Split {
|
||
|
|
_ = binary.Write(b, binary.BigEndian, packet.SplitCount)
|
||
|
|
_ = binary.Write(b, binary.BigEndian, packet.SplitID)
|
||
|
|
_ = binary.Write(b, binary.BigEndian, packet.SplitIndex)
|
||
|
|
}
|
||
|
|
b.Write(packet.Content)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Read reads a Packet and its Content from the buffer passed.
|
||
|
|
func (packet *Packet) Read(b *bytes.Buffer) error {
|
||
|
|
header, err := b.ReadByte()
|
||
|
|
if err != nil {
|
||
|
|
return fmt.Errorf("error reading Packet header: %v", err)
|
||
|
|
}
|
||
|
|
packet.Split = (header & SplitFlag) != 0
|
||
|
|
packet.Reliability = (header & 224) >> 5
|
||
|
|
var packetLength uint16
|
||
|
|
if err := binary.Read(b, binary.BigEndian, &packetLength); err != nil {
|
||
|
|
return fmt.Errorf("error reading Packet length: %v", err)
|
||
|
|
}
|
||
|
|
packetLength >>= 3
|
||
|
|
if packetLength == 0 {
|
||
|
|
return fmt.Errorf("invalid Packet length: cannot be 0")
|
||
|
|
}
|
||
|
|
|
||
|
|
if packet.reliable() {
|
||
|
|
packet.MessageIndex, err = utils.ReadUint24(b)
|
||
|
|
if err != nil {
|
||
|
|
return fmt.Errorf("error reading Packet message index: %v", err)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if packet.sequenced() {
|
||
|
|
packet.sequenceIndex, err = utils.ReadUint24(b)
|
||
|
|
if err != nil {
|
||
|
|
return fmt.Errorf("error reading Packet sequence index: %v", err)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if packet.sequencedOrOrdered() {
|
||
|
|
packet.OrderIndex, err = utils.ReadUint24(b)
|
||
|
|
if err != nil {
|
||
|
|
return fmt.Errorf("error reading Packet order index: %v", err)
|
||
|
|
}
|
||
|
|
// Order channel (byte), we don't care about this.
|
||
|
|
b.Next(1)
|
||
|
|
}
|
||
|
|
|
||
|
|
if packet.Split {
|
||
|
|
if err := binary.Read(b, binary.BigEndian, &packet.SplitCount); err != nil {
|
||
|
|
return fmt.Errorf("error reading Packet split count: %v", err)
|
||
|
|
}
|
||
|
|
if err := binary.Read(b, binary.BigEndian, &packet.SplitID); err != nil {
|
||
|
|
return fmt.Errorf("error reading Packet split ID: %v", err)
|
||
|
|
}
|
||
|
|
if err := binary.Read(b, binary.BigEndian, &packet.SplitIndex); err != nil {
|
||
|
|
return fmt.Errorf("error reading Packet split index: %v", err)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
packet.Content = make([]byte, packetLength)
|
||
|
|
if n, err := b.Read(packet.Content); err != nil || n != int(packetLength) {
|
||
|
|
return fmt.Errorf("not enough data in Packet: %v bytes read but need %v", n, packetLength)
|
||
|
|
}
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func (packet *Packet) reliable() bool {
|
||
|
|
switch packet.Reliability {
|
||
|
|
case ReliabilityReliable,
|
||
|
|
ReliabilityReliableOrdered,
|
||
|
|
ReliabilityReliableSequenced:
|
||
|
|
return true
|
||
|
|
}
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
|
||
|
|
func (packet *Packet) sequencedOrOrdered() bool {
|
||
|
|
switch packet.Reliability {
|
||
|
|
case ReliabilityUnreliableSequenced,
|
||
|
|
ReliabilityReliableOrdered,
|
||
|
|
ReliabilityReliableSequenced:
|
||
|
|
return true
|
||
|
|
}
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
|
||
|
|
func (packet *Packet) sequenced() bool {
|
||
|
|
switch packet.Reliability {
|
||
|
|
case ReliabilityUnreliableSequenced,
|
||
|
|
ReliabilityReliableSequenced:
|
||
|
|
return true
|
||
|
|
}
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
|
||
|
|
const (
|
||
|
|
// packetRange indicates a range of packets, followed by the first and the
|
||
|
|
// last Packet in the range.
|
||
|
|
packetRange = iota
|
||
|
|
// packetSingle indicates a single Packet, followed by its sequence number.
|
||
|
|
packetSingle
|
||
|
|
)
|
||
|
|
|
||
|
|
// Acknowledgement is an Acknowledgement Packet that may either be an ACK or a
|
||
|
|
// NACK, depending on the purpose that it is sent with.
|
||
|
|
type Acknowledgement struct {
|
||
|
|
Packets []utils.Uint24
|
||
|
|
}
|
||
|
|
|
||
|
|
// Write encodes an Acknowledgement Packet and returns an error if not
|
||
|
|
// successful.
|
||
|
|
func (ack *Acknowledgement) Write(b *bytes.Buffer, mtu uint16) (n int, err error) {
|
||
|
|
packets := ack.Packets
|
||
|
|
if len(packets) == 0 {
|
||
|
|
return 0, binary.Write(b, binary.BigEndian, int16(0))
|
||
|
|
}
|
||
|
|
buffer := bytes.NewBuffer(nil)
|
||
|
|
// Sort packets before encoding to ensure packets are encoded correctly.
|
||
|
|
sort.Slice(packets, func(i, j int) bool {
|
||
|
|
return packets[i] < packets[j]
|
||
|
|
})
|
||
|
|
|
||
|
|
var firstPacketInRange utils.Uint24
|
||
|
|
var lastPacketInRange utils.Uint24
|
||
|
|
var recordCount int16
|
||
|
|
|
||
|
|
for index, packet := range packets {
|
||
|
|
if buffer.Len() >= int(mtu-10) {
|
||
|
|
// We must make sure the final Packet length doesn't exceed the MTU
|
||
|
|
// size.
|
||
|
|
break
|
||
|
|
}
|
||
|
|
n++
|
||
|
|
if index == 0 {
|
||
|
|
// The first Packet, set the first and last Packet to it.
|
||
|
|
firstPacketInRange = packet
|
||
|
|
lastPacketInRange = packet
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
if packet == lastPacketInRange+1 {
|
||
|
|
// Packet is still part of the current range, as it's sequenced
|
||
|
|
// properly with the last Packet. Set the last Packet in range to
|
||
|
|
// the Packet and continue to the next Packet.
|
||
|
|
lastPacketInRange = packet
|
||
|
|
continue
|
||
|
|
} else {
|
||
|
|
// We got to the end of a range/single Packet. We need to write
|
||
|
|
// those down now.
|
||
|
|
if firstPacketInRange == lastPacketInRange {
|
||
|
|
// First Packet equals last Packet, so we have a single Packet
|
||
|
|
// record. Write down the Packet, and set the first and last
|
||
|
|
// Packet to the current Packet.
|
||
|
|
if err := buffer.WriteByte(packetSingle); err != nil {
|
||
|
|
return 0, err
|
||
|
|
}
|
||
|
|
utils.WriteUint24(buffer, firstPacketInRange)
|
||
|
|
|
||
|
|
firstPacketInRange = packet
|
||
|
|
lastPacketInRange = packet
|
||
|
|
} else {
|
||
|
|
// There's a gap between the first and last Packet, so we have a
|
||
|
|
// range of packets. Write the first and last Packet of the
|
||
|
|
// range and set both to the current Packet.
|
||
|
|
if err := buffer.WriteByte(packetRange); err != nil {
|
||
|
|
return 0, err
|
||
|
|
}
|
||
|
|
utils.WriteUint24(buffer, firstPacketInRange)
|
||
|
|
utils.WriteUint24(buffer, lastPacketInRange)
|
||
|
|
|
||
|
|
firstPacketInRange = packet
|
||
|
|
lastPacketInRange = packet
|
||
|
|
}
|
||
|
|
// Keep track of the amount of records as we need to write that
|
||
|
|
// first.
|
||
|
|
recordCount++
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Make sure the last single Packet/range is written, as we always need to
|
||
|
|
// know one Packet ahead to know how we should write the current.
|
||
|
|
if firstPacketInRange == lastPacketInRange {
|
||
|
|
if err := buffer.WriteByte(packetSingle); err != nil {
|
||
|
|
return 0, err
|
||
|
|
}
|
||
|
|
utils.WriteUint24(buffer, firstPacketInRange)
|
||
|
|
} else {
|
||
|
|
if err := buffer.WriteByte(packetRange); err != nil {
|
||
|
|
return 0, err
|
||
|
|
}
|
||
|
|
utils.WriteUint24(buffer, firstPacketInRange)
|
||
|
|
utils.WriteUint24(buffer, lastPacketInRange)
|
||
|
|
}
|
||
|
|
recordCount++
|
||
|
|
if err := binary.Write(b, binary.BigEndian, recordCount); err != nil {
|
||
|
|
return 0, err
|
||
|
|
}
|
||
|
|
if _, err := b.Write(buffer.Bytes()); err != nil {
|
||
|
|
return 0, err
|
||
|
|
}
|
||
|
|
return n, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// Read decodes an Acknowledgement Packet and returns an error if not
|
||
|
|
// successful.
|
||
|
|
func (ack *Acknowledgement) Read(b *bytes.Buffer) error {
|
||
|
|
const maxAcknowledgementPackets = 8192
|
||
|
|
var recordCount int16
|
||
|
|
if err := binary.Read(b, binary.BigEndian, &recordCount); err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
for i := int16(0); i < recordCount; i++ {
|
||
|
|
recordType, err := b.ReadByte()
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
switch recordType {
|
||
|
|
case packetRange:
|
||
|
|
start, err := utils.ReadUint24(b)
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
end, err := utils.ReadUint24(b)
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
for pack := start; pack <= end; pack++ {
|
||
|
|
ack.Packets = append(ack.Packets, pack)
|
||
|
|
if len(ack.Packets) > maxAcknowledgementPackets {
|
||
|
|
return fmt.Errorf("maximum amount of packets in acknowledgement exceeded")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
case packetSingle:
|
||
|
|
packet, err := utils.ReadUint24(b)
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
ack.Packets = append(ack.Packets, packet)
|
||
|
|
if len(ack.Packets) > maxAcknowledgementPackets {
|
||
|
|
return fmt.Errorf("maximum amount of packets in acknowledgement exceeded")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return nil
|
||
|
|
}
|