diff --git a/common/socks5/requests/src/lib.rs b/common/socks5/requests/src/lib.rs index 661f7266e2..58c23dcd9d 100644 --- a/common/socks5/requests/src/lib.rs +++ b/common/socks5/requests/src/lib.rs @@ -26,7 +26,7 @@ pub struct InsufficientSocketDataError { expected: usize, } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, Eq, PartialEq)] pub struct SocketDataHeader { pub seq: u64, pub connection_id: ConnectionId, @@ -112,7 +112,7 @@ impl SocketDataHeader { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct SocketData { pub header: SocketDataHeader, pub data: Vec, @@ -231,6 +231,103 @@ mod tests { use super::*; use nym_service_providers_common::interface::RequestContent; + #[cfg(test)] + mod socket_data_serialization { + use super::*; + + #[test] + fn for_requests() { + assert_eq!( + InsufficientSocketDataError { + received: 0, + expected: SocketDataHeader::SERIALIZED_LEN + }, + SocketData::try_from_request_bytes(&[]).unwrap_err() + ); + + assert_eq!( + InsufficientSocketDataError { + received: 10, + expected: SocketDataHeader::SERIALIZED_LEN + }, + SocketData::try_from_request_bytes(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]).unwrap_err() + ); + + let good_data = SocketData::new(42, 12345, false, vec![2, 3]); + let serialized = good_data.clone().into_request_bytes(); + + assert_eq!( + good_data, + SocketData::try_from_request_bytes(&serialized).unwrap() + ); + assert_ne!( + good_data, + SocketData::try_from_response_bytes(&serialized).unwrap() + ); + + let raw_bytes = [ + 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 1, 2, 3, 4, 5, 6, 7, 255, 255, 255, + ]; + assert_eq!( + SocketData { + header: SocketDataHeader { + seq: u64::from_be_bytes([0, 1, 2, 3, 4, 5, 6, 7]), + connection_id: ConnectionId::from_be_bytes([6, 6, 6, 6, 6, 6, 6, 6]), + local_socket_closed: false, + }, + data: vec![255, 255, 255], + }, + SocketData::try_from_request_bytes(&raw_bytes).unwrap() + ) + } + + #[test] + fn for_responses() { + assert_eq!( + InsufficientSocketDataError { + received: 0, + expected: SocketDataHeader::SERIALIZED_LEN + }, + SocketData::try_from_response_bytes(&[]).unwrap_err() + ); + + assert_eq!( + InsufficientSocketDataError { + received: 10, + expected: SocketDataHeader::SERIALIZED_LEN + }, + SocketData::try_from_response_bytes(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]).unwrap_err() + ); + + let good_data = SocketData::new(42, 12345, false, vec![2, 3]); + let serialized = good_data.clone().into_response_bytes(); + + assert_eq!( + good_data, + SocketData::try_from_response_bytes(&serialized).unwrap() + ); + assert_ne!( + good_data, + SocketData::try_from_request_bytes(&serialized).unwrap() + ); + + let raw_bytes = [ + 0, 6, 6, 6, 6, 6, 6, 6, 6, 0, 1, 2, 3, 4, 5, 6, 7, 255, 255, 255, + ]; + assert_eq!( + SocketData { + header: SocketDataHeader { + seq: u64::from_be_bytes([0, 1, 2, 3, 4, 5, 6, 7]), + connection_id: ConnectionId::from_be_bytes([6, 6, 6, 6, 6, 6, 6, 6]), + local_socket_closed: false, + }, + data: vec![255, 255, 255], + }, + SocketData::try_from_response_bytes(&raw_bytes).unwrap() + ) + } + } + #[cfg(test)] mod interface_backwards_compatibility { use super::*; @@ -280,7 +377,8 @@ mod tests { RequestContent::ProviderData(req) => match req.content { Socks5RequestContent::Send(send_req) => { assert_eq!(send_req.data.header.connection_id, 7810961472501196273); - assert_eq!(send_req.data.data.len(), 111); + assert_eq!(send_req.data.header.seq, 0); + assert_eq!(send_req.data.data.len(), 103); assert!(!send_req.data.header.local_socket_closed); } _ => panic!("unexpected request"), diff --git a/common/socks5/requests/src/request.rs b/common/socks5/requests/src/request.rs index 4dfc096b30..248d76442c 100644 --- a/common/socks5/requests/src/request.rs +++ b/common/socks5/requests/src/request.rs @@ -603,26 +603,7 @@ mod request_deserialization_tests { #[test] fn works_when_request_is_sized_properly_even_without_data() { - // correct 8 bytes of connection_id, 1 byte of local_closed and 0 bytes request data - let request_bytes = [RequestFlag::Send as u8, 1, 2, 3, 4, 5, 6, 7, 8, 0].to_vec(); - let request = Socks5RequestContent::try_from_bytes(&request_bytes).unwrap(); - match request { - Socks5RequestContent::Send(SendRequest { - conn_id, - data: data, - local_closed, - }) => { - assert_eq!(u64::from_be_bytes([1, 2, 3, 4, 5, 6, 7, 8]), conn_id); - assert_eq!(Vec::::new(), data); - assert!(!local_closed) - } - _ => unreachable!(), - } - } - - #[test] - fn works_when_request_is_sized_properly_and_has_data() { - // correct 8 bytes of connection_id, 1 byte of local_closed and 3 bytes request data (all 255) + // correct 8 bytes of connection_id, 1 byte of local_closed, 8 bytes of sequence and 0 bytes request data let request_bytes = [ RequestFlag::Send as u8, 1, @@ -634,6 +615,53 @@ mod request_deserialization_tests { 7, 8, 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + ] + .to_vec(); + let request = Socks5RequestContent::try_from_bytes(&request_bytes).unwrap(); + match request { + Socks5RequestContent::Send(SendRequest { data }) => { + assert_eq!( + u64::from_be_bytes([1, 2, 3, 4, 5, 6, 7, 8]), + data.header.connection_id + ); + assert!(!data.header.local_socket_closed); + assert_eq!(1, data.header.seq); + assert!(data.data.is_empty()); + } + _ => unreachable!(), + } + } + + #[test] + fn works_when_request_is_sized_properly_and_has_data() { + // correct 8 bytes of connection_id, 1 byte of local_closed, 8 bytes of sequence and 3 bytes request data (all 255) + let request_bytes = [ + RequestFlag::Send as u8, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, 255, 255, 255, @@ -642,14 +670,14 @@ mod request_deserialization_tests { let request = Socks5RequestContent::try_from_bytes(&request_bytes).unwrap(); match request { - Socks5RequestContent::Send(SendRequest { - conn_id, - data: data, - local_closed, - }) => { - assert_eq!(u64::from_be_bytes([1, 2, 3, 4, 5, 6, 7, 8]), conn_id); - assert_eq!(vec![255, 255, 255], data); - assert!(!local_closed) + Socks5RequestContent::Send(SendRequest { data }) => { + assert_eq!( + u64::from_be_bytes([1, 2, 3, 4, 5, 6, 7, 8]), + data.header.connection_id + ); + assert!(data.header.local_socket_closed); + assert_eq!(1, data.header.seq); + assert_eq!(vec![255, 255, 255], data.data); } _ => unreachable!(), } diff --git a/common/socks5/requests/src/response.rs b/common/socks5/requests/src/response.rs index 5d0696d715..4e0c906439 100644 --- a/common/socks5/requests/src/response.rs +++ b/common/socks5/requests/src/response.rs @@ -298,57 +298,6 @@ pub enum QueryResponse { mod tests { use super::*; - #[cfg(test)] - mod constructing_socks5_data_responses_from_bytes { - use super::*; - - #[test] - fn fails_when_zero_bytes_are_supplied() { - let response_bytes = Vec::new(); - - let err = NetworkData::try_from_bytes(&response_bytes).unwrap_err(); - assert!(matches!(err, ResponseDeserializationError::NoData)); - } - - #[test] - fn fails_when_connection_id_bytes_are_too_short() { - let response_bytes = vec![0, 1, 2, 3, 4, 5, 6]; - let err = NetworkData::try_from_bytes(&response_bytes).unwrap_err(); - assert!(matches!( - err, - ResponseDeserializationError::ConnectionIdTooShort, - )); - } - - #[test] - fn works_when_there_is_no_data() { - let response_bytes = vec![0, 0, 1, 2, 3, 4, 5, 6, 7]; - let expected = NetworkData::new( - u64::from_be_bytes([0, 1, 2, 3, 4, 5, 6, 7]), - Vec::new(), - false, - ); - let actual = NetworkData::try_from_bytes(&response_bytes).unwrap(); - assert_eq!(expected.connection_id, actual.connection_id); - assert_eq!(expected.data, actual.data); - assert_eq!(expected.is_closed, actual.is_closed); - } - - #[test] - fn works_when_there_is_data() { - let response_bytes = vec![0, 0, 1, 2, 3, 4, 5, 6, 7, 255, 255, 255]; - let expected = NetworkData::new( - u64::from_be_bytes([0, 1, 2, 3, 4, 5, 6, 7]), - vec![255, 255, 255], - false, - ); - let actual = NetworkData::try_from_bytes(&response_bytes).unwrap(); - assert_eq!(expected.connection_id, actual.connection_id); - assert_eq!(expected.data, actual.data); - assert_eq!(expected.is_closed, actual.is_closed); - } - } - #[cfg(test)] mod connection_error_response_serde_tests { use super::*;