Added user/ip/wildcard/regex ban commands

This commit is contained in:
LAX1DUDE 2022-03-30 16:46:54 -07:00
parent 94a8c3f6e9
commit 09fdd00900
23 changed files with 2116 additions and 36 deletions

View file

@ -19,7 +19,6 @@ import net.md_5.bungee.api.connection.ProxiedPlayer;
import java.util.MissingResourceException; import java.util.MissingResourceException;
import net.md_5.bungee.protocol.packet.DefinedPacket; import net.md_5.bungee.protocol.packet.DefinedPacket;
import io.netty.channel.ChannelException; import io.netty.channel.ChannelException;
import java.util.Iterator;
import io.netty.util.concurrent.GenericFutureListener; import io.netty.util.concurrent.GenericFutureListener;
import java.net.SocketAddress; import java.net.SocketAddress;
import io.netty.channel.EventLoopGroup; import io.netty.channel.EventLoopGroup;
@ -28,7 +27,6 @@ import io.netty.util.AttributeKey;
import net.md_5.bungee.netty.PipelineUtils; import net.md_5.bungee.netty.PipelineUtils;
import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.bootstrap.ServerBootstrap; import io.netty.bootstrap.ServerBootstrap;
import io.netty.util.concurrent.Future;
import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelFutureListener;
import net.md_5.bungee.api.config.ListenerInfo; import net.md_5.bungee.api.config.ListenerInfo;
@ -38,7 +36,7 @@ import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.CommandSender; import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.command.ConsoleCommandSender; import net.md_5.bungee.command.ConsoleCommandSender;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.Calendar; import java.util.ArrayList;
import java.io.IOException; import java.io.IOException;
import jline.UnsupportedTerminal; import jline.UnsupportedTerminal;
import java.io.OutputStream; import java.io.OutputStream;
@ -50,6 +48,14 @@ import jline.internal.Log;
import java.io.PrintStream; import java.io.PrintStream;
import com.google.common.io.ByteStreams; import com.google.common.io.ByteStreams;
import net.md_5.bungee.command.CommandFind; import net.md_5.bungee.command.CommandFind;
import net.md_5.bungee.command.CommandGlobalBan;
import net.md_5.bungee.command.CommandGlobalBanIP;
import net.md_5.bungee.command.CommandGlobalBanRegex;
import net.md_5.bungee.command.CommandGlobalBanReload;
import net.md_5.bungee.command.CommandGlobalBanWildcard;
import net.md_5.bungee.command.CommandGlobalCheckBan;
import net.md_5.bungee.command.CommandGlobalListBan;
import net.md_5.bungee.command.CommandGlobalUnban;
import net.md_5.bungee.command.CommandSend; import net.md_5.bungee.command.CommandSend;
import net.md_5.bungee.command.CommandPerms; import net.md_5.bungee.command.CommandPerms;
import net.md_5.bungee.command.CommandBungee; import net.md_5.bungee.command.CommandBungee;
@ -61,10 +67,9 @@ import net.md_5.bungee.command.CommandEnd;
import net.md_5.bungee.api.plugin.Command; import net.md_5.bungee.api.plugin.Command;
import net.md_5.bungee.api.plugin.Plugin; import net.md_5.bungee.api.plugin.Plugin;
import net.md_5.bungee.command.CommandReload; import net.md_5.bungee.command.CommandReload;
import java.util.concurrent.ExecutorService;
import net.md_5.bungee.scheduler.BungeeScheduler; import net.md_5.bungee.scheduler.BungeeScheduler;
import net.md_5.bungee.config.YamlConfig; import net.md_5.bungee.config.YamlConfig;
import net.md_5.bungee.eaglercraft.PluginEaglerAuth; import net.md_5.bungee.eaglercraft.BanList;
import net.md_5.bungee.eaglercraft.PluginEaglerSkins; import net.md_5.bungee.eaglercraft.PluginEaglerSkins;
import net.md_5.bungee.eaglercraft.WebSocketListener; import net.md_5.bungee.eaglercraft.WebSocketListener;
@ -99,6 +104,8 @@ public class BungeeCord extends ProxyServer {
public final ScheduledThreadPoolExecutor executors; public final ScheduledThreadPoolExecutor executors;
public final MultithreadEventLoopGroup eventLoops; public final MultithreadEventLoopGroup eventLoops;
private final Timer saveThread; private final Timer saveThread;
private final Timer reloadBanThread;
private final Timer closeInactiveSockets;
private Collection<Channel> listeners; private Collection<Channel> listeners;
private Collection<WebSocketListener> wsListeners; private Collection<WebSocketListener> wsListeners;
private final Map<String, UserConnection> connections; private final Map<String, UserConnection> connections;
@ -111,6 +118,7 @@ public class BungeeCord extends ProxyServer {
private final TaskScheduler scheduler; private final TaskScheduler scheduler;
private ConsoleReader consoleReader; private ConsoleReader consoleReader;
private final Logger logger; private final Logger logger;
private Collection<Command> banCommands;
public static BungeeCord getInstance() { public static BungeeCord getInstance() {
return (BungeeCord) ProxyServer.getInstance(); return (BungeeCord) ProxyServer.getInstance();
@ -122,6 +130,8 @@ public class BungeeCord extends ProxyServer {
this.executors = new BungeeThreadPool(new ThreadFactoryBuilder().setNameFormat("Bungee Pool Thread #%1$d").build()); this.executors = new BungeeThreadPool(new ThreadFactoryBuilder().setNameFormat("Bungee Pool Thread #%1$d").build());
this.eventLoops = (MultithreadEventLoopGroup) new NioEventLoopGroup(Runtime.getRuntime().availableProcessors(), new ThreadFactoryBuilder().setNameFormat("Netty IO Thread #%1$d").build()); this.eventLoops = (MultithreadEventLoopGroup) new NioEventLoopGroup(Runtime.getRuntime().availableProcessors(), new ThreadFactoryBuilder().setNameFormat("Netty IO Thread #%1$d").build());
this.saveThread = new Timer("Reconnect Saver"); this.saveThread = new Timer("Reconnect Saver");
this.reloadBanThread = new Timer("Ban List Reload");
this.closeInactiveSockets = new Timer("close Inactive WebSockets");
this.listeners = new HashSet<Channel>(); this.listeners = new HashSet<Channel>();
this.wsListeners = new HashSet<WebSocketListener>(); this.wsListeners = new HashSet<WebSocketListener>();
this.connections = (Map<String, UserConnection>) new CaseInsensitiveMap(); this.connections = (Map<String, UserConnection>) new CaseInsensitiveMap();
@ -131,6 +141,7 @@ public class BungeeCord extends ProxyServer {
this.pluginChannels = new HashSet<String>(); this.pluginChannels = new HashSet<String>();
this.pluginsFolder = new File("plugins"); this.pluginsFolder = new File("plugins");
this.scheduler = new BungeeScheduler(); this.scheduler = new BungeeScheduler();
this.banCommands = new ArrayList();
this.getPluginManager().registerCommand(null, new CommandReload()); this.getPluginManager().registerCommand(null, new CommandReload());
this.getPluginManager().registerCommand(null, new CommandEnd()); this.getPluginManager().registerCommand(null, new CommandEnd());
this.getPluginManager().registerCommand(null, new CommandList()); this.getPluginManager().registerCommand(null, new CommandList());
@ -153,6 +164,42 @@ public class BungeeCord extends ProxyServer {
this.logger.info("NOTE: This error is non crucial, and BungeeCord will still function correctly! Do not bug the author about it unless you are still unable to get it working"); this.logger.info("NOTE: This error is non crucial, and BungeeCord will still function correctly! Do not bug the author about it unless you are still unable to get it working");
} }
} }
public void reconfigureBanCommands(boolean replaceBukkit) {
if(banCommands.size() > 0) {
for(Command c : banCommands) {
this.getPluginManager().unregisterCommand(c);
}
banCommands.clear();
}
Command cBan = new CommandGlobalBan(replaceBukkit);
Command cUnban = new CommandGlobalUnban(replaceBukkit);
Command cBanReload = new CommandGlobalBanReload(replaceBukkit);
Command cBanIP = new CommandGlobalBanIP(replaceBukkit);
Command cBanWildcard = new CommandGlobalBanWildcard(replaceBukkit);
Command cBanRegex = new CommandGlobalBanRegex(replaceBukkit);
Command cBanCheck = new CommandGlobalCheckBan(replaceBukkit);
Command cBanList = new CommandGlobalListBan(replaceBukkit);
banCommands.add(cBan);
banCommands.add(cUnban);
banCommands.add(cBanReload);
banCommands.add(cBanIP);
banCommands.add(cBanWildcard);
banCommands.add(cBanRegex);
banCommands.add(cBanCheck);
banCommands.add(cBanList);
this.getPluginManager().registerCommand(null, cBan);
this.getPluginManager().registerCommand(null, cUnban);
this.getPluginManager().registerCommand(null, cBanReload);
this.getPluginManager().registerCommand(null, cBanIP);
this.getPluginManager().registerCommand(null, cBanWildcard);
this.getPluginManager().registerCommand(null, cBanRegex);
this.getPluginManager().registerCommand(null, cBanCheck);
this.getPluginManager().registerCommand(null, cBanList);
}
public static void main(final String[] args) throws Exception { public static void main(final String[] args) throws Exception {
final BungeeCord bungee = new BungeeCord(); final BungeeCord bungee = new BungeeCord();
@ -186,6 +233,20 @@ public class BungeeCord extends ProxyServer {
BungeeCord.this.getReconnectHandler().save(); BungeeCord.this.getReconnectHandler().save();
} }
}, 0L, TimeUnit.MINUTES.toMillis(5L)); }, 0L, TimeUnit.MINUTES.toMillis(5L));
this.reloadBanThread.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
BanList.maybeReloadBans(null);
}
}, 0L, TimeUnit.SECONDS.toMillis(3L));
this.closeInactiveSockets.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
for(WebSocketListener lst : BungeeCord.this.wsListeners) {
lst.closeInactiveSockets();
}
}
}, 0L, TimeUnit.SECONDS.toMillis(10L));
} }
public void startListeners() { public void startListeners() {

View file

@ -4,13 +4,10 @@
package net.md_5.bungee; package net.md_5.bungee;
import net.md_5.bungee.api.connection.Server;
import net.md_5.bungee.api.connection.PendingConnection;
import java.beans.ConstructorProperties; import java.beans.ConstructorProperties;
import net.md_5.bungee.util.CaseInsensitiveSet; import net.md_5.bungee.util.CaseInsensitiveSet;
import java.util.HashSet; import java.util.HashSet;
import net.md_5.bungee.api.config.TexturePackInfo; import net.md_5.bungee.api.config.TexturePackInfo;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.event.PermissionCheckEvent; import net.md_5.bungee.api.event.PermissionCheckEvent;
import java.util.Collections; import java.util.Collections;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
@ -36,10 +33,14 @@ import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelInitializer;
import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.ChatColor;
import java.util.Objects; import java.util.Objects;
import java.util.WeakHashMap;
import net.md_5.bungee.api.event.ServerConnectEvent; import net.md_5.bungee.api.event.ServerConnectEvent;
import net.md_5.bungee.protocol.packet.DefinedPacket; import net.md_5.bungee.protocol.packet.DefinedPacket;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map;
import net.md_5.bungee.api.connection.Connection; import net.md_5.bungee.api.connection.Connection;
import net.md_5.bungee.api.score.Scoreboard; import net.md_5.bungee.api.score.Scoreboard;
import net.md_5.bungee.protocol.packet.PacketCCSettings; import net.md_5.bungee.protocol.packet.PacketCCSettings;
@ -71,6 +72,7 @@ public final class UserConnection implements ProxiedPlayer {
private final Scoreboard serverSentScoreboard; private final Scoreboard serverSentScoreboard;
private String displayName; private String displayName;
private final Connection.Unsafe unsafe; private final Connection.Unsafe unsafe;
private final Map<String, Object> attachment = new WeakHashMap();
public void init() { public void init() {
this.displayName = this.name; this.displayName = this.name;
@ -383,4 +385,9 @@ public final class UserConnection implements ProxiedPlayer {
public String getDisplayName() { public String getDisplayName() {
return this.displayName; return this.displayName;
} }
@Override
public Map<String, Object> getAttachment() {
return attachment;
}
} }

View file

@ -5,6 +5,7 @@
package net.md_5.bungee.api; package net.md_5.bungee.api;
import java.util.Collection; import java.util.Collection;
import java.util.Map;
public interface CommandSender { public interface CommandSender {
String getName(); String getName();
@ -22,4 +23,6 @@ public interface CommandSender {
boolean hasPermission(final String p0); boolean hasPermission(final String p0);
void setPermission(final String p0, final boolean p1); void setPermission(final String p0, final boolean p1);
Map<String, Object> getAttachment();
} }

View file

@ -5,6 +5,9 @@
package net.md_5.bungee.api.config; package net.md_5.bungee.api.config;
import java.beans.ConstructorProperties; import java.beans.ConstructorProperties;
import java.io.File;
import net.md_5.bungee.api.ServerIcon;
import net.md_5.bungee.api.tab.TabListHandler; import net.md_5.bungee.api.tab.TabListHandler;
import java.util.Map; import java.util.Map;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
@ -18,13 +21,18 @@ public class ListenerInfo {
private final String fallbackServer; private final String fallbackServer;
private final boolean forceDefault; private final boolean forceDefault;
private final boolean websocket; private final boolean websocket;
private final boolean forwardIp;
private final Map<String, String> forcedHosts; private final Map<String, String> forcedHosts;
private final TexturePackInfo texturePack; private final TexturePackInfo texturePack;
private final Class<? extends TabListHandler> tabList; private final Class<? extends TabListHandler> tabList;
private final String serverIcon;
private final int[] serverIconCache;
private boolean serverIconLoaded;
private boolean serverIconSet;
@ConstructorProperties({ "host", "motd", "maxPlayers", "tabListSize", "defaultServer", "fallbackServer", "forceDefault", "websocket", "forcedHosts", "texturePack", "tabList" }) @ConstructorProperties({ "host", "motd", "maxPlayers", "tabListSize", "defaultServer", "fallbackServer", "forceDefault", "websocket", "forwardIp", "forcedHosts", "texturePack", "tabList", "serverIcon" })
public ListenerInfo(final InetSocketAddress host, final String motd, final int maxPlayers, final int tabListSize, final String defaultServer, final String fallbackServer, final boolean forceDefault, final boolean websocket, public ListenerInfo(final InetSocketAddress host, final String motd, final int maxPlayers, final int tabListSize, final String defaultServer, final String fallbackServer, final boolean forceDefault, final boolean websocket,
final Map<String, String> forcedHosts, final TexturePackInfo texturePack, final Class<? extends TabListHandler> tabList) { final boolean forwardIp, final Map<String, String> forcedHosts, final TexturePackInfo texturePack, final Class<? extends TabListHandler> tabList, final String serverIcon) {
this.host = host; this.host = host;
this.motd = motd; this.motd = motd;
this.maxPlayers = maxPlayers; this.maxPlayers = maxPlayers;
@ -33,9 +41,14 @@ public class ListenerInfo {
this.fallbackServer = fallbackServer; this.fallbackServer = fallbackServer;
this.forceDefault = forceDefault; this.forceDefault = forceDefault;
this.websocket = websocket; this.websocket = websocket;
this.forwardIp = forwardIp;
this.forcedHosts = forcedHosts; this.forcedHosts = forcedHosts;
this.texturePack = texturePack; this.texturePack = texturePack;
this.tabList = tabList; this.tabList = tabList;
this.serverIcon = serverIcon;
this.serverIconCache = new int[4096];
this.serverIconLoaded = false;
this.serverIconSet = false;
} }
public InetSocketAddress getHost() { public InetSocketAddress getHost() {
@ -120,6 +133,9 @@ public class ListenerInfo {
if (this.getTabListSize() != other.getTabListSize()) { if (this.getTabListSize() != other.getTabListSize()) {
return false; return false;
} }
if (this.isWebsocket() != other.isWebsocket()) {
return false;
}
final Object this$defaultServer = this.getDefaultServer(); final Object this$defaultServer = this.getDefaultServer();
final Object other$defaultServer = other.getDefaultServer(); final Object other$defaultServer = other.getDefaultServer();
Label_0165: { Label_0165: {
@ -180,6 +196,15 @@ public class ListenerInfo {
} else if (this$tabList.equals(other$tabList)) { } else if (this$tabList.equals(other$tabList)) {
return true; return true;
} }
final Object this$getServerIcon = this.getServerIcon();
final Object other$getServerIcon = other.getServerIcon();
if (this$getServerIcon == null) {
if (other$getServerIcon == null) {
return true;
}
} else if (this$getServerIcon.equals(other$getServerIcon)) {
return true;
}
return false; return false;
} }
@ -208,6 +233,8 @@ public class ListenerInfo {
result = result * 31 + (($texturePack == null) ? 0 : $texturePack.hashCode()); result = result * 31 + (($texturePack == null) ? 0 : $texturePack.hashCode());
final Object $tabList = this.getTabList(); final Object $tabList = this.getTabList();
result = result * 31 + (($tabList == null) ? 0 : $tabList.hashCode()); result = result * 31 + (($tabList == null) ? 0 : $tabList.hashCode());
final Object $serverIconCache = this.getTabList();
result = result * 31 + (($serverIconCache == null) ? 0 : $serverIconCache.hashCode());
return result; return result;
} }
@ -220,4 +247,9 @@ public class ListenerInfo {
public boolean isWebsocket() { public boolean isWebsocket() {
return websocket; return websocket;
} }
public boolean hasForwardedHeaders() {
return forwardIp;
}
} }

View file

@ -0,0 +1,61 @@
package net.md_5.bungee.command;
import java.util.Collection;
import net.md_5.bungee.BungeeCord;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.plugin.Command;
import net.md_5.bungee.eaglercraft.BanList;
public class CommandGlobalBan extends Command {
private final boolean replaceBukkit;
public CommandGlobalBan(boolean replaceBukkit) {
super(replaceBukkit ? "ban" : "eag-ban", "bungeecord.command.eag.ban", replaceBukkit ? new String[] { "kickban", "eag-ban", "e-ban", "gban" } : new String[] { "e-ban", "gban" });
this.replaceBukkit = replaceBukkit;
}
@Override
public void execute(CommandSender p0, String[] p1) {
if(p1.length >= 1) {
String p = p1[0].trim().toLowerCase();
if(p0.getName().equalsIgnoreCase(p)) {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "You cannot ban yourself");
return;
}
String reason = "The ban hammer has spoken!";
if(p1.length >= 2) {
reason = "";
for(int i = 1; i < p1.length; ++i) {
if(reason.length() > 0) {
reason += " ";
}
reason += p1[i];
}
}
String wasTheKick = null;
Collection<ProxiedPlayer> playerz = BungeeCord.getInstance().getPlayers();
for(ProxiedPlayer pp : playerz) {
if(pp.getName().equalsIgnoreCase(p)) {
wasTheKick = pp.getName();
pp.disconnect("" + ChatColor.RED + "You are banned.\n" + ChatColor.DARK_GRAY + "Reason: " + reason);
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.WHITE + "Kicked: " + pp.getName());
}
}
if(BanList.ban(p, reason)) {
if(wasTheKick == null) {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.YELLOW + "Warning! '" + ChatColor.WHITE + p + ChatColor.YELLOW + "' is not currently on this server");
}
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "Username '" + ChatColor.WHITE + (wasTheKick == null ? p : wasTheKick) + ChatColor.GREEN + "' was added to the ban list");
}else {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "Username '" + ChatColor.WHITE + p + ChatColor.RED + "' is already banned");
}
}else {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "To ban a player, use: " + ChatColor.WHITE + "/" + (replaceBukkit?"":"eag-") + "ban <player> [reason]");
}
}
}

View file

@ -0,0 +1,148 @@
package net.md_5.bungee.command;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import net.md_5.bungee.BungeeCord;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.plugin.Command;
import net.md_5.bungee.eaglercraft.BanList;
import net.md_5.bungee.eaglercraft.BanList.IPBan;
public class CommandGlobalBanIP extends Command {
private final boolean replaceBukkit;
public CommandGlobalBanIP(boolean replaceBukkit) {
super(replaceBukkit ? "ban-ip" : "eag-ban-ip", "bungeecord.command.eag.banip", (replaceBukkit ? new String[] {"eag-ban-ip", "banip", "e-ban-ip", "gban-ip"} :
new String[] {"gban-ip", "e-ban-ip", "gbanip", "e-banip"}) );
this.replaceBukkit = replaceBukkit;
}
@Override
public void execute(CommandSender p0, String[] p1) {
String w = (String) p0.getAttachment().get("banIPWaitingToAdd");
if(w != null) {
List<ProxiedPlayer> lst = (List<ProxiedPlayer>)p0.getAttachment().get("banIPWaitingToKick");
if(p1.length != 1 || (!p1[0].equalsIgnoreCase("confirm") && !p1[0].equalsIgnoreCase("cancel"))) {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "Type " + ChatColor.WHITE + (replaceBukkit ? "/ban-ip" : "/eag-ban-ip") + " confirm" + ChatColor.RED + " to add IP " + ChatColor.WHITE + w +
ChatColor.RED + " and ban " + ChatColor.WHITE + lst.size() + ChatColor.RED + " players");
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "Type " + ChatColor.WHITE + (replaceBukkit ? "/ban-ip" : "/eag-ban-ip") + " cancel" + ChatColor.RED + " to cancel this operation");
}else {
if(p1[0].equalsIgnoreCase("confirm")) {
try {
if(BanList.banIP(w)) {
for(ProxiedPlayer pp : lst) {
pp.disconnect("" + ChatColor.RED + "You are banned.\n" + ChatColor.DARK_GRAY + "Reason: banned by IP");
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "Kicked: " + ChatColor.WHITE + pp.getName());
}
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "Added IP '" + ChatColor.WHITE + w + ChatColor.GREEN + "' to the ban list");
}else {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "IP '" + ChatColor.WHITE + w + ChatColor.RED + "' is already on the ban list");
}
} catch (UnknownHostException e) {
e.printStackTrace();
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "ERROR: address '" + ChatColor.WHITE + w + ChatColor.RED + "' is suddenly invalid for some reason");
}
}else {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "Canceled ban");
}
p0.getAttachment().remove("banIPWaitingToAdd");
p0.getAttachment().remove("banIPWaitingToKick");
}
return;
}
if(p1.length != 1) {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "How to use: " + ChatColor.WHITE + (replaceBukkit ? "/ban-ip" : "/eag-ban-ip") + " <addr|player>");
return;
}
boolean isPlayer = false;
IPBan p = null;
try {
p = BanList.constructIpBan(p1[0]);
}catch(Throwable t) {
for(ProxiedPlayer pp : BungeeCord.getInstance().getPlayers()) {
if(pp.getName().equalsIgnoreCase(p1[0])) {
Object addr = pp.getAttachment().get("remoteAddr");
if(addr != null) {
String newAddr = ((InetAddress)addr).getHostAddress();
isPlayer = true;
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "Player '" + ChatColor.WHITE + p1[0] + ChatColor.GREEN + "' has IP " + ChatColor.WHITE + newAddr);
p1[0] = newAddr;
try {
p = BanList.constructIpBan(p1[0]);
}catch(UnknownHostException ex) {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "Address '" + ChatColor.WHITE + p1[0] + "' is suddenly invalid: " + ChatColor.WHITE + p1[0]);
return;
}
}
break;
}
}
if(!isPlayer) {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "Player '" + ChatColor.WHITE + p1[0] + "' is not on this server");
return;
}
}
boolean blocked = false;
for(IPBan b : BanList.blockedBans) {
if(b.checkBan(p.getBaseAddress()) || p.checkBan(b.getBaseAddress())) {
blocked = true;
}
}
if(blocked) {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "Cannot ban '" + ChatColor.WHITE + p1[0] + ChatColor.RED + "', it will ban local addresses that may break your game");
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "To force, add to the " + ChatColor.WHITE + "[IPs]" + ChatColor.RED + " section of " + ChatColor.WHITE + "bans.txt" + ChatColor.RED + " in your bungee directory");
return;
}
boolean isSenderGonnaGetKicked = false;
List<ProxiedPlayer> usersThatAreGonnaBeKicked = new ArrayList();
for(ProxiedPlayer pp : BungeeCord.getInstance().getPlayers()) {
Object addr = pp.getAttachment().get("remoteAddr");
if(addr != null) {
InetAddress addrr = (InetAddress)addr;
if(p.checkBan(addrr)) {
usersThatAreGonnaBeKicked.add(pp);
if(pp.getName().equalsIgnoreCase(p0.getName())) {
isSenderGonnaGetKicked = true;
break;
}
}
}
}
if(isSenderGonnaGetKicked) {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "banning address '" + ChatColor.WHITE + p1[0] + ChatColor.RED + "' will ban you off of your own server");
return;
}
if(usersThatAreGonnaBeKicked.size() > 1) {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "WARNING: banning address '" + ChatColor.WHITE + p1[0] + ChatColor.RED + "' is gonna ban " +
ChatColor.WHITE + usersThatAreGonnaBeKicked.size() + ChatColor.RED + " players off of your server");
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "Type " + ChatColor.WHITE + (replaceBukkit ? "/ban-ip" : "/eag-ban-ip") + " confirm" + ChatColor.RED + " to continue, or type " +
ChatColor.WHITE + (replaceBukkit ? "/ban-ip" : "/eag-ban-ip") + " cancel" + ChatColor.RED + " to cancel");
p0.getAttachment().put("banIPWaitingToKick", usersThatAreGonnaBeKicked);
p0.getAttachment().put("banIPWaitingToAdd", p1[0]);
}else {
try {
if(BanList.banIP(p1[0])) {
if(usersThatAreGonnaBeKicked.size() > 0) {
usersThatAreGonnaBeKicked.get(0).disconnect("" + ChatColor.RED + "You are banned.\n" + ChatColor.DARK_GRAY + "Reason: banned by IP");
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "Kicked: " + ChatColor.WHITE + usersThatAreGonnaBeKicked.get(0).getName());
}
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "Added IP '" + ChatColor.WHITE + p1[0] + ChatColor.GREEN + "' to the ban list");
}else {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "IP '" + ChatColor.WHITE + p1[0] + ChatColor.RED + "' is already on the ban list");
}
} catch (UnknownHostException e) {
e.printStackTrace();
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "ERROR: address '" + ChatColor.WHITE + p1[0] + ChatColor.RED + "' is suddenly invalid for some reason");
return;
}
}
}
}

