java.lang.Object
net.i2p.router.transport.ntcp.EstablishBase
net.i2p.router.transport.ntcp.InboundEstablishState
All Implemented Interfaces:
EstablishState, NTCP2Payload.PayloadCallback

class InboundEstablishStateextends EstablishBase implements NTCP2Payload.PayloadCallback
NTCP 2 inbound connection establishment state machine. Handles the server-side (Bob) of the NTCP 2 handshake process, including cryptographic operations, peer verification, and transition to the data phase.

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.

  • Field Details

    • _curEncrypted

      private byte[] _curEncrypted
      Current encrypted block we are reading (IB only) or an IV buf used at the end for OB.
    • _aliceIdent

      private RouterIdentity _aliceIdent
      Alice's RouterIdentity, set after gotRI(RouterInfo, boolean, boolean) validation succeeds.
    • _released

      private volatile boolean _released
      Flag to ensure releaseBufs(boolean) is called only once.
    • _handshakeState

      private HandshakeState _handshakeState
      Noise protocol handshake state for XK pattern.
    • _padlen1

      private int _padlen1
      Length of padding specified in message 1 options, used for probing resistance.
    • _msg3p2len

      private int _msg3p2len
      Length of message 3 part 2 (RI + signature).
    • _msg3p2FailReason

      private int _msg3p2FailReason
      Reason code for handshake failure; negative means success, non-negative is failure reason.
    • _msg3tmp

      private ByteArray _msg3tmp
      Temporary buffer for receiving message 3.
    • _payloadTmp

      private ByteArray _payloadTmp
      Cached payload buffer for message 3 processing to reduce pool overhead.
    • _hisPadding

      private NTCP2Options _hisPadding
      Alice's negotiated options from message 3.
    • _version

      private int _version
      NTCP version in use, 2 until the hello says otherwise.
    • BUFFER_SIZE

      private static final int BUFFER_SIZE
      Buffer size for reading data phase packets (16 KB), same as I2PTunnelRunner.
      See Also:
    • MAX_DATA_READ_BUFS

      private static final int MAX_DATA_READ_BUFS
      Maximum number of read buffers to cache (32 on slow devices, 64 otherwise).
    • _dataReadBufs

      private static final ByteCache _dataReadBufs
      Cache for read buffers.
    • PADDING1_FAIL_MAX

      private static final int PADDING1_FAIL_MAX
      Maximum padding for probing resistance strategy (128 bytes).
      See Also:
    • RI_MIN

      private static final int RI_MIN
      Minimum RouterInfo size: DSA signature (40) + overhead (8+1+1+2+387).
      See Also:
    • MSG3P2_MIN

      private static final int MSG3P2_MIN
      Minimum message 3 part 2 size: header (1+2+1) + RI_MIN + MAC (16).
      See Also:
    • MSG3P2_MAX

      private static final int MSG3P2_MAX
      Maximum message 3 part 2 size (6000 bytes, less than full buffer).
      See Also:
    • STATES_NTCP2

      private static final Set<EstablishBase.State> STATES_NTCP2
      The set of states that are part of NTCP 2 protocol processing.
    • _banLogger

      private final BanLogger _banLogger
      Logs and times the bans this peer earns.
  • Constructor Details

    • InboundEstablishState

      public InboundEstablishState(RouterContext ctx, NTCPTransport transport, NTCPConnection con)
      Creates a new InboundEstablishState for the given context, transport, and connection.
      Parameters:
      ctx - the router context
      transport - the NTCP transport
      con - the NTCP connection
  • Method Details

    • receive

      public void receive(ByteBuffer src)
      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 as Reader.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:
      receive in interface EstablishState
      Overrides:
      receive in class EstablishBase
      Parameters:
      src - the ByteBuffer containing received data; caller must not modify position
    • getVersion

      public int getVersion()
      NTCP version.
      Specified by:
      getVersion in interface EstablishState
      Specified by:
      getVersion in class EstablishBase
      Returns:
      2-5 or 0 if unknown
    • receiveInbound

      private void receiveInbound(ByteBuffer src)
      Receives bytes as part of an inbound connection (Bob's perspective).

      This method dispatches to the appropriate handler based on state:

      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

      private void decodeInboundNTCP2X(ByteBuffer src)
      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

      private boolean verifyInbound(Hash aliceHash)
      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

      private boolean verifyInboundNetworkID(RouterInfo alice)
      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

      private void receiveInboundNTCP2(ByteBuffer src)
      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

      private void setDataPhase(ByteBuffer buf)
      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

      public void gotRI(RouterInfo ri, boolean isHandshake, boolean flood) throws DataFormatException
      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:
      gotRI in interface NTCP2Payload.PayloadCallback
      Parameters:
      ri - Alice's RouterInfo from message 3
      isHandshake - always true; indicates this is during handshake processing
      flood - 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:
      gotOptions in interface NTCP2Payload.PayloadCallback
      Parameters:
      options - the options byte array from Alice
      isHandshake - 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:
      gotPadding in interface NTCP2Payload.PayloadCallback
      Parameters:
      paddingLength - the length of padding in the frame
      frameLength - 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:
      gotTermination in interface NTCP2Payload.PayloadCallback
      Parameters:
      reason - the termination reason code
      lastReceived - 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:
      gotUnknown in interface NTCP2Payload.PayloadCallback
      Parameters:
      type - the unknown payload type
      len - 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:
      gotDateTime in interface NTCP2Payload.PayloadCallback
      Parameters:
      time - ignored, since the payload is never parsed during the handshake
    • gotI2NP

      public void gotI2NP(I2NPMessage msg)
      Illegal during handshake - I2NP messages are only in the data phase.
      Specified by:
      gotI2NP in interface NTCP2Payload.PayloadCallback
      Parameters:
      msg - the I2NP message
    • fail

      protected void fail(String reason, Exception e, boolean bySkew)
      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:
      fail in class EstablishBase
      Parameters:
      reason - the failure reason string
      e - the exception that caused the failure, or null
      bySkew - 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:
      releaseBufs in class EstablishBase
      Parameters:
      isVerified - true if handshake succeeded; false if it failed
    • parseReason

      public static String parseReason(int reasonCode)
      Converts a termination reason code to a human-readable string.

      Reason codes are defined in NTCPConnection and 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