Files
philippe lhardy 6d7c03d468 MaimMim Man in the middle minetest interceptor
- prototype
- between client and server, allow to capture all exchanges and potentially change them
- created to capture server maps in laby
- first test get only MapBlock, support version serialization version 28
  - prepartion for 29 with zstd but untested.
2022-04-23 11:54:25 +02:00

288 lines
9.2 KiB
Java

package org.artisanlogiciel.games.minetest.net;
import com.github.luben.zstd.Zstd;
import org.artisanlogiciel.games.minetest.MapBlock;
import org.artisanlogiciel.games.minetest.MapNode;
import org.artisanlogiciel.games.minetest.core.PacketException;
import org.artisanlogiciel.games.minetest.core.Serialize;
import org.artisanlogiciel.games.minetest.core.v2s16;
import org.artisanlogiciel.games.minetest.core.v3s16;
import java.nio.ByteBuffer;
/**
* see src/network/networkprotocol.h of minetest sources
*
*
* === NOTES ===
*
* A packet is sent through a channel to a peer with a basic header:
* Header (7 bytes):
* [0] u32 protocol_id
* [4] session_t sender_peer_id
* [6] u8 channel
* sender_peer_id:
* Unique to each peer.
* value 0 (PEER_ID_INEXISTENT) is reserved for making new connections
* value 1 (PEER_ID_SERVER) is reserved for server
* these constants are defined in constants.h
* channel:
* Channel numbers have no intrinsic meaning. Currently only 0, 1, 2 exist.
*
*
* */
public class PacketHandler {
ReliablePacketBuffer reliableBuffer = null;
IncomingSplitBuffer[] incomingChanneleSplitBuffer = new IncomingSplitBuffer[4];
// server serialization in hello version
int ser_version;
// minetest protocol should be 0x4f457403
static int readProtocolId(byte[] buffer, int length)
throws PacketException
{
return Serialize.readU32(buffer, 0, length);
}
static int readPeerId(byte[] buffer, int length)
throws PacketException
{
return Serialize.readU16(buffer,4,length);
}
static int readChannel(byte[] buffer, int length)
throws PacketException
{
return Serialize.readU8(buffer, 6, length);
}
NetworkPacket handleAny(byte[] buffer, int length)
throws PacketException
{
int protocol_id = readProtocolId(buffer, length);
int peer_id = readPeerId(buffer, length);
int channel = readChannel(buffer, length);
int type = Serialize.readU8(buffer,7,length);
PacketType packetType = PacketType.getPacketType(type);
NetworkPacket networkPacket = new NetworkPacket(protocol_id,peer_id,channel,packetType, buffer, length);
// offset of packet within buffer.
networkPacket.addOffset(BufferedPacket.BASE_HEADER_SIZE);
System.out.println("length " + length + " protocol_id " + String.format("%x", protocol_id) + " peer_id " + peer_id + " channel " + channel + " type " + packetType);
return networkPacket;
}
void handlePacketType_Control(NetworkPacket networkPacket)
throws PacketException {
}
void handlePacketType_Reliable(NetworkPacket networkPacket)
throws PacketException
{
// TODO handle misordered...
/*
if ( reliableBuffer == null )
{
reliableBuffer = new ReliablePacketBuffer();
}
BufferedPacket packet = new BufferedPacket(buffer);
int nextExpected = 0;
reliableBuffer.insert(packet, nextExpected);
*/
// handle nested packet
networkPacket.addOffset(3);
int offset = networkPacket.getOffset();
byte buffer[] = networkPacket.getBuffer();
int length = networkPacket.getLength();
PacketType packetType = PacketType.getPacketType(Serialize.readU8(buffer,offset,length));
System.out.println( "reliable " + packetType.toString());
switch (packetType)
{
case PACKET_TYPE_CONTROL:
//
handlePacketType_Control(networkPacket);
break;
case PACKET_TYPE_ORIGINAL:
handlePacketType_Original(networkPacket);
break;
case PACKET_TYPE_SPLIT:
handlePacketType_Split(networkPacket);
break;
case PACKET_TYPE_RELIABLE:
// this is an error, no nested reliable accepted.
throw new PacketException("nested reliable");
default: // error
throw new PacketException("unknown type");
}
}
void handleCommand_Hello(NetworkPacket networkPacket)
throws PacketException {
// u8 deployed serialisation version
ByteBuffer buffer = networkPacket.getByteBuffer();
int ser_ver = Serialize.readU8(buffer);
ser_version = ser_ver;
// u16 deployed network compression mode
int net_compress = Serialize.readU16(buffer);
// u16 deployed protocol version
int deployed = Serialize.readU16(buffer);
System.out.println(String.format("HELLO ser_ver=%d net_compress %d deployed %d", ser_ver,net_compress,deployed));
// u32 supported auth methods
// std::string username that should be used for legacy hash (for proper casing)
}
// clientpackethandler.cpp Client::handleCommand_BlockData(NetworkPacket* pkt)
// TOCLIENT_BLOCKDATA
void handleCommand_BlockData(NetworkPacket networkPacket)
throws PacketException
{
v3s16 p = networkPacket.v3s16();
// will be used to get vector...
// v2s16 p2d = new v2s16(p.X,p.Z);
System.out.println(String.format(" (X,Y,Z) %d %d %d", p.X, p.Y,p.Z));
//
networkPacket.addOffset(6);
// FIXME get it from handshake
int version = 28;
// Should be a MapBlock
MapBlock block = new MapBlock();
block.deSerialize(networkPacket.getByteBuffer(),version);
// now we have a block ! what to do with it ?
}
void handlePacketCommand(NetworkPacket networkPacket)
throws PacketException {
// consume type and ??? well ... 2
int command = Serialize.readU16(networkPacket.getBuffer(),networkPacket.getOffset(),networkPacket.getLength());
System.out.println(String.format("command %x length %d", command, networkPacket.getLength()));
networkPacket.addOffset(2);
// Original ... toClient - toServer
switch (command)
{
case 0x02:
{
System.out.println("TOCLIENT_HELLO");
handleCommand_Hello(networkPacket);
}
break;
case 0x20:
{
System.out.println("TOCLIENT_BLOCKDATA");
handleCommand_BlockData(networkPacket);
}
break;
case 0x4f:
{
//TOCLIENT_SET_SKY = 0x4f,
System.out.println("TOCLIENT_SET_SKY");
}
break;
}
}
void handlePacketType_Original(NetworkPacket networkPacket)
throws PacketException {
// eat original type 1.
networkPacket.addOffset(1);
handlePacketCommand(networkPacket);
}
void handlePacketType_Split(NetworkPacket networkPacket)
throws PacketException {
int channel = networkPacket.getChannel();
if ( channel < incomingChanneleSplitBuffer.length) {
IncomingSplitBuffer splitBuffer = incomingChanneleSplitBuffer[channel];
if ( splitBuffer == null )
{
splitBuffer = new IncomingSplitBuffer();
incomingChanneleSplitBuffer[channel] = splitBuffer;
}
if ( splitBuffer != null ) {
BufferedPacket bufferedPacket = splitBuffer.insert(networkPacket);
if ( bufferedPacket != null ) {
// well should handle it.
System.out.println("Reassembled packet size " + bufferedPacket.m_data.length);
// reset it.
incomingChanneleSplitBuffer[channel] = new IncomingSplitBuffer();
handleBufferedPacket(bufferedPacket);
}
}
}
else {
throw new PacketException("invalid channel " + channel);
}
}
void handleBufferedPacket(BufferedPacket bufferedPacket)
throws PacketException
{
// FIXME, why a BufferedPacket anyway since we finaly need a NetworkPacket ?
NetworkPacket networkPacket = new NetworkPacket(0,0,0, PacketType.PACKET_TYPE_ORIGINAL,bufferedPacket.m_data, bufferedPacket.size());
networkPacket.addOffset(BufferedPacket.BASE_HEADER_SIZE);
handlePacketCommand(networkPacket);
}
void fromServer(byte[] buffer, int length)
throws PacketException
{
System.out.print(" <- ");
NetworkPacket networkPacket = handleAny(buffer,length);
switch (networkPacket.packetType)
{
case PACKET_TYPE_CONTROL:
//
handlePacketType_Control(networkPacket);
break;
case PACKET_TYPE_RELIABLE:
//
handlePacketType_Reliable(networkPacket);
break;
case PACKET_TYPE_ORIGINAL:
handlePacketType_Original(networkPacket);
break;
case PACKET_TYPE_SPLIT:
handlePacketType_Split(networkPacket);
break;
default: // error
throw new PacketException("unknown type");
}
}
void fromClient(byte[] buffer, int length)
throws PacketException
{
System.out.print(" -> ");
handleAny(buffer,length);
}
}