Geographic and IP-Based Rate Limiting

Geographic and IP-Based Rate Limiting

Geographic distribution of rate limits helps manage global traffic while preventing localized attacks. Different regions may have different usage patterns and attack profiles, requiring tailored rate limiting strategies. IP-based rate limiting provides an additional layer of defense against distributed attacks.

# Python example of geographic rate limiting
import geoip2.database
from ipaddress import ip_address, ip_network
from typing import Dict, List, Optional

class GeographicRateLimiter:
    def __init__(self, geoip_db_path: str):
        self.reader = geoip2.database.Reader(geoip_db_path)
        self.country_limits = {
            'default': {'rate': 100, 'burst': 1000},
            'US': {'rate': 200, 'burst': 2000},
            'CN': {'rate': 50, 'burst': 500},
            'RU': {'rate': 50, 'burst': 500}
        }
        self.blocked_countries = {'KP', 'IR'}  # Example blocked countries
        self.suspicious_asns = {13335, 16509}  # Example ASNs to monitor
        
    def get_rate_limit(self, ip: str) -> Optional[Dict]:
        try:
            response = self.reader.city(ip)
            country = response.country.iso_code
            
            # Check if country is blocked
            if country in self.blocked_countries:
                return None
            
            # Get country-specific limits or default
            limits = self.country_limits.get(country, self.country_limits['default'])
            
            # Check for suspicious ASNs
            asn = self.get_asn(ip)
            if asn in self.suspicious_asns:
                # Reduce limits for suspicious networks
                limits = {
                    'rate': limits['rate'] // 2,
                    'burst': limits['burst'] // 2
                }
            
            return limits
            
        except Exception as e:
            # Default limits for unknown IPs
            return self.country_limits['default']
    
    def is_ip_suspicious(self, ip: str) -> bool:
        """Check if IP exhibits suspicious characteristics"""
        checks = [
            self.is_datacenter_ip(ip),
            self.is_proxy_ip(ip),
            self.is_tor_exit_node(ip),
            self.has_poor_reputation(ip)
        ]
        
        return any(checks)
    
    def is_datacenter_ip(self, ip: str) -> bool:
        """Check if IP belongs to known datacenter ranges"""
        datacenter_ranges = [
            '104.16.0.0/12',  # Cloudflare
            '35.0.0.0/8',     # Google Cloud
            '52.0.0.0/8'      # AWS
        ]
        
        ip_obj = ip_address(ip)
        return any(ip_obj in ip_network(range) for range in datacenter_ranges)

# Integration with rate limiting
class EnhancedRateLimiter:
    def __init__(self, geo_limiter: GeographicRateLimiter):
        self.geo_limiter = geo_limiter
        self.ip_buckets = {}
        
    def check_rate_limit(self, ip: str, api_key: Optional[str] = None) -> Dict:
        # Get geographic limits
        geo_limits = self.geo_limiter.get_rate_limit(ip)
        if not geo_limits:
            return {'allowed': False, 'reason': 'Geographic restriction'}
        
        # Apply stricter limits for suspicious IPs
        if self.geo_limiter.is_ip_suspicious(ip):
            geo_limits['rate'] = min(geo_limits['rate'], 10)
            geo_limits['burst'] = min(geo_limits['burst'], 50)
        
        # Apply rate limiting with geographic limits
        return self.apply_token_bucket(ip, geo_limits['rate'], geo_limits['burst'])