private string BanIpByRateLimitRule(ZoneEntity zoneEntity, bool ifTestStage, CloudFlareApiService cloudflare, int timeStage, string requestHost, string ip, int period, int threshold, int requestCount)
        {
            var sbDetail = new StringBuilder();

            if (ifTestStage)
            {
                sbDetail.AppendFormat("Ban IP [{0}] successfully.<br />", ip);
            }
            else
            {
                var cloudflareAccessRuleResponse = cloudflare.BanIp(ip, "Ban Ip By Attack Prevent Windows service!");
                if (cloudflareAccessRuleResponse.Success)
                {
                    sbDetail.AppendFormat("Ban IP [{0}] and add ban history successfully.<br />", ip);

                    BanIpHistoryBusiness.Add(new BanIpHistory()
                    {
                        IP     = ip,
                        ZoneId = zoneEntity.ZoneId,
                        RuleId = 0,
                        Remark = string.Format("IP [{0}] visited [{2}] [{3}] times, time range:[{1}].<br /> Exceeded rate limit threshold(Period=[{4}],Threshold=[{5}]).",
                                               ip, timeStage, requestHost, requestCount, period, threshold)
                    });
                }
                else
                {
                    sbDetail.AppendFormat("Ban IP [{0}] failure, the reason is:[{1}].<br />", ip, cloudflareAccessRuleResponse.Errors.Length > 0 ? cloudflareAccessRuleResponse.Errors[0].message : "No error message from Cloudflare.");
                }
            }
            return(sbDetail.ToString());
        }
        private List <AuditLogEntity> BanIp(ZoneEntity zone, CloudFlareApiService cloudflare, AnalyzeResult analyzeResult)
        {
            List <AuditLogEntity> auditLogEntities = new List <AuditLogEntity>();

            foreach (var rst in analyzeResult.result)
            {
                foreach (var broken in rst.BrokenIpList)
                {
                    StringBuilder sbDetail = new StringBuilder();
                    if (rst.Url.EndsWith("*"))
                    {
                        var count = broken.RequestRecords.Sum(a => a.RequestCount);
                        //logger.Debug(JsonConvert.SerializeObject(new {
                        //    count= count,
                        //    RequestRecords = broken.RequestRecords
                        //}));
                        sbDetail.Append($"IP [{broken.IP}] visited [{rst.Url}] [{count}] times, time range:[{analyzeResult.timeStage}].<br /> Exceeded rate limiting threshold(URL=[{rst.Url}],Period=[{rst.Period}],Threshold=[{rst.Threshold}],EnlargementFactor=[{rst.EnlargementFactor}]),details(only list the top 10 records):<br />");
                        var top10 = broken.RequestRecords.OrderByDescending(a => a.RequestCount).Take(10);

                        foreach (var item in top10)
                        {
                            sbDetail.AppendFormat("[{0}] {1} times.<br />", item.FullUrl, item.RequestCount);
                        }
                    }
                    else
                    {
                        var count = broken.RequestRecords.Sum(a => a.RequestCount);
                        //logger.Debug(JsonConvert.SerializeObject(new
                        //{
                        //    count = count,
                        //    RequestRecords = broken.RequestRecords
                        //}));
                        sbDetail.Append($"IP [{broken.IP}] visited [{rst.Url}] [{count}] times, time range:[{analyzeResult.timeStage}].<br /> Exceeded rate limiting threshold(URL=[{rst.Url}],Period=[{rst.Period}],Threshold=[{rst.Threshold}],EnlargementFactor=[{rst.EnlargementFactor}]).<br />");
                    }
                    string banIpLog = BanIpByRateLimitRule(zone, zone.IfTestStage, cloudflare, analyzeResult.timeStage, broken.RequestRecords.FirstOrDefault().HostName, broken.IP, rst.Period, rst.Threshold, rst.BrokenIpList.Count);

                    if (!string.IsNullOrEmpty(banIpLog))
                    {
                        sbDetail.Append(banIpLog);
                    }

                    auditLogEntities.Add(new AuditLogEntity(zone.TableID, LogLevel.Audit, sbDetail.ToString()));
                }
            }

            return(auditLogEntities);
        }
        private bool isStoreToday;//2020.7.10

        public CloudflareLogHandleSercie(string zoneId, string authEmail, string authKey, double sample, DateTime start, DateTime end, bool isStoreToday = false)
        {
            this.zoneId    = zoneId;
            this.authEmail = authEmail;
            this.authKey   = authKey;
            this.sample    = sample;
            this.startTime = start;
            this.endTime   = end;

            this.isStoreToday = isStoreToday;

            _cloudFlareApiService = new CloudFlareApiService();
            logService            = new Business.LogService();

            if (dicCloudflareLogsToday == null)
            {
                dicCloudflareLogsToday = new ConcurrentDictionary <string, List <CloudflareLog> >();
            }
        }
        private void Analyze(AnalyzeResult analyzeResult)
        {
            if (analyzeResult != null && analyzeResult.result != null)
            {
                List <AuditLogEntity> auditLogEntities = new List <AuditLogEntity>();
                string            key      = "AnalyzeRatelimit_GetZoneList_Key";
                List <ZoneEntity> zoneList = Utils.GetMemoryCache(key, () =>
                {
                    return(ZoneBusiness.GetZoneList());
                }, 1440);

                string zoneID = analyzeResult.ZoneId;
                var    zone   = zoneList.FirstOrDefault(a => a.ZoneId == zoneID);

                if (zone != null)
                {
                    string authEmail = zone.AuthEmail;
                    string authKey   = zone.AuthKey;

                    var cloudflare = new CloudFlareApiService(zone.ZoneId, zone.AuthEmail, zone.AuthKey);

                    //发送警报
                    Warn(analyzeResult);

                    //开启RateLimit
                    var logs = OpenRageLimit(zone, cloudflare, analyzeResult);
                    auditLogEntities.AddRange(logs);

                    //Ban IP
                    //logs = BanIp(zone, cloudflare, analyzeResult);
                    //auditLogEntities.AddRange(logs);

                    //记录日志
                    InsertLogs(auditLogEntities);
                }
            }
        }
        private void GeneratedWhiteListReport(string title, ZoneEntity zone, List <List <CloudflareLog> > cloudflareLogs)
        {
            var cloundFlareApiService = new CloudFlareApiService();
            var whiteList             = cloundFlareApiService.GetAccessRuleList(zone.ZoneId, zone.AuthEmail, zone.AuthKey, EnumMode.whitelist);
            var subWhiteList          = whiteList.Where(a => a.notes.Contains("WHITELIST CLEINT'S IP ADDRESS SITEID"))
                                        .Select(a => new WhiteListModel
            {
                IP = a.configurationValue
            }).ToList();

            //var subWhiteList = new List< WhiteListModel>(){
            //    new WhiteListModel {
            //        IP= "131.242.135.253",
            //    },
            //    new WhiteListModel {
            //        IP= "131.242.135.252",
            //    }
            //};

            var totalList = cloudflareLogs.SelectMany(a => a)
                            .Join(subWhiteList,
                                  left => left.ClientIP,
                                  right => right.IP,
                                  (left, right) => new
            {
                left.ClientIP,
                left.ClientRequestHost
            })
                            .GroupBy(a => new { a.ClientIP, a.ClientRequestHost })
                            .Select(
                g => new
            {
                IP       = g.Key.ClientIP,
                HostName = g.Key.ClientRequestHost,
                Count    = g.Count(),
            })
                            .OrderByDescending(a => a.Count);

            List <string> ipList = new List <string>();

            foreach (var item in totalList)
            {
                //取不同的20个IP
                if (!ipList.Contains(item.IP))
                {
                    ipList.Add(item.IP);
                }

                if (ipList.Count > 20)
                {
                    break;
                }

                int           max      = GetMax(cloudflareLogs, item.IP, item.HostName);
                int           min      = GetMin(cloudflareLogs, item.IP, item.HostName);
                int           avg      = GetAvg(cloudflareLogs, item.IP, item.HostName);
                List <string> urls     = GetTop5Urls(cloudflareLogs, item.IP, item.HostName);
                string        urlsJson = JsonConvert.SerializeObject(urls);

                int?maxHistory = ActionReportBusiness.GetMaxForWhiteList(zone.ZoneId, item.IP, item.HostName);
                int?minHistory = ActionReportBusiness.GetMinForWhiteList(zone.ZoneId, item.IP, item.HostName);
                int?avgHistory = ActionReportBusiness.GetAvgForWhiteList(zone.ZoneId, item.IP, item.HostName);

                string maxDisplay = string.Format("{0}({1})", max, maxHistory.HasValue ? maxHistory.Value.ToString() : nothing);
                string minDisplay = string.Format("{0}({1})", min, minHistory.HasValue ? minHistory.Value.ToString() : nothing);
                string avgDisplay = string.Format("{0}({1})", avg, avgHistory.HasValue ? avgHistory.Value.ToString() : nothing);

                ActionReport report = new ActionReport
                {
                    IP          = item.IP,
                    HostName    = item.HostName,
                    Max         = max,
                    Min         = min,
                    Avg         = avg,
                    FullUrl     = urlsJson,
                    Title       = title,
                    ZoneId      = zone.ZoneId,
                    Count       = item.Count,
                    Mode        = "WhiteList",
                    CreatedTime = DateTime.UtcNow,
                    MaxDisplay  = maxDisplay,
                    MinDisplay  = minDisplay,
                    AvgDisplay  = avgDisplay,
                    Remark      = "",
                };
                ActionReportBusiness.Add(report);
            }
        }
        private void GeneratedActiveReport(string title, ZoneEntity zone, List <List <CloudflareLog> > cloudflareLogs)
        {
            var cloundFlareApiService = new CloudFlareApiService();
            var whiteList             = cloundFlareApiService.GetAccessRuleList(zone.ZoneId, zone.AuthEmail, zone.AuthKey, EnumMode.whitelist);
            var whiteListIps          = whiteList.Select(a => a.configurationValue);

            var totalList = cloudflareLogs.SelectMany(a => a)
                            .GroupBy(a => new { a.ClientIP, a.ClientRequestHost })
                            .Select(
                g => new
            {
                IP       = g.Key.ClientIP,
                HostName = g.Key.ClientRequestHost,
                Count    = g.Count(),
            })
                            .Where(a => !whiteListIps.Contains(a.IP))
                            .OrderByDescending(a => a.Count);

            List <string> ipList = new List <string>();

            foreach (var item in totalList)
            {
                //取不同的20个IP
                if (!ipList.Contains(item.IP))
                {
                    ipList.Add(item.IP);
                }

                if (ipList.Count > 20)
                {
                    break;
                }

                int           max      = GetMax(cloudflareLogs, item.IP, item.HostName);
                int           min      = GetMin(cloudflareLogs, item.IP, item.HostName);
                int           avg      = GetAvg(cloudflareLogs, item.IP, item.HostName);
                List <string> urls     = GetTop5Urls(cloudflareLogs, item.IP, item.HostName);
                string        urlsJson = JsonConvert.SerializeObject(urls);

                int?maxHistory = ActionReportBusiness.GetMaxForAction(zone.ZoneId, item.IP, item.HostName);
                int?minHistory = ActionReportBusiness.GetMinForAction(zone.ZoneId, item.IP, item.HostName);
                int?avgHistory = ActionReportBusiness.GetAvgForAction(zone.ZoneId, item.IP, item.HostName);

                string maxDisplay = string.Format("{0}({1})", max, maxHistory.HasValue ? maxHistory.Value.ToString() : nothing);
                string minDisplay = string.Format("{0}({1})", min, minHistory.HasValue ? minHistory.Value.ToString() : nothing);
                string avgDisplay = string.Format("{0}({1})", avg, avgHistory.HasValue ? avgHistory.Value.ToString() : nothing);

                ActionReport report = new ActionReport
                {
                    IP          = item.IP,
                    HostName    = item.HostName,
                    Max         = max,
                    Min         = min,
                    Avg         = avg,
                    FullUrl     = urlsJson,
                    Title       = title,
                    ZoneId      = zone.ZoneId,
                    Count       = item.Count,
                    Mode        = "Action",
                    CreatedTime = DateTime.UtcNow,
                    MaxDisplay  = maxDisplay,
                    MinDisplay  = minDisplay,
                    AvgDisplay  = avgDisplay,
                    Remark      = "",
                };
                ActionReportBusiness.Add(report);
            }
        }
        private List <AuditLogEntity> OpenRageLimit(ZoneEntity zone, CloudFlareApiService cloudflare, AnalyzeResult analyzeResult)
        {
            List <AuditLogEntity> auditLogEntities = new List <AuditLogEntity>();
            var sbDetail = new StringBuilder();

            #region Open Rate Limiting Rule

            foreach (var rst in analyzeResult.result)
            {
                // 更新 Rate Limit Trigger Time
                RateLimitBusiness.TriggerRateLimit(new RateLimitEntity()
                {
                    Url       = rst.Url,
                    Period    = rst.Period,
                    Threshold = rst.Threshold,
                    ZoneId    = zone.ZoneId
                });

                sbDetail = new StringBuilder(
                    $"[{rst.BrokenIpList.Count}] IPs exceeded rate limiting threshold(Url=[{rst.Url}],Threshold=[{rst.Threshold}],Period=[{rst.Period}],EnlargementFactor=[{rst.EnlargementFactor}],RateLimitTriggerIpCount=[{rst.RateLimitTriggerIpCount}]), time range:[{analyzeResult.timeStage}], details:<br />");

                foreach (var rule in rst.BrokenIpList)
                {
                    sbDetail.AppendFormat("IP [{0}] visited [{1}] times.<br /> ", rule.IP, rule.RequestRecords.Sum(x => x.RequestCount));
                }
                //auditLogEntities.Add(new AuditLogEntity(zone.TableID, LogLevel.App, sbDetail.ToString()));
                ////sbDetail.AppendFormat("Start opening rate limiting rule in Cloudflare [URL=[{0}],Threshold=[{1}],Period=[{2}]].<br />", rateLimit.Url, rateLimit.Threshold, rateLimit.Period);
                //sbDetail = new StringBuilder();
                if (zone != null && zone.IfTestStage)
                {
                    sbDetail.AppendFormat("Open rate limiting rule in Cloudflare [URL=[{0}],Threshold=[{1}],Period=[{2}]] successfully.<br />", rst.Url, rst.Threshold, rst.Period);
                }
                else
                {
                    if (cloudflare.OpenRateLimit(rst.Url, rst.Threshold, rst.Period, out var errorLog))
                    {
                        sbDetail.AppendFormat("Open rate limiting rule in Cloudflare [URL=[{0}],Threshold=[{1}],Period=[{2}]] successfully.<br />", rst.Url, rst.Threshold, rst.Period);
                    }
                    else
                    {
                        sbDetail.AppendFormat(errorLog.Detail);
                    }
                }

                auditLogEntities.Add(new AuditLogEntity(zone.TableID, LogLevel.Audit, sbDetail.ToString()));

                //Ban Ip
                foreach (var broken in rst.BrokenIpList)
                {
                    sbDetail = new StringBuilder();
                    if (rst.Url.EndsWith("*"))
                    {
                        var count = broken.RequestRecords.Sum(a => a.RequestCount);
                        sbDetail.Append($"IP [{broken.IP}] visited [{rst.Url}] [{count}] times, time range:[{analyzeResult.timeStage}].<br /> Exceeded rate limiting threshold(URL=[{rst.Url}],Period=[{rst.Period}],Threshold=[{rst.Threshold}],EnlargementFactor=[{rst.EnlargementFactor}]),details(only list the top 10 records):<br />");
                        var top10 = broken.RequestRecords.OrderByDescending(a => a.RequestCount).Take(10);

                        foreach (var item in top10)
                        {
                            sbDetail.AppendFormat("[{0}] {1} times.<br />", item.FullUrl, item.RequestCount);
                        }
                    }
                    else
                    {
                        var count = broken.RequestRecords.Sum(a => a.RequestCount);
                        sbDetail.Append($"IP [{broken.IP}] visited [{rst.Url}] [{count}] times, time range:[{analyzeResult.timeStage}].<br /> Exceeded rate limiting threshold(URL=[{rst.Url}],Period=[{rst.Period}],Threshold=[{rst.Threshold}],EnlargementFactor=[{rst.EnlargementFactor}]).<br />");
                    }
                    string banIpLog = BanIpByRateLimitRule(zone, zone.IfTestStage, cloudflare, analyzeResult.timeStage, broken.RequestRecords.FirstOrDefault().HostName, broken.IP, rst.Period, rst.Threshold, rst.BrokenIpList.Count);

                    if (!string.IsNullOrEmpty(banIpLog))
                    {
                        sbDetail.Append(banIpLog);
                    }

                    auditLogEntities.Add(new AuditLogEntity(zone.TableID, LogLevel.Audit, sbDetail.ToString()));
                }
            }

            #endregion
            return(auditLogEntities);
        }