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 final List<Lease> _leases;
protected boolean _receivedAsPublished; protected boolean _receivedAsPublished;
private boolean _receivedAsReply; private boolean _receivedAsReply;
private Hash _receivedBy;
// Store these since isCurrent() and getEarliestLeaseDate() are called frequently // Store these since isCurrent() and getEarliestLeaseDate() are called frequently
private long _firstExpiration; private long _firstExpiration;
protected long _lastExpiration; protected long _lastExpiration;
@ -198,9 +199,30 @@ public class LeaseSet extends DatabaseEntry {
*/ */
public boolean getReceivedAsReply() { return _receivedAsReply; } public boolean getReceivedAsReply() { return _receivedAsReply; }
/** set to true @since 0.7.14 */ /**
* set to true
* @since 0.7.14
*/
public void setReceivedAsReply() { _receivedAsReply = true; } 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 * @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); 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 * Lookup using the client's tunnels
* Succeeds even if LS validation fails due to unsupported sig type * 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 void lookupLeaseSet(Hash key, Job onFindJob, Job onFailedLookupJob, long timeoutMs, Hash fromLocalDest) {}
public LeaseSet lookupLeaseSetLocally(Hash key) { return null; } public LeaseSet lookupLeaseSetLocally(Hash key) { return null; }
public void lookupLeaseSetRemotely(Hash key, Hash fromLocalDest) {} 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) {} 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(); _to = msg.getDestination();
Hash toHash = _to.calculateHash(); Hash toHash = _to.calculateHash();
_hashPair = new OutboundCache.HashPair(_from.calculateHash(), toHash); _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 // we look up here rather than runJob() so we may adjust the timeout
_leaseSet = ctx.netDb().lookupLeaseSetLocally(toHash); _leaseSet = ctx.netDb().lookupLeaseSetLocally(toHash);
@ -297,6 +297,23 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
SendJob success = new SendJob(getContext()); SendJob success = new SendJob(getContext());
// set in constructor // set in constructor
if (_leaseSet != null) { 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)) if (_log.shouldLog(Log.DEBUG))
_log.debug(getJobId() + ": Send outbound client message - leaseSet found locally for " + _toString); _log.debug(getJobId() + ": Send outbound client message - leaseSet found locally for " + _toString);
if (!_leaseSet.isCurrent(Router.CLOCK_FUDGE_FACTOR / 4)) { if (!_leaseSet.isCurrent(Router.CLOCK_FUDGE_FACTOR / 4)) {
@ -405,13 +422,17 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
*/ */
private int getNextLease() { private int getNextLease() {
// set in runJob if found locally // set in runJob if found locally
if (_leaseSet == null) { if (_leaseSet == null || !_leaseSet.getReceivedAsReply()) {
_leaseSet = getContext().netDb().lookupLeaseSetLocally(_to.calculateHash()); _leaseSet = getContext().netDb().lookupLeaseSetLocally(_to.calculateHash());
if (_leaseSet == null) { if (_leaseSet == null) {
// shouldn't happen // shouldn't happen
if (_log.shouldLog(Log.WARN)) if (_log.shouldLog(Log.WARN))
_log.warn(getJobId() + ": Lookup locally didn't find the leaseSet for " + _toString); _log.warn(getJobId() + ": Lookup locally didn't find the leaseSet for " + _toString);
return MessageStatusMessage.STATUS_SEND_FAILURE_NO_LEASESET; 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"); _log.warn("Unable to send to " + _toString + " because the sig type is unsupported");
cause = MessageStatusMessage.STATUS_SEND_FAILURE_UNSUPPORTED_ENCRYPTION; cause = MessageStatusMessage.STATUS_SEND_FAILURE_UNSUPPORTED_ENCRYPTION;
} else { } else {
if (_log.shouldLog(Log.WARN)) if (_log.shouldInfo())
_log.warn("Unable to send to " + _toString + " because we couldn't find their leaseSet"); _log.info("Unable to send to " + _toString + ", no LS found");
cause = MessageStatusMessage.STATUS_SEND_FAILURE_NO_LEASESET; cause = MessageStatusMessage.STATUS_SEND_FAILURE_NO_LEASESET;
} }

View File

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

View File

@ -602,9 +602,28 @@ public abstract class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacad
public void lookupLeaseSetRemotely(Hash key, Hash fromLocalDest) { public void lookupLeaseSetRemotely(Hash key, Hash fromLocalDest) {
if (!_initialized) return; if (!_initialized) return;
key = _blindCache.getHash(key); key = _blindCache.getHash(key);
if (isNegativeCached(key))
return;
search(key, null, null, 20*1000, true, fromLocalDest); 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. * 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); rv = (LeaseSet)_ds.get(key);
if ( (rv != null) && (rv.equals(leaseSet)) ) { if ( (rv != null) && (rv.equals(leaseSet)) ) {
// if it hasn't changed, no need to do anything // 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; return rv;
} }
} catch (ClassCastException cce) { } catch (ClassCastException cce) {

View File

@ -125,7 +125,7 @@ class InboundMessageDistributor implements GarlicMessageReceiver.CloveReceiver {
// allow DSM of our own key (used by FloodfillVerifyStoreJob) // allow DSM of our own key (used by FloodfillVerifyStoreJob)
// or other keys (used by IterativeSearchJob) // 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) // 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; break;
@ -155,7 +155,7 @@ class InboundMessageDistributor implements GarlicMessageReceiver.CloveReceiver {
return; return;
} }
if (dsm.getEntry().isLeaseSet()) if (dsm.getEntry().isLeaseSet())
((LeaseSet)dsm.getEntry()).setReceivedAsReply(); ((LeaseSet)dsm.getEntry()).setReceivedBy(_client);
break; break;
case DatabaseSearchReplyMessage.MESSAGE_TYPE: 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. // Or, it's a normal LS bundled with data and a MessageStatusMessage.
// ... and inject it. // ... and inject it.
((LeaseSet)dsm.getEntry()).setReceivedAsReply(); ((LeaseSet)dsm.getEntry()).setReceivedBy(_client);
if (_log.shouldLog(Log.INFO)) if (_log.shouldLog(Log.INFO))
_log.info("Storing garlic LS down tunnel for: " + dsm.getKey() + " sent to: " + _log.info("Storing garlic LS down tunnel for: " + dsm.getKey() + " sent to: " +
(_client != null ? _client.toBase32() : "router")); (_client != null ? _client.toBase32() : "router"));