quinn-rs / quinn

Async-friendly QUIC implementation in Rust
Apache License 2.0
3.76k stars 380 forks source link

QUIC Version negotiation packet #1249

Closed BiagioFesta closed 2 years ago

BiagioFesta commented 2 years ago

Maybe I am missing something, but it seems version negotiation is missing.

Example

 ┌────────────────┐       ┌────────────────┐
 │  Quinn Client  │       │  Quinn Server  │
 │     quinn 0.8  │       │     quinn 0.7  │
 │                │ ◄───► │                │
 │    QUIC v1     │       │    QUIC draft29│
 │                │       │                │
 └────────────────┘       └────────────────┘
> Client: Initial (version 1)
> Server: Handshake (version draft29)

> Client: "Why draft29?!?". Socket closed.

In the above example, I use a quinn(0.8) client against a quinn(0.7) server. On the client initial packet, the server replies with a handshake with its different version.

This is already reproducible with the quinn examples (client/server).

Expectation

> Client: Initial (version 1)
> Server: Version Negotiation (supported version: draft27, supported version: draft28, draft29)

> (maybe?) Client: Initial (draft 29)
...

Probably this is a dup of: #1235

However, I am not sure is exactly the same thing. Honestly, I did not read the extension draft mentioned by that issue yet. However, it seems the version negotiation packet is already covered (at least in part by the QUIC standard). If I am not misreading the server should reply with the supported versions.

RFC9000#6:Version Negotiation (emphasis mine):

[...] A server sends a Version Negotiation packet in response to each packet that might initiate a new connection; [...] If the version selected by the client is not acceptable to the server, the server responds with a Version Negotiation packet; see Section 17.2.1. This includes a list of versions that the server will accept. [...]

(The same for draft-29)

Ralith commented 2 years ago

QUIC 1 does not support version negotiation; see RFC9000 §6.2:

How to perform version negotiation is left as future work defined by future Standards Track specifications. In particular, that future work will ensure robustness against version downgrade attacks; see Section 21.12.

§21.12:

Future versions of QUIC that use Version Negotiation packets MUST define a mechanism that is robust against version downgrade attacks.

As no such mechanism is defined, Quinn's current behavior is correct. If you want to communicate with quinn 0.7 servers, you must set ClientConfig::version to 0xff00_0020. Note that a client so configured will also be compatible with quinn 0.8 servers using a default configuration, but may or may not be compatible with other QUIC implementations.

Ralith commented 2 years ago

To clarify, Quinn's expected behavior in the situation you outlined is for the server to reply with a version negotiation packet, and for the client to then fail the connection with ConnectionError::VersionMismatch. If you have evidence that the connection is failing in a different fashion, this is a minor bug; please share details.

BiagioFesta commented 2 years ago

To clarify, Quinn's expected behavior in the situation you outlined is for the server to reply with a version negotiation packet, and for the client to then fail the connection with ConnectionError::VersionMismatch. If you have evidence that the connection is failing in a different fashion, this is a minor bug; please share details.

That's exactly what I meant.

Clearly I wasn't clear enough, sorry. But that's why I said it might not be not a dup of that ticket. As title, I am referring to the version negotiation packet. In my expectation the client's reply is a maybe (?).

Anyway, I tried to reproduce it again this morning and it seems that the server is correctly sending the version negotiation packet. Probably there was something unclear in my tested environment yesterday.

I am going to close this issue, sorry for the false alarm :)

Ralith commented 2 years ago

No worries!