Skip to content

Commit

Permalink
(1.4) fork by www.n0nexist.gq
Browse files Browse the repository at this point in the history
  • Loading branch information
n0nexist authored Jan 26, 2023
1 parent 79e2156 commit 1d09fdd
Show file tree
Hide file tree
Showing 48 changed files with 3,000 additions and 0 deletions.
111 changes: 111 additions & 0 deletions src/main/java/me/replydev/mcping/LegacyPinger.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package me.replydev.mcping;

import me.replydev.mcping.data.FinalResponse;
import me.replydev.mcping.rawData.Players;
import me.replydev.mcping.rawData.Version;

import java.io.*;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.charset.StandardCharsets;

/**
* Pinger for 1.6 protocol
* https://wiki.vg/Server_List_Ping#Client_to_server
*/
public class LegacyPinger {
private InetSocketAddress host;
private int timeout;
private int protocolVersion = -1;

void setAddress(InetSocketAddress host)
{
this.host = host;
}
void setTimeout(int timeout)
{
this.timeout = timeout;
}
void setProtocolVersion(int protocolVersion) {
this.protocolVersion = protocolVersion;
}

public LegacyPingResponse ping() throws IOException {
Socket socket = new Socket();
socket.setSoTimeout(this.timeout);
socket.connect(this.host, this.timeout);
sendPing(new DataOutputStream(socket.getOutputStream()));
socket.close(); // the socked was never closed in the original version...
return readResponse(new DataInputStream(socket.getInputStream()));
}

private void sendPing(DataOutputStream dataOutputStream) throws IOException {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
DataOutputStream handshake = new DataOutputStream(bytes);
handshake.writeByte(0xFE);
handshake.writeByte(0x01);
handshake.writeByte(0xFA);
byte[] hostNameBytes = host.getHostName().getBytes(StandardCharsets.UTF_16BE);
String hostStr = "MC|" + host.getHostName();
byte[] hostStrBytes = hostStr.getBytes(StandardCharsets.UTF_16BE);
handshake.writeShort(hostStrBytes.length);
for (byte aByte : hostStrBytes) {
handshake.writeByte(aByte);
}
handshake.write(7 + hostStrBytes.length);
handshake.write(protocolVersion);
handshake.writeShort(hostNameBytes.length);
for (byte aByte : hostNameBytes) {
handshake.writeByte(aByte);
}
handshake.writeInt(host.getPort());
dataOutputStream.write(bytes.toByteArray());
}

private LegacyPingResponse readResponse(DataInputStream dataInputStream) throws IOException {
dataInputStream.readByte(); // Single data identifier
dataInputStream.readShort();
byte[] bytes = dataInputStream.readNBytes(dataInputStream.available());
String str = new String(bytes, StandardCharsets.UTF_16BE);
String[] split = str.split("\\0000");
return new LegacyPingResponse(Integer.parseInt(split[1]), split[2], split[3], Integer.parseInt(split[4]), Integer.parseInt(split[5]));
}

public static final class LegacyPingResponse {
public final int protocolVersion;
public final String serverVersion;
public final String motd;
public final int players;
public final int maxPlayers;

public LegacyPingResponse(int protocolVersion, String serverVersion, String motd, int players, int maxPlayers) {
this.protocolVersion = protocolVersion;
this.serverVersion = serverVersion;
this.motd = motd;
this.players = players;
this.maxPlayers = maxPlayers;
}

@Override
public String toString() {
final StringBuilder sb = new StringBuilder("LegacyPingResponse{");
sb.append("protocolVersion=").append(protocolVersion);
sb.append(", serverVersion='").append(serverVersion).append('\'');
sb.append(", motd='").append(motd).append('\'');
sb.append(", players=").append(players);
sb.append(", maxPlayers=").append(maxPlayers);
sb.append('}');
return sb.toString();
}

public FinalResponse toFinalResponse() {
Players players = new Players();
players.setOnline(this.players);
players.setMax(this.maxPlayers);
Version version = new Version();
version.setProtocol(this.protocolVersion);
version.setName(this.serverVersion);
return new FinalResponse(players, version, null, motd);
}
}
}
119 changes: 119 additions & 0 deletions src/main/java/me/replydev/mcping/MCPing.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package me.replydev.mcping;

