forked from I2P_Developers/i2p.i2p
SSU2: Handle handshake messages
Decrypt handshake headers in Packet Handler Pass handshake messages to Establishment Manager SSU 1 and 2: Pass establish state to Establishment Manager so it doesn't have to look it up again Add notes about causes of decrypt failures WIP, untested
This commit is contained in:
@ -483,8 +483,10 @@ class EstablishmentManager {
|
||||
* Got a SessionRequest (initiates an inbound establishment)
|
||||
*
|
||||
* SSU 1 only.
|
||||
*
|
||||
* @param state as looked up in PacketHandler, but probably null unless retransmitted
|
||||
*/
|
||||
void receiveSessionRequest(RemoteHostId from, UDPPacketReader reader) {
|
||||
void receiveSessionRequest(RemoteHostId from, InboundEstablishState state, UDPPacketReader reader) {
|
||||
if (!TransportUtil.isValidPort(from.getPort()) || !_transport.isValid(from.getIP())) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Receive session request from invalid: " + from);
|
||||
@ -493,7 +495,8 @@ class EstablishmentManager {
|
||||
|
||||
boolean isNew = false;
|
||||
|
||||
InboundEstablishState state = _inboundStates.get(from);
|
||||
if (state == null)
|
||||
state = _inboundStates.get(from);
|
||||
if (state == null) {
|
||||
// TODO this is insufficient to prevent DoSing, especially if
|
||||
// IP spoofing is used. For further study.
|
||||
@ -560,16 +563,17 @@ class EstablishmentManager {
|
||||
* Got a SessionRequest OR a TokenRequest (initiates an inbound establishment)
|
||||
*
|
||||
* SSU 2 only.
|
||||
* @param state as looked up in PacketHandler, but null unless retransmitted or retry sent
|
||||
* @param packet header decrypted only
|
||||
* @since 0.9.54
|
||||
*/
|
||||
void receiveSessionRequest(RemoteHostId from, UDPPacket packet) {
|
||||
void receiveSessionOrTokenRequest(RemoteHostId from, InboundEstablishState2 state, UDPPacket packet) {
|
||||
if (!TransportUtil.isValidPort(from.getPort()) || !_transport.isValid(from.getIP())) {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Receive session request from invalid: " + from);
|
||||
return;
|
||||
}
|
||||
boolean isNew = false;
|
||||
InboundEstablishState state = _inboundStates.get(from);
|
||||
if (state == null) {
|
||||
// TODO this is insufficient to prevent DoSing, especially if
|
||||
// IP spoofing is used. For further study.
|
||||
@ -607,9 +611,20 @@ class EstablishmentManager {
|
||||
|
||||
InboundEstablishState oldState = _inboundStates.putIfAbsent(from, state);
|
||||
isNew = oldState == null;
|
||||
if (!isNew)
|
||||
if (!isNew) {
|
||||
// whoops, somebody beat us to it, throw out the state we just created
|
||||
state = oldState;
|
||||
if (oldState.getVersion() == 2)
|
||||
state = (InboundEstablishState2) oldState;
|
||||
// else don't cast, this is only for printing below
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
state.receiveSessionRequestAfterRetry(packet);
|
||||
} catch (GeneralSecurityException gse) {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Corrupt Session Request after Retry from: " + state, gse);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (isNew) {
|
||||
@ -629,10 +644,10 @@ class EstablishmentManager {
|
||||
}
|
||||
****/
|
||||
if (_log.shouldInfo())
|
||||
_log.info("Received NEW session request " + state);
|
||||
_log.info("Received NEW session/token request " + state);
|
||||
} else {
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("Receive DUP session request from: " + state);
|
||||
_log.debug("Receive DUP session/token request from: " + state);
|
||||
}
|
||||
notifyActivity();
|
||||
}
|
||||
@ -642,9 +657,12 @@ class EstablishmentManager {
|
||||
* establishment)
|
||||
*
|
||||
* SSU 1 only.
|
||||
*
|
||||
* @param state as looked up in PacketHandler, if null is probably retransmitted
|
||||
*/
|
||||
void receiveSessionConfirmed(RemoteHostId from, UDPPacketReader reader) {
|
||||
InboundEstablishState state = _inboundStates.get(from);
|
||||
void receiveSessionConfirmed(RemoteHostId from, InboundEstablishState state, UDPPacketReader reader) {
|
||||
if (state == null)
|
||||
state = _inboundStates.get(from);
|
||||
if (state != null) {
|
||||
state.receiveSessionConfirmed(reader.getSessionConfirmedReader());
|
||||
notifyActivity();
|
||||
@ -661,40 +679,36 @@ class EstablishmentManager {
|
||||
* establishment)
|
||||
*
|
||||
* SSU 2 only.
|
||||
* @param state non-null
|
||||
* @param packet header decrypted only
|
||||
* @since 0.9.54
|
||||
*/
|
||||
void receiveSessionConfirmed(RemoteHostId from, UDPPacket packet) {
|
||||
InboundEstablishState state = _inboundStates.get(from);
|
||||
if (state != null) {
|
||||
if (state.getVersion() != 2)
|
||||
return;
|
||||
InboundEstablishState2 state2 = (InboundEstablishState2) state;
|
||||
try {
|
||||
state2.receiveSessionConfirmed(packet);
|
||||
} catch (GeneralSecurityException gse) {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Corrupt Session Confirmed from: " + from, gse);
|
||||
state.fail();
|
||||
return;
|
||||
}
|
||||
// we are done, go right to ps2
|
||||
handleCompletelyEstablished(state2);
|
||||
notifyActivity();
|
||||
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);
|
||||
void receiveSessionConfirmed(InboundEstablishState2 state, UDPPacket packet) {
|
||||
try {
|
||||
state.receiveSessionConfirmed(packet);
|
||||
} catch (GeneralSecurityException gse) {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Corrupt Session Confirmed on: " + state, gse);
|
||||
state.fail();
|
||||
return;
|
||||
}
|
||||
// we are done, go right to ps2
|
||||
handleCompletelyEstablished(state);
|
||||
notifyActivity();
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Receive session confirmed from: " + state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Got a SessionCreated (in response to our outbound SessionRequest)
|
||||
*
|
||||
* SSU 1 only.
|
||||
*
|
||||
* @param state as looked up in PacketHandler, if null is probably retransmitted
|
||||
*/
|
||||
void receiveSessionCreated(RemoteHostId from, UDPPacketReader reader) {
|
||||
OutboundEstablishState state = _outboundStates.get(from);
|
||||
void receiveSessionCreated(RemoteHostId from, OutboundEstablishState state, UDPPacketReader reader) {
|
||||
if (state == null)
|
||||
state = _outboundStates.get(from);
|
||||
if (state != null) {
|
||||
state.receiveSessionCreated(reader.getSessionCreatedReader());
|
||||
notifyActivity();
|
||||
@ -710,29 +724,23 @@ class EstablishmentManager {
|
||||
* Got a SessionCreated (in response to our outbound SessionRequest)
|
||||
*
|
||||
* SSU 2 only.
|
||||
*
|
||||
* @param state non-null
|
||||
* @param packet header decrypted only
|
||||
* @since 0.9.54
|
||||
*/
|
||||
void receiveSessionCreated(RemoteHostId from, UDPPacket packet) {
|
||||
OutboundEstablishState state = _outboundStates.get(from);
|
||||
if (state != null) {
|
||||
if (state.getVersion() != 2)
|
||||
return;
|
||||
OutboundEstablishState2 state2 = (OutboundEstablishState2) state;
|
||||
try {
|
||||
state2.receiveSessionCreated(packet);
|
||||
} catch (GeneralSecurityException gse) {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Corrupt Session Created from: " + from, gse);
|
||||
state.fail();
|
||||
return;
|
||||
}
|
||||
notifyActivity();
|
||||
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);
|
||||
void receiveSessionCreated(OutboundEstablishState2 state, UDPPacket packet) {
|
||||
try {
|
||||
state.receiveSessionCreated(packet);
|
||||
} catch (GeneralSecurityException gse) {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Corrupt Session Created on: " + state, gse);
|
||||
state.fail();
|
||||
return;
|
||||
}
|
||||
notifyActivity();
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Receive session created from: " + state);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -741,27 +749,18 @@ class EstablishmentManager {
|
||||
* SSU 2 only.
|
||||
* @since 0.9.54
|
||||
*/
|
||||
void receiveRetry(RemoteHostId from, UDPPacket packet) {
|
||||
OutboundEstablishState state = _outboundStates.get(from);
|
||||
if (state != null) {
|
||||
if (state.getVersion() != 2)
|
||||
return;
|
||||
OutboundEstablishState2 state2 = (OutboundEstablishState2) state;
|
||||
try {
|
||||
state2.receiveSessionCreated(packet);
|
||||
} catch (GeneralSecurityException gse) {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Corrupt Retry from: " + from, gse);
|
||||
state.fail();
|
||||
return;
|
||||
}
|
||||
notifyActivity();
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Receive retry from: " + state);
|
||||
} else {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Receive (DUP?) retry from: " + from);
|
||||
void receiveRetry(OutboundEstablishState2 state, UDPPacket packet) {
|
||||
try {
|
||||
state.receiveSessionCreated(packet);
|
||||
} catch (GeneralSecurityException gse) {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Corrupt Retry from: " + state, gse);
|
||||
state.fail();
|
||||
return;
|
||||
}
|
||||
notifyActivity();
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Receive retry from: " + state);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -41,6 +41,7 @@ class PacketHandler {
|
||||
private final BlockingQueue<UDPPacket> _inboundQueue;
|
||||
private static final Object DUMMY = new Object();
|
||||
private final boolean _enableSSU2;
|
||||
private final int _networkID;
|
||||
|
||||
private static final int TYPE_POISON = -99999;
|
||||
private static final int MIN_QUEUE_SIZE = 16;
|
||||
@ -68,6 +69,7 @@ class PacketHandler {
|
||||
_testManager = testManager;
|
||||
_introManager = introManager;
|
||||
_failCache = new LHMCache<RemoteHostId, Object>(24);
|
||||
_networkID = ctx.router().getNetworkID();
|
||||
|
||||
long maxMemory = SystemVersion.getMaxMemory();
|
||||
int qsize = (int) Math.max(MIN_QUEUE_SIZE, Math.min(MAX_QUEUE_SIZE, maxMemory / (2*1024*1024)));
|
||||
@ -241,7 +243,7 @@ class PacketHandler {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Packet received IS for an inbound establishment");
|
||||
if (est.getVersion() == 2)
|
||||
receiveSSU2Packet(packet, (InboundEstablishState2) est);
|
||||
receiveSSU2Packet(rem, packet, (InboundEstablishState2) est);
|
||||
else
|
||||
receivePacket(reader, packet, est);
|
||||
} else {
|
||||
@ -354,6 +356,17 @@ class PacketHandler {
|
||||
alreadyFailed = _failCache.get(remoteHost) != null;
|
||||
}
|
||||
if (!alreadyFailed) {
|
||||
// For now, try SSU2 Session/Token Request processing here.
|
||||
// After we've migrated the majority of the network over to SSU2,
|
||||
// we can try SSU2 first.
|
||||
if (_enableSSU2 && peerType == PeerType.NEW_PEER) {
|
||||
boolean handled = receiveSSU2Packet(remoteHost, packet, (InboundEstablishState2) null);
|
||||
if (handled)
|
||||
return;
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("Continuing with SSU1 fallback processing, wasn't an SSU2 packet from " + remoteHost);
|
||||
}
|
||||
|
||||
// this is slow, that's why we cache it above.
|
||||
List<PeerState> peers = _transport.getPeerStatesByIP(remoteHost);
|
||||
if (!peers.isEmpty()) {
|
||||
@ -623,9 +636,6 @@ class PacketHandler {
|
||||
return;
|
||||
}
|
||||
|
||||
//InetAddress fromHost = packet.getPacket().getAddress();
|
||||
//int fromPort = packet.getPacket().getPort();
|
||||
//RemoteHostId from = new RemoteHostId(fromHost.getAddress(), fromPort);
|
||||
RemoteHostId from = packet.getRemoteHost();
|
||||
|
||||
switch (type) {
|
||||
@ -635,7 +645,7 @@ class PacketHandler {
|
||||
_log.warn("Dropping type " + type + " auth " + auth + ": " + packet);
|
||||
break;
|
||||
}
|
||||
_establisher.receiveSessionRequest(from, reader);
|
||||
_establisher.receiveSessionRequest(from, inState, reader);
|
||||
break;
|
||||
case UDPPacket.PAYLOAD_TYPE_SESSION_CONFIRMED:
|
||||
if (auth != AuthType.SESSION) {
|
||||
@ -643,7 +653,7 @@ class PacketHandler {
|
||||
_log.warn("Dropping type " + type + " auth " + auth + ": " + packet);
|
||||
break;
|
||||
}
|
||||
_establisher.receiveSessionConfirmed(from, reader);
|
||||
_establisher.receiveSessionConfirmed(from, inState, reader);
|
||||
break;
|
||||
case UDPPacket.PAYLOAD_TYPE_SESSION_CREATED:
|
||||
// this is the only type that allows BOBINTRO
|
||||
@ -652,7 +662,7 @@ class PacketHandler {
|
||||
_log.warn("Dropping type " + type + " auth " + auth + ": " + packet);
|
||||
break;
|
||||
}
|
||||
_establisher.receiveSessionCreated(from, reader);
|
||||
_establisher.receiveSessionCreated(from, outState, reader);
|
||||
break;
|
||||
case UDPPacket.PAYLOAD_TYPE_DATA:
|
||||
if (auth != AuthType.SESSION) {
|
||||
@ -763,37 +773,199 @@ class PacketHandler {
|
||||
* Packet is decrypted in-place, no fallback
|
||||
* processing is possible.
|
||||
*
|
||||
* @param state must be version 2
|
||||
* @param packet any in-session message
|
||||
* @param state must be version 2, non-null
|
||||
* @since 0.9.54
|
||||
*/
|
||||
private void receiveSSU2Packet(UDPPacket packet, PeerState2 state) {
|
||||
// header and body decryption is done by PeerState2
|
||||
state.receivePacket(packet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hand off to the state for processing.
|
||||
* Packet is decrypted in-place, no fallback
|
||||
* processing is possible.
|
||||
* Decrypt the header and hand off to the state for processing.
|
||||
* Packet is trial-decrypted, so fallback
|
||||
* processing is possible if this returns false.
|
||||
*
|
||||
* @param state must be version 2
|
||||
* Possible messages here are Session Request, Token Request, Session Confirmed, or Peer Test.
|
||||
* Data messages out-of-order from Session Confirmed, or following a
|
||||
* Session Confirmed that was lost, or in-order but before the Session Confirmed was processed,
|
||||
* will not be successfully decrypted and will be dropped.
|
||||
*
|
||||
* @param state must be version 2, but will be null for session request unless retransmitted
|
||||
* @return true if the header was validated as a SSU2 packet, cannot fallback to SSU 1
|
||||
* @since 0.9.54
|
||||
*/
|
||||
private void receiveSSU2Packet(UDPPacket packet, InboundEstablishState2 state) {
|
||||
|
||||
private boolean receiveSSU2Packet(RemoteHostId from, UDPPacket packet, InboundEstablishState2 state) {
|
||||
// decrypt header
|
||||
byte[] k1 = _transport.getSSU2StaticIntroKey();
|
||||
byte[] k2;
|
||||
SSU2Header.Header header;
|
||||
int type;
|
||||
if (state == null) {
|
||||
// Session Request, Token Request, or Peer Test
|
||||
k2 = k1;
|
||||
header = SSU2Header.trialDecryptHandshakeHeader(packet, k1, k2);
|
||||
if (header == null ||
|
||||
header.getType() != SSU2Util.SESSION_REQUEST_FLAG_BYTE ||
|
||||
header.getVersion() != 2 ||
|
||||
header.getNetID() != _networkID) {
|
||||
if (_log.shouldInfo())
|
||||
_log.info("Does not decrypt as Session Request, attempt to decrypt as Token Request/Peer Test: " + header);
|
||||
// The first 32 bytes were fine, but it corrupted the next 32 bytes
|
||||
// TODO make this more efficient, just take the first 32 bytes
|
||||
header = SSU2Header.trialDecryptLongHeader(packet, k1, k2);
|
||||
if (header == null ||
|
||||
header.getVersion() != 2 ||
|
||||
header.getNetID() != _networkID) {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Does not decrypt as Session Request, Token Request, or Peer Test: " + header);
|
||||
return false;
|
||||
}
|
||||
type = header.getType();
|
||||
} else {
|
||||
type = SSU2Util.SESSION_REQUEST_FLAG_BYTE;
|
||||
}
|
||||
} else {
|
||||
// Session Request (after Retry) or Session Confirmed
|
||||
// or retransmitted Session Request or Token Rquest
|
||||
k2 = state.getRcvHeaderEncryptKey2();
|
||||
if (state.getState() == InboundEstablishState.InboundState.IB_STATE_RETRY_SENT) {
|
||||
// Session Request
|
||||
header = SSU2Header.trialDecryptHandshakeHeader(packet, k1, k2);
|
||||
if (header == null ||
|
||||
header.getType() != SSU2Util.SESSION_REQUEST_FLAG_BYTE ||
|
||||
header.getVersion() != 2 ||
|
||||
header.getNetID() != _networkID) {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Failed decrypt Session Request after Retry: " + header);
|
||||
return false;
|
||||
}
|
||||
type = SSU2Util.SESSION_REQUEST_FLAG_BYTE;
|
||||
} else {
|
||||
// Session Confirmed or retransmitted Session Request or Token Request
|
||||
header = SSU2Header.trialDecryptShortHeader(packet, k1, k2);
|
||||
if (header == null ||
|
||||
header.getType() != SSU2Util.SESSION_CONFIRMED_FLAG_BYTE) {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Failed decrypt Session Confirmed: " + header);
|
||||
// TODO either attempt to decrypt as a retransmitted
|
||||
// Session Request or Token Request,
|
||||
// or just tell establisher so it can retransmit Session Created or Retry
|
||||
// Could also be Data messages after (possibly lost or out-of-order) Session Confirmed
|
||||
return false;
|
||||
}
|
||||
type = SSU2Util.SESSION_CONFIRMED_FLAG_BYTE;
|
||||
}
|
||||
if (header.getDestConnID() != state.getRcvConnID()) {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Bad Dest Conn id " + header);
|
||||
return false;
|
||||
}
|
||||
if (header.getSrcConnID() != state.getSendConnID()) {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Bad Source Conn id " + header);
|
||||
// TODO could be a retransmitted Session Request,
|
||||
// tell establisher?
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// all good
|
||||
SSU2Header.acceptTrialDecrypt(packet, header);
|
||||
if (type == SSU2Util.SESSION_REQUEST_FLAG_BYTE) {
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("Got a Session Request on " + state);
|
||||
_establisher.receiveSessionOrTokenRequest(from, state, packet);
|
||||
} else if (type == SSU2Util.TOKEN_REQUEST_FLAG_BYTE) {
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("Got a Token Request on " + state);
|
||||
_establisher.receiveSessionOrTokenRequest(from, state, packet);
|
||||
} else if (type == SSU2Util.SESSION_CONFIRMED_FLAG_BYTE) {
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("Got a Session Confirmed on " + state);
|
||||
_establisher.receiveSessionConfirmed(state, packet);
|
||||
} else if (type == SSU2Util.PEER_TEST_FLAG_BYTE) {
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("Got a Peer Test on " + state);
|
||||
// TODO
|
||||
} else {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Got unknown message " + header + " on " + state);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hand off to the state for processing.
|
||||
* Packet is decrypted in-place, no fallback
|
||||
* processing is possible.
|
||||
* Decrypt the header and hand off to the state for processing.
|
||||
* Packet is trial-decrypted, so fallback
|
||||
* processing is possible if this returns false.
|
||||
* But that's probably not necessary.
|
||||
*
|
||||
* @param state must be version 2
|
||||
* Possible messages here are Session Created or Retry
|
||||
*
|
||||
* @param state must be version 2, non-null
|
||||
* @return true if the header was validated as a SSU2 packet, cannot fallback to SSU 1
|
||||
* @since 0.9.54
|
||||
*/
|
||||
private void receiveSSU2Packet(UDPPacket packet, OutboundEstablishState2 state) {
|
||||
|
||||
private boolean receiveSSU2Packet(UDPPacket packet, OutboundEstablishState2 state) {
|
||||
// decrypt header
|
||||
byte[] k1 = state.getRcvHeaderEncryptKey1();
|
||||
byte[] k2 = state.getRcvHeaderEncryptKey2();
|
||||
SSU2Header.Header header = SSU2Header.trialDecryptHandshakeHeader(packet, k1, k2);
|
||||
if (header != null) {
|
||||
// dest conn ID decrypts the same for both Session Created
|
||||
// and Retry, so we can bail out now if it doesn't match
|
||||
if (header.getDestConnID() != state.getRcvConnID()) {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Bad Dest Conn id " + header);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
int type;
|
||||
if (header == null ||
|
||||
header.getType() != SSU2Util.SESSION_CREATED_FLAG_BYTE ||
|
||||
header.getVersion() != 2 ||
|
||||
header.getNetID() != _networkID) {
|
||||
if (_log.shouldInfo())
|
||||
_log.info("Does not decrypt as Session Created, attempt to decrypt as Retry: " + header);
|
||||
k2 = state.getRcvRetryHeaderEncryptKey2();
|
||||
header = SSU2Header.trialDecryptLongHeader(packet, k1, k2);
|
||||
if (header == null ||
|
||||
header.getType() != SSU2Util.RETRY_FLAG_BYTE ||
|
||||
header.getVersion() != 2 ||
|
||||
header.getNetID() != _networkID) {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Does not decrypt as Session Created or Retry: " + header);
|
||||
return false;
|
||||
}
|
||||
type = SSU2Util.RETRY_FLAG_BYTE;
|
||||
} else {
|
||||
type = SSU2Util.SESSION_CREATED_FLAG_BYTE;
|
||||
}
|
||||
if (header.getDestConnID() != state.getRcvConnID()) {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Bad Dest Conn id " + header);
|
||||
return false;
|
||||
}
|
||||
if (header.getSrcConnID() != state.getSendConnID()) {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Bad Source Conn id " + header);
|
||||
return false;
|
||||
}
|
||||
|
||||
// all good
|
||||
SSU2Header.acceptTrialDecrypt(packet, header);
|
||||
if (type == SSU2Util.SESSION_CREATED_FLAG_BYTE) {
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("Got a Session Created on " + state);
|
||||
_establisher.receiveSessionCreated(state, packet);
|
||||
} else {
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("Got a Retry on " + state);
|
||||
_establisher.receiveRetry(state, packet);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -138,6 +138,9 @@ public class PeerState2 extends PeerState implements SSU2Payload.PayloadCallback
|
||||
SSU2Bitfield getReceivedMessages() { return _receivedMessages; }
|
||||
SSU2Bitfield getAckedMessages() { return _ackedMessages; }
|
||||
|
||||
/**
|
||||
* @param packet fully encrypted, header and body decryption will be done here
|
||||
*/
|
||||
void receivePacket(UDPPacket packet) {
|
||||
DatagramPacket dpacket = packet.getPacket();
|
||||
byte[] data = dpacket.getData();
|
||||
@ -163,6 +166,14 @@ public class PeerState2 extends PeerState implements SSU2Payload.PayloadCallback
|
||||
if (header.getType() != DATA_FLAG_BYTE) {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("bad data pkt type " + (header.getType() & 0xff) + " on " + this);
|
||||
// TODO if it's early:
|
||||
// If inbound, could be a retransmitted Session Confirmed,
|
||||
// ack it again.
|
||||
// If outbound, and Session Confirmed is not acked yet,
|
||||
// could be a retransmitted Session Created,
|
||||
// retransmit Session Confirmed.
|
||||
// Alternatively, could be a new Session Request or Token Request,
|
||||
// we didn't know the session has disconnected yet.
|
||||
return;
|
||||
}
|
||||
long n = header.getPacketNumber();
|
||||
|
@ -25,7 +25,7 @@ final class SSU2Header {
|
||||
* Session Request and Session Created only. 64 bytes.
|
||||
* Packet is unmodified.
|
||||
*
|
||||
* @param packet must be 56 bytes min
|
||||
* @param packet must be 88 bytes min
|
||||
* @return 64 byte header, null if data too short
|
||||
*/
|
||||
public static Header trialDecryptHandshakeHeader(UDPPacket packet, byte[] key1, byte[] key2) {
|
||||
@ -155,6 +155,7 @@ final class SSU2Header {
|
||||
*/
|
||||
public static class Header {
|
||||
public final byte[] data;
|
||||
|
||||
public Header(int len) { data = new byte[len]; }
|
||||
|
||||
/** all headers */
|
||||
|
Reference in New Issue
Block a user