PrismarineJS / node-minecraft-protocol

Parse and serialize minecraft packets, plus authentication and encryption.
https://prismarinejs.github.io/node-minecraft-protocol/
BSD 3-Clause "New" or "Revised" License
1.24k stars 239 forks source link

Deserialize without client or server #591

Open hhoughgg opened 6 years ago

hhoughgg commented 6 years ago

I have a very simple tcp proxy setup similar to https://gist.github.com/kfox/2313683

It listens on ip address and forwards the packets to the minecraft server listening on localhost.

I don't care about most of the packets I just want to parse the handshake packet as well as ping packets. Is there a way to do this with the library without creating an entire client or server.

I have tried with the code below but I get errors on ping packet or connection as listed below. The variable data below is the raw buffer from the remote connection.

Thanks

const parse = mc.createDeserializer({ state: 'handshaking', isServer: false, version: '1.13.1' })
console.log('parse: ', parse.parsePacketBuffer(data))

Error: Read error for name : 20 is not in the mappings value
rom1504 commented 6 years ago

You also need the other transform. At least splitter and possibly compressor. Look at client.js code to see how to plug them.

On Sat, Sep 15, 2018, 05:39 Harry Hough notifications@github.com wrote:

I have a very simple tcp proxy setup similar to https://gist.github.com/kfox/2313683

It listens on ip address and forwards the packets to the minecraft server listening on localhost.

I don't care about most of the packets I just want to parse the handshake packet as well as ping packets. Is there a way to do this with the library without creating an entire client or server.

I have tried with the code below but I get errors on ping packet or connection as listed below. The variable data below is the raw buffer from the remote connection.

Thanks

` const parse = mc.createDeserializer({ state: 'handshaking', isServer: false, version: '1.13.1' }) console.log('parse: ', parse.parsePacketBuffer(data))

Error: Read error for name : 20 is not in the mappings value `

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/PrismarineJS/node-minecraft-protocol/issues/591, or mute the thread https://github.com/notifications/unsubscribe-auth/ACPN_gvoEg-qnLpMUxMZs1rYjq0dpbr_ks5ubHaAgaJpZM4WqLWv .

plexigras commented 6 years ago

socket -> decipher -> splitter -> decompressor -> deserializer

most but not all servers need the decipher and decompressor.

why not use a nmp server as a proxy?

hhoughgg commented 6 years ago

Basically my use case is that I am directing different people connecting with their minecraft client to different minecraft servers on localhost ports based on the dns used for connection. All connections are to serverip:25565.

All I really want to be able to do is parse ping packets and initial connection packets and respond to ping packets without hitting the actual minecraft server.

I tried to proxy example but I assume I need to set my minecraft server to offline mode where the nmp server proxy handles login? Do this mean my minecraft server is actually still effectively in online mode?

This is where I am at now and this is the result of my minecraft client sending a ping packet. It definately looks closer than it was before but I'm unsure why its failing. The ping packets don't look compressed or encrypted.

const parse = mc.createDeserializer({ state: 'status', isServer: true, version: '1.13.1' })

const server = net.createServer((remotesocket) => {
  const splitter = createSplitter()
  remotesocket.pipe(splitter).pipe(parse)

  remotesocket.on('data', (data) => {
    console.log('data', data)
    console.log('data string: ', data.toString())

    //> Chunk size is 20 but only 1 was read ; partial packet : {"name":"ping_start","params":{}};
  });
})

Thanks for the explanations so far.

rom1504 commented 6 years ago

The initial state is handshaking not status, that's your (current) problem.

plexigras commented 6 years ago

yes you need to wait for the right state

here in this proxy example we wait for the state to be play to connect the client to the remote.

const version = '1.9.4'

const nmp   = require('minecraft-protocol')

const server = nmp.createServer({ port:25566, version })

server.on('login', connect)

function connect(client) {
  const remote = nmp.createClient({
    username: client.username,
    version,
    keepAlive: false
  })

  remote.on('raw', (buffer, metadata) => {
    if (metadata.state !== 'play') return
    client.writeRaw(buffer)
  })
  client.on('raw', (buffer, metadata) => {
    remote.writeRaw(buffer)
  })
}
DeliciousJaffa commented 5 years ago

@bluestreek18 Is there a need to pipe this through your own software?

Basically my use case is that I am directing different people connecting with their minecraft client to different minecraft servers on localhost ports based on the dns used for connection.

This use case can already be handled natively by Minecraft clients through the use of SRV records (if you make the servers accessible by internet)

Inrixia commented 5 years ago

I'm looking into doing this too (Parsing packets without actually creating a server/client) but am struggling a bit with the process of getting it working. Would you be able to give me a idea of how I am meant to pipe the data from the socket to get a properly parsed packet with the meta etc similar to what you can get from client.on('packet',function(data, meta){})?

iceiix commented 5 years ago

@Inrixia I use this to parse a packet read from a file (assumes decrypted and decompressed etc):

const mc=require('minecraft-protocol');
const d=mc.createDeserializer({version:"1.12.2", state:mc.states.PLAY});
d.on('data',(parsed)=>{
  console.log(JSON.stringify(parsed, null, ''));
  console.log(parsed.data.params);
});
d.write(require('fs').readFileSync('last-packet'));
Inrixia commented 5 years ago

@iceiix Thanks. Was actually able to get the whole thing somewhat working after a few days. Just stuck on the encryption/decryption now but have been taking a break for the past few weeks as have had other priorities. Ill leave a post here once I get a fully working thing going I guess.