diff --git a/LICENSE.txt b/LICENSE.txt
index 99c83c33d0d9d9a3842c13f253c4468d977c8e67..bc8d615ae5990e43cb48a2310b93cec343f4ae7a 100644
--- a/LICENSE.txt
+++ b/LICENSE.txt
@@ -103,6 +103,9 @@ Public domain except as listed below:
    http://creativecommons.org/licenses/by-sa/3.0/
    This product includes GeoLite data created by MaxMind, available from http://www.maxmind.com/
 
+   GeoIP API 1.3.1:
+   See licenses/LICENSE-LGPLv2.1.txt
+
 
 Installer:
    Launch4j 3.0.1:
diff --git a/apps/i2psnark/java/build.xml b/apps/i2psnark/java/build.xml
index 5a4d3dd2496f1ba78bad21587eadecb060edf102..2cbcd2ea88504b3b28fe97da7bccad00577c6afc 100644
--- a/apps/i2psnark/java/build.xml
+++ b/apps/i2psnark/java/build.xml
@@ -18,6 +18,8 @@
                 <pathelement location="../../../core/java/build/obj" />
                 <pathelement location="../../ministreaming/java/build/obj" />
                 <pathelement location="../../jetty/jettylib/javax.servlet.jar" />
+                <!-- jsp-api.jar only present for debian builds -->
+                <pathelement location="../../jetty/jettylib/jsp-api.jar" />
             </classpath>
         </depend>
     </target>
@@ -37,9 +39,15 @@
             srcdir="./src" 
             debug="true" deprecation="on" source="${javac.version}" target="${javac.version}" 
             destdir="./build/obj" 
-            includeAntRuntime="false"
-            classpath="../../../core/java/build/i2p.jar:../../jetty/jettylib/javax.servlet.jar:../../ministreaming/java/build/mstreaming.jar" >
+            includeAntRuntime="false" >
             <compilerarg line="${javac.compilerargs}" />
+            <classpath>
+                <pathelement location="../../../core/java/build/i2p.jar" />
+                <pathelement location="../../ministreaming/java/build/mstreaming.jar" />
+                <pathelement location="../../jetty/jettylib/javax.servlet.jar" />
+                <!-- jsp-api.jar only present for debian builds -->
+                <pathelement location="../../jetty/jettylib/jsp-api.jar" />
+            </classpath>
         </javac>
     </target>
 
diff --git a/apps/i2ptunnel/java/build.xml b/apps/i2ptunnel/java/build.xml
index a009bc6979f04061c814c646d2815ae5f7ee42d7..f5b47257294aa4f5b265cde3ad67f454a67c182c 100644
--- a/apps/i2ptunnel/java/build.xml
+++ b/apps/i2ptunnel/java/build.xml
@@ -258,6 +258,8 @@
             <classpath>
                 <pathelement location="../../jetty/jettylib/jasper-runtime.jar" />
                 <pathelement location="../../jetty/jettylib/javax.servlet.jar" />
+                <!-- jsp-api.jar only present for debian builds -->
+                <pathelement location="../../jetty/jettylib/jsp-api.jar" />
                 <pathelement location="../../jetty/jettylib/commons-logging.jar" />
                 <pathelement location="../../jetty/jettylib/commons-el.jar" />
                 <pathelement location="${ant.home}/lib/ant.jar" />
@@ -282,6 +284,8 @@
             <classpath>
                 <pathelement location="../../jetty/jettylib/jasper-runtime.jar" />
                 <pathelement location="../../jetty/jettylib/javax.servlet.jar" />
+                <!-- jsp-api.jar only present for debian builds -->
+                <pathelement location="../../jetty/jettylib/jsp-api.jar" />
                 <pathelement location="../../jetty/jettylib/commons-logging.jar" />
                 <pathelement location="../../jetty/jettylib/commons-el.jar" />
                 <pathelement location="build/i2ptunnel.jar" />
diff --git a/apps/jetty/build.xml b/apps/jetty/build.xml
index b1fdbcd461996716c13d2e4277b6bf07d2c1c9b6..6c5c48ada0d60b7fbf612668d4fba24d7aa8d62c 100644
--- a/apps/jetty/build.xml
+++ b/apps/jetty/build.xml
@@ -1,6 +1,18 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <project basedir="." default="all" name="jetty">
 
+    <!-- This copies jars, with some modifications and renaming,
+         from the jetty-distribution directory to the jettylib directory.
+         This is disabled if the property with-libjetty8-java=true.
+
+         This copies jars, with some modifications and renaming,
+         from the apache-tomcat-deployer and apache-tomcat directories to the jettylib directory.
+         This is disabled if the property with-libservlet2.5-java=true.
+
+         This also builds the small helper jar jetty-i2p.jar from
+         the source in the java/ directory.
+     -->
+
     <property name="jetty.ver" value="8.1.17.v20150415" />
     <property name="jetty.base" value="jetty-distribution-${jetty.ver}" />
     <property name="jetty.sha1" value="ce7bcd1bdcdac4cf130467f6d55155b9e1517e71" />
@@ -22,16 +34,24 @@
       - updating to a new Jetty version by changing ${jetty.ver} and ${jetty.sha1} above.
      -->
 
-    <target name="ensureJettylib" >
-        <available property="jetty.zip.extracted" file="${jetty.base}" type="dir" />
+    <!-- verify everything we need is in jettylib/ -->
+    <target name="ensureJettylib" depends="ensureJettylib1, copyJettylib" />
+
+    <target name="ensureJettylib1" >
+        <condition property="jetty.zip.extracted" >
+            <or>
+                <istrue value="${with-libjetty8-java}" />
+                <available file="${jetty.base}" type="dir" />
+            </or>
+        </condition>
         <condition property="jetty.zip.available" >
             <or>
                 <istrue value="${jetty.zip.extracted}" />
                 <available file="${jetty.filename}" type="file" />
             </or>
         </condition>
-        <ant target="copyJettylib" />
     </target>
+
   <!--
     <target name="ensureJettylib" depends="extractJettylib" />
    -->
@@ -62,6 +82,7 @@
 
     <condition property="verified.already" >
         <or>
+            <istrue value="${with-libjetty8-java}" />
             <istrue value="${jetty.zip.extracted}" />
             <and>
                 <available file="${jetty.filename}" />
@@ -94,8 +115,15 @@
         <unzip src="${jetty.filename}" dest="." />
     </target>
 
-    <target name="copyJettylib" depends="extractJettylib" >
+    <target name="mkJettylibdir" >
         <mkdir dir="jettylib" />
+    </target>
+
+    <!-- Jetty and tomcat files -->
+    <target name="copyJettylib" depends="mkJettylibdir, copyJettylib1, copyTomcatLib" />
+
+    <!-- Jetty files only -->
+    <target name="copyJettylib1" depends="extractJettylib" unless="${with-libjetty8-java}" >
       <!-- We copy everything to names without the version numbers so we
            can update them later. Where there was something similar in Jetty 5/6,
            we use the same names so they will overwrite the Jetty 5/6 jar on upgrade.
@@ -157,7 +185,6 @@
             <zipfileset excludes="META-INF/LICENSE.txt META-INF/NOTICE.txt" src="../../installer/lib/launch4j/lib/commons-logging.jar" />
         </jar>
       -->
-        <ant target="copyTomcatLib" />
     </target>
 
     <!-- Tomcat util jar.
@@ -169,7 +196,7 @@
          Apparently this is only required for precompilation of jsps, so this is put in
          with the JspC compiler jasper-runtime.jar below.
      -->
-    <target name="buildTomcatUtilJar" >
+    <target name="buildTomcatUtilJar" unless="${with-libservlet2.5-java}" >
         <!-- take only what we need from the tomcat-coyote jar -->
         <jar destfile="${tomcat2.lib.small}/tomcat-coyote-util.jar" >
             <zipfileset src="${tomcat2.lib}/tomcat-coyote.jar"
@@ -192,15 +219,26 @@
          If we go to Tomcat 7:
          tomcat-api.jar + tomcat-util.jar: Add to javax.servlet.jar (as of Tomcat 7 / Jetty 8)
      -->
-    <target name="copyTomcatLib" >
-        <jar destfile="jettylib/jasper-runtime.jar" filesetmanifest="merge" >
-            <zipfileset excludes="META-INF/LICENSE META-INF/NOTICE" src="${tomcat.lib}/jasper.jar" />
-            <zipfileset src="${tomcat2.lib.small}/tomcat-coyote-util.jar" />
-        </jar>
+    <target name="copyTomcatLib" depends="mkJettylibdir, copyTomcatLib1, copyTomcatLib2, copyTomcatLib3" />
+
+    <target name="copyTomcatLib1" unless="${with-libservlet2.5-java}" >
+        <!-- EL libs.
+             Tomcat 6 has EL 2.1.
+             Tomcat 7 / libservlet3.0 has EL 2.2.
+             According to http://stackoverflow.com/questions/7202686/differences-between-el-2-1-and-2-2
+             2.2 is backwards-compatible with 2.1.
+         -->
         <jar destfile="jettylib/commons-el.jar" duplicate="preserve" filesetmanifest="merge" >
             <zipfileset excludes="META-INF/LICENSE META-INF/NOTICE" src="${tomcat.lib}/jasper-el.jar" />
             <zipfileset excludes="META-INF/**/*" src="${tomcat.lib}/el-api.jar" />
         </jar>
+    </target>
+
+    <target name="copyTomcatLib2" unless="${with-libtomcat6-java}" >
+        <jar destfile="jettylib/jasper-runtime.jar" filesetmanifest="merge" >
+            <zipfileset excludes="META-INF/LICENSE META-INF/NOTICE" src="${tomcat.lib}/jasper.jar" />
+            <zipfileset src="${tomcat2.lib.small}/tomcat-coyote-util.jar" />
+        </jar>
 <!--
         <jar destfile="jettylib/javax.servlet.jar" duplicate="preserve" filesetmanifest="mergewithoutmain" >
             <zipfileset excludes="META-INF/LICENSE META-INF/NOTICE" src="${tomcat.lib}/servlet-api.jar" />
@@ -215,6 +253,9 @@
         <jar destfile="jettylib/commons-logging.jar" update="true" >
             <zipfileset excludes="META-INF/LICENSE META-INF/NOTICE" src="${tomcat.lib}/tomcat-juli.jar" />
         </jar>
+    </target>
+
+    <target name="copyTomcatLib3" unless="${with-libtomcat7-java}" >
         <jar destfile="jettylib/jasper-compiler.jar" >
             <manifest>
                 <attribute name="Note" value="Intentionally empty" />
diff --git a/apps/routerconsole/java/build.xml b/apps/routerconsole/java/build.xml
index f897cff20e96b9ca9e5d1afc3b770df29be5d19d..6bcc2fa7cde30ba4344e4a717a512ed3170abbb7 100644
--- a/apps/routerconsole/java/build.xml
+++ b/apps/routerconsole/java/build.xml
@@ -345,6 +345,8 @@
             <classpath>
                 <pathelement location="../../jetty/jettylib/jasper-runtime.jar" />
                 <pathelement location="../../jetty/jettylib/javax.servlet.jar" />
+                <!-- jsp-api.jar only present for debian builds -->
+                <pathelement location="../../jetty/jettylib/jsp-api.jar" />
                 <pathelement location="../../jetty/jettylib/commons-logging.jar" />
                 <pathelement location="../../jetty/jettylib/commons-el.jar" />
                 <pathelement location="${ant.home}/lib/ant.jar" />
@@ -378,6 +380,8 @@
             <classpath>
                 <pathelement location="../../jetty/jettylib/jasper-runtime.jar" />
                 <pathelement location="../../jetty/jettylib/javax.servlet.jar" />
+                <!-- jsp-api.jar only present for debian builds -->
+                <pathelement location="../../jetty/jettylib/jsp-api.jar" />
                 <pathelement location="../../jetty/jettylib/commons-logging.jar" />
                 <pathelement location="../../jetty/jettylib/commons-el.jar" />
                 <pathelement location="../../jetty/jettylib/org.mortbay.jetty.jar" />
diff --git a/apps/susidns/src/build.xml b/apps/susidns/src/build.xml
index fdf42ceb5ec169f2a7c1cd7cabf1298fb8f82de0..bb8d5a97144832992b553935372742b1079299ba 100644
--- a/apps/susidns/src/build.xml
+++ b/apps/susidns/src/build.xml
@@ -11,14 +11,15 @@
 		<pathelement path="${classpath}" />
 		<pathelement location="${bin}" />
 		<pathelement location="${lib}/javax.servlet.jar"/>
-        <pathelement location="WEB-INF/lib/jstl.jar" />
-        <pathelement location="WEB-INF/lib/standard.jar" />
-        <pathelement location="${lib}/jasper-runtime.jar" />
-        <pathelement location="${lib}/javax.servlet.jar" />
-        <pathelement location="${lib}/commons-logging.jar" />
-        <pathelement location="${lib}/commons-el.jar" />
-        <pathelement location="${ant.home}/lib/ant.jar" />
-        <pathelement location="../../../core/java/build/i2p.jar" />
+                <!-- jsp-api.jar only present for debian builds -->
+                <pathelement location="${lib}/jsp-api.jar" />
+		<pathelement location="WEB-INF/lib/jstl.jar" />
+		<pathelement location="WEB-INF/lib/standard.jar" />
+		<pathelement location="${lib}/jasper-runtime.jar" />
+		<pathelement location="${lib}/commons-logging.jar" />
+		<pathelement location="${lib}/commons-el.jar" />
+		<pathelement location="${ant.home}/lib/ant.jar" />
+		<pathelement location="../../../core/java/build/i2p.jar" />
  	</path>
 
 	<property name="javac.compilerargs" value="" />
diff --git a/apps/susimail/build.xml b/apps/susimail/build.xml
index 192a90ca393a7a278c2c7688ce38ceb17cf383af..ad9ad447b2d71389de4765dca8940cc313d4a3b6 100644
--- a/apps/susimail/build.xml
+++ b/apps/susimail/build.xml
@@ -25,6 +25,8 @@
             <classpath>
                 <pathelement location="../../core/java/build/obj" />
                 <pathelement location="../jetty/jettylib/javax.servlet.jar" />
