propagate from branch 'i2p.i2p.zzz.test2' (head 9dca19f228a66b5ac646c3d97d4f018c733081de)

to branch 'i2p.i2p' (head e7f2b0990f1ff9ab0e0d8633ac2faf35a993b917)
This commit is contained in:
zzz
2014-11-06 17:53:02 +00:00
115 changed files with 56462 additions and 45656 deletions

View File

@ -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 = 10;
public final static long BUILD = 1;
/** for example "-test" */
public final static String EXTRA = "";

View File

@ -13,12 +13,14 @@ import java.util.HashMap;
import java.util.Map;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLContext;
import net.i2p.client.I2PClient;
import net.i2p.crypto.KeyStoreUtil;
import net.i2p.router.RouterContext;
import net.i2p.util.I2PSSLSocketFactory;
import net.i2p.util.Log;
import net.i2p.util.SecureDirectory;
@ -174,6 +176,7 @@ class SSLClientListenerRunner extends ClientListenerRunner {
_log.info("Listening on port " + _port + " of the specific interface: " + listenInterface);
rv = _factory.createServerSocket(_port, 0, InetAddress.getByName(listenInterface));
}
I2PSSLSocketFactory.setProtocolsAndCiphers((SSLServerSocket) rv);
return rv;
}

View File

