Phase8
This commit is contained in:
174
apps/edge-gateway/internal/mc/handshake.go
Normal file
174
apps/edge-gateway/internal/mc/handshake.go
Normal file
@@ -0,0 +1,174 @@
|
||||
package mc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Handshake struct {
|
||||
ProtocolVersion int32
|
||||
ServerAddress string
|
||||
ServerPort uint16
|
||||
NextState int32
|
||||
Raw []byte
|
||||
}
|
||||
|
||||
func ReadHandshake(r io.Reader) (*Handshake, error) {
|
||||
raw, err := readPacket(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
reader := newReader(raw)
|
||||
packetID, err := reader.readVarInt()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if packetID != 0 {
|
||||
return nil, fmt.Errorf("unexpected packet id %d", packetID)
|
||||
}
|
||||
|
||||
protocolVersion, err := reader.readVarInt()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
serverAddress, err := reader.readString()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
portBytes, err := reader.readBytes(2)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
serverPort := binary.BigEndian.Uint16(portBytes)
|
||||
|
||||
nextState, err := reader.readVarInt()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Handshake{
|
||||
ProtocolVersion: protocolVersion,
|
||||
ServerAddress: serverAddress,
|
||||
ServerPort: serverPort,
|
||||
NextState: nextState,
|
||||
Raw: raw,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func ExtractSlug(hostname, playDomain string) string {
|
||||
host := strings.ToLower(strings.Split(hostname, "\x00")[0])
|
||||
domain := strings.ToLower(playDomain)
|
||||
suffix := "." + domain
|
||||
if !strings.HasSuffix(host, suffix) {
|
||||
return ""
|
||||
}
|
||||
slug := strings.TrimSuffix(host, suffix)
|
||||
if slug == "" || strings.Contains(slug, ".") {
|
||||
return ""
|
||||
}
|
||||
return slug
|
||||
}
|
||||
|
||||
func readPacket(r io.Reader) ([]byte, error) {
|
||||
length, err := readVarIntFrom(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if length <= 0 || length > 1<<20 {
|
||||
return nil, fmt.Errorf("invalid packet length %d", length)
|
||||
}
|
||||
|
||||
payload := make([]byte, length)
|
||||
if _, err := io.ReadFull(r, payload); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return payload, nil
|
||||
}
|
||||
|
||||
type packetReader struct {
|
||||
buf *bytes.Reader
|
||||
}
|
||||
|
||||
func newReader(data []byte) *packetReader {
|
||||
return &packetReader{buf: bytes.NewReader(data)}
|
||||
}
|
||||
|
||||
func (p *packetReader) readVarInt() (int32, error) {
|
||||
return readVarIntFrom(p.buf)
|
||||
}
|
||||
|
||||
func (p *packetReader) readString() (string, error) {
|
||||
length, err := p.readVarInt()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if length < 0 || length > 255 {
|
||||
return "", fmt.Errorf("invalid string length %d", length)
|
||||
}
|
||||
data, err := p.readBytes(int(length))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(data), nil
|
||||
}
|
||||
|
||||
func (p *packetReader) readBytes(n int) ([]byte, error) {
|
||||
out := make([]byte, n)
|
||||
if _, err := io.ReadFull(p.buf, out); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func readVarIntFrom(r io.Reader) (int32, error) {
|
||||
var numRead int
|
||||
var result int32
|
||||
|
||||
for {
|
||||
var value [1]byte
|
||||
if _, err := io.ReadFull(r, value[:]); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
result |= int32(value[0]&0x7F) << (7 * numRead)
|
||||
numRead++
|
||||
if numRead > 5 {
|
||||
return 0, fmt.Errorf("varint too big")
|
||||
}
|
||||
if value[0]&0x80 == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func WritePacket(w io.Writer, payload []byte) error {
|
||||
if err := writeVarIntTo(w, int32(len(payload))); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := w.Write(payload)
|
||||
return err
|
||||
}
|
||||
|
||||
func writeVarIntTo(w io.Writer, value int32) error {
|
||||
for {
|
||||
temp := byte(value & 0x7F)
|
||||
value >>= 7
|
||||
if value != 0 {
|
||||
temp |= 0x80
|
||||
}
|
||||
if _, err := w.Write([]byte{temp}); err != nil {
|
||||
return err
|
||||
}
|
||||
if value == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user