コード例 #1
0
        public List <RateLimitRule> GetMatchingRules(ClientRequestIdentity identity)
        {
            var limits   = new List <RateLimitRule>();
            var policies = _policyStore.Get($"{_options.IpPolicyPrefix}");

            if (policies != null && policies.IpRules != null && policies.IpRules.Any())
            {
                // search for rules with IP intervals containing client IP
                var matchPolicies = policies.IpRules.Where(r => _ipParser.ContainsIp(r.Ip, identity.ClientIp)).AsEnumerable();
                var rules         = new List <RateLimitRule>();
                foreach (var item in matchPolicies)
                {
                    rules.AddRange(item.Rules);
                }

                foreach (var rule in rules)
                {
                    var regex = new Regex(rule.UrlRegex, RegexOptions.IgnoreCase);
                    var match = regex.Match(identity.HttpVerb + ":" + identity.Path);
                    if (match.Success)
                    {
                        limits.Add(rule);
                    }
                }
            }

            // get the most restrictive limit for each period
            limits = limits.GroupBy(l => l.Period).Select(l => l.OrderBy(x => x.Limit)).Select(l => l.First()).ToList();

            // search for matching general rules
            if (_options.GeneralRules != null)
            {
                var matchingGeneralLimits = new List <RateLimitRule>();

                foreach (var generalRule in _options.GeneralRules)
                {
                    var regex = new Regex(generalRule.UrlRegex, RegexOptions.IgnoreCase);
                    var match = regex.Match(identity.HttpVerb + ":" + identity.Path);
                    if (match.Success)
                    {
                        matchingGeneralLimits.Add(generalRule);
                    }
                }

                // get the most restrictive general limit for each period
                var generalLimits = matchingGeneralLimits.GroupBy(l => l.Period).Select(l => l.OrderBy(x => x.Limit)).Select(l => l.First()).ToList();

                foreach (var generalLimit in generalLimits)
                {
                    // add general rule if no specific rule is declared for the specified period
                    if (!limits.Exists(l => l.Period == generalLimit.Period))
                    {
                        limits.Add(generalLimit);
                    }
                }
            }

            foreach (var item in limits)
            {
                //parse period text into time spans
                item.PeriodTimespan = _core.ConvertToTimeSpan(item.Period);
            }

            limits = limits.OrderBy(l => l.PeriodTimespan).ToList();
            if (_options.StackBlockedRequests)
            {
                limits.Reverse();
            }

            return(limits);
        }
