From fe2804df12f443d3fc1e4340c15edc1ba2f3e1ed Mon Sep 17 00:00:00 2001 From: Dan Wiebe Date: Thu, 14 Aug 2025 21:53:17 -0400 Subject: [PATCH 01/21] Fixed the AddRouteResultMessage panic problem too --- node/src/proxy_server/mod.rs | 200 +++++++++++++++++++++++-------- node/src/sub_lib/proxy_server.rs | 2 +- node/src/sub_lib/ttl_hashmap.rs | 63 ++++++++-- 3 files changed, 205 insertions(+), 60 deletions(-) diff --git a/node/src/proxy_server/mod.rs b/node/src/proxy_server/mod.rs index fc03348349..2bd9f9f991 100644 --- a/node/src/proxy_server/mod.rs +++ b/node/src/proxy_server/mod.rs @@ -58,7 +58,8 @@ use std::time::{Duration, SystemTime}; use tokio::prelude::Future; pub const CRASH_KEY: &str = "PROXYSERVER"; -pub const RETURN_ROUTE_TTL: Duration = Duration::from_secs(120); +pub const RETURN_ROUTE_TTL_FIRST_CHANCE: Duration = Duration::from_secs(120); +pub const RETURN_ROUTE_TTL_STRAGGLERS: Duration = Duration::from_secs(5); pub const STREAM_KEY_PURGE_DELAY: Duration = Duration::from_secs(30); @@ -89,7 +90,11 @@ pub struct ProxyServer { alias_cryptde: &'static dyn CryptDE, crashable: bool, logger: Logger, - route_ids_to_return_routes: TtlHashMap, + // Holds return-route information for requests that have not yet seen any responses + route_ids_to_return_routes_first_chance: TtlHashMap, + // Holds return-route information for requests that have seen at least one response and may + // see more in the future. The near future, because this TTL is much shorter. + route_ids_to_return_routes_stragglers: TtlHashMap, browser_proxy_sequence_offset: bool, inbound_client_data_helper_opt: Option>, stream_key_purge_delay: Duration, @@ -139,7 +144,7 @@ impl Handler for ProxyServer { type Result = (); fn handle(&mut self, msg: AddReturnRouteMessage, _ctx: &mut Self::Context) -> Self::Result { - self.route_ids_to_return_routes + self.route_ids_to_return_routes_first_chance .insert(msg.return_route_id, msg); } } @@ -163,12 +168,13 @@ impl Handler for ProxyServer { type Result = (); fn handle(&mut self, msg: AddRouteResultMessage, _ctx: &mut Self::Context) -> Self::Result { - let dns_failure = self - .dns_failure_retries - .get(&msg.stream_key) - .unwrap_or_else(|| { - panic!("AddRouteResultMessage Handler: stream key: {} not found within dns_failure_retries", msg.stream_key); - }); + let dns_failure = match self.dns_failure_retries.get(&msg.stream_key) { + Some(retry) => retry, + None => { + error!(self.logger, "AddRouteResultMessage stream key {} not found within dns_failure_retries", msg.stream_key); + return + } + }; match msg.result { Ok(route_query_response) => { @@ -272,7 +278,8 @@ impl ProxyServer { alias_cryptde, crashable, logger: Logger::new("ProxyServer"), - route_ids_to_return_routes: TtlHashMap::new(RETURN_ROUTE_TTL), + route_ids_to_return_routes_first_chance: TtlHashMap::new(RETURN_ROUTE_TTL_FIRST_CHANCE), + route_ids_to_return_routes_stragglers: TtlHashMap::new(RETURN_ROUTE_TTL_STRAGGLERS), browser_proxy_sequence_offset: false, inbound_client_data_helper_opt: Some(Box::new(IBCDHelperReal::new())), stream_key_purge_delay: STREAM_KEY_PURGE_DELAY, @@ -362,8 +369,12 @@ impl ProxyServer { } fn handle_dns_resolve_failure(&mut self, msg: &ExpiredCoresPackage) { + let return_route_id = match self.rri_from_remaining_route(&msg.remaining_route) { + Some(rri) => rri, + None => return, // TODO: Eventually we'll have to do something better here, but we'll probably need some heuristics. + }; let return_route_info = - match self.get_return_route_info(&msg.remaining_route, "dns resolve failure") { + match self.get_return_route_info(return_route_id, "dns resolve failure") { Some(rri) => rri, None => return, // TODO: Eventually we'll have to do something better here, but we'll probably need some heuristics. }; @@ -503,8 +514,13 @@ impl ProxyServer { "Relaying ClientResponsePayload (stream key {}, sequence {}, length {}) from Hopper to Dispatcher for client", response.stream_key, response.sequenced_packet.sequence_number, response.sequenced_packet.data.len() ); + let return_route_id = + match self.rri_from_remaining_route(&msg.remaining_route) { + Some(rri) => rri, + None => return, + }; let return_route_info = - match self.get_return_route_info(&msg.remaining_route, "client response") { + match self.get_return_route_info(return_route_id, "client response") { Some(rri) => rri, None => return, }; @@ -923,31 +939,43 @@ impl ProxyServer { } } - fn get_return_route_info( + fn rri_from_remaining_route( &self, remaining_route: &Route, - source: &str, - ) -> Option> { + ) -> Option { let mut mut_remaining_route = remaining_route.clone(); mut_remaining_route .shift(self.main_cryptde) .expect("Internal error: remaining route in ProxyServer with no hops"); - let return_route_id = match mut_remaining_route.id(self.main_cryptde) { - Ok(rri) => rri, + match mut_remaining_route.id(self.main_cryptde) { + Ok(rri) => Some(rri), Err(e) => { error!(self.logger, "Can't report services consumed: {}", e); - return None; - } - }; - match self.route_ids_to_return_routes.get(&return_route_id) { - Some(rri) => Some(rri), - None => { - error!(self.logger, "Can't report services consumed: received response with bogus return-route ID {} for {}. Ignoring", return_route_id, source); None } } } + fn get_return_route_info( + &mut self, + return_route_id: u32, + source: &str, + ) -> Option> { + match self.route_ids_to_return_routes_first_chance.remove(&return_route_id) { + Some(rri) => { + self.route_ids_to_return_routes_stragglers.insert(return_route_id, (*rri).clone()); + Some(rri) + }, + None => match self.route_ids_to_return_routes_stragglers.get(&return_route_id) { + Some(rri) => Some(rri), + None => { + error!(self.logger, "Can't report services consumed: received response with bogus return-route ID {} for {}. Ignoring", return_route_id, source); + None + } + } + } + } + fn report_response_services_consumed( &self, return_route_info: &AddReturnRouteMessage, @@ -1479,10 +1507,11 @@ mod tests { self } } + #[test] fn constants_have_correct_values() { assert_eq!(CRASH_KEY, "PROXYSERVER"); - assert_eq!(RETURN_ROUTE_TTL, Duration::from_secs(120)); + assert_eq!(RETURN_ROUTE_TTL_FIRST_CHANCE, Duration::from_secs(120)); assert_eq!(STREAM_KEY_PURGE_DELAY, Duration::from_secs(30)); } @@ -1617,6 +1646,70 @@ mod tests { } } + #[test] + fn get_return_route_info_produces_nothing_if_nothing_exists() { + let mut subject = ProxyServer::new( + main_cryptde(), + alias_cryptde(), + true, + Some(STANDARD_CONSUMING_WALLET_BALANCE), + false, + false, + ); + + let result = subject.get_return_route_info(1234, "test"); + + assert!(result.is_none(), "Expected no return route info, but got: {:?}", result); + } + + #[test] + fn get_return_route_info_produces_rri_from_first_chance_if_it_exists_and_moves_into_stragglers() { + let mut subject = ProxyServer::new( + main_cryptde(), + alias_cryptde(), + true, + Some(STANDARD_CONSUMING_WALLET_BALANCE), + false, + false, + ); + let return_route_message = AddReturnRouteMessage { + return_route_id: 1234, + expected_services: vec![ExpectedService::Nothing], + protocol: ProxyProtocol::TLS, + hostname_opt: None, + }; + subject.route_ids_to_return_routes_first_chance.insert(1234, return_route_message.clone()); + + let result = subject.get_return_route_info(1234, "test").unwrap(); + + assert_eq!(*result, return_route_message); + assert_eq!(subject.route_ids_to_return_routes_first_chance.get(&1234), None); + assert_eq!(subject.route_ids_to_return_routes_stragglers.get(&1234), Some(Rc::new(return_route_message))); + } + + #[test] + fn get_return_route_info_produces_rri_from_stragglers_if_it_exists() { + let mut subject = ProxyServer::new( + main_cryptde(), + alias_cryptde(), + true, + Some(STANDARD_CONSUMING_WALLET_BALANCE), + false, + false, + ); + let return_route_message = AddReturnRouteMessage { + return_route_id: 1234, + expected_services: vec![ExpectedService::Nothing], + protocol: ProxyProtocol::TLS, + hostname_opt: None, + }; + subject.route_ids_to_return_routes_stragglers.insert(1234, return_route_message.clone()); + + let result = subject.get_return_route_info(1234, "test").unwrap(); + + assert_eq!(*result, return_route_message); + } + #[test] fn proxy_server_receives_http_request_with_new_stream_key_from_dispatcher_then_sends_cores_package_to_hopper( ) { @@ -1865,7 +1958,7 @@ mod tests { .keys_and_addrs .insert(stream_key.clone(), socket_addr.clone()); - subject.route_ids_to_return_routes.insert( + subject.route_ids_to_return_routes_first_chance.insert( 1234, AddReturnRouteMessage { return_route_id: 1234, @@ -3072,10 +3165,8 @@ mod tests { } #[test] - #[should_panic( - expected = "AddRouteResultMessage Handler: stream key: AAAAAAAAAAAAAAAAAAAAAAAAAAA not found within dns_failure_retries" - )] fn route_result_message_handler_panics_when_dns_retries_hashmap_doesnt_contain_a_stream_key() { + init_test_logging(); let system = System::new("route_result_message_handler_panics_when_dns_retries_hashmap_doesnt_contain_a_stream_key"); let subject = ProxyServer::new( main_cryptde(), @@ -3096,7 +3187,9 @@ mod tests { }) .unwrap(); + System::current().stop(); system.run(); + TestLogHandler::new().exists_log_containing("ERROR: ProxyServer: AddRouteResultMessage stream key AAAAAAAAAAAAAAAAAAAAAAAAAAA not found within dns_failure_retries"); } #[test] @@ -3604,7 +3697,7 @@ mod tests { let expected_data = tls_request.to_vec(); let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), - client_addr: client_addr, + client_addr, reception_port: Some(TLS_PORT), sequence_number: Some(0), last_data: true, @@ -3759,7 +3852,7 @@ mod tests { subject .keys_and_addrs .insert(stream_key.clone(), socket_addr.clone()); - subject.route_ids_to_return_routes.insert( + subject.route_ids_to_return_routes_first_chance.insert( 1234, AddReturnRouteMessage { return_route_id: 1234, @@ -3856,7 +3949,7 @@ mod tests { subject .tunneled_hosts .insert(stream_key.clone(), "hostname".to_string()); - subject.route_ids_to_return_routes.insert( + subject.route_ids_to_return_routes_first_chance.insert( 1234, AddReturnRouteMessage { return_route_id: 1234, @@ -3886,6 +3979,9 @@ mod tests { assert!(subject.keys_and_addrs.is_empty()); assert!(subject.stream_key_routes.is_empty()); assert!(subject.tunneled_hosts.is_empty()); + assert!(subject.route_ids_to_return_routes_first_chance.get(&1234).is_none()); + // TODO: This assert should be much stronger + assert!(subject.route_ids_to_return_routes_stragglers.get(&1234).is_some()); } #[test] @@ -3965,7 +4061,7 @@ mod tests { subject .tunneled_hosts .insert(stream_key.clone(), "hostname".to_string()); - subject.route_ids_to_return_routes.insert( + subject.route_ids_to_return_routes_first_chance.insert( 1234, AddReturnRouteMessage { return_route_id: 1234, @@ -4076,7 +4172,7 @@ mod tests { exit_byte_rate: 100, exit_service_rate: 60000, }; - subject.route_ids_to_return_routes.insert( + subject.route_ids_to_return_routes_first_chance.insert( 1234, AddReturnRouteMessage { return_route_id: 1234, @@ -4168,7 +4264,7 @@ mod tests { let rate_pack_d = rate_pack(101); let rate_pack_e = rate_pack(102); let rate_pack_f = rate_pack(103); - subject.route_ids_to_return_routes.insert( + subject.route_ids_to_return_routes_first_chance.insert( 1234, AddReturnRouteMessage { return_route_id: 1234, @@ -4200,7 +4296,7 @@ mod tests { let rate_pack_g = rate_pack(104); let rate_pack_h = rate_pack(105); let rate_pack_i = rate_pack(106); - subject.route_ids_to_return_routes.insert( + subject.route_ids_to_return_routes_first_chance.insert( 1235, AddReturnRouteMessage { return_route_id: 1235, @@ -4388,7 +4484,7 @@ mod tests { let rate_pack_d = rate_pack(101); let rate_pack_e = rate_pack(102); let rate_pack_f = rate_pack(103); - subject.route_ids_to_return_routes.insert( + subject.route_ids_to_return_routes_first_chance.insert( 1234, AddReturnRouteMessage { return_route_id: 1234, @@ -4471,7 +4567,7 @@ mod tests { let incoming_route_e_wallet = make_wallet("E Earning"); let rate_pack_d = rate_pack(101); let rate_pack_e = rate_pack(102); - subject.route_ids_to_return_routes.insert( + subject.route_ids_to_return_routes_first_chance.insert( 1234, AddReturnRouteMessage { return_route_id: 1234, @@ -4662,7 +4758,7 @@ mod tests { let rate_pack_d = rate_pack(101); let rate_pack_e = rate_pack(102); let rate_pack_f = rate_pack(103); - subject.route_ids_to_return_routes.insert( + subject.route_ids_to_return_routes_first_chance.insert( 1234, AddReturnRouteMessage { return_route_id: 1234, @@ -4776,7 +4872,7 @@ mod tests { .insert(stream_key.clone(), socket_addr.clone()); let exit_public_key = PublicKey::from(&b"exit_key"[..]); let exit_wallet = make_wallet("exit wallet"); - subject.route_ids_to_return_routes.insert( + subject.route_ids_to_return_routes_first_chance.insert( 1234, AddReturnRouteMessage { return_route_id: 1234, @@ -4858,7 +4954,7 @@ mod tests { .insert(stream_key.clone(), socket_addr); let exit_public_key = PublicKey::from(&b"exit_key"[..]); let exit_wallet = make_wallet("exit wallet"); - subject.route_ids_to_return_routes.insert( + subject.route_ids_to_return_routes_first_chance.insert( 1234, AddReturnRouteMessage { return_route_id: 1234, @@ -4929,7 +5025,7 @@ mod tests { .insert(stream_key.clone(), socket_addr.clone()); let exit_public_key = PublicKey::from(&b"exit_key"[..]); let exit_wallet = make_wallet("exit wallet"); - subject.route_ids_to_return_routes.insert( + subject.route_ids_to_return_routes_first_chance.insert( return_route_id, AddReturnRouteMessage { return_route_id, @@ -5006,7 +5102,7 @@ mod tests { .insert(stream_key.clone(), socket_addr.clone()); let exit_public_key = PublicKey::from(&b"exit_key"[..]); let exit_wallet = make_wallet("exit wallet"); - subject.route_ids_to_return_routes.insert( + subject.route_ids_to_return_routes_first_chance.insert( return_route_id, AddReturnRouteMessage { return_route_id, @@ -5096,7 +5192,7 @@ mod tests { expected_services: ExpectedServices::OneWay(vec![]), }, ); - subject.route_ids_to_return_routes.insert( + subject.route_ids_to_return_routes_first_chance.insert( 1234, AddReturnRouteMessage { return_route_id: 1234, @@ -5155,7 +5251,7 @@ mod tests { subject .keys_and_addrs .insert(stream_key.clone(), socket_addr.clone()); - subject.route_ids_to_return_routes.insert( + subject.route_ids_to_return_routes_first_chance.insert( 1234, AddReturnRouteMessage { return_route_id: 1234, @@ -5256,7 +5352,7 @@ mod tests { subject .keys_and_addrs .insert(stream_key.clone(), socket_addr.clone()); - subject.route_ids_to_return_routes.insert( + subject.route_ids_to_return_routes_first_chance.insert( 1234, AddReturnRouteMessage { return_route_id: 1234, @@ -5344,7 +5440,7 @@ mod tests { subject .keys_and_addrs .insert(stream_key.clone(), socket_addr.clone()); - subject.route_ids_to_return_routes.insert( + subject.route_ids_to_return_routes_first_chance.insert( 1234, AddReturnRouteMessage { return_route_id: 1234, @@ -5432,7 +5528,7 @@ mod tests { subject .keys_and_addrs .insert(stream_key.clone(), socket_addr.clone()); - subject.route_ids_to_return_routes.insert( + subject.route_ids_to_return_routes_first_chance.insert( 1234, AddReturnRouteMessage { return_route_id: 1234, @@ -5513,7 +5609,7 @@ mod tests { .keys_and_addrs .insert(stream_key.clone(), socket_addr.clone()); let remaining_route = return_route_with_id(cryptde, 4321); - subject.route_ids_to_return_routes.insert( + subject.route_ids_to_return_routes_first_chance.insert( 4321, AddReturnRouteMessage { return_route_id: 4321, @@ -5701,11 +5797,13 @@ mod tests { false, false, ); - subject.route_ids_to_return_routes = TtlHashMap::new(Duration::from_millis(250)); + subject.route_ids_to_return_routes_first_chance = TtlHashMap::new( + Duration::from_millis(250), + ); subject .keys_and_addrs .insert(stream_key, SocketAddr::from_str("1.2.3.4:5678").unwrap()); - subject.route_ids_to_return_routes.insert( + subject.route_ids_to_return_routes_first_chance.insert( 1234, AddReturnRouteMessage { return_route_id: 1234, diff --git a/node/src/sub_lib/proxy_server.rs b/node/src/sub_lib/proxy_server.rs index c3042859fb..8b28c588ab 100644 --- a/node/src/sub_lib/proxy_server.rs +++ b/node/src/sub_lib/proxy_server.rs @@ -55,7 +55,7 @@ impl ClientRequestPayload_0v1 { } } -#[derive(Message, Debug, PartialEq, Eq)] +#[derive(Message, Debug, PartialEq, Eq, Clone)] pub struct AddReturnRouteMessage { pub return_route_id: u32, pub expected_services: Vec, diff --git a/node/src/sub_lib/ttl_hashmap.rs b/node/src/sub_lib/ttl_hashmap.rs index faa79b68a6..9eae4c1793 100644 --- a/node/src/sub_lib/ttl_hashmap.rs +++ b/node/src/sub_lib/ttl_hashmap.rs @@ -54,6 +54,17 @@ where } } + pub fn remove(&self, key: &K) -> Option> { + self.remove_expired_entries(); + + match self.data.borrow_mut().remove(key) { + Some((result, _)) => { + Some(result) + } + None => None, + } + } + fn remove_expired_entries(&self) { let now = Instant::now(); @@ -88,17 +99,55 @@ mod tests { fn new_sets_ttl() { let subject = TtlHashMap::::new(Duration::from_millis(1000)); - assert_eq!(subject.ttl, Duration::from_millis(1000)); + let result = subject.ttl; + + assert_eq!(result, Duration::from_millis(1000)); } #[test] - fn remove_returns_none_for_entry_that_was_never_inserted() { + fn get_returns_none_for_entry_that_was_never_inserted() { let subject = TtlHashMap::::new(Duration::from_millis(1000)); - assert_eq!(subject.get(&11u32), None); + let result = subject.get(&11u32); + + assert_eq!(result, None); assert_eq!(subject.ttl(), Duration::from_millis(1000)); } + #[test] + fn remove_returns_none_if_no_such_entry_exists() { + let subject = TtlHashMap::::new(Duration::from_millis(1000)); + + let result = subject.remove(&11u32); + + assert_eq!(result, None); + } + + #[test] + fn remove_returns_existing_entry_and_removes() { + let mut subject = TtlHashMap::::new(Duration::from_millis(1000)); + subject.insert(11u32, 42u32); + + let before_result = subject.remove(&11u32); + let after_result = subject.remove(&11u32); + + assert_eq!(before_result, Some(Rc::new(42u32))); + assert_eq!(after_result, None); + } + + #[test] + fn ttl_hashmap_remove_removes_expired_entry() { + let mut subject = TtlHashMap::new(Duration::from_millis(10)); + subject.insert(42u32, "Hello"); + thread::sleep(Duration::from_millis(20)); + + let result = subject.remove(&11u32); // nonexistent key + + assert_eq!(result, None); + // Low-level get, because high-level get would remove it if .remove() didn't + assert_eq!(subject.data.borrow().get(&42u32), None); + } + #[test] fn ttl_hashmap_does_not_remove_entry_before_it_is_expired() { let mut subject = TtlHashMap::new(Duration::from_millis(10)); @@ -114,20 +163,18 @@ mod tests { #[test] fn ttl_hashmap_get_removes_expired_entry() { let mut subject = TtlHashMap::new(Duration::from_millis(10)); - subject.insert(42u32, "Hello"); - thread::sleep(Duration::from_millis(20)); - assert_eq!(subject.get(&42u32), None); + let result = subject.get(&42u32); + + assert_eq!(result, None); } #[test] fn ttl_hashmap_insert_removes_expired_entry() { let mut subject = TtlHashMap::new(Duration::from_millis(10)); - subject.insert(42u32, "Hello"); - thread::sleep(Duration::from_millis(20)); subject.insert(24u32, "World"); From 81333fe7a49d16dc90e9e66bab5741fd64e429a2 Mon Sep 17 00:00:00 2001 From: Dan Wiebe Date: Thu, 14 Aug 2025 22:20:44 -0400 Subject: [PATCH 02/21] Preemptive review issues --- node/src/proxy_server/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/node/src/proxy_server/mod.rs b/node/src/proxy_server/mod.rs index 2bd9f9f991..c75ec08ea6 100644 --- a/node/src/proxy_server/mod.rs +++ b/node/src/proxy_server/mod.rs @@ -1512,6 +1512,7 @@ mod tests { fn constants_have_correct_values() { assert_eq!(CRASH_KEY, "PROXYSERVER"); assert_eq!(RETURN_ROUTE_TTL_FIRST_CHANCE, Duration::from_secs(120)); + assert_eq!(RETURN_ROUTE_TTL_STRAGGLERS, Duration::from_secs(5)); assert_eq!(STREAM_KEY_PURGE_DELAY, Duration::from_secs(30)); } From 02d46c39cd876192a444895e19fd2a0315589aef Mon Sep 17 00:00:00 2001 From: Dan Wiebe Date: Thu, 14 Aug 2025 22:51:13 -0400 Subject: [PATCH 03/21] Formatting --- node/src/proxy_server/mod.rs | 91 +++++++++++++++++++++------------ node/src/sub_lib/ttl_hashmap.rs | 7 +-- 2 files changed, 60 insertions(+), 38 deletions(-) diff --git a/node/src/proxy_server/mod.rs b/node/src/proxy_server/mod.rs index c75ec08ea6..91007d7e8c 100644 --- a/node/src/proxy_server/mod.rs +++ b/node/src/proxy_server/mod.rs @@ -171,8 +171,12 @@ impl Handler for ProxyServer { let dns_failure = match self.dns_failure_retries.get(&msg.stream_key) { Some(retry) => retry, None => { - error!(self.logger, "AddRouteResultMessage stream key {} not found within dns_failure_retries", msg.stream_key); - return + error!( + self.logger, + "AddRouteResultMessage stream key {} not found within dns_failure_retries", + msg.stream_key + ); + return; } }; @@ -514,16 +518,15 @@ impl ProxyServer { "Relaying ClientResponsePayload (stream key {}, sequence {}, length {}) from Hopper to Dispatcher for client", response.stream_key, response.sequenced_packet.sequence_number, response.sequenced_packet.data.len() ); - let return_route_id = - match self.rri_from_remaining_route(&msg.remaining_route) { - Some(rri) => rri, - None => return, - }; - let return_route_info = - match self.get_return_route_info(return_route_id, "client response") { - Some(rri) => rri, - None => return, - }; + let return_route_id = match self.rri_from_remaining_route(&msg.remaining_route) { + Some(rri) => rri, + None => return, + }; + let return_route_info = match self.get_return_route_info(return_route_id, "client response") + { + Some(rri) => rri, + None => return, + }; self.report_response_services_consumed( &return_route_info, response.sequenced_packet.data.len(), @@ -939,10 +942,7 @@ impl ProxyServer { } } - fn rri_from_remaining_route( - &self, - remaining_route: &Route, - ) -> Option { + fn rri_from_remaining_route(&self, remaining_route: &Route) -> Option { let mut mut_remaining_route = remaining_route.clone(); mut_remaining_route .shift(self.main_cryptde) @@ -961,18 +961,25 @@ impl ProxyServer { return_route_id: u32, source: &str, ) -> Option> { - match self.route_ids_to_return_routes_first_chance.remove(&return_route_id) { + match self + .route_ids_to_return_routes_first_chance + .remove(&return_route_id) + { Some(rri) => { - self.route_ids_to_return_routes_stragglers.insert(return_route_id, (*rri).clone()); + self.route_ids_to_return_routes_stragglers + .insert(return_route_id, (*rri).clone()); Some(rri) - }, - None => match self.route_ids_to_return_routes_stragglers.get(&return_route_id) { + } + None => match self + .route_ids_to_return_routes_stragglers + .get(&return_route_id) + { Some(rri) => Some(rri), None => { error!(self.logger, "Can't report services consumed: received response with bogus return-route ID {} for {}. Ignoring", return_route_id, source); None } - } + }, } } @@ -1660,11 +1667,16 @@ mod tests { let result = subject.get_return_route_info(1234, "test"); - assert!(result.is_none(), "Expected no return route info, but got: {:?}", result); + assert!( + result.is_none(), + "Expected no return route info, but got: {:?}", + result + ); } #[test] - fn get_return_route_info_produces_rri_from_first_chance_if_it_exists_and_moves_into_stragglers() { + fn get_return_route_info_produces_rri_from_first_chance_if_it_exists_and_moves_into_stragglers() + { let mut subject = ProxyServer::new( main_cryptde(), alias_cryptde(), @@ -1679,13 +1691,21 @@ mod tests { protocol: ProxyProtocol::TLS, hostname_opt: None, }; - subject.route_ids_to_return_routes_first_chance.insert(1234, return_route_message.clone()); + subject + .route_ids_to_return_routes_first_chance + .insert(1234, return_route_message.clone()); let result = subject.get_return_route_info(1234, "test").unwrap(); assert_eq!(*result, return_route_message); - assert_eq!(subject.route_ids_to_return_routes_first_chance.get(&1234), None); - assert_eq!(subject.route_ids_to_return_routes_stragglers.get(&1234), Some(Rc::new(return_route_message))); + assert_eq!( + subject.route_ids_to_return_routes_first_chance.get(&1234), + None + ); + assert_eq!( + subject.route_ids_to_return_routes_stragglers.get(&1234), + Some(Rc::new(return_route_message)) + ); } #[test] @@ -1704,7 +1724,9 @@ mod tests { protocol: ProxyProtocol::TLS, hostname_opt: None, }; - subject.route_ids_to_return_routes_stragglers.insert(1234, return_route_message.clone()); + subject + .route_ids_to_return_routes_stragglers + .insert(1234, return_route_message.clone()); let result = subject.get_return_route_info(1234, "test").unwrap(); @@ -3980,9 +4002,15 @@ mod tests { assert!(subject.keys_and_addrs.is_empty()); assert!(subject.stream_key_routes.is_empty()); assert!(subject.tunneled_hosts.is_empty()); - assert!(subject.route_ids_to_return_routes_first_chance.get(&1234).is_none()); + assert!(subject + .route_ids_to_return_routes_first_chance + .get(&1234) + .is_none()); // TODO: This assert should be much stronger - assert!(subject.route_ids_to_return_routes_stragglers.get(&1234).is_some()); + assert!(subject + .route_ids_to_return_routes_stragglers + .get(&1234) + .is_some()); } #[test] @@ -5798,9 +5826,8 @@ mod tests { false, false, ); - subject.route_ids_to_return_routes_first_chance = TtlHashMap::new( - Duration::from_millis(250), - ); + subject.route_ids_to_return_routes_first_chance = + TtlHashMap::new(Duration::from_millis(250)); subject .keys_and_addrs .insert(stream_key, SocketAddr::from_str("1.2.3.4:5678").unwrap()); diff --git a/node/src/sub_lib/ttl_hashmap.rs b/node/src/sub_lib/ttl_hashmap.rs index 9eae4c1793..dc06d18aaa 100644 --- a/node/src/sub_lib/ttl_hashmap.rs +++ b/node/src/sub_lib/ttl_hashmap.rs @@ -57,12 +57,7 @@ where pub fn remove(&self, key: &K) -> Option> { self.remove_expired_entries(); - match self.data.borrow_mut().remove(key) { - Some((result, _)) => { - Some(result) - } - None => None, - } + self.data.borrow_mut().remove(key).map(|(result, _)| result) } fn remove_expired_entries(&self) { From 442e63c6ed3b35262bc74d48bd60c8ffb3206593 Mon Sep 17 00:00:00 2001 From: Dan Wiebe Date: Mon, 18 Aug 2025 06:58:05 -0400 Subject: [PATCH 04/21] example.com -> www.example.com --- .../tests/bookkeeping_test.rs | 4 ++-- .../tests/communication_failure_test.rs | 4 ++-- .../tests/data_routing_test.rs | 4 ++-- node/src/blockchain/blockchain_bridge.rs | 2 +- node/src/proxy_server/mod.rs | 12 ++++++------ node/src/stream_reader.rs | 6 +++--- node/src/test_utils/mod.rs | 2 +- node/tests/http_through_node_test.rs | 2 +- node/tests/initialization_test.rs | 2 +- node/tests/tls_through_node_test.rs | 4 ++-- node/tests/ui_gateway_test.rs | 2 +- 11 files changed, 22 insertions(+), 22 deletions(-) diff --git a/multinode_integration_tests/tests/bookkeeping_test.rs b/multinode_integration_tests/tests/bookkeeping_test.rs index 6c7552eae4..97b39f5c90 100644 --- a/multinode_integration_tests/tests/bookkeeping_test.rs +++ b/multinode_integration_tests/tests/bookkeeping_test.rs @@ -29,13 +29,13 @@ fn provided_and_consumed_services_are_recorded_in_databases() { let mut client = originating_node.make_client(8080, STANDARD_CLIENT_TIMEOUT_MILLIS); client.set_timeout(Duration::from_secs(10)); - let request = "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n".as_bytes(); + let request = "GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n".as_bytes(); client.send_chunk(request); let response = String::from_utf8(client.wait_for_chunk()).unwrap(); assert!( response.contains("

Example Domain

"), - "Not from example.com:\n{}", + "Not from www.example.com:\n{}", response ); diff --git a/multinode_integration_tests/tests/communication_failure_test.rs b/multinode_integration_tests/tests/communication_failure_test.rs index 65d31dd4fc..f687cf05df 100644 --- a/multinode_integration_tests/tests/communication_failure_test.rs +++ b/multinode_integration_tests/tests/communication_failure_test.rs @@ -103,7 +103,7 @@ fn neighborhood_notified_of_newly_missing_node() { //Establish a client on the originating Node and send some ill-fated traffic. let mut client = originating_node.make_client(8080, STANDARD_CLIENT_TIMEOUT_MILLIS); - client.send_chunk("GET http://example.com HTTP/1.1\r\n\r\n".as_bytes()); + client.send_chunk("GET http://www.example.com HTTP/1.1\r\n\r\n".as_bytes()); // Now direct the witness Node to wait for Gossip about the disappeared Node. let (disappearance_gossip, _) = witness_node @@ -405,7 +405,7 @@ fn dns_resolution_failure_no_longer_blacklists_exit_node_for_all_hosts() { ), ); - client.send_chunk("GET / HTTP/1.1\r\nHost: example.com\r\n\r\n".as_bytes()); + client.send_chunk("GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n".as_bytes()); let cheapest_node = node_list.first().unwrap(); let cheapest_node_expired_cores_package = cheapest_node .wait_for_specific_package( diff --git a/multinode_integration_tests/tests/data_routing_test.rs b/multinode_integration_tests/tests/data_routing_test.rs index cdefcd354e..98dd460a11 100644 --- a/multinode_integration_tests/tests/data_routing_test.rs +++ b/multinode_integration_tests/tests/data_routing_test.rs @@ -175,7 +175,7 @@ fn tls_end_to_end_routing_test() { .expect("Could not set read timeout to 1000ms"); let connector = TlsConnector::new().expect("Could not build TlsConnector"); match connector.connect( - "example.com", + "www.example.com", stream.try_clone().expect("Couldn't clone TcpStream"), ) { Ok(s) => { @@ -199,7 +199,7 @@ fn tls_end_to_end_routing_test() { tls_stream.expect("Couldn't handshake") }; - let request = "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n".as_bytes(); + let request = "GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n".as_bytes(); tls_stream .write(request.clone()) .expect("Could not write request to TLS stream"); diff --git a/node/src/blockchain/blockchain_bridge.rs b/node/src/blockchain/blockchain_bridge.rs index e4275b036e..a0e501393b 100644 --- a/node/src/blockchain/blockchain_bridge.rs +++ b/node/src/blockchain/blockchain_bridge.rs @@ -662,7 +662,7 @@ mod tests { #[test] fn blockchain_interface_is_constructed_with_a_blockchain_service_url() { init_test_logging(); - let blockchain_service_url = "https://example.com"; + let blockchain_service_url = "https://www.example.com"; let subject = BlockchainBridge::initialize_blockchain_interface( Some(blockchain_service_url.to_string()), TEST_DEFAULT_CHAIN, diff --git a/node/src/proxy_server/mod.rs b/node/src/proxy_server/mod.rs index 91007d7e8c..f130f017a8 100644 --- a/node/src/proxy_server/mod.rs +++ b/node/src/proxy_server/mod.rs @@ -6504,15 +6504,15 @@ mod tests { #[test] fn hostname_works() { - assert_on_hostname("https://example.com/folder/file.html", "example.com"); - assert_on_hostname("example.com/index.php?arg=test", "example.com"); + assert_on_hostname("https://www.example.com/folder/file.html", "www.example.com"); + assert_on_hostname("www.example.com/index.php?arg=test", "www.example.com"); assert_on_hostname("sub.example.com/index.php?arg=test", "sub.example.com"); assert_on_hostname("1.1.1.1", "1.1.1.1"); assert_on_hostname("", ""); assert_on_hostname("example", "example"); assert_on_hostname( - "htttttps://example.com/folder/file.html", - "htttttps://example.com/folder/file.html", + "htttttps://www.example.com/folder/file.html", + "htttttps://www.example.com/folder/file.html", ); } @@ -6554,11 +6554,11 @@ mod tests { Err("localhost".to_string()) ); assert_eq!( - Hostname::new("example.com").validate_non_loopback_host(), + Hostname::new("www.example.com").validate_non_loopback_host(), Ok(()) ); assert_eq!( - Hostname::new("https://example.com").validate_non_loopback_host(), + Hostname::new("https://www.example.com").validate_non_loopback_host(), Ok(()) ); } diff --git a/node/src/stream_reader.rs b/node/src/stream_reader.rs index 34a7b62bdf..ea96b7d5a4 100644 --- a/node/src/stream_reader.rs +++ b/node/src/stream_reader.rs @@ -538,7 +538,7 @@ mod tests { Box::new(TlsDiscriminatorFactory::new()), Box::new(HttpRequestDiscriminatorFactory::new()), ]; - let http_connect_request = Vec::from("CONNECT example.com:443 HTTP/1.1\r\n\r\n".as_bytes()); + let http_connect_request = Vec::from("CONNECT www.example.com:443 HTTP/1.1\r\n\r\n".as_bytes()); // Magic TLS Sauce stolen from Configuration let tls_request = Vec::from(&[0x16, 0x03, 0x01, 0x00, 0x03, 0x01, 0x02, 0x03][..]); let reader = ReadHalfWrapperMock { @@ -594,7 +594,7 @@ mod tests { let discriminator_factories: Vec> = vec![Box::new(HttpRequestDiscriminatorFactory::new())]; let request1 = Vec::from("GET http://here.com HTTP/1.1\r\n\r\n".as_bytes()); - let request2 = Vec::from("GET http://example.com HTTP/1.1\r\n\r\n".as_bytes()); + let request2 = Vec::from("GET http://www.example.com HTTP/1.1\r\n\r\n".as_bytes()); let reader = ReadHalfWrapperMock { poll_read_results: vec![ (request1.clone(), Ok(Async::Ready(request1.len()))), @@ -651,7 +651,7 @@ mod tests { last_data: false, is_clandestine: false, sequence_number: Some(1), - data: Vec::from("GET http://example.com HTTP/1.1\r\n\r\n".as_bytes()), + data: Vec::from("GET http://www.example.com HTTP/1.1\r\n\r\n".as_bytes()), } ); } diff --git a/node/src/test_utils/mod.rs b/node/src/test_utils/mod.rs index 1bf32b4b54..595bf36993 100644 --- a/node/src/test_utils/mod.rs +++ b/node/src/test_utils/mod.rs @@ -713,7 +713,7 @@ pub mod unshared_test_utils { ClientRequestPayload_0v1 { stream_key: StreamKey::make_meaningful_stream_key("request"), sequenced_packet: SequencedPacket::new(make_garbage_data(bytes), 0, true), - target_hostname: Some("example.com".to_string()), + target_hostname: Some("www.example.com".to_string()), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: cryptde.public_key().clone(), diff --git a/node/tests/http_through_node_test.rs b/node/tests/http_through_node_test.rs index f49cb25b9f..9f2d3669f7 100644 --- a/node/tests/http_through_node_test.rs +++ b/node/tests/http_through_node_test.rs @@ -24,7 +24,7 @@ fn http_through_node_integration() { stream .set_read_timeout(Some(Duration::from_millis(1000))) .unwrap(); - let request = "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n".as_bytes(); + let request = "GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n".as_bytes(); stream.write(request.clone()).unwrap(); let buf = read_until_timeout(&mut stream); diff --git a/node/tests/initialization_test.rs b/node/tests/initialization_test.rs index 5b57d5b969..b124195db4 100644 --- a/node/tests/initialization_test.rs +++ b/node/tests/initialization_test.rs @@ -76,7 +76,7 @@ fn initialization_sequence_integration() { ("neighborhood-mode", Some("zero-hop")), ("log-level", Some("trace")), ("data-directory", Some(&data_directory.to_str().unwrap())), - ("blockchain-service-url", Some("https://example.com")), + ("blockchain-service-url", Some("https://www.example.com")), ])) .unwrap(); let financials_request = UiFinancialsRequest { diff --git a/node/tests/tls_through_node_test.rs b/node/tests/tls_through_node_test.rs index 1509e38c7a..d8975c9b07 100644 --- a/node/tests/tls_through_node_test.rs +++ b/node/tests/tls_through_node_test.rs @@ -33,7 +33,7 @@ fn tls_through_node_integration() { .expect("Could not set read timeout to 1000ms"); let connector = TlsConnector::new().expect("Could not build TlsConnector"); match connector.connect( - "example.com", + "www.example.com", stream.try_clone().expect("Couldn't clone TcpStream"), ) { Ok(s) => { @@ -57,7 +57,7 @@ fn tls_through_node_integration() { tls_stream.expect("Couldn't handshake") }; - let request = "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n".as_bytes(); + let request = "GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n".as_bytes(); tls_stream .write(request.clone()) .expect("Could not write request to TLS stream"); diff --git a/node/tests/ui_gateway_test.rs b/node/tests/ui_gateway_test.rs index fc68020751..07b603bff6 100644 --- a/node/tests/ui_gateway_test.rs +++ b/node/tests/ui_gateway_test.rs @@ -142,7 +142,7 @@ fn daemon_does_not_allow_node_to_keep_his_client_alive_integration() { ("chain", Some("polygon-mainnet")), ("neighborhood-mode", Some("standard")), ("log-level", Some("trace")), - ("blockchain-service-url", Some("https://example.com")), + ("blockchain-service-url", Some("https://www.example.com")), ("data-directory", Some(&data_directory.to_str().unwrap())), ])) .unwrap(); From ac4c096f77cf8bf024a75d97a96d2af6e165c54a Mon Sep 17 00:00:00 2001 From: Dan Wiebe Date: Mon, 18 Aug 2025 06:59:25 -0400 Subject: [PATCH 05/21] Formatting --- node/src/proxy_server/mod.rs | 5 ++++- node/src/stream_reader.rs | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/node/src/proxy_server/mod.rs b/node/src/proxy_server/mod.rs index f130f017a8..cfed990e70 100644 --- a/node/src/proxy_server/mod.rs +++ b/node/src/proxy_server/mod.rs @@ -6504,7 +6504,10 @@ mod tests { #[test] fn hostname_works() { - assert_on_hostname("https://www.example.com/folder/file.html", "www.example.com"); + assert_on_hostname( + "https://www.example.com/folder/file.html", + "www.example.com", + ); assert_on_hostname("www.example.com/index.php?arg=test", "www.example.com"); assert_on_hostname("sub.example.com/index.php?arg=test", "sub.example.com"); assert_on_hostname("1.1.1.1", "1.1.1.1"); diff --git a/node/src/stream_reader.rs b/node/src/stream_reader.rs index ea96b7d5a4..cac9211a67 100644 --- a/node/src/stream_reader.rs +++ b/node/src/stream_reader.rs @@ -538,7 +538,8 @@ mod tests { Box::new(TlsDiscriminatorFactory::new()), Box::new(HttpRequestDiscriminatorFactory::new()), ]; - let http_connect_request = Vec::from("CONNECT www.example.com:443 HTTP/1.1\r\n\r\n".as_bytes()); + let http_connect_request = + Vec::from("CONNECT www.example.com:443 HTTP/1.1\r\n\r\n".as_bytes()); // Magic TLS Sauce stolen from Configuration let tls_request = Vec::from(&[0x16, 0x03, 0x01, 0x00, 0x03, 0x01, 0x02, 0x03][..]); let reader = ReadHalfWrapperMock { From 1234f5cb7fb5a279ac9f45313b843aa7668b621a Mon Sep 17 00:00:00 2001 From: Dan Wiebe Date: Mon, 25 Aug 2025 23:48:58 -0400 Subject: [PATCH 06/21] Added some debug logging to track RRI --- node/src/proxy_server/mod.rs | 18 +++++++-- node/src/sub_lib/ttl_hashmap.rs | 66 +++++++++++++++++++++++++++++++-- 2 files changed, 77 insertions(+), 7 deletions(-) diff --git a/node/src/proxy_server/mod.rs b/node/src/proxy_server/mod.rs index cfed990e70..7435610da1 100644 --- a/node/src/proxy_server/mod.rs +++ b/node/src/proxy_server/mod.rs @@ -267,6 +267,8 @@ impl ProxyServer { crashable: bool, is_running_in_integration_test: bool, ) -> ProxyServer { + let ps_logger = Logger::new("ProxyServer"); + let hm_logger = ps_logger.clone(); ProxyServer { subs: None, client_request_payload_factory: Box::new(ClientRequestPayloadFactoryReal::new()), @@ -281,9 +283,15 @@ impl ProxyServer { main_cryptde, alias_cryptde, crashable, - logger: Logger::new("ProxyServer"), + logger: ps_logger, route_ids_to_return_routes_first_chance: TtlHashMap::new(RETURN_ROUTE_TTL_FIRST_CHANCE), - route_ids_to_return_routes_stragglers: TtlHashMap::new(RETURN_ROUTE_TTL_STRAGGLERS), + route_ids_to_return_routes_stragglers: TtlHashMap::new_with_retire( + RETURN_ROUTE_TTL_STRAGGLERS, + move |k, _| { + debug!(hm_logger,"Return route info {} expired from straggler cache", *k); + true + }, + ), browser_proxy_sequence_offset: false, inbound_client_data_helper_opt: Some(Box::new(IBCDHelperReal::new())), stream_key_purge_delay: STREAM_KEY_PURGE_DELAY, @@ -968,13 +976,17 @@ impl ProxyServer { Some(rri) => { self.route_ids_to_return_routes_stragglers .insert(return_route_id, (*rri).clone()); + debug!(self.logger, "Return route info {} found in first-chance cache; graduated to straggler cache", return_route_id); Some(rri) } None => match self .route_ids_to_return_routes_stragglers .get(&return_route_id) { - Some(rri) => Some(rri), + Some(rri) => { + debug!(self.logger, "Return route info {} found in straggler cache", return_route_id); + Some(rri) + }, None => { error!(self.logger, "Can't report services consumed: received response with bogus return-route ID {} for {}. Ignoring", return_route_id, source); None diff --git a/node/src/sub_lib/ttl_hashmap.rs b/node/src/sub_lib/ttl_hashmap.rs index dc06d18aaa..6d5d404f24 100644 --- a/node/src/sub_lib/ttl_hashmap.rs +++ b/node/src/sub_lib/ttl_hashmap.rs @@ -15,6 +15,7 @@ where last_check: RefCell, data: RefCell, Instant)>>, ttl: Duration, + retire_closure: Box bool> } impl TtlHashMap @@ -27,6 +28,19 @@ where last_check: RefCell::new(Instant::now()), data: RefCell::new(HashMap::new()), ttl, + retire_closure: Box::new(|_, _| true), + } + } + + pub fn new_with_retire(ttl: Duration, retire_closure: F) -> TtlHashMap + where + F: 'static + Fn(&K, &V) -> bool, + { + TtlHashMap { + last_check: RefCell::new(Instant::now()), + data: RefCell::new(HashMap::new()), + ttl, + retire_closure: Box::new(retire_closure), } } @@ -80,13 +94,22 @@ where }; expired.iter().for_each(|key| { - self.data.borrow_mut().remove(key); + let mut data = self.data.borrow_mut(); + match data.remove(key) { + Some((value, _)) => { + if !(self.retire_closure)(key, value.as_ref()) { + data.insert(key.clone(), (value, now)); + } + } + None => ()// already removed + } }); } } #[cfg(test)] mod tests { + use std::sync::{Arc, Mutex}; use super::*; use std::thread; @@ -145,7 +168,12 @@ mod tests { #[test] fn ttl_hashmap_does_not_remove_entry_before_it_is_expired() { - let mut subject = TtlHashMap::new(Duration::from_millis(10)); + let retire_closure_has_run = Arc::new(Mutex::new(false)); + let retire_closure_has_run_inner = retire_closure_has_run.clone(); + let mut subject = TtlHashMap::new_with_retire( + Duration::from_millis(10), + move |_, _| { *(retire_closure_has_run_inner.lock().unwrap()) = true; true } + ); subject.insert(42u32, "Hello"); subject.insert(24u32, "World"); @@ -153,22 +181,51 @@ mod tests { assert_eq!(subject.get(&42u32).unwrap().as_ref(), &"Hello"); assert_eq!(subject.get(&24u32).unwrap().as_ref(), &"World"); assert_eq!(subject.ttl(), Duration::from_millis(10)); + assert_eq!(*retire_closure_has_run.lock().unwrap(), false); } #[test] fn ttl_hashmap_get_removes_expired_entry() { - let mut subject = TtlHashMap::new(Duration::from_millis(10)); + let retire_closure_has_run = Arc::new(Mutex::new(false)); + let retire_closure_has_run_inner = retire_closure_has_run.clone(); + let mut subject = TtlHashMap::new_with_retire( + Duration::from_millis(10), + move |_, _| { *(retire_closure_has_run_inner.lock().unwrap()) = true; true } + ); subject.insert(42u32, "Hello"); thread::sleep(Duration::from_millis(20)); let result = subject.get(&42u32); assert_eq!(result, None); + assert_eq!(*retire_closure_has_run.lock().unwrap(), true); + } + + #[test] + fn ttl_hashmap_get_does_not_remove_expired_entry_if_closure_returns_false() { + let retire_closure_has_run = Arc::new(Mutex::new(false)); + let retire_closure_has_run_inner = retire_closure_has_run.clone(); + let mut subject = TtlHashMap::new_with_retire( + Duration::from_millis(10), + move |_, _| { *(retire_closure_has_run_inner.lock().unwrap()) = true; false } + ); + subject.insert(42u32, "Hello"); + thread::sleep(Duration::from_millis(20)); + + let result = subject.get(&42u32); + + assert_eq!(result, Some(Rc::new("Hello"))); + assert_eq!(*retire_closure_has_run.lock().unwrap(), true); } #[test] fn ttl_hashmap_insert_removes_expired_entry() { - let mut subject = TtlHashMap::new(Duration::from_millis(10)); + let retire_closure_has_run = Arc::new(Mutex::new(false)); + let retire_closure_has_run_inner = retire_closure_has_run.clone(); + let mut subject = TtlHashMap::new_with_retire( + Duration::from_millis(10), + move |_, _| { *(retire_closure_has_run_inner.lock().unwrap()) = true; true } + ); subject.insert(42u32, "Hello"); thread::sleep(Duration::from_millis(20)); @@ -179,6 +236,7 @@ mod tests { subject.data.borrow().get(&24u32).unwrap().0.as_ref(), &"World" ); + assert_eq!(*retire_closure_has_run.lock().unwrap(), true); } #[test] From 70049a9a909bba7cb73dba03bf96bf7d41031867 Mon Sep 17 00:00:00 2001 From: Dan Wiebe Date: Tue, 26 Aug 2025 00:08:14 -0400 Subject: [PATCH 07/21] Formatting --- node/src/proxy_server/mod.rs | 12 ++++++++--- node/src/sub_lib/ttl_hashmap.rs | 38 ++++++++++++++++----------------- 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/node/src/proxy_server/mod.rs b/node/src/proxy_server/mod.rs index 7435610da1..23e50fb130 100644 --- a/node/src/proxy_server/mod.rs +++ b/node/src/proxy_server/mod.rs @@ -288,7 +288,10 @@ impl ProxyServer { route_ids_to_return_routes_stragglers: TtlHashMap::new_with_retire( RETURN_ROUTE_TTL_STRAGGLERS, move |k, _| { - debug!(hm_logger,"Return route info {} expired from straggler cache", *k); + debug!( + hm_logger, + "Return route info {} expired from straggler cache", *k + ); true }, ), @@ -984,9 +987,12 @@ impl ProxyServer { .get(&return_route_id) { Some(rri) => { - debug!(self.logger, "Return route info {} found in straggler cache", return_route_id); + debug!( + self.logger, + "Return route info {} found in straggler cache", return_route_id + ); Some(rri) - }, + } None => { error!(self.logger, "Can't report services consumed: received response with bogus return-route ID {} for {}. Ignoring", return_route_id, source); None diff --git a/node/src/sub_lib/ttl_hashmap.rs b/node/src/sub_lib/ttl_hashmap.rs index 6d5d404f24..2a519c1e21 100644 --- a/node/src/sub_lib/ttl_hashmap.rs +++ b/node/src/sub_lib/ttl_hashmap.rs @@ -15,7 +15,7 @@ where last_check: RefCell, data: RefCell, Instant)>>, ttl: Duration, - retire_closure: Box bool> + retire_closure: Box bool>, } impl TtlHashMap @@ -101,7 +101,7 @@ where data.insert(key.clone(), (value, now)); } } - None => ()// already removed + None => (), // already removed } }); } @@ -109,8 +109,8 @@ where #[cfg(test)] mod tests { - use std::sync::{Arc, Mutex}; use super::*; + use std::sync::{Arc, Mutex}; use std::thread; #[test] @@ -170,10 +170,10 @@ mod tests { fn ttl_hashmap_does_not_remove_entry_before_it_is_expired() { let retire_closure_has_run = Arc::new(Mutex::new(false)); let retire_closure_has_run_inner = retire_closure_has_run.clone(); - let mut subject = TtlHashMap::new_with_retire( - Duration::from_millis(10), - move |_, _| { *(retire_closure_has_run_inner.lock().unwrap()) = true; true } - ); + let mut subject = TtlHashMap::new_with_retire(Duration::from_millis(10), move |_, _| { + *(retire_closure_has_run_inner.lock().unwrap()) = true; + true + }); subject.insert(42u32, "Hello"); subject.insert(24u32, "World"); @@ -188,10 +188,10 @@ mod tests { fn ttl_hashmap_get_removes_expired_entry() { let retire_closure_has_run = Arc::new(Mutex::new(false)); let retire_closure_has_run_inner = retire_closure_has_run.clone(); - let mut subject = TtlHashMap::new_with_retire( - Duration::from_millis(10), - move |_, _| { *(retire_closure_has_run_inner.lock().unwrap()) = true; true } - ); + let mut subject = TtlHashMap::new_with_retire(Duration::from_millis(10), move |_, _| { + *(retire_closure_has_run_inner.lock().unwrap()) = true; + true + }); subject.insert(42u32, "Hello"); thread::sleep(Duration::from_millis(20)); @@ -205,10 +205,10 @@ mod tests { fn ttl_hashmap_get_does_not_remove_expired_entry_if_closure_returns_false() { let retire_closure_has_run = Arc::new(Mutex::new(false)); let retire_closure_has_run_inner = retire_closure_has_run.clone(); - let mut subject = TtlHashMap::new_with_retire( - Duration::from_millis(10), - move |_, _| { *(retire_closure_has_run_inner.lock().unwrap()) = true; false } - ); + let mut subject = TtlHashMap::new_with_retire(Duration::from_millis(10), move |_, _| { + *(retire_closure_has_run_inner.lock().unwrap()) = true; + false + }); subject.insert(42u32, "Hello"); thread::sleep(Duration::from_millis(20)); @@ -222,10 +222,10 @@ mod tests { fn ttl_hashmap_insert_removes_expired_entry() { let retire_closure_has_run = Arc::new(Mutex::new(false)); let retire_closure_has_run_inner = retire_closure_has_run.clone(); - let mut subject = TtlHashMap::new_with_retire( - Duration::from_millis(10), - move |_, _| { *(retire_closure_has_run_inner.lock().unwrap()) = true; true } - ); + let mut subject = TtlHashMap::new_with_retire(Duration::from_millis(10), move |_, _| { + *(retire_closure_has_run_inner.lock().unwrap()) = true; + true + }); subject.insert(42u32, "Hello"); thread::sleep(Duration::from_millis(20)); From 30f832bdbf694e44f296a17a59c6b506f7ac13eb Mon Sep 17 00:00:00 2001 From: Dan Wiebe Date: Tue, 26 Aug 2025 07:20:48 -0400 Subject: [PATCH 08/21] Clippy --- node/src/sub_lib/ttl_hashmap.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/node/src/sub_lib/ttl_hashmap.rs b/node/src/sub_lib/ttl_hashmap.rs index 2a519c1e21..1c32dea0d7 100644 --- a/node/src/sub_lib/ttl_hashmap.rs +++ b/node/src/sub_lib/ttl_hashmap.rs @@ -8,6 +8,7 @@ use std::rc::Rc; use std::time::Duration; use std::time::Instant; +#[allow(clippy::type_complexity)] pub struct TtlHashMap where K: Hash + Clone, From 7c3fa52c431200aef7e7aad36af21602ce3a198b Mon Sep 17 00:00:00 2001 From: Dan Wiebe Date: Wed, 27 Aug 2025 07:11:45 -0400 Subject: [PATCH 09/21] Made RRI logs more consistent and increased straggler timeout to 30s --- node/src/proxy_server/mod.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/node/src/proxy_server/mod.rs b/node/src/proxy_server/mod.rs index 23e50fb130..05c4b9b95e 100644 --- a/node/src/proxy_server/mod.rs +++ b/node/src/proxy_server/mod.rs @@ -59,7 +59,7 @@ use tokio::prelude::Future; pub const CRASH_KEY: &str = "PROXYSERVER"; pub const RETURN_ROUTE_TTL_FIRST_CHANCE: Duration = Duration::from_secs(120); -pub const RETURN_ROUTE_TTL_STRAGGLERS: Duration = Duration::from_secs(5); +pub const RETURN_ROUTE_TTL_STRAGGLERS: Duration = Duration::from_secs(30); pub const STREAM_KEY_PURGE_DELAY: Duration = Duration::from_secs(30); @@ -290,7 +290,7 @@ impl ProxyServer { move |k, _| { debug!( hm_logger, - "Return route info {} expired from straggler cache", *k + "Return route info RRI{} expired from straggler cache", *k ); true }, @@ -763,7 +763,7 @@ impl ProxyServer { }; debug!( args.logger, - "Adding expectant return route info: {:?}", return_route_info + "Adding expectant return route info: RRI{:?}", return_route_info ); add_return_route_sub .try_send(return_route_info) @@ -979,7 +979,7 @@ impl ProxyServer { Some(rri) => { self.route_ids_to_return_routes_stragglers .insert(return_route_id, (*rri).clone()); - debug!(self.logger, "Return route info {} found in first-chance cache; graduated to straggler cache", return_route_id); + debug!(self.logger, "Return route info RRI{} found in first-chance cache; graduated to straggler cache", return_route_id); Some(rri) } None => match self @@ -989,12 +989,12 @@ impl ProxyServer { Some(rri) => { debug!( self.logger, - "Return route info {} found in straggler cache", return_route_id + "Return route info RRI{} found in straggler cache", return_route_id ); Some(rri) } None => { - error!(self.logger, "Can't report services consumed: received response with bogus return-route ID {} for {}. Ignoring", return_route_id, source); + error!(self.logger, "Can't report services consumed: received response with bogus return-route ID RRI{} for {}. Ignoring", return_route_id, source); None } }, @@ -1687,7 +1687,7 @@ mod tests { assert!( result.is_none(), - "Expected no return route info, but got: {:?}", + "Expected no return route info, but got: RRI{:?}", result ); } From f9cab9a822ed9e33a9a8ae2a220d81f388b81cf4 Mon Sep 17 00:00:00 2001 From: Dan Wiebe Date: Thu, 28 Aug 2025 08:02:13 -0400 Subject: [PATCH 10/21] Typo corrections --- node/src/proxy_server/mod.rs | 3 ++- node/src/sub_lib/http_packet_framer.rs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/node/src/proxy_server/mod.rs b/node/src/proxy_server/mod.rs index 05c4b9b95e..6c775ef27f 100644 --- a/node/src/proxy_server/mod.rs +++ b/node/src/proxy_server/mod.rs @@ -146,6 +146,7 @@ impl Handler for ProxyServer { fn handle(&mut self, msg: AddReturnRouteMessage, _ctx: &mut Self::Context) -> Self::Result { self.route_ids_to_return_routes_first_chance .insert(msg.return_route_id, msg); + debug!(self.logger,"Added return route info RRI{} to first-chance cache",msg.return_route_id); } } @@ -1210,7 +1211,7 @@ impl IBCDHelper for IBCDHelperReal { } let args = TransmitToHopperArgs::new(proxy, payload, client_addr, timestamp, retire_stream_key); - let add_return_route_sub = proxy.out_subs("ProxysServer").add_return_route.clone(); + let add_return_route_sub = proxy.out_subs("ProxyServer").add_return_route.clone(); let pld = &args.payload; if let Some(route_query_response) = proxy.stream_key_routes.get(&pld.stream_key) { debug!( diff --git a/node/src/sub_lib/http_packet_framer.rs b/node/src/sub_lib/http_packet_framer.rs index 29685f46b9..28d4f895f2 100644 --- a/node/src/sub_lib/http_packet_framer.rs +++ b/node/src/sub_lib/http_packet_framer.rs @@ -104,7 +104,7 @@ impl HttpPacketFramer { lines: Vec::new(), }, start_finder, - logger: Logger::new("HttpRequestFramer"), + logger: Logger::new("HttpPacketFramer"), } } From 5a89e1a86cf4b2f62588a264c22dd95f563e107b Mon Sep 17 00:00:00 2001 From: Dan Wiebe Date: Sun, 31 Aug 2025 20:24:50 -0400 Subject: [PATCH 11/21] Interim commit --- node/src/hopper/live_cores_package.rs | 2 +- node/src/neighborhood/mod.rs | 75 +++------------------------ node/src/proxy_server/mod.rs | 72 ++++++++++++------------- node/src/sub_lib/neighborhood.rs | 2 +- node/src/sub_lib/route.rs | 41 +++++++-------- node/src/test_utils/mod.rs | 6 +-- 6 files changed, 63 insertions(+), 135 deletions(-) diff --git a/node/src/hopper/live_cores_package.rs b/node/src/hopper/live_cores_package.rs index 9ec2106788..113a00ea67 100644 --- a/node/src/hopper/live_cores_package.rs +++ b/node/src/hopper/live_cores_package.rs @@ -310,10 +310,10 @@ mod tests { ), cryptde, Some(paying_wallet.clone()), - 1234, Some(contract_address), ) .unwrap(); + let mut route = route.set_return_route_id(cryptde, 1234); route.shift(&relay_cryptde).unwrap(); let subject = LiveCoresPackage::new(route.clone(), encrypted_payload.clone()); diff --git a/node/src/neighborhood/mod.rs b/node/src/neighborhood/mod.rs index bb85ea8baa..72e30ed064 100644 --- a/node/src/neighborhood/mod.rs +++ b/node/src/neighborhood/mod.rs @@ -980,7 +980,6 @@ impl Neighborhood { } fn zero_hop_route_response(&mut self) -> RouteQueryResponse { - let return_route_id = self.advance_return_route_id(); let route = Route::round_trip( RouteSegment::new( vec![self.cryptde.public_key(), self.cryptde.public_key()], @@ -992,7 +991,6 @@ impl Neighborhood { ), self.cryptde, None, - return_route_id, None, ) .expect("Couldn't create route"); @@ -1001,7 +999,6 @@ impl Neighborhood { expected_services: ExpectedServices::RoundTrip( vec![ExpectedService::Nothing, ExpectedService::Nothing], vec![ExpectedService::Nothing, ExpectedService::Nothing], - return_route_id, ), } } @@ -1067,21 +1064,18 @@ impl Neighborhood { Err(e) => return Err(e), }; - let return_route_id = self.advance_return_route_id(); Ok(RouteQueryResponse { route: Route::round_trip( over, back, self.cryptde, self.consuming_wallet_opt.clone(), - return_route_id, Some(self.chain.rec().contract), ) .expect("Internal error: bad route"), expected_services: ExpectedServices::RoundTrip( expected_request_services, expected_response_services, - return_route_id, ), }) } @@ -1324,6 +1318,7 @@ impl Neighborhood { } fn advance_return_route_id(&mut self) -> u32 { + todo!("Move this logic into the ProxyServer"); let return_route_id = self.next_return_route_id; self.next_return_route_id = return_route_id.wrapping_add(1); return_route_id @@ -3382,10 +3377,10 @@ mod tests { ), cryptde, None, - 0, None, ) - .unwrap(), + .unwrap() + .set_return_route_id(cryptde, 0), expected_services: ExpectedServices::RoundTrip( vec![ ExpectedService::Nothing, @@ -3403,7 +3398,6 @@ mod tests { ), ExpectedService::Nothing, ], - 0, ), }; assert_eq!(expected_response, result); @@ -3455,39 +3449,18 @@ mod tests { ), cryptde, None, - 0, None, ) - .unwrap(), + .unwrap() + .set_return_route_id(cryptde, 0), expected_services: ExpectedServices::RoundTrip( vec![ExpectedService::Nothing, ExpectedService::Nothing], vec![ExpectedService::Nothing, ExpectedService::Nothing], - 0, ), }; assert_eq!(result, expected_response); } - #[test] - fn zero_hop_routing_handles_return_route_id_properly() { - let mut subject = make_standard_subject(); - let result0 = subject.zero_hop_route_response(); - let result1 = subject.zero_hop_route_response(); - - let return_route_id_0 = match result0.expected_services { - ExpectedServices::RoundTrip(_, _, id) => id, - _ => panic!("expected RoundTrip got OneWay"), - }; - - let return_route_id_1 = match result1.expected_services { - ExpectedServices::RoundTrip(_, _, id) => id, - _ => panic!("expected RoundTrip got OneWay"), - }; - - assert_eq!(return_route_id_0, 0); - assert_eq!(return_route_id_1, 1); - } - /* Database: @@ -3546,10 +3519,10 @@ mod tests { segment(&[r, q, p], &Component::ProxyServer), cryptde, consuming_wallet_opt, - 0, Some(contract_address), ) - .unwrap(), + .unwrap() + .set_return_route_id(cryptde, 0), expected_services: ExpectedServices::RoundTrip( vec![ ExpectedService::Nothing, @@ -3577,7 +3550,6 @@ mod tests { ), ExpectedService::Nothing, ], - 0, ), }; assert_eq!(expected_response, result); @@ -3619,37 +3591,6 @@ mod tests { Tests will be written from the viewpoint of O. */ - #[test] - fn return_route_ids_increase() { - let cryptde = main_cryptde(); - let system = System::new("return_route_ids_increase"); - let (_, _, _, mut subject) = make_o_r_e_subject(); - subject.min_hops = Hops::TwoHops; - let addr: Addr = subject.start(); - let sub: Recipient = addr.recipient::(); - - let data_route_0 = sub.send(RouteQueryMessage::data_indefinite_route_request(None, 2000)); - let data_route_1 = sub.send(RouteQueryMessage::data_indefinite_route_request(None, 3000)); - - System::current().stop_with_code(0); - system.run(); - let result_0 = data_route_0.wait().unwrap().unwrap(); - let result_1 = data_route_1.wait().unwrap().unwrap(); - let juicy_parts = |result: RouteQueryResponse| { - let last_element = result.route.hops.last().unwrap(); - let last_element_dec = cryptde.decode(last_element).unwrap(); - let network_return_route_id: u32 = - serde_cbor::de::from_slice(last_element_dec.as_slice()).unwrap(); - let metadata_return_route_id = match result.expected_services { - ExpectedServices::RoundTrip(_, _, id) => id, - _ => panic!("expected RoundTrip got OneWay"), - }; - (network_return_route_id, metadata_return_route_id) - }; - assert_eq!(juicy_parts(result_0), (0, 0)); - assert_eq!(juicy_parts(result_1), (1, 1)); - } - #[test] fn handle_neighborhood_graph_message_works() { let test_name = "handle_neighborhood_graph_message_works"; @@ -7169,7 +7110,7 @@ mod tests { let (over, back) = match response.expected_services { ExpectedServices::OneWay(_) => panic!("Expecting RoundTrip"), - ExpectedServices::RoundTrip(o, b, _) => (o[1].clone(), b[1].clone()), + ExpectedServices::RoundTrip(o, b) => (o[1].clone(), b[1].clone()), }; let extract_key = |es: ExpectedService| match es { ExpectedService::Routing(pk, _, _) => pk, diff --git a/node/src/proxy_server/mod.rs b/node/src/proxy_server/mod.rs index 6c775ef27f..95ad79f466 100644 --- a/node/src/proxy_server/mod.rs +++ b/node/src/proxy_server/mod.rs @@ -7,6 +7,7 @@ pub mod server_impersonator_http; pub mod server_impersonator_tls; pub mod tls_protocol_pack; +use std::cell::Cell; use crate::proxy_server::client_request_payload_factory::{ ClientRequestPayloadFactory, ClientRequestPayloadFactoryReal, }; @@ -59,7 +60,7 @@ use tokio::prelude::Future; pub const CRASH_KEY: &str = "PROXYSERVER"; pub const RETURN_ROUTE_TTL_FIRST_CHANCE: Duration = Duration::from_secs(120); -pub const RETURN_ROUTE_TTL_STRAGGLERS: Duration = Duration::from_secs(30); +pub const RETURN_ROUTE_TTL_STRAGGLERS: Duration = Duration::from_secs(5); pub const STREAM_KEY_PURGE_DELAY: Duration = Duration::from_secs(30); @@ -98,6 +99,7 @@ pub struct ProxyServer { browser_proxy_sequence_offset: bool, inbound_client_data_helper_opt: Option>, stream_key_purge_delay: Duration, + next_return_route_id: Cell, is_running_in_integration_test: bool, } @@ -144,9 +146,10 @@ impl Handler for ProxyServer { type Result = (); fn handle(&mut self, msg: AddReturnRouteMessage, _ctx: &mut Self::Context) -> Self::Result { + let return_route_id = msg.return_route_id; self.route_ids_to_return_routes_first_chance .insert(msg.return_route_id, msg); - debug!(self.logger,"Added return route info RRI{} to first-chance cache",msg.return_route_id); + debug!(self.logger,"Added return route info RRI{} to first-chance cache", return_route_id); } } @@ -299,6 +302,7 @@ impl ProxyServer { browser_proxy_sequence_offset: false, inbound_client_data_helper_opt: Some(Box::new(IBCDHelperReal::new())), stream_key_purge_delay: STREAM_KEY_PURGE_DELAY, + next_return_route_id: Cell::new(1), is_running_in_integration_test, } } @@ -749,13 +753,21 @@ impl ProxyServer { } } + fn get_next_return_route_id(&self) -> u32 { + let return_route_id = self.next_return_route_id.get(); + *(self.next_return_route_id.get_mut()) = return_route_id.wrapping_add(1); + return_route_id + } + fn try_transmit_to_hopper( + &self, args: TransmitToHopperArgs, add_return_route_sub: Recipient, route_query_response: RouteQueryResponse, ) -> Result<(), String> { match route_query_response.expected_services { - ExpectedServices::RoundTrip(over, back, return_route_id) => { + ExpectedServices::RoundTrip(over, back) => { + let return_route_id = self.get_next_return_route_id(); let return_route_info = AddReturnRouteMessage { return_route_id, expected_services: back, @@ -959,7 +971,7 @@ impl ProxyServer { mut_remaining_route .shift(self.main_cryptde) .expect("Internal error: remaining route in ProxyServer with no hops"); - match mut_remaining_route.id(self.main_cryptde) { + match mut_remaining_route.return_route_id(self.main_cryptde) { Ok(rri) => Some(rri), Err(e) => { error!(self.logger, "Can't report services consumed: {}", e); @@ -1109,7 +1121,7 @@ impl RouteQueryResponseResolver for RouteQueryResponseResolverReal { let stream_key = args.payload.stream_key; let result = match route_result_opt { Ok(Some(route_query_response)) => { - match ProxyServer::try_transmit_to_hopper( + match self.try_transmit_to_hopper( args, add_return_route_sub, route_query_response.clone(), @@ -1768,7 +1780,6 @@ mod tests { expected_services: ExpectedServices::RoundTrip( vec![make_exit_service_from_key(destination_key.clone())], vec![], - 1234, ), })); let (proxy_server_mock, _, proxy_server_recording_arc) = make_recorder(); @@ -1872,7 +1883,6 @@ mod tests { expected_services: ExpectedServices::RoundTrip( vec![make_exit_service_from_key(destination_key.clone())], vec![], - 1234, ), })); let route = Route { hops: vec![] }; @@ -2494,7 +2504,6 @@ mod tests { expected_services: ExpectedServices::RoundTrip( vec![make_exit_service_from_key(destination_key.clone())], vec![], - 1234, ), })); let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); @@ -2594,10 +2603,10 @@ mod tests { ), main_cryptde, Some(consuming_wallet), - 1234, Some(TEST_DEFAULT_CHAIN.rec().contract), ) - .unwrap(); + .unwrap() + .set_return_route_id(main_cryptde, 1234); let (neighborhood_mock, _, neighborhood_recording_arc) = make_recorder(); let neighborhood_mock = neighborhood_mock.route_query_response(Some(RouteQueryResponse { route: route.clone(), @@ -2614,7 +2623,6 @@ mod tests { ExpectedService::Nothing, ExpectedService::Exit(PublicKey::new(&[3]), earning_wallet, rate_pack(102)), ], - 1234, ), })); let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); @@ -2700,7 +2708,6 @@ mod tests { expected_services: ExpectedServices::RoundTrip( vec![expected_service.clone()], vec![expected_service], - 123, ), }); let (neighborhood_mock, _, _) = make_recorder(); @@ -2869,7 +2876,6 @@ mod tests { expected_services: ExpectedServices::RoundTrip( vec![make_exit_service_from_key(destination_key.clone())], vec![], - 1234, ), }; let (hopper_mock, hopper_awaiter, hopper_recording_arc) = make_recorder(); @@ -2988,7 +2994,6 @@ mod tests { ), ExpectedService::Nothing, ], - 0, ), }; let source_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); @@ -3079,7 +3084,6 @@ mod tests { expected_services: ExpectedServices::RoundTrip( vec![ExpectedService::Nothing], vec![ExpectedService::Nothing], - 0, ), }; let source_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); @@ -3161,7 +3165,6 @@ mod tests { rate_pack(3), )], vec![], - 0, ); let neighborhood_mock = neighborhood_mock.route_query_response(Some(route_query_response.clone())); @@ -3458,11 +3461,11 @@ mod tests { RouteSegment::new(vec![public_key, public_key], Component::ProxyServer), cryptde, None, - 1234, None, ) - .unwrap(), - expected_services: ExpectedServices::RoundTrip(vec![], vec![], 1234), + .unwrap() + .set_return_route_id(cryptde, 1234), + expected_services: ExpectedServices::RoundTrip(vec![], vec![]), }; let neighborhood_mock = neighborhood_mock.route_query_response(Some(route_query_response)); let dispatcher = Recorder::new(); @@ -3560,7 +3563,6 @@ mod tests { expected_services: ExpectedServices::RoundTrip( vec![make_exit_service_from_key(destination_key.clone())], vec![], - 1234, ), })); let stream_key = StreamKey::make_meaningless_stream_key(); @@ -3646,7 +3648,6 @@ mod tests { expected_services: ExpectedServices::RoundTrip( vec![make_exit_service_from_key(destination_key.clone())], vec![], - 1234, ), })); let stream_key = StreamKey::make_meaningless_stream_key(); @@ -3731,7 +3732,6 @@ mod tests { expected_services: ExpectedServices::RoundTrip( vec![make_exit_service_from_key(destination_key.clone())], vec![], - 1234, ), })); let client_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); @@ -3985,7 +3985,7 @@ mod tests { stream_key.clone(), RouteQueryResponse { route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip(vec![], vec![], 1234), + expected_services: ExpectedServices::RoundTrip(vec![], vec![]), }, ); subject @@ -4103,7 +4103,7 @@ mod tests { stream_key.clone(), RouteQueryResponse { route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip(vec![], vec![], 1234), + expected_services: ExpectedServices::RoundTrip(vec![], vec![]), }, ); subject @@ -4206,7 +4206,7 @@ mod tests { stream_key.clone(), RouteQueryResponse { route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip(vec![], vec![], 1234), + expected_services: ExpectedServices::RoundTrip(vec![], vec![]), }, ); subject @@ -5370,7 +5370,6 @@ mod tests { expected_services: ExpectedServices::RoundTrip( expected_services.clone(), expected_services.clone(), - 1234, ), }; let neighborhood_mock = neighborhood_mock @@ -5540,7 +5539,6 @@ mod tests { expected_services: ExpectedServices::RoundTrip( expected_services.clone(), expected_services.clone(), - 1234, ), }; let neighborhood_mock = neighborhood_mock @@ -5904,7 +5902,7 @@ mod tests { unaffected_stream_key, RouteQueryResponse { route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip(vec![], vec![], 1234), + expected_services: ExpectedServices::RoundTrip(vec![], vec![]), }, ); subject @@ -5957,7 +5955,7 @@ mod tests { unaffected_stream_key, RouteQueryResponse { route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip(vec![], vec![], 1234), + expected_services: ExpectedServices::RoundTrip(vec![], vec![]), }, ); let affected_route = Route::round_trip( @@ -5971,10 +5969,10 @@ mod tests { ), main_cryptde(), Some(make_paying_wallet(b"consuming")), - 1234, Some(TEST_DEFAULT_CHAIN.rec().contract), ) - .unwrap(); + .unwrap() + .set_return_route_id(main_cryptde(), 1234); let affected_expected_services = vec![ExpectedService::Exit( affected_cryptde.public_key().clone(), make_paying_wallet(b"1234"), @@ -5987,7 +5985,6 @@ mod tests { expected_services: ExpectedServices::RoundTrip( affected_expected_services, vec![], - 1234, ), }, ); @@ -6082,7 +6079,7 @@ mod tests { unaffected_stream_key, RouteQueryResponse { route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip(vec![], vec![], 1234), + expected_services: ExpectedServices::RoundTrip(vec![], vec![]), }, ); let affected_route = Route::round_trip( @@ -6096,10 +6093,10 @@ mod tests { ), main_cryptde(), Some(make_paying_wallet(b"consuming")), - 1234, Some(TEST_DEFAULT_CHAIN.rec().contract), ) - .unwrap(); + .unwrap() + .set_return_route_id(main_cryptde(), 1234); let affected_expected_services = vec![ExpectedService::Exit( affected_cryptde.public_key().clone(), make_paying_wallet(b"1234"), @@ -6112,7 +6109,6 @@ mod tests { expected_services: ExpectedServices::RoundTrip( affected_expected_services, vec![], - 1234, ), }, ); @@ -6221,7 +6217,7 @@ mod tests { stream_key, RouteQueryResponse { route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip(vec![], vec![], 0), + expected_services: ExpectedServices::RoundTrip(vec![], vec![]), }, ); subject @@ -6395,7 +6391,6 @@ mod tests { expected_services: ExpectedServices::RoundTrip( vec![make_exit_service_from_key(destination_key.clone())], vec![], - 1234, ), })); let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); @@ -6464,7 +6459,6 @@ mod tests { expected_services: ExpectedServices::RoundTrip( vec![make_exit_service_from_key(destination_key.clone())], vec![], - 1234, ), })); let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); diff --git a/node/src/sub_lib/neighborhood.rs b/node/src/sub_lib/neighborhood.rs index 79623cda3b..f8e93f951c 100644 --- a/node/src/sub_lib/neighborhood.rs +++ b/node/src/sub_lib/neighborhood.rs @@ -505,7 +505,7 @@ pub enum ExpectedService { #[derive(Clone, Debug, PartialEq, Eq)] pub enum ExpectedServices { OneWay(Vec), - RoundTrip(Vec, Vec, u32), + RoundTrip(Vec, Vec), } #[derive(Clone, Debug, PartialEq, Eq)] diff --git a/node/src/sub_lib/route.rs b/node/src/sub_lib/route.rs index ecbd0261ed..83ebc03d86 100644 --- a/node/src/sub_lib/route.rs +++ b/node/src/sub_lib/route.rs @@ -32,7 +32,6 @@ impl Route { cryptde, None, None, - None, ) } @@ -47,7 +46,6 @@ impl Route { None, cryptde, consuming_wallet, - None, contract_address, ) } @@ -57,7 +55,6 @@ impl Route { route_segment_back: RouteSegment, cryptde: &dyn CryptDE, // Must be the CryptDE of the originating Node: used to encrypt return_route_id. consuming_wallet: Option, - return_route_id: u32, contract_address: Option
, ) -> Result { Self::construct( @@ -65,12 +62,11 @@ impl Route { Some(route_segment_back), cryptde, consuming_wallet, - Some(return_route_id), contract_address, ) } - pub fn id(&self, cryptde: &dyn CryptDE) -> Result { + pub fn return_route_id(&self, cryptde: &dyn CryptDE) -> Result { if let Some(first) = self.hops.first() { match decodex(cryptde, first) { Ok(n) => Ok(n), @@ -81,6 +77,12 @@ impl Route { } } + pub fn set_return_route_id(mut self, cryptde: &dyn CryptDE, return_route_id: u32) -> Self { + let return_route_id_enc = Self::encrypt_return_route_id(return_route_id, cryptde); + self.hops.push(return_route_id_enc); + self + } + // This cryptde must be the CryptDE of the next hop to come off the Route. pub fn next_hop(&self, cryptde: &dyn CryptDE) -> Result { match self.hops.first() { @@ -148,7 +150,6 @@ impl Route { back: Option, cryptde: &dyn CryptDE, consuming_wallet: Option, - return_route_id_opt: Option, contract_address: Option
, ) -> Result { if let Some(error) = Route::validate_route_segments(&over, &back) { @@ -176,7 +177,6 @@ impl Route { Route::hops_to_route( hops[0..].to_vec(), &over.keys[0], - return_route_id_opt, cryptde, ) } @@ -295,7 +295,6 @@ impl Route { fn hops_to_route( hops: Vec, top_hop_key: &PublicKey, - return_route_id_opt: Option, cryptde: &dyn CryptDE, ) -> Result { let mut hops_enc: Vec = Vec::new(); @@ -307,10 +306,6 @@ impl Route { }); hop_key = &data_hop.public_key; } - if let Some(return_route_id) = return_route_id_opt { - let return_route_id_enc = Self::encrypt_return_route_id(return_route_id, cryptde); - hops_enc.push(return_route_id_enc); - } Ok(Route { hops: hops_enc }) } @@ -353,38 +348,38 @@ mod tests { use serde_cbor; #[test] - fn id_decodes_return_route_id() { + fn return_route_id_works() { let cryptde = main_cryptde(); let subject = Route { hops: vec![Route::encrypt_return_route_id(42, cryptde)], }; - assert_eq!(subject.id(cryptde), Ok(42)); + assert_eq!(subject.return_route_id(cryptde), Ok(42)); } #[test] - fn id_returns_empty_route_error_when_the_route_is_empty() { + fn return_route_id_returns_empty_route_error_when_the_route_is_empty() { let cryptde = main_cryptde(); let subject = Route { hops: vec![] }; assert_eq!( - subject.id(cryptde), + subject.return_route_id(cryptde), Err("Response route did not contain a return route ID".to_string()) ); } #[test] #[should_panic(expected = "Could not decrypt with ebe5f9a0e2 data beginning with ebe5f9a0e1")] - fn id_returns_error_when_the_id_fails_to_decrypt() { + fn return_route_id_returns_error_when_the_id_fails_to_decrypt() { let cryptde1 = CryptDENull::from(&PublicKey::new(b"key a"), TEST_DEFAULT_CHAIN); let cryptde2 = CryptDENull::from(&PublicKey::new(b"key b"), TEST_DEFAULT_CHAIN); let subject = Route { hops: vec![Route::encrypt_return_route_id(42, &cryptde1)], }; - let _ = subject.id(&cryptde2); + let _ = subject.return_route_id(&cryptde2); } #[test] @@ -420,7 +415,6 @@ mod tests { RouteSegment::new(vec![&c_key, &d_key], Component::ProxyServer), cryptde, Some(paying_wallet.clone()), - 0, Some(TEST_DEFAULT_CHAIN.rec().contract), ) .err() @@ -472,10 +466,10 @@ mod tests { RouteSegment::new(vec![&d_key, &e_key, &f_key, &a_key], Component::ProxyServer), cryptde, Some(paying_wallet.clone()), - return_route_id, Some(contract_address.clone()), ) .unwrap(); + let subject = subject.set_return_route_id(cryptde, return_route_id); assert_eq!( subject.hops[0], @@ -745,10 +739,10 @@ mod tests { RouteSegment::new(vec![&key2, &key1], Component::ProxyServer), cryptde, Some(paying_wallet), - 1234, Some(TEST_DEFAULT_CHAIN.rec().contract), ) .unwrap(); + let original = original.set_return_route_id(cryptde, 1234); let serialized = serde_cbor::ser::to_vec(&original).unwrap(); @@ -794,16 +788,17 @@ Encrypted with 0x03040506: LiveHop { public_key: 0x, payer: Some(Payer { wallet: let key1 = PublicKey::new(&[1, 2, 3, 4]); let key2 = PublicKey::new(&[2, 3, 4, 5]); let key3 = PublicKey::new(&[3, 4, 5, 6]); + let cryptde = CryptDENull::from(&key1, TEST_DEFAULT_CHAIN); let paying_wallet = make_paying_wallet(b"wallet"); let subject = Route::round_trip( RouteSegment::new(vec![&key1, &key2, &key3], Component::ProxyClient), RouteSegment::new(vec![&key3, &key2, &key1], Component::ProxyServer), - &CryptDENull::from(&key1, TEST_DEFAULT_CHAIN), + &cryptde, Some(paying_wallet), - 1234, Some(TEST_DEFAULT_CHAIN.rec().contract), ) .unwrap(); + let subject = subject.set_return_route_id(&cryptde, 1234); let result = subject.to_string(vec![ &CryptDENull::from(&key1, TEST_DEFAULT_CHAIN), diff --git a/node/src/test_utils/mod.rs b/node/src/test_utils/mod.rs index 595bf36993..1589ea5cca 100644 --- a/node/src/test_utils/mod.rs +++ b/node/src/test_utils/mod.rs @@ -240,14 +240,13 @@ pub fn zero_hop_route_response( RouteSegment::new(vec![public_key, public_key], Component::ProxyServer), cryptde, None, - 0, None, ) - .unwrap(), + .unwrap() + .set_return_route_id(cryptde, 0), expected_services: ExpectedServices::RoundTrip( vec![ExpectedService::Nothing, ExpectedService::Nothing], vec![ExpectedService::Nothing, ExpectedService::Nothing], - 0, ), } } @@ -1268,7 +1267,6 @@ mod tests { ExpectedServices::RoundTrip( vec![ExpectedService::Nothing, ExpectedService::Nothing,], vec![ExpectedService::Nothing, ExpectedService::Nothing,], - 0 ) ); } From 8f774b66b071e215508faea2cdcd5d291da4d07a Mon Sep 17 00:00:00 2001 From: Dan Wiebe Date: Fri, 5 Sep 2025 21:20:37 -0400 Subject: [PATCH 12/21] Tests pass --- node/src/hopper/live_cores_package.rs | 2 +- node/src/neighborhood/mod.rs | 68 ++------ node/src/proxy_server/mod.rs | 223 ++++++++++++++++++-------- node/src/sub_lib/route.rs | 8 +- 4 files changed, 173 insertions(+), 128 deletions(-) diff --git a/node/src/hopper/live_cores_package.rs b/node/src/hopper/live_cores_package.rs index 113a00ea67..8ed830b947 100644 --- a/node/src/hopper/live_cores_package.rs +++ b/node/src/hopper/live_cores_package.rs @@ -302,7 +302,7 @@ mod tests { let encrypted_payload = encodex(cryptde, &first_stop_key, &payload).unwrap(); let paying_wallet = make_paying_wallet(b"wallet"); let contract_address = TEST_DEFAULT_CHAIN.rec().contract; - let mut route = Route::round_trip( + let route = Route::round_trip( RouteSegment::new(vec![&relay_key, &first_stop_key], Component::Neighborhood), RouteSegment::new( vec![&first_stop_key, &relay_key, &second_stop_key], diff --git a/node/src/neighborhood/mod.rs b/node/src/neighborhood/mod.rs index 72e30ed064..f81911c0c7 100644 --- a/node/src/neighborhood/mod.rs +++ b/node/src/neighborhood/mod.rs @@ -105,7 +105,6 @@ pub struct Neighborhood { mode: NeighborhoodModeLight, min_hops: Hops, db_patch_size: u8, - next_return_route_id: u32, overall_connection_status: OverallConnectionStatus, chain: Chain, crashable: bool, @@ -431,7 +430,6 @@ impl Neighborhood { mode, min_hops, db_patch_size, - next_return_route_id: 0, overall_connection_status, chain: config.blockchain_bridge_config.chain, crashable: config.crash_point == CrashPoint::Message, @@ -1317,13 +1315,6 @@ impl Neighborhood { } } - fn advance_return_route_id(&mut self) -> u32 { - todo!("Move this logic into the ProxyServer"); - let return_route_id = self.next_return_route_id; - self.next_return_route_id = return_route_id.wrapping_add(1); - return_route_id - } - pub fn find_exit_locations<'a>( &'a self, source: &'a PublicKey, @@ -3379,8 +3370,7 @@ mod tests { None, None, ) - .unwrap() - .set_return_route_id(cryptde, 0), + .unwrap(), expected_services: ExpectedServices::RoundTrip( vec![ ExpectedService::Nothing, @@ -3451,8 +3441,7 @@ mod tests { None, None, ) - .unwrap() - .set_return_route_id(cryptde, 0), + .unwrap(), expected_services: ExpectedServices::RoundTrip( vec![ExpectedService::Nothing, ExpectedService::Nothing], vec![ExpectedService::Nothing, ExpectedService::Nothing], @@ -3521,8 +3510,7 @@ mod tests { consuming_wallet_opt, Some(contract_address), ) - .unwrap() - .set_return_route_id(cryptde, 0), + .unwrap(), expected_services: ExpectedServices::RoundTrip( vec![ ExpectedService::Nothing, @@ -3552,7 +3540,7 @@ mod tests { ], ), }; - assert_eq!(expected_response, result); + assert_eq!(result, expected_response); } #[test] @@ -3571,18 +3559,6 @@ mod tests { ); } - #[test] - fn next_return_route_id_wraps_around() { - let mut subject = make_standard_subject(); - subject.next_return_route_id = 0xFFFFFFFF; - - let end = subject.advance_return_route_id(); - let beginning = subject.advance_return_route_id(); - - assert_eq!(end, 0xFFFFFFFF); - assert_eq!(beginning, 0x00000000); - } - /* Database: @@ -4474,7 +4450,6 @@ mod tests { error_expectation, "Cannot make multi_hop with unknown neighbor" ); - assert_eq!(subject.next_return_route_id, 0); } #[test] @@ -6958,7 +6933,7 @@ mod tests { let hops = result.clone().unwrap().route.hops; let actual_keys: Vec = match hops.as_slice() { - [hop, exit, hop_back, origin, empty, _accounting] => vec![ + [hop, exit, hop_back, origin, empty] => vec![ decodex::(main_cryptde(), hop) .expect("hop") .public_key, @@ -6975,7 +6950,11 @@ mod tests { .expect("empty") .public_key, ], - l => panic!("our match is wrong, real size is {}, {:?}", l.len(), l), + l => panic!( + "our match is wrong, real size is {} instead of 5, {:?}", + l.len(), + l + ), }; let expected_public_keys = vec![ next_door_neighbor.public_key().clone(), @@ -7013,24 +6992,23 @@ mod tests { } }; /* - This is how the route_hops vector looks like: [C1, C2, ..., C(nodes_count), ..., C2, C1, accounting] + This is how the route_hops vector looks like: [C1, C2, ..., C(nodes_count), ..., C2, C1] Let's consider for 3-hop route ==> Nodes Count --> 4 Route Length --> 8 - Route Hops --> [C1, C2, C3, C4, C3, C2, C1, accounting] + Route Hops --> [C1, C2, C3, C4, C3, C2, C1] Over Route --> [C1, C2, C3] Back Route --> [C4, C3, C2, C1] */ - let mut route_hops = result.unwrap().route.hops; + let route_hops = result.unwrap().route.hops; let route_length = route_hops.len(); - let _accounting = route_hops.pop(); let over_route = &route_hops[..hops]; let back_route = &route_hops[hops..]; let over_cryptdes = cryptdes_from_node_records(&nodes[..hops]); let mut back_cryptdes = cryptdes_from_node_records(&nodes); back_cryptdes.reverse(); - assert_eq!(route_length, 2 * nodes_count); + assert_eq!(route_length, 2 * nodes_count - 1); assert_hops(over_cryptdes, over_route); assert_hops(back_cryptdes, back_route); } @@ -7504,24 +7482,6 @@ mod tests { subject } - fn make_o_r_e_subject() -> (NodeRecord, NodeRecord, NodeRecord, Neighborhood) { - let mut subject = make_standard_subject(); - let o = &subject.neighborhood_database.root().clone(); - let r = &make_node_record(4567, false); - let e = &make_node_record(5678, false); - { - let db = &mut subject.neighborhood_database; - db.add_node(r.clone()).unwrap(); - db.add_node(e.clone()).unwrap(); - let mut dual_edge = |a: &NodeRecord, b: &NodeRecord| { - db.add_arbitrary_full_neighbor(a.public_key(), b.public_key()) - }; - dual_edge(o, r); - dual_edge(r, e); - } - (o.clone(), r.clone(), e.clone(), subject) - } - fn segment(nodes: &[&NodeRecord], component: &Component) -> RouteSegment { RouteSegment::new( nodes.into_iter().map(|n| n.public_key()).collect(), diff --git a/node/src/proxy_server/mod.rs b/node/src/proxy_server/mod.rs index 95ad79f466..301ce98ec0 100644 --- a/node/src/proxy_server/mod.rs +++ b/node/src/proxy_server/mod.rs @@ -7,7 +7,6 @@ pub mod server_impersonator_http; pub mod server_impersonator_tls; pub mod tls_protocol_pack; -use std::cell::Cell; use crate::proxy_server::client_request_payload_factory::{ ClientRequestPayloadFactory, ClientRequestPayloadFactoryReal, }; @@ -51,6 +50,7 @@ use masq_lib::logger::Logger; use masq_lib::ui_gateway::NodeFromUiMessage; use masq_lib::utils::MutabilityConflictHelper; use regex::Regex; +use std::cell::Cell; use std::collections::HashMap; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}; use std::rc::Rc; @@ -149,7 +149,10 @@ impl Handler for ProxyServer { let return_route_id = msg.return_route_id; self.route_ids_to_return_routes_first_chance .insert(msg.return_route_id, msg); - debug!(self.logger,"Added return route info RRI{} to first-chance cache", return_route_id); + debug!( + self.logger, + "Added return route info RRI{} to first-chance cache", return_route_id + ); } } @@ -755,28 +758,27 @@ impl ProxyServer { fn get_next_return_route_id(&self) -> u32 { let return_route_id = self.next_return_route_id.get(); - *(self.next_return_route_id.get_mut()) = return_route_id.wrapping_add(1); + self.next_return_route_id + .set(return_route_id.wrapping_add(1)); return_route_id } fn try_transmit_to_hopper( - &self, args: TransmitToHopperArgs, add_return_route_sub: Recipient, route_query_response: RouteQueryResponse, ) -> Result<(), String> { match route_query_response.expected_services { ExpectedServices::RoundTrip(over, back) => { - let return_route_id = self.get_next_return_route_id(); let return_route_info = AddReturnRouteMessage { - return_route_id, + return_route_id: args.return_route_id, expected_services: back, protocol: args.payload.protocol, hostname_opt: args.payload.target_hostname.clone(), }; debug!( args.logger, - "Adding expectant return route info: RRI{:?}", return_route_info + "Adding expectant return route info: RRI{}", args.return_route_id ); add_return_route_sub .try_send(return_route_info) @@ -882,9 +884,11 @@ impl ProxyServer { let payload = args.payload; let payload_size = payload.sequenced_packet.data.len(); let stream_key = payload.stream_key; + let route_with_return_route_id = + route.set_return_route_id(args.main_cryptde, args.return_route_id); let pkg = IncipientCoresPackage::new( args.main_cryptde, - route, + route_with_return_route_id, payload.into(), &payload_destination_key, ) @@ -1121,7 +1125,7 @@ impl RouteQueryResponseResolver for RouteQueryResponseResolverReal { let stream_key = args.payload.stream_key; let result = match route_result_opt { Ok(Some(route_query_response)) => { - match self.try_transmit_to_hopper( + match ProxyServer::try_transmit_to_hopper( args, add_return_route_sub, route_query_response.clone(), @@ -1167,6 +1171,7 @@ impl IBCDHelperReal { } } } + impl IBCDHelper for IBCDHelperReal { fn handle_normal_client_data( &self, @@ -1290,6 +1295,7 @@ impl IBCDHelper for IBCDHelperReal { pub struct TransmitToHopperArgs { pub main_cryptde: &'static dyn CryptDE, pub payload: ClientRequestPayload_0v1, + pub return_route_id: u32, pub client_addr: SocketAddr, pub timestamp: SystemTime, pub is_decentralized: bool, @@ -1318,9 +1324,11 @@ impl TransmitToHopperArgs { } else { None }; + let return_route_id = proxy_server.get_next_return_route_id(); Self { main_cryptde: proxy_server.main_cryptde, payload, + return_route_id, client_addr, timestamp, logger: proxy_server.logger.clone(), @@ -1419,6 +1427,7 @@ impl Hostname { #[cfg(test)] mod tests { use super::*; + use crate::blockchain::bip32::Bip32EncryptionKeyProvider; use crate::match_every_type_id; use crate::proxy_server::protocol_pack::ServerImpersonator; use crate::proxy_server::server_impersonator_http::ServerImpersonatorHttp; @@ -1811,7 +1820,7 @@ mod tests { }; let expected_pkg = IncipientCoresPackage::new( main_cryptde, - route.clone(), + route.clone().set_return_route_id(main_cryptde, 1), expected_payload.into(), &destination_key, ) @@ -1928,7 +1937,7 @@ mod tests { }; let expected_pkg = IncipientCoresPackage::new( main_cryptde, - route.clone(), + route.clone().set_return_route_id(main_cryptde, 1), expected_payload.into(), &destination_key, ) @@ -2391,7 +2400,7 @@ mod tests { hopper_recording.get_record::(0), &IncipientCoresPackage::new( main_cryptde, - expected_route.route, + expected_route.route.set_return_route_id(main_cryptde, 1), MessageType::ClientRequest(VersionedData::new( &crate::sub_lib::migrations::client_request_payload::MIGRATIONS, &ClientRequestPayload_0v1 { @@ -2471,7 +2480,7 @@ mod tests { hopper_recording.get_record::(0), &IncipientCoresPackage::new( main_cryptde, - expected_route.route, + expected_route.route.set_return_route_id(main_cryptde, 1), MessageType::ClientRequest(VersionedData::new( &crate::sub_lib::migrations::client_request_payload::MIGRATIONS, &ClientRequestPayload_0v1 { @@ -2534,7 +2543,7 @@ mod tests { }; let expected_pkg = IncipientCoresPackage::new( main_cryptde, - route.clone(), + route.clone().set_return_route_id(main_cryptde, 1), expected_payload.into(), &destination_key, ) @@ -2652,7 +2661,7 @@ mod tests { }; let expected_pkg = IncipientCoresPackage::new( main_cryptde, - route.clone(), + route.clone().set_return_route_id(main_cryptde, 1), expected_payload.into(), &payload_destination_key, ) @@ -2871,8 +2880,10 @@ mod tests { let alias_cryptde = alias_cryptde(); let http_request = b"GET /index.html HTTP/1.1\r\nHost: nowhere.com\r\n\r\n"; let destination_key = PublicKey::from(&b"our destination"[..]); + let route = Route { hops: vec![] }; + let route_with_rrid = route.clone().set_return_route_id(main_cryptde, 4444); let route_query_response = RouteQueryResponse { - route: Route { hops: vec![] }, + route, expected_services: ExpectedServices::RoundTrip( vec![make_exit_service_from_key(destination_key.clone())], vec![], @@ -2905,7 +2916,7 @@ mod tests { }; let expected_pkg = IncipientCoresPackage::new( main_cryptde, - Route { hops: vec![] }, + route_with_rrid, expected_payload.into(), &destination_key, ) @@ -2926,6 +2937,7 @@ mod tests { subject .stream_key_routes .insert(stream_key, route_query_response); + subject.next_return_route_id = Cell::new(4444); let subject_addr: Addr = subject.start(); let peer_actors = peer_actors_builder().hopper(hopper_mock).build(); subject_addr.try_send(BindMessage { peer_actors }).unwrap(); @@ -2945,52 +2957,84 @@ mod tests { fn proxy_server_sends_message_to_accountant_about_all_services_consumed_on_the_route_over() { let cryptde = main_cryptde(); let now = SystemTime::now(); - let exit_earning_wallet = make_wallet("exit earning wallet"); - let route_1_earning_wallet = make_wallet("route 1 earning wallet"); - let route_2_earning_wallet = make_wallet("route 2 earning wallet"); + let routing_node_1_public_key = PublicKey::new(&[1]); + let routing_node_2_public_key = PublicKey::new(&[2]); + let exit_node_public_key = PublicKey::new(&[3]); + let key_bytes = b"__originating consuming wallet__"; + let keypair = Bip32EncryptionKeyProvider::from_raw_secret(key_bytes).unwrap(); + let originating_consuming_wallet = Wallet::from(keypair); + let routing_node_1_earning_wallet = make_wallet("route 1 earning wallet"); + let routing_node_2_earning_wallet = make_wallet("route 2 earning wallet"); + let exit_node_earning_wallet = make_wallet("exit earning wallet"); + let routing_node_1_rate_pack = rate_pack(101); + let routing_node_2_rate_pack = rate_pack(102); + let exit_node_rate_pack = rate_pack(103); let http_request = b"GET /index.html HTTP/1.1\r\nHost: nowhere.com\r\n\r\n"; let (accountant_mock, _, accountant_recording_arc) = make_recorder(); let (hopper_mock, _, hopper_recording_arc) = make_recorder(); let (proxy_server_mock, _, proxy_server_recording_arc) = make_recorder(); - let routing_node_1_rate_pack = rate_pack(101); - let routing_node_2_rate_pack = rate_pack(102); - let exit_node_rate_pack = rate_pack(103); + let over_route_segment = RouteSegment::new( + vec![ + &cryptde.public_key(), + &routing_node_1_public_key, + &routing_node_2_public_key, + &exit_node_public_key, + ], + Component::ProxyClient, + ); + let back_route_segment = RouteSegment::new( + vec![ + &exit_node_public_key, + &routing_node_2_public_key, + &routing_node_1_public_key, + &cryptde.public_key(), + ], + Component::ProxyServer, + ); + let route = Route::round_trip( + over_route_segment, + back_route_segment, + cryptde, + Some(originating_consuming_wallet), + Some(TEST_DEFAULT_CHAIN.rec().contract), + ) + .unwrap(); let route_query_response = RouteQueryResponse { - route: make_meaningless_route(), + route, expected_services: ExpectedServices::RoundTrip( vec![ ExpectedService::Nothing, ExpectedService::Routing( - PublicKey::new(&[1]), - route_1_earning_wallet.clone(), - routing_node_1_rate_pack, + routing_node_1_public_key.clone(), + routing_node_1_earning_wallet.clone(), + routing_node_1_rate_pack.clone(), ), ExpectedService::Routing( - PublicKey::new(&[2]), - route_2_earning_wallet.clone(), - routing_node_2_rate_pack, + routing_node_2_public_key.clone(), + routing_node_2_earning_wallet.clone(), + routing_node_2_rate_pack.clone(), ), ExpectedService::Exit( - PublicKey::new(&[3]), - exit_earning_wallet.clone(), - exit_node_rate_pack, + exit_node_public_key.clone(), + exit_node_earning_wallet.clone(), + exit_node_rate_pack.clone(), ), ], vec![ ExpectedService::Exit( - PublicKey::new(&[3]), - make_wallet("some wallet 1"), - rate_pack(104), + exit_node_public_key.clone(), + exit_node_earning_wallet.clone(), + exit_node_rate_pack, ), ExpectedService::Routing( - PublicKey::new(&[2]), - make_wallet("some wallet 2"), - rate_pack(105), + routing_node_2_public_key.clone(), + routing_node_2_earning_wallet.clone(), + routing_node_2_rate_pack, ), ExpectedService::Routing( - PublicKey::new(&[1]), - make_wallet("some wallet 3"), - rate_pack(106), + routing_node_1_public_key.clone(), + routing_node_1_earning_wallet.clone(), + routing_node_1_rate_pack, ), ExpectedService::Nothing, ], @@ -3019,6 +3063,7 @@ mod tests { let args = TransmitToHopperArgs { main_cryptde: cryptde, payload, + return_route_id: 4444, client_addr: source_addr, timestamp: now, is_decentralized: true, @@ -3038,8 +3083,31 @@ mod tests { System::current().stop(); system.run(); let recording = hopper_recording_arc.lock().unwrap(); - let record = recording.get_record::(0); + let mut record = recording.get_record::(0).clone(); let payload_enc_length = record.payload.len(); + let _ = record.route.shift(cryptde); + let _ = record.route.shift(&CryptDENull::from( + &routing_node_1_public_key, + TEST_DEFAULT_CHAIN, + )); + let _ = record.route.shift(&CryptDENull::from( + &routing_node_2_public_key, + TEST_DEFAULT_CHAIN, + )); + let _ = record.route.shift(&CryptDENull::from( + &exit_node_public_key, + TEST_DEFAULT_CHAIN, + )); + let _ = record.route.shift(&CryptDENull::from( + &routing_node_2_public_key, + TEST_DEFAULT_CHAIN, + )); + let _ = record.route.shift(&CryptDENull::from( + &routing_node_1_public_key, + TEST_DEFAULT_CHAIN, + )); + let _ = record.route.shift(cryptde); + assert_eq!(record.route.return_route_id(cryptde).unwrap(), 4444); let recording = accountant_recording_arc.lock().unwrap(); let record = recording.get_record::(0); assert_eq!(recording.len(), 1); @@ -3048,7 +3116,7 @@ mod tests { &ReportServicesConsumedMessage { timestamp: now, exit: ExitServiceConsumed { - earning_wallet: exit_earning_wallet, + earning_wallet: exit_node_earning_wallet, payload_size: exit_payload_size, service_rate: exit_node_rate_pack.exit_service_rate, byte_rate: exit_node_rate_pack.exit_byte_rate @@ -3056,12 +3124,12 @@ mod tests { routing_payload_size: payload_enc_length, routing: vec![ RoutingServiceConsumed { - earning_wallet: route_1_earning_wallet, + earning_wallet: routing_node_1_earning_wallet, service_rate: routing_node_1_rate_pack.routing_service_rate, byte_rate: routing_node_1_rate_pack.routing_byte_rate, }, RoutingServiceConsumed { - earning_wallet: route_2_earning_wallet, + earning_wallet: routing_node_2_earning_wallet, service_rate: routing_node_2_rate_pack.routing_service_rate, byte_rate: routing_node_2_rate_pack.routing_byte_rate, } @@ -3106,6 +3174,7 @@ mod tests { let args = TransmitToHopperArgs { main_cryptde: cryptde, payload, + return_route_id: 3333, client_addr: source_addr, timestamp: SystemTime::now(), is_decentralized: false, @@ -3129,7 +3198,7 @@ mod tests { assert_eq!( record, &AddReturnRouteMessage { - return_route_id: 0, + return_route_id: 3333, expected_services: vec![ExpectedService::Nothing], protocol: ProxyProtocol::HTTP, hostname_opt: Some("nowhere.com".to_string()) @@ -3394,6 +3463,7 @@ mod tests { let args = TransmitToHopperArgs { main_cryptde: cryptde, payload, + return_route_id: 2222, client_addr: source_addr, timestamp: SystemTime::now(), is_decentralized: true, @@ -3578,7 +3648,7 @@ mod tests { data: expected_data.clone(), }; let expected_tls_request = PlainData::new(tls_request); - let route = Route { hops: vec![] }; + let route = Route { hops: vec![] }.set_return_route_id(main_cryptde, 1); let expected_payload = ClientRequestPayload_0v1 { stream_key: stream_key.clone(), sequenced_packet: SequencedPacket { @@ -3678,7 +3748,7 @@ mod tests { }; let expected_pkg = IncipientCoresPackage::new( main_cryptde, - route.clone(), + route.clone().set_return_route_id(main_cryptde, 1), expected_payload.into(), &destination_key, ) @@ -3762,7 +3832,7 @@ mod tests { }; let expected_pkg = IncipientCoresPackage::new( main_cryptde, - route.clone(), + route.clone().set_return_route_id(main_cryptde, 1), expected_payload.into(), &destination_key, ) @@ -5725,6 +5795,7 @@ mod tests { ) { init_test_logging(); let cryptde = main_cryptde(); + let return_route_id = 272727; let (dispatcher, _, dispatcher_recording_arc) = make_recorder(); let (accountant, _, accountant_recording_arc) = make_recorder(); let system = System::new("report_response_services_consumed_complains_and_drops_package_if_return_route_id_is_unrecognized"); @@ -5756,7 +5827,7 @@ mod tests { let expired_cores_package = ExpiredCoresPackage::new( SocketAddr::from_str("1.2.3.4:1234").unwrap(), Some(make_wallet("irrelevant")), - return_route_with_id(cryptde, 1234), + return_route_with_id(cryptde, return_route_id), client_response_payload, 0, ); @@ -5766,7 +5837,7 @@ mod tests { System::current().stop(); system.run(); - TestLogHandler::new().exists_log_containing("ERROR: ProxyServer: Can't report services consumed: received response with bogus return-route ID 1234 for client response. Ignoring"); + TestLogHandler::new().exists_log_containing(format!("ERROR: ProxyServer: Can't report services consumed: received response with bogus return-route ID RRI{} for client response. Ignoring", return_route_id).as_str()); assert_eq!(dispatcher_recording_arc.lock().unwrap().len(), 0); assert_eq!(accountant_recording_arc.lock().unwrap().len(), 0); } @@ -5886,7 +5957,7 @@ mod tests { ); subject_addr.try_send(expired_cores_package).unwrap(); - TestLogHandler::new().await_log_containing("ERROR: ProxyServer: Can't report services consumed: received response with bogus return-route ID 1234 for client response. Ignoring", 1000); + TestLogHandler::new().await_log_containing("ERROR: ProxyServer: Can't report services consumed: received response with bogus return-route ID RRI1234 for client response. Ignoring", 1000); } #[test] @@ -5971,8 +6042,7 @@ mod tests { Some(make_paying_wallet(b"consuming")), Some(TEST_DEFAULT_CHAIN.rec().contract), ) - .unwrap() - .set_return_route_id(main_cryptde(), 1234); + .unwrap(); let affected_expected_services = vec![ExpectedService::Exit( affected_cryptde.public_key().clone(), make_paying_wallet(b"1234"), @@ -5982,10 +6052,7 @@ mod tests { affected_stream_key, RouteQueryResponse { route: affected_route.clone(), - expected_services: ExpectedServices::RoundTrip( - affected_expected_services, - vec![], - ), + expected_services: ExpectedServices::RoundTrip(affected_expected_services, vec![]), }, ); subject @@ -6018,7 +6085,10 @@ mod tests { system.run(); let recording = hopper_recording_arc.lock().unwrap(); let record = recording.get_record::(0); - assert_eq!(record.route, affected_route); + assert_eq!( + record.route, + affected_route.set_return_route_id(main_cryptde(), 1) + ); let payload = decodex::(&affected_cryptde, &record.payload).unwrap(); match payload { MessageType::ClientRequest(vd) => assert_eq!( @@ -6082,6 +6152,7 @@ mod tests { expected_services: ExpectedServices::RoundTrip(vec![], vec![]), }, ); + subject.next_return_route_id = Cell::new(1234); let affected_route = Route::round_trip( RouteSegment::new( vec![main_cryptde().public_key(), affected_cryptde.public_key()], @@ -6095,8 +6166,7 @@ mod tests { Some(make_paying_wallet(b"consuming")), Some(TEST_DEFAULT_CHAIN.rec().contract), ) - .unwrap() - .set_return_route_id(main_cryptde(), 1234); + .unwrap(); let affected_expected_services = vec![ExpectedService::Exit( affected_cryptde.public_key().clone(), make_paying_wallet(b"1234"), @@ -6106,10 +6176,7 @@ mod tests { affected_stream_key, RouteQueryResponse { route: affected_route.clone(), - expected_services: ExpectedServices::RoundTrip( - affected_expected_services, - vec![], - ), + expected_services: ExpectedServices::RoundTrip(affected_expected_services, vec![]), }, ); subject.logger = Logger::new(test_name); @@ -6137,7 +6204,10 @@ mod tests { system.run(); let recording = hopper_recording_arc.lock().unwrap(); let record = recording.get_record::(0); - assert_eq!(record.route, affected_route); + assert_eq!( + record.route, + affected_route.set_return_route_id(main_cryptde(), 1234) + ); let payload = decodex::(&affected_cryptde, &record.payload).unwrap(); match payload { MessageType::ClientRequest(vd) => assert_eq!( @@ -6286,6 +6356,7 @@ mod tests { let args = TransmitToHopperArgs { main_cryptde: cryptde, payload, + return_route_id: 8888, client_addr: SocketAddr::from_str("1.2.3.4:1234").unwrap(), timestamp: SystemTime::now(), is_decentralized: false, @@ -6698,6 +6769,24 @@ mod tests { ); } + #[test] + fn get_next_return_route_id_wraps_around() { + let mut mut_subject = + ProxyServer::new(main_cryptde(), alias_cryptde(), true, None, false, false); + mut_subject.next_return_route_id = Cell::new(0xFFFFFFFE); + let subject = mut_subject; + + let end_minus_one = subject.get_next_return_route_id(); + let end = subject.get_next_return_route_id(); + let beginning = subject.get_next_return_route_id(); + let beginning_plus_one = subject.get_next_return_route_id(); + + assert_eq!(end_minus_one, 0xFFFFFFFE); + assert_eq!(end, 0xFFFFFFFF); + assert_eq!(beginning, 0x00000000); + assert_eq!(beginning_plus_one, 0x00000001); + } + fn make_exit_service_from_key(public_key: PublicKey) -> ExpectedService { ExpectedService::Exit(public_key, make_wallet("exit wallet"), rate_pack(100)) } diff --git a/node/src/sub_lib/route.rs b/node/src/sub_lib/route.rs index 83ebc03d86..a9314d29e9 100644 --- a/node/src/sub_lib/route.rs +++ b/node/src/sub_lib/route.rs @@ -53,7 +53,7 @@ impl Route { pub fn round_trip( route_segment_over: RouteSegment, route_segment_back: RouteSegment, - cryptde: &dyn CryptDE, // Must be the CryptDE of the originating Node: used to encrypt return_route_id. + cryptde: &dyn CryptDE, // Doesn't matter which CryptDE: only used for encoding. consuming_wallet: Option, contract_address: Option
, ) -> Result { @@ -174,11 +174,7 @@ impl Route { contract_address, ); - Route::hops_to_route( - hops[0..].to_vec(), - &over.keys[0], - cryptde, - ) + Route::hops_to_route(hops[0..].to_vec(), &over.keys[0], cryptde) } fn over_segment<'a>( From f79d84d2c639183f2ac3313abdbf61889a704933 Mon Sep 17 00:00:00 2001 From: Dan Wiebe Date: Mon, 15 Sep 2025 07:36:56 -0400 Subject: [PATCH 13/21] Unit tests pass --- node/src/proxy_server/mod.rs | 776 ++++++++++++++++++++++------------- 1 file changed, 488 insertions(+), 288 deletions(-) diff --git a/node/src/proxy_server/mod.rs b/node/src/proxy_server/mod.rs index 301ce98ec0..4fb577776b 100644 --- a/node/src/proxy_server/mod.rs +++ b/node/src/proxy_server/mod.rs @@ -76,15 +76,72 @@ struct ProxyServerOutSubs { schedule_stream_key_purge: Recipient>, } +struct StreamInfo { + tunneled_host_opt: Option, + dns_failure_retry_opt: Option, + route_opt: Option, + time_to_live_opt: Option, + // return_route_info: AddReturnRouteMessage, +} + +struct StreamInfoBuilder { + product: StreamInfo +} + +impl StreamInfoBuilder { + pub fn new() -> Self { + Self { + product: StreamInfo { + tunneled_host_opt: None, + dns_failure_retry_opt: None, + route_opt: None, + time_to_live_opt: None, + // return_route_info: AddReturnRouteMessage{ + // return_route_id: 0, + // expected_services: vec![], + // protocol: ProxyProtocol::HTTP, + // hostname_opt: None, + // }, + } + } + } + + pub fn tunneled_host(mut self, host: &str) -> Self { + self.product.tunneled_host_opt = Some(host.to_string()); + self + } + + pub fn dns_failure_retry(mut self, retry: DNSFailureRetry) -> Self { + self.product.dns_failure_retry_opt = Some(retry); + self + } + + pub fn route(mut self, route: RouteQueryResponse) -> Self { + self.product.route_opt = Some(route); + self + } + + pub fn time_to_live(mut self, ttl: SystemTime) -> Self { + self.product.time_to_live_opt = Some(ttl); + self + } + + // pub fn return_route_info(mut self, add_return_route_message: AddReturnRouteMessage) -> Self { + // self.product.return_route_info = add_return_route_message; + // self + // } + + pub fn build(self) -> StreamInfo { + self.product + } +} + pub struct ProxyServer { subs: Option, client_request_payload_factory: Box, stream_key_factory: Box, keys_and_addrs: BidiHashMap, - tunneled_hosts: HashMap, - dns_failure_retries: HashMap, - stream_key_routes: HashMap, - stream_key_ttl: HashMap, + stream_info: HashMap, is_decentralized: bool, consuming_wallet_balance: Option, main_cryptde: &'static dyn CryptDE, @@ -175,34 +232,56 @@ impl Handler for ProxyServer { type Result = (); fn handle(&mut self, msg: AddRouteResultMessage, _ctx: &mut Self::Context) -> Self::Result { - let dns_failure = match self.dns_failure_retries.get(&msg.stream_key) { - Some(retry) => retry, - None => { - error!( - self.logger, - "AddRouteResultMessage stream key {} not found within dns_failure_retries", - msg.stream_key - ); - return; - } - }; - - match msg.result { - Ok(route_query_response) => { - debug!( - self.logger, - "Found a new route for hostname: {:?} - stream key: {} retries left: {}", - dns_failure.unsuccessful_request.target_hostname, - msg.stream_key, - dns_failure.retries_left - ); - self.stream_key_routes - .insert(msg.stream_key, route_query_response); - } - Err(e) => { - warning!(self.logger, "No route found for hostname: {:?} - stream key {} - retries left: {} - AddRouteResultMessage Error: {}",dns_failure.unsuccessful_request.target_hostname, msg.stream_key, dns_failure.retries_left, e); - } + let mut delayed_log: Box = Box::new(|_: &Logger| {}); + if let Some(stream_info) = self.stream_info_mut(&msg.stream_key) { + match &stream_info.dns_failure_retry_opt { + Some(dns_failure) => { + match msg.result { + Ok(route_query_response) => { + let target_hostname = dns_failure.unsuccessful_request.target_hostname.clone(); + let retries_left = dns_failure.retries_left; + let stream_key = msg.stream_key.clone(); + delayed_log = Box::new(move |logger: &Logger| { + debug!( + logger, + "Found a new route for hostname: {:?} - stream key: {} retries left: {}", + target_hostname, + stream_key, + retries_left + ); + }); + stream_info.route_opt = Some(route_query_response); + } + Err(e) => { + let target_hostname = dns_failure.unsuccessful_request.target_hostname.clone(); + let retries_left = dns_failure.retries_left; + let stream_key = msg.stream_key.clone(); + delayed_log = Box::new(move |logger: &Logger| { + warning!( + logger, + "No route found for hostname: {:?} - stream key {} - retries left: {} - AddRouteResultMessage Error: {}", + target_hostname, + stream_key, + retries_left, + e + ); + }); + } + } + }, + None => { + let stream_key = msg.stream_key.clone(); + delayed_log = Box::new(move |logger: &Logger| { + error!( + logger, + "AddRouteResultMessage stream key {} not found within dns_failure_retries", + stream_key + ); + }); + } + }; } + delayed_log(&self.logger); } } @@ -281,10 +360,7 @@ impl ProxyServer { client_request_payload_factory: Box::new(ClientRequestPayloadFactoryReal::new()), stream_key_factory: Box::new(StreamKeyFactoryReal {}), keys_and_addrs: BidiHashMap::new(), - tunneled_hosts: HashMap::new(), - dns_failure_retries: HashMap::new(), - stream_key_routes: HashMap::new(), - stream_key_ttl: HashMap::new(), + stream_info: HashMap::new(), is_decentralized, consuming_wallet_balance, main_cryptde, @@ -324,16 +400,52 @@ impl ProxyServer { } } + fn stream_info(&self, stream_key: &StreamKey, logger: &Logger) -> Option<&StreamInfo> { + match self.stream_info.get(stream_key) { + None => { + error!( + logger, + "Stream key {} not found in stream_info", stream_key + ); + None + } + Some(info) => Some(info), + } + } + + fn stream_info_mut(&mut self, stream_key: &StreamKey) -> Option<&mut StreamInfo> { + match self.stream_info.get_mut(stream_key) { + None => { + error!( + self.logger, + "Stream key {} not found in stream_info", stream_key + ); + None + } + Some(info) => Some(info), + } + } + fn remove_dns_failure_retry( &mut self, stream_key: &StreamKey, ) -> Result { - match self.dns_failure_retries.remove(stream_key) { - None => Err(format!( - "No entry found inside dns_failure_retries hashmap for the stream_key: {:?}", - stream_key - )), - Some(retry) => Ok(retry), + match self.stream_info.get_mut(stream_key) { + None => { + Err(format!( + "No stream_info record found for the stream_key: {:?}", + stream_key + )) + }, + Some(info) => match info.dns_failure_retry_opt.take() { + None => { + Err(format!( + "No DNSFailureRetry entry found for the stream_key: {:?}", + stream_key + )) + }, + Some(retry) => Ok(retry) + } } } @@ -457,8 +569,9 @@ impl ProxyServer { if retry.retries_left > 0 { let mut returned_retry = self.retry_dns_resolution(retry, client_addr); returned_retry.retries_left -= 1; - self.dns_failure_retries - .insert(response.stream_key, returned_retry); + self.stream_info_mut(&response.stream_key) + .expect(&format!("Stream key {} present in keys_and_addrs but not in stream_info", &response.stream_key)) + .dns_failure_retry_opt = Some(returned_retry); } else { self.retire_stream_key(&response.stream_key); self.send_dns_failure_response_to_the_browser( @@ -479,27 +592,34 @@ impl ProxyServer { } fn schedule_stream_key_purge(&mut self, stream_key: StreamKey) { - let host_info = match self.tunneled_hosts.get(&stream_key) { - None => String::from(""), - Some(hostname) => format!(", which was tunneling to the host {:?}", hostname), - }; - debug!( - self.logger, - "Client closed stream referenced by stream key {:?}{}. It will be purged after {:?}.", - &stream_key, - host_info, - self.stream_key_purge_delay - ); - self.stream_key_ttl.insert(stream_key, SystemTime::now()); - self.subs - .as_ref() - .expect("ProxyServer Subs Unbound") - .schedule_stream_key_purge - .try_send(MessageScheduler { - scheduled_msg: StreamKeyPurge { stream_key }, - delay: self.stream_key_purge_delay, - }) - .expect("ProxyServer is dead"); + let stream_key_purge_delay = self.stream_key_purge_delay; + let mut delayed_log: Box = Box::new(|_: &Logger| {}); + if let Some(stream_info) = self.stream_info_mut(&stream_key) { + let host_info = match &stream_info.tunneled_host_opt { + None => String::from(""), + Some(hostname) => format!(", which was tunneling to the host {:?}", hostname), + }; + delayed_log = Box::new(move |logger: &Logger| { + debug!( + logger, + "Client closed stream referenced by stream key {:?}{}. It will be purged after {:?}.", + &stream_key, + host_info, + stream_key_purge_delay + ); + }); + stream_info.time_to_live_opt = Some(SystemTime::now()); + self.subs + .as_ref() + .expect("ProxyServer Subs Unbound") + .schedule_stream_key_purge + .try_send(MessageScheduler { + scheduled_msg: StreamKeyPurge { stream_key }, + delay: self.stream_key_purge_delay, + }) + .expect("ProxyServer is dead"); + } + delayed_log(&self.logger); } fn log_straggling_packet( @@ -564,8 +684,14 @@ impl ProxyServer { ) } } - if let Some(old_timestamp) = self.stream_key_ttl.get(&stream_key) { - self.log_straggling_packet(&stream_key, payload_data_len, old_timestamp) + let stream_info_opt = self.stream_info(&stream_key, &self.logger); + let old_timestamp_opt = match stream_info_opt { + Some(info) => info.time_to_live_opt, + None => None, + }; + if let Some(old_timestamp) = old_timestamp_opt { + self.log_straggling_packet(&stream_key, payload_data_len, &old_timestamp) + // TODO: Make sure we actually do something (other than logging) about stragglers. } else { match self.keys_and_addrs.a_to_b(&stream_key) { Some(socket_addr) => { @@ -612,7 +738,10 @@ impl ProxyServer { match http_data { Some(ref host) if host.port == TLS_PORT => { let stream_key = self.find_or_generate_stream_key(msg); - self.tunneled_hosts.insert(stream_key, host.name.clone()); + match self.stream_info_mut(&stream_key) { + None => return, + Some(stream_info) => stream_info.tunneled_host_opt = Some(host.name.clone()), + } self.subs .as_ref() .expect("Dispatcher unbound in ProxyServer") @@ -703,7 +832,11 @@ impl ProxyServer { let stream_key = self .stream_key_factory .make(self.main_cryptde.public_key(), ibcd.client_addr); - self.keys_and_addrs.insert(stream_key, ibcd.client_addr); + self.keys_and_addrs.insert(stream_key.clone(), ibcd.client_addr); + self.stream_info.insert( + stream_key.clone(), + StreamInfoBuilder::new().build(), + ); debug!( self.logger, "find_or_generate_stream_key() inserted new key {} for {}", @@ -721,9 +854,7 @@ impl ProxyServer { "Retiring stream key {} due to {}", &stream_key, reason ); let _ = self.keys_and_addrs.remove_a(stream_key); - let _ = self.stream_key_routes.remove(stream_key); - let _ = self.tunneled_hosts.remove(stream_key); - let _ = self.stream_key_ttl.remove(stream_key); + let _ = self.stream_info.remove(stream_key); } fn make_payload( @@ -731,8 +862,12 @@ impl ProxyServer { ibcd: InboundClientData, stream_key: &StreamKey, ) -> Result { - let tunnelled_host = self.tunneled_hosts.get(stream_key); - let new_ibcd = match tunnelled_host { + let stream_info_opt = self.stream_info.get(stream_key); + let tunnelled_host_opt = match stream_info_opt { + None => None, + Some(info) => info.tunneled_host_opt.clone(), + }; + let new_ibcd = match tunnelled_host_opt { Some(_) => InboundClientData { reception_port: Some(443), ..ibcd @@ -746,9 +881,9 @@ impl ProxyServer { &self.logger, ) { None => Err("Couldn't create ClientRequestPayload".to_string()), - Some(payload) => match tunnelled_host { + Some(payload) => match tunnelled_host_opt { Some(hostname) => Ok(ClientRequestPayload_0v1 { - target_hostname: Some(hostname.clone()), + target_hostname: Some(hostname), ..payload }), None => Ok(payload), @@ -1217,20 +1352,25 @@ impl IBCDHelper for IBCDHelperReal { Err(e) => return Err(e), }; - if proxy.dns_failure_retries.get(&stream_key).is_none() { - let dns_failure_retry = DNSFailureRetry { - unsuccessful_request: payload.clone(), - retries_left: if proxy.is_decentralized { 3 } else { 0 }, - }; - proxy - .dns_failure_retries - .insert(stream_key, dns_failure_retry); + { + let is_decentralized = proxy.is_decentralized; + let mut stream_info = proxy.stream_info_mut(&stream_key) + .expect(&format!("Stream key {} disappeared!", &stream_key)); + if stream_info.dns_failure_retry_opt.is_none() { + let dns_failure_retry = DNSFailureRetry { + unsuccessful_request: payload.clone(), + retries_left: if is_decentralized { 3 } else { 0 }, + }; + stream_info.dns_failure_retry_opt = Some(dns_failure_retry); + } } let args = TransmitToHopperArgs::new(proxy, payload, client_addr, timestamp, retire_stream_key); let add_return_route_sub = proxy.out_subs("ProxyServer").add_return_route.clone(); let pld = &args.payload; - if let Some(route_query_response) = proxy.stream_key_routes.get(&pld.stream_key) { + let stream_info = proxy.stream_info(&pld.stream_key, &proxy.logger) + .expect(&format!("Stream key {} disappeared!", &pld.stream_key)); + if let Some(route_query_response) = &stream_info.route_opt { debug!( proxy.logger, "Transmitting down existing stream {}: sequence {}, length {}", @@ -1830,7 +1970,7 @@ mod tests { thread::spawn(move || { let stream_key_factory = StreamKeyFactoryMock::new() .make_parameters(&make_parameters_arc) - .make_result(stream_key); + .make_result(stream_key.clone()); let system = System::new(test_name); let mut subject = ProxyServer::new( main_cryptde, @@ -1853,6 +1993,13 @@ mod tests { subject_addr.try_send(msg_from_dispatcher).unwrap(); + subject_addr + .try_send(AssertionsMessage { + assertions: Box::new(move |proxy_server: &mut ProxyServer| { + assert!(proxy_server.stream_info.contains_key(&stream_key)); + }), + }) + .unwrap(); system.run(); }); @@ -1948,7 +2095,7 @@ mod tests { thread::spawn(move || { let stream_key_factory = StreamKeyFactoryMock::new() .make_parameters(&make_parameters_arc_thread) - .make_result(stream_key); + .make_result(stream_key.clone()); let system = System::new( "proxy_server_receives_connect_responds_with_ok_and_stores_stream_key_and_hostname", ); @@ -1971,6 +2118,13 @@ mod tests { subject_addr.try_send(msg_from_dispatcher).unwrap(); subject_addr.try_send(tunnelled_msg).unwrap(); + subject_addr + .try_send(AssertionsMessage { + assertions: Box::new(move |proxy_server: &mut ProxyServer| { + assert!(proxy_server.stream_info.contains_key(&stream_key)); + }), + }) + .unwrap(); system.run(); }); @@ -2018,6 +2172,10 @@ mod tests { subject .keys_and_addrs .insert(stream_key.clone(), socket_addr.clone()); + subject.stream_info.insert( + stream_key.clone(), + StreamInfoBuilder::new().build() + ); subject.route_ids_to_return_routes_first_chance.insert( 1234, @@ -2368,7 +2526,11 @@ mod tests { let mut subject = ProxyServer::new(main_cryptde, alias_cryptde, false, None, false, false); subject.stream_key_factory = Box::new(stream_key_factory); - subject.keys_and_addrs.insert(stream_key, socket_addr); + subject.keys_and_addrs.insert(stream_key.clone(), socket_addr); + subject.stream_info.insert( + stream_key, + StreamInfoBuilder::new().build() + ); let subject_addr: Addr = subject.start(); let peer_actors = peer_actors_builder() .dispatcher(dispatcher) @@ -2449,6 +2611,10 @@ mod tests { ProxyServer::new(main_cryptde, alias_cryptde, false, None, false, false); subject.stream_key_factory = Box::new(stream_key_factory); subject.keys_and_addrs.insert(stream_key, socket_addr); + subject.stream_info.insert( + stream_key.clone(), + StreamInfoBuilder::new().build() + ); let subject_addr: Addr = subject.start(); let peer_actors = peer_actors_builder() .dispatcher(dispatcher) @@ -2561,6 +2727,10 @@ mod tests { ); subject.stream_key_factory = Box::new(stream_key_factory); subject.keys_and_addrs.insert(stream_key, socket_addr); + subject.stream_info.insert( + stream_key.clone(), + StreamInfoBuilder::new().build() + ); let subject_addr: Addr = subject.start(); let peer_actors = peer_actors_builder() .hopper(hopper_mock) @@ -2895,7 +3065,7 @@ mod tests { let expected_data = http_request.to_vec(); let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), - client_addr: socket_addr.clone(), + client_addr: socket_addr, reception_port: Some(HTTP_PORT), sequence_number: Some(0), last_data: true, @@ -2934,9 +3104,11 @@ mod tests { false, ); subject.stream_key_factory = Box::new(stream_key_factory); - subject - .stream_key_routes - .insert(stream_key, route_query_response); + subject.keys_and_addrs.insert(stream_key.clone(), socket_addr); + subject.stream_info.insert( + stream_key, + StreamInfoBuilder::new().route(route_query_response).build() + ); subject.next_return_route_id = Cell::new(4444); let subject_addr: Addr = subject.start(); let peer_actors = peer_actors_builder().hopper(hopper_mock).build(); @@ -3279,10 +3451,10 @@ mod tests { } #[test] - fn route_result_message_handler_panics_when_dns_retries_hashmap_doesnt_contain_a_stream_key() { + fn route_result_message_handler_logs_error_when_no_dns_retries_exist() { init_test_logging(); - let system = System::new("route_result_message_handler_panics_when_dns_retries_hashmap_doesnt_contain_a_stream_key"); - let subject = ProxyServer::new( + let system = System::new("route_result_message_handler_logs_error_when_no_dns_retries_exist"); + let mut subject = ProxyServer::new( main_cryptde(), alias_cryptde(), true, @@ -3290,13 +3462,18 @@ mod tests { false, false, ); + let stream_key = StreamKey::make_meaningless_stream_key(); + subject.stream_info.insert( + stream_key.clone(), + StreamInfoBuilder::new().build() // no DNS retries + ); let subject_addr: Addr = subject.start(); let peer_actors = peer_actors_builder().build(); subject_addr.try_send(BindMessage { peer_actors }).unwrap(); subject_addr .try_send(AddRouteResultMessage { - stream_key: StreamKey::make_meaningless_stream_key(), + stream_key, result: Err("Some Error".to_string()), }) .unwrap(); @@ -3847,6 +4024,10 @@ mod tests { false, ); subject.keys_and_addrs.insert(stream_key, client_addr); + subject.stream_info.insert( + stream_key, + StreamInfoBuilder::new().build(), + ); let system = System::new(test_name); let subject_addr: Addr = subject.start(); let peer_actors = peer_actors_builder() @@ -3964,6 +4145,11 @@ mod tests { subject .keys_and_addrs .insert(stream_key.clone(), socket_addr.clone()); + subject.stream_info.insert( + stream_key.clone(), + StreamInfoBuilder::new() + .build() + ); subject.route_ids_to_return_routes_first_chance.insert( 1234, AddReturnRouteMessage { @@ -4051,16 +4237,16 @@ mod tests { subject .keys_and_addrs .insert(stream_key.clone(), socket_addr.clone()); - subject.stream_key_routes.insert( + subject.stream_info.insert( stream_key.clone(), - RouteQueryResponse { - route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip(vec![], vec![]), - }, + StreamInfoBuilder::new() + .route(RouteQueryResponse { + route: Route { hops: vec![] }, + expected_services: ExpectedServices::RoundTrip(vec![], vec![]), + }) + .tunneled_host("hostname") + .build() ); - subject - .tunneled_hosts - .insert(stream_key.clone(), "hostname".to_string()); subject.route_ids_to_return_routes_first_chance.insert( 1234, AddReturnRouteMessage { @@ -4089,8 +4275,7 @@ mod tests { subject.handle_client_response_payload(expired_cores_package); assert!(subject.keys_and_addrs.is_empty()); - assert!(subject.stream_key_routes.is_empty()); - assert!(subject.tunneled_hosts.is_empty()); + assert!(subject.stream_info.get(&stream_key).is_none()); assert!(subject .route_ids_to_return_routes_first_chance .get(&1234) @@ -4169,16 +4354,16 @@ mod tests { subject .keys_and_addrs .insert(stream_key.clone(), msg.peer_addr.clone()); - subject.stream_key_routes.insert( + subject.stream_info.insert( stream_key.clone(), - RouteQueryResponse { - route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip(vec![], vec![]), - }, + StreamInfoBuilder::new() + .route(RouteQueryResponse { + route: Route { hops: vec![] }, + expected_services: ExpectedServices::RoundTrip(vec![], vec![]), + }) + .tunneled_host("hostname") + .build() ); - subject - .tunneled_hosts - .insert(stream_key.clone(), "hostname".to_string()); subject.route_ids_to_return_routes_first_chance.insert( 1234, AddReturnRouteMessage { @@ -4204,18 +4389,14 @@ mod tests { .unwrap(); let pre_purge_assertions = AssertionsMessage { assertions: Box::new(move |proxy_server: &mut ProxyServer| { - let purge_timestamp = proxy_server - .stream_key_ttl - .get(&stream_key) - .unwrap() - .clone(); + let stream_info = proxy_server.stream_info.get(&stream_key).unwrap(); + let purge_timestamp = stream_info.time_to_live_opt.unwrap(); assert!( time_before_sending_package <= purge_timestamp && purge_timestamp <= time_after_sending_package ); + assert!(!proxy_server.stream_info.get(&stream_key).is_none()); assert!(!proxy_server.keys_and_addrs.is_empty()); - assert!(!proxy_server.stream_key_routes.is_empty()); - assert!(!proxy_server.tunneled_hosts.is_empty()); TestLogHandler::new().exists_log_containing(&format!( "DEBUG: {test_name}: Client closed stream referenced by stream key {:?}, \ which was tunneling to the host \"hostname\". \ @@ -4233,9 +4414,7 @@ mod tests { let post_purge_assertions = AssertionsMessage { assertions: Box::new(move |proxy_server: &mut ProxyServer| { assert!(proxy_server.keys_and_addrs.is_empty()); - assert!(proxy_server.stream_key_routes.is_empty()); - assert!(proxy_server.tunneled_hosts.is_empty()); - assert!(proxy_server.stream_key_ttl.is_empty()); + assert!(proxy_server.stream_info.get(&stream_key).is_none()); TestLogHandler::new().exists_log_containing(&format!( "DEBUG: {test_name}: Retiring stream key {:?}", stream_key @@ -4272,16 +4451,17 @@ mod tests { subject .keys_and_addrs .insert(stream_key.clone(), socket_addr.clone()); - subject.stream_key_routes.insert( + subject.stream_info.insert( stream_key.clone(), - RouteQueryResponse { - route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip(vec![], vec![]), - }, + StreamInfoBuilder::new() + .route(RouteQueryResponse { + route: Route { hops: vec![] }, + expected_services: ExpectedServices::RoundTrip(vec![], vec![]), + }) + .tunneled_host("hostname") + .time_to_live(SystemTime::now()) + .build() ); - subject - .tunneled_hosts - .insert(stream_key.clone(), "hostname".to_string()); let exit_key = PublicKey::new(&b"blah"[..]); let exit_wallet = make_wallet("abc"); let exit_rates = RatePack { @@ -4303,9 +4483,6 @@ mod tests { hostname_opt: None, }, ); - subject - .stream_key_ttl - .insert(stream_key.clone(), SystemTime::now()); let (accountant, _, accountant_recording_arc) = make_recorder(); let (dispatcher, _, dispatcher_recording_arc) = make_recorder(); let proxy_server_addr = subject.start(); @@ -4376,6 +4553,11 @@ mod tests { subject .keys_and_addrs .insert(stream_key.clone(), socket_addr.clone()); + subject.stream_info.insert( + stream_key.clone(), + StreamInfoBuilder::new() + .build() + ); let incoming_route_d_wallet = make_wallet("D Earning"); let incoming_route_e_wallet = make_wallet("E Earning"); let incoming_route_f_wallet = make_wallet("F Earning"); @@ -4569,6 +4751,7 @@ mod tests { let test_name = "dns_retry_entry_is_removed_after_a_successful_client_response"; let system = System::new(test_name); let cryptde = main_cryptde(); + let logger = Logger::new(test_name); let mut subject = ProxyServer::new( cryptde, alias_cryptde(), @@ -4585,17 +4768,17 @@ mod tests { .keys_and_addrs .insert(stream_key.clone(), socket_addr.clone()); subject.logger = Logger::new(test_name); - let mut dns_failure_retries_hash_map = HashMap::new(); let mut dns_fail_client_payload = make_request_payload(111, cryptde); dns_fail_client_payload.stream_key = stream_key; - dns_failure_retries_hash_map.insert( - stream_key, - DNSFailureRetry { - unsuccessful_request: dns_fail_client_payload, - retries_left: 3, - }, + subject.stream_info.insert( + stream_key_clone.clone(), + StreamInfoBuilder::new() + .dns_failure_retry(DNSFailureRetry{ + unsuccessful_request: dns_fail_client_payload, + retries_left: 3, + }) + .build() ); - subject.dns_failure_retries = dns_failure_retries_hash_map; let incoming_route_d_wallet = make_wallet("D Earning"); let incoming_route_e_wallet = make_wallet("E Earning"); let incoming_route_f_wallet = make_wallet("F Earning"); @@ -4653,8 +4836,8 @@ mod tests { subject_addr .try_send(AssertionsMessage { assertions: Box::new(move |proxy_server: &mut ProxyServer| { - let retry_opt = proxy_server.dns_failure_retries.get(&stream_key); - assert_eq!(retry_opt, None); + let retry_opt = &proxy_server.stream_info(&stream_key_clone, &logger).unwrap().dns_failure_retry_opt; + assert!(retry_opt.is_none()); }), }) .unwrap(); @@ -4681,6 +4864,10 @@ mod tests { let stream_key = StreamKey::make_meaningless_stream_key(); let irrelevant_public_key = PublicKey::from(&b"irrelevant"[..]); // subject.keys_and_addrs contains no browser stream + subject.stream_info.insert( + stream_key.clone(), + StreamInfoBuilder::new().build() + ); let incoming_route_d_wallet = make_wallet("D Earning"); let incoming_route_e_wallet = make_wallet("E Earning"); let rate_pack_d = rate_pack(101); @@ -4782,19 +4969,19 @@ mod tests { let stream_key = StreamKey::make_meaningless_stream_key(); let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); - let mut dns_failure_retries_hash_map = HashMap::new(); let client_payload = make_request_payload(111, cryptde); - dns_failure_retries_hash_map.insert( - stream_key, - DNSFailureRetry { - unsuccessful_request: client_payload, - retries_left: 0, - }, - ); - subject.dns_failure_retries = dns_failure_retries_hash_map; subject .keys_and_addrs .insert(stream_key.clone(), socket_addr.clone()); + subject.stream_info.insert( + stream_key.clone(), + StreamInfoBuilder::new() + .dns_failure_retry(DNSFailureRetry{ + unsuccessful_request: client_payload, + retries_left: 0, + }) + .build() + ); let exit_public_key = PublicKey::from(&b"exit_key"[..]); let exit_wallet = make_wallet("exit wallet"); let subject_addr: Addr = subject.start(); @@ -4857,16 +5044,16 @@ mod tests { let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); let stream_key = StreamKey::make_meaningless_stream_key(); let irrelevant_public_key = PublicKey::from(&b"irrelevant"[..]); - let mut dns_failure_retries_hash_map = HashMap::new(); let client_payload = make_request_payload(111, cryptde); - dns_failure_retries_hash_map.insert( - stream_key, - DNSFailureRetry { - unsuccessful_request: client_payload, - retries_left: 0, - }, + subject.stream_info.insert( + stream_key.clone(), + StreamInfoBuilder::new() + .dns_failure_retry(DNSFailureRetry{ + unsuccessful_request: client_payload, + retries_left: 0, + }) + .build() ); - subject.dns_failure_retries = dns_failure_retries_hash_map; subject .keys_and_addrs .insert(stream_key.clone(), socket_addr.clone()); @@ -4974,17 +5161,17 @@ mod tests { ); let stream_key = StreamKey::make_meaningless_stream_key(); let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); - let mut dns_failure_retries_hash_map = HashMap::new(); let client_payload = make_request_payload(111, cryptde); - dns_failure_retries_hash_map.insert( - stream_key, - DNSFailureRetry { - unsuccessful_request: client_payload, - retries_left: 0, - }, - ); subject.logger = Logger::new(test_name); - subject.dns_failure_retries = dns_failure_retries_hash_map; + subject.stream_info.insert( + stream_key.clone(), + StreamInfoBuilder::new() + .dns_failure_retry(DNSFailureRetry{ + unsuccessful_request: client_payload, + retries_left: 0, + }) + .build() + ); subject .keys_and_addrs .insert(stream_key.clone(), socket_addr.clone()); @@ -5056,17 +5243,17 @@ mod tests { ); let stream_key = StreamKey::make_meaningless_stream_key(); let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); - let mut dns_failure_retries_hash_map = HashMap::new(); let client_payload = make_request_payload(111, cryptde); - dns_failure_retries_hash_map.insert( + subject.logger = Logger::new(test_name); + subject.stream_info.insert( stream_key, - DNSFailureRetry { - unsuccessful_request: client_payload, - retries_left: 0, - }, + StreamInfoBuilder::new() + .dns_failure_retry(DNSFailureRetry{ + unsuccessful_request: client_payload, + retries_left: 0, + }) + .build() ); - subject.logger = Logger::new(test_name); - subject.dns_failure_retries = dns_failure_retries_hash_map; subject .keys_and_addrs .insert(stream_key.clone(), socket_addr); @@ -5128,16 +5315,16 @@ mod tests { let stream_key = StreamKey::make_meaningless_stream_key(); let return_route_id = 1234; let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); - let mut dns_failure_retries_hash_map = HashMap::new(); let client_payload = make_request_payload(111, cryptde); - dns_failure_retries_hash_map.insert( + subject.stream_info.insert( stream_key, - DNSFailureRetry { - unsuccessful_request: client_payload, - retries_left: 0, - }, + StreamInfoBuilder::new() + .dns_failure_retry(DNSFailureRetry{ + unsuccessful_request: client_payload, + retries_left: 0, + }) + .build() ); - subject.dns_failure_retries = dns_failure_retries_hash_map; subject .keys_and_addrs .insert(stream_key.clone(), socket_addr.clone()); @@ -5205,16 +5392,16 @@ mod tests { let stream_key = StreamKey::make_meaningless_stream_key(); let return_route_id = 1234; let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); - let mut dns_failure_retries_hash_map = HashMap::new(); let client_payload = make_request_payload(111, cryptde); - dns_failure_retries_hash_map.insert( + subject.stream_info.insert( stream_key, - DNSFailureRetry { - unsuccessful_request: client_payload, - retries_left: 0, - }, + StreamInfoBuilder::new() + .dns_failure_retry(DNSFailureRetry{ + unsuccessful_request: client_payload, + retries_left: 0, + }) + .build() ); - subject.dns_failure_retries = dns_failure_retries_hash_map; subject .keys_and_addrs .insert(stream_key.clone(), socket_addr.clone()); @@ -5287,29 +5474,24 @@ mod tests { subject.subs.as_mut().unwrap().dispatcher = peer_actors.dispatcher.from_dispatcher_client; let stream_key = StreamKey::make_meaningless_stream_key(); let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); - let mut dns_failure_retries_hash_map = HashMap::new(); let client_payload = make_request_payload(111, cryptde); - dns_failure_retries_hash_map.insert( + subject.stream_info.insert( stream_key, - DNSFailureRetry { - unsuccessful_request: client_payload, - retries_left: 0, - }, + StreamInfoBuilder::new() + .dns_failure_retry(DNSFailureRetry{ + unsuccessful_request: client_payload, + retries_left: 0, + }) + .tunneled_host("tunneled host") + .route(RouteQueryResponse { + route: Route { hops: vec![] }, + expected_services: ExpectedServices::OneWay(vec![]), + }) + .build() ); - subject.dns_failure_retries = dns_failure_retries_hash_map; subject .keys_and_addrs .insert(stream_key.clone(), socket_addr.clone()); - subject - .tunneled_hosts - .insert(stream_key.clone(), "tunneled host".to_string()); - subject.stream_key_routes.insert( - stream_key.clone(), - RouteQueryResponse { - route: Route { hops: vec![] }, - expected_services: ExpectedServices::OneWay(vec![]), - }, - ); subject.route_ids_to_return_routes_first_chance.insert( 1234, AddReturnRouteMessage { @@ -5335,8 +5517,7 @@ mod tests { subject.handle_dns_resolve_failure(&expired_cores_package); assert!(subject.keys_and_addrs.is_empty()); - assert!(subject.stream_key_routes.is_empty()); - assert!(subject.tunneled_hosts.is_empty()); + assert!(subject.stream_info.get(&stream_key).is_none()); } #[test] @@ -5356,16 +5537,16 @@ mod tests { ); let stream_key = StreamKey::make_meaningless_stream_key(); let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); - let mut dns_failure_retries_hash_map = HashMap::new(); let client_payload = make_request_payload(111, cryptde); - dns_failure_retries_hash_map.insert( - stream_key, - DNSFailureRetry { - unsuccessful_request: client_payload, - retries_left: 0, - }, + subject.stream_info.insert( + stream_key.clone(), + StreamInfoBuilder::new() + .dns_failure_retry(DNSFailureRetry{ + unsuccessful_request: client_payload, + retries_left: 0, + }) + .build() ); - subject.dns_failure_retries = dns_failure_retries_hash_map; subject .keys_and_addrs .insert(stream_key.clone(), socket_addr.clone()); @@ -5425,7 +5606,9 @@ mod tests { #[test] fn handle_dns_resolve_failure_sent_request_retry() { - let system = System::new("test"); + let test_name = "handle_dns_resolve_failure_sent_request_retry"; + let system = System::new(test_name); + let logger = Logger::new(test_name); let resolve_message_params_arc = Arc::new(Mutex::new(vec![])); let (neighborhood_mock, _, _) = make_recorder(); let exit_public_key = PublicKey::from(&b"exit_key"[..]); @@ -5455,17 +5638,17 @@ mod tests { false, ); let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); - let mut dns_failure_retries_hash_map = HashMap::new(); let client_payload = make_request_payload(111, cryptde); let stream_key = client_payload.stream_key; - dns_failure_retries_hash_map.insert( - stream_key, - DNSFailureRetry { - unsuccessful_request: client_payload.clone(), - retries_left: 3, - }, + subject.stream_info.insert( + stream_key.clone(), + StreamInfoBuilder::new() + .dns_failure_retry(DNSFailureRetry{ + unsuccessful_request: client_payload.clone(), + retries_left: 3, + }) + .build() ); - subject.dns_failure_retries = dns_failure_retries_hash_map; subject .keys_and_addrs .insert(stream_key.clone(), socket_addr.clone()); @@ -5505,7 +5688,9 @@ mod tests { subject_addr .try_send(AssertionsMessage { assertions: Box::new(move |proxy_server: &mut ProxyServer| { - let retry = proxy_server.dns_failure_retries.get(&stream_key).unwrap(); + let retry = proxy_server.stream_info(&stream_key, &logger).unwrap().dns_failure_retry_opt + .as_ref() + .unwrap(); assert_eq!(retry.retries_left, 2); }), }) @@ -5585,8 +5770,7 @@ mod tests { system.run(); TestLogHandler::new().exists_log_containing(&format!( "ERROR: {test_name}: While \ - handling ExpiredCoresPackage: No entry found inside dns_failure_retries hashmap for \ - the stream_key: AAAAAAAAAAAAAAAAAAAAAAAAAAA" + handling ExpiredCoresPackage: No stream_info record found for the stream_key: AAAAAAAAAAAAAAAAAAAAAAAAAAA" )); } @@ -5629,18 +5813,18 @@ mod tests { ); subject.logger = Logger::new(test_name); let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); - let mut dns_failure_retries_hash_map = HashMap::new(); let client_payload = make_request_payload(111, cryptde); let stream_key = client_payload.stream_key; let stream_key_clone = stream_key.clone(); - dns_failure_retries_hash_map.insert( - stream_key, - DNSFailureRetry { - unsuccessful_request: client_payload.clone(), - retries_left: 3, - }, + subject.stream_info.insert( + stream_key_clone.clone(), + StreamInfoBuilder::new() + .dns_failure_retry(DNSFailureRetry{ + unsuccessful_request: client_payload, + retries_left: 3, + }) + .build() ); - subject.dns_failure_retries = dns_failure_retries_hash_map; subject .keys_and_addrs .insert(stream_key.clone(), socket_addr.clone()); @@ -5692,9 +5876,7 @@ mod tests { .try_send(AssertionsMessage { assertions: Box::new(move |proxy_server: &mut ProxyServer| { assert_eq!(proxy_server.keys_and_addrs.a_to_b(&stream_key), None); - assert_eq!(proxy_server.stream_key_routes.get(&stream_key), None); - assert_eq!(proxy_server.tunneled_hosts.get(&stream_key), None); - assert_eq!(proxy_server.dns_failure_retries.get(&stream_key), None); + assert_eq!(proxy_server.stream_info.get(&stream_key).is_none(), true); }), }) .unwrap(); @@ -5724,6 +5906,10 @@ mod tests { subject .keys_and_addrs .insert(stream_key.clone(), socket_addr.clone()); + subject.stream_info.insert( + stream_key.clone(), + StreamInfoBuilder::new().build() + ); let remaining_route = return_route_with_id(cryptde, 4321); subject.route_ids_to_return_routes_first_chance.insert( 4321, @@ -5962,6 +6148,8 @@ mod tests { #[test] fn handle_stream_shutdown_msg_handles_unknown_peer_addr() { + let test_name = "handle_stream_shutdown_msg_handles_unknown_peer_addr"; + let logger = Logger::new(test_name); let mut subject = ProxyServer::new(main_cryptde(), alias_cryptde(), true, None, false, false); let unaffected_socket_addr = SocketAddr::from_str("2.3.4.5:6789").unwrap(); @@ -5969,16 +6157,16 @@ mod tests { subject .keys_and_addrs .insert(unaffected_stream_key, unaffected_socket_addr); - subject.stream_key_routes.insert( + subject.stream_info.insert ( unaffected_stream_key, - RouteQueryResponse { - route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip(vec![], vec![]), - }, + StreamInfoBuilder::new() + .route(RouteQueryResponse { + route: Route { hops: vec![] }, + expected_services: ExpectedServices::RoundTrip(vec![], vec![]), + }) + .tunneled_host("blah") + .build() ); - subject - .tunneled_hosts - .insert(unaffected_stream_key, "blah".to_string()); subject.handle_stream_shutdown_msg(StreamShutdownMsg { peer_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), @@ -5995,9 +6183,9 @@ mod tests { .a_to_b(&unaffected_stream_key) .is_some()); assert!(subject - .stream_key_routes + .stream_info .contains_key(&unaffected_stream_key)); - assert!(subject.tunneled_hosts.contains_key(&unaffected_stream_key)); + assert!(subject.stream_info(&unaffected_stream_key, &logger).unwrap().tunneled_host_opt.is_some()); } #[test] @@ -6022,12 +6210,15 @@ mod tests { subject .keys_and_addrs .insert(affected_stream_key, affected_socket_addr); - subject.stream_key_routes.insert( + subject.stream_info.insert( unaffected_stream_key, - RouteQueryResponse { - route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip(vec![], vec![]), - }, + StreamInfoBuilder::new() + .route(RouteQueryResponse { + route: Route { hops: vec![] }, + expected_services: ExpectedServices::RoundTrip(vec![], vec![]), + }) + .tunneled_host("blah") + .build() ); let affected_route = Route::round_trip( RouteSegment::new( @@ -6048,19 +6239,16 @@ mod tests { make_paying_wallet(b"1234"), DEFAULT_RATE_PACK, )]; - subject.stream_key_routes.insert( + subject.stream_info.insert( affected_stream_key, - RouteQueryResponse { - route: affected_route.clone(), - expected_services: ExpectedServices::RoundTrip(affected_expected_services, vec![]), - }, + StreamInfoBuilder::new() + .route(RouteQueryResponse { + route: affected_route.clone(), + expected_services: ExpectedServices::RoundTrip(affected_expected_services, vec![]), + }) + .tunneled_host("tunneled.com") + .build() ); - subject - .tunneled_hosts - .insert(unaffected_stream_key, "blah".to_string()); - subject - .tunneled_hosts - .insert(affected_stream_key, "tunneled.com".to_string()); let subject_addr = subject.start(); let (hopper, _, hopper_recording_arc) = make_recorder(); let (proxy_server, _, proxy_server_recording_arc) = make_recorder(); @@ -6145,12 +6333,14 @@ mod tests { subject .keys_and_addrs .insert(affected_stream_key, affected_socket_addr); - subject.stream_key_routes.insert( + subject.stream_info.insert( unaffected_stream_key, - RouteQueryResponse { - route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip(vec![], vec![]), - }, + StreamInfoBuilder::new() + .route(RouteQueryResponse { + route: Route { hops: vec![] }, + expected_services: ExpectedServices::RoundTrip(vec![], vec![]), + }) + .build() ); subject.next_return_route_id = Cell::new(1234); let affected_route = Route::round_trip( @@ -6172,12 +6362,14 @@ mod tests { make_paying_wallet(b"1234"), DEFAULT_RATE_PACK, )]; - subject.stream_key_routes.insert( + subject.stream_info.insert( affected_stream_key, - RouteQueryResponse { - route: affected_route.clone(), - expected_services: ExpectedServices::RoundTrip(affected_expected_services, vec![]), - }, + StreamInfoBuilder::new() + .route(RouteQueryResponse { + route: affected_route.clone(), + expected_services: ExpectedServices::RoundTrip(affected_expected_services, vec![]), + }) + .build() ); subject.logger = Logger::new(test_name); let subject_addr = subject.start(); @@ -6256,6 +6448,10 @@ mod tests { let socket_addr = SocketAddr::from_str("3.4.5.6:7777").unwrap(); let stream_key = StreamKey::make_meaningful_stream_key("All Things Must Pass"); subject.keys_and_addrs.insert(stream_key, socket_addr); + subject.stream_info.insert( + stream_key.clone(), + StreamInfoBuilder::new().build() + ); let msg = StreamShutdownMsg { peer_addr: socket_addr, stream_type: RemovedStreamType::NonClandestine(NonClandestineAttributes { @@ -6283,16 +6479,16 @@ mod tests { let socket_addr = SocketAddr::from_str("3.4.5.6:7890").unwrap(); let stream_key = StreamKey::make_meaningful_stream_key("All Things Must Pass"); subject.keys_and_addrs.insert(stream_key, socket_addr); - subject.stream_key_routes.insert( + subject.stream_info.insert ( stream_key, - RouteQueryResponse { - route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip(vec![], vec![]), - }, + StreamInfoBuilder::new() + .route(RouteQueryResponse { + route: Route { hops: vec![] }, + expected_services: ExpectedServices::RoundTrip(vec![], vec![]), + }) + .tunneled_host("blah") + .build() ); - subject - .tunneled_hosts - .insert(stream_key, "blah".to_string()); let msg = StreamShutdownMsg { peer_addr: socket_addr, stream_type: RemovedStreamType::NonClandestine(NonClandestineAttributes { @@ -6452,6 +6648,8 @@ mod tests { #[test] fn new_http_request_creates_new_entry_inside_dns_retries_hashmap() { + let test_name = "new_http_request_creates_new_entry_inside_dns_retries_hashmap"; + let logger = Logger::new(test_name); let main_cryptde = main_cryptde(); let alias_cryptde = alias_cryptde(); let http_request = b"GET /index.html HTTP/1.1\r\nHost: nowhere.com\r\n\r\n"; @@ -6508,7 +6706,7 @@ mod tests { subject_addr .try_send(AssertionsMessage { assertions: Box::new(move |proxy_server: &mut ProxyServer| { - let dns_retry = proxy_server.dns_failure_retries.get(&stream_key).unwrap(); + let dns_retry = proxy_server.stream_info(&stream_key, &logger).unwrap().dns_failure_retry_opt.as_ref().unwrap(); assert_eq!(dns_retry.retries_left, 3); assert_eq!(dns_retry.unsuccessful_request, expected_payload); }), @@ -6520,6 +6718,8 @@ mod tests { #[test] fn new_http_request_creates_new_exhausted_entry_inside_dns_retries_hashmap_zero_hop() { + let test_name = "new_http_request_creates_new_exhausted_entry_inside_dns_retries_hashmap_zero_hop"; + let logger = Logger::new(test_name); let main_cryptde = main_cryptde(); let alias_cryptde = alias_cryptde(); let http_request = b"GET /index.html HTTP/1.1\r\nHost: nowhere.com\r\n\r\n"; @@ -6576,7 +6776,7 @@ mod tests { subject_addr .try_send(AssertionsMessage { assertions: Box::new(move |proxy_server: &mut ProxyServer| { - let dns_retry = proxy_server.dns_failure_retries.get(&stream_key).unwrap(); + let dns_retry = proxy_server.stream_info(&stream_key, &logger).unwrap().dns_failure_retry_opt.as_ref().unwrap(); assert_eq!(dns_retry.retries_left, 0); assert_eq!(dns_retry.unsuccessful_request, expected_payload); }), From b5df05ca26df8bd444e830db7c91eef868e45b79 Mon Sep 17 00:00:00 2001 From: Dan Wiebe Date: Tue, 16 Sep 2025 07:39:44 -0400 Subject: [PATCH 14/21] Interim commit: a real mess --- node/src/proxy_server/mod.rs | 134 ++++++++++++------------------- node/src/sub_lib/neighborhood.rs | 34 ++++++++ 2 files changed, 87 insertions(+), 81 deletions(-) diff --git a/node/src/proxy_server/mod.rs b/node/src/proxy_server/mod.rs index 4fb577776b..2953c26853 100644 --- a/node/src/proxy_server/mod.rs +++ b/node/src/proxy_server/mod.rs @@ -81,7 +81,6 @@ struct StreamInfo { dns_failure_retry_opt: Option, route_opt: Option, time_to_live_opt: Option, - // return_route_info: AddReturnRouteMessage, } struct StreamInfoBuilder { @@ -96,12 +95,6 @@ impl StreamInfoBuilder { dns_failure_retry_opt: None, route_opt: None, time_to_live_opt: None, - // return_route_info: AddReturnRouteMessage{ - // return_route_id: 0, - // expected_services: vec![], - // protocol: ProxyProtocol::HTTP, - // hostname_opt: None, - // }, } } } @@ -126,11 +119,6 @@ impl StreamInfoBuilder { self } - // pub fn return_route_info(mut self, add_return_route_message: AddReturnRouteMessage) -> Self { - // self.product.return_route_info = add_return_route_message; - // self - // } - pub fn build(self) -> StreamInfo { self.product } @@ -148,11 +136,11 @@ pub struct ProxyServer { alias_cryptde: &'static dyn CryptDE, crashable: bool, logger: Logger, - // Holds return-route information for requests that have not yet seen any responses - route_ids_to_return_routes_first_chance: TtlHashMap, - // Holds return-route information for requests that have seen at least one response and may - // see more in the future. The near future, because this TTL is much shorter. - route_ids_to_return_routes_stragglers: TtlHashMap, + // // Holds return-route information for requests that have not yet seen any responses + // route_ids_to_return_routes_first_chance: TtlHashMap, + // // Holds return-route information for requests that have seen at least one response and may + // // see more in the future. The near future, because this TTL is much shorter. + // route_ids_to_return_routes_stragglers: TtlHashMap, browser_proxy_sequence_offset: bool, inbound_client_data_helper_opt: Option>, stream_key_purge_delay: Duration, @@ -203,13 +191,7 @@ impl Handler for ProxyServer { type Result = (); fn handle(&mut self, msg: AddReturnRouteMessage, _ctx: &mut Self::Context) -> Self::Result { - let return_route_id = msg.return_route_id; - self.route_ids_to_return_routes_first_chance - .insert(msg.return_route_id, msg); - debug!( - self.logger, - "Added return route info RRI{} to first-chance cache", return_route_id - ); + // TODO: I think this whole message should probably be deleted from the application. } } @@ -367,17 +349,6 @@ impl ProxyServer { alias_cryptde, crashable, logger: ps_logger, - route_ids_to_return_routes_first_chance: TtlHashMap::new(RETURN_ROUTE_TTL_FIRST_CHANCE), - route_ids_to_return_routes_stragglers: TtlHashMap::new_with_retire( - RETURN_ROUTE_TTL_STRAGGLERS, - move |k, _| { - debug!( - hm_logger, - "Return route info RRI{} expired from straggler cache", *k - ); - true - }, - ), browser_proxy_sequence_offset: false, inbound_client_data_helper_opt: Some(Box::new(IBCDHelperReal::new())), stream_key_purge_delay: STREAM_KEY_PURGE_DELAY, @@ -504,12 +475,20 @@ impl ProxyServer { } fn handle_dns_resolve_failure(&mut self, msg: &ExpiredCoresPackage) { + let response = &msg.payload; + if let Some(stream_info) = self.stream_info(&response.stream_key, &self.logger) { + let exit_public_key = if !self.is_decentralized { + self.main_cryptde.public_key() + } + else if + } + let return_route_id = match self.rri_from_remaining_route(&msg.remaining_route) { Some(rri) => rri, None => return, // TODO: Eventually we'll have to do something better here, but we'll probably need some heuristics. }; let return_route_info = - match self.get_return_route_info(return_route_id, "dns resolve failure") { + match self.get_expected_services(return_route_id, "dns resolve failure") { Some(rri) => rri, None => return, // TODO: Eventually we'll have to do something better here, but we'll probably need some heuristics. }; @@ -661,7 +640,7 @@ impl ProxyServer { Some(rri) => rri, None => return, }; - let return_route_info = match self.get_return_route_info(return_route_id, "client response") + let return_route_info = match self.get_expected_services(return_route_id, "client response") { Some(rri) => rri, None => return, @@ -900,7 +879,7 @@ impl ProxyServer { fn try_transmit_to_hopper( args: TransmitToHopperArgs, - add_return_route_sub: Recipient, + // add_return_route_sub: Recipient, route_query_response: RouteQueryResponse, ) -> Result<(), String> { match route_query_response.expected_services { @@ -915,9 +894,9 @@ impl ProxyServer { args.logger, "Adding expectant return route info: RRI{}", args.return_route_id ); - add_return_route_sub - .try_send(return_route_info) - .expect("ProxyServer is dead"); + // add_return_route_sub + // .try_send(return_route_info) + // .expect("ProxyServer is dead"); ProxyServer::transmit_to_hopper(args, route_query_response.route, over) } _ => panic!("Expected RoundTrip ExpectedServices but got OneWay"), @@ -1119,37 +1098,22 @@ impl ProxyServer { } } - fn get_return_route_info( + fn get_expected_services( &mut self, - return_route_id: u32, - source: &str, - ) -> Option> { - match self - .route_ids_to_return_routes_first_chance - .remove(&return_route_id) - { - Some(rri) => { - self.route_ids_to_return_routes_stragglers - .insert(return_route_id, (*rri).clone()); - debug!(self.logger, "Return route info RRI{} found in first-chance cache; graduated to straggler cache", return_route_id); - Some(rri) - } - None => match self - .route_ids_to_return_routes_stragglers - .get(&return_route_id) - { - Some(rri) => { - debug!( - self.logger, - "Return route info RRI{} found in straggler cache", return_route_id - ); - Some(rri) - } - None => { - error!(self.logger, "Can't report services consumed: received response with bogus return-route ID RRI{} for {}. Ignoring", return_route_id, source); - None - } + stream_key: &StreamKey, + ) -> Option> { + match self.stream_info(stream_key, &self.logger) { + None => { + error!(self.logger, "Can't pay for return services consumed: received response with unrecognized stream key {:?}. Ignoring", stream_key); + return None }, + Some(stream_info) => match stream_info { + None => { + error!(self.logger, "Can't pay for return services consumed: stream_info contains no expected services list", stream_key); + return None + }, + Some(info) => info.expected_services.clone() + } } } @@ -1226,6 +1190,14 @@ pub trait IBCDHelper { &self, proxy_s: &mut ProxyServer, msg: InboundClientData, + // TODO: I was wondering: could we just use msg.is_last_data here, instead of a whole different + // parameter? Then I thought no, they're not the same: is_last_data means the client won't + // send any more data, but we don't want to retire_stream_key until we've waited for any + // straggling responses from the server, so that we can pay for them. However, it turns out + // that if there is any such delay for straggling data, it's doesn't have anything to do with + // retire_stream_key, because retire_stream_key is always equal to msg.is_last_data. So we + // _could_ remove retire_stream_key and use msg.is_last_data, but I think the whole thing + // ought to be rejiggered to wait for straggling data. retire_stream_key: bool, ) -> Result<(), String>; @@ -1242,7 +1214,7 @@ trait RouteQueryResponseResolver: Send { fn resolve_message( &self, args: TransmitToHopperArgs, - add_return_route_sub: Recipient, + // add_return_route_sub: Recipient, proxy_server_sub: Recipient, route_result_opt: Result, MailboxError>, ); @@ -1253,7 +1225,7 @@ impl RouteQueryResponseResolver for RouteQueryResponseResolverReal { fn resolve_message( &self, args: TransmitToHopperArgs, - add_return_route_sub: Recipient, + // add_return_route_sub: Recipient, proxy_server_sub: Recipient, route_result_opt: Result, MailboxError>, ) { @@ -1262,7 +1234,7 @@ impl RouteQueryResponseResolver for RouteQueryResponseResolverReal { Ok(Some(route_query_response)) => { match ProxyServer::try_transmit_to_hopper( args, - add_return_route_sub, + // add_return_route_sub, route_query_response.clone(), ) { Ok(()) => Ok(route_query_response), @@ -1667,14 +1639,14 @@ mod tests { fn resolve_message( &self, args: TransmitToHopperArgs, - _add_return_route_sub: Recipient, + // _add_return_route_sub: Recipient, _proxy_server_sub: Recipient, route_result: Result, MailboxError>, ) { - self.resolve_message_params - .lock() - .unwrap() - .push((args, route_result)); + // self.resolve_message_params + // .lock() + // .unwrap() + // .push((args, route_result)); } } @@ -1845,7 +1817,7 @@ mod tests { false, ); - let result = subject.get_return_route_info(1234, "test"); + let result = subject.get_expected_services(1234, "test"); assert!( result.is_none(), @@ -1875,7 +1847,7 @@ mod tests { .route_ids_to_return_routes_first_chance .insert(1234, return_route_message.clone()); - let result = subject.get_return_route_info(1234, "test").unwrap(); + let result = subject.get_expected_services(1234, "test").unwrap(); assert_eq!(*result, return_route_message); assert_eq!( @@ -1908,7 +1880,7 @@ mod tests { .route_ids_to_return_routes_stragglers .insert(1234, return_route_message.clone()); - let result = subject.get_return_route_info(1234, "test").unwrap(); + let result = subject.get_expected_services(1234, "test").unwrap(); assert_eq!(*result, return_route_message); } diff --git a/node/src/sub_lib/neighborhood.rs b/node/src/sub_lib/neighborhood.rs index f8e93f951c..5603fb73da 100644 --- a/node/src/sub_lib/neighborhood.rs +++ b/node/src/sub_lib/neighborhood.rs @@ -502,6 +502,40 @@ pub enum ExpectedService { Nothing, } +impl ExpectedService { + pub fn exit_node_key_opt(&self) -> Option { + match self { + ExpectedService::Exit(key, _, _) => Some(key.clone()), + _ => None, + } + } + + pub fn public_key_opt(&self) -> Option { + match self { + ExpectedService::Exit(key, _, _) | ExpectedService::Routing(key, _, _) => Some(key.clone()), + _ => None, + } + } + + pub fn wallet_opt(&self) -> Option<&Wallet> { + match self { + ExpectedService::Exit(_, wallet, _) | ExpectedService::Routing(_, wallet, _) => { + Some(wallet) + } + _ => None, + } + } + + pub fn rate_pack_opt(&self) -> Option<&RatePack> { + match self { + ExpectedService::Exit(_, _, rate_pack) | ExpectedService::Routing(_, _, rate_pack) => { + Some(rate_pack) + } + _ => None, + } + } +} + #[derive(Clone, Debug, PartialEq, Eq)] pub enum ExpectedServices { OneWay(Vec), From 828ad890d04a8a82bbb38119e57defcd9d53675a Mon Sep 17 00:00:00 2001 From: Dan Wiebe Date: Wed, 24 Sep 2025 07:49:16 -0400 Subject: [PATCH 15/21] Proxy Server tests passing; some cleanup yet to do --- node/src/neighborhood/mod.rs | 19 +- node/src/proxy_server/mod.rs | 1246 ++++++++++++------------------ node/src/sub_lib/cryptde_null.rs | 1 + node/src/sub_lib/neighborhood.rs | 1 + node/src/sub_lib/stream_key.rs | 4 +- node/src/test_utils/mod.rs | 1 + 6 files changed, 526 insertions(+), 746 deletions(-) diff --git a/node/src/neighborhood/mod.rs b/node/src/neighborhood/mod.rs index f81911c0c7..12d5800546 100644 --- a/node/src/neighborhood/mod.rs +++ b/node/src/neighborhood/mod.rs @@ -998,6 +998,7 @@ impl Neighborhood { vec![ExpectedService::Nothing, ExpectedService::Nothing], vec![ExpectedService::Nothing, ExpectedService::Nothing], ), + hostname_opt: None, } } @@ -1033,13 +1034,14 @@ impl Neighborhood { hostname_opt, )?; debug!(self.logger, "Route back: {:?}", back); - self.compose_route_query_response(over, back) + self.compose_route_query_response(over, back, request_msg.hostname_opt) } fn compose_route_query_response( &mut self, over: RouteSegment, back: RouteSegment, + hostname_opt: Option, ) -> Result { let segments = vec![&over, &back]; @@ -1075,6 +1077,7 @@ impl Neighborhood { expected_request_services, expected_response_services, ), + hostname_opt }) } @@ -3343,7 +3346,7 @@ mod tests { } let addr: Addr = subject.start(); let sub: Recipient = addr.recipient::(); - let msg = RouteQueryMessage::data_indefinite_route_request(None, 54000); + let msg = RouteQueryMessage::data_indefinite_route_request(Some("booga.com".to_string()), 54000); let future = sub.send(msg); @@ -3389,6 +3392,7 @@ mod tests { ExpectedService::Nothing, ], ), + hostname_opt: Some("booga.com".to_string()), }; assert_eq!(expected_response, result); } @@ -3446,6 +3450,7 @@ mod tests { vec![ExpectedService::Nothing, ExpectedService::Nothing], vec![ExpectedService::Nothing, ExpectedService::Nothing], ), + hostname_opt: None, }; assert_eq!(result, expected_response); } @@ -3539,6 +3544,7 @@ mod tests { ExpectedService::Nothing, ], ), + hostname_opt: None, }; assert_eq!(result, expected_response); } @@ -3550,6 +3556,7 @@ mod tests { let result: Result = subject.compose_route_query_response( RouteSegment::new(vec![], Component::Neighborhood), RouteSegment::new(vec![], Component::Neighborhood), + None, ); assert!(result.is_err()); let error_expectation: String = result.expect_err("Expected an Err but got:"); @@ -4427,6 +4434,7 @@ mod tests { let result: Result = subject.compose_route_query_response( RouteSegment::new(vec![], Component::ProxyClient), RouteSegment::new(vec![], Component::ProxyServer), + None, ); assert!(result.is_err()); let error_expectation: String = result.expect_err("Expected an Err but got:"); @@ -4443,6 +4451,7 @@ mod tests { let result: Result = subject.compose_route_query_response( RouteSegment::new(vec![&PublicKey::new(&[3, 3, 8])], Component::ProxyClient), RouteSegment::new(vec![&PublicKey::new(&[8, 3, 3])], Component::ProxyServer), + None, ); assert!(result.is_err()); let error_expectation: String = result.expect_err("Expected an Err but got:"); @@ -6276,7 +6285,7 @@ mod tests { }); let tlh = TestLogHandler::new(); tlh.await_log_containing( - &format!("\"BAYFBw\" [label=\"AR v0 US\\nBAYFBw\\n4.6.5.7:4657\"];"), + "\"BAYFBw\" [label=\"AR v0 US\\nBAYFBw\\n4.6.5.7:4657\"];", 5000, ); @@ -7136,9 +7145,9 @@ mod tests { .metadata .unreachable_hosts .contains(&unreachable_host)); - TestLogHandler::new().exists_log_matching(&format!( + TestLogHandler::new().exists_log_matching( "DEBUG: Neighborhood: Marking host facebook.com unreachable for the Node with public key 0x657869745F6E6F6465" - )); + ); }); addr.try_send(AssertionsMessage { assertions }).unwrap(); System::current().stop(); diff --git a/node/src/proxy_server/mod.rs b/node/src/proxy_server/mod.rs index 2953c26853..86cb38483c 100644 --- a/node/src/proxy_server/mod.rs +++ b/node/src/proxy_server/mod.rs @@ -37,7 +37,6 @@ use crate::sub_lib::proxy_server::{ use crate::sub_lib::route::Route; use crate::sub_lib::stream_handler_pool::TransmitDataMsg; use crate::sub_lib::stream_key::StreamKey; -use crate::sub_lib::ttl_hashmap::TtlHashMap; use crate::sub_lib::utils::{handle_ui_crash_request, MessageScheduler, NODE_MAILBOX_CAPACITY}; use crate::sub_lib::wallet::Wallet; use actix::Context; @@ -53,7 +52,6 @@ use regex::Regex; use std::cell::Cell; use std::collections::HashMap; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}; -use std::rc::Rc; use std::str::FromStr; use std::time::{Duration, SystemTime}; use tokio::prelude::Future; @@ -76,10 +74,12 @@ struct ProxyServerOutSubs { schedule_stream_key_purge: Recipient>, } +#[derive(Clone)] struct StreamInfo { tunneled_host_opt: Option, dns_failure_retry_opt: Option, route_opt: Option, + protocol_opt: Option, time_to_live_opt: Option, } @@ -94,6 +94,7 @@ impl StreamInfoBuilder { tunneled_host_opt: None, dns_failure_retry_opt: None, route_opt: None, + protocol_opt: None, time_to_live_opt: None, } } @@ -114,6 +115,11 @@ impl StreamInfoBuilder { self } + pub fn protocol(mut self, protocol: ProxyProtocol) -> Self { + self.product.protocol_opt = Some(protocol); + self + } + pub fn time_to_live(mut self, ttl: SystemTime) -> Self { self.product.time_to_live_opt = Some(ttl); self @@ -190,7 +196,7 @@ impl Handler for ProxyServer { impl Handler for ProxyServer { type Result = (); - fn handle(&mut self, msg: AddReturnRouteMessage, _ctx: &mut Self::Context) -> Self::Result { + fn handle(&mut self, _msg: AddReturnRouteMessage, _ctx: &mut Self::Context) -> Self::Result { // TODO: I think this whole message should probably be deleted from the application. } } @@ -256,7 +262,7 @@ impl Handler for ProxyServer { delayed_log = Box::new(move |logger: &Logger| { error!( logger, - "AddRouteResultMessage stream key {} not found within dns_failure_retries", + "No dns_failure_retry found for stream key {} while handling AddRouteResultMessage", stream_key ); }); @@ -336,7 +342,6 @@ impl ProxyServer { is_running_in_integration_test: bool, ) -> ProxyServer { let ps_logger = Logger::new("ProxyServer"); - let hm_logger = ps_logger.clone(); ProxyServer { subs: None, client_request_payload_factory: Box::new(ClientRequestPayloadFactoryReal::new()), @@ -398,33 +403,25 @@ impl ProxyServer { } fn remove_dns_failure_retry( - &mut self, + stream_info: &mut StreamInfo, stream_key: &StreamKey, ) -> Result { - match self.stream_info.get_mut(stream_key) { + match stream_info.dns_failure_retry_opt.take() { None => { Err(format!( - "No stream_info record found for the stream_key: {:?}", + "No DNSFailureRetry entry found for the stream_key: {:?}", stream_key )) }, - Some(info) => match info.dns_failure_retry_opt.take() { - None => { - Err(format!( - "No DNSFailureRetry entry found for the stream_key: {:?}", - stream_key - )) - }, - Some(retry) => Ok(retry) - } + Some(retry) => Ok(retry) } } fn retry_dns_resolution( &mut self, - retry: DNSFailureRetry, + retry: &DNSFailureRetry, client_addr: SocketAddr, - ) -> DNSFailureRetry { + ) { let args = TransmitToHopperArgs::new( self, retry.unsuccessful_request.clone(), @@ -432,7 +429,6 @@ impl ProxyServer { SystemTime::now(), false, ); - let add_return_route_sub = self.out_subs("ProxyServer").add_return_route.clone(); let route_source = self.out_subs("Neighborhood").route_source.clone(); let proxy_server_sub = self.out_subs("ProxyServer").route_result_sub.clone(); let inbound_client_data_helper = self @@ -442,11 +438,9 @@ impl ProxyServer { inbound_client_data_helper.request_route_and_transmit( args, - add_return_route_sub, route_source, proxy_server_sub, ); - retry } fn retire_stream_key(&mut self, stream_key: &StreamKey) { @@ -474,48 +468,86 @@ impl ProxyServer { .expect("Dispatcher is dead"); } + fn get_response_services(route_query_response: &RouteQueryResponse) -> Option<&Vec> { + match &route_query_response.expected_services { + ExpectedServices::RoundTrip(_, back) => Some(back), + _ => None, + } + } + + fn find_exit_node_key(response_services: &Vec) -> Option { + match response_services.first() { + Some(ExpectedService::Exit(pk, _, _)) => Some(pk.clone()), + _ => None, + } + } + fn handle_dns_resolve_failure(&mut self, msg: &ExpiredCoresPackage) { let response = &msg.payload; - if let Some(stream_info) = self.stream_info(&response.stream_key, &self.logger) { - let exit_public_key = if !self.is_decentralized { - self.main_cryptde.public_key() + + // The idea here is that the Borrow Checker will not allow us to modify the StreamInfo in + // ProxyServer's map while we're looking at one of its values. So we're making a mutable + // copy of the StreamInfo, modifying that as necessary, and then overwriting the original + // map element with the modified copy at the end of the function. However, under certain + // circumstances we want to _retire_ the stream key; so we have a restore_stream_info + // flag that starts out true and is set to false if we retire the stream key. It's an + // ugly hack. Thanks, Borrow Checker! + let mut stream_info = match self.stream_info(&response.stream_key, &self.logger) { + Some(info) => (*info).clone(), + None => { + error!(self.logger, + "Discarding DnsResolveFailure message from an unrecognized stream key {:?}", + &response.stream_key + ); + return; } - else if - } + }; + let mut restore_stream_info = true; - let return_route_id = match self.rri_from_remaining_route(&msg.remaining_route) { - Some(rri) => rri, - None => return, // TODO: Eventually we'll have to do something better here, but we'll probably need some heuristics. + let route_query_response = match &stream_info.route_opt { + Some(route_query_response) => route_query_response, + None => { + error!( + self.logger, + "Stream info for stream key {} has no route info", + &response.stream_key + ); + return; + } }; - let return_route_info = - match self.get_expected_services(return_route_id, "dns resolve failure") { - Some(rri) => rri, - None => return, // TODO: Eventually we'll have to do something better here, but we'll probably need some heuristics. - }; - let exit_public_key = { - // ugly, ugly - let self_public_key = self.main_cryptde.public_key(); - return_route_info - .find_exit_node_key() - .unwrap_or_else(|| { - if !self.is_decentralized { - self_public_key - } else { - panic!( - "Internal error: return_route_info for {} has no exit Node", - return_route_info.return_route_id - ); - } - }) - .clone() + let response_services = match Self::get_response_services(route_query_response) { + Some(response_services) => response_services, + None => { + error!( + self.logger, + "Stream info for stream key {} has no response services in its route info", + &response.stream_key + ); + return; + } + }; + let exit_public_key = if !self.is_decentralized { + self.main_cryptde.public_key().clone() + } + else { + match Self::find_exit_node_key(response_services) { + Some(exit_public_key) => exit_public_key.clone(), + None => { + error!( + self.logger, + "Stream info for stream key {} has no exit node in its response services", + &response.stream_key + ); + return; + } + } }; - - let hostname_opt = return_route_info.hostname_opt.clone(); let response = &msg.payload; match self.keys_and_addrs.a_to_b(&response.stream_key) { Some(client_addr) => { - if let Some(server_name) = hostname_opt.clone() { + let hostname_opt = route_query_response.hostname_opt.clone(); + if let Some(ref server_name) = hostname_opt { self.subs .as_ref() .expect("Neighborhood unbound in ProxyServer") @@ -523,7 +555,7 @@ impl ProxyServer { .try_send(UpdateNodeRecordMetadataMessage { public_key: exit_public_key, metadata_change: NRMetadataChange::AddUnreachableHost { - hostname: server_name, + hostname: server_name.clone(), }, }) .expect("Neighborhood is dead"); @@ -534,40 +566,50 @@ impl ProxyServer { ); // TODO: Malefactor ban the exit node because it lied about the DNS failure. } - self.report_response_services_consumed(&return_route_info, 0, msg.payload_len); - let retry = match self.remove_dns_failure_retry(&response.stream_key) { - Ok(retry) => retry, - Err(error_msg) => { - error!( - self.logger, - "While handling ExpiredCoresPackage: {}", error_msg + self.report_response_services_consumed(response_services, 0, msg.payload_len); + if let (Some(retry_ref)) = &mut stream_info.dns_failure_retry_opt { + debug!( + self.logger, + "Handling DNS failure for hostname {:?} - stream key: {} retries left: {}", + retry_ref.unsuccessful_request.target_hostname, + &response.stream_key, + retry_ref.retries_left + ); + if retry_ref.retries_left > 0 { + self.retry_dns_resolution(retry_ref, client_addr); + retry_ref.retries_left -= 1; + } else { + restore_stream_info = false; + self.retire_stream_key(&response.stream_key); + let protocol = stream_info.protocol_opt.expect( + "StreamInfo should always have a protocol_opt set by the time we get a DNS failure" + ); + self.send_dns_failure_response_to_the_browser( + client_addr, + protocol, + hostname_opt.clone(), ); - return; } - }; - if retry.retries_left > 0 { - let mut returned_retry = self.retry_dns_resolution(retry, client_addr); - returned_retry.retries_left -= 1; - self.stream_info_mut(&response.stream_key) - .expect(&format!("Stream key {} present in keys_and_addrs but not in stream_info", &response.stream_key)) - .dns_failure_retry_opt = Some(returned_retry); } else { - self.retire_stream_key(&response.stream_key); - self.send_dns_failure_response_to_the_browser( - client_addr, - return_route_info.protocol, - hostname_opt, + error!( + self.logger, + "While handling ExpiredCoresPackage: No DNSFailureRetry entry found for the stream_key: {:?}", + &response.stream_key ); + return; } } None => { error!(self.logger, "Discarding DnsResolveFailure message for {} from an unrecognized stream key {:?}", - hostname_opt.unwrap_or_else(|| "".to_string()), + route_query_response.hostname_opt.clone().unwrap_or_else(|| "".to_string()), &response.stream_key ) } } + if restore_stream_info { + self.stream_info.insert(response.stream_key, stream_info); + } } fn schedule_stream_key_purge(&mut self, stream_key: StreamKey) { @@ -623,12 +665,12 @@ impl ProxyServer { &mut self, msg: ExpiredCoresPackage, ) { - debug!( - self.logger, - "ExpiredCoresPackage remaining_route: {}", - msg.remaining_route - .to_string(vec![self.main_cryptde, self.main_cryptde]) - ); + // debug!( + // self.logger, + // "ExpiredCoresPackage remaining_route: {}", + // msg.remaining_route + // .to_string(vec![self.main_cryptde, self.main_cryptde]) + // ); let payload_data_len = msg.payload_len; let response = msg.payload; debug!( @@ -636,36 +678,28 @@ impl ProxyServer { "Relaying ClientResponsePayload (stream key {}, sequence {}, length {}) from Hopper to Dispatcher for client", response.stream_key, response.sequenced_packet.sequence_number, response.sequenced_packet.data.len() ); - let return_route_id = match self.rri_from_remaining_route(&msg.remaining_route) { - Some(rri) => rri, - None => return, - }; - let return_route_info = match self.get_expected_services(return_route_id, "client response") - { - Some(rri) => rri, + let expected_services = match self.get_expected_return_services(&response.stream_key) { + Some(expected_services) => expected_services, None => return, }; self.report_response_services_consumed( - &return_route_info, + &expected_services, response.sequenced_packet.data.len(), payload_data_len, ); let stream_key = response.stream_key; - match self.remove_dns_failure_retry(&stream_key) { - Ok(_) => { - debug!(self.logger, "Successful attempt of DNS resolution, removing DNS retry entry for stream key: {}", &response.stream_key) - } - Err(_) => { - trace!( - self.logger, - "No DNS retry entry found for stream key: {} during a successful attempt", - &response.stream_key - ) - } - } - let stream_info_opt = self.stream_info(&stream_key, &self.logger); - let old_timestamp_opt = match stream_info_opt { - Some(info) => info.time_to_live_opt, + let old_timestamp_opt = match self.stream_info_mut(&stream_key) { + Some(info) => { + let time_to_live_opt = info.time_to_live_opt; + match ProxyServer::remove_dns_failure_retry(info, &stream_key) { + _ => trace!( + self.logger, + "No DNS retry entry found for stream key: {} during a successful attempt", + &stream_key + ) + }; + time_to_live_opt + }, None => None, }; if let Some(old_timestamp) = old_timestamp_opt { @@ -879,26 +913,12 @@ impl ProxyServer { fn try_transmit_to_hopper( args: TransmitToHopperArgs, - // add_return_route_sub: Recipient, route_query_response: RouteQueryResponse, ) -> Result<(), String> { match route_query_response.expected_services { - ExpectedServices::RoundTrip(over, back) => { - let return_route_info = AddReturnRouteMessage { - return_route_id: args.return_route_id, - expected_services: back, - protocol: args.payload.protocol, - hostname_opt: args.payload.target_hostname.clone(), - }; - debug!( - args.logger, - "Adding expectant return route info: RRI{}", args.return_route_id - ); - // add_return_route_sub - // .try_send(return_route_info) - // .expect("ProxyServer is dead"); + ExpectedServices::RoundTrip(over, _) => { ProxyServer::transmit_to_hopper(args, route_query_response.route, over) - } + }, _ => panic!("Expected RoundTrip ExpectedServices but got OneWay"), } } @@ -1084,47 +1104,35 @@ impl ProxyServer { } } - fn rri_from_remaining_route(&self, remaining_route: &Route) -> Option { - let mut mut_remaining_route = remaining_route.clone(); - mut_remaining_route - .shift(self.main_cryptde) - .expect("Internal error: remaining route in ProxyServer with no hops"); - match mut_remaining_route.return_route_id(self.main_cryptde) { - Ok(rri) => Some(rri), - Err(e) => { - error!(self.logger, "Can't report services consumed: {}", e); - None - } - } - } - - fn get_expected_services( + fn get_expected_return_services( &mut self, stream_key: &StreamKey, ) -> Option> { match self.stream_info(stream_key, &self.logger) { None => { error!(self.logger, "Can't pay for return services consumed: received response with unrecognized stream key {:?}. Ignoring", stream_key); - return None + None }, - Some(stream_info) => match stream_info { + Some(stream_info) => match &stream_info.route_opt { None => { - error!(self.logger, "Can't pay for return services consumed: stream_info contains no expected services list", stream_key); - return None + error!(self.logger, "Can't pay for return services consumed: stream_info contains no route for stream key {:?}", stream_key); + None }, - Some(info) => info.expected_services.clone() + Some(route) => match route.expected_services { + ExpectedServices::RoundTrip(_, ref return_services) => Some(return_services.clone()), + _ => panic!("Internal error: ExpectedServices in ProxyServer for stream key {:?} is not RoundTrip", stream_key), + } } } } fn report_response_services_consumed( &self, - return_route_info: &AddReturnRouteMessage, + expected_services: &Vec, exit_size: usize, routing_size: usize, ) { - let exit_service_report: ExitServiceSearch = return_route_info - .expected_services + let exit_service_report: ExitServiceSearch = expected_services .iter() .filter(|service| !matches!(service, ExpectedService::Nothing)) .fold(ZeroHop, |acc, service| { @@ -1150,8 +1158,7 @@ impl ProxyServer { ZeroHop => return, Definite(report) => report, }; - let routing_service_reports = return_route_info - .expected_services + let routing_service_reports = expected_services .iter() .flat_map(|service| match service { ExpectedService::Routing(_, wallet, rate_pack) => Some(RoutingServiceConsumed { @@ -1204,7 +1211,6 @@ pub trait IBCDHelper { fn request_route_and_transmit( &self, args: TransmitToHopperArgs, - add_return_route_sub: Recipient, route_source: Recipient, proxy_server_sub: Recipient, ); @@ -1225,7 +1231,6 @@ impl RouteQueryResponseResolver for RouteQueryResponseResolverReal { fn resolve_message( &self, args: TransmitToHopperArgs, - // add_return_route_sub: Recipient, proxy_server_sub: Recipient, route_result_opt: Result, MailboxError>, ) { @@ -1234,7 +1239,6 @@ impl RouteQueryResponseResolver for RouteQueryResponseResolverReal { Ok(Some(route_query_response)) => { match ProxyServer::try_transmit_to_hopper( args, - // add_return_route_sub, route_query_response.clone(), ) { Ok(()) => Ok(route_query_response), @@ -1334,11 +1338,11 @@ impl IBCDHelper for IBCDHelperReal { retries_left: if is_decentralized { 3 } else { 0 }, }; stream_info.dns_failure_retry_opt = Some(dns_failure_retry); + stream_info.protocol_opt = Some(payload.protocol); } } let args = TransmitToHopperArgs::new(proxy, payload, client_addr, timestamp, retire_stream_key); - let add_return_route_sub = proxy.out_subs("ProxyServer").add_return_route.clone(); let pld = &args.payload; let stream_info = proxy.stream_info(&pld.stream_key, &proxy.logger) .expect(&format!("Stream key {} disappeared!", &pld.stream_key)); @@ -1351,13 +1355,12 @@ impl IBCDHelper for IBCDHelperReal { pld.sequenced_packet.data.len() ); let route_query_response = route_query_response.clone(); - ProxyServer::try_transmit_to_hopper(args, add_return_route_sub, route_query_response) + ProxyServer::try_transmit_to_hopper(args, route_query_response) } else { let route_source = proxy.out_subs("Neighborhood").route_source.clone(); let proxy_server_sub = proxy.out_subs("ProxyServer").route_result_sub.clone(); self.request_route_and_transmit( args, - add_return_route_sub, route_source, proxy_server_sub, ); @@ -1368,7 +1371,6 @@ impl IBCDHelper for IBCDHelperReal { fn request_route_and_transmit( &self, args: TransmitToHopperArgs, - add_return_route_sub: Recipient, neighborhood_sub: Recipient, proxy_server_sub: Recipient, ) { @@ -1394,7 +1396,6 @@ impl IBCDHelper for IBCDHelperReal { .then(move |route_result| { message_resolver.resolve_message( args, - add_return_route_sub, proxy_server_sub, route_result, ); @@ -1560,7 +1561,6 @@ mod tests { use crate::sub_lib::route::Route; use crate::sub_lib::route::RouteSegment; use crate::sub_lib::sequence_buffer::SequencedPacket; - use crate::sub_lib::ttl_hashmap::TtlHashMap; use crate::sub_lib::versioned_data::VersionedData; use crate::test_utils::make_paying_wallet; use crate::test_utils::make_wallet; @@ -1575,7 +1575,6 @@ mod tests { use crate::test_utils::{alias_cryptde, rate_pack}; use crate::test_utils::{main_cryptde, make_meaningless_route}; use actix::System; - use crossbeam_channel::unbounded; use masq_lib::constants::{HTTP_PORT, TLS_PORT}; use masq_lib::test_utils::logging::init_test_logging; use masq_lib::test_utils::logging::TestLogHandler; @@ -1639,14 +1638,13 @@ mod tests { fn resolve_message( &self, args: TransmitToHopperArgs, - // _add_return_route_sub: Recipient, _proxy_server_sub: Recipient, route_result: Result, MailboxError>, ) { - // self.resolve_message_params - // .lock() - // .unwrap() - // .push((args, route_result)); + self.resolve_message_params + .lock() + .unwrap() + .push((args, route_result)); } } @@ -1781,7 +1779,6 @@ mod tests { fn request_route_and_transmit( &self, _args: TransmitToHopperArgs, - _add_return_route_sub: Recipient, _route_source: Recipient, _proxy_server_sub: Recipient, ) { @@ -1807,7 +1804,7 @@ mod tests { } #[test] - fn get_return_route_info_produces_nothing_if_nothing_exists() { + fn get_expected_services_produces_nothing_if_nothing_exists() { let mut subject = ProxyServer::new( main_cryptde(), alias_cryptde(), @@ -1816,18 +1813,19 @@ mod tests { false, false, ); + let stream_key = StreamKey::make_meaningless_stream_key(); - let result = subject.get_expected_services(1234, "test"); + let result = subject.get_expected_return_services(&stream_key); assert!( result.is_none(), - "Expected no return route info, but got: RRI{:?}", + "Expected no expected services, but got: {:?}", result ); } #[test] - fn get_return_route_info_produces_rri_from_first_chance_if_it_exists_and_moves_into_stragglers() + fn get_expected_services_produces_rri_when_it_exists() { let mut subject = ProxyServer::new( main_cryptde(), @@ -1837,52 +1835,35 @@ mod tests { false, false, ); - let return_route_message = AddReturnRouteMessage { - return_route_id: 1234, - expected_services: vec![ExpectedService::Nothing], - protocol: ProxyProtocol::TLS, - hostname_opt: None, - }; - subject - .route_ids_to_return_routes_first_chance - .insert(1234, return_route_message.clone()); - - let result = subject.get_expected_services(1234, "test").unwrap(); - - assert_eq!(*result, return_route_message); - assert_eq!( - subject.route_ids_to_return_routes_first_chance.get(&1234), - None - ); - assert_eq!( - subject.route_ids_to_return_routes_stragglers.get(&1234), - Some(Rc::new(return_route_message)) - ); - } - - #[test] - fn get_return_route_info_produces_rri_from_stragglers_if_it_exists() { - let mut subject = ProxyServer::new( - main_cryptde(), - alias_cryptde(), - true, - Some(STANDARD_CONSUMING_WALLET_BALANCE), - false, - false, + let exit_public_key = PublicKey::new(&b"exit key"[..]); + let stream_key = StreamKey::make_meaningless_stream_key(); + let back_services = vec![ExpectedService::Exit(exit_public_key, make_wallet("booga"), rate_pack(1000))]; + let expected_services = ExpectedServices::RoundTrip( + vec![], + back_services.clone() ); let return_route_message = AddReturnRouteMessage { return_route_id: 1234, - expected_services: vec![ExpectedService::Nothing], + expected_services: back_services.clone(), protocol: ProxyProtocol::TLS, hostname_opt: None, }; subject - .route_ids_to_return_routes_stragglers - .insert(1234, return_route_message.clone()); + .stream_info.insert( + stream_key.clone(), + StreamInfoBuilder::new() + .route(RouteQueryResponse{ + route: make_meaningless_route(), + expected_services: expected_services.clone(), + hostname_opt: Some("booga.com".to_string()), + }) + .build(), + ); - let result = subject.get_expected_services(1234, "test").unwrap(); + let result = subject.get_expected_return_services(&stream_key).unwrap(); - assert_eq!(*result, return_route_message); + let back = expected_services; + assert_eq!(result, back_services); } #[test] @@ -1902,6 +1883,7 @@ mod tests { vec![make_exit_service_from_key(destination_key.clone())], vec![], ), + hostname_opt: Some("booga.com".to_string()), })); let (proxy_server_mock, _, proxy_server_recording_arc) = make_recorder(); let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); @@ -2012,6 +1994,7 @@ mod tests { vec![make_exit_service_from_key(destination_key.clone())], vec![], ), + hostname_opt: Some("booga.com".to_string()), })); let route = Route { hops: vec![] }; let (dispatcher_mock, _, dispatcher_recording_arc) = make_recorder(); @@ -2148,15 +2131,15 @@ mod tests { stream_key.clone(), StreamInfoBuilder::new().build() ); - - subject.route_ids_to_return_routes_first_chance.insert( - 1234, - AddReturnRouteMessage { - return_route_id: 1234, - expected_services: vec![ExpectedService::Nothing], - protocol: ProxyProtocol::TLS, - hostname_opt: None, - }, + subject.stream_info.insert( + stream_key.clone(), + StreamInfoBuilder::new() + .route(RouteQueryResponse{ + route: make_meaningless_route(), + expected_services: ExpectedServices::RoundTrip(vec![], vec![ExpectedService::Nothing]), + hostname_opt: None, + }) + .build(), ); let subject_addr: Addr = subject.start(); let http_request = b"CONNECT https://realdomain.nu:443 HTTP/1.1\r\nHost: https://bunkjunk.wrong:443\r\n\r\n"; @@ -2652,6 +2635,7 @@ mod tests { vec![make_exit_service_from_key(destination_key.clone())], vec![], ), + hostname_opt: Some("booga.com".to_string()), })); let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); let stream_key = StreamKey::make_meaningless_stream_key(); @@ -2775,6 +2759,7 @@ mod tests { ExpectedService::Exit(PublicKey::new(&[3]), earning_wallet, rate_pack(102)), ], ), + hostname_opt: Some("booga.com".to_string()), })); let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); let stream_key = StreamKey::make_meaningless_stream_key(); @@ -2860,6 +2845,7 @@ mod tests { vec![expected_service.clone()], vec![expected_service], ), + hostname_opt: Some("booga.com".to_string()), }); let (neighborhood_mock, _, _) = make_recorder(); let neighborhood_mock = @@ -3030,6 +3016,7 @@ mod tests { vec![make_exit_service_from_key(destination_key.clone())], vec![], ), + hostname_opt: Some("booga.com".to_string()), }; let (hopper_mock, hopper_awaiter, hopper_recording_arc) = make_recorder(); let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); @@ -3183,6 +3170,7 @@ mod tests { ExpectedService::Nothing, ], ), + hostname_opt: Some("booga.com".to_string()), }; let source_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); let stream_key = StreamKey::make_meaningless_stream_key(); @@ -3220,7 +3208,6 @@ mod tests { let result = ProxyServer::try_transmit_to_hopper( args, - peer_actors.proxy_server.add_return_route, route_query_response, ); @@ -3281,8 +3268,7 @@ mod tests { } ); let recording = proxy_server_recording_arc.lock().unwrap(); - let _ = recording.get_record::(0); // don't care about this, other than type - assert_eq!(recording.len(), 1); // No StreamShutdownMsg: that's the important thing + assert_eq!(recording.len(), 0); // No StreamShutdownMsg: that's the important thing assert_eq!(result, Ok(())); } @@ -3297,6 +3283,7 @@ mod tests { vec![ExpectedService::Nothing], vec![ExpectedService::Nothing], ), + hostname_opt: Some("booga.com".to_string()), }; let source_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); let stream_key = StreamKey::make_meaningless_stream_key(); @@ -3331,24 +3318,13 @@ mod tests { let result = ProxyServer::try_transmit_to_hopper( args, - peer_actors.proxy_server.add_return_route, route_query_response, ); System::current().stop(); system.run(); let recording = proxy_server_recording_arc.lock().unwrap(); - let record = recording.get_record::(0); - assert_eq!( - record, - &AddReturnRouteMessage { - return_route_id: 3333, - expected_services: vec![ExpectedService::Nothing], - protocol: ProxyProtocol::HTTP, - hostname_opt: Some("nowhere.com".to_string()) - } - ); - let record = recording.get_record::(1); + let record = recording.get_record::(0); assert_eq!( record, &StreamShutdownMsg { @@ -3452,7 +3428,7 @@ mod tests { System::current().stop(); system.run(); - TestLogHandler::new().exists_log_containing("ERROR: ProxyServer: AddRouteResultMessage stream key AAAAAAAAAAAAAAAAAAAAAAAAAAA not found within dns_failure_retries"); + TestLogHandler::new().exists_log_containing(&format!("ERROR: ProxyServer: No dns_failure_retry found for stream key {stream_key} while handling AddRouteResultMessage")); } #[test] @@ -3594,6 +3570,7 @@ mod tests { rate_pack(103), ), ]), + hostname_opt: Some("booga.com".to_string()), }; let payload = ClientRequestPayload_0v1 { stream_key: StreamKey::make_meaningless_stream_key(), @@ -3625,7 +3602,6 @@ mod tests { let _result = ProxyServer::try_transmit_to_hopper( args, - peer_actors.proxy_server.add_return_route, route_result, ); } @@ -3662,7 +3638,7 @@ mod tests { hostname_opt: None, }; - subject.report_response_services_consumed(&add_return_route_message, 1234, 3456); + subject.report_response_services_consumed(&add_return_route_message.expected_services, 1234, 3456); } #[test] @@ -3685,6 +3661,7 @@ mod tests { .unwrap() .set_return_route_id(cryptde, 1234), expected_services: ExpectedServices::RoundTrip(vec![], vec![]), + hostname_opt: Some("booga.com".to_string()), }; let neighborhood_mock = neighborhood_mock.route_query_response(Some(route_query_response)); let dispatcher = Recorder::new(); @@ -3783,6 +3760,7 @@ mod tests { vec![make_exit_service_from_key(destination_key.clone())], vec![], ), + hostname_opt: Some("booga.com".to_string()), })); let stream_key = StreamKey::make_meaningless_stream_key(); let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); @@ -3868,6 +3846,7 @@ mod tests { vec![make_exit_service_from_key(destination_key.clone())], vec![], ), + hostname_opt: Some("booga.com".to_string()), })); let stream_key = StreamKey::make_meaningless_stream_key(); let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); @@ -3952,6 +3931,7 @@ mod tests { vec![make_exit_service_from_key(destination_key.clone())], vec![], ), + hostname_opt: Some("booga.com".to_string()), })); let client_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); let stream_key = StreamKey::make_meaningful_stream_key(test_name); @@ -4120,17 +4100,14 @@ mod tests { subject.stream_info.insert( stream_key.clone(), StreamInfoBuilder::new() + .route(RouteQueryResponse { + route: Route { hops: vec![] }, + expected_services: ExpectedServices::RoundTrip(vec![], vec![ExpectedService::Nothing]), + hostname_opt: None, + }) + .protocol(ProxyProtocol::TLS) .build() ); - subject.route_ids_to_return_routes_first_chance.insert( - 1234, - AddReturnRouteMessage { - return_route_id: 1234, - expected_services: vec![ExpectedService::Nothing], - protocol: ProxyProtocol::TLS, - hostname_opt: None, - }, - ); let subject_addr: Addr = subject.start(); let remaining_route = return_route_with_id(cryptde, 1234); let client_response_payload = ClientResponsePayload_0v1 { @@ -4168,7 +4145,7 @@ mod tests { stream_key )); tlh.exists_log_containing(&format!( - "WARN: {test_name}: Discarding 16-byte packet 12345678 from an unrecognized stream key: {:?}", + "ERROR: {test_name}: Can't pay for return services consumed: received response with unrecognized stream key {:?}. Ignoring", stream_key )); } @@ -4215,18 +4192,11 @@ mod tests { .route(RouteQueryResponse { route: Route { hops: vec![] }, expected_services: ExpectedServices::RoundTrip(vec![], vec![]), + hostname_opt: None, }) + .protocol(ProxyProtocol::HTTP) .tunneled_host("hostname") - .build() - ); - subject.route_ids_to_return_routes_first_chance.insert( - 1234, - AddReturnRouteMessage { - return_route_id: 1234, - expected_services: vec![], - protocol: ProxyProtocol::HTTP, - hostname_opt: None, - }, + .build(), ); let client_response_payload = ClientResponsePayload_0v1 { stream_key: stream_key.clone(), @@ -4248,15 +4218,6 @@ mod tests { assert!(subject.keys_and_addrs.is_empty()); assert!(subject.stream_info.get(&stream_key).is_none()); - assert!(subject - .route_ids_to_return_routes_first_chance - .get(&1234) - .is_none()); - // TODO: This assert should be much stronger - assert!(subject - .route_ids_to_return_routes_stragglers - .get(&1234) - .is_some()); } #[test] @@ -4332,19 +4293,12 @@ mod tests { .route(RouteQueryResponse { route: Route { hops: vec![] }, expected_services: ExpectedServices::RoundTrip(vec![], vec![]), + hostname_opt: None, }) + .protocol(ProxyProtocol::HTTP) .tunneled_host("hostname") .build() ); - subject.route_ids_to_return_routes_first_chance.insert( - 1234, - AddReturnRouteMessage { - return_route_id: 1234, - expected_services: vec![], - protocol: ProxyProtocol::HTTP, - hostname_opt: None, - }, - ); let proxy_server_addr = subject.start(); let schedule_stream_key_purge_sub = proxy_server_addr.clone().recipient(); let mut peer_actors = peer_actors_builder().build(); @@ -4423,38 +4377,31 @@ mod tests { subject .keys_and_addrs .insert(stream_key.clone(), socket_addr.clone()); + let exit_key = PublicKey::new(&b"blah"[..]); + let exit_wallet = make_wallet("abc"); + let exit_rates = RatePack { + routing_byte_rate: 0, + routing_service_rate: 0, + exit_byte_rate: 100, + exit_service_rate: 60000, + }; subject.stream_info.insert( stream_key.clone(), StreamInfoBuilder::new() .route(RouteQueryResponse { route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip(vec![], vec![]), + expected_services: ExpectedServices::RoundTrip(vec![], vec![ExpectedService::Exit( + exit_key, + exit_wallet.clone(), + exit_rates.clone(), + )]), + hostname_opt: None, }) .tunneled_host("hostname") + .protocol(ProxyProtocol::HTTP) .time_to_live(SystemTime::now()) .build() ); - let exit_key = PublicKey::new(&b"blah"[..]); - let exit_wallet = make_wallet("abc"); - let exit_rates = RatePack { - routing_byte_rate: 0, - routing_service_rate: 0, - exit_byte_rate: 100, - exit_service_rate: 60000, - }; - subject.route_ids_to_return_routes_first_chance.insert( - 1234, - AddReturnRouteMessage { - return_route_id: 1234, - expected_services: vec![ExpectedService::Exit( - exit_key, - exit_wallet.clone(), - exit_rates.clone(), - )], - protocol: ProxyProtocol::HTTP, - hostname_opt: None, - }, - ); let (accountant, _, accountant_recording_arc) = make_recorder(); let (dispatcher, _, dispatcher_recording_arc) = make_recorder(); let proxy_server_addr = subject.start(); @@ -4525,74 +4472,38 @@ mod tests { subject .keys_and_addrs .insert(stream_key.clone(), socket_addr.clone()); - subject.stream_info.insert( - stream_key.clone(), - StreamInfoBuilder::new() - .build() - ); let incoming_route_d_wallet = make_wallet("D Earning"); let incoming_route_e_wallet = make_wallet("E Earning"); let incoming_route_f_wallet = make_wallet("F Earning"); let rate_pack_d = rate_pack(101); let rate_pack_e = rate_pack(102); let rate_pack_f = rate_pack(103); - subject.route_ids_to_return_routes_first_chance.insert( - 1234, - AddReturnRouteMessage { - return_route_id: 1234, - expected_services: vec![ - ExpectedService::Exit( - irrelevant_public_key.clone(), - incoming_route_d_wallet.clone(), - rate_pack_d, - ), - ExpectedService::Routing( - irrelevant_public_key.clone(), - incoming_route_e_wallet.clone(), - rate_pack_e, - ), - ExpectedService::Routing( - irrelevant_public_key.clone(), - incoming_route_f_wallet.clone(), - rate_pack_f, - ), - ExpectedService::Nothing, - ], - protocol: ProxyProtocol::TLS, - hostname_opt: None, - }, - ); - let incoming_route_g_wallet = make_wallet("G Earning"); - let incoming_route_h_wallet = make_wallet("H Earning"); - let incoming_route_i_wallet = make_wallet("I Earning"); - let rate_pack_g = rate_pack(104); - let rate_pack_h = rate_pack(105); - let rate_pack_i = rate_pack(106); - subject.route_ids_to_return_routes_first_chance.insert( - 1235, - AddReturnRouteMessage { - return_route_id: 1235, - expected_services: vec![ - ExpectedService::Exit( - irrelevant_public_key.clone(), - incoming_route_g_wallet.clone(), - rate_pack_g, - ), - ExpectedService::Routing( - irrelevant_public_key.clone(), - incoming_route_h_wallet.clone(), - rate_pack_h, - ), - ExpectedService::Routing( - irrelevant_public_key.clone(), - incoming_route_i_wallet.clone(), - rate_pack_i, - ), - ExpectedService::Nothing, - ], - protocol: ProxyProtocol::TLS, - hostname_opt: None, - }, + subject.stream_info.insert( + stream_key.clone(), + StreamInfoBuilder::new() + .route(RouteQueryResponse { + route: Route { hops: vec![] }, + expected_services: ExpectedServices::RoundTrip(vec![], vec![ + ExpectedService::Exit( + irrelevant_public_key.clone(), + incoming_route_d_wallet.clone(), + rate_pack_d, + ), + ExpectedService::Routing( + irrelevant_public_key.clone(), + incoming_route_e_wallet.clone(), + rate_pack_e, + ), + ExpectedService::Routing( + irrelevant_public_key.clone(), + incoming_route_f_wallet.clone(), + rate_pack_f, + ), + ExpectedService::Nothing, + ]), + hostname_opt: None, + }) + .build() ); let subject_addr: Addr = subject.start(); let first_client_response_payload = ClientResponsePayload_0v1 { @@ -4664,7 +4575,7 @@ mod tests { &ReportServicesConsumedMessage { timestamp: first_report_timestamp, exit: ExitServiceConsumed { - earning_wallet: incoming_route_d_wallet, + earning_wallet: incoming_route_d_wallet.clone(), payload_size: first_exit_size, service_rate: rate_pack_d.exit_service_rate, byte_rate: rate_pack_d.exit_byte_rate @@ -4672,12 +4583,12 @@ mod tests { routing_payload_size: routing_size, routing: vec![ RoutingServiceConsumed { - earning_wallet: incoming_route_e_wallet, + earning_wallet: incoming_route_e_wallet.clone(), service_rate: rate_pack_e.routing_service_rate, byte_rate: rate_pack_e.routing_byte_rate }, RoutingServiceConsumed { - earning_wallet: incoming_route_f_wallet, + earning_wallet: incoming_route_f_wallet.clone(), service_rate: rate_pack_f.routing_service_rate, byte_rate: rate_pack_f.routing_byte_rate } @@ -4693,22 +4604,22 @@ mod tests { &ReportServicesConsumedMessage { timestamp: second_report_timestamp, exit: ExitServiceConsumed { - earning_wallet: incoming_route_g_wallet, + earning_wallet: incoming_route_d_wallet, payload_size: second_exit_size, - service_rate: rate_pack_g.exit_service_rate, - byte_rate: rate_pack_g.exit_byte_rate + service_rate: rate_pack_d.exit_service_rate, + byte_rate: rate_pack_d.exit_byte_rate }, routing_payload_size: routing_size, routing: vec![ RoutingServiceConsumed { - earning_wallet: incoming_route_h_wallet, - service_rate: rate_pack_h.routing_service_rate, - byte_rate: rate_pack_h.routing_byte_rate + earning_wallet: incoming_route_e_wallet, + service_rate: rate_pack_e.routing_service_rate, + byte_rate: rate_pack_e.routing_byte_rate }, RoutingServiceConsumed { - earning_wallet: incoming_route_i_wallet, - service_rate: rate_pack_i.routing_service_rate, - byte_rate: rate_pack_i.routing_byte_rate + earning_wallet: incoming_route_f_wallet, + service_rate: rate_pack_f.routing_service_rate, + byte_rate: rate_pack_f.routing_byte_rate } ] } @@ -4742,6 +4653,12 @@ mod tests { subject.logger = Logger::new(test_name); let mut dns_fail_client_payload = make_request_payload(111, cryptde); dns_fail_client_payload.stream_key = stream_key; + let incoming_route_d_wallet = make_wallet("D Earning"); + let incoming_route_e_wallet = make_wallet("E Earning"); + let incoming_route_f_wallet = make_wallet("F Earning"); + let rate_pack_d = rate_pack(101); + let rate_pack_e = rate_pack(102); + let rate_pack_f = rate_pack(103); subject.stream_info.insert( stream_key_clone.clone(), StreamInfoBuilder::new() @@ -4749,40 +4666,31 @@ mod tests { unsuccessful_request: dns_fail_client_payload, retries_left: 3, }) + .route(RouteQueryResponse{ + route: Route { hops: vec![] }, + expected_services: ExpectedServices::RoundTrip(vec![], vec![ + ExpectedService::Exit( + irrelevant_public_key.clone(), + incoming_route_d_wallet.clone(), + rate_pack_d, + ), + ExpectedService::Routing( + irrelevant_public_key.clone(), + incoming_route_e_wallet.clone(), + rate_pack_e, + ), + ExpectedService::Routing( + irrelevant_public_key.clone(), + incoming_route_f_wallet.clone(), + rate_pack_f, + ), + ExpectedService::Nothing, + ]), + hostname_opt: None, + }) + .protocol(ProxyProtocol::TLS) .build() ); - let incoming_route_d_wallet = make_wallet("D Earning"); - let incoming_route_e_wallet = make_wallet("E Earning"); - let incoming_route_f_wallet = make_wallet("F Earning"); - let rate_pack_d = rate_pack(101); - let rate_pack_e = rate_pack(102); - let rate_pack_f = rate_pack(103); - subject.route_ids_to_return_routes_first_chance.insert( - 1234, - AddReturnRouteMessage { - return_route_id: 1234, - expected_services: vec![ - ExpectedService::Exit( - irrelevant_public_key.clone(), - incoming_route_d_wallet.clone(), - rate_pack_d, - ), - ExpectedService::Routing( - irrelevant_public_key.clone(), - incoming_route_e_wallet.clone(), - rate_pack_e, - ), - ExpectedService::Routing( - irrelevant_public_key.clone(), - incoming_route_f_wallet.clone(), - rate_pack_f, - ), - ExpectedService::Nothing, - ], - protocol: ProxyProtocol::TLS, - hostname_opt: None, - }, - ); let subject_addr: Addr = subject.start(); let first_client_response_payload = ClientResponsePayload_0v1 { stream_key, @@ -4815,7 +4723,6 @@ mod tests { .unwrap(); System::current().stop(); system.run(); - TestLogHandler::new().exists_log_containing(&format!("DEBUG: {test_name}: Successful attempt of DNS resolution, removing DNS retry entry for stream key: {stream_key_clone}")); } #[test] @@ -4836,33 +4743,31 @@ mod tests { let stream_key = StreamKey::make_meaningless_stream_key(); let irrelevant_public_key = PublicKey::from(&b"irrelevant"[..]); // subject.keys_and_addrs contains no browser stream - subject.stream_info.insert( - stream_key.clone(), - StreamInfoBuilder::new().build() - ); let incoming_route_d_wallet = make_wallet("D Earning"); let incoming_route_e_wallet = make_wallet("E Earning"); let rate_pack_d = rate_pack(101); let rate_pack_e = rate_pack(102); - subject.route_ids_to_return_routes_first_chance.insert( - 1234, - AddReturnRouteMessage { - return_route_id: 1234, - expected_services: vec![ - ExpectedService::Exit( - irrelevant_public_key.clone(), - incoming_route_d_wallet.clone(), - rate_pack_d, - ), - ExpectedService::Routing( - irrelevant_public_key.clone(), - incoming_route_e_wallet.clone(), - rate_pack_e, - ), - ], - protocol: ProxyProtocol::TLS, - hostname_opt: None, - }, + subject.stream_info.insert( + stream_key.clone(), + StreamInfoBuilder::new() + .route(RouteQueryResponse{ + route: Route { hops: vec![] }, + expected_services: ExpectedServices::RoundTrip(vec![], vec![ + ExpectedService::Exit( + irrelevant_public_key.clone(), + incoming_route_d_wallet.clone(), + rate_pack_d, + ), + ExpectedService::Routing( + irrelevant_public_key.clone(), + incoming_route_e_wallet.clone(), + rate_pack_e, + ), + ]), + hostname_opt: None, + }) + .protocol(ProxyProtocol::TLS) + .build() ); let subject_addr: Addr = subject.start(); let client_response_payload = ClientResponsePayload_0v1 { @@ -4942,6 +4847,8 @@ mod tests { let stream_key = StreamKey::make_meaningless_stream_key(); let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); let client_payload = make_request_payload(111, cryptde); + let exit_public_key = PublicKey::from(&b"exit_key"[..]); + let exit_wallet = make_wallet("exit wallet"); subject .keys_and_addrs .insert(stream_key.clone(), socket_addr.clone()); @@ -4952,10 +4859,18 @@ mod tests { unsuccessful_request: client_payload, retries_left: 0, }) + .route(RouteQueryResponse{ + route: Route { hops: vec![] }, + expected_services: ExpectedServices::RoundTrip(vec![], vec![ExpectedService::Exit( + exit_public_key.clone(), + exit_wallet, + rate_pack(10), + )]), + hostname_opt: Some("server.com".to_string()), + }) + .protocol(ProxyProtocol::HTTP) .build() ); - let exit_public_key = PublicKey::from(&b"exit_key"[..]); - let exit_wallet = make_wallet("exit wallet"); let subject_addr: Addr = subject.start(); let dns_resolve_failure = DnsResolveFailure_0v1::new(stream_key); let expired_cores_package: ExpiredCoresPackage = @@ -4969,18 +4884,6 @@ mod tests { let peer_actors = peer_actors_builder().dispatcher(dispatcher_mock).build(); subject_addr.try_send(BindMessage { peer_actors }).unwrap(); - subject_addr - .try_send(AddReturnRouteMessage { - return_route_id: 1234, - expected_services: vec![ExpectedService::Exit( - exit_public_key.clone(), - exit_wallet, - rate_pack(10), - )], - protocol: ProxyProtocol::HTTP, - hostname_opt: Some("server.com".to_string()), - }) - .unwrap(); subject_addr.try_send(expired_cores_package).unwrap(); System::current().stop(); @@ -5017,15 +4920,6 @@ mod tests { let stream_key = StreamKey::make_meaningless_stream_key(); let irrelevant_public_key = PublicKey::from(&b"irrelevant"[..]); let client_payload = make_request_payload(111, cryptde); - subject.stream_info.insert( - stream_key.clone(), - StreamInfoBuilder::new() - .dns_failure_retry(DNSFailureRetry{ - unsuccessful_request: client_payload, - retries_left: 0, - }) - .build() - ); subject .keys_and_addrs .insert(stream_key.clone(), socket_addr.clone()); @@ -5035,31 +4929,37 @@ mod tests { let rate_pack_d = rate_pack(101); let rate_pack_e = rate_pack(102); let rate_pack_f = rate_pack(103); - subject.route_ids_to_return_routes_first_chance.insert( - 1234, - AddReturnRouteMessage { - return_route_id: 1234, - expected_services: vec![ - ExpectedService::Exit( - irrelevant_public_key.clone(), - incoming_route_d_wallet.clone(), - rate_pack_d, - ), - ExpectedService::Routing( - irrelevant_public_key.clone(), - incoming_route_e_wallet.clone(), - rate_pack_e, - ), - ExpectedService::Routing( - irrelevant_public_key.clone(), - incoming_route_f_wallet.clone(), - rate_pack_f, - ), - ExpectedService::Nothing, - ], - protocol: ProxyProtocol::TLS, - hostname_opt: Some("server.com".to_string()), - }, + subject.stream_info.insert( + stream_key.clone(), + StreamInfoBuilder::new() + .dns_failure_retry(DNSFailureRetry{ + unsuccessful_request: client_payload, + retries_left: 0, + }) + .route(RouteQueryResponse{ + route: Route { hops: vec![] }, + expected_services: ExpectedServices::RoundTrip(vec![], vec![ + ExpectedService::Exit( + irrelevant_public_key.clone(), + incoming_route_d_wallet.clone(), + rate_pack_d, + ), + ExpectedService::Routing( + irrelevant_public_key.clone(), + incoming_route_e_wallet.clone(), + rate_pack_e, + ), + ExpectedService::Routing( + irrelevant_public_key.clone(), + incoming_route_f_wallet.clone(), + rate_pack_f, + ), + ExpectedService::Nothing, + ]), + hostname_opt: None, + }) + .protocol(ProxyProtocol::TLS) + .build() ); let subject_addr: Addr = subject.start(); let dns_resolve_failure_payload = DnsResolveFailure_0v1::new(stream_key); @@ -5135,6 +5035,11 @@ mod tests { let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); let client_payload = make_request_payload(111, cryptde); subject.logger = Logger::new(test_name); + subject + .keys_and_addrs + .insert(stream_key.clone(), socket_addr.clone()); + let exit_public_key = PublicKey::from(&b"exit_key"[..]); + let exit_wallet = make_wallet("exit wallet"); subject.stream_info.insert( stream_key.clone(), StreamInfoBuilder::new() @@ -5142,26 +5047,18 @@ mod tests { unsuccessful_request: client_payload, retries_left: 0, }) + .route(RouteQueryResponse{ + route: Route { hops: vec![] }, + expected_services: ExpectedServices::RoundTrip(vec![], vec![ExpectedService::Exit( + exit_public_key.clone(), + exit_wallet.clone(), + rate_pack(10), + )]), + hostname_opt: Some("server.com".to_string()), + }) + .protocol(ProxyProtocol::HTTP) .build() ); - subject - .keys_and_addrs - .insert(stream_key.clone(), socket_addr.clone()); - let exit_public_key = PublicKey::from(&b"exit_key"[..]); - let exit_wallet = make_wallet("exit wallet"); - subject.route_ids_to_return_routes_first_chance.insert( - 1234, - AddReturnRouteMessage { - return_route_id: 1234, - expected_services: vec![ExpectedService::Exit( - exit_public_key.clone(), - exit_wallet, - rate_pack(10), - )], - protocol: ProxyProtocol::HTTP, - hostname_opt: Some("server.com".to_string()), - }, - ); let subject_addr: Addr = subject.start(); let dns_resolve_failure = DnsResolveFailure_0v1::new(stream_key); let expired_cores_package: ExpiredCoresPackage = @@ -5217,6 +5114,11 @@ mod tests { let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); let client_payload = make_request_payload(111, cryptde); subject.logger = Logger::new(test_name); + subject + .keys_and_addrs + .insert(stream_key.clone(), socket_addr); + let exit_public_key = PublicKey::from(&b"exit_key"[..]); + let exit_wallet = make_wallet("exit wallet"); subject.stream_info.insert( stream_key, StreamInfoBuilder::new() @@ -5224,26 +5126,18 @@ mod tests { unsuccessful_request: client_payload, retries_left: 0, }) + .route(RouteQueryResponse{ + route: Route { hops: vec![] }, + expected_services: ExpectedServices::RoundTrip(vec![], vec![ExpectedService::Exit( + exit_public_key.clone(), + exit_wallet, + rate_pack(10), + )]), + hostname_opt: None, + }) + .protocol(ProxyProtocol::HTTP) .build() ); - subject - .keys_and_addrs - .insert(stream_key.clone(), socket_addr); - let exit_public_key = PublicKey::from(&b"exit_key"[..]); - let exit_wallet = make_wallet("exit wallet"); - subject.route_ids_to_return_routes_first_chance.insert( - 1234, - AddReturnRouteMessage { - return_route_id: 1234, - expected_services: vec![ExpectedService::Exit( - exit_public_key.clone(), - exit_wallet, - rate_pack(10), - )], - protocol: ProxyProtocol::HTTP, - hostname_opt: None, - }, - ); let subject_addr: Addr = subject.start(); let dns_resolve_failure = DnsResolveFailure_0v1::new(stream_key); let expired_cores_package: ExpiredCoresPackage = @@ -5266,12 +5160,13 @@ mod tests { neighborhood_recording.get_record_opt::(0); assert_eq!(record_opt, None); TestLogHandler::new().exists_log_containing(&format!( - "ERROR: {test_name}: Exit node {exit_public_key} complained of DNS failure, but was given no hostname to resolve." + "ERROR: {}: Exit node {} complained of DNS failure, but was given no hostname to resolve.", + test_name, &exit_public_key )); } #[test] - fn handle_dns_resolve_failure_logs_when_stream_key_be_gone_but_server_name_be_not() { + fn handle_dns_resolve_failure_logs_when_stream_key_is_found_in_stream_info_but_not_keys_and_addrs() { init_test_logging(); let system = System::new("test"); let (neighborhood_mock, _, _) = make_recorder(); @@ -5288,6 +5183,8 @@ mod tests { let return_route_id = 1234; let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); let client_payload = make_request_payload(111, cryptde); + let exit_public_key = PublicKey::from(&b"exit_key"[..]); + let exit_wallet = make_wallet("exit wallet"); subject.stream_info.insert( stream_key, StreamInfoBuilder::new() @@ -5295,26 +5192,18 @@ mod tests { unsuccessful_request: client_payload, retries_left: 0, }) + .route(RouteQueryResponse{ + route: Route { hops: vec![] }, + expected_services: ExpectedServices::RoundTrip(vec![], vec![ExpectedService::Exit( + exit_public_key.clone(), + exit_wallet.clone(), + rate_pack(10), + )]), + hostname_opt: Some("server.com".to_string()), + }) + .protocol(ProxyProtocol::HTTP) .build() ); - subject - .keys_and_addrs - .insert(stream_key.clone(), socket_addr.clone()); - let exit_public_key = PublicKey::from(&b"exit_key"[..]); - let exit_wallet = make_wallet("exit wallet"); - subject.route_ids_to_return_routes_first_chance.insert( - return_route_id, - AddReturnRouteMessage { - return_route_id, - expected_services: vec![ExpectedService::Exit( - exit_public_key.clone(), - exit_wallet, - rate_pack(10), - )], - protocol: ProxyProtocol::HTTP, - hostname_opt: Some("server.com".to_string()), - }, - ); let subject_addr: Addr = subject.start(); let dns_resolve_failure = DnsResolveFailure_0v1::new(stream_key); let expired_cores_package: ExpiredCoresPackage = @@ -5365,6 +5254,11 @@ mod tests { let return_route_id = 1234; let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); let client_payload = make_request_payload(111, cryptde); + subject + .keys_and_addrs + .insert(stream_key.clone(), socket_addr.clone()); + let exit_public_key = PublicKey::from(&b"exit_key"[..]); + let exit_wallet = make_wallet("exit wallet"); subject.stream_info.insert( stream_key, StreamInfoBuilder::new() @@ -5372,26 +5266,18 @@ mod tests { unsuccessful_request: client_payload, retries_left: 0, }) + .route(RouteQueryResponse{ + route: Route { hops: vec![] }, + expected_services: ExpectedServices::RoundTrip(vec![], vec![ExpectedService::Exit( + exit_public_key.clone(), + exit_wallet.clone(), + rate_pack(10), + )]), + hostname_opt: None, + }) + .protocol(ProxyProtocol::HTTP) .build() ); - subject - .keys_and_addrs - .insert(stream_key.clone(), socket_addr.clone()); - let exit_public_key = PublicKey::from(&b"exit_key"[..]); - let exit_wallet = make_wallet("exit wallet"); - subject.route_ids_to_return_routes_first_chance.insert( - return_route_id, - AddReturnRouteMessage { - return_route_id, - expected_services: vec![ExpectedService::Exit( - exit_public_key.clone(), - exit_wallet, - rate_pack(10), - )], - protocol: ProxyProtocol::HTTP, - hostname_opt: None, - }, - ); let subject_addr: Addr = subject.start(); let dns_resolve_failure = DnsResolveFailure_0v1::new(stream_key); let expired_cores_package: ExpiredCoresPackage = @@ -5417,7 +5303,7 @@ mod tests { system.run(); TestLogHandler::new().exists_log_containing( &format!( - "Discarding DnsResolveFailure message for from an unrecognized stream key {:?}", + "Discarding DnsResolveFailure message from an unrecognized stream key {:?}", stream_key ) ); @@ -5447,6 +5333,9 @@ mod tests { let stream_key = StreamKey::make_meaningless_stream_key(); let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); let client_payload = make_request_payload(111, cryptde); + subject + .keys_and_addrs + .insert(stream_key.clone(), socket_addr.clone()); subject.stream_info.insert( stream_key, StreamInfoBuilder::new() @@ -5457,25 +5346,18 @@ mod tests { .tunneled_host("tunneled host") .route(RouteQueryResponse { route: Route { hops: vec![] }, - expected_services: ExpectedServices::OneWay(vec![]), + expected_services: ExpectedServices::RoundTrip( + vec![], + vec![ + make_exit_service_from_key(PublicKey::new(b"exit_node")), + ExpectedService::Nothing, + ] + ), + hostname_opt: None, }) + .protocol(ProxyProtocol::HTTP) .build() ); - subject - .keys_and_addrs - .insert(stream_key.clone(), socket_addr.clone()); - subject.route_ids_to_return_routes_first_chance.insert( - 1234, - AddReturnRouteMessage { - return_route_id: 1234, - expected_services: vec![ - make_exit_service_from_key(PublicKey::new(b"exit_node")), - ExpectedService::Nothing, - ], - protocol: ProxyProtocol::HTTP, - hostname_opt: None, - }, - ); let dns_resolve_failure = DnsResolveFailure_0v1::new(stream_key); let expired_cores_package: ExpiredCoresPackage = ExpiredCoresPackage::new( @@ -5510,6 +5392,9 @@ mod tests { let stream_key = StreamKey::make_meaningless_stream_key(); let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); let client_payload = make_request_payload(111, cryptde); + subject + .keys_and_addrs + .insert(stream_key.clone(), socket_addr.clone()); subject.stream_info.insert( stream_key.clone(), StreamInfoBuilder::new() @@ -5517,20 +5402,14 @@ mod tests { unsuccessful_request: client_payload, retries_left: 0, }) + .route(RouteQueryResponse{ + route: Route { hops: vec![] }, + expected_services: ExpectedServices::RoundTrip(vec![], vec![ExpectedService::Nothing, ExpectedService::Nothing]), + hostname_opt: Some("server.com".to_string()), + }) + .protocol(ProxyProtocol::HTTP) .build() ); - subject - .keys_and_addrs - .insert(stream_key.clone(), socket_addr.clone()); - subject.route_ids_to_return_routes_first_chance.insert( - 1234, - AddReturnRouteMessage { - return_route_id: 1234, - expected_services: vec![ExpectedService::Nothing, ExpectedService::Nothing], - protocol: ProxyProtocol::HTTP, - hostname_opt: Some("server.com".to_string()), - }, - ); let subject_addr: Addr = subject.start(); let dns_resolve_failure = DnsResolveFailure_0v1::new(stream_key); let expired_cores_package: ExpiredCoresPackage = @@ -5596,6 +5475,7 @@ mod tests { expected_services.clone(), expected_services.clone(), ), + hostname_opt: Some("booga.com".to_string()), }; let neighborhood_mock = neighborhood_mock .system_stop_conditions(match_every_type_id!(RouteQueryMessage)) @@ -5612,6 +5492,9 @@ mod tests { let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); let client_payload = make_request_payload(111, cryptde); let stream_key = client_payload.stream_key; + subject + .keys_and_addrs + .insert(stream_key.clone(), socket_addr.clone()); subject.stream_info.insert( stream_key.clone(), StreamInfoBuilder::new() @@ -5619,20 +5502,14 @@ mod tests { unsuccessful_request: client_payload.clone(), retries_left: 3, }) + .route(RouteQueryResponse{ + route: Route { hops: vec![] }, + expected_services: ExpectedServices::RoundTrip(vec![], expected_services.clone()), + hostname_opt: Some("server.com".to_string()), + }) + .protocol(ProxyProtocol::HTTP) .build() ); - subject - .keys_and_addrs - .insert(stream_key.clone(), socket_addr.clone()); - subject.route_ids_to_return_routes_first_chance.insert( - 1234, - AddReturnRouteMessage { - return_route_id: 1234, - expected_services: expected_services.clone(), - protocol: ProxyProtocol::HTTP, - hostname_opt: Some("server.com".to_string()), - }, - ); let message_resolver = RouteQueryResponseResolverMock::default() .resolve_message_params(&resolve_message_params_arc); let message_resolver_factory = RouteQueryResponseResolverFactoryMock::default() @@ -5660,7 +5537,9 @@ mod tests { subject_addr .try_send(AssertionsMessage { assertions: Box::new(move |proxy_server: &mut ProxyServer| { - let retry = proxy_server.stream_info(&stream_key, &logger).unwrap().dns_failure_retry_opt + let retry = proxy_server + .stream_info(&stream_key, &logger) + .unwrap().dns_failure_retry_opt .as_ref() .unwrap(); assert_eq!(retry.retries_left, 2); @@ -5687,10 +5566,10 @@ mod tests { } #[test] - fn handle_dns_resolve_failure_logs_error_when_there_is_no_entry_in_the_hashmap_for_the_stream_key( + fn handle_dns_resolve_failure_logs_error_when_there_is_no_dns_failure_retry_entry_for_the_stream_key( ) { init_test_logging(); - let test_name = "handle_dns_resolve_failure_logs_error_when_there_is_no_entry_in_the_hashmap_for_the_stream_key"; + let test_name = "handle_dns_resolve_failure_logs_error_when_there_is_no_dns_failure_retry_entry_for_the_stream_key"; let system = System::new(test_name); let exit_public_key = PublicKey::from(&b"exit_key"[..]); let exit_wallet = make_wallet("exit wallet"); @@ -5714,14 +5593,16 @@ mod tests { subject .keys_and_addrs .insert(stream_key.clone(), socket_addr.clone()); - subject.route_ids_to_return_routes_first_chance.insert( - 1234, - AddReturnRouteMessage { - return_route_id: 1234, - expected_services: expected_services.clone(), - protocol: ProxyProtocol::HTTP, - hostname_opt: Some("server.com".to_string()), - }, + subject.stream_info.insert( + stream_key.clone(), + StreamInfoBuilder::new() + .route(RouteQueryResponse{ + route: Route { hops: vec![] }, + expected_services: ExpectedServices::RoundTrip(vec![], expected_services.clone()), + hostname_opt: Some("server.com".to_string()), + }) + .protocol(ProxyProtocol::HTTP) + .build() ); let subject_addr: Addr = subject.start(); let dns_resolve_failure = DnsResolveFailure_0v1::new(stream_key); @@ -5742,7 +5623,7 @@ mod tests { system.run(); TestLogHandler::new().exists_log_containing(&format!( "ERROR: {test_name}: While \ - handling ExpiredCoresPackage: No stream_info record found for the stream_key: AAAAAAAAAAAAAAAAAAAAAAAAAAA" + handling ExpiredCoresPackage: No DNSFailureRetry entry found for the stream_key: {stream_key}" )); } @@ -5766,6 +5647,7 @@ mod tests { expected_services.clone(), expected_services.clone(), ), + hostname_opt: Some("booga.com".to_string()), }; let neighborhood_mock = neighborhood_mock .system_stop_conditions(match_every_type_id!( @@ -5788,6 +5670,9 @@ mod tests { let client_payload = make_request_payload(111, cryptde); let stream_key = client_payload.stream_key; let stream_key_clone = stream_key.clone(); + subject + .keys_and_addrs + .insert(stream_key.clone(), socket_addr.clone()); subject.stream_info.insert( stream_key_clone.clone(), StreamInfoBuilder::new() @@ -5795,20 +5680,14 @@ mod tests { unsuccessful_request: client_payload, retries_left: 3, }) + .route(RouteQueryResponse{ + route: Route { hops: vec![] }, + expected_services: ExpectedServices::RoundTrip(vec![], expected_services.clone()), + hostname_opt: Some("server.com".to_string()), + }) + .protocol(ProxyProtocol::HTTP) .build() ); - subject - .keys_and_addrs - .insert(stream_key.clone(), socket_addr.clone()); - subject.route_ids_to_return_routes_first_chance.insert( - 1234, - AddReturnRouteMessage { - return_route_id: 1234, - expected_services: expected_services.clone(), - protocol: ProxyProtocol::HTTP, - hostname_opt: Some("server.com".to_string()), - }, - ); let message_resolver_factory = RouteQueryResponseResolverFactoryMock::default() .make_params(&make_params_arc) .make_result(Box::new(RouteQueryResponseResolverMock::default())) @@ -5878,19 +5757,17 @@ mod tests { subject .keys_and_addrs .insert(stream_key.clone(), socket_addr.clone()); + let remaining_route = return_route_with_id(cryptde, 4321); subject.stream_info.insert( stream_key.clone(), - StreamInfoBuilder::new().build() - ); - let remaining_route = return_route_with_id(cryptde, 4321); - subject.route_ids_to_return_routes_first_chance.insert( - 4321, - AddReturnRouteMessage { - return_route_id: 4321, - expected_services: vec![ExpectedService::Nothing], - protocol: ProxyProtocol::HTTP, - hostname_opt: None, - }, + StreamInfoBuilder::new() + .route(RouteQueryResponse{ + route: Route { hops: vec![] }, + expected_services: ExpectedServices::RoundTrip(vec![], vec![ExpectedService::Nothing]), + hostname_opt: None, + }) + .protocol(ProxyProtocol::HTTP) + .build() ); let subject_addr: Addr = subject.start(); @@ -5975,58 +5852,7 @@ mod tests { .accountant(accountant) .build(); let client_response_payload = ClientResponsePayload_0v1 { - stream_key, - sequenced_packet: SequencedPacket { - data: b"some data".to_vec(), - sequence_number: 4321, - last_data: false, - }, - }; - let expired_cores_package = ExpiredCoresPackage::new( - SocketAddr::from_str("1.2.3.4:1234").unwrap(), - Some(make_wallet("irrelevant")), - return_route_with_id(cryptde, return_route_id), - client_response_payload, - 0, - ); - subject_addr.try_send(BindMessage { peer_actors }).unwrap(); - - subject_addr.try_send(expired_cores_package).unwrap(); - - System::current().stop(); - system.run(); - TestLogHandler::new().exists_log_containing(format!("ERROR: ProxyServer: Can't report services consumed: received response with bogus return-route ID RRI{} for client response. Ignoring", return_route_id).as_str()); - assert_eq!(dispatcher_recording_arc.lock().unwrap().len(), 0); - assert_eq!(accountant_recording_arc.lock().unwrap().len(), 0); - } - - #[test] - fn report_response_services_consumed_complains_and_drops_package_if_return_route_id_is_unreadable( - ) { - init_test_logging(); - let cryptde = main_cryptde(); - let (dispatcher, _, dispatcher_recording_arc) = make_recorder(); - let (accountant, _, accountant_recording_arc) = make_recorder(); - let system = System::new("report_response_services_consumed_complains_and_drops_package_if_return_route_id_is_unreadable"); - let mut subject = ProxyServer::new( - cryptde, - alias_cryptde(), - true, - Some(STANDARD_CONSUMING_WALLET_BALANCE), - false, - false, - ); - let stream_key = StreamKey::make_meaningless_stream_key(); - subject - .keys_and_addrs - .insert(stream_key, SocketAddr::from_str("1.2.3.4:5678").unwrap()); - let subject_addr: Addr = subject.start(); - let peer_actors = peer_actors_builder() - .dispatcher(dispatcher) - .accountant(accountant) - .build(); - let client_response_payload = ClientResponsePayload_0v1 { - stream_key, + stream_key: stream_key.clone(), sequenced_packet: SequencedPacket { data: b"some data".to_vec(), sequence_number: 4321, @@ -6036,9 +5862,7 @@ mod tests { let expired_cores_package = ExpiredCoresPackage::new( SocketAddr::from_str("1.2.3.4:1234").unwrap(), Some(make_wallet("irrelevant")), - Route { - hops: vec![make_cover_hop(cryptde), CryptData::new(&[0])], - }, + return_route_with_id(cryptde, 0 /* dummy */), client_response_payload, 0, ); @@ -6048,76 +5872,11 @@ mod tests { System::current().stop(); system.run(); - TestLogHandler::new().exists_log_containing( - "ERROR: ProxyServer: Can't report services consumed: DecryptionError(InvalidKey(\"Could not decrypt with", - ); + TestLogHandler::new().exists_log_containing(format!("ERROR: ProxyServer: Can't pay for return services consumed: received response with unrecognized stream key {}. Ignoring", stream_key).as_str()); assert_eq!(dispatcher_recording_arc.lock().unwrap().len(), 0); assert_eq!(accountant_recording_arc.lock().unwrap().len(), 0); } - #[test] - fn return_route_ids_expire_when_instructed() { - init_test_logging(); - let cryptde = main_cryptde(); - let stream_key = StreamKey::make_meaningless_stream_key(); - - let (tx, rx) = unbounded(); - thread::spawn(move || { - let system = System::new("report_response_services_consumed_complains_and_drops_package_if_return_route_id_does_not_exist"); - let mut subject = ProxyServer::new( - cryptde, - alias_cryptde(), - true, - Some(STANDARD_CONSUMING_WALLET_BALANCE), - false, - false, - ); - subject.route_ids_to_return_routes_first_chance = - TtlHashMap::new(Duration::from_millis(250)); - subject - .keys_and_addrs - .insert(stream_key, SocketAddr::from_str("1.2.3.4:5678").unwrap()); - subject.route_ids_to_return_routes_first_chance.insert( - 1234, - AddReturnRouteMessage { - return_route_id: 1234, - expected_services: vec![], - protocol: ProxyProtocol::TLS, - hostname_opt: None, - }, - ); - let subject_addr: Addr = subject.start(); - let peer_actors = peer_actors_builder().build(); - subject_addr.try_send(BindMessage { peer_actors }).unwrap(); - tx.send(subject_addr).unwrap(); - - system.run(); - }); - - let subject_addr = rx.recv().unwrap(); - - thread::sleep(Duration::from_millis(300)); - - let client_response_payload = ClientResponsePayload_0v1 { - stream_key, - sequenced_packet: SequencedPacket { - data: b"some data".to_vec(), - sequence_number: 4321, - last_data: false, - }, - }; - let expired_cores_package = ExpiredCoresPackage::new( - SocketAddr::from_str("1.2.3.4:1234").unwrap(), - Some(make_wallet("irrelevant")), - return_route_with_id(cryptde, 1234), - client_response_payload, - 0, - ); - subject_addr.try_send(expired_cores_package).unwrap(); - - TestLogHandler::new().await_log_containing("ERROR: ProxyServer: Can't report services consumed: received response with bogus return-route ID RRI1234 for client response. Ignoring", 1000); - } - #[test] fn handle_stream_shutdown_msg_handles_unknown_peer_addr() { let test_name = "handle_stream_shutdown_msg_handles_unknown_peer_addr"; @@ -6135,6 +5894,7 @@ mod tests { .route(RouteQueryResponse { route: Route { hops: vec![] }, expected_services: ExpectedServices::RoundTrip(vec![], vec![]), + hostname_opt: Some("booga.com".to_string()), }) .tunneled_host("blah") .build() @@ -6188,6 +5948,7 @@ mod tests { .route(RouteQueryResponse { route: Route { hops: vec![] }, expected_services: ExpectedServices::RoundTrip(vec![], vec![]), + hostname_opt: Some("booga.com".to_string()), }) .tunneled_host("blah") .build() @@ -6217,6 +5978,7 @@ mod tests { .route(RouteQueryResponse { route: affected_route.clone(), expected_services: ExpectedServices::RoundTrip(affected_expected_services, vec![]), + hostname_opt: Some("booga.com".to_string()), }) .tunneled_host("tunneled.com") .build() @@ -6311,6 +6073,7 @@ mod tests { .route(RouteQueryResponse { route: Route { hops: vec![] }, expected_services: ExpectedServices::RoundTrip(vec![], vec![]), + hostname_opt: Some("booga.com".to_string()), }) .build() ); @@ -6340,6 +6103,7 @@ mod tests { .route(RouteQueryResponse { route: affected_route.clone(), expected_services: ExpectedServices::RoundTrip(affected_expected_services, vec![]), + hostname_opt: Some("booga.com".to_string()), }) .build() ); @@ -6457,6 +6221,7 @@ mod tests { .route(RouteQueryResponse { route: Route { hops: vec![] }, expected_services: ExpectedServices::RoundTrip(vec![], vec![]), + hostname_opt: Some("booga.com".to_string()), }) .tunneled_host("blah") .build() @@ -6540,7 +6305,6 @@ mod tests { subject.resolve_message( args, - add_return_route_sub, proxy_server_sub, Err(MailboxError::Timeout), ); @@ -6633,6 +6397,7 @@ mod tests { vec![make_exit_service_from_key(destination_key.clone())], vec![], ), + hostname_opt: Some("booga.com".to_string()), })); let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); let stream_key = StreamKey::make_meaningless_stream_key(); @@ -6703,6 +6468,7 @@ mod tests { vec![make_exit_service_from_key(destination_key.clone())], vec![], ), + hostname_opt: Some("booga.com".to_string()), })); let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); let stream_key = StreamKey::make_meaningless_stream_key(); diff --git a/node/src/sub_lib/cryptde_null.rs b/node/src/sub_lib/cryptde_null.rs index 4b724ca77c..e9439b2855 100644 --- a/node/src/sub_lib/cryptde_null.rs +++ b/node/src/sub_lib/cryptde_null.rs @@ -246,6 +246,7 @@ impl CryptDENull { fn wrong_key_message(key_data: &[u8], data: &CryptData) -> String { let prefix_len = std::cmp::min(key_data.len(), data.len()); let vec = Vec::from(&data.as_slice()[0..prefix_len]); +panic!("Wrong key"); format!( "Could not decrypt with {} data beginning with {}", key_data.to_hex::(), diff --git a/node/src/sub_lib/neighborhood.rs b/node/src/sub_lib/neighborhood.rs index 5603fb73da..1905bf2b20 100644 --- a/node/src/sub_lib/neighborhood.rs +++ b/node/src/sub_lib/neighborhood.rs @@ -546,6 +546,7 @@ pub enum ExpectedServices { pub struct RouteQueryResponse { pub route: Route, pub expected_services: ExpectedServices, + pub hostname_opt: Option, } #[derive(Clone, Debug, Message, PartialEq, Eq)] diff --git a/node/src/sub_lib/stream_key.rs b/node/src/sub_lib/stream_key.rs index 7c3110ee1e..e14efd358b 100644 --- a/node/src/sub_lib/stream_key.rs +++ b/node/src/sub_lib/stream_key.rs @@ -97,8 +97,10 @@ impl StreamKey { impl StreamKey { pub fn make_meaningless_stream_key() -> StreamKey { + let mut bytes = [0; sha1::DIGEST_LENGTH]; + randombytes_into(&mut bytes); StreamKey { - hash: [0; sha1::DIGEST_LENGTH], + hash: bytes, } } diff --git a/node/src/test_utils/mod.rs b/node/src/test_utils/mod.rs index 1589ea5cca..f2d3f0c72a 100644 --- a/node/src/test_utils/mod.rs +++ b/node/src/test_utils/mod.rs @@ -248,6 +248,7 @@ pub fn zero_hop_route_response( vec![ExpectedService::Nothing, ExpectedService::Nothing], vec![ExpectedService::Nothing, ExpectedService::Nothing], ), + hostname_opt: None, } } From 814bdef1cb92064e833836143265ea130a582a61 Mon Sep 17 00:00:00 2001 From: Dan Wiebe Date: Wed, 24 Sep 2025 21:00:28 -0400 Subject: [PATCH 16/21] Unit tests are all passing --- .gitignore | 1 + node/src/proxy_client/stream_establisher.rs | 6 +- node/src/proxy_client/stream_handler_pool.rs | 26 ++++--- node/src/proxy_client/stream_reader.rs | 20 ++--- node/src/proxy_server/mod.rs | 80 +++++--------------- node/src/sub_lib/cryptde_null.rs | 1 - node/src/sub_lib/proxy_server.rs | 12 +-- node/src/test_utils/recorder.rs | 4 +- 8 files changed, 55 insertions(+), 95 deletions(-) diff --git a/.gitignore b/.gitignore index 88a2ab5f90..666a5a0987 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ **/*.rs.bk .idea/azure/ .idea/inspectionProfiles/Project_Default.xml +.idea/copilot.data.migration.* ### Node node_modules diff --git a/node/src/proxy_client/stream_establisher.rs b/node/src/proxy_client/stream_establisher.rs index 4d6fdad24f..bfd7408a5b 100644 --- a/node/src/proxy_client/stream_establisher.rs +++ b/node/src/proxy_client/stream_establisher.rs @@ -155,6 +155,8 @@ mod tests { fn spawn_stream_reader_handles_data() { let (proxy_client, proxy_client_awaiter, proxy_client_recording_arc) = make_recorder(); let (sub_tx, sub_rx) = unbounded(); + let stream_key = StreamKey::make_meaningless_stream_key(); + let stream_key_inner = stream_key.clone(); thread::spawn(move || { let system = System::new("spawn_stream_reader_handles_data"); let peer_actors = peer_actors_builder().proxy_client(proxy_client).build(); @@ -188,7 +190,7 @@ mod tests { }; subject.spawn_stream_reader( &ClientRequestPayload_0v1 { - stream_key: StreamKey::make_meaningless_stream_key(), + stream_key: stream_key_inner, sequenced_packet: SequencedPacket { data: vec![], sequence_number: 0, @@ -222,7 +224,7 @@ mod tests { assert_eq!( ibsd, InboundServerData { - stream_key: StreamKey::make_meaningless_stream_key(), + stream_key, last_data: false, sequence_number: 0, source: SocketAddr::from_str("1.2.3.4:5678").unwrap(), diff --git a/node/src/proxy_client/stream_handler_pool.rs b/node/src/proxy_client/stream_handler_pool.rs index 5ecbe9794b..f9eadac822 100644 --- a/node/src/proxy_client/stream_handler_pool.rs +++ b/node/src/proxy_client/stream_handler_pool.rs @@ -761,12 +761,14 @@ mod tests { init_test_logging(); let test_name = "write_failure_for_nonexistent_stream_generates_termination_message"; let cryptde = main_cryptde(); + let stream_key = StreamKey::make_meaningless_stream_key(); + let stream_key_inner = stream_key.clone(); let (proxy_client, proxy_client_awaiter, proxy_client_recording_arc) = make_recorder(); let originator_key = PublicKey::new(&b"men's souls"[..]); let (reader_shutdown_tx, reader_shutdown_rx) = unbounded(); thread::spawn(move || { let client_request_payload = ClientRequestPayload_0v1 { - stream_key: StreamKey::make_meaningless_stream_key(), + stream_key: stream_key_inner, sequenced_packet: SequencedPacket { data: b"These are the times".to_vec(), sequence_number: 0, @@ -820,7 +822,7 @@ mod tests { assert_eq!( proxy_client_recording.get_record::(0), &InboundServerData { - stream_key: StreamKey::make_meaningless_stream_key(), + stream_key: stream_key.clone(), last_data: true, sequence_number: 0, source: SocketAddr::from_str("2.3.4.5:80").unwrap(), @@ -829,7 +831,7 @@ mod tests { ); TestLogHandler::new().exists_log_containing(&format!( "DEBUG: {test_name}: A shutdown signal was sent to the StreamReader \ - for stream key AAAAAAAAAAAAAAAAAAAAAAAAAAA." + for stream key {}.", stream_key )); } @@ -838,11 +840,13 @@ mod tests { let cryptde = main_cryptde(); let write_parameters = Arc::new(Mutex::new(vec![])); let expected_write_parameters = write_parameters.clone(); + let stream_key = StreamKey::make_meaningless_stream_key(); + let stream_key_inner = stream_key.clone(); let (proxy_client, proxy_client_awaiter, proxy_client_recording_arc) = make_recorder(); thread::spawn(move || { let peer_actors = peer_actors_builder().proxy_client(proxy_client).build(); let client_request_payload = ClientRequestPayload_0v1 { - stream_key: StreamKey::make_meaningless_stream_key(), + stream_key: stream_key_inner, sequenced_packet: SequencedPacket { data: b"These are the times".to_vec(), sequence_number: 0, @@ -921,7 +925,7 @@ mod tests { assert_eq!( proxy_client_recording.get_record::(0), &InboundServerData { - stream_key: StreamKey::make_meaningless_stream_key(), + stream_key, last_data: false, sequence_number: 0, source: SocketAddr::from_str("3.4.5.6:80").unwrap(), @@ -1057,11 +1061,13 @@ mod tests { let expected_lookup_ip_parameters = lookup_ip_parameters.clone(); let write_parameters = Arc::new(Mutex::new(vec![])); let expected_write_parameters = write_parameters.clone(); + let stream_key = StreamKey::make_meaningless_stream_key(); + let stream_key_inner = stream_key.clone(); let (proxy_client, proxy_client_awaiter, proxy_client_recording_arc) = make_recorder(); thread::spawn(move || { let peer_actors = peer_actors_builder().proxy_client(proxy_client).build(); let client_request_payload = ClientRequestPayload_0v1 { - stream_key: StreamKey::make_meaningless_stream_key(), + stream_key: stream_key_inner, sequenced_packet: SequencedPacket { data: b"These are the times".to_vec(), sequence_number: 0, @@ -1150,7 +1156,7 @@ mod tests { assert_eq!( proxy_client_recording.get_record::(0), &InboundServerData { - stream_key: StreamKey::make_meaningless_stream_key(), + stream_key, last_data: false, sequence_number: 0, source: SocketAddr::from_str("3.4.5.6:80").unwrap(), @@ -1231,6 +1237,8 @@ mod tests { let expected_lookup_ip_parameters = lookup_ip_parameters.clone(); let write_parameters = Arc::new(Mutex::new(vec![])); let expected_write_parameters = write_parameters.clone(); + let stream_key = StreamKey::make_meaningless_stream_key(); + let stream_key_inner = stream_key.clone(); let (proxy_client, proxy_client_awaiter, proxy_client_recording_arc) = make_recorder(); let (accountant, accountant_awaiter, accountant_recording_arc) = make_recorder(); let before = SystemTime::now(); @@ -1240,7 +1248,7 @@ mod tests { .accountant(accountant) .build(); let client_request_payload = ClientRequestPayload_0v1 { - stream_key: StreamKey::make_meaningless_stream_key(), + stream_key: stream_key_inner, sequenced_packet: SequencedPacket { data: b"These are the times".to_vec(), sequence_number: 0, @@ -1331,7 +1339,7 @@ mod tests { assert_eq!( proxy_client_recording.get_record::(0), &InboundServerData { - stream_key: StreamKey::make_meaningless_stream_key(), + stream_key, last_data: false, sequence_number: 0, source: SocketAddr::from_str("3.4.5.6:80").unwrap(), diff --git a/node/src/proxy_client/stream_reader.rs b/node/src/proxy_client/stream_reader.rs index 992b58dbfa..1e7b6bf415 100644 --- a/node/src/proxy_client/stream_reader.rs +++ b/node/src/proxy_client/stream_reader.rs @@ -179,9 +179,10 @@ mod tests { }); let proxy_client_sub = rx.recv().unwrap(); + let stream_key = StreamKey::make_meaningless_stream_key(); let (stream_killer, stream_killer_params) = unbounded(); let mut subject = StreamReader { - stream_key: StreamKey::make_meaningless_stream_key(), + stream_key: stream_key.clone(), proxy_client_sub, stream, stream_killer, @@ -198,7 +199,7 @@ mod tests { assert_eq!( proxy_client_recording.get_record::(0), &InboundServerData { - stream_key: StreamKey::make_meaningless_stream_key(), + stream_key: stream_key.clone(), last_data: false, sequence_number: 0, source: SocketAddr::from_str("8.7.4.3:50").unwrap(), @@ -208,7 +209,7 @@ mod tests { assert_eq!( proxy_client_recording.get_record::(1), &InboundServerData { - stream_key: StreamKey::make_meaningless_stream_key(), + stream_key: stream_key.clone(), last_data: false, sequence_number: 1, source: SocketAddr::from_str("8.7.4.3:50").unwrap(), @@ -218,7 +219,7 @@ mod tests { assert_eq!( proxy_client_recording.get_record::(2), &InboundServerData { - stream_key: StreamKey::make_meaningless_stream_key(), + stream_key: stream_key.clone(), last_data: false, sequence_number: 2, source: SocketAddr::from_str("8.7.4.3:50").unwrap(), @@ -228,7 +229,7 @@ mod tests { let stream_killer_parameters = stream_killer_params.try_recv().unwrap(); assert_eq!( stream_killer_parameters, - (StreamKey::make_meaningless_stream_key(), 3) + (stream_key, 3) ); } @@ -266,6 +267,7 @@ mod tests { let (stream_killer, stream_killer_params) = unbounded(); let peer_addr = SocketAddr::from_str("5.7.9.0:95").unwrap(); let mut subject = make_subject(); + let stream_key = subject.stream_key.clone(); subject.proxy_client_sub = proxy_client_sub; subject.stream = Box::new(stream); subject.stream_killer = stream_killer; @@ -279,7 +281,7 @@ mod tests { assert_eq!( proxy_client_recording.get_record::(0), &InboundServerData { - stream_key: StreamKey::make_meaningless_stream_key(), + stream_key: stream_key.clone(), last_data: false, sequence_number: 0, source: peer_addr, @@ -289,7 +291,7 @@ mod tests { assert_eq!( proxy_client_recording.get_record::(1), &InboundServerData { - stream_key: StreamKey::make_meaningless_stream_key(), + stream_key: stream_key.clone(), last_data: false, sequence_number: 1, source: peer_addr, @@ -299,7 +301,7 @@ mod tests { assert_eq!( proxy_client_recording.get_record::(2), &InboundServerData { - stream_key: StreamKey::make_meaningless_stream_key(), + stream_key: stream_key.clone(), last_data: false, sequence_number: 2, source: peer_addr, @@ -312,7 +314,7 @@ mod tests { .expect("stream was not killed"); assert_eq!( kill_stream_msg, - (StreamKey::make_meaningless_stream_key(), 3) + (stream_key, 3) ); assert!(stream_killer_params.try_recv().is_err()); } diff --git a/node/src/proxy_server/mod.rs b/node/src/proxy_server/mod.rs index 86cb38483c..fc2baeb9b4 100644 --- a/node/src/proxy_server/mod.rs +++ b/node/src/proxy_server/mod.rs @@ -30,7 +30,7 @@ use crate::sub_lib::neighborhood::{NRMetadataChange, RouteQueryMessage}; use crate::sub_lib::peer_actors::BindMessage; use crate::sub_lib::proxy_client::{ClientResponsePayload_0v1, DnsResolveFailure_0v1}; use crate::sub_lib::proxy_server::ProxyServerSubs; -use crate::sub_lib::proxy_server::{AddReturnRouteMessage, StreamKeyPurge}; +use crate::sub_lib::proxy_server::{StreamKeyPurge}; use crate::sub_lib::proxy_server::{ AddRouteResultMessage, ClientRequestPayload_0v1, ProxyProtocol, }; @@ -68,7 +68,6 @@ struct ProxyServerOutSubs { accountant: Recipient, route_source: Recipient, update_node_record_metadata: Recipient, - add_return_route: Recipient, stream_shutdown_sub: Recipient, route_result_sub: Recipient, schedule_stream_key_purge: Recipient>, @@ -169,7 +168,6 @@ impl Handler for ProxyServer { accountant: msg.peer_actors.accountant.report_services_consumed, route_source: msg.peer_actors.neighborhood.route_query, update_node_record_metadata: msg.peer_actors.neighborhood.update_node_record_metadata, - add_return_route: msg.peer_actors.proxy_server.add_return_route, stream_shutdown_sub: msg.peer_actors.proxy_server.stream_shutdown_sub, route_result_sub: msg.peer_actors.proxy_server.route_result_sub, schedule_stream_key_purge: msg.peer_actors.proxy_server.schedule_stream_key_purge, @@ -193,29 +191,6 @@ impl Handler for ProxyServer { } } -impl Handler for ProxyServer { - type Result = (); - - fn handle(&mut self, _msg: AddReturnRouteMessage, _ctx: &mut Self::Context) -> Self::Result { - // TODO: I think this whole message should probably be deleted from the application. - } -} - -impl AddReturnRouteMessage { - pub fn find_exit_node_key(&self) -> Option<&PublicKey> { - self.expected_services - .iter() - .find_map(|service| match service { - ExpectedService::Exit(public_key, _, _) => Some(public_key), - _ => None, - }) - } - - pub fn is_zero_hop(&self) -> bool { - self.expected_services == vec![ExpectedService::Nothing, ExpectedService::Nothing] - } -} - impl Handler for ProxyServer { type Result = (); @@ -368,7 +343,6 @@ impl ProxyServer { from_dispatcher: recipient!(addr, InboundClientData), from_hopper: recipient!(addr, ExpiredCoresPackage), dns_failure_from_hopper: recipient!(addr, ExpiredCoresPackage), - add_return_route: recipient!(addr, AddReturnRouteMessage), stream_shutdown_sub: recipient!(addr, StreamShutdownMsg), node_from_ui: recipient!(addr, NodeFromUiMessage), route_result_sub: recipient!(addr, AddRouteResultMessage), @@ -567,7 +541,7 @@ impl ProxyServer { // TODO: Malefactor ban the exit node because it lied about the DNS failure. } self.report_response_services_consumed(response_services, 0, msg.payload_len); - if let (Some(retry_ref)) = &mut stream_info.dns_failure_retry_opt { + if let Some(retry_ref) = &mut stream_info.dns_failure_retry_opt { debug!( self.logger, "Handling DNS failure for hostname {:?} - stream key: {} retries left: {}", @@ -1684,7 +1658,6 @@ mod tests { accountant: recipient!(addr, ReportServicesConsumedMessage), route_source: recipient!(addr, RouteQueryMessage), update_node_record_metadata: recipient!(addr, UpdateNodeRecordMetadataMessage), - add_return_route: recipient!(addr, AddReturnRouteMessage), stream_shutdown_sub: recipient!(addr, StreamShutdownMsg), route_result_sub: recipient!(addr, AddRouteResultMessage), schedule_stream_key_purge: recipient!(addr, MessageScheduler), @@ -1842,12 +1815,6 @@ mod tests { vec![], back_services.clone() ); - let return_route_message = AddReturnRouteMessage { - return_route_id: 1234, - expected_services: back_services.clone(), - protocol: ProxyProtocol::TLS, - hostname_opt: None, - }; subject .stream_info.insert( stream_key.clone(), @@ -1855,14 +1822,14 @@ mod tests { .route(RouteQueryResponse{ route: make_meaningless_route(), expected_services: expected_services.clone(), - hostname_opt: Some("booga.com".to_string()), + hostname_opt: None, }) + .protocol(ProxyProtocol::TLS) .build(), ); let result = subject.get_expected_return_services(&stream_key).unwrap(); - let back = expected_services; assert_eq!(result, back_services); } @@ -3009,7 +2976,7 @@ mod tests { let http_request = b"GET /index.html HTTP/1.1\r\nHost: nowhere.com\r\n\r\n"; let destination_key = PublicKey::from(&b"our destination"[..]); let route = Route { hops: vec![] }; - let route_with_rrid = route.clone().set_return_route_id(main_cryptde, 4444); + let route_with_rrid = route.clone().set_return_route_id(main_cryptde, 0); let route_query_response = RouteQueryResponse { route, expected_services: ExpectedServices::RoundTrip( @@ -3068,7 +3035,7 @@ mod tests { stream_key, StreamInfoBuilder::new().route(route_query_response).build() ); - subject.next_return_route_id = Cell::new(4444); + subject.next_return_route_id = Cell::new(0); let subject_addr: Addr = subject.start(); let peer_actors = peer_actors_builder().hopper(hopper_mock).build(); subject_addr.try_send(BindMessage { peer_actors }).unwrap(); @@ -3620,25 +3587,20 @@ mod tests { false, false, ); - let add_return_route_message = AddReturnRouteMessage { - return_route_id: 0, - expected_services: vec![ - ExpectedService::Routing( - PublicKey::from(&b"key"[..]), - make_wallet("some wallet"), - rate_pack(10), - ), - ExpectedService::Exit( - PublicKey::from(&b"exit_key"[..]), - make_wallet("exit"), - rate_pack(11), - ), - ], - protocol: ProxyProtocol::HTTP, - hostname_opt: None, - }; + let expected_services = vec![ + ExpectedService::Routing( + PublicKey::from(&b"key"[..]), + make_wallet("some wallet"), + rate_pack(10), + ), + ExpectedService::Exit( + PublicKey::from(&b"exit_key"[..]), + make_wallet("exit"), + rate_pack(11), + ), + ]; - subject.report_response_services_consumed(&add_return_route_message.expected_services, 1234, 3456); + subject.report_response_services_consumed(&expected_services, 1234, 3456); } #[test] @@ -5208,7 +5170,7 @@ mod tests { let dns_resolve_failure = DnsResolveFailure_0v1::new(stream_key); let expired_cores_package: ExpiredCoresPackage = ExpiredCoresPackage::new( - SocketAddr::from_str("1.2.3.4:1234").unwrap(), + socket_addr, Some(make_wallet("irrelevant")), return_route_with_id(cryptde, return_route_id), dns_resolve_failure.into(), @@ -5830,7 +5792,6 @@ mod tests { ) { init_test_logging(); let cryptde = main_cryptde(); - let return_route_id = 272727; let (dispatcher, _, dispatcher_recording_arc) = make_recorder(); let (accountant, _, accountant_recording_arc) = make_recorder(); let system = System::new("report_response_services_consumed_complains_and_drops_package_if_return_route_id_is_unrecognized"); @@ -6299,7 +6260,6 @@ mod tests { accountant_sub: recipient!(&addr, ReportServicesConsumedMessage), retire_stream_key_sub_opt: None, }; - let add_return_route_sub = recipient!(&addr, AddReturnRouteMessage); let subject = RouteQueryResponseResolverReal {}; let system = System::new("resolve_message_handles_mailbox_error_from_neighborhood"); diff --git a/node/src/sub_lib/cryptde_null.rs b/node/src/sub_lib/cryptde_null.rs index e9439b2855..4b724ca77c 100644 --- a/node/src/sub_lib/cryptde_null.rs +++ b/node/src/sub_lib/cryptde_null.rs @@ -246,7 +246,6 @@ impl CryptDENull { fn wrong_key_message(key_data: &[u8], data: &CryptData) -> String { let prefix_len = std::cmp::min(key_data.len(), data.len()); let vec = Vec::from(&data.as_slice()[0..prefix_len]); -panic!("Wrong key"); format!( "Could not decrypt with {} data beginning with {}", key_data.to_hex::(), diff --git a/node/src/sub_lib/proxy_server.rs b/node/src/sub_lib/proxy_server.rs index 8b28c588ab..644bef24e6 100644 --- a/node/src/sub_lib/proxy_server.rs +++ b/node/src/sub_lib/proxy_server.rs @@ -4,7 +4,7 @@ use crate::sub_lib::data_version::DataVersion; use crate::sub_lib::dispatcher::InboundClientData; use crate::sub_lib::dispatcher::StreamShutdownMsg; use crate::sub_lib::hopper::{ExpiredCoresPackage, MessageType}; -use crate::sub_lib::neighborhood::{ExpectedService, RouteQueryResponse}; +use crate::sub_lib::neighborhood::{RouteQueryResponse}; use crate::sub_lib::peer_actors::BindMessage; use crate::sub_lib::proxy_client::{ClientResponsePayload_0v1, DnsResolveFailure_0v1}; use crate::sub_lib::sequence_buffer::SequencedPacket; @@ -55,14 +55,6 @@ impl ClientRequestPayload_0v1 { } } -#[derive(Message, Debug, PartialEq, Eq, Clone)] -pub struct AddReturnRouteMessage { - pub return_route_id: u32, - pub expected_services: Vec, - pub protocol: ProxyProtocol, - pub hostname_opt: Option, -} - #[derive(Message, Debug, PartialEq, Eq)] pub struct AddRouteResultMessage { pub stream_key: StreamKey, @@ -81,7 +73,6 @@ pub struct ProxyServerSubs { pub from_dispatcher: Recipient, pub from_hopper: Recipient>, pub dns_failure_from_hopper: Recipient>, - pub add_return_route: Recipient, pub stream_shutdown_sub: Recipient, pub node_from_ui: Recipient, pub route_result_sub: Recipient, @@ -113,7 +104,6 @@ mod tests { recorder, ExpiredCoresPackage ), - add_return_route: recipient!(recorder, AddReturnRouteMessage), stream_shutdown_sub: recipient!(recorder, StreamShutdownMsg), node_from_ui: recipient!(recorder, NodeFromUiMessage), route_result_sub: recipient!(recorder, AddRouteResultMessage), diff --git a/node/src/test_utils/recorder.rs b/node/src/test_utils/recorder.rs index f66125182c..f1f841126d 100644 --- a/node/src/test_utils/recorder.rs +++ b/node/src/test_utils/recorder.rs @@ -40,7 +40,7 @@ use crate::sub_lib::peer_actors::{BindMessage, NewPublicIp, StartMessage}; use crate::sub_lib::proxy_client::{ClientResponsePayload_0v1, InboundServerData}; use crate::sub_lib::proxy_client::{DnsResolveFailure_0v1, ProxyClientSubs}; use crate::sub_lib::proxy_server::{ - AddReturnRouteMessage, ClientRequestPayload_0v1, StreamKeyPurge, + ClientRequestPayload_0v1, StreamKeyPurge, }; use crate::sub_lib::proxy_server::{AddRouteResultMessage, ProxyServerSubs}; use crate::sub_lib::stream_handler_pool::DispatcherNodeQueryResponse; @@ -123,7 +123,6 @@ macro_rules! recorder_message_handler_t_p { }; } -recorder_message_handler_t_m_p!(AddReturnRouteMessage); recorder_message_handler_t_m_p!(AddRouteResultMessage); recorder_message_handler_t_p!(AddStreamMsg); recorder_message_handler_t_m_p!(BindMessage); @@ -398,7 +397,6 @@ pub fn make_proxy_server_subs_from_recorder(addr: &Addr) -> ProxyServe from_dispatcher: recipient!(addr, InboundClientData), from_hopper: recipient!(addr, ExpiredCoresPackage), dns_failure_from_hopper: recipient!(addr, ExpiredCoresPackage), - add_return_route: recipient!(addr, AddReturnRouteMessage), stream_shutdown_sub: recipient!(addr, StreamShutdownMsg), node_from_ui: recipient!(addr, NodeFromUiMessage), route_result_sub: recipient!(addr, AddRouteResultMessage), From bdec124eda7c9a03f44601bc47084d274a6cbbdb Mon Sep 17 00:00:00 2001 From: Dan Wiebe Date: Thu, 25 Sep 2025 08:20:17 -0400 Subject: [PATCH 17/21] Unit and multinode tests pass --- .../tests/connection_termination_test.rs | 75 +- .../tests/self_test.rs | 11 +- node/src/hopper/consuming_service.rs | 9 +- node/src/hopper/live_cores_package.rs | 16 +- node/src/hopper/mod.rs | 7 +- node/src/hopper/routing_service.rs | 2 +- node/src/neighborhood/mod.rs | 5 +- node/src/proxy_client/stream_handler_pool.rs | 3 +- node/src/proxy_client/stream_reader.rs | 10 +- node/src/proxy_server/mod.rs | 788 ++++++++++-------- node/src/sub_lib/hopper.rs | 11 +- node/src/sub_lib/neighborhood.rs | 4 +- node/src/sub_lib/proxy_server.rs | 2 +- node/src/sub_lib/stream_key.rs | 4 +- node/src/test_utils/mod.rs | 4 +- node/src/test_utils/recorder.rs | 4 +- 16 files changed, 497 insertions(+), 458 deletions(-) diff --git a/multinode_integration_tests/tests/connection_termination_test.rs b/multinode_integration_tests/tests/connection_termination_test.rs index 2657661b8f..b015c9da94 100644 --- a/multinode_integration_tests/tests/connection_termination_test.rs +++ b/multinode_integration_tests/tests/connection_termination_test.rs @@ -86,13 +86,12 @@ fn reported_server_drop() { let (_, _, lcp) = mock_node .wait_for_package(&masquerader, Duration::from_secs(2)) .unwrap(); - let (stream_key, return_route_id) = - context_from_request_lcp(lcp, real_node.main_cryptde_null().unwrap(), &exit_cryptde); + let stream_key = stream_key_from_request_lcp(lcp, &exit_cryptde); mock_node .transmit_package( mock_node.port_list()[0], - create_server_drop_report(&mock_node, &real_node, stream_key, return_route_id), + create_server_drop_report(&mock_node, &real_node, stream_key), &masquerader, real_node.main_public_key(), real_node.socket_addr(PortSelector::First), @@ -115,7 +114,7 @@ fn actual_server_drop() { let server_port = find_free_port(); let mut server = real_node.make_server(server_port); let masquerader = JsonMasquerader::new(); - let (stream_key, return_route_id) = arbitrary_context(); + let stream_key = arbitrary_stream_key(); let index: u64 = 0; request_server_payload( index, @@ -125,7 +124,6 @@ fn actual_server_drop() { &mut server, &masquerader, stream_key, - return_route_id, ); let index: u64 = 1; request_server_payload( @@ -136,7 +134,6 @@ fn actual_server_drop() { &mut server, &masquerader, stream_key, - return_route_id, ); server.shutdown(); @@ -174,7 +171,6 @@ fn request_server_payload( server: &mut MASQNodeServer, masquerader: &JsonMasquerader, stream_key: StreamKey, - return_route_id: u32, ) { mock_node .transmit_package( @@ -184,7 +180,6 @@ fn request_server_payload( &mock_node, &real_node, stream_key, - return_route_id, &server, cluster.chain, ), @@ -212,7 +207,7 @@ fn reported_client_drop() { let server_port = find_free_port(); let mut server = real_node.make_server(server_port); let masquerader = JsonMasquerader::new(); - let (stream_key, return_route_id) = arbitrary_context(); + let stream_key = arbitrary_stream_key(); let index: u64 = 0; mock_node .transmit_package( @@ -222,7 +217,6 @@ fn reported_client_drop() { &mock_node, &real_node, stream_key, - return_route_id, &server, cluster.chain, ), @@ -240,7 +234,7 @@ fn reported_client_drop() { mock_node .transmit_package( mock_node.port_list()[0], - create_client_drop_report(&mock_node, &real_node, stream_key, return_route_id), + create_client_drop_report(&mock_node, &real_node, stream_key), &masquerader, real_node.main_public_key(), real_node.socket_addr(PortSelector::First), @@ -322,11 +316,7 @@ fn full_neighbor(one: &mut NodeRecord, another: &mut NodeRecord) { .unwrap(); } -fn context_from_request_lcp( - lcp: LiveCoresPackage, - originating_cryptde: &dyn CryptDE, - exit_cryptde: &dyn CryptDE, -) -> (StreamKey, u32) { +fn stream_key_from_request_lcp(lcp: LiveCoresPackage, exit_cryptde: &dyn CryptDE) -> StreamKey { let payload = match decodex::(exit_cryptde, &lcp.payload).unwrap() { MessageType::ClientRequest(vd) => vd .extract(&node_lib::sub_lib::migrations::client_request_payload::MIGRATIONS) @@ -334,15 +324,11 @@ fn context_from_request_lcp( mt => panic!("Unexpected: {:?}", mt), }; let stream_key = payload.stream_key; - let return_route_id = decodex::(originating_cryptde, &lcp.route.hops[6]).unwrap(); - (stream_key, return_route_id) + stream_key } -fn arbitrary_context() -> (StreamKey, u32) { - ( - StreamKey::make_meaningful_stream_key("arbitrary_context"), - 12345678, - ) +fn arbitrary_stream_key() -> StreamKey { + StreamKey::make_meaningful_stream_key("arbitrary_context") } fn create_request_icp( @@ -350,12 +336,12 @@ fn create_request_icp( originating_node: &MASQMockNode, exit_node: &MASQRealNode, stream_key: StreamKey, - return_route_id: u32, server: &MASQNodeServer, chain: Chain, ) -> IncipientCoresPackage { + let originating_main_cryptde = originating_node.main_cryptde_null().unwrap(); IncipientCoresPackage::new( - originating_node.main_cryptde_null().unwrap(), + originating_main_cryptde, Route::round_trip( RouteSegment::new( vec![ @@ -371,12 +357,12 @@ fn create_request_icp( ], Component::ProxyServer, ), - originating_node.main_cryptde_null().unwrap(), + originating_main_cryptde, originating_node.consuming_wallet(), - return_route_id, Some(chain.rec().contract), ) - .unwrap(), + .unwrap() + .set_return_route_id(originating_main_cryptde, 0), MessageType::ClientRequest(VersionedData::new( &node_lib::sub_lib::migrations::client_request_payload::MIGRATIONS, &ClientRequestPayload_0v1 { @@ -400,8 +386,9 @@ fn create_meaningless_icp( let socket_addr = SocketAddr::from_str("3.2.1.0:7654").unwrap(); let stream_key = StreamKey::make_meaningful_stream_key("Chancellor on brink of second bailout for banks"); + let main_cryptde = originating_node.main_cryptde_null().unwrap(); IncipientCoresPackage::new( - originating_node.main_cryptde_null().unwrap(), + main_cryptde, Route::round_trip( RouteSegment::new( vec![ @@ -417,9 +404,8 @@ fn create_meaningless_icp( ], Component::ProxyServer, ), - originating_node.main_cryptde_null().unwrap(), + main_cryptde, originating_node.consuming_wallet(), - 1357, Some(TEST_DEFAULT_MULTINODE_CHAIN.rec().contract), ) .unwrap(), @@ -428,7 +414,7 @@ fn create_meaningless_icp( &ClientRequestPayload_0v1 { stream_key, sequenced_packet: SequencedPacket::new(Vec::from(HTTP_REQUEST), 0, false), - target_hostname: Some(format!("nowhere.com")), + target_hostname: Some("nowhere.com".to_string()), target_port: socket_addr.port(), protocol: ProxyProtocol::HTTP, originator_public_key: originating_node.main_public_key().clone(), @@ -443,8 +429,9 @@ fn create_server_drop_report( exit_node: &MASQMockNode, originating_node: &MASQRealNode, stream_key: StreamKey, - return_route_id: u32, ) -> IncipientCoresPackage { + let exit_main_cryptde = exit_node.main_cryptde_null().unwrap(); + let originating_main_cryptde = originating_node.main_cryptde_null().unwrap(); let mut route = Route::round_trip( RouteSegment::new( vec![ @@ -460,15 +447,13 @@ fn create_server_drop_report( ], Component::ProxyServer, ), - originating_node.main_cryptde_null().unwrap(), + originating_main_cryptde, originating_node.consuming_wallet(), - return_route_id, Some(TEST_DEFAULT_MULTINODE_CHAIN.rec().contract), ) - .unwrap(); - route - .shift(originating_node.main_cryptde_null().unwrap()) - .unwrap(); + .unwrap() + .set_return_route_id(originating_main_cryptde, 0); + route.shift(originating_main_cryptde).unwrap(); let payload = MessageType::ClientResponse(VersionedData::new( &node_lib::sub_lib::migrations::client_response_payload::MIGRATIONS, &ClientResponsePayload_0v1 { @@ -478,7 +463,7 @@ fn create_server_drop_report( )); IncipientCoresPackage::new( - exit_node.main_cryptde_null().unwrap(), + exit_main_cryptde, route, payload, originating_node.alias_public_key(), @@ -490,8 +475,8 @@ fn create_client_drop_report( originating_node: &MASQMockNode, exit_node: &MASQRealNode, stream_key: StreamKey, - return_route_id: u32, ) -> IncipientCoresPackage { + let originating_main_cryptde = originating_node.main_cryptde_null().unwrap(); let route = Route::round_trip( RouteSegment::new( vec![ @@ -507,12 +492,12 @@ fn create_client_drop_report( ], Component::ProxyServer, ), - originating_node.main_cryptde_null().unwrap(), + originating_main_cryptde, originating_node.consuming_wallet(), - return_route_id, Some(TEST_DEFAULT_MULTINODE_CHAIN.rec().contract), ) - .unwrap(); + .unwrap() + .set_return_route_id(originating_main_cryptde, 0); let payload = MessageType::ClientRequest(VersionedData::new( &node_lib::sub_lib::migrations::client_request_payload::MIGRATIONS, &ClientRequestPayload_0v1 { @@ -526,7 +511,7 @@ fn create_client_drop_report( )); IncipientCoresPackage::new( - originating_node.main_cryptde_null().unwrap(), + originating_main_cryptde, route, payload, exit_node.main_public_key(), diff --git a/multinode_integration_tests/tests/self_test.rs b/multinode_integration_tests/tests/self_test.rs index bbbca61ec1..bf73a98e0d 100644 --- a/multinode_integration_tests/tests/self_test.rs +++ b/multinode_integration_tests/tests/self_test.rs @@ -14,6 +14,7 @@ use node_lib::sub_lib::dispatcher::Component; use node_lib::sub_lib::hopper::IncipientCoresPackage; use node_lib::sub_lib::route::Route; use node_lib::sub_lib::route::RouteSegment; +use node_lib::sub_lib::stream_key::StreamKey; use node_lib::test_utils::{main_cryptde, make_meaningless_message_type, make_paying_wallet}; use std::collections::HashSet; use std::io::ErrorKind; @@ -66,6 +67,7 @@ fn server_relays_cores_package() { let masquerader = JsonMasquerader::new(); let server = MASQCoresServer::new(cluster.chain); let cryptde = server.main_cryptde(); + let stream_key = StreamKey::make_meaningless_stream_key(); let mut client = MASQCoresClient::new(server.local_addr(), cryptde); let mut route = Route::one_way( RouteSegment::new( @@ -80,7 +82,7 @@ fn server_relays_cores_package() { let incipient = IncipientCoresPackage::new( cryptde, route.clone(), - make_meaningless_message_type(), + make_meaningless_message_type(stream_key), &cryptde.public_key(), ) .unwrap(); @@ -97,7 +99,7 @@ fn server_relays_cores_package() { route.shift(cryptde).unwrap(); assert_eq!(expired.remaining_route, route); - assert_eq!(expired.payload, make_meaningless_message_type()); + assert_eq!(expired.payload, make_meaningless_message_type(stream_key)); } #[test] @@ -109,6 +111,7 @@ fn one_mock_node_talks_to_another() { let mock_node_1 = cluster.get_mock_node_by_name("mock_node_1").unwrap(); let mock_node_2 = cluster.get_mock_node_by_name("mock_node_2").unwrap(); let cryptde = main_cryptde(); + let stream_key = StreamKey::make_meaningless_stream_key(); let route = Route::one_way( RouteSegment::new( vec![ @@ -125,7 +128,7 @@ fn one_mock_node_talks_to_another() { let incipient_cores_package = IncipientCoresPackage::new( cryptde, route, - make_meaningless_message_type(), + make_meaningless_message_type(stream_key), &mock_node_2.main_public_key(), ) .unwrap(); @@ -154,7 +157,7 @@ fn one_mock_node_talks_to_another() { assert_eq!(package_to, mock_node_2.socket_addr(PortSelector::First)); assert_eq!( expired_cores_package.payload, - make_meaningless_message_type() + make_meaningless_message_type(stream_key) ); } diff --git a/node/src/hopper/consuming_service.rs b/node/src/hopper/consuming_service.rs index b0df18b1f2..6c81d4256c 100644 --- a/node/src/hopper/consuming_service.rs +++ b/node/src/hopper/consuming_service.rs @@ -138,6 +138,7 @@ mod tests { use crate::sub_lib::node_addr::NodeAddr; use crate::sub_lib::route::Route; use crate::sub_lib::route::RouteSegment; + use crate::sub_lib::stream_key::StreamKey; use crate::test_utils::recorder::make_recorder; use crate::test_utils::recorder::peer_actors_builder; use crate::test_utils::{main_cryptde, make_meaningless_message_type, make_paying_wallet}; @@ -158,7 +159,7 @@ mod tests { main_cryptde(), &target_key, &target_node_addr, - make_meaningless_message_type(), + make_meaningless_message_type(StreamKey::make_meaningless_stream_key()), ) .unwrap(); let system = System::new(""); @@ -228,7 +229,7 @@ mod tests { Some(TEST_DEFAULT_CHAIN.rec().contract), ) .unwrap(); - let payload = make_meaningless_message_type(); + let payload = make_meaningless_message_type(StreamKey::make_meaningless_stream_key()); let incipient_cores_package = IncipientCoresPackage::new(cryptde, route.clone(), payload, &destination_key).unwrap(); let system = System::new("converts_incipient_message_to_live_and_sends_to_dispatcher"); @@ -275,7 +276,7 @@ mod tests { Some(TEST_DEFAULT_CHAIN.rec().contract), ) .unwrap(); - let payload = make_meaningless_message_type(); + let payload = make_meaningless_message_type(StreamKey::make_meaningless_stream_key()); let incipient_cores_package = IncipientCoresPackage::new(cryptde, route.clone(), payload, &destination_key).unwrap(); let system = System::new("consume_sends_zero_hop_incipient_directly_to_hopper"); @@ -326,7 +327,7 @@ mod tests { IncipientCoresPackage::new( main_cryptde(), Route { hops: vec![] }, - make_meaningless_message_type(), + make_meaningless_message_type(StreamKey::make_meaningless_stream_key()), &PublicKey::new(&[1, 2]), ) .unwrap(), diff --git a/node/src/hopper/live_cores_package.rs b/node/src/hopper/live_cores_package.rs index 8ed830b947..01f1d57933 100644 --- a/node/src/hopper/live_cores_package.rs +++ b/node/src/hopper/live_cores_package.rs @@ -99,6 +99,7 @@ mod tests { use crate::sub_lib::node_addr::NodeAddr; use crate::sub_lib::route::RouteSegment; use crate::sub_lib::route::{Route, RouteError}; + use crate::sub_lib::stream_key::StreamKey; use crate::test_utils::{ main_cryptde, make_meaningless_message_type, make_meaningless_route, make_paying_wallet, }; @@ -135,7 +136,9 @@ mod tests { let relay_key = PublicKey::new(&[1, 2]); let relay_cryptde = CryptDENull::from(&relay_key, TEST_DEFAULT_CHAIN); let cryptde = main_cryptde(); - let serialized_payload = serde_cbor::ser::to_vec(&make_meaningless_message_type()).unwrap(); + let stream_key = StreamKey::make_meaningless_stream_key(); + let serialized_payload = + serde_cbor::ser::to_vec(&make_meaningless_message_type(stream_key)).unwrap(); let encrypted_payload = cryptde .encode(&destination_key, &PlainData::new(&serialized_payload)) .unwrap(); @@ -198,7 +201,7 @@ mod tests { let key34 = PublicKey::new(&[3, 4]); let node_addr34 = NodeAddr::new(&IpAddr::from_str("3.4.3.4").unwrap(), &[1234]); let mut route = Route::single_hop(&key34, cryptde).unwrap(); - let payload = make_meaningless_message_type(); + let payload = make_meaningless_message_type(StreamKey::make_meaningless_stream_key()); let incipient = NoLookupIncipientCoresPackage::new(cryptde, &key34, &node_addr34, payload.clone()) @@ -222,7 +225,7 @@ mod tests { cryptde, &blank_key, &node_addr34, - make_meaningless_message_type(), + make_meaningless_message_type(StreamKey::make_meaningless_stream_key()), ); assert_eq!( @@ -248,7 +251,7 @@ mod tests { Some(contract_address), ) .unwrap(); - let payload = make_meaningless_message_type(); + let payload = make_meaningless_message_type(StreamKey::make_meaningless_stream_key()); let incipient = IncipientCoresPackage::new(cryptde, route.clone(), payload.clone(), &key56).unwrap(); @@ -274,7 +277,7 @@ mod tests { let incipient = IncipientCoresPackage::new( cryptde, Route { hops: vec![] }, - make_meaningless_message_type(), + make_meaningless_message_type(StreamKey::make_meaningless_stream_key()), &PublicKey::new(&[3, 4]), ) .unwrap(); @@ -291,7 +294,8 @@ mod tests { #[test] fn expired_cores_package_can_be_constructed_from_live_cores_package() { let immediate_neighbor_ip = SocketAddr::from_str("1.2.3.4:1234").unwrap(); - let payload = make_meaningless_message_type(); + let stream_key = StreamKey::make_meaningless_stream_key(); + let payload = make_meaningless_message_type(stream_key); let first_stop_key = PublicKey::new(&[3, 4]); let first_stop_cryptde = CryptDENull::from(&first_stop_key, TEST_DEFAULT_CHAIN); let relay_key = PublicKey::new(&[1, 2]); diff --git a/node/src/hopper/mod.rs b/node/src/hopper/mod.rs index 8cfe5e9553..ef854be518 100644 --- a/node/src/hopper/mod.rs +++ b/node/src/hopper/mod.rs @@ -149,6 +149,7 @@ mod tests { use crate::sub_lib::hopper::IncipientCoresPackage; use crate::sub_lib::route::Route; use crate::sub_lib::route::RouteSegment; + use crate::sub_lib::stream_key::StreamKey; use crate::test_utils::unshared_test_utils::prove_that_crash_request_handler_is_hooked_up; use crate::test_utils::{ alias_cryptde, main_cryptde, make_cryptde_pair, make_meaningless_message_type, @@ -173,7 +174,9 @@ mod tests { let alias_cryptde = alias_cryptde(); let client_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); let route = route_to_proxy_client(&main_cryptde.public_key(), main_cryptde); - let serialized_payload = serde_cbor::ser::to_vec(&make_meaningless_message_type()).unwrap(); + let stream_key = StreamKey::make_meaningless_stream_key(); + let serialized_payload = + serde_cbor::ser::to_vec(&make_meaningless_message_type(stream_key)).unwrap(); let data = main_cryptde .encode( &main_cryptde.public_key(), @@ -235,7 +238,7 @@ mod tests { let incipient_package = IncipientCoresPackage::new( main_cryptde, route, - make_meaningless_message_type(), + make_meaningless_message_type(StreamKey::make_meaningless_stream_key()), &main_cryptde.public_key(), ) .unwrap(); diff --git a/node/src/hopper/routing_service.rs b/node/src/hopper/routing_service.rs index 05d8af9d68..2be37e1071 100644 --- a/node/src/hopper/routing_service.rs +++ b/node/src/hopper/routing_service.rs @@ -1286,7 +1286,7 @@ mod tests { let origin_key = PublicKey::new(&[1, 2]); let origin_cryptde = CryptDENull::from(&origin_key, TEST_DEFAULT_CHAIN); let destination_key = PublicKey::new(&[3, 4]); - let payload = make_meaningless_message_type(); + let payload = make_meaningless_message_type(StreamKey::make_meaningless_stream_key()); let route = Route::one_way( RouteSegment::new( vec![&origin_key, &main_cryptde.public_key(), &destination_key], diff --git a/node/src/neighborhood/mod.rs b/node/src/neighborhood/mod.rs index 12d5800546..f90b7926bb 100644 --- a/node/src/neighborhood/mod.rs +++ b/node/src/neighborhood/mod.rs @@ -1077,7 +1077,7 @@ impl Neighborhood { expected_request_services, expected_response_services, ), - hostname_opt + hostname_opt, }) } @@ -3346,7 +3346,8 @@ mod tests { } let addr: Addr = subject.start(); let sub: Recipient = addr.recipient::(); - let msg = RouteQueryMessage::data_indefinite_route_request(Some("booga.com".to_string()), 54000); + let msg = + RouteQueryMessage::data_indefinite_route_request(Some("booga.com".to_string()), 54000); let future = sub.send(msg); diff --git a/node/src/proxy_client/stream_handler_pool.rs b/node/src/proxy_client/stream_handler_pool.rs index f9eadac822..5e2047e26a 100644 --- a/node/src/proxy_client/stream_handler_pool.rs +++ b/node/src/proxy_client/stream_handler_pool.rs @@ -831,7 +831,8 @@ mod tests { ); TestLogHandler::new().exists_log_containing(&format!( "DEBUG: {test_name}: A shutdown signal was sent to the StreamReader \ - for stream key {}.", stream_key + for stream key {}.", + stream_key )); } diff --git a/node/src/proxy_client/stream_reader.rs b/node/src/proxy_client/stream_reader.rs index 1e7b6bf415..bf39de6e31 100644 --- a/node/src/proxy_client/stream_reader.rs +++ b/node/src/proxy_client/stream_reader.rs @@ -227,10 +227,7 @@ mod tests { }, ); let stream_killer_parameters = stream_killer_params.try_recv().unwrap(); - assert_eq!( - stream_killer_parameters, - (stream_key, 3) - ); + assert_eq!(stream_killer_parameters, (stream_key, 3)); } #[test] @@ -312,10 +309,7 @@ mod tests { let kill_stream_msg = stream_killer_params .try_recv() .expect("stream was not killed"); - assert_eq!( - kill_stream_msg, - (stream_key, 3) - ); + assert_eq!(kill_stream_msg, (stream_key, 3)); assert!(stream_killer_params.try_recv().is_err()); } diff --git a/node/src/proxy_server/mod.rs b/node/src/proxy_server/mod.rs index fc2baeb9b4..2912ac5da3 100644 --- a/node/src/proxy_server/mod.rs +++ b/node/src/proxy_server/mod.rs @@ -30,7 +30,7 @@ use crate::sub_lib::neighborhood::{NRMetadataChange, RouteQueryMessage}; use crate::sub_lib::peer_actors::BindMessage; use crate::sub_lib::proxy_client::{ClientResponsePayload_0v1, DnsResolveFailure_0v1}; use crate::sub_lib::proxy_server::ProxyServerSubs; -use crate::sub_lib::proxy_server::{StreamKeyPurge}; +use crate::sub_lib::proxy_server::StreamKeyPurge; use crate::sub_lib::proxy_server::{ AddRouteResultMessage, ClientRequestPayload_0v1, ProxyProtocol, }; @@ -82,53 +82,6 @@ struct StreamInfo { time_to_live_opt: Option, } -struct StreamInfoBuilder { - product: StreamInfo -} - -impl StreamInfoBuilder { - pub fn new() -> Self { - Self { - product: StreamInfo { - tunneled_host_opt: None, - dns_failure_retry_opt: None, - route_opt: None, - protocol_opt: None, - time_to_live_opt: None, - } - } - } - - pub fn tunneled_host(mut self, host: &str) -> Self { - self.product.tunneled_host_opt = Some(host.to_string()); - self - } - - pub fn dns_failure_retry(mut self, retry: DNSFailureRetry) -> Self { - self.product.dns_failure_retry_opt = Some(retry); - self - } - - pub fn route(mut self, route: RouteQueryResponse) -> Self { - self.product.route_opt = Some(route); - self - } - - pub fn protocol(mut self, protocol: ProxyProtocol) -> Self { - self.product.protocol_opt = Some(protocol); - self - } - - pub fn time_to_live(mut self, ttl: SystemTime) -> Self { - self.product.time_to_live_opt = Some(ttl); - self - } - - pub fn build(self) -> StreamInfo { - self.product - } -} - pub struct ProxyServer { subs: Option, client_request_payload_factory: Box, @@ -198,29 +151,30 @@ impl Handler for ProxyServer { let mut delayed_log: Box = Box::new(|_: &Logger| {}); if let Some(stream_info) = self.stream_info_mut(&msg.stream_key) { match &stream_info.dns_failure_retry_opt { - Some(dns_failure) => { - match msg.result { - Ok(route_query_response) => { - let target_hostname = dns_failure.unsuccessful_request.target_hostname.clone(); - let retries_left = dns_failure.retries_left; - let stream_key = msg.stream_key.clone(); - delayed_log = Box::new(move |logger: &Logger| { - debug!( + Some(dns_failure) => match msg.result { + Ok(route_query_response) => { + let target_hostname = + dns_failure.unsuccessful_request.target_hostname.clone(); + let retries_left = dns_failure.retries_left; + let stream_key = msg.stream_key; + delayed_log = Box::new(move |logger: &Logger| { + debug!( logger, "Found a new route for hostname: {:?} - stream key: {} retries left: {}", target_hostname, stream_key, retries_left ); - }); - stream_info.route_opt = Some(route_query_response); - } - Err(e) => { - let target_hostname = dns_failure.unsuccessful_request.target_hostname.clone(); - let retries_left = dns_failure.retries_left; - let stream_key = msg.stream_key.clone(); - delayed_log = Box::new(move |logger: &Logger| { - warning!( + }); + stream_info.route_opt = Some(route_query_response); + } + Err(e) => { + let target_hostname = + dns_failure.unsuccessful_request.target_hostname.clone(); + let retries_left = dns_failure.retries_left; + let stream_key = msg.stream_key; + delayed_log = Box::new(move |logger: &Logger| { + warning!( logger, "No route found for hostname: {:?} - stream key {} - retries left: {} - AddRouteResultMessage Error: {}", target_hostname, @@ -228,12 +182,11 @@ impl Handler for ProxyServer { retries_left, e ); - }); - } + }); } }, None => { - let stream_key = msg.stream_key.clone(); + let stream_key = msg.stream_key; delayed_log = Box::new(move |logger: &Logger| { error!( logger, @@ -353,10 +306,7 @@ impl ProxyServer { fn stream_info(&self, stream_key: &StreamKey, logger: &Logger) -> Option<&StreamInfo> { match self.stream_info.get(stream_key) { None => { - error!( - logger, - "Stream key {} not found in stream_info", stream_key - ); + error!(logger, "Stream key {} not found in stream_info", stream_key); None } Some(info) => Some(info), @@ -381,21 +331,15 @@ impl ProxyServer { stream_key: &StreamKey, ) -> Result { match stream_info.dns_failure_retry_opt.take() { - None => { - Err(format!( - "No DNSFailureRetry entry found for the stream_key: {:?}", - stream_key - )) - }, - Some(retry) => Ok(retry) + None => Err(format!( + "No DNSFailureRetry entry found for the stream_key: {:?}", + stream_key + )), + Some(retry) => Ok(retry), } } - fn retry_dns_resolution( - &mut self, - retry: &DNSFailureRetry, - client_addr: SocketAddr, - ) { + fn retry_dns_resolution(&mut self, retry: &DNSFailureRetry, client_addr: SocketAddr) { let args = TransmitToHopperArgs::new( self, retry.unsuccessful_request.clone(), @@ -410,11 +354,7 @@ impl ProxyServer { .as_ref() .expect("IBCDHelper uninitialized"); - inbound_client_data_helper.request_route_and_transmit( - args, - route_source, - proxy_server_sub, - ); + inbound_client_data_helper.request_route_and_transmit(args, route_source, proxy_server_sub); } fn retire_stream_key(&mut self, stream_key: &StreamKey) { @@ -442,14 +382,16 @@ impl ProxyServer { .expect("Dispatcher is dead"); } - fn get_response_services(route_query_response: &RouteQueryResponse) -> Option<&Vec> { + fn get_response_services( + route_query_response: &RouteQueryResponse, + ) -> Option<&[ExpectedService]> { match &route_query_response.expected_services { ExpectedServices::RoundTrip(_, back) => Some(back), _ => None, } } - fn find_exit_node_key(response_services: &Vec) -> Option { + fn find_exit_node_key(response_services: &[ExpectedService]) -> Option { match response_services.first() { Some(ExpectedService::Exit(pk, _, _)) => Some(pk.clone()), _ => None, @@ -469,7 +411,8 @@ impl ProxyServer { let mut stream_info = match self.stream_info(&response.stream_key, &self.logger) { Some(info) => (*info).clone(), None => { - error!(self.logger, + error!( + self.logger, "Discarding DnsResolveFailure message from an unrecognized stream key {:?}", &response.stream_key ); @@ -482,10 +425,9 @@ impl ProxyServer { Some(route_query_response) => route_query_response, None => { error!( - self.logger, - "Stream info for stream key {} has no route info", - &response.stream_key - ); + self.logger, + "Stream info for stream key {} has no route info", &response.stream_key + ); return; } }; @@ -493,19 +435,18 @@ impl ProxyServer { Some(response_services) => response_services, None => { error!( - self.logger, - "Stream info for stream key {} has no response services in its route info", - &response.stream_key - ); + self.logger, + "Stream info for stream key {} has no response services in its route info", + &response.stream_key + ); return; } }; let exit_public_key = if !self.is_decentralized { self.main_cryptde.public_key().clone() - } - else { + } else { match Self::find_exit_node_key(response_services) { - Some(exit_public_key) => exit_public_key.clone(), + Some(exit_public_key) => exit_public_key, None => { error!( self.logger, @@ -561,7 +502,7 @@ impl ProxyServer { self.send_dns_failure_response_to_the_browser( client_addr, protocol, - hostname_opt.clone(), + hostname_opt, ); } } else { @@ -639,6 +580,8 @@ impl ProxyServer { &mut self, msg: ExpiredCoresPackage, ) { + // TODO: Maybe comment this back in. The issue is apparently that the second hop is the + // return route information, which doesn't to_string() very well anymore. // debug!( // self.logger, // "ExpiredCoresPackage remaining_route: {}", @@ -665,15 +608,18 @@ impl ProxyServer { let old_timestamp_opt = match self.stream_info_mut(&stream_key) { Some(info) => { let time_to_live_opt = info.time_to_live_opt; - match ProxyServer::remove_dns_failure_retry(info, &stream_key) { - _ => trace!( + // This call to remove_dns_failure_retry is here only because it needs access to + // a mutable StreamInfo, and we have one handy here. It has nothing to do with + // timestamps. + if let Err(e) = ProxyServer::remove_dns_failure_retry(info, &stream_key) { + trace!( self.logger, - "No DNS retry entry found for stream key: {} during a successful attempt", - &stream_key - ) - }; + "No DNS retry entry found for stream key {} during a successful attempt: {}", + &stream_key, e + ); + } time_to_live_opt - }, + } None => None, }; if let Some(old_timestamp) = old_timestamp_opt { @@ -819,10 +765,16 @@ impl ProxyServer { let stream_key = self .stream_key_factory .make(self.main_cryptde.public_key(), ibcd.client_addr); - self.keys_and_addrs.insert(stream_key.clone(), ibcd.client_addr); + self.keys_and_addrs.insert(stream_key, ibcd.client_addr); self.stream_info.insert( - stream_key.clone(), - StreamInfoBuilder::new().build(), + stream_key, + StreamInfo { + tunneled_host_opt: None, + dns_failure_retry_opt: None, + route_opt: None, + protocol_opt: None, + time_to_live_opt: None, + }, ); debug!( self.logger, @@ -892,7 +844,7 @@ impl ProxyServer { match route_query_response.expected_services { ExpectedServices::RoundTrip(over, _) => { ProxyServer::transmit_to_hopper(args, route_query_response.route, over) - }, + } _ => panic!("Expected RoundTrip ExpectedServices but got OneWay"), } } @@ -1102,7 +1054,7 @@ impl ProxyServer { fn report_response_services_consumed( &self, - expected_services: &Vec, + expected_services: &[ExpectedService], exit_size: usize, routing_size: usize, ) { @@ -1211,10 +1163,7 @@ impl RouteQueryResponseResolver for RouteQueryResponseResolverReal { let stream_key = args.payload.stream_key; let result = match route_result_opt { Ok(Some(route_query_response)) => { - match ProxyServer::try_transmit_to_hopper( - args, - route_query_response.clone(), - ) { + match ProxyServer::try_transmit_to_hopper(args, route_query_response.clone()) { Ok(()) => Ok(route_query_response), Err(e) => Err(e), } @@ -1304,8 +1253,9 @@ impl IBCDHelper for IBCDHelperReal { { let is_decentralized = proxy.is_decentralized; - let mut stream_info = proxy.stream_info_mut(&stream_key) - .expect(&format!("Stream key {} disappeared!", &stream_key)); + let mut stream_info = proxy + .stream_info_mut(&stream_key) + .unwrap_or_else(|| panic!("Stream key {} disappeared!", &stream_key)); if stream_info.dns_failure_retry_opt.is_none() { let dns_failure_retry = DNSFailureRetry { unsuccessful_request: payload.clone(), @@ -1318,8 +1268,9 @@ impl IBCDHelper for IBCDHelperReal { let args = TransmitToHopperArgs::new(proxy, payload, client_addr, timestamp, retire_stream_key); let pld = &args.payload; - let stream_info = proxy.stream_info(&pld.stream_key, &proxy.logger) - .expect(&format!("Stream key {} disappeared!", &pld.stream_key)); + let stream_info = proxy + .stream_info(&pld.stream_key, &proxy.logger) + .unwrap_or_else(|| panic!("Stream key {} disappeared!", &pld.stream_key)); if let Some(route_query_response) = &stream_info.route_opt { debug!( proxy.logger, @@ -1333,11 +1284,7 @@ impl IBCDHelper for IBCDHelperReal { } else { let route_source = proxy.out_subs("Neighborhood").route_source.clone(); let proxy_server_sub = proxy.out_subs("ProxyServer").route_result_sub.clone(); - self.request_route_and_transmit( - args, - route_source, - proxy_server_sub, - ); + self.request_route_and_transmit(args, route_source, proxy_server_sub); Ok(()) } } @@ -1368,11 +1315,7 @@ impl IBCDHelper for IBCDHelperReal { payload_size, )) .then(move |route_result| { - message_resolver.resolve_message( - args, - proxy_server_sub, - route_result, - ); + message_resolver.resolve_message(args, proxy_server_sub, route_result); Ok(()) }), ); @@ -1639,6 +1582,53 @@ mod tests { } } + struct StreamInfoBuilder { + product: StreamInfo, + } + + impl StreamInfoBuilder { + pub fn new() -> Self { + Self { + product: StreamInfo { + tunneled_host_opt: None, + dns_failure_retry_opt: None, + route_opt: None, + protocol_opt: None, + time_to_live_opt: None, + }, + } + } + + pub fn tunneled_host(mut self, host: &str) -> Self { + self.product.tunneled_host_opt = Some(host.to_string()); + self + } + + pub fn dns_failure_retry(mut self, retry: DNSFailureRetry) -> Self { + self.product.dns_failure_retry_opt = Some(retry); + self + } + + pub fn route(mut self, route: RouteQueryResponse) -> Self { + self.product.route_opt = Some(route); + self + } + + pub fn protocol(mut self, protocol: ProxyProtocol) -> Self { + self.product.protocol_opt = Some(protocol); + self + } + + pub fn time_to_live(mut self, ttl: SystemTime) -> Self { + self.product.time_to_live_opt = Some(ttl); + self + } + + pub fn build(self) -> StreamInfo { + self.product + } + } + #[test] fn constants_have_correct_values() { assert_eq!(CRASH_KEY, "PROXYSERVER"); @@ -1798,8 +1788,7 @@ mod tests { } #[test] - fn get_expected_services_produces_rri_when_it_exists() - { + fn get_expected_services_produces_rri_when_it_exists() { let mut subject = ProxyServer::new( main_cryptde(), alias_cryptde(), @@ -1810,23 +1799,23 @@ mod tests { ); let exit_public_key = PublicKey::new(&b"exit key"[..]); let stream_key = StreamKey::make_meaningless_stream_key(); - let back_services = vec![ExpectedService::Exit(exit_public_key, make_wallet("booga"), rate_pack(1000))]; - let expected_services = ExpectedServices::RoundTrip( - vec![], - back_services.clone() + let back_services = vec![ExpectedService::Exit( + exit_public_key, + make_wallet("booga"), + rate_pack(1000), + )]; + let expected_services = ExpectedServices::RoundTrip(vec![], back_services.clone()); + subject.stream_info.insert( + stream_key.clone(), + StreamInfoBuilder::new() + .route(RouteQueryResponse { + route: make_meaningless_route(), + expected_services: expected_services.clone(), + hostname_opt: None, + }) + .protocol(ProxyProtocol::TLS) + .build(), ); - subject - .stream_info.insert( - stream_key.clone(), - StreamInfoBuilder::new() - .route(RouteQueryResponse{ - route: make_meaningless_route(), - expected_services: expected_services.clone(), - hostname_opt: None, - }) - .protocol(ProxyProtocol::TLS) - .build(), - ); let result = subject.get_expected_return_services(&stream_key).unwrap(); @@ -2094,16 +2083,18 @@ mod tests { subject .keys_and_addrs .insert(stream_key.clone(), socket_addr.clone()); - subject.stream_info.insert( - stream_key.clone(), - StreamInfoBuilder::new().build() - ); + subject + .stream_info + .insert(stream_key.clone(), StreamInfoBuilder::new().build()); subject.stream_info.insert( stream_key.clone(), StreamInfoBuilder::new() - .route(RouteQueryResponse{ + .route(RouteQueryResponse { route: make_meaningless_route(), - expected_services: ExpectedServices::RoundTrip(vec![], vec![ExpectedService::Nothing]), + expected_services: ExpectedServices::RoundTrip( + vec![], + vec![ExpectedService::Nothing], + ), hostname_opt: None, }) .build(), @@ -2448,11 +2439,12 @@ mod tests { let mut subject = ProxyServer::new(main_cryptde, alias_cryptde, false, None, false, false); subject.stream_key_factory = Box::new(stream_key_factory); - subject.keys_and_addrs.insert(stream_key.clone(), socket_addr); - subject.stream_info.insert( - stream_key, - StreamInfoBuilder::new().build() - ); + subject + .keys_and_addrs + .insert(stream_key.clone(), socket_addr); + subject + .stream_info + .insert(stream_key, StreamInfoBuilder::new().build()); let subject_addr: Addr = subject.start(); let peer_actors = peer_actors_builder() .dispatcher(dispatcher) @@ -2533,10 +2525,9 @@ mod tests { ProxyServer::new(main_cryptde, alias_cryptde, false, None, false, false); subject.stream_key_factory = Box::new(stream_key_factory); subject.keys_and_addrs.insert(stream_key, socket_addr); - subject.stream_info.insert( - stream_key.clone(), - StreamInfoBuilder::new().build() - ); + subject + .stream_info + .insert(stream_key.clone(), StreamInfoBuilder::new().build()); let subject_addr: Addr = subject.start(); let peer_actors = peer_actors_builder() .dispatcher(dispatcher) @@ -2650,10 +2641,9 @@ mod tests { ); subject.stream_key_factory = Box::new(stream_key_factory); subject.keys_and_addrs.insert(stream_key, socket_addr); - subject.stream_info.insert( - stream_key.clone(), - StreamInfoBuilder::new().build() - ); + subject + .stream_info + .insert(stream_key.clone(), StreamInfoBuilder::new().build()); let subject_addr: Addr = subject.start(); let peer_actors = peer_actors_builder() .hopper(hopper_mock) @@ -3030,10 +3020,12 @@ mod tests { false, ); subject.stream_key_factory = Box::new(stream_key_factory); - subject.keys_and_addrs.insert(stream_key.clone(), socket_addr); + subject + .keys_and_addrs + .insert(stream_key.clone(), socket_addr); subject.stream_info.insert( stream_key, - StreamInfoBuilder::new().route(route_query_response).build() + StreamInfoBuilder::new().route(route_query_response).build(), ); subject.next_return_route_id = Cell::new(0); let subject_addr: Addr = subject.start(); @@ -3173,10 +3165,7 @@ mod tests { retire_stream_key_sub_opt: None, }; - let result = ProxyServer::try_transmit_to_hopper( - args, - route_query_response, - ); + let result = ProxyServer::try_transmit_to_hopper(args, route_query_response); System::current().stop(); system.run(); @@ -3283,10 +3272,7 @@ mod tests { retire_stream_key_sub_opt: Some(peer_actors.proxy_server.stream_shutdown_sub), }; - let result = ProxyServer::try_transmit_to_hopper( - args, - route_query_response, - ); + let result = ProxyServer::try_transmit_to_hopper(args, route_query_response); System::current().stop(); system.run(); @@ -3368,7 +3354,8 @@ mod tests { #[test] fn route_result_message_handler_logs_error_when_no_dns_retries_exist() { init_test_logging(); - let system = System::new("route_result_message_handler_logs_error_when_no_dns_retries_exist"); + let system = + System::new("route_result_message_handler_logs_error_when_no_dns_retries_exist"); let mut subject = ProxyServer::new( main_cryptde(), alias_cryptde(), @@ -3380,7 +3367,7 @@ mod tests { let stream_key = StreamKey::make_meaningless_stream_key(); subject.stream_info.insert( stream_key.clone(), - StreamInfoBuilder::new().build() // no DNS retries + StreamInfoBuilder::new().build(), // no DNS retries ); let subject_addr: Addr = subject.start(); let peer_actors = peer_actors_builder().build(); @@ -3567,10 +3554,7 @@ mod tests { retire_stream_key_sub_opt: None, }; - let _result = ProxyServer::try_transmit_to_hopper( - args, - route_result, - ); + let _result = ProxyServer::try_transmit_to_hopper(args, route_result); } #[test] @@ -3938,10 +3922,9 @@ mod tests { false, ); subject.keys_and_addrs.insert(stream_key, client_addr); - subject.stream_info.insert( - stream_key, - StreamInfoBuilder::new().build(), - ); + subject + .stream_info + .insert(stream_key, StreamInfoBuilder::new().build()); let system = System::new(test_name); let subject_addr: Addr = subject.start(); let peer_actors = peer_actors_builder() @@ -4064,11 +4047,14 @@ mod tests { StreamInfoBuilder::new() .route(RouteQueryResponse { route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip(vec![], vec![ExpectedService::Nothing]), + expected_services: ExpectedServices::RoundTrip( + vec![], + vec![ExpectedService::Nothing], + ), hostname_opt: None, }) .protocol(ProxyProtocol::TLS) - .build() + .build(), ); let subject_addr: Addr = subject.start(); let remaining_route = return_route_with_id(cryptde, 1234); @@ -4259,7 +4245,7 @@ mod tests { }) .protocol(ProxyProtocol::HTTP) .tunneled_host("hostname") - .build() + .build(), ); let proxy_server_addr = subject.start(); let schedule_stream_key_purge_sub = proxy_server_addr.clone().recipient(); @@ -4352,17 +4338,20 @@ mod tests { StreamInfoBuilder::new() .route(RouteQueryResponse { route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip(vec![], vec![ExpectedService::Exit( - exit_key, - exit_wallet.clone(), - exit_rates.clone(), - )]), + expected_services: ExpectedServices::RoundTrip( + vec![], + vec![ExpectedService::Exit( + exit_key, + exit_wallet.clone(), + exit_rates.clone(), + )], + ), hostname_opt: None, }) .tunneled_host("hostname") .protocol(ProxyProtocol::HTTP) .time_to_live(SystemTime::now()) - .build() + .build(), ); let (accountant, _, accountant_recording_arc) = make_recorder(); let (dispatcher, _, dispatcher_recording_arc) = make_recorder(); @@ -4445,27 +4434,30 @@ mod tests { StreamInfoBuilder::new() .route(RouteQueryResponse { route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip(vec![], vec![ - ExpectedService::Exit( - irrelevant_public_key.clone(), - incoming_route_d_wallet.clone(), - rate_pack_d, - ), - ExpectedService::Routing( - irrelevant_public_key.clone(), - incoming_route_e_wallet.clone(), - rate_pack_e, - ), - ExpectedService::Routing( - irrelevant_public_key.clone(), - incoming_route_f_wallet.clone(), - rate_pack_f, - ), - ExpectedService::Nothing, - ]), + expected_services: ExpectedServices::RoundTrip( + vec![], + vec![ + ExpectedService::Exit( + irrelevant_public_key.clone(), + incoming_route_d_wallet.clone(), + rate_pack_d, + ), + ExpectedService::Routing( + irrelevant_public_key.clone(), + incoming_route_e_wallet.clone(), + rate_pack_e, + ), + ExpectedService::Routing( + irrelevant_public_key.clone(), + incoming_route_f_wallet.clone(), + rate_pack_f, + ), + ExpectedService::Nothing, + ], + ), hostname_opt: None, }) - .build() + .build(), ); let subject_addr: Addr = subject.start(); let first_client_response_payload = ClientResponsePayload_0v1 { @@ -4624,34 +4616,37 @@ mod tests { subject.stream_info.insert( stream_key_clone.clone(), StreamInfoBuilder::new() - .dns_failure_retry(DNSFailureRetry{ + .dns_failure_retry(DNSFailureRetry { unsuccessful_request: dns_fail_client_payload, retries_left: 3, }) - .route(RouteQueryResponse{ + .route(RouteQueryResponse { route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip(vec![], vec![ - ExpectedService::Exit( - irrelevant_public_key.clone(), - incoming_route_d_wallet.clone(), - rate_pack_d, - ), - ExpectedService::Routing( - irrelevant_public_key.clone(), - incoming_route_e_wallet.clone(), - rate_pack_e, - ), - ExpectedService::Routing( - irrelevant_public_key.clone(), - incoming_route_f_wallet.clone(), - rate_pack_f, - ), - ExpectedService::Nothing, - ]), + expected_services: ExpectedServices::RoundTrip( + vec![], + vec![ + ExpectedService::Exit( + irrelevant_public_key.clone(), + incoming_route_d_wallet.clone(), + rate_pack_d, + ), + ExpectedService::Routing( + irrelevant_public_key.clone(), + incoming_route_e_wallet.clone(), + rate_pack_e, + ), + ExpectedService::Routing( + irrelevant_public_key.clone(), + incoming_route_f_wallet.clone(), + rate_pack_f, + ), + ExpectedService::Nothing, + ], + ), hostname_opt: None, }) .protocol(ProxyProtocol::TLS) - .build() + .build(), ); let subject_addr: Addr = subject.start(); let first_client_response_payload = ClientResponsePayload_0v1 { @@ -4678,7 +4673,10 @@ mod tests { subject_addr .try_send(AssertionsMessage { assertions: Box::new(move |proxy_server: &mut ProxyServer| { - let retry_opt = &proxy_server.stream_info(&stream_key_clone, &logger).unwrap().dns_failure_retry_opt; + let retry_opt = &proxy_server + .stream_info(&stream_key_clone, &logger) + .unwrap() + .dns_failure_retry_opt; assert!(retry_opt.is_none()); }), }) @@ -4712,24 +4710,27 @@ mod tests { subject.stream_info.insert( stream_key.clone(), StreamInfoBuilder::new() - .route(RouteQueryResponse{ + .route(RouteQueryResponse { route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip(vec![], vec![ - ExpectedService::Exit( - irrelevant_public_key.clone(), - incoming_route_d_wallet.clone(), - rate_pack_d, - ), - ExpectedService::Routing( - irrelevant_public_key.clone(), - incoming_route_e_wallet.clone(), - rate_pack_e, - ), - ]), + expected_services: ExpectedServices::RoundTrip( + vec![], + vec![ + ExpectedService::Exit( + irrelevant_public_key.clone(), + incoming_route_d_wallet.clone(), + rate_pack_d, + ), + ExpectedService::Routing( + irrelevant_public_key.clone(), + incoming_route_e_wallet.clone(), + rate_pack_e, + ), + ], + ), hostname_opt: None, }) .protocol(ProxyProtocol::TLS) - .build() + .build(), ); let subject_addr: Addr = subject.start(); let client_response_payload = ClientResponsePayload_0v1 { @@ -4817,21 +4818,24 @@ mod tests { subject.stream_info.insert( stream_key.clone(), StreamInfoBuilder::new() - .dns_failure_retry(DNSFailureRetry{ + .dns_failure_retry(DNSFailureRetry { unsuccessful_request: client_payload, retries_left: 0, }) - .route(RouteQueryResponse{ + .route(RouteQueryResponse { route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip(vec![], vec![ExpectedService::Exit( - exit_public_key.clone(), - exit_wallet, - rate_pack(10), - )]), + expected_services: ExpectedServices::RoundTrip( + vec![], + vec![ExpectedService::Exit( + exit_public_key.clone(), + exit_wallet, + rate_pack(10), + )], + ), hostname_opt: Some("server.com".to_string()), }) .protocol(ProxyProtocol::HTTP) - .build() + .build(), ); let subject_addr: Addr = subject.start(); let dns_resolve_failure = DnsResolveFailure_0v1::new(stream_key); @@ -4894,34 +4898,37 @@ mod tests { subject.stream_info.insert( stream_key.clone(), StreamInfoBuilder::new() - .dns_failure_retry(DNSFailureRetry{ + .dns_failure_retry(DNSFailureRetry { unsuccessful_request: client_payload, retries_left: 0, }) - .route(RouteQueryResponse{ + .route(RouteQueryResponse { route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip(vec![], vec![ - ExpectedService::Exit( - irrelevant_public_key.clone(), - incoming_route_d_wallet.clone(), - rate_pack_d, - ), - ExpectedService::Routing( - irrelevant_public_key.clone(), - incoming_route_e_wallet.clone(), - rate_pack_e, - ), - ExpectedService::Routing( - irrelevant_public_key.clone(), - incoming_route_f_wallet.clone(), - rate_pack_f, - ), - ExpectedService::Nothing, - ]), + expected_services: ExpectedServices::RoundTrip( + vec![], + vec![ + ExpectedService::Exit( + irrelevant_public_key.clone(), + incoming_route_d_wallet.clone(), + rate_pack_d, + ), + ExpectedService::Routing( + irrelevant_public_key.clone(), + incoming_route_e_wallet.clone(), + rate_pack_e, + ), + ExpectedService::Routing( + irrelevant_public_key.clone(), + incoming_route_f_wallet.clone(), + rate_pack_f, + ), + ExpectedService::Nothing, + ], + ), hostname_opt: None, }) .protocol(ProxyProtocol::TLS) - .build() + .build(), ); let subject_addr: Addr = subject.start(); let dns_resolve_failure_payload = DnsResolveFailure_0v1::new(stream_key); @@ -5005,21 +5012,24 @@ mod tests { subject.stream_info.insert( stream_key.clone(), StreamInfoBuilder::new() - .dns_failure_retry(DNSFailureRetry{ + .dns_failure_retry(DNSFailureRetry { unsuccessful_request: client_payload, retries_left: 0, }) - .route(RouteQueryResponse{ + .route(RouteQueryResponse { route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip(vec![], vec![ExpectedService::Exit( - exit_public_key.clone(), - exit_wallet.clone(), - rate_pack(10), - )]), + expected_services: ExpectedServices::RoundTrip( + vec![], + vec![ExpectedService::Exit( + exit_public_key.clone(), + exit_wallet.clone(), + rate_pack(10), + )], + ), hostname_opt: Some("server.com".to_string()), }) .protocol(ProxyProtocol::HTTP) - .build() + .build(), ); let subject_addr: Addr = subject.start(); let dns_resolve_failure = DnsResolveFailure_0v1::new(stream_key); @@ -5084,21 +5094,24 @@ mod tests { subject.stream_info.insert( stream_key, StreamInfoBuilder::new() - .dns_failure_retry(DNSFailureRetry{ + .dns_failure_retry(DNSFailureRetry { unsuccessful_request: client_payload, retries_left: 0, }) - .route(RouteQueryResponse{ + .route(RouteQueryResponse { route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip(vec![], vec![ExpectedService::Exit( - exit_public_key.clone(), - exit_wallet, - rate_pack(10), - )]), + expected_services: ExpectedServices::RoundTrip( + vec![], + vec![ExpectedService::Exit( + exit_public_key.clone(), + exit_wallet, + rate_pack(10), + )], + ), hostname_opt: None, }) .protocol(ProxyProtocol::HTTP) - .build() + .build(), ); let subject_addr: Addr = subject.start(); let dns_resolve_failure = DnsResolveFailure_0v1::new(stream_key); @@ -5128,7 +5141,8 @@ mod tests { } #[test] - fn handle_dns_resolve_failure_logs_when_stream_key_is_found_in_stream_info_but_not_keys_and_addrs() { + fn handle_dns_resolve_failure_logs_when_stream_key_is_found_in_stream_info_but_not_keys_and_addrs( + ) { init_test_logging(); let system = System::new("test"); let (neighborhood_mock, _, _) = make_recorder(); @@ -5150,21 +5164,24 @@ mod tests { subject.stream_info.insert( stream_key, StreamInfoBuilder::new() - .dns_failure_retry(DNSFailureRetry{ + .dns_failure_retry(DNSFailureRetry { unsuccessful_request: client_payload, retries_left: 0, }) - .route(RouteQueryResponse{ + .route(RouteQueryResponse { route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip(vec![], vec![ExpectedService::Exit( - exit_public_key.clone(), - exit_wallet.clone(), - rate_pack(10), - )]), + expected_services: ExpectedServices::RoundTrip( + vec![], + vec![ExpectedService::Exit( + exit_public_key.clone(), + exit_wallet.clone(), + rate_pack(10), + )], + ), hostname_opt: Some("server.com".to_string()), }) .protocol(ProxyProtocol::HTTP) - .build() + .build(), ); let subject_addr: Addr = subject.start(); let dns_resolve_failure = DnsResolveFailure_0v1::new(stream_key); @@ -5224,21 +5241,24 @@ mod tests { subject.stream_info.insert( stream_key, StreamInfoBuilder::new() - .dns_failure_retry(DNSFailureRetry{ + .dns_failure_retry(DNSFailureRetry { unsuccessful_request: client_payload, retries_left: 0, }) - .route(RouteQueryResponse{ + .route(RouteQueryResponse { route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip(vec![], vec![ExpectedService::Exit( - exit_public_key.clone(), - exit_wallet.clone(), - rate_pack(10), - )]), + expected_services: ExpectedServices::RoundTrip( + vec![], + vec![ExpectedService::Exit( + exit_public_key.clone(), + exit_wallet.clone(), + rate_pack(10), + )], + ), hostname_opt: None, }) .protocol(ProxyProtocol::HTTP) - .build() + .build(), ); let subject_addr: Addr = subject.start(); let dns_resolve_failure = DnsResolveFailure_0v1::new(stream_key); @@ -5263,12 +5283,10 @@ mod tests { System::current().stop(); system.run(); - TestLogHandler::new().exists_log_containing( - &format!( - "Discarding DnsResolveFailure message from an unrecognized stream key {:?}", - stream_key - ) - ); + TestLogHandler::new().exists_log_containing(&format!( + "Discarding DnsResolveFailure message from an unrecognized stream key {:?}", + stream_key + )); } #[test] @@ -5301,7 +5319,7 @@ mod tests { subject.stream_info.insert( stream_key, StreamInfoBuilder::new() - .dns_failure_retry(DNSFailureRetry{ + .dns_failure_retry(DNSFailureRetry { unsuccessful_request: client_payload, retries_left: 0, }) @@ -5313,12 +5331,12 @@ mod tests { vec![ make_exit_service_from_key(PublicKey::new(b"exit_node")), ExpectedService::Nothing, - ] + ], ), hostname_opt: None, }) .protocol(ProxyProtocol::HTTP) - .build() + .build(), ); let dns_resolve_failure = DnsResolveFailure_0v1::new(stream_key); let expired_cores_package: ExpiredCoresPackage = @@ -5360,17 +5378,20 @@ mod tests { subject.stream_info.insert( stream_key.clone(), StreamInfoBuilder::new() - .dns_failure_retry(DNSFailureRetry{ + .dns_failure_retry(DNSFailureRetry { unsuccessful_request: client_payload, retries_left: 0, }) - .route(RouteQueryResponse{ + .route(RouteQueryResponse { route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip(vec![], vec![ExpectedService::Nothing, ExpectedService::Nothing]), + expected_services: ExpectedServices::RoundTrip( + vec![], + vec![ExpectedService::Nothing, ExpectedService::Nothing], + ), hostname_opt: Some("server.com".to_string()), }) .protocol(ProxyProtocol::HTTP) - .build() + .build(), ); let subject_addr: Addr = subject.start(); let dns_resolve_failure = DnsResolveFailure_0v1::new(stream_key); @@ -5460,17 +5481,20 @@ mod tests { subject.stream_info.insert( stream_key.clone(), StreamInfoBuilder::new() - .dns_failure_retry(DNSFailureRetry{ + .dns_failure_retry(DNSFailureRetry { unsuccessful_request: client_payload.clone(), retries_left: 3, }) - .route(RouteQueryResponse{ + .route(RouteQueryResponse { route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip(vec![], expected_services.clone()), + expected_services: ExpectedServices::RoundTrip( + vec![], + expected_services.clone(), + ), hostname_opt: Some("server.com".to_string()), }) .protocol(ProxyProtocol::HTTP) - .build() + .build(), ); let message_resolver = RouteQueryResponseResolverMock::default() .resolve_message_params(&resolve_message_params_arc); @@ -5501,7 +5525,8 @@ mod tests { assertions: Box::new(move |proxy_server: &mut ProxyServer| { let retry = proxy_server .stream_info(&stream_key, &logger) - .unwrap().dns_failure_retry_opt + .unwrap() + .dns_failure_retry_opt .as_ref() .unwrap(); assert_eq!(retry.retries_left, 2); @@ -5558,13 +5583,16 @@ mod tests { subject.stream_info.insert( stream_key.clone(), StreamInfoBuilder::new() - .route(RouteQueryResponse{ + .route(RouteQueryResponse { route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip(vec![], expected_services.clone()), + expected_services: ExpectedServices::RoundTrip( + vec![], + expected_services.clone(), + ), hostname_opt: Some("server.com".to_string()), }) .protocol(ProxyProtocol::HTTP) - .build() + .build(), ); let subject_addr: Addr = subject.start(); let dns_resolve_failure = DnsResolveFailure_0v1::new(stream_key); @@ -5638,17 +5666,20 @@ mod tests { subject.stream_info.insert( stream_key_clone.clone(), StreamInfoBuilder::new() - .dns_failure_retry(DNSFailureRetry{ + .dns_failure_retry(DNSFailureRetry { unsuccessful_request: client_payload, retries_left: 3, }) - .route(RouteQueryResponse{ + .route(RouteQueryResponse { route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip(vec![], expected_services.clone()), + expected_services: ExpectedServices::RoundTrip( + vec![], + expected_services.clone(), + ), hostname_opt: Some("server.com".to_string()), }) .protocol(ProxyProtocol::HTTP) - .build() + .build(), ); let message_resolver_factory = RouteQueryResponseResolverFactoryMock::default() .make_params(&make_params_arc) @@ -5723,13 +5754,16 @@ mod tests { subject.stream_info.insert( stream_key.clone(), StreamInfoBuilder::new() - .route(RouteQueryResponse{ + .route(RouteQueryResponse { route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip(vec![], vec![ExpectedService::Nothing]), + expected_services: ExpectedServices::RoundTrip( + vec![], + vec![ExpectedService::Nothing], + ), hostname_opt: None, }) .protocol(ProxyProtocol::HTTP) - .build() + .build(), ); let subject_addr: Addr = subject.start(); @@ -5849,7 +5883,7 @@ mod tests { subject .keys_and_addrs .insert(unaffected_stream_key, unaffected_socket_addr); - subject.stream_info.insert ( + subject.stream_info.insert( unaffected_stream_key, StreamInfoBuilder::new() .route(RouteQueryResponse { @@ -5858,7 +5892,7 @@ mod tests { hostname_opt: Some("booga.com".to_string()), }) .tunneled_host("blah") - .build() + .build(), ); subject.handle_stream_shutdown_msg(StreamShutdownMsg { @@ -5875,10 +5909,12 @@ mod tests { .keys_and_addrs .a_to_b(&unaffected_stream_key) .is_some()); + assert!(subject.stream_info.contains_key(&unaffected_stream_key)); assert!(subject - .stream_info - .contains_key(&unaffected_stream_key)); - assert!(subject.stream_info(&unaffected_stream_key, &logger).unwrap().tunneled_host_opt.is_some()); + .stream_info(&unaffected_stream_key, &logger) + .unwrap() + .tunneled_host_opt + .is_some()); } #[test] @@ -5912,7 +5948,7 @@ mod tests { hostname_opt: Some("booga.com".to_string()), }) .tunneled_host("blah") - .build() + .build(), ); let affected_route = Route::round_trip( RouteSegment::new( @@ -5938,11 +5974,14 @@ mod tests { StreamInfoBuilder::new() .route(RouteQueryResponse { route: affected_route.clone(), - expected_services: ExpectedServices::RoundTrip(affected_expected_services, vec![]), + expected_services: ExpectedServices::RoundTrip( + affected_expected_services, + vec![], + ), hostname_opt: Some("booga.com".to_string()), }) .tunneled_host("tunneled.com") - .build() + .build(), ); let subject_addr = subject.start(); let (hopper, _, hopper_recording_arc) = make_recorder(); @@ -6036,7 +6075,7 @@ mod tests { expected_services: ExpectedServices::RoundTrip(vec![], vec![]), hostname_opt: Some("booga.com".to_string()), }) - .build() + .build(), ); subject.next_return_route_id = Cell::new(1234); let affected_route = Route::round_trip( @@ -6063,10 +6102,13 @@ mod tests { StreamInfoBuilder::new() .route(RouteQueryResponse { route: affected_route.clone(), - expected_services: ExpectedServices::RoundTrip(affected_expected_services, vec![]), + expected_services: ExpectedServices::RoundTrip( + affected_expected_services, + vec![], + ), hostname_opt: Some("booga.com".to_string()), }) - .build() + .build(), ); subject.logger = Logger::new(test_name); let subject_addr = subject.start(); @@ -6145,10 +6187,9 @@ mod tests { let socket_addr = SocketAddr::from_str("3.4.5.6:7777").unwrap(); let stream_key = StreamKey::make_meaningful_stream_key("All Things Must Pass"); subject.keys_and_addrs.insert(stream_key, socket_addr); - subject.stream_info.insert( - stream_key.clone(), - StreamInfoBuilder::new().build() - ); + subject + .stream_info + .insert(stream_key.clone(), StreamInfoBuilder::new().build()); let msg = StreamShutdownMsg { peer_addr: socket_addr, stream_type: RemovedStreamType::NonClandestine(NonClandestineAttributes { @@ -6176,7 +6217,7 @@ mod tests { let socket_addr = SocketAddr::from_str("3.4.5.6:7890").unwrap(); let stream_key = StreamKey::make_meaningful_stream_key("All Things Must Pass"); subject.keys_and_addrs.insert(stream_key, socket_addr); - subject.stream_info.insert ( + subject.stream_info.insert( stream_key, StreamInfoBuilder::new() .route(RouteQueryResponse { @@ -6185,7 +6226,7 @@ mod tests { hostname_opt: Some("booga.com".to_string()), }) .tunneled_host("blah") - .build() + .build(), ); let msg = StreamShutdownMsg { peer_addr: socket_addr, @@ -6263,11 +6304,7 @@ mod tests { let subject = RouteQueryResponseResolverReal {}; let system = System::new("resolve_message_handles_mailbox_error_from_neighborhood"); - subject.resolve_message( - args, - proxy_server_sub, - Err(MailboxError::Timeout), - ); + subject.resolve_message(args, proxy_server_sub, Err(MailboxError::Timeout)); System::current().stop(); system.run(); @@ -6403,7 +6440,12 @@ mod tests { subject_addr .try_send(AssertionsMessage { assertions: Box::new(move |proxy_server: &mut ProxyServer| { - let dns_retry = proxy_server.stream_info(&stream_key, &logger).unwrap().dns_failure_retry_opt.as_ref().unwrap(); + let dns_retry = proxy_server + .stream_info(&stream_key, &logger) + .unwrap() + .dns_failure_retry_opt + .as_ref() + .unwrap(); assert_eq!(dns_retry.retries_left, 3); assert_eq!(dns_retry.unsuccessful_request, expected_payload); }), @@ -6415,7 +6457,8 @@ mod tests { #[test] fn new_http_request_creates_new_exhausted_entry_inside_dns_retries_hashmap_zero_hop() { - let test_name = "new_http_request_creates_new_exhausted_entry_inside_dns_retries_hashmap_zero_hop"; + let test_name = + "new_http_request_creates_new_exhausted_entry_inside_dns_retries_hashmap_zero_hop"; let logger = Logger::new(test_name); let main_cryptde = main_cryptde(); let alias_cryptde = alias_cryptde(); @@ -6474,7 +6517,12 @@ mod tests { subject_addr .try_send(AssertionsMessage { assertions: Box::new(move |proxy_server: &mut ProxyServer| { - let dns_retry = proxy_server.stream_info(&stream_key, &logger).unwrap().dns_failure_retry_opt.as_ref().unwrap(); + let dns_retry = proxy_server + .stream_info(&stream_key, &logger) + .unwrap() + .dns_failure_retry_opt + .as_ref() + .unwrap(); assert_eq!(dns_retry.retries_left, 0); assert_eq!(dns_retry.unsuccessful_request, expected_payload); }), diff --git a/node/src/sub_lib/hopper.rs b/node/src/sub_lib/hopper.rs index 5c1c000a73..935a16ba1d 100644 --- a/node/src/sub_lib/hopper.rs +++ b/node/src/sub_lib/hopper.rs @@ -173,6 +173,7 @@ mod tests { use crate::sub_lib::cryptde::PlainData; use crate::sub_lib::dispatcher::Component; use crate::sub_lib::route::RouteSegment; + use crate::sub_lib::stream_key::StreamKey; use crate::test_utils::recorder::Recorder; use crate::test_utils::{main_cryptde, make_meaningless_message_type, make_paying_wallet}; use actix::Actor; @@ -200,7 +201,7 @@ mod tests { let cryptde = main_cryptde(); let public_key = PublicKey::new(&[1, 2]); let node_addr = NodeAddr::new(&IpAddr::from_str("1.2.3.4").unwrap(), &[1, 2, 3, 4]); - let payload = make_meaningless_message_type(); + let payload = make_meaningless_message_type(StreamKey::make_meaningless_stream_key()); let result = NoLookupIncipientCoresPackage::new(cryptde, &public_key, &node_addr, payload.clone()); @@ -226,7 +227,7 @@ mod tests { cryptde, &PublicKey::new(&[]), &NodeAddr::new(&IpAddr::from_str("1.1.1.1").unwrap(), &[]), - make_meaningless_message_type(), + make_meaningless_message_type(StreamKey::make_meaningless_stream_key()), ); assert_eq!( result, @@ -250,7 +251,7 @@ mod tests { Some(TEST_DEFAULT_CHAIN.rec().contract), ) .unwrap(); - let payload = make_meaningless_message_type(); + let payload = make_meaningless_message_type(StreamKey::make_meaningless_stream_key()); let result = IncipientCoresPackage::new(cryptde, route.clone(), payload.clone(), &key56); let subject = result.unwrap(); @@ -273,7 +274,7 @@ mod tests { let result = IncipientCoresPackage::new( cryptde, Route { hops: vec![] }, - make_meaningless_message_type(), + make_meaningless_message_type(StreamKey::make_meaningless_stream_key()), &PublicKey::new(&[]), ); @@ -299,7 +300,7 @@ mod tests { Some(TEST_DEFAULT_CHAIN.rec().contract), ) .unwrap(); - let payload = make_meaningless_message_type(); + let payload = make_meaningless_message_type(StreamKey::make_meaningless_stream_key()); let subject: ExpiredCoresPackage = ExpiredCoresPackage::new( immediate_neighbor, diff --git a/node/src/sub_lib/neighborhood.rs b/node/src/sub_lib/neighborhood.rs index 1905bf2b20..e30310df71 100644 --- a/node/src/sub_lib/neighborhood.rs +++ b/node/src/sub_lib/neighborhood.rs @@ -512,7 +512,9 @@ impl ExpectedService { pub fn public_key_opt(&self) -> Option { match self { - ExpectedService::Exit(key, _, _) | ExpectedService::Routing(key, _, _) => Some(key.clone()), + ExpectedService::Exit(key, _, _) | ExpectedService::Routing(key, _, _) => { + Some(key.clone()) + } _ => None, } } diff --git a/node/src/sub_lib/proxy_server.rs b/node/src/sub_lib/proxy_server.rs index 644bef24e6..97b541b25b 100644 --- a/node/src/sub_lib/proxy_server.rs +++ b/node/src/sub_lib/proxy_server.rs @@ -4,7 +4,7 @@ use crate::sub_lib::data_version::DataVersion; use crate::sub_lib::dispatcher::InboundClientData; use crate::sub_lib::dispatcher::StreamShutdownMsg; use crate::sub_lib::hopper::{ExpiredCoresPackage, MessageType}; -use crate::sub_lib::neighborhood::{RouteQueryResponse}; +use crate::sub_lib::neighborhood::RouteQueryResponse; use crate::sub_lib::peer_actors::BindMessage; use crate::sub_lib::proxy_client::{ClientResponsePayload_0v1, DnsResolveFailure_0v1}; use crate::sub_lib::sequence_buffer::SequencedPacket; diff --git a/node/src/sub_lib/stream_key.rs b/node/src/sub_lib/stream_key.rs index e14efd358b..de5003ee81 100644 --- a/node/src/sub_lib/stream_key.rs +++ b/node/src/sub_lib/stream_key.rs @@ -99,9 +99,7 @@ impl StreamKey { pub fn make_meaningless_stream_key() -> StreamKey { let mut bytes = [0; sha1::DIGEST_LENGTH]; randombytes_into(&mut bytes); - StreamKey { - hash: bytes, - } + StreamKey { hash: bytes } } pub fn make_meaningful_stream_key(phrase: &str) -> StreamKey { diff --git a/node/src/test_utils/mod.rs b/node/src/test_utils/mod.rs index f2d3f0c72a..148c18a21d 100644 --- a/node/src/test_utils/mod.rs +++ b/node/src/test_utils/mod.rs @@ -448,8 +448,8 @@ pub fn read_until_timeout(stream: &mut dyn Read) -> Vec { response } -pub fn make_meaningless_message_type() -> MessageType { - DnsResolveFailure_0v1::new(StreamKey::make_meaningless_stream_key()).into() +pub fn make_meaningless_message_type(stream_key: StreamKey) -> MessageType { + DnsResolveFailure_0v1::new(stream_key).into() } pub fn handle_connection_error(stream: TcpStream) { diff --git a/node/src/test_utils/recorder.rs b/node/src/test_utils/recorder.rs index f1f841126d..20daaec868 100644 --- a/node/src/test_utils/recorder.rs +++ b/node/src/test_utils/recorder.rs @@ -39,10 +39,8 @@ use crate::sub_lib::peer_actors::PeerActors; use crate::sub_lib::peer_actors::{BindMessage, NewPublicIp, StartMessage}; use crate::sub_lib::proxy_client::{ClientResponsePayload_0v1, InboundServerData}; use crate::sub_lib::proxy_client::{DnsResolveFailure_0v1, ProxyClientSubs}; -use crate::sub_lib::proxy_server::{ - ClientRequestPayload_0v1, StreamKeyPurge, -}; use crate::sub_lib::proxy_server::{AddRouteResultMessage, ProxyServerSubs}; +use crate::sub_lib::proxy_server::{ClientRequestPayload_0v1, StreamKeyPurge}; use crate::sub_lib::stream_handler_pool::DispatcherNodeQueryResponse; use crate::sub_lib::stream_handler_pool::TransmitDataMsg; use crate::sub_lib::ui_gateway::UiGatewaySubs; From 379817775d0b3e933b531b363b105236e439ec68 Mon Sep 17 00:00:00 2001 From: Dan Wiebe Date: Wed, 1 Oct 2025 07:04:20 -0400 Subject: [PATCH 18/21] All the tests pass now --- node/src/neighborhood/mod.rs | 87 +++++++++++++-------- node/src/proxy_server/mod.rs | 145 +++++++++++++++++++++-------------- 2 files changed, 146 insertions(+), 86 deletions(-) diff --git a/node/src/neighborhood/mod.rs b/node/src/neighborhood/mod.rs index f90b7926bb..af6dbccacf 100644 --- a/node/src/neighborhood/mod.rs +++ b/node/src/neighborhood/mod.rs @@ -497,7 +497,7 @@ impl Neighborhood { fn handle_route_query_message(&mut self, msg: RouteQueryMessage) -> Option { let debug_msg_opt = self.logger.debug_enabled().then(|| format!("{:?}", msg)); let route_result = if self.mode == NeighborhoodModeLight::ZeroHop { - Ok(self.zero_hop_route_response()) + Ok(self.zero_hop_route_response(msg.hostname_opt)) } else { self.make_round_trip_route(msg) }; @@ -977,7 +977,7 @@ impl Neighborhood { .expect("route creation error") } - fn zero_hop_route_response(&mut self) -> RouteQueryResponse { + fn zero_hop_route_response(&mut self, hostname_opt: Option) -> RouteQueryResponse { let route = Route::round_trip( RouteSegment::new( vec![self.cryptde.public_key(), self.cryptde.public_key()], @@ -998,7 +998,7 @@ impl Neighborhood { vec![ExpectedService::Nothing, ExpectedService::Nothing], vec![ExpectedService::Nothing, ExpectedService::Nothing], ), - hostname_opt: None, + hostname_opt, } } @@ -2174,6 +2174,15 @@ mod tests { use actix::Recipient; use actix::System; use itertools::Itertools; + use masq_lib::constants::{DEFAULT_CHAIN, TLS_PORT}; + use masq_lib::messages::{ + CountryGroups, ToMessageBody, UiConnectionChangeBroadcast, UiConnectionStage, + }; + use masq_lib::test_utils::utils::{ensure_node_home_directory_exists, TEST_DEFAULT_CHAIN}; + use masq_lib::ui_gateway::MessageBody; + use masq_lib::ui_gateway::MessagePath::Conversation; + use masq_lib::ui_gateway::MessageTarget; + use masq_lib::utils::running_test; use serde_cbor; use std::any::TypeId; use std::cell::RefCell; @@ -2187,16 +2196,7 @@ mod tests { use std::time::Duration; use std::time::Instant; use tokio::prelude::Future; - - use masq_lib::constants::{DEFAULT_CHAIN, TLS_PORT}; - use masq_lib::messages::{ - CountryGroups, ToMessageBody, UiConnectionChangeBroadcast, UiConnectionStage, - }; - use masq_lib::test_utils::utils::{ensure_node_home_directory_exists, TEST_DEFAULT_CHAIN}; - use masq_lib::ui_gateway::MessageBody; - use masq_lib::ui_gateway::MessagePath::Conversation; - use masq_lib::ui_gateway::MessageTarget; - use masq_lib::utils::running_test; + use ExpectedService::Exit; use crate::db_config::persistent_configuration::PersistentConfigError; use crate::neighborhood::gossip::Gossip_0v1; @@ -2248,6 +2248,8 @@ mod tests { use crate::neighborhood::overall_connection_status::{ ConnectionProgress, ConnectionStage, OverallConnectionStage, }; + use crate::sub_lib::neighborhood::ExpectedService::{Nothing, Routing}; + use crate::sub_lib::neighborhood::ExpectedServices::RoundTrip; use crate::test_utils::unshared_test_utils::notify_handlers::NotifyLaterHandleMock; use masq_lib::test_utils::logging::{init_test_logging, TestLogHandler}; @@ -3378,14 +3380,14 @@ mod tests { expected_services: ExpectedServices::RoundTrip( vec![ ExpectedService::Nothing, - ExpectedService::Exit( + Exit( desirable_exit_node.public_key().clone(), desirable_exit_node.earning_wallet(), rate_pack(2345), ), ], vec![ - ExpectedService::Exit( + Exit( desirable_exit_node.public_key().clone(), desirable_exit_node.earning_wallet(), rate_pack(2345), @@ -3426,7 +3428,8 @@ mod tests { let sub: Recipient = addr.recipient::(); let future = sub.send(RouteQueryMessage::data_indefinite_route_request( - None, 12345, + Some("google.com".to_string()), + 12345, )); System::current().stop_with_code(0); @@ -3451,7 +3454,7 @@ mod tests { vec![ExpectedService::Nothing, ExpectedService::Nothing], vec![ExpectedService::Nothing, ExpectedService::Nothing], ), - hostname_opt: None, + hostname_opt: Some("google.com".to_string()), }; assert_eq!(result, expected_response); } @@ -3525,18 +3528,10 @@ mod tests { q.earning_wallet(), rate_pack(3456), ), - ExpectedService::Exit( - r.public_key().clone(), - r.earning_wallet(), - rate_pack(4567), - ), + Exit(r.public_key().clone(), r.earning_wallet(), rate_pack(4567)), ], vec![ - ExpectedService::Exit( - r.public_key().clone(), - r.earning_wallet(), - rate_pack(4567), - ), + Exit(r.public_key().clone(), r.earning_wallet(), rate_pack(4567)), ExpectedService::Routing( q.public_key().clone(), q.earning_wallet(), @@ -6934,14 +6929,14 @@ mod tests { target_component: Component::ProxyClient, return_component_opt: Some(Component::ProxyServer), payload_size: 10000, - hostname_opt: None, + hostname_opt: Some("host.name".to_string()), }); let next_door_neighbor_cryptde = CryptDENull::from(&next_door_neighbor.public_key(), TEST_DEFAULT_CHAIN); let exit_node_cryptde = CryptDENull::from(&exit_node.public_key(), TEST_DEFAULT_CHAIN); - - let hops = result.clone().unwrap().route.hops; + let response = result.clone().unwrap(); + let hops = &response.route.hops; let actual_keys: Vec = match hops.as_slice() { [hop, exit, hop_back, origin, empty] => vec![ decodex::(main_cryptde(), hop) @@ -6974,6 +6969,38 @@ mod tests { PublicKey::new(b""), ]; assert_eq!(expected_public_keys, actual_keys); + assert_eq!( + response.expected_services, + RoundTrip( + vec![ + Nothing, + Routing( + next_door_neighbor.public_key().clone(), + next_door_neighbor.earning_wallet(), + next_door_neighbor.rate_pack().clone() + ), + Exit( + exit_node.public_key().clone(), + exit_node.earning_wallet(), + exit_node.rate_pack().clone() + ), + ], + vec![ + Exit( + exit_node.public_key().clone(), + exit_node.earning_wallet(), + exit_node.rate_pack().clone() + ), + Routing( + next_door_neighbor.public_key().clone(), + next_door_neighbor.earning_wallet(), + next_door_neighbor.rate_pack().clone() + ), + Nothing, + ] + ) + ); + assert_eq!(response.hostname_opt, Some("host.name".to_string())); } fn assert_route_query_message(min_hops: Hops) { diff --git a/node/src/proxy_server/mod.rs b/node/src/proxy_server/mod.rs index 2912ac5da3..6442d77265 100644 --- a/node/src/proxy_server/mod.rs +++ b/node/src/proxy_server/mod.rs @@ -59,8 +59,8 @@ use tokio::prelude::Future; pub const CRASH_KEY: &str = "PROXYSERVER"; pub const RETURN_ROUTE_TTL_FIRST_CHANCE: Duration = Duration::from_secs(120); pub const RETURN_ROUTE_TTL_STRAGGLERS: Duration = Duration::from_secs(5); - pub const STREAM_KEY_PURGE_DELAY: Duration = Duration::from_secs(30); +pub const DNS_FAILURE_RETRIES: usize = 3; struct ProxyServerOutSubs { dispatcher: Recipient, @@ -73,7 +73,7 @@ struct ProxyServerOutSubs { schedule_stream_key_purge: Recipient>, } -#[derive(Clone)] +#[derive(Clone, Debug)] struct StreamInfo { tunneled_host_opt: Option, dns_failure_retry_opt: Option, @@ -148,56 +148,7 @@ impl Handler for ProxyServer { type Result = (); fn handle(&mut self, msg: AddRouteResultMessage, _ctx: &mut Self::Context) -> Self::Result { - let mut delayed_log: Box = Box::new(|_: &Logger| {}); - if let Some(stream_info) = self.stream_info_mut(&msg.stream_key) { - match &stream_info.dns_failure_retry_opt { - Some(dns_failure) => match msg.result { - Ok(route_query_response) => { - let target_hostname = - dns_failure.unsuccessful_request.target_hostname.clone(); - let retries_left = dns_failure.retries_left; - let stream_key = msg.stream_key; - delayed_log = Box::new(move |logger: &Logger| { - debug!( - logger, - "Found a new route for hostname: {:?} - stream key: {} retries left: {}", - target_hostname, - stream_key, - retries_left - ); - }); - stream_info.route_opt = Some(route_query_response); - } - Err(e) => { - let target_hostname = - dns_failure.unsuccessful_request.target_hostname.clone(); - let retries_left = dns_failure.retries_left; - let stream_key = msg.stream_key; - delayed_log = Box::new(move |logger: &Logger| { - warning!( - logger, - "No route found for hostname: {:?} - stream key {} - retries left: {} - AddRouteResultMessage Error: {}", - target_hostname, - stream_key, - retries_left, - e - ); - }); - } - }, - None => { - let stream_key = msg.stream_key; - delayed_log = Box::new(move |logger: &Logger| { - error!( - logger, - "No dns_failure_retry found for stream key {} while handling AddRouteResultMessage", - stream_key - ); - }); - } - }; - } - delayed_log(&self.logger); + self.handle_add_route_result_message(msg) } } @@ -398,6 +349,82 @@ impl ProxyServer { } } + fn handle_add_route_result_message(&mut self, msg: AddRouteResultMessage) { + type DelayedLogArgs = Box, StreamKey, usize, String)>; + #[allow(unused_assignments)] + let mut delayed_log: DelayedLogArgs = Box::new(|_, _, _, _, _| {}); + let (target_hostname_opt, stream_key, retries_left, message) = { + let mut stream_info = self.stream_info_mut(&msg.stream_key).unwrap_or_else(|| { + panic!( + "AddRouteResultMessage Handler: stream key: {} not found", + msg.stream_key + ) + }); + let dns_failure_retry = stream_info + .dns_failure_retry_opt + .as_ref() + .unwrap_or_else(|| + panic!("AddRouteResultMessage Handler: dns_failure_retry_opt is None for stream key {}", msg.stream_key) + ); + let mut message = String::new(); + match msg.result { + Ok(route_query_response) => { + delayed_log = Box::new( + move |logger: &Logger, + target_hostname_opt: Option, + stream_key: StreamKey, + retries_left: usize, + _: String| { + debug!( + logger, + "Found a new route for hostname: {:?} - stream key: {} retries left: {}", + target_hostname_opt, + stream_key, + retries_left + ); + }, + ); + stream_info.route_opt = Some(route_query_response); + } + Err(e) => { + message = e; + delayed_log = Box::new( + move |logger: &Logger, + target_hostname_opt: Option, + stream_key: StreamKey, + retries_left: usize, + message: String| { + warning!( + logger, + "No route found for hostname: {:?} - stream key {} - retries left: {} - AddRouteResultMessage Error: {}", + target_hostname_opt, + stream_key, + retries_left, + message + ); + }, + ); + } + } + ( + dns_failure_retry + .unsuccessful_request + .target_hostname + .clone(), + msg.stream_key, + dns_failure_retry.retries_left, + message, + ) + }; + delayed_log( + &self.logger, + target_hostname_opt, + stream_key, + retries_left, + message, + ); + } + fn handle_dns_resolve_failure(&mut self, msg: &ExpiredCoresPackage) { let response = &msg.payload; @@ -1259,7 +1286,11 @@ impl IBCDHelper for IBCDHelperReal { if stream_info.dns_failure_retry_opt.is_none() { let dns_failure_retry = DNSFailureRetry { unsuccessful_request: payload.clone(), - retries_left: if is_decentralized { 3 } else { 0 }, + retries_left: if is_decentralized { + DNS_FAILURE_RETRIES + } else { + 0 + }, }; stream_info.dns_failure_retry_opt = Some(dns_failure_retry); stream_info.protocol_opt = Some(payload.protocol); @@ -3352,10 +3383,12 @@ mod tests { } #[test] - fn route_result_message_handler_logs_error_when_no_dns_retries_exist() { + #[should_panic( + expected = "AddRouteResultMessage Handler: dns_failure_retry_opt is None for stream key" + )] + fn route_result_message_handler_panics_when_no_dns_retries_exist() { init_test_logging(); - let system = - System::new("route_result_message_handler_logs_error_when_no_dns_retries_exist"); + let system = System::new("route_result_message_handler_panics_when_no_dns_retries_exist"); let mut subject = ProxyServer::new( main_cryptde(), alias_cryptde(), From d6432d1f7986cc399365a3318f50e389be7ac4bb Mon Sep 17 00:00:00 2001 From: Dan Wiebe Date: Thu, 9 Oct 2025 00:46:00 -0400 Subject: [PATCH 19/21] Tests passing except one in proxy_client --- node/src/dispatcher.rs | 16 +- node/src/hopper/consuming_service.rs | 4 +- node/src/hopper/mod.rs | 4 +- node/src/hopper/routing_service.rs | 56 +- node/src/neighborhood/mod.rs | 122 +-- node/src/proxy_client/mod.rs | 12 +- node/src/proxy_client/stream_establisher.rs | 2 +- node/src/proxy_client/stream_handler_pool.rs | 59 +- .../client_request_payload_factory.rs | 170 +++-- node/src/proxy_server/http_protocol_pack.rs | 4 +- node/src/proxy_server/mod.rs | 717 +++++++++--------- node/src/proxy_server/protocol_pack.rs | 20 +- .../proxy_server/server_impersonator_http.rs | 24 +- .../proxy_server/server_impersonator_tls.rs | 4 +- node/src/proxy_server/tls_protocol_pack.rs | 4 +- node/src/stream_handler_pool.rs | 14 +- node/src/stream_reader.rs | 20 +- node/src/sub_lib/dispatcher.rs | 12 +- node/src/sub_lib/host.rs | 39 + .../migrations/client_request_payload.rs | 12 +- node/src/sub_lib/mod.rs | 1 + node/src/sub_lib/neighborhood.rs | 13 +- node/src/sub_lib/proxy_server.rs | 2 +- node/src/test_utils/mod.rs | 27 +- 24 files changed, 722 insertions(+), 636 deletions(-) create mode 100644 node/src/sub_lib/host.rs diff --git a/node/src/dispatcher.rs b/node/src/dispatcher.rs index 067ddf22a3..3e1cb81162 100644 --- a/node/src/dispatcher.rs +++ b/node/src/dispatcher.rs @@ -261,12 +261,12 @@ mod tests { let recording_arc = proxy_server.get_recording(); let awaiter = proxy_server.get_awaiter(); let client_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); - let reception_port = Some(8080); + let reception_port_opt = Some(8080); let data: Vec = vec![9, 10, 11]; let ibcd_in = InboundClientData { timestamp: SystemTime::now(), client_addr, - reception_port, + reception_port_opt, sequence_number: Some(0), last_data: false, is_clandestine: false, @@ -300,12 +300,12 @@ mod tests { let subject_addr = subject.start(); let (hopper, hopper_awaiter, hopper_recording_arc) = make_recorder(); let client_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); - let reception_port = Some(8080); + let reception_port_opt = Some(8080); let data: Vec = vec![9, 10, 11]; let ibcd_in = InboundClientData { timestamp: SystemTime::now(), client_addr, - reception_port, + reception_port_opt, last_data: false, is_clandestine: true, sequence_number: None, @@ -340,12 +340,12 @@ mod tests { let subject_addr = subject.start(); let subject_ibcd = subject_addr.recipient::(); let client_addr = SocketAddr::from_str("1.2.3.4:8765").unwrap(); - let reception_port = Some(1234); + let reception_port_opt = Some(1234); let data: Vec = vec![9, 10, 11]; let ibcd_in = InboundClientData { timestamp: SystemTime::now(), client_addr, - reception_port, + reception_port_opt, last_data: false, is_clandestine: false, sequence_number: Some(0), @@ -366,12 +366,12 @@ mod tests { let subject_addr = subject.start(); let subject_ibcd = subject_addr.recipient::(); let client_addr = SocketAddr::from_str("1.2.3.4:8765").unwrap(); - let reception_port = Some(1234); + let reception_port_opt = Some(1234); let data: Vec = vec![9, 10, 11]; let ibcd_in = InboundClientData { timestamp: SystemTime::now(), client_addr, - reception_port, + reception_port_opt, last_data: false, is_clandestine: true, sequence_number: None, diff --git a/node/src/hopper/consuming_service.rs b/node/src/hopper/consuming_service.rs index 6c81d4256c..edad7b2684 100644 --- a/node/src/hopper/consuming_service.rs +++ b/node/src/hopper/consuming_service.rs @@ -96,7 +96,7 @@ impl ConsumingService { let ibcd = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 0), - reception_port: None, + reception_port_opt: None, last_data: false, is_clandestine: true, sequence_number: None, @@ -304,7 +304,7 @@ mod tests { InboundClientData { timestamp: record.timestamp, client_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 0), - reception_port: None, + reception_port_opt: None, last_data: false, is_clandestine: true, sequence_number: None, diff --git a/node/src/hopper/mod.rs b/node/src/hopper/mod.rs index ef854be518..8e87882695 100644 --- a/node/src/hopper/mod.rs +++ b/node/src/hopper/mod.rs @@ -173,7 +173,7 @@ mod tests { let main_cryptde = main_cryptde(); let alias_cryptde = alias_cryptde(); let client_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); - let route = route_to_proxy_client(&main_cryptde.public_key(), main_cryptde); + let route = route_to_proxy_client(&main_cryptde.public_key(), main_cryptde, false); let stream_key = StreamKey::make_meaningless_stream_key(); let serialized_payload = serde_cbor::ser::to_vec(&make_meaningless_message_type(stream_key)).unwrap(); @@ -193,7 +193,7 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr, - reception_port: None, + reception_port_opt: None, last_data: false, is_clandestine: false, sequence_number: None, diff --git a/node/src/hopper/routing_service.rs b/node/src/hopper/routing_service.rs index 2be37e1071..abea6caf50 100644 --- a/node/src/hopper/routing_service.rs +++ b/node/src/hopper/routing_service.rs @@ -186,7 +186,7 @@ impl RoutingService { let inbound_client_data = InboundClientData { timestamp: ibcd_but_data.timestamp, client_addr: ibcd_but_data.client_addr, - reception_port: ibcd_but_data.reception_port, + reception_port_opt: ibcd_but_data.reception_port_opt, last_data: ibcd_but_data.last_data, is_clandestine: ibcd_but_data.is_clandestine, sequence_number: ibcd_but_data.sequence_number, @@ -536,7 +536,7 @@ mod tests { #[test] fn dns_resolution_failures_are_reported_to_the_proxy_server() { let cryptdes = make_cryptde_pair(); - let route = route_to_proxy_server(&cryptdes.main.public_key(), cryptdes.main); + let route = route_to_proxy_server(&cryptdes.main.public_key(), cryptdes.main, false); let stream_key = StreamKey::make_meaningless_stream_key(); let dns_resolve_failure = DnsResolveFailure_0v1::new(stream_key); let lcp = LiveCoresPackage::new( @@ -555,7 +555,7 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port: None, + reception_port_opt: None, sequence_number: None, last_data: false, is_clandestine: false, @@ -594,7 +594,7 @@ mod tests { fn logs_and_ignores_message_that_cannot_be_deserialized() { init_test_logging(); let cryptdes = make_cryptde_pair(); - let route = route_from_proxy_client(&cryptdes.main.public_key(), cryptdes.main); + let route = route_from_proxy_client(&cryptdes.main.public_key(), cryptdes.main, false); let lcp = LiveCoresPackage::new( route, encodex(cryptdes.main, &cryptdes.main.public_key(), &[42u8]).unwrap(), @@ -603,7 +603,7 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port: None, + reception_port_opt: None, sequence_number: None, last_data: false, is_clandestine: false, @@ -641,7 +641,7 @@ mod tests { (pair.main, pair.alias) }; let rogue_cryptde = CryptDEReal::new(TEST_DEFAULT_CHAIN); - let route = route_from_proxy_client(main_cryptde.public_key(), main_cryptde); + let route = route_from_proxy_client(main_cryptde.public_key(), main_cryptde, false); let lcp = LiveCoresPackage::new( route, encodex(&rogue_cryptde, rogue_cryptde.public_key(), &[42u8]).unwrap(), @@ -650,7 +650,7 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port: None, + reception_port_opt: None, sequence_number: None, last_data: false, is_clandestine: false, @@ -687,7 +687,7 @@ mod tests { init_test_logging(); let main_cryptde = main_cryptde(); let alias_cryptde = alias_cryptde(); - let route = route_from_proxy_client(&main_cryptde.public_key(), main_cryptde); + let route = route_from_proxy_client(&main_cryptde.public_key(), main_cryptde, false); let payload = GossipBuilder::empty(); let lcp = LiveCoresPackage::new( route, @@ -702,7 +702,7 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port: None, + reception_port_opt: None, sequence_number: None, last_data: false, is_clandestine: false, @@ -737,7 +737,7 @@ mod tests { let main_cryptde = main_cryptde(); let alias_cryptde = alias_cryptde(); let (component, _, component_recording_arc) = make_recorder(); - let route = route_to_proxy_client(&main_cryptde.public_key(), main_cryptde); + let route = route_to_proxy_client(&main_cryptde.public_key(), main_cryptde, false); let payload = make_request_payload(0, main_cryptde); let lcp = LiveCoresPackage::new( route, @@ -756,7 +756,7 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port: None, + reception_port_opt: None, sequence_number: None, last_data: true, is_clandestine: false, @@ -811,7 +811,7 @@ mod tests { BAN_CACHE.clear(); let main_cryptde = main_cryptde(); let alias_cryptde = alias_cryptde(); - let route = route_to_proxy_client(&main_cryptde.public_key(), main_cryptde); + let route = route_to_proxy_client(&main_cryptde.public_key(), main_cryptde, false); let payload = make_request_payload(0, main_cryptde); let lcp = LiveCoresPackage::new( route, @@ -829,7 +829,7 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port: None, + reception_port_opt: None, sequence_number: None, last_data: true, is_clandestine: false, @@ -872,7 +872,7 @@ mod tests { let main_cryptde = main_cryptde(); let alias_cryptde = alias_cryptde(); let (proxy_server, _, proxy_server_recording_arc) = make_recorder(); - let route = route_to_proxy_server(&main_cryptde.public_key(), main_cryptde); + let route = route_to_proxy_server(&main_cryptde.public_key(), main_cryptde, false); let payload = make_response_payload(0); let lcp = LiveCoresPackage::new( route, @@ -888,7 +888,7 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.3.2.4:5678").unwrap(), - reception_port: None, + reception_port_opt: None, last_data: false, is_clandestine: true, sequence_number: None, @@ -969,7 +969,7 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.3.2.4:5678").unwrap(), - reception_port: None, + reception_port_opt: None, last_data: false, is_clandestine: true, sequence_number: None, @@ -1045,7 +1045,7 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.3.2.4:5678").unwrap(), - reception_port: None, + reception_port_opt: None, last_data: false, is_clandestine: true, sequence_number: None, @@ -1125,7 +1125,7 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port: None, + reception_port_opt: None, last_data: true, is_clandestine: true, sequence_number: None, @@ -1221,7 +1221,7 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port: None, + reception_port_opt: None, last_data: true, is_clandestine: true, sequence_number: None, @@ -1267,7 +1267,7 @@ mod tests { InboundClientData { timestamp: record.timestamp, client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port: None, + reception_port_opt: None, last_data: true, is_clandestine: true, sequence_number: None, @@ -1307,7 +1307,7 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port: None, + reception_port_opt: None, last_data: true, is_clandestine: true, sequence_number: None, @@ -1408,7 +1408,7 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port: None, + reception_port_opt: None, last_data: true, is_clandestine: true, sequence_number: None, @@ -1592,7 +1592,7 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port: None, + reception_port_opt: None, last_data: true, is_clandestine: true, sequence_number: None, @@ -1666,7 +1666,7 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port: None, + reception_port_opt: None, last_data: true, is_clandestine: true, sequence_number: None, @@ -1713,7 +1713,7 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port: None, + reception_port_opt: None, last_data: true, is_clandestine: true, sequence_number: None, @@ -1771,7 +1771,7 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port: None, + reception_port_opt: None, last_data: true, is_clandestine: true, sequence_number: None, @@ -1841,7 +1841,7 @@ mod tests { let ibcd = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port: None, + reception_port_opt: None, last_data: true, is_clandestine: true, sequence_number: None, @@ -1905,7 +1905,7 @@ mod tests { &ClientRequestPayload_0v1 { stream_key: StreamKey::make_meaningless_stream_key(), sequenced_packet: SequencedPacket::new(vec![1, 2, 3, 4], 1234, false), - target_hostname: Some("hostname".to_string()), + target_hostname: "hostname".to_string(), target_port: 1234, protocol: ProxyProtocol::TLS, originator_public_key: PublicKey::new(b"1234"), diff --git a/node/src/neighborhood/mod.rs b/node/src/neighborhood/mod.rs index af6dbccacf..97b93ff951 100644 --- a/node/src/neighborhood/mod.rs +++ b/node/src/neighborhood/mod.rs @@ -81,6 +81,7 @@ use std::fmt::Debug; use std::net::{IpAddr, SocketAddr}; use std::path::PathBuf; use std::string::ToString; +use crate::sub_lib::host::Host; pub const CRASH_KEY: &str = "NEIGHBORHOOD"; pub const DEFAULT_MIN_HOPS: Hops = Hops::ThreeHops; @@ -495,9 +496,9 @@ impl Neighborhood { } fn handle_route_query_message(&mut self, msg: RouteQueryMessage) -> Option { - let debug_msg_opt = self.logger.debug_enabled().then(|| format!("{:?}", msg)); + let debug_msg_opt = self.logger.debug_enabled().then(|| format!("{}", msg.host)); let route_result = if self.mode == NeighborhoodModeLight::ZeroHop { - Ok(self.zero_hop_route_response(msg.hostname_opt)) + Ok(self.zero_hop_route_response(msg.host)) } else { self.make_round_trip_route(msg) }; @@ -881,7 +882,7 @@ impl Neighborhood { target_component: Component::ProxyClient, return_component_opt: Some(Component::ProxyServer), payload_size: 10000, - hostname_opt: None, + host: Host::new("booga.com", 1234), }; if self.handle_route_query_message(msg).is_some() { debug!( @@ -977,7 +978,7 @@ impl Neighborhood { .expect("route creation error") } - fn zero_hop_route_response(&mut self, hostname_opt: Option) -> RouteQueryResponse { + fn zero_hop_route_response(&mut self, host: Host) -> RouteQueryResponse { let route = Route::round_trip( RouteSegment::new( vec![self.cryptde.public_key(), self.cryptde.public_key()], @@ -998,7 +999,7 @@ impl Neighborhood { vec![ExpectedService::Nothing, ExpectedService::Nothing], vec![ExpectedService::Nothing, ExpectedService::Nothing], ), - hostname_opt, + host, } } @@ -1006,7 +1007,7 @@ impl Neighborhood { &mut self, request_msg: RouteQueryMessage, ) -> Result { - let hostname_opt = request_msg.hostname_opt.as_deref(); + let host = request_msg.host; let over = self.make_route_segment( self.cryptde.public_key(), request_msg.target_key_opt.as_ref(), @@ -1014,7 +1015,7 @@ impl Neighborhood { request_msg.target_component, request_msg.payload_size, RouteDirection::Over, - hostname_opt, + &host.name, )?; debug!(self.logger, "Route over: {:?}", over); // Estimate for routing-undesirability calculations. @@ -1031,17 +1032,17 @@ impl Neighborhood { .expect("No return component"), anticipated_response_payload_len, RouteDirection::Back, - hostname_opt, + &host.name, )?; debug!(self.logger, "Route back: {:?}", back); - self.compose_route_query_response(over, back, request_msg.hostname_opt) + self.compose_route_query_response(over, back, host) } fn compose_route_query_response( &mut self, over: RouteSegment, back: RouteSegment, - hostname_opt: Option, + host: Host, ) -> Result { let segments = vec![&over, &back]; @@ -1077,7 +1078,7 @@ impl Neighborhood { expected_request_services, expected_response_services, ), - hostname_opt, + host, }) } @@ -1090,7 +1091,7 @@ impl Neighborhood { target_component: Component, payload_size: usize, direction: RouteDirection, - hostname_opt: Option<&str>, + hostname: &str, ) -> Result { let route_opt = self.find_best_route_segment( origin, @@ -1098,7 +1099,7 @@ impl Neighborhood { minimum_hop_count, payload_size, direction, - hostname_opt, + hostname, ); match route_opt { None => { @@ -1268,11 +1269,11 @@ impl Neighborhood { UndesirabilityType::Relay => { node_record.inner.rate_pack.routing_charge(payload_size) as i64 } - UndesirabilityType::ExitRequest(None) => { + UndesirabilityType::ExitRequest("booga.com") => { node_record.inner.rate_pack.exit_charge(payload_size) as i64 + node_record.metadata.country_undesirability as i64 } - UndesirabilityType::ExitRequest(Some(hostname)) => { + UndesirabilityType::ExitRequest(hostname) => { let exit_undesirability = node_record.inner.rate_pack.exit_charge(payload_size) as i64; let country_undesirability = node_record.metadata.country_undesirability as i64; @@ -1336,7 +1337,7 @@ impl Neighborhood { PAYLOAD_ZERO_SIZE, RouteDirection::Over, &mut minimum_undesirability, - None, + "booga.com", true, research_exits, ); @@ -1358,7 +1359,7 @@ impl Neighborhood { minimum_hops: usize, payload_size: usize, direction: RouteDirection, - hostname_opt: Option<&str>, + hostname: &str, ) -> Option> { let mut minimum_undesirability = i64::MAX; let initial_undesirability = @@ -1375,7 +1376,7 @@ impl Neighborhood { payload_size, direction, &mut minimum_undesirability, - hostname_opt, + hostname, false, &mut vec![], ) @@ -1399,7 +1400,7 @@ impl Neighborhood { payload_size: usize, direction: RouteDirection, minimum_undesirability: &mut i64, - hostname_opt: Option<&str>, + hostname: &str, research_neighborhood: bool, research_exits: &mut Vec<&'a PublicKey>, ) -> Vec> { @@ -1445,7 +1446,7 @@ impl Neighborhood { payload_size, direction, minimum_undesirability, - hostname_opt, + hostname, research_neighborhood, research_exits, previous_node, @@ -1467,7 +1468,7 @@ impl Neighborhood { payload_size, direction, minimum_undesirability, - hostname_opt, + hostname, research_neighborhood, research_exits, previous_node, @@ -1485,7 +1486,7 @@ impl Neighborhood { payload_size: usize, direction: RouteDirection, minimum_undesirability: &mut i64, - hostname_opt: Option<&str>, + hostname: &str, research_neighborhood: bool, exits_research: &mut Vec<&'a PublicKey>, previous_node: &NodeRecord, @@ -1516,7 +1517,7 @@ impl Neighborhood { new_hops_remaining, payload_size as u64, direction, - hostname_opt, + hostname, ); self.routing_engine( @@ -1527,7 +1528,7 @@ impl Neighborhood { payload_size, direction, minimum_undesirability, - hostname_opt, + hostname, research_neighborhood, exits_research, ) @@ -1584,11 +1585,11 @@ impl Neighborhood { hops_remaining: usize, payload_size: u64, direction: RouteDirection, - hostname_opt: Option<&str>, + hostname: &str, ) -> i64 { let undesirability_type = match (direction, target_opt) { (RouteDirection::Over, None) if hops_remaining == 0 => { - UndesirabilityType::ExitRequest(hostname_opt) + UndesirabilityType::ExitRequest(hostname) } (RouteDirection::Over, _) => UndesirabilityType::Relay, // The exit-and-relay undesirability is initial_undesirability @@ -2150,7 +2151,7 @@ impl UserExitPreferences { #[derive(PartialEq, Eq, Debug)] enum UndesirabilityType<'hostname> { Relay, - ExitRequest(Option<&'hostname str>), + ExitRequest(&'hostname str), ExitAndRouteResponse, } @@ -2252,6 +2253,7 @@ mod tests { use crate::sub_lib::neighborhood::ExpectedServices::RoundTrip; use crate::test_utils::unshared_test_utils::notify_handlers::NotifyLaterHandleMock; use masq_lib::test_utils::logging::{init_test_logging, TestLogHandler}; + use crate::sub_lib::host::Host; impl Neighborhood { fn get_node_country_undesirability(&self, pubkey: &PublicKey) -> u32 { @@ -3292,7 +3294,7 @@ mod tests { let addr: Addr = subject.start(); let sub: Recipient = addr.recipient::(); - let future = sub.send(RouteQueryMessage::data_indefinite_route_request(None, 400)); + let future = sub.send(RouteQueryMessage::data_indefinite_route_request(Host::new("booga.com", 1234), 400)); System::current().stop_with_code(0); system.run(); @@ -3308,7 +3310,7 @@ mod tests { let addr: Addr = subject.start(); let sub: Recipient = addr.recipient::(); - let future = sub.send(RouteQueryMessage::data_indefinite_route_request(None, 430)); + let future = sub.send(RouteQueryMessage::data_indefinite_route_request(Host::new("booga.com", 1234), 430)); System::current().stop_with_code(0); system.run(); @@ -3349,7 +3351,7 @@ mod tests { let addr: Addr = subject.start(); let sub: Recipient = addr.recipient::(); let msg = - RouteQueryMessage::data_indefinite_route_request(Some("booga.com".to_string()), 54000); + RouteQueryMessage::data_indefinite_route_request(Host::new("booga.com", 1234), 54000); let future = sub.send(msg); @@ -3395,7 +3397,7 @@ mod tests { ExpectedService::Nothing, ], ), - hostname_opt: Some("booga.com".to_string()), + host: Host::new("booga.com", 1234), }; assert_eq!(expected_response, result); } @@ -3408,7 +3410,7 @@ mod tests { subject.min_hops = Hops::TwoHops; let addr: Addr = subject.start(); let sub: Recipient = addr.recipient::(); - let msg = RouteQueryMessage::data_indefinite_route_request(None, 20000); + let msg = RouteQueryMessage::data_indefinite_route_request(Host::new("booga.com", 1234), 20000); let future = sub.send(msg); @@ -3428,7 +3430,7 @@ mod tests { let sub: Recipient = addr.recipient::(); let future = sub.send(RouteQueryMessage::data_indefinite_route_request( - Some("google.com".to_string()), + Host::new("google.com", 1234), 12345, )); @@ -3454,7 +3456,7 @@ mod tests { vec![ExpectedService::Nothing, ExpectedService::Nothing], vec![ExpectedService::Nothing, ExpectedService::Nothing], ), - hostname_opt: Some("google.com".to_string()), + host: Host::new("google.com", 1234), }; assert_eq!(result, expected_response); } @@ -3504,7 +3506,7 @@ mod tests { let addr: Addr = subject.start(); let sub: Recipient = addr.recipient::(); - let data_route = sub.send(RouteQueryMessage::data_indefinite_route_request(None, 5000)); + let data_route = sub.send(RouteQueryMessage::data_indefinite_route_request(Host::new("booga.com", 1234), 5000)); System::current().stop_with_code(0); system.run(); @@ -3540,7 +3542,7 @@ mod tests { ExpectedService::Nothing, ], ), - hostname_opt: None, + host: Host::new("booga.com", 1234), }; assert_eq!(result, expected_response); } @@ -3552,7 +3554,7 @@ mod tests { let result: Result = subject.compose_route_query_response( RouteSegment::new(vec![], Component::Neighborhood), RouteSegment::new(vec![], Component::Neighborhood), - None, + Host::new("booga.com", 1234), ); assert!(result.is_err()); let error_expectation: String = result.expect_err("Expected an Err but got:"); @@ -4430,7 +4432,7 @@ mod tests { let result: Result = subject.compose_route_query_response( RouteSegment::new(vec![], Component::ProxyClient), RouteSegment::new(vec![], Component::ProxyServer), - None, + Host::new("booga.com", 1234), ); assert!(result.is_err()); let error_expectation: String = result.expect_err("Expected an Err but got:"); @@ -4447,7 +4449,7 @@ mod tests { let result: Result = subject.compose_route_query_response( RouteSegment::new(vec![&PublicKey::new(&[3, 3, 8])], Component::ProxyClient), RouteSegment::new(vec![&PublicKey::new(&[8, 3, 3])], Component::ProxyServer), - None, + Host::new("booga.com", 1234), ); assert!(result.is_err()); let error_expectation: String = result.expect_err("Expected an Err but got:"); @@ -4576,34 +4578,34 @@ mod tests { // At least two hops from p to anywhere standard let route_opt = - subject.find_best_route_segment(p, None, 2, 10000, RouteDirection::Over, None); + subject.find_best_route_segment(p, None, 2, 10000, RouteDirection::Over, "booga.com"); assert_eq!(route_opt.unwrap(), vec![p, s, t]); // no [p, r, s] or [p, s, r] because s and r are both neighbors of p and can't exit for it // At least two hops over from p to t let route_opt = - subject.find_best_route_segment(p, Some(t), 2, 10000, RouteDirection::Over, None); + subject.find_best_route_segment(p, Some(t), 2, 10000, RouteDirection::Over, "booga.com"); assert_eq!(route_opt.unwrap(), vec![p, s, t]); // At least two hops over from t to p let route_opt = - subject.find_best_route_segment(t, Some(p), 2, 10000, RouteDirection::Over, None); + subject.find_best_route_segment(t, Some(p), 2, 10000, RouteDirection::Over, "booga.com"); assert_eq!(route_opt, None); // p is consume-only; can't be an exit Node. // At least two hops back from t to p let route_opt = - subject.find_best_route_segment(t, Some(p), 2, 10000, RouteDirection::Back, None); + subject.find_best_route_segment(t, Some(p), 2, 10000, RouteDirection::Back, "booga.com"); assert_eq!(route_opt.unwrap(), vec![t, s, p]); // p is consume-only, but it's the originating Node, so including it is okay // At least two hops from p to Q - impossible let route_opt = - subject.find_best_route_segment(p, Some(q), 2, 10000, RouteDirection::Over, None); + subject.find_best_route_segment(p, Some(q), 2, 10000, RouteDirection::Over, "booga.com"); assert_eq!(route_opt, None); } @@ -4648,7 +4650,7 @@ mod tests { 3, 10000, RouteDirection::Back, - None, + "booga.com", ) .unwrap(); @@ -4723,7 +4725,7 @@ mod tests { 3, 10000, RouteDirection::Over, - None, + "booga.com", ); let after = Instant::now(); @@ -4775,7 +4777,7 @@ mod tests { subject.handle_exit_location_message(message, 0, 0); let route_cz = - subject.find_best_route_segment(root_key, None, 2, 10000, RouteDirection::Over, None); + subject.find_best_route_segment(root_key, None, 2, 10000, RouteDirection::Over, "booga.com"); assert_eq!(route_cz, None); } @@ -4840,7 +4842,7 @@ mod tests { subject_min_hops, 10000, RouteDirection::Over, - None, + "booga.com", ); let exit_node = cdb.node_by_key(&route_au.as_ref().unwrap().last().unwrap()); @@ -4896,7 +4898,7 @@ mod tests { subject.handle_exit_location_message(message, 0, 0); let route_fr = - subject.find_best_route_segment(root_key, None, 2, 10000, RouteDirection::Over, None); + subject.find_best_route_segment(root_key, None, 2, 10000, RouteDirection::Over, "booga.com"); let exit_node = cdb.node_by_key(&route_fr.as_ref().unwrap().last().unwrap()); assert_eq!( @@ -4919,7 +4921,7 @@ mod tests { // At least two hops from P to anywhere standard let route_opt = - subject.find_best_route_segment(p, None, 2, 10000, RouteDirection::Over, None); + subject.find_best_route_segment(p, None, 2, 10000, RouteDirection::Over, "booga.com"); assert_eq!(route_opt, None); } @@ -4936,7 +4938,7 @@ mod tests { 5, // Lots of hops to go yet 1_000, RouteDirection::Over, - Some("hostname.com"), + "hostname.com", ); let rate_pack = node_record.rate_pack(); @@ -4960,7 +4962,7 @@ mod tests { 0, // Last hop 1_000, RouteDirection::Over, - Some("hostname.com"), + "hostname.com", ); let rate_pack = node_record.rate_pack(); @@ -4988,7 +4990,7 @@ mod tests { 0, // Last hop 1_000, RouteDirection::Over, - Some("hostname.com"), + "hostname.com", ); let rate_pack = node_record.rate_pack(); @@ -5061,7 +5063,7 @@ mod tests { 5, // Plenty of hops remaining: not there yet 1_000, RouteDirection::Back, - None, + "booga.com", ); let rate_pack = node_record.rate_pack(); @@ -6518,7 +6520,7 @@ mod tests { target_component: Component::ProxyClient, return_component_opt: None, payload_size: 10000, - hostname_opt: None, + host: Host::new("booga.com", 1234), }; let unsuccessful_three_hop_route = addr.send(three_hop_route_request); let asserted_node_record = a.clone(); @@ -6884,7 +6886,7 @@ mod tests { target_component: Component::ProxyClient, return_component_opt: Some(Component::ProxyServer), payload_size: 10000, - hostname_opt: None, + host: Host::new("booga.com", 1234), }); assert_eq!( @@ -6929,7 +6931,7 @@ mod tests { target_component: Component::ProxyClient, return_component_opt: Some(Component::ProxyServer), payload_size: 10000, - hostname_opt: Some("host.name".to_string()), + host: Host::new("host.name", 88), }); let next_door_neighbor_cryptde = @@ -7000,7 +7002,7 @@ mod tests { ] ) ); - assert_eq!(response.hostname_opt, Some("host.name".to_string())); + assert_eq!(response.host, Host::new("host.name", 88)); } fn assert_route_query_message(min_hops: Hops) { @@ -7019,7 +7021,7 @@ mod tests { target_component: Component::ProxyClient, return_component_opt: Some(Component::ProxyServer), payload_size: 10000, - hostname_opt: None, + host: Host::new("booga.com", 1234), }); let assert_hops = |cryptdes: Vec, route: &[CryptData]| { @@ -7119,7 +7121,7 @@ mod tests { target_component: Component::ProxyClient, return_component_opt: Some(Component::ProxyServer), payload_size, - hostname_opt: None, + host: Host::new("booga.com", 1234), }) .unwrap(); diff --git a/node/src/proxy_client/mod.rs b/node/src/proxy_client/mod.rs index d05cb505b4..3af7d27d1e 100644 --- a/node/src/proxy_client/mod.rs +++ b/node/src/proxy_client/mod.rs @@ -607,7 +607,7 @@ mod tests { sequence_number: 0, last_data: false, }, - target_hostname: Some(String::from("target.hostname.com")), + target_hostname: String::from("target.hostname.com"), target_port: 1234, protocol: ProxyProtocol::HTTP, originator_public_key: PublicKey::new(&b"originator_public_key"[..]), @@ -616,7 +616,7 @@ mod tests { let package = ExpiredCoresPackage::new( SocketAddr::from_str("1.2.3.4:1234").unwrap(), Some(make_wallet("consuming")), - route_to_proxy_client(&cryptde.public_key(), cryptde), + route_to_proxy_client(&cryptde.public_key(), cryptde, false), request, 0, ); @@ -750,7 +750,7 @@ mod tests { sequence_number: 0, last_data: false, }, - target_hostname: None, + target_hostname: "booga.com".to_string(), target_port: 0, protocol: ProxyProtocol::HTTP, originator_public_key: PublicKey::new(&b"originator"[..]), @@ -810,7 +810,7 @@ mod tests { sequence_number: 0, last_data: false, }, - target_hostname: None, + target_hostname: "booga.com".to_string(), target_port: 0, protocol: ProxyProtocol::HTTP, originator_public_key: PublicKey::new(&b"originator"[..]), @@ -867,7 +867,7 @@ mod tests { sequence_number: 0, last_data: false, }, - target_hostname: None, + target_hostname: "booga.com".to_string(), target_port: 0, protocol: ProxyProtocol::HTTP, originator_public_key: alias_cryptde.public_key().clone(), @@ -1223,7 +1223,7 @@ mod tests { sequence_number: 0, last_data: false, }, - target_hostname: None, + target_hostname: "booga.com".to_string(), target_port: 0, protocol: ProxyProtocol::HTTP, originator_public_key: originator_public_key.clone(), diff --git a/node/src/proxy_client/stream_establisher.rs b/node/src/proxy_client/stream_establisher.rs index bfd7408a5b..772c94e247 100644 --- a/node/src/proxy_client/stream_establisher.rs +++ b/node/src/proxy_client/stream_establisher.rs @@ -196,7 +196,7 @@ mod tests { sequence_number: 0, last_data: false, }, - target_hostname: Some("blah".to_string()), + target_hostname: "blah".to_string(), target_port: 0, protocol: ProxyProtocol::HTTP, originator_public_key: subject.cryptde.public_key().clone(), diff --git a/node/src/proxy_client/stream_handler_pool.rs b/node/src/proxy_client/stream_handler_pool.rs index 5e2047e26a..18d343e417 100644 --- a/node/src/proxy_client/stream_handler_pool.rs +++ b/node/src/proxy_client/stream_handler_pool.rs @@ -282,27 +282,14 @@ impl StreamHandlerPoolReal { "No stream to {:?} exists; resolving host", &payload.target_hostname ); - match payload.target_hostname { - Some(ref target_hostname) => match Self::parse_ip(target_hostname) { - Ok(socket_addr) => Self::handle_ip( - payload.clone(), - socket_addr, - inner_arc, - target_hostname.to_string(), - ), - Err(_) => Self::lookup_dns(inner_arc, target_hostname.to_string(), payload.clone()), - }, - None => { - error!( - logger, - "Cannot open new stream with key {:?}: no hostname supplied", - payload.stream_key - ); - Box::new(err::< - Box + 'static>, - String, - >("No hostname provided".to_string())) - } + match Self::parse_ip(&payload.target_hostname) { + Ok(socket_addr) => Self::handle_ip( + payload.clone(), + socket_addr, + inner_arc, + payload.target_hostname.clone(), + ), + Err(_) => Self::lookup_dns(inner_arc, payload.target_hostname.clone(), payload.clone()), } } @@ -673,7 +660,7 @@ mod tests { let payload = ClientRequestPayload_0v1 { stream_key, sequenced_packet: SequencedPacket::new(b"booga".to_vec(), 0, false), - target_hostname: Some("www.example.com".to_string()), + target_hostname: "www.example.com".to_string(), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: cryptde.public_key().clone(), @@ -706,7 +693,7 @@ mod tests { sequence_number: 0, last_data: false, }, - target_hostname: None, + target_hostname: "booga.com".to_string(), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: PublicKey::new(&b"men's souls"[..]), @@ -774,7 +761,7 @@ mod tests { sequence_number: 0, last_data: false, }, - target_hostname: Some(String::from("that.try")), + target_hostname: String::from("that.try"), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: originator_key, @@ -853,7 +840,7 @@ mod tests { sequence_number: 0, last_data: false, }, - target_hostname: Some(String::from("3.4.5.6:80")), + target_hostname: String::from("3.4.5.6:80"), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: PublicKey::new(&b"men's souls"[..]), @@ -949,7 +936,7 @@ mod tests { sequence_number: 0, last_data: true, }, - target_hostname: Some(String::from("3.4.5.6:80")), + target_hostname: String::from("3.4.5.6:80"), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: PublicKey::new(&b"brutal death"[..]), @@ -1010,7 +997,7 @@ mod tests { sequence_number: 0, last_data: true, }, - target_hostname: Some(String::from("3.4.5.6:80")), + target_hostname: String::from("3.4.5.6:80"), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: PublicKey::new(&b"brutal death"[..]), @@ -1074,7 +1061,7 @@ mod tests { sequence_number: 0, last_data: false, }, - target_hostname: Some(String::from("3.4.5.6")), + target_hostname: String::from("3.4.5.6"), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: PublicKey::new(&b"men's souls"[..]), @@ -1184,7 +1171,7 @@ mod tests { sequence_number: 0, last_data: false, }, - target_hostname: None, + target_hostname: "booga.com".to_string(), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: originator_key, @@ -1255,7 +1242,7 @@ mod tests { sequence_number: 0, last_data: false, }, - target_hostname: Some(String::from("that.try")), + target_hostname: String::from("that.try"), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: PublicKey::new(&b"men's souls"[..]), @@ -1368,7 +1355,7 @@ mod tests { sequence_number: 0, last_data: false, }, - target_hostname: Some(String::from("that.try")), + target_hostname: String::from("that.try"), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: originator_key, @@ -1490,7 +1477,7 @@ mod tests { sequence_number: 0, last_data: false, }, - target_hostname: Some(String::from("blockedwebsite.com")), + target_hostname: String::from("blockedwebsite.com"), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: originator_key, @@ -1587,7 +1574,7 @@ mod tests { let client_request_payload = ClientRequestPayload_0v1 { stream_key, sequenced_packet: sequenced_packet.clone(), - target_hostname: Some(String::from("that.try")), + target_hostname: String::from("that.try"), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: PublicKey::new(&b"men's souls"[..]), @@ -1700,7 +1687,7 @@ mod tests { sequence_number: 0, last_data: true, }, - target_hostname: Some(String::from("that.try")), + target_hostname: String::from("that.try"), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: originator_key, @@ -1762,7 +1749,7 @@ mod tests { let client_request_payload = ClientRequestPayload_0v1 { stream_key: stream_key.clone(), sequenced_packet: sequenced_packet.clone(), - target_hostname: Some(String::from("that.try")), + target_hostname: String::from("that.try"), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: PublicKey::new(&b"men's souls"[..]), @@ -1833,7 +1820,7 @@ mod tests { sequence_number: 0, last_data: false, }, - target_hostname: None, + target_hostname: "booga.com".to_string(), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: PublicKey::new(&b"booga"[..]), diff --git a/node/src/proxy_server/client_request_payload_factory.rs b/node/src/proxy_server/client_request_payload_factory.rs index e146501e20..6f0b38423a 100644 --- a/node/src/proxy_server/client_request_payload_factory.rs +++ b/node/src/proxy_server/client_request_payload_factory.rs @@ -7,12 +7,14 @@ use crate::sub_lib::proxy_server::ClientRequestPayload_0v1; use crate::sub_lib::sequence_buffer::SequencedPacket; use crate::sub_lib::stream_key::StreamKey; use masq_lib::logger::Logger; +use crate::sub_lib::host::Host; pub trait ClientRequestPayloadFactory { fn make( &self, ibcd: &InboundClientData, stream_key: StreamKey, + host_opt: Option, cryptde: &dyn CryptDE, logger: &Logger, ) -> Option; @@ -26,10 +28,33 @@ impl ClientRequestPayloadFactory for ClientRequestPayloadFactoryReal { &self, ibcd: &InboundClientData, stream_key: StreamKey, + host_opt: Option, cryptde: &dyn CryptDE, logger: &Logger, ) -> Option { let protocol_pack = from_ibcd(ibcd).map_err(|e| error!(logger, "{}", e)).ok()?; + let host_from_ibcd = Box::new (|| { + let data = PlainData::new(&ibcd.data); + match protocol_pack.find_host(&data) { + Some(host) => Ok(host), + // So far we've only looked in the client packet; but this message will evaporate + // unless there's no host information in host_opt (from ProxyServer's StreamInfo) either. + None => Err(format!( + "No hostname information found in either client packet or ProxyServer for protocol {:?}", + protocol_pack.proxy_protocol() + )), + } + }); + let target_host: Host = match host_from_ibcd() { + Ok(host) => host, + Err(e) => match host_opt { + Some(host) => host, + None => { + error!(logger, "{}", e); + return None; + } + } + }; let sequence_number = match ibcd.sequence_number { Some(sequence_number) => sequence_number, None => { @@ -41,12 +66,6 @@ impl ClientRequestPayloadFactory for ClientRequestPayloadFactoryReal { return None; } }; - let data = PlainData::new(&ibcd.data); - let target_host = protocol_pack.find_host(&data); - let (target_hostname_opt, target_port) = match target_host { - Some(host) => (Some(host.name), host.port), - None => (None, protocol_pack.standard_port()), - }; Some(ClientRequestPayload_0v1 { stream_key, sequenced_packet: SequencedPacket { @@ -54,8 +73,8 @@ impl ClientRequestPayloadFactory for ClientRequestPayloadFactoryReal { sequence_number, last_data: ibcd.last_data, }, - target_hostname: target_hostname_opt, - target_port, + target_hostname: target_host.name, + target_port: target_host.port, protocol: protocol_pack.proxy_protocol(), originator_public_key: cryptde.public_key().clone(), }) @@ -80,13 +99,85 @@ mod tests { use std::str::FromStr; use std::time::SystemTime; + #[test] + fn ibcd_hostname_overrides_supplied_hostname() { + let data = PlainData::new(&b"GET http://borkoed.com:1234/fleebs.html HTTP/1.1\r\n\r\n"[..]); + let ibcd = InboundClientData { + timestamp: SystemTime::now(), + client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), + reception_port_opt: Some(HTTP_PORT), + sequence_number: Some(1), + last_data: false, + is_clandestine: false, + data: data.clone().into(), + }; + let cryptde = main_cryptde(); + let stream_key = StreamKey::make_meaningless_stream_key(); + let logger = Logger::new("ibcd_hostname_overrides_supplied_hostname"); + let subject = Box::new(ClientRequestPayloadFactoryReal::new()); + + let result = subject.make(&ibcd, stream_key, Some(Host::new("ignored.com", 4321)), cryptde, &logger).unwrap(); + + assert_eq!(result.target_hostname, String::from("borkoed.com")); + assert_eq!(result.target_port, 1234); + } + + #[test] + fn uses_supplied_host_if_ibcd_does_not_have_one() { + let test_name = "uses_supplied_hostname_if_ibcd_does_not_have_one"; + let data = PlainData::new(&[0x01, 0x02, 0x03]); // No host can be extracted here + let ibcd = InboundClientData { + timestamp: SystemTime::now(), + client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), + reception_port_opt: Some(HTTP_PORT), + sequence_number: Some(1), + last_data: false, + is_clandestine: false, + data: data.into(), + }; + let cryptde = main_cryptde(); + let stream_key = StreamKey::make_meaningful_stream_key(test_name); + let logger = Logger::new(test_name); + let subject = Box::new(ClientRequestPayloadFactoryReal::new()); + let supplied_host = Host::new("supplied.com", 4321); + + let result = subject.make(&ibcd, stream_key, Some(supplied_host.clone()), cryptde, &logger).unwrap(); + + assert_eq!(result.target_hostname, supplied_host.name); + } + + #[test] + fn logs_error_and_returns_none_if_no_ibcd_host_and_no_supplied_host() { + init_test_logging(); + let test_name = "logs_error_and_returns_none_if_no_ibcd_hostname_and_no_supplied_hostname"; + let data = PlainData::new(&[0x01, 0x02, 0x03]); // no host can be extracted here + let ibcd = InboundClientData { + timestamp: SystemTime::now(), + client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), + reception_port_opt: Some(HTTP_PORT), + sequence_number: Some(1), + last_data: false, + is_clandestine: false, + data: data.into(), + }; + let cryptde = main_cryptde(); + let stream_key = StreamKey::make_meaningful_stream_key(test_name); + let logger = Logger::new(test_name); + let subject = Box::new(ClientRequestPayloadFactoryReal::new()); + + let result = subject.make(&ibcd, stream_key, None, cryptde, &logger); + + assert_eq!(result, None); + TestLogHandler::new().exists_log_containing(&format!("ERROR: {test_name}: No hostname information found in either client packet or ProxyServer for protocol HTTP")); + } + #[test] fn handles_http_with_a_port() { let data = PlainData::new(&b"GET http://borkoed.com:2345/fleebs.html HTTP/1.1\r\n\r\n"[..]); let ibcd = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port: Some(HTTP_PORT), + reception_port_opt: Some(HTTP_PORT), sequence_number: Some(1), last_data: false, is_clandestine: false, @@ -97,7 +188,7 @@ mod tests { let logger = Logger::new("test"); let subject = Box::new(ClientRequestPayloadFactoryReal::new()); - let result = subject.make(&ibcd, stream_key, cryptde, &logger); + let result = subject.make(&ibcd, stream_key, None, cryptde, &logger); assert_eq!( result, @@ -108,7 +199,7 @@ mod tests { sequence_number: 1, last_data: false }, - target_hostname: Some(String::from("borkoed.com")), + target_hostname: String::from("borkoed.com"), target_port: 2345, protocol: ProxyProtocol::HTTP, originator_public_key: cryptde.public_key().clone(), @@ -123,7 +214,7 @@ mod tests { let ibcd = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port: Some(HTTP_PORT), + reception_port_opt: Some(HTTP_PORT), sequence_number: Some(1), last_data: false, is_clandestine: false, @@ -134,7 +225,7 @@ mod tests { let stream_key = StreamKey::make_meaningful_stream_key(test_name); let subject = Box::new(ClientRequestPayloadFactoryReal::new()); - let result = subject.make(&ibcd, stream_key, cryptde, &logger); + let result = subject.make(&ibcd, stream_key, None, cryptde, &logger); assert_eq!( result, @@ -145,7 +236,7 @@ mod tests { sequence_number: 1, last_data: false }, - target_hostname: Some(String::from("borkoed.com")), + target_hostname: String::from("borkoed.com"), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: cryptde.public_key().clone(), @@ -179,7 +270,7 @@ mod tests { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), sequence_number: Some(0), - reception_port: Some(443), + reception_port_opt: Some(443), last_data: false, is_clandestine: false, data: data.clone().into(), @@ -189,7 +280,7 @@ mod tests { let logger = Logger::new("test"); let subject = Box::new(ClientRequestPayloadFactoryReal::new()); - let result = subject.make(&ibcd, stream_key, cryptde, &logger); + let result = subject.make(&ibcd, stream_key, None, cryptde, &logger); assert_eq!( result, @@ -200,7 +291,7 @@ mod tests { sequence_number: 0, last_data: false }, - target_hostname: Some(String::from("server.com")), + target_hostname: String::from("server.com"), target_port: 443, protocol: ProxyProtocol::TLS, originator_public_key: cryptde.public_key().clone(), @@ -210,6 +301,7 @@ mod tests { #[test] fn handles_tls_without_hostname() { + init_test_logging(); let test_name = "handles_tls_without_hostname"; let data = PlainData::new(&[ 0x16, // content_type: Handshake @@ -228,7 +320,7 @@ mod tests { let ibcd = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port: Some(443), + reception_port_opt: Some(443), last_data: true, is_clandestine: false, sequence_number: Some(0), @@ -239,23 +331,10 @@ mod tests { let stream_key = StreamKey::make_meaningful_stream_key(test_name); let subject = Box::new(ClientRequestPayloadFactoryReal::new()); - let result = subject.make(&ibcd, stream_key, cryptde, &logger); + let result = subject.make(&ibcd, stream_key, None, cryptde, &logger); - assert_eq!( - result, - Some(ClientRequestPayload_0v1 { - stream_key, - sequenced_packet: SequencedPacket { - data: data.into(), - sequence_number: 0, - last_data: true - }, - target_hostname: None, - target_port: 443, - protocol: ProxyProtocol::TLS, - originator_public_key: cryptde.public_key().clone(), - }) - ); + assert_eq!(result, None); + TestLogHandler::new().exists_log_containing(&format!("ERROR: {test_name}: No hostname information found in either client packet or ProxyServer for protocol TLS")); } #[test] @@ -266,7 +345,7 @@ mod tests { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), sequence_number: Some(0), - reception_port: None, + reception_port_opt: None, last_data: false, is_clandestine: false, data: vec![0x10, 0x11, 0x12], @@ -276,7 +355,7 @@ mod tests { let stream_key = StreamKey::make_meaningful_stream_key(test_name); let subject = Box::new(ClientRequestPayloadFactoryReal::new()); - let result = subject.make(&ibcd, stream_key, cryptde, &logger); + let result = subject.make(&ibcd, stream_key, None, cryptde, &logger); assert_eq!(result, None); TestLogHandler::new().exists_log_containing( @@ -291,7 +370,7 @@ mod tests { let ibcd = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port: Some(1234), + reception_port_opt: Some(1234), sequence_number: Some(0), last_data: false, is_clandestine: true, @@ -302,7 +381,7 @@ mod tests { let stream_key = StreamKey::make_meaningful_stream_key(test_name); let subject = Box::new(ClientRequestPayloadFactoryReal::new()); - let result = subject.make(&ibcd, stream_key, cryptde, &logger); + let result = subject.make(&ibcd, stream_key, None, cryptde, &logger); assert_eq!(result, None); TestLogHandler::new().exists_log_containing(&format!("ERROR: {test_name}: No protocol associated with origin port 1234 for 3-byte non-clandestine packet: [16, 17, 18]")); @@ -310,13 +389,14 @@ mod tests { #[test] fn use_sequence_from_inbound_client_data_in_client_request_payload() { + let data = PlainData::new(&b"GET http://borkoed.com/fleebs.html HTTP/1.1\r\n\r\n"[..]); let ibcd = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:80").unwrap(), - reception_port: Some(HTTP_PORT), + reception_port_opt: Some(HTTP_PORT), sequence_number: Some(1), last_data: false, - data: vec![0x10, 0x11, 0x12], + data: data.into(), is_clandestine: false, }; let cryptde = main_cryptde(); @@ -327,6 +407,7 @@ mod tests { .make( &ibcd, StreamKey::make_meaningless_stream_key(), + None, cryptde, &logger, ) @@ -339,25 +420,26 @@ mod tests { fn makes_no_payload_if_sequence_number_is_unknown() { init_test_logging(); let test_name = "makes_no_payload_if_sequence_number_is_unknown"; + let data = PlainData::new(&b"GET http://borkoed.com/fleebs.html HTTP/1.1\r\n\r\n"[..]); let ibcd = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:80").unwrap(), - reception_port: Some(HTTP_PORT), + reception_port_opt: Some(HTTP_PORT), last_data: false, is_clandestine: false, sequence_number: None, - data: vec![1, 3, 5, 7], + data: data.into(), }; let cryptde = main_cryptde(); let logger = Logger::new(test_name); let stream_key = StreamKey::make_meaningful_stream_key(test_name); let subject = Box::new(ClientRequestPayloadFactoryReal::new()); - let result = subject.make(&ibcd, stream_key, cryptde, &logger); + let result = subject.make(&ibcd, stream_key, None, cryptde, &logger); assert_eq!(result, None); TestLogHandler::new().exists_log_containing(&format!( - "ERROR: {test_name}: internal error: got IBCD with no sequence number and 4 bytes" + "ERROR: {test_name}: internal error: got IBCD with no sequence number and 47 bytes" )); } } diff --git a/node/src/proxy_server/http_protocol_pack.rs b/node/src/proxy_server/http_protocol_pack.rs index b611f2be30..220ce79ded 100644 --- a/node/src/proxy_server/http_protocol_pack.rs +++ b/node/src/proxy_server/http_protocol_pack.rs @@ -1,5 +1,5 @@ // Copyright (c) 2019, MASQ (https://masq.ai) and/or its affiliates. All rights reserved. -use crate::proxy_server::protocol_pack::{Host, ProtocolPack, ServerImpersonator}; +use crate::proxy_server::protocol_pack::{ProtocolPack, ServerImpersonator}; use crate::proxy_server::server_impersonator_http::ServerImpersonatorHttp; use crate::sub_lib::cryptde::PlainData; use crate::sub_lib::proxy_server::ProxyProtocol; @@ -7,11 +7,13 @@ use lazy_static::lazy_static; use masq_lib::constants::HTTP_PORT; use masq_lib::utils::index_of; use regex::Regex; +use crate::sub_lib::host::Host; lazy_static! { static ref HOST_PATTERN: Regex = Regex::new(r"^(?:https?://)?([^\s/]+)").expect("bad regex"); } +#[derive(Clone, Copy)] pub struct HttpProtocolPack {} impl ProtocolPack for HttpProtocolPack { diff --git a/node/src/proxy_server/mod.rs b/node/src/proxy_server/mod.rs index 6442d77265..69a1810603 100644 --- a/node/src/proxy_server/mod.rs +++ b/node/src/proxy_server/mod.rs @@ -49,12 +49,12 @@ use masq_lib::logger::Logger; use masq_lib::ui_gateway::NodeFromUiMessage; use masq_lib::utils::MutabilityConflictHelper; use regex::Regex; -use std::cell::Cell; use std::collections::HashMap; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}; use std::str::FromStr; use std::time::{Duration, SystemTime}; use tokio::prelude::Future; +use crate::sub_lib::host::Host; pub const CRASH_KEY: &str = "PROXYSERVER"; pub const RETURN_ROUTE_TTL_FIRST_CHANCE: Duration = Duration::from_secs(120); @@ -102,7 +102,6 @@ pub struct ProxyServer { browser_proxy_sequence_offset: bool, inbound_client_data_helper_opt: Option>, stream_key_purge_delay: Duration, - next_return_route_id: Cell, is_running_in_integration_test: bool, } @@ -236,7 +235,6 @@ impl ProxyServer { browser_proxy_sequence_offset: false, inbound_client_data_helper_opt: Some(Box::new(IBCDHelperReal::new())), stream_key_purge_delay: STREAM_KEY_PURGE_DELAY, - next_return_route_id: Cell::new(1), is_running_in_integration_test, } } @@ -316,7 +314,7 @@ impl ProxyServer { &self, client_addr: SocketAddr, proxy_protocol: ProxyProtocol, - hostname_opt: Option, + hostname: String, ) { self.subs .as_ref() @@ -328,7 +326,7 @@ impl ProxyServer { sequence_number: Some(0), // DNS resolution errors always happen on the first request data: from_protocol(proxy_protocol) .server_impersonator() - .dns_resolution_failure_response(hostname_opt), + .dns_resolution_failure_response(hostname), }) .expect("Dispatcher is dead"); } @@ -350,10 +348,10 @@ impl ProxyServer { } fn handle_add_route_result_message(&mut self, msg: AddRouteResultMessage) { - type DelayedLogArgs = Box, StreamKey, usize, String)>; + type DelayedLogArgs = Box; #[allow(unused_assignments)] let mut delayed_log: DelayedLogArgs = Box::new(|_, _, _, _, _| {}); - let (target_hostname_opt, stream_key, retries_left, message) = { + let (target_hostname, stream_key, retries_left, message) = { let mut stream_info = self.stream_info_mut(&msg.stream_key).unwrap_or_else(|| { panic!( "AddRouteResultMessage Handler: stream key: {} not found", @@ -371,14 +369,14 @@ impl ProxyServer { Ok(route_query_response) => { delayed_log = Box::new( move |logger: &Logger, - target_hostname_opt: Option, + target_hostname: String, stream_key: StreamKey, retries_left: usize, _: String| { debug!( logger, "Found a new route for hostname: {:?} - stream key: {} retries left: {}", - target_hostname_opt, + target_hostname, stream_key, retries_left ); @@ -390,14 +388,14 @@ impl ProxyServer { message = e; delayed_log = Box::new( move |logger: &Logger, - target_hostname_opt: Option, + target_hostname: String, stream_key: StreamKey, retries_left: usize, message: String| { warning!( logger, "No route found for hostname: {:?} - stream key {} - retries left: {} - AddRouteResultMessage Error: {}", - target_hostname_opt, + target_hostname, stream_key, retries_left, message @@ -418,7 +416,7 @@ impl ProxyServer { }; delayed_log( &self.logger, - target_hostname_opt, + target_hostname, stream_key, retries_left, message, @@ -488,26 +486,17 @@ impl ProxyServer { match self.keys_and_addrs.a_to_b(&response.stream_key) { Some(client_addr) => { - let hostname_opt = route_query_response.hostname_opt.clone(); - if let Some(ref server_name) = hostname_opt { - self.subs - .as_ref() - .expect("Neighborhood unbound in ProxyServer") - .update_node_record_metadata - .try_send(UpdateNodeRecordMetadataMessage { - public_key: exit_public_key, - metadata_change: NRMetadataChange::AddUnreachableHost { - hostname: server_name.clone(), - }, - }) - .expect("Neighborhood is dead"); - } else { - error!( - self.logger, - "Exit node {exit_public_key} complained of DNS failure, but was given no hostname to resolve." - ); - // TODO: Malefactor ban the exit node because it lied about the DNS failure. - } + self.subs + .as_ref() + .expect("Neighborhood unbound in ProxyServer") + .update_node_record_metadata + .try_send(UpdateNodeRecordMetadataMessage { + public_key: exit_public_key, + metadata_change: NRMetadataChange::AddUnreachableHost { + hostname: route_query_response.host.name.clone(), + }, + }) + .expect("Neighborhood is dead"); self.report_response_services_consumed(response_services, 0, msg.payload_len); if let Some(retry_ref) = &mut stream_info.dns_failure_retry_opt { debug!( @@ -529,7 +518,7 @@ impl ProxyServer { self.send_dns_failure_response_to_the_browser( client_addr, protocol, - hostname_opt, + route_query_response.host.name.clone(), ); } } else { @@ -544,7 +533,7 @@ impl ProxyServer { None => { error!(self.logger, "Discarding DnsResolveFailure message for {} from an unrecognized stream key {:?}", - route_query_response.hostname_opt.clone().unwrap_or_else(|| "".to_string()), + route_query_response.host.name, &response.stream_key ) } @@ -763,7 +752,7 @@ impl ProxyServer { let ibcd = InboundClientData { timestamp: SystemTime::now(), client_addr: msg.peer_addr, - reception_port: Some(nca.reception_port), + reception_port_opt: Some(nca.reception_port), last_data: true, is_clandestine: false, sequence_number: Some(nca.sequence_number), @@ -829,13 +818,16 @@ impl ProxyServer { stream_key: &StreamKey, ) -> Result { let stream_info_opt = self.stream_info.get(stream_key); - let tunnelled_host_opt = match stream_info_opt { - None => None, - Some(info) => info.tunneled_host_opt.clone(), + let (host_opt, tunnelled_host_opt) = match stream_info_opt { + None => (None, None), + Some(info) => match &info.route_opt { + Some(route) => (Some(route.host.clone()), info.tunneled_host_opt.clone()), + None => (None, info.tunneled_host_opt.clone()), + } }; let new_ibcd = match tunnelled_host_opt { Some(_) => InboundClientData { - reception_port: Some(443), + reception_port_opt: Some(443), ..ibcd }, None => ibcd, @@ -843,13 +835,14 @@ impl ProxyServer { match self.client_request_payload_factory.make( &new_ibcd, *stream_key, + host_opt, self.alias_cryptde, &self.logger, ) { None => Err("Couldn't create ClientRequestPayload".to_string()), Some(payload) => match tunnelled_host_opt { Some(hostname) => Ok(ClientRequestPayload_0v1 { - target_hostname: Some(hostname), + target_hostname: hostname, ..payload }), None => Ok(payload), @@ -857,13 +850,6 @@ impl ProxyServer { } } - fn get_next_return_route_id(&self) -> u32 { - let return_route_id = self.next_return_route_id.get(); - self.next_return_route_id - .set(return_route_id.wrapping_add(1)); - return_route_id - } - fn try_transmit_to_hopper( args: TransmitToHopperArgs, route_query_response: RouteQueryResponse, @@ -971,8 +957,11 @@ impl ProxyServer { let payload = args.payload; let payload_size = payload.sequenced_packet.data.len(); let stream_key = payload.stream_key; + // TODO: This return route ID is completely unnecessary, except that unenlightened + // Nodes are expecting it, so we have to put it in. We should make it random garbage + // instead of 0. let route_with_return_route_id = - route.set_return_route_id(args.main_cryptde, args.return_route_id); + route.set_return_route_id(args.main_cryptde, 0); let pkg = IncipientCoresPackage::new( args.main_cryptde, route_with_return_route_id, @@ -1024,7 +1013,7 @@ impl ProxyServer { source_addr: SocketAddr, dispatcher: &Recipient, ) -> String { - let target_hostname = ProxyServer::hostname(&payload); + let target_hostname = payload.target_hostname.clone(); let stream_key = payload.stream_key; ProxyServer::send_route_failure(payload, source_addr, dispatcher); format!( @@ -1040,7 +1029,7 @@ impl ProxyServer { ) { let data = from_protocol(payload.protocol) .server_impersonator() - .route_query_failure_response(&ProxyServer::hostname(&payload)); + .route_query_failure_response(&payload.target_hostname); let msg = TransmitDataMsg { endpoint: Endpoint::Socket(source_addr), last_data: true, @@ -1050,13 +1039,6 @@ impl ProxyServer { dispatcher.try_send(msg).expect("Dispatcher is dead"); } - fn hostname(payload: &ClientRequestPayload_0v1) -> String { - match payload.target_hostname { - Some(ref thn) => thn.clone(), - None => "".to_string(), - } - } - fn get_expected_return_services( &mut self, stream_key: &StreamKey, @@ -1236,12 +1218,12 @@ impl IBCDHelperReal { impl IBCDHelper for IBCDHelperReal { fn handle_normal_client_data( &self, - proxy: &mut ProxyServer, + proxy_server: &mut ProxyServer, msg: InboundClientData, retire_stream_key: bool, ) -> Result<(), String> { let client_addr = msg.client_addr; - if proxy.consuming_wallet_balance.is_none() && proxy.is_decentralized { + if proxy_server.consuming_wallet_balance.is_none() && proxy_server.is_decentralized { let protocol_pack = match from_ibcd(&msg) { Err(e) => return Err(e), Ok(pp) => pp, @@ -1255,22 +1237,20 @@ impl IBCDHelper for IBCDHelperReal { sequence_number: Some(0), data, }; - proxy + proxy_server .out_subs("Dispatcher") .dispatcher .try_send(msg) .expect("Dispatcher is dead"); return Err("Browser request rejected due to missing consuming wallet".to_string()); } - let stream_key = proxy.find_or_generate_stream_key(&msg); + let stream_key = proxy_server.find_or_generate_stream_key(&msg); let timestamp = msg.timestamp; - let payload = match proxy.make_payload(msg, &stream_key) { + let payload = match proxy_server.make_payload(msg, &stream_key) { Ok(payload) => { - if !proxy.is_running_in_integration_test { - if let Some(hostname) = &payload.target_hostname { - if let Err(e) = Hostname::new(hostname).validate_non_loopback_host() { - return Err(format!("Request to wildcard IP detected - {} (Most likely because Blockchain Service URL is not set)", e)); - } + if !proxy_server.is_running_in_integration_test { + if let Err(e) = Hostname::new(&payload.target_hostname).validate_non_loopback_host() { + return Err(format!("Request to wildcard IP detected - {} (Most likely because Blockchain Service URL is not set)", e)); } } payload @@ -1279,8 +1259,8 @@ impl IBCDHelper for IBCDHelperReal { }; { - let is_decentralized = proxy.is_decentralized; - let mut stream_info = proxy + let is_decentralized = proxy_server.is_decentralized; + let mut stream_info = proxy_server .stream_info_mut(&stream_key) .unwrap_or_else(|| panic!("Stream key {} disappeared!", &stream_key)); if stream_info.dns_failure_retry_opt.is_none() { @@ -1297,14 +1277,14 @@ impl IBCDHelper for IBCDHelperReal { } } let args = - TransmitToHopperArgs::new(proxy, payload, client_addr, timestamp, retire_stream_key); + TransmitToHopperArgs::new(proxy_server, payload, client_addr, timestamp, retire_stream_key); let pld = &args.payload; - let stream_info = proxy - .stream_info(&pld.stream_key, &proxy.logger) + let stream_info = proxy_server + .stream_info(&pld.stream_key, &proxy_server.logger) .unwrap_or_else(|| panic!("Stream key {} disappeared!", &pld.stream_key)); if let Some(route_query_response) = &stream_info.route_opt { debug!( - proxy.logger, + proxy_server.logger, "Transmitting down existing stream {}: sequence {}, length {}", pld.stream_key, pld.sequenced_packet.sequence_number, @@ -1313,8 +1293,8 @@ impl IBCDHelper for IBCDHelperReal { let route_query_response = route_query_response.clone(); ProxyServer::try_transmit_to_hopper(args, route_query_response) } else { - let route_source = proxy.out_subs("Neighborhood").route_source.clone(); - let proxy_server_sub = proxy.out_subs("ProxyServer").route_result_sub.clone(); + let route_source = proxy_server.out_subs("Neighborhood").route_source.clone(); + let proxy_server_sub = proxy_server.out_subs("ProxyServer").route_result_sub.clone(); self.request_route_and_transmit(args, route_source, proxy_server_sub); Ok(()) } @@ -1327,7 +1307,7 @@ impl IBCDHelper for IBCDHelperReal { proxy_server_sub: Recipient, ) { let pld = &args.payload; - let hostname_opt = pld.target_hostname.clone(); + let host = Host::new(&pld.target_hostname, pld.target_port); let logger = args.logger.clone(); debug!( logger, @@ -1342,7 +1322,7 @@ impl IBCDHelper for IBCDHelperReal { tokio::spawn( neighborhood_sub .send(RouteQueryMessage::data_indefinite_route_request( - hostname_opt, + host, payload_size, )) .then(move |route_result| { @@ -1356,7 +1336,6 @@ impl IBCDHelper for IBCDHelperReal { pub struct TransmitToHopperArgs { pub main_cryptde: &'static dyn CryptDE, pub payload: ClientRequestPayload_0v1, - pub return_route_id: u32, pub client_addr: SocketAddr, pub timestamp: SystemTime, pub is_decentralized: bool, @@ -1385,11 +1364,9 @@ impl TransmitToHopperArgs { } else { None }; - let return_route_id = proxy_server.get_next_return_route_id(); Self { main_cryptde: proxy_server.main_cryptde, payload, - return_route_id, client_addr, timestamp, logger: proxy_server.logger.clone(), @@ -1534,6 +1511,7 @@ mod tests { use std::sync::{Arc, Mutex}; use std::thread; use std::time::SystemTime; + use crate::sub_lib::host::Host; impl Handler> for ProxyServer { type Result = (); @@ -1842,7 +1820,7 @@ mod tests { .route(RouteQueryResponse { route: make_meaningless_route(), expected_services: expected_services.clone(), - hostname_opt: None, + host: Host::new("booga.com", TLS_PORT), }) .protocol(ProxyProtocol::TLS) .build(), @@ -1870,7 +1848,7 @@ mod tests { vec![make_exit_service_from_key(destination_key.clone())], vec![], ), - hostname_opt: Some("booga.com".to_string()), + host: Host::new("booga.com", HTTP_PORT), })); let (proxy_server_mock, _, proxy_server_recording_arc) = make_recorder(); let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); @@ -1879,7 +1857,7 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr, - reception_port: Some(HTTP_PORT), + reception_port_opt: Some(HTTP_PORT), sequence_number: Some(0), last_data: true, is_clandestine: false, @@ -1894,14 +1872,14 @@ mod tests { sequence_number: 0, last_data: true, }, - target_hostname: Some(String::from("nowhere.com")), + target_hostname: String::from("nowhere.com"), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: alias_cryptde.public_key().clone(), }; let expected_pkg = IncipientCoresPackage::new( main_cryptde, - route.clone().set_return_route_id(main_cryptde, 1), + route.clone().set_return_route_id(main_cryptde, 0), expected_payload.into(), &destination_key, ) @@ -1957,13 +1935,13 @@ mod tests { let record = recording.get_record::(0); assert_eq!( record, - &RouteQueryMessage::data_indefinite_route_request(Some("nowhere.com".to_string()), 47) + &RouteQueryMessage::data_indefinite_route_request(Host::new("nowhere.com", HTTP_PORT), 47) ); let recording = proxy_server_recording_arc.lock().unwrap(); assert_eq!(recording.len(), 0); TestLogHandler::new().exists_log_containing( - &format!("DEBUG: {test_name}: Found a new route for hostname: Some(\"nowhere.com\") - stream key: {stream_key} retries left: 3") + &format!("DEBUG: {test_name}: Found a new route for hostname: \"nowhere.com\" - stream key: {stream_key} retries left: 3") ); } @@ -1981,17 +1959,18 @@ mod tests { vec![make_exit_service_from_key(destination_key.clone())], vec![], ), - hostname_opt: Some("booga.com".to_string()), + host: Host::new("booga.com", HTTP_PORT), })); let route = Route { hops: vec![] }; let (dispatcher_mock, _, dispatcher_recording_arc) = make_recorder(); let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); let stream_key = StreamKey::make_meaningless_stream_key(); let request_data = http_request.to_vec(); + let tunneled_data = make_server_com_client_hello(); let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port: Some(8443), + reception_port_opt: Some(8443), sequence_number: Some(0), last_data: false, is_clandestine: false, @@ -2000,11 +1979,11 @@ mod tests { let tunnelled_msg = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr, - reception_port: Some(8443), + reception_port_opt: Some(8443), sequence_number: Some(0), last_data: false, is_clandestine: false, - data: b"client hello".to_vec(), + data: tunneled_data.clone(), }; let expected_tdm = TransmitDataMsg { endpoint: Endpoint::Socket(socket_addr), @@ -2015,18 +1994,18 @@ mod tests { let expected_payload = ClientRequestPayload_0v1 { stream_key: stream_key.clone(), sequenced_packet: SequencedPacket { - data: b"client hello".to_vec(), + data: tunneled_data, sequence_number: 0, last_data: false, }, - target_hostname: Some(String::from("realdomain.nu")), + target_hostname: String::from("realdomain.nu"), target_port: 443, protocol: ProxyProtocol::TLS, originator_public_key: alias_cryptde.public_key().clone(), }; let expected_pkg = IncipientCoresPackage::new( main_cryptde, - route.clone().set_return_route_id(main_cryptde, 1), + route.clone().set_return_route_id(main_cryptde, 0), expected_payload.into(), &destination_key, ) @@ -2089,8 +2068,8 @@ mod tests { assert_eq!( neighborhood_record, &RouteQueryMessage::data_indefinite_route_request( - Some("realdomain.nu".to_string()), - 12 + Host::new("realdomain.nu", TLS_PORT), + 68 ) ); } @@ -2126,7 +2105,7 @@ mod tests { vec![], vec![ExpectedService::Nothing], ), - hostname_opt: None, + host: Host::new("booga.com", HTTP_PORT), }) .build(), ); @@ -2136,7 +2115,7 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr, - reception_port: Some(443), + reception_port_opt: Some(443), last_data: false, is_clandestine: false, sequence_number: Some(0), @@ -2188,7 +2167,7 @@ mod tests { let (dispatcher_mock, _dispatcher_awaiter, dispatcher_recording_arc) = make_recorder(); let neighborhood_mock = neighborhood_mock.route_query_response(Some( - zero_hop_route_response(&cryptde.public_key(), cryptde), + zero_hop_route_response(&cryptde.public_key(), cryptde, false), )); let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); @@ -2197,7 +2176,7 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port: Some(8443), + reception_port_opt: Some(8443), sequence_number: Some(0), last_data: false, is_clandestine: false, @@ -2260,7 +2239,7 @@ mod tests { let (dispatcher_mock, _dispatcher_awaiter, dispatcher_recording_arc) = make_recorder(); let neighborhood_mock = neighborhood_mock.route_query_response(Some( - zero_hop_route_response(&cryptde.public_key(), cryptde), + zero_hop_route_response(&cryptde.public_key(), cryptde, false), )); let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); @@ -2269,7 +2248,7 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port: Some(8443), + reception_port_opt: Some(8443), sequence_number: Some(0), last_data: false, is_clandestine: false, @@ -2337,7 +2316,7 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port: Some(HTTP_PORT), + reception_port_opt: Some(HTTP_PORT), sequence_number: Some(0), last_data: true, is_clandestine: false, @@ -2396,7 +2375,7 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port: Some(TLS_PORT), + reception_port_opt: Some(TLS_PORT), sequence_number: Some(0), last_data: true, is_clandestine: false, @@ -2448,7 +2427,7 @@ mod tests { let alias_cryptde = alias_cryptde(); let expected_data = b"GET /index.html HTTP/1.1\r\nHost: nowhere.com\r\n\r\n".to_vec(); let expected_data_inner = expected_data.clone(); - let expected_route = zero_hop_route_response(main_cryptde.public_key(), main_cryptde); + let expected_route = zero_hop_route_response(main_cryptde.public_key(), main_cryptde, false); let stream_key = StreamKey::make_meaningless_stream_key(); let (hopper, hopper_awaiter, hopper_log_arc) = make_recorder(); let neighborhood = Recorder::new().route_query_response(Some(expected_route.clone())); @@ -2459,7 +2438,7 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port: Some(HTTP_PORT), + reception_port_opt: Some(HTTP_PORT), sequence_number: Some(0), last_data: true, is_clandestine: false, @@ -2497,7 +2476,7 @@ mod tests { target_component: Component::ProxyClient, return_component_opt: Some(Component::ProxyServer), payload_size: 47, - hostname_opt: Some("nowhere.com".to_string()), + host: Host::new("nowhere.com", HTTP_PORT), } ); let dispatcher_recording = dispatcher_log_arc.lock().unwrap(); @@ -2507,14 +2486,14 @@ mod tests { hopper_recording.get_record::(0), &IncipientCoresPackage::new( main_cryptde, - expected_route.route.set_return_route_id(main_cryptde, 1), + expected_route.route.set_return_route_id(main_cryptde, 0), MessageType::ClientRequest(VersionedData::new( &crate::sub_lib::migrations::client_request_payload::MIGRATIONS, &ClientRequestPayload_0v1 { stream_key, sequenced_packet: SequencedPacket::new(expected_data, 0, true), - target_hostname: Some("nowhere.com".to_string()), - target_port: 80, + target_hostname: "nowhere.com".to_string(), + target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: alias_cryptde.public_key().clone(), } @@ -2533,24 +2512,25 @@ mod tests { let alias_cryptde = alias_cryptde(); let expected_data = b"Fake TLS request".to_vec(); let expected_data_inner = expected_data.clone(); - let expected_route = zero_hop_route_response(main_cryptde.public_key(), main_cryptde); + let expected_route = zero_hop_route_response(main_cryptde.public_key(), main_cryptde, true); + let expected_route_inner = expected_route.clone(); let stream_key = StreamKey::make_meaningless_stream_key(); let (hopper, hopper_awaiter, hopper_log_arc) = make_recorder(); let neighborhood = Recorder::new().route_query_response(Some(expected_route.clone())); - let neighborhood_log_arc = neighborhood.get_recording(); let (dispatcher, _, dispatcher_log_arc) = make_recorder(); thread::spawn(move || { let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port: Some(TLS_PORT), + reception_port_opt: Some(TLS_PORT), sequence_number: Some(0), last_data: true, is_clandestine: false, data: expected_data_inner, }; - let stream_key_factory = StreamKeyFactoryMock::new(); // can't make any stream keys; shouldn't have to + let stream_key_factory = StreamKeyFactoryMock::new() + .make_result(stream_key.clone()); let system = System::new("proxy_server_receives_tls_request_with_no_consuming_wallet_in_zero_hop_mode_and_handles_normally"); let mut subject = ProxyServer::new(main_cryptde, alias_cryptde, false, None, false, false); @@ -2558,7 +2538,10 @@ mod tests { subject.keys_and_addrs.insert(stream_key, socket_addr); subject .stream_info - .insert(stream_key.clone(), StreamInfoBuilder::new().build()); + .insert(stream_key, StreamInfoBuilder::new() + .route(expected_route_inner) + .protocol(ProxyProtocol::TLS) + .build()); let subject_addr: Addr = subject.start(); let peer_actors = peer_actors_builder() .dispatcher(dispatcher) @@ -2572,17 +2555,6 @@ mod tests { system.run(); }); hopper_awaiter.await_message_count(1); - let neighborhood_recording = neighborhood_log_arc.lock().unwrap(); - assert_eq!( - neighborhood_recording.get_record::(0), - &RouteQueryMessage { - target_key_opt: None, - target_component: Component::ProxyClient, - return_component_opt: Some(Component::ProxyServer), - payload_size: 16, - hostname_opt: None, - } - ); let dispatcher_recording = dispatcher_log_arc.lock().unwrap(); assert!(dispatcher_recording.is_empty()); let hopper_recording = hopper_log_arc.lock().unwrap(); @@ -2590,14 +2562,14 @@ mod tests { hopper_recording.get_record::(0), &IncipientCoresPackage::new( main_cryptde, - expected_route.route.set_return_route_id(main_cryptde, 1), + expected_route.route.set_return_route_id(main_cryptde, 0), MessageType::ClientRequest(VersionedData::new( &crate::sub_lib::migrations::client_request_payload::MIGRATIONS, &ClientRequestPayload_0v1 { stream_key, sequenced_packet: SequencedPacket::new(expected_data, 0, true), - target_hostname: None, - target_port: 443, + target_hostname: "booga.com".to_string(), + target_port: TLS_PORT, protocol: ProxyProtocol::TLS, originator_public_key: alias_cryptde.public_key().clone(), } @@ -2624,7 +2596,7 @@ mod tests { vec![make_exit_service_from_key(destination_key.clone())], vec![], ), - hostname_opt: Some("booga.com".to_string()), + host: Host::new("booga.com", HTTP_PORT), })); let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); let stream_key = StreamKey::make_meaningless_stream_key(); @@ -2632,7 +2604,7 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port: Some(HTTP_PORT), + reception_port_opt: Some(HTTP_PORT), sequence_number: Some(0), last_data: true, is_clandestine: false, @@ -2647,14 +2619,14 @@ mod tests { sequence_number: 0, last_data: true, }, - target_hostname: Some(String::from("nowhere.com")), + target_hostname: String::from("nowhere.com"), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: alias_cryptde.public_key().clone(), }; let expected_pkg = IncipientCoresPackage::new( main_cryptde, - route.clone().set_return_route_id(main_cryptde, 1), + route.clone().set_return_route_id(main_cryptde, 0), expected_payload.into(), &destination_key, ) @@ -2729,7 +2701,7 @@ mod tests { Some(TEST_DEFAULT_CHAIN.rec().contract), ) .unwrap() - .set_return_route_id(main_cryptde, 1234); + .set_return_route_id(main_cryptde, 0); let (neighborhood_mock, _, neighborhood_recording_arc) = make_recorder(); let neighborhood_mock = neighborhood_mock.route_query_response(Some(RouteQueryResponse { route: route.clone(), @@ -2747,7 +2719,7 @@ mod tests { ExpectedService::Exit(PublicKey::new(&[3]), earning_wallet, rate_pack(102)), ], ), - hostname_opt: Some("booga.com".to_string()), + host: Host::new("booga.com", HTTP_PORT), })); let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); let stream_key = StreamKey::make_meaningless_stream_key(); @@ -2755,7 +2727,7 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port: Some(HTTP_PORT), + reception_port_opt: Some(HTTP_PORT), sequence_number: Some(0), last_data: true, is_clandestine: false, @@ -2769,14 +2741,14 @@ mod tests { sequence_number: 0, last_data: true, }, - target_hostname: Some(String::from("nowhere.com")), + target_hostname: String::from("nowhere.com"), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: alias_cryptde.public_key().clone(), }; let expected_pkg = IncipientCoresPackage::new( main_cryptde, - route.clone().set_return_route_id(main_cryptde, 1), + route.clone().set_return_route_id(main_cryptde, 0), expected_payload.into(), &payload_destination_key, ) @@ -2813,7 +2785,7 @@ mod tests { let record = recording.get_record::(0); assert_eq!( record, - &RouteQueryMessage::data_indefinite_route_request(Some("nowhere.com".to_string()), 47) + &RouteQueryMessage::data_indefinite_route_request(Host::new("nowhere.com", HTTP_PORT), 47) ); } @@ -2833,7 +2805,7 @@ mod tests { vec![expected_service.clone()], vec![expected_service], ), - hostname_opt: Some("booga.com".to_string()), + host: Host::new("booga.com", HTTP_PORT), }); let (neighborhood_mock, _, _) = make_recorder(); let neighborhood_mock = @@ -2844,7 +2816,7 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port: Some(HTTP_PORT), + reception_port_opt: Some(HTTP_PORT), sequence_number: Some(0), last_data: true, is_clandestine: false, @@ -2906,7 +2878,7 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port: Some(HTTP_PORT), + reception_port_opt: Some(HTTP_PORT), sequence_number: Some(0), last_data: true, is_clandestine: false, @@ -2960,7 +2932,7 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port: Some(HTTP_PORT), + reception_port_opt: Some(HTTP_PORT), sequence_number: Some(0), last_data: true, is_clandestine: false, @@ -3004,7 +2976,7 @@ mod tests { vec![make_exit_service_from_key(destination_key.clone())], vec![], ), - hostname_opt: Some("booga.com".to_string()), + host: Host::new("booga.com", HTTP_PORT), }; let (hopper_mock, hopper_awaiter, hopper_recording_arc) = make_recorder(); let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); @@ -3013,7 +2985,7 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr, - reception_port: Some(HTTP_PORT), + reception_port_opt: Some(HTTP_PORT), sequence_number: Some(0), last_data: true, is_clandestine: false, @@ -3026,7 +2998,7 @@ mod tests { sequence_number: 0, last_data: true, }, - target_hostname: Some(String::from("nowhere.com")), + target_hostname: String::from("nowhere.com"), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: alias_cryptde.public_key().clone(), @@ -3058,7 +3030,6 @@ mod tests { stream_key, StreamInfoBuilder::new().route(route_query_response).build(), ); - subject.next_return_route_id = Cell::new(0); let subject_addr: Addr = subject.start(); let peer_actors = peer_actors_builder().hopper(hopper_mock).build(); subject_addr.try_send(BindMessage { peer_actors }).unwrap(); @@ -3160,7 +3131,7 @@ mod tests { ExpectedService::Nothing, ], ), - hostname_opt: Some("booga.com".to_string()), + host: Host::new("booga.com", HTTP_PORT), }; let source_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); let stream_key = StreamKey::make_meaningless_stream_key(); @@ -3176,7 +3147,7 @@ mod tests { let payload = ClientRequestPayload_0v1 { stream_key, sequenced_packet: SequencedPacket::new(expected_data, 0, false), - target_hostname: Some("nowhere.com".to_string()), + target_hostname: "nowhere.com".to_string(), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: PublicKey::new(b"originator_public_key"), @@ -3185,7 +3156,6 @@ mod tests { let args = TransmitToHopperArgs { main_cryptde: cryptde, payload, - return_route_id: 4444, client_addr: source_addr, timestamp: now, is_decentralized: true, @@ -3225,7 +3195,7 @@ mod tests { TEST_DEFAULT_CHAIN, )); let _ = record.route.shift(cryptde); - assert_eq!(record.route.return_route_id(cryptde).unwrap(), 4444); + assert_eq!(record.route.return_route_id(cryptde).unwrap(), 0); let recording = accountant_recording_arc.lock().unwrap(); let record = recording.get_record::(0); assert_eq!(recording.len(), 1); @@ -3270,7 +3240,7 @@ mod tests { vec![ExpectedService::Nothing], vec![ExpectedService::Nothing], ), - hostname_opt: Some("booga.com".to_string()), + host: Host::new("booga.com", HTTP_PORT), }; let source_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); let stream_key = StreamKey::make_meaningless_stream_key(); @@ -3283,7 +3253,7 @@ mod tests { let payload = ClientRequestPayload_0v1 { stream_key, sequenced_packet: SequencedPacket::new(expected_data, 0, false), - target_hostname: Some("nowhere.com".to_string()), + target_hostname: "nowhere.com".to_string(), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: PublicKey::new(b"originator_public_key"), @@ -3292,7 +3262,6 @@ mod tests { let args = TransmitToHopperArgs { main_cryptde: cryptde, payload, - return_route_id: 3333, client_addr: source_addr, timestamp: SystemTime::now(), is_decentralized: false, @@ -3330,7 +3299,7 @@ mod tests { let http_request = b"GET /index.html HTTP/1.1\r\nHost: nowhere.com\r\n\r\n"; let (accountant_mock, accountant_awaiter, _) = make_recorder(); let (neighborhood_mock, _, _) = make_recorder(); - let mut route_query_response = zero_hop_route_response(&cryptde.public_key(), cryptde); + let mut route_query_response = zero_hop_route_response(&cryptde.public_key(), cryptde, false); route_query_response.expected_services = ExpectedServices::RoundTrip( vec![ExpectedService::Exit( cryptde.public_key().clone(), @@ -3347,7 +3316,7 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port: Some(HTTP_PORT), + reception_port_opt: Some(HTTP_PORT), sequence_number: Some(0), last_data: true, is_clandestine: false, @@ -3477,7 +3446,7 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port: Some(HTTP_PORT), + reception_port_opt: Some(HTTP_PORT), sequence_number: Some(0), last_data: true, data: expected_data.clone(), @@ -3523,10 +3492,10 @@ mod tests { let record = recording.get_record::(0); assert_eq!( record, - &RouteQueryMessage::data_indefinite_route_request(Some("nowhere.com".to_string()), 47) + &RouteQueryMessage::data_indefinite_route_request(Host::new("nowhere.com", HTTP_PORT), 47) ); TestLogHandler::new().exists_log_containing(&format!( - "WARN: {test_name}: No route found for hostname: Some(\"nowhere.com\") - stream key {stream_key} - retries left: 3 - AddRouteResultMessage Error: Failed to find route to nowhere.com" + "WARN: {test_name}: No route found for hostname: \"nowhere.com\" - stream key {stream_key} - retries left: 3 - AddRouteResultMessage Error: Failed to find route to nowhere.com" )); } @@ -3557,7 +3526,7 @@ mod tests { rate_pack(103), ), ]), - hostname_opt: Some("booga.com".to_string()), + host: Host::new("booga.com", HTTP_PORT), }; let payload = ClientRequestPayload_0v1 { stream_key: StreamKey::make_meaningless_stream_key(), @@ -3566,7 +3535,7 @@ mod tests { sequence_number: 0, last_data: false, }, - target_hostname: None, + target_hostname: "booga.com".to_string(), target_port: 0, protocol: ProxyProtocol::TLS, originator_public_key: cryptde.public_key().clone(), @@ -3576,7 +3545,6 @@ mod tests { let args = TransmitToHopperArgs { main_cryptde: cryptde, payload, - return_route_id: 2222, client_addr: source_addr, timestamp: SystemTime::now(), is_decentralized: true, @@ -3638,9 +3606,9 @@ mod tests { None, ) .unwrap() - .set_return_route_id(cryptde, 1234), + .set_return_route_id(cryptde, 0), expected_services: ExpectedServices::RoundTrip(vec![], vec![]), - hostname_opt: Some("booga.com".to_string()), + host: Host::new("booga.com", HTTP_PORT), }; let neighborhood_mock = neighborhood_mock.route_query_response(Some(route_query_response)); let dispatcher = Recorder::new(); @@ -3651,7 +3619,7 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port: Some(HTTP_PORT), + reception_port_opt: Some(HTTP_PORT), sequence_number: Some(0), last_data: true, data: expected_data.clone(), @@ -3698,35 +3666,16 @@ mod tests { let record = recording.get_record::(0); assert_eq!( record, - &RouteQueryMessage::data_indefinite_route_request(Some("nowhere.com".to_string()), 47) + &RouteQueryMessage::data_indefinite_route_request(Host::new("nowhere.com", HTTP_PORT), 47) ); TestLogHandler::new().exists_log_containing(&format!( - "WARN: {test_name}: No route found for hostname: Some(\"nowhere.com\") - stream key {stream_key} - retries left: 3 - AddRouteResultMessage Error: Failed to find route to nowhere.com" + "WARN: {test_name}: No route found for hostname: \"nowhere.com\" - stream key {stream_key} - retries left: 3 - AddRouteResultMessage Error: Failed to find route to nowhere.com" )); } #[test] fn proxy_server_receives_tls_client_hello_from_dispatcher_then_sends_cores_package_to_hopper() { - let tls_request = &[ - 0x16, // content_type: Handshake - 0x00, 0x00, 0x00, 0x00, // version, length: don't care - 0x01, // handshake_type: ClientHello - 0x00, 0x00, 0x00, 0x00, 0x00, // length, version: don't care - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, // random: don't care - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, // random: don't care - 0x00, // session_id_length - 0x00, 0x00, // cipher_suites_length - 0x00, // compression_methods_length - 0x00, 0x13, // extensions_length - 0x00, 0x00, // extension_type: server_name - 0x00, 0x0F, // extension_length - 0x00, 0x0D, // server_name_list_length - 0x00, // server_name_type - 0x00, 0x0A, // server_name_length - b's', b'e', b'r', b'v', b'e', b'r', b'.', b'c', b'o', b'm', // server_name - ]; + let tls_request = make_server_com_client_hello(); let main_cryptde = main_cryptde(); let alias_cryptde = alias_cryptde(); let hopper_mock = Recorder::new(); @@ -3739,22 +3688,22 @@ mod tests { vec![make_exit_service_from_key(destination_key.clone())], vec![], ), - hostname_opt: Some("booga.com".to_string()), + host: Host::new("booga.com", TLS_PORT), })); let stream_key = StreamKey::make_meaningless_stream_key(); let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); - let expected_data = tls_request.to_vec(); + let expected_data = tls_request.clone(); let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port: Some(TLS_PORT), + reception_port_opt: Some(TLS_PORT), sequence_number: Some(0), last_data: false, is_clandestine: false, data: expected_data.clone(), }; - let expected_tls_request = PlainData::new(tls_request); - let route = Route { hops: vec![] }.set_return_route_id(main_cryptde, 1); + let expected_tls_request = PlainData::new(tls_request.as_slice()); + let route = Route { hops: vec![] }.set_return_route_id(main_cryptde, 0); let expected_payload = ClientRequestPayload_0v1 { stream_key: stream_key.clone(), sequenced_packet: SequencedPacket { @@ -3762,7 +3711,7 @@ mod tests { sequence_number: 0, last_data: false, }, - target_hostname: Some(String::from("server.com")), + target_hostname: String::from("server.com"), target_port: TLS_PORT, protocol: ProxyProtocol::TLS, originator_public_key: alias_cryptde.public_key().clone(), @@ -3825,7 +3774,7 @@ mod tests { vec![make_exit_service_from_key(destination_key.clone())], vec![], ), - hostname_opt: Some("booga.com".to_string()), + host: Host::new("booga.com", TLS_PORT), })); let stream_key = StreamKey::make_meaningless_stream_key(); let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); @@ -3833,7 +3782,7 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port: Some(TLS_PORT), + reception_port_opt: Some(TLS_PORT), sequence_number: Some(0), last_data: false, is_clandestine: false, @@ -3848,14 +3797,14 @@ mod tests { sequence_number: 0, last_data: false, }, - target_hostname: None, + target_hostname: "booga.com".to_string(), target_port: TLS_PORT, protocol: ProxyProtocol::TLS, originator_public_key: alias_cryptde.public_key().clone(), }; let expected_pkg = IncipientCoresPackage::new( main_cryptde, - route.clone().set_return_route_id(main_cryptde, 1), + route.clone().set_return_route_id(main_cryptde, 0), expected_payload.into(), &destination_key, ) @@ -3871,6 +3820,20 @@ mod tests { ); subject.stream_key_factory = Box::new(StreamKeyFactoryMock::new().make_result(stream_key.clone())); + subject.keys_and_addrs.insert(stream_key.clone(), socket_addr); + subject.stream_info.insert( + stream_key.clone(), + StreamInfoBuilder::new() + .route(RouteQueryResponse { + route: Route { hops: vec![] }, + expected_services: ExpectedServices::RoundTrip( + vec![make_exit_service_from_key(destination_key.clone())], + vec![], + ), + host: Host::new("booga.com", TLS_PORT), + }) + .build(), + ); let system = System::new("proxy_server_receives_tls_client_hello_from_dispatcher_then_sends_cores_package_to_hopper"); let subject_addr: Addr = subject.start(); let peer_actors = peer_actors_builder() @@ -3883,7 +3846,6 @@ mod tests { system.run(); }); - hopper_awaiter.await_message_count(1); let recording = hopper_log_arc.lock().unwrap(); let record = recording.get_record::(0); @@ -3910,7 +3872,7 @@ mod tests { vec![make_exit_service_from_key(destination_key.clone())], vec![], ), - hostname_opt: Some("booga.com".to_string()), + host: Host::new("booga.com", TLS_PORT), })); let client_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); let stream_key = StreamKey::make_meaningful_stream_key(test_name); @@ -3918,7 +3880,7 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr, - reception_port: Some(TLS_PORT), + reception_port_opt: Some(TLS_PORT), sequence_number: Some(0), last_data: true, is_clandestine: false, @@ -3933,14 +3895,14 @@ mod tests { sequence_number: 0, last_data: true, }, - target_hostname: None, + target_hostname: "booga.com".to_string(), target_port: TLS_PORT, protocol: ProxyProtocol::TLS, originator_public_key: alias_cryptde.public_key().clone(), }; let expected_pkg = IncipientCoresPackage::new( main_cryptde, - route.clone().set_return_route_id(main_cryptde, 1), + route.clone().set_return_route_id(main_cryptde, 0), expected_payload.into(), &destination_key, ) @@ -3957,7 +3919,17 @@ mod tests { subject.keys_and_addrs.insert(stream_key, client_addr); subject .stream_info - .insert(stream_key, StreamInfoBuilder::new().build()); + .insert(stream_key, StreamInfoBuilder::new() + .route(RouteQueryResponse { + route: Route { hops: vec![] }, + expected_services: ExpectedServices::RoundTrip( + vec![make_exit_service_from_key(destination_key.clone())], + vec![], + ), + host: Host::new("booga.com", TLS_PORT), + }) + .protocol(ProxyProtocol::TLS) + .build()); let system = System::new(test_name); let subject_addr: Addr = subject.start(); let peer_actors = peer_actors_builder() @@ -4012,7 +3984,7 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port: Some(TLS_PORT), + reception_port_opt: Some(TLS_PORT), sequence_number: Some(0), last_data: true, data: tls_request, @@ -4084,13 +4056,13 @@ mod tests { vec![], vec![ExpectedService::Nothing], ), - hostname_opt: None, + host: Host::new("booga.com", TLS_PORT), }) .protocol(ProxyProtocol::TLS) .build(), ); let subject_addr: Addr = subject.start(); - let remaining_route = return_route_with_id(cryptde, 1234); + let remaining_route = return_route_with_id(cryptde, 0); let client_response_payload = ClientResponsePayload_0v1 { stream_key: stream_key.clone(), sequenced_packet: SequencedPacket { @@ -4173,7 +4145,7 @@ mod tests { .route(RouteQueryResponse { route: Route { hops: vec![] }, expected_services: ExpectedServices::RoundTrip(vec![], vec![]), - hostname_opt: None, + host: Host::new("booga.com", HTTP_PORT), }) .protocol(ProxyProtocol::HTTP) .tunneled_host("hostname") @@ -4190,7 +4162,7 @@ mod tests { ExpiredCoresPackage::new( SocketAddr::from_str("1.2.3.4:1234").unwrap(), Some(make_wallet("irrelevant")), - return_route_with_id(cryptde, 1234), + return_route_with_id(cryptde, 0), client_response_payload.into(), 0, ); @@ -4274,7 +4246,7 @@ mod tests { .route(RouteQueryResponse { route: Route { hops: vec![] }, expected_services: ExpectedServices::RoundTrip(vec![], vec![]), - hostname_opt: None, + host: Host::new("booga.com", HTTP_PORT), }) .protocol(ProxyProtocol::HTTP) .tunneled_host("hostname") @@ -4379,7 +4351,7 @@ mod tests { exit_rates.clone(), )], ), - hostname_opt: None, + host: Host::new("booga.com", HTTP_PORT), }) .tunneled_host("hostname") .protocol(ProxyProtocol::HTTP) @@ -4403,7 +4375,7 @@ mod tests { ExpiredCoresPackage::new( SocketAddr::from_str("1.2.3.4:1234").unwrap(), Some(make_wallet("irrelevant")), - return_route_with_id(cryptde, 1234), + return_route_with_id(cryptde, 0), client_response_payload.into(), 5432, ); @@ -4488,7 +4460,7 @@ mod tests { ExpectedService::Nothing, ], ), - hostname_opt: None, + host: Host::new("booga.com", HTTP_PORT), }) .build(), ); @@ -4506,7 +4478,7 @@ mod tests { ExpiredCoresPackage::new( SocketAddr::from_str("1.2.3.4:1234").unwrap(), Some(make_wallet("irrelevant")), - return_route_with_id(cryptde, 1234), + return_route_with_id(cryptde, 0), first_client_response_payload.into(), 0, ); @@ -4676,7 +4648,7 @@ mod tests { ExpectedService::Nothing, ], ), - hostname_opt: None, + host: Host::new("booga.com", TLS_PORT), }) .protocol(ProxyProtocol::TLS) .build(), @@ -4694,7 +4666,7 @@ mod tests { ExpiredCoresPackage::new( SocketAddr::from_str("1.2.3.4:1234").unwrap(), Some(make_wallet("irrelevant")), - return_route_with_id(cryptde, 1234), + return_route_with_id(cryptde, 0), first_client_response_payload.into(), 0, ); @@ -4760,7 +4732,7 @@ mod tests { ), ], ), - hostname_opt: None, + host: Host::new("booga.com", TLS_PORT), }) .protocol(ProxyProtocol::TLS) .build(), @@ -4779,7 +4751,7 @@ mod tests { ExpiredCoresPackage::new( SocketAddr::from_str("1.2.3.4:1234").unwrap(), Some(make_wallet("irrelevant")), - return_route_with_id(cryptde, 1234), + return_route_with_id(cryptde, 0), client_response_payload.into(), 0, ); @@ -4865,7 +4837,7 @@ mod tests { rate_pack(10), )], ), - hostname_opt: Some("server.com".to_string()), + host: Host::new("server.com", HTTP_PORT), }) .protocol(ProxyProtocol::HTTP) .build(), @@ -4876,7 +4848,7 @@ mod tests { ExpiredCoresPackage::new( SocketAddr::from_str("1.2.3.4:1234").unwrap(), Some(make_wallet("irrelevant")), - return_route_with_id(cryptde, 1234), + return_route_with_id(cryptde, 0), dns_resolve_failure.into(), 0, ); @@ -4896,7 +4868,7 @@ mod tests { last_data: true, sequence_number: Some(0), data: ServerImpersonatorHttp {} - .dns_resolution_failure_response(Some("server.com".to_string()),), + .dns_resolution_failure_response("server.com".to_string()), }, *record ); @@ -4958,7 +4930,7 @@ mod tests { ExpectedService::Nothing, ], ), - hostname_opt: None, + host: Host::new("booga.com", TLS_PORT), }) .protocol(ProxyProtocol::TLS) .build(), @@ -4969,7 +4941,7 @@ mod tests { ExpiredCoresPackage::new( SocketAddr::from_str("1.2.3.4:1234").unwrap(), Some(make_wallet("irrelevant")), - return_route_with_id(cryptde, 1234), + return_route_with_id(cryptde, 0), dns_resolve_failure_payload.into(), 0, ); @@ -5059,7 +5031,7 @@ mod tests { rate_pack(10), )], ), - hostname_opt: Some("server.com".to_string()), + host: Host::new("server.com", HTTP_PORT), }) .protocol(ProxyProtocol::HTTP) .build(), @@ -5070,7 +5042,7 @@ mod tests { ExpiredCoresPackage::new( SocketAddr::from_str("1.2.3.4:1234").unwrap(), Some(make_wallet("irrelevant")), - return_route_with_id(cryptde, 1234), + return_route_with_id(cryptde, 0), dns_resolve_failure.into(), 0, ); @@ -5099,80 +5071,6 @@ mod tests { )); } - #[test] - fn handle_dns_resolve_failure_does_not_send_message_to_neighborhood_when_server_is_not_specified( - ) { - init_test_logging(); - let test_name = "handle_dns_resolve_failure_does_not_send_message_to_neighborhood_when_server_is_not_specified"; - let system = System::new(test_name); - let (neighborhood, _, neighborhood_recording_arc) = make_recorder(); - let cryptde = main_cryptde(); - let mut subject = ProxyServer::new( - cryptde, - alias_cryptde(), - true, - Some(STANDARD_CONSUMING_WALLET_BALANCE), - false, - false, - ); - let stream_key = StreamKey::make_meaningless_stream_key(); - let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); - let client_payload = make_request_payload(111, cryptde); - subject.logger = Logger::new(test_name); - subject - .keys_and_addrs - .insert(stream_key.clone(), socket_addr); - let exit_public_key = PublicKey::from(&b"exit_key"[..]); - let exit_wallet = make_wallet("exit wallet"); - subject.stream_info.insert( - stream_key, - StreamInfoBuilder::new() - .dns_failure_retry(DNSFailureRetry { - unsuccessful_request: client_payload, - retries_left: 0, - }) - .route(RouteQueryResponse { - route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip( - vec![], - vec![ExpectedService::Exit( - exit_public_key.clone(), - exit_wallet, - rate_pack(10), - )], - ), - hostname_opt: None, - }) - .protocol(ProxyProtocol::HTTP) - .build(), - ); - let subject_addr: Addr = subject.start(); - let dns_resolve_failure = DnsResolveFailure_0v1::new(stream_key); - let expired_cores_package: ExpiredCoresPackage = - ExpiredCoresPackage::new( - SocketAddr::from_str("1.2.3.4:1234").unwrap(), - Some(make_wallet("irrelevant")), - return_route_with_id(cryptde, 1234), - dns_resolve_failure.into(), - 0, - ); - let peer_actors = peer_actors_builder().neighborhood(neighborhood).build(); - - subject_addr.try_send(BindMessage { peer_actors }).unwrap(); - subject_addr.try_send(expired_cores_package).unwrap(); - - System::current().stop(); - system.run(); - let neighborhood_recording = neighborhood_recording_arc.lock().unwrap(); - let record_opt = - neighborhood_recording.get_record_opt::(0); - assert_eq!(record_opt, None); - TestLogHandler::new().exists_log_containing(&format!( - "ERROR: {}: Exit node {} complained of DNS failure, but was given no hostname to resolve.", - test_name, &exit_public_key - )); - } - #[test] fn handle_dns_resolve_failure_logs_when_stream_key_is_found_in_stream_info_but_not_keys_and_addrs( ) { @@ -5189,7 +5087,7 @@ mod tests { false, ); let stream_key = StreamKey::make_meaningless_stream_key(); - let return_route_id = 1234; + let return_route_id = 0; let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); let client_payload = make_request_payload(111, cryptde); let exit_public_key = PublicKey::from(&b"exit_key"[..]); @@ -5211,7 +5109,7 @@ mod tests { rate_pack(10), )], ), - hostname_opt: Some("server.com".to_string()), + host: Host::new("server.com", HTTP_PORT), }) .protocol(ProxyProtocol::HTTP) .build(), @@ -5263,7 +5161,7 @@ mod tests { false, ); let stream_key = StreamKey::make_meaningless_stream_key(); - let return_route_id = 1234; + let return_route_id = 0; let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); let client_payload = make_request_payload(111, cryptde); subject @@ -5288,7 +5186,7 @@ mod tests { rate_pack(10), )], ), - hostname_opt: None, + host: Host::new("booga.com", HTTP_PORT), }) .protocol(ProxyProtocol::HTTP) .build(), @@ -5366,7 +5264,7 @@ mod tests { ExpectedService::Nothing, ], ), - hostname_opt: None, + host: Host::new("booga.com", HTTP_PORT), }) .protocol(ProxyProtocol::HTTP) .build(), @@ -5376,7 +5274,7 @@ mod tests { ExpiredCoresPackage::new( SocketAddr::from_str("1.2.3.4:1234").unwrap(), Some(make_wallet("irrelevant")), - return_route_with_id(cryptde, 1234), + return_route_with_id(cryptde, 0), dns_resolve_failure.into(), 0, ); @@ -5421,7 +5319,7 @@ mod tests { vec![], vec![ExpectedService::Nothing, ExpectedService::Nothing], ), - hostname_opt: Some("server.com".to_string()), + host: Host::new("server.com", HTTP_PORT), }) .protocol(ProxyProtocol::HTTP) .build(), @@ -5432,7 +5330,7 @@ mod tests { ExpiredCoresPackage::new( SocketAddr::from_str("1.2.3.4:1234").unwrap(), Some(make_wallet("irrelevant")), - return_route_with_id(cryptde, 1234), + return_route_with_id(cryptde, 0), dns_resolve_failure.into(), 0, ); @@ -5465,7 +5363,7 @@ mod tests { last_data: true, sequence_number: Some(0), data: ServerImpersonatorHttp {} - .dns_resolution_failure_response(Some("server.com".to_string()),), + .dns_resolution_failure_response("server.com".to_string()), }, *record ); @@ -5491,7 +5389,7 @@ mod tests { expected_services.clone(), expected_services.clone(), ), - hostname_opt: Some("booga.com".to_string()), + host: Host::new("booga.com", HTTP_PORT), }; let neighborhood_mock = neighborhood_mock .system_stop_conditions(match_every_type_id!(RouteQueryMessage)) @@ -5524,7 +5422,7 @@ mod tests { vec![], expected_services.clone(), ), - hostname_opt: Some("server.com".to_string()), + host: Host::new("server.com", HTTP_PORT), }) .protocol(ProxyProtocol::HTTP) .build(), @@ -5542,7 +5440,7 @@ mod tests { ExpiredCoresPackage::new( SocketAddr::from_str("1.2.3.4:1234").unwrap(), Some(make_wallet("irrelevant")), - return_route_with_id(cryptde, 1234), + return_route_with_id(cryptde, 0), dns_resolve_failure.into(), 0, ); @@ -5622,7 +5520,7 @@ mod tests { vec![], expected_services.clone(), ), - hostname_opt: Some("server.com".to_string()), + host: Host::new("server.com", HTTP_PORT), }) .protocol(ProxyProtocol::HTTP) .build(), @@ -5633,7 +5531,7 @@ mod tests { ExpiredCoresPackage::new( SocketAddr::from_str("1.2.3.4:1234").unwrap(), Some(make_wallet("irrelevant")), - return_route_with_id(cryptde, 1234), + return_route_with_id(cryptde, 0), dns_resolve_failure.into(), 0, ); @@ -5670,7 +5568,7 @@ mod tests { expected_services.clone(), expected_services.clone(), ), - hostname_opt: Some("booga.com".to_string()), + host: Host::new("booga.com", HTTP_PORT), }; let neighborhood_mock = neighborhood_mock .system_stop_conditions(match_every_type_id!( @@ -5709,7 +5607,7 @@ mod tests { vec![], expected_services.clone(), ), - hostname_opt: Some("server.com".to_string()), + host: Host::new("server.com", HTTP_PORT), }) .protocol(ProxyProtocol::HTTP) .build(), @@ -5729,7 +5627,7 @@ mod tests { ExpiredCoresPackage::new( SocketAddr::from_str("1.2.3.4:1234").unwrap(), Some(make_wallet("irrelevant")), - return_route_with_id(cryptde, 1234), + return_route_with_id(cryptde, 0), dns_resolve_failure.into(), 0, ); @@ -5793,7 +5691,7 @@ mod tests { vec![], vec![ExpectedService::Nothing], ), - hostname_opt: None, + host: Host::new("booga.com", HTTP_PORT), }) .protocol(ProxyProtocol::HTTP) .build(), @@ -5840,7 +5738,7 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port: Some(80), + reception_port_opt: Some(80), sequence_number: Some(0), last_data: false, is_clandestine: false, @@ -5922,7 +5820,7 @@ mod tests { .route(RouteQueryResponse { route: Route { hops: vec![] }, expected_services: ExpectedServices::RoundTrip(vec![], vec![]), - hostname_opt: Some("booga.com".to_string()), + host: Host::new("booga.com", HTTP_PORT), }) .tunneled_host("blah") .build(), @@ -5978,7 +5876,7 @@ mod tests { .route(RouteQueryResponse { route: Route { hops: vec![] }, expected_services: ExpectedServices::RoundTrip(vec![], vec![]), - hostname_opt: Some("booga.com".to_string()), + host: Host::new("gooba.com", HTTP_PORT), }) .tunneled_host("blah") .build(), @@ -6011,7 +5909,7 @@ mod tests { affected_expected_services, vec![], ), - hostname_opt: Some("booga.com".to_string()), + host: Host::new("gooba.com", TLS_PORT), }) .tunneled_host("tunneled.com") .build(), @@ -6042,7 +5940,7 @@ mod tests { let record = recording.get_record::(0); assert_eq!( record.route, - affected_route.set_return_route_id(main_cryptde(), 1) + affected_route.set_return_route_id(main_cryptde(), 0) ); let payload = decodex::(&affected_cryptde, &record.payload).unwrap(); match payload { @@ -6052,8 +5950,8 @@ mod tests { ClientRequestPayload_0v1 { stream_key: affected_stream_key, sequenced_packet: SequencedPacket::new(vec![], 1234, true), - target_hostname: Some(String::from("tunneled.com")), - target_port: 443, + target_hostname: String::from("tunneled.com"), + target_port: TLS_PORT, protocol: ProxyProtocol::TLS, originator_public_key: alias_cryptde().public_key().clone(), } @@ -6106,11 +6004,10 @@ mod tests { .route(RouteQueryResponse { route: Route { hops: vec![] }, expected_services: ExpectedServices::RoundTrip(vec![], vec![]), - hostname_opt: Some("booga.com".to_string()), + host: Host::new("booga.com", HTTP_PORT), }) .build(), ); - subject.next_return_route_id = Cell::new(1234); let affected_route = Route::round_trip( RouteSegment::new( vec![main_cryptde().public_key(), affected_cryptde.public_key()], @@ -6139,7 +6036,7 @@ mod tests { affected_expected_services, vec![], ), - hostname_opt: Some("booga.com".to_string()), + host: Host::new("booga.com", HTTP_PORT), }) .build(), ); @@ -6170,7 +6067,7 @@ mod tests { let record = recording.get_record::(0); assert_eq!( record.route, - affected_route.set_return_route_id(main_cryptde(), 1234) + affected_route.set_return_route_id(main_cryptde(), 0) ); let payload = decodex::(&affected_cryptde, &record.payload).unwrap(); match payload { @@ -6180,7 +6077,7 @@ mod tests { ClientRequestPayload_0v1 { stream_key: affected_stream_key, sequenced_packet: SequencedPacket::new(vec![], 1234, true), - target_hostname: None, + target_hostname: "booga.com".to_string(), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: alias_cryptde().public_key().clone(), @@ -6256,7 +6153,7 @@ mod tests { .route(RouteQueryResponse { route: Route { hops: vec![] }, expected_services: ExpectedServices::RoundTrip(vec![], vec![]), - hostname_opt: Some("booga.com".to_string()), + host: Host::new("booga.com", HTTP_PORT), }) .tunneled_host("blah") .build(), @@ -6294,7 +6191,7 @@ mod tests { let inbound_client_data_msg = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:4578").unwrap(), - reception_port: None, + reception_port_opt: None, last_data: true, is_clandestine: false, sequence_number: Some(123), @@ -6324,7 +6221,6 @@ mod tests { let args = TransmitToHopperArgs { main_cryptde: cryptde, payload, - return_route_id: 8888, client_addr: SocketAddr::from_str("1.2.3.4:1234").unwrap(), timestamp: SystemTime::now(), is_decentralized: false, @@ -6355,22 +6251,37 @@ mod tests { #[derive(Default)] struct ClientRequestPayloadFactoryMock { + make_params: Arc, Box, Logger)>>>, make_results: RefCell>>, } impl ClientRequestPayloadFactory for ClientRequestPayloadFactoryMock { fn make( &self, - _ibcd: &InboundClientData, - _stream_key: StreamKey, - _cryptde: &dyn CryptDE, - _logger: &Logger, + ibcd: &InboundClientData, + stream_key: StreamKey, + host_opt: Option, + cryptde: &dyn CryptDE, + logger: &Logger, ) -> Option { + self.make_params + .lock() + .unwrap() + .push((ibcd.clone(), stream_key, host_opt, cryptde.dup(), logger.clone())); self.make_results.borrow_mut().remove(0) } } impl ClientRequestPayloadFactoryMock { + fn new() -> Self { + Self::default() + } + + fn make_params(mut self, params: &Arc, Box, Logger)>>>) -> Self { + self.make_params = params.clone(); + self + } + fn make_result(self, result: Option) -> Self { self.make_results.borrow_mut().push(result); self @@ -6393,7 +6304,7 @@ mod tests { let inbound_client_data_msg = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:4578").unwrap(), - reception_port: Some(568), + reception_port_opt: Some(568), last_data: true, is_clandestine: false, sequence_number: Some(123), @@ -6427,7 +6338,7 @@ mod tests { vec![make_exit_service_from_key(destination_key.clone())], vec![], ), - hostname_opt: Some("booga.com".to_string()), + host: Host::new("booga.com", HTTP_PORT), })); let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); let stream_key = StreamKey::make_meaningless_stream_key(); @@ -6435,7 +6346,7 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port: Some(HTTP_PORT), + reception_port_opt: Some(HTTP_PORT), sequence_number: Some(0), last_data: true, is_clandestine: false, @@ -6445,6 +6356,7 @@ mod tests { .make( &msg_from_dispatcher, stream_key.clone(), + None, alias_cryptde, &Logger::new("test"), ) @@ -6504,7 +6416,7 @@ mod tests { vec![make_exit_service_from_key(destination_key.clone())], vec![], ), - hostname_opt: Some("booga.com".to_string()), + host: Host::new("booga.com", HTTP_PORT), })); let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); let stream_key = StreamKey::make_meaningless_stream_key(); @@ -6512,7 +6424,7 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port: Some(HTTP_PORT), + reception_port_opt: Some(HTTP_PORT), sequence_number: Some(0), last_data: true, is_clandestine: false, @@ -6522,6 +6434,7 @@ mod tests { .make( &msg_from_dispatcher, stream_key.clone(), + None, alias_cryptde, &Logger::new("test"), ) @@ -6646,7 +6559,7 @@ mod tests { let inbound_client_data_msg = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:4578").unwrap(), - reception_port: Some(80), + reception_port_opt: Some(80), last_data: true, is_clandestine: false, sequence_number: Some(123), @@ -6665,6 +6578,87 @@ mod tests { ); } + #[test] + fn make_payload_passes_no_hostname_if_none_is_known() { + let mut subject = ProxyServer::new( + main_cryptde(), + alias_cryptde(), + true, + Some(58), + false, + false, + ); + let make_params_arc = Arc::new(Mutex::new(vec![])); + let client_request_payload_factory = ClientRequestPayloadFactoryMock::new() + .make_params(&make_params_arc) + .make_result(None); + subject.client_request_payload_factory = Box::new(client_request_payload_factory); + let stream_key = StreamKey::make_meaningless_stream_key(); + // Do not create an entry in subject.stream_info for stream_key, so that no hostname is known + + let _ = subject.make_payload( + InboundClientData { // irrelevant + timestamp: SystemTime::now(), + client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), + reception_port_opt: Some(HTTP_PORT), + last_data: false, + is_clandestine: false, + sequence_number: Some(123), + data: vec![], + }, + &stream_key + ); + + let (_ibcd, _sk, hostname_opt, _cryptde, _logger) = &make_params_arc.lock().unwrap()[0]; + assert_eq!(hostname_opt, &None); + } + + #[test] + fn make_payload_passes_hostname_if_known() { + let mut subject = ProxyServer::new( + main_cryptde(), + alias_cryptde(), + true, + Some(58), + false, + false, + ); + let make_params_arc = Arc::new(Mutex::new(vec![])); + let client_request_payload_factory = ClientRequestPayloadFactoryMock::new() + .make_params(&make_params_arc) + .make_result(None); // Don't care about return value, only parameters + subject.client_request_payload_factory = Box::new(client_request_payload_factory); + let stream_key = StreamKey::make_meaningless_stream_key(); + let si_host = Host::new("knownhostname.com", 2345); + subject.stream_info.insert(stream_key.clone(), StreamInfo { + tunneled_host_opt: None, + dns_failure_retry_opt: None, + route_opt: Some(RouteQueryResponse { + route: Route { hops: vec![] }, + expected_services: ExpectedServices::RoundTrip(vec![], vec![]), + host: Host::new(&si_host.name, 2345), + }), + protocol_opt: None, + time_to_live_opt: None, + }); + + let _ = subject.make_payload( + InboundClientData { // irrelevant + timestamp: SystemTime::now(), + client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), + reception_port_opt: Some(HTTP_PORT), + last_data: false, + is_clandestine: false, + sequence_number: Some(123), + data: vec![], + }, + &stream_key + ); + + let (_ibcd, _sk, host_opt, _cryptde, _logger) = &make_params_arc.lock().unwrap()[0]; + assert_eq!(host_opt, &Some(si_host)); + } + #[test] #[should_panic( expected = "ProxyServer should never get ShutdownStreamMsg about clandestine stream" @@ -6707,7 +6701,7 @@ mod tests { let ibcd = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr, - reception_port: Some(2222), + reception_port_opt: Some(2222), last_data: true, is_clandestine: false, sequence_number: Some(333), @@ -6732,7 +6726,7 @@ mod tests { let ibcd = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr, - reception_port: Some(2222), + reception_port_opt: Some(2222), last_data: true, is_clandestine: false, sequence_number: Some(333), @@ -6748,22 +6742,27 @@ mod tests { ); } - #[test] - fn get_next_return_route_id_wraps_around() { - let mut mut_subject = - ProxyServer::new(main_cryptde(), alias_cryptde(), true, None, false, false); - mut_subject.next_return_route_id = Cell::new(0xFFFFFFFE); - let subject = mut_subject; - - let end_minus_one = subject.get_next_return_route_id(); - let end = subject.get_next_return_route_id(); - let beginning = subject.get_next_return_route_id(); - let beginning_plus_one = subject.get_next_return_route_id(); - - assert_eq!(end_minus_one, 0xFFFFFFFE); - assert_eq!(end, 0xFFFFFFFF); - assert_eq!(beginning, 0x00000000); - assert_eq!(beginning_plus_one, 0x00000001); + fn make_server_com_client_hello() -> Vec { + [ + 0x16, // content_type: Handshake + 0x00, 0x00, 0x00, 0x00, // version, length: don't care + 0x01, // handshake_type: ClientHello + 0x00, 0x00, 0x00, 0x00, 0x00, // length, version: don't care + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // random: don't care + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // random: don't care + 0x00, // session_id_length + 0x00, 0x00, // cipher_suites_length + 0x00, // compression_methods_length + 0x00, 0x13, // extensions_length + 0x00, 0x00, // extension_type: server_name + 0x00, 0x0F, // extension_length + 0x00, 0x0D, // server_name_list_length + 0x00, // server_name_type + 0x00, 0x0A, // server_name_length + b's', b'e', b'r', b'v', b'e', b'r', b'.', b'c', b'o', b'm', // server_name + ].to_vec() } fn make_exit_service_from_key(public_key: PublicKey) -> ExpectedService { diff --git a/node/src/proxy_server/protocol_pack.rs b/node/src/proxy_server/protocol_pack.rs index 9697ce6a22..7015358ed1 100644 --- a/node/src/proxy_server/protocol_pack.rs +++ b/node/src/proxy_server/protocol_pack.rs @@ -5,21 +5,7 @@ use crate::sub_lib::cryptde::PlainData; use crate::sub_lib::dispatcher::InboundClientData; use crate::sub_lib::proxy_server::ProxyProtocol; use masq_lib::constants::{HTTP_PORT, TLS_PORT}; - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct Host { - pub name: String, - pub port: u16, -} - -impl Host { - pub fn new(name: &str, port: u16) -> Host { - Host { - name: name.to_string(), - port, - } - } -} +use crate::sub_lib::host::Host; pub trait ProtocolPack: Send + Sync { fn proxy_protocol(&self) -> ProxyProtocol; @@ -44,7 +30,7 @@ pub fn from_standard_port(standard_port: u16) -> Option> { } pub fn from_ibcd(ibcd: &InboundClientData) -> Result, String> { - let origin_port = match ibcd.reception_port { + let origin_port = match ibcd.reception_port_opt { None => { return Err(format!( "No origin port specified with {}-byte non-clandestine packet: {:?}", @@ -67,6 +53,6 @@ pub fn from_ibcd(ibcd: &InboundClientData) -> Result, Stri pub trait ServerImpersonator { fn route_query_failure_response(&self, server_name: &str) -> Vec; - fn dns_resolution_failure_response(&self, server_name_opt: Option) -> Vec; + fn dns_resolution_failure_response(&self, server_name: String) -> Vec; fn consuming_wallet_absent(&self) -> Vec; } diff --git a/node/src/proxy_server/server_impersonator_http.rs b/node/src/proxy_server/server_impersonator_http.rs index 554741aaed..92c1f35610 100644 --- a/node/src/proxy_server/server_impersonator_http.rs +++ b/node/src/proxy_server/server_impersonator_http.rs @@ -19,11 +19,8 @@ impl ServerImpersonator for ServerImpersonatorHttp { ) } - fn dns_resolution_failure_response(&self, server_name_opt: Option) -> Vec { - let (server_name, quoted_server_name) = match &server_name_opt { - Some(name) => (name.clone(), format!("\"{}\"", name)), - None => ("".to_string(), "".to_string()), - }; + fn dns_resolution_failure_response(&self, server_name: String) -> Vec { + let (server_name, quoted_server_name) = (server_name.clone(), format!("\"{}\"", server_name)); ServerImpersonatorHttp::make_error_response( 503, "DNS Resolution Problem", @@ -197,7 +194,7 @@ mod tests { fn dns_resolution_failure_response_with_server_name_produces_expected_error_page() { let subject = ServerImpersonatorHttp {}; - let result = subject.dns_resolution_failure_response(Some("server.com".to_string())); + let result = subject.dns_resolution_failure_response("server.com".to_string()); let expected = ServerImpersonatorHttp::make_error_response( 503, @@ -208,21 +205,6 @@ mod tests { assert_eq!(expected, result); } - #[test] - fn dns_resolution_failure_response_without_server_name_produces_expected_error_page() { - let subject = ServerImpersonatorHttp {}; - - let result = subject.dns_resolution_failure_response(None); - - let expected = ServerImpersonatorHttp::make_error_response( - 503, - "DNS Resolution Problem", - "Exit Nodes couldn't resolve ", - "DNS Failure, We have tried multiple Exit Nodes and all have failed to resolve this address ", - ); - assert_eq!(expected, result); - } - #[test] fn consuming_wallet_absent_response_produces_expected_error_page() { let subject = ServerImpersonatorHttp {}; diff --git a/node/src/proxy_server/server_impersonator_tls.rs b/node/src/proxy_server/server_impersonator_tls.rs index 7a193a2699..3312be6569 100644 --- a/node/src/proxy_server/server_impersonator_tls.rs +++ b/node/src/proxy_server/server_impersonator_tls.rs @@ -8,7 +8,7 @@ impl ServerImpersonator for ServerImpersonatorTls { Vec::from(&TLS_INTERNAL_ERROR_ALERT[..]) } - fn dns_resolution_failure_response(&self, _server_name: Option) -> Vec { + fn dns_resolution_failure_response(&self, _server_name: String) -> Vec { Vec::from(&TLS_UNRECOGNIZED_NAME_ALERT[..]) } @@ -75,7 +75,7 @@ mod tests { fn dns_resolution_failure_response_produces_unrecognized_name_alert() { let subject = ServerImpersonatorTls {}; - let result = subject.dns_resolution_failure_response(None); + let result = subject.dns_resolution_failure_response("booga.com".to_string()); assert_eq!(Vec::from(&TLS_UNRECOGNIZED_NAME_ALERT[..]), result); } diff --git a/node/src/proxy_server/tls_protocol_pack.rs b/node/src/proxy_server/tls_protocol_pack.rs index d167ef0fa8..f348f339cd 100644 --- a/node/src/proxy_server/tls_protocol_pack.rs +++ b/node/src/proxy_server/tls_protocol_pack.rs @@ -1,11 +1,13 @@ // Copyright (c) 2019, MASQ (https://masq.ai) and/or its affiliates. All rights reserved. -use crate::proxy_server::protocol_pack::{Host, ProtocolPack, ServerImpersonator}; +use crate::proxy_server::protocol_pack::{ProtocolPack, ServerImpersonator}; use crate::proxy_server::server_impersonator_tls::ServerImpersonatorTls; use crate::sub_lib::binary_traverser::BinaryTraverser; use crate::sub_lib::cryptde::PlainData; use crate::sub_lib::proxy_server::ProxyProtocol; use masq_lib::constants::TLS_PORT; +use crate::sub_lib::host::Host; +#[derive(Clone, Copy)] pub struct TlsProtocolPack {} impl ProtocolPack for TlsProtocolPack { diff --git a/node/src/stream_handler_pool.rs b/node/src/stream_handler_pool.rs index 470f0c44f6..c9332d77bb 100644 --- a/node/src/stream_handler_pool.rs +++ b/node/src/stream_handler_pool.rs @@ -844,7 +844,7 @@ mod tests { let peer_addr = SocketAddr::from_str("1.2.3.4:80").unwrap(); let peer_addr_a = peer_addr.clone(); let local_addr = SocketAddr::from_str("1.2.3.5:80").unwrap(); - let reception_port = Some(8081); + let reception_port_opt = Some(8081); let is_clandestine = false; let one_http_req = b"GET http://here.com HTTP/1.1\r\n\r\n".to_vec(); let one_http_req_a = one_http_req.clone(); @@ -896,7 +896,7 @@ mod tests { .add_sub .try_send(AddStreamMsg::new( connection_info, // the stream splitter mock will return mocked reader/writer - reception_port, + reception_port_opt, PortConfiguration::new( vec![Box::new(HttpRequestDiscriminatorFactory::new())], is_clandestine, @@ -917,7 +917,7 @@ mod tests { &dispatcher::InboundClientData { timestamp: dispatcher_record.timestamp, client_addr: peer_addr_a, - reception_port, + reception_port_opt, last_data: false, is_clandestine, sequence_number: Some(0), @@ -931,7 +931,7 @@ mod tests { &dispatcher::InboundClientData { timestamp: dispatcher_record.timestamp, client_addr: peer_addr_a, - reception_port, + reception_port_opt, last_data: false, is_clandestine, sequence_number: Some(1), @@ -945,7 +945,7 @@ mod tests { &dispatcher::InboundClientData { timestamp: dispatcher_record.timestamp, client_addr: peer_addr_a, - reception_port, + reception_port_opt, last_data: false, is_clandestine, sequence_number: Some(2), @@ -958,7 +958,7 @@ mod tests { &dispatcher::StreamShutdownMsg { peer_addr: peer_addr_a, stream_type: RemovedStreamType::NonClandestine(NonClandestineAttributes { - reception_port: reception_port.unwrap(), + reception_port: reception_port_opt.unwrap(), sequence_number: 3 }), report_to_counterpart: true, @@ -1500,7 +1500,7 @@ mod tests { &InboundClientData { timestamp: ibcd.timestamp, client_addr: SocketAddr::from_str("1.2.3.5:7000").unwrap(), - reception_port: Some(54321), + reception_port_opt: Some(54321), last_data: false, is_clandestine: true, sequence_number: None, diff --git a/node/src/stream_reader.rs b/node/src/stream_reader.rs index cac9211a67..0cab540334 100644 --- a/node/src/stream_reader.rs +++ b/node/src/stream_reader.rs @@ -19,7 +19,7 @@ pub struct StreamReaderReal { stream: Box, local_addr: SocketAddr, peer_addr: SocketAddr, - reception_port: Option, + reception_port_opt: Option, ibcd_sub: Recipient, remove_sub: Recipient, dispatcher_stream_shutdown_sub: Recipient, @@ -86,7 +86,7 @@ impl StreamReaderReal { #[allow(clippy::too_many_arguments)] pub fn new( stream: Box, - reception_port: Option, + reception_port_opt: Option, ibcd_sub: Recipient, remove_sub: Recipient, dispatcher_sub: Recipient, @@ -107,7 +107,7 @@ impl StreamReaderReal { stream, local_addr, peer_addr, - reception_port, + reception_port_opt, ibcd_sub, remove_sub, dispatcher_stream_shutdown_sub: dispatcher_sub, @@ -162,7 +162,7 @@ impl StreamReaderReal { let msg = dispatcher::InboundClientData { timestamp: SystemTime::now(), client_addr: self.peer_addr, - reception_port: self.reception_port, + reception_port_opt: self.reception_port_opt, last_data: false, is_clandestine: self.is_clandestine, sequence_number, @@ -181,7 +181,7 @@ impl StreamReaderReal { } fn shutdown(&mut self) { - debug!(self.logger, "Directing removal of {}clandestine StreamReader with reception_port {:?} on {} listening to {}", if self.is_clandestine {""} else {"non-"}, self.reception_port, self.local_addr, self.peer_addr); + debug!(self.logger, "Directing removal of {}clandestine StreamReader with reception_port {:?} on {} listening to {}", if self.is_clandestine {""} else {"non-"}, self.reception_port_opt, self.local_addr, self.peer_addr); self.remove_sub .try_send(RemoveStreamMsg { peer_addr: self.peer_addr, @@ -190,7 +190,7 @@ impl StreamReaderReal { RemovedStreamType::Clandestine } else { RemovedStreamType::NonClandestine(NonClandestineAttributes { - reception_port: self.reception_port.expect( + reception_port: self.reception_port_opt.expect( "Non-clandestine StreamReader should always have a reception_port", ), sequence_number: self.sequencer.next_sequence_number(), @@ -511,7 +511,7 @@ mod tests { &dispatcher::InboundClientData { timestamp: d_record.timestamp, client_addr: peer_addr, - reception_port: Some(1234 as u16), + reception_port_opt: Some(1234 as u16), last_data: false, is_clandestine: true, sequence_number: Some(0), @@ -633,7 +633,7 @@ mod tests { &dispatcher::InboundClientData { timestamp: d_record.timestamp, client_addr: peer_addr, - reception_port: Some(1234 as u16), + reception_port_opt: Some(1234 as u16), last_data: false, is_clandestine: false, sequence_number: Some(0), @@ -648,7 +648,7 @@ mod tests { &dispatcher::InboundClientData { timestamp: d_record.timestamp, client_addr: peer_addr, - reception_port: Some(1234 as u16), + reception_port_opt: Some(1234 as u16), last_data: false, is_clandestine: false, sequence_number: Some(1), @@ -707,7 +707,7 @@ mod tests { &dispatcher::InboundClientData { timestamp: d_record.timestamp, client_addr, - reception_port: Some(1234 as u16), + reception_port_opt: Some(1234 as u16), last_data: false, is_clandestine: true, sequence_number: None, diff --git a/node/src/sub_lib/dispatcher.rs b/node/src/sub_lib/dispatcher.rs index 66e349e112..6ad7678b19 100644 --- a/node/src/sub_lib/dispatcher.rs +++ b/node/src/sub_lib/dispatcher.rs @@ -116,7 +116,7 @@ pub enum DispatcherError { pub struct InboundClientData { pub timestamp: SystemTime, pub client_addr: SocketAddr, - pub reception_port: Option, + pub reception_port_opt: Option, pub last_data: bool, pub is_clandestine: bool, pub sequence_number: Option, @@ -130,7 +130,7 @@ impl Debug for InboundClientData { Err(_) => self.data.hex_dump().to_string(), }; write!(f, "InboundClientData {{ peer_addr: {:?}, reception_port: {:?}, last_data: {}, sequence_number: {:?}, {} bytes of data: {} }}", - self.client_addr, self.reception_port, self.last_data, self.sequence_number, self.data.len(), data_string) + self.client_addr, self.reception_port_opt, self.last_data, self.sequence_number, self.data.len(), data_string) } } @@ -139,7 +139,7 @@ impl InboundClientData { InboundClientData { timestamp: SystemTime::now(), client_addr: self.client_addr, - reception_port: self.reception_port, + reception_port_opt: self.reception_port_opt, last_data: self.last_data, is_clandestine: self.is_clandestine, sequence_number: self.sequence_number, @@ -274,7 +274,7 @@ mod tests { let subject = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.4.3.2:9999").unwrap(), - reception_port: None, + reception_port_opt: None, last_data: false, is_clandestine: false, sequence_number: None, @@ -289,7 +289,7 @@ mod tests { let subject = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.4.3.2:9999").unwrap(), - reception_port: None, + reception_port_opt: None, last_data: false, is_clandestine: false, sequence_number: None, @@ -304,7 +304,7 @@ mod tests { let subject = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.4.3.2:9999").unwrap(), - reception_port: None, + reception_port_opt: None, last_data: false, is_clandestine: false, sequence_number: None, diff --git a/node/src/sub_lib/host.rs b/node/src/sub_lib/host.rs new file mode 100644 index 0000000000..49276e2957 --- /dev/null +++ b/node/src/sub_lib/host.rs @@ -0,0 +1,39 @@ +use std::fmt::Display; + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Host { + pub name: String, + pub port: u16, +} + +impl Display for Host { + fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + write!(f, "{}:{}", self.name, self.port) + } +} + +impl Host { + pub fn new(name: &str, port: u16) -> Host { + Host { + name: name.to_string(), + port, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn display() { + let subject = Host { + name: "example.com".to_string(), + port: 8080, + }; + + let result = format!("{}", subject); + + assert_eq!(result, "example.com:8080".to_string()); + } +} \ No newline at end of file diff --git a/node/src/sub_lib/migrations/client_request_payload.rs b/node/src/sub_lib/migrations/client_request_payload.rs index 2bd9993f5d..460ccce10d 100644 --- a/node/src/sub_lib/migrations/client_request_payload.rs +++ b/node/src/sub_lib/migrations/client_request_payload.rs @@ -49,7 +49,7 @@ impl TryFrom<&Value> for ClientRequestPayload_0v1 { Value::Map(map) => { let mut stream_key_opt: Option = None; let mut sequenced_packet_opt: Option = None; - let mut target_hostname_opt: Option> = None; + let mut target_hostname: Option = None; let mut target_port_opt: Option = None; let mut protocol_opt: Option = None; let mut originator_public_key_opt: Option = None; @@ -62,7 +62,7 @@ impl TryFrom<&Value> for ClientRequestPayload_0v1 { sequenced_packet_opt = value_to_type::(v) } "target_hostname" => { - target_hostname_opt = value_to_type::>(v) + target_hostname = value_to_type::(v) } "target_port" => target_port_opt = value_to_type::(v), "protocol" => protocol_opt = value_to_type::(v), @@ -89,7 +89,7 @@ impl TryFrom<&Value> for ClientRequestPayload_0v1 { "sequenced_packet", &sequenced_packet_opt, ); - check_field(&mut missing_fields, "target_hostname", &target_hostname_opt); + check_field(&mut missing_fields, "target_hostname", &target_hostname); check_field(&mut missing_fields, "target_port", &target_port_opt); check_field(&mut missing_fields, "protocol", &protocol_opt); check_field( @@ -103,7 +103,7 @@ impl TryFrom<&Value> for ClientRequestPayload_0v1 { Ok(ClientRequestPayload_0v1 { stream_key: stream_key_opt.expect("stream_key disappeared"), sequenced_packet: sequenced_packet_opt.expect("sequenced_packet disappeared"), - target_hostname: target_hostname_opt.expect("target_hostname disappeared"), + target_hostname: target_hostname.expect("target_hostname disappeared"), target_port: target_port_opt.expect("target_port disappeared"), protocol: protocol_opt.expect("protocol disappeared"), originator_public_key: originator_public_key_opt @@ -131,7 +131,7 @@ mod tests { struct ExampleFutureCRP { pub stream_key: StreamKey, pub sequenced_packet: SequencedPacket, - pub target_hostname: Option, + pub target_hostname: String, pub target_port: u16, pub protocol: ProxyProtocol, pub originator_public_key: PublicKey, @@ -141,7 +141,7 @@ mod tests { let expected_crp = ClientRequestPayload_0v1 { stream_key: StreamKey::make_meaningful_stream_key("All Things Must Pass"), sequenced_packet: SequencedPacket::new(vec![4, 3, 2, 1], 4321, false), - target_hostname: Some("target.hostname.com".to_string()), + target_hostname: "target.hostname.com".to_string(), target_port: 1234, protocol: ProxyProtocol::HTTP, originator_public_key: PublicKey::new(&[2, 3, 4, 5]), diff --git a/node/src/sub_lib/mod.rs b/node/src/sub_lib/mod.rs index 51360357bc..4c1a76fce9 100644 --- a/node/src/sub_lib/mod.rs +++ b/node/src/sub_lib/mod.rs @@ -21,6 +21,7 @@ pub mod framer; pub mod framer_utils; pub mod hop; pub mod hopper; +pub mod host; pub mod http_packet_framer; pub mod http_response_start_finder; pub mod limiter; diff --git a/node/src/sub_lib/neighborhood.rs b/node/src/sub_lib/neighborhood.rs index e30310df71..d2755363d4 100644 --- a/node/src/sub_lib/neighborhood.rs +++ b/node/src/sub_lib/neighborhood.rs @@ -31,6 +31,7 @@ use std::fmt::{Debug, Display, Formatter}; use std::net::IpAddr; use std::str::FromStr; use std::time::Duration; +use crate::sub_lib::host::Host; const ASK_ABOUT_GOSSIP_INTERVAL: Duration = Duration::from_secs(10); @@ -473,7 +474,7 @@ pub struct RouteQueryMessage { pub target_component: Component, pub return_component_opt: Option, pub payload_size: usize, - pub hostname_opt: Option, + pub host: Host, } impl Message for RouteQueryMessage { @@ -482,7 +483,7 @@ impl Message for RouteQueryMessage { impl RouteQueryMessage { pub fn data_indefinite_route_request( - hostname_opt: Option, + host: Host, payload_size: usize, ) -> RouteQueryMessage { RouteQueryMessage { @@ -490,7 +491,7 @@ impl RouteQueryMessage { target_component: Component::ProxyClient, return_component_opt: Some(Component::ProxyServer), payload_size, - hostname_opt, + host, } } } @@ -548,7 +549,7 @@ pub enum ExpectedServices { pub struct RouteQueryResponse { pub route: Route, pub expected_services: ExpectedServices, - pub hostname_opt: Option, + pub host: Host, } #[derive(Clone, Debug, Message, PartialEq, Eq)] @@ -1089,7 +1090,7 @@ mod tests { #[test] fn data_indefinite_route_request() { - let result = RouteQueryMessage::data_indefinite_route_request(None, 7500); + let result = RouteQueryMessage::data_indefinite_route_request(Host::new("booga.com", 1234), 7500); assert_eq!( result, @@ -1098,7 +1099,7 @@ mod tests { target_component: Component::ProxyClient, return_component_opt: Some(Component::ProxyServer), payload_size: 7500, - hostname_opt: None, + host: Host::new("booga.com", 1234), } ); } diff --git a/node/src/sub_lib/proxy_server.rs b/node/src/sub_lib/proxy_server.rs index 97b541b25b..c7b0ab49ce 100644 --- a/node/src/sub_lib/proxy_server.rs +++ b/node/src/sub_lib/proxy_server.rs @@ -34,7 +34,7 @@ pub enum ProxyProtocol { pub struct ClientRequestPayload_0v1 { pub stream_key: StreamKey, pub sequenced_packet: SequencedPacket, - pub target_hostname: Option, + pub target_hostname: String, pub target_port: u16, pub protocol: ProxyProtocol, pub originator_public_key: PublicKey, diff --git a/node/src/test_utils/mod.rs b/node/src/test_utils/mod.rs index 148c18a21d..24c0285bef 100644 --- a/node/src/test_utils/mod.rs +++ b/node/src/test_utils/mod.rs @@ -62,6 +62,8 @@ use std::thread; use std::time::Duration; use std::time::Instant; use web3::types::{Address, U256}; +use masq_lib::constants::{HTTP_PORT, TLS_PORT}; +use crate::sub_lib::host::Host; lazy_static! { static ref MAIN_CRYPTDE_NULL: Box = @@ -214,25 +216,26 @@ pub fn make_meaningless_wallet_private_key() -> PlainData { } // TODO: The three functions below should use only one argument, cryptde -pub fn route_to_proxy_client(main_key: &PublicKey, main_cryptde: &dyn CryptDE) -> Route { +pub fn route_to_proxy_client(main_key: &PublicKey, main_cryptde: &dyn CryptDE, tls: bool) -> Route { shift_one_hop( - zero_hop_route_response(main_key, main_cryptde).route, + zero_hop_route_response(main_key, main_cryptde, tls).route, main_cryptde, ) } -pub fn route_from_proxy_client(key: &PublicKey, cryptde: &dyn CryptDE) -> Route { +pub fn route_from_proxy_client(key: &PublicKey, cryptde: &dyn CryptDE, tls: bool) -> Route { // Happens to be the same - route_to_proxy_client(key, cryptde) + route_to_proxy_client(key, cryptde, tls) } -pub fn route_to_proxy_server(key: &PublicKey, cryptde: &dyn CryptDE) -> Route { - shift_one_hop(route_from_proxy_client(key, cryptde), cryptde) +pub fn route_to_proxy_server(key: &PublicKey, cryptde: &dyn CryptDE, tls: bool) -> Route { + shift_one_hop(route_from_proxy_client(key, cryptde, tls), cryptde) } pub fn zero_hop_route_response( public_key: &PublicKey, cryptde: &dyn CryptDE, + tls: bool, ) -> RouteQueryResponse { RouteQueryResponse { route: Route::round_trip( @@ -248,7 +251,7 @@ pub fn zero_hop_route_response( vec![ExpectedService::Nothing, ExpectedService::Nothing], vec![ExpectedService::Nothing, ExpectedService::Nothing], ), - hostname_opt: None, + host: Host::new("booga.com", if tls { TLS_PORT } else { HTTP_PORT }), } } @@ -713,7 +716,7 @@ pub mod unshared_test_utils { ClientRequestPayload_0v1 { stream_key: StreamKey::make_meaningful_stream_key("request"), sequenced_packet: SequencedPacket::new(make_garbage_data(bytes), 0, true), - target_hostname: Some("www.example.com".to_string()), + target_hostname: "www.example.com".to_string(), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: cryptde.public_key().clone(), @@ -1246,7 +1249,7 @@ mod tests { let cryptde = main_cryptde(); let key = cryptde.public_key(); - let subject = zero_hop_route_response(&key, cryptde); + let subject = zero_hop_route_response(&key, cryptde, false); assert_eq!( subject.route.hops, @@ -1277,7 +1280,7 @@ mod tests { let cryptde = main_cryptde(); let key = cryptde.public_key(); - let subject = route_to_proxy_client(&key, cryptde); + let subject = route_to_proxy_client(&key, cryptde, false); let mut garbage_can: Vec = iter::repeat(0u8).take(96).collect(); cryptde.random(&mut garbage_can[..]); @@ -1301,7 +1304,7 @@ mod tests { let cryptde = main_cryptde(); let key = cryptde.public_key(); - let subject = route_from_proxy_client(&key, cryptde); + let subject = route_from_proxy_client(&key, cryptde, false); let mut garbage_can: Vec = iter::repeat(0u8).take(96).collect(); cryptde.random(&mut garbage_can[..]); @@ -1325,7 +1328,7 @@ mod tests { let cryptde = main_cryptde(); let key = cryptde.public_key(); - let subject = route_to_proxy_server(&key, cryptde); + let subject = route_to_proxy_server(&key, cryptde, false); let mut first_garbage_can: Vec = iter::repeat(0u8).take(96).collect(); let mut second_garbage_can: Vec = iter::repeat(0u8).take(96).collect(); From 7791bb32d1d766321e15cb46e2543d08ad2b4258 Mon Sep 17 00:00:00 2001 From: Dan Wiebe Date: Thu, 9 Oct 2025 21:41:49 -0400 Subject: [PATCH 20/21] RRIDs are completely gone; hostnames are mandatory. --- .../tests/connection_termination_test.rs | 18 ++--- node/src/hopper/live_cores_package.rs | 8 +- node/src/proxy_client/stream_handler_pool.rs | 65 --------------- .../client_request_payload_factory.rs | 4 +- node/src/proxy_server/mod.rs | 40 ++++------ node/src/sub_lib/route.rs | 79 +------------------ node/src/test_utils/mod.rs | 15 +--- 7 files changed, 29 insertions(+), 200 deletions(-) diff --git a/multinode_integration_tests/tests/connection_termination_test.rs b/multinode_integration_tests/tests/connection_termination_test.rs index b015c9da94..125b3bef95 100644 --- a/multinode_integration_tests/tests/connection_termination_test.rs +++ b/multinode_integration_tests/tests/connection_termination_test.rs @@ -34,6 +34,7 @@ use std::io; use std::net::SocketAddr; use std::str::FromStr; use std::time::Duration; +use masq_lib::constants::HTTP_PORT; const HTTP_REQUEST: &[u8] = b"GET / HTTP/1.1\r\nHost: booga.com\r\n\r\n"; const HTTP_RESPONSE: &[u8] = @@ -361,14 +362,13 @@ fn create_request_icp( originating_node.consuming_wallet(), Some(chain.rec().contract), ) - .unwrap() - .set_return_route_id(originating_main_cryptde, 0), + .unwrap(), MessageType::ClientRequest(VersionedData::new( &node_lib::sub_lib::migrations::client_request_payload::MIGRATIONS, &ClientRequestPayload_0v1 { stream_key, sequenced_packet: SequencedPacket::new(Vec::from(HTTP_REQUEST), index, false), - target_hostname: Some(format!("{}", server.local_addr().ip())), + target_hostname: format!("{}", server.local_addr().ip()), target_port: server.local_addr().port(), protocol: ProxyProtocol::HTTP, originator_public_key: originating_node.main_public_key().clone(), @@ -414,7 +414,7 @@ fn create_meaningless_icp( &ClientRequestPayload_0v1 { stream_key, sequenced_packet: SequencedPacket::new(Vec::from(HTTP_REQUEST), 0, false), - target_hostname: Some("nowhere.com".to_string()), + target_hostname: "nowhere.com".to_string(), target_port: socket_addr.port(), protocol: ProxyProtocol::HTTP, originator_public_key: originating_node.main_public_key().clone(), @@ -451,8 +451,7 @@ fn create_server_drop_report( originating_node.consuming_wallet(), Some(TEST_DEFAULT_MULTINODE_CHAIN.rec().contract), ) - .unwrap() - .set_return_route_id(originating_main_cryptde, 0); + .unwrap(); route.shift(originating_main_cryptde).unwrap(); let payload = MessageType::ClientResponse(VersionedData::new( &node_lib::sub_lib::migrations::client_response_payload::MIGRATIONS, @@ -496,15 +495,14 @@ fn create_client_drop_report( originating_node.consuming_wallet(), Some(TEST_DEFAULT_MULTINODE_CHAIN.rec().contract), ) - .unwrap() - .set_return_route_id(originating_main_cryptde, 0); + .unwrap(); let payload = MessageType::ClientRequest(VersionedData::new( &node_lib::sub_lib::migrations::client_request_payload::MIGRATIONS, &ClientRequestPayload_0v1 { stream_key, sequenced_packet: SequencedPacket::new(vec![], 1, true), - target_hostname: Some(String::from("doesnt.matter.com")), - target_port: 80, + target_hostname: String::from("doesnt.matter.com"), + target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: originating_node.main_public_key().clone(), }, diff --git a/node/src/hopper/live_cores_package.rs b/node/src/hopper/live_cores_package.rs index 01f1d57933..001ddd5ff5 100644 --- a/node/src/hopper/live_cores_package.rs +++ b/node/src/hopper/live_cores_package.rs @@ -306,7 +306,7 @@ mod tests { let encrypted_payload = encodex(cryptde, &first_stop_key, &payload).unwrap(); let paying_wallet = make_paying_wallet(b"wallet"); let contract_address = TEST_DEFAULT_CHAIN.rec().contract; - let route = Route::round_trip( + let mut route = Route::round_trip( RouteSegment::new(vec![&relay_key, &first_stop_key], Component::Neighborhood), RouteSegment::new( vec![&first_stop_key, &relay_key, &second_stop_key], @@ -317,7 +317,6 @@ mod tests { Some(contract_address), ) .unwrap(); - let mut route = route.set_return_route_id(cryptde, 1234); route.shift(&relay_cryptde).unwrap(); let subject = LiveCoresPackage::new(route.clone(), encrypted_payload.clone()); @@ -373,11 +372,6 @@ mod tests { Component::ProxyServer, ) ); - assert_eq!( - route.hops[0], - crate::test_utils::encrypt_return_route_id(1234, cryptde), - ); - route.hops.remove(0); assert_eq!( &route.hops[0].as_slice()[..8], &[52, 52, 52, 52, 52, 52, 52, 52] diff --git a/node/src/proxy_client/stream_handler_pool.rs b/node/src/proxy_client/stream_handler_pool.rs index 18d343e417..3910536e1b 100644 --- a/node/src/proxy_client/stream_handler_pool.rs +++ b/node/src/proxy_client/stream_handler_pool.rs @@ -1153,71 +1153,6 @@ mod tests { ); } - #[test] - fn missing_hostname_for_nonexistent_stream_generates_log_and_termination_message() { - init_test_logging(); - let test_name = - "missing_hostname_for_nonexistent_stream_generates_log_and_termination_message"; - let cryptde = main_cryptde(); - let (proxy_client, proxy_client_awaiter, proxy_client_recording_arc) = make_recorder(); - let originator_key = PublicKey::new(&b"men's souls"[..]); - let stream_key = StreamKey::make_meaningful_stream_key(test_name); - thread::spawn(move || { - let peer_actors = peer_actors_builder().proxy_client(proxy_client).build(); - let client_request_payload = ClientRequestPayload_0v1 { - stream_key: stream_key.clone(), - sequenced_packet: SequencedPacket { - data: b"These are the times".to_vec(), - sequence_number: 0, - last_data: false, - }, - target_hostname: "booga.com".to_string(), - target_port: HTTP_PORT, - protocol: ProxyProtocol::HTTP, - originator_public_key: originator_key, - }; - let package = ExpiredCoresPackage::new( - SocketAddr::from_str("1.2.3.4:1234").unwrap(), - Some(make_wallet("consuming")), - make_meaningless_route(), - client_request_payload.into(), - 0, - ); - let resolver = - ResolverWrapperMock::new().lookup_ip_failure(ResolveErrorKind::Io.into()); - let subject = StreamHandlerPoolReal::new( - Box::new(resolver), - cryptde, - peer_actors.accountant.report_exit_service_provided.clone(), - peer_actors.proxy_client_opt.unwrap().clone(), - 100, - 200, - ); - - run_process_package_in_actix(subject, package); - }); - - proxy_client_awaiter.await_message_count(1); - let proxy_client_recording = proxy_client_recording_arc.lock().unwrap(); - assert_eq!( - proxy_client_recording.get_record::(0), - &InboundServerData { - stream_key: stream_key.clone(), - last_data: true, - sequence_number: 0, - source: error_socket_addr(), - data: vec![], - } - ); - TestLogHandler::new().exists_log_containing( - format!( - "ERROR: ProxyClient: Cannot open new stream with key {:?}: no hostname supplied", - stream_key - ) - .as_str(), - ); - } - #[test] fn nonexistent_connection_springs_into_being_and_is_persisted_to_handle_transaction() { let cryptde = main_cryptde(); diff --git a/node/src/proxy_server/client_request_payload_factory.rs b/node/src/proxy_server/client_request_payload_factory.rs index 6f0b38423a..aff775d1c9 100644 --- a/node/src/proxy_server/client_request_payload_factory.rs +++ b/node/src/proxy_server/client_request_payload_factory.rs @@ -92,7 +92,7 @@ mod tests { use super::*; use crate::sub_lib::proxy_server::ProxyProtocol; use crate::test_utils::main_cryptde; - use masq_lib::constants::HTTP_PORT; + use masq_lib::constants::{HTTP_PORT, TLS_PORT}; use masq_lib::test_utils::logging::init_test_logging; use masq_lib::test_utils::logging::TestLogHandler; use std::net::SocketAddr; @@ -292,7 +292,7 @@ mod tests { last_data: false }, target_hostname: String::from("server.com"), - target_port: 443, + target_port: TLS_PORT, protocol: ProxyProtocol::TLS, originator_public_key: cryptde.public_key().clone(), }) diff --git a/node/src/proxy_server/mod.rs b/node/src/proxy_server/mod.rs index 69a1810603..68df5da3e2 100644 --- a/node/src/proxy_server/mod.rs +++ b/node/src/proxy_server/mod.rs @@ -957,14 +957,9 @@ impl ProxyServer { let payload = args.payload; let payload_size = payload.sequenced_packet.data.len(); let stream_key = payload.stream_key; - // TODO: This return route ID is completely unnecessary, except that unenlightened - // Nodes are expecting it, so we have to put it in. We should make it random garbage - // instead of 0. - let route_with_return_route_id = - route.set_return_route_id(args.main_cryptde, 0); let pkg = IncipientCoresPackage::new( args.main_cryptde, - route_with_return_route_id, + route, payload.into(), &payload_destination_key, ) @@ -1879,7 +1874,7 @@ mod tests { }; let expected_pkg = IncipientCoresPackage::new( main_cryptde, - route.clone().set_return_route_id(main_cryptde, 0), + route.clone(), expected_payload.into(), &destination_key, ) @@ -1999,13 +1994,13 @@ mod tests { last_data: false, }, target_hostname: String::from("realdomain.nu"), - target_port: 443, + target_port: TLS_PORT, protocol: ProxyProtocol::TLS, originator_public_key: alias_cryptde.public_key().clone(), }; let expected_pkg = IncipientCoresPackage::new( main_cryptde, - route.clone().set_return_route_id(main_cryptde, 0), + route.clone(), expected_payload.into(), &destination_key, ) @@ -2486,7 +2481,7 @@ mod tests { hopper_recording.get_record::(0), &IncipientCoresPackage::new( main_cryptde, - expected_route.route.set_return_route_id(main_cryptde, 0), + expected_route.route, MessageType::ClientRequest(VersionedData::new( &crate::sub_lib::migrations::client_request_payload::MIGRATIONS, &ClientRequestPayload_0v1 { @@ -2562,7 +2557,7 @@ mod tests { hopper_recording.get_record::(0), &IncipientCoresPackage::new( main_cryptde, - expected_route.route.set_return_route_id(main_cryptde, 0), + expected_route.route, MessageType::ClientRequest(VersionedData::new( &crate::sub_lib::migrations::client_request_payload::MIGRATIONS, &ClientRequestPayload_0v1 { @@ -2626,7 +2621,7 @@ mod tests { }; let expected_pkg = IncipientCoresPackage::new( main_cryptde, - route.clone().set_return_route_id(main_cryptde, 0), + route.clone(), expected_payload.into(), &destination_key, ) @@ -2700,8 +2695,7 @@ mod tests { Some(consuming_wallet), Some(TEST_DEFAULT_CHAIN.rec().contract), ) - .unwrap() - .set_return_route_id(main_cryptde, 0); + .unwrap(); let (neighborhood_mock, _, neighborhood_recording_arc) = make_recorder(); let neighborhood_mock = neighborhood_mock.route_query_response(Some(RouteQueryResponse { route: route.clone(), @@ -2748,7 +2742,7 @@ mod tests { }; let expected_pkg = IncipientCoresPackage::new( main_cryptde, - route.clone().set_return_route_id(main_cryptde, 0), + route.clone(), expected_payload.into(), &payload_destination_key, ) @@ -2969,7 +2963,7 @@ mod tests { let http_request = b"GET /index.html HTTP/1.1\r\nHost: nowhere.com\r\n\r\n"; let destination_key = PublicKey::from(&b"our destination"[..]); let route = Route { hops: vec![] }; - let route_with_rrid = route.clone().set_return_route_id(main_cryptde, 0); + let route_with_rrid = route.clone(); let route_query_response = RouteQueryResponse { route, expected_services: ExpectedServices::RoundTrip( @@ -3195,7 +3189,6 @@ mod tests { TEST_DEFAULT_CHAIN, )); let _ = record.route.shift(cryptde); - assert_eq!(record.route.return_route_id(cryptde).unwrap(), 0); let recording = accountant_recording_arc.lock().unwrap(); let record = recording.get_record::(0); assert_eq!(recording.len(), 1); @@ -3605,8 +3598,7 @@ mod tests { None, None, ) - .unwrap() - .set_return_route_id(cryptde, 0), + .unwrap(), expected_services: ExpectedServices::RoundTrip(vec![], vec![]), host: Host::new("booga.com", HTTP_PORT), }; @@ -3703,7 +3695,7 @@ mod tests { data: expected_data.clone(), }; let expected_tls_request = PlainData::new(tls_request.as_slice()); - let route = Route { hops: vec![] }.set_return_route_id(main_cryptde, 0); + let route = Route { hops: vec![] }; let expected_payload = ClientRequestPayload_0v1 { stream_key: stream_key.clone(), sequenced_packet: SequencedPacket { @@ -3804,7 +3796,7 @@ mod tests { }; let expected_pkg = IncipientCoresPackage::new( main_cryptde, - route.clone().set_return_route_id(main_cryptde, 0), + route.clone(), expected_payload.into(), &destination_key, ) @@ -3902,7 +3894,7 @@ mod tests { }; let expected_pkg = IncipientCoresPackage::new( main_cryptde, - route.clone().set_return_route_id(main_cryptde, 0), + route.clone(), expected_payload.into(), &destination_key, ) @@ -5940,7 +5932,7 @@ mod tests { let record = recording.get_record::(0); assert_eq!( record.route, - affected_route.set_return_route_id(main_cryptde(), 0) + affected_route ); let payload = decodex::(&affected_cryptde, &record.payload).unwrap(); match payload { @@ -6067,7 +6059,7 @@ mod tests { let record = recording.get_record::(0); assert_eq!( record.route, - affected_route.set_return_route_id(main_cryptde(), 0) + affected_route ); let payload = decodex::(&affected_cryptde, &record.payload).unwrap(); match payload { diff --git a/node/src/sub_lib/route.rs b/node/src/sub_lib/route.rs index a9314d29e9..b51bbae303 100644 --- a/node/src/sub_lib/route.rs +++ b/node/src/sub_lib/route.rs @@ -1,5 +1,4 @@ // Copyright (c) 2019, MASQ (https://masq.ai) and/or its affiliates. All rights reserved. -use crate::sub_lib::cryptde::encodex; use crate::sub_lib::cryptde::CryptDE; use crate::sub_lib::cryptde::CryptData; use crate::sub_lib::cryptde::PublicKey; @@ -66,23 +65,6 @@ impl Route { ) } - pub fn return_route_id(&self, cryptde: &dyn CryptDE) -> Result { - if let Some(first) = self.hops.first() { - match decodex(cryptde, first) { - Ok(n) => Ok(n), - Err(e) => Err(format!("{:?}", e)), - } - } else { - Err("Response route did not contain a return route ID".to_string()) - } - } - - pub fn set_return_route_id(mut self, cryptde: &dyn CryptDE, return_route_id: u32) -> Self { - let return_route_id_enc = Self::encrypt_return_route_id(return_route_id, cryptde); - self.hops.push(return_route_id_enc); - self - } - // This cryptde must be the CryptDE of the next hop to come off the Route. pub fn next_hop(&self, cryptde: &dyn CryptDE) -> Result { match self.hops.first() { @@ -133,15 +115,7 @@ impl Route { last_cryptde.public_key(), live_hop ), - Err(outside) => match decodex::(last_cryptde, &last_hop_enc) { - Ok(return_route_id) => format!( - "{}\nEncrypted with {:?}: Return Route ID: {}\n", - most_strings, - last_cryptde.public_key(), - return_route_id - ), - Err(inside) => format!("{}\nError: {:?} / {:?}", most_strings, outside, inside), - }, + Err(error) => format!("{}\nError: {:?}", most_strings, error), } } @@ -304,11 +278,6 @@ impl Route { } Ok(Route { hops: hops_enc }) } - - fn encrypt_return_route_id(return_route_id: u32, cryptde: &dyn CryptDE) -> CryptData { - encodex(cryptde, cryptde.public_key(), &return_route_id) - .expect("Internal error encrypting u32 return_route_id") - } } #[derive(Debug)] @@ -343,41 +312,6 @@ mod tests { use masq_lib::test_utils::utils::TEST_DEFAULT_CHAIN; use serde_cbor; - #[test] - fn return_route_id_works() { - let cryptde = main_cryptde(); - - let subject = Route { - hops: vec![Route::encrypt_return_route_id(42, cryptde)], - }; - - assert_eq!(subject.return_route_id(cryptde), Ok(42)); - } - - #[test] - fn return_route_id_returns_empty_route_error_when_the_route_is_empty() { - let cryptde = main_cryptde(); - - let subject = Route { hops: vec![] }; - - assert_eq!( - subject.return_route_id(cryptde), - Err("Response route did not contain a return route ID".to_string()) - ); - } - - #[test] - #[should_panic(expected = "Could not decrypt with ebe5f9a0e2 data beginning with ebe5f9a0e1")] - fn return_route_id_returns_error_when_the_id_fails_to_decrypt() { - let cryptde1 = CryptDENull::from(&PublicKey::new(b"key a"), TEST_DEFAULT_CHAIN); - let cryptde2 = CryptDENull::from(&PublicKey::new(b"key b"), TEST_DEFAULT_CHAIN); - let subject = Route { - hops: vec![Route::encrypt_return_route_id(42, &cryptde1)], - }; - - let _ = subject.return_route_id(&cryptde2); - } - #[test] fn construct_does_not_like_route_segments_with_too_few_keys() { let cryptde = main_cryptde(); @@ -454,7 +388,6 @@ mod tests { let f_key = PublicKey::new(&[70, 70, 70]); let cryptde = main_cryptde(); let paying_wallet = make_paying_wallet(b"wallet"); - let return_route_id = 4321; let contract_address = TEST_DEFAULT_CHAIN.rec().contract; let subject = Route::round_trip( @@ -465,7 +398,6 @@ mod tests { Some(contract_address.clone()), ) .unwrap(); - let subject = subject.set_return_route_id(cryptde, return_route_id); assert_eq!( subject.hops[0], @@ -551,12 +483,6 @@ mod tests { .unwrap(), "seventh hop" ); - - assert_eq!( - subject.hops[7], - Route::encrypt_return_route_id(return_route_id, cryptde), - "eighth hop" - ); } #[test] @@ -738,7 +664,6 @@ mod tests { Some(TEST_DEFAULT_CHAIN.rec().contract), ) .unwrap(); - let original = original.set_return_route_id(cryptde, 1234); let serialized = serde_cbor::ser::to_vec(&original).unwrap(); @@ -794,7 +719,6 @@ Encrypted with 0x03040506: LiveHop { public_key: 0x, payer: Some(Payer { wallet: Some(TEST_DEFAULT_CHAIN.rec().contract), ) .unwrap(); - let subject = subject.set_return_route_id(&cryptde, 1234); let result = subject.to_string(vec![ &CryptDENull::from(&key1, TEST_DEFAULT_CHAIN), @@ -814,7 +738,6 @@ Encrypted with 0x02030405: LiveHop { public_key: 0x03040506, payer: Some(Payer { Encrypted with 0x03040506: LiveHop { public_key: 0x02030405, payer: Some(Payer { wallet: Wallet { kind: Address(0x71d0fc7d1c570b1ed786382b551a09391c91e33d) }, proof: Signature { v: 1, r: "8649b8f6db6232cb1e4f1f04786ad4ef33488c968e64bec74ecd893d6d05c1b9", s: "8649b8f6db6232cb1e4f1f04786ad4ef33488c968e64bec74ecd893d6d05c1b9" } }), component: ProxyClient } Encrypted with 0x02030405: LiveHop { public_key: 0x01020304, payer: Some(Payer { wallet: Wallet { kind: Address(0x71d0fc7d1c570b1ed786382b551a09391c91e33d) }, proof: Signature { v: 0, r: "4324a40295bb36ef2b927fb24250fe42397a57b861ea152bbbe4f84150d4ff5a", s: "4324a40295bb36ef2b927fb24250fe42397a57b861ea152bbbe4f84150d4ff5a" } }), component: Hopper } Encrypted with 0x01020304: LiveHop { public_key: 0x, payer: Some(Payer { wallet: Wallet { kind: Address(0x71d0fc7d1c570b1ed786382b551a09391c91e33d) }, proof: Signature { v: 0, r: "3e3a92d7284c2c2ff7119e9f7a7e183b062a335a598e965a47c36a2f288b6f8d", s: "3e3a92d7284c2c2ff7119e9f7a7e183b062a335a598e965a47c36a2f288b6f8d" } }), component: ProxyServer } -Encrypted with 0x01020304: Return Route ID: 1234 "# ) ); diff --git a/node/src/test_utils/mod.rs b/node/src/test_utils/mod.rs index 24c0285bef..58e2ff0bcf 100644 --- a/node/src/test_utils/mod.rs +++ b/node/src/test_utils/mod.rs @@ -21,7 +21,6 @@ use crate::blockchain::bip32::Bip32EncryptionKeyProvider; use crate::blockchain::payer::Payer; use crate::bootstrapper::CryptDEPair; use crate::sub_lib::cryptde::CryptDE; -use crate::sub_lib::cryptde::CryptData; use crate::sub_lib::cryptde::PlainData; use crate::sub_lib::cryptde::PublicKey; use crate::sub_lib::cryptde_null::CryptDENull; @@ -245,8 +244,7 @@ pub fn zero_hop_route_response( None, None, ) - .unwrap() - .set_return_route_id(cryptde, 0), + .unwrap(), expected_services: ExpectedServices::RoundTrip( vec![ExpectedService::Nothing, ExpectedService::Nothing], vec![ExpectedService::Nothing, ExpectedService::Nothing], @@ -260,13 +258,6 @@ fn shift_one_hop(mut route: Route, cryptde: &dyn CryptDE) -> Route { route } -pub fn encrypt_return_route_id(return_route_id: u32, cryptde: &dyn CryptDE) -> CryptData { - let return_route_id_ser = serde_cbor::ser::to_vec(&return_route_id).unwrap(); - cryptde - .encode(cryptde.public_key(), &PlainData::from(return_route_id_ser)) - .unwrap() -} - pub fn make_garbage_data(bytes: usize) -> Vec { let mut data = vec![0; bytes]; rand::thread_rng().fill_bytes(&mut data); @@ -1263,7 +1254,6 @@ mod tests { LiveHop::new(&PublicKey::new(b""), None, Component::ProxyServer) .encode(&key, cryptde) .unwrap(), - encrypt_return_route_id(0, cryptde), ) ); assert_eq!( @@ -1293,7 +1283,6 @@ mod tests { LiveHop::new(&PublicKey::new(b""), None, Component::ProxyServer) .encode(&key, cryptde) .unwrap(), - encrypt_return_route_id(0, cryptde), CryptData::new(&garbage_can[..]) ) ); @@ -1317,7 +1306,6 @@ mod tests { LiveHop::new(&PublicKey::new(b""), None, Component::ProxyServer) .encode(&key, cryptde) .unwrap(), - encrypt_return_route_id(0, cryptde), CryptData::new(&garbage_can[..]) ) ); @@ -1340,7 +1328,6 @@ mod tests { LiveHop::new(&PublicKey::new(b""), None, Component::ProxyServer) .encode(&key, cryptde) .unwrap(), - encrypt_return_route_id(0, cryptde), CryptData::new(&first_garbage_can[..]), CryptData::new(&second_garbage_can[..]), ) From 42b055a61382578d80238d78af5095551e2d3181 Mon Sep 17 00:00:00 2001 From: Dan Wiebe Date: Fri, 10 Oct 2025 23:09:31 -0400 Subject: [PATCH 21/21] MOre review issues --- node/src/neighborhood/mod.rs | 63 +++++++++++++----------------------- node/src/proxy_server/mod.rs | 40 ++++++++++------------- 2 files changed, 40 insertions(+), 63 deletions(-) diff --git a/node/src/neighborhood/mod.rs b/node/src/neighborhood/mod.rs index d25a307e38..355029a2e1 100644 --- a/node/src/neighborhood/mod.rs +++ b/node/src/neighborhood/mod.rs @@ -28,12 +28,14 @@ use crate::sub_lib::dispatcher::{Component, StreamShutdownMsg}; use crate::sub_lib::hopper::{ExpiredCoresPackage, NoLookupIncipientCoresPackage}; use crate::sub_lib::hopper::{IncipientCoresPackage, MessageType}; use crate::sub_lib::host::Host; +use crate::sub_lib::neighborhood::ConnectionProgressEvent; +use crate::sub_lib::neighborhood::ExpectedService::{Exit, Nothing, Routing}; +use crate::sub_lib::neighborhood::ExpectedServices::{OneWay, RoundTrip}; use crate::sub_lib::neighborhood::RouteQueryResponse; use crate::sub_lib::neighborhood::UpdateNodeRecordMetadataMessage; use crate::sub_lib::neighborhood::{AskAboutDebutGossipMessage, NodeDescriptor}; use crate::sub_lib::neighborhood::{ConfigChange, RemoveNeighborMessage}; use crate::sub_lib::neighborhood::{ConfigChangeMsg, RouteQueryMessage}; -use crate::sub_lib::neighborhood::{ConnectionProgressEvent, ExpectedServices}; use crate::sub_lib::neighborhood::{ConnectionProgressMessage, ExpectedService}; use crate::sub_lib::neighborhood::{DispatcherNodeQueryMessage, GossipFailure_0v1}; use crate::sub_lib::neighborhood::{Hops, NeighborhoodMetadata, NodeQueryResponseMetadata}; @@ -998,10 +1000,7 @@ impl Neighborhood { .expect("Couldn't create route"); RouteQueryResponse { route, - expected_services: ExpectedServices::RoundTrip( - vec![ExpectedService::Nothing, ExpectedService::Nothing], - vec![ExpectedService::Nothing, ExpectedService::Nothing], - ), + expected_services: RoundTrip(vec![Nothing, Nothing], vec![Nothing, Nothing]), host, } } @@ -1077,10 +1076,7 @@ impl Neighborhood { Some(self.chain.rec().contract), ) .expect("Internal error: bad route"), - expected_services: ExpectedServices::RoundTrip( - expected_request_services, - expected_response_services, - ), + expected_services: RoundTrip(expected_request_services, expected_response_services), host, }) } @@ -1141,20 +1137,20 @@ impl Neighborhood { match self.neighborhood_database.node_by_key(route_segment_key) { Some(node) => { if route_segment_key == self.neighborhood_database.root().public_key() { - Ok(ExpectedService::Nothing) + Ok(Nothing) } else { match (originator_key, exit_key) { (Some(originator_key), Some(exit_key)) if route_segment_key == originator_key || route_segment_key == exit_key => { - Ok(ExpectedService::Exit( + Ok(Exit( route_segment_key.clone(), node.earning_wallet(), *node.rate_pack(), )) } - (Some(_), Some(_)) => Ok(ExpectedService::Routing( + (Some(_), Some(_)) => Ok(Routing( route_segment_key.clone(), node.earning_wallet(), *node.rate_pack(), @@ -2175,6 +2171,7 @@ impl<'a> ComputedRouteSegment<'a> { #[cfg(test)] mod tests { + use super::*; use actix::Recipient; use actix::System; use itertools::Itertools; @@ -2201,7 +2198,6 @@ mod tests { use std::time::Duration; use std::time::Instant; use tokio::prelude::Future; - use ExpectedService::Exit; use crate::db_config::persistent_configuration::PersistentConfigError; use crate::neighborhood::gossip::Gossip_0v1; @@ -2255,8 +2251,6 @@ mod tests { ConnectionProgress, ConnectionStage, OverallConnectionStage, }; use crate::sub_lib::host::Host; - use crate::sub_lib::neighborhood::ExpectedService::{Nothing, Routing}; - use crate::sub_lib::neighborhood::ExpectedServices::RoundTrip; use crate::test_utils::unshared_test_utils::notify_handlers::NotifyLaterHandleMock; use masq_lib::test_utils::logging::{init_test_logging, TestLogHandler}; @@ -3169,7 +3163,7 @@ mod tests { } #[test] - pub fn progress_in_the_stage_of_overall_connection_status_made_by_one_cpm_is_not_overriden_by_the_other( + pub fn progress_in_the_stage_of_overall_connection_status_made_by_one_cpm_is_not_overridden_by_the_other( ) { let peer_1 = make_ip(1); let peer_2 = make_ip(2); @@ -3189,7 +3183,7 @@ mod tests { neighborhood_config, make_wallet("earning"), None, - "progress_in_the_stage_of_overall_connection_status_made_by_one_cpm_is_not_overriden_by_the_other"), + "progress_in_the_stage_of_overall_connection_status_made_by_one_cpm_is_not_overridden_by_the_other"), ); let (node_to_ui_recipient, _) = make_node_to_ui_recipient(); subject.node_to_ui_recipient_opt = Some(node_to_ui_recipient); @@ -3393,9 +3387,9 @@ mod tests { None, ) .unwrap(), - expected_services: ExpectedServices::RoundTrip( + expected_services: RoundTrip( vec![ - ExpectedService::Nothing, + Nothing, Exit( desirable_exit_node.public_key().clone(), desirable_exit_node.earning_wallet(), @@ -3408,7 +3402,7 @@ mod tests { desirable_exit_node.earning_wallet(), rate_pack(2345), ), - ExpectedService::Nothing, + Nothing, ], ), host: Host::new("booga.com", 1234), @@ -3467,10 +3461,7 @@ mod tests { None, ) .unwrap(), - expected_services: ExpectedServices::RoundTrip( - vec![ExpectedService::Nothing, ExpectedService::Nothing], - vec![ExpectedService::Nothing, ExpectedService::Nothing], - ), + expected_services: RoundTrip(vec![Nothing, Nothing], vec![Nothing, Nothing]), host: Host::new("google.com", 1234), }; assert_eq!(result, expected_response); @@ -3540,24 +3531,16 @@ mod tests { Some(contract_address), ) .unwrap(), - expected_services: ExpectedServices::RoundTrip( + expected_services: RoundTrip( vec![ - ExpectedService::Nothing, - ExpectedService::Routing( - q.public_key().clone(), - q.earning_wallet(), - rate_pack(3456), - ), + Nothing, + Routing(q.public_key().clone(), q.earning_wallet(), rate_pack(3456)), Exit(r.public_key().clone(), r.earning_wallet(), rate_pack(4567)), ], vec![ Exit(r.public_key().clone(), r.earning_wallet(), rate_pack(4567)), - ExpectedService::Routing( - q.public_key().clone(), - q.earning_wallet(), - rate_pack(3456), - ), - ExpectedService::Nothing, + Routing(q.public_key().clone(), q.earning_wallet(), rate_pack(3456)), + Nothing, ], ), host: Host::new("booga.com", 1234), @@ -7199,11 +7182,11 @@ mod tests { .unwrap(); let (over, back) = match response.expected_services { - ExpectedServices::OneWay(_) => panic!("Expecting RoundTrip"), - ExpectedServices::RoundTrip(o, b) => (o[1].clone(), b[1].clone()), + OneWay(_) => panic!("Expecting RoundTrip"), + RoundTrip(o, b) => (o[1].clone(), b[1].clone()), }; let extract_key = |es: ExpectedService| match es { - ExpectedService::Routing(pk, _, _) => pk, + Routing(pk, _, _) => pk, x => panic!("Expecting Routing, found {:?}", x), }; let expected_relay_key = if a_not_b { a.clone() } else { b.clone() }; diff --git a/node/src/proxy_server/mod.rs b/node/src/proxy_server/mod.rs index a926ad3450..491cb11118 100644 --- a/node/src/proxy_server/mod.rs +++ b/node/src/proxy_server/mod.rs @@ -58,8 +58,6 @@ use std::time::{Duration, SystemTime}; use tokio::prelude::Future; pub const CRASH_KEY: &str = "PROXYSERVER"; -pub const RETURN_ROUTE_TTL_FIRST_CHANCE: Duration = Duration::from_secs(120); -pub const RETURN_ROUTE_TTL_STRAGGLERS: Duration = Duration::from_secs(5); pub const STREAM_KEY_PURGE_DELAY: Duration = Duration::from_secs(30); pub const DNS_FAILURE_RETRIES: usize = 3; @@ -94,11 +92,6 @@ pub struct ProxyServer { cryptde_pair: CryptDEPair, crashable: bool, logger: Logger, - // // Holds return-route information for requests that have not yet seen any responses - // route_ids_to_return_routes_first_chance: TtlHashMap, - // // Holds return-route information for requests that have seen at least one response and may - // // see more in the future. The near future, because this TTL is much shorter. - // route_ids_to_return_routes_stragglers: TtlHashMap, browser_proxy_sequence_offset: bool, inbound_client_data_helper_opt: Option>, stream_key_purge_delay: Duration, @@ -250,10 +243,13 @@ impl ProxyServer { } } - fn stream_info(&self, stream_key: &StreamKey, logger: &Logger) -> Option<&StreamInfo> { + fn stream_info(&self, stream_key: &StreamKey) -> Option<&StreamInfo> { match self.stream_info.get(stream_key) { None => { - error!(logger, "Stream key {} not found in stream_info", stream_key); + error!( + self.logger, + "Stream key {} not found in stream_info", stream_key + ); None } Some(info) => Some(info), @@ -339,10 +335,9 @@ impl ProxyServer { } fn find_exit_node_key(response_services: &[ExpectedService]) -> Option { - match response_services.first() { - Some(ExpectedService::Exit(pk, _, _)) => Some(pk.clone()), - _ => None, - } + response_services + .iter() + .find_map(|service| service.exit_node_key_opt()) } fn handle_add_route_result_message(&mut self, msg: AddRouteResultMessage) { @@ -431,7 +426,7 @@ impl ProxyServer { // circumstances we want to _retire_ the stream key; so we have a restore_stream_info // flag that starts out true and is set to false if we retire the stream key. It's an // ugly hack. Thanks, Borrow Checker! - let mut stream_info = match self.stream_info(&response.stream_key, &self.logger) { + let mut stream_info = match self.stream_info(&response.stream_key) { Some(info) => (*info).clone(), None => { error!( @@ -1029,7 +1024,7 @@ impl ProxyServer { &mut self, stream_key: &StreamKey, ) -> Option> { - match self.stream_info(stream_key, &self.logger) { + match self.stream_info(stream_key) { None => { error!(self.logger, "Can't pay for return services consumed: received response with unrecognized stream key {:?}. Ignoring", stream_key); None @@ -1273,7 +1268,7 @@ impl IBCDHelper for IBCDHelperReal { ); let pld = &args.payload; let stream_info = proxy_server - .stream_info(&pld.stream_key, &proxy_server.logger) + .stream_info(&pld.stream_key) .unwrap_or_else(|| panic!("Stream key {} disappeared!", &pld.stream_key)); if let Some(route_query_response) = &stream_info.route_opt { debug!( @@ -1643,9 +1638,8 @@ mod tests { #[test] fn constants_have_correct_values() { assert_eq!(CRASH_KEY, "PROXYSERVER"); - assert_eq!(RETURN_ROUTE_TTL_FIRST_CHANCE, Duration::from_secs(120)); - assert_eq!(RETURN_ROUTE_TTL_STRAGGLERS, Duration::from_secs(5)); assert_eq!(STREAM_KEY_PURGE_DELAY, Duration::from_secs(30)); + assert_eq!(DNS_FAILURE_RETRIES, 3); } const STANDARD_CONSUMING_WALLET_BALANCE: i64 = 0; @@ -4654,7 +4648,7 @@ mod tests { .try_send(AssertionsMessage { assertions: Box::new(move |proxy_server: &mut ProxyServer| { let retry_opt = &proxy_server - .stream_info(&stream_key_clone, &logger) + .stream_info(&stream_key_clone) .unwrap() .dns_failure_retry_opt; assert!(retry_opt.is_none()); @@ -5421,7 +5415,7 @@ mod tests { .try_send(AssertionsMessage { assertions: Box::new(move |proxy_server: &mut ProxyServer| { let retry = proxy_server - .stream_info(&stream_key, &logger) + .stream_info(&stream_key) .unwrap() .dns_failure_retry_opt .as_ref() @@ -5802,7 +5796,7 @@ mod tests { .is_some()); assert!(subject.stream_info.contains_key(&unaffected_stream_key)); assert!(subject - .stream_info(&unaffected_stream_key, &logger) + .stream_info(&unaffected_stream_key) .unwrap() .tunneled_host_opt .is_some()); @@ -6369,7 +6363,7 @@ mod tests { .try_send(AssertionsMessage { assertions: Box::new(move |proxy_server: &mut ProxyServer| { let dns_retry = proxy_server - .stream_info(&stream_key, &logger) + .stream_info(&stream_key) .unwrap() .dns_failure_retry_opt .as_ref() @@ -6444,7 +6438,7 @@ mod tests { .try_send(AssertionsMessage { assertions: Box::new(move |proxy_server: &mut ProxyServer| { let dns_retry = proxy_server - .stream_info(&stream_key, &logger) + .stream_info(&stream_key) .unwrap() .dns_failure_retry_opt .as_ref()