diff --git a/quinn-proto/src/connection/mod.rs b/quinn-proto/src/connection/mod.rs index 20ee55d50..f84c3ad6b 100644 --- a/quinn-proto/src/connection/mod.rs +++ b/quinn-proto/src/connection/mod.rs @@ -1865,8 +1865,14 @@ impl Connection { None }; + let packet = partial_decode.data(); + let stateless_reset = packet.len() >= RESET_TOKEN_SIZE + 5 + && self.peer_params.stateless_reset_token.as_deref() + == Some(&packet[packet.len() - RESET_TOKEN_SIZE..]); + match partial_decode.finish(header_crypto) { - Ok(packet) => self.handle_packet(now, remote, ecn, packet), + Ok(packet) => self.handle_packet(now, remote, ecn, Some(packet), stateless_reset), + Err(_) if stateless_reset => self.handle_packet(now, remote, ecn, None, true), Err(e) => { trace!("unable to complete packet decoding: {}", e); } @@ -1878,15 +1884,18 @@ impl Connection { now: Instant, remote: SocketAddr, ecn: Option, - mut packet: Packet, + packet: Option, + stateless_reset: bool, ) { - trace!( - "got {:?} packet ({} bytes) from {} using id {}", - packet.header.space(), - packet.payload.len() + packet.header_data.len(), - remote, - packet.header.dst_cid(), - ); + if let Some(ref packet) = packet { + trace!( + "got {:?} packet ({} bytes) from {} using id {}", + packet.header.space(), + packet.payload.len() + packet.header_data.len(), + remote, + packet.header.dst_cid(), + ); + } if self.is_handshaking() && remote != self.path.remote { debug!("discarding packet with unexpected remote during handshake"); @@ -1895,15 +1904,14 @@ impl Connection { let was_closed = self.state.is_closed(); let was_drained = self.state.is_drained(); - let stateless_reset = self - .peer_params - .stateless_reset_token - .map_or(false, |token| { - packet.payload.len() >= RESET_TOKEN_SIZE - && packet.payload[packet.payload.len() - RESET_TOKEN_SIZE..] == token[..] - }); - let result = match self.decrypt_packet(now, &mut packet) { + let decrypted = match packet { + None => Err(None), + Some(mut packet) => self + .decrypt_packet(now, &mut packet) + .map(move |number| (packet, number)), + }; + let result = match decrypted { Err(Some(e)) => { warn!("illegal packet: {}", e); Err(e.into()) @@ -1929,7 +1937,7 @@ impl Connection { } } } - Ok(number) => { + Ok((packet, number)) => { let span = match number { Some(pn) => trace_span!("recv", space = ?packet.header.space(), pn), None => trace_span!("recv", space = ?packet.header.space()), diff --git a/quinn-proto/src/tests/mod.rs b/quinn-proto/src/tests/mod.rs index 483ba0f19..2b93a89b1 100644 --- a/quinn-proto/src/tests/mod.rs +++ b/quinn-proto/src/tests/mod.rs @@ -175,13 +175,10 @@ fn server_stateless_reset() { let mut pair = Pair::new(endpoint_config.clone(), server_config()); let (client_ch, _) = pair.connect(); + pair.drive(); // Flush any post-handshake frames pair.server.endpoint = Endpoint::new(endpoint_config, Some(Arc::new(server_config()))); - // Send something big enough to allow room for a smaller stateless reset. - pair.client.connections.get_mut(&client_ch).unwrap().close( - pair.time, - VarInt(42), - (&[0xab; 128][..]).into(), - ); + // Force the server to generate the smallest possible stateless reset + pair.client.connections.get_mut(&client_ch).unwrap().ping(); info!("resetting"); pair.drive(); assert_matches!(