コード例 #2
0
        public List <RateLimitRule> GetMatchingRules(ClientRequestIdentity identity)
        {
            var limits   = new List <RateLimitRule>();
            var policies = _policyStore.Get($"{_options.IpPolicyPrefix}");

            if (policies != null && policies.IpRules != null && policies.IpRules.Any())
            {
                // search for rules with IP intervals containing client IP
                var matchPolicies = policies.IpRules.Where(r => _ipParser.ContainsIp(r.Ip, identity.ClientIp)).AsEnumerable();
                var rules         = new List <RateLimitRule>();
                foreach (var item in matchPolicies)
                {
                    rules.AddRange(item.Rules);
                }

                if (_options.EnableEndpointRateLimiting)
                {
                    // search for rules with endpoints like "*" and "*:/matching_path"
                    var pathLimits = rules.Where(l => $"*:{identity.Path}".ToLowerInvariant().Contains(l.Endpoint.ToLowerInvariant())).AsEnumerable();
                    limits.AddRange(pathLimits);

                    // search for rules with endpoints like "matching_verb:/matching_path"
                    var verbLimits = rules.Where(l => $"{identity.HttpVerb}:{identity.Path}".ToLowerInvariant().Contains(l.Endpoint.ToLowerInvariant())).AsEnumerable();
                    limits.AddRange(verbLimits);
                }
                else
                {
                    //ignore endpoint rules and search for global rules only
                    var genericLimits = rules.Where(l => l.Endpoint == "*").AsEnumerable();
                    limits.AddRange(genericLimits);
                }
            }

            // get the most restrictive limit for each period
            limits = limits.GroupBy(l => l.Period).Select(l => l.OrderBy(x => x.Limit)).Select(l => l.First()).ToList();

            // search for matching general rules
            if (_options.GeneralRules != null)
            {
                var matchingGeneralLimits = new List <RateLimitRule>();
                if (_options.EnableEndpointRateLimiting)
                {
                    // search for rules with endpoints like "*" and "*:/matching_path" in general rules
                    var pathLimits = _options.GeneralRules.Where(l => $"*:{identity.Path}".ToLowerInvariant().Contains(l.Endpoint.ToLowerInvariant())).AsEnumerable();
                    matchingGeneralLimits.AddRange(pathLimits);

                    // search for rules with endpoints like "matching_verb:/matching_path" in general rules
                    var verbLimits = _options.GeneralRules.Where(l => $"{identity.HttpVerb}:{identity.Path}".ToLowerInvariant().IsMatch(l.Endpoint.ToLowerInvariant())).AsEnumerable();
                    matchingGeneralLimits.AddRange(verbLimits);
                }
                else
                {
                    //ignore endpoint rules and search for global rules in general rules
                    var genericLimits = _options.GeneralRules.Where(l => l.Endpoint == "*").AsEnumerable();
                    matchingGeneralLimits.AddRange(genericLimits);
                }

                // get the most restrictive general limit for each period
                var generalLimits = matchingGeneralLimits.GroupBy(l => l.Period).Select(l => l.OrderBy(x => x.Limit)).Select(l => l.First()).ToList();

                foreach (var generalLimit in generalLimits)
                {
                    // add general rule if no specific rule is declared for the specified period
                    if (!limits.Exists(l => l.Period == generalLimit.Period))
                    {
                        limits.Add(generalLimit);
                    }
                }
            }

            foreach (var item in limits)
            {
                //parse period text into time spans
                item.PeriodTimespan = _core.ConvertToTimeSpan(item.Period);
            }

            limits = limits.OrderBy(l => l.PeriodTimespan).ToList();
            if (_options.StackBlockedRequests)
            {
                limits.Reverse();
            }

            return(limits);
        }
コード例 #3
0
        public bool RateExceeded(HttpContext context, IPRateLimitingSetting setting, out int retryAfter)
        {
            retryAfter = 0;
            var path   = context.Request.Path;
            var method = context.Request.Method.ToLower();

            var clientIP = _ipParser.GetClientIp(context);

            //System.Diagnostics.Debugger.Break();

            if (_ipParser.ContainsIp(setting.IPWhitelist, clientIP.ToString()))
            {
                return(false);
            }

            if (_ipParser.ContainsIp(setting.IPBlockedlist, clientIP.ToString()))
            {
                return(true);
            }

            var generalRuleExists = setting.GeneralRules.FirstOrDefault(q => q.Verbs.ToLower().Contains(method) && q.Path == path);

            if (generalRuleExists == null)
            {
                return(false);
            }

            if (!IpRateLimiterDictionary.TryGetValue(clientIP.ToString(), out IPRateCounter existedRate))
            {
                var iPRateCounter = new IPRateCounter()
                {
                    Count = 1, CreatedAt = DateTime.Now
                };
                IpRateLimiterDictionary.AddOrUpdate(clientIP.ToString(), iPRateCounter, (key, oldValue) => iPRateCounter);
                return(false);
            }


            var now       = DateTime.Now.AddSeconds(-generalRuleExists.PeriodTime);
            var createdAt = existedRate.CreatedAt;

            if (createdAt > now)
            {
                retryAfter = (int)(now - createdAt).TotalSeconds;
                if (existedRate.Count >= generalRuleExists.Limit)
                {
                    return(true);
                }
                else
                {
                    existedRate.Count++;
                    return(false);
                }
            }
            else
            {
                existedRate.Count     = 1;
                existedRate.CreatedAt = DateTime.Now;
                IpRateLimiterDictionary.AddOrUpdate(clientIP.ToString(), existedRate, (key, oldValue) => existedRate);
                return(false);
            }
        }