Support for retros with raw IP (not done yet)

This commit is contained in:
sirjonasxx 2020-04-25 03:37:31 +02:00
parent d64927178f
commit a8d70f16a1
9 changed files with 245 additions and 41 deletions

View File

@ -2,8 +2,10 @@ package gearth.protocol;
import gearth.misc.Cacher; import gearth.misc.Cacher;
import gearth.misc.OSValidator; import gearth.misc.OSValidator;
import gearth.protocol.hostreplacer.HostReplacer; import gearth.protocol.hostreplacer.hostsfile.HostReplacer;
import gearth.protocol.hostreplacer.HostReplacerFactory; import gearth.protocol.hostreplacer.hostsfile.HostReplacerFactory;
import gearth.protocol.hostreplacer.ipmapping.IpMapper;
import gearth.protocol.hostreplacer.ipmapping.IpMapperFactory;
import gearth.protocol.memory.Rc4Obtainer; import gearth.protocol.memory.Rc4Obtainer;
import gearth.protocol.misc.ConnectionInfoOverrider; import gearth.protocol.misc.ConnectionInfoOverrider;
import gearth.protocol.packethandler.IncomingPacketHandler; import gearth.protocol.packethandler.IncomingPacketHandler;
@ -15,6 +17,9 @@ import java.net.ServerSocket;
import java.net.Socket; import java.net.Socket;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.util.*; import java.util.*;
import java.util.function.IntFunction;
import java.util.function.Predicate;
import java.util.stream.Stream;
public class HConnection { public class HConnection {
@ -65,6 +70,17 @@ public class HConnection {
CONNECTED // CONNECTED CONNECTED // CONNECTED
} }
// checks if host is a raw IP instead of a domain
private static boolean hostIsIpAddress(String host){
for (char c : host.toCharArray()) {
if (c != '.' && (c < '0' || c > '9')) {
return false;
}
}
return true;
}
public static List<String> autoDetectHosts; public static List<String> autoDetectHosts;
static { static {
autoDetectHosts = new ArrayList<>(); autoDetectHosts = new ArrayList<>();
@ -102,7 +118,7 @@ public class HConnection {
private static volatile ConnectionInfoOverrider connectionInfoOverrider; private static volatile ConnectionInfoOverrider connectionInfoOverrider;
public static volatile boolean DECRYPTPACKETS = true; public static volatile boolean DECRYPTPACKETS = true;
public static volatile boolean DEBUG = false; public static volatile boolean DEBUG = true;
private static final HostReplacer hostsReplacer = HostReplacerFactory.get(); private static final HostReplacer hostsReplacer = HostReplacerFactory.get();
private volatile boolean hostRedirected = false; private volatile boolean hostRedirected = false;
@ -178,6 +194,9 @@ public class HConnection {
private volatile Proxy actual_proxy = null; private volatile Proxy actual_proxy = null;
private volatile String hotelVersion = ""; private volatile String hotelVersion = "";
private volatile boolean rawIpMode = false;
public State getState() { public State getState() {
return state; return state;
} }
@ -200,11 +219,22 @@ public class HConnection {
List<String> potentialHost = new ArrayList<>(); List<String> potentialHost = new ArrayList<>();
potentialHost.add(domain+":"+port); potentialHost.add(domain+":"+port);
prepare(potentialHost);
if (hostIsIpAddress(domain)) {
rawIpMode = true;
potentialProxies.clear();
potentialProxies.add(new Proxy(domain, domain, port, port, "0.0.0.0"));
setState(State.PREPARED);
}
else {
prepare(potentialHost);
}
actual_proxy = null; actual_proxy = null;
} }
private void prepare(List<String> allPotentialHosts) { private void prepare(List<String> allPotentialHosts) {
rawIpMode = false;
setState(State.PREPARING); setState(State.PREPARING);
clearAllProxies(); clearAllProxies();
actual_proxy = null; actual_proxy = null;
@ -222,23 +252,25 @@ public class HConnection {
for (String host : allPotentialHosts) { for (String host : allPotentialHosts) {
String[] split = host.split(":"); String[] split = host.split(":");
String input_dom = split[0]; String input_dom = split[0];
int port = Integer.parseInt(split[1]); if (!hostIsIpAddress(input_dom)) {
String actual_dom; int port = Integer.parseInt(split[1]);
String actual_dom;
InetAddress address = null; InetAddress address = null;
try { try {
address = InetAddress.getByName(input_dom); address = InetAddress.getByName(input_dom);
actual_dom = address.getHostAddress(); actual_dom = address.getHostAddress();
} }
catch (UnknownHostException e) { catch (UnknownHostException e) {
willremove.add(host); willremove.add(host);
continue; continue;
} }
int intercept_port = port; int intercept_port = port;
String intercept_host = "127.0." + (c / 254) + "." + (1 + c % 254); String intercept_host = "127.0." + (c / 254) + "." + (1 + c % 254);
potentialProxies.add(new Proxy(input_dom, actual_dom, port, intercept_port, intercept_host)); potentialProxies.add(new Proxy(input_dom, actual_dom, port, intercept_port, intercept_host));
c++; c++;
}
} }
List<Object> additionalCachedHotels = Cacher.getList(HOTELS_CACHE_KEY); List<Object> additionalCachedHotels = Cacher.getList(HOTELS_CACHE_KEY);
@ -254,15 +286,79 @@ public class HConnection {
setState(State.PREPARED); setState(State.PREPARED);
} }
private void startForRawIp() throws IOException {
new Thread(() -> {
try {
Proxy proxy = potentialProxies.get(0);
Queue<Socket> preConnectedServerConnections = new LinkedList<>();
for (int i = 0; i < 3; i++) {
preConnectedServerConnections.add(new Socket(proxy.actual_domain, proxy.actual_port));
Thread.sleep(80);
}
IpMapper ipMapper = IpMapperFactory.get();
ipMapper.enable();
ipMapper.addMapping(proxy.actual_domain);
if (DEBUG) System.out.println("Added mapping for raw IP");
ServerSocket proxy_server = new ServerSocket(proxy.getIntercept_port(), 10, InetAddress.getByName(proxy.getIntercept_host()));
proxy.initProxy(proxy_server);
if (DEBUG) System.out.println("");
Thread.sleep(30);
while ((state == State.WAITING_FOR_CLIENT) && !proxy_server.isClosed()) {
try {
if (DEBUG) System.out.println("try accept proxy");
Socket client = proxy_server.accept();
client.setTcpNoDelay(true);
actual_proxy = proxy;
if (DEBUG) System.out.println("accepted a proxy");
new Thread(() -> {
try {
if (preConnectedServerConnections.isEmpty()) {
if (DEBUG) System.out.println("pre-made server connections ran out of stock");
}
else {
startProxyThread(client, preConnectedServerConnections.poll(), actual_proxy);
}
} catch (InterruptedException | IOException e) {
e.printStackTrace();
}
}).start();
} catch (IOException e1) {
}
}
// if (proxy_server.isClosed()) {
// if (rawIpMode) {
// IpMapperFactory.get().deleteMapping(proxy.actual_domain);
// }
// }
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
public void start() throws IOException { public void start() throws IOException {
if (state == State.PREPARED) { if (state == State.PREPARED) {
setState(State.WAITING_FOR_CLIENT); setState(State.WAITING_FOR_CLIENT);
if (rawIpMode) {
startForRawIp();
return;
}
if (!hostRedirected && !connectionInfoOverrider.mustOverrideConnection()) { if (!hostRedirected && !connectionInfoOverrider.mustOverrideConnection()) {
addToHosts(); addToHosts();
} }
for (int c = 0; c < potentialProxies.size(); c++) { for (int c = 0; c < potentialProxies.size(); c++) {
Proxy potentialProxy = potentialProxies.get(c); Proxy potentialProxy = potentialProxies.get(c);
@ -282,7 +378,8 @@ public class HConnection {
new Thread(() -> { new Thread(() -> {
try { try {
startProxyThread(client, potentialProxy); Socket server = new Socket(actual_proxy.actual_domain, actual_proxy.actual_port);
startProxyThread(client, server, actual_proxy);
} catch (InterruptedException | IOException e) { } catch (InterruptedException | IOException e) {
// TODO Auto-generated catch block // TODO Auto-generated catch block
e.printStackTrace(); e.printStackTrace();
@ -305,18 +402,16 @@ public class HConnection {
if (DEBUG) System.out.println("done waiting for clients with: " + this.state ); if (DEBUG) System.out.println("done waiting for clients with: " + this.state );
} }
} }
private void startProxyThread(Socket client, Proxy proxy) throws InterruptedException, UnknownHostException, IOException { private void startProxyThread(Socket client, Socket server, Proxy proxy) throws InterruptedException, UnknownHostException, IOException {
final boolean[] datastream = new boolean[1]; final boolean[] datastream = new boolean[1];
server.setTcpNoDelay(true);
Socket habbo_server = new Socket(proxy.actual_domain, proxy.actual_port);
habbo_server.setTcpNoDelay(true);
OutputStream client_out = client.getOutputStream(); OutputStream client_out = client.getOutputStream();
InputStream client_in = client.getInputStream(); InputStream client_in = client.getInputStream();
OutputStream habbo_server_out = habbo_server.getOutputStream(); OutputStream habbo_server_out = server.getOutputStream();
InputStream habbo_server_in = habbo_server.getInputStream(); InputStream habbo_server_in = server.getInputStream();
if (DEBUG) System.out.println(habbo_server.getLocalAddress().getHostAddress() + ": " + habbo_server.getLocalPort()); if (DEBUG) System.out.println(server.getLocalAddress().getHostAddress() + ": " + server.getLocalPort());
final boolean[] aborted = new boolean[1]; final boolean[] aborted = new boolean[1];
Rc4Obtainer rc4Obtainer = new Rc4Obtainer(this); Rc4Obtainer rc4Obtainer = new Rc4Obtainer(this);
@ -357,7 +452,7 @@ public class HConnection {
if (habbo_server_in != null) habbo_server_in.close(); if (habbo_server_in != null) habbo_server_in.close();
if (client_in != null) client_in.close(); if (client_in != null) client_in.close();
if (client_out != null) client_out.close(); if (client_out != null) client_out.close();
if (habbo_server != null && !habbo_server.isClosed()) habbo_server.close(); if (server != null && !server.isClosed()) server.close();
if (client != null && !client.isClosed()) client.close(); if (client != null && !client.isClosed()) client.close();
aborted[0] = true; aborted[0] = true;
} catch (IOException e) { } catch (IOException e) {
@ -366,6 +461,9 @@ public class HConnection {
if (datastream[0]) { if (datastream[0]) {
setState(State.NOT_CONNECTED); setState(State.NOT_CONNECTED);
proxy.verifyProxy(null, null); proxy.verifyProxy(null, null);
if (rawIpMode) {
IpMapperFactory.get().deleteMapping(proxy.actual_domain);
}
actual_proxy = null; actual_proxy = null;
}; };
} }
@ -373,7 +471,7 @@ public class HConnection {
// wachten op data van server // wachten op data van server
new Thread(() -> { new Thread(() -> {
try { try {
while (!habbo_server.isClosed() && (state == State.CONNECTED || state == State.WAITING_FOR_CLIENT)) { while (!server.isClosed() && (state == State.CONNECTED || state == State.WAITING_FOR_CLIENT)) {
byte[] buffer; byte[] buffer;
while (habbo_server_in.available() > 0) { while (habbo_server_in.available() > 0) {
habbo_server_in.read(buffer = new byte[habbo_server_in.available()]); habbo_server_in.read(buffer = new byte[habbo_server_in.available()]);
@ -389,7 +487,7 @@ public class HConnection {
if (habbo_server_in != null) habbo_server_in.close(); if (habbo_server_in != null) habbo_server_in.close();
if (client_in != null) client_in.close(); if (client_in != null) client_in.close();
if (client_out != null) client_out.close(); if (client_out != null) client_out.close();
if (!habbo_server.isClosed()) habbo_server.close(); if (!server.isClosed()) server.close();
if (!client.isClosed()) client.close(); if (!client.isClosed()) client.close();
aborted[0] = true; aborted[0] = true;
} catch (IOException e) { } catch (IOException e) {
@ -398,13 +496,12 @@ public class HConnection {
} }
}).start(); }).start();
while(!aborted[0]) while(!aborted[0]) {
{
Thread.sleep(50); Thread.sleep(50);
} }
try { try {
if (!habbo_server.isClosed()) habbo_server.close(); if (!server.isClosed()) server.close();
if (!client.isClosed()) client.close(); if (!client.isClosed()) client.close();
if (DEBUG) System.out.println("STOP"); if (DEBUG) System.out.println("STOP");
} }
@ -412,18 +509,25 @@ public class HConnection {
e.printStackTrace(); e.printStackTrace();
} }
} }
private void onConnect() { private void onConnect() {
if (hostRedirected && !connectionInfoOverrider.mustOverrideConnection()) { if (hostRedirected) {
removeFromHosts(); removeFromHosts();
} }
clearAllProxies(); clearAllProxies();
} }
public void abort() { public void abort() {
if (hostRedirected && !connectionInfoOverrider.mustOverrideConnection()) { if (hostRedirected) {
removeFromHosts(); removeFromHosts();
} }
if (rawIpMode && actual_proxy != null) {
IpMapperFactory.get().deleteMapping(actual_proxy.actual_domain);
}
actual_proxy = null; actual_proxy = null;
setState(State.NOT_CONNECTED); setState(State.NOT_CONNECTED);
@ -578,4 +682,8 @@ public class HConnection {
public static void setConnectionInfoOverrider(ConnectionInfoOverrider connectionInfoOverrider) { public static void setConnectionInfoOverrider(ConnectionInfoOverrider connectionInfoOverrider) {
HConnection.connectionInfoOverrider = connectionInfoOverrider; HConnection.connectionInfoOverrider = connectionInfoOverrider;
} }
public boolean isRawIpMode() {
return rawIpMode;
}
} }

View File

@ -1,4 +1,4 @@
package gearth.protocol.hostreplacer; package gearth.protocol.hostreplacer.hostsfile;
public interface HostReplacer { public interface HostReplacer {

View File

@ -1,4 +1,4 @@
package gearth.protocol.hostreplacer; package gearth.protocol.hostreplacer.hostsfile;
import gearth.misc.OSValidator; import gearth.misc.OSValidator;

View File

@ -1,11 +1,11 @@
package gearth.protocol.hostreplacer; package gearth.protocol.hostreplacer.hostsfile;
import java.io.*; import java.io.*;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
* Created by Jeunez on 04/04/18. * Created by Jonas on 04/04/18.
*/ */
class UnixHostReplacer implements HostReplacer { class UnixHostReplacer implements HostReplacer {

View File

@ -1,4 +1,4 @@
package gearth.protocol.hostreplacer; package gearth.protocol.hostreplacer.hostsfile;
/** /**
* Created by Jonas on 04/04/18. * Created by Jonas on 04/04/18.

View File

@ -0,0 +1,27 @@
package gearth.protocol.hostreplacer.ipmapping;
import java.util.ArrayList;
import java.util.List;
// Temporary class for the sake of not getting nullpointers on linux&mac until they have an IpMapper as well
public class EmptyIpMapper implements IpMapper {
@Override
public void enable() {
}
@Override
public void addMapping(String ip) {
}
@Override
public void deleteMapping(String ip) {
}
@Override
public List<String> getCurrentMappings() {
return new ArrayList<>();
}
}

View File

@ -0,0 +1,16 @@
package gearth.protocol.hostreplacer.ipmapping;
import java.util.List;
// always map to 127.0.0.1, same port
public interface IpMapper {
void enable();
void addMapping(String ip);
void deleteMapping(String ip);
List<String> getCurrentMappings();
}

View File

@ -0,0 +1,14 @@
package gearth.protocol.hostreplacer.ipmapping;
import gearth.misc.OSValidator;
public class IpMapperFactory {
public static IpMapper get() {
if (OSValidator.isWindows()) return new WindowsIpMapper();
return new EmptyIpMapper();
}
}

View File

@ -0,0 +1,39 @@
package gearth.protocol.hostreplacer.ipmapping;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class WindowsIpMapper implements IpMapper {
private void runCommand(String... args) {
ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.command(args);
try {
processBuilder.start();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void enable() {
runCommand("netsh", "interface", "ip", "set", "dns", "1", "dhcp");
}
@Override
public void addMapping(String ip) {
runCommand("netsh", "interface", "ip", "add", "address", "\"Loopback\"", ip, "255.255.255.255");
}
@Override
public void deleteMapping(String ip) {
runCommand("netsh", "interface", "ip", "delete", "address", "\"Loopback\"", ip);
}
//todo implement
@Override
public List<String> getCurrentMappings() {
return new ArrayList<>();
}
}