nex-go/packet_v0.go

226 lines
5.9 KiB
Go

package nex
import (
"bytes"
"crypto/hmac"
"crypto/md5"
"encoding/binary"
"encoding/hex"
"fmt"
)
func decodePacketV0(PRUDPPacket *Packet) map[string]interface{} {
checksumVersion := PRUDPPacket.Sender.Server.Settings.PrudpV0ChecksumVersion
checksumSize := 1
if checksumVersion == 0 {
checksumSize = 4
}
stream := NewInputStream(PRUDPPacket.Data)
source := stream.UInt8()
destination := stream.UInt8()
typeFlags := stream.UInt16LE()
sessionID := stream.UInt8()
signature := stream.Bytes(4)
sequenceID := stream.UInt16LE()
sourceType := source >> 4
sourcePort := source & 0xF
destinationType := destination >> 4
destinationPort := destination & 0xF
var packetType uint16
var flags uint16
if PRUDPPacket.Sender.Server.Settings.PrudpV0FlagsVersion == 0 {
packetType = typeFlags & 7
flags = typeFlags >> 3
} else {
packetType = typeFlags & 0xF
flags = typeFlags >> 4
}
decoded := map[string]interface{}{
"Source": source,
"Destination": destination,
"SourceType": sourceType,
"SourcePort": sourcePort,
"DestinationType": destinationType,
"DestinationPort": destinationPort,
"SequenceID": sequenceID,
"SessionID": sessionID,
"Flags": flags,
"Type": packetType,
"FragmentID": 0,
"Signature": signature,
"Payload": []byte{},
}
if packetType == Types["Syn"] || packetType == Types["Connect"] {
decoded["Signature"] = stream.Bytes(4)
}
if packetType == Types["Data"] {
decoded["FragmentID"] = int(stream.UInt8())
}
var payloadSize uint16
if flags&Flags["HasSize"] != 0 {
payloadSize = stream.UInt16LE()
} else {
payloadSize = uint16(len(stream.data) - stream.pos - checksumSize)
}
payload := stream.Bytes(int(payloadSize))
decoded["Payload"] = payload
if packetType == Types["Data"] && len(payload) > 0 {
crypted := make([]byte, len(payload))
PRUDPPacket.Sender.Decipher.XORKeyStream(crypted, payload)
request := NewRMCRequest(crypted)
decoded["RMCRequest"] = request
}
var checksum int
if checksumSize == 1 {
checksum = int(stream.UInt8())
} else {
checksum = int(stream.UInt32LE())
}
decoded["Checksum"] = checksum
if CalculateV0Checksum(PRUDPPacket.Sender.SignatureBase, stream.data[:len(stream.data)-checksumSize], checksumVersion) != checksum {
fmt.Println("[ERROR] Calculated checksum does not match decoded checksum!")
}
return decoded
}
func encodePacketV0(PRUDPPacket *Packet) []byte {
checksumVersion := PRUDPPacket.Sender.Server.Settings.PrudpV0ChecksumVersion
if PRUDPPacket.Type == Types["Data"] && len(PRUDPPacket.Payload) > 0 {
crypted := make([]byte, len(PRUDPPacket.Payload))
PRUDPPacket.Sender.Cipher.XORKeyStream(crypted, PRUDPPacket.Payload)
PRUDPPacket.Payload = crypted
}
stream := NewOutputStream()
options := encodeOptionsV0(PRUDPPacket)
stream.UInt8(PRUDPPacket.Source)
stream.UInt8(PRUDPPacket.Destination)
stream.UInt16LE(PRUDPPacket.Type | PRUDPPacket.Flags<<4)
stream.UInt8(uint8(PRUDPPacket.Sender.SessionID))
stream.Write(CalculateV0Signature(PRUDPPacket))
stream.UInt16LE(PRUDPPacket.SequenceID)
stream.Write(options)
stream.Write(PRUDPPacket.Payload)
stream.UInt8(uint8(CalculateV0Checksum(PRUDPPacket.Sender.SignatureBase, stream.Bytes(), checksumVersion)))
return stream.Bytes()
}
// CalculateV0Checksum calculates the checksum of a prudpv0 packet
//
// Parameters:
// checksum: the base checksum for the packet
// packet: the packet to calculate the checksum of
// version: the version to calculate the checksum off of (unused)
//
// Returns:
// the calculated checksum of the provided packet
func CalculateV0Checksum(checksum int, packet []byte, version int) int {
// in the future we need to check the `version` here and change the alg accordingly
pos := 0
sections := len(packet) / 4
chunks := make([]uint32, 0, sections)
for i := 0; i < sections; i++ {
chunk := binary.LittleEndian.Uint32(packet[pos : pos+4])
chunks = append(chunks, chunk)
pos += 4
}
temp1 := sum(chunks)
temp := temp1 & 0xFFFFFFFF
buff := make([]byte, 4)
binary.LittleEndian.PutUint32(buff, uint32(temp))
tempSum := sum(packet[len(packet) & ^3:])
checksum += tempSum
tempSum = sum(buff)
checksum += tempSum
return (checksum & 0xFF)
}
func encodeOptionsV0(PRUDPPacket *Packet) []byte {
stream := NewOutputStream()
if PRUDPPacket.Type == Types["Syn"] || PRUDPPacket.Type == Types["Connect"] {
stream.Write(PRUDPPacket.Signature)
}
if PRUDPPacket.Type == Types["Data"] {
stream.UInt8(uint8(PRUDPPacket.FragmentID))
}
if PRUDPPacket.HasFlag(Flags["HasSize"]) {
stream.UInt16LE(uint16(len(PRUDPPacket.Payload)))
}
return stream.Bytes()
}
// CalculateV0Signature calculates the signature of a prudpv0 packet
//
// Parameters:
// PRUDPPacket: the packet to calculate the signature of
//
// Returns:
// the calculated signature of the provided packet
func CalculateV0Signature(PRUDPPacket *Packet) []byte {
if PRUDPPacket.Type == Types["Data"] || (PRUDPPacket.Type == Types["Disconnect"] && PRUDPPacket.Sender.Server.Settings.PrudpV0SignatureVersion == 0) {
data := PRUDPPacket.Payload
if PRUDPPacket.Sender.Server.Settings.PrudpV0SignatureVersion == 0 {
length := len(PRUDPPacket.Sender.SecureKey) + 2 + 1 + len(data)
buffer := bytes.NewBuffer(make([]byte, 0, length))
binary.Write(buffer, binary.LittleEndian, PRUDPPacket.Sender.SecureKey)
binary.Write(buffer, binary.LittleEndian, uint16(PRUDPPacket.SequenceID))
binary.Write(buffer, binary.LittleEndian, uint8(PRUDPPacket.FragmentID))
binary.Write(buffer, binary.LittleEndian, data)
data = buffer.Bytes()
}
if len(data) > 0 {
key, _ := hex.DecodeString(PRUDPPacket.Sender.SignatureKey)
cipher := hmac.New(md5.New, key)
cipher.Write(data)
return cipher.Sum(nil)[:4]
}
buffer := bytes.NewBuffer(make([]byte, 0, 4))
binary.Write(buffer, binary.LittleEndian, uint32(0x12345678))
return buffer.Bytes()
}
if PRUDPPacket.Signature != nil {
return PRUDPPacket.Signature
}
return make([]byte, 4)
}