Esempio n. 1
0
 public virtual Task <bool> AllowIPAddresses(IEnumerable <string> ipAddresses, CancellationToken cancelToken = default)
 {
     try
     {
         return(Task.FromResult(UpdateRule(AllowRuleName, "ACCEPT", ipAddresses, hashTypeSingleIP, allowRuleMaxCount, null, cancelToken)));
     }
     catch (Exception ex)
     {
         IPBanLog.Error(ex);
         return(Task.FromResult(false));
     }
 }
Esempio n. 2
0
 /// <summary>
 /// Get a value from configuration manager app settings
 /// </summary>
 /// <typeparam name="T">Type of value to get</typeparam>
 /// <param name="key">Key</param>
 /// <param name="defaultValue">Default value if null or not found</param>
 /// <returns>Value</returns>
 public T GetConfig <T>(string key, T defaultValue = default)
 {
     try
     {
         var converter = TypeDescriptor.GetConverter(typeof(T));
         return((T)converter.ConvertFromInvariantString(appSettings[key]));
     }
     catch (Exception ex)
     {
         IPBanLog.Error(ex, "Error deserializing appSettings key {0}", key);
         return(defaultValue);
     }
 }
Esempio n. 3
0
 public virtual Task <bool> AllowIPAddresses(string ruleNamePrefix, IEnumerable <IPAddressRange> ipAddresses, IEnumerable <PortRange> allowedPorts = null, CancellationToken cancelToken = default)
 {
     try
     {
         ruleNamePrefix.ThrowIfNullOrEmpty();
         return(Task.FromResult(UpdateRule(RulePrefix + ruleNamePrefix, "ACCEPT", ipAddresses.Select(r => r.ToCidrString()), hashTypeCidrMask, blockRuleMaxCount, allowedPorts, cancelToken)));
     }
     catch (Exception ex)
     {
         IPBanLog.Error(ex);
         return(Task.FromResult(false));
     }
 }
Esempio n. 4
0
 public virtual Task <bool> BlockIPAddressesDelta(string ruleNamePrefix, IEnumerable <IPBanFirewallIPAddressDelta> deltas, IEnumerable <PortRange> allowedPorts = null, CancellationToken cancelToken = default)
 {
     try
     {
         string ruleName = (string.IsNullOrWhiteSpace(ruleNamePrefix) ? BlockRuleName : RulePrefix + ruleNamePrefix);
         return(Task.FromResult(UpdateRuleDelta(ruleName, "DROP", deltas, hashTypeSingleIP, blockRuleMaxCount, false, allowedPorts, cancelToken)));
     }
     catch (Exception ex)
     {
         IPBanLog.Error(ex);
         return(Task.FromResult(false));
     }
 }
Esempio n. 5
0
        /// <summary>
        /// Easy way to execute processes. If the process has not finished after timeoutMilliseconds, it is forced killed.
        /// </summary>
        /// <param name="timeoutMilliseconds">Timeout in milliseconds</param>
        /// <param name="program">Program to run</param>
        /// <param name="args">Arguments</param>
        /// <param name="allowedExitCodes">Allowed exit codes, if null or empty it is not checked, otherwise a mismatch will throw an exception.</param>
        /// <returns>Output</returns>
        /// <exception cref="ApplicationException">Exit code did not match allowed exit codes</exception>
        public static string StartProcessAndWait(int timeoutMilliseconds, string program, string args, params int[] allowedExitCodes)
        {
            IPBanLog.Info($"Executing process {program} {args}...");

            var process = new Process
            {
                StartInfo = new ProcessStartInfo(program, args)
                {
                    CreateNoWindow         = true,
                    UseShellExecute        = false,
                    WindowStyle            = ProcessWindowStyle.Hidden,
                    RedirectStandardOutput = true,
                    RedirectStandardError  = true,
                    Verb = processVerb
                }
            };
            StringBuilder output = new StringBuilder();

            process.OutputDataReceived += (object sender, DataReceivedEventArgs e) =>
            {
                lock (output)
                {
                    output.Append("[OUT]: ");
                    output.AppendLine(e.Data);
                }
            };
            process.ErrorDataReceived += (object sender, DataReceivedEventArgs e) =>
            {
                lock (output)
                {
                    output.Append("[ERR]: ");
                    output.AppendLine(e.Data);
                }
            };
            process.Start();
            process.BeginOutputReadLine();
            process.BeginErrorReadLine();
            if (!process.WaitForExit(timeoutMilliseconds))
            {
                lock (output)
                {
                    output.Append("[ERR]: Terminating process due to 60 second timeout");
                }
                process.Kill();
            }
            if (allowedExitCodes.Length != 0 && Array.IndexOf(allowedExitCodes, process.ExitCode) < 0)
            {
                throw new ApplicationException($"Program {program} {args}: failed with exit code {process.ExitCode}, output: {output}");
            }
            return(output.ToString());
        }
