GeoIP: Hook maxmind geoip2 code into transport lookup.

This commit is contained in:
zzz
2018-11-20 14:14:34 +00:00
parent f1297e7c62
commit ef44c36f0c

View File

@ -16,8 +16,10 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import com.maxmind.db.CHMCache;
import com.maxmind.geoip.InvalidDatabaseException;
import com.maxmind.geoip.LookupService;
import com.maxmind.geoip2.DatabaseReader;
import net.i2p.I2PAppContext;
import net.i2p.data.DataHelper;
@ -64,13 +66,15 @@ public class GeoIP {
public static final String PROP_GEOIP_DIR = "geoip.dir";
public static final String GEOIP_DIR_DEFAULT = "geoip";
static final String GEOIP_FILE_DEFAULT = "geoip.txt";
static final String GEOIP2_FILE_DEFAULT = "GeoLite2-Country.mmdb";
static final String COUNTRY_FILE_DEFAULT = "countries.txt";
public static final String PROP_IP_COUNTRY = "i2np.lastCountry";
public static final String PROP_DEBIAN_GEOIP = "geoip.dat";
public static final String PROP_DEBIAN_GEOIPV6 = "geoip.v6.dat";
private static final String DEBIAN_GEOIP_FILE = "/usr/share/GeoIP/GeoIP.dat";
private static final String DEBIAN_GEOIPV6_FILE = "/usr/share/GeoIP/GeoIPv6.dat";
private static final boolean ENABLE_DEBIAN = !(SystemVersion.isWindows() || SystemVersion.isAndroid());
private static final boolean DISABLE_DEBIAN = false;
private static final boolean ENABLE_DEBIAN = !DISABLE_DEBIAN && !(SystemVersion.isWindows() || SystemVersion.isAndroid());
/** maxmind API */
private static final String UNKNOWN_COUNTRY_CODE = "--";
@ -147,6 +151,8 @@ public class GeoIP {
public void run() {
if (_lock.getAndSet(true))
return;
File geoip2 = getGeoIP2();
DatabaseReader dbr = null;
try {
// clear the negative cache every few runs, to prevent it from getting too big
if (((++_lookupRunCount) % CLEAR) == 0)
@ -158,19 +164,20 @@ public class GeoIP {
Arrays.sort(search);
File f = new File(_context.getProperty(PROP_DEBIAN_GEOIP, DEBIAN_GEOIP_FILE));
if (ENABLE_DEBIAN && f.exists()) {
// Maxmind database
// Maxmind v1 database
LookupService ls = null;
try {
ls = new LookupService(f, LookupService.GEOIP_STANDARD);
for (int i = 0; i < search.length; i++) {
long ip = search[i].longValue();
Long ipl = search[i];
long ip = ipl.longValue();
// returns upper case or "--"
String uc = ls.getCountry(ip).getCode();
if (!uc.equals(UNKNOWN_COUNTRY_CODE)) {
String cached = _codeCache.get(uc.toLowerCase(Locale.US));
_IPToCountry.put(search[i], cached);
_IPToCountry.put(ipl, cached);
} else {
_notFound.add(search[i]);
_notFound.add(ipl);
}
}
} catch (IOException ioe) {
@ -180,6 +187,25 @@ public class GeoIP {
} finally {
if (ls != null) ls.close();
}
} else if (geoip2 != null) {
// Maxmind v2 database
try {
dbr = openGeoIP2(geoip2);
for (int i = 0; i < search.length; i++) {
Long ipl = search[i];
String ipv4 = toV4(ipl);
// returns upper case or null
String uc = dbr.country(ipv4);
if (uc != null) {
String cached = _codeCache.get(uc.toLowerCase(Locale.US));
_IPToCountry.put(ipl, cached);
} else {
_notFound.add(ipl);
}
}
} catch (IOException ioe) {
_log.error("GeoIP2 failure", ioe);
}
} else {
// Tor-style database
String[] countries = readGeoIPFile(search);
@ -198,12 +224,13 @@ public class GeoIP {
Arrays.sort(search);
File f = new File(_context.getProperty(PROP_DEBIAN_GEOIPV6, DEBIAN_GEOIPV6_FILE));
if (ENABLE_DEBIAN && f.exists()) {
// Maxmind database
// Maxmind v1 database
LookupService ls = null;
try {
ls = new LookupService(f, LookupService.GEOIP_STANDARD);
for (int i = 0; i < search.length; i++) {
long ip = search[i].longValue();
Long ipl = search[i];
long ip = ipl.longValue();
String ipv6 = toV6(ip);
// returns upper case or "--"
String uc = ls.getCountryV6(ipv6).getCode();
@ -212,9 +239,9 @@ public class GeoIP {
String cached = _codeCache.get(lc);
if (cached == null)
cached = lc;
_IPToCountry.put(search[i], cached);
_IPToCountry.put(ipl, cached);
} else {
_notFound.add(search[i]);
_notFound.add(ipl);
}
}
} catch (IOException ioe) {
@ -224,8 +251,28 @@ public class GeoIP {
} finally {
if (ls != null) ls.close();
}
} else {
// Tor-style database
} else if (geoip2 != null) {
// Maxmind v2 database
try {
if (dbr == null)
dbr = openGeoIP2(geoip2);
for (int i = 0; i < search.length; i++) {
Long ipl = search[i];
String ipv6 = toV6(ipl);
// returns upper case or null
String uc = dbr.country(ipv6);
if (uc != null) {
String cached = _codeCache.get(uc.toLowerCase(Locale.US));
_IPToCountry.put(ipl, cached);
} else {
_notFound.add(ipl);
}
}
} catch (IOException ioe) {
_log.error("GeoIP2 failure", ioe);
}
} else {
// I2P format IPv6 database
String[] countries = GeoIPv6.readGeoIPFile(_context, search, _codeCache);
for (int i = 0; i < countries.length; i++) {
if (countries[i] != null)
@ -236,11 +283,45 @@ public class GeoIP {
}
}
} finally {
if (dbr != null) try { dbr.close(); } catch (IOException ioe) {}
_lock.set(false);
}
}
}
/**
* Get the GeoIP2 database file
*
* @return null if not found
* @since 0.9.38
*/
private File getGeoIP2() {
String geoDir = _context.getProperty(PROP_GEOIP_DIR, GEOIP_DIR_DEFAULT);
File geoFile = new File(geoDir);
if (!geoFile.isAbsolute())
geoFile = new File(_context.getBaseDir(), geoDir);
geoFile = new File(geoFile, GEOIP2_FILE_DEFAULT);
if (!geoFile.exists()) {
if (_log.shouldLog(Log.WARN))
_log.warn("GeoIP2 file not found: " + geoFile.getAbsolutePath());
return null;
}
return geoFile;
}
/**
* Open a GeoIP2 database
* @since 0.9.38
*/
private DatabaseReader openGeoIP2(File geoFile) throws IOException {
DatabaseReader.Builder b = new DatabaseReader.Builder(geoFile);
b.withCache(new CHMCache(256));
DatabaseReader rv = b.build();
if (_log.shouldDebug())
_log.debug("Opened GeoIP2 Database, Metadata: " + rv.getMetadata());
return rv;
}
/**
* Read in and parse the country file.
* The file need not be sorted.
@ -473,6 +554,21 @@ public class GeoIP {
}
}
/**
* @return e.g. 1.2.3.4
* @since 0.9.38 for maxmind
*/
private static String toV4(long ip) {
StringBuilder buf = new StringBuilder(15);
for (int i = 0; i < 4; i++) {
buf.append(Long.toString((ip >> ((3-i)*8)) & 0xff));
if (i == 3)
break;
buf.append('.');
}
return buf.toString();
}
/**
* @return e.g. aabb:ccdd:eeff:1122::
* @since 0.9.26 for maxmind
@ -498,7 +594,7 @@ public class GeoIP {
/***
public static void main(String args[]) {
GeoIP g = new GeoIP(new Router().getContext());
GeoIP g = new GeoIP(I2PAppContext.getGlobalContext());
String tests[] = {"0.0.0.0", "0.0.0.1", "0.0.0.2", "0.0.0.255", "1.0.0.0",
"94.3.3.3", "77.1.2.3", "127.0.0.0", "127.127.127.127", "128.0.0.0",
"89.8.9.3", "72.5.6.8", "217.4.9.7", "175.107.027.107", "135.6.5.2",