diff --git a/G-Earth/src/main/java/gearth/protocol/HConnection.java b/G-Earth/src/main/java/gearth/protocol/HConnection.java index d802308..6c9018f 100644 --- a/G-Earth/src/main/java/gearth/protocol/HConnection.java +++ b/G-Earth/src/main/java/gearth/protocol/HConnection.java @@ -2,8 +2,10 @@ package gearth.protocol; import gearth.misc.Cacher; import gearth.misc.OSValidator; -import gearth.protocol.hostreplacer.HostReplacer; -import gearth.protocol.hostreplacer.HostReplacerFactory; +import gearth.protocol.hostreplacer.hostsfile.HostReplacer; +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.misc.ConnectionInfoOverrider; import gearth.protocol.packethandler.IncomingPacketHandler; @@ -15,6 +17,9 @@ import java.net.ServerSocket; import java.net.Socket; import java.net.UnknownHostException; import java.util.*; +import java.util.function.IntFunction; +import java.util.function.Predicate; +import java.util.stream.Stream; public class HConnection { @@ -65,6 +70,17 @@ public class HConnection { 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 autoDetectHosts; static { autoDetectHosts = new ArrayList<>(); @@ -102,7 +118,7 @@ public class HConnection { private static volatile ConnectionInfoOverrider connectionInfoOverrider; 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 volatile boolean hostRedirected = false; @@ -178,6 +194,9 @@ public class HConnection { private volatile Proxy actual_proxy = null; private volatile String hotelVersion = ""; + private volatile boolean rawIpMode = false; + + public State getState() { return state; } @@ -200,11 +219,22 @@ public class HConnection { List potentialHost = new ArrayList<>(); 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; } private void prepare(List allPotentialHosts) { + rawIpMode = false; setState(State.PREPARING); clearAllProxies(); actual_proxy = null; @@ -222,23 +252,25 @@ public class HConnection { for (String host : allPotentialHosts) { String[] split = host.split(":"); String input_dom = split[0]; - int port = Integer.parseInt(split[1]); - String actual_dom; + if (!hostIsIpAddress(input_dom)) { + int port = Integer.parseInt(split[1]); + String actual_dom; - InetAddress address = null; - try { - address = InetAddress.getByName(input_dom); - actual_dom = address.getHostAddress(); - } - catch (UnknownHostException e) { - willremove.add(host); - continue; - } + InetAddress address = null; + try { + address = InetAddress.getByName(input_dom); + actual_dom = address.getHostAddress(); + } + catch (UnknownHostException e) { + willremove.add(host); + continue; + } - int intercept_port = port; - String intercept_host = "127.0." + (c / 254) + "." + (1 + c % 254); - potentialProxies.add(new Proxy(input_dom, actual_dom, port, intercept_port, intercept_host)); - c++; + int intercept_port = port; + String intercept_host = "127.0." + (c / 254) + "." + (1 + c % 254); + potentialProxies.add(new Proxy(input_dom, actual_dom, port, intercept_port, intercept_host)); + c++; + } } List additionalCachedHotels = Cacher.getList(HOTELS_CACHE_KEY); @@ -254,15 +286,79 @@ public class HConnection { setState(State.PREPARED); } + private void startForRawIp() throws IOException { + + new Thread(() -> { + try { + Proxy proxy = potentialProxies.get(0); + Queue 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 { if (state == State.PREPARED) { setState(State.WAITING_FOR_CLIENT); + + if (rawIpMode) { + startForRawIp(); + return; + } + if (!hostRedirected && !connectionInfoOverrider.mustOverrideConnection()) { addToHosts(); } - for (int c = 0; c < potentialProxies.size(); c++) { Proxy potentialProxy = potentialProxies.get(c); @@ -282,7 +378,8 @@ public class HConnection { new Thread(() -> { 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) { // TODO Auto-generated catch block e.printStackTrace(); @@ -305,18 +402,16 @@ public class HConnection { 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]; - - Socket habbo_server = new Socket(proxy.actual_domain, proxy.actual_port); - habbo_server.setTcpNoDelay(true); + server.setTcpNoDelay(true); OutputStream client_out = client.getOutputStream(); InputStream client_in = client.getInputStream(); - OutputStream habbo_server_out = habbo_server.getOutputStream(); - InputStream habbo_server_in = habbo_server.getInputStream(); + OutputStream habbo_server_out = server.getOutputStream(); + 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]; Rc4Obtainer rc4Obtainer = new Rc4Obtainer(this); @@ -357,7 +452,7 @@ public class HConnection { if (habbo_server_in != null) habbo_server_in.close(); if (client_in != null) client_in.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(); aborted[0] = true; } catch (IOException e) { @@ -366,6 +461,9 @@ public class HConnection { if (datastream[0]) { setState(State.NOT_CONNECTED); proxy.verifyProxy(null, null); + if (rawIpMode) { + IpMapperFactory.get().deleteMapping(proxy.actual_domain); + } actual_proxy = null; }; } @@ -373,7 +471,7 @@ public class HConnection { // wachten op data van server new Thread(() -> { 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; while (habbo_server_in.available() > 0) { 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 (client_in != null) client_in.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(); aborted[0] = true; } catch (IOException e) { @@ -398,13 +496,12 @@ public class HConnection { } }).start(); - while(!aborted[0]) - { + while(!aborted[0]) { Thread.sleep(50); } try { - if (!habbo_server.isClosed()) habbo_server.close(); + if (!server.isClosed()) server.close(); if (!client.isClosed()) client.close(); if (DEBUG) System.out.println("STOP"); } @@ -412,18 +509,25 @@ public class HConnection { e.printStackTrace(); } } + + + private void onConnect() { - if (hostRedirected && !connectionInfoOverrider.mustOverrideConnection()) { + if (hostRedirected) { removeFromHosts(); } clearAllProxies(); } public void abort() { - if (hostRedirected && !connectionInfoOverrider.mustOverrideConnection()) { + if (hostRedirected) { removeFromHosts(); } + if (rawIpMode && actual_proxy != null) { + IpMapperFactory.get().deleteMapping(actual_proxy.actual_domain); + } + actual_proxy = null; setState(State.NOT_CONNECTED); @@ -578,4 +682,8 @@ public class HConnection { public static void setConnectionInfoOverrider(ConnectionInfoOverrider connectionInfoOverrider) { HConnection.connectionInfoOverrider = connectionInfoOverrider; } + + public boolean isRawIpMode() { + return rawIpMode; + } } diff --git a/G-Earth/src/main/java/gearth/protocol/hostreplacer/HostReplacer.java b/G-Earth/src/main/java/gearth/protocol/hostreplacer/hostsfile/HostReplacer.java similarity index 70% rename from G-Earth/src/main/java/gearth/protocol/hostreplacer/HostReplacer.java rename to G-Earth/src/main/java/gearth/protocol/hostreplacer/hostsfile/HostReplacer.java index 596fae7..dc4499e 100644 --- a/G-Earth/src/main/java/gearth/protocol/hostreplacer/HostReplacer.java +++ b/G-Earth/src/main/java/gearth/protocol/hostreplacer/hostsfile/HostReplacer.java @@ -1,4 +1,4 @@ -package gearth.protocol.hostreplacer; +package gearth.protocol.hostreplacer.hostsfile; public interface HostReplacer { diff --git a/G-Earth/src/main/java/gearth/protocol/hostreplacer/HostReplacerFactory.java b/G-Earth/src/main/java/gearth/protocol/hostreplacer/hostsfile/HostReplacerFactory.java similarity index 88% rename from G-Earth/src/main/java/gearth/protocol/hostreplacer/HostReplacerFactory.java rename to G-Earth/src/main/java/gearth/protocol/hostreplacer/hostsfile/HostReplacerFactory.java index a895828..9824e92 100644 --- a/G-Earth/src/main/java/gearth/protocol/hostreplacer/HostReplacerFactory.java +++ b/G-Earth/src/main/java/gearth/protocol/hostreplacer/hostsfile/HostReplacerFactory.java @@ -1,4 +1,4 @@ -package gearth.protocol.hostreplacer; +package gearth.protocol.hostreplacer.hostsfile; import gearth.misc.OSValidator; diff --git a/G-Earth/src/main/java/gearth/protocol/hostreplacer/UnixHostReplacer.java b/G-Earth/src/main/java/gearth/protocol/hostreplacer/hostsfile/UnixHostReplacer.java similarity index 97% rename from G-Earth/src/main/java/gearth/protocol/hostreplacer/UnixHostReplacer.java rename to G-Earth/src/main/java/gearth/protocol/hostreplacer/hostsfile/UnixHostReplacer.java index 80ed3d6..cc9ea5e 100644 --- a/G-Earth/src/main/java/gearth/protocol/hostreplacer/UnixHostReplacer.java +++ b/G-Earth/src/main/java/gearth/protocol/hostreplacer/hostsfile/UnixHostReplacer.java @@ -1,11 +1,11 @@ -package gearth.protocol.hostreplacer; +package gearth.protocol.hostreplacer.hostsfile; import java.io.*; import java.util.ArrayList; import java.util.List; /** - * Created by Jeunez on 04/04/18. + * Created by Jonas on 04/04/18. */ class UnixHostReplacer implements HostReplacer { diff --git a/G-Earth/src/main/java/gearth/protocol/hostreplacer/WindowsHostReplacer.java b/G-Earth/src/main/java/gearth/protocol/hostreplacer/hostsfile/WindowsHostReplacer.java similarity index 83% rename from G-Earth/src/main/java/gearth/protocol/hostreplacer/WindowsHostReplacer.java rename to G-Earth/src/main/java/gearth/protocol/hostreplacer/hostsfile/WindowsHostReplacer.java index 092c73f..9143f22 100644 --- a/G-Earth/src/main/java/gearth/protocol/hostreplacer/WindowsHostReplacer.java +++ b/G-Earth/src/main/java/gearth/protocol/hostreplacer/hostsfile/WindowsHostReplacer.java @@ -1,4 +1,4 @@ -package gearth.protocol.hostreplacer; +package gearth.protocol.hostreplacer.hostsfile; /** * Created by Jonas on 04/04/18. diff --git a/G-Earth/src/main/java/gearth/protocol/hostreplacer/ipmapping/EmptyIpMapper.java b/G-Earth/src/main/java/gearth/protocol/hostreplacer/ipmapping/EmptyIpMapper.java new file mode 100644 index 0000000..3b825f5 --- /dev/null +++ b/G-Earth/src/main/java/gearth/protocol/hostreplacer/ipmapping/EmptyIpMapper.java @@ -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 getCurrentMappings() { + return new ArrayList<>(); + } +} diff --git a/G-Earth/src/main/java/gearth/protocol/hostreplacer/ipmapping/IpMapper.java b/G-Earth/src/main/java/gearth/protocol/hostreplacer/ipmapping/IpMapper.java new file mode 100644 index 0000000..360bd95 --- /dev/null +++ b/G-Earth/src/main/java/gearth/protocol/hostreplacer/ipmapping/IpMapper.java @@ -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 getCurrentMappings(); + +} diff --git a/G-Earth/src/main/java/gearth/protocol/hostreplacer/ipmapping/IpMapperFactory.java b/G-Earth/src/main/java/gearth/protocol/hostreplacer/ipmapping/IpMapperFactory.java new file mode 100644 index 0000000..c70ff30 --- /dev/null +++ b/G-Earth/src/main/java/gearth/protocol/hostreplacer/ipmapping/IpMapperFactory.java @@ -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(); + } + +} diff --git a/G-Earth/src/main/java/gearth/protocol/hostreplacer/ipmapping/WindowsIpMapper.java b/G-Earth/src/main/java/gearth/protocol/hostreplacer/ipmapping/WindowsIpMapper.java new file mode 100644 index 0000000..c3acd5f --- /dev/null +++ b/G-Earth/src/main/java/gearth/protocol/hostreplacer/ipmapping/WindowsIpMapper.java @@ -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 getCurrentMappings() { + return new ArrayList<>(); + } +}