private void AddBannedIPAddress(string ipAddress, string source, string userName, List <IPAddressLogEvent> bannedIpAddresses, DateTime startBanDate, bool configBlacklisted, int counter, string extraInfo, object transaction, bool external) { // never ban whitelisted ip addresses if (IsWhitelisted(ipAddress)) { Logger.Info("Ignoring ban request for whitelisted ip address {0}", ipAddress); return; } TimeSpan[] banTimes = Config.BanTimes; TimeSpan banTime = banTimes.First(); DateTime banEndDate = startBanDate + banTime; // if we have an ip in the database, use the ban time to move to the next ban slot in the list of ban times // if ban times only has one entry, do not do this if (banTimes.Length > 1 && ipDB.TryGetIPAddress(ipAddress, out IPBanDB.IPAddressEntry ipEntry, transaction) && ipEntry.BanStartDate != null && ipEntry.BanEndDate != null) { // find the next ban time in the array banTime = ipEntry.BanEndDate.Value - ipEntry.BanStartDate.Value; for (int i = 0; i < banTimes.Length; i++) { if (banTime < banTimes[i]) { // ban for next timespan banTime = banTimes[i]; banEndDate = startBanDate + banTime; Logger.Info("Moving to next ban duration {0} at index {1} for ip {1}", banTimes[i], i, ipAddress); break; } } } int adjustedCount = (counter <= 0 ? Config.FailedLoginAttemptsBeforeBan : counter); bannedIpAddresses?.Add(new IPAddressLogEvent(ipAddress, userName, source, adjustedCount, IPAddressEventType.Blocked)); if (ipDB.SetBanDates(ipAddress, startBanDate, banEndDate, UtcNow, transaction)) { firewallNeedsBlockedIPAddressesUpdate = true; } Logger.Warn(startBanDate, "Banning ip address: {0}, user name: {1}, config black listed: {2}, count: {3}, extra info: {4}, duration: {5}", ipAddress, userName, configBlacklisted, counter, extraInfo, banTime); // if this is a delegate callback (counter of 0), exit out - we don't want to run handlers or processes for shared banned ip addresses if (counter <= 0) { return; } else if (BannedIPAddressHandler != null && System.Net.IPAddress.TryParse(ipAddress, out System.Net.IPAddress ipAddressObj) && !ipAddressObj.IsInternal()) { try { ExecuteTask(BannedIPAddressHandler.HandleBannedIPAddress(ipAddress, source, userName, OSName, OSVersion, AssemblyVersion, RequestMaker)); } catch { // eat exception, delicious } } if (IPBanDelegate != null && !external) { try { ExecuteTask(IPBanDelegate.IPAddressBanned(ipAddress, source, userName, MachineGuid, OSName, OSVersion, UtcNow, true)); } catch (Exception ex) { Logger.Info("Error calling ipban delegate with banned ip address: " + ex.ToString()); } } }
private async Task ProcessPendingFailedLogins(IReadOnlyList <IPAddressLogEvent> ipAddresses) { List <IPAddressLogEvent> bannedIpAddresses = new List <IPAddressLogEvent>(); object transaction = BeginTransaction(); try { foreach (IPAddressLogEvent failedLogin in ipAddresses) { try { string ipAddress = failedLogin.IPAddress; string userName = failedLogin.UserName; string source = failedLogin.Source; if (IsWhitelisted(ipAddress)) { Logger.Warn("Login failure, ignoring whitelisted ip address {0}, {1}, {2}", ipAddress, userName, source); } else { int maxFailedLoginAttempts; if (Config.IsWhitelisted(userName)) { maxFailedLoginAttempts = Config.FailedLoginAttemptsBeforeBanUserNameWhitelist; } else { // see if there is an override for max failed login attempts maxFailedLoginAttempts = (failedLogin.FailedLoginThreshold > 0 ? failedLogin.FailedLoginThreshold : Config.FailedLoginAttemptsBeforeBan); } DateTime now = failedLogin.Timestamp; // check for the target user name for additional blacklisting checks bool ipBlacklisted = Config.IsBlackListed(ipAddress); bool userBlacklisted = (ipBlacklisted ? false : Config.IsBlackListed(userName)); bool userFailsWhitelistRegex = (userBlacklisted ? false : Config.UserNameFailsUserNameWhitelistRegex(userName)); bool editDistanceBlacklisted = (ipBlacklisted || userBlacklisted || userFailsWhitelistRegex ? false : !Config.IsUserNameWithinMaximumEditDistanceOfUserNameWhitelist(userName)); bool configBlacklisted = ipBlacklisted || userBlacklisted || userFailsWhitelistRegex || editDistanceBlacklisted; // if the event came in with a count of 0 that means it is an automatic ban int incrementCount = (failedLogin.Count < 1 ? maxFailedLoginAttempts : failedLogin.Count); int newCount = ipDB.IncrementFailedLoginCount(ipAddress, userName, source, UtcNow, incrementCount, transaction); Logger.Warn(now, "Login failure: {0}, {1}, {2}, {3}", ipAddress, userName, source, newCount); // if the ip address is black listed or the ip address has reached the maximum failed login attempts before ban, ban the ip address if (configBlacklisted || newCount >= maxFailedLoginAttempts) { Logger.Info("IP blacklisted: {0}, user name blacklisted: {1}, fails user name white list regex: {2}, user name edit distance blacklisted: {3}", ipBlacklisted, userBlacklisted, userFailsWhitelistRegex, editDistanceBlacklisted); if (ipDB.TryGetIPAddressState(ipAddress, out IPBanDB.IPAddressState? state, transaction) && (state.Value == IPBanDB.IPAddressState.Active || state.Value == IPBanDB.IPAddressState.AddPending)) { Logger.Warn(now, "IP {0}, {1}, {2} ban pending.", ipAddress, userName, source); } else { Logger.Debug("Failed login count {0} >= ban count {1}{2}", newCount, maxFailedLoginAttempts, (configBlacklisted ? " config blacklisted" : string.Empty)); // if delegate and non-zero count, forward on - count of 0 means it was from external source, like a delegate if (IPBanDelegate != null && !failedLogin.External) { await IPBanDelegate.LoginAttemptFailed(ipAddress, source, userName, MachineGuid, OSName, OSVersion, UtcNow); } AddBannedIPAddress(ipAddress, source, userName, bannedIpAddresses, now, configBlacklisted, newCount, string.Empty, transaction, failedLogin.External); } } else { Logger.Debug("Failed login count {0} <= ban count {1}", newCount, maxFailedLoginAttempts); if (OSUtility.UserIsActive(userName)) { Logger.Warn("Login failed for known active user {0}", userName); } // if delegate and non-zero count, forward on - count of 0 means it was from external source, like a delegate if (IPBanDelegate != null && !failedLogin.External) { await IPBanDelegate.LoginAttemptFailed(ipAddress, source, userName, MachineGuid, OSName, OSVersion, UtcNow); } } } } catch (Exception ex) { Logger.Error(ex); } } CommitTransaction(transaction); ExecuteExternalProcessForBannedIPAddresses(bannedIpAddresses); } catch (Exception ex) { RollbackTransaction(transaction); Logger.Error(ex); } }