Skip to content

Commit

Permalink
Implement draft-ietf-quic-bit-grease-02
Browse files Browse the repository at this point in the history
  • Loading branch information
Ralith committed Jan 22, 2022
1 parent a319e66 commit 6b8cf90
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 8 deletions.
13 changes: 13 additions & 0 deletions quinn-proto/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,7 @@ pub struct EndpointConfig {
pub(crate) connection_id_generator_factory:
Arc<dyn Fn() -> Box<dyn ConnectionIdGenerator> + Send + Sync>,
pub(crate) supported_versions: Vec<u32>,
pub(crate) grease_quic_bit: bool,
}

impl EndpointConfig {
Expand All @@ -320,6 +321,7 @@ impl EndpointConfig {
max_udp_payload_size: 1480u32.into(), // Typical internet MTU minus IPv4 and UDP overhead, rounded up to a multiple of 8
connection_id_generator_factory: Arc::new(cid_factory),
supported_versions: DEFAULT_SUPPORTED_VERSIONS.to_vec(),
grease_quic_bit: true,
}
}

Expand Down Expand Up @@ -375,6 +377,16 @@ impl EndpointConfig {
self.supported_versions = supported_versions;
self
}

/// Whether to accept QUIC packets containing any value for the fixed bit
///
/// Enabled by default. Helps protect against protocol ossification and makes traffic less
/// identifiable to observers. Disable if helping observers identify this traffic as QUIC is
/// desired.
pub fn grease_quic_bit(&mut self, value: bool) -> &mut Self {
self.grease_quic_bit = value;
self
}
}

impl fmt::Debug for EndpointConfig {
Expand All @@ -384,6 +396,7 @@ impl fmt::Debug for EndpointConfig {
.field("max_udp_payload_size", &self.max_udp_payload_size)
.field("cid_generator_factory", &"[ elided ]")
.field("supported_versions", &self.supported_versions)
.field("grease_quic_bit", &self.grease_quic_bit)
.finish()
}
}
Expand Down
14 changes: 11 additions & 3 deletions quinn-proto/src/connection/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ use crate::{
EndpointEventInner, IssuedCid,
},
transport_parameters::TransportParameters,
Dir, Frame, Side, StreamId, Transmit, TransportError, TransportErrorCode, VarInt,
MAX_STREAM_COUNT, MIN_INITIAL_SIZE, RESET_TOKEN_SIZE, TIMER_GRANULARITY,
Dir, EndpointConfig, Frame, Side, StreamId, Transmit, TransportError, TransportErrorCode,
VarInt, MAX_STREAM_COUNT, MIN_INITIAL_SIZE, RESET_TOKEN_SIZE, TIMER_GRANULARITY,
};

