diff --git a/eaglercraftbungee/src/main/java/net/md_5/bungee/BungeeCord.java b/eaglercraftbungee/src/main/java/net/md_5/bungee/BungeeCord.java index 2eead0f..d534da1 100644 --- a/eaglercraftbungee/src/main/java/net/md_5/bungee/BungeeCord.java +++ b/eaglercraftbungee/src/main/java/net/md_5/bungee/BungeeCord.java @@ -61,6 +61,10 @@ import net.md_5.bungee.command.CommandPerms; import net.md_5.bungee.command.CommandBungee; import net.md_5.bungee.command.CommandClearRatelimit; import net.md_5.bungee.command.CommandConfirmCode; +import net.md_5.bungee.command.CommandDomain; +import net.md_5.bungee.command.CommandDomainBlock; +import net.md_5.bungee.command.CommandDomainBlockDomain; +import net.md_5.bungee.command.CommandDomainUnblock; import net.md_5.bungee.command.CommandAlert; import net.md_5.bungee.command.CommandIP; import net.md_5.bungee.command.CommandServer; @@ -72,6 +76,7 @@ import net.md_5.bungee.command.CommandReload; import net.md_5.bungee.scheduler.BungeeScheduler; import net.md_5.bungee.config.YamlConfig; import net.md_5.bungee.eaglercraft.BanList; +import net.md_5.bungee.eaglercraft.DomainBlacklist; import net.md_5.bungee.eaglercraft.PluginEaglerSkins; import net.md_5.bungee.eaglercraft.WebSocketListener; @@ -156,6 +161,10 @@ public class BungeeCord extends ProxyServer { this.getPluginManager().registerCommand(null, new CommandFind()); this.getPluginManager().registerCommand(null, new CommandClearRatelimit()); this.getPluginManager().registerCommand(null, new CommandConfirmCode()); + this.getPluginManager().registerCommand(null, new CommandDomain()); + this.getPluginManager().registerCommand(null, new CommandDomainBlock()); + this.getPluginManager().registerCommand(null, new CommandDomainBlockDomain()); + this.getPluginManager().registerCommand(null, new CommandDomainUnblock()); this.registerChannel("BungeeCord"); Log.setOutput(new PrintStream(ByteStreams.nullOutputStream())); AnsiConsole.systemInstall(); @@ -243,9 +252,11 @@ public class BungeeCord extends ProxyServer { BanList.maybeReloadBans(null); } }, 0L, TimeUnit.SECONDS.toMillis(3L)); + DomainBlacklist.init(); this.closeInactiveSockets.scheduleAtFixedRate(new TimerTask() { @Override public void run() { + DomainBlacklist.update(); for(WebSocketListener lst : BungeeCord.this.wsListeners) { lst.closeInactiveSockets(); ListenerInfo info = lst.getInfo(); diff --git a/eaglercraftbungee/src/main/java/net/md_5/bungee/api/config/ConfigurationAdapter.java b/eaglercraftbungee/src/main/java/net/md_5/bungee/api/config/ConfigurationAdapter.java index f976d20..29e2eb6 100644 --- a/eaglercraftbungee/src/main/java/net/md_5/bungee/api/config/ConfigurationAdapter.java +++ b/eaglercraftbungee/src/main/java/net/md_5/bungee/api/config/ConfigurationAdapter.java @@ -23,6 +23,10 @@ public interface ConfigurationAdapter { Collection getGroups(final String p0); Collection getPermissions(final String p0); + + Collection getBlacklistURLs(); + + boolean getBlacklistOfflineDownload(); AuthServiceInfo getAuthSettings(); diff --git a/eaglercraftbungee/src/main/java/net/md_5/bungee/command/CommandDomain.java b/eaglercraftbungee/src/main/java/net/md_5/bungee/command/CommandDomain.java new file mode 100644 index 0000000..041d1f4 --- /dev/null +++ b/eaglercraftbungee/src/main/java/net/md_5/bungee/command/CommandDomain.java @@ -0,0 +1,37 @@ +package net.md_5.bungee.command; + +import net.md_5.bungee.api.ChatColor; +import net.md_5.bungee.api.CommandSender; +import net.md_5.bungee.api.ProxyServer; +import net.md_5.bungee.api.connection.ProxiedPlayer; +import net.md_5.bungee.api.plugin.Command; + +public class CommandDomain extends Command { + + public CommandDomain() { + super("domain", "bungeecord.command.eag.domain"); + } + + @Override + public void execute(CommandSender p0, String[] p1) { + if (p1.length < 1) { + p0.sendMessage(ChatColor.RED + "Please follow this command by a user name"); + return; + } + final ProxiedPlayer user = ProxyServer.getInstance().getPlayer(p1[0]); + if (user == null) { + p0.sendMessage(ChatColor.RED + "That user is not online"); + } else { + Object o = user.getAttachment().get("origin"); + if(o != null) { + p0.sendMessage(ChatColor.BLUE + "Domain of " + p1[0] + " is " + o); + if(p0.hasPermission("bungeecord.command.eag.blockdomain")) { + p0.sendMessage(ChatColor.BLUE + "Type " + ChatColor.WHITE + "/block-domain " + p1[0] + ChatColor.BLUE + " to block this person"); + } + }else { + p0.sendMessage(ChatColor.RED + "Domain of " + p1[0] + " is unknown"); + } + } + } + +} diff --git a/eaglercraftbungee/src/main/java/net/md_5/bungee/command/CommandDomainBlock.java b/eaglercraftbungee/src/main/java/net/md_5/bungee/command/CommandDomainBlock.java new file mode 100644 index 0000000..983b8e6 --- /dev/null +++ b/eaglercraftbungee/src/main/java/net/md_5/bungee/command/CommandDomainBlock.java @@ -0,0 +1,38 @@ +package net.md_5.bungee.command; + +import net.md_5.bungee.api.ChatColor; +import net.md_5.bungee.api.CommandSender; +import net.md_5.bungee.api.ProxyServer; +import net.md_5.bungee.api.connection.ProxiedPlayer; +import net.md_5.bungee.api.plugin.Command; +import net.md_5.bungee.eaglercraft.DomainBlacklist; + +public class CommandDomainBlock extends Command { + + public CommandDomainBlock() { + super("block-domain", "bungeecord.command.eag.blockdomain"); + } + + @Override + public void execute(CommandSender p0, String[] p1) { + if (p1.length < 1) { + p0.sendMessage(ChatColor.RED + "Please follow this command by a username"); + return; + } + final ProxiedPlayer user = ProxyServer.getInstance().getPlayer(p1[0]); + if (user == null) { + p0.sendMessage(ChatColor.RED + "That user is not online"); + }else { + Object o = user.getAttachment().get("origin"); + if(o != null) { + DomainBlacklist.addLocal((String)o); + p0.sendMessage(ChatColor.RED + "Domain of " + ChatColor.WHITE + p1[0] + ChatColor.RED + " is " + ChatColor.WHITE + o); + p0.sendMessage(ChatColor.RED + "It was added to the local block list."); + user.disconnect("client blocked"); + }else { + p0.sendMessage(ChatColor.RED + "Domain of " + p1[0] + " is unknown"); + } + } + } + +} diff --git a/eaglercraftbungee/src/main/java/net/md_5/bungee/command/CommandDomainBlockDomain.java b/eaglercraftbungee/src/main/java/net/md_5/bungee/command/CommandDomainBlockDomain.java new file mode 100644 index 0000000..8533de8 --- /dev/null +++ b/eaglercraftbungee/src/main/java/net/md_5/bungee/command/CommandDomainBlockDomain.java @@ -0,0 +1,24 @@ +package net.md_5.bungee.command; + +import net.md_5.bungee.api.ChatColor; +import net.md_5.bungee.api.CommandSender; +import net.md_5.bungee.api.plugin.Command; +import net.md_5.bungee.eaglercraft.DomainBlacklist; + +public class CommandDomainBlockDomain extends Command { + + public CommandDomainBlockDomain() { + super("block-domain-name", "bungeecord.command.eag.blockdomainname"); + } + + @Override + public void execute(CommandSender p0, String[] p1) { + if (p1.length < 1) { + p0.sendMessage(ChatColor.RED + "Please follow this command by a domain"); + return; + } + DomainBlacklist.addLocal(p1[0]); + p0.sendMessage(ChatColor.GREEN + "The domain '" + ChatColor.WHITE + p1[0] + ChatColor.GREEN + "' was added to the block list"); + } + +} diff --git a/eaglercraftbungee/src/main/java/net/md_5/bungee/command/CommandDomainUnblock.java b/eaglercraftbungee/src/main/java/net/md_5/bungee/command/CommandDomainUnblock.java new file mode 100644 index 0000000..2a0ab1b --- /dev/null +++ b/eaglercraftbungee/src/main/java/net/md_5/bungee/command/CommandDomainUnblock.java @@ -0,0 +1,27 @@ +package net.md_5.bungee.command; + +import net.md_5.bungee.api.ChatColor; +import net.md_5.bungee.api.CommandSender; +import net.md_5.bungee.api.plugin.Command; +import net.md_5.bungee.eaglercraft.DomainBlacklist; + +public class CommandDomainUnblock extends Command { + + public CommandDomainUnblock() { + super("unblock-domain", "bungeecord.command.eag.unblockdomain", "unblock-domain-name"); + } + + @Override + public void execute(CommandSender p0, String[] p1) { + if (p1.length < 1) { + p0.sendMessage(ChatColor.RED + "Please follow this command by a domain"); + return; + } + if(DomainBlacklist.removeLocal(p1[0])) { + p0.sendMessage(ChatColor.GREEN + "The domain '" + p1[0] + "' was removed from the local block list"); + }else { + p0.sendMessage(ChatColor.RED + "The domain was not removed, is it on the block list? Check '" + DomainBlacklist.localBlacklist.getName() + "' in your bungeecord directory"); + } + } + +} diff --git a/eaglercraftbungee/src/main/java/net/md_5/bungee/config/YamlConfig.java b/eaglercraftbungee/src/main/java/net/md_5/bungee/config/YamlConfig.java index 4bd1d15..149df64 100644 --- a/eaglercraftbungee/src/main/java/net/md_5/bungee/config/YamlConfig.java +++ b/eaglercraftbungee/src/main/java/net/md_5/bungee/config/YamlConfig.java @@ -70,10 +70,11 @@ public class YamlConfig implements ConfigurationAdapter { } final Map permissions = this.get("permissions", new HashMap()); if (permissions.isEmpty()) { - permissions.put("default", Arrays.asList("bungeecord.command.server", "bungeecord.command.list")); + permissions.put("default", Arrays.asList("bungeecord.command.server", "bungeecord.command.list", "bungeecord.command.eag.domain")); permissions.put("admin", Arrays.asList("bungeecord.command.alert", "bungeecord.command.end", "bungeecord.command.ip", "bungeecord.command.reload", "bungeecord.command.eag.ban", "bungeecord.command.eag.banwildcard", "bungeecord.command.eag.banip", "bungeecord.command.eag.banregex", - "bungeecord.command.eag.reloadban", "bungeecord.command.eag.banned", "bungeecord.command.eag.banlist", "bungeecord.command.eag.unban", "bungeecord.command.eag.ratelimit")); + "bungeecord.command.eag.reloadban", "bungeecord.command.eag.banned", "bungeecord.command.eag.banlist", "bungeecord.command.eag.unban", "bungeecord.command.eag.ratelimit", + "bungeecord.command.eag.blockdomain", "bungeecord.command.eag.blockdomainname", "bungeecord.command.eag.unblockdomain")); } this.get("groups", new HashMap()); } @@ -287,5 +288,26 @@ public class YamlConfig implements ConfigurationAdapter { public void forceSave() { this.save(); } + + @Override + public Collection getBlacklistURLs() { + boolean blacklistEnable = this.getBoolean("enable_origin_blacklist", true); + if(!blacklistEnable) { + return null; + } + Collection c = this.get("origin_blacklist_subscriptions", null); + if(c == null) { + c = new ArrayList(); + c.add("https://g.eags.us/eaglercraft/origin_blacklist.txt"); + c.add("https://raw.githubusercontent.com/LAX1DUDE/eaglercraft/main/stable-download/origin_blacklist.txt"); + c = this.get("origin_blacklist_subscriptions", c); + } + return c; + } + + @Override + public boolean getBlacklistOfflineDownload() { + return this.getBoolean("enable_offline_download_blacklist", false); + } } diff --git a/eaglercraftbungee/src/main/java/net/md_5/bungee/connection/InitialHandler.java b/eaglercraftbungee/src/main/java/net/md_5/bungee/connection/InitialHandler.java index 75f5c5a..0909e1b 100644 --- a/eaglercraftbungee/src/main/java/net/md_5/bungee/connection/InitialHandler.java +++ b/eaglercraftbungee/src/main/java/net/md_5/bungee/connection/InitialHandler.java @@ -139,31 +139,39 @@ public class InitialHandler extends PacketHandler implements PendingConnection { } InetAddress sc = WebSocketProxy.localToRemote.get(this.ch.getHandle().remoteAddress()); if(sc == null) { - System.out.println("WARNING: player '" + un + "' doesn't have a websocket IP, remote address: " + this.ch.getHandle().remoteAddress().toString()); + this.bungee.getLogger().log(Level.WARNING, "player '" + un + "' doesn't have a websocket IP, remote address: " + this.ch.getHandle().remoteAddress().toString()); }else { BanCheck bc = BanList.checkIpBanned(sc); if(bc.isBanned()) { - System.err.println("Player '" + un + "' [" + sc.toString() + "] is banned by IP: " + bc.match + " (" + bc.string + ")"); + this.bungee.getLogger().log(Level.SEVERE, "Player '" + un + "' [" + sc.toString() + "] is banned by IP: " + bc.match + " (" + bc.string + ")"); this.disconnect("" + ChatColor.RED + "You are banned.\n" + ChatColor.DARK_GRAY + "Reason: " + bc.string); return; }else { - System.out.println("Player '" + un + "' [" + sc.toString() + "] has remote websocket IP: " + sc.getHostAddress()); + this.bungee.getLogger().log(Level.INFO, "Player '" + un + "' [" + sc.toString() + "] has remote websocket IP: " + sc.getHostAddress()); + } + } + String dnm = WebSocketProxy.origins.get(this.ch.getHandle().remoteAddress()); + if(dnm != null) { + if(dnm.equalsIgnoreCase("null")) { + this.bungee.getLogger().log(Level.INFO, "Player '" + un + "' [" + sc.toString() + "] is using an offline download"); + }else { + this.bungee.getLogger().log(Level.INFO, "Player '" + un + "' [" + sc.toString() + "] is using a client at: " + dnm); } } BanCheck bc = BanList.checkBanned(un); if(bc.isBanned()) { switch(bc.reason) { case USER_BANNED: - System.err.println("Player '" + un + "' is banned by username, because '" + bc.string + "'"); + this.bungee.getLogger().log(Level.SEVERE, "Player '" + un + "' is banned by username, because '" + bc.string + "'"); break; case WILDCARD_BANNED: - System.err.println("Player '" + un + "' is banned by wildcard: " + bc.match); + this.bungee.getLogger().log(Level.SEVERE, "Player '" + un + "' is banned by wildcard: " + bc.match); break; case REGEX_BANNED: - System.err.println("Player '" + un + "' is banned by regex: " + bc.match); + this.bungee.getLogger().log(Level.SEVERE, "Player '" + un + "' is banned by regex: " + bc.match); break; default: - System.err.println("Player '" + un + "' is banned: " + bc.string); + this.bungee.getLogger().log(Level.SEVERE, "Player '" + un + "' is banned: " + bc.string); } if(bc.reason == BanState.USER_BANNED || ((BungeeCord)bungee).config.shouldShowBanType()) { this.disconnect("" + ChatColor.RED + "You are banned.\n" + ChatColor.DARK_GRAY + "Reason: " + bc.string); @@ -242,6 +250,10 @@ public class InitialHandler extends PacketHandler implements PendingConnection { if(ins != null) { userCon.getAttachment().put("remoteAddr", ins); } + String origin = WebSocketProxy.origins.get(this.ch.getHandle().remoteAddress()); + if(origin != null) { + userCon.getAttachment().put("origin", origin); + } userCon.init(); this.bungee.getPluginManager().callEvent(new PostLoginEvent(userCon)); ((HandlerBoss) this.ch.getHandle().pipeline().get((Class) HandlerBoss.class)).setHandler(new UpstreamBridge(this.bungee, userCon)); diff --git a/eaglercraftbungee/src/main/java/net/md_5/bungee/eaglercraft/DomainBlacklist.java b/eaglercraftbungee/src/main/java/net/md_5/bungee/eaglercraft/DomainBlacklist.java new file mode 100644 index 0000000..ae00f1d --- /dev/null +++ b/eaglercraftbungee/src/main/java/net/md_5/bungee/eaglercraft/DomainBlacklist.java @@ -0,0 +1,249 @@ +package net.md_5.bungee.eaglercraft; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +import net.md_5.bungee.BungeeCord; + +public class DomainBlacklist { + + public static final Collection regexBlacklist = new HashSet(); + public static final Collection regexLocalBlacklist = new HashSet(); + public static final File localBlacklist = new File("origin_blacklist.txt"); + private static final HashSet brokenURLs = new HashSet(); + private static final HashSet brokenRegex = new HashSet(); + + private static int updateRate = 15 * 60 * 1000; + private static long lastLocalUpdate = 0l; + private static long lastUpdate = 0; + + public static boolean test(String origin) { + synchronized(regexBlacklist) { + if(origin.equalsIgnoreCase("null") && BungeeCord.getInstance().getConfigurationAdapter().getBlacklistOfflineDownload()) { + return true; + } + for(Pattern m : regexBlacklist) { + if(m.matcher(origin).matches()) { + return true; + } + } + for(Pattern m : regexLocalBlacklist) { + if(m.matcher(origin).matches()) { + return true; + } + } + } + return false; + } + + public static void init() { + synchronized(regexBlacklist) { + brokenURLs.clear(); + brokenRegex.clear(); + regexBlacklist.clear(); + regexLocalBlacklist.clear(); + lastLocalUpdate = 0l; + lastUpdate = System.currentTimeMillis() - updateRate - 1000l; + update(); + } + } + + public static void update() { + long ct = System.currentTimeMillis(); + if((int)(ct - lastUpdate) > updateRate) { + lastUpdate = ct; + synchronized(regexBlacklist) { + Collection blurls = BungeeCord.getInstance().getConfigurationAdapter().getBlacklistURLs(); + if(blurls != null) { + ArrayList newBlacklist = new ArrayList(); + HashSet newBlacklistSet = new HashSet(); + for(String str : blurls) { + try { + URL u; + try { + u = new URL(str); + }catch(MalformedURLException e) { + if(brokenURLs.add(str)) { + System.err.println("ERROR: the blacklist subscription URL '" + str + "' is invalid"); + } + continue; + } + URLConnection cc = u.openConnection(); + if(cc instanceof HttpURLConnection) { + HttpURLConnection ccc = (HttpURLConnection)cc; + ccc.setRequestProperty("Accept", "text/plain,text/html,application/xhtml+xml,application/xml"); + ccc.setRequestProperty("User-Agent", "Mozilla/5.0 EaglercraftBungee/" + EaglercraftBungee.version); + } + cc.connect(); + BufferedReader is = new BufferedReader(new InputStreamReader(cc.getInputStream())); + String firstLine = is.readLine(); + if(firstLine == null) { + is.close(); + throw new IOException("Could not read line"); + } + firstLine = firstLine.trim(); + if(!firstLine.startsWith("#") || !firstLine.substring(1).trim().toLowerCase().startsWith("eaglercraft domain blacklist")) { + throw new IOException("File does not contain a list of domains"); + } + String ss; + while((ss = is.readLine()) != null) { + if((ss = ss.trim()).length() > 0) { + if(ss.startsWith("#")) { + continue; + } + if(newBlacklistSet.add(ss)) { + try { + newBlacklist.add(Pattern.compile(ss)); + }catch(PatternSyntaxException shit) { + if(brokenRegex.add(ss)) { + System.err.println("ERROR: the blacklist regex '" + ss + "' is invalid"); + continue; + } + } + brokenRegex.remove(ss); + } + } + } + is.close(); + brokenURLs.remove(str); + }catch(Throwable t) { + if(brokenURLs.add(str)) { + System.err.println("ERROR: the blacklist subscription URL '" + str + "' is invalid"); + } + t.printStackTrace(); + } + } + if(!newBlacklist.isEmpty()) { + regexBlacklist.clear(); + regexBlacklist.addAll(newBlacklist); + } + }else { + brokenURLs.clear(); + brokenRegex.clear(); + regexBlacklist.clear(); + regexLocalBlacklist.clear(); + lastLocalUpdate = 0l; + } + } + } + if(localBlacklist.exists()) { + long lastLocalEdit = localBlacklist.lastModified(); + if(lastLocalEdit != lastLocalUpdate) { + lastLocalUpdate = lastLocalEdit; + synchronized(regexBlacklist) { + try { + BufferedReader is = new BufferedReader(new FileReader(localBlacklist)); + regexLocalBlacklist.clear(); + String ss; + while((ss = is.readLine()) != null) { + try { + if((ss = ss.trim()).length() > 0) { + regexLocalBlacklist.add(Pattern.compile(ss)); + } + }catch(PatternSyntaxException shit) { + System.err.println("ERROR: the local blacklist regex '" + ss + "' is invalid"); + } + } + is.close(); + System.out.println("Reloaded '" + localBlacklist.getName() + "'."); + }catch(IOException ex) { + regexLocalBlacklist.clear(); + System.err.println("ERROR: failed to read local blacklist file '" + localBlacklist.getName() + "'"); + ex.printStackTrace(); + } + } + } + }else { + synchronized(regexBlacklist) { + if(!regexLocalBlacklist.isEmpty()) { + System.err.println("WARNING: the blacklist file '" + localBlacklist.getName() + "' has been deleted"); + } + regexLocalBlacklist.clear(); + } + } + } + + public static void addLocal(String o) { + String p = "^" + Pattern.quote(o.trim()) + "$"; + ArrayList lines = new ArrayList(); + if(localBlacklist.exists()) { + try { + BufferedReader is = new BufferedReader(new FileReader(localBlacklist)); + String ss; + while((ss = is.readLine()) != null) { + if((ss = ss.trim()).length() > 0) { + lines.add(ss); + } + } + is.close(); + }catch(IOException ex) { + // ? + } + } + if(!lines.contains(p)) { + lines.add(p); + try { + PrintWriter os = new PrintWriter(new FileWriter(localBlacklist)); + for(String s : lines) { + os.println(s); + } + os.close(); + lastLocalUpdate = 0l; + update(); + }catch(IOException ex) { + // ? + } + } + } + + public static boolean removeLocal(String o) { + String p = "^" + Pattern.quote(o.trim()) + "$"; + ArrayList lines = new ArrayList(); + if(localBlacklist.exists()) { + try { + BufferedReader is = new BufferedReader(new FileReader(localBlacklist)); + String ss; + while((ss = is.readLine()) != null) { + if((ss = ss.trim()).length() > 0) { + lines.add(ss); + } + } + is.close(); + }catch(IOException ex) { + // ? + } + } + if(lines.contains(p)) { + lines.remove(p); + try { + PrintWriter os = new PrintWriter(new FileWriter(localBlacklist)); + for(String s : lines) { + os.println(s); + } + os.close(); + lastLocalUpdate = 0l; + update(); + return true; + }catch(IOException ex) { + System.err.println("Failed to save '" + localBlacklist.getName() + "'"); + ex.printStackTrace(); + } + } + return false; + } + +} diff --git a/eaglercraftbungee/src/main/java/net/md_5/bungee/eaglercraft/EaglercraftBungee.java b/eaglercraftbungee/src/main/java/net/md_5/bungee/eaglercraft/EaglercraftBungee.java index 9b21f9a..2d77298 100644 --- a/eaglercraftbungee/src/main/java/net/md_5/bungee/eaglercraft/EaglercraftBungee.java +++ b/eaglercraftbungee/src/main/java/net/md_5/bungee/eaglercraft/EaglercraftBungee.java @@ -4,7 +4,7 @@ public class EaglercraftBungee { public static final String brand = "Eagtek"; public static final String name = "EaglercraftBungee"; - public static final String version = "0.2.0"; + public static final String version = "0.3.0"; // wtf does this even mean at this point public static final boolean cracked = true; } diff --git a/eaglercraftbungee/src/main/java/net/md_5/bungee/eaglercraft/WebSocketListener.java b/eaglercraftbungee/src/main/java/net/md_5/bungee/eaglercraft/WebSocketListener.java index 776224e..55c019e 100644 --- a/eaglercraftbungee/src/main/java/net/md_5/bungee/eaglercraft/WebSocketListener.java +++ b/eaglercraftbungee/src/main/java/net/md_5/bungee/eaglercraft/WebSocketListener.java @@ -31,10 +31,12 @@ public class WebSocketListener extends WebSocketServer { public static class PendingSocket { public long openTime; public InetAddress realAddress; + public String origin; public boolean bypassBan; - protected PendingSocket(long openTime, InetAddress realAddress, boolean bypassBan) { + protected PendingSocket(long openTime, InetAddress realAddress, String origin, boolean bypassBan) { this.openTime = openTime; this.realAddress = realAddress; + this.origin = origin; this.bypassBan = bypassBan; } } @@ -192,7 +194,7 @@ public class WebSocketListener extends WebSocketServer { return; } } - WebSocketProxy proxyObj = new WebSocketProxy(arg0, realAddr, bungeeProxy); + WebSocketProxy proxyObj = new WebSocketProxy(arg0, realAddr, ((PendingSocket)o).origin, bungeeProxy); arg0.setAttachment(proxyObj); if(!proxyObj.connect()) { System.err.println("loopback to '" + bungeeProxy.toString() + "' failed - " + realAddr); @@ -212,6 +214,19 @@ public class WebSocketListener extends WebSocketServer { @Override public void onOpen(WebSocket arg0, ClientHandshake arg1) { + String origin = arg1.getFieldValue("Origin"); + if(origin != null) { + int idx = origin.indexOf("://"); + if(idx != -1) { + origin = origin.substring(idx + 3); + } + origin = origin.trim(); + if(DomainBlacklist.test(origin)) { + arg0.send(createRawKickPacket("End of Stream (RIP)")); + arg0.close(); + return; + } + } InetAddress addr; if(info.hasForwardedHeaders()) { String s = arg1.getFieldValue("X-Real-IP"); @@ -242,7 +257,7 @@ public class WebSocketListener extends WebSocketServer { return; } } - arg0.setAttachment(new PendingSocket(System.currentTimeMillis(), addr, bypassBan)); + arg0.setAttachment(new PendingSocket(System.currentTimeMillis(), addr, origin, bypassBan)); } @Override diff --git a/eaglercraftbungee/src/main/java/net/md_5/bungee/eaglercraft/WebSocketProxy.java b/eaglercraftbungee/src/main/java/net/md_5/bungee/eaglercraft/WebSocketProxy.java index e0d0d6d..4715c42 100644 --- a/eaglercraftbungee/src/main/java/net/md_5/bungee/eaglercraft/WebSocketProxy.java +++ b/eaglercraftbungee/src/main/java/net/md_5/bungee/eaglercraft/WebSocketProxy.java @@ -31,20 +31,24 @@ public class WebSocketProxy extends SimpleChannelInboundHandler { private InetSocketAddress tcpListener; private InetSocketAddress localAddress; private InetAddress realRemoteAddr; + private String origin; private NioSocketChannel tcpChannel; private static final EventLoopGroup group = new NioEventLoopGroup(4); public static final HashMap localToRemote = new HashMap(); + public static final HashMap origins = new HashMap(); - public WebSocketProxy(WebSocket w, InetAddress remoteAddr, InetSocketAddress addr) { + public WebSocketProxy(WebSocket w, InetAddress remoteAddr, String originz, InetSocketAddress addr) { client = w; realRemoteAddr = remoteAddr; + origin = originz; tcpListener = addr; tcpChannel = null; } public void killConnection() { localToRemote.remove(localAddress); + origins.remove(localAddress); if(tcpChannel != null && tcpChannel.isOpen()) { try { tcpChannel.disconnect().sync(); @@ -69,12 +73,16 @@ public class WebSocketProxy extends SimpleChannelInboundHandler { @Override public void operationComplete(Future paramF) throws Exception { localToRemote.remove(localAddress); + origins.remove(localAddress); } }); } }); tcpChannel = (NioSocketChannel) clientBootstrap.connect().sync().channel(); localToRemote.put(localAddress = tcpChannel.localAddress(), realRemoteAddr); + if(origin != null) { + origins.put(localAddress, origin); + } return true; } }catch(Throwable t) { @@ -104,6 +112,7 @@ public class WebSocketProxy extends SimpleChannelInboundHandler { public void finalize() { localToRemote.remove(localAddress); + origins.remove(localAddress); } } diff --git a/stable-download/origin_blacklist.txt b/stable-download/origin_blacklist.txt new file mode 100644 index 0000000..8e75c0f --- /dev/null +++ b/stable-download/origin_blacklist.txt @@ -0,0 +1,9 @@ +# eaglercraft domain blacklist +# this is a fallback in case eags.us goes down + +.*thecoderkid\.repl\.co$ + +# ayuncraft has not been removed because ayunami is removing the flyhack + +# snitch other domains out at https://g.eags.us/eaglercraft/report.html +# or join the discord server at https://discord.com/invite/KMQW9Uvjyq and ping @Moderator with the domain and name of the client \ No newline at end of file