... | @@ -2,10 +2,11 @@ |
... | @@ -2,10 +2,11 @@ |
|
|
|
|
|
Google's QUIC is a very interesting and recent protocol. You can find its code in chromium, there's no external library...
|
|
Google's QUIC is a very interesting and recent protocol. You can find its code in chromium, there's no external library...
|
|
|
|
|
|
You can find some of its features summarized [here](http://www.riskcompletefailure.com/2013/08/quic-notes-stream-multiplexing-and.html) and [here](http://www.riskcompletefailure.com/2013/07/quic-notes-rational-fec-and-head-of.html), and there's a tentative [RFC](https://datatracker.ietf.org/doc/draft-tsvwg-quic-protocol/)
|
|
You can find some of its features summarized [here](http://www.riskcompletefailure.com/2013/08/quic-notes-stream-multiplexing-and.html) and [here](http://www.riskcompletefailure.com/2013/07/quic-notes-rational-fec-and-head-of.html), and there's the [RFC](https://datatracker.ietf.org/doc/draft-ietf-quic-transport/)
|
|
|
|
|
|
There is also an introductory video (nothing advanced ~51m) on [youtube](http://www.youtube.com/watch?v=hQZ-0mXFmk8)
|
|
There is also an introductory video (nothing advanced ~51m) on [youtube](http://www.youtube.com/watch?v=hQZ-0mXFmk8)
|
|
|
|
|
|
|
|
A lot of documents are pooled [here](https://www.chromium.org/quic).
|
|
The main document that lists its features and design rationale is on [google docs](https://docs.google.com/a/google.com/document/d/1RNHkx_VvKWyWg6Lr8SZ-saqsQx7rFV-ev2jRFUoVD34/preview?sle=true&pli=1) , there's a [crypto document](https://docs.google.com/document/d/1g5nIXAIkN_Y-7XJW5K45IblHd_L2f5LTaDUDwvZ5L6g/view) and there is also a [wire layout specification](https://docs.google.com/document/d/1WJvyZflAO2pq77yOLbp9NsGjC1CHetAXV8I0fQe-B_U/view) you can read
|
|
The main document that lists its features and design rationale is on [google docs](https://docs.google.com/a/google.com/document/d/1RNHkx_VvKWyWg6Lr8SZ-saqsQx7rFV-ev2jRFUoVD34/preview?sle=true&pli=1) , there's a [crypto document](https://docs.google.com/document/d/1g5nIXAIkN_Y-7XJW5K45IblHd_L2f5LTaDUDwvZ5L6g/view) and there is also a [wire layout specification](https://docs.google.com/document/d/1WJvyZflAO2pq77yOLbp9NsGjC1CHetAXV8I0fQe-B_U/view) you can read
|
|
|
|
|
|
Here we will look at the main differences between QUIC and Fenrir
|
|
Here we will look at the main differences between QUIC and Fenrir
|
... | @@ -24,30 +25,40 @@ Fenrir Tries to do the same as QUIC in regard to the number of packets required |
... | @@ -24,30 +25,40 @@ Fenrir Tries to do the same as QUIC in regard to the number of packets required |
|
|
|
|
|
The main difference in general is that **QUIC seems to be a way to bring TLS to a lower level, while focusing on latency, while in Fenrir we focus a lot more on security and flexibility.**
|
|
The main difference in general is that **QUIC seems to be a way to bring TLS to a lower level, while focusing on latency, while in Fenrir we focus a lot more on security and flexibility.**
|
|
|
|
|
|
### packet size
|
|
### Header & packet size
|
|
|
|
|
|
By having integrated encryption and authentication we don't need redundant identifiers for the connection, and can optimize the packet structure as a whole.
|
|
By having integrated encryption and authentication both QUIC and Fenrir do not need redundant identifiers for the connection, and can optimize the packet structure as a whole.
|
|
|
|
|
|
The result is that you can send encrypted and authenticated messages with Fenrir in just about 30 bytes. QUIC can take up to 45 bytes.
|
|
The result is that you can send encrypted and authenticated messages with Fenrir in just about 30-40 bytes.
|
|
|
|
QUIC is more difficult to understand, since basically all of its header fields are completely optional and with varied length. Just for an estimate, a QUIC header can go from 1 byte to 60 bytes.
|
|
|
|
|
|
The packet structure is not extremely different, but the way it's handled in the protocol differs greatly:
|
|
QUIC format can sometimes be more efficient than Fenrir, but at the cost of a more difficult parser.
|
|
in QUIC all multiplexed streams are ordered, reliable streams, while in Fenrir you can choose any combination of (un)reliable, (un)ordered delivery, both stream and datagram.
|
|
Fenrir also includes the option of multiple alignments, while in QUIC everything is byte-aligned.
|
|
|
|
|
|
|
|
### Features
|
|
|
|
|
|
|
|
In QUIC all multiplexed streams are ordered, reliable streams. As a hack you can have unreliable streams by exploting the implicit stream creation: send data in a new stream, and then forget about that stream. This way it is not tracked as a reliable stream.
|
|
|
|
The problem with this approach is that it can not span multiple packets and is actually just a hack.
|
|
|
|
|
|
|
|
In Fenrir you need to explicitly create each stream, but you can choose any combination of (un)reliable, (un)ordered delivery, both stream and datagram.
|
|
|
|
|
|
|
|
Fenrir is also the first protocol to support both unicast **and** multicast connections tied together. This means that while you send data on a multicast stream you can send additional recovery data or lost packets in a normal unicast stream, and have Fenrir combine them together, obtaining something akin to **reliable multicast**
|
|
|
|
|
|
### RTT needed
|
|
### RTT needed
|
|
|
|
|
|
The connection setup is a 4-way handshake with cookies to avoid SYN flood attacks, much like SCTP. Fenrir uses a similar structure.
|
|
The connection setup is a 4-way handshake with cookies to avoid SYN flood attacks, much like SCTP. Fenrir uses a similar structure.
|
|
|
|
|
|
|
|
#### 0-RTT
|
|
|
|
|
|
QUIC supports a 0-RTT reconnection. Fenrir does not do less than 1-RTT by design. But maintaining long timeouts for the connections will have the same result. 0-RTT connections are avoided in Fenrir as they leave way too many options for amplification attacks.
|
|
QUIC supports a 0-RTT reconnection. Fenrir does not do less than 1-RTT by design. But maintaining long timeouts for the connections will have the same result. 0-RTT connections are avoided in Fenrir as they leave way too many options for amplification attacks.
|
|
|
|
|
|
|
|
While QUIC supports 0-RTT connections, applications need to be designed to avoid amplification attacks by requiring an ulterior RTT before sending a lot of data. Relying on applications to implement the correct security features for such as a feature is bound to create a lot of amplification attacks.
|
|
|
|
|
|
Here we can see what we meant before by "latency vs security". To reduce latency QUIC does neither a full PFS (next section), or have a full protection against replay attacks. As you can read in the [QUIC Crypto](https://docs.google.com/document/d/1g5nIXAIkN_Y-7XJW5K45IblHd_L2f5LTaDUDwvZ5L6g/edit) document:
|
|
Here we can see what we meant before by "latency vs security". To reduce latency QUIC does neither a full PFS (next section), or have a full protection against replay attacks. As you can read in the [QUIC Crypto](https://docs.google.com/document/d/1g5nIXAIkN_Y-7XJW5K45IblHd_L2f5LTaDUDwvZ5L6g/edit) document:
|
|
|
|
|
|
> QUIC doesn’t provide replay protection for the client’s data prior to the server’s first reply. It’s up the application to ensure that any such information is safe if replayed by an attacker.
|
|
> QUIC doesn’t provide replay protection for the client’s data prior to the server’s first reply. It’s up the application to ensure that any such information is safe if replayed by an attacker.
|
|
|
|
|
|
This is the same old mistake of pushing security details on the developers. It will likely never happen.
|
|
This is the same old mistake of pushing security details on the developers. Developers will (unknowingly) ignore it, until everyone will use a common framework that limits QUIC features to the safest subset. Same as happened with OAuth.
|
|
|
|
|
|
Fenrir is actually a federated authentication protocol, so things are a little more complex, and the first time we authenticate into a federated server we might actually get up to 4 RTTs. 3 RTTs are the norm after the client has its authentication data signed for its domain.
|
|
|
|
|
|
|
|
Both QUIC and Fenrir use an id for the connection. This also means that both protocols have automatically enabled multi-homing features and support mobile devices. It is unclear how QUIC handles those, though. Given their use of the "entropy bit" it is likely that multihoming and mobility can not be used.
|
|
|
|
|
|
|
|
|
|
|
|
## Perfect forward secrecy
|
|
## Perfect forward secrecy
|
... | @@ -56,30 +67,30 @@ PFS is mandatory in both Fenrir and QUIC. QUIC changes the ephemeral public key |
... | @@ -56,30 +67,30 @@ PFS is mandatory in both Fenrir and QUIC. QUIC changes the ephemeral public key |
|
|
|
|
|
This enables QUIC to have one RTT less then Fenrir, but the connection is not totally isolated.
|
|
This enables QUIC to have one RTT less then Fenrir, but the connection is not totally isolated.
|
|
|
|
|
|
As long as the ephemeral public key is changed quickly (let's say, every couple of hours at most) this seems a good idea, and Fenrir implements it with the Stateful handshake.
|
|
As long as the ephemeral public key is changed quickly (let's say, every couple of hours at most) this seems a good idea, and Fenrir implements it with the Stateful and Directory synchronized handshakes.
|
|
|
|
|
|
|
|
An other example of latency vs security. To decrease latency, the initial data sent by the client is NOT protected by PFS. Instead, PFS is set up at the first packet sent by the server. The client can, however, still send non-PFS data in this period of time. The first bytes of a connection might contain login data or other information, and I see no reason to treat this differently, so in Fenrir such behaviour is avoided by design.
|
|
|
|
|
|
An other example of latency vs security. To decrease latency, the initial data sent by the client is NOT protected by PFS. Instead, PFS is set up at the first packet sent by the server. The client can, however, still
|
|
|
|
send non-PFS data in this period of time.
|
|
|
|
|
|
|
|
### PFS on resumed connections
|
|
### PFS on resumed connections
|
|
|
|
|
|
QUIC simply tries to guess that the last public key used is still in use, so it hopes for a 0-RTT reconnection, and has a fallback to 1-RTT reconnection.
|
|
QUIC simply tries to guess that the last public key used is still in use, so it hopes for a 0-RTT reconnection, and has a fallback to 1-RTT reconnection.
|
|
|
|
|
|
Connection resumption is not a thing in Fenrir, as we just need to give longer timeouts, and there will be no need for further handshakes.
|
|
Connection resumption is not a thing in Fenrir (yet), as we just need to give longer timeouts, and there will be no need for further handshakes.
|
|
|
|
|
|
## Forward Error Correction
|
|
## Forward Error Correction
|
|
|
|
|
|
This is a very nice improvement of QUIC over previous protocols:
|
|
This is a very nice improvement of QUIC over previous protocols:
|
|
|
|
|
|
Basically every 2 packets we send an other packet which is the XOR of the previous 2. So if one was lost, the receiver can reconstruct it without asking a retransmission.
|
|
Basically every 2 packets QUIC sends an other packet which is the XOR of the previous 2 (like RAID-4). So if one was lost, the receiver can reconstruct it without asking a retransmission.
|
|
|
|
|
|
This is actually a good idea, and I decided to copy it and put it into Fenrir. However it is not flexible enough, so I created the [libRaptorQ](https://www.fenrirproject.org/Luker/libRaptorQ) project that generalizes the same concept over any number of source packets and repair packets. It's not as quick as a single XOR, but much more flexible.
|
|
This is actually a good idea, and I decided to copy it and put it into Fenrir. However it is not flexible enough, so I created the [libRaptorQ](https://www.fenrirproject.org/Luker/libRaptorQ) project implements the RaptorQ algorithm that generalizes the same concept over any number of source packets and repair packets. It's not as quick as a single XOR, but much more flexible.
|
|
|
|
|
|
## Stream/connection identifiers
|
|
## Stream/connection identifiers
|
|
|
|
|
|
Both QUIC and Fenrir have a variable number of streams to be used in a connection, and both use a 32-bit connection identifier at the beginning of the packet. (in QUIC the id length is actually variable)
|
|
Both QUIC and Fenrir have a variable number of streams to be used in a connection, and both use a 32-bit connection identifier at the beginning of the packet. (in QUIC the id length is actually variable)
|
|
|
|
|
|
QUIC stream identifiers are actually larger (32 bits) then Fenrir's (16 bits), but really, today's applications use just one stream (TCP) for everything, 65534 streams should be enough. Even assuming it is not enough, introducing an other multiplexing layer before the application is trivial.
|
|
QUIC stream identifiers are actually larger (1-8 bytes) then Fenrir's (4 bytes), but really, today's applications use just one stream (TCP) for everything, 65534 streams should be enough. Even assuming it is not enough, introducing an other multiplexing layer before the application is trivial. Trying to get a proper priority out of all the streams is also an other problem itself.
|
|
|
|
|
|
QUIC uses a 64-bit sequence number for its streams, while Fenrir has a 30-bit one, like extended TCP. Having a bigger sequence number is actually a good thing, as it helps a lot in high-latency-high bandwidth connections, such as satellite ones, but 30 bit should be enough for everybody. Putting together the stream multiplexing and the 30-bit counter already lets us have connections in the range of the Tb/s for satellite connections.
|
|
QUIC uses a 64-bit sequence number for its streams, while Fenrir has a 30-bit one, like extended TCP. Having a bigger sequence number is actually a good thing, as it helps a lot in high-latency-high bandwidth connections, such as satellite ones, but 30 bit should be enough for everybody. Putting together the stream multiplexing and the 30-bit counter already lets us have connections in the range of the Tb/s for satellite connections.
|
|
|
|
|
... | @@ -91,7 +102,7 @@ This has some limitations, however. It means that if we use a 30-bit offset we c |
... | @@ -91,7 +102,7 @@ This has some limitations, however. It means that if we use a 30-bit offset we c |
|
|
|
|
|
Does this means that the maximum message size will be 2^30 = 1Gb ? Not really. That is the maximum window size. But as soon as we have the initial part of the message complete, we can put it into a buffer, and wait for the rest, and we can keep doing this as many times as we want.
|
|
Does this means that the maximum message size will be 2^30 = 1Gb ? Not really. That is the maximum window size. But as soon as we have the initial part of the message complete, we can put it into a buffer, and wait for the rest, and we can keep doing this as many times as we want.
|
|
|
|
|
|
Of course, you should not expect Fenrir to handle a multi-Gb buffer. The packet will be truncated at a certain length (user defined) and a partial message will be delivered to the user application. Big messages are usually just file transfer anyway, so chunking them does not give any problem. And do you really want Fenrir to keep a 2^64 buffer?
|
|
Of course, you should not expect Fenrir to handle a multi-Gb buffer. The message will be truncated at a certain length (user defined) and a partial message will be delivered to the user application. Big messages are usually just file transfer anyway, so chunking them does not give any problem. And do you really want Fenrir to keep a 2^64 buffer?
|
|
|
|
|
|
## Proof of ownership
|
|
## Proof of ownership
|
|
|
|
|
... | @@ -114,12 +125,6 @@ The SCTP and Fenrir way of doing ACKs is not only to acknowledge the last stream |
... | @@ -114,12 +125,6 @@ The SCTP and Fenrir way of doing ACKs is not only to acknowledge the last stream |
|
|
|
|
|
So if we received the bytes 1...10 15...30 of a message, maybe because the 10..15 bytes were lost, we acknowledge both the 1...10 and 15...30 chunks in a single message. This should help the sender to retransmit only the part that we want, so in case of retransmission we should have a lot less duplicate packets
|
|
So if we received the bytes 1...10 15...30 of a message, maybe because the 10..15 bytes were lost, we acknowledge both the 1...10 and 15...30 chunks in a single message. This should help the sender to retransmit only the part that we want, so in case of retransmission we should have a lot less duplicate packets
|
|
|
|
|
|
A second, new ACK type is under development: it is based on the Forward Error Correction idea (see earlier section), where we only need to know how may repair symbols the receiver needs in order to recover the lost data, without listing all the holes in the received message. This should be much more efficient, but brings some problems due to the nature of the FEC algorithm, which is probabilistic.
|
|
NACK support is being developed atm.
|
|
|
|
|
|
## Congestion Control
|
|
|
|
|
|
|
|
Quick uses the TCP-Cubic algorithm, the same used by linux today. It can also track the time of each packet with timers.
|
|
A second, new ACK type is under development: it is based on the Forward Error Correction idea (see earlier section), where we only need to know how may repair symbols the receiver needs in order to recover the lost data, without listing all the holes in the received message. This should be much more efficient, but brings some problems due to the nature of the FEC algorithm, which is probabilistic. |
|
|
|
|
|
I haven't decided exactly what to use yet, but I think I'll be going for the [curvecp congestion control](http://curvecp.org/decongestion.html) algorithm, as it tracks both bandwidth and RTT estimations.
|
|
|
|
|
|
|
|
I will be doing some simulations before deciding the final algorithm, but the idea is to track packet loss, RTT and trying to get as close as possible to the maximum without dropping the transmission rate too much once we reach a congestion or have a packet loss (see [TCP behavior](http://c3lab.poliba.it/images/5/5a/Tcp_westwood.gif) ) |
|
|