diff options
Diffstat (limited to 'EssentialsGeoIP/src/com/maxmind/geoip/LookupService.java')
-rw-r--r-- | EssentialsGeoIP/src/com/maxmind/geoip/LookupService.java | 1046 |
1 files changed, 1046 insertions, 0 deletions
diff --git a/EssentialsGeoIP/src/com/maxmind/geoip/LookupService.java b/EssentialsGeoIP/src/com/maxmind/geoip/LookupService.java new file mode 100644 index 000000000..406cda004 --- /dev/null +++ b/EssentialsGeoIP/src/com/maxmind/geoip/LookupService.java @@ -0,0 +1,1046 @@ +/** + * LookupService.java + * + * Copyright (C) 2003 MaxMind LLC. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +package com.maxmind.geoip; + +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.net.InetAddress; +import java.net.Inet6Address; +import java.net.UnknownHostException; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.StringTokenizer; + +import javax.naming.NamingException; +import javax.naming.directory.Attributes; +import javax.naming.directory.DirContext; +import javax.naming.directory.InitialDirContext; + +/** + * Provides a lookup service for information based on an IP address. The location of + * a database file is supplied when creating a lookup service instance. The edition of + * the database determines what information is available about an IP address. See the + * DatabaseInfo class for further details.<p> + * + * The following code snippet demonstrates looking up the country that an IP + * address is from: + * <pre> + * // First, create a LookupService instance with the location of the database. + * LookupService lookupService = new LookupService("c:\\geoip.dat"); + * // Assume we have a String ipAddress (in dot-decimal form). + * Country country = lookupService.getCountry(ipAddress); + * System.out.println("The country is: " + country.getName()); + * System.out.println("The country code is: " + country.getCode()); + * </pre> + * + * In general, a single LookupService instance should be created and then reused + * repeatedly.<p> + * + * <i>Tip:</i> Those deploying the GeoIP API as part of a web application may find it + * difficult to pass in a File to create the lookup service, as the location of the + * database may vary per deployment or may even be part of the web-application. In this + * case, the database should be added to the classpath of the web-app. For example, by + * putting it into the WEB-INF/classes directory of the web application. The following code + * snippet demonstrates how to create a LookupService using a database that can be found + * on the classpath: + * + * <pre> + * String fileName = getClass().getResource("/GeoIP.dat").toExternalForm().substring(6); + * LookupService lookupService = new LookupService(fileName);</pre> + * + * @author Matt Tucker (matt@jivesoftware.com) + */ +public class LookupService { + + /** + * Database file. + */ + private RandomAccessFile file = null; + private File databaseFile = null; + + /** + * Information about the database. + */ + private DatabaseInfo databaseInfo = null; + + /** + * The database type. Default is the country edition. + */ + byte databaseType = DatabaseInfo.COUNTRY_EDITION; + + int databaseSegments[]; + int recordLength; + + String licenseKey; + int dnsService = 0; + int dboptions; + byte dbbuffer[]; + byte index_cache[]; + long mtime; + int last_netmask; + private final static int US_OFFSET = 1; + private final static int CANADA_OFFSET = 677; + private final static int WORLD_OFFSET = 1353; + private final static int FIPS_RANGE = 360; + private final static int COUNTRY_BEGIN = 16776960; + private final static int STATE_BEGIN_REV0 = 16700000; + private final static int STATE_BEGIN_REV1 = 16000000; + private final static int STRUCTURE_INFO_MAX_SIZE = 20; + private final static int DATABASE_INFO_MAX_SIZE = 100; + public final static int GEOIP_STANDARD = 0; + public final static int GEOIP_MEMORY_CACHE = 1; + public final static int GEOIP_CHECK_CACHE = 2; + public final static int GEOIP_INDEX_CACHE = 4; + public final static int GEOIP_UNKNOWN_SPEED = 0; + public final static int GEOIP_DIALUP_SPEED = 1; + public final static int GEOIP_CABLEDSL_SPEED = 2; + public final static int GEOIP_CORPORATE_SPEED = 3; + + + private final static int SEGMENT_RECORD_LENGTH = 3; + private final static int STANDARD_RECORD_LENGTH = 3; + private final static int ORG_RECORD_LENGTH = 4; + private final static int MAX_RECORD_LENGTH = 4; + + private final static int MAX_ORG_RECORD_LENGTH = 300; + private final static int FULL_RECORD_LENGTH = 60; + + private final Country UNKNOWN_COUNTRY = new Country("--", "N/A"); + + private static final HashMap hashmapcountryCodetoindex = new HashMap(512); + private static final HashMap hashmapcountryNametoindex = new HashMap(512); + private static final String[] countryCode = { + "--","AP","EU","AD","AE","AF","AG","AI","AL","AM","AN","AO","AQ","AR", + "AS","AT","AU","AW","AZ","BA","BB","BD","BE","BF","BG","BH","BI","BJ", + "BM","BN","BO","BR","BS","BT","BV","BW","BY","BZ","CA","CC","CD","CF", + "CG","CH","CI","CK","CL","CM","CN","CO","CR","CU","CV","CX","CY","CZ", + "DE","DJ","DK","DM","DO","DZ","EC","EE","EG","EH","ER","ES","ET","FI", + "FJ","FK","FM","FO","FR","FX","GA","GB","GD","GE","GF","GH","GI","GL", + "GM","GN","GP","GQ","GR","GS","GT","GU","GW","GY","HK","HM","HN","HR", + "HT","HU","ID","IE","IL","IN","IO","IQ","IR","IS","IT","JM","JO","JP", + "KE","KG","KH","KI","KM","KN","KP","KR","KW","KY","KZ","LA","LB","LC", + "LI","LK","LR","LS","LT","LU","LV","LY","MA","MC","MD","MG","MH","MK", + "ML","MM","MN","MO","MP","MQ","MR","MS","MT","MU","MV","MW","MX","MY", + "MZ","NA","NC","NE","NF","NG","NI","NL","NO","NP","NR","NU","NZ","OM", + "PA","PE","PF","PG","PH","PK","PL","PM","PN","PR","PS","PT","PW","PY", + "QA","RE","RO","RU","RW","SA","SB","SC","SD","SE","SG","SH","SI","SJ", + "SK","SL","SM","SN","SO","SR","ST","SV","SY","SZ","TC","TD","TF","TG", + "TH","TJ","TK","TM","TN","TO","TL","TR","TT","TV","TW","TZ","UA","UG", + "UM","US","UY","UZ","VA","VC","VE","VG","VI","VN","VU","WF","WS","YE", + "YT","RS","ZA","ZM","ME","ZW","A1","A2","O1","AX","GG","IM","JE","BL", + "MF"}; + + private static final String[] countryName = { + "N/A","Asia/Pacific Region","Europe","Andorra","United Arab Emirates", + "Afghanistan","Antigua and Barbuda","Anguilla","Albania","Armenia", + "Netherlands Antilles","Angola","Antarctica","Argentina","American Samoa", + "Austria","Australia","Aruba","Azerbaijan","Bosnia and Herzegovina", + "Barbados","Bangladesh","Belgium","Burkina Faso","Bulgaria","Bahrain", + "Burundi","Benin","Bermuda","Brunei Darussalam","Bolivia","Brazil","Bahamas", + "Bhutan","Bouvet Island","Botswana","Belarus","Belize","Canada", + "Cocos (Keeling) Islands","Congo, The Democratic Republic of the", + "Central African Republic","Congo","Switzerland","Cote D'Ivoire", + "Cook Islands","Chile","Cameroon","China","Colombia","Costa Rica","Cuba", + "Cape Verde","Christmas Island","Cyprus","Czech Republic","Germany", + "Djibouti","Denmark","Dominica","Dominican Republic","Algeria","Ecuador", + "Estonia","Egypt","Western Sahara","Eritrea","Spain","Ethiopia","Finland", + "Fiji","Falkland Islands (Malvinas)","Micronesia, Federated States of", + "Faroe Islands","France","France, Metropolitan","Gabon","United Kingdom", + "Grenada","Georgia","French Guiana","Ghana","Gibraltar","Greenland","Gambia", + "Guinea","Guadeloupe","Equatorial Guinea","Greece", + "South Georgia and the South Sandwich Islands","Guatemala","Guam", + "Guinea-Bissau","Guyana","Hong Kong","Heard Island and McDonald Islands", + "Honduras","Croatia","Haiti","Hungary","Indonesia","Ireland","Israel","India", + "British Indian Ocean Territory","Iraq","Iran, Islamic Republic of", + "Iceland","Italy","Jamaica","Jordan","Japan","Kenya","Kyrgyzstan","Cambodia", + "Kiribati","Comoros","Saint Kitts and Nevis", + "Korea, Democratic People's Republic of","Korea, Republic of","Kuwait", + "Cayman Islands","Kazakhstan","Lao People's Democratic Republic","Lebanon", + "Saint Lucia","Liechtenstein","Sri Lanka","Liberia","Lesotho","Lithuania", + "Luxembourg","Latvia","Libyan Arab Jamahiriya","Morocco","Monaco", + "Moldova, Republic of","Madagascar","Marshall Islands", + "Macedonia","Mali","Myanmar","Mongolia", + "Macau","Northern Mariana Islands","Martinique","Mauritania","Montserrat", + "Malta","Mauritius","Maldives","Malawi","Mexico","Malaysia","Mozambique", + "Namibia","New Caledonia","Niger","Norfolk Island","Nigeria","Nicaragua", + "Netherlands","Norway","Nepal","Nauru","Niue","New Zealand","Oman","Panama", + "Peru","French Polynesia","Papua New Guinea","Philippines","Pakistan", + "Poland","Saint Pierre and Miquelon","Pitcairn Islands","Puerto Rico","" + + "Palestinian Territory","Portugal","Palau","Paraguay","Qatar", + "Reunion","Romania","Russian Federation","Rwanda","Saudi Arabia", + "Solomon Islands","Seychelles","Sudan","Sweden","Singapore","Saint Helena", + "Slovenia","Svalbard and Jan Mayen","Slovakia","Sierra Leone","San Marino", + "Senegal","Somalia","Suriname","Sao Tome and Principe","El Salvador", + "Syrian Arab Republic","Swaziland","Turks and Caicos Islands","Chad", + "French Southern Territories","Togo","Thailand","Tajikistan","Tokelau", + "Turkmenistan","Tunisia","Tonga","Timor-Leste","Turkey","Trinidad and Tobago", + "Tuvalu","Taiwan","Tanzania, United Republic of","Ukraine","Uganda", + "United States Minor Outlying Islands","United States","Uruguay","Uzbekistan", + "Holy See (Vatican City State)","Saint Vincent and the Grenadines", + "Venezuela","Virgin Islands, British","Virgin Islands, U.S.","Vietnam", + "Vanuatu","Wallis and Futuna","Samoa","Yemen","Mayotte","Serbia", + "South Africa","Zambia","Montenegro","Zimbabwe","Anonymous Proxy", + "Satellite Provider","Other","Aland Islands","Guernsey","Isle of Man","Jersey", + "Saint Barthelemy","Saint Martin"}; + + + /* init the hashmap once at startup time */ + static { + int i; + if(countryCode.length!=countryName.length) + throw new AssertionError("countryCode.length!=countryName.length"); + + // distributed service only + for (i = 0; i < countryCode.length ;i++){ + hashmapcountryCodetoindex.put(countryCode[i],Integer.valueOf(i)); + hashmapcountryNametoindex.put(countryName[i],Integer.valueOf(i)); + } + }; + + + /** + * Create a new distributed lookup service using the license key + * + * @param databaseFile String representation of the database file. + * @param licenseKey license key provided by Maxmind to access distributed service + */ + public LookupService(String databaseFile,String licenseKey) throws IOException { + this(new File(databaseFile)); + this.licenseKey = licenseKey; + dnsService = 1; + } + /** + * Create a new distributed lookup service using the license key + * + * @param databaseFile the database file. + * @param licenseKey license key provided by Maxmind to access distributed service + */ + public LookupService(File databaseFile,String licenseKey) throws IOException { + this(databaseFile); + this.licenseKey = licenseKey; + dnsService = 1; + } + /** + * Create a new distributed lookup service using the license key + * + * @param options Resevered for future use + * @param licenseKey license key provided by Maxmind to access distributed service + */ + public LookupService(int options,String licenseKey) throws IOException { + this.licenseKey = licenseKey; + dnsService = 1; + init(); + } + /** + * Create a new lookup service using the specified database file. + * + * @param databaseFile String representation of the database file. + * @throws java.io.IOException if an error occured creating the lookup service + * from the database file. + */ + public LookupService(String databaseFile) throws IOException { + this(new File(databaseFile)); + } + + /** + * Create a new lookup service using the specified database file. + * + * @param databaseFile the database file. + * @throws java.io.IOException if an error occured creating the lookup service + * from the database file. + */ + public LookupService(File databaseFile) throws IOException { + this.databaseFile = databaseFile; + this.file = new RandomAccessFile(databaseFile, "r"); + init(); + } + + /** + * Create a new lookup service using the specified database file. + * + * @param databaseFile String representation of the database file. + * @param options database flags to use when opening the database + * GEOIP_STANDARD read database from disk + * GEOIP_MEMORY_CACHE cache the database in RAM and read it from RAM + * @throws java.io.IOException if an error occured creating the lookup service + * from the database file. + */ + public LookupService(String databaseFile, int options) throws IOException{ + this(new File(databaseFile),options); + } + + /** + * Create a new lookup service using the specified database file. + * + * @param databaseFile the database file. + * @param options database flags to use when opening the database + * GEOIP_STANDARD read database from disk + * GEOIP_MEMORY_CACHE cache the database in RAM and read it from RAM + * @throws java.io.IOException if an error occured creating the lookup service + * from the database file. + */ + public LookupService(File databaseFile, int options) throws IOException{ + this.databaseFile = databaseFile; + this.file = new RandomAccessFile(databaseFile, "r"); + dboptions = options; + init(); + } + /** + * Reads meta-data from the database file. + * + * @throws java.io.IOException if an error occurs reading from the database file. + */ + private void init() throws IOException { + int i, j; + byte [] delim = new byte[3]; + byte [] buf = new byte[SEGMENT_RECORD_LENGTH]; + + if (file == null) { + return; + } + if ((dboptions & GEOIP_CHECK_CACHE) != 0) { + mtime = databaseFile.lastModified(); + } + file.seek(file.length() - 3); + for (i = 0; i < STRUCTURE_INFO_MAX_SIZE; i++) { + file.readFully(delim); + if (delim[0] == -1 && delim[1] == -1 && delim[2] == -1) { + databaseType = file.readByte(); + if (databaseType >= 106) { + // Backward compatibility with databases from April 2003 and earlier + databaseType -= 105; + } + // Determine the database type. + if (databaseType == DatabaseInfo.REGION_EDITION_REV0) { + databaseSegments = new int[1]; + databaseSegments[0] = STATE_BEGIN_REV0; + recordLength = STANDARD_RECORD_LENGTH; + }else if (databaseType == DatabaseInfo.REGION_EDITION_REV1){ + databaseSegments = new int[1]; + databaseSegments[0] = STATE_BEGIN_REV1; + recordLength = STANDARD_RECORD_LENGTH; + } + else if (databaseType == DatabaseInfo.CITY_EDITION_REV0 || + databaseType == DatabaseInfo.CITY_EDITION_REV1 || + databaseType == DatabaseInfo.ORG_EDITION || + databaseType == DatabaseInfo.ISP_EDITION || + databaseType == DatabaseInfo.ASNUM_EDITION) { + databaseSegments = new int[1]; + databaseSegments[0] = 0; + if (databaseType == DatabaseInfo.CITY_EDITION_REV0 || + databaseType == DatabaseInfo.CITY_EDITION_REV1 || + databaseType == DatabaseInfo.ASNUM_EDITION) { + recordLength = STANDARD_RECORD_LENGTH; + } + else { + recordLength = ORG_RECORD_LENGTH; + } + file.readFully(buf); + for (j = 0; j < SEGMENT_RECORD_LENGTH; j++) { + databaseSegments[0] += (unsignedByteToInt(buf[j]) << (j * 8)); + } + } + break; + } + else { + file.seek(file.getFilePointer() - 4); + } + } + if ((databaseType == DatabaseInfo.COUNTRY_EDITION) || + (databaseType == DatabaseInfo.COUNTRY_EDITION_V6) || + (databaseType == DatabaseInfo.PROXY_EDITION) || + (databaseType == DatabaseInfo.NETSPEED_EDITION)) { + databaseSegments = new int[1]; + databaseSegments[0] = COUNTRY_BEGIN; + recordLength = STANDARD_RECORD_LENGTH; + } + if ((dboptions & GEOIP_MEMORY_CACHE) == 1) { + int l = (int) file.length(); + dbbuffer = new byte[l]; + file.seek(0); + file.readFully(dbbuffer,0,l); + databaseInfo = this.getDatabaseInfo(); + file.close(); + } + if ((dboptions & GEOIP_INDEX_CACHE) != 0) { + int l = databaseSegments[0] * recordLength * 2; + index_cache = new byte[l]; + if (index_cache != null){ + file.seek(0); + file.readFully(index_cache,0,l); + } + } else { + index_cache = null; + } + } + + /** + * Closes the lookup service. + */ + public void close() { + try { + if (file != null){ + file.close(); + } + file = null; + } + catch (Exception e) { } + } + + /** + * Returns the country the IP address is in. + * + * @param ipAddress String version of an IPv6 address, i.e. "::127.0.0.1" + * @return the country the IP address is from. + */ + public Country getCountryV6(String ipAddress) { + InetAddress addr; + try { + addr = Inet6Address.getByName(ipAddress); + } + catch (UnknownHostException e) { + return UNKNOWN_COUNTRY; + } + return getCountryV6(addr); + } + + /** + * Returns the country the IP address is in. + * + * @param ipAddress String version of an IP address, i.e. "127.0.0.1" + * @return the country the IP address is from. + */ + public Country getCountry(String ipAddress) { + InetAddress addr; + try { + addr = InetAddress.getByName(ipAddress); + } + catch (UnknownHostException e) { + return UNKNOWN_COUNTRY; + } + return getCountry(bytesToLong(addr.getAddress())); + } + + /** + * Returns the country the IP address is in. + * + * @param ipAddress the IP address. + * @return the country the IP address is from. + */ + public synchronized Country getCountry(InetAddress ipAddress) { + return getCountry(bytesToLong(ipAddress.getAddress())); + } + + /** + * Returns the country the IP address is in. + * + * @param addr the IP address as Inet6Address. + * @return the country the IP address is from. + */ + public Country getCountryV6(InetAddress addr) { + if (file == null && (dboptions & GEOIP_MEMORY_CACHE) == 0) { + throw new IllegalStateException("Database has been closed."); + } + int ret = seekCountryV6(addr) - COUNTRY_BEGIN; + if (ret == 0) { + return UNKNOWN_COUNTRY; + } + else { + return new Country(countryCode[ret], countryName[ret]); + } + } + + /** + * Returns the country the IP address is in. + * + * @param ipAddress the IP address in long format. + * @return the country the IP address is from. + */ + public Country getCountry(long ipAddress) { + if (file == null && (dboptions & GEOIP_MEMORY_CACHE) == 0) { + throw new IllegalStateException("Database has been closed."); + } + int ret = seekCountry(ipAddress) - COUNTRY_BEGIN; + if (ret == 0) { + return UNKNOWN_COUNTRY; + } + else { + return new Country(countryCode[ret], countryName[ret]); + } + } + + public int getID(String ipAddress) { + InetAddress addr; + try { + addr = InetAddress.getByName(ipAddress); + } + catch (UnknownHostException e) { + return 0; + } + return getID(bytesToLong(addr.getAddress())); + } + + public int getID(InetAddress ipAddress) { + return getID(bytesToLong(ipAddress.getAddress())); + } + + public synchronized int getID(long ipAddress) { + if (file == null && (dboptions & GEOIP_MEMORY_CACHE) == 0) { + throw new IllegalStateException("Database has been closed."); + } + int ret = seekCountry(ipAddress) - databaseSegments[0]; + return ret; + } + + public int last_netmask() { + return this.last_netmask; + } + + public void netmask(int nm){ + this.last_netmask = nm; + } + + /** + * Returns information about the database. + * + * @return database info. + */ + public synchronized DatabaseInfo getDatabaseInfo() { + if (databaseInfo != null) { + return databaseInfo; + } + try { + _check_mtime(); + boolean hasStructureInfo = false; + byte [] delim = new byte[3]; + // Advance to part of file where database info is stored. + file.seek(file.length() - 3); + for (int i=0; i<STRUCTURE_INFO_MAX_SIZE; i++) { + int read = file.read( delim ); + if( read==3 && (delim[0]&0xFF)==255 && (delim[1]&0xFF) == 255 && (delim[2]&0xFF)==255 ){ + hasStructureInfo = true; + break; + } + file.seek(file.getFilePointer() - 4); + + } + if (hasStructureInfo) { + file.seek(file.getFilePointer() - 6); + } + else { + // No structure info, must be pre Sep 2002 database, go back to end. + file.seek(file.length() - 3); + } + // Find the database info string. + for (int i=0; i<DATABASE_INFO_MAX_SIZE; i++) { + file.readFully(delim); + if (delim[0]==0 && delim[1]==0 && delim[2]==0) { + byte[] dbInfo = new byte[i]; + file.readFully(dbInfo); + // Create the database info object using the string. + this.databaseInfo = new DatabaseInfo(new String(dbInfo)); + return databaseInfo; + } + file.seek(file.getFilePointer() -4); + } + } + catch (Exception e) { + e.printStackTrace(); + } + return new DatabaseInfo(""); + } + + synchronized void _check_mtime(){ + try { + if ((dboptions & GEOIP_CHECK_CACHE) != 0){ + long t = databaseFile.lastModified(); + if (t != mtime){ + /* GeoIP Database file updated */ + /* refresh filehandle */ + file.close(); + file = new RandomAccessFile(databaseFile,"r"); + databaseInfo = null; + init(); + } + } + } catch (IOException e) { + System.out.println("file not found"); + } + } + + // for GeoIP City only + public Location getLocation(InetAddress addr) { + return getLocation(bytesToLong(addr.getAddress())); + } + + // for GeoIP City only + public Location getLocation(String str) { + if (dnsService == 0) { + InetAddress addr; + try { + addr = InetAddress.getByName(str); + } + catch (UnknownHostException e) { + return null; + } + + return getLocation(addr); + } else { + String str2 = getDnsAttributes(str); + return getLocationwithdnsservice(str2); + // TODO if DNS is not available, go to local file as backup + } + } + + String getDnsAttributes(String ip) { + try { + Hashtable env = new Hashtable(); + env.put("java.naming.factory.initial", "com.sun.jndi.dns.DnsContextFactory"); + // TODO don't specify ws1, instead use ns servers for s.maxmind.com + env.put("java.naming.provider.url","dns://ws1.maxmind.com/"); + + DirContext ictx = new InitialDirContext(env); + Attributes attrs = ictx.getAttributes(licenseKey + "." + ip + ".s.maxmind.com", new String[] {"txt"}); + //System.out.println(attrs.get("txt").get()); + String str = attrs.get("txt").get().toString(); + return str; + } + catch(NamingException e) { + // TODO fix this to handle exceptions + System.out.println("DNS error"); + return null; + } + + } + + public Location getLocationwithdnsservice(String str) { + Location record = new Location(); + String key; + String value; + StringTokenizer st = new StringTokenizer(str,";=\""); + while (st.hasMoreTokens()) { + key = st.nextToken(); + if (st.hasMoreTokens()) { + value = st.nextToken(); + } else { + value = "";} + if (key.equals("co")) { + Integer i = (Integer)hashmapcountryCodetoindex.get(value); + record.countryCode = value; + record.countryName = countryName[i.intValue()]; + } + if (key.equals("ci")) { + record.city = value; + } + if (key.equals("re")) { + record.region = value; + } + if (key.equals("zi")) { + record.postalCode = value; + } + // TODO, ISP and Organization + //if (key.equals("or")) { + //record.org = value; + //} + //if (key.equals("is")) { + //record.isp = value; + //} + if (key.equals("la")) { + try{ + record.latitude = Float.parseFloat(value); + } catch(NumberFormatException e) { + record.latitude = 0; + } + } + if (key.equals("lo")) { + try{ + record.longitude = Float.parseFloat(value); + } catch(NumberFormatException e) { + record.latitude = 0; + } + } + // dm depreciated use me ( metro_code ) instead + if (key.equals("dm") || key.equals("me")) { + try{ + record.metro_code = record.dma_code = Integer.parseInt(value); + } catch(NumberFormatException e) { + record.metro_code = record.dma_code = 0; + } + } + if (key.equals("ac")) { + try{ + record.area_code = Integer.parseInt(value); + } catch(NumberFormatException e) { + record.area_code = 0; + } + } + } + return record; + } + + public synchronized Region getRegion(String str) { + InetAddress addr; + try { + addr = InetAddress.getByName(str); + } + catch (UnknownHostException e) { + return null; + } + + return getRegion(bytesToLong(addr.getAddress())); + } + + public synchronized Region getRegion(long ipnum) { + Region record = new Region(); + int seek_region = 0; + if (databaseType == DatabaseInfo.REGION_EDITION_REV0) { + seek_region = seekCountry(ipnum) - STATE_BEGIN_REV0; + char ch[] = new char[2]; + if (seek_region >= 1000) { + record.countryCode = "US"; + record.countryName = "United States"; + ch[0] = (char)(((seek_region - 1000)/26) + 65); + ch[1] = (char)(((seek_region - 1000)%26) + 65); + record.region = new String(ch); + } else { + record.countryCode = countryCode[seek_region]; + record.countryName = countryName[seek_region]; + record.region = ""; + } + } else if (databaseType == DatabaseInfo.REGION_EDITION_REV1) { + seek_region = seekCountry(ipnum) - STATE_BEGIN_REV1; + char ch[] = new char[2]; + if (seek_region < US_OFFSET) { + record.countryCode = ""; + record.countryName = ""; + record.region = ""; + } else if (seek_region < CANADA_OFFSET) { + record.countryCode = "US"; + record.countryName = "United States"; + ch[0] = (char)(((seek_region - US_OFFSET)/26) + 65); + ch[1] = (char)(((seek_region - US_OFFSET)%26) + 65); + record.region = new String(ch); + } else if (seek_region < WORLD_OFFSET) { + record.countryCode = "CA"; + record.countryName = "Canada"; + ch[0] = (char)(((seek_region - CANADA_OFFSET)/26) + 65); + ch[1] = (char)(((seek_region - CANADA_OFFSET)%26) + 65); + record.region = new String(ch); + } else { + record.countryCode = countryCode[(seek_region - WORLD_OFFSET) / FIPS_RANGE]; + record.countryName = countryName[(seek_region - WORLD_OFFSET) / FIPS_RANGE]; + record.region = ""; + } + } + return record; + } + + public synchronized Location getLocation(long ipnum) { + int record_pointer; + byte record_buf[] = new byte[FULL_RECORD_LENGTH]; + int record_buf_offset = 0; + Location record = new Location(); + int str_length = 0; + int j, seek_country; + double latitude = 0, longitude = 0; + + try { + seek_country = seekCountry(ipnum); + if (seek_country == databaseSegments[0]) { + return null; + } + record_pointer = seek_country + (2 * recordLength - 1) * databaseSegments[0]; + + if ((dboptions & GEOIP_MEMORY_CACHE) == 1) { + //read from memory + System.arraycopy(dbbuffer, record_pointer, record_buf, 0, Math.min(dbbuffer.length - record_pointer, FULL_RECORD_LENGTH)); +} else { + //read from disk + file.seek(record_pointer); + file.readFully(record_buf); + } + + // get country + record.countryCode = countryCode[unsignedByteToInt(record_buf[0])]; + record.countryName = countryName[unsignedByteToInt(record_buf[0])]; + record_buf_offset++; + + // get region + while (record_buf[record_buf_offset + str_length] != '\0') + str_length++; + if (str_length > 0) { + record.region = new String(record_buf, record_buf_offset, str_length); + } + record_buf_offset += str_length + 1; + str_length = 0; + + // get city + while (record_buf[record_buf_offset + str_length] != '\0') + str_length++; + if (str_length > 0) { + record.city = new String(record_buf, record_buf_offset, str_length, "ISO-8859-1"); + } + record_buf_offset += str_length + 1; + str_length = 0; + + // get postal code + while (record_buf[record_buf_offset + str_length] != '\0') + str_length++; + if (str_length > 0) { + record.postalCode = new String(record_buf, record_buf_offset, str_length); + } + record_buf_offset += str_length + 1; + + // get latitude + for (j = 0; j < 3; j++) + latitude += (unsignedByteToInt(record_buf[record_buf_offset + j]) << (j * 8)); + record.latitude = (float) latitude/10000 - 180; + record_buf_offset += 3; + + // get longitude + for (j = 0; j < 3; j++) + longitude += (unsignedByteToInt(record_buf[record_buf_offset + j]) << (j * 8)); + record.longitude = (float) longitude/10000 - 180; + + record.dma_code = record.metro_code = 0; + record.area_code = 0; + if (databaseType == DatabaseInfo.CITY_EDITION_REV1) { + // get DMA code + int metroarea_combo = 0; + if (record.countryCode == "US") { + record_buf_offset += 3; + for (j = 0; j < 3; j++) + metroarea_combo += (unsignedByteToInt(record_buf[record_buf_offset + j]) << (j * 8)); + record.metro_code = record.dma_code = metroarea_combo/1000; + record.area_code = metroarea_combo % 1000; + } + } + } + catch (IOException e) { + System.err.println("IO Exception while seting up segments"); + } + return record; + } + + public String getOrg(InetAddress addr) { + return getOrg(bytesToLong(addr.getAddress())); + } + + public String getOrg(String str) { + InetAddress addr; + try { + addr = InetAddress.getByName(str); + } + catch (UnknownHostException e) { + return null; + } + return getOrg(addr); + } + + // GeoIP Organization and ISP Edition methods + public synchronized String getOrg(long ipnum) { + int seek_org; + int record_pointer; + int str_length = 0; + byte [] buf = new byte[MAX_ORG_RECORD_LENGTH]; + String org_buf; + + try { + seek_org = seekCountry(ipnum); + if (seek_org == databaseSegments[0]) { + return null; + } + + record_pointer = seek_org + (2 * recordLength - 1) * databaseSegments[0]; + if ((dboptions & GEOIP_MEMORY_CACHE) == 1) { + //read from memory + System.arraycopy(dbbuffer, record_pointer, buf, 0, Math.min(dbbuffer.length - record_pointer, MAX_ORG_RECORD_LENGTH)); + } else { + //read from disk + file.seek(record_pointer); + file.readFully(buf); + } + while (buf[str_length] != '\0') { + str_length++; + } + org_buf = new String(buf, 0, str_length, "ISO-8859-1"); + return org_buf; + } + catch (IOException e) { + System.out.println("IO Exception"); + return null; + } + } + + /** + * Finds the country index value given an IPv6 address. + * + * @param addr the ip address to find in long format. + * @return the country index. + */ + private synchronized int seekCountryV6(InetAddress addr) { + byte [] v6vec = addr.getAddress(); + byte [] buf = new byte[2 * MAX_RECORD_LENGTH]; + int [] x = new int[2]; + int offset = 0; + _check_mtime(); + for (int depth = 127; depth >= 0; depth--) { + if ((dboptions & GEOIP_MEMORY_CACHE) == 1) { + //read from memory + for (int i = 0;i < 2 * MAX_RECORD_LENGTH;i++) { + buf[i] = dbbuffer[(2 * recordLength * offset)+i]; + } + } else if ((dboptions & GEOIP_INDEX_CACHE) != 0) { + //read from index cache + for (int i = 0;i < 2 * MAX_RECORD_LENGTH;i++) { + buf[i] = index_cache[(2 * recordLength * offset)+i]; + } + } else { + //read from disk + try { + file.seek(2 * recordLength * offset); + file.readFully(buf); + } + catch (IOException e) { + System.out.println("IO Exception"); + } + } + for (int i = 0; i<2; i++) { + x[i] = 0; + for (int j = 0; j<recordLength; j++) { + int y = buf[i*recordLength+j]; + if (y < 0) { + y+= 256; + } + x[i] += (y << (j * 8)); + } + } + + int bnum = 127 - depth; + int idx = bnum >> 3; + int b_mask = 1 << ( bnum & 7 ^ 7 ); + if ((v6vec[idx] & b_mask) > 0) { + if (x[1] >= databaseSegments[0]) { + last_netmask = 128 - depth; + return x[1]; + } + offset = x[1]; + } + else { + if (x[0] >= databaseSegments[0]) { + last_netmask = 128 - depth; + return x[0]; + } + offset = x[0]; + } + } + + // shouldn't reach here + System.err.println("Error seeking country while seeking " + addr.getHostAddress() ); + return 0; + } + /** + * Finds the country index value given an IP address. + * + * @param ipAddress the ip address to find in long format. + * @return the country index. + */ + private synchronized int seekCountry(long ipAddress) { + byte [] buf = new byte[2 * MAX_RECORD_LENGTH]; + int [] x = new int[2]; + int offset = 0; + _check_mtime(); + for (int depth = 31; depth >= 0; depth--) { + if ((dboptions & GEOIP_MEMORY_CACHE) == 1) { + //read from memory + for (int i = 0;i < 2 * MAX_RECORD_LENGTH;i++) { + buf[i] = dbbuffer[(2 * recordLength * offset)+i]; + } + } else if ((dboptions & GEOIP_INDEX_CACHE) != 0) { + //read from index cache + for (int i = 0;i < 2 * MAX_RECORD_LENGTH;i++) { + buf[i] = index_cache[(2 * recordLength * offset)+i]; + } + } else { + //read from disk + try { + file.seek(2 * recordLength * offset); + file.readFully(buf); + } + catch (IOException e) { + System.out.println("IO Exception"); + } + } + for (int i = 0; i<2; i++) { + x[i] = 0; + for (int j = 0; j<recordLength; j++) { + int y = buf[i*recordLength+j]; + if (y < 0) { + y+= 256; + } + x[i] += (y << (j * 8)); + } + } + + if ((ipAddress & (1 << depth)) > 0) { + if (x[1] >= databaseSegments[0]) { + last_netmask = 32 - depth; + return x[1]; + } + offset = x[1]; + } + else { + if (x[0] >= databaseSegments[0]) { + last_netmask = 32 - depth; + return x[0]; + } + offset = x[0]; + } + } + + // shouldn't reach here + System.err.println("Error seeking country while seeking " + ipAddress); + return 0; + } + + /** + * Returns the long version of an IP address given an InetAddress object. + * + * @param address the InetAddress. + * @return the long form of the IP address. + */ + private static long bytesToLong(byte [] address) { + long ipnum = 0; + for (int i = 0; i < 4; ++i) { + long y = address[i]; + if (y < 0) { + y+= 256; + } + ipnum += y << ((3-i)*8); + } + return ipnum; + } + + private static int unsignedByteToInt(byte b) { + return (int) b & 0xFF; + } +} |