Skip to content

fix: handle private IP addresses gracefully in geo lookups#63

Merged
jloh merged 1 commit into
mainfrom
fix/private-ip-handling
Feb 8, 2026
Merged

fix: handle private IP addresses gracefully in geo lookups#63
jloh merged 1 commit into
mainfrom
fix/private-ip-handling

Conversation

@jloh

@jloh jloh commented Feb 7, 2026

Copy link
Copy Markdown
Owner

Summary

  • Fix error logging when looking up private/reserved IP addresses via the ip= query parameter
  • Add is_private_ip() function to detect RFC1918, loopback, link-local, and IPv6 private address ranges
  • Skip MaxMind DB lookup for private IPs to avoid "not found" errors

Problem

Previously, looking up private IP addresses via query parameters (e.g., /v1/ip/geo.json?ip=10.10.123.190) would cause error logs:

[error] [lua] utils.lua:240: geoip_lookup(): Error with Geo DB: not found
[error] [lua] utils.lua:243: geoip_lookup(): Error with ASN DB: not found

This is because MaxMind databases don't contain data for private/reserved addresses.

Solution

  1. Add is_private_ip() function that detects:

    • RFC1918 ranges: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16
    • Loopback: 127.0.0.0/8
    • Link-local: 169.254.0.0/16
    • IPv6 loopback: ::1
    • IPv6 unique local: fc00::/7 (fc00:: and fd00::)
    • IPv6 link-local: fe80::/10
  2. Modify geoip_lookup() to skip MaxMind lookup for private IPs and return default values directly

  3. Update country_lookup() to return empty strings instead of nil for missing country data (prevents nil concatenation errors)

Affected Endpoints

All endpoints using ip= query parameter:

  • /v1/ip/country?ip=...
  • /v1/ip/country.json?ip=...
  • /v1/ip/country.js?ip=...
  • /v1/ip/country/full?ip=...
  • /v1/ip/geo.json?ip=...
  • /v1/ip/geo.js?ip=...

Test plan

  • Add unit tests for is_private_ip() function (tests 19-24)
  • Add tests for geoip_lookup with private IPs (tests 25-27)
  • Add integration tests for country endpoints with private IPs (tests 7-10)
  • Add integration tests for geo endpoints with private IPs (tests 5-9)
  • All 302 tests pass

Previously, looking up private/reserved IP addresses (10.x.x.x,
172.16-31.x.x, 192.168.x.x, 127.0.0.1, etc.) via the ip= query
parameter would cause error logs because MaxMind databases don't
contain data for these addresses.

Changes:
- Add is_private_ip() function to detect RFC1918, loopback, link-local,
  and IPv6 private/reserved address ranges
- Modify geoip_lookup() to skip MaxMind DB lookup for private IPs and
  return default values directly
- Update country_lookup() to return empty strings instead of nil for
  missing country data

This prevents unnecessary error logs like:
  "Error with Geo DB: not found"
  "Error with ASN DB: not found"

Fixes handling for endpoints:
- /v1/ip/country?ip=...
- /v1/ip/country.json?ip=...
- /v1/ip/country.js?ip=...
- /v1/ip/country/full?ip=...
- /v1/ip/geo.json?ip=...
- /v1/ip/geo.js?ip=...
@jloh
jloh force-pushed the fix/private-ip-handling branch from 4075bf7 to 7874b2f Compare February 8, 2026 06:20
@jloh
jloh merged commit 7874b2f into main Feb 8, 2026
1 check passed
@jloh
jloh deleted the fix/private-ip-handling branch February 8, 2026 06:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant