I2NP: Implement DatabaseLookupMessage search type field,

to replace all-zeros hash, and ease implementation for
separate LS and RI databases, as documented in i2np spec.
This commit is contained in:
zzz
2014-10-14 13:57:02 +00:00
parent d2c6a80d24
commit 266a20d55e
8 changed files with 112 additions and 11 deletions

View File

@ -1,3 +1,6 @@
2014-10-14 zzz
* I2NP: Implement DatabaseLookupMessage search type field
2014-10-13 zzz 2014-10-13 zzz
* i2ptunnel: Set default sig type to ECDSA-P256 for client types * i2ptunnel: Set default sig type to ECDSA-P256 for client types
Standard, IRC, and Socks IRC, if non-shared. Standard, IRC, and Socks IRC, if non-shared.

View File

@ -40,6 +40,7 @@ public class DatabaseLookupMessage extends FastI2NPMessageImpl {
private List<Hash> _dontIncludePeers; private List<Hash> _dontIncludePeers;
private SessionKey _replyKey; private SessionKey _replyKey;
private SessionTag _replyTag; private SessionTag _replyTag;
private Type _type;
//private static volatile long _currentLookupPeriod = 0; //private static volatile long _currentLookupPeriod = 0;
//private static volatile int _currentLookupCount = 0; //private static volatile int _currentLookupCount = 0;
@ -52,7 +53,26 @@ public class DatabaseLookupMessage extends FastI2NPMessageImpl {
private static final int MAX_NUM_PEERS = 512; private static final int MAX_NUM_PEERS = 512;
private static final byte FLAG_TUNNEL = 0x01; private static final byte FLAG_TUNNEL = 0x01;
// any flags below here will confuse routers 0.9.5 or lower
private static final byte FLAG_ENCRYPT = 0x02; private static final byte FLAG_ENCRYPT = 0x02;
private static final byte FLAG_TYPE_MASK = 0x0c;
private static final byte FLAG_TYPE_ANY = 0;
private static final byte FLAG_TYPE_LS = 0x04;
private static final byte FLAG_TYPE_RI = 0x08;
private static final byte FLAG_TYPE_EXPL = 0x0c;
/** @since 0.9.16 */
public enum Type {
/** default - LS or RI */
ANY,
/** lease set only */
LS,
/** router info only */
RI,
/** exploratory - return closest non-floodfill router infos */
EXPL
}
/** /**
* It's not supported until 0.9.7, but as of * It's not supported until 0.9.7, but as of
@ -86,6 +106,7 @@ public class DatabaseLookupMessage extends FastI2NPMessageImpl {
// + " messages so far)", new Exception("Flood cause")); // + " messages so far)", new Exception("Flood cause"));
// } // }
//} //}
_type = Type.ANY;
} }
/** /**
@ -130,6 +151,30 @@ public class DatabaseLookupMessage extends FastI2NPMessageImpl {
_key = key; _key = key;
} }
/**
* Defines the type of data being searched for.
* Default ANY.
*
* @return non-null
* @since 0.9.16
*/
public Type getSearchType() { return _type; }
/**
* Defines the type of data being searched for.
* Default ANY.
* Must be ANY for queried routers 0.9.5 or lower, but there are few if
* any floodfills that old left, so not even worth checking.
*
* @param type non-null
* @since 0.9.16
*/
public void setSearchType(Type type) {
if (type == null)
throw new IllegalArgumentException();
_type = type;
}
/** /**
* Contains the router who requested this lookup * Contains the router who requested this lookup
* *
@ -285,6 +330,21 @@ public class DatabaseLookupMessage extends FastI2NPMessageImpl {
// TODO store the whole flag byte // TODO store the whole flag byte
boolean tunnelSpecified = (data[curIndex] & FLAG_TUNNEL) != 0; boolean tunnelSpecified = (data[curIndex] & FLAG_TUNNEL) != 0;
boolean replyKeySpecified = (data[curIndex] & FLAG_ENCRYPT) != 0; boolean replyKeySpecified = (data[curIndex] & FLAG_ENCRYPT) != 0;
switch (data[curIndex] & FLAG_TYPE_MASK) {
case FLAG_TYPE_LS:
_type = Type.LS;
break;
case FLAG_TYPE_RI:
_type = Type.RI;
break;
case FLAG_TYPE_EXPL:
_type = Type.EXPL;
break;
case FLAG_TYPE_ANY:
default:
_type = Type.ANY;
break;
}
curIndex++; curIndex++;
if (tunnelSpecified) { if (tunnelSpecified) {
@ -348,6 +408,21 @@ public class DatabaseLookupMessage extends FastI2NPMessageImpl {
byte flag = FLAG_TUNNEL; byte flag = FLAG_TUNNEL;
if (_replyKey != null) if (_replyKey != null)
flag |= FLAG_ENCRYPT; 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;
}
out[curIndex++] = flag; out[curIndex++] = flag;
byte id[] = DataHelper.toLong(4, _replyTunnel.getTunnelId()); byte id[] = DataHelper.toLong(4, _replyTunnel.getTunnelId());
System.arraycopy(id, 0, out, curIndex, 4); System.arraycopy(id, 0, out, curIndex, 4);
@ -410,6 +485,7 @@ public class DatabaseLookupMessage extends FastI2NPMessageImpl {
public String toString() { public String toString() {
StringBuilder buf = new StringBuilder(256); StringBuilder buf = new StringBuilder(256);
buf.append("[DatabaseLookupMessage: "); buf.append("[DatabaseLookupMessage: ");
buf.append("\n\tSearch Type: ").append(_type);
buf.append("\n\tSearch Key: ").append(_key); buf.append("\n\tSearch Key: ").append(_key);
if (_replyKey != null) if (_replyKey != null)
buf.append("\n\tReply GW: "); buf.append("\n\tReply GW: ");

View File

@ -18,7 +18,7 @@ public class RouterVersion {
/** deprecated */ /** deprecated */
public final static String ID = "Monotone"; public final static String ID = "Monotone";
public final static String VERSION = CoreVersion.VERSION; public final static String VERSION = CoreVersion.VERSION;
public final static long BUILD = 9; public final static long BUILD = 10;
/** for example "-test" */ /** for example "-test" */
public final static String EXTRA = ""; public final static String EXTRA = "";

View File

@ -9,6 +9,7 @@ package net.i2p.router.networkdb;
*/ */
import java.util.Collections; import java.util.Collections;
import java.util.HashSet;
import java.util.Set; import java.util.Set;
import net.i2p.data.DatabaseEntry; import net.i2p.data.DatabaseEntry;
@ -82,9 +83,11 @@ public class HandleDatabaseLookupMessageJob extends JobImpl {
return; return;
} }
DatabaseLookupMessage.Type lookupType = _message.getSearchType();
// only lookup once, then cast to correct type // only lookup once, then cast to correct type
DatabaseEntry dbe = getContext().netDb().lookupLocally(_message.getSearchKey()); DatabaseEntry dbe = getContext().netDb().lookupLocally(_message.getSearchKey());
if (dbe != null && dbe.getType() == DatabaseEntry.KEY_TYPE_LEASESET) { if (dbe != null && dbe.getType() == DatabaseEntry.KEY_TYPE_LEASESET &&
(lookupType == DatabaseLookupMessage.Type.ANY || lookupType == DatabaseLookupMessage.Type.LS)) {
LeaseSet ls = (LeaseSet) dbe; LeaseSet ls = (LeaseSet) dbe;
// We have to be very careful here to decide whether or not to send out the leaseSet, // We have to be very careful here to decide whether or not to send out the leaseSet,
// to avoid anonymity vulnerabilities. // to avoid anonymity vulnerabilities.
@ -131,7 +134,7 @@ public class HandleDatabaseLookupMessageJob extends JobImpl {
if (_log.shouldLog(Log.INFO)) if (_log.shouldLog(Log.INFO))
_log.info("We have local LS " + _message.getSearchKey() + ", NOT answering query, out of our keyspace"); _log.info("We have local LS " + _message.getSearchKey() + ", NOT answering query, out of our keyspace");
getContext().statManager().addRateData("netDb.lookupsMatchedLocalNotClosest", 1); getContext().statManager().addRateData("netDb.lookupsMatchedLocalNotClosest", 1);
Set<Hash> routerHashSet = getNearestRouters(); Set<Hash> routerHashSet = getNearestRouters(lookupType);
sendClosest(_message.getSearchKey(), routerHashSet, fromKey, _message.getReplyTunnel()); sendClosest(_message.getSearchKey(), routerHashSet, fromKey, _message.getReplyTunnel());
} }
} else { } else {
@ -144,10 +147,11 @@ public class HandleDatabaseLookupMessageJob extends JobImpl {
", NOT answering query - local? " + isLocal + " shouldPublish? " + shouldPublishLocal + ", NOT answering query - local? " + isLocal + " shouldPublish? " + shouldPublishLocal +
" RAP? " + ls.getReceivedAsPublished() + " RAR? " + ls.getReceivedAsReply()); " RAP? " + ls.getReceivedAsPublished() + " RAR? " + ls.getReceivedAsReply());
getContext().statManager().addRateData("netDb.lookupsMatchedRemoteNotClosest", 1); getContext().statManager().addRateData("netDb.lookupsMatchedRemoteNotClosest", 1);
Set<Hash> routerHashSet = getNearestRouters(); Set<Hash> routerHashSet = getNearestRouters(lookupType);
sendClosest(_message.getSearchKey(), routerHashSet, fromKey, _message.getReplyTunnel()); sendClosest(_message.getSearchKey(), routerHashSet, fromKey, _message.getReplyTunnel());
} }
} else if (dbe != null && dbe.getType() == DatabaseEntry.KEY_TYPE_ROUTERINFO) { } else if (dbe != null && dbe.getType() == DatabaseEntry.KEY_TYPE_ROUTERINFO &&
lookupType != DatabaseLookupMessage.Type.LS) {
RouterInfo info = (RouterInfo) dbe; RouterInfo info = (RouterInfo) dbe;
if (info.isCurrent(EXPIRE_DELAY)) { if (info.isCurrent(EXPIRE_DELAY)) {
if ( (info.getIdentity().isHidden()) || (isUnreachable(info) && !publishUnreachable()) ) { if ( (info.getIdentity().isHidden()) || (isUnreachable(info) && !publishUnreachable()) ) {
@ -172,7 +176,7 @@ public class HandleDatabaseLookupMessageJob extends JobImpl {
} }
} else { } else {
// expired locally - return closest peer hashes // expired locally - return closest peer hashes
Set<Hash> routerHashSet = getNearestRouters(); Set<Hash> routerHashSet = getNearestRouters(lookupType);
// ERR: see above // ERR: see above
// // Remove hidden nodes from set.. // // Remove hidden nodes from set..
@ -190,7 +194,7 @@ public class HandleDatabaseLookupMessageJob extends JobImpl {
} }
} else { } else {
// not found locally - return closest peer hashes // not found locally - return closest peer hashes
Set<Hash> routerHashSet = getNearestRouters(); Set<Hash> routerHashSet = getNearestRouters(lookupType);
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("We do not have key " + _message.getSearchKey() + _log.debug("We do not have key " + _message.getSearchKey() +
" locally. sending back " + routerHashSet.size() + " peers to " + fromKey); " locally. sending back " + routerHashSet.size() + " peers to " + fromKey);
@ -204,13 +208,23 @@ public class HandleDatabaseLookupMessageJob extends JobImpl {
* Will not include us. * Will not include us.
* Side effect - adds us to the message's dontInclude set. * Side effect - adds us to the message's dontInclude set.
*/ */
private Set<Hash> getNearestRouters() { private Set<Hash> getNearestRouters(DatabaseLookupMessage.Type lookupType) {
// convert the new EXPL type flag to the old-style FAKE_HASH
// to pass to findNearestRouters()
Set<Hash> dontInclude = _message.getDontIncludePeers(); Set<Hash> dontInclude = _message.getDontIncludePeers();
Hash us = getContext().routerHash(); Hash us = getContext().routerHash();
if (dontInclude == null) if (dontInclude == null && lookupType == DatabaseLookupMessage.Type.EXPL) {
dontInclude = Collections.singleton(us); dontInclude = new HashSet<Hash>(2);
else
dontInclude.add(us); dontInclude.add(us);
dontInclude.add(Hash.FAKE_HASH);
} else if (dontInclude == null) {
dontInclude = Collections.singleton(us);
} else if (lookupType == DatabaseLookupMessage.Type.EXPL) {
dontInclude.add(us);
dontInclude.add(Hash.FAKE_HASH);
} else {
dontInclude.add(us);
}
// Honor flag to exclude all floodfills // Honor flag to exclude all floodfills
//if (dontInclude.contains(Hash.FAKE_HASH)) { //if (dontInclude.contains(Hash.FAKE_HASH)) {
// This is handled in FloodfillPeerSelector // This is handled in FloodfillPeerSelector

View File

@ -99,6 +99,8 @@ class ExploreJob extends SearchJob {
if (dontIncludePeers.add(Hash.FAKE_HASH)) if (dontIncludePeers.add(Hash.FAKE_HASH))
available--; available--;
} }
// supported as of 0.9.16. TODO remove fake hash above
msg.setSearchType(DatabaseLookupMessage.Type.EXPL);
KBucketSet<Hash> ks = _facade.getKBuckets(); KBucketSet<Hash> ks = _facade.getKBuckets();
Hash rkey = getContext().routingKeyGenerator().getRoutingKey(getState().getTarget()); Hash rkey = getContext().routingKeyGenerator().getRoutingKey(getState().getTarget());

View File

@ -215,6 +215,7 @@ class FloodfillVerifyStoreJob extends JobImpl {
m.setReplyTunnel(replyTunnelInfo.getReceiveTunnelId(0)); m.setReplyTunnel(replyTunnelInfo.getReceiveTunnelId(0));
m.setFrom(replyTunnelInfo.getPeer(0)); m.setFrom(replyTunnelInfo.getPeer(0));
m.setSearchKey(_key); m.setSearchKey(_key);
m.setSearchType(_isRouterInfo ? DatabaseLookupMessage.Type.RI : DatabaseLookupMessage.Type.LS);
return m; return m;
} }

View File

@ -307,6 +307,7 @@ class IterativeSearchJob extends FloodSearchJob {
dlm.setMessageExpiration(getContext().clock().now() + SINGLE_SEARCH_MSG_TIME); dlm.setMessageExpiration(getContext().clock().now() + SINGLE_SEARCH_MSG_TIME);
dlm.setReplyTunnel(replyTunnel.getReceiveTunnelId(0)); dlm.setReplyTunnel(replyTunnel.getReceiveTunnelId(0));
dlm.setSearchKey(_key); dlm.setSearchKey(_key);
dlm.setSearchType(_isLease ? DatabaseLookupMessage.Type.LS : DatabaseLookupMessage.Type.RI);
if (_log.shouldLog(Log.INFO)) { if (_log.shouldLog(Log.INFO)) {
int tries; int tries;

View File

@ -19,6 +19,9 @@ class SingleSearchJob extends FloodOnlySearchJob {
private static final int TIMEOUT = 8*1000; private static final int TIMEOUT = 8*1000;
/**
* @param key for Router Info ONLY
*/
public SingleSearchJob(RouterContext ctx, Hash key, Hash to) { public SingleSearchJob(RouterContext ctx, Hash key, Hash to) {
// warning, null FloodfillNetworkDatabaseFacade ... // warning, null FloodfillNetworkDatabaseFacade ...
// define our own failed() and success() below so _facade isn't used. // define our own failed() and success() below so _facade isn't used.
@ -46,6 +49,7 @@ class SingleSearchJob extends FloodOnlySearchJob {
dlm.setMessageExpiration(getContext().clock().now()+5*1000); dlm.setMessageExpiration(getContext().clock().now()+5*1000);
dlm.setReplyTunnel(replyTunnel.getReceiveTunnelId(0)); dlm.setReplyTunnel(replyTunnel.getReceiveTunnelId(0));
dlm.setSearchKey(_key); dlm.setSearchKey(_key);
dlm.setSearchType(DatabaseLookupMessage.Type.RI);
if (_log.shouldLog(Log.INFO)) if (_log.shouldLog(Log.INFO))
_log.info(getJobId() + ": Single search for " + _key + " to " + _to); _log.info(getJobId() + ": Single search for " + _key + " to " + _to);