Skip to content

Fix header_rewrite MaxMind geo lookups for GeoIP2/GeoLite2 mmdb databases#12948

Open
bryancall wants to merge 8 commits intoapache:masterfrom
bryancall:fix-header-rewrite-maxmind-geo
Open

Fix header_rewrite MaxMind geo lookups for GeoIP2/GeoLite2 mmdb databases#12948
bryancall wants to merge 8 commits intoapache:masterfrom
bryancall:fix-header-rewrite-maxmind-geo

Conversation

@bryancall
Copy link
Contributor

@bryancall bryancall commented Mar 6, 2026

Problem

The header_rewrite plugin's MaxMind geo lookup code used incorrect MMDB
field paths that don't match the structure of standard MaxMind GeoIP2
databases (GeoLite2, GeoIP2, DBIP). All geo lookups (%{GEO:COUNTRY},
%{GEO:ASN}, %{GEO:ASN-NAME}) returned (unknown) or -1 even
when the mmdb file loaded successfully. The code queried flat field names
like "country_code" that don't exist -- these databases use nested
structures like country -> iso_code.

Changes

  • Fix country code lookup -- change GEO_QUAL_COUNTRY from flat
    "country_code" to nested "country", "iso_code" path, returning
    the ISO country code (e.g. "KR", "US") consistent with the old GeoIP
    backend's GeoIP_country_code_by_ipnum() behavior
  • Fix null-after-delete bug in initLibrary -- set
    gMaxMindDB = nullptr after delete on MMDB_open failure to
    avoid leaving a dangling global pointer
  • Add data validation -- check entry_data.has_data and
    entry_data.type before accessing entry values to avoid reading
    uninitialized data
  • Remove unnecessary MMDB_get_entry_data_list allocation -- the
    MMDB_get_value() API works directly from result.entry, so the
    expensive list allocation/traversal was unnecessary overhead on every
    geo lookup
  • Add MMDB path validation unit test -- verifies the nested lookup
    paths against a real MaxMind/DBIP database with gai_error checking;
    skips gracefully when no MMDB file is available

Testing

  • Standalone MMDB test program verified field paths against DBIP
    Country Lite and ASN Lite databases on eris (ASAN build)
  • Korean IP (1.201.194.27): COUNTRY: KR
  • Google DNS (8.8.8.8): COUNTRY: US
  • ASN db (1.201.194.27): ASN-NAME: KINX, ASN: 9286
  • Loopback (127.0.0.1): correctly returns (unknown) / -1
  • mmdblookup confirms paths match database structure

Fixes: #11812

The MaxMind geo lookup code used incorrect field paths that don't match
the structure of standard GeoLite2 and DBIP mmdb databases. Country
lookups used a flat "country_code" field that doesn't exist; the correct
path is "country" -> "names" -> "en" for country name and "country" ->
"iso_code" for the ISO code.

Changes:
- Fix GEO_QUAL_COUNTRY to use nested path "country/names/en"
- Add missing GEO_QUAL_COUNTRY_ISO support using "country/iso_code"
- Add has_data and type checks before accessing entry data
- Fix memory leak: set gMaxMindDB to nullptr after delete on open failure
- Ensure entry_data_list is freed on all code paths

Verified with DBIP Country Lite and ASN Lite databases using the same
MMDB_get_value paths. Matches the field paths used by maxmind_acl plugin.

Fixes: apache#11812
@bryancall bryancall added this to the 11.0.0 milestone Mar 6, 2026
@bryancall bryancall self-assigned this Mar 6, 2026
@bryancall bryancall added Bug header_rewrite header_rewrite plugin labels Mar 6, 2026
@bryancall
Copy link
Contributor Author

[approve ci autest 1]

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the header_rewrite plugin’s MaxMind (MMDB) geo lookup implementation to better match the field layout used by standard GeoLite2 / DBIP databases, and improves cleanup/error-handling around lookups and initialization.

Changes:

  • Adjust MMDB lookup paths for geo string fields and add handling for GEO_QUAL_COUNTRY_ISO in the string lookup function.
  • Improve robustness by validating entry_data before reading values and ensuring MMDB entry data lists are freed on more return paths.
  • Fix a retry reliability issue by nulling gMaxMindDB after delete on MMDB_open() failure.

You can also share your feedback on Copilot code review. Take the survey.

- GEO_QUAL_COUNTRY now returns iso_code ("KR") instead of English
  name ("South Korea"), matching the GeoIP backend behavior
- Remove dead GEO_QUAL_COUNTRY_ISO case from get_geo_string() since
  the dispatcher routes it to get_geo_int()
- Remove unnecessary MMDB_get_entry_data_list() allocation -- the
  MMDB_get_value() API works directly from result.entry
@bryancall bryancall changed the title Fix header_rewrite MaxMind geo lookups for standard mmdb databases Fix header_rewrite MaxMind geo lookups for GeoIP2/GeoLite2 mmdb databases Mar 6, 2026
Adds a test that verifies the MMDB lookup paths used by the
geo conditions (country/iso_code, country/names/en) work correctly
against a real MaxMind or DBIP database. The test skips gracefully
if no MMDB file is available, and can be pointed at a specific file
via MMDB_COUNTRY_PATH environment variable.
zwoop
zwoop previously approved these changes Mar 9, 2026
Copy link
Contributor

@zwoop zwoop left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. I made a comment, but it's no big deal.

@bryancall bryancall requested a review from cmcfarlen March 9, 2026 22:16
Check gai_error from MMDB_lookup_string() in the unit test instead of
silently ignoring it (per zwoop review comment). Add comments explaining
the nested MMDB field paths, nullptr-after-delete fix, data type
validation guards, and the dual error code API.
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.


You can also share your feedback on Copilot code review. Take the survey.

@bryancall
Copy link
Contributor Author

[approve ci autest 0]

@bryancall bryancall requested a review from zwoop March 11, 2026 19:56
zwoop
zwoop previously approved these changes Mar 11, 2026
Some vendor MMDB databases use flat top-level fields (country_code),
while standard GeoLite2/GeoIP2/DBIP databases use nested paths
(country/iso_code).  Detect the schema on the first successful lookup
by probing for the nested path first, then falling back to flat.
Cache the result in an atomic for the process lifetime.

Add a Python script to generate test MMDB files with both schemas,
and rewrite the unit test to verify lookups work against both.
Probe the database at load time with well-known IPs (8.8.8.8, 1.1.1.1,
128.0.0.1) instead of detecting lazily on first lookup.  Removes the
need for std::atomic and simplifies the hot path.
@bryancall bryancall requested a review from zwoop March 12, 2026 22:26
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 7 comments.


You can also share your feedback on Copilot code review. Take the survey.

- Check for mmdb-writer/netaddr Python modules at CMake configure time
  before adding the MMDB generation target (prevents Ninja failures when
  declared outputs are not produced)
- Exit non-zero from generate_test_mmdb.py on missing dependencies
- Fix skip message to mention both required packages (mmdb-writer netaddr)
- Add missing <cstdlib> include for getenv()
- Remove unused <arpa/inet.h> and <netdb.h> includes from test file
@bryancall
Copy link
Contributor Author

[approve ci autest 2]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Bug header_rewrite header_rewrite plugin

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ATS 10.0.0, header_rewrite plugin does not work with geoip file (maxmind mmdb)

3 participants