Monitors the accuracy of RFC 8805 geofeeds by validating geolocation claims against third-party geolocation databases, routing tables, the UN/LOCODE location registry, and RIR whois data.
- Fetches geofeed CSVs — lists of IP prefixes with their claimed country, subdivision, and city.
- Looks up each prefix in multiple geolocation providers (MaxMind GeoLite2, IPinfo Lite, IP2Location Lite) and compares the results.
- Validates each location entry against the UN/LOCODE 2024-2 registry — checking that the city exists, belongs to the claimed country, and is in the correct subdivision.
- Checks each prefix for visibility in the global routing table using RIPE RIS whois dumps.
- Checks each prefix for a registered geofeed URL in RIR whois (RFC 9092/9632) using the geolocatemuch.com validated prefix list.
- Generates self-contained HTML reports with:
- Global accuracy statistics (by prefix and by address count)
- Per-location breakdown with expandable prefix details
- UN/LOCODE validation warnings per location
- Routing visibility indicators per prefix (visible / not visible / too specific)
- Geofeed in RIR indicators per prefix (matches / mismatches / not registered)
- Search by prefix or IP address
- Filter to show only inaccurate entries
- Generates a landing page (
index.html) with per-feed summary cards showing prefix count, accuracy, routing, UN/LOCODE, and Geofeed in RIR stats. - Sends Slack alerts on detected changes or issues (see Alerting).
| Network | Geofeed | Report |
|---|---|---|
| AWS (Official) | geo-ip-feed.csv | aws.html |
| Google Cloud | cloud_geofeed | gcp.html |
| Microsoft | geoloc-Microsoft.csv | microsoft.html |
| AWS (Christian Elsen) | aws-geofeed.txt | aws-ce.html |
| AS213151 | geofeed.as213151.net | as213151.html |
| Starlink | geoip.starlinkisp.net | starlink.html |
Note: The Microsoft feed is not a strict RFC 8805 geofeed — it uses a CSV with a header row and uppercase city names. The download URL is resolved dynamically from the Microsoft Download Center page on each run.
The reports are published via GitHub Pages and refreshed daily:
https://chriselsen.github.io/Geofeed-Monitor/
pip install -r requirements.txt
export MAXMIND_ACCOUNT_ID="<your_account_id>"
export MAXMIND_LICENSE_KEY="<your_license_key>"
export IPINFO_TOKEN="<your_token>"
export IP2LOCATION_TOKEN="<your_token>"
export ARIN_API_KEY="<your_api_key>" # optional, for ARIN bulk whois
python3 monitor-geofeed.pyProvider credentials are optional — if unset, that provider is skipped. Reports are written to aws.html, gcp.html, microsoft.html, aws-ce.html, as213151.html, starlink.html, and a landing page index.html.
| Provider | Database | Coverage |
|---|---|---|
| MaxMind | GeoLite2-City | Country + City |
| IPinfo | IPinfo Lite | Country only |
| IP2Location | DB3 Lite | Country + City |
| DB-IP | City Lite | Country + City |
| IPLocate | IP-to-Country | Country only (City when upgraded) |
Each geofeed location entry is validated against the official UN/LOCODE 2024-2 dataset. The following issues are flagged with a warning icon on the location row:
- City name not found anywhere in UN/LOCODE
- City found but not in the claimed country (e.g. Hong Kong claimed as
CNinstead ofHK) - City found in the correct country but wrong subdivision (e.g. Frankfurt am Main in
DE-RPinstead ofDE-HE)
City name matching is diacritic- and case-insensitive, and handles parenthetical alternate names (e.g. Helsinki (Helsingfors) matches Helsinki) and alias entries (e.g. Copenhagen = København matches Copenhagen).
Each prefix is checked against RIPE RIS whois dumps (updated every ~5 minutes), requiring visibility by at least 2 peers. A prefix is considered routed if:
- The exact prefix is announced, or
- A covering supernet is announced (e.g. geofeed has
/24, BGP has/23), or - A more-specific is announced (e.g. geofeed has
/23, BGP has/24)
Prefixes more specific than /24 (IPv4) or /48 (IPv6) are marked as too specific to appear in the global routing table and shown with a grey indicator.
Each prefix is checked against the geolocatemuch.com daily-updated validated prefix list (sourced from all RIR whois databases). If a prefix is found, its registered geofeed URL is retrieved via RDAP and compared to the monitored feed URL. Results are cached locally to avoid repeated RDAP queries.
Per-prefix indicators:
- 🟢 Green shield — geofeed URL in RIR whois matches the monitored feed URL
- 🟡 Amber shield — geofeed URL in RIR whois points to a different URL
- ⚫ Grey shield — no geofeed entry found in RIR whois
Per-location summary icons reflect the proportion of prefixes with registered geofeed entries.
This check is opt-in per feed via the check_rdap config key. Currently enabled for: AWS (Official), AS213151.
Slack alerts are sent via webhooks on a per-feed, per-alert-type basis. Each alert type has a fixed JSON schema for use with Slack Workflows.
| Type | Trigger | Key fields |
|---|---|---|
UNREACHABLE |
Feed URL failed to load | feed, url |
EMBARGO |
Location claims a sanctioned country | feed, location, country, prefix_count, prefixes |
NEW_LOCATION |
A new location group appeared | feed, location, country, prefix_count, prefixes |
REMOVED_LOCATION |
A previously known location is gone | feed, location, country, prefix_count, prefixes |
NEW_PREFIX |
Prefixes added to an existing location | feed, location, country, prefix_count, prefixes |
REMOVED_PREFIX |
Prefixes removed from an existing location | feed, location, country, prefix_count, prefixes |
ACCURACY_DROP |
Country or city accuracy dropped ≥5pp or fell below 80% | feed, location, metric, previous_pct, current_pct, drop_pp |
UNROUTED |
A previously routed prefix is no longer visible | feed, prefix, proto |
LOCODE |
A new UN/LOCODE violation was introduced | feed, prefix, location, issue |
Webhooks are resolved per feed and alert type with a fallback chain:
SLACK_WEBHOOK_<FEED>_<TYPE> → SLACK_WEBHOOK_<TYPE>
Where <FEED> is the feed's output filename uppercased (e.g. AWS, GCP, MICROSOFT, STARLINK) and <TYPE> is one of the alert types above.
Example — AWS embargo alerts with global fallback:
SLACK_WEBHOOK_AWS_EMBARGO (feed-specific)
SLACK_WEBHOOK_EMBARGO (global fallback)
Sanctioned countries default to the OFAC comprehensive list: IR, CU, KP, SY. This can be overridden per feed via the embargo_countries config key. The AWS Official feed uses an extended list that also includes RU and BY.
Alert state is stored in state/<feed>.json and committed to the repository by the GitHub Action after each run. This tracks known locations, prefixes, routing status, and LOCODE issues to detect changes between runs.
This project is for monitoring purposes. The geolocation databases are subject to their respective licenses.