import com.google.gson.Gson;
import me.replydev.mcping.LegacyPinger.LegacyPingResponse;
import me.replydev.mcping.data.*;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;

public class MCPing
{
private static final Logger LOGGER = LogManager.getLogger(MCPing.class.getName());

/**
* If the client is pinging to determine what version to use, by convention -1 should be set.
*/
public static final int PROTOCOL_VERSION_DISCOVERY = -1;

public ResponseDetails getLegacyPingWithDetails(PingOptions options) throws IOException {
LegacyPinger pinger = new LegacyPinger();
pinger.setProtocolVersion(options.getProtocolVersion());
pinger.setAddress(new InetSocketAddress(options.getHostname(),options.getPort()));
pinger.setTimeout(options.getTimeout());
pinger.setProtocolVersion(options.getProtocolVersion());
LegacyPingResponse response = pinger.ping();
return new ResponseDetails(response.toFinalResponse(), null, null, null, null, null, null, response, null);
}

public ResponseDetails getPingWithDetails(PingOptions options) throws IOException
{
final Gson gson = new Gson();
Pinger a = new Pinger();
a.setAddress(new InetSocketAddress(options.getHostname(),options.getPort()));
a.setTimeout(options.getTimeout());
a.setProtocolVersion(options.getProtocolVersion());
String json = a.fetchData();
try {
if(json != null){
if (json.getBytes(StandardCharsets.UTF_8).length > 5000000) {
// got a response greater than 5mb, possible honeypot?
LOGGER.error("Got a json response > 5mb, possible honeypot?");
LOGGER.error(options.getHostname() + ":" + options.getPort());
return null;
}
if(json.contains("{"))
{
if(json.contains("\"modid\"") && json.contains("\"translate\"")){ //it's a forge response translate
ForgeResponseTranslate forgeResponseTranslate = gson.fromJson(json, ForgeResponseTranslate.class);
return new ResponseDetails(forgeResponseTranslate.toFinalResponse(), forgeResponseTranslate, null, null, null, null, null, null, json);
}
else if(json.contains("\"modid\"") && json.contains("\"text\"")){ //it's a normal forge response
ForgeResponse forgeResponse = gson.fromJson(json, ForgeResponse.class);
return new ResponseDetails(forgeResponse.toFinalResponse(), null, forgeResponse, null, null, null, null, null, json);
}
else if(json.contains("\"modid\"")){ //it's an old forge response
ForgeResponseOld forgeResponseOld = gson.fromJson(json, ForgeResponseOld.class);
return new ResponseDetails(forgeResponseOld.toFinalResponse(), null, null, forgeResponseOld, null, null, null, null, json);
}
else if(json.contains("\"extra\"")){ //it's an extra response
ExtraResponse extraResponse = gson.fromJson(json, ExtraResponse.class);
return new ResponseDetails(extraResponse.toFinalResponse(), null, null, null, extraResponse, null, null, null, json);
}
else if(json.contains("\"text\"")){ //it's a new response
NewResponse newResponse = gson.fromJson(json, NewResponse.class);
return new ResponseDetails(newResponse.toFinalResponse(), null, null, null, null, newResponse, null, null, json);
}
else { //it's an old response
OldResponse oldResponse = gson.fromJson(json, OldResponse.class);
return new ResponseDetails(oldResponse.toFinalResponse(), null, null, null, null, null, oldResponse, null, json);
}
}
}
} catch (Exception e) {
e.printStackTrace();
System.out.println(json);
}

return null;
}

public FinalResponse getPing(PingOptions options) throws IOException {
return getPingWithDetails(options).standard;
}

public static class ResponseDetails {
public final FinalResponse standard;
public final ForgeResponseTranslate forgeTranslate;
public final ForgeResponse forge;
public final ForgeResponseOld oldForge;
public final ExtraResponse extraResponse;
public final NewResponse response;
public final OldResponse oldResponse;
public final LegacyPingResponse legacyResponse;
public final String json;

public ResponseDetails(FinalResponse standard,
ForgeResponseTranslate forgeTranslate,
ForgeResponse forge,
ForgeResponseOld oldForge,
ExtraResponse extraResponse,
NewResponse response,
OldResponse oldResponse,
LegacyPingResponse legacyResponse,
String json) {
this.standard = standard;
this.forgeTranslate = forgeTranslate;
this.forge = forge;
this.oldForge = oldForge;
this.extraResponse = extraResponse;
this.response = response;
this.oldResponse = oldResponse;
this.legacyResponse = legacyResponse;
this.json = json;
}
}
}
44 changes: 44 additions & 0 deletions src/main/java/me/replydev/mcping/PingOptions.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package me.replydev.mcping;

