diff --git a/LICENSE.txt b/LICENSE.txt index 766691a55e7fe8c49c3ade68171d02cd66f8b5dd..d177d7983ccac15d23a3d94a0d4a919a64c2667f 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -283,7 +283,7 @@ Applications: Bundles systray4j-2.4.1: See licenses/LICENSE-LGPLv2.1.txt - Tomcat 6.0.47: + Tomcat 6.0.48: Copyright 1999-2016 The Apache Software Foundation See licenses/LICENSE-Apache2.0.txt See licenses/NOTICE-Tomcat.txt diff --git a/apps/addressbook/build.xml b/apps/addressbook/build.xml index e4e913cb20e6e43b58d744d24ad619d9cfaa91bc..eed69a3fa427bcef4fe73bd1d78ec65253a6b315 100644 --- a/apps/addressbook/build.xml +++ b/apps/addressbook/build.xml @@ -86,6 +86,8 @@ <attribute name="Build-Date" value="${build.timestamp}" /> <attribute name="Base-Revision" value="${workspace.version}" /> <attribute name="Workspace-Changes" value="${workspace.changes.tr}" /> + <attribute name="X-Compile-Source-JDK" value="${javac.version}" /> + <attribute name="X-Compile-Target-JDK" value="${javac.version}" /> </manifest> </jar> </target> @@ -106,6 +108,8 @@ <attribute name="Build-Date" value="${build.timestamp}" /> <attribute name="Base-Revision" value="${workspace.version}" /> <attribute name="Workspace-Changes" value="${workspace.changes.tr}" /> + <attribute name="X-Compile-Source-JDK" value="${javac.version}" /> + <attribute name="X-Compile-Target-JDK" value="${javac.version}" /> </manifest> </war> <delete dir="${dist}/tmp"/> diff --git a/apps/desktopgui/build.xml b/apps/desktopgui/build.xml index b31cc86dfdbd29405a65c2a6afb24bcf9005224c..a42633518952ee435744c88e7fd31b406abc696e 100644 --- a/apps/desktopgui/build.xml +++ b/apps/desktopgui/build.xml @@ -83,6 +83,8 @@ <attribute name="Build-Date" value="${build.timestamp}" /> <attribute name="Base-Revision" value="${workspace.version}" /> <attribute name="Workspace-Changes" value="${workspace.changes.tr}" /> + <attribute name="X-Compile-Source-JDK" value="${javac.version}" /> + <attribute name="X-Compile-Target-JDK" value="${javac.version}" /> </manifest> </jar> </target> diff --git a/apps/i2psnark/java/build.xml b/apps/i2psnark/java/build.xml index ee3ad0f036712bdb12cd40910d246bf45cb01e22..3ecde039383a1d13a66fa19cbbd0c083ee5fbb9d 100644 --- a/apps/i2psnark/java/build.xml +++ b/apps/i2psnark/java/build.xml @@ -84,6 +84,8 @@ <attribute name="Build-Date" value="${build.timestamp}" /> <attribute name="Base-Revision" value="${workspace.version}" /> <attribute name="Workspace-Changes" value="${workspace.changes.tr}" /> + <attribute name="X-Compile-Source-JDK" value="${javac.version}" /> + <attribute name="X-Compile-Target-JDK" value="${javac.version}" /> </manifest> </jar> </target> @@ -130,6 +132,8 @@ <attribute name="Build-Date" value="${build.timestamp}" /> <attribute name="Base-Revision" value="${workspace.version}" /> <attribute name="Workspace-Changes" value="${workspace.changes.tr}" /> + <attribute name="X-Compile-Source-JDK" value="${javac.version}" /> + <attribute name="X-Compile-Target-JDK" value="${javac.version}" /> </manifest> </war> </target> diff --git a/apps/i2psnark/java/src/org/klomp/snark/dht/KRPC.java b/apps/i2psnark/java/src/org/klomp/snark/dht/KRPC.java index 29a0f33fc4ac851ef0c00e9166499ff53a5ac2f2..f92c3da9975d2fd974d53bcb3f07bcb314e913aa 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/dht/KRPC.java +++ b/apps/i2psnark/java/src/org/klomp/snark/dht/KRPC.java @@ -123,6 +123,7 @@ public class KRPC implements I2PSessionMuxedListener, DHT { private final AtomicLong _rxBytes = new AtomicLong(); private final AtomicLong _txBytes = new AtomicLong(); private long _started; + private long _nodesLastSaved; /** all-zero NID used for pings */ public static final NID FAKE_NID = new NID(new byte[NID.HASH_LENGTH]); @@ -156,6 +157,7 @@ public class KRPC implements I2PSessionMuxedListener, DHT { private static final long CLEAN_TIME = 63*1000; private static final long EXPLORE_TIME = 877*1000; private static final long BLACKLIST_CLEAN_TIME = 17*60*1000; + private static final long NODES_SAVE_TIME = 3*60*60*1000; public static final String DHT_FILE_SUFFIX = ".dht.dat"; private static final int SEND_CRYPTO_TAGS = 8; @@ -635,6 +637,7 @@ public class KRPC implements I2PSessionMuxedListener, DHT { _txBytes.set(0); _rxBytes.set(0); _started = _context.clock().now(); + _nodesLastSaved = _started; } /** @@ -1675,6 +1678,10 @@ public class KRPC implements I2PSessionMuxedListener, DHT { if (nid.lastSeen() < expire) iter.remove(); } + if (now - _nodesLastSaved > NODES_SAVE_TIME) { + PersistDHT.saveDHT(_knownNodes, false, _dhtFile); + _nodesLastSaved = now; + } // TODO sent queries? if (_log.shouldLog(Log.DEBUG)) _log.debug("KRPC cleaner done, now with " + diff --git a/apps/i2ptunnel/java/build.xml b/apps/i2ptunnel/java/build.xml index 6c4698a27a61f81d5b1396620eb89c816271954a..93f5cc3391f6130fa152bc8bc77e837935d91328 100644 --- a/apps/i2ptunnel/java/build.xml +++ b/apps/i2ptunnel/java/build.xml @@ -72,6 +72,8 @@ <attribute name="Build-Date" value="${build.timestamp}" /> <attribute name="Base-Revision" value="${workspace.version}" /> <attribute name="Workspace-Changes" value="${workspace.changes.j.tr}" /> + <attribute name="X-Compile-Source-JDK" value="${javac.version}" /> + <attribute name="X-Compile-Target-JDK" value="${javac.version}" /> </manifest> </jar> <jar destfile="./build/temp-beans.jar" basedir="./build/obj" includes="**/ui/*.class **/EditBean.class **/IndexBean.class" /> @@ -103,6 +105,8 @@ <attribute name="Build-Date" value="${build.timestamp}" /> <attribute name="Base-Revision" value="${workspace.version}" /> <attribute name="Workspace-Changes" value="${workspace.changes.j.tr}" /> + <attribute name="X-Compile-Source-JDK" value="${javac.version}" /> + <attribute name="X-Compile-Target-JDK" value="${javac.version}" /> </manifest> </jar> </target> @@ -241,6 +245,8 @@ <attribute name="Build-Date" value="${build.timestamp}" /> <attribute name="Base-Revision" value="${workspace.version}" /> <attribute name="Workspace-Changes" value="${workspace.changes.w.tr}" /> + <attribute name="X-Compile-Source-JDK" value="${javac.version}" /> + <attribute name="X-Compile-Target-JDK" value="${javac.version}" /> </manifest> </war> </target> diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClientBase.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClientBase.java index 2d6e053b03054c67712bd0ac1394399e66d09dc3..4908042dd660030e4ef6adf6597e0067eb0e4ecc 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClientBase.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClientBase.java @@ -304,7 +304,7 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem return AuthResult.AUTH_GOOD; } } - _log.logAlways(Log.WARN, "PROXY AUTH FAILURE: user " + user); + _log.logAlways(Log.WARN, "HTTP proxy authentication failed, user: " + user); } catch (UnsupportedEncodingException uee) { _log.error(getPrefix(requestId) + "No UTF-8 support? B64: " + authorization, uee); } catch (ArrayIndexOutOfBoundsException aioobe) { @@ -363,7 +363,7 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem String ha1 = getTunnel().getClientOptions().getProperty(PROP_PROXY_DIGEST_PREFIX + user + PROP_PROXY_DIGEST_SUFFIX); if (ha1 == null) { - _log.logAlways(Log.WARN, "PROXY AUTH FAILURE: user " + user); + _log.logAlways(Log.WARN, "HTTP proxy authentication failed, user: " + user); return AuthResult.AUTH_BAD; } // get H(A2) @@ -373,7 +373,7 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem String kd = ha1 + ':' + nonce + ':' + nc + ':' + cnonce + ':' + qop + ':' + ha2; String hkd = PasswordManager.md5Hex(kd); if (!response.equals(hkd)) { - _log.logAlways(Log.WARN, "PROXY AUTH FAILURE: user " + user); + _log.logAlways(Log.WARN, "HTTP proxy authentication failed, user: " + user); if (_log.shouldLog(Log.INFO)) _log.info("Bad digest auth: " + DataHelper.toString(args)); return AuthResult.AUTH_BAD; diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKS5Server.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKS5Server.java index 823497f281c1460ccc5c08bc2cfc6c59749a3c1c..f3d5246fdcd2a5280c9a9664942fb319ee39b89f 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKS5Server.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKS5Server.java @@ -131,26 +131,32 @@ class SOCKS5Server extends SOCKSServer { */ private void verifyPassword(DataInputStream in, DataOutputStream out) throws IOException, SOCKSException { int c = in.readUnsignedByte(); - if (c != AUTH_VERSION) + if (c != AUTH_VERSION) { + _log.logAlways(Log.WARN, "SOCKS proxy authentication failed"); throw new SOCKSException("Unsupported authentication version"); + } c = in.readUnsignedByte(); - if (c <= 0) + if (c <= 0) { + _log.logAlways(Log.WARN, "SOCKS proxy authentication failed"); throw new SOCKSException("Bad authentication"); + } byte[] user = new byte[c]; + String u = new String(user, "UTF-8"); in.readFully(user); c = in.readUnsignedByte(); - if (c <= 0) + if (c <= 0) { + _log.logAlways(Log.WARN, "SOCKS proxy authentication failed, user: " + u); throw new SOCKSException("Bad authentication"); + } byte[] pw = new byte[c]; in.readFully(pw); // Hopefully these are in UTF-8, since that's what our config file is in // these throw UnsupportedEncodingException which is an IOE - String u = new String(user, "UTF-8"); String p = new String(pw, "UTF-8"); String configUser = props.getProperty(I2PTunnelHTTPClientBase.PROP_USER); String configPW = props.getProperty(I2PTunnelHTTPClientBase.PROP_PW); if ((!u.equals(configUser)) || (!p.equals(configPW))) { - _log.error("SOCKS authorization failure"); + _log.logAlways(Log.WARN, "SOCKS proxy authentication failed, user: " + u); sendAuthReply(AUTH_FAILURE, out); throw new SOCKSException("SOCKS authorization failure"); } @@ -591,9 +597,13 @@ class SOCKS5Server extends SOCKSServer { // todo pass the response through? } catch (IOException e) { try { destSock.close(); } catch (IOException ioe) {} + if (in != null) try { in.close(); } catch (IOException ioe) {} + if (out != null) try { out.close(); } catch (IOException ioe) {} throw e; } catch (SOCKSException e) { try { destSock.close(); } catch (IOException ioe) {} + if (in != null) try { in.close(); } catch (IOException ioe) {} + if (out != null) try { out.close(); } catch (IOException ioe) {} throw e; } // that's it, caller will send confirmation to our client @@ -601,9 +611,10 @@ class SOCKS5Server extends SOCKSServer { } // This isn't really the right place for this, we can't stop the tunnel once it starts. - static SOCKSUDPTunnel _tunnel; - static final Object _startLock = new Object(); - static byte[] dummyIP = new byte[4]; + private static SOCKSUDPTunnel _tunnel; + private static final Object _startLock = new Object(); + private static final byte[] dummyIP = new byte[4]; + /** * We got a UDP associate command. * Loop here looking for more, never return normally, diff --git a/apps/imagegen/identicon/build.xml b/apps/imagegen/identicon/build.xml index e0e85bd53287ac6658dd4f8998d4622a9907f031..831b3ff7f33236f33a7c2e826d8efb53f35a819b 100644 --- a/apps/imagegen/identicon/build.xml +++ b/apps/imagegen/identicon/build.xml @@ -71,6 +71,8 @@ <attribute name="Build-Date" value="${build.timestamp}" /> <attribute name="Base-Revision" value="${workspace.version}" /> <attribute name="Workspace-Changes" value="${workspace.changes.tr}" /> + <attribute name="X-Compile-Source-JDK" value="${javac.version}" /> + <attribute name="X-Compile-Target-JDK" value="${javac.version}" /> </manifest> </jar> </target> diff --git a/apps/imagegen/imagegen/build.xml b/apps/imagegen/imagegen/build.xml index 7cc657c05177f0613d2363cd530ae247b18d1011..bc0d96f24fbb3247c74c39c3025904c646d034c3 100644 --- a/apps/imagegen/imagegen/build.xml +++ b/apps/imagegen/imagegen/build.xml @@ -75,6 +75,8 @@ <attribute name="Build-Date" value="${build.timestamp}" /> <attribute name="Base-Revision" value="${workspace.version}" /> <attribute name="Workspace-Changes" value="${workspace.changes.tr}" /> + <attribute name="X-Compile-Source-JDK" value="${javac.version}" /> + <attribute name="X-Compile-Target-JDK" value="${javac.version}" /> </manifest> </war> </target> diff --git a/apps/imagegen/zxing/build.xml b/apps/imagegen/zxing/build.xml index c878015b17eafa31bacfd5441dc7aac3f16b4281..c615d86839e04f231bb76cdef0cc2dc6c65c6a80 100644 --- a/apps/imagegen/zxing/build.xml +++ b/apps/imagegen/zxing/build.xml @@ -17,6 +17,7 @@ </target> <!-- only used if not set by a higher build.xml --> + <property name="javac.version" value="1.7" /> <property name="javac.compilerargs7" value="" /> <target name="compile" depends="depend"> @@ -39,7 +40,7 @@ <mkdir dir="./buildTest/obj" /> <javac srcdir="./test/junit" - debug="true" deprecation="on" source="1.7" target="1.7" + debug="true" deprecation="on" source="${javac.version}" target="${javac.version}" includeAntRuntime="false" destdir="./buildTest/obj" classpath="./build/zxing.jar" > @@ -75,6 +76,8 @@ <attribute name="Build-Date" value="${build.timestamp}" /> <attribute name="Base-Revision" value="${workspace.version}" /> <attribute name="Workspace-Changes" value="${workspace.changes.tr}" /> + <attribute name="X-Compile-Source-JDK" value="${javac.version}" /> + <attribute name="X-Compile-Target-JDK" value="${javac.version}" /> </manifest> </jar> </target> diff --git a/apps/jetty/apache-tomcat-deployer/README-i2p.txt b/apps/jetty/apache-tomcat-deployer/README-i2p.txt index c354fb71af810a69c72b2b26a837384326d59123..6b8c0edf3159935d2009190e588c58b9db99d51c 100644 --- a/apps/jetty/apache-tomcat-deployer/README-i2p.txt +++ b/apps/jetty/apache-tomcat-deployer/README-i2p.txt @@ -2,7 +2,7 @@ This is Apache Tomcat 6.x, supporting Servlet 2.5 and JSP 2.1. The Glassfish JSP 2.1 bundled in Jetty 6 is way too old. Retrieved from the file - apache-tomcat-6.0.44-deployer.tar.gz + apache-tomcat-6.0.48-deployer.tar.gz minus the following files and directores: diff --git a/apps/jetty/apache-tomcat-deployer/lib/el-api.jar b/apps/jetty/apache-tomcat-deployer/lib/el-api.jar index 4b5aa36d302381d8b05d04d91ed45141030ab908..2598a4a8fa66bcaec88ccede7710159f6d9fead8 100644 Binary files a/apps/jetty/apache-tomcat-deployer/lib/el-api.jar and b/apps/jetty/apache-tomcat-deployer/lib/el-api.jar differ diff --git a/apps/jetty/apache-tomcat-deployer/lib/jasper-el.jar b/apps/jetty/apache-tomcat-deployer/lib/jasper-el.jar index 51ec6f3080e949072f84ae6fbeb3383d846ca02a..b7205e347de032147194f587b4a5adaaae554fbe 100644 Binary files a/apps/jetty/apache-tomcat-deployer/lib/jasper-el.jar and b/apps/jetty/apache-tomcat-deployer/lib/jasper-el.jar differ diff --git a/apps/jetty/apache-tomcat-deployer/lib/jasper.jar b/apps/jetty/apache-tomcat-deployer/lib/jasper.jar index 7242ce7d1bd874900ca2ed17ff3ce825acb69a46..ca2d7269d81e81c090fbb58fd48c239a017b7466 100644 Binary files a/apps/jetty/apache-tomcat-deployer/lib/jasper.jar and b/apps/jetty/apache-tomcat-deployer/lib/jasper.jar differ diff --git a/apps/jetty/apache-tomcat-deployer/lib/tomcat-juli.jar b/apps/jetty/apache-tomcat-deployer/lib/tomcat-juli.jar index 37d316ecacc7d4746890c6a17f8c933de73adf7c..c5e0f8f7791109d3a488042772351e1a47f16c21 100644 Binary files a/apps/jetty/apache-tomcat-deployer/lib/tomcat-juli.jar and b/apps/jetty/apache-tomcat-deployer/lib/tomcat-juli.jar differ diff --git a/apps/jetty/apache-tomcat/README-i2p.txt b/apps/jetty/apache-tomcat/README-i2p.txt index f62c55e862898c2b60e0b83f2ef10ba23b9d8d8a..015ff4736a7757a2868b3ef29c58a02e4a4815e9 100644 --- a/apps/jetty/apache-tomcat/README-i2p.txt +++ b/apps/jetty/apache-tomcat/README-i2p.txt @@ -1,7 +1,7 @@ This is Apache Tomcat 6.x, supporting Servlet 2.5 and JSP 2.1. Retrieved from the file - apache-tomcat-6.0.44.tar.gz + apache-tomcat-6.0.48.tar.gz containing only a small subset of lib/tomcat-coyote.jar. diff --git a/apps/jetty/apache-tomcat/lib/tomcat-coyote-util.jar b/apps/jetty/apache-tomcat/lib/tomcat-coyote-util.jar index 9403f2ece5024641e010d97365c52eeb0b6ad1cb..a45499414ec8c2d28372de113225872cb40113f9 100644 Binary files a/apps/jetty/apache-tomcat/lib/tomcat-coyote-util.jar and b/apps/jetty/apache-tomcat/lib/tomcat-coyote-util.jar differ diff --git a/apps/jetty/build.xml b/apps/jetty/build.xml index 7e19fa1dbeafa1d501dadabc62bea973df48c83a..f0b2c7cce669d63b66a528e62d1bd680f7d5fcdc 100644 --- a/apps/jetty/build.xml +++ b/apps/jetty/build.xml @@ -22,7 +22,7 @@ <property name="javac.compilerargs" value="" /> <property name="javac.version" value="1.7" /> <property name="tomcat.lib" value="apache-tomcat-deployer/lib" /> - <property name="tomcat.ver" value="6.0.47" /> + <property name="tomcat.ver" value="6.0.48" /> <property name="tomcat2.lib" value="apache-tomcat-${tomcat.ver}/lib" /> <property name="tomcat2.lib.small" value="apache-tomcat/lib" /> @@ -340,6 +340,8 @@ <!-- needed by JettyStart for pre-0.7.5 wrapper.config --> <attribute name="Class-Path" value="jetty-deploy.jar jetty-xml.jar" /> <attribute name="Workspace-Changes" value="${workspace.changes.tr}" /> + <attribute name="X-Compile-Source-JDK" value="${javac.version}" /> + <attribute name="X-Compile-Target-JDK" value="${javac.version}" /> </manifest> </jar> </target> diff --git a/apps/jrobin/java/build.xml b/apps/jrobin/java/build.xml index 3d481f99eb392261508212634e41e5202e175be6..c569ddfecb31bda7289777ce8e7bdaca2d3a4127 100644 --- a/apps/jrobin/java/build.xml +++ b/apps/jrobin/java/build.xml @@ -13,6 +13,9 @@ cache="../../../build" srcdir="./src" destdir="./build/obj" > + <classpath> + <pathelement location="../../../core/java/build/i2p.jar" /> + </classpath> </depend> </target> @@ -32,6 +35,9 @@ includeAntRuntime="false" includes="**/*.java" > <compilerarg line="${javac.compilerargs}" /> + <classpath> + <pathelement location="../../../core/java/build/i2p.jar" /> + </classpath> </javac> </target> @@ -54,6 +60,7 @@ <property name="workspace.changes.tr" value="" /> <jar destfile="./build/jrobin.jar" basedir="./build/obj" includes="**/*.class"> <manifest> + <attribute name="Class-Path" value="i2p.jar" /> <attribute name="Implementation-Version" value="1.6.0-1" /> <attribute name="Built-By" value="${build.built-by}" /> <attribute name="Build-Date" value="${build.timestamp}" /> diff --git a/apps/jrobin/java/src/engine/misc/DeallocationHelper.java b/apps/jrobin/java/src/engine/misc/DeallocationHelper.java index 679b658e5266b22b2a7ce55ff8438cc27374e895..3bc2205e03d95a37556c42862e984f2483661113 100644 --- a/apps/jrobin/java/src/engine/misc/DeallocationHelper.java +++ b/apps/jrobin/java/src/engine/misc/DeallocationHelper.java @@ -31,8 +31,10 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; + +import net.i2p.I2PAppContext; +import net.i2p.util.Log; + /** * Helper to deallocate memory on the native heap allocated during the creation @@ -56,12 +58,16 @@ import java.util.logging.Logger; */ public class DeallocationHelper { + private final Log logger = I2PAppContext.getGlobalContext().logManager().getLog(DeallocationHelper.class); + /** * tool responsible for releasing the native memory of a deallocatable byte * buffer */ public static abstract class Deallocator { + protected final Log logger = I2PAppContext.getGlobalContext().logManager().getLog(DeallocationHelper.class); + public Deallocator() { super(); } @@ -101,7 +107,7 @@ public class DeallocationHelper { cleanerCleanMethod = cleanerClass.getDeclaredMethod("clean"); } } catch (ClassNotFoundException | NoSuchMethodException e) { - logger.log(Level.WARNING, + logger.warn( "The initialization of the deallocator for Oracle Java, Sun Java and OpenJDK has failed", e); } } @@ -122,7 +128,7 @@ public class DeallocationHelper { success = true; } } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { - logger.log(Level.WARNING, "The deallocation of a direct NIO buffer has failed", e); + logger.warn("The deallocation of a direct NIO buffer has failed", e); } finally { directByteBufferCleanerMethod.setAccessible(directByteBufferCleanerMethodWasAccessible); cleanerCleanMethod.setAccessible(cleanerCleanMethodWasAccessible); @@ -142,7 +148,7 @@ public class DeallocationHelper { final Class<?> directByteBufferClass = Class.forName("java.nio.DirectByteBuffer"); directByteBufferFreeMethod = directByteBufferClass.getDeclaredMethod("free"); } catch (ClassNotFoundException | NoSuchMethodException e) { - logger.log(Level.WARNING, "The initialization of the deallocator for Android has failed", e); + logger.warn("The initialization of the deallocator for Android has failed", e); } } @@ -156,7 +162,7 @@ public class DeallocationHelper { directByteBufferFreeMethod.invoke(directByteBuffer); success = true; } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { - logger.log(Level.WARNING, "The deallocation of a direct NIO buffer has failed", e); + logger.warn("The deallocation of a direct NIO buffer has failed", e); } finally { directByteBufferFreeMethod.setAccessible(directByteBufferFreeMethodWasAccessible); } @@ -180,7 +186,7 @@ public class DeallocationHelper { gnuClasspathPointerClass); bufferAddressField = Buffer.class.getDeclaredField("address"); } catch (ClassNotFoundException | NoSuchMethodException | NoSuchFieldException e) { - logger.log(Level.WARNING, "The initialization of the deallocator for GNU Classpath has failed", e); + logger.warn("The initialization of the deallocator for GNU Classpath has failed", e); } } @@ -199,7 +205,7 @@ public class DeallocationHelper { success = true; } } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { - logger.log(Level.WARNING, "The deallocation of a direct NIO buffer has failed", e); + logger.warn("The deallocation of a direct NIO buffer has failed", e); } finally { bufferAddressField.setAccessible(bufferAddressFieldWasAccessible); vmDirectByteBufferFreeMethod.setAccessible(vmDirectByteBufferFreeMethodWasAccessible); @@ -219,7 +225,7 @@ public class DeallocationHelper { final Class<?> directByteBufferClass = Class.forName("java.nio.DirectByteBuffer"); directByteBufferFreeMethod = directByteBufferClass.getDeclaredMethod("free"); } catch (ClassNotFoundException | NoSuchMethodException e) { - logger.log(Level.WARNING, "The initialization of the deallocator for Apache Harmony has failed", e); + logger.warn("The initialization of the deallocator for Apache Harmony has failed", e); } } @@ -233,7 +239,7 @@ public class DeallocationHelper { directByteBufferFreeMethod.invoke(directByteBuffer); success = true; } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { - logger.log(Level.WARNING, "The deallocation of a direct NIO buffer has failed", e); + logger.warn("The deallocation of a direct NIO buffer has failed", e); } finally { directByteBufferFreeMethod.setAccessible(directByteBufferFreeMethodWasAccessible); } @@ -242,8 +248,6 @@ public class DeallocationHelper { } } - private static final Logger logger = Logger.getLogger(DeallocationHelper.class.getName()); - private Map<Class<?>, Field> attachmentOrByteBufferFieldMap; private Set<Class<?>> deallocatableBufferClassSet; @@ -431,7 +435,7 @@ public class DeallocationHelper { } superClassesMsg = builder.toString(); } - logger.warning("The field " + fieldname + " hasn't been found in the class " + classname + logger.warn("The field " + fieldname + " hasn't been found in the class " + classname + superClassesMsg); } else {// the field has been found, stores it into the map attachmentOrByteBufferFieldMap.put(bufferClass, bufferField); @@ -449,7 +453,7 @@ public class DeallocationHelper { final String msg = "The class " + classname + " hasn't been found while initializing the deallocator. Java vendor: " + javaVendor + " Java version: " + javaVersion; - logger.log(Level.WARNING, msg, cnfe); + logger.warn(msg, cnfe); } } // if a known implementation has drastically changed or if the current @@ -567,7 +571,7 @@ public class DeallocationHelper { break; } } catch (IllegalAccessException iae) { - logger.log(Level.WARNING, "Cannot access the field " + field.getName() + logger.warn("Cannot access the field " + field.getName() + " of the class " + bufferIntermediaryClass.getName(), iae); } finally { field.setAccessible(fieldWasAccessible); @@ -594,7 +598,7 @@ public class DeallocationHelper { final String msg = "The class " + directByteBufferClassName + " hasn't been found while initializing the deallocator. Java vendor: " + javaVendor + " Java version: " + javaVersion; - logger.log(Level.WARNING, msg, cnfe); + logger.warn(msg, cnfe); } if (directByteBufferClass != null) deallocatableBufferClassSet.add(directByteBufferClass); @@ -607,7 +611,7 @@ public class DeallocationHelper { final String msg = "The class " + readOnlyDirectByteBufferClassName + " hasn't been found while initializing the deallocator. Java vendor: " + javaVendor + " Java version: " + javaVersion; - logger.log(Level.WARNING, msg, cnfe); + logger.warn(msg, cnfe); } if (readOnlyDirectByteBufferClass != null) deallocatableBufferClassSet.add(readOnlyDirectByteBufferClass); @@ -619,7 +623,7 @@ public class DeallocationHelper { final String msg = "The class " + readWriteDirectByteBufferClassName + " hasn't been found while initializing the deallocator. Java vendor: " + javaVendor + " Java version: " + javaVersion; - logger.log(Level.WARNING, msg, cnfe); + logger.warn(msg, cnfe); } if (readWriteDirectByteBufferClass != null) deallocatableBufferClassSet.add(readWriteDirectByteBufferClass); @@ -632,7 +636,7 @@ public class DeallocationHelper { final String msg = "The class " + readOnlyDirectByteBufferClassName + " hasn't been found while initializing the deallocator. Java vendor: " + javaVendor + " Java version: " + javaVersion; - logger.log(Level.WARNING, msg, cnfe); + logger.warn(msg, cnfe); } if (readOnlyDirectByteBufferClass != null) deallocatableBufferClassSet.add(readOnlyDirectByteBufferClass); @@ -644,7 +648,7 @@ public class DeallocationHelper { final String msg = "The class " + readWriteDirectByteBufferClassName + " hasn't been found while initializing the deallocator. Java vendor: " + javaVendor + " Java version: " + javaVersion; - logger.log(Level.WARNING, msg, cnfe); + logger.warn(msg, cnfe); } if (readWriteDirectByteBufferClass != null) deallocatableBufferClassSet.add(readWriteDirectByteBufferClass); @@ -730,7 +734,7 @@ public class DeallocationHelper { // deallocatable buffer deallocatableDirectByteBuffer = null; final String bufferClassName = bufferClass.getName(); - logger.warning("No deallocatable buffer has been found for an instance of the class " + logger.warn("No deallocatable buffer has been found for an instance of the class " + bufferClassName + " whereas it is a direct NIO buffer"); } } else {// the passed buffer contains another buffer, looks for a diff --git a/apps/jrobin/java/src/org/jrobin/core/jrrd/RRDFile.java b/apps/jrobin/java/src/org/jrobin/core/jrrd/RRDFile.java index 179cc473e1729640f8f8c81c7f095158b1b2ef1f..0dcd7808d52ef4341bf4514fe8d898dc97697073 100644 --- a/apps/jrobin/java/src/org/jrobin/core/jrrd/RRDFile.java +++ b/apps/jrobin/java/src/org/jrobin/core/jrrd/RRDFile.java @@ -188,7 +188,7 @@ public class RRDFile implements Constants { if(this.debug) { System.out.println(value); } - return (int)value; + return value; } String readString(int maxLength) throws IOException, RrdException { diff --git a/apps/ministreaming/java/build.xml b/apps/ministreaming/java/build.xml index 8232492b1f7ceaa2af6e7fbb430965d9f0ed4073..cbef281b9375b9ef35420fe91fd1ec03b231779b 100644 --- a/apps/ministreaming/java/build.xml +++ b/apps/ministreaming/java/build.xml @@ -86,6 +86,8 @@ <attribute name="Build-Date" value="${build.timestamp}" /> <attribute name="Base-Revision" value="${workspace.version}" /> <attribute name="Workspace-Changes" value="${workspace.changes.tr}" /> + <attribute name="X-Compile-Source-JDK" value="${javac.version}" /> + <attribute name="X-Compile-Target-JDK" value="${javac.version}" /> </manifest> </jar> </target> diff --git a/apps/routerconsole/java/build.xml b/apps/routerconsole/java/build.xml index 76162ae04cb781b9aae68ae7570cb2c45009ba13..522ee06a76f67e8f09eaefda393af1f4c5489b75 100644 --- a/apps/routerconsole/java/build.xml +++ b/apps/routerconsole/java/build.xml @@ -130,6 +130,8 @@ <attribute name="Build-Date" value="${build.timestamp}" /> <attribute name="Base-Revision" value="${workspace.version}" /> <attribute name="Workspace-Changes" value="${workspace.changes.j.tr}" /> + <attribute name="X-Compile-Source-JDK" value="${javac.version}" /> + <attribute name="X-Compile-Target-JDK" value="${javac.version}" /> </manifest> </jar> </target> @@ -302,6 +304,8 @@ <attribute name="Build-Date" value="${build.timestamp}" /> <attribute name="Base-Revision" value="${workspace.version}" /> <attribute name="Workspace-Changes" value="${workspace.changes.w.tr}" /> + <attribute name="X-Compile-Source-JDK" value="${javac.version}" /> + <attribute name="X-Compile-Target-JDK" value="${javac.version}" /> </manifest> </war> </target> diff --git a/apps/routerconsole/java/src/net/i2p/router/news/NewsManager.java b/apps/routerconsole/java/src/net/i2p/router/news/NewsManager.java index e85e232085682a3dbfa3008141f7e49f0f4d8eed..2b5af405d1bbedb107666fc43e9f5a1ed4bf6b63 100644 --- a/apps/routerconsole/java/src/net/i2p/router/news/NewsManager.java +++ b/apps/routerconsole/java/src/net/i2p/router/news/NewsManager.java @@ -172,6 +172,23 @@ public class NewsManager implements ClientApp { return parseNews(newsContent, false); } + /** + * The initial (welcome to i2p) news + * + * @return entry with first-installed date stamp, or null + * @since 0.9.28 + */ + public NewsEntry getInitialNews() { + List<NewsEntry> list = parseInitialNews(); + if (list.isEmpty()) + return null; + NewsEntry rv = list.get(0); + long installed = _context.getProperty("router.firstInstalled", 0L); + if (installed > 0) + rv.updated = installed; + return rv; + } + private List<NewsEntry> parseInitialNews() { NewsEntry entry = new NewsEntry(); File file = new File(_context.getBaseDir(), "docs/initialNews/initialNews.xml"); diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHandler.java index 7e4c7c5f74be947ad2969dc75fe4e219719a2302..8a53fde1c2882c77ea858dc144c2515c51f93a90 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHandler.java @@ -52,6 +52,7 @@ public class ConfigNetHandler extends FormHandler { private boolean _udpDisabled; private String _ipv6Mode; private boolean _ipv4Firewalled; + private boolean _ipv6Firewalled; private final Map<String, String> changes = new HashMap<String, String>(); private static final String PROP_HIDDEN = Router.PROP_HIDDEN_HIDDEN; // see Router for other choice @@ -87,6 +88,9 @@ public class ConfigNetHandler extends FormHandler { /** @since 0.9.20 */ public void setIPv4Firewalled(String moo) { _ipv4Firewalled = true; } + + /** @since 0.9.28 */ + public void setIPv6Firewalled(String moo) { _ipv6Firewalled = true; } public void setHostname(String hostname) { _hostname = (hostname != null ? hostname.trim() : null); @@ -366,6 +370,16 @@ public class ConfigNetHandler extends FormHandler { } changes.put(TransportUtil.PROP_IPV4_FIREWALLED, "" + _ipv4Firewalled); + if (Boolean.parseBoolean(_context.getProperty(TransportUtil.PROP_IPV6_FIREWALLED)) != + _ipv6Firewalled) { + if (_ipv6Firewalled) + addFormNotice(_t("Disabling inbound IPv6")); + else + addFormNotice(_t("Enabling inbound IPv6")); + restartRequired = true; + } + changes.put(TransportUtil.PROP_IPV6_FIREWALLED, "" + _ipv6Firewalled); + if (_context.getBooleanPropertyDefaultTrue(TransportManager.PROP_ENABLE_UDP) != !_udpDisabled) { if (_udpDisabled) diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHelper.java index 76b1369888d1801787eeb2805758af654199d91e..8222a057230d26b65f5e47368df07aeba4d5bca3 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHelper.java @@ -90,6 +90,11 @@ public class ConfigNetHelper extends HelperBase { return getChecked(TransportUtil.PROP_IPV4_FIREWALLED); } + /** @since 0.9.28 */ + public String getIPv6FirewalledChecked() { + return getChecked(TransportUtil.PROP_IPV6_FIREWALLED); + } + public String getTcpAutoPortChecked(int mode) { String port = _context.getProperty(PROP_I2NP_NTCP_PORT); boolean specified = port != null && port.length() > 0; diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigStatsHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigStatsHandler.java index 86e63a65f6de613a58f6acdd3f9661e2467dbaeb..b218a18f26af8923f79bb44d6431e7131b3e10f2 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigStatsHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigStatsHandler.java @@ -31,7 +31,9 @@ public class ConfigStatsHandler extends FormHandler { @Override protected void processForm() { - saveChanges(); + if (_action != null && _action.equals("foo")) { + saveChanges(); + } } public void setFilename(String filename) { diff --git a/apps/routerconsole/java/src/net/i2p/router/web/HomeHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/HomeHelper.java index c625ac19ec8322078f32097d1c71058e28619f7d..1a61bac550ef72cbc569af183b6c10ea8f06ccbb 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/HomeHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/HomeHelper.java @@ -50,9 +50,9 @@ public class HomeHelper extends HelperBase { _x("FAQ") + S + _x("Frequently Asked Questions") + S + "http://i2p-projekt.i2p/faq" + S + I + "question.png" + S + _x("Forum") + S + _x("Community forum") + S + "http://forum.i2p/" + S + I + "group.png" + S + _x("Anonymous Git Hosting") + S + _x("A public anonymous Git hosting site - supports pulling via Git and HTTP and pushing via SSH") + S + "http://git.repo.i2p/" + S + I + "git-logo.png" + S + - "hiddengate.i2p" + S + _x("HiddenGate") + S + "http://hiddengate.i2p/" + S + I + "hglogo32.png" + S + + //"hiddengate.i2p" + S + _x("HiddenGate") + S + "http://hiddengate.i2p/" + S + I + "hglogo32.png" + S + _x("I2P Wiki") + S + _x("Anonymous wiki - share the knowledge") + S + "http://i2pwiki.i2p/" + S + I + "i2pwiki_logo.png" + S + - "Ident " + _x("Microblog") + S + _x("Your premier microblogging service on I2P") + S + "http://id3nt.i2p/" + S + I + "ident_icon_blue.png" + S + + //"Ident " + _x("Microblog") + S + _x("Your premier microblogging service on I2P") + S + "http://id3nt.i2p/" + S + I + "ident_icon_blue.png" + S + //_x("Javadocs") + S + _x("Technical documentation") + S + "http://i2p-javadocs.i2p/" + S + I + "education.png" + S + //"jisko.i2p" + S + _x("Simple and fast microblogging website") + S + "http://jisko.i2p/" + S + I + "jisko_console_icon.png" + S + //_x("Key Server") + S + _x("OpenPGP Keyserver") + S + "http://keys.i2p/" + S + I + "education.png" + S + @@ -63,14 +63,14 @@ public class HomeHelper extends HelperBase { _x("Plugins") + S + _x("Add-on directory") + S + "http://i2pwiki.i2p/index.php?title=Plugins" + S + I + "plugin.png" + S + _x("Postman's Tracker") + S + _x("Bittorrent tracker") + S + "http://tracker2.postman.i2p/" + S + I + "magnet.png" + S + _x("Project Website") + S + _x("I2P home page") + S + "http://i2p-projekt.i2p/" + S + I + "info_rhombus.png" + S + - _x("Russian News Feed") + S + "lenta.i2p" + S + "http://lenta.i2p/" + S + I + "lenta_main_logo.png" + S + + //_x("Russian News Feed") + S + "lenta.i2p" + S + "http://lenta.i2p/" + S + I + "lenta_main_logo.png" + S + //"Salt" + S + "salt.i2p" + S + "http://salt.i2p/" + S + I + "salt_console.png" + S + "stats.i2p" + S + _x("I2P Network Statistics") + S + "http://stats.i2p/cgi-bin/dashboard.cgi" + S + I + "chart_line.png" + S + _x("Technical Docs") + S + _x("Technical documentation") + S + "http://i2p-projekt.i2p/how" + S + I + "education.png" + S + _x("The Tin Hat") + S + _x("Privacy guides and tutorials") + S + "http://secure.thetinhat.i2p/" + S + I + "thetinhat.png" + S + _x("Trac Wiki") + S + S + "http://trac.i2p2.i2p/" + S + I + "billiard_marker.png" + S + //_x("Ugha's Wiki") + S + S + "http://ugha.i2p/" + S + I + "billiard_marker.png" + S + - _x("Sponge's main site") + S + _x("Seedless and the Robert BitTorrent applications") + S + "http://sponge.i2p/" + S + I + "user_astronaut.png" + S + + //_x("Sponge's main site") + S + _x("Seedless and the Robert BitTorrent applications") + S + "http://sponge.i2p/" + S + I + "user_astronaut.png" + S + ""; diff --git a/apps/routerconsole/java/src/net/i2p/router/web/NetDbHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/NetDbHelper.java index ba977a6e8005b78a1fd78bfd747bb47119be3117..313018db9561615c0f83385fb4fed4140e52cbd5 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/NetDbHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/NetDbHelper.java @@ -7,6 +7,7 @@ public class NetDbHelper extends HelperBase { private String _routerPrefix; private String _version; private String _country; + private String _family; private int _full; private boolean _lease; private boolean _debug; @@ -49,6 +50,12 @@ public class NetDbHelper extends HelperBase { _country = DataHelper.stripHTML(c); // XSS } + /** @since 0.9.28 */ + public void setFamily(String c) { + if (c != null) + _family = DataHelper.stripHTML(c); // XSS + } + public void setFull(String f) { try { _full = Integer.parseInt(f); @@ -75,8 +82,8 @@ public class NetDbHelper extends HelperBase { NetDbRenderer renderer = new NetDbRenderer(_context); try { renderNavBar(); - if (_routerPrefix != null || _version != null || _country != null) - renderer.renderRouterInfoHTML(_out, _routerPrefix, _version, _country); + if (_routerPrefix != null || _version != null || _country != null || _family != null) + renderer.renderRouterInfoHTML(_out, _routerPrefix, _version, _country, _family); else if (_lease) renderer.renderLeaseSetHTML(_out, _debug); else if (_full == 3) diff --git a/apps/routerconsole/java/src/net/i2p/router/web/NetDbRenderer.java b/apps/routerconsole/java/src/net/i2p/router/web/NetDbRenderer.java index c9a34ece06d5e9f7764d32e6b9b95b0a3fc84fef..05ef0c1ac443ab5198b4ba5e6a55273ee6dd2df5 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/NetDbRenderer.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/NetDbRenderer.java @@ -85,8 +85,10 @@ class NetDbRenderer { * @param routerPrefix may be null. "." for our router only * @param version may be null * @param country may be null + * @param family may be null */ - public void renderRouterInfoHTML(Writer out, String routerPrefix, String version, String country) throws IOException { + public void renderRouterInfoHTML(Writer out, String routerPrefix, String version, + String country, String family) throws IOException { StringBuilder buf = new StringBuilder(4*1024); if (".".equals(routerPrefix)) { renderRouterInfo(buf, _context.router().getRouterInfo(), true, true); @@ -97,7 +99,8 @@ class NetDbRenderer { Hash key = ri.getIdentity().getHash(); if ((routerPrefix != null && key.toBase64().startsWith(routerPrefix)) || (version != null && version.equals(ri.getVersion())) || - (country != null && country.equals(_context.commSystem().getCountry(key)))) { + (country != null && country.equals(_context.commSystem().getCountry(key))) || + (family != null && family.equals(ri.getOption("family")))) { renderRouterInfo(buf, ri, false, true); notFound = false; } @@ -110,6 +113,8 @@ class NetDbRenderer { buf.append(version); else if (country != null) buf.append(country); + else if (family != null) + buf.append(_t("Family")).append(' ').append(family); buf.append(' ').append(_t("not found in network database")); } } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/NewsFeedHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/NewsFeedHelper.java index 5eaa3e3625ce662be63c37f1fd2226d9f8a8bbbb..a40e3061a61674aa1af7166c0229ed5b4ce70ce7 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/NewsFeedHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/NewsFeedHelper.java @@ -50,8 +50,18 @@ public class NewsFeedHelper extends HelperBase { ClientAppManager cmgr = ctx.clientAppManager(); if (cmgr != null) { NewsManager nmgr = (NewsManager) cmgr.getRegisteredApp(NewsManager.APP_NAME); - if (nmgr != null) + if (nmgr != null) { entries = nmgr.getEntries(); + NewsEntry init = nmgr.getInitialNews(); + if (init != null) { + // crude check to see if it's already in there + if (entries.size() != 1 || !DataHelper.eq(entries.get(0).title, init.title)) + if (entries.isEmpty()) + entries = Collections.singletonList(init); // in case it was an emtpyList + else + entries.add(init); + } + } } if (!entries.isEmpty()) { DateFormat fmt = DateFormat.getDateInstance(DateFormat.SHORT); diff --git a/apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java b/apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java index ae9cb0eb72a684d90eb11fe88dcb1e818bee1a52..7b0414d2e644ed03a2e7268d5d99f9ba555a186a 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java @@ -48,6 +48,7 @@ import org.eclipse.jetty.server.AbstractConnector; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.NCSARequestLog; import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.UserIdentity; import org.eclipse.jetty.server.bio.SocketConnector; import org.eclipse.jetty.server.handler.ContextHandlerCollection; import org.eclipse.jetty.server.handler.DefaultHandler; @@ -848,7 +849,8 @@ public class RouterConsoleRunner implements RouterApp { enable = false; ctx.router().saveConfig(PROP_CONSOLE_PW, "false"); } else { - HashLoginService realm = new HashLoginService(JETTY_REALM); + HashLoginService realm = new CustomHashLoginService(JETTY_REALM, context.getContextPath(), + ctx.logManager().getLog(RouterConsoleRunner.class)); sec.setLoginService(realm); sec.setAuthenticator(authenticator); String[] role = new String[] {JETTY_ROLE}; @@ -932,6 +934,30 @@ public class RouterConsoleRunner implements RouterApp { context.setSecurityHandler(sec); } + /** + * For logging authentication failures + * @since 0.9.28 + */ + private static class CustomHashLoginService extends HashLoginService { + private final String _webapp; + private final net.i2p.util.Log _log; + + public CustomHashLoginService(String realm, String webapp, net.i2p.util.Log log) { + super(realm); + _webapp = webapp; + _log = log; + } + + @Override + public UserIdentity login(String username, Object credentials) { + UserIdentity rv = super.login(username, credentials); + if (rv == null) + //_log.logAlways(net.i2p.util.Log.WARN, "Console authentication failed, webapp: " + _webapp + ", user: " + username); + _log.logAlways(net.i2p.util.Log.WARN, "Console authentication failed, user: " + username); + return rv; + } + } + /** @since 0.8.8 */ private class ServerShutdown implements Runnable { public void run() { diff --git a/apps/routerconsole/java/src/net/i2p/router/web/SybilRenderer.java b/apps/routerconsole/java/src/net/i2p/router/web/SybilRenderer.java index 98671a146fe49055105c8f47db120377aa24d577..703e93958a3cf0c82a14564138b010a8626e24b1 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/SybilRenderer.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/SybilRenderer.java @@ -4,6 +4,7 @@ import java.io.IOException; import java.io.Serializable; import java.io.Writer; import java.math.BigInteger; +import java.text.Collator; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Collections; @@ -24,6 +25,7 @@ import net.i2p.data.router.RouterInfo; import net.i2p.data.router.RouterKeyGenerator; import net.i2p.router.RouterContext; import net.i2p.router.TunnelPoolSettings; +import net.i2p.router.crypto.FamilyKeyCrypto; import net.i2p.router.peermanager.DBHistory; import net.i2p.router.peermanager.PeerProfile; import net.i2p.router.tunnel.pool.TunnelPool; @@ -61,6 +63,8 @@ class SybilRenderer { private static final double POINTS_US24 = 25.0; private static final double POINTS_US16 = 10.0; private static final double POINTS_FAMILY = -2.0; + private static final double POINTS_BAD_OUR_FAMILY = 100.0; + private static final double POINTS_OUR_FAMILY = -100.0; private static final double MIN_CLOSE = 242.0; private static final double PAIR_DISTANCE_FACTOR = 2.0; private static final double OUR_KEY_FACTOR = 4.0; @@ -370,6 +374,7 @@ class SybilRenderer { private static class FoofComparator implements Comparator<String>, Serializable { private final ObjectCounter<String> _o; + private final Collator _comp = Collator.getInstance(); public FoofComparator(ObjectCounter<String> o) { _o = o;} public int compare(String l, String r) { // reverse by count @@ -377,7 +382,7 @@ class SybilRenderer { if (rv != 0) return rv; // foward by name - return l.compareTo(r); + return _comp.compare(l, r); } } @@ -578,11 +583,14 @@ class SybilRenderer { } List<String> foo = new ArrayList<String>(oc.objects()); Collections.sort(foo, new FoofComparator(oc)); + FamilyKeyCrypto fkc = _context.router().getFamilyKeyCrypto(); + String ourFamily = fkc != null ? fkc.getOurFamilyName() : null; boolean found = false; for (String s : foo) { int count = oc.count(s); - buf.append("<p><b>").append(count).append(" floodfills in declared family \"").append(DataHelper.escapeHTML(s) + '"') - .append("</b></p>"); + String ss = DataHelper.escapeHTML(s); + buf.append("<p><b>").append(count).append(" floodfills in declared family \"<a href=\"/netdb?fam=") + .append(ss).append("\">").append(ss).append("</a>\"</b></p>"); for (RouterInfo info : ris) { String fam = info.getOption("family"); if (fam == null) @@ -593,10 +601,16 @@ class SybilRenderer { // limit display //renderRouterInfo(buf, info, null, false, false); double point = POINTS_FAMILY; - if (count > 1) + if (fkc != null && s.equals(ourFamily)) { + if (fkc.verifyOurFamily(info)) + addPoints(points, info.getHash(), POINTS_OUR_FAMILY, "Our family \"" + DataHelper.escapeHTML(s) + "\" with " + (count - 1) + " other" + (( count > 2) ? "s" : "")); + else + addPoints(points, info.getHash(), POINTS_BAD_OUR_FAMILY, "Spoofed our family \"" + DataHelper.escapeHTML(s) + "\" with " + (count - 1) + " other" + (( count > 2) ? "s" : "")); + } else if (count > 1) { addPoints(points, info.getHash(), point, "Same declared family \"" + DataHelper.escapeHTML(s) + "\" with " + (count - 1) + " other" + (( count > 2) ? "s" : "")); - else + } else { addPoints(points, info.getHash(), point, "Declared family \"" + DataHelper.escapeHTML(s) + '"'); + } } } if (!found) diff --git a/apps/routerconsole/jsp/confignet.jsp b/apps/routerconsole/jsp/confignet.jsp index 7b81518e34fc264f88b425b5d648b844fcbf9f9a..4551668637608408ebacf477dcc74a45f874e4b8 100644 --- a/apps/routerconsole/jsp/confignet.jsp +++ b/apps/routerconsole/jsp/confignet.jsp @@ -56,6 +56,8 @@ <%=intl._t("Disable inbound (Firewalled by Carrier-grade NAT or DS-Lite)")%> </p><p> <%=intl._t("IPv6 Configuration")%>:<br> + <input type="checkbox" class="optbox" name="IPv6Firewalled" value="true" <jsp:getProperty name="nethelper" property="IPv6FirewalledChecked" /> > + <%=intl._t("Disable inbound (Firewalled by Carrier-grade NAT or DS-Lite)")%><br> <input type="radio" class="optbox" name="ipv6" value="false" <%=nethelper.getIPv6Checked("false") %> > <%=intl._t("Disable IPv6")%><br> <input type="radio" class="optbox" name="ipv6" value="enable" <%=nethelper.getIPv6Checked("enable") %> > diff --git a/apps/routerconsole/jsp/netdb.jsp b/apps/routerconsole/jsp/netdb.jsp index 1b9be5d03fef789276c176b2f1a6476fa421036c..c323aa760b4e8fb9c3d5f90935f4f6d4ef42252e 100644 --- a/apps/routerconsole/jsp/netdb.jsp +++ b/apps/routerconsole/jsp/netdb.jsp @@ -25,5 +25,6 @@ <jsp:setProperty name="netdbHelper" property="lease" value="<%=request.getParameter(\"l\")%>" /> <jsp:setProperty name="netdbHelper" property="version" value="<%=request.getParameter(\"v\")%>" /> <jsp:setProperty name="netdbHelper" property="country" value="<%=request.getParameter(\"c\")%>" /> + <jsp:setProperty name="netdbHelper" property="family" value="<%=request.getParameter(\"fam\")%>" /> <jsp:getProperty name="netdbHelper" property="netDbSummary" /> </div></div></body></html> diff --git a/apps/sam/java/build.xml b/apps/sam/java/build.xml index 9aab0527c6d07fdb4a400b525ac0751dc28a0862..5891bd1a84c57ebaf816cacc7f694c4b25edd2bf 100644 --- a/apps/sam/java/build.xml +++ b/apps/sam/java/build.xml @@ -77,6 +77,8 @@ <attribute name="Build-Date" value="${build.timestamp}" /> <attribute name="Base-Revision" value="${workspace.version}" /> <attribute name="Workspace-Changes" value="${workspace.changes.tr}" /> + <attribute name="X-Compile-Source-JDK" value="${javac.version}" /> + <attribute name="X-Compile-Target-JDK" value="${javac.version}" /> </manifest> </jar> </target> diff --git a/apps/sam/java/src/net/i2p/sam/SAMHandlerFactory.java b/apps/sam/java/src/net/i2p/sam/SAMHandlerFactory.java index 54e9c56b56446e853ad1917bd2e6cc29746cac6b..c6ed6243b64992544ea24940e6b8d41eba6d5bcb 100644 --- a/apps/sam/java/src/net/i2p/sam/SAMHandlerFactory.java +++ b/apps/sam/java/src/net/i2p/sam/SAMHandlerFactory.java @@ -91,14 +91,23 @@ class SAMHandlerFactory { if (Boolean.parseBoolean(i2cpProps.getProperty(SAMBridge.PROP_AUTH))) { String user = props.getProperty("USER"); String pw = props.getProperty("PASSWORD"); - if (user == null || pw == null) + if (user == null || pw == null) { + if (user == null) + log.logAlways(Log.WARN, "SAM authentication failed"); + else + log.logAlways(Log.WARN, "SAM authentication failed, user: " + user); throw new SAMException("USER and PASSWORD required"); + } String savedPW = i2cpProps.getProperty(SAMBridge.PROP_PW_PREFIX + user + SAMBridge.PROP_PW_SUFFIX); - if (savedPW == null) + if (savedPW == null) { + log.logAlways(Log.WARN, "SAM authentication failed, user: " + user); throw new SAMException("Authorization failed"); + } PasswordManager pm = new PasswordManager(I2PAppContext.getGlobalContext()); - if (!pm.checkHash(savedPW, pw)) + if (!pm.checkHash(savedPW, pw)) { + log.logAlways(Log.WARN, "SAM authentication failed, user: " + user); throw new SAMException("Authorization failed"); + } } // Let's answer positively diff --git a/apps/streaming/java/build.xml b/apps/streaming/java/build.xml index 0c2b80d71e5e85e6d187d9ec0fde360b82945ca4..1b421e2f52e94c618633c4aea385423f370fa0c9 100644 --- a/apps/streaming/java/build.xml +++ b/apps/streaming/java/build.xml @@ -213,6 +213,8 @@ <attribute name="Build-Date" value="${build.timestamp}" /> <attribute name="Base-Revision" value="${workspace.version}" /> <attribute name="Workspace-Changes" value="${workspace.changes.tr}" /> + <attribute name="X-Compile-Source-JDK" value="${javac.version}" /> + <attribute name="X-Compile-Target-JDK" value="${javac.version}" /> </manifest> </jar> </target> diff --git a/apps/susidns/src/build.xml b/apps/susidns/src/build.xml index eefdacd5950b6c89d145b038ed541c6f011f17d1..ac9a6f63aa3e0e43ecefdfa783d2406fcf82c3c1 100644 --- a/apps/susidns/src/build.xml +++ b/apps/susidns/src/build.xml @@ -117,6 +117,8 @@ <attribute name="Build-Date" value="${build.timestamp}" /> <attribute name="Base-Revision" value="${workspace.version}" /> <attribute name="Workspace-Changes" value="${workspace.changes.tr}" /> + <attribute name="X-Compile-Source-JDK" value="${javac.version}" /> + <attribute name="X-Compile-Target-JDK" value="${javac.version}" /> </manifest> </war> </target> diff --git a/apps/susimail/build.xml b/apps/susimail/build.xml index b3ede69b37f2c70aaaac3a2975a8666f1683576f..1df5e1129bde691ce68eee4f87629b166839cac4 100644 --- a/apps/susimail/build.xml +++ b/apps/susimail/build.xml @@ -81,6 +81,8 @@ <attribute name="Build-Date" value="${build.timestamp}" /> <attribute name="Base-Revision" value="${workspace.version}" /> <attribute name="Workspace-Changes" value="${workspace.changes.tr}" /> + <attribute name="X-Compile-Source-JDK" value="${javac.version}" /> + <attribute name="X-Compile-Target-JDK" value="${javac.version}" /> </manifest> </war> </target> diff --git a/apps/susimail/src/src/i2p/susi/webmail/WebMail.java b/apps/susimail/src/src/i2p/susi/webmail/WebMail.java index edf94936fa2775af8d09ce995743c893a1cd7d12..4da8c680ea83c89572681d6363715d0d6ecb093e 100644 --- a/apps/susimail/src/src/i2p/susi/webmail/WebMail.java +++ b/apps/susimail/src/src/i2p/susi/webmail/WebMail.java @@ -87,6 +87,7 @@ public class WebMail extends HttpServlet private static final int version = 13; private static final long serialVersionUID = 1L; + private static final String LOGIN_NONCE = Long.toString(I2PAppContext.getGlobalContext().random().nextLong()); private static final String DEFAULT_HOST = "127.0.0.1"; private static final int DEFAULT_POP3PORT = 7660; @@ -466,6 +467,8 @@ public class WebMail extends HttpServlet /** @since 0.9.27 */ public boolean isValidNonce(String nonce) { + if (state == STATE_AUTH && LOGIN_NONCE.equals(nonce)) + return true; synchronized(nonces) { return nonces.contains(nonce); } @@ -856,7 +859,7 @@ public class WebMail extends HttpServlet } sessionObject.info += _t("User logged out.") + '\n'; sessionObject.state = STATE_AUTH; - } else if( sessionObject.mailbox == null ) { + } else if( sessionObject.mailbox == null && !buttonPressed(request, CANCEL)) { sessionObject.error += _t("Internal error, lost connection.") + '\n'; sessionObject.state = STATE_AUTH; } @@ -878,7 +881,7 @@ public class WebMail extends HttpServlet if( sessionObject.state == STATE_AUTH && isPOST ) processLogin( sessionObject, request ); - if( sessionObject.state != STATE_AUTH && sessionObject.state != STATE_CONFIG ) + if( sessionObject.state != STATE_AUTH ) processLogout( sessionObject, request, isPOST ); /* @@ -1797,7 +1800,8 @@ public class WebMail extends HttpServlet out.println("<script src=\"/susimail/js/folder.js\" type=\"text/javascript\"></script>"); } out.print("</head>\n<body" + (sessionObject.state == STATE_LIST ? " onload=\"deleteboxclicked()\">" : ">")); - String nonce = Long.toString(ctx.random().nextLong()); + String nonce = sessionObject.state == STATE_AUTH ? LOGIN_NONCE : + Long.toString(ctx.random().nextLong()); sessionObject.addNonce(nonce); out.println( "<div class=\"page\"><div class=\"header\"><img class=\"header\" src=\"" + sessionObject.imgPath + "susimail.png\" alt=\"Susimail\"></div>\n" + @@ -2409,6 +2413,7 @@ public class WebMail extends HttpServlet out.println(button2(DELETE, _t("Delete"))); else out.println(button(DELETE, _t("Delete"))); + out.println(spacer + button(LOGOUT, _t("Logout") )); out.println("<br>" + ( sessionObject.folder.isFirstElement( sessionObject.showUIDL ) ? button2( PREV, _t("Previous") ) : button( PREV, _t("Previous") ) ) + spacer + button( LIST, _t("Back to Folder") ) + spacer + @@ -2416,7 +2421,6 @@ public class WebMail extends HttpServlet out.println("</div>"); //if (Config.hasConfigFile()) // out.println(button( RELOAD, _t("Reload Config") ) + spacer); - //out.println(button( LOGOUT, _t("Logout") ) ); if( mail != null ) { out.println( "<table cellspacing=\"0\" cellpadding=\"5\">\n" + "<tr><td colspan=\"2\" align=\"center\"><hr></td></tr>\n" + @@ -2473,6 +2477,8 @@ public class WebMail extends HttpServlet out.println("<br>"); out.println(button(SAVE, _t("Save Configuration"))); out.println(button(CANCEL, _t("Cancel"))); + if (sessionObject.folder != null) + out.println(spacer + button(LOGOUT, _t("Logout") )); out.println("</div>"); } diff --git a/apps/systray/java/build.xml b/apps/systray/java/build.xml index 448c5ca8fcafa0bff60a7aa5972f6d2284f61f2b..8d00ba1f8b6edac68f8b9f7b124ae246086baaa7 100644 --- a/apps/systray/java/build.xml +++ b/apps/systray/java/build.xml @@ -65,6 +65,8 @@ <attribute name="Build-Date" value="${build.timestamp}" /> <attribute name="Base-Revision" value="${workspace.version}" /> <attribute name="Workspace-Changes" value="${workspace.changes.tr}" /> + <attribute name="X-Compile-Source-JDK" value="${javac.version}" /> + <attribute name="X-Compile-Target-JDK" value="${javac.version}" /> </manifest> </jar> </target> diff --git a/build.xml b/build.xml index 180976fd758e6e8dc9bf16cee26073dfe8ab97b8..750db1ad0aab257e9e9d9cf0c7ad2ca86ee189b1 100644 --- a/build.xml +++ b/build.xml @@ -400,7 +400,7 @@ <copy file="core/java/build/i2p.jar" todir="build/" /> </target> - <target name="buildJrobin" depends="buildProperties" > + <target name="buildJrobin" depends="buildCore" > <ant dir="apps/jrobin/java/" target="jar" /> <copy file="apps/jrobin/java/build/jrobin.jar" todir="build/" /> </target> @@ -1184,7 +1184,7 @@ </target> <!-- see targets below for conditional copying --> - <target name="preppkg-base" depends="build, preplicenses, prepConsoleDocs, prepthemeupdates, prepCertificates, prepRouterInfos, copyjetty, copytomcat-unlesspkg, copyjstl-unlesspkg, copystandard-unlesspkg"> + <target name="preppkg-base" depends="build, preplicenses, prepConsoleDocs, prepthemeupdates, prepCertificates, prepRouterInfos, copyjetty, copytomcat-unlesspkg, copyjstl-unlesspkg, copystandard-unlesspkg, truncatehistory"> <!-- if updater200 was run previously, it left *.pack files in pkg-temp --> <!-- Also remove deletelist.txt used for updater only --> <delete> @@ -1218,8 +1218,6 @@ <copy file="installer/resources/wrapper.config" todir="pkg-temp/" /> <copy file="installer/resources/hosts.txt" todir="pkg-temp/" /> <copy file="INSTALL-headless.txt" todir="pkg-temp/" /> - <!-- overwrite the truncated history put in by the updater --> - <copy file="history.txt" todir="pkg-temp/" overwrite="true" /> <mkdir dir="pkg-temp/scripts" /> <copy file="apps/proxyscript/i2pProxy.pac" todir="pkg-temp/scripts/" /> <copy file="apps/apparmor/home.i2p.i2prouter" todir="pkg-temp/scripts/" /> @@ -1506,7 +1504,7 @@ </exec> </target> - <target name="prepupdate" depends="build2, prepupdateSmall, prepConsoleDocUpdates, prepCertificates, prep-script-translation"> + <target name="prepupdate" depends="build2, prepupdateSmall, prepConsoleDocUpdates, prepCertificates, prep-script-translation, truncatehistory"> <copy file="build/BOB.jar" todir="pkg-temp/lib/" /> <copy file="build/sam.jar" todir="pkg-temp/lib/" /> <copy file="build/i2psnark.jar" todir="pkg-temp/lib" /> @@ -1523,6 +1521,14 @@ <copy file="apps/susidns/src/lib/standard.jar" todir="pkg-temp/lib/" /> --> <copy file="build/i2psnark.war" todir="pkg-temp/webapps/" /> + <copy file="installer/resources/deletelist.txt" todir="pkg-temp/" /> + <copy file="installer/resources/blocklist.txt" todir="pkg-temp/" /> + <copy todir="pkg-temp/man/"> + <fileset dir="installer/resources/man/" /> + </copy> + </target> + + <target name="truncatehistory"> <copy file="history.txt" todir="pkg-temp/" /> <!-- the following overwrites history.txt on unix to shrink the update file --> <copy file="history.txt" tofile="pkg-temp/history.txt" overwrite="true"> @@ -1530,12 +1536,7 @@ <headfilter lines="1500" /> </filterchain> </copy> - <concat append="true" destfile="pkg-temp/history.txt"> ---------------- EARLIER HISTORY IS AVAILABLE IN THE SOURCE PACKAGE"</concat> - <copy file="installer/resources/deletelist.txt" todir="pkg-temp/" /> - <copy file="installer/resources/blocklist.txt" todir="pkg-temp/" /> - <copy todir="pkg-temp/man/"> - <fileset dir="installer/resources/man/" /> - </copy> + <concat append="true" destfile="pkg-temp/history.txt"> ---------------- EARLIER HISTORY IS AVAILABLE IN THE SOURCE PACKAGE</concat> </target> <target name="prepupdateSmall" depends="buildSmall, prepupdateRouter, prepjupdatefixes, prepthemeupdates"> diff --git a/core/java/build.xml b/core/java/build.xml index 3143f550c92979fd9e76c3cd6f0770f78bacc2d0..1f301ae591b7982b0dcf06ecc6bd1b7b33dce65e 100644 --- a/core/java/build.xml +++ b/core/java/build.xml @@ -108,6 +108,8 @@ <attribute name="Base-Revision" value="${workspace.version}" /> <attribute name="Main-Class" value="net.i2p.util.CommandLine" /> <attribute name="Workspace-Changes" value="${workspace.changes.tr}" /> + <attribute name="X-Compile-Source-JDK" value="${javac.version}" /> + <attribute name="X-Compile-Target-JDK" value="${javac.version}" /> </manifest> </jar> </target> diff --git a/core/java/src/net/i2p/client/impl/RequestLeaseSetMessageHandler.java b/core/java/src/net/i2p/client/impl/RequestLeaseSetMessageHandler.java index 09dab72ff429486a5456a615a47c64ce3ff58354..809492c4cca9d62d08265d04135909908e1aecc1 100644 --- a/core/java/src/net/i2p/client/impl/RequestLeaseSetMessageHandler.java +++ b/core/java/src/net/i2p/client/impl/RequestLeaseSetMessageHandler.java @@ -9,6 +9,7 @@ package net.i2p.client.impl; * */ +import java.io.EOFException; import java.security.GeneralSecurityException; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -185,7 +186,16 @@ class RequestLeaseSetMessageHandler extends HandlerImpl { } catch (DataFormatException dfe) { session.propogateError("Error signing the leaseSet", dfe); } catch (I2PSessionException ise) { - session.propogateError("Error sending the signed leaseSet", ise); + if (session.isClosed()) { + // race, closed while signing leaseset + // EOFExceptions are logged at WARN level (see I2PSessionImpl.propogateError()) + // so the user won't see this + EOFException eof = new EOFException("Session closed while signing leaseset"); + eof.initCause(ise); + session.propogateError("Session closed while signing leaseset", eof); + } else { + session.propogateError("Error sending the signed leaseSet", ise); + } } } diff --git a/core/java/src/net/i2p/crypto/CertUtil.java b/core/java/src/net/i2p/crypto/CertUtil.java index ed0c63ce16348c7ff5666014b69a3ec2e82937f0..be7d100c938b6c8b02cc5c34edc4f30eb9edbaf1 100644 --- a/core/java/src/net/i2p/crypto/CertUtil.java +++ b/core/java/src/net/i2p/crypto/CertUtil.java @@ -535,8 +535,6 @@ public final class CertUtil { } - -/**** public static final void main(String[] args) { if (args.length < 2) { System.out.println("Usage: [loadcert | loadcrl | loadcrldir | loadcrldirs | isrevoked | loadprivatekey] file"); @@ -545,7 +543,8 @@ public final class CertUtil { try { File f = new File(args[1]); if (args[0].equals("loadcert")) { - loadCert(f); + X509Certificate cert = loadCert(f); + System.out.println(net.i2p.util.HexDump.dump(cert.getEncoded())); } else if (args[0].equals("loadcrl")) { loadCRL(f); } else if (args[0].equals("loadcrldir")) { @@ -569,5 +568,4 @@ public final class CertUtil { System.exit(1); } } -****/ } diff --git a/core/java/src/net/i2p/crypto/SelfSignedGenerator.java b/core/java/src/net/i2p/crypto/SelfSignedGenerator.java index 35a0a831aa60792848cd5454e532246d93dd8638..5f525b2d7a59bef19eec2ee18aa11fd4b867a3fd 100644 --- a/core/java/src/net/i2p/crypto/SelfSignedGenerator.java +++ b/core/java/src/net/i2p/crypto/SelfSignedGenerator.java @@ -264,11 +264,11 @@ public final class SelfSignedGenerator { // a0 ???, int = 2 byte[] version = { (byte) 0xa0, 3, 2, 1, 2 }; - // postive serial number (int) - byte[] serial = new byte[6]; + // positive serial number (long) + byte[] serial = new byte[10]; serial[0] = 2; - serial[1] = 4; - RandomSource.getInstance().nextBytes(serial, 2, 4); + serial[1] = 8; + RandomSource.getInstance().nextBytes(serial, 2, 8); serial[2] &= 0x7f; // going to use this for both issuer and subject diff --git a/core/java/src/net/i2p/crypto/eddsa/math/Constants.java b/core/java/src/net/i2p/crypto/eddsa/math/Constants.java index 885bee57ff6c0b49602783c792a36f766e9e51f4..3b67f240ca4afdd2783d665a1a47e027e32706f9 100644 --- a/core/java/src/net/i2p/crypto/eddsa/math/Constants.java +++ b/core/java/src/net/i2p/crypto/eddsa/math/Constants.java @@ -2,7 +2,7 @@ package net.i2p.crypto.eddsa.math; import net.i2p.crypto.eddsa.Utils; -public class Constants { +final class Constants { public static final byte[] ZERO = Utils.hexToBytes("0000000000000000000000000000000000000000000000000000000000000000"); public static final byte[] ONE = Utils.hexToBytes("0100000000000000000000000000000000000000000000000000000000000000"); public static final byte[] TWO = Utils.hexToBytes("0200000000000000000000000000000000000000000000000000000000000000"); diff --git a/core/java/src/net/i2p/util/Addresses.java b/core/java/src/net/i2p/util/Addresses.java index 15352975bc8bf14fdac88f634f1dcdfe0bff478b..db28be6baa8169b88402ffb1dbf6f17fc502fa38 100644 --- a/core/java/src/net/i2p/util/Addresses.java +++ b/core/java/src/net/i2p/util/Addresses.java @@ -4,14 +4,21 @@ package net.i2p.util; * public domain */ +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; import java.net.InetAddress; import java.net.Inet4Address; +import java.net.Inet6Address; import java.net.NetworkInterface; import java.net.SocketException; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -21,6 +28,8 @@ import java.util.TreeSet; import org.apache.http.conn.util.InetAddressUtils; import net.i2p.I2PAppContext; +import net.i2p.data.DataHelper; + /** * Methods to get the local addresses, and other IP utilities @@ -30,6 +39,16 @@ import net.i2p.I2PAppContext; */ public abstract class Addresses { + private static final File IF_INET6_FILE = new File("/proc/net/if_inet6"); + private static final long INET6_CACHE_EXPIRE = 10*60*1000; + private static final boolean INET6_CACHE_ENABLED = !SystemVersion.isMac() && !SystemVersion.isWindows() && + !SystemVersion.isAndroid() && IF_INET6_FILE.exists(); + private static final int FLAG_PERMANENT = 0x80; + private static final int FLAG_DEPRECATED = 0x20; + private static final int FLAG_TEMPORARY = 0x01; + private static long _ifCacheTime; + private static final Map<Inet6Address, Inet6Addr> _ifCache = INET6_CACHE_ENABLED ? new HashMap<Inet6Address, Inet6Addr>(8) : null; + /** * Do we have any non-loop, non-wildcard IPv4 address at all? * @since 0.9.4 @@ -101,18 +120,25 @@ public abstract class Addresses { boolean haveIPv4 = false; boolean haveIPv6 = false; SortedSet<String> rv = new TreeSet<String>(); + final boolean omitDeprecated = INET6_CACHE_ENABLED && !includeSiteLocal && includeIPv6; try { InetAddress localhost = InetAddress.getLocalHost(); InetAddress[] allMyIps = InetAddress.getAllByName(localhost.getCanonicalHostName()); if (allMyIps != null) { for (int i = 0; i < allMyIps.length; i++) { - if (allMyIps[i] instanceof Inet4Address) + boolean isv4 = allMyIps[i] instanceof Inet4Address; + if (isv4) haveIPv4 = true; else haveIPv6 = true; + if (omitDeprecated && !isv4) { + if (isDeprecated((Inet6Address) allMyIps[i])) + continue; + } if (shouldInclude(allMyIps[i], includeSiteLocal, - includeLoopbackAndWildcard, includeIPv6)) + includeLoopbackAndWildcard, includeIPv6)) { rv.add(stripScope(allMyIps[i].getHostAddress())); + } } } } catch (UnknownHostException e) {} @@ -124,13 +150,19 @@ public abstract class Addresses { NetworkInterface ifc = ifcs.nextElement(); for(Enumeration<InetAddress> addrs = ifc.getInetAddresses(); addrs.hasMoreElements();) { InetAddress addr = addrs.nextElement(); - if (addr instanceof Inet4Address) + boolean isv4 = addr instanceof Inet4Address; + if (isv4) haveIPv4 = true; else haveIPv6 = true; + if (omitDeprecated && !isv4) { + if (isDeprecated((Inet6Address) addr)) + continue; + } if (shouldInclude(addr, includeSiteLocal, - includeLoopbackAndWildcard, includeIPv6)) + includeLoopbackAndWildcard, includeIPv6)) { rv.add(stripScope(addr.getHostAddress())); + } } } } @@ -333,8 +365,8 @@ public abstract class Addresses { /** * For literal IP addresses, this is the same as getIP(String). - * For host names, will return the preferred type (IPv4/v6) if available, - * else the other type if available. + * For host names, may return multiple addresses, both IPv4 and IPv6, + * even if those addresses are not reachable due to configuration or available interfaces. * Will resolve but not cache DNS host names. * * Note that order of returned results, and whether @@ -370,6 +402,136 @@ public abstract class Addresses { return null; } + //////// IPv6 Cache Utils /////// + + /** + * @since 0.9.28 + */ + private static class Inet6Addr { + private final Inet6Address addr; + private final boolean isDyn, isDep, isTemp; + + public Inet6Addr(Inet6Address a, int flags) { + addr = a; + isDyn = (flags & FLAG_PERMANENT) == 0; + isDep = (flags & FLAG_DEPRECATED) != 0; + isTemp = (flags & FLAG_TEMPORARY) != 0; + } + + public Inet6Address getAddress() { return addr; } + public boolean isDynamic() { return isDyn; } + public boolean isDeprecated() { return isDep; } + public boolean isTemporary() { return isTemp; } + } + + /** + * Only call if INET6_CACHE_ENABLED. + * Caller must sync on _ifCache. + * @since 0.9.28 + */ + private static void refreshCache() { + long now = System.currentTimeMillis(); + if (now - _ifCacheTime < INET6_CACHE_EXPIRE) + return; + _ifCache.clear(); + BufferedReader in = null; + try { + in = new BufferedReader(new InputStreamReader(new FileInputStream(IF_INET6_FILE), "ISO-8859-1"), 4096); + String line = null; + while ( (line = in.readLine()) != null) { + // http://tldp.org/HOWTO/html_single/Linux+IPv6-HOWTO/#PROC-NET + // 00000000000000000000000000000001 01 80 10 80 lo + String[] parts = DataHelper.split(line, " ", 6); + if (parts.length < 5) + continue; + String as = parts[0]; + if (as.length() != 32) + continue; + StringBuilder buf = new StringBuilder(40); + int i = 0; + while(true) { + buf.append(as.substring(i, i+4)); + i += 4; + if (i >= 32) + break; + buf.append(':'); + } + Inet6Address addr; + try { + addr = (Inet6Address) InetAddress.getByName(buf.toString()); + } catch (UnknownHostException uhe) { + continue; + } + int flags = FLAG_PERMANENT; + try { + flags = Integer.parseInt(parts[4], 16); + } catch (NumberFormatException nfe) {} + Inet6Addr a = new Inet6Addr(addr, flags); + _ifCache.put(addr, a); + } + } catch (IOException ioe) { + } finally { + if (in != null) try { in.close(); } catch (IOException ioe) {} + } + _ifCacheTime = now; + } + + /** + * Is this address dynamic? + * Returns false if unknown. + * @since 0.9.28 + */ + public static boolean isDynamic(Inet6Address addr) { + if (!INET6_CACHE_ENABLED) + return false; + Inet6Addr a; + synchronized(_ifCache) { + refreshCache(); + a = _ifCache.get(addr); + } + if (a == null) + return false; + return a.isDynamic(); + } + + /** + * Is this address deprecated? + * Returns false if unknown. + * @since 0.9.28 + */ + public static boolean isDeprecated(Inet6Address addr) { + if (!INET6_CACHE_ENABLED) + return false; + Inet6Addr a; + synchronized(_ifCache) { + refreshCache(); + a = _ifCache.get(addr); + } + if (a == null) + return false; + return a.isDeprecated(); + } + + /** + * Is this address temporary? + * Returns false if unknown. + * @since 0.9.28 + */ + public static boolean isTemporary(Inet6Address addr) { + if (!INET6_CACHE_ENABLED) + return false; + Inet6Addr a; + synchronized(_ifCache) { + refreshCache(); + a = _ifCache.get(addr); + } + if (a == null) + return false; + return a.isTemporary(); + } + + //////// End IPv6 Cache Utils /////// + /** * @since 0.9.3 */ @@ -377,32 +539,66 @@ public abstract class Addresses { synchronized(_IPAddress) { _IPAddress.clear(); } + if (_ifCache != null) { + synchronized(_ifCache) { + _ifCache.clear(); + _ifCacheTime = 0; + } + } } /** * Print out the local addresses */ public static void main(String[] args) { - System.err.println("External IPv4 Addresses:"); + System.out.println("External IPv4 Addresses:"); Set<String> a = getAddresses(false, false, false); for (String s : a) - System.err.println(s); - System.err.println("\nExternal and Local IPv4 Addresses:"); + System.out.println(s); + System.out.println("\nExternal and Local IPv4 Addresses:"); a = getAddresses(true, false, false); for (String s : a) - System.err.println(s); - System.err.println("\nAll External Addresses:"); + System.out.println(s); + System.out.println("\nAll External Addresses:"); a = getAddresses(false, false, true); for (String s : a) - System.err.println(s); - System.err.println("\nAll External and Local Addresses:"); + System.out.println(s); + System.out.println("\nAll External and Local Addresses:"); a = getAddresses(true, false, true); for (String s : a) - System.err.println(s); - System.err.println("\nAll addresses:"); + System.out.println(s); + System.out.println("\nAll addresses:"); a = getAddresses(true, true, true); for (String s : a) - System.err.println(s); - System.err.println("\nIs connected? " + isConnected()); + System.out.println(s); + System.out.println("\nIPv6 address flags:"); + for (String s : a) { + if (!s.contains(":")) + continue; + StringBuilder buf = new StringBuilder(64); + buf.append(s); + Inet6Address addr; + try { + addr = (Inet6Address) InetAddress.getByName(buf.toString()); + if (addr.isSiteLocalAddress()) + buf.append(" host"); + else if (addr.isLinkLocalAddress()) + buf.append(" link"); + else if (addr.isAnyLocalAddress()) + buf.append(" wildcard"); + else if (addr.isLoopbackAddress()) + buf.append(" loopback"); + else + buf.append(" global"); + if (isTemporary(addr)) + buf.append(" temporary"); + if (isDeprecated(addr)) + buf.append(" deprecated"); + if (isDynamic(addr)) + buf.append(" dynamic"); + } catch (UnknownHostException uhe) {} + System.out.println(buf.toString()); + } + System.out.println("\nIs connected? " + isConnected()); } } diff --git a/core/java/src/net/i2p/util/CommandLine.java b/core/java/src/net/i2p/util/CommandLine.java index f2d57f5346f74d33b0400a4d3748fa4dc9bbd3f2..bfd1ca231a246b66a45d66c7f90bc2ef574008e9 100644 --- a/core/java/src/net/i2p/util/CommandLine.java +++ b/core/java/src/net/i2p/util/CommandLine.java @@ -22,6 +22,7 @@ public class CommandLine { "freenet.support.CPUInformation.CPUID", "net.i2p.CoreVersion", "net.i2p.client.naming.BlockfileNamingService", + "net.i2p.crypto.CertUtil", "net.i2p.crypto.CryptoCheck", "net.i2p.crypto.SU3File", "net.i2p.crypto.TrustedUpdate", diff --git a/core/java/src/net/i2p/util/LogWriter.java b/core/java/src/net/i2p/util/LogWriter.java index 1b585fb3868ad8950e8add394e3767f5bc065db1..38830841b6c4b6618277e86b2b320a676d7b5835 100644 --- a/core/java/src/net/i2p/util/LogWriter.java +++ b/core/java/src/net/i2p/util/LogWriter.java @@ -29,6 +29,7 @@ abstract class LogWriter implements Runnable { protected volatile boolean _write; private LogRecord _last; + private long _firstTimestamp; // ms private volatile long _flushInterval = FLUSH_INTERVAL; @@ -95,7 +96,7 @@ abstract class LogWriter implements Runnable { Queue<LogRecord> records = _manager.getQueue(); if (records == null) return; if (!records.isEmpty()) { - if (_last != null && _last.getDate() < _manager.getContext().clock().now() - 30*60*1000) + if (_last != null && _firstTimestamp < _manager.getContext().clock().now() - 30*60*1000) _last = null; LogRecord rec; int dupCount = 0; @@ -108,6 +109,7 @@ abstract class LogWriter implements Runnable { dupCount = 0; } writeRecord(rec); + _firstTimestamp = rec.getDate(); } _last = rec; } diff --git a/core/java/src/net/i2p/util/SystemVersion.java b/core/java/src/net/i2p/util/SystemVersion.java index aaa00da9b5d5818876fe223be11913ab34364780..bd159fb1ab991f18b7cc9e35d0287b5ef3d7aecc 100644 --- a/core/java/src/net/i2p/util/SystemVersion.java +++ b/core/java/src/net/i2p/util/SystemVersion.java @@ -34,8 +34,7 @@ public abstract class SystemVersion { private static final boolean _isOpenJDK; private static final boolean _is64; private static final boolean _hasWrapper = System.getProperty("wrapper.version") != null; - private static final boolean _isLinuxService = !_isWin && !_isMac && - DAEMON_USER.equals(System.getProperty("user.name")); + private static final boolean _isLinuxService; private static final boolean _oneDotSix; private static final boolean _oneDotSeven; @@ -63,6 +62,8 @@ public abstract class SystemVersion { vendor.startsWith("Free Software Foundation"); // gij String runtime = System.getProperty("java.runtime.name"); _isOpenJDK = runtime != null && runtime.contains("OpenJDK"); + _isLinuxService = !_isWin && !_isMac && !_isAndroid && + DAEMON_USER.equals(System.getProperty("user.name")); int sdk = 0; if (_isAndroid) { diff --git a/history.txt b/history.txt index 0c3a302a71ecec89e847d5898de2df05b5089edf..77bf74c33c1258d60579e325553805880af7c75e 100644 --- a/history.txt +++ b/history.txt @@ -1,3 +1,69 @@ +2016-11-16 zzz + * Console: Remove dead home page links (ticket #1882) + * Profiles: Pull same-IP detection into a utility class + * Router: Add methods to verify and track members of our family + +2016-11-15 zzz + * Certs: Add Let's Encrypt ISRG Root X1 cert + +2016-11-14 zzz + * Logs: Fix output of dup message after 30 minutes + +2016-11-13 zzz + * Console: Add initial news to bottom of news page (ticket #1153) + * i2psnark: Periodically DHT nodes (ticket #1328) + * UPnP: + - Prevent exception on bad HTTP header (ticket #1480) + - Prevent NPE on socket creation fail (tickets #728, #1681) + +2016-11-12 zzz + * Console: + - Fix inadvertent config save when clicking sidebar + buttons on /configstats + - Add IPv6 firewalled setting on /confignet + * I2CP: Reduce error level on session closed while signing LS (ticket #1606) + * JRobin: Move DeallocationHelper logging from wrapper log to router log + * Profiles: Periodically save, delete old ones after saving (ticket #1328) + * Susimail: + - Add logout button to more pages (ticket #1374) + - Fix nonce error on login after logout + - Fix internal error after cancel button on settings form when not logged in + +2016-11-11 zzz + * Build: Truncate history.txt bundled in installers + +2016-11-10 zzz + * Transport: Use NTCP for some outbound connections even before + SSU minimums are met (ticket #1835) + +2016-11-09 zzz + * Transport: Add stats for inbound v4/v6 connections (ticket #1854) + * Tunnels: Reduce default VTBM records from 5 to 4 + +2016-11-08 zzz + * Build: Fix minimum Java version for Windows + * Install: Add max memory option to runplain.sh + * Crypto: Change serial number in selfsigned certs from int to long + * Router: Fix low-memory log messages for non-wrapper (ticket #1795) + * Transport: Improve IPv6 selection logic + +2016-11-06 zzz + * Console: Add Java 9 log warning (ticket #1870) + * Security: Consistently log authentication failures for all interfaces + * Util: Consolidate linux service detection code + +2016-11-05 zzz + * Build: Add support for using libtomcat8-java package + * Console: Add message to ignore InstanceManager warning (ticket #1818) + * SusiDNS: Fix jsp EL syntax error with EL 3.0 (Tomcat 8) (ticket #1870) + +2016-11-04 zzz + * Console: Improve handling and logging of webapps that fail to start + * i2psnark: Add launch-i2psnark.bat (ticket #1871) + * Transports: + - New config i2np.allowLocal, fixes test networks (ticket #1875) + - New configs i2np.udp.minpeers and i2np.udp.minv6peers, for testing (ticket #1876) + 2016-10-29 zzz * Console: Java 9 fixes for classloader (ticket #1870) @@ -47,7 +113,7 @@ * Console: Fix HTML error on /configservice * Debian: Update package descriptions, allow Java 9 * i2psnark: Add ids to rows, add to per-torrent show peers link - * SSU: Fix minimum version check for IPv6 peer test (ticket #1861) + * SSU: Fix minimum version check for IPv6 peer test (tickets #1829, #1861) * 2016-10-17 0.9.27 released diff --git a/installer/i2pinstaller.xml b/installer/i2pinstaller.xml index 84edded227a89180f3480ccc8412e2617e97fda1..62912b8284081aa27c0953fb43ba61303018be41 100644 --- a/installer/i2pinstaller.xml +++ b/installer/i2pinstaller.xml @@ -7,7 +7,7 @@ <customProcName>false</customProcName> <icon>resources/console.ico</icon> <jre> - <minVersion>1.6.0</minVersion> + <minVersion>1.7.0</minVersion> </jre> <!-- <splash> diff --git a/installer/i2pstandalone.xml b/installer/i2pstandalone.xml index 8b92ed21eeb1d0895cdf83de34e35d694aae03fc..71e338dd922ca913a852fe8d7799ebc75b4f2e68 100644 --- a/installer/i2pstandalone.xml +++ b/installer/i2pstandalone.xml @@ -7,7 +7,7 @@ <customProcName>false</customProcName> <icon>resources/start.ico</icon> <jre> - <minVersion>1.6.0</minVersion> + <minVersion>1.7.0</minVersion> <!-- <minHeapSize>64</minHeapSize> --> diff --git a/installer/java/build.xml b/installer/java/build.xml index f0caf6b8610222a1f6c04477548422f06b530345..e73ff9036eaea4fd1d2e7716b6b4ce35e7a56a51 100644 --- a/installer/java/build.xml +++ b/installer/java/build.xml @@ -57,6 +57,8 @@ <attribute name="Build-Date" value="${build.timestamp}" /> <attribute name="Base-Revision" value="${workspace.version}" /> <attribute name="Workspace-Changes" value="${workspace.changes.util.tr}" /> + <attribute name="X-Compile-Source-JDK" value="${javac.version}" /> + <attribute name="X-Compile-Target-JDK" value="${javac.version}" /> </manifest> </jar> </target> diff --git a/installer/resources/blocklist.txt b/installer/resources/blocklist.txt index fa05f88bfe4a8e1ae4b07822ccd0d7176615c420..74e7e01ffff380fb178b9c01fa370ddd2ccc9ca9 100644 --- a/installer/resources/blocklist.txt +++ b/installer/resources/blocklist.txt @@ -45,6 +45,10 @@ # * hostname (DNS looked up at list readin time, not dynamically, so may not be much use) # * 44-byte Base64 router hash # * +# * Acceptable formats (IPV6 only): +# * comment:IPv6 (must replace : with ; e.g. abcd;1234;0;12;;ff) +# * IPv6 (must replace : with ; e.g. abcd;1234;0;12;;ff) +# * # * No whitespace allowed after the last ':'. # * # * For further information and downloads: diff --git a/installer/resources/certificates/ssl/isrgrootx1.crt b/installer/resources/certificates/ssl/isrgrootx1.crt new file mode 100644 index 0000000000000000000000000000000000000000..9548dc1bf6f4423bec47e315927e687e47a44117 --- /dev/null +++ b/installer/resources/certificates/ssl/isrgrootx1.crt @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 +WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu +ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY +MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc +h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ +0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U +A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW +T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH +B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC +B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv +KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn +OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn +jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw +qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI +rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq +hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL +ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ +3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK +NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 +ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur +TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC +jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc +oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq +4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA +mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d +emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= +-----END CERTIFICATE----- diff --git a/installer/resources/runplain.sh b/installer/resources/runplain.sh index f1bf81d81034306dfef0e6b0d4bb5887f7e7cce5..eb4995dfed45a1aaf4c86c31591b6fcf0a0de262 100644 --- a/installer/resources/runplain.sh +++ b/installer/resources/runplain.sh @@ -3,7 +3,7 @@ # This runs the router by itself, WITHOUT the wrapper. # This means the router will not restart if it crashes. # Also, you will be using the default memory size, which is -# probably not enough for i2p. +# probably not enough for i2p, unless you set it below. # You should really use the i2prouter script instead. # @@ -19,6 +19,10 @@ I2PTEMP="%SYSTEM_java_io_tmpdir" PREFERv4="false" CP= +# Uncomment to set the maximum memory. The default and the option may vary in different JVMs. +# Check your java documentation to be sure. +#MAXMEMOPT="-Xmx256m" + # Try using the Java binary that I2P was installed with. # If it's not found, try looking in the system PATH. JAVA=$(which %JAVA_HOME/bin/java || which java) @@ -39,7 +43,7 @@ done if [ $(uname -s) = "Darwin" ]; then export JAVA_TOOL_OPTIONS="-Djava.awt.headless=true" fi -JAVAOPTS="-Djava.net.preferIPv4Stack=${PREFERv4} -Djava.library.path=${I2P}:${I2P}/lib -Di2p.dir.base=${I2P} -DloggerFilenameOverride=logs/log-router-@.txt" +JAVAOPTS="${MAXMEMOPT} -Djava.net.preferIPv4Stack=${PREFERv4} -Djava.library.path=${I2P}:${I2P}/lib -Di2p.dir.base=${I2P} -DloggerFilenameOverride=logs/log-router-@.txt" ( nohup ${JAVA} -cp \"${CP}\" ${JAVAOPTS} net.i2p.router.RouterLaunch > /dev/null 2>&1 ) & diff --git a/installer/tools/java/build.xml b/installer/tools/java/build.xml index c7dff1b4e9cf3b28956732c2ef2368ebdd37d94d..40d8514a77570e640227ede7ae38bc3463649c50 100644 --- a/installer/tools/java/build.xml +++ b/installer/tools/java/build.xml @@ -38,6 +38,8 @@ <attribute name="Built-By" value="${build.built-by}" /> <attribute name="Build-Date" value="${build.timestamp}" /> <attribute name="Base-Revision" value="${workspace.version}" /> + <attribute name="X-Compile-Source-JDK" value="${javac.version}" /> + <attribute name="X-Compile-Target-JDK" value="${javac.version}" /> </manifest> </jar> </target> diff --git a/router/java/build.xml b/router/java/build.xml index fb2493089386d68efb39b0385f69cb653bdda360..1f42e4cd102b2f685d34aa02c5cd9249421a731b 100644 --- a/router/java/build.xml +++ b/router/java/build.xml @@ -78,6 +78,8 @@ <attribute name="Base-Revision" value="${workspace.version}" /> <attribute name="Main-Class" value="net.i2p.router.CommandLine" /> <attribute name="Workspace-Changes" value="${workspace.changes.tr}" /> + <attribute name="X-Compile-Source-JDK" value="${javac.version}" /> + <attribute name="X-Compile-Target-JDK" value="${javac.version}" /> </manifest> </jar> </target> diff --git a/router/java/src/net/i2p/router/Blocklist.java b/router/java/src/net/i2p/router/Blocklist.java index 3ad8e7387507513ea489f484f8d5d2d3595cc5b1..9799ae443d5a7b0129517707a75b924e74c86ecc 100644 --- a/router/java/src/net/i2p/router/Blocklist.java +++ b/router/java/src/net/i2p/router/Blocklist.java @@ -248,6 +248,10 @@ public class Blocklist { * hostname (DNS looked up at list readin time, not dynamically, so may not be much use) * 44-byte Base64 router hash * + * Acceptable formats (IPV6 only): + * comment:IPv6 (must replace : with ; e.g. abcd;1234;0;12;;ff) + * IPv6 (must replace : with ; e.g. abcd;1234;0;12;;ff) + * * No whitespace allowed after the last ':'. * * For further information and downloads: @@ -290,10 +294,14 @@ public class Blocklist { continue; } byte[] ip1 = e.ip1; - byte[] ip2 = e.ip2; - - store(ip1, ip2, count++); - ipcount += 1 + toInt(ip2) - toInt(ip1); // includes dups, oh well + if (ip1.length == 4) { + byte[] ip2 = e.ip2; + store(ip1, ip2, count++); + ipcount += 1 + toInt(ip2) - toInt(ip1); // includes dups, oh well + } else { + // IPv6 + add(ip1); + } } } catch (IOException ioe) { if (_log.shouldLog(Log.ERROR)) @@ -393,25 +401,25 @@ public class Blocklist { int start2 = -1; int mask = -1; String comment = null; - int index = buf.indexOf("#"); + int index = buf.indexOf('#'); if (index == 0) return null; // comment - index = buf.lastIndexOf(":"); + index = buf.lastIndexOf(':'); if (index >= 0) { comment = buf.substring(0, index); start1 = index + 1; } - if (end1 - start1 == 44 && buf.substring(start1).indexOf(".") < 0) { + if (end1 - start1 == 44 && buf.substring(start1).indexOf('.') < 0) { byte b[] = Base64.decode(buf.substring(start1)); if (b != null) return new Entry(comment, Hash.create(b), null, null); } - index = buf.indexOf("-", start1); + index = buf.indexOf('-', start1); if (index >= 0) { end1 = index; start2 = index + 1; } else { - index = buf.indexOf("/", start1); + index = buf.indexOf('/', start1); if (index >= 0) { end1 = index; mask = index + 1; @@ -420,11 +428,14 @@ public class Blocklist { if (end1 - start1 <= 0) return null; // blank try { - InetAddress pi = InetAddress.getByName(buf.substring(start1, end1)); + String sip = buf.substring(start1, end1); + // IPv6 + sip = sip.replace(';', ':'); + InetAddress pi = InetAddress.getByName(sip); if (pi == null) return null; ip1 = pi.getAddress(); - if (ip1.length != 4) - throw new UnknownHostException(); + //if (ip1.length != 4) + // throw new UnknownHostException(); if (start2 >= 0) { pi = InetAddress.getByName(buf.substring(start2)); if (pi == null) return null; @@ -462,16 +473,16 @@ public class Blocklist { ip2 = ip1; } } catch (UnknownHostException uhe) { - if (shouldLog && _log.shouldLog(Log.ERROR)) - _log.error("Format error in the blocklist file: " + buf); + if (shouldLog) + _log.logAlways(Log.WARN, "Format error in the blocklist file: " + buf); return null; } catch (NumberFormatException nfe) { - if (shouldLog && _log.shouldLog(Log.ERROR)) - _log.error("Format error in the blocklist file: " + buf); + if (shouldLog) + _log.logAlways(Log.WARN, "Format error in the blocklist file: " + buf); return null; } catch (IndexOutOfBoundsException ioobe) { - if (shouldLog && _log.shouldLog(Log.ERROR)) - _log.error("Format error in the blocklist file: " + buf); + if (shouldLog) + _log.logAlways(Log.WARN, "Format error in the blocklist file: " + buf); return null; } return new Entry(comment, null, ip1, ip2); @@ -743,6 +754,9 @@ public class Blocklist { return entry; } + /** + * IPv4 only + */ private void store(byte ip1[], byte ip2[], int idx) { _blocklist[idx] = toEntry(ip1, ip2); } @@ -1035,10 +1049,16 @@ public class Blocklist { } /**** - public static void main(String args[]) { - Blocklist b = new Blocklist(); - if ( (args != null) && (args.length == 1) ) - b.readBlocklistFile(args[0]); + public static void main(String args[]) throws Exception { + Blocklist b = new Blocklist(new Router().getContext()); + if (args != null && args.length == 1) { + File f = new File(args[0]); + b.allocate(Collections.singletonList(f)); + int count = b.readBlocklistFile(f, 0); + b.merge(count); + Writer w = new java.io.OutputStreamWriter(System.out); + b.renderStatusHTML(w); + } System.out.println("Saved " + b._blocklistSize + " records"); String tests[] = {"0.0.0.0", "0.0.0.1", "0.0.0.2", "0.0.0.255", "1.0.0.0", "3.3.3.3", "77.1.2.3", "127.0.0.0", "127.127.127.127", "128.0.0.0", diff --git a/router/java/src/net/i2p/router/CommandLine.java b/router/java/src/net/i2p/router/CommandLine.java index 8a3986d86dd779f44b2d82f891396b22eed9a8ac..c3af8d7381c085b96e9bf4c449308d5d57cb83b3 100644 --- a/router/java/src/net/i2p/router/CommandLine.java +++ b/router/java/src/net/i2p/router/CommandLine.java @@ -23,7 +23,7 @@ public class CommandLine extends net.i2p.util.CommandLine { "net.i2p.router.tasks.CryptoChecker", "net.i2p.router.transport.GeoIPv6", "net.i2p.router.transport.udp.MTU", - //"net.i2p.router.transport.UPnP" + "net.i2p.router.transport.UPnP" }); protected CommandLine() {} diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index c10128fe6223a59f4fa2320e38c3309487438a87..f2522cd4ed540000a936a603d4922f4a287ece1f 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -18,7 +18,7 @@ public class RouterVersion { /** deprecated */ public final static String ID = "Monotone"; public final static String VERSION = CoreVersion.VERSION; - public final static long BUILD = 6; + public final static long BUILD = 9; /** for example "-test" */ public final static String EXTRA = ""; diff --git a/router/java/src/net/i2p/router/client/ClientMessageEventListener.java b/router/java/src/net/i2p/router/client/ClientMessageEventListener.java index a50a6c9bce0ca68df89775f16516febbb57f75ed..b6893b59c0922a9ca95b8dc32e5a701a99031615 100644 --- a/router/java/src/net/i2p/router/client/ClientMessageEventListener.java +++ b/router/java/src/net/i2p/router/client/ClientMessageEventListener.java @@ -329,14 +329,14 @@ class ClientMessageEventListener implements I2CPMessageReader.I2CPMessageEventLi pw = props.getProperty("i2cp.password"); } if (user == null || user.length() == 0 || pw == null || pw.length() == 0) { - _log.error("I2CP auth failed"); + _log.logAlways(Log.WARN, "I2CP authentication failed"); _runner.disconnectClient("Authorization required, specify i2cp.username and i2cp.password in options"); _authorized = false; return false; } PasswordManager mgr = new PasswordManager(_context); if (!mgr.checkHash(PROP_AUTH, user, pw)) { - _log.error("I2CP auth failed user: " + user); + _log.logAlways(Log.WARN, "I2CP authentication failed, user: " + user); _runner.disconnectClient("Authorization failed, user = " + user); _authorized = false; return false; diff --git a/router/java/src/net/i2p/router/crypto/FamilyKeyCrypto.java b/router/java/src/net/i2p/router/crypto/FamilyKeyCrypto.java index cdb0811dc7b52a7d83cfaeaf1a84e1ea81e29ea4..f1bfe2063a316196cb20003015fee061ebde2ce9 100644 --- a/router/java/src/net/i2p/router/crypto/FamilyKeyCrypto.java +++ b/router/java/src/net/i2p/router/crypto/FamilyKeyCrypto.java @@ -10,6 +10,7 @@ import java.security.PrivateKey; import java.security.PublicKey; import java.security.cert.X509Certificate; import java.security.cert.X509CRL; +import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Set; @@ -44,6 +45,7 @@ public class FamilyKeyCrypto { private final Log _log; private final Map<Hash, String> _verified; private final Set<Hash> _negativeCache; + private final Set<Hash> _ourFamily; // following for verification only, otherwise null private final String _fname; private final SigningPrivateKey _privkey; @@ -82,13 +84,15 @@ public class FamilyKeyCrypto { _fname = _context.getProperty(PROP_FAMILY_NAME); if (_fname != null) { if (_fname.contains("/") || _fname.contains("\\") || - _fname.contains("..") || (new File(_fname)).isAbsolute()) - throw new GeneralSecurityException("Illegal family name"); + _fname.contains("..") || (new File(_fname)).isAbsolute() || + _fname.length() <= 0) + throw new GeneralSecurityException("Illegal family name: " + _fname); } _privkey = (_fname != null) ? initialize() : null; _pubkey = (_privkey != null) ? _privkey.toPublic() : null; _verified = new ConcurrentHashMap<Hash, String>(4); _negativeCache = new ConcurrentHashSet<Hash>(4); + _ourFamily = (_privkey != null) ? new ConcurrentHashSet<Hash>(4) : Collections.<Hash>emptySet(); } /** @@ -144,6 +148,35 @@ public class FamilyKeyCrypto { return rv; } + /** + * Do we have a valid family? + * @since 0.9.28 + */ + public boolean hasFamily() { + return _pubkey != null; + } + + /** + * Get verified members of our family. + * Will not contain ourselves. + * + * @return non-null, not a copy, do not modify + * @since 0.9.28 + */ + public Set<Hash> getOurFamily() { + return _ourFamily; + } + + /** + * Get our family name. + * + * @return name or null + * @since 0.9.28 + */ + public String getOurFamilyName() { + return _fname; + } + /** * Verify the family signature in a RouterInfo. * @return true if good sig or if no family specified at all @@ -152,6 +185,44 @@ public class FamilyKeyCrypto { String name = ri.getOption(OPT_NAME); if (name == null) return true; + return verify(ri, name); + } + + /** + * Verify the family in a RouterInfo matches ours and the signature is good. + * Returns false if we don't have a family and sig, or they don't. + * Returns false for ourselves. + * + * @return true if family matches with good sig + * @since 0.9.28 + */ + public boolean verifyOurFamily(RouterInfo ri) { + if (_pubkey == null) + return false; + String name = ri.getOption(OPT_NAME); + if (!_fname.equals(name)) + return false; + Hash h = ri.getHash(); + if (_ourFamily.contains(h)) + return true; + if (h.equals(_context.routerHash())) + return false; + boolean rv = verify(ri, name); + if (rv) { + _ourFamily.add(h); + _log.logAlways(Log.INFO, "Found and verified member of our family (" + _fname + "): " + h); + } else { + if (_log.shouldWarn()) + _log.warn("Found spoofed member of our family (" + _fname + "): " + h); + } + return rv; + } + + /** + * Verify the family in a RouterInfo, name already retrieved + * @since 0.9.28 + */ + private boolean verify(RouterInfo ri, String name) { Hash h = ri.getHash(); String ssig = ri.getOption(OPT_SIG); if (ssig == null) { diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillVerifyStoreJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillVerifyStoreJob.java index 9ffda0201e34912afc0e9a4a2e3459e09328436d..d0f94131ccb1d700cabc47282eeda97ec20c0829 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillVerifyStoreJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillVerifyStoreJob.java @@ -19,6 +19,7 @@ import net.i2p.router.MessageSelector; import net.i2p.router.ReplyJob; import net.i2p.router.RouterContext; import net.i2p.router.TunnelInfo; +import net.i2p.router.util.MaskedIPSet; import net.i2p.util.Log; /** @@ -39,11 +40,13 @@ class FloodfillVerifyStoreJob extends JobImpl { private final boolean _isRouterInfo; private MessageWrapper.WrappedMessage _wrappedMessage; private final Set<Hash> _ignore; + private final MaskedIPSet _ipSet; private static final int START_DELAY = 18*1000; private static final int START_DELAY_RAND = 9*1000; private static final int VERIFY_TIMEOUT = 20*1000; private static final int MAX_PEERS_TO_TRY = 4; + private static final int IP_CLOSE_BYTES = 3; /** * Delay a few seconds, then start the verify @@ -60,7 +63,10 @@ class FloodfillVerifyStoreJob extends JobImpl { _facade = facade; _ignore = new HashSet<Hash>(MAX_PEERS_TO_TRY); if (sentTo != null) { + _ipSet = new MaskedIPSet(ctx, sentTo, IP_CLOSE_BYTES); _ignore.add(_sentTo); + } else { + _ipSet = new MaskedIPSet(4); } // wait some time before trying to verify the store getTiming().setStartAfter(ctx.clock().now() + START_DELAY + ctx.random().nextInt(START_DELAY_RAND)); @@ -188,10 +194,19 @@ class FloodfillVerifyStoreJob extends JobImpl { break; Hash peer = peers.get(0); RouterInfo ri = _facade.lookupRouterInfoLocally(peer); - if (ri != null && StoreJob.supportsCert(ri, keyCert)) - return peer; - if (_log.shouldLog(Log.INFO)) - _log.info(getJobId() + ": Skipping verify w/ router that doesn't support key certs " + peer); + if (ri != null && StoreJob.supportsCert(ri, keyCert)) { + Set<String> peerIPs = new MaskedIPSet(getContext(), ri, IP_CLOSE_BYTES); + if (!_ipSet.containsAny(peerIPs)) { + _ipSet.addAll(peerIPs); + return peer; + } else { + if (_log.shouldLog(Log.INFO)) + _log.info(getJobId() + ": Skipping verify w/ router too close to the store " + peer); + } + } else { + if (_log.shouldLog(Log.INFO)) + _log.info(getJobId() + ": Skipping verify w/ router that doesn't support key certs " + peer); + } _ignore.add(peer); } } else { diff --git a/router/java/src/net/i2p/router/peermanager/PeerManager.java b/router/java/src/net/i2p/router/peermanager/PeerManager.java index b3cc3643b029881c435b6239de036407b15525c9..362c67b5a7a7f8fc5a02fadd0884053099173fca 100644 --- a/router/java/src/net/i2p/router/peermanager/PeerManager.java +++ b/router/java/src/net/i2p/router/peermanager/PeerManager.java @@ -17,6 +17,7 @@ import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; import net.i2p.data.Hash; import net.i2p.data.router.RouterInfo; @@ -43,6 +44,9 @@ class PeerManager { private final Map<Character, Set<Hash>> _peersByCapability; /** value strings are lower case */ private final Map<Hash, String> _capabilitiesByPeer; + private final AtomicBoolean _storeLock = new AtomicBoolean(); + private volatile long _lastStore; + private static final long REORGANIZE_TIME = 45*1000; private static final long REORGANIZE_TIME_MEDIUM = 123*1000; /** @@ -52,6 +56,8 @@ class PeerManager { * Rate contained in the profile, as the Rates must be coalesced. */ private static final long REORGANIZE_TIME_LONG = 351*1000; + private static final long STORE_TIME = 19*60*60*1000; + private static final long EXPIRE_AGE = 3*24*60*60*1000; public static final String TRACKED_CAPS = "" + FloodfillNetworkDatabaseFacade.CAPABILITY_FLOODFILL + @@ -97,11 +103,14 @@ class PeerManager { } /** + * Reorganize the profiles. Also periodically store them, + * and delete very old ones. + * * This takes too long to run on the SimpleTimer2 queue * @since 0.9.10 */ private class ReorgThread extends I2PThread { - private SimpleTimer2.TimedEvent _event; + private final SimpleTimer2.TimedEvent _event; public ReorgThread(SimpleTimer2.TimedEvent event) { super("PeerManager Reorg"); @@ -117,6 +126,19 @@ class PeerManager { _log.log(Log.CRIT, "Error evaluating profiles", t); } long orgtime = System.currentTimeMillis() - start; + if (_lastStore == 0) { + _lastStore = start; + } else if (start - _lastStore > STORE_TIME) { + _lastStore = start; + try { + _log.debug("Periodic profile store start"); + storeProfiles(); + _persistenceHelper.deleteOldProfiles(EXPIRE_AGE); + _log.debug("Periodic profile store end"); + } catch (Throwable t) { + _log.log(Log.CRIT, "Error storing profiles", t); + } + } long uptime = _context.router().getUptime(); long delay; if (orgtime > 1000 || uptime > 2*60*60*1000) @@ -130,9 +152,16 @@ class PeerManager { } void storeProfiles() { - Set<Hash> peers = selectPeers(); - for (Hash peer : peers) { - storeProfile(peer); + // lock in case shutdown bumps into periodic store + if (!_storeLock.compareAndSet(false, true)) + return; + try { + Set<Hash> peers = selectPeers(); + for (Hash peer : peers) { + storeProfile(peer); + } + } finally { + _storeLock.set(false); } } diff --git a/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java b/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java index c71f8b6a65fdfdc05b5e9c6e14099d45cf8e0a00..481cc18b626f701675e1f8013156115eb7ed0d5f 100644 --- a/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java +++ b/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java @@ -24,6 +24,7 @@ import net.i2p.data.router.RouterInfo; import net.i2p.router.NetworkDatabaseFacade; import net.i2p.router.RouterContext; import net.i2p.router.tunnel.pool.TunnelPeerSelector; +import net.i2p.router.util.MaskedIPSet; import net.i2p.router.util.RandomIterator; import net.i2p.stat.Rate; import net.i2p.stat.RateStat; @@ -1245,7 +1246,7 @@ public class ProfileOrganizer { */ private void locked_selectPeers(Map<Hash, PeerProfile> peers, int howMany, Set<Hash> toExclude, Set<Hash> matches, int mask) { List<Hash> all = new ArrayList<Hash>(peers.keySet()); - Set<String> IPSet = new HashSet<String>(8); + MaskedIPSet IPSet = new MaskedIPSet(8); // use RandomIterator to avoid shuffling the whole thing for (Iterator<Hash> iter = new RandomIterator<Hash>(all); (matches.size() < howMany) && iter.hasNext(); ) { Hash peer = iter.next(); @@ -1277,77 +1278,14 @@ public class ProfileOrganizer { * @param mask is 1-4 (number of bytes to match) * @param IPMatches all IPs so far, modified by this routine */ - private boolean notRestricted(Hash peer, Set<String> IPSet, int mask) { - Set<String> peerIPs = maskedIPSet(peer, mask); - if (containsAny(IPSet, peerIPs)) + private boolean notRestricted(Hash peer, MaskedIPSet IPSet, int mask) { + Set<String> peerIPs = new MaskedIPSet(_context, peer, mask); + if (IPSet.containsAny(peerIPs)) return false; IPSet.addAll(peerIPs); return true; } - /** - * The Set of IPs for this peer, with a given mask. - * Includes the comm system's record of the IP, and all netDb addresses. - * - * As of 0.9.24, returned set will include netdb family as well. - * - * @return an opaque set of masked IPs for this peer - */ - private Set<String> maskedIPSet(Hash peer, int mask) { - Set<String> rv = new HashSet<String>(4); - byte[] commIP = _context.commSystem().getIP(peer); - if (commIP != null) - rv.add(maskedIP(commIP, mask)); - RouterInfo pinfo = _context.netDb().lookupRouterInfoLocally(peer); - if (pinfo == null) - return rv; - Collection<RouterAddress> paddr = pinfo.getAddresses(); - for (RouterAddress pa : paddr) { - byte[] pib = pa.getIP(); - if (pib == null) continue; - rv.add(maskedIP(pib, mask)); - } - String family = pinfo.getOption("family"); - if (family != null) { - // TODO should KNDF put a family-verified indicator in the RI, - // after checking the sig, or does it matter? - // What's the threat here of not avoid ding a router - // falsely claiming to be in the family? - // Prefix with something so an IP can't be spoofed - rv.add('x' + family); - } - return rv; - } - - /** - * generate an arbitrary unique value for this ip/mask (mask = 1-4) - * If IPv6, force mask = 6. - */ - private static String maskedIP(byte[] ip, int mask) { - final StringBuilder buf = new StringBuilder(1 + (mask*2)); - final char delim; - if (ip.length == 16) { - mask = 6; - delim = ':'; - } else { - delim = '.'; - } - buf.append(delim); - buf.append(Long.toHexString(DataHelper.fromLong(ip, 0, mask))); - return buf.toString(); - } - - /** does a contain any of the elements in b? */ - private static <T> boolean containsAny(Set<T> a, Set<T> b) { - if (a.isEmpty() || b.isEmpty()) - return false; - for (T o : b) { - if (a.contains(o)) - return true; - } - return false; - } - /** * @param randomKey used for deterministic random partitioning into subtiers * @param subTierMode 2-7: diff --git a/router/java/src/net/i2p/router/peermanager/ProfilePersistenceHelper.java b/router/java/src/net/i2p/router/peermanager/ProfilePersistenceHelper.java index f978194d3867a3fec8eb02b52fc3a9c8f3a8ff32..f22bf0e3f14c5ebd3e69df5c41f595d3d7e5e05f 100644 --- a/router/java/src/net/i2p/router/peermanager/ProfilePersistenceHelper.java +++ b/router/java/src/net/i2p/router/peermanager/ProfilePersistenceHelper.java @@ -229,6 +229,26 @@ class ProfilePersistenceHelper { } } + /** + * Delete profile files with timestamps older than 'age' ago + * @since 0.9.28 + */ + public void deleteOldProfiles(long age) { + long cutoff = System.currentTimeMillis() - age; + List<File> files = selectFiles(); + int i = 0; + for (File f : files) { + if (!f.isFile()) + continue; + if (f.lastModified() < cutoff) { + i++; + f.delete(); + } + } + if (_log.shouldWarn()) + _log.warn("Deleted " + i + " old profiles"); + } + private boolean isExpired(long lastSentToSuccessfully) { long timeSince = _context.clock().now() - lastSentToSuccessfully; return (timeSince > EXPIRE_AGE); diff --git a/router/java/src/net/i2p/router/tasks/OOMListener.java b/router/java/src/net/i2p/router/tasks/OOMListener.java index 3aa2c08661367d714d5888b8b314f66dbc47e5e6..ed2050a390188919a9fbada02f54df9073b10ed8 100644 --- a/router/java/src/net/i2p/router/tasks/OOMListener.java +++ b/router/java/src/net/i2p/router/tasks/OOMListener.java @@ -49,17 +49,23 @@ public class OOMListener implements I2PThread.OOMEventListener { log.log(Log.CRIT, "Thread ran out of memory, shutting down I2P", oom); log.log(Log.CRIT, "free mem: " + Runtime.getRuntime().freeMemory() + " total mem: " + Runtime.getRuntime().totalMemory()); + // Can't find any System property or wrapper property that gives + // you the actual config file path, have to guess + String path; + if (SystemVersion.isLinuxService()) { + path = "/etc/i2p"; + } else { + path = _context.getBaseDir().toString(); + } if (_context.hasWrapper()) { - // Can't find any System property or wrapper property that gives - // you the actual config file path, have to guess - String path; - if (SystemVersion.isLinuxService()) { - path = "/etc/i2p"; - } else { - path = _context.getBaseDir().toString(); - } log.log(Log.CRIT, "To prevent future shutdowns, increase wrapper.java.maxmemory in " + path + File.separatorChar + "wrapper.config"); + } else if (!SystemVersion.isWindows()) { + log.log(Log.CRIT, "To prevent future shutdowns, increase MAXMEMOPT in " + + path + File.separatorChar + "runplain.sh or /usr/bin/i2prouter-nowrapper"); + } else { + log.log(Log.CRIT, "To prevent future shutdowns, run the restartable version of I2P, and increase wrapper.java.maxmemory in " + + path + File.separatorChar + "wrapper.config"); } } catch (OutOfMemoryError oome) {} try { diff --git a/router/java/src/net/i2p/router/transport/TransportManager.java b/router/java/src/net/i2p/router/transport/TransportManager.java index 80888ead7bf56787c6977a14b38ca1367a2dd9b2..9e6c9a953c29a27c1b7767793450abe99a057925 100644 --- a/router/java/src/net/i2p/router/transport/TransportManager.java +++ b/router/java/src/net/i2p/router/transport/TransportManager.java @@ -11,6 +11,7 @@ package net.i2p.router.transport; import java.io.IOException; import java.io.Writer; import java.net.InetAddress; +import java.net.Inet6Address; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.HashMap; @@ -165,7 +166,7 @@ public class TransportManager implements TransportEventListener { // so that NTCP may bind early int port = udp.getRequestedPort(); if (port > 0) - ntcp.externalAddressReceived(SOURCE_CONFIG, null, port); + ntcp.externalAddressReceived(SOURCE_CONFIG, (byte[]) null, port); } } if (_transports.isEmpty()) @@ -182,15 +183,52 @@ public class TransportManager implements TransportEventListener { */ private void initializeAddress(Transport t) { Set<String> ipset = Addresses.getAddresses(false, true); // non-local, include IPv6 + // + // Avoid IPv6 temporary addresses if we have a non-temporary one + // + boolean hasNonTempV6Address = false; + List<InetAddress> addresses = new ArrayList<InetAddress>(4); + List<Inet6Address> tempV6Addresses = new ArrayList<Inet6Address>(4); for (String ips : ipset) { try { - InetAddress ia = InetAddress.getByName(ips); - byte[] ip = ia.getAddress(); - t.externalAddressReceived(SOURCE_INTERFACE, ip, 0); + InetAddress addr = InetAddress.getByName(ips); + if (ips.contains(":") && (addr instanceof Inet6Address)) { + Inet6Address v6addr = (Inet6Address) addr; + // getAddresses(false, true) will not return deprecated addresses + //if (Addresses.isDeprecated(v6addr)) { + // if (_log.shouldWarn()) + // _log.warn("Not binding to deprecated temporary address " + bt); + // continue; + //} + if (Addresses.isTemporary(v6addr)) { + // Save temporary addresses + // we only use these if we don't have a non-temporary adress + tempV6Addresses.add(v6addr); + continue; + } + hasNonTempV6Address = true; + } + addresses.add(addr); } catch (UnknownHostException e) { _log.error("UDP failed to bind to local address", e); } } + // we only use these if we don't have a non-temporary adress + if (!tempV6Addresses.isEmpty()) { + if (hasNonTempV6Address) { + if (_log.shouldWarn()) { + for (Inet6Address addr : tempV6Addresses) { + _log.warn("Not binding to temporary address " + addr.getHostAddress()); + } + } + } else { + addresses.addAll(tempV6Addresses); + } + } + for (InetAddress ia : addresses) { + byte[] ip = ia.getAddress(); + t.externalAddressReceived(SOURCE_INTERFACE, ip, 0); + } } /** diff --git a/router/java/src/net/i2p/router/transport/TransportUtil.java b/router/java/src/net/i2p/router/transport/TransportUtil.java index 16ede3b34447095476c3ae04417bf1dfd8749a4a..bb4e022d6c301d0236f7e358bd8aca7a85499a88 100644 --- a/router/java/src/net/i2p/router/transport/TransportUtil.java +++ b/router/java/src/net/i2p/router/transport/TransportUtil.java @@ -25,6 +25,8 @@ public abstract class TransportUtil { public static final String NTCP_IPV6_CONFIG = "i2np.ntcp.ipv6"; public static final String SSU_IPV6_CONFIG = "i2np.udp.ipv6"; public static final String PROP_IPV4_FIREWALLED = "i2np.ipv4.firewalled"; + /** @since 0.9.28 */ + public static final String PROP_IPV6_FIREWALLED = "i2np.ipv6.firewalled"; public enum IPv6Config { /** IPv6 disabled */ @@ -99,12 +101,10 @@ public abstract class TransportUtil { * This returns true if the force-firewalled setting is configured, false otherwise. * * @param transportStyle ignored - * @since 0.9.27 + * @since 0.9.27, implemented in 0.9.28 */ public static boolean isIPv6Firewalled(RouterContext ctx, String transportStyle) { - // TODO - //return ctx.getBooleanProperty(PROP_IPV6_FIREWALLED); - return false; + return ctx.getBooleanProperty(PROP_IPV6_FIREWALLED); } /** diff --git a/router/java/src/net/i2p/router/transport/UPnP.java b/router/java/src/net/i2p/router/transport/UPnP.java index 1f30c768c1e3b34718853707d054187743a05386..52637cec9603ee78f7fd480c97a99e51138925b5 100644 --- a/router/java/src/net/i2p/router/transport/UPnP.java +++ b/router/java/src/net/i2p/router/transport/UPnP.java @@ -58,6 +58,8 @@ import org.freenetproject.ForwardPortStatus; * * some code has been borrowed from Limewire : @see com.limegroup.gnutella.UPnPManager * + * Public only for command line usage. Not a public API, not for external use. + * * @see "http://www.upnp.org/" * @see "http://en.wikipedia.org/wiki/Universal_Plug_and_Play" * @since 0.7.4 @@ -68,7 +70,7 @@ import org.freenetproject.ForwardPortStatus; * TODO: Advertise the node like the MDNS plugin does * TODO: Implement EventListener and react on ip-change */ -class UPnP extends ControlPoint implements DeviceChangeListener, EventListener { +public class UPnP extends ControlPoint implements DeviceChangeListener, EventListener { private final Log _log; private final I2PAppContext _context; diff --git a/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java b/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java index 13cba50f59162372fe3392df3883992e6f8ae447..90138313b8dad6eca4302a298a24aa31c1bf0e9c 100644 --- a/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java +++ b/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java @@ -150,6 +150,8 @@ public class NTCPTransport extends TransportImpl { //_context.statManager().createRateStat("ntcp.inboundCheckConnection", "", "ntcp", RATES); _context.statManager().createRateStat("ntcp.inboundEstablished", "", "ntcp", RATES); _context.statManager().createRateStat("ntcp.inboundEstablishedDuplicate", "", "ntcp", RATES); + _context.statManager().createRateStat("ntcp.inboundIPv4Conn", "Inbound IPv4 NTCP Connection", "ntcp", RATES); + _context.statManager().createRateStat("ntcp.inboundIPv6Conn", "Inbound IPv6 NTCP Connection", "ntcp", RATES); //_context.statManager().createRateStat("ntcp.infoMessageEnqueued", "", "ntcp", RATES); //_context.statManager().createRateStat("ntcp.floodInfoMessageEnqueued", "", "ntcp", RATES); _context.statManager().createRateStat("ntcp.invalidDH", "", "ntcp", RATES); @@ -213,10 +215,13 @@ public class NTCPTransport extends TransportImpl { synchronized (_conLock) { old = _conByIdent.put(peer, con); } - if (con.isIPv6()) + if (con.isIPv6()) { _lastInboundIPv6 = con.getCreated(); - else + _context.statManager().addRateData("ntcp.inboundIPv6Conn", 1); + } else { _lastInboundIPv4 = con.getCreated(); + _context.statManager().addRateData("ntcp.inboundIPv4Conn", 1); + } return old; } diff --git a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java index 064e1497ad5afaa42b64ca699c518751ee847dcb..5686a4aa8e7898662666f5c04b7fec47c65d0e14 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java @@ -289,6 +289,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority _context.statManager().createRateStat("udp.proactiveReestablish", "How long a session was idle for when we proactively reestablished it", "udp", RATES); _context.statManager().createRateStat("udp.dropPeerDroplist", "How many peers currently have their packets dropped outright when a new peer is added to the list?", "udp", RATES); _context.statManager().createRateStat("udp.dropPeerConsecutiveFailures", "How many consecutive failed sends to a peer did we attempt before giving up and reestablishing a new session (lifetime is inactivity perood)", "udp", RATES); + _context.statManager().createRateStat("udp.inboundIPv4Conn", "Inbound IPv4 UDP Connection", "udp", RATES); + _context.statManager().createRateStat("udp.inboundIPv6Conn", "Inbound IPv4 UDP Connection", "udp", RATES); // following are for PacketBuider //_context.statManager().createRateStat("udp.packetAuthTime", "How long it takes to encrypt and MAC a packet for sending", "udp", RATES); //_context.statManager().createRateStat("udp.packetAuthTimeSlow", "How long it takes to encrypt and MAC a packet for sending (when its slow)", "udp", RATES); @@ -780,6 +782,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority void inboundConnectionReceived(boolean isIPv6) { if (isIPv6) { _lastInboundIPv6 = _context.clock().now(); + _context.statManager().addRateData("udp.inboundIPv6Conn", 1); // former workaround for lack of IPv6 peer testing //if (_currentOurV6Address != null) // setReachabilityStatus(Status.IPV4_UNKNOWN_IPV6_OK, true); @@ -788,6 +791,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority // that we are not firewalled. // use OS clock since its an ordering thing, not a time thing _lastInboundReceivedOn = System.currentTimeMillis(); + _context.statManager().addRateData("udp.inboundIPv4Conn", 1); } } @@ -1765,13 +1769,23 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority // (Otherwise we only talk UDP to those that are firewalled, and we will // never get any introducers) int count = _peersByIdent.size(); - if (alwaysPreferUDP() || count < _min_peers || - (_haveIPv6Address && count < _min_v6_peers) || - (introducersRequired() && _introManager.introducerCount() < MIN_INTRODUCER_POOL)) + if (alwaysPreferUDP()) { return _cachedBid[SLOW_PREFERRED_BID]; - else if (preferUDP()) + } else if (count < _min_peers || + (_haveIPv6Address && count < _min_v6_peers) || + (introducersRequired() && _introManager.introducerCount() < MIN_INTRODUCER_POOL)) { + // Even if we haven't hit our minimums, give NTCP a chance some of the time. + // This may make things work a little faster at startup + // (especially when we have an IPv6 address and the increased minimums), + // and if UDP is completely blocked we'll still have some connectivity. + // TODO After some time, decide that UDP is blocked/broken and return TRANSIENT_FAIL_BID? + if (_context.random().nextInt(4) == 0) + return _cachedBid[SLOWEST_BID]; + else + return _cachedBid[SLOW_PREFERRED_BID]; + } else if (preferUDP()) { return _cachedBid[SLOW_BID]; - else if (haveCapacity()) { + } else if (haveCapacity()) { if (addr.getCost() > DEFAULT_COST) return _cachedBid[SLOWEST_COST_BID]; else diff --git a/router/java/src/net/i2p/router/tunnel/BloomFilterIVValidator.java b/router/java/src/net/i2p/router/tunnel/BloomFilterIVValidator.java index f96bdfece26e5622b063151fc24323fb402cd8f4..61a52e2a356effdb07349975a9944d2a08918001 100644 --- a/router/java/src/net/i2p/router/tunnel/BloomFilterIVValidator.java +++ b/router/java/src/net/i2p/router/tunnel/BloomFilterIVValidator.java @@ -104,7 +104,6 @@ class BloomFilterIVValidator implements IVValidator { return; // Can't find any System property or wrapper property that gives // you the actual config file path, have to guess - // TODO if !SystemVersion.hasWrapper ... String path; if (SystemVersion.isLinuxService()) { path = "/etc/i2p"; @@ -114,13 +113,21 @@ class BloomFilterIVValidator implements IVValidator { String msg = "Configured for " + DataHelper.formatSize(KBps *1024L) + "Bps share bandwidth but only " + - DataHelper.formatSize(maxMemory) + "B available memory." + - " Recommend increasing wrapper.java.maxmemory in " + - path + File.separatorChar + "wrapper.config" + - // getMaxMemory() returns significantly lower than wrapper config, so add 10% - " to at least " + (recMaxMem * 11 / 10 / (1024*1024)) + " (MB)" + - " if the actual share bandwidth exceeds " + - DataHelper.formatSize(threshKBps * 1024L) + "Bps."; + DataHelper.formatSize(maxMemory) + "B available memory."; + if (_context.hasWrapper()) { + msg += " Recommend increasing wrapper.java.maxmemory in " + + path + File.separatorChar + "wrapper.config"; + } else if (!SystemVersion.isWindows()) { + msg += " Recommend increasing MAXMEMOPT in " + + path + File.separatorChar + "runplain.sh or /usr/bin/i2prouter-nowrapper"; + } else { + msg += " Recommend running the restartable version of I2P, and increasing wrapper.java.maxmemory in " + + path + File.separatorChar + "wrapper.config"; + } + // getMaxMemory() returns significantly lower than wrapper config, so add 10% + msg += " to at least " + (recMaxMem * 11 / 10 / (1024*1024)) + " (MB)" + + " if the actual share bandwidth exceeds " + + DataHelper.formatSize(threshKBps * 1024L) + "Bps."; System.out.println("WARN: " + msg); _context.logManager().getLog(BloomFilterIVValidator.class).logAlways(Log.WARN, msg); } diff --git a/router/java/src/net/i2p/router/tunnel/pool/BuildRequestor.java b/router/java/src/net/i2p/router/tunnel/pool/BuildRequestor.java index 15c90b092ca21390e2ed24026097e25f5c173c69..ca3caa1b7185734e716c978f553c8afe8cdd0fde 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/BuildRequestor.java +++ b/router/java/src/net/i2p/router/tunnel/pool/BuildRequestor.java @@ -25,9 +25,23 @@ import net.i2p.util.VersionComparator; */ abstract class BuildRequestor { private static final List<Integer> ORDER = new ArrayList<Integer>(TunnelBuildMessage.MAX_RECORD_COUNT); + private static final String MIN_VARIABLE_VERSION = "0.7.12"; + private static final boolean SEND_VARIABLE = true; + private static final int SHORT_RECORDS = 4; + private static final List<Integer> SHORT_ORDER = new ArrayList<Integer>(SHORT_RECORDS); + /** 5 (~2600 bytes) fits nicely in 3 tunnel messages */ + private static final int MEDIUM_RECORDS = 5; + private static final List<Integer> MEDIUM_ORDER = new ArrayList<Integer>(MEDIUM_RECORDS); static { - for (int i = 0; i < TunnelBuildMessage.MAX_RECORD_COUNT; i++) + for (int i = 0; i < TunnelBuildMessage.MAX_RECORD_COUNT; i++) { ORDER.add(Integer.valueOf(i)); + } + for (int i = 0; i < SHORT_RECORDS; i++) { + SHORT_ORDER.add(Integer.valueOf(i)); + } + for (int i = 0; i < MEDIUM_RECORDS; i++) { + MEDIUM_ORDER.add(Integer.valueOf(i)); + } } private static final int PRIORITY = OutNetMessage.PRIORITY_MY_BUILD_REQUEST; @@ -223,17 +237,6 @@ abstract class BuildRequestor { // + "ms and dispatched in " + (System.currentTimeMillis()-beforeDispatch)); return true; } - - private static final String MIN_VARIABLE_VERSION = "0.7.12"; - /** change this to true in 0.7.13 if testing goes well */ - private static final boolean SEND_VARIABLE = true; - /** 5 (~2600 bytes) fits nicely in 3 tunnel messages */ - private static final int SHORT_RECORDS = 5; - private static final List<Integer> SHORT_ORDER = new ArrayList<Integer>(SHORT_RECORDS); - static { - for (int i = 0; i < SHORT_RECORDS; i++) - SHORT_ORDER.add(Integer.valueOf(i)); - } /** @since 0.7.12 */ private static boolean supportsVariable(RouterContext ctx, Hash h) { @@ -256,7 +259,7 @@ abstract class BuildRequestor { Log log = ctx.logManager().getLog(BuildRequestor.class); long replyTunnel = 0; Hash replyRouter = null; - boolean useVariable = SEND_VARIABLE && cfg.getLength() <= SHORT_RECORDS; + boolean useVariable = SEND_VARIABLE && cfg.getLength() <= MEDIUM_RECORDS; if (cfg.isInbound()) { //replyTunnel = 0; // as above replyRouter = ctx.routerHash(); @@ -295,10 +298,13 @@ abstract class BuildRequestor { TunnelBuildMessage msg; List<Integer> order; if (useVariable) { - msg = new VariableTunnelBuildMessage(ctx, SHORT_RECORDS); - order = new ArrayList<Integer>(SHORT_ORDER); - //if (log.shouldLog(Log.INFO)) - // log.info("Using new VTBM"); + if (cfg.getLength() <= SHORT_RECORDS) { + msg = new VariableTunnelBuildMessage(ctx, SHORT_RECORDS); + order = new ArrayList<Integer>(SHORT_ORDER); + } else { + msg = new VariableTunnelBuildMessage(ctx, MEDIUM_RECORDS); + order = new ArrayList<Integer>(MEDIUM_ORDER); + } } else { msg = new TunnelBuildMessage(ctx); order = new ArrayList<Integer>(ORDER); diff --git a/router/java/src/net/i2p/router/util/MaskedIPSet.java b/router/java/src/net/i2p/router/util/MaskedIPSet.java new file mode 100644 index 0000000000000000000000000000000000000000..eaf3b6e7e3ccf14af8ed52dcb16840ba440d6b1e --- /dev/null +++ b/router/java/src/net/i2p/router/util/MaskedIPSet.java @@ -0,0 +1,106 @@ +package net.i2p.router.util; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import net.i2p.data.DataHelper; +import net.i2p.data.Hash; +import net.i2p.data.router.RouterAddress; +import net.i2p.data.router.RouterInfo; +import net.i2p.router.RouterContext; + +/** + * Used for detection of routers with matching IPs or family. + * Moved out of ProfileOrganizer for use in netdb also. + * + * @since 0.9.28 + */ +public class MaskedIPSet extends HashSet<String> { + + public MaskedIPSet() { + super(); + } + + public MaskedIPSet(int initialCapacity) { + super(initialCapacity); + } + + /** + * The Set of IPs for this peer, with a given mask. + * Includes the comm system's record of the IP, and all netDb addresses. + * + * As of 0.9.24, returned set will include netdb family as well. + * + * @param peer non-null + * @param mask is 1-4 (number of bytes to match) + * @return an opaque set of masked IPs for this peer + */ + public MaskedIPSet(RouterContext ctx, Hash peer, int mask) { + this(ctx, ctx.netDb().lookupRouterInfoLocally(peer), mask); + } + + /** + * The Set of IPs for this peer, with a given mask. + * Includes the comm system's record of the IP, and all netDb addresses. + * + * As of 0.9.24, returned set will include netdb family as well. + * + * @param pinfo may be null + * @param mask is 1-4 (number of bytes to match) + * @return an opaque set of masked IPs for this peer + */ + public MaskedIPSet(RouterContext ctx, RouterInfo pinfo, int mask) { + super(4); + if (pinfo == null) + return; + byte[] commIP = ctx.commSystem().getIP(pinfo.getHash()); + if (commIP != null) + add(maskedIP(commIP, mask)); + Collection<RouterAddress> paddr = pinfo.getAddresses(); + for (RouterAddress pa : paddr) { + byte[] pib = pa.getIP(); + if (pib == null) continue; + add(maskedIP(pib, mask)); + } + String family = pinfo.getOption("family"); + if (family != null) { + // TODO should KNDF put a family-verified indicator in the RI, + // after checking the sig, or does it matter? + // What's the threat here of not avoid ding a router + // falsely claiming to be in the family? + // Prefix with something so an IP can't be spoofed + add('x' + family); + } + } + + /** + * generate an arbitrary unique value for this ip/mask (mask = 1-4) + * If IPv6, force mask = 6. + * @param mask is 1-4 (number of bytes to match) + */ + private static String maskedIP(byte[] ip, int mask) { + final StringBuilder buf = new StringBuilder(1 + (mask*2)); + final char delim; + if (ip.length == 16) { + mask = 6; + delim = ':'; + } else { + delim = '.'; + } + buf.append(delim); + buf.append(Long.toHexString(DataHelper.fromLong(ip, 0, mask))); + return buf.toString(); + } + + /** does this contain any of the elements in b? */ + public boolean containsAny(Set<String> b) { + if (isEmpty() || b.isEmpty()) + return false; + for (String s : b) { + if (contains(s)) + return true; + } + return false; + } +} diff --git a/router/java/src/org/cybergarage/http/HTTPHeader.java b/router/java/src/org/cybergarage/http/HTTPHeader.java index 9f3849b0af1f1e18011fd1145b9226c71f48e593..cfb1082d21f920f6b054ac427e08dc053b2e17f0 100644 --- a/router/java/src/org/cybergarage/http/HTTPHeader.java +++ b/router/java/src/org/cybergarage/http/HTTPHeader.java @@ -116,6 +116,9 @@ public class HTTPHeader public final static String getValue(String data, String name) { + // I2P #1480 avoid IAE + if (data.length() <= 0) + return ""; /* Thanks for Stephan Mehlhase (2010-10-26) */ StringReader strReader = new StringReader(data); LineNumberReader lineReader = new LineNumberReader(strReader, Math.min(data.length(), MAX_LENGTH)); diff --git a/router/java/src/org/cybergarage/upnp/ssdp/HTTPUSocket.java b/router/java/src/org/cybergarage/upnp/ssdp/HTTPUSocket.java index c21f452e3d457024a933b7b8cf04c73ca7f5c8e0..65f8b7302a3cb5dea29be6e5dad764078bc8e796 100644 --- a/router/java/src/org/cybergarage/upnp/ssdp/HTTPUSocket.java +++ b/router/java/src/org/cybergarage/upnp/ssdp/HTTPUSocket.java @@ -92,6 +92,9 @@ public class HTTPUSocket { if (0 < localAddr.length()) return localAddr; + // I2P prevent NPE #1681 + if (ssdpUniSock == null) + return ""; return ssdpUniSock.getLocalAddress().getHostAddress(); }