- All Implemented Interfaces:
EstablishState, NTCP2Payload.PayloadCallback
This class manages the complete inbound NTCP 2 connection lifecycle:
- Receives and processes Alice's handshake messages (1 and 3)
- Sends Bob's responses (messages 2 and 4)
- Performs Noise protocol XK handshake with Elligator2
- Validates peer RouterInfo and signatures
- Establishes data phase keys (ChaChaPoly + SipHash)
- Handles clock skew detection and peer banlisting
State transitions:
IB_INIT -> IB_NTCP2_INIT -> IB_NTCP2_GOT_X -> IB_NTCP2_GOT_PADDING
-> IB_NTCP2_SENT_Y -> IB_NTCP2_GOT_RI -> VERIFIED
Threading: All methods are synchronized. Caller must hold locks when invoking methods that modify state.
Nested Class Summary
Nested classes/interfaces inherited from class EstablishBase
EstablishBase.StateModifier and TypeClassDescriptionprotected static enumStates for NTCP connection establishment process.Field Summary
FieldsModifier and TypeFieldDescriptionprivate RouterIdentityAlice's RouterIdentity, set aftergotRI(RouterInfo, boolean, boolean)validation succeeds.private final BanLoggerLogs and times the bans this peer earns.private byte[]Current encrypted block we are reading (IB only) or an IV buf used at the end for OB.private static final ByteCacheCache for read buffers.private HandshakeStateNoise protocol handshake state for XK pattern.private NTCP2OptionsAlice's negotiated options from message 3.private intReason code for handshake failure; negative means success, non-negative is failure reason.private intLength of message 3 part 2 (RI + signature).private ByteArrayTemporary buffer for receiving message 3.private intLength of padding specified in message 1 options, used for probing resistance.private ByteArrayCached payload buffer for message 3 processing to reduce pool overhead.private booleanFlag to ensurereleaseBufs(boolean)is called only once.private intNTCP version in use, 2 until the hello says otherwise.private static final intBuffer size for reading data phase packets (16 KB), same as I2PTunnelRunner.private static final intMaximum number of read buffers to cache (32 on slow devices, 64 otherwise).private static final intMaximum message 3 part 2 size (6000 bytes, less than full buffer).private static final intMinimum message 3 part 2 size: header (1+2+1) + RI_MIN + MAC (16).private static final intMaximum padding for probing resistance strategy (128 bytes).private static final intMinimum RouterInfo size: DSA signature (40) + overhead (8+1+1+2+387).private static final Set<EstablishBase.State> The set of states that are part of NTCP 2 protocol processing.Fields inherited from class EstablishBase
_con, _context, _failReason, _log, _peerSkew, _prevEncrypted, _received, _state, _stateLock, _transport, _X, _Y, AES_SIZE, FAILED, STATES_DONE, VERIFIEDModifier and TypeFieldDescriptionprotected final NTCPConnectionConnection being established by this handshake.protected final RouterContextRouter context, supplied to the subclass that constructs this.protected StringWhy the handshake failed, or null while it is still viable.protected final LogLog scoped to the subclass that constructs this.protected longOUR clock minus HIS clock, in seconds.protected byte[]Previously received encrypted block (or the IV).protected intBytes received so far.protected EstablishBase.StateCurrent handshake state, replaced under the state lock.protected final ObjectMonitor serialising every handshake state change.protected final NTCPTransportNTCP transport running this handshake.protected final byte[]Key block Bob receives and Alice sends, doubled as padding on inbound handshakes.protected final byte[]Key block Alice receives and Bob sends, null on outbound handshakes.protected static final intAES block and key size in bytes.static final EstablishBase.FailedEstablishStateShared instance marking a handshake that ended in corruption.protected static final Set<EstablishBase.State> The two terminal states, VERIFIED and CORRUPT.static final EstablishBase.VerifiedEstablishStateShared instance marking a handshake that completed and verified successfully.Constructor Summary
ConstructorsConstructorDescriptionInboundEstablishState(RouterContext ctx, NTCPTransport transport, NTCPConnection con) Creates a new InboundEstablishState for the given context, transport, and connection.Method Summary
Modifier and TypeMethodDescriptionprivate voidDecodes the first 32 bytes (X) from the inbound NTCP2 message 1.protected voidHandles handshake failure by transitioning to CORRUPT state and cleaning up.intNTCP version.voidgotDateTime(long time) Illegal during handshake - date/time is only in the options, not a separate payload.voidgotI2NP(I2NPMessage msg) Illegal during handshake - I2NP messages are only in the data phase.voidgotOptions(byte[] options, boolean isHandshake) Receives and validates Alice's option preferences from message 3.voidgotPadding(int paddingLength, int frameLength) Receives padding information from message 3.voidgotRI(RouterInfo ri, boolean isHandshake, boolean flood) Validates Alice's RouterInfo and extracts the static key for comparison.voidgotTermination(int reason, long lastReceived) Illegal during handshake - termination is only valid after connection is established.voidgotUnknown(int type, int len) Illegal during handshake - unknown payload types should not appear.static StringparseReason(int reasonCode) Converts a termination reason code to a human-readable string.private voidMessage 2 of the NTCP 2 handshake, built and queued for sending to Alice.voidreceive(ByteBuffer src) Entry point for receiving data on an inbound NTCP connection.private voidreceiveInbound(ByteBuffer src) Receives bytes as part of an inbound connection (Bob's perspective).private voidNTCP2 only.protected voidreleaseBufs(boolean isVerified) Releases buffers and resources held by this state machine.private voidsetDataPhase(ByteBuffer buf) Performs key derivation for the NTCP 2 data phase and transitions connection state.private booleanverifyInbound(Hash aliceHash) Validates an inbound peer's identity and eligibility for connection.private booleanverifyInboundNetworkID(RouterInfo alice) Validates the network ID from a peer's RouterInfo.Methods inherited from class EstablishBase
_x, changeState, close, fail, fail, getFailReason, isComplete, isCorrupt, prefix, prepareOutbound, storeFailCause, toStringModifier and TypeMethodDescriptionprotected static final StringMarker function for i18n, returns the string unchanged.protected voidchangeState(EstablishBase.State state) Change the handshake state and update completion/corruption flags.voidRelease resources on timeout.protected voidFail the handshake.protected voidFail the handshake with exception.Failure reason if the handshake failed, or null if not failed/corrupt.booleanIf synchronized on this, fails with deadlocks from all over viaCSFI.isEstablished().booleanDid the handshake fail for some reason?protected Stringprefix()Logging prefix string.voidDoes nothing.(package private) static StringThe bare cause from a netdb store rejection, stripped of the "Invalid NetDbStore attempt" wrapper, capability flags and router ID.toString()String representation of this state.
Field Details
_curEncrypted
private byte[] _curEncryptedCurrent encrypted block we are reading (IB only) or an IV buf used at the end for OB._aliceIdent
Alice's RouterIdentity, set aftergotRI(RouterInfo, boolean, boolean)validation succeeds._released
private volatile boolean _releasedFlag to ensurereleaseBufs(boolean)is called only once._handshakeState
Noise protocol handshake state for XK pattern._padlen1
private int _padlen1Length of padding specified in message 1 options, used for probing resistance._msg3p2len
private int _msg3p2lenLength of message 3 part 2 (RI + signature)._msg3p2FailReason
private int _msg3p2FailReasonReason code for handshake failure; negative means success, non-negative is failure reason._msg3tmp
Temporary buffer for receiving message 3._payloadTmp
Cached payload buffer for message 3 processing to reduce pool overhead._hisPadding
Alice's negotiated options from message 3._version
private int _versionNTCP version in use, 2 until the hello says otherwise.BUFFER_SIZE
private static final int BUFFER_SIZEBuffer size for reading data phase packets (16 KB), same as I2PTunnelRunner.- See Also:
MAX_DATA_READ_BUFS
private static final int MAX_DATA_READ_BUFSMaximum number of read buffers to cache (32 on slow devices, 64 otherwise)._dataReadBufs
Cache for read buffers.PADDING1_FAIL_MAX
private static final int PADDING1_FAIL_MAXMaximum padding for probing resistance strategy (128 bytes).- See Also:
RI_MIN
private static final int RI_MINMinimum RouterInfo size: DSA signature (40) + overhead (8+1+1+2+387).- See Also:
MSG3P2_MIN
private static final int MSG3P2_MINMinimum message 3 part 2 size: header (1+2+1) + RI_MIN + MAC (16).- See Also:
MSG3P2_MAX
private static final int MSG3P2_MAXMaximum message 3 part 2 size (6000 bytes, less than full buffer).- See Also:
STATES_NTCP2
The set of states that are part of NTCP 2 protocol processing._banLogger
Logs and times the bans this peer earns.
Constructor Details
InboundEstablishState
Creates a new InboundEstablishState for the given context, transport, and connection.- Parameters:
ctx- the router contexttransport- the NTCP transportcon- the NTCP connection
Method Details
receive
Entry point for receiving data on an inbound NTCP connection. Parses the contents of the buffer as part of the handshake.Delegates to
receiveInbound(ByteBuffer)for actual processing. All data is copied out of the buffer asReader.processRead(NTCPConnection)will return it to the pool.If there are additional data in the buffer after the handshake is complete, this EstablishState is responsible for passing it to NTCPConnection.
- Specified by:
receivein interfaceEstablishState- Overrides:
receivein classEstablishBase- Parameters:
src- the ByteBuffer containing received data; caller must not modify position
getVersion
public int getVersion()NTCP version.- Specified by:
getVersionin interfaceEstablishState- Specified by:
getVersionin classEstablishBase- Returns:
- 2-5 or 0 if unknown
receiveInbound
Receives bytes as part of an inbound connection (Bob's perspective).This method dispatches to the appropriate handler based on state:
EstablishBase.State.IB_INIT: Waits for sufficient data to determine NTCP versionSTATES_NTCP2: Delegates to receiveInboundNTCP2()
For NTCP 2, this method receives messages 1 and 3 from Alice, and sends messages 2 and 4 in response.
All data must be copied out of the buffer as
Reader.processRead(NTCPConnection)will return it to the pool.- Parameters:
src- the ByteBuffer containing received data; data is copied out
decodeInboundNTCP2X
Decodes the first 32 bytes (X) from the inbound NTCP2 message 1. Performs replay check, decryption, zero-key check, and MSB-based version detection.- Parameters:
src- the inbound data buffer to read X from
verifyInbound
Validates an inbound peer's identity and eligibility for connection.Performs the following checks after receiving Alice's RouterIdentity in message 3:
- Banlist checks (permanent, hostile, temporary)
- IP address recording for banlisted peers
- Clock skew validation and adjustment
- Clock update (desperate one-time adjustment)
Side effects:
- Sets _msg3p2FailReason when returning false
- May blocklist the peer's IP address
- May update the router's clock offset
- Parameters:
aliceHash- the hash of Alice's RouterIdentity to validate- Returns:
- true if the peer is valid and connection should proceed; false if validation failed (caller should return immediately)
verifyInboundNetworkID
Validates the network ID from a peer's RouterInfo.NTCP 2 only. This is called when storing the RouterInfo in the network database fails, to validate the network identifier before rejecting the connection.
Side effects when returning false:
- Sets _msg3p2FailReason to REASON_BANNED
- Blocklists the peer's IP address
- Marks the router as unreachable
- Parameters:
alice- the RouterInfo received from Alice- Returns:
- true if network IDs match; false if they don't
receiveInboundNTCP2
NTCP2 only. State must be one of IB_NTCP2_*. Decoded X must be in _X. Remaining part of msg1 must be in _X or src. Padding if any is still in src and will be read here.Side effect: Sets state to IB_NTCP2_GOT_MSG1, IB_NTCP2_GOT_PADDING, or a failure state.
we are Bob, so receive these bytes as part of an inbound connection This method receives messages 1 and 3, and sends message 2.
All data must be copied out of the buffer as
Reader.processRead(NTCPConnection)will return it to the pool.- Parameters:
src- the inbound data buffer holding the rest of message 1 and any padding
prepareOutbound2
private void prepareOutbound2()Message 2 of the NTCP 2 handshake, built and queued for sending to Alice.Message 2 contains:
- Bob's Noise public key (Y), 32 bytes
- Options: padding length (2 bytes), timestamp (4 bytes)
- Padding (variable length, scaled to the peer's message 1 padding: 0-222 bytes, or up to the version's limit once the peer used long padding)
- AES-CBC MAC (16 bytes)
The IV for CBC encryption must be in _prevEncrypted (extracted from the last 16 bytes of Alice's X in message 1).
After sending, transitions to IB_NTCP2_SENT_Y and waits for message 3.
setDataPhase
Performs key derivation for the NTCP 2 data phase and transitions connection state.This method is called after successfully receiving and validating message 3. It performs the following:
- Splits the Noise handshake to derive ChaChaPoly cipher states
- Generates SipHash keys for message authentication
- Either finishes the connection or sends termination
- Processes any "extra" data in the buffer for the data phase
- Zeros out sensitive key material
On success (_msg3p2FailReason < 0):
- Calls con.finishInboundEstablishment() with keys and states
- Transitions to VERIFIED state
On failure (_msg3p2FailReason >= 0):
- Calls con.failInboundEstablishment() with termination reason
- Transitions to CORRUPT state
Note: If you don't call this method, call
EstablishBase.fail(String)directly.- Parameters:
buf- ByteBuffer possibly containing "extra" data for immediate processing in the data phase; typically present for inbound connections
gotRI
Validates Alice's RouterInfo and extracts the static key for comparison.This is a PayloadCallback method invoked during message 3 processing.
Validations performed:
- Ensures RouterInfo contains an NTCP2-capable address
- Extracts and validates the "s" (static key) option
- Compares static key against the Noise handshake public key
- Verifies the peer's identity via verifyInbound()
- Checks IP address consistency (RI-published vs. actual connection)
- Validates router version, capabilities, and network ID
- Stores RouterInfo in the network database
Side effects:
- Sets _msg3p2FailReason on validation failure
- May banlist the peer hash and/or blocklist the IP
- Stores RouterInfo in netdb
- Sets _aliceIdent and calls con.setRemotePeer()
- Specified by:
gotRIin interfaceNTCP2Payload.PayloadCallback- Parameters:
ri- Alice's RouterInfo from message 3isHandshake- always true; indicates this is during handshake processingflood- true if the RouterInfo should be flooded to the network- Throws:
DataFormatException- if validation fails (bad sig, no static key, key mismatch, IP mismatch, banned, etc.)
gotOptions
public void gotOptions(byte[] options, boolean isHandshake) Receives and validates Alice's option preferences from message 3.Parses the options byte array into an NTCP2Options object containing negotiated parameters like congestion control and flags.
- Specified by:
gotOptionsin interfaceNTCP2Payload.PayloadCallback- Parameters:
options- the options byte array from AliceisHandshake- always true; indicates this is during handshake processing
gotPadding
public void gotPadding(int paddingLength, int frameLength) Receives padding information from message 3.NTCP 2 padding is handled differently - the actual padding data is not separately tracked in this implementation.
- Specified by:
gotPaddingin interfaceNTCP2Payload.PayloadCallback- Parameters:
paddingLength- the length of padding in the frameframeLength- the total length of the frame including padding
gotTermination
public void gotTermination(int reason, long lastReceived) Illegal during handshake - termination is only valid after connection is established. Stub implementations are required by the PayloadCallback interface, and these payload types will never be received.- Specified by:
gotTerminationin interfaceNTCP2Payload.PayloadCallback- Parameters:
reason- the termination reason codelastReceived- the number of bytes received when termination occurred
gotUnknown
public void gotUnknown(int type, int len) Illegal during handshake - unknown payload types should not appear.- Specified by:
gotUnknownin interfaceNTCP2Payload.PayloadCallback- Parameters:
type- the unknown payload typelen- the payload length
gotDateTime
public void gotDateTime(long time) Illegal during handshake - date/time is only in the options, not a separate payload.- Specified by:
gotDateTimein interfaceNTCP2Payload.PayloadCallback- Parameters:
time- ignored, since the payload is never parsed during the handshake
gotI2NP
Illegal during handshake - I2NP messages are only in the data phase.- Specified by:
gotI2NPin interfaceNTCP2Payload.PayloadCallback- Parameters:
msg- the I2NP message
fail
Handles handshake failure by transitioning to CORRUPT state and cleaning up.Overrides the base implementation to additionally destroy the Noise handshake state for security.
- Overrides:
failin classEstablishBase- Parameters:
reason- the failure reason stringe- the exception that caused the failure, or nullbySkew- true if failure was due to clock skew (suppresses stat collection)
releaseBufs
protected void releaseBufs(boolean isVerified) Releases buffers and resources held by this state machine.Must be called exactly once when the handshake completes (success or failure). Caller must hold synchronization.
Actions:
- Releases _curEncrypted buffer if verification failed (passed to NTCPConnection on success)
- Zeros out _X buffer for security
- Releases _X and _msg3tmp buffers back to caches
- Overrides:
releaseBufsin classEstablishBase- Parameters:
isVerified- true if handshake succeeded; false if it failed
parseReason
Converts a termination reason code to a human-readable string.Reason codes are defined in
NTCPConnectionand used in termination messages to indicate why a connection failed.- Parameters:
reasonCode- the numeric reason code from NTCPConnection- Returns:
- a descriptive string for the reason code