diff --git a/.gitignore b/.gitignore index 88a2ab5f9..666a5a098 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ **/*.rs.bk .idea/azure/ .idea/inspectionProfiles/Project_Default.xml +.idea/copilot.data.migration.* ### Node node_modules diff --git a/multinode_integration_tests/tests/connection_termination_test.rs b/multinode_integration_tests/tests/connection_termination_test.rs index 2657661b8..287f2f120 100644 --- a/multinode_integration_tests/tests/connection_termination_test.rs +++ b/multinode_integration_tests/tests/connection_termination_test.rs @@ -1,6 +1,7 @@ // 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; @@ -86,13 +87,12 @@ fn reported_server_drop() { let (_, _, lcp) = mock_node .wait_for_package(&masquerader, Duration::from_secs(2)) .unwrap(); - let (stream_key, return_route_id) = - context_from_request_lcp(lcp, real_node.main_cryptde_null().unwrap(), &exit_cryptde); + let stream_key = stream_key_from_request_lcp(lcp, &exit_cryptde); mock_node .transmit_package( mock_node.port_list()[0], - create_server_drop_report(&mock_node, &real_node, stream_key, return_route_id), + create_server_drop_report(&mock_node, &real_node, stream_key), &masquerader, real_node.main_public_key(), real_node.socket_addr(PortSelector::First), @@ -115,7 +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, return_route_id) = arbitrary_context(); + let stream_key = arbitrary_stream_key(); let index: u64 = 0; request_server_payload( index, @@ -125,7 +125,6 @@ fn actual_server_drop() { &mut server, &masquerader, stream_key, - return_route_id, ); let index: u64 = 1; request_server_payload( @@ -136,7 +135,6 @@ fn actual_server_drop() { &mut server, &masquerader, stream_key, - return_route_id, ); server.shutdown(); @@ -174,7 +172,6 @@ fn request_server_payload( server: &mut MASQNodeServer, masquerader: &JsonMasquerader, stream_key: StreamKey, - return_route_id: u32, ) { mock_node .transmit_package( @@ -184,7 +181,6 @@ fn request_server_payload( &mock_node, &real_node, stream_key, - return_route_id, &server, cluster.chain, ), @@ -212,7 +208,7 @@ fn reported_client_drop() { let server_port = find_free_port(); let mut server = real_node.make_server(server_port); let masquerader = JsonMasquerader::new(); - let (stream_key, return_route_id) = arbitrary_context(); + let stream_key = arbitrary_stream_key(); let index: u64 = 0; mock_node .transmit_package( @@ -222,7 +218,6 @@ fn reported_client_drop() { &mock_node, &real_node, stream_key, - return_route_id, &server, cluster.chain, ), @@ -240,7 +235,7 @@ fn reported_client_drop() { mock_node .transmit_package( mock_node.port_list()[0], - create_client_drop_report(&mock_node, &real_node, stream_key, return_route_id), + create_client_drop_report(&mock_node, &real_node, stream_key), &masquerader, real_node.main_public_key(), real_node.socket_addr(PortSelector::First), @@ -322,11 +317,7 @@ fn full_neighbor(one: &mut NodeRecord, another: &mut NodeRecord) { .unwrap(); } -fn context_from_request_lcp( - lcp: LiveCoresPackage, - originating_cryptde: &dyn CryptDE, - exit_cryptde: &dyn CryptDE, -) -> (StreamKey, u32) { +fn stream_key_from_request_lcp(lcp: LiveCoresPackage, exit_cryptde: &dyn CryptDE) -> StreamKey { let payload = match decodex::(exit_cryptde, &lcp.payload).unwrap() { MessageType::ClientRequest(vd) => vd .extract(&node_lib::sub_lib::migrations::client_request_payload::MIGRATIONS) @@ -334,15 +325,11 @@ fn context_from_request_lcp( mt => panic!("Unexpected: {:?}", mt), }; let stream_key = payload.stream_key; - let return_route_id = decodex::(originating_cryptde, &lcp.route.hops[6]).unwrap(); - (stream_key, return_route_id) + stream_key } -fn arbitrary_context() -> (StreamKey, u32) { - ( - StreamKey::make_meaningful_stream_key("arbitrary_context"), - 12345678, - ) +fn arbitrary_stream_key() -> StreamKey { + StreamKey::make_meaningful_stream_key("arbitrary_context") } fn create_request_icp( @@ -350,12 +337,12 @@ fn create_request_icp( originating_node: &MASQMockNode, exit_node: &MASQRealNode, stream_key: StreamKey, - return_route_id: u32, server: &MASQNodeServer, chain: Chain, ) -> IncipientCoresPackage { + let originating_main_cryptde = originating_node.main_cryptde_null().unwrap(); IncipientCoresPackage::new( - originating_node.main_cryptde_null().unwrap(), + originating_main_cryptde, Route::round_trip( RouteSegment::new( vec![ @@ -371,9 +358,8 @@ fn create_request_icp( ], Component::ProxyServer, ), - originating_node.main_cryptde_null().unwrap(), + originating_main_cryptde, originating_node.consuming_wallet(), - return_route_id, Some(chain.rec().contract), ) .unwrap(), @@ -382,7 +368,7 @@ fn create_request_icp( &ClientRequestPayload_0v1 { stream_key, sequenced_packet: SequencedPacket::new(Vec::from(HTTP_REQUEST), index, false), - target_hostname: Some(format!("{}", server.local_addr().ip())), + target_hostname: format!("{}", server.local_addr().ip()), target_port: server.local_addr().port(), protocol: ProxyProtocol::HTTP, originator_public_key: originating_node.main_public_key().clone(), @@ -400,8 +386,9 @@ fn create_meaningless_icp( let socket_addr = SocketAddr::from_str("3.2.1.0:7654").unwrap(); let stream_key = StreamKey::make_meaningful_stream_key("Chancellor on brink of second bailout for banks"); + let main_cryptde = originating_node.main_cryptde_null().unwrap(); IncipientCoresPackage::new( - originating_node.main_cryptde_null().unwrap(), + main_cryptde, Route::round_trip( RouteSegment::new( vec![ @@ -417,9 +404,8 @@ fn create_meaningless_icp( ], Component::ProxyServer, ), - originating_node.main_cryptde_null().unwrap(), + main_cryptde, originating_node.consuming_wallet(), - 1357, Some(TEST_DEFAULT_MULTINODE_CHAIN.rec().contract), ) .unwrap(), @@ -428,7 +414,7 @@ fn create_meaningless_icp( &ClientRequestPayload_0v1 { stream_key, sequenced_packet: SequencedPacket::new(Vec::from(HTTP_REQUEST), 0, false), - target_hostname: Some(format!("nowhere.com")), + target_hostname: "nowhere.com".to_string(), target_port: socket_addr.port(), protocol: ProxyProtocol::HTTP, originator_public_key: originating_node.main_public_key().clone(), @@ -443,8 +429,9 @@ fn create_server_drop_report( exit_node: &MASQMockNode, originating_node: &MASQRealNode, stream_key: StreamKey, - return_route_id: u32, ) -> IncipientCoresPackage { + let exit_main_cryptde = exit_node.main_cryptde_null().unwrap(); + let originating_main_cryptde = originating_node.main_cryptde_null().unwrap(); let mut route = Route::round_trip( RouteSegment::new( vec![ @@ -460,15 +447,12 @@ fn create_server_drop_report( ], Component::ProxyServer, ), - originating_node.main_cryptde_null().unwrap(), + originating_main_cryptde, originating_node.consuming_wallet(), - return_route_id, Some(TEST_DEFAULT_MULTINODE_CHAIN.rec().contract), ) .unwrap(); - route - .shift(originating_node.main_cryptde_null().unwrap()) - .unwrap(); + route.shift(originating_main_cryptde).unwrap(); let payload = MessageType::ClientResponse(VersionedData::new( &node_lib::sub_lib::migrations::client_response_payload::MIGRATIONS, &ClientResponsePayload_0v1 { @@ -478,7 +462,7 @@ fn create_server_drop_report( )); IncipientCoresPackage::new( - exit_node.main_cryptde_null().unwrap(), + exit_main_cryptde, route, payload, originating_node.alias_public_key(), @@ -490,8 +474,8 @@ fn create_client_drop_report( originating_node: &MASQMockNode, exit_node: &MASQRealNode, stream_key: StreamKey, - return_route_id: u32, ) -> IncipientCoresPackage { + let originating_main_cryptde = originating_node.main_cryptde_null().unwrap(); let route = Route::round_trip( RouteSegment::new( vec![ @@ -507,9 +491,8 @@ fn create_client_drop_report( ], Component::ProxyServer, ), - originating_node.main_cryptde_null().unwrap(), + originating_main_cryptde, originating_node.consuming_wallet(), - return_route_id, Some(TEST_DEFAULT_MULTINODE_CHAIN.rec().contract), ) .unwrap(); @@ -518,15 +501,15 @@ fn create_client_drop_report( &ClientRequestPayload_0v1 { stream_key, sequenced_packet: SequencedPacket::new(vec![], 1, true), - target_hostname: Some(String::from("doesnt.matter.com")), - target_port: 80, + target_hostname: String::from("doesnt.matter.com"), + target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: originating_node.main_public_key().clone(), }, )); IncipientCoresPackage::new( - originating_node.main_cryptde_null().unwrap(), + originating_main_cryptde, route, payload, exit_node.main_public_key(), diff --git a/multinode_integration_tests/tests/self_test.rs b/multinode_integration_tests/tests/self_test.rs index 973affaf0..c19db4c33 100644 --- a/multinode_integration_tests/tests/self_test.rs +++ b/multinode_integration_tests/tests/self_test.rs @@ -16,6 +16,7 @@ use node_lib::sub_lib::dispatcher::Component; use node_lib::sub_lib::hopper::IncipientCoresPackage; use node_lib::sub_lib::route::Route; use node_lib::sub_lib::route::RouteSegment; +use node_lib::sub_lib::stream_key::StreamKey; use node_lib::test_utils::{make_meaningless_message_type, make_paying_wallet}; use std::collections::HashSet; use std::io::ErrorKind; @@ -68,6 +69,7 @@ fn server_relays_cores_package() { let masquerader = JsonMasquerader::new(); let server = MASQCoresServer::new(cluster.chain); let cryptde = server.main_cryptde(); + let stream_key = StreamKey::make_meaningless_stream_key(); let mut client = MASQCoresClient::new(server.local_addr(), cryptde); let mut route = Route::one_way( RouteSegment::new( @@ -82,7 +84,7 @@ fn server_relays_cores_package() { let incipient = IncipientCoresPackage::new( cryptde, route.clone(), - make_meaningless_message_type(), + make_meaningless_message_type(stream_key), &cryptde.public_key(), ) .unwrap(); @@ -99,7 +101,7 @@ fn server_relays_cores_package() { route.shift(cryptde).unwrap(); assert_eq!(expired.remaining_route, route); - assert_eq!(expired.payload, make_meaningless_message_type()); + assert_eq!(expired.payload, make_meaningless_message_type(stream_key)); } #[test] @@ -111,6 +113,7 @@ fn one_mock_node_talks_to_another() { let mock_node_1 = cluster.get_mock_node_by_name("mock_node_1").unwrap(); let mock_node_2 = cluster.get_mock_node_by_name("mock_node_2").unwrap(); let cryptde = CryptDENull::new(TEST_DEFAULT_CHAIN); + let stream_key = StreamKey::make_meaningless_stream_key(); let route = Route::one_way( RouteSegment::new( vec![ @@ -127,7 +130,7 @@ fn one_mock_node_talks_to_another() { let incipient_cores_package = IncipientCoresPackage::new( &cryptde, route, - make_meaningless_message_type(), + make_meaningless_message_type(stream_key), &mock_node_2.main_public_key(), ) .unwrap(); @@ -156,7 +159,7 @@ fn one_mock_node_talks_to_another() { assert_eq!(package_to, mock_node_2.socket_addr(PortSelector::First)); assert_eq!( expired_cores_package.payload, - make_meaningless_message_type() + make_meaningless_message_type(stream_key) ); } diff --git a/node/src/dispatcher.rs b/node/src/dispatcher.rs index ac698e043..e74d97e9d 100644 --- a/node/src/dispatcher.rs +++ b/node/src/dispatcher.rs @@ -271,12 +271,12 @@ mod tests { let recording_arc = proxy_server.get_recording(); let awaiter = proxy_server.get_awaiter(); let client_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); - let reception_port = Some(8080); + let reception_port_opt = Some(8080); let data: Vec = vec![9, 10, 11]; let ibcd_in = InboundClientData { timestamp: SystemTime::now(), client_addr, - reception_port, + reception_port_opt, sequence_number: Some(0), last_data: false, is_clandestine: false, @@ -310,12 +310,12 @@ mod tests { let subject_addr = subject.start(); let (hopper, hopper_awaiter, hopper_recording_arc) = make_recorder(); let client_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); - let reception_port = Some(8080); + let reception_port_opt = Some(8080); let data: Vec = vec![9, 10, 11]; let ibcd_in = InboundClientData { timestamp: SystemTime::now(), client_addr, - reception_port, + reception_port_opt, last_data: false, is_clandestine: true, sequence_number: None, @@ -350,12 +350,12 @@ mod tests { let subject_addr = subject.start(); let subject_ibcd = subject_addr.recipient::(); let client_addr = SocketAddr::from_str("1.2.3.4:8765").unwrap(); - let reception_port = Some(1234); + let reception_port_opt = Some(1234); let data: Vec = vec![9, 10, 11]; let ibcd_in = InboundClientData { timestamp: SystemTime::now(), client_addr, - reception_port, + reception_port_opt, last_data: false, is_clandestine: false, sequence_number: Some(0), @@ -376,12 +376,12 @@ mod tests { let subject_addr = subject.start(); let subject_ibcd = subject_addr.recipient::(); let client_addr = SocketAddr::from_str("1.2.3.4:8765").unwrap(); - let reception_port = Some(1234); + let reception_port_opt = Some(1234); let data: Vec = vec![9, 10, 11]; let ibcd_in = InboundClientData { timestamp: SystemTime::now(), client_addr, - reception_port, + reception_port_opt, last_data: false, is_clandestine: true, sequence_number: None, diff --git a/node/src/hopper/consuming_service.rs b/node/src/hopper/consuming_service.rs index 7d5660a8b..dc9d2e6f1 100644 --- a/node/src/hopper/consuming_service.rs +++ b/node/src/hopper/consuming_service.rs @@ -100,7 +100,7 @@ impl ConsumingService { let ibcd = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 0), - reception_port: None, + reception_port_opt: None, last_data: false, is_clandestine: true, sequence_number: None, @@ -143,6 +143,7 @@ mod tests { use crate::sub_lib::node_addr::NodeAddr; use crate::sub_lib::route::Route; use crate::sub_lib::route::RouteSegment; + use crate::sub_lib::stream_key::StreamKey; use crate::test_utils::recorder::make_recorder; use crate::test_utils::recorder::peer_actors_builder; use crate::test_utils::{make_meaningless_message_type, make_paying_wallet}; @@ -168,7 +169,7 @@ mod tests { CRYPTDE_PAIR.main.as_ref(), &target_key, &target_node_addr, - make_meaningless_message_type(), + make_meaningless_message_type(StreamKey::make_meaningless_stream_key()), ) .unwrap(); let system = System::new(""); @@ -242,7 +243,7 @@ mod tests { Some(TEST_DEFAULT_CHAIN.rec().contract), ) .unwrap(); - let payload = make_meaningless_message_type(); + let payload = make_meaningless_message_type(StreamKey::make_meaningless_stream_key()); let incipient_cores_package = IncipientCoresPackage::new(cryptde, route.clone(), payload, &destination_key).unwrap(); let system = System::new("converts_incipient_message_to_live_and_sends_to_dispatcher"); @@ -289,7 +290,7 @@ mod tests { Some(TEST_DEFAULT_CHAIN.rec().contract), ) .unwrap(); - let payload = make_meaningless_message_type(); + let payload = make_meaningless_message_type(StreamKey::make_meaningless_stream_key()); let incipient_cores_package = IncipientCoresPackage::new(cryptde, route.clone(), payload, &destination_key).unwrap(); let system = System::new("consume_sends_zero_hop_incipient_directly_to_hopper"); @@ -317,7 +318,7 @@ mod tests { InboundClientData { timestamp: record.timestamp, client_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 0), - reception_port: None, + reception_port_opt: None, last_data: false, is_clandestine: true, sequence_number: None, @@ -340,7 +341,7 @@ mod tests { IncipientCoresPackage::new( CRYPTDE_PAIR.main.as_ref(), Route { hops: vec![] }, - make_meaningless_message_type(), + make_meaningless_message_type(StreamKey::make_meaningless_stream_key()), &PublicKey::new(&[1, 2]), ) .unwrap(), diff --git a/node/src/hopper/live_cores_package.rs b/node/src/hopper/live_cores_package.rs index 2b05b27e8..cac27bebc 100644 --- a/node/src/hopper/live_cores_package.rs +++ b/node/src/hopper/live_cores_package.rs @@ -100,6 +100,7 @@ mod tests { use crate::sub_lib::node_addr::NodeAddr; use crate::sub_lib::route::RouteSegment; use crate::sub_lib::route::{Route, RouteError}; + use crate::sub_lib::stream_key::StreamKey; use crate::test_utils::{ make_meaningless_message_type, make_meaningless_route, make_paying_wallet, }; @@ -141,7 +142,9 @@ 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 serialized_payload = serde_cbor::ser::to_vec(&make_meaningless_message_type()).unwrap(); + let stream_key = StreamKey::make_meaningless_stream_key(); + let serialized_payload = + serde_cbor::ser::to_vec(&make_meaningless_message_type(stream_key)).unwrap(); let encrypted_payload = cryptde .encode(&destination_key, &PlainData::new(&serialized_payload)) .unwrap(); @@ -204,7 +207,7 @@ mod tests { let key34 = PublicKey::new(&[3, 4]); let node_addr34 = NodeAddr::new(&IpAddr::from_str("3.4.3.4").unwrap(), &[1234]); let mut route = Route::single_hop(&key34, cryptde).unwrap(); - let payload = make_meaningless_message_type(); + let payload = make_meaningless_message_type(StreamKey::make_meaningless_stream_key()); let incipient = NoLookupIncipientCoresPackage::new(cryptde, &key34, &node_addr34, payload.clone()) @@ -228,7 +231,7 @@ mod tests { cryptde, &blank_key, &node_addr34, - make_meaningless_message_type(), + make_meaningless_message_type(StreamKey::make_meaningless_stream_key()), ); assert_eq!( @@ -254,7 +257,7 @@ mod tests { Some(contract_address), ) .unwrap(); - let payload = make_meaningless_message_type(); + let payload = make_meaningless_message_type(StreamKey::make_meaningless_stream_key()); let incipient = IncipientCoresPackage::new(cryptde, route.clone(), payload.clone(), &key56).unwrap(); @@ -280,7 +283,7 @@ mod tests { let incipient = IncipientCoresPackage::new( cryptde, Route { hops: vec![] }, - make_meaningless_message_type(), + make_meaningless_message_type(StreamKey::make_meaningless_stream_key()), &PublicKey::new(&[3, 4]), ) .unwrap(); @@ -297,7 +300,8 @@ mod tests { #[test] fn expired_cores_package_can_be_constructed_from_live_cores_package() { let immediate_neighbor_ip = SocketAddr::from_str("1.2.3.4:1234").unwrap(); - let payload = make_meaningless_message_type(); + let stream_key = StreamKey::make_meaningless_stream_key(); + let payload = make_meaningless_message_type(stream_key); let first_stop_key = PublicKey::new(&[3, 4]); let first_stop_cryptde = CryptDENull::from(&first_stop_key, TEST_DEFAULT_CHAIN); let relay_key = PublicKey::new(&[1, 2]); @@ -316,7 +320,6 @@ mod tests { ), cryptde, Some(paying_wallet.clone()), - 1234, Some(contract_address), ) .unwrap(); @@ -375,11 +378,6 @@ mod tests { Component::ProxyServer, ) ); - assert_eq!( - route.hops[0], - crate::test_utils::encrypt_return_route_id(1234, cryptde), - ); - route.hops.remove(0); assert_eq!( &route.hops[0].as_slice()[..8], &[52, 52, 52, 52, 52, 52, 52, 52] diff --git a/node/src/hopper/mod.rs b/node/src/hopper/mod.rs index 588016440..55b0c8e24 100644 --- a/node/src/hopper/mod.rs +++ b/node/src/hopper/mod.rs @@ -149,6 +149,7 @@ mod tests { use crate::sub_lib::hopper::IncipientCoresPackage; use crate::sub_lib::route::Route; use crate::sub_lib::route::RouteSegment; + use crate::sub_lib::stream_key::StreamKey; use crate::test_utils::unshared_test_utils::prove_that_crash_request_handler_is_hooked_up; use crate::test_utils::{ make_meaningless_message_type, make_paying_wallet, route_to_proxy_client, @@ -175,8 +176,10 @@ 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); - let serialized_payload = serde_cbor::ser::to_vec(&make_meaningless_message_type()).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 data = main_cryptde .encode( &main_cryptde.public_key(), @@ -193,7 +196,7 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr, - reception_port: None, + reception_port_opt: None, last_data: false, is_clandestine: false, sequence_number: None, @@ -234,7 +237,7 @@ mod tests { let incipient_package = IncipientCoresPackage::new( main_cryptde, route, - make_meaningless_message_type(), + make_meaningless_message_type(StreamKey::make_meaningless_stream_key()), &main_cryptde.public_key(), ) .unwrap(); diff --git a/node/src/hopper/routing_service.rs b/node/src/hopper/routing_service.rs index 7f7134d20..3e23b1bed 100644 --- a/node/src/hopper/routing_service.rs +++ b/node/src/hopper/routing_service.rs @@ -186,7 +186,7 @@ impl RoutingService { let inbound_client_data = InboundClientData { timestamp: ibcd_but_data.timestamp, client_addr: ibcd_but_data.client_addr, - reception_port: ibcd_but_data.reception_port, + reception_port_opt: ibcd_but_data.reception_port_opt, last_data: ibcd_but_data.last_data, is_clandestine: ibcd_but_data.is_clandestine, sequence_number: ibcd_but_data.sequence_number, @@ -542,16 +542,18 @@ mod tests { #[test] fn dns_resolution_failures_are_reported_to_the_proxy_server() { - let cryptde_pair = CRYPTDE_PAIR.clone(); - let route = - route_to_proxy_server(&cryptde_pair.main.public_key(), cryptde_pair.main.as_ref()); + let route = route_to_proxy_server( + &CRYPTDE_PAIR.main.public_key(), + CRYPTDE_PAIR.main.as_ref(), + false, + ); 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(), @@ -560,15 +562,15 @@ 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: None, + reception_port_opt: None, sequence_number: None, last_data: false, is_clandestine: false, @@ -579,7 +581,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, + CRYPTDE_PAIR.clone(), RoutingServiceSubs { proxy_client_subs_opt: peer_actors.proxy_client_opt, proxy_server_subs: peer_actors.proxy_server, @@ -606,28 +608,30 @@ mod tests { #[test] fn logs_and_ignores_message_that_cannot_be_deserialized() { init_test_logging(); - let cryptde_pair = CRYPTDE_PAIR.clone(); - let route = - route_from_proxy_client(&cryptde_pair.main.public_key(), cryptde_pair.main.as_ref()); + let route = route_from_proxy_client( + &CRYPTDE_PAIR.main.public_key(), + CRYPTDE_PAIR.main.as_ref(), + false, + ); 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: None, + reception_port_opt: None, sequence_number: None, last_data: false, is_clandestine: false, @@ -635,7 +639,7 @@ mod tests { }; let peer_actors = peer_actors_builder().build(); let subject = RoutingService::new( - cryptde_pair, + CRYPTDE_PAIR.clone(), RoutingServiceSubs { proxy_client_subs_opt: peer_actors.proxy_client_opt, proxy_server_subs: peer_actors.proxy_server, @@ -661,7 +665,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); + let route = route_from_proxy_client(main_cryptde.public_key(), &main_cryptde, false); let lcp = LiveCoresPackage::new( route, encodex(&rogue_cryptde, rogue_cryptde.public_key(), &[42u8]).unwrap(), @@ -670,7 +674,7 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port: None, + reception_port_opt: None, sequence_number: None, last_data: false, is_clandestine: false, @@ -707,7 +711,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); + let route = route_from_proxy_client(&main_cryptde.public_key(), main_cryptde, false); let payload = GossipBuilder::empty(); let lcp = LiveCoresPackage::new( route, @@ -722,7 +726,7 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port: None, + reception_port_opt: None, sequence_number: None, last_data: false, is_clandestine: false, @@ -753,7 +757,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); + let route = route_to_proxy_client(&main_cryptde.public_key(), main_cryptde, false); let payload = make_request_payload(0, main_cryptde); let lcp = LiveCoresPackage::new( route, @@ -772,7 +776,7 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port: None, + reception_port_opt: None, sequence_number: None, last_data: true, is_clandestine: false, @@ -823,7 +827,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); + let route = route_to_proxy_client(&main_cryptde.public_key(), main_cryptde, false); let payload = make_request_payload(0, main_cryptde); let lcp = LiveCoresPackage::new( route, @@ -841,7 +845,7 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port: None, + reception_port_opt: None, sequence_number: None, last_data: true, is_clandestine: false, @@ -881,7 +885,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); + let route = route_to_proxy_server(&main_cryptde.public_key(), main_cryptde, false); let payload = make_response_payload(0); let lcp = LiveCoresPackage::new( route, @@ -897,7 +901,7 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.3.2.4:5678").unwrap(), - reception_port: None, + reception_port_opt: None, last_data: false, is_clandestine: true, sequence_number: None, @@ -974,7 +978,7 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.3.2.4:5678").unwrap(), - reception_port: None, + reception_port_opt: None, last_data: false, is_clandestine: true, sequence_number: None, @@ -1047,7 +1051,7 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.3.2.4:5678").unwrap(), - reception_port: None, + reception_port_opt: None, last_data: false, is_clandestine: true, sequence_number: None, @@ -1123,7 +1127,7 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port: None, + reception_port_opt: None, last_data: true, is_clandestine: true, sequence_number: None, @@ -1215,7 +1219,7 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port: None, + reception_port_opt: None, last_data: true, is_clandestine: true, sequence_number: None, @@ -1258,7 +1262,7 @@ mod tests { InboundClientData { timestamp: record.timestamp, client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port: None, + reception_port_opt: None, last_data: true, is_clandestine: true, sequence_number: None, @@ -1276,7 +1280,7 @@ mod tests { let origin_key = PublicKey::new(&[1, 2]); let origin_cryptde = CryptDENull::from(&origin_key, TEST_DEFAULT_CHAIN); let destination_key = PublicKey::new(&[3, 4]); - let payload = make_meaningless_message_type(); + let payload = make_meaningless_message_type(StreamKey::make_meaningless_stream_key()); let route = Route::one_way( RouteSegment::new( vec![&origin_key, &main_cryptde.public_key(), &destination_key], @@ -1297,7 +1301,7 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port: None, + reception_port_opt: None, last_data: true, is_clandestine: true, sequence_number: None, @@ -1394,7 +1398,7 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port: None, + reception_port_opt: None, last_data: true, is_clandestine: true, sequence_number: None, @@ -1570,7 +1574,7 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port: None, + reception_port_opt: None, last_data: true, is_clandestine: true, sequence_number: None, @@ -1640,7 +1644,7 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port: None, + reception_port_opt: None, last_data: true, is_clandestine: true, sequence_number: None, @@ -1684,7 +1688,7 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port: None, + reception_port_opt: None, last_data: true, is_clandestine: true, sequence_number: None, @@ -1741,7 +1745,7 @@ mod tests { let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port: None, + reception_port_opt: None, last_data: true, is_clandestine: true, sequence_number: None, @@ -1808,7 +1812,7 @@ mod tests { let ibcd = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port: None, + reception_port_opt: None, last_data: true, is_clandestine: true, sequence_number: None, @@ -1873,7 +1877,7 @@ mod tests { &ClientRequestPayload_0v1 { stream_key: StreamKey::make_meaningless_stream_key(), sequenced_packet: SequencedPacket::new(vec![1, 2, 3, 4], 1234, false), - target_hostname: Some("hostname".to_string()), + target_hostname: "hostname".to_string(), target_port: 1234, protocol: ProxyProtocol::TLS, originator_public_key: PublicKey::new(b"1234"), diff --git a/node/src/neighborhood/mod.rs b/node/src/neighborhood/mod.rs index 9c685c0af..355029a2e 100644 --- a/node/src/neighborhood/mod.rs +++ b/node/src/neighborhood/mod.rs @@ -27,12 +27,15 @@ 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::{OneWay, RoundTrip}; use crate::sub_lib::neighborhood::RouteQueryResponse; use crate::sub_lib::neighborhood::UpdateNodeRecordMetadataMessage; use crate::sub_lib::neighborhood::{AskAboutDebutGossipMessage, NodeDescriptor}; use crate::sub_lib::neighborhood::{ConfigChange, RemoveNeighborMessage}; use crate::sub_lib::neighborhood::{ConfigChangeMsg, RouteQueryMessage}; -use crate::sub_lib::neighborhood::{ConnectionProgressEvent, ExpectedServices}; use crate::sub_lib::neighborhood::{ConnectionProgressMessage, ExpectedService}; use crate::sub_lib::neighborhood::{DispatcherNodeQueryMessage, GossipFailure_0v1}; use crate::sub_lib::neighborhood::{Hops, NeighborhoodMetadata, NodeQueryResponseMetadata}; @@ -105,7 +108,6 @@ pub struct Neighborhood { mode: NeighborhoodModeLight, min_hops: Hops, db_patch_size: u8, - next_return_route_id: u32, overall_connection_status: OverallConnectionStatus, chain: Chain, crashable: bool, @@ -430,7 +432,6 @@ impl Neighborhood { mode, min_hops, db_patch_size, - next_return_route_id: 0, overall_connection_status, chain: config.blockchain_bridge_config.chain, crashable: config.crash_point == CrashPoint::Message, @@ -496,9 +497,9 @@ impl Neighborhood { } fn handle_route_query_message(&mut self, msg: RouteQueryMessage) -> Option { - let debug_msg_opt = self.logger.debug_enabled().then(|| format!("{:?}", msg)); + let debug_msg_opt = self.logger.debug_enabled().then(|| format!("{}", msg.host)); let route_result = if self.mode == NeighborhoodModeLight::ZeroHop { - Ok(self.zero_hop_route_response()) + Ok(self.zero_hop_route_response(msg.host)) } else { self.make_round_trip_route(msg) }; @@ -882,7 +883,7 @@ impl Neighborhood { target_component: Component::ProxyClient, return_component_opt: Some(Component::ProxyServer), payload_size: 10000, - hostname_opt: None, + host: Host::new("booga.com", 1234), }; if self.handle_route_query_message(msg).is_some() { debug!( @@ -982,8 +983,7 @@ impl Neighborhood { .expect("route creation error") } - fn zero_hop_route_response(&mut self) -> RouteQueryResponse { - let return_route_id = self.advance_return_route_id(); + fn zero_hop_route_response(&mut self, host: Host) -> RouteQueryResponse { let route = Route::round_trip( RouteSegment::new( vec![self.cryptde.public_key(), self.cryptde.public_key()], @@ -995,17 +995,13 @@ impl Neighborhood { ), self.cryptde.as_ref(), None, - return_route_id, None, ) .expect("Couldn't create route"); RouteQueryResponse { route, - expected_services: ExpectedServices::RoundTrip( - vec![ExpectedService::Nothing, ExpectedService::Nothing], - vec![ExpectedService::Nothing, ExpectedService::Nothing], - return_route_id, - ), + expected_services: RoundTrip(vec![Nothing, Nothing], vec![Nothing, Nothing]), + host, } } @@ -1013,7 +1009,7 @@ impl Neighborhood { &mut self, request_msg: RouteQueryMessage, ) -> Result { - let hostname_opt = request_msg.hostname_opt.as_deref(); + let host = request_msg.host; let over = self.make_route_segment( self.cryptde.public_key(), request_msg.target_key_opt.as_ref(), @@ -1021,7 +1017,7 @@ impl Neighborhood { request_msg.target_component, request_msg.payload_size, RouteDirection::Over, - hostname_opt, + &host.name, )?; debug!(self.logger, "Route over: {:?}", over); // Estimate for routing-undesirability calculations. @@ -1038,16 +1034,17 @@ impl Neighborhood { .expect("No return component"), anticipated_response_payload_len, RouteDirection::Back, - hostname_opt, + &host.name, )?; debug!(self.logger, "Route back: {:?}", back); - self.compose_route_query_response(over, back) + self.compose_route_query_response(over, back, host) } fn compose_route_query_response( &mut self, over: RouteSegment, back: RouteSegment, + host: Host, ) -> Result { let segments = vec![&over, &back]; @@ -1070,22 +1067,17 @@ 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: ExpectedServices::RoundTrip( - expected_request_services, - expected_response_services, - return_route_id, - ), + expected_services: RoundTrip(expected_request_services, expected_response_services), + host, }) } @@ -1098,7 +1090,7 @@ impl Neighborhood { target_component: Component, payload_size: usize, direction: RouteDirection, - hostname_opt: Option<&str>, + hostname: &str, ) -> Result { let route_opt = self.find_best_route_segment( origin, @@ -1106,7 +1098,7 @@ impl Neighborhood { minimum_hop_count, payload_size, direction, - hostname_opt, + hostname, ); match route_opt { None => { @@ -1145,20 +1137,20 @@ impl Neighborhood { match self.neighborhood_database.node_by_key(route_segment_key) { Some(node) => { if route_segment_key == self.neighborhood_database.root().public_key() { - Ok(ExpectedService::Nothing) + Ok(Nothing) } else { match (originator_key, exit_key) { (Some(originator_key), Some(exit_key)) if route_segment_key == originator_key || route_segment_key == exit_key => { - Ok(ExpectedService::Exit( + Ok(Exit( route_segment_key.clone(), node.earning_wallet(), *node.rate_pack(), )) } - (Some(_), Some(_)) => Ok(ExpectedService::Routing( + (Some(_), Some(_)) => Ok(Routing( route_segment_key.clone(), node.earning_wallet(), *node.rate_pack(), @@ -1276,11 +1268,11 @@ impl Neighborhood { UndesirabilityType::Relay => { node_record.inner.rate_pack.routing_charge(payload_size) as i64 } - UndesirabilityType::ExitRequest(None) => { + UndesirabilityType::ExitRequest("booga.com") => { node_record.inner.rate_pack.exit_charge(payload_size) as i64 + node_record.metadata.country_undesirability as i64 } - UndesirabilityType::ExitRequest(Some(hostname)) => { + UndesirabilityType::ExitRequest(hostname) => { let exit_undesirability = node_record.inner.rate_pack.exit_charge(payload_size) as i64; let country_undesirability = node_record.metadata.country_undesirability as i64; @@ -1326,12 +1318,6 @@ 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, @@ -1350,7 +1336,7 @@ impl Neighborhood { PAYLOAD_ZERO_SIZE, RouteDirection::Over, &mut minimum_undesirability, - None, + "booga.com", true, research_exits, ); @@ -1372,7 +1358,7 @@ impl Neighborhood { minimum_hops: usize, payload_size: usize, direction: RouteDirection, - hostname_opt: Option<&str>, + hostname: &str, ) -> Option> { let mut minimum_undesirability = i64::MAX; let initial_undesirability = @@ -1389,7 +1375,7 @@ impl Neighborhood { payload_size, direction, &mut minimum_undesirability, - hostname_opt, + hostname, false, &mut vec![], ) @@ -1413,7 +1399,7 @@ impl Neighborhood { payload_size: usize, direction: RouteDirection, minimum_undesirability: &mut i64, - hostname_opt: Option<&str>, + hostname: &str, research_neighborhood: bool, research_exits: &mut Vec<&'a PublicKey>, ) -> Vec> { @@ -1459,7 +1445,7 @@ impl Neighborhood { payload_size, direction, minimum_undesirability, - hostname_opt, + hostname, research_neighborhood, research_exits, previous_node, @@ -1481,7 +1467,7 @@ impl Neighborhood { payload_size, direction, minimum_undesirability, - hostname_opt, + hostname, research_neighborhood, research_exits, previous_node, @@ -1499,7 +1485,7 @@ impl Neighborhood { payload_size: usize, direction: RouteDirection, minimum_undesirability: &mut i64, - hostname_opt: Option<&str>, + hostname: &str, research_neighborhood: bool, exits_research: &mut Vec<&'a PublicKey>, previous_node: &NodeRecord, @@ -1530,7 +1516,7 @@ impl Neighborhood { new_hops_remaining, payload_size as u64, direction, - hostname_opt, + hostname, ); self.routing_engine( @@ -1541,7 +1527,7 @@ impl Neighborhood { payload_size, direction, minimum_undesirability, - hostname_opt, + hostname, research_neighborhood, exits_research, ) @@ -1598,11 +1584,11 @@ impl Neighborhood { hops_remaining: usize, payload_size: u64, direction: RouteDirection, - hostname_opt: Option<&str>, + hostname: &str, ) -> i64 { let undesirability_type = match (direction, target_opt) { (RouteDirection::Over, None) if hops_remaining == 0 => { - UndesirabilityType::ExitRequest(hostname_opt) + UndesirabilityType::ExitRequest(hostname) } (RouteDirection::Over, _) => UndesirabilityType::Relay, // The exit-and-relay undesirability is initial_undesirability @@ -2164,7 +2150,7 @@ impl UserExitPreferences { #[derive(PartialEq, Eq, Debug)] enum UndesirabilityType<'hostname> { Relay, - ExitRequest(Option<&'hostname str>), + ExitRequest(&'hostname str), ExitAndRouteResponse, } @@ -2185,10 +2171,20 @@ 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; @@ -2203,16 +2199,6 @@ mod tests { use std::time::Instant; use tokio::prelude::Future; - use masq_lib::constants::{DEFAULT_CHAIN, TLS_PORT}; - use masq_lib::messages::{ - CountryGroups, ToMessageBody, UiConnectionChangeBroadcast, UiConnectionStage, - }; - use masq_lib::test_utils::utils::{ensure_node_home_directory_exists, TEST_DEFAULT_CHAIN}; - use masq_lib::ui_gateway::MessageBody; - use masq_lib::ui_gateway::MessagePath::Conversation; - use masq_lib::ui_gateway::MessageTarget; - use masq_lib::utils::running_test; - use crate::db_config::persistent_configuration::PersistentConfigError; use crate::neighborhood::gossip::Gossip_0v1; use crate::neighborhood::gossip::{GossipBuilder, GossipNodeRecord}; @@ -2264,6 +2250,7 @@ mod tests { use crate::neighborhood::overall_connection_status::{ ConnectionProgress, ConnectionStage, OverallConnectionStage, }; + use crate::sub_lib::host::Host; use crate::test_utils::unshared_test_utils::notify_handlers::NotifyLaterHandleMock; use masq_lib::test_utils::logging::{init_test_logging, TestLogHandler}; @@ -3176,7 +3163,7 @@ mod tests { } #[test] - pub fn progress_in_the_stage_of_overall_connection_status_made_by_one_cpm_is_not_overriden_by_the_other( + pub fn progress_in_the_stage_of_overall_connection_status_made_by_one_cpm_is_not_overridden_by_the_other( ) { let peer_1 = make_ip(1); let peer_2 = make_ip(2); @@ -3196,7 +3183,7 @@ mod tests { neighborhood_config, make_wallet("earning"), None, - "progress_in_the_stage_of_overall_connection_status_made_by_one_cpm_is_not_overriden_by_the_other"), + "progress_in_the_stage_of_overall_connection_status_made_by_one_cpm_is_not_overridden_by_the_other"), ); let (node_to_ui_recipient, _) = make_node_to_ui_recipient(); subject.node_to_ui_recipient_opt = Some(node_to_ui_recipient); @@ -3309,7 +3296,10 @@ mod tests { let addr: Addr = subject.start(); let sub: Recipient = addr.recipient::(); - let future = sub.send(RouteQueryMessage::data_indefinite_route_request(None, 400)); + let future = sub.send(RouteQueryMessage::data_indefinite_route_request( + Host::new("booga.com", 1234), + 400, + )); System::current().stop_with_code(0); system.run(); @@ -3325,7 +3315,10 @@ mod tests { let addr: Addr = subject.start(); let sub: Recipient = addr.recipient::(); - let future = sub.send(RouteQueryMessage::data_indefinite_route_request(None, 430)); + let future = sub.send(RouteQueryMessage::data_indefinite_route_request( + Host::new("booga.com", 1234), + 430, + )); System::current().stop_with_code(0); system.run(); @@ -3365,7 +3358,8 @@ mod tests { } let addr: Addr = subject.start(); let sub: Recipient = addr.recipient::(); - let msg = RouteQueryMessage::data_indefinite_route_request(None, 54000); + let msg = + RouteQueryMessage::data_indefinite_route_request(Host::new("booga.com", 1234), 54000); let future = sub.send(msg); @@ -3390,29 +3384,28 @@ mod tests { ), cryptde, None, - 0, None, ) .unwrap(), - expected_services: ExpectedServices::RoundTrip( + expected_services: RoundTrip( vec![ - ExpectedService::Nothing, - ExpectedService::Exit( + Nothing, + Exit( desirable_exit_node.public_key().clone(), desirable_exit_node.earning_wallet(), rate_pack(2345), ), ], vec![ - ExpectedService::Exit( + Exit( desirable_exit_node.public_key().clone(), desirable_exit_node.earning_wallet(), rate_pack(2345), ), - ExpectedService::Nothing, + Nothing, ], - 0, ), + host: Host::new("booga.com", 1234), }; assert_eq!(expected_response, result); } @@ -3425,7 +3418,8 @@ mod tests { subject.min_hops = Hops::TwoHops; let addr: Addr = subject.start(); let sub: Recipient = addr.recipient::(); - let msg = RouteQueryMessage::data_indefinite_route_request(None, 20000); + let msg = + RouteQueryMessage::data_indefinite_route_request(Host::new("booga.com", 1234), 20000); let future = sub.send(msg); @@ -3445,7 +3439,8 @@ mod tests { let sub: Recipient = addr.recipient::(); let future = sub.send(RouteQueryMessage::data_indefinite_route_request( - None, 12345, + Host::new("google.com", 1234), + 12345, )); System::current().stop_with_code(0); @@ -3463,39 +3458,15 @@ mod tests { ), cryptde, None, - 0, None, ) .unwrap(), - expected_services: ExpectedServices::RoundTrip( - vec![ExpectedService::Nothing, ExpectedService::Nothing], - vec![ExpectedService::Nothing, ExpectedService::Nothing], - 0, - ), + expected_services: RoundTrip(vec![Nothing, Nothing], vec![Nothing, Nothing]), + host: Host::new("google.com", 1234), }; 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: @@ -3541,7 +3512,10 @@ mod tests { let addr: Addr = subject.start(); let sub: Recipient = addr.recipient::(); - let data_route = sub.send(RouteQueryMessage::data_indefinite_route_request(None, 5000)); + let data_route = sub.send(RouteQueryMessage::data_indefinite_route_request( + Host::new("booga.com", 1234), + 5000, + )); System::current().stop_with_code(0); system.run(); @@ -3554,41 +3528,24 @@ mod tests { segment(&[r, q, p], &Component::ProxyServer), cryptde, consuming_wallet_opt, - 0, Some(contract_address), ) .unwrap(), - expected_services: ExpectedServices::RoundTrip( + expected_services: RoundTrip( vec![ - ExpectedService::Nothing, - ExpectedService::Routing( - q.public_key().clone(), - q.earning_wallet(), - rate_pack(3456), - ), - ExpectedService::Exit( - r.public_key().clone(), - r.earning_wallet(), - rate_pack(4567), - ), + Nothing, + Routing(q.public_key().clone(), q.earning_wallet(), rate_pack(3456)), + Exit(r.public_key().clone(), r.earning_wallet(), rate_pack(4567)), ], vec![ - 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, + Exit(r.public_key().clone(), r.earning_wallet(), rate_pack(4567)), + Routing(q.public_key().clone(), q.earning_wallet(), rate_pack(3456)), + Nothing, ], - 0, ), + host: Host::new("booga.com", 1234), }; - assert_eq!(expected_response, result); + assert_eq!(result, expected_response); } #[test] @@ -3598,6 +3555,7 @@ 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:"); @@ -3607,18 +3565,6 @@ mod tests { ); } - #[test] - fn next_return_route_id_wraps_around() { - let mut subject = make_standard_subject(); - subject.next_return_route_id = 0xFFFFFFFF; - - let end = subject.advance_return_route_id(); - let beginning = subject.advance_return_route_id(); - - assert_eq!(end, 0xFFFFFFFF); - assert_eq!(beginning, 0x00000000); - } - /* Database: @@ -3627,37 +3573,6 @@ 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"; @@ -4518,6 +4433,7 @@ 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:"); @@ -4534,6 +4450,7 @@ mod tests { let result: Result = subject.compose_route_query_response( RouteSegment::new(vec![&PublicKey::new(&[3, 3, 8])], Component::ProxyClient), RouteSegment::new(vec![&PublicKey::new(&[8, 3, 3])], Component::ProxyServer), + Host::new("booga.com", 1234), ); assert!(result.is_err()); let error_expectation: String = result.expect_err("Expected an Err but got:"); @@ -4541,7 +4458,6 @@ mod tests { error_expectation, "Cannot make multi_hop with unknown neighbor" ); - assert_eq!(subject.next_return_route_id, 0); } #[test] @@ -4663,34 +4579,58 @@ mod tests { // At least two hops from p to anywhere standard let route_opt = - subject.find_best_route_segment(p, None, 2, 10000, RouteDirection::Over, None); + subject.find_best_route_segment(p, None, 2, 10000, RouteDirection::Over, "booga.com"); assert_eq!(route_opt.unwrap(), vec![p, s, t]); // no [p, r, s] or [p, s, r] because s and r are both neighbors of p and can't exit for it // At least two hops over from p to t - let route_opt = - subject.find_best_route_segment(p, Some(t), 2, 10000, RouteDirection::Over, None); + let route_opt = subject.find_best_route_segment( + p, + Some(t), + 2, + 10000, + RouteDirection::Over, + "booga.com", + ); assert_eq!(route_opt.unwrap(), vec![p, s, t]); // At least two hops over from t to p - let route_opt = - subject.find_best_route_segment(t, Some(p), 2, 10000, RouteDirection::Over, None); + let route_opt = subject.find_best_route_segment( + t, + Some(p), + 2, + 10000, + RouteDirection::Over, + "booga.com", + ); assert_eq!(route_opt, None); // p is consume-only; can't be an exit Node. // At least two hops back from t to p - let route_opt = - subject.find_best_route_segment(t, Some(p), 2, 10000, RouteDirection::Back, None); + let route_opt = subject.find_best_route_segment( + t, + Some(p), + 2, + 10000, + RouteDirection::Back, + "booga.com", + ); assert_eq!(route_opt.unwrap(), vec![t, s, p]); // p is consume-only, but it's the originating Node, so including it is okay // At least two hops from p to Q - impossible - let route_opt = - subject.find_best_route_segment(p, Some(q), 2, 10000, RouteDirection::Over, None); + let route_opt = subject.find_best_route_segment( + p, + Some(q), + 2, + 10000, + RouteDirection::Over, + "booga.com", + ); assert_eq!(route_opt, None); } @@ -4735,7 +4675,7 @@ mod tests { 3, 10000, RouteDirection::Back, - None, + "booga.com", ) .unwrap(); @@ -4810,7 +4750,7 @@ mod tests { 3, 10000, RouteDirection::Over, - None, + "booga.com", ); let after = Instant::now(); @@ -4861,8 +4801,14 @@ 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, None); + let route_cz = subject.find_best_route_segment( + root_key, + None, + 2, + 10000, + RouteDirection::Over, + "booga.com", + ); assert_eq!(route_cz, None); } @@ -4927,7 +4873,7 @@ mod tests { subject_min_hops, 10000, RouteDirection::Over, - None, + "booga.com", ); let exit_node = cdb.node_by_key(&route_au.as_ref().unwrap().last().unwrap()); @@ -4982,8 +4928,14 @@ mod tests { }; subject.handle_exit_location_message(message, 0, 0); - let route_fr = - subject.find_best_route_segment(root_key, None, 2, 10000, RouteDirection::Over, None); + let route_fr = subject.find_best_route_segment( + root_key, + None, + 2, + 10000, + RouteDirection::Over, + "booga.com", + ); let exit_node = cdb.node_by_key(&route_fr.as_ref().unwrap().last().unwrap()); assert_eq!( @@ -5006,7 +4958,7 @@ mod tests { // At least two hops from P to anywhere standard let route_opt = - subject.find_best_route_segment(p, None, 2, 10000, RouteDirection::Over, None); + subject.find_best_route_segment(p, None, 2, 10000, RouteDirection::Over, "booga.com"); assert_eq!(route_opt, None); } @@ -5023,7 +4975,7 @@ mod tests { 5, // Lots of hops to go yet 1_000, RouteDirection::Over, - Some("hostname.com"), + "hostname.com", ); let rate_pack = node_record.rate_pack(); @@ -5047,7 +4999,7 @@ mod tests { 0, // Last hop 1_000, RouteDirection::Over, - Some("hostname.com"), + "hostname.com", ); let rate_pack = node_record.rate_pack(); @@ -5075,7 +5027,7 @@ mod tests { 0, // Last hop 1_000, RouteDirection::Over, - Some("hostname.com"), + "hostname.com", ); let rate_pack = node_record.rate_pack(); @@ -5148,7 +5100,7 @@ mod tests { 5, // Plenty of hops remaining: not there yet 1_000, RouteDirection::Back, - None, + "booga.com", ); let rate_pack = node_record.rate_pack(); @@ -6622,7 +6574,7 @@ mod tests { target_component: Component::ProxyClient, return_component_opt: None, payload_size: 10000, - hostname_opt: None, + host: Host::new("booga.com", 1234), }; let unsuccessful_three_hop_route = addr.send(three_hop_route_request); let asserted_node_record = a.clone(); @@ -6989,7 +6941,7 @@ mod tests { target_component: Component::ProxyClient, return_component_opt: Some(Component::ProxyServer), payload_size: 10000, - hostname_opt: None, + host: Host::new("booga.com", 1234), }); assert_eq!( @@ -7035,16 +6987,16 @@ mod tests { target_component: Component::ProxyClient, return_component_opt: Some(Component::ProxyServer), payload_size: 10000, - hostname_opt: None, + host: Host::new("host.name", 88), }); let next_door_neighbor_cryptde = CryptDENull::from(&next_door_neighbor.public_key(), TEST_DEFAULT_CHAIN); let exit_node_cryptde = CryptDENull::from(&exit_node.public_key(), TEST_DEFAULT_CHAIN); - - let hops = result.clone().unwrap().route.hops; + let response = result.clone().unwrap(); + let hops = &response.route.hops; let actual_keys: Vec = match hops.as_slice() { - [hop, exit, hop_back, origin, empty, _accounting] => vec![ + [hop, exit, hop_back, origin, empty] => vec![ decodex::(CRYPTDE_PAIR.main.as_ref(), hop) .expect("hop") .public_key, @@ -7061,7 +7013,11 @@ mod tests { .expect("empty") .public_key, ], - l => panic!("our match is wrong, real size is {}, {:?}", l.len(), l), + l => panic!( + "our match is wrong, real size is {} instead of 5, {:?}", + l.len(), + l + ), }; let expected_public_keys = vec![ next_door_neighbor.public_key().clone(), @@ -7071,6 +7027,38 @@ mod tests { PublicKey::new(b""), ]; assert_eq!(expected_public_keys, actual_keys); + assert_eq!( + response.expected_services, + RoundTrip( + vec![ + Nothing, + Routing( + next_door_neighbor.public_key().clone(), + next_door_neighbor.earning_wallet(), + next_door_neighbor.rate_pack().clone() + ), + Exit( + exit_node.public_key().clone(), + exit_node.earning_wallet(), + exit_node.rate_pack().clone() + ), + ], + vec![ + Exit( + exit_node.public_key().clone(), + exit_node.earning_wallet(), + exit_node.rate_pack().clone() + ), + Routing( + next_door_neighbor.public_key().clone(), + next_door_neighbor.earning_wallet(), + next_door_neighbor.rate_pack().clone() + ), + Nothing, + ] + ) + ); + assert_eq!(response.host, Host::new("host.name", 88)); } fn assert_route_query_message(min_hops: Hops) { @@ -7089,7 +7077,7 @@ mod tests { target_component: Component::ProxyClient, return_component_opt: Some(Component::ProxyServer), payload_size: 10000, - hostname_opt: None, + host: Host::new("booga.com", 1234), }); let assert_hops = |cryptdes: Vec, route: &[CryptData]| { @@ -7099,24 +7087,23 @@ mod tests { } }; /* - This is how the route_hops vector looks like: [C1, C2, ..., C(nodes_count), ..., C2, C1, accounting] + This is how the route_hops vector looks like: [C1, C2, ..., C(nodes_count), ..., C2, C1] Let's consider for 3-hop route ==> Nodes Count --> 4 Route Length --> 8 - Route Hops --> [C1, C2, C3, C4, C3, C2, C1, accounting] + Route Hops --> [C1, C2, C3, C4, C3, C2, C1] Over Route --> [C1, C2, C3] Back Route --> [C4, C3, C2, C1] */ - let mut route_hops = result.unwrap().route.hops; + let route_hops = result.unwrap().route.hops; let route_length = route_hops.len(); - let _accounting = route_hops.pop(); let over_route = &route_hops[..hops]; let back_route = &route_hops[hops..]; let over_cryptdes = cryptdes_from_node_records(&nodes[..hops]); let mut back_cryptdes = cryptdes_from_node_records(&nodes); back_cryptdes.reverse(); - assert_eq!(route_length, 2 * nodes_count); + assert_eq!(route_length, 2 * nodes_count - 1); assert_hops(over_cryptdes, over_route); assert_hops(back_cryptdes, back_route); } @@ -7190,16 +7177,16 @@ mod tests { target_component: Component::ProxyClient, return_component_opt: Some(Component::ProxyServer), payload_size, - hostname_opt: None, + host: Host::new("booga.com", 1234), }) .unwrap(); let (over, back) = match response.expected_services { - ExpectedServices::OneWay(_) => panic!("Expecting RoundTrip"), - ExpectedServices::RoundTrip(o, b, _) => (o[1].clone(), b[1].clone()), + OneWay(_) => panic!("Expecting RoundTrip"), + RoundTrip(o, b) => (o[1].clone(), b[1].clone()), }; let extract_key = |es: ExpectedService| match es { - ExpectedService::Routing(pk, _, _) => pk, + Routing(pk, _, _) => pk, x => panic!("Expecting Routing, found {:?}", x), }; let expected_relay_key = if a_not_b { a.clone() } else { b.clone() }; @@ -7591,24 +7578,6 @@ mod tests { subject } - fn make_o_r_e_subject() -> (NodeRecord, NodeRecord, NodeRecord, Neighborhood) { - let mut subject = make_standard_subject(); - let o = &subject.neighborhood_database.root().clone(); - let r = &make_node_record(4567, false); - let e = &make_node_record(5678, false); - { - let db = &mut subject.neighborhood_database; - db.add_node(r.clone()).unwrap(); - db.add_node(e.clone()).unwrap(); - let mut dual_edge = |a: &NodeRecord, b: &NodeRecord| { - db.add_arbitrary_full_neighbor(a.public_key(), b.public_key()) - }; - dual_edge(o, r); - dual_edge(r, e); - } - (o.clone(), r.clone(), e.clone(), subject) - } - fn segment(nodes: &[&NodeRecord], component: &Component) -> RouteSegment { RouteSegment::new( nodes.into_iter().map(|n| n.public_key()).collect(), diff --git a/node/src/proxy_client/mod.rs b/node/src/proxy_client/mod.rs index aa0f33010..c17daaf16 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: Some(String::from("target.hostname.com")), + target_hostname: String::from("target.hostname.com"), target_port: 1234, protocol: ProxyProtocol::HTTP, originator_public_key: PublicKey::new(&b"originator_public_key"[..]), @@ -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), + route_to_proxy_client(&cryptde.public_key(), cryptde, false), request, 0, ); @@ -754,7 +754,7 @@ mod tests { sequence_number: 0, last_data: false, }, - target_hostname: None, + target_hostname: "booga.com".to_string(), target_port: 0, protocol: ProxyProtocol::HTTP, originator_public_key: PublicKey::new(&b"originator"[..]), @@ -813,7 +813,7 @@ mod tests { sequence_number: 0, last_data: false, }, - target_hostname: None, + target_hostname: "booga.com".to_string(), target_port: 0, protocol: ProxyProtocol::HTTP, originator_public_key: PublicKey::new(&b"originator"[..]), @@ -870,7 +870,7 @@ mod tests { sequence_number: 0, last_data: false, }, - target_hostname: None, + target_hostname: "booga.com".to_string(), target_port: 0, protocol: ProxyProtocol::HTTP, originator_public_key: alias_cryptde.public_key().clone(), @@ -1226,7 +1226,7 @@ mod tests { sequence_number: 0, last_data: false, }, - target_hostname: None, + target_hostname: "booga.com".to_string(), target_port: 0, protocol: ProxyProtocol::HTTP, originator_public_key: originator_public_key.clone(), diff --git a/node/src/proxy_client/stream_establisher.rs b/node/src/proxy_client/stream_establisher.rs index 602b3c0c1..a07e4d730 100644 --- a/node/src/proxy_client/stream_establisher.rs +++ b/node/src/proxy_client/stream_establisher.rs @@ -160,6 +160,8 @@ mod tests { fn spawn_stream_reader_handles_data() { let (proxy_client, proxy_client_awaiter, proxy_client_recording_arc) = make_recorder(); let (sub_tx, sub_rx) = unbounded(); + let stream_key = StreamKey::make_meaningless_stream_key(); + let stream_key_inner = stream_key.clone(); thread::spawn(move || { let system = System::new("spawn_stream_reader_handles_data"); let peer_actors = peer_actors_builder().proxy_client(proxy_client).build(); @@ -193,13 +195,13 @@ mod tests { }; subject.spawn_stream_reader( &ClientRequestPayload_0v1 { - stream_key: StreamKey::make_meaningless_stream_key(), + stream_key: stream_key_inner, sequenced_packet: SequencedPacket { data: vec![], sequence_number: 0, last_data: false, }, - target_hostname: Some("blah".to_string()), + target_hostname: "blah".to_string(), target_port: 0, protocol: ProxyProtocol::HTTP, originator_public_key: subject.cryptde.public_key().clone(), @@ -227,7 +229,7 @@ mod tests { assert_eq!( ibsd, InboundServerData { - stream_key: StreamKey::make_meaningless_stream_key(), + stream_key, last_data: false, sequence_number: 0, source: SocketAddr::from_str("1.2.3.4:5678").unwrap(), diff --git a/node/src/proxy_client/stream_handler_pool.rs b/node/src/proxy_client/stream_handler_pool.rs index 7fc623617..8a42ca2ae 100644 --- a/node/src/proxy_client/stream_handler_pool.rs +++ b/node/src/proxy_client/stream_handler_pool.rs @@ -114,11 +114,7 @@ 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 - .as_ref() - .unwrap_or(&"".to_string()) - .to_string(); + let hostname = payload.target_hostname.clone(); let target_port = payload.target_port; match Self::find_stream_with_key(&stream_key, &inner_arc) { Some(sender_wrapper) => { @@ -315,27 +311,14 @@ impl StreamHandlerPoolReal { "No stream to {:?} exists; resolving host", &payload.target_hostname ); - match payload.target_hostname { - Some(ref target_hostname) => match Self::parse_ip(target_hostname) { - Ok(socket_addr) => Self::handle_ip( - payload.clone(), - socket_addr, - inner_arc, - target_hostname.to_string(), - ), - Err(_) => Self::lookup_dns(inner_arc, target_hostname.to_string(), payload.clone()), - }, - None => { - error!( - logger, - "Cannot open new stream with key {:?}: no hostname supplied", - payload.stream_key - ); - Box::new(err::< - Box + 'static>, - String, - >("No hostname provided".to_string())) - } + match Self::parse_ip(&payload.target_hostname) { + Ok(socket_addr) => Self::handle_ip( + payload.clone(), + socket_addr, + inner_arc, + payload.target_hostname.clone(), + ), + Err(_) => Self::lookup_dns(inner_arc, payload.target_hostname.clone(), payload.clone()), } } @@ -732,7 +715,7 @@ mod tests { let payload = ClientRequestPayload_0v1 { stream_key, sequenced_packet: SequencedPacket::new(b"booga".to_vec(), 0, false), - target_hostname: Some("www.example.com".to_string()), + target_hostname: "www.example.com".to_string(), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: cryptde.public_key().clone(), @@ -765,7 +748,7 @@ mod tests { sequence_number: 0, last_data: false, }, - target_hostname: None, + target_hostname: "booga.com".to_string(), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: PublicKey::new(&b"men's souls"[..]), @@ -820,18 +803,20 @@ 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: StreamKey::make_meaningless_stream_key(), + stream_key: stream_key_inner, sequenced_packet: SequencedPacket { data: b"These are the times".to_vec(), sequence_number: 0, last_data: false, }, - target_hostname: Some(String::from("that.try")), + target_hostname: String::from("that.try"), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: originator_key, @@ -879,7 +864,7 @@ mod tests { assert_eq!( proxy_client_recording.get_record::(0), &InboundServerData { - stream_key: StreamKey::make_meaningless_stream_key(), + stream_key: stream_key.clone(), last_data: true, sequence_number: 0, source: SocketAddr::from_str("2.3.4.5:80").unwrap(), @@ -888,7 +873,8 @@ mod tests { ); TestLogHandler::new().exists_log_containing(&format!( "DEBUG: {test_name}: A shutdown signal was sent to the StreamReader \ - for stream key AAAAAAAAAAAAAAAAAAAAAAAAAAA." + for stream key {}.", + stream_key )); } @@ -897,17 +883,19 @@ 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: StreamKey::make_meaningless_stream_key(), + stream_key: stream_key_inner, sequenced_packet: SequencedPacket { data: b"These are the times".to_vec(), sequence_number: 0, last_data: false, }, - target_hostname: Some(String::from("3.4.5.6:80")), + target_hostname: String::from("3.4.5.6:80"), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: PublicKey::new(&b"men's souls"[..]), @@ -980,7 +968,7 @@ mod tests { assert_eq!( proxy_client_recording.get_record::(0), &InboundServerData { - stream_key: StreamKey::make_meaningless_stream_key(), + stream_key, last_data: false, sequence_number: 0, source: SocketAddr::from_str("3.4.5.6:80").unwrap(), @@ -1003,7 +991,7 @@ mod tests { sequence_number: 0, last_data: true, }, - target_hostname: Some(String::from("3.4.5.6:80")), + target_hostname: String::from("3.4.5.6:80"), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: PublicKey::new(&b"brutal death"[..]), @@ -1064,7 +1052,7 @@ mod tests { sequence_number: 0, last_data: true, }, - target_hostname: Some(String::from("3.4.5.6:80")), + target_hostname: String::from("3.4.5.6:80"), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: PublicKey::new(&b"brutal death"[..]), @@ -1116,17 +1104,19 @@ mod tests { let expected_lookup_ip_parameters = lookup_ip_parameters.clone(); let write_parameters = Arc::new(Mutex::new(vec![])); let expected_write_parameters = write_parameters.clone(); + let stream_key = StreamKey::make_meaningless_stream_key(); + let stream_key_inner = stream_key.clone(); let (proxy_client, proxy_client_awaiter, proxy_client_recording_arc) = make_recorder(); thread::spawn(move || { let peer_actors = peer_actors_builder().proxy_client(proxy_client).build(); let client_request_payload = ClientRequestPayload_0v1 { - stream_key: StreamKey::make_meaningless_stream_key(), + stream_key: stream_key_inner, sequenced_packet: SequencedPacket { data: b"These are the times".to_vec(), sequence_number: 0, last_data: false, }, - target_hostname: Some(String::from("3.4.5.6")), + target_hostname: String::from("3.4.5.6"), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: PublicKey::new(&b"men's souls"[..]), @@ -1209,7 +1199,7 @@ mod tests { assert_eq!( proxy_client_recording.get_record::(0), &InboundServerData { - stream_key: StreamKey::make_meaningless_stream_key(), + stream_key, last_data: false, sequence_number: 0, source: SocketAddr::from_str("3.4.5.6:80").unwrap(), @@ -1218,71 +1208,6 @@ mod tests { ); } - #[test] - fn missing_hostname_for_nonexistent_stream_generates_log_and_termination_message() { - init_test_logging(); - let test_name = - "missing_hostname_for_nonexistent_stream_generates_log_and_termination_message"; - let cryptde = 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(); @@ -1290,6 +1215,8 @@ mod tests { let expected_lookup_ip_parameters = lookup_ip_parameters.clone(); let write_parameters = Arc::new(Mutex::new(vec![])); let expected_write_parameters = write_parameters.clone(); + let stream_key = StreamKey::make_meaningless_stream_key(); + let stream_key_inner = stream_key.clone(); let (proxy_client, proxy_client_awaiter, proxy_client_recording_arc) = make_recorder(); let (accountant, accountant_awaiter, accountant_recording_arc) = make_recorder(); let before = SystemTime::now(); @@ -1299,13 +1226,13 @@ mod tests { .accountant(accountant) .build(); let client_request_payload = ClientRequestPayload_0v1 { - stream_key: StreamKey::make_meaningless_stream_key(), + stream_key: stream_key_inner, sequenced_packet: SequencedPacket { data: b"These are the times".to_vec(), sequence_number: 0, last_data: false, }, - target_hostname: Some(String::from("that.try")), + target_hostname: String::from("that.try"), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: PublicKey::new(&b"men's souls"[..]), @@ -1390,7 +1317,7 @@ mod tests { assert_eq!( proxy_client_recording.get_record::(0), &InboundServerData { - stream_key: StreamKey::make_meaningless_stream_key(), + stream_key, last_data: false, sequence_number: 0, source: SocketAddr::from_str("3.4.5.6:80").unwrap(), @@ -1418,7 +1345,7 @@ mod tests { sequence_number: 0, last_data: false, }, - target_hostname: Some(String::from("that.try")), + target_hostname: String::from("that.try"), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: originator_key, @@ -1540,7 +1467,7 @@ mod tests { sequence_number: 0, last_data: false, }, - target_hostname: Some(String::from("blockedwebsite.com")), + target_hostname: String::from("blockedwebsite.com"), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: originator_key, @@ -1637,7 +1564,7 @@ mod tests { let client_request_payload = ClientRequestPayload_0v1 { stream_key, sequenced_packet: sequenced_packet.clone(), - target_hostname: Some(String::from("that.try")), + target_hostname: String::from("that.try"), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: PublicKey::new(&b"men's souls"[..]), @@ -1750,7 +1677,7 @@ mod tests { sequence_number: 0, last_data: true, }, - target_hostname: Some(String::from("that.try")), + target_hostname: String::from("that.try"), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: originator_key, @@ -1812,7 +1739,7 @@ mod tests { let client_request_payload = ClientRequestPayload_0v1 { stream_key: stream_key.clone(), sequenced_packet: sequenced_packet.clone(), - target_hostname: Some(String::from("that.try")), + target_hostname: String::from("that.try"), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: PublicKey::new(&b"men's souls"[..]), @@ -1883,7 +1810,7 @@ mod tests { sequence_number: 0, last_data: false, }, - target_hostname: None, + target_hostname: "booga.com".to_string(), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: PublicKey::new(&b"booga"[..]), diff --git a/node/src/proxy_client/stream_reader.rs b/node/src/proxy_client/stream_reader.rs index 992b58dbf..bf39de6e3 100644 --- a/node/src/proxy_client/stream_reader.rs +++ b/node/src/proxy_client/stream_reader.rs @@ -179,9 +179,10 @@ mod tests { }); let proxy_client_sub = rx.recv().unwrap(); + let stream_key = StreamKey::make_meaningless_stream_key(); let (stream_killer, stream_killer_params) = unbounded(); let mut subject = StreamReader { - stream_key: StreamKey::make_meaningless_stream_key(), + stream_key: stream_key.clone(), proxy_client_sub, stream, stream_killer, @@ -198,7 +199,7 @@ mod tests { assert_eq!( proxy_client_recording.get_record::(0), &InboundServerData { - stream_key: StreamKey::make_meaningless_stream_key(), + stream_key: stream_key.clone(), last_data: false, sequence_number: 0, source: SocketAddr::from_str("8.7.4.3:50").unwrap(), @@ -208,7 +209,7 @@ mod tests { assert_eq!( proxy_client_recording.get_record::(1), &InboundServerData { - stream_key: StreamKey::make_meaningless_stream_key(), + stream_key: stream_key.clone(), last_data: false, sequence_number: 1, source: SocketAddr::from_str("8.7.4.3:50").unwrap(), @@ -218,7 +219,7 @@ mod tests { assert_eq!( proxy_client_recording.get_record::(2), &InboundServerData { - stream_key: StreamKey::make_meaningless_stream_key(), + stream_key: stream_key.clone(), last_data: false, sequence_number: 2, source: SocketAddr::from_str("8.7.4.3:50").unwrap(), @@ -226,10 +227,7 @@ mod tests { }, ); let stream_killer_parameters = stream_killer_params.try_recv().unwrap(); - assert_eq!( - stream_killer_parameters, - (StreamKey::make_meaningless_stream_key(), 3) - ); + assert_eq!(stream_killer_parameters, (stream_key, 3)); } #[test] @@ -266,6 +264,7 @@ mod tests { let (stream_killer, stream_killer_params) = unbounded(); let peer_addr = SocketAddr::from_str("5.7.9.0:95").unwrap(); let mut subject = make_subject(); + let stream_key = subject.stream_key.clone(); subject.proxy_client_sub = proxy_client_sub; subject.stream = Box::new(stream); subject.stream_killer = stream_killer; @@ -279,7 +278,7 @@ mod tests { assert_eq!( proxy_client_recording.get_record::(0), &InboundServerData { - stream_key: StreamKey::make_meaningless_stream_key(), + stream_key: stream_key.clone(), last_data: false, sequence_number: 0, source: peer_addr, @@ -289,7 +288,7 @@ mod tests { assert_eq!( proxy_client_recording.get_record::(1), &InboundServerData { - stream_key: StreamKey::make_meaningless_stream_key(), + stream_key: stream_key.clone(), last_data: false, sequence_number: 1, source: peer_addr, @@ -299,7 +298,7 @@ mod tests { assert_eq!( proxy_client_recording.get_record::(2), &InboundServerData { - stream_key: StreamKey::make_meaningless_stream_key(), + stream_key: stream_key.clone(), last_data: false, sequence_number: 2, source: peer_addr, @@ -310,10 +309,7 @@ mod tests { let kill_stream_msg = stream_killer_params .try_recv() .expect("stream was not killed"); - assert_eq!( - kill_stream_msg, - (StreamKey::make_meaningless_stream_key(), 3) - ); + assert_eq!(kill_stream_msg, (stream_key, 3)); assert!(stream_killer_params.try_recv().is_err()); } diff --git a/node/src/proxy_server/client_request_payload_factory.rs b/node/src/proxy_server/client_request_payload_factory.rs index 75a484a37..48479312c 100644 --- a/node/src/proxy_server/client_request_payload_factory.rs +++ b/node/src/proxy_server/client_request_payload_factory.rs @@ -3,6 +3,7 @@ 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; @@ -13,6 +14,7 @@ pub trait ClientRequestPayloadFactory { &self, ibcd: &InboundClientData, stream_key: StreamKey, + host_opt: Option, cryptde: &dyn CryptDE, logger: &Logger, ) -> Option; @@ -26,10 +28,33 @@ impl ClientRequestPayloadFactory for ClientRequestPayloadFactoryReal { &self, ibcd: &InboundClientData, stream_key: StreamKey, + host_opt: Option, cryptde: &dyn CryptDE, logger: &Logger, ) -> Option { let protocol_pack = from_ibcd(ibcd).map_err(|e| error!(logger, "{}", e)).ok()?; + let host_from_ibcd = Box::new(|| { + let data = PlainData::new(&ibcd.data); + match protocol_pack.find_host(&data) { + Some(host) => Ok(host), + // So far we've only looked in the client packet; but this message will evaporate + // unless there's no host information in host_opt (from ProxyServer's StreamInfo) either. + None => Err(format!( + "No hostname information found in either client packet or ProxyServer for protocol {:?}", + protocol_pack.proxy_protocol() + )), + } + }); + let target_host: Host = match host_from_ibcd() { + Ok(host) => host, + Err(e) => match host_opt { + Some(host) => host, + None => { + error!(logger, "{}", e); + return None; + } + }, + }; let sequence_number = match ibcd.sequence_number { Some(sequence_number) => sequence_number, None => { @@ -41,12 +66,6 @@ impl ClientRequestPayloadFactory for ClientRequestPayloadFactoryReal { return None; } }; - let data = PlainData::new(&ibcd.data); - let target_host = protocol_pack.find_host(&data); - let (target_hostname_opt, target_port) = match target_host { - Some(host) => (Some(host.name), host.port), - None => (None, protocol_pack.standard_port()), - }; Some(ClientRequestPayload_0v1 { stream_key, sequenced_packet: SequencedPacket { @@ -54,8 +73,8 @@ impl ClientRequestPayloadFactory for ClientRequestPayloadFactoryReal { sequence_number, last_data: ibcd.last_data, }, - target_hostname: target_hostname_opt, - target_port, + target_hostname: target_host.name, + target_port: target_host.port, protocol: protocol_pack.proxy_protocol(), originator_public_key: cryptde.public_key().clone(), }) @@ -74,7 +93,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; + use masq_lib::constants::{HTTP_PORT, TLS_PORT}; use masq_lib::test_utils::logging::init_test_logging; use masq_lib::test_utils::logging::TestLogHandler; use std::net::SocketAddr; @@ -85,13 +104,101 @@ 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: 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: 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: 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 or ProxyServer for protocol HTTP")); + } + #[test] fn handles_http_with_a_port() { let data = PlainData::new(&b"GET http://borkoed.com:2345/fleebs.html HTTP/1.1\r\n\r\n"[..]); let ibcd = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port: Some(HTTP_PORT), + reception_port_opt: Some(HTTP_PORT), sequence_number: Some(1), last_data: false, is_clandestine: false, @@ -102,7 +209,7 @@ mod tests { let logger = Logger::new("test"); let subject = Box::new(ClientRequestPayloadFactoryReal::new()); - let result = subject.make(&ibcd, stream_key, cryptde, &logger); + let result = subject.make(&ibcd, stream_key, None, cryptde, &logger); assert_eq!( result, @@ -113,7 +220,7 @@ mod tests { sequence_number: 1, last_data: false }, - target_hostname: Some(String::from("borkoed.com")), + target_hostname: String::from("borkoed.com"), target_port: 2345, protocol: ProxyProtocol::HTTP, originator_public_key: cryptde.public_key().clone(), @@ -128,7 +235,7 @@ mod tests { let ibcd = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port: Some(HTTP_PORT), + reception_port_opt: Some(HTTP_PORT), sequence_number: Some(1), last_data: false, is_clandestine: false, @@ -139,7 +246,7 @@ mod tests { let stream_key = StreamKey::make_meaningful_stream_key(test_name); let subject = Box::new(ClientRequestPayloadFactoryReal::new()); - let result = subject.make(&ibcd, stream_key, cryptde, &logger); + let result = subject.make(&ibcd, stream_key, None, cryptde, &logger); assert_eq!( result, @@ -150,7 +257,7 @@ mod tests { sequence_number: 1, last_data: false }, - target_hostname: Some(String::from("borkoed.com")), + target_hostname: String::from("borkoed.com"), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: cryptde.public_key().clone(), @@ -184,7 +291,7 @@ mod tests { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), sequence_number: Some(0), - reception_port: Some(443), + reception_port_opt: Some(443), last_data: false, is_clandestine: false, data: data.clone().into(), @@ -194,7 +301,7 @@ mod tests { let logger = Logger::new("test"); let subject = Box::new(ClientRequestPayloadFactoryReal::new()); - let result = subject.make(&ibcd, stream_key, cryptde, &logger); + let result = subject.make(&ibcd, stream_key, None, cryptde, &logger); assert_eq!( result, @@ -205,8 +312,8 @@ mod tests { sequence_number: 0, last_data: false }, - target_hostname: Some(String::from("server.com")), - target_port: 443, + target_hostname: String::from("server.com"), + target_port: TLS_PORT, protocol: ProxyProtocol::TLS, originator_public_key: cryptde.public_key().clone(), }) @@ -215,6 +322,7 @@ mod tests { #[test] fn handles_tls_without_hostname() { + init_test_logging(); let test_name = "handles_tls_without_hostname"; let data = PlainData::new(&[ 0x16, // content_type: Handshake @@ -233,7 +341,7 @@ mod tests { let ibcd = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port: Some(443), + reception_port_opt: Some(443), last_data: true, is_clandestine: false, sequence_number: Some(0), @@ -244,23 +352,10 @@ mod tests { let stream_key = StreamKey::make_meaningful_stream_key(test_name); let subject = Box::new(ClientRequestPayloadFactoryReal::new()); - let result = subject.make(&ibcd, stream_key, cryptde, &logger); + let result = subject.make(&ibcd, stream_key, None, cryptde, &logger); - assert_eq!( - result, - Some(ClientRequestPayload_0v1 { - stream_key, - sequenced_packet: SequencedPacket { - data: data.into(), - sequence_number: 0, - last_data: true - }, - target_hostname: None, - target_port: 443, - protocol: ProxyProtocol::TLS, - originator_public_key: cryptde.public_key().clone(), - }) - ); + assert_eq!(result, None); + TestLogHandler::new().exists_log_containing(&format!("ERROR: {test_name}: No hostname information found in either client packet or ProxyServer for protocol TLS")); } #[test] @@ -271,7 +366,7 @@ mod tests { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), sequence_number: Some(0), - reception_port: None, + reception_port_opt: None, last_data: false, is_clandestine: false, data: vec![0x10, 0x11, 0x12], @@ -281,7 +376,7 @@ mod tests { let stream_key = StreamKey::make_meaningful_stream_key(test_name); let subject = Box::new(ClientRequestPayloadFactoryReal::new()); - let result = subject.make(&ibcd, stream_key, cryptde, &logger); + let result = subject.make(&ibcd, stream_key, None, cryptde, &logger); assert_eq!(result, None); TestLogHandler::new().exists_log_containing( @@ -296,7 +391,7 @@ mod tests { let ibcd = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:5678").unwrap(), - reception_port: Some(1234), + reception_port_opt: Some(1234), sequence_number: Some(0), last_data: false, is_clandestine: true, @@ -307,7 +402,7 @@ mod tests { let stream_key = StreamKey::make_meaningful_stream_key(test_name); let subject = Box::new(ClientRequestPayloadFactoryReal::new()); - let result = subject.make(&ibcd, stream_key, cryptde, &logger); + let result = subject.make(&ibcd, stream_key, None, cryptde, &logger); assert_eq!(result, None); TestLogHandler::new().exists_log_containing(&format!("ERROR: {test_name}: No protocol associated with origin port 1234 for 3-byte non-clandestine packet: [16, 17, 18]")); @@ -315,13 +410,14 @@ mod tests { #[test] fn use_sequence_from_inbound_client_data_in_client_request_payload() { + let data = PlainData::new(&b"GET http://borkoed.com/fleebs.html HTTP/1.1\r\n\r\n"[..]); let ibcd = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:80").unwrap(), - reception_port: Some(HTTP_PORT), + reception_port_opt: Some(HTTP_PORT), sequence_number: Some(1), last_data: false, - data: vec![0x10, 0x11, 0x12], + data: data.into(), is_clandestine: false, }; let cryptde = CRYPTDE_PAIR.main.as_ref(); @@ -332,6 +428,7 @@ mod tests { .make( &ibcd, StreamKey::make_meaningless_stream_key(), + None, cryptde, &logger, ) @@ -344,25 +441,26 @@ mod tests { fn makes_no_payload_if_sequence_number_is_unknown() { init_test_logging(); let test_name = "makes_no_payload_if_sequence_number_is_unknown"; + let data = PlainData::new(&b"GET http://borkoed.com/fleebs.html HTTP/1.1\r\n\r\n"[..]); let ibcd = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:80").unwrap(), - reception_port: Some(HTTP_PORT), + reception_port_opt: Some(HTTP_PORT), last_data: false, is_clandestine: false, sequence_number: None, - data: vec![1, 3, 5, 7], + data: data.into(), }; let cryptde = 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, cryptde, &logger); + let result = subject.make(&ibcd, stream_key, None, cryptde, &logger); assert_eq!(result, None); TestLogHandler::new().exists_log_containing(&format!( - "ERROR: {test_name}: internal error: got IBCD with no sequence number and 4 bytes" + "ERROR: {test_name}: internal error: got IBCD with no sequence number and 47 bytes" )); } } diff --git a/node/src/proxy_server/http_protocol_pack.rs b/node/src/proxy_server/http_protocol_pack.rs index b611f2be3..523e34e3b 100644 --- a/node/src/proxy_server/http_protocol_pack.rs +++ b/node/src/proxy_server/http_protocol_pack.rs @@ -1,7 +1,8 @@ // Copyright (c) 2019, MASQ (https://masq.ai) and/or its affiliates. All rights reserved. -use crate::proxy_server::protocol_pack::{Host, ProtocolPack, ServerImpersonator}; +use crate::proxy_server::protocol_pack::{ProtocolPack, ServerImpersonator}; use crate::proxy_server::server_impersonator_http::ServerImpersonatorHttp; use crate::sub_lib::cryptde::PlainData; +use crate::sub_lib::host::Host; use crate::sub_lib::proxy_server::ProxyProtocol; use lazy_static::lazy_static; use masq_lib::constants::HTTP_PORT; @@ -12,6 +13,7 @@ lazy_static! { static ref HOST_PATTERN: Regex = Regex::new(r"^(?:https?://)?([^\s/]+)").expect("bad regex"); } +#[derive(Clone, Copy)] pub struct HttpProtocolPack {} impl ProtocolPack for HttpProtocolPack { diff --git a/node/src/proxy_server/mod.rs b/node/src/proxy_server/mod.rs index 459acf668..491cb1111 100644 --- a/node/src/proxy_server/mod.rs +++ b/node/src/proxy_server/mod.rs @@ -24,6 +24,7 @@ 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}; @@ -31,14 +32,13 @@ use crate::sub_lib::neighborhood::{NRMetadataChange, RouteQueryMessage}; use crate::sub_lib::peer_actors::BindMessage; use crate::sub_lib::proxy_client::{ClientResponsePayload_0v1, DnsResolveFailure_0v1}; use crate::sub_lib::proxy_server::ProxyServerSubs; -use crate::sub_lib::proxy_server::{AddReturnRouteMessage, StreamKeyPurge}; +use crate::sub_lib::proxy_server::StreamKeyPurge; use crate::sub_lib::proxy_server::{ AddRouteResultMessage, ClientRequestPayload_0v1, ProxyProtocol, }; 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,15 +53,13 @@ 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, @@ -69,27 +67,31 @@ 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, - tunneled_hosts: HashMap, - dns_failure_retries: HashMap, - stream_key_routes: HashMap, - stream_key_ttl: HashMap, + stream_info: HashMap, is_decentralized: bool, consuming_wallet_balance: Option, 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, @@ -111,7 +113,6 @@ impl Handler for ProxyServer { accountant: msg.peer_actors.accountant.report_services_consumed, route_source: msg.peer_actors.neighborhood.route_query, update_node_record_metadata: msg.peer_actors.neighborhood.update_node_record_metadata, - add_return_route: msg.peer_actors.proxy_server.add_return_route, stream_shutdown_sub: msg.peer_actors.proxy_server.stream_shutdown_sub, route_result_sub: msg.peer_actors.proxy_server.route_result_sub, schedule_stream_key_purge: msg.peer_actors.proxy_server.schedule_stream_key_purge, @@ -135,57 +136,11 @@ impl Handler for ProxyServer { } } -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 { - 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); - } - } + self.handle_add_route_result_message(msg) } } @@ -256,21 +211,18 @@ 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(), - tunneled_hosts: HashMap::new(), - dns_failure_retries: HashMap::new(), - stream_key_routes: HashMap::new(), - stream_key_ttl: HashMap::new(), + stream_info: HashMap::new(), is_decentralized, consuming_wallet_balance, cryptde_pair, crashable, - logger: Logger::new("ProxyServer"), - route_ids_to_return_routes: TtlHashMap::new(RETURN_ROUTE_TTL), + logger: ps_logger, browser_proxy_sequence_offset: false, inbound_client_data_helper_opt: Some(Box::new(IBCDHelperReal::new())), stream_key_purge_delay: STREAM_KEY_PURGE_DELAY, @@ -284,7 +236,6 @@ impl ProxyServer { from_dispatcher: recipient!(addr, InboundClientData), from_hopper: recipient!(addr, ExpiredCoresPackage), dns_failure_from_hopper: recipient!(addr, ExpiredCoresPackage), - add_return_route: recipient!(addr, AddReturnRouteMessage), stream_shutdown_sub: recipient!(addr, StreamShutdownMsg), node_from_ui: recipient!(addr, NodeFromUiMessage), route_result_sub: recipient!(addr, AddRouteResultMessage), @@ -292,24 +243,46 @@ 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( - &mut self, + stream_info: &mut StreamInfo, stream_key: &StreamKey, ) -> Result { - match self.dns_failure_retries.remove(stream_key) { + match stream_info.dns_failure_retry_opt.take() { None => Err(format!( - "No entry found inside dns_failure_retries hashmap for the stream_key: {:?}", + "No DNSFailureRetry entry found for the stream_key: {:?}", stream_key )), Some(retry) => Ok(retry), } } - fn retry_dns_resolution( - &mut self, - retry: DNSFailureRetry, - client_addr: SocketAddr, - ) -> DNSFailureRetry { + fn retry_dns_resolution(&mut self, retry: &DNSFailureRetry, client_addr: SocketAddr) { let args = TransmitToHopperArgs::new( self, retry.unsuccessful_request.clone(), @@ -317,7 +290,6 @@ impl ProxyServer { SystemTime::now(), false, ); - let add_return_route_sub = self.out_subs("ProxyServer").add_return_route.clone(); let route_source = self.out_subs("Neighborhood").route_source.clone(); let proxy_server_sub = self.out_subs("ProxyServer").route_result_sub.clone(); let inbound_client_data_helper = self @@ -325,13 +297,7 @@ impl ProxyServer { .as_ref() .expect("IBCDHelper uninitialized"); - inbound_client_data_helper.request_route_and_transmit( - args, - add_return_route_sub, - route_source, - proxy_server_sub, - ); - retry + inbound_client_data_helper.request_route_and_transmit(args, route_source, proxy_server_sub); } fn retire_stream_key(&mut self, stream_key: &StreamKey) { @@ -342,7 +308,7 @@ impl ProxyServer { &self, client_addr: SocketAddr, proxy_protocol: ProxyProtocol, - hostname_opt: Option, + hostname: String, ) { self.subs .as_ref() @@ -354,116 +320,251 @@ impl ProxyServer { sequence_number: Some(0), // DNS resolution errors always happen on the first request data: from_protocol(proxy_protocol) .server_impersonator() - .dns_resolution_failure_response(hostname_opt), + .dns_resolution_failure_response(hostname), }) .expect("Dispatcher is dead"); } - fn handle_dns_resolve_failure(&mut self, msg: &ExpiredCoresPackage) { - 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 + 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) { + 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 ); - } - }) - .clone() + }, + ); + 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, + ); + } - let hostname_opt = return_route_info.hostname_opt.clone(); + fn handle_dns_resolve_failure(&mut self, msg: &ExpiredCoresPackage) { let response = &msg.payload; - match self.keys_and_addrs.a_to_b(&response.stream_key) { - Some(client_addr) => { - if let Some(server_name) = hostname_opt.clone() { - 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 { + // The idea here is that the Borrow Checker will not allow us to modify the StreamInfo in + // ProxyServer's map while we're looking at one of its values. So we're making a mutable + // copy of the StreamInfo, modifying that as necessary, and then overwriting the original + // map element with the modified copy at the end of the function. However, under certain + // circumstances we want to _retire_ the stream key; so we have a restore_stream_info + // flag that starts out true and is set to false if we retire the stream key. It's an + // ugly hack. Thanks, Borrow Checker! + let mut stream_info = match self.stream_info(&response.stream_key) { + Some(info) => (*info).clone(), + None => { + error!( + self.logger, + "Discarding DnsResolveFailure message from an unrecognized stream key {:?}", + &response.stream_key + ); + return; + } + }; + 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, - "Exit node {exit_public_key} complained of DNS failure, but was given no hostname to resolve." + "Stream info for stream key {} has no exit node in its response services", + &response.stream_key ); - // TODO: Malefactor ban the exit node because it lied about the DNS failure. + return; } - 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 + } + }; + 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!( + self.logger, + "Handling DNS failure for hostname {:?} - stream key: {} retries left: {}", + retry_ref.unsuccessful_request.target_hostname, + &response.stream_key, + retry_ref.retries_left + ); + if retry_ref.retries_left > 0 { + self.retry_dns_resolution(retry_ref, client_addr); + retry_ref.retries_left -= 1; + } else { + restore_stream_info = false; + self.retire_stream_key(&response.stream_key); + let protocol = stream_info.protocol_opt.expect( + "StreamInfo should always have a protocol_opt set by the time we get a DNS failure" + ); + self.send_dns_failure_response_to_the_browser( + client_addr, + protocol, + route_query_response.host.name.clone(), ); - 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 { - self.retire_stream_key(&response.stream_key); - self.send_dns_failure_response_to_the_browser( - client_addr, - return_route_info.protocol, - hostname_opt, + error!( + self.logger, + "While handling ExpiredCoresPackage: No DNSFailureRetry entry found for the stream_key: {:?}", + &response.stream_key ); + return; } } None => { error!(self.logger, "Discarding DnsResolveFailure message for {} from an unrecognized stream key {:?}", - hostname_opt.unwrap_or_else(|| "".to_string()), + route_query_response.host.name, &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 host_info = match self.tunneled_hosts.get(&stream_key) { - None => String::from(""), - Some(hostname) => format!(", which was tunneling to the host {:?}", hostname), - }; - debug!( - self.logger, - "Client closed stream referenced by stream key {:?}{}. It will be purged after {:?}.", - &stream_key, - host_info, - self.stream_key_purge_delay - ); - self.stream_key_ttl.insert(stream_key, SystemTime::now()); - self.subs - .as_ref() - .expect("ProxyServer Subs Unbound") - .schedule_stream_key_purge - .try_send(MessageScheduler { - scheduled_msg: StreamKeyPurge { stream_key }, - delay: self.stream_key_purge_delay, - }) - .expect("ProxyServer is dead"); + let stream_key_purge_delay = self.stream_key_purge_delay; + let mut delayed_log: Box = Box::new(|_: &Logger| {}); + if let Some(stream_info) = self.stream_info_mut(&stream_key) { + let host_info = match &stream_info.tunneled_host_opt { + None => String::from(""), + Some(hostname) => format!(", which was tunneling to the host {:?}", hostname), + }; + delayed_log = Box::new(move |logger: &Logger| { + debug!( + logger, + "Client closed stream referenced by stream key {:?}{}. It will be purged after {:?}.", + &stream_key, + host_info, + stream_key_purge_delay + ); + }); + stream_info.time_to_live_opt = Some(SystemTime::now()); + self.subs + .as_ref() + .expect("ProxyServer Subs Unbound") + .schedule_stream_key_purge + .try_send(MessageScheduler { + scheduled_msg: StreamKeyPurge { stream_key }, + delay: self.stream_key_purge_delay, + }) + .expect("ProxyServer is dead"); + } + delayed_log(&self.logger); } fn log_straggling_packet( @@ -488,14 +589,6 @@ 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!( @@ -503,31 +596,36 @@ impl ProxyServer { "Relaying ClientResponsePayload (stream key {}, sequence {}, length {}) from Hopper to Dispatcher for client", response.stream_key, response.sequenced_packet.sequence_number, response.sequenced_packet.data.len() ); - let return_route_info = - match self.get_return_route_info(&msg.remaining_route, "client response") { - Some(rri) => rri, - None => return, - }; + let expected_services = match self.get_expected_return_services(&response.stream_key) { + Some(expected_services) => expected_services, + None => return, + }; self.report_response_services_consumed( - &return_route_info, + &expected_services, response.sequenced_packet.data.len(), payload_data_len, ); let stream_key = response.stream_key; - match self.remove_dns_failure_retry(&stream_key) { - Ok(_) => { - debug!(self.logger, "Successful attempt of DNS resolution, removing DNS retry entry for stream key: {}", &response.stream_key) - } - Err(_) => { - trace!( - self.logger, - "No DNS retry entry found for stream key: {} during a successful attempt", - &response.stream_key - ) + let old_timestamp_opt = match self.stream_info_mut(&stream_key) { + Some(info) => { + let time_to_live_opt = info.time_to_live_opt; + // This call to remove_dns_failure_retry is here only because it needs access to + // a mutable StreamInfo, and we have one handy here. It has nothing to do with + // timestamps. + if let Err(e) = ProxyServer::remove_dns_failure_retry(info, &stream_key) { + trace!( + self.logger, + "No DNS retry entry found for stream key {} during a successful attempt: {}", + &stream_key, e + ); + } + time_to_live_opt } - } - if let Some(old_timestamp) = self.stream_key_ttl.get(&stream_key) { - self.log_straggling_packet(&stream_key, payload_data_len, old_timestamp) + None => None, + }; + if let Some(old_timestamp) = old_timestamp_opt { + self.log_straggling_packet(&stream_key, payload_data_len, &old_timestamp) + // TODO: Make sure we actually do something (other than logging) about stragglers. } else { match self.keys_and_addrs.a_to_b(&stream_key) { Some(socket_addr) => { @@ -574,7 +672,10 @@ impl ProxyServer { match http_data { Some(ref host) if host.port == TLS_PORT => { let stream_key = self.find_or_generate_stream_key(msg); - self.tunneled_hosts.insert(stream_key, host.name.clone()); + match self.stream_info_mut(&stream_key) { + None => return, + Some(stream_info) => stream_info.tunneled_host_opt = Some(host.name.clone()), + } self.subs .as_ref() .expect("Dispatcher unbound in ProxyServer") @@ -636,7 +737,7 @@ impl ProxyServer { let ibcd = InboundClientData { timestamp: SystemTime::now(), client_addr: msg.peer_addr, - reception_port: Some(nca.reception_port), + reception_port_opt: Some(nca.reception_port), last_data: true, is_clandestine: false, sequence_number: Some(nca.sequence_number), @@ -667,6 +768,16 @@ 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 {}", @@ -684,9 +795,7 @@ impl ProxyServer { "Retiring stream key {} due to {}", &stream_key, reason ); let _ = self.keys_and_addrs.remove_a(stream_key); - let _ = self.stream_key_routes.remove(stream_key); - let _ = self.tunneled_hosts.remove(stream_key); - let _ = self.stream_key_ttl.remove(stream_key); + let _ = self.stream_info.remove(stream_key); } fn make_payload( @@ -694,10 +803,17 @@ impl ProxyServer { ibcd: InboundClientData, stream_key: &StreamKey, ) -> Result { - let tunnelled_host = self.tunneled_hosts.get(stream_key); - let new_ibcd = match tunnelled_host { + let stream_info_opt = self.stream_info.get(stream_key); + let (host_opt, tunnelled_host_opt) = match stream_info_opt { + None => (None, None), + Some(info) => match &info.route_opt { + Some(route) => (Some(route.host.clone()), info.tunneled_host_opt.clone()), + None => (None, info.tunneled_host_opt.clone()), + }, + }; + let new_ibcd = match tunnelled_host_opt { Some(_) => InboundClientData { - reception_port: Some(443), + reception_port_opt: Some(443), ..ibcd }, None => ibcd, @@ -705,13 +821,14 @@ 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 { + Some(payload) => match tunnelled_host_opt { Some(hostname) => Ok(ClientRequestPayload_0v1 { - target_hostname: Some(hostname.clone()), + target_hostname: hostname, ..payload }), None => Ok(payload), @@ -721,24 +838,10 @@ impl ProxyServer { fn try_transmit_to_hopper( args: TransmitToHopperArgs, - add_return_route_sub: Recipient, route_query_response: RouteQueryResponse, ) -> Result<(), String> { match route_query_response.expected_services { - ExpectedServices::RoundTrip(over, back, 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"); + ExpectedServices::RoundTrip(over, _) => { ProxyServer::transmit_to_hopper(args, route_query_response.route, over) } _ => panic!("Expected RoundTrip ExpectedServices but got OneWay"), @@ -891,7 +994,7 @@ impl ProxyServer { source_addr: SocketAddr, dispatcher: &Recipient, ) -> String { - let target_hostname = ProxyServer::hostname(&payload); + let target_hostname = payload.target_hostname.clone(); let stream_key = payload.stream_key; ProxyServer::send_route_failure(payload, source_addr, dispatcher); format!( @@ -907,7 +1010,7 @@ impl ProxyServer { ) { let data = from_protocol(payload.protocol) .server_impersonator() - .route_query_failure_response(&ProxyServer::hostname(&payload)); + .route_query_failure_response(&payload.target_hostname); let msg = TransmitDataMsg { endpoint: Endpoint::Socket(source_addr), last_data: true, @@ -917,46 +1020,35 @@ impl ProxyServer { dispatcher.try_send(msg).expect("Dispatcher is dead"); } - fn hostname(payload: &ClientRequestPayload_0v1) -> String { - match payload.target_hostname { - Some(ref thn) => thn.clone(), - None => "".to_string(), - } - } - - fn get_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), + fn get_expected_return_services( + &mut self, + stream_key: &StreamKey, + ) -> Option> { + match self.stream_info(stream_key) { None => { - error!(self.logger, "Can't report services consumed: received response with bogus return-route ID {} for {}. Ignoring", return_route_id, source); + error!(self.logger, "Can't pay for return services consumed: received response with unrecognized stream key {:?}. Ignoring", stream_key); None + }, + Some(stream_info) => match &stream_info.route_opt { + None => { + error!(self.logger, "Can't pay for return services consumed: stream_info contains no route for stream key {:?}", stream_key); + None + }, + Some(route) => match route.expected_services { + ExpectedServices::RoundTrip(_, ref return_services) => Some(return_services.clone()), + _ => panic!("Internal error: ExpectedServices in ProxyServer for stream key {:?} is not RoundTrip", stream_key), + } } } } fn report_response_services_consumed( &self, - return_route_info: &AddReturnRouteMessage, + expected_services: &[ExpectedService], exit_size: usize, routing_size: usize, ) { - let exit_service_report: ExitServiceSearch = return_route_info - .expected_services + let exit_service_report: ExitServiceSearch = expected_services .iter() .filter(|service| !matches!(service, ExpectedService::Nothing)) .fold(ZeroHop, |acc, service| { @@ -982,8 +1074,7 @@ impl ProxyServer { ZeroHop => return, Definite(report) => report, }; - let routing_service_reports = return_route_info - .expected_services + let routing_service_reports = expected_services .iter() .flat_map(|service| match service { ExpectedService::Routing(_, wallet, rate_pack) => Some(RoutingServiceConsumed { @@ -1022,13 +1113,20 @@ pub trait IBCDHelper { &self, proxy_s: &mut ProxyServer, msg: InboundClientData, + // TODO: I was wondering: could we just use msg.is_last_data here, instead of a whole different + // parameter? Then I thought no, they're not the same: is_last_data means the client won't + // send any more data, but we don't want to retire_stream_key until we've waited for any + // straggling responses from the server, so that we can pay for them. However, it turns out + // that if there is any such delay for straggling data, it's doesn't have anything to do with + // retire_stream_key, because retire_stream_key is always equal to msg.is_last_data. So we + // _could_ remove retire_stream_key and use msg.is_last_data, but I think the whole thing + // ought to be rejiggered to wait for straggling data. retire_stream_key: bool, ) -> Result<(), String>; fn request_route_and_transmit( &self, args: TransmitToHopperArgs, - add_return_route_sub: Recipient, route_source: Recipient, proxy_server_sub: Recipient, ); @@ -1038,7 +1136,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>, ); @@ -1049,18 +1147,13 @@ 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, - add_return_route_sub, - route_query_response.clone(), - ) { + match ProxyServer::try_transmit_to_hopper(args, route_query_response.clone()) { Ok(()) => Ok(route_query_response), Err(e) => Err(e), } @@ -1102,15 +1195,16 @@ impl IBCDHelperReal { } } } + impl IBCDHelper for IBCDHelperReal { fn handle_normal_client_data( &self, - proxy: &mut ProxyServer, + proxy_server: &mut ProxyServer, msg: InboundClientData, retire_stream_key: bool, ) -> Result<(), String> { let client_addr = msg.client_addr; - if proxy.consuming_wallet_balance.is_none() && proxy.is_decentralized { + if proxy_server.consuming_wallet_balance.is_none() && proxy_server.is_decentralized { let protocol_pack = match from_ibcd(&msg) { Err(e) => return Err(e), Ok(pp) => pp, @@ -1124,22 +1218,22 @@ impl IBCDHelper for IBCDHelperReal { sequence_number: Some(0), data, }; - proxy + proxy_server .out_subs("Dispatcher") .dispatcher .try_send(msg) .expect("Dispatcher is dead"); return Err("Browser request rejected due to missing consuming wallet".to_string()); } - let stream_key = proxy.find_or_generate_stream_key(&msg); + let stream_key = proxy_server.find_or_generate_stream_key(&msg); let timestamp = msg.timestamp; - let payload = match proxy.make_payload(msg, &stream_key) { + let payload = match proxy_server.make_payload(msg, &stream_key) { Ok(payload) => { - if !proxy.is_running_in_integration_test { - if let Some(hostname) = &payload.target_hostname { - if let Err(e) = Hostname::new(hostname).validate_non_loopback_host() { - return Err(format!("Request to wildcard IP detected - {} (Most likely because Blockchain Service URL is not set)", e)); - } + if !proxy_server.is_running_in_integration_test { + if let Err(e) = + Hostname::new(&payload.target_hostname).validate_non_loopback_host() + { + return Err(format!("Request to wildcard IP detected - {} (Most likely because Blockchain Service URL is not set)", e)); } } payload @@ -1147,38 +1241,52 @@ impl IBCDHelper for IBCDHelperReal { Err(e) => return Err(e), }; - if proxy.dns_failure_retries.get(&stream_key).is_none() { - let dns_failure_retry = DNSFailureRetry { - unsuccessful_request: payload.clone(), - retries_left: if proxy.is_decentralized { 3 } else { 0 }, - }; - proxy - .dns_failure_retries - .insert(stream_key, dns_failure_retry); + { + let is_decentralized = proxy_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); + } } - let args = - TransmitToHopperArgs::new(proxy, payload, client_addr, timestamp, retire_stream_key); - let add_return_route_sub = proxy.out_subs("ProxysServer").add_return_route.clone(); + let args = TransmitToHopperArgs::new( + proxy_server, + payload, + client_addr, + timestamp, + retire_stream_key, + ); let pld = &args.payload; - if let Some(route_query_response) = proxy.stream_key_routes.get(&pld.stream_key) { + 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 { debug!( - proxy.logger, + proxy_server.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, add_return_route_sub, route_query_response) + ProxyServer::try_transmit_to_hopper(args, route_query_response) } else { - let route_source = proxy.out_subs("Neighborhood").route_source.clone(); - let proxy_server_sub = proxy.out_subs("ProxyServer").route_result_sub.clone(); - self.request_route_and_transmit( - args, - add_return_route_sub, - route_source, - proxy_server_sub, - ); + let route_source = proxy_server.out_subs("Neighborhood").route_source.clone(); + let proxy_server_sub = proxy_server + .out_subs("ProxyServer") + .route_result_sub + .clone(); + self.request_route_and_transmit(args, route_source, proxy_server_sub); Ok(()) } } @@ -1186,12 +1294,11 @@ 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 hostname_opt = pld.target_hostname.clone(); + let host = Host::new(&pld.target_hostname, pld.target_port); let logger = args.logger.clone(); debug!( logger, @@ -1206,16 +1313,11 @@ impl IBCDHelper for IBCDHelperReal { tokio::spawn( neighborhood_sub .send(RouteQueryMessage::data_indefinite_route_request( - hostname_opt, + host, payload_size, )) .then(move |route_result| { - message_resolver.resolve_message( - args, - add_return_route_sub, - proxy_server_sub, - route_result, - ); + message_resolver.resolve_message(args, proxy_server_sub, route_result); Ok(()) }), ); @@ -1354,6 +1456,7 @@ 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; @@ -1367,6 +1470,7 @@ 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}; @@ -1375,7 +1479,6 @@ mod tests { use crate::sub_lib::route::Route; use crate::sub_lib::route::RouteSegment; use crate::sub_lib::sequence_buffer::SequencedPacket; - use crate::sub_lib::ttl_hashmap::TtlHashMap; use crate::sub_lib::versioned_data::VersionedData; use crate::test_utils::make_meaningless_route; use crate::test_utils::make_paying_wallet; @@ -1390,7 +1493,6 @@ 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; @@ -1459,7 +1561,6 @@ mod tests { fn resolve_message( &self, args: TransmitToHopperArgs, - _add_return_route_sub: Recipient, _proxy_server_sub: Recipient, route_result: Result, MailboxError>, ) { @@ -1486,11 +1587,59 @@ 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; @@ -1504,7 +1653,6 @@ mod tests { accountant: recipient!(addr, ReportServicesConsumedMessage), route_source: recipient!(addr, RouteQueryMessage), update_node_record_metadata: recipient!(addr, UpdateNodeRecordMetadataMessage), - add_return_route: recipient!(addr, AddReturnRouteMessage), stream_shutdown_sub: recipient!(addr, StreamShutdownMsg), route_result_sub: recipient!(addr, AddRouteResultMessage), schedule_stream_key_purge: recipient!(addr, MessageScheduler), @@ -1599,7 +1747,6 @@ mod tests { fn request_route_and_transmit( &self, _args: TransmitToHopperArgs, - _add_return_route_sub: Recipient, _route_source: Recipient, _proxy_server_sub: Recipient, ) { @@ -1624,6 +1771,60 @@ 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] fn proxy_server_receives_http_request_with_new_stream_key_from_dispatcher_then_sends_cores_package_to_hopper( ) { @@ -1640,8 +1841,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 (proxy_server_mock, _, proxy_server_recording_arc) = make_recorder(); let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); @@ -1650,7 +1851,7 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr, - reception_port: Some(HTTP_PORT), + reception_port_opt: Some(HTTP_PORT), sequence_number: Some(0), last_data: true, is_clandestine: false, @@ -1665,7 +1866,7 @@ mod tests { sequence_number: 0, last_data: true, }, - target_hostname: Some(String::from("nowhere.com")), + target_hostname: String::from("nowhere.com"), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: alias_cryptde.public_key().clone(), @@ -1682,7 +1883,7 @@ mod tests { thread::spawn(move || { let stream_key_factory = StreamKeyFactoryMock::new() .make_parameters(&make_parameters_arc) - .make_result(stream_key); + .make_result(stream_key.clone()); let system = System::new(test_name); let mut subject = ProxyServer::new( CRYPTDE_PAIR.clone(), @@ -1704,6 +1905,13 @@ mod tests { subject_addr.try_send(msg_from_dispatcher).unwrap(); + subject_addr + .try_send(AssertionsMessage { + assertions: Box::new(move |proxy_server: &mut ProxyServer| { + assert!(proxy_server.stream_info.contains_key(&stream_key)); + }), + }) + .unwrap(); system.run(); }); @@ -1720,13 +1928,16 @@ mod tests { let record = recording.get_record::(0); assert_eq!( record, - &RouteQueryMessage::data_indefinite_route_request(Some("nowhere.com".to_string()), 47) + &RouteQueryMessage::data_indefinite_route_request( + Host::new("nowhere.com", HTTP_PORT), + 47 + ) ); let recording = proxy_server_recording_arc.lock().unwrap(); assert_eq!(recording.len(), 0); TestLogHandler::new().exists_log_containing( - &format!("DEBUG: {test_name}: Found a new route for hostname: Some(\"nowhere.com\") - stream key: {stream_key} retries left: 3") + &format!("DEBUG: {test_name}: Found a new route for hostname: \"nowhere.com\" - stream key: {stream_key} retries left: 3") ); } @@ -1743,18 +1954,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: Some(8443), + reception_port_opt: Some(8443), sequence_number: Some(0), last_data: false, is_clandestine: false, @@ -1763,11 +1975,11 @@ mod tests { let tunnelled_msg = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr, - reception_port: Some(8443), + reception_port_opt: Some(8443), sequence_number: Some(0), last_data: false, is_clandestine: false, - data: b"client hello".to_vec(), + data: tunneled_data.clone(), }; let expected_tdm = TransmitDataMsg { endpoint: Endpoint::Socket(socket_addr), @@ -1778,12 +1990,12 @@ mod tests { let expected_payload = ClientRequestPayload_0v1 { stream_key: stream_key.clone(), sequenced_packet: SequencedPacket { - data: b"client hello".to_vec(), + data: tunneled_data, sequence_number: 0, last_data: false, }, - target_hostname: Some(String::from("realdomain.nu")), - target_port: 443, + target_hostname: String::from("realdomain.nu"), + target_port: TLS_PORT, protocol: ProxyProtocol::TLS, originator_public_key: alias_cryptde.public_key().clone(), }; @@ -1800,7 +2012,7 @@ mod tests { thread::spawn(move || { let stream_key_factory = StreamKeyFactoryMock::new() .make_parameters(&make_parameters_arc_thread) - .make_result(stream_key); + .make_result(stream_key.clone()); let system = System::new( "proxy_server_receives_connect_responds_with_ok_and_stores_stream_key_and_hostname", ); @@ -1822,6 +2034,13 @@ mod tests { subject_addr.try_send(msg_from_dispatcher).unwrap(); subject_addr.try_send(tunnelled_msg).unwrap(); + subject_addr + .try_send(AssertionsMessage { + assertions: Box::new(move |proxy_server: &mut ProxyServer| { + assert!(proxy_server.stream_info.contains_key(&stream_key)); + }), + }) + .unwrap(); system.run(); }); @@ -1844,8 +2063,8 @@ mod tests { assert_eq!( neighborhood_record, &RouteQueryMessage::data_indefinite_route_request( - Some("realdomain.nu".to_string()), - 12 + Host::new("realdomain.nu", TLS_PORT), + 68 ) ); } @@ -1868,23 +2087,29 @@ mod tests { subject .keys_and_addrs .insert(stream_key.clone(), socket_addr.clone()); - - 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"; + subject + .stream_info + .insert(stream_key.clone(), StreamInfoBuilder::new().build()); + 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", HTTP_PORT), + }) + .build(), + ); + let subject_addr: Addr = subject.start(); + let http_request = b"CONNECT https://realdomain.nu:443 HTTP/1.1\r\nHost: https://bunkjunk.wrong:443\r\n\r\n"; let request_data = http_request.to_vec(); let inbound_client_data = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr, - reception_port: Some(443), + reception_port_opt: Some(443), last_data: false, is_clandestine: false, sequence_number: Some(0), @@ -1936,7 +2161,7 @@ mod tests { let (dispatcher_mock, _dispatcher_awaiter, dispatcher_recording_arc) = make_recorder(); let neighborhood_mock = neighborhood_mock.route_query_response(Some( - zero_hop_route_response(&cryptde.public_key(), cryptde), + zero_hop_route_response(&cryptde.public_key(), cryptde, false), )); let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); @@ -1945,7 +2170,7 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port: Some(8443), + reception_port_opt: Some(8443), sequence_number: Some(0), last_data: false, is_clandestine: false, @@ -2007,7 +2232,7 @@ mod tests { let (dispatcher_mock, _dispatcher_awaiter, dispatcher_recording_arc) = make_recorder(); let neighborhood_mock = neighborhood_mock.route_query_response(Some( - zero_hop_route_response(&cryptde.public_key(), cryptde), + zero_hop_route_response(&cryptde.public_key(), cryptde, false), )); let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); @@ -2016,7 +2241,7 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port: Some(8443), + reception_port_opt: Some(8443), sequence_number: Some(0), last_data: false, is_clandestine: false, @@ -2082,7 +2307,7 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port: Some(HTTP_PORT), + reception_port_opt: Some(HTTP_PORT), sequence_number: Some(0), last_data: true, is_clandestine: false, @@ -2140,7 +2365,7 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port: Some(TLS_PORT), + reception_port_opt: Some(TLS_PORT), sequence_number: Some(0), last_data: true, is_clandestine: false, @@ -2192,7 +2417,8 @@ 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); + let expected_route = + zero_hop_route_response(main_cryptde.public_key(), main_cryptde, false); let stream_key = StreamKey::make_meaningless_stream_key(); let (hopper, hopper_awaiter, hopper_log_arc) = make_recorder(); let neighborhood = Recorder::new().route_query_response(Some(expected_route.clone())); @@ -2203,7 +2429,7 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port: Some(HTTP_PORT), + reception_port_opt: Some(HTTP_PORT), sequence_number: Some(0), last_data: true, is_clandestine: false, @@ -2213,7 +2439,12 @@ 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, socket_addr); + subject + .keys_and_addrs + .insert(stream_key.clone(), socket_addr); + subject + .stream_info + .insert(stream_key, StreamInfoBuilder::new().build()); let subject_addr: Addr = subject.start(); let peer_actors = peer_actors_builder() .dispatcher(dispatcher) @@ -2235,7 +2466,7 @@ mod tests { target_component: Component::ProxyClient, return_component_opt: Some(Component::ProxyServer), payload_size: 47, - hostname_opt: Some("nowhere.com".to_string()), + host: Host::new("nowhere.com", HTTP_PORT), } ); let dispatcher_recording = dispatcher_log_arc.lock().unwrap(); @@ -2251,8 +2482,8 @@ mod tests { &ClientRequestPayload_0v1 { stream_key, sequenced_packet: SequencedPacket::new(expected_data, 0, true), - target_hostname: Some("nowhere.com".to_string()), - target_port: 80, + target_hostname: "nowhere.com".to_string(), + target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: alias_cryptde.public_key().clone(), } @@ -2271,28 +2502,35 @@ 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); + let expected_route = zero_hop_route_response(main_cryptde.public_key(), main_cryptde, true); + let expected_route_inner = expected_route.clone(); let stream_key = StreamKey::make_meaningless_stream_key(); let (hopper, hopper_awaiter, hopper_log_arc) = make_recorder(); let neighborhood = Recorder::new().route_query_response(Some(expected_route.clone())); - let neighborhood_log_arc = neighborhood.get_recording(); let (dispatcher, _, dispatcher_log_arc) = make_recorder(); thread::spawn(move || { let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port: Some(TLS_PORT), + reception_port_opt: Some(TLS_PORT), sequence_number: Some(0), last_data: true, is_clandestine: false, data: expected_data_inner, }; - let stream_key_factory = StreamKeyFactoryMock::new(); // can't make any stream keys; shouldn't have to + let stream_key_factory = StreamKeyFactoryMock::new().make_result(stream_key.clone()); let system = System::new("proxy_server_receives_tls_request_with_no_consuming_wallet_in_zero_hop_mode_and_handles_normally"); let mut subject = ProxyServer::new(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) @@ -2306,17 +2544,6 @@ mod tests { system.run(); }); hopper_awaiter.await_message_count(1); - let neighborhood_recording = neighborhood_log_arc.lock().unwrap(); - assert_eq!( - neighborhood_recording.get_record::(0), - &RouteQueryMessage { - target_key_opt: None, - target_component: Component::ProxyClient, - return_component_opt: Some(Component::ProxyServer), - payload_size: 16, - hostname_opt: None, - } - ); let dispatcher_recording = dispatcher_log_arc.lock().unwrap(); assert!(dispatcher_recording.is_empty()); let hopper_recording = hopper_log_arc.lock().unwrap(); @@ -2330,8 +2557,8 @@ mod tests { &ClientRequestPayload_0v1 { stream_key, sequenced_packet: SequencedPacket::new(expected_data, 0, true), - target_hostname: None, - target_port: 443, + target_hostname: "booga.com".to_string(), + target_port: TLS_PORT, protocol: ProxyProtocol::TLS, originator_public_key: alias_cryptde.public_key().clone(), } @@ -2357,8 +2584,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(); @@ -2366,7 +2593,7 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port: Some(HTTP_PORT), + reception_port_opt: Some(HTTP_PORT), sequence_number: Some(0), last_data: true, is_clandestine: false, @@ -2381,7 +2608,7 @@ mod tests { sequence_number: 0, last_data: true, }, - target_hostname: Some(String::from("nowhere.com")), + target_hostname: String::from("nowhere.com"), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: alias_cryptde.public_key().clone(), @@ -2405,6 +2632,9 @@ mod tests { ); subject.stream_key_factory = Box::new(stream_key_factory); subject.keys_and_addrs.insert(stream_key, socket_addr); + subject + .stream_info + .insert(stream_key.clone(), StreamInfoBuilder::new().build()); let subject_addr: Addr = subject.start(); let peer_actors = peer_actors_builder() .hopper(hopper_mock) @@ -2456,7 +2686,6 @@ mod tests { ), main_cryptde, Some(consuming_wallet), - 1234, Some(TEST_DEFAULT_CHAIN.rec().contract), ) .unwrap(); @@ -2476,8 +2705,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(); @@ -2485,7 +2714,7 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port: Some(HTTP_PORT), + reception_port_opt: Some(HTTP_PORT), sequence_number: Some(0), last_data: true, is_clandestine: false, @@ -2499,7 +2728,7 @@ mod tests { sequence_number: 0, last_data: true, }, - target_hostname: Some(String::from("nowhere.com")), + target_hostname: String::from("nowhere.com"), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: alias_cryptde.public_key().clone(), @@ -2542,7 +2771,10 @@ mod tests { let record = recording.get_record::(0); assert_eq!( record, - &RouteQueryMessage::data_indefinite_route_request(Some("nowhere.com".to_string()), 47) + &RouteQueryMessage::data_indefinite_route_request( + Host::new("nowhere.com", HTTP_PORT), + 47 + ) ); } @@ -2560,8 +2792,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 = @@ -2572,7 +2804,7 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port: Some(HTTP_PORT), + reception_port_opt: Some(HTTP_PORT), sequence_number: Some(0), last_data: true, is_clandestine: false, @@ -2632,7 +2864,7 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port: Some(HTTP_PORT), + reception_port_opt: Some(HTTP_PORT), sequence_number: Some(0), last_data: true, is_clandestine: false, @@ -2684,7 +2916,7 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port: Some(HTTP_PORT), + reception_port_opt: Some(HTTP_PORT), sequence_number: Some(0), last_data: true, is_clandestine: false, @@ -2719,13 +2951,15 @@ 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_with_rrid = route.clone(); let route_query_response = RouteQueryResponse { - route: Route { hops: vec![] }, + route, 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(); @@ -2733,8 +2967,8 @@ mod tests { let expected_data = http_request.to_vec(); let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), - client_addr: socket_addr.clone(), - reception_port: Some(HTTP_PORT), + client_addr: socket_addr, + reception_port_opt: Some(HTTP_PORT), sequence_number: Some(0), last_data: true, is_clandestine: false, @@ -2747,14 +2981,14 @@ mod tests { sequence_number: 0, last_data: true, }, - target_hostname: Some(String::from("nowhere.com")), + target_hostname: String::from("nowhere.com"), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: alias_cryptde.public_key().clone(), }; let expected_pkg = IncipientCoresPackage::new( main_cryptde, - Route { hops: vec![] }, + route_with_rrid, expected_payload.into(), &destination_key, ) @@ -2772,8 +3006,12 @@ mod tests { ); subject.stream_key_factory = Box::new(stream_key_factory); subject - .stream_key_routes - .insert(stream_key, route_query_response); + .keys_and_addrs + .insert(stream_key.clone(), socket_addr); + subject.stream_info.insert( + stream_key, + StreamInfoBuilder::new().route(route_query_response).build(), + ); let subject_addr: Addr = subject.start(); let peer_actors = peer_actors_builder().hopper(hopper_mock).build(); subject_addr.try_send(BindMessage { peer_actors }).unwrap(); @@ -2793,57 +3031,89 @@ 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 exit_earning_wallet = make_wallet("exit earning wallet"); - let route_1_earning_wallet = make_wallet("route 1 earning wallet"); - let route_2_earning_wallet = make_wallet("route 2 earning wallet"); + let routing_node_1_public_key = PublicKey::new(&[1]); + let routing_node_2_public_key = PublicKey::new(&[2]); + let exit_node_public_key = PublicKey::new(&[3]); + let key_bytes = b"__originating consuming wallet__"; + let keypair = Bip32EncryptionKeyProvider::from_raw_secret(key_bytes).unwrap(); + let originating_consuming_wallet = Wallet::from(keypair); + let routing_node_1_earning_wallet = make_wallet("route 1 earning wallet"); + let routing_node_2_earning_wallet = make_wallet("route 2 earning wallet"); + let exit_node_earning_wallet = make_wallet("exit earning wallet"); + let routing_node_1_rate_pack = rate_pack(101); + let routing_node_2_rate_pack = rate_pack(102); + let exit_node_rate_pack = rate_pack(103); let http_request = b"GET /index.html HTTP/1.1\r\nHost: nowhere.com\r\n\r\n"; let (accountant_mock, _, accountant_recording_arc) = make_recorder(); let (hopper_mock, _, hopper_recording_arc) = make_recorder(); let (proxy_server_mock, _, proxy_server_recording_arc) = make_recorder(); - let routing_node_1_rate_pack = rate_pack(101); - let routing_node_2_rate_pack = rate_pack(102); - let exit_node_rate_pack = rate_pack(103); + let over_route_segment = RouteSegment::new( + vec![ + &cryptde.public_key(), + &routing_node_1_public_key, + &routing_node_2_public_key, + &exit_node_public_key, + ], + Component::ProxyClient, + ); + let back_route_segment = RouteSegment::new( + vec![ + &exit_node_public_key, + &routing_node_2_public_key, + &routing_node_1_public_key, + &cryptde.public_key(), + ], + Component::ProxyServer, + ); + let route = Route::round_trip( + over_route_segment, + back_route_segment, + cryptde, + Some(originating_consuming_wallet), + Some(TEST_DEFAULT_CHAIN.rec().contract), + ) + .unwrap(); let route_query_response = RouteQueryResponse { - route: make_meaningless_route(&CRYPTDE_PAIR), + route, expected_services: ExpectedServices::RoundTrip( vec![ ExpectedService::Nothing, ExpectedService::Routing( - PublicKey::new(&[1]), - route_1_earning_wallet.clone(), - routing_node_1_rate_pack, + routing_node_1_public_key.clone(), + routing_node_1_earning_wallet.clone(), + routing_node_1_rate_pack.clone(), ), ExpectedService::Routing( - PublicKey::new(&[2]), - route_2_earning_wallet.clone(), - routing_node_2_rate_pack, + routing_node_2_public_key.clone(), + routing_node_2_earning_wallet.clone(), + routing_node_2_rate_pack.clone(), ), ExpectedService::Exit( - PublicKey::new(&[3]), - exit_earning_wallet.clone(), - exit_node_rate_pack, + exit_node_public_key.clone(), + exit_node_earning_wallet.clone(), + exit_node_rate_pack.clone(), ), ], vec![ ExpectedService::Exit( - PublicKey::new(&[3]), - make_wallet("some wallet 1"), - rate_pack(104), + exit_node_public_key.clone(), + exit_node_earning_wallet.clone(), + exit_node_rate_pack, ), ExpectedService::Routing( - PublicKey::new(&[2]), - make_wallet("some wallet 2"), - rate_pack(105), + routing_node_2_public_key.clone(), + routing_node_2_earning_wallet.clone(), + routing_node_2_rate_pack, ), ExpectedService::Routing( - PublicKey::new(&[1]), - make_wallet("some wallet 3"), - rate_pack(106), + routing_node_1_public_key.clone(), + routing_node_1_earning_wallet.clone(), + routing_node_1_rate_pack, ), ExpectedService::Nothing, ], - 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(); @@ -2859,7 +3129,7 @@ mod tests { let payload = ClientRequestPayload_0v1 { stream_key, sequenced_packet: SequencedPacket::new(expected_data, 0, false), - target_hostname: Some("nowhere.com".to_string()), + target_hostname: "nowhere.com".to_string(), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: PublicKey::new(b"originator_public_key"), @@ -2878,17 +3148,35 @@ mod tests { retire_stream_key_sub_opt: None, }; - let result = ProxyServer::try_transmit_to_hopper( - args, - peer_actors.proxy_server.add_return_route, - route_query_response, - ); + let result = ProxyServer::try_transmit_to_hopper(args, route_query_response); System::current().stop(); system.run(); let recording = hopper_recording_arc.lock().unwrap(); - let record = recording.get_record::(0); + let mut record = recording.get_record::(0).clone(); let payload_enc_length = record.payload.len(); + let _ = record.route.shift(cryptde); + let _ = record.route.shift(&CryptDENull::from( + &routing_node_1_public_key, + TEST_DEFAULT_CHAIN, + )); + let _ = record.route.shift(&CryptDENull::from( + &routing_node_2_public_key, + TEST_DEFAULT_CHAIN, + )); + let _ = record.route.shift(&CryptDENull::from( + &exit_node_public_key, + TEST_DEFAULT_CHAIN, + )); + let _ = record.route.shift(&CryptDENull::from( + &routing_node_2_public_key, + TEST_DEFAULT_CHAIN, + )); + let _ = record.route.shift(&CryptDENull::from( + &routing_node_1_public_key, + TEST_DEFAULT_CHAIN, + )); + let _ = record.route.shift(cryptde); let recording = accountant_recording_arc.lock().unwrap(); let record = recording.get_record::(0); assert_eq!(recording.len(), 1); @@ -2897,7 +3185,7 @@ mod tests { &ReportServicesConsumedMessage { timestamp: now, exit: ExitServiceConsumed { - earning_wallet: exit_earning_wallet, + earning_wallet: exit_node_earning_wallet, payload_size: exit_payload_size, service_rate: exit_node_rate_pack.exit_service_rate, byte_rate: exit_node_rate_pack.exit_byte_rate @@ -2905,12 +3193,12 @@ mod tests { routing_payload_size: payload_enc_length, routing: vec![ RoutingServiceConsumed { - earning_wallet: route_1_earning_wallet, + earning_wallet: routing_node_1_earning_wallet, service_rate: routing_node_1_rate_pack.routing_service_rate, byte_rate: routing_node_1_rate_pack.routing_byte_rate, }, RoutingServiceConsumed { - earning_wallet: route_2_earning_wallet, + earning_wallet: routing_node_2_earning_wallet, service_rate: routing_node_2_rate_pack.routing_service_rate, byte_rate: routing_node_2_rate_pack.routing_byte_rate, } @@ -2918,8 +3206,7 @@ mod tests { } ); let recording = proxy_server_recording_arc.lock().unwrap(); - let _ = recording.get_record::(0); // don't care about this, other than type - assert_eq!(recording.len(), 1); // No StreamShutdownMsg: that's the important thing + assert_eq!(recording.len(), 0); // No StreamShutdownMsg: that's the important thing assert_eq!(result, Ok(())); } @@ -2933,8 +3220,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(); @@ -2947,7 +3234,7 @@ mod tests { let payload = ClientRequestPayload_0v1 { stream_key, sequenced_packet: SequencedPacket::new(expected_data, 0, false), - target_hostname: Some("nowhere.com".to_string()), + target_hostname: "nowhere.com".to_string(), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: PublicKey::new(b"originator_public_key"), @@ -2966,26 +3253,12 @@ mod tests { retire_stream_key_sub_opt: Some(peer_actors.proxy_server.stream_shutdown_sub), }; - let result = ProxyServer::try_transmit_to_hopper( - args, - peer_actors.proxy_server.add_return_route, - route_query_response, - ); + let result = ProxyServer::try_transmit_to_hopper(args, route_query_response); System::current().stop(); system.run(); let recording = proxy_server_recording_arc.lock().unwrap(); - let record = recording.get_record::(0); - assert_eq!( - record, - &AddReturnRouteMessage { - return_route_id: 0, - expected_services: vec![ExpectedService::Nothing], - protocol: ProxyProtocol::HTTP, - hostname_opt: Some("nowhere.com".to_string()) - } - ); - let record = recording.get_record::(1); + let record = recording.get_record::(0); assert_eq!( record, &StreamShutdownMsg { @@ -3007,7 +3280,8 @@ mod tests { let http_request = b"GET /index.html HTTP/1.1\r\nHost: nowhere.com\r\n\r\n"; let (accountant_mock, accountant_awaiter, _) = make_recorder(); let (neighborhood_mock, _, _) = make_recorder(); - let mut route_query_response = zero_hop_route_response(&cryptde.public_key(), cryptde); + let mut route_query_response = + zero_hop_route_response(&cryptde.public_key(), cryptde, false); route_query_response.expected_services = ExpectedServices::RoundTrip( vec![ExpectedService::Exit( cryptde.public_key().clone(), @@ -3015,7 +3289,6 @@ mod tests { rate_pack(3), )], vec![], - 0, ); let neighborhood_mock = neighborhood_mock.route_query_response(Some(route_query_response.clone())); @@ -3025,7 +3298,7 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port: Some(HTTP_PORT), + reception_port_opt: Some(HTTP_PORT), sequence_number: Some(0), last_data: true, is_clandestine: false, @@ -3061,29 +3334,37 @@ mod tests { #[test] #[should_panic( - expected = "AddRouteResultMessage Handler: stream key: AAAAAAAAAAAAAAAAAAAAAAAAAAA not found within dns_failure_retries" + expected = "AddRouteResultMessage Handler: dns_failure_retry_opt is None for stream key" )] - 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( + 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( 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: StreamKey::make_meaningless_stream_key(), + stream_key, result: Err("Some Error".to_string()), }) .unwrap(); + System::current().stop(); system.run(); + TestLogHandler::new().exists_log_containing(&format!("ERROR: ProxyServer: No dns_failure_retry found for stream key {stream_key} while handling AddRouteResultMessage")); } #[test] @@ -3144,7 +3425,7 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port: Some(HTTP_PORT), + reception_port_opt: Some(HTTP_PORT), sequence_number: Some(0), last_data: true, data: expected_data.clone(), @@ -3189,10 +3470,13 @@ mod tests { let record = recording.get_record::(0); assert_eq!( record, - &RouteQueryMessage::data_indefinite_route_request(Some("nowhere.com".to_string()), 47) + &RouteQueryMessage::data_indefinite_route_request( + Host::new("nowhere.com", HTTP_PORT), + 47 + ) ); TestLogHandler::new().exists_log_containing(&format!( - "WARN: {test_name}: No route found for hostname: Some(\"nowhere.com\") - stream key {stream_key} - retries left: 3 - AddRouteResultMessage Error: Failed to find route to nowhere.com" + "WARN: {test_name}: No route found for hostname: \"nowhere.com\" - stream key {stream_key} - retries left: 3 - AddRouteResultMessage Error: Failed to find route to nowhere.com" )); } @@ -3223,6 +3507,7 @@ mod tests { rate_pack(103), ), ]), + host: Host::new("booga.com", HTTP_PORT), }; let payload = ClientRequestPayload_0v1 { stream_key: StreamKey::make_meaningless_stream_key(), @@ -3231,7 +3516,7 @@ mod tests { sequence_number: 0, last_data: false, }, - target_hostname: None, + target_hostname: "booga.com".to_string(), target_port: 0, protocol: ProxyProtocol::TLS, originator_public_key: cryptde.public_key().clone(), @@ -3251,11 +3536,7 @@ mod tests { retire_stream_key_sub_opt: None, }; - let _result = ProxyServer::try_transmit_to_hopper( - args, - peer_actors.proxy_server.add_return_route, - route_result, - ); + let _result = ProxyServer::try_transmit_to_hopper(args, route_result); } #[test] @@ -3269,25 +3550,20 @@ mod tests { false, false, ); - let add_return_route_message = AddReturnRouteMessage { - return_route_id: 0, - expected_services: vec![ - ExpectedService::Routing( - PublicKey::from(&b"key"[..]), - make_wallet("some wallet"), - rate_pack(10), - ), - ExpectedService::Exit( - PublicKey::from(&b"exit_key"[..]), - make_wallet("exit"), - rate_pack(11), - ), - ], - protocol: ProxyProtocol::HTTP, - hostname_opt: None, - }; + let expected_services = vec![ + ExpectedService::Routing( + PublicKey::from(&b"key"[..]), + make_wallet("some wallet"), + rate_pack(10), + ), + ExpectedService::Exit( + PublicKey::from(&b"exit_key"[..]), + make_wallet("exit"), + rate_pack(11), + ), + ]; - subject.report_response_services_consumed(&add_return_route_message, 1234, 3456); + subject.report_response_services_consumed(&expected_services, 1234, 3456); } #[test] @@ -3305,11 +3581,11 @@ mod tests { RouteSegment::new(vec![public_key, public_key], Component::ProxyServer), cryptde, None, - 1234, None, ) .unwrap(), - expected_services: ExpectedServices::RoundTrip(vec![], vec![], 1234), + expected_services: ExpectedServices::RoundTrip(vec![], vec![]), + host: Host::new("booga.com", HTTP_PORT), }; let neighborhood_mock = neighborhood_mock.route_query_response(Some(route_query_response)); let dispatcher = Recorder::new(); @@ -3320,7 +3596,7 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port: Some(HTTP_PORT), + reception_port_opt: Some(HTTP_PORT), sequence_number: Some(0), last_data: true, data: expected_data.clone(), @@ -3366,35 +3642,19 @@ mod tests { let record = recording.get_record::(0); assert_eq!( record, - &RouteQueryMessage::data_indefinite_route_request(Some("nowhere.com".to_string()), 47) + &RouteQueryMessage::data_indefinite_route_request( + Host::new("nowhere.com", HTTP_PORT), + 47 + ) ); TestLogHandler::new().exists_log_containing(&format!( - "WARN: {test_name}: No route found for hostname: Some(\"nowhere.com\") - stream key {stream_key} - retries left: 3 - AddRouteResultMessage Error: Failed to find route to nowhere.com" + "WARN: {test_name}: No route found for hostname: \"nowhere.com\" - stream key {stream_key} - retries left: 3 - AddRouteResultMessage Error: Failed to find route to nowhere.com" )); } #[test] fn proxy_server_receives_tls_client_hello_from_dispatcher_then_sends_cores_package_to_hopper() { - let tls_request = &[ - 0x16, // content_type: Handshake - 0x00, 0x00, 0x00, 0x00, // version, length: don't care - 0x01, // handshake_type: ClientHello - 0x00, 0x00, 0x00, 0x00, 0x00, // length, version: don't care - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, // random: don't care - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, // random: don't care - 0x00, // session_id_length - 0x00, 0x00, // cipher_suites_length - 0x00, // compression_methods_length - 0x00, 0x13, // extensions_length - 0x00, 0x00, // extension_type: server_name - 0x00, 0x0F, // extension_length - 0x00, 0x0D, // server_name_list_length - 0x00, // server_name_type - 0x00, 0x0A, // server_name_length - b's', b'e', b'r', b'v', b'e', b'r', b'.', b'c', b'o', b'm', // server_name - ]; + let tls_request = make_server_com_client_hello(); let main_cryptde = CRYPTDE_PAIR.main.as_ref(); let alias_cryptde = CRYPTDE_PAIR.alias.as_ref(); let hopper_mock = Recorder::new(); @@ -3406,22 +3666,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.to_vec(); + let expected_data = tls_request.clone(); let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port: Some(TLS_PORT), + reception_port_opt: Some(TLS_PORT), sequence_number: Some(0), last_data: false, is_clandestine: false, data: expected_data.clone(), }; - let expected_tls_request = PlainData::new(tls_request); + let expected_tls_request = PlainData::new(tls_request.as_slice()); let route = Route { hops: vec![] }; let expected_payload = ClientRequestPayload_0v1 { stream_key: stream_key.clone(), @@ -3430,7 +3690,7 @@ mod tests { sequence_number: 0, last_data: false, }, - target_hostname: Some(String::from("server.com")), + target_hostname: String::from("server.com"), target_port: TLS_PORT, protocol: ProxyProtocol::TLS, originator_public_key: alias_cryptde.public_key().clone(), @@ -3491,8 +3751,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(); @@ -3500,7 +3760,7 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port: Some(TLS_PORT), + reception_port_opt: Some(TLS_PORT), sequence_number: Some(0), last_data: false, is_clandestine: false, @@ -3515,7 +3775,7 @@ mod tests { sequence_number: 0, last_data: false, }, - target_hostname: None, + target_hostname: "booga.com".to_string(), target_port: TLS_PORT, protocol: ProxyProtocol::TLS, originator_public_key: alias_cryptde.public_key().clone(), @@ -3537,6 +3797,22 @@ 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() @@ -3549,7 +3825,6 @@ mod tests { system.run(); }); - hopper_awaiter.await_message_count(1); let recording = hopper_log_arc.lock().unwrap(); let record = recording.get_record::(0); @@ -3575,8 +3850,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); @@ -3584,7 +3859,7 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr, - reception_port: Some(TLS_PORT), + reception_port_opt: Some(TLS_PORT), sequence_number: Some(0), last_data: true, is_clandestine: false, @@ -3599,7 +3874,7 @@ mod tests { sequence_number: 0, last_data: true, }, - target_hostname: None, + target_hostname: "booga.com".to_string(), target_port: TLS_PORT, protocol: ProxyProtocol::TLS, originator_public_key: alias_cryptde.public_key().clone(), @@ -3620,6 +3895,20 @@ 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() @@ -3673,7 +3962,7 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port: Some(TLS_PORT), + reception_port_opt: Some(TLS_PORT), sequence_number: Some(0), last_data: true, data: tls_request, @@ -3734,17 +4023,22 @@ mod tests { subject .keys_and_addrs .insert(stream_key.clone(), socket_addr.clone()); - subject.route_ids_to_return_routes.insert( - 1234, - AddReturnRouteMessage { - return_route_id: 1234, - expected_services: vec![ExpectedService::Nothing], - protocol: ProxyProtocol::TLS, - hostname_opt: None, - }, + subject.stream_info.insert( + stream_key.clone(), + StreamInfoBuilder::new() + .route(RouteQueryResponse { + route: Route { hops: vec![] }, + expected_services: ExpectedServices::RoundTrip( + vec![], + vec![ExpectedService::Nothing], + ), + host: Host::new("booga.com", TLS_PORT), + }) + .protocol(ProxyProtocol::TLS) + .build(), ); let subject_addr: Addr = subject.start(); - let remaining_route = return_route_with_id(cryptde, 1234); + let remaining_route = return_route_with_id(cryptde, 0); let client_response_payload = ClientResponsePayload_0v1 { stream_key: stream_key.clone(), sequenced_packet: SequencedPacket { @@ -3780,7 +4074,7 @@ mod tests { stream_key )); tlh.exists_log_containing(&format!( - "WARN: {test_name}: Discarding 16-byte packet 12345678 from an unrecognized stream key: {:?}", + "ERROR: {test_name}: Can't pay for return services consumed: received response with unrecognized stream key {:?}. Ignoring", stream_key )); } @@ -3819,24 +4113,17 @@ mod tests { subject .keys_and_addrs .insert(stream_key.clone(), socket_addr.clone()); - subject.stream_key_routes.insert( + subject.stream_info.insert( stream_key.clone(), - RouteQueryResponse { - route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip(vec![], vec![], 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, - }, + 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(), ); let client_response_payload = ClientResponsePayload_0v1 { stream_key: stream_key.clone(), @@ -3849,7 +4136,7 @@ mod tests { ExpiredCoresPackage::new( SocketAddr::from_str("1.2.3.4:1234").unwrap(), Some(make_wallet("irrelevant")), - return_route_with_id(cryptde, 1234), + return_route_with_id(cryptde, 0), client_response_payload.into(), 0, ); @@ -3857,8 +4144,7 @@ mod tests { subject.handle_client_response_payload(expired_cores_package); assert!(subject.keys_and_addrs.is_empty()); - assert!(subject.stream_key_routes.is_empty()); - assert!(subject.tunneled_hosts.is_empty()); + assert!(subject.stream_info.get(&stream_key).is_none()); } #[test] @@ -3926,24 +4212,17 @@ mod tests { subject .keys_and_addrs .insert(stream_key.clone(), msg.peer_addr.clone()); - subject.stream_key_routes.insert( + subject.stream_info.insert( stream_key.clone(), - RouteQueryResponse { - route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip(vec![], vec![], 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, - }, + 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(), ); let proxy_server_addr = subject.start(); let schedule_stream_key_purge_sub = proxy_server_addr.clone().recipient(); @@ -3961,18 +4240,14 @@ mod tests { .unwrap(); let pre_purge_assertions = AssertionsMessage { assertions: Box::new(move |proxy_server: &mut ProxyServer| { - let purge_timestamp = proxy_server - .stream_key_ttl - .get(&stream_key) - .unwrap() - .clone(); + let stream_info = proxy_server.stream_info.get(&stream_key).unwrap(); + let purge_timestamp = stream_info.time_to_live_opt.unwrap(); assert!( time_before_sending_package <= purge_timestamp && purge_timestamp <= time_after_sending_package ); + assert!(!proxy_server.stream_info.get(&stream_key).is_none()); assert!(!proxy_server.keys_and_addrs.is_empty()); - assert!(!proxy_server.stream_key_routes.is_empty()); - assert!(!proxy_server.tunneled_hosts.is_empty()); TestLogHandler::new().exists_log_containing(&format!( "DEBUG: {test_name}: Client closed stream referenced by stream key {:?}, \ which was tunneling to the host \"hostname\". \ @@ -3990,9 +4265,7 @@ mod tests { let post_purge_assertions = AssertionsMessage { assertions: Box::new(move |proxy_server: &mut ProxyServer| { assert!(proxy_server.keys_and_addrs.is_empty()); - assert!(proxy_server.stream_key_routes.is_empty()); - assert!(proxy_server.tunneled_hosts.is_empty()); - assert!(proxy_server.stream_key_ttl.is_empty()); + assert!(proxy_server.stream_info.get(&stream_key).is_none()); TestLogHandler::new().exists_log_containing(&format!( "DEBUG: {test_name}: Retiring stream key {:?}", stream_key @@ -4028,16 +4301,6 @@ 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 { @@ -4046,22 +4309,26 @@ mod tests { exit_byte_rate: 100, exit_service_rate: 60000, }; - 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_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 - .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(); @@ -4079,7 +4346,7 @@ mod tests { ExpiredCoresPackage::new( SocketAddr::from_str("1.2.3.4:1234").unwrap(), Some(make_wallet("irrelevant")), - return_route_with_id(cryptde, 1234), + return_route_with_id(cryptde, 0), client_response_payload.into(), 5432, ); @@ -4137,63 +4404,35 @@ mod tests { let rate_pack_d = rate_pack(101); let rate_pack_e = rate_pack(102); let rate_pack_f = rate_pack(103); - subject.route_ids_to_return_routes.insert( - 1234, - AddReturnRouteMessage { - return_route_id: 1234, - expected_services: vec![ - ExpectedService::Exit( - irrelevant_public_key.clone(), - incoming_route_d_wallet.clone(), - rate_pack_d, - ), - ExpectedService::Routing( - irrelevant_public_key.clone(), - incoming_route_e_wallet.clone(), - rate_pack_e, - ), - ExpectedService::Routing( - irrelevant_public_key.clone(), - incoming_route_f_wallet.clone(), - rate_pack_f, - ), - ExpectedService::Nothing, - ], - protocol: ProxyProtocol::TLS, - hostname_opt: None, - }, - ); - let incoming_route_g_wallet = make_wallet("G Earning"); - let incoming_route_h_wallet = make_wallet("H Earning"); - let incoming_route_i_wallet = make_wallet("I Earning"); - let rate_pack_g = rate_pack(104); - let rate_pack_h = rate_pack(105); - let rate_pack_i = rate_pack(106); - subject.route_ids_to_return_routes.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, + 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, + ], ), - ExpectedService::Nothing, - ], - protocol: ProxyProtocol::TLS, - hostname_opt: None, - }, + host: Host::new("booga.com", HTTP_PORT), + }) + .build(), ); let subject_addr: Addr = subject.start(); let first_client_response_payload = ClientResponsePayload_0v1 { @@ -4209,7 +4448,7 @@ mod tests { ExpiredCoresPackage::new( SocketAddr::from_str("1.2.3.4:1234").unwrap(), Some(make_wallet("irrelevant")), - return_route_with_id(cryptde, 1234), + return_route_with_id(cryptde, 0), first_client_response_payload.into(), 0, ); @@ -4265,7 +4504,7 @@ mod tests { &ReportServicesConsumedMessage { timestamp: first_report_timestamp, exit: ExitServiceConsumed { - earning_wallet: incoming_route_d_wallet, + earning_wallet: incoming_route_d_wallet.clone(), payload_size: first_exit_size, service_rate: rate_pack_d.exit_service_rate, byte_rate: rate_pack_d.exit_byte_rate @@ -4273,12 +4512,12 @@ mod tests { routing_payload_size: routing_size, routing: vec![ RoutingServiceConsumed { - earning_wallet: incoming_route_e_wallet, + earning_wallet: incoming_route_e_wallet.clone(), service_rate: rate_pack_e.routing_service_rate, byte_rate: rate_pack_e.routing_byte_rate }, RoutingServiceConsumed { - earning_wallet: incoming_route_f_wallet, + earning_wallet: incoming_route_f_wallet.clone(), service_rate: rate_pack_f.routing_service_rate, byte_rate: rate_pack_f.routing_byte_rate } @@ -4294,22 +4533,22 @@ mod tests { &ReportServicesConsumedMessage { timestamp: second_report_timestamp, exit: ExitServiceConsumed { - earning_wallet: incoming_route_g_wallet, + earning_wallet: incoming_route_d_wallet, payload_size: second_exit_size, - service_rate: rate_pack_g.exit_service_rate, - byte_rate: rate_pack_g.exit_byte_rate + service_rate: rate_pack_d.exit_service_rate, + byte_rate: rate_pack_d.exit_byte_rate }, routing_payload_size: routing_size, routing: vec![ RoutingServiceConsumed { - earning_wallet: incoming_route_h_wallet, - service_rate: rate_pack_h.routing_service_rate, - byte_rate: rate_pack_h.routing_byte_rate + earning_wallet: incoming_route_e_wallet, + service_rate: rate_pack_e.routing_service_rate, + byte_rate: rate_pack_e.routing_byte_rate }, RoutingServiceConsumed { - earning_wallet: incoming_route_i_wallet, - service_rate: rate_pack_i.routing_service_rate, - byte_rate: rate_pack_i.routing_byte_rate + earning_wallet: incoming_route_f_wallet, + service_rate: rate_pack_f.routing_service_rate, + byte_rate: rate_pack_f.routing_byte_rate } ] } @@ -4324,6 +4563,7 @@ mod tests { let test_name = "dns_retry_entry_is_removed_after_a_successful_client_response"; let system = System::new(test_name); let cryptde = CRYPTDE_PAIR.main.as_ref(); + let logger = Logger::new(test_name); let mut subject = ProxyServer::new( CRYPTDE_PAIR.clone(), true, @@ -4339,48 +4579,48 @@ 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.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, - ), - 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, + 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, + ], ), - ExpectedService::Nothing, - ], - protocol: ProxyProtocol::TLS, - hostname_opt: None, - }, + host: Host::new("booga.com", TLS_PORT), + }) + .protocol(ProxyProtocol::TLS) + .build(), ); let subject_addr: Addr = subject.start(); let first_client_response_payload = ClientResponsePayload_0v1 { @@ -4395,7 +4635,7 @@ mod tests { ExpiredCoresPackage::new( SocketAddr::from_str("1.2.3.4:1234").unwrap(), Some(make_wallet("irrelevant")), - return_route_with_id(cryptde, 1234), + return_route_with_id(cryptde, 0), first_client_response_payload.into(), 0, ); @@ -4407,14 +4647,16 @@ mod tests { subject_addr .try_send(AssertionsMessage { assertions: Box::new(move |proxy_server: &mut ProxyServer| { - let retry_opt = proxy_server.dns_failure_retries.get(&stream_key); - assert_eq!(retry_opt, None); + let retry_opt = &proxy_server + .stream_info(&stream_key_clone) + .unwrap() + .dns_failure_retry_opt; + assert!(retry_opt.is_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] @@ -4438,25 +4680,30 @@ mod tests { let incoming_route_e_wallet = make_wallet("E Earning"); let rate_pack_d = rate_pack(101); let rate_pack_e = rate_pack(102); - subject.route_ids_to_return_routes.insert( - 1234, - AddReturnRouteMessage { - return_route_id: 1234, - expected_services: vec![ - ExpectedService::Exit( - irrelevant_public_key.clone(), - incoming_route_d_wallet.clone(), - rate_pack_d, - ), - ExpectedService::Routing( - irrelevant_public_key.clone(), - incoming_route_e_wallet.clone(), - rate_pack_e, + 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, + ), + ], ), - ], - protocol: ProxyProtocol::TLS, - hostname_opt: None, - }, + host: Host::new("booga.com", TLS_PORT), + }) + .protocol(ProxyProtocol::TLS) + .build(), ); let subject_addr: Addr = subject.start(); let client_response_payload = ClientResponsePayload_0v1 { @@ -4472,7 +4719,7 @@ mod tests { ExpiredCoresPackage::new( SocketAddr::from_str("1.2.3.4:1234").unwrap(), Some(make_wallet("irrelevant")), - return_route_with_id(cryptde, 1234), + return_route_with_id(cryptde, 0), client_response_payload.into(), 0, ); @@ -4534,46 +4781,47 @@ 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; + let exit_public_key = PublicKey::from(&b"exit_key"[..]); + let exit_wallet = make_wallet("exit wallet"); subject .keys_and_addrs .insert(stream_key.clone(), socket_addr.clone()); - 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, + rate_pack(10), + )], + ), + host: Host::new("server.com", HTTP_PORT), + }) + .protocol(ProxyProtocol::HTTP) + .build(), + ); let subject_addr: Addr = subject.start(); let dns_resolve_failure = DnsResolveFailure_0v1::new(stream_key); let expired_cores_package: ExpiredCoresPackage = ExpiredCoresPackage::new( SocketAddr::from_str("1.2.3.4:1234").unwrap(), Some(make_wallet("irrelevant")), - return_route_with_id(cryptde, 1234), + return_route_with_id(cryptde, 0), 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(); @@ -4587,7 +4835,7 @@ mod tests { last_data: true, sequence_number: Some(0), data: ServerImpersonatorHttp {} - .dns_resolution_failure_response(Some("server.com".to_string()),), + .dns_resolution_failure_response("server.com".to_string()), }, *record ); @@ -4608,16 +4856,7 @@ 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()); @@ -4627,31 +4866,40 @@ mod tests { let rate_pack_d = rate_pack(101); let rate_pack_e = rate_pack(102); let rate_pack_f = rate_pack(103); - subject.route_ids_to_return_routes.insert( - 1234, - AddReturnRouteMessage { - return_route_id: 1234, - expected_services: vec![ - ExpectedService::Exit( - irrelevant_public_key.clone(), - incoming_route_d_wallet.clone(), - rate_pack_d, - ), - ExpectedService::Routing( - irrelevant_public_key.clone(), - incoming_route_e_wallet.clone(), - rate_pack_e, - ), - ExpectedService::Routing( - irrelevant_public_key.clone(), - incoming_route_f_wallet.clone(), - rate_pack_f, + 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, + ], ), - ExpectedService::Nothing, - ], - protocol: ProxyProtocol::TLS, - hostname_opt: Some("server.com".to_string()), - }, + host: Host::new("booga.com", TLS_PORT), + }) + .protocol(ProxyProtocol::TLS) + .build(), ); let subject_addr: Addr = subject.start(); let dns_resolve_failure_payload = DnsResolveFailure_0v1::new(stream_key); @@ -4659,7 +4907,7 @@ mod tests { ExpiredCoresPackage::new( SocketAddr::from_str("1.2.3.4:1234").unwrap(), Some(make_wallet("irrelevant")), - return_route_with_id(cryptde, 1234), + return_route_with_id(cryptde, 0), dns_resolve_failure_payload.into(), 0, ); @@ -4724,34 +4972,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.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()), - }, + 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(), ); let subject_addr: Addr = subject.start(); let dns_resolve_failure = DnsResolveFailure_0v1::new(stream_key); @@ -4759,7 +5007,7 @@ mod tests { ExpiredCoresPackage::new( SocketAddr::from_str("1.2.3.4:1234").unwrap(), Some(make_wallet("irrelevant")), - return_route_with_id(cryptde, 1234), + return_route_with_id(cryptde, 0), dns_resolve_failure.into(), 0, ); @@ -4789,79 +5037,8 @@ mod tests { } #[test] - fn handle_dns_resolve_failure_does_not_send_message_to_neighborhood_when_server_is_not_specified( + fn handle_dns_resolve_failure_logs_when_stream_key_is_found_in_stream_info_but_not_keys_and_addrs( ) { - 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(); @@ -4874,41 +5051,38 @@ mod tests { false, ); let stream_key = StreamKey::make_meaningless_stream_key(); - let return_route_id = 1234; + let return_route_id = 0; let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); - let 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.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()), - }, + 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(), ); 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(), + socket_addr, Some(make_wallet("irrelevant")), return_route_with_id(cryptde, return_route_id), dns_resolve_failure.into(), @@ -4950,35 +5124,35 @@ mod tests { false, ); let stream_key = StreamKey::make_meaningless_stream_key(); - let return_route_id = 1234; + let return_route_id = 0; let socket_addr = SocketAddr::from_str("1.2.3.4:5678").unwrap(); - let 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.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, - }, + 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(), ); let subject_addr: Addr = subject.start(); let dns_resolve_failure = DnsResolveFailure_0v1::new(stream_key); @@ -5003,12 +5177,10 @@ mod tests { System::current().stop(); system.run(); - TestLogHandler::new().exists_log_containing( - &format!( - "Discarding DnsResolveFailure message for from an unrecognized stream key {:?}", - stream_key - ) - ); + TestLogHandler::new().exists_log_containing(&format!( + "Discarding DnsResolveFailure message from an unrecognized stream key {:?}", + stream_key + )); } #[test] @@ -5033,47 +5205,38 @@ 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 - .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, - }, + 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(), ); 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), + return_route_with_id(cryptde, 0), dns_resolve_failure.into(), 0, ); @@ -5081,8 +5244,7 @@ mod tests { subject.handle_dns_resolve_failure(&expired_cores_package); assert!(subject.keys_and_addrs.is_empty()); - assert!(subject.stream_key_routes.is_empty()); - assert!(subject.tunneled_hosts.is_empty()); + assert!(subject.stream_info.get(&stream_key).is_none()); } #[test] @@ -5101,27 +5263,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.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()), - }, + 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(), ); let subject_addr: Addr = subject.start(); let dns_resolve_failure = DnsResolveFailure_0v1::new(stream_key); @@ -5129,7 +5291,7 @@ mod tests { ExpiredCoresPackage::new( SocketAddr::from_str("1.2.3.4:1234").unwrap(), Some(make_wallet("irrelevant")), - return_route_with_id(cryptde, 1234), + return_route_with_id(cryptde, 0), dns_resolve_failure.into(), 0, ); @@ -5162,7 +5324,7 @@ mod tests { last_data: true, sequence_number: Some(0), data: ServerImpersonatorHttp {} - .dns_resolution_failure_response(Some("server.com".to_string()),), + .dns_resolution_failure_response("server.com".to_string()), }, *record ); @@ -5170,7 +5332,9 @@ mod tests { #[test] fn handle_dns_resolve_failure_sent_request_retry() { - let system = System::new("test"); + let test_name = "handle_dns_resolve_failure_sent_request_retry"; + let system = System::new(test_name); + let logger = Logger::new(test_name); let resolve_message_params_arc = Arc::new(Mutex::new(vec![])); let (neighborhood_mock, _, _) = make_recorder(); let exit_public_key = PublicKey::from(&b"exit_key"[..]); @@ -5185,8 +5349,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)) @@ -5200,28 +5364,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.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()), - }, + 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(), ); let message_resolver = RouteQueryResponseResolverMock::default() .resolve_message_params(&resolve_message_params_arc); @@ -5236,7 +5400,7 @@ mod tests { ExpiredCoresPackage::new( SocketAddr::from_str("1.2.3.4:1234").unwrap(), Some(make_wallet("irrelevant")), - return_route_with_id(cryptde, 1234), + return_route_with_id(cryptde, 0), dns_resolve_failure.into(), 0, ); @@ -5250,7 +5414,12 @@ mod tests { subject_addr .try_send(AssertionsMessage { assertions: Box::new(move |proxy_server: &mut ProxyServer| { - let retry = proxy_server.dns_failure_retries.get(&stream_key).unwrap(); + let retry = proxy_server + .stream_info(&stream_key) + .unwrap() + .dns_failure_retry_opt + .as_ref() + .unwrap(); assert_eq!(retry.retries_left, 2); }), }) @@ -5275,10 +5444,10 @@ mod tests { } #[test] - fn handle_dns_resolve_failure_logs_error_when_there_is_no_entry_in_the_hashmap_for_the_stream_key( + fn handle_dns_resolve_failure_logs_error_when_there_is_no_dns_failure_retry_entry_for_the_stream_key( ) { init_test_logging(); - let test_name = "handle_dns_resolve_failure_logs_error_when_there_is_no_entry_in_the_hashmap_for_the_stream_key"; + let test_name = "handle_dns_resolve_failure_logs_error_when_there_is_no_dns_failure_retry_entry_for_the_stream_key"; let system = System::new(test_name); let exit_public_key = PublicKey::from(&b"exit_key"[..]); let exit_wallet = make_wallet("exit wallet"); @@ -5301,14 +5470,19 @@ mod tests { subject .keys_and_addrs .insert(stream_key.clone(), socket_addr.clone()); - 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()), - }, + 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(), ); let subject_addr: Addr = subject.start(); let dns_resolve_failure = DnsResolveFailure_0v1::new(stream_key); @@ -5316,7 +5490,7 @@ mod tests { ExpiredCoresPackage::new( SocketAddr::from_str("1.2.3.4:1234").unwrap(), Some(make_wallet("irrelevant")), - return_route_with_id(cryptde, 1234), + return_route_with_id(cryptde, 0), dns_resolve_failure.into(), 0, ); @@ -5329,8 +5503,7 @@ mod tests { system.run(); TestLogHandler::new().exists_log_containing(&format!( "ERROR: {test_name}: While \ - handling ExpiredCoresPackage: No entry found inside dns_failure_retries hashmap for \ - the stream_key: AAAAAAAAAAAAAAAAAAAAAAAAAAA" + handling ExpiredCoresPackage: No DNSFailureRetry entry found for the stream_key: {stream_key}" )); } @@ -5353,8 +5526,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!( @@ -5373,29 +5546,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.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()), - }, + 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(), ); let message_resolver_factory = RouteQueryResponseResolverFactoryMock::default() .make_params(&make_params_arc) @@ -5412,7 +5585,7 @@ mod tests { ExpiredCoresPackage::new( SocketAddr::from_str("1.2.3.4:1234").unwrap(), Some(make_wallet("irrelevant")), - return_route_with_id(cryptde, 1234), + return_route_with_id(cryptde, 0), dns_resolve_failure.into(), 0, ); @@ -5436,9 +5609,7 @@ mod tests { .try_send(AssertionsMessage { assertions: Box::new(move |proxy_server: &mut ProxyServer| { assert_eq!(proxy_server.keys_and_addrs.a_to_b(&stream_key), None); - assert_eq!(proxy_server.stream_key_routes.get(&stream_key), None); - assert_eq!(proxy_server.tunneled_hosts.get(&stream_key), None); - assert_eq!(proxy_server.dns_failure_retries.get(&stream_key), None); + assert_eq!(proxy_server.stream_info.get(&stream_key).is_none(), true); }), }) .unwrap(); @@ -5468,14 +5639,19 @@ mod tests { .keys_and_addrs .insert(stream_key.clone(), socket_addr.clone()); let remaining_route = return_route_with_id(cryptde, 4321); - subject.route_ids_to_return_routes.insert( - 4321, - AddReturnRouteMessage { - return_route_id: 4321, - expected_services: vec![ExpectedService::Nothing], - protocol: ProxyProtocol::HTTP, - hostname_opt: None, - }, + subject.stream_info.insert( + stream_key.clone(), + StreamInfoBuilder::new() + .route(RouteQueryResponse { + route: Route { hops: vec![] }, + expected_services: ExpectedServices::RoundTrip( + vec![], + vec![ExpectedService::Nothing], + ), + host: Host::new("booga.com", HTTP_PORT), + }) + .protocol(ProxyProtocol::HTTP) + .build(), ); let subject_addr: Addr = subject.start(); @@ -5518,7 +5694,7 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port: Some(80), + reception_port_opt: Some(80), sequence_number: Some(0), last_data: false, is_clandestine: false, @@ -5557,57 +5733,7 @@ mod tests { .accountant(accountant) .build(); let client_response_payload = ClientResponsePayload_0v1 { - stream_key, - sequenced_packet: SequencedPacket { - data: b"some data".to_vec(), - sequence_number: 4321, - last_data: false, - }, - }; - let expired_cores_package = ExpiredCoresPackage::new( - SocketAddr::from_str("1.2.3.4:1234").unwrap(), - Some(make_wallet("irrelevant")), - return_route_with_id(cryptde, 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, + stream_key: stream_key.clone(), sequenced_packet: SequencedPacket { data: b"some data".to_vec(), sequence_number: 4321, @@ -5617,9 +5743,7 @@ mod tests { let expired_cores_package = ExpiredCoresPackage::new( SocketAddr::from_str("1.2.3.4:1234").unwrap(), Some(make_wallet("irrelevant")), - Route { - hops: vec![make_cover_hop(cryptde), CryptData::new(&[0])], - }, + return_route_with_id(cryptde, 0 /* dummy */), client_response_payload, 0, ); @@ -5629,92 +5753,32 @@ mod tests { System::current().stop(); system.run(); - TestLogHandler::new().exists_log_containing( - "ERROR: ProxyServer: Can't report services consumed: DecryptionError(InvalidKey(\"Could not decrypt with", - ); + TestLogHandler::new().exists_log_containing(format!("ERROR: ProxyServer: Can't pay for return services consumed: received response with unrecognized stream key {}. Ignoring", stream_key).as_str()); assert_eq!(dispatcher_recording_arc.lock().unwrap().len(), 0); assert_eq!(accountant_recording_arc.lock().unwrap().len(), 0); } - #[test] - fn return_route_ids_expire_when_instructed() { - init_test_logging(); - let cryptde = 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 test_name = "handle_stream_shutdown_msg_handles_unknown_peer_addr"; + let logger = Logger::new(test_name); let mut subject = ProxyServer::new(CRYPTDE_PAIR.clone(), true, None, false, false); let unaffected_socket_addr = SocketAddr::from_str("2.3.4.5:6789").unwrap(); let unaffected_stream_key = StreamKey::make_meaningful_stream_key("unaffected"); subject .keys_and_addrs .insert(unaffected_stream_key, unaffected_socket_addr); - subject.stream_key_routes.insert( + subject.stream_info.insert( unaffected_stream_key, - RouteQueryResponse { - route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip(vec![], vec![], 1234), - }, + 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(), ); - 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(), @@ -5730,10 +5794,12 @@ mod tests { .keys_and_addrs .a_to_b(&unaffected_stream_key) .is_some()); + assert!(subject.stream_info.contains_key(&unaffected_stream_key)); assert!(subject - .stream_key_routes - .contains_key(&unaffected_stream_key)); - assert!(subject.tunneled_hosts.contains_key(&unaffected_stream_key)); + .stream_info(&unaffected_stream_key) + .unwrap() + .tunneled_host_opt + .is_some()); } #[test] @@ -5757,12 +5823,16 @@ mod tests { subject .keys_and_addrs .insert(affected_stream_key, affected_socket_addr); - subject.stream_key_routes.insert( + subject.stream_info.insert( unaffected_stream_key, - RouteQueryResponse { - route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip(vec![], vec![], 1234), - }, + 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(), ); let affected_route = Route::round_trip( RouteSegment::new( @@ -5781,7 +5851,6 @@ mod tests { ), CRYPTDE_PAIR.main.as_ref(), Some(make_paying_wallet(b"consuming")), - 1234, Some(TEST_DEFAULT_CHAIN.rec().contract), ) .unwrap(); @@ -5790,23 +5859,20 @@ mod tests { make_paying_wallet(b"1234"), DEFAULT_RATE_PACK, )]; - subject.stream_key_routes.insert( + subject.stream_info.insert( affected_stream_key, - RouteQueryResponse { - route: affected_route.clone(), - expected_services: ExpectedServices::RoundTrip( - affected_expected_services, - vec![], - 1234, - ), - }, + 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(), ); - 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(); @@ -5840,8 +5906,8 @@ mod tests { ClientRequestPayload_0v1 { stream_key: affected_stream_key, sequenced_packet: SequencedPacket::new(vec![], 1234, true), - target_hostname: Some(String::from("tunneled.com")), - target_port: 443, + target_hostname: String::from("tunneled.com"), + target_port: TLS_PORT, protocol: ProxyProtocol::TLS, originator_public_key: CRYPTDE_PAIR.alias.as_ref().public_key().clone(), } @@ -5887,12 +5953,15 @@ mod tests { subject .keys_and_addrs .insert(affected_stream_key, affected_socket_addr); - subject.stream_key_routes.insert( + subject.stream_info.insert( unaffected_stream_key, - RouteQueryResponse { - route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip(vec![], vec![], 1234), - }, + StreamInfoBuilder::new() + .route(RouteQueryResponse { + route: Route { hops: vec![] }, + expected_services: ExpectedServices::RoundTrip(vec![], vec![]), + host: Host::new("booga.com", HTTP_PORT), + }) + .build(), ); let affected_route = Route::round_trip( RouteSegment::new( @@ -5911,7 +5980,6 @@ mod tests { ), CRYPTDE_PAIR.main.as_ref(), Some(make_paying_wallet(b"consuming")), - 1234, Some(TEST_DEFAULT_CHAIN.rec().contract), ) .unwrap(); @@ -5920,16 +5988,18 @@ mod tests { make_paying_wallet(b"1234"), DEFAULT_RATE_PACK, )]; - subject.stream_key_routes.insert( + subject.stream_info.insert( affected_stream_key, - RouteQueryResponse { - route: affected_route.clone(), - expected_services: ExpectedServices::RoundTrip( - affected_expected_services, - vec![], - 1234, - ), - }, + StreamInfoBuilder::new() + .route(RouteQueryResponse { + route: affected_route.clone(), + expected_services: ExpectedServices::RoundTrip( + affected_expected_services, + vec![], + ), + host: Host::new("booga.com", HTTP_PORT), + }) + .build(), ); subject.logger = Logger::new(test_name); let subject_addr = subject.start(); @@ -5965,7 +6035,7 @@ mod tests { ClientRequestPayload_0v1 { stream_key: affected_stream_key, sequenced_packet: SequencedPacket::new(vec![], 1234, true), - target_hostname: None, + target_hostname: "booga.com".to_string(), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: CRYPTDE_PAIR.alias.as_ref().public_key().clone(), @@ -6004,6 +6074,9 @@ mod tests { let socket_addr = SocketAddr::from_str("3.4.5.6:7777").unwrap(); let stream_key = StreamKey::make_meaningful_stream_key("All Things Must Pass"); subject.keys_and_addrs.insert(stream_key, socket_addr); + subject + .stream_info + .insert(stream_key.clone(), StreamInfoBuilder::new().build()); let msg = StreamShutdownMsg { peer_addr: socket_addr, stream_type: RemovedStreamType::NonClandestine(NonClandestineAttributes { @@ -6030,16 +6103,17 @@ mod tests { let socket_addr = SocketAddr::from_str("3.4.5.6:7890").unwrap(); let stream_key = StreamKey::make_meaningful_stream_key("All Things Must Pass"); subject.keys_and_addrs.insert(stream_key, socket_addr); - subject.stream_key_routes.insert( + subject.stream_info.insert( stream_key, - RouteQueryResponse { - route: Route { hops: vec![] }, - expected_services: ExpectedServices::RoundTrip(vec![], vec![], 0), - }, + 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(), ); - subject - .tunneled_hosts - .insert(stream_key, "blah".to_string()); let msg = StreamShutdownMsg { peer_addr: socket_addr, stream_type: RemovedStreamType::NonClandestine(NonClandestineAttributes { @@ -6072,7 +6146,7 @@ mod tests { let inbound_client_data_msg = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:4578").unwrap(), - reception_port: None, + reception_port_opt: None, last_data: true, is_clandestine: false, sequence_number: Some(123), @@ -6111,16 +6185,10 @@ 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, - add_return_route_sub, - proxy_server_sub, - Err(MailboxError::Timeout), - ); + subject.resolve_message(args, proxy_server_sub, Err(MailboxError::Timeout)); System::current().stop(); system.run(); @@ -6138,22 +6206,63 @@ 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, - _cryptde: &dyn CryptDE, - _logger: &Logger, + ibcd: &InboundClientData, + stream_key: StreamKey, + host_opt: Option, + cryptde: &dyn CryptDE, + logger: &Logger, ) -> Option { + self.make_params.lock().unwrap().push(( + ibcd.clone(), + stream_key, + host_opt, + cryptde.dup(), + logger.clone(), + )); self.make_results.borrow_mut().remove(0) } } impl ClientRequestPayloadFactoryMock { + fn new() -> Self { + Self::default() + } + + fn make_params( + mut self, + params: &Arc< + 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 @@ -6175,7 +6284,7 @@ mod tests { let inbound_client_data_msg = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:4578").unwrap(), - reception_port: Some(568), + reception_port_opt: Some(568), last_data: true, is_clandestine: false, sequence_number: Some(123), @@ -6196,7 +6305,8 @@ mod tests { #[test] fn new_http_request_creates_new_entry_inside_dns_retries_hashmap() { - let alias_cryptde = CRYPTDE_PAIR.alias.as_ref(); + let test_name = "new_http_request_creates_new_entry_inside_dns_retries_hashmap"; + let logger = Logger::new(test_name); 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"[..]); @@ -6205,8 +6315,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(); @@ -6214,7 +6324,7 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port: Some(HTTP_PORT), + reception_port_opt: Some(HTTP_PORT), sequence_number: Some(0), last_data: true, is_clandestine: false, @@ -6224,7 +6334,8 @@ mod tests { .make( &msg_from_dispatcher, stream_key.clone(), - alias_cryptde, + None, + CRYPTDE_PAIR.alias.as_ref(), &Logger::new("test"), ) .unwrap(); @@ -6251,7 +6362,12 @@ mod tests { subject_addr .try_send(AssertionsMessage { assertions: Box::new(move |proxy_server: &mut ProxyServer| { - let dns_retry = proxy_server.dns_failure_retries.get(&stream_key).unwrap(); + let dns_retry = proxy_server + .stream_info(&stream_key) + .unwrap() + .dns_failure_retry_opt + .as_ref() + .unwrap(); assert_eq!(dns_retry.retries_left, 3); assert_eq!(dns_retry.unsuccessful_request, expected_payload); }), @@ -6263,6 +6379,9 @@ mod tests { #[test] fn new_http_request_creates_new_exhausted_entry_inside_dns_retries_hashmap_zero_hop() { + let test_name = + "new_http_request_creates_new_exhausted_entry_inside_dns_retries_hashmap_zero_hop"; + let logger = Logger::new(test_name); let 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"[..]); @@ -6271,8 +6390,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(); @@ -6280,7 +6399,7 @@ mod tests { let msg_from_dispatcher = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr.clone(), - reception_port: Some(HTTP_PORT), + reception_port_opt: Some(HTTP_PORT), sequence_number: Some(0), last_data: true, is_clandestine: false, @@ -6290,6 +6409,7 @@ mod tests { .make( &msg_from_dispatcher, stream_key.clone(), + None, CRYPTDE_PAIR.alias.as_ref(), &Logger::new("test"), ) @@ -6317,7 +6437,12 @@ mod tests { subject_addr .try_send(AssertionsMessage { assertions: Box::new(move |proxy_server: &mut ProxyServer| { - let dns_retry = proxy_server.dns_failure_retries.get(&stream_key).unwrap(); + let dns_retry = proxy_server + .stream_info(&stream_key) + .unwrap() + .dns_failure_retry_opt + .as_ref() + .unwrap(); assert_eq!(dns_retry.retries_left, 0); assert_eq!(dns_retry.unsuccessful_request, expected_payload); }), @@ -6407,7 +6532,7 @@ mod tests { let inbound_client_data_msg = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.2.3.4:4578").unwrap(), - reception_port: Some(80), + reception_port_opt: Some(80), last_data: true, is_clandestine: false, sequence_number: Some(123), @@ -6426,6 +6551,78 @@ 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: 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: 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" @@ -6466,7 +6663,7 @@ mod tests { let ibcd = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr, - reception_port: Some(2222), + reception_port_opt: Some(2222), last_data: true, is_clandestine: false, sequence_number: Some(333), @@ -6490,7 +6687,7 @@ mod tests { let ibcd = InboundClientData { timestamp: SystemTime::now(), client_addr: socket_addr, - reception_port: Some(2222), + reception_port_opt: Some(2222), last_data: true, is_clandestine: false, sequence_number: Some(333), @@ -6506,6 +6703,30 @@ 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 9697ce6a2..080a9050e 100644 --- a/node/src/proxy_server/protocol_pack.rs +++ b/node/src/proxy_server/protocol_pack.rs @@ -3,24 +3,10 @@ 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; @@ -44,7 +30,7 @@ pub fn from_standard_port(standard_port: u16) -> Option> { } pub fn from_ibcd(ibcd: &InboundClientData) -> Result, String> { - let origin_port = match ibcd.reception_port { + let origin_port = match ibcd.reception_port_opt { None => { return Err(format!( "No origin port specified with {}-byte non-clandestine packet: {:?}", @@ -67,6 +53,6 @@ pub fn from_ibcd(ibcd: &InboundClientData) -> Result, Stri pub trait ServerImpersonator { fn route_query_failure_response(&self, server_name: &str) -> Vec; - fn dns_resolution_failure_response(&self, server_name_opt: Option) -> Vec; + fn dns_resolution_failure_response(&self, server_name: String) -> Vec; fn consuming_wallet_absent(&self) -> Vec; } diff --git a/node/src/proxy_server/server_impersonator_http.rs b/node/src/proxy_server/server_impersonator_http.rs index 554741aae..9de02301d 100644 --- a/node/src/proxy_server/server_impersonator_http.rs +++ b/node/src/proxy_server/server_impersonator_http.rs @@ -19,11 +19,9 @@ impl ServerImpersonator for ServerImpersonatorHttp { ) } - fn dns_resolution_failure_response(&self, server_name_opt: Option) -> Vec { - let (server_name, quoted_server_name) = match &server_name_opt { - Some(name) => (name.clone(), format!("\"{}\"", name)), - None => ("".to_string(), "".to_string()), - }; + fn dns_resolution_failure_response(&self, server_name: String) -> Vec { + let (server_name, quoted_server_name) = + (server_name.clone(), format!("\"{}\"", server_name)); ServerImpersonatorHttp::make_error_response( 503, "DNS Resolution Problem", @@ -197,7 +195,7 @@ mod tests { fn dns_resolution_failure_response_with_server_name_produces_expected_error_page() { let subject = ServerImpersonatorHttp {}; - let result = subject.dns_resolution_failure_response(Some("server.com".to_string())); + let result = subject.dns_resolution_failure_response("server.com".to_string()); let expected = ServerImpersonatorHttp::make_error_response( 503, @@ -208,21 +206,6 @@ mod tests { assert_eq!(expected, result); } - #[test] - fn dns_resolution_failure_response_without_server_name_produces_expected_error_page() { - let subject = ServerImpersonatorHttp {}; - - let result = subject.dns_resolution_failure_response(None); - - let expected = ServerImpersonatorHttp::make_error_response( - 503, - "DNS Resolution Problem", - "Exit Nodes couldn't resolve ", - "DNS Failure, We have tried multiple Exit Nodes and all have failed to resolve this address ", - ); - assert_eq!(expected, result); - } - #[test] fn consuming_wallet_absent_response_produces_expected_error_page() { let subject = ServerImpersonatorHttp {}; diff --git a/node/src/proxy_server/server_impersonator_tls.rs b/node/src/proxy_server/server_impersonator_tls.rs index 7a193a269..3312be656 100644 --- a/node/src/proxy_server/server_impersonator_tls.rs +++ b/node/src/proxy_server/server_impersonator_tls.rs @@ -8,7 +8,7 @@ impl ServerImpersonator for ServerImpersonatorTls { Vec::from(&TLS_INTERNAL_ERROR_ALERT[..]) } - fn dns_resolution_failure_response(&self, _server_name: Option) -> Vec { + fn dns_resolution_failure_response(&self, _server_name: String) -> Vec { Vec::from(&TLS_UNRECOGNIZED_NAME_ALERT[..]) } @@ -75,7 +75,7 @@ mod tests { fn dns_resolution_failure_response_produces_unrecognized_name_alert() { let subject = ServerImpersonatorTls {}; - let result = subject.dns_resolution_failure_response(None); + let result = subject.dns_resolution_failure_response("booga.com".to_string()); assert_eq!(Vec::from(&TLS_UNRECOGNIZED_NAME_ALERT[..]), result); } diff --git a/node/src/proxy_server/tls_protocol_pack.rs b/node/src/proxy_server/tls_protocol_pack.rs index d167ef0fa..1ede34301 100644 --- a/node/src/proxy_server/tls_protocol_pack.rs +++ b/node/src/proxy_server/tls_protocol_pack.rs @@ -1,11 +1,13 @@ // Copyright (c) 2019, MASQ (https://masq.ai) and/or its affiliates. All rights reserved. -use crate::proxy_server::protocol_pack::{Host, ProtocolPack, ServerImpersonator}; +use crate::proxy_server::protocol_pack::{ProtocolPack, ServerImpersonator}; use crate::proxy_server::server_impersonator_tls::ServerImpersonatorTls; use crate::sub_lib::binary_traverser::BinaryTraverser; use crate::sub_lib::cryptde::PlainData; +use crate::sub_lib::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 { diff --git a/node/src/stream_handler_pool.rs b/node/src/stream_handler_pool.rs index 7aa6d0ff6..bc362ca18 100644 --- a/node/src/stream_handler_pool.rs +++ b/node/src/stream_handler_pool.rs @@ -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 = Some(8081); + let reception_port_opt = Some(8081); let is_clandestine = false; let one_http_req = b"GET http://here.com HTTP/1.1\r\n\r\n".to_vec(); let one_http_req_a = one_http_req.clone(); @@ -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, + reception_port_opt, PortConfiguration::new( vec![Box::new(HttpRequestDiscriminatorFactory::new())], is_clandestine, @@ -922,7 +922,7 @@ mod tests { &dispatcher::InboundClientData { timestamp: dispatcher_record.timestamp, client_addr: peer_addr_a, - reception_port, + reception_port_opt, last_data: false, is_clandestine, sequence_number: Some(0), @@ -936,7 +936,7 @@ mod tests { &dispatcher::InboundClientData { timestamp: dispatcher_record.timestamp, client_addr: peer_addr_a, - reception_port, + reception_port_opt, last_data: false, is_clandestine, sequence_number: Some(1), @@ -950,7 +950,7 @@ mod tests { &dispatcher::InboundClientData { timestamp: dispatcher_record.timestamp, client_addr: peer_addr_a, - reception_port, + reception_port_opt, last_data: false, is_clandestine, sequence_number: Some(2), @@ -963,7 +963,7 @@ mod tests { &dispatcher::StreamShutdownMsg { peer_addr: peer_addr_a, stream_type: RemovedStreamType::NonClandestine(NonClandestineAttributes { - reception_port: reception_port.unwrap(), + reception_port: reception_port_opt.unwrap(), sequence_number: 3 }), report_to_counterpart: true, @@ -1505,7 +1505,7 @@ mod tests { &InboundClientData { timestamp: ibcd.timestamp, client_addr: SocketAddr::from_str("1.2.3.5:7000").unwrap(), - reception_port: Some(54321), + reception_port_opt: Some(54321), last_data: false, is_clandestine: true, sequence_number: None, diff --git a/node/src/stream_reader.rs b/node/src/stream_reader.rs index cac9211a6..0cab54033 100644 --- a/node/src/stream_reader.rs +++ b/node/src/stream_reader.rs @@ -19,7 +19,7 @@ pub struct StreamReaderReal { stream: Box, local_addr: SocketAddr, peer_addr: SocketAddr, - reception_port: Option, + reception_port_opt: Option, ibcd_sub: Recipient, remove_sub: Recipient, dispatcher_stream_shutdown_sub: Recipient, @@ -86,7 +86,7 @@ impl StreamReaderReal { #[allow(clippy::too_many_arguments)] pub fn new( stream: Box, - reception_port: Option, + reception_port_opt: Option, ibcd_sub: Recipient, remove_sub: Recipient, dispatcher_sub: Recipient, @@ -107,7 +107,7 @@ impl StreamReaderReal { stream, local_addr, peer_addr, - reception_port, + reception_port_opt, ibcd_sub, remove_sub, dispatcher_stream_shutdown_sub: dispatcher_sub, @@ -162,7 +162,7 @@ impl StreamReaderReal { let msg = dispatcher::InboundClientData { timestamp: SystemTime::now(), client_addr: self.peer_addr, - reception_port: self.reception_port, + reception_port_opt: self.reception_port_opt, last_data: false, is_clandestine: self.is_clandestine, sequence_number, @@ -181,7 +181,7 @@ impl StreamReaderReal { } fn shutdown(&mut self) { - debug!(self.logger, "Directing removal of {}clandestine StreamReader with reception_port {:?} on {} listening to {}", if self.is_clandestine {""} else {"non-"}, self.reception_port, self.local_addr, self.peer_addr); + debug!(self.logger, "Directing removal of {}clandestine StreamReader with reception_port {:?} on {} listening to {}", if self.is_clandestine {""} else {"non-"}, self.reception_port_opt, self.local_addr, self.peer_addr); self.remove_sub .try_send(RemoveStreamMsg { peer_addr: self.peer_addr, @@ -190,7 +190,7 @@ impl StreamReaderReal { RemovedStreamType::Clandestine } else { RemovedStreamType::NonClandestine(NonClandestineAttributes { - reception_port: self.reception_port.expect( + reception_port: self.reception_port_opt.expect( "Non-clandestine StreamReader should always have a reception_port", ), sequence_number: self.sequencer.next_sequence_number(), @@ -511,7 +511,7 @@ mod tests { &dispatcher::InboundClientData { timestamp: d_record.timestamp, client_addr: peer_addr, - reception_port: Some(1234 as u16), + reception_port_opt: Some(1234 as u16), last_data: false, is_clandestine: true, sequence_number: Some(0), @@ -633,7 +633,7 @@ mod tests { &dispatcher::InboundClientData { timestamp: d_record.timestamp, client_addr: peer_addr, - reception_port: Some(1234 as u16), + reception_port_opt: Some(1234 as u16), last_data: false, is_clandestine: false, sequence_number: Some(0), @@ -648,7 +648,7 @@ mod tests { &dispatcher::InboundClientData { timestamp: d_record.timestamp, client_addr: peer_addr, - reception_port: Some(1234 as u16), + reception_port_opt: Some(1234 as u16), last_data: false, is_clandestine: false, sequence_number: Some(1), @@ -707,7 +707,7 @@ mod tests { &dispatcher::InboundClientData { timestamp: d_record.timestamp, client_addr, - reception_port: Some(1234 as u16), + reception_port_opt: Some(1234 as u16), last_data: false, is_clandestine: true, sequence_number: None, diff --git a/node/src/sub_lib/dispatcher.rs b/node/src/sub_lib/dispatcher.rs index 66e349e11..6ad7678b1 100644 --- a/node/src/sub_lib/dispatcher.rs +++ b/node/src/sub_lib/dispatcher.rs @@ -116,7 +116,7 @@ pub enum DispatcherError { pub struct InboundClientData { pub timestamp: SystemTime, pub client_addr: SocketAddr, - pub reception_port: Option, + pub reception_port_opt: Option, pub last_data: bool, pub is_clandestine: bool, pub sequence_number: Option, @@ -130,7 +130,7 @@ impl Debug for InboundClientData { Err(_) => self.data.hex_dump().to_string(), }; write!(f, "InboundClientData {{ peer_addr: {:?}, reception_port: {:?}, last_data: {}, sequence_number: {:?}, {} bytes of data: {} }}", - self.client_addr, self.reception_port, self.last_data, self.sequence_number, self.data.len(), data_string) + self.client_addr, self.reception_port_opt, self.last_data, self.sequence_number, self.data.len(), data_string) } } @@ -139,7 +139,7 @@ impl InboundClientData { InboundClientData { timestamp: SystemTime::now(), client_addr: self.client_addr, - reception_port: self.reception_port, + reception_port_opt: self.reception_port_opt, last_data: self.last_data, is_clandestine: self.is_clandestine, sequence_number: self.sequence_number, @@ -274,7 +274,7 @@ mod tests { let subject = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.4.3.2:9999").unwrap(), - reception_port: None, + reception_port_opt: None, last_data: false, is_clandestine: false, sequence_number: None, @@ -289,7 +289,7 @@ mod tests { let subject = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.4.3.2:9999").unwrap(), - reception_port: None, + reception_port_opt: None, last_data: false, is_clandestine: false, sequence_number: None, @@ -304,7 +304,7 @@ mod tests { let subject = InboundClientData { timestamp: SystemTime::now(), client_addr: SocketAddr::from_str("1.4.3.2:9999").unwrap(), - reception_port: None, + reception_port_opt: None, last_data: false, is_clandestine: false, sequence_number: None, diff --git a/node/src/sub_lib/hopper.rs b/node/src/sub_lib/hopper.rs index 96d756ef2..08af13bb5 100644 --- a/node/src/sub_lib/hopper.rs +++ b/node/src/sub_lib/hopper.rs @@ -173,6 +173,7 @@ mod tests { use crate::sub_lib::cryptde::PlainData; use crate::sub_lib::dispatcher::Component; use crate::sub_lib::route::RouteSegment; + use crate::sub_lib::stream_key::StreamKey; use crate::test_utils::recorder::Recorder; use crate::test_utils::{make_meaningless_message_type, make_paying_wallet}; use actix::Actor; @@ -205,7 +206,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(); + let payload = make_meaningless_message_type(StreamKey::make_meaningless_stream_key()); let result = NoLookupIncipientCoresPackage::new(cryptde, &public_key, &node_addr, payload.clone()); @@ -231,7 +232,7 @@ mod tests { cryptde, &PublicKey::new(&[]), &NodeAddr::new(&IpAddr::from_str("1.1.1.1").unwrap(), &[]), - make_meaningless_message_type(), + make_meaningless_message_type(StreamKey::make_meaningless_stream_key()), ); assert_eq!( result, @@ -255,7 +256,7 @@ mod tests { Some(TEST_DEFAULT_CHAIN.rec().contract), ) .unwrap(); - let payload = make_meaningless_message_type(); + let payload = make_meaningless_message_type(StreamKey::make_meaningless_stream_key()); let result = IncipientCoresPackage::new(cryptde, route.clone(), payload.clone(), &key56); let subject = result.unwrap(); @@ -278,7 +279,7 @@ mod tests { let result = IncipientCoresPackage::new( cryptde, Route { hops: vec![] }, - make_meaningless_message_type(), + make_meaningless_message_type(StreamKey::make_meaningless_stream_key()), &PublicKey::new(&[]), ); @@ -304,7 +305,7 @@ mod tests { Some(TEST_DEFAULT_CHAIN.rec().contract), ) .unwrap(); - let payload = make_meaningless_message_type(); + let payload = make_meaningless_message_type(StreamKey::make_meaningless_stream_key()); let subject: ExpiredCoresPackage = ExpiredCoresPackage::new( immediate_neighbor, diff --git a/node/src/sub_lib/host.rs b/node/src/sub_lib/host.rs new file mode 100644 index 000000000..bb23d8d16 --- /dev/null +++ b/node/src/sub_lib/host.rs @@ -0,0 +1,39 @@ +use std::fmt::Display; + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Host { + pub name: String, + pub port: u16, +} + +impl Display for Host { + fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + write!(f, "{}:{}", self.name, self.port) + } +} + +impl Host { + pub fn new(name: &str, port: u16) -> Host { + Host { + name: name.to_string(), + port, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn display() { + let subject = Host { + name: "example.com".to_string(), + port: 8080, + }; + + let result = format!("{}", subject); + + assert_eq!(result, "example.com:8080".to_string()); + } +} diff --git a/node/src/sub_lib/http_packet_framer.rs b/node/src/sub_lib/http_packet_framer.rs index 29685f46b..28d4f895f 100644 --- a/node/src/sub_lib/http_packet_framer.rs +++ b/node/src/sub_lib/http_packet_framer.rs @@ -104,7 +104,7 @@ impl HttpPacketFramer { lines: Vec::new(), }, start_finder, - logger: Logger::new("HttpRequestFramer"), + logger: Logger::new("HttpPacketFramer"), } } diff --git a/node/src/sub_lib/migrations/client_request_payload.rs b/node/src/sub_lib/migrations/client_request_payload.rs index 2bd9993f5..b048c1900 100644 --- a/node/src/sub_lib/migrations/client_request_payload.rs +++ b/node/src/sub_lib/migrations/client_request_payload.rs @@ -49,7 +49,7 @@ impl TryFrom<&Value> for ClientRequestPayload_0v1 { Value::Map(map) => { let mut stream_key_opt: Option = None; let mut sequenced_packet_opt: Option = None; - let mut target_hostname_opt: Option> = None; + let mut target_hostname: Option = None; let mut target_port_opt: Option = None; let mut protocol_opt: Option = None; let mut originator_public_key_opt: Option = None; @@ -61,9 +61,7 @@ impl TryFrom<&Value> for ClientRequestPayload_0v1 { "sequenced_packet" => { sequenced_packet_opt = value_to_type::(v) } - "target_hostname" => { - target_hostname_opt = value_to_type::>(v) - } + "target_hostname" => target_hostname = value_to_type::(v), "target_port" => target_port_opt = value_to_type::(v), "protocol" => protocol_opt = value_to_type::(v), "originator_public_key" => { @@ -89,7 +87,7 @@ impl TryFrom<&Value> for ClientRequestPayload_0v1 { "sequenced_packet", &sequenced_packet_opt, ); - check_field(&mut missing_fields, "target_hostname", &target_hostname_opt); + check_field(&mut missing_fields, "target_hostname", &target_hostname); check_field(&mut missing_fields, "target_port", &target_port_opt); check_field(&mut missing_fields, "protocol", &protocol_opt); check_field( @@ -103,7 +101,7 @@ impl TryFrom<&Value> for ClientRequestPayload_0v1 { Ok(ClientRequestPayload_0v1 { stream_key: stream_key_opt.expect("stream_key disappeared"), sequenced_packet: sequenced_packet_opt.expect("sequenced_packet disappeared"), - target_hostname: target_hostname_opt.expect("target_hostname disappeared"), + target_hostname: target_hostname.expect("target_hostname disappeared"), target_port: target_port_opt.expect("target_port disappeared"), protocol: protocol_opt.expect("protocol disappeared"), originator_public_key: originator_public_key_opt @@ -131,7 +129,7 @@ mod tests { struct ExampleFutureCRP { pub stream_key: StreamKey, pub sequenced_packet: SequencedPacket, - pub target_hostname: Option, + pub target_hostname: String, pub target_port: u16, pub protocol: ProxyProtocol, pub originator_public_key: PublicKey, @@ -141,7 +139,7 @@ mod tests { let expected_crp = ClientRequestPayload_0v1 { stream_key: StreamKey::make_meaningful_stream_key("All Things Must Pass"), sequenced_packet: SequencedPacket::new(vec![4, 3, 2, 1], 4321, false), - target_hostname: Some("target.hostname.com".to_string()), + target_hostname: "target.hostname.com".to_string(), target_port: 1234, protocol: ProxyProtocol::HTTP, originator_public_key: PublicKey::new(&[2, 3, 4, 5]), diff --git a/node/src/sub_lib/mod.rs b/node/src/sub_lib/mod.rs index 51360357b..4c1a76fce 100644 --- a/node/src/sub_lib/mod.rs +++ b/node/src/sub_lib/mod.rs @@ -21,6 +21,7 @@ pub mod framer; pub mod framer_utils; pub mod hop; pub mod hopper; +pub mod host; pub mod http_packet_framer; pub mod http_response_start_finder; pub mod limiter; diff --git a/node/src/sub_lib/neighborhood.rs b/node/src/sub_lib/neighborhood.rs index f26282aa6..674f83191 100644 --- a/node/src/sub_lib/neighborhood.rs +++ b/node/src/sub_lib/neighborhood.rs @@ -8,6 +8,7 @@ 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; @@ -473,7 +474,7 @@ pub struct RouteQueryMessage { pub target_component: Component, pub return_component_opt: Option, pub payload_size: usize, - pub hostname_opt: Option, + pub host: Host, } impl Message for RouteQueryMessage { @@ -481,16 +482,13 @@ impl Message for RouteQueryMessage { } impl RouteQueryMessage { - pub fn data_indefinite_route_request( - hostname_opt: Option, - payload_size: usize, - ) -> RouteQueryMessage { + pub fn data_indefinite_route_request(host: Host, payload_size: usize) -> RouteQueryMessage { RouteQueryMessage { target_key_opt: None, target_component: Component::ProxyClient, return_component_opt: Some(Component::ProxyServer), payload_size, - hostname_opt, + host, } } } @@ -502,16 +500,53 @@ 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, u32), + RoundTrip(Vec, Vec), } #[derive(Clone, Debug, PartialEq, Eq)] pub struct RouteQueryResponse { pub route: Route, pub expected_services: ExpectedServices, + pub host: Host, } #[derive(Clone, Debug, Message, PartialEq, Eq)] @@ -1060,7 +1095,8 @@ mod tests { #[test] fn data_indefinite_route_request() { - let result = RouteQueryMessage::data_indefinite_route_request(None, 7500); + let result = + RouteQueryMessage::data_indefinite_route_request(Host::new("booga.com", 1234), 7500); assert_eq!( result, @@ -1069,7 +1105,7 @@ mod tests { target_component: Component::ProxyClient, return_component_opt: Some(Component::ProxyServer), payload_size: 7500, - hostname_opt: None, + host: Host::new("booga.com", 1234), } ); } diff --git a/node/src/sub_lib/proxy_server.rs b/node/src/sub_lib/proxy_server.rs index c3042859f..c7b0ab49c 100644 --- a/node/src/sub_lib/proxy_server.rs +++ b/node/src/sub_lib/proxy_server.rs @@ -4,7 +4,7 @@ use crate::sub_lib::data_version::DataVersion; use crate::sub_lib::dispatcher::InboundClientData; use crate::sub_lib::dispatcher::StreamShutdownMsg; use crate::sub_lib::hopper::{ExpiredCoresPackage, MessageType}; -use crate::sub_lib::neighborhood::{ExpectedService, RouteQueryResponse}; +use crate::sub_lib::neighborhood::RouteQueryResponse; use crate::sub_lib::peer_actors::BindMessage; use crate::sub_lib::proxy_client::{ClientResponsePayload_0v1, DnsResolveFailure_0v1}; use crate::sub_lib::sequence_buffer::SequencedPacket; @@ -34,7 +34,7 @@ pub enum ProxyProtocol { pub struct ClientRequestPayload_0v1 { pub stream_key: StreamKey, pub sequenced_packet: SequencedPacket, - pub target_hostname: Option, + pub target_hostname: String, pub target_port: u16, pub protocol: ProxyProtocol, pub originator_public_key: PublicKey, @@ -55,14 +55,6 @@ 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, @@ -81,7 +73,6 @@ pub struct ProxyServerSubs { pub from_dispatcher: Recipient, pub from_hopper: Recipient>, pub dns_failure_from_hopper: Recipient>, - pub add_return_route: Recipient, pub stream_shutdown_sub: Recipient, pub node_from_ui: Recipient, pub route_result_sub: Recipient, @@ -113,7 +104,6 @@ mod tests { recorder, ExpiredCoresPackage ), - add_return_route: recipient!(recorder, AddReturnRouteMessage), stream_shutdown_sub: recipient!(recorder, StreamShutdownMsg), node_from_ui: recipient!(recorder, NodeFromUiMessage), route_result_sub: recipient!(recorder, AddRouteResultMessage), diff --git a/node/src/sub_lib/route.rs b/node/src/sub_lib/route.rs index 6d9b52604..05bcc15ad 100644 --- a/node/src/sub_lib/route.rs +++ b/node/src/sub_lib/route.rs @@ -1,5 +1,4 @@ // Copyright (c) 2019, MASQ (https://masq.ai) and/or its affiliates. All rights reserved. -use crate::sub_lib::cryptde::encodex; use crate::sub_lib::cryptde::CryptDE; use crate::sub_lib::cryptde::CryptData; use crate::sub_lib::cryptde::PublicKey; @@ -33,7 +32,6 @@ impl Route { cryptde, None, None, - None, ) } @@ -48,7 +46,6 @@ impl Route { None, cryptde, consuming_wallet, - None, contract_address, ) } @@ -56,9 +53,8 @@ impl Route { pub fn round_trip( route_segment_over: RouteSegment, route_segment_back: RouteSegment, - cryptde: &dyn CryptDE, // Must be the CryptDE of the originating Node: used to encrypt return_route_id. + cryptde: &dyn CryptDE, // Doesn't matter which CryptDE: only used for encoding. consuming_wallet: Option, - return_route_id: u32, contract_address: Option
, ) -> Result { Self::construct( @@ -66,22 +62,10 @@ 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() { @@ -132,15 +116,7 @@ impl Route { last_cryptde.public_key(), live_hop ), - Err(outside) => match decodex::(last_cryptde, &last_hop_enc) { - Ok(return_route_id) => format!( - "{}\nEncrypted with {:?}: Return Route ID: {}\n", - most_strings, - last_cryptde.public_key(), - return_route_id - ), - Err(inside) => format!("{}\nError: {:?} / {:?}", most_strings, outside, inside), - }, + Err(error) => format!("{}\nError: {:?}", most_strings, error), } } @@ -149,7 +125,6 @@ impl Route { back: Option, cryptde: &dyn CryptDE, consuming_wallet: Option, - return_route_id_opt: Option, contract_address: Option
, ) -> Result { if let Some(error) = Route::validate_route_segments(&over, &back) { @@ -174,12 +149,7 @@ impl Route { contract_address, ); - Route::hops_to_route( - hops[0..].to_vec(), - &over.keys[0], - return_route_id_opt, - cryptde, - ) + Route::hops_to_route(hops[0..].to_vec(), &over.keys[0], cryptde) } fn over_segment<'a>( @@ -296,7 +266,6 @@ impl Route { fn hops_to_route( hops: Vec, top_hop_key: &PublicKey, - return_route_id_opt: Option, cryptde: &dyn CryptDE, ) -> Result { let mut hops_enc: Vec = Vec::new(); @@ -308,17 +277,8 @@ 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 { @@ -365,66 +325,6 @@ 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(); @@ -458,7 +358,6 @@ mod tests { RouteSegment::new(vec![&c_key, &d_key], Component::ProxyServer), cryptde, Some(paying_wallet.clone()), - 0, Some(TEST_DEFAULT_CHAIN.rec().contract), ) .err() @@ -502,7 +401,6 @@ 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( @@ -510,7 +408,6 @@ 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(); @@ -599,12 +496,6 @@ mod tests { .unwrap(), "seventh hop" ); - - assert_eq!( - subject.hops[7], - Route::encrypt_return_route_id(return_route_id, cryptde), - "eighth hop" - ); } #[test] @@ -783,7 +674,6 @@ mod tests { RouteSegment::new(vec![&key2, &key1], Component::ProxyServer), cryptde, Some(paying_wallet), - 1234, Some(TEST_DEFAULT_CHAIN.rec().contract), ) .unwrap(); @@ -832,13 +722,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), - &CryptDENull::from(&key1, TEST_DEFAULT_CHAIN), + &cryptde, Some(paying_wallet), - 1234, Some(TEST_DEFAULT_CHAIN.rec().contract), ) .unwrap(); @@ -861,7 +751,6 @@ Encrypted with 0x02030405: LiveHop { public_key: 0x03040506, payer: Some(Payer { Encrypted with 0x03040506: LiveHop { public_key: 0x02030405, payer: Some(Payer { wallet: Wallet { kind: Address(0x71d0fc7d1c570b1ed786382b551a09391c91e33d) }, proof: Signature { v: 1, r: "8649b8f6db6232cb1e4f1f04786ad4ef33488c968e64bec74ecd893d6d05c1b9", s: "8649b8f6db6232cb1e4f1f04786ad4ef33488c968e64bec74ecd893d6d05c1b9" } }), component: ProxyClient } Encrypted with 0x02030405: LiveHop { public_key: 0x01020304, payer: Some(Payer { wallet: Wallet { kind: Address(0x71d0fc7d1c570b1ed786382b551a09391c91e33d) }, proof: Signature { v: 0, r: "4324a40295bb36ef2b927fb24250fe42397a57b861ea152bbbe4f84150d4ff5a", s: "4324a40295bb36ef2b927fb24250fe42397a57b861ea152bbbe4f84150d4ff5a" } }), component: Hopper } Encrypted with 0x01020304: LiveHop { public_key: 0x, payer: Some(Payer { wallet: Wallet { kind: Address(0x71d0fc7d1c570b1ed786382b551a09391c91e33d) }, proof: Signature { v: 0, r: "3e3a92d7284c2c2ff7119e9f7a7e183b062a335a598e965a47c36a2f288b6f8d", s: "3e3a92d7284c2c2ff7119e9f7a7e183b062a335a598e965a47c36a2f288b6f8d" } }), component: ProxyServer } -Encrypted with 0x01020304: Return Route ID: 1234 "# ) ); diff --git a/node/src/sub_lib/stream_key.rs b/node/src/sub_lib/stream_key.rs index bca70efe4..0e6132a7f 100644 --- a/node/src/sub_lib/stream_key.rs +++ b/node/src/sub_lib/stream_key.rs @@ -97,9 +97,9 @@ impl StreamKey { impl StreamKey { pub fn make_meaningless_stream_key() -> StreamKey { - StreamKey { - hash: [0; sha1::DIGEST_LENGTH], - } + let mut bytes = [0; sha1::DIGEST_LENGTH]; + randombytes_into(&mut bytes); + StreamKey { hash: bytes } } 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 faa79b68a..1c32dea0d 100644 --- a/node/src/sub_lib/ttl_hashmap.rs +++ b/node/src/sub_lib/ttl_hashmap.rs @@ -8,6 +8,7 @@ use std::rc::Rc; use std::time::Duration; use std::time::Instant; +#[allow(clippy::type_complexity)] pub struct TtlHashMap where K: Hash + Clone, @@ -15,6 +16,7 @@ where last_check: RefCell, data: RefCell, Instant)>>, ttl: Duration, + retire_closure: Box bool>, } impl TtlHashMap @@ -27,6 +29,19 @@ where last_check: RefCell::new(Instant::now()), data: RefCell::new(HashMap::new()), ttl, + retire_closure: Box::new(|_, _| true), + } + } + + pub fn new_with_retire(ttl: Duration, retire_closure: F) -> TtlHashMap + where + F: 'static + Fn(&K, &V) -> bool, + { + TtlHashMap { + last_check: RefCell::new(Instant::now()), + data: RefCell::new(HashMap::new()), + ttl, + retire_closure: Box::new(retire_closure), } } @@ -54,6 +69,12 @@ 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(); @@ -74,7 +95,15 @@ where }; expired.iter().for_each(|key| { - self.data.borrow_mut().remove(key); + let mut data = self.data.borrow_mut(); + match data.remove(key) { + Some((value, _)) => { + if !(self.retire_closure)(key, value.as_ref()) { + data.insert(key.clone(), (value, now)); + } + } + None => (), // already removed + } }); } } @@ -82,26 +111,70 @@ 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)); - assert_eq!(subject.ttl, Duration::from_millis(1000)); + let result = subject.ttl; + + assert_eq!(result, Duration::from_millis(1000)); } #[test] - fn remove_returns_none_for_entry_that_was_never_inserted() { + fn get_returns_none_for_entry_that_was_never_inserted() { let subject = TtlHashMap::::new(Duration::from_millis(1000)); - assert_eq!(subject.get(&11u32), None); + let result = subject.get(&11u32); + + assert_eq!(result, None); assert_eq!(subject.ttl(), Duration::from_millis(1000)); } #[test] - fn ttl_hashmap_does_not_remove_entry_before_it_is_expired() { + 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 + }); subject.insert(42u32, "Hello"); subject.insert(24u32, "World"); @@ -109,25 +182,52 @@ mod tests { assert_eq!(subject.get(&42u32).unwrap().as_ref(), &"Hello"); assert_eq!(subject.get(&24u32).unwrap().as_ref(), &"World"); assert_eq!(subject.ttl(), Duration::from_millis(10)); + assert_eq!(*retire_closure_has_run.lock().unwrap(), false); } #[test] fn ttl_hashmap_get_removes_expired_entry() { - let mut subject = TtlHashMap::new(Duration::from_millis(10)); - + let retire_closure_has_run = Arc::new(Mutex::new(false)); + let retire_closure_has_run_inner = retire_closure_has_run.clone(); + let mut subject = TtlHashMap::new_with_retire(Duration::from_millis(10), move |_, _| { + *(retire_closure_has_run_inner.lock().unwrap()) = true; + true + }); subject.insert(42u32, "Hello"); + thread::sleep(Duration::from_millis(20)); + + let result = subject.get(&42u32); + + assert_eq!(result, None); + assert_eq!(*retire_closure_has_run.lock().unwrap(), true); + } + #[test] + fn ttl_hashmap_get_does_not_remove_expired_entry_if_closure_returns_false() { + let retire_closure_has_run = Arc::new(Mutex::new(false)); + let retire_closure_has_run_inner = retire_closure_has_run.clone(); + let mut subject = TtlHashMap::new_with_retire(Duration::from_millis(10), move |_, _| { + *(retire_closure_has_run_inner.lock().unwrap()) = true; + false + }); + subject.insert(42u32, "Hello"); thread::sleep(Duration::from_millis(20)); - assert_eq!(subject.get(&42u32), None); + let result = subject.get(&42u32); + + assert_eq!(result, Some(Rc::new("Hello"))); + assert_eq!(*retire_closure_has_run.lock().unwrap(), true); } #[test] fn ttl_hashmap_insert_removes_expired_entry() { - let mut subject = TtlHashMap::new(Duration::from_millis(10)); - + let retire_closure_has_run = Arc::new(Mutex::new(false)); + let retire_closure_has_run_inner = retire_closure_has_run.clone(); + let mut subject = TtlHashMap::new_with_retire(Duration::from_millis(10), move |_, _| { + *(retire_closure_has_run_inner.lock().unwrap()) = true; + true + }); subject.insert(42u32, "Hello"); - thread::sleep(Duration::from_millis(20)); subject.insert(24u32, "World"); @@ -137,6 +237,7 @@ 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 351b27711..73c5e5044 100644 --- a/node/src/test_utils/mod.rs +++ b/node/src/test_utils/mod.rs @@ -21,7 +21,6 @@ use crate::blockchain::bip32::Bip32EncryptionKeyProvider; use crate::blockchain::payer::Payer; use crate::bootstrapper::CryptDEPair; use crate::sub_lib::cryptde::CryptDE; -use crate::sub_lib::cryptde::CryptData; use crate::sub_lib::cryptde::PlainData; use crate::sub_lib::cryptde::PublicKey; use crate::sub_lib::dispatcher::Component; @@ -52,8 +51,10 @@ 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; @@ -195,25 +196,26 @@ pub fn make_meaningless_wallet_private_key() -> PlainData { } // TODO: The three functions below should use only one argument, cryptde -pub fn route_to_proxy_client(main_key: &PublicKey, main_cryptde: &dyn CryptDE) -> Route { +pub fn route_to_proxy_client(main_key: &PublicKey, main_cryptde: &dyn CryptDE, tls: bool) -> Route { shift_one_hop( - zero_hop_route_response(main_key, main_cryptde).route, + zero_hop_route_response(main_key, main_cryptde, tls).route, main_cryptde, ) } -pub fn route_from_proxy_client(key: &PublicKey, cryptde: &dyn CryptDE) -> Route { +pub fn route_from_proxy_client(key: &PublicKey, cryptde: &dyn CryptDE, tls: bool) -> Route { // Happens to be the same - route_to_proxy_client(key, cryptde) + route_to_proxy_client(key, cryptde, tls) } -pub fn route_to_proxy_server(key: &PublicKey, cryptde: &dyn CryptDE) -> Route { - shift_one_hop(route_from_proxy_client(key, cryptde), cryptde) +pub fn route_to_proxy_server(key: &PublicKey, cryptde: &dyn CryptDE, tls: bool) -> Route { + shift_one_hop(route_from_proxy_client(key, cryptde, tls), cryptde) } pub fn zero_hop_route_response( public_key: &PublicKey, cryptde: &dyn CryptDE, + tls: bool, ) -> RouteQueryResponse { RouteQueryResponse { route: Route::round_trip( @@ -221,15 +223,14 @@ 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 }), } } @@ -238,13 +239,6 @@ fn shift_one_hop(mut route: Route, cryptde: &dyn CryptDE) -> Route { route } -pub fn encrypt_return_route_id(return_route_id: u32, cryptde: &dyn CryptDE) -> CryptData { - let return_route_id_ser = serde_cbor::ser::to_vec(&return_route_id).unwrap(); - cryptde - .encode(cryptde.public_key(), &PlainData::from(return_route_id_ser)) - .unwrap() -} - pub fn make_garbage_data(bytes: usize) -> Vec { let mut data = vec![0; bytes]; rand::thread_rng().fill_bytes(&mut data); @@ -429,8 +423,8 @@ pub fn read_until_timeout(stream: &mut dyn Read) -> Vec { response } -pub fn make_meaningless_message_type() -> MessageType { - DnsResolveFailure_0v1::new(StreamKey::make_meaningless_stream_key()).into() +pub fn make_meaningless_message_type(stream_key: StreamKey) -> MessageType { + DnsResolveFailure_0v1::new(stream_key).into() } pub fn handle_connection_error(stream: TcpStream) { @@ -694,7 +688,7 @@ pub mod unshared_test_utils { ClientRequestPayload_0v1 { stream_key: StreamKey::make_meaningful_stream_key("request"), sequenced_packet: SequencedPacket::new(make_garbage_data(bytes), 0, true), - target_hostname: Some("www.example.com".to_string()), + target_hostname: "www.example.com".to_string(), target_port: HTTP_PORT, protocol: ProxyProtocol::HTTP, originator_public_key: cryptde.public_key().clone(), @@ -1231,7 +1225,7 @@ mod tests { let cryptde = CRYPTDE_PAIR.main.as_ref(); let key = cryptde.public_key(); - let subject = zero_hop_route_response(&key, cryptde); + let subject = zero_hop_route_response(&key, cryptde, false); assert_eq!( subject.route.hops, @@ -1245,7 +1239,6 @@ mod tests { LiveHop::new(&PublicKey::new(b""), None, Component::ProxyServer) .encode(&key, cryptde) .unwrap(), - encrypt_return_route_id(0, cryptde), ) ); assert_eq!( @@ -1253,7 +1246,6 @@ mod tests { ExpectedServices::RoundTrip( vec![ExpectedService::Nothing, ExpectedService::Nothing,], vec![ExpectedService::Nothing, ExpectedService::Nothing,], - 0 ) ); } @@ -1263,7 +1255,7 @@ mod tests { let cryptde = CRYPTDE_PAIR.main.as_ref(); let key = cryptde.public_key(); - let subject = route_to_proxy_client(&key, cryptde); + let subject = route_to_proxy_client(&key, cryptde, false); let mut garbage_can: Vec = iter::repeat(0u8).take(96).collect(); cryptde.random(&mut garbage_can[..]); @@ -1276,7 +1268,6 @@ mod tests { LiveHop::new(&PublicKey::new(b""), None, Component::ProxyServer) .encode(&key, cryptde) .unwrap(), - encrypt_return_route_id(0, cryptde), CryptData::new(&garbage_can[..]) ) ); @@ -1287,7 +1278,7 @@ mod tests { let cryptde = CRYPTDE_PAIR.main.as_ref(); let key = cryptde.public_key(); - let subject = route_from_proxy_client(&key, cryptde); + let subject = route_from_proxy_client(&key, cryptde, false); let mut garbage_can: Vec = iter::repeat(0u8).take(96).collect(); cryptde.random(&mut garbage_can[..]); @@ -1300,7 +1291,6 @@ mod tests { LiveHop::new(&PublicKey::new(b""), None, Component::ProxyServer) .encode(&key, cryptde) .unwrap(), - encrypt_return_route_id(0, cryptde), CryptData::new(&garbage_can[..]) ) ); @@ -1311,7 +1301,7 @@ mod tests { let cryptde = CRYPTDE_PAIR.main.as_ref(); let key = cryptde.public_key(); - let subject = route_to_proxy_server(&key, cryptde); + let subject = route_to_proxy_server(&key, cryptde, false); let mut first_garbage_can: Vec = iter::repeat(0u8).take(96).collect(); let mut second_garbage_can: Vec = iter::repeat(0u8).take(96).collect(); @@ -1323,7 +1313,6 @@ mod tests { LiveHop::new(&PublicKey::new(b""), None, Component::ProxyServer) .encode(&key, cryptde) .unwrap(), - encrypt_return_route_id(0, cryptde), CryptData::new(&first_garbage_can[..]), CryptData::new(&second_garbage_can[..]), ) diff --git a/node/src/test_utils/recorder.rs b/node/src/test_utils/recorder.rs index f66125182..20daaec86 100644 --- a/node/src/test_utils/recorder.rs +++ b/node/src/test_utils/recorder.rs @@ -39,10 +39,8 @@ use crate::sub_lib::peer_actors::PeerActors; use crate::sub_lib::peer_actors::{BindMessage, NewPublicIp, StartMessage}; use crate::sub_lib::proxy_client::{ClientResponsePayload_0v1, InboundServerData}; use crate::sub_lib::proxy_client::{DnsResolveFailure_0v1, ProxyClientSubs}; -use crate::sub_lib::proxy_server::{ - 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; @@ -123,7 +121,6 @@ macro_rules! recorder_message_handler_t_p { }; } -recorder_message_handler_t_m_p!(AddReturnRouteMessage); recorder_message_handler_t_m_p!(AddRouteResultMessage); recorder_message_handler_t_p!(AddStreamMsg); recorder_message_handler_t_m_p!(BindMessage); @@ -398,7 +395,6 @@ pub fn make_proxy_server_subs_from_recorder(addr: &Addr) -> ProxyServe from_dispatcher: recipient!(addr, InboundClientData), from_hopper: recipient!(addr, ExpiredCoresPackage), dns_failure_from_hopper: recipient!(addr, ExpiredCoresPackage), - add_return_route: recipient!(addr, AddReturnRouteMessage), stream_shutdown_sub: recipient!(addr, StreamShutdownMsg), node_from_ui: recipient!(addr, NodeFromUiMessage), route_result_sub: recipient!(addr, AddRouteResultMessage),