public class PingOptions {

private String hostname;
private int port;
private int timeout;
private int protocolVersion = -1;

public PingOptions setHostname(String hostname) {
this.hostname = hostname;
return this;
}

public PingOptions setPort(int port) {
this.port = port;
return this;
}

public PingOptions setTimeout(int timeout) {
this.timeout = timeout;
return this;
}

String getHostname() {
return this.hostname;
}

int getPort() {
return this.port;
}

public int getTimeout() {
return this.timeout;
}

public int getProtocolVersion() {
return protocolVersion;
}

public void setProtocolVersion(int protocol) {
this.protocolVersion = protocol;
}
}
105 changes: 105 additions & 0 deletions src/main/java/me/replydev/mcping/Pinger.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package me.replydev.mcping;

import java.io.*;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.charset.StandardCharsets;

class Pinger
{
private InetSocketAddress host;
private int timeout;
// If the client is pinging to determine what version to use, by convention -1 should be set.
private int protocolVersion = -1;

void setAddress(InetSocketAddress host)
{
this.host = host;
}
void setTimeout(int timeout)
{
this.timeout = timeout;
}

public void setProtocolVersion(int protocolVersion) {
this.protocolVersion = protocolVersion;
}

private int readVarInt(DataInputStream in) throws IOException {
int i = 0;
int j = 0;
int k;
do
{
k = in.readByte();
i |= (k & 0x7F) << j++ * 7;
if (j > 5) {
//throw new RuntimeException("VarInt too big");
return -1;
}
} while ((k & 0x80) == 128);
return i;
}

private void writeVarInt(DataOutputStream out, int paramInt) throws IOException {
for (;;)
{
if ((paramInt & 0xFFFFFF80) == 0)
{
out.writeByte(paramInt);
return;
}
out.writeByte(paramInt & 0x7F | 0x80);
paramInt >>>= 7;
}
}

public String fetchData() throws IOException
{
Socket socket = new Socket();
socket.setSoTimeout(this.timeout);
socket.connect(this.host, this.timeout);

OutputStream outputStream = socket.getOutputStream();
DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
InputStream inputStream = socket.getInputStream();
ByteArrayOutputStream b = new ByteArrayOutputStream();
DataOutputStream handshake = new DataOutputStream(b);

handshake.writeByte(0);
writeVarInt(handshake, protocolVersion);
writeVarInt(handshake, this.host.getHostString().length());
handshake.writeBytes(this.host.getHostString());
handshake.writeShort(this.host.getPort());
writeVarInt(handshake, 1);

writeVarInt(dataOutputStream, b.size());
dataOutputStream.write(b.toByteArray());
dataOutputStream.writeByte(1);
dataOutputStream.writeByte(0);
DataInputStream dataInputStream = new DataInputStream(inputStream);

int size = readVarInt(dataInputStream);
int id = readVarInt(dataInputStream);
int length = readVarInt(dataInputStream);

if (size < 0 || id < 0 || length <= 0)
{
closeAll(b, dataInputStream, handshake, dataOutputStream, outputStream, inputStream, socket);
return null;
}

byte[] in = new byte[length];
dataInputStream.readFully(in);
closeAll(b, dataInputStream, handshake, dataOutputStream, outputStream, inputStream, socket);
return new String(in, StandardCharsets.UTF_8); //JSON
}

public void closeAll(Closeable... closeables) throws IOException
{
for (Closeable closeable : closeables)
{
closeable.close();
}
}
}
Loading

0 comments on commit 1d09fdd

Please sign in to comment.