propagate from branch 'i2p.i2p.zzz.test2' (head 0feb2e6806927f68c7333aaa0892de185bb2629c)

to branch 'i2p.i2p' (head 0482fa843cb1e9d7ec281440056eef3a0ab07bdb)
This commit is contained in:
zzz
2014-12-05 15:14:40 +00:00
55 changed files with 666 additions and 295 deletions

View File

@@ -2,6 +2,7 @@ package net.i2p.data.i2np;
import net.i2p.I2PAppContext;
import net.i2p.data.ByteArray;
import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper;
import net.i2p.data.Hash;
import net.i2p.data.PrivateKey;
@@ -9,7 +10,8 @@ import net.i2p.data.PublicKey;
import net.i2p.data.SessionKey;
/**
* Hold the tunnel request record, managing its ElGamal encryption and decryption.
* Holds the unencrypted 222-byte tunnel request record,
* with a constructor for ElGamal decryption and a method for ElGamal encryption.
* Iterative AES encryption/decryption is done elsewhere.
*
* Cleartext:
@@ -36,7 +38,7 @@ import net.i2p.data.SessionKey;
*
*/
public class BuildRequestRecord {
private ByteArray _data;
private final byte[] _data;
/**
* If set in the flag byte, any peer may send a message into this tunnel, but if
@@ -55,11 +57,10 @@ public class BuildRequestRecord {
/** we show 16 bytes of the peer hash outside the elGamal block */
public static final int PEER_SIZE = 16;
public BuildRequestRecord(ByteArray data) { _data = data; }
public BuildRequestRecord() { }
public ByteArray getData() { return _data; }
public void setData(ByteArray data) { _data = data; }
/**
* @return 222 bytes, non-null
*/
public byte[] getData() { return _data; }
private static final int OFF_RECV_TUNNEL = 0;
private static final int OFF_OUR_IDENT = OFF_RECV_TUNNEL + 4;
@@ -72,91 +73,101 @@ public class BuildRequestRecord {
private static final int OFF_FLAG = OFF_REPLY_IV + IV_SIZE;
private static final int OFF_REQ_TIME = OFF_FLAG + 1;
private static final int OFF_SEND_MSG_ID = OFF_REQ_TIME + 4;
private static final int PADDING_SIZE = 29;
// 222
private static final int LENGTH = OFF_SEND_MSG_ID + 4 + PADDING_SIZE;
/** what tunnel ID should this receive messages on */
public long readReceiveTunnelId() {
return DataHelper.fromLong(_data.getData(), _data.getOffset() + OFF_RECV_TUNNEL, 4);
}
/** true if the identity they expect us to be is who we are */
public boolean readOurIdentityMatches(Hash ourIdentity) {
return DataHelper.eq(ourIdentity.getData(), 0, _data.getData(), _data.getOffset() + OFF_OUR_IDENT, Hash.HASH_LENGTH);
return DataHelper.fromLong(_data, OFF_RECV_TUNNEL, 4);
}
/**
* What tunnel ID the next hop receives messages on. If this is the outbound tunnel endpoint,
* this specifies the tunnel ID to which the reply should be sent.
*/
public long readNextTunnelId() {
return DataHelper.fromLong(_data.getData(), _data.getOffset() + OFF_SEND_TUNNEL, 4);
return DataHelper.fromLong(_data, OFF_SEND_TUNNEL, 4);
}
/**
* Read the next hop from the record. If this is the outbound tunnel endpoint, this specifies
* the gateway to which the reply should be sent.
*/
public Hash readNextIdentity() {
//byte rv[] = new byte[Hash.HASH_LENGTH];
//System.arraycopy(_data.getData(), _data.getOffset() + OFF_SEND_IDENT, rv, 0, Hash.HASH_LENGTH);
//System.arraycopy(_data, OFF_SEND_IDENT, rv, 0, Hash.HASH_LENGTH);
//return new Hash(rv);
return Hash.create(_data.getData(), _data.getOffset() + OFF_SEND_IDENT);
return Hash.create(_data, OFF_SEND_IDENT);
}
/**
* Tunnel layer encryption key that the current hop should use
*/
public SessionKey readLayerKey() {
byte key[] = new byte[SessionKey.KEYSIZE_BYTES];
System.arraycopy(_data.getData(), _data.getOffset() + OFF_LAYER_KEY, key, 0, SessionKey.KEYSIZE_BYTES);
System.arraycopy(_data, OFF_LAYER_KEY, key, 0, SessionKey.KEYSIZE_BYTES);
return new SessionKey(key);
}
/**
* Tunnel IV encryption key that the current hop should use
*/
public SessionKey readIVKey() {
byte key[] = new byte[SessionKey.KEYSIZE_BYTES];
System.arraycopy(_data.getData(), _data.getOffset() + OFF_IV_KEY, key, 0, SessionKey.KEYSIZE_BYTES);
System.arraycopy(_data, OFF_IV_KEY, key, 0, SessionKey.KEYSIZE_BYTES);
return new SessionKey(key);
}
/**
* Session key that should be used to encrypt the reply
*/
public SessionKey readReplyKey() {
byte key[] = new byte[SessionKey.KEYSIZE_BYTES];
System.arraycopy(_data.getData(), _data.getOffset() + OFF_REPLY_KEY, key, 0, SessionKey.KEYSIZE_BYTES);
System.arraycopy(_data, OFF_REPLY_KEY, key, 0, SessionKey.KEYSIZE_BYTES);
return new SessionKey(key);
}
/**
* IV that should be used to encrypt the reply
*/
public byte[] readReplyIV() {
byte iv[] = new byte[IV_SIZE];
System.arraycopy(_data.getData(), _data.getOffset() + OFF_REPLY_IV, iv, 0, IV_SIZE);
System.arraycopy(_data, OFF_REPLY_IV, iv, 0, IV_SIZE);
return iv;
}
/**
* The current hop is the inbound gateway. If this is true, it means anyone can send messages to
* this tunnel, but if it is false, only the current predecessor can.
*
*/
public boolean readIsInboundGateway() {
return (_data.getData()[_data.getOffset() + OFF_FLAG] & FLAG_UNRESTRICTED_PREV) != 0;
return (_data[OFF_FLAG] & FLAG_UNRESTRICTED_PREV) != 0;
}
/**
* The current hop is the outbound endpoint. If this is true, the next identity and next tunnel
* fields refer to where the reply should be sent.
*/
public boolean readIsOutboundEndpoint() {
return (_data.getData()[_data.getOffset() + OFF_FLAG] & FLAG_OUTBOUND_ENDPOINT) != 0;
return (_data[OFF_FLAG] & FLAG_OUTBOUND_ENDPOINT) != 0;
}
/**
* Time that the request was sent (ms), truncated to the nearest hour
*/
public long readRequestTime() {
return DataHelper.fromLong(_data.getData(), _data.getOffset() + OFF_REQ_TIME, 4) * (60 * 60 * 1000L);
return DataHelper.fromLong(_data, OFF_REQ_TIME, 4) * (60 * 60 * 1000L);
}
/**
* What message ID should we send the request to the next hop with. If this is the outbound tunnel endpoint,
* this specifies the message ID with which the reply should be sent.
*/
public long readReplyMessageId() {
return DataHelper.fromLong(_data.getData(), _data.getOffset() + OFF_SEND_MSG_ID, 4);
return DataHelper.fromLong(_data, OFF_SEND_MSG_ID, 4);
}
/**
@@ -164,42 +175,43 @@ public class BuildRequestRecord {
* bytes 0-15: truncated SHA-256 of the current hop's identity (the toPeer parameter)
* bytes 15-527: ElGamal-2048 encrypted block
* </pre>
*
* @return non-null
*/
public void encryptRecord(I2PAppContext ctx, PublicKey toKey, Hash toPeer, byte out[], int outOffset) {
System.arraycopy(toPeer.getData(), 0, out, outOffset, PEER_SIZE);
byte preEncr[] = new byte[OFF_SEND_MSG_ID + 4 + PADDING_SIZE];
System.arraycopy(_data.getData(), _data.getOffset(), preEncr, 0, preEncr.length);
byte encrypted[] = ctx.elGamalEngine().encrypt(preEncr, toKey);
public EncryptedBuildRecord encryptRecord(I2PAppContext ctx, PublicKey toKey, Hash toPeer) {
byte[] out = new byte[EncryptedBuildRecord.LENGTH];
System.arraycopy(toPeer.getData(), 0, out, 0, PEER_SIZE);
byte encrypted[] = ctx.elGamalEngine().encrypt(_data, toKey);
// the elg engine formats it kind of weird, giving 257 bytes for each part rather than 256, so
// we want to strip out that excess byte and store it in the record
System.arraycopy(encrypted, 1, out, outOffset + PEER_SIZE, 256);
System.arraycopy(encrypted, 258, out, outOffset + 256 + PEER_SIZE, 256);
System.arraycopy(encrypted, 1, out, PEER_SIZE, 256);
System.arraycopy(encrypted, 258, out, 256 + PEER_SIZE, 256);
return new EncryptedBuildRecord(out);
}
/**
* Decrypt the data from the specified record, writing the decrypted record into this instance's
* buffer (but not overwriting the array contained within the old buffer)
* data buffer
*
* Caller MUST check that first 16 bytes of our hash matches first 16 bytes of encryptedRecord
* before calling this. Not checked here.
*
* @throws DataFormatException on decrypt fail
* @since 0.9.18, was decryptRecord()
*/
public boolean decryptRecord(I2PAppContext ctx, PrivateKey ourKey, Hash ourIdent, ByteArray encryptedRecord) {
if (DataHelper.eq(ourIdent.getData(), 0, encryptedRecord.getData(), encryptedRecord.getOffset(), PEER_SIZE)) {
public BuildRequestRecord(I2PAppContext ctx, PrivateKey ourKey,
EncryptedBuildRecord encryptedRecord) throws DataFormatException {
byte preDecrypt[] = new byte[514];
System.arraycopy(encryptedRecord.getData(), encryptedRecord.getOffset() + PEER_SIZE, preDecrypt, 1, 256);
System.arraycopy(encryptedRecord.getData(), encryptedRecord.getOffset() + PEER_SIZE + 256, preDecrypt, 258, 256);
System.arraycopy(encryptedRecord.getData(), PEER_SIZE, preDecrypt, 1, 256);
System.arraycopy(encryptedRecord.getData(), PEER_SIZE + 256, preDecrypt, 258, 256);
byte decrypted[] = ctx.elGamalEngine().decrypt(preDecrypt, ourKey);
if (decrypted != null) {
_data = new ByteArray(decrypted);
_data.setOffset(0);
return true;
_data = decrypted;
} else {
return false;
throw new DataFormatException("decrypt fail");
}
} else {
return false;
}
}
private static final int PADDING_SIZE = 29;
/**
* Populate this instance with data. A new buffer is created to contain the data, with the
* necessary randomized padding.
@@ -215,14 +227,13 @@ public class BuildRequestRecord {
* @param iv iv to be used when encrypting the reply to this build request
* @param isInGateway are we the gateway of an inbound tunnel?
* @param isOutEndpoint are we the endpoint of an outbound tunnel?
* @since 0.9.18, was createRecord()
*/
public void createRecord(I2PAppContext ctx, long receiveTunnelId, Hash peer, long nextTunnelId, Hash nextHop, long nextMsgId,
public BuildRequestRecord(I2PAppContext ctx, long receiveTunnelId, Hash peer, long nextTunnelId, Hash nextHop, long nextMsgId,
SessionKey layerKey, SessionKey ivKey, SessionKey replyKey, byte iv[], boolean isInGateway,
boolean isOutEndpoint) {
if ( (_data == null) || (_data.getData() != null) )
_data = new ByteArray();
byte buf[] = new byte[OFF_SEND_MSG_ID+4+PADDING_SIZE];
_data.setData(buf);
byte buf[] = new byte[LENGTH];
_data = buf;
/* bytes 0-3: tunnel ID to receive messages as
* bytes 4-35: local router identity hash

View File

@@ -7,12 +7,17 @@ import net.i2p.data.SessionKey;
//import net.i2p.util.Log;
/**
* Read and write the reply to a tunnel build message record.
* Class that creates an encrypted tunnel build message record.
*
* The reply record is the same size as the request record (528 bytes).
*
* When decrypted:
*
*<pre>
* Bytes 0-31 contain the hash of bytes 32-527
* Bytes 32-526 contain random data.
* Byte 527 contains the reply.
*</pre>
*/
public class BuildResponseRecord {
@@ -20,10 +25,12 @@ public class BuildResponseRecord {
* Create a new encrypted response
*
* @param status the response 0-255
* @param replyIV 16 bytes
* @param responseMessageId unused except for debugging
* @return a 528-byte response record
*/
public static byte[] create(I2PAppContext ctx, int status, SessionKey replyKey, byte replyIV[], long responseMessageId) {
public static EncryptedBuildRecord create(I2PAppContext ctx, int status, SessionKey replyKey,
byte replyIV[], long responseMessageId) {
//Log log = ctx.logManager().getLog(BuildResponseRecord.class);
byte rv[] = new byte[TunnelBuildReplyMessage.RECORD_SIZE];
ctx.random().nextBytes(rv, Hash.HASH_LENGTH, TunnelBuildReplyMessage.RECORD_SIZE - Hash.HASH_LENGTH - 1);
@@ -35,6 +42,6 @@ public class BuildResponseRecord {
ctx.aes().encrypt(rv, 0, rv, 0, replyKey, replyIV, rv.length);
//if (log.shouldLog(Log.DEBUG))
// log.debug(responseMessageId + ": after encrypt: " + Base64.encode(rv, 0, 128));
return rv;
return new EncryptedBuildRecord(rv);
}
}

View File

@@ -214,9 +214,8 @@ public class DatabaseLookupMessage extends FastI2NPMessageImpl {
public static boolean supportsEncryptedReplies(RouterInfo to) {
if (to == null)
return false;
String v = to.getOption("router.version");
return v != null &&
VersionComparator.comp(v, MIN_ENCRYPTION_VERSION) >= 0;
String v = to.getVersion();
return VersionComparator.comp(v, MIN_ENCRYPTION_VERSION) >= 0;
}
/**

View File

@@ -105,7 +105,8 @@ public class DatabaseStoreMessage extends FastI2NPMessageImpl {
_key = Hash.create(data, curIndex);
curIndex += Hash.HASH_LENGTH;
type = (int)DataHelper.fromLong(data, curIndex, 1);
// as of 0.9.18, ignore other 7 bits of the type byte, in preparation for future options
int dbType = data[curIndex] & 0x01;
curIndex++;
_replyToken = DataHelper.fromLong(data, curIndex, 4);
@@ -124,7 +125,7 @@ public class DatabaseStoreMessage extends FastI2NPMessageImpl {
_replyGateway = null;
}
if (type == DatabaseEntry.KEY_TYPE_LEASESET) {
if (dbType == DatabaseEntry.KEY_TYPE_LEASESET) {
_dbEntry = new LeaseSet();
try {
_dbEntry.readBytes(new ByteArrayInputStream(data, curIndex, data.length-curIndex));
@@ -133,7 +134,7 @@ public class DatabaseStoreMessage extends FastI2NPMessageImpl {
} catch (IOException ioe) {
throw new I2NPMessageException("Error reading the leaseSet", ioe);
}
} else if (type == DatabaseEntry.KEY_TYPE_ROUTERINFO) {
} else { // dbType == DatabaseEntry.KEY_TYPE_ROUTERINFO
_dbEntry = new RouterInfo();
int compressedSize = (int)DataHelper.fromLong(data, curIndex, 2);
curIndex += 2;
@@ -154,8 +155,6 @@ public class DatabaseStoreMessage extends FastI2NPMessageImpl {
} catch (IOException ioe) {
throw new I2NPMessageException("Corrupt compressed routerInfo size = " + compressedSize, ioe);
}
} else {
throw new I2NPMessageException("Invalid type of key read from the structure - " + type);
}
//if (!key.equals(_dbEntry.getHash()))
// throw new I2NPMessageException("Hash mismatch in DSM");

View File

@@ -0,0 +1,32 @@
package net.i2p.data.i2np;
/*
* free (adj.): unencumbered; not under the control of others
* No warranty of any kind, either expressed or implied.
*/
import net.i2p.data.SimpleDataStructure;
/**
* ElGamal-encrypted request or response.
* 528 bytes. Previously stored in a ByteArray.
* May or may not be AES layer-encrypted.
*
* Note that these are layer-encrypted and layer-decrypted in-place.
* Do not cache.
*
* @since 0.9.18
*/
public class EncryptedBuildRecord extends SimpleDataStructure {
public final static int LENGTH = TunnelBuildMessageBase.RECORD_SIZE;
/** @throws IllegalArgumentException if data is not correct length (null is ok) */
public EncryptedBuildRecord(byte data[]) {
super(data);
}
public int length() {
return LENGTH;
}
}

View File

@@ -1,7 +1,6 @@
package net.i2p.data.i2np;
import net.i2p.I2PAppContext;
import net.i2p.data.ByteArray;
/**
* Base for TBM, TBRM, VTBM, VTBRM
@@ -18,7 +17,7 @@ import net.i2p.data.ByteArray;
* @since 0.8.8
*/
public abstract class TunnelBuildMessageBase extends I2NPMessageImpl {
protected ByteArray _records[];
protected EncryptedBuildRecord _records[];
protected int RECORD_COUNT;
public static final int MAX_RECORD_COUNT = 8;
@@ -31,14 +30,14 @@ public abstract class TunnelBuildMessageBase extends I2NPMessageImpl {
super(context);
if (records > 0) {
RECORD_COUNT = records;
_records = new ByteArray[records];
_records = new EncryptedBuildRecord[records];
}
// else will be initialized by readMessage()
}
public void setRecord(int index, ByteArray record) { _records[index] = record; }
public void setRecord(int index, EncryptedBuildRecord record) { _records[index] = record; }
public ByteArray getRecord(int index) { return _records[index]; }
public EncryptedBuildRecord getRecord(int index) { return _records[index]; }
/** @since 0.7.12 */
public int getRecordCount() { return RECORD_COUNT; }
@@ -57,7 +56,7 @@ public abstract class TunnelBuildMessageBase extends I2NPMessageImpl {
int off = offset + (i * RECORD_SIZE);
byte rec[] = new byte[RECORD_SIZE];
System.arraycopy(data, off, rec, 0, RECORD_SIZE);
setRecord(i, new ByteArray(rec));
setRecord(i, new EncryptedBuildRecord(rec));
}
}
@@ -66,7 +65,7 @@ public abstract class TunnelBuildMessageBase extends I2NPMessageImpl {
if (remaining < 0)
throw new I2NPMessageException("Not large enough (too short by " + remaining + ")");
for (int i = 0; i < RECORD_COUNT; i++) {
System.arraycopy(_records[i].getData(), _records[i].getOffset(), out, curIndex, RECORD_SIZE);
System.arraycopy(_records[i].getData(), 0, out, curIndex, RECORD_SIZE);
curIndex += RECORD_SIZE;
}
return curIndex;

View File

@@ -1,7 +1,6 @@
package net.i2p.data.i2np;
import net.i2p.I2PAppContext;
import net.i2p.data.ByteArray;
import net.i2p.data.DataHelper;
/**
@@ -36,7 +35,7 @@ public class VariableTunnelBuildMessage extends TunnelBuildMessage {
RECORD_COUNT = r;
if (dataSize != calculateWrittenLength())
throw new I2NPMessageException("Wrong length (expects " + calculateWrittenLength() + ", recv " + dataSize + ")");
_records = new ByteArray[RECORD_COUNT];
_records = new EncryptedBuildRecord[RECORD_COUNT];
super.readMessage(data, offset + 1, dataSize, type);
}
@@ -51,7 +50,7 @@ public class VariableTunnelBuildMessage extends TunnelBuildMessage {
// can't call super, written length check will fail
//return super.writeMessageBody(out, curIndex + 1);
for (int i = 0; i < RECORD_COUNT; i++) {
System.arraycopy(_records[i].getData(), _records[i].getOffset(), out, curIndex, RECORD_SIZE);
System.arraycopy(_records[i].getData(), 0, out, curIndex, RECORD_SIZE);
curIndex += RECORD_SIZE;
}
return curIndex;

View File

@@ -1,7 +1,6 @@
package net.i2p.data.i2np;
import net.i2p.I2PAppContext;
import net.i2p.data.ByteArray;
import net.i2p.data.DataHelper;
/**
@@ -38,7 +37,7 @@ public class VariableTunnelBuildReplyMessage extends TunnelBuildReplyMessage {
RECORD_COUNT = r;
if (dataSize != calculateWrittenLength())
throw new I2NPMessageException("Wrong length (expects " + calculateWrittenLength() + ", recv " + dataSize + ")");
_records = new ByteArray[RECORD_COUNT];
_records = new EncryptedBuildRecord[RECORD_COUNT];
super.readMessage(data, offset + 1, dataSize, type);
}
@@ -53,7 +52,7 @@ public class VariableTunnelBuildReplyMessage extends TunnelBuildReplyMessage {
// can't call super, written length check will fail
//return super.writeMessageBody(out, curIndex + 1);
for (int i = 0; i < RECORD_COUNT; i++) {
System.arraycopy(_records[i].getData(), _records[i].getOffset(), out, curIndex, RECORD_SIZE);
System.arraycopy(_records[i].getData(), 0, out, curIndex, RECORD_SIZE);
curIndex += RECORD_SIZE;
}
return curIndex;

View File

@@ -261,6 +261,18 @@ public class RouterInfo extends DatabaseEntry {
return _options.getProperty(opt);
}
/**
* For convenience, the same as getOption("router.version"),
* but returns "0" if unset.
*
* @return non-null, "0" if unknown.
* @since 0.9.18
*/
public String getVersion() {
String rv = _options.getProperty("router.version");
return rv != null ? rv : "0";
}
/**
* Configure a set of options or statistics that the router can expose.
* Makes a copy.

View File

@@ -513,9 +513,7 @@ class StoreJob extends JobImpl {
* @since 0.7.10
*/
private static boolean supportsEncryption(RouterInfo ri) {
String v = ri.getOption("router.version");
if (v == null)
return false;
String v = ri.getVersion();
return VersionComparator.comp(v, MIN_ENCRYPTION_VERSION) >= 0;
}
@@ -535,9 +533,7 @@ class StoreJob extends JobImpl {
}
if (type == null)
return false;
String v = ri.getOption("router.version");
if (v == null)
return false;
String v = ri.getVersion();
String since = type.getSupportedSince();
return VersionComparator.comp(v, since) >= 0;
}
@@ -549,9 +545,7 @@ class StoreJob extends JobImpl {
* @since 0.9.12
*/
public static boolean supportsBigLeaseSets(RouterInfo ri) {
String v = ri.getOption("router.version");
if (v == null)
return false;
String v = ri.getVersion();
return VersionComparator.comp(v, MIN_BIGLEASESET_VERSION) >= 0;
}

View File

@@ -367,6 +367,29 @@ public class ProfileOrganizer {
return;
}
/**
* Replaces integer subTierMode argument, for clarity
*
* @since 0.9.18
*/
public enum Slice {
SLICE_ALL(0x00, 0),
SLICE_0_1(0x02, 0),
SLICE_2_3(0x02, 2),
SLICE_0(0x03, 0),
SLICE_1(0x03, 1),
SLICE_2(0x03, 2),
SLICE_3(0x03, 3);
final int mask, val;
Slice(int mask, int val) {
this.mask = mask;
this.val = val;
}
}
/**
* Return a set of Hashes for peers that are both fast and reliable. If an insufficient
* number of peers are both fast and reliable, fall back onto high capacity peers, and if that
@@ -388,15 +411,15 @@ public class ProfileOrganizer {
* 7: return only from group 3
*</pre>
*/
public void selectFastPeers(int howMany, Set<Hash> exclude, Set<Hash> matches, Hash randomKey, int subTierMode) {
public void selectFastPeers(int howMany, Set<Hash> exclude, Set<Hash> matches, Hash randomKey, Slice subTierMode) {
getReadLock();
try {
if (subTierMode > 0) {
if (subTierMode != Slice.SLICE_ALL) {
int sz = _fastPeers.size();
if (sz < 6 || (subTierMode >= 4 && sz < 12))
subTierMode = 0;
if (sz < 6 || (subTierMode.mask >= 3 && sz < 12))
subTierMode = Slice.SLICE_ALL;
}
if (subTierMode > 0)
if (subTierMode != Slice.SLICE_ALL)
locked_selectPeers(_fastPeers, howMany, exclude, matches, randomKey, subTierMode);
else
locked_selectPeers(_fastPeers, howMany, exclude, matches, 2);
@@ -674,9 +697,9 @@ public class ProfileOrganizer {
// they probably don't have a TCP hole punched in their firewall either.
RouterInfo info = _context.netDb().lookupRouterInfoLocally(peer);
if (info != null) {
String v = info.getOption("router.version");
String v = info.getVersion();
// this only works if there is no 0.6.1.34!
if (v != null && (!v.equals("0.6.1.33")) &&
if ((!v.equals("0.6.1.33")) &&
v.startsWith("0.6.1.") && info.getTargetAddress("NTCP") == null)
l.add(peer);
else {
@@ -1302,7 +1325,8 @@ public class ProfileOrganizer {
* 7: return only from group 3
*</pre>
*/
private void locked_selectPeers(Map<Hash, PeerProfile> peers, int howMany, Set<Hash> toExclude, Set<Hash> matches, Hash randomKey, int subTierMode) {
private void locked_selectPeers(Map<Hash, PeerProfile> peers, int howMany, Set<Hash> toExclude,
Set<Hash> matches, Hash randomKey, Slice subTierMode) {
List<Hash> all = new ArrayList<Hash>(peers.keySet());
// use RandomIterator to avoid shuffling the whole thing
for (Iterator<Hash> iter = new RandomIterator<Hash>(all); (matches.size() < howMany) && iter.hasNext(); ) {
@@ -1314,13 +1338,8 @@ public class ProfileOrganizer {
if (_us.equals(peer))
continue;
int subTier = getSubTier(peer, randomKey);
if (subTierMode >= 4) {
if (subTier != (subTierMode & 0x03))
continue;
} else {
if ((subTier >> 1) != (subTierMode & 0x01))
continue;
}
if ((subTier & subTierMode.mask) != subTierMode.val)
continue;
boolean ok = isSelectable(peer);
if (ok)
matches.add(peer);

View File

@@ -173,11 +173,22 @@ public abstract class TransportUtil {
/**
* Is this a valid port for us or a remote router?
*
* ref: http://i2p-projekt.i2p/en/docs/ports
*
* @since 0.9.17 moved from logic in individual transports
*/
public static boolean isValidPort(int port) {
// update log message in UDPEndpoint if you update this list
return port >= 1024 &&
port <= 65535 &&
port != 1900; // UPnP SSDP
port != 1900 && // UPnP SSDP
port != 2827 && // BOB
port != 4444 && // HTTP
port != 4445 && // HTTPS
port != 6668 && // IRC
(!(port >= 7650 && port <= 7664)) && // standard I2P range
port != 8998 && // mtn
port != 31000 && // Wrapper
port != 32000; // Wrapper
}
}

View File

@@ -375,8 +375,8 @@ public class NTCPTransport extends TransportImpl {
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) {
String v = toAddress.getVersion();
if (VersionComparator.comp(v, MIN_SIGTYPE_VERSION) < 0) {
markUnreachable(peer);
return null;
}

View File

@@ -113,8 +113,12 @@ class UDPEndpoint implements SocketListener {
private DatagramSocket getSocket() {
DatagramSocket socket = null;
int port = _listenPort;
if (port > 0 && !TransportUtil.isValidPort(port))
_log.error("Specified UDP port is " + port + ", ports lower than 1024 not recommended");
if (port > 0 && !TransportUtil.isValidPort(port)) {
_log.error("Specified UDP port " + port + " is not valid, selecting a new port");
// See isValidPort() for list
_log.error("Invalid ports are: 0-1023, 1900, 2827, 4444, 4445, 6668, 7650-7664, 8998, 31000, 32000, 65536+");
port = -1;
}
for (int i = 0; i < MAX_PORT_RETRIES; i++) {
if (port <= 0) {

View File

@@ -1232,7 +1232,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
_context.simpleScheduler().addEvent(new RemoveDropList(remote), DROPLIST_PERIOD);
}
markUnreachable(peerHash);
_context.banlist().banlistRouter(peerHash, "Part of the wrong network, version = " + ((RouterInfo) entry).getOption("router.version"));
_context.banlist().banlistRouter(peerHash, "Part of the wrong network, version = " + ((RouterInfo) entry).getVersion());
//_context.banlist().banlistRouter(peerHash, "Part of the wrong network", STYLE);
dropPeer(peerHash, false, "wrong network");
if (_log.shouldLog(Log.WARN))
@@ -1578,8 +1578,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
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) {
String v = toAddress.getVersion();
if (VersionComparator.comp(v, MIN_SIGTYPE_VERSION) < 0) {
markUnreachable(to);
return null;
}

View File

@@ -3,11 +3,11 @@ package net.i2p.router.tunnel;
import java.util.List;
import net.i2p.I2PAppContext;
import net.i2p.data.ByteArray;
import net.i2p.data.Hash;
import net.i2p.data.PublicKey;
import net.i2p.data.SessionKey;
import net.i2p.data.i2np.BuildRequestRecord;
import net.i2p.data.i2np.EncryptedBuildRecord;
import net.i2p.data.i2np.I2NPMessage;
import net.i2p.data.i2np.TunnelBuildMessage;
@@ -54,33 +54,41 @@ public abstract class BuildMessageGenerator {
* containing the hop's configuration (as well as the reply info, if it is an outbound endpoint)
*
* @param msg out parameter
* @throws IllegalArgumentException if hop bigger than config
*/
public static void createRecord(int recordNum, int hop, TunnelBuildMessage msg,
TunnelCreatorConfig cfg, Hash replyRouter,
long replyTunnel, I2PAppContext ctx, PublicKey peerKey) {
byte encrypted[] = new byte[TunnelBuildMessage.RECORD_SIZE];
//Log log = ctx.logManager().getLog(BuildMessageGenerator.class);
EncryptedBuildRecord erec;
if (peerKey != null) {
BuildRequestRecord req = null;
if ( (!cfg.isInbound()) && (hop + 1 == cfg.getLength()) ) //outbound endpoint
req = createUnencryptedRecord(ctx, cfg, hop, replyRouter, replyTunnel);
else
req = createUnencryptedRecord(ctx, cfg, hop, null, -1);
if (req == null)
throw new IllegalArgumentException("hop bigger than config");
Hash peer = cfg.getPeer(hop);
//if (log.shouldLog(Log.DEBUG))
// log.debug("Record " + recordNum + "/" + hop + "/" + peer.toBase64()
// + ": unencrypted = " + Base64.encode(req.getData().getData()));
req.encryptRecord(ctx, peerKey, peer, encrypted, 0);
erec = req.encryptRecord(ctx, peerKey, peer);
//if (log.shouldLog(Log.DEBUG))
// log.debug("Record " + recordNum + "/" + hop + ": encrypted = " + Base64.encode(encrypted));
} else {
//if (log.shouldLog(Log.DEBUG))
// log.debug("Record " + recordNum + "/" + hop + "/ is blank/random");
byte encrypted[] = new byte[TunnelBuildMessage.RECORD_SIZE];
ctx.random().nextBytes(encrypted);
erec = new EncryptedBuildRecord(encrypted);
}
msg.setRecord(recordNum, new ByteArray(encrypted));
msg.setRecord(recordNum, erec);
}
/**
* Returns null if hop >= cfg.length
*/
private static BuildRequestRecord createUnencryptedRecord(I2PAppContext ctx, TunnelCreatorConfig cfg, int hop,
Hash replyRouter, long replyTunnel) {
//Log log = ctx.logManager().getLog(BuildMessageGenerator.class);
@@ -111,11 +119,11 @@ public abstract class BuildMessageGenerator {
SessionKey layerKey = hopConfig.getLayerKey();
SessionKey ivKey = hopConfig.getIVKey();
SessionKey replyKey = hopConfig.getReplyKey();
byte iv[] = hopConfig.getReplyIV().getData();
if ( (iv == null) || (iv.length != BuildRequestRecord.IV_SIZE) ) {
byte iv[] = hopConfig.getReplyIV();
if (iv == null) {
iv = new byte[BuildRequestRecord.IV_SIZE];
ctx.random().nextBytes(iv);
hopConfig.getReplyIV().setData(iv);
hopConfig.setReplyIV(iv);
}
boolean isInGW = (cfg.isInbound() && (hop == 0));
boolean isOutEnd = (!cfg.isInbound() && (hop + 1 >= cfg.getLength()));
@@ -132,9 +140,9 @@ public abstract class BuildMessageGenerator {
// log.debug("Hop " + hop + " has the next message ID of " + nextMsgId + " for " + cfg
// + " with replyKey " + replyKey.toBase64() + " and replyIV " + Base64.encode(iv));
BuildRequestRecord rec= new BuildRequestRecord();
rec.createRecord(ctx, recvTunnelId, peer, nextTunnelId, nextPeer, nextMsgId, layerKey, ivKey, replyKey,
iv, isInGW, isOutEnd);
BuildRequestRecord rec= new BuildRequestRecord(ctx, recvTunnelId, peer, nextTunnelId, nextPeer,
nextMsgId, layerKey, ivKey, replyKey,
iv, isInGW, isOutEnd);
return rec;
} else {
@@ -143,7 +151,11 @@ public abstract class BuildMessageGenerator {
}
/**
* Encrypt the records so their hop ident is visible at the appropriate times
* Encrypt the records so their hop ident is visible at the appropriate times.
*
* Note that this layer-encrypts the build records for the message in-place.
* Only call this onece for a given message.
*
* @param order list of hop #s as Integers. For instance, if (order.get(1) is 4), it is peer cfg.getPeer(4)
*/
public static void layeredEncrypt(I2PAppContext ctx, TunnelBuildMessage msg,
@@ -151,7 +163,7 @@ public abstract class BuildMessageGenerator {
//Log log = ctx.logManager().getLog(BuildMessageGenerator.class);
// encrypt the records so that the right elements will be visible at the right time
for (int i = 0; i < msg.getRecordCount(); i++) {
ByteArray rec = msg.getRecord(i);
EncryptedBuildRecord rec = msg.getRecord(i);
Integer hopNum = order.get(i);
int hop = hopNum.intValue();
if ( (isBlank(cfg, hop)) || (!cfg.isInbound() && hop == 1) ) {
@@ -166,12 +178,12 @@ public abstract class BuildMessageGenerator {
for (int j = hop-1; j >= stop; j--) {
HopConfig hopConfig = cfg.getConfig(j);
SessionKey key = hopConfig.getReplyKey();
byte iv[] = hopConfig.getReplyIV().getData();
int off = rec.getOffset();
byte iv[] = hopConfig.getReplyIV();
//if (log.shouldLog(Log.DEBUG))
// log.debug(msg.getUniqueId() + ": pre-decrypting record " + i + "/" + hop + " for " + cfg
// + " with " + key.toBase64() + "/" + Base64.encode(iv));
ctx.aes().decrypt(rec.getData(), off, rec.getData(), off, key, iv, TunnelBuildMessage.RECORD_SIZE);
// corrupts the SDS
ctx.aes().decrypt(rec.getData(), 0, rec.getData(), 0, key, iv, TunnelBuildMessage.RECORD_SIZE);
}
}
//if (log.shouldLog(Log.DEBUG))

View File

@@ -2,12 +2,13 @@ package net.i2p.router.tunnel;
import net.i2p.I2PAppContext;
import net.i2p.data.Base64;
import net.i2p.data.ByteArray;
import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper;
import net.i2p.data.Hash;
import net.i2p.data.PrivateKey;
import net.i2p.data.SessionKey;
import net.i2p.data.i2np.BuildRequestRecord;
import net.i2p.data.i2np.EncryptedBuildRecord;
import net.i2p.data.i2np.TunnelBuildMessage;
import net.i2p.router.util.DecayingBloomFilter;
import net.i2p.router.util.DecayingHashSet;
@@ -32,7 +33,10 @@ public class BuildMessageProcessor {
* message (so that the reply can be placed in that position after going through the decrypted
* request record).
*
* @return the current hop's decrypted record
* Note that this layer-decrypts the build records in-place.
* Do not call this more than once for a given message.
*
* @return the current hop's decrypted record or null on failure
*/
public BuildRequestRecord decrypt(I2PAppContext ctx, TunnelBuildMessage msg, Hash ourHash, PrivateKey privKey) {
Log log = ctx.logManager().getLog(getClass());
@@ -44,35 +48,33 @@ public class BuildMessageProcessor {
long totalDup = 0;
long beforeLoop = System.currentTimeMillis();
for (int i = 0; i < msg.getRecordCount(); i++) {
ByteArray rec = msg.getRecord(i);
int off = rec.getOffset();
EncryptedBuildRecord rec = msg.getRecord(i);
int len = BuildRequestRecord.PEER_SIZE;
long beforeEq = System.currentTimeMillis();
boolean eq = DataHelper.eq(ourHash.getData(), 0, rec.getData(), off, len);
boolean eq = DataHelper.eq(ourHash.getData(), 0, rec.getData(), 0, len);
totalEq += System.currentTimeMillis()-beforeEq;
if (eq) {
long beforeIsDup = System.currentTimeMillis();
boolean isDup = _filter.add(rec.getData(), off + len, 32);
boolean isDup = _filter.add(rec.getData(), len, 32);
totalDup += System.currentTimeMillis()-beforeIsDup;
if (isDup) {
if (log.shouldLog(Log.WARN))
log.debug(msg.getUniqueId() + ": A record matching our hash was found, but it seems to be a duplicate");
ctx.statManager().addRateData("tunnel.buildRequestDup", 1, 0);
ctx.statManager().addRateData("tunnel.buildRequestDup", 1);
return null;
}
BuildRequestRecord req = new BuildRequestRecord();
beforeActualDecrypt = System.currentTimeMillis();
boolean ok = req.decryptRecord(ctx, privKey, ourHash, rec);
afterActualDecrypt = System.currentTimeMillis();
if (ok) {
try {
BuildRequestRecord req = new BuildRequestRecord(ctx, privKey, rec);
if (log.shouldLog(Log.DEBUG))
log.debug(msg.getUniqueId() + ": A record matching our hash was found and decrypted");
rv = req;
} else {
} catch (DataFormatException dfe) {
if (log.shouldLog(Log.DEBUG))
log.debug(msg.getUniqueId() + ": A record matching our hash was found, but could not be decrypted");
return null; // our hop is invalid? b0rkage
}
afterActualDecrypt = System.currentTimeMillis();
ourHop = i;
}
}
@@ -89,11 +91,12 @@ public class BuildMessageProcessor {
int ivOff = 0;
for (int i = 0; i < msg.getRecordCount(); i++) {
if (i != ourHop) {
ByteArray data = msg.getRecord(i);
EncryptedBuildRecord data = msg.getRecord(i);
if (log.shouldLog(Log.DEBUG))
log.debug("Encrypting record " + i + "/?/" + data.getOffset() + "/" + data.getValid() + " with replyKey " + replyKey.toBase64() + "/" + Base64.encode(iv, ivOff, 16));
ctx.aes().encrypt(data.getData(), data.getOffset(), data.getData(), data.getOffset(), replyKey,
iv, ivOff, data.getValid());
log.debug("Encrypting record " + i + "/? with replyKey " + replyKey.toBase64() + "/" + Base64.encode(iv, ivOff, 16));
// corrupts SDS
ctx.aes().encrypt(data.getData(), 0, data.getData(), 0, replyKey,
iv, ivOff, data.length());
}
}
long afterEncrypt = System.currentTimeMillis();

View File

@@ -4,10 +4,10 @@ import java.util.List;
import net.i2p.I2PAppContext;
import net.i2p.data.Base64;
import net.i2p.data.ByteArray;
import net.i2p.data.DataHelper;
import net.i2p.data.Hash;
import net.i2p.data.SessionKey;
import net.i2p.data.i2np.EncryptedBuildRecord;
import net.i2p.data.i2np.TunnelBuildReplyMessage;
import net.i2p.util.Log;
import net.i2p.util.SimpleByteCache;
@@ -34,6 +34,9 @@ public class BuildReplyHandler {
* Decrypt the tunnel build reply records. This overwrites the contents of the reply.
* Thread safe (no state).
*
* Note that this layer-decrypts the build records in-place.
* Do not call this more than once for a given message.
*
* @return status for the records (in record order), or null if the replies were not valid. Fake records
* always have 0 as their value
*/
@@ -70,7 +73,10 @@ public class BuildReplyHandler {
/**
* Decrypt the record (removing the layers of reply encyption) and read out the status
*
* @return -1 on decrypt failure
* Note that this layer-decrypts the build records in-place.
* Do not call this more than once for a given message.
*
* @return the status 0-255, or -1 on decrypt failure
*/
private int decryptRecord(TunnelBuildReplyMessage reply, TunnelCreatorConfig cfg, int recordNum, int hop) {
if (BuildMessageGenerator.isBlank(cfg, hop)) {
@@ -78,9 +84,8 @@ public class BuildReplyHandler {
log.debug(reply.getUniqueId() + ": Record " + recordNum + "/" + hop + " is fake, so consider it valid...");
return 0;
}
ByteArray rec = reply.getRecord(recordNum);
EncryptedBuildRecord rec = reply.getRecord(recordNum);
byte[] data = rec.getData();
int off = rec.getOffset();
int start = cfg.getLength() - 1;
if (cfg.isInbound())
start--; // the last hop in an inbound tunnel response doesn't actually encrypt
@@ -88,35 +93,34 @@ public class BuildReplyHandler {
for (int j = start; j >= hop; j--) {
HopConfig hopConfig = cfg.getConfig(j);
SessionKey replyKey = hopConfig.getReplyKey();
byte replyIV[] = hopConfig.getReplyIV().getData();
int replyIVOff = hopConfig.getReplyIV().getOffset();
byte replyIV[] = hopConfig.getReplyIV();
if (log.shouldLog(Log.DEBUG)) {
log.debug(reply.getUniqueId() + ": Decrypting record " + recordNum + "/" + hop + "/" + j + " with replyKey "
+ replyKey.toBase64() + "/" + Base64.encode(replyIV, replyIVOff, 16) + ": " + cfg);
log.debug(reply.getUniqueId() + ": before decrypt("+ off + "-"+(off+rec.getValid())+"): " + Base64.encode(data, off, rec.getValid()));
log.debug(reply.getUniqueId() + ": Full reply rec: offset=" + off + ", sz=" + data.length + "/" + rec.getValid() + ", data=" + Base64.encode(data, off, TunnelBuildReplyMessage.RECORD_SIZE));
+ replyKey.toBase64() + "/" + Base64.encode(replyIV) + ": " + cfg);
log.debug(reply.getUniqueId() + ": before decrypt: " + Base64.encode(data));
log.debug(reply.getUniqueId() + ": Full reply rec: sz=" + data.length + " data=" + Base64.encode(data, 0, TunnelBuildReplyMessage.RECORD_SIZE));
}
ctx.aes().decrypt(data, off, data, off, replyKey, replyIV, replyIVOff, TunnelBuildReplyMessage.RECORD_SIZE);
ctx.aes().decrypt(data, 0, data, 0, replyKey, replyIV, 0, TunnelBuildReplyMessage.RECORD_SIZE);
if (log.shouldLog(Log.DEBUG))
log.debug(reply.getUniqueId() + ": after decrypt: " + Base64.encode(data, off, rec.getValid()));
log.debug(reply.getUniqueId() + ": after decrypt: " + Base64.encode(data));
}
// ok, all of the layered encryption is stripped, so lets verify it
// (formatted per BuildResponseRecord.create)
// don't cache the result
//Hash h = ctx.sha().calculateHash(data, off + Hash.HASH_LENGTH, TunnelBuildReplyMessage.RECORD_SIZE-Hash.HASH_LENGTH);
byte[] h = SimpleByteCache.acquire(Hash.HASH_LENGTH);
ctx.sha().calculateHash(data, off + Hash.HASH_LENGTH, TunnelBuildReplyMessage.RECORD_SIZE-Hash.HASH_LENGTH, h, 0);
boolean ok = DataHelper.eq(h, 0, data, off, Hash.HASH_LENGTH);
ctx.sha().calculateHash(data, Hash.HASH_LENGTH, TunnelBuildReplyMessage.RECORD_SIZE-Hash.HASH_LENGTH, h, 0);
boolean ok = DataHelper.eq(h, 0, data, 0, Hash.HASH_LENGTH);
if (!ok) {
if (log.shouldLog(Log.DEBUG))
log.debug(reply.getUniqueId() + ": Failed verification on " + recordNum + "/" + hop + ": " + Base64.encode(h) + " calculated, " +
Base64.encode(data, off, Hash.HASH_LENGTH) + " expected\n" +
"Record: " + Base64.encode(data, off+Hash.HASH_LENGTH, TunnelBuildReplyMessage.RECORD_SIZE-Hash.HASH_LENGTH));
Base64.encode(data, 0, Hash.HASH_LENGTH) + " expected\n" +
"Record: " + Base64.encode(data, Hash.HASH_LENGTH, TunnelBuildReplyMessage.RECORD_SIZE-Hash.HASH_LENGTH));
SimpleByteCache.release(h);
return -1;
} else {
SimpleByteCache.release(h);
int rv = (int)DataHelper.fromLong(data, off + TunnelBuildReplyMessage.RECORD_SIZE - 1, 1);
int rv = (int)DataHelper.fromLong(data, TunnelBuildReplyMessage.RECORD_SIZE - 1, 1);
if (log.shouldLog(Log.DEBUG))
log.debug(reply.getUniqueId() + ": Verified: " + rv + " for record " + recordNum + "/" + hop);
return rv;

View File

@@ -1,6 +1,5 @@
package net.i2p.router.tunnel;
import net.i2p.data.ByteArray;
import net.i2p.data.DataHelper;
import net.i2p.data.Hash;
import net.i2p.data.SessionKey;
@@ -20,7 +19,7 @@ public class HopConfig {
private SessionKey _layerKey;
private SessionKey _ivKey;
private SessionKey _replyKey;
private ByteArray _replyIV;
private byte[] _replyIV;
private long _creation;
private long _expiration;
//private Map _options;
@@ -87,9 +86,23 @@ public class HopConfig {
public SessionKey getReplyKey() { return _replyKey; }
public void setReplyKey(SessionKey key) { _replyKey = key; }
/** iv used to encrypt the reply sent for the new tunnel creation crypto */
public ByteArray getReplyIV() { return _replyIV; }
public void setReplyIV(ByteArray iv) { _replyIV = iv; }
/**
* IV used to encrypt the reply sent for the new tunnel creation crypto
*
* @return 16 bytes
*/
public byte[] getReplyIV() { return _replyIV; }
/**
* IV used to encrypt the reply sent for the new tunnel creation crypto
*
* @throws IllegalArgumentException if not 16 bytes
*/
public void setReplyIV(byte[] iv) {
if (iv.length != REPLY_IV_LENGTH)
throw new IllegalArgumentException();
_replyIV = iv;
}
/** when does this tunnel expire (in ms since the epoch)? */
public long getExpiration() { return _expiration; }

View File

@@ -6,7 +6,6 @@ import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
import net.i2p.data.Base64;
import net.i2p.data.ByteArray;
import net.i2p.data.DataHelper;
import net.i2p.data.Hash;
import net.i2p.data.router.RouterIdentity;
@@ -14,6 +13,7 @@ import net.i2p.data.router.RouterInfo;
import net.i2p.data.TunnelId;
import net.i2p.data.i2np.BuildRequestRecord;
import net.i2p.data.i2np.BuildResponseRecord;
import net.i2p.data.i2np.EncryptedBuildRecord;
import net.i2p.data.i2np.I2NPMessage;
import net.i2p.data.i2np.TunnelBuildMessage;
import net.i2p.data.i2np.TunnelBuildReplyMessage;
@@ -782,13 +782,13 @@ class BuildHandler implements Runnable {
return;
}
byte reply[] = BuildResponseRecord.create(_context, response, req.readReplyKey(), req.readReplyIV(), state.msg.getUniqueId());
EncryptedBuildRecord reply = BuildResponseRecord.create(_context, response, req.readReplyKey(), req.readReplyIV(), state.msg.getUniqueId());
int records = state.msg.getRecordCount();
int ourSlot = -1;
for (int j = 0; j < records; j++) {
if (state.msg.getRecord(j) == null) {
ourSlot = j;
state.msg.setRecord(j, new ByteArray(reply));
state.msg.setRecord(j, reply);
//if (_log.shouldLog(Log.DEBUG))
// _log.debug("Full reply record for slot " + ourSlot + "/" + ourId + "/" + nextId + "/" + req.readReplyMessageId()
// + ": " + Base64.encode(reply));

View File

@@ -4,7 +4,6 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import net.i2p.data.ByteArray;
import net.i2p.data.DataHelper;
import net.i2p.data.Hash;
import net.i2p.data.PublicKey;
@@ -90,7 +89,7 @@ abstract class BuildRequestor {
cfg.getConfig(i-1).setSendTunnelId(cfg.getConfig(i).getReceiveTunnelId());
byte iv[] = new byte[16];
ctx.random().nextBytes(iv);
cfg.getConfig(i).setReplyIV(new ByteArray(iv));
cfg.getConfig(i).setReplyIV(iv);
cfg.getConfig(i).setReplyKey(ctx.keyGenerator().generateSessionKey());
}
// This is in BuildExecutor.buildTunnel() now
@@ -239,9 +238,7 @@ abstract class BuildRequestor {
RouterInfo ri = ctx.netDb().lookupRouterInfoLocally(h);
if (ri == null)
return false;
String v = ri.getOption("router.version");
if (v == null)
return false;
String v = ri.getVersion();
return VersionComparator.comp(v, MIN_VARIABLE_VERSION) >= 0;
}

View File

@@ -8,6 +8,7 @@ import java.util.Set;
import net.i2p.data.Hash;
import net.i2p.router.RouterContext;
import net.i2p.router.TunnelPoolSettings;
import static net.i2p.router.peermanager.ProfileOrganizer.Slice.*;
/**
* Pick peers randomly out of the fast pool, and put them into tunnels
@@ -65,7 +66,7 @@ class ClientPeerSelector extends TunnelPeerSelector {
} else {
firstHopExclude = exclude;
}
ctx.profileOrganizer().selectFastPeers(1, firstHopExclude, matches, settings.getRandomKey(), length == 2 ? 2 : 4);
ctx.profileOrganizer().selectFastPeers(1, firstHopExclude, matches, settings.getRandomKey(), length == 2 ? SLICE_0_1 : SLICE_0);
matches.remove(ctx.routerHash());
exclude.addAll(matches);
rv.addAll(matches);
@@ -73,7 +74,7 @@ class ClientPeerSelector extends TunnelPeerSelector {
if (length > 2) {
// middle hop(s)
// group 2 or 3
ctx.profileOrganizer().selectFastPeers(length - 2, exclude, matches, settings.getRandomKey(), 3);
ctx.profileOrganizer().selectFastPeers(length - 2, exclude, matches, settings.getRandomKey(), SLICE_2_3);
matches.remove(ctx.routerHash());
if (matches.size() > 1) {
// order the middle peers for tunnels >= 4 hops
@@ -96,7 +97,7 @@ class ClientPeerSelector extends TunnelPeerSelector {
if (moreExclude != null)
exclude.addAll(moreExclude);
}
ctx.profileOrganizer().selectFastPeers(1, exclude, matches, settings.getRandomKey(), length == 2 ? 3 : 5);
ctx.profileOrganizer().selectFastPeers(1, exclude, matches, settings.getRandomKey(), length == 2 ? SLICE_2_3 : SLICE_1);
matches.remove(ctx.routerHash());
rv.addAll(matches);
}

View File

@@ -349,9 +349,7 @@ public abstract class TunnelPeerSelector {
if (known != null) {
for (int i = 0; i < known.size(); i++) {
RouterInfo peer = known.get(i);
String v = peer.getOption("router.version");
if (v == null)
continue;
String v = peer.getVersion();
// RI sigtypes added in 0.9.16
// SSU inbound connection bug fixed in 0.9.17, but it won't bid, so NTCP only,
// no need to check
@@ -402,8 +400,8 @@ public abstract class TunnelPeerSelector {
// so don't exclude it based on published capacity
// minimum version check
String v = peer.getOption("router.version");
if (v == null || VersionComparator.comp(v, MIN_VERSION) < 0)
String v = peer.getVersion();
if (VersionComparator.comp(v, MIN_VERSION) < 0)
return true;
// uptime is always spoofed to 90m, so just remove all this