test(client): use protocol encoders in fake peers #60

Merged
Lochnair merged 1 commits from test/client-use-proto-encoders into main 2026-08-10 15:53:36 +00:00
3 changed files with 76 additions and 124 deletions

No files matched your search

+6 -3
View File
@@ -215,9 +215,12 @@ fn trusted_zero_token_normal_reply_is_terminal() {
let params = default_params(); let params = default_params();
let server = start_fake_server(move |socket, tx| { let server = start_fake_server(move |socket, tx| {
let (_, peer) = recv_request(&socket, &tx); let (_, peer) = recv_request(&socket, &tx);
socket // encode_open_reply rejects a zero token without FLAG_CLOSE, so this
.send_to(&open_reply(FLAG_OPEN | FLAG_REPLY, 0, &params, None), peer) // deliberately non-compliant reply is built by encoding a normal
.unwrap(); // reply with a placeholder token and then zeroing the token field.
let mut reply = open_reply(FLAG_OPEN | FLAG_REPLY, TOKEN, &params, 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(); let mut client = Client::connect(default_test_config(server.addr)).unwrap();
+34 -64
View File
@@ -1,8 +1,8 @@
use super::*; use super::*;
use irtt_proto::{ use irtt_proto::{
compute_hmac_in_place, echo_packet_len as checked_echo_packet_len, flags::FLAG_HMAC, echo_packet_len as checked_echo_packet_len, encode_echo_reply, encode_open_reply,
flags::FLAG_OPEN, flags::FLAG_REPLY, layout::PacketLayout, Clock, ReceivedStats, StampAt, flags::FLAG_OPEN, flags::FLAG_REPLY, layout::PacketLayout, Clock, EchoReply, OpenReply,
HMAC_SIZE, MAGIC, ReceivedStats, StampAt,
}; };
use std::{ use std::{
net::UdpSocket, net::UdpSocket,
@@ -61,18 +61,15 @@ pub(super) fn open_reply(
params: &Params, params: &Params,
hmac_key: Option<&[u8]>, hmac_key: Option<&[u8]>,
) -> Vec<u8> { ) -> Vec<u8> {
let mut packet = Vec::new(); encode_open_reply(
packet.extend_from_slice(&MAGIC); &OpenReply {
packet.push(flags | hmac_key.map_or(0, |_| FLAG_HMAC)); flags,
if hmac_key.is_some() { token,
packet.extend_from_slice(&[0_u8; HMAC_SIZE]); params: params.clone(),
} },
packet.extend_from_slice(&token.to_le_bytes()); hmac_key,
packet.extend_from_slice(&params.encode()); )
if let Some(key) = hmac_key { .unwrap()
compute_hmac_in_place(key, &mut packet, HMAC_OFFSET).unwrap();
}
packet
} }
pub(crate) fn echo_packet_len(hmac: bool, params: &Params) -> usize { 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]>, hmac_key: Option<&[u8]>,
flags: u8, flags: u8,
) -> Vec<u8> { ) -> Vec<u8> {
let has_hmac = hmac_key.is_some(); let layout = PacketLayout::echo(hmac_key.is_some(), params);
let layout = PacketLayout::echo(has_hmac, params); let reply = EchoReply {
let packet_len = echo_packet_len(has_hmac, params); flags,
let mut packet = Vec::with_capacity(packet_len); token,
sequence: seq,
let mut flags = flags; recv_count: layout.recv_count.then_some(42),
if has_hmac { recv_window: layout.recv_window.then_some(0x07),
flags |= FLAG_HMAC; timestamps: TimestampFields {
} recv_wall: layout.recv_wall.then(|| timestamps.recv_wall.unwrap_or(0)),
packet.extend_from_slice(&MAGIC); recv_mono: layout.recv_mono.then(|| timestamps.recv_mono.unwrap_or(0)),
packet.push(flags); midpoint_wall: layout
if has_hmac { .midpoint_wall
packet.extend_from_slice(&[0_u8; HMAC_SIZE]); .then(|| timestamps.midpoint_wall.unwrap_or(0)),
} midpoint_mono: layout
packet.extend_from_slice(&token.to_le_bytes()); .midpoint_mono
packet.extend_from_slice(&seq.to_le_bytes()); .then(|| timestamps.midpoint_mono.unwrap_or(0)),
send_wall: layout.send_wall.then(|| timestamps.send_wall.unwrap_or(0)),
if layout.recv_count { send_mono: layout.send_mono.then(|| timestamps.send_mono.unwrap_or(0)),
packet.extend_from_slice(&42_u32.to_le_bytes()); },
} payload: Vec::new(),
if layout.recv_window { };
packet.extend_from_slice(&0x07_u64.to_le_bytes()); encode_echo_reply(&reply, params, hmac_key).unwrap()
}
if layout.recv_wall {
packet.extend_from_slice(&timestamps.recv_wall.unwrap_or(0).to_le_bytes());
}
if layout.recv_mono {
packet.extend_from_slice(&timestamps.recv_mono.unwrap_or(0).to_le_bytes());
}
if layout.midpoint_wall {
packet.extend_from_slice(&timestamps.midpoint_wall.unwrap_or(0).to_le_bytes());
}
if layout.midpoint_mono {
packet.extend_from_slice(&timestamps.midpoint_mono.unwrap_or(0).to_le_bytes());
}
if layout.send_wall {
packet.extend_from_slice(&timestamps.send_wall.unwrap_or(0).to_le_bytes());
}
if layout.send_mono {
packet.extend_from_slice(&timestamps.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
} }
pub(super) fn open_success_server(params: Params) -> FakeServer { pub(super) fn open_success_server(params: Params) -> FakeServer {
+36 -57
View File
@@ -12,8 +12,9 @@ use std::{
use irtt_client::{Client, ClientConfig, ClientEvent, NegotiatedParams, OpenOutcome, SocketConfig}; use irtt_client::{Client, ClientConfig, ClientEvent, NegotiatedParams, OpenOutcome, SocketConfig};
use irtt_proto::{ use irtt_proto::{
compute_hmac_in_place, echo_packet_len, flags, verify_hmac, Clock, Params, ProtoError, compute_hmac_in_place, echo_packet_len, encode_echo_reply, encode_open_reply, flags,
ReceivedStats, ServerFill, StampAt, TimestampFields, HMAC_SIZE, MAGIC, PROTOCOL_VERSION, verify_hmac, Clock, EchoReply, OpenReply, PacketLayout, Params, ProtoError, ReceivedStats,
ServerFill, StampAt, TimestampFields, HMAC_SIZE, MAGIC, PROTOCOL_VERSION,
}; };
pub use real_irtt::RealIrtServer; pub use real_irtt::RealIrtServer;
@@ -495,6 +496,8 @@ fn observe_close_request(packet: &[u8], hmac_key: &[u8]) -> ServerObservation {
ServerObservation::Close { hmac: true, token } 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<u8> { fn close_reply(token: u64, hmac_key: &[u8]) -> Vec<u8> {
let mut packet = Vec::new(); let mut packet = Vec::new();
packet.extend_from_slice(&MAGIC); packet.extend_from_slice(&MAGIC);
@@ -506,18 +509,15 @@ fn close_reply(token: u64, hmac_key: &[u8]) -> Vec<u8> {
} }
fn open_reply(flags: u8, token: u64, params: &Params, hmac_key: Option<&[u8]>) -> Vec<u8> { fn open_reply(flags: u8, token: u64, params: &Params, hmac_key: Option<&[u8]>) -> Vec<u8> {
let mut packet = Vec::new(); encode_open_reply(
packet.extend_from_slice(&MAGIC); &OpenReply {
packet.push(flags | hmac_key.map_or(0, |_| flags::FLAG_HMAC)); flags,
if hmac_key.is_some() { token,
packet.extend_from_slice(&[0_u8; HMAC_SIZE]); params: params.clone(),
} },
packet.extend_from_slice(&token.to_le_bytes()); hmac_key,
packet.extend_from_slice(&params.encode()); )
if let Some(key) = hmac_key { .unwrap()
compute_hmac_in_place(key, &mut packet, HMAC_OFFSET).unwrap();
}
packet
} }
pub(super) fn test_echo_packet_len(hmac: bool, params: &Params) -> usize { pub(super) fn test_echo_packet_len(hmac: bool, params: &Params) -> usize {
@@ -532,49 +532,28 @@ fn echo_reply_packet(
timestamps: &TimestampFields, timestamps: &TimestampFields,
hmac_key: Option<&[u8]>, hmac_key: Option<&[u8]>,
) -> Vec<u8> { ) -> Vec<u8> {
let has_hmac = hmac_key.is_some(); let layout = PacketLayout::echo(hmac_key.is_some(), params);
let layout = irtt_proto::PacketLayout::echo(has_hmac, params); let reply = EchoReply {
let packet_len = test_echo_packet_len(has_hmac, params); flags: flags::FLAG_REPLY,
let mut packet = Vec::with_capacity(packet_len); token,
sequence: seq,
packet.extend_from_slice(&MAGIC); recv_count: layout.recv_count.then_some(RECV_COUNT),
packet.push(flags::FLAG_REPLY | hmac_key.map_or(0, |_| flags::FLAG_HMAC)); recv_window: layout.recv_window.then_some(RECV_WINDOW),
if has_hmac { timestamps: TimestampFields {
packet.extend_from_slice(&[0_u8; HMAC_SIZE]); recv_wall: layout.recv_wall.then(|| timestamps.recv_wall.unwrap_or(0)),
} recv_mono: layout.recv_mono.then(|| timestamps.recv_mono.unwrap_or(0)),
packet.extend_from_slice(&token.to_le_bytes()); midpoint_wall: layout
packet.extend_from_slice(&seq.to_le_bytes()); .midpoint_wall
.then(|| timestamps.midpoint_wall.unwrap_or(0)),
if layout.recv_count { midpoint_mono: layout
packet.extend_from_slice(&RECV_COUNT.to_le_bytes()); .midpoint_mono
} .then(|| timestamps.midpoint_mono.unwrap_or(0)),
if layout.recv_window { send_wall: layout.send_wall.then(|| timestamps.send_wall.unwrap_or(0)),
packet.extend_from_slice(&RECV_WINDOW.to_le_bytes()); send_mono: layout.send_mono.then(|| timestamps.send_mono.unwrap_or(0)),
} },
if layout.recv_wall { payload: Vec::new(),
packet.extend_from_slice(&timestamps.recv_wall.unwrap_or(0).to_le_bytes()); };
} encode_echo_reply(&reply, params, hmac_key).unwrap()
if layout.recv_mono {
packet.extend_from_slice(&timestamps.recv_mono.unwrap_or(0).to_le_bytes());
}
if layout.midpoint_wall {
packet.extend_from_slice(&timestamps.midpoint_wall.unwrap_or(0).to_le_bytes());
}
if layout.midpoint_mono {
packet.extend_from_slice(&timestamps.midpoint_mono.unwrap_or(0).to_le_bytes());
}
if layout.send_wall {
packet.extend_from_slice(&timestamps.send_wall.unwrap_or(0).to_le_bytes());
}
if layout.send_mono {
packet.extend_from_slice(&timestamps.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
} }
fn materialize_wall_timestamps(mut timestamps: TimestampFields) -> TimestampFields { fn materialize_wall_timestamps(mut timestamps: TimestampFields) -> TimestampFields {