diff --git a/LaunchServer/MANIFEST.MF b/LaunchServer/MANIFEST.MF index f652062..1981922 100644 --- a/LaunchServer/MANIFEST.MF +++ b/LaunchServer/MANIFEST.MF @@ -4,7 +4,7 @@ ibraries/hikaricp/slf4j-api.jar libraries/hikaricp/slf4j-simple.jar l ibraries/launch4j/launch4j.jar ibraries/postgresql.jar libraries/mysq l-8.jar libraries/sqlite.jar libraries/mariadb.jar libraries/jbcrypt. - jar + jar libraries/gson.jar Main-Class: launchserver.LaunchServer Name: launchserver/ diff --git a/LaunchServer/resources/launchserver/defaults/config.cfg b/LaunchServer/resources/launchserver/defaults/config.cfg index d7f5dfa..5a3defe 100644 --- a/LaunchServer/resources/launchserver/defaults/config.cfg +++ b/LaunchServer/resources/launchserver/defaults/config.cfg @@ -14,13 +14,18 @@ # Лимит на авторизацию / защита от брутфорса authLimit: false; authLimitConfig: { + # Основные настройки authRateLimit: 5; authRateLimitMilis: 8000; + useAllowIp: false; + useBlockIp: false; + + # Сообщения клиентам authRejectString: "Превышен лимит авторизаций, подождите некоторое время!"; authBannedString: "Ваш IP заблокирован!"; + + # Дополнительные настройки blockOnConnect: false; - allowIp: []; - blockIp: []; }; # Управление системой хранения и обработки UUID пользователей diff --git a/LaunchServer/source/LaunchServer.java b/LaunchServer/source/LaunchServer.java index e8480f9..e8525a7 100644 --- a/LaunchServer/source/LaunchServer.java +++ b/LaunchServer/source/LaunchServer.java @@ -19,6 +19,7 @@ import launchserver.auth.handler.CachedAuthHandler; import launchserver.auth.handler.FileAuthHandler; import launchserver.auth.limiter.AuthLimiterConfig; +import launchserver.auth.limiter.AuthLimiterIPConfig; import launchserver.auth.provider.AuthProvider; import launchserver.auth.provider.DigestAuthProvider; import launchserver.binary.*; @@ -60,6 +61,8 @@ @LauncherAPI public final Path configFile; @LauncherAPI + public final Path ipConfigFile; + @LauncherAPI public final Path publicKeyFile; @LauncherAPI public final Path privateKeyFile; @@ -108,6 +111,7 @@ // Setup config locations this.dir = dir; configFile = dir.resolve("LaunchServer.cfg"); + ipConfigFile = dir.resolve("ListIpConnection.json"); publicKeyFile = dir.resolve("public.key"); privateKeyFile = dir.resolve("private.key"); updatesDir = dir.resolve("updates"); @@ -175,6 +179,17 @@ } config.verify(); + // Read IpList config + LogHelper.info("Reading IP Connection List file"); + try + { + AuthLimiterIPConfig.load(ipConfigFile.toFile()); + } + catch (Exception error) + { + if (LogHelper.isDebugEnabled()) LogHelper.error(error); + } + // anti-brutforce limiter = new AuthLimiter(this); diff --git a/LaunchServer/source/auth/limiter/AuthLimiterConfig.java b/LaunchServer/source/auth/limiter/AuthLimiterConfig.java index 0b82822..b9b9af4 100644 --- a/LaunchServer/source/auth/limiter/AuthLimiterConfig.java +++ b/LaunchServer/source/auth/limiter/AuthLimiterConfig.java @@ -21,9 +21,9 @@ @LauncherAPI public boolean blockOnConnect; @LauncherAPI - public ListConfigEntry allowIp; + public boolean useAllowIp; @LauncherAPI - public ListConfigEntry blockIp; + public boolean useBlockIp; @LauncherAPI public AuthLimiterConfig(BlockConfigEntry block) @@ -38,7 +38,7 @@ authBannedString = block.hasEntry("authBannedString") ? block.getEntryValue("authBannedString", StringConfigEntry.class) : "Ваш IP заблокирован!"; blockOnConnect = block.getEntryValue("blockOnConnect", BooleanConfigEntry.class); - allowIp = block.getEntry("allowIp", ListConfigEntry.class); - blockIp = block.getEntry("blockIp", ListConfigEntry.class); + useAllowIp = block.getEntryValue("useAllowIp", BooleanConfigEntry.class); + useBlockIp = block.getEntryValue("useBlockIp", BooleanConfigEntry.class); } } diff --git a/LaunchServer/source/auth/limiter/AuthLimiterIPConfig.java b/LaunchServer/source/auth/limiter/AuthLimiterIPConfig.java new file mode 100644 index 0000000..9cd6298 --- /dev/null +++ b/LaunchServer/source/auth/limiter/AuthLimiterIPConfig.java @@ -0,0 +1,88 @@ +package launchserver.auth.limiter; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.annotations.Expose; +import com.google.gson.stream.JsonReader; +import launcher.helper.LogHelper; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.FileWriter; +import java.util.ArrayList; +import java.util.List; + +public class AuthLimiterIPConfig +{ + public static File ipConfigFile; + public static Gson gson = new GsonBuilder().setPrettyPrinting().excludeFieldsWithoutExposeAnnotation().create(); + public static AuthLimiterIPConfig Instance; + + @Expose + List allowIp = new ArrayList<>(); + @Expose + List blockIp = new ArrayList<>(); + + public static void load(File file) throws Exception { + ipConfigFile = file; + if (file.exists()) { + LogHelper.subDebug("IP List file found! Loading..."); + if (file.length() > 2) { + try + { + AuthLimiterIPConfig authLimiterIPConfig = gson.fromJson(new JsonReader(new FileReader(file)), AuthLimiterIPConfig.class); + Instance = authLimiterIPConfig; + return; + } + catch (FileNotFoundException error) + { + LogHelper.subWarning("Ip List not reading!"); + if (LogHelper.isDebugEnabled()) LogHelper.error(error); + } + } + } + + LogHelper.subWarning("IP List file not found! Creating file..."); + AuthLimiterIPConfig IpConfig = new AuthLimiterIPConfig(); + Instance = IpConfig; + IpConfig.saveIPConfig(); + } + + public void saveIPConfig() throws Exception + { + if (!ipConfigFile.exists()) ipConfigFile.createNewFile(); + + FileWriter fw = new FileWriter(ipConfigFile, false); + fw.write(gson.toJson(this)); + fw.close(); + } + + public List getAllowIp() { + return allowIp; + } + + public AuthLimiterIPConfig addAllowIp(String allowIp) { + this.allowIp.add(allowIp); + return this; + } + + public AuthLimiterIPConfig delAllowIp(String allowIp) { + this.allowIp.removeIf(e -> e.equals(allowIp)); + return this; + } + + public List getBlockIp() { + return blockIp; + } + + public AuthLimiterIPConfig addBlockIp(String blockIp) { + this.blockIp.add(blockIp); + return this; + } + + public AuthLimiterIPConfig delBlockIp(String blockIp) { + this.blockIp.removeIf(e -> e.equals(blockIp)); + return this; + } +} \ No newline at end of file diff --git a/LaunchServer/source/command/handler/CommandHandler.java b/LaunchServer/source/command/handler/CommandHandler.java index b29e9d0..7f49565 100644 --- a/LaunchServer/source/command/handler/CommandHandler.java +++ b/LaunchServer/source/command/handler/CommandHandler.java @@ -9,6 +9,8 @@ import launchserver.command.auth.*; import launchserver.command.basic.*; import launchserver.command.hash.*; +import launchserver.command.ip.IPAllowCommand; +import launchserver.command.ip.IPBlockCommand; import launchserver.command.legacy.DumpBinaryAuthHandler; import java.io.IOException; @@ -41,7 +43,12 @@ registerCommand("syncBinaries", new SyncBinariesCommand(server)); registerCommand("syncUpdates", new SyncUpdatesCommand(server)); registerCommand("syncProfiles", new SyncProfilesCommand(server)); - // Custom + + // Register IP commands + registerCommand("allowIp", new IPAllowCommand(server)); + registerCommand("blockIp", new IPBlockCommand(server)); + + // Register custom commands registerCommand("syncAll", new SyncAllCommand(server)); // Register auth commands diff --git a/LaunchServer/source/command/ip/IPAllowCommand.java b/LaunchServer/source/command/ip/IPAllowCommand.java new file mode 100644 index 0000000..ea3fc4d --- /dev/null +++ b/LaunchServer/source/command/ip/IPAllowCommand.java @@ -0,0 +1,70 @@ +package launchserver.command.ip; + +import launcher.helper.LogHelper; +import launchserver.LaunchServer; +import launchserver.auth.limiter.AuthLimiterIPConfig; +import launchserver.command.Command; +import sun.net.util.IPAddressUtil; + +import java.util.Locale; + +public class IPAllowCommand extends Command +{ + public IPAllowCommand(LaunchServer server) + { + super(server); + } + + @Override + public String getArgsDescription() + { + return " "; + } + + @Override + public String getUsageDescription() + { + return "Add/Remove IP to Allow List"; + } + + @Override + public void invoke(String... args) throws Throwable + { + verifyArgs(args, 2); + String type = args[0].toLowerCase(Locale.ROOT); + String getIP = args[1]; + + if (type.isEmpty()) + { + LogHelper.error("Type cannot be empty!"); + } + + if (getIP.isEmpty()) + { + LogHelper.error("IP address cannot be empty!"); + return; + } + + if (!IPAddressUtil.isIPv4LiteralAddress(getIP) || !IPAddressUtil.isIPv6LiteralAddress(getIP)) + { + LogHelper.error("This is not an IP address!"); + return; + } + + if (type.equals("add")) + { + AuthLimiterIPConfig.Instance.addAllowIp(getIP).saveIPConfig(); + LogHelper.info("IP address add to Allow List!"); + return; + } + + if (type.equals("del")) + { + AuthLimiterIPConfig.Instance.delAllowIp(getIP).saveIPConfig(); + LogHelper.info("IP address remove to Allow List!"); + return; + } + + LogHelper.error("This is type is unknown!"); + } +} diff --git a/LaunchServer/source/command/ip/IPBlockCommand.java b/LaunchServer/source/command/ip/IPBlockCommand.java new file mode 100644 index 0000000..e728508 --- /dev/null +++ b/LaunchServer/source/command/ip/IPBlockCommand.java @@ -0,0 +1,70 @@ +package launchserver.command.ip; + +import launcher.helper.LogHelper; +import launchserver.LaunchServer; +import launchserver.auth.limiter.AuthLimiterIPConfig; +import launchserver.command.Command; +import sun.net.util.IPAddressUtil; + +import java.util.Locale; + +public class IPBlockCommand extends Command +{ + public IPBlockCommand(LaunchServer server) + { + super(server); + } + + @Override + public String getArgsDescription() + { + return " "; + } + + @Override + public String getUsageDescription() + { + return "Add/Remove IP to Block List"; + } + + @Override + public void invoke(String... args) throws Throwable + { + verifyArgs(args, 2); + String type = args[0].toLowerCase(Locale.ROOT); + String getIP = args[1]; + + if (type.isEmpty()) + { + LogHelper.error("Type cannot be empty!"); + } + + if (getIP.isEmpty()) + { + LogHelper.error("IP address cannot be empty!"); + return; + } + + if (!IPAddressUtil.isIPv4LiteralAddress(getIP) || !IPAddressUtil.isIPv6LiteralAddress(getIP)) + { + LogHelper.error("This is not an IP address!"); + return; + } + + if (type.equals("add")) + { + AuthLimiterIPConfig.Instance.addBlockIp(getIP).saveIPConfig(); + LogHelper.info("IP address add to Block List!"); + return; + } + + if (type.equals("del")) + { + AuthLimiterIPConfig.Instance.delBlockIp(getIP).saveIPConfig(); + LogHelper.info("IP address remove to Block List!"); + return; + } + + LogHelper.error("This is type is unknown!"); + } +} diff --git a/LaunchServer/source/response/ResponseThread.java b/LaunchServer/source/response/ResponseThread.java index edd0349..a728994 100644 --- a/LaunchServer/source/response/ResponseThread.java +++ b/LaunchServer/source/response/ResponseThread.java @@ -11,6 +11,7 @@ import launcher.serialize.HOutput; import launcher.serialize.config.entry.StringConfigEntry; import launchserver.LaunchServer; +import launchserver.auth.limiter.AuthLimiterIPConfig; import launchserver.response.auth.AuthResponse; import launchserver.response.auth.CheckServerResponse; import launchserver.response.auth.JoinServerResponse; @@ -45,9 +46,9 @@ @Override public void run() { - if (server.config.authLimitConfig.blockIp.stream(StringConfigEntry.class).anyMatch(s -> s.equals(ip)) && server.config.authLimitConfig.blockOnConnect) + if (AuthLimiterIPConfig.Instance.getBlockIp().stream().anyMatch(s -> s.equals(ip)) && !server.config.authLimitConfig.blockOnConnect && server.config.authLimit && server.config.authLimitConfig.useBlockIp) { - if (!server.serverSocketHandler.logConnections) LogHelper.debug("Blocked connection from %s", ip); + if (!server.serverSocketHandler.logConnections) LogHelper.debug("Blocked connection from %s [Found in Block List]", ip); return; } else diff --git a/LaunchServer/source/response/auth/AuthResponse.java b/LaunchServer/source/response/auth/AuthResponse.java index ff113bd..a453e8f 100644 --- a/LaunchServer/source/response/auth/AuthResponse.java +++ b/LaunchServer/source/response/auth/AuthResponse.java @@ -9,6 +9,7 @@ import launcher.serialize.config.entry.StringConfigEntry; import launchserver.LaunchServer; import launchserver.auth.AuthException; +import launchserver.auth.limiter.AuthLimiterIPConfig; import launchserver.auth.provider.AuthProvider; import launchserver.auth.provider.AuthProviderResult; import launchserver.response.Response; @@ -60,13 +61,13 @@ AuthProviderResult result; try { - if (server.config.authLimitConfig.blockIp.stream(StringConfigEntry.class).anyMatch(s -> s.equals(ip)) && !server.config.authLimitConfig.blockOnConnect) + if (AuthLimiterIPConfig.Instance.getBlockIp().stream().anyMatch(s -> s.equals(ip)) && !server.config.authLimitConfig.blockOnConnect && server.config.authLimit && server.config.authLimitConfig.useBlockIp) { AuthProvider.authError(server.config.authLimitConfig.authBannedString); return; } - if (server.config.authLimitConfig.allowIp.stream(StringConfigEntry.class).noneMatch(s -> s.equals(ip))) + if (AuthLimiterIPConfig.Instance.getAllowIp().stream().noneMatch(s -> s.equals(ip)) && server.config.authLimit && server.config.authLimitConfig.useAllowIp) { if (server.limiter.isLimit(ip)) { diff --git a/buildnumber b/buildnumber index 672e1b2..60e7efd 100644 --- a/buildnumber +++ b/buildnumber @@ -1 +1 @@ -564, 19.07.2021 \ No newline at end of file +566, 20.07.2021 \ No newline at end of file