package gearth.protocol.connection.proxy.windows; import gearth.misc.Cacher; import gearth.protocol.HConnection; import gearth.protocol.connection.HProxy; import gearth.protocol.connection.HProxySetter; import gearth.protocol.connection.HState; import gearth.protocol.connection.HStateSetter; import gearth.protocol.connection.proxy.ProxyProvider; import gearth.protocol.connection.proxy.unix.LinuxRawIpProxyProvider; import gearth.protocol.hostreplacer.ipmapping.IpMapper; import gearth.protocol.hostreplacer.ipmapping.IpMapperFactory; import javafx.application.Platform; import javafx.scene.control.Alert; import javafx.scene.control.ButtonType; import javafx.scene.layout.Region; import org.json.JSONObject; import java.io.IOException; import java.math.BigInteger; import java.net.*; import java.util.LinkedList; import java.util.Queue; import java.util.UUID; // windows raw ip proxy provider extends the Linux one with the exception that it does not want to close // the IP redirect on connect public class WindowsRawIpProxyProvider extends LinuxRawIpProxyProvider { private boolean hasMapped = false; public WindowsRawIpProxyProvider(HProxySetter proxySetter, HStateSetter stateSetter, HConnection hConnection, String input_host, int input_port, boolean useSocks) { super(proxySetter, stateSetter, hConnection, input_host, input_port, useSocks); } @Override protected void onConnect() { //NOTE: DOES NOT CALL SUPER METHOD stateSetter.setState(HState.CONNECTED); tryCloseProxy(); } protected void maybeAddMapping() { if (!hasMapped) { hasMapped = true; if (isNoneConnected()) { ipMapper.enable(); ipMapper.addMapping(proxy.getActual_domain(), proxy.getActual_port(), proxy.getIntercept_port()); } addMappingCache(); } } protected void maybeRemoveMapping() { if (hasMapped) { hasMapped = false; removeMappingCache(); if (isNoneConnected()) { ipMapper.deleteMapping(proxy.getActual_domain(), proxy.getActual_port(), proxy.getIntercept_port()); } } } private static final UUID INSTANCE_ID = UUID.randomUUID(); private static final String RAWIP_CONNECTIONS = "rawip_connections"; // let other G-Earth instances know you're connected private void addMappingCache() { new Thread(() -> { while (hasMapped) { updateMappingCache(); try { Thread.sleep(55000); } catch (InterruptedException ignored) {} } }).start(); } // checks if no G-Earth instances are connected // every G-Earth instance is supposed to update if it's still connected every 60 seconds private boolean isNoneConnected() { return isNoneConnected(proxy.getActual_domain()); } private void updateMappingCache() { JSONObject connections = getCurrentConnectionsCache(); JSONObject instance = new JSONObject(); instance.put("timestamp", BigInteger.valueOf(System.currentTimeMillis())); connections.put(INSTANCE_ID.toString(), instance); saveCurrentConnectionsCache(connections); } private void removeMappingCache() { JSONObject connections = getCurrentConnectionsCache(); connections.remove(INSTANCE_ID.toString()); saveCurrentConnectionsCache(connections); } private JSONObject getCurrentConnectionsCache() { return getCurrentConnectionsCache(proxy.getActual_domain()); } private void saveCurrentConnectionsCache(JSONObject connections) { if (!Cacher.getCacheContents().has(proxy.getActual_domain())) { Cacher.put(RAWIP_CONNECTIONS, new JSONObject()); } JSONObject gearthConnections = Cacher.getCacheContents().getJSONObject(RAWIP_CONNECTIONS); gearthConnections.put(proxy.getActual_domain(), connections); Cacher.put(RAWIP_CONNECTIONS, gearthConnections); } private static JSONObject getCurrentConnectionsCache(String actual_host) { if (!Cacher.getCacheContents().has(RAWIP_CONNECTIONS)) { Cacher.put(RAWIP_CONNECTIONS, new JSONObject()); } JSONObject gearthConnections = Cacher.getCacheContents().getJSONObject(RAWIP_CONNECTIONS); if (!gearthConnections.has(actual_host)) { gearthConnections.put(actual_host, new JSONObject()); Cacher.put(RAWIP_CONNECTIONS, gearthConnections); } return gearthConnections.getJSONObject(actual_host); } public static boolean isNoneConnected(String actual_host) { JSONObject connections = getCurrentConnectionsCache(actual_host); BigInteger timeoutTimestamp = BigInteger.valueOf(System.currentTimeMillis() - 60000); for (String key : connections.keySet()) { JSONObject connection = connections.getJSONObject(key); if (!key.equals(INSTANCE_ID.toString())) { if (connection.getBigInteger("timestamp").compareTo(timeoutTimestamp) > 0) { return false; } } } return true; } }