/** * OnionCoffee - Anonymous Communication through TOR Network * Copyright (C) 2005-2007 RWTH Aachen University, Informatik IV * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. * * This program 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 General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ package TorJava.Common; import java.util.zip.*; import java.net.*; import java.util.*; import java.io.*; public class GeoIP { Vector<TableEntry> list; // CONSTRUCTORZ public GeoIP(String pathToZip) throws IOException { readFromFile(pathToZip); } public static void main(String[] argv) { // used for testing this class (stand-alone) try{ GeoIP gi = new GeoIP(argv[0]); if (argv.length>1) System.out.println(argv[1]+" is in "+gi.getCountryLong(argv[1])); } catch(Exception e) { System.err.println(e); e.printStackTrace(); } } // *** init void readFromFile(String filename) throws IOException { list = new Vector<TableEntry>(10000,1000); try{ ZipFile file = new ZipFile(filename); Enumeration<? extends ZipEntry> e = file.entries(); while(e.hasMoreElements()) { ZipEntry ze = (ZipEntry)e.nextElement(); if (ze.isDirectory()) continue; try{ parseEntry( file.getInputStream(ze)); } catch(Exception e3) { /* ignore exceptions */ } } file.close(); } catch(Exception ex) { // could not read from REAL FILE, try fetching file from inside this jar try{ ZipInputStream zipIn = new ZipInputStream(ClassLoader.getSystemResourceAsStream(filename)); ZipEntry zEntry = zipIn.getNextEntry(); while(zEntry != null) { if (zEntry.isDirectory()) continue; ByteArrayOutputStream out = new ByteArrayOutputStream(); while(zipIn.available()!=0) { byte[] smallBuffer = new byte[1024]; int len = zipIn.read(smallBuffer,0,smallBuffer.length); if (len>0) out.write(smallBuffer,0,len); } byte[] data = out.toByteArray(); try{ parseEntry(new ByteArrayInputStream(data)); } catch(Exception e3) { /* ignore exceptions */ } zEntry = zipIn.getNextEntry(); } } catch(Exception ex2) { /*bla*/ } } } private void parseEntry(InputStream compIn) throws IOException { BufferedReader bin = new BufferedReader( new InputStreamReader( compIn ) ); String line = bin.readLine().trim(); while( line.length() > 0) { line = bin.readLine().trim(); try{ String[] parts = line.split(","); insertSorted(new TableEntry(parts[2],parts[3],parts[4],parts[5])); } catch(Exception e2) { /* ignore exceptions */ } } } // **** main functionality // (yes I know that the list provided by maxmind.com IS sorted, but better // safe then sorry!) private void insertSorted(TableEntry fresh) { // list is filled int first = 0; int last = list.size(); // empty list if (last==0) { list.add(fresh); return; } // check if entry is sorted after the last element (if input is sorted!) TableEntry here = (TableEntry) list.elementAt(last-1); if (fresh.from > here.from) { list.add(fresh); return; } // iterate //System.out.println(""); while (last>first) { int mid = (last+first)/2; //System.out.println(first+" "+mid+" "+last); here = (TableEntry) list.elementAt(mid); if (fresh.from < here.from) { last = mid-1; } else { first = mid+1; } } //System.out.println("insert at "+first); // insert list.insertElementAt(fresh,first); } private TableEntry search(long ip) { // use binary search to find record //System.out.println("searching for "+ip); int first = 0; int last = list.size()-1; while (last>first) { int mid = (last+first)/2; TableEntry here = (TableEntry) list.elementAt(mid); //System.out.println(first+" "+mid+" ("+here.from+") "+last); if (ip < here.from) { last = mid-1; } else { if (first == mid) { first=mid+1; } else { first=mid; } } } //System.out.println("found at "+first); return (TableEntry) list.elementAt(first); } // for unit32-notation public String getCountryShort(long ip) { return search(ip).country_short; } public String getCountryLong(long ip) { return search(ip).country_long; } // for char-array notation (convert to unit32 and call those functions) private long CharArrayToUint32(char[] ip) { long result = 0; for(int i=0;i<ip.length;++i) result = (result << 8) + ip[i]; return result; } public String getCountryShort(char[] ip) { return getCountryShort(CharArrayToUint32(ip)); } public String getCountryLong(char[] ip) { return getCountryLong(CharArrayToUint32(ip)); } // for byte arrays private long ByteArrayToUint32(byte[] ip) { long result = 0; for(int i=0;i<ip.length;++i) result = (result << 8) + ((int)(256+ip[i]) & 0xff); return result; } public String getCountryShort(byte[] ip) { return getCountryShort(ByteArrayToUint32(ip)); } public String getCountryLong(byte[] ip) { return getCountryLong(ByteArrayToUint32(ip)); } // for dotted-quad notation (convert to uint32 and call those functions) private char[] StringToCharArray(String ip) { String[] a = ip.split("\\."); char[] x = new char[a.length]; for(int i=0;i<a.length;++i) x[i] = (char)Integer.parseInt(a[i]); return x; } public String getCountryShort(String ip) { return getCountryShort(CharArrayToUint32(StringToCharArray(ip))); } public String getCountryLong(String ip) { return getCountryLong(CharArrayToUint32(StringToCharArray(ip))); } // for InetAdress public String getCountryShort(InetAddress ip) { return getCountryShort(ip.getAddress()); } public String getCountryLong(InetAddress ip) { return getCountryLong(ip.getAddress()); } // ***** struct to store data in list private class TableEntry { long from; long to; String country_short; String country_long; TableEntry(String from,String to,String c_short,String c_long) throws NumberFormatException { this.from = Long.parseLong(from.replace('"',' ').trim()); this.to = Long.parseLong(to.replace('"',' ').trim()); country_short = c_short.replace('"',' ').trim(); country_long = c_long.replace('"',' ').trim(); } } }