Esempio n. 6
0
 public static async Task MainService(string[] args, Func <string[], Task> start, Action stop, bool requireAdministrator = true)
 {
     try
     {
         using (IPBanServiceRunner runner = new IPBanServiceRunner(args, start, stop))
         {
             await runner.RunAsync(requireAdministrator);
         }
     }
     catch (Exception ex)
     {
         IPBanExtensionMethods.FileWriteAllTextWithRetry(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "startup_fail.txt"), ex.ToString());
         IPBanLog.Fatal("Fatal error starting service", ex);
     }
 }
Esempio n. 7
0
 /// <summary>
 /// Set a field / variable from configuration manager app settings. If null or not found, nothing is changed.
 /// </summary>
 /// <typeparam name="T">Type of value to set</typeparam>
 /// <param name="key">Key</param>
 /// <param name="value">Value</param>
 public void GetConfig <T>(string key, ref T value)
 {
     try
     {
         var converter = TypeDescriptor.GetConverter(typeof(T));
         if (appSettings.ContainsKey(key))
         {
             value = (T)converter.ConvertFromInvariantString(appSettings[key]);
         }
     }
     catch (Exception ex)
     {
         IPBanLog.Error(ex, "Error deserializing appSettings key {0}", key);
     }
 }
Esempio n. 8
0
 protected override void OnStart(string[] args)
 {
     base.OnStart(args);
     Task.Run(async() =>
     {
         try
         {
             await runner.start.Invoke(args);
         }
         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);
            bool result = ParseRegex(regexFailure, line, false);

            if (!result)
            {
                result = ParseRegex(regexSuccess, line, true);
                if (!result)
                {
                    IPBanLog.Debug("No match for line {0}", line);
                }
            }
            return(true);
        }
 /// <summary>
 /// Update - if the text file path exists, all ip addresses from each line will be unbanned
 /// </summary>
 public async Task Update()
 {
     try
     {
         if (File.Exists(textFilePath))
         {
             string[] lines = (await File.ReadAllLinesAsync(textFilePath)).Where(l => IPAddress.TryParse(l, out _)).ToArray();
             IPBanLog.Warn("Queueing {0} ip addresses to unban from {1} file", lines.Length, textFilePath);
             UnblockIPAddresses(lines);
             IPBanExtensionMethods.FileDeleteWithRetry(textFilePath);
         }
     }
     catch (Exception ex)
     {
         IPBanLog.Error(ex);
     }
 }
Esempio n. 11
0
        protected override void OnInitialize()
        {
            base.OnInitialize();
            IPBanLog.Info("Initializing IPBan database at {0}", ConnectionString);
            ExecuteNonQuery("PRAGMA auto_vacuum = INCREMENTAL;");
            ExecuteNonQuery("PRAGMA journal_mode = WAL;");
            ExecuteNonQuery("CREATE TABLE IF NOT EXISTS IPAddresses (IPAddress VARBINARY(16) NOT NULL, IPAddressText VARCHAR(64) NOT NULL, LastFailedLogin BIGINT NOT NULL, FailedLoginCount BIGINT NOT NULL, BanDate BIGINT NULL, PRIMARY KEY (IPAddress))");
            ExecuteNonQueryIgnoreExceptions("ALTER TABLE IPAddresses ADD COLUMN State INT NOT NULL DEFAULT 0");
            ExecuteNonQueryIgnoreExceptions("ALTER TABLE IPAddresses ADD COLUMN BanEndDate BIGINT NULL");
            ExecuteNonQuery("CREATE INDEX IF NOT EXISTS IPAddresses_LastFailedLoginDate ON IPAddresses (LastFailedLogin)");
            ExecuteNonQuery("CREATE INDEX IF NOT EXISTS IPAddresses_BanDate ON IPAddresses (BanDate)");
            ExecuteNonQuery("CREATE INDEX IF NOT EXISTS IPAddresses_BanEndDate ON IPAddresses (BanEndDate)");
            ExecuteNonQuery("CREATE INDEX IF NOT EXISTS IPAddresses_State ON IPAddresses (State)");

            // set to failed login state if no ban date
            ExecuteNonQuery("UPDATE IPAddresses SET State = 3 WHERE State IN (0, 1) AND BanDate IS NULL");
        }
Esempio n. 12
0
        /// <summary>
        /// Get a value from configuration manager app settings
        /// </summary>
        /// <typeparam name="T">Type of value to get</typeparam>
        /// <param name="key">Key</param>
        /// <param name="value">Value to set</param>
        /// <param name="minValue">Min value</param>
        /// <param name="maxValue">Max value</param>
        /// <param name="clampSmallTimeSpan">Whether to clamp small timespan to max value</param>
        /// <returns>Value</returns>
        public void GetConfig <T>(string key, ref T value, T?minValue = null, T?maxValue = null, bool clampSmallTimeSpan = true) where T : struct, IComparable <T>
        {
            try
            {
                var converter = TypeDescriptor.GetConverter(typeof(T));
                value = (T)converter.ConvertFromInvariantString(appSettings[key]);
            }
            catch (Exception ex)
            {
                IPBanLog.Error(ex, "Error deserializing appSettings key {0}", key);
            }

            if (minValue != null && maxValue != null)
            {
                value = value.Clamp(minValue.Value, maxValue.Value, clampSmallTimeSpan);
            }
        }
 private bool ParseRegex(Regex regex, string line, bool notifyOnly)
 {
     if (regex != null)
     {
         IPAddressLogEvent info = IPBanService.GetIPAddressInfoFromRegex(dns, regex, line);
         if (info.FoundMatch)
         {
             info.Type   = (notifyOnly ? IPAddressEventType.SuccessfulLogin : IPAddressEventType.FailedLogin);
             info.Source = info.Source ?? Source;
             IPBanLog.Debug("Log file found match, ip: {0}, user: {1}, source: {2}, count: {3}, type: {4}",
                            info.IPAddress, info.UserName, info.Source, info.Count, info.Type);
             loginHandler.AddIPAddressLogEvents(new IPAddressLogEvent[] { info });
             return(true);
         }
     }
     return(false);
 }
Esempio n. 14
0
        private async Task FirewallTask(AsyncQueue <Func <CancellationToken, Task> > queue)
        {
            while (!firewallQueueCancel.IsCancellationRequested)
            {
                KeyValuePair <bool, Func <CancellationToken, Task> > nextAction = await queue.TryDequeueAsync(firewallQueueCancel.Token);

                if (nextAction.Key && nextAction.Value != null)
                {
                    try
                    {
                        await nextAction.Value.Invoke(firewallQueueCancel.Token);
                    }
                    catch (Exception ex)
                    {
                        IPBanLog.Error(ex);
                    }
                }
            }
        }
Esempio n. 15
0
        /// <summary>
        /// Process event viewer XML
        /// </summary>
        /// <param name="xml">XML</param>
        /// <returns>Log event or null if fail to parse/process</returns>
        public IPAddressLogEvent ProcessEventViewerXml(string xml)
        {
            IPBanLog.Debug("Processing event viewer xml: {0}", xml);

            XmlDocument       doc  = ParseXml(xml);
            IPAddressLogEvent info = ExtractEventViewerXml(doc);

            if (info != null && info.FoundMatch && (info.Type == IPAddressEventType.FailedLogin || info.Type == IPAddressEventType.SuccessfulLogin))
            {
                if (!FindSourceAndUserNameForInfo(info, doc))
                {
                    // bad ip address
                    return(null);
                }
                service.AddIPAddressLogEvents(new IPAddressLogEvent[] { info });
                IPBanLog.Debug("Event viewer found: {0}, {1}, {2}, {3}", info.IPAddress, info.Source, info.UserName, info.Type);
            }
            return(info);
        }
Esempio n. 16
0
        public bool IsIPAddressBlocked(string ipAddress, out string ruleName, int port = -1)
        {
            ruleName = null;

            try
            {
                lock (policy)
                {
                    for (int i = 0; ; i += MaxIpAddressesPerRule)
                    {
                        string firewallRuleName = BlockRulePrefix + i.ToString(CultureInfo.InvariantCulture);
                        try
                        {
                            INetFwRule rule = policy.Rules.Item(firewallRuleName);
                            if (rule is null)
                            {
                                // no more rules to check
                                break;
                            }
                            else
                            {
                                HashSet <string> set = new HashSet <string>(rule.RemoteAddresses.Split(',').Select(i2 => IPAddressRange.Parse(i2).Begin.ToString()));
                                if (set.Contains(ipAddress))
                                {
                                    ruleName = firewallRuleName;
                                    return(true);
                                }
                            }
                        }
                        catch
                        {
                            // no more rules to check
                            break;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                IPBanLog.Error(ex);
            }
            return(false);
        }
Esempio n. 17
0
 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");
     }
 }
Esempio n. 18
0
 /// <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 TryNormalizeIPAddress(this string ipAddress, out string normalizedIP)
 {
     normalizedIP = (ipAddress ?? string.Empty).Trim();
     if (string.IsNullOrWhiteSpace(normalizedIP) ||
         normalizedIP == "-" ||
         normalizedIP == "0.0.0.0" ||
         normalizedIP == "127.0.0.1" ||
         normalizedIP == "::0" ||
         normalizedIP == "::1" ||
         !IPAddressRange.TryParse(normalizedIP, out IPAddressRange range))
     {
         // try parsing assuming the ip is followed by a port
         int pos = normalizedIP.LastIndexOf(':');
         if (pos >= 0)
         {
             normalizedIP = normalizedIP.Substring(0, pos);
             if (!IPAddressRange.TryParse(normalizedIP, out range))
             {
                 normalizedIP = null;
                 return(false);
             }
         }
         else
         {
             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);
 }
Esempio n. 19
0
        protected int RunProcess(string program, bool requireExitCode, out IReadOnlyList <string> lines, string commandLine, params object[] args)
        {
            commandLine = string.Format(commandLine, args);
            string bash = "-c \"" + program + " " + commandLine.Replace("\"", "\\\"") + "\"";

            IPBanLog.Debug("Running firewall process: {0} {1}", program, commandLine);
            using (Process p = new Process
            {
                StartInfo = new ProcessStartInfo
                {
                    FileName = "/bin/bash",
                    Arguments = bash,
                    UseShellExecute = false,
                    CreateNoWindow = true,
                    RedirectStandardOutput = true
                }
            })
            {
                p.Start();
                List <string> lineList = new List <string>();
                string        line;
                while ((line = p.StandardOutput.ReadLine()) != null)
                {
                    lineList.Add(line);
                }
                lines = lineList;
                if (!p.WaitForExit(60000))
                {
                    IPBanLog.Error("Process {0} {1} timed out", program, commandLine);
                    p.Kill();
                }
                if (requireExitCode && p.ExitCode != 0)
                {
                    IPBanLog.Error("Process {0} {1} had exit code {2}", program, commandLine, p.ExitCode);
                }
                return(p.ExitCode);
            }
        }
Esempio n. 20
0
        /// <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);
            }
        }
Esempio n. 21
0
 public IPBanWindowsServiceRunner(IPBanServiceRunner runner, string[] args)
 {
     runner.ThrowIfNull();
     try
     {
         IPBanLog.Warn("Running as a Windows service");
         this.runner = runner;
         CanShutdown = false;
         CanStop     = CanHandleSessionChangeEvent = CanHandlePowerEvent = true;
         var acceptedCommandsField = typeof(ServiceBase).GetField("acceptedCommands", BindingFlags.Instance | BindingFlags.NonPublic);
         if (acceptedCommandsField != null)
         {
             int acceptedCommands = (int)acceptedCommandsField.GetValue(this);
             acceptedCommands |= 0x00000100; // SERVICE_ACCEPT_PRESHUTDOWN;
             acceptedCommandsField.SetValue(this, acceptedCommands);
         }
         Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);
     }
     catch (Exception ex)
     {
         IPBanLog.Error(ex);
     }
 }
