public void TestWhitelistDns() { IPBanConfig config = IPBanConfig.LoadFromXml("<?xml version='1.0'?><configuration>" + "<appSettings><add key='Whitelist' value='test.com' /></appSettings></configuration>", this); Assert.IsTrue(config.IsWhitelisted("99.88.77.66")); Assert.IsFalse(config.IsBlackListed("99.88.77.66")); }
public void TestUserNameWhitelistBan() { using IPBanConfig.TempConfigChanger configChanger = new IPBanConfig.TempConfigChanger(service, xml => { return(IPBanConfig.ChangeConfigAppSetting(xml, "UserNameWhitelist", "OnlyMe")); }, out string newConfig); // TODO: ensure non OnlyMe users are banned immediately // TODO: ensure OnlyMe user gets 20 failed logins before ban }
public void TestListComments() { IPBanConfig config = IPBanConfig.LoadFromXml("<?xml version='1.0'?><configuration>" + "<appSettings><add key='Whitelist' value='99.99.99.99?TestIP?2020-05-25," + "88.88.88.88?TestIP2?2020-05-24' /></appSettings></configuration>", DefaultDnsLookup.Instance); Assert.AreEqual(string.Join(",", config.Whitelist.OrderBy(i => i)), "88.88.88.88,99.99.99.99"); Assert.IsTrue(config.IsWhitelisted("99.99.99.99")); Assert.IsTrue(config.IsWhitelisted("88.88.88.88")); Assert.IsFalse(config.IsWhitelisted("77.77.77.77")); }
private void AssertLogFilesToParse(IPBanConfig cfg) { const int maxFileSize = 16777216; const int pingInterval = 10000; // path and mask, fail expression, success expression, platform regex, recursive, source object[] logFileData = new object[] { "/var/log/auth*.log\n/var/log/secure*", @"failed\s+password\s+for\s+(invalid\s+user\s+)?(?<username>.+?\s+)from\s+(?<ipaddress>.+?)\s+port\s+[0-9]+\s+ssh|did\s+not\s+receive\s+identification\s+string\s+from\s+(?<ipaddress>[^\s]+)|connection\s+closed\s+by\s+(invalid\s+user\s+)?(?<username>.+?\s+)?(?<ipaddress>.+?)\s+port\s+[0-9]+\s+\[preauth\]\s*(\(no\s+attempt\s+to\s+login\s+after\s+timeout\))?|disconnected\s+from\s+(invalid\s+user\s+)?(?<username>.+?)\s+(?<ipaddress>.+?)\s+port\s+[0-9]+\s+\[preauth\]|disconnected\s+from\s+(?<ipaddress>.+?)\s+port\s+[0-9]+\s+\[preauth\]|disconnected\s+from\s+authenticating\s+user\s+(?<username>.+?)\s+(?<ipaddress>.+?)\s+port\s+[0-9]+\s+\[preauth\]", @"Accepted\s+password\s+for\s+(?<username>.+?)\s+from\s+(?<ipaddress>.+?)\s+port\s+[0-9]+\s+ssh", "Linux", false, "SSH", "/var/log/ipbancustom*.log", @"(?<timestamp>\d\d\d\d-\d\d-\d\d\s\d\d:\d\d:\d\d\.?\d*Z?,\s)?ipban\sfailed\slogin,\sip\saddress:\s(?<ipaddress>.+?),\ssource:\s(?<source>.+?),\suser:\s?(?<username>[^\s,]+)?", @"(?<timestamp>\d\d\d\d-\d\d-\d\d\s\d\d:\d\d:\d\d\.?\d*Z?,\s)?ipban\ssuccess\slogin,\sip\saddress:\s(?<ipaddress>.+?),\ssource:\s(?<source>.+?),\suser:\s?(?<username>[^\s,]+)?", "Linux", false, "IPBanCustom", "C:/Program Files/Microsoft/Exchange Server/*.log", @".*?,.*?,.*?,.*?,(?<ipaddress>.+?),(?<username>.+?),.*?AuthFailed", @"", "Windows", true, "MSExchange", "C:/Program Files/Smarter Tools/Smarter Mail/*.log\nC:/ Program Files(x86) / Smarter Tools / Smarter Mail/*.log\nC:/SmarterMail/logs/*.log\nC:/Smarter Mail/logs/*.log", @"\[(?<ipaddress>[^\]]+)\](\[.*?\]\s+)?(The domain given in the EHLO command violates an EHLO SMTP|IP blocked by brute force abuse detection rule)", @"", "Windows", true, "SmarterMail", "C:/Program Files/Tomcat/logs/*access_log*.txt", @"^(?<ipaddress>.*?)\s.*?((php|md5sum|cgi-bin|joomla).*?\s404\s[0-9]+$|\s400\s-)$", @"", "Windows", true, "Apache", "C:/IPBanCustomLogs/*.log", @"ipban\sfailed\slogin,\sip\saddress:\s(?<ipaddress>.+?),\ssource:\s(?<source>.+?),\suser:\s?(?<username>[^\s,]+)?", @"ipban\ssuccess\slogin,\sip\saddress:\s(?<ipaddress>.+?),\ssource:\s(?<source>.+?),\suser:\s?(?<username>[^\s,]+)?", "Windows", true, "IPBanCustom" }; Assert.AreEqual(logFileData.Length / 6, cfg.LogFilesToParse.Count); for (int i = 0; i < logFileData.Length; i += 6) { AssertLogFileToParse(cfg.LogFilesToParse[i / 6], (string)logFileData[i + 1], maxFileSize, (string)logFileData[i], pingInterval, (string)logFileData[i + 3], (bool)logFileData[i + 4], (string)logFileData[i + 5], (string)logFileData[i + 2]); } }
private void AssertLogFileToParse(IPBanLogFileToParse file, string failedLoginRegex, int maxFileSize, string pathAndMask, int pingInterval, string platformRegex, bool recursive, string source, string successfulLoginRegex) { Assert.AreEqual(IPBanConfig.ParseRegex(failedLoginRegex)?.ToString(), IPBanConfig.ParseRegex(file.FailedLoginRegex)?.ToString()); Assert.AreEqual(maxFileSize, file.MaxFileSize); Assert.AreEqual(Regex.Replace(pathAndMask.Trim().Replace('\n', '|'), "\\s+", string.Empty), Regex.Replace(file.PathAndMask.Trim().Replace('\n', '|'), "\\s+", string.Empty)); Assert.AreEqual(pingInterval, file.PingInterval); Assert.AreEqual(IPBanConfig.ParseRegex(platformRegex)?.ToString(), IPBanConfig.ParseRegex(file.PlatformRegex)?.ToString()); Assert.AreEqual(recursive, file.Recursive); Assert.AreEqual(source, file.Source); Assert.AreEqual(IPBanConfig.ParseRegex(successfulLoginRegex)?.ToString(), IPBanConfig.ParseRegex(file.SuccessfulLoginRegex)?.ToString()); }
private void AssertLogFileToParse(IPBanLogFileToParse file, string failedLoginRegex, string failedLoginRegexTimestampFormat, int maxFileSize, string pathAndMask, int pingInterval, string platformRegex, string source, string successfulLoginRegex, string successfulLoginRegexTimestampFormat, LogLevel failedLogLevel = LogLevel.Warning, LogLevel successLogLevel = LogLevel.Warning) { Assert.AreEqual(IPBanConfig.ParseRegex(failedLoginRegex)?.ToString(), IPBanConfig.ParseRegex(file.FailedLoginRegex)?.ToString()); Assert.AreEqual(failedLoginRegexTimestampFormat, file.FailedLoginRegexTimestampFormat); Assert.AreEqual(maxFileSize, file.MaxFileSize); Assert.AreEqual(Regex.Replace(pathAndMask.Trim().Replace('\n', '|'), "\\s+", string.Empty), Regex.Replace(file.PathAndMask.Trim().Replace('\n', '|'), "\\s+", string.Empty)); Assert.AreEqual(pingInterval, file.PingInterval); Assert.AreEqual(IPBanConfig.ParseRegex(platformRegex)?.ToString(), IPBanConfig.ParseRegex(file.PlatformRegex)?.ToString()); Assert.AreEqual(source, file.Source); Assert.AreEqual(IPBanConfig.ParseRegex(successfulLoginRegex)?.ToString(), IPBanConfig.ParseRegex(file.SuccessfulLoginRegex)?.ToString()); Assert.AreEqual(successfulLoginRegexTimestampFormat, file.SuccessfulLoginRegexTimestampFormat); Assert.AreEqual(failedLogLevel, file.FailedLoginLogLevel); Assert.AreEqual(successLogLevel, file.SuccessfulLoginLogLevel); }
public async Task TestDefaultConfig() { // ensure config file is read properly IPBanService service = IPBanService.CreateAndStartIPBanTestService <IPBanService>(); try { IPBanConfig cfg = service.Config; Assert.IsNotNull(cfg); Assert.AreEqual(TimeSpan.FromDays(1.0), cfg.BanTimes.First()); Assert.AreEqual(1, cfg.BanTimes.Length); Assert.IsEmpty(cfg.BlacklistFilter.IPAddressRanges); Assert.IsTrue(string.IsNullOrEmpty(cfg.BlacklistFilter.Regex?.ToString())); Assert.IsFalse(cfg.ClearBannedIPAddressesOnRestart); Assert.IsFalse(cfg.ClearFailedLoginsOnSuccessfulLogin); Assert.IsFalse(cfg.ProcessInternalIPAddresses); Assert.AreEqual(TimeSpan.FromSeconds(15.0), cfg.CycleTime); Assert.AreEqual(TimeSpan.FromDays(1.0), cfg.ExpireTime); Assert.AreEqual("https://checkip.amazonaws.com/", cfg.ExternalIPAddressUrl); Assert.AreEqual(5, cfg.FailedLoginAttemptsBeforeBan); Assert.AreEqual(20, cfg.FailedLoginAttemptsBeforeBanUserNameWhitelist); Assert.AreEqual("IPBan_", cfg.FirewallRulePrefix); Assert.AreEqual(TimeSpan.FromSeconds(1.0), cfg.MinimumTimeBetweenFailedLoginAttempts); Assert.IsEmpty(cfg.ProcessToRunOnBan); Assert.IsEmpty(cfg.ProcessToRunOnUnban); Assert.IsFalse(cfg.ResetFailedLoginCountForUnbannedIPAddresses); Assert.IsTrue(cfg.UseDefaultBannedIPAddressHandler); Assert.IsEmpty(cfg.UserNameWhitelist); Assert.IsEmpty(cfg.UserNameWhitelistRegex); Assert.IsEmpty(cfg.WhitelistFilter.IPAddressRanges); Assert.IsTrue(string.IsNullOrEmpty(cfg.WhitelistFilter.Regex?.ToString())); Assert.AreEqual(0, cfg.ExtraRules.Count); Assert.AreEqual(cfg.FirewallUriRules.Trim(), "EmergingThreats,01:00:00:00,https://rules.emergingthreats.net/fwrules/emerging-Block-IPs.txt"); AssertLogFilesToParse(cfg); AssertEventViewer(cfg); string xml = await service.ConfigReaderWriter.ReadConfigAsync(); IPBanConfig prod = IPBanConfig.LoadFromXml(xml); Assert.IsTrue(prod.UseDefaultBannedIPAddressHandler); } finally { IPBanService.DisposeIPBanTestService(service); } }
public async Task TestDefaultConfig() { // ensure config file is read properly IPBanService service = IPBanService.CreateAndStartIPBanTestService <IPBanService>(); try { IPBanConfig cfg = service.Config; Assert.IsNotNull(cfg); Assert.AreEqual(TimeSpan.FromDays(1.0), cfg.BanTimes.First()); Assert.AreEqual(1, cfg.BanTimes.Length); Assert.IsEmpty(cfg.BlackList); Assert.IsEmpty(cfg.BlackListRegex); Assert.IsFalse(cfg.ClearBannedIPAddressesOnRestart); Assert.AreEqual(TimeSpan.FromSeconds(15.0), cfg.CycleTime); Assert.AreEqual(TimeSpan.FromDays(1.0), cfg.ExpireTime); Assert.AreEqual("https://checkip.amazonaws.com/", cfg.ExternalIPAddressUrl); Assert.AreEqual(5, cfg.FailedLoginAttemptsBeforeBan); Assert.AreEqual(20, cfg.FailedLoginAttemptsBeforeBanUserNameWhitelist); Assert.AreEqual(1, cfg.FirewallOSAndType.Count); Assert.AreEqual("*:Default", cfg.FirewallOSAndType.Keys.First() + ":" + cfg.FirewallOSAndType.Values.First()); Assert.AreEqual("IPBan_", cfg.FirewallRulePrefix); Assert.AreEqual(TimeSpan.FromSeconds(1.0), cfg.MinimumTimeBetweenFailedLoginAttempts); Assert.IsEmpty(cfg.ProcessToRunOnBan); Assert.IsFalse(cfg.ResetFailedLoginCountForUnbannedIPAddresses); Assert.IsTrue(cfg.UseDefaultBannedIPAddressHandler); Assert.IsEmpty(cfg.UserNameWhitelist); Assert.IsEmpty(cfg.UserNameWhitelistRegex); Assert.IsEmpty(cfg.WhiteList); Assert.IsEmpty(cfg.WhiteListRegex); Assert.AreEqual(0, cfg.ExtraRules.Count); AssertLogFilesToParse(cfg); AssertEventViewer(cfg); string xml = await service.ReadConfigAsync(); IPBanConfig prod = IPBanConfig.LoadFromXml(xml, null); Assert.IsTrue(prod.UseDefaultBannedIPAddressHandler); } finally { IPBanService.DisposeIPBanTestService(service); } }
public async Task TestUserNameWhitelistRegexBan() { using IPBanConfig.TempConfigChanger configChanger = new IPBanConfig.TempConfigChanger(service, xml => { return(IPBanConfig.ChangeConfigAppSetting(xml, "UserNameWhitelistRegex", "ftp_[0-9]+")); }, out string newConfig); service.AddIPAddressLogEvents(new IPAddressLogEvent[] { // a single failed login with a non-blacklisted user name should not get banned new IPAddressLogEvent("99.99.99.99", "ftp_1", "RDP", 1, IPAddressEventType.FailedLogin), // a single failed login with a failed user name whitelist regex should get banned new IPAddressLogEvent("99.99.99.90", "NaughtyUserName", "RDP", 1, IPAddressEventType.FailedLogin) }); await service.RunCycle(); Assert.IsTrue(service.Firewall.IsIPAddressBlocked("99.99.99.90", out _)); Assert.IsFalse(service.Firewall.IsIPAddressBlocked("99.99.99.99", out _)); }
private void AssertEventViewerGroup(EventViewerExpressionGroup group, string keywords, int windowsMinimumMajorVersion, int windowsMinimumMinorVersion, bool notifyOnly, string path, string source, params string[] expressions) { Assert.NotNull(group); Assert.AreEqual(keywords, group.Keywords); Assert.AreEqual(ulong.Parse(keywords.Replace("0x", string.Empty), System.Globalization.NumberStyles.HexNumber), group.KeywordsULONG); Assert.AreEqual(windowsMinimumMajorVersion, group.MinimumWindowsMajorVersion); Assert.AreEqual(windowsMinimumMinorVersion, group.MinimumWindowsMinorVersion); Assert.AreEqual(notifyOnly, group.NotifyOnly); Assert.AreEqual(path, group.Path); Assert.AreEqual(source, group.Source); Assert.NotNull(group.Expressions); Assert.AreEqual(group.Expressions.Count, expressions.Length / 2); for (int i = 0; i < expressions.Length;) { int groupIndex = i / 2; Regex regex = IPBanConfig.ParseRegex(group.Expressions[groupIndex].Regex); Assert.AreEqual(expressions[i++], group.Expressions[groupIndex].XPath?.Trim()); Assert.AreEqual(expressions[i++], (regex is null ? string.Empty : regex.ToString())); } }
public async Task TestIPWhitelist() { const string whitelist = "192.168.0.0/16"; string config = await service.ReadConfigAsync(); string newConfig = IPBanConfig.ChangeConfigAppSetting(config, "Whitelist", whitelist); await service.WriteConfigAsync(newConfig); try { // load new config service.RunCycle().Sync(); string banIP = "99.99.99.99"; string noBanIP = "192.168.99.99"; service.AddIPAddressLogEvents(new IPAddressLogEvent[] { // should be banned new IPAddressLogEvent(banIP, "user1", "RDP", 999, IPAddressEventType.FailedLogin), // whitelisted new IPAddressLogEvent(noBanIP, "user2", "RDP", 999, IPAddressEventType.FailedLogin), }); // process failed logins service.RunCycle().Sync(); Assert.IsTrue(service.Firewall.IsIPAddressBlocked(banIP, out _)); Assert.IsFalse(service.Firewall.IsIPAddressBlocked(noBanIP, out _)); Assert.IsTrue(service.DB.TryGetIPAddress(banIP, out IPBanDB.IPAddressEntry e1)); Assert.IsFalse(service.DB.TryGetIPAddress(noBanIP, out IPBanDB.IPAddressEntry e2)); } finally { // restore config await service.WriteConfigAsync(config); } }
public async Task TestExtraFirewallRules() { string config = await service.ReadConfigAsync(); string newConfig = IPBanConfig.ChangeConfigAppSetting(config, "FirewallRules", @" ReddisAllowIP;allow;10.0.0.1,10.0.0.2,192.168.1.168/24;6379;. WebOnly;block;0.0.0.0/1,128.0.0.0/1,::/1,8000::/1;22,80,443,3389;^(?:(?!Windows).)+$ "); await service.WriteConfigAsync(newConfig); await service.RunCycle(); List <string> rules = service.Firewall.GetRuleNames().ToList(); string reddisRule = service.Firewall.RulePrefix + "EXTRA_ReddisAllowIP"; string webRule = service.Firewall.RulePrefix + "EXTRA_WebOnly"; if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { // on Windows, block is the default, so only the allow rules should show up Assert.IsTrue(rules.Exists((s) => s.StartsWith(reddisRule))); Assert.IsFalse(rules.Exists((s) => s.StartsWith(webRule))); Assert.AreEqual(1, service.Config.ExtraRules.Count); IPBanFirewallRule rule1 = service.Config.ExtraRules[0]; string regexString = rule1.ToString(); Assert.AreEqual("EXTRA_ReddisAllowIP;allow;10.0.0.1/32,10.0.0.2/32,192.168.1.0/24;6379;.", regexString); } else { // on Linux, both rules are needed Assert.AreEqual(2, service.Config.ExtraRules.Count); Assert.IsTrue(rules.Exists((s) => s.StartsWith(reddisRule))); Assert.IsTrue(rules.Exists((s) => s.StartsWith(webRule))); IPBanFirewallRule rule1 = service.Config.ExtraRules[0]; IPBanFirewallRule rule2 = service.Config.ExtraRules[1]; string regexString1 = rule1.ToString(); string regexString2 = rule2.ToString(); Assert.AreEqual("EXTRA_ReddisAllowIP;allow;10.0.0.1/32,10.0.0.2/32,192.168.1.0/24;6379;.", regexString1); Assert.AreEqual("EXTRA_WebOnly;block;0.0.0.0/1,128.0.0.0/1,::/1,8000::/1;22,80,443,3389;^(?:(?!Windows).)+$", regexString2); } }
public void TestDefaultConfig() { // ensure config file is read properly IPBanService service = IPBanService.CreateAndStartIPBanTestService <IPBanService>(); try { IPBanConfig cfg = service.Config; Assert.IsNotNull(cfg); Assert.AreEqual(TimeSpan.FromDays(1.0), cfg.BanTime); Assert.IsEmpty(cfg.BlackList); Assert.IsEmpty(cfg.BlackListRegex); Assert.IsFalse(cfg.ClearBannedIPAddressesOnRestart); Assert.IsFalse(cfg.CreateWhitelistFirewallRule); Assert.AreEqual(TimeSpan.FromSeconds(15.0), cfg.CycleTime); Assert.AreEqual(TimeSpan.FromDays(1.0), cfg.ExpireTime); Assert.AreEqual("https://checkip.amazonaws.com/", cfg.ExternalIPAddressUrl); Assert.AreEqual(5, cfg.FailedLoginAttemptsBeforeBan); Assert.AreEqual(20, cfg.FailedLoginAttemptsBeforeBanUserNameWhitelist); Assert.AreEqual(1, cfg.FirewallOSAndType.Count); Assert.AreEqual("*:Default", cfg.FirewallOSAndType.Keys.First() + ":" + cfg.FirewallOSAndType.Values.First()); Assert.AreEqual("IPBan_", cfg.FirewallRulePrefix); Assert.AreEqual(TimeSpan.FromSeconds(1.0), cfg.MinimumTimeBetweenFailedLoginAttempts); Assert.IsEmpty(cfg.ProcessToRunOnBan); Assert.IsFalse(cfg.UseDefaultBannedIPAddressHandler); // the create and start test service forces this false, it is true otherwise in production by default Assert.IsEmpty(cfg.UserNameWhitelist); Assert.IsEmpty(cfg.WhiteList); Assert.IsEmpty(cfg.WhiteListRegex); AssertLogFilesToParse(cfg); AssertEventViewer(cfg); IPBanConfig prod = IPBanConfig.LoadFromFile(service.ConfigFilePath.Replace(".tmp", string.Empty), null); Assert.IsTrue(prod.UseDefaultBannedIPAddressHandler); } finally { IPBanService.DisposeIPBanTestService(service); } }
private void RunConfigBanTest(string key, string value, string banIP, string noBanIP, int noBanIPCount = 999) { // turn on clear failed logins upon success login using IPBanConfig.TempConfigChanger configChanger = new IPBanConfig.TempConfigChanger(service, xml => { return(IPBanConfig.ChangeConfigAppSetting(xml, key, value)); }, out string newConfig); List <IPAddressLogEvent> events = new List <IPAddressLogEvent> { new IPAddressLogEvent(banIP, "user1", "RDP", 999, IPAddressEventType.FailedLogin) }; if (!string.IsNullOrWhiteSpace(noBanIP)) { events.Add(new IPAddressLogEvent(noBanIP, "user2", "RDP", noBanIPCount, IPAddressEventType.FailedLogin)); } service.AddIPAddressLogEvents(events); // process failed logins service.RunCycle().Sync(); Assert.IsTrue(service.Firewall.IsIPAddressBlocked(banIP, out _)); Assert.IsTrue(service.DB.TryGetIPAddress(banIP, out IPBanDB.IPAddressEntry e1)); Assert.AreEqual(e1.FailedLoginCount, 999); if (!string.IsNullOrWhiteSpace(noBanIP)) { Assert.IsFalse(service.Firewall.IsIPAddressBlocked(noBanIP, out _)); if (noBanIPCount > 0) { Assert.IsTrue(service.DB.TryGetIPAddress(noBanIP, out IPBanDB.IPAddressEntry e2)); Assert.AreEqual(e2.FailedLoginCount, noBanIPCount); } else { Assert.IsFalse(service.DB.TryGetIPAddress(noBanIP, out _)); } } }
public async Task TestUserNameBan() { string config = await service.ReadConfigAsync(); string newConfig = IPBanConfig.ChangeConfigAppSetting(config, "Blacklist", "NaughtyUserName"); await service.WriteConfigAsync(newConfig); await service.RunCycle(); service.AddIPAddressLogEvents(new IPAddressLogEvent[] { // a single failed login with a non-blacklisted user name should not get banned new IPAddressLogEvent("99.99.99.99", "Good User Name", "RDP", 1, IPAddressEventType.FailedLogin), // a single failed login with a blacklisted user name should get banned new IPAddressLogEvent("99.99.99.90", "NaughtyUserName", "RDP", 1, IPAddressEventType.FailedLogin) }); await service.RunCycle(); Assert.IsTrue(service.Firewall.IsIPAddressBlocked("99.99.99.90", out _)); Assert.IsFalse(service.Firewall.IsIPAddressBlocked("99.99.99.99", out _)); }
public async Task TestFailedLoginsClearOnSuccessfulLogin() { // turn on clear failed logins upon success login string config = await service.ReadConfigAsync(); string newConfig = IPBanConfig.ChangeConfigAppSetting(config, nameof(IPBanConfig.ClearFailedLoginsOnSuccessfulLogin), "true"); await service.WriteConfigAsync(newConfig); try { await service.RunCycle(); string ip = "99.88.77.66"; for (int i = 0; i < 2; i++) { service.AddIPAddressLogEvents(new IPAddressLogEvent[] { // fail login new IPAddressLogEvent(ip, "user1", "RDP", 1, IPAddressEventType.FailedLogin), }); } await service.RunCycle(); service.AddIPAddressLogEvents(new IPAddressLogEvent[] { new IPAddressLogEvent(ip, "user1", "RDP", 1, IPAddressEventType.SuccessfulLogin), }); await service.RunCycle(); Assert.IsFalse(service.DB.TryGetIPAddress(ip, out _)); } finally { // restore config await service.WriteConfigAsync(config); } }
private void AssertLogFilesToParse(IPBanConfig cfg) { const int maxFileSize = 16777216; const int pingInterval = 10000; const string pathAndMask1 = "/var/log/auth*.log\n/var/log/secure*"; const string pathAndMask2 = "/var/log/ipbancustom*.log"; const string pathAndMask3 = "C:/Program Files/Microsoft/Exchange Server/*.log"; const string pathAndMask4 = "C:/IPBanCustomLogs/*.log"; const string failedRegex1 = @"failed\s+password\s+for\s+(invalid\s+user\s+)?(?<username>.+?\s+)from\s+(?<ipaddress>.+?)\s+port\s+[0-9]+\s+ssh|did\s+not\s+receive\s+identification\s+string\s+from\s+(?<ipaddress>[^\s]+)|connection\s+closed\s+by\s+(invalid\s+user\s+)?(?<username>.+?\s+)?(?<ipaddress>.+?)\s+port\s+[0-9]+\s+\[preauth\]\s*(\(no\s+attempt\s+to\s+login\s+after\s+timeout\))?|disconnected\s+from\s+(invalid\s+user\s+)?(?<username>.+?)\s+(?<ipaddress>.+?)\s+port\s+[0-9]+\s+\[preauth\]|disconnected\s+from\s+(?<ipaddress>.+?)\s+port\s+[0-9]+\s+\[preauth\]|disconnected\s+from\s+authenticating\s+user\s+(?<username>.+?)\s+(?<ipaddress>.+?)\s+port\s+[0-9]+\s+\[preauth\]"; const string successRegex1 = @"Accepted\s+password\s+for\s+(?<username>.+?)\s+from\s+(?<ipaddress>.+?)\s+port\s+[0-9]+\s+ssh"; const string failedRegex2 = @"ipban\sfailed\slogin,\sip\saddress:\s(?<ipaddress>.+?),\ssource:\s(?<source>.+?),\suser:\s(?<username>[^\s,]+)"; const string successRegex2 = @"ipban\ssuccess\slogin,\sip\saddress:\s(?<ipaddress>.+?),\ssource:\s(?<source>.+?),\suser:\s(?<username>[^\s,]+)"; const string failedRegex3 = @".*?,.*?,.*?,.*?,(?<ipaddress>.+?),(?<username>.+?),.*?AuthFailed"; const string successRegex3 = @""; const string failedRegex4 = @"ipban\sfailed\slogin,\sip\saddress:\s(?<ipaddress>.+?),\ssource:\s(?<source>.+?),\suser:\s(?<username>[^\s,]+)"; const string successRegex4 = @"ipban\ssuccess\slogin,\sip\saddress:\s(?<ipaddress>.+?),\ssource:\s(?<source>.+?),\suser:\s(?<username>[^\s,]+)"; Assert.AreEqual(4, cfg.LogFilesToParse.Count); AssertLogFileToParse(cfg.LogFilesToParse[0], failedRegex1, maxFileSize, pathAndMask1, pingInterval, "Linux", false, "SSH", successRegex1); AssertLogFileToParse(cfg.LogFilesToParse[1], failedRegex2, maxFileSize, pathAndMask2, pingInterval, "Linux", false, "IPBanCustom", successRegex2); AssertLogFileToParse(cfg.LogFilesToParse[2], failedRegex3, maxFileSize, pathAndMask3, pingInterval, "Windows", true, "MSExchange", successRegex3); AssertLogFileToParse(cfg.LogFilesToParse[3], failedRegex4, maxFileSize, pathAndMask4, pingInterval, "Windows", true, "IPBanCustom", successRegex4); }
private void AssertEventViewer(IPBanConfig cfg) { const int minimumWindowsMajorVersion = 6; EventViewerExpressionGroup[] groups = cfg.WindowsEventViewerExpressionsToBlock.Groups; Assert.NotNull(groups); Assert.AreEqual(9, groups.Length); AssertEventViewerGroup(groups[0], "0x8010000000000000", minimumWindowsMajorVersion, 0, false, "Security", "RDP", "//EventID", "^(4625|5152)$", "//Data[@Name='IpAddress' or @Name='Workstation' or @Name='SourceAddress']", "(?<ipaddress>.+)"); AssertEventViewerGroup(groups[1], "0x80000000000000", minimumWindowsMajorVersion, 0, false, "Application", "IPBanCustom", "//Data", @"ipban\sfailed\slogin,\sip\saddress:\s(?<ipaddress>.+?),\ssource:\s(?<source>.+?),\suser:\s(?<username>[^\s,]+)"); AssertEventViewerGroup(groups[2], "0x90000000000000", minimumWindowsMajorVersion, 0, false, "Application", "MSSQL", "//Provider[@Name='MSSQLSERVER']", string.Empty, "//Data", @"(?!(\[CLIENT\s?:|Reason\s?:))(?<username>.+)", "//Data", @"\[CLIENT\s?:\s?(?<ipaddress>.*?)\]"); AssertEventViewerGroup(groups[3], "0x80000000000000", minimumWindowsMajorVersion, 0, false, "Application", "MySQL", "//Provider[@Name='MySQL']", string.Empty, "//Data", "Access denied for user '?(?<username>.*?)'@'(?<ipaddress>.*?)'"); AssertEventViewerGroup(groups[4], "0x80000000000000", minimumWindowsMajorVersion, 0, false, "System", "MSExchange", "//Provider[@Name='MSExchangeTransport']", string.Empty, "//Data", "LogonDenied", "//Data", "(?<ipaddress_exact>.+)"); AssertEventViewerGroup(groups[5], "0x80000000000000", minimumWindowsMajorVersion, 0, false, "Application", "phpMyAdmin", "//Data", "phpMyAdmin", "//Data", @"user denied: (?<username>.*?)\(mysql-denied\) from *(?<ipaddress>.+)"); AssertEventViewerGroup(groups[6], "0x8000000000000000", minimumWindowsMajorVersion, 0, false, "OpenSSH/Admin", "SSH", "//Data[@Name='payload']", @"maximum authentication attempts exceeded for( invalid user)? (?<username>.*?) from (?<ipaddress>.*?)\s"); AssertEventViewerGroup(groups[7], "0x4000000000000000", minimumWindowsMajorVersion, 0, false, "OpenSSH/Operational", "SSH", "//Data[@Name='payload']", @"Failed password for( invalid user)? (?<username>.*?) from (?<ipaddress>.*?)\s|Connection closed by (?<ipaddress>.*?) port [0-9]+ \[preauth\]"); AssertEventViewerGroup(groups[8], "0x4000000000000000", minimumWindowsMajorVersion, 0, false, "Microsoft-Windows-RemoteDesktopServices-RdpCoreTS/Operational", "RDP", "//Opcode", "^14$", "//Data[@Name='ClientIP' or @Name='IPString']", "(?<ipaddress>.+)"); groups = cfg.WindowsEventViewerExpressionsToNotify.Groups; Assert.NotNull(groups); Assert.AreEqual(3, groups.Length); AssertEventViewerGroup(groups[0], "0x8000000000000000", minimumWindowsMajorVersion, 0, true, "Security", "RDP", "//EventID", "^4624$", "//Data[@Name='IpAddress' or @Name='Workstation' or @Name='SourceAddress']", "(?<ipaddress>.+)"); AssertEventViewerGroup(groups[1], "0x4000000000000000", minimumWindowsMajorVersion, 0, true, "OpenSSH/Operational", "SSH", "//Data[@Name='payload']", "Accepted password for (?<username>.+?) from (?<ipaddress>.+?) port [0-9]+ ssh"); AssertEventViewerGroup(groups[2], "0x80000000000000", minimumWindowsMajorVersion, 0, true, "Application", "IPBanCustom", "//Data", @"ipban\ssuccess\slogin,\sip\saddress:\s(?<ipaddress>.+?),\ssource:\s(?<source>.+?),\suser:\s(?<username>[^\s,]+)"); }
private async Task TestMultipleBanTimespansExternalBlockAsync(bool resetFailedLogin) { const string ipAddress = "99.99.99.99"; const string userName = "******"; const string source = "RDP"; const IPAddressEventType type = IPAddressEventType.FailedLogin; KeyValuePair <DateTime?, DateTime?> banDates; service.IPBanDelegate = new ExternalBlocker(service); IPAddressLogEvent[] events = new IPAddressLogEvent[1]; using IPBanConfig.TempConfigChanger configChanger = new IPBanConfig.TempConfigChanger(service, xml => { xml = IPBanConfig.ChangeConfigAppSetting(xml, "BanTime", "00:00:01:00,00:00:05:00,00:00:15:00,89:00:00:00"); xml = IPBanConfig.ChangeConfigAppSetting(xml, "ResetFailedLoginCountForUnbannedIPAddresses", resetFailedLogin.ToString()); return(xml); }, out string newConfig); Assert.AreEqual(4, service.Config.BanTimes.Length); // send a block event, should get banned for 1 minute IPBanService.UtcNow = new DateTime(2020, 1, 1, 1, 1, 1, DateTimeKind.Utc); for (int i = 0; i < 2; i++) { events[0] = new IPAddressLogEvent(ipAddress, userName, source, 1, type, IPBanService.UtcNow); service.AddIPAddressLogEvents(events); await service.RunCycle(); Assert.IsFalse(service.Firewall.IsIPAddressBlocked(ipAddress)); // run cycle again, should get pinged by external blocker and ip should be blocked await service.RunCycle(); Assert.IsTrue(service.Firewall.IsIPAddressBlocked(ipAddress)); Assert.IsTrue(service.DB.TryGetBanDates(ipAddress, out banDates)); Assert.AreEqual(IPBanService.UtcNow, banDates.Key); Assert.AreEqual(IPBanService.UtcNow.AddMinutes(1.0), banDates.Value); // short step, should still be blocked IPBanService.UtcNow += TimeSpan.FromSeconds(1.0); await service.RunCycle(); Assert.IsTrue(service.Firewall.IsIPAddressBlocked(ipAddress)); IPBanService.UtcNow += TimeSpan.FromMinutes(1.0); await service.RunCycle(); Assert.IsFalse(service.Firewall.IsIPAddressBlocked(ipAddress)); // send a fail login event, should get banned for 5 minutes events[0] = new IPAddressLogEvent(ipAddress, userName, source, 1, type, IPBanService.UtcNow); service.AddIPAddressLogEvents(events); await service.RunCycle(); Assert.IsFalse(service.Firewall.IsIPAddressBlocked(ipAddress)); DateTime savedBanDate = IPBanService.UtcNow; // add a failed and blocked login event, should not interfere with the ban cycle events[0] = new IPAddressLogEvent(ipAddress, userName, source, 1, IPAddressEventType.FailedLogin, IPBanService.UtcNow); service.AddIPAddressLogEvents(events); await service.RunCycle(); events[0] = new IPAddressLogEvent(ipAddress, userName, source, 1, IPAddressEventType.Blocked, IPBanService.UtcNow, true); service.AddIPAddressLogEvents(events); await service.RunCycle(); // throw in some chaos IPBanService.UtcNow += TimeSpan.FromSeconds(7.213); // blocker will ban the ip await service.RunCycle(); Assert.IsTrue(service.Firewall.IsIPAddressBlocked(ipAddress)); Assert.IsTrue(service.DB.TryGetBanDates(ipAddress, out banDates)); Assert.AreEqual(savedBanDate, banDates.Key); Assert.AreEqual(savedBanDate.AddMinutes(5.0), banDates.Value); IPBanService.UtcNow += TimeSpan.FromMinutes(20.0); await service.RunCycle(); Assert.IsFalse(service.Firewall.IsIPAddressBlocked(ipAddress)); // send a failed login event, should get banned for 15 minutes events[0] = new IPAddressLogEvent(ipAddress, userName, source, 1, type, IPBanService.UtcNow); service.AddIPAddressLogEvents(events); await service.RunCycle(); Assert.IsFalse(service.Firewall.IsIPAddressBlocked(ipAddress)); // cycle again, blocker will ban await service.RunCycle(); Assert.IsTrue(service.Firewall.IsIPAddressBlocked(ipAddress)); Assert.IsTrue(service.DB.TryGetBanDates(ipAddress, out banDates)); Assert.AreEqual(IPBanService.UtcNow, banDates.Key); Assert.AreEqual(IPBanService.UtcNow.AddMinutes(15.0), banDates.Value); IPBanService.UtcNow += TimeSpan.FromMinutes(30.0); await service.RunCycle(); Assert.IsFalse(service.Firewall.IsIPAddressBlocked(ipAddress)); // send a block event, should get banned for 89 days events[0] = new IPAddressLogEvent(ipAddress, userName, source, 1, type, IPBanService.UtcNow); service.AddIPAddressLogEvents(events); await service.RunCycle(); Assert.IsFalse(service.Firewall.IsIPAddressBlocked(ipAddress)); // cycle again, blocker will ban await service.RunCycle(); Assert.IsTrue(service.Firewall.IsIPAddressBlocked(ipAddress)); Assert.IsTrue(service.DB.TryGetBanDates(ipAddress, out banDates)); Assert.AreEqual(IPBanService.UtcNow, banDates.Key); Assert.AreEqual(IPBanService.UtcNow.AddDays(89.0), banDates.Value); IPBanService.UtcNow += TimeSpan.FromDays(91.0); await service.RunCycle(); Assert.IsFalse(service.Firewall.IsIPAddressBlocked(ipAddress)); } }
private async Task TestMultipleBanTimespansAsync(bool resetFailedLogin) { string config = await service.ReadConfigAsync(); string newConfig = IPBanConfig.ChangeConfigAppSetting(config, "BanTime", "00:00:01:00,00:00:02:00,00:00:03:00"); newConfig = IPBanConfig.ChangeConfigAppSetting(newConfig, "ResetFailedLoginCountForUnbannedIPAddresses", resetFailedLogin.ToString()); await service.WriteConfigAsync(newConfig); try { await service.RunCycle(); Assert.AreEqual(3, service.Config.BanTimes.Length); Assert.AreEqual(resetFailedLogin, service.Config.ResetFailedLoginCountForUnbannedIPAddresses); for (int i = 1; i <= 3; i++) { Assert.AreEqual(TimeSpan.FromMinutes(i), service.Config.BanTimes[i - 1]); } for (int i = 0; i < 4; i++) { // forget all the bans, but they should still be in the database due to the multiple timespans as failed logins IPBanService.UtcNow += TimeSpan.FromDays(14.0); await service.RunCycle(); if (i < 3) { if (i > 0) { AssertIPAddressesAreNotBanned(true, true); } AddFailedLogins((i == 0 ? -1 : 1)); if (resetFailedLogin) { if (i > 0) { // after one fail login, should not be banned AssertIPAddressesAreNotBanned(true, true); } // add more failed logins AddFailedLogins(); // now they should be banned, fail login counts are reset upon ban AssertIPAddressesAreBanned(0, 0); } else { // should have gotten back in with just a single failed login AssertIPAddressesAreBanned(info1.Count + i, info2.Count + i); } Assert.IsTrue(service.DB.TryGetIPAddress(ip1, out IPBanDB.IPAddressEntry e1)); Assert.IsTrue(service.DB.TryGetIPAddress(ip2, out IPBanDB.IPAddressEntry e2)); // i == 3 means wrap around from 3 minutes back to 1 minute TimeSpan expectedBanDuration = (i < 3 ? expectedBanDuration = TimeSpan.FromMinutes(i + 1) : TimeSpan.FromMinutes(1.0)); Assert.AreEqual(expectedBanDuration, e1.BanEndDate - e1.BanStartDate); Assert.AreEqual(expectedBanDuration, e2.BanEndDate - e2.BanStartDate); if (resetFailedLogin) { Assert.AreEqual(0, e1.FailedLoginCount); Assert.AreEqual(0, e2.FailedLoginCount); } else { Assert.AreNotEqual(0, e1.FailedLoginCount); Assert.AreNotEqual(0, e2.FailedLoginCount); } } else { // the cycle will run and remove the expired ip first as they have finished the loop through the ban times, they should all have a single failed login count AddFailedLogins(1); AssertIPAddressesAreNotBanned(true, true); Assert.IsTrue(service.DB.TryGetIPAddress(ip1, out IPBanDB.IPAddressEntry e1)); Assert.IsTrue(service.DB.TryGetIPAddress(ip2, out IPBanDB.IPAddressEntry e2)); Assert.IsNull(e1.BanStartDate); Assert.IsNull(e2.BanStartDate); Assert.IsNull(e1.BanEndDate); Assert.IsNull(e2.BanEndDate); Assert.AreEqual(1, e1.FailedLoginCount); Assert.AreEqual(1, e2.FailedLoginCount); // now add a bunch of fail logins, ip should ban with a time span of 1 minute AddFailedLogins(); if (resetFailedLogin) { AssertIPAddressesAreBanned(0, 0); } else { AssertIPAddressesAreBanned(info1.Count + 1, info2.Count + 1); } Assert.IsTrue(service.DB.TryGetIPAddress(ip1, out e1)); Assert.IsTrue(service.DB.TryGetIPAddress(ip2, out e2)); TimeSpan expectedBanDuration = TimeSpan.FromMinutes(1.0); Assert.AreEqual(expectedBanDuration, e1.BanEndDate - e1.BanStartDate); Assert.AreEqual(expectedBanDuration, e2.BanEndDate - e2.BanStartDate); if (resetFailedLogin) { Assert.AreEqual(0, e1.FailedLoginCount); Assert.AreEqual(0, e2.FailedLoginCount); } else { Assert.AreEqual(info1.Count + 1, e1.FailedLoginCount); Assert.AreEqual(info2.Count + 1, e2.FailedLoginCount); } } } } finally { // restore config await service.WriteConfigAsync(config); } }
private static void AssertLogFilesToParse(IPBanConfig cfg) { const int maxFileSize = 16777216; const int pingInterval = 10000; // path and mask, fail expression, fail timestamp format, success expression, success timestamp format, platform regex, source object[] logFileData = new object[] { "/var/log/auth*.log\n/var/log/secure*\n/var/log/messages", @"failed\s+password\s+for\s+(invalid\s+user\s+)?(?<username>[^\s]+)\s+from\s+(?<ipaddress>[^\s]+)\s+port\s+[0-9]+\s+ssh|did\s+not\s+receive\s+identification\s+string\s+from\s+(?<ipaddress>[^\s]+)|connection\s+closed\s+by\s+((invalid\s+user\s+)?(?<username>[^\s]+)\s+)?(?<ipaddress>[^\s]+)\s+port\s+[0-9]+\s+\[preauth\]|disconnected\s+from\s+(invalid\s+user\s+)?(?<username>[^\s]+)\s+(?<ipaddress>[^\s]+)\s+port\s+[0-9]+\s+\[preauth\]|disconnected\s+from\s+(?<ipaddress>[^\s]+)\s+port\s+[0-9]+\s+\[preauth\]|disconnected\s+from\s+authenticating\s+user\s+(?<username>[^\s]+)\s+(?<ipaddress>[^\s]+)\s+port\s+[0-9]+\s+\[preauth\]", @"", @"Accepted\s+password\s+for\s+(?<username>[^\s]+)\s+from\s+(?<ipaddress>[^\s]+)\s+port\s+[0-9]+\s+ssh", @"", "Linux", "SSH", "/var/log/ipbancustom*.log", @"(?<timestamp>\d\d\d\d-\d\d-\d\d\s\d\d:\d\d:\d\d(?:\.\d+)?Z?)?(?:,\s)?ipban\sfailed\slogin,\sip\saddress:\s(?<ipaddress>[^,\n]+),\ssource:\s(?<source>[^,\n]+)?,\suser:\s(?<username>[^\s,]+)?", @"", @"(?<timestamp>\d\d\d\d-\d\d-\d\d\s\d\d:\d\d:\d\d(?:\.\d+)?Z?)?(?:,\s)?ipban\ssuccess\slogin,\sip\saddress:\s(?<ipaddress>[^,\n]+),\ssource:\s(?<source>[^,\n]+)?,\suser:\s(?<username>[^\s,]+)?", @"", "Linux", "IPBanCustom", "C:/Program Files/Microsoft/Exchange Server/*/TransportRoles/Logs/FrontEnd/ProtocolLog/**.log", @"^(?<timestamp>[0-9TZ\-:\.]+),(?:.*?\\(?:External\sAuthenticated\sRelay|Internet\sRecive\sFrontend),)?(?:[^,\n]*,){3}(?<ipaddress>[^,\n]+).*?(?:(?:504\s5\.7\.4\sUnrecognized\sauthentication\stype)|(?:LogonDenied\n?.*?(?:User\:|User\sName\:)\s(?<username>[^\n,""]+)))", @"", @"^(?<timestamp>[0-9TZ\-:\.]+)?,(?:[^,\n]*,){4}(?<ipaddress>[^,\n]+),(?:[^,\n]*),(?<username>[^,\n]*),authenticated", @"", "Windows", "MSExchange", "C:/Program Files/Smarter Tools/Smarter Mail/**/*.log\nC:/Program Files (x86)/Smarter Tools/Smarter Mail/**/*.log\nC:/SmarterMail/logs/**/*.log\nC:/Smarter Mail/logs/**/*.log", @"\[(?<ipaddress>[^\]\n]+)\](?:\[[^\]\n]*\]\s+).*?(?:(?:The\sdomain\sgiven\sin\sthe\sEHLO\scommand\sviolates\san\sEHLO\sSMTP)|(?:IP\sblocked\sby\sbrute\sforce\sabuse\sdetection\srule)|(?:login\sfailed)|(?:IP\sblocked\sby\sbrute\sforce\sabuse\sdetection\srule)|(?:IP\sis\sblacklisted)|(?:too\smany\sauthentication\sfailures)|(?:Authentication\sfailed)|(?:EHLO\sSMTP\sblocking\srule)|(?:IP\sblocked\sby\sbrute\sforce\sabuse\sdetection\srule)|(?:IP\sis\sblacklisted)|(?:Mail\srejected\sdue\sto\sSMTP\sSpam\sBlocking)|(?:Too\smany\sauthentication\sfailures))", @"", @"", @"", "Windows", "SmarterMail", "C:/Program Files (x86)/Mail Enable/Logging/SMTP/SMTP-Activity-*.log\nC:/Program Files/Mail Enable/Logging/SMTP/SMTP-Activity-*.log\nC:/Program Files (x86)/Mail Enable/Logging/IMAP\nC:/Program Files/Mail Enable/Logging/IMAP", @"^(?<timestamp>[0-9\/:\s]+)SMTP\-IN\s+[^\s]+\s+[^\s]+\s(?<ipaddress>[^\s]+)\s+[^\s]+\s+[^\s]+\s+[^\s]+\s+Invalid\sUsername\sor\sPassword\s+[^\s]+\s+[^\s]+\s+(?<username>[^\n]+)$|^(?<timestamp>[0-9\/:\s]+)IMAP\-IN\s+[^\s]+\s+(?<ipaddress>[^\s]+)\s+LOGIN\s+LOGIN\s+""(?<username>[^""]+)""\s+""[^""]+""\s+[^\s]+\s+NO\s+LOGIN\s+Failed\s+[^\s]+\s+Invalid\s+username\s+or\s+password[^\n]*$", @"MM/dd/yy HH:mm:ss", @"", @"", "Windows", "MailEnable", "C:/Program Files/Tomcat/logs/**/*access_log*.txt\n/var/log/httpd/access_log", @"^(?<ipaddress>[^\s]+)\s.*?\[(?<timestamp>.*?)\].*?(?:(?:\s40[034]\s(-|[0-9]+))|((php|md5sum|cgi-bin|joomla).*?\s404\s[0-9]+|\s400\s-))[^\n]*", @"dd/MMM/yyyy:HH:mm:ss zzzz", @"", @"", "Windows|Linux", "Apache", "C:/IPBanCustomLogs/**/*.log", @"(?<timestamp>\d\d\d\d-\d\d-\d\d\s\d\d:\d\d:\d\d(?:\.\d+)?Z?)?(?:,\s)?ipban\sfailed\slogin,\sip\saddress:\s(?<ipaddress>[^,\n]+),\ssource:\s(?<source>[^,\n]+)?,\suser:\s(?<username>[^\s,]+)?", @"", @"(?<timestamp>\d\d\d\d-\d\d-\d\d\s\d\d:\d\d:\d\d(?:\.\d+)?Z?)?(?:,\s)?ipban\ssuccess\slogin,\sip\saddress:\s(?<ipaddress>[^,\n]+),\ssource:\s(?<source>[^,\n]+)?,\suser:\s(?<username>[^\s,]+)?", @"", "Windows", "IPBanCustom" }; Assert.AreEqual(logFileData.Length / 7, cfg.LogFilesToParse.Count); for (int i = 0; i < logFileData.Length; i += 7) { AssertLogFileToParse(cfg.LogFilesToParse[i / 7], (string)logFileData[i + 1], (string)logFileData[i + 2], maxFileSize, (string)logFileData[i], pingInterval, (string)logFileData[i + 5], (string)logFileData[i + 6], (string)logFileData[i + 3], (string)logFileData[i + 4]); } }
private void AssertLogFilesToParse(IPBanConfig cfg) { const int maxFileSize = 16777216; const int pingInterval = 10000; // path and mask, fail expression, fail timestamp format, success expression, success timestamp format, platform regex, source object[] logFileData = new object[] { "/var/log/auth*.log\n/var/log/secure*", @"failed\s+password\s+for\s+(invalid\s+user\s+)?(?<username>[^\s]+)\s+from\s+(?<ipaddress>[^\s]+)\s+port\s+[0-9]+\s+ssh|did\s+not\s+receive\s+identification\s+string\s+from\s+(?<ipaddress>[^\s]+)|connection\s+closed\s+by\s+((invalid\s+user\s+)?(?<username>[^\s]+)\s+)?(?<ipaddress>[^\s]+)\s+port\s+[0-9]+\s+\[preauth\]|disconnected\s+from\s+(invalid\s+user\s+)?(?<username>[^\s]+)\s+(?<ipaddress>[^\s]+)\s+port\s+[0-9]+\s+\[preauth\]|disconnected\s+from\s+(?<ipaddress>[^\s]+)\s+port\s+[0-9]+\s+\[preauth\]|disconnected\s+from\s+authenticating\s+user\s+(?<username>[^\s]+)\s+(?<ipaddress>[^\s]+)\s+port\s+[0-9]+\s+\[preauth\]", @"", @"Accepted\s+password\s+for\s+(?<username>[^\s]+)\s+from\s+(?<ipaddress>[^\s]+)\s+port\s+[0-9]+\s+ssh", @"", "Linux", "SSH", "/var/log/ipbancustom*.log", @"(?<timestamp>\d\d\d\d-\d\d-\d\d\s\d\d:\d\d:\d\d\.?\d*Z?,\s)?ipban\sfailed\slogin,\sip\saddress:\s(?<ipaddress>[^,\n]+),\ssource:\s(?<source>[^,\n]+),\suser:\s?(?<username>[^\s,]+)?", @"", @"(?<timestamp>\d\d\d\d-\d\d-\d\d\s\d\d:\d\d:\d\d\.?\d*Z?,\s)?ipban\ssuccess\slogin,\sip\saddress:\s(?<ipaddress>[^,\n]+),\ssource:\s(?<source>[^,\n]+),\suser:\s?(?<username>[^\s,]+)?", @"", "Linux", "IPBanCustom", "C:/Program Files/Microsoft/Exchange Server/*/TransportRoles/Logs/FrontEnd/ProtocolLog/**.log", @"^(?<timestamp>[0-9TZ\-:\.]+),(?:[^,\n]*,){3}(?:(?<ipaddress>[^,\n]+),(?<username>[^,\n]*),.*?AuthFailed[^\n]*|(?:[^,\n]*,)(?<ipaddress>[^,\n]+),(?:[^,\n]*,){2}.*?\sof\sLogonDenied\n.*?User\sName:\s(?<username>[^\n]*))\n", @"", @"^(?<timestamp>[0-9TZ\-:\.]+)?,(?:[^,\n]*,){4}(?<ipaddress>[^,\n]+),(?:[^,\n]*),(?<username>[^,\n]*),authenticated", @"", "Windows", "MSExchange", "C:/Program Files/Smarter Tools/Smarter Mail/**/*.log\nC:/Program Files (x86)/Smarter Tools/Smarter Mail/**/*.log\nC:/SmarterMail/logs/**/*.log\nC:/Smarter Mail/logs/**/*.log", @"\[(?<ipaddress>[^\]\n]+)\](?:\[[^\]\n]*\]\s+).*?(?:(?:The\sdomain\sgiven\sin\sthe\sEHLO\scommand\sviolates\san\sEHLO\sSMTP)|(?:IP\sblocked\sby\sbrute\sforce\sabuse\sdetection\srule)|(?:login\sfailed)|(?:IP\sblocked\sby\sbrute\sforce\sabuse\sdetection\srule)|(?:IP\sis\sblacklisted)|(?:too\smany\sauthentication\sfailures)|(?:Authentication\sfailed)|(?:EHLO\sSMTP\sblocking\srule)|(?:IP\sblocked\sby\sbrute\sforce\sabuse\sdetection\srule)|(?:IP\sis\sblacklisted)|(?:Mail\srejected\sdue\sto\sSMTP\sSpam\sBlocking)|(?:Too\smany\sauthentication\sfailures))", @"", @"", @"", "Windows", "SmarterMail", "C:/Program Files/Tomcat/logs/**/*access_log*.txt", @"^(?<ipaddress>[^\s]+)\s.*?\[(?<timestamp>.*?)\].*?((php|md5sum|cgi-bin|joomla).*?\s404\s[0-9]+|\s400\s-)$", @"dd/MMM/yyyy:HH:mm:ss zzzz", @"", @"", "Windows", "Apache", "C:/IPBanCustomLogs/**/*.log", @"(?<timestamp>\d\d\d\d-\d\d-\d\d\s\d\d:\d\d:\d\d\.?\d*Z?,\s)?ipban\sfailed\slogin,\sip\saddress:\s(?<ipaddress>[^,\n]+),\ssource:\s(?<source>[^,\n]+),\suser:\s?(?<username>[^\s,]+)?", @"", @"(?<timestamp>\d\d\d\d-\d\d-\d\d\s\d\d:\d\d:\d\d\.?\d*Z?,\s)?ipban\ssuccess\slogin,\sip\saddress:\s(?<ipaddress>[^,\n]+),\ssource:\s(?<source>[^,\n]+),\suser:\s?(?<username>[^\s,]+)?", @"", "Windows", "IPBanCustom" }; Assert.AreEqual(logFileData.Length / 7, cfg.LogFilesToParse.Count); for (int i = 0; i < logFileData.Length; i += 7) { AssertLogFileToParse(cfg.LogFilesToParse[i / 7], (string)logFileData[i + 1], (string)logFileData[i + 2], maxFileSize, (string)logFileData[i], pingInterval, (string)logFileData[i + 5], (string)logFileData[i + 6], (string)logFileData[i + 3], (string)logFileData[i + 4]); } }
/// <summary> /// Config from ConfigXml /// </summary> public IPBanConfig GetConfig() => config ??= IPBanConfig.LoadFromXml(ConfigXml);