From c8fa30a509d8fadbe0f7271b4254e064729fafd9 Mon Sep 17 00:00:00 2001 From: Cameron Garnham Date: Tue, 18 Oct 2022 18:31:28 +0200 Subject: [PATCH 1/4] fix: prepare tests for connection cookie Co-authored-by: Jose Celano --- src/protocol/clock/time_extent.rs | 1 + src/tracker/peer.rs | 1 - src/udp/handlers.rs | 76 +++++++++++++++++++++++-------- 3 files changed, 57 insertions(+), 21 deletions(-) diff --git a/src/protocol/clock/time_extent.rs b/src/protocol/clock/time_extent.rs index d0713645b..3fa60de82 100644 --- a/src/protocol/clock/time_extent.rs +++ b/src/protocol/clock/time_extent.rs @@ -133,6 +133,7 @@ where } } } + fn now_before(increment: &TimeExtentBase, sub_time: &Duration) -> Option> { match Clock::sub(sub_time) { None => None, diff --git a/src/tracker/peer.rs b/src/tracker/peer.rs index 09509e50f..2d0985fc9 100644 --- a/src/tracker/peer.rs +++ b/src/tracker/peer.rs @@ -131,7 +131,6 @@ mod test { use crate::peer::TorrentPeer; use crate::protocol::utils::get_connection_id; - // todo: duplicate functions is PR 82. Remove duplication once both PR are merged. fn sample_ipv4_remote_addr() -> SocketAddr { diff --git a/src/udp/handlers.rs b/src/udp/handlers.rs index 5e286b9f7..f22436bc1 100644 --- a/src/udp/handlers.rs +++ b/src/udp/handlers.rs @@ -482,7 +482,8 @@ mod tests { use std::net::Ipv4Addr; use aquatic_udp_protocol::{ - AnnounceEvent, AnnounceRequest, NumberOfBytes, NumberOfPeers, PeerId as AquaticPeerId, PeerKey, Port, TransactionId, + AnnounceEvent, AnnounceRequest, ConnectionId, NumberOfBytes, NumberOfPeers, PeerId as AquaticPeerId, PeerKey, Port, + TransactionId, }; use crate::protocol::utils::get_connection_id; @@ -517,6 +518,11 @@ mod tests { } } + pub fn with_connection_id(mut self, connection_id: ConnectionId) -> Self { + self.request.connection_id = connection_id; + self + } + pub fn with_info_hash(mut self, info_hash: aquatic_udp_protocol::InfoHash) -> Self { self.request.info_hash = info_hash; self @@ -552,6 +558,7 @@ mod tests { Response, ResponsePeer, }; + use crate::protocol::utils::get_connection_id; use crate::statistics::TrackerStatisticsEvent; use crate::tracker::tracker::TorrentTracker; use crate::udp::handle_announce; @@ -571,14 +578,16 @@ mod tests { let info_hash = AquaticInfoHash([0u8; 20]); let peer_id = AquaticPeerId([255u8; 20]); + let remote_addr = SocketAddr::new(IpAddr::V4(client_ip), client_port); + let request = AnnounceRequestBuilder::default() + .with_connection_id(get_connection_id(&remote_addr)) .with_info_hash(info_hash) .with_peer_id(peer_id) .with_ip_address(client_ip) .with_port(client_port) .into(); - let remote_addr = SocketAddr::new(IpAddr::V4(client_ip), client_port); handle_announce(remote_addr, &request, tracker.clone()).await.unwrap(); let peers = tracker.get_all_torrent_peers(&info_hash.0.into()).await; @@ -593,9 +602,12 @@ mod tests { #[tokio::test] async fn the_announced_peer_should_not_be_included_in_the_response() { - let request = AnnounceRequestBuilder::default().into(); let remote_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(126, 0, 0, 1)), 8080); + let request = AnnounceRequestBuilder::default() + .with_connection_id(get_connection_id(&remote_addr)) + .into(); + let response = handle_announce(remote_addr, &request, initialized_public_tracker()) .await .unwrap(); @@ -629,14 +641,16 @@ mod tests { let remote_client_port = 8081; let peer_address = Ipv4Addr::new(126, 0, 0, 2); + let remote_addr = SocketAddr::new(IpAddr::V4(remote_client_ip), remote_client_port); + let request = AnnounceRequestBuilder::default() + .with_connection_id(get_connection_id(&remote_addr)) .with_info_hash(info_hash) .with_peer_id(peer_id) .with_ip_address(peer_address) .with_port(client_port) .into(); - let remote_addr = SocketAddr::new(IpAddr::V4(remote_client_ip), remote_client_port); handle_announce(remote_addr, &request, tracker.clone()).await.unwrap(); let peers = tracker.get_all_torrent_peers(&info_hash.0.into()).await; @@ -663,8 +677,10 @@ mod tests { } async fn announce_a_new_peer_using_ipv4(tracker: Arc) -> Response { - let request = AnnounceRequestBuilder::default().into(); let remote_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(126, 0, 0, 1)), 8080); + let request = AnnounceRequestBuilder::default() + .with_connection_id(get_connection_id(&remote_addr)) + .into(); let response = handle_announce(remote_addr, &request, tracker.clone()).await.unwrap(); response } @@ -707,6 +723,7 @@ mod tests { use aquatic_udp_protocol::{InfoHash as AquaticInfoHash, PeerId as AquaticPeerId}; + use crate::protocol::utils::get_connection_id; use crate::udp::handle_announce; use crate::udp::handlers::tests::announce_request::AnnounceRequestBuilder; use crate::udp::handlers::tests::{initialized_public_tracker, TorrentPeerBuilder}; @@ -721,14 +738,16 @@ mod tests { let info_hash = AquaticInfoHash([0u8; 20]); let peer_id = AquaticPeerId([255u8; 20]); + let remote_addr = SocketAddr::new(IpAddr::V4(client_ip), client_port); + let request = AnnounceRequestBuilder::default() + .with_connection_id(get_connection_id(&remote_addr)) .with_info_hash(info_hash) .with_peer_id(peer_id) .with_ip_address(client_ip) .with_port(client_port) .into(); - let remote_addr = SocketAddr::new(IpAddr::V4(client_ip), client_port); handle_announce(remote_addr, &request, tracker.clone()).await.unwrap(); let peers = tracker.get_all_torrent_peers(&info_hash.0.into()).await; @@ -756,6 +775,7 @@ mod tests { Response, ResponsePeer, }; + use crate::protocol::utils::get_connection_id; use crate::statistics::TrackerStatisticsEvent; use crate::tracker::tracker::TorrentTracker; use crate::udp::handle_announce; @@ -776,14 +796,16 @@ mod tests { let info_hash = AquaticInfoHash([0u8; 20]); let peer_id = AquaticPeerId([255u8; 20]); + let remote_addr = SocketAddr::new(IpAddr::V6(client_ip_v6), client_port); + let request = AnnounceRequestBuilder::default() + .with_connection_id(get_connection_id(&remote_addr)) .with_info_hash(info_hash) .with_peer_id(peer_id) .with_ip_address(client_ip_v4) .with_port(client_port) .into(); - let remote_addr = SocketAddr::new(IpAddr::V6(client_ip_v6), client_port); handle_announce(remote_addr, &request, tracker.clone()).await.unwrap(); let peers = tracker.get_all_torrent_peers(&info_hash.0.into()).await; @@ -798,11 +820,15 @@ mod tests { #[tokio::test] async fn the_announced_peer_should_not_be_included_in_the_response() { - let request = AnnounceRequestBuilder::default().into(); let client_ip_v4 = Ipv4Addr::new(126, 0, 0, 1); let client_ip_v6 = client_ip_v4.to_ipv6_compatible(); + let remote_addr = SocketAddr::new(IpAddr::V6(client_ip_v6), 8080); + let request = AnnounceRequestBuilder::default() + .with_connection_id(get_connection_id(&remote_addr)) + .into(); + let response = handle_announce(remote_addr, &request, initialized_public_tracker()) .await .unwrap(); @@ -836,14 +862,16 @@ mod tests { let remote_client_port = 8081; let peer_address = "126.0.0.1".parse().unwrap(); + let remote_addr = SocketAddr::new(IpAddr::V6(remote_client_ip), remote_client_port); + let request = AnnounceRequestBuilder::default() + .with_connection_id(get_connection_id(&remote_addr)) .with_info_hash(info_hash) .with_peer_id(peer_id) .with_ip_address(peer_address) .with_port(client_port) .into(); - let remote_addr = SocketAddr::new(IpAddr::V6(remote_client_ip), remote_client_port); handle_announce(remote_addr, &request, tracker.clone()).await.unwrap(); let peers = tracker.get_all_torrent_peers(&info_hash.0.into()).await; @@ -874,7 +902,9 @@ mod tests { let client_ip_v6 = client_ip_v4.to_ipv6_compatible(); let client_port = 8080; let remote_addr = SocketAddr::new(IpAddr::V6(client_ip_v6), client_port); - let request = AnnounceRequestBuilder::default().into(); + let request = AnnounceRequestBuilder::default() + .with_connection_id(get_connection_id(&remote_addr)) + .into(); let response = handle_announce(remote_addr, &request, tracker.clone()).await.unwrap(); response } @@ -903,13 +933,16 @@ mod tests { tracker_stats_service.should_throw_event(TrackerStatisticsEvent::Udp6Announce); let tracker = Arc::new(TorrentTracker::new(default_tracker_config(), tracker_stats_service).unwrap()); - handle_announce( - sample_ipv6_remote_addr(), - &AnnounceRequestBuilder::default().into(), - tracker.clone(), - ) - .await - .unwrap(); + + let remote_addr = sample_ipv6_remote_addr(); + + let announce_request = AnnounceRequestBuilder::default() + .with_connection_id(get_connection_id(&remote_addr)) + .into(); + + handle_announce(remote_addr, &announce_request, tracker.clone()) + .await + .unwrap(); } mod from_a_loopback_ip { @@ -918,6 +951,7 @@ mod tests { use aquatic_udp_protocol::{InfoHash as AquaticInfoHash, PeerId as AquaticPeerId}; + use crate::protocol::utils::get_connection_id; use crate::statistics::StatsTracker; use crate::tracker::tracker::TorrentTracker; use crate::udp::handle_announce; @@ -940,14 +974,16 @@ mod tests { let info_hash = AquaticInfoHash([0u8; 20]); let peer_id = AquaticPeerId([255u8; 20]); + let remote_addr = SocketAddr::new(IpAddr::V6(client_ip_v6), client_port); + let request = AnnounceRequestBuilder::default() + .with_connection_id(get_connection_id(&remote_addr)) .with_info_hash(info_hash) .with_peer_id(peer_id) .with_ip_address(client_ip_v4) .with_port(client_port) .into(); - let remote_addr = SocketAddr::new(IpAddr::V6(client_ip_v6), client_port); handle_announce(remote_addr, &request, tracker.clone()).await.unwrap(); let peers = tracker.get_all_torrent_peers(&info_hash.0.into()).await; @@ -1036,7 +1072,7 @@ mod tests { let info_hashes = vec![*info_hash]; ScrapeRequest { - connection_id: get_connection_id(remote_addr), + connection_id: get_connection_id(&remote_addr), transaction_id: TransactionId(0i32), info_hashes, } @@ -1181,7 +1217,7 @@ mod tests { let info_hashes = vec![info_hash]; ScrapeRequest { - connection_id: get_connection_id(remote_addr), + connection_id: get_connection_id(&remote_addr), transaction_id: TransactionId(0i32), info_hashes, } From 43685b69004583f54e16e834b73122a7603483cb Mon Sep 17 00:00:00 2001 From: Cameron Garnham Date: Tue, 18 Oct 2022 18:37:19 +0200 Subject: [PATCH 2/4] dev: connection cookie implmentation --- src/udp/connection_cookie.rs | 178 +++++++++++++++++++++++++++++++++++ src/udp/mod.rs | 1 + 2 files changed, 179 insertions(+) create mode 100644 src/udp/connection_cookie.rs diff --git a/src/udp/connection_cookie.rs b/src/udp/connection_cookie.rs new file mode 100644 index 000000000..712c2ce61 --- /dev/null +++ b/src/udp/connection_cookie.rs @@ -0,0 +1,178 @@ +use std::net::SocketAddr; + +use aquatic_udp_protocol::ConnectionId; + +use crate::protocol::clock::time_extent::{Extent, TimeExtent}; +use crate::udp::ServerError; + +pub type Cookie = [u8; 8]; + +pub type SinceUnixEpochTimeExtent = TimeExtent; + +pub const COOKIE_LIFETIME: TimeExtent = TimeExtent::from_sec(2, &60); + +pub fn from_connection_id(connection_id: &ConnectionId) -> Cookie { + connection_id.0.to_le_bytes() +} + +pub fn into_connection_id(connection_cookie: &Cookie) -> ConnectionId { + ConnectionId(i64::from_le_bytes(*connection_cookie)) +} + +pub fn make_connection_cookie(remote_address: &SocketAddr) -> Cookie { + let time_extent = cookie_builder::get_last_time_extent(); + + let cookie = cookie_builder::build(remote_address, &time_extent); + //println!("remote_address: {remote_address:?}, time_extent: {time_extent:?}, cookie: {cookie:?}"); + cookie +} + +pub fn check_connection_cookie( + remote_address: &SocketAddr, + connection_cookie: &Cookie, +) -> Result { + // we loop backwards testing each time_extent until we find one that matches. + // (or the lifetime of time_extents is exhausted) + for offset in 0..=COOKIE_LIFETIME.amount { + let checking_time_extent = cookie_builder::get_last_time_extent().decrease(offset).unwrap(); + + let checking_cookie = cookie_builder::build(remote_address, &checking_time_extent); + //println!("remote_address: {remote_address:?}, time_extent: {checking_time_extent:?}, cookie: {checking_cookie:?}"); + + if *connection_cookie == checking_cookie { + return Ok(checking_time_extent); + } + } + Err(ServerError::InvalidConnectionId) +} + +mod cookie_builder { + use std::collections::hash_map::DefaultHasher; + use std::hash::{Hash, Hasher}; + use std::net::SocketAddr; + + use super::{Cookie, SinceUnixEpochTimeExtent, COOKIE_LIFETIME}; + use crate::protocol::clock::time_extent::{DefaultTimeExtentMaker, Extent, MakeTimeExtent, TimeExtent}; + use crate::protocol::crypto::keys::seeds::{DefaultSeed, SeedKeeper}; + + pub(super) fn get_last_time_extent() -> SinceUnixEpochTimeExtent { + DefaultTimeExtentMaker::now(&COOKIE_LIFETIME.increment) + .unwrap() + .unwrap() + .increase(COOKIE_LIFETIME.amount) + .unwrap() + } + + pub(super) fn build(remote_address: &SocketAddr, time_extent: &TimeExtent) -> Cookie { + let seed = DefaultSeed::get_seed(); + + let mut hasher = DefaultHasher::new(); + + remote_address.hash(&mut hasher); + time_extent.hash(&mut hasher); + seed.hash(&mut hasher); + + hasher.finish().to_le_bytes() + } +} + +#[cfg(test)] +mod tests { + use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}; + + use super::cookie_builder::get_last_time_extent; + use crate::protocol::clock::time_extent::Extent; + use crate::protocol::clock::{StoppedClock, StoppedTime}; + use crate::udp::connection_cookie::{check_connection_cookie, make_connection_cookie, Cookie, COOKIE_LIFETIME}; + + fn make_test_socket_addr() -> SocketAddr { + SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080) + } + + fn make_test_cookie(remote_address: Option<&SocketAddr>) -> Cookie { + make_connection_cookie(remote_address.unwrap_or(&make_test_socket_addr())) + } + + #[test] + fn it_should_make_a_connection_cookie() { + // remote_address: 127.0.0.1:8080, time_extent: 60, + // seed: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + + const ID_COOKIE: Cookie = [45, 59, 50, 101, 97, 203, 48, 19]; + + let test_cookie = make_test_cookie(None); + //println!("{test_cookie:?}"); + + assert_eq!(test_cookie, ID_COOKIE) + } + + #[test] + fn it_should_make_different_connection_cookie_with_different_remote_addresses() { + let test_remote_address_1 = SocketAddr::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), 1); + let test_remote_address_2 = SocketAddr::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), 2); + let test_remote_address_3 = SocketAddr::new(IpAddr::V6(Ipv6Addr::LOCALHOST), 1); + + assert_ne!( + make_test_cookie(Some(&test_remote_address_1)), + make_test_cookie(Some(&test_remote_address_2)) + ); + + assert_ne!( + make_test_cookie(Some(&test_remote_address_1)), + make_test_cookie(Some(&test_remote_address_3)) + ); + + assert_ne!( + make_test_cookie(Some(&test_remote_address_2)), + make_test_cookie(Some(&test_remote_address_3)) + ) + } + + #[test] + fn it_should_make_different_cookies_for_the_next_time_extent() { + let cookie_now = make_test_cookie(None); + + StoppedClock::local_add(&COOKIE_LIFETIME.increment).unwrap(); + + let cookie_next = make_test_cookie(None); + + assert_ne!(cookie_now, cookie_next) + } + + #[test] + fn it_should_be_valid_for_this_time_extent() { + let cookie_now = make_test_cookie(None); + + check_connection_cookie(&make_test_socket_addr(), &cookie_now).unwrap(); + } + + #[test] + fn it_should_be_valid_for_the_next_time_extent() { + let cookie_now = make_test_cookie(None); + + StoppedClock::local_add(&COOKIE_LIFETIME.increment).unwrap(); + + check_connection_cookie(&make_test_socket_addr(), &cookie_now).unwrap(); + } + + #[test] + fn it_cookies_should_be_valid_for_the_last_time_extent() { + let cookie_now = make_test_cookie(None); + + StoppedClock::local_set(&COOKIE_LIFETIME.total().unwrap().unwrap()); + + check_connection_cookie(&make_test_socket_addr(), &cookie_now).unwrap(); + } + + #[test] + #[should_panic] + fn it_cookies_should_be_not_valid_after_their_last_time_extent() { + let cookie_now = make_test_cookie(None); + + let last_time_extent = get_last_time_extent().increase(COOKIE_LIFETIME.amount).unwrap(); + + StoppedClock::local_set(&last_time_extent.total_next().unwrap().unwrap()); + + check_connection_cookie(&make_test_socket_addr(), &cookie_now).unwrap(); + } +} diff --git a/src/udp/mod.rs b/src/udp/mod.rs index ae87973f1..4c98875c5 100644 --- a/src/udp/mod.rs +++ b/src/udp/mod.rs @@ -3,6 +3,7 @@ pub use self::handlers::*; pub use self::request::*; pub use self::server::*; +pub mod connection_cookie; pub mod errors; pub mod handlers; pub mod request; From 4949424b9158706205753667a5ed6c28ab5209c9 Mon Sep 17 00:00:00 2001 From: Cameron Garnham Date: Tue, 18 Oct 2022 18:40:18 +0200 Subject: [PATCH 3/4] dev: use the connection cookie implementation --- src/protocol/utils.rs | 14 +--------- src/tracker/peer.rs | 4 +-- src/udp/handlers.rs | 60 ++++++++++++++++++++++++------------------- 3 files changed, 37 insertions(+), 41 deletions(-) diff --git a/src/protocol/utils.rs b/src/protocol/utils.rs index 48fe4eb17..ac20aa41e 100644 --- a/src/protocol/utils.rs +++ b/src/protocol/utils.rs @@ -1,16 +1,4 @@ -use std::net::SocketAddr; - -use aquatic_udp_protocol::ConnectionId; - -use super::clock::{DefaultClock, DurationSinceUnixEpoch, Time}; - -pub fn get_connection_id(remote_address: &SocketAddr) -> ConnectionId { - ConnectionId(((current_time() / 3600) | ((remote_address.port() as u64) << 36)) as i64) -} - -pub fn current_time() -> u64 { - DefaultClock::now().as_secs() -} +use super::clock::DurationSinceUnixEpoch; pub fn ser_unix_time_value(unix_time_value: &DurationSinceUnixEpoch, ser: S) -> Result { ser.serialize_u64(unix_time_value.as_millis() as u64) diff --git a/src/tracker/peer.rs b/src/tracker/peer.rs index 2d0985fc9..7ac35179a 100644 --- a/src/tracker/peer.rs +++ b/src/tracker/peer.rs @@ -130,7 +130,7 @@ mod test { }; use crate::peer::TorrentPeer; - use crate::protocol::utils::get_connection_id; + use crate::udp::connection_cookie::{into_connection_id, make_connection_cookie}; // todo: duplicate functions is PR 82. Remove duplication once both PR are merged. fn sample_ipv4_remote_addr() -> SocketAddr { @@ -152,7 +152,7 @@ mod test { let info_hash_aquatic = aquatic_udp_protocol::InfoHash([0u8; 20]); let default_request = AnnounceRequest { - connection_id: get_connection_id(&sample_ipv4_remote_addr()), + connection_id: into_connection_id(&make_connection_cookie(&sample_ipv4_remote_addr())), transaction_id: TransactionId(0i32), info_hash: info_hash_aquatic, peer_id: AquaticPeerId(*b"-qB00000000000000000"), diff --git a/src/udp/handlers.rs b/src/udp/handlers.rs index f22436bc1..d46cd9231 100644 --- a/src/udp/handlers.rs +++ b/src/udp/handlers.rs @@ -6,8 +6,8 @@ use aquatic_udp_protocol::{ NumberOfPeers, Port, Request, Response, ResponsePeer, ScrapeRequest, ScrapeResponse, TorrentScrapeStatistics, TransactionId, }; +use super::connection_cookie::{check_connection_cookie, from_connection_id, into_connection_id, make_connection_cookie}; use crate::peer::TorrentPeer; -use crate::protocol::utils::get_connection_id; use crate::tracker::statistics::TrackerStatisticsEvent; use crate::tracker::torrent::TorrentError; use crate::tracker::tracker::TorrentTracker; @@ -69,7 +69,8 @@ pub async fn handle_connect( request: &ConnectRequest, tracker: Arc, ) -> Result { - let connection_id = get_connection_id(&remote_addr); + let connection_cookie = make_connection_cookie(&remote_addr); + let connection_id = into_connection_id(&connection_cookie); let response = Response::from(ConnectResponse { transaction_id: request.transaction_id, @@ -94,6 +95,13 @@ pub async fn handle_announce( announce_request: &AnnounceRequest, tracker: Arc, ) -> Result { + match check_connection_cookie(&remote_addr, &from_connection_id(&announce_request.connection_id)) { + Ok(_) => {} + Err(e) => { + return Err(e); + } + } + let wrapped_announce_request = AnnounceRequestWrapper::new(announce_request.clone()); authenticate(&wrapped_announce_request.info_hash, tracker.clone()).await?; @@ -401,9 +409,9 @@ mod tests { use aquatic_udp_protocol::{ConnectRequest, ConnectResponse, Response, TransactionId}; use super::{default_tracker_config, sample_ipv4_socket_address, sample_ipv6_remote_addr, TrackerStatsServiceMock}; - use crate::protocol::utils::get_connection_id; use crate::statistics::TrackerStatisticsEvent; use crate::tracker::tracker::TorrentTracker; + use crate::udp::connection_cookie::{into_connection_id, make_connection_cookie}; use crate::udp::handle_connect; use crate::udp::handlers::tests::{initialized_public_tracker, sample_ipv4_remote_addr}; @@ -426,7 +434,7 @@ mod tests { assert_eq!( response, Response::Connect(ConnectResponse { - connection_id: get_connection_id(&sample_ipv4_remote_addr()), + connection_id: into_connection_id(&make_connection_cookie(&sample_ipv4_remote_addr())), transaction_id: request.transaction_id }) ); @@ -445,7 +453,7 @@ mod tests { assert_eq!( response, Response::Connect(ConnectResponse { - connection_id: get_connection_id(&sample_ipv4_remote_addr()), + connection_id: into_connection_id(&make_connection_cookie(&sample_ipv4_remote_addr())), transaction_id: request.transaction_id }) ); @@ -486,7 +494,7 @@ mod tests { TransactionId, }; - use crate::protocol::utils::get_connection_id; + use crate::udp::connection_cookie::{into_connection_id, make_connection_cookie}; use crate::udp::handlers::tests::sample_ipv4_remote_addr; struct AnnounceRequestBuilder { @@ -500,7 +508,7 @@ mod tests { let info_hash_aquatic = aquatic_udp_protocol::InfoHash([0u8; 20]); let default_request = AnnounceRequest { - connection_id: get_connection_id(&sample_ipv4_remote_addr()), + connection_id: into_connection_id(&make_connection_cookie(&sample_ipv4_remote_addr())), transaction_id: TransactionId(0i32), info_hash: info_hash_aquatic, peer_id: AquaticPeerId([255u8; 20]), @@ -558,9 +566,9 @@ mod tests { Response, ResponsePeer, }; - use crate::protocol::utils::get_connection_id; use crate::statistics::TrackerStatisticsEvent; use crate::tracker::tracker::TorrentTracker; + use crate::udp::connection_cookie::{into_connection_id, make_connection_cookie}; use crate::udp::handle_announce; use crate::udp::handlers::tests::announce_request::AnnounceRequestBuilder; use crate::udp::handlers::tests::{ @@ -581,7 +589,7 @@ mod tests { let remote_addr = SocketAddr::new(IpAddr::V4(client_ip), client_port); let request = AnnounceRequestBuilder::default() - .with_connection_id(get_connection_id(&remote_addr)) + .with_connection_id(into_connection_id(&make_connection_cookie(&remote_addr))) .with_info_hash(info_hash) .with_peer_id(peer_id) .with_ip_address(client_ip) @@ -605,7 +613,7 @@ mod tests { let remote_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(126, 0, 0, 1)), 8080); let request = AnnounceRequestBuilder::default() - .with_connection_id(get_connection_id(&remote_addr)) + .with_connection_id(into_connection_id(&make_connection_cookie(&remote_addr))) .into(); let response = handle_announce(remote_addr, &request, initialized_public_tracker()) @@ -644,7 +652,7 @@ mod tests { let remote_addr = SocketAddr::new(IpAddr::V4(remote_client_ip), remote_client_port); let request = AnnounceRequestBuilder::default() - .with_connection_id(get_connection_id(&remote_addr)) + .with_connection_id(into_connection_id(&make_connection_cookie(&remote_addr))) .with_info_hash(info_hash) .with_peer_id(peer_id) .with_ip_address(peer_address) @@ -679,7 +687,7 @@ mod tests { async fn announce_a_new_peer_using_ipv4(tracker: Arc) -> Response { let remote_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(126, 0, 0, 1)), 8080); let request = AnnounceRequestBuilder::default() - .with_connection_id(get_connection_id(&remote_addr)) + .with_connection_id(into_connection_id(&make_connection_cookie(&remote_addr))) .into(); let response = handle_announce(remote_addr, &request, tracker.clone()).await.unwrap(); response @@ -723,7 +731,7 @@ mod tests { use aquatic_udp_protocol::{InfoHash as AquaticInfoHash, PeerId as AquaticPeerId}; - use crate::protocol::utils::get_connection_id; + use crate::udp::connection_cookie::{into_connection_id, make_connection_cookie}; use crate::udp::handle_announce; use crate::udp::handlers::tests::announce_request::AnnounceRequestBuilder; use crate::udp::handlers::tests::{initialized_public_tracker, TorrentPeerBuilder}; @@ -741,7 +749,7 @@ mod tests { let remote_addr = SocketAddr::new(IpAddr::V4(client_ip), client_port); let request = AnnounceRequestBuilder::default() - .with_connection_id(get_connection_id(&remote_addr)) + .with_connection_id(into_connection_id(&make_connection_cookie(&remote_addr))) .with_info_hash(info_hash) .with_peer_id(peer_id) .with_ip_address(client_ip) @@ -775,9 +783,9 @@ mod tests { Response, ResponsePeer, }; - use crate::protocol::utils::get_connection_id; use crate::statistics::TrackerStatisticsEvent; use crate::tracker::tracker::TorrentTracker; + use crate::udp::connection_cookie::{into_connection_id, make_connection_cookie}; use crate::udp::handle_announce; use crate::udp::handlers::tests::announce_request::AnnounceRequestBuilder; use crate::udp::handlers::tests::{ @@ -799,7 +807,7 @@ mod tests { let remote_addr = SocketAddr::new(IpAddr::V6(client_ip_v6), client_port); let request = AnnounceRequestBuilder::default() - .with_connection_id(get_connection_id(&remote_addr)) + .with_connection_id(into_connection_id(&make_connection_cookie(&remote_addr))) .with_info_hash(info_hash) .with_peer_id(peer_id) .with_ip_address(client_ip_v4) @@ -826,7 +834,7 @@ mod tests { let remote_addr = SocketAddr::new(IpAddr::V6(client_ip_v6), 8080); let request = AnnounceRequestBuilder::default() - .with_connection_id(get_connection_id(&remote_addr)) + .with_connection_id(into_connection_id(&make_connection_cookie(&remote_addr))) .into(); let response = handle_announce(remote_addr, &request, initialized_public_tracker()) @@ -865,7 +873,7 @@ mod tests { let remote_addr = SocketAddr::new(IpAddr::V6(remote_client_ip), remote_client_port); let request = AnnounceRequestBuilder::default() - .with_connection_id(get_connection_id(&remote_addr)) + .with_connection_id(into_connection_id(&make_connection_cookie(&remote_addr))) .with_info_hash(info_hash) .with_peer_id(peer_id) .with_ip_address(peer_address) @@ -903,7 +911,7 @@ mod tests { let client_port = 8080; let remote_addr = SocketAddr::new(IpAddr::V6(client_ip_v6), client_port); let request = AnnounceRequestBuilder::default() - .with_connection_id(get_connection_id(&remote_addr)) + .with_connection_id(into_connection_id(&make_connection_cookie(&remote_addr))) .into(); let response = handle_announce(remote_addr, &request, tracker.clone()).await.unwrap(); response @@ -937,7 +945,7 @@ mod tests { let remote_addr = sample_ipv6_remote_addr(); let announce_request = AnnounceRequestBuilder::default() - .with_connection_id(get_connection_id(&remote_addr)) + .with_connection_id(into_connection_id(&make_connection_cookie(&remote_addr))) .into(); handle_announce(remote_addr, &announce_request, tracker.clone()) @@ -951,9 +959,9 @@ mod tests { use aquatic_udp_protocol::{InfoHash as AquaticInfoHash, PeerId as AquaticPeerId}; - use crate::protocol::utils::get_connection_id; use crate::statistics::StatsTracker; use crate::tracker::tracker::TorrentTracker; + use crate::udp::connection_cookie::{into_connection_id, make_connection_cookie}; use crate::udp::handle_announce; use crate::udp::handlers::tests::announce_request::AnnounceRequestBuilder; use crate::udp::handlers::tests::TrackerConfigurationBuilder; @@ -977,7 +985,7 @@ mod tests { let remote_addr = SocketAddr::new(IpAddr::V6(client_ip_v6), client_port); let request = AnnounceRequestBuilder::default() - .with_connection_id(get_connection_id(&remote_addr)) + .with_connection_id(into_connection_id(&make_connection_cookie(&remote_addr))) .with_info_hash(info_hash) .with_peer_id(peer_id) .with_ip_address(client_ip_v4) @@ -1012,8 +1020,8 @@ mod tests { }; use super::TorrentPeerBuilder; - use crate::protocol::utils::get_connection_id; use crate::tracker::tracker::TorrentTracker; + use crate::udp::connection_cookie::{into_connection_id, make_connection_cookie}; use crate::udp::handle_scrape; use crate::udp::handlers::tests::{initialized_public_tracker, sample_ipv4_remote_addr}; use crate::PeerId; @@ -1034,7 +1042,7 @@ mod tests { let info_hashes = vec![info_hash]; let request = ScrapeRequest { - connection_id: get_connection_id(&remote_addr), + connection_id: into_connection_id(&make_connection_cookie(&remote_addr)), transaction_id: TransactionId(0i32), info_hashes, }; @@ -1072,7 +1080,7 @@ mod tests { let info_hashes = vec![*info_hash]; ScrapeRequest { - connection_id: get_connection_id(&remote_addr), + connection_id: into_connection_id(&make_connection_cookie(&remote_addr)), transaction_id: TransactionId(0i32), info_hashes, } @@ -1217,7 +1225,7 @@ mod tests { let info_hashes = vec![info_hash]; ScrapeRequest { - connection_id: get_connection_id(&remote_addr), + connection_id: into_connection_id(&make_connection_cookie(&remote_addr)), transaction_id: TransactionId(0i32), info_hashes, } From 2911f3d05587bc0501979e76347c73279456b0fe Mon Sep 17 00:00:00 2001 From: Cameron Garnham Date: Wed, 19 Oct 2022 14:08:05 +0200 Subject: [PATCH 4/4] tests: improve connection cookie tests Co-authored-by: Jose Celano --- src/udp/connection_cookie.rs | 161 +++++++++++++++++++++++++---------- 1 file changed, 114 insertions(+), 47 deletions(-) diff --git a/src/udp/connection_cookie.rs b/src/udp/connection_cookie.rs index 712c2ce61..a17431b9c 100644 --- a/src/udp/connection_cookie.rs +++ b/src/udp/connection_cookie.rs @@ -80,99 +80,166 @@ mod cookie_builder { mod tests { use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}; - use super::cookie_builder::get_last_time_extent; - use crate::protocol::clock::time_extent::Extent; + use super::cookie_builder::{self}; + use crate::protocol::clock::time_extent::{self, Extent}; use crate::protocol::clock::{StoppedClock, StoppedTime}; use crate::udp::connection_cookie::{check_connection_cookie, make_connection_cookie, Cookie, COOKIE_LIFETIME}; - fn make_test_socket_addr() -> SocketAddr { - SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080) + // #![feature(const_socketaddr)] + // const REMOTE_ADDRESS_IPV4_ZERO: SocketAddr = SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0); + + #[test] + fn it_should_make_a_connection_cookie() { + let cookie = make_connection_cookie(&SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0)); + + // Note: This constant may need to be updated in the future as the hash is not guaranteed to to be stable between versions. + const ID_COOKIE: Cookie = [23, 204, 198, 29, 48, 180, 62, 19]; + + assert_eq!(cookie, ID_COOKIE) } - fn make_test_cookie(remote_address: Option<&SocketAddr>) -> Cookie { - make_connection_cookie(remote_address.unwrap_or(&make_test_socket_addr())) + #[test] + fn it_should_make_the_same_connection_cookie_for_the_same_input_data() { + let remote_address = SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0); + let time_extent_zero = time_extent::ZERO; + + let cookie = cookie_builder::build(&remote_address, &time_extent_zero); + let cookie_2 = cookie_builder::build(&remote_address, &time_extent_zero); + + println!("remote_address: {remote_address:?}, time_extent: {time_extent_zero:?}, cookie: {cookie:?}"); + println!("remote_address: {remote_address:?}, time_extent: {time_extent_zero:?}, cookie: {cookie_2:?}"); + + //remote_address: 127.0.0.1:8080, time_extent: TimeExtent { increment: 0ns, amount: 0 }, cookie: [212, 9, 204, 223, 176, 190, 150, 153] + //remote_address: 127.0.0.1:8080, time_extent: TimeExtent { increment: 0ns, amount: 0 }, cookie: [212, 9, 204, 223, 176, 190, 150, 153] + + assert_eq!(cookie, cookie_2) } #[test] - fn it_should_make_a_connection_cookie() { - // remote_address: 127.0.0.1:8080, time_extent: 60, - // seed: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + fn it_should_make_the_different_connection_cookie_for_different_ip() { + let remote_address = SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0); + let remote_address_2 = SocketAddr::new(IpAddr::V4(Ipv4Addr::BROADCAST), 0); + let time_extent_zero = time_extent::ZERO; + + let cookie = cookie_builder::build(&remote_address, &time_extent_zero); + let cookie_2 = cookie_builder::build(&remote_address_2, &time_extent_zero); + + println!("remote_address: {remote_address:?}, time_extent: {time_extent_zero:?}, cookie: {cookie:?}"); + println!("remote_address: {remote_address_2:?}, time_extent: {time_extent_zero:?}, cookie: {cookie_2:?}"); + + //remote_address: 0.0.0.0:0, time_extent: TimeExtent { increment: 0ns, amount: 0 }, cookie: [151, 130, 30, 157, 190, 41, 179, 135] + //remote_address: 255.255.255.255:0, time_extent: TimeExtent { increment: 0ns, amount: 0 }, cookie: [217, 87, 239, 178, 182, 126, 66, 166] + + assert_ne!(cookie, cookie_2) + } + + #[test] + fn it_should_make_the_different_connection_cookie_for_different_ip_version() { + let remote_address = SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0); + let remote_address_2 = SocketAddr::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), 0); + let time_extent_zero = time_extent::ZERO; + + let cookie = cookie_builder::build(&remote_address, &time_extent_zero); + let cookie_2 = cookie_builder::build(&remote_address_2, &time_extent_zero); - const ID_COOKIE: Cookie = [45, 59, 50, 101, 97, 203, 48, 19]; + println!("remote_address: {remote_address:?}, time_extent: {time_extent_zero:?}, cookie: {cookie:?}"); + println!("remote_address: {remote_address_2:?}, time_extent: {time_extent_zero:?}, cookie: {cookie_2:?}"); - let test_cookie = make_test_cookie(None); - //println!("{test_cookie:?}"); + //remote_address: 0.0.0.0:0, time_extent: TimeExtent { increment: 0ns, amount: 0 }, cookie: [151, 130, 30, 157, 190, 41, 179, 135] + //remote_address: [::]:0, time_extent: TimeExtent { increment: 0ns, amount: 0 }, cookie: [99, 119, 230, 177, 20, 220, 163, 187] - assert_eq!(test_cookie, ID_COOKIE) + assert_ne!(cookie, cookie_2) } #[test] - fn it_should_make_different_connection_cookie_with_different_remote_addresses() { - let test_remote_address_1 = SocketAddr::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), 1); - let test_remote_address_2 = SocketAddr::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), 2); - let test_remote_address_3 = SocketAddr::new(IpAddr::V6(Ipv6Addr::LOCALHOST), 1); - - assert_ne!( - make_test_cookie(Some(&test_remote_address_1)), - make_test_cookie(Some(&test_remote_address_2)) - ); - - assert_ne!( - make_test_cookie(Some(&test_remote_address_1)), - make_test_cookie(Some(&test_remote_address_3)) - ); - - assert_ne!( - make_test_cookie(Some(&test_remote_address_2)), - make_test_cookie(Some(&test_remote_address_3)) - ) + fn it_should_make_the_different_connection_cookie_for_different_socket() { + let remote_address = SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0); + let remote_address_2 = SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 1); + let time_extent_zero = time_extent::ZERO; + + let cookie = cookie_builder::build(&remote_address, &time_extent_zero); + let cookie_2 = cookie_builder::build(&remote_address_2, &time_extent_zero); + + println!("remote_address: {remote_address:?}, time_extent: {time_extent_zero:?}, cookie: {cookie:?}"); + println!("remote_address: {remote_address_2:?}, time_extent: {time_extent_zero:?}, cookie: {cookie_2:?}"); + + //remote_address: 0.0.0.0:0, time_extent: TimeExtent { increment: 0ns, amount: 0 }, cookie: [151, 130, 30, 157, 190, 41, 179, 135] + //remote_address: 0.0.0.0:1, time_extent: TimeExtent { increment: 0ns, amount: 0 }, cookie: [38, 8, 0, 102, 92, 170, 220, 11] + + assert_ne!(cookie, cookie_2) + } + + #[test] + fn it_should_make_the_different_connection_cookie_for_different_time_extents() { + let remote_address = SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0); + let time_extent_zero = time_extent::ZERO; + let time_extent_max = time_extent::MAX; + + let cookie = cookie_builder::build(&remote_address, &time_extent_zero); + let cookie_2 = cookie_builder::build(&remote_address, &time_extent_max); + + println!("remote_address: {remote_address:?}, time_extent: {time_extent_zero:?}, cookie: {cookie:?}"); + println!("remote_address: {remote_address:?}, time_extent: {time_extent_max:?}, cookie: {cookie_2:?}"); + + //remote_address: 0.0.0.0:0, time_extent: TimeExtent { increment: 0ns, amount: 0 }, cookie: [151, 130, 30, 157, 190, 41, 179, 135] + //remote_address: 0.0.0.0:0, time_extent: TimeExtent { increment: 18446744073709551615.999999999s, amount: 18446744073709551615 }, cookie: [87, 111, 109, 125, 182, 206, 3, 201] + + assert_ne!(cookie, cookie_2) } #[test] fn it_should_make_different_cookies_for_the_next_time_extent() { - let cookie_now = make_test_cookie(None); + let remote_address = SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0); + + let cookie = make_connection_cookie(&remote_address); StoppedClock::local_add(&COOKIE_LIFETIME.increment).unwrap(); - let cookie_next = make_test_cookie(None); + let cookie_next = make_connection_cookie(&remote_address); - assert_ne!(cookie_now, cookie_next) + assert_ne!(cookie, cookie_next) } #[test] fn it_should_be_valid_for_this_time_extent() { - let cookie_now = make_test_cookie(None); + let remote_address = SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0); + + let cookie = make_connection_cookie(&remote_address); - check_connection_cookie(&make_test_socket_addr(), &cookie_now).unwrap(); + check_connection_cookie(&remote_address, &cookie).unwrap(); } #[test] fn it_should_be_valid_for_the_next_time_extent() { - let cookie_now = make_test_cookie(None); + let remote_address = SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0); + + let cookie = make_connection_cookie(&remote_address); StoppedClock::local_add(&COOKIE_LIFETIME.increment).unwrap(); - check_connection_cookie(&make_test_socket_addr(), &cookie_now).unwrap(); + check_connection_cookie(&remote_address, &cookie).unwrap(); } #[test] - fn it_cookies_should_be_valid_for_the_last_time_extent() { - let cookie_now = make_test_cookie(None); + fn it_should_be_valid_for_the_last_time_extent() { + let remote_address = SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0); + + let cookie = make_connection_cookie(&remote_address); StoppedClock::local_set(&COOKIE_LIFETIME.total().unwrap().unwrap()); - check_connection_cookie(&make_test_socket_addr(), &cookie_now).unwrap(); + check_connection_cookie(&remote_address, &cookie).unwrap(); } #[test] #[should_panic] - fn it_cookies_should_be_not_valid_after_their_last_time_extent() { - let cookie_now = make_test_cookie(None); + fn it_should_be_not_valid_after_their_last_time_extent() { + let remote_address = SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0); - let last_time_extent = get_last_time_extent().increase(COOKIE_LIFETIME.amount).unwrap(); + let cookie = make_connection_cookie(&remote_address); - StoppedClock::local_set(&last_time_extent.total_next().unwrap().unwrap()); + StoppedClock::local_set(&COOKIE_LIFETIME.total_next().unwrap().unwrap()); - check_connection_cookie(&make_test_socket_addr(), &cookie_now).unwrap(); + check_connection_cookie(&remote_address, &cookie).unwrap(); } }