From 2f63762c80ca26be78d72e03e92d4e8c34bb90cb Mon Sep 17 00:00:00 2001 From: zzz Date: Sun, 13 Mar 2022 07:33:36 -0400 Subject: [PATCH] SSU2: Fixes part 9 Fix length calculation to see if new token block will fit in session confirmed Extend timeout after sending retry Fix retx timer for sess req after sending token req Remove dup call to confirmedPacketsSent() Cancel ack timer when sending acks Include intro key in firewalled addresses too Use SSU2 version of ping packet for SSU2 peers Reduce max padding Log tweaks --- history.txt | 3 +++ .../src/net/i2p/router/RouterVersion.java | 2 +- .../transport/udp/EstablishmentManager.java | 19 ++++++++++--------- .../transport/udp/InboundEstablishState2.java | 8 ++++++-- .../transport/udp/IntroductionManager.java | 9 ++++++++- .../transport/udp/OutboundEstablishState.java | 2 +- .../udp/OutboundEstablishState2.java | 12 +++++++++--- .../router/transport/udp/PacketBuilder2.java | 2 +- .../i2p/router/transport/udp/PeerState.java | 3 ++- .../i2p/router/transport/udp/PeerState2.java | 4 ++++ .../router/transport/udp/SSU2Bitfield.java | 2 ++ .../i2p/router/transport/udp/SSU2Util.java | 2 +- .../router/transport/udp/UDPTransport.java | 15 ++++++++------- 13 files changed, 56 insertions(+), 27 deletions(-) diff --git a/history.txt b/history.txt index f02cd0804..83ae581e0 100644 --- a/history.txt +++ b/history.txt @@ -1,3 +1,6 @@ +2022-03-13 zzz + * SSU2: Fixes + 2022-03-12 zzz * SSU2: Fixes * Tunnels: Reduce build reply timeout diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index 707cdcd34..6a9511fad 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 = "Git"; public final static String VERSION = CoreVersion.VERSION; - public final static long BUILD = 7; + public final static long BUILD = 8; /** 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 f4bc75172..72e249ba4 100644 --- a/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java +++ b/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java @@ -518,8 +518,8 @@ class EstablishmentManager { } if (_context.blocklist().isBlocklisted(from.getIP())) { - if (_log.shouldLog(Log.WARN)) - _log.warn("Receive session request from blocklisted IP: " + from); + if (_log.shouldInfo()) + _log.info("Receive session request from blocklisted IP: " + from); _context.statManager().addRateData("udp.establishBadIP", 1); return; // drop the packet } @@ -594,8 +594,8 @@ class EstablishmentManager { return; // drop the packet } if (_context.blocklist().isBlocklisted(from.getIP())) { - if (_log.shouldWarn()) - _log.warn("Receive session request from blocklisted IP: " + from); + if (_log.shouldInfo()) + _log.info("Receive session request from blocklisted IP: " + from); _context.statManager().addRateData("udp.establishBadIP", 1); return; // drop the packet } @@ -679,8 +679,8 @@ class EstablishmentManager { if (_log.shouldLog(Log.DEBUG)) _log.debug("Receive session confirmed from: " + state); } else { - if (_log.shouldLog(Log.WARN)) - _log.warn("Receive (DUP?) session confirmed from: " + from); + if (_log.shouldInfo()) + _log.info("Receive (DUP?) session confirmed from: " + from); } } @@ -725,8 +725,8 @@ class EstablishmentManager { if (_log.shouldLog(Log.DEBUG)) _log.debug("Receive session created from: " + state); } else { - if (_log.shouldLog(Log.WARN)) - _log.warn("Receive (DUP?) session created from: " + from); + if (_log.shouldInfo()) + _log.info("Receive (DUP?) session created from: " + from); } } @@ -1427,7 +1427,8 @@ class EstablishmentManager { } else { // save for retx OutboundEstablishState2 state2 = (OutboundEstablishState2) state; - state2.confirmedPacketsSent(packets); + // PacketBuilder2 told the state + //state2.confirmedPacketsSent(packets); // we are done, go right to ps2 handleCompletelyEstablished(state2); } 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 ead02c0ae..b6d8b83b7 100644 --- a/router/java/src/net/i2p/router/transport/udp/InboundEstablishState2.java +++ b/router/java/src/net/i2p/router/transport/udp/InboundEstablishState2.java @@ -91,6 +91,8 @@ class InboundEstablishState2 extends InboundEstablishState implements SSU2Payloa int type = data[off + TYPE_OFFSET] & 0xff; long token = DataHelper.fromLong8(data, off + TOKEN_OFFSET); if (type == TOKEN_REQUEST_FLAG_BYTE) { + if (_log.shouldInfo()) + _log.info("Got token request from: " + _aliceSocketAddress); _currentState = InboundState.IB_STATE_TOKEN_REQUEST_RECEIVED; // decrypt in-place ChaChaPolyCipherState chacha = new ChaChaPolyCipherState(); @@ -430,9 +432,9 @@ class InboundEstablishState2 extends InboundEstablishState implements SSU2Payloa throw new IllegalStateException("Bad state for Retry Sent: " + _currentState); _currentState = InboundState.IB_STATE_RETRY_SENT; _lastSend = _context.clock().now(); - // Won't really be transmitted, they have 3 sec to respond or + // Won't really be retransmitted, they have 9 sec to respond or // EstablishmentManager.handleInbound() will fail the connection - _nextSend = _lastSend + RETRANSMIT_DELAY; + _nextSend = _lastSend + (3 * RETRANSMIT_DELAY); } /** @@ -441,6 +443,8 @@ class InboundEstablishState2 extends InboundEstablishState implements SSU2Payloa public synchronized void receiveSessionRequestAfterRetry(UDPPacket packet) throws GeneralSecurityException { if (_currentState != InboundState.IB_STATE_RETRY_SENT) throw new GeneralSecurityException("Bad state for Session Request after Retry: " + _currentState); + if (_log.shouldInfo()) + _log.info("Got session request after retry from: " + _aliceSocketAddress); DatagramPacket pkt = packet.getPacket(); SocketAddress from = pkt.getSocketAddress(); if (!from.equals(_aliceSocketAddress)) 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 b513a4e61..d31c4ae2c 100644 --- a/router/java/src/net/i2p/router/transport/udp/IntroductionManager.java +++ b/router/java/src/net/i2p/router/transport/udp/IntroductionManager.java @@ -76,6 +76,7 @@ class IntroductionManager { private final Log _log; private final UDPTransport _transport; private final PacketBuilder _builder; + private final PacketBuilder2 _builder2; /** map of relay tag to PeerState that should receive the introduction */ private final Map _outbound; /** map of relay tag to PeerState who have given us introduction tags */ @@ -107,6 +108,7 @@ class IntroductionManager { _log = ctx.logManager().getLog(IntroductionManager.class); _transport = transport; _builder = transport.getBuilder(); + _builder2 = transport.getBuilder2(); _outbound = new ConcurrentHashMap(MAX_OUTBOUND); _inbound = new ConcurrentHashMap(MAX_INBOUND); _recentHolePunches = new HashSet(16); @@ -396,7 +398,12 @@ class IntroductionManager { if (_log.shouldLog(Log.INFO)) _log.info("Pinging introducer: " + cur); cur.setLastSendTime(now); - _transport.send(_builder.buildPing(cur)); + UDPPacket ping; + if (cur.getVersion() == 2) + ping = _builder2.buildPing((PeerState2) cur); + else + ping = _builder.buildPing(cur); + _transport.send(ping); } } } 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 fa9d950cd..29ef7b5d6 100644 --- a/router/java/src/net/i2p/router/transport/udp/OutboundEstablishState.java +++ b/router/java/src/net/i2p/router/transport/udp/OutboundEstablishState.java @@ -120,7 +120,7 @@ class OutboundEstablishState { * Transmissions at 0, 3, 9 sec * Previously: 1500 (0, 1.5, 4.5, 10.5) */ - private static final long RETRANSMIT_DELAY = 3000; + protected static final long RETRANSMIT_DELAY = 3000; /** max delay including backoff */ private static final long MAX_DELAY = 15*1000; 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 45d9cfb0c..c2cae324e 100644 --- a/router/java/src/net/i2p/router/transport/udp/OutboundEstablishState2.java +++ b/router/java/src/net/i2p/router/transport/udp/OutboundEstablishState2.java @@ -404,7 +404,7 @@ class OutboundEstablishState2 extends OutboundEstablishState implements SSU2Payl } /** - * note that we just sent the SessionConfirmed packets + * Note that we just sent a token request packet. * and save them for retransmission */ public synchronized void tokenRequestSent(DatagramPacket packet) { @@ -420,6 +420,8 @@ class OutboundEstablishState2 extends OutboundEstablishState implements SSU2Payl * and save it for retransmission */ public synchronized void requestSent(DatagramPacket pkt) { + OutboundState old = _currentState; + requestSent(); if (_sessReqForReTX == null) { // store pkt for retx byte data[] = pkt.getData(); @@ -427,11 +429,15 @@ class OutboundEstablishState2 extends OutboundEstablishState implements SSU2Payl int len = pkt.getLength(); _sessReqForReTX = new byte[len]; System.arraycopy(data, off, _sessReqForReTX, 0, len); + if (_requestSentCount > 1) { + // fixup the counter and delay because we also called + // requestSent() when sending the token request + _requestSentCount = 1; + _nextSend = _lastSend + RETRANSMIT_DELAY; + } } if (_rcvHeaderEncryptKey2 == null) _rcvHeaderEncryptKey2 = SSU2Util.hkdf(_context, _handshakeState.getChainingKey(), "SessCreateHeader"); - OutboundState old = _currentState; - requestSent(); if (old == OutboundState.OB_STATE_RETRY_RECEIVED) _currentState = OutboundState.OB_STATE_REQUEST_SENT_NEW_TOKEN; } 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 a272262c8..df52f4ab6 100644 --- a/router/java/src/net/i2p/router/transport/udp/PacketBuilder2.java +++ b/router/java/src/net/i2p/router/transport/udp/PacketBuilder2.java @@ -953,7 +953,7 @@ class PacketBuilder2 { int len = riblock.getTotalLength(); blocks.add(riblock); // only if room - if (token > 0 && mtu - len >= 15) { + if (token > 0 && mtu - (SHORT_HEADER_SIZE + KEY_LEN + MAC_LEN + len + MAC_LEN) >= 15) { Block block = new SSU2Payload.NewTokenBlock(token, _context.clock().now() + EstablishmentManager.IB_TOKEN_EXPIRATION); len += block.getTotalLength(); blocks.add(block); 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 992060280..096729849 100644 --- a/router/java/src/net/i2p/router/transport/udp/PeerState.java +++ b/router/java/src/net/i2p/router/transport/udp/PeerState.java @@ -1722,10 +1722,11 @@ public class PeerState { } } } + /**** if ( rv == null && _log.shouldLog(Log.DEBUG)) _log.debug("Nothing to send to " + _remotePeer + ", with " + _outboundMessages.size() + " / " + _outboundQueue.size() + " remaining, rtx timer in " + (_retransmitTimer - now)); - + ****/ return rv; } 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 4d9b1a1d5..d7db35b36 100644 --- a/router/java/src/net/i2p/router/transport/udp/PeerState2.java +++ b/router/java/src/net/i2p/router/transport/udp/PeerState2.java @@ -271,6 +271,10 @@ public class PeerState2 extends PeerState implements SSU2Payload.PayloadCallback // logged in PacketBuilder2 //if (_log.shouldDebug()) // _log.debug("Sending acks " + _receivedMessages + " on " + this); + synchronized(this) { + // cancel the ack timer + _wantACKSendSince = 0; + } return _receivedMessages; } SSU2Bitfield getAckedMessages() { return _ackedMessages; } diff --git a/router/java/src/net/i2p/router/transport/udp/SSU2Bitfield.java b/router/java/src/net/i2p/router/transport/udp/SSU2Bitfield.java index 380997c49..bbad4ed27 100644 --- a/router/java/src/net/i2p/router/transport/udp/SSU2Bitfield.java +++ b/router/java/src/net/i2p/router/transport/udp/SSU2Bitfield.java @@ -308,6 +308,7 @@ class SSU2Bitfield { } } } + /**** sb.append(" (RAW: ").append(thru).append(" A:").append(acnt); if (ranges != null) { for (int i = 0; i < rangeCount * 2; i += 2) { @@ -316,6 +317,7 @@ class SSU2Bitfield { } } sb.append(')'); + ****/ return sb.toString(); } 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 ff26d4a8a..d8eacf585 100644 --- a/router/java/src/net/i2p/router/transport/udp/SSU2Util.java +++ b/router/java/src/net/i2p/router/transport/udp/SSU2Util.java @@ -45,7 +45,7 @@ final class SSU2Util { public static final int HEADER_PROT_1_OFFSET = DEST_CONN_ID_OFFSET; public static final int HEADER_PROT_2_OFFSET = PKT_NUM_OFFSET; - public static final int PADDING_MAX = 64; + public static final int PADDING_MAX = 32; /** 40 */ public static final int MIN_DATA_LEN = SHORT_HEADER_SIZE + TOTAL_PROT_SAMPLE_LEN; 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 da1742394..e0f6c30af 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java @@ -944,12 +944,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority * @since 0.9.54 */ private void addSSU2Options(Properties props) { - // only set i if we are not firewalled - if (props.containsKey("host")) { - props.setProperty("i", _ssu2B64StaticIntroKey); - } else { - props.remove("i"); - } + // Unlike in NTCP2, we need the intro key whether firewalled or not + props.setProperty("i", _ssu2B64StaticIntroKey); props.setProperty("s", _ssu2B64StaticPubKey); props.setProperty("v", SSU2_VERSION); } @@ -3544,7 +3540,12 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority // TODO if both sides are firewalled should only one ping // or else session will stay open forever? //peer.setLastSendTime(now); - send(_packetBuilder.buildPing(peer)); + UDPPacket ping; + if (peer.getVersion() == 2) + ping = _packetBuilder2.buildPing((PeerState2) peer); + else + ping = _packetBuilder.buildPing(peer); + send(ping); peer.setLastPingTime(now); // If external port is different, it may be changing the port for every // session, so ping all of them. Otherwise only one.