+                <!-- jsp-api.jar only present for debian builds -->
+                <pathelement location="../../jetty/jettylib/jsp-api.jar" />
                 <pathelement location="../jetty/jettylib/jetty-i2p.jar" />
             </classpath>
         </depend>
@@ -40,6 +42,8 @@
             <compilerarg line="${javac.compilerargs}" />
             <classpath>
                 <pathelement location="../jetty/jettylib/javax.servlet.jar" />
+                <!-- jsp-api.jar only present for debian builds -->
+                <pathelement location="../../jetty/jettylib/jsp-api.jar" />
                 <pathelement location="../jetty/jettylib/jetty-i2p.jar" />
                 <pathelement location="../../core/java/build/i2p.jar" />
             </classpath>
diff --git a/build.properties b/build.properties
index 2cb15c4cadb5ca8a407f410ded69d0502817c580..8fe441fee2ea419f1c4f9ad00c9db5f17de4e83c 100644
--- a/build.properties
+++ b/build.properties
@@ -113,3 +113,19 @@ javac.version=1.6
 #bundle.routerInfos=true
 #bundle.routerInfos.count=200
 #bundle.routerInfos.i2pConfigDir=/PATH/TO/.i2p
+
+### Debian/Ubuntu packages ###
+# Don't include geoip files, we will use geoip-database package
+#with-geoip-database=true
+# Don't include jetty files, we will use libjetty8-java package
+#with-libjetty8-java=true
+# Don't include tomcat files, we will use libservlet2.5-java package
+#with-libservlet2.5-java=true
+# Don't include tomcat juli files, we will use libtomcat6-java package
+#with-libtomcat6-java=true
+# Don't build with bundled tomcat 6, we will use libtomcat7-java package
+#with-libtomcat7-java=true
+# Don't include standard.jar, we will use libjakarta-taglibs-standard-java package
+#with-libjakarta-taglibs-standard-java=true
+# Don't include jstl.jar, we will use libjstl1.1-java package
+#with-libjstl1.1-java=true
diff --git a/build.xml b/build.xml
index 13411903b523365dd5e9cb6b55024afc0d398953..fd2a6e7980cddc7a379ab8f867ec5ca67a9cd93c 100644
--- a/build.xml
+++ b/build.xml
@@ -699,7 +699,7 @@
             windowtitle="I2P Anonymous Network - Java Documentation - Version ${release.number}">
             <group title="Core SDK (i2p.jar)" packages="net.i2p:net.i2p.*:net.i2p.client:net.i2p.client.*:net.i2p.internal:net.i2p.internal.*:freenet.support.CPUInformation:org.bouncycastle.oldcrypto:org.bouncycastle.oldcrypto.*:gnu.crypto.*:gnu.getopt:gnu.gettext:com.nettgryppa.security:net.metanotion:net.metanotion.*:org.apache.http.conn.ssl:org.apache.http.conn.util:org.apache.http.util" />
             <group title="Streaming Library" packages="net.i2p.client.streaming:net.i2p.client.streaming.impl" />
-            <group title="Router" packages="net.i2p.router:net.i2p.router.*:net.i2p.data.i2np:net.i2p.data.router:org.cybergarage:org.cybergarage.*:org.freenetproject:org.xlattice.crypto.filters" />
+            <group title="Router" packages="net.i2p.router:net.i2p.router.*:net.i2p.data.i2np:net.i2p.data.router:org.cybergarage:org.cybergarage.*:org.freenetproject:org.xlattice.crypto.filters:com.maxmind.geoip" />
             <group title="Router Console" packages="net.i2p.router.web:net.i2p.router.update:net.i2p.router.news" />
             <!-- apps and bridges starting here, alphabetical please -->
             <group title="Addressbook Application" packages="net.i2p.addressbook" />
@@ -764,6 +764,7 @@
         </javadoc>
         <echo message="Warning, javadoc embeds timestamps in the output, run with 'TZ=UTC ant javadoc' if you plan to distribute" />
     </target>
+
     <target name="javadoc-zip" depends="javadoc">
         <zip destfile="javadoc.zip" basedir="build" level="9" includes="javadoc\**" />
     </target>
@@ -1062,6 +1063,7 @@
         <copy file="installer/lib/wrapper/all/wrapper.jar" todir="pkg-temp/lib" />
     </target>
 
+    <!-- This is the target called by debian/rules -->
     <target name="preppkg-unix" depends="preppkg-base, prep-script-translation" >
         <copy file="installer/resources/runplain.sh" todir="pkg-temp/" />
         <copy file="installer/resources/eepget" todir="pkg-temp/" />
@@ -1140,7 +1142,8 @@
         <copy file="installer/lib/wrapper/all/wrapper.jar" todir="pkg-temp/lib" />
     </target>
 
-    <target name="preppkg-base" depends="build, preplicenses, prepConsoleDocs, prepthemeupdates, prepCertificates, prepRouterInfos">
+    <!-- see targets below for conditional copying -->
+    <target name="preppkg-base" depends="build, preplicenses, prepConsoleDocs, prepthemeupdates, prepCertificates, prepRouterInfos, copyjetty, copytomcat-unlesspkg, copyjstl-unlesspkg, copystandard-unlesspkg">
         <!-- if updater200 was run previously, it left *.pack files in pkg-temp -->
         <!-- Also remove deletelist.txt used for updater only -->
         <delete>
@@ -1148,10 +1151,6 @@
         </delete>
         <copy file="build/i2p.jar" todir="pkg-temp/lib/" />
         <copy file="build/i2ptunnel.jar" todir="pkg-temp/lib/" />
-        <!-- all jetty stuff -->
-        <copy todir="pkg-temp/lib" >
-            <fileset dir="build" includes="commons*.jar jasper*.jar javax*.jar jetty*.jar jsp*.jar org.mortbay.*.jar" />
-        </copy>
         <copy file="build/mstreaming.jar" todir="pkg-temp/lib/" />
         <copy file="build/streaming.jar" todir="pkg-temp/lib/" />
         <copy file="build/router.jar" todir="pkg-temp/lib/" />
@@ -1170,8 +1169,6 @@
         <copy file="build/susimail.war" todir="pkg-temp/webapps/" />
         <copy file="build/susidns.war" todir="pkg-temp/webapps/" />
         <copy file="build/imagegen.war" todir="pkg-temp/webapps/" />
-        <copy file="apps/susidns/src/WEB-INF/lib/jstl.jar" todir="pkg-temp/lib/" />
-        <copy file="apps/susidns/src/WEB-INF/lib/standard.jar" todir="pkg-temp/lib/" />
         <copy file="build/i2psnark.war" todir="pkg-temp/webapps/" />
         <copy file="apps/i2psnark/i2psnark.config" todir="pkg-temp/" />
         <copy file="installer/resources/blocklist.txt" todir="pkg-temp/" />
@@ -1204,16 +1201,42 @@
         </copy>
     </target>
 
+    <target name="copyjetty" depends="copyjetty-unlesspkg" >
+        <copy file="build/jetty-i2p.jar" todir="pkg-temp/lib" />
+    </target>
+
+    <target name="copyjetty-unlesspkg" unless="${with-libjetty8-java}" >
+        <copy todir="pkg-temp/lib" >
+            <fileset dir="build" includes="javax.servlet.jar jetty*.jar org.mortbay.*.jar" excludes="jetty-i2p.jar" />
+        </copy>
+    </target>
+
+    <target name="copytomcat-unlesspkg" unless="${with-libservlet2.5-java}" >
+        <copy todir="pkg-temp/lib" >
+            <fileset dir="build" includes="commons*.jar jasper*.jar javax*.jar" />
+        </copy>
+    </target>
+
+    <target name="copyjstl-unlesspkg" unless="${with-libjstl1.1-java}" >
+        <copy file="apps/susidns/src/WEB-INF/lib/jstl.jar" todir="pkg-temp/lib/" />
+    </target>
+
+    <target name="copystandard-unlesspkg" unless="${with-libjakarta-taglibs-standard-java}" >
+        <copy file="apps/susidns/src/WEB-INF/lib/standard.jar" todir="pkg-temp/lib/" />
+    </target>
+
     <!-- does NOT include launch4j licenses for Windows builds -->
-    <target name="preplicenses">
+    <target name="preplicenses" depends="preplicenses-unlesspkg" >
         <copy file="LICENSE.txt" todir="pkg-temp/" />
         <copy todir="pkg-temp/licenses/" >
           <fileset dir="licenses/" />
         </copy>
-        <copy file="apps/jetty/apache-tomcat-deployer/NOTICE" tofile="pkg-temp/licenses/NOTICE-Tomcat.txt" />
         <copy file="apps/imagegen/identicon/README.md" tofile="pkg-temp/licenses/LICENSE-Identicon.txt" />
     </target>
 
+    <target name="preplicenses-unlesspkg" unless="${with-libjetty8-java}" >
+        <copy file="apps/jetty/apache-tomcat-deployer/NOTICE" tofile="pkg-temp/licenses/NOTICE-Tomcat.txt" />
+    </target>
 
     <!-- DOES include launch4j licenses for Windows builds -->
     <target name="preplicenses-windows" depends="preplicenses">
@@ -1481,10 +1504,8 @@
         <copy file="build/jbigi.jar" todir="pkg-temp/lib/" />
     </target>
 
-    <!-- GeoIP files and flag icons -->
-    <target name="prepgeoupdate">
-        <copy file="installer/resources/geoip.txt" todir="pkg-temp/geoip/" />
-        <copy file="installer/resources/geoipv6.dat.gz" todir="pkg-temp/geoip/" />
+    <!-- GeoIP files -->
+    <target name="prepgeoupdate" depends="prepgeoupdate-unlesspkg" >
         <copy file="installer/resources/countries.txt" todir="pkg-temp/geoip/" />
         <copy file="installer/resources/continents.txt" todir="pkg-temp/geoip/" />
       <!--
@@ -1492,6 +1513,13 @@
        -->
     </target>
 
+    <!-- GeoIP files, set withGeoIPDatabase=true in override.properties to prevent -->
+    <!-- As of 0.9.26, the files are not included in Debian/Ubuntu builds. -->
+    <target name="prepgeoupdate-unlesspkg" unless="${with-geoip-database}" >
+        <copy file="installer/resources/geoip.txt" todir="pkg-temp/geoip/" />
+        <copy file="installer/resources/geoipv6.dat.gz" todir="pkg-temp/geoip/" />
+    </target>
+
     <!-- All jetty jars required for update.
          TODO do we need to bother updating jasper?
       -->
@@ -1972,8 +2000,6 @@
         <delete dir="../i2p-${Extended.Version}" />
         <exec executable="mtn" failonerror="true">
             <arg value="co" />
-            <arg value="-b" />
-            <arg value="i2p.i2p" />
             <!-- w: is the revision of the current workspace -->
             <arg value="-r" />
             <arg value="w:" />
@@ -1984,6 +2010,16 @@
             <fileset dir="../i2p-${Extended.Version}/installer/lib/" />
             <fileset dir="../i2p-${Extended.Version}/Slackware" />
             <fileset dir="../i2p-${Extended.Version}/_MTN" />
+            <file name="../i2p-${Extended.Version}/installer/resources/geoip.txt" />
+            <file name="../i2p-${Extended.Version}/installer/resources/geoipv6.dat.gz" />
+            <fileset dir="../i2p-${Extended.Version}/apps/jetty/jetty-distribution-8.1.17.v20150415" />
+          <!--
+            <fileset dir="../i2p-${Extended.Version}/apps/jetty/apache-tomcat" />
+            <fileset dir="../i2p-${Extended.Version}/apps/jetty/apache-tomcat-deployer/" />
+            <file name="../i2p-${Extended.Version}/apps/susidns/src/WEB-INF/lib/jstl.jar" />
+            <file name="../i2p-${Extended.Version}/apps/susidns/src/WEB-INF/lib/standard.jar" />
+           -->
+            <!-- anything added above, add in debian-release-tarball also -->
         </delete>
         <tar longfile="gnu" destfile="../${debian.tarball.name}" compression="bzip2">
             <tarfileset dir="../i2p-${Extended.Version}" prefix="/i2p-${Extended.Version}">
@@ -1991,6 +2027,16 @@
                 <exclude name="debian/**"/>
                 <exclude name="debian-alt/**"/>
                 <exclude name="**/*.sh"/>
+                <exclude name="installer/resources/geoip.txt"/>
+                <exclude name="installer/resources/geoipv6.dat.gz"/>
+                <exclude name="apps/jetty/jetty-distribution-*/**"/>
+          <!--
+                <exclude name="apps/jetty/apache-tomcat/**"/>
+                <exclude name="apps/jetty/apache-tomcat-deployer/**"/>
+                <exclude name="apps/susidns/src/WEB-INF/lib/jstl.jar" />
+                <exclude name="apps/susidns/src/WEB-INF/lib/standard.jar" />
+           -->
+                <!-- anything added above, add in debian-release-tarball also -->
             </tarfileset>
             <tarfileset dir="../i2p-${Extended.Version}" prefix="/i2p-${Extended.Version}" filemode="755">
                 <exclude name="debian/**" />
@@ -2014,8 +2060,6 @@
         <delete dir="../i2p-${Extended.Version}" />
         <exec executable="mtn" failonerror="true">
             <arg value="co" />
-            <arg value="-b" />
-            <arg value="i2p.i2p" />
             <!-- w: is the revision of the current workspace -->
             <arg value="-r" />
             <arg value="w:" />
@@ -2026,6 +2070,16 @@
             <fileset dir="../i2p-${Extended.Version}/installer/lib/" />
             <fileset dir="../i2p-${Extended.Version}/Slackware" />
             <fileset dir="../i2p-${Extended.Version}/_MTN" />
