aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Yu <yumike@google.com>2023-02-03 08:56:48 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2023-02-03 08:56:48 +0000
commitbc84d7fe6a68fe896149e38d2cd700a2ae74d69e (patch)
tree1f18091d69d3556cffc993a3c0b09e22afcc150d
parent1443fcc38ac624d25713fd9f38fbe806f057a7c1 (diff)
parenteea8ca9dc8451f68d81ebcbda454369edfbdcbaa (diff)
downloadquiche-bc84d7fe6a68fe896149e38d2cd700a2ae74d69e.tar.gz
Initial stateless reset detection am: e1d5b66375 am: eea8ca9dc8
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/quiche/+/2411180 Change-Id: I9033fe184139cfa8c4d818ed28ecd7266850437f Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--patches/Initial-stateless-reset-detection.patch91
-rw-r--r--src/lib.rs36
2 files changed, 126 insertions, 1 deletions
diff --git a/patches/Initial-stateless-reset-detection.patch b/patches/Initial-stateless-reset-detection.patch
new file mode 100644
index 0000000..24461a7
--- /dev/null
+++ b/patches/Initial-stateless-reset-detection.patch
@@ -0,0 +1,91 @@
+From 2c1ce8948b8fe1a11ea57ff8d1bcee07d038f49e Mon Sep 17 00:00:00 2001
+From: Mike Yu <yumike@google.com>
+Date: Wed, 1 Feb 2023 06:14:18 +0000
+Subject: [PATCH] Initial stateless reset detection
+
+Backport the stateless reset patch to AOSP (current
+version of quiche is 0.14.0) so that we don't need to
+wait until the patch is released to a quiche version
+newer than 0.16.0 (currently, the latest version is 0.16.0).
+
+This patch is slightly modified because the type of
+stateless_reset_token is different (In 0.14.0 the
+type is Option<Vec<u8>>; in 0.16.0 the type is
+Option<u128>).
+
+Source patch:
+https://github.com/cloudflare/quiche/commit/c6357db0b5311010e266637eda2f645b7fa91df4.
+
+Bug: 242832641
+Bug: 245074765
+Bug: 258767218
+Test: cd packages/modules/DnsResolver && atest
+Test: cd external/rust/crates/quiche && atest
+Test: 1. Applied ag/20124672 to DnsResolver
+ 2. Ran dnschk every 5 minutes for 1 hour
+ 3. Checked the log:
+ a. Confirmed that some stateless reset packets were received
+ b. Confirmed that DNS queries fallback'ed to DoT immediately
+ after DnsResolver received stateless reset packets
+Change-Id: Ife933f54ac6ec1098a9046673ca200c6b4e2ebbf
+---
+ src/lib.rs | 36 +++++++++++++++++++++++++++++++++++-
+ 1 file changed, 35 insertions(+), 1 deletion(-)
+
+diff --git a/src/lib.rs b/src/lib.rs
+index 2e13278..d590979 100644
+--- a/src/lib.rs
++++ b/src/lib.rs
+@@ -1864,7 +1864,17 @@ impl Connection {
+ let read = match self.recv_single(&mut buf[len - left..len], &info) {
+ Ok(v) => v,
+
+- Err(Error::Done) => left,
++ Err(Error::Done) => {
++ // If the packet can't be processed or decrypted, check if
++ // it's a stateless reset.
++ if self.is_stateless_reset(&buf[len - left..len]) {
++ trace!("{} packet is a stateless reset", self.trace_id);
++
++ self.closed = true;
++ }
++
++ left
++ },
+
+ Err(e) => {
+ // In case of error processing the incoming packet, close
+@@ -1900,6 +1910,30 @@ impl Connection {
+ Ok(done)
+ }
+
++ /// Returns true if a QUIC packet is a stateless reset.
++ fn is_stateless_reset(&self, buf: &[u8]) -> bool {
++ // If the packet is too small, then we just throw it away.
++ let buf_len = buf.len();
++ if buf_len < 21 {
++ return false;
++ }
++
++ // TODO: we should iterate over all active destination connection IDs
++ // and check against their reset token.
++ match &self.peer_transport_params.stateless_reset_token {
++ Some(token) => {
++ let token_len = 16;
++ ring::constant_time::verify_slices_are_equal(
++ &token,
++ &buf[buf_len - token_len..buf_len],
++ )
++ .is_ok()
++ },
++
++ None => false,
++ }
++ }
++
+ /// Processes a single QUIC packet received from the peer.
+ ///
+ /// On success the number of bytes processed from the input buffer is
+--
+2.39.1.456.gfc5497dd1b-goog
+
diff --git a/src/lib.rs b/src/lib.rs
index 2e13278..d590979 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1864,7 +1864,17 @@ impl Connection {
let read = match self.recv_single(&mut buf[len - left..len], &info) {
Ok(v) => v,
- Err(Error::Done) => left,
+ Err(Error::Done) => {
+ // If the packet can't be processed or decrypted, check if
+ // it's a stateless reset.
+ if self.is_stateless_reset(&buf[len - left..len]) {
+ trace!("{} packet is a stateless reset", self.trace_id);
+
+ self.closed = true;
+ }
+
+ left
+ },
Err(e) => {
// In case of error processing the incoming packet, close
@@ -1900,6 +1910,30 @@ impl Connection {
Ok(done)
}
+ /// Returns true if a QUIC packet is a stateless reset.
+ fn is_stateless_reset(&self, buf: &[u8]) -> bool {
+ // If the packet is too small, then we just throw it away.
+ let buf_len = buf.len();
+ if buf_len < 21 {
+ return false;
+ }
+
+ // TODO: we should iterate over all active destination connection IDs
+ // and check against their reset token.
+ match &self.peer_transport_params.stateless_reset_token {
+ Some(token) => {
+ let token_len = 16;
+ ring::constant_time::verify_slices_are_equal(
+ &token,
+ &buf[buf_len - token_len..buf_len],
+ )
+ .is_ok()
+ },
+
+ None => false,
+ }
+ }
+
/// Processes a single QUIC packet received from the peer.
///
/// On success the number of bytes processed from the input buffer is