java.lang.Object
net.i2p.router.tunnel.FragmentHandler

class FragmentHandlerextends Object
Handle fragments at the endpoint of a tunnel, peeling off fully completed I2NPMessages when they arrive, and dropping fragments if they take too long to arrive.

From tunnel-alt.html.

When the gateway wants to deliver data through the tunnel, it first gathers zero or more I2NP messages, selects how much padding will be used, fragments it across the necessary number of 1KB tunnel messages, and decides how each I2NP message should be handled by the tunnel endpoint, encoding that data into the raw tunnel payload:

  • The 4 byte Tunnel ID
  • The 16 byte IV
  • the first 4 bytes of the SHA256 of (the remaining preprocessed data concatenated with the IV), using the IV as will be seen on the tunnel endpoint (for outbound tunnels), or the IV as was seen on the tunnel gateway (for inbound tunnels) (see below for IV processing).
  • 0 or more bytes containing random nonzero integers
  • 1 byte containing 0x00
  • a series of zero or more { instructions, message } pairs

Note that the padding, if any, must be before the instruction/message pairs. there is no provision for padding at the end.

The instructions are encoded with a single control byte, followed by any necessary additional information. The first bit in that control byte determines how the remainder of the header is interpreted - if it is not set, the message is either not fragmented or this is the first fragment in the message. If it is set, this is a follow on fragment.

With the first (leftmost or MSB) bit being 0, the instructions are:

  • 1 byte control byte:
          bit 7: is follow on fragment?  (1 = true, 0 = false, must be 0)
       bits 6-5: delivery type
                 (0x0 = LOCAL, 0x01 = TUNNEL, 0x02 = ROUTER)
          bit 4: delay included?  (1 = true, 0 = false) (unimplemented)
          bit 3: fragmented?  (1 = true, 0 = false)
          bit 2: extended options?  (1 = true, 0 = false) (unimplemented)
       bits 1-0: reserved
  • if the delivery type was TUNNEL, a 4 byte tunnel ID
  • if the delivery type was TUNNEL or ROUTER, a 32 byte router hash
  • if the delay included flag is true, a 1 byte value (unimplemented):
          bit 7: type (0 = strict, 1 = randomized)
       bits 0-6: delay exponent (2^value minutes)
  • if the fragmented flag is true, a 4 byte message ID
  • if the extended options flag is true (unimplemented):
       = a 1 byte option size (in bytes)
       = that many bytes
  • 2 byte size of the I2NP message or this fragment

If the first bit being 1, the instructions are:

  • 1 byte control byte:
          bit 7: is follow on fragment?  (1 = true, 0 = false, must be 1)
       bits 6-1: fragment number
          bit 0: is last? (1 = true, 0 = false)
  • 4 byte message ID (same one defined in the first fragment)
  • 2 byte size of this fragment