View file

@ -0,0 +1,106 @@
package net.md_5.bungee.command;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import net.md_5.bungee.BungeeCord;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.plugin.Command;
import net.md_5.bungee.eaglercraft.BanList;
public class CommandGlobalBanRegex extends Command {
private final boolean replaceBukkit;
public CommandGlobalBanRegex(boolean replaceBukkit) {
super(replaceBukkit ? "ban-regex" : "eag-ban-regex", "bungeecord.command.eag.banregex", replaceBukkit ? new String[] { "eag-ban-regex", "e-ban-regex",
"gban-regex", "eag-banregex", "e-banregex", "gbanregex", "banregex" } : new String[] { "e-ban-regex", "gban-regex",
"eag-banregex", "e-banregex", "gbanregex" });
this.replaceBukkit = replaceBukkit;
}
@Override
public void execute(CommandSender p0, String[] p1) {
String w = (String) p0.getAttachment().get("banRegexWaitingToAdd");
if(w != null) {
List<ProxiedPlayer> lst = (List<ProxiedPlayer>)p0.getAttachment().get("banRegexWaitingToKick");
if(p1.length != 1 || (!p1[0].equalsIgnoreCase("confirm") && !p1[0].equalsIgnoreCase("cancel"))) {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "Type " + ChatColor.WHITE + (replaceBukkit ? "/ban-regex" : "/eag-ban-regex") + " confirm" + ChatColor.RED + " to add regex " + ChatColor.WHITE + w +
ChatColor.RED + " and ban " + ChatColor.WHITE + lst.size() + ChatColor.RED + " players");
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "Type " + ChatColor.WHITE + (replaceBukkit ? "/ban-regex" : "/eag-ban-regex") + " cancel" + ChatColor.RED + " to cancel this operation");
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.YELLOW + "Note: all usernames are converted to lowercase before being matched");
}else {
if(p1[0].equalsIgnoreCase("confirm")) {
if(BanList.banRegex(w)) {
for(ProxiedPlayer pp : lst) {
pp.disconnect("" + ChatColor.RED + "You are banned.\n" + ChatColor.DARK_GRAY + "Reason: banned by regex");
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "Kicked: " + ChatColor.WHITE + pp.getName());
}
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "Added regex '" + ChatColor.WHITE + w + ChatColor.GREEN + "' to the ban list");
}else {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "Regex '" + ChatColor.WHITE + w + ChatColor.RED + "' is already banned");
}
}else {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "Canceled ban");
}
p0.getAttachment().remove("banRegexWaitingToAdd");
p0.getAttachment().remove("banRegexWaitingToKick");
}
return;
}
if(p1.length != 1) {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "How to use: " + ChatColor.WHITE + (replaceBukkit ? "/ban-regex" : "/eag-ban-regex") + " <pattern>");
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.YELLOW + "Note: all usernames are converted to lowercase before being matched");
return;
}
Pattern p;
try {
p = Pattern.compile(p1[0]);
}catch(Throwable t) {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "Regex syntax error: " + t.getMessage());
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.YELLOW + "Note: all usernames are converted to lowercase before being matched");
return;
}
boolean isSenderGonnaGetKicked = false;
List<ProxiedPlayer> usersThatAreGonnaBeKicked = new ArrayList();
for(ProxiedPlayer pp : BungeeCord.getInstance().getPlayers()) {
String n = pp.getName().toLowerCase();
if(p.matcher(n).matches()) {
usersThatAreGonnaBeKicked.add(pp);
if(n.equalsIgnoreCase(p0.getName())) {
isSenderGonnaGetKicked = true;
break;
}
}
}
if(isSenderGonnaGetKicked) {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "banning regex '" + ChatColor.WHITE + p1[0] + ChatColor.RED + "' is gonna ban your own username");
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.YELLOW + "Note: all usernames are converted to lowercase before being matched");
return;
}
if(usersThatAreGonnaBeKicked.size() > 1) {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "WARNING: banning regex '" + ChatColor.WHITE + p1[0] + ChatColor.RED + "' is gonna ban " +
ChatColor.WHITE + usersThatAreGonnaBeKicked.size() + ChatColor.RED + " players off of your server");
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "Type " + ChatColor.WHITE + (replaceBukkit ? "/ban-regex" : "/eag-ban-regex") + " confirm" + ChatColor.RED + " to continue, or type " +
ChatColor.WHITE + "/eag-ban-regex cancel" + ChatColor.RED + " to cancel");
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.YELLOW + "Note: all usernames are converted to lowercase before being matched");
p0.getAttachment().put("banRegexWaitingToKick", usersThatAreGonnaBeKicked);
p0.getAttachment().put("banRegexWaitingToAdd", p1[0]);
}else {
if(BanList.banRegex(p1[0])) {
if(usersThatAreGonnaBeKicked.size() > 0) {
usersThatAreGonnaBeKicked.get(0).disconnect("" + ChatColor.RED + "You are banned.\n" + ChatColor.DARK_GRAY + "Reason: banned by regex");
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "Kicked: " + ChatColor.WHITE + usersThatAreGonnaBeKicked.get(0).getName());
}
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "Added regex '" + ChatColor.WHITE + p1[0] + ChatColor.GREEN + "' to the ban list");
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.YELLOW + "Note: all usernames are converted to lowercase before being matched");
}else {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "Regex '" + ChatColor.WHITE + p1[0] + ChatColor.RED + "' is already banned");
}
}
}
}

