Files
Xray-core/transport/internet/finalmask/xmc/server.go
T

365 lines
8.6 KiB
Go

package xmc
import (
"bufio"
"bytes"
"crypto/rand"
"crypto/rsa"
"crypto/subtle"
"crypto/x509"
"fmt"
"io"
"net"
"sync"
"time"
)
// Response by vanilla 26.1.2 server.
var statusResponse = `{"description":"A Minecraft Server","players":{"max":20,"online":0},"version":{"name":"26.1.2","protocol":775},"enforcesSecureChat":true}`
type serverState int
var (
serverStateHandshake serverState = 1
serverStateProxy serverState = 3
)
type serverConn struct {
reader io.Reader
writer io.Writer
c net.Conn
state serverState
handshakeLock sync.Mutex
lifecycleMu sync.Mutex
closed bool
profiles []loginProfile
password string
rsaPrivateKey *rsa.PrivateKey
rsaPublicKey []byte
paddingSchedule []paddingTurn
packet *packetStream
deadlines *connectionDeadlines
}
func (c *serverConn) handshake() error {
c.handshakeLock.Lock()
defer c.handshakeLock.Unlock()
if c.state != serverStateHandshake {
return nil
}
if err := c.deadlines.beginHandshake(); err != nil {
return fmt.Errorf("set deadline: %w", err)
}
defer func() { _ = c.deadlines.endHandshake() }()
var (
protocolVersion Varint
serverAddress String
serverPort UnsignedShort
nextState Varint
)
// handshake packet
pkt, err := readPacket(c.reader)
if err != nil {
return fmt.Errorf("read handshake packet: %w", err)
}
if pkt.packetID != 0 {
return fmt.Errorf("bad handshake packet id")
}
err = pkt.readFields(&protocolVersion, &serverAddress, &serverPort, &nextState)
if err != nil {
return fmt.Errorf("read handshake packet: %w", err)
}
switch nextState {
case 1:
// Ping
for range 2 {
pkt, err := readPacket(c.reader)
if err != nil {
return fmt.Errorf("read packet: %w", err)
}
switch pkt.packetID {
case 0: // Status Request
err = writePacket(c.writer, 0, new(String(statusResponse)))
if err != nil {
return fmt.Errorf("write status response: %w", err)
}
case 1: // Ping
var payload Long
err = pkt.readFields(&payload)
if err != nil {
return fmt.Errorf("read ping packet: %w", err)
}
err = writePacket(c.writer, 1, &payload)
if err != nil {
return fmt.Errorf("write ping response: %w", err)
}
}
}
return fmt.Errorf("ping")
case 2:
// Login
// login start
pkt, err := readPacket(c.reader)
if err != nil {
return fmt.Errorf("read login start packet: %w", err)
}
if pkt.packetID != 0 {
return fmt.Errorf("bad login start packet id")
}
var (
username String
uuid UUID
)
err = pkt.readFields(&username, &uuid)
if err != nil {
return fmt.Errorf("read login start packet: %w", err)
}
profile, found := findProfile(c.profiles, string(username), uuid)
// encrypt request
var (
serverId String = String("")
publicKey Bytes = Bytes(c.rsaPublicKey)
verifyToken Bytes = Bytes(make([]byte, 4))
shouldAuthenticate Boolean = true
)
if _, err = rand.Read(verifyToken); err != nil {
return fmt.Errorf("generate verify token: %w", err)
}
err = writePacket(c.writer, 0x01, &serverId, &publicKey, &verifyToken, &shouldAuthenticate)
if err != nil {
return fmt.Errorf("write encryption request: %w", err)
}
// encrypt response
var (
encryptedSharedSecret Bytes
encryptedVerifyToken Bytes
sharedSecret []byte
decryptedVerifyToken []byte
)
pkt, err = readPacket(c.reader)
if err != nil {
return fmt.Errorf("read encrypt response: %w", err)
}
if pkt.packetID != 0x01 {
return fmt.Errorf("bad encrypt response packet id")
}
err = pkt.readFields(&encryptedSharedSecret, &encryptedVerifyToken)
if err != nil {
return fmt.Errorf("read encrypt response: %w", err)
}
sharedSecret, err = rsa.DecryptPKCS1v15(rand.Reader, c.rsaPrivateKey, encryptedSharedSecret)
if err != nil {
return fmt.Errorf("decrypt shared secret: %w", err)
}
if len(sharedSecret) != 16 {
return fmt.Errorf("bad shared secret length: %d", len(sharedSecret))
}
decryptedVerifyToken, err = rsa.DecryptPKCS1v15(rand.Reader, c.rsaPrivateKey, encryptedVerifyToken)
if err != nil {
return fmt.Errorf("decrypt verify token: %w", err)
}
if len(decryptedVerifyToken) < 4 || !bytes.Equal(verifyToken, decryptedVerifyToken[:4]) {
return fmt.Errorf("verify token mismatch")
}
c.reader, err = newCryptoReader(c.reader, sharedSecret)
if err != nil {
return fmt.Errorf("new crypto reader: %w", err)
}
c.writer, err = newCryptoWriter(c.writer, sharedSecret)
if err != nil {
return fmt.Errorf("new crypto writer: %w", err)
}
// verify password
receivedPassword := decryptedVerifyToken[4:]
if subtle.ConstantTimeCompare(receivedPassword, []byte(c.password)) != 1 {
writeDisconnectPacket(c.writer, `{"type":"translatable","translate":"multiplayer.disconnect.authservers_down"}`)
return fmt.Errorf("bad password")
}
if !found {
if err = writeDisconnectPacket(c.writer, `{"text":"You are not white-listed on this server!"}`); err != nil {
return fmt.Errorf("write unknown login profile disconnect: %w", err)
}
return fmt.Errorf("unknown login profile")
}
loginName := String(profile.Username)
propertyCount := Varint(1)
propertyName := String("textures")
texturesValue := String(profile.TexturesValue)
signed := Boolean(true)
texturesSignature := String(profile.TexturesSignature)
if err = writePacket(c.writer, 0x02, &profile.UUID, &loginName, &propertyCount, &propertyName, &texturesValue, &signed, &texturesSignature); err != nil {
return fmt.Errorf("write login finished: %w", err)
}
var loginAcknowledgedLength int
pkt, loginAcknowledgedLength, err = readPacketWithLength(c.reader)
if err != nil {
return fmt.Errorf("read login acknowledged: %w", err)
}
if err = validateLoginAcknowledgedPacket(pkt); err != nil {
return err
}
if err = runPaddingSchedule(c.reader, c.writer, false, loginAcknowledgedLength, c.paddingSchedule); err != nil {
return fmt.Errorf("run startup padding: %w", err)
}
packet := newPacketStream(c.reader, c.writer, false)
c.lifecycleMu.Lock()
if c.closed {
c.lifecycleMu.Unlock()
packet.Stop()
return net.ErrClosed
}
c.packet = packet
c.reader = packet
c.writer = packet
c.state = serverStateProxy
c.lifecycleMu.Unlock()
return nil
default:
return fmt.Errorf("bad handshake packet: bad next state: %d", nextState)
}
}
func validateLoginAcknowledgedPacket(pkt *mcPacket) error {
if pkt.packetID != 0x03 {
return fmt.Errorf("bad login acknowledged packet id: %d", pkt.packetID)
}
if len(pkt.data) != 0 {
return fmt.Errorf("bad login acknowledged packet data length: %d", len(pkt.data))
}
return nil
}
func (c *serverConn) Read(b []byte) (int, error) {
err := c.handshake()
if err != nil {
return 0, fmt.Errorf("handshake: %w", err)
}
return c.reader.Read(b)
}
func (c *serverConn) Write(b []byte) (int, error) {
err := c.handshake()
if err != nil {
return 0, fmt.Errorf("handshake: %w", err)
}
return c.writer.Write(b)
}
func (c *serverConn) Close() error {
c.lifecycleMu.Lock()
c.closed = true
packet := c.packet
c.lifecycleMu.Unlock()
if packet != nil {
packet.Stop()
}
return c.c.Close()
}
func (c *serverConn) LocalAddr() net.Addr {
return c.c.LocalAddr()
}
func (c *serverConn) RemoteAddr() net.Addr {
return c.c.RemoteAddr()
}
func (c *serverConn) SetDeadline(t time.Time) error {
return c.deadlines.setDeadline(t)
}
func (c *serverConn) SetReadDeadline(t time.Time) error {
return c.deadlines.setReadDeadline(t)
}
func (c *serverConn) SetWriteDeadline(t time.Time) error {
return c.deadlines.setWriteDeadline(t)
}
func wrapConnServer(c net.Conn, profiles []loginProfile, password string, rsaPrivateKeyDER []byte, rsaPublicKey []byte) (*serverConn, error) {
if len(profiles) == 0 {
return nil, fmt.Errorf("empty profiles")
}
if len(rsaPrivateKeyDER) == 0 {
return nil, fmt.Errorf("empty rsa private key")
}
if len(rsaPublicKey) == 0 {
return nil, fmt.Errorf("empty rsa public key")
}
rsaPrivateKey, err := x509.ParsePKCS1PrivateKey(rsaPrivateKeyDER)
if err != nil {
return nil, fmt.Errorf("parse rsa private key: %w", err)
}
paddingSchedule, err := newServerPaddingSchedule2612()
if err != nil {
return nil, fmt.Errorf("select padding profile: %w", err)
}
s := &serverConn{
reader: bufio.NewReader(c),
writer: c,
c: c,
state: serverStateHandshake,
profiles: profiles,
password: password,
rsaPrivateKey: rsaPrivateKey,
rsaPublicKey: rsaPublicKey,
paddingSchedule: paddingSchedule,
deadlines: newConnectionDeadlines(c),
}
return s, nil
}