Router: Add preliminary support for more LS2 types (proposal 123)

I2CP: Don't require privkeys for meta in CLS2 message
This commit is contained in:
zzz
2018-12-01 13:13:51 +00:00
parent 79440f84eb
commit 026ddb3278
10 changed files with 84 additions and 62 deletions

View File

@ -103,11 +103,34 @@ public abstract class DatabaseEntry extends DataStructureImpl {
* Get the type of the data structure. * Get the type of the data structure.
* This should be faster than instanceof. * This should be faster than instanceof.
* *
* @return KEY_TYPE_ROUTERINFO or KEY_TYPE_LEASESET * @return KEY_TYPE_ROUTERINFO or KEY_TYPE_LEASESET or LS2 types
* @since 0.8.2 * @since 0.8.2
*/ */
public abstract int getType(); public abstract int getType();
/**
* Convenience method, is the type any variant of leaseset?
*
* @return true for any type of LeaseSet, false for RouterInfo, false for others
* @since 0.9.38
*/
public boolean isLeaseSet() {
return isLeaseSet(getType());
}
/**
* Convenience method, is the type any variant of leaseset?
*
* @return true for any type of LeaseSet, false for RouterInfo, false for others
* @since 0.9.38
*/
public static boolean isLeaseSet(int type) {
return type == KEY_TYPE_LEASESET ||
type == KEY_TYPE_LS2 ||
type == KEY_TYPE_ENCRYPTED_LS2 ||
type == KEY_TYPE_META_LS2;
}
/** /**
* Returns the raw payload data, excluding the signature, to be signed by sign(). * Returns the raw payload data, excluding the signature, to be signed by sign().
* *

View File

@ -9,8 +9,10 @@ import net.i2p.crypto.EncType;
import net.i2p.crypto.SigType; import net.i2p.crypto.SigType;
import net.i2p.data.DatabaseEntry; import net.i2p.data.DatabaseEntry;
import net.i2p.data.DataFormatException; import net.i2p.data.DataFormatException;
import net.i2p.data.EncryptedLeaseSet;
import net.i2p.data.LeaseSet; import net.i2p.data.LeaseSet;
import net.i2p.data.LeaseSet2; import net.i2p.data.LeaseSet2;
import net.i2p.data.MetaLeaseSet;
import net.i2p.data.PrivateKey; import net.i2p.data.PrivateKey;
import net.i2p.data.SigningPrivateKey; import net.i2p.data.SigningPrivateKey;
@ -24,6 +26,9 @@ import net.i2p.data.SigningPrivateKey;
* serialized after the LeaseSet, not before, so we can * serialized after the LeaseSet, not before, so we can
* infer the types from the LeaseSet. * infer the types from the LeaseSet.
* *
* For Meta LS:
* SigningPrivateKey and PrivateKey are not present.
*
* @since 0.9.38 * @since 0.9.38
*/ */
public class CreateLeaseSet2Message extends CreateLeaseSetMessage { public class CreateLeaseSet2Message extends CreateLeaseSetMessage {
@ -43,26 +48,32 @@ public class CreateLeaseSet2Message extends CreateLeaseSetMessage {
_leaseSet = new LeaseSet(); _leaseSet = new LeaseSet();
} else if (type == DatabaseEntry.KEY_TYPE_LS2) { } else if (type == DatabaseEntry.KEY_TYPE_LS2) {
_leaseSet = new LeaseSet2(); _leaseSet = new LeaseSet2();
} else if (type == DatabaseEntry.KEY_TYPE_ENCRYPTED_LS2) {
_leaseSet = new EncryptedLeaseSet();
} else if (type == DatabaseEntry.KEY_TYPE_META_LS2) {
_leaseSet = new MetaLeaseSet();
} else if (type == -1) { } else if (type == -1) {
throw new EOFException("EOF reading LS type"); throw new EOFException("EOF reading LS type");
} else { } else {
throw new I2CPMessageException("Unsupported Leaseset type: " + type); throw new I2CPMessageException("Unsupported Leaseset type: " + type);
} }
_leaseSet.readBytes(in); _leaseSet.readBytes(in);
// In CLSM this is the type of the dest, but revocation is unimplemented. if (type != DatabaseEntry.KEY_TYPE_META_LS2) {
// In CLS2M this is the type of the signature (which may be different than the // In CLSM this is the type of the dest, but revocation is unimplemented.
// type of the dest if it's an offline signature) // In CLS2M this is the type of the signature (which may be different than the
// and is needed by the session tag manager. // type of the dest if it's an offline signature)
SigType stype = _leaseSet.getSignature().getType(); // and is needed by the session tag manager.
if (stype == null) SigType stype = _leaseSet.getSignature().getType();
throw new I2CPMessageException("Unsupported sig type"); if (stype == null)
_signingPrivateKey = new SigningPrivateKey(stype); throw new I2CPMessageException("Unsupported sig type");
_signingPrivateKey.readBytes(in); _signingPrivateKey = new SigningPrivateKey(stype);
EncType etype = _leaseSet.getEncryptionKey().getType(); _signingPrivateKey.readBytes(in);
if (etype == null) EncType etype = _leaseSet.getEncryptionKey().getType();
throw new I2CPMessageException("Unsupported encryption type"); if (etype == null)
_privateKey = new PrivateKey(etype); throw new I2CPMessageException("Unsupported encryption type");
_privateKey.readBytes(in); _privateKey = new PrivateKey(etype);
_privateKey.readBytes(in);
}
} catch (DataFormatException dfe) { } catch (DataFormatException dfe) {
throw new I2CPMessageException("Error reading the CreateLeaseSetMessage", dfe); throw new I2CPMessageException("Error reading the CreateLeaseSetMessage", dfe);
} }
@ -70,7 +81,8 @@ public class CreateLeaseSet2Message extends CreateLeaseSetMessage {
@Override @Override
protected byte[] doWriteMessage() throws I2CPMessageException, IOException { protected byte[] doWriteMessage() throws I2CPMessageException, IOException {
if (_sessionId == null || _signingPrivateKey == null || _privateKey == null || _leaseSet == null) if (_sessionId == null || _leaseSet == null ||
(_leaseSet.getType() != DatabaseEntry.KEY_TYPE_META_LS2 && (_signingPrivateKey == null || _privateKey == null)))
throw new I2CPMessageException("Unable to write out the message as there is not enough data"); throw new I2CPMessageException("Unable to write out the message as there is not enough data");
int size = 4 // sessionId int size = 4 // sessionId
+ 1 // type + 1 // type
@ -82,8 +94,10 @@ public class CreateLeaseSet2Message extends CreateLeaseSetMessage {
_sessionId.writeBytes(os); _sessionId.writeBytes(os);
os.write(_leaseSet.getType()); os.write(_leaseSet.getType());
_leaseSet.writeBytes(os); _leaseSet.writeBytes(os);
_signingPrivateKey.writeBytes(os); if (_leaseSet.getType() != DatabaseEntry.KEY_TYPE_META_LS2) {
_privateKey.writeBytes(os); _signingPrivateKey.writeBytes(os);
_privateKey.writeBytes(os);
}
} catch (DataFormatException dfe) { } catch (DataFormatException dfe) {
throw new I2CPMessageException("Error writing out the message data", dfe); throw new I2CPMessageException("Error writing out the message data", dfe);
} }

View File

@ -16,9 +16,11 @@ import net.i2p.I2PAppContext;
import net.i2p.data.DatabaseEntry; import net.i2p.data.DatabaseEntry;
import net.i2p.data.DataFormatException; import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper; import net.i2p.data.DataHelper;
import net.i2p.data.EncryptedLeaseSet;
import net.i2p.data.Hash; import net.i2p.data.Hash;
import net.i2p.data.LeaseSet; import net.i2p.data.LeaseSet;
import net.i2p.data.LeaseSet2; import net.i2p.data.LeaseSet2;
import net.i2p.data.MetaLeaseSet;
import net.i2p.data.router.RouterInfo; import net.i2p.data.router.RouterInfo;
import net.i2p.data.TunnelId; import net.i2p.data.TunnelId;
@ -134,17 +136,15 @@ public class DatabaseStoreMessage extends FastI2NPMessageImpl {
_replyGateway = null; _replyGateway = null;
} }
if (dbType == DatabaseEntry.KEY_TYPE_LEASESET) { if (DatabaseEntry.isLeaseSet(dbType)) {
_dbEntry = new LeaseSet(); if (dbType == DatabaseEntry.KEY_TYPE_LEASESET)
try { _dbEntry = new LeaseSet();
_dbEntry.readBytes(new ByteArrayInputStream(data, curIndex, data.length-curIndex)); else if (dbType == DatabaseEntry.KEY_TYPE_LS2)
} catch (DataFormatException dfe) { _dbEntry = new LeaseSet2();
throw new I2NPMessageException("Error reading the leaseSet", dfe); else if (dbType == DatabaseEntry.KEY_TYPE_ENCRYPTED_LS2)
} catch (IOException ioe) { _dbEntry = new EncryptedLeaseSet();
throw new I2NPMessageException("Error reading the leaseSet", ioe); else
} _dbEntry = new MetaLeaseSet();
} else if (dbType == DatabaseEntry.KEY_TYPE_LS2) {
_dbEntry = new LeaseSet2();
try { try {
_dbEntry.readBytes(new ByteArrayInputStream(data, curIndex, data.length-curIndex)); _dbEntry.readBytes(new ByteArrayInputStream(data, curIndex, data.length-curIndex));
} catch (DataFormatException dfe) { } catch (DataFormatException dfe) {
@ -196,7 +196,7 @@ public class DatabaseStoreMessage extends FastI2NPMessageImpl {
if (_replyToken > 0) if (_replyToken > 0)
len += 4 + Hash.HASH_LENGTH; // replyTunnel+replyGateway len += 4 + Hash.HASH_LENGTH; // replyTunnel+replyGateway
int type = _dbEntry.getType(); int type = _dbEntry.getType();
if (type == DatabaseEntry.KEY_TYPE_LEASESET) { if (_dbEntry.isLeaseSet()) {
if (_byteCache == null) { if (_byteCache == null) {
_byteCache = _dbEntry.toByteArray(); _byteCache = _dbEntry.toByteArray();
} }
@ -218,7 +218,7 @@ public class DatabaseStoreMessage extends FastI2NPMessageImpl {
protected int writeMessageBody(byte out[], int curIndex) throws I2NPMessageException { protected int writeMessageBody(byte out[], int curIndex) throws I2NPMessageException {
if (_dbEntry == null) throw new I2NPMessageException("Missing entry"); if (_dbEntry == null) throw new I2NPMessageException("Missing entry");
int type = _dbEntry.getType(); int type = _dbEntry.getType();
if (type != DatabaseEntry.KEY_TYPE_LEASESET && type != DatabaseEntry.KEY_TYPE_ROUTERINFO) if (type != DatabaseEntry.KEY_TYPE_ROUTERINFO && !_dbEntry.isLeaseSet())
throw new I2NPMessageException("Invalid key type " + type); throw new I2NPMessageException("Invalid key type " + type);
// Use the hash of the DatabaseEntry // Use the hash of the DatabaseEntry

View File

@ -95,7 +95,7 @@ public class HandleDatabaseLookupMessageJob extends JobImpl {
// 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());
int type = dbe != null ? dbe.getType() : -1; int type = dbe != null ? dbe.getType() : -1;
if ((type == DatabaseEntry.KEY_TYPE_LEASESET || type == DatabaseEntry.KEY_TYPE_LS2) && if (DatabaseEntry.isLeaseSet(type) &&
(lookupType == DatabaseLookupMessage.Type.ANY || lookupType == DatabaseLookupMessage.Type.LS)) { (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,
@ -260,8 +260,7 @@ public class HandleDatabaseLookupMessageJob extends JobImpl {
_log.debug("Sending data matching key " + key + " to peer " + toPeer _log.debug("Sending data matching key " + key + " to peer " + toPeer
+ " tunnel " + replyTunnel); + " tunnel " + replyTunnel);
DatabaseStoreMessage msg = new DatabaseStoreMessage(getContext()); DatabaseStoreMessage msg = new DatabaseStoreMessage(getContext());
int type = data.getType(); if (data.isLeaseSet()) {
if (type == DatabaseEntry.KEY_TYPE_LEASESET || type == DatabaseEntry.KEY_TYPE_LS2) {
getContext().statManager().addRateData("netDb.lookupsMatchedLeaseSet", 1); getContext().statManager().addRateData("netDb.lookupsMatchedLeaseSet", 1);
} }
msg.setEntry(data); msg.setEntry(data);

View File

@ -61,9 +61,7 @@ class ExpireLeasesJob extends JobImpl {
Set<Hash> toExpire = new HashSet<Hash>(128); Set<Hash> toExpire = new HashSet<Hash>(128);
for (Map.Entry<Hash, DatabaseEntry> entry : _facade.getDataStore().getMapEntries()) { for (Map.Entry<Hash, DatabaseEntry> entry : _facade.getDataStore().getMapEntries()) {
DatabaseEntry obj = entry.getValue(); DatabaseEntry obj = entry.getValue();
int type = obj.getType(); if (obj.isLeaseSet()) {
if (type == DatabaseEntry.KEY_TYPE_LEASESET ||
type == DatabaseEntry.KEY_TYPE_LS2) {
LeaseSet ls = (LeaseSet)obj; LeaseSet ls = (LeaseSet)obj;
if (!ls.isCurrent(Router.CLOCK_FUDGE_FACTOR)) if (!ls.isCurrent(Router.CLOCK_FUDGE_FACTOR))
toExpire.add(entry.getKey()); toExpire.add(entry.getKey());

View File

@ -54,8 +54,7 @@ class FloodOnlyLookupMatchJob extends JobImpl implements ReplyJob {
// Should we just pass the DataStructure directly back to somebody? // Should we just pass the DataStructure directly back to somebody?
DatabaseEntry entry = dsm.getEntry(); DatabaseEntry entry = dsm.getEntry();
int type = entry.getType(); int type = entry.getType();
if (type == DatabaseEntry.KEY_TYPE_LEASESET || if (DatabaseEntry.isLeaseSet(type)) {
type == DatabaseEntry.KEY_TYPE_LS2) {
// Since HFDSMJ wants to setReceivedAsPublished(), we have to // Since HFDSMJ wants to setReceivedAsPublished(), we have to
// set a flag saying this was really the result of a query, // set a flag saying this was really the result of a query,
// so don't do that. // so don't do that.

View File

@ -70,8 +70,7 @@ class HandleFloodfillDatabaseStoreMessageJob extends JobImpl {
Hash key = _message.getKey(); Hash key = _message.getKey();
DatabaseEntry entry = _message.getEntry(); DatabaseEntry entry = _message.getEntry();
int type = entry.getType(); int type = entry.getType();
if (type == DatabaseEntry.KEY_TYPE_LEASESET || if (DatabaseEntry.isLeaseSet(type)) {
type == DatabaseEntry.KEY_TYPE_LS2) {
getContext().statManager().addRateData("netDb.storeLeaseSetHandled", 1); getContext().statManager().addRateData("netDb.storeLeaseSetHandled", 1);
if (_log.shouldLog(Log.INFO)) if (_log.shouldLog(Log.INFO))
_log.info("Handling dbStore of leaseset " + _message); _log.info("Handling dbStore of leaseset " + _message);

View File

@ -438,8 +438,7 @@ public abstract class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacad
//return _ds.countLeaseSets(); //return _ds.countLeaseSets();
int rv = 0; int rv = 0;
for (DatabaseEntry ds : _ds.getEntries()) { for (DatabaseEntry ds : _ds.getEntries()) {
int type = ds.getType(); if (ds.isLeaseSet() &&
if ((type == DatabaseEntry.KEY_TYPE_LEASESET || type == DatabaseEntry.KEY_TYPE_LS2) &&
((LeaseSet)ds).getReceivedAsPublished()) ((LeaseSet)ds).getReceivedAsPublished())
rv++; rv++;
} }
@ -468,7 +467,7 @@ public abstract class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacad
if (rv == null) if (rv == null)
return null; return null;
int type = rv.getType(); int type = rv.getType();
if (type == DatabaseEntry.KEY_TYPE_LEASESET || type == DatabaseEntry.KEY_TYPE_LS2) { if (DatabaseEntry.isLeaseSet(type)) {
LeaseSet ls = (LeaseSet)rv; LeaseSet ls = (LeaseSet)rv;
if (ls.isCurrent(Router.CLOCK_FUDGE_FACTOR)) if (ls.isCurrent(Router.CLOCK_FUDGE_FACTOR))
return rv; return rv;
@ -553,8 +552,7 @@ public abstract class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacad
if (!_initialized) return null; if (!_initialized) return null;
DatabaseEntry ds = _ds.get(key); DatabaseEntry ds = _ds.get(key);
if (ds != null) { if (ds != null) {
int type = ds.getType(); if (ds.isLeaseSet()) {
if (type == DatabaseEntry.KEY_TYPE_LEASESET || type == DatabaseEntry.KEY_TYPE_LS2) {
LeaseSet ls = (LeaseSet)ds; LeaseSet ls = (LeaseSet)ds;
if (ls.isCurrent(Router.CLOCK_FUDGE_FACTOR)) { if (ls.isCurrent(Router.CLOCK_FUDGE_FACTOR)) {
return ls; return ls;
@ -607,8 +605,7 @@ public abstract class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacad
if (!_initialized) return null; if (!_initialized) return null;
DatabaseEntry ds = _ds.get(key); DatabaseEntry ds = _ds.get(key);
if (ds != null) { if (ds != null) {
int type = ds.getType(); if (ds.isLeaseSet()) {
if (type == DatabaseEntry.KEY_TYPE_LEASESET || type == DatabaseEntry.KEY_TYPE_LS2) {
LeaseSet ls = (LeaseSet)ds; LeaseSet ls = (LeaseSet)ds;
return ls.getDestination(); return ls.getDestination();
} }
@ -1082,7 +1079,7 @@ public abstract class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacad
private void processStoreFailure(Hash h, DatabaseEntry entry) throws UnsupportedCryptoException { private void processStoreFailure(Hash h, DatabaseEntry entry) throws UnsupportedCryptoException {
if (entry.getHash().equals(h)) { if (entry.getHash().equals(h)) {
int etype = entry.getType(); int etype = entry.getType();
if (etype == DatabaseEntry.KEY_TYPE_LEASESET || etype == DatabaseEntry.KEY_TYPE_LS2) { if (DatabaseEntry.isLeaseSet(etype)) {
LeaseSet ls = (LeaseSet) entry; LeaseSet ls = (LeaseSet) entry;
Destination d = ls.getDestination(); Destination d = ls.getDestination();
Certificate c = d.getCertificate(); Certificate c = d.getCertificate();
@ -1242,8 +1239,7 @@ public abstract class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacad
if (!_initialized) return null; if (!_initialized) return null;
Set<LeaseSet> leases = new HashSet<LeaseSet>(); Set<LeaseSet> leases = new HashSet<LeaseSet>();
for (DatabaseEntry o : getDataStore().getEntries()) { for (DatabaseEntry o : getDataStore().getEntries()) {
int type = o.getType(); if (o.isLeaseSet())
if (type == DatabaseEntry.KEY_TYPE_LEASESET || type == DatabaseEntry.KEY_TYPE_LS2)
leases.add((LeaseSet)o); leases.add((LeaseSet)o);
} }
return leases; return leases;

View File

@ -78,8 +78,7 @@ abstract class StoreJob extends JobImpl {
_timeoutMs = timeoutMs; _timeoutMs = timeoutMs;
_expiration = context.clock().now() + timeoutMs; _expiration = context.clock().now() + timeoutMs;
_peerSelector = facade.getPeerSelector(); _peerSelector = facade.getPeerSelector();
int type = data.getType(); if (data.isLeaseSet()) {
if (type == DatabaseEntry.KEY_TYPE_LEASESET || type == DatabaseEntry.KEY_TYPE_LS2) {
_connectChecker = null; _connectChecker = null;
_connectMask = 0; _connectMask = 0;
} else { } else {
@ -313,8 +312,7 @@ abstract class StoreJob extends JobImpl {
if (type == DatabaseEntry.KEY_TYPE_ROUTERINFO) { if (type == DatabaseEntry.KEY_TYPE_ROUTERINFO) {
if (responseTime > MAX_DIRECT_EXPIRATION) if (responseTime > MAX_DIRECT_EXPIRATION)
responseTime = MAX_DIRECT_EXPIRATION; responseTime = MAX_DIRECT_EXPIRATION;
} else if (type == DatabaseEntry.KEY_TYPE_LEASESET || type == DatabaseEntry.KEY_TYPE_LS2) { } else if (!DatabaseEntry.isLeaseSet(type)) {
} else {
throw new IllegalArgumentException("Storing an unknown data type! " + _state.getData()); throw new IllegalArgumentException("Storing an unknown data type! " + _state.getData());
} }
msg.setEntry(_state.getData()); msg.setEntry(_state.getData());
@ -340,8 +338,7 @@ abstract class StoreJob extends JobImpl {
* *
*/ */
private void sendStore(DatabaseStoreMessage msg, RouterInfo peer, long expiration) { private void sendStore(DatabaseStoreMessage msg, RouterInfo peer, long expiration) {
int type = msg.getEntry().getType(); if (msg.getEntry().isLeaseSet()) {
if (type == DatabaseEntry.KEY_TYPE_LEASESET || type == DatabaseEntry.KEY_TYPE_LS2) {
getContext().statManager().addRateData("netDb.storeLeaseSetSent", 1); getContext().statManager().addRateData("netDb.storeLeaseSetSent", 1);
// if it is an encrypted leaseset... // if it is an encrypted leaseset...
if (getContext().keyRing().get(msg.getKey()) != null) if (getContext().keyRing().get(msg.getKey()) != null)

View File

@ -99,9 +99,7 @@ class TransientDataStore implements DataStore {
public int countLeaseSets() { public int countLeaseSets() {
int count = 0; int count = 0;
for (DatabaseEntry d : _data.values()) { for (DatabaseEntry d : _data.values()) {
int type = d.getType(); if (d.isLeaseSet())
if (type == DatabaseEntry.KEY_TYPE_LEASESET ||
type == DatabaseEntry.KEY_TYPE_LS2)
count++; count++;
} }
return count; return count;
@ -151,8 +149,7 @@ class TransientDataStore implements DataStore {
_log.info("New router for " + key + ": published on " + new Date(ri.getPublished())); _log.info("New router for " + key + ": published on " + new Date(ri.getPublished()));
rv = true; rv = true;
} }
} else if (type == DatabaseEntry.KEY_TYPE_LEASESET || } else if (DatabaseEntry.isLeaseSet(type)) {
type == DatabaseEntry.KEY_TYPE_LS2) {
LeaseSet ls = (LeaseSet)data; LeaseSet ls = (LeaseSet)data;
if (old != null) { if (old != null) {
LeaseSet ols = (LeaseSet)old; LeaseSet ols = (LeaseSet)old;