From 08e95655c17c77d49fa8cabb7ff81796bc9985f1 Mon Sep 17 00:00:00 2001 From: zzz <zzz@i2pmail.org> Date: Wed, 22 Jun 2022 11:00:56 -0400 Subject: [PATCH] SSU2: More MTU checks Add code for bob rejecting alice peer test address Don't allow MTU to exceed his MTU Don't use a token about to expire Send token with termination message Add internal type to termination message log tweaks --- .../transport/udp/EstablishmentManager.java | 13 ++++++++++++ .../transport/udp/InboundEstablishState2.java | 10 ++++++--- .../transport/udp/IntroductionManager.java | 3 ++- .../udp/OutboundEstablishState2.java | 8 +++++-- .../router/transport/udp/PacketBuilder2.java | 21 ++++++++++++++++--- .../i2p/router/transport/udp/PeerState.java | 3 ++- .../i2p/router/transport/udp/PeerState2.java | 12 ++++++----- .../i2p/router/transport/udp/SSU2Util.java | 1 + 8 files changed, 56 insertions(+), 15 deletions(-) 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 a51a49c239..91758a8ec5 100644 --- a/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java +++ b/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java @@ -415,6 +415,17 @@ class EstablishmentManager { version = 1; } } + if (version == 2) { + int mtu = addr.getMTU(); + if (mtu > 0 && mtu < PeerState2.MIN_MTU) { + if (ra.getTransportStyle().equals("SSU2")) { + _transport.markUnreachable(toHash); + _transport.failed(msg, "MTU too small"); + return; + } + version = 1; + } + } if (version == 1) { keyBytes = addr.getIntroKey(); } else { @@ -2435,6 +2446,8 @@ class EstablishmentManager { * @since 0.9.54 */ public void addOutboundToken(RemoteHostId peer, long token, long expires) { + // so we don't use a token about to expire + expires -= 2*60*1000; if (expires < _context.clock().now()) return; Token tok = new Token(token, expires); 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 ee0c312c24..48b1b1f0dc 100644 --- a/router/java/src/net/i2p/router/transport/udp/InboundEstablishState2.java +++ b/router/java/src/net/i2p/router/transport/udp/InboundEstablishState2.java @@ -202,8 +202,8 @@ class InboundEstablishState2 extends InboundEstablishState implements SSU2Payloa } public void gotRI(RouterInfo ri, boolean isHandshake, boolean flood) throws DataFormatException { - if (_log.shouldDebug()) - _log.debug("Got RI block: " + ri); + //if (_log.shouldDebug()) + // _log.debug("Got RI block: " + ri); if (isHandshake) throw new DataFormatException("RI in Sess Req"); if (_receivedUnconfirmedIdentity != null) @@ -275,7 +275,9 @@ class InboundEstablishState2 extends InboundEstablishState implements SSU2Payloa mtu = PeerState2.DEFAULT_SSU_IPV4_MTU; } } else { - // TODO if too small, give up now + // if too small, give up now + if (mtu < PeerState2.MIN_MTU) + throw new DataFormatException("MTU too small " + mtu); if (ra.getTransportStyle().equals(UDPTransport.STYLE2)) { mtu = Math.min(Math.max(mtu, PeerState2.MIN_MTU), PeerState2.MAX_MTU); } else { @@ -369,6 +371,8 @@ class InboundEstablishState2 extends InboundEstablishState implements SSU2Payloa } public void gotToken(long token, long expires) { + if (_log.shouldDebug()) + _log.debug("Got token: " + token + " expires " + DataHelper.formatTime(expires) + " on " + this); if (_receivedConfirmedIdentity == null) throw new IllegalStateException("RI must be first"); _transport.getEstablisher().addOutboundToken(_remoteHostId, token, expires); 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 082b90b398..69b6856266 100644 --- a/router/java/src/net/i2p/router/transport/udp/IntroductionManager.java +++ b/router/java/src/net/i2p/router/transport/udp/IntroductionManager.java @@ -1059,7 +1059,8 @@ class IntroductionManager { } UDPPacket packet = _builder2.buildRelayResponse(data, bob); if (_log.shouldInfo()) - _log.info("Send relay response " + rcode + " as charlie " + " nonce " + nonce + " to bob " + bob); + _log.info("Send relay response " + rcode + " as charlie " + " nonce " + nonce + " to bob " + bob + + " for alice " + Addresses.toString(testIP, testPort) + ' ' + aliceRI); _transport.send(packet); if (rcode == SSU2Util.RELAY_ACCEPT) { // send hole punch with the same data we sent to Bob diff --git a/router/java/src/net/i2p/router/transport/udp/OutboundEstablishState2.java b/router/java/src/net/i2p/router/transport/udp/OutboundEstablishState2.java index 5c644cd683..3381b2c80d 100644 --- a/router/java/src/net/i2p/router/transport/udp/OutboundEstablishState2.java +++ b/router/java/src/net/i2p/router/transport/udp/OutboundEstablishState2.java @@ -155,9 +155,11 @@ class OutboundEstablishState2 extends OutboundEstablishState implements SSU2Payl mtu = PeerState2.DEFAULT_SSU_IPV4_MTU; } } else { - // TODO if too small, give up now + // If too small, give up now + if (mtu < PeerState2.MIN_MTU) + throw new IllegalArgumentException("MTU " + mtu + " too small for " + remotePeer.getHash()); if (ra.getTransportStyle().equals(UDPTransport.STYLE2)) { - mtu = Math.min(Math.max(mtu, PeerState2.MIN_MTU), PeerState2.MAX_MTU); + mtu = Math.min(mtu, PeerState2.MAX_MTU); } else { if (_bobIP != null && _bobIP.length == 16) mtu = Math.min(Math.max(mtu, PeerState2.MIN_SSU_IPV6_MTU), PeerState2.MAX_SSU_IPV6_MTU); @@ -321,6 +323,8 @@ class OutboundEstablishState2 extends OutboundEstablishState implements SSU2Payl } public void gotToken(long token, long expires) { + if (_log.shouldDebug()) + _log.debug("Got token: " + token + " expires " + DataHelper.formatTime(expires) + " on " + this); _transport.getEstablisher().addOutboundToken(_remoteHostId, token, expires); } 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 d9eaedf3ea..7c20f84ab4 100644 --- a/router/java/src/net/i2p/router/transport/udp/PacketBuilder2.java +++ b/router/java/src/net/i2p/router/transport/udp/PacketBuilder2.java @@ -60,6 +60,7 @@ class PacketBuilder2 { static final int TYPE_CONF = 71; static final int TYPE_SREQ = 72; static final int TYPE_CREAT = 73; + static final int TYPE_DESTROY = 74; /** IPv4 only */ public static final int IP_HEADER_SIZE = PacketBuilder.IP_HEADER_SIZE; @@ -100,6 +101,7 @@ class PacketBuilder2 { /** * Will a packet to 'peer' that already has 'numFragments' fragments * totalling 'curDataSize' bytes fit another fragment? + * This includes the 3 byte block overhead, but NOT the 5 byte followon fragment overhead. * * This doesn't leave anything for acks or anything else. * @@ -279,7 +281,7 @@ class PacketBuilder2 { if (_log.shouldWarn()) { int maxMTU = PeerState2.MAX_MTU; off += MAC_LEN; - if (off + ipHeaderSize > maxMTU) { + if (off + ipHeaderSize > currentMTU) { _log.warn("Size is " + off + " for " + packet + " data size " + dataSize + " pkt size " + (off + ipHeaderSize) + @@ -340,11 +342,24 @@ class PacketBuilder2 { /** * Build a data packet with a termination block. - * This will also include acks and padding. + * This will also include acks, a new token block, and padding. */ public UDPPacket buildSessionDestroyPacket(int reason, PeerState2 peer) { + if (_log.shouldWarn()) + _log.warn("Sending termination " + reason + " to : " + peer); + List<Block> blocks = new ArrayList<Block>(2); + if (peer.getKeyEstablishedTime() - _context.clock().now() > EstablishmentManager.IB_TOKEN_EXPIRATION / 2 && + !_context.router().gracefulShutdownInProgress()) { + // update token + EstablishmentManager.Token token = _transport.getEstablisher().getInboundToken(peer.getRemoteHostId()); + Block block = new SSU2Payload.NewTokenBlock(token.token, token.expires); + blocks.add(block); + } Block block = new SSU2Payload.TerminationBlock(reason, peer.getReceivedMessages().getHighestSet()); - return buildPacket(Collections.emptyList(), Collections.singletonList(block), peer); + blocks.add(block); + UDPPacket packet = buildPacket(Collections.emptyList(), blocks, peer); + packet.setMessageType(TYPE_DESTROY); + return packet; } /** diff --git a/router/java/src/net/i2p/router/transport/udp/PeerState.java b/router/java/src/net/i2p/router/transport/udp/PeerState.java index e2636ef426..a3bf19991c 100644 --- a/router/java/src/net/i2p/router/transport/udp/PeerState.java +++ b/router/java/src/net/i2p/router/transport/udp/PeerState.java @@ -1267,7 +1267,8 @@ public class PeerState { synchronized void setHisMTU(int mtu) { if (mtu <= _minMTU || mtu >= _largeMTU) return; - _largeMTU = mtu; + if (mtu < _largeMTU) + _largeMTU = mtu; if (mtu < _mtu) _mtu = mtu; } diff --git a/router/java/src/net/i2p/router/transport/udp/PeerState2.java b/router/java/src/net/i2p/router/transport/udp/PeerState2.java index 29ee6305ed..097eb1a0ab 100644 --- a/router/java/src/net/i2p/router/transport/udp/PeerState2.java +++ b/router/java/src/net/i2p/router/transport/udp/PeerState2.java @@ -563,14 +563,16 @@ public class PeerState2 extends PeerState implements SSU2Payload.PayloadCallback public void gotACK(long ackThru, int acks, byte[] ranges) { int hc = (((int) ackThru) << 8) ^ (acks << 24) ^ DataHelper.hashCode(ranges); if (_lastAckHashCode.getAndSet(hc) == hc) { - if (_log.shouldDebug()) - _log.debug("Got dup ACK block: " + SSU2Bitfield.toString(ackThru, acks, ranges, (ranges != null ? ranges.length / 2 : 0))); + //if (_log.shouldDebug()) + // _log.debug("Got dup ACK block: " + SSU2Bitfield.toString(ackThru, acks, ranges, (ranges != null ? ranges.length / 2 : 0))); return; } try { SSU2Bitfield ackbf = SSU2Bitfield.fromACKBlock(ackThru, acks, ranges, (ranges != null ? ranges.length / 2 : 0)); if (_log.shouldDebug()) - _log.debug("Got new ACK block: " + SSU2Bitfield.toString(ackThru, acks, ranges, (ranges != null ? ranges.length / 2 : 0))); + _log.debug("Got new ACK block from " + + _remotePeer.toBase64().substring(0,6) + ' ' + + SSU2Bitfield.toString(ackThru, acks, ranges, (ranges != null ? ranges.length / 2 : 0))); // calls bitSet() below ackbf.forEachAndNot(_ackedMessages, this); } catch (Exception e) { @@ -583,8 +585,8 @@ public class PeerState2 extends PeerState implements SSU2Payload.PayloadCallback } public void gotTermination(int reason, long count) { - if (_log.shouldDebug()) - _log.debug("Got TERMINATION block, reason: " + reason + " count: " + count + " on " + this); + if (_log.shouldInfo()) + _log.info("Got TERMINATION block, reason: " + reason + " count: " + count + " on " + this); _transport.getEstablisher().receiveSessionDestroy(_remoteHostId, this); } diff --git a/router/java/src/net/i2p/router/transport/udp/SSU2Util.java b/router/java/src/net/i2p/router/transport/udp/SSU2Util.java index 46418292a6..63fd04e82d 100644 --- a/router/java/src/net/i2p/router/transport/udp/SSU2Util.java +++ b/router/java/src/net/i2p/router/transport/udp/SSU2Util.java @@ -125,6 +125,7 @@ final class SSU2Util { public static final int TEST_REJECT_BOB_NO_CHARLIE = 2; public static final int TEST_REJECT_BOB_LIMIT = 3; public static final int TEST_REJECT_BOB_SIGFAIL = 4; + public static final int TEST_REJECT_BOB_ADDRESS = 5; public static final int TEST_REJECT_CHARLIE_UNSPEC = 64; public static final int TEST_REJECT_CHARLIE_ADDRESS = 65; public static final int TEST_REJECT_CHARLIE_LIMIT = 66; -- GitLab