NetDB: Track client that requested LS

OCMOSJ: Don't send to a RAP LS
This commit is contained in:
zzz
2020-08-01 12:36:31 +00:00
parent d1bdeae596
commit d73b327fd0
7 changed files with 97 additions and 12 deletions

View File

@ -70,6 +70,7 @@ public class LeaseSet extends DatabaseEntry {
protected final List<Lease> _leases;
protected boolean _receivedAsPublished;
private boolean _receivedAsReply;
private Hash _receivedBy;
// Store these since isCurrent() and getEarliestLeaseDate() are called frequently
private long _firstExpiration;
protected long _lastExpiration;
@ -198,9 +199,30 @@ public class LeaseSet extends DatabaseEntry {
*/
public boolean getReceivedAsReply() { return _receivedAsReply; }
/** set to true @since 0.7.14 */
/**
* set to true
* @since 0.7.14
*/
public void setReceivedAsReply() { _receivedAsReply = true; }
/**
* The Hash of the local client that received this LS,
* null if the router or unknown.
*
* @since 0.9.47
*/
public Hash getReceivedBy() { return _receivedBy; }
/**
* Also sets receivedAsReply to true
* @param localClient may be null
* @since 0.9.47
*/
public void setReceivedBy(Hash localClient) {
_receivedAsReply = true;
_receivedBy = localClient;
}
/**
* @throws IllegalStateException if already signed
*/

View File

@ -74,6 +74,17 @@ public abstract class NetworkDatabaseFacade implements Service {
*/
public abstract void lookupLeaseSetRemotely(Hash key, Hash fromLocalDest);
/**
* Unconditionally lookup using the client's tunnels.
*
* @param fromLocalDest use these tunnels for the lookup, or null for exploratory
* @param onFindJob may be null
* @param onFailedLookupJob may be null
* @since 0.9.47
*/
public abstract void lookupLeaseSetRemotely(Hash key, Job onFindJob, Job onFailedLookupJob,
long timeoutMs, Hash fromLocalDest);
/**
* Lookup using the client's tunnels
* Succeeds even if LS validation fails due to unsupported sig type

View File

@ -45,6 +45,8 @@ public class DummyNetworkDatabaseFacade extends NetworkDatabaseFacade {
public void lookupLeaseSet(Hash key, Job onFindJob, Job onFailedLookupJob, long timeoutMs, Hash fromLocalDest) {}
public LeaseSet lookupLeaseSetLocally(Hash key) { return null; }
public void lookupLeaseSetRemotely(Hash key, Hash fromLocalDest) {}
public void lookupLeaseSetRemotely(Hash key, Job onFindJob, Job onFailedLookupJob,
long timeoutMs, Hash fromLocalDest) {}
public void lookupDestination(Hash key, Job onFinishedJob, long timeoutMs, Hash fromLocalDest) {}

View File

@ -207,7 +207,7 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
_to = msg.getDestination();
Hash toHash = _to.calculateHash();
_hashPair = new OutboundCache.HashPair(_from.calculateHash(), toHash);
_toString = toHash.toBase64().substring(0,4);
_toString = toHash.toBase32();
// we look up here rather than runJob() so we may adjust the timeout
_leaseSet = ctx.netDb().lookupLeaseSetLocally(toHash);
@ -297,6 +297,23 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
SendJob success = new SendJob(getContext());
// set in constructor
if (_leaseSet != null) {
if (!_leaseSet.getReceivedAsReply()) {
boolean shouldFetch = true;
if (_leaseSet.getType() != DatabaseEntry.KEY_TYPE_LEASESET) {
LeaseSet2 ls2 = (LeaseSet2) _leaseSet;
shouldFetch = !ls2.isUnpublished() || ls2.isBlindedWhenPublished();
}
if (shouldFetch) {
if (_log.shouldInfo())
_log.info(getJobId() + ": RAP LS, firing search: " + _leaseSet.getHash().toBase32());
LookupLeaseSetFailedJob failed = new LookupLeaseSetFailedJob(getContext());
getContext().netDb().lookupLeaseSetRemotely(_leaseSet.getHash(), success, failed,
LS_LOOKUP_TIMEOUT, _from.calculateHash());
} else {
dieFatal(MessageStatusMessage.STATUS_SEND_FAILURE_NO_LEASESET);
}
return;
}
if (_log.shouldLog(Log.DEBUG))
_log.debug(getJobId() + ": Send outbound client message - leaseSet found locally for " + _toString);
if (!_leaseSet.isCurrent(Router.CLOCK_FUDGE_FACTOR / 4)) {
@ -405,13 +422,17 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
*/
private int getNextLease() {
// set in runJob if found locally
if (_leaseSet == null) {
if (_leaseSet == null || !_leaseSet.getReceivedAsReply()) {
_leaseSet = getContext().netDb().lookupLeaseSetLocally(_to.calculateHash());
if (_leaseSet == null) {
// shouldn't happen
if (_log.shouldLog(Log.WARN))
_log.warn(getJobId() + ": Lookup locally didn't find the leaseSet for " + _toString);
return MessageStatusMessage.STATUS_SEND_FAILURE_NO_LEASESET;
} else if (_leaseSet.getReceivedAsPublished()) {
if (_log.shouldLog(Log.WARN))
_log.warn(getJobId() + ": Only have RAP LS for " + _toString);
return MessageStatusMessage.STATUS_SEND_FAILURE_NO_LEASESET;
}
}
@ -571,8 +592,8 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
_log.warn("Unable to send to " + _toString + " because the sig type is unsupported");
cause = MessageStatusMessage.STATUS_SEND_FAILURE_UNSUPPORTED_ENCRYPTION;
} else {
if (_log.shouldLog(Log.WARN))
_log.warn("Unable to send to " + _toString + " because we couldn't find their leaseSet");
if (_log.shouldInfo())
_log.info("Unable to send to " + _toString + ", no LS found");
cause = MessageStatusMessage.STATUS_SEND_FAILURE_NO_LEASESET;
}

View File

@ -116,16 +116,16 @@ class HandleFloodfillDatabaseStoreMessageJob extends JobImpl {
} else if (match.getEarliestLeaseDate() < ls.getEarliestLeaseDate()) {
wasNew = true;
// If it is in our keyspace and we are talking to it
if (match.getReceivedAsPublished())
ls.setReceivedAsPublished(true);
//if (match.getReceivedAsPublished())
// ls.setReceivedAsPublished(true);
} else if (type != DatabaseEntry.KEY_TYPE_LEASESET &&
match.getType() != DatabaseEntry.KEY_TYPE_LEASESET) {
LeaseSet2 ls2 = (LeaseSet2) ls;
LeaseSet2 match2 = (LeaseSet2) match;
if (match2.getPublished() < ls2.getPublished()) {
wasNew = true;
if (match.getReceivedAsPublished())
ls.setReceivedAsPublished(true);
//if (match.getReceivedAsPublished())
// ls.setReceivedAsPublished(true);
} else {
wasNew = false;
}

View File

@ -602,9 +602,28 @@ public abstract class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacad
public void lookupLeaseSetRemotely(Hash key, Hash fromLocalDest) {
if (!_initialized) return;
key = _blindCache.getHash(key);
if (isNegativeCached(key))
return;
search(key, null, null, 20*1000, true, fromLocalDest);
}
/**
* Unconditionally lookup using the client's tunnels.
*
* @param fromLocalDest use these tunnels for the lookup, or null for exploratory
* @param onFindJob may be null
* @param onFailedLookupJob may be null
* @since 0.9.47
*/
public void lookupLeaseSetRemotely(Hash key, Job onFindJob, Job onFailedLookupJob,
long timeoutMs, Hash fromLocalDest) {
if (!_initialized) return;
key = _blindCache.getHash(key);
if (isNegativeCached(key))
return;
search(key, onFindJob, onFailedLookupJob, timeoutMs, true, fromLocalDest);
}
/**
* Use lookupDestination() if you don't need the LS or don't need it validated.
*/
@ -936,6 +955,16 @@ public abstract class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacad
rv = (LeaseSet)_ds.get(key);
if ( (rv != null) && (rv.equals(leaseSet)) ) {
// if it hasn't changed, no need to do anything
// except copy over the flags
Hash to = leaseSet.getReceivedBy();
if (to != null) {
rv.setReceivedBy(to);
} else if (leaseSet.getReceivedAsReply()) {
rv.setReceivedAsReply();
}
if (leaseSet.getReceivedAsPublished()) {
rv.setReceivedAsPublished(true);
}
return rv;
}
} catch (ClassCastException cce) {

View File

@ -125,7 +125,7 @@ class InboundMessageDistributor implements GarlicMessageReceiver.CloveReceiver {
// allow DSM of our own key (used by FloodfillVerifyStoreJob)
// or other keys (used by IterativeSearchJob)
// as long as there's no reply token (we will never set a reply token but an attacker might)
((LeaseSet)dsm.getEntry()).setReceivedAsReply();
((LeaseSet)dsm.getEntry()).setReceivedBy(_client);
}
break;
@ -155,7 +155,7 @@ class InboundMessageDistributor implements GarlicMessageReceiver.CloveReceiver {
return;
}
if (dsm.getEntry().isLeaseSet())
((LeaseSet)dsm.getEntry()).setReceivedAsReply();
((LeaseSet)dsm.getEntry()).setReceivedBy(_client);
break;
case DatabaseSearchReplyMessage.MESSAGE_TYPE:
@ -264,7 +264,7 @@ class InboundMessageDistributor implements GarlicMessageReceiver.CloveReceiver {
// Or, it's a normal LS bundled with data and a MessageStatusMessage.
// ... and inject it.
((LeaseSet)dsm.getEntry()).setReceivedAsReply();
((LeaseSet)dsm.getEntry()).setReceivedBy(_client);
if (_log.shouldLog(Log.INFO))
_log.info("Storing garlic LS down tunnel for: " + dsm.getKey() + " sent to: " +
(_client != null ? _client.toBase32() : "router"));