Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.Sign up
Freenet 0.7 communicates with its Opennet and Darknet peers through UDP. The production protocol has drawbacks and to counter them a new protocol has been specified. This page aims to be a technical description of the UDP protocol (the only protocol currently in use), for discussion of the Transport Layer in its entirety see Transport Layer.
Table of Contents
The packet format currently used by Freenet 0.7. See the proposed new packet format, which is somewhat more secure.
Authentication is through JFKi (Just Fast Keying initiator variant).
Authentication/link setup packets are super-encrypted with a temporary setup key derived from the identities of the nodes involved. The plaintext (the actual STS exchange) is padded with between 0 and 100 bytes of random data, is encrypted, and an IV and hash of the plaintext are prepended. Thus the packets are variable size and contain no recognizable bytes. The key exchange produces a single session key which is used in both directions. For more details, check the source! :)
- Hash of plaintext (32 bytes)
- Plaintext encrypted using session key in PCFB mode (= CFB as we use 256/256 rijndael), with IV = the above hash
- Sequence number (4 bytes)
- Random padding (12 bytes)
- Version = 0 (1 byte)
- Sequence number (4 bytes) - may be -1 if no messages included, otherwise incremented on each packet sent
- Real sequence number (4 bytes) - only included if sequence number = -1
- Reference sequence number (4 bytes) - last seen sequence number of *incoming* packets
- Number of acks (1 byte, unsigned)
- Ack's (1 byte, unsigned offsets from the reference sequence number)
- Number of retransmit requests
- Retransmit requests (as ack's)
- Number of ack requests
- Ack requests (relative to seqno/real seqno)
- Number of forgotten packets
- Forgotten packet numbers (relative to seqno/real seqno)
- Number of messages (1 byte unsigned)
This protocol aims to be more TCP like but as freenet does not require that messages/packets (currently messages do not span more than one packet) be delivered in order it allows for out-of-order delivery.
During handshaking, the peers establish three keys for each direction of the connection: the encryption key, the authentication key, and the IV key. Different keys must be used in each direction.
Each plaintext packet starts with a unique, non-wrapping sequence number. This is distinct from the payload number described below - if a packet is retransmitted, it will have the same payload number as the original, but a new sequence number.
The IV for encryption is obtained by encrypting the unique sequence number with the IV key. This is equivalent to using a block cipher in CTR mode as a pseudo-random number generator to generate the IVs. The IVs are guaranteed to be unique.
The packet is encrypted in CFB mode using its unique IV and the encryption key. A MAC is then calculated over the encrypted packet using the authentication key, and the MAC is prepended to the encrypted packet.
There is no need to send the packet's unique sequence number in plaintext - the receiver can calculate the IV in advance and the packet is encrypted using a stream cipher, so the receiver can calculate the ciphertext sequence number in advance. The receiver simply looks for the ciphertext sequence numbers of the next few expected packets instead of looking for the plaintext sequence numbers. This makes it harder for eavesdroppers to identify Freenet traffic, because no part of the packet is in plaintext. A window of 64 sequence numbers should be sufficient to cope with reordering at the IP layer (IPSec uses 32). Note that it is possible, though unlikely, for two packets in the window to have the same ciphertext sequence number due to the random nature of the IVs - the receiver must detect this case and try both possibilities.
Each packet contains:
- A count of the number of acks (unsigned byte).
- Zero or more acks. Each ack echoes the payload number of a packet received in the other direction.
- These are encoded as follows: The first (lowest) ack is a full 4-byte unsigned value; subsequent acks are 2 byte unsigned offsets from this (add to the first to get the ack number).
- For each ack, the time in milliseconds that the ack was queued for, so we can accurately determine the round-trip time (2 bytes each).
- A count of the number of payload messages (unsigned byte). If there are no payload messages, skip the following.
- A 4-byte payload number. This number will be used by the receiver to acknowledge receipt of the packet, and unlike the unique sequence number it will not change if the packet is retransmitted. However, apart from retransmissions the payload number should be unique and non-wrapping.
- Freenet messages follow the payload number. Each message starts with 2 bytes indicating its type followed by 2 bytes indicating its length. Messages are never split across more than one packet.
The receiver detects duplicate packets by keeping a bitmap of received payload numbers. The bitmap contains up to 2^16 entries, starting with the lowest payload number not yet received. The sender must not send payload number n+2^16 until payload number n has been acknowledged - however, it must still send acks when necessary (packets that contain acks but no Freenet messages do not require payload numbers).
In the current code, hold acknowledgements and messages for up to 100ms before sending. In future it would be useful to be able to make this a function of the round-trip time, so we need an accurate delay time in the packets. Also, some messages may be less urgent than others.