From c0464d9c47b4a3e21a614e3965052889755536f7 Mon Sep 17 00:00:00 2001 From: linsaftw <25271111+linsaftw@users.noreply.github.com> Date: Fri, 30 Apr 2021 22:54:44 -0300 Subject: [PATCH] Firewall System diff --git a/flamecord/src/main/java/dev/_2lstudios/flamecord/FlameCord.java b/flamecord/src/main/java/dev/_2lstudios/flamecord/FlameCord.java index 8957c79ac..fd889644f 100644 --- a/flamecord/src/main/java/dev/_2lstudios/flamecord/FlameCord.java +++ b/flamecord/src/main/java/dev/_2lstudios/flamecord/FlameCord.java @@ -6,6 +6,7 @@ import java.util.logging.Logger; import dev._2lstudios.flamecord.configuration.FlameCordConfiguration; import dev._2lstudios.flamecord.configuration.MessagesConfiguration; import dev._2lstudios.flamecord.configuration.ModulesConfiguration; +import dev._2lstudios.flamecord.firewall.FirewallManager; import lombok.Getter; import net.md_5.bungee.config.ConfigurationProvider; import net.md_5.bungee.config.YamlConfiguration; @@ -14,12 +15,15 @@ public class FlameCord { @Getter private static FlameCord instance; @Getter + private final FirewallManager firewallManager; + @Getter private final FlameCordConfiguration flameCordConfiguration; @Getter private final ModulesConfiguration modulesConfiguration; @Getter private final MessagesConfiguration messagesConfiguration; @Getter + private final Thread thread; private boolean running = true; public static void renew(final Logger logger, final Collection whitelistedAddresses) { @@ -36,7 +40,29 @@ public class FlameCord { final ConfigurationProvider configurationProvider = ConfigurationProvider.getProvider(YamlConfiguration.class); this.flameCordConfiguration = new FlameCordConfiguration(configurationProvider); + this.firewallManager = new FirewallManager(logger, whitelistedAddresses, + flameCordConfiguration.getFirewallSeconds()); this.modulesConfiguration = new ModulesConfiguration(configurationProvider); this.messagesConfiguration = new MessagesConfiguration(logger, configurationProvider); + this.thread = new Thread() { + @Override + public void run() { + while (running) { + try { + sleep(1000L); + + if (!running) { + return; + } + + firewallManager.tick(); + } catch (final Exception e) { + // Ignored + } + } + } + }; + + this.thread.start(); } } \ No newline at end of file diff --git a/flamecord/src/main/java/dev/_2lstudios/flamecord/configuration/FlameCordConfiguration.java b/flamecord/src/main/java/dev/_2lstudios/flamecord/configuration/FlameCordConfiguration.java index 81ded2243..8bb61ac11 100644 --- a/flamecord/src/main/java/dev/_2lstudios/flamecord/configuration/FlameCordConfiguration.java +++ b/flamecord/src/main/java/dev/_2lstudios/flamecord/configuration/FlameCordConfiguration.java @@ -12,6 +12,15 @@ import net.md_5.bungee.config.Configuration; import net.md_5.bungee.config.ConfigurationProvider; public class FlameCordConfiguration { + @Getter + private boolean firewallNotify = true; + @Getter + private boolean firewallEnabled = true; + @Getter + private int firewallSeconds = 60; + @Getter + private Collection firewallNames = new HashSet<>(Arrays.asList(new String[] { "mcspam" })); + public FlameCordConfiguration(final ConfigurationProvider configurationProvider) { try { final String fileName = "./flamecord.yml"; @@ -25,6 +34,11 @@ public class FlameCordConfiguration { configuration = configurationProvider.load(configurationFile); } + this.firewallEnabled = setIfUnexistant("firewall.enabled", this.firewallEnabled, configuration); + this.firewallNotify = setIfUnexistant("firewall.notify", this.firewallNotify, configuration); + this.firewallSeconds = setIfUnexistant("firewall.seconds", this.firewallSeconds, configuration); + this.firewallNames = setIfUnexistant("firewall.names", this.firewallNames, configuration); + if (!configurationExists) { configurationProvider.save(configuration, configurationFile); } diff --git a/flamecord/src/main/java/dev/_2lstudios/flamecord/configuration/MessagesConfiguration.java b/flamecord/src/main/java/dev/_2lstudios/flamecord/configuration/MessagesConfiguration.java index ebfaa761c..c88077ade 100644 --- a/flamecord/src/main/java/dev/_2lstudios/flamecord/configuration/MessagesConfiguration.java +++ b/flamecord/src/main/java/dev/_2lstudios/flamecord/configuration/MessagesConfiguration.java @@ -82,9 +82,17 @@ public class MessagesConfiguration { setIfUnexistant("command_ip", "&9IP of {0} is {1}", configuration); // FlameCord + setIfUnexistant("firewall_added", "&e{0}&c had been firewalled from the proxy!", configuration); + setIfUnexistant("firewall_blocked", "&e{0}&c is firewalled from the proxy, request blocked!", + configuration); + setIfUnexistant("firewall_info", + "&aThere are&b {0} &aaddresses firewalled!\n&aThe firewall will clear in &b{1} &aseconds!", + configuration); + setIfUnexistant("firewall_cleared", "&b{0}&a addresses had been automatically removed from the firewall!", + configuration); setIfUnexistant("flamecord_reload", "&aAll files had been successfully reloaded!", configuration); setIfUnexistant("flamecord_help", - "&aFlameCord&b {0}&a by&b LinsaFTW&a &&b Sammwy&r\n&e /flamecord reload&7 >&b Reloads FlameCord files!\n&e /flamecord help&7 >&b Shows this message!", + "&aFlameCord&b {0}&a by&b LinsaFTW&a &&b Sammwy&r\n&e /flamecord reload&7 >&b Reloads FlameCord files!\n&e /flamecord firewall&7 >&b Shows information about the Firewall!\n&e /flamecord help&7 >&b Shows this message!", configuration); setIfUnexistant("flamecord_nopermission", "&cYou don't have permission to do this!", configuration); diff --git a/flamecord/src/main/java/dev/_2lstudios/flamecord/firewall/FirewallException.java b/flamecord/src/main/java/dev/_2lstudios/flamecord/firewall/FirewallException.java new file mode 100644 index 000000000..6a661898d --- /dev/null +++ b/flamecord/src/main/java/dev/_2lstudios/flamecord/firewall/FirewallException.java @@ -0,0 +1,30 @@ +package dev._2lstudios.flamecord.firewall; + +import java.net.SocketAddress; + +public class FirewallException extends Exception { + private static final long serialVersionUID = 1L; + + public FirewallException(final SocketAddress address) { + super("The address " + address + " is blocked from the server!"); + } + + public FirewallException(final String string) { + super(string); + } + + public FirewallException(final String string, final Throwable throwable) { + super(string, throwable); + } + + @Override + public synchronized Throwable initCause(final Throwable cause) + { + return this; + } + + @Override + public synchronized Throwable fillInStackTrace() { + return this; + } +} \ No newline at end of file diff --git a/flamecord/src/main/java/dev/_2lstudios/flamecord/firewall/FirewallManager.java b/flamecord/src/main/java/dev/_2lstudios/flamecord/firewall/FirewallManager.java new file mode 100644 index 000000000..8a4747588 --- /dev/null +++ b/flamecord/src/main/java/dev/_2lstudios/flamecord/firewall/FirewallManager.java @@ -0,0 +1,116 @@ +package dev._2lstudios.flamecord.firewall; + +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.util.Collection; +import java.util.HashSet; +import java.util.logging.Logger; + +import dev._2lstudios.flamecord.FlameCord; +import dev._2lstudios.flamecord.configuration.FlameCordConfiguration; +import lombok.Getter; + +public class FirewallManager { + private final Logger logger; + private final Collection whitelistedAddresses; + private final Collection firewalled; + private final int defaultSeconds; + @Getter + private int seconds; + + public FirewallManager(final Logger logger, final Collection whitelistedAddresses, + final int defaultSeconds) { + this.logger = logger; + this.whitelistedAddresses = whitelistedAddresses; + this.firewalled = new HashSet<>(); + this.defaultSeconds = defaultSeconds; + this.seconds = defaultSeconds; + } + + public boolean isWhitelisted(final SocketAddress address) { + final String addressString = address.toString(); + + for (final String whitelistedAddressString : whitelistedAddresses) { + if (addressString.endsWith(whitelistedAddressString)) { + return true; + } + } + + return false; + } + + public void addFirewalled(final SocketAddress address) { + if (FlameCord.getInstance().getFlameCordConfiguration().isFirewallEnabled() && !isWhitelisted(address)) { + final InetSocketAddress iNetSocketAddress = (InetSocketAddress) address; + final String hostString = iNetSocketAddress.getHostString(); + + if (!this.firewalled.contains(hostString)) { + this.firewalled.add(hostString); + logAdded(address); + } + } + } + + public void logAdded(final SocketAddress address) { + final FlameCord flameCord = FlameCord.getInstance(); + final FlameCordConfiguration flameCordConfiguration = flameCord.getFlameCordConfiguration(); + + if (flameCordConfiguration.isFirewallNotify()) { + final InetSocketAddress iNetSocketAddress = (InetSocketAddress) address; + final String hostString = iNetSocketAddress.getHostString(); + + this.logger.info(flameCord.getMessagesConfiguration().getTranslation("firewall_added", hostString)); + } + } + + public void logBlocked(final SocketAddress address) { + final FlameCord flameCord = FlameCord.getInstance(); + final FlameCordConfiguration flameCordConfiguration = flameCord.getFlameCordConfiguration(); + + if (flameCordConfiguration.isFirewallNotify()) { + final InetSocketAddress iNetSocketAddress = (InetSocketAddress) address; + final String hostString = iNetSocketAddress.getHostString(); + + this.logger.info(flameCord.getMessagesConfiguration().getTranslation("firewall_blocked", hostString)); + } + } + + public Collection getFirewalled() { + return this.firewalled; + } + + public boolean isFirewalled(final SocketAddress address) { + final InetSocketAddress iNetSocketAddress = (InetSocketAddress) address; + + return this.firewalled.contains(iNetSocketAddress.getHostString()); + } + + public boolean isFirewalled(final String name) { + final String nameLowerCase = name.toLowerCase(); + + for (final String string : FlameCord.getInstance().getFlameCordConfiguration().getFirewallNames()) { + if (nameLowerCase.contains(string)) { + return true; + } + } + + return false; + } + + public void tick() { + if (--seconds <= 0) { + final FlameCord flameCord = FlameCord.getInstance(); + final int size = this.firewalled.size(); + + if (size > 0) { + if (flameCord.getFlameCordConfiguration().isFirewallNotify()) { + this.logger.info(flameCord.getMessagesConfiguration().getTranslation("firewall_cleared", size)); + } + + this.firewalled.clear(); + } + + this.seconds = defaultSeconds; + } + } +} \ No newline at end of file diff --git a/proxy/src/main/java/dev/_2lstudios/flamecord/commands/FlameCordCommand.java b/proxy/src/main/java/dev/_2lstudios/flamecord/commands/FlameCordCommand.java index bf6f85386..fa0b59c27 100644 --- a/proxy/src/main/java/dev/_2lstudios/flamecord/commands/FlameCordCommand.java +++ b/proxy/src/main/java/dev/_2lstudios/flamecord/commands/FlameCordCommand.java @@ -5,6 +5,7 @@ import java.util.HashSet; import dev._2lstudios.flamecord.FlameCord; import dev._2lstudios.flamecord.configuration.MessagesConfiguration; +import dev._2lstudios.flamecord.firewall.FirewallManager; import net.md_5.bungee.BungeeCord; import net.md_5.bungee.api.CommandSender; import net.md_5.bungee.api.chat.TextComponent; @@ -30,6 +31,15 @@ private final BungeeCord bungeeCord; final String arg0 = args[0]; switch (arg0) { + case "firewall": { + final FirewallManager firewallManager = flameCord.getFirewallManager(); + final int amount = firewallManager.getFirewalled().size(), + seconds = firewallManager.getSeconds(); + + sender.sendMessage(TextComponent.fromLegacyText( + messagesConfiguration.getTranslation("firewall_info", amount, seconds))); + break; + } case "reload": { // FlameCord - Collect ips from servers final Collection whitelistedAddresses = new HashSet<>(); diff --git a/proxy/src/main/java/net/md_5/bungee/ServerConnector.java b/proxy/src/main/java/net/md_5/bungee/ServerConnector.java index 494375cd6..aedfece35 100644 --- a/proxy/src/main/java/net/md_5/bungee/ServerConnector.java +++ b/proxy/src/main/java/net/md_5/bungee/ServerConnector.java @@ -165,6 +165,9 @@ public class ServerConnector extends PacketHandler { if ( packet.packet == null ) { + // FlameCord - Firewall on unexpected packet + FlameCord.getInstance().getFirewallManager().addFirewalled(ch.getRemoteAddress()); + throw new QuietException( "Unexpected packet received during server connector process!\n" + BufUtil.dump(packet.buf, 16) ); } } diff --git a/proxy/src/main/java/net/md_5/bungee/connection/InitialHandler.java b/proxy/src/main/java/net/md_5/bungee/connection/InitialHandler.java index deee607dc..3720825af 100644 --- a/proxy/src/main/java/net/md_5/bungee/connection/InitialHandler.java +++ b/proxy/src/main/java/net/md_5/bungee/connection/InitialHandler.java @@ -154,6 +154,9 @@ public class InitialHandler extends PacketHandler implements PendingConnection { if ( packet.packet == null ) { + // FlameCord - Firewall on unexpected packet + FlameCord.getInstance().getFirewallManager().addFirewalled(ch.getRemoteAddress()); + throw new QuietException( "Unexpected packet received during server login process!\n" + BufUtil.dump(packet.buf, 16) ); } } @@ -396,6 +399,9 @@ public class InitialHandler extends PacketHandler implements PendingConnection } break; default: + // FlameCord - Firewall on unexpected packet + FlameCord.getInstance().getFirewallManager().addFirewalled(ch.getRemoteAddress()); + throw new QuietException( "Cannot request protocol " + handshake.getRequestedProtocol() ); } } diff --git a/proxy/src/main/java/net/md_5/bungee/connection/PingHandler.java b/proxy/src/main/java/net/md_5/bungee/connection/PingHandler.java index 423af854f..70917b0b0 100644 --- a/proxy/src/main/java/net/md_5/bungee/connection/PingHandler.java +++ b/proxy/src/main/java/net/md_5/bungee/connection/PingHandler.java @@ -2,6 +2,7 @@ package net.md_5.bungee.connection; import com.google.gson.Gson; +import dev._2lstudios.flamecord.FlameCord; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import lombok.RequiredArgsConstructor; import net.md_5.bungee.BungeeCord; @@ -59,6 +60,9 @@ public class PingHandler extends PacketHandler { if ( packet.packet == null ) { + // FlameCord - Firewall on unexpected packet + FlameCord.getInstance().getFirewallManager().addFirewalled(channel.getRemoteAddress()); + throw new QuietException( "Unexpected packet received during ping process! " + BufUtil.dump( packet.buf, 16 ) ); } } diff --git a/proxy/src/main/java/net/md_5/bungee/netty/HandlerBoss.java b/proxy/src/main/java/net/md_5/bungee/netty/HandlerBoss.java index 7f18b5646..5de0414ec 100644 --- a/proxy/src/main/java/net/md_5/bungee/netty/HandlerBoss.java +++ b/proxy/src/main/java/net/md_5/bungee/netty/HandlerBoss.java @@ -3,6 +3,7 @@ package net.md_5.bungee.netty; import com.google.common.base.Preconditions; import dev._2lstudios.flamecord.FlameCord; +import dev._2lstudios.flamecord.firewall.FirewallException; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.handler.codec.CorruptedFrameException; @@ -11,6 +12,7 @@ import io.netty.handler.codec.haproxy.HAProxyMessage; import io.netty.handler.timeout.ReadTimeoutException; import java.io.IOException; import java.net.InetSocketAddress; +import java.net.SocketAddress; import java.util.logging.Level; import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.connection.CancelSendSignal; @@ -140,6 +142,23 @@ public class HandlerBoss extends ChannelInboundHandlerAdapter { boolean logExceptions = !( handler instanceof PingHandler ); + // FlameCord - Don't log firewall exceptions + logExceptions = cause instanceof FirewallException ? false : logExceptions; + + // FlameCord - Firewall system + if (cause instanceof DecoderException || cause instanceof IllegalStateException || cause instanceof BadPacketException) { + final SocketAddress remoteAddress = ctx.channel().remoteAddress(); + + if (remoteAddress != null) { + FlameCord.getInstance().getFirewallManager().addFirewalled(remoteAddress); + } + } + + // FlameCord - Handle firewall exceptions + if (cause instanceof FirewallException) { + FlameCord.getInstance().getFirewallManager().logBlocked(ctx.channel().remoteAddress()); + } + if ( logExceptions ) { if ( cause instanceof ReadTimeoutException ) diff --git a/proxy/src/main/java/net/md_5/bungee/netty/PipelineUtils.java b/proxy/src/main/java/net/md_5/bungee/netty/PipelineUtils.java index 1d86aa63c..81987ca39 100644 --- a/proxy/src/main/java/net/md_5/bungee/netty/PipelineUtils.java +++ b/proxy/src/main/java/net/md_5/bungee/netty/PipelineUtils.java @@ -3,6 +3,7 @@ package net.md_5.bungee.netty; import com.google.common.base.Preconditions; import dev._2lstudios.flamecord.FlameCord; +import dev._2lstudios.flamecord.firewall.FirewallException; import io.github.waterfallmc.waterfall.event.ConnectionInitEvent; import io.netty.buffer.PooledByteBufAllocator; import io.netty.channel.Channel; @@ -63,6 +64,11 @@ public class PipelineUtils { SocketAddress remoteAddress = ( ch.remoteAddress() == null ) ? ch.parent().localAddress() : ch.remoteAddress(); + // FlameCord - Firewall system + if (remoteAddress != null && FlameCord.getInstance().getFirewallManager().isFirewalled(remoteAddress)) { + throw new FirewallException(remoteAddress); + } + if ( BungeeCord.getInstance().getConnectionThrottle() != null && BungeeCord.getInstance().getConnectionThrottle().throttle( remoteAddress ) ) { ch.close(); -- 2.31.1