java.lang.Object
net.i2p.router.transport.udp.PacketBuilder2
Builds and encrypts SSU2 protocol packets for UDP transport. Handles all SSU2 message types including data packets, session establishment, peer testing, relay requests, and hole punching. Provides packet fragmentation, padding, and encryption for secure UDP communication.
Nested Class Summary
Modifier and TypeClassDescriptionprivate static final classPer-thread pool of payload block objects and the reusable block list.static classClass for passing multiple fragments to buildPacket().Field Summary
Modifier and TypeFieldDescriptionprivate static final ThreadLocal<PacketBuilder2.BlockPool> The block pool, one per thread.private final RouterContextThe router context.private final LogLogger for the packet builder.private final UDPTransportThe transport the packets go out on.private static final intMost ack ranges allowed in one packet.private static final intPackets between date and time blocks.static final intIPv4 only.static final intIPv6 header size in bytes.static final intMinimum IPv4 data packet overhead with MAC in bytes (60).static final intMinimum IPv6 data packet overhead with MAC in bytes (80).(package private) static final intHigher than all other OutNetMessage priorities, but still droppable, and will be shown in thecodel.UDP-Sender.drop.500stat.private static final intSend priority of the medium class messages.(package private) static final intSSU2 packet type constant for debugging/stats.(package private) static final intSSU2 packet type constant for debugging/stats.(package private) static final intSSU2 packet type constant for debugging/stats.(package private) static final intSSU2 packet type constant for debugging/stats.(package private) static final intFor debugging and stats only - does not go out on the wire.(package private) static final intSSU2 packet type constant for debugging/stats.(package private) static final intSSU2 packet type constant for debugging/stats.(package private) static final intSSU2 packet type constant for debugging/stats.(package private) static final intSSU2 packet type constant for debugging/stats.(package private) static final intSSU2 packet type constant for debugging/stats.(package private) static final intSSU2 packet type constant for debugging/stats.(package private) static final intSSU2 packet type constant for debugging/stats.(package private) static final intSSU2 packet type constant for debugging/stats.(package private) static final intSSU2 packet type constant for debugging/stats.static final intSame for IPv4 and IPv6.Constructor Summary
ConstructorsConstructorDescriptionPacketBuilder2(RouterContext ctx, UDPTransport transport) No state, all methods are thread-safe.Method Summary
Modifier and TypeMethodDescriptionprivate intaddHandshakePadding(List<SSU2Payload.Block> blocks, int len, int version, boolean isIPv6, int pqlen, int mtu, int maxPadding) Adds the padding block a handshake packet can afford to the block list, returning the new payload length.buildACK(PeerState2 peer) Build the ack packet.buildHolePunch(InetAddress to, int port, SessionKey introKey, long sendID, long rcvID, byte[] signedData) Out-of-session, containing a RelayResponse block.private UDPPacketbuildLongPacketHeader(long destID, long pktNum, byte type, long srcID, long token, int version) Build the header block of a long SSU2 packet.buildPacket(List<PacketBuilder2.Fragment> fragments, List<SSU2Payload.Block> otherBlocks, SSU2Sender peer) Build a packet from multiple fragments and optional other blocks.buildPacket(List<PacketBuilder2.Fragment> fragments, PeerState2 peer) Build a packet from multiple fragments.buildPacket(OutboundMessageState state, int fragment, PeerState2 peer) This builds a data packet (PAYLOAD_TYPE_DATA).buildPeerTestFromAlice(byte[] signedData, PeerState2 bob) Build a packet as Alice, to Bob to begin a peer test.buildPeerTestFromAlice(InetAddress toIP, int toPort, SessionKey introKey, long sendID, long rcvID, byte[] signedData) Build a packet as Alice to Charlie.buildPeerTestToAlice(int code, Hash charlieHash, byte[] signedData, PeerState2 alice) Build a packet as Bob to Alice, with the response from Charlie, or a rejection by Bob.buildPeerTestToAlice(int code, Hash charlieHash, byte[] signedData, SSU2Payload.Block riBlock, PeerState2 alice) Build a packet as Bob to Alice, with the response from Charlie, or a rejection by Bob.buildPeerTestToAlice(InetAddress aliceIP, int alicePort, SessionKey introKey, boolean firstSend, long sendID, long rcvID, byte[] signedData) Build a packet as Charlie to Alice.buildPeerTestToBob(int code, byte[] signedData, PeerState2 bob) Build a packet as Charlie to Bob verifying that we will help test Alice.buildPeerTestToCharlie(Hash aliceHash, byte[] signedData, SSU2Payload.Block riBlock, PeerState2 charlie) Build a packet as Bob to Charlie to help test Alice.buildPing(PeerState2 peer) A DATA packet with padding only.(package private) UDPPacketbuildRelayIntro(byte[] signedData, SSU2Payload.Block riBlock, PeerState2 charlie) From Bob to Charlie.(package private) UDPPacketbuildRelayRequest(byte[] signedData, PeerState2 bob) From Alice to Bob.(package private) UDPPacketbuildRelayResponse(byte[] signedData, PeerState2 state) From Charlie to Bob or Bob to Alice.buildRetryPacket(InboundEstablishState2 state, int terminationCode) Build a new Retry packet for the given peer, encrypting it as necessary.buildRetryPacket(RemoteHostId to, SocketAddress toAddr, long destID, long srcID, int version, int terminationCode) Build a new Retry packet with a termination code, for a rejection direct from the EstablishmentManager.private UDPPacketBuild a single new SessionConfirmed packet for the given peer, unfragmented.buildSessionConfirmedPackets(OutboundEstablishState2 state, RouterInfo ourInfo) Build a new series of SessionConfirmed packets for the given peer, encrypting it as necessary.private UDPPacket[]Build all the fragmented SessionConfirmed packets.Build a new SessionCreated packet for the given peer, encrypting it as necessary.buildSessionDestroyPacket(int reason, SSU2Sender peer) Build a data packet with a termination block.Build a new SessionRequest packet for the given peer, encrypting it as necessary.private UDPPacketbuildShortPacketHeader(long destID, long pktNum, byte type) Build the header block of a short SSU2 packet.Build a new SessionRequest packet for the given peer, encrypting it as necessary.(package private) static intdataPacketHeaderSize(boolean isIPv6) Size of the IP + UDP headers for a data packet to a peer.(package private) static intdataPacketOverhead(boolean isIPv6) Minimum fixed overhead (IP + UDP + short packet header + MAC) of a data packet, used to compute how much room remains for acks and body blocks at the peer's MTU.private voidencryptDataPacket(UDPPacket packet, CipherState chacha, long n, byte[] hdrKey1, byte[] hdrKey2) Encrypts the payload of one data packet and appends the MAC.private voidencryptPeerTest(UDPPacket packet, byte[] chachaKey, long n, byte[] hdrKey1, byte[] hdrKey2, byte[] ip, int port, SSU2Payload.Block ptBlock) Also used for hole punch with a relay request block.private voidencryptRetry(UDPPacket packet, byte[] chachaKey, long n, byte[] hdrKey1, byte[] hdrKey2, byte[] ip, int port, int terminationCode) Encrypt and write out the body of a Retry packet.private voidencryptSessionConfirmed(UDPPacket packet, HandshakeState state, int mtu, int numFragments, int addPadding, boolean isIPv6, byte[] hdrKey1, byte[] hdrKey2, SSU2Payload.RIBlock riblock, EstablishmentManager.Token token) If numFragments larger than 1, we do NOT encrypt the header here, that's caller's responsibility.private voidencryptSessionCreated(UDPPacket packet, HandshakeState state, int mtu, byte[] hdrKey1, byte[] hdrKey2, long relayTag, EstablishmentManager.Token token, byte[] ip, int port, int version) Encrypt and write out message 2 of the handshake, the SessionCreated.private voidencryptSessionRequest(UDPPacket packet, HandshakeState state, boolean isIPv6, int mtu, byte[] hdrKey1, byte[] hdrKey2, boolean needIntro, int version, Hash bob) Encrypt and write out message 1 of the handshake, the SessionRequest.private voidencryptTokenRequest(UDPPacket packet, byte[] chachaKey, long n, byte[] hdrKey1, byte[] hdrKey2) Encrypt and write out the body of a Token Request packet.(package private) static booleanfitsDateTimeBlock(int ipHeaderSize, int sizeWritten, int mtu) Whether a 7-byte DateTime block still fits in the packet at the peer's MTU, counting the short header and MAC that surround the body.(package private) static intfragmentDataSize(int fragmentSize, int fragment) Total bytes a single fragment contributes to a data packet body: the fragment payload plus the per-block header, plus the extra 5-byte overhead carried by follow-on fragments (fragment number and message ID).static intgetMaxAdditionalFragmentSize(PeerState peer, int numFragments, int curDataSize) Will a packet to 'peer' that already has 'numFragments' fragments totalling 'curDataSize' bytes fit another fragment? This includes the 3 byte block overhead, but NOT the 5 byte followon fragment overhead.static intgetMaxDataSize(PeerState peer) Calculates the maximum payload size that can be sent to this peer in a single data packet.private SSU2Payload.BlockgetPadding(int len, int max) Random padding block up to the maximum size.private SSU2Payload.BlockgetPadding(int len, int max, int maxPadding) Random padding block with an explicit cap.(package private) static inthandshakePaddingBase(int version, boolean isIPv6, int blockLen, int pqlen) The size a handshake packet's padding budget is measured against.(package private) static inthandshakePaddingMTU(int version, int mtu) The MTU a handshake packet's padding is sized against.(package private) static inthandshakePayloadOffset(int pqlen) Offset within the packet, measured from the start of the long header, where the plaintext payload blocks of a handshake message are staged.(package private) static inthandshakeWireSize(boolean isIPv6, int blockLen, int pqlen) On-wire size of a handshake packet before padding: the IP and UDP headers, the long header and ephemeral key, the PQ frame if any, the MAC, and the payload blocks written so far.(package private) static booleanhasRoomForAckBlock(int availableForAcks) Whether enough ack space remains to fit at least one ack range.(package private) static booleanisDateTimeSendPeriod(long packetNumber) Whether this packet number falls on the boundary where a DateTime block should be emitted (packetNumber % DATETIME_SEND_FREQUENCY == DATETIME_SEND_FREQUENCY - 1).(package private) static booleanisSingleFragment(int fragment, int count) Whether a message is carried as a single I2NP block: the first fragment is also the only fragment.(package private) static intmaxAckRanges(int availableForAcks) Maximum number of ack ranges that fit in the free space, capped atABSOLUTE_MAX_ACK_RANGES.(package private) static intotherBlocksSize(List<SSU2Payload.Block> otherBlocks) Sum of the on-wire lengths of the non-fragment blocks to be appended to a data packet, used to budget ack space.private static voidsetTo(UDPPacket packet, InetAddress ip, int port) Sets the destination address of the packet.
Field Details
_context
The router context._log
Logger for the packet builder._transport
The transport the packets go out on._blockPool
The block pool, one per thread.TYPE_FIRST
static final int TYPE_FIRSTFor 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. SSU2 packet type constant for debugging/stats.- See Also:
TYPE_ACK
static final int TYPE_ACKSSU2 packet type constant for debugging/stats.- See Also:
TYPE_PUNCH
static final int TYPE_PUNCHSSU2 packet type constant for debugging/stats.- See Also:
TYPE_RESP
static final int TYPE_RESPSSU2 packet type constant for debugging/stats.- See Also:
TYPE_INTRO
static final int TYPE_INTROSSU2 packet type constant for debugging/stats.- See Also:
TYPE_RREQ
static final int TYPE_RREQSSU2 packet type constant for debugging/stats.- See Also:
TYPE_TCB
static final int TYPE_TCBSSU2 packet type constant for debugging/stats.- See Also:
TYPE_TBC
static final int TYPE_TBCSSU2 packet type constant for debugging/stats.- See Also:
TYPE_TTA
static final int TYPE_TTASSU2 packet type constant for debugging/stats.- See Also:
TYPE_TFA
static final int TYPE_TFASSU2 packet type constant for debugging/stats.- See Also:
TYPE_CONF
static final int TYPE_CONFSSU2 packet type constant for debugging/stats.- See Also:
TYPE_SREQ
static final int TYPE_SREQSSU2 packet type constant for debugging/stats.- See Also:
TYPE_CREAT
static final int TYPE_CREATSSU2 packet type constant for debugging/stats.- See Also:
TYPE_DESTROY
static final int TYPE_DESTROYSSU2 packet type constant for debugging/stats.- See Also:
IP_HEADER_SIZE
UDP_HEADER_SIZE
MIN_DATA_PACKET_OVERHEAD
public static final int MIN_DATA_PACKET_OVERHEADMinimum IPv4 data packet overhead with MAC in bytes (60).- See Also:
IPV6_HEADER_SIZE
MIN_IPV6_DATA_PACKET_OVERHEAD
public static final int MIN_IPV6_DATA_PACKET_OVERHEADMinimum IPv6 data packet overhead with MAC in bytes (80).- See Also:
ABSOLUTE_MAX_ACK_RANGES
private static final int ABSOLUTE_MAX_ACK_RANGESMost ack ranges allowed in one packet.- See Also:
PRIORITY_HIGH
static final int PRIORITY_HIGHHigher than all other OutNetMessage priorities, but still droppable, and will be shown in thecodel.UDP-Sender.drop.500stat.- See Also:
PRIORITY_MEDIUM
private static final int PRIORITY_MEDIUMSend priority of the medium class messages.- See Also:
DATETIME_SEND_FREQUENCY
private static final int DATETIME_SEND_FREQUENCYPackets between date and time blocks.- See Also:
Constructor Details
PacketBuilder2
No state, all methods are thread-safe.- Parameters:
ctx- router context for logging, randomness, and router identitytransport- may be null for unit testing only
Method Details
getMaxAdditionalFragmentSize
Will a packet to 'peer' that already has 'numFragments' fragments totalling 'curDataSize' bytes fit another fragment? This includes the 3 byte block overhead, but NOT the 5 byte followon fragment overhead.This doesn't leave anything for acks or anything else.
- Parameters:
peer- supplies the MTU and address family for the overheadnumFragments- >= 1curDataSize- bytes of body already committed by those fragments- Returns:
- max additional fragment size
fragmentDataSize
static int fragmentDataSize(int fragmentSize, int fragment) Total bytes a single fragment contributes to a data packet body: the fragment payload plus the per-block header, plus the extra 5-byte overhead carried by follow-on fragments (fragment number and message ID).- Parameters:
fragmentSize- size of the fragment payload fromOutboundMessageState.fragmentSize(int)fragment-0for the first fragment, > 0 for follow-ons- Returns:
- total body bytes for this fragment
dataPacketHeaderSize
static int dataPacketHeaderSize(boolean isIPv6) Size of the IP + UDP headers for a data packet to a peer. This excludes the SSU2 short packet header and MAC.- Parameters:
isIPv6-truefor IPv6 peers- Returns:
- combined IP and UDP header size in bytes
dataPacketOverhead
static int dataPacketOverhead(boolean isIPv6) Minimum fixed overhead (IP + UDP + short packet header + MAC) of a data packet, used to compute how much room remains for acks and body blocks at the peer's MTU.- Parameters:
isIPv6-truefor IPv6 peers- Returns:
MIN_IPV6_DATA_PACKET_OVERHEADorMIN_DATA_PACKET_OVERHEAD
otherBlocksSize
Sum of the on-wire lengths of the non-fragment blocks to be appended to a data packet, used to budget ack space.- Parameters:
otherBlocks- may benullor empty- Returns:
- total block lengths,
0when null/empty
hasRoomForAckBlock
static boolean hasRoomForAckBlock(int availableForAcks) Whether enough ack space remains to fit at least one ack range. An ack block needs its own block header plus a 5-byte first range.- Parameters:
availableForAcks- bytes free after the payload fragments- Returns:
truewhen an ack block can be emitted
maxAckRanges
static int maxAckRanges(int availableForAcks) Maximum number of ack ranges that fit in the free space, capped atABSOLUTE_MAX_ACK_RANGES. Each additional range costs 2 bytes.- Parameters:
availableForAcks- bytes free after the payload fragments- Returns:
- range count, >= 0
isSingleFragment
static boolean isSingleFragment(int fragment, int count) Whether a message is carried as a single I2NP block: the first fragment is also the only fragment.- Parameters:
fragment- fragment number within the message (0= first)count- total fragments in the message- Returns:
truefor a one-fragment message
isDateTimeSendPeriod
static boolean isDateTimeSendPeriod(long packetNumber) Whether this packet number falls on the boundary where a DateTime block should be emitted (packetNumber % DATETIME_SEND_FREQUENCY == DATETIME_SEND_FREQUENCY - 1). Kept cheap via a power-of-two mask.- Parameters:
packetNumber- the packet's sequence number- Returns:
trueto send a DateTime block
fitsDateTimeBlock
static boolean fitsDateTimeBlock(int ipHeaderSize, int sizeWritten, int mtu) Whether a 7-byte DateTime block still fits in the packet at the peer's MTU, counting the short header and MAC that surround the body.- Parameters:
ipHeaderSize- IP + UDP header size for this peersizeWritten- bytes written to the body so farmtu- the peer's current MTU- Returns:
truewhen the block fits
buildPacket
public UDPPacket buildPacket(OutboundMessageState state, int fragment, PeerState2 peer) throws IOException This builds a data packet (PAYLOAD_TYPE_DATA). See the methods below for the other message types.Note that while the UDP message spec allows for more than one fragment in a message, this method writes exactly one fragment. For no fragments use buildAck().
- Parameters:
state- the outbound message statefragment- fragment number within the message,0for the firstpeer- the destination session- Returns:
- ready to send packet, non-null
- Throws:
IOException- if peer is dead
buildPacket
public UDPPacket buildPacket(List<PacketBuilder2.Fragment> fragments, PeerState2 peer) throws IOException Build a packet from multiple fragments.- Parameters:
fragments- one or more fragments of a message, in fragment orderpeer- the destination session- Returns:
- ready to send packet, non-null
- Throws:
IOException- if peer is dead
buildPacket
public UDPPacket buildPacket(List<PacketBuilder2.Fragment> fragments, List<SSU2Payload.Block> otherBlocks, SSU2Sender peer) throws IOException Build a packet from multiple fragments and optional other blocks.- Parameters:
fragments- one or more fragments of a message, in fragment order; empty for an ack-only packetotherBlocks- may be null or emptypeer- the destination session- Returns:
- ready to send packet, non-null
- Throws:
IOException- if peer is dead
buildPing
A DATA packet with padding only. We use this for keepalive purposes.- Parameters:
peer- the destination session- Returns:
- ready to send packet, or null if padding did not fit
- Throws:
IOException- if peer is dead
buildACK
Build the ack packet. An ack packet is just a data packet with no data. See buildPacket() for format.- Parameters:
peer- the destination session- Returns:
- ready to send packet, non-null
- Throws:
IOException- if peer is dead
buildSessionDestroyPacket
Build a data packet with a termination block. This will also include acks, a new token block, and padding.- Parameters:
reason- termination reason code (0-255), also recorded on the peerpeer- the session being destroyed- Returns:
- ready to send packet, non-null
- Throws:
IOException- if peer is dead
buildTokenRequestPacket
Build a new SessionRequest packet for the given peer, encrypting it as necessary.- Parameters:
state- the outbound establish state carrying conn IDs, version, and keys- Returns:
- ready to send packet, non-null
buildSessionRequestPacket
Build a new SessionRequest packet for the given peer, encrypting it as necessary.- Parameters:
state- the outbound establish state carrying conn IDs, token, and keys- Returns:
- ready to send packet, non-null
buildSessionCreatedPacket
Build a new SessionCreated packet for the given peer, encrypting it as necessary.- Parameters:
state- the inbound establish state carrying conn IDs and keys- Returns:
- ready to send packet, non-null
buildRetryPacket
Build a new Retry packet for the given peer, encrypting it as necessary.- Parameters:
state- the inbound establish state carrying conn IDs and keysterminationCode- 0 normally, nonzero to send termination block- Returns:
- ready to send packet, non-null
buildRetryPacket
public UDPPacket buildRetryPacket(RemoteHostId to, SocketAddress toAddr, long destID, long srcID, int version, int terminationCode) Build a new Retry packet with a termination code, for a rejection direct from the EstablishmentManager. No InboundEstablishState2 required.- Parameters:
to- remote address family, supplying the IP and port for the address blocktoAddr- socket address to send the packet todestID- destination connection ID, or 0 when unknownsrcID- our connection ID for the replyversion- SSU2 protocol version of the peerterminationCode- must be greater than zero- Returns:
- ready to send packet, non-null
buildSessionConfirmedPackets
Build a new series of SessionConfirmed packets for the given peer, encrypting it as necessary.If the RI is large enough that it is fragmented, this will still only return a single Session Confirmed message. The remaining RI blocks will be passed to the establish state via confirmedPacketsSent(), and the state will transmit them via the new PeerState2.
- Parameters:
state- the outbound establish state carrying conn IDs, keys, and MTUourInfo- the RouterInfo to send, gzipped here if it shrinks- Returns:
- ready to send packets, non-null
buildSessionConfirmedPacket
private UDPPacket buildSessionConfirmedPacket(OutboundEstablishState2 state, SSU2Payload.RIBlock block) Build a single new SessionConfirmed packet for the given peer, unfragmented.- Parameters:
state- the in-progress outbound handshake state, source of the connection ID, header encryption keys, MTU and destination addressblock- the RouterInfo payload block to carry, not fragmented- Returns:
- ready to send packet, non-null
buildSessionConfirmedPackets
private UDPPacket[] buildSessionConfirmedPackets(OutboundEstablishState2 state, SSU2Payload.RIBlock block) Build all the fragmented SessionConfirmed packets.- Parameters:
state- the in-progress outbound handshake state, source of the connection ID, header encryption keys, MTU and destination addressblock- the RouterInfo payload block to split across the packets- Returns:
- one packet per fragment, in fragment order, non-null
buildPeerTestFromAlice
Build a packet as Alice, to Bob to begin a peer test. In-session, message 1.- Parameters:
signedData- flag + signed databob- the destination session- Returns:
- ready to send packet, non-null
- Throws:
IOException- if peer is dead
buildPeerTestFromAlice
public UDPPacket buildPeerTestFromAlice(InetAddress toIP, int toPort, SessionKey introKey, long sendID, long rcvID, byte[] signedData) Build a packet as Alice to Charlie. Out-of-session, message 6.- Parameters:
toIP- Charlie's IP, taken from the introducer that gave us Bob's current address; may be an IPv6 addresstoPort- Charlie's port, from that same introducerintroKey- static introduction key used to encrypt the packetsendID- our connection IDrcvID- Charlie's connection IDsignedData- flag + signed data- Returns:
- ready to send packet, non-null
buildPeerTestToAlice
public UDPPacket buildPeerTestToAlice(int code, Hash charlieHash, byte[] signedData, PeerState2 alice) throws IOException Build a packet as Bob to Alice, with the response from Charlie, or a rejection by Bob. In-session, message 4.- Parameters:
code- peer test response code from Charlie, or Bob's rejection codecharlieHash- fake hash (all zeros) if rejected by bobsignedData- flag + signed dataalice- the destination session- Returns:
- ready to send packet, non-null
- Throws:
IOException- if peer is dead
buildPeerTestToAlice
public UDPPacket buildPeerTestToAlice(int code, Hash charlieHash, byte[] signedData, SSU2Payload.Block riBlock, PeerState2 alice) throws IOException Build a packet as Bob to Alice, with the response from Charlie, or a rejection by Bob. In-session, message 4.- Parameters:
code- peer test response code from Charlie, or Bob's rejection codecharlieHash- fake hash (all zeros) if rejected by bobsignedData- flag + signed datariBlock- to include, may be nullalice- the destination session- Returns:
- ready to send packet, non-null
- Throws:
IOException- if peer is dead
buildPeerTestToAlice
public UDPPacket buildPeerTestToAlice(InetAddress aliceIP, int alicePort, SessionKey introKey, boolean firstSend, long sendID, long rcvID, byte[] signedData) Build a packet as Charlie to Alice. Out-of-session, messages 5 and 7.- Parameters:
aliceIP- Alice's IP, taken from the peer test we are replying toalicePort- Alice's port, from that same peer testintroKey- static introduction key used to encrypt the packetfirstSend-truefor message 5,falsefor the message 7 retrysendID- our connection IDrcvID- Alice's connection IDsignedData- flag + signed data- Returns:
- ready to send packet, non-null
buildPeerTestToCharlie
public UDPPacket buildPeerTestToCharlie(Hash aliceHash, byte[] signedData, SSU2Payload.Block riBlock, PeerState2 charlie) throws IOException Build a packet as Bob to Charlie to help test Alice. In-session, message 2.- Parameters:
aliceHash- hash of Alice's transient key, or all zeros if Alice is unknownsignedData- flag + signed datariBlock- to include, may be nullcharlie- the destination session- Returns:
- ready to send packet, non-null
- Throws:
IOException- if peer is dead
buildPeerTestToBob
Build a packet as Charlie to Bob verifying that we will help test Alice. In-session, message 3.- Parameters:
code- peer test response code relayed from Charlie to BobsignedData- flag + signed databob- the destination session- Returns:
- ready to send packet, non-null
- Throws:
IOException- if peer is dead
buildRelayRequest
From Alice to Bob. In-session.- Parameters:
signedData- flag + signed databob- the destination session- Returns:
- non-null
- Throws:
IOException- if peer is dead
buildRelayIntro
UDPPacket buildRelayIntro(byte[] signedData, SSU2Payload.Block riBlock, PeerState2 charlie) throws IOException From Bob to Charlie. In-session.- Parameters:
signedData- flag + alice hash + signed datariBlock- to include, may be nullcharlie- the destination session- Returns:
- non-null
- Throws:
IOException- if peer is dead
buildRelayResponse
From Charlie to Bob or Bob to Alice. In-session.- Parameters:
signedData- flag + response code + signed data + optional tokenstate- Alice or Bob- Returns:
- non-null
- Throws:
IOException- if peer is dead
buildHolePunch
public UDPPacket buildHolePunch(InetAddress to, int port, SessionKey introKey, long sendID, long rcvID, byte[] signedData) Out-of-session, containing a RelayResponse block.- Parameters:
to- the peer's IP addressport- the peer's portintroKey- static introduction key used to encrypt the packetsendID- our connection IDrcvID- the peer's connection IDsignedData- flag + response code + signed data + optional token- Returns:
- ready to send packet, non-null
buildLongPacketHeader
private UDPPacket buildLongPacketHeader(long destID, long pktNum, byte type, long srcID, long token, int version) Build the header block of a long SSU2 packet.- Parameters:
destID- peer's connection ID we are addressing, or 0 when not yet knownpktNum- 0 - 0xFFFFFFFFtype- packet type flag byte, written to header offset 12srcID- our connection ID, for the peer to address its reply totoken- token echoed back to the peer, or 0 for none; only meaningful for the handshake and test packet typesversion- SSU2 protocol version of the peer, written to header offset 13- Returns:
- a packet with the first 32 bytes filled in
buildShortPacketHeader
Build the header block of a short SSU2 packet.- Parameters:
destID- peer's connection ID we are addressing, or 0 when not yet knownpktNum- 0 - 0xFFFFFFFFtype- packet type flag byte, written to header offset 12- Returns:
- a packet with the first 16 bytes filled in
setTo
Sets the destination address of the packet.- Parameters:
packet- the packet to setip- the destination addressport- the destination port
handshakeWireSize
static int handshakeWireSize(boolean isIPv6, int blockLen, int pqlen) On-wire size of a handshake packet before padding: the IP and UDP headers, the long header and ephemeral key, the PQ frame if any, the MAC, and the payload blocks written so far. A version 4 session request fills the minimum MTU with no padding at all - seePeerState2.MIN_MLKEM768_IPV4_MTU- so that version needs the exact figure to size its padding, while the others fit with room to spare.- Parameters:
isIPv6- the address family of the packetblockLen- total length of the payload blocks written so farpqlen- the PQ frame length fromSSU2Util.pqRequestExtra(int)orSSU2Util.pqCreatedExtra(int), 0 for version 2- Returns:
- the total on-wire size in bytes
handshakePayloadOffset
static int handshakePayloadOffset(int pqlen) Offset within the packet, measured from the start of the long header, where the plaintext payload blocks of a handshake message are staged. Noise writes the ephemeral key, and for the PQ versions the ML-KEM frame, into the message buffer before it reads the payload, so staging the blocks any earlier makes writeMessage() encrypt its own key material as the payload - a well-formed message whose blocks are garbage, with a tag that still verifies.- Parameters:
pqlen- the PQ frame length fromSSU2Util.pqRequestExtra(int)orSSU2Util.pqCreatedExtra(int), 0 for version 2- Returns:
- the staging offset from the start of the long header
handshakePaddingBase
static int handshakePaddingBase(int version, boolean isIPv6, int blockLen, int pqlen) The size a handshake packet's padding budget is measured against. Version 4 needs the exact on-wire figure, because its ML-KEM frame already fills the minimum MTU; the other versions have room to spare and are measured against the payload blocks alone, as before the PQ work.- Parameters:
version- the negotiated SSU2 versionisIPv6- the address family of the packetblockLen- total length of the payload blocks written so farpqlen- the PQ frame length fromSSU2Util.pqRequestExtra(int)orSSU2Util.pqCreatedExtra(int), 0 for version 2- Returns:
- the size in bytes the padding budget is measured against
handshakePaddingMTU
static int handshakePaddingMTU(int version, int mtu) The MTU a handshake packet's padding is sized against. Version 4 uses the peer's MTU, because its frame alone exceedsPeerState2.MIN_MTU; the other versions are sized against the minimum, as before the PQ work.- Parameters:
version- the negotiated SSU2 versionmtu- the peer's MTU in bytes- Returns:
- the MTU budget in bytes
addHandshakePadding
private int addHandshakePadding(List<SSU2Payload.Block> blocks, int len, int version, boolean isIPv6, int pqlen, int mtu, int maxPadding) Adds the padding block a handshake packet can afford to the block list, returning the new payload length. The budget comes from the version's own geometry - seehandshakePaddingBase(int, boolean, int, int)andhandshakePaddingMTU(int, int)- and running out of room is not fatal, the packet simply goes out without padding.- Parameters:
blocks- the payload blocks staged so far, appended to if there is paddinglen- total length of those blocksversion- the negotiated SSU2 versionisIPv6- the address family of the packetpqlen- the PQ frame length fromSSU2Util.pqRequestExtra(int)orSSU2Util.pqCreatedExtra(int), 0 for version 2mtu- the peer's MTU in bytesmaxPadding- the house cap on the padding for this message type- Returns:
- the payload length, including the padding block if one was added
encryptSessionRequest
private void encryptSessionRequest(UDPPacket packet, HandshakeState state, boolean isIPv6, int mtu, byte[] hdrKey1, byte[] hdrKey2, boolean needIntro, int version, Hash bob) Encrypt and write out message 1 of the handshake, the SessionRequest.- Parameters:
packet- containing only 32 byte headerstate- the Noise handshake state, already started with our ephemeral key pairisIPv6- the peer's address family, for the version 4 padding budgetmtu- the peer's MTU, for the version 4 padding budgethdrKey1- 32-byte ChaCha20 key protecting header bytes 0-7hdrKey2- 32-byte ChaCha20 key protecting header bytes 8-31needIntro- append a relay tag request block, for a peer that asked us to introduce it to a third peerversion- the negotiated SSU2 version, 2 to 4bob- the peer's router hash, mixed into the handshake for the PQ versions, unused for version 2
encryptSessionCreated
private void encryptSessionCreated(UDPPacket packet, HandshakeState state, int mtu, byte[] hdrKey1, byte[] hdrKey2, long relayTag, EstablishmentManager.Token token, byte[] ip, int port, int version) Encrypt and write out message 2 of the handshake, the SessionCreated.- Parameters:
packet- containing only 32 byte headerstate- the Noise handshake state, already started with our ephemeral key pairmtu- the peer's MTU, for the version 4 padding budgethdrKey1- 32-byte ChaCha20 key protecting header bytes 0-7hdrKey2- 32-byte ChaCha20 key protecting header bytes 8-31relayTag- relay tag for the peer to send us, or 0 to omit the relay tag blocktoken- may be nullip- the peer's address for the address block, 4 or 16 bytesport- the peer's UDP port for the address blockversion- the negotiated SSU2 version, 2 to 4
encryptRetry
private void encryptRetry(UDPPacket packet, byte[] chachaKey, long n, byte[] hdrKey1, byte[] hdrKey2, byte[] ip, int port, int terminationCode) Encrypt and write out the body of a Retry packet.- Parameters:
packet- containing only 32 byte headerchachaKey- 32-byte ChaCha20-Poly1305 key for the payload, the static introduction keyn- packet number from the header, also the payload noncehdrKey1- 32-byte ChaCha20 key protecting header bytes 0-7hdrKey2- 32-byte ChaCha20 key protecting header bytes 8-31ip- the peer's address for the address block, 4 or 16 bytesport- the peer's UDP port for the address blockterminationCode- 0 normally, nonzero to send termination block
encryptPeerTest
private void encryptPeerTest(UDPPacket packet, byte[] chachaKey, long n, byte[] hdrKey1, byte[] hdrKey2, byte[] ip, int port, SSU2Payload.Block ptBlock) Also used for hole punch with a relay request block. Also used for retry with (usually) ptBlock = null.- Parameters:
packet- containing only 32 byte headerchachaKey- 32-byte ChaCha20-Poly1305 key for the payload, the static introduction keyn- packet number from the header, also the payload noncehdrKey1- 32-byte ChaCha20 key protecting header bytes 0-7hdrKey2- 32-byte ChaCha20 key protecting header bytes 8-31ip- the recipient's address for the address block, 4 or 16 bytesport- the recipient's UDP port for the address blockptBlock- Peer Test or Relay Request block. Null for retry.
encryptTokenRequest
private void encryptTokenRequest(UDPPacket packet, byte[] chachaKey, long n, byte[] hdrKey1, byte[] hdrKey2) Encrypt and write out the body of a Token Request packet.- Parameters:
packet- containing only 32 byte headerchachaKey- 32-byte ChaCha20-Poly1305 key for the payload, the static introduction keyn- packet number from the header, also the payload noncehdrKey1- 32-byte ChaCha20 key protecting header bytes 0-7hdrKey2- 32-byte ChaCha20 key protecting header bytes 8-31
encryptSessionConfirmed
private void encryptSessionConfirmed(UDPPacket packet, HandshakeState state, int mtu, int numFragments, int addPadding, boolean isIPv6, byte[] hdrKey1, byte[] hdrKey2, SSU2Payload.RIBlock riblock, EstablishmentManager.Token token) If numFragments larger than 1, we do NOT encrypt the header here, that's caller's responsibility.- Parameters:
packet- containing only 16 byte headerstate- the Noise handshake state, still open, that encrypts the payload in placemtu- peer's MTU in bytes, including the IP and UDP headers, which are subtracted herenumFragments- total SessionConfirmed fragments, 1 - 15, written to the header flags byteaddPadding- force-add exactly this size a padding block, for jumbo onlyisIPv6- true to subtract the 40-byte IPv6 header from the MTU, false for the 20-byte IPv4 headerhdrKey1- 32-byte ChaCha20 key protecting header bytes 0-7hdrKey2- 32-byte ChaCha20 key protecting header bytes 8-15riblock- the RouterInfo block to send, already builttoken- may be null
encryptDataPacket
private void encryptDataPacket(UDPPacket packet, CipherState chacha, long n, byte[] hdrKey1, byte[] hdrKey2) Encrypts the payload of one data packet and appends the MAC.- Parameters:
packet- containing 16 byte header and all data with length set to the end of the data. This will extend the length by 16 for the MAC.chacha- the peer's send cipher state, locked for the duration of the encryptionn- packet number from the header, also the payload noncehdrKey1- 32-byte ChaCha20 key protecting header bytes 0-7hdrKey2- 32-byte ChaCha20 key protecting header bytes 8-15
getPadding
Random padding block up to the maximum size.- Parameters:
len- current length of the packet including IP/UDP header (unless header subtracted from max) If len == 0 ensure 8 byte block minimummax- max length of the packet- Returns:
- null if no room
getPadding
Random padding block with an explicit cap.- Parameters:
len- current length of the packet including IP/UDP header (unless header subtracted from max) If len == 0 ensure 8 byte block minimummax- max length of the packetmaxPadding- max length of the padding (not including block header)- Returns:
- null if no room
getMaxDataSize
Calculates the maximum payload size that can be sent to this peer in a single data packet.- Parameters:
peer- the destination session, may be null- Returns:
- the max data size in bytes