* 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:
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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))
|
||||
|
@ -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 {
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
Reference in New Issue
Block a user