diff --git a/quiche/include/quiche.h b/quiche/include/quiche.h index 2ce662e5ed..9b6a42197a 100644 --- a/quiche/include/quiche.h +++ b/quiche/include/quiche.h @@ -178,6 +178,9 @@ int quiche_config_set_application_protos(quiche_config *config, const uint8_t *protos, size_t protos_len); +// Sets the anti-amplification limit factor. +void quiche_config_set_max_amplification_factor(quiche_config *config, size_t v); + // Sets the `max_idle_timeout` transport parameter, in milliseconds, default is // no timeout. void quiche_config_set_max_idle_timeout(quiche_config *config, uint64_t v); diff --git a/quiche/src/ffi.rs b/quiche/src/ffi.rs index bf28f76564..faa0d2ef0e 100644 --- a/quiche/src/ffi.rs +++ b/quiche/src/ffi.rs @@ -240,6 +240,13 @@ pub extern fn quiche_config_set_application_protos( } } +#[no_mangle] +pub extern fn quiche_config_set_max_amplification_factor( + config: &mut Config, v: usize, +) { + config.set_max_amplification_factor(v); +} + #[no_mangle] pub extern fn quiche_config_set_max_idle_timeout(config: &mut Config, v: u64) { config.set_max_idle_timeout(v); diff --git a/quiche/src/lib.rs b/quiche/src/lib.rs index 58676f31d0..4bccfec107 100644 --- a/quiche/src/lib.rs +++ b/quiche/src/lib.rs @@ -810,6 +810,8 @@ pub struct Config { max_connection_window: u64, max_stream_window: u64, + max_amplification_factor: usize, + disable_dcid_reuse: bool, } @@ -876,6 +878,8 @@ impl Config { max_connection_window: MAX_CONNECTION_WINDOW, max_stream_window: stream::MAX_STREAM_WINDOW, + max_amplification_factor: MAX_AMPLIFICATION_FACTOR, + disable_dcid_reuse: false, }) } @@ -1062,6 +1066,13 @@ impl Config { self.set_application_protos(&protos_list) } + /// Sets the anti-amplification limit factor. + /// + /// The default value is `3`. + pub fn set_max_amplification_factor(&mut self, v: usize) { + self.max_amplification_factor = v; + } + /// Sets the `max_idle_timeout` transport parameter, in milliseconds. /// /// The default value is infinite, that is, no timeout is used. @@ -1515,7 +1526,7 @@ pub struct Connection { /// Whether the connection is closed. closed: bool, - // Whether the connection was timed out + /// Whether the connection was timed out. timed_out: bool, /// Whether to send GREASE. @@ -1552,6 +1563,9 @@ pub struct Connection { /// The number of streams stopped by remote. stopped_stream_remote_count: u64, + + /// The anti-amplification limit factor. + max_amplification_factor: usize, } /// Creates a new server-side connection. @@ -1992,6 +2006,8 @@ impl Connection { stopped_stream_local_count: 0, reset_stream_remote_count: 0, stopped_stream_remote_count: 0, + + max_amplification_factor: config.max_amplification_factor, }; if let Some(odcid) = odcid { @@ -2246,7 +2262,7 @@ impl Connection { // Note that we also need to limit the number of bytes we sent on a // path if we are not the host that initiated its usage. if self.is_server && !recv_path.verified_peer_address { - recv_path.max_send_bytes += len * MAX_AMPLIFICATION_FACTOR; + recv_path.max_send_bytes += len * self.max_amplification_factor; } } else if !self.is_server { // If a client receives packets from an unknown server address, @@ -7622,7 +7638,7 @@ impl Connection { false, ); - path.max_send_bytes = buf_len * MAX_AMPLIFICATION_FACTOR; + path.max_send_bytes = buf_len * self.max_amplification_factor; path.active_scid_seq = Some(in_scid_seq); // Automatically probes the new path. @@ -9668,6 +9684,34 @@ mod tests { assert_eq!(server_sent, client_sent * MAX_AMPLIFICATION_FACTOR); } + #[test] + fn custom_limit_handshake_data() { + const CUSTOM_AMPLIFICATION_FACTOR: usize = 2; + + let mut config = Config::new(PROTOCOL_VERSION).unwrap(); + config + .load_cert_chain_from_pem_file("examples/cert-big.crt") + .unwrap(); + config + .load_priv_key_from_pem_file("examples/cert.key") + .unwrap(); + config + .set_application_protos(&[b"proto1", b"proto2"]) + .unwrap(); + config.set_max_amplification_factor(CUSTOM_AMPLIFICATION_FACTOR); + + let mut pipe = testing::Pipe::with_server_config(&mut config).unwrap(); + + let flight = testing::emit_flight(&mut pipe.client).unwrap(); + let client_sent = flight.iter().fold(0, |out, p| out + p.0.len()); + testing::process_flight(&mut pipe.server, flight).unwrap(); + + let flight = testing::emit_flight(&mut pipe.server).unwrap(); + let server_sent = flight.iter().fold(0, |out, p| out + p.0.len()); + + assert_eq!(server_sent, client_sent * CUSTOM_AMPLIFICATION_FACTOR); + } + #[test] fn stream() { let mut pipe = testing::Pipe::new().unwrap();