diff --git a/src/main/java/fi/flexplex/connect/FlexConnect.java b/src/main/java/fi/flexplex/connect/FlexConnect.java index 077febe..19dd383 100644 --- a/src/main/java/fi/flexplex/connect/FlexConnect.java +++ b/src/main/java/fi/flexplex/connect/FlexConnect.java @@ -12,13 +12,13 @@ import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.plugin.java.JavaPlugin; import fi.flexplex.connect.util.FileChangeListener; +import fi.flexplex.connect.util.Proxy; import fi.flexplex.connect.util.Tunnel; -import fi.flexplex.connect.util.TunnelConnector; public final class FlexConnect extends JavaPlugin { - private final Set tunnelConnectors = new HashSet<>(); - private final Set proxyAddresses = new HashSet<>(); + private final Set tunnels = new HashSet<>(); + private final Set proxies = new HashSet<>(); private String token = ""; private FlexPlexGraphQLApi flexPlexGraphQLApi; @@ -31,8 +31,13 @@ public final class FlexConnect extends JavaPlugin { return this.flexPlexGraphQLApi; } - public Set getProxyAddresses() { - return this.proxyAddresses; + public boolean isIpAllowedToJoin(final String ip) { + for (final Proxy proxy : this.proxies) { + if (proxy.ipAllowedToJoin(ip)) { + return true; + } + } + return false; } @Override @@ -104,23 +109,28 @@ public final class FlexConnect extends JavaPlugin { this.flexPlexGraphQLApi.updateWhitelist(); // Load allowed proxy addresses from config - this.proxyAddresses.addAll(this.getConfig().getStringList("allowedProxies")); + for (final String host : this.getConfig().getStringList("allowedProxies")) { + this.proxies.add(new Proxy(host)); + } // Load tunnels and proxy addresses from FlexPlex API and start tunnels - final Set tunnels = new HashSet<>(); - tunnels.addAll(this.flexPlexGraphQLApi.getTunnels()); - for (final Tunnel tunnel : tunnels) { - this.proxyAddresses.add(tunnel.host); - final TunnelConnector connector = new TunnelConnector(this, tunnel); - this.tunnelConnectors.add(connector); - connector.start(); + // Load proxies from FlexPlex API + this.proxies.addAll(this.flexPlexGraphQLApi.getProxies()); + + // Open tunnels if there is any available + for (final Proxy proxy : this.proxies) { + if (proxy.hasTunnel()) { + final Tunnel tunnel = new Tunnel(this, proxy); + this.tunnels.add(tunnel); + tunnel.start(); + } } } @Override public void onDisable() { - for (final TunnelConnector connector : this.tunnelConnectors) { - connector.stop(); + for (final Tunnel tunnel : this.tunnels) { + tunnel.stop(); } } diff --git a/src/main/java/fi/flexplex/connect/FlexConnectListener.java b/src/main/java/fi/flexplex/connect/FlexConnectListener.java index 3307449..ac57d9a 100644 --- a/src/main/java/fi/flexplex/connect/FlexConnectListener.java +++ b/src/main/java/fi/flexplex/connect/FlexConnectListener.java @@ -21,7 +21,7 @@ public final class FlexConnectListener implements Listener { @EventHandler public void onPlayerLogin(final PlayerLoginEvent event) { final String ip = event.getRealAddress().getHostAddress(); - if (flexConnect.getProxyAddresses().contains(ip)) { + if (this.flexConnect.isIpAllowedToJoin(ip)) { // Connection is coming from allowed proxy return; } diff --git a/src/main/java/fi/flexplex/connect/FlexPlexGraphQLApi.java b/src/main/java/fi/flexplex/connect/FlexPlexGraphQLApi.java index 1b4beaf..e4aa7f2 100644 --- a/src/main/java/fi/flexplex/connect/FlexPlexGraphQLApi.java +++ b/src/main/java/fi/flexplex/connect/FlexPlexGraphQLApi.java @@ -16,7 +16,7 @@ import com.google.gson.JsonArray; import com.google.gson.JsonObject; import com.google.gson.JsonParser; -import fi.flexplex.connect.util.Tunnel; +import fi.flexplex.connect.util.Proxy; import org.bukkit.OfflinePlayer; @@ -30,8 +30,8 @@ public final class FlexPlexGraphQLApi { this.graphqlEndpoint = URI.create(graphQLEndpoint).toURL(); } - public Set getTunnels() { - final Set output = new HashSet<>(); + public Set getProxies() { + final Set output = new HashSet<>(); try { final HttpURLConnection conn = (HttpURLConnection) graphqlEndpoint.openConnection(); conn.setDoOutput(true); @@ -43,27 +43,26 @@ public final class FlexPlexGraphQLApi { final DataOutputStream wr = new DataOutputStream(conn.getOutputStream()); - wr.writeBytes("{\"query\":\"query{tunnels(token:\\\"" + this.flexConnect.getToken() + "\\\"){host,port,forwardingPort}}\"}"); + wr.writeBytes("{\"query\":\"query{proxies(token:\\\"" + this.flexConnect.getToken() + "\\\"){host,tunnelPort,forwardingPort}}\"}"); wr.flush(); wr.close(); final JsonObject response = (JsonObject) new JsonParser().parse(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8)); - if (response.get("data").getAsJsonObject().has("tunnels")) { - final JsonArray array = response.get("data").getAsJsonObject().get("tunnels").getAsJsonArray(); + if (response.get("data").getAsJsonObject().has("proxies")) { + final JsonArray array = response.get("data").getAsJsonObject().get("proxies").getAsJsonArray(); for (int i = 0; i < array.size(); i++) { - final JsonObject tunnel = array.get(i).getAsJsonObject(); - output.add(new Tunnel( - tunnel.get("host").getAsString(), - tunnel.get("port").getAsInt(), - tunnel.get("forwardingPort").getAsInt() - )); + final JsonObject proxy = array.get(i).getAsJsonObject(); + final Proxy p = new Proxy(proxy.get("host").getAsString()); + p.setForwardingPort(proxy.get("forwardingPort").getAsInt()); + p.setTunnelPort(proxy.get("tunnelPort").getAsInt()); + output.add(p); } } conn.disconnect(); } catch (final IOException e) { - this.flexConnect.getLogger().warning("Getting tunnels failed, propably connection to FlexPlex API server is down."); + this.flexConnect.getLogger().warning("Getting proxies failed, propably connection to FlexPlex API server is down."); } return output; } diff --git a/src/main/java/fi/flexplex/connect/util/Proxy.java b/src/main/java/fi/flexplex/connect/util/Proxy.java new file mode 100644 index 0000000..01aeff4 --- /dev/null +++ b/src/main/java/fi/flexplex/connect/util/Proxy.java @@ -0,0 +1,45 @@ +package fi.flexplex.connect.util; + +public final class Proxy { + + private final String host; + private int tunnelPort = -1; + private int forwardingPort = -1; + + public Proxy(final String host) { + this.host = host; + } + + public String getHost() { + return this.host; + } + + public int getTunnelPort() { + return this.tunnelPort; + } + + public int getForwardingPort() { + return this.forwardingPort; + } + + public void setTunnelPort(final int port) { + this.tunnelPort = port; + } + + public void setForwardingPort(final int port) { + this.forwardingPort = port; + } + + public boolean hasTunnel() { + return this.tunnelPort != -1 && this.forwardingPort != -1; + } + + public boolean ipAllowedToJoin(final String ip) { + if (this.hasTunnel()) { + return "0:0:0:0:0:0:0:1%0".equals(ip); + } else { + return ip.equals(this.host); + } + } + +} diff --git a/src/main/java/fi/flexplex/connect/util/Tunnel.java b/src/main/java/fi/flexplex/connect/util/Tunnel.java index 4c91b81..922d89f 100644 --- a/src/main/java/fi/flexplex/connect/util/Tunnel.java +++ b/src/main/java/fi/flexplex/connect/util/Tunnel.java @@ -1,15 +1,83 @@ package fi.flexplex.connect.util; +import java.io.IOException; +import java.util.concurrent.TimeUnit; + +import org.apache.sshd.client.SshClient; +import org.apache.sshd.client.future.ConnectFuture; +import org.apache.sshd.client.session.ClientSession; +import org.apache.sshd.client.session.forward.PortForwardingTracker; +import org.apache.sshd.common.util.net.SshdSocketAddress; +import org.bukkit.Bukkit; + +import fi.flexplex.connect.FlexConnect; + public final class Tunnel { - public final String host; - public final int port; - public final int forwardingPort; + private final FlexConnect flexConnect; + private final Proxy proxy; + private final Thread thread; + private final SshClient client = SshClient.setUpDefaultClient(); + private boolean isRunning = false; - public Tunnel(final String host, final int port, final int forwardingPort) { - this.host = host; - this.port = port; - this.forwardingPort = forwardingPort; + public Tunnel(final FlexConnect flexConnect, final Proxy proxy) { + this.flexConnect = flexConnect; + this.proxy = proxy; + this.client.setForwardingFilter(new TunnelForwardingFilter()); + this.thread = new Thread() { + @Override + public void run() { + while (isRunning) { + session(); + flexConnect.getLogger().warning("Tunnel session ended. Trying to reconnect in 10 seconds"); + try { + Thread.sleep(10_000); + } catch (final InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + } + }; + } + + public void start() { + this.isRunning = true; + this.thread.start(); + } + + public void stop() { + this.isRunning = false; + this.client.stop(); + } + + private void session() { + this.flexConnect.getLogger().info("Tunnel connecting to " + this.proxy.getHost() + ":" + this.proxy.getTunnelPort()); + try { + client.start(); + + final ConnectFuture cf = client.connect("FlexConnect", this.proxy.getHost(), this.proxy.getTunnelPort()); + final ClientSession session = cf.verify().getSession(); + + session.addPasswordIdentity(flexConnect.getToken()); + session.auth().verify(TimeUnit.SECONDS.toMillis(5)); + + final SshdSocketAddress remote = new SshdSocketAddress("127.0.0.1", this.proxy.getForwardingPort()); + final SshdSocketAddress local = new SshdSocketAddress(Bukkit.getPort()); + + try (PortForwardingTracker tracker = session.createRemotePortForwardingTracker(remote, local)) { + this.flexConnect.getLogger().info("Tunnel successfully connected " + this.proxy.getHost() + ":" + this.proxy.getTunnelPort()); + while (isRunning) { + Thread.sleep(5000); + if (session.isClosed()) { + break; + } + } + } catch (final InterruptedException e) { + Thread.currentThread().interrupt(); + } + } catch (final IOException e) { + this.flexConnect.getLogger().warning(e.getMessage()); + } } } diff --git a/src/main/java/fi/flexplex/connect/util/TunnelConnector.java b/src/main/java/fi/flexplex/connect/util/TunnelConnector.java deleted file mode 100644 index fd6eccb..0000000 --- a/src/main/java/fi/flexplex/connect/util/TunnelConnector.java +++ /dev/null @@ -1,83 +0,0 @@ -package fi.flexplex.connect.util; - -import java.io.IOException; -import java.util.concurrent.TimeUnit; - -import org.apache.sshd.client.SshClient; -import org.apache.sshd.client.future.ConnectFuture; -import org.apache.sshd.client.session.ClientSession; -import org.apache.sshd.client.session.forward.PortForwardingTracker; -import org.apache.sshd.common.util.net.SshdSocketAddress; -import org.bukkit.Bukkit; - -import fi.flexplex.connect.FlexConnect; - -public final class TunnelConnector { - - private final FlexConnect flexConnect; - private final Tunnel tunnel; - private final Thread thread; - private final SshClient client = SshClient.setUpDefaultClient(); - private boolean isRunning = false; - - public TunnelConnector(final FlexConnect flexConnect, final Tunnel tunnel) { - this.flexConnect = flexConnect; - this.tunnel = tunnel; - this.client.setForwardingFilter(new TunnelForwardingFilter()); - this.thread = new Thread() { - @Override - public void run() { - while (isRunning) { - session(); - flexConnect.getLogger().warning("Tunnel session ended. Trying to reconnect in 10 seconds"); - try { - Thread.sleep(10_000); - } catch (final InterruptedException e) { - Thread.currentThread().interrupt(); - } - } - } - }; - } - - public void start() { - this.isRunning = true; - this.thread.start(); - } - - public void stop() { - this.isRunning = false; - this.client.stop(); - } - - private void session() { - this.flexConnect.getLogger().info("Tunnel connecting to " + this.tunnel.host + ":" + this.tunnel.port); - try { - client.start(); - - final ConnectFuture cf = client.connect("FlexConnect", this.tunnel.host, this.tunnel.port); - final ClientSession session = cf.verify().getSession(); - - session.addPasswordIdentity(flexConnect.getToken()); - session.auth().verify(TimeUnit.SECONDS.toMillis(5)); - - final SshdSocketAddress remote = new SshdSocketAddress("127.0.0.1", this.tunnel.forwardingPort); - final SshdSocketAddress local = new SshdSocketAddress(Bukkit.getPort()); - - try (PortForwardingTracker tracker = session.createRemotePortForwardingTracker(remote, local)) { - this.flexConnect.getLogger().info("Tunnel successfully connected " + this.tunnel.host + ":" + this.tunnel.port); - while (isRunning) { - Thread.sleep(5000); - if (session.isClosed()) { - break; - } - } - } catch (final InterruptedException e) { - Thread.currentThread().interrupt(); - } - } catch (final IOException e) { - this.flexConnect.getLogger().warning(e.getMessage()); - } - } - -}