net.i2p.router.transport.udp

## Class PacketBuilder

- java.lang.Object
- - net.i2p.router.transport.udp.PacketBuilder

-      class PacketBuilder
      extends Object

  Big ol' class to do all our packet formatting. The UDPPackets generated are fully authenticated, encrypted, and configured for delivery to the peer. The following is from udp.html on the website:

  All UDP datagrams begin with a 16 byte MAC (Message Authentication Code) and a 16 byte IV (Initialization Vector followed by a variable size payload encrypted with the appropriate key. The MAC used is HMAC-MD5, truncated to 16 bytes, while the key is a full 32 byte AES256 key. The specific construct of the MAC is the first 16 bytes from:

        HMAC-MD5(payload || IV || (payloadLength ^ protocolVersion), macKey)

  The protocol version is currently 0.

  The payload itself is AES256/CBC encrypted with the IV and the sessionKey, with replay prevention addressed within its body, explained below. The payloadLength in the MAC is a 2 byte unsigned integer in 2s complement.

  The protocolVersion is a 2 byte unsigned integer in 2s complement, and currently set to 0. Peers using a different protocol version will not be able to communicate with this peer, though earlier versions not using this flag are.

  ## Payload

  Within the AES encrypted payload, there is a minimal common structure to the various messages - a one byte flag and a four byte sending timestamp (*seconds* since the unix epoch). The flag byte contains the following bitfields:

        bits 0-3: payload type
           bit 4: rekey?
           bit 5: extended options included
        bits 6-7: reserved

  If the rekey flag is set, 64 bytes of keying material follow the timestamp. If the extended options flag is set, a one byte option size value is appended to, followed by that many extended option bytes, which are currently uninterpreted.

  When rekeying, the first 32 bytes of the keying material is fed into a SHA256 to produce the new MAC key, and the next 32 bytes are fed into a SHA256 to produce the new session key, though the keys are not immediately used. The other side should also reply with the rekey flag set and that same keying material. Once both sides have sent and received those values, the new keys should be used and the previous keys discarded. It may be useful to keep the old keys around briefly, to address packet loss and reordering.

  NOTE: Rekeying is currently unimplemented.

       Header: 37+ bytes
       +----+----+----+----+----+----+----+----+
       |                  MAC                  |
       |                                       |
       +----+----+----+----+----+----+----+----+
       |                   IV                  |
       |                                       |
       +----+----+----+----+----+----+----+----+
       |flag|        time       | (optionally  |
       +----+----+----+----+----+              |
       | this may have 64 byte keying material |
       | and/or a one+N byte extended options) |
       +---------------------------------------|

- - ### Field Summary

    Fields
    Modifier and Type | Field and Description
    --- | ---
    `(package private) static int` | `PROTOCOL_VERSION` we only talk to people of the right version
    `(package private) static int` | `TYPE_ACK`
    `(package private) static int` | `TYPE_CONF`
    `(package private) static int` | `TYPE_CREAT`
    `(package private) static int` | `TYPE_FIRST` For debugging and stats only - does not go out on the wire.
    `(package private) static int` | `TYPE_INTRO`
    `(package private) static int` | `TYPE_PUNCH`
    `(package private) static int` | `TYPE_RESP`
    `(package private) static int` | `TYPE_RREQ`
    `(package private) static int` | `TYPE_SREQ`
    `(package private) static int` | `TYPE_TBC`
    `(package private) static int` | `TYPE_TCB`
    `(package private) static int` | `TYPE_TFA`
    `(package private) static int` | `TYPE_TTA`

  - ### Constructor Summary

    Constructors
    Constructor and Description
    `PacketBuilder(I2PAppContext ctx, UDPTransport transport)`

  - ### Method Summary

    Methods
    Modifier and Type | Method and Description
    --- | ---
    `UDPPacket` | `buildACK(PeerState peer, List<ACKBitfield> ackBitfields)` Build the ack packet.
    `UDPPacket` | `buildHolePunch(UDPPacketReader reader)` Sends an empty unauthenticated packet for hole punching
    `UDPPacket` | `buildPacket(OutboundMessageState state, int fragment, PeerState peer, List<Long> ackIdsRemaining, List<ACKBitfield> partialACKsRemaining)` This builds a data packet (PAYLOAD_TYPE_DATA).
    `UDPPacket` | `buildPeerTestFromAlice(InetAddress toIP, int toPort, SessionKey toIntroKey, long nonce, SessionKey aliceIntroKey)` Build a packet as if we are Alice and we either want Bob to begin a peer test or Charlie to finish a peer test.
    `UDPPacket` | `buildPeerTestFromAlice(InetAddress toIP, int toPort, SessionKey toCipherKey, SessionKey toMACKey, long nonce, SessionKey aliceIntroKey)`
    `UDPPacket` | `buildPeerTestToAlice(InetAddress aliceIP, int alicePort, SessionKey aliceIntroKey, SessionKey charlieIntroKey, long nonce)` Build a packet as if we are either Bob or Charlie and we are helping test Alice.
    `UDPPacket` | `buildPeerTestToBob(InetAddress bobIP, int bobPort, InetAddress aliceIP, int alicePort, SessionKey aliceIntroKey, long nonce, SessionKey bobCipherKey, SessionKey bobMACKey)` Build a packet as if we are Charlie sending Bob a packet verifying that we will help test Alice.
    `UDPPacket` | `buildPeerTestToCharlie(InetAddress aliceIP, int alicePort, SessionKey aliceIntroKey, long nonce, InetAddress charlieIP, int charliePort, SessionKey charlieCipherKey, SessionKey charlieMACKey)` Build a packet as if we are Bob sending Charlie a packet to help test Alice.
    `UDPPacket` | `buildPing(PeerState peer)` We use this for keepalive purposes.
    `(package private) UDPPacket` | `buildRelayIntro(RemoteHostId alice, PeerState charlie, UDPPacketReader.RelayRequestReader request)`
    `UDPPacket` | `buildRelayRequest(InetAddress introHost, int introPort, byte[] introKey, long introTag, SessionKey ourIntroKey, long introNonce, boolean encrypt)`
    `UDPPacket[]` | `buildRelayRequest(UDPTransport transport, OutboundEstablishState state, SessionKey ourIntroKey)` build intro packets for each of the published introducers
    `(package private) UDPPacket` | `buildRelayResponse(RemoteHostId alice, PeerState charlie, long nonce, SessionKey aliceIntroKey)`
    `UDPPacket` | `buildSessionConfirmedPacket(OutboundEstablishState state, int fragmentNum, int numFragments, byte[] identity)` Build a new SessionConfirmed packet for the given peer
    `UDPPacket[]` | `buildSessionConfirmedPackets(OutboundEstablishState state, RouterIdentity ourIdentity)` Build a new series of SessionConfirmed packets for the given peer, encrypting it as necessary.
    `UDPPacket` | `buildSessionCreatedPacket(InboundEstablishState state, int externalPort, SessionKey ourIntroKey)` Build a new SessionCreated packet for the given peer, encrypting it as necessary.
    `UDPPacket` | `buildSessionDestroyPacket(PeerState peer)` Build a destroy packet, which contains a header but no body.
    `UDPPacket` | `buildSessionRequestPacket(OutboundEstablishState state)` Build a new SessionRequest packet for the given peer, encrypting it as necessary.

    - ### Methods inherited from class java.lang.Object

      `clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

- - ### Field Detail

    - #### TYPE_FIRST

          static final int TYPE_FIRST

      For debugging and stats only - does not go out on the wire. These are chosen to be higher than the highest I2NP message type, as a data packet is set to the underlying I2NP message type.
      See Also:
        Constant Field Values

    - #### TYPE_ACK

          static final int TYPE_ACK

      See Also:
        Constant Field Values

    - #### TYPE_PUNCH

          static final int TYPE_PUNCH

      See Also:
        Constant Field Values

    - #### TYPE_RESP

          static final int TYPE_RESP

      See Also:
        Constant Field Values

    - #### TYPE_INTRO

          static final int TYPE_INTRO

      See Also:
        Constant Field Values

    - #### TYPE_RREQ

          static final int TYPE_RREQ

      See Also:
        Constant Field Values

    - #### TYPE_TCB

          static final int TYPE_TCB

      See Also:
        Constant Field Values

    - #### TYPE_TBC

          static final int TYPE_TBC

      See Also:
        Constant Field Values

    - #### TYPE_TTA

          static final int TYPE_TTA

      See Also:
        Constant Field Values

    - #### TYPE_TFA

          static final int TYPE_TFA

      See Also:
        Constant Field Values

    - #### TYPE_CONF

          static final int TYPE_CONF

      See Also:
        Constant Field Values

    - #### TYPE_SREQ

          static final int TYPE_SREQ

      See Also:
        Constant Field Values

    - #### TYPE_CREAT

          static final int TYPE_CREAT

      See Also:
        Constant Field Values

    - #### PROTOCOL_VERSION

          static final int PROTOCOL_VERSION

      we only talk to people of the right version
      See Also:
        Constant Field Values

  - ### Constructor Detail

    - #### PacketBuilder

          public PacketBuilder(I2PAppContext ctx,
                       UDPTransport transport)

  - ### Method Detail

    - #### buildPacket

          public UDPPacket buildPacket(OutboundMessageState state,
                              int fragment,
                              PeerState peer,
                              List<Long> ackIdsRemaining,
                              List<ACKBitfield> partialACKsRemaining)

      This builds a data packet (PAYLOAD_TYPE_DATA). See the methods below for the other message types.
      Parameters:
        `ackIdsRemaining` - list of messageIds (Long) that should be acked by this packet. The list itself is passed by reference, and if a messageId is transmitted and the sender does not want the ID to be included in subsequent acks, it should be removed from the list. NOTE: right now this does NOT remove the IDs, which means it assumes that the IDs will be transmitted potentially multiple times, and should otherwise be removed from the list.
        `partialACKsRemaining` - list of messageIds (ACKBitfield) that should be acked by this packet. The list itself is passed by reference, and if a messageId is included, it should be removed from the list.

    - #### buildPing

          public UDPPacket buildPing(PeerState peer)

      We use this for keepalive purposes. It doesn't generate a reply, but that's ok.

    - #### buildACK

          public UDPPacket buildACK(PeerState peer,
                           List<ACKBitfield> ackBitfields)

      Build the ack packet. The list need not be sorted into full and partial; this method will put all fulls before the partials in the outgoing packet. An ack packet is just a data packet with no data.
      Parameters:
        `ackBitfields` - list of ACKBitfield instances to either fully or partially ACK

    - #### buildSessionCreatedPacket

          public UDPPacket buildSessionCreatedPacket(InboundEstablishState state,
                                            int externalPort,
                                            SessionKey ourIntroKey)

      Build a new SessionCreated packet for the given peer, encrypting it as necessary.
      Returns:
        ready to send packet, or null if there was a problem

    - #### buildSessionRequestPacket

          public UDPPacket buildSessionRequestPacket(OutboundEstablishState state)

      Build a new SessionRequest packet for the given peer, encrypting it as necessary.
      Returns:
        ready to send packet, or null if there was a problem

    - #### buildSessionConfirmedPackets

          public UDPPacket[] buildSessionConfirmedPackets(OutboundEstablishState state,
                                                 RouterIdentity ourIdentity)

      Build a new series of SessionConfirmed packets for the given peer, encrypting it as necessary.
      Returns:
        ready to send packets, or null if there was a problem TODO: doesn't really return null, and caller doesn't handle null return (null SigningPrivateKey should cause this?) Should probably return null if buildSessionConfirmedPacket() turns null for any fragment

    - #### buildSessionConfirmedPacket

          public UDPPacket buildSessionConfirmedPacket(OutboundEstablishState state,
                                              int fragmentNum,
                                              int numFragments,
                                              byte[] identity)

      Build a new SessionConfirmed packet for the given peer
      Returns:
        ready to send packets, or null if there was a problem

    - #### buildSessionDestroyPacket

          public UDPPacket buildSessionDestroyPacket(PeerState peer)

      Build a destroy packet, which contains a header but no body.
      Since:
        0.8.1

    - #### buildPeerTestFromAlice

          public UDPPacket buildPeerTestFromAlice(InetAddress toIP,
                                         int toPort,
                                         SessionKey toIntroKey,
                                         long nonce,
                                         SessionKey aliceIntroKey)

      Build a packet as if we are Alice and we either want Bob to begin a peer test or Charlie to finish a peer test.
      Returns:
        ready to send packet, or null if there was a problem

    - #### buildPeerTestFromAlice

          public UDPPacket buildPeerTestFromAlice(InetAddress toIP,
                                         int toPort,
                                         SessionKey toCipherKey,
                                         SessionKey toMACKey,
                                         long nonce,
                                         SessionKey aliceIntroKey)

    - #### buildPeerTestToAlice

          public UDPPacket buildPeerTestToAlice(InetAddress aliceIP,
                                       int alicePort,
                                       SessionKey aliceIntroKey,
                                       SessionKey charlieIntroKey,
                                       long nonce)

      Build a packet as if we are either Bob or Charlie and we are helping test Alice.
      Returns:
        ready to send packet, or null if there was a problem

    - #### buildPeerTestToCharlie

          public UDPPacket buildPeerTestToCharlie(InetAddress aliceIP,
                                         int alicePort,
                                         SessionKey aliceIntroKey,
                                         long nonce,
                                         InetAddress charlieIP,
                                         int charliePort,
                                         SessionKey charlieCipherKey,
                                         SessionKey charlieMACKey)

      Build a packet as if we are Bob sending Charlie a packet to help test Alice.
      Returns:
        ready to send packet, or null if there was a problem

    - #### buildPeerTestToBob

          public UDPPacket buildPeerTestToBob(InetAddress bobIP,
                                     int bobPort,
                                     InetAddress aliceIP,
                                     int alicePort,
                                     SessionKey aliceIntroKey,
                                     long nonce,
                                     SessionKey bobCipherKey,
                                     SessionKey bobMACKey)

      Build a packet as if we are Charlie sending Bob a packet verifying that we will help test Alice.
      Returns:
        ready to send packet, or null if there was a problem

    - #### buildRelayRequest

          public UDPPacket[] buildRelayRequest(UDPTransport transport,
                                      OutboundEstablishState state,
                                      SessionKey ourIntroKey)

      build intro packets for each of the published introducers

    - #### buildRelayRequest

          public UDPPacket buildRelayRequest(InetAddress introHost,
                                    int introPort,
                                    byte[] introKey,
                                    long introTag,
                                    SessionKey ourIntroKey,
                                    long introNonce,
                                    boolean encrypt)

    - #### buildRelayIntro

          UDPPacket buildRelayIntro(RemoteHostId alice,
                                  PeerState charlie,
                                  UDPPacketReader.RelayRequestReader request)

    - #### buildRelayResponse

          UDPPacket buildRelayResponse(RemoteHostId alice,
                                     PeerState charlie,
                                     long nonce,
                                     SessionKey aliceIntroKey)

    - #### buildHolePunch

          public UDPPacket buildHolePunch(UDPPacketReader reader)

      Sends an empty unauthenticated packet for hole punching