개요
quiche는 Rust로 구현된 QUIC 전송 프로토콜 및 HTTP/3 라이브러리로, 패킷과 연결 상태를 처리하는 저수준 API를 제공합니다. 애플리케이션은 I/O, 이벤트 루프 및 타이머를 직접 처리해야 합니다. quiche는 Cloudflare 엣지 네트워크, Android DNS over HTTP/3 및 curl의 HTTP/3 지원에 사용되고 있습니다.
README 미리보기
\n\n[](https://crates.io/crates/quiche)\n[](https://docs.rs/quiche)\n[](https://opensource.org/licenses/BSD-2-Clause)\n\n\n[quiche] is an implementation of the QUIC transport protocol and HTTP/3 as\nspecified by the [IETF]. It provides a low level API for processing QUIC packets\nand handling connection state. The application is responsible for providing I/O\n(e.g. sockets handling) as well as an event loop with support for timers.\n\nFor more information on how quiche came about and some insights into its design\nyou can read a [post] on Cloudflare's blog that goes into some more detail.\n\n[quiche]: https://docs.quic.tech/quiche/\n[ietf]: https://quicwg.org/\n[post]: https://blog.cloudflare.com/enjoy-a-slice-of-quic-and-rust/\n\nWho uses quiche?\n----------------\n\n### Cloudflare\n\nquiche powers Cloudflare edge network's [HTTP/3 support][cloudflare-http3]. The\n[cloudflare-quic.com](https://cloudflare-quic.com) website can be used for\ntesting and experimentation.\n\n### Android\n\nAndroid's DNS resolver uses quiche to [implement DNS over HTTP/3][android-http3].\n\n### curl\n\nquiche can be [integrated into curl][curl-http3] to provide support for HTTP/3.\n\n[cloudflare-http3]: https://blog.cloudflare.com/http3-the-past-present-and-future/\n[android-http3]: https://security.googleblog.com/2022/07/dns-over-http3-in-android.html\n[curl-http3]: https://github.com/curl/curl/blob/master/docs/HTTP3.md#quiche-version\n\nGetting Started\n---------------\n\n### Command-line apps\n\nBefore diving into the quiche API, here are a few examples on how to use the\nquiche tools provided as part of the [quiche-apps](apps/) crate. These are not\nsuitable for production environments; see [disclaimers and\nnotes](#disclaimers-and-notes).\n\nAfter cloning the project according to the command mentioned in the [building](#building) section, the client can be run as follows:\n\n```bash\n $ cargo run --bin quiche-client -- https://cloudflare-quic.com/\n```\n\nwhile the server can be run
FAQ (5)
문제 해결송신자가 MAX_DATA를 초과하지 않았는데도 quiche가 장시간 실행되는 QUIC 벌크 전송을 FLOW_CONTROL_ERROR로 닫는 문제를 어떻게 해결할 수 있나요?
이 문제는 quiche 이슈 #2696으로 인해 발생합니다. 길이가 0인 non-FIN STREAM 프레임은 스트림의 최대 수신 오프셋을 전진시키고 연결 수준 흐름 제어에 반영되지만, RecvBuf::write()는 스트림 high-water mark를 전진시키지 않은 채 빈 프레임을 버립니다. 이후 실제 데이터가 해당 오프셋에 도달하면 동일한 바이트가 다시 반영되어, 결국 정상적인 트래픽이 MAX_DATA를 초과한 것처럼 보이게 됩니다. 이 문제는 리비전 0b1a89af에서 재현되었으며, 일반적으로 긴 전송의 후반부에 큰 스트림 ID/오프셋으로 인해 남은 패킷 용량을 정확히 채우는 빈 STREAM 프레임이 생성될 때 발생합니다. 수신 측은 RecvBuf::write()의 빈 non-FIN 조기 반환 경로를 수정하여 반환 전에 high-water mark를 동기화하도록 고치세요: self.len = cmp::max(self.len, buf.max_off());. 송신 측 수정도 적용하세요: 스트림 프레임 emit()이 (0, false)를 반환할 때 STREAM 프레임을 인코딩하지 말고, 이를 application-limited가 아닌 packet-size-limited로 처리하여 BBR2 샘플이 app-limited로 표시되지 않도록 하세요. quiche를 다시 빌드하여 재배포하거나, 이슈 #2696에 대한 PR이 포함된 릴리스로 업그레이드하세요. 임시 완화 조치만 가능하고 양쪽 피어를 모두 제어할 수 있는 경우에는, 송신 측 변경을 배포하는 것만으로도 이러한 중복된 빈 프레임이 생성되는 것을 막을 수 있습니다.
문제 해결quiche의 zero-length STREAM FIN이 drop되어 peer가 EOF를 수신하지 못하는 문제를 해결하는 방법은?
이것은 quiche 0.29.2의 버그입니다: SendBuf::is_complete()는 FIN을 전달하는 STREAM 프레임이 전송되거나 확인(acknowledge)된 적이 없더라도, 모든 스트림 바이트가 확인되면 스트림이 완료된 것으로 간주합니다. 따라서 이미 확인된 오프셋에서의 길이가 0인 stream_send(id, b"", true)는 폐기될 수 있으며, 피어는 최종 스트림 크기를 알지 못하게 됩니다.
stream: track FIN acknowledgements separately 수정이 포함된 릴리스로 업그레이드하세요. 이 수정은 FIN 확인을 확인된 바이트 범위와 독립적으로 추적합니다: fin_off 위치에서 FIN=true인 STREAM 프레임이 확인될 때까지 스트림은 유지되고, 빈 FIN은 플러시 및 재전송 가능한 상태로 남습니다.
전송할 최종 데이터가 있는 경우 임시 해결 방법으로, 나중에 빈 FIN을 보내는 대신 데이터와 FIN을 함께 전송하세요:
// 피할 것:
stream_send(id, b"response", false)?;
// ... 데이터가 확인된 후 ...
stream_send(id, b"", true)?;
// 권장:
stream_send(id, b"response", true)?;
실제로 길이가 0인 스트림의 경우에는 FIN을 함께 실어 보낼 수 있는 비어 있지 않은 데이터 프레임이 없으므로, 업그레이드하거나 FIN 추적 패치를 적용해야 합니다.
문제 해결quiche가 RFC 9000의 3x anti-amplification 제한을 초과하지 않도록 하려면 어떻게 해야 하나요?
3보다 큰 anti-amplification factor를 설정하지 마세요. quiche는 기본적으로 RFC를 준수하는 값 3을 사용하므로, 기본값을 사용하는 애플리케이션은 안전합니다. Rust에서 config.set_max_amplification_factor(v)를 호출하거나 C에서 quiche_config_set_max_amplification_factor()를 호출하는 경우, 반드시 v <= 3이 되도록 하세요. 프로토콜 최대값으로는 3을 사용하고, 더 엄격한 제한이 필요하면 더 작은 값을 사용하세요. 예: config.set_max_amplification_factor(3);. 4와 같은 값은 주소 검증 전에 3 * received_bytes를 초과하는 전송을 의도적으로 허용하며, RFC 9000 §8.1/RFC 9001 §9.3을 위반합니다. 규정 준수를 강제해야 하는 포크를 유지 관리하는 경우, setter에서 입력을 거부하거나 클램프하세요. 예를 들어 self.max_amplification_factor = v.min(3);처럼 작성할 수 있습니다.
문제 해결중복된 RETIRE_CONNECTION_ID 프레임 이후 quiche가 PROTOCOL VIOLATION으로 QUIC 연결을 종료하는 문제를 어떻게 해결하나요?
issue #1833에 대한 수정이 포함된 릴리스로 quiche를 업그레이드하거나, 링크된 PR을 적용/cherry-pick한 후 다시 빌드하십시오. Git에서 빌드하는 경우, 중복 RETIRE_CONNECTION_ID 수정이 포함된 quiche 리비전을 사용하십시오.
올바른 동작은 다음과 같습니다:
1. 먼저 활성 connection-ID 목록에서 시퀀스 번호를 조회합니다.
2. 시퀀스 번호가 이미 폐기되었거나 알 수 없는 경우, 해당 프레임을 유효한 재전송으로 간주하여 무시합니다.
3. ID가 활성 상태인 경우에만 폐기합니다.
4. 활성 ID를 폐기했을 때 사용 가능한 connection ID가 남지 않는 경우에만 프로토콜 위반을 반환합니다.
quiche/src/cid.rs에서 inner.len() 가용성 검사는 광고된 시퀀스 번호가 현재 활성 상태인지 확인하기 전에 실행되어서는 안 됩니다. RFC 9000은 패킷 손실 후 프레임이 재전송될 수 있으므로 중복 RETIRE_CONNECTION_ID 프레임을 허용합니다.
임시 해결 방법: 패치가 적용된 quiche 빌드를 사용하거나, 폐기로 인해 connection-ID 집합이 고갈되지 않도록 피어가 추가적인 활성 connection ID를 사용할 수 있도록 하십시오.
문제 해결accept stream이 drop된 후에도 tokio-quiche listener가 UDP socket을 해제하지 않는 문제를 어떻게 해결하나요?
이 문제는 tokio-quiche 0.20.0에 영향을 줍니다. 라우터는 accept_sink.is_closed()를 확인하지만, 유휴 상태의 리스너는 스트림 종료에 대한 waker를 등록하지 않으므로 UDP/연결 이벤트에서 대기(parked) 상태로 남아 소켓을 계속 보유하게 됩니다. 라우터의 poll/select 루프에서 accept 채널의 Sender::closed() future를 보유하고 폴링하는 업스트림 수정 사항을 적용하세요. 그러면 반환된 accept 스트림이 드롭될 때 유휴 리스너가 깨어나 종료될 수 있습니다. PR fix(tokio-quiche): wake idle listener on stream drop이 포함된 릴리스를 사용하거나, 해당 PR로 tokio-quiche를 패치하거나 수정된 커밋을 빌드하세요. 임시 해결 방법으로는 UDP 패킷을 수신하면 대기 중인 라우터가 깨어나 closed 플래그를 확인할 수 있지만, 패치가 확실한 해결책입니다.