java.lang.Object
net.i2p.router.transport.udp.OutboundEstablishState
net.i2p.router.transport.udp.OutboundEstablishState2
- All Implemented Interfaces:
SSU2Payload.PayloadCallback
Data for a new connection being established, where we initiated the connection with a remote peer. In other words, we are Alice and they are Bob.
SSU2 only.
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic enumPer-introducer introduction states.Nested classes/interfaces inherited from class OutboundEstablishState
OutboundEstablishState.OutboundStateModifier and TypeClassDescriptionstatic enumStates for outbound SSU session establishment.Field Summary
FieldsModifier and TypeFieldDescriptionprivate final BanLoggerRecords why routers were banned.private InetSocketAddressBob's socket address.private HandshakeStateHandshake state for the ratchet keys.private final byte[]First header encryption key, Bob's introduction key, used for sending and receiving alike.private final Map<Hash, OutboundEstablishState2.IntroState> Introduction states, by introducer hash.private final intThe MTU agreed for the new peer.private PeerState2The peer state being built, once created.private final longConnection id we receive with.private byte[]Second header encryption key for receiving.private final byte[]Retry key for the second receive header.private final RouterAddressThe router address being connected to.private final longConnection id we send with.private byte[]Second header encryption key for sending.private byte[][]Session Confirmed fragments for retransmission.private byte[]Session Request packet held for retransmission.private longOur clock skew to Bob, in ms, not adjusted for RTT.private longWhen the handshake started.private longThe handshake token echoed by Bob.private final UDPTransportThe SSU transport we serve.private final intVersion of the handshake.private static final longMaximum clock skew accepted in a handshake.Fields inherited from class OutboundEstablishState
_aliceIP, _alicePort, _bobIP, _bobPort, _context, _currentState, _establishBegin, _lastSend, _log, _nextSend, _receivedRelayTag, _remoteHostId, _remotePeer, _requestSentCount, _requestSentTime, _rtt, MAX_DELAY, RETRANSMIT_DELAYModifier and TypeFieldDescriptionprotected byte[]Alice's IP, from the SessionCreated message.protected intAlice's port.protected byte[]Bob's IP, from the SessionRequest message.protected intBob's port.protected final RouterContextThe router context.protected OutboundEstablishState.OutboundStateCurrent state.protected final longEstablish begin time.protected longLast send time.protected final LogLogger.protected longNext send time.protected longReceived relay tag.protected RemoteHostIdRemote host ID.protected final RouterIdentityRemote peer.protected intRequest sent count.protected longRequest sent time.protected intRound trip time.protected static final longMax delay including backoff (15 seconds).protected static final longFlat delay between all retransmits (no exponential backoff).Constructor Summary
ConstructorsConstructorDescriptionOutboundEstablishState2(RouterContext ctx, UDPTransport transport, RemoteHostId claimedAddress, RemoteHostId remoteHostId, RouterIdentity remotePeer, boolean needIntroduction, SessionKey introKey, RouterAddress ra, UDPAddress addr, int version) Prepare to start a new handshake with the given peer.Method Summary
Modifier and TypeMethodDescriptionprivate static final StringMark a string for extraction by xgettext and translation.confirmedPacketsSent(UDPPacket[] packets) Note that we just sent the SessionConfirmed packets and save them for retransmission.intNumber of current introducers.private voidcreateNewState(RouterAddress addr) This will be called 0 times if we don't have a token and never get a retry; once if we have a token; and twice if the token we had was bad and we got a retry.(package private) static inteffectiveMTU(int version, byte[] bobIP, int peerMTU, int ourMTU) The MTU to size a packet to this peer against: his MTU, capped by our own for that address family.voidfail()Overridden from SSU1 to destroy the handshake state.Current handshake state.The current state for the SSU2 introducer specified.intgetMTU()What is the largest packet we can send to the peer? His MTU, capped by ours.Get the next token for this connection.The peer state for this connection.longConnection ID we receive from the peer.byte[]Header encryption key 1 for receiving.byte[]Header encryption key 2 for receiving.byte[]Retry header encryption key 2 for receiving.A packet to retransmit the SessionRequest.longConnection ID we use when sending.byte[]Header encryption key 1 for sending.byte[]Header encryption key 2 for sending.Socket address we sent the session request to.longgetToken()Current session token.intVersion of the SSU protocol in use.voidgotACK(long ackThru, int acks, byte[] ranges) Receive an acknowledgment block.voidgotAddress(byte[] ip, int port) Receive an address block.voidgotDateTime(long time) //////////////////////////////////////////////////////voidgotFragment(byte[] data, int off, int len, long messageId, int frag, boolean isLast) Receive a fragment of a fragmented message.voidgotI2NP(I2NPMessage msg) Receive an I2NP message block.voidgotOptions(byte[] options, boolean isHandshake) Receive a session options block.voidgotPathChallenge(RemoteHostId from, byte[] data) Receive a path challenge block.voidgotPathResponse(RemoteHostId from, byte[] data) Receive a path response block.voidgotPeerTest(int msg, int status, Hash h, byte[] data) Receive a peer test block.voidgotRelayIntro(Hash aliceHash, byte[] data) Receive a relay introduction.voidgotRelayRequest(byte[] data) Receive a relay request.voidgotRelayResponse(int status, byte[] data) Receive a relay response.voidgotRelayTag(long tag) Receive a relay tag.voidReceive a relay tag request.voidgotRI(RouterInfo ri, boolean isHandshake, boolean flood) Receive a complete RouterInfo block.voidgotRIFragment(byte[] data, boolean isHandshake, boolean flood, boolean isGzipped, int frag, int totalFrags) Receive a fragment of a RouterInfo block.voidgotTermination(int reason, long count) Receive a session termination block.voidgotToken(long token, long expires) Receive a new session token.voidintroduced(byte[] ip, int port, long token) After introduction.voidA relay request was sent to the SSU2 introducer specified.private voidlocked_receiveRetry(UDPPacket packet) Process a Retry packet, with the lock held.private voidProcess SessionCreated, with the lock held.private voidprocessPayload(byte[] payload, int offset, int length, boolean isHandshake) Processes one handshake payload.(package private) booleanOverridden because we don't have to wait for Relay Response first.voidreceiveRetry(UDPPacket packet) Receive a retry packet.voidreceiveSessionCreated(UDPPacket packet) Receive a SessionCreated packet.voidNote that we just sent the SessionRequest packet and save it for retransmission.voidThe current state for the SSU2 introducer specified.voidtokenRequestSent(DatagramPacket packet) Note that we just sent a token request packet and save it for retransmission.(package private) StringCompact one-line establish-state identifier for log output: peer hash and current state.toString()String representation.booleanBlocking call (run in the establisher thread) to determine if the session was created properly.Methods inherited from class OutboundEstablishState
addMessage, complete, confirmedPacketsSent, dataReceived, getClaimedAddress, getConfirmedSentTime, getEstablishBeginTime, getIntroKey, getIntroNonce, getIntroSentTime, getLifetime, getLifetime, getNextQueuedMessage, getNextSendTime, getReceivedIP, getReceivedPort, getReceivedRelayTag, getReceivedSignedOnTime, getRemoteAddress, getRemoteHostId, getRemoteIdentity, getRequestSentTime, getRTT, getSentIP, getSentPort, getSentSignedOnTime, getState, hasRetried, introduced, introductionFailed, introSent, isExtendedOptionsAllowed, isFirstMessageOurDSM, needIntroduction, packetReceived, requestSent, setIntroNonceModifier and TypeMethodDescriptionvoidaddMessage(OutNetMessage msg) Queue a message to be sent after the session is established.booleancomplete()Mark as complete.voidNote that we just sent the SessionConfirmed packet.voidWe have received a real data packet, so we're done establishing.(package private) RemoteHostIdThis will never be a hash-based address.longWhen we sent the first SessionConfirmed packet.longTime the establish began.Bob's introduction key, as published in the netdb.longIntroduction nonce, or -1 if unset.longWhen we sent the first RelayRequest packet.longHow long have we been trying to establish this session?longgetLifetime(long now) How long have we been trying to establish this session?Next queued message.longThe next time a message should be sent.byte[]IP address reported by the peer.intPort reported by the peer.longRelay tag received from the introducer.longTime the signed-on packet was received.Remote address of the peer.(package private) RemoteHostIdThis should be what the state is currently indexed by in the _outboundStates table.Remote router identity.longWhen we sent the first SessionRequest packet.(package private) intgetRTT()Round-trip time estimate.byte[]The remote side (Bob) - note that in some places he's called Charlie.intThe remote side (Bob) - note that in some places he's called Charlie.longTime the signed-on packet was sent.getState()Current outbound handshake state.booleanWhether the state machine has already scheduled a resend.voidintroduced(byte[] bobIP, int bobPort) This changes the remoteHostId from a hash-based one or possibly incorrect IP/port to what the introducer told us.voidRecord that the introduction failed.voidNote that we just sent the RelayRequest packet.booleanAre we allowed to send extended options to this peer?booleanIs the first message queued our own DatabaseStoreMessage?booleanShould we ask this peer to be an introducer for us? Ignored unless allowExtendedOptions is true.protected voidCall from synchronized method only.voidNote that we just sent the SessionRequest packet.voidsetIntroNonce(long nonce) Introduction nonce.
Field Details
_banLogger
Records why routers were banned._bobSocketAddress
Bob's socket address._transport
The SSU transport we serve._sendConnID
private final long _sendConnIDConnection id we send with._rcvConnID
private final long _rcvConnIDConnection id we receive with._routerAddress
The router address being connected to._introducers
Introduction states, by introducer hash._token
private long _tokenThe handshake token echoed by Bob._handshakeState
Handshake state for the ratchet keys._version
private final int _versionVersion of the handshake._headerEncryptKey1
private final byte[] _headerEncryptKey1First header encryption key, Bob's introduction key, used for sending and receiving alike._sendHeaderEncryptKey2
private byte[] _sendHeaderEncryptKey2Second header encryption key for sending._rcvHeaderEncryptKey2
private byte[] _rcvHeaderEncryptKey2Second header encryption key for receiving._rcvRetryHeaderEncryptKey2
private final byte[] _rcvRetryHeaderEncryptKey2Retry key for the second receive header._mtu
private final int _mtuThe MTU agreed for the new peer._sessReqForReTX
private byte[] _sessReqForReTXSession Request packet held for retransmission._sessConfForReTX
private byte[][] _sessConfForReTXSession Confirmed fragments for retransmission._timeReceived
private long _timeReceivedWhen the handshake started._skew
private long _skewOur clock skew to Bob, in ms, not adjusted for RTT._pstate
The peer state being built, once created.MAX_SKEW
private static final long MAX_SKEWMaximum clock skew accepted in a handshake.- See Also:
Constructor Details
OutboundEstablishState2
public OutboundEstablishState2(RouterContext ctx, UDPTransport transport, RemoteHostId claimedAddress, RemoteHostId remoteHostId, RouterIdentity remotePeer, boolean needIntroduction, SessionKey introKey, RouterAddress ra, UDPAddress addr, int version) throws IllegalArgumentException Prepare to start a new handshake with the given peer.Caller must then check
OutboundEstablishState.getState()and build a Token Request or Session Request to send to the peer.- Parameters:
ctx- the router contexttransport- the UDP transportclaimedAddress- an IP/port based RemoteHostId, or null if unknownremoteHostId- non-null, == claimedAddress if direct, or a hash-based one if indirectremotePeer- must have supported sig typeneedIntroduction- should we ask Bob to be an introducer for us? ignored unless allowExtendedOptions is trueintroKey- Bob's introduction key, as published in the netdbra- the router addressaddr- non-nullversion- the SSU2 version- Throws:
IllegalArgumentException
Method Details
introduced
public void introduced(byte[] ip, int port, long token) After introduction.- Parameters:
ip- the IP address bytesport- the port numbertoken- the token received
createNewState
This will be called 0 times if we don't have a token and never get a retry; once if we have a token; and twice if the token we had was bad and we got a retry. We must regenerate the handshake state if we get a new token, because we only save the full encrypted packet for retransmission, and the encryption changes if the token does.caller must synch.
- Parameters:
addr- the introducer's RouterAddress carrying the SSU2 keys and token- Throws:
IllegalArgumentException- if the address has no SSU2 static key option
processPayload
private void processPayload(byte[] payload, int offset, int length, boolean isHandshake) throws GeneralSecurityException Processes one handshake payload.- Parameters:
payload- the packet payloadoffset- where the handshake data startslength- the handshake data lengthisHandshake- true for a handshake packet- Throws:
GeneralSecurityException- if the decryption or MAC fails
gotDateTime
public void gotDateTime(long time) //////////////////////////////////////////////////////- Specified by:
gotDateTimein interfaceSSU2Payload.PayloadCallback- Parameters:
time- time in milliseconds since epoch
gotOptions
public void gotOptions(byte[] options, boolean isHandshake) Description copied from interface:SSU2Payload.PayloadCallbackReceive a session options block.- Specified by:
gotOptionsin interfaceSSU2Payload.PayloadCallback- Parameters:
options- the option dataisHandshake- true only for message 3 part 2
gotRI
Description copied from interface:SSU2Payload.PayloadCallbackReceive a complete RouterInfo block.- Specified by:
gotRIin interfaceSSU2Payload.PayloadCallback- Parameters:
ri- will already be validatedisHandshake- true only for message 3 part 2flood- true if this is a floodfill router- Throws:
DataFormatException- if the RouterInfo block is malformed
gotRIFragment
public void gotRIFragment(byte[] data, boolean isHandshake, boolean flood, boolean isGzipped, int frag, int totalFrags) Description copied from interface:SSU2Payload.PayloadCallbackReceive a fragment of a RouterInfo block.- Specified by:
gotRIFragmentin interfaceSSU2Payload.PayloadCallback- Parameters:
data- is first gzipped and then fragmentedisHandshake- true only for message 3 part 2flood- true if this is a floodfill routerisGzipped- true if the data is gzippedfrag- fragment number (0-based)totalFrags- total number of fragments
gotAddress
public void gotAddress(byte[] ip, int port) Description copied from interface:SSU2Payload.PayloadCallbackReceive an address block.- Specified by:
gotAddressin interfaceSSU2Payload.PayloadCallback- Parameters:
ip- IP address bytesport- the port number to send
gotRelayTagRequest
public void gotRelayTagRequest()Description copied from interface:SSU2Payload.PayloadCallbackReceive a relay tag request.- Specified by:
gotRelayTagRequestin interfaceSSU2Payload.PayloadCallback
gotRelayTag
public void gotRelayTag(long tag) Description copied from interface:SSU2Payload.PayloadCallbackReceive a relay tag.- Specified by:
gotRelayTagin interfaceSSU2Payload.PayloadCallback- Parameters:
tag- the relay tag
gotRelayRequest
public void gotRelayRequest(byte[] data) Description copied from interface:SSU2Payload.PayloadCallbackReceive a relay request.- Specified by:
gotRelayRequestin interfaceSSU2Payload.PayloadCallback- Parameters:
data- excludes flag, includes signature
gotRelayResponse
public void gotRelayResponse(int status, byte[] data) Description copied from interface:SSU2Payload.PayloadCallbackReceive a relay response.- Specified by:
gotRelayResponsein interfaceSSU2Payload.PayloadCallback- Parameters:
status- 0 = accept, 1-255 = rejectdata- excludes flag, includes signature
gotRelayIntro
Description copied from interface:SSU2Payload.PayloadCallbackReceive a relay introduction.- Specified by:
gotRelayIntroin interfaceSSU2Payload.PayloadCallback- Parameters:
aliceHash- hash of the introducerdata- excludes flag, includes signature
gotPeerTest
Description copied from interface:SSU2Payload.PayloadCallbackReceive a peer test block.- Specified by:
gotPeerTestin interfaceSSU2Payload.PayloadCallback- Parameters:
msg- 1-7status- 0 = accept, 1-255 = rejecth- Alice or Charlie hash for msg 2 and 4, null for msg 1, 3, 5-7data- excludes flag, includes signature
gotToken
public void gotToken(long token, long expires) Description copied from interface:SSU2Payload.PayloadCallbackReceive a new session token.- Specified by:
gotTokenin interfaceSSU2Payload.PayloadCallback- Parameters:
token- the session token to attach to the next peer testexpires- token expiration time in milliseconds
gotI2NP
Description copied from interface:SSU2Payload.PayloadCallbackReceive an I2NP message block.- Specified by:
gotI2NPin interfaceSSU2Payload.PayloadCallback- Parameters:
msg- the parsed I2NP message
gotFragment
public void gotFragment(byte[] data, int off, int len, long messageId, int frag, boolean isLast) throws DataFormatException Description copied from interface:SSU2Payload.PayloadCallbackReceive a fragment of a fragmented message. Data must be copied out in this method. Data starts at the 9 byte header for fragment 0.- Specified by:
gotFragmentin interfaceSSU2Payload.PayloadCallback- Parameters:
data- buffer containing fragment dataoff- offset in datalen- length of data to copymessageId- unique message identifierfrag- fragment number (0-based)isLast- whether this is the last fragment- Throws:
DataFormatException- if the fragment is malformed
gotACK
public void gotACK(long ackThru, int acks, byte[] ranges) Description copied from interface:SSU2Payload.PayloadCallbackReceive an acknowledgment block.- Specified by:
gotACKin interfaceSSU2Payload.PayloadCallback- Parameters:
ackThru- highest contiguous sequence number acknowledgedacks- number of additional acknowledgments beyond ackThruranges- null if none
gotTermination
public void gotTermination(int reason, long count) Description copied from interface:SSU2Payload.PayloadCallbackReceive a session termination block.- Specified by:
gotTerminationin interfaceSSU2Payload.PayloadCallback- Parameters:
reason- termination reason codecount- in theory could wrap around to negative, but very unlikely
gotPathChallenge
Description copied from interface:SSU2Payload.PayloadCallbackReceive a path challenge block.- Specified by:
gotPathChallengein interfaceSSU2Payload.PayloadCallback- Parameters:
from- null if unknowndata- the challenge bytes, which must be copied out
gotPathResponse
Description copied from interface:SSU2Payload.PayloadCallbackReceive a path response block.- Specified by:
gotPathResponsein interfaceSSU2Payload.PayloadCallback- Parameters:
from- null if unknowndata- the response bytes, which must be copied out
fail
public void fail()Overridden from SSU1 to destroy the handshake state.- Overrides:
failin classOutboundEstablishState
validateSessionCreated
public boolean validateSessionCreated()Description copied from class:OutboundEstablishStateBlocking call (run in the establisher thread) to determine if the session was created properly. If it wasn't, all the SessionCreated remnants are dropped (perhaps they were spoofed, etc) so that we can receive another oneGenerates session key and mac key.
- Overrides:
validateSessionCreatedin classOutboundEstablishState- Returns:
- true if valid
receiveHolePunch
boolean receiveHolePunch()Overridden because we don't have to wait for Relay Response first.- Overrides:
receiveHolePunchin classOutboundEstablishState- Returns:
- true if we should send the SessionRequest now
getVersion
public int getVersion()Description copied from class:OutboundEstablishStateVersion of the SSU protocol in use.- Overrides:
getVersionin classOutboundEstablishState- Returns:
- the protocol version
getSendConnID
public long getSendConnID()Connection ID we use when sending.- Returns:
- the send connection ID
getRcvConnID
public long getRcvConnID()Connection ID we receive from the peer.- Returns:
- the receive connection ID
getToken
public long getToken()Current session token.- Returns:
- the current token
getNextToken
Get the next token for this connection.- Returns:
- may be null
getHandshakeState
getSendHeaderEncryptKey1
public byte[] getSendHeaderEncryptKey1()Header encryption key 1 for sending.- Returns:
- the send header encrypt key 1
getRcvHeaderEncryptKey1
public byte[] getRcvHeaderEncryptKey1()Header encryption key 1 for receiving.- Returns:
- the receive header encrypt key 1
getSendHeaderEncryptKey2
public byte[] getSendHeaderEncryptKey2()Header encryption key 2 for sending.- Returns:
- the send header encrypt key 2
getRcvHeaderEncryptKey2
public byte[] getRcvHeaderEncryptKey2()Header encryption key 2 for receiving.- Returns:
- null before Session Request is sent (i.e. we sent a Token Request first)
getRcvRetryHeaderEncryptKey2
public byte[] getRcvRetryHeaderEncryptKey2()Retry header encryption key 2 for receiving.- Returns:
- the retry header encrypt key 2
getSentAddress
Socket address we sent the session request to.- Returns:
- the Bob socket address
getMTU
public int getMTU()What is the largest packet we can send to the peer? His MTU, capped by ours. Only used for Session Confirmed packets. Session Request is very small, except for MLKEM768.- Returns:
- the MTU in bytes
effectiveMTU
static int effectiveMTU(int version, byte[] bobIP, int peerMTU, int ourMTU) The MTU to size a packet to this peer against: his MTU, capped by our own for that address family. IPv6, and a peer whose address family we do not know, is held toPeerState2.MIN_MTUto avoid PMTU problems on brokered IPv6 tunnels - the data phase probes and increases if possible. Version 4 is exempt, because its ML-KEM frame is already larger than that minimum and the version gate only negotiates it where the real MTU fits; clamping it would leave the handshake no padding room at all.- Parameters:
version- the negotiated SSU2 versionbobIP- the peer's address bytes, 4 or 16 of them, null if unknownpeerMTU- the peer's MTU in bytesourMTU- our own MTU for that address family, 0 if unavailable- Returns:
- the MTU in bytes to size packets against
receiveRetry
Receive a retry packet.- Parameters:
packet- the UDP packet received- Throws:
GeneralSecurityException- if the packet does not match the pending Retry request - wrong address, connection IDs, or an unexpected retry token - or carries a bad or zero DateTime block
locked_receiveRetry
Process a Retry packet, with the lock held.- Parameters:
packet- the Retry packet from the peer- Throws:
GeneralSecurityException- if the source address does not match the configured one, or decrypting or validating the retry fails
receiveSessionCreated
Receive a SessionCreated packet.- Parameters:
packet- the UDP packet received- Throws:
GeneralSecurityException- if the packet does not match the pending request - wrong address or connection IDs - or is missing its DateTime or address block, or exceeds the two minute skew limit
locked_receiveSessionCreated
Process SessionCreated, with the lock held.- Parameters:
packet- the SessionCreated packet from the peer- Throws:
GeneralSecurityException- if the source address does not match or decrypting or validating the response fails
tokenRequestSent
Note that we just sent a token request packet and save it for retransmission.- Parameters:
packet- the datagram packet sent
requestSent
Note that we just sent the SessionRequest packet and save it for retransmission.- Parameters:
pkt- the datagram packet sent
confirmedPacketsSent
Note that we just sent the SessionConfirmed packets and save them for retransmission.- Parameters:
packets- the UDP packets sent- Returns:
- the new PeerState2, may also be retrieved from
getPeerState()
getRetransmitSessionRequestPacket
A packet to retransmit the SessionRequest.- Returns:
- null if not sent or already got the session created
getPeerState
The peer state for this connection.- Returns:
- null if we have not sent the session confirmed
getIntroState
The current state for the SSU2 introducer specified.- Parameters:
h- the introducer hash- Returns:
- non-null current state for the SSU2 introducer specified, or INTRO_STATE_INVALID if peer is not an SSU2 introducer
setIntroState
The current state for the SSU2 introducer specified.- Parameters:
h- the introducer hashstate- the new state
introSent
A relay request was sent to the SSU2 introducer specified.- Parameters:
h- the introducer hash
toShortString
String toShortString()Compact one-line establish-state identifier for log output: peer hash and current state. No lifetime or introducer details, no newlines.- Returns:
- the peer hash and state, on one line
toString
Description copied from class:OutboundEstablishStateString representation.- Overrides:
toStringin classOutboundEstablishState
countIntroducers
public int countIntroducers()Number of current introducers.- Returns:
- the number of introducers
_x