Philipp Krüger 8ca5916dec fix(proto): Ignore PATH_CIDS_BLOCKED when it refers to abandoned paths (#710)
## Description

When receiving a `PATH_CIDS_BLOCKED` frame we used to check the
`next_seq` value for protocol compliance like so:
```rs
if next_seq.0
    > self
        .local_cid_state
        .get(&path_id)
        .map(|cid_state| cid_state.active_seq().1 + 1)
        .unwrap_or_default()
{
    return Err(TransportError::PROTOCOL_VIOLATION(
        "PATH_CIDS_BLOCKED next sequence number larger than in local state",
    ));
}
```
But the `.unwrap_or_default()` would fail if we don't actually store
path state for the given path. This can occur when the path has already
been abandoned and discarded.
Usually, we wouldn't hit this case because the most likely value for
`next_seq` for PATH_CIDS_BLOCKED is 0, *unless* it is lost and
retransmitted.

The added regression test simulates all of these rare circumstances at
once:
- All PATH_NEW_CONNECTION_ID frames from server to client are delayed
such that opening a path on the client side generates a
PATH_CIDS_BLOCKED frame
- The PATH_CIDS_BLOCKED frame is lost as well to ensure it is resent
with a newer `next_seq` number *after* the delayed
PATH_NEW_CONNECTION_ID frames have come in
- The path is abadoned and discarded on both ends before we send the
delayed PATH_CIDS_BLOCKED frame triggering the bug

The fix is to correctly check for
`!self.abandoned_paths.contains(&path_id)` in the above condition.

## Breaking Changes

None

## Notes & open questions

This bug report is what originally prompted this work:
https://github.com/n0-computer/iroh/issues/4347

It should now be fixed.

## Change checklist

- [x] Self-review.
- [x] Tests if relevant.
- [x] All breaking changes documented.
2026-06-18 16:24:31 +00:00
2026-02-06 10:04:56 +00:00
2026-06-15 11:20:37 +02:00
2026-06-15 11:20:37 +02:00
2025-03-24 15:57:34 +00:00
2026-06-15 11:20:37 +02:00
2026-06-11 09:52:50 +00:00
2026-06-15 11:20:37 +02:00
2026-03-09 14:40:18 +01:00
2020-01-27 10:21:10 -08:00
2026-03-09 14:45:33 +01:00
2025-02-23 11:52:46 +00:00

noq

Documentation Crates.io Chat License: MIT License: Apache 2.0

General purpose implementation of the QUIC transport protocol in pure Rust. Noq is built as an async-friendly API in the noq crate on top of a sans-io protocol library in noq-proto.

Noq started out as a fork of the excellent Quinn project. The main focus of development has been towards adding support for more QUIC (draft) extensions:

Features

  • Easy to use futures-based async API.
  • Client and server server functionality.
  • 0-RTT and 0.5-RTT data support.
  • Ordered and unordered stream reads.
  • Custom and zero-length connection identifiers.
  • Fully pluggable crypto API with a Rustls implementation using ring or aws-lc-rs provided by default for convenience.
  • Broad platform support, including Linux, Windows, macOS, android, iOS and wasm.

Standards

The noq library aims to be correct implementation of various QUIC standards:

Getting started

Examples at https://github.com/n0-computer/noq/blob/main/noq/examples

$ cargo run --example server ./
$ cargo run --example client https://localhost:4433/Cargo.toml

This launches an HTTP 0.9 server over the QUIC transport on the loopback address serving the current working directory, with the client fetching ./Cargo.toml. By default, the server generates a self-signed certificate and stores it to disk, where the client will automatically find and trust it.

License

Copyright 2025 The quinn developers Copyright 2025 N0, INC.

This project is licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this project by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

S
Description
noq, a QUIC implementation in Rust
Readme 110 MiB
Languages
Rust 99.3%
Python 0.5%
Shell 0.2%