Tunnels: Ban peer on excessive build requests

Drop requests if previous or next peer is banned
Console: Drop peer when manually banned
Update: Drop peer when banlisted
This commit is contained in:
zzz
2021-11-21 08:17:43 -05:00
parent d7fdd6d9dc
commit e3fc34ef1f
9 changed files with 81 additions and 13 deletions

View File

@@ -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) {

View File

@@ -22,6 +22,7 @@ public class ConfigPeerHandler extends FormHandler {
Hash h = getHash();
if (h != null) {
_context.banlist().banlistRouterForever(h, _t("Manually banned via {0}"), "<a href=\"configpeer\">configpeer</a>");
_context.commSystem().forceDisconnect(h);
addFormNotice(_t("Peer") + " " + _peer + " " + _t("banned until restart") );
return;
}

View File

@@ -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

View File

@@ -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=

View File

@@ -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);

View File

@@ -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)

View File

@@ -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;
}
}

View File

@@ -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<Hash> 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<Hash>();
_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);
}
}
}

View File

@@ -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<Hash> 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<Hash>();
_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);
}
}
}