Esempio n. 22
0
 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.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(IPBanOS.Description, newFile.PlatformRegex.ToString().Trim(), RegexOptions.IgnoreCase | RegexOptions.CultureInvariant))
                 {
                     // log files use a timer internally and do not need to be updated regularly
                     IPBanLogFileScanner scanner = new IPBanIPAddressLogFileScanner(this, DnsLookup,
                                                                                    newFile.Source, pathAndMask, newFile.Recursive, newFile.FailedLoginRegex, newFile.SuccessfulLoginRegex, newFile.MaxFileSize, newFile.PingInterval);
                     logFilesToParse.Add(scanner);
                     IPBanLog.Debug("Adding log file to parse: {0}", pathAndMask);
                 }
                 else
                 {
                     IPBanLog.Debug("Ignoring log file path {0}, regex: {1}", pathAndMask, newFile.PlatformRegex);
                 }
             }
         }
     }
Esempio n. 23
0
        private void ParseFirewallBlockRules()
        {
            string firewallBlockRuleString = null;

            GetConfig <string>("FirewallRules", ref firewallBlockRuleString);
            firewallBlockRuleString = (firewallBlockRuleString ?? string.Empty).Trim();
            if (firewallBlockRuleString.Length == 0)
            {
                return;
            }
            IEnumerable <string> firewallBlockRuleList = firewallBlockRuleString.Trim().Split('\n').Select(s => s.Trim()).Where(s => s.Length != 0);

            foreach (string firewallBlockRule in firewallBlockRuleList)
            {
                string[] pieces = firewallBlockRule.Split(';');
                if (pieces.Length == 5)
                {
                    IPBanFirewallRule firewallBlockRuleObj = new IPBanFirewallRule
                    {
                        Block           = (pieces[1].Equals("block", StringComparison.OrdinalIgnoreCase)),
                        IPAddressRanges = pieces[2].Split(',').Select(p => IPAddressRange.Parse(p)).ToList(),
                        Name            = "EXTRA_" + pieces[0].Trim(),
                        AllowPortRanges = pieces[3].Split(',').Select(p => PortRange.Parse(p)).Where(p => p.MinPort >= 0).ToList(),
                        PlatformRegex   = new Regex(pieces[4].Replace('*', '.'), RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)
                    };
                    if (firewallBlockRuleObj.PlatformRegex.IsMatch(IPBanOS.Name))
                    {
                        extraRules.Add(firewallBlockRuleObj);
                    }
                }
                else
                {
                    IPBanLog.Warn("Firewall block rule entry should have 3 comma separated pieces: name;ips;ports. Invalid entry: {0}", firewallBlockRule);
                }
            }
        }
