* reduced the period used to detect / avoid peers who send invalid data (60m instead of 120m)

* expose the reason for a dbStore rejection more cleanly
This commit is contained in:
jrandom
2004-08-17 20:37:47 +00:00
committed by zzz
parent 7794547d30
commit 692cd7adae
5 changed files with 47 additions and 33 deletions

View File

@ -48,16 +48,14 @@ public class HandleDatabaseStoreMessageJob extends JobImpl {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Handling database store message");
boolean invalid = false;
String invalidMessage = null;
boolean wasNew = false;
if (_message.getValueType() == DatabaseStoreMessage.KEY_TYPE_LEASESET) {
try {
Object match = getContext().netDb().store(_message.getKey(), _message.getLeaseSet());
wasNew = (null == match);
} catch (IllegalArgumentException iae) {
if (_log.shouldLog(Log.WARN))
_log.warn("Not storing a leaseSet", iae);
invalid = true;
invalidMessage = iae.getMessage();
}
} else if (_message.getValueType() == DatabaseStoreMessage.KEY_TYPE_ROUTERINFO) {
if (_log.shouldLog(Log.INFO))
@ -68,9 +66,7 @@ public class HandleDatabaseStoreMessageJob extends JobImpl {
wasNew = (null == match);
getContext().profileManager().heardAbout(_message.getKey());
} catch (IllegalArgumentException iae) {
if (_log.shouldLog(Log.WARN))
_log.warn("Not storing a routerInfo", iae);
invalid = true;
invalidMessage = iae.getMessage();
}
} else {
if (_log.shouldLog(Log.ERROR))
@ -84,9 +80,12 @@ public class HandleDatabaseStoreMessageJob extends JobImpl {
if (_from != null)
_fromHash = _from.getHash();
if (_fromHash != null) {
if (!invalid) {
if (invalidMessage == null) {
getContext().profileManager().dbStoreReceived(_fromHash, wasNew);
getContext().statManager().addRateData("netDb.storeHandled", 1, 0);
} else {
if (_log.shouldLog(Log.WARN))
_log.warn("Peer " + _fromHash.toBase64() + " sent bad data: " + invalidMessage);
}
}
}

View File

@ -437,31 +437,36 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
* Determine whether this leaseSet will be accepted as valid and current
* given what we know now.
*
* @return reason why the entry is not valid, or null if it is valid
*/
boolean validate(Hash key, LeaseSet leaseSet) {
String validate(Hash key, LeaseSet leaseSet) {
if (!key.equals(leaseSet.getDestination().calculateHash())) {
if (_log.shouldLog(Log.ERROR))
_log.error("Invalid store attempt! key does not match leaseSet.destination! key = "
+ key + ", leaseSet = " + leaseSet);
return false;
if (_log.shouldLog(Log.WARN))
_log.warn("Invalid store attempt! key does not match leaseSet.destination! key = "
+ key + ", leaseSet = " + leaseSet);
return "Key does not match leaseSet.destination - " + key.toBase64();
} else if (!leaseSet.verifySignature()) {
if (_log.shouldLog(Log.ERROR))
_log.error("Invalid leaseSet signature! leaseSet = " + leaseSet);
return false;
if (_log.shouldLog(Log.WARN))
_log.warn("Invalid leaseSet signature! leaseSet = " + leaseSet);
return "Invalid leaseSet signature on " + leaseSet.getDestination().calculateHash().toBase64();
} else if (leaseSet.getEarliestLeaseDate() <= _context.clock().now() - Router.CLOCK_FUDGE_FACTOR) {
long age = _context.clock().now() - leaseSet.getEarliestLeaseDate();
if (_log.shouldLog(Log.WARN))
_log.warn("Old leaseSet! not storing it: "
+ leaseSet.getDestination().calculateHash().toBase64()
+ " expires on " + new Date(leaseSet.getEarliestLeaseDate()), new Exception("Rejecting store"));
return false;
return "Expired leaseSet for " + leaseSet.getDestination().calculateHash().toBase64()
+ " expired " + DataHelper.formatDuration(age) + " ago";
} else if (leaseSet.getEarliestLeaseDate() > _context.clock().now() + Router.CLOCK_FUDGE_FACTOR + MAX_LEASE_FUTURE) {
long age = leaseSet.getEarliestLeaseDate() - _context.clock().now();
if (_log.shouldLog(Log.WARN))
_log.warn("LeaseSet to expire too far in the future: "
+ leaseSet.getDestination().calculateHash().toBase64()
+ " expires on " + new Date(leaseSet.getEarliestLeaseDate()), new Exception("Rejecting store"));
return false;
return "Expired leaseSet for " + leaseSet.getDestination().calculateHash().toBase64()
+ " expiring in " + DataHelper.formatDuration(age);
}
return true;
return null;
}
/**
@ -472,8 +477,9 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
public LeaseSet store(Hash key, LeaseSet leaseSet) throws IllegalArgumentException {
if (!_initialized) return null;
boolean valid = validate(key, leaseSet);
if (!valid) throw new IllegalArgumentException("LeaseSet is not valid");
String err = validate(key, leaseSet);
if (err != null)
throw new IllegalArgumentException("Invalid store attempt - " + err);
LeaseSet rv = null;
if (_ds.isKnown(key))
@ -509,21 +515,24 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
* given what we know now.
*
*/
boolean validate(Hash key, RouterInfo routerInfo) {
String validate(Hash key, RouterInfo routerInfo) throws IllegalArgumentException {
long now = _context.clock().now();
if (!key.equals(routerInfo.getIdentity().getHash())) {
_log.error("Invalid store attempt! key does not match routerInfo.identity! key = " + key + ", router = " + routerInfo);
return false;
if (_log.shouldLog(Log.WARN))
_log.warn("Invalid store attempt! key does not match routerInfo.identity! key = " + key + ", router = " + routerInfo);
return "Key does not match routerInfo.identity - " + key.toBase64();
} else if (!routerInfo.isValid()) {
_log.error("Invalid routerInfo signature! forged router structure! router = " + routerInfo);
return false;
if (_log.shouldLog(Log.WARN))
_log.warn("Invalid routerInfo signature! forged router structure! router = " + routerInfo);
return "Invalid routerInfo signature on " + key.toBase64();
} else if (!routerInfo.isCurrent(Router.CLOCK_FUDGE_FACTOR + ExpireRoutersJob.EXPIRE_DELAY)) {
long age = _context.clock().now() - routerInfo.getPublished();
int existing = _kb.size();
if (existing >= MIN_REMAINING_ROUTERS) {
if (_log.shouldLog(Log.INFO))
_log.info("Not storing expired router for " + key.toBase64(), new Exception("Rejecting store"));
return false;
return "Peer " + key.toBase64() + " expired " + DataHelper.formatDuration(age) + "ms ago";
} else {
if (_log.shouldLog(Log.WARN))
_log.warn("Even though the peer is old, we have only " + existing
@ -531,12 +540,13 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
+ new Date(routerInfo.getPublished()));
}
} else if (routerInfo.getPublished() > now + Router.CLOCK_FUDGE_FACTOR) {
long age = routerInfo.getPublished() - _context.clock().now();
if (_log.shouldLog(Log.WARN))
_log.warn("Peer " + key.toBase64() + " published their routerInfo in the future?! ["
+ new Date(routerInfo.getPublished()) + "]", new Exception("Rejecting store"));
return false;
return "Peer " + key.toBase64() + " published " + DataHelper.formatDuration(age) + " in the future?!";
}
return true;
return null;
}
/**
@ -547,8 +557,9 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
public RouterInfo store(Hash key, RouterInfo routerInfo) throws IllegalArgumentException {
if (!_initialized) return null;
boolean valid = validate(key, routerInfo);
if (!valid) throw new IllegalArgumentException("LeaseSet is not valid");
String err = validate(key, routerInfo);
if (err != null)
throw new IllegalArgumentException("Invalid store attempt - " + err);
RouterInfo rv = null;
if (_ds.isKnown(key))

View File

@ -50,6 +50,8 @@ class SearchUpdateReplyFoundJob extends JobImpl implements ReplyJob {
_facade.store(msg.getKey(), msg.getLeaseSet());
getContext().profileManager().dbLookupSuccessful(_peer, timeToReply);
} catch (IllegalArgumentException iae) {
if (_log.shouldLog(Log.ERROR))
_log.warn("Peer " + _peer + " sent us an invalid leaseSet: " + iae.getMessage());
getContext().profileManager().dbLookupReply(_peer, 0, 0, 1, 0, timeToReply);
}
} else if (msg.getValueType() == DatabaseStoreMessage.KEY_TYPE_ROUTERINFO) {
@ -61,6 +63,8 @@ class SearchUpdateReplyFoundJob extends JobImpl implements ReplyJob {
_facade.store(msg.getKey(), msg.getRouterInfo());
getContext().profileManager().dbLookupSuccessful(_peer, timeToReply);
} catch (IllegalArgumentException iae) {
if (_log.shouldLog(Log.ERROR))
_log.warn("Peer " + _peer + " sent us an invalid routerInfo: " + iae.getMessage());
getContext().profileManager().dbLookupReply(_peer, 0, 0, 1, 0, timeToReply);
}
} else {

View File

@ -220,7 +220,7 @@ public class DBHistory {
if (_failedLookupRate == null)
_failedLookupRate = new RateStat("dbHistory.failedLookupRate", "How often does this peer to respond to a lookup?", "dbHistory", new long[] { 60*1000l, 60*60*1000l, 24*60*60*1000l });
if (_invalidReplyRate == null)
_invalidReplyRate = new RateStat("dbHistory.invalidReplyRate", "How often does this peer give us a bad (nonexistant, forged, etc) peer?", "dbHistory", new long[] { 60*1000l, 60*60*1000l, 24*60*60*1000l });
_invalidReplyRate = new RateStat("dbHistory.invalidReplyRate", "How often does this peer give us a bad (nonexistant, forged, etc) peer?", "dbHistory", new long[] { 30*60*1000l, 60*60*1000l, 24*60*60*1000l });
}
private final static long getLong(Properties props, String key) {

View File

@ -217,7 +217,7 @@ public class ProfileOrganizer {
PeerProfile profile = getProfile(peer);
if (profile != null) {
RateStat invalidReplyRateStat = profile.getDBHistory().getInvalidReplyRate();
Rate invalidReplyRate = invalidReplyRateStat.getRate(60*60*1000l);
Rate invalidReplyRate = invalidReplyRateStat.getRate(30*60*1000l);
if ( (invalidReplyRate.getCurrentTotalValue() > MAX_BAD_REPLIES_PER_HOUR) ||
(invalidReplyRate.getLastTotalValue() > MAX_BAD_REPLIES_PER_HOUR) ) {
return true;