private void UpdateLogFiles(IPBanConfig newConfig) { // remove existing log files that are no longer in config foreach (IPBanLogFileScanner file in logFilesToParse.ToArray()) { if (newConfig.LogFilesToParse.FirstOrDefault(f => f.PathsAndMasks.Contains(file.PathAndMask)) is null) { file.Dispose(); logFilesToParse.Remove(file); } } foreach (IPBanLogFileToParse newFile in newConfig.LogFilesToParse) { string[] pathsAndMasks = newFile.PathsAndMasks; for (int i = 0; i < pathsAndMasks.Length; i++) { string pathAndMask = pathsAndMasks[i]; if (!string.IsNullOrWhiteSpace(pathAndMask)) { // if we don't have this log file and the platform matches, add it bool noMatchingLogFile = logFilesToParse.FirstOrDefault(f => f.PathAndMask == pathAndMask) is null; bool platformMatches = !string.IsNullOrWhiteSpace(newFile.PlatformRegex) && Regex.IsMatch(OSUtility.Description, newFile.PlatformRegex.ToString().Trim(), RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); if (noMatchingLogFile && platformMatches) { // log files use a timer internally and do not need to be updated regularly IPBanIPAddressLogFileScannerOptions options = new IPBanIPAddressLogFileScannerOptions { Dns = service.DnsLookup, LoginHandler = service, MaxFileSizeBytes = newFile.MaxFileSize, PathAndMask = pathAndMask, PingIntervalMilliseconds = (service.ManualCycle ? 0 : newFile.PingInterval), RegexFailure = newFile.FailedLoginRegex, RegexSuccess = newFile.SuccessfulLoginRegex, RegexFailureTimestampFormat = newFile.FailedLoginRegexTimestampFormat, RegexSuccessTimestampFormat = newFile.SuccessfulLoginRegexTimestampFormat, Source = newFile.Source, FailedLoginThreshold = newFile.FailedLoginThreshold }; IPBanLogFileScanner scanner = new IPBanLogFileScanner(options); logFilesToParse.Add(scanner); Logger.Info("Adding log file to parse: {0}", pathAndMask); } else { Logger.Trace("Ignoring log file path {0}, regex: {1}, no matching file: {2}, platform match: {3}", pathAndMask, newFile.PlatformRegex, noMatchingLogFile, platformMatches); } } } } }
private void UpdateLogFiles(IPBanConfig newConfig) { // remove existing log files that are no longer in config foreach (LogFileScanner file in logFilesToParse.ToArray()) { if (newConfig.LogFilesToParse.FirstOrDefault(f => f.PathsAndMasks.Contains(file.PathAndMask)) is null) { file.Dispose(); logFilesToParse.Remove(file); } } foreach (IPBanLogFileToParse newFile in newConfig.LogFilesToParse) { string[] pathsAndMasks = newFile.PathAndMask.Split('\n'); for (int i = 0; i < pathsAndMasks.Length; i++) { string pathAndMask = pathsAndMasks[i].Trim(); if (pathAndMask.Length != 0) { // if we don't have this log file and the platform matches, add it if (logFilesToParse.FirstOrDefault(f => f.PathAndMask == pathAndMask) is null && !string.IsNullOrWhiteSpace(newFile.PlatformRegex) && Regex.IsMatch(OSUtility.Description, newFile.PlatformRegex.ToString().Trim(), RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)) { // log files use a timer internally and do not need to be updated regularly IPBanIPAddressLogFileScannerOptions options = new IPBanIPAddressLogFileScannerOptions { Dns = DnsLookup, LoginHandler = this, MaxFileSizeBytes = newFile.MaxFileSize, PathAndMask = pathAndMask, PingIntervalMilliseconds = newFile.PingInterval, Recursive = newFile.Recursive, RegexFailure = newFile.FailedLoginRegex, RegexSuccess = newFile.SuccessfulLoginRegex, RegexFailureTimestampFormat = newFile.FailedLoginRegexTimestampFormat, RegexSuccessTimestampFormat = newFile.SuccessfulLoginRegexTimestampFormat, Source = newFile.Source }; LogFileScanner scanner = new IPBanIPAddressLogFileScanner(options); logFilesToParse.Add(scanner); Logger.Debug("Adding log file to parse: {0}", pathAndMask); } else { Logger.Debug("Ignoring log file path {0}, regex: {1}", pathAndMask, newFile.PlatformRegex); } } } }
internal async Task UpdateConfiguration() { try { ConfigFilePath = (!File.Exists(ConfigFilePath) ? Path.Combine(AppContext.BaseDirectory, IPBanService.ConfigFileName) : ConfigFilePath); string newXml = await ConfigReaderWriter.CheckForConfigChange(); if (!string.IsNullOrWhiteSpace(newXml)) { IPBanConfig oldConfig = Config; IPBanConfig newConfig = IPBanConfig.LoadFromXml(newXml, DnsLookup); ConfigChanged?.Invoke(newConfig); whitelistChanged = (Config is null || Config.Whitelist != newConfig.Whitelist || Config.WhitelistRegex != newConfig.WhitelistRegex); Config = newConfig; LoadFirewall(oldConfig); ParseAndAddUriFirewallRules(newConfig); Logger.Info("Config file changed"); } } catch (Exception ex) { Logger.Error(ex); } if (Config is null) { throw new ApplicationException("Configuration failed to load, make sure to check for XML errors or unblock all the files."); } if (Firewall is null) { throw new ApplicationException("Firewall failed to load, check that your firewall is enabled and setup in configuration properly"); } // set or unset default banned ip address handler based on config if (Config.UseDefaultBannedIPAddressHandler && BannedIPAddressHandler is null) { BannedIPAddressHandler = new DefaultBannedIPAddressHandler(); } else if (!Config.UseDefaultBannedIPAddressHandler && BannedIPAddressHandler != null && BannedIPAddressHandler is DefaultBannedIPAddressHandler) { BannedIPAddressHandler = NullBannedIPAddressHandler.Instance; } // will only execute once UpdateBannedIPAddressesOnStart(); // will only execute once SetupWindowsEventViewer(); }
private void ParseAndAddUriFirewallRules(IPBanConfig newConfig) { List <IPBanUriFirewallRule> toRemove = new List <IPBanUriFirewallRule>(updaters.Where(u => u is IPBanUriFirewallRule).Select(u => u as IPBanUriFirewallRule)); using StringReader reader = new StringReader(newConfig.FirewallUriRules); string line; while ((line = reader.ReadLine()) != null) { line = line.Trim(); string[] pieces = line.Split(','); if (pieces.Length == 3) { if (TimeSpan.TryParse(pieces[1], out TimeSpan interval)) { if (Uri.TryCreate(pieces[2], UriKind.Absolute, out Uri uri)) { string rulePrefix = pieces[0]; IPBanUriFirewallRule newRule = new IPBanUriFirewallRule(Firewall, this, RequestMaker, rulePrefix, interval, uri); if (updaters.Where(u => u.Equals(newRule)).FirstOrDefault() is IPBanUriFirewallRule existingRule) { // exact duplicate rule, do nothing toRemove.Remove(existingRule); } else { // new rule, add it updaters.Add(newRule); } } else { Logger.Warn("Invalid uri format in uri firewall rule {0}", line); } } else { Logger.Warn("Invalid timestamp format in uri firewall rule {0}", line); } } } // remove any left-over rules that were not in the new config foreach (IPBanUriFirewallRule updater in toRemove.ToArray()) { updater.DeleteRule(); RemoveUpdater(updater); } }
internal async Task UpdateConfiguration() { try { ConfigFilePath = (!File.Exists(ConfigFilePath) ? Path.Combine(AppContext.BaseDirectory, IPBanConfig.DefaultFileName) : ConfigFilePath); var configChange = await ConfigReaderWriter.CheckForConfigChange(); if (!string.IsNullOrWhiteSpace(configChange.Item1)) { IPBanConfig oldConfig = Config; IPBanConfig newConfig = IPBanConfig.LoadFromXml(configChange.Item1, DnsLookup, DnsList, RequestMaker); ConfigChanged?.Invoke(newConfig); whitelistChanged = (Config is null || Config.Whitelist != newConfig.Whitelist || Config.WhitelistRegex != newConfig.WhitelistRegex); Config = newConfig; LoadFirewall(oldConfig); ParseAndAddUriFirewallRules(newConfig); // if the config change was not a force refresh with no actual config values changed, log it if (!configChange.Item2) { Logger.Info("Config file changed"); } } } catch (Exception ex) { Logger.Error(ex); } if (Config is null) { throw new ApplicationException("Configuration failed to load, make sure to check for XML errors or unblock all the files."); } if (Firewall is null) { throw new ApplicationException("Firewall failed to load, check that your firewall is enabled and setup in configuration properly"); } // set or unset default banned ip address handler based on config if (Config.UseDefaultBannedIPAddressHandler && BannedIPAddressHandler is null) { BannedIPAddressHandler = new DefaultBannedIPAddressHandler(); } else if (!Config.UseDefaultBannedIPAddressHandler && BannedIPAddressHandler != null && BannedIPAddressHandler is DefaultBannedIPAddressHandler) { BannedIPAddressHandler = NullBannedIPAddressHandler.Instance; } }
/// <summary> /// Create a log file scanner /// </summary> /// <param name="options">Options</param> public IPBanLogFileScanner(IPBanIPAddressLogFileScannerOptions options) : base(options.PathAndMask, options.MaxFileSizeBytes, options.PingIntervalMilliseconds) { options.ThrowIfNull(nameof(options)); options.LoginHandler.ThrowIfNull(nameof(options.LoginHandler)); options.Dns.ThrowIfNull(nameof(options.Dns)); Source = options.Source; this.loginHandler = options.LoginHandler; this.dns = options.Dns; this.regexFailure = IPBanConfig.ParseRegex(options.RegexFailure, true); this.regexFailureTimestampFormat = options.RegexFailureTimestampFormat; this.regexSuccess = IPBanConfig.ParseRegex(options.RegexSuccess, true); this.regexSuccessTimestampFormat = options.RegexSuccessTimestampFormat; }
/// <summary> /// Create a log file scanner /// </summary> /// <param name="loginHandler">Interface for handling logins</param> /// <param name="dns">Interface for dns lookup</param> /// <param name="source">The source, i.e. SSH or SMTP, etc.</param> /// <param name="pathAndMask">File path and mask (i.e. /var/log/auth*.log)</param> /// <param name="recursive">Whether to parse all sub directories of path and mask recursively</param> /// <param name="regexFailure">Regex to parse file lines to pull out failed login ipaddress and username</param> /// <param name="regexSuccess">Regex to parse file lines to pull out successful login ipaddress and username</param> /// <param name="maxFileSizeBytes">Max size of file (in bytes) before it is deleted or 0 for unlimited</param> /// <param name="pingIntervalMilliseconds">Ping interval in milliseconds, less than 1 for manual ping required</param> public IPBanIPAddressLogFileScanner ( IIPAddressEventHandler loginHandler, IDnsLookup dns, string source, string pathAndMask, bool recursive, string regexFailure, string regexSuccess, long maxFileSizeBytes = 0, int pingIntervalMilliseconds = 0 ) : base(pathAndMask, recursive, maxFileSizeBytes, pingIntervalMilliseconds) { loginHandler.ThrowIfNull(nameof(loginHandler)); dns.ThrowIfNull(nameof(dns)); Source = source; this.loginHandler = loginHandler; this.dns = dns; this.regexFailure = IPBanConfig.ParseRegex(regexFailure); this.regexSuccess = IPBanConfig.ParseRegex(regexSuccess); }
/// <summary> /// Check if an ip address range is whitelisted /// </summary> /// <param name="range">Range</param> /// <returns>True if whitelisted, false otherwise</returns> public bool IsWhitelisted(IPAddressRange range) { IPBanConfig config = Config; return(config != null && Config.IsWhitelisted(range)); }
/// <summary> /// Check if an entry is whitelisted /// </summary> /// <param name="entry">Entry</param> /// <returns>True if whitelisted, false otherwise</returns> public bool IsWhitelisted(string entry) { IPBanConfig config = Config; return(config != null && config.IsWhitelisted(entry)); }
/// <inheritdoc /> public IIPBanFirewall CreateFirewall(IPBanConfig config, IIPBanFirewall previousFirewall) { return(IPBanFirewallUtility.CreateFirewall(config.FirewallRulePrefix, previousFirewall)); }
private void LoadFirewall(IPBanConfig oldConfig) { IIPBanFirewall existing = Firewall; Firewall = FirewallCreator.CreateFirewall(Config, Firewall); if (existing != Firewall) { AddUpdater(Firewall); Logger.Warn("Loaded firewall type {0}", Firewall.GetType()); if (existing != null) { RemoveUpdater(existing); // transfer banned ip to new firewall Firewall.BlockIPAddresses(null, ipDB.EnumerateBannedIPAddresses()).Sync(); } } if (oldConfig is null) { // clear out all previous custom rules foreach (string rule in Firewall.GetRuleNames(Firewall.RulePrefix + "EXTRA_").ToArray()) { Firewall.DeleteRule(rule); } } else { // check for updated / new / removed block rules List <string> deleteList = new List <string>(oldConfig.ExtraRules.Select(r => r.Name)); // cleanup rules that are no longer in the config foreach (string newRule in Config.ExtraRules.Select(r => r.Name)) { deleteList.Remove(newRule); } foreach (string rule in deleteList) { foreach (string ruleName in Firewall.GetRuleNames(rule).ToArray()) { Firewall.DeleteRule(ruleName); } } } // ensure firewall is cleared out if needed - will only execute once UpdateBannedIPAddressesOnStart(); // ensure windows event viewer is setup if needed - will only execute once SetupWindowsEventViewer(); // add/update global rules Firewall.AllowIPAddresses("GlobalWhitelist", Config.Whitelist); Firewall.BlockIPAddresses("GlobalBlacklist", Config.BlackList); // add/update user specified rules foreach (IPBanFirewallRule rule in Config.ExtraRules) { if (rule.Block) { Firewall.BlockIPAddresses(rule.Name, rule.IPAddressRanges, rule.AllowPortRanges); } else { Firewall.AllowIPAddresses(rule.Name, rule.IPAddressRanges, rule.AllowPortRanges); } } }
/// <summary> /// Test a log file /// </summary> /// <param name="fileName">Log file</param> public static void RunLogFileTest(string fileName, string regexFailureFile, string regexFailureTimestampFormat, string regexSuccessFile, string regexSuccessTimestampFormat) { IPBanLogFileScanner scanner = new(new() { Dns = new DefaultDnsLookup(), FailedLoginThreshold = 3, FailedLogLevel = LogLevel.Warning, LoginHandler = new LogFileWriter(), MaxFileSizeBytes = 0, PathAndMask = fileName.Trim(), PingIntervalMilliseconds = 0, RegexFailure = (File.Exists(regexFailureFile) && regexFailureFile.Length > 2 ? IPBanConfig.ParseRegex(File.ReadAllText(regexFailureFile)) : null), RegexFailureTimestampFormat = regexFailureTimestampFormat.Trim('.'), RegexSuccess = (File.Exists(regexSuccessFile) && regexSuccessFile.Length > 2 ? IPBanConfig.ParseRegex(File.ReadAllText(regexSuccessFile)) : null), RegexSuccessTimestampFormat = regexSuccessTimestampFormat.Trim('.'), Source = "test", SuccessfulLogLevel = LogLevel.Warning }); // start with empty file File.Move(fileName, fileName + ".temp"); File.WriteAllText(fileName, string.Empty); // read the empty file scanner.ProcessFiles(); // get rid of the empty file File.Delete(fileName); // put the full file back File.Move(fileName + ".temp", fileName); // now the scanner will process the entire file scanner.ProcessFiles(); }
/// <inheritdoc /> public IIPBanFirewall CreateFirewall(System.Collections.Generic.IReadOnlyCollection <Type> allTypes, IPBanConfig config, IIPBanFirewall previousFirewall) { return(IPBanFirewallUtility.CreateFirewall(allTypes, config.FirewallRulePrefix, previousFirewall)); }