+            <file name="../i2p-${Extended.Version}/installer/resources/geoip.txt" />
+            <file name="../i2p-${Extended.Version}/installer/resources/geoipv6.dat.gz" />
+            <fileset dir="../i2p-${Extended.Version}/apps/jetty/jetty-distribution-8.1.17.v20150415" />
+          <!--
+            <fileset dir="../i2p-${Extended.Version}/apps/jetty/apache-tomcat" />
+            <fileset dir="../i2p-${Extended.Version}/apps/jetty/apache-tomcat-deployer/" />
+            <file name="../i2p-${Extended.Version}/apps/susidns/src/WEB-INF/lib/jstl.jar" />
+            <file name="../i2p-${Extended.Version}/apps/susidns/src/WEB-INF/lib/standard.jar" />
+           -->
+            <!-- anything added above, add in debian-tarball also -->
         </delete>
         <tar longfile="gnu" destfile="../${debian.tarball.name}" compression="bzip2">
             <tarfileset dir="../i2p-${Extended.Version}" prefix="/i2p-${release.number}">
@@ -2033,6 +2087,16 @@
                 <exclude name="debian/**"/>
                 <exclude name="debian-alt/**"/>
                 <exclude name="**/*.sh"/>
+                <exclude name="installer/resources/geoip.txt"/>
+                <exclude name="installer/resources/geoipv6.dat.gz"/>
+                <exclude name="apps/jetty/jetty-distribution-*/**"/>
+          <!--
+                <exclude name="apps/jetty/apache-tomcat/**"/>
+                <exclude name="apps/jetty/apache-tomcat-deployer/**"/>
+                <exclude name="apps/susidns/src/WEB-INF/lib/jstl.jar" />
+                <exclude name="apps/susidns/src/WEB-INF/lib/standard.jar" />
+           -->
+                <!-- anything added above, add in debian-tarball also -->
             </tarfileset>
             <tarfileset dir="../i2p-${Extended.Version}" prefix="/i2p-${release.number}" filemode="755">
                 <exclude name="debian/**" />
diff --git a/debian-alt/README.txt b/debian-alt/README.txt
index 0ee136eba198e869bab8728035c58f7d19d305d3..7ceec41976e1247202047a595accd9fd235232dd 100644
--- a/debian-alt/README.txt
+++ b/debian-alt/README.txt
@@ -1,6 +1,10 @@
-The files in ../debian/ are for launchpad (trusty/utopic/vivid/wily).
+The files in ../debian/ are for jessie/stable.
 Alternates are in the subdirectories here.
 
+trusty may be copied to utopic and vivid.
+They do not have libjetty8-java.
+wily has libjetty8-java.
+
 tails-jessie and tails-wheezy are currently the same as
 jessie and wheezy, respectively. If they diverge, put the changes here.
 
@@ -10,15 +14,9 @@ Note on systemd:
 # and is only Ubuntu as of "Saucy". The official packages will enable this for Debian unstable and
 # Ubuntu Saucy (and newer)
 
-Files are extracted from the following
-packages on deb.i2p2.no and will need to be updated
-for 0.9.25 or later:
-
-wheezy:
-i2p_0.9.23-2~deb7u+1.debian.tar.xz
-precise:
-i2p_0.9.23-2~precise+1.debian.tar.xz
-jessie:
-i2p_0.9.24-1~deb8u+1.debian.tar.xz
-unstable:
-i2p_0.9.24-1.debian.tar.xz
+Through release 0.9.25, the debian/ directory was not current for the release;
+any changes required for the build were checked in after the release.
+Starting with release 0.9.26, we will attempt to test debian builds
+before the release, and check in any required changes to debian/
+and debian-alt/ before the release, so that the files
+may actually be used to build the release.
diff --git a/debian-alt/jessie/changelog b/debian-alt/trusty/changelog
similarity index 90%
rename from debian-alt/jessie/changelog
rename to debian-alt/trusty/changelog
index c515372c845d561fcf3933945678209a41e37bb8..18b5f90384272ae805dea959daa943a15d5922ae 100644
--- a/debian-alt/jessie/changelog
+++ b/debian-alt/trusty/changelog
@@ -1,8 +1,14 @@
-i2p (0.9.25-1~deb8u+1) stable; urgency=medium
+i2p (0.9.25-1ubuntu1) trusty; urgency=medium
 
-  * Backport to Jessie
+  * New upstream version 0.9.25
 
- -- zzz on i2p <zzz@i2pmail.org>  Tue, 29 Mar 2016 18:12:12 +0000
+ -- zzz on i2p (key signing) <zzz@i2pmail.org>  Sat, 26 Mar 2016 12:12:12 +0000
+
+i2p (0.9.24-1ubuntu1) trusty; urgency=medium
+
+  * Upload to PPA
+
+ -- Kill Your TV <killyourtv@i2pmail.org>  Sat, 30 Jan 2016 14:12:27 +0000
 
 i2p (0.9.24-1) unstable; urgency=medium
 
@@ -112,7 +118,6 @@ i2p (0.9.20-3) unstable; urgency=medium
   * Add datagram exception to the apparmor profile
 
  -- Kill Your TV <killyourtv@i2pmail.org>  Sat, 20 Jun 2015 11:22:28 +0000
-
 i2p (0.9.20-2) unstable; urgency=medium
 
   [str4d]
@@ -326,11 +331,9 @@ i2p (0.9.16-1) unstable; urgency=medium
     - Translation updates
     - Update GeoIP data
 
- -- Kill Your TV <killyourtv@i2pmail.org>  Sat, 01 Nov 2014 23:34:28 +0000
-
 i2p (0.9.15-1) unstable; urgency=medium
 
-  * New Upstream Version
+  * New Upstream release
     - Add support for Ed25519 signatures
     - i2psnark move to separate config file for each torrent to better support
       per-torrent settings
@@ -367,10 +370,14 @@ i2p (0.9.14.1-1) unstable; urgency=medium
     - Console:
       + Fix update buttons
       + Don't filter parameter names starting with "nofilter_"
-      + Re-allow configadvanced, news URL, and unsigned update URL if routerconsole.advanced=true
-      + Re-allow plugin install if routerconsole.advanced=true or routerconsole.enablePluginInstall=true
-      + Only allow whitelisted plugin signers, unless routerconsole.allowUntrustedPlugins=true
-      + Re-allow clients.config changes if routerconsole.advanced=true or routerconsole.enableClientChange=true
+      + Re-allow configadvanced, news URL, and unsigned update URL if
+        routerconsole.advanced=true
+      + Re-allow plugin install if routerconsole.advanced=true or
+        routerconsole.enablePluginInstall=true
+      + Only allow whitelisted plugin signers, unless
+        routerconsole.allowUntrustedPlugins=true
+      + Re-allow clients.config changes if routerconsole.advanced=true or
+        routerconsole.enableClientChange=true
       + More escaping
     - i2psnark: Fix add torrent form
     - ExecNamingService: Remove
@@ -394,10 +401,12 @@ i2p (0.9.14-1) unstable; urgency=high
     - Several i2psnark improvements and fixes (GUI and DHT), including changes
       for better compatibility with Vuze
   * Other
-    - Reseeding now fetches a signed zip file containing router infos for security and speed
+    - Reseeding now fetches a signed zip file containing router infos for
+      security and speed
     - Use JVM's AES implementation if it is faster
     - More advanced options shown in the i2ptunnel edit pages
-    - Per-message reliabilitiy settings in I2CP and error propagation back from router to client
+    - Per-message reliabilitiy settings in I2CP and error propagation back
+      from router to client
     - Lots of findbugs fixes and cleanups
     - Support signature types in SAM, bump rev to 3.1
     - New event log page in console
@@ -439,94 +448,46 @@ i2p (0.9.11-3) unstable; urgency=medium
 
 i2p (0.9.11-1) unstable; urgency=medium
 
-  * New Upstream Version
-  * Debconf: New Japanese and Korean translations
+  * New release
+  * Debconf: New Korean and Polish translations
 
- -- Kill Your TV <killyourtv@i2pmail.org>  Sat, 08 Feb 2014 22:31:59 +0000
+ -- Kill Your TV <killyourtv@i2pmail.org>  Sat, 09 Feb 2014 00:00:00 +0000
 
 i2p (0.9.10-1) unstable; urgency=medium
 
-  * New Upstream Version
+  * New release
   * Remove /var/lib/i2p when i2p package is purged.
   * Bump standards version to 3.9.5 (no changes needed)
 
  -- Kill Your TV <killyourtv@i2pmail.org>  Wed, 22 Jan 2014 16:00:24 +0000
 
-i2p (0.9.9-1deb8u1) unstable; urgency=medium
+i2p (0.9.9-1) unstable; urgency=medium
 
-  * New Upstream Version
-  * Drop from debian/patches (already in 0.9.9):
-    - 0006-allow-webapps-to-be-preseeded.patch
-    - 0007-geoipv6-fix.patch
-    - 0008-IPv6-categories-in-netdb.patch
-    - 0009-mark-ipv6-only-as-experimental.patch
-    - 0010-snark-start-torrent-by-default.patch
-    - 0011-fix-start-and-start-all-buttons.patch
-    - 0012-add-no.i2p-registrar.patch
-    - 0013-persistent-keying-for-SOCKS-tunnels.patch
-    - 0014-post-limiter.patch
-    - 0015-home-remove-config-when-restoring-default.patch
-    - 0016-new-netdb-categories.patch
-    - 0017-updated-trac-links.patch
+  * New Upstream release
   * debconf:
     - Updated French translation
     - New Romanian translation
 
  -- Kill Your TV <killyourtv@i2pmail.org>  Sat, 07 Dec 2013 18:17:24 +0000
 
