From 8924cc531cb0e7ba03cb9f8393f695f3ba1044af Mon Sep 17 00:00:00 2001 From: Nils Andreas Svee Date: Mon, 10 Aug 2026 22:41:31 +0700 Subject: [PATCH] test(client): use protocol encoders in fake peers --- crates/irtt-client/src/client/tests/open.rs | 9 +- .../irtt-client/src/client/tests/support.rs | 98 +++++++------------ crates/irtt-client/tests/support/mod.rs | 93 +++++++----------- 3 files changed, 76 insertions(+), 124 deletions(-) diff --git a/crates/irtt-client/src/client/tests/open.rs b/crates/irtt-client/src/client/tests/open.rs index f7f4c21..e4e7fb6 100644 --- a/crates/irtt-client/src/client/tests/open.rs +++ b/crates/irtt-client/src/client/tests/open.rs @@ -215,9 +215,12 @@ fn trusted_zero_token_normal_reply_is_terminal() { let params = default_params(); let server = start_fake_server(move |socket, tx| { let (_, peer) = recv_request(&socket, &tx); - socket - .send_to(&open_reply(FLAG_OPEN | FLAG_REPLY, 0, ¶ms, None), peer) - .unwrap(); + // encode_open_reply rejects a zero token without FLAG_CLOSE, so this + // deliberately non-compliant reply is built by encoding a normal + // reply with a placeholder token and then zeroing the token field. + let mut reply = open_reply(FLAG_OPEN | FLAG_REPLY, TOKEN, ¶ms, None); + reply[HMAC_OFFSET..HMAC_OFFSET + 8].copy_from_slice(&0_u64.to_le_bytes()); + socket.send_to(&reply, peer).unwrap(); }); let mut client = Client::connect(default_test_config(server.addr)).unwrap(); diff --git a/crates/irtt-client/src/client/tests/support.rs b/crates/irtt-client/src/client/tests/support.rs index a3cddd7..d612696 100644 --- a/crates/irtt-client/src/client/tests/support.rs +++ b/crates/irtt-client/src/client/tests/support.rs @@ -1,8 +1,8 @@ use super::*; use irtt_proto::{ - compute_hmac_in_place, echo_packet_len as checked_echo_packet_len, flags::FLAG_HMAC, - flags::FLAG_OPEN, flags::FLAG_REPLY, layout::PacketLayout, Clock, ReceivedStats, StampAt, - HMAC_SIZE, MAGIC, + echo_packet_len as checked_echo_packet_len, encode_echo_reply, encode_open_reply, + flags::FLAG_OPEN, flags::FLAG_REPLY, layout::PacketLayout, Clock, EchoReply, OpenReply, + ReceivedStats, StampAt, }; use std::{ net::UdpSocket, @@ -61,18 +61,15 @@ pub(super) fn open_reply( params: &Params, hmac_key: Option<&[u8]>, ) -> Vec { - let mut packet = Vec::new(); - packet.extend_from_slice(&MAGIC); - packet.push(flags | hmac_key.map_or(0, |_| FLAG_HMAC)); - if hmac_key.is_some() { - packet.extend_from_slice(&[0_u8; HMAC_SIZE]); - } - packet.extend_from_slice(&token.to_le_bytes()); - packet.extend_from_slice(¶ms.encode()); - if let Some(key) = hmac_key { - compute_hmac_in_place(key, &mut packet, HMAC_OFFSET).unwrap(); - } - packet + encode_open_reply( + &OpenReply { + flags, + token, + params: params.clone(), + }, + hmac_key, + ) + .unwrap() } pub(crate) fn echo_packet_len(hmac: bool, params: &Params) -> usize { @@ -98,55 +95,28 @@ pub(super) fn echo_reply_packet_with_flags( hmac_key: Option<&[u8]>, flags: u8, ) -> Vec { - let has_hmac = hmac_key.is_some(); - let layout = PacketLayout::echo(has_hmac, params); - let packet_len = echo_packet_len(has_hmac, params); - let mut packet = Vec::with_capacity(packet_len); - - let mut flags = flags; - if has_hmac { - flags |= FLAG_HMAC; - } - packet.extend_from_slice(&MAGIC); - packet.push(flags); - if has_hmac { - packet.extend_from_slice(&[0_u8; HMAC_SIZE]); - } - packet.extend_from_slice(&token.to_le_bytes()); - packet.extend_from_slice(&seq.to_le_bytes()); - - if layout.recv_count { - packet.extend_from_slice(&42_u32.to_le_bytes()); - } - if layout.recv_window { - packet.extend_from_slice(&0x07_u64.to_le_bytes()); - } - - if layout.recv_wall { - packet.extend_from_slice(×tamps.recv_wall.unwrap_or(0).to_le_bytes()); - } - if layout.recv_mono { - packet.extend_from_slice(×tamps.recv_mono.unwrap_or(0).to_le_bytes()); - } - if layout.midpoint_wall { - packet.extend_from_slice(×tamps.midpoint_wall.unwrap_or(0).to_le_bytes()); - } - if layout.midpoint_mono { - packet.extend_from_slice(×tamps.midpoint_mono.unwrap_or(0).to_le_bytes()); - } - if layout.send_wall { - packet.extend_from_slice(×tamps.send_wall.unwrap_or(0).to_le_bytes()); - } - if layout.send_mono { - packet.extend_from_slice(×tamps.send_mono.unwrap_or(0).to_le_bytes()); - } - - packet.resize(packet_len, 0); - - if let Some(key) = hmac_key { - compute_hmac_in_place(key, &mut packet, HMAC_OFFSET).unwrap(); - } - packet + let layout = PacketLayout::echo(hmac_key.is_some(), params); + let reply = EchoReply { + flags, + token, + sequence: seq, + recv_count: layout.recv_count.then_some(42), + recv_window: layout.recv_window.then_some(0x07), + timestamps: TimestampFields { + recv_wall: layout.recv_wall.then(|| timestamps.recv_wall.unwrap_or(0)), + recv_mono: layout.recv_mono.then(|| timestamps.recv_mono.unwrap_or(0)), + midpoint_wall: layout + .midpoint_wall + .then(|| timestamps.midpoint_wall.unwrap_or(0)), + midpoint_mono: layout + .midpoint_mono + .then(|| timestamps.midpoint_mono.unwrap_or(0)), + send_wall: layout.send_wall.then(|| timestamps.send_wall.unwrap_or(0)), + send_mono: layout.send_mono.then(|| timestamps.send_mono.unwrap_or(0)), + }, + payload: Vec::new(), + }; + encode_echo_reply(&reply, params, hmac_key).unwrap() } pub(super) fn open_success_server(params: Params) -> FakeServer { diff --git a/crates/irtt-client/tests/support/mod.rs b/crates/irtt-client/tests/support/mod.rs index c5e977f..985f0cc 100644 --- a/crates/irtt-client/tests/support/mod.rs +++ b/crates/irtt-client/tests/support/mod.rs @@ -12,8 +12,9 @@ use std::{ use irtt_client::{Client, ClientConfig, ClientEvent, NegotiatedParams, OpenOutcome, SocketConfig}; use irtt_proto::{ - compute_hmac_in_place, echo_packet_len, flags, verify_hmac, Clock, Params, ProtoError, - ReceivedStats, ServerFill, StampAt, TimestampFields, HMAC_SIZE, MAGIC, PROTOCOL_VERSION, + compute_hmac_in_place, echo_packet_len, encode_echo_reply, encode_open_reply, flags, + verify_hmac, Clock, EchoReply, OpenReply, PacketLayout, Params, ProtoError, ReceivedStats, + ServerFill, StampAt, TimestampFields, HMAC_SIZE, MAGIC, PROTOCOL_VERSION, }; pub use real_irtt::RealIrtServer; @@ -495,6 +496,8 @@ fn observe_close_request(packet: &[u8], hmac_key: &[u8]) -> ServerObservation { ServerObservation::Close { hmac: true, token } } +// irtt-proto has no encode_close_reply/CloseReply API yet, so this stays a +// manual encoder. Migrate it once server-side close encoding is added. fn close_reply(token: u64, hmac_key: &[u8]) -> Vec { let mut packet = Vec::new(); packet.extend_from_slice(&MAGIC); @@ -506,18 +509,15 @@ fn close_reply(token: u64, hmac_key: &[u8]) -> Vec { } fn open_reply(flags: u8, token: u64, params: &Params, hmac_key: Option<&[u8]>) -> Vec { - let mut packet = Vec::new(); - packet.extend_from_slice(&MAGIC); - packet.push(flags | hmac_key.map_or(0, |_| flags::FLAG_HMAC)); - if hmac_key.is_some() { - packet.extend_from_slice(&[0_u8; HMAC_SIZE]); - } - packet.extend_from_slice(&token.to_le_bytes()); - packet.extend_from_slice(¶ms.encode()); - if let Some(key) = hmac_key { - compute_hmac_in_place(key, &mut packet, HMAC_OFFSET).unwrap(); - } - packet + encode_open_reply( + &OpenReply { + flags, + token, + params: params.clone(), + }, + hmac_key, + ) + .unwrap() } pub(super) fn test_echo_packet_len(hmac: bool, params: &Params) -> usize { @@ -532,49 +532,28 @@ fn echo_reply_packet( timestamps: &TimestampFields, hmac_key: Option<&[u8]>, ) -> Vec { - let has_hmac = hmac_key.is_some(); - let layout = irtt_proto::PacketLayout::echo(has_hmac, params); - let packet_len = test_echo_packet_len(has_hmac, params); - let mut packet = Vec::with_capacity(packet_len); - - packet.extend_from_slice(&MAGIC); - packet.push(flags::FLAG_REPLY | hmac_key.map_or(0, |_| flags::FLAG_HMAC)); - if has_hmac { - packet.extend_from_slice(&[0_u8; HMAC_SIZE]); - } - packet.extend_from_slice(&token.to_le_bytes()); - packet.extend_from_slice(&seq.to_le_bytes()); - - if layout.recv_count { - packet.extend_from_slice(&RECV_COUNT.to_le_bytes()); - } - if layout.recv_window { - packet.extend_from_slice(&RECV_WINDOW.to_le_bytes()); - } - if layout.recv_wall { - packet.extend_from_slice(×tamps.recv_wall.unwrap_or(0).to_le_bytes()); - } - if layout.recv_mono { - packet.extend_from_slice(×tamps.recv_mono.unwrap_or(0).to_le_bytes()); - } - if layout.midpoint_wall { - packet.extend_from_slice(×tamps.midpoint_wall.unwrap_or(0).to_le_bytes()); - } - if layout.midpoint_mono { - packet.extend_from_slice(×tamps.midpoint_mono.unwrap_or(0).to_le_bytes()); - } - if layout.send_wall { - packet.extend_from_slice(×tamps.send_wall.unwrap_or(0).to_le_bytes()); - } - if layout.send_mono { - packet.extend_from_slice(×tamps.send_mono.unwrap_or(0).to_le_bytes()); - } - - packet.resize(packet_len, 0); - if let Some(key) = hmac_key { - compute_hmac_in_place(key, &mut packet, HMAC_OFFSET).unwrap(); - } - packet + let layout = PacketLayout::echo(hmac_key.is_some(), params); + let reply = EchoReply { + flags: flags::FLAG_REPLY, + token, + sequence: seq, + recv_count: layout.recv_count.then_some(RECV_COUNT), + recv_window: layout.recv_window.then_some(RECV_WINDOW), + timestamps: TimestampFields { + recv_wall: layout.recv_wall.then(|| timestamps.recv_wall.unwrap_or(0)), + recv_mono: layout.recv_mono.then(|| timestamps.recv_mono.unwrap_or(0)), + midpoint_wall: layout + .midpoint_wall + .then(|| timestamps.midpoint_wall.unwrap_or(0)), + midpoint_mono: layout + .midpoint_mono + .then(|| timestamps.midpoint_mono.unwrap_or(0)), + send_wall: layout.send_wall.then(|| timestamps.send_wall.unwrap_or(0)), + send_mono: layout.send_mono.then(|| timestamps.send_mono.unwrap_or(0)), + }, + payload: Vec::new(), + }; + encode_echo_reply(&reply, params, hmac_key).unwrap() } fn materialize_wall_timestamps(mut timestamps: TimestampFields) -> TimestampFields {