The main.go file demonstrates how to build a Man-in-the-Middle (MITM) proxy that forwards Minecraft players from a local address to a remote address.
Key steps in the proxy lifecycle:
- Authentication: Use
auth.RequestLiveToken() to obtain a token and auth.RefreshTokenSource(token) to create an oauth2.TokenSource. - Status Provider: Initialize a
minecraft.NewForeignStatusProvider using the remote address to handle status requests. - Listening: Use
minecraft.ListenConfig with a StatusProvider to start a listener on a specific protocol (e.g., "raknet") and local address. - Connection Handling: For every accepted connection, use
minecraft.Dialer to connect to the remote server, passing the TokenSource and the client's ClientData(). - Session Initialization: Synchronize the game state by calling
conn.StartGame(serverConn.GameData()) on the client connection and serverConn.DoSpawn() on the server connection. - Packet Forwarding: Run two concurrent loops to read packets from the client and write them to the server, and vice versa, ensuring
minecraft.DisconnectError is handled to disconnect the client gracefully.
// Simplified proxy logic flow
// 1. Setup Listener
p, _ := minecraft.NewForeignStatusProvider(remoteAddr)
listener, _ := minecraft.ListenConfig{StatusProvider: p}.Listen("raknet", localAddr)
// 2. Handle Connections
for {
conn, _ := listener.Accept()
go func(c *minecraft.Conn) {
// 3. Dial Remote
serverConn, _ := minecraft.Dialer{
TokenSource: src,
ClientData: c.ClientData(),
}.Dial("raknet", remoteAddr)
// 4. Initialize Game
_ = c.StartGame(serverConn.GameData())
_ = serverConn.DoSpawn()
// 5. Forward Packets (Client -> Server)
// ... loop conn.ReadPacket() -> serverConn.WritePacket(pk)
// 6. Forward Packets (Server -> Client)
// ... loop serverConn.ReadPacket() -> c.WritePacket(pk)
}(conn.(*minecraft.Conn))
}