java.lang.Object
net.i2p.router.transport.udp.SSU2Payload

class SSU2Payloadextends Object
SSU2 Payload generation and parsing utilities.
  • Field Details

    • BLOCK_ACK

      static final int BLOCK_ACK
      SSU2 block type: ACK.
      See Also:
    • BLOCK_ADDRESS

      static final int BLOCK_ADDRESS
      SSU2 block type: ADDRESS.
      See Also:
    • BLOCK_DATETIME

      static final int BLOCK_DATETIME
      SSU2 block type: DATETIME (must be the first block of a handshake).
      See Also:
    • BLOCK_FIRSTFRAG

      static final int BLOCK_FIRSTFRAG
      SSU2 block type: FIRSTFRAG.
      See Also:
    • BLOCK_FOLLOWONFRAG

      static final int BLOCK_FOLLOWONFRAG
      SSU2 block type: FOLLOWONFRAG.
      See Also:
    • BLOCK_I2NP

      static final int BLOCK_I2NP
      SSU2 block type: I2NP.
      See Also:
    • BLOCK_NEWTOKEN

      static final int BLOCK_NEWTOKEN
      SSU2 block type: NEWTOKEN.
      See Also:
    • BLOCK_OPTIONS

      static final int BLOCK_OPTIONS
      SSU2 block type: OPTIONS.
      See Also:
    • BLOCK_PADDING

      static final int BLOCK_PADDING
      SSU2 block type: PADDING (must end the block list).
      See Also:
    • BLOCK_PATHCHALLENGE

      static final int BLOCK_PATHCHALLENGE
      SSU2 block type: PATHCHALLENGE.
      See Also:
    • BLOCK_PATHRESP

      static final int BLOCK_PATHRESP
      SSU2 block type: PATHRESP.
      See Also:
    • BLOCK_PEERTEST

      static final int BLOCK_PEERTEST
      SSU2 block type: PEERTEST.
      See Also:
    • BLOCK_RELAYINTRO

      static final int BLOCK_RELAYINTRO
      SSU2 block type: RELAYINTRO.
      See Also:
    • BLOCK_RELAYREQ

      static final int BLOCK_RELAYREQ
      SSU2 block type: RELAYREQ.
      See Also:
    • BLOCK_RELAYRESP

      static final int BLOCK_RELAYRESP
      SSU2 block type: RELAYRESP.
      See Also:
    • BLOCK_RELAYTAG

      static final int BLOCK_RELAYTAG
      SSU2 block type: RELAYTAG.
      See Also:
    • BLOCK_RELAYTAGREQ

      static final int BLOCK_RELAYTAGREQ
      SSU2 block type: RELAYTAGREQ.
      See Also:
    • BLOCK_ROUTERINFO

      static final int BLOCK_ROUTERINFO
      SSU2 block type: ROUTERINFO.
      See Also:
    • BLOCK_HEADER_SIZE

      public static final int BLOCK_HEADER_SIZE
      Bytes of type-and-length prefix that precede the data of every block.
      See Also:
    • BLOCK_TERMINATION

      public static final int BLOCK_TERMINATION
      SSU2 block type: TERMINATION.
      See Also:
  • Constructor Details

    • SSU2Payload

      private SSU2Payload()
      The block writers and parsers below are static, and the only fields are block-type constants, so an instance carries nothing.
  • Method Details

    • processPayload

      public static int processPayload(I2PAppContext ctx, SSU2Payload.PayloadCallback cb, byte[] payload, int off, int length, boolean isHandshake, RemoteHostId from) throws IOException, DataFormatException, I2NPMessageException
      Incoming payload. Calls the callback for each received block.
      Parameters:
      ctx - the application context
      cb - called once per received block
      payload - buffer holding the payload
      off - offset in payload of the first byte
      length - number of bytes to read
      isHandshake - true for Token Req, Retry, Sess Req, Sess Created; false for Sess Confirmed
      from - for path challenge/response only, may be null
      Returns:
      number of blocks processed
      Throws:
      IOException - on major errors
      DataFormatException - on parsing of individual blocks
      I2NPMessageException - on parsing of I2NP block
    • checkBlockOrder

      static void checkBlockOrder(int type, boolean gotPadding, boolean gotTermination, boolean isHandshake, int blocks) throws IOException
      Order-rule guard for the incoming-block scan. Padding must terminate the block list; only padding may follow a termination block; a handshake must start with a DATETIME block. Each violation is a protocol error, thrown as an IOException.
      Parameters:
      type - the current block type byte
      gotPadding - true if a BLOCK_PADDING preceded this block
      gotTermination - true if a BLOCK_TERMINATION preceded this block
      isHandshake - true if this is a handshake frame, where the first block must be DATETIME
      blocks - the number of blocks processed before this one
      Throws:
      IOException - on any ordering violation
    • checkHandshakeNotEmpty

      static void checkHandshakeNotEmpty(boolean isHandshake, int blocks) throws IOException
      Guard that a handshake frame carries at least one block.
      Parameters:
      isHandshake - true if this is a handshake frame
      blocks - the total number of blocks processed in the frame
      Throws:
      IOException - if the frame is a handshake with no blocks
    • checkFrameOverflow

      static void checkFrameOverflow(int off, int length, int dataOff, int len, int blocks, int type) throws IOException
      Guard that a block's declared length fits inside the frame. Offsets in the error message are byte positions relative to the frame. The frame contents are deliberately not included, they may be decrypted data. Callers that want a dump log it at DEBUG.
      Parameters:
      off - start of the payload in the array
      length - frame size in bytes
      dataOff - offset of the block's 2-byte length field
      len - the declared block length
      blocks - the zero-based index of this block for the error message
      type - the block type byte for the error message
      Throws:
      IOException - if the block runs past the end of the frame
    • parseDateTime

      static void parseDateTime(SSU2Payload.PayloadCallback cb, byte[] payload, int i, int len) throws IOException, DataFormatException
      Parse a DATETIME block of exactly 4 bytes.
      Parameters:
      cb - callback
      payload - the whole frame
      i - offset of the block data
      len - declared block length, must be 4
      Throws:
      IOException - on bad length
      DataFormatException - if the callback rejects the timestamp
    • parseOptions

      static void parseOptions(SSU2Payload.PayloadCallback cb, byte[] payload, int i, int len, boolean isHandshake) throws DataFormatException
      Parse an OPTIONS block, copying the option bytes for the callback.
      Parameters:
      cb - callback
      payload - the whole frame
      i - offset of the block data
      len - declared block length
      isHandshake - passed through to the callback
      Throws:
      DataFormatException - if the callback rejects the options
    • parseRouterInfo

      static void parseRouterInfo(I2PAppContext ctx, SSU2Payload.PayloadCallback cb, byte[] payload, int i, int len, boolean isHandshake) throws IOException, DataFormatException
      Parse a ROUTERINFO block: one- or two-byte header, then either a single (possibly compressed) RouterInfo or a fragment piece.
      Parameters:
      ctx - context for decompression and logging
      cb - callback
      payload - the whole frame
      i - offset of the block data
      len - declared block length, must be > 1
      isHandshake - passed through to the callback
      Throws:
      IOException - on framing errors
      DataFormatException - if the RouterInfo is too large or fails verification
    • parseRouterInfoSingle

      static RouterInfo parseRouterInfoSingle(I2PAppContext ctx, ByteArrayInputStream bais) throws IOException, DataFormatException
      Read a complete RouterInfo from the stream, falling back to an alternate signature verification when the strict parse fails.
      Parameters:
      ctx - context for logging
      bais - the RI bytes, positioned at the start
      Returns:
      the parsed RouterInfo (possibly a partially filled-in one, signalled by RouterInfo.setPublished(long) of -1)
      Throws:
      IOException - on any I/O while reading the stream
      DataFormatException - on a genuinely malformed RI that fails the alternate verification
    • recoverRouterInfo

      Alternate verification of a RouterInfo whose strict parse failed: if the signed prefix is valid, return a partially filled-in RI (published = -1) so the session layer can still act on the identity.
      Parameters:
      ctx - context for logging
      bais - the RI bytes; position is reset for re-reading identity and signature
      dfe - the original parse failure
      Returns:
      a partially filled-in RouterInfo when the signature verifies
      Throws:
      IOException - on any I/O while re-reading the stream
      DataFormatException - the original parse failure when verification fails
    • parseI2NP

      static void parseI2NP(I2PAppContext ctx, SSU2Payload.PayloadCallback cb, byte[] payload, int i, int len, boolean isHandshake) throws IOException, I2NPMessageException
      Parse an I2NP block (data blocks only, never in handshakes).
      Parameters:
      ctx - context for I2NP parsing
      cb - callback
      payload - the whole frame
      i - offset of the block data
      len - declared block length, must be ≥ 9
      isHandshake - if true the block is illegal
      Throws:
      IOException - if the block appears in a handshake or is too short
      I2NPMessageException - if the embedded I2NP message is malformed
    • parseFirstFragment

      static void parseFirstFragment(SSU2Payload.PayloadCallback cb, byte[] payload, int i, int len, boolean isHandshake) throws IOException, DataFormatException
      Parse the first fragment of a fragmented message (data blocks only). The 1-byte flag and 4-byte message ID precede the fragment data; the callback receives the raw payload slice.
      Parameters:
      cb - callback
      payload - the whole frame
      i - offset of the block data
      len - declared block length, must be > 9
      isHandshake - if true the block is illegal
      Throws:
      IOException - if the block appears in a handshake or is too short
      DataFormatException - if the callback rejects the fragment
    • parseFollowonFragment

      static void parseFollowonFragment(SSU2Payload.PayloadCallback cb, byte[] payload, int i, int len, boolean isHandshake) throws IOException, DataFormatException
      Parse a follow-on fragment block (data blocks only). The low bit of the flag byte marks the last fragment; the remaining bits carry the fragment number.
      Parameters:
      cb - callback
      payload - the whole frame
      i - offset of the block data
      len - declared block length, must be > 5
      isHandshake - if true the block is illegal
      Throws:
      IOException - if the block appears in a handshake, is too short, or has fragment number 0
      DataFormatException - if the callback rejects the fragment
    • parseACK

      static void parseACK(SSU2Payload.PayloadCallback cb, byte[] payload, int i, int len, boolean isHandshake) throws IOException
      Parse an ACK block (data blocks only). Odd block length: 4-byte ack ID, 1-byte fragment count, then the ACK range bitmap (possibly zero length).
      Parameters:
      cb - callback
      payload - the whole frame
      i - offset of the block data
      len - declared block length, must be ≥ 5 and odd
      isHandshake - if true the block is illegal
      Throws:
      IOException - if the block appears in a handshake or has a bad length
    • parseAddress

      static void parseAddress(SSU2Payload.PayloadCallback cb, byte[] payload, int i, int len) throws IOException
      Parse an ADDRESS block of 4 bytes IPv4 or 16 bytes IPv6.
      Parameters:
      cb - callback
      payload - the whole frame
      i - offset of the block data
      len - declared block length, must be 6 or 18
      Throws:
      IOException - on bad length
    • parseRelayTag

      static void parseRelayTag(SSU2Payload.PayloadCallback cb, byte[] payload, int i, int len) throws IOException
      Parse a RELAYTAG block of at least 4 bytes.
      Parameters:
      cb - callback
      payload - the whole frame
      i - offset of the block data
      len - declared block length, must be ≥ 4
      Throws:
      IOException - on bad length
    • parseRelayRequest

      static void parseRelayRequest(SSU2Payload.PayloadCallback cb, byte[] payload, int i, int len, boolean isHandshake) throws IOException
      Parse a RELAYREQ block (data blocks only): 1 flag byte then the relay request (IPv4 address + DSA signature).
      Parameters:
      cb - callback
      payload - the whole frame
      i - offset of the block data
      len - declared block length, must be ≥ 61
      isHandshake - if true the block is illegal
      Throws:
      IOException - if the block appears in a handshake or is too short
    • parseRelayResponse

      static void parseRelayResponse(SSU2Payload.PayloadCallback cb, byte[] payload, int i, int len, boolean isHandshake) throws IOException
      Parse a RELAYRESP block (data blocks only): 1 flag byte, 1 response code byte, and the remaining response data.
      Parameters:
      cb - callback
      payload - the whole frame
      i - offset of the block data
      len - declared block length, must be ≥ 52
      isHandshake - if true the block is illegal
      Throws:
      IOException - if the block appears in a handshake or is too short
    • parseRelayIntro

      static void parseRelayIntro(SSU2Payload.PayloadCallback cb, byte[] payload, int i, int len, boolean isHandshake) throws IOException
      Parse a RELAYINTRO block (data blocks only): 1 flag byte, the 32-byte introducer hash, then the intro data.
      Parameters:
      cb - callback
      payload - the whole frame
      i - offset of the block data
      len - declared block length, must be ≥ 93
      isHandshake - if true the block is illegal
      Throws:
      IOException - if the block appears in a handshake or is too short
    • parsePeerTest

      static void parsePeerTest(SSU2Payload.PayloadCallback cb, byte[] payload, int i, int len, boolean isHandshake) throws IOException, DataFormatException
      Parse a PEERTEST block (data blocks only): message number, response code, an optional 32-byte hash for questions 2/4, and the data payload.
      Parameters:
      cb - callback
      payload - the whole frame
      i - offset of the block data
      len - declared block length, must be ≥ 19
      isHandshake - if true the block is illegal
      Throws:
      IOException - if the block appears in a handshake or is too short
      DataFormatException - if the message number is out of the 1-7 range
    • parseNewToken

      static void parseNewToken(SSU2Payload.PayloadCallback cb, byte[] payload, int i, int len) throws IOException
      Parse a NEWTOKEN block of at least 12 bytes: 4-byte expiry, 8-byte token.
      Parameters:
      cb - callback
      payload - the whole frame
      i - offset of the block data
      len - declared block length, must be ≥ 12
      Throws:
      IOException - on bad length
    • parseTermination

      static void parseTermination(SSU2Payload.PayloadCallback cb, byte[] payload, int i, int len) throws IOException
      Parse a TERMINATION block of at least 9 bytes: 8-byte receive time, 1 byte reason code. The caller must flag the frame as terminated.
      Parameters:
      cb - callback
      payload - the whole frame
      i - offset of the block data
      len - declared block length, must be ≥ 9
      Throws:
      IOException - on bad length
    • parsePathChallenge

      static void parsePathChallenge(SSU2Payload.PayloadCallback cb, byte[] payload, int i, int len, boolean isHandshake, RemoteHostId from) throws IOException
      Parse a PATHCHALLENGE block (data blocks only), passing the challenge array up with the originating address.
      Parameters:
      cb - callback
      payload - the whole frame
      i - offset of the block data
      len - declared block length
      isHandshake - if true the block is illegal
      from - the originating address, may be null
      Throws:
      IOException - if the block appears in a handshake
    • parsePathResponse

      static void parsePathResponse(SSU2Payload.PayloadCallback cb, byte[] payload, int i, int len, boolean isHandshake, RemoteHostId from) throws IOException
      Parse a PATHRESP block (data blocks only), passing the response array up with the originating address.
      Parameters:
      cb - callback
      payload - the whole frame
      i - offset of the block data
      len - declared block length
      isHandshake - if true the block is illegal
      from - the originating address, may be null
      Throws:
      IOException - if the block appears in a handshake
    • parseUnknown

      static void parseUnknown(I2PAppContext ctx, SSU2Payload.PayloadCallback cb, int type, int len)
      Unknown block type: warn once per occurrence and skip the block.
      Parameters:
      ctx - context for logging
      cb - callback, included in the message for context
      type - the unknown block type byte
      len - the declared block length
    • writePayload

      public static int writePayload(byte[] payload, int off, List<SSU2Payload.Block> blocks)
      Serialize a list of blocks into a payload.
      Parameters:
      payload - writes to it starting at off
      off - offset in payload to start writing at
      blocks - the blocks to write, in order
      Returns:
      the new offset