diff --git a/apps/streaming/java/src/net/i2p/client/streaming/Connection.java b/apps/streaming/java/src/net/i2p/client/streaming/Connection.java index 48a90d780..1fb61338a 100644 --- a/apps/streaming/java/src/net/i2p/client/streaming/Connection.java +++ b/apps/streaming/java/src/net/i2p/client/streaming/Connection.java @@ -121,6 +121,8 @@ public class Connection { _context.statManager().createRateStat("stream.con.windowSizeAtCongestion", "How large was our send window when we send a dup?", "Stream", new long[] { 60*1000, 10*60*1000, 60*60*1000 }); _context.statManager().createRateStat("stream.chokeSizeBegin", "How many messages were outstanding when we started to choke?", "Stream", new long[] { 60*1000, 10*60*1000, 60*60*1000 }); _context.statManager().createRateStat("stream.chokeSizeEnd", "How many messages were outstanding when we stopped being choked?", "Stream", new long[] { 60*1000, 10*60*1000, 60*60*1000 }); + if (_log.shouldLog(Log.DEBUG)) + _log.debug("New connection created with options: " + _options); } public long getNextOutboundPacketNum() { @@ -805,6 +807,8 @@ public class Connection { buf.append(" close received"); buf.append(" acked packets ").append(getAckedPackets()); + buf.append(" maxWin ").append(getOptions().getMaxWindowSize()); + buf.append("]"); return buf.toString(); } @@ -885,14 +889,15 @@ public class Connection { newWindowSize /= 2; if (newWindowSize <= 0) newWindowSize = 1; - - if (_log.shouldLog(Log.WARN)) - _log.warn("Congestion resending packet " + _packet.getSequenceNum() + ": new windowSize " + newWindowSize - + ") for " + Connection.this.toString()); - + // setRTT has its own ceiling getOptions().setRTT(getOptions().getRTT() + 10*1000); getOptions().setWindowSize(newWindowSize); + + if (_log.shouldLog(Log.WARN)) + _log.warn("Congestion resending packet " + _packet.getSequenceNum() + ": new windowSize " + newWindowSize + + "/" + getOptions().getWindowSize() + ") for " + Connection.this.toString()); + windowAdjusted(); } } diff --git a/apps/streaming/java/src/net/i2p/client/streaming/ConnectionPacketHandler.java b/apps/streaming/java/src/net/i2p/client/streaming/ConnectionPacketHandler.java index 9117cc3de..aeab27d66 100644 --- a/apps/streaming/java/src/net/i2p/client/streaming/ConnectionPacketHandler.java +++ b/apps/streaming/java/src/net/i2p/client/streaming/ConnectionPacketHandler.java @@ -227,15 +227,17 @@ public class ConnectionPacketHandler { oldSize >>>= 1; if (oldSize <= 0) oldSize = 1; - if (_log.shouldLog(Log.DEBUG)) - _log.debug("Congestion occurred - new windowSize " + oldSize + " congestionSeenAt: " - + con.getLastCongestionSeenAt() + " (#resends: " + numResends - + ") for " + con); // setRTT has its own ceiling con.getOptions().setRTT(con.getOptions().getRTT() + 10*1000); con.getOptions().setWindowSize(oldSize); - + + if (_log.shouldLog(Log.DEBUG)) + _log.debug("Congestion occurred - new windowSize " + oldSize + " / " + con.getOptions().getWindowSize() + " congestionSeenAt: " + + con.getLastCongestionSeenAt() + " (#resends: " + numResends + + ") for " + con); + + congested = true; } @@ -266,13 +268,14 @@ public class ConnectionPacketHandler { if (newWindowSize <= 0) newWindowSize = 1; - - if (_log.shouldLog(Log.DEBUG)) - _log.debug("New window size " + newWindowSize + "/" + oldWindow + " congestionSeenAt: " - + con.getLastCongestionSeenAt() + " (#resends: " + numResends - + ") for " + con); + con.getOptions().setWindowSize(newWindowSize); con.setCongestionWindowEnd(newWindowSize + lowest); + + if (_log.shouldLog(Log.DEBUG)) + _log.debug("New window size " + newWindowSize + "/" + oldWindow + "/" + con.getOptions().getWindowSize() + " congestionSeenAt: " + + con.getLastCongestionSeenAt() + " (#resends: " + numResends + + ") for " + con); } con.windowAdjusted(); diff --git a/core/java/src/net/i2p/client/I2CPMessageProducer.java b/core/java/src/net/i2p/client/I2CPMessageProducer.java index 0fa933682..068e41daf 100644 --- a/core/java/src/net/i2p/client/I2CPMessageProducer.java +++ b/core/java/src/net/i2p/client/I2CPMessageProducer.java @@ -181,4 +181,4 @@ class I2CPMessageProducer { msg.setSessionId(session.getSessionId()); session.sendMessage(msg); } -} \ No newline at end of file +} diff --git a/core/java/src/net/i2p/client/I2PSessionImpl2.java b/core/java/src/net/i2p/client/I2PSessionImpl2.java index 7cf15a61f..1be9b887e 100644 --- a/core/java/src/net/i2p/client/I2PSessionImpl2.java +++ b/core/java/src/net/i2p/client/I2PSessionImpl2.java @@ -119,49 +119,57 @@ class I2PSessionImpl2 extends I2PSessionImpl { private boolean sendBestEffort(Destination dest, byte payload[], SessionKey keyUsed, Set tagsSent) throws I2PSessionException { - long begin = _context.clock().now(); - if (_log.shouldLog(Log.DEBUG)) _log.debug("begin sendBestEffort"); - SessionKey key = _context.sessionKeyManager().getCurrentKey(dest.getPublicKey()); - if (_log.shouldLog(Log.DEBUG)) _log.debug("key fetched"); - if (key == null) key = _context.sessionKeyManager().createSession(dest.getPublicKey()); - SessionTag tag = _context.sessionKeyManager().consumeNextAvailableTag(dest.getPublicKey(), key); - if (_log.shouldLog(Log.DEBUG)) _log.debug("tag consumed"); + SessionKey key = null; + SessionKey newKey = null; + SessionTag tag = null; Set sentTags = null; - int oldTags = _context.sessionKeyManager().getAvailableTags(dest.getPublicKey(), key); - long availTimeLeft = _context.sessionKeyManager().getAvailableTimeLeft(dest.getPublicKey(), key); + int oldTags = 0; + long begin = _context.clock().now(); + if (I2CPMessageProducer.END_TO_END_CRYPTO) { + if (_log.shouldLog(Log.DEBUG)) _log.debug("begin sendBestEffort"); + key = _context.sessionKeyManager().getCurrentKey(dest.getPublicKey()); + if (_log.shouldLog(Log.DEBUG)) _log.debug("key fetched"); + if (key == null) key = _context.sessionKeyManager().createSession(dest.getPublicKey()); + tag = _context.sessionKeyManager().consumeNextAvailableTag(dest.getPublicKey(), key); + if (_log.shouldLog(Log.DEBUG)) _log.debug("tag consumed"); + sentTags = null; + oldTags = _context.sessionKeyManager().getAvailableTags(dest.getPublicKey(), key); + long availTimeLeft = _context.sessionKeyManager().getAvailableTimeLeft(dest.getPublicKey(), key); - if ( (tagsSent == null) || (tagsSent.size() <= 0) ) { - if (oldTags < NUM_TAGS) { - sentTags = createNewTags(NUM_TAGS); - if (_log.shouldLog(Log.DEBUG)) - _log.debug("** sendBestEffort only had " + oldTags + " with " + availTimeLeft + ", adding " + NUM_TAGS + ": " + sentTags); - } else if (availTimeLeft < 2 * 60 * 1000) { - // if we have > 50 tags, but they expire in under 2 minutes, we want more - sentTags = createNewTags(NUM_TAGS); - if (_log.shouldLog(Log.DEBUG)) - _log.debug(getPrefix() + "Tags expiring in " + availTimeLeft + ", adding " + NUM_TAGS + " new ones: " + sentTags); - //_log.error("** sendBestEffort available time left " + availTimeLeft); + if ( (tagsSent == null) || (tagsSent.size() <= 0) ) { + if (oldTags < NUM_TAGS) { + sentTags = createNewTags(NUM_TAGS); + if (_log.shouldLog(Log.DEBUG)) + _log.debug("** sendBestEffort only had " + oldTags + " with " + availTimeLeft + ", adding " + NUM_TAGS + ": " + sentTags); + } else if (availTimeLeft < 2 * 60 * 1000) { + // if we have > 50 tags, but they expire in under 2 minutes, we want more + sentTags = createNewTags(NUM_TAGS); + if (_log.shouldLog(Log.DEBUG)) + _log.debug(getPrefix() + "Tags expiring in " + availTimeLeft + ", adding " + NUM_TAGS + " new ones: " + sentTags); + //_log.error("** sendBestEffort available time left " + availTimeLeft); + } else { + if (_log.shouldLog(Log.DEBUG)) + _log.debug("sendBestEffort old tags: " + oldTags + " available time left: " + availTimeLeft); + } } else { if (_log.shouldLog(Log.DEBUG)) - _log.debug("sendBestEffort old tags: " + oldTags + " available time left: " + availTimeLeft); + _log.debug("sendBestEffort is sending " + tagsSent.size() + " with " + availTimeLeft + + "ms left, " + oldTags + " tags known and " + + (tag == null ? "no tag" : " a valid tag")); + } + + if (false) // rekey + newKey = _context.keyGenerator().generateSessionKey(); + + if ( (tagsSent != null) && (tagsSent.size() > 0) ) { + if (sentTags == null) + sentTags = new HashSet(); + sentTags.addAll(tagsSent); } } else { - if (_log.shouldLog(Log.DEBUG)) - _log.debug("sendBestEffort is sending " + tagsSent.size() + " with " + availTimeLeft - + "ms left, " + oldTags + " tags known and " - + (tag == null ? "no tag" : " a valid tag")); + // not using end to end crypto, so don't ever bundle any tags } - SessionKey newKey = null; - if (false) // rekey - newKey = _context.keyGenerator().generateSessionKey(); - - if ( (tagsSent != null) && (tagsSent.size() > 0) ) { - if (sentTags == null) - sentTags = new HashSet(); - sentTags.addAll(tagsSent); - } - if (_log.shouldLog(Log.DEBUG)) _log.debug("before creating nonce"); long nonce = _context.random().nextInt(Integer.MAX_VALUE); @@ -174,10 +182,14 @@ class I2PSessionImpl2 extends I2PSessionImpl { if (_log.shouldLog(Log.DEBUG)) _log.debug(getPrefix() + "Setting key = " + key); if (keyUsed != null) { - if (newKey != null) - keyUsed.setData(newKey.getData()); - else - keyUsed.setData(key.getData()); + if (I2CPMessageProducer.END_TO_END_CRYPTO) { + if (newKey != null) + keyUsed.setData(newKey.getData()); + else + keyUsed.setData(key.getData()); + } else { + keyUsed.setData(SessionKey.INVALID_KEY.getData()); + } } if (tagsSent != null) { if (sentTags != null) { diff --git a/core/java/src/net/i2p/crypto/DHSessionKeyBuilder.java b/core/java/src/net/i2p/crypto/DHSessionKeyBuilder.java index a96a0846a..7fc4df6a7 100644 --- a/core/java/src/net/i2p/crypto/DHSessionKeyBuilder.java +++ b/core/java/src/net/i2p/crypto/DHSessionKeyBuilder.java @@ -18,6 +18,7 @@ import java.io.InputStream; import java.io.OutputStream; import net.i2p.I2PAppContext; +import net.i2p.I2PException; import net.i2p.data.ByteArray; import net.i2p.data.DataHelper; import net.i2p.data.SessionKey; @@ -157,8 +158,14 @@ public class DHSessionKeyBuilder { // read: Y BigInteger Y = readBigI(in); if (Y == null) return null; - builder.setPeerPublicValue(Y); - return builder; + try { + builder.setPeerPublicValue(Y); + return builder; + } catch (InvalidPublicParameterException ippe) { + if (_log.shouldLog(Log.ERROR)) + _log.error("Key exchange failed (hostile peer?)", ippe); + return null; + } } static BigInteger readBigI(InputStream in) throws IOException { @@ -175,7 +182,7 @@ public class DHSessionKeyBuilder { System.arraycopy(Y, 0, Y2, 1, 256); Y = Y2; } - return new NativeBigInteger(Y); + return new NativeBigInteger(1, Y); } /** @@ -269,10 +276,11 @@ public class DHSessionKeyBuilder { * Specify the value given by the peer for use in the session key negotiation * */ - public void setPeerPublicValue(BigInteger peerVal) { + public void setPeerPublicValue(BigInteger peerVal) throws InvalidPublicParameterException { + validatePublic(peerVal); _peerValue = peerVal; } - public void setPeerPublicValue(byte val[]) { + public void setPeerPublicValue(byte val[]) throws InvalidPublicParameterException { if (val.length != 256) throw new IllegalArgumentException("Peer public value must be exactly 256 bytes"); @@ -284,7 +292,8 @@ public class DHSessionKeyBuilder { System.arraycopy(val, 0, val2, 1, 256); val = val2; } - _peerValue = new NativeBigInteger(val); + setPeerPublicValue(new NativeBigInteger(1, val)); + //_peerValue = new NativeBigInteger(val); } public BigInteger getPeerPublicValue() { @@ -355,8 +364,58 @@ public class DHSessionKeyBuilder { } return key; } + + /** + * rfc2631: + * The following algorithm MAY be used to validate a received public key y. + * + * 1. Verify that y lies within the interval [2,p-1]. If it does not, + * the key is invalid. + * 2. Compute y^q mod p. If the result == 1, the key is valid. + * Otherwise the key is invalid. + */ + private static final void validatePublic(BigInteger publicValue) throws InvalidPublicParameterException { + int cmp = publicValue.compareTo(NativeBigInteger.ONE); + if (cmp <= 0) + throw new InvalidPublicParameterException("Public value is below two: " + publicValue.toString()); + + cmp = publicValue.compareTo(CryptoConstants.elgp); + if (cmp >= 0) + throw new InvalidPublicParameterException("Public value is above p-1: " + publicValue.toString()); + + // todo: + // whatever validation needs to be done to mirror the rfc's part 2 (we don't have a q, so can't do + // if (NativeBigInteger.ONE.compareTo(publicValue.modPow(q, CryptoConstants.elgp)) != 0) + // throw new InvalidPublicParameterException("Invalid public value with y^q mod p != 1"); + // + } + /* + private static void testValidation() { + NativeBigInteger bi = new NativeBigInteger("-3416069082912684797963255430346582466254460710249795973742848334283491150671563023437888953432878859472362439146158925287289114133666004165938814597775594104058593692562989626922979416277152479694258099203456493995467386903611666213773085025718340335205240293383622352894862685806192183268523899615405287022135356656720938278415659792084974076416864813957028335830794117802560169423133816961503981757298122040391506600117301607823659479051969827845787626261515313227076880722069706394405554113103165334903531980102626092646197079218895216346725765704256096661045699444128316078549709132753443706200863682650825635513"); + try { + validatePublic(bi); + System.err.println("valid?!"); + } catch (InvalidPublicParameterException ippe) { + System.err.println("Ok, invalid. cool"); + } + + byte val[] = bi.toByteArray(); + System.out.println("Len: " + val.length + " first is ok? " + ( (val[0] & 0x80) == 1) + + "\n" + DataHelper.toString(val, 64)); + NativeBigInteger bi2 = new NativeBigInteger(1, val); + try { + validatePublic(bi2); + System.out.println("valid"); + } catch (InvalidPublicParameterException ippe) { + System.out.println("invalid"); + } + } + */ + public static void main(String args[]) { + //if (true) { testValidation(); return; } + RandomSource.getInstance().nextBoolean(); // warm it up try { Thread.sleep(20 * 1000); @@ -365,36 +424,40 @@ public class DHSessionKeyBuilder { I2PAppContext ctx = new I2PAppContext(); _log.debug("\n\n\n\nBegin test\n"); long negTime = 0; - for (int i = 0; i < 5; i++) { - long startNeg = Clock.getInstance().now(); - DHSessionKeyBuilder builder1 = new DHSessionKeyBuilder(); - DHSessionKeyBuilder builder2 = new DHSessionKeyBuilder(); - BigInteger pub1 = builder1.getMyPublicValue(); - builder2.setPeerPublicValue(pub1); - BigInteger pub2 = builder2.getMyPublicValue(); - builder1.setPeerPublicValue(pub2); - SessionKey key1 = builder1.getSessionKey(); - SessionKey key2 = builder2.getSessionKey(); - long endNeg = Clock.getInstance().now(); - negTime += endNeg - startNeg; + try { + for (int i = 0; i < 5; i++) { + long startNeg = Clock.getInstance().now(); + DHSessionKeyBuilder builder1 = new DHSessionKeyBuilder(); + DHSessionKeyBuilder builder2 = new DHSessionKeyBuilder(); + BigInteger pub1 = builder1.getMyPublicValue(); + builder2.setPeerPublicValue(pub1); + BigInteger pub2 = builder2.getMyPublicValue(); + builder1.setPeerPublicValue(pub2); + SessionKey key1 = builder1.getSessionKey(); + SessionKey key2 = builder2.getSessionKey(); + long endNeg = Clock.getInstance().now(); + negTime += endNeg - startNeg; - if (!key1.equals(key2)) - _log.error("**ERROR: Keys do not match"); - else - _log.debug("**Success: Keys match"); + if (!key1.equals(key2)) + _log.error("**ERROR: Keys do not match"); + else + _log.debug("**Success: Keys match"); - byte iv[] = new byte[16]; - RandomSource.getInstance().nextBytes(iv); - String origVal = "1234567890123456"; // 16 bytes max using AESEngine - byte enc[] = new byte[16]; - byte dec[] = new byte[16]; - ctx.aes().encrypt(origVal.getBytes(), 0, enc, 0, key1, iv, 16); - ctx.aes().decrypt(enc, 0, dec, 0, key2, iv, 16); - String tranVal = new String(dec); - if (origVal.equals(tranVal)) - _log.debug("**Success: D(E(val)) == val"); - else - _log.error("**ERROR: D(E(val)) != val [val=(" + tranVal + "), origVal=(" + origVal + ")"); + byte iv[] = new byte[16]; + RandomSource.getInstance().nextBytes(iv); + String origVal = "1234567890123456"; // 16 bytes max using AESEngine + byte enc[] = new byte[16]; + byte dec[] = new byte[16]; + ctx.aes().encrypt(origVal.getBytes(), 0, enc, 0, key1, iv, 16); + ctx.aes().decrypt(enc, 0, dec, 0, key2, iv, 16); + String tranVal = new String(dec); + if (origVal.equals(tranVal)) + _log.debug("**Success: D(E(val)) == val"); + else + _log.error("**ERROR: D(E(val)) != val [val=(" + tranVal + "), origVal=(" + origVal + ")"); + } + } catch (InvalidPublicParameterException ippe) { + _log.error("Invalid dh", ippe); } _log.debug("Negotiation time for 5 runs: " + negTime + " @ " + negTime / 5l + "ms each"); try { @@ -451,4 +514,13 @@ public class DHSessionKeyBuilder { return builder; } } + + public static class InvalidPublicParameterException extends I2PException { + public InvalidPublicParameterException() { + super(); + } + public InvalidPublicParameterException(String msg) { + super(msg); + } + } } \ No newline at end of file diff --git a/core/java/src/net/i2p/crypto/TransientSessionKeyManager.java b/core/java/src/net/i2p/crypto/TransientSessionKeyManager.java index 4a184f6be..f7a2579ce 100644 --- a/core/java/src/net/i2p/crypto/TransientSessionKeyManager.java +++ b/core/java/src/net/i2p/crypto/TransientSessionKeyManager.java @@ -220,10 +220,10 @@ class TransientSessionKeyManager extends SessionKeyManager { * */ public void tagsDelivered(PublicKey target, SessionKey key, Set sessionTags) { - if (_log.shouldLog(Log.WARN)) { + if (_log.shouldLog(Log.DEBUG)) { //_log.debug("Tags delivered to set " + set + " on session " + sess); if (sessionTags.size() > 0) - _log.warn("Tags delivered: " + sessionTags.size() + " for key: " + key.toBase64() + ": " + sessionTags); + _log.debug("Tags delivered: " + sessionTags.size() + " for key: " + key.toBase64() + ": " + sessionTags); } OutboundSession sess = getSession(target); if (sess == null) { @@ -286,10 +286,10 @@ class TransientSessionKeyManager extends SessionKeyManager { } } - if (_log.shouldLog(Log.ERROR)) { - _log.error("Multiple tags matching! tagSet: " + tagSet + " and old tagSet: " + old + " tag: " + dupTag); - _log.error("Earlier tag set creation: " + old + ": key=" + old.getAssociatedKey().toBase64(), old.getCreatedBy()); - _log.error("Current tag set creation: " + tagSet + ": key=" + tagSet.getAssociatedKey().toBase64(), tagSet.getCreatedBy()); + if (_log.shouldLog(Log.WARN)) { + _log.warn("Multiple tags matching! tagSet: " + tagSet + " and old tagSet: " + old + " tag: " + dupTag + "/" + dupTag.toBase64()); + _log.warn("Earlier tag set creation: " + old + ": key=" + old.getAssociatedKey().toBase64(), old.getCreatedBy()); + _log.warn("Current tag set creation: " + tagSet + ": key=" + tagSet.getAssociatedKey().toBase64(), tagSet.getCreatedBy()); } } @@ -413,7 +413,7 @@ class TransientSessionKeyManager extends SessionKeyManager { long now = _context.clock().now(); StringBuffer buf = null; StringBuffer bufSummary = null; - if (_log.shouldLog(Log.WARN)) { + if (_log.shouldLog(Log.DEBUG)) { buf = new StringBuffer(128); buf.append("Expiring inbound: "); bufSummary = new StringBuffer(1024); @@ -438,9 +438,9 @@ class TransientSessionKeyManager extends SessionKeyManager { } _context.statManager().addRateData("crypto.sessionTagsRemaining", remaining, 0); if ( (buf != null) && (removed > 0) ) - _log.warn(buf.toString()); + _log.debug(buf.toString()); if (bufSummary != null) - _log.warn("Cleaning up with remaining: " + bufSummary.toString()); + _log.debug("Cleaning up with remaining: " + bufSummary.toString()); //_log.warn("Expiring tags: [" + tagsToDrop + "]"); diff --git a/core/java/src/net/i2p/data/ByteArray.java b/core/java/src/net/i2p/data/ByteArray.java index c6b79c2da..b36efbc27 100644 --- a/core/java/src/net/i2p/data/ByteArray.java +++ b/core/java/src/net/i2p/data/ByteArray.java @@ -10,6 +10,7 @@ package net.i2p.data; */ import java.io.Serializable; +import net.i2p.data.Base64; /** * Wrap up an array of bytes so that they can be compared and placed in hashes, @@ -82,6 +83,10 @@ public class ByteArray implements Serializable, Comparable { } public final String toString() { - return DataHelper.toString(getData(), 32); + return super.toString() + "/" + DataHelper.toString(getData(), 32) + "." + _valid; + } + + public final String toBase64() { + return Base64.encode(_data, _offset, _valid); } } \ No newline at end of file diff --git a/core/java/src/net/i2p/data/SessionKey.java b/core/java/src/net/i2p/data/SessionKey.java index 551c7d7ff..bf68528d4 100644 --- a/core/java/src/net/i2p/data/SessionKey.java +++ b/core/java/src/net/i2p/data/SessionKey.java @@ -27,6 +27,7 @@ public class SessionKey extends DataStructureImpl { private Object _preparedKey; public final static int KEYSIZE_BYTES = 32; + public static final SessionKey INVALID_KEY = new SessionKey(new byte[KEYSIZE_BYTES]); public SessionKey() { this(null); diff --git a/core/java/src/net/i2p/stat/BufferedStatLog.java b/core/java/src/net/i2p/stat/BufferedStatLog.java index e7442b775..41f964242 100644 --- a/core/java/src/net/i2p/stat/BufferedStatLog.java +++ b/core/java/src/net/i2p/stat/BufferedStatLog.java @@ -31,11 +31,13 @@ public class BufferedStatLog implements StatLog { private String _outFile; private static final int BUFFER_SIZE = 1024; + private static final boolean DISABLE_LOGGING = false; public BufferedStatLog(I2PAppContext ctx) { _context = ctx; _log = ctx.logManager().getLog(BufferedStatLog.class); _events = new StatEvent[BUFFER_SIZE]; + if (DISABLE_LOGGING) return; for (int i = 0; i < BUFFER_SIZE; i++) _events[i] = new StatEvent(); _eventNext = 0; @@ -48,6 +50,7 @@ public class BufferedStatLog implements StatLog { } public void addData(String scope, String stat, long value, long duration) { + if (DISABLE_LOGGING) return; synchronized (_events) { _events[_eventNext].init(scope, stat, value, duration); _eventNext = (_eventNext + 1) % _events.length; diff --git a/core/java/src/net/i2p/util/ByteCache.java b/core/java/src/net/i2p/util/ByteCache.java index 8344e0989..2034fe859 100644 --- a/core/java/src/net/i2p/util/ByteCache.java +++ b/core/java/src/net/i2p/util/ByteCache.java @@ -85,11 +85,15 @@ public final class ByteCache { * */ public final void release(ByteArray entry) { + release(entry, true); + } + public final void release(ByteArray entry, boolean shouldZero) { if (_cache) { if ( (entry == null) || (entry.getData() == null) ) return; - Arrays.fill(entry.getData(), (byte)0x0); + if (shouldZero) + Arrays.fill(entry.getData(), (byte)0x0); synchronized (_available) { if (_available.size() < _maxCached) _available.add(entry); diff --git a/core/java/src/net/i2p/util/PooledRandomSource.java b/core/java/src/net/i2p/util/PooledRandomSource.java index eaf8ea95e..2e70bbaa9 100644 --- a/core/java/src/net/i2p/util/PooledRandomSource.java +++ b/core/java/src/net/i2p/util/PooledRandomSource.java @@ -61,9 +61,14 @@ public class PooledRandomSource extends RandomSource { } private final RandomSource pickPRNG() { - int i = _nextPool % POOL_SIZE; - _nextPool = (++_nextPool) % POOL_SIZE; - return _pool[i]; + // how much more explicit can we get? + int cur = _nextPool; + cur = cur % POOL_SIZE; + RandomSource rv = _pool[cur]; + cur++; + cur = cur % POOL_SIZE; + _nextPool = cur; + return rv; } /** diff --git a/history.txt b/history.txt index 6471df13b..75f968e99 100644 --- a/history.txt +++ b/history.txt @@ -1,12 +1,19 @@ -$Id: history.txt,v 1.212 2005/07/13 15:07:32 jrandom Exp $ +$Id: history.txt,v 1.213 2005/07/16 07:52:36 cervantes Exp $ + +2005-07-19 jrandom + * Further preparation for removing I2CP crypto + * Added some validation to the DH key agreement (thanks $anon) + * Validate tunnel data message expirations (though not really a problem, + since tunnels expire) + * Minor PRNG threading cleanup 2005-07-15 cervantes - * Added workaround for an odd win32 bug in the stats configuration - console page which meant only the first checkbox selection was saved. + * Added workaround for an odd win32 bug in the stats configuration console + page which meant only the first checkbox selection was saved. 2005-07-15 Romster - * Added per group selection toggles in the stats configuration console - page. + * Added per group selection toggles in the stats configuration console + page. 2005-07-13 jrandom * Fixed a recently injected bug in the multitransport bidding which had diff --git a/router/java/src/net/i2p/data/i2np/DeliveryStatusMessage.java b/router/java/src/net/i2p/data/i2np/DeliveryStatusMessage.java index 955a8ef45..f0f0183df 100644 --- a/router/java/src/net/i2p/data/i2np/DeliveryStatusMessage.java +++ b/router/java/src/net/i2p/data/i2np/DeliveryStatusMessage.java @@ -54,8 +54,7 @@ public class DeliveryStatusMessage extends I2NPMessageImpl { protected int writeMessageBody(byte out[], int curIndex) throws I2NPMessageException { if ( (_id < 0) || (_arrival <= 0) ) throw new I2NPMessageException("Not enough data to write out"); - byte id[] = DataHelper.toLong(4, _id); - System.arraycopy(id, 0, out, curIndex, 4); + DataHelper.toLong(out, curIndex, 4, _id); curIndex += 4; DataHelper.toLong(out, curIndex, DataHelper.DATE_LENGTH, _arrival); curIndex += DataHelper.DATE_LENGTH; diff --git a/router/java/src/net/i2p/data/i2np/I2NPMessage.java b/router/java/src/net/i2p/data/i2np/I2NPMessage.java index b30fa9709..c7a19acb2 100644 --- a/router/java/src/net/i2p/data/i2np/I2NPMessage.java +++ b/router/java/src/net/i2p/data/i2np/I2NPMessage.java @@ -51,6 +51,7 @@ public interface I2NPMessage extends DataStructure { * @throws IOException if there is a problem reading from the stream */ public void readMessage(byte data[], int offset, int dataSize, int type) throws I2NPMessageException, IOException; + public void readMessage(byte data[], int offset, int dataSize, int type, I2NPMessageHandler handler) throws I2NPMessageException, IOException; /** * Return the unique identifier for this type of I2NP message, as defined in diff --git a/router/java/src/net/i2p/data/i2np/I2NPMessageImpl.java b/router/java/src/net/i2p/data/i2np/I2NPMessageImpl.java index fa0ade8d2..1ca75f6ec 100644 --- a/router/java/src/net/i2p/data/i2np/I2NPMessageImpl.java +++ b/router/java/src/net/i2p/data/i2np/I2NPMessageImpl.java @@ -268,7 +268,16 @@ public abstract class I2NPMessageImpl extends DataStructureImpl implements I2NPM } } + public void readMessage(byte data[], int offset, int dataSize, int type, I2NPMessageHandler handler) throws I2NPMessageException, IOException { + // ignore the handler (overridden in subclasses if necessary + readMessage(data, offset, dataSize, type); + } + + public static I2NPMessage fromRawByteArray(I2PAppContext ctx, byte buffer[], int offset, int len) throws I2NPMessageException { + return fromRawByteArray(ctx, buffer, offset, len, new I2NPMessageHandler(ctx)); + } + public static I2NPMessage fromRawByteArray(I2PAppContext ctx, byte buffer[], int offset, int len, I2NPMessageHandler handler) throws I2NPMessageException { int type = (int)DataHelper.fromLong(buffer, offset, 1); offset++; I2NPMessage msg = createMessage(ctx, type); @@ -287,7 +296,7 @@ public abstract class I2NPMessageImpl extends DataStructureImpl implements I2NPM offset += 4; int dataSize = len - 1 - 4; try { - msg.readMessage(buffer, offset, dataSize, type); + msg.readMessage(buffer, offset, dataSize, type, handler); msg.setMessageExpiration(expiration); return msg; } catch (IOException ioe) { diff --git a/router/java/src/net/i2p/data/i2np/TunnelGatewayMessage.java b/router/java/src/net/i2p/data/i2np/TunnelGatewayMessage.java index 373ca6f4d..9848d31e8 100644 --- a/router/java/src/net/i2p/data/i2np/TunnelGatewayMessage.java +++ b/router/java/src/net/i2p/data/i2np/TunnelGatewayMessage.java @@ -81,6 +81,10 @@ public class TunnelGatewayMessage extends I2NPMessageImpl { public void readMessage(byte data[], int offset, int dataSize, int type) throws I2NPMessageException, IOException { + I2NPMessageHandler h = new I2NPMessageHandler(_context); + readMessage(data, offset, dataSize, type, h); + } + public void readMessage(byte data[], int offset, int dataSize, int type, I2NPMessageHandler handler) throws I2NPMessageException, IOException { if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message"); int curIndex = offset; @@ -92,9 +96,8 @@ public class TunnelGatewayMessage extends I2NPMessageImpl { int size = (int)DataHelper.fromLong(data, curIndex, 2); curIndex += 2; - I2NPMessageHandler h = new I2NPMessageHandler(_context); - curIndex = h.readMessage(data, curIndex); - _msg = h.lastRead(); + curIndex = handler.readMessage(data, curIndex); + _msg = handler.lastRead(); if (_msg == null) throw new I2NPMessageException("wtf, message read has no payload?"); } diff --git a/router/java/src/net/i2p/router/InNetMessagePool.java b/router/java/src/net/i2p/router/InNetMessagePool.java index 98c320988..63e1a0135 100644 --- a/router/java/src/net/i2p/router/InNetMessagePool.java +++ b/router/java/src/net/i2p/router/InNetMessagePool.java @@ -113,30 +113,35 @@ public class InNetMessagePool implements Service { // _context.statManager().getStatLog().addData(fromRouterHash.toBase64().substring(0,6), "udp.floodDataReceived", 1, 0); // return 0; //} + + String invalidReason = null; if (messageBody instanceof TunnelDataMessage) { - // do not validate the message with the validator - the IV validator is sufficient - } else { - String invalidReason = _context.messageValidator().validateMessage(messageBody.getUniqueId(), exp); - if (invalidReason != null) { - int level = Log.WARN; - if (messageBody instanceof TunnelCreateMessage) - level = Log.INFO; - if (_log.shouldLog(level)) - _log.log(level, "Duplicate message received [" + messageBody.getUniqueId() - + " expiring on " + exp + "]: " + messageBody.getClass().getName() + ": " + invalidReason - + ": " + messageBody); - _context.statManager().addRateData("inNetPool.dropped", 1, 0); - _context.statManager().addRateData("inNetPool.duplicate", 1, 0); - _context.messageHistory().droppedOtherMessage(messageBody); - _context.messageHistory().messageProcessingError(messageBody.getUniqueId(), - messageBody.getClass().getName(), - "Duplicate/expired"); - return -1; - } else { - if (_log.shouldLog(Log.DEBUG)) - _log.debug("Message received [" + messageBody.getUniqueId() - + " expiring on " + exp + "] is NOT a duplicate or exipired"); - } + // the IV validator is sufficient for dup detection on tunnel messages, so + // just validate the expiration + invalidReason = _context.messageValidator().validateMessage(exp); + } else { + invalidReason = _context.messageValidator().validateMessage(messageBody.getUniqueId(), exp); + } + + if (invalidReason != null) { + int level = Log.WARN; + if (messageBody instanceof TunnelCreateMessage) + level = Log.INFO; + if (_log.shouldLog(level)) + _log.log(level, "Duplicate message received [" + messageBody.getUniqueId() + + " expiring on " + exp + "]: " + messageBody.getClass().getName() + ": " + invalidReason + + ": " + messageBody); + _context.statManager().addRateData("inNetPool.dropped", 1, 0); + _context.statManager().addRateData("inNetPool.duplicate", 1, 0); + _context.messageHistory().droppedOtherMessage(messageBody); + _context.messageHistory().messageProcessingError(messageBody.getUniqueId(), + messageBody.getClass().getName(), + "Duplicate/expired"); + return -1; + } else { + if (_log.shouldLog(Log.DEBUG)) + _log.debug("Message received [" + messageBody.getUniqueId() + + " expiring on " + exp + "] is NOT a duplicate or exipired"); } boolean jobFound = false; diff --git a/router/java/src/net/i2p/router/MessageHistory.java b/router/java/src/net/i2p/router/MessageHistory.java index b401f05c9..eed0a9d71 100644 --- a/router/java/src/net/i2p/router/MessageHistory.java +++ b/router/java/src/net/i2p/router/MessageHistory.java @@ -443,13 +443,13 @@ public class MessageHistory { addEntry(buf.toString()); } - public void receiveTunnelFragment(long messageId, int fragmentId, String status) { + public void receiveTunnelFragment(long messageId, int fragmentId, Object status) { if (!_doLog) return; if (messageId == -1) throw new IllegalArgumentException("why are you -1?"); StringBuffer buf = new StringBuffer(48); buf.append(getPrefix()); buf.append("Receive fragment ").append(fragmentId).append(" in ").append(messageId); - buf.append(" status: ").append(status); + buf.append(" status: ").append(status.toString()); addEntry(buf.toString()); } public void receiveTunnelFragmentComplete(long messageId) { diff --git a/router/java/src/net/i2p/router/MessageValidator.java b/router/java/src/net/i2p/router/MessageValidator.java index 140e83d44..8df7b9901 100644 --- a/router/java/src/net/i2p/router/MessageValidator.java +++ b/router/java/src/net/i2p/router/MessageValidator.java @@ -34,18 +34,9 @@ public class MessageValidator { * @return reason why the message is invalid (or null if the message is valid) */ public String validateMessage(long messageId, long expiration) { - long now = _context.clock().now(); - if (now - Router.CLOCK_FUDGE_FACTOR >= expiration) { - if (_log.shouldLog(Log.WARN)) - _log.warn("Rejecting message " + messageId + " because it expired " + (now-expiration) + "ms ago"); - _context.statManager().addRateData("router.invalidMessageTime", (now-expiration), 0); - return "expired " + (now-expiration) + "ms ago"; - } else if (now + 4*Router.CLOCK_FUDGE_FACTOR < expiration) { - if (_log.shouldLog(Log.WARN)) - _log.warn("Rejecting message " + messageId + " because it will expire too far in the future (" + (expiration-now) + "ms)"); - _context.statManager().addRateData("router.invalidMessageTime", (now-expiration), 0); - return "expire too far in the future (" + (expiration-now) + "ms)"; - } + String msg = validateMessage(expiration); + if (msg != null) + return msg; boolean isDuplicate = noteReception(messageId, expiration); if (isDuplicate) { @@ -59,6 +50,24 @@ public class MessageValidator { return null; } } + /** + * Only check the expiration for the message + */ + public String validateMessage(long expiration) { + long now = _context.clock().now(); + if (now - Router.CLOCK_FUDGE_FACTOR >= expiration) { + if (_log.shouldLog(Log.WARN)) + _log.warn("Rejecting message because it expired " + (now-expiration) + "ms ago"); + _context.statManager().addRateData("router.invalidMessageTime", (now-expiration), 0); + return "expired " + (now-expiration) + "ms ago"; + } else if (now + 4*Router.CLOCK_FUDGE_FACTOR < expiration) { + if (_log.shouldLog(Log.WARN)) + _log.warn("Rejecting message because it will expire too far in the future (" + (expiration-now) + "ms)"); + _context.statManager().addRateData("router.invalidMessageTime", (now-expiration), 0); + return "expire too far in the future (" + (expiration-now) + "ms)"; + } + return null; + } private static final long TIME_MASK = 0xFFFFFC00; diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index 51b2927ff..5c5a8bc85 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -15,9 +15,9 @@ import net.i2p.CoreVersion; * */ public class RouterVersion { - public final static String ID = "$Revision: 1.203 $ $Date: 2005/07/13 15:07:32 $"; + public final static String ID = "$Revision: 1.204 $ $Date: 2005/07/16 07:52:36 $"; public final static String VERSION = "0.5.0.7"; - public final static long BUILD = 15; + public final static long BUILD = 16; public static void main(String args[]) { System.out.println("I2P Router version: " + VERSION); System.out.println("Router ID: " + RouterVersion.ID); diff --git a/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java b/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java index b371c0b02..9ce8976f8 100644 --- a/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java +++ b/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java @@ -100,6 +100,7 @@ public class CommSystemFacadeImpl extends CommSystemFacade { private final static String PROP_I2NP_TCP_HOSTNAME = "i2np.tcp.hostname"; private final static String PROP_I2NP_TCP_PORT = "i2np.tcp.port"; + private final static String PROP_I2NP_TCP_DISABLED = "i2np.tcp.disable"; private RouterAddress createTCPAddress() { RouterAddress addr = new RouterAddress(); @@ -108,6 +109,10 @@ public class CommSystemFacadeImpl extends CommSystemFacade { Properties props = new Properties(); String name = _context.router().getConfigSetting(PROP_I2NP_TCP_HOSTNAME); String port = _context.router().getConfigSetting(PROP_I2NP_TCP_PORT); + String disabledStr = _context.router().getConfigSetting(PROP_I2NP_TCP_DISABLED); + boolean disabled = false; + if ( (disabledStr != null) && ("true".equalsIgnoreCase(disabledStr)) ) + return null; if ( (name == null) || (port == null) ) { //_log.info("TCP Host/Port not specified in config file - skipping TCP transport"); return null; diff --git a/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java b/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java index c18794c80..b464ff6d6 100644 --- a/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java +++ b/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java @@ -5,6 +5,7 @@ import java.util.HashMap; import java.util.Iterator; import java.util.Map; +import net.i2p.crypto.DHSessionKeyBuilder; import net.i2p.data.RouterAddress; import net.i2p.data.RouterIdentity; import net.i2p.data.SessionKey; @@ -286,7 +287,16 @@ public class EstablishmentManager { if (_log.shouldLog(Log.DEBUG)) _log.debug("Send created to: " + state.getRemoteHostId().toString()); - state.generateSessionKey(); + try { + state.generateSessionKey(); + } catch (DHSessionKeyBuilder.InvalidPublicParameterException ippe) { + if (_log.shouldLog(Log.ERROR)) + _log.error("Peer " + state.getRemoteHostId() + " sent us an invalid DH parameter (or were spoofed)", ippe); + synchronized (_inboundStates) { + _inboundStates.remove(state.getRemoteHostId()); + } + return; + } _transport.send(_builder.buildSessionCreatedPacket(state, _transport.getExternalPort(), _transport.getIntroKey())); // if they haven't advanced to sending us confirmed packets in 5s, // repeat diff --git a/router/java/src/net/i2p/router/transport/udp/InboundEstablishState.java b/router/java/src/net/i2p/router/transport/udp/InboundEstablishState.java index 7f3ded998..8f426f442 100644 --- a/router/java/src/net/i2p/router/transport/udp/InboundEstablishState.java +++ b/router/java/src/net/i2p/router/transport/udp/InboundEstablishState.java @@ -99,7 +99,7 @@ public class InboundEstablishState { public synchronized byte[] getReceivedX() { return _receivedX; } public synchronized byte[] getReceivedOurIP() { return _bobIP; } - public synchronized void generateSessionKey() { + public synchronized void generateSessionKey() throws DHSessionKeyBuilder.InvalidPublicParameterException { if (_sessionKey != null) return; _keyBuilder = new DHSessionKeyBuilder(); _keyBuilder.setPeerPublicValue(_receivedX); diff --git a/router/java/src/net/i2p/router/transport/udp/MessageReceiver.java b/router/java/src/net/i2p/router/transport/udp/MessageReceiver.java index 5e1e266a5..1176cf024 100644 --- a/router/java/src/net/i2p/router/transport/udp/MessageReceiver.java +++ b/router/java/src/net/i2p/router/transport/udp/MessageReceiver.java @@ -9,6 +9,7 @@ import net.i2p.data.DataFormatException; import net.i2p.data.i2np.I2NPMessage; import net.i2p.data.i2np.I2NPMessageImpl; import net.i2p.data.i2np.I2NPMessageException; +import net.i2p.data.i2np.I2NPMessageHandler; import net.i2p.router.RouterContext; import net.i2p.util.ByteCache; import net.i2p.util.I2PThread; @@ -27,6 +28,7 @@ public class MessageReceiver implements Runnable { private List _completeMessages; private boolean _alive; private ByteCache _cache; + private I2NPMessageHandler _handler; public MessageReceiver(RouterContext ctx, UDPTransport transport) { _context = ctx; @@ -34,6 +36,7 @@ public class MessageReceiver implements Runnable { _transport = transport; _completeMessages = new ArrayList(16); _cache = ByteCache.getInstance(64, I2NPMessage.MAX_SIZE); + _handler = new I2NPMessageHandler(ctx); _alive = true; } @@ -60,6 +63,8 @@ public class MessageReceiver implements Runnable { public void run() { InboundMessageState message = null; + ByteArray buf = _cache.acquire(); + while (_alive) { try { synchronized (_completeMessages) { @@ -74,16 +79,18 @@ public class MessageReceiver implements Runnable { int size = message.getCompleteSize(); if (_log.shouldLog(Log.INFO)) _log.info("Full message received (" + message.getMessageId() + ") after " + message.getLifetime()); - I2NPMessage msg = readMessage(message); + I2NPMessage msg = readMessage(buf, message); if (msg != null) _transport.messageReceived(msg, null, message.getFrom(), message.getLifetime(), size); message = null; } } + + // no need to zero it out, as these buffers are only used with an explicit getCompleteSize + _cache.release(buf, false); } - private I2NPMessage readMessage(InboundMessageState state) { - ByteArray buf = _cache.acquire(); + private I2NPMessage readMessage(ByteArray buf, InboundMessageState state) { try { //byte buf[] = new byte[state.getCompleteSize()]; ByteArray fragments[] = state.getFragments(); @@ -102,7 +109,7 @@ public class MessageReceiver implements Runnable { _log.error("Hmm, offset of the fragments = " + off + " while the state says " + state.getCompleteSize()); if (_log.shouldLog(Log.DEBUG)) _log.debug("Raw byte array for " + state.getMessageId() + ": " + Base64.encode(buf.getData(), 0, state.getCompleteSize())); - I2NPMessage m = I2NPMessageImpl.fromRawByteArray(_context, buf.getData(), 0, state.getCompleteSize()); + I2NPMessage m = I2NPMessageImpl.fromRawByteArray(_context, buf.getData(), 0, state.getCompleteSize(), _handler); m.setUniqueId(state.getMessageId()); return m; } catch (I2NPMessageException ime) { @@ -114,7 +121,6 @@ public class MessageReceiver implements Runnable { return null; } finally { state.releaseResources(); - _cache.release(buf); } } } diff --git a/router/java/src/net/i2p/router/transport/udp/OutboundEstablishState.java b/router/java/src/net/i2p/router/transport/udp/OutboundEstablishState.java index 19b6cef49..f97697393 100644 --- a/router/java/src/net/i2p/router/transport/udp/OutboundEstablishState.java +++ b/router/java/src/net/i2p/router/transport/udp/OutboundEstablishState.java @@ -163,10 +163,18 @@ public class OutboundEstablishState { return true; } - generateSessionKey(); - decryptSignature(); + boolean valid = true; + try { + generateSessionKey(); + } catch (DHSessionKeyBuilder.InvalidPublicParameterException ippe) { + if (_log.shouldLog(Log.ERROR)) + _log.error("Peer " + getRemoteHostId() + " sent us an invalid DH parameter (or were spoofed)", ippe); + valid = false; + } + if (valid) + decryptSignature(); - if (verifySessionCreated()) { + if (valid && verifySessionCreated()) { if (_log.shouldLog(Log.DEBUG)) _log.debug("Session created passed validation"); return true; @@ -191,7 +199,7 @@ public class OutboundEstablishState { } } - private void generateSessionKey() { + private void generateSessionKey() throws DHSessionKeyBuilder.InvalidPublicParameterException { if (_sessionKey != null) return; _keyBuilder.setPeerPublicValue(_receivedY); _sessionKey = _keyBuilder.getSessionKey(); diff --git a/router/java/src/net/i2p/router/transport/udp/PeerState.java b/router/java/src/net/i2p/router/transport/udp/PeerState.java index 6932c2cc6..2d8c82ce3 100644 --- a/router/java/src/net/i2p/router/transport/udp/PeerState.java +++ b/router/java/src/net/i2p/router/transport/udp/PeerState.java @@ -509,7 +509,8 @@ public class PeerState { synchronized (_currentACKs) { rv = new ArrayList(_currentACKs.size()); while ( (bytesRemaining >= 4) && (_currentACKs.size() > 0) ) { - rv.add(new FullACKBitfield((Long)_currentACKs.remove(0))); + long id = ((Long)_currentACKs.remove(0)).longValue(); + rv.add(new FullACKBitfield(id)); bytesRemaining -= 4; } if (_currentACKs.size() <= 0) @@ -576,9 +577,9 @@ public class PeerState { } /** represent a full ACK of a message */ - private class FullACKBitfield implements ACKBitfield { + private static class FullACKBitfield implements ACKBitfield { private long _msgId; - public FullACKBitfield(Long id) { _msgId = id.longValue(); } + public FullACKBitfield(long id) { _msgId = id; } public int fragmentCount() { return 0; } public long getMessageId() { return _msgId; } public boolean received(int fragmentNum) { return true; } 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 86a96884d..afceef342 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java @@ -310,9 +310,10 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority boolean addRemotePeerState(PeerState peer) { if (_log.shouldLog(Log.INFO)) _log.info("Add remote peer state: " + peer); + PeerState oldPeer = null; if (peer.getRemotePeer() != null) { synchronized (_peersByIdent) { - PeerState oldPeer = (PeerState)_peersByIdent.put(peer.getRemotePeer(), peer); + oldPeer = (PeerState)_peersByIdent.put(peer.getRemotePeer(), peer); if ( (oldPeer != null) && (oldPeer != peer) ) { // should we transfer the oldPeer's RTT/RTO/etc? nah // or perhaps reject the new session? nah, @@ -321,17 +322,24 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority } } + if ( (oldPeer != null) && (_log.shouldLog(Log.WARN)) ) + _log.warn("Peer already connected: old=" + oldPeer + " new=" + peer, new Exception("dup")); + oldPeer = null; + RemoteHostId remoteId = peer.getRemoteHostId(); if (remoteId == null) return false; synchronized (_peersByRemoteHost) { - PeerState oldPeer = (PeerState)_peersByRemoteHost.put(remoteId, peer); + oldPeer = (PeerState)_peersByRemoteHost.put(remoteId, peer); if ( (oldPeer != null) && (oldPeer != peer) ) { //_peersByRemoteHost.put(remoteString, oldPeer); //return false; } } + if ( (oldPeer != null) && (_log.shouldLog(Log.WARN)) ) + _log.warn("Peer already connected: old=" + oldPeer + " new=" + peer, new Exception("dup")); + _activeThrottle.unchoke(peer.getRemotePeer()); _context.shitlist().unshitlistRouter(peer.getRemotePeer()); @@ -348,7 +356,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority } private void dropPeer(PeerState peer, boolean shouldShitlist) { if (_log.shouldLog(Log.INFO)) - _log.info("Dropping remote peer: " + peer); + _log.info("Dropping remote peer: " + peer + " shitlist? " + shouldShitlist, new Exception("Dropped by")); if (peer.getRemotePeer() != null) { if (shouldShitlist) { long now = _context.clock().now(); diff --git a/router/java/src/net/i2p/router/tunnel/FragmentHandler.java b/router/java/src/net/i2p/router/tunnel/FragmentHandler.java index 8d7cd9963..12ff97c63 100644 --- a/router/java/src/net/i2p/router/tunnel/FragmentHandler.java +++ b/router/java/src/net/i2p/router/tunnel/FragmentHandler.java @@ -264,7 +264,7 @@ public class FragmentHandler { SimpleTimer.getInstance().removeEvent(msg.getExpireEvent()); receiveComplete(msg); } else { - noteReception(msg.getMessageId(), 0, msg.toString()); + noteReception(msg.getMessageId(), 0, msg); } if (isNew && fragmented && !msg.isComplete()) { @@ -326,7 +326,7 @@ public class FragmentHandler { _context.statManager().addRateData("tunnel.fragmentedComplete", msg.getFragmentCount(), msg.getLifetime()); receiveComplete(msg); } else { - noteReception(msg.getMessageId(), fragmentNum, msg.toString()); + noteReception(msg.getMessageId(), fragmentNum, msg); } if (isNew && !msg.isComplete()) { @@ -360,7 +360,7 @@ public class FragmentHandler { } } - protected void noteReception(long messageId, int fragmentId, String status) {} + protected void noteReception(long messageId, int fragmentId, Object status) {} protected void noteCompletion(long messageId) {} protected void noteFailure(long messageId, String status) {} diff --git a/router/java/src/net/i2p/router/tunnel/RouterFragmentHandler.java b/router/java/src/net/i2p/router/tunnel/RouterFragmentHandler.java index bb0b3920d..7caa3271e 100644 --- a/router/java/src/net/i2p/router/tunnel/RouterFragmentHandler.java +++ b/router/java/src/net/i2p/router/tunnel/RouterFragmentHandler.java @@ -16,7 +16,7 @@ public class RouterFragmentHandler extends FragmentHandler { _log = context.logManager().getLog(RouterFragmentHandler.class); } - protected void noteReception(long messageId, int fragmentId, String status) { + protected void noteReception(long messageId, int fragmentId, Object status) { if (_log.shouldLog(Log.INFO)) _log.info("Received fragment " + fragmentId + " for message " + messageId + ": " + status); _routerContext.messageHistory().receiveTunnelFragment(messageId, fragmentId, status);