public IEnumerable <string> EnumerateAllowedIPAddresses() { string tempFile = IPBanOS.GetTempFileName(); try { RunProcess("ipset", true, $"save > \"{tempFile}\""); bool inAllow = true; foreach (string line in File.ReadLines(tempFile)) { string[] pieces = line.Split(' '); if (pieces.Length > 1 && pieces[0].Equals("create", StringComparison.OrdinalIgnoreCase)) { inAllow = (pieces[1].Equals(AllowRuleName)); } else if (inAllow && pieces.Length > 2 && pieces[0] == "add") { yield return(pieces[2]); } } } finally { IPBanExtensionMethods.FileDeleteWithRetry(tempFile); } }
public IEnumerable <IPAddressRange> EnumerateIPAddresses(string ruleNamePrefix = null) { string tempFile = IPBanOS.GetTempFileName(); try { string prefix = RulePrefix + (ruleNamePrefix ?? string.Empty); RunProcess("ipset", true, $"save > \"{tempFile}\""); bool inSet = false; foreach (string line in File.ReadLines(tempFile)) { string[] pieces = line.Split(' '); if (pieces.Length > 1 && pieces[0].Equals("create", StringComparison.OrdinalIgnoreCase)) { inSet = (pieces[1].StartsWith(prefix, StringComparison.OrdinalIgnoreCase)); } else if (inSet && pieces.Length > 2 && pieces[0] == "add") { yield return(IPAddressRange.Parse(pieces[2])); } } } finally { IPBanExtensionMethods.FileDeleteWithRetry(tempFile); } }
public bool DeleteRules(int startIndex = 0) { string scriptFileName = IPBanOS.GetTempFileName(); Directory.CreateDirectory(Path.GetDirectoryName(scriptFileName)); using (StreamWriter writer = File.CreateText(scriptFileName)) { WriteDeleteRules(writer, true); } RunScript(scriptFileName); return(true); }
public bool CreateRules(IReadOnlyList <string> ipAddresses) { string subRuleName; string scriptFileName = IPBanOS.GetTempFileName(); Directory.CreateDirectory(Path.GetDirectoryName(scriptFileName)); using (StreamWriter writer = File.CreateText(scriptFileName)) { writer.WriteLine(fileScriptHeader); WriteDeleteRules(writer, false); for (int i = 0; i < ipAddresses.Count; i += blockSize) { subRuleName = RulePrefix + i.ToString(CultureInfo.InvariantCulture); string ipAddressesArray = string.Join(",", ipAddresses.Skip(i).Take(blockSize)); string line = string.Format(fileScriptAddLine, subRuleName, ipAddressesArray); writer.WriteLine(line); } writer.WriteLine(fileScriptEnd); } RunScript(scriptFileName); return(true); }
/// <summary> /// Run the service /// </summary> /// <param name="requireAdministrator">True to require administrator, false otherwise</param> /// <returns>Exit code</returns> public async Task RunAsync(bool requireAdministrator = true) { if (requireAdministrator) { IPBanExtensionMethods.RequireAdministrator(); } if (args.Length != 0 && (args[0].Equals("info", StringComparison.OrdinalIgnoreCase) || args[0].Equals("-info", StringComparison.OrdinalIgnoreCase))) { IPBanLog.Warn("System info: {0}", IPBanOS.OSString()); } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { await RunWindowsService(args); } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { await RunLinuxService(args); } else { throw new PlatformNotSupportedException(); } }
static IPBanOS() { try { tempFolder = Path.GetTempPath(); if (string.IsNullOrWhiteSpace(tempFolder)) { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { tempFolder = "c:\\temp"; } else { tempFolder = "/tmp"; } } Directory.CreateDirectory(tempFolder); // 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)) { isLinux = true; string tempFile = IPBanOS.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(); IPBanExtensionMethods.FileDeleteWithRetry(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)) { isWindows = true; processVerb = "runas"; Name = IPBanOS.Windows; string tempFile = IPBanOS.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); IPBanExtensionMethods.FileDeleteWithRetry(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("Error determining platform info", ex); } }
/// <summary> /// Initialize and start the service /// </summary> public async Task StartAsync() { if (IsRunning) { return; } try { IsRunning = true; ipDB = new IPBanDB(DatabasePath ?? "ipban.sqlite"); AddWindowsEventViewer(); AddUpdater(new IPBanUnblockIPAddressesUpdater(this, Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "unban.txt"))); AddUpdater(new IPBanBlockIPAddressesUpdater(this, Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ban.txt"))); AssemblyVersion = IPBanService.IPBanAssembly.GetName().Version.ToString(); await ReadAppSettings(); UpdateBannedIPAddressesOnStart(); IPBanDelegate?.Start(this); if (!ManualCycle) { if (RunFirstCycleRightAway) { await RunCycle(); // run one cycle right away } cycleTimer = new System.Timers.Timer(Config.CycleTime.TotalMilliseconds); cycleTimer.Elapsed += async(sender, e) => await CycleTimerElapsed(sender, e); cycleTimer.Start(); } IPBanLog.Warn("IPBan {0} service started and initialized. Operating System: {1}", IPBanOS.Name, IPBanOS.OSString()); IPBanLog.WriteLogLevels(); } catch (Exception ex) { IPBanLog.Error("Critical error in IPBanService.Start", ex); } }
// deleteRule will drop the rule and matching set before creating the rule and set, use this is you don't care to update the rule and set in place protected bool UpdateRuleDelta(string ruleName, string action, IEnumerable <IPBanFirewallIPAddressDelta> deltas, string hashType, int maxCount, bool deleteRule, IEnumerable <PortRange> allowPorts, CancellationToken cancelToken) { string ipFileTemp = IPBanOS.GetTempFileName(); try { // add and remove the appropriate ip addresses from the set using (StreamWriter writer = File.CreateText(ipFileTemp)) { if (cancelToken.IsCancellationRequested) { throw new OperationCanceledException(cancelToken); } writer.WriteLine($"create {ruleName} hash:{hashType} family {INetFamily} hashsize {hashSize} maxelem {maxCount} -exist"); foreach (IPBanFirewallIPAddressDelta delta in deltas) { if (cancelToken.IsCancellationRequested) { throw new OperationCanceledException(cancelToken); } if (IPAddressRange.TryParse(delta.IPAddress, out IPAddressRange range) && range.Begin.AddressFamily == addressFamily && range.End.AddressFamily == addressFamily) { try { if (delta.Added) { if (range.Begin.Equals(range.End)) { writer.WriteLine($"add {ruleName} {range.Begin} -exist"); } else { writer.WriteLine($"add {ruleName} {range.ToCidrString()} -exist"); } } else { if (range.Begin.Equals(range.End)) { writer.WriteLine($"del {ruleName} {range.Begin} -exist"); } else { writer.WriteLine($"del {ruleName} {range.ToCidrString()} -exist"); } } } catch { // ignore invalid cidr ranges } } } } if (cancelToken.IsCancellationRequested) { throw new OperationCanceledException(cancelToken); } else { // restore the deltas into the existing set bool result = (RunProcess("ipset", true, $"restore < \"{ipFileTemp}\"") == 0); CreateOrUpdateRule(ruleName, action, hashType, maxCount, allowPorts, cancelToken); return(result); } } finally { IPBanExtensionMethods.FileDeleteWithRetry(ipFileTemp); } }