{% extends "_layout.html" %} {% block title %}I2NP Specification{% endblock %} {% block content %} Updated August 2010, current as of router version 0.8
The I2P Network Protocol (I2NP), which is sandwiched between I2CP and the various I2P transport protocols, manages the routing and mixing of messages between routers, as well as the selection of what transports to use when communicating with a peer for which there are multiple common transports supported.
Common header to all I2NP messages, which contains important information like a checksum, expiration date, etc.
1 byte Integer specifying the type of this message, followed by an 4 byte Integer specifying the message-id. After that there is an expiration Date, followed by an 2 byte Integer specifying the length of the message payload, followed by an Hash, which is truncated to the first byte. After that the actual message data follows.
{% filter escape %} +----+----+----+----+----+ |type| msg-id | +----+----+----+----+----+----+----+----+ | expiration | +----+----+----+----+----+----+----+----+ | size |chks| +----+----+----+ {% endfilter %}
{% filter escape %} type :: Integer length -> 1 byte purpose -> identifies the message type (see table below) msg-id :: Integer length -> 4 bytes purpose -> uniquely identifies this message (for some time at least) expiration :: Date 8 bytes date this message will expire size :: Integer length -> 2 bytes purpose -> length of the payload chks :: Hash length -> 1 byte purpose -> checksum of the payload SHA256 hash truncated to the first byte data :: Data length -> $size bytes purpose -> actual message contents {% endfilter %}
One Record in a set of multiple records to request the creation of one hop in the tunnel. For more details see the tunnel overview and the tunnel creation specification.
TunnelId to receive messages on, followed by the Hash of our RouterIdentity. After that the TunnelId and the Hash of the next router's RouterIdentity follow.
{% filter escape %} Cleartext: +----+----+----+----+----+----+----+----+ | receive_tunnel | our_ident | +----+----+----+----+ + | | + + | | + + | | + +----+----+----+----+ | | next_tunnel | +----+----+----+----+----+----+----+----+ | next_ident | + + | | + + | | + + | | +----+----+----+----+----+----+----+----+ | layer_key | + + | | + + | | + + | | +----+----+----+----+----+----+----+----+ | iv_key | + + | | + + | | + + | | +----+----+----+----+----+----+----+----+ | reply_key | + + | | + + | | + + | | +----+----+----+----+----+----+----+----+ | reply_iv | + + | | +----+----+----+----+----+----+----+----+ |flag| request_time | send_msg_id +----+----+----+----+----+----+----+----+ | | +----+ + | 29 bytes padding | + + | | + +----+----+ | | +----+----+----+----+----+----+ ElGamal encrypted: +----+----+----+----+----+----+----+----+ | toPeer | + + | | +----+----+----+----+----+----+----+----+ | encrypted data ... | ~ ~ | | +----+----+----+----+----+----+----+----+ ElGamal and AES encrypted: +----+----+----+----+----+----+----+----+ | encrypted data ... | ~ ~ | | +----+----+----+----+----+----+----+----+ {% endfilter %}
{% filter escape %} unencrypted: receive_tunnel :: TunnelId length -> 4 bytes our_ident :: Hash length -> 32 bytes next_tunnel :: TunnelId length -> 4 bytes next_ident :: Hash length -> 32 bytes layer_key :: SessionKey length -> 32 bytes iv_key :: SessionKey length -> 32 bytes reply_key :: SessionKey length -> 32 bytes reply_iv :: data length -> 16 bytes flag :: Integer length -> 1 byte request_time :: Integer length -> 4 bytes Hours since the epoch, i.e. current time / 3600 send_message_id :: Integer length -> 4 bytes padding :: Data length -> 29 bytes source -> random total length: 222 ElGamal encrypted: toPeer :: First 16 bytes of the SHA-256 Hash of the peer's router identity length -> 16 bytes encrypted_data :: ElGamal-2048 encrypted data (see notes) length -> 512 total length: 528 ElGamal and AES encrypted: encrypted_data :: ElGamal and AES encrypted data length -> 528 total length: 528 {% endfilter %}
{% filter escape %} unencrypted: +----+----+----+----+----+----+----+----+ | random data... | ~ ~ | | + +----+ | |ret | +----+----+----+----+----+----+----+----+ {% endfilter %}
{% filter escape %} unencrypted: bytes 0-526: random data byte 527 : reply encrypted: bytes 0-527: AES-encrypted record(note: same size as BuildRequestRecord) total length: 528 {% endfilter %}
See also the tunnel creation specification.
{% filter escape %} unencrypted: +----+----+----+----+----+----+----+----+ | Delivery Instructions | ~ ~ ~ ~ | | +----+----+----+----+----+----+----+----+ | I2NP Message | ~ ~ ~ ~ | | +----+----+----+----+----+----+----+----+ | Clove ID | Expiration +----+----+----+----+----+----+----+----+ | Certificate | +----+----+----+----+----+----+----+ {% endfilter %}
unencrypted: Delivery Instructions :: as defined here Length varies but is typically 39, 43, or 47 bytes I2NP Message :: Any I2NP Message Clove ID :: 4 byte Integer Expiration :: Date (8 bytes) Certificate :: Always NULL in the current implementation (3 bytes total, all zeroes)
Message | Type |
---|---|
DatabaseStore | 1 |
DatabaseLookup | 2 |
DatabaseSearchReply | 3 |
DeliveryStatus | 10 |
Garlic | 11 |
TunnelData | 18 |
TunnelGateway | 19 |
Data | 20 |
TunnelBuild | 21 |
TunnelBuildReply | 22 |
VariableTunnelBuild | 23 |
VariableTunnelBuildReply | 24 |
An unsolicited database store, or the response to a successful Database Lookup Message
An uncompressed LeaseSet or a compressed RouterInfo
with reply token: +----+----+----+----+----+----+----+----+ | SHA256 Hash as key | + + | | + + | | + + | | +----+----+----+----+----+----+----+----+ |type| reply token | reply tunnel- +----+----+----+----+----+----+----+----+ Id | SHA256 of the gateway RouterInfo | +----+ + | | + + | | + + | | + +----+----+----+----+----+----+----+ | | data ... +----+--------\\ with reply token == 0: +----+----+----+----+----+----+----+----+ | SHA256 Hash as key | + + | | + + | | + + | | +----+----+----+----+----+----+----+----+ |type| 0 | data ... +----+-------------------+---------\\
key: 32 bytes SHA256 hash type: 1 byte type identifier mapping: 0 RouterInfo 1 LeaseSet reply token: 4 bytes If greater than zero, a Delivery Status Message is requested with the Message ID set to the value of the Reply Token. A floodfill router is also expected to flood the data to the closest floodfill peers if the token is greater than zero. reply tunnelId: 4 byte Tunnel ID only included if reply token > 0 This is the tunnel ID of the inbound gateway of the tunnel the response should be sent to reply gateway: 32 bytes Hash of the routerInfo entry to reach the gateway only included if reply token > 0 This is the router hash of the inbound gateway of the tunnel the response should be sent to data: If type == 0, data is a 2-byte integer specifying the number of bytes that follow, followed by a gzip-compressed RouterInfo. If type == 1, data is an uncompressed LeaseSet.
{% filter escape %} +----+----+----+----+----+----+----+----+ | SHA256 hash as the key to look up | + + | | + + | | + + | | +----+----+----+----+----+----+----+----+ | SHA256 hash of the routerInfo | + who is asking, or the gateway to + | send the reply to | + + | | + + | | +----+----+----+----+----+----+----+----+ |flag| reply tunnelId |size | | +----+----+----+----+----+----+----+ + | SHA256 of $key1 to exclude | + + | | + + | | + +----+ | | | +----+----+----+----+----+----+----+ + | SHA256 of $key2 to exclude | .... {% endfilter %}
{% filter escape %} key: 32 bytes SHA256 hash of the object to lookup from: 32 bytes If flag == 0, the SHA256 hash of the routerInfo entry this request came from (and to which the reply should be sent) If flag == 1, the SHA256 hash of the reply tunnel gateway (to which the reply should be sent) flag: 1 byte valid values: 0 FALSE => send reply directly 1 TRUE => send reply to some tunnel reply tunnelId: 4 byte Tunnel ID only included if flag==TRUE tunnelId of the tunnel to send the reply to size: 2 byte Integer valid range: 0-512 number of peers to exclude from the Database Search Reply Message excludedPeers: Rest of the message are $size SHA256 hashes of 32 bytes each (total $size*32 bytes) If the lookup fails, these peers are requested to be excluded from the list in the Database Search Reply Message. If excludedPeers includes a hash of all zeroes, the request is exploratory, and the Database Search Reply Message is requested to list non-floodfill routers only. {% endfilter %}
To do: Use a bit of the flag field to request an AES-encrypted response. Use parts of this message as the key and IV? Add a message ID also? Backward compatibility?
The response to a failed Database Lookup Message
A list of router hashes closest to the requested key
{% filter escape %} +----+----+----+----+----+----+----+----+ | SHA256 hash as query key | + + | | + + | | + + | | +----+----+----+----+----+----+----+----+ |num | peer hash $1 | +----+ + | | + + | | + + | | + +----+----+----+----+----+----+----+ | | | +----+.... $num peer hashes + +----+----+----+----+----+----+----+ | | from | +----+ + | | + + | | + + | | + +----+----+----+----+----+----+----+ | | +----+ {% endfilter %}
{% filter escape %} key: 32 bytes SHA256 of the object being searched num: 1 byte Integer number of peer hashes that follow peer hash: 32 bytes SHA256 of the RouterInfo that the other router thinks are close to the key $num entries from: 32 bytes SHA256 of the RouterInfo of the router this reply was sent from {% endfilter %}
The 'from' hash is unauthenticated and cannot be trusted.
A simple message acknowledgment. Generally created by the message originator, and wrapped in a Garlic Message with the message itself, to be returned by the destination.
The ID of the delivered message, and the creation or arrival time.
{% filter escape %} +----+----+----+----+----+----+----+----+----+----+----+----+ |msg-id | arrival-time | +----+----+----+----+----+----+----+----+----+----+----+----+ {% endfilter %}
{% filter escape %} msg-id: 4 bytes unique ID of the message we deliver the DeliveryStatus for(see common I2NP header for details) arrival-time: 8 bytes time the message was successfully created or delivered {% endfilter %}
Used to wrap multiple encrypted I2NP Messages
When decrypted, a series of Garlic Cloves.
{% filter escape %} encrypted: +----+----+----+----+----+----+----+----+ | length | data | +----+----+----+----+ + | | ~ ~ ~ ~ | | +----+----+----+----+----+----+----+----+ unencrypted data: +----+----+----+----+----+----+----+----+ |num | clove 1 | +----+ + | | ~ ~ ~ ~ | | +----+----+----+----+----+----+----+----+ | clove 2 ... | ~ ~ ~ ~ | | +----+----+----+----+----+----+----+----+ | Certificate | Message ID | +----+----+----+----+----+----+----+----+ Expiration | +----+----+----+----+----+----+----+ {% endfilter %}
{% filter escape %} Encrypted: length: 4 byte Integer number of bytes that follow 0 - 64 KB data: $length bytes ElGamal encrypted data Unencrypted data: num: 1 byte Integer number of Garlic Cloves to follow clove: A Garlic Clove Certificate :: Always NULL in the current implementation (3 bytes total, all zeroes) Message ID :: 4 byte Integer Expiration :: Date (8 bytes) {% endfilter %}
{% filter escape %} +----+----+----+----+----+----+----+----+ | length | data | +----+----+----+----+ | | | ~ ~ ~ ~ | | +----+----+----+----+----+----+----+----+ {% endfilter %}
{% filter escape %} length: 4 byte Integer number of bytes that follow 0 - 64 KB - should always be 1024 data: 1024 bytes payload data.. fixed to 1024 bytes {% endfilter %}
{% filter escape %} +----+----+----+----+----+----+--\\----+ | tunnelId | length | data...| +----+----+----+----+----+----+--\\----+ {% endfilter %}
{% filter escape %} tunnelId: 4 byte Tunnel ID identifies the tunnel this message is directed at length: 2 byte Integer length of the payload data: $length bytes actual payload of this message {% endfilter %}
Used as a wrapper for encrypted Garlic Messages and Garlic Cloves. Also used previously for network load testing.
A length Integer, followed by opaque data.
{% filter escape %} +----+----+----+----+----+---//--+ | length | data... | +----+----+----+----+----+---//--+ {% endfilter %}
{% filter escape %} length: 4 bytes length of the payload data: $length bytes actual payload of this message {% endfilter %}
{% filter escape %} +----+----+----+----+----+----+----+----+ | Record 0 ... | | | +----+----+----+----+----+----+----+----+ | Record 1 ... | ..... +----+----+----+----+----+----+----+----+ | Record 7 ... | | | +----+----+----+----+----+----+----+----+ {% endfilter %}
{% filter escape %} Just 8 Build Request Records attached together Record size: 528 bytes Total size: 8*528 = 4224 bytes {% endfilter %}
See also the tunnel creation specification.
{% filter escape %} same format as TunnelBuild message, with Build Response Records {% endfilter %}
See also the tunnel creation specification.
{% filter escape %} +----+----+----+----+----+----+----+----+ |num | .... {% endfilter %}
{% filter escape %} Same format as TunnelBuildMessage, except for the addition of an "num" field in front and $num number of Build Request Records instead of 8 num: 1 byte Integer Valid values: 1-8 Record size: 528 bytes Total size: 1 + $num*528 {% endfilter %}
{% filter escape %} Same format as VariableTunnelBuild message, with Build Response Records {% endfilter %}