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 7989169d4..8ce4aa661 100644 --- a/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java +++ b/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java @@ -1246,7 +1246,7 @@ class EstablishmentManager { case IB_STATE_REQUEST_BAD_TOKEN_RECEIVED: if (_log.shouldDebug()) _log.debug("Send retry to: " + state); - pkt = _builder2.buildRetryPacket(state2); + pkt = _builder2.buildRetryPacket(state2, 0); break; default: diff --git a/router/java/src/net/i2p/router/transport/udp/InboundEstablishState2.java b/router/java/src/net/i2p/router/transport/udp/InboundEstablishState2.java index 9d26ab7e6..d075c7b64 100644 --- a/router/java/src/net/i2p/router/transport/udp/InboundEstablishState2.java +++ b/router/java/src/net/i2p/router/transport/udp/InboundEstablishState2.java @@ -166,7 +166,9 @@ class InboundEstablishState2 extends InboundEstablishState implements SSU2Payloa throw new GeneralSecurityException("No DateTime block in Session/Token Request"); _skew = _establishBegin - _timeReceived; if (_skew > MAX_SKEW || _skew < 0 - MAX_SKEW) { - // TODO send retry with termination + // send retry with termination + UDPPacket retry = _transport.getBuilder2().buildRetryPacket(this, SSU2Util.REASON_SKEW); + _transport.send(retry); throw new GeneralSecurityException("Skew exceeded in Session/Token Request: " + _skew); } packetReceived(); @@ -519,8 +521,12 @@ class InboundEstablishState2 extends InboundEstablishState implements SSU2Payloa throw new GeneralSecurityException("No DateTime block in Session Request"); // _nextSend is now(), from packetReceived() _skew = _nextSend - _timeReceived; - if (_skew > MAX_SKEW || _skew < 0 - MAX_SKEW) + if (_skew > MAX_SKEW || _skew < 0 - MAX_SKEW) { + // send another retry with termination + UDPPacket retry = _transport.getBuilder2().buildRetryPacket(this, SSU2Util.REASON_SKEW); + _transport.send(retry); throw new GeneralSecurityException("Skew exceeded in Session Request: " + _skew); + } _sendHeaderEncryptKey2 = SSU2Util.hkdf(_context, _handshakeState.getChainingKey(), "SessCreateHeader"); _currentState = InboundState.IB_STATE_REQUEST_RECEIVED; _rtt = (int) (_nextSend - _lastSend); @@ -531,6 +537,8 @@ class InboundEstablishState2 extends InboundEstablishState implements SSU2Payloa * If the message is fragmented, store the data for reassembly and return, * unless this was the last one. * + * Exceptions thrown from here are fatal. + * * @return the new PeerState2 if are done, may also be retrieved from getPeerState(), * or null if more fragments to go */ diff --git a/router/java/src/net/i2p/router/transport/udp/PacketBuilder2.java b/router/java/src/net/i2p/router/transport/udp/PacketBuilder2.java index dbf1df53b..64a7a5de4 100644 --- a/router/java/src/net/i2p/router/transport/udp/PacketBuilder2.java +++ b/router/java/src/net/i2p/router/transport/udp/PacketBuilder2.java @@ -433,12 +433,14 @@ class PacketBuilder2 { * Build a new Retry packet for the given peer, encrypting it * as necessary. * + * @param terminationCode 0 normally, nonzero to send termination block * @return ready to send packet, or null if there was a problem */ - public UDPPacket buildRetryPacket(InboundEstablishState2 state) { + public UDPPacket buildRetryPacket(InboundEstablishState2 state, int terminationCode) { long n = _context.random().signedNextInt() & 0xFFFFFFFFL; + long token = terminationCode == 0 ? state.getToken() : 0; UDPPacket packet = buildLongPacketHeader(state.getSendConnID(), n, RETRY_FLAG_BYTE, - state.getRcvConnID(), state.getToken()); + state.getRcvConnID(), token); DatagramPacket pkt = packet.getPacket(); byte sentIP[] = state.getSentIP(); @@ -446,7 +448,7 @@ class PacketBuilder2 { int port = state.getSentPort(); encryptRetry(packet, state.getSendHeaderEncryptKey1(), n, state.getSendHeaderEncryptKey1(), state.getSendHeaderEncryptKey2(), - sentIP, port); + sentIP, port, terminationCode); pkt.setSocketAddress(state.getSentAddress()); packet.setMessageType(TYPE_CREAT); packet.setPriority(PRIORITY_HIGH); @@ -945,10 +947,18 @@ class PacketBuilder2 { /** * @param packet containing only 32 byte header + * @param terminationCode 0 normally, nonzero to send termination block */ private void encryptRetry(UDPPacket packet, byte[] chachaKey, long n, - byte[] hdrKey1, byte[] hdrKey2, byte[] ip, int port) { - encryptPeerTest(packet, chachaKey, n, hdrKey1, hdrKey2, ip, port, null); + byte[] hdrKey1, byte[] hdrKey2, byte[] ip, int port, + int terminationCode) { + Block block; + if (terminationCode != 0) { + block = new SSU2Payload.TerminationBlock(terminationCode, 0); + } else { + block = null; + } + encryptPeerTest(packet, chachaKey, n, hdrKey1, hdrKey2, ip, port, block); } /**