elixir_quic — experimental QUIC v1 library
This app is imported into the http_fetch umbrella from gsmlg-dev/ex_quic@14974913390e12d03a78a2903d18e55a04fa89d6. It shares the coordinated umbrella version and requires the matching sibling ex_ssl version. The imported TLS source came from gsmlg-dev/ex_ssl@fb47051355c9d0a29caee046fa060a745ad0ce5b; historical package comparison remains recorded in the TLS contract. Independent certificate handshakes, Retry, single-fault packet impairment and certificate/ALPN rejection passed in the source repository against aioquic 1.2.0. Full protocol lifecycle and product acceptance remain incomplete. See the Phase 1 acceptance record for source evidence and limitations.
The project has three mandatory goals: JA3/JA4 observation of visible QUIC ClientHello data, measured profile-controlled client behavior, and opt-in integration with the Abyss UDP server. It is not a client-only plan.
Start here
Use CODEX-START.md for the imported historical plan. The first execution slice implements M0–M1: engineering/dependency contracts, wire codecs and Initial/Retry protection with tests. It does not claim that UDP networking is complete.
| Document | Purpose |
|---|---|
| Phase 1 plan / Consumer API / I/O contract | Reliable streams, public handles, admission outcomes and integration ownership |
| Implementation plan | Ordered M0–M6 tasks, dependencies and concrete exit gates |
| Architecture / Detailed design | Functional core, runtime ownership, routing, sending and resource constraints |
| Actual TLS contract | Existing public SSL.QUIC API, action order and limitations |
| Fingerprint design | Observation, matching, simulation and fidelity evidence |
| Abyss integration | Opt-in pre-handler dispatch and shared-socket lifecycle |
| Testing / PRD | Requirements, independent oracles and experimental release acceptance |
| ex_ssl review | F1 closure and honest scope of current verification |
| Revision changes / Sources | Supersession rules and pinned evidence |
Dependency and status
SSL.QUIC and SSL.Fingerprint are real upstream APIs at the reviewed pin, not work to invent in ex_quic. The umbrella resolves ex_ssl from the local apps/ex_ssl sibling; its upstream source pin and historical Hex package comparison are recorded in the TLS contract. See implementation progress and runtime evidence and independent peer evidence and M3-C through M3-E acceptance for implemented surfaces and remaining gates; design documents also include future modules.
The upstream formatter finding is closed and the inspected supported-runtime compiler/test and TLS-reference jobs pass. Current known upstream limitations, historical macOS TCP integration failures and the absence of a whole-library security audit remain explicit in the review document.
Adopting this package
The Hex package and OTP application are elixir_quic / :elixir_quic.
The canonical source repository is gsmlg-dev/http_fetch; the public module namespace is Quic.
After the shared 0.16.1 release is published, depend on:
{:elixir_quic, "== 0.16.1"}
Consumers moving from the Git dependency must replace their :ex_quic
dependency/application entry with :elixir_quic, including application config
or release configuration that names the old app. Rename calls and aliases from
QUIC / QUIC.* to Quic / Quic.*; function names and arguments are unchanged.
The unrelated Hex package named ex_quic is not this library.
Local tests cover codecs, packet protection, inspection, recovery, and both-role UDP certificate handshakes. These self-connection tests are not independent interoperability or security certification. The full product gate requires observer + measured client profiles + Abyss termination; HTTP/3/QPACK and additional TLS features remain separate work.
Application ALPN and unreliable datagrams
Profiles accept application ALPN, for example
Quic.Profile.compile(:ordered, alpn: ["h3"]); the default remains ex-quic.
Negotiating h3 does not implement HTTP/3 or QPACK. Consumers own those protocols.
Quic.capabilities().http3 remains false; the separate
elixir_quic_http3 companion implements the
HTTP/3 beta client profile with static/literal QPACK. Its application support
does not expand raw QUIC's protocol ownership.
RFC 9221 DATAGRAM support is opt-in per endpoint with
datagram: [max_frame_size: 1200, max_items: 64, max_buffer_bytes: 65_536].
Use Quic.send_datagram/3 and Quic.read_datagrams/3 with a public connection
handle. DATAGRAM payloads are unreliable, message-oriented, congestion-controlled,
and never retransmitted after loss. See the consumer contract
for negotiation, size limits, bounded queues and admission semantics.
Established servers also accept authenticated client NAT rebinding and IP
migration, retaining connection and stream handles. Quic.capabilities().migration
is %{peer: [:server], local: []}; there is no explicit local migration API yet.
The engine bounds validation to two paths with separate amplification/recovery
state and path-specific CID bindings. See the consumer contract
and independent UDP acceptance.
Resumption and 0-RTT remain unsupported.
Idle expiry and keepalive
Set idle_timeout: :infinity on Quic.listen/1 or Quic.client/1 to advertise
RFC 9000's disabled local idle limit (max_idle_timeout = 0). The default remains
30,000 ms and is advertised to the peer. Both endpoints must disable their limits
for no finite idle timer to be armed; a peer's finite limit still applies.
There is no absolute connection lifetime imposed by this option. Handshake,
operation, closing and draining deadlines remain finite.
Quic.info(connection) exposes idle_timeout.local_ms, peer_ms,
negotiated_ms, and effective_ms (positive milliseconds or :infinity).
The effective finite period is at least three current PTOs. Quic.ping/2 admits
one bounded ack-eliciting PING through normal recovery and operation accounting.
Applications can choose a finite cadence below the peer's advertised limit;
there is no automatic keepalive loop. PING admission is not a peer ACK, and
repeated sends without successfully processing peer packets cannot postpone
local expiry indefinitely. See the consumer contract
for reset rules, raw transport parameters and peer-policy limits.
Publishing
elixir_quic is one of nine packages released together from the http_fetch umbrella. See the root release workflow and contributor guidance for validation, dependency order, and publication. HexDocs publication is separate from package publication.
License
MIT. See LICENSE. Copied test-only TLS fixtures retain their upstream
Apache-2.0 license in test/fixtures/tls/LICENSE and are excluded from the Hex package.