예제 #1
0
        private HashSet <WatchedFile> GetCurrentWatchedFiles()
        {
            HashSet <WatchedFile> watchedFilesCopy = new HashSet <WatchedFile>();

            try
            {
                // read in existing files that match the mask in the directory being watched
                if (Directory.Exists(directoryToWatch))
                {
                    string replacedDirectory = ReplacePathVars(directoryToWatch);
                    string replacedFileMask  = ReplacePathVars(fileMask);
                    foreach (string file in Directory.EnumerateFiles(replacedDirectory, replacedFileMask, 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 of everything so we can enumerate outside a lock
                watchedFilesCopy.Clear();
                foreach (WatchedFile file in watchedFiles)
                {
                    watchedFilesCopy.Add(file);
                }
            }

            return(watchedFilesCopy);
        }
        /// <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);
        }
 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);
 }
예제 #4
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);
        }
예제 #5
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);
 }
예제 #6
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);
            }
        }
예제 #7
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);
                 }
             }
         }
     }
예제 #8
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
            {
            }
        }
예제 #9
0
        private IPAddressLogEvent 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);
            IPAddressLogEvent info          = null;
            bool foundNotifyOnly            = false;

            if (keywordsNode != null)
            {
                // we must match on keywords
                foreach (EventViewerExpressionGroup group in service.Config.WindowsEventViewerGetGroupsMatchingKeywords(keywordsULONG))
                {
                    string userName = null;
                    string source   = null;
                    foreach (EventViewerExpression 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.Debug("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.Debug("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)
                                {
                                    if (group.NotifyOnly)
                                    {
                                        foundNotifyOnly = true;
                                    }
                                    else if (foundNotifyOnly)
                                    {
                                        throw new InvalidDataException("Conflicting expressions in event viewer, both failed and success logins matched keywords " + group.Keywords);
                                    }
                                    userName = (userName ?? info.UserName);
                                    source   = (source ?? info.Source);
                                    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.Debug("Regex {0} did not match any nodes with xpath {1}", expression.Regex, expression.XPath);
                                info            = null;
                                foundNotifyOnly = false;
                                break;
                            }
                        }
                    }
                    if (info != null && info.FoundMatch && info.IPAddress != null)
                    {
                        info.UserName = (info.UserName ?? userName);
                        info.Source   = info.Source ?? source ?? group.Source;
                        break;
                    }
                    info = null; // set null for next attempt
                }
            }

            if (info != null)
            {
                info.Type = (foundNotifyOnly ? IPAddressEventType.SuccessfulLogin : IPAddressEventType.FailedLogin);
            }
            return(info);
        }