From e6ce50df78087e26000d0d99f2f5a51b7334b93c Mon Sep 17 00:00:00 2001 From: linsaftw Date: Fri, 30 Apr 2021 19:23:36 -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 8957c79a..fd889644 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 650cb302..b7268e1d 100644 --- a/flamecord/src/main/java/dev/_2lstudios/flamecord/configuration/FlameCordConfiguration.java +++ b/flamecord/src/main/java/dev/_2lstudios/flamecord/configuration/FlameCordConfiguration.java @@ -13,7 +13,12 @@ import net.md_5.bungee.config.ConfigurationProvider; public class FlameCordConfiguration { @Getter - private boolean loggerInitialhandler = false, loggerExceptions = false, loggerDump = false; + private boolean loggerInitialhandler = false, loggerExceptions = false, loggerDump = false, firewallNotify = true, + firewallEnabled = true; + @Getter + private int firewallSeconds = 60; + @Getter + private Collection firewallNames = new HashSet<>(Arrays.asList(new String[] { "mcspam" })); public FlameCordConfiguration(final ConfigurationProvider configurationProvider) { try { @@ -32,6 +37,10 @@ public class FlameCordConfiguration { configuration); this.loggerExceptions = setIfUnexistant("logger.exceptions", this.loggerExceptions, configuration); this.loggerDump = setIfUnexistant("logger.dump", this.loggerDump, configuration); + 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 ebfaa761..c88077ad 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 00000000..6a661898 --- /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 00000000..8a474758 --- /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 bf6f8538..fa0b59c2 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/netty/HandlerBoss.java b/proxy/src/main/java/net/md_5/bungee/netty/HandlerBoss.java index d3a89e79..60c9ddcd 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; @@ -143,7 +145,21 @@ public class HandlerBoss extends ChannelInboundHandlerAdapter // FlameCord - Use flamecord final FlameCord flameCord = FlameCord.getInstance(); // FlameCord - Log exceptions based on FlameCord - boolean logExceptions = flameCord.getFlameCordConfiguration().isLoggerExceptions(); + boolean logExceptions = flameCord.getFlameCordConfiguration().isLoggerExceptions() && !(cause instanceof FirewallException); + + // FlameCord - Firewall system + if (cause instanceof DecoderException || cause instanceof IllegalStateException || cause instanceof BadPacketException) { + final SocketAddress remoteAddress = ctx.channel().remoteAddress(); + + if (remoteAddress != null) { + flameCord.getFirewallManager().addFirewalled(remoteAddress); + } + } + + // FlameCord - Handle firewall exceptions + if (cause instanceof FirewallException) { + flameCord.getFirewallManager().logBlocked(ctx.channel().remoteAddress()); + } if ( logExceptions ) { 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 1680ce96..5ddc84a3 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