I2P Address: [http://git.idk.i2p]

Skip to content
Snippets Groups Projects
Commit 79c68c56 authored by zzz's avatar zzz
Browse files

* BuildHandler: Prelmiinary participating tunnel throttler

parent 4967f8de
No related branches found
No related tags found
No related merge requests found
2011-02-22 zzz
* BuildHandler: Prelmiinary participating tunnel throttler
* I2PTunnel:
- Add spellcheck=false to textareas
- Fix HTML error in 503 error page
2011-02-19 zzz 2011-02-19 zzz
* I2PTunnel: Fix standalone server tunnels * I2PTunnel: Fix standalone server tunnels
http://forum.i2p/viewtopic.php?t=5376 http://forum.i2p/viewtopic.php?t=5376
......
...@@ -18,7 +18,7 @@ public class RouterVersion { ...@@ -18,7 +18,7 @@ public class RouterVersion {
/** deprecated */ /** deprecated */
public final static String ID = "Monotone"; public final static String ID = "Monotone";
public final static String VERSION = CoreVersion.VERSION; public final static String VERSION = CoreVersion.VERSION;
public final static long BUILD = 16; public final static long BUILD = 17;
/** for example "-test" */ /** for example "-test" */
public final static String EXTRA = "-rc"; public final static String EXTRA = "-rc";
......
...@@ -37,18 +37,19 @@ import net.i2p.util.Log; ...@@ -37,18 +37,19 @@ import net.i2p.util.Log;
* *
*/ */
class BuildHandler { class BuildHandler {
private RouterContext _context; private final RouterContext _context;
private Log _log; private final Log _log;
private BuildExecutor _exec; private final BuildExecutor _exec;
private Job _buildMessageHandlerJob; private final Job _buildMessageHandlerJob;
private Job _buildReplyMessageHandlerJob; private final Job _buildReplyMessageHandlerJob;
/** list of BuildMessageState, oldest first */ /** list of BuildMessageState, oldest first */
private final List<BuildMessageState> _inboundBuildMessages; private final List<BuildMessageState> _inboundBuildMessages;
/** list of BuildReplyMessageState, oldest first - unused unless HANDLE_REPLIES_INLINE == false */ /** list of BuildReplyMessageState, oldest first - unused unless HANDLE_REPLIES_INLINE == false */
private final List<BuildReplyMessageState> _inboundBuildReplyMessages; private final List<BuildReplyMessageState> _inboundBuildReplyMessages;
/** list of BuildEndMessageState, oldest first - unused unless HANDLE_REPLIES_INLINE == false */ /** list of BuildEndMessageState, oldest first - unused unless HANDLE_REPLIES_INLINE == false */
private final List<BuildEndMessageState> _inboundBuildEndMessages; private final List<BuildEndMessageState> _inboundBuildEndMessages;
private BuildMessageProcessor _processor; private final BuildMessageProcessor _processor;
private final ParticipatingThrottler _throttler;
private static final boolean HANDLE_REPLIES_INLINE = true; private static final boolean HANDLE_REPLIES_INLINE = true;
...@@ -101,6 +102,7 @@ class BuildHandler { ...@@ -101,6 +102,7 @@ class BuildHandler {
ctx.inNetMessagePool().registerHandlerJobBuilder(TunnelBuildReplyMessage.MESSAGE_TYPE, tbrmhjb); ctx.inNetMessagePool().registerHandlerJobBuilder(TunnelBuildReplyMessage.MESSAGE_TYPE, tbrmhjb);
ctx.inNetMessagePool().registerHandlerJobBuilder(VariableTunnelBuildMessage.MESSAGE_TYPE, tbmhjb); ctx.inNetMessagePool().registerHandlerJobBuilder(VariableTunnelBuildMessage.MESSAGE_TYPE, tbmhjb);
ctx.inNetMessagePool().registerHandlerJobBuilder(VariableTunnelBuildReplyMessage.MESSAGE_TYPE, tbrmhjb); ctx.inNetMessagePool().registerHandlerJobBuilder(VariableTunnelBuildReplyMessage.MESSAGE_TYPE, tbrmhjb);
_throttler = new ParticipatingThrottler(ctx);
} }
private static final int MAX_HANDLE_AT_ONCE = 2; private static final int MAX_HANDLE_AT_ONCE = 2;
...@@ -498,6 +500,7 @@ class BuildHandler { ...@@ -498,6 +500,7 @@ class BuildHandler {
long nextId = req.readNextTunnelId(); long nextId = req.readNextTunnelId();
boolean isInGW = req.readIsInboundGateway(); boolean isInGW = req.readIsInboundGateway();
boolean isOutEnd = req.readIsOutboundEndpoint(); boolean isOutEnd = req.readIsOutboundEndpoint();
// time is in hours, and only for log below - what's the point? // time is in hours, and only for log below - what's the point?
// tunnel-alt-creation.html specifies that this is enforced +/- 1 hour but it is not. // tunnel-alt-creation.html specifies that this is enforced +/- 1 hour but it is not.
long time = req.readRequestTime(); long time = req.readRequestTime();
...@@ -531,7 +534,7 @@ class BuildHandler { ...@@ -531,7 +534,7 @@ class BuildHandler {
_context.statManager().addRateData("tunnel.acceptLoad", recvDelay, recvDelay); _context.statManager().addRateData("tunnel.acceptLoad", recvDelay, recvDelay);
} }
} }
/* /*
* Being a IBGW or OBEP generally leads to more connections, so if we are * Being a IBGW or OBEP generally leads to more connections, so if we are
* approaching our connection limit (i.e. !haveCapacity()), * approaching our connection limit (i.e. !haveCapacity()),
...@@ -550,6 +553,28 @@ class BuildHandler { ...@@ -550,6 +553,28 @@ class BuildHandler {
_context.throttle().setTunnelStatus(_x("Rejecting tunnels: Connection limit")); _context.throttle().setTunnelStatus(_x("Rejecting tunnels: Connection limit"));
response = TunnelHistory.TUNNEL_REJECT_BANDWIDTH; response = TunnelHistory.TUNNEL_REJECT_BANDWIDTH;
} }
// Check participating throttle counters for previous and next hops
// This is at the end as it compares to a percentage of created tunnels.
// We may need another counter above for requests.
if (response == 0 && !isInGW) {
Hash from = state.fromHash;
if (from == null)
from = state.from.calculateHash();
if (_throttler.shouldThrottle(from)) {
if (_log.shouldLog(Log.WARN))
_log.warn("Rejecting tunnel (hop throttle), previous hop: " + from);
// no setTunnelStatus() indication
response = TunnelHistory.TUNNEL_REJECT_BANDWIDTH;
}
}
if (response == 0 && (!isOutEnd) &&
_throttler.shouldThrottle(req.readNextIdentity())) {
if (_log.shouldLog(Log.WARN))
_log.warn("Rejecting tunnel (hop throttle), next hop: " + req.readNextIdentity());
// no setTunnelStatus() indication
response = TunnelHistory.TUNNEL_REJECT_BANDWIDTH;
}
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("Responding to " + state.msg.getUniqueId() + "/" + ourId _log.debug("Responding to " + state.msg.getUniqueId() + "/" + ourId
......
package net.i2p.router.tunnel.pool;
import net.i2p.data.Hash;
import net.i2p.router.RouterContext;
import net.i2p.util.ObjectCounter;
import net.i2p.util.SimpleScheduler;
import net.i2p.util.SimpleTimer;
/**
* Count how often we have accepted a tunnel with the peer
* as the previous or next hop.
* We limit each peer to a percentage of all participating tunnels,
* subject to minimum and maximum values for the limit.
*
* This offers basic protection against simple attacks
* but is not a complete solution, as by design, we don't know
* the originator of a tunnel request.
*
* This also effectively limits the number of tunnels between
* any given pair of routers, which probably isn't a bad thing.
*
* Note that the counts are of previous + next hops, so the total will
* be higher than the participating tunnel count, and will also grow
* as the network uses more 3-hop tunnels.
*
* @since 0.8.4
*/
class ParticipatingThrottler {
private final RouterContext context;
private final ObjectCounter<Hash> counter;
/** portion of the tunnel lifetime */
private static final int LIFETIME_PORTION = 3;
private static final int MIN_LIMIT = 18 / LIFETIME_PORTION;
private static final int MAX_LIMIT = 81 / LIFETIME_PORTION;
private static final int PERCENT_LIMIT = 12 / LIFETIME_PORTION;
private static final long CLEAN_TIME = 10*60*1000 / LIFETIME_PORTION;
ParticipatingThrottler(RouterContext ctx) {
this.context = ctx;
this.counter = new ObjectCounter();
SimpleScheduler.getInstance().addPeriodicEvent(new Cleaner(), CLEAN_TIME);
}
/** increments before checking */
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;
}
private class Cleaner implements SimpleTimer.TimedEvent {
public void timeReached() {
ParticipatingThrottler.this.counter.clear();
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment