From b994fb927303276b600286415cc503d6272b1471 Mon Sep 17 00:00:00 2001 From: Nils Andreas Svee Date: Fri, 8 May 2026 10:06:00 +0700 Subject: [PATCH] fix(client): reject runtime-invalid negotiated dscp --- .../irtt-client/src/client/tests/negotiation.rs | 16 ++++++++++++++++ crates/irtt-client/src/session.rs | 13 ++++++++++++- crates/irtt-proto/src/params.rs | 2 +- 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/crates/irtt-client/src/client/tests/negotiation.rs b/crates/irtt-client/src/client/tests/negotiation.rs index 3870bc7..337e76f 100644 --- a/crates/irtt-client/src/client/tests/negotiation.rs +++ b/crates/irtt-client/src/client/tests/negotiation.rs @@ -52,3 +52,19 @@ fn strict_negotiation_rejects_negative_returned_length() { Err(ClientError::NegotiationRejected { reason }) if reason == "length must be non-negative" )); } + +#[test] +fn loose_negotiation_rejects_runtime_invalid_returned_dscp() { + let config = ClientConfig::default(); + let requested = params_from_config(&config).unwrap(); + + for dscp in [-1, 64] { + let mut returned = requested.clone(); + returned.dscp = dscp; + assert!(matches!( + validate_negotiated_params(&requested, &returned, NegotiationPolicy::Loose), + Err(ClientError::NegotiationRejected { reason }) + if reason == "dscp must be in range 0..=63" + )); + } +} diff --git a/crates/irtt-client/src/session.rs b/crates/irtt-client/src/session.rs index 88d91ec..b52b4ad 100644 --- a/crates/irtt-client/src/session.rs +++ b/crates/irtt-client/src/session.rs @@ -3,7 +3,7 @@ use std::time::Instant; use irtt_proto::{Params, PROTOCOL_VERSION}; use crate::{ - config::NegotiationPolicy, + config::{NegotiationPolicy, MAX_DSCP_CODEPOINT}, error::ClientError, probe::{CompletedSet, PendingMap, TimedOutMap}, }; @@ -63,6 +63,7 @@ pub(crate) fn validate_negotiated_params( reason: "interval must be positive".to_owned(), }); } + validate_dscp_restriction(returned.dscp)?; if policy == NegotiationPolicy::Strict && returned != requested { return Err(ClientError::NegotiationRejected { @@ -94,6 +95,16 @@ fn validate_duration_restriction(requested: i64, returned: i64) -> Result<(), Cl Ok(()) } +fn validate_dscp_restriction(returned: i64) -> Result<(), ClientError> { + if !(0..=i64::from(MAX_DSCP_CODEPOINT)).contains(&returned) { + return Err(ClientError::NegotiationRejected { + reason: format!("dscp must be in range 0..={MAX_DSCP_CODEPOINT}"), + }); + } + + Ok(()) +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/irtt-proto/src/params.rs b/crates/irtt-proto/src/params.rs index 06d1f8a..2b58805 100644 --- a/crates/irtt-proto/src/params.rs +++ b/crates/irtt-proto/src/params.rs @@ -272,7 +272,7 @@ mod tests { #[test] fn params_round_trip_dscp_codepoints_without_shifting() { - for dscp in [0, 46, 63] { + for dscp in [0, 46, 63, 64, 184, -1] { let params = Params { protocol_version: 1, dscp,