View file

@ -0,0 +1,21 @@
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.BanList;
public class CommandGlobalBanReload extends Command {
public CommandGlobalBanReload(boolean replaceBukkit) {
super(replaceBukkit ? "reloadban" : "eag-reloadban", "bungeecord.command.eag.reloadban", replaceBukkit ? new String[] { "eag-reloadban", "banreload", "eag-banreload", "e-reloadban",
"e-banreload", "gbanreload", "greloadban"} : new String[] { "eag-banreload", "e-reloadban", "e-banreload", "gbanreload", "greloadban"});
}
@Override
public void execute(CommandSender p0, String[] p1) {
BanList.maybeReloadBans(p0);
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.WHITE + "Ban list reloaded");
}
}

View file

@ -0,0 +1,125 @@
package net.md_5.bungee.command;
import java.util.ArrayList;
import java.util.List;
import net.md_5.bungee.BungeeCord;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.plugin.Command;
import net.md_5.bungee.eaglercraft.BanList;
public class CommandGlobalBanWildcard extends Command {
private final boolean replaceBukkit;
public CommandGlobalBanWildcard(boolean replaceBukkit) {
super(replaceBukkit ? "ban-wildcard" : "eag-ban-wildcard", "bungeecord.command.eag.banwildcard", replaceBukkit ? new String[] { "eag-ban-wildcard", "e-ban-wildcard", "gban-wildcard",
"banwildcard", "eag-banwildcard", "banwildcard"} : new String[] { "e-ban-wildcard", "gban-wildcard", "eag-banwildcard"});
this.replaceBukkit = replaceBukkit;
}
@Override
public void execute(CommandSender p0, String[] p1) {
String w = (String) p0.getAttachment().get("banWildcardWaitingToAdd");
if(w != null) {
List<ProxiedPlayer> lst = (List<ProxiedPlayer>)p0.getAttachment().get("banWildcardWaitingToKick");
if(p1.length != 1 || (!p1[0].equalsIgnoreCase("confirm") && !p1[0].equalsIgnoreCase("cancel"))) {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "Type " + ChatColor.WHITE + (replaceBukkit ? "/ban-wildcard" : "/eag-ban-wildcard") + " confirm" + ChatColor.RED + " to add wildcard " + ChatColor.WHITE + w +
ChatColor.RED + " and ban " + ChatColor.WHITE + lst.size() + ChatColor.RED + " players");
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "Type " + ChatColor.WHITE + (replaceBukkit ? "/ban-wildcard" : "/eag-ban-wildcard") + " cancel" + ChatColor.RED + " to cancel this operation");
}else {
if(p1[0].equalsIgnoreCase("confirm")) {
if(BanList.banWildcard(w)) {
for(ProxiedPlayer pp : lst) {
pp.disconnect("" + ChatColor.RED + "You are banned.\n" + ChatColor.DARK_GRAY + "Reason: banned by wildcard");
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "Kicked: " + ChatColor.WHITE + pp.getName());
}
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "Added wildcard '" + ChatColor.WHITE + w + ChatColor.GREEN + "' to the ban list");
}else {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "Wildcard '" + ChatColor.WHITE + w + ChatColor.RED + "' is already banned");
}
}else {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "Canceled ban");
}
p0.getAttachment().remove("banWildcardWaitingToAdd");
p0.getAttachment().remove("banWildcardWaitingToKick");
}
return;
}
if(p1.length != 1) {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "How to use: " + ChatColor.WHITE + (replaceBukkit ? "/ban-wildcard" : "/eag-ban-wildcard") + " <pattern>");
return;
}
p1[0] = p1[0].toLowerCase();
String s = p1[0];
boolean startStar = s.startsWith("*");
if(startStar) {
s = s.substring(1);
}
boolean endStar = s.endsWith("*");
if(endStar) {
s = s.substring(0, s.length() - 1);
}
if(!startStar && !endStar) {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "'" + ChatColor.WHITE + p1[0] + ChatColor.RED + "' is not a wildcard, try '"
+ ChatColor.WHITE + "*" + p1[0] + ChatColor.RED + "' or '" + ChatColor.WHITE + p1[0] + "*" + ChatColor.RED + "' or '" + ChatColor.WHITE
+ "*" + p1[0] + "*" + ChatColor.RED + "' instead");
return;
}
boolean isSenderGonnaGetKicked = false;
List<ProxiedPlayer> usersThatAreGonnaBeKicked = new ArrayList();
for(ProxiedPlayer pp : BungeeCord.getInstance().getPlayers()) {
String n = pp.getName().toLowerCase();
if(startStar && endStar) {
if(n.contains(s)) {
usersThatAreGonnaBeKicked.add(pp);
if(pp.getName().equalsIgnoreCase(p0.getName())) {
isSenderGonnaGetKicked = true;
break;
}
}
}else if(startStar) {
if(n.endsWith(s)) {
usersThatAreGonnaBeKicked.add(pp);
if(pp.getName().equalsIgnoreCase(p0.getName())) {
isSenderGonnaGetKicked = true;
break;
}
}
}else if(endStar) {
if(n.startsWith(s)) {
usersThatAreGonnaBeKicked.add(pp);
if(pp.getName().equalsIgnoreCase(p0.getName())) {
isSenderGonnaGetKicked = true;
break;
}
}
}
}
if(isSenderGonnaGetKicked) {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "banning wildcard '" + ChatColor.WHITE + p1[0] + ChatColor.RED + "' is gonna ban your own username");
return;
}
if(usersThatAreGonnaBeKicked.size() > 1) {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "WARNING: banning wildcard '" + ChatColor.WHITE + p1[0] + ChatColor.RED + "' is gonna ban " +
ChatColor.WHITE + usersThatAreGonnaBeKicked.size() + ChatColor.RED + " players off of your server");
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "Type " + ChatColor.WHITE + (replaceBukkit ? "/ban-wildcard" : "/eag-ban-wildcard") + " confirm" + ChatColor.RED + " to continue, or type " +
ChatColor.WHITE + (replaceBukkit ? "/ban-wildcard" : "/eag-ban-wildcard") + " cancel" + ChatColor.RED + " to cancel");
p0.getAttachment().put("banWildcardWaitingToKick", usersThatAreGonnaBeKicked);
p0.getAttachment().put("banWildcardWaitingToAdd", p1[0]);
}else {
if(BanList.banWildcard(p1[0])) {
if(usersThatAreGonnaBeKicked.size() > 0) {
usersThatAreGonnaBeKicked.get(0).disconnect("" + ChatColor.RED + "You are banned.\n" + ChatColor.DARK_GRAY + "Reason: banned by wildcard");
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "Kicked: " + ChatColor.WHITE + usersThatAreGonnaBeKicked.get(0).getName());
}
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "Added wildcard '" + ChatColor.WHITE + p1[0] + ChatColor.GREEN + "' to the ban list");
}else {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "Wildcard '" + ChatColor.WHITE + p1[0] + ChatColor.RED + "' is already banned");
}
}
}
}

