Skip to content

Commit da6f5b6

Browse files
committed
fix: Minecraft login packet version difference
1 parent 8662e4a commit da6f5b6

File tree

5 files changed

+71
-31
lines changed

5 files changed

+71
-31
lines changed

common/bufio/cached.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ func NewCachedConn(c net.Conn) *CachedConn {
2727
}
2828
}
2929

30+
func (c *CachedConn) Cache() *buf.Buffer {
31+
return c.cache
32+
}
33+
3034
func (c *CachedConn) Read(p []byte) (n int, err error) {
3135
if c.cache != nil && !c.cache.IsEmpty() {
3236
return c.cache.Read(p)

protocol/minecraft/outbound.go

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -201,9 +201,15 @@ func (o *Outbound) InjectConnection(ctx context.Context, conn *bufio.CachedConn,
201201
}
202202
switch metadata.Minecraft.NextState {
203203
case mcprotocol.NextStateStatus:
204+
// skip Status Request packet
205+
_, err := conn.Peek(2)
206+
if err != nil {
207+
return common.Cause("skip status request: ", err)
208+
}
204209
if o.config.Minecraft.MotdFavicon == "" && o.config.Minecraft.MotdDescription == "" {
205210
// directly proxy MOTD from server
206-
remoteConn, err := o.connectServer(ctx, metadata)
211+
var remoteConn net.Conn
212+
remoteConn, err = o.connectServer(ctx, metadata)
207213
if err != nil {
208214
return common.Cause("request remote MOTD: ", err)
209215
}
@@ -261,7 +267,7 @@ func (o *Outbound) InjectConnection(ctx context.Context, conn *bufio.CachedConn,
261267
Writer: common.UnwrapWriter(conn), // unwrap to make writev syscall possible
262268
Conn: conn,
263269
}
264-
err := clientMC.WriteVectorizedPacket(buffer, motd)
270+
err = clientMC.WriteVectorizedPacket(buffer, motd)
265271
if err != nil {
266272
return common.Cause("respond MOTD: ", err)
267273
}
@@ -366,26 +372,16 @@ func (o *Outbound) InjectConnection(ctx context.Context, conn *bufio.CachedConn,
366372
binary.BigEndian.PutUint16(buffer.Extend(2), port)
367373
buffer.WriteByte(mcprotocol.NextStateLogin)
368374
mcprotocol.AppendPacketLength(buffer, buffer.Len())
369-
// construct login packet
370-
loginPacketSize := 2 + len(metadata.Minecraft.PlayerName) // should not exceed 127
371-
hasUUID := false
372-
if metadata.Minecraft.UUID != [16]byte{} { // is not empty
373-
loginPacketSize += 16
374-
hasUUID = true
375-
}
376-
buffer.WriteByte(byte(loginPacketSize))
377-
buffer.WriteByte(0) // Server bound : Login Start
378-
buffer.WriteByte(byte(len(metadata.Minecraft.PlayerName)))
379-
buffer.WriteString(metadata.Minecraft.PlayerName)
380-
if hasUUID {
381-
buffer.Write(metadata.Minecraft.UUID[:])
382-
}
383-
_, err = serverConn.Write(buffer.Bytes())
375+
// write handshake and login packet
376+
cache := conn.Cache()
377+
vector := net.Buffers{buffer.Bytes(), cache.Bytes()}
378+
_, err = vector.WriteTo(serverConn)
384379
buffer.Release()
385380
if err != nil {
386381
serverConn.Close()
387382
return common.Cause("server handshake: ", err)
388383
}
384+
cache.Advance(cache.Len()) // all written
389385
o.logger.Info().Str("id", metadata.ConnectionID).Str("outbound", o.config.Name).
390386
Str("player", metadata.Minecraft.PlayerName).Msg("Created Minecraft connection")
391387
o.onlineCount.Add(1)

protocol/minecraft/sniff.go

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package minecraft
22

33
import (
44
"errors"
5+
"io"
56
"time"
67

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

89+
metadata.Minecraft.SniffPosition = conn.CurrentPosition()
8890
if nextState == mcprotocol.NextStateStatus {
8991
// status packet
9092
conn.SetReadDeadline(time.Now().Add(10 * time.Second))
@@ -99,9 +101,6 @@ func SniffClientHandshake(conn bufio.PeekConn, metadata *adapter.Metadata) error
99101
if err != nil {
100102
return common.Cause("read packet size: ", err)
101103
}
102-
if packetSize > 33 { // maximum possible size of this kind of packet
103-
return ErrBadPacket
104-
}
105104
conn.SetReadDeadline(time.Now().Add(10 * time.Second))
106105
packetContent, err = conn.Peek(int(packetSize))
107106
if err != nil {
@@ -120,11 +119,52 @@ func SniffClientHandshake(conn bufio.PeekConn, metadata *adapter.Metadata) error
120119
if err != nil {
121120
return common.Cause("read player name: ", err)
122121
}
123-
if buffer.Len() == 16 { // UUID exists
124-
copy(metadata.Minecraft.UUID[:], buffer.Bytes())
122+
if metadata.Minecraft.ProtocolVersion >= 764 { // 1.20.2
123+
if buffer.Len() == 16 { // UUID exists
124+
copy(metadata.Minecraft.UUID[:], buffer.Bytes())
125+
}
126+
} else if metadata.Minecraft.ProtocolVersion >= 761 { // 1.19.3
127+
var hasUUID byte
128+
hasUUID, err = buffer.ReadByte()
129+
if err != nil {
130+
return common.Cause("read has UUID: ", err)
131+
}
132+
if hasUUID == mcprotocol.BooleanTrue {
133+
copy(metadata.Minecraft.UUID[:], buffer.Bytes())
134+
}
135+
} else if metadata.Minecraft.ProtocolVersion >= 759 { // 1.19
136+
var hasSigData byte
137+
hasSigData, err = buffer.ReadByte()
138+
if err != nil {
139+
return common.Cause("read has sig data: ", err)
140+
}
141+
if hasSigData == mcprotocol.BooleanTrue {
142+
// skip timestamp
143+
buffer.Advance(8) // size of Long
144+
var length int32
145+
// skip public key
146+
length, _, err = mcprotocol.ReadVarIntFrom(buffer)
147+
if err != nil {
148+
return common.Cause("read public key length: ", err)
149+
}
150+
buffer.Advance(int(length))
151+
// skip signature
152+
length, _, err = mcprotocol.ReadVarIntFrom(buffer)
153+
if err != nil {
154+
return common.Cause("read signature length: ", err)
155+
}
156+
buffer.Advance(int(length))
157+
}
158+
var hasUUID byte
159+
hasUUID, err = buffer.ReadByte()
160+
if err != nil && err != io.EOF {
161+
return common.Cause("read has UUID: ", err)
162+
}
163+
if hasUUID == mcprotocol.BooleanTrue {
164+
copy(metadata.Minecraft.UUID[:], buffer.Bytes())
165+
}
125166
}
126167
}
127168

128-
metadata.Minecraft.SniffPosition = conn.CurrentPosition()
129169
return nil
130170
}

protocol/sniff.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ func Sniff(logger *log.Logger, conn bufio.PeekConn, metadata *adapter.Metadata,
3333
if metadata.Minecraft == nil {
3434
err = minecraft.SniffClientHandshake(conn, metadata)
3535
if err != nil {
36-
logger.Trace().Str("protocol", protocol).Err(err).Msg("sniff error")
36+
logger.Trace().Str("protocol", protocol).Err(err).Msg("Sniff error")
3737
}
3838
}
3939
if !sniffAll {
@@ -48,21 +48,21 @@ func Sniff(logger *log.Logger, conn bufio.PeekConn, metadata *adapter.Metadata,
4848
for _, snifferFunc := range registry {
4949
err = snifferFunc(logger, conn, metadata)
5050
if err != nil {
51-
logger.Trace().Str("protocol", protocol).Err(err).Msg("sniff error")
51+
logger.Trace().Str("protocol", protocol).Err(err).Msg("Sniff error")
5252
}
5353
}
5454
return
5555
} else if len(registry) > 0 {
5656
if snifferFunc := registry[protocol]; snifferFunc != nil {
5757
err = snifferFunc(logger, conn, metadata)
5858
if err != nil {
59-
logger.Trace().Str("protocol", protocol).Err(err).Msg("sniff error")
59+
logger.Trace().Str("protocol", protocol).Err(err).Msg("Sniff error")
6060
}
6161
} else {
62-
logger.Fatal().Str("protocol", protocol).Msg("unsupported protocol")
62+
logger.Fatal().Str("protocol", protocol).Msg("Unsupported protocol")
6363
}
6464
} else {
65-
logger.Fatal().Str("protocol", protocol).Msg("unsupported protocol")
65+
logger.Fatal().Str("protocol", protocol).Msg("Unsupported protocol")
6666
}
6767
}
6868
conn.Rewind(startPosition)

route/router.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,11 +142,11 @@ func (r *Router) HandleConnection(conn net.Conn, metadata *adapter.Metadata) {
142142
}
143143
r.access.RUnlock()
144144
err = bufio.CopyConn(destinationConn, cachedConn)
145-
logger := r.logger.Warn().Str("id", metadata.ConnectionID).Str("outbound", outbound.Name())
146145
if err != nil {
147-
logger = logger.Err(err)
146+
r.logger.Warn().Str("id", metadata.ConnectionID).Str("outbound", outbound.Name()).Err(err).Msg("Handled connection")
147+
} else {
148+
r.logger.Info().Str("id", metadata.ConnectionID).Str("outbound", outbound.Name()).Msg("Handled connection")
148149
}
149-
logger.Msg("Handled connection")
150150
cachedConn.Close()
151151
return
152152
}

0 commit comments

Comments
 (0)