From b61127270e95e83d984ed490a4f4ec24d9de769d Mon Sep 17 00:00:00 2001 From: zzz Date: Wed, 22 Aug 2012 17:43:09 +0000 Subject: [PATCH] * SSU: - Fail establishment immediately on SessionCreated validation fail - Defer outbound DH generation until required - Validate address/port in RelayIntro messages - Throttle hole punches - More cleanups --- history.txt | 12 +++ .../src/net/i2p/router/RouterVersion.java | 2 +- .../transport/udp/EstablishmentManager.java | 58 +++++++---- .../transport/udp/InboundEstablishState.java | 21 ++-- .../transport/udp/IntroductionManager.java | 96 +++++++++++++++++-- .../transport/udp/OutboundEstablishState.java | 49 +++++++--- .../router/transport/udp/PacketBuilder.java | 53 ++++------ .../router/transport/udp/UDPTransport.java | 17 ++++ 8 files changed, 225 insertions(+), 83 deletions(-) diff --git a/history.txt b/history.txt index fb575400a7..b96e008c44 100644 --- a/history.txt +++ b/history.txt @@ -1,3 +1,15 @@ +2012-08-22 zzz + * NetDB: Add hash collision detection + * SimpleTimer2: Synchronization improvements (ticket #653) + * SSU: + - Fail establishment immediately on SessionCreated + validation fail + - Defer outbound DH generation until required + - Validate address/port in RelayIntro messages + - Throttle hole punches + - Workaround for Android ICS bug + - More cleanups + 2012-08-21 zzz * NetDB: Decrease stat publish probability * SSU: diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index 31c35f8c3e..ea17ad55f3 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -18,7 +18,7 @@ public class RouterVersion { /** deprecated */ public final static String ID = "Monotone"; public final static String VERSION = CoreVersion.VERSION; - public final static long BUILD = 14; + public final static long BUILD = 15; /** for example "-test" */ public final static String EXTRA = ""; 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 c1d472915f..b63b0ac51d 100644 --- a/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java +++ b/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java @@ -340,7 +340,7 @@ class EstablishmentManager { } state = new OutboundEstablishState(_context, maybeTo, to, toIdentity, - sessionKey, addr, _transport.getDHBuilder()); + sessionKey, addr, _transport.getDHFactory()); OutboundEstablishState oldState = _outboundStates.putIfAbsent(to, state); boolean isNew = oldState == null; if (isNew) { @@ -394,6 +394,15 @@ class EstablishmentManager { return getMaxConcurrentEstablish()/2; } + /** + * Should we allow another inbound establishment? + * Used to throttle outbound hole punches. + * @since 0.9.2 + */ + public boolean shouldAllowInboundEstablishment() { + return _inboundStates.size() < getMaxInboundEstablishers(); + } + /** * Got a SessionRequest (initiates an inbound establishment) * @@ -405,15 +414,13 @@ class EstablishmentManager { return; } - int maxInbound = getMaxInboundEstablishers(); - boolean isNew = false; InboundEstablishState state = _inboundStates.get(from); if (state == null) { // TODO this is insufficient to prevent DoSing, especially if // IP spoofing is used. For further study. - if (_inboundStates.size() >= maxInbound) { + if (!shouldAllowInboundEstablishment()) { if (_log.shouldLog(Log.WARN)) _log.warn("Dropping inbound establish, increase " + PROP_MAX_CONCURRENT_ESTABLISH); _context.statManager().addRateData("udp.establishDropped", 1); @@ -861,10 +868,15 @@ class EstablishmentManager { state.setIntroNonce(nonce); } _context.statManager().addRateData("udp.sendIntroRelayRequest", 1, 0); - UDPPacket requests[] = _builder.buildRelayRequest(_transport, state, _transport.getIntroKey()); - for (int i = 0; i < requests.length; i++) { - if (requests[i] != null) - _transport.send(requests[i]); + List requests = _builder.buildRelayRequest(_transport, state, _transport.getIntroKey()); + if (requests.isEmpty()) { + // FIXME need a failed OB state + if (_log.shouldLog(Log.WARN)) + _log.warn("No valid introducers! " + state); + // set failed state, remove nonce, and return + } + for (UDPPacket req : requests) { + _transport.send(req); } if (_log.shouldLog(Log.DEBUG)) _log.debug("Send intro for " + state + " with our intro key as " + _transport.getIntroKey()); @@ -895,8 +907,9 @@ class EstablishmentManager { if (_log.shouldLog(Log.WARN)) _log.warn("Introducer for " + state + " (" + bob + ") sent us an invalid address for our target: " + Addresses.toString(ip, port), uhe); // these two cause this peer to requeue for a new intro peer - state.introductionFailed(); - notifyActivity(); + // FIXME no it doesn't, we send to all at once + //state.introductionFailed(); + //notifyActivity(); return; } _context.statManager().addRateData("udp.receiveIntroRelayResponse", state.getLifetime(), 0); @@ -936,7 +949,7 @@ class EstablishmentManager { boolean valid = state.validateSessionCreated(); if (!valid) { // validate clears fields on failure - // TODO - send destroy? shitlist? + // sendDestroy(state) won't work as we haven't sent the confirmed... if (_log.shouldLog(Log.WARN)) _log.warn("SessionCreated validate failed: " + state); return; @@ -1018,16 +1031,16 @@ class EstablishmentManager { // completely received (though the signature may be invalid) iter.remove(); inboundState = cur; - if (_log.shouldLog(Log.DEBUG)) - _log.debug("Removing completely confirmed inbound state"); + //if (_log.shouldLog(Log.DEBUG)) + // _log.debug("Removing completely confirmed inbound state"); break; } else if (cur.getLifetime() > MAX_IB_ESTABLISH_TIME) { // took too long iter.remove(); inboundState = cur; //_context.statManager().addRateData("udp.inboundEstablishFailedState", cur.getState(), cur.getLifetime()); - if (_log.shouldLog(Log.DEBUG)) - _log.debug("Removing expired inbound state"); + //if (_log.shouldLog(Log.DEBUG)) + // _log.debug("Removing expired inbound state"); expired = true; break; } else if (cur.getState() == IB_STATE_FAILED) { @@ -1133,20 +1146,19 @@ class EstablishmentManager { for (Iterator iter = _outboundStates.values().iterator(); iter.hasNext(); ) { OutboundEstablishState cur = iter.next(); - if (cur.getState() == OB_STATE_CONFIRMED_COMPLETELY) { - // completely received + OutboundEstablishState.OutboundState state = cur.getState(); + if (state == OB_STATE_CONFIRMED_COMPLETELY || + state == OB_STATE_VALIDATION_FAILED) { iter.remove(); outboundState = cur; - if (_log.shouldLog(Log.DEBUG)) - _log.debug("Removing confirmed outbound: " + cur); break; } else if (cur.getLifetime() >= MAX_OB_ESTABLISH_TIME) { // took too long iter.remove(); outboundState = cur; //_context.statManager().addRateData("udp.outboundEstablishFailedState", cur.getState(), cur.getLifetime()); - if (_log.shouldLog(Log.DEBUG)) - _log.debug("Removing expired outbound: " + cur); + //if (_log.shouldLog(Log.DEBUG)) + // _log.debug("Removing expired outbound: " + cur); break; } else { if (cur.getNextSendTime() <= now) { @@ -1233,6 +1245,10 @@ class EstablishmentManager { else if (outboundState.getNextSendTime() <= now) handlePendingIntro(outboundState); break; + + case OB_STATE_VALIDATION_FAILED: + processExpired(outboundState); + break; } } diff --git a/router/java/src/net/i2p/router/transport/udp/InboundEstablishState.java b/router/java/src/net/i2p/router/transport/udp/InboundEstablishState.java index 6540293d68..d69e9b76d9 100644 --- a/router/java/src/net/i2p/router/transport/udp/InboundEstablishState.java +++ b/router/java/src/net/i2p/router/transport/udp/InboundEstablishState.java @@ -178,8 +178,6 @@ class InboundEstablishState { /** what port number do they appear to be coming from? */ public int getSentPort() { return _alicePort; } - public synchronized byte[] getBobIP() { return _bobIP; } - public synchronized byte[] getSentY() { if (_sentY == null) _sentY = _keyBuilder.getMyPublicValueBytes(); @@ -328,6 +326,8 @@ class InboundEstablishState { /** * Who is Alice (null if forged/unknown) + * + * Note that this isn't really confirmed - see below. */ public synchronized RouterIdentity getConfirmedIdentity() { if (!_verificationAttempted) { @@ -341,8 +341,13 @@ class InboundEstablishState { * Determine if Alice sent us a valid confirmation packet. The * identity signs: Alice's IP + Alice's port + Bob's IP + Bob's port * + Alice's new relay key + Alice's signed on time + * + * Note that the protocol does not include a signature of the RouterIdentity, + * which could be a problem? + * + * Caller must synch on this. */ - private synchronized void verifyIdentity() { + private void verifyIdentity() { int identSize = 0; for (int i = 0; i < _receivedIdentity.length; i++) identSize += _receivedIdentity[i].length; @@ -385,6 +390,8 @@ class InboundEstablishState { Signature sig = new Signature(_receivedSignature); boolean ok = _context.dsa().verifySignature(sig, signed, peer.getSigningPublicKey()); if (ok) { + // todo partial spoof detection - get peer.calculateHash(), + // lookup in netdb locally, if not equal, fail? _receivedConfirmedIdentity = peer; } else { if (_log.shouldLog(Log.WARN)) @@ -408,10 +415,10 @@ class InboundEstablishState { StringBuilder buf = new StringBuilder(128); buf.append("IES "); buf.append(Addresses.toString(_aliceIP, _alicePort)); - if (_receivedX != null) - buf.append(" ReceivedX: ").append(Base64.encode(_receivedX, 0, 4)); - if (_sentY != null) - buf.append(" SentY: ").append(Base64.encode(_sentY, 0, 4)); + //if (_receivedX != null) + // buf.append(" ReceivedX: ").append(Base64.encode(_receivedX, 0, 4)); + //if (_sentY != null) + // buf.append(" SentY: ").append(Base64.encode(_sentY, 0, 4)); //buf.append(" Bob: ").append(Addresses.toString(_bobIP, _bobPort)); buf.append(" RelayTag: ").append(_sentRelayTag); //buf.append(" SignedOn: ").append(_sentSignedOnTime); diff --git a/router/java/src/net/i2p/router/transport/udp/IntroductionManager.java b/router/java/src/net/i2p/router/transport/udp/IntroductionManager.java index c539af49d2..96e51be4b0 100644 --- a/router/java/src/net/i2p/router/transport/udp/IntroductionManager.java +++ b/router/java/src/net/i2p/router/transport/udp/IntroductionManager.java @@ -1,6 +1,9 @@ package net.i2p.router.transport.udp; +import java.net.InetAddress; +import java.net.UnknownHostException; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Properties; @@ -18,7 +21,7 @@ import net.i2p.util.ConcurrentHashSet; import net.i2p.util.Log; /** - * + * Keep track of inbound and outbound introductions. */ class IntroductionManager { private final RouterContext _context; @@ -29,6 +32,8 @@ class IntroductionManager { private final Map _outbound; /** list of peers (PeerState) who have given us introduction tags */ private final Set _inbound; + private final Set _recentHolePunches; + private long _lastHolePunchClean; /** * Limit since we ping to keep the conn open @@ -42,6 +47,11 @@ class IntroductionManager { */ private static final int MAX_OUTBOUND = 100; + /** Max one per target in this time */ + private static final long PUNCH_CLEAN_TIME = 5*1000; + /** Max for all targets per PUNCH_CLEAN_TIME */ + private static final int MAX_PUNCHES = 8; + public IntroductionManager(RouterContext ctx, UDPTransport transport) { _context = ctx; _log = ctx.logManager().getLog(IntroductionManager.class); @@ -49,6 +59,7 @@ class IntroductionManager { _builder = new PacketBuilder(ctx, transport); _outbound = new ConcurrentHashMap(MAX_OUTBOUND); _inbound = new ConcurrentHashSet(MAX_INBOUND); + _recentHolePunches = new HashSet(16); ctx.statManager().createRateStat("udp.receiveRelayIntro", "How often we get a relayed request for us to talk to someone?", "udp", UDPTransport.RATES); ctx.statManager().createRateStat("udp.receiveRelayRequest", "How often we receive a good request to relay to someone else?", "udp", UDPTransport.RATES); ctx.statManager().createRateStat("udp.receiveRelayRequestBadTag", "Received relay requests with bad/expired tag", "udp", UDPTransport.RATES); @@ -203,18 +214,87 @@ class IntroductionManager { void receiveRelayIntro(RemoteHostId bob, UDPPacketReader reader) { if (_context.router().isHidden()) return; - if (_log.shouldLog(Log.INFO)) - _log.info("Receive relay intro from " + bob); _context.statManager().addRateData("udp.receiveRelayIntro", 1, 0); - if (!_transport.allowConnection()) + if (!_transport.allowConnection()) { + if (_log.shouldLog(Log.WARN)) + _log.warn("Dropping RelayIntro, over conn limit"); return; + } + + int ipSize = reader.getRelayIntroReader().readIPSize(); + byte ip[] = new byte[ipSize]; + reader.getRelayIntroReader().readIP(ip, 0); + int port = reader.getRelayIntroReader().readPort(); + if (_log.shouldLog(Log.INFO)) + _log.info("Receive relay intro from " + bob + " for " + Addresses.toString(ip, port)); + + InetAddress to = null; + try { + if (!_transport.isValid(ip)) + throw new UnknownHostException("non-public IP"); + if (port <= 0 || port > 65535) + throw new UnknownHostException("bad port " + port); + to = InetAddress.getByAddress(ip); + } catch (UnknownHostException uhe) { + // shitlist Bob? + if (_log.shouldLog(Log.WARN)) + _log.warn("IP for alice to hole punch to is invalid", uhe); + return; + } + + RemoteHostId alice = new RemoteHostId(ip, port); + if (_transport.getPeerState(alice) != null) { + if (_log.shouldLog(Log.INFO)) + _log.info("Ignoring RelayIntro, already have a session to " + to); + return; + } + EstablishmentManager establisher = _transport.getEstablisher(); + if (establisher != null) { + if (establisher.getInboundState(alice) != null) { + // This check may be common, as Alice sends RelayRequests to + // several introducers at once. + if (_log.shouldLog(Log.INFO)) + _log.info("Ignoring RelayIntro, establishment in progress to " + to); + return; + } + if (!establisher.shouldAllowInboundEstablishment()) { + if (_log.shouldLog(Log.WARN)) + _log.warn("Dropping RelayIntro, too many establishments in progress - for " + to); + return; + } + } - // TODO throttle - // TODO IB req limits - // TODO check if already have a session or in progress state. + // basic throttle, don't bother saving per-peer send times + // we throttle on IP only, ignoring port + boolean tooMany = false; + boolean already = false; + synchronized (_recentHolePunches) { + long now = _context.clock().now(); + if (now > _lastHolePunchClean + PUNCH_CLEAN_TIME) { + _recentHolePunches.clear(); + _lastHolePunchClean = now; + _recentHolePunches.add(to); + } else { + tooMany = _recentHolePunches.size() >= MAX_PUNCHES; + if (!tooMany) + already = !_recentHolePunches.add(to); + } + } + if (tooMany) { + if (_log.shouldLog(Log.WARN)) + _log.warn("Dropping - too many - RelayIntro for " + to); + return; + } + if (already) { + // This check will trigger a lot, as Alice sends RelayRequests to + // several introducers at once. + if (_log.shouldLog(Log.INFO)) + _log.info("Ignoring dup RelayIntro for " + to); + return; + } - _transport.send(_builder.buildHolePunch(reader)); + _transport.send(_builder.buildHolePunch(to, port)); } /** diff --git a/router/java/src/net/i2p/router/transport/udp/OutboundEstablishState.java b/router/java/src/net/i2p/router/transport/udp/OutboundEstablishState.java index 6e94173c5f..47922180d7 100644 --- a/router/java/src/net/i2p/router/transport/udp/OutboundEstablishState.java +++ b/router/java/src/net/i2p/router/transport/udp/OutboundEstablishState.java @@ -26,10 +26,11 @@ class OutboundEstablishState { private final RouterContext _context; private final Log _log; // SessionRequest message - private final byte _sentX[]; + private byte _sentX[]; private byte _bobIP[]; private int _bobPort; - private final DHSessionKeyBuilder _keyBuilder; + private final DHSessionKeyBuilder.Factory _keyFactory; + private DHSessionKeyBuilder _keyBuilder; // SessionCreated message private byte _receivedY[]; private byte _aliceIP[]; @@ -82,7 +83,9 @@ class OutboundEstablishState { /** we need to have someone introduce us to the peer, but haven't received a RelayResponse yet */ OB_STATE_PENDING_INTRO, /** RelayResponse received */ - OB_STATE_INTRODUCED + OB_STATE_INTRODUCED, + /** SessionConfirmed failed validation */ + OB_STATE_VALIDATION_FAILED } /** basic delay before backoff */ @@ -99,7 +102,7 @@ class OutboundEstablishState { public OutboundEstablishState(RouterContext ctx, RemoteHostId claimedAddress, RemoteHostId remoteHostId, RouterIdentity remotePeer, SessionKey introKey, UDPAddress addr, - DHSessionKeyBuilder dh) { + DHSessionKeyBuilder.Factory dh) { _context = ctx; _log = ctx.logManager().getLog(OutboundEstablishState.class); if (claimedAddress != null) { @@ -117,9 +120,7 @@ class OutboundEstablishState { _establishBegin = ctx.clock().now(); _remoteAddress = addr; _introductionNonce = -1; - _keyBuilder = dh; - _sentX = new byte[UDPPacketReader.SessionRequestReader.X_LENGTH]; - prepareSessionRequest(); + _keyFactory = dh; if (addr.getIntroducerCount() > 0) { if (_log.shouldLog(Log.DEBUG)) _log.debug("new outbound establish to " + remotePeer.calculateHash() + ", with address: " + addr); @@ -165,8 +166,10 @@ class OutboundEstablishState { public RouterIdentity getRemoteIdentity() { return _remotePeer; } public SessionKey getIntroKey() { return _introKey; } - /** called from constructor, no need to synch */ + /** caller must synch - only call once */ private void prepareSessionRequest() { + _keyBuilder = _keyFactory.getBuilder(); + _sentX = new byte[UDPPacketReader.SessionRequestReader.X_LENGTH]; byte X[] = _keyBuilder.getMyPublicValue().toByteArray(); if (X.length == 257) System.arraycopy(X, 1, _sentX, 0, _sentX.length); @@ -176,7 +179,13 @@ class OutboundEstablishState { System.arraycopy(X, 0, _sentX, _sentX.length - X.length, X.length); } - public byte[] getSentX() { return _sentX; } + public synchronized byte[] getSentX() { + // We defer keygen until now so that it gets done in the Establisher loop, + // and so that we don't waste entropy on failed introductions + if (_sentX == null) + prepareSessionRequest(); + return _sentX; + } /** * The remote side (Bob) - note that in some places he's called Charlie. @@ -191,6 +200,11 @@ class OutboundEstablishState { public synchronized int getSentPort() { return _bobPort; } public synchronized void receiveSessionCreated(UDPPacketReader.SessionCreatedReader reader) { + if (_currentState == OutboundState.OB_STATE_VALIDATION_FAILED) { + if (_log.shouldLog(Log.WARN)) + _log.warn("Session created already failed"); + return; + } if (_receivedY != null) { if (_log.shouldLog(Log.DEBUG)) _log.debug("Session created already received, ignoring"); @@ -236,6 +250,11 @@ class OutboundEstablishState { * @return true if valid */ public synchronized boolean validateSessionCreated() { + if (_currentState == OutboundState.OB_STATE_VALIDATION_FAILED) { + if (_log.shouldLog(Log.WARN)) + _log.warn("Session created already failed"); + return false; + } if (_receivedSignature != null) { if (_log.shouldLog(Log.WARN)) _log.warn("Session created already validated"); @@ -265,6 +284,9 @@ class OutboundEstablishState { } } + /** + * The SessionCreated validation failed + */ public synchronized void fail() { _receivedY = null; _aliceIP = null; @@ -273,10 +295,9 @@ class OutboundEstablishState { _receivedEncryptedSignature = null; _receivedIV = null; _receivedSignature = null; - - if ( (_currentState == OutboundState.OB_STATE_UNKNOWN) || - (_currentState == OutboundState.OB_STATE_CREATED_RECEIVED) ) - _currentState = OutboundState.OB_STATE_REQUEST_SENT; + // sure, there's a chance the packet was corrupted, but in practice + // this means that Bob doesn't know his external port, so give up. + _currentState = OutboundState.OB_STATE_VALIDATION_FAILED; _nextSend = _context.clock().now(); } @@ -287,6 +308,8 @@ class OutboundEstablishState { */ private void generateSessionKey() throws DHSessionKeyBuilder.InvalidPublicParameterException { if (_sessionKey != null) return; + if (_keyBuilder == null) + throw new DHSessionKeyBuilder.InvalidPublicParameterException("Illegal state - never generated a key builder"); _keyBuilder.setPeerPublicValue(_receivedY); _sessionKey = _keyBuilder.getSessionKey(); ByteArray extra = _keyBuilder.getExtraBytes(); diff --git a/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java b/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java index 8b2b3414e8..7da5fca702 100644 --- a/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java +++ b/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java @@ -2,6 +2,7 @@ package net.i2p.router.transport.udp; import java.net.InetAddress; import java.net.UnknownHostException; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Iterator; @@ -659,13 +660,15 @@ class PacketBuilder { _log.debug("Sending request"); // now for the body - System.arraycopy(state.getSentX(), 0, data, off, state.getSentX().length); - off += state.getSentX().length; - DataHelper.toLong(data, off, 1, state.getSentIP().length); + byte[] x = state.getSentX(); + System.arraycopy(x, 0, data, off, x.length); + off += x.length; + DataHelper.toLong(data, off, 1, toIP.length); off += 1; - System.arraycopy(toIP, 0, data, off, state.getSentIP().length); + System.arraycopy(toIP, 0, data, off, toIP.length); off += toIP.length; - DataHelper.toLong(data, off, 2, state.getSentPort()); + int port = state.getSentPort(); + DataHelper.toLong(data, off, 2, port); off += 2; // we can pad here if we want, maybe randomized? @@ -675,7 +678,7 @@ class PacketBuilder { off += 16 - (off % 16); packet.getPacket().setLength(off); authenticate(packet, state.getIntroKey(), state.getIntroKey()); - setTo(packet, to, state.getSentPort()); + setTo(packet, to, port); packet.setMessageType(TYPE_SREQ); return packet; } @@ -1050,14 +1053,14 @@ class PacketBuilder { private byte[] getOurExplicitIP() { return null; } private int getOurExplicitPort() { return 0; } - /** build intro packets for each of the published introducers */ - @SuppressWarnings("static-access") - public UDPPacket[] buildRelayRequest(UDPTransport transport, OutboundEstablishState state, SessionKey ourIntroKey) { + /** + * build intro packets for each of the published introducers + * @return empty list on failure + */ + public List buildRelayRequest(UDPTransport transport, OutboundEstablishState state, SessionKey ourIntroKey) { UDPAddress addr = state.getRemoteAddress(); int count = addr.getIntroducerCount(); - if (count <= 0) - return new UDPPacket[0]; - UDPPacket rv[] = new UDPPacket[count]; + List rv = new ArrayList(count); for (int i = 0; i < count; i++) { InetAddress iaddr = addr.getIntroducerHost(i); int iport = addr.getIntroducerPort(i); @@ -1069,8 +1072,9 @@ class PacketBuilder { + ", as their UDP address is invalid: addr=" + addr + " index=" + i); continue; } + // TODO implement some sort of introducer shitlist if (transport.isValid(iaddr.getAddress())) - rv[i] = buildRelayRequest(iaddr, iport, ikey, tag, ourIntroKey, state.getIntroNonce(), true); + rv.add(buildRelayRequest(iaddr, iport, ikey, tag, ourIntroKey, state.getIntroNonce(), true)); } return rv; } @@ -1227,28 +1231,11 @@ class PacketBuilder { } /** - * Sends an empty unauthenticated packet for hole punching + * Sends an empty unauthenticated packet for hole punching. + * Parameters must be validated previously. */ - public UDPPacket buildHolePunch(UDPPacketReader reader) { + public UDPPacket buildHolePunch(InetAddress to, int port) { UDPPacket packet = UDPPacket.acquire(_context, false); - byte data[] = packet.getPacket().getData(); - Arrays.fill(data, 0, data.length, (byte)0x0); - - int ipSize = reader.getRelayIntroReader().readIPSize(); - byte ip[] = new byte[ipSize]; - reader.getRelayIntroReader().readIP(ip, 0); - int port = reader.getRelayIntroReader().readPort(); - - InetAddress to = null; - try { - to = InetAddress.getByAddress(ip); - } catch (UnknownHostException uhe) { - if (_log.shouldLog(Log.WARN)) - _log.warn("IP for alice to hole punch to is invalid", uhe); - packet.release(); - return null; - } - if (_log.shouldLog(Log.INFO)) _log.info("Sending relay hole punch to " + to + ":" + port); diff --git a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java index 91e239807d..a956cb1e03 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java @@ -716,6 +716,14 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority return _peersByIdent.get(remotePeer); } + /** + * For IntroductionManager + * @return may be null if not started + * @since 0.9.2 + */ + EstablishmentManager getEstablisher() { + return _establisher; + } /** * Intercept RouterInfo entries received directly from a peer to inject them into * the PeersByCapacity listing. @@ -1682,11 +1690,20 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority } /** + * @return a new DHSessionKeyBuilder * @since 0.9 */ DHSessionKeyBuilder getDHBuilder() { return _dhFactory.getBuilder(); } + + /** + * @return the factory + * @since 0.9.2 + */ + DHSessionKeyBuilder.Factory getDHFactory() { + return _dhFactory; + } private static final int FLAG_ALPHA = 0; private static final int FLAG_IDLE_IN = 1;