diff --git a/apps/i2psnark/java/src/org/klomp/snark/dht/DHTNodes.java b/apps/i2psnark/java/src/org/klomp/snark/dht/DHTNodes.java
index 1b2ae428e7c3aea0ac8542c84bb5a3e3803256bc..64a650bae8b2fb08a3c2643d7f78a9152858bc44 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/dht/DHTNodes.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/dht/DHTNodes.java
@@ -46,13 +46,15 @@ class DHTNodes {
     private static final int MAX_PEERS = 799;
     /** Buckets older than this are refreshed - BEP 5 says 15 minutes */
     private static final long MAX_BUCKET_AGE = 15*60*1000;
+    private static final int KAD_K = 8;
+    private static final int KAD_B = 1;
 
     public DHTNodes(I2PAppContext ctx, NID me) {
         _context = ctx;
         _expireTime = MAX_EXPIRE_TIME;
         _log = _context.logManager().getLog(DHTNodes.class);
         _nodeMap = new ConcurrentHashMap();
-        _kad = new KBucketSet(ctx, me, 8, 1);
+        _kad = new KBucketSet(ctx, me, KAD_K, KAD_B, new KBTrimmer(ctx, KAD_K));
     }
 
     public void start() {
diff --git a/apps/i2psnark/java/src/org/klomp/snark/dht/KBTrimmer.java b/apps/i2psnark/java/src/org/klomp/snark/dht/KBTrimmer.java
new file mode 100644
index 0000000000000000000000000000000000000000..96809cbc214b27e9720d4b846c7962f13aab90b2
--- /dev/null
+++ b/apps/i2psnark/java/src/org/klomp/snark/dht/KBTrimmer.java
@@ -0,0 +1,37 @@
+package org.klomp.snark.dht;
+
+import java.util.Set;
+
+import net.i2p.I2PAppContext;
+import net.i2p.kademlia.KBucket;
+import net.i2p.kademlia.KBucketSet;
+
+/**
+ *  Removes an element older than 15 minutes, but only if the bucket hasn't changed in 5 minutes.
+ */
+class KBTrimmer implements KBucketSet.KBucketTrimmer<NID> {
+    private final I2PAppContext _ctx;
+    private final int _max;
+
+    private static final long MIN_BUCKET_AGE = 5*60*1000;
+    private static final long MAX_NODE_AGE = 15*60*1000;
+
+    public KBTrimmer(I2PAppContext ctx, int max) {
+        _ctx = ctx;
+        _max = max;
+    }
+
+    public boolean trim(KBucket<NID> kbucket, NID toAdd) {
+        long now = _ctx.clock().now();
+        if (kbucket.getLastChanged() > now - MIN_BUCKET_AGE)
+            return false;
+        Set<NID> entries = kbucket.getEntries();
+        for (NID nid : entries) {
+            if (nid.lastSeen() < now - MAX_NODE_AGE) {
+                if (kbucket.remove(nid))
+                    return true;
+            }
+        }
+        return entries.size() < _max;
+    }
+}
diff --git a/apps/i2psnark/java/src/org/klomp/snark/dht/MsgID.java b/apps/i2psnark/java/src/org/klomp/snark/dht/MsgID.java
index 6d53f7c8fb1a17bee2815aa54b6908f56766020e..c28fba5c70ac5eb0cd5c096e44764f6a08ed4d91 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/dht/MsgID.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/dht/MsgID.java
@@ -14,7 +14,9 @@ import net.i2p.data.ByteArray;
  */
 class MsgID extends ByteArray {
 
+    /** BEP 5: 2 bytes, incremented */
     private static final int MY_TOK_LEN = 8;
+    private static final int MAX_TOK_LEN = 16;
 
     /** outgoing - generate a random ID */
     public MsgID(I2PAppContext ctx) {
@@ -28,5 +30,8 @@ class MsgID extends ByteArray {
     /** incoming  - save the ID (arbitrary length) */
     public MsgID(byte[] data) {
         super(data);
+        // lets not get carried away
+        if (data.length > MAX_TOK_LEN)
+            throw new IllegalArgumentException();
     }
 }