use std::sync::Arc; use base64::{Engine as _, engine::general_purpose::STANDARD as BASE64_STANDARD}; use x25519_dalek::{PublicKey, StaticSecret}; use crate::foundation::time::{Duration, timeout}; use crate::{ packet::{PacketType, ZCPacket}, peers::{ conn::{ peer_conn::{PeerConn, PeerConnId}, peer_map::PeerMap, peer_session::PeerSessionStore, }, context::NetworkIdentity, create_packet_recv_chan, error::Error, test_support::NoopPeerContext, }, tunnel::ring::create_ring_tunnel_pair, }; impl PeerConn { #[tracing::instrument] async fn do_handshake_as_server(&mut self) -> Result<(), Error> { self.do_handshake_as_server_ext(|_, _| Ok(())).await } } #[tokio::test] async fn peer_conn_handshake_over_memory_tunnel() { let peer_session_store = Arc::new(PeerSessionStore::new()); let (client_tunnel, server_tunnel) = create_ring_tunnel_pair(); let client_ctx = Arc::new(NoopPeerContext::default()); let server_ctx = Arc::new(NoopPeerContext::default()); let mut client = PeerConn::new(1, client_ctx, client_tunnel, peer_session_store.clone()); let mut server = PeerConn::new(2, server_ctx, server_tunnel, peer_session_store); let (client_ret, server_ret) = tokio::join!( client.do_handshake_as_client(), server.do_handshake_as_server() ); client_ret.unwrap(); server_ret.unwrap(); assert_eq!(client.get_peer_id(), 2); assert_eq!(server.get_peer_id(), 1); assert_eq!(client.get_conn_info().features, ["liveness-echo-v1"]); assert_eq!(server.get_conn_info().features, ["liveness-echo-v1"]); } #[tokio::test] async fn peer_conn_noise_handshake_advertises_liveness_echo() { fn context(peer_key: u8) -> Arc { let private = StaticSecret::from([peer_key; 32]); let public = PublicKey::from(&private); Arc::new( NoopPeerContext::new(NetworkIdentity { network_name: "net".to_owned(), network_secret: Some("secret".to_owned()), network_secret_digest: None, }) .with_secure_mode(crate::proto::common::SecureModeConfig { enabled: true, local_private_key: Some(BASE64_STANDARD.encode(private.as_bytes())), local_public_key: Some(BASE64_STANDARD.encode(public.as_bytes())), }), ) } let (client_tunnel, server_tunnel) = create_ring_tunnel_pair(); let mut client = PeerConn::new( 1, context(1), client_tunnel, Arc::new(PeerSessionStore::new()), ); let mut server = PeerConn::new( 2, context(2), server_tunnel, Arc::new(PeerSessionStore::new()), ); let (client_ret, server_ret) = tokio::join!( client.do_handshake_as_client(), server.do_handshake_as_server() ); client_ret.unwrap(); server_ret.unwrap(); assert_eq!(client.get_conn_info().features, ["liveness-echo-v1"]); assert_eq!(server.get_conn_info().features, ["liveness-echo-v1"]); } #[tokio::test] async fn peer_conn_handshake_matches_plaintext_secret_identity() { let peer_session_store = Arc::new(PeerSessionStore::new()); let (client_tunnel, server_tunnel) = create_ring_tunnel_pair(); let client_ctx = Arc::new(NoopPeerContext::new(NetworkIdentity { network_name: "net".to_string(), network_secret: Some("secret".to_string()), network_secret_digest: None, })); let server_ctx = Arc::new(NoopPeerContext::new(NetworkIdentity { network_name: "net".to_string(), network_secret: Some("secret".to_string()), network_secret_digest: None, })); let mut client = PeerConn::new(1, client_ctx, client_tunnel, peer_session_store.clone()); let mut server = PeerConn::new(2, server_ctx, server_tunnel, peer_session_store); let (client_ret, server_ret) = tokio::join!( client.do_handshake_as_client(), server.do_handshake_as_server() ); client_ret.unwrap(); server_ret.unwrap(); assert!(client.matches_local_network_secret()); assert!(server.matches_local_network_secret()); } #[tokio::test] async fn peer_map_forwards_packet_over_memory_tunnel() { let peer_session_store = Arc::new(PeerSessionStore::new()); let (client_tunnel, server_tunnel) = create_ring_tunnel_pair(); let client_ctx = Arc::new(NoopPeerContext::default()); let server_ctx = Arc::new(NoopPeerContext::default()); let mut client_conn = PeerConn::new( 1, client_ctx.clone(), client_tunnel, peer_session_store.clone(), ); let mut server_conn = PeerConn::new(2, server_ctx.clone(), server_tunnel, peer_session_store); let (client_ret, server_ret) = tokio::join!( client_conn.do_handshake_as_client(), server_conn.do_handshake_as_server() ); client_ret.unwrap(); server_ret.unwrap(); let (client_tx, _client_rx) = create_packet_recv_chan(); let (server_tx, mut server_rx) = create_packet_recv_chan(); let client_map = PeerMap::new(client_tx, client_ctx, 1); let server_map = PeerMap::new(server_tx, server_ctx, 2); client_map.add_new_peer_conn(client_conn).await.unwrap(); server_map.add_new_peer_conn(server_conn).await.unwrap(); let mut packet = ZCPacket::new_with_payload(b"hello"); packet.fill_peer_manager_hdr(1, 2, PacketType::Data as u8); client_map.send_msg_directly(packet, 2).await.unwrap(); let received = timeout(Duration::from_secs(1), server_rx.recv()) .await .unwrap() .unwrap(); assert_eq!(received.payload(), b"hello"); } #[tokio::test] async fn peer_map_reselects_cached_connection_after_close() { let peer_session_store = Arc::new(PeerSessionStore::new()); let (client_tunnel_a, server_tunnel_a) = create_ring_tunnel_pair(); let (client_tunnel_b, server_tunnel_b) = create_ring_tunnel_pair(); let client_ctx = Arc::new(NoopPeerContext::default()); let server_ctx = Arc::new(NoopPeerContext::default()); let mut client_conn_a = PeerConn::new( 1, client_ctx.clone(), client_tunnel_a, peer_session_store.clone(), ); let mut server_conn_a = PeerConn::new( 2, server_ctx.clone(), server_tunnel_a, peer_session_store.clone(), ); let mut client_conn_b = PeerConn::new( 1, client_ctx.clone(), client_tunnel_b, peer_session_store.clone(), ); let mut server_conn_b = PeerConn::new(2, server_ctx.clone(), server_tunnel_b, peer_session_store); let (client_a_ret, server_a_ret, client_b_ret, server_b_ret) = tokio::join!( client_conn_a.do_handshake_as_client(), server_conn_a.do_handshake_as_server(), client_conn_b.do_handshake_as_client(), server_conn_b.do_handshake_as_server(), ); client_a_ret.unwrap(); server_a_ret.unwrap(); client_b_ret.unwrap(); server_b_ret.unwrap(); let (client_tx, _client_rx) = create_packet_recv_chan(); let (server_tx, mut server_rx) = create_packet_recv_chan(); let client_map = PeerMap::new(client_tx, client_ctx, 1); let server_map = PeerMap::new(server_tx, server_ctx, 2); client_map.add_new_peer_conn(client_conn_a).await.unwrap(); client_map.add_new_peer_conn(client_conn_b).await.unwrap(); server_map.add_new_peer_conn(server_conn_a).await.unwrap(); server_map.add_new_peer_conn(server_conn_b).await.unwrap(); let mut first_packet = ZCPacket::new_with_payload(b"first"); first_packet.fill_peer_manager_hdr(1, 2, PacketType::Data as u8); client_map.send_msg_directly(first_packet, 2).await.unwrap(); let first_received = timeout(Duration::from_secs(1), server_rx.recv()) .await .unwrap() .unwrap(); assert_eq!(first_received.payload(), b"first"); let first_conn_id = client_map.get_peer_default_conn_id(2).await.unwrap(); assert_ne!(first_conn_id, PeerConnId::default()); client_map.close_peer_conn(2, &first_conn_id).await.unwrap(); timeout(Duration::from_secs(1), async { while client_map.get_peer_default_conn_id(2).await == Some(first_conn_id) { tokio::task::yield_now().await; } }) .await .unwrap(); let mut second_packet = ZCPacket::new_with_payload(b"second"); second_packet.fill_peer_manager_hdr(1, 2, PacketType::Data as u8); client_map .send_msg_directly(second_packet, 2) .await .unwrap(); let second_received = timeout(Duration::from_secs(1), server_rx.recv()) .await .unwrap() .unwrap(); assert_eq!(second_received.payload(), b"second"); assert_ne!( client_map.get_peer_default_conn_id(2).await, Some(first_conn_id) ); }