From b2135214e4d10f503cf72e5448a35847cd0bef84 Mon Sep 17 00:00:00 2001 From: zzz Date: Mon, 22 Apr 2024 19:40:50 +0000 Subject: [PATCH] Transport: SSU1 removal part 3/n --- .../router/transport/udp/PeerTestManager.java | 685 +----------------- 1 file changed, 8 insertions(+), 677 deletions(-) diff --git a/router/java/src/net/i2p/router/transport/udp/PeerTestManager.java b/router/java/src/net/i2p/router/transport/udp/PeerTestManager.java index dff613c39..a94ab89b7 100644 --- a/router/java/src/net/i2p/router/transport/udp/PeerTestManager.java +++ b/router/java/src/net/i2p/router/transport/udp/PeerTestManager.java @@ -226,7 +226,7 @@ class PeerTestManager { PeerTestState test = new PeerTestState(ALICE, bob, bobIP instanceof Inet6Address, _context.random().nextLong(MAX_NONCE), _context.clock().now()); - if (bob.getVersion() == 2) { + PeerState2 b2 = (PeerState2) bob; // We test our current address, NOT the IP we have with Bob, which may have changed since, // especially with IPv6 transient addresses, @@ -259,18 +259,7 @@ class PeerTestManager { _log.warn("Unable to get our IP", uhe); return false; } - } else { - // set Alice IP/port, needed for receiveTestReply() checks for msg 7 - RouterAddress ra = _transport.getCurrentExternalAddress(bob.isIPv6()); - if (ra != null) { - byte[] ourIP = ra.getIP(); - int ourPort = ra.getPort(); - try { - InetAddress addr = InetAddress.getByAddress(ourIP); - test.setAlice(addr, ourPort, null); - } catch (UnknownHostException uhe) {} - } - } + _currentTest = test; _currentTestComplete = false; @@ -331,9 +320,7 @@ class PeerTestManager { // received from Bob, but no reply from Charlie. send it to // Bob again so he pokes Charlie // We don't resend to Bob for SSU2; Charlie will retransmit. - if (state.getBob().getVersion() == 1) { - sendTestToBob(); - } else if (ENABLE_SSU2_SYMNAT_TEST) { + if (ENABLE_SSU2_SYMNAT_TEST) { // if version 2 and it's been long enough, and Charlie isn't firewalled, send msg 6 anyway // This allows us to detect Symmetric NAT. // We don't have his IP/port if he's firewalled, and we wouldn't trust his answer @@ -400,11 +387,7 @@ class PeerTestManager { _log.debug("Sending test to Bob: " + test); UDPPacket packet; PeerState bob = test.getBob(); - if (bob.getVersion() == 1) { - packet = _packetBuilder.buildPeerTestFromAlice(test.getBobIP(), test.getBobPort(), - test.getBobCipherKey(), test.getBobMACKey(), - test.getNonce(), _transport.getIntroKey()); - } else { + PeerState2 bob2 = (PeerState2) bob; // only create this once byte[] data = test.getTestData(); @@ -427,7 +410,7 @@ class PeerTestManager { fail(); return; } - } + _transport.send(packet); long now = _context.clock().now(); test.setLastSendTime(now); @@ -451,12 +434,7 @@ class PeerTestManager { long now = _context.clock().now(); test.setLastSendTime(now); test.setSendCharlieTime(now); - UDPPacket packet; - if (test.getBob().getVersion() == 1) { - packet = _packetBuilder.buildPeerTestFromAlice(test.getCharlieIP(), test.getCharliePort(), - test.getCharlieIntroKey(), - test.getNonce(), _transport.getIntroKey()); - } else { + long nonce = test.getNonce(); long rcvId = (nonce << 32) | nonce; long sendId = ~rcvId; @@ -471,10 +449,10 @@ class PeerTestManager { data[9] = (byte) (iplen + 2); DataHelper.toLong(data, 10, 2, alicePort); System.arraycopy(aliceIP, 0, data, 12, iplen); - packet = _packetBuilder2.buildPeerTestFromAlice(test.getCharlieIP(), test.getCharliePort(), + UDPPacket packet = _packetBuilder2.buildPeerTestFromAlice(test.getCharlieIP(), test.getCharliePort(), test.getCharlieIntroKey(), sendId, rcvId, data); - } + _transport.send(packet); } else { _currentTest = null; @@ -492,197 +470,6 @@ class PeerTestManager { */ private static final long CHARLIE_RECENT_PERIOD = 10*60*1000; - /** - * Receive a PeerTest message which contains the correct nonce for our current - * test. We are Alice. - * - * SSU 1 only. - * - * @param fromPeer non-null if an associated session was found, otherwise may be null - * @param inSession true if authenticated in-session - */ - private synchronized void receiveTestReply(RemoteHostId from, PeerState fromPeer, boolean inSession, - UDPPacketReader.PeerTestReader testInfo) { - _context.statManager().addRateData("udp.receiveTestReply", 1); - PeerTestState test = _currentTest; - if (expired()) - return; - if (_currentTestComplete) - return; - if ( (DataHelper.eq(from.getIP(), test.getBobIP().getAddress())) && (from.getPort() == test.getBobPort()) ) { - // The reply is from Bob - - if (inSession) { - // i2pd has sent the Bob->Alice message in-session for a long time - // Java I2P switched to in-session in 0.9.52 - //if (_log.shouldDebug()) - // _log.debug("Bob replied to us (Alice) in-session " + fromPeer); - } else { - // Check Bob version, drop if >= 0.9.52 - fromPeer = test.getBob(); - Hash bob = fromPeer.getRemotePeer(); - RouterInfo bobRI = _context.netDb().lookupRouterInfoLocally(bob); - if (bobRI == null || VersionComparator.comp(bobRI.getVersion(), "0.9.52") >= 0) { - if (_log.shouldInfo()) - _log.info("Bob replied to us (Alice) with intro key " + fromPeer); - fail(); - return; - } - } - - int ipSize = testInfo.readIPSize(); - boolean expectV6 = test.isIPv6(); - if ((!expectV6 && ipSize != 4) || - (expectV6 && ipSize != 16)) { - // There appears to be an i2pd bug where Bob is sending us a zero-length IP. - // We could proceed without setting the IP, but then when Charlie - // sends us his message, we will think we are behind a symmetric NAT - // because the Bob and Charlie IPs won't match. - // Stop the test. - // Sometimes, the first response has an IP but a later one does not, - // check every time. - if (_log.shouldLog(Log.WARN)) - _log.warn("Bad IP length " + ipSize + " from bob's reply: " + from); - fail(); - return; - } - byte ip[] = new byte[ipSize]; - testInfo.readIP(ip, 0); - try { - if (test.getReceiveBobTime() <= 0) { - InetAddress addr = InetAddress.getByAddress(ip); - int testPort = testInfo.readPort(); - if (testPort == 0) - throw new UnknownHostException("port 0"); - test.setAlice(addr, testPort, null); - } // else ignore IP/port - test.setReceiveBobTime(_context.clock().now()); - - if (_log.shouldLog(Log.DEBUG)) - _log.debug("Receive test reply from Bob: " + test); - if (test.getAlicePortFromCharlie() > 0) - testComplete(); - } catch (UnknownHostException uhe) { - if (_log.shouldLog(Log.WARN)) - _log.warn("Unable to get our IP (length " + ipSize + - ") from bob's reply: " + from, uhe); - _context.statManager().addRateData("udp.testBadIP", 1); - } - } else { - // The reply is from Charlie - - PeerState charlieSession = _transport.getPeerState(from); - long recentBegin = _context.clock().now() - CHARLIE_RECENT_PERIOD; - if ( (charlieSession != null) && - ( (charlieSession.getLastACKSend() > recentBegin) || - (charlieSession.getLastSendTime() > recentBegin) ) ) { - if (_log.shouldLog(Log.WARN)) - _log.warn("Bob chose a charlie we already have a session to, cancelling the test and rerunning (bob: " - + _currentTest + ", charlie: " + from + ")"); - // why are we doing this instead of calling testComplete() ? - _currentTestComplete = true; - _context.statManager().addRateData("udp.statusKnownCharlie", 1); - honorStatus(Status.UNKNOWN, test.isIPv6()); - _currentTest = null; - return; - } - - if (test.getReceiveCharlieTime() > 0) { - // this is our second charlie, yay! - try { - int testPort = testInfo.readPort(); - if (testPort < 1024) - throw new UnknownHostException("port " + testPort); - test.setAlicePortFromCharlie(testPort); - byte ip[] = new byte[testInfo.readIPSize()]; - int ipSize = ip.length; - boolean expectV6 = test.isIPv6(); - if ((!expectV6 && ipSize != 4) || - (expectV6 && ipSize != 16)) - throw new UnknownHostException("bad sz - expect v6? " + expectV6 + " act sz: " + ipSize); - testInfo.readIP(ip, 0); - InetAddress addr = InetAddress.getByAddress(ip); - - if (_log.shouldLog(Log.DEBUG)) - _log.debug("Receive test reply from Charlie: " + test); - - // fixups if we didn't know our IP/port at the start - int origPort = test.getAlicePort(); - InetAddress origAddr = test.getAliceIP(); - boolean portok; - if (origPort > 0) { - portok = testPort == origPort; - } else { - portok = true; - test.setAlice(test.getAliceIP(), testPort, null); - } - boolean IPok; - if (origAddr != null) { - IPok = DataHelper.eq(ip, origAddr.getAddress()); - } else { - IPok = true; - test.setAlice(addr, test.getAlicePort(), null); - } - if (!portok || !IPok) { - if (_log.shouldWarn()) - _log.warn("Charlie said we had a different IP/port: " + - Addresses.toString(ip, testPort) + " on " + test); - // Since we did get msg 5, it's almost impossible for us to be symmetric natted. - // It's much more likely that Charlie is symmetric natted. - // However, our IP could have changed. - // Force result to OK - // testComplete() will deal with it - if (!portok) { - // Port different. Charlie probably symmetric natted. - // Reset port so testComplete() will return success. - test.setAlicePortFromCharlie(test.getAlicePort()); - } - if (!IPok) { - // Our IP changed? - // Reset IP so testComplete() will return success. - addr = test.getAliceIP(); - } - } - test.setAliceIPFromCharlie(addr); - if (test.getReceiveBobTime() > 0) - testComplete(); - } catch (UnknownHostException uhe) { - if (_log.shouldWarn()) - _log.warn("Charlie @ " + from + " said we were an invalid IP address: " + uhe.getMessage(), uhe); - _context.statManager().addRateData("udp.testBadIP", 1); - } - } else { - if (test.incrementPacketsRelayed() > MAX_RELAYED_PER_TEST_ALICE) { - if (_log.shouldLog(Log.WARN)) - _log.warn("Sent too many packets on the test: " + test); - if (!_currentTestComplete) - testComplete(); - return; - } - - if (_log.shouldLog(Log.INFO) && charlieSession != null) - _log.info("Bob chose a charlie we last acked " + DataHelper.formatDuration(_context.clock().now() - charlieSession.getLastACKSend()) + " last sent " + DataHelper.formatDuration(_context.clock().now() - charlieSession.getLastSendTime()) + " (bob: " - + _currentTest + ", charlie: " + from + ")"); - - // ok, first charlie. send 'em a packet - test.setReceiveCharlieTime(_context.clock().now()); - SessionKey charlieIntroKey = new SessionKey(new byte[SessionKey.KEYSIZE_BYTES]); - testInfo.readIntroKey(charlieIntroKey.getData(), 0); - test.setCharlieIntroKey(charlieIntroKey); - try { - test.setCharlie(InetAddress.getByAddress(from.getIP()), from.getPort(), null); - if (_log.shouldLog(Log.DEBUG)) - _log.debug("Receive test from Charlie: " + test); - sendTestToCharlie(); - } catch (UnknownHostException uhe) { - if (_log.shouldLog(Log.WARN)) - _log.warn("Charlie's IP is b0rked: " + from); - _context.statManager().addRateData("udp.testBadIP", 1); - } - } - } - } - /** * Reset all state and call testComplete(). We are Alice. * @@ -863,175 +650,6 @@ class PeerTestManager { _transport.setReachabilityStatus(status, isIPv6); } - /** - * Entry point for all incoming packets. Most of the source and dest validation is here. - * - * SSU 1 only. - * - * Receive a test message of some sort from the given peer, queueing up any packet - * that should be sent in response, or if its a reply to our own current testing, - * adjusting our test state. - * - * We could be Alice, Bob, or Charlie. - * - * @param fromPeer non-null if an associated session was found, otherwise null - * @param inSession true if authenticated in-session - */ - public void receiveTest(RemoteHostId from, PeerState fromPeer, boolean inSession, UDPPacketReader reader) { - _context.statManager().addRateData("udp.receiveTest", 1); - byte[] fromIP = from.getIP(); - int fromPort = from.getPort(); - // no need to do these checks if we received it in-session - if (!inSession || fromPeer == null) { - if (!TransportUtil.isValidPort(fromPort) || - (!_transport.isValid(fromIP)) || - _transport.isTooClose(fromIP) || - _context.blocklist().isBlocklisted(fromIP)) { - // spoof check, and don't respond to privileged ports - if (_log.shouldWarn()) - _log.warn("Invalid PeerTest address: " + Addresses.toString(fromIP, fromPort)); - _context.statManager().addRateData("udp.testBadIP", 1); - return; - } - } else { - fromPeer.setLastReceiveTime(_context.clock().now()); - } - - UDPPacketReader.PeerTestReader testInfo = reader.getPeerTestReader(); - byte testIP[] = null; - int testPort = testInfo.readPort(); - - if (testInfo.readIPSize() > 0) { - testIP = new byte[testInfo.readIPSize()]; - testInfo.readIP(testIP, 0); - } - - if ((testPort > 0 && (!TransportUtil.isValidPort(testPort))) || - (testIP != null && - ((!_transport.isValid(testIP)) || - (testIP.length != 4 && testIP.length != 16) || - _context.blocklist().isBlocklisted(testIP)))) { - // spoof check, and don't respond to privileged ports - if (_log.shouldLog(Log.WARN)) - _log.warn("Invalid address in PeerTest: " + Addresses.toString(testIP, testPort)); - _context.statManager().addRateData("udp.testBadIP", 1); - return; - } - - // The from IP/port and message's IP/port are now validated. - // EXCEPT that either the message's IP could be empty or the message's port could be 0. - // Both of those cases should be checked in receiveXfromY() as appropriate. - // Also, IP could be us, check is below. - - long nonce = testInfo.readNonce(); - PeerTestState test = _currentTest; - if ( (test != null) && (test.getNonce() == nonce) ) { - // we are Alice, we initiated the test - receiveTestReply(from, fromPeer, inSession, testInfo); - return; - } - - // we are Bob or Charlie, we are helping Alice - - if (_throttle.shouldThrottle(fromIP)) { - if (_log.shouldLog(Log.WARN)) - _log.warn("PeerTest throttle from " + Addresses.toString(fromIP, fromPort)); - return; - } - - // use the same counter for both from and to IPs - if (testIP != null && _throttle.shouldThrottle(testIP)) { - if (_log.shouldLog(Log.WARN)) - _log.warn("PeerTest throttle to " + Addresses.toString(testIP, testPort)); - return; - } - - Long lNonce = Long.valueOf(nonce); - PeerTestState state = _activeTests.get(lNonce); - - if (testIP != null && _transport.isTooClose(testIP)) { - // spoof check - have to do this after receiveTestReply(), since - // the field should be us there. - // Let's also eliminate anybody in the same /16 - if (_recentTests.contains(lNonce)) { - if (_log.shouldLog(Log.INFO)) - _log.info("Got delayed reply on nonce " + nonce + - " from: " + Addresses.toString(fromIP, fromPort)); - } else { - if (_log.shouldLog(Log.WARN)) - _log.warn("Nearby address in PeerTest: " + Addresses.toString(testIP, testPort) + - " from: " + Addresses.toString(fromIP, fromPort) + - " state? " + state); - _context.statManager().addRateData("udp.testBadIP", 1); - } - return; - } - - if (state == null) { - // NEW TEST - if ( (testIP == null) || (testPort <= 0) ) { - // we are bob, since we haven't seen this nonce before AND its coming from alice - if (_activeTests.size() >= MAX_ACTIVE_TESTS) { - if (_log.shouldLog(Log.WARN)) - _log.warn("Too many active tests, droppping from Alice " + Addresses.toString(fromIP, fromPort)); - return; - } - if (!inSession || fromPeer == null) { - // Require an existing session to start a test, - // as a way of preventing trouble - if (_log.shouldLog(Log.WARN)) - _log.warn("No session, dropping new test from Alice " + Addresses.toString(fromIP, fromPort)); - return; - } - if (_log.shouldLog(Log.DEBUG)) - _log.debug("test IP/port are blank coming from " + from + ", assuming we are Bob and they are alice"); - receiveFromAliceAsBob(from, fromPeer, testInfo, nonce, null); - } else { - if (_recentTests.contains(lNonce)) { - // ignore the packet, as its a holdover from a recently completed locally - // initiated test - } else { - if (_activeTests.size() >= MAX_ACTIVE_TESTS) { - if (_log.shouldLog(Log.WARN)) - _log.warn("Too many active tests, droppping from Bob " + Addresses.toString(fromIP, fromPort)); - return; - } - if (_log.shouldLog(Log.DEBUG)) - _log.debug("We are charlie, as the testIP/port is " + Addresses.toString(testIP, testPort) + " and the state is unknown for " + nonce); - // we are charlie, since alice never sends us her IP and port, only bob does (and, - // erm, we're not alice, since it isn't our nonce) - receiveFromBobAsCharlie(from, fromPeer, inSession, testInfo, nonce, null); - } - } - } else { - // EXISTING TEST - if (state.getOurRole() == BOB) { - if (DataHelper.eq(fromIP, state.getAliceIP().getAddress()) && - (fromPort == state.getAlicePort()) ) { - if (!inSession || fromPeer == null) { - // Still should be in-session - if (_log.shouldWarn()) - _log.warn("No session, dropping test from Alice " + Addresses.toString(fromIP, fromPort)); - return; - } - receiveFromAliceAsBob(from, fromPeer, testInfo, nonce, state); - } else if (DataHelper.eq(fromIP, state.getCharlieIP().getAddress()) && - (fromPort == state.getCharliePort()) ) { - receiveFromCharlieAsBob(from, fromPeer, inSession, state); - } else { - if (_log.shouldLog(Log.WARN)) - _log.warn("Received from a fourth party as bob! alice: " + state.getAliceIP() + ", charlie: " + state.getCharlieIP() + ", dave: " + from); - } - } else if (state.getOurRole() == CHARLIE) { - if ( (testIP == null) || (testPort <= 0) ) { - receiveFromAliceAsCharlie(from, testInfo, nonce, state); - } else { - receiveFromBobAsCharlie(from, fromPeer, inSession, testInfo, nonce, state); - } - } - } - } - /** * Entry point for all out-of-session packets, messages 5-7 only. * @@ -2121,293 +1739,6 @@ class PeerTestManager { // Below here are methods for when we are Bob or Charlie - /** - * The packet's IP/port does not match the IP/port included in the message, - * so we must be Charlie receiving a PeerTest from Bob. - * - * SSU 1 only. - * - * @param bob non-null if received in-session, otherwise null - * @param inSession true if authenticated in-session - * @param state null if new - */ - private void receiveFromBobAsCharlie(RemoteHostId from, PeerState bob, boolean inSession, - UDPPacketReader.PeerTestReader testInfo, long nonce, PeerTestState state) { - if (!inSession || bob == null) { - if (_log.shouldWarn()) - _log.warn("Received from bob (" + from + ") as charlie w/o session"); - return; - } - - long now = _context.clock().now(); - int sz = testInfo.readIPSize(); - boolean isNew = false; - if (state == null) { - isNew = true; - state = new PeerTestState(CHARLIE, bob, sz == 16, nonce, now); - } else { - if (state.getReceiveBobTime() > now - (RESEND_TIMEOUT / 2)) { - if (_log.shouldDebug()) - _log.debug("Too soon, not retransmitting: " + state); - return; - } - } - - // TODO should only do most of this if isNew - byte aliceIPData[] = new byte[sz]; - try { - testInfo.readIP(aliceIPData, 0); - boolean expectV6 = state.isIPv6(); - if ((!expectV6 && sz != 4) || - (expectV6 && sz != 16)) - throw new UnknownHostException("bad sz - expect v6? " + expectV6 + " act sz: " + sz); - int alicePort = testInfo.readPort(); - if (alicePort == 0) - throw new UnknownHostException("port 0"); - InetAddress aliceIP = InetAddress.getByAddress(aliceIPData); - InetAddress bobIP = InetAddress.getByAddress(from.getIP()); - SessionKey aliceIntroKey = new SessionKey(new byte[SessionKey.KEYSIZE_BYTES]); - testInfo.readIntroKey(aliceIntroKey.getData(), 0); - - state.setAlice(aliceIP, alicePort, null); - state.setAliceIntroKey(aliceIntroKey); - state.setReceiveBobTime(now); - - // we send two packets below, but increment just once - if (state.incrementPacketsRelayed() > MAX_RELAYED_PER_TEST_CHARLIE) { - if (_log.shouldDebug()) - _log.debug("Too many, not retransmitting: " + state); - return; - } - - if (_log.shouldLog(Log.DEBUG)) - _log.debug("Receive from Bob: " + state); - - if (isNew) { - Long lnonce = Long.valueOf(nonce); - _activeTests.put(lnonce, state); - new RemoveTest(lnonce, MAX_CHARLIE_LIFETIME); - } - - state.setLastSendTime(now); - UDPPacket packet = _packetBuilder.buildPeerTestToBob(bobIP, from.getPort(), aliceIP, alicePort, - aliceIntroKey, nonce, - state.getBobCipherKey(), state.getBobMACKey()); - _transport.send(packet); - bob.setLastSendTime(now); - - packet = _packetBuilder.buildPeerTestToAlice(aliceIP, alicePort, aliceIntroKey, - _transport.getIntroKey(), nonce); - _transport.send(packet); - } catch (UnknownHostException uhe) { - if (_log.shouldLog(Log.WARN)) - _log.warn("Unable to build the aliceIP from " + from + ", ip size: " + sz + " ip val: " + Base64.encode(aliceIPData), uhe); - _context.statManager().addRateData("udp.testBadIP", 1); - } - } - - /** - * The PeerTest message came from the peer referenced in the message (or there wasn't - * any info in the message), plus we are not acting as Charlie (so we've got to be Bob). - * - * SSU 1 only. - * - * testInfo IP/port ignored - * - * @param alice non-null - * @param state null if new - */ - private void receiveFromAliceAsBob(RemoteHostId from, PeerState alice, UDPPacketReader.PeerTestReader testInfo, - long nonce, PeerTestState state) { - // we are Bob, so pick a (potentially) Charlie and send Charlie Alice's info - PeerState charlie; - RouterInfo charlieInfo = null; - int sz = from.getIP().length; - boolean isIPv6 = sz == 16; - if (state == null) { // pick a new charlie - //if (from.getIP().length != 4) { - // if (_log.shouldLog(Log.WARN)) - // _log.warn("PeerTest over IPv6 from Alice as Bob? " + from); - // return; - //} - charlie = _transport.pickTestPeer(CHARLIE, alice.getVersion(), isIPv6, from); - } else { - charlie = _transport.getPeerState(new RemoteHostId(state.getCharlieIP().getAddress(), state.getCharliePort())); - } - if (charlie == null) { - if (_log.shouldLog(Log.WARN)) - _log.warn("Unable to pick a charlie (no peer), IPv6? " + isIPv6); - return; - } - charlieInfo = _context.netDb().lookupRouterInfoLocally(charlie.getRemotePeer()); - if (charlieInfo == null) { - if (_log.shouldLog(Log.WARN)) - _log.warn("Unable to pick a charlie (no RI), IPv6? " + isIPv6); - return; - } - - // TODO should only do most of this if isNew - InetAddress aliceIP = null; - SessionKey aliceIntroKey = null; - try { - aliceIP = InetAddress.getByAddress(from.getIP()); - aliceIntroKey = new SessionKey(new byte[SessionKey.KEYSIZE_BYTES]); - testInfo.readIntroKey(aliceIntroKey.getData(), 0); - - RouterAddress raddr = _transport.getTargetAddress(charlieInfo); - if (raddr == null) { - if (_log.shouldLog(Log.WARN)) - _log.warn("Unable to pick a charlie (no addr), IPv6? " + isIPv6); - return; - } - UDPAddress addr = new UDPAddress(raddr); - byte[] ikey = addr.getIntroKey(); - if (ikey == null) { - if (_log.shouldLog(Log.WARN)) - _log.warn("Unable to pick a charlie (no ikey), IPv6? " + isIPv6); - return; - } - SessionKey charlieIntroKey = new SessionKey(ikey); - - //UDPPacket packet = _packetBuilder.buildPeerTestToAlice(aliceIP, from.getPort(), aliceIntroKey, charlieIntroKey, nonce); - //_transport.send(packet); - - long now = _context.clock().now(); - boolean isNew = false; - if (state == null) { - isNew = true; - state = new PeerTestState(BOB, null, isIPv6, nonce, now); - } else { - if (state.getReceiveAliceTime() > now - (RESEND_TIMEOUT / 2)) { - if (_log.shouldDebug()) - _log.debug("Too soon, not retransmitting: " + state); - return; - } - } - state.setAlice(aliceIP, from.getPort(), null); - state.setAliceIntroKey(aliceIntroKey); - state.setAliceKeys(alice.getCurrentCipherKey(), alice.getCurrentMACKey()); - state.setCharlie(charlie.getRemoteIPAddress(), charlie.getRemotePort(), null); - state.setCharlieIntroKey(charlieIntroKey); - state.setReceiveAliceTime(now); - - if (state.incrementPacketsRelayed() > MAX_RELAYED_PER_TEST_BOB) { - if (_log.shouldDebug()) - _log.debug("Too many, not retransmitting: " + state); - return; - } - - if (isNew) { - Long lnonce = Long.valueOf(nonce); - _activeTests.put(lnonce, state); - new RemoveTest(lnonce, MAX_BOB_LIFETIME); - } - - state.setLastSendTime(now); - UDPPacket packet = _packetBuilder.buildPeerTestToCharlie(aliceIP, from.getPort(), aliceIntroKey, nonce, - charlie.getRemoteIPAddress(), - charlie.getRemotePort(), - charlie.getCurrentCipherKey(), - charlie.getCurrentMACKey()); - - if (_log.shouldLog(Log.DEBUG)) - _log.debug("Receive from Alice: " + state); - - _transport.send(packet); - } catch (UnknownHostException uhe) { - if (_log.shouldLog(Log.WARN)) - _log.warn("Unable to build the aliceIP from " + from, uhe); - _context.statManager().addRateData("udp.testBadIP", 1); - } - } - - /** - * The PeerTest message came from one of the Charlies picked for an existing test, so send Alice the - * packet verifying participation. - * - * testInfo IP/port ignored - * - * @param fromPeer non-null if an associated session was found, otherwise null - * @param inSession true if authenticated in-session - * @param state non-null - */ - private void receiveFromCharlieAsBob(RemoteHostId from, PeerState charlie, boolean inSession, PeerTestState state) { - if (!inSession || charlie == null) { - if (_log.shouldWarn()) - _log.warn("Received from charlie (" + from + ") as bob w/o session"); - return; - } - - long now = _context.clock().now(); - if (state.getReceiveCharlieTime() > now - (RESEND_TIMEOUT / 2)) { - if (_log.shouldDebug()) - _log.debug("Too soon, not retransmitting: " + state); - return; - } - - if (state.incrementPacketsRelayed() > MAX_RELAYED_PER_TEST_BOB) { - if (_log.shouldDebug()) - _log.debug("Too many, not retransmitting: " + state); - return; - } - state.setReceiveCharlieTime(now); - state.setLastSendTime(now); - - // In-session as of 0.9.52 - UDPPacket packet = _packetBuilder.buildPeerTestToAlice(state.getAliceIP(), state.getAlicePort(), - state.getAliceCipherKey(), state.getAliceMACKey(), - state.getCharlieIntroKey(), state.getNonce()); - - if (_log.shouldLog(Log.DEBUG)) - _log.debug("Receive from Charlie, sending Alice back the OK: " + state); - - _transport.send(packet); - } - - /** - * We are Charlie, receiving message 6, so send Alice her PeerTest message 7. - * We send it to wherever message 6 came from, which may be different than - * where we sent message 5. - * - * SSU 1 only. - * - * testInfo IP/port ignored - * @param state non-null - */ - private void receiveFromAliceAsCharlie(RemoteHostId from, UDPPacketReader.PeerTestReader testInfo, - long nonce, PeerTestState state) { - long now = _context.clock().now(); - if (state.getReceiveAliceTime() > now - (RESEND_TIMEOUT / 2)) { - if (_log.shouldDebug()) - _log.debug("Too soon, not retransmitting: " + state); - return; - } - - if (state.incrementPacketsRelayed() > MAX_RELAYED_PER_TEST_CHARLIE) { - if (_log.shouldDebug()) - _log.debug("Too many, not retransmitting: " + state); - return; - } - state.setReceiveAliceTime(now); - state.setLastSendTime(now); - - try { - InetAddress aliceIP = InetAddress.getByAddress(from.getIP()); - SessionKey aliceIntroKey = new SessionKey(new byte[SessionKey.KEYSIZE_BYTES]); - testInfo.readIntroKey(aliceIntroKey.getData(), 0); - UDPPacket packet = _packetBuilder.buildPeerTestToAlice(aliceIP, from.getPort(), aliceIntroKey, _transport.getIntroKey(), nonce); - - if (_log.shouldLog(Log.DEBUG)) - _log.debug("Receive from Alice: " + state); - - _transport.send(packet); - } catch (UnknownHostException uhe) { - if (_log.shouldLog(Log.WARN)) - _log.warn("Unable to build the aliceIP from " + from, uhe); - _context.statManager().addRateData("udp.testBadIP", 1); - } - } - /** * SSU 1 Bob/Charlie and SSU 2 Bob * forget about charlie's nonce after a short while.