View file

@ -0,0 +1,56 @@
package net.md_5.bungee.command;
import java.net.InetAddress;
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.BanList;
import net.md_5.bungee.eaglercraft.BanList.BanCheck;
import net.md_5.bungee.eaglercraft.BanList.BanState;
public class CommandGlobalCheckBan extends Command {
private final boolean replaceBukkit;
public CommandGlobalCheckBan(boolean replaceBukkit) {
super(replaceBukkit ? "banned" : "eag-bannned", "bungeecord.command.eag.banned", replaceBukkit ? new String[] { "eag-banned", "isbanned", "e-banned", "gbanned", "eag-isbanned", "e-isbanned", "gisbanned" } :
new String[] { "e-banned", "gbanned", "eag-isbanned", "e-isbanned", "gisbanned" });
this.replaceBukkit = replaceBukkit;
}
@Override
public void execute(CommandSender p0, String[] p1) {
if(p1.length != 1) {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "To check if a player or IP is banned, use: " + ChatColor.WHITE + (replaceBukkit ? "/banned" : "/eag-banned") + " <username|ip>");
}else {
BanCheck bc = BanList.checkBanned(p1[0]);
if(!bc.isBanned()) {
try {
InetAddress addr = InetAddress.getByName(p1[0]);
bc = BanList.checkIpBanned(addr);
if(bc.isBanned()) {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "IP address '" + ChatColor.WHITE + p1[0] + ChatColor.RED + "' is banned by: "
+ "'" + ChatColor.WHITE + bc.match + ChatColor.RED + "' " + ChatColor.YELLOW + "(" + bc.string + ")");
return;
}
}catch(Throwable t) {
// no
}
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "Player '" + ChatColor.WHITE + p1[0] + ChatColor.RED + "' has not been banned");
}else {
if(bc.reason == BanState.USER_BANNED) {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "Player '" + ChatColor.WHITE + p1[0] + ChatColor.RED + "' is banned by username, reason: "
+ ChatColor.YELLOW + "\"" + bc.string + "\"");
}else if(bc.reason == BanState.WILDCARD_BANNED) {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "Player '" + ChatColor.WHITE + p1[0] + ChatColor.RED + "' is banned by wildcard: "
+ ChatColor.WHITE + "\"" + bc.match + "\"");
}else if(bc.reason == BanState.REGEX_BANNED) {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "Player '" + ChatColor.WHITE + p1[0] + ChatColor.RED + "' is banned by regex: "
+ ChatColor.WHITE + "\"" + bc.match + "\"");
}
}
}
}
}

View file

@ -0,0 +1,66 @@
package net.md_5.bungee.command;
import java.util.List;
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.BanList;
public class CommandGlobalListBan extends Command {
private final boolean replaceBukkit;
public CommandGlobalListBan(boolean replaceBukkit) {
super(replaceBukkit ? "banlist" : "eag-banlist", "bungeecord.command.eag.banlist", replaceBukkit ? new String[] { "eag-banlist", "gbanlist", "e-banlist",
"gbanlist" } : new String[] { "gbanlist", "e-banlist" });
this.replaceBukkit = replaceBukkit;
}
@Override
public void execute(CommandSender p0, String[] p1) {
if(p1.length == 0 || (p1.length == 1 && (p1[0].equalsIgnoreCase("user") || p1[0].equalsIgnoreCase("username")
|| p1[0].equalsIgnoreCase("users") || p1[0].equalsIgnoreCase("usernames")))) {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "Players banned by username: " + ChatColor.WHITE + BanList.listAllBans());
return;
}else if(p1.length == 1) {
if(p1[0].equalsIgnoreCase("regex") || p1[0].equalsIgnoreCase("regexes")) {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "Regex ban list: " + ChatColor.WHITE + BanList.listAllRegexBans());
return;
}else if(p1[0].equalsIgnoreCase("wildcard") || p1[0].equalsIgnoreCase("wildcards")) {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "Wildcard ban list: " + ChatColor.WHITE + BanList.listAllWildcardBans());
return;
}else if(p1[0].equalsIgnoreCase("ip") || p1[0].equalsIgnoreCase("ips")) {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "To list IP bans, use: " + ChatColor.WHITE + (replaceBukkit ? "/banlist" : "/eag-banlist") + " ip <addr|netmask> [v4|v6]");
return;
}
}else if(p1.length > 1 && p1.length <= 3 && (p1[0].equalsIgnoreCase("ip") || p1[0].equalsIgnoreCase("ips"))) {
int addrOrNetmask = 0;
if(p1[1].equalsIgnoreCase("addr") || p1[1].equalsIgnoreCase("addrs")) {
addrOrNetmask = 1;
}else if(p1[1].equalsIgnoreCase("netmask") || p1[1].equalsIgnoreCase("netmasks")) {
addrOrNetmask = 2;
}
if(addrOrNetmask > 0) {
boolean yes = false;
if(p1.length == 2 || (p1.length == 3 && (p1[2].equalsIgnoreCase("v4") || p1[2].equals("4")))) {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "IPv4 " + (addrOrNetmask == 2 ? "netmask" : "address") + " ban list: " + ChatColor.WHITE + BanList.listAllIPBans(false, addrOrNetmask == 2));
yes = true;
}
if(p1.length == 2 || (p1.length == 3 && (p1[2].equalsIgnoreCase("v6") || p1[2].equals("6")))) {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "IPv6 " + (addrOrNetmask == 2 ? "netmask" : "address") + " ban list: " + ChatColor.WHITE + BanList.listAllIPBans(true, addrOrNetmask == 2));
yes = true;
}
if(yes) {
return;
}
}
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "To list IP bans, use: " + ChatColor.WHITE + (replaceBukkit ? "/banlist" : "/eag-banlist") + " ip <addr|netmask> [v4|v6]");
return;
}
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "To list all user bans, use: " + ChatColor.WHITE + (replaceBukkit ? "/banlist" : "/eag-banlist"));
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "To list ips, regexes, and wildcards, use: " + ChatColor.WHITE + (replaceBukkit ? "/banlist" : "/eag-banlist") + " <ip|regex|wildcard>");
return;
}
}

View file

@ -0,0 +1,56 @@
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.BanList;
public class CommandGlobalUnban extends Command {
private final boolean replaceBukkit;
public CommandGlobalUnban(boolean replaceBukkit) {
super(replaceBukkit ? "unban" : "eag-unban", "bungeecord.command.eag.unban", replaceBukkit ? new String[] {"eag-unban", "e-unban", "gunban"} :new String[] {"e-unban", "gunban"});
this.replaceBukkit = replaceBukkit;
}
@Override
public void execute(CommandSender p0, String[] p1) {
if(p1.length != 2 || (!p1[0].equalsIgnoreCase("user") && !p1[0].equalsIgnoreCase("username") && !p1[0].equalsIgnoreCase("player")
&& !p1[0].equalsIgnoreCase("wildcard") && !p1[0].equalsIgnoreCase("regex") && !p1[0].equalsIgnoreCase("ip"))) {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "To unban a player, use: " + ChatColor.WHITE + "/" + (replaceBukkit?"":"eag-") + "unban user <player>");
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "To unban an ip/wildcard/regex, use: " + ChatColor.WHITE + "/" + (replaceBukkit?"":"eag-") + "unban <ip|wildcard|regex> <value>");
return;
}
if(p1[0].equalsIgnoreCase("user") || p1[0].equalsIgnoreCase("username") || p1[0].equalsIgnoreCase("player")) {
if(BanList.unban(p1[1])) {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "User '" + ChatColor.WHITE + p1[1] + ChatColor.GREEN + "' was unbanned");
}else {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "User '" + ChatColor.WHITE + p1[1] + ChatColor.RED + "' is not banned");
}
}else if(p1[0].equalsIgnoreCase("ip")) {
try {
if(BanList.unbanIP(p1[1])) {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "IP '" + ChatColor.WHITE + p1[1] + ChatColor.GREEN + "' was unbanned");
}else {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "IP '" + ChatColor.WHITE + p1[1] + ChatColor.RED + "' is not banned");
}
}catch(Throwable t) {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "IP address '" + ChatColor.WHITE + p1[1] + ChatColor.RED + "' is invalid: " + t.getMessage());
}
}else if(p1[0].equalsIgnoreCase("wildcard")) {
if(BanList.unbanWildcard(p1[1])) {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "Wildcard '" + ChatColor.WHITE + p1[1] + ChatColor.GREEN + "' was unbanned");
}else {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "Wildcard '" + ChatColor.WHITE + p1[1] + ChatColor.RED + "' is not banned");
}
}else if(p1[0].equalsIgnoreCase("regex")) {
if(BanList.unbanRegex(p1[1])) {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "Regex '" + ChatColor.WHITE + p1[1] + ChatColor.GREEN + "' was unbanned");
}else {
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "Regex '" + ChatColor.WHITE + p1[1] + ChatColor.RED + "' is not banned");
}
}
}
}

View file

@ -6,6 +6,9 @@ package net.md_5.bungee.command;
import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.ProxyServer;
import java.net.InetAddress;
import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.CommandSender; import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.plugin.Command; import net.md_5.bungee.api.plugin.Command;
@ -25,7 +28,12 @@ public class CommandIP extends Command {
if (user == null) { if (user == null) {
sender.sendMessage(ChatColor.RED + "That user is not online"); sender.sendMessage(ChatColor.RED + "That user is not online");
} else { } else {
sender.sendMessage(ChatColor.BLUE + "IP of " + args[0] + " is " + user.getAddress()); Object o = user.getAttachment().get("remoteAddr");
if(o != null) {
sender.sendMessage(ChatColor.BLUE + "IP of " + args[0] + " is " + (InetAddress)o);
}else {
sender.sendMessage(ChatColor.BLUE + "IP of " + args[0] + " is " + user.getAddress());
}
} }
} }
} }

View file

