forked from I2P_Developers/i2p.i2p
GeoIP: Hook maxmind geoip2 code into transport lookup.
This commit is contained in:
@ -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",
|
||||
|
Reference in New Issue
Block a user