122 lines
2.8 KiB
Go
122 lines
2.8 KiB
Go
package sbproxy
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/binary"
|
|
"encoding/json"
|
|
"io"
|
|
"net"
|
|
|
|
"github.com/sagernet/sing-box/adapter"
|
|
N "github.com/sagernet/sing/common/network"
|
|
)
|
|
|
|
func (h *Inbound) handleJavaConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) {
|
|
_, _, err := ReadVarInt(conn) // packet len
|
|
if err != nil {
|
|
conn.Close()
|
|
return
|
|
}
|
|
packetID, _, err := ReadVarInt(conn)
|
|
if err != nil || packetID != 0x00 {
|
|
conn.Close()
|
|
return
|
|
}
|
|
|
|
ReadVarInt(conn) // protocol version
|
|
ReadString(conn) // server address
|
|
binary.Read(conn, binary.BigEndian, new(uint16))
|
|
nextState, _, _ := ReadVarInt(conn)
|
|
|
|
switch nextState {
|
|
case 1: // Status
|
|
h.handleJavaStatus(conn)
|
|
case 2: // Login
|
|
h.handleJavaLogin(ctx, conn, metadata, onClose)
|
|
default:
|
|
conn.Close()
|
|
}
|
|
}
|
|
|
|
func (h *Inbound) handleJavaStatus(conn net.Conn) {
|
|
for {
|
|
packetLen, _, err := ReadVarInt(conn)
|
|
if err != nil {
|
|
return
|
|
}
|
|
packetID, _, err := ReadVarInt(conn)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
if packetID == 0x00 { // Status Request
|
|
motd := h.options.MOTD
|
|
if motd == "" {
|
|
motd = "A Minecraft Server"
|
|
}
|
|
ver := h.options.Version
|
|
if ver == "" {
|
|
ver = "1.20.1"
|
|
}
|
|
|
|
resp := map[string]any{
|
|
"version": map[string]any{"name": ver, "protocol": 763},
|
|
"players": map[string]any{"max": h.options.MaxPlayers, "online": 0, "sample": []any{}},
|
|
"description": map[string]any{"text": motd},
|
|
}
|
|
data, _ := json.Marshal(resp)
|
|
|
|
var body bytes.Buffer
|
|
WriteVarInt(&body, 0x00) // Response ID
|
|
WriteString(&body, string(data))
|
|
|
|
WriteVarInt(conn, int32(body.Len()))
|
|
conn.Write(body.Bytes())
|
|
} else if packetID == 0x01 { // Ping
|
|
var b [8]byte
|
|
if _, err := io.ReadFull(conn, b[:]); err != nil {
|
|
return
|
|
}
|
|
|
|
var body bytes.Buffer
|
|
WriteVarInt(&body, 0x01)
|
|
body.Write(b[:])
|
|
|
|
WriteVarInt(conn, int32(body.Len()))
|
|
conn.Write(body.Bytes())
|
|
return
|
|
} else {
|
|
io.CopyN(io.Discard, conn, int64(packetLen)-1)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (h *Inbound) handleJavaLogin(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) {
|
|
// Login Start
|
|
_, _, err := ReadVarInt(conn)
|
|
if err != nil {
|
|
conn.Close()
|
|
return
|
|
}
|
|
packetID, _, err := ReadVarInt(conn)
|
|
if err != nil || packetID != 0x00 {
|
|
conn.Close()
|
|
return
|
|
}
|
|
user, _ := ReadString(conn)
|
|
|
|
// Offline Mode: No encryption/auth sequence, just Login Success
|
|
var loginSuccess bytes.Buffer
|
|
WriteVarInt(&loginSuccess, 0x02) // Login Success ID
|
|
// UUID (offline)
|
|
loginSuccess.Write(make([]byte, 16))
|
|
WriteString(&loginSuccess, user)
|
|
WriteVarInt(&loginSuccess, 0) // No properties
|
|
|
|
WriteVarInt(conn, int32(loginSuccess.Len()))
|
|
conn.Write(loginSuccess.Bytes())
|
|
|
|
h.handlePlay(ctx, conn, user, metadata, onClose)
|
|
}
|