Skip to content

Add an optional IP-to-country lookup behind a cmake option - #147

Open
jagerman wants to merge 1 commit into
session-foundation:clientfrom
jagerman:ip-country
Open

Add an optional IP-to-country lookup behind a cmake option#147
jagerman wants to merge 1 commit into
session-foundation:clientfrom
jagerman:ip-country

Conversation

@jagerman

Copy link
Copy Markdown
Member

Every client draws a path screen naming the country of each hop, and each of them currently ships and maintains its own geo database to do it. This puts the lookup upstream: session::ip_country::lookup(ipv4) returns an ISO 3166-1 alpha-2 code, with available(), attribution() and database_version() alongside it.

It is off by default. With WITH_IP_GEOLOCATION off the compiled-in database is an empty one rather than absent, so every lookup misses and a client needs no #ifdef of its own; available() is a link-time fact, not a macro, so nothing about the option reaches a header. data.cpp and no_data.cpp define the same accessors and the lookup itself is identical either way -- only the table it searches differs.

DB-IP Lite is the source, chosen over MaxMind's GeoLite2 on licensing rather than accuracy: CC BY 4.0 permits redistribution and has no clause requiring a copy to stay current, which is what makes a bundled snapshot viable at all. Its IPv4 rows already tile the address space with no gaps and no mergeable neighbours, so a range needs only its first address -- the next range's start ends it. That leaves parallel arrays of 357k ipv4 starts and uint8_t country indices plus a 246-entry code table: 5 bytes a range, 1.79MB, of which a binary search touches only the 1.43MB of starts.

The codes are numbered by descending range count. The countries holding the most ranges get the shortest indices, which is worth ~0.4MB of generated source, and the rare countries -- the ones that come and go between releases -- land at the end where nothing follows them to renumber. Numbering them alphabetically instead rewrote 86% of the table across the Aug->Sep refresh, where two mid-alphabet countries disappeared; this ordering rewrote 9%.

The generated table is not committed: utils/update-ip-country-db.py downloads a release and generates it, and cmake refuses to configure with the option on until it has been run. Nothing downloads during a build. The tests run in both configurations and check the mechanism -- table invariants, range boundaries, the unknown path -- rather than pinning countries, save for one anchor commented as expected to move when the snapshot does.

Every client draws a path screen naming the country of each hop, and each
of them currently ships and maintains its own geo database to do it.  This
puts the lookup upstream: session::ip_country::lookup(ipv4) returns an ISO
3166-1 alpha-2 code, with available(), attribution() and database_version()
alongside it.

It is off by default.  With WITH_IP_GEOLOCATION off the compiled-in database
is an empty one rather than absent, so every lookup misses and a client needs
no #ifdef of its own; available() is a link-time fact, not a macro, so nothing
about the option reaches a header.  data.cpp and no_data.cpp define the same
accessors and the lookup itself is identical either way -- only the table it
searches differs.

DB-IP Lite is the source, chosen over MaxMind's GeoLite2 on licensing rather
than accuracy: CC BY 4.0 permits redistribution and has no clause requiring a
copy to stay current, which is what makes a bundled snapshot viable at all.
Its IPv4 rows already tile the address space with no gaps and no mergeable
neighbours, so a range needs only its first address -- the next range's start
ends it.  That leaves parallel arrays of 357k ipv4 starts and uint8_t country
indices plus a 246-entry code table: 5 bytes a range, 1.79MB, of which a
binary search touches only the 1.43MB of starts.

The codes are numbered by descending range count.  The countries holding the
most ranges get the shortest indices, which is worth ~0.4MB of generated
source, and the rare countries -- the ones that come and go between releases
-- land at the end where nothing follows them to renumber.  Numbering them
alphabetically instead rewrote 86% of the table across the Aug->Sep refresh,
where two mid-alphabet countries disappeared; this ordering rewrote 9%.

The generated table is not committed: utils/update-ip-country-db.py downloads
a release and generates it, and cmake refuses to configure with the option on
until it has been run.  Nothing downloads during a build.  The tests run in
both configurations and check the mechanism -- table invariants, range
boundaries, the unknown path -- rather than pinning countries, save for one
anchor commented as expected to move when the snapshot does.
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.

2 participants