From 160af8c9a43c4a028b766ebf26ef530b51fa5e57 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 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 81ded224..8bb61ac1 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 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/FirewallManager.java b/flamecord/src/main/java/dev/_2lstudios/flamecord/firewall/FirewallManager.java new file mode 100644 index 00000000..dfb5c6d3 --- /dev/null +++ b/flamecord/src/main/java/dev/_2lstudios/flamecord/firewall/FirewallManager.java @@ -0,0 +1,120 @@ +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 (address == null) { + return; + } + + 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/protocol/src/main/java/net/md_5/bungee/protocol/MinecraftDecoder.java b/protocol/src/main/java/net/md_5/bungee/protocol/MinecraftDecoder.java index c03e1b51..7f4b5b45 100644 --- a/protocol/src/main/java/net/md_5/bungee/protocol/MinecraftDecoder.java +++ b/protocol/src/main/java/net/md_5/bungee/protocol/MinecraftDecoder.java @@ -46,8 +46,14 @@ public class MinecraftDecoder extends MessageToMessageDecoder final int capacity = in.capacity(); if (readableBytes > 2097152) { + // FlameCord - Firewall system + FlameCord.getInstance().getFirewallManager().addFirewalled(ctx.channel().remoteAddress()); + throw new FastDecoderException("Error decoding packet with too many readableBytes: " + readableBytes); } else if (capacity > 2097152) { + // FlameCord - Firewall system + FlameCord.getInstance().getFirewallManager().addFirewalled(ctx.channel().remoteAddress()); + throw new FastDecoderException("Error decoding packet with too big capacity: " + capacity); } } @@ -108,6 +114,9 @@ public class MinecraftDecoder extends MessageToMessageDecoder } else { packetTypeStr = "unknown"; } + + // FlameCord - Firewall system + FlameCord.getInstance().getFirewallManager().addFirewalled(ctx.channel().remoteAddress()); throw new FastDecoderException("Error decoding packet " + packetTypeStr + " with contents:\n" + ByteBufUtil.prettyHexDump(slice), e); // Waterfall } finally { 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/ServerConnector.java b/proxy/src/main/java/net/md_5/bungee/ServerConnector.java index ccab6800..d57a0516 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 a1ec1bff..3c8bd33b 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 @@ -152,6 +152,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) ); } } @@ -379,6 +382,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 264c22e8..2101cbc4 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; @@ -58,6 +59,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 4c53e02c..376daee9 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 @@ -11,6 +11,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; 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 a840bc70..4e23c996 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 @@ -63,6 +63,13 @@ public class PipelineUtils { SocketAddress remoteAddress = ( ch.remoteAddress() == null ) ? ch.parent().localAddress() : ch.remoteAddress(); + // FlameCord - Firewall system + if ( FlameCord.getInstance().getFirewallManager().isFirewalled( remoteAddress ) ) { + FlameCord.getInstance().getFirewallManager().logBlocked( remoteAddress ); + ch.close(); + return; + } + if ( BungeeCord.getInstance().getConnectionThrottle() != null && BungeeCord.getInstance().getConnectionThrottle().throttle( remoteAddress ) ) { ch.close(); diff --git a/query/src/main/java/net/md_5/bungee/query/QueryHandler.java b/query/src/main/java/net/md_5/bungee/query/QueryHandler.java index b3bdfd05..49d53f17 100644 --- a/query/src/main/java/net/md_5/bungee/query/QueryHandler.java +++ b/query/src/main/java/net/md_5/bungee/query/QueryHandler.java @@ -2,6 +2,8 @@ package net.md_5.bungee.query; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; + +import dev._2lstudios.flamecord.FlameCord; import io.github.waterfallmc.waterfall.QueryResult; import io.github.waterfallmc.waterfall.event.ProxyQueryEvent; import io.netty.buffer.ByteBuf; @@ -70,6 +72,9 @@ public class QueryHandler extends SimpleChannelInboundHandler ByteBuf in = msg.content(); if ( in.readUnsignedByte() != 0xFE || in.readUnsignedByte() != 0xFD ) { + // FlameCord - Firewall system + FlameCord.getInstance().getFirewallManager().addFirewalled(ctx.channel().remoteAddress()); + bungee.getLogger().log( Level.WARNING, "Query - Incorrect magic!: {0}", msg.sender() ); // FlameCord - Close on incorrect magic ctx.close(); @@ -164,6 +169,9 @@ public class QueryHandler extends SimpleChannelInboundHandler out.writeByte( 0x00 ); // Null } else { + // FlameCord - Firewall system + FlameCord.getInstance().getFirewallManager().addFirewalled(ctx.channel().remoteAddress()); + // Error! throw new IllegalStateException( "Invalid data request packet" ); } -- 2.31.1.windows.1