I2CP, NetDB: More encrypted LS2 fixes (WIP)

Marked encrypted LS hash as local
Fix isCurrent() on encrypted LS
Fix unpublish of encrypted LS
This commit is contained in:
zzz
2019-03-04 17:06:01 +00:00
parent 54d9a29855
commit cd97718682
5 changed files with 120 additions and 10 deletions

View File

@ -281,6 +281,21 @@ public class LeaseSet2 extends LeaseSet {
log.warn("Don't set revocation key in ls2", new Exception("I did it"));
}
/**
* Determine whether the leaseset is currently valid, at least within a given
* fudge factor.
* Overridden to use the expiration time instead of the last expiration.
*
* @param fudge milliseconds fudge factor to allow between the current time
* @return true if there are current leases, false otherwise
* @since 0.9.39
*/
@Override
public boolean isCurrent(long fudge) {
long now = Clock.getInstance().now();
return _expires > now - fudge;
}
/** without sig! */
@Override
protected byte[] getBytes() {

View File

@ -28,6 +28,7 @@ import net.i2p.client.I2PClient;
import net.i2p.crypto.SessionKeyManager;
import net.i2p.data.DatabaseEntry;
import net.i2p.data.Destination;
import net.i2p.data.EncryptedLeaseSet;
import net.i2p.data.Hash;
import net.i2p.data.LeaseSet;
import net.i2p.data.Payload;
@ -99,6 +100,7 @@ class ClientConnectionRunner {
/** For inbound traffic. true if i2cp.fastReceive = "true"; @since 0.9.4 */
private boolean _dontSendMSMOnReceive;
private final AtomicInteger _messageId; // messageId counter
private Hash _encryptedLSHash;
// Was 32767 since the beginning (04-2004).
// But it's 4 bytes in the I2CP spec and stored as a long in MessageID....
@ -125,7 +127,10 @@ class ClientConnectionRunner {
SessionConfig config;
LeaseRequestState leaseRequest;
Rerequest rerequestTimer;
/** possibly decrypted */
LeaseSet currentLeaseSet;
/** only if encrypted */
LeaseSet currentEncryptedLeaseSet;
SessionParams(Destination d, boolean isPrimary) {
dest = d;
@ -199,11 +204,17 @@ class ClientConnectionRunner {
_acceptedPending.clear();
if (_sessionKeyManager != null)
_sessionKeyManager.shutdown();
if (_encryptedLSHash != null)
_manager.unregisterEncryptedDestination(this, _encryptedLSHash);
_manager.unregisterConnection(this);
// netdb may be null in unit tests
if (_context.netDb() != null) {
for (SessionParams sp : _sessions.values()) {
LeaseSet ls = sp.currentLeaseSet;
if (ls != null)
_context.netDb().unpublish(ls);
// unpublish encrypted LS also
ls = sp.currentEncryptedLeaseSet;
if (ls != null)
_context.netDb().unpublish(ls);
if (!sp.isPrimary)
@ -431,6 +442,10 @@ class ClientConnectionRunner {
// Tell client manger
_manager.unregisterSession(id, sp.dest);
LeaseSet ls = sp.currentLeaseSet;
if (ls != null)
_context.netDb().unpublish(ls);
// unpublish encrypted LS also
ls = sp.currentEncryptedLeaseSet;
if (ls != null)
_context.netDb().unpublish(ls);
isPrimary = sp.isPrimary;
@ -446,6 +461,10 @@ class ClientConnectionRunner {
_log.info("Destroying remaining client subsession " + sp.sessionId);
_manager.unregisterSession(sp.sessionId, sp.dest);
LeaseSet ls = sp.currentLeaseSet;
if (ls != null)
_context.netDb().unpublish(ls);
// unpublish encrypted LS also
ls = sp.currentEncryptedLeaseSet;
if (ls != null)
_context.netDb().unpublish(ls);
_context.tunnelManager().removeAlias(sp.dest);
@ -588,6 +607,8 @@ class ClientConnectionRunner {
/**
* called after a new leaseSet is granted by the client, the NetworkDb has been
* updated. This takes care of all the LeaseRequestState stuff (including firing any jobs)
*
* @param ls, if encrypted, the encrypted LS, not the decrypted one
*/
void leaseSetCreated(LeaseSet ls) {
Hash h = ls.getDestination().calculateHash();
@ -596,6 +617,11 @@ class ClientConnectionRunner {
return;
LeaseRequestState state;
synchronized (this) {
if (ls.getType() == DatabaseEntry.KEY_TYPE_ENCRYPTED_LS2) {
EncryptedLeaseSet encls = (EncryptedLeaseSet) ls;
sp.currentEncryptedLeaseSet = encls;
ls = encls.getDecryptedLeaseSet();
}
sp.currentLeaseSet = ls;
state = sp.leaseRequest;
if (state == null) {
@ -616,6 +642,30 @@ class ClientConnectionRunner {
_context.jobQueue().addJob(state.getOnGranted());
}
/**
* Call after destinationEstablished(),
* when an encrypted leaseset is created, so we know it's local.
* Add to the clients list. Check for a dup hash.
* Caller must call runner.disconnectClient() on failure.
*
* @param hash the location of the encrypted LS, will change every day
* @return success, false on dup
* @since 0.9.39
*/
public boolean registerEncryptedLS(Hash hash) {
boolean rv = true;
synchronized(this) {
if (!hash.equals(_encryptedLSHash)) {
if (_encryptedLSHash != null)
_manager.unregisterEncryptedDestination(this, _encryptedLSHash);
rv = _manager.registerEncryptedDestination(this, hash);
if (rv)
_encryptedLSHash = hash;
}
}
return rv;
}
/**
* Send a DisconnectMessage and log with level Log.ERROR.
* This is always bad.

View File

@ -288,6 +288,20 @@ class ClientManager {
}
}
/**
* Remove the hash for the encrypted LS.
* Call before unregisterConnection, or when the hash changes.
*
* @since 0.9.39
*/
public void unregisterEncryptedDestination(ClientConnectionRunner runner, Hash hash) {
if (_log.shouldLog(Log.WARN))
_log.warn("Unregistering encrypted LS " + hash.toBase32());
synchronized (_runners) {
_runnersByHash.remove(hash);
}
}
/**
* Add to the clients list. Check for a dup destination.
* Side effect: Sets the session ID of the runner.
@ -328,6 +342,31 @@ class ClientManager {
return rv;
}
/**
* Call after destinationEstablished(),
* when an encrypted leaseset is created, so we know it's local.
* Add to the clients list. Check for a dup hash.
* Caller must call runner.disconnectClient() on failure.
*
* @param hash the location of the encrypted LS, will change every day
* @return success, false on dup
* @since 0.9.39
*/
public boolean registerEncryptedDestination(ClientConnectionRunner runner, Hash hash) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("New encrypted LS " + hash.toBase32());
boolean rv;
synchronized (_runners) {
rv = !_runnersByHash.containsKey(hash);
if (rv)
_runnersByHash.put(hash, runner);
}
if (!rv)
_log.error("Encrypted dest collision " + hash.toBase32());
return rv;
}
/**
* Generate a new random, unused sessionId. Caller must synch on _runners.
* @return null on failure

View File

@ -632,6 +632,17 @@ class ClientMessageEventListener implements I2CPMessageReader.I2CPMessageEventLi
}
}
try {
if (type == DatabaseEntry.KEY_TYPE_ENCRYPTED_LS2) {
// so the client manager knows it's a local hash
// we could put this in runner.leaseSetCreated(), but
// need to set it before calling publish()
Hash newHash = ls.getHash();
boolean ok = _runner.registerEncryptedLS(newHash);
if (!ok) {
_runner.disconnectClient("Duplicate hash of encrypted LS2");
return;
}
}
if (_log.shouldDebug())
_log.debug("Publishing: " + ls);
_context.netDb().publish(ls);
@ -652,13 +663,8 @@ class ClientMessageEventListener implements I2CPMessageReader.I2CPMessageEventLi
_log.info("New lease set granted for destination " + dest);
// leaseSetCreated takes care of all the LeaseRequestState stuff (including firing any jobs)
if (type == DatabaseEntry.KEY_TYPE_ENCRYPTED_LS2) {
EncryptedLeaseSet encls = (EncryptedLeaseSet) ls;
_runner.leaseSetCreated(encls.getDecryptedLeaseSet());
} else {
_runner.leaseSetCreated(ls);
}
}
/** override for testing */
protected void handleDestLookup(DestLookupMessage message) {

View File

@ -1200,7 +1200,7 @@ public abstract class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacad
public void unpublish(LeaseSet localLeaseSet) {
if (!_initialized) return;
Hash h = localLeaseSet.getDestination().calculateHash();
Hash h = localLeaseSet.getHash();
DatabaseEntry data = _ds.remove(h);
if (data == null) {