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:
zzz
2022-03-13 07:33:36 -04:00
parent ca0d9f5a26
commit 2f63762c80
13 changed files with 56 additions and 27 deletions

View File

@@ -1,3 +1,6 @@
2022-03-13 zzz
* SSU2: Fixes
2022-03-12 zzz
* SSU2: Fixes
* Tunnels: Reduce build reply timeout

View File

@@ -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 = "";

View File

@@ -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);
}

View File

@@ -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))

View File

@@ -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);
}
}
}

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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; }

View File

@@ -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();
}

View File

@@ -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;

View File

@@ -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.