@ -110,10 +110,10 @@ public class TransientSessionKeyManager extends SessionKeyManager {
private static final long SESSION_TAG_EXPIRATION_WINDOW = 90 * 1000;
/**
* a few MB? how about 16MB!
* a few MB? how about 24 MB!
* This is the max size of _inboundTagSets.
*/
public final static int MAX_INBOUND_SESSION_TAGS = 500 * 1000; // this will consume at most a few MB
public final static int MAX_INBOUND_SESSION_TAGS = 750 * 1000;
/**
* This was 100 since 0.6.1.10 (50 before that). It's important because:
@ -584,7 +584,7 @@ public class TransientSessionKeyManager extends SessionKeyManager {
int recent = 0;
int tags = 0;
int toRemove = overage * 2;
_log.log(Log.CRIT, "TOO MANY SESSION TAGS! Starting cleanup, overage = " + overage);
_log.logAlways(Log.WARN, "TOO MANY SESSION TAGS! Starting cleanup, overage = " + overage);
List<TagSet> removed = new ArrayList<TagSet>(toRemove);
synchronized (_inboundTagSets) {
for (TagSet set : _inboundTagSets.values()) {
@ -593,12 +593,18 @@ public class TransientSessionKeyManager extends SessionKeyManager {
absurd++;
if (size > 100)
large++;
if (now >= set.getDate())
if (set.getDate() - now < 3*60*1000) {
// expiration is 12 minutes, so these are older than 9 minutes
old++;
else if (set.getDate() - now > 10*60*1000)
removed.add(set);
continue;
} else if (set.getDate() - now > 8*60*1000) {
// expiration is 12 minutes, so these were created in last 4 minutes
recent++;
continue;
}
if ((removed.size() < (toRemove)) || (now >= set.getDate()))
if (removed.size() < toRemove)
removed.add(set);
}
for (int i = 0; i < removed.size(); i++) {
@ -609,11 +615,10 @@ public class TransientSessionKeyManager extends SessionKeyManager {
}
}
}
if (_log.shouldLog(Log.CRIT))
_log.log(Log.CRIT, "TOO MANY SESSION TAGS! removing " + removed
_log.logAlways(Log.WARN, "TOO MANY SESSION TAGS! removed " + removed.size()
+ " tag sets arbitrarily, with " + tags + " tags,"
+ "where there are " + old + " long lasting sessions, "
+ recent + " ones created in the last minute, and "
+ recent + " ones created in the last few minutes, and "
+ large + " sessions with more than 100 tags (and "
+ absurd + " with more than 1000!), leaving a total of "
+ _inboundTagSets.size() + " tags behind");

View File

@ -220,6 +220,11 @@ class OutboundClientMessageJobHelper {
ackClove.setId(ctx.random().nextLong(I2NPMessage.MAX_ID_VALUE));
DeliveryStatusMessage dsm = buildDSM(ctx, replyToken);
GarlicMessage msg = wrapDSM(ctx, skm, dsm);
if (msg == null) {
if (log.shouldLog(Log.WARN))
log.warn("Failed to wrap ack clove");
return null;
}
ackClove.setPayload(msg);
// this does nothing, the clove is not separately encrypted
//ackClove.setRecipient(ctx.router().getRouterInfo());

View File

@ -72,9 +72,9 @@ public class CreateRouterInfoJob extends JobImpl {
/**
* Writes 6 files: router.info (standard RI format),
* router.keys2, and 4 individual key files under keyBackup/
* router.keys.dat, and 4 individual key files under keyBackup/
*
* router.keys2 file format: This is the
* router.keys.dat file format: This is the
* same "eepPriv.dat" format used by the client code,
* as documented in PrivateKeyFile.
*

View File

@ -66,7 +66,7 @@ class LoadRouterInfoJob extends JobImpl {
}
/**
* Loads router.info and router.keys2 or router.keys.
* Loads router.info and either router.keys.dat or router.keys.
*
* See CreateRouterInfoJob for file formats
*/

View File

@ -121,6 +121,7 @@ class EstablishState {
private static final int HXY_SIZE = 32; //Hash.HASH_LENGTH;
private static final int HXY_TSB_PAD_SIZE = HXY_SIZE + 4 + 12; // 48
private static final Object _stateLock = new Object();
protected State _state;
private enum State {
@ -193,6 +194,13 @@ class EstablishState {
_curDecrypted = SimpleByteCache.acquire(AES_SIZE);
}
/** @since 0.9.16 */
private void changeState(State state) {
synchronized (_stateLock) {
_state = state;
}
}
/**
* parse the contents of the buffer as part of the handshake. if the
* handshake is completed and there is more data remaining, the data are
@ -203,8 +211,10 @@ class EstablishState {
* will return it to the pool.
*/
public synchronized void receive(ByteBuffer src) {
if (_state == State.VERIFIED || _state == State.CORRUPT)
throw new IllegalStateException(prefix() + "received unexpected data on " + _con);
synchronized(_stateLock) {
if (_state == State.VERIFIED || _state == State.CORRUPT)
throw new IllegalStateException(prefix() + "received unexpected data on " + _con);
}
if (!src.hasRemaining())
return; // nothing to receive
@ -229,6 +239,9 @@ class EstablishState {
* will return it to the pool.
*
* Caller must synch.
*
* FIXME none of the _state comparisons use _stateLock, but whole thing
* is synchronized, should be OK. See isComplete()
*/
private void receiveInbound(ByteBuffer src) {
while (_state == State.IB_INIT && src.hasRemaining()) {
@ -243,7 +256,7 @@ class EstablishState {
// }
//}
if (_received >= XY_SIZE)
_state = State.IB_GOT_X;
changeState(State.IB_GOT_X);
}
while (_state == State.IB_GOT_X && src.hasRemaining()) {
int i = _received - XY_SIZE;
@ -252,7 +265,7 @@ class EstablishState {
_hX_xor_bobIdentHash[i] = c;
//if (_log.shouldLog(Log.DEBUG)) _log.debug("recv bih" + (int)c + " received=" + _received);
if (i >= HXY_SIZE - 1)
_state = State.IB_GOT_HX;
changeState(State.IB_GOT_HX);
}
if (_state == State.IB_GOT_HX) {
@ -325,7 +338,7 @@ class EstablishState {
System.arraycopy(_e_hXY_tsB, 0, write, XY_SIZE, HXY_TSB_PAD_SIZE);
// ok, now that is prepared, we want to actually send it, so make sure we are up for writing
_state = State.IB_SENT_Y;
changeState(State.IB_SENT_Y);
_transport.getPumper().wantsWrite(_con, write);
if (!src.hasRemaining()) return;
} catch (DHSessionKeyBuilder.InvalidPublicParameterException e) {
@ -370,7 +383,7 @@ class EstablishState {
if (_log.shouldLog(Log.DEBUG))
_log.debug(prefix() + "got the RI size: " + sz);
_aliceIdentSize = sz;
_state = State.IB_GOT_RI_SIZE;
changeState(State.IB_GOT_RI_SIZE);
// We must defer the calculations for total size of the message until
// we get the full alice ident so
@ -401,7 +414,7 @@ class EstablishState {
fail("Unsupported sig type");
return;
}
_state = State.IB_GOT_RI;
changeState(State.IB_GOT_RI);
// handle variable signature size
_sz_aliceIdent_tsA_padding_aliceSigSize = 2 + _aliceIdentSize + 4 + type.getSigLen();
int rem = (_sz_aliceIdent_tsA_padding_aliceSigSize % AES_SIZE);
@ -453,6 +466,9 @@ class EstablishState {
* will return it to the pool.
*
* Caller must synch.
*
* FIXME none of the _state comparisons use _stateLock, but whole thing
* is synchronized, should be OK. See isComplete()
*/
private void receiveOutbound(ByteBuffer src) {
// recv Y+E(H(X+Y)+tsB, sk, Y[239:255])
@ -466,7 +482,7 @@ class EstablishState {
_dh.getSessionKey(); // force the calc
if (_log.shouldLog(Log.DEBUG))
_log.debug(prefix()+"DH session key calculated (" + _dh.getSessionKey().toBase64() + ")");
_state = State.OB_GOT_Y;
changeState(State.OB_GOT_Y);
} catch (DHSessionKeyBuilder.InvalidPublicParameterException e) {
_context.statManager().addRateData("ntcp.invalidDH", 1);
fail("Invalid X", e);
@ -500,7 +516,7 @@ class EstablishState {
return;
}
SimpleByteCache.release(h);
_state = State.OB_GOT_HXY;
changeState(State.OB_GOT_HXY);
_tsB = DataHelper.fromLong(hXY_tsB, HXY_SIZE, 4); // their (Bob's) timestamp in seconds
_tsA = (_context.clock().now() + 500) / 1000; // our (Alice's) timestamp in seconds
if (_log.shouldLog(Log.DEBUG))
@ -573,7 +589,7 @@ class EstablishState {
//_log.debug(prefix() + "encrypted response to Bob: " + Base64.encode(_prevEncrypted));
//}
// send 'er off (when the bw limiter says, etc)
_state = State.OB_SENT_RI;
changeState(State.OB_SENT_RI);
_transport.getPumper().wantsWrite(_con, _prevEncrypted);
}
}
@ -607,7 +623,7 @@ class EstablishState {
_received++;
if (off >= _e_bobSig.length) {
_state = State.OB_GOT_SIG;
changeState(State.OB_GOT_SIG);
//if (_log.shouldLog(Log.DEBUG))
// _log.debug(prefix() + "received E(S(X+Y+Alice.identHash+tsA+tsB)+padding, sk, prev): " + Base64.encode(_e_bobSig));
byte bobSig[] = new byte[_e_bobSig.length];
@ -634,7 +650,6 @@ class EstablishState {
_context.statManager().addRateData("ntcp.invalidSignature", 1);
fail("Signature was invalid - attempt to spoof " + _con.getRemotePeer().calculateHash().toBase64() + "?");
} else {
_state = State.VERIFIED;
if (_log.shouldLog(Log.DEBUG))
_log.debug(prefix() + "signature verified from Bob. done!");
prepareExtra(src);
@ -642,11 +657,12 @@ class EstablishState {
System.arraycopy(_prevEncrypted, _prevEncrypted.length-AES_SIZE, nextWriteIV, 0, AES_SIZE);
// this does not copy the nextWriteIV, do not release to cache
_con.finishOutboundEstablishment(_dh.getSessionKey(), (_tsA-_tsB), nextWriteIV, _e_bobSig); // skew in seconds
releaseBufs();
releaseBufs(true);
// if socket gets closed this will be null - prevent NPE
InetAddress ia = _con.getChannel().socket().getInetAddress();
if (ia != null)
_transport.setIP(_con.getRemotePeer().calculateHash(), ia.getAddress());
changeState(State.VERIFIED);
}
return;
}
@ -655,10 +671,24 @@ class EstablishState {
}
/** did the handshake fail for some reason? */
public synchronized boolean isCorrupt() { return _state == State.CORRUPT; }
public boolean isCorrupt() {
synchronized(_stateLock) {
return _state == State.CORRUPT;
}
}
/** @return is the handshake complete and valid? */
public synchronized boolean isComplete() { return _state == State.VERIFIED; }
/**
* If synchronized on this, fails with
* deadlocks from all over via CSFI.isEstablished().
* Also CSFI.getFramedAveragePeerClockSkew().
*
* @return is the handshake complete and valid?
*/
public boolean isComplete() {
synchronized(_stateLock) {
return _state == State.VERIFIED;
}
}
/**
* We are Alice.
@ -667,13 +697,17 @@ class EstablishState {
* This method sends message #1 to Bob.
*/
public synchronized void prepareOutbound() {
if (_state == State.OB_INIT) {
boolean shouldSend;
synchronized(_stateLock) {
shouldSend = _state == State.OB_INIT;
}
if (shouldSend) {
if (_log.shouldLog(Log.DEBUG))
_log.debug(prefix() + "send X");
byte toWrite[] = new byte[XY_SIZE + _hX_xor_bobIdentHash.length];
System.arraycopy(_X, 0, toWrite, 0, XY_SIZE);
System.arraycopy(_hX_xor_bobIdentHash, 0, toWrite, XY_SIZE, _hX_xor_bobIdentHash.length);
_state = State.OB_SENT_X;
changeState(State.OB_SENT_X);
_transport.getPumper().wantsWrite(_con, toWrite);
} else {
if (_log.shouldLog(Log.WARN))
@ -815,7 +849,6 @@ class EstablishState {
_log.debug(prefix()+"Clock skew: " + diff + " ms");
}
_state = State.VERIFIED;
sendInboundConfirm(_aliceIdent, tsA);
_con.setRemotePeer(_aliceIdent);
if (_log.shouldLog(Log.DEBUG))
@ -824,9 +857,10 @@ class EstablishState {
System.arraycopy(_e_bobSig, _e_bobSig.length-AES_SIZE, iv, 0, AES_SIZE);
// this does not copy the IV, do not release to cache
_con.finishInboundEstablishment(_dh.getSessionKey(), (tsA-_tsB), iv, _prevEncrypted); // skew in seconds
releaseBufs();
releaseBufs(true);
if (_log.shouldLog(Log.INFO))
_log.info(prefix()+"Verified remote peer as " + _aliceIdent.calculateHash());
changeState(State.VERIFIED);
} else {
_context.statManager().addRateData("ntcp.invalidInboundSignature", 1);
fail("Peer verification failed - spoof of " + _aliceIdent.calculateHash() + "?");
@ -917,28 +951,30 @@ class EstablishState {
/** Caller must synch. */
private void fail(String reason, Exception e, boolean bySkew) {
if (_state == State.CORRUPT || _state == State.VERIFIED)
return;
_state = State.CORRUPT;
synchronized(_stateLock) {
if (_state == State.CORRUPT || _state == State.VERIFIED)
return;
changeState(State.CORRUPT);
}
_failedBySkew = bySkew;
_err = reason;
_e = e;
if (_log.shouldLog(Log.WARN))
_log.warn(prefix()+"Failed to establish: " + _err, e);
releaseBufs();
releaseBufs(false);
}
/**
* Only call once. Caller must synch.
* @since 0.9.16
*/
private void releaseBufs() {
private void releaseBufs(boolean isVerified) {
// null or longer for OB
if (_prevEncrypted != null && _prevEncrypted.length == AES_SIZE)
SimpleByteCache.release(_prevEncrypted);
// Do not release _curEncrypted if verified, it is passed to
// NTCPConnection to use as the IV
if (_state != State.VERIFIED)
if (!isVerified)
SimpleByteCache.release(_curEncrypted);
SimpleByteCache.release(_curDecrypted);
SimpleByteCache.release(_hX_xor_bobIdentHash);

View File

@ -958,8 +958,8 @@ class EstablishmentManager {
if (!oldId.equals(newId)) {
_outboundStates.remove(oldId);
_outboundStates.put(newId, state);
if (_log.shouldLog(Log.WARN))
_log.warn("RR replaced " + oldId + " with " + newId + ", claimed address was " + claimed);
if (_log.shouldLog(Log.INFO))
_log.info("RR replaced " + oldId + " with " + newId + ", claimed address was " + claimed);
}
//
if (claimed != null)
@ -980,17 +980,17 @@ class EstablishmentManager {
if (state != null) {
boolean sendNow = state.receiveHolePunch();
if (sendNow) {
if (_log.shouldLog(Log.WARN))
_log.warn("Hole punch from " + state + ", sending SessionRequest now");
if (_log.shouldLog(Log.INFO))
_log.info("Hole punch from " + state + ", sending SessionRequest now");
notifyActivity();
} else {
if (_log.shouldLog(Log.WARN))
_log.warn("Hole punch from " + state + ", already sent SessionRequest");
if (_log.shouldLog(Log.INFO))
_log.info("Hole punch from " + state + ", already sent SessionRequest");
}
} else {
// HolePunch received before RelayResponse, and we didn't know the IP/port, or it changed
if (_log.shouldLog(Log.WARN))
_log.warn("No state found for hole punch from " + from + " port " + fromPort);
if (_log.shouldLog(Log.INFO))
_log.info("No state found for hole punch from " + from + " port " + fromPort);
}
}

View File

@ -72,10 +72,14 @@ class InboundMessageState implements CDQEntry {
_log = ctx.logManager().getLog(InboundMessageState.class);
_messageId = messageId;
_from = from;
if (data.readMessageIsLast(dataFragment))
_fragments = new ByteArray[1 + data.readMessageFragmentNum(dataFragment)];
else
if (data.readMessageIsLast(dataFragment)) {
int num = 1 + data.readMessageFragmentNum(dataFragment);
if (num > MAX_FRAGMENTS)
throw new DataFormatException("corrupt - too many fragments: " + num);
_fragments = new ByteArray[num];
} else {
_fragments = new ByteArray[MAX_FRAGMENTS];
}
_lastFragment = -1;
_completeSize = -1;
_receiveBegin = ctx.clock().now();
@ -222,8 +226,10 @@ class InboundMessageState implements CDQEntry {
return _completeSize;
}
/** FIXME synch here or PeerState.fetchPartialACKs() */
public ACKBitfield createACKBitfield() {
int sz = (_lastFragment >= 0) ? _lastFragment + 1 : _fragments.length;
int last = _lastFragment;
int sz = (last >= 0) ? last + 1 : _fragments.length;
return new PartialBitfield(_messageId, _fragments, sz);
}

View File

@ -221,7 +221,7 @@ class OutboundEstablishState {
return _sentX;
}
/**x
/**
* The remote side (Bob) - note that in some places he's called Charlie.
* Warning - may change after introduction. May be null before introduction.
*/
@ -618,8 +618,8 @@ class OutboundEstablishState {
if (_requestSentCount > 0)
return false;
long now = _context.clock().now();
if (_log.shouldLog(Log.WARN))
_log.warn(toString() + " accelerating SessionRequest by " + (_nextSend - now) + " ms");
if (_log.shouldLog(Log.INFO))
_log.info(toString() + " accelerating SessionRequest by " + (_nextSend - now) + " ms");
_nextSend = now;
return true;
}

View File

@ -434,7 +434,9 @@ class PacketBuilder {
off += 4;
for (int curByte = 0; curByte < size; curByte++) {
if (curByte + 1 < size)
data[off] |= (byte)(1 << 7);
data[off] = (byte)(1 << 7);
else
data[off] = 0;
for (int curBit = 0; curBit < 7; curBit++) {
if (bitfield.received(curBit + 7*curByte))
@ -467,7 +469,7 @@ class PacketBuilder {
DataHelper.toLong(data, off, 4, state.getMessageId());
off += 4;
data[off] |= fragment << 1;
data[off] = (byte) (fragment << 1);
if (fragment == state.getFragmentCount() - 1)
data[off] |= 1; // isLast
off++;
@ -621,8 +623,7 @@ class PacketBuilder {
off++;
for (int i = 0; i < ackBitfields.size(); i++) {
ACKBitfield bitfield = ackBitfields.get(i);
// no, this will corrupt the packet
//if (bitfield.receivedComplete()) continue;
if (bitfield.receivedComplete()) continue;
DataHelper.toLong(data, off, 4, bitfield.getMessageId());
off += 4;
// only send what we have to
@ -633,7 +634,9 @@ class PacketBuilder {
size++;
for (int curByte = 0; curByte < size; curByte++) {
if (curByte + 1 < size)
data[off] |= (byte)(1 << 7);
data[off] = (byte)(1 << 7);
else
data[off] = 0;
for (int curBit = 0; curBit < 7; curBit++) {
if (bitfield.received(curBit + 7*curByte))
@ -878,7 +881,7 @@ class PacketBuilder {
}
// now for the body
data[off] |= fragmentNum << 4;
data[off] = (byte) (fragmentNum << 4);
data[off] |= (numFragments & 0xF);
off++;