Esempio n. 24
0
        /// <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();
            }
        }
Esempio n. 25
0
        /// <summary>
        /// Check if a user name is active on the local machine
        /// </summary>
        /// <param name="userName">User name to check</param>
        /// <returns>True if user name is active, false otherwise</returns>
        public static bool UserIsActive(string userName)
        {
            if (string.IsNullOrWhiteSpace(userName))
            {
                return(false);
            }
            userName = userName.Trim();

            try
            {
                if (isWindows)
                {
                    // Windows: WMI
                    SelectQuery query = new SelectQuery("Win32_UserAccount");
                    ManagementObjectSearcher searcher = new ManagementObjectSearcher(query);
                    foreach (ManagementObject user in searcher.Get())
                    {
                        if (user["Disabled"] is null || user["Disabled"].Equals(false))
                        {
                            string possibleMatch = user["Name"]?.ToString();
                            if (possibleMatch != null && possibleMatch.Equals(userName, StringComparison.OrdinalIgnoreCase))
                            {
                                return(true);
                            }
                        }
                    }
                }
                else if (isLinux)
                {
                    // Linux: /etc/passwd
                    if (File.Exists("/etc/passwd"))
                    {
                        bool     enabled = false;
                        string[] lines;
                        if (File.Exists("/etc/shadow"))
                        {
                            lines = File.ReadAllLines("/etc/shadow");
                            // example line:
                            // root:!$1$Fp$SSSuo3L.xA5s/kMEEIloU1:18049:0:99999:7:::
                            foreach (string[] pieces in lines.Select(l => l.Split(':')).Where(p => p.Length == 9))
                            {
                                string checkUserName = pieces[0].Trim();
                                if (checkUserName.Equals(userName))
                                {
                                    string pwdHash = pieces[1].Trim();
                                    if (pwdHash.Length != 0 && pwdHash[0] != '*' && pwdHash[0] != '!')
                                    {
                                        enabled = true;
                                        break;
                                    }
                                    else
                                    {
                                        return(false);
                                    }
                                }
                            }
                        }

                        if (enabled)
                        {
                            // user is OK in shadow file, check passwd file
                            lines = File.ReadAllLines("/etc/passwd");
                            // example line:
                            // root:x:0:0:root:/root:/bin/bash
                            foreach (string[] pieces in lines.Select(l => l.Split(':')).Where(p => p.Length == 7))
                            {
                                // x means shadow file is where the password is at
                                string checkUserName = pieces[0].Trim();
                                string nologin       = pieces[6];
                                if (checkUserName.Equals(userName) && nologin.IndexOf("nologin", StringComparison.OrdinalIgnoreCase) < 0 &&
                                    !nologin.Contains("/bin/false"))
                                {
                                    return(true);
                                }
                            }
                        }
                    }
                }
                // TODO: MAC
            }
            catch (Exception ex)
            {
                IPBanLog.Error("Error determining if user is active", ex);
            }

            return(false);
        }
