propagate from branch 'i2p.i2p' (head bde4ef3680071b416b3528bad4c16245964f432a)

to branch 'i2p.i2p.zzz.test2' (head 183d2a30edd10165451d0cbbf75636f3b1dfda16)
This commit is contained in:
zzz
2014-11-15 17:48:39 +00:00
185 changed files with 63189 additions and 46431 deletions

View File

@@ -70,8 +70,7 @@ public class DataMessage extends FastI2NPMessageImpl {
out[curIndex++] = 0x0;
out[curIndex++] = 0x0;
} else {
byte len[] = DataHelper.toLong(4, _data.length);
System.arraycopy(len, 0, out, curIndex, 4);
DataHelper.toLong(out, curIndex, 4, _data.length);
curIndex += 4;
System.arraycopy(_data, 0, out, curIndex, _data.length);
curIndex += _data.length;

View File

@@ -404,33 +404,33 @@ public class DatabaseLookupMessage extends FastI2NPMessageImpl {
System.arraycopy(_fromHash.getData(), 0, out, curIndex, Hash.HASH_LENGTH);
curIndex += Hash.HASH_LENGTH;
// Generate the flag byte
byte flag;
if (_replyKey != null)
flag = FLAG_ENCRYPT;
else
flag = 0;
switch (_type) {
case LS:
flag |= FLAG_TYPE_LS;
break;
case RI:
flag |= FLAG_TYPE_RI;
break;
case EXPL:
flag |= FLAG_TYPE_EXPL;
break;
case ANY:
default:
// lookup type bits are 0
break;
}
if (_replyTunnel != null) {
byte flag = FLAG_TUNNEL;
if (_replyKey != null)
flag |= FLAG_ENCRYPT;
switch (_type) {
case LS:
flag |= FLAG_TYPE_LS;
break;
case RI:
flag |= FLAG_TYPE_RI;
break;
case EXPL:
flag |= FLAG_TYPE_EXPL;
break;
case ANY:
default:
// flag is 0
break;
}
flag |= FLAG_TUNNEL;
out[curIndex++] = flag;
byte id[] = DataHelper.toLong(4, _replyTunnel.getTunnelId());
System.arraycopy(id, 0, out, curIndex, 4);
DataHelper.toLong(out, curIndex, 4, _replyTunnel.getTunnelId());
curIndex += 4;
} else if (_replyKey != null) {
out[curIndex++] = FLAG_ENCRYPT;
} else {
out[curIndex++] = 0x00;
out[curIndex++] = flag;
}
if ( (_dontIncludePeers == null) || (_dontIncludePeers.isEmpty()) ) {
out[curIndex++] = 0x0;
@@ -439,9 +439,8 @@ public class DatabaseLookupMessage extends FastI2NPMessageImpl {
int size = _dontIncludePeers.size();
if (size > MAX_NUM_PEERS)
throw new I2NPMessageException("Too many peers: " + size);
byte len[] = DataHelper.toLong(2, size);
out[curIndex++] = len[0];
out[curIndex++] = len[1];
DataHelper.toLong(out, curIndex, 2, size);
curIndex += 2;
for (Hash peer : _dontIncludePeers) {
System.arraycopy(peer.getData(), 0, out, curIndex, Hash.HASH_LENGTH);
curIndex += Hash.HASH_LENGTH;

View File

@@ -103,8 +103,8 @@ public class DatabaseSearchReplyMessage extends FastI2NPMessageImpl {
System.arraycopy(_key.getData(), 0, out, curIndex, Hash.HASH_LENGTH);
curIndex += Hash.HASH_LENGTH;
byte len[] = DataHelper.toLong(1, _peerHashes.size());
out[curIndex++] = len[0];
DataHelper.toLong(out, curIndex, 1, _peerHashes.size());
curIndex++;
for (int i = 0; i < getNumReplies(); i++) {
System.arraycopy(getReply(i).getData(), 0, out, curIndex, Hash.HASH_LENGTH);
curIndex += Hash.HASH_LENGTH;

View File

@@ -204,16 +204,14 @@ public class DatabaseStoreMessage extends FastI2NPMessageImpl {
System.arraycopy(getKey().getData(), 0, out, curIndex, Hash.HASH_LENGTH);
curIndex += Hash.HASH_LENGTH;
out[curIndex++] = (byte) type;
byte tok[] = DataHelper.toLong(4, _replyToken);
System.arraycopy(tok, 0, out, curIndex, 4);
DataHelper.toLong(out, curIndex, 4, _replyToken);
curIndex += 4;
if (_replyToken > 0) {
long replyTunnel = 0;
if (_replyTunnel != null)
replyTunnel = _replyTunnel.getTunnelId();
byte id[] = DataHelper.toLong(4, replyTunnel);
System.arraycopy(id, 0, out, curIndex, 4);
DataHelper.toLong(out, curIndex, 4, replyTunnel);
curIndex += 4;
System.arraycopy(_replyGateway.getData(), 0, out, curIndex, Hash.HASH_LENGTH);
curIndex += Hash.HASH_LENGTH;
@@ -221,9 +219,8 @@ public class DatabaseStoreMessage extends FastI2NPMessageImpl {
// _byteCache initialized in calculateWrittenLength
if (type == DatabaseEntry.KEY_TYPE_ROUTERINFO) {
byte len[] = DataHelper.toLong(2, _byteCache.length);
out[curIndex++] = len[0];
out[curIndex++] = len[1];
DataHelper.toLong(out, curIndex, 2, _byteCache.length);
curIndex += 2;
}
System.arraycopy(_byteCache, 0, out, curIndex, _byteCache.length);
curIndex += _byteCache.length;

View File

@@ -54,8 +54,7 @@ public class GarlicMessage extends FastI2NPMessageImpl {
}
/** write the message body to the output array, starting at the given index */
protected int writeMessageBody(byte out[], int curIndex) throws I2NPMessageException {
byte len[] = DataHelper.toLong(4, _data.length);
System.arraycopy(len, 0, out, curIndex, 4);
DataHelper.toLong(out, curIndex, 4, _data.length);
curIndex += 4;
System.arraycopy(_data, 0, out, curIndex, _data.length);
curIndex += _data.length;

View File

@@ -113,7 +113,7 @@ public class RouterInfo extends DatabaseEntry {
return _published;
}
protected KeysAndCert getKeysAndCert() {
public KeysAndCert getKeysAndCert() {
return _identity;
}

View File

@@ -25,13 +25,18 @@ import java.util.concurrent.ConcurrentHashMap;
import gnu.getopt.Getopt;
import net.i2p.crypto.SigUtil;
import net.i2p.data.Base64;
import net.i2p.data.Certificate;
import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper;
import net.i2p.data.Destination;
import net.i2p.data.router.RouterInfo;
import net.i2p.data.Hash;
import net.i2p.data.PublicKey;
import net.i2p.data.SigningPrivateKey;
import net.i2p.data.SigningPublicKey;
import net.i2p.data.i2np.GarlicMessage;
import net.i2p.data.router.RouterInfo;
import net.i2p.router.message.GarlicMessageHandler;
import net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade;
import net.i2p.router.startup.CreateRouterInfoJob;
@@ -101,6 +106,8 @@ public class Router implements RouterClock.ClockShiftListener {
public final static String PROP_HIDDEN_HIDDEN = "router.isHidden";
public final static String PROP_DYNAMIC_KEYS = "router.dynamicKeys";
public final static String PROP_SHUTDOWN_IN_PROGRESS = "__shutdownInProgress";
private static final String PROP_IB_RANDOM_KEY = TunnelPoolSettings.PREFIX_INBOUND_EXPLORATORY + TunnelPoolSettings.PROP_RANDOM_KEY;
private static final String PROP_OB_RANDOM_KEY = TunnelPoolSettings.PREFIX_OUTBOUND_EXPLORATORY + TunnelPoolSettings.PROP_RANDOM_KEY;
public final static String DNS_CACHE_TIME = "" + (5*60);
private static final String EVENTLOG = "eventlog.txt";
private static final String PROP_JBIGI = "jbigi.loadedResource";
@@ -343,6 +350,10 @@ public class Router implements RouterClock.ClockShiftListener {
SimpleByteCache.clearAll();
Destination.clearCache();
Translate.clearCache();
Hash.clearCache();
PublicKey.clearCache();
SigningPublicKey.clearCache();
SigUtil.clearCaches();
}
/**
@@ -486,6 +497,18 @@ public class Router implements RouterClock.ClockShiftListener {
//_sessionKeyPersistenceHelper.startup();
//_context.adminManager().startup();
_context.blocklist().startup();
synchronized(_configFileLock) {
// persistent key for peer ordering since 0.9.17
if (!_config.containsKey(PROP_IB_RANDOM_KEY)) {
byte rk[] = new byte[32];
_context.random().nextBytes(rk);
_config.put(PROP_IB_RANDOM_KEY, Base64.encode(rk));
_context.random().nextBytes(rk);
_config.put(PROP_OB_RANDOM_KEY, Base64.encode(rk));
saveConfig();
}
}
// let the timestamper get us sync'ed
// this will block for quite a while on a disconnected machine
@@ -711,9 +734,11 @@ public class Router implements RouterClock.ClockShiftListener {
}
// now that we have random ports, keeping the same port would be bad
synchronized(this) {
synchronized(_configFileLock) {
removeConfigSetting(UDPTransport.PROP_INTERNAL_PORT);
removeConfigSetting(UDPTransport.PROP_EXTERNAL_PORT);
removeConfigSetting(PROP_IB_RANDOM_KEY);
removeConfigSetting(PROP_OB_RANDOM_KEY);
saveConfig();
}
}

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 = 6;
/** for example "-test" */
public final static String EXTRA = "";

View File

@@ -4,6 +4,7 @@ import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import net.i2p.data.Base64;
import net.i2p.data.Hash;
import net.i2p.util.NativeBigInteger;
import net.i2p.util.RandomSource;
@@ -28,7 +29,7 @@ public class TunnelPoolSettings {
private boolean _allowZeroHop;
private int _IPRestriction;
private final Properties _unknownOptions;
private final Hash _randomKey;
private Hash _randomKey;
private int _priority;
/** prefix used to override the router's defaults for clients */
@@ -51,6 +52,8 @@ public class TunnelPoolSettings {
public static final String PROP_ALLOW_ZERO_HOP = "allowZeroHop";
public static final String PROP_IP_RESTRICTION = "IPRestriction";
public static final String PROP_PRIORITY = "priority";
/** @since 0.9.17 */
public static final String PROP_RANDOM_KEY = "randomKey";
public static final int DEFAULT_QUANTITY = 2;
public static final int DEFAULT_BACKUP_QUANTITY = 0;
@@ -204,7 +207,11 @@ public class TunnelPoolSettings {
/** what destination is this a client tunnel for (or null if exploratory) */
public Hash getDestination() { return _destination; }
/** random key used for peer ordering */
/**
* random key used for peer ordering
*
* @return non-null
*/
public Hash getRandomKey() { return _randomKey; }
/** what user supplied name was given to the client connected (can be null) */
@@ -265,6 +272,10 @@ public class TunnelPoolSettings {
int def = _isExploratory ? EXPLORATORY_PRIORITY : 0;
int max = _isExploratory ? EXPLORATORY_PRIORITY : MAX_PRIORITY;
_priority = Math.min(max, Math.max(MIN_PRIORITY, getInt(value, def)));
} else if (name.equalsIgnoreCase(prefix + PROP_RANDOM_KEY)) {
byte[] rk = Base64.decode(value);
if (rk != null && rk.length == Hash.HASH_LENGTH)
_randomKey = new Hash(rk);
} else
_unknownOptions.setProperty(name.substring(prefix.length()), value);
}

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

@@ -1334,12 +1334,13 @@ public class ProfileOrganizer {
* others.
* @return 0-3
*/
private static int getSubTier(Hash peer, Hash randomKey) {
byte[] data = new byte[Hash.HASH_LENGTH + 4];
private int getSubTier(Hash peer, Hash randomKey) {
// input is first 36 bytes; output is last 32 bytes
byte[] data = new byte[Hash.HASH_LENGTH + 4 + Hash.HASH_LENGTH];
System.arraycopy(peer.getData(), 0, data, 0, Hash.HASH_LENGTH);
System.arraycopy(randomKey.getData(), 0, data, Hash.HASH_LENGTH, 4);
Hash rh = SHA256Generator.getInstance().calculateHash(data);
return rh.getData()[0] & 0x03;
_context.sha().calculateHash(data, 0, Hash.HASH_LENGTH + 4, data, Hash.HASH_LENGTH + 4);
return data[Hash.HASH_LENGTH + 4] & 0x03;
}
public boolean isSelectable(Hash peer) {

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

@@ -23,6 +23,7 @@ import java.util.TreeSet;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;
import net.i2p.crypto.SigType;
import net.i2p.data.DataHelper;
import net.i2p.data.Hash;
import net.i2p.data.router.RouterAddress;
@@ -47,6 +48,7 @@ import net.i2p.util.ConcurrentHashSet;
import net.i2p.util.Log;
import net.i2p.util.OrderedProperties;
import net.i2p.util.SystemVersion;
import net.i2p.util.VersionComparator;
/**
* The NIO TCP transport
@@ -101,6 +103,12 @@ public class NTCPTransport extends TransportImpl {
//private static final String THINSP = "&thinsp;/&thinsp;";
private static final String THINSP = " / ";
/**
* RI sigtypes supported in 0.9.16
*/
private static final String MIN_SIGTYPE_VERSION = "0.9.16";
public NTCPTransport(RouterContext ctx, DHSessionKeyBuilder.Factory dh) {
super(ctx);
_dhFactory = dh;
@@ -356,11 +364,25 @@ public class NTCPTransport extends TransportImpl {
}
// Check for supported sig type
if (toAddress.getIdentity().getSigningPublicKey().getType() == null) {
SigType type = toAddress.getIdentity().getSigType();
if (type == null || !type.isAvailable()) {
markUnreachable(peer);
return null;
}
// Can we connect to them if we are not DSA?
RouterInfo us = _context.router().getRouterInfo();
if (us != null) {
RouterIdentity id = us.getIdentity();
if (id.getSigType() != SigType.DSA_SHA1) {
String v = toAddress.getOption("router.version");
if (v != null && VersionComparator.comp(v, MIN_SIGTYPE_VERSION) < 0) {
markUnreachable(peer);
return null;
}
}
}
if (!allowConnection()) {
if (_log.shouldLog(Log.WARN))
_log.warn("no bid when trying to send to " + peer + ", max connection limit reached");

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

@@ -448,7 +448,7 @@ class InboundEstablishState {
DataHelper.toLong(signed, off, 4, _sentRelayTag);
off += 4;
DataHelper.toLong(signed, off, 4, _receivedSignedOnTime);
Signature sig = new Signature(_receivedSignature);
Signature sig = new Signature(_receivedUnconfirmedIdentity.getSigType(), _receivedSignature);
boolean ok = _context.dsa().verifySignature(sig, signed, _receivedUnconfirmedIdentity.getSigningPublicKey());
if (ok) {
// todo partial spoof detection - get peer.calculateHash(),

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++;

View File

@@ -7,6 +7,7 @@ import java.util.Map;
import net.i2p.data.Base64;
import net.i2p.data.router.RouterAddress;
import net.i2p.data.SessionKey;
import net.i2p.router.transport.TransportUtil;
import net.i2p.util.LHMCache;
import net.i2p.util.SystemVersion;
@@ -100,7 +101,7 @@ class UDPAddress {
int p;
try {
p = Integer.parseInt(port);
if (p < UDPTransport.MIN_PEER_PORT || p > 65535) continue;
if (!TransportUtil.isValidPort(p)) continue;
} catch (NumberFormatException nfe) {
continue;
}

View File

@@ -22,6 +22,7 @@ import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import net.i2p.crypto.SigType;
import net.i2p.data.DatabaseEntry;
import net.i2p.data.DataHelper;
import net.i2p.data.Hash;
@@ -51,6 +52,7 @@ import net.i2p.util.Log;
import net.i2p.util.OrderedProperties;
import net.i2p.util.SimpleTimer;
import net.i2p.util.SimpleTimer2;
import net.i2p.util.VersionComparator;
/**
* The SSU transport
@@ -198,6 +200,13 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
//private static final String THINSP = "&thinsp;/&thinsp;";
private static final String THINSP = " / ";
/**
* RI sigtypes supported in 0.9.16, but due to a bug in InboundEstablishState
* fixed in 0.9.17, we cannot connect out to routers before that version.
*/
private static final String MIN_SIGTYPE_VERSION = "0.9.17";
public UDPTransport(RouterContext ctx, DHSessionKeyBuilder.Factory dh) {
super(ctx);
_dhFactory = dh;
@@ -1558,11 +1567,25 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
}
// Check for supported sig type
if (toAddress.getIdentity().getSigningPublicKey().getType() == null) {
SigType type = toAddress.getIdentity().getSigType();
if (type == null || !type.isAvailable()) {
markUnreachable(to);
return null;
}
// Can we connect to them if we are not DSA?
RouterInfo us = _context.router().getRouterInfo();
if (us != null) {
RouterIdentity id = us.getIdentity();
if (id.getSigType() != SigType.DSA_SHA1) {
String v = toAddress.getOption("router.version");
if (v != null && VersionComparator.comp(v, MIN_SIGTYPE_VERSION) < 0) {
markUnreachable(to);
return null;
}
}
}
if (!allowConnection())
return _cachedBid[TRANSIENT_FAIL_BID];