diff --git a/apps/routerconsole/java/src/net/i2p/router/update/NewsFetcher.java b/apps/routerconsole/java/src/net/i2p/router/update/NewsFetcher.java
index 5043ca623..f2376f8ad 100644
--- a/apps/routerconsole/java/src/net/i2p/router/update/NewsFetcher.java
+++ b/apps/routerconsole/java/src/net/i2p/router/update/NewsFetcher.java
@@ -651,8 +651,10 @@ class NewsFetcher extends UpdateRunner {
continue;
}
Hash h = Hash.create(b);
- if (!ban.isBanlistedForever(h))
+ if (!ban.isBanlistedForever(h)) {
ban.banlistRouterForever(h, reason);
+ _context.commSystem().forceDisconnect(h);
+ }
} else {
byte[] ip = Addresses.getIP(s);
if (ip == null) {
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/helpers/ConfigPeerHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/helpers/ConfigPeerHandler.java
index 1b29feb4d..243e06b89 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/helpers/ConfigPeerHandler.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/helpers/ConfigPeerHandler.java
@@ -22,6 +22,7 @@ public class ConfigPeerHandler extends FormHandler {
Hash h = getHash();
if (h != null) {
_context.banlist().banlistRouterForever(h, _t("Manually banned via {0}"), "configpeer");
+ _context.commSystem().forceDisconnect(h);
addFormNotice(_t("Peer") + " " + _peer + " " + _t("banned until restart") );
return;
}
diff --git a/history.txt b/history.txt
index 5e6321e1d..32916b8e8 100644
--- a/history.txt
+++ b/history.txt
@@ -1,3 +1,10 @@
+2021-11-21 zzz
+ * Console: Drop peer when manually banned
+ * Tunnels:
+ - Ban peer on excessive build requests
+ - Drop requests if previous or next peer is banned
+ * Update: Drop peer when banlisted
+
2021-11-12 zzz
* Tunnels: Improve build success when at conn limits
diff --git a/installer/resources/blocklist.txt b/installer/resources/blocklist.txt
index 82971857e..b034a36ca 100644
--- a/installer/resources/blocklist.txt
+++ b/installer/resources/blocklist.txt
@@ -101,6 +101,7 @@ Sybil:47.90.120.30
Sybil:47.208.97.112
Sybil:51.211.161.115
Sybil:66.42.58.61
+Tunnels:93.157.12.248
Sybil:95.47.57.0/24
Sybil:95.85.100.0/22
Sybil:95.85.104.0/22
@@ -135,3 +136,4 @@ Sybil:2400;8500;1302;819;a150;95;134;1590
Sybil:2400;8500;1302;824;a150;95;144;951
Sybil:2400;8500;1302;825;150;95;147;89
Sybil:2400;8500;1302;828;a150;95;153;2202
+Tunnels:JbifzqZZqeTXtxK6KDqNUPWaW-phKqeS~tfJT82SIYI=
diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java
index 9bc4388a0..cf2cf692a 100644
--- a/router/java/src/net/i2p/router/RouterVersion.java
+++ b/router/java/src/net/i2p/router/RouterVersion.java
@@ -18,10 +18,10 @@ public class RouterVersion {
/** deprecated */
public final static String ID = "Git";
public final static String VERSION = CoreVersion.VERSION;
- public final static long BUILD = 5;
+ public final static long BUILD = 6;
/** for example "-test" */
- public final static String EXTRA = "";
+ public final static String EXTRA = "-rc";
public final static String FULL_VERSION = VERSION + "-" + BUILD + EXTRA;
public static void main(String args[]) {
System.out.println("I2P Router version: " + FULL_VERSION);
diff --git a/router/java/src/net/i2p/router/transport/ntcp/InboundEstablishState.java b/router/java/src/net/i2p/router/transport/ntcp/InboundEstablishState.java
index c5fba8f04..e06caca8b 100644
--- a/router/java/src/net/i2p/router/transport/ntcp/InboundEstablishState.java
+++ b/router/java/src/net/i2p/router/transport/ntcp/InboundEstablishState.java
@@ -33,6 +33,7 @@ import net.i2p.router.RouterContext;
import net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade;
import net.i2p.router.transport.crypto.DHSessionKeyBuilder;
import static net.i2p.router.transport.ntcp.OutboundNTCP2State.*;
+import net.i2p.util.Addresses;
import net.i2p.util.ByteArrayStream;
import net.i2p.util.ByteCache;
import net.i2p.util.Log;
@@ -181,8 +182,8 @@ class InboundEstablishState extends EstablishBase implements NTCP2Payload.Payloa
InetAddress addr = this._con.getChannel().socket().getInetAddress();
byte[] ip = (addr == null) ? null : addr.getAddress();
if (_context.banlist().isBanlistedForever(aliceHash)) {
- if (_log.shouldLog(Log.WARN))
- _log.warn("Dropping inbound connection from permanently banlisted peer: " + aliceHash);
+ if (_log.shouldWarn())
+ _log.warn("Dropping inbound connection from permanently banlisted peer at " + Addresses.toString(ip) + " : " + aliceHash);
// So next time we will not accept the con from this IP,
// rather than doing the whole handshake
if(ip != null)
diff --git a/router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java b/router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java
index 6a552b56e..b586b1dbf 100644
--- a/router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java
+++ b/router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java
@@ -467,6 +467,13 @@ class BuildHandler implements Runnable {
Hash from = state.fromHash;
if (from == null && state.from != null)
from = state.from.calculateHash();
+ if (from != null && _context.banlist().isBanlisted(from)) {
+ // Usually won't have connected, but may have been banlisted after connect
+ if (_log.shouldWarn())
+ _log.warn("Drop request, previous peer is banned: " + from);
+ _context.commSystem().mayDisconnect(from);
+ return -1;
+ }
if (timeSinceReceived > (BuildRequestor.REQUEST_TIMEOUT*3)) {
// don't even bother, since we are so overloaded locally
@@ -499,13 +506,15 @@ class BuildHandler implements Runnable {
return -1;
}
- long beforeLookup = System.currentTimeMillis();
Hash nextPeer = req.readNextIdentity();
- long readPeerTime = System.currentTimeMillis()-beforeLookup;
+ if (_context.banlist().isBanlisted(nextPeer)) {
+ if (_log.shouldWarn())
+ _log.warn("Drop request, next peer is banned: " + nextPeer);
+ if (from != null)
+ _context.commSystem().mayDisconnect(from);
+ return -1;
+ }
RouterInfo nextPeerInfo = _context.netDb().lookupRouterInfoLocally(nextPeer);
- long lookupTime = System.currentTimeMillis()-beforeLookup;
- if (lookupTime > 500 && _log.shouldLog(Log.WARN))
- _log.warn("Took too long to lookup the request: " + lookupTime + "/" + readPeerTime + " for " + req);
if (nextPeerInfo == null) {
// limit concurrent next-hop lookups to prevent job queue overload attacks
int numTunnels = _context.tunnelManager().getParticipatingCount();
@@ -549,7 +558,7 @@ class BuildHandler implements Runnable {
+ " ID: " + state.msg.getUniqueId()
+ " handled and we know the next peer "
+ nextPeer + " after " + handleTime
- + "/" + decryptTime + "/" + lookupTime + "/" + timeSinceReceived);
+ + "/" + decryptTime + "/" + timeSinceReceived);
return handleTime;
}
}
diff --git a/router/java/src/net/i2p/router/tunnel/pool/ParticipatingThrottler.java b/router/java/src/net/i2p/router/tunnel/pool/ParticipatingThrottler.java
index e3d877725..abd186ca2 100644
--- a/router/java/src/net/i2p/router/tunnel/pool/ParticipatingThrottler.java
+++ b/router/java/src/net/i2p/router/tunnel/pool/ParticipatingThrottler.java
@@ -2,6 +2,7 @@ package net.i2p.router.tunnel.pool;
import net.i2p.data.Hash;
import net.i2p.router.RouterContext;
+import net.i2p.util.Log;
import net.i2p.util.ObjectCounter;
import net.i2p.util.SimpleTimer;
@@ -30,6 +31,7 @@ import net.i2p.util.SimpleTimer;
class ParticipatingThrottler {
private final RouterContext context;
private final ObjectCounter counter;
+ private final Log _log;
/** portion of the tunnel lifetime */
private static final int LIFETIME_PORTION = 3;
@@ -41,6 +43,7 @@ class ParticipatingThrottler {
ParticipatingThrottler(RouterContext ctx) {
this.context = ctx;
this.counter = new ObjectCounter();
+ _log = ctx.logManager().getLog(ParticipatingThrottler.class);
ctx.simpleTimer2().addPeriodicEvent(new Cleaner(), CLEAN_TIME);
}
@@ -48,7 +51,16 @@ class ParticipatingThrottler {
boolean shouldThrottle(Hash h) {
int numTunnels = this.context.tunnelManager().getParticipatingCount();
int limit = Math.max(MIN_LIMIT, Math.min(MAX_LIMIT, numTunnels * PERCENT_LIMIT / 100));
- return this.counter.increment(h) > limit;
+ int count = counter.increment(h);
+ boolean rv = count > limit;
+ if (rv && count == 2 * limit) {
+ context.banlist().banlistRouter(h, "Excess participating tunnels", null, null, context.clock().now() + 30*60*1000);
+ // drop after any accepted tunnels have expired
+ context.simpleTimer2().addEvent(new Disconnector(h), 11*60*1000);
+ if (_log.shouldWarn())
+ _log.warn("Banning router for excess part. tunnels, limit: " + limit + " count: " + count + ' ' + h.toBase64());
+ }
+ return rv;
}
private class Cleaner implements SimpleTimer.TimedEvent {
@@ -56,4 +68,15 @@ class ParticipatingThrottler {
ParticipatingThrottler.this.counter.clear();
}
}
+
+ /**
+ * @since 0.9.52
+ */
+ private class Disconnector implements SimpleTimer.TimedEvent {
+ private final Hash h;
+ public Disconnector(Hash h) { this.h = h; }
+ public void timeReached() {
+ context.commSystem().forceDisconnect(h);
+ }
+ }
}
diff --git a/router/java/src/net/i2p/router/tunnel/pool/RequestThrottler.java b/router/java/src/net/i2p/router/tunnel/pool/RequestThrottler.java
index 794808408..7c29a5500 100644
--- a/router/java/src/net/i2p/router/tunnel/pool/RequestThrottler.java
+++ b/router/java/src/net/i2p/router/tunnel/pool/RequestThrottler.java
@@ -2,6 +2,7 @@ package net.i2p.router.tunnel.pool;
import net.i2p.data.Hash;
import net.i2p.router.RouterContext;
+import net.i2p.util.Log;
import net.i2p.util.ObjectCounter;
import net.i2p.util.SimpleTimer;
@@ -15,6 +16,7 @@ import net.i2p.util.SimpleTimer;
class RequestThrottler {
private final RouterContext context;
private final ObjectCounter counter;
+ private final Log _log;
/** portion of the tunnel lifetime */
private static final int LIFETIME_PORTION = 6;
@@ -26,6 +28,7 @@ class RequestThrottler {
RequestThrottler(RouterContext ctx) {
this.context = ctx;
this.counter = new ObjectCounter();
+ _log = ctx.logManager().getLog(RequestThrottler.class);
ctx.simpleTimer2().addPeriodicEvent(new Cleaner(), CLEAN_TIME);
}
@@ -33,7 +36,16 @@ class RequestThrottler {
boolean shouldThrottle(Hash h) {
int numTunnels = this.context.tunnelManager().getParticipatingCount();
int limit = Math.max(MIN_LIMIT, Math.min(MAX_LIMIT, numTunnels * PERCENT_LIMIT / 100));
- return this.counter.increment(h) > limit;
+ int count = counter.increment(h);
+ boolean rv = count > limit;
+ if (rv && count == 2 * limit) {
+ context.banlist().banlistRouter(h, "Excess tunnel requests", null, null, context.clock().now() + 30*60*1000);
+ // drop after any accepted tunnels have expired
+ context.simpleTimer2().addEvent(new Disconnector(h), 11*60*1000);
+ if (_log.shouldWarn())
+ _log.warn("Banning router for excess tunnel requests, limit: " + limit + " count: " + count + ' ' + h.toBase64());
+ }
+ return rv;
}
private class Cleaner implements SimpleTimer.TimedEvent {
@@ -41,4 +53,15 @@ class RequestThrottler {
RequestThrottler.this.counter.clear();
}
}
+
+ /**
+ * @since 0.9.52
+ */
+ private class Disconnector implements SimpleTimer.TimedEvent {
+ private final Hash h;
+ public Disconnector(Hash h) { this.h = h; }
+ public void timeReached() {
+ context.commSystem().forceDisconnect(h);
+ }
+ }
}