From 6de81d41d2bac38076a744dca23e8cba4c35a0b8 Mon Sep 17 00:00:00 2001 From: zzz <zzz@mail.i2p> Date: Thu, 17 Apr 2014 18:52:40 +0000 Subject: [PATCH] SSU: SessionRequest replay prevention (ticket #1212) NTCP: Just use first 8 bytes of Hx^Hi for replay check --- .../i2p/router/transport/ntcp/NTCPTransport.java | 4 ++-- .../transport/udp/EstablishmentManager.java | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java b/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java index 77b1332018..053ab176ec 100644 --- a/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java +++ b/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java @@ -178,7 +178,7 @@ public class NTCPTransport extends TransportImpl { _establishing = new ConcurrentHashSet<NTCPConnection>(16); _conLock = new Object(); _conByIdent = new ConcurrentHashMap<Hash, NTCPConnection>(64); - _replayFilter = new DecayingHashSet(ctx, 10*60*1000, 32, "NTCP-Hx^HI"); + _replayFilter = new DecayingHashSet(ctx, 10*60*1000, 8, "NTCP-Hx^HI"); _finisher = new NTCPSendFinisher(ctx, this); @@ -522,7 +522,7 @@ public class NTCPTransport extends TransportImpl { * @since 0.9.12 */ boolean isHXHIValid(byte[] hxhi) { - return !_replayFilter.add(hxhi); + return !_replayFilter.add(hxhi, 0, 8); } private static final int MIN_CONCURRENT_READERS = 2; // unless < 32MB diff --git a/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java b/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java index b471a3c971..41b0eeddd6 100644 --- a/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java +++ b/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java @@ -23,6 +23,8 @@ import net.i2p.router.RouterContext; import net.i2p.router.transport.crypto.DHSessionKeyBuilder; import static net.i2p.router.transport.udp.InboundEstablishState.InboundState.*; import static net.i2p.router.transport.udp.OutboundEstablishState.OutboundState.*; +import net.i2p.router.util.DecayingHashSet; +import net.i2p.router.util.DecayingBloomFilter; import net.i2p.util.Addresses; import net.i2p.util.I2PThread; import net.i2p.util.Log; @@ -82,6 +84,9 @@ class EstablishmentManager { private volatile boolean _alive; private final Object _activityLock; private int _activity; + + /** "bloom filter" */ + private final DecayingBloomFilter _replayFilter; /** max outbound in progress - max inbound is half of this */ private final int DEFAULT_MAX_CONCURRENT_ESTABLISH; @@ -132,6 +137,7 @@ class EstablishmentManager { _outboundByClaimedAddress = new ConcurrentHashMap<RemoteHostId, OutboundEstablishState>(); _outboundByHash = new ConcurrentHashMap<Hash, OutboundEstablishState>(); _activityLock = new Object(); + _replayFilter = new DecayingHashSet(ctx, 10*60*1000, 8, "SSU-DH-X"); DEFAULT_MAX_CONCURRENT_ESTABLISH = Math.max(DEFAULT_LOW_MAX_CONCURRENT_ESTABLISH, Math.min(DEFAULT_HIGH_MAX_CONCURRENT_ESTABLISH, ctx.bandwidthLimiter().getOutboundKBytesPerSecond() / 2)); @@ -159,6 +165,7 @@ class EstablishmentManager { _context.statManager().createRateStat("udp.rejectConcurrentSequence", "How many consecutive concurrency rejections have we had when we stop rejecting (period is how many concurrent packets we are on)", "udp", UDPTransport.RATES); //_context.statManager().createRateStat("udp.queueDropSize", "How many messages were queued up when it was considered full, causing a tail drop?", "udp", UDPTransport.RATES); //_context.statManager().createRateStat("udp.queueAllowTotalLifetime", "When a peer is retransmitting and we probabalistically allow a new message, what is the sum of the pending message lifetimes? (period is the new message's lifetime)?", "udp", UDPTransport.RATES); + _context.statManager().createRateStat("udp.dupDHX", "Session request replay", "udp", new long[] { 24*60*60*1000L } ); } public synchronized void startup() { @@ -450,6 +457,14 @@ class EstablishmentManager { _transport.getExternalPort(fromIP.length == 16), _transport.getDHBuilder()); state.receiveSessionRequest(reader.getSessionRequestReader()); + + if (_replayFilter.add(state.getReceivedX(), 0, 8)) { + if (_log.shouldLog(Log.WARN)) + _log.warn("Duplicate X in session request from: " + from); + _context.statManager().addRateData("udp.dupDHX", 1); + return; // drop the packet + } + InboundEstablishState oldState = _inboundStates.putIfAbsent(from, state); isNew = oldState == null; if (!isNew) -- GitLab