Esempio n. 26
0
        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);
            }
        }
Esempio n. 27
0
        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, 1, 50);
            GetConfig <bool>("ResetFailedLoginCountForUnbannedIPAddresses", ref resetFailedLoginCountForUnbannedIPAddresses);
            GetConfigArray <TimeSpan>("BanTime", ref banTimes, emptyTimeSpanArray);
            for (int i = 0; i < banTimes.Length; i++)
            {
                banTimes[i] = banTimes[i].Clamp(TimeSpan.FromMinutes(1.0), maxBanTimeSpan);
            }
            GetConfig <bool>("ClearBannedIPAddressesOnRestart", ref clearBannedIPAddressesOnRestart);
            GetConfig <TimeSpan>("ExpireTime", ref expireTime, TimeSpan.FromMinutes(1.0), maxBanTimeSpan);
            GetConfig <TimeSpan>("CycleTime", ref cycleTime, TimeSpan.FromSeconds(5.0), TimeSpan.FromMinutes(1.0), false);
            GetConfig <TimeSpan>("MinimumTimeBetweenFailedLoginAttempts", ref minimumTimeBetweenFailedLoginAttempts, TimeSpan.Zero, TimeSpan.FromSeconds(15.0), false);
            GetConfig <string>("FirewallRulePrefix", ref firewallRulePrefix);

            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, whiteListRanges, ref whiteListRegex, whiteListString, whiteListRegexString);
            PopulateList(blackList, blackListRanges, ref blackListRegex, blacklistString, blacklistRegexString);
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                expressionsFailure = new XmlSerializer(typeof(EventViewerExpressionsToBlock)).Deserialize(new XmlNodeReader(doc.SelectSingleNode("//ExpressionsToBlock"))) as EventViewerExpressionsToBlock;
                if (expressionsFailure != null)
                {
                    foreach (EventViewerExpressionGroup group in expressionsFailure.Groups)
                    {
                        foreach (EventViewerExpression expression in group.Expressions)
                        {
                            expression.Regex = (expression.Regex?.ToString() ?? string.Empty).Trim();
                        }
                    }
                }
                expressionsSuccess = new XmlSerializer(typeof(EventViewerExpressionsToNotify)).Deserialize(new XmlNodeReader(doc.SelectSingleNode("//ExpressionsToNotify"))) as EventViewerExpressionsToNotify;
                if (expressionsSuccess != null)
                {
                    foreach (EventViewerExpressionGroup group in expressionsSuccess.Groups)
                    {
                        group.NotifyOnly = true;
                        foreach (EventViewerExpression expression in group.Expressions)
                        {
                            expression.Regex = (expression.Regex?.ToString() ?? string.Empty).Trim();
                        }
                    }
                }
            }
            else
            {
                expressionsFailure = new EventViewerExpressionsToBlock();
                expressionsSuccess = new EventViewerExpressionsToNotify();
            }
            try
            {
                if (new XmlSerializer(typeof(IPBanLogFilesToParse)).Deserialize(new XmlNodeReader(doc.SelectSingleNode("//LogFilesToParse"))) is IPBanLogFilesToParse logFilesToParse)
                {
                    logFiles = logFilesToParse.LogFiles;
                }
                else
                {
                    logFiles = emptyLogFilesToParseArray;
                }
            }
            catch (Exception ex)
            {
                IPBanLog.Error(ex);
                logFiles = new IPBanLogFileToParse[0];
            }
            GetConfig <string>("ProcessToRunOnBan", ref processToRunOnBan);
            GetConfig <bool>("UseDefaultBannedIPAddressHandler", ref useDefaultBannedIPAddressHandler);

            // 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().ToUpperInvariant().Trim();
                if (userNameTrimmed.Length > 0)
                {
                    userNameWhitelist.Add(userNameTrimmed);
                }
            }
            string userNameWhiteListRegexString = GetConfig <string>("UserNameWhiteListRegex", string.Empty);

            if (!string.IsNullOrWhiteSpace(userNameWhiteListRegexString))
            {
                userNameWhitelistRegex = new Regex(userNameWhiteListRegexString, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.Singleline);
            }
            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);

            // parse firewall block rules, one per line
            ParseFirewallBlockRules();
        }
Esempio n. 28
0
        /// <summary>
        /// Get an ip address and user name out of text using regex. Regex may contain groups named source_[sourcename] to override the source.
        /// </summary>
        /// <param name="dns">Dns lookup to resolve ip addresses</param>
        /// <param name="regex">Regex</param>
        /// <param name="text">Text</param>
        /// <param name="ipAddress">Found ip address or null if none</param>
        /// <param name="userName">Found user name or null if none</param>
        /// <returns>True if a regex match was found, false otherwise</returns>
        public static IPAddressLogEvent GetIPAddressInfoFromRegex(IDnsLookup dns, Regex regex, string text)
        {
            const string customSourcePrefix = "source_";
            bool         foundMatch         = false;
            string       userName           = null;
            string       ipAddress          = null;
            string       source             = null;
            int          repeatCount        = 1;

            Match repeater = Regex.Match(text, "message repeated (?<count>[0-9]+) times", RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);

            if (repeater.Success)
            {
                repeatCount = int.Parse(repeater.Groups["count"].Value, CultureInfo.InvariantCulture);
            }

            foreach (Match m in regex.Matches(text))
            {
                if (!m.Success)
                {
                    continue;
                }

                // check for a user name
                Group userNameGroup = m.Groups["username"];
                if (userNameGroup != null && userNameGroup.Success)
                {
                    userName = (userName ?? userNameGroup.Value.Trim('\'', '\"', '(', ')', '[', ']', '{', '}', ' ', '\r', '\n'));
                }
                Group sourceGroup = m.Groups["source"];
                if (sourceGroup != null && sourceGroup.Success)
                {
                    source = (source ?? sourceGroup.Value.Trim('\'', '\"', '(', ')', '[', ']', '{', '}', ' ', '\r', '\n'));
                }
                if (string.IsNullOrWhiteSpace(source))
                {
                    foreach (Group group in m.Groups)
                    {
                        if (group.Success && group.Name != null && group.Name.StartsWith(customSourcePrefix))
                        {
                            source = group.Name.Substring(customSourcePrefix.Length);
                        }
                    }
                }

                // check if the regex had an ipadddress group
                Group ipAddressGroup = m.Groups["ipaddress"];
                if (ipAddressGroup is null)
                {
                    ipAddressGroup = m.Groups["ipaddress_exact"];
                }
                if (ipAddressGroup != null && ipAddressGroup.Success && !string.IsNullOrWhiteSpace(ipAddressGroup.Value))
                {
                    string tempIPAddress = ipAddressGroup.Value.Trim();

                    // in case of IP:PORT format, try a second time, stripping off the :PORT, saves having to do this in all
                    //  the different ip regex.
                    int  lastColon        = tempIPAddress.LastIndexOf(':');
                    bool isValidIPAddress = IPAddress.TryParse(tempIPAddress, out IPAddress tmp);
                    if (isValidIPAddress || (lastColon >= 0 && IPAddress.TryParse(tempIPAddress.Substring(0, lastColon), out tmp)))
                    {
                        ipAddress  = tmp.ToString();
                        foundMatch = true;
                        break;
                    }

                    // if we are parsing anything as ip address (including dns names)
                    if (ipAddressGroup.Name == "ipaddress" && tempIPAddress != Environment.MachineName && tempIPAddress != "-")
                    {
                        // Check Host by name
                        IPBanLog.Info("Parsing as IP failed, checking dns '{0}'", tempIPAddress);
                        try
                        {
                            IPHostEntry entry = dns.GetHostEntryAsync(tempIPAddress).Sync();
                            if (entry != null && entry.AddressList != null && entry.AddressList.Length > 0)
                            {
                                ipAddress = entry.AddressList.FirstOrDefault().ToString();
                                IPBanLog.Info("Dns result '{0}' = '{1}'", tempIPAddress, ipAddress);
                                foundMatch = true;
                                break;
                            }
                        }
                        catch
                        {
                            IPBanLog.Info("Parsing as dns failed '{0}'", tempIPAddress);
                        }
                    }
                }
                else
                {
                    // found a match but no ip address, that is OK.
                    foundMatch = true;
                }
            }

            return(new IPAddressLogEvent(ipAddress, userName, source, repeatCount, IPAddressEventType.FailedLogin)
            {
                FoundMatch = foundMatch
            });
        }
Esempio n. 29
0
        /// <summary>
        /// Ping the files, this is normally done on a timer, but if you have passed a 0 second
        /// ping interval to the constructor, you must call this manually
        /// </summary>
        public void PingFiles()
        {
            try
            {
                if (pingTimer != null)
                {
                    pingTimer.Enabled = false;
                }
            }
            catch
            {
            }


            foreach (WatchedFile file in GetCurrentWatchedFiles())
            {
                try
                {
                    // 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, 16))
                    {
                        try
                        {
                            if (fs.Length != 0)
                            {
                                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, 256))
                        {
                            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
            {
                if (pingTimer != null)
                {
                    pingTimer.Enabled = true;
                }
            }
            catch
            {
            }
        }
Esempio n. 30
0
        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 is 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 == "0.0.0.0/0,::/0" ? "*" : 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 == "*" && remoteIPAddresses != "0.0.0.0/0,::/0"))
                {
                    // 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);
            }
        }