Class: Otto::Privacy::GeoResolver
- Inherits:
-
Object
- Object
- Otto::Privacy::GeoResolver
- Defined in:
- lib/otto/privacy/geo_resolver.rb
Overview
Lightweight geo-location resolution for IP addresses
Provides country-level geo-location without requiring external databases or API calls. Supports headers from major CDN/infrastructure providers (Cloudflare, AWS CloudFront, Fastly, Akamai, Azure) with fallback to basic IP range detection.
Supported CDN/Infrastructure Headers:
-
Cloudflare: CF-IPCountry
-
AWS CloudFront: CloudFront-Viewer-Country
-
Fastly: Fastly-Client-IP-Country
-
Akamai: X-Akamai-Edgescape (country_code=XX format)
-
Azure Front Door: X-Azure-ClientIP-Country
-
Semi-standard: X-Geo-Country, X-Country-Code, Country-Code
Resolution flow
Request → Has familiar HTTP Header?
├─ Yes → Return country (Cloudflare, AWS, etc.)
└─ No → Custom Resolver?
├─ Configured → Call & validate
│ ├─ Valid → Return country
│ └─ Invalid/Error → Continue
└─ Not configured → Built-in range detection
└─ Unknown ('**')
Constant Summary collapse
- UNKNOWN =
Unknown country code (not ISO 3166-1 alpha-2, intentionally distinct)
'**'- KNOWN_RANGES =
Known IP ranges for major providers (limited set for basic detection) For comprehensive geo-location, use CDN headers or custom resolver
{ # Google Public DNS IPAddr.new('8.8.8.0/24') => 'US', IPAddr.new('8.8.4.0/24') => 'US', # Cloudflare DNS IPAddr.new('1.1.1.0/24') => 'US', IPAddr.new('1.0.0.0/24') => 'US', # AWS US-East IPAddr.new('52.0.0.0/11') => 'US', IPAddr.new('54.0.0.0/8') => 'US', # AWS EU-West IPAddr.new('34.240.0.0/13') => 'IE', IPAddr.new('52.16.0.0/14') => 'IE', # AWS AP-Southeast IPAddr.new('13.210.0.0/15') => 'AU', IPAddr.new('52.62.0.0/15') => 'AU', # Quad9 DNS (Switzerland) IPAddr.new('9.9.9.0/24') => 'CH', # OpenDNS IPAddr.new('208.67.222.0/24') => 'US', IPAddr.new('208.67.220.0/24') => 'US', }.freeze
Class Attribute Summary collapse
-
.custom_resolver ⇒ Object
Returns the value of attribute custom_resolver.
Class Method Summary collapse
-
.resolve(ip, env = {}) ⇒ String
Resolve country code for an IP address.
Class Attribute Details
.custom_resolver ⇒ Object
Returns the value of attribute custom_resolver.
98 99 100 |
# File 'lib/otto/privacy/geo_resolver.rb', line 98 def custom_resolver @custom_resolver end |
Class Method Details
.resolve(ip, env = {}) ⇒ String
Resolve country code for an IP address
Resolution priority:
-
CDN/infrastructure provider headers (Cloudflare, AWS, Fastly, etc.)
-
Basic IP range detection for major countries/providers
-
Return ‘**’ for unknown
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
# File 'lib/otto/privacy/geo_resolver.rb', line 127 def self.resolve(ip, env = {}) return UNKNOWN if ip.nil? || ip.empty? # Check CDN/infrastructure headers in priority order # Priority based on reliability and deployment frequency country = check_geo_headers(env) return country if country # Try custom resolver if configured if @custom_resolver begin country = @custom_resolver.call(ip, env) return country if country && valid_country_code?(country) rescue StandardError => e # Log error but don't crash - fall through to built-in detection warn "GeoResolver custom resolver error: #{e.}" if $DEBUG end end # Fallback: Basic range detection detect_by_range(ip) rescue IPAddr::InvalidAddressError UNKNOWN end |