Skip to content

Commit

Permalink
fix: Minecraft login packet version difference
Browse files Browse the repository at this point in the history
  • Loading branch information
layou233 committed Jul 19, 2024
1 parent 8662e4a commit da6f5b6
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 31 deletions.
4 changes: 4 additions & 0 deletions common/bufio/cached.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ func NewCachedConn(c net.Conn) *CachedConn {
}
}

func (c *CachedConn) Cache() *buf.Buffer {
return c.cache
}

func (c *CachedConn) Read(p []byte) (n int, err error) {
if c.cache != nil && !c.cache.IsEmpty() {
return c.cache.Read(p)
Expand Down
30 changes: 13 additions & 17 deletions protocol/minecraft/outbound.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,9 +201,15 @@ func (o *Outbound) InjectConnection(ctx context.Context, conn *bufio.CachedConn,
}
switch metadata.Minecraft.NextState {
case mcprotocol.NextStateStatus:
// skip Status Request packet
_, err := conn.Peek(2)
if err != nil {
return common.Cause("skip status request: ", err)
}
if o.config.Minecraft.MotdFavicon == "" && o.config.Minecraft.MotdDescription == "" {
// directly proxy MOTD from server
remoteConn, err := o.connectServer(ctx, metadata)
var remoteConn net.Conn
remoteConn, err = o.connectServer(ctx, metadata)
if err != nil {
return common.Cause("request remote MOTD: ", err)
}
Expand Down Expand Up @@ -261,7 +267,7 @@ func (o *Outbound) InjectConnection(ctx context.Context, conn *bufio.CachedConn,
Writer: common.UnwrapWriter(conn), // unwrap to make writev syscall possible
Conn: conn,
}
err := clientMC.WriteVectorizedPacket(buffer, motd)
err = clientMC.WriteVectorizedPacket(buffer, motd)
if err != nil {
return common.Cause("respond MOTD: ", err)
}
Expand Down Expand Up @@ -366,26 +372,16 @@ func (o *Outbound) InjectConnection(ctx context.Context, conn *bufio.CachedConn,
binary.BigEndian.PutUint16(buffer.Extend(2), port)
buffer.WriteByte(mcprotocol.NextStateLogin)
mcprotocol.AppendPacketLength(buffer, buffer.Len())
// construct login packet
loginPacketSize := 2 + len(metadata.Minecraft.PlayerName) // should not exceed 127
hasUUID := false
if metadata.Minecraft.UUID != [16]byte{} { // is not empty
loginPacketSize += 16
hasUUID = true
}
buffer.WriteByte(byte(loginPacketSize))
buffer.WriteByte(0) // Server bound : Login Start
buffer.WriteByte(byte(len(metadata.Minecraft.PlayerName)))
buffer.WriteString(metadata.Minecraft.PlayerName)
if hasUUID {
buffer.Write(metadata.Minecraft.UUID[:])
}
_, err = serverConn.Write(buffer.Bytes())
// write handshake and login packet
cache := conn.Cache()
vector := net.Buffers{buffer.Bytes(), cache.Bytes()}
_, err = vector.WriteTo(serverConn)
buffer.Release()
if err != nil {
serverConn.Close()
return common.Cause("server handshake: ", err)
}
cache.Advance(cache.Len()) // all written
o.logger.Info().Str("id", metadata.ConnectionID).Str("outbound", o.config.Name).
Str("player", metadata.Minecraft.PlayerName).Msg("Created Minecraft connection")
o.onlineCount.Add(1)
Expand Down
52 changes: 46 additions & 6 deletions protocol/minecraft/sniff.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package minecraft

import (
"errors"
"io"
"time"

"github.com/layou233/zbproxy/v3/adapter"
Expand Down Expand Up @@ -85,6 +86,7 @@ func SniffClientHandshake(conn bufio.PeekConn, metadata *adapter.Metadata) error
}
metadata.Minecraft.NextState = int8(nextState)

metadata.Minecraft.SniffPosition = conn.CurrentPosition()
if nextState == mcprotocol.NextStateStatus {
// status packet
conn.SetReadDeadline(time.Now().Add(10 * time.Second))
Expand All @@ -99,9 +101,6 @@ func SniffClientHandshake(conn bufio.PeekConn, metadata *adapter.Metadata) error
if err != nil {
return common.Cause("read packet size: ", err)
}
if packetSize > 33 { // maximum possible size of this kind of packet
return ErrBadPacket
}
conn.SetReadDeadline(time.Now().Add(10 * time.Second))
packetContent, err = conn.Peek(int(packetSize))
if err != nil {
Expand All @@ -120,11 +119,52 @@ func SniffClientHandshake(conn bufio.PeekConn, metadata *adapter.Metadata) error
if err != nil {
return common.Cause("read player name: ", err)
}
if buffer.Len() == 16 { // UUID exists
copy(metadata.Minecraft.UUID[:], buffer.Bytes())
if metadata.Minecraft.ProtocolVersion >= 764 { // 1.20.2
if buffer.Len() == 16 { // UUID exists
copy(metadata.Minecraft.UUID[:], buffer.Bytes())
}
} else if metadata.Minecraft.ProtocolVersion >= 761 { // 1.19.3
var hasUUID byte
hasUUID, err = buffer.ReadByte()
if err != nil {
return common.Cause("read has UUID: ", err)
}
if hasUUID == mcprotocol.BooleanTrue {
copy(metadata.Minecraft.UUID[:], buffer.Bytes())
}
} else if metadata.Minecraft.ProtocolVersion >= 759 { // 1.19
var hasSigData byte
hasSigData, err = buffer.ReadByte()
if err != nil {
return common.Cause("read has sig data: ", err)
}
if hasSigData == mcprotocol.BooleanTrue {
// skip timestamp
buffer.Advance(8) // size of Long
var length int32
// skip public key
length, _, err = mcprotocol.ReadVarIntFrom(buffer)
if err != nil {
return common.Cause("read public key length: ", err)
}
buffer.Advance(int(length))
// skip signature
length, _, err = mcprotocol.ReadVarIntFrom(buffer)
if err != nil {
return common.Cause("read signature length: ", err)
}
buffer.Advance(int(length))
}
var hasUUID byte
hasUUID, err = buffer.ReadByte()
if err != nil && err != io.EOF {
return common.Cause("read has UUID: ", err)
}
if hasUUID == mcprotocol.BooleanTrue {
copy(metadata.Minecraft.UUID[:], buffer.Bytes())
}
}
}

metadata.Minecraft.SniffPosition = conn.CurrentPosition()
return nil
}
10 changes: 5 additions & 5 deletions protocol/sniff.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func Sniff(logger *log.Logger, conn bufio.PeekConn, metadata *adapter.Metadata,
if metadata.Minecraft == nil {
err = minecraft.SniffClientHandshake(conn, metadata)
if err != nil {
logger.Trace().Str("protocol", protocol).Err(err).Msg("sniff error")
logger.Trace().Str("protocol", protocol).Err(err).Msg("Sniff error")
}
}
if !sniffAll {
Expand All @@ -48,21 +48,21 @@ func Sniff(logger *log.Logger, conn bufio.PeekConn, metadata *adapter.Metadata,
for _, snifferFunc := range registry {
err = snifferFunc(logger, conn, metadata)
if err != nil {
logger.Trace().Str("protocol", protocol).Err(err).Msg("sniff error")
logger.Trace().Str("protocol", protocol).Err(err).Msg("Sniff error")
}
}
return
} else if len(registry) > 0 {
if snifferFunc := registry[protocol]; snifferFunc != nil {
err = snifferFunc(logger, conn, metadata)
if err != nil {
logger.Trace().Str("protocol", protocol).Err(err).Msg("sniff error")
logger.Trace().Str("protocol", protocol).Err(err).Msg("Sniff error")
}
} else {
logger.Fatal().Str("protocol", protocol).Msg("unsupported protocol")
logger.Fatal().Str("protocol", protocol).Msg("Unsupported protocol")
}
} else {
logger.Fatal().Str("protocol", protocol).Msg("unsupported protocol")
logger.Fatal().Str("protocol", protocol).Msg("Unsupported protocol")
}
}
conn.Rewind(startPosition)
Expand Down
6 changes: 3 additions & 3 deletions route/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,11 +142,11 @@ func (r *Router) HandleConnection(conn net.Conn, metadata *adapter.Metadata) {
}
r.access.RUnlock()
err = bufio.CopyConn(destinationConn, cachedConn)
logger := r.logger.Warn().Str("id", metadata.ConnectionID).Str("outbound", outbound.Name())
if err != nil {
logger = logger.Err(err)
r.logger.Warn().Str("id", metadata.ConnectionID).Str("outbound", outbound.Name()).Err(err).Msg("Handled connection")
} else {
r.logger.Info().Str("id", metadata.ConnectionID).Str("outbound", outbound.Name()).Msg("Handled connection")
}
logger.Msg("Handled connection")
cachedConn.Close()
return
}
Expand Down

0 comments on commit da6f5b6

Please sign in to comment.