mirror of
https://github.com/XTLS/Xray-core.git
synced 2026-09-24 01:50:26 +00:00
https://github.com/XTLS/Xray-core/pull/6210#issuecomment-4573680059 https://github.com/XTLS/Xray-core/pull/6210#issuecomment-4582554889 https://github.com/XTLS/Xray-core/pull/6210#issuecomment-4937008835
336 lines
6.1 KiB
Go
336 lines
6.1 KiB
Go
// Minecraft protocol
|
|
package xmc
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
)
|
|
|
|
type field interface {
|
|
readFrom(r io.Reader) error
|
|
writeTo(w io.Writer) error
|
|
}
|
|
|
|
type mcPacket struct {
|
|
packetID int
|
|
data []byte
|
|
}
|
|
|
|
func readPacket(b io.Reader) (*mcPacket, error) {
|
|
var packetLength Varint
|
|
err := packetLength.readFrom(b)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("read packet length: %w", err)
|
|
}
|
|
|
|
var packetID Varint
|
|
err = packetID.readFrom(b)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("read packet ID: %w", err)
|
|
}
|
|
|
|
dataLength := int(packetLength) - varintSize(packetID)
|
|
if dataLength < 0 || dataLength > 1024*32 {
|
|
return nil, fmt.Errorf("read packet: bad length: %d", dataLength)
|
|
}
|
|
|
|
data := make([]byte, dataLength)
|
|
_, err = io.ReadFull(b, data)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("read packet data: %w", err)
|
|
}
|
|
|
|
return &mcPacket{
|
|
packetID: int(packetID),
|
|
data: data,
|
|
}, nil
|
|
}
|
|
|
|
func (p *mcPacket) readFields(fields ...field) error {
|
|
r := bytes.NewReader(p.data)
|
|
|
|
for _, field := range fields {
|
|
err := field.readFrom(r)
|
|
if err != nil {
|
|
return fmt.Errorf("read packet field: %w", err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
type Varint int32
|
|
|
|
func (v *Varint) readFrom(r io.Reader) error {
|
|
SEGMENT_BITS := byte(0x7F)
|
|
CONTINUE_BIT := byte(0x80)
|
|
|
|
var err error
|
|
|
|
var value int32 = 0
|
|
var position int32 = 0
|
|
var currentByte byte
|
|
|
|
for true {
|
|
currentByte, err = readByte(r)
|
|
if err != nil {
|
|
return fmt.Errorf("read varint: %w", err)
|
|
}
|
|
value |= int32(currentByte&SEGMENT_BITS) << position
|
|
|
|
if (currentByte & CONTINUE_BIT) == 0 {
|
|
break
|
|
}
|
|
|
|
position += 7
|
|
|
|
if position >= 32 {
|
|
return fmt.Errorf("read varint: too large")
|
|
}
|
|
}
|
|
|
|
*v = Varint(value)
|
|
|
|
return nil
|
|
}
|
|
|
|
func (v *Varint) writeTo(w io.Writer) error {
|
|
SEGMENT_BITS := byte(0x7F)
|
|
CONTINUE_BIT := byte(0x80)
|
|
|
|
value := int32(*v)
|
|
|
|
for {
|
|
currentByte := byte(value & int32(SEGMENT_BITS))
|
|
value >>= 7
|
|
if value != 0 {
|
|
currentByte |= CONTINUE_BIT
|
|
}
|
|
|
|
_, err := w.Write([]byte{currentByte})
|
|
if err != nil {
|
|
return fmt.Errorf("write varint: %w", err)
|
|
}
|
|
|
|
if value == 0 {
|
|
break
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func varintSize(value Varint) int {
|
|
size := 0
|
|
for {
|
|
size++
|
|
value >>= 7
|
|
if value == 0 {
|
|
break
|
|
}
|
|
}
|
|
return size
|
|
}
|
|
|
|
type String string
|
|
|
|
func (v *String) readFrom(r io.Reader) error {
|
|
var length Varint = 0
|
|
|
|
err := length.readFrom(r)
|
|
if err != nil {
|
|
return fmt.Errorf("read string: %w", err)
|
|
}
|
|
|
|
if length < 0 || length > 4096 {
|
|
return fmt.Errorf("read string: bad length: %d", length)
|
|
}
|
|
|
|
buf := make([]byte, length)
|
|
_, err = io.ReadFull(r, buf)
|
|
if err != nil {
|
|
return fmt.Errorf("read string: %w", err)
|
|
}
|
|
|
|
*v = String(string(buf))
|
|
|
|
return nil
|
|
}
|
|
|
|
func (v *String) writeTo(w io.Writer) error {
|
|
strBytes := []byte(*v)
|
|
length := Varint(len(strBytes))
|
|
|
|
err := length.writeTo(w)
|
|
if err != nil {
|
|
return fmt.Errorf("write string: %w", err)
|
|
}
|
|
|
|
_, err = w.Write(strBytes)
|
|
if err != nil {
|
|
return fmt.Errorf("write string: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
type UnsignedShort uint16
|
|
|
|
func (v *UnsignedShort) readFrom(r io.Reader) error {
|
|
var buf [2]byte
|
|
_, err := io.ReadFull(r, buf[:])
|
|
if err != nil {
|
|
return fmt.Errorf("read unsigned short: %w", err)
|
|
}
|
|
|
|
*v = UnsignedShort(buf[0])<<8 | UnsignedShort(buf[1])
|
|
|
|
return nil
|
|
}
|
|
|
|
func (v *UnsignedShort) writeTo(w io.Writer) error {
|
|
buf := []byte{byte(*v >> 8), byte(*v & 0xFF)}
|
|
_, err := w.Write(buf)
|
|
if err != nil {
|
|
return fmt.Errorf("write unsigned short: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type Long int64
|
|
|
|
func (v *Long) readFrom(r io.Reader) error {
|
|
var buf [8]byte
|
|
_, err := io.ReadFull(r, buf[:])
|
|
if err != nil {
|
|
return fmt.Errorf("read long: %w", err)
|
|
}
|
|
|
|
*v = Long(buf[0])<<56 | Long(buf[1])<<48 | Long(buf[2])<<40 | Long(buf[3])<<32 |
|
|
Long(buf[4])<<24 | Long(buf[5])<<16 | Long(buf[6])<<8 | Long(buf[7])
|
|
|
|
return nil
|
|
}
|
|
|
|
func (v *Long) writeTo(w io.Writer) error {
|
|
buf := []byte{
|
|
byte(*v >> 56), byte((*v >> 48) & 0xFF), byte((*v >> 40) & 0xFF), byte((*v >> 32) & 0xFF),
|
|
byte((*v >> 24) & 0xFF), byte((*v >> 16) & 0xFF), byte((*v >> 8) & 0xFF), byte(*v & 0xFF),
|
|
}
|
|
|
|
_, err := w.Write(buf)
|
|
if err != nil {
|
|
return fmt.Errorf("write long: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
type UUID [16]byte
|
|
|
|
func (v *UUID) readFrom(r io.Reader) error {
|
|
_, err := io.ReadFull(r, v[:])
|
|
if err != nil {
|
|
return fmt.Errorf("read UUID: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (v *UUID) writeTo(w io.Writer) error {
|
|
_, err := w.Write(v[:])
|
|
if err != nil {
|
|
return fmt.Errorf("write UUID: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type Bytes []byte
|
|
|
|
func (v *Bytes) readFrom(r io.Reader) error {
|
|
var length Varint
|
|
err := length.readFrom(r)
|
|
if err != nil {
|
|
return fmt.Errorf("read bytes: %w", err)
|
|
}
|
|
|
|
if length < 0 || length >= 1024 {
|
|
return fmt.Errorf("read bytes: invalid size: %d", err)
|
|
}
|
|
|
|
buf := make([]byte, length)
|
|
|
|
_, err = io.ReadFull(r, buf)
|
|
if err != nil {
|
|
return fmt.Errorf("read bytes: %w", err)
|
|
}
|
|
|
|
*v = append([]byte(*v), buf...)
|
|
|
|
return nil
|
|
}
|
|
|
|
func (v *Bytes) writeTo(w io.Writer) error {
|
|
length := Varint(len(*v))
|
|
err := length.writeTo(w)
|
|
if err != nil {
|
|
return fmt.Errorf("write bytes length: %w", err)
|
|
}
|
|
|
|
_, err = w.Write(*v)
|
|
if err != nil {
|
|
return fmt.Errorf("write bytes: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func readByte(r io.Reader) (byte, error) {
|
|
var buf [1]byte
|
|
_, err := io.ReadFull(r, buf[:])
|
|
if err != nil {
|
|
return 0, fmt.Errorf("read byte: %w", err)
|
|
}
|
|
|
|
return buf[0], nil
|
|
}
|
|
|
|
func writePacket(w io.Writer, packetID int, fields ...field) error {
|
|
var dataBuf bytes.Buffer
|
|
|
|
for _, field := range fields {
|
|
err := field.writeTo(&dataBuf)
|
|
if err != nil {
|
|
return fmt.Errorf("write packet field: %w", err)
|
|
}
|
|
}
|
|
|
|
var buf bytes.Buffer
|
|
|
|
var packetLength Varint = Varint(varintSize(Varint(packetID)) + dataBuf.Len())
|
|
err := packetLength.writeTo(&buf)
|
|
if err != nil {
|
|
return fmt.Errorf("write packet length: %w", err)
|
|
}
|
|
|
|
var packetIDVarint Varint = Varint(packetID)
|
|
err = packetIDVarint.writeTo(&buf)
|
|
if err != nil {
|
|
return fmt.Errorf("write packet ID: %w", err)
|
|
}
|
|
|
|
buf.Write(dataBuf.Bytes())
|
|
|
|
_, err = w.Write(buf.Bytes())
|
|
if err != nil {
|
|
return fmt.Errorf("write packet data: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func writeDisconnectPacket(w io.Writer, reason string) error {
|
|
return writePacket(w, 0x00, new(String(reason)))
|
|
}
|