2025-11-24 22:52:51 +03:00

158 lines
5.7 KiB
Java

/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* com.mojang.logging.LogUtils
* org.slf4j.Logger
*/
package net.minecraft.server.rcon.thread;
import com.mojang.logging.LogUtils;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.Locale;
import net.minecraft.server.ServerInterface;
import net.minecraft.server.rcon.PktUtils;
import net.minecraft.server.rcon.thread.GenericThread;
import org.slf4j.Logger;
public class RconClient
extends GenericThread {
private static final Logger LOGGER = LogUtils.getLogger();
private static final int SERVERDATA_AUTH = 3;
private static final int SERVERDATA_EXECCOMMAND = 2;
private static final int SERVERDATA_RESPONSE_VALUE = 0;
private static final int SERVERDATA_AUTH_RESPONSE = 2;
private static final int SERVERDATA_AUTH_FAILURE = -1;
private boolean authed;
private final Socket client;
private final byte[] buf = new byte[1460];
private final String rconPassword;
private final ServerInterface serverInterface;
RconClient(ServerInterface serverInterface, String rconPassword, Socket socket) {
super("RCON Client " + String.valueOf(socket.getInetAddress()));
this.serverInterface = serverInterface;
this.client = socket;
try {
this.client.setSoTimeout(0);
}
catch (Exception ignored) {
this.running = false;
}
this.rconPassword = rconPassword;
}
/*
* WARNING - Removed try catching itself - possible behaviour change.
*/
@Override
public void run() {
try {
while (this.running) {
BufferedInputStream inputStream = new BufferedInputStream(this.client.getInputStream());
int read = inputStream.read(this.buf, 0, 1460);
if (10 > read) {
return;
}
int offset = 0;
int pktsize = PktUtils.intFromByteArray(this.buf, 0, read);
if (pktsize != read - 4) {
return;
}
int requestid = PktUtils.intFromByteArray(this.buf, offset += 4, read);
int cmd = PktUtils.intFromByteArray(this.buf, offset += 4);
offset += 4;
switch (cmd) {
case 3: {
String password = PktUtils.stringFromByteArray(this.buf, offset, read);
offset += password.length();
if (!password.isEmpty() && password.equals(this.rconPassword)) {
this.authed = true;
this.send(requestid, 2, "");
break;
}
this.authed = false;
this.sendAuthFailure();
break;
}
case 2: {
if (this.authed) {
String command = PktUtils.stringFromByteArray(this.buf, offset, read);
try {
this.sendCmdResponse(requestid, this.serverInterface.runCommand(command));
}
catch (Exception e) {
this.sendCmdResponse(requestid, "Error executing: " + command + " (" + e.getMessage() + ")");
}
break;
}
this.sendAuthFailure();
break;
}
default: {
this.sendCmdResponse(requestid, String.format(Locale.ROOT, "Unknown request %s", Integer.toHexString(cmd)));
}
}
}
}
catch (IOException inputStream) {
}
catch (Exception e) {
LOGGER.error("Exception whilst parsing RCON input", (Throwable)e);
}
finally {
this.closeSocket();
LOGGER.info("Thread {} shutting down", (Object)this.name);
this.running = false;
}
}
private void send(int requestid, int cmd, String str) throws IOException {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(1248);
DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
dataOutputStream.writeInt(Integer.reverseBytes(bytes.length + 10));
dataOutputStream.writeInt(Integer.reverseBytes(requestid));
dataOutputStream.writeInt(Integer.reverseBytes(cmd));
dataOutputStream.write(bytes);
dataOutputStream.write(0);
dataOutputStream.write(0);
this.client.getOutputStream().write(outputStream.toByteArray());
}
private void sendAuthFailure() throws IOException {
this.send(-1, 2, "");
}
private void sendCmdResponse(int requestid, String response) throws IOException {
int dataLen;
int len = response.length();
do {
dataLen = 4096 <= len ? 4096 : len;
this.send(requestid, 0, response.substring(0, dataLen));
} while (0 != (len = (response = response.substring(dataLen)).length()));
}
@Override
public void stop() {
this.running = false;
this.closeSocket();
super.stop();
}
private void closeSocket() {
try {
this.client.close();
}
catch (IOException e) {
LOGGER.warn("Failed to close socket", (Throwable)e);
}
}
}