From 820eeb5989ade42e3718545b43a9745209edf601 Mon Sep 17 00:00:00 2001 From: czarte Date: Thu, 6 Nov 2025 12:53:23 +0100 Subject: [PATCH 1/2] Revert "Breaking change to remove RRID from CORES packages (#740)" This reverts commit a151e96a19ec81845f0f7e0415d7b5d7d25c2e99. --- .gitignore | 1 - .../tests/connection_termination_test.rs | 73 +- .../tests/self_test.rs | 11 +- node/src/dispatcher.rs | 28 +- node/src/hopper/consuming_service.rs | 23 +- node/src/hopper/live_cores_package.rs | 22 +- node/src/hopper/mod.rs | 13 +- node/src/hopper/routing_service.rs | 134 +- node/src/neighborhood/mod.rs | 459 +-- node/src/proxy_client/mod.rs | 12 +- node/src/proxy_client/stream_establisher.rs | 8 +- node/src/proxy_client/stream_handler_pool.rs | 155 +- node/src/proxy_client/stream_reader.rs | 26 +- .../client_request_payload_factory.rs | 243 +- node/src/proxy_server/http_protocol_pack.rs | 167 +- node/src/proxy_server/mod.rs | 2979 ++++++++--------- node/src/proxy_server/protocol_pack.rs | 21 +- .../proxy_server/server_impersonator_http.rs | 25 +- .../proxy_server/server_impersonator_tls.rs | 4 +- node/src/proxy_server/tls_protocol_pack.rs | 354 +- node/src/stream_handler_pool.rs | 62 +- node/src/stream_reader.rs | 38 +- node/src/sub_lib/dispatcher.rs | 22 +- node/src/sub_lib/hopper.rs | 11 +- node/src/sub_lib/host.rs | 39 - node/src/sub_lib/http_packet_framer.rs | 2 +- .../migrations/client_request_payload.rs | 14 +- node/src/sub_lib/mod.rs | 1 - node/src/sub_lib/neighborhood.rs | 54 +- node/src/sub_lib/proxy_server.rs | 14 +- node/src/sub_lib/route.rs | 121 +- node/src/sub_lib/sequence_buffer.rs | 8 +- node/src/sub_lib/stream_handler_pool.rs | 2 +- node/src/sub_lib/stream_key.rs | 15 +- node/src/sub_lib/ttl_hashmap.rs | 123 +- node/src/test_utils/mod.rs | 45 +- node/src/test_utils/recorder.rs | 6 +- 37 files changed, 2292 insertions(+), 3043 deletions(-) delete mode 100644 node/src/sub_lib/host.rs diff --git a/.gitignore b/.gitignore index 666a5a0987..88a2ab5f90 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,6 @@ **/*.rs.bk .idea/azure/ .idea/inspectionProfiles/Project_Default.xml -.idea/copilot.data.migration.* ### Node node_modules diff --git a/multinode_integration_tests/tests/connection_termination_test.rs b/multinode_integration_tests/tests/connection_termination_test.rs index 287f2f1205..2657661b8f 100644 --- a/multinode_integration_tests/tests/connection_termination_test.rs +++ b/multinode_integration_tests/tests/connection_termination_test.rs @@ -1,7 +1,6 @@ // Copyright (c) 2019, MASQ (https://masq.ai) and/or its affiliates. All rights reserved. use masq_lib::blockchains::chains::Chain; -use masq_lib::constants::HTTP_PORT; use masq_lib::test_utils::utils::TEST_DEFAULT_MULTINODE_CHAIN; use masq_lib::utils::find_free_port; use multinode_integration_tests_lib::masq_mock_node::MASQMockNode; @@ -87,12 +86,13 @@ fn reported_server_drop() { let (_, _, lcp) = mock_node .wait_for_package(&masquerader, Duration::from_secs(2)) .unwrap(); - let stream_key = stream_key_from_request_lcp(lcp, &exit_cryptde); + let (stream_key, return_route_id) = + context_from_request_lcp(lcp, real_node.main_cryptde_null().unwrap(), &exit_cryptde); mock_node .transmit_package( mock_node.port_list()[0], - create_server_drop_report(&mock_node, &real_node, stream_key), + create_server_drop_report(&mock_node, &real_node, stream_key, return_route_id), &masquerader, real_node.main_public_key(), real_node.socket_addr(PortSelector::First), @@ -115,7 +115,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 = arbitrary_stream_key(); + let (stream_key, return_route_id) = arbitrary_context(); let index: u64 = 0; request_server_payload( index, @@ -125,6 +125,7 @@ fn actual_server_drop() { &mut server, &masquerader, stream_key, + return_route_id, ); let index: u64 = 1; request_server_payload( @@ -135,6 +136,7 @@ fn actual_server_drop() { &mut server, &masquerader, stream_key, + return_route_id, ); server.shutdown(); @@ -172,6 +174,7 @@ fn request_server_payload( server: &mut MASQNodeServer, masquerader: &JsonMasquerader, stream_key: StreamKey, + return_route_id: u32, ) { mock_node .transmit_package( @@ -181,6 +184,7 @@ fn request_server_payload( &mock_node, &real_node, stream_key, + return_route_id, &server, cluster.chain, ), @@ -208,7 +212,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 = arbitrary_stream_key(); + let (stream_key, return_route_id) = arbitrary_context(); let index: u64 = 0; mock_node .transmit_package( @@ -218,6 +222,7 @@ fn reported_client_drop() { &mock_node, &real_node, stream_key, + return_route_id, &server, cluster.chain, ), @@ -235,7 +240,7 @@ fn reported_client_drop() { mock_node .transmit_package( mock_node.port_list()[0], - create_client_drop_report(&mock_node, &real_node, stream_key), + create_client_drop_report(&mock_node, &real_node, stream_key, return_route_id), &masquerader, real_node.main_public_key(), real_node.socket_addr(PortSelector::First), @@ -317,7 +322,11 @@ fn full_neighbor(one: &mut NodeRecord, another: &mut NodeRecord) { .unwrap(); } -fn stream_key_from_request_lcp(lcp: LiveCoresPackage, exit_cryptde: &dyn CryptDE) -> StreamKey { +fn context_from_request_lcp( + lcp: LiveCoresPackage, + originating_cryptde: &dyn CryptDE, + exit_cryptde: &dyn CryptDE, +) -> (StreamKey, u32) { let payload = match decodex::(exit_cryptde, &lcp.payload).unwrap() { MessageType::ClientRequest(vd) => vd .extract(&node_lib::sub_lib::migrations::client_request_payload::MIGRATIONS) @@ -325,11 +334,15 @@ fn stream_key_from_request_lcp(lcp: LiveCoresPackage, exit_cryptde: &dyn CryptDE mt => panic!("Unexpected: {:?}", mt), }; let stream_key = payload.stream_key; - stream_key + let return_route_id = decodex::(originating_cryptde, &lcp.route.hops[6]).unwrap(); + (stream_key, return_route_id) } -fn arbitrary_stream_key() -> StreamKey { - StreamKey::make_meaningful_stream_key("arbitrary_context") +fn arbitrary_context() -> (StreamKey, u32) { + ( + StreamKey::make_meaningful_stream_key("arbitrary_context"), + 12345678, + ) } fn create_request_icp( @@ -337,12 +350,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_main_cryptde, + originating_node.main_cryptde_null().unwrap(), Route::round_trip( RouteSegment::new( vec![ @@ -358,8 +371,9 @@ fn create_request_icp( ], Component::ProxyServer, ), - originating_main_cryptde, + originating_node.main_cryptde_null().unwrap(), originating_node.consuming_wallet(), + return_route_id, Some(chain.rec().contract), ) .unwrap(), @@ -368,7 +382,7 @@ fn create_request_icp( &ClientRequestPayload_0v1 { stream_key, sequenced_packet: SequencedPacket::new(Vec::from(HTTP_REQUEST), index, false), - target_hostname: format!("{}", server.local_addr().ip()), + target_hostname: Some(format!("{}", server.local_addr().ip())), target_port: server.local_addr().port(), protocol: ProxyProtocol::HTTP, originator_public_key: originating_node.main_public_key().clone(), @@ -386,9 +400,8 @@ 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( - main_cryptde, + originating_node.main_cryptde_null().unwrap(), Route::round_trip( RouteSegment::new( vec![ @@ -404,8 +417,9 @@ fn create_meaningless_icp( ], Component::ProxyServer, ), - main_cryptde, + originating_node.main_cryptde_null().unwrap(), originating_node.consuming_wallet(), + 1357, Some(TEST_DEFAULT_MULTINODE_CHAIN.rec().contract), ) .unwrap(), @@ -414,7 +428,7 @@ fn create_meaningless_icp( &ClientRequestPayload_0v1 { stream_key, sequenced_packet: SequencedPacket::new(Vec::from(HTTP_REQUEST), 0, false), - target_hostname: "nowhere.com".to_string(), + target_hostname: Some(format!("nowhere.com")), target_port: socket_addr.port(), protocol: ProxyProtocol::HTTP, originator_public_key: originating_node.main_public_key().clone(), @@ -429,9 +443,8 @@ 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![ @@ -447,12 +460,15 @@ fn create_server_drop_report( ], Component::ProxyServer, ), - originating_main_cryptde, + originating_node.main_cryptde_null().unwrap(), originating_node.consuming_wallet(), + return_route_id, Some(TEST_DEFAULT_MULTINODE_CHAIN.rec().contract), ) .unwrap(); - route.shift(originating_main_cryptde).unwrap(); + route + .shift(originating_node.main_cryptde_null().unwrap()) + .unwrap(); let payload = MessageType::ClientResponse(VersionedData::new( &node_lib::sub_lib::migrations::client_response_payload::MIGRATIONS, &ClientResponsePayload_0v1 { @@ -462,7 +478,7 @@ fn create_server_drop_report( )); IncipientCoresPackage::new( - exit_main_cryptde, + exit_node.main_cryptde_null().unwrap(), route, payload, originating_node.alias_public_key(), @@ -474,8 +490,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![ @@ -491,8 +507,9 @@ fn create_client_drop_report( ], Component::ProxyServer, ), - originating_main_cryptde, + originating_node.main_cryptde_null().unwrap(), originating_node.consuming_wallet(), + return_route_id, Some(TEST_DEFAULT_MULTINODE_CHAIN.rec().contract), ) .unwrap(); @@ -501,15 +518,15 @@ fn create_client_drop_report( &ClientRequestPayload_0v1 { stream_key, sequenced_packet: SequencedPacket::new(vec![], 1, true), - target_hostname: String::from("doesnt.matter.com"), - target_port: HTTP_PORT, + target_hostname: Some(String::from("doesnt.matter.com")), + target_port: 80, protocol: ProxyProtocol::HTTP, originator_public_key: originating_node.main_public_key().clone(), }, )); IncipientCoresPackage::new( - originating_main_cryptde, + originating_node.main_cryptde_null().unwrap(), 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 c19db4c330..973affaf06 100644 --- a/multinode_integration_tests/tests/self_test.rs +++ b/multinode_integration_tests/tests/self_test.rs @@ -16,7 +16,6 @@ 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::{make_meaningless_message_type, make_paying_wallet}; use std::collections::HashSet; use std::io::ErrorKind; @@ -69,7 +68,6 @@ 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( @@ -84,7 +82,7 @@ fn server_relays_cores_package() { let incipient = IncipientCoresPackage::new( cryptde, route.clone(), - make_meaningless_message_type(stream_key), + make_meaningless_message_type(), &cryptde.public_key(), ) .unwrap(); @@ -101,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(stream_key)); + assert_eq!(expired.payload, make_meaningless_message_type()); } #[test] @@ -113,7 +111,6 @@ 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 = CryptDENull::new(TEST_DEFAULT_CHAIN); - let stream_key = StreamKey::make_meaningless_stream_key(); let route = Route::one_way( RouteSegment::new( vec![ @@ -130,7 +127,7 @@ fn one_mock_node_talks_to_another() { let incipient_cores_package = IncipientCoresPackage::new( &cryptde, route, - make_meaningless_message_type(stream_key), + make_meaningless_message_type(), &mock_node_2.main_public_key(), ) .unwrap(); @@ -159,7 +156,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(stream_key) + make_meaningless_message_type() ); } diff --git a/node/src/dispatcher.rs b/node/src/dispatcher.rs index 4b01cd5938..ac698e043e 100644 --- a/node/src/dispatcher.rs +++ b/node/src/dispatcher.rs @@ -271,13 +271,13 @@ 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_opt = Some(8080); + let reception_port = Some(8080); let data: Vec = vec![9, 10, 11]; let ibcd_in = InboundClientData { timestamp: SystemTime::now(), client_addr, - reception_port_opt, - sequence_number_opt: Some(0), + reception_port, + sequence_number: Some(0), last_data: false, is_clandestine: false, data: data.clone(), @@ -310,15 +310,15 @@ 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_opt = Some(8080); + let reception_port = Some(8080); let data: Vec = vec![9, 10, 11]; let ibcd_in = InboundClientData { timestamp: SystemTime::now(), client_addr, - reception_port_opt, + reception_port, last_data: false, is_clandestine: true, - sequence_number_opt: None, + sequence_number: None, data: data.clone(), }; let mut peer_actors = peer_actors_builder().hopper(hopper).build(); @@ -350,15 +350,15 @@ 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_opt = Some(1234); + let reception_port = Some(1234); let data: Vec = vec![9, 10, 11]; let ibcd_in = InboundClientData { timestamp: SystemTime::now(), client_addr, - reception_port_opt, + reception_port, last_data: false, is_clandestine: false, - sequence_number_opt: Some(0), + sequence_number: Some(0), data: data.clone(), }; @@ -376,15 +376,15 @@ 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_opt = Some(1234); + let reception_port = Some(1234); let data: Vec = vec![9, 10, 11]; let ibcd_in = InboundClientData { timestamp: SystemTime::now(), client_addr, - reception_port_opt, + reception_port, last_data: false, is_clandestine: true, - sequence_number_opt: None, + sequence_number: None, data: data.clone(), }; @@ -406,7 +406,7 @@ mod tests { let obcd = TransmitDataMsg { endpoint: Endpoint::Socket(socket_addr), last_data: false, - sequence_number_opt: Some(0), + sequence_number: Some(0), data: data.clone(), }; @@ -430,7 +430,7 @@ mod tests { let obcd = TransmitDataMsg { endpoint: Endpoint::Socket(socket_addr), last_data: false, - sequence_number_opt: None, + sequence_number: None, data: data.clone(), }; let mut peer_actors = peer_actors_builder().build(); diff --git a/node/src/hopper/consuming_service.rs b/node/src/hopper/consuming_service.rs index 0eb34cb52e..7d5660a8be 100644 --- a/node/src/hopper/consuming_service.rs +++ b/node/src/hopper/consuming_service.rs @@ -100,10 +100,10 @@ impl ConsumingService { let ibcd = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 0), - reception_port_opt: None, + reception_port: None, last_data: false, is_clandestine: true, - sequence_number_opt: None, + sequence_number: None, data: encrypted_package.into(), }; debug!( @@ -119,7 +119,7 @@ impl ConsumingService { endpoint: next_stop, last_data: false, // Hopper-to-Hopper clandestine streams are never remotely killed data: encrypted_package.into(), - sequence_number_opt: None, + sequence_number: None, }; debug!( @@ -143,7 +143,6 @@ 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::{make_meaningless_message_type, make_paying_wallet}; @@ -169,7 +168,7 @@ mod tests { CRYPTDE_PAIR.main.as_ref(), &target_key, &target_node_addr, - make_meaningless_message_type(StreamKey::make_meaningless_stream_key()), + make_meaningless_message_type(), ) .unwrap(); let system = System::new(""); @@ -193,7 +192,7 @@ mod tests { &TransmitDataMsg { endpoint: Endpoint::Socket(SocketAddr::from_str("1.2.1.2:1212").unwrap()), last_data: false, - sequence_number_opt: None, + sequence_number: None, data: encodex(CRYPTDE_PAIR.main.as_ref(), &target_key, &lcp) .unwrap() .into(), @@ -243,7 +242,7 @@ mod tests { Some(TEST_DEFAULT_CHAIN.rec().contract), ) .unwrap(); - let payload = make_meaningless_message_type(StreamKey::make_meaningless_stream_key()); + let payload = make_meaningless_message_type(); 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"); @@ -267,7 +266,7 @@ mod tests { TransmitDataMsg { endpoint: Endpoint::Key(destination_key.clone()), last_data: false, - sequence_number_opt: None, + sequence_number: None, data: expected_lcp_enc.into(), }, *record, @@ -290,7 +289,7 @@ mod tests { Some(TEST_DEFAULT_CHAIN.rec().contract), ) .unwrap(); - let payload = make_meaningless_message_type(StreamKey::make_meaningless_stream_key()); + let payload = make_meaningless_message_type(); 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"); @@ -318,10 +317,10 @@ mod tests { InboundClientData { timestamp: record.timestamp, client_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 0), - reception_port_opt: None, + reception_port: None, last_data: false, is_clandestine: true, - sequence_number_opt: None, + sequence_number: None, data: expected_lcp_enc.into(), }, ); @@ -341,7 +340,7 @@ mod tests { IncipientCoresPackage::new( CRYPTDE_PAIR.main.as_ref(), Route { hops: vec![] }, - make_meaningless_message_type(StreamKey::make_meaningless_stream_key()), + make_meaningless_message_type(), &PublicKey::new(&[1, 2]), ) .unwrap(), diff --git a/node/src/hopper/live_cores_package.rs b/node/src/hopper/live_cores_package.rs index cac27bebcb..2b05b27e87 100644 --- a/node/src/hopper/live_cores_package.rs +++ b/node/src/hopper/live_cores_package.rs @@ -100,7 +100,6 @@ 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::{ make_meaningless_message_type, make_meaningless_route, make_paying_wallet, }; @@ -142,9 +141,7 @@ mod tests { let relay_key = PublicKey::new(&[1, 2]); let relay_cryptde = CryptDENull::from(&relay_key, TEST_DEFAULT_CHAIN); let cryptde = CRYPTDE_PAIR.main.as_ref(); - let stream_key = StreamKey::make_meaningless_stream_key(); - let serialized_payload = - serde_cbor::ser::to_vec(&make_meaningless_message_type(stream_key)).unwrap(); + let serialized_payload = serde_cbor::ser::to_vec(&make_meaningless_message_type()).unwrap(); let encrypted_payload = cryptde .encode(&destination_key, &PlainData::new(&serialized_payload)) .unwrap(); @@ -207,7 +204,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(StreamKey::make_meaningless_stream_key()); + let payload = make_meaningless_message_type(); let incipient = NoLookupIncipientCoresPackage::new(cryptde, &key34, &node_addr34, payload.clone()) @@ -231,7 +228,7 @@ mod tests { cryptde, &blank_key, &node_addr34, - make_meaningless_message_type(StreamKey::make_meaningless_stream_key()), + make_meaningless_message_type(), ); assert_eq!( @@ -257,7 +254,7 @@ mod tests { Some(contract_address), ) .unwrap(); - let payload = make_meaningless_message_type(StreamKey::make_meaningless_stream_key()); + let payload = make_meaningless_message_type(); let incipient = IncipientCoresPackage::new(cryptde, route.clone(), payload.clone(), &key56).unwrap(); @@ -283,7 +280,7 @@ mod tests { let incipient = IncipientCoresPackage::new( cryptde, Route { hops: vec![] }, - make_meaningless_message_type(StreamKey::make_meaningless_stream_key()), + make_meaningless_message_type(), &PublicKey::new(&[3, 4]), ) .unwrap(); @@ -300,8 +297,7 @@ 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 stream_key = StreamKey::make_meaningless_stream_key(); - let payload = make_meaningless_message_type(stream_key); + let payload = make_meaningless_message_type(); 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]); @@ -320,6 +316,7 @@ mod tests { ), cryptde, Some(paying_wallet.clone()), + 1234, Some(contract_address), ) .unwrap(); @@ -378,6 +375,11 @@ 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/hopper/mod.rs b/node/src/hopper/mod.rs index b2f3d6dc09..5880164408 100644 --- a/node/src/hopper/mod.rs +++ b/node/src/hopper/mod.rs @@ -149,7 +149,6 @@ 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::{ make_meaningless_message_type, make_paying_wallet, route_to_proxy_client, @@ -176,10 +175,8 @@ mod tests { fn panics_if_routing_service_is_unbound() { let main_cryptde = CRYPTDE_PAIR.main.as_ref(); let client_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); - 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(); + 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 data = main_cryptde .encode( &main_cryptde.public_key(), @@ -196,10 +193,10 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr, - reception_port_opt: None, + reception_port: None, last_data: false, is_clandestine: false, - sequence_number_opt: None, + sequence_number: None, data: encrypted_package, }; let system = System::new("panics_if_routing_service_is_unbound"); @@ -237,7 +234,7 @@ mod tests { let incipient_package = IncipientCoresPackage::new( main_cryptde, route, - make_meaningless_message_type(StreamKey::make_meaningless_stream_key()), + make_meaningless_message_type(), &main_cryptde.public_key(), ) .unwrap(); diff --git a/node/src/hopper/routing_service.rs b/node/src/hopper/routing_service.rs index 69a88aed44..7f7134d203 100644 --- a/node/src/hopper/routing_service.rs +++ b/node/src/hopper/routing_service.rs @@ -186,10 +186,10 @@ impl RoutingService { let inbound_client_data = InboundClientData { timestamp: ibcd_but_data.timestamp, client_addr: ibcd_but_data.client_addr, - reception_port_opt: ibcd_but_data.reception_port_opt, + reception_port: ibcd_but_data.reception_port, last_data: ibcd_but_data.last_data, is_clandestine: ibcd_but_data.is_clandestine, - sequence_number_opt: ibcd_but_data.sequence_number_opt, + sequence_number: ibcd_but_data.sequence_number, data: payload.into(), }; self.routing_service_subs @@ -495,7 +495,7 @@ impl RoutingService { endpoint: Endpoint::Key(next_hop.public_key), last_data, data: next_live_package_enc.into(), - sequence_number_opt: None, + sequence_number: None, }) } } @@ -542,18 +542,16 @@ mod tests { #[test] fn dns_resolution_failures_are_reported_to_the_proxy_server() { - let route = route_to_proxy_server( - &CRYPTDE_PAIR.main.public_key(), - CRYPTDE_PAIR.main.as_ref(), - false, - ); + let cryptde_pair = CRYPTDE_PAIR.clone(); + let route = + route_to_proxy_server(&cryptde_pair.main.public_key(), cryptde_pair.main.as_ref()); let stream_key = StreamKey::make_meaningless_stream_key(); let dns_resolve_failure = DnsResolveFailure_0v1::new(stream_key); let lcp = LiveCoresPackage::new( route, encodex( - CRYPTDE_PAIR.alias.as_ref(), - &CRYPTDE_PAIR.alias.public_key(), + cryptde_pair.alias.as_ref(), + &cryptde_pair.alias.public_key(), &MessageType::DnsResolveFailed(VersionedData::new( &crate::sub_lib::migrations::dns_resolve_failure::MIGRATIONS, &dns_resolve_failure.clone(), @@ -562,16 +560,16 @@ mod tests { .unwrap(), ); let data_enc = encodex( - CRYPTDE_PAIR.main.as_ref(), - &CRYPTDE_PAIR.main.public_key(), + cryptde_pair.main.as_ref(), + &cryptde_pair.main.public_key(), &lcp, ) .unwrap(); let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port_opt: None, - sequence_number_opt: None, + reception_port: None, + sequence_number: None, last_data: false, is_clandestine: false, data: data_enc.into(), @@ -581,7 +579,7 @@ mod tests { let system = System::new("dns_resolution_failures_are_reported_to_the_proxy_server"); let peer_actors = peer_actors_builder().proxy_server(proxy_server).build(); let subject = RoutingService::new( - CRYPTDE_PAIR.clone(), + cryptde_pair, RoutingServiceSubs { proxy_client_subs_opt: peer_actors.proxy_client_opt, proxy_server_subs: peer_actors.proxy_server, @@ -608,38 +606,36 @@ mod tests { #[test] fn logs_and_ignores_message_that_cannot_be_deserialized() { init_test_logging(); - let route = route_from_proxy_client( - &CRYPTDE_PAIR.main.public_key(), - CRYPTDE_PAIR.main.as_ref(), - false, - ); + let cryptde_pair = CRYPTDE_PAIR.clone(); + let route = + route_from_proxy_client(&cryptde_pair.main.public_key(), cryptde_pair.main.as_ref()); let lcp = LiveCoresPackage::new( route, encodex( - CRYPTDE_PAIR.main.as_ref(), - &CRYPTDE_PAIR.main.public_key(), + cryptde_pair.main.as_ref(), + &cryptde_pair.main.public_key(), &[42u8], ) .unwrap(), ); let data_enc = encodex( - CRYPTDE_PAIR.main.as_ref(), - &CRYPTDE_PAIR.main.public_key(), + cryptde_pair.main.as_ref(), + &cryptde_pair.main.public_key(), &lcp, ) .unwrap(); let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port_opt: None, - sequence_number_opt: None, + reception_port: None, + sequence_number: None, last_data: false, is_clandestine: false, data: data_enc.into(), }; let peer_actors = peer_actors_builder().build(); let subject = RoutingService::new( - CRYPTDE_PAIR.clone(), + cryptde_pair, RoutingServiceSubs { proxy_client_subs_opt: peer_actors.proxy_client_opt, proxy_server_subs: peer_actors.proxy_server, @@ -665,7 +661,7 @@ mod tests { init_test_logging(); let main_cryptde = CryptDEReal::new(TEST_DEFAULT_CHAIN); let rogue_cryptde = CryptDEReal::new(TEST_DEFAULT_CHAIN); - let route = route_from_proxy_client(main_cryptde.public_key(), &main_cryptde, false); + let route = route_from_proxy_client(main_cryptde.public_key(), &main_cryptde); let lcp = LiveCoresPackage::new( route, encodex(&rogue_cryptde, rogue_cryptde.public_key(), &[42u8]).unwrap(), @@ -674,8 +670,8 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port_opt: None, - sequence_number_opt: None, + reception_port: None, + sequence_number: None, last_data: false, is_clandestine: false, data: data_enc.into(), @@ -711,7 +707,7 @@ mod tests { fn logs_and_ignores_message_that_had_invalid_destination() { init_test_logging(); let main_cryptde = CRYPTDE_PAIR.main.as_ref(); - let route = route_from_proxy_client(&main_cryptde.public_key(), main_cryptde, false); + let route = route_from_proxy_client(&main_cryptde.public_key(), main_cryptde); let payload = GossipBuilder::empty(); let lcp = LiveCoresPackage::new( route, @@ -726,8 +722,8 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port_opt: None, - sequence_number_opt: None, + reception_port: None, + sequence_number: None, last_data: false, is_clandestine: false, data: data_enc.into(), @@ -757,7 +753,7 @@ mod tests { BAN_CACHE.clear(); let main_cryptde = CRYPTDE_PAIR.main.as_ref(); let (component, _, component_recording_arc) = make_recorder(); - let route = route_to_proxy_client(&main_cryptde.public_key(), main_cryptde, false); + let route = route_to_proxy_client(&main_cryptde.public_key(), main_cryptde); let payload = make_request_payload(0, main_cryptde); let lcp = LiveCoresPackage::new( route, @@ -776,8 +772,8 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port_opt: None, - sequence_number_opt: None, + reception_port: None, + sequence_number: None, last_data: true, is_clandestine: false, data: data_enc.into(), @@ -827,7 +823,7 @@ mod tests { init_test_logging(); BAN_CACHE.clear(); let main_cryptde = CRYPTDE_PAIR.main.as_ref(); - let route = route_to_proxy_client(&main_cryptde.public_key(), main_cryptde, false); + let route = route_to_proxy_client(&main_cryptde.public_key(), main_cryptde); let payload = make_request_payload(0, main_cryptde); let lcp = LiveCoresPackage::new( route, @@ -845,8 +841,8 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port_opt: None, - sequence_number_opt: None, + reception_port: None, + sequence_number: None, last_data: true, is_clandestine: false, data: data_enc.into(), @@ -885,7 +881,7 @@ mod tests { let main_cryptde = CRYPTDE_PAIR.main.as_ref(); let alias_cryptde = CRYPTDE_PAIR.alias.as_ref(); let (proxy_server, _, proxy_server_recording_arc) = make_recorder(); - let route = route_to_proxy_server(&main_cryptde.public_key(), main_cryptde, false); + let route = route_to_proxy_server(&main_cryptde.public_key(), main_cryptde); let payload = make_response_payload(0); let lcp = LiveCoresPackage::new( route, @@ -901,10 +897,10 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.3.2.4:5678").unwrap(), - reception_port_opt: None, + reception_port: None, last_data: false, is_clandestine: true, - sequence_number_opt: None, + sequence_number: None, data: lcp_enc.into(), }; @@ -978,10 +974,10 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.3.2.4:5678").unwrap(), - reception_port_opt: None, + reception_port: None, last_data: false, is_clandestine: true, - sequence_number_opt: None, + sequence_number: None, data: data_enc.into(), }; @@ -1051,10 +1047,10 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.3.2.4:5678").unwrap(), - reception_port_opt: None, + reception_port: None, last_data: false, is_clandestine: true, - sequence_number_opt: None, + sequence_number: None, data: data_enc.into(), }; @@ -1127,10 +1123,10 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port_opt: None, + reception_port: None, last_data: true, is_clandestine: true, - sequence_number_opt: None, + sequence_number: None, data: data_enc.into(), }; @@ -1170,7 +1166,7 @@ mod tests { TransmitDataMsg { endpoint: Endpoint::Key(next_key.clone()), last_data: true, - sequence_number_opt: None, + sequence_number: None, data: expected_lcp_enc.into(), } ); @@ -1219,10 +1215,10 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port_opt: None, + reception_port: None, last_data: true, is_clandestine: true, - sequence_number_opt: None, + sequence_number: None, data: data_enc.into(), }; @@ -1262,10 +1258,10 @@ mod tests { InboundClientData { timestamp: record.timestamp, client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port_opt: None, + reception_port: None, last_data: true, is_clandestine: true, - sequence_number_opt: None, + sequence_number: None, data: expected_lcp_enc.into() } ); @@ -1280,7 +1276,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(StreamKey::make_meaningless_stream_key()); + let payload = make_meaningless_message_type(); let route = Route::one_way( RouteSegment::new( vec![&origin_key, &main_cryptde.public_key(), &destination_key], @@ -1301,10 +1297,10 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port_opt: None, + reception_port: None, last_data: true, is_clandestine: true, - sequence_number_opt: None, + sequence_number: None, data: data_enc.into(), }; let system = System::new( @@ -1398,10 +1394,10 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port_opt: None, + reception_port: None, last_data: true, is_clandestine: true, - sequence_number_opt: None, + sequence_number: None, data: data_enc.into(), }; let system = System::new( @@ -1574,10 +1570,10 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port_opt: None, + reception_port: None, last_data: true, is_clandestine: true, - sequence_number_opt: None, + sequence_number: None, data: data_enc.into(), }; let system = System::new("test"); @@ -1644,10 +1640,10 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port_opt: None, + reception_port: None, last_data: true, is_clandestine: true, - sequence_number_opt: None, + sequence_number: None, data: data_enc.into(), }; let system = System::new("test"); @@ -1688,10 +1684,10 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port_opt: None, + reception_port: None, last_data: true, is_clandestine: true, - sequence_number_opt: None, + sequence_number: None, data: vec![], }; let system = System::new("consume_logs_error_when_given_bad_input_data"); @@ -1745,10 +1741,10 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port_opt: None, + reception_port: None, last_data: true, is_clandestine: true, - sequence_number_opt: None, + sequence_number: None, data: data_enc.into(), }; let system = System::new("consume_logs_error_when_given_bad_input_data"); @@ -1812,10 +1808,10 @@ mod tests { let ibcd = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port_opt: None, + reception_port: None, last_data: true, is_clandestine: true, - sequence_number_opt: None, + sequence_number: None, data: vec![], }; @@ -1877,7 +1873,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: "hostname".to_string(), + target_hostname: Some("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 2345342d81..9c685c0aff 100644 --- a/node/src/neighborhood/mod.rs +++ b/node/src/neighborhood/mod.rs @@ -27,15 +27,12 @@ use crate::sub_lib::cryptde::PublicKey; 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::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}; @@ -108,6 +105,7 @@ 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, @@ -432,6 +430,7 @@ 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, @@ -497,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.host)); + 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(msg.host)) + Ok(self.zero_hop_route_response()) } else { self.make_round_trip_route(msg) }; @@ -883,7 +882,7 @@ impl Neighborhood { target_component: Component::ProxyClient, return_component_opt: Some(Component::ProxyServer), payload_size: 10000, - host: Host::new("booga.com", 1234), + hostname_opt: None, }; if self.handle_route_query_message(msg).is_some() { debug!( @@ -983,7 +982,8 @@ impl Neighborhood { .expect("route creation error") } - fn zero_hop_route_response(&mut self, host: Host) -> RouteQueryResponse { + 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()], @@ -995,13 +995,17 @@ impl Neighborhood { ), self.cryptde.as_ref(), None, + return_route_id, None, ) .expect("Couldn't create route"); RouteQueryResponse { route, - expected_services: RoundTrip(vec![Nothing, Nothing], vec![Nothing, Nothing]), - host, + expected_services: ExpectedServices::RoundTrip( + vec![ExpectedService::Nothing, ExpectedService::Nothing], + vec![ExpectedService::Nothing, ExpectedService::Nothing], + return_route_id, + ), } } @@ -1009,7 +1013,7 @@ impl Neighborhood { &mut self, request_msg: RouteQueryMessage, ) -> Result { - let host = request_msg.host; + let hostname_opt = request_msg.hostname_opt.as_deref(); let over = self.make_route_segment( self.cryptde.public_key(), request_msg.target_key_opt.as_ref(), @@ -1017,7 +1021,7 @@ impl Neighborhood { request_msg.target_component, request_msg.payload_size, RouteDirection::Over, - &host.name, + hostname_opt, )?; debug!(self.logger, "Route over: {:?}", over); // Estimate for routing-undesirability calculations. @@ -1034,17 +1038,16 @@ impl Neighborhood { .expect("No return component"), anticipated_response_payload_len, RouteDirection::Back, - &host.name, + hostname_opt, )?; debug!(self.logger, "Route back: {:?}", back); - self.compose_route_query_response(over, back, host) + self.compose_route_query_response(over, back) } fn compose_route_query_response( &mut self, over: RouteSegment, back: RouteSegment, - host: Host, ) -> Result { let segments = vec![&over, &back]; @@ -1067,17 +1070,22 @@ 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.as_ref(), self.consuming_wallet_opt.clone(), + return_route_id, Some(self.chain.rec().contract), ) .expect("Internal error: bad route"), - expected_services: RoundTrip(expected_request_services, expected_response_services), - host, + expected_services: ExpectedServices::RoundTrip( + expected_request_services, + expected_response_services, + return_route_id, + ), }) } @@ -1090,7 +1098,7 @@ impl Neighborhood { target_component: Component, payload_size: usize, direction: RouteDirection, - hostname: &str, + hostname_opt: Option<&str>, ) -> Result { let route_opt = self.find_best_route_segment( origin, @@ -1098,7 +1106,7 @@ impl Neighborhood { minimum_hop_count, payload_size, direction, - hostname, + hostname_opt, ); match route_opt { None => { @@ -1137,20 +1145,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(Nothing) + Ok(ExpectedService::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(Exit( + Ok(ExpectedService::Exit( route_segment_key.clone(), node.earning_wallet(), *node.rate_pack(), )) } - (Some(_), Some(_)) => Ok(Routing( + (Some(_), Some(_)) => Ok(ExpectedService::Routing( route_segment_key.clone(), node.earning_wallet(), *node.rate_pack(), @@ -1268,7 +1276,11 @@ impl Neighborhood { UndesirabilityType::Relay => { node_record.inner.rate_pack.routing_charge(payload_size) as i64 } - UndesirabilityType::ExitRequest(hostname) => { + UndesirabilityType::ExitRequest(None) => { + node_record.inner.rate_pack.exit_charge(payload_size) as i64 + + node_record.metadata.country_undesirability as i64 + } + UndesirabilityType::ExitRequest(Some(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; @@ -1314,6 +1326,12 @@ impl Neighborhood { } } + fn advance_return_route_id(&mut self) -> u32 { + 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, @@ -1332,7 +1350,7 @@ impl Neighborhood { PAYLOAD_ZERO_SIZE, RouteDirection::Over, &mut minimum_undesirability, - "booga.com", + None, true, research_exits, ); @@ -1354,7 +1372,7 @@ impl Neighborhood { minimum_hops: usize, payload_size: usize, direction: RouteDirection, - hostname: &str, + hostname_opt: Option<&str>, ) -> Option> { let mut minimum_undesirability = i64::MAX; let initial_undesirability = @@ -1371,7 +1389,7 @@ impl Neighborhood { payload_size, direction, &mut minimum_undesirability, - hostname, + hostname_opt, false, &mut vec![], ) @@ -1395,7 +1413,7 @@ impl Neighborhood { payload_size: usize, direction: RouteDirection, minimum_undesirability: &mut i64, - hostname: &str, + hostname_opt: Option<&str>, research_neighborhood: bool, research_exits: &mut Vec<&'a PublicKey>, ) -> Vec> { @@ -1441,7 +1459,7 @@ impl Neighborhood { payload_size, direction, minimum_undesirability, - hostname, + hostname_opt, research_neighborhood, research_exits, previous_node, @@ -1463,7 +1481,7 @@ impl Neighborhood { payload_size, direction, minimum_undesirability, - hostname, + hostname_opt, research_neighborhood, research_exits, previous_node, @@ -1481,7 +1499,7 @@ impl Neighborhood { payload_size: usize, direction: RouteDirection, minimum_undesirability: &mut i64, - hostname: &str, + hostname_opt: Option<&str>, research_neighborhood: bool, exits_research: &mut Vec<&'a PublicKey>, previous_node: &NodeRecord, @@ -1512,7 +1530,7 @@ impl Neighborhood { new_hops_remaining, payload_size as u64, direction, - hostname, + hostname_opt, ); self.routing_engine( @@ -1523,7 +1541,7 @@ impl Neighborhood { payload_size, direction, minimum_undesirability, - hostname, + hostname_opt, research_neighborhood, exits_research, ) @@ -1580,11 +1598,11 @@ impl Neighborhood { hops_remaining: usize, payload_size: u64, direction: RouteDirection, - hostname: &str, + hostname_opt: Option<&str>, ) -> i64 { let undesirability_type = match (direction, target_opt) { (RouteDirection::Over, None) if hops_remaining == 0 => { - UndesirabilityType::ExitRequest(hostname) + UndesirabilityType::ExitRequest(hostname_opt) } (RouteDirection::Over, _) => UndesirabilityType::Relay, // The exit-and-relay undesirability is initial_undesirability @@ -2146,7 +2164,7 @@ impl UserExitPreferences { #[derive(PartialEq, Eq, Debug)] enum UndesirabilityType<'hostname> { Relay, - ExitRequest(&'hostname str), + ExitRequest(Option<&'hostname str>), ExitAndRouteResponse, } @@ -2167,20 +2185,10 @@ impl<'a> ComputedRouteSegment<'a> { #[cfg(test)] mod tests { - use super::*; use actix::Recipient; use actix::System; use itertools::Itertools; use lazy_static::lazy_static; - 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; @@ -2195,28 +2203,29 @@ mod tests { use std::time::Instant; use tokio::prelude::Future; - use crate::accountant::test_utils::bc_from_earning_wallet; - use crate::bootstrapper::CryptDEPair; + 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 crate::db_config::persistent_configuration::PersistentConfigError; use crate::neighborhood::gossip::Gossip_0v1; use crate::neighborhood::gossip::{GossipBuilder, GossipNodeRecord}; use crate::neighborhood::node_record::{NodeRecordInner_0v1, NodeRecordInputs}; - use crate::neighborhood::overall_connection_status::ConnectionStageErrors::{ - NoGossipResponseReceived, PassLoopFound, TcpConnectionFailed, - }; - use crate::neighborhood::overall_connection_status::{ - ConnectionProgress, ConnectionStage, OverallConnectionStage, - }; use crate::stream_messages::{NonClandestineAttributes, RemovedStreamType}; use crate::sub_lib::cryptde::{decodex, encodex, CryptData, PlainData}; use crate::sub_lib::cryptde_null::CryptDENull; use crate::sub_lib::dispatcher::Endpoint; use crate::sub_lib::hop::LiveHop; use crate::sub_lib::hopper::MessageType; - use crate::sub_lib::host::Host; - use crate::sub_lib::neighborhood::ExpectedServices::OneWay; use crate::sub_lib::neighborhood::{ - AskAboutDebutGossipMessage, ConfigChange, ConfigChangeMsg, NeighborhoodMode, WalletPair, + AskAboutDebutGossipMessage, ConfigChange, ConfigChangeMsg, ExpectedServices, + NeighborhoodMode, WalletPair, }; use crate::sub_lib::neighborhood::{NeighborhoodConfig, DEFAULT_RATE_PACK}; use crate::sub_lib::neighborhood::{NeighborhoodMetadata, RatePack}; @@ -2239,13 +2248,23 @@ mod tests { use crate::test_utils::recorder::peer_actors_builder; use crate::test_utils::recorder::Recorder; use crate::test_utils::recorder::Recording; - use crate::test_utils::unshared_test_utils::notify_handlers::NotifyLaterHandleMock; use crate::test_utils::unshared_test_utils::{ assert_on_initialization_with_panic_on_migration, make_cpm_recipient, make_node_to_ui_recipient, make_recipient_and_recording_arc, prove_that_crash_request_handler_is_hooked_up, AssertionsMessage, }; use crate::test_utils::vec_to_set; + + use super::*; + use crate::accountant::test_utils::bc_from_earning_wallet; + use crate::bootstrapper::CryptDEPair; + use crate::neighborhood::overall_connection_status::ConnectionStageErrors::{ + NoGossipResponseReceived, PassLoopFound, TcpConnectionFailed, + }; + use crate::neighborhood::overall_connection_status::{ + ConnectionProgress, ConnectionStage, OverallConnectionStage, + }; + use crate::test_utils::unshared_test_utils::notify_handlers::NotifyLaterHandleMock; use masq_lib::test_utils::logging::{init_test_logging, TestLogHandler}; lazy_static! { @@ -3157,7 +3176,7 @@ mod tests { } #[test] - pub fn progress_in_the_stage_of_overall_connection_status_made_by_one_cpm_is_not_overridden_by_the_other( + pub fn progress_in_the_stage_of_overall_connection_status_made_by_one_cpm_is_not_overriden_by_the_other( ) { let peer_1 = make_ip(1); let peer_2 = make_ip(2); @@ -3177,7 +3196,7 @@ mod tests { neighborhood_config, make_wallet("earning"), None, - "progress_in_the_stage_of_overall_connection_status_made_by_one_cpm_is_not_overridden_by_the_other"), + "progress_in_the_stage_of_overall_connection_status_made_by_one_cpm_is_not_overriden_by_the_other"), ); let (node_to_ui_recipient, _) = make_node_to_ui_recipient(); subject.node_to_ui_recipient_opt = Some(node_to_ui_recipient); @@ -3290,10 +3309,7 @@ mod tests { let addr: Addr = subject.start(); let sub: Recipient = addr.recipient::(); - let future = sub.send(RouteQueryMessage::data_indefinite_route_request( - Host::new("booga.com", 1234), - 400, - )); + let future = sub.send(RouteQueryMessage::data_indefinite_route_request(None, 400)); System::current().stop_with_code(0); system.run(); @@ -3309,10 +3325,7 @@ mod tests { let addr: Addr = subject.start(); let sub: Recipient = addr.recipient::(); - let future = sub.send(RouteQueryMessage::data_indefinite_route_request( - Host::new("booga.com", 1234), - 430, - )); + let future = sub.send(RouteQueryMessage::data_indefinite_route_request(None, 430)); System::current().stop_with_code(0); system.run(); @@ -3352,8 +3365,7 @@ mod tests { } let addr: Addr = subject.start(); let sub: Recipient = addr.recipient::(); - let msg = - RouteQueryMessage::data_indefinite_route_request(Host::new("booga.com", 1234), 54000); + let msg = RouteQueryMessage::data_indefinite_route_request(None, 54000); let future = sub.send(msg); @@ -3378,28 +3390,29 @@ mod tests { ), cryptde, None, + 0, None, ) .unwrap(), - expected_services: RoundTrip( + expected_services: ExpectedServices::RoundTrip( vec![ - Nothing, - Exit( + ExpectedService::Nothing, + ExpectedService::Exit( desirable_exit_node.public_key().clone(), desirable_exit_node.earning_wallet(), rate_pack(2345), ), ], vec![ - Exit( + ExpectedService::Exit( desirable_exit_node.public_key().clone(), desirable_exit_node.earning_wallet(), rate_pack(2345), ), - Nothing, + ExpectedService::Nothing, ], + 0, ), - host: Host::new("booga.com", 1234), }; assert_eq!(expected_response, result); } @@ -3412,8 +3425,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(Host::new("booga.com", 1234), 20000); + let msg = RouteQueryMessage::data_indefinite_route_request(None, 20000); let future = sub.send(msg); @@ -3433,8 +3445,7 @@ mod tests { let sub: Recipient = addr.recipient::(); let future = sub.send(RouteQueryMessage::data_indefinite_route_request( - Host::new("google.com", 1234), - 12345, + None, 12345, )); System::current().stop_with_code(0); @@ -3452,15 +3463,39 @@ mod tests { ), cryptde, None, + 0, None, ) .unwrap(), - expected_services: RoundTrip(vec![Nothing, Nothing], vec![Nothing, Nothing]), - host: Host::new("google.com", 1234), + 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: @@ -3506,10 +3541,7 @@ mod tests { let addr: Addr = subject.start(); let sub: Recipient = addr.recipient::(); - let data_route = sub.send(RouteQueryMessage::data_indefinite_route_request( - Host::new("booga.com", 1234), - 5000, - )); + let data_route = sub.send(RouteQueryMessage::data_indefinite_route_request(None, 5000)); System::current().stop_with_code(0); system.run(); @@ -3522,24 +3554,41 @@ mod tests { segment(&[r, q, p], &Component::ProxyServer), cryptde, consuming_wallet_opt, + 0, Some(contract_address), ) .unwrap(), - expected_services: RoundTrip( + expected_services: ExpectedServices::RoundTrip( vec![ - Nothing, - Routing(q.public_key().clone(), q.earning_wallet(), rate_pack(3456)), - Exit(r.public_key().clone(), r.earning_wallet(), rate_pack(4567)), + ExpectedService::Nothing, + ExpectedService::Routing( + q.public_key().clone(), + q.earning_wallet(), + rate_pack(3456), + ), + ExpectedService::Exit( + r.public_key().clone(), + r.earning_wallet(), + rate_pack(4567), + ), ], vec![ - Exit(r.public_key().clone(), r.earning_wallet(), rate_pack(4567)), - Routing(q.public_key().clone(), q.earning_wallet(), rate_pack(3456)), - Nothing, + ExpectedService::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, ], + 0, ), - host: Host::new("booga.com", 1234), }; - assert_eq!(result, expected_response); + assert_eq!(expected_response, result); } #[test] @@ -3549,7 +3598,6 @@ mod tests { let result: Result = subject.compose_route_query_response( RouteSegment::new(vec![], Component::Neighborhood), RouteSegment::new(vec![], Component::Neighborhood), - Host::new("booga.com", 1234), ); assert!(result.is_err()); let error_expectation: String = result.expect_err("Expected an Err but got:"); @@ -3559,6 +3607,18 @@ 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: @@ -3567,6 +3627,37 @@ mod tests { Tests will be written from the viewpoint of O. */ + #[test] + fn return_route_ids_increase() { + let cryptde = CRYPTDE_PAIR.main.as_ref(); + 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"; @@ -4427,7 +4518,6 @@ mod tests { let result: Result = subject.compose_route_query_response( RouteSegment::new(vec![], Component::ProxyClient), RouteSegment::new(vec![], Component::ProxyServer), - Host::new("booga.com", 1234), ); assert!(result.is_err()); let error_expectation: String = result.expect_err("Expected an Err but got:"); @@ -4444,7 +4534,6 @@ 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), - Host::new("booga.com", 1234), ); assert!(result.is_err()); let error_expectation: String = result.expect_err("Expected an Err but got:"); @@ -4452,6 +4541,7 @@ mod tests { error_expectation, "Cannot make multi_hop with unknown neighbor" ); + assert_eq!(subject.next_return_route_id, 0); } #[test] @@ -4573,58 +4663,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, "booga.com"); + subject.find_best_route_segment(p, None, 2, 10000, RouteDirection::Over, None); 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, - "booga.com", - ); + let route_opt = + subject.find_best_route_segment(p, Some(t), 2, 10000, RouteDirection::Over, None); 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, - "booga.com", - ); + let route_opt = + subject.find_best_route_segment(t, Some(p), 2, 10000, RouteDirection::Over, None); 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, - "booga.com", - ); + let route_opt = + subject.find_best_route_segment(t, Some(p), 2, 10000, RouteDirection::Back, None); 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, - "booga.com", - ); + let route_opt = + subject.find_best_route_segment(p, Some(q), 2, 10000, RouteDirection::Over, None); assert_eq!(route_opt, None); } @@ -4669,7 +4735,7 @@ mod tests { 3, 10000, RouteDirection::Back, - "booga.com", + None, ) .unwrap(); @@ -4744,7 +4810,7 @@ mod tests { 3, 10000, RouteDirection::Over, - "booga.com", + None, ); let after = Instant::now(); @@ -4795,14 +4861,8 @@ mod tests { db.add_arbitrary_full_neighbor(c_au_key, a_fr_key); subject.handle_exit_location_message(message, 0, 0); - let route_cz = subject.find_best_route_segment( - root_key, - None, - 2, - 10000, - RouteDirection::Over, - "booga.com", - ); + let route_cz = + subject.find_best_route_segment(root_key, None, 2, 10000, RouteDirection::Over, None); assert_eq!(route_cz, None); } @@ -4867,7 +4927,7 @@ mod tests { subject_min_hops, 10000, RouteDirection::Over, - "booga.com", + None, ); let exit_node = cdb.node_by_key(&route_au.as_ref().unwrap().last().unwrap()); @@ -4922,14 +4982,8 @@ 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, - "booga.com", - ); + let route_fr = + subject.find_best_route_segment(root_key, None, 2, 10000, RouteDirection::Over, None); let exit_node = cdb.node_by_key(&route_fr.as_ref().unwrap().last().unwrap()); assert_eq!( @@ -4952,7 +5006,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, "booga.com"); + subject.find_best_route_segment(p, None, 2, 10000, RouteDirection::Over, None); assert_eq!(route_opt, None); } @@ -4969,7 +5023,7 @@ mod tests { 5, // Lots of hops to go yet 1_000, RouteDirection::Over, - "hostname.com", + Some("hostname.com"), ); let rate_pack = node_record.rate_pack(); @@ -4993,7 +5047,7 @@ mod tests { 0, // Last hop 1_000, RouteDirection::Over, - "hostname.com", + Some("hostname.com"), ); let rate_pack = node_record.rate_pack(); @@ -5021,7 +5075,7 @@ mod tests { 0, // Last hop 1_000, RouteDirection::Over, - "hostname.com", + Some("hostname.com"), ); let rate_pack = node_record.rate_pack(); @@ -5094,7 +5148,7 @@ mod tests { 5, // Plenty of hops remaining: not there yet 1_000, RouteDirection::Back, - "booga.com", + None, ); let rate_pack = node_record.rate_pack(); @@ -6568,7 +6622,7 @@ mod tests { target_component: Component::ProxyClient, return_component_opt: None, payload_size: 10000, - host: Host::new("booga.com", 1234), + hostname_opt: None, }; let unsuccessful_three_hop_route = addr.send(three_hop_route_request); let asserted_node_record = a.clone(); @@ -6618,7 +6672,7 @@ mod tests { context: TransmitDataMsg { endpoint: Endpoint::Key(cryptde.public_key().clone()), last_data: false, - sequence_number_opt: None, + sequence_number: None, data: Vec::new(), }, recipient, @@ -6681,7 +6735,7 @@ mod tests { context: TransmitDataMsg { endpoint: Endpoint::Key(cryptde.public_key().clone()), last_data: false, - sequence_number_opt: None, + sequence_number: None, data: Vec::new(), }, recipient, @@ -6710,7 +6764,7 @@ mod tests { let context = TransmitDataMsg { endpoint: Endpoint::Key(cryptde.public_key().clone()), last_data: false, - sequence_number_opt: None, + sequence_number: None, data: Vec::new(), }; let context_a = context.clone(); @@ -6810,7 +6864,7 @@ mod tests { context: TransmitDataMsg { endpoint: Endpoint::Key(cryptde.public_key().clone()), last_data: false, - sequence_number_opt: None, + sequence_number: None, data: Vec::new(), }, recipient, @@ -6838,7 +6892,7 @@ mod tests { let context = TransmitDataMsg { endpoint: Endpoint::Key(cryptde.public_key().clone()), last_data: false, - sequence_number_opt: None, + sequence_number: None, data: Vec::new(), }; let context_a = context.clone(); @@ -6935,7 +6989,7 @@ mod tests { target_component: Component::ProxyClient, return_component_opt: Some(Component::ProxyServer), payload_size: 10000, - host: Host::new("booga.com", 1234), + hostname_opt: None, }); assert_eq!( @@ -6981,16 +7035,16 @@ mod tests { target_component: Component::ProxyClient, return_component_opt: Some(Component::ProxyServer), payload_size: 10000, - host: Host::new("host.name", 88), + hostname_opt: None, }); 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 response = result.clone().unwrap(); - let hops = &response.route.hops; + + let hops = result.clone().unwrap().route.hops; let actual_keys: Vec = match hops.as_slice() { - [hop, exit, hop_back, origin, empty] => vec![ + [hop, exit, hop_back, origin, empty, _accounting] => vec![ decodex::(CRYPTDE_PAIR.main.as_ref(), hop) .expect("hop") .public_key, @@ -7007,11 +7061,7 @@ mod tests { .expect("empty") .public_key, ], - l => panic!( - "our match is wrong, real size is {} instead of 5, {:?}", - l.len(), - l - ), + l => panic!("our match is wrong, real size is {}, {:?}", l.len(), l), }; let expected_public_keys = vec![ next_door_neighbor.public_key().clone(), @@ -7021,38 +7071,6 @@ 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.host, Host::new("host.name", 88)); } fn assert_route_query_message(min_hops: Hops) { @@ -7071,7 +7089,7 @@ mod tests { target_component: Component::ProxyClient, return_component_opt: Some(Component::ProxyServer), payload_size: 10000, - host: Host::new("booga.com", 1234), + hostname_opt: None, }); let assert_hops = |cryptdes: Vec, route: &[CryptData]| { @@ -7081,23 +7099,24 @@ mod tests { } }; /* - This is how the route_hops vector looks like: [C1, C2, ..., C(nodes_count), ..., C2, C1] + This is how the route_hops vector looks like: [C1, C2, ..., C(nodes_count), ..., C2, C1, accounting] Let's consider for 3-hop route ==> Nodes Count --> 4 Route Length --> 8 - Route Hops --> [C1, C2, C3, C4, C3, C2, C1] + Route Hops --> [C1, C2, C3, C4, C3, C2, C1, accounting] Over Route --> [C1, C2, C3] Back Route --> [C4, C3, C2, C1] */ - let route_hops = result.unwrap().route.hops; + let mut 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 - 1); + assert_eq!(route_length, 2 * nodes_count); assert_hops(over_cryptdes, over_route); assert_hops(back_cryptdes, back_route); } @@ -7171,16 +7190,16 @@ mod tests { target_component: Component::ProxyClient, return_component_opt: Some(Component::ProxyServer), payload_size, - host: Host::new("booga.com", 1234), + hostname_opt: None, }) .unwrap(); let (over, back) = match response.expected_services { - OneWay(_) => panic!("Expecting RoundTrip"), - RoundTrip(o, b) => (o[1].clone(), b[1].clone()), + ExpectedServices::OneWay(_) => panic!("Expecting RoundTrip"), + ExpectedServices::RoundTrip(o, b, _) => (o[1].clone(), b[1].clone()), }; let extract_key = |es: ExpectedService| match es { - Routing(pk, _, _) => pk, + ExpectedService::Routing(pk, _, _) => pk, x => panic!("Expecting Routing, found {:?}", x), }; let expected_relay_key = if a_not_b { a.clone() } else { b.clone() }; @@ -7572,6 +7591,24 @@ 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_client/mod.rs b/node/src/proxy_client/mod.rs index c17daaf168..aa0f330104 100644 --- a/node/src/proxy_client/mod.rs +++ b/node/src/proxy_client/mod.rs @@ -613,7 +613,7 @@ mod tests { sequence_number: 0, last_data: false, }, - target_hostname: String::from("target.hostname.com"), + target_hostname: Some(String::from("target.hostname.com")), target_port: 1234, protocol: ProxyProtocol::HTTP, originator_public_key: PublicKey::new(&b"originator_public_key"[..]), @@ -622,7 +622,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, false), + route_to_proxy_client(&cryptde.public_key(), cryptde), request, 0, ); @@ -754,7 +754,7 @@ mod tests { sequence_number: 0, last_data: false, }, - target_hostname: "booga.com".to_string(), + target_hostname: None, target_port: 0, protocol: ProxyProtocol::HTTP, originator_public_key: PublicKey::new(&b"originator"[..]), @@ -813,7 +813,7 @@ mod tests { sequence_number: 0, last_data: false, }, - target_hostname: "booga.com".to_string(), + target_hostname: None, target_port: 0, protocol: ProxyProtocol::HTTP, originator_public_key: PublicKey::new(&b"originator"[..]), @@ -870,7 +870,7 @@ mod tests { sequence_number: 0, last_data: false, }, - target_hostname: "booga.com".to_string(), + target_hostname: None, target_port: 0, protocol: ProxyProtocol::HTTP, originator_public_key: alias_cryptde.public_key().clone(), @@ -1226,7 +1226,7 @@ mod tests { sequence_number: 0, last_data: false, }, - target_hostname: "booga.com".to_string(), + target_hostname: None, 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 a07e4d7307..602b3c0c1c 100644 --- a/node/src/proxy_client/stream_establisher.rs +++ b/node/src/proxy_client/stream_establisher.rs @@ -160,8 +160,6 @@ 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(); @@ -195,13 +193,13 @@ mod tests { }; subject.spawn_stream_reader( &ClientRequestPayload_0v1 { - stream_key: stream_key_inner, + stream_key: StreamKey::make_meaningless_stream_key(), sequenced_packet: SequencedPacket { data: vec![], sequence_number: 0, last_data: false, }, - target_hostname: "blah".to_string(), + target_hostname: Some("blah".to_string()), target_port: 0, protocol: ProxyProtocol::HTTP, originator_public_key: subject.cryptde.public_key().clone(), @@ -229,7 +227,7 @@ mod tests { assert_eq!( ibsd, InboundServerData { - stream_key, + stream_key: StreamKey::make_meaningless_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 8a42ca2ae0..7fc6236176 100644 --- a/node/src/proxy_client/stream_handler_pool.rs +++ b/node/src/proxy_client/stream_handler_pool.rs @@ -114,7 +114,11 @@ impl StreamHandlerPoolReal { let inner_arc_1 = inner_arc.clone(); let logger = Self::make_logger_copy(&inner_arc); let data_len = payload.sequenced_packet.data.len(); - let hostname = payload.target_hostname.clone(); + let hostname = payload + .target_hostname + .as_ref() + .unwrap_or(&"".to_string()) + .to_string(); let target_port = payload.target_port; match Self::find_stream_with_key(&stream_key, &inner_arc) { Some(sender_wrapper) => { @@ -311,14 +315,27 @@ impl StreamHandlerPoolReal { "No stream to {:?} exists; resolving host", &payload.target_hostname ); - 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()), + 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())) + } } } @@ -715,7 +732,7 @@ mod tests { let payload = ClientRequestPayload_0v1 { stream_key, sequenced_packet: SequencedPacket::new(b"booga".to_vec(), 0, false), - target_hostname: "www.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(), @@ -748,7 +765,7 @@ mod tests { sequence_number: 0, last_data: false, }, - target_hostname: "booga.com".to_string(), + target_hostname: None, target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: PublicKey::new(&b"men's souls"[..]), @@ -803,20 +820,18 @@ mod tests { init_test_logging(); let test_name = "write_failure_for_nonexistent_stream_generates_termination_message"; let cryptde = CRYPTDE_PAIR.main.as_ref(); - 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: stream_key_inner, + stream_key: StreamKey::make_meaningless_stream_key(), sequenced_packet: SequencedPacket { data: b"These are the times".to_vec(), sequence_number: 0, last_data: false, }, - target_hostname: String::from("that.try"), + target_hostname: Some(String::from("that.try")), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: originator_key, @@ -864,7 +879,7 @@ mod tests { assert_eq!( proxy_client_recording.get_record::(0), &InboundServerData { - stream_key: stream_key.clone(), + stream_key: StreamKey::make_meaningless_stream_key(), last_data: true, sequence_number: 0, source: SocketAddr::from_str("2.3.4.5:80").unwrap(), @@ -873,8 +888,7 @@ 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 AAAAAAAAAAAAAAAAAAAAAAAAAAA." )); } @@ -883,19 +897,17 @@ mod tests { let cryptde = CRYPTDE_PAIR.main.as_ref(); 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: stream_key_inner, + stream_key: StreamKey::make_meaningless_stream_key(), sequenced_packet: SequencedPacket { data: b"These are the times".to_vec(), sequence_number: 0, last_data: false, }, - target_hostname: String::from("3.4.5.6:80"), + target_hostname: Some(String::from("3.4.5.6:80")), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: PublicKey::new(&b"men's souls"[..]), @@ -968,7 +980,7 @@ mod tests { assert_eq!( proxy_client_recording.get_record::(0), &InboundServerData { - stream_key, + stream_key: StreamKey::make_meaningless_stream_key(), last_data: false, sequence_number: 0, source: SocketAddr::from_str("3.4.5.6:80").unwrap(), @@ -991,7 +1003,7 @@ mod tests { sequence_number: 0, last_data: true, }, - target_hostname: String::from("3.4.5.6:80"), + target_hostname: Some(String::from("3.4.5.6:80")), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: PublicKey::new(&b"brutal death"[..]), @@ -1052,7 +1064,7 @@ mod tests { sequence_number: 0, last_data: true, }, - target_hostname: String::from("3.4.5.6:80"), + target_hostname: Some(String::from("3.4.5.6:80")), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: PublicKey::new(&b"brutal death"[..]), @@ -1104,19 +1116,17 @@ 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: stream_key_inner, + stream_key: StreamKey::make_meaningless_stream_key(), sequenced_packet: SequencedPacket { data: b"These are the times".to_vec(), sequence_number: 0, last_data: false, }, - target_hostname: String::from("3.4.5.6"), + target_hostname: Some(String::from("3.4.5.6")), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: PublicKey::new(&b"men's souls"[..]), @@ -1199,7 +1209,7 @@ mod tests { assert_eq!( proxy_client_recording.get_record::(0), &InboundServerData { - stream_key, + stream_key: StreamKey::make_meaningless_stream_key(), last_data: false, sequence_number: 0, source: SocketAddr::from_str("3.4.5.6:80").unwrap(), @@ -1208,6 +1218,71 @@ 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 = CRYPTDE_PAIR.main.as_ref(); + 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: None, + 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(&CRYPTDE_PAIR), + 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 = CRYPTDE_PAIR.main.as_ref(); @@ -1215,8 +1290,6 @@ 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(); @@ -1226,13 +1299,13 @@ mod tests { .accountant(accountant) .build(); let client_request_payload = ClientRequestPayload_0v1 { - stream_key: stream_key_inner, + stream_key: StreamKey::make_meaningless_stream_key(), sequenced_packet: SequencedPacket { data: b"These are the times".to_vec(), sequence_number: 0, last_data: false, }, - target_hostname: String::from("that.try"), + target_hostname: Some(String::from("that.try")), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: PublicKey::new(&b"men's souls"[..]), @@ -1317,7 +1390,7 @@ mod tests { assert_eq!( proxy_client_recording.get_record::(0), &InboundServerData { - stream_key, + stream_key: StreamKey::make_meaningless_stream_key(), last_data: false, sequence_number: 0, source: SocketAddr::from_str("3.4.5.6:80").unwrap(), @@ -1345,7 +1418,7 @@ mod tests { sequence_number: 0, last_data: false, }, - target_hostname: String::from("that.try"), + target_hostname: Some(String::from("that.try")), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: originator_key, @@ -1467,7 +1540,7 @@ mod tests { sequence_number: 0, last_data: false, }, - target_hostname: String::from("blockedwebsite.com"), + target_hostname: Some(String::from("blockedwebsite.com")), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: originator_key, @@ -1564,7 +1637,7 @@ mod tests { let client_request_payload = ClientRequestPayload_0v1 { stream_key, sequenced_packet: sequenced_packet.clone(), - target_hostname: String::from("that.try"), + target_hostname: Some(String::from("that.try")), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: PublicKey::new(&b"men's souls"[..]), @@ -1677,7 +1750,7 @@ mod tests { sequence_number: 0, last_data: true, }, - target_hostname: String::from("that.try"), + target_hostname: Some(String::from("that.try")), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: originator_key, @@ -1739,7 +1812,7 @@ mod tests { let client_request_payload = ClientRequestPayload_0v1 { stream_key: stream_key.clone(), sequenced_packet: sequenced_packet.clone(), - target_hostname: String::from("that.try"), + target_hostname: Some(String::from("that.try")), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: PublicKey::new(&b"men's souls"[..]), @@ -1810,7 +1883,7 @@ mod tests { sequence_number: 0, last_data: false, }, - target_hostname: "booga.com".to_string(), + target_hostname: None, target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: PublicKey::new(&b"booga"[..]), diff --git a/node/src/proxy_client/stream_reader.rs b/node/src/proxy_client/stream_reader.rs index bf39de6e31..992b58dbfa 100644 --- a/node/src/proxy_client/stream_reader.rs +++ b/node/src/proxy_client/stream_reader.rs @@ -179,10 +179,9 @@ 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: stream_key.clone(), + stream_key: StreamKey::make_meaningless_stream_key(), proxy_client_sub, stream, stream_killer, @@ -199,7 +198,7 @@ mod tests { assert_eq!( proxy_client_recording.get_record::(0), &InboundServerData { - stream_key: stream_key.clone(), + stream_key: StreamKey::make_meaningless_stream_key(), last_data: false, sequence_number: 0, source: SocketAddr::from_str("8.7.4.3:50").unwrap(), @@ -209,7 +208,7 @@ mod tests { assert_eq!( proxy_client_recording.get_record::(1), &InboundServerData { - stream_key: stream_key.clone(), + stream_key: StreamKey::make_meaningless_stream_key(), last_data: false, sequence_number: 1, source: SocketAddr::from_str("8.7.4.3:50").unwrap(), @@ -219,7 +218,7 @@ mod tests { assert_eq!( proxy_client_recording.get_record::(2), &InboundServerData { - stream_key: stream_key.clone(), + stream_key: StreamKey::make_meaningless_stream_key(), last_data: false, sequence_number: 2, source: SocketAddr::from_str("8.7.4.3:50").unwrap(), @@ -227,7 +226,10 @@ 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, + (StreamKey::make_meaningless_stream_key(), 3) + ); } #[test] @@ -264,7 +266,6 @@ 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; @@ -278,7 +279,7 @@ mod tests { assert_eq!( proxy_client_recording.get_record::(0), &InboundServerData { - stream_key: stream_key.clone(), + stream_key: StreamKey::make_meaningless_stream_key(), last_data: false, sequence_number: 0, source: peer_addr, @@ -288,7 +289,7 @@ mod tests { assert_eq!( proxy_client_recording.get_record::(1), &InboundServerData { - stream_key: stream_key.clone(), + stream_key: StreamKey::make_meaningless_stream_key(), last_data: false, sequence_number: 1, source: peer_addr, @@ -298,7 +299,7 @@ mod tests { assert_eq!( proxy_client_recording.get_record::(2), &InboundServerData { - stream_key: stream_key.clone(), + stream_key: StreamKey::make_meaningless_stream_key(), last_data: false, sequence_number: 2, source: peer_addr, @@ -309,7 +310,10 @@ 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, + (StreamKey::make_meaningless_stream_key(), 3) + ); assert!(stream_killer_params.try_recv().is_err()); } diff --git a/node/src/proxy_server/client_request_payload_factory.rs b/node/src/proxy_server/client_request_payload_factory.rs index 4f9e5df60a..75a484a37b 100644 --- a/node/src/proxy_server/client_request_payload_factory.rs +++ b/node/src/proxy_server/client_request_payload_factory.rs @@ -3,7 +3,6 @@ use crate::proxy_server::protocol_pack::from_ibcd; use crate::sub_lib::cryptde::CryptDE; use crate::sub_lib::cryptde::PlainData; use crate::sub_lib::dispatcher::InboundClientData; -use crate::sub_lib::host::Host; use crate::sub_lib::proxy_server::ClientRequestPayload_0v1; use crate::sub_lib::sequence_buffer::SequencedPacket; use crate::sub_lib::stream_key::StreamKey; @@ -14,7 +13,6 @@ pub trait ClientRequestPayloadFactory { &self, ibcd: &InboundClientData, stream_key: StreamKey, - host_opt: Option, cryptde: &dyn CryptDE, logger: &Logger, ) -> Option; @@ -28,44 +26,11 @@ impl ClientRequestPayloadFactory for ClientRequestPayloadFactoryReal { &self, ibcd: &InboundClientData, stream_key: StreamKey, - host_from_history_opt: Option, cryptde: &dyn CryptDE, logger: &Logger, ) -> Option { let protocol_pack = from_ibcd(ibcd).map_err(|e| error!(logger, "{}", e)).ok()?; - let host_from_request_result_closure = 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 {:?}, with StreamKey {}", - protocol_pack.describe_packet(&data), - protocol_pack.proxy_protocol(), - stream_key - )), - } - }); - let target_host = match (host_from_request_result_closure(), host_from_history_opt) { - (Ok(host), _) => host, - (Err(_), Some(host)) => host, - (Err(e), None) => { - if ibcd.last_data && ibcd.data.is_empty() { - warning!( - logger, - "Client opened {:?} connection and immediately closed it without sending any data, with StreamKey {}", - protocol_pack.proxy_protocol(), - stream_key - ); - } else { - error!(logger, "{}", e); - } - error!(logger, "{}", e); - return None; - } - }; - let sequence_number = match ibcd.sequence_number_opt { + let sequence_number = match ibcd.sequence_number { Some(sequence_number) => sequence_number, None => { error!( @@ -76,6 +41,12 @@ 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 { @@ -83,8 +54,8 @@ impl ClientRequestPayloadFactory for ClientRequestPayloadFactoryReal { sequence_number, last_data: ibcd.last_data, }, - target_hostname: target_host.name, - target_port: target_host.port, + target_hostname: target_hostname_opt, + target_port, protocol: protocol_pack.proxy_protocol(), originator_public_key: cryptde.public_key().clone(), }) @@ -103,7 +74,7 @@ mod tests { use crate::bootstrapper::CryptDEPair; use crate::sub_lib::proxy_server::ProxyProtocol; use lazy_static::lazy_static; - use masq_lib::constants::{HTTP_PORT, TLS_PORT}; + use masq_lib::constants::HTTP_PORT; use masq_lib::test_utils::logging::init_test_logging; use masq_lib::test_utils::logging::TestLogHandler; use std::net::SocketAddr; @@ -114,127 +85,14 @@ mod tests { static ref CRYPTDE_PAIR: CryptDEPair = CryptDEPair::null(); } - #[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_opt: Some(1), - last_data: false, - is_clandestine: false, - data: data.clone().into(), - }; - let cryptde = CRYPTDE_PAIR.main.dup(); - 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.as_ref(), - &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_opt: Some(1), - last_data: false, - is_clandestine: false, - data: data.into(), - }; - let cryptde = CRYPTDE_PAIR.main.dup(); - 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.as_ref(), - &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_opt: Some(1), - last_data: false, - is_clandestine: false, - data: data.into(), - }; - let cryptde = CRYPTDE_PAIR.main.dup(); - 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.as_ref(), &logger); - - assert_eq!(result, None); - TestLogHandler::new().exists_log_containing(&format!("ERROR: {test_name}: No hostname information found in either client packet (Malformed HTTP request: '') or ProxyServer for protocol HTTP")); - } - - #[test] - fn logs_different_error_and_returns_none_if_connection_is_opened_and_immediately_closed() { - init_test_logging(); - let test_name = - "logs_different_error_and_returns_none_if_connection_is_opened_and_immediately_closed"; - 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_opt: Some(1), - last_data: true, - is_clandestine: false, - data: vec![], - }; - let cryptde = CRYPTDE_PAIR.main.dup(); - 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.as_ref(), &logger); - - assert_eq!(result, None); - TestLogHandler::new().exists_log_containing(&format!("WARN: {test_name}: Client opened HTTP connection and immediately closed it without sending any data")); - } - #[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_opt: Some(HTTP_PORT), - sequence_number_opt: Some(1), + reception_port: Some(HTTP_PORT), + sequence_number: Some(1), last_data: false, is_clandestine: false, data: data.clone().into(), @@ -244,7 +102,7 @@ mod tests { let logger = Logger::new("test"); let subject = Box::new(ClientRequestPayloadFactoryReal::new()); - let result = subject.make(&ibcd, stream_key, None, cryptde, &logger); + let result = subject.make(&ibcd, stream_key, cryptde, &logger); assert_eq!( result, @@ -255,7 +113,7 @@ mod tests { sequence_number: 1, last_data: false }, - target_hostname: String::from("borkoed.com"), + target_hostname: Some(String::from("borkoed.com")), target_port: 2345, protocol: ProxyProtocol::HTTP, originator_public_key: cryptde.public_key().clone(), @@ -270,8 +128,8 @@ mod tests { 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_opt: Some(1), + reception_port: Some(HTTP_PORT), + sequence_number: Some(1), last_data: false, is_clandestine: false, data: data.clone().into(), @@ -281,7 +139,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, None, cryptde, &logger); + let result = subject.make(&ibcd, stream_key, cryptde, &logger); assert_eq!( result, @@ -292,7 +150,7 @@ mod tests { sequence_number: 1, last_data: false }, - target_hostname: String::from("borkoed.com"), + target_hostname: Some(String::from("borkoed.com")), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: cryptde.public_key().clone(), @@ -325,8 +183,8 @@ mod tests { let ibcd = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - sequence_number_opt: Some(0), - reception_port_opt: Some(443), + sequence_number: Some(0), + reception_port: Some(443), last_data: false, is_clandestine: false, data: data.clone().into(), @@ -336,7 +194,7 @@ mod tests { let logger = Logger::new("test"); let subject = Box::new(ClientRequestPayloadFactoryReal::new()); - let result = subject.make(&ibcd, stream_key, None, cryptde, &logger); + let result = subject.make(&ibcd, stream_key, cryptde, &logger); assert_eq!( result, @@ -347,8 +205,8 @@ mod tests { sequence_number: 0, last_data: false }, - target_hostname: String::from("server.com"), - target_port: TLS_PORT, + target_hostname: Some(String::from("server.com")), + target_port: 443, protocol: ProxyProtocol::TLS, originator_public_key: cryptde.public_key().clone(), }) @@ -357,7 +215,6 @@ 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 @@ -376,10 +233,10 @@ mod tests { let ibcd = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port_opt: Some(443), + reception_port: Some(443), last_data: true, is_clandestine: false, - sequence_number_opt: Some(0), + sequence_number: Some(0), data: data.clone().into(), }; let cryptde = CRYPTDE_PAIR.main.as_ref(); @@ -387,10 +244,23 @@ 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, None, cryptde, &logger); + let result = subject.make(&ibcd, stream_key, cryptde, &logger); - assert_eq!(result, None); - TestLogHandler::new().exists_log_containing(&format!("ERROR: {test_name}: No hostname information found in either client packet (ClientHello with no SNI extension) or ProxyServer for protocol TLS")); + 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(), + }) + ); } #[test] @@ -400,8 +270,8 @@ mod tests { let ibcd = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - sequence_number_opt: Some(0), - reception_port_opt: None, + sequence_number: Some(0), + reception_port: None, last_data: false, is_clandestine: false, data: vec![0x10, 0x11, 0x12], @@ -411,7 +281,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, None, cryptde, &logger); + let result = subject.make(&ibcd, stream_key, cryptde, &logger); assert_eq!(result, None); TestLogHandler::new().exists_log_containing( @@ -426,8 +296,8 @@ mod tests { let ibcd = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port_opt: Some(1234), - sequence_number_opt: Some(0), + reception_port: Some(1234), + sequence_number: Some(0), last_data: false, is_clandestine: true, data: vec![0x10, 0x11, 0x12], @@ -437,7 +307,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, None, cryptde, &logger); + let result = subject.make(&ibcd, stream_key, 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]")); @@ -445,14 +315,13 @@ 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_opt: Some(HTTP_PORT), - sequence_number_opt: Some(1), + reception_port: Some(HTTP_PORT), + sequence_number: Some(1), last_data: false, - data: data.into(), + data: vec![0x10, 0x11, 0x12], is_clandestine: false, }; let cryptde = CRYPTDE_PAIR.main.as_ref(); @@ -463,7 +332,6 @@ mod tests { .make( &ibcd, StreamKey::make_meaningless_stream_key(), - None, cryptde, &logger, ) @@ -476,26 +344,25 @@ 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_opt: Some(HTTP_PORT), + reception_port: Some(HTTP_PORT), last_data: false, is_clandestine: false, - sequence_number_opt: None, - data: data.into(), + sequence_number: None, + data: vec![1, 3, 5, 7], }; let cryptde = CRYPTDE_PAIR.main.as_ref(); 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, None, cryptde, &logger); + let result = subject.make(&ibcd, stream_key, cryptde, &logger); assert_eq!(result, None); TestLogHandler::new().exists_log_containing(&format!( - "ERROR: {test_name}: internal error: got IBCD with no sequence number and 47 bytes" + "ERROR: {test_name}: internal error: got IBCD with no sequence number and 4 bytes" )); } } diff --git a/node/src/proxy_server/http_protocol_pack.rs b/node/src/proxy_server/http_protocol_pack.rs index ef8940c6d6..b611f2be30 100644 --- a/node/src/proxy_server/http_protocol_pack.rs +++ b/node/src/proxy_server/http_protocol_pack.rs @@ -1,8 +1,7 @@ // Copyright (c) 2019, MASQ (https://masq.ai) and/or its affiliates. All rights reserved. -use crate::proxy_server::protocol_pack::{ProtocolPack, ServerImpersonator}; +use crate::proxy_server::protocol_pack::{Host, ProtocolPack, ServerImpersonator}; use crate::proxy_server::server_impersonator_http::ServerImpersonatorHttp; use crate::sub_lib::cryptde::PlainData; -use crate::sub_lib::host::Host; use crate::sub_lib::proxy_server::ProxyProtocol; use lazy_static::lazy_static; use masq_lib::constants::HTTP_PORT; @@ -13,7 +12,6 @@ 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 { @@ -35,14 +33,6 @@ impl ProtocolPack for HttpProtocolPack { fn server_impersonator(&self) -> Box { Box::new(ServerImpersonatorHttp {}) } - - fn describe_packet(&self, data: &PlainData) -> String { - if data.as_slice().starts_with(b"HTTP/") { - self.describe_response(data) - } else { - self.describe_request(data) - } - } } impl HttpProtocolPack { @@ -110,82 +100,6 @@ impl HttpProtocolPack { Ok(port) => Ok(port), } } - - fn describe_request(&self, data: &PlainData) -> String { - let first_line_end = data - .as_slice() - .iter() - .position(|&b| b == b'\r') - .unwrap_or(data.len()); - let first_line = &data.as_slice()[0..first_line_end]; - let mut parts = first_line.split(|&b| b == b' '); - if let (Some(method_bytes), Some(path_bytes), Some(http_version_bytes)) = - (parts.next(), parts.next(), parts.next()) - { - let method = Self::from_utf8(method_bytes); - let path = Self::from_utf8(path_bytes); - let http_version = Self::from_utf8(http_version_bytes); - if let Some(host) = self.find_host(data) { - return if path.starts_with('/') { - format!( - "{} {} request to {}{}", - http_version, method, host.name, path - ) - } else { - format!("{} {} request to {}", http_version, method, path) - }; - } else { - return format!( - "{} {} request to unknown host: {}", - http_version, method, path - ); - } - } - format!( - "Malformed HTTP request: {}", - Self::truncate_data_as_string(data, 50) - ) - } - - fn describe_response(&self, data: &PlainData) -> String { - let first_line_end = data - .as_slice() - .iter() - .position(|&b| b == b'\r') - .unwrap_or(data.as_slice().len()); - let first_line = &data.as_slice()[0..first_line_end]; - let mut parts = first_line.split(|&b| b == b' '); - if let (Some(http_version_bytes), Some(status_code_bytes), Some(status_text_bytes)) = - (parts.next(), parts.next(), parts.next()) - { - let http_with_version = Self::from_utf8(http_version_bytes); - let status_code = Self::from_utf8(status_code_bytes); - let status_text = Self::from_utf8(status_text_bytes); - return format!( - "{} response with status {} {}", - http_with_version, status_code, status_text - ); - } - format!( - "Malformed HTTP response: {}", - Self::truncate_data_as_string(data, 50) - ) - } - - fn truncate_data_as_string(data: &PlainData, truncate_at: usize) -> String { - if data.as_slice().len() > truncate_at { - format!( - "'{}'...", - String::from_utf8_lossy(&data.as_slice()[0..truncate_at]) - ) - } else { - format!("'{}'", String::from_utf8_lossy(data.as_slice())) - } - } - - fn from_utf8(bytes: &[u8]) -> String { - String::from_utf8_lossy(bytes).to_string() - } } #[cfg(test)] @@ -422,83 +336,4 @@ mod tests { let data = b"CONNECTX"; assert!(!HttpProtocolPack::is_connect(data)); } - - #[test] - fn describe_packet_works_on_get_request_with_header_host() { - let data = - PlainData::new(b"GET /index.html?item=booga HTTP/1.1\r\nHost: www.example.com\r\n\r\n"); - let subject = HttpProtocolPack {}; - - let result = subject.describe_packet(&data); - - assert_eq!( - result, - "HTTP/1.1 GET request to www.example.com/index.html?item=booga" - ); - } - - #[test] - fn describe_packet_works_on_post_request_with_url_host() { - let data = PlainData::new( - b"POST www.example.com/person/1234 HTTP/1.1\r\nContent-Length: 2\r\n\r\n{}", - ); - let subject = HttpProtocolPack {}; - - let result = subject.describe_packet(&data); - - assert_eq!( - result, - "HTTP/1.1 POST request to www.example.com/person/1234" - ); - } - - #[test] - fn describe_packet_works_on_unexpected_request_with_unspecified_host() { - let data = PlainData::new(b"BOOGA /person/1234 HTTP/1.1\r\nContent-Length: 2\r\n\r\n{}"); - let subject = HttpProtocolPack {}; - - let result = subject.describe_packet(&data); - - assert_eq!( - result, - "HTTP/1.1 BOOGA request to unknown host: /person/1234" - ); - } - - #[test] - fn describe_packet_works_on_malformed_request() { - let data = PlainData::new(b"Fourscore_and_seven_years_ago_our_fathers_brought_forth_on_this_continent_a_new_nation,_conceived_in_liberty_and_dedicated_to_the_proposition_that_all_men_are_created_equal."); - let subject = HttpProtocolPack {}; - - let result = subject.describe_packet(&data); - - assert_eq!( - result, - "Malformed HTTP request: 'Fourscore_and_seven_years_ago_our_fathers_brought_'..." - ); - } - - #[test] - fn describe_packet_works_on_200_response() { - let data = - PlainData::new(b"HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n"); - let subject = HttpProtocolPack {}; - - let result = subject.describe_packet(&data); - - assert_eq!(result, "HTTP/1.1 response with status 200 OK"); - } - - #[test] - fn describe_packet_works_on_malformed_response() { - let data = PlainData::new(b"HTTP/Fourscore_and_seven_years_ago_our_fathers_brought_forth_on_this_continent_a_new_nation,_conceived_in_liberty_and_dedicated_to_the_proposition_that_all_men_are_created_equal."); - let subject = HttpProtocolPack {}; - - let result = subject.describe_packet(&data); - - assert_eq!( - result, - "Malformed HTTP response: 'HTTP/Fourscore_and_seven_years_ago_our_fathers_bro'..." - ); - } } diff --git a/node/src/proxy_server/mod.rs b/node/src/proxy_server/mod.rs index 68d7b1ebc3..459acf668c 100644 --- a/node/src/proxy_server/mod.rs +++ b/node/src/proxy_server/mod.rs @@ -24,7 +24,6 @@ use crate::sub_lib::cryptde::PublicKey; use crate::sub_lib::dispatcher::InboundClientData; use crate::sub_lib::dispatcher::{Endpoint, StreamShutdownMsg}; use crate::sub_lib::hopper::{ExpiredCoresPackage, IncipientCoresPackage}; -use crate::sub_lib::host::Host; use crate::sub_lib::neighborhood::RouteQueryResponse; use crate::sub_lib::neighborhood::{ExpectedService, UpdateNodeRecordMetadataMessage}; use crate::sub_lib::neighborhood::{ExpectedServices, RatePack}; @@ -32,13 +31,14 @@ 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::{AddReturnRouteMessage, StreamKeyPurge}; use crate::sub_lib::proxy_server::{ AddRouteResultMessage, ClientRequestPayload_0v1, ProxyProtocol, }; 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,13 +53,15 @@ use masq_lib::utils::MutabilityConflictHelper; use regex::Regex; 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; pub const CRASH_KEY: &str = "PROXYSERVER"; +pub const RETURN_ROUTE_TTL: Duration = Duration::from_secs(120); + pub const STREAM_KEY_PURGE_DELAY: Duration = Duration::from_secs(30); -pub const DNS_FAILURE_RETRIES: usize = 3; struct ProxyServerOutSubs { dispatcher: Recipient, @@ -67,31 +69,27 @@ 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>, } -#[derive(Clone, Debug)] -struct StreamInfo { - tunneled_host_opt: Option, - dns_failure_retry_opt: Option, - route_opt: Option, - protocol_opt: Option, - time_to_live_opt: Option, -} - pub struct ProxyServer { subs: Option, client_request_payload_factory: Box, stream_key_factory: Box, keys_and_addrs: BidiHashMap, - stream_info: HashMap, + tunneled_hosts: HashMap, + dns_failure_retries: HashMap, + stream_key_routes: HashMap, + stream_key_ttl: HashMap, is_decentralized: bool, consuming_wallet_balance: Option, cryptde_pair: CryptDEPair, crashable: bool, logger: Logger, + route_ids_to_return_routes: TtlHashMap, browser_proxy_sequence_offset: bool, inbound_client_data_helper_opt: Option>, stream_key_purge_delay: Duration, @@ -113,6 +111,7 @@ 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, @@ -129,19 +128,64 @@ impl Handler for ProxyServer { self.tls_connect(&msg); self.browser_proxy_sequence_offset = true; } else if let Err(e) = - // NOTE: I removed a 'false' parameter here for retire_stream_key because I think it was wrong. - self.help(|helper, proxy| helper.handle_normal_client_data(proxy, msg)) + self.help(|helper, proxy| helper.handle_normal_client_data(proxy, msg, false)) { error!(self.logger, "{}", e) } } } +impl Handler for ProxyServer { + type Result = (); + + fn handle(&mut self, msg: AddReturnRouteMessage, _ctx: &mut Self::Context) -> Self::Result { + self.route_ids_to_return_routes + .insert(msg.return_route_id, msg); + } +} + +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 = (); fn handle(&mut self, msg: AddRouteResultMessage, _ctx: &mut Self::Context) -> Self::Result { - self.handle_add_route_result_message(msg) + 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); + }); + + 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); + } + } } } @@ -212,18 +256,21 @@ impl ProxyServer { crashable: bool, is_running_in_integration_test: bool, ) -> ProxyServer { - let ps_logger = Logger::new("ProxyServer"); ProxyServer { subs: None, client_request_payload_factory: Box::new(ClientRequestPayloadFactoryReal::new()), stream_key_factory: Box::new(StreamKeyFactoryReal {}), keys_and_addrs: BidiHashMap::new(), - stream_info: HashMap::new(), + tunneled_hosts: HashMap::new(), + dns_failure_retries: HashMap::new(), + stream_key_routes: HashMap::new(), + stream_key_ttl: HashMap::new(), is_decentralized, consuming_wallet_balance, cryptde_pair, crashable, - logger: ps_logger, + logger: Logger::new("ProxyServer"), + route_ids_to_return_routes: TtlHashMap::new(RETURN_ROUTE_TTL), browser_proxy_sequence_offset: false, inbound_client_data_helper_opt: Some(Box::new(IBCDHelperReal::new())), stream_key_purge_delay: STREAM_KEY_PURGE_DELAY, @@ -237,6 +284,7 @@ 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), @@ -244,46 +292,24 @@ impl ProxyServer { } } - fn stream_info(&self, stream_key: &StreamKey) -> Option<&StreamInfo> { - match self.stream_info.get(stream_key) { - None => { - error!( - self.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( - stream_info: &mut StreamInfo, + &mut self, stream_key: &StreamKey, ) -> Result { - match stream_info.dns_failure_retry_opt.take() { + match self.dns_failure_retries.remove(stream_key) { None => Err(format!( - "No DNSFailureRetry entry found for the stream_key: {:?}", + "No entry found inside dns_failure_retries hashmap 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, + ) -> DNSFailureRetry { let args = TransmitToHopperArgs::new( self, retry.unsuccessful_request.clone(), @@ -291,6 +317,7 @@ 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 @@ -298,7 +325,13 @@ 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, + add_return_route_sub, + route_source, + proxy_server_sub, + ); + retry } fn retire_stream_key(&mut self, stream_key: &StreamKey) { @@ -309,7 +342,7 @@ impl ProxyServer { &self, client_addr: SocketAddr, proxy_protocol: ProxyProtocol, - hostname: String, + hostname_opt: Option, ) { self.subs .as_ref() @@ -318,261 +351,119 @@ impl ProxyServer { .try_send(TransmitDataMsg { endpoint: Endpoint::Socket(client_addr), last_data: true, - sequence_number_opt: Some(0), // DNS resolution errors always happen on the first request + 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), + .dns_resolution_failure_response(hostname_opt), }) .expect("Dispatcher is dead"); } - 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: &[ExpectedService]) -> Option { - response_services - .iter() - .find_map(|service| service.exit_node_key_opt()) - } - - fn handle_add_route_result_message(&mut self, msg: AddRouteResultMessage) { - // We can't access self.logger for logging once we obtain mutable access to a stream_info - // element. So we create a delayed_log closure that we can call with self.logger after - // we've finished with the mutable borrow. We have to use #[allow(unused_assignments)] - // because Rust can't figure out that delayed_log will always be assigned before it's used. - type DelayedLogArgs = Box; - #[allow(unused_assignments)] - let mut delayed_log: DelayedLogArgs = Box::new(|_, _, _, _, _| {}); - 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", - 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: String, - stream_key: StreamKey, - retries_left: usize, - _: String| { - 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) => { - message = e; - delayed_log = Box::new( - move |logger: &Logger, - 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, - 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, - stream_key, - retries_left, - message, - ); - } - fn handle_dns_resolve_failure(&mut self, msg: &ExpiredCoresPackage) { - let response = &msg.payload; - - // 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.remove(&response.stream_key) { - Some(info) => info, - None => { - error!( - self.logger, - "Discarding DnsResolveFailure message from an unrecognized stream key {:?}", - &response.stream_key - ); - return; - } + let return_route_info = + match self.get_return_route_info(&msg.remaining_route, "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.cryptde_pair.main.as_ref().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 mut restore_stream_info = true; - 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 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.cryptde_pair.main.public_key().clone() - } else { - match Self::find_exit_node_key(response_services) { - Some(exit_public_key) => exit_public_key, - 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) => { - 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!( + if let Some(server_name) = hostname_opt.clone() { + 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, + }, + }) + .expect("Neighborhood is dead"); + } else { + error!( self.logger, - "Handling DNS failure for hostname {:?} - stream key: {} retries left: {}", - retry_ref.unsuccessful_request.target_hostname, - &response.stream_key, - retry_ref.retries_left + "Exit node {exit_public_key} complained of DNS failure, but was given no hostname to resolve." ); - 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, - route_query_response.host.name.clone(), + // 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 ); + return; } + }; + 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); } else { - error!( - self.logger, - "While handling ExpiredCoresPackage: No DNSFailureRetry entry found for the stream_key: {:?}", - &response.stream_key + self.retire_stream_key(&response.stream_key); + self.send_dns_failure_response_to_the_browser( + client_addr, + return_route_info.protocol, + hostname_opt, ); - return; } } None => { error!(self.logger, "Discarding DnsResolveFailure message for {} from an unrecognized stream key {:?}", - route_query_response.host.name, + hostname_opt.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) { - let stream_key_purge_delay = self.stream_key_purge_delay; - // We can't access self.logger for logging once we obtain mutable access to a stream_info - // element. So we create a delayed_log closure that we can call with self.logger after - // we've finished with the mutable borrow. - 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); + 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"); } fn log_straggling_packet( @@ -597,6 +488,14 @@ impl ProxyServer { &mut self, msg: ExpiredCoresPackage, ) { + debug!( + self.logger, + "ExpiredCoresPackage remaining_route: {}", + msg.remaining_route.to_string(vec![ + self.cryptde_pair.main.as_ref(), + self.cryptde_pair.main.as_ref() + ]) + ); let payload_data_len = msg.payload_len; let response = msg.payload; debug!( @@ -604,70 +503,68 @@ 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 expected_services = match self.get_expected_return_services(&response.stream_key) { - Some(expected_services) => expected_services, - None => return, - }; + let return_route_info = + match self.get_return_route_info(&msg.remaining_route, "client response") { + Some(rri) => rri, + None => return, + }; self.report_response_services_consumed( - &expected_services, + &return_route_info, response.sequenced_packet.data.len(), payload_data_len, ); let stream_key = response.stream_key; - if let Some(info) = self.stream_info_mut(&stream_key) { - if let Err(e) = ProxyServer::remove_dns_failure_retry(info, &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: {}", - &stream_key, - e - ); + "No DNS retry entry found for stream key: {} during a successful attempt", + &response.stream_key + ) } } - if let Some(info) = self.stream_info(&stream_key) { - if let Some(old_timestamp) = info.time_to_live_opt { - self.log_straggling_packet(&stream_key, payload_data_len, &old_timestamp) - } else { - match self.keys_and_addrs.a_to_b(&stream_key) { - Some(socket_addr) => { - let last_data = response.sequenced_packet.last_data; - let sequence_number_opt = Some( - response.sequenced_packet.sequence_number - + self.browser_proxy_sequence_offset as u64, - ); - self.subs - .as_ref() - .expect("Dispatcher unbound in ProxyServer") - .dispatcher - .try_send(TransmitDataMsg { - endpoint: Endpoint::Socket(socket_addr), - last_data, - sequence_number_opt, - data: response.sequenced_packet.data, - }) - .expect("Dispatcher is dead"); - if last_data { - self.purge_stream_key( - &stream_key, - "last data received from the exit node", - ); - } - } - None => { - // TODO GH-608: It would be really nice to be able to send an InboundClientData with last_data: true - // back to the ProxyClient (and the distant server) so that the server could shut down - // its stream, since the browser has shut down _its_ stream and no more data will - // ever be accepted from the server on that stream; but we don't have enough information - // to do so, since our stream key has been purged and all the information it keyed - // is gone. Sorry, server! - warning!(self.logger, - "Discarding {}-byte packet {} from an unrecognized stream key: {:?}; can't send response back to client", - response.sequenced_packet.data.len(), - response.sequenced_packet.sequence_number, - response.stream_key, - ) + if let Some(old_timestamp) = self.stream_key_ttl.get(&stream_key) { + self.log_straggling_packet(&stream_key, payload_data_len, old_timestamp) + } else { + match self.keys_and_addrs.a_to_b(&stream_key) { + Some(socket_addr) => { + let last_data = response.sequenced_packet.last_data; + let sequence_number = Some( + response.sequenced_packet.sequence_number + + self.browser_proxy_sequence_offset as u64, + ); + self.subs + .as_ref() + .expect("Dispatcher unbound in ProxyServer") + .dispatcher + .try_send(TransmitDataMsg { + endpoint: Endpoint::Socket(socket_addr), + last_data, + sequence_number, + data: response.sequenced_packet.data, + }) + .expect("Dispatcher is dead"); + if last_data { + self.purge_stream_key(&stream_key, "last data received from the exit node"); } } + None => { + // TODO GH-608: It would be really nice to be able to send an InboundClientData with last_data: true + // back to the ProxyClient (and the distant server) so that the server could shut down + // its stream, since the browser has shut down _its_ stream and no more data will + // ever be accepted from the server on that stream; but we don't have enough information + // to do so, since our stream key has been purged and all the information it keyed + // is gone. Sorry, server! + warning!(self.logger, + "Discarding {}-byte packet {} from an unrecognized stream key: {:?}; can't send response back to client", + response.sequenced_packet.data.len(), + response.sequenced_packet.sequence_number, + response.stream_key, + ) + } } } } @@ -677,10 +574,7 @@ impl ProxyServer { match http_data { Some(ref host) if host.port == TLS_PORT => { let stream_key = self.find_or_generate_stream_key(msg); - match self.stream_info_mut(&stream_key) { - None => return, - Some(stream_info) => stream_info.tunneled_host_opt = Some(host.name.clone()), - } + self.tunneled_hosts.insert(stream_key, host.name.clone()); self.subs .as_ref() .expect("Dispatcher unbound in ProxyServer") @@ -688,7 +582,7 @@ impl ProxyServer { .try_send(TransmitDataMsg { endpoint: Endpoint::Socket(msg.client_addr), last_data: false, - sequence_number_opt: msg.sequence_number_opt, + sequence_number: msg.sequence_number, data: b"HTTP/1.1 200 OK\r\n\r\n".to_vec(), }) .expect("Dispatcher is dead"); @@ -701,7 +595,7 @@ impl ProxyServer { .try_send(TransmitDataMsg { endpoint: Endpoint::Socket(msg.client_addr), last_data: true, - sequence_number_opt: msg.sequence_number_opt, + sequence_number: msg.sequence_number, data: b"HTTP/1.1 400 Bad Request\r\nContent-Length: 0\r\n\r\n".to_vec(), }) .expect("Dispatcher is dead"); @@ -742,13 +636,14 @@ impl ProxyServer { let ibcd = InboundClientData { timestamp: SystemTime::now(), client_addr: msg.peer_addr, - reception_port_opt: Some(nca.reception_port), + reception_port: Some(nca.reception_port), last_data: true, is_clandestine: false, - sequence_number_opt: Some(nca.sequence_number), + sequence_number: Some(nca.sequence_number), data: vec![], }; - if let Err(e) = self.help(|helper, proxy| helper.handle_normal_client_data(proxy, ibcd)) + if let Err(e) = + self.help(|helper, proxy| helper.handle_normal_client_data(proxy, ibcd, true)) { error!(self.logger, "{}", e) }; @@ -772,16 +667,6 @@ impl ProxyServer { ibcd.client_addr, ); self.keys_and_addrs.insert(stream_key, ibcd.client_addr); - self.stream_info.insert( - 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, "find_or_generate_stream_key() inserted new key {} for {}", @@ -799,7 +684,9 @@ impl ProxyServer { "Retiring stream key {} due to {}", &stream_key, reason ); let _ = self.keys_and_addrs.remove_a(stream_key); - let _ = self.stream_info.remove(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); } fn make_payload( @@ -807,17 +694,10 @@ impl ProxyServer { ibcd: InboundClientData, stream_key: &StreamKey, ) -> Result { - let stream_info_opt = self.stream_info.get(stream_key); - 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 { + let tunnelled_host = self.tunneled_hosts.get(stream_key); + let new_ibcd = match tunnelled_host { Some(_) => InboundClientData { - reception_port_opt: Some(TLS_PORT), + reception_port: Some(443), ..ibcd }, None => ibcd, @@ -825,14 +705,13 @@ impl ProxyServer { match self.client_request_payload_factory.make( &new_ibcd, *stream_key, - host_opt, self.cryptde_pair.alias.as_ref(), &self.logger, ) { None => Err("Couldn't create ClientRequestPayload".to_string()), - Some(payload) => match tunnelled_host_opt { + Some(payload) => match tunnelled_host { Some(hostname) => Ok(ClientRequestPayload_0v1 { - target_hostname: hostname, + target_hostname: Some(hostname.clone()), ..payload }), None => Ok(payload), @@ -842,10 +721,24 @@ 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, _) => { + ExpectedServices::RoundTrip(over, back, return_route_id) => { + let return_route_info = AddReturnRouteMessage { + 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: {:?}", return_route_info + ); + 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"), @@ -998,7 +891,7 @@ impl ProxyServer { source_addr: SocketAddr, dispatcher: &Recipient, ) -> String { - let target_hostname = payload.target_hostname.clone(); + let target_hostname = ProxyServer::hostname(&payload); let stream_key = payload.stream_key; ProxyServer::send_route_failure(payload, source_addr, dispatcher); format!( @@ -1014,45 +907,56 @@ impl ProxyServer { ) { let data = from_protocol(payload.protocol) .server_impersonator() - .route_query_failure_response(&payload.target_hostname); + .route_query_failure_response(&ProxyServer::hostname(&payload)); let msg = TransmitDataMsg { endpoint: Endpoint::Socket(source_addr), last_data: true, - sequence_number_opt: Some(0), + sequence_number: Some(0), data, }; dispatcher.try_send(msg).expect("Dispatcher is dead"); } - fn get_expected_return_services( - &mut self, - stream_key: &StreamKey, - ) -> Option> { - match self.stream_info(stream_key) { + fn hostname(payload: &ClientRequestPayload_0v1) -> String { + match payload.target_hostname { + Some(ref thn) => thn.clone(), + None => "".to_string(), + } + } + + fn get_return_route_info( + &self, + remaining_route: &Route, + source: &str, + ) -> Option> { + let mut mut_remaining_route = remaining_route.clone(); + mut_remaining_route + .shift(self.cryptde_pair.main.as_ref()) + .expect("Internal error: remaining route in ProxyServer with no hops"); + let return_route_id = match mut_remaining_route.id(self.cryptde_pair.main.as_ref()) { + Ok(rri) => 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 pay for return services consumed: received response with unrecognized stream key {:?}. Ignoring", stream_key); + error!(self.logger, "Can't report services consumed: received response with bogus return-route ID {} for {}. Ignoring", return_route_id, source); None } - Some(stream_info) => { - let route = stream_info - .route_opt - .as_ref() - .unwrap_or_else(|| panic!("Internal error: Request was sent over stream {:?} without an associated route being stored in stream_info: can't pay", stream_key)); - 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, - expected_services: &[ExpectedService], + return_route_info: &AddReturnRouteMessage, exit_size: usize, routing_size: usize, ) { - let exit_service_report: ExitServiceSearch = expected_services + let exit_service_report: ExitServiceSearch = return_route_info + .expected_services .iter() .filter(|service| !matches!(service, ExpectedService::Nothing)) .fold(ZeroHop, |acc, service| { @@ -1078,7 +982,8 @@ impl ProxyServer { ZeroHop => return, Definite(report) => report, }; - let routing_service_reports = expected_services + let routing_service_reports = return_route_info + .expected_services .iter() .flat_map(|service| match service { ExpectedService::Routing(_, wallet, rate_pack) => Some(RoutingServiceConsumed { @@ -1117,11 +1022,13 @@ pub trait IBCDHelper { &self, proxy_s: &mut ProxyServer, msg: InboundClientData, + retire_stream_key: bool, ) -> Result<(), String>; fn request_route_and_transmit( &self, args: TransmitToHopperArgs, + add_return_route_sub: Recipient, route_source: Recipient, proxy_server_sub: Recipient, ); @@ -1131,7 +1038,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>, ); @@ -1142,13 +1049,18 @@ impl RouteQueryResponseResolver for RouteQueryResponseResolverReal { fn resolve_message( &self, args: TransmitToHopperArgs, + add_return_route_sub: Recipient, proxy_server_sub: Recipient, route_result_opt: Result, MailboxError>, ) { 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, + add_return_route_sub, + route_query_response.clone(), + ) { Ok(()) => Ok(route_query_response), Err(e) => Err(e), } @@ -1190,16 +1102,15 @@ impl IBCDHelperReal { } } } - impl IBCDHelper for IBCDHelperReal { fn handle_normal_client_data( &self, - proxy_server: &mut ProxyServer, + proxy: &mut ProxyServer, msg: InboundClientData, + retire_stream_key: bool, ) -> Result<(), String> { let client_addr = msg.client_addr; - let last_data = msg.last_data; - if proxy_server.consuming_wallet_balance.is_none() && proxy_server.is_decentralized { + if proxy.consuming_wallet_balance.is_none() && proxy.is_decentralized { let protocol_pack = match from_ibcd(&msg) { Err(e) => return Err(e), Ok(pp) => pp, @@ -1210,25 +1121,25 @@ impl IBCDHelper for IBCDHelperReal { let msg = TransmitDataMsg { endpoint: Endpoint::Socket(client_addr), last_data: true, - sequence_number_opt: Some(0), + sequence_number: Some(0), data, }; - proxy_server + proxy .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_server.find_or_generate_stream_key(&msg); + let stream_key = proxy.find_or_generate_stream_key(&msg); let timestamp = msg.timestamp; - let payload = match proxy_server.make_payload(msg, &stream_key) { + let payload = match proxy.make_payload(msg, &stream_key) { Ok(payload) => { - 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)); + 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)); + } } } payload @@ -1236,47 +1147,38 @@ impl IBCDHelper for IBCDHelperReal { Err(e) => return Err(e), }; - { - 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() { - let dns_failure_retry = DNSFailureRetry { - unsuccessful_request: payload.clone(), - 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); - } + 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 args = - TransmitToHopperArgs::new(proxy_server, payload, client_addr, timestamp, last_data); + TransmitToHopperArgs::new(proxy, payload, client_addr, timestamp, retire_stream_key); + let add_return_route_sub = proxy.out_subs("ProxysServer").add_return_route.clone(); let pld = &args.payload; - let stream_info = proxy_server - .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 { + if let Some(route_query_response) = proxy.stream_key_routes.get(&pld.stream_key) { debug!( - proxy_server.logger, + proxy.logger, "Transmitting down existing stream {}: sequence {}, length {}", pld.stream_key, pld.sequenced_packet.sequence_number, pld.sequenced_packet.data.len() ); let route_query_response = route_query_response.clone(); - ProxyServer::try_transmit_to_hopper(args, route_query_response) + ProxyServer::try_transmit_to_hopper(args, add_return_route_sub, route_query_response) } else { - 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); + 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, + ); Ok(()) } } @@ -1284,11 +1186,12 @@ impl IBCDHelper for IBCDHelperReal { fn request_route_and_transmit( &self, args: TransmitToHopperArgs, + add_return_route_sub: Recipient, neighborhood_sub: Recipient, proxy_server_sub: Recipient, ) { let pld = &args.payload; - let host = Host::new(&pld.target_hostname, pld.target_port); + let hostname_opt = pld.target_hostname.clone(); let logger = args.logger.clone(); debug!( logger, @@ -1303,11 +1206,16 @@ impl IBCDHelper for IBCDHelperReal { tokio::spawn( neighborhood_sub .send(RouteQueryMessage::data_indefinite_route_request( - host, + hostname_opt, payload_size, )) .then(move |route_result| { - message_resolver.resolve_message(args, proxy_server_sub, route_result); + message_resolver.resolve_message( + args, + add_return_route_sub, + proxy_server_sub, + route_result, + ); Ok(()) }), ); @@ -1446,7 +1354,6 @@ impl Hostname { #[cfg(test)] mod tests { use super::*; - use crate::blockchain::bip32::Bip32EncryptionKeyProvider; use crate::bootstrapper::CryptDEPair; use crate::match_every_type_id; use crate::proxy_server::protocol_pack::ServerImpersonator; @@ -1460,7 +1367,6 @@ mod tests { use crate::sub_lib::dispatcher::Component; use crate::sub_lib::hop::LiveHop; use crate::sub_lib::hopper::MessageType; - use crate::sub_lib::host::Host; use crate::sub_lib::neighborhood::ExpectedServices; use crate::sub_lib::neighborhood::{ExpectedService, DEFAULT_RATE_PACK}; use crate::sub_lib::proxy_client::{ClientResponsePayload_0v1, DnsResolveFailure_0v1}; @@ -1469,6 +1375,7 @@ 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_meaningless_route; use crate::test_utils::make_paying_wallet; @@ -1483,6 +1390,7 @@ mod tests { }; use crate::test_utils::zero_hop_route_response; use actix::System; + use crossbeam_channel::unbounded; use lazy_static::lazy_static; use masq_lib::constants::{HTTP_PORT, TLS_PORT}; use masq_lib::test_utils::logging::init_test_logging; @@ -1551,6 +1459,7 @@ mod tests { fn resolve_message( &self, args: TransmitToHopperArgs, + _add_return_route_sub: Recipient, _proxy_server_sub: Recipient, route_result: Result, MailboxError>, ) { @@ -1577,59 +1486,11 @@ mod tests { self } } - - 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"); + assert_eq!(RETURN_ROUTE_TTL, Duration::from_secs(120)); assert_eq!(STREAM_KEY_PURGE_DELAY, Duration::from_secs(30)); - assert_eq!(DNS_FAILURE_RETRIES, 3); } const STANDARD_CONSUMING_WALLET_BALANCE: i64 = 0; @@ -1643,6 +1504,7 @@ 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), @@ -1686,9 +1548,16 @@ mod tests { } } - fn return_route(cryptde: &dyn CryptDE) -> Route { + fn return_route_with_id(cryptde: &dyn CryptDE, return_route_id: u32) -> Route { + let cover_hop = make_cover_hop(cryptde); + let id_hop = cryptde + .encode( + &cryptde.public_key(), + &PlainData::from(serde_cbor::ser::to_vec(&return_route_id).unwrap()), + ) + .unwrap(); Route { - hops: vec![make_cover_hop(cryptde)], + hops: vec![cover_hop, id_hop], } } @@ -1707,7 +1576,7 @@ mod tests { #[derive(Default)] struct IBCDHelperMock { - handle_normal_client_data_params: Arc>>, + handle_normal_client_data_params: Arc>>, handle_normal_client_data_results: RefCell>>, } @@ -1716,11 +1585,12 @@ mod tests { &self, _proxy_s: &mut ProxyServer, msg: InboundClientData, + retire_stream_key: bool, ) -> Result<(), String> { self.handle_normal_client_data_params .lock() .unwrap() - .push(msg); + .push((msg, retire_stream_key)); self.handle_normal_client_data_results .borrow_mut() .remove(0) @@ -1729,6 +1599,7 @@ mod tests { fn request_route_and_transmit( &self, _args: TransmitToHopperArgs, + _add_return_route_sub: Recipient, _route_source: Recipient, _proxy_server_sub: Recipient, ) { @@ -1739,7 +1610,7 @@ mod tests { impl IBCDHelperMock { fn handle_normal_client_data_params( mut self, - params: &Arc>>, + params: &Arc>>, ) -> Self { self.handle_normal_client_data_params = params.clone(); self @@ -1754,111 +1625,33 @@ mod tests { } #[test] - fn get_expected_services_produces_nothing_if_nothing_exists() { - let mut subject = ProxyServer::new( - CRYPTDE_PAIR.clone(), - true, - Some(STANDARD_CONSUMING_WALLET_BALANCE), - false, - false, - ); - let stream_key = StreamKey::make_meaningless_stream_key(); - - let result = subject.get_expected_return_services(&stream_key); - - assert!( - result.is_none(), - "Expected no expected services, but got: {:?}", - result - ); - } - - #[test] - fn get_expected_services_produces_rri_when_it_exists() { - let mut subject = ProxyServer::new( - CRYPTDE_PAIR.clone(), - 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()); - subject.stream_info.insert( - stream_key.clone(), - StreamInfoBuilder::new() - .route(RouteQueryResponse { - route: make_meaningless_route(&CRYPTDE_PAIR), - expected_services: expected_services.clone(), - host: Host::new("booga.com", TLS_PORT), - }) - .protocol(ProxyProtocol::TLS) - .build(), - ); - - let result = subject.get_expected_return_services(&stream_key).unwrap(); - - assert_eq!(result, back_services); - } - - #[test] - #[should_panic( - expected = "Internal error: Request was sent over stream Y29uc3RhbnQgZm9yIHBhbmljIG0 without an associated route being stored in stream_info: can't pay" - )] - fn get_expected_services_panics_if_stream_info_exists_but_has_no_route() { - let mut subject = ProxyServer::new( - CRYPTDE_PAIR.clone(), - true, - Some(STANDARD_CONSUMING_WALLET_BALANCE), - false, - false, - ); - let stream_key = StreamKey::from_bytes(b"constant for panic message"); - subject.stream_info.insert( - stream_key.clone(), - StreamInfoBuilder::new() - // no route_opt: problem - .protocol(ProxyProtocol::TLS) - .build(), - ); - - let _ = subject.get_expected_return_services(&stream_key).unwrap(); - } - - #[test] - fn proxy_server_receives_http_request_with_new_stream_key_from_dispatcher_then_sends_cores_package_to_hopper( - ) { - init_test_logging(); - let test_name = "proxy_server_receives_http_request_with_new_stream_key_from_dispatcher_then_sends_cores_package_to_hopper"; - let main_cryptde = CRYPTDE_PAIR.main.as_ref(); - let alias_cryptde = CRYPTDE_PAIR.alias.as_ref(); - let http_request = b"GET /index.html HTTP/1.1\r\nHost: nowhere.com\r\n\r\n"; - let (hopper_mock, hopper_awaiter, hopper_log_arc) = make_recorder(); - let (neighborhood_mock, _, neighborhood_recording_arc) = make_recorder(); - let destination_key = PublicKey::from(&b"our destination"[..]); - let neighborhood_mock = neighborhood_mock.route_query_response(Some(RouteQueryResponse { - route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip( - vec![make_exit_service_from_key(destination_key.clone())], - vec![], - ), - 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(); + fn proxy_server_receives_http_request_with_new_stream_key_from_dispatcher_then_sends_cores_package_to_hopper( + ) { + init_test_logging(); + let test_name = "proxy_server_receives_http_request_with_new_stream_key_from_dispatcher_then_sends_cores_package_to_hopper"; + let main_cryptde = CRYPTDE_PAIR.main.as_ref(); + let alias_cryptde = CRYPTDE_PAIR.alias.as_ref(); + let http_request = b"GET /index.html HTTP/1.1\r\nHost: nowhere.com\r\n\r\n"; + let (hopper_mock, hopper_awaiter, hopper_log_arc) = make_recorder(); + let (neighborhood_mock, _, neighborhood_recording_arc) = make_recorder(); + let destination_key = PublicKey::from(&b"our destination"[..]); + let neighborhood_mock = neighborhood_mock.route_query_response(Some(RouteQueryResponse { + route: Route { hops: vec![] }, + 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(); + let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); let stream_key = StreamKey::make_meaningless_stream_key(); let expected_data = http_request.to_vec(); let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr, - reception_port_opt: Some(HTTP_PORT), - sequence_number_opt: Some(0), + reception_port: Some(HTTP_PORT), + sequence_number: Some(0), last_data: true, is_clandestine: false, data: expected_data.clone(), @@ -1872,7 +1665,7 @@ mod tests { sequence_number: 0, last_data: true, }, - target_hostname: String::from("nowhere.com"), + target_hostname: Some(String::from("nowhere.com")), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: alias_cryptde.public_key().clone(), @@ -1889,7 +1682,7 @@ mod tests { thread::spawn(move || { let stream_key_factory = StreamKeyFactoryMock::new() .make_parameters(&make_parameters_arc) - .make_result(stream_key.clone()); + .make_result(stream_key); let system = System::new(test_name); let mut subject = ProxyServer::new( CRYPTDE_PAIR.clone(), @@ -1911,13 +1704,6 @@ 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(); }); @@ -1934,16 +1720,13 @@ mod tests { let record = recording.get_record::(0); assert_eq!( record, - &RouteQueryMessage::data_indefinite_route_request( - Host::new("nowhere.com", HTTP_PORT), - 47 - ) + &RouteQueryMessage::data_indefinite_route_request(Some("nowhere.com".to_string()), 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: \"nowhere.com\" - stream key: {stream_key} retries left: 3") + &format!("DEBUG: {test_name}: Found a new route for hostname: Some(\"nowhere.com\") - stream key: {stream_key} retries left: 3") ); } @@ -1960,20 +1743,19 @@ mod tests { expected_services: ExpectedServices::RoundTrip( vec![make_exit_service_from_key(destination_key.clone())], vec![], + 1234, ), - 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_opt: Some(8443), - sequence_number_opt: Some(0), + reception_port: Some(8443), + sequence_number: Some(0), last_data: false, is_clandestine: false, data: request_data.clone(), @@ -1981,27 +1763,27 @@ mod tests { let tunnelled_msg = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr, - reception_port_opt: Some(8443), - sequence_number_opt: Some(0), + reception_port: Some(8443), + sequence_number: Some(0), last_data: false, is_clandestine: false, - data: tunneled_data.clone(), + data: b"client hello".to_vec(), }; let expected_tdm = TransmitDataMsg { endpoint: Endpoint::Socket(socket_addr), last_data: false, - sequence_number_opt: Some(0), + sequence_number: Some(0), data: b"HTTP/1.1 200 OK\r\n\r\n".to_vec(), }; let expected_payload = ClientRequestPayload_0v1 { stream_key: stream_key.clone(), sequenced_packet: SequencedPacket { - data: tunneled_data, + data: b"client hello".to_vec(), sequence_number: 0, last_data: false, }, - target_hostname: String::from("realdomain.nu"), - target_port: TLS_PORT, + target_hostname: Some(String::from("realdomain.nu")), + target_port: 443, protocol: ProxyProtocol::TLS, originator_public_key: alias_cryptde.public_key().clone(), }; @@ -2018,7 +1800,7 @@ mod tests { thread::spawn(move || { let stream_key_factory = StreamKeyFactoryMock::new() .make_parameters(&make_parameters_arc_thread) - .make_result(stream_key.clone()); + .make_result(stream_key); let system = System::new( "proxy_server_receives_connect_responds_with_ok_and_stores_stream_key_and_hostname", ); @@ -2040,13 +1822,6 @@ 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(); }); @@ -2069,8 +1844,8 @@ mod tests { assert_eq!( neighborhood_record, &RouteQueryMessage::data_indefinite_route_request( - Host::new("realdomain.nu", TLS_PORT), - 68 + Some("realdomain.nu".to_string()), + 12 ) ); } @@ -2093,18 +1868,15 @@ mod tests { subject .keys_and_addrs .insert(stream_key.clone(), socket_addr.clone()); - subject.stream_info.insert( - stream_key.clone(), - StreamInfoBuilder::new() - .route(RouteQueryResponse { - route: make_meaningless_route(&CRYPTDE_PAIR), - expected_services: ExpectedServices::RoundTrip( - vec![], - vec![ExpectedService::Nothing], - ), - host: Host::new("booga.com", TLS_PORT), - }) - .build(), + + subject.route_ids_to_return_routes.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 http_request = b"CONNECT https://realdomain.nu:443 HTTP/1.1\r\nHost: https://bunkjunk.wrong:443\r\n\r\n"; @@ -2112,10 +1884,10 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr, - reception_port_opt: Some(TLS_PORT), + reception_port: Some(443), last_data: false, is_clandestine: false, - sequence_number_opt: Some(0), + sequence_number: Some(0), data: request_data, }; @@ -2132,7 +1904,7 @@ mod tests { ExpiredCoresPackage::new( SocketAddr::from_str("1.2.3.4:1234").unwrap(), Some(make_wallet("irrelevant")), - return_route(cryptde), + return_route_with_id(cryptde, 1234), client_response_payload.into(), 0, ); @@ -2149,10 +1921,9 @@ mod tests { system.run(); let dispatcher_recording = dispatcher_log_arc.lock().unwrap(); - let record = dispatcher_recording.get_record::(0); - assert_eq!(record.sequence_number_opt.unwrap(), 0); let record = dispatcher_recording.get_record::(1); - assert_eq!(record.sequence_number_opt.unwrap(), 1); + + assert_eq!(record.sequence_number.unwrap(), 1); } #[test] @@ -2165,7 +1936,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, false), + zero_hop_route_response(&cryptde.public_key(), cryptde), )); let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); @@ -2174,8 +1945,8 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port_opt: Some(8443), - sequence_number_opt: Some(0), + reception_port: Some(8443), + sequence_number: Some(0), last_data: false, is_clandestine: false, data: request_data.clone(), @@ -2216,7 +1987,7 @@ mod tests { let expected_transmit_data_msg = TransmitDataMsg { endpoint: Endpoint::Socket(socket_addr), last_data: true, - sequence_number_opt: Some(0), + sequence_number: Some(0), data: b"HTTP/1.1 400 Bad Request\r\nContent-Length: 0\r\n\r\n".to_vec(), }; @@ -2236,7 +2007,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, false), + zero_hop_route_response(&cryptde.public_key(), cryptde), )); let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); @@ -2245,8 +2016,8 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port_opt: Some(8443), - sequence_number_opt: Some(0), + reception_port: Some(8443), + sequence_number: Some(0), last_data: false, is_clandestine: false, data: request_data.clone(), @@ -2287,7 +2058,7 @@ mod tests { let expected_transmit_data_msg = TransmitDataMsg { endpoint: Endpoint::Socket(socket_addr), last_data: true, - sequence_number_opt: Some(0), + sequence_number: Some(0), data: b"HTTP/1.1 400 Bad Request\r\nContent-Length: 0\r\n\r\n".to_vec(), }; @@ -2311,8 +2082,8 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port_opt: Some(HTTP_PORT), - sequence_number_opt: Some(0), + reception_port: Some(HTTP_PORT), + sequence_number: Some(0), last_data: true, is_clandestine: false, data: expected_data.clone(), @@ -2346,7 +2117,7 @@ mod tests { &TransmitDataMsg { endpoint: Endpoint::Socket(socket_addr), last_data: true, - sequence_number_opt: Some(0), + sequence_number: Some(0), data: server_impersonator.consuming_wallet_absent(), } ); @@ -2369,8 +2140,8 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port_opt: Some(TLS_PORT), - sequence_number_opt: Some(0), + reception_port: Some(TLS_PORT), + sequence_number: Some(0), last_data: true, is_clandestine: false, data: expected_data.clone(), @@ -2404,7 +2175,7 @@ mod tests { &TransmitDataMsg { endpoint: Endpoint::Socket(socket_addr), last_data: true, - sequence_number_opt: Some(0), + sequence_number: Some(0), data: server_impersonator.consuming_wallet_absent(), } ); @@ -2421,8 +2192,7 @@ mod tests { let alias_cryptde = CRYPTDE_PAIR.alias.as_ref(); 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, false); + let expected_route = zero_hop_route_response(main_cryptde.public_key(), main_cryptde); 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())); @@ -2433,8 +2203,8 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port_opt: Some(HTTP_PORT), - sequence_number_opt: Some(0), + reception_port: Some(HTTP_PORT), + sequence_number: Some(0), last_data: true, is_clandestine: false, data: expected_data_inner, @@ -2443,12 +2213,7 @@ mod tests { let system = System::new("proxy_server_receives_http_request_with_no_consuming_wallet_in_zero_hop_mode_and_handles_normally"); let mut subject = ProxyServer::new(CRYPTDE_PAIR.clone(), 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, socket_addr); let subject_addr: Addr = subject.start(); let peer_actors = peer_actors_builder() .dispatcher(dispatcher) @@ -2470,7 +2235,7 @@ mod tests { target_component: Component::ProxyClient, return_component_opt: Some(Component::ProxyServer), payload_size: 47, - host: Host::new("nowhere.com", HTTP_PORT), + hostname_opt: Some("nowhere.com".to_string()), } ); let dispatcher_recording = dispatcher_log_arc.lock().unwrap(); @@ -2486,8 +2251,8 @@ mod tests { &ClientRequestPayload_0v1 { stream_key, sequenced_packet: SequencedPacket::new(expected_data, 0, true), - target_hostname: "nowhere.com".to_string(), - target_port: HTTP_PORT, + target_hostname: Some("nowhere.com".to_string()), + target_port: 80, protocol: ProxyProtocol::HTTP, originator_public_key: alias_cryptde.public_key().clone(), } @@ -2506,35 +2271,28 @@ mod tests { let alias_cryptde = CRYPTDE_PAIR.alias.as_ref(); 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, true); - let expected_route_inner = expected_route.clone(); + let expected_route = zero_hop_route_response(main_cryptde.public_key(), main_cryptde); 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_opt: Some(TLS_PORT), - sequence_number_opt: Some(0), + reception_port: Some(TLS_PORT), + sequence_number: Some(0), last_data: true, is_clandestine: false, data: expected_data_inner, }; - let stream_key_factory = StreamKeyFactoryMock::new().make_result(stream_key.clone()); + let stream_key_factory = StreamKeyFactoryMock::new(); // can't make any stream keys; shouldn't have to 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(CRYPTDE_PAIR.clone(), 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, - StreamInfoBuilder::new() - .route(expected_route_inner) - .protocol(ProxyProtocol::TLS) - .build(), - ); let subject_addr: Addr = subject.start(); let peer_actors = peer_actors_builder() .dispatcher(dispatcher) @@ -2548,6 +2306,17 @@ 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(); @@ -2561,8 +2330,8 @@ mod tests { &ClientRequestPayload_0v1 { stream_key, sequenced_packet: SequencedPacket::new(expected_data, 0, true), - target_hostname: "booga.com".to_string(), - target_port: TLS_PORT, + target_hostname: None, + target_port: 443, protocol: ProxyProtocol::TLS, originator_public_key: alias_cryptde.public_key().clone(), } @@ -2588,8 +2357,8 @@ mod tests { expected_services: ExpectedServices::RoundTrip( vec![make_exit_service_from_key(destination_key.clone())], vec![], + 1234, ), - 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(); @@ -2597,8 +2366,8 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port_opt: Some(HTTP_PORT), - sequence_number_opt: Some(0), + reception_port: Some(HTTP_PORT), + sequence_number: Some(0), last_data: true, is_clandestine: false, data: expected_data.clone(), @@ -2612,7 +2381,7 @@ mod tests { sequence_number: 0, last_data: true, }, - target_hostname: String::from("nowhere.com"), + target_hostname: Some(String::from("nowhere.com")), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: alias_cryptde.public_key().clone(), @@ -2636,9 +2405,6 @@ 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) @@ -2690,6 +2456,7 @@ mod tests { ), main_cryptde, Some(consuming_wallet), + 1234, Some(TEST_DEFAULT_CHAIN.rec().contract), ) .unwrap(); @@ -2709,8 +2476,8 @@ mod tests { ExpectedService::Nothing, ExpectedService::Exit(PublicKey::new(&[3]), earning_wallet, rate_pack(102)), ], + 1234, ), - 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(); @@ -2718,8 +2485,8 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port_opt: Some(HTTP_PORT), - sequence_number_opt: Some(0), + reception_port: Some(HTTP_PORT), + sequence_number: Some(0), last_data: true, is_clandestine: false, data: expected_data.clone(), @@ -2732,7 +2499,7 @@ mod tests { sequence_number: 0, last_data: true, }, - target_hostname: String::from("nowhere.com"), + target_hostname: Some(String::from("nowhere.com")), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: alias_cryptde.public_key().clone(), @@ -2775,10 +2542,7 @@ mod tests { let record = recording.get_record::(0); assert_eq!( record, - &RouteQueryMessage::data_indefinite_route_request( - Host::new("nowhere.com", HTTP_PORT), - 47 - ) + &RouteQueryMessage::data_indefinite_route_request(Some("nowhere.com".to_string()), 47) ); } @@ -2796,8 +2560,8 @@ mod tests { expected_services: ExpectedServices::RoundTrip( vec![expected_service.clone()], vec![expected_service], + 123, ), - host: Host::new("booga.com", HTTP_PORT), }); let (neighborhood_mock, _, _) = make_recorder(); let neighborhood_mock = @@ -2808,8 +2572,8 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port_opt: Some(HTTP_PORT), - sequence_number_opt: Some(0), + reception_port: Some(HTTP_PORT), + sequence_number: Some(0), last_data: true, is_clandestine: false, data: expected_data.clone(), @@ -2868,8 +2632,8 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port_opt: Some(HTTP_PORT), - sequence_number_opt: Some(0), + reception_port: Some(HTTP_PORT), + sequence_number: Some(0), last_data: true, is_clandestine: false, data: expected_data.clone(), @@ -2920,8 +2684,8 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port_opt: Some(HTTP_PORT), - sequence_number_opt: Some(0), + reception_port: Some(HTTP_PORT), + sequence_number: Some(0), last_data: true, is_clandestine: false, data: expected_data.clone(), @@ -2955,14 +2719,13 @@ mod tests { let alias_cryptde = CRYPTDE_PAIR.alias.as_ref(); 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_query_response = RouteQueryResponse { - route: route.clone(), + route: Route { hops: vec![] }, expected_services: ExpectedServices::RoundTrip( vec![make_exit_service_from_key(destination_key.clone())], vec![], + 1234, ), - 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(); @@ -2970,9 +2733,9 @@ mod tests { let expected_data = http_request.to_vec(); let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), - client_addr: socket_addr, - reception_port_opt: Some(HTTP_PORT), - sequence_number_opt: Some(0), + client_addr: socket_addr.clone(), + reception_port: Some(HTTP_PORT), + sequence_number: Some(0), last_data: true, is_clandestine: false, data: expected_data.clone(), @@ -2984,14 +2747,14 @@ mod tests { sequence_number: 0, last_data: true, }, - target_hostname: String::from("nowhere.com"), + target_hostname: Some(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, + Route { hops: vec![] }, expected_payload.into(), &destination_key, ) @@ -3009,12 +2772,8 @@ mod tests { ); 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().route(route_query_response).build(), - ); + .stream_key_routes + .insert(stream_key, route_query_response); let subject_addr: Addr = subject.start(); let peer_actors = peer_actors_builder().hopper(hopper_mock).build(); subject_addr.try_send(BindMessage { peer_actors }).unwrap(); @@ -3034,89 +2793,57 @@ mod tests { fn proxy_server_sends_message_to_accountant_about_all_services_consumed_on_the_route_over() { let cryptde = CRYPTDE_PAIR.main.as_ref(); let now = SystemTime::now(); - 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 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 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 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 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 route_query_response = RouteQueryResponse { - route, + route: make_meaningless_route(&CRYPTDE_PAIR), expected_services: ExpectedServices::RoundTrip( vec![ ExpectedService::Nothing, ExpectedService::Routing( - routing_node_1_public_key.clone(), - routing_node_1_earning_wallet.clone(), - routing_node_1_rate_pack.clone(), + PublicKey::new(&[1]), + route_1_earning_wallet.clone(), + routing_node_1_rate_pack, ), ExpectedService::Routing( - routing_node_2_public_key.clone(), - routing_node_2_earning_wallet.clone(), - routing_node_2_rate_pack.clone(), + PublicKey::new(&[2]), + route_2_earning_wallet.clone(), + routing_node_2_rate_pack, ), ExpectedService::Exit( - exit_node_public_key.clone(), - exit_node_earning_wallet.clone(), - exit_node_rate_pack.clone(), + PublicKey::new(&[3]), + exit_earning_wallet.clone(), + exit_node_rate_pack, ), ], vec![ ExpectedService::Exit( - exit_node_public_key.clone(), - exit_node_earning_wallet.clone(), - exit_node_rate_pack, + PublicKey::new(&[3]), + make_wallet("some wallet 1"), + rate_pack(104), ), ExpectedService::Routing( - routing_node_2_public_key.clone(), - routing_node_2_earning_wallet.clone(), - routing_node_2_rate_pack, + PublicKey::new(&[2]), + make_wallet("some wallet 2"), + rate_pack(105), ), ExpectedService::Routing( - routing_node_1_public_key.clone(), - routing_node_1_earning_wallet.clone(), - routing_node_1_rate_pack, + PublicKey::new(&[1]), + make_wallet("some wallet 3"), + rate_pack(106), ), ExpectedService::Nothing, ], + 0, ), - 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(); @@ -3132,7 +2859,7 @@ mod tests { let payload = ClientRequestPayload_0v1 { stream_key, sequenced_packet: SequencedPacket::new(expected_data, 0, false), - target_hostname: "nowhere.com".to_string(), + target_hostname: Some("nowhere.com".to_string()), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: PublicKey::new(b"originator_public_key"), @@ -3151,35 +2878,17 @@ 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, + peer_actors.proxy_server.add_return_route, + route_query_response, + ); System::current().stop(); system.run(); let recording = hopper_recording_arc.lock().unwrap(); - let mut record = recording.get_record::(0).clone(); + let record = recording.get_record::(0); 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); let recording = accountant_recording_arc.lock().unwrap(); let record = recording.get_record::(0); assert_eq!(recording.len(), 1); @@ -3188,7 +2897,7 @@ mod tests { &ReportServicesConsumedMessage { timestamp: now, exit: ExitServiceConsumed { - earning_wallet: exit_node_earning_wallet, + earning_wallet: exit_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 @@ -3196,12 +2905,12 @@ mod tests { routing_payload_size: payload_enc_length, routing: vec![ RoutingServiceConsumed { - earning_wallet: routing_node_1_earning_wallet, + earning_wallet: route_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: routing_node_2_earning_wallet, + earning_wallet: route_2_earning_wallet, service_rate: routing_node_2_rate_pack.routing_service_rate, byte_rate: routing_node_2_rate_pack.routing_byte_rate, } @@ -3209,7 +2918,8 @@ mod tests { } ); let recording = proxy_server_recording_arc.lock().unwrap(); - assert_eq!(recording.len(), 0); // No StreamShutdownMsg: that's the important thing + 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!(result, Ok(())); } @@ -3223,8 +2933,8 @@ mod tests { expected_services: ExpectedServices::RoundTrip( vec![ExpectedService::Nothing], vec![ExpectedService::Nothing], + 0, ), - 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(); @@ -3237,7 +2947,7 @@ mod tests { let payload = ClientRequestPayload_0v1 { stream_key, sequenced_packet: SequencedPacket::new(expected_data, 0, false), - target_hostname: "nowhere.com".to_string(), + target_hostname: Some("nowhere.com".to_string()), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: PublicKey::new(b"originator_public_key"), @@ -3256,12 +2966,26 @@ 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, + 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); + let record = recording.get_record::(0); + assert_eq!( + record, + &AddReturnRouteMessage { + return_route_id: 0, + expected_services: vec![ExpectedService::Nothing], + protocol: ProxyProtocol::HTTP, + hostname_opt: Some("nowhere.com".to_string()) + } + ); + let record = recording.get_record::(1); assert_eq!( record, &StreamShutdownMsg { @@ -3283,8 +3007,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, false); + let mut route_query_response = zero_hop_route_response(&cryptde.public_key(), cryptde); route_query_response.expected_services = ExpectedServices::RoundTrip( vec![ExpectedService::Exit( cryptde.public_key().clone(), @@ -3292,6 +3015,7 @@ mod tests { rate_pack(3), )], vec![], + 0, ); let neighborhood_mock = neighborhood_mock.route_query_response(Some(route_query_response.clone())); @@ -3301,8 +3025,8 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port_opt: Some(HTTP_PORT), - sequence_number_opt: Some(0), + reception_port: Some(HTTP_PORT), + sequence_number: Some(0), last_data: true, is_clandestine: false, data: expected_data.clone(), @@ -3337,35 +3061,28 @@ mod tests { #[test] #[should_panic( - expected = "AddRouteResultMessage Handler: dns_failure_retry_opt is None for stream key" + expected = "AddRouteResultMessage Handler: stream key: AAAAAAAAAAAAAAAAAAAAAAAAAAA not found within dns_failure_retries" )] - fn route_result_message_handler_panics_when_no_dns_retries_exist() { - init_test_logging(); - let system = System::new("route_result_message_handler_panics_when_no_dns_retries_exist"); - let mut subject = ProxyServer::new( + fn route_result_message_handler_panics_when_dns_retries_hashmap_doesnt_contain_a_stream_key() { + let system = System::new("route_result_message_handler_panics_when_dns_retries_hashmap_doesnt_contain_a_stream_key"); + let subject = ProxyServer::new( CRYPTDE_PAIR.clone(), true, Some(STANDARD_CONSUMING_WALLET_BALANCE), 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, + stream_key: StreamKey::make_meaningless_stream_key(), result: Err("Some Error".to_string()), }) .unwrap(); - System::current().stop(); system.run(); } @@ -3427,8 +3144,8 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port_opt: Some(HTTP_PORT), - sequence_number_opt: Some(0), + reception_port: Some(HTTP_PORT), + sequence_number: Some(0), last_data: true, data: expected_data.clone(), is_clandestine: false, @@ -3464,7 +3181,7 @@ mod tests { let expected_msg = TransmitDataMsg { endpoint: Endpoint::Socket(SocketAddr::from_str("1.2.3.4:5678").unwrap()), last_data: true, - sequence_number_opt: Some(0), + sequence_number: Some(0), data: ServerImpersonatorHttp {}.route_query_failure_response("nowhere.com"), }; assert_eq!(record, &expected_msg); @@ -3472,13 +3189,10 @@ mod tests { let record = recording.get_record::(0); assert_eq!( record, - &RouteQueryMessage::data_indefinite_route_request( - Host::new("nowhere.com", HTTP_PORT), - 47 - ) + &RouteQueryMessage::data_indefinite_route_request(Some("nowhere.com".to_string()), 47) ); TestLogHandler::new().exists_log_containing(&format!( - "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" + "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" )); } @@ -3509,7 +3223,6 @@ mod tests { rate_pack(103), ), ]), - host: Host::new("booga.com", HTTP_PORT), }; let payload = ClientRequestPayload_0v1 { stream_key: StreamKey::make_meaningless_stream_key(), @@ -3518,7 +3231,7 @@ mod tests { sequence_number: 0, last_data: false, }, - target_hostname: "booga.com".to_string(), + target_hostname: None, target_port: 0, protocol: ProxyProtocol::TLS, originator_public_key: cryptde.public_key().clone(), @@ -3538,7 +3251,11 @@ 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, + peer_actors.proxy_server.add_return_route, + route_result, + ); } #[test] @@ -3552,20 +3269,25 @@ mod tests { false, false, ); - 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), - ), - ]; + 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, + }; - subject.report_response_services_consumed(&expected_services, 1234, 3456); + subject.report_response_services_consumed(&add_return_route_message, 1234, 3456); } #[test] @@ -3583,11 +3305,11 @@ mod tests { RouteSegment::new(vec![public_key, public_key], Component::ProxyServer), cryptde, None, + 1234, None, ) .unwrap(), - expected_services: ExpectedServices::RoundTrip(vec![], vec![]), - host: Host::new("booga.com", HTTP_PORT), + expected_services: ExpectedServices::RoundTrip(vec![], vec![], 1234), }; let neighborhood_mock = neighborhood_mock.route_query_response(Some(route_query_response)); let dispatcher = Recorder::new(); @@ -3598,8 +3320,8 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port_opt: Some(HTTP_PORT), - sequence_number_opt: Some(0), + reception_port: Some(HTTP_PORT), + sequence_number: Some(0), last_data: true, data: expected_data.clone(), is_clandestine: false, @@ -3636,7 +3358,7 @@ mod tests { let expected_msg = TransmitDataMsg { endpoint: Endpoint::Socket(SocketAddr::from_str("1.2.3.4:5678").unwrap()), last_data: true, - sequence_number_opt: Some(0), + sequence_number: Some(0), data: ServerImpersonatorHttp {}.route_query_failure_response("nowhere.com"), }; assert_eq!(record, &expected_msg); @@ -3644,19 +3366,35 @@ mod tests { let record = recording.get_record::(0); assert_eq!( record, - &RouteQueryMessage::data_indefinite_route_request( - Host::new("nowhere.com", HTTP_PORT), - 47 - ) + &RouteQueryMessage::data_indefinite_route_request(Some("nowhere.com".to_string()), 47) ); TestLogHandler::new().exists_log_containing(&format!( - "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" + "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" )); } #[test] fn proxy_server_receives_tls_client_hello_from_dispatcher_then_sends_cores_package_to_hopper() { - let tls_request = make_server_com_client_hello(); + 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 main_cryptde = CRYPTDE_PAIR.main.as_ref(); let alias_cryptde = CRYPTDE_PAIR.alias.as_ref(); let hopper_mock = Recorder::new(); @@ -3668,22 +3406,22 @@ mod tests { expected_services: ExpectedServices::RoundTrip( vec![make_exit_service_from_key(destination_key.clone())], vec![], + 1234, ), - 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.clone(); + let expected_data = tls_request.to_vec(); let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port_opt: Some(TLS_PORT), - sequence_number_opt: Some(0), + reception_port: 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.as_slice()); + let expected_tls_request = PlainData::new(tls_request); let route = Route { hops: vec![] }; let expected_payload = ClientRequestPayload_0v1 { stream_key: stream_key.clone(), @@ -3692,7 +3430,7 @@ mod tests { sequence_number: 0, last_data: false, }, - target_hostname: String::from("server.com"), + target_hostname: Some(String::from("server.com")), target_port: TLS_PORT, protocol: ProxyProtocol::TLS, originator_public_key: alias_cryptde.public_key().clone(), @@ -3753,8 +3491,8 @@ mod tests { expected_services: ExpectedServices::RoundTrip( vec![make_exit_service_from_key(destination_key.clone())], vec![], + 1234, ), - 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(); @@ -3762,8 +3500,8 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port_opt: Some(TLS_PORT), - sequence_number_opt: Some(0), + reception_port: Some(TLS_PORT), + sequence_number: Some(0), last_data: false, is_clandestine: false, data: expected_data.clone(), @@ -3777,7 +3515,7 @@ mod tests { sequence_number: 0, last_data: false, }, - target_hostname: "booga.com".to_string(), + target_hostname: None, target_port: TLS_PORT, protocol: ProxyProtocol::TLS, originator_public_key: alias_cryptde.public_key().clone(), @@ -3799,22 +3537,6 @@ 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() @@ -3827,6 +3549,7 @@ mod tests { system.run(); }); + hopper_awaiter.await_message_count(1); let recording = hopper_log_arc.lock().unwrap(); let record = recording.get_record::(0); @@ -3852,8 +3575,8 @@ mod tests { expected_services: ExpectedServices::RoundTrip( vec![make_exit_service_from_key(destination_key.clone())], vec![], + 1234, ), - 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); @@ -3861,8 +3584,8 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr, - reception_port_opt: Some(TLS_PORT), - sequence_number_opt: Some(0), + reception_port: Some(TLS_PORT), + sequence_number: Some(0), last_data: true, is_clandestine: false, data: expected_data.clone(), @@ -3876,7 +3599,7 @@ mod tests { sequence_number: 0, last_data: true, }, - target_hostname: "booga.com".to_string(), + target_hostname: None, target_port: TLS_PORT, protocol: ProxyProtocol::TLS, originator_public_key: alias_cryptde.public_key().clone(), @@ -3897,20 +3620,6 @@ mod tests { false, ); subject.keys_and_addrs.insert(stream_key, client_addr); - subject.stream_info.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() @@ -3964,8 +3673,8 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port_opt: Some(TLS_PORT), - sequence_number_opt: Some(0), + reception_port: Some(TLS_PORT), + sequence_number: Some(0), last_data: true, data: tls_request, is_clandestine: false, @@ -3999,7 +3708,7 @@ mod tests { let expected_msg = TransmitDataMsg { endpoint: Endpoint::Socket(SocketAddr::from_str("1.2.3.4:5678").unwrap()), last_data: true, - sequence_number_opt: Some(0), + sequence_number: Some(0), data: ServerImpersonatorTls {}.route_query_failure_response("ignored"), }; assert_eq!(record, &expected_msg); @@ -4025,22 +3734,17 @@ mod tests { subject .keys_and_addrs .insert(stream_key.clone(), socket_addr.clone()); - subject.stream_info.insert( - stream_key.clone(), - StreamInfoBuilder::new() - .route(RouteQueryResponse { - route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip( - vec![], - vec![ExpectedService::Nothing], - ), - host: Host::new("booga.com", TLS_PORT), - }) - .protocol(ProxyProtocol::TLS) - .build(), + subject.route_ids_to_return_routes.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(cryptde); + let remaining_route = return_route_with_id(cryptde, 1234); let client_response_payload = ClientResponsePayload_0v1 { stream_key: stream_key.clone(), sequenced_packet: SequencedPacket { @@ -4076,7 +3780,7 @@ mod tests { stream_key )); tlh.exists_log_containing(&format!( - "ERROR: {test_name}: Can't pay for return services consumed: received response with unrecognized stream key {:?}. Ignoring", + "WARN: {test_name}: Discarding 16-byte packet 12345678 from an unrecognized stream key: {:?}", stream_key )); } @@ -4115,17 +3819,24 @@ mod tests { subject .keys_and_addrs .insert(stream_key.clone(), socket_addr.clone()); - subject.stream_info.insert( + subject.stream_key_routes.insert( stream_key.clone(), - StreamInfoBuilder::new() - .route(RouteQueryResponse { - route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip(vec![], vec![]), - host: Host::new("booga.com", HTTP_PORT), - }) - .protocol(ProxyProtocol::HTTP) - .tunneled_host("hostname") - .build(), + RouteQueryResponse { + route: Route { hops: vec![] }, + expected_services: ExpectedServices::RoundTrip(vec![], vec![], 1234), + }, + ); + subject + .tunneled_hosts + .insert(stream_key.clone(), "hostname".to_string()); + subject.route_ids_to_return_routes.insert( + 1234, + AddReturnRouteMessage { + return_route_id: 1234, + expected_services: vec![], + protocol: ProxyProtocol::HTTP, + hostname_opt: None, + }, ); let client_response_payload = ClientResponsePayload_0v1 { stream_key: stream_key.clone(), @@ -4138,7 +3849,7 @@ mod tests { ExpiredCoresPackage::new( SocketAddr::from_str("1.2.3.4:1234").unwrap(), Some(make_wallet("irrelevant")), - return_route(cryptde), + return_route_with_id(cryptde, 1234), client_response_payload.into(), 0, ); @@ -4146,7 +3857,8 @@ mod tests { subject.handle_client_response_payload(expired_cores_package); assert!(subject.keys_and_addrs.is_empty()); - assert!(subject.stream_info.get(&stream_key).is_none()); + assert!(subject.stream_key_routes.is_empty()); + assert!(subject.tunneled_hosts.is_empty()); } #[test] @@ -4214,17 +3926,24 @@ mod tests { subject .keys_and_addrs .insert(stream_key.clone(), msg.peer_addr.clone()); - subject.stream_info.insert( + subject.stream_key_routes.insert( stream_key.clone(), - StreamInfoBuilder::new() - .route(RouteQueryResponse { - route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip(vec![], vec![]), - host: Host::new("booga.com", HTTP_PORT), - }) - .protocol(ProxyProtocol::HTTP) - .tunneled_host("hostname") - .build(), + RouteQueryResponse { + route: Route { hops: vec![] }, + expected_services: ExpectedServices::RoundTrip(vec![], vec![], 1234), + }, + ); + subject + .tunneled_hosts + .insert(stream_key.clone(), "hostname".to_string()); + subject.route_ids_to_return_routes.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(); @@ -4242,14 +3961,18 @@ mod tests { .unwrap(); let pre_purge_assertions = AssertionsMessage { assertions: Box::new(move |proxy_server: &mut ProxyServer| { - let stream_info = proxy_server.stream_info.get(&stream_key).unwrap(); - let purge_timestamp = stream_info.time_to_live_opt.unwrap(); + let purge_timestamp = proxy_server + .stream_key_ttl + .get(&stream_key) + .unwrap() + .clone(); 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\". \ @@ -4267,7 +3990,9 @@ 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_info.get(&stream_key).is_none()); + assert!(proxy_server.stream_key_routes.is_empty()); + assert!(proxy_server.tunneled_hosts.is_empty()); + assert!(proxy_server.stream_key_ttl.is_empty()); TestLogHandler::new().exists_log_containing(&format!( "DEBUG: {test_name}: Retiring stream key {:?}", stream_key @@ -4303,6 +4028,16 @@ mod tests { subject .keys_and_addrs .insert(stream_key.clone(), socket_addr.clone()); + subject.stream_key_routes.insert( + stream_key.clone(), + RouteQueryResponse { + route: Route { hops: vec![] }, + expected_services: ExpectedServices::RoundTrip(vec![], vec![], 1234), + }, + ); + 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 { @@ -4311,26 +4046,22 @@ mod tests { 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![ExpectedService::Exit( - exit_key, - exit_wallet.clone(), - exit_rates.clone(), - )], - ), - host: Host::new("booga.com", HTTP_PORT), - }) - .tunneled_host("hostname") - .protocol(ProxyProtocol::HTTP) - .time_to_live(SystemTime::now()) - .build(), + subject.route_ids_to_return_routes.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, + }, ); + 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(); @@ -4348,7 +4079,7 @@ mod tests { ExpiredCoresPackage::new( SocketAddr::from_str("1.2.3.4:1234").unwrap(), Some(make_wallet("irrelevant")), - return_route(cryptde), + return_route_with_id(cryptde, 1234), client_response_payload.into(), 5432, ); @@ -4406,35 +4137,63 @@ mod tests { 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(), - 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, - ], + subject.route_ids_to_return_routes.insert( + 1234, + AddReturnRouteMessage { + return_route_id: 1234, + expected_services: vec![ + ExpectedService::Exit( + irrelevant_public_key.clone(), + incoming_route_d_wallet.clone(), + rate_pack_d, ), - host: Host::new("booga.com", HTTP_PORT), - }) - .build(), + 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.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, + }, ); let subject_addr: Addr = subject.start(); let first_client_response_payload = ClientResponsePayload_0v1 { @@ -4450,7 +4209,7 @@ mod tests { ExpiredCoresPackage::new( SocketAddr::from_str("1.2.3.4:1234").unwrap(), Some(make_wallet("irrelevant")), - return_route(cryptde), + return_route_with_id(cryptde, 1234), first_client_response_payload.into(), 0, ); @@ -4468,7 +4227,7 @@ mod tests { ExpiredCoresPackage::new( SocketAddr::from_str("1.2.3.5:1235").unwrap(), Some(make_wallet("irrelevant")), - return_route(cryptde), + return_route_with_id(cryptde, 1235), second_client_response_payload.into(), 0, ); @@ -4506,7 +4265,7 @@ mod tests { &ReportServicesConsumedMessage { timestamp: first_report_timestamp, exit: ExitServiceConsumed { - earning_wallet: incoming_route_d_wallet.clone(), + earning_wallet: incoming_route_d_wallet, payload_size: first_exit_size, service_rate: rate_pack_d.exit_service_rate, byte_rate: rate_pack_d.exit_byte_rate @@ -4514,12 +4273,12 @@ mod tests { routing_payload_size: routing_size, routing: vec![ RoutingServiceConsumed { - earning_wallet: incoming_route_e_wallet.clone(), + 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_f_wallet.clone(), + earning_wallet: incoming_route_f_wallet, service_rate: rate_pack_f.routing_service_rate, byte_rate: rate_pack_f.routing_byte_rate } @@ -4535,22 +4294,22 @@ mod tests { &ReportServicesConsumedMessage { timestamp: second_report_timestamp, exit: ExitServiceConsumed { - earning_wallet: incoming_route_d_wallet, + earning_wallet: incoming_route_g_wallet, payload_size: second_exit_size, - service_rate: rate_pack_d.exit_service_rate, - byte_rate: rate_pack_d.exit_byte_rate + service_rate: rate_pack_g.exit_service_rate, + byte_rate: rate_pack_g.exit_byte_rate }, routing_payload_size: routing_size, routing: vec![ RoutingServiceConsumed { - earning_wallet: incoming_route_e_wallet, - service_rate: rate_pack_e.routing_service_rate, - byte_rate: rate_pack_e.routing_byte_rate + earning_wallet: incoming_route_h_wallet, + service_rate: rate_pack_h.routing_service_rate, + byte_rate: rate_pack_h.routing_byte_rate }, RoutingServiceConsumed { - earning_wallet: incoming_route_f_wallet, - service_rate: rate_pack_f.routing_service_rate, - byte_rate: rate_pack_f.routing_byte_rate + earning_wallet: incoming_route_i_wallet, + service_rate: rate_pack_i.routing_service_rate, + byte_rate: rate_pack_i.routing_byte_rate } ] } @@ -4580,52 +4339,52 @@ 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.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"); 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() - .dns_failure_retry(DNSFailureRetry { - 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, - ], + subject.route_ids_to_return_routes.insert( + 1234, + AddReturnRouteMessage { + return_route_id: 1234, + expected_services: vec![ + ExpectedService::Exit( + irrelevant_public_key.clone(), + incoming_route_d_wallet.clone(), + rate_pack_d, ), - host: Host::new("booga.com", TLS_PORT), - }) - .protocol(ProxyProtocol::TLS) - .build(), - ); - let subject_addr: Addr = subject.start(); - let first_client_response_payload = ClientResponsePayload_0v1 { - stream_key, + 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, sequenced_packet: SequencedPacket { data: b"some data".to_vec(), sequence_number: 4321, @@ -4636,7 +4395,7 @@ mod tests { ExpiredCoresPackage::new( SocketAddr::from_str("1.2.3.4:1234").unwrap(), Some(make_wallet("irrelevant")), - return_route(cryptde), + return_route_with_id(cryptde, 1234), first_client_response_payload.into(), 0, ); @@ -4648,16 +4407,14 @@ 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) - .unwrap() - .dns_failure_retry_opt; - assert!(retry_opt.is_none()); + let retry_opt = proxy_server.dns_failure_retries.get(&stream_key); + assert_eq!(retry_opt, None); }), }) .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] @@ -4681,30 +4438,25 @@ 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.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, - ), - ], + subject.route_ids_to_return_routes.insert( + 1234, + AddReturnRouteMessage { + return_route_id: 1234, + expected_services: vec![ + ExpectedService::Exit( + irrelevant_public_key.clone(), + incoming_route_d_wallet.clone(), + rate_pack_d, ), - host: Host::new("booga.com", TLS_PORT), - }) - .protocol(ProxyProtocol::TLS) - .build(), + ExpectedService::Routing( + irrelevant_public_key.clone(), + incoming_route_e_wallet.clone(), + rate_pack_e, + ), + ], + protocol: ProxyProtocol::TLS, + hostname_opt: None, + }, ); let subject_addr: Addr = subject.start(); let client_response_payload = ClientResponsePayload_0v1 { @@ -4720,7 +4472,7 @@ mod tests { ExpiredCoresPackage::new( SocketAddr::from_str("1.2.3.4:1234").unwrap(), Some(make_wallet("irrelevant")), - return_route(cryptde), + return_route_with_id(cryptde, 1234), client_response_payload.into(), 0, ); @@ -4782,47 +4534,46 @@ 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); - let exit_public_key = PublicKey::from(&b"exit_key"[..]); - let exit_wallet = make_wallet("exit wallet"); + 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, - }) - .route(RouteQueryResponse { - route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip( - vec![], - vec![ExpectedService::Exit( - exit_public_key.clone(), - exit_wallet, - rate_pack(10), - )], - ), - host: Host::new("server.com", HTTP_PORT), - }) - .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 = ExpiredCoresPackage::new( SocketAddr::from_str("1.2.3.4:1234").unwrap(), Some(make_wallet("irrelevant")), - return_route(cryptde), + return_route_with_id(cryptde, 1234), dns_resolve_failure.into(), 0, ); 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(); @@ -4834,9 +4585,9 @@ mod tests { TransmitDataMsg { endpoint: Endpoint::Socket(socket_addr), last_data: true, - sequence_number_opt: Some(0), + sequence_number: Some(0), data: ServerImpersonatorHttp {} - .dns_resolution_failure_response("server.com".to_string()), + .dns_resolution_failure_response(Some("server.com".to_string()),), }, *record ); @@ -4857,7 +4608,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.dns_failure_retries = dns_failure_retries_hash_map; subject .keys_and_addrs .insert(stream_key.clone(), socket_addr.clone()); @@ -4867,40 +4627,31 @@ mod tests { 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(), - 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, - ], + subject.route_ids_to_return_routes.insert( + 1234, + AddReturnRouteMessage { + return_route_id: 1234, + expected_services: vec![ + ExpectedService::Exit( + irrelevant_public_key.clone(), + incoming_route_d_wallet.clone(), + rate_pack_d, ), - host: Host::new("booga.com", TLS_PORT), - }) - .protocol(ProxyProtocol::TLS) - .build(), + 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()), + }, ); let subject_addr: Addr = subject.start(); let dns_resolve_failure_payload = DnsResolveFailure_0v1::new(stream_key); @@ -4908,7 +4659,7 @@ mod tests { ExpiredCoresPackage::new( SocketAddr::from_str("1.2.3.4:1234").unwrap(), Some(make_wallet("irrelevant")), - return_route(cryptde), + return_route_with_id(cryptde, 1234), dns_resolve_failure_payload.into(), 0, ); @@ -4973,34 +4724,34 @@ 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 .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() - .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.clone(), - rate_pack(10), - )], - ), - host: Host::new("server.com", HTTP_PORT), - }) - .protocol(ProxyProtocol::HTTP) - .build(), + subject.route_ids_to_return_routes.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); @@ -5008,7 +4759,7 @@ mod tests { ExpiredCoresPackage::new( SocketAddr::from_str("1.2.3.4:1234").unwrap(), Some(make_wallet("irrelevant")), - return_route(cryptde), + return_route_with_id(cryptde, 1234), dns_resolve_failure.into(), 0, ); @@ -5038,8 +4789,79 @@ 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_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 = CRYPTDE_PAIR.main.as_ref(); + let mut subject = ProxyServer::new( + CRYPTDE_PAIR.clone(), + 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 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 + .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.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 = + 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: {test_name}: Exit node {exit_public_key} complained of DNS failure, but was given no hostname to resolve." + )); + } + + #[test] + fn handle_dns_resolve_failure_logs_when_stream_key_be_gone_but_server_name_be_not() { init_test_logging(); let system = System::new("test"); let (neighborhood_mock, _, _) = make_recorder(); @@ -5052,39 +4874,43 @@ mod tests { false, ); 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( + 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()); 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.clone(), - rate_pack(10), - )], - ), - host: Host::new("server.com", HTTP_PORT), - }) - .protocol(ProxyProtocol::HTTP) - .build(), + subject.route_ids_to_return_routes.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 = ExpiredCoresPackage::new( - socket_addr, + SocketAddr::from_str("1.2.3.4:1234").unwrap(), Some(make_wallet("irrelevant")), - return_route(cryptde), + return_route_with_id(cryptde, return_route_id), dns_resolve_failure.into(), 0, ); @@ -5124,34 +4950,35 @@ mod tests { false, ); 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( + 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()); 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.clone(), - rate_pack(10), - )], - ), - host: Host::new("booga.com", HTTP_PORT), - }) - .protocol(ProxyProtocol::HTTP) - .build(), + subject.route_ids_to_return_routes.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); @@ -5159,7 +4986,7 @@ mod tests { ExpiredCoresPackage::new( SocketAddr::from_str("1.2.3.4:1234").unwrap(), Some(make_wallet("irrelevant")), - return_route(cryptde), + return_route_with_id(cryptde, return_route_id), dns_resolve_failure.into(), 0, ); @@ -5176,10 +5003,12 @@ 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 for from an unrecognized stream key {:?}", + stream_key + ) + ); } #[test] @@ -5204,38 +5033,47 @@ 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( + 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, - 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::RoundTrip( - vec![], - vec![ - make_exit_service_from_key(PublicKey::new(b"exit_node")), - ExpectedService::Nothing, - ], - ), - host: Host::new("booga.com", HTTP_PORT), - }) - .protocol(ProxyProtocol::HTTP) - .build(), + 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.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( SocketAddr::from_str("1.2.3.4:1234").unwrap(), Some(make_wallet("irrelevant")), - return_route(cryptde), + return_route_with_id(cryptde, 1234), dns_resolve_failure.into(), 0, ); @@ -5243,7 +5081,8 @@ mod tests { subject.handle_dns_resolve_failure(&expired_cores_package); assert!(subject.keys_and_addrs.is_empty()); - assert!(subject.stream_info.get(&stream_key).is_none()); + assert!(subject.stream_key_routes.is_empty()); + assert!(subject.tunneled_hosts.is_empty()); } #[test] @@ -5262,27 +5101,27 @@ 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, - }) - .route(RouteQueryResponse { - route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip( - vec![], - vec![ExpectedService::Nothing, ExpectedService::Nothing], - ), - host: Host::new("server.com", HTTP_PORT), - }) - .protocol(ProxyProtocol::HTTP) - .build(), + subject.route_ids_to_return_routes.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); @@ -5290,7 +5129,7 @@ mod tests { ExpiredCoresPackage::new( SocketAddr::from_str("1.2.3.4:1234").unwrap(), Some(make_wallet("irrelevant")), - return_route(cryptde), + return_route_with_id(cryptde, 1234), dns_resolve_failure.into(), 0, ); @@ -5321,9 +5160,9 @@ mod tests { TransmitDataMsg { endpoint: Endpoint::Socket(socket_addr), last_data: true, - sequence_number_opt: Some(0), + sequence_number: Some(0), data: ServerImpersonatorHttp {} - .dns_resolution_failure_response("server.com".to_string()), + .dns_resolution_failure_response(Some("server.com".to_string()),), }, *record ); @@ -5331,8 +5170,7 @@ mod tests { #[test] fn handle_dns_resolve_failure_sent_request_retry() { - let test_name = "handle_dns_resolve_failure_sent_request_retry"; - let system = System::new(test_name); + let system = System::new("test"); let resolve_message_params_arc = Arc::new(Mutex::new(vec![])); let (neighborhood_mock, _, _) = make_recorder(); let exit_public_key = PublicKey::from(&b"exit_key"[..]); @@ -5347,8 +5185,8 @@ mod tests { expected_services: ExpectedServices::RoundTrip( expected_services.clone(), expected_services.clone(), + 1234, ), - host: Host::new("booga.com", HTTP_PORT), }; let neighborhood_mock = neighborhood_mock .system_stop_conditions(match_every_type_id!(RouteQueryMessage)) @@ -5362,28 +5200,28 @@ 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.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.clone(), - retries_left: 3, - }) - .route(RouteQueryResponse { - route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip( - vec![], - expected_services.clone(), - ), - host: Host::new("server.com", HTTP_PORT), - }) - .protocol(ProxyProtocol::HTTP) - .build(), + subject.route_ids_to_return_routes.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); @@ -5398,7 +5236,7 @@ mod tests { ExpiredCoresPackage::new( SocketAddr::from_str("1.2.3.4:1234").unwrap(), Some(make_wallet("irrelevant")), - return_route(cryptde), + return_route_with_id(cryptde, 1234), dns_resolve_failure.into(), 0, ); @@ -5412,12 +5250,7 @@ mod tests { subject_addr .try_send(AssertionsMessage { assertions: Box::new(move |proxy_server: &mut ProxyServer| { - let retry = proxy_server - .stream_info(&stream_key) - .unwrap() - .dns_failure_retry_opt - .as_ref() - .unwrap(); + let retry = proxy_server.dns_failure_retries.get(&stream_key).unwrap(); assert_eq!(retry.retries_left, 2); }), }) @@ -5442,10 +5275,10 @@ mod tests { } #[test] - fn handle_dns_resolve_failure_logs_error_when_there_is_no_dns_failure_retry_entry_for_the_stream_key( + fn handle_dns_resolve_failure_logs_error_when_there_is_no_entry_in_the_hashmap_for_the_stream_key( ) { init_test_logging(); - let test_name = "handle_dns_resolve_failure_logs_error_when_there_is_no_dns_failure_retry_entry_for_the_stream_key"; + let test_name = "handle_dns_resolve_failure_logs_error_when_there_is_no_entry_in_the_hashmap_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"); @@ -5468,19 +5301,14 @@ mod tests { subject .keys_and_addrs .insert(stream_key.clone(), socket_addr.clone()); - subject.stream_info.insert( - stream_key.clone(), - StreamInfoBuilder::new() - .route(RouteQueryResponse { - route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip( - vec![], - expected_services.clone(), - ), - host: Host::new("server.com", HTTP_PORT), - }) - .protocol(ProxyProtocol::HTTP) - .build(), + subject.route_ids_to_return_routes.insert( + 1234, + AddReturnRouteMessage { + return_route_id: 1234, + expected_services: expected_services.clone(), + 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); @@ -5488,7 +5316,7 @@ mod tests { ExpiredCoresPackage::new( SocketAddr::from_str("1.2.3.4:1234").unwrap(), Some(make_wallet("irrelevant")), - return_route(cryptde), + return_route_with_id(cryptde, 1234), dns_resolve_failure.into(), 0, ); @@ -5501,7 +5329,8 @@ mod tests { system.run(); TestLogHandler::new().exists_log_containing(&format!( "ERROR: {test_name}: While \ - handling ExpiredCoresPackage: No DNSFailureRetry entry found for the stream_key: {stream_key}" + handling ExpiredCoresPackage: No entry found inside dns_failure_retries hashmap for \ + the stream_key: AAAAAAAAAAAAAAAAAAAAAAAAAAA" )); } @@ -5524,8 +5353,8 @@ mod tests { expected_services: ExpectedServices::RoundTrip( expected_services.clone(), expected_services.clone(), + 1234, ), - host: Host::new("booga.com", HTTP_PORT), }; let neighborhood_mock = neighborhood_mock .system_stop_conditions(match_every_type_id!( @@ -5544,29 +5373,29 @@ 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.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.clone(), - StreamInfoBuilder::new() - .dns_failure_retry(DNSFailureRetry { - unsuccessful_request: client_payload, - retries_left: 3, - }) - .route(RouteQueryResponse { - route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip( - vec![], - expected_services.clone(), - ), - host: Host::new("server.com", HTTP_PORT), - }) - .protocol(ProxyProtocol::HTTP) - .build(), + subject.route_ids_to_return_routes.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) @@ -5583,7 +5412,7 @@ mod tests { ExpiredCoresPackage::new( SocketAddr::from_str("1.2.3.4:1234").unwrap(), Some(make_wallet("irrelevant")), - return_route(cryptde), + return_route_with_id(cryptde, 1234), dns_resolve_failure.into(), 0, ); @@ -5607,7 +5436,9 @@ 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_info.get(&stream_key).is_none(), true); + 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); }), }) .unwrap(); @@ -5636,20 +5467,15 @@ mod tests { subject .keys_and_addrs .insert(stream_key.clone(), socket_addr.clone()); - let remaining_route = return_route(cryptde); - subject.stream_info.insert( - stream_key.clone(), - StreamInfoBuilder::new() - .route(RouteQueryResponse { - route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip( - vec![], - vec![ExpectedService::Nothing], - ), - host: Host::new("booga.com", HTTP_PORT), - }) - .protocol(ProxyProtocol::HTTP) - .build(), + let remaining_route = return_route_with_id(cryptde, 4321); + subject.route_ids_to_return_routes.insert( + 4321, + AddReturnRouteMessage { + return_route_id: 4321, + expected_services: vec![ExpectedService::Nothing], + protocol: ProxyProtocol::HTTP, + hostname_opt: None, + }, ); let subject_addr: Addr = subject.start(); @@ -5692,8 +5518,8 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port_opt: Some(80), - sequence_number_opt: Some(0), + reception_port: Some(80), + sequence_number: Some(0), last_data: false, is_clandestine: false, data: expected_data.clone(), @@ -5731,7 +5557,57 @@ mod tests { .accountant(accountant) .build(); let client_response_payload = ClientResponsePayload_0v1 { - stream_key: stream_key.clone(), + 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(BindMessage { peer_actors }).unwrap(); + + subject_addr.try_send(expired_cores_package).unwrap(); + + 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"); + 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 = CRYPTDE_PAIR.main.as_ref(); + 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_PAIR.clone(), + 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, sequenced_packet: SequencedPacket { data: b"some data".to_vec(), sequence_number: 4321, @@ -5741,7 +5617,9 @@ mod tests { let expired_cores_package = ExpiredCoresPackage::new( SocketAddr::from_str("1.2.3.4:1234").unwrap(), Some(make_wallet("irrelevant")), - return_route(cryptde), + Route { + hops: vec![make_cover_hop(cryptde), CryptData::new(&[0])], + }, client_response_payload, 0, ); @@ -5751,11 +5629,74 @@ mod tests { System::current().stop(); system.run(); - 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()); + TestLogHandler::new().exists_log_containing( + "ERROR: ProxyServer: Can't report services consumed: DecryptionError(InvalidKey(\"Could not decrypt with", + ); 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 = CRYPTDE_PAIR.main.as_ref(); + 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_PAIR.clone(), + true, + Some(STANDARD_CONSUMING_WALLET_BALANCE), + false, + false, + ); + subject.route_ids_to_return_routes = 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( + 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 1234 for client response. Ignoring", 1000); + } + #[test] fn handle_stream_shutdown_msg_handles_unknown_peer_addr() { let mut subject = ProxyServer::new(CRYPTDE_PAIR.clone(), true, None, false, false); @@ -5764,17 +5705,16 @@ mod tests { subject .keys_and_addrs .insert(unaffected_stream_key, unaffected_socket_addr); - subject.stream_info.insert( + subject.stream_key_routes.insert( unaffected_stream_key, - StreamInfoBuilder::new() - .route(RouteQueryResponse { - route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip(vec![], vec![]), - host: Host::new("booga.com", HTTP_PORT), - }) - .tunneled_host("blah") - .build(), + RouteQueryResponse { + route: Route { hops: vec![] }, + expected_services: ExpectedServices::RoundTrip(vec![], vec![], 1234), + }, ); + 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(), @@ -5790,12 +5730,10 @@ 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(&unaffected_stream_key) - .unwrap() - .tunneled_host_opt - .is_some()); + .stream_key_routes + .contains_key(&unaffected_stream_key)); + assert!(subject.tunneled_hosts.contains_key(&unaffected_stream_key)); } #[test] @@ -5819,16 +5757,12 @@ mod tests { subject .keys_and_addrs .insert(affected_stream_key, affected_socket_addr); - subject.stream_info.insert( + subject.stream_key_routes.insert( unaffected_stream_key, - StreamInfoBuilder::new() - .route(RouteQueryResponse { - route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip(vec![], vec![]), - host: Host::new("gooba.com", HTTP_PORT), - }) - .tunneled_host("blah") - .build(), + RouteQueryResponse { + route: Route { hops: vec![] }, + expected_services: ExpectedServices::RoundTrip(vec![], vec![], 1234), + }, ); let affected_route = Route::round_trip( RouteSegment::new( @@ -5847,6 +5781,7 @@ mod tests { ), CRYPTDE_PAIR.main.as_ref(), Some(make_paying_wallet(b"consuming")), + 1234, Some(TEST_DEFAULT_CHAIN.rec().contract), ) .unwrap(); @@ -5855,20 +5790,23 @@ mod tests { make_paying_wallet(b"1234"), DEFAULT_RATE_PACK, )]; - subject.stream_info.insert( + subject.stream_key_routes.insert( affected_stream_key, - StreamInfoBuilder::new() - .route(RouteQueryResponse { - route: affected_route.clone(), - expected_services: ExpectedServices::RoundTrip( - affected_expected_services, - vec![], - ), - host: Host::new("gooba.com", TLS_PORT), - }) - .tunneled_host("tunneled.com") - .build(), + RouteQueryResponse { + route: affected_route.clone(), + expected_services: ExpectedServices::RoundTrip( + affected_expected_services, + vec![], + 1234, + ), + }, ); + 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(); @@ -5902,8 +5840,8 @@ mod tests { ClientRequestPayload_0v1 { stream_key: affected_stream_key, sequenced_packet: SequencedPacket::new(vec![], 1234, true), - target_hostname: String::from("tunneled.com"), - target_port: TLS_PORT, + target_hostname: Some(String::from("tunneled.com")), + target_port: 443, protocol: ProxyProtocol::TLS, originator_public_key: CRYPTDE_PAIR.alias.as_ref().public_key().clone(), } @@ -5949,15 +5887,12 @@ mod tests { subject .keys_and_addrs .insert(affected_stream_key, affected_socket_addr); - subject.stream_info.insert( + subject.stream_key_routes.insert( unaffected_stream_key, - StreamInfoBuilder::new() - .route(RouteQueryResponse { - route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip(vec![], vec![]), - host: Host::new("booga.com", HTTP_PORT), - }) - .build(), + RouteQueryResponse { + route: Route { hops: vec![] }, + expected_services: ExpectedServices::RoundTrip(vec![], vec![], 1234), + }, ); let affected_route = Route::round_trip( RouteSegment::new( @@ -5976,6 +5911,7 @@ mod tests { ), CRYPTDE_PAIR.main.as_ref(), Some(make_paying_wallet(b"consuming")), + 1234, Some(TEST_DEFAULT_CHAIN.rec().contract), ) .unwrap(); @@ -5984,18 +5920,16 @@ mod tests { make_paying_wallet(b"1234"), DEFAULT_RATE_PACK, )]; - subject.stream_info.insert( + subject.stream_key_routes.insert( affected_stream_key, - StreamInfoBuilder::new() - .route(RouteQueryResponse { - route: affected_route.clone(), - expected_services: ExpectedServices::RoundTrip( - affected_expected_services, - vec![], - ), - host: Host::new("booga.com", HTTP_PORT), - }) - .build(), + RouteQueryResponse { + route: affected_route.clone(), + expected_services: ExpectedServices::RoundTrip( + affected_expected_services, + vec![], + 1234, + ), + }, ); subject.logger = Logger::new(test_name); let subject_addr = subject.start(); @@ -6031,7 +5965,7 @@ mod tests { ClientRequestPayload_0v1 { stream_key: affected_stream_key, sequenced_packet: SequencedPacket::new(vec![], 1234, true), - target_hostname: "booga.com".to_string(), + target_hostname: None, target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: CRYPTDE_PAIR.alias.as_ref().public_key().clone(), @@ -6070,9 +6004,6 @@ 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 { @@ -6099,17 +6030,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_info.insert( + subject.stream_key_routes.insert( stream_key, - StreamInfoBuilder::new() - .route(RouteQueryResponse { - route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip(vec![], vec![]), - host: Host::new("booga.com", HTTP_PORT), - }) - .tunneled_host("blah") - .build(), + RouteQueryResponse { + route: Route { hops: vec![] }, + expected_services: ExpectedServices::RoundTrip(vec![], vec![], 0), + }, ); + subject + .tunneled_hosts + .insert(stream_key, "blah".to_string()); let msg = StreamShutdownMsg { peer_addr: socket_addr, stream_type: RemovedStreamType::NonClandestine(NonClandestineAttributes { @@ -6125,13 +6055,14 @@ mod tests { let after = SystemTime::now(); let handle_normal_client_data = help_to_handle_normal_client_data_params_arc.lock().unwrap(); - let inbound_client_data_msg = &handle_normal_client_data[0]; + let (inbound_client_data_msg, retire_stream_key) = &handle_normal_client_data[0]; assert_eq!(inbound_client_data_msg.client_addr, socket_addr); assert_eq!(inbound_client_data_msg.data, Vec::::new()); assert_eq!(inbound_client_data_msg.last_data, true); assert_eq!(inbound_client_data_msg.is_clandestine, false); let actual_timestamp = inbound_client_data_msg.timestamp; assert!(before <= actual_timestamp && actual_timestamp <= after); + assert_eq!(*retire_stream_key, true) } #[test] @@ -6141,15 +6072,18 @@ mod tests { let inbound_client_data_msg = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:4578").unwrap(), - reception_port_opt: None, + reception_port: None, last_data: true, is_clandestine: false, - sequence_number_opt: Some(123), + sequence_number: Some(123), data: vec![], }; - let result = IBCDHelperReal::new() - .handle_normal_client_data(&mut proxy_server, inbound_client_data_msg); + let result = IBCDHelperReal::new().handle_normal_client_data( + &mut proxy_server, + inbound_client_data_msg, + true, + ); assert_eq!( result, @@ -6177,10 +6111,16 @@ 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"); - subject.resolve_message(args, proxy_server_sub, Err(MailboxError::Timeout)); + subject.resolve_message( + args, + add_return_route_sub, + proxy_server_sub, + Err(MailboxError::Timeout), + ); System::current().stop(); system.run(); @@ -6198,63 +6138,22 @@ mod tests { #[derive(Default)] struct ClientRequestPayloadFactoryMock { - make_params: Arc< - Mutex< - Vec<( - InboundClientData, - StreamKey, - Option, - Box, - Logger, - )>, - >, - >, make_results: RefCell>>, } impl ClientRequestPayloadFactory for ClientRequestPayloadFactoryMock { fn make( &self, - ibcd: &InboundClientData, - stream_key: StreamKey, - host_opt: Option, - cryptde: &dyn CryptDE, - logger: &Logger, + _ibcd: &InboundClientData, + _stream_key: StreamKey, + _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< - Mutex< - Vec<( - InboundClientData, - StreamKey, - Option, - Box, - Logger, - )>, - >, - >, - ) -> Self { - self.make_params = params.clone(); - self - } - fn make_result(self, result: Option) -> Self { self.make_results.borrow_mut().push(result); self @@ -6276,15 +6175,18 @@ mod tests { let inbound_client_data_msg = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:4578").unwrap(), - reception_port_opt: Some(568), + reception_port: Some(568), last_data: true, is_clandestine: false, - sequence_number_opt: Some(123), + sequence_number: Some(123), data: vec![], }; - let result = IBCDHelperReal::new() - .handle_normal_client_data(&mut proxy_server, inbound_client_data_msg); + let result = IBCDHelperReal::new().handle_normal_client_data( + &mut proxy_server, + inbound_client_data_msg, + true, + ); assert_eq!( result, @@ -6294,7 +6196,7 @@ 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 alias_cryptde = CRYPTDE_PAIR.alias.as_ref(); let http_request = b"GET /index.html HTTP/1.1\r\nHost: nowhere.com\r\n\r\n"; let (neighborhood_mock, _, _) = make_recorder(); let destination_key = PublicKey::from(&b"our destination"[..]); @@ -6303,8 +6205,8 @@ mod tests { expected_services: ExpectedServices::RoundTrip( vec![make_exit_service_from_key(destination_key.clone())], vec![], + 1234, ), - 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(); @@ -6312,8 +6214,8 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port_opt: Some(HTTP_PORT), - sequence_number_opt: Some(0), + reception_port: Some(HTTP_PORT), + sequence_number: Some(0), last_data: true, is_clandestine: false, data: expected_data.clone(), @@ -6322,13 +6224,14 @@ mod tests { .make( &msg_from_dispatcher, stream_key.clone(), - None, - CRYPTDE_PAIR.alias.as_ref(), + alias_cryptde, &Logger::new("test"), ) .unwrap(); let stream_key_factory = StreamKeyFactoryMock::new().make_result(stream_key.clone()); - let system = System::new(test_name); + let system = System::new( + "proxy_server_receives_http_request_from_dispatcher_then_sends_cores_package_to_hopper", + ); let mut subject = ProxyServer::new( CRYPTDE_PAIR.clone(), true, @@ -6348,12 +6251,7 @@ mod tests { subject_addr .try_send(AssertionsMessage { assertions: Box::new(move |proxy_server: &mut ProxyServer| { - let dns_retry = proxy_server - .stream_info(&stream_key) - .unwrap() - .dns_failure_retry_opt - .as_ref() - .unwrap(); + let dns_retry = proxy_server.dns_failure_retries.get(&stream_key).unwrap(); assert_eq!(dns_retry.retries_left, 3); assert_eq!(dns_retry.unsuccessful_request, expected_payload); }), @@ -6365,8 +6263,6 @@ 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 http_request = b"GET /index.html HTTP/1.1\r\nHost: nowhere.com\r\n\r\n"; let (neighborhood_mock, _, _) = make_recorder(); let destination_key = PublicKey::from(&b"our destination"[..]); @@ -6375,8 +6271,8 @@ mod tests { expected_services: ExpectedServices::RoundTrip( vec![make_exit_service_from_key(destination_key.clone())], vec![], + 1234, ), - 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(); @@ -6384,8 +6280,8 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port_opt: Some(HTTP_PORT), - sequence_number_opt: Some(0), + reception_port: Some(HTTP_PORT), + sequence_number: Some(0), last_data: true, is_clandestine: false, data: expected_data.clone(), @@ -6394,13 +6290,14 @@ mod tests { .make( &msg_from_dispatcher, stream_key.clone(), - None, CRYPTDE_PAIR.alias.as_ref(), &Logger::new("test"), ) .unwrap(); let stream_key_factory = StreamKeyFactoryMock::new().make_result(stream_key.clone()); - let system = System::new(test_name); + let system = System::new( + "new_http_request_creates_new_exhausted_entry_inside_dns_retries_hashmap_zero_hop", + ); let mut subject = ProxyServer::new( CRYPTDE_PAIR.clone(), false, @@ -6420,12 +6317,7 @@ mod tests { subject_addr .try_send(AssertionsMessage { assertions: Box::new(move |proxy_server: &mut ProxyServer| { - let dns_retry = proxy_server - .stream_info(&stream_key) - .unwrap() - .dns_failure_retry_opt - .as_ref() - .unwrap(); + let dns_retry = proxy_server.dns_failure_retries.get(&stream_key).unwrap(); assert_eq!(dns_retry.retries_left, 0); assert_eq!(dns_retry.unsuccessful_request, expected_payload); }), @@ -6515,15 +6407,18 @@ mod tests { let inbound_client_data_msg = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:4578").unwrap(), - reception_port_opt: Some(80), + reception_port: Some(80), last_data: true, is_clandestine: false, - sequence_number_opt: Some(123), + sequence_number: Some(123), data: expected_data, }; - let result = IBCDHelperReal::new() - .handle_normal_client_data(&mut proxy_server, inbound_client_data_msg); + let result = IBCDHelperReal::new().handle_normal_client_data( + &mut proxy_server, + inbound_client_data_msg, + true, + ); assert_eq!( result, @@ -6531,78 +6426,6 @@ mod tests { ); } - #[test] - fn make_payload_passes_no_hostname_if_none_is_known() { - let mut subject = ProxyServer::new(CRYPTDE_PAIR.clone(), 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_opt: 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(CRYPTDE_PAIR.clone(), 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_opt: 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" @@ -6643,10 +6466,10 @@ mod tests { let ibcd = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr, - reception_port_opt: Some(2222), + reception_port: Some(2222), last_data: true, is_clandestine: false, - sequence_number_opt: Some(333), + sequence_number: Some(333), data: b"GET /index.html HTTP/1.1\r\nHost: header.com:3333\r\n\r\n".to_vec(), }; @@ -6667,10 +6490,10 @@ mod tests { let ibcd = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr, - reception_port_opt: Some(2222), + reception_port: Some(2222), last_data: true, is_clandestine: false, - sequence_number_opt: Some(333), + sequence_number: Some(333), data: b"GET /index.html HTTP/1.1\r\nHost: header.com:4444\r\n\r\n".to_vec(), }; @@ -6683,30 +6506,6 @@ mod tests { ); } - 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 { ExpectedService::Exit(public_key, make_wallet("exit wallet"), rate_pack(100)) } diff --git a/node/src/proxy_server/protocol_pack.rs b/node/src/proxy_server/protocol_pack.rs index e5607bb082..9697ce6a22 100644 --- a/node/src/proxy_server/protocol_pack.rs +++ b/node/src/proxy_server/protocol_pack.rs @@ -3,16 +3,29 @@ use crate::proxy_server::http_protocol_pack::HttpProtocolPack; use crate::proxy_server::tls_protocol_pack::TlsProtocolPack; use crate::sub_lib::cryptde::PlainData; use crate::sub_lib::dispatcher::InboundClientData; -use crate::sub_lib::host::Host; 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, + } + } +} + pub trait ProtocolPack: Send + Sync { fn proxy_protocol(&self) -> ProxyProtocol; fn standard_port(&self) -> u16; fn find_host(&self, data: &PlainData) -> Option; fn server_impersonator(&self) -> Box; - fn describe_packet(&self, data: &PlainData) -> String; } pub fn from_protocol(protocol: ProxyProtocol) -> Box { @@ -31,7 +44,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_opt { + let origin_port = match ibcd.reception_port { None => { return Err(format!( "No origin port specified with {}-byte non-clandestine packet: {:?}", @@ -54,6 +67,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: String) -> Vec; + fn dns_resolution_failure_response(&self, server_name_opt: Option) -> 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 9de02301d4..554741aaed 100644 --- a/node/src/proxy_server/server_impersonator_http.rs +++ b/node/src/proxy_server/server_impersonator_http.rs @@ -19,9 +19,11 @@ impl ServerImpersonator for ServerImpersonatorHttp { ) } - fn dns_resolution_failure_response(&self, server_name: String) -> Vec { - let (server_name, quoted_server_name) = - (server_name.clone(), format!("\"{}\"", server_name)); + 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()), + }; ServerImpersonatorHttp::make_error_response( 503, "DNS Resolution Problem", @@ -195,7 +197,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("server.com".to_string()); + let result = subject.dns_resolution_failure_response(Some("server.com".to_string())); let expected = ServerImpersonatorHttp::make_error_response( 503, @@ -206,6 +208,21 @@ 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 3312be6569..7a193a2699 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: String) -> Vec { + fn dns_resolution_failure_response(&self, _server_name: Option) -> 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("booga.com".to_string()); + let result = subject.dns_resolution_failure_response(None); 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 bb81f85430..d167ef0fa8 100644 --- a/node/src/proxy_server/tls_protocol_pack.rs +++ b/node/src/proxy_server/tls_protocol_pack.rs @@ -1,13 +1,11 @@ // Copyright (c) 2019, MASQ (https://masq.ai) and/or its affiliates. All rights reserved. -use crate::proxy_server::protocol_pack::{ProtocolPack, ServerImpersonator}; +use crate::proxy_server::protocol_pack::{Host, 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::host::Host; use crate::sub_lib::proxy_server::ProxyProtocol; use masq_lib::constants::TLS_PORT; -#[derive(Clone, Copy)] pub struct TlsProtocolPack {} impl ProtocolPack for TlsProtocolPack { @@ -39,21 +37,6 @@ impl ProtocolPack for TlsProtocolPack { fn server_impersonator(&self) -> Box { Box::new(ServerImpersonatorTls {}) } - - fn describe_packet(&self, data: &PlainData) -> String { - match data.get_u8(0) { - Some(0x16u8) => self.describe_handshake(data), - Some(0x14u8) => self.describe_cipher_spec(data), - Some(0x15u8) => self.describe_alert(data), - Some(0x17u8) => self.describe_application_data(data), - Some(opcode) => format!( - "{}-byte packet of unrecognized type 0x{:02X}", - data.len(), - opcode - ), - None => format!("Incomplete {}-byte TLS packet", data.len()), - } - } } impl TlsProtocolPack { @@ -116,89 +99,6 @@ impl TlsProtocolPack { Err(_) => Err(()), } } - - fn describe_handshake(&self, data: &PlainData) -> String { - match data.get_u8(5) { - Some(0x00u8) => "HelloRequest".to_string(), - Some(0x01u8) => self.describe_client_hello(data), - Some(0x02u8) => "ServerHello".to_string(), - Some(0x03u8) => "HelloVerifyRequest".to_string(), - Some(0x04u8) => "NewSessionTicket".to_string(), - Some(0x05u8) => "EndOfEarlyData".to_string(), - Some(0x06u8) => "HelloRetryRequest".to_string(), - Some(0x0Bu8) => "Certificate".to_string(), - Some(0x0Cu8) => "ServerKeyExchange".to_string(), - Some(0x0Du8) => "CertificateRequest".to_string(), - Some(0x0Eu8) => "ServerHelloDone".to_string(), - Some(0x0Fu8) => "CertificateVerify".to_string(), - Some(0x10u8) => "ClientKeyExchange".to_string(), - Some(0x14u8) => "Finished".to_string(), - Some(opcode) => format!("Unrecognized Handshake 0x{:02X}", opcode), - None => format!("Incomplete {}-byte Handshake packet", data.len()), - } - } - - fn describe_client_hello(&self, data: &PlainData) -> String { - match self.find_host(data) { - Some(host) => format!("ClientHello with SNI '{}'", host.name), - None => "ClientHello with no SNI extension".to_string(), - } - } - - fn describe_cipher_spec(&self, data: &PlainData) -> String { - match data.get_u8(5) { - Some(0x01u8) => "ChangeCipherSpec".to_string(), - Some(opcode) => format!("Unrecognized ChangeCipherSpec 0x{:02X}", opcode), - None => format!("Incomplete {}-byte ChangeCipherSpec packet", data.len()), - } - } - - fn describe_alert(&self, data: &PlainData) -> String { - let level = match data.get_u8(5) { - Some(0x01u8) => "Warning".to_string(), - Some(0x02u8) => "Fatal".to_string(), - Some(opcode) => format!("Unrecognized Alert Level 0x{:02X}", opcode), - None => return format!("Incomplete {}-byte Alert packet", data.len()), - }; - let description = match data.get_u8(6) { - Some(0x00) => "CloseNotify".to_string(), - Some(0x01) => "Unrecognized Alert Description 0x01".to_string(), - Some(0x0A) => "UnexpectedMessage".to_string(), - Some(0x14) => "BadRecordMAC".to_string(), - Some(0x15) => "DecryptionFailed".to_string(), - Some(0x16) => "RecordOverflow".to_string(), - Some(0x1E) => "DecompressionFailure".to_string(), - Some(0x28) => "HandshakeFailure".to_string(), - Some(0x29) => "NoCertificate".to_string(), - Some(0x2A) => "BadCertificate".to_string(), - Some(0x2B) => "UnsupportedCertificate".to_string(), - Some(0x2C) => "CertificateRevoked".to_string(), - Some(0x2D) => "CertificateExpired".to_string(), - Some(0x2E) => "CertificateUnknown".to_string(), - Some(0x2F) => "IllegalParameter".to_string(), - Some(0x30) => "UnknownCA".to_string(), - Some(0x31) => "AccessDenied".to_string(), - Some(0x32) => "DecodeError".to_string(), - Some(0x33) => "DecryptError".to_string(), - Some(0x3C) => "ExportRestriction".to_string(), - Some(0x46) => "ProtocolVersion".to_string(), - Some(0x47) => "InsufficientSecurity".to_string(), - Some(0x50) => "InternalError".to_string(), - Some(0x5A) => "UserCanceled".to_string(), - Some(0x64) => "NoRenegotiation".to_string(), - Some(0x72) => "UnsupportedExtension".to_string(), - Some(opcode) => format!("Unrecognized Alert Description 0x{:02X}", opcode), - None => return format!("Incomplete {}-byte Alert packet", data.len()), - }; - format!("{} {}", level, description) - } - - fn describe_application_data(&self, data: &PlainData) -> String { - if data.len() < 5 { - return "Incomplete ApplicationData".to_string(); - } - format!("{}-byte ApplicationData", data.len() - 5) - } } #[cfg(test)] @@ -896,256 +796,4 @@ mod tests { assert_eq!(None, result); } - - #[test] - fn describe_packet_handles_empty_packet() { - let data = PlainData::new(&[]); - - let result = TlsProtocolPack {}.describe_packet(&data); - - assert_eq!("Incomplete 0-byte TLS packet", result); - } - - #[test] - fn describe_packet_handles_unrecognized_packet_type() { - let data = PlainData::new(&[0xFFu8]); - - let result = TlsProtocolPack {}.describe_packet(&data); - - assert_eq!("1-byte packet of unrecognized type 0xFF", result); - } - - #[test] - fn describe_packet_handles_short_handshake_packet() { - let data = PlainData::new(&[0x16u8]); - - let result = TlsProtocolPack {}.describe_packet(&data); - - assert_eq!("Incomplete 1-byte Handshake packet", result); - } - - #[test] - fn identifies_client_hello_with_sni() { - #[rustfmt::skip] - let data = PlainData::new(&[ - 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, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // random: don't care - 0x01, // session_id_length - 0x00, // session_id: don't care - 0x00, 0x01, // cipher_suites_length - 0x00, // cipher_suite: don't care - 0x01, // compression_methods_length - 0x00, // compression_method: don't care - 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 result = TlsProtocolPack {}.describe_packet(&data); - - assert_eq!("ClientHello with SNI 'server.com'", result); - } - - #[test] - fn identifies_client_hello_without_sni() { - #[rustfmt::skip] - let data = PlainData::new(&[ - 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, - 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, 0x00, // extensions_length - ]); - - let result = TlsProtocolPack {}.describe_packet(&data); - - assert_eq!("ClientHello with no SNI extension", result); - } - - #[test] - fn identifies_other_handshakes() { - #[rustfmt::skip] - let mut bytes: Vec = vec![ - 0x16, // content_type: Handshake - 0x00, 0x00, 0x00, 0x00, // version, length: don't care - 0x00, // handshake_type: replace me - ]; - let handshake_types = vec![ - (0x00, "HelloRequest"), - (0x02, "ServerHello"), - (0x03, "HelloVerifyRequest"), - (0x04, "NewSessionTicket"), - (0x05, "EndOfEarlyData"), - (0x06, "HelloRetryRequest"), - (0x07, "Unrecognized Handshake 0x07"), - (0x08, "Unrecognized Handshake 0x08"), - (0x0B, "Certificate"), - (0x0C, "ServerKeyExchange"), - (0x0D, "CertificateRequest"), - (0x0E, "ServerHelloDone"), - (0x0F, "CertificateVerify"), - (0x10, "ClientKeyExchange"), - (0x14, "Finished"), - ]; - handshake_types.iter().for_each(|(opcode, name)| { - bytes[5] = *opcode; - let data = PlainData::new(&bytes); - - let result = TlsProtocolPack {}.describe_packet(&data); - - assert_eq!(*name, result); - }); - } - - #[test] - fn identifies_cipher_spec_packets() { - #[rustfmt::skip] - let mut bytes: Vec = vec![ - 0x14, // content_type: ChangeCipherSpec - 0x00, 0x00, 0x00, 0x00, // version, length: don't care - 0x00, // change_cipher_spec: replace me - ]; - let change_cipher_specs = vec![ - (0x00, "Unrecognized ChangeCipherSpec 0x00"), - (0x01, "ChangeCipherSpec"), - (0x02, "Unrecognized ChangeCipherSpec 0x02"), - ]; - change_cipher_specs.iter().for_each(|(opcode, name)| { - bytes[5] = *opcode; - let data = PlainData::new(&bytes); - - let result = TlsProtocolPack {}.describe_packet(&data); - - assert_eq!(*name, result); - }); - } - - #[test] - fn handles_incomplete_cipher_spec_packet() { - #[rustfmt::skip] - let data = PlainData::new(&[ - 0x14, // content_type: ChangeCipherSpec - ]); - - let result = TlsProtocolPack {}.describe_packet(&data); - - assert_eq!("Incomplete 1-byte ChangeCipherSpec packet", result); - } - - #[test] - fn identifies_alert_packets() { - #[rustfmt::skip] - let mut bytes: Vec = vec![ - 0x15, // content_type: Alert - 0x00, 0x00, 0x00, 0x00, // version, length: don't care - 0x00, // alert_level: replace me - 0x00, // alert_description: replace me - ]; - let alert_levels = vec![ - (0x01, "Warning"), - (0x02, "Fatal"), - (0x03, "Unrecognized Alert Level 0x03"), - (0x04, "Unrecognized Alert Level 0x04"), - ]; - let alert_descriptions = vec![ - (0x00, "CloseNotify"), - (0x01, "Unrecognized Alert Description 0x01"), - (0x0A, "UnexpectedMessage"), - (0x14, "BadRecordMAC"), - (0x15, "DecryptionFailed"), - (0x16, "RecordOverflow"), - (0x1E, "DecompressionFailure"), - (0x28, "HandshakeFailure"), - (0x29, "NoCertificate"), - (0x2A, "BadCertificate"), - (0x2B, "UnsupportedCertificate"), - (0x2C, "CertificateRevoked"), - (0x2D, "CertificateExpired"), - (0x2E, "CertificateUnknown"), - (0x2F, "IllegalParameter"), - (0x30, "UnknownCA"), - (0x31, "AccessDenied"), - (0x32, "DecodeError"), - (0x33, "DecryptError"), - (0x3C, "ExportRestriction"), - (0x46, "ProtocolVersion"), - (0x47, "InsufficientSecurity"), - (0x50, "InternalError"), - (0x5A, "UserCanceled"), - (0x64, "NoRenegotiation"), - (0x72, "UnsupportedExtension"), - (0xFF, "Unrecognized Alert Description 0xFF"), - ]; - alert_descriptions - .iter() - .for_each(|(description, description_name)| { - bytes[6] = *description; - alert_levels.iter().for_each(|(level, level_name)| { - bytes[5] = *level; - let data = PlainData::new(&bytes); - - let result = TlsProtocolPack {}.describe_packet(&data); - - let expected = format!("{} {}", level_name, description_name); - assert_eq!(expected, result); - }); - }); - } - - #[test] - fn handles_incomplete_alert_packet() { - #[rustfmt::skip] - let data = PlainData::new(&[ - 0x15, // content_type: Alert - ]); - - let result = TlsProtocolPack {}.describe_packet(&data); - - assert_eq!("Incomplete 1-byte Alert packet", result); - } - - #[test] - fn identifies_application_data_packets() { - #[rustfmt::skip] - let data = PlainData::new(&[ - 0x17, // content_type: ApplicationData - 0x00, 0x00, 0x00, 0x00, // version, length: don't care - 0x01, 0x02, 0x03, 0x04, 0x05, // data - ]); - - let result = TlsProtocolPack {}.describe_packet(&data); - - assert_eq!("5-byte ApplicationData", result); - } - - #[test] - fn handles_short_application_data_packets() { - #[rustfmt::skip] - let data = PlainData::new(&[ - 0x17, // content_type: ApplicationData - 0x00, 0x00, 0x00, // Too short by one byte - ]); - - let result = TlsProtocolPack {}.describe_packet(&data); - - assert_eq!("Incomplete ApplicationData", result); - } } diff --git a/node/src/stream_handler_pool.rs b/node/src/stream_handler_pool.rs index b759a703cc..7aa6d0ff6c 100644 --- a/node/src/stream_handler_pool.rs +++ b/node/src/stream_handler_pool.rs @@ -516,7 +516,7 @@ impl StreamHandlerPool { sw_key ); debug!(self.logger, "Masking {} bytes", msg.context.data.len()); - let packet = if msg.context.sequence_number_opt.is_none() { + let packet = if msg.context.sequence_number.is_none() { let masquerader = self.traffic_analyzer.get_masquerader(); match masquerader.mask(msg.context.data.as_slice()) { Ok(masked_data) => SequencedPacket::new(masked_data, 0, false), @@ -849,7 +849,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_opt = Some(8081); + let reception_port = 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(); @@ -901,7 +901,7 @@ mod tests { .add_sub .try_send(AddStreamMsg::new( connection_info, // the stream splitter mock will return mocked reader/writer - reception_port_opt, + reception_port, PortConfiguration::new( vec![Box::new(HttpRequestDiscriminatorFactory::new())], is_clandestine, @@ -922,10 +922,10 @@ mod tests { &dispatcher::InboundClientData { timestamp: dispatcher_record.timestamp, client_addr: peer_addr_a, - reception_port_opt, + reception_port, last_data: false, is_clandestine, - sequence_number_opt: Some(0), + sequence_number: Some(0), data: one_http_req_a, } ); @@ -936,10 +936,10 @@ mod tests { &dispatcher::InboundClientData { timestamp: dispatcher_record.timestamp, client_addr: peer_addr_a, - reception_port_opt, + reception_port, last_data: false, is_clandestine, - sequence_number_opt: Some(1), + sequence_number: Some(1), data: another_http_req_a, } ); @@ -950,10 +950,10 @@ mod tests { &dispatcher::InboundClientData { timestamp: dispatcher_record.timestamp, client_addr: peer_addr_a, - reception_port_opt, + reception_port, last_data: false, is_clandestine, - sequence_number_opt: Some(2), + sequence_number: Some(2), data: a_third_http_req_a, } ); @@ -963,7 +963,7 @@ mod tests { &dispatcher::StreamShutdownMsg { peer_addr: peer_addr_a, stream_type: RemovedStreamType::NonClandestine(NonClandestineAttributes { - reception_port: reception_port_opt.unwrap(), + reception_port: reception_port.unwrap(), sequence_number: 3 }), report_to_counterpart: true, @@ -1025,7 +1025,7 @@ mod tests { .try_send(TransmitDataMsg { endpoint: Endpoint::Socket(peer_addr), last_data: true, - sequence_number_opt: Some(0), + sequence_number: Some(0), data: b"hello".to_vec(), }) .unwrap(); @@ -1107,7 +1107,7 @@ mod tests { .try_send(TransmitDataMsg { endpoint: Endpoint::Socket(peer_addr), last_data: true, - sequence_number_opt: Some(0), + sequence_number: Some(0), data: vec![0x12, 0x34], }) .unwrap(); @@ -1130,7 +1130,7 @@ mod tests { .try_send(TransmitDataMsg { endpoint: Endpoint::Socket(peer_addr), last_data: true, - sequence_number_opt: Some(0), + sequence_number: Some(0), data: vec![0x56, 0x78], }) .unwrap(); @@ -1209,7 +1209,7 @@ mod tests { .try_send(TransmitDataMsg { endpoint: Endpoint::Socket(peer_addr), last_data: true, - sequence_number_opt: Some(0), + sequence_number: Some(0), data: vec![0x12, 0x34], }) .unwrap(); @@ -1381,7 +1381,7 @@ mod tests { context: TransmitDataMsg { endpoint: Endpoint::Key(public_key), last_data: false, - sequence_number_opt: None, + sequence_number: None, data: b"hello".to_vec(), }, }) @@ -1470,7 +1470,7 @@ mod tests { .try_send(TransmitDataMsg { endpoint: Endpoint::Key(public_key.clone()), last_data: false, - sequence_number_opt: None, + sequence_number: None, data: outgoing_unmasked, }) .unwrap(); @@ -1505,10 +1505,10 @@ mod tests { &InboundClientData { timestamp: ibcd.timestamp, client_addr: SocketAddr::from_str("1.2.3.5:7000").unwrap(), - reception_port_opt: Some(54321), + reception_port: Some(54321), last_data: false, is_clandestine: true, - sequence_number_opt: None, + sequence_number: None, data: incoming_unmasked, } ); @@ -1586,7 +1586,7 @@ mod tests { .try_send(TransmitDataMsg { endpoint: Endpoint::Key(key.clone()), last_data: false, - sequence_number_opt: Some(0), + sequence_number: Some(0), data: b"hello".to_vec(), }) .unwrap(); @@ -1646,7 +1646,7 @@ mod tests { context: TransmitDataMsg { endpoint: Endpoint::Key(key.clone()), last_data: false, - sequence_number_opt: Some(0), + sequence_number: Some(0), data: b"hello".to_vec(), }, }) @@ -1698,7 +1698,7 @@ mod tests { context: TransmitDataMsg { endpoint: Endpoint::Key(key.clone()), last_data: false, - sequence_number_opt: None, + sequence_number: None, data: b"hello".to_vec(), }, }) @@ -1728,7 +1728,7 @@ mod tests { let msg = TransmitDataMsg { endpoint: Endpoint::Socket(peer_addr.clone()), last_data: false, - sequence_number_opt: Some(0), + sequence_number: Some(0), data: b"hello".to_vec(), }; let msg_a = msg.clone(); @@ -1840,7 +1840,7 @@ mod tests { context: TransmitDataMsg { endpoint: Endpoint::Socket(peer_addr.clone()), last_data: true, - sequence_number_opt: Some(0), + sequence_number: Some(0), data: b"hello".to_vec(), }, }; @@ -1869,13 +1869,13 @@ mod tests { let msg = TransmitDataMsg { endpoint: Endpoint::Socket(peer_addr.clone()), last_data: false, - sequence_number_opt: None, + sequence_number: None, data: b"hello".to_vec(), }; let msg_a = TransmitDataMsg { endpoint: Endpoint::Socket(peer_addr.clone()), last_data: false, - sequence_number_opt: None, + sequence_number: None, data: b"worlds".to_vec(), }; let expected_data = JsonMasquerader::new().mask(&msg_a.data).unwrap(); @@ -1995,7 +1995,7 @@ mod tests { context: TransmitDataMsg { endpoint: Endpoint::Socket(peer_addr.clone()), last_data: true, - sequence_number_opt: Some(0), + sequence_number: Some(0), data: b"hello".to_vec(), }, }); @@ -2035,7 +2035,7 @@ mod tests { let msg = TransmitDataMsg { endpoint: Endpoint::Socket(peer_addr.clone()), last_data: false, - sequence_number_opt: None, + sequence_number: None, data: b"hello".to_vec(), }; @@ -2126,7 +2126,7 @@ mod tests { .try_send(TransmitDataMsg { endpoint: Endpoint::Socket(peer_addr), last_data: false, - sequence_number_opt: None, + sequence_number: None, data: hello, }) .unwrap(); @@ -2136,7 +2136,7 @@ mod tests { .try_send(TransmitDataMsg { endpoint: Endpoint::Socket(peer_addr), last_data: false, - sequence_number_opt: None, + sequence_number: None, data: worlds, }) .unwrap(); @@ -2200,7 +2200,7 @@ mod tests { .try_send(TransmitDataMsg { endpoint: Endpoint::Socket(peer_addr), last_data: false, - sequence_number_opt: None, + sequence_number: None, data: b"hello".to_vec(), }) .unwrap(); @@ -2249,7 +2249,7 @@ mod tests { .try_send(TransmitDataMsg { endpoint: Endpoint::Socket(local_addr), last_data: false, - sequence_number_opt: Some(0), + sequence_number: Some(0), data: outgoing_unmasked, }) .unwrap(); diff --git a/node/src/stream_reader.rs b/node/src/stream_reader.rs index df8dd8f33f..cac9211a67 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_opt: Option, + reception_port: 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_opt: Option, + reception_port: Option, ibcd_sub: Recipient, remove_sub: Recipient, dispatcher_sub: Recipient, @@ -107,7 +107,7 @@ impl StreamReaderReal { stream, local_addr, peer_addr, - reception_port_opt, + reception_port, ibcd_sub, remove_sub, dispatcher_stream_shutdown_sub: dispatcher_sub, @@ -137,7 +137,7 @@ impl StreamReaderReal { // handshake and should start the sequence at Some(0) as well, the ProxyServer will // handle the sequenced packet offset before sending them through the stream_writer // and avoid dropping duplicate packets. - let sequence_number_opt = if unmasked_chunk.sequenced && !is_connect { + let sequence_number = if unmasked_chunk.sequenced && !is_connect { Some(self.sequencer.next_sequence_number()) } else if is_connect { // This case needs to explicitly be Some(0) instead of None so that the StreamHandlerPool does @@ -146,7 +146,7 @@ impl StreamReaderReal { } else { None }; - match sequence_number_opt { + match sequence_number { Some(num) => debug!( self.logger, "Read {} bytes of clear data (#{})", @@ -162,10 +162,10 @@ impl StreamReaderReal { let msg = dispatcher::InboundClientData { timestamp: SystemTime::now(), client_addr: self.peer_addr, - reception_port_opt: self.reception_port_opt, + reception_port: self.reception_port, last_data: false, is_clandestine: self.is_clandestine, - sequence_number_opt, + sequence_number, data: unmasked_chunk.chunk.clone(), }; debug!(self.logger, "Discriminator framed and unmasked {} bytes for {}; transmitting via Hopper", @@ -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_opt, 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, 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_opt.expect( + reception_port: self.reception_port.expect( "Non-clandestine StreamReader should always have a reception_port", ), sequence_number: self.sequencer.next_sequence_number(), @@ -511,10 +511,10 @@ mod tests { &dispatcher::InboundClientData { timestamp: d_record.timestamp, client_addr: peer_addr, - reception_port_opt: Some(1234 as u16), + reception_port: Some(1234 as u16), last_data: false, is_clandestine: true, - sequence_number_opt: Some(0), + sequence_number: Some(0), data: Vec::from("GET http://here.com HTTP/1.1\r\n\r\n".as_bytes()), } ); @@ -575,13 +575,13 @@ mod tests { Some(0), d_recording .get_record::(0) - .sequence_number_opt, + .sequence_number, ); assert_eq!( Some(0), d_recording .get_record::(1) - .sequence_number_opt, + .sequence_number, ); } @@ -633,10 +633,10 @@ mod tests { &dispatcher::InboundClientData { timestamp: d_record.timestamp, client_addr: peer_addr, - reception_port_opt: Some(1234 as u16), + reception_port: Some(1234 as u16), last_data: false, is_clandestine: false, - sequence_number_opt: Some(0), + sequence_number: Some(0), data: Vec::from("GET http://here.com HTTP/1.1\r\n\r\n".as_bytes()), } ); @@ -648,10 +648,10 @@ mod tests { &dispatcher::InboundClientData { timestamp: d_record.timestamp, client_addr: peer_addr, - reception_port_opt: Some(1234 as u16), + reception_port: Some(1234 as u16), last_data: false, is_clandestine: false, - sequence_number_opt: Some(1), + sequence_number: Some(1), data: Vec::from("GET http://www.example.com HTTP/1.1\r\n\r\n".as_bytes()), } ); @@ -707,10 +707,10 @@ mod tests { &dispatcher::InboundClientData { timestamp: d_record.timestamp, client_addr, - reception_port_opt: Some(1234 as u16), + reception_port: Some(1234 as u16), last_data: false, is_clandestine: true, - sequence_number_opt: None, + sequence_number: None, data: Vec::from("GET http://here.com HTTP/1.1\r\n\r\n".as_bytes()), } ); diff --git a/node/src/sub_lib/dispatcher.rs b/node/src/sub_lib/dispatcher.rs index e04401220b..66e349e112 100644 --- a/node/src/sub_lib/dispatcher.rs +++ b/node/src/sub_lib/dispatcher.rs @@ -116,10 +116,10 @@ pub enum DispatcherError { pub struct InboundClientData { pub timestamp: SystemTime, pub client_addr: SocketAddr, - pub reception_port_opt: Option, + pub reception_port: Option, pub last_data: bool, pub is_clandestine: bool, - pub sequence_number_opt: Option, + pub sequence_number: Option, pub data: Vec, } @@ -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_opt, self.last_data, self.sequence_number_opt, self.data.len(), data_string) + self.client_addr, self.reception_port, self.last_data, self.sequence_number, self.data.len(), data_string) } } @@ -139,10 +139,10 @@ impl InboundClientData { InboundClientData { timestamp: SystemTime::now(), client_addr: self.client_addr, - reception_port_opt: self.reception_port_opt, + reception_port: self.reception_port, last_data: self.last_data, is_clandestine: self.is_clandestine, - sequence_number_opt: self.sequence_number_opt, + sequence_number: self.sequence_number, data: vec![], } } @@ -274,10 +274,10 @@ mod tests { let subject = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.4.3.2:9999").unwrap(), - reception_port_opt: None, + reception_port: None, last_data: false, is_clandestine: false, - sequence_number_opt: None, + sequence_number: None, data: b"CONNECT server.example.com:80 HTTP/1.1\r\nHost: server.example.com:80\r\nProxy-Authorization: basic aGVsbG86d29ybGQ=\r\n\r\n".to_vec(), }; @@ -289,10 +289,10 @@ mod tests { let subject = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.4.3.2:9999").unwrap(), - reception_port_opt: None, + reception_port: None, last_data: false, is_clandestine: false, - sequence_number_opt: None, + sequence_number: None, data: b"GET server.example.com:80 HTTP/1.1\r\nHost: server.example.com:80\r\nProxy-Authorization: basic aGVsbG86d29ybGQ=\r\n\r\n".to_vec(), }; @@ -304,10 +304,10 @@ mod tests { let subject = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.4.3.2:9999").unwrap(), - reception_port_opt: None, + reception_port: None, last_data: false, is_clandestine: false, - sequence_number_opt: None, + sequence_number: None, data: b"CONNECTX".to_vec(), }; diff --git a/node/src/sub_lib/hopper.rs b/node/src/sub_lib/hopper.rs index 08af13bb58..96d756ef20 100644 --- a/node/src/sub_lib/hopper.rs +++ b/node/src/sub_lib/hopper.rs @@ -173,7 +173,6 @@ 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::{make_meaningless_message_type, make_paying_wallet}; use actix::Actor; @@ -206,7 +205,7 @@ mod tests { let cryptde = CRYPTDE_PAIR.main.as_ref(); 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(StreamKey::make_meaningless_stream_key()); + let payload = make_meaningless_message_type(); let result = NoLookupIncipientCoresPackage::new(cryptde, &public_key, &node_addr, payload.clone()); @@ -232,7 +231,7 @@ mod tests { cryptde, &PublicKey::new(&[]), &NodeAddr::new(&IpAddr::from_str("1.1.1.1").unwrap(), &[]), - make_meaningless_message_type(StreamKey::make_meaningless_stream_key()), + make_meaningless_message_type(), ); assert_eq!( result, @@ -256,7 +255,7 @@ mod tests { Some(TEST_DEFAULT_CHAIN.rec().contract), ) .unwrap(); - let payload = make_meaningless_message_type(StreamKey::make_meaningless_stream_key()); + let payload = make_meaningless_message_type(); let result = IncipientCoresPackage::new(cryptde, route.clone(), payload.clone(), &key56); let subject = result.unwrap(); @@ -279,7 +278,7 @@ mod tests { let result = IncipientCoresPackage::new( cryptde, Route { hops: vec![] }, - make_meaningless_message_type(StreamKey::make_meaningless_stream_key()), + make_meaningless_message_type(), &PublicKey::new(&[]), ); @@ -305,7 +304,7 @@ mod tests { Some(TEST_DEFAULT_CHAIN.rec().contract), ) .unwrap(); - let payload = make_meaningless_message_type(StreamKey::make_meaningless_stream_key()); + let payload = make_meaningless_message_type(); let subject: ExpiredCoresPackage = ExpiredCoresPackage::new( immediate_neighbor, diff --git a/node/src/sub_lib/host.rs b/node/src/sub_lib/host.rs deleted file mode 100644 index bb23d8d162..0000000000 --- a/node/src/sub_lib/host.rs +++ /dev/null @@ -1,39 +0,0 @@ -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()); - } -} diff --git a/node/src/sub_lib/http_packet_framer.rs b/node/src/sub_lib/http_packet_framer.rs index 28d4f895f2..29685f46b9 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("HttpPacketFramer"), + logger: Logger::new("HttpRequestFramer"), } } diff --git a/node/src/sub_lib/migrations/client_request_payload.rs b/node/src/sub_lib/migrations/client_request_payload.rs index b048c1900b..2bd9993f5d 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: Option = None; + let mut target_hostname_opt: Option> = None; let mut target_port_opt: Option = None; let mut protocol_opt: Option = None; let mut originator_public_key_opt: Option = None; @@ -61,7 +61,9 @@ impl TryFrom<&Value> for ClientRequestPayload_0v1 { "sequenced_packet" => { sequenced_packet_opt = value_to_type::(v) } - "target_hostname" => target_hostname = value_to_type::(v), + "target_hostname" => { + target_hostname_opt = value_to_type::>(v) + } "target_port" => target_port_opt = value_to_type::(v), "protocol" => protocol_opt = value_to_type::(v), "originator_public_key" => { @@ -87,7 +89,7 @@ impl TryFrom<&Value> for ClientRequestPayload_0v1 { "sequenced_packet", &sequenced_packet_opt, ); - check_field(&mut missing_fields, "target_hostname", &target_hostname); + check_field(&mut missing_fields, "target_hostname", &target_hostname_opt); check_field(&mut missing_fields, "target_port", &target_port_opt); check_field(&mut missing_fields, "protocol", &protocol_opt); check_field( @@ -101,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.expect("target_hostname disappeared"), + target_hostname: target_hostname_opt.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 @@ -129,7 +131,7 @@ mod tests { struct ExampleFutureCRP { pub stream_key: StreamKey, pub sequenced_packet: SequencedPacket, - pub target_hostname: String, + pub target_hostname: Option, pub target_port: u16, pub protocol: ProxyProtocol, pub originator_public_key: PublicKey, @@ -139,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: "target.hostname.com".to_string(), + target_hostname: Some("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 4c1a76fce9..51360357bc 100644 --- a/node/src/sub_lib/mod.rs +++ b/node/src/sub_lib/mod.rs @@ -21,7 +21,6 @@ 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 674f83191a..f26282aa60 100644 --- a/node/src/sub_lib/neighborhood.rs +++ b/node/src/sub_lib/neighborhood.rs @@ -8,7 +8,6 @@ use crate::sub_lib::cryptde::{CryptDE, PublicKey}; use crate::sub_lib::cryptde_real::CryptDEReal; use crate::sub_lib::dispatcher::{Component, StreamShutdownMsg}; use crate::sub_lib::hopper::ExpiredCoresPackage; -use crate::sub_lib::host::Host; use crate::sub_lib::node_addr::NodeAddr; use crate::sub_lib::peer_actors::{BindMessage, NewPublicIp, StartMessage}; use crate::sub_lib::route::Route; @@ -474,7 +473,7 @@ pub struct RouteQueryMessage { pub target_component: Component, pub return_component_opt: Option, pub payload_size: usize, - pub host: Host, + pub hostname_opt: Option, } impl Message for RouteQueryMessage { @@ -482,13 +481,16 @@ impl Message for RouteQueryMessage { } impl RouteQueryMessage { - pub fn data_indefinite_route_request(host: Host, payload_size: usize) -> RouteQueryMessage { + pub fn data_indefinite_route_request( + hostname_opt: Option, + payload_size: usize, + ) -> RouteQueryMessage { RouteQueryMessage { target_key_opt: None, target_component: Component::ProxyClient, return_component_opt: Some(Component::ProxyServer), payload_size, - host, + hostname_opt, } } } @@ -500,53 +502,16 @@ 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), - RoundTrip(Vec, Vec), + RoundTrip(Vec, Vec, u32), } #[derive(Clone, Debug, PartialEq, Eq)] pub struct RouteQueryResponse { pub route: Route, pub expected_services: ExpectedServices, - pub host: Host, } #[derive(Clone, Debug, Message, PartialEq, Eq)] @@ -1095,8 +1060,7 @@ mod tests { #[test] fn data_indefinite_route_request() { - let result = - RouteQueryMessage::data_indefinite_route_request(Host::new("booga.com", 1234), 7500); + let result = RouteQueryMessage::data_indefinite_route_request(None, 7500); assert_eq!( result, @@ -1105,7 +1069,7 @@ mod tests { target_component: Component::ProxyClient, return_component_opt: Some(Component::ProxyServer), payload_size: 7500, - host: Host::new("booga.com", 1234), + hostname_opt: None, } ); } diff --git a/node/src/sub_lib/proxy_server.rs b/node/src/sub_lib/proxy_server.rs index c7b0ab49ce..c3042859fb 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::{ExpectedService, 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; @@ -34,7 +34,7 @@ pub enum ProxyProtocol { pub struct ClientRequestPayload_0v1 { pub stream_key: StreamKey, pub sequenced_packet: SequencedPacket, - pub target_hostname: String, + pub target_hostname: Option, pub target_port: u16, pub protocol: ProxyProtocol, pub originator_public_key: PublicKey, @@ -55,6 +55,14 @@ impl ClientRequestPayload_0v1 { } } +#[derive(Message, Debug, PartialEq, Eq)] +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, @@ -73,6 +81,7 @@ 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, @@ -104,6 +113,7 @@ 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/sub_lib/route.rs b/node/src/sub_lib/route.rs index 05bcc15ad6..6d9b526040 100644 --- a/node/src/sub_lib/route.rs +++ b/node/src/sub_lib/route.rs @@ -1,4 +1,5 @@ // 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; @@ -32,6 +33,7 @@ impl Route { cryptde, None, None, + None, ) } @@ -46,6 +48,7 @@ impl Route { None, cryptde, consuming_wallet, + None, contract_address, ) } @@ -53,8 +56,9 @@ impl Route { pub fn round_trip( route_segment_over: RouteSegment, route_segment_back: RouteSegment, - cryptde: &dyn CryptDE, // Doesn't matter which CryptDE: only used for encoding. + 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( @@ -62,10 +66,22 @@ impl Route { Some(route_segment_back), cryptde, consuming_wallet, + Some(return_route_id), contract_address, ) } + pub fn 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()) + } + } + // 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() { @@ -116,7 +132,15 @@ impl Route { last_cryptde.public_key(), live_hop ), - Err(error) => format!("{}\nError: {:?}", most_strings, error), + 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), + }, } } @@ -125,6 +149,7 @@ 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) { @@ -149,7 +174,12 @@ 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], + return_route_id_opt, + cryptde, + ) } fn over_segment<'a>( @@ -266,6 +296,7 @@ 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(); @@ -277,8 +308,17 @@ 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 }) } + + 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") + } } pub struct RouteSegment { @@ -325,6 +365,66 @@ mod tests { static ref CRYPTDE_PAIR: CryptDEPair = CryptDEPair::null(); } + #[test] + fn id_decodes_return_route_id() { + let cryptde = CRYPTDE_PAIR.main.as_ref(); + + let subject = Route { + hops: vec![Route::encrypt_return_route_id(42, cryptde)], + }; + + assert_eq!(subject.id(cryptde), Ok(42)); + } + + #[test] + fn id_returns_empty_route_error_when_the_route_is_empty() { + let cryptde = CRYPTDE_PAIR.main.as_ref(); + + let subject = Route { hops: vec![] }; + + assert_eq!( + subject.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() { + 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); + } + + #[test] + fn route_segments_are_represented_in_base64_by_debug() { + let public_key_data_1: Vec = vec![12, 34, 56, 78, 90]; + let public_key_data_2: Vec = vec![34, 56, 78, 90, 12]; + let public_key_data_3: Vec = vec![56, 78, 90, 12, 34]; + let subject = RouteSegment::new( + vec![ + &PublicKey::new(public_key_data_1.as_slice()), + &PublicKey::new(public_key_data_2.as_slice()), + &PublicKey::new(public_key_data_3.as_slice()), + ], + Component::ProxyClient, + ); + + let result = format!("{:?}", subject); + + let base64_1 = base64::encode_config(&public_key_data_1, base64::STANDARD_NO_PAD); + let base64_2 = base64::encode_config(&public_key_data_2, base64::STANDARD_NO_PAD); + let base64_3 = base64::encode_config(&public_key_data_3, base64::STANDARD_NO_PAD); + assert_eq!( + result, + format!("{} -> {} -> {} : ProxyClient", base64_1, base64_2, base64_3) + ); + } + #[test] fn construct_does_not_like_route_segments_with_too_few_keys() { let cryptde = CRYPTDE_PAIR.main.as_ref(); @@ -358,6 +458,7 @@ mod tests { RouteSegment::new(vec![&c_key, &d_key], Component::ProxyServer), cryptde, Some(paying_wallet.clone()), + 0, Some(TEST_DEFAULT_CHAIN.rec().contract), ) .err() @@ -401,6 +502,7 @@ mod tests { let f_key = PublicKey::new(&[70, 70, 70]); let cryptde = CRYPTDE_PAIR.main.as_ref(); 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( @@ -408,6 +510,7 @@ 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(); @@ -496,6 +599,12 @@ mod tests { .unwrap(), "seventh hop" ); + + assert_eq!( + subject.hops[7], + Route::encrypt_return_route_id(return_route_id, cryptde), + "eighth hop" + ); } #[test] @@ -674,6 +783,7 @@ mod tests { RouteSegment::new(vec![&key2, &key1], Component::ProxyServer), cryptde, Some(paying_wallet), + 1234, Some(TEST_DEFAULT_CHAIN.rec().contract), ) .unwrap(); @@ -722,13 +832,13 @@ 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), - &cryptde, + &CryptDENull::from(&key1, TEST_DEFAULT_CHAIN), Some(paying_wallet), + 1234, Some(TEST_DEFAULT_CHAIN.rec().contract), ) .unwrap(); @@ -751,6 +861,7 @@ 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/sub_lib/sequence_buffer.rs b/node/src/sub_lib/sequence_buffer.rs index 2cb101c411..c73dbc021c 100644 --- a/node/src/sub_lib/sequence_buffer.rs +++ b/node/src/sub_lib/sequence_buffer.rs @@ -38,7 +38,7 @@ impl<'a> From<&'a TransmitDataMsg> for SequencedPacket { fn from(tdm: &'a TransmitDataMsg) -> Self { SequencedPacket::new( tdm.data.clone(), - tdm.sequence_number_opt.unwrap_or(0), + tdm.sequence_number.unwrap_or(0), tdm.last_data, ) } @@ -253,7 +253,7 @@ mod tests { endpoint: Endpoint::Socket(SocketAddr::from_str("1.2.3.4:80").unwrap()), last_data: true, data: vec![1, 4, 5, 9], - sequence_number_opt: None, + sequence_number: None, }; let result = SequencedPacket::from(&tdm); @@ -267,7 +267,7 @@ mod tests { endpoint: Endpoint::Socket(SocketAddr::from_str("1.2.3.4:80").unwrap()), last_data: true, data: vec![1, 4, 5, 9], - sequence_number_opt: Some(1), + sequence_number: Some(1), }; let result = SequencedPacket::from(&tdm); @@ -280,7 +280,7 @@ mod tests { endpoint: Endpoint::Socket(SocketAddr::from_str("1.2.3.4:80").unwrap()), last_data: false, data: vec![4, 2, 5, 67], - sequence_number_opt: Some(4), + sequence_number: Some(4), }; let result = SequencedPacket::from(&tdm); diff --git a/node/src/sub_lib/stream_handler_pool.rs b/node/src/sub_lib/stream_handler_pool.rs index 92ade9931a..fcb0f2e645 100644 --- a/node/src/sub_lib/stream_handler_pool.rs +++ b/node/src/sub_lib/stream_handler_pool.rs @@ -8,7 +8,7 @@ use actix::Message; pub struct TransmitDataMsg { pub endpoint: Endpoint, pub last_data: bool, - pub sequence_number_opt: Option, // Some implies clear data; None implies clandestine. + pub sequence_number: Option, // Some implies clear data; None implies clandestine. pub data: Vec, } diff --git a/node/src/sub_lib/stream_key.rs b/node/src/sub_lib/stream_key.rs index 8e6629ab59..bca70efe43 100644 --- a/node/src/sub_lib/stream_key.rs +++ b/node/src/sub_lib/stream_key.rs @@ -93,22 +93,13 @@ impl StreamKey { hash: hash.digest().bytes(), } } - - #[cfg(test)] - pub fn from_bytes(bytes: &[u8]) -> StreamKey { - let mut hash = [0xA; sha1::DIGEST_LENGTH]; - for i in 0..std::cmp::min(sha1::DIGEST_LENGTH, bytes.len()) { - hash[i] = bytes[i]; - } - StreamKey { hash } - } } 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: [0; sha1::DIGEST_LENGTH], + } } pub fn make_meaningful_stream_key(phrase: &str) -> StreamKey { diff --git a/node/src/sub_lib/ttl_hashmap.rs b/node/src/sub_lib/ttl_hashmap.rs index 4782e78a31..faa79b68a6 100644 --- a/node/src/sub_lib/ttl_hashmap.rs +++ b/node/src/sub_lib/ttl_hashmap.rs @@ -8,7 +8,6 @@ use std::rc::Rc; use std::time::Duration; use std::time::Instant; -#[allow(clippy::type_complexity)] pub struct TtlHashMap where K: Hash + Clone, @@ -16,7 +15,6 @@ where last_check: RefCell, data: RefCell, Instant)>>, ttl: Duration, - retire_closure: Box bool>, } impl TtlHashMap @@ -29,19 +27,6 @@ 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), } } @@ -69,12 +54,6 @@ where } } - pub fn remove(&self, key: &K) -> Option> { - self.remove_expired_entries(); - - self.data.borrow_mut().remove(key).map(|(result, _)| result) - } - fn remove_expired_entries(&self) { let now = Instant::now(); @@ -94,16 +73,8 @@ where .collect() }; - let mut data = self.data.borrow_mut(); expired.iter().for_each(|key| { - match data.remove(key) { - Some((value, _)) => { - if !(self.retire_closure)(key, value.as_ref()) { - data.insert(key.clone(), (value, now)); - } - } - None => (), // already removed - } + self.data.borrow_mut().remove(key); }); } } @@ -111,70 +82,26 @@ where #[cfg(test)] mod tests { use super::*; - use std::sync::{Arc, Mutex}; use std::thread; #[test] fn new_sets_ttl() { let subject = TtlHashMap::::new(Duration::from_millis(1000)); - let result = subject.ttl; - - assert_eq!(result, Duration::from_millis(1000)); + assert_eq!(subject.ttl, Duration::from_millis(1000)); } #[test] - fn get_returns_none_for_entry_that_was_never_inserted() { + fn remove_returns_none_for_entry_that_was_never_inserted() { let subject = TtlHashMap::::new(Duration::from_millis(1000)); - let result = subject.get(&11u32); - - assert_eq!(result, None); + assert_eq!(subject.get(&11u32), 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 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(Duration::from_millis(10)); subject.insert(42u32, "Hello"); subject.insert(24u32, "World"); @@ -182,52 +109,25 @@ 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 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); - } + let mut subject = TtlHashMap::new(Duration::from_millis(10)); - #[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); + thread::sleep(Duration::from_millis(20)); - assert_eq!(result, Some(Rc::new("Hello"))); - assert_eq!(*retire_closure_has_run.lock().unwrap(), true); + assert_eq!(subject.get(&42u32), None); } #[test] 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(Duration::from_millis(10)); + subject.insert(42u32, "Hello"); + thread::sleep(Duration::from_millis(20)); subject.insert(24u32, "World"); @@ -237,7 +137,6 @@ mod tests { subject.data.borrow().get(&24u32).unwrap().0.as_ref(), &"World" ); - assert_eq!(*retire_closure_has_run.lock().unwrap(), true); } #[test] diff --git a/node/src/test_utils/mod.rs b/node/src/test_utils/mod.rs index 73c5e50444..351b27711c 100644 --- a/node/src/test_utils/mod.rs +++ b/node/src/test_utils/mod.rs @@ -21,6 +21,7 @@ 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::dispatcher::Component; @@ -51,10 +52,8 @@ use std::iter::repeat; use std::net::{Shutdown, TcpStream}; use crate::sub_lib::hopper::MessageType; -use crate::sub_lib::host::Host; use crate::sub_lib::proxy_client::DnsResolveFailure_0v1; use crate::sub_lib::stream_key::StreamKey; -use masq_lib::constants::{HTTP_PORT, TLS_PORT}; use std::str::FromStr; use std::sync::{Arc, Mutex}; use std::thread; @@ -196,26 +195,25 @@ 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, tls: bool) -> Route { +pub fn route_to_proxy_client(main_key: &PublicKey, main_cryptde: &dyn CryptDE) -> Route { shift_one_hop( - zero_hop_route_response(main_key, main_cryptde, tls).route, + zero_hop_route_response(main_key, main_cryptde).route, main_cryptde, ) } -pub fn route_from_proxy_client(key: &PublicKey, cryptde: &dyn CryptDE, tls: bool) -> Route { +pub fn route_from_proxy_client(key: &PublicKey, cryptde: &dyn CryptDE) -> Route { // Happens to be the same - route_to_proxy_client(key, cryptde, tls) + route_to_proxy_client(key, 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 route_to_proxy_server(key: &PublicKey, cryptde: &dyn CryptDE) -> Route { + shift_one_hop(route_from_proxy_client(key, cryptde), cryptde) } pub fn zero_hop_route_response( public_key: &PublicKey, cryptde: &dyn CryptDE, - tls: bool, ) -> RouteQueryResponse { RouteQueryResponse { route: Route::round_trip( @@ -223,14 +221,15 @@ pub fn zero_hop_route_response( RouteSegment::new(vec![public_key, public_key], Component::ProxyServer), cryptde, None, + 0, None, ) .unwrap(), expected_services: ExpectedServices::RoundTrip( vec![ExpectedService::Nothing, ExpectedService::Nothing], vec![ExpectedService::Nothing, ExpectedService::Nothing], + 0, ), - host: Host::new("booga.com", if tls { TLS_PORT } else { HTTP_PORT }), } } @@ -239,6 +238,13 @@ 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); @@ -423,8 +429,8 @@ pub fn read_until_timeout(stream: &mut dyn Read) -> Vec { response } -pub fn make_meaningless_message_type(stream_key: StreamKey) -> MessageType { - DnsResolveFailure_0v1::new(stream_key).into() +pub fn make_meaningless_message_type() -> MessageType { + DnsResolveFailure_0v1::new(StreamKey::make_meaningless_stream_key()).into() } pub fn handle_connection_error(stream: TcpStream) { @@ -688,7 +694,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: "www.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(), @@ -1225,7 +1231,7 @@ mod tests { let cryptde = CRYPTDE_PAIR.main.as_ref(); let key = cryptde.public_key(); - let subject = zero_hop_route_response(&key, cryptde, false); + let subject = zero_hop_route_response(&key, cryptde); assert_eq!( subject.route.hops, @@ -1239,6 +1245,7 @@ mod tests { LiveHop::new(&PublicKey::new(b""), None, Component::ProxyServer) .encode(&key, cryptde) .unwrap(), + encrypt_return_route_id(0, cryptde), ) ); assert_eq!( @@ -1246,6 +1253,7 @@ mod tests { ExpectedServices::RoundTrip( vec![ExpectedService::Nothing, ExpectedService::Nothing,], vec![ExpectedService::Nothing, ExpectedService::Nothing,], + 0 ) ); } @@ -1255,7 +1263,7 @@ mod tests { let cryptde = CRYPTDE_PAIR.main.as_ref(); let key = cryptde.public_key(); - let subject = route_to_proxy_client(&key, cryptde, false); + let subject = route_to_proxy_client(&key, cryptde); let mut garbage_can: Vec = iter::repeat(0u8).take(96).collect(); cryptde.random(&mut garbage_can[..]); @@ -1268,6 +1276,7 @@ mod tests { LiveHop::new(&PublicKey::new(b""), None, Component::ProxyServer) .encode(&key, cryptde) .unwrap(), + encrypt_return_route_id(0, cryptde), CryptData::new(&garbage_can[..]) ) ); @@ -1278,7 +1287,7 @@ mod tests { let cryptde = CRYPTDE_PAIR.main.as_ref(); let key = cryptde.public_key(); - let subject = route_from_proxy_client(&key, cryptde, false); + let subject = route_from_proxy_client(&key, cryptde); let mut garbage_can: Vec = iter::repeat(0u8).take(96).collect(); cryptde.random(&mut garbage_can[..]); @@ -1291,6 +1300,7 @@ mod tests { LiveHop::new(&PublicKey::new(b""), None, Component::ProxyServer) .encode(&key, cryptde) .unwrap(), + encrypt_return_route_id(0, cryptde), CryptData::new(&garbage_can[..]) ) ); @@ -1301,7 +1311,7 @@ mod tests { let cryptde = CRYPTDE_PAIR.main.as_ref(); let key = cryptde.public_key(); - let subject = route_to_proxy_server(&key, cryptde, false); + let subject = route_to_proxy_server(&key, cryptde); let mut first_garbage_can: Vec = iter::repeat(0u8).take(96).collect(); let mut second_garbage_can: Vec = iter::repeat(0u8).take(96).collect(); @@ -1313,6 +1323,7 @@ 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[..]), ) diff --git a/node/src/test_utils/recorder.rs b/node/src/test_utils/recorder.rs index 20daaec868..f66125182c 100644 --- a/node/src/test_utils/recorder.rs +++ b/node/src/test_utils/recorder.rs @@ -39,8 +39,10 @@ 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::{ + AddReturnRouteMessage, 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; @@ -121,6 +123,7 @@ 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); @@ -395,6 +398,7 @@ 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 1991c391d530113a8d1bf02978217db4a8a89454 Mon Sep 17 00:00:00 2001 From: czarte Date: Thu, 20 Nov 2025 11:14:59 +0100 Subject: [PATCH 2/2] zero-hop as defailt neighborhood-mode --- masq/tests/startup_shutdown_tests_integration.rs | 2 +- node/src/daemon/setup_reporter.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/masq/tests/startup_shutdown_tests_integration.rs b/masq/tests/startup_shutdown_tests_integration.rs index c66589130f..a41e564a45 100644 --- a/masq/tests/startup_shutdown_tests_integration.rs +++ b/masq/tests/startup_shutdown_tests_integration.rs @@ -85,7 +85,7 @@ fn masq_terminates_based_on_loss_of_connection_to_the_daemon_integration() { assert_eq!(exit_code, None); #[cfg(target_os = "windows")] assert_eq!(exit_code.unwrap(), 1); - assert!(stdout.contains("neighborhood-mode standard Default")); + assert!(stdout.contains("neighborhood-mode zero-hop Default")); assert_eq!( stderr, "\nThe Daemon is no longer running; masq is terminating.\n\n" diff --git a/node/src/daemon/setup_reporter.rs b/node/src/daemon/setup_reporter.rs index a7448eba44..8fb684a824 100644 --- a/node/src/daemon/setup_reporter.rs +++ b/node/src/daemon/setup_reporter.rs @@ -986,7 +986,7 @@ impl ValueRetriever for NeighborhoodMode { _persistent_config: &dyn PersistentConfiguration, _db_password_opt: &Option, ) -> Option<(String, UiSetupResponseValueStatus)> { - Some(("standard".to_string(), Default)) + Some(("zero-hop".to_string(), Default)) } fn is_required(&self, _params: &SetupCluster) -> bool { @@ -1448,7 +1448,7 @@ mod tests { ("log-level", "warn", Default), ("mapping-protocol", "", Blank), ("min-hops", &DEFAULT_MIN_HOPS.to_string(), Default), - ("neighborhood-mode", "standard", Default), + ("neighborhood-mode", "zero-hop", Default), ( "neighbors", "masq://eth-mainnet:QUJDRDU2Nzg5MDEyMzQ1Njc4OTIxMjM0NTY3ODkzMTI@1.2.3.4:1234,masq://eth-mainnet:RUZHSDU2Nzg5MDEyMzQ1Njc4OTIxMjM0NTY3ODkzMTI@5.6.7.8:5678", @@ -3287,7 +3287,7 @@ mod tests { &None, ); - assert_eq!(result, Some(("standard".to_string(), Default))) + assert_eq!(result, Some(("zero-hop".to_string(), Default))) } #[test]