Removed Legacy response; update modern response. 1.5

This commit is contained in:
Dereku 2024-09-04 10:06:08 +07:00
parent 5932933f77
commit 7608e43669
2 changed files with 73 additions and 38 deletions

View file

@ -6,7 +6,7 @@
<groupId>net.rubeta</groupId> <groupId>net.rubeta</groupId>
<artifactId>LegacyPing</artifactId> <artifactId>LegacyPing</artifactId>
<version>1.4</version> <version>1.5</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>LegacyPing</name> <name>LegacyPing</name>

View file

@ -5,16 +5,19 @@ import org.bukkit.craftbukkit.CraftServer;
import java.io.*; import java.io.*;
import java.net.*; import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
public class ServerThread extends Thread { public class ServerThread extends Thread {
private static final String MODERN_RESPONSE = private static final String MODERN_RESPONSE =
"{\"version\": {\"name\": \"%version%\",\"protocol\": -%protocol%}," + "{\"version\": {\"name\": \"%version%\",\"protocol\": %protocol%}," +
"\"players\": {\"max\": %max%,\"online\": %now%}," + "\"players\": {\"max\": %max%,\"online\": %now%}," +
"\"description\": {\"text\": \"%motd%\"}," + "\"description\": {\"text\": \"%motd%\"}," +
"\"enforcesSecureChat\": false,\"previewsChat\": true}"; "\"enforcesSecureChat\": false,\"previewsChat\": true}";
private static final String DISCONNECT_REASON = "[\"\",{\"text\":\"This is b1.7.3 server. Visit \"}," +
"{\"text\":\"https://rubeta.net\",\"underlined\":true},{\"text\":\" for more information.\"}]";
private final ServerSocket serverSocket; private final ServerSocket serverSocket;
private final AtomicBoolean working = new AtomicBoolean(false); private final AtomicBoolean working = new AtomicBoolean(false);
private final Server minecraftServer; private final Server minecraftServer;
@ -25,7 +28,7 @@ public class ServerThread extends Thread {
this.minecraftServer = server; this.minecraftServer = server;
this.setName("LegacyPing thread listening " + host + ":" + port); this.setName("LegacyPing thread listening " + host + ":" + port);
this.version = version; this.version = version;
this.protocol = Math.abs(protocol); this.protocol = protocol;
final InetAddress address = InetAddress.getByName(host); final InetAddress address = InetAddress.getByName(host);
this.serverSocket = new ServerSocket(port, 10, address); this.serverSocket = new ServerSocket(port, 10, address);
this.serverSocket.setSoTimeout((int) TimeUnit.SECONDS.toMillis(10L)); this.serverSocket.setSoTimeout((int) TimeUnit.SECONDS.toMillis(10L));
@ -47,6 +50,7 @@ public class ServerThread extends Thread {
new ServerThread("", 25565).start(); new ServerThread("", 25565).start();
} }
@SuppressWarnings("unused")
@Override @Override
public void run() { public void run() {
this.working.set(true); this.working.set(true);
@ -54,17 +58,32 @@ public class ServerThread extends Thread {
try { try {
final Socket socket = this.serverSocket.accept(); final Socket socket = this.serverSocket.accept();
socket.setTrafficClass(SocketOptions.TCP_NODELAY & SocketOptions.IP_TOS); socket.setTrafficClass(SocketOptions.TCP_NODELAY & SocketOptions.IP_TOS);
System.out.println("[LegacyPing] Got new ping from " + socket.getRemoteSocketAddress()); // System.out.println("[LegacyPing] Got new ping from " + socket.getRemoteSocketAddress());
final InputStream inputStream = socket.getInputStream(); final DataInputStream inputStream = new DataInputStream(socket.getInputStream());
final OutputStream outputStream = socket.getOutputStream(); final DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream());
final int firstByte = inputStream.read(); final int packetLength = inputStream.readByte() | inputStream.readByte() << 1; // idk why it doesn't a VarInt
if (firstByte == 254) { final int protocolVersion = this.readVarInt(inputStream);
this.responseForLegacyPing(outputStream); final String hostname = this.readUtf(inputStream);
final int port = inputStream.readShort();
final int status = this.readVarInt(inputStream);
// System.out.println(packetLength + "; Protocol version: " + protocolVersion + ", host: " + hostname
// + ", port: " + port + ", status: " + status);
if (status != 2) {
this.responseForModernPing(outputStream, MODERN_RESPONSE);
} else { } else {
this.responseForModernPing(outputStream); this.responseForModernPing(outputStream, DISCONNECT_REASON);
} }
outputStream.flush(); outputStream.flush();
//socket.close();
inputStream.readShort(); // legacy data
this.writeVarInt(outputStream, this.readVarInt(inputStream)); // Packet length (9)
this.writeVarInt(outputStream, this.readVarInt(inputStream)); // Packet id (1)
outputStream.writeLong(inputStream.readLong()); // timestamp
inputStream.close();
outputStream.close();
socket.close();
} catch (SocketTimeoutException ignore) { } catch (SocketTimeoutException ignore) {
} catch (IOException ex) { } catch (IOException ex) {
System.out.println("Exception caught: " + ex); System.out.println("Exception caught: " + ex);
@ -80,32 +99,20 @@ public class ServerThread extends Thread {
} }
} }
@SuppressWarnings("UnnecessaryUnicodeEscape") private void responseForModernPing(final DataOutputStream outputStream, String response) throws IOException {
private void responseForLegacyPing(final OutputStream outputStream) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream();
final DataOutputStream clientOutput = new DataOutputStream(outputStream); DataOutputStream dos = new DataOutputStream(baos);
clientOutput.write(255); final String responseJson = response
final String response = this.getMotd() + '\u00a7' + this.getOnlinePlayers() + '\u00a7' + this.getMaxPlayers();
clientOutput.writeShort(response.length());
for (char c : response.toCharArray()) {
clientOutput.writeChar(c);
}
// Packet data end
}
private void responseForModernPing(final OutputStream outputStream) throws IOException {
final String responseJson = MODERN_RESPONSE
.replace("%version%", String.valueOf(this.version)) .replace("%version%", String.valueOf(this.version))
.replace("%protocol%", String.valueOf(this.protocol)) .replace("%protocol%", String.valueOf(this.protocol))
.replace("%max%", String.valueOf(this.getMaxPlayers())) .replace("%max%", String.valueOf(this.getMaxPlayers()))
.replace("%now%", String.valueOf(this.getOnlinePlayers())) .replace("%now%", String.valueOf(this.getOnlinePlayers()))
.replace("%motd%", this.getMotd()); .replace("%motd%", this.getMotd());
byte[] bytes = responseJson.getBytes(); this.writeVarInt(dos, 0);
final DataOutputStream clientOutput = new DataOutputStream(outputStream); this.writeUtf(dos, responseJson);
this.writeVarInt(clientOutput, bytes.length + 3); dos.close();
this.writeVarInt(clientOutput, 0); this.writeVarInt(outputStream, baos.size());
this.writeVarInt(clientOutput, bytes.length); outputStream.write(baos.toByteArray());
clientOutput.write(bytes);
// Packet data end
} }
private String getMotd() { private String getMotd() {
@ -120,14 +127,42 @@ public class ServerThread extends Thread {
return this.minecraftServer == null ? 37 : this.minecraftServer.getMaxPlayers(); return this.minecraftServer == null ? 37 : this.minecraftServer.getMaxPlayers();
} }
private void writeVarInt(DataOutputStream out, int paramInt) throws IOException { public int readVarInt(DataInputStream in) throws IOException {
while (true) { int i = 0;
if ((paramInt & 0xFFFFFF80) == 0) { int j = 0;
out.writeByte(paramInt); byte b0;
return; do {
b0 = in.readByte();
i |= (b0 & 127) << j++ * 7;
if (j > 5) {
throw new RuntimeException("VarInt too big");
} }
out.writeByte(paramInt & 0x7F | 0x80); } while((b0 & 128) == 128);
return i;
}
private void writeVarInt(DataOutputStream out, int paramInt) throws IOException {
while((paramInt & 0xffffff80) != 0) {
out.writeByte(paramInt & 0x7f | 0x80);
paramInt >>>= 7; paramInt >>>= 7;
} }
out.writeByte(paramInt);
}
@SuppressWarnings("ResultOfMethodCallIgnored")
private String readUtf(DataInputStream in) throws IOException {
int length = this.readVarInt(in);
byte[] data = new byte[length];
in.read(data);
return new String(data, StandardCharsets.UTF_8);
}
private void writeUtf(DataOutputStream out, String string) throws IOException {
byte[] data = string.getBytes(StandardCharsets.UTF_8);
if (data.length > 32767) {
throw new RuntimeException("String too big (was " + data.length + " bytes encoded, max 32767");
}
this.writeVarInt(out, data.length);
out.write(data);
} }
} }