forked from I2P_Developers/i2p.i2p
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
This commit is contained in:
@@ -1,3 +1,6 @@
|
||||
2022-03-13 zzz
|
||||
* SSU2: Fixes
|
||||
|
||||
2022-03-12 zzz
|
||||
* SSU2: Fixes
|
||||
* Tunnels: Reduce build reply timeout
|
||||
|
||||
@@ -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 = "";
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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<Long, PeerState> _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<Long, PeerState>(MAX_OUTBOUND);
|
||||
_inbound = new ConcurrentHashMap<Long, PeerState>(MAX_INBOUND);
|
||||
_recentHolePunches = new HashSet<InetAddress>(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user