@ -4,14 +4,16 @@
package net.md_5.bungee.command; package net.md_5.bungee.command;
import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.Collection; import java.util.Collection;
import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.CommandSender; import net.md_5.bungee.api.CommandSender;
public class ConsoleCommandSender implements CommandSender { public class ConsoleCommandSender implements CommandSender {
private static final ConsoleCommandSender instance; private static final ConsoleCommandSender instance;
private static final Map<String, Object> attachment = new WeakHashMap();
private ConsoleCommandSender() { private ConsoleCommandSender() {
} }
@ -65,4 +67,9 @@ public class ConsoleCommandSender implements CommandSender {
static { static {
instance = new ConsoleCommandSender(); instance = new ConsoleCommandSender();
} }
@Override
public Map<String, Object> getAttachment() {
return attachment;
}
} }

View file

@ -12,6 +12,7 @@ import com.google.common.base.Preconditions;
import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.ProxyServer;
import java.util.UUID; import java.util.UUID;
import net.md_5.bungee.api.config.ServerInfo; import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.eaglercraft.EaglercraftBungee;
import gnu.trove.map.TMap; import gnu.trove.map.TMap;
import net.md_5.bungee.api.config.ListenerInfo; import net.md_5.bungee.api.config.ListenerInfo;
import java.util.Collection; import java.util.Collection;
@ -24,6 +25,7 @@ public class Configuration {
private AuthServiceInfo authInfo; private AuthServiceInfo authInfo;
private boolean onlineMode; private boolean onlineMode;
private int playerLimit; private int playerLimit;
private String name;
public Configuration() { public Configuration() {
this.timeout = 30000; this.timeout = 30000;
@ -41,6 +43,7 @@ public class Configuration {
this.authInfo = adapter.getAuthSettings(); this.authInfo = adapter.getAuthSettings();
this.onlineMode = false; this.onlineMode = false;
this.playerLimit = adapter.getInt("player_limit", this.playerLimit); this.playerLimit = adapter.getInt("player_limit", this.playerLimit);
this.name = adapter.getString("server_name", EaglercraftBungee.brand + " Server");
Preconditions.checkArgument(this.listeners != null && !this.listeners.isEmpty(), (Object) "No listeners defined."); Preconditions.checkArgument(this.listeners != null && !this.listeners.isEmpty(), (Object) "No listeners defined.");
final Map<String, ServerInfo> newServers = adapter.getServers(); final Map<String, ServerInfo> newServers = adapter.getServers();
Preconditions.checkArgument(newServers != null && !newServers.isEmpty(), (Object) "No servers defined"); Preconditions.checkArgument(newServers != null && !newServers.isEmpty(), (Object) "No servers defined");
@ -88,4 +91,8 @@ public class Configuration {
public AuthServiceInfo getAuthInfo() { public AuthServiceInfo getAuthInfo() {
return authInfo; return authInfo;
} }
public String getServerName() {
return name;
}
} }

View file

@ -67,18 +67,11 @@ public class YamlConfig implements ConfigurationAdapter {
final Map<String, Object> permissions = this.get("permissions", new HashMap<String, Object>()); final Map<String, Object> permissions = this.get("permissions", new HashMap<String, Object>());
if (permissions.isEmpty()) { 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"));
permissions.put("admin", Arrays.asList("bungeecord.command.alert", "bungeecord.command.end", "bungeecord.command.ip", "bungeecord.command.reload")); 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"));
} }
this.get("groups", new HashMap<String, Object>()); this.get("groups", new HashMap<String, Object>());
/*
final Map<String, Object> auth = this.get("authservice", new HashMap<String, Object>());
if(auth.isEmpty()) {
auth.put("enabled", false);
auth.put("limbo", "lobby");
auth.put("authfile", "passwords.yml");
auth.put("timeout", 30);
}
*/
} }
private <T> T get(final String path, final T def) { private <T> T get(final String path, final T def) {
@ -159,6 +152,7 @@ public class YamlConfig implements ConfigurationAdapter {
final String fallbackServer = this.get("fallback_server", defaultServer, val); final String fallbackServer = this.get("fallback_server", defaultServer, val);
final boolean forceDefault = this.get("force_default_server", true, val); final boolean forceDefault = this.get("force_default_server", true, val);
final boolean websocket = this.get("websocket", true, val); final boolean websocket = this.get("websocket", true, val);
final boolean forwardIp = this.get("forward_ip", false, val);
final String host = this.get("host", "0.0.0.0:25565", val); final String host = this.get("host", "0.0.0.0:25565", val);
final int tabListSize = this.get("tab_size", 60, val); final int tabListSize = this.get("tab_size", 60, val);
final InetSocketAddress address = Util.getAddr(host); final InetSocketAddress address = Util.getAddr(host);
@ -167,11 +161,12 @@ public class YamlConfig implements ConfigurationAdapter {
final int textureSize = this.get("texture_size", 16, val); final int textureSize = this.get("texture_size", 16, val);
final TexturePackInfo texture = (textureURL == null) ? null : new TexturePackInfo(textureURL, textureSize); final TexturePackInfo texture = (textureURL == null) ? null : new TexturePackInfo(textureURL, textureSize);
final String tabListName = this.get("tab_list", "GLOBAL_PING", val); final String tabListName = this.get("tab_list", "GLOBAL_PING", val);
final String serverIcon = this.get("server_icon", "server-icon.png", val);
DefaultTabList value = DefaultTabList.valueOf(tabListName.toUpperCase()); DefaultTabList value = DefaultTabList.valueOf(tabListName.toUpperCase());
if (value == null) { if (value == null) {
value = DefaultTabList.GLOBAL_PING; value = DefaultTabList.GLOBAL_PING;
} }
final ListenerInfo info = new ListenerInfo(address, motd, maxPlayers, tabListSize, defaultServer, fallbackServer, forceDefault, websocket, forced, texture, value.clazz); final ListenerInfo info = new ListenerInfo(address, motd, maxPlayers, tabListSize, defaultServer, fallbackServer, forceDefault, websocket, forwardIp, forced, texture, value.clazz, serverIcon);
ret.add(info); ret.add(info);
} }
return ret; return ret;

View file

@ -6,6 +6,7 @@ package net.md_5.bungee.connection;
import java.beans.ConstructorProperties; import java.beans.ConstructorProperties;
import java.util.ArrayList; import java.util.ArrayList;
import java.net.InetAddress;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import net.md_5.bungee.protocol.packet.PacketFFKick; import net.md_5.bungee.protocol.packet.PacketFFKick;
import net.md_5.bungee.api.config.ServerInfo; import net.md_5.bungee.api.config.ServerInfo;
@ -37,6 +38,9 @@ import net.md_5.bungee.protocol.Forge;
import net.md_5.bungee.netty.PacketDecoder; import net.md_5.bungee.netty.PacketDecoder;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import net.md_5.bungee.api.event.ProxyPingEvent; import net.md_5.bungee.api.event.ProxyPingEvent;
import net.md_5.bungee.eaglercraft.BanList;
import net.md_5.bungee.eaglercraft.WebSocketProxy;
import net.md_5.bungee.eaglercraft.BanList.BanCheck;
import net.md_5.bungee.api.ServerPing; import net.md_5.bungee.api.ServerPing;
import net.md_5.bungee.protocol.packet.PacketFEPing; import net.md_5.bungee.protocol.packet.PacketFEPing;
import net.md_5.bungee.Util; import net.md_5.bungee.Util;
@ -112,8 +116,12 @@ public class InitialHandler extends PacketHandler implements PendingConnection {
if (handshake.getProcolVersion() == 69) { if (handshake.getProcolVersion() == 69) {
skipEncryption = true; skipEncryption = true;
this.handshake.swapProtocol((byte) 61); this.handshake.swapProtocol((byte) 61);
}else if(handshake.getProcolVersion() == 71) {
this.disconnect("this server does not support microsoft accounts");
return;
}else if(handshake.getProcolVersion() != 61) { }else if(handshake.getProcolVersion() != 61) {
this.disconnect("minecraft 1.5.2 required for eaglercraft backdoor access"); this.disconnect("minecraft 1.5.2 required for eaglercraft backdoor access");
return;
} }
String un = handshake.getUsername(); String un = handshake.getUsername();
if (un.length() < 3) { if (un.length() < 3) {
@ -128,6 +136,37 @@ public class InitialHandler extends PacketHandler implements PendingConnection {
this.disconnect("Go fuck yourself"); this.disconnect("Go fuck yourself");
return; return;
} }
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());
}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.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());
}
}
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 + "'");
break;
case WILDCARD_BANNED:
System.err.println("Player '" + un + "' is banned by wildcard: " + bc.match);
break;
case REGEX_BANNED:
System.err.println("Player '" + un + "' is banned by regex: " + bc.match);
break;
default:
System.err.println("Player '" + un + "' is banned: " + bc.string);
}
this.disconnect("" + ChatColor.RED + "You are banned.\n" + ChatColor.DARK_GRAY + "Reason: " + bc.string);
return;
}
final int limit = BungeeCord.getInstance().config.getPlayerLimit(); final int limit = BungeeCord.getInstance().config.getPlayerLimit();
if (limit > 0 && this.bungee.getOnlineCount() > limit) { if (limit > 0 && this.bungee.getOnlineCount() > limit) {
this.disconnect(this.bungee.getTranslation("proxy_full")); this.disconnect(this.bungee.getTranslation("proxy_full"));
@ -194,6 +233,10 @@ public class InitialHandler extends PacketHandler implements PendingConnection {
public void handle(final PacketCDClientStatus clientStatus) throws Exception { public void handle(final PacketCDClientStatus clientStatus) throws Exception {
Preconditions.checkState(this.thisState == State.LOGIN, (Object) "Not expecting LOGIN"); Preconditions.checkState(this.thisState == State.LOGIN, (Object) "Not expecting LOGIN");
final UserConnection userCon = new UserConnection(this.bungee, this.ch, this.getName(), this); final UserConnection userCon = new UserConnection(this.bungee, this.ch, this.getName(), this);
InetAddress ins = WebSocketProxy.localToRemote.get(this.ch.getHandle().remoteAddress());
if(ins != null) {
userCon.getAttachment().put("remoteAddr", ins);
}
userCon.init(); userCon.init();
this.bungee.getPluginManager().callEvent(new PostLoginEvent(userCon)); this.bungee.getPluginManager().callEvent(new PostLoginEvent(userCon));
((HandlerBoss) this.ch.getHandle().pipeline().get((Class) HandlerBoss.class)).setHandler(new UpstreamBridge(this.bungee, userCon)); ((HandlerBoss) this.ch.getHandle().pipeline().get((Class) HandlerBoss.class)).setHandler(new UpstreamBridge(this.bungee, userCon));

View file

@ -0,0 +1,863 @@
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.PrintWriter;
import java.math.BigInteger;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import net.md_5.bungee.BungeeCord;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.eaglercraft.sun.net.util.IPAddressUtil;
public class BanList {
private static final Object banListMutex = new Object();
public static enum BanState {
NOT_BANNED, USER_BANNED, IP_BANNED, WILDCARD_BANNED, REGEX_BANNED;
}
public static class BanCheck {
public final BanState reason;
public final String match;
public final String string;
private BanCheck(BanState reason, String match, String string) {
this.reason = reason;
this.match = match;
this.string = string;
}
public boolean isBanned() {
return reason != BanState.NOT_BANNED;
}
}
private static class RegexBan {
public final String string;
public final Pattern compiled;
private RegexBan(String string, Pattern compiled) {
this.string = string;
this.compiled = compiled;
}
public String toString() {
return string;
}
public int hashCode() {
return string.hashCode();
}
}
public static interface IPBan {
boolean checkBan(InetAddress addr);
InetAddress getBaseAddress();
boolean hasNetMask();
}
private static class IPBan4 implements IPBan {
private final int addr;
private final InetAddress addrI;
private final int mask;
private final String string;
protected IPBan4(Inet4Address addr, String s, int mask) {
if(mask >= 32) {
this.mask = 0xFFFFFFFF;
}else {
this.mask = ~((1 << (32 - mask)) - 1);
}
this.string = s;
byte[] bits = addr.getAddress();
this.addr = this.mask & ((bits[0] << 24) | (bits[1] << 16) | (bits[2] << 8) | (bits[3] & 0xFF));
this.addrI = addr;
}
@Override
public boolean checkBan(InetAddress addr4) {
if(addr4 instanceof Inet4Address) {
Inet4Address a = (Inet4Address)addr4;
byte[] bits = a.getAddress();
int addrBits = ((bits[0] << 24) | (bits[1] << 16) | (bits[2] << 8) | (bits[3] & 0xFF));
return (mask & addrBits) == addr;
}else {
return false;
}
}
@Override
public InetAddress getBaseAddress() {
return addrI;
}
@Override
public String toString() {
return string;
}
@Override
public int hashCode() {
return string.hashCode();
}
@Override
public boolean equals(Object o) {
return o != null && o instanceof IPBan4 && ((IPBan4)o).addr == addr && ((IPBan4)o).mask == mask;
}
@Override
public boolean hasNetMask() {
return mask != 0xFFFFFFFF;
}
}
private static class IPBan6 implements IPBan {
private static final BigInteger mask128 = new BigInteger(1, new byte[] {
(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,
(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,
(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,
(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF
});
private final BigInteger addr;
private final InetAddress addrI;
private final BigInteger mask;
private final String string;
protected IPBan6(Inet6Address addr, String s, int mask) {
this.mask = BigInteger.valueOf(1l).shiftLeft(128 - mask).subtract(BigInteger.valueOf(1l)).xor(mask128);
this.string = s.toLowerCase();
this.addr = new BigInteger(1, addr.getAddress()).and(this.mask);
this.addrI = addr;
}
@Override
public boolean checkBan(InetAddress addr6) {
if(addr6 instanceof Inet6Address) {
Inet6Address a = (Inet6Address)addr6;
BigInteger addrBits = new BigInteger(1, a.getAddress()).and(this.mask);
return addr.equals(addrBits);
}else {
return false;
}
}
@Override
public InetAddress getBaseAddress() {
return addrI;
}
@Override
public String toString() {
return string;
}
@Override
public int hashCode() {
return string.hashCode();
}
@Override
public boolean equals(Object o) {
return o != null && o instanceof IPBan6 && ((IPBan6)o).addr.equals(addr) && ((IPBan6)o).mask.equals(mask);
}
@Override
public boolean hasNetMask() {
return !mask.equals(mask128);
}
}
public static final File bansFile = new File("bans.txt");
public static final String banChatMessagePrefix = ChatColor.GOLD + "[BanList] ";
public static final Map<String,String> userBans = new HashMap();
public static final Set<IPBan> ipBans = new HashSet();
public static final Set<String> wildcardBans = new HashSet();
public static final Set<RegexBan> regexBans = new HashSet();
private static List<String> currentBanList = null;
public static final List<IPBan> blockedBans = new ArrayList();
static {
try {
blockedBans.add(constructIpBan("127.0.0.0/8"));
}catch(UnknownHostException e) {
System.err.println("Error: could not whitelist '127.0.0.0/8'");
e.printStackTrace();
}
try {
blockedBans.add(constructIpBan("10.0.0.0/8"));
}catch(UnknownHostException e) {
System.err.println("Error: could not whitelist '10.0.0.0/8'");
e.printStackTrace();
}
try {
blockedBans.add(constructIpBan("172.24.0.0/14"));
}catch(UnknownHostException e) {
System.err.println("Error: could not whitelist '172.24.0.0/14'");
e.printStackTrace();
}
try {
blockedBans.add(constructIpBan("192.168.0.0/16"));
}catch(UnknownHostException e) {
System.err.println("Error: could not whitelist '192.168.0.0/16'");
e.printStackTrace();
}
try {
blockedBans.add(constructIpBan("::1/128"));
}catch(UnknownHostException e) {
System.err.println("Error: could not whitelist '::1/128'");
e.printStackTrace();
}
}
private static long lastListTest = 0l;
private static long lastListLoad = 0l;
private static boolean fileIsBroken = false;
public static BanCheck checkIpBanned(InetAddress addr) {
synchronized(banListMutex) {
for(IPBan b : ipBans) {
if(b.checkBan(addr)) {
return new BanCheck(BanState.IP_BANNED, b.toString(), b.hasNetMask() ? "Banned by Netmask" : "Banned by IP");
}
}
}
return new BanCheck(BanState.NOT_BANNED, "none", "not banned");
}
public static BanCheck checkBanned(String player) {
synchronized(banListMutex) {
player = player.trim().toLowerCase();
String r = userBans.get(player);
if(r != null) {
if(r.length() <= 0) {
r = "The ban hammer has spoken";
}
return new BanCheck(BanState.USER_BANNED, player, r);
}
for(String ss : wildcardBans) {
String s = ss;
boolean startStar = s.startsWith("*");
if(startStar) {
s = s.substring(1);
}
boolean endStar = s.endsWith("*");
if(endStar) {
s = s.substring(0, s.length() - 1);
}
if(startStar && endStar) {
if(player.contains(s)) {
return new BanCheck(BanState.WILDCARD_BANNED, ss, "You've been banned via wildcard");
}
}else if(endStar) {
if(player.startsWith(s)) {
return new BanCheck(BanState.WILDCARD_BANNED, ss, "You've been banned via wildcard");
}
}else if(startStar) {
if(player.endsWith(s)) {
return new BanCheck(BanState.WILDCARD_BANNED, ss, "You've been banned via wildcard");
}
}else {
if(player.equals(s)) {
return new BanCheck(BanState.WILDCARD_BANNED, ss, "You've been banned via wildcard");
}
}
}
for(RegexBan p : regexBans) {
if(p.compiled.matcher(player).matches()) {
return new BanCheck(BanState.REGEX_BANNED, p.string, "You've been banned via regex");
}
}
}
return new BanCheck(BanState.NOT_BANNED, "none", "not banned");
}
private static void saveCurrentBanListLines() {
try {
PrintWriter pf = new PrintWriter(new FileWriter(bansFile));
for(String s : currentBanList) {
pf.println(s);
}
pf.close();
lastListLoad = lastListTest = System.currentTimeMillis();
}catch(Throwable t) {
System.err.println("ERROR: the ban list could not be saved to file '" + bansFile.getName() + "', please fix this or you will lose all your bans next time this server restarts");
t.printStackTrace();
}
}
private static boolean addEntryToFile(BanState b, String s) {
if(b == null || b == BanState.NOT_BANNED) {
return false;
}
String wantedHeader = b == BanState.USER_BANNED ? "[Usernames]" : (b == BanState.WILDCARD_BANNED ? "[Wildcards]" : (b == BanState.REGEX_BANNED ? "[Regex]" : (b == BanState.IP_BANNED ? "[IPs]" : "shit")));
int lastFullPart = -1;
boolean isFilePart = false;
boolean isPartStart = false;
for(int i = 0, l = currentBanList.size(); i < l; ++i) {
String ss = currentBanList.get(i).trim();
if(ss.length() <= 0) {
continue;
}
if(ss.startsWith("#")) {
continue;
}
if(ss.equalsIgnoreCase(wantedHeader)) {
isFilePart = true;
isPartStart = true;
lastFullPart = i;
}else if(ss.indexOf('[') != -1) {
if(isFilePart) {
break;
}
}else {
if(isFilePart) {
lastFullPart = i;
isPartStart = false;
}
}
}
if(lastFullPart != -1) {
if(isPartStart) {
lastFullPart += 1;
currentBanList.add(lastFullPart, "");
}
lastFullPart += 1;
currentBanList.add(lastFullPart, s);
lastFullPart += 1;
if(currentBanList.size() > lastFullPart && currentBanList.get(lastFullPart).trim().length() > 0) {
currentBanList.add(lastFullPart, "");
}
}else {
if(currentBanList.size() > 0 && currentBanList.get(currentBanList.size() - 1).trim().length() > 0) {
currentBanList.add("");
}
currentBanList.add(wantedHeader);
currentBanList.add("");
currentBanList.add(s);
currentBanList.add("");
}
saveCurrentBanListLines();
return true;
}
private static boolean removeEntryFromFile(BanState b, String s, boolean ignoreCase) {
if(b == null || b == BanState.NOT_BANNED) {
return false;
}
String wantedHeader = b == BanState.USER_BANNED ? "[Usernames]" : (b == BanState.WILDCARD_BANNED ? "[Wildcards]" : (b == BanState.REGEX_BANNED ? "[Regex]" : (b == BanState.IP_BANNED ? "[IPs]" : "shit")));
Iterator<String> lns = currentBanList.iterator();
boolean isFilePart = false;
boolean wasRemoved = false;
while(lns.hasNext()) {
String ss = lns.next().trim();
if(ss.length() <= 0) {
continue;
}
if(ss.startsWith("#")) {
continue;
}
if(ss.equalsIgnoreCase(wantedHeader)) {
isFilePart = true;
}else if(ss.indexOf('[') != -1) {
isFilePart = false;
}else {
if(b == BanState.USER_BANNED && ss.contains(":")) {
ss = ss.substring(0, ss.indexOf(':')).trim();
}
if(isFilePart && (ignoreCase ? ss.equalsIgnoreCase(s) : ss.equals(s))) {
lns.remove();
wasRemoved = true;
}
}
}
if(wasRemoved) {
saveCurrentBanListLines();
}
return wasRemoved;
}
public static boolean unban(String player) {
synchronized(banListMutex) {
String s = player.trim().toLowerCase();
if(userBans.remove(s) != null) {
removeEntryFromFile(BanState.USER_BANNED, player, true);
return true;
}else {
return false;
}
}
}
public static boolean ban(String player, String reason) {
synchronized(banListMutex) {
player = player.trim().toLowerCase();
if(userBans.put(player, reason) == null) {
addEntryToFile(BanState.USER_BANNED, player + (reason == null || reason.length() <= 0 ? "" : ": " + reason));
return true;
}else {
return false;
}
}
}
public static boolean banWildcard(String wc) throws PatternSyntaxException {
synchronized(banListMutex) {
wc = wc.trim().toLowerCase();
boolean b = wc.contains("*");
if(!b || (b && !wc.startsWith("*") && !wc.endsWith("*"))) {
throw new PatternSyntaxException("Wildcard can only begin and/or end with *", wc, 0);
}
if(wildcardBans.add(wc)) {
addEntryToFile(BanState.WILDCARD_BANNED, wc);
return true;
}else {
return false;
}
}
}
public static boolean unbanWildcard(String wc) {
synchronized(banListMutex) {
wc = wc.trim().toLowerCase();
if(wildcardBans.remove(wc)) {
removeEntryFromFile(BanState.WILDCARD_BANNED, wc, true);
return true;
}else {
return false;
}
}
}
public static boolean banRegex(String regex) throws PatternSyntaxException {
synchronized(banListMutex) {
regex = regex.trim();
Pattern p = Pattern.compile(regex);
if(regexBans.add(new RegexBan(regex, p))) {
addEntryToFile(BanState.REGEX_BANNED, regex);
return true;
}else {
return false;
}
}
}
public static boolean unbanRegex(String regex) {
synchronized(banListMutex) {
regex = regex.trim();
Iterator<RegexBan> banz = regexBans.iterator();
while(banz.hasNext()) {
if(banz.next().string.equals(regex)) {
banz.remove();
removeEntryFromFile(BanState.REGEX_BANNED, regex, false);
return true;
}
}
return false;
}
}
public static IPBan constructIpBan(String ip) throws UnknownHostException {
synchronized(banListMutex) {
ip = ip.trim();
String s = ip;
int subnet = -1;
int i = s.indexOf('/');
if(i != -1) {
String s2 = s.substring(i + 1);
s = s.substring(0, i);
try {
subnet = Integer.parseInt(s2);
}catch(Throwable t) {
throw new UnknownHostException("Invalid netmask: '" + s + "'");
}
}
if(!IPAddressUtil.isIPv4LiteralAddress(s) && !IPAddressUtil.isIPv6LiteralAddress(s)) {
throw new UnknownHostException("Invalid address: '" + s + "'");
}
InetAddress aa = InetAddress.getByName(s);
if(aa instanceof Inet4Address) {
if(subnet > 32 || subnet < -1) {
throw new UnknownHostException("IPv4 netmask '" + subnet + "' is invalid");
}
if(subnet == -1) {
subnet = 32;
}
return new IPBan4((Inet4Address)aa, ip, subnet);
}else if(aa instanceof Inet6Address) {
if(subnet > 128 || subnet < -1) {
throw new UnknownHostException("IPv6 netmask '" + subnet + "' is invalid");
}
if(subnet == -1) {
subnet = 128;
}
return new IPBan6((Inet6Address)aa, ip, subnet);
}else {
throw new UnknownHostException("Only ipv4 and ipv6 addresses allowed in Eaglercraft");
}
}
}
public static boolean banIP(String ip) throws UnknownHostException {
synchronized(banListMutex) {
ip = ip.trim();
IPBan b = constructIpBan(ip);
if(b != null) {
if(ipBans.add(b)) {
addEntryToFile(BanState.IP_BANNED, ip);
return true;
}
}
return false;
}
}
public static boolean unbanIP(String ip) throws UnknownHostException {
synchronized(banListMutex) {
ip = ip.trim();
IPBan b = constructIpBan(ip);
if(b != null) {
Iterator<IPBan> banz = ipBans.iterator();
while(banz.hasNext()) {
IPBan bb = banz.next();
if(bb.equals(b)) {
banz.remove();
removeEntryFromFile(BanState.IP_BANNED, bb.toString(), true);
return true;
}
}
}
return false;
}
}
private static final int MAX_CHAT_LENGTH = 118;
public static String listAllBans() {
synchronized(banListMutex) {
String ret = "";
for(String s : userBans.keySet()) {
if(ret.length() > 0) {
ret += ", ";
}
ret += s;
}
return ret.length() > 0 ? ret : "(none)";
}
}
public static String listAllWildcardBans() {
synchronized(banListMutex) {
String ret = "";
for(String s : wildcardBans) {
if(ret.length() > 0) {
ret += ", ";
}
ret += s;
}
return ret.length() > 0 ? ret : "(none)";
}
}
public static String listAllRegexBans() {
synchronized(banListMutex) {
String ret = "";
for(RegexBan s : regexBans) {
if(ret.length() > 0) {
ret += " | ";
}
ret += s.string;
}
return ret.length() > 0 ? ret : "(none)";
}
}
public static String listAllIPBans(boolean v6, boolean netmask) {
synchronized(banListMutex) {
String ret = "";
for(IPBan b : ipBans) {
if(v6) {
if(b instanceof IPBan6) {
IPBan6 b2 = (IPBan6)b;
if(netmask == b2.hasNetMask()) {
if(ret.length() > 0) {
ret += ", ";
}
ret += b2.string;
}
}
}else {
if(b instanceof IPBan4) {
IPBan4 b2 = (IPBan4)b;
if(netmask == b2.hasNetMask()) {
if(ret.length() > 0) {
ret += ", ";
}
ret += b2.string;
}
}
}
}
if(ret.length() <= 0) {
ret = "(none)";
}
return ret;
}
}
public static void maybeReloadBans(CommandSender cs) {
synchronized(banListMutex) {
long st = System.currentTimeMillis();
if(cs == null && st - lastListTest < 1000l) {
return;
}
lastListTest = st;
boolean ex = bansFile.exists();
if(!fileIsBroken && !ex) {
try {
PrintWriter p = new PrintWriter(new FileWriter(bansFile));
p.println();
p.println("#");
p.println("# This file allows you to configure bans for eaglercraftbungee");
p.println("# When it is saved, eaglercraft should reload it automatically");
p.println("# (check the console though to be safe)");
p.println("#");
p.println("# For a [Usernames] ban, just add the player's name. Use a colon ':' to put in a ban reason");
p.println("# For a [IPs] ban, just add the player's IP, or a subnet like 69.69.0.0/16 to ban all IPs beginning with 69.69.*");
p.println("# For a [Wildcards] ban, type a string and prefix and/or suffix it with * to define the wildcard");
p.println("# For a [Regex] ban, type a valid regular expression in the java.util.regex format");
p.println("#");
p.println("# All bans are case-insensitive, USERNAMES ARE CONVERTED TO LOWERCASE BEFORE BEING MATCHED VIA REGEX");
p.println("# Java regex syntax: https://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html");
p.println("#");
p.println();
p.println("# set this to false to use \"/eag-ban\" to ban on bungee instead of just \"/ban\"");
p.println("# (most likely needs a restart to take effect)");
p.println("replace-bukkit=true");
p.println();
p.println();
p.println("[Usernames]");
p.println();
p.println("# ban_test1: The ban hammer has spoken!");
p.println("# ban_test2: custom ban message here");
p.println("# ban_test3");
p.println();
p.println("# (remove the '#' before each line to enable)");
p.println();
p.println("[IPs]");
p.println();
p.println("# WARNING: if you're using nginx, banning any player's IP is gonna ban ALL PLAYERS on your server");
p.println("# For this reason, the ban IP command doesn't ban 127.0.0.1 or any other 'private' range IPs");
p.println();
p.println("# 101.202.69.11");
p.println("# 123.21.43.0/24");
p.println("# 2601:1062:69:418:BEEF::10");
p.println("# 2601:6090:420::/48");
p.println();
p.println();
p.println("[Wildcards]");
p.println();
p.println("# *fuck*");
p.println("# nigg*");
p.println();
p.println();
p.println("[Regex]");
p.println();
p.println("# you.+are.(a|the).+bitch");
p.println();
p.println();
p.println("# end of file");
p.println();
p.close();
System.out.println("Wrote a new bans.txt to: " + bansFile.getAbsolutePath());
lastListLoad = 0l;
}catch(Throwable t) {
fileIsBroken = true;
if(cs != null) {
cs.sendMessage(banChatMessagePrefix + ChatColor.RED + "Could not create blank 'bans.txt' list file");
cs.sendMessage(banChatMessagePrefix + ChatColor.RED + "(Reason: " + t.toString() + ")");
}
System.err.println("Could not create blank 'bans.txt' list file");
System.err.println("(Reason: " + t.toString() + ")");
t.printStackTrace();
}
return;
}
if(fileIsBroken && ex) {
fileIsBroken = false;
lastListLoad = 0l;
}
if(fileIsBroken) {
return;
}
long lastEdit = bansFile.lastModified();
if(cs != null || lastEdit - lastListLoad > 400l) {
try {
BufferedReader r = new BufferedReader(new FileReader(bansFile));
currentBanList = new LinkedList();
String s;
while((s = r.readLine()) != null) {
currentBanList.add(s);
}
r.close();
lastListLoad = lastEdit;
System.out.println("Server bans.txt changed, it will be reloaded automatically");
if(cs == null) {
for(ProxiedPlayer pp : BungeeCord.getInstance().getPlayers()) {
if(pp.hasPermission("bungeecord.command.eag.reloadban")) {
pp.sendMessage(BanList.banChatMessagePrefix + ChatColor.WHITE + "Your Eaglercraftbungee bans.txt just got modified, it will be reloaded asap");
pp.sendMessage(BanList.banChatMessagePrefix + ChatColor.YELLOW + "Stop your server and check your config immediately if you don't know how this happened!!");
}
}
}
parseListFrom();
System.out.println("Reload complete");
}catch(Throwable t) {
if(cs != null) {
cs.sendMessage(banChatMessagePrefix + ChatColor.RED + "Could not reload 'bans.txt' list file");
cs.sendMessage(banChatMessagePrefix + ChatColor.RED + "(Reason: " + t.toString() + ")");
}
System.err.println("Could not reload 'bans.txt' list file");
System.err.println("(Reason: " + t.toString() + ")");
}
}
}
}
private static void parseListFrom() {
userBans.clear();
ipBans.clear();
wildcardBans.clear();
regexBans.clear();
int filePart = 0;
boolean replaceBukkit = false;
for(String s : currentBanList) {
s = s.trim();
if(s.length() <= 0) {
continue;
}
if(s.startsWith("#")) {
continue;
}
if(s.equals("[Usernames]")) {
filePart = 1;
}else if(s.equals("[Wildcards]")) {
filePart = 2;
}else if(s.equals("[Regex]")) {
filePart = 3;
}else if(s.equals("[IPs]")) {
filePart = 4;
}else if(s.equals("replace-bukkit=true")) {
replaceBukkit = true;
}else if(s.equals("replace-bukkit=false")) {
continue;
}else {
if(filePart == 1) {
int i = s.indexOf(':');
if(i == -1) {
userBans.put(s.toLowerCase(), "");
}else {
userBans.put(s.substring(0, i).trim().toLowerCase(), s.substring(i + 1).trim());
}
}else if(filePart == 2) {
boolean ws = s.startsWith("*");
boolean we = s.endsWith("*");
if(!ws && !we) {
if(s.contains("*")) {
System.err.println("Error: wildcard '" + s + "' contains a '*' not at the start/end of the string");
}else {
System.err.println("Error: wildcard '" + s + "' does not contain a '*' wildcard character");
}
}else {
int total = (ws ? 1 : 0) + (we ? 1 : 0);
int t2 = 0;
for(char c : s.toCharArray()) {
if(c == '*') ++t2;
}
if(total != t2) {
System.err.println("Error: wildcard '" + s + "' contains a '*' not at the start/end of the string");
}
}
wildcardBans.add(s.toLowerCase());
}else if(filePart == 3) {
Pattern p = null;
try {
p = Pattern.compile(s);
}catch(Throwable t) {
System.err.println("Error: the regex " + s.toLowerCase() + " is invalid");
System.err.println("Reason: " + t.getClass().getSimpleName() + ": " + t.getLocalizedMessage());
}
if(p != null) {
regexBans.add(new RegexBan(s, p));
}
}else if(filePart == 4) {
String ss = s;
int subnet = -1;
int i = s.indexOf('/');
if(i != -1) {
String s2 = s.substring(i + 1);
s = s.substring(0, i);
try {
subnet = Integer.parseInt(s2);
}catch(Throwable t) {
System.err.println("Error: the subnet '"+ s2 +"' for IP ban address " + s + " was invalid");
subnet = -2;
}
}
if(subnet >= -1) {
try {
InetAddress aa = InetAddress.getByName(s);
if(aa instanceof Inet4Address) {
if(subnet == -1) {
subnet = 32;
}
ipBans.add(new IPBan4((Inet4Address)aa, ss, subnet));
}else if(aa instanceof Inet6Address) {
if(subnet == -1) {
subnet = 128;
}
ipBans.add(new IPBan6((Inet6Address)aa, ss, subnet));
}else {
throw new UnknownHostException("Only ipv4 and ipv6 addresses allowed in Eaglercraft");
}
}catch(Throwable t) {
System.err.println("Error: the IP ban address " + s + " could not be parsed");
t.printStackTrace();
}
}
}
}
}
BungeeCord.getInstance().reconfigureBanCommands(replaceBukkit);
}
}

View file

@ -0,0 +1,9 @@
package net.md_5.bungee.eaglercraft;
public class EaglercraftBungee {
public static final String brand = "Eagtek";
public static final String version = "0.1.0";
public static final boolean cracked = true;
}

View file

@ -1,33 +1,50 @@
package net.md_5.bungee.eaglercraft; package net.md_5.bungee.eaglercraft;
import java.net.InetAddress;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import org.java_websocket.WebSocket; import org.java_websocket.WebSocket;
import org.java_websocket.handshake.ClientHandshake; import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.server.WebSocketServer; import org.java_websocket.server.WebSocketServer;
import net.md_5.bungee.BungeeCord;
import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.config.ListenerInfo; import net.md_5.bungee.api.config.ListenerInfo;
public class WebSocketListener extends WebSocketServer { public class WebSocketListener extends WebSocketServer {
public static class PendingSocket {
public long openTime;
public InetAddress realAddress;
protected PendingSocket(long openTime, InetAddress realAddress) {
this.openTime = openTime;
this.realAddress = realAddress;
}
}
private InetSocketAddress bungeeProxy; private InetSocketAddress bungeeProxy;
private ProxyServer bungeeCord; private ProxyServer bungeeCord;
private ListenerInfo info;
public WebSocketListener(ListenerInfo info, InetSocketAddress sock, ProxyServer bungeeCord) { public WebSocketListener(ListenerInfo info, InetSocketAddress sock, ProxyServer bungeeCord) {
super(info.getHost()); super(info.getHost());
this.setTcpNoDelay(true); this.setTcpNoDelay(true);
this.setConnectionLostTimeout(5); this.setConnectionLostTimeout(5);
this.start(); this.start();
this.info = info;
this.bungeeProxy = sock; this.bungeeProxy = sock;
this.bungeeCord = bungeeCord; this.bungeeCord = bungeeCord;
} }
@Override @Override
public void onClose(WebSocket arg0, int arg1, String arg2, boolean arg3) { public void onClose(WebSocket arg0, int arg1, String arg2, boolean arg3) {
if(arg0.getAttachment() != null) { Object o = arg0.getAttachment();
((WebSocketProxy)arg0.getAttachment()).killConnection(); if(o != null) {
if(o instanceof WebSocketProxy) {
((WebSocketProxy)arg0.getAttachment()).killConnection();
}
} }
System.out.println("websocket closed - " + arg0.getRemoteSocketAddress()); System.out.println("websocket closed - " + arg0.getRemoteSocketAddress());
} }
@ -43,24 +60,73 @@ public class WebSocketListener extends WebSocketServer {
@Override @Override
public void onMessage(WebSocket arg0, ByteBuffer arg1) { public void onMessage(WebSocket arg0, ByteBuffer arg1) {
if(arg0.getAttachment() != null) { Object o = arg0.getAttachment();
((WebSocketProxy)arg0.getAttachment()).sendPacket(arg1); if(o == null || (o instanceof PendingSocket)) {
InetAddress realAddr;
if(o == null) {
realAddr = arg0.getRemoteSocketAddress().getAddress();
}else {
realAddr = ((PendingSocket)o).realAddress;
}
System.out.println("connection is binary - " + realAddr);
WebSocketProxy proxyObj = new WebSocketProxy(arg0, realAddr, bungeeProxy);
arg0.setAttachment(proxyObj);
if(!proxyObj.connect()) {
System.err.println("loopback to '" + bungeeProxy.toString() + "' failed - " + realAddr);
arg0.close();
return;
}
o = proxyObj;
}
if(o != null) {
if(o instanceof WebSocketProxy) {
((WebSocketProxy)o).sendPacket(arg1);
}else {
System.out.println("error: recieved binary data on text websocket - " + arg0.getRemoteSocketAddress());
arg0.close();
}
} }
} }
@Override @Override
public void onOpen(WebSocket arg0, ClientHandshake arg1) { public void onOpen(WebSocket arg0, ClientHandshake arg1) {
System.out.println("websocket opened - " + arg0.getRemoteSocketAddress()); System.out.println("websocket opened - " + arg0.getRemoteSocketAddress());
WebSocketProxy proxyObj = new WebSocketProxy(arg0, bungeeProxy); if(info.hasForwardedHeaders()) {
arg0.setAttachment(proxyObj); String s = arg1.getFieldValue("X-Real-IP");
if(!proxyObj.connect()) { if(s != null) {
arg0.close(); try {
InetAddress addr = InetAddress.getByName(s);
arg0.setAttachment(new PendingSocket(System.currentTimeMillis(), addr));
System.out.println("real IP of '" + arg0.getRemoteSocketAddress().toString() + "' is '" + addr.getHostAddress() + "'");
}catch(UnknownHostException e) {
System.out.println("invalid 'X-Real-IP' header - " + e.toString());
arg0.close();
}
}else {
arg0.setAttachment(new PendingSocket(System.currentTimeMillis(), arg0.getRemoteSocketAddress().getAddress()));
}
}else {
arg0.setAttachment(new PendingSocket(System.currentTimeMillis(), arg0.getRemoteSocketAddress().getAddress()));
} }
} }
@Override @Override
public void onStart() { public void onStart() {
}
public void closeInactiveSockets() {
for(WebSocket w : this.getConnections()) {
Object o = w.getAttachment();
if(o == null) {
System.out.println("close inactive websocket - " + w.getRemoteSocketAddress());
w.close();
}else if(o instanceof PendingSocket) {
if(System.currentTimeMillis() - ((PendingSocket)o).openTime > 5000l) {
System.out.println("close inactive websocket - " + ((PendingSocket)o).realAddress);
w.close();
}
}
}
} }
} }

View file

@ -1,7 +1,9 @@
package net.md_5.bungee.eaglercraft; package net.md_5.bungee.eaglercraft;
import java.net.InetAddress;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.HashMap;
import org.java_websocket.WebSocket; import org.java_websocket.WebSocket;
@ -16,6 +18,8 @@ import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
/** /**
* Not the ideal solution but what are we supposed to do * Not the ideal solution but what are we supposed to do
@ -25,20 +29,22 @@ public class WebSocketProxy extends SimpleChannelInboundHandler<ByteBuf> {
private WebSocket client; private WebSocket client;
private InetSocketAddress tcpListener; private InetSocketAddress tcpListener;
private InetSocketAddress localAddress;
private InetAddress realRemoteAddr;
private NioSocketChannel tcpChannel; private NioSocketChannel tcpChannel;
private static final EventLoopGroup group = new NioEventLoopGroup(4); private static final EventLoopGroup group = new NioEventLoopGroup(4);
public static final HashMap<InetSocketAddress,InetAddress> localToRemote = new HashMap();
public WebSocketProxy(WebSocket w, InetSocketAddress addr) { public WebSocketProxy(WebSocket w, InetAddress remoteAddr, InetSocketAddress addr) {
client = w; client = w;
realRemoteAddr = remoteAddr;
tcpListener = addr; tcpListener = addr;
tcpChannel = null; tcpChannel = null;
} }
public void killConnection() { public void killConnection() {
if(client.isOpen()) { localToRemote.remove(localAddress);
client.close();
}
if(tcpChannel != null && tcpChannel.isOpen()) { if(tcpChannel != null && tcpChannel.isOpen()) {
try { try {
tcpChannel.disconnect().sync(); tcpChannel.disconnect().sync();
@ -59,9 +65,16 @@ public class WebSocketProxy extends SimpleChannelInboundHandler<ByteBuf> {
clientBootstrap.handler(new ChannelInitializer<SocketChannel>() { clientBootstrap.handler(new ChannelInitializer<SocketChannel>() {
protected void initChannel(SocketChannel socketChannel) throws Exception { protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(WebSocketProxy.this); socketChannel.pipeline().addLast(WebSocketProxy.this);
socketChannel.closeFuture().addListener(new GenericFutureListener<Future<? super Void>>() {
@Override
public void operationComplete(Future<? super Void> paramF) throws Exception {
localToRemote.remove(localAddress);
}
});
} }
}); });
tcpChannel = (NioSocketChannel) clientBootstrap.connect().sync().channel(); tcpChannel = (NioSocketChannel) clientBootstrap.connect().sync().channel();
localToRemote.put(localAddress = tcpChannel.localAddress(), realRemoteAddr);
return true; return true;
} }
}catch(Throwable t) { }catch(Throwable t) {
@ -89,4 +102,8 @@ public class WebSocketProxy extends SimpleChannelInboundHandler<ByteBuf> {
} }
} }
public void finalize() {
localToRemote.remove(localAddress);
}
} }

View file

@ -0,0 +1,323 @@
package net.md_5.bungee.eaglercraft.sun.net.util;
import java.net.URL;
import java.util.Arrays;
public class IPAddressUtil {
private static final int INADDR4SZ = 4;
private static final int INADDR16SZ = 16;
private static final int INT16SZ = 2;
private static final long L_IPV6_DELIMS = 0L;
private static final long H_IPV6_DELIMS = 671088640L;
private static final long L_GEN_DELIMS = -8935000888854970368L;
private static final long H_GEN_DELIMS = 671088641L;
private static final long L_AUTH_DELIMS = 288230376151711744L;
private static final long H_AUTH_DELIMS = 671088641L;
private static final long L_COLON = 288230376151711744L;
private static final long H_COLON = 0L;
private static final long L_SLASH = 140737488355328L;
private static final long H_SLASH = 0L;
private static final long L_BACKSLASH = 0L;
private static final long H_BACKSLASH = 268435456L;
private static final long L_NON_PRINTABLE = 4294967295L;
private static final long H_NON_PRINTABLE = -9223372036854775808L;
private static final long L_EXCLUDE = -8935000884560003073L;
private static final long H_EXCLUDE = -9223372035915251711L;
public static byte[] textToNumericFormatV4(String paramString) {
byte[] arrayOfByte = new byte[4];
long l = 0L;
byte b1 = 0;
boolean bool = true;
int i = paramString.length();
if (i == 0 || i > 15)
return null;
for (byte b2 = 0; b2 < i; b2++) {
char c = paramString.charAt(b2);
if (c == '.') {
if (bool || l < 0L || l > 255L || b1 == 3)
return null;
arrayOfByte[b1++] = (byte) (int) (l & 0xFFL);
l = 0L;
bool = true;
} else {
int j = Character.digit(c, 10);
if (j < 0)
return null;
l *= 10L;
l += j;
bool = false;
}
}
if (bool || l < 0L || l >= 1L << (4 - b1) * 8)
return null;
switch (b1) {
case 0 :
arrayOfByte[0] = (byte) (int) (l >> 24L & 0xFFL);
case 1 :
arrayOfByte[1] = (byte) (int) (l >> 16L & 0xFFL);
case 2 :
arrayOfByte[2] = (byte) (int) (l >> 8L & 0xFFL);
case 3 :
arrayOfByte[3] = (byte) (int) (l >> 0L & 0xFFL);
break;
}
return arrayOfByte;
}
public static byte[] textToNumericFormatV6(String paramString) {
if (paramString.length() < 2)
return null;
char[] arrayOfChar = paramString.toCharArray();
byte[] arrayOfByte1 = new byte[16];
int j = arrayOfChar.length;
int k = paramString.indexOf("%");
if (k == j - 1)
return null;
if (k != -1)
j = k;
byte b = -1;
byte b1 = 0, b2 = 0;
if (arrayOfChar[b1] == ':' && arrayOfChar[++b1] != ':')
return null;
byte b3 = b1;
boolean bool = false;
int i = 0;
while (b1 < j) {
char c = arrayOfChar[b1++];
int m = Character.digit(c, 16);
if (m != -1) {
i <<= 4;
i |= m;
if (i > 65535)
return null;
bool = true;
continue;
}
if (c == ':') {
b3 = b1;
if (!bool) {
if (b != -1)
return null;
b = b2;
continue;
}
if (b1 == j)
return null;
if (b2 + 2 > 16)
return null;
arrayOfByte1[b2++] = (byte) (i >> 8 & 0xFF);
arrayOfByte1[b2++] = (byte) (i & 0xFF);
bool = false;
i = 0;
continue;
}
if (c == '.' && b2 + 4 <= 16) {
String str = paramString.substring(b3, j);
byte b4 = 0;
int n = 0;
while ((n = str.indexOf('.', n)) != -1) {
b4++;
n++;
}
if (b4 != 3)
return null;
byte[] arrayOfByte = textToNumericFormatV4(str);
if (arrayOfByte == null)
return null;
for (byte b5 = 0; b5 < 4; b5++)
arrayOfByte1[b2++] = arrayOfByte[b5];
bool = false;
break;
}
return null;
}
if (bool) {
if (b2 + 2 > 16)
return null;
arrayOfByte1[b2++] = (byte) (i >> 8 & 0xFF);
arrayOfByte1[b2++] = (byte) (i & 0xFF);
}
if (b != -1) {
int m = b2 - b;
if (b2 == 16)
return null;
for (b1 = 1; b1 <= m; b1++) {
arrayOfByte1[16 - b1] = arrayOfByte1[b + m - b1];
arrayOfByte1[b + m - b1] = 0;
}
b2 = 16;
}
if (b2 != 16)
return null;
byte[] arrayOfByte2 = convertFromIPv4MappedAddress(arrayOfByte1);
if (arrayOfByte2 != null)
return arrayOfByte2;
return arrayOfByte1;
}
public static boolean isIPv4LiteralAddress(String paramString) {
return (textToNumericFormatV4(paramString) != null);
}
public static boolean isIPv6LiteralAddress(String paramString) {
return (textToNumericFormatV6(paramString) != null);
}
public static byte[] convertFromIPv4MappedAddress(byte[] paramArrayOfbyte) {
if (isIPv4MappedAddress(paramArrayOfbyte)) {
byte[] arrayOfByte = new byte[4];
System.arraycopy(paramArrayOfbyte, 12, arrayOfByte, 0, 4);
return arrayOfByte;
}
return null;
}
private static boolean isIPv4MappedAddress(byte[] paramArrayOfbyte) {
if (paramArrayOfbyte.length < 16)
return false;
if (paramArrayOfbyte[0] == 0 && paramArrayOfbyte[1] == 0 && paramArrayOfbyte[2] == 0 && paramArrayOfbyte[3] == 0
&& paramArrayOfbyte[4] == 0 && paramArrayOfbyte[5] == 0 && paramArrayOfbyte[6] == 0
&& paramArrayOfbyte[7] == 0 && paramArrayOfbyte[8] == 0 && paramArrayOfbyte[9] == 0
&& paramArrayOfbyte[10] == -1 && paramArrayOfbyte[11] == -1)
return true;
return false;
}
public static boolean match(char paramChar, long paramLong1, long paramLong2) {
if (paramChar < '@')
return ((1L << paramChar & paramLong1) != 0L);
if (paramChar < '€')
return ((1L << paramChar - 64 & paramLong2) != 0L);
return false;
}
public static int scan(String paramString, long paramLong1, long paramLong2) {
byte b = -1;
int i;
if (paramString == null || (i = paramString.length()) == 0)
return -1;
boolean bool = false;
while (++b < i && !(bool = match(paramString.charAt(b), paramLong1, paramLong2)));
if (bool)
return b;
return -1;
}
public static int scan(String paramString, long paramLong1, long paramLong2, char[] paramArrayOfchar) {
byte b = -1;
int i;
if (paramString == null || (i = paramString.length()) == 0)
return -1;
boolean bool = false;
char c2 = paramArrayOfchar[0];
char c1;
while (++b < i && !(bool = match(c1 = paramString.charAt(b), paramLong1, paramLong2))) {
if (c1 >= c2 && Arrays.binarySearch(paramArrayOfchar, c1) > -1) {
bool = true;
break;
}
}
if (bool)
return b;
return -1;
}
private static String describeChar(char paramChar) {
if (paramChar < ' ' || paramChar == '') {
if (paramChar == '\n')
return "LF";
if (paramChar == '\r')
return "CR";
return "control char (code=" + paramChar + ")";
}
if (paramChar == '\\')
return "'\\'";
return "'" + paramChar + "'";
}
private static String checkUserInfo(String paramString) {
int i = scan(paramString, -9223231260711714817L, -9223372035915251711L);
if (i >= 0)
return "Illegal character found in user-info: " + describeChar(paramString.charAt(i));
return null;
}
private static String checkHost(String paramString) {
if (paramString.startsWith("[") && paramString.endsWith("]")) {
paramString = paramString.substring(1, paramString.length() - 1);
if (isIPv6LiteralAddress(paramString)) {
int j = paramString.indexOf('%');
if (j >= 0) {
j = scan(paramString = paramString.substring(j), 4294967295L, -9223372036183687168L);
if (j >= 0)
return "Illegal character found in IPv6 scoped address: " + describeChar(paramString.charAt(j));
}
return null;
}
return "Unrecognized IPv6 address format";
}
int i = scan(paramString, -8935000884560003073L, -9223372035915251711L);
if (i >= 0)
return "Illegal character found in host: " + describeChar(paramString.charAt(i));
return null;
}
private static String checkAuth(String paramString) {
int i = scan(paramString, -9223231260711714817L, -9223372036586340352L);
if (i >= 0)
return "Illegal character found in authority: " + describeChar(paramString.charAt(i));
return null;
}
public static String checkAuthority(URL paramURL) {
if (paramURL == null)
return null;
String str1;
String str2;
if ((str1 = checkUserInfo(str2 = paramURL.getUserInfo())) != null)
return str1;
String str3;
if ((str1 = checkHost(str3 = paramURL.getHost())) != null)
return str1;
if (str3 == null && str2 == null)
return checkAuth(paramURL.getAuthority());
return null;
}
public static String checkExternalForm(URL paramURL) {
if (paramURL == null)
return null;
String str;
int i = scan(str = paramURL.getUserInfo(), 140741783322623L, Long.MIN_VALUE);
if (i >= 0)
return "Illegal character found in authority: " + describeChar(str.charAt(i));
if ((str = checkHostString(paramURL.getHost())) != null)
return str;
return null;
}
public static String checkHostString(String paramString) {
if (paramString == null)
return null;
return null;
}
}