From 014d39c097b51ad8a2f621428263eb48ffcb861b Mon Sep 17 00:00:00 2001 From: zzz <zzz@mail.i2p> Date: Wed, 10 Jan 2024 17:04:32 +0000 Subject: [PATCH] SSU2: Delay sending relay tag --- .../transport/udp/EstablishmentManager.java | 22 +++++++---- .../transport/udp/InboundEstablishState2.java | 38 ++++++++++++++++++- .../i2p/router/transport/udp/PeerState2.java | 35 ++++++++++++++--- 3 files changed, 81 insertions(+), 14 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 f65660b498..9bb132e4c9 100644 --- a/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java +++ b/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java @@ -842,14 +842,18 @@ class EstablishmentManager { else _log.debug("Receive DUP session/token request from: " + state); } + + // Wait until we have RI + // sentRelayTag remains 0 and will not be sent in SessionConfirmed + // See InboundEstablishState2 // call for both Session and Token request, why not - if (state.isIntroductionRequested() && - state.getSentRelayTag() == 0 && // only set once - state.getSentPort() >= 1024 && - _transport.canIntroduce(state.getSentIP().length == 16)) { - long tag = 1 + _context.random().nextLong(MAX_TAG_VALUE); - state.setSentRelayTag(tag); - } + //if (state.isIntroductionRequested() && + // state.getSentRelayTag() == 0 && // only set once + // state.getSentPort() >= 1024 && + // _transport.canIntroduce(state.getSentIP().length == 16)) { + // long tag = 1 + _context.random().nextLong(MAX_TAG_VALUE); + // state.setSentRelayTag(tag); + //} notifyActivity(); } @@ -1175,11 +1179,13 @@ class EstablishmentManager { peer = new PeerState(_context, _transport, state.getSentIP(), state.getSentPort(), remote.calculateHash(), true, state.getRTT(), state.getCipherKey(), state.getMACKey()); + peer.setWeRelayToThemAs(state.getSentRelayTag()); } else { InboundEstablishState2 state2 = (InboundEstablishState2) state; peer = state2.getPeerState(); + // now handled in IES2.createPeerState() + //peer.setWeRelayToThemAs(state.getSentRelayTag()); } - peer.setWeRelayToThemAs(state.getSentRelayTag()); if (version == 1) { // Lookup the peer's MTU from the netdb, since it isn't included in the protocol setup (yet) 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 16ef065567..e102c62c6e 100644 --- a/router/java/src/net/i2p/router/transport/udp/InboundEstablishState2.java +++ b/router/java/src/net/i2p/router/transport/udp/InboundEstablishState2.java @@ -25,12 +25,14 @@ import net.i2p.data.SessionKey; import net.i2p.data.i2np.I2NPMessage; import net.i2p.data.router.RouterAddress; import net.i2p.data.router.RouterInfo; +import net.i2p.router.Router; import net.i2p.router.RouterContext; import net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade; import net.i2p.router.transport.TransportImpl; import static net.i2p.router.transport.udp.SSU2Util.*; import net.i2p.util.Addresses; import net.i2p.util.Log; +import net.i2p.util.VersionComparator; /** * Data for a new connection being established, where the remote peer has @@ -63,6 +65,8 @@ class InboundEstablishState2 extends InboundEstablishState implements SSU2Payloa // testing private static final boolean ENFORCE_TOKEN = true; private static final long MAX_SKEW = 2*60*1000L; + // SSU2 fixes (2.1.0) + private static final String MIN_RELAY_VERSION = "0.9.57"; /** @@ -398,6 +402,32 @@ class InboundEstablishState2 extends InboundEstablishState implements SSU2Payloa } _receivedConfirmedIdentity = _receivedUnconfirmedIdentity; + // deferred relay tag request handling, now that we have the RI + // formerly in EstablishmentManager.receiveSessionOrTokenReques() + if (_introductionRequested) { + if (getSentPort() < 1024 || + !_transport.canIntroduce(isIPv6)) { + _introductionRequested = false; + } else if (VersionComparator.comp(ri.getVersion(), MIN_RELAY_VERSION) < 0) { + _introductionRequested = false; + String caps = ri.getCapabilities(); + if (_log.shouldWarn()) + _log.warn("Not offering to relay to router version " + ri.getVersion() + " caps " + caps + ": " + this); + } else { + String caps = ri.getCapabilities(); + // may be requesting relay for ipv4/6 if reachable on the other + // or may be starting up and not know if reachable or not + if (caps.indexOf(Router.CAPABILITY_REACHABLE) < 0 || + _context.random().nextInt(4) == 0) { + // leave it set to true; createPeerState() will copy to PS2, + // who will send the relay tag with ACK 0 + } else { + _introductionRequested = false; + if (_log.shouldWarn()) + _log.warn("Not offering to relay to router version " + ri.getVersion() + " caps " + caps + ": " + this); + } + } + } createPeerState(); //_sendHeaderEncryptKey2 calculated below } @@ -419,7 +449,7 @@ class InboundEstablishState2 extends InboundEstablishState implements SSU2Payloa public void gotRelayTagRequest() { if (_log.shouldDebug()) - _log.debug("Got relay tag request"); + _log.debug("Got relay tag request on " + this); _introductionRequested = true; } @@ -877,6 +907,12 @@ class InboundEstablishState2 extends InboundEstablishState implements SSU2Payloa RouterAddress ra = _transport.getCurrentExternalAddress(isIPv6); if (ra != null) _pstate.setOurAddress(ra.getIP(), ra.getPort()); + if (_introductionRequested) { + long tag = 1 + _context.random().nextLong(EstablishmentManager.MAX_TAG_VALUE); + setSentRelayTag(tag); + _pstate.setWeRelayToThemAs(tag); + } + _pstate.sendAck0(); } /** 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 608c147f3f..ef46abe2ce 100644 --- a/router/java/src/net/i2p/router/transport/udp/PeerState2.java +++ b/router/java/src/net/i2p/router/transport/udp/PeerState2.java @@ -115,6 +115,8 @@ public class PeerState2 extends PeerState implements SSU2Payload.PayloadCallback /** + * If inbound, caller MUST immediately call setWeRelayToThemAs() (if nonzero) and sendAck0(). + * * @param rtt from the EstablishState, or 0 if not available */ public PeerState2(RouterContext ctx, UDPTransport transport, @@ -135,12 +137,9 @@ public class PeerState2 extends PeerState implements SSU2Payload.PayloadCallback _sentMessages = new ConcurrentHashMap<Long, List<PacketBuilder.Fragment>>(32); _sentMessagesLastExpired = _keyEstablishedTime; if (isInbound) { - // Send immediate ack of Session Confirmed + // Prep for immediate ack of Session Confirmed _receivedMessages.set(0); - try { - UDPPacket ack = transport.getBuilder2().buildACK(this); - transport.send(ack); - } catch (IOException ioe) {} + // ACK 0 now sent in sendAck0() below } else { // For outbound, SessionConfirmed is packet 0 _packetNumber.set(1); @@ -148,6 +147,32 @@ public class PeerState2 extends PeerState implements SSU2Payload.PayloadCallback _ackTimer = new ACKTimer(); } + /** + * Send immediate ACK 0 of Session Confirmed. Inbound only. + * Bundle relay tag if requested, see InboundEstablishState2. + * + * @since 0.9.62 + */ + void sendAck0() { + if (!_isInbound) + return; + long tag = getWeRelayToThemAs(); + try { + UDPPacket pkt; + if (tag > 0) { + SSU2Payload.Block block = new SSU2Payload.RelayTagBlock(tag); + pkt = _transport.getBuilder2().buildPacket(Collections.<Fragment>emptyList(), + Collections.singletonList(block), + this); + if (_log.shouldInfo()) + _log.info("Sending ack 0 with tag " + tag + " on " + this); + } else { + pkt = _transport.getBuilder2().buildACK(this); + } + _transport.send(pkt); + } catch (IOException ioe) {} + } + // SSU 1 overrides @Override -- GitLab