Files
kmtnflower/backend/probe_geo.py
T

201 lines
5.6 KiB
Python

"""Probe the GeoLite2 database to find IPs that resolve to real countries.
Run inside the api container:
docker compose exec api python /app/probe_geo.py
Or locally if the DB is present:
python probe_geo.py /path/to/GeoLite2-City.mmdb
Tests a curated list of well-known public IPs and prints the ones that resolve.
"""
import sys
import json
import os
import maxminddb
# Well-known public IPs from various countries
CANDIDATE_IPS = [
# United States
("23.21.30.100", "US"),
("72.14.198.234", "US"),
("68.49.71.1", "US"),
("208.67.222.222", "US"), # OpenDNS
("74.125.200.100", "US"), # Google
("151.101.1.69", "US"), # Fastly
("142.250.80.46", "US"), # Google
("216.58.214.206", "US"), # Google
("172.217.164.110", "US"), # Google
("13.107.42.14", "US"), # Microsoft
("20.190.128.1", "US"), # Microsoft
("52.84.74.1", "US"), # AWS CloudFront
("99.86.0.1", "US"), # AWS
# United Kingdom
("81.2.69.142", "GB"),
("212.58.224.10", "GB"),
("51.140.137.15", "GB"),
("178.173.57.1", "GB"),
# France
("51.140.137.15", "FR"),
("193.70.150.1", "FR"),
# Japan
("210.170.232.46", "JP"),
("133.244.200.1", "JP"),
("202.214.69.1", "JP"), # NTT
("210.188.206.1", "JP"), # Softbank
# Germany
("217.160.0.1", "DE"),
("212.227.156.1", "DE"),
("2a02:2e0::1", "DE"), # IPv6 - may not resolve
("217.69.70.1", "DE"),
# Australia
("101.168.100.1", "AU"),
("203.50.224.1", "AU"),
("1.35.128.1", "AU"), # Telstra
# Brazil
("177.72.120.1", "BR"),
("200.149.130.1", "BR"),
("189.75.1.1", "BR"),
# Canada
("76.69.248.1", "CA"),
("24.199.12.1", "CA"),
("99.248.1.1", "CA"), # Bell
# India
("117.239.1.1", "IN"),
("180.151.1.1", "IN"),
("106.192.1.1", "IN"),
# South Korea
("1.235.198.1", "KR"),
("211.36.1.1", "KR"),
# Netherlands
("185.30.1.1", "NL"),
("94.23.1.1", "NL"),
# Mexico
("189.203.1.1", "MX"),
("200.44.1.1", "MX"),
# Italy
("217.20.1.1", "IT"),
("93.45.1.1", "IT"),
# Spain
("213.99.1.1", "ES"),
("88.0.1.1", "ES"),
# Sweden
("213.248.1.1", "SE"),
# Poland
("79.133.1.1", "PL"),
# Argentina
("190.15.1.1", "AR"),
# South Africa
("196.201.1.1", "ZA"),
# Egypt
("213.53.1.1", "EG"),
# Turkey
("37.146.1.1", "TR"),
# Russia
("77.88.55.1", "RU"), # Yandex DNS
("5.255.255.1", "RU"),
]
def probe(db_path: str):
"""Test each candidate IP against the GeoLite2 database."""
reader = maxminddb.open_database(db_path)
results = []
# Deduplicate IPs but keep all expected countries
seen_ips = set()
for ip, expected_country in CANDIDATE_IPS:
if ip in seen_ips:
continue
seen_ips.add(ip)
try:
result = reader.lookup(ip)
if result is None:
continue
country = result.get("country", {})
city = result.get("city", {})
location = result.get("location", {})
country_code = country.get("iso_code", "")
country_name = country.get("names", {}).get("en", country_code)
city_name = city.get("names", {}).get("en", "")
lat = location.get("latitude")
lon = location.get("longitude")
results.append({
"ip": ip,
"country": country_name,
"country_code": country_code,
"city": city_name,
"latitude": lat,
"longitude": lon,
})
except Exception as e:
print(f" ERROR looking up {ip}: {e}")
reader.close()
return results
def main():
# Determine DB path
db_path = None
if len(sys.argv) > 1:
# Explicit path provided
db_path = sys.argv[1]
else:
# Try common locations
candidates = [
"/app/geo/GeoLite2-City.mmdb", # container path
os.path.join(os.path.dirname(__file__), "geo", "GeoLite2-City.mmdb"), # local
]
for p in candidates:
if os.path.exists(p):
db_path = p
break
if db_path is None:
print("GeoLite2-City.mmdb not found.")
print("Usage:")
print(" docker compose exec api python /app/probe_geo.py")
print(" python probe_geo.py /path/to/GeoLite2-City.mmdb")
sys.exit(1)
print(f"Probing GeoLite2 at: {db_path}")
results = probe(db_path)
if not results:
print("No IPs resolved! The database might be empty or outdated.")
sys.exit(1)
print(f"\nResolved {len(results)} IPs:\n")
# Group by country
by_country = {}
for r in results:
by_country.setdefault(r["country_code"], []).append(r)
for cc in sorted(by_country.keys()):
entries = by_country[cc]
print(f" {cc} ({entries[0]['country']}):")
for e in entries:
print(f" {e['ip']:20s} -> {e['city'] or 'N/A':20s} ({e['latitude']}, {e['longitude']})")
# Output as Python tuples for inject_test_logs.py
print(f"\n\nTuples for inject_test_logs.py TEST_IPS:")
print("TEST_IPS = [")
for r in results:
print(f' ("{r["ip"]}", "{r["country"]}", "{r["city"]}"),')
print("]")
# Also output JSON for convenience
print(f"\nJSON output:")
print(json.dumps(results, indent=2))
if __name__ == "__main__":
main()