use of net.i2p.data.i2np.DatabaseLookupMessage in project i2p.i2p by i2p.
the class FloodfillVerifyStoreJob method buildLookup.
/**
* @return non-null
*/
private DatabaseLookupMessage buildLookup(TunnelInfo replyTunnelInfo) {
// If we are verifying a leaseset, use the destination's own tunnels,
// to avoid association by the exploratory tunnel OBEP.
// Unless it is an encrypted leaseset.
DatabaseLookupMessage m = new DatabaseLookupMessage(getContext(), true);
m.setMessageExpiration(getContext().clock().now() + VERIFY_TIMEOUT);
m.setReplyTunnel(replyTunnelInfo.getReceiveTunnelId(0));
m.setFrom(replyTunnelInfo.getPeer(0));
m.setSearchKey(_key);
m.setSearchType(_isRouterInfo ? DatabaseLookupMessage.Type.RI : DatabaseLookupMessage.Type.LS);
return m;
}
use of net.i2p.data.i2np.DatabaseLookupMessage in project i2p.i2p by i2p.
the class FloodfillVerifyStoreJob method runJob.
/**
* Query a random floodfill for the leaseset or routerinfo
* that we just stored to a (hopefully different) floodfill peer.
*
* If it fails (after a timeout period), resend the data.
* If the queried data is older than what we stored, that counts as a fail.
*/
public void runJob() {
_target = pickTarget();
if (_target == null) {
_facade.verifyFinished(_key);
return;
}
boolean isInboundExploratory;
TunnelInfo replyTunnelInfo;
if (_isRouterInfo || getContext().keyRing().get(_key) != null) {
replyTunnelInfo = getContext().tunnelManager().selectInboundExploratoryTunnel(_target);
isInboundExploratory = true;
} else {
replyTunnelInfo = getContext().tunnelManager().selectInboundTunnel(_key, _target);
isInboundExploratory = false;
}
if (replyTunnelInfo == null) {
if (_log.shouldLog(Log.WARN))
_log.warn("No inbound tunnels to get a reply from!");
return;
}
DatabaseLookupMessage lookup = buildLookup(replyTunnelInfo);
// If we are verifying a leaseset, use the destination's own tunnels,
// to avoid association by the exploratory tunnel OBEP.
// Unless it is an encrypted leaseset.
TunnelInfo outTunnel;
if (_isRouterInfo || getContext().keyRing().get(_key) != null)
outTunnel = getContext().tunnelManager().selectOutboundExploratoryTunnel(_target);
else
outTunnel = getContext().tunnelManager().selectOutboundTunnel(_key, _target);
if (outTunnel == null) {
if (_log.shouldLog(Log.WARN))
_log.warn("No outbound tunnels to verify a store");
_facade.verifyFinished(_key);
return;
}
// garlic encrypt to hide contents from the OBEP
RouterInfo peer = _facade.lookupRouterInfoLocally(_target);
if (peer == null) {
if (_log.shouldLog(Log.WARN))
_log.warn("Fail finding target RI");
_facade.verifyFinished(_key);
return;
}
if (DatabaseLookupMessage.supportsEncryptedReplies(peer)) {
// register the session with the right SKM
MessageWrapper.OneTimeSession sess;
if (isInboundExploratory) {
sess = MessageWrapper.generateSession(getContext());
} else {
sess = MessageWrapper.generateSession(getContext(), _key);
if (sess == null) {
if (_log.shouldLog(Log.WARN))
_log.warn("No SKM to reply to");
_facade.verifyFinished(_key);
return;
}
}
if (_log.shouldLog(Log.INFO))
_log.info("Requesting encrypted reply from " + _target + ' ' + sess.key + ' ' + sess.tag);
lookup.setReplySession(sess.key, sess.tag);
}
Hash fromKey;
if (_isRouterInfo)
fromKey = null;
else
fromKey = _key;
_wrappedMessage = MessageWrapper.wrap(getContext(), lookup, fromKey, peer);
if (_wrappedMessage == null) {
if (_log.shouldLog(Log.WARN))
_log.warn("Fail Garlic encrypting");
_facade.verifyFinished(_key);
return;
}
I2NPMessage sent = _wrappedMessage.getMessage();
if (_log.shouldLog(Log.INFO))
_log.info("Starting verify (stored " + _key + " to " + _sentTo + "), asking " + _target);
_sendTime = getContext().clock().now();
_expiration = _sendTime + VERIFY_TIMEOUT;
getContext().messageRegistry().registerPending(new VerifyReplySelector(), new VerifyReplyJob(getContext()), new VerifyTimeoutJob(getContext()));
getContext().tunnelDispatcher().dispatchOutbound(sent, outTunnel.getSendTunnelId(0), _target);
}
use of net.i2p.data.i2np.DatabaseLookupMessage in project i2p.i2p by i2p.
the class SingleSearchJob method runJob.
@Override
public void runJob() {
_onm = getContext().messageRegistry().registerPending(_replySelector, _onReply, _onTimeout);
DatabaseLookupMessage dlm = new DatabaseLookupMessage(getContext(), true);
TunnelInfo replyTunnel = getContext().tunnelManager().selectInboundExploratoryTunnel(_to);
TunnelInfo outTunnel = getContext().tunnelManager().selectOutboundExploratoryTunnel(_to);
if ((replyTunnel == null) || (outTunnel == null)) {
failed();
return;
}
dlm.setFrom(replyTunnel.getPeer(0));
dlm.setMessageExpiration(getContext().clock().now() + 5 * 1000);
dlm.setReplyTunnel(replyTunnel.getReceiveTunnelId(0));
dlm.setSearchKey(_key);
dlm.setSearchType(DatabaseLookupMessage.Type.RI);
if (_log.shouldLog(Log.INFO))
_log.info(getJobId() + ": Single search for " + _key + " to " + _to);
getContext().tunnelDispatcher().dispatchOutbound(dlm, outTunnel.getSendTunnelId(0), _to);
_lookupsRemaining.set(1);
}
use of net.i2p.data.i2np.DatabaseLookupMessage in project i2p.i2p by i2p.
the class ExploreJob method buildMessage.
/**
* Build the database search message, but unlike the normal searches, we're more explicit in
* what we /dont/ want. We don't just ask them to ignore the peers we've already searched
* on, but to ignore a number of the peers we already know about (in the target key's bucket) as well.
*
* Perhaps we may want to ignore other keys too, such as the ones in nearby
* buckets, but we probably don't want the dontIncludePeers set to get too
* massive (aka sending the entire routing table as 'dont tell me about these
* guys'). but maybe we do. dunno. lots of implications.
*
* FloodfillPeerSelector would add only the floodfill peers,
* and PeerSelector doesn't include the floodfill peers,
* so we add the ff peers ourselves and then use the regular PeerSelector.
*
* @param replyTunnelId tunnel to receive replies through, or our router hash if replyGateway is null
* @param replyGateway gateway for the reply tunnel, if null, we are sending direct, do not encrypt
* @param expiration when the search should stop
* @param peer the peer to send it to
*
* @return a DatabaseLookupMessage or GarlicMessage or null on error
*/
@Override
protected I2NPMessage buildMessage(TunnelId replyTunnelId, Hash replyGateway, long expiration, RouterInfo peer) {
DatabaseLookupMessage msg = new DatabaseLookupMessage(getContext(), true);
msg.setSearchKey(getState().getTarget());
msg.setFrom(replyGateway);
// Moved below now that DLM makes a copy
// msg.setDontIncludePeers(getState().getClosestAttempted(MAX_CLOSEST));
Set<Hash> dontIncludePeers = getState().getClosestAttempted(MAX_CLOSEST);
msg.setMessageExpiration(expiration);
if (replyTunnelId != null)
msg.setReplyTunnel(replyTunnelId);
int available = MAX_CLOSEST - dontIncludePeers.size();
if (available > 0) {
// Supported as of 0.7.9
if (dontIncludePeers.add(Hash.FAKE_HASH))
available--;
}
// supported as of 0.9.16. TODO remove fake hash above
msg.setSearchType(DatabaseLookupMessage.Type.EXPL);
KBucketSet<Hash> ks = _facade.getKBuckets();
Hash rkey = getContext().routingKeyGenerator().getRoutingKey(getState().getTarget());
// in a few releases, we can (and should) remove this,
// as routers will honor the above flag, and we want the table to include
// only non-floodfills.
// Removed in 0.8.8, good thing, as we had well over MAX_CLOSEST floodfills.
// if (available > 0 && ks != null) {
// List peers = _peerSelector.selectFloodfillParticipants(rkey, available, ks);
// int len = peers.size();
// if (len > 0)
// msg.getDontIncludePeers().addAll(peers);
// }
available = MAX_CLOSEST - dontIncludePeers.size();
if (available > 0) {
// selectNearestExplicit adds our hash to the dontInclude set (3rd param) ...
// And we end up with MAX_CLOSEST+1 entries.
// We don't want our hash in the message's don't-include list though.
// We're just exploring, but this could give things away, and tie our exploratory tunnels to our router,
// so let's not put our hash in there.
Set<Hash> dontInclude = new HashSet<Hash>(dontIncludePeers);
List<Hash> peers = _peerSelector.selectNearestExplicit(rkey, available, dontInclude, ks);
dontIncludePeers.addAll(peers);
}
if (_log.shouldLog(Log.DEBUG))
_log.debug("Peers we don't want to hear about: " + dontIncludePeers);
msg.setDontIncludePeers(dontIncludePeers);
// Now encrypt if we can
I2NPMessage outMsg;
if (replyTunnelId != null && getContext().getProperty(IterativeSearchJob.PROP_ENCRYPT_RI, IterativeSearchJob.DEFAULT_ENCRYPT_RI)) {
// request encrypted reply?
if (DatabaseLookupMessage.supportsEncryptedReplies(peer)) {
MessageWrapper.OneTimeSession sess;
sess = MessageWrapper.generateSession(getContext());
if (_log.shouldLog(Log.INFO))
_log.info(getJobId() + ": Requesting encrypted reply from " + peer.getIdentity().calculateHash() + ' ' + sess.key + ' ' + sess.tag);
msg.setReplySession(sess.key, sess.tag);
}
// may be null
outMsg = MessageWrapper.wrap(getContext(), msg, peer);
if (_log.shouldLog(Log.DEBUG))
_log.debug(getJobId() + ": Encrypted exploratory DLM for " + getState().getTarget() + " to " + peer.getIdentity().calculateHash());
} else {
outMsg = msg;
}
return outMsg;
}
use of net.i2p.data.i2np.DatabaseLookupMessage in project i2p.i2p by i2p.
the class IterativeSearchJob method sendQuery.
/**
* Send a DLM to the peer
*/
private void sendQuery(Hash peer) {
TunnelManagerFacade tm = getContext().tunnelManager();
RouterInfo ri = getContext().netDb().lookupRouterInfoLocally(peer);
if (ri != null) {
// Now that most of the netdb is Ed RIs and EC LSs, don't even bother
// querying old floodfills that don't know about those sig types.
// This is also more recent than the version that supports encrypted replies,
// so we won't request unencrypted replies anymore either.
String v = ri.getVersion();
String since = MIN_QUERY_VERSION;
if (VersionComparator.comp(v, since) < 0) {
failed(peer, false);
if (_log.shouldLog(Log.WARN))
_log.warn(getJobId() + ": not sending query to old version " + v + ": " + peer);
return;
}
}
TunnelInfo outTunnel;
TunnelInfo replyTunnel;
boolean isClientReplyTunnel;
boolean isDirect;
if (_fromLocalDest != null) {
outTunnel = tm.selectOutboundTunnel(_fromLocalDest, peer);
if (outTunnel == null)
outTunnel = tm.selectOutboundExploratoryTunnel(peer);
replyTunnel = tm.selectInboundTunnel(_fromLocalDest, peer);
isClientReplyTunnel = replyTunnel != null;
if (!isClientReplyTunnel)
replyTunnel = tm.selectInboundExploratoryTunnel(peer);
isDirect = false;
} else if ((!_isLease) && ri != null && getContext().commSystem().isEstablished(peer)) {
// If it's a RI lookup, not from a client, and we're already connected, just ask directly
// This also saves the ElG encryption for us and the decryption for the ff
// There's no anonymity reason to use an expl. tunnel... the main reason
// is to limit connections to the ffs. But if we're already connected,
// do it the fast and easy way.
outTunnel = null;
replyTunnel = null;
isClientReplyTunnel = false;
isDirect = true;
getContext().statManager().addRateData("netDb.RILookupDirect", 1);
} else {
outTunnel = tm.selectOutboundExploratoryTunnel(peer);
replyTunnel = tm.selectInboundExploratoryTunnel(peer);
isClientReplyTunnel = false;
isDirect = false;
getContext().statManager().addRateData("netDb.RILookupDirect", 0);
}
if ((!isDirect) && (replyTunnel == null || outTunnel == null)) {
failed();
return;
}
// not being able to send to the floodfill, if we don't have an older netdb entry.
if (outTunnel != null && outTunnel.getLength() <= 1) {
if (peer.equals(_key)) {
failed(peer, false);
if (_log.shouldLog(Log.WARN))
_log.warn(getJobId() + ": not doing zero-hop self-lookup of " + peer);
return;
}
if (_facade.lookupLocallyWithoutValidation(peer) == null) {
failed(peer, false);
if (_log.shouldLog(Log.WARN))
_log.warn(getJobId() + ": not doing zero-hop lookup to unknown " + peer);
return;
}
}
DatabaseLookupMessage dlm = new DatabaseLookupMessage(getContext(), true);
if (isDirect) {
dlm.setFrom(getContext().routerHash());
} else {
dlm.setFrom(replyTunnel.getPeer(0));
dlm.setReplyTunnel(replyTunnel.getReceiveTunnelId(0));
}
dlm.setMessageExpiration(getContext().clock().now() + SINGLE_SEARCH_MSG_TIME);
dlm.setSearchKey(_key);
dlm.setSearchType(_isLease ? DatabaseLookupMessage.Type.LS : DatabaseLookupMessage.Type.RI);
if (_log.shouldLog(Log.INFO)) {
int tries;
synchronized (this) {
tries = _unheardFrom.size() + _failedPeers.size();
}
_log.info(getJobId() + ": ISJ try " + tries + " for " + (_isLease ? "LS " : "RI ") + _key + " to " + peer + " direct? " + isDirect + " reply via client tunnel? " + isClientReplyTunnel);
}
long now = getContext().clock().now();
_sentTime.put(peer, Long.valueOf(now));
I2NPMessage outMsg = null;
if (isDirect) {
// never wrap
} else if (_isLease || (getContext().getProperty(PROP_ENCRYPT_RI, DEFAULT_ENCRYPT_RI) && getContext().jobQueue().getMaxLag() < 300)) {
// if we have the ff RI, garlic encrypt it
if (ri != null) {
// if (DatabaseLookupMessage.supportsEncryptedReplies(ri)) {
if (true) {
MessageWrapper.OneTimeSession sess;
if (isClientReplyTunnel)
sess = MessageWrapper.generateSession(getContext(), _fromLocalDest);
else
sess = MessageWrapper.generateSession(getContext());
if (sess != null) {
if (_log.shouldLog(Log.INFO))
_log.info(getJobId() + ": Requesting encrypted reply from " + peer + ' ' + sess.key + ' ' + sess.tag);
dlm.setReplySession(sess.key, sess.tag);
}
// else client went away, but send it anyway
}
outMsg = MessageWrapper.wrap(getContext(), dlm, ri);
// a response may have come in.
if (_dead) {
if (_log.shouldLog(Log.DEBUG))
_log.debug(getJobId() + ": aborting send, finished while wrapping msg to " + peer);
return;
}
if (_log.shouldLog(Log.DEBUG))
_log.debug(getJobId() + ": Encrypted DLM for " + _key + " to " + peer);
}
}
if (outMsg == null)
outMsg = dlm;
if (isDirect) {
OutNetMessage m = new OutNetMessage(getContext(), outMsg, outMsg.getMessageExpiration(), OutNetMessage.PRIORITY_MY_NETDB_LOOKUP, ri);
// Should always succeed, we are connected already
// m.setOnFailedReplyJob(onFail);
// m.setOnFailedSendJob(onFail);
// m.setOnReplyJob(onReply);
// m.setReplySelector(selector);
// getContext().messageRegistry().registerPending(m);
getContext().commSystem().processMessage(m);
} else {
getContext().tunnelDispatcher().dispatchOutbound(outMsg, outTunnel.getSendTunnelId(0), peer);
}
// The timeout job is always run (never cancelled)
// Note that the timeout is much shorter than the message expiration (see above)
Job j = new IterativeTimeoutJob(getContext(), peer, this);
long expire = Math.min(_expiration, now + _singleSearchTime);
j.getTiming().setStartAfter(expire);
getContext().jobQueue().addJob(j);
}
Aggregations