The lookup is expensive, so a lookup is queued with add(). The actual lookup of multiple IPs is fired with lookup(). To get a country for an IP, use get() which returns a lower-case, generally two-letter country code or null.
Everything here uses longs, since Java is signed-only, the file is sorted by unsigned, and we don't store the table in memory (unlike in Blocklist.java, where it's in-memory so we want to be space-efficient).
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionprivate classRuns the GeoIP lookups for the console.Field Summary
Modifier and TypeFieldDescriptionprivate ReaderReader for the ASN to organization name lookups.Countries treated as one, by country code.private static BanLoggerRecords why routers were banned.Code to itself to prevent String proliferation.Country names, by country code.private final I2PAppContextThe app context.private static final ThreadLocal<DateFormat> Formats a database build date for the console, e.g.Country codes, keyed by the IP: an IPv4 address as a non-negative long, the first 8 bytes of an IPv6 address as a signed long.private final AtomicBooleanTrue while a lookup run is in progress.private final LogLogger for the GeoIP lookups.private intLookups run in the current batch.Addresses searched already without a result.IPv6 addresses queued for lookup.IPv4 addresses queued for lookup.private static final PatternSingle combined abbreviation pattern.Abbreviation map for verbose words.private static final PatternPrecompiled pattern for short all-caps acronym detection.Known broken org names in the MaxMind ASN DB — straight replacements.private static final PatternEmbedded ASN numbers (e.g.static final StringDefault MaxMind ASN database file name.private static final PatternMatches a trailing AS number in an organization name.Brand names that should keep their exact casing.private static final PatternChina carrier network labels and region designators to drop (China169 backbone, IP Network, Province, Municipality, Autonomous Region); leftover spaces are collapsed by the DOUBLE_SPACE step below.(package private) static final StringDefault country names file name.private static final PatternNormalize mangled dash separators: "hosted- -vdsina" → "hosted - vdsina".private static final StringDebian's IPv4 GeoIP database path.private static final StringDebian's IPv6 GeoIP database path.private static final booleanDeveloper switch disabling the Debian databases.private static final PatternMatches doubled commas in an organization name.private static final PatternMatches doubled spaces in an organization name.private static final booleanSystemVersion.isAndroid()) True where the Debian databases are usable.private static final PatternFiller prepositions/articles to drop.private static final PatternFiller words that can be trimmed from long names.static final StringDefault GeoIP directory, under the router's base directory.(package private) static final StringDefault geoip file name.static final StringGEOIP2_FILE_DEFAULT.Words to keep uppercase.Common org/internet words used to detect character-reversed names.private static final PatternLeading/trailing junk.private static final PatternLeading/trailing punctuation trim.private static final intCap for _IPToCountry to prevent unbounded growth.private static final PatternPaired single quotes around text (e.g.private static final PatternParentheticals to strip (anywhere, not just trailing).static final StringProperty: whether to refuse tunnels to destinations in our own country.static final StringProperty: the Debian-packaged IPv4 GeoIP database path.static final StringPROP_DEBIAN_GEOIPV6.static final StringProperty: the directory the GeoIP databases are read from.(package private) static final StringProperty: whether GeoIP lookups are enabled.static final StringProperty: the last country an IP was seen in, set for the console.(package private) static final StringNormalize ISP/org names from ASN database (strip suffixes, abbreviate, title-case).private static final PatternNames that should be returned as-is — single combined pattern vs array.private static final PatternWhitespace split.private static final PatternVerbose prefixes to strip — single combined alternation (3→1).private static final PatternSuffixes to strip from org names — single combined alternation (44→1).private static final PatternMatches trailing punctuation in an organization name.private static final PatternTrailing generic words to drop (redundant suffixes like "Communications", "Services").private static final StringMaxmind API.private static final StringUnknown code from db-ip.com (https://db-ip.com/faq.php).Vodafone regional brand aliases that are not country names.Vodafone subsidiaries: "Vodafone <Country>" names, longest first so a multi-word country matches before a shorter prefix of it.Constructor Summary
ConstructorsMethod Summary
Modifier and TypeMethodDescriptionvoidadd(byte[] ip) Add to the list needing lookup Public for BundleRouterInfos.private voidadd(long ip) See above for ip-to-long mapping.voidAdd to the list needing lookup Public for BundleRouterInfos.private static StringapplyAbbreviation(String name) Single-pass abbreviation replacement (was 29× replaceAll).static voidbanCountry(RouterContext ctx, String country) Bans routers located in a specified country.voidBlocking lookup of all pending IPs.private static StringCollapse "Vodafone <Country> ..." names, with corporate-suffix cruft from truncated MaxMind entries, to just "Vodafone <Country>".private static intcountKnownWordMatches(String text) Count how many space-separated words match known words.private voidcountryToIP(String country) Write all IP ranges for country to blocklist-country.txt.private static intcountTitleCaseWords(String text) Count words starting with uppercase (title-case signal for proper org names).private static StringFirst whitespace-delimited word of a string with trailing punctuation stripped, or the whole string.private static StringfixReversedWords(String name) Detect and fix character-reversed words from MaxMind ASN DB.The untranslated country name for a country code.(package private) Stringget(byte[] ip) The country for an IP from the cache.private Stringget(long ip) The country for an IP from the cache.The country for an IP from the cache.private FilegetASN()The ASN database file to use.Return the current ASN database version.The country code map.private FileThe GeoIP2 database file to use.Return the country database's build date, size and path, for the console.getOrgName(String ipAddress) The organization name for an IP from the local ASN database.private static booleanlooksReversed(String word) A word looks reversed if: 1.static StringnormalizeOrgName(String raw) Normalize an ISP/org name from the ASN database.private voidnotifyVersion(String subtype, long version) Tell the update manager.(package private) static voidnotifyVersion(I2PAppContext ctx, String subtype, long version) Tell the update manager.(package private) static voidnotifyVersion(I2PAppContext ctx, String subtype, String version) Tell the update manager, with a version string as-is, e.g.private ReaderopenASN()Open the ASN database reader (lazy, cached).private DatabaseReaderopenGeoIP2(File geoFile) Open a GeoIP2 database.private voidRead in and parse the country file.private String[]readGeoIPFile(Long[] search) Read in and parse the geoip file.private static StringreverseWord(String word) Reverse a single word.private static intscoreCandidate(String text) Score a candidate by known-word matches (weighted 3x) plus title-case word count.voidshutdown()Shutdown and release resources.private static StringswapFirstLastCase(String word) Swap the case of the first and last characters of a word.private static StringtitleCasePreserve(String name) Title-case a name while preserving acronyms and brand names.private static longtoLong(byte[] ip) Convert an address to the long form used as the cache key.private static StringtoV4(long ip) The given IPv4 as a dotted-quad string.private static StringtoV6(long ip) The given IPv6 as a hex string.private static StringtryCaseSwap(String[] words) Try swapping the case of first and last characters in each word.private static StringtryFixAsTrading(String name, String allWordReversed) Detect "as trading" pattern (lowercase), a strong signal that word order is reversed.private static StringtryFullStringReversal(String name) Try reversing the entire string as one block (for compound words).private static StringtryFullWordReversal(String[] words) Reverse every word at character level unconditionally.private static StringIf text contains "as trading", reverse word order and check for "trading as".private static StringtryWordOrderReversal(String name) Reverse the order of words.private static StringtryWordReversal(String[] words) Try reversing individual words that look reversed (lowercase start, uppercase end).private voidupdateOurCountry(long ts) Put our country code in the config, where others (such as Timestamper) can get it, and it will be there next time at startup.
Field Details
_log
Logger for the GeoIP lookups._context
The app context._banLogger
Records why routers were banned._codeToName
_codeCache
_IPToCountry
MAX_IP_CACHE_SIZE
private static final int MAX_IP_CACHE_SIZECap for _IPToCountry to prevent unbounded growth.- See Also:
_pendingSearch
_pendingIPv6Search
_notFound
_lock
True while a lookup run is in progress._lookupRunCount
private int _lookupRunCountLookups run in the current batch._associatedCountries
_asnReader
Reader for the ASN to organization name lookups.PROP_GEOIP_ENABLED
Property: whether GeoIP lookups are enabled.- See Also:
PROP_NORMALIZE_ISP
Normalize ISP/org names from ASN database (strip suffixes, abbreviate, title-case).- See Also:
PROP_GEOIP_DIR
Property: the directory the GeoIP databases are read from.- See Also:
GEOIP_DIR_DEFAULT
Default GeoIP directory, under the router's base directory.- See Also:
GEOIP_FILE_DEFAULT
GEOIP2_FILE_DEFAULT
ASN_FILE_DEFAULT
Default MaxMind ASN database file name.- See Also:
COUNTRY_FILE_DEFAULT
Default country names file name.- See Also:
PROP_IP_COUNTRY
Property: the last country an IP was seen in, set for the console.- See Also:
PROP_DEBIAN_GEOIP
Property: the Debian-packaged IPv4 GeoIP database path.- See Also:
PROP_DEBIAN_GEOIPV6
DEBIAN_GEOIP_FILE
Debian's IPv4 GeoIP database path.- See Also:
DEBIAN_GEOIPV6_FILE
Debian's IPv6 GeoIP database path.- See Also:
DISABLE_DEBIAN
private static final boolean DISABLE_DEBIANDeveloper switch disabling the Debian databases.- See Also:
ENABLE_DEBIAN
private static final boolean ENABLE_DEBIANSystemVersion.isAndroid()) True where the Debian databases are usable.PROP_BLOCK_MY_COUNTRY
Property: whether to refuse tunnels to destinations in our own country.- See Also:
UNKNOWN_COUNTRY_CODE
UNKNOWN_COUNTRY_CODE2
Unknown code from db-ip.com (https://db-ip.com/faq.php).- See Also:
ASN_DB_OVERRIDES
KNOWN_WORDS
SUFFIX_ALL
Suffixes to strip from org names — single combined alternation (44→1).KEEP_UPPER
BRAND_NAMES
VODAFONE_COUNTRIES
VODAFONE_ALIASES
TRAILING_VERBOSE
Trailing generic words to drop (redundant suffixes like "Communications", "Services").CHINA_VERBOSE
China carrier network labels and region designators to drop (China169 backbone, IP Network, Province, Municipality, Autonomous Region); leftover spaces are collapsed by the DOUBLE_SPACE step below.ABBREV_MAP
ABBREV_ALL
Single combined abbreviation pattern.FILLER_DROP
Filler prepositions/articles to drop.ASN_EMBEDDED
Embedded ASN numbers (e.g. AS12345).ASN_TRAILING
Matches a trailing AS number in an organization name.PAIRED_SINGLE_QUOTES
Paired single quotes around text (e.g. 'TIMEWEB') — keeps internal apostrophes like O'Brien.PAREN_ALL
Parentheticals to strip (anywhere, not just trailing).DASH_SPACE_DASH
Normalize mangled dash separators: "hosted- -vdsina" → "hosted - vdsina".LEADING_JUNK
Leading/trailing junk.TRAILING_JUNK
Matches trailing punctuation in an organization name.DOUBLE_COMMA
Matches doubled commas in an organization name.DOUBLE_SPACE
Matches doubled spaces in an organization name.SPACE_SPLIT
Whitespace split.LEADING_TRAILING_JUNK
Leading/trailing punctuation trim.STRIP_PREFIX_ALL
Verbose prefixes to strip — single combined alternation (3→1).FILLER_WORDS
Filler words that can be trimmed from long names.ACRONYM_PATTERN
Precompiled pattern for short all-caps acronym detection.SKIP_ALL
Names that should be returned as-is — single combined pattern vs array._GEOIP_DATE_FORMAT
Formats a database build date for the console, e.g. "Oct 22, 2026". One formatter per thread, as SimpleDateFormat is not thread-safe.
Constructor Details
GeoIP
GeoIP lookup service for IP to country mapping.- Parameters:
context- RouterContext in production, I2PAppContext for testing only
Method Details
shutdown
public void shutdown()Shutdown and release resources.blockingLookup
public void blockingLookup()Blocking lookup of all pending IPs. Results will be added to the table and available via get() after completion.Public for BundleRouterInfos.
countryToIP
Write all IP ranges for country to blocklist-country.txt. Inline, blocking.- Parameters:
country- lower-case two-letter country code
getGeoIP2
getASN
openASN
Open the ASN database reader (lazy, cached).- Returns:
- the reader for the ASN database, or null if the database file is missing
- Throws:
IOException- if the file exists but cannot be read as a MaxMind database
getOrgName
reverseWord
applyAbbreviation
fixReversedWords
Detect and fix character-reversed words from MaxMind ASN DB. e.g. "eteicoS esiacnarF uD enohpeletoidaR" -> "Societe France Du RadioTelephone"Detection passes: 1. Word-by-word: words starting lowercase and ending uppercase are likely reversed. 2. Full-string: try reversing the entire name for compound words without spaces. 3. First/last char case-swap: turns "techteL" back into "Techtel". 4. Full word-level char reversal: reverse every word unconditionally, catching all-lowercase reversed words like "enofadov" where decode isn't in known-words. 5. Word-order reversal: flip the word order (catches "loclix as trading..."). 6. Combined: char-reversal then word-order, catching both at once, as in "tsohxuled sa gnidart inolletram oettam". Also detects "as trading" pattern which strongly signals word-order is reversed. Picks whichever pass scores highest (known-word matches + title-case words).
AS numbers must be stripped before calling this (see normalizeOrgName).
- Parameters:
name- the organisation name as read from the database- Returns:
- the corrected name, or the input unchanged if no reversal was detected
scoreCandidate
Score a candidate by known-word matches (weighted 3x) plus title-case word count. Title-case words are a strong signal because ASN org names are stored title-cased, and reversed names are all-lowercase.- Parameters:
text- the candidate name to score- Returns:
- the score, or -1 for an empty candidate so that it always loses
countTitleCaseWords
Count words starting with uppercase (title-case signal for proper org names).- Parameters:
text- the name to scan- Returns:
- how many space-separated words of two or more characters start with an uppercase letter
tryFixAsTrading
Detect "as trading" pattern (lowercase), a strong signal that word order is reversed. A correct org name has "Trading as X", but word-order reversal produces "X as trading". Also checks the char-reversed candidate for the same pattern.- Parameters:
name- the original organisation nameallWordReversed- the candidate with every word char-reversed, may be empty- Returns:
- the reordered name when the "as trading" pattern is present, otherwise ""
tryWordOrderIfHasAsTrading
tryWordReversal
tryCaseSwap
Try swapping the case of first and last characters in each word. Handles MaxMind corruption where "Techtel" becomes "techteL", with the first and last characters' case swapped. Only acts if at least one word has the corruption signature, a lowercase start with an uppercase end; words that don't match the pattern are left unchanged.- Parameters:
words- the name split on spaces- Returns:
- the name with the corrupted words' case swapped, "" if none are corrupted
swapFirstLastCase
tryFullStringReversal
tryFullWordReversal
Reverse every word at character level unconditionally. Catches all-lowercase reversed words like "enofadov" where the decoded form ("vodafone") isn't in the known-words list, so case-pattern detection wouldn't trigger.- Parameters:
words- the name split on spaces- Returns:
- every word reversed, in the original word order
tryWordOrderReversal
Reverse the order of words. Catches word-order reversal like "loclix as trading sciacca filiberto matteo" → "matteo filiberto sciacca trading as loclix".- Parameters:
name- the organisation name to reorder- Returns:
- the words in reverse order, "" if there are fewer than two words
countKnownWordMatches
Count how many space-separated words match known words.- Parameters:
text- the name to scan- Returns:
- how many of its words are in the known-words set, ignoring case
looksReversed
A word looks reversed if: 1. Its first letter is lowercase and last letter is uppercase (e.g. "puorG" → "Group"), OR 2. Reversing its letters yields a known word (e.g. "CSJP" → "PJSC").Leading/trailing non-letter characters are ignored for the letter check so that "talasite(" and ")puorG" are correctly detected.
- Parameters:
word- the word to test- Returns:
- true if the word's case pattern, or the word its letters decode to when reversed, suggests it was stored reversed
normalizeOrgName
Normalize an ISP/org name from the ASN database. Strips suffixes, abbreviates verbose words, title-cases with acronym preservation.- Parameters:
raw- original org name from MMDB- Returns:
- the normalized organisation name, or the input if it was null or empty
collapseVodafoneCountry
Collapse "Vodafone <Country> ..." names, with corporate-suffix cruft from truncated MaxMind entries, to just "Vodafone <Country>". Country matching is multi-word aware ("Czech Republic", "New Zealand"). Non-country Vodafone names (Group, Idea, etc.) pass through unchanged.- Parameters:
name- the already-normalized organisation name- Returns:
- collapsed name if a known country was matched, else the input
firstWord
titleCasePreserve
openGeoIP2
Open a GeoIP2 database.- Parameters:
geoFile- the GeoIP2 database file to open- Returns:
- a reader with a 256-entry cache, whose build date is also reported to the update manager
- Throws:
IOException- if the file cannot be read, or is not a valid MaxMind database
getGeoIPBuildInfo
Return the country database's build date, size and path, for the console.- Returns:
- the HTML build info, or a not-found or error message
getASNBuildInfo
Return the current ASN database version.- Returns:
- the HTML build info, or a not-found or error message
readCountryFile
private void readCountryFile()Read in and parse the country file. The file need not be sorted.Acceptable formats: #comment (# must be in column 1) code,full name
Example: US,UNITED STATES
To create: wget https://web.archive.org/web/2010id_/http://ip-to-country.webhosting.info/downloads/ip-to-country.csv.zip unzip ip-to-country.csv.zip cut -d, -f3,5 < ip-to-country.csv|sed 's/"//g' | sort | uniq > countries.txt.
readGeoIPFile
Read in and parse the geoip file. The geoip file must be sorted, and may not contain overlapping entries.Acceptable formats (IPV4 only): #comment (# must be in column 1) integer IP,integer IP, country code
Example: 121195296,121195327,IT
This is identical to the Tor geoip file, which can be found in src/config/geoip in their distribution, or /usr/local/lib/share/tor/geoip in their installation.
To create: wget https://web.archive.org/web/2010id_/http://ip-to-country.webhosting.info/downloads/ip-to-country.csv.zip unzip ip-to-country.csv.zip cut -d, -f0-3 < ip-to-country.csv|sed 's/"//g' > geoip.txt.
- Parameters:
search- a sorted array of IPs to search- Returns:
- an array of country codes, same order as the search param, with null for an IP outside every range in the file; a zero-length array if the file is missing
notifyVersion
Tell the update manager.- Parameters:
subtype- the updater subtype recorded against the GEOIP update typeversion- the version number to report; zero or below is ignored
notifyVersion
Tell the update manager.- Parameters:
ctx- the application context whose client app manager holds the registered update managersubtype- the updater subtype recorded against the GEOIP update type, e.g. "GeoIP"version- the version number being reported; anything zero or below is ignored
notifyVersion
Tell the update manager, with a version string as-is, e.g. the product version embedded in a database's metadata.- Parameters:
ctx- the application context whose client app manager holds the registered update managersubtype- the updater subtype recorded against the GEOIP update type, e.g. "ASN"version- the version being reported; null or empty is ignored
updateOurCountry
private void updateOurCountry(long ts) Put our country code in the config, where others (such as Timestamper) can get it, and it will be there next time at startup.Does nothing in
I2PAppContext.- Parameters:
ts- the timestamp of the geoip file that was read, greater than zero
banCountry
Bans routers located in a specified country.This method iterates through all known routers in the network database and adds those located in the specified country to the banlist. Routers are banned indefinitely with a reason message that reflects whether the application is in 'block my country' mode or 'hidden' mode.
- Parameters:
ctx- the RouterContext instance providing access to network database and banlistcountry- the country code (ISO 3166-1 alpha-2 format) of the country whose routers should be banned
add
Add to the list needing lookup Public for BundleRouterInfos.- Parameters:
ip- IPv4 or IPv6
add
public void add(byte[] ip) Add to the list needing lookup Public for BundleRouterInfos.- Parameters:
ip- IPv4 or IPv6
add
private void add(long ip) See above for ip-to-long mapping.- Parameters:
ip- the address as a long, IPv4 in the low 32 bits, IPv6 as the first 8 bytes
get
get
The country for an IP from the cache.- Parameters:
ip- IPv4 or IPv6- Returns:
- lower-case code, generally two letters, or null.
get
The country for an IP from the cache. See above for ip-to-long mapping.- Parameters:
ip- the address as a long, IPv4 in the low 32 bits, IPv6 as the first 8 bytes- Returns:
- lower-case code, generally two letters, or null if not cached
toLong
private static long toLong(byte[] ip) Convert an address to the long form used as the cache key. See above for ip-to-long mapping.- Parameters:
ip- four bytes for IPv4, sixteen bytes for IPv6- Returns:
- IPv4 as a non-negative long, IPv6 as the first 8 bytes as a signed long
toV4
The given IPv4 as a dotted-quad string.- Parameters:
ip- the IPv4 address as a non-negative long- Returns:
- the address in dotted-quad form, for example 1.2.3.4
toV6
The given IPv6 as a hex string.- Parameters:
ip- the first 8 bytes of the IPv6 address as a long- Returns:
- the address in hex form, for example aabb:ccdd:eeff:1122::
fullName
getCountries