-i2p (0.9.8.1-deb8u1) stable; urgency=low
-
-  * Change initscript to grant read/write permissions to members of the i2psvc
-    group.
-  * Postinst: Silence a misleading warning
-
- -- Kill Your TV <killyourtv@i2pmail.org>  Thu, 07 Nov 2013 00:22:48 +0000
-
-i2p (0.9.8.1-1deb1) stable; urgency=low
-
-  * New upstream version 0.9.8.1. Initially I was not going to build 0.9.8.1
-    packages since 0.9.8.1 was a Windows-only point release but I thought it
-    would be good to have it in Tails. At the same time we may as well
-    cherry-pick some easy bugfixes/updates from mtn.
-  * debian/rules: Set the builddistribution specific versions
-  * use xz for the 'debian' quilt 3.0 tarball
-  * Cherry-picked fixes/updates:
-    - Allow webapps.config to be preseeded by distributions
-    - IPv6:
-      + GeoIPv6 fixes (ticket #1096)
-      + Add IPv6 NetDB categories
-      + Mark IPv6-only as experimental
-    - I2PSnark:
-      + Start torrent by default
-      + Fix start and start-all buttons on text browsers and Opera
-        (ticket #1093)
-    - I2PTunnel:
-      + Post limiter
-      + Persistent keying for SOCKS tunnels (ticket #1088)
-    - Add no.i2p registrar
-    - Remove config when restoring default settings
-    - Additional NetDB categories
-    - Change Trac links to HTTPS
-
- -- Kill Your TV <killyourtv@i2pmail.org>  Tue, 05 Nov 2013 17:34:38 +0000
-
-i2p (0.9.8-1) stable; urgency=low
+i2p (0.9.8-1) unstable; urgency=low
 
   * New Upstream Version
   * Debconf: updated Swedish translation
 
  -- Kill Your TV <killyourtv@i2pmail.org>  Mon, 30 Sep 2013 16:14:40 +0000
 
-i2p (0.9.7.1-1) stable; urgency=low
+i2p (0.9.7.1-1) unstable; urgency=low
 
   * New upstream version 0.9.7.1
   * Compress packages with xz
 
- -- Kill Your TV <killyourtv@i2pmail.org>  Sat, 10 Aug 2013 19:02:24 +0000
+ -- Kill Your TV <killyourtv@i2pmail.org>  Sat, 10 Aug 2013 22:10:08 +0000
 
 i2p (0.9.7-2) unstable; urgency=low
 
   * Bugfix: Add missing ; to i2prouter script.
+  * Test scripts with "sh -n" in the build target
 
  -- Kill Your TV <killyourtv@i2pmail.org>  Tue, 16 Jul 2013 11:08:48 +0000
 
@@ -542,15 +503,16 @@ i2p (0.9.7-1) unstable; urgency=low
 i2p (0.9.6-1) unstable; urgency=low
 
   * New upstream release
+  * i2prouter: allow overrides to be set in /etc/default/i2p
 
- -- Kill Your TV <killyourtv@i2pmail.org>  Mon, 27 May 2013 23:18:54 +0000
+ -- Kill Your TV <killyourtv@i2pmail.org>  Mon, 27 May 2013 00:00:00 +0000
 
 i2p (0.9.5-2) unstable; urgency=low
 
   * debian/i2p.postinst: Explicitly set permissions on /etc/i2p/wrapper.config
-    to compensate for stricter umasks. Fixes #906.
+    to compensate for stricter umasks.
 
- -- Kill Your TV <killyourtv@i2pmail.org>  Sun, 31 Mar 2013 12:53:43 +0000
+ -- Kill Your TV <killyourtv@i2pmail.org>  Sun, 31 Mar 2013 12:50:17 +0000
 
 i2p (0.9.5-1) unstable; urgency=low
 
@@ -561,19 +523,19 @@ i2p (0.9.5-1) unstable; urgency=low
 
  -- Kill Your TV <killyourtv@i2pmail.org>  Fri, 08 Mar 2013 23:04:51 +0000
 
-i2p (0.9.4+repack-3) unstable; urgency=low
+i2p (0.9.4-3) unstable; urgency=low
 
   * Backport fix from MTN for ticket #817
 
  -- Kill Your TV <killyourtv@i2pmail.org>  Sat, 22 Dec 2012 13:07:47 +0000
 
-i2p (0.9.4+repack-2) unstable; urgency=low
+i2p (0.9.4-2) unstable; urgency=low
 
   * Add missing build-dep on libservice-wrapper-java
 
  -- Kill Your TV <killyourtv@i2pmail.org>  Mon, 17 Dec 2012 20:40:07 +0000
 
-i2p (0.9.4+repack-1) unstable; urgency=low
+i2p (0.9.4-1) stable; urgency=low
 
   * explicitly prefer openjdk-*-headless over default-jre-headless. Debian
     Squeeze has default-jre-headless set to gij. Performance with gij is
@@ -610,10 +572,10 @@ i2p (0.9.4+repack-1) unstable; urgency=low
 
  -- Kill Your TV <killyourtv@i2pmail.org>  Mon, 17 Dec 2012 23:59:59 +0000
 
-i2p (0.9.3+repack-1) unstable; urgency=low
+i2p (0.9.3-1) stable; urgency=low
 
   * New Upstream release
-  * Upstream changelog:
+  * Upstream changelog (full details in history.txt):
     - Active Queue Management
     - I2PSnark DHT: Several bug fixes, enable by default.
     - Priority queues
@@ -644,19 +606,19 @@ i2p (0.9.3+repack-1) unstable; urgency=low
 
  -- Kill Your TV <killyourtv@i2pmail.org>  Sat, 27 Oct 2012 16:47:37 +0000
 
-i2p (0.9.2+repack-2) unstable; urgency=high
+i2p (0.9.2-2) stable; urgency=high
 
   * Fix stupid bug in i2prouter
 
  -- Kill Your TV <killyourtv@i2pmail.org>  Sat, 22 Sep 2012 13:57:39 +0000
 
-i2p (0.9.2+repack-1) stable; urgency=low
+i2p (0.9.2-1) stable; urgency=low
 
   * New upstream release (see history.txt for details)
 
  -- Kill Your TV <killyourtv@i2pmail.org>  Fri, 21 Sep 2012 18:13:32 +0000
 
-i2p (0.9.1+repack-1) unstable; urgency=low
+i2p (0.9.1-1) stable; urgency=low
 
   * New upstream version 0.9.1
   * Don't depend on Debian's/Ubuntu's version of Jetty. Jetty6 is going away
@@ -671,13 +633,13 @@ i2p (0.9.1+repack-1) unstable; urgency=low
 
  -- Kill Your TV <killyourtv@i2pmail.org>  Mon, 30 Jul 2012 17:41:04 +0000
 
-i2p (0.9-1) unstable; urgency=low
+i2p (0.9-1) stable; urgency=low
 
   * New Upstream Version
 
  -- Kill Your TV <killyourtv@i2pmail.org>  Wed, 02 May 2012 16:33:11 +0000
 
-i2p (0.8.13-2) unstable; urgency=low
+i2p (0.8.13-2) stable; urgency=low
 
   * Fix bug in postinst cause by changes to adduser's behaviour.
 
@@ -724,38 +686,38 @@ i2p (0.8.12-1) stable; urgency=low
 
  -- Kill Your TV <killyourtv@i2pmail.org>  Fri, 06 Jan 2012 02:49:03 +0000
 
-i2p (0.8.11+repack-2) stable; urgency=medium
+i2p (0.8.11-2) stable; urgency=medium
 
   * Fix STUPID bug running I2P with i2prouter. Thanks soundwave.
 
  -- Kill Your TV <killyourtv@i2pmail.org>  Tue, 08 Nov 2011 20:02:05 +0000
 
-i2p (0.8.11+repack-1) stable; urgency=low
+i2p (0.8.11-1) stable; urgency=low
 
   * New Upstream Version
   * sv and uk debconf translation updates
 
  -- Kill Your TV <killyourtv@i2pmail.org>  Mon, 07 Nov 2011 19:20:15 +0000
 
-i2p (0.8.10+repack-1) stable; urgency=medium
+i2p (0.8.10-1) stable; urgency=medium
 
   * New upstream version
 
  -- Kill Your TV <killyourtv@i2pmail.org>  Thu, 20 Oct 2011 05:25:04 +0000
 
-i2p (0.8.9+repack-1) stable; urgency=medium
+i2p (0.8.9-1) stable; urgency=medium
 
   * New upstream version
 
  -- Kill Your TV <killyourtv@i2pmail.org>  Tue, 11 Oct 2011 19:55:08 +0000
 
-i2p (0.8.8+repack-3) UNRELEASED; urgency=low
+i2p (0.8.8-3) UNRELEASED; urgency=low
 
   * Add dump option to initscript
 
  -- Kill Your TV <killyourtv@i2pmail.org>  Tue, 06 Sep 2011 12:42:22 +0000
 
-i2p (0.8.8+repack-2) stable; urgency=medium
+i2p (0.8.8-2) stable; urgency=medium
 
   * Backport patch from mtn 04ec606 to fix trac #515
   * Fix trac ticket #514 ("debconf values are overwritten upon
@@ -765,7 +727,7 @@ i2p (0.8.8+repack-2) stable; urgency=medium
 
  -- Kill Your TV <killyourtv@i2pmail.org>  Fri, 02 Sep 2011 23:32:32 +0000
 
-i2p (0.8.8+repack-1) stable; urgency=low
+i2p (0.8.8-1) stable; urgency=low
 
   * New Upstream Version
 
diff --git a/debian/changelog b/debian/changelog
index 18b5f90384272ae805dea959daa943a15d5922ae..c515372c845d561fcf3933945678209a41e37bb8 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,14 +1,8 @@
-i2p (0.9.25-1ubuntu1) trusty; urgency=medium
+i2p (0.9.25-1~deb8u+1) stable; urgency=medium
 
-  * New upstream version 0.9.25
+  * Backport to Jessie
 
- -- zzz on i2p (key signing) <zzz@i2pmail.org>  Sat, 26 Mar 2016 12:12:12 +0000
-
-i2p (0.9.24-1ubuntu1) trusty; urgency=medium
-
-  * Upload to PPA
-
- -- Kill Your TV <killyourtv@i2pmail.org>  Sat, 30 Jan 2016 14:12:27 +0000
+ -- zzz on i2p <zzz@i2pmail.org>  Tue, 29 Mar 2016 18:12:12 +0000
 
 i2p (0.9.24-1) unstable; urgency=medium
 
@@ -118,6 +112,7 @@ i2p (0.9.20-3) unstable; urgency=medium
   * Add datagram exception to the apparmor profile
 
  -- Kill Your TV <killyourtv@i2pmail.org>  Sat, 20 Jun 2015 11:22:28 +0000
+
 i2p (0.9.20-2) unstable; urgency=medium
 
   [str4d]
@@ -331,9 +326,11 @@ i2p (0.9.16-1) unstable; urgency=medium
     - Translation updates
     - Update GeoIP data
 
+ -- Kill Your TV <killyourtv@i2pmail.org>  Sat, 01 Nov 2014 23:34:28 +0000
+
 i2p (0.9.15-1) unstable; urgency=medium
 
-  * New Upstream release
+  * New Upstream Version
     - Add support for Ed25519 signatures
     - i2psnark move to separate config file for each torrent to better support
       per-torrent settings
@@ -370,14 +367,10 @@ i2p (0.9.14.1-1) unstable; urgency=medium
     - Console:
       + Fix update buttons
       + Don't filter parameter names starting with "nofilter_"
-      + Re-allow configadvanced, news URL, and unsigned update URL if
-        routerconsole.advanced=true
-      + Re-allow plugin install if routerconsole.advanced=true or
-        routerconsole.enablePluginInstall=true
-      + Only allow whitelisted plugin signers, unless
-        routerconsole.allowUntrustedPlugins=true
-      + Re-allow clients.config changes if routerconsole.advanced=true or
-        routerconsole.enableClientChange=true
+      + Re-allow configadvanced, news URL, and unsigned update URL if routerconsole.advanced=true
+      + Re-allow plugin install if routerconsole.advanced=true or routerconsole.enablePluginInstall=true
+      + Only allow whitelisted plugin signers, unless routerconsole.allowUntrustedPlugins=true
+      + Re-allow clients.config changes if routerconsole.advanced=true or routerconsole.enableClientChange=true
       + More escaping
     - i2psnark: Fix add torrent form
     - ExecNamingService: Remove
@@ -401,12 +394,10 @@ i2p (0.9.14-1) unstable; urgency=high
     - Several i2psnark improvements and fixes (GUI and DHT), including changes
       for better compatibility with Vuze
   * Other
-    - Reseeding now fetches a signed zip file containing router infos for
-      security and speed
+    - Reseeding now fetches a signed zip file containing router infos for security and speed
     - Use JVM's AES implementation if it is faster
     - More advanced options shown in the i2ptunnel edit pages
-    - Per-message reliabilitiy settings in I2CP and error propagation back
-      from router to client
+    - Per-message reliabilitiy settings in I2CP and error propagation back from router to client
     - Lots of findbugs fixes and cleanups
     - Support signature types in SAM, bump rev to 3.1
     - New event log page in console
@@ -448,46 +439,94 @@ i2p (0.9.11-3) unstable; urgency=medium
 
 i2p (0.9.11-1) unstable; urgency=medium
 
-  * New release
-  * Debconf: New Korean and Polish translations
+  * New Upstream Version
+  * Debconf: New Japanese and Korean translations
 
- -- Kill Your TV <killyourtv@i2pmail.org>  Sat, 09 Feb 2014 00:00:00 +0000
+ -- Kill Your TV <killyourtv@i2pmail.org>  Sat, 08 Feb 2014 22:31:59 +0000
 
 i2p (0.9.10-1) unstable; urgency=medium
 
-  * New release
+  * New Upstream Version
   * Remove /var/lib/i2p when i2p package is purged.
   * Bump standards version to 3.9.5 (no changes needed)
 
  -- Kill Your TV <killyourtv@i2pmail.org>  Wed, 22 Jan 2014 16:00:24 +0000
 
-i2p (0.9.9-1) unstable; urgency=medium
+i2p (0.9.9-1deb8u1) unstable; urgency=medium
 
-  * New Upstream release
+  * New Upstream Version
+  * Drop from debian/patches (already in 0.9.9):
+    - 0006-allow-webapps-to-be-preseeded.patch
+    - 0007-geoipv6-fix.patch
+    - 0008-IPv6-categories-in-netdb.patch
+    - 0009-mark-ipv6-only-as-experimental.patch
+    - 0010-snark-start-torrent-by-default.patch
+    - 0011-fix-start-and-start-all-buttons.patch
+    - 0012-add-no.i2p-registrar.patch
+    - 0013-persistent-keying-for-SOCKS-tunnels.patch
+    - 0014-post-limiter.patch
+    - 0015-home-remove-config-when-restoring-default.patch
+    - 0016-new-netdb-categories.patch
+    - 0017-updated-trac-links.patch
   * debconf:
     - Updated French translation
     - New Romanian translation
 
  -- Kill Your TV <killyourtv@i2pmail.org>  Sat, 07 Dec 2013 18:17:24 +0000
 
-i2p (0.9.8-1) unstable; urgency=low
+i2p (0.9.8.1-deb8u1) stable; urgency=low
+
+  * Change initscript to grant read/write permissions to members of the i2psvc
+    group.
+  * Postinst: Silence a misleading warning
+
+ -- Kill Your TV <killyourtv@i2pmail.org>  Thu, 07 Nov 2013 00:22:48 +0000
+
+i2p (0.9.8.1-1deb1) stable; urgency=low
+
+  * New upstream version 0.9.8.1. Initially I was not going to build 0.9.8.1
+    packages since 0.9.8.1 was a Windows-only point release but I thought it
+    would be good to have it in Tails. At the same time we may as well
+    cherry-pick some easy bugfixes/updates from mtn.
+  * debian/rules: Set the builddistribution specific versions
+  * use xz for the 'debian' quilt 3.0 tarball
+  * Cherry-picked fixes/updates:
+    - Allow webapps.config to be preseeded by distributions
+    - IPv6:
+      + GeoIPv6 fixes (ticket #1096)
+      + Add IPv6 NetDB categories
+      + Mark IPv6-only as experimental
+    - I2PSnark:
+      + Start torrent by default
+      + Fix start and start-all buttons on text browsers and Opera
+        (ticket #1093)
+    - I2PTunnel:
+      + Post limiter
+      + Persistent keying for SOCKS tunnels (ticket #1088)
+    - Add no.i2p registrar
+    - Remove config when restoring default settings
+    - Additional NetDB categories
+    - Change Trac links to HTTPS
+
+ -- Kill Your TV <killyourtv@i2pmail.org>  Tue, 05 Nov 2013 17:34:38 +0000
+
+i2p (0.9.8-1) stable; urgency=low
 
   * New Upstream Version
   * Debconf: updated Swedish translation
 
  -- Kill Your TV <killyourtv@i2pmail.org>  Mon, 30 Sep 2013 16:14:40 +0000
 
-i2p (0.9.7.1-1) unstable; urgency=low
+i2p (0.9.7.1-1) stable; urgency=low
 
   * New upstream version 0.9.7.1
   * Compress packages with xz
 
- -- Kill Your TV <killyourtv@i2pmail.org>  Sat, 10 Aug 2013 22:10:08 +0000
+ -- Kill Your TV <killyourtv@i2pmail.org>  Sat, 10 Aug 2013 19:02:24 +0000
 
 i2p (0.9.7-2) unstable; urgency=low
 
   * Bugfix: Add missing ; to i2prouter script.
-  * Test scripts with "sh -n" in the build target
 
  -- Kill Your TV <killyourtv@i2pmail.org>  Tue, 16 Jul 2013 11:08:48 +0000
 
@@ -503,16 +542,15 @@ i2p (0.9.7-1) unstable; urgency=low
 i2p (0.9.6-1) unstable; urgency=low
 
   * New upstream release
-  * i2prouter: allow overrides to be set in /etc/default/i2p
 
- -- Kill Your TV <killyourtv@i2pmail.org>  Mon, 27 May 2013 00:00:00 +0000
+ -- Kill Your TV <killyourtv@i2pmail.org>  Mon, 27 May 2013 23:18:54 +0000
 
 i2p (0.9.5-2) unstable; urgency=low
 
   * debian/i2p.postinst: Explicitly set permissions on /etc/i2p/wrapper.config
-    to compensate for stricter umasks.
+    to compensate for stricter umasks. Fixes #906.
 
- -- Kill Your TV <killyourtv@i2pmail.org>  Sun, 31 Mar 2013 12:50:17 +0000
+ -- Kill Your TV <killyourtv@i2pmail.org>  Sun, 31 Mar 2013 12:53:43 +0000
 
 i2p (0.9.5-1) unstable; urgency=low
 
@@ -523,19 +561,19 @@ i2p (0.9.5-1) unstable; urgency=low
 
  -- Kill Your TV <killyourtv@i2pmail.org>  Fri, 08 Mar 2013 23:04:51 +0000
 
-i2p (0.9.4-3) unstable; urgency=low
+i2p (0.9.4+repack-3) unstable; urgency=low
 
   * Backport fix from MTN for ticket #817
 
  -- Kill Your TV <killyourtv@i2pmail.org>  Sat, 22 Dec 2012 13:07:47 +0000
 
-i2p (0.9.4-2) unstable; urgency=low
+i2p (0.9.4+repack-2) unstable; urgency=low
 
   * Add missing build-dep on libservice-wrapper-java
 
  -- Kill Your TV <killyourtv@i2pmail.org>  Mon, 17 Dec 2012 20:40:07 +0000
 
-i2p (0.9.4-1) stable; urgency=low
+i2p (0.9.4+repack-1) unstable; urgency=low
 
   * explicitly prefer openjdk-*-headless over default-jre-headless. Debian
     Squeeze has default-jre-headless set to gij. Performance with gij is
@@ -572,10 +610,10 @@ i2p (0.9.4-1) stable; urgency=low
 
  -- Kill Your TV <killyourtv@i2pmail.org>  Mon, 17 Dec 2012 23:59:59 +0000
 
-i2p (0.9.3-1) stable; urgency=low
+i2p (0.9.3+repack-1) unstable; urgency=low
 
   * New Upstream release
-  * Upstream changelog (full details in history.txt):
+  * Upstream changelog:
     - Active Queue Management
     - I2PSnark DHT: Several bug fixes, enable by default.
     - Priority queues
@@ -606,19 +644,19 @@ i2p (0.9.3-1) stable; urgency=low
 
  -- Kill Your TV <killyourtv@i2pmail.org>  Sat, 27 Oct 2012 16:47:37 +0000
 
-i2p (0.9.2-2) stable; urgency=high
+i2p (0.9.2+repack-2) unstable; urgency=high
 
   * Fix stupid bug in i2prouter
 
  -- Kill Your TV <killyourtv@i2pmail.org>  Sat, 22 Sep 2012 13:57:39 +0000
 
-i2p (0.9.2-1) stable; urgency=low
+i2p (0.9.2+repack-1) stable; urgency=low
 
   * New upstream release (see history.txt for details)
 
  -- Kill Your TV <killyourtv@i2pmail.org>  Fri, 21 Sep 2012 18:13:32 +0000
 
-i2p (0.9.1-1) stable; urgency=low
+i2p (0.9.1+repack-1) unstable; urgency=low
 
   * New upstream version 0.9.1
   * Don't depend on Debian's/Ubuntu's version of Jetty. Jetty6 is going away
@@ -633,13 +671,13 @@ i2p (0.9.1-1) stable; urgency=low
 
  -- Kill Your TV <killyourtv@i2pmail.org>  Mon, 30 Jul 2012 17:41:04 +0000
 
-i2p (0.9-1) stable; urgency=low
+i2p (0.9-1) unstable; urgency=low
 
   * New Upstream Version
 
  -- Kill Your TV <killyourtv@i2pmail.org>  Wed, 02 May 2012 16:33:11 +0000
 
-i2p (0.8.13-2) stable; urgency=low
+i2p (0.8.13-2) unstable; urgency=low
 
   * Fix bug in postinst cause by changes to adduser's behaviour.
 
@@ -686,38 +724,38 @@ i2p (0.8.12-1) stable; urgency=low
 
  -- Kill Your TV <killyourtv@i2pmail.org>  Fri, 06 Jan 2012 02:49:03 +0000
 
-i2p (0.8.11-2) stable; urgency=medium
+i2p (0.8.11+repack-2) stable; urgency=medium
 
   * Fix STUPID bug running I2P with i2prouter. Thanks soundwave.
 
  -- Kill Your TV <killyourtv@i2pmail.org>  Tue, 08 Nov 2011 20:02:05 +0000
 
-i2p (0.8.11-1) stable; urgency=low
+i2p (0.8.11+repack-1) stable; urgency=low
 
   * New Upstream Version
   * sv and uk debconf translation updates
 
  -- Kill Your TV <killyourtv@i2pmail.org>  Mon, 07 Nov 2011 19:20:15 +0000
 
-i2p (0.8.10-1) stable; urgency=medium
+i2p (0.8.10+repack-1) stable; urgency=medium
 
   * New upstream version
 
  -- Kill Your TV <killyourtv@i2pmail.org>  Thu, 20 Oct 2011 05:25:04 +0000
 
-i2p (0.8.9-1) stable; urgency=medium
+i2p (0.8.9+repack-1) stable; urgency=medium
 
   * New upstream version
 
  -- Kill Your TV <killyourtv@i2pmail.org>  Tue, 11 Oct 2011 19:55:08 +0000
 
-i2p (0.8.8-3) UNRELEASED; urgency=low
+i2p (0.8.8+repack-3) UNRELEASED; urgency=low
 
   * Add dump option to initscript
 
  -- Kill Your TV <killyourtv@i2pmail.org>  Tue, 06 Sep 2011 12:42:22 +0000
 
-i2p (0.8.8-2) stable; urgency=medium
+i2p (0.8.8+repack-2) stable; urgency=medium
 
   * Backport patch from mtn 04ec606 to fix trac #515
   * Fix trac ticket #514 ("debconf values are overwritten upon
@@ -727,7 +765,7 @@ i2p (0.8.8-2) stable; urgency=medium
 
  -- Kill Your TV <killyourtv@i2pmail.org>  Fri, 02 Sep 2011 23:32:32 +0000
 
-i2p (0.8.8-1) stable; urgency=low
+i2p (0.8.8+repack-1) stable; urgency=low
 
   * New Upstream Version
 
diff --git a/debian/control b/debian/control
index e56a71ac9577f9247ca3ace2f17a80f52519c6e1..cbd1866f1dd060ed3d26716c73bf4b6b3bfc0f1e 100644
--- a/debian/control
+++ b/debian/control
@@ -10,6 +10,7 @@ Build-Depends: debhelper (>= 7.0.50~)
  ,ant-optional
  ,debconf
  ,openjdk-7-jdk
+ ,libjetty8-java, libservlet3.0-java
  ,dh-apparmor
  ,gettext
  ,libgmp-dev (>= 2:5.0.5)
@@ -70,7 +71,10 @@ Architecture: all
 Section: net
 Priority: optional
 Depends: ${misc:Depends}, ${java:Depends}, ${shlibs:Depends},
- openjdk-8-jre-headless | openjdk-7-jre-headless | default-jre-headless | java8-runtime-headless | java7-runtime-headless, libecj-java
+ openjdk-8-jre-headless | openjdk-7-jre-headless | default-jre-headless | java8-runtime-headless | java7-runtime-headless,
+ libecj-java,
+ geoip-database,
+ libjetty8-java, libservlet3.0-java
 Replaces: i2p ( << 0.8.6-5)
 Breaks: i2p (<< 0.8.6-5)
 Recommends: libjbigi-jni, ttf-dejavu
diff --git a/debian/i2p-router.install b/debian/i2p-router.install
index afc5353256fb26ab616ef6aac8750a8090b8352f..162dcf8f875e29ba3c3bb7e7654e39e58aa98056 100644
--- a/debian/i2p-router.install
+++ b/debian/i2p-router.install
@@ -20,36 +20,64 @@ pkg-temp/webapps usr/share/i2p
 
 
 pkg-temp/lib/BOB.jar usr/share/i2p/lib
-pkg-temp/lib/commons-el.jar usr/share/i2p/lib
-pkg-temp/lib/commons-logging.jar usr/share/i2p/lib
 pkg-temp/lib/desktopgui.jar usr/share/i2p/lib
 pkg-temp/lib/i2p.jar usr/share/i2p/lib
 pkg-temp/lib/i2psnark.jar usr/share/i2p/lib
 pkg-temp/lib/i2ptunnel.jar usr/share/i2p/lib
-pkg-temp/lib/jasper-runtime.jar usr/share/i2p/lib
-pkg-temp/lib/javax.servlet.jar usr/share/i2p/lib
-pkg-temp/lib/jetty-continuation.jar usr/share/i2p/lib
-pkg-temp/lib/jetty-deploy.jar usr/share/i2p/lib
-pkg-temp/lib/jetty-http.jar usr/share/i2p/lib
 pkg-temp/lib/jetty-i2p.jar usr/share/i2p/lib
-pkg-temp/lib/jetty-io.jar usr/share/i2p/lib
-pkg-temp/lib/jetty-rewrite-handler.jar usr/share/i2p/lib
-pkg-temp/lib/jetty-security.jar usr/share/i2p/lib
-pkg-temp/lib/jetty-servlet.jar usr/share/i2p/lib
-pkg-temp/lib/jetty-servlets.jar usr/share/i2p/lib
-pkg-temp/lib/jetty-start.jar usr/share/i2p/lib
-pkg-temp/lib/jetty-util.jar usr/share/i2p/lib
-pkg-temp/lib/jetty-webapp.jar usr/share/i2p/lib
-pkg-temp/lib/jetty-xml.jar usr/share/i2p/lib
 pkg-temp/lib/jrobin.jar usr/share/i2p/lib
-pkg-temp/lib/jstl.jar usr/share/i2p/lib
 pkg-temp/lib/mstreaming.jar usr/share/i2p/lib
-pkg-temp/lib/org.mortbay.jetty.jar usr/share/i2p/lib
-pkg-temp/lib/org.mortbay.jmx.jar usr/share/i2p/lib
 pkg-temp/lib/routerconsole.jar usr/share/i2p/lib
 pkg-temp/lib/router.jar usr/share/i2p/lib
 pkg-temp/lib/sam.jar usr/share/i2p/lib
-pkg-temp/lib/standard.jar usr/share/i2p/lib
 pkg-temp/lib/streaming.jar usr/share/i2p/lib
 pkg-temp/lib/systray4j.jar usr/share/i2p/lib
 pkg-temp/lib/systray.jar usr/share/i2p/lib
+
+
+# uncomment if not building with libjetty8-java
+# ubuntu: only in wily
+# debian: in wheezy jessie stretch sid
+#pkg-temp/lib/jetty-continuation.jar usr/share/i2p/lib
+#pkg-temp/lib/jetty-deploy.jar usr/share/i2p/lib
+#pkg-temp/lib/jetty-http.jar usr/share/i2p/lib
+#pkg-temp/lib/jetty-io.jar usr/share/i2p/lib
+#pkg-temp/lib/jetty-rewrite-handler.jar usr/share/i2p/lib
+#pkg-temp/lib/jetty-security.jar usr/share/i2p/lib
+#pkg-temp/lib/jetty-servlet.jar usr/share/i2p/lib
+#pkg-temp/lib/jetty-servlets.jar usr/share/i2p/lib
+#pkg-temp/lib/jetty-start.jar usr/share/i2p/lib
+#pkg-temp/lib/jetty-util.jar usr/share/i2p/lib
+#pkg-temp/lib/jetty-webapp.jar usr/share/i2p/lib
+#pkg-temp/lib/jetty-xml.jar usr/share/i2p/lib
+#pkg-temp/lib/org.mortbay.jetty.jar usr/share/i2p/lib
+#pkg-temp/lib/org.mortbay.jmx.jar usr/share/i2p/lib
+# following two are from libservlet3.0-java which is a dependency of libjetty8-java
+#pkg-temp/lib/javax.servlet.jar usr/share/i2p/lib
+
+
+# uncomment if not building with libservlet2.5-java
+# ubuntu: only in wily
+# debian: in wheezy jessie stretch sid
+pkg-temp/lib/commons-el.jar usr/share/i2p/lib
+
+
+# uncomment if not building with libtomcat6-java
+# ubuntu: only in precise trusty vivid
+# debian: only in wheezy
+# todo: see if libtomcat7-java will work
+# legacy name, contains only tomcat-juli, not commons-logging
+pkg-temp/lib/commons-logging.jar usr/share/i2p/lib
+pkg-temp/lib/jasper-runtime.jar usr/share/i2p/lib
+
+
+# uncomment if not building with libjakarta-taglibs-standard-java
+# ubuntu: only in wily
+# debian: in wheezy jessie stretch sid
+pkg-temp/lib/jstl.jar usr/share/i2p/lib
+
+
+# uncomment if not building with libjstl1.1-java
+# ubuntu: in precise trusty vivid wily xenial
+# debian: in wheezy jessie stretch sid
+pkg-temp/lib/standard.jar usr/share/i2p/lib
diff --git a/debian/i2p-router.links b/debian/i2p-router.links
index 9371f8e7b84c10215b42c2e44ca4f2af0dc68ce5..719c32917fe7d8c9620c994657bec0072b0b608b 100644
--- a/debian/i2p-router.links
+++ b/debian/i2p-router.links
@@ -3,4 +3,60 @@ usr/share/common-licenses/LGPL-2.1 usr/share/doc/i2p-router/licenses/LICENSE-LGP
 usr/share/common-licenses/Apache-2.0 usr/share/doc/i2p-router/licenses/LICENSE-Apache2.0.txt
 usr/share/common-licenses/BSD usr/share/doc/i2p-router/licenses/LICENSE-BSD.txt
 
-usr/share/java/eclipse-ecj.jar usr/share/i2p/lib/eclipse-ecj.jar
+usr/share/java/eclipse-ecj.jar /usr/share/i2p/lib/eclipse-ecj.jar
+
+
+# comment out if not building with libjetty8-java
+# ubuntu: only in wily
+# debian: in wheezy jessie stretch sid
+usr/share/java/jetty8-continuation.jar usr/share/i2p/lib/jetty-continuation.jar
+usr/share/java/jetty8-deploy.jar usr/share/i2p/lib/jetty-deploy.jar
+usr/share/java/jetty8-http.jar usr/share/i2p/lib/jetty-http.jar
+usr/share/java/jetty8-io.jar usr/share/i2p/lib/jetty-io.jar
+# legacy name in lib/
+usr/share/java/jetty8-rewrite.jar usr/share/i2p/lib/jetty-rewrite-handler.jar
+usr/share/java/jetty8-security.jar usr/share/i2p/lib/jetty-security.jar
+usr/share/java/jetty8-servlet.jar usr/share/i2p/lib/jetty-servlet.jar
+usr/share/java/jetty8-servlets.jar usr/share/i2p/lib/jetty-servlets.jar
+usr/share/java/jetty8-start.jar usr/share/i2p/lib/jetty-start.jar
+usr/share/java/jetty8-util.jar usr/share/i2p/lib/jetty-util.jar
+usr/share/java/jetty8-webapp.jar usr/share/i2p/lib/jetty-webapp.jar
+usr/share/java/jetty8-xml.jar usr/share/i2p/lib/jetty-xml.jar
+# legacy name in lib/
+usr/share/java/jetty8-server.jar usr/share/i2p/lib/org.mortbay.jetty.jar
+# legacy name in lib/
+usr/share/java/jetty8-jmx.jar usr/share/i2p/lib/org.mortbay.jmx.jar
+# following two are from libservlet3.0-java which is a dependency of libjetty8-java
+# legacy name in lib/
+usr/share/java/servlet-api-3.0.jar usr/share/i2p/lib/javax.servlet.jar
+# combined into javax.servlet.jar in non-package builds
+usr/share/java/jsp-api-2.2.jar usr/share/i2p/lib/jsp-api.jar
+
+
+# comment out if not building with libservlet2.5-java
+# ubuntu: only in wily
+# debian: in wheezy jessie stretch sid
+#usr/share/java/el-api-2.1.jar usr/share/i2p/lib/commons-el.jar
+
+
+# comment out if not building with libtomcat6-java
+# ubuntu: only in precise trusty vivid
+# debian: only in wheezy
+# todo: see if libtomcat7-java will work
+# legacy name, contains only tomcat-juli, not commons-logging
+#usr/share/java/tomcat-juli.jar usr/share/i2p/lib/commons-logging.jar
+#usr/share/java/jasper.jar usr/share/i2p/lib/jasper-runtime.jar
+# combined into jasper-runtime.jar in non-package builds
+#usr/share/java/tomcat-coyote.jar usr/share/i2p/lib/tomcat-coyote.jar
+
+
+# comment out if not building with libjakarta-taglibs-standard-java
+# ubuntu: only in wily
+# debian: in wheezy jessie stretch sid
+#usr/share/java/standard.jar usr/share/i2p/lib/standard.jar
+
+
+# comment out if not building with libjstl1.1-java
+# ubuntu: in precise trusty vivid wily xenial
+# debian: in wheezy jessie stretch sid
+#usr/share/java/jstl1.1.jar usr/share/i2p/lib/jstl.jar
diff --git a/debian/repack.sh b/debian/repack.sh
index b9b49e87f1e06b0a5ccc61d857cc54c4f5522715..b92bf9a636e481846b0731c04416e972b7354536 100755
--- a/debian/repack.sh
+++ b/debian/repack.sh
@@ -29,6 +29,13 @@ echo "Filtering tarball contents..."
 bzcat "$tarball" | tar --wildcards --delete '*/installer/lib/*' \
                         --delete '*/Slackware/*' \
                         --delete '*/debian-alt/*' \
+                        --delete '*/installer/resources/geoip.txt' \
+                        --delete '*/installer/resources/geoipv6.dat.gz' \
+                        --delete '*/apps/jetty/apache-tomcat/*' \
+                        --delete '*/apps/jetty/apache-tomcat-deployer/*' \
+                        --delete '*/apps/jetty/jetty-distribution-*/*' \
+                        --delete '*/apps/susidns/src/WEB-INF/lib/jstl.jar' \
+                        --delete '*/apps/susidns/src/WEB-INF/lib/standard.jar' \
                         --delete '*/debian/*' > "$tdir/${fname}"
 
 echo "Compressing filtered tarball..."
diff --git a/debian/rules b/debian/rules
index 8d6ab28c3ee8ee8e95fd4037d4739491fb143393..db4538f6cd0050651892fa9c8dba423fd01b9a5e 100755
--- a/debian/rules
+++ b/debian/rules
@@ -77,6 +77,64 @@ endif
 	@/bin/echo -e "javac.compilerargs=-bootclasspath $(JAVA_HOME)/jre/lib/rt.jar:$(JAVA_HOME)/jre/lib/jce.jar" >> $(CURDIR)/override.properties
 	@/bin/echo -e "javac.compilerargs7=-bootclasspath $(JAVA_HOME)/jre/lib/rt.jar:$(JAVA_HOME)/jre/lib/jce.jar" >> $(CURDIR)/override.properties
 	@/bin/echo -e "build.built-by=debian" >> $(CURDIR)/override.properties
+
+	# debian and ubuntu: everywhere
+	@/bin/echo -e "with-geoip-database=true" >> $(CURDIR)/override.properties
+
+	# ubuntu: only in wily
+	# debian: in wheezy jessie stretch sid
+	@/bin/echo -e "with-libjetty8-java=true" >> $(CURDIR)/override.properties
+	mkdir -p $(CURDIR)/apps/jetty/jettylib
+	ln -sf /usr/share/java/jetty8-continuation.jar $(CURDIR)/apps/jetty/jettylib/jetty-continuation.jar
+	ln -sf /usr/share/java/jetty8-deploy.jar $(CURDIR)/apps/jetty/jettylib/jetty-deploy.jar
+	ln -sf /usr/share/java/jetty8-http.jar $(CURDIR)/apps/jetty/jettylib/jetty-http.jar
+	ln -sf /usr/share/java/jetty8-io.jar $(CURDIR)/apps/jetty/jettylib/jetty-io.jar
+	ln -sf /usr/share/java/jetty8-rewrite.jar $(CURDIR)/apps/jetty/jettylib/jetty-rewrite-handler.jar
+	ln -sf /usr/share/java/jetty8-security.jar $(CURDIR)/apps/jetty/jettylib/jetty-security.jar
+	ln -sf /usr/share/java/jetty8-servlet.jar $(CURDIR)/apps/jetty/jettylib/jetty-servlet.jar
+	ln -sf /usr/share/java/jetty8-servlets.jar $(CURDIR)/apps/jetty/jettylib/jetty-servlets.jar
+	ln -sf /usr/share/java/jetty8-start.jar $(CURDIR)/apps/jetty/jettylib/jetty-start.jar
+	ln -sf /usr/share/java/jetty8-util.jar $(CURDIR)/apps/jetty/jettylib/jetty-util.jar
+	ln -sf /usr/share/java/jetty8-webapp.jar $(CURDIR)/apps/jetty/jettylib/jetty-webapp.jar
+	ln -sf /usr/share/java/jetty8-xml.jar $(CURDIR)/apps/jetty/jettylib/jetty-xml.jar
+	ln -sf /usr/share/java/jetty8-server.jar $(CURDIR)/apps/jetty/jettylib/org.mortbay.jetty.jar
+	ln -sf /usr/share/java/jetty8-jmx.jar $(CURDIR)/apps/jetty/jettylib/org.mortbay.jmx.jar
+	# following two are from libservlet3.0-java which is a dependency of libjetty8-java
+	ln -sf /usr/share/java/servlet-api-3.0.jar $(CURDIR)/apps/jetty/jettylib/javax.servlet.jar
+	ln -sf /usr/share/java/jsp-api-2.1.jar $(CURDIR)/apps/jetty/jettylib/jsp-api.jar
+
+	# ubuntu: only in wily
+	# debian: in wheezy jessie stretch sid
+	#mkdir -p $(CURDIR)/apps/jetty/jettylib
+	#@/bin/echo -e "with-libservlet2.5-java=true" >> $(CURDIR)/override.properties
+	#ln -sf /usr/share/java/el-api-2.1.jar $(CURDIR)/apps/jetty/jettylib/commons-el.jar
+
+	# ubuntu: only in precise trusty vivid
+	# debian: only in wheezy
+	#@/bin/echo -e "with-libtomcat6-java=true" >> $(CURDIR)/override.properties
+	#mkdir -p $(CURDIR)/apps/jetty/jettylib
+	#ln -sf /usr/share/java/jasper.jar $(CURDIR)/apps/jetty/jettylib/jasper-compiler.jar
+	#ln -sf /usr/share/java/jasper.jar $(CURDIR)/apps/jetty/jettylib/jasper-runtime.jar
+	#ln -sf /usr/share/java/tomcat-coyote.jar $(CURDIR)/apps/jetty/jettylib/tomcat-coyote.jar
+	#ln -sf /usr/share/java/tomcat-juli.jar $(CURDIR)/apps/jetty/jettylib/commons-logging.jar
+
+	# debian and ubuntu: everywhere
+	#@/bin/echo -e "with-libtomcat7-java=true" >> $(CURDIR)/override.properties
+	#mkdir -p $(CURDIR)/apps/jetty/jettylib
+	#ln -sf /usr/share/java/tomcat-jasper.jar $(CURDIR)/apps/jetty/jettylib/jasper-compiler.jar
+	#ln -sf /usr/share/java/tomcat-jasper.jar $(CURDIR)/apps/jetty/jettylib/jasper-runtime.jar
+	#ln -sf /usr/share/java/tomcat-coyote.jar $(CURDIR)/apps/jetty/jettylib/tomcat-coyote.jar
+	#ln -sf /usr/share/java/tomcat-juli.jar $(CURDIR)/apps/jetty/jettylib/commons-logging.jar
+
+	# ubuntu: only in wily
+	# debian: in wheezy jessie stretch sid
+	#@/bin/echo -e "with-libjakarta-taglibs-standard-java=true" >> $(CURDIR)/override.properties
+	#ln -sf /usr/share/java/standard.jar $(CURDIR)/apps/susidns/src/WEB-INF/lib/standard.jar
+
+	# debian and ubuntu: everywhere
+	#@/bin/echo -e "with-libjstl1.1-java=true" >> $(CURDIR)/override.properties
+	#ln -sf /usr/share/java/jstl1.1.jar $(CURDIR)/apps/susidns/src/WEB-INF/lib/jstl.jar
+
 	TZ=UTC JAVA_TOOL_OPTIONS=-Dfile.encoding=UTF8 ant preppkg-unix javadoc
 	echo router.updateDisabled=true > $(I2P)/router.config
 	mv $(I2P)/runplain.sh $(I2P)/i2prouter-nowrapper
diff --git a/router/java/src/com/maxmind/geoip/Country.java b/router/java/src/com/maxmind/geoip/Country.java
new file mode 100644
index 0000000000000000000000000000000000000000..dbd3a4e7a0dcbf8c804a6864bafd2fe285e2a17d
--- /dev/null
+++ b/router/java/src/com/maxmind/geoip/Country.java
@@ -0,0 +1,63 @@
+/**
+ * Country.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;
+
+/**
+ * Represents a country.
+ * 
+ * @author Matt Tucker
+ */
+public class Country {
+
+	private String code;
+	private String name;
+
+	/**
+	 * Creates a new Country.
+	 * 
+	 * @param code
+	 *            the country code.
+	 * @param name
+	 *            the country name.
+	 */
+	public Country(String code, String name) {
+		this.code = code;
+		this.name = name;
+	}
+
+	/**
+	 * Returns the ISO two-letter country code of this country.
+	 * 
+	 * @return the country code.
+	 */
+	public String getCode() {
+		return code;
+	}
+
+	/**
+	 * Returns the name of this country.
+	 * 
+	 * @return the country name.
+	 */
+	public String getName() {
+		return name;
+	}
+}
diff --git a/router/java/src/com/maxmind/geoip/DatabaseInfo.java b/router/java/src/com/maxmind/geoip/DatabaseInfo.java
new file mode 100644
index 0000000000000000000000000000000000000000..78ff7033ded350586f0601b06b37684a416ba75a
--- /dev/null
+++ b/router/java/src/com/maxmind/geoip/DatabaseInfo.java
@@ -0,0 +1,128 @@
+/**
+ * DatabaseInfo.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.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * Encapsulates metadata about the GeoIP database. The database has a date, is a
+ * premium or standard version, and is one of the following types:
+ *
+ * <ul>
+ * <li>Country edition -- this is the most common version of the database. It
+ * includes the name of the country and it's ISO country code given an IP
+ * address.
+ * <li>Region edition -- includes the country information as well as what U.S.
+ * state or Canadian province the IP address is from if the IP address is from
+ * the U.S. or Canada.
+ * <li>City edition -- includes country, region, city, postal code, latitude,
+ * and longitude information.
+ * <li>Org edition -- includes netblock owner.
+ * <li>ISP edition -- ISP information.
+ * </ul>
+ *
+ * @see com.maxmind.geoip.LookupService#getDatabaseInfo()
+ * @author Matt Tucker
+ */
+public class DatabaseInfo {
+
+    public static final int COUNTRY_EDITION = 1;
+    public static final int REGION_EDITION_REV0 = 7;
+    public static final int REGION_EDITION_REV1 = 3;
+    public static final int CITY_EDITION_REV0 = 6;
+    public static final int CITY_EDITION_REV1 = 2;
+    public static final int ORG_EDITION = 5;
+    public static final int ISP_EDITION = 4;
+    public static final int PROXY_EDITION = 8;
+    public static final int ASNUM_EDITION = 9;
+    public static final int NETSPEED_EDITION = 10;
+    public static final int DOMAIN_EDITION = 11;
+    public static final int COUNTRY_EDITION_V6 = 12;
+    public static final int ASNUM_EDITION_V6 = 21;
+    public static final int ISP_EDITION_V6 = 22;
+    public static final int ORG_EDITION_V6 = 23;
+    public static final int DOMAIN_EDITION_V6 = 24;
+    public static final int CITY_EDITION_REV1_V6 = 30;
+    public static final int CITY_EDITION_REV0_V6 = 31;
+    public static final int NETSPEED_EDITION_REV1 = 32;
+    public static final int NETSPEED_EDITION_REV1_V6 = 33;
+
+    private static SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd");
+
+    private String info;
+
+    /**
+     * Creates a new DatabaseInfo object given the database info String.
+     *
+     * @param info
+     */
+    public DatabaseInfo(String info) {
+        this.info = info;
+    }
+
+    public int getType() {
+        if (info == null || info.length() == 0) {
+            return COUNTRY_EDITION;
+        } else {
+            // Get the type code from the database info string and then
+            // subtract 105 from the value to preserve compatability with
+            // databases from April 2003 and earlier.
+            return Integer.parseInt(info.substring(4, 7)) - 105;
+        }
+    }
+
+    /**
+     * Returns true if the database is the premium version.
+     *
+     * @return true if the premium version of the database.
+     */
+    public boolean isPremium() {
+        return !info.contains("FREE");
+    }
+
+    /**
+     * Returns the date of the database.
+     *
+     * @return the date of the database.
+     */
+    public Date getDate() {
+        for (int i = 0; i < info.length() - 9; i++) {
+            if (Character.isWhitespace(info.charAt(i))) {
+                String dateString = info.substring(i + 1, i + 9);
+                try {
+                    synchronized (formatter) {
+                        return formatter.parse(dateString);
+                    }
+                } catch (ParseException pe) {
+                }
+                break;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public String toString() {
+        return info;
+    }
+}
diff --git a/router/java/src/com/maxmind/geoip/InvalidDatabaseException.java b/router/java/src/com/maxmind/geoip/InvalidDatabaseException.java
new file mode 100644
index 0000000000000000000000000000000000000000..c5dde17c2c6149a44e318fb1e0e42951e66bfbe7
--- /dev/null
+++ b/router/java/src/com/maxmind/geoip/InvalidDatabaseException.java
@@ -0,0 +1,26 @@
+package com.maxmind.geoip;
+
+import java.io.IOException;
+
+/**
+ * Signals that there was an issue reading from the database file due to
+ * unexpected data formatting. This generally suggests that the database is
+ * corrupt or otherwise not in a format supported by the reader.
+ */
+public final class InvalidDatabaseException extends RuntimeException {
+
+    /**
+     * @param message A message describing the reason why the exception was thrown.
+     */
+    public InvalidDatabaseException(String message) {
+        super(message);
+    }
+
+    /**
+     * @param message A message describing the reason why the exception was thrown.
+     * @param cause   The cause of the exception.
+     */
+    public InvalidDatabaseException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
\ No newline at end of file
diff --git a/router/java/src/com/maxmind/geoip/Location.java b/router/java/src/com/maxmind/geoip/Location.java
new file mode 100644
index 0000000000000000000000000000000000000000..8076990697e9938c2119aa0b6b772509e4559fa9
--- /dev/null
+++ b/router/java/src/com/maxmind/geoip/Location.java
@@ -0,0 +1,62 @@
+/**
+ * Location.java
+ *
+ * Copyright (C) 2004 MaxMind LLC.  All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Lesser 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;
+
+public class Location {
+	public String countryCode;
+	public String countryName;
+	public String region;
+	public String city;
+	public String postalCode;
+	public float latitude;
+	public float longitude;
+	public int dma_code;
+	public int area_code;
+	public int metro_code;
+
+	private final static double EARTH_DIAMETER = 2 * 6378.2;
+	private final static double PI = 3.14159265;
+	private final static double RAD_CONVERT = PI / 180;
+
+	public double distance(Location loc) {
+		double delta_lat, delta_lon;
+		double temp;
+
+		float lat1 = latitude;
+		float lon1 = longitude;
+		float lat2 = loc.latitude;
+		float lon2 = loc.longitude;
+
+		// convert degrees to radians
+		lat1 *= RAD_CONVERT;
+		lat2 *= RAD_CONVERT;
+
+		// find the deltas
+		delta_lat = lat2 - lat1;
+		delta_lon = (lon2 - lon1) * RAD_CONVERT;
+
+		// Find the great circle distance
+		temp = Math.pow(Math.sin(delta_lat / 2), 2) + Math.cos(lat1)
+				* Math.cos(lat2) * Math.pow(Math.sin(delta_lon / 2), 2);
+		return EARTH_DIAMETER
+				* Math.atan2(Math.sqrt(temp), Math.sqrt(1 - temp));
+	}
+}
diff --git a/router/java/src/com/maxmind/geoip/LookupService.java b/router/java/src/com/maxmind/geoip/LookupService.java
new file mode 100644
index 0000000000000000000000000000000000000000..94687fb559ad5dd6ae7db5f5097978973b49fe4a
--- /dev/null
+++ b/router/java/src/com/maxmind/geoip/LookupService.java
@@ -0,0 +1,988 @@
+/*
+ * 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.UnknownHostException;
+import java.nio.ByteBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * 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(&quot;c:\\geoip.dat&quot;);
+ * // Assume we have a String ipAddress (in dot-decimal form).
+ * Country country = lookupService.getCountry(ipAddress);
+ * System.out.println(&quot;The country is: &quot; + country.getName());
+ * System.out.println(&quot;The country code is: &quot; + 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(&quot;/GeoIP.dat&quot;).toExternalForm()
+ *         .substring(6);
+ * LookupService lookupService = new LookupService(fileName);
+ * </pre>
+ *
+ * @author Matt Tucker (matt@jivesoftware.com)
+ */
+public class LookupService {
+
+    /**
+     * Database file.
+     */
+    private RandomAccessFile file;
+    private final File databaseFile;
+
+    /**
+     * Information about the database.
+     */
+    private DatabaseInfo databaseInfo;
+
+    private static final Charset charset = Charset.forName("ISO-8859-1");
+    private final CharsetDecoder charsetDecoder = charset.newDecoder();
+
+    /**
+     * The database type. Default is the country edition.
+     */
+    private byte databaseType = DatabaseInfo.COUNTRY_EDITION;
+
+    private int[] databaseSegments;
+    private int recordLength;
+
+    private int dboptions;
+    private byte[] dbbuffer;
+    private byte[] index_cache;
+    private long mtime;
+    private int last_netmask;
+    private static final int US_OFFSET = 1;
+    private static final int CANADA_OFFSET = 677;
+    private static final int WORLD_OFFSET = 1353;
+    private static final int FIPS_RANGE = 360;
+    private static final int COUNTRY_BEGIN = 16776960;
+    private static final int STATE_BEGIN_REV0 = 16700000;
+    private static final int STATE_BEGIN_REV1 = 16000000;
+    private static final int STRUCTURE_INFO_MAX_SIZE = 20;
+    private static final int DATABASE_INFO_MAX_SIZE = 100;
+    public static final int GEOIP_STANDARD = 0;
+    public static final int GEOIP_MEMORY_CACHE = 1;
+    public static final int GEOIP_CHECK_CACHE = 2;
+    public static final int GEOIP_INDEX_CACHE = 4;
+    public static final int GEOIP_UNKNOWN_SPEED = 0;
+    public static final int GEOIP_DIALUP_SPEED = 1;
+    public static final int GEOIP_CABLEDSL_SPEED = 2;
+    public static final int GEOIP_CORPORATE_SPEED = 3;
+
+    private static final int SEGMENT_RECORD_LENGTH = 3;
+    private static final int STANDARD_RECORD_LENGTH = 3;
+    private static final int ORG_RECORD_LENGTH = 4;
+    private static final int MAX_RECORD_LENGTH = 4;
+
+    private static final int MAX_ORG_RECORD_LENGTH = 300;
+    private static final int FULL_RECORD_LENGTH = 60;
+
+    private final Country UNKNOWN_COUNTRY = new Country("--", "N/A");
+
+    private static final String[] countryCode = { "--", "AP", "EU", "AD", "AE",
+            "AF", "AG", "AI", "AL", "AM", "CW", "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", "SX", "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", "BQ", "SS", "O1" };
+
+    private static final String[] countryName = { "N/A", "Asia/Pacific Region",
+            "Europe", "Andorra", "United Arab Emirates", "Afghanistan",
+            "Antigua and Barbuda", "Anguilla", "Albania", "Armenia", "Curacao",
+            "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",
+            "Sint Maarten (Dutch part)", "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", "Libya", "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", "Bonaire, Saint Eustatius and Saba", "South Sudan",
+            "Other" };
+
+    /* init the hashmap once at startup time */
+    static {
+        if (countryCode.length != countryName.length) {
+            throw new AssertionError("countryCode.length!=countryName.length");
+        }
+    }
+
+    /**
+     * Create a new lookup service using the specified database file.
+     *
+     * @param databaseFile
+     *            String representation of the database file.
+     * @throws 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 IOException
+     *             if an error occured creating the lookup service from the
+     *             database file.
+     */
+    public LookupService(File databaseFile) throws IOException {
+        this.databaseFile = databaseFile;
+        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 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 IOException
+     *             if an error occured creating the lookup service from the
+     *             database file.
+     */
+    public LookupService(File databaseFile, int options) throws IOException {
+        this.databaseFile = databaseFile;
+        file = new RandomAccessFile(databaseFile, "r");
+        dboptions = options;
+        init();
+    }
+
+    /**
+     * Reads meta-data from the database file.
+     *
+     * @throws IOException
+     *             if an error occurs reading from the database file.
+     */
+    private synchronized void init() throws IOException {
+        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 (int 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.ORG_EDITION_V6
+                        || databaseType == DatabaseInfo.ISP_EDITION
+                        || databaseType == DatabaseInfo.ISP_EDITION_V6
+                        || databaseType == DatabaseInfo.DOMAIN_EDITION
+                        || databaseType == DatabaseInfo.DOMAIN_EDITION_V6
+                        || databaseType == DatabaseInfo.ASNUM_EDITION
+                        || databaseType == DatabaseInfo.ASNUM_EDITION_V6
+                        || databaseType == DatabaseInfo.NETSPEED_EDITION_REV1
+                        || databaseType == DatabaseInfo.NETSPEED_EDITION_REV1_V6
+                        || databaseType == DatabaseInfo.CITY_EDITION_REV0_V6
+                        || databaseType == DatabaseInfo.CITY_EDITION_REV1_V6) {
+                    databaseSegments = new int[1];
+                    databaseSegments[0] = 0;
+                    if (databaseType == DatabaseInfo.CITY_EDITION_REV0
+                            || databaseType == DatabaseInfo.CITY_EDITION_REV1
+                            || databaseType == DatabaseInfo.ASNUM_EDITION_V6
+                            || databaseType == DatabaseInfo.NETSPEED_EDITION_REV1
+                            || databaseType == DatabaseInfo.NETSPEED_EDITION_REV1_V6
+                            || databaseType == DatabaseInfo.CITY_EDITION_REV0_V6
+                            || databaseType == DatabaseInfo.CITY_EDITION_REV1_V6
+                            || databaseType == DatabaseInfo.ASNUM_EDITION) {
+                        recordLength = STANDARD_RECORD_LENGTH;
+                    } else {
+                        recordLength = ORG_RECORD_LENGTH;
+                    }
+                    file.readFully(buf);
+                    for (int 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 = getDatabaseInfo();
+            file.close();
+        }
+        if ((dboptions & GEOIP_INDEX_CACHE) != 0) {
+            int l = databaseSegments[0] * recordLength * 2;
+            index_cache = new byte[l];
+            file.seek(0);
+            file.readFully(index_cache, 0, l);
+        } else {
+            index_cache = null;
+        }
+    }
+
+    /**
+     * Closes the lookup service.
+     */
+    public synchronized void close() {
+        try {
+            if (file != null) {
+                file.close();
+            }
+            file = null;
+        } catch (IOException e) {
+            // Here for backward compatibility.
+        }
+    }
+
+    /**
+     * @return The list of all known country names
+     */
+    public List<String> getAllCountryNames() {
+        return Arrays.asList(Arrays.copyOf(countryName, countryName.length));
+    }
+    
+    /**
+     * @return The list of all known country codes
+     */
+    public List<String> getAllCountryCodes() {
+        return Arrays.asList(Arrays.copyOf(countryCode, countryCode.length));
+    }
+    
+    /**
+     * 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 = InetAddress.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(addr);
+    }
+
+    /**
+     * 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 synchronized 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 synchronized 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.");
+        }
+        return seekCountry(ipAddress) - databaseSegments[0];
+    }
+
+    public int last_netmask() {
+        return last_netmask;
+    }
+
+    public void netmask(int nm) {
+        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.
+                    databaseInfo = new DatabaseInfo(new String(dbInfo, charset));
+                    return databaseInfo;
+                }
+                file.seek(file.getFilePointer() - 4);
+            }
+        } catch (IOException e) {
+            throw new InvalidDatabaseException("Error reading database info", e);
+        }
+        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 */
+                    close();
+                    file = new RandomAccessFile(databaseFile, "r");
+                    databaseInfo = null;
+                    init();
+                }
+            }
+        } catch (IOException e) {
+            throw new InvalidDatabaseException("Database not found", e);
+        }
+    }
+
+    // for GeoIP City only
+    public Location getLocationV6(String str) {
+        InetAddress addr;
+        try {
+            addr = InetAddress.getByName(str);
+        } catch (UnknownHostException e) {
+            return null;
+        }
+
+        return getLocationV6(addr);
+    }
+
+    // for GeoIP City only
+    public Location getLocation(InetAddress addr) {
+        return getLocation(bytesToLong(addr.getAddress()));
+    }
+
+    // for GeoIP City only
+    public Location getLocation(String str) {
+        InetAddress addr;
+        try {
+            addr = InetAddress.getByName(str);
+        } catch (UnknownHostException e) {
+            return null;
+        }
+
+        return getLocation(addr);
+    }
+
+    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(InetAddress addr) {
+        return getRegion(bytesToLong(addr.getAddress()));
+    }
+
+    public synchronized Region getRegion(long ipnum) {
+        Region record = new Region();
+        int seek_region;
+        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 getLocationV6(InetAddress addr) {
+        int seek_country;
+
+        try {
+            seek_country = seekCountryV6(addr);
+            return readCityRecord(seek_country);
+        } catch (IOException e) {
+            throw new InvalidDatabaseException("Error while seting up segments", e);
+        }
+    }
+
+    public synchronized Location getLocation(long ipnum) {
+        int seek_country;
+
+        try {
+            seek_country = seekCountry(ipnum);
+            return readCityRecord(seek_country);
+        } catch (IOException e) {
+            throw new InvalidDatabaseException("Error while seting up segments", e);
+        }
+    }
+
+    private Location readCityRecord(int seekCountry) throws IOException {
+        if (seekCountry == databaseSegments[0]) {
+            return null;
+        }
+        ByteBuffer buffer = readRecordBuf(seekCountry, FULL_RECORD_LENGTH);
+
+        Location record = new Location();
+        int country = unsignedByteToInt(buffer.get());
+
+        // get country
+        record.countryCode = countryCode[country];
+        record.countryName = countryName[country];
+
+        record.region = readString(buffer);
+        record.city = readString(buffer);
+        record.postalCode  = readString(buffer);
+        record.latitude = readAngle(buffer);
+        record.longitude = readAngle(buffer);
+
+        if (databaseType == DatabaseInfo.CITY_EDITION_REV1) {
+            // get DMA code
+            if ("US".equals(record.countryCode)) {
+                int metroarea_combo = readMetroAreaCombo(buffer);
+                record.metro_code = record.dma_code = metroarea_combo / 1000;
+                record.area_code = metroarea_combo % 1000;
+            }
+        }
+        return record;
+    }
+
+    private ByteBuffer readRecordBuf(int seek, int maxLength) throws IOException {
+
+        int recordPointer = seek + (2 * recordLength - 1)
+                * databaseSegments[0];
+
+        ByteBuffer buffer;
+        if ((dboptions & GEOIP_MEMORY_CACHE) == 1) {
+            buffer = ByteBuffer.wrap(dbbuffer, recordPointer, Math
+                    .min(dbbuffer.length - recordPointer, maxLength));
+        } else {
+            byte[] recordBuf = new byte[maxLength];
+            // read from disk
+            file.seek(recordPointer);
+            file.read(recordBuf);
+            buffer = ByteBuffer.wrap(recordBuf);
+        }
+        return buffer;
+    }
+
+
+    private String readString(ByteBuffer buffer) throws CharacterCodingException {
+        int start = buffer.position();
+        int oldLimit = buffer.limit();
+
+        while (buffer.hasRemaining() && buffer.get() != 0) {}
+
+        int end = buffer.position() - 1;
+        String str = null;
+        if (end > start) {
+            buffer.position(start);
+            buffer.limit(end);
+            str = charsetDecoder.decode(buffer).toString();
+            buffer.limit(oldLimit);
+        }
+        buffer.position(end + 1);
+        return str;
+    }
+
+    private static float readAngle(ByteBuffer buffer) {
+        if (buffer.remaining() < 3) {
+            throw new InvalidDatabaseException("Unexpected end of data record when reading angle");
+        }
+        double num = 0;
+        for (int j = 0; j < 3; j++) {
+            num += unsignedByteToInt(buffer.get()) << (j * 8);
+        }
+        return (float) num / 10000 - 180;
+    }
+
+    private static int readMetroAreaCombo(ByteBuffer buffer) {
+        if (buffer.remaining() < 3) {
+            throw new InvalidDatabaseException("Unexpected end of data record when reading metro area");
+        }
+        int metroareaCombo = 0;
+        for (int j = 0; j < 3; j++) {
+            metroareaCombo += unsignedByteToInt(buffer.get()) << (j * 8);
+        }
+        return metroareaCombo;
+    }
+
+    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) {
+        try {
+            int seekOrg = seekCountry(ipnum);
+            return readOrgRecord(seekOrg);
+
+        } catch (IOException e) {
+            throw new InvalidDatabaseException("Error while reading org", e);
+        }
+    }
+
+    public String getOrgV6(String str) {
+        InetAddress addr;
+        try {
+            addr = InetAddress.getByName(str);
+        } catch (UnknownHostException e) {
+            return null;
+        }
+        return getOrgV6(addr);
+    }
+
+    // GeoIP Organization and ISP Edition methods
+    public synchronized String getOrgV6(InetAddress addr) {
+          try {
+            int seekOrg = seekCountryV6(addr);
+             return readOrgRecord(seekOrg);
+        } catch (IOException e) {
+            throw new InvalidDatabaseException("Error while reading org", e);
+        }
+    }
+
+    private String readOrgRecord(int seekOrg) throws IOException {
+        if (seekOrg == databaseSegments[0]) {
+            return null;
+        }
+        ByteBuffer buf = readRecordBuf(seekOrg, MAX_ORG_RECORD_LENGTH);
+        return readString(buf);
+    }
+
+    /**
+     * 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();
+
+        if (v6vec.length == 4) {
+            // sometimes java returns an ipv4 address for IPv6 input
+            // we have to work around that feature
+            // It happens for ::ffff:24.24.24.24
+            byte[] t = new byte[16];
+            System.arraycopy(v6vec, 0, t, 12, 4);
+            v6vec = t;
+        }
+
+        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--) {
+            readNode(buf, x, offset);
+
+            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];
+            }
+        }
+
+        throw new InvalidDatabaseException("Error seeking country while searching for "
+                + addr.getHostAddress());
+    }
+
+    /**
+     * 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--) {
+            readNode(buf, x, offset);
+
+            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];
+            }
+        }
+        throw new InvalidDatabaseException("Error seeking country while searching for "
+                + ipAddress);
+    }
+
+    private void readNode(byte[] buf, int[] x, int offset) {
+        if ((dboptions & GEOIP_MEMORY_CACHE) == 1) {
+            // read from memory
+            System.arraycopy(dbbuffer, (2 * recordLength * offset), buf, 0, 2 * recordLength);
+        } else if ((dboptions & GEOIP_INDEX_CACHE) != 0) {
+            // read from index cache
+            System.arraycopy(index_cache, (2 * recordLength * offset), buf, 0, 2 * recordLength);
+        } else {
+            // read from disk
+            try {
+                file.seek(2 * recordLength * offset);
+                file.read(buf);
+            }  catch (IOException e) {
+                throw new InvalidDatabaseException("Error seeking in database", e);
+            }
+        }
+        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));
+            }
+        }
+    }
+
+    /**
+     * 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;
+    }
+}
diff --git a/router/java/src/com/maxmind/geoip/Region.java b/router/java/src/com/maxmind/geoip/Region.java
new file mode 100644
index 0000000000000000000000000000000000000000..d8f12632c811d54c6983c2ed15d33f25ee8be2d4
--- /dev/null
+++ b/router/java/src/com/maxmind/geoip/Region.java
@@ -0,0 +1,7 @@
+package com.maxmind.geoip;
+
+public class Region {
+	public String countryCode;
+	public String countryName;
+	public String region;
+}
\ No newline at end of file
diff --git a/router/java/src/com/maxmind/geoip/package.html b/router/java/src/com/maxmind/geoip/package.html
new file mode 100644
index 0000000000000000000000000000000000000000..4f91804b9c18ec432cdb9931a19e0fb90f99f3cb
--- /dev/null
+++ b/router/java/src/com/maxmind/geoip/package.html
@@ -0,0 +1,15 @@
+<html>
+<body>
+<p>
+This is geoip-api-java release 1.3.1 2016-02-08
+retrieved from <a href="https://github.com/maxmind/geoip-api-java">github</a>.
+It is used only on Debian-based systems where the geoip-database package
+is installed, with the files in /usr/share/GeoIP/ .
+See net.i2p.router.transport.GeoIP.
+</p><p>
+Unmodified, except that
+regionName.java and timeZone.java are omitted.
+LGPL v2.1.
+</p>
+</body>
+</html>
diff --git a/router/java/src/net/i2p/router/transport/GeoIP.java b/router/java/src/net/i2p/router/transport/GeoIP.java
index 6a204016428903afc4a4a8089e7f856a101a0cdc..222923dc78cf716d0e418107b9846227bd3f37ad 100644
--- a/router/java/src/net/i2p/router/transport/GeoIP.java
+++ b/router/java/src/net/i2p/router/transport/GeoIP.java
@@ -16,6 +16,9 @@ import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicBoolean;
 
+import com.maxmind.geoip.InvalidDatabaseException;
+import com.maxmind.geoip.LookupService;
+
 import net.i2p.I2PAppContext;
 import net.i2p.data.DataHelper;
 import net.i2p.data.Hash;
@@ -24,6 +27,7 @@ import net.i2p.router.RouterContext;
 import net.i2p.util.Addresses;
 import net.i2p.util.ConcurrentHashSet;
 import net.i2p.util.Log;
+import net.i2p.util.SystemVersion;
 
 /**
  * Manage geoip lookup in a file with the Tor geoip format.
@@ -56,6 +60,20 @@ public class GeoIP {
     private final AtomicBoolean _lock;
     private int _lookupRunCount;
     
+    static final String PROP_GEOIP_ENABLED = "routerconsole.geoip.enable";
+    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 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();
+    /** maxmind API */
+    private static final String UNKNOWN_COUNTRY_CODE = "--";
+
     /**
      *  @param context RouterContext in production, I2PAppContext for testing only
      */
@@ -71,13 +89,6 @@ public class GeoIP {
         _lock = new AtomicBoolean();
         readCountryFile();
     }
-    
-    static final String PROP_GEOIP_ENABLED = "routerconsole.geoip.enable";
-    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 COUNTRY_FILE_DEFAULT = "countries.txt";
-    public static final String PROP_IP_COUNTRY = "i2np.lastCountry";
 
     /**
      *  @since 0.9.3
@@ -145,12 +156,39 @@ public class GeoIP {
                 _pendingSearch.clear();
                 if (search.length > 0) {
                     Arrays.sort(search);
-                    String[] countries = readGeoIPFile(search);
-                    for (int i = 0; i < countries.length; i++) {
-                        if (countries[i] != null)
-                            _IPToCountry.put(search[i], countries[i]);
-                        else
-                            _notFound.add(search[i]);
+                    File f = new File(_context.getProperty(PROP_DEBIAN_GEOIP, DEBIAN_GEOIP_FILE));
+                    if (ENABLE_DEBIAN && f.exists()) {
+                        // Maxmind 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();
+                                // 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);
+                                } else {
+                                    _notFound.add(search[i]);
+                                }
+                            }
+                        } catch (IOException ioe) {
+                            _log.error("GeoIP failure", ioe);
+                        } catch (InvalidDatabaseException ide) {
+                            _log.error("GeoIP failure", ide);
+                        } finally {
+                            if (ls != null) ls.close();
+                        }
+                    } else {
+                        // Tor-style database
+                        String[] countries = readGeoIPFile(search);
+                        for (int i = 0; i < countries.length; i++) {
+                            if (countries[i] != null)
+                                _IPToCountry.put(search[i], countries[i]);
+                            else
+                                _notFound.add(search[i]);
+                        }
                     }
                 }
                 // IPv6
@@ -158,12 +196,40 @@ public class GeoIP {
                 _pendingIPv6Search.clear();
                 if (search.length > 0) {
                     Arrays.sort(search);
-                    String[] countries = GeoIPv6.readGeoIPFile(_context, search, _codeCache);
-                    for (int i = 0; i < countries.length; i++) {
-                        if (countries[i] != null)
-                            _IPToCountry.put(search[i], countries[i]);
-                        else
-                            _notFound.add(search[i]);
+                    File f = new File(_context.getProperty(PROP_DEBIAN_GEOIPV6, DEBIAN_GEOIPV6_FILE));
+                    if (ENABLE_DEBIAN && f.exists()) {
+                        // Maxmind 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();
+                                String ipv6 = toV6(ip);
+                                // returns upper case or "--"
+                                String uc = ls.getCountryV6(ipv6).getCode();
+                                if (!uc.equals(UNKNOWN_COUNTRY_CODE)) {
+                                    String cached = _codeCache.get(uc.toLowerCase(Locale.US));
+                                    _IPToCountry.put(search[i], cached);
+                                } else {
+                                    _notFound.add(search[i]);
+                                }
+                            }
+                        } catch (IOException ioe) {
+                            _log.error("GeoIP failure", ioe);
+                        } catch (InvalidDatabaseException ide) {
+                            _log.error("GeoIP failure", ide);
+                        } finally {
+                            if (ls != null) ls.close();
+                        }
+                    } else {
+                        // Tor-style database
+                        String[] countries = GeoIPv6.readGeoIPFile(_context, search, _codeCache);
+                        for (int i = 0; i < countries.length; i++) {
+                            if (countries[i] != null)
+                                _IPToCountry.put(search[i], countries[i]);
+                            else
+                                _notFound.add(search[i]);
+                        }
                     }
                 }
             } finally {
@@ -404,6 +470,20 @@ public class GeoIP {
         }
     }
 
+    /**
+     * @return e.g. aabb:ccdd:eeff:1122::
+     * @since 0.9.26 for maxmind
+     */
+    private static String toV6(long ip) {
+        StringBuilder buf = new StringBuilder(21);
+        for (int i = 0; i < 4; i++) {
+            buf.append(Long.toHexString((ip >> ((3-i)*16)) & 0xffff));
+            buf.append(':');
+        }
+        buf.append(':');
+        return buf.toString();
+    }
+
     /**
      * Get the country for a country code
      * @param code two-letter lower case code