mod assembler;
Expand Down Expand Up @@ -118,6 +118,7 @@ use timer::{Timer, TimerTable};
/// call to [`handle_event`](Self::handle_event) at that same instant; however
/// events or timeouts with different instants must not be interleaved.
pub struct Connection {
endpoint_config: Arc<EndpointConfig>,
server_config: Option<Arc<ServerConfig>>,
config: Arc<TransportConfig>,
rng: StdRng,
Expand Down Expand Up @@ -217,6 +218,7 @@ pub struct Connection {

impl Connection {
pub(crate) fn new(
endpoint_config: Arc<EndpointConfig>,
server_config: Option<Arc<ServerConfig>>,
config: Arc<TransportConfig>,
init_cid: ConnectionId,
Expand Down Expand Up @@ -246,6 +248,7 @@ impl Connection {
let mut rng = StdRng::from_entropy();
let path_validated = server_config.as_ref().map_or(true, |c| c.use_retry);
let mut this = Self {
endpoint_config,
server_config,
crypto,
handshake_cid: loc_cid,
Expand Down Expand Up @@ -1772,7 +1775,12 @@ impl Connection {
self.path.total_recvd = self.path.total_recvd.saturating_add(data.len() as u64);
let mut remaining = Some(data);
while let Some(data) = remaining {
match PartialDecode::new(data, self.local_cid_state.cid_len(), &[self.version]) {
match PartialDecode::new(
data,
self.local_cid_state.cid_len(),
&[self.version],
self.endpoint_config.grease_quic_bit,
) {
Ok((partial_decode, rest)) => {
remaining = rest;
self.handle_decode(now, remote, ecn, partial_decode);
Expand Down
2 changes: 2 additions & 0 deletions quinn-proto/src/endpoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ impl Endpoint {
data,
self.local_cid_generator.cid_len(),
&self.config.supported_versions,
self.config.grease_quic_bit,
) {
Ok(x) => x,
Err(PacketDecodeError::UnsupportedVersion {
Expand Down Expand Up @@ -630,6 +631,7 @@ impl Endpoint {
transport_config: Arc<TransportConfig>,
) -> (ConnectionHandle, Connection) {
let conn = Connection::new(
self.config.clone(),
server_config,
transport_config,
init_cid,
Expand Down
13 changes: 8 additions & 5 deletions quinn-proto/src/packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@ impl PartialDecode {
bytes: BytesMut,
local_cid_len: usize,
supported_versions: &[u32],
grease_quic_bit: bool,
) -> Result<(Self, Option<BytesMut>), PacketDecodeError> {
let mut buf = io::Cursor::new(bytes);
let plain_header = PlainHeader::decode(&mut buf, local_cid_len, supported_versions)?;
let plain_header =
PlainHeader::decode(&mut buf, local_cid_len, supported_versions, grease_quic_bit)?;
let dgram_len = buf.get_ref().len();
let packet_len = plain_header
.payload_len()
Expand Down Expand Up @@ -531,6 +533,7 @@ impl PlainHeader {
buf: &mut io::Cursor<BytesMut>,
local_cid_len: usize,
supported_versions: &[u32],
grease_quic_bit: bool,
) -> Result<Self, PacketDecodeError> {
let first = buf.get::<u8>()?;
if first & LONG_HEADER_FORM == 0 {
Expand Down Expand Up @@ -569,7 +572,7 @@ impl PlainHeader {
});
}

match LongHeaderType::from_byte(first)? {
match LongHeaderType::from_byte(first, grease_quic_bit)? {
LongHeaderType::Initial => {
let token_len = buf.get_var()? as usize;
let token_start = buf.position() as usize;
Expand Down Expand Up @@ -713,9 +716,9 @@ pub(crate) enum LongHeaderType {
}

impl LongHeaderType {
fn from_byte(b: u8) -> Result<Self, PacketDecodeError> {
fn from_byte(b: u8, grease_quic_bit: bool) -> Result<Self, PacketDecodeError> {
use self::{LongHeaderType::*, LongType::*};
if b & FIXED_BIT == 0 {
if !grease_quic_bit && b & FIXED_BIT == 0 {
return Err(PacketDecodeError::InvalidHeader("fixed bit unset"));
}
debug_assert!(b & LONG_HEADER_FORM != 0, "not a long packet");
Expand Down Expand Up @@ -870,7 +873,7 @@ mod tests {

let server = initial_keys(Version::V1, &dcid, Side::Server);
let supported_versions = DEFAULT_SUPPORTED_VERSIONS.to_vec();
let decode = PartialDecode::new(buf.as_slice().into(), 0, &supported_versions)
let decode = PartialDecode::new(buf.as_slice().into(), 0, &supported_versions, false)
.unwrap()
.0;
let mut packet = decode.finish(Some(&*server.header.remote)).unwrap();
Expand Down
18 changes: 18 additions & 0 deletions quinn-proto/src/transport_parameters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ macro_rules! make_struct {
/// The value that the endpoint included in the Source Connection ID field of the first
/// Initial packet it sends for the connection
pub(crate) initial_src_cid: Option<ConnectionId>,
/// The endpoint is willing to receive QUIC packets containing any value for the fixed
/// bit
pub(crate) grease_quic_bit: bool,

// Server-only
/// The value of the Destination Connection ID field from the first Initial packet sent
Expand All @@ -100,6 +103,7 @@ macro_rules! make_struct {
disable_active_migration: false,
max_datagram_frame_size: None,
initial_src_cid: None,
grease_quic_bit: false,

original_dst_cid: None,
retry_src_cid: None,
Expand Down Expand Up @@ -141,6 +145,7 @@ impl TransportParameters {
max_datagram_frame_size: config
.datagram_receive_buffer_size
.map(|x| (x.min(u16::max_value().into()) as u16).into()),
grease_quic_bit: endpoint_config.grease_quic_bit,
..Self::default()
}
}
Expand All @@ -159,6 +164,7 @@ impl TransportParameters {
|| cached.initial_max_streams_bidi > self.initial_max_streams_bidi
|| cached.initial_max_streams_uni > self.initial_max_streams_uni
|| cached.max_datagram_frame_size > self.max_datagram_frame_size
|| cached.grease_quic_bit && !self.grease_quic_bit
{
return Err(TransportError::PROTOCOL_VIOLATION(
"0-RTT accepted with incompatible transport parameters",
Expand Down Expand Up @@ -321,6 +327,11 @@ impl TransportParameters {
w.put_slice(cid);
}
}

if self.grease_quic_bit {
w.write_var(0x2ab2);
w.write_var(0);
}
}

/// Decode `TransportParameters` from buffer
Expand Down Expand Up @@ -381,6 +392,12 @@ impl TransportParameters {
}
params.max_datagram_frame_size = Some(r.get().unwrap());
}
0x2ab2 => {
if len != 0 {
return Err(Error::Malformed);
}
params.grease_quic_bit = true;
}
_ => {
macro_rules! parse {
{$($(#[$doc:meta])* $name:ident ($code:expr) = $default:expr,)*} => {
Expand Down Expand Up @@ -446,6 +463,7 @@ mod test {
connection_id: ConnectionId::new(&[]),
stateless_reset_token: [0xab; RESET_TOKEN_SIZE].into(),
}),
grease_quic_bit: true,
..TransportParameters::default()
};
params.write(&mut buf);
Expand Down

0 comments on commit 6b8cf90

Please sign in to comment.