/// <summary> /// Process event viewer XML /// </summary> /// <param name="xml">XML</param> /// <param name="testing">True if testing, false otherwise</param> public void ProcessEventViewerXml(string xml, bool testing = false) { IPBanLog.Write(LogLevel.Information, "Processing xml: {0}", xml); XmlDocument doc = ParseXml(xml); ExtractEventViewerXml(doc, out string ipAddress, out string source, out string userName); if (AddFailedLoginForEventViewerXml(ipAddress, source, userName, doc) && testing) { Console.WriteLine("Found {0}, {1}, {2}", ipAddress, source, userName); } }
private HashSet <WatchedFile> UpdateWatchedFiles() { HashSet <WatchedFile> watchedFilesCopy = new HashSet <WatchedFile>(); try { // read in existing files that match the mask in the directory being watched if (Directory.Exists(directoryToWatch)) { foreach (string file in Directory.EnumerateFiles(directoryToWatch, fileMask, SearchOption.TopDirectoryOnly)) { watchedFilesCopy.Add(new WatchedFile(file, new FileInfo(file).Length)); } } } catch { // nothing to do here, something failed enumerating the directory files } lock (watchedFiles) { // remove files that no longer exist foreach (WatchedFile existing in watchedFiles.ToArray()) { if (!watchedFilesCopy.Contains(existing)) { IPBanLog.Debug("Removing parsed log file {0}", existing.FileName); watchedFiles.Remove(existing); } } // add new files foreach (WatchedFile newFile in watchedFilesCopy) { // add the file, will fail if it already exists if (watchedFiles.Add(newFile)) { IPBanLog.Debug("Adding parsed log file {0}", newFile.FileName); } } // make a copy so we can enumerate outside a lock watchedFilesCopy.Clear(); foreach (WatchedFile file in watchedFiles) { watchedFilesCopy.Add(file); } } return(watchedFilesCopy); }
public Task <bool> AllowIPAddresses(IEnumerable <string> ipAddresses, CancellationToken cancelToken = default) { try { allowedIPAddresses = UpdateRule(allowRuleName, "ACCEPT", ipAddresses, allowedIPAddresses, "ip", allowRuleMaxCount, false, null, cancelToken, out bool result); return(Task.FromResult <bool>(result)); } catch (Exception ex) { IPBanLog.Error(ex); return(Task.FromResult <bool>(false)); } }
public Task <bool> BlockIPAddresses(IEnumerable <string> ipAddresses, CancellationToken cancelToken = default) { try { bannedIPAddresses = UpdateRule(blockRuleName, "DROP", ipAddresses, bannedIPAddresses, "ip", blockRuleMaxCount, false, null, cancelToken, out bool result); return(Task.FromResult(result)); } catch (Exception ex) { IPBanLog.Error(ex); return(Task.FromResult(false)); } }
private int RunProcess(string program, bool requireExitCode, string commandLine, params object[] args) { commandLine = program + " " + string.Format(commandLine, args); commandLine = "-c \"" + commandLine.Replace("\"", "\\\"") + "\""; IPBanLog.Write(LogLevel.Debug, "Running firewall process: /bin/bash {0}", commandLine); Process p = Process.Start("/bin/bash", commandLine); p.WaitForExit(); if (requireExitCode && p.ExitCode != 0) { IPBanLog.Write(LogLevel.Error, "Process {0} {1} had exit code {2}", program, commandLine, p.ExitCode); } return(p.ExitCode); }
/// <summary> /// Update - if the text file path exists, all ip addresses from each line will be unbanned /// </summary> public void Update() { try { if (File.Exists(textFilePath)) { UnbanIPAddresses(File.ReadLines(textFilePath)); File.Delete(textFilePath); } } catch (Exception ex) { IPBanLog.Error(ex); } }
public void UnblockIPAddresses(IEnumerable <string> ipAddresses) { try { lock (policy) { for (int i = 0; ; i += MaxIpAddressesPerRule) { string ruleName = RulePrefix + i.ToString(CultureInfo.InvariantCulture); try { INetFwRule rule = policy.Rules.Item(ruleName); if (rule == null) { // no more rules to check break; } string remoteIPs = rule.RemoteAddresses; foreach (string ipAddress in ipAddresses) { remoteIPs = Regex.Replace(remoteIPs, ipAddress.Replace(".", "\\.") + "\\/[^,]+,?", ",", RegexOptions.IgnoreCase); remoteIPs = remoteIPs.Replace(",,", ","); remoteIPs = remoteIPs.Trim().Trim(','); } // ensure we don't have a block rule with no ip addresses, this will block the entire world (WTF Microsoft)... if (string.IsNullOrWhiteSpace(remoteIPs)) { policy.Rules.Remove(rule.Name); } else { rule.RemoteAddresses = remoteIPs; } } catch { // no more rules to check break; } } } } catch (Exception ex) { IPBanLog.Error(ex); } }
/// <summary> /// Process a line, checking for ip addresses /// </summary> /// <param name="line">Line to process</param> /// <returns>True</returns> protected override bool OnProcessLine(string line) { IPBanLog.Debug("Parsing log file line {0}...", line); IPAddressLogInfo info = IPBanService.GetIPAddressInfoFromRegex(dns, regex, line); if (info.FoundMatch) { info.Source = info.Source ?? Source; IPBanLog.Debug("Log file found match, ip: {0}, user: {1}, source: {2}, count: {3}", info.IPAddress, info.UserName, info.Source, info.Count); failedLogin.AddFailedLogin(info); } else { IPBanLog.Debug("No match for line {0}", line); } return(true); }
public bool BlockIPAddresses(IReadOnlyList <string> ipAddresses) { try { int i; for (i = 0; i < ipAddresses.Count; i += maxIpAddressesPerRule) { CreateBlockRule(ipAddresses, i, maxIpAddressesPerRule); } DeleteRules(i); return(true); } catch (Exception ex) { IPBanLog.Error(ex); return(false); } }
public Task <bool> AllowIPAddresses(IEnumerable <string> ipAddresses, CancellationToken cancelToken = default) { try { List <string> ipAddressesList = new List <string>(); int i = 0; foreach (string ipAddress in ipAddresses) { if (cancelToken.IsCancellationRequested) { throw new OperationCanceledException(); } ipAddressesList.Add(ipAddress); if (ipAddressesList.Count == MaxIpAddressesPerRule) { string remoteIP = CreateRuleStringForIPAddresses(ipAddressesList, i, MaxIpAddressesPerRule); GetOrCreateRule(allowRulePrefix + i.ToString(CultureInfo.InvariantCulture), remoteIP, NET_FW_ACTION_.NET_FW_ACTION_ALLOW); i += MaxIpAddressesPerRule; ipAddressesList.Clear(); } } if (cancelToken.IsCancellationRequested) { throw new OperationCanceledException(); } if (ipAddressesList.Count != 0) { string remoteIP = CreateRuleStringForIPAddresses(ipAddressesList, i, MaxIpAddressesPerRule); GetOrCreateRule(allowRulePrefix + i.ToString(CultureInfo.InvariantCulture), remoteIP, NET_FW_ACTION_.NET_FW_ACTION_ALLOW); i += MaxIpAddressesPerRule; } if (cancelToken.IsCancellationRequested) { throw new OperationCanceledException(); } DeleteRules(allowRulePrefix, i); return(Task.FromResult <bool>(true)); } catch (Exception ex) { IPBanLog.Error(ex); return(Task.FromResult <bool>(false)); } }
public Task <bool> BlockIPAddresses(string ruleNamePrefix, IEnumerable <IPAddressRange> ranges, IEnumerable <PortRange> allowedPorts, CancellationToken cancelToken = default) { if (string.IsNullOrWhiteSpace(ruleNamePrefix)) { return(Task.FromResult(false)); } try { string ruleName = RulePrefix + "_" + ruleNamePrefix + "_0"; UpdateRule(ruleName, "DROP", ranges.Select(r => r.ToCidrString()), null, "net", blockRuleRangesMaxCount, true, allowedPorts, cancelToken, out bool result); return(Task.FromResult(result)); } catch (Exception ex) { IPBanLog.Error(ex); return(Task.FromResult(false)); } }
private static void LoadVersionFromWmiApi() { try { // WMI API sometimes fails to initialize on .NET core on some systems, not sure why... // fall-back to WMI, maybe future .NET core versions will fix the bug using (ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT Caption, Version FROM Win32_OperatingSystem")) { foreach (var result in searcher.Get()) { FriendlyName = result["Caption"] as string; Version = result["Version"] as string; break; } } } catch (Exception ex) { IPBanLog.Error(ex, "Unable to load os version from wmi api"); } }
public Task <bool> BlockIPAddresses(IEnumerable <string> ipAddresses, CancellationToken cancelToken = default) { try { int i = 0; List <string> ipAddressesList = new List <string>(); foreach (string ipAddress in ipAddresses) { if (cancelToken.IsCancellationRequested) { throw new OperationCanceledException(cancelToken); } ipAddressesList.Add(ipAddress); if (ipAddressesList.Count == MaxIpAddressesPerRule) { CreateBlockRule(ipAddressesList, 0, MaxIpAddressesPerRule, RulePrefix + i.ToStringInvariant()); i += MaxIpAddressesPerRule; ipAddressesList.Clear(); } } if (cancelToken.IsCancellationRequested) { throw new OperationCanceledException(cancelToken); } if (ipAddressesList.Count != 0) { CreateBlockRule(ipAddressesList, 0, MaxIpAddressesPerRule, RulePrefix + i.ToStringInvariant()); i += MaxIpAddressesPerRule; } DeleteRules(RulePrefix, i); return(Task.FromResult(true)); } catch (Exception ex) { IPBanLog.Error(ex); return(Task.FromResult(false)); } }
public bool IsIPAddressAllowed(string ipAddress) { try { lock (policy) { string ruleName = RulePrefix + "AllowIPAddresses"; try { INetFwRule rule = policy.Rules.Item(ruleName); return(rule != null && rule.RemoteAddresses.Contains(ipAddress)); } catch { // OK, rule does not exist } } } catch (Exception ex) { IPBanLog.Error(ex); } return(false); }
public bool IsIPAddressBlocked(string ipAddress) { try { lock (policy) { for (int i = 0; ; i += maxIpAddressesPerRule) { string ruleName = RulePrefix + i.ToString(CultureInfo.InvariantCulture); try { INetFwRule rule = policy.Rules.Item(ruleName); if (rule == null) { // no more rules to check break; } else if (rule.RemoteAddresses.Contains(ipAddress)) { return(true); } } catch { // no more rules to check break; } } } } catch (Exception ex) { IPBanLog.Error(ex); } return(false); }
/// <summary> /// Get a firewall ip address, clean and normalize /// </summary> /// <param name="ipAddress">IP Address</param> /// <param name="normalizedIP">The normalized ip ready to go in the firewall or null if invalid ip address</param> /// <returns>True if ip address can go in the firewall, false otherwise</returns> public static bool TryGetFirewallIPAddress(this string ipAddress, out string normalizedIP) { normalizedIP = ipAddress?.Trim(); if (string.IsNullOrWhiteSpace(normalizedIP) || normalizedIP == "0.0.0.0" || normalizedIP == "127.0.0.1" || normalizedIP == "::0" || normalizedIP == "::1" || !IPAddressRange.TryParse(normalizedIP, out IPAddressRange range)) { normalizedIP = null; return(false); } try { normalizedIP = (range.Begin.Equals(range.End) ? range.Begin.ToString() : range.ToCidrString()); } catch (Exception ex) { IPBanLog.Debug("Failed to normalize ip {0}, it is not a single ip or cidr range: {1}", ipAddress, ex); return(false); } return(true); }
static IPBanOS() { try { Version = Environment.OSVersion.VersionString; Description = RuntimeInformation.OSDescription; if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { string tempFile = Path.GetTempFileName(); Process.Start("/bin/bash", "-c \"cat /etc/*release* > " + tempFile + "\"").WaitForExit(); string versionText = File.ReadAllText(tempFile); File.Delete(tempFile); Name = IPBanOS.Linux; FriendlyName = ExtractRegex(versionText, "^(Id|Distrib_Id)=(?<value>.*?)$", string.Empty); if (FriendlyName.Length != 0) { string codeName = ExtractRegex(versionText, "^(Name|Distrib_CodeName)=(?<value>.+)$", string.Empty); if (codeName.Length != 0) { FriendlyName += " - " + codeName; } Version = ExtractRegex(versionText, "^Version_Id=(?<value>.+)$", Version); } } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { Name = IPBanOS.Windows; string tempFile = Path.GetTempFileName(); // .net core WMI has a strange bug where WMI will not initialize on some systems // since this is the only place where WMI is used, we can just work-around it // with the wmic executable, which exists (as of 2018) on all supported Windows. StartProcessAndWait("cmd", "/C wmic path Win32_OperatingSystem get Caption,Version /format:table > \"" + tempFile + "\""); if (File.Exists(tempFile)) { string[] lines = File.ReadAllLines(tempFile); File.Delete(tempFile); if (lines.Length > 1) { int versionIndex = lines[0].IndexOf("Version"); if (versionIndex >= 0) { FriendlyName = lines[1].Substring(0, versionIndex - 1).Trim(); Version = lines[1].Substring(versionIndex).Trim(); } } } else { // fall-back to WMI, maybe future .NET core versions will fix the bug using (ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT Caption, Version FROM Win32_OperatingSystem")) { foreach (var result in searcher.Get()) { FriendlyName = result["Caption"] as string; Version = result["Version"] as string; break; } } } } else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { // TODO: Implement better for MAC Name = IPBanOS.Mac; FriendlyName = "OSX"; } else { Name = IPBanOS.Unknown; FriendlyName = "Unknown"; } } catch (Exception ex) { IPBanLog.Error(ex); } }
private void ExtractEventViewerXml(XmlDocument doc, out string ipAddress, out string source, out string userName) { XmlNode keywordsNode = doc.SelectSingleNode("//Keywords"); string keywordsText = keywordsNode.InnerText; if (keywordsText.StartsWith("0x")) { keywordsText = keywordsText.Substring(2); } ulong keywordsULONG = ulong.Parse(keywordsText, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture); ipAddress = source = userName = null; if (keywordsNode != null) { // we must match on keywords foreach (ExpressionsToBlockGroup group in service.Config.WindowsEventViewerGetGroupsMatchingKeywords(keywordsULONG)) { foreach (ExpressionToBlock expression in group.Expressions) { // find all the nodes, try and get an ip from any of them, all must match XmlNodeList nodes = doc.SelectNodes(expression.XPath); if (nodes.Count == 0) { IPBanLog.Write(LogLevel.Information, "No nodes found for xpath {0}", expression.XPath); ipAddress = null; break; } // if there is a regex, it must match if (string.IsNullOrWhiteSpace(expression.Regex)) { // count as a match, do not modify the ip address if it was already set IPBanLog.Write(LogLevel.Information, "No regex, so counting as a match"); } else { bool foundMatch = false; // try and find an ip from any of the nodes foreach (XmlNode node in nodes) { // if we get a match, stop checking nodes if ((foundMatch = IPBanService.GetIPAddressAndUserNameFromRegex(expression.RegexObject, node.InnerText, ref ipAddress, ref userName))) { break; } } if (!foundMatch) { // match fail, null out ip, we have to match ALL the nodes or we get null ip and do not ban IPBanLog.Write(LogLevel.Information, "Regex {0} did not match any nodes with xpath {1}", expression.Regex, expression.XPath); ipAddress = null; break; } } } if (ipAddress != null) { source = group.Source; break; } ipAddress = source = userName = null; // set null for the next node attempt } } }
private bool GetOrCreateRule(string ruleName, string remoteIPAddresses, NET_FW_ACTION_ action, IEnumerable <PortRange> allowedPorts = null) { remoteIPAddresses = (remoteIPAddresses ?? string.Empty).Trim(); bool emptyIPAddressString = string.IsNullOrWhiteSpace(remoteIPAddresses) || remoteIPAddresses == "*"; bool ruleNeedsToBeAdded = false; lock (policy) { recreateRule: INetFwRule rule = null; try { rule = policy.Rules.Item(ruleName); } catch { // ignore exception, assume does not exist } if (rule == null) { rule = Activator.CreateInstance(ruleType) as INetFwRule; rule.Name = ruleName; rule.Enabled = true; rule.Action = action; rule.Description = "Automatically created by IPBan"; rule.Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN; rule.EdgeTraversal = false; rule.Grouping = "IPBan"; rule.LocalAddresses = "*"; rule.Profiles = int.MaxValue; // all ruleNeedsToBeAdded = true; } // do not ever set an empty string, Windows treats this as * which means everything if (!emptyIPAddressString) { try { PortRange[] allowedPortsArray = (allowedPorts?.ToArray()); if (allowedPortsArray != null && allowedPortsArray.Length != 0) { rule.Protocol = (int)NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_TCP; string localPorts; if (action == NET_FW_ACTION_.NET_FW_ACTION_BLOCK) { localPorts = IPBanFirewallUtility.GetPortRangeStringBlockExcept(allowedPortsArray); } else { localPorts = IPBanFirewallUtility.GetPortRangeStringAllow(allowedPortsArray); } rule.LocalPorts = localPorts; } else { try { rule.Protocol = (int)NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_ANY; } catch { // failed to set protocol to any, we are switching from tcp back to any without ports, the only option is to // recreate the rule if (!ruleNeedsToBeAdded) { policy.Rules.Remove(ruleName); goto recreateRule; } } } rule.RemoteAddresses = remoteIPAddresses; } catch (Exception ex) { // if something failed, do not create the rule emptyIPAddressString = true; IPBanLog.Error(ex); } } if (emptyIPAddressString || string.IsNullOrWhiteSpace(rule.RemoteAddresses) || rule.RemoteAddresses == "*") { // if no ip addresses, remove the rule as it will allow or block everything with an empty RemoteAddresses string try { rule = null; policy.Rules.Remove(ruleName); } catch { } } else if (ruleNeedsToBeAdded) { policy.Rules.Add(rule); } return(rule != null); } }
private IPBanConfig(string xml, IDnsLookup dns) { this.dns = dns; // deserialize with XmlDocument, the .net core Configuration class is quite buggy XmlDocument doc = new XmlDocument(); doc.LoadXml(xml); foreach (XmlNode node in doc.SelectNodes("//appSettings/add")) { appSettings[node.Attributes["key"].Value] = node.Attributes["value"].Value; } GetConfig <int>("FailedLoginAttemptsBeforeBan", ref failedLoginAttemptsBeforeBan); GetConfig <TimeSpan>("BanTime", ref banTime); GetConfig <bool>("ClearBannedIPAddressesOnRestart", ref clearBannedIPAddressesOnRestart); GetConfig <TimeSpan>("ExpireTime", ref expireTime); GetConfig <TimeSpan>("CycleTime", ref cycleTime); GetConfig <TimeSpan>("MinimumTimeBetweenFailedLoginAttempts", ref minimumTimeBetweenFailedLoginAttempts); GetConfig <string>("FirewallRulePrefix", ref firewallRulePrefix); GetConfig <bool>("CreateWhitelistFirewallRule", ref createWhitelistFirewallRule); string whiteListString = GetConfig <string>("Whitelist", string.Empty); string whiteListRegexString = GetConfig <string>("WhitelistRegex", string.Empty); string blacklistString = GetConfig <string>("Blacklist", string.Empty); string blacklistRegexString = GetConfig <string>("BlacklistRegex", string.Empty); PopulateList(whiteList, ref whiteListRegex, whiteListString, whiteListRegexString); PopulateList(blackList, ref blackListRegex, blacklistString, blacklistRegexString); if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { expressions = new XmlSerializer(typeof(ExpressionsToBlock)).Deserialize(new XmlNodeReader(doc.SelectSingleNode("//ExpressionsToBlock"))) as ExpressionsToBlock; if (expressions != null) { foreach (ExpressionsToBlockGroup group in expressions.Groups) { foreach (ExpressionToBlock expression in group.Expressions) { expression.Regex = (expression.Regex ?? string.Empty).Trim(); } } } } else { expressions = new ExpressionsToBlock { Groups = new ExpressionsToBlockGroup[0] }; } try { LogFilesToParse logFilesToParse = new XmlSerializer(typeof(LogFilesToParse)).Deserialize(new XmlNodeReader(doc.SelectSingleNode("//LogFilesToParse"))) as LogFilesToParse; logFiles = (logFilesToParse == null ? new LogFileToParse[0] : logFilesToParse.LogFiles); } catch (Exception ex) { IPBanLog.Error(ex); logFiles = new LogFileToParse[0]; } GetConfig <string>("ProcessToRunOnBan", ref processToRunOnBan); // retrieve firewall configuration string[] firewallTypes = GetConfig <string>("FirewallType", string.Empty).Split(',', StringSplitOptions.RemoveEmptyEntries); foreach (string firewallOSAndType in firewallTypes) { string[] pieces = firewallOSAndType.Split(':'); if (pieces.Length == 2) { osAndFirewallType[pieces[0]] = pieces[1]; } } string userNameWhiteListString = GetConfig <string>("UserNameWhiteList", string.Empty); foreach (string userName in userNameWhiteListString.Split(',')) { string userNameTrimmed = userName.Normalize().Trim(); if (userNameTrimmed.Length > 0) { userNameWhitelist.Add(userNameTrimmed); } } GetConfig <int>("UserNameWhiteListMinimumEditDistance", ref userNameWhitelistMaximumEditDistance); GetConfig <int>("FailedLoginAttemptsBeforeBanUserNameWhitelist", ref failedLoginAttemptsBeforeBanUserNameWhitelist); GetConfig <string>("GetUrlUpdate", ref getUrlUpdate); GetConfig <string>("GetUrlStart", ref getUrlStart); GetConfig <string>("GetUrlStop", ref getUrlStop); GetConfig <string>("GetUrlConfig", ref getUrlConfig); GetConfig <string>("ExternalIPAddressUrl", ref externalIPAddressUrl); }
/// <summary> /// Log current log levels /// </summary> public static void WriteLogLevels(IPBan.LogLevel level = LogLevel.Warn) { IPBanLog.Write(level, "Log levels: {0},{1},{2},{3},{4},{5}", logger.IsFatalEnabled, logger.IsErrorEnabled, logger.IsWarnEnabled, logger.IsInfoEnabled, logger.IsDebugEnabled, logger.IsTraceEnabled); }
private IPAddressLogInfo ExtractEventViewerXml(XmlDocument doc) { XmlNode keywordsNode = doc.SelectSingleNode("//Keywords"); string keywordsText = keywordsNode.InnerText; if (keywordsText.StartsWith("0x")) { keywordsText = keywordsText.Substring(2); } ulong keywordsULONG = ulong.Parse(keywordsText, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture); IPAddressLogInfo info = null; if (keywordsNode != null) { // we must match on keywords foreach (ExpressionsToBlockGroup group in service.Config.WindowsEventViewerGetGroupsMatchingKeywords(keywordsULONG)) { foreach (ExpressionToBlock expression in group.Expressions) { // find all the nodes, try and get an ip from any of them, all must match XmlNodeList nodes = doc.SelectNodes(expression.XPath); if (nodes.Count == 0) { IPBanLog.Info("No nodes found for xpath {0}", expression.XPath); info = null; break; } // if there is a regex, it must match if (string.IsNullOrWhiteSpace(expression.Regex)) { // count as a match, do not modify the ip address if it was already set IPBanLog.Info("No regex, so counting as a match"); } else { info = null; // try and find an ip from any of the nodes foreach (XmlNode node in nodes) { // if we get a match, stop checking nodes info = IPBanService.GetIPAddressInfoFromRegex(service.DnsLookup, expression.RegexObject, node.InnerText); if (info.FoundMatch) { break; } } if (info != null && !info.FoundMatch) { // match fail, null out ip, we have to match ALL the nodes or we get null ip and do not ban IPBanLog.Info("Regex {0} did not match any nodes with xpath {1}", expression.Regex, expression.XPath); info = null; break; } } } if (info != null && info.FoundMatch && info.IPAddress != null) { info.Source = info.Source ?? group.Source; break; } info = null; // set null for next attempt } } return(info); }
static IPBanOS() { try { // start off with built in version info, this is not as detailed or nice as we like, // so we try some other ways to get more detailed information Version = Environment.OSVersion.VersionString; Description = RuntimeInformation.OSDescription; // attempt to get detailed version info if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { string tempFile = Path.GetTempFileName(); Process.Start("/bin/bash", "-c \"cat /etc/*release* > " + tempFile + "\"").WaitForExit(); System.Threading.Tasks.Task.Delay(100); // wait a small bit for file to really be closed string versionText = File.ReadAllText(tempFile).Trim(); File.Delete(tempFile); if (string.IsNullOrWhiteSpace(versionText)) { IPBanLog.Error(new IOException("Unable to load os version from /etc/*release* ...")); } else { Name = IPBanOS.Linux; FriendlyName = ExtractRegex(versionText, "^(Id|Distrib_Id)=(?<value>.*?)$", string.Empty); if (FriendlyName.Length != 0) { string codeName = ExtractRegex(versionText, "^(Name|Distrib_CodeName)=(?<value>.+)$", string.Empty); if (codeName.Length != 0) { FriendlyName += " - " + codeName; } Version = ExtractRegex(versionText, "^Version_Id=(?<value>.+)$", Version); } } } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { Name = IPBanOS.Windows; string tempFile = Path.GetTempFileName(); // .net core WMI has a strange bug where WMI will not initialize on some systems // since this is the only place where WMI is used, we can just work-around it // with the wmic executable, which exists (as of 2018) on all supported Windows. StartProcessAndWait("cmd", "/C wmic path Win32_OperatingSystem get Caption,Version /format:table > \"" + tempFile + "\""); if (File.Exists(tempFile)) { // try up to 10 times to read the file for (int i = 0; i < 10; i++) { try { string[] lines = File.ReadAllLines(tempFile); File.Delete(tempFile); if (lines.Length > 1) { int versionIndex = lines[0].IndexOf("Version"); if (versionIndex >= 0) { FriendlyName = lines[1].Substring(0, versionIndex - 1).Trim(); Version = lines[1].Substring(versionIndex).Trim(); break; } } throw new IOException("Invalid file generated from wmic"); } catch (Exception ex) { if (i < 9) { System.Threading.Tasks.Task.Delay(200).Wait(); } else { IPBanLog.Error(ex, "Unable to load os version using wmic, trying wmi api..."); // last resort, try wmi api LoadVersionFromWmiApi(); } } } } else { // last resort, try wmi api LoadVersionFromWmiApi(); } } else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { // TODO: Implement better for MAC Name = IPBanOS.Mac; FriendlyName = "OSX"; } else { Name = IPBanOS.Unknown; FriendlyName = "Unknown"; } } catch (Exception ex) { IPBanLog.Error(ex); } }
private bool PingFile(WatchedFile file, FileStream fs) { const int maxCountBeforeNewline = 1024; int b; long lastNewlinePos = -1; byte[] bytes; long end = Math.Min(file.LastLength, fs.Length); int countBeforeNewline = 0; fs.Position = file.LastPosition; while (fs.Position < end && countBeforeNewline++ != maxCountBeforeNewline) { // read until last \n is found b = fs.ReadByte(); if (b == '\n') { lastNewlinePos = fs.Position - 1; countBeforeNewline = 0; } } if (countBeforeNewline == maxCountBeforeNewline) { throw new InvalidOperationException("Log file " + this.fileMask + " may not be a plain text new line delimited file"); } if (lastNewlinePos > -1) { // set file position ready for the next read right after the newline fs.Position = file.LastPosition; bytes = new BinaryReader(fs).ReadBytes((int)(lastNewlinePos - fs.Position)); // set position for next ping file.LastPosition = lastNewlinePos + 1; // read text and run regex to find ip addresses to ban string subString = Encoding.UTF8.GetString(bytes); string[] lines = subString.Split('\n'); string ipAddress = null; string userName = null; bool foundOne = false; // find ip and user name from all lines foreach (string line in lines) { IPBanLog.Write(LogLevel.Debug, "Parsing log file line {0}...", line); bool foundMatch = IPBanService.GetIPAddressAndUserNameFromRegex(Regex, line.Trim(), ref ipAddress, ref userName); if (foundMatch) { IPBanLog.Write(LogLevel.Debug, "Found match, ip: {0}, user: {1}", ipAddress, userName); service.AddFailedLogin(ipAddress, Source, userName); foundOne = true; } else { IPBanLog.Write(LogLevel.Debug, "No match!"); } } if (foundOne) { // signal that we have found ip addresses ipEvent.Set(); } } return(maxFileSize > 0 && fs.Length > maxFileSize); }
private void PingFiles() { try { pingTimer.Enabled = false; } catch { } try { // re-open files and read one byte to flush disk cache foreach (WatchedFile file in UpdateWatchedFiles()) { // if file length has changed, ping the file bool delete = false; // ugly hack to force file to flush using (FileStream fs = new FileStream(file.FileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { try { fs.Position = fs.Length - 1; fs.ReadByte(); } catch { } } long len = new FileInfo(file.FileName).Length; // if file has shrunk (deleted and recreated for example) reset positions to 0 if (len < file.LastLength || len < file.LastPosition) { file.LastPosition = 0; } // use file info for length compare to avoid doing a full file open if (len != file.LastLength) { using (FileStream fs = new FileStream(file.FileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { file.LastLength = len; delete = PingFile(file, fs); } } else { IPBanLog.Debug("Watched file {0} length has not changed", file.FileName); } if (delete) { try { File.Delete(file.FileName); } catch { // OK someone else might have it open, in which case we have no chance to delete } } } } catch (Exception ex) { IPBanLog.Error(ex); } try { pingTimer.Enabled = true; } catch { } }
private bool PingFile(WatchedFile file, FileStream fs) { const int maxCountBeforeNewline = 1024; int b; long lastNewlinePos = -1; byte[] bytes; long end = Math.Min(file.LastLength, fs.Length); int countBeforeNewline = 0; fs.Position = file.LastPosition; IPBanLog.Info("Processing watched file {0}, len = {1}, pos = {2}", file.FileName, file.LastLength, file.LastPosition); while (fs.Position < end && countBeforeNewline++ != maxCountBeforeNewline) { // read until last \n is found b = fs.ReadByte(); if (b == '\n') { lastNewlinePos = fs.Position - 1; countBeforeNewline = 0; } } if (countBeforeNewline == maxCountBeforeNewline) { throw new InvalidOperationException("Log file " + this.fileMask + " may not be a plain text new line delimited file"); } if (lastNewlinePos > -1) { // set file position ready for the next read right after the newline fs.Position = file.LastPosition; bytes = new BinaryReader(fs).ReadBytes((int)(lastNewlinePos - fs.Position)); // set position for next ping file.LastPosition = lastNewlinePos + 1; // read text and run regex to find ip addresses to ban string subString = Encoding.UTF8.GetString(bytes); string[] lines = subString.Split('\n'); bool foundOne = false; // find ip and user name from all lines foreach (string line in lines) { string trimmedLine = line.Trim(); IPBanLog.Debug("Parsing log file line {0}...", trimmedLine); IPAddressLogInfo info = IPBanService.GetIPAddressInfoFromRegex(dns, Regex, trimmedLine); if (info.FoundMatch) { info.Source = info.Source ?? Source; IPBanLog.Debug("Log file found match, ip: {0}, user: {1}, source: {2}, count: {3}", info.IPAddress, info.UserName, info.Source, info.Count); failedLogin.AddFailedLogin(info); foundOne = true; } else { IPBanLog.Debug("No match for line {0}", line); } } if (foundOne) { // signal that we have found ip addresses ipEvent.Set(); } } return(maxFileSize > 0 && fs.Length > maxFileSize); }