quinn

repository·main·Indexed 26 days ago

https://github.com/quinn-rs/quinn

A pure-Rust, async-compatible implementation of the IETF QUIC transport protocol. It provides a high-level Tokio-based API via the quinn crate, a sans-io protocol state machine via quinn-proto, and tuned UDP sockets via quinn-udp. Key features include stream multiplexing, support for reliable and unreliable data, connection migration, and TLS 1.3 integration using rustls.

Tokens
7.2K
Snippets
8
Records
58
Agent score
89%

What's inside quinn

  1. Understand Quinn crate architecture

    main

    Quinn is composed of several crates depending on your integration needs:

    • quinn: The high-level async API based on tokio. This is the primary crate used by most developers.
    • quinn-proto: A deterministic state machine of the QUIC protocol that performs no I/O internally (sans-io). It is suitable for use with custom event loops or potentially for C/C++ bindings.
    • quinn-udp: UDP sockets tuned with ECN information specifically for the QUIC protocol.
    • bench: Benchmarks without an external framework.
    • fuzz: Fuzz testing utilities.
  2. Compare TCP, UDP, and QUIC features

    main

    When deciding whether to use QUIC via quinn, understand how it compares to traditional protocols:

    • TCP: Connection-oriented, reliable, stream-based, and runs control flow/congestion avoidance in kernel space. It has a header size of ~20 bytes.
    • UDP: Connectionless, unreliable, message-based, and lacks built-in control flow or congestion avoidance. It has a header size of 8 bytes.
    • QUIC: Connection-oriented, reliable (unreliable is supported as an extension), stream-based, and runs control flow/congestion avoidance in userspace. It is based on UDP and has a header size of ~16 bytes (depending on connection ID).
  3. Core Features of Quinn

    main

    Quinn provides a complete implementation of the QUIC protocol, including:

    • Stream Multiplexing: Multiple independent streams over a single connection.
    • Reliable and Unreliable Data: Support for both ordered/reliable and unordered/unreliable data delivery.
    • Connection Migration: Support for maintaining connections when client IP addresses change.
    • TLS 1.3 Integration: Uses rustls for secure handshakes.
    • Flow Control: Built-in stream-level and connection-level flow control.
  4. Compare Connection Setup Durations

    main

    QUIC provides more efficient connection establishment compared to the traditional TCP + TLS + HTTP stack:

    • TCP + TLS 1.3: Requires approximately 10 handshake messages (6 for TCP and 4 for TLS 1.3).
    • QUIC: Integrates the transport protocol and TLS handshakes into a single process, significantly reducing the number of messages required to establish a session.
  5. Configure an insecure connection by disabling certificate verification

    main

    For development or testing where you want the client to trust any server without valid certificates, you can disable verification. This requires the dangerous_configuration feature flag from the rustls crate.

    1. Add rustls with the dangerous_configuration feature to your Cargo.toml.
    2. Implement the rustls::client::ServerCertVerifier trait to always return successful verification.
    3. Use this verifier in your quinn::ClientConfig.
    4. Apply the configuration to your endpoint using Endpoint::set_default_client_config().

    Warning: Do not use this in production as it makes the connection vulnerable to man-in-the-middle attacks.

  6. Configure certificate validation and trust

    main

    Quinn clients validate the cryptographic identity of servers by default. For standard use cases, using certificates from Let's Encrypt is recommended.

    For specialized use cases like peer-to-peer, trust-on-first-use (TOFU), or non-domain-name servers, you can implement arbitrary certificate validation by customizing the rustls configuration. See the insecure_connection.rs example in the repository for implementation details.

    To support TOFU, servers that generate self-signed certificates should write them to persistent storage and reuse them in future runs. You can use the rcgen crate to generate self-signed certificates on demand.

  7. Use self-signed certificates with Quinn

    main

    Self-signed certificates are simpler for testing because they don't require a third-party Certificate Authority (CA), but they do not protect against man-in-the-middle attacks. You can generate them using the rcgen crate or openssl.

    When using rcgen, the generated Certificate can be serialized into .der or .pem formats for use in your Quinn configuration.

  8. Run Quinn examples for client and server

    main

    You can quickly test the Quinn implementation by running the provided examples. The following commands launch an HTTP 0.9 server on the loopback address serving the current working directory, and a client that fetches ./Cargo.toml. By default, the server generates a self-signed certificate and stores it to disk, which the client will automatically find and trust.

    $ cargo run --example server ./
    $ cargo run --example client https://localhost:4433/Cargo.toml
  9. Use non-self-signed certificates (e.g., Let's Encrypt)

    main

    To use certificates from a trusted CA like Let's Encrypt, you typically use certbot to handle the cryptographic challenges.

    For a standalone test server, you can run: certbot certonly --standalone

    This will generate fullchain.pem (the certificate) and privkey.pem (the private key). You can then load these files into your Quinn server configuration.

  10. Set up a QUIC server and client using Endpoint

    main

    To use quinn, you start with the Endpoint struct, which serves as the library's entry point.

    Server Setup

    Use the Endpoint::server() method to bind an endpoint to a socket. The resulting Endpoint can be used to accept incoming connections.

    Client Setup

    Use the Endpoint::client() method to create a client endpoint. To establish a connection, call the connect(server_name) method on the client endpoint. The server_name argument must be the DNS name that matches the certificate configured on the server.

  11. Understand Head-of-line Blocking in TCP vs QUIC

    main

    In TCP, if a single packet is lost during transmission, all subsequent packets must wait at the transport layer until the lost packet is retransmitted and arrives. This is known as Head-of-line blocking, which increases latency in high-throughput scenarios like multiplayer gaming or web page loading.

    While HTTP/2 attempts to mitigate this via multiplexing, a single packet loss still blocks all response streams because they all reside within a single TCP stream. QUIC is designed to resolve this by providing independent streams, ensuring that packet loss in one stream does not block others.

  12. Get started with Quinn

    main

    Quinn is a high-performance, asynchronous QUIC implementation in Rust. It is built on top of tokio and rustls. To use Quinn, add it to your Cargo.toml dependencies.

    Note: Quinn requires a runtime like tokio to handle asynchronous operations.