The I2NP message is encoded in its standard form, and the preprocessed payload must be padded to a multiple of 16 bytes. The total size, including the tunnel ID and IV, is 1028 bytes.

  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Class
    Description
    static interface 
    Receive messages out of the tunnel endpoint.
  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    protected final RouterContext
    The router context.
    protected final Log
    The log.
    (package private) static final byte
    Are there follow-up headers? UNIMPLEMENTED.
    (package private) static final byte
    Is this the first fragment of a fragmented message?
    (package private) static final byte
    Is this a follow-up byte?
    (package private) static final byte
    How this should be delivered.
    (package private) static long
    Don't wait more than this long to completely receive a fragmented message.
    (package private) static final int
    Maximum number of partially reassembled messages held at once.
    (package private) static final short
    Local delivery.
    (package private) static final short
    Router delivery.
    (package private) static final short
    Tunnel delivery.
    (package private) static final short
    Undefined delivery.
  • Constructor Summary

    Constructors
    Constructor
    Description
    For unit tests only, others use 3-arg constructor.
    FragmentHandler(RouterContext context, FragmentHandler.DefragmentedReceiver receiver, boolean isInbound)
    Binds the given context and receiver, storing the inbound flag.
  • Method Summary

    Modifier and Type
    Method
    Description
    int
    Fragments received and complete.
    int
    Fragments that failed.
    (package private) FragmentedMessage
    getOrCreate(int messageId, long fMessageId)
    Get the message being reassembled for the given ID, starting it if this is its first fragment.
    (package private) static int[]
    hashRanges(int offset, int validLength, int paddingEnd)
    The two byte ranges the inbound verifier must hash, in the order they must be fed to the digest: {payloadOffset, payloadLength, ivOffset, ivLength}.
    (package private) static boolean
    Determine whether another message may begin reassembling given how many are already in progress.
    boolean
    receiveTunnelMessage(byte[] preprocessed, int offset, int length)
    Receive the raw preprocessed message at the endpoint, parsing out each of the fragments, using those to fill various FragmentedMessages, and sending the resulting I2NPMessages where necessary.

    Methods inherited from class Object

    clone, equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Field Details

    • _context

      protected final RouterContext _context
      The router context.
    • _log

      protected final Log _log
      The log.
    • MAX_DEFRAGMENT_TIME

      static long MAX_DEFRAGMENT_TIME
      Don't wait more than this long to completely receive a fragmented message.
    • MAX_FRAGMENTED_MESSAGES

      static final int MAX_FRAGMENTED_MESSAGES
      Maximum number of partially reassembled messages held at once. Entries expire after MAX_DEFRAGMENT_TIME, but a peer that sends fragments for many distinct message IDs faster than they expire would otherwise grow the map without bound, so new messages are refused while the map is at the limit and the remaining fragments of those messages are dropped.
      See Also:
    • MASK_IS_SUBSEQUENT

      static final byte MASK_IS_SUBSEQUENT
      Is this a follow-up byte?
      See Also:
    • MASK_TYPE

      static final byte MASK_TYPE
      How this should be delivered. Shift right 5 to get TYPE_*.
      See Also:
    • MASK_FRAGMENTED

      static final byte MASK_FRAGMENTED
      Is this the first fragment of a fragmented message?
      See Also:
    • MASK_EXTENDED

      static final byte MASK_EXTENDED
      Are there follow-up headers? UNIMPLEMENTED.
      See Also:
    • TYPE_LOCAL

      static final short TYPE_LOCAL
      Local delivery.
      See Also:
    • TYPE_TUNNEL

      static final short TYPE_TUNNEL
      Tunnel delivery.
      See Also:
    • TYPE_ROUTER

      static final short TYPE_ROUTER
      Router delivery.
      See Also:
    • TYPE_UNDEF

      static final short TYPE_UNDEF
      Undefined delivery.
      See Also:
  • Constructor Details

    • FragmentHandler

      public FragmentHandler(RouterContext context, FragmentHandler.DefragmentedReceiver receiver)
      For unit tests only, others use 3-arg constructor.
      Parameters:
      context - the router context
      receiver - callback that receives each fully reassembled message
    • FragmentHandler

      public FragmentHandler(RouterContext context, FragmentHandler.DefragmentedReceiver receiver, boolean isInbound)
      Binds the given context and receiver, storing the inbound flag.
      Parameters:
      context - the router context
      receiver - the defragmented receiver
      isInbound - true for IBEP, false for OBEP
  • Method Details

    • receiveTunnelMessage

      public boolean receiveTunnelMessage(byte[] preprocessed, int offset, int length)
      Receive the raw preprocessed message at the endpoint, parsing out each of the fragments, using those to fill various FragmentedMessages, and sending the resulting I2NPMessages where necessary. The received fragments are all verified.
      Parameters:
      preprocessed - the preprocessed message as read from the transport
      offset - index in the buffer at which the message starts
      length - number of bytes of the message to process
      Returns:
      ok (false if corrupt)
    • getCompleteCount

      public int getCompleteCount()
      Fragments received and complete.
      Returns:
      the number of fragments that completed
    • getFailedCount

      public int getFailedCount()
      Fragments that failed.
      Returns:
      the number of fragments that failed
    • hashRanges

      static int[] hashRanges(int offset, int validLength, int paddingEnd)
      The two byte ranges the inbound verifier must hash, in the order they must be fed to the digest: {payloadOffset, payloadLength, ivOffset, ivLength}.

      The preprocessed buffer holds the IV at the front, but the spec hashes the payload followed by the IV, so the IV range is returned second even though it comes first in the buffer. Hashing IV first would yield a different digest and fail every message, so the order here is load-bearing.

      Parameters:
      offset - where this message's data starts within the buffer
      validLength - total number of bytes hashed, payload plus the IV
      paddingEnd - one past the final padding byte, i.e. where the payload starts
      Returns:
      {payloadOffset, payloadLength, ivOffset, ivLength} in hash order
    • mayStartNewFragmentedMessage

      static boolean mayStartNewFragmentedMessage(int activeCount)
      Determine whether another message may begin reassembling given how many are already in progress. Refused messages are dropped until older ones complete or expire, which bounds the memory a single peer can pin.
      Parameters:
      activeCount - messages currently being reassembled
      Returns:
      true if a new message may be started
    • getOrCreate

      FragmentedMessage getOrCreate(int messageId, long fMessageId)
      Get the message being reassembled for the given ID, starting it if this is its first fragment. Refuses to start a new message while the map is at its cap; fragments of messages already in progress are always accepted so an existing reassembly can still finish.
      Parameters:
      messageId - the message ID
      fMessageId - the message ID as a long, for the new message
      Returns:
      the message, or null if a new message may not be started