Skip to content

Commit 8c70395

Browse files
committed
udp: various changes
- remove old logging module - remove udp test for private mode - check `ConnectionID` for scrape - check `ConnectionID` when included in badly formatted responses - pass-through any errors when parsing a response
1 parent b827c31 commit 8c70395

File tree

14 files changed

+288
-320
lines changed

14 files changed

+288
-320
lines changed

cSpell.json

+1
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@
164164
"typenum",
165165
"Unamed",
166166
"underflows",
167+
"Unsendable",
167168
"untuple",
168169
"uroot",
169170
"Vagaa",

src/core/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,7 @@ use torrust_tracker_primitives::torrent_metrics::TorrentsMetrics;
470470
use torrust_tracker_primitives::{peer, DurationSinceUnixEpoch};
471471
use torrust_tracker_torrent_repository::entry::EntrySync;
472472
use torrust_tracker_torrent_repository::repository::Repository;
473+
use tracing::instrument;
473474

474475
use self::auth::Key;
475476
use self::error::Error;
@@ -1092,6 +1093,7 @@ impl Tracker {
10921093
///
10931094
/// Will return an error if the tracker is running in `listed` mode
10941095
/// and the infohash is not whitelisted.
1096+
#[instrument(skip(self, info_hash), err)]
10951097
pub async fn authorize(&self, info_hash: &InfoHash) -> Result<(), Error> {
10961098
if !self.is_listed() {
10971099
return Ok(());

src/core/services/statistics/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,11 @@ pub async fn get_metrics(tracker: Arc<Tracker>) -> TrackerMetrics {
7676
udp4_connections_handled: stats.udp4_connections_handled,
7777
udp4_announces_handled: stats.udp4_announces_handled,
7878
udp4_scrapes_handled: stats.udp4_scrapes_handled,
79+
udp4_errors_handled: stats.udp4_errors_handled,
7980
udp6_connections_handled: stats.udp6_connections_handled,
8081
udp6_announces_handled: stats.udp6_announces_handled,
8182
udp6_scrapes_handled: stats.udp6_scrapes_handled,
83+
udp6_errors_handled: stats.udp6_errors_handled,
8284
},
8385
}
8486
}

src/core/statistics.rs

+24
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,11 @@ pub enum Event {
4747
Udp4Connect,
4848
Udp4Announce,
4949
Udp4Scrape,
50+
Udp4Error,
5051
Udp6Connect,
5152
Udp6Announce,
5253
Udp6Scrape,
54+
Udp6Error,
5355
}
5456

5557
/// Metrics collected by the tracker.
@@ -82,12 +84,16 @@ pub struct Metrics {
8284
pub udp4_announces_handled: u64,
8385
/// Total number of UDP (UDP tracker) `scrape` requests from IPv4 peers.
8486
pub udp4_scrapes_handled: u64,
87+
/// Total number of UDP (UDP tracker) `error` requests from IPv4 peers.
88+
pub udp4_errors_handled: u64,
8589
/// Total number of UDP (UDP tracker) `connection` requests from IPv6 peers.
8690
pub udp6_connections_handled: u64,
8791
/// Total number of UDP (UDP tracker) `announce` requests from IPv6 peers.
8892
pub udp6_announces_handled: u64,
8993
/// Total number of UDP (UDP tracker) `scrape` requests from IPv6 peers.
9094
pub udp6_scrapes_handled: u64,
95+
/// Total number of UDP (UDP tracker) `error` requests from IPv6 peers.
96+
pub udp6_errors_handled: u64,
9197
}
9298

9399
/// The service responsible for keeping tracker metrics (listening to statistics events and handle them).
@@ -168,6 +174,9 @@ async fn event_handler(event: Event, stats_repository: &Repo) {
168174
Event::Udp4Scrape => {
169175
stats_repository.increase_udp4_scrapes().await;
170176
}
177+
Event::Udp4Error => {
178+
stats_repository.increase_udp4_errors().await;
179+
}
171180

172181
// UDP6
173182
Event::Udp6Connect => {
@@ -179,6 +188,9 @@ async fn event_handler(event: Event, stats_repository: &Repo) {
179188
Event::Udp6Scrape => {
180189
stats_repository.increase_udp6_scrapes().await;
181190
}
191+
Event::Udp6Error => {
192+
stats_repository.increase_udp6_errors().await;
193+
}
182194
}
183195

184196
tracing::debug!("stats: {:?}", stats_repository.get_stats().await);
@@ -282,6 +294,12 @@ impl Repo {
282294
drop(stats_lock);
283295
}
284296

297+
pub async fn increase_udp4_errors(&self) {
298+
let mut stats_lock = self.stats.write().await;
299+
stats_lock.udp4_errors_handled += 1;
300+
drop(stats_lock);
301+
}
302+
285303
pub async fn increase_udp6_connections(&self) {
286304
let mut stats_lock = self.stats.write().await;
287305
stats_lock.udp6_connections_handled += 1;
@@ -299,6 +317,12 @@ impl Repo {
299317
stats_lock.udp6_scrapes_handled += 1;
300318
drop(stats_lock);
301319
}
320+
321+
pub async fn increase_udp6_errors(&self) {
322+
let mut stats_lock = self.stats.write().await;
323+
stats_lock.udp6_errors_handled += 1;
324+
drop(stats_lock);
325+
}
302326
}
303327

304328
#[cfg(test)]

src/servers/apis/v1/context/stats/resources.rs

+16-6
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,16 @@ pub struct Stats {
3838
pub udp4_announces_handled: u64,
3939
/// Total number of UDP (UDP tracker) `scrape` requests from IPv4 peers.
4040
pub udp4_scrapes_handled: u64,
41+
/// Total number of UDP (UDP tracker) `scrape` requests from IPv4 peers.
42+
pub udp4_errors_handled: u64,
4143
/// Total number of UDP (UDP tracker) `connection` requests from IPv6 peers.
4244
pub udp6_connections_handled: u64,
4345
/// Total number of UDP (UDP tracker) `announce` requests from IPv6 peers.
4446
pub udp6_announces_handled: u64,
4547
/// Total number of UDP (UDP tracker) `scrape` requests from IPv6 peers.
4648
pub udp6_scrapes_handled: u64,
49+
/// Total number of UDP (UDP tracker) `scrape` requests from IPv6 peers.
50+
pub udp6_errors_handled: u64,
4751
}
4852

4953
impl From<TrackerMetrics> for Stats {
@@ -62,9 +66,11 @@ impl From<TrackerMetrics> for Stats {
6266
udp4_connections_handled: metrics.protocol_metrics.udp4_connections_handled,
6367
udp4_announces_handled: metrics.protocol_metrics.udp4_announces_handled,
6468
udp4_scrapes_handled: metrics.protocol_metrics.udp4_scrapes_handled,
69+
udp4_errors_handled: metrics.protocol_metrics.udp4_errors_handled,
6570
udp6_connections_handled: metrics.protocol_metrics.udp6_connections_handled,
6671
udp6_announces_handled: metrics.protocol_metrics.udp6_announces_handled,
6772
udp6_scrapes_handled: metrics.protocol_metrics.udp6_scrapes_handled,
73+
udp6_errors_handled: metrics.protocol_metrics.udp6_errors_handled,
6874
}
6975
}
7076
}
@@ -97,9 +103,11 @@ mod tests {
97103
udp4_connections_handled: 11,
98104
udp4_announces_handled: 12,
99105
udp4_scrapes_handled: 13,
100-
udp6_connections_handled: 14,
101-
udp6_announces_handled: 15,
102-
udp6_scrapes_handled: 16
106+
udp4_errors_handled: 14,
107+
udp6_connections_handled: 15,
108+
udp6_announces_handled: 16,
109+
udp6_scrapes_handled: 17,
110+
udp6_errors_handled: 18
103111
}
104112
}),
105113
Stats {
@@ -116,9 +124,11 @@ mod tests {
116124
udp4_connections_handled: 11,
117125
udp4_announces_handled: 12,
118126
udp4_scrapes_handled: 13,
119-
udp6_connections_handled: 14,
120-
udp6_announces_handled: 15,
121-
udp6_scrapes_handled: 16
127+
udp4_errors_handled: 14,
128+
udp6_connections_handled: 15,
129+
udp6_announces_handled: 16,
130+
udp6_scrapes_handled: 17,
131+
udp6_errors_handled: 18
122132
}
123133
);
124134
}

src/servers/udp/connection_cookie.rs

+16-11
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@
7979
8080
use aquatic_udp_protocol::ConnectionId as Cookie;
8181
use cookie_builder::{assemble, decode, disassemble, encode};
82+
use tracing::instrument;
8283
use zerocopy::AsBytes;
8384

8485
use super::error::Error;
@@ -94,9 +95,12 @@ use crate::shared::crypto::keys::CipherArrayBlowfish;
9495
///
9596
/// It would panic if the cookie is not exactly 8 bytes is size.
9697
///
98+
#[instrument(err)]
9799
pub fn make(fingerprint: u64, issue_at: f64) -> Result<Cookie, Error> {
98100
if !issue_at.is_normal() {
99-
return Err(Error::InvalidCookieIssueTime { invalid_value: issue_at });
101+
return Err(Error::CookieValueNotNormal {
102+
not_normal_value: issue_at,
103+
});
100104
}
101105

102106
let cookie = assemble(fingerprint, issue_at);
@@ -117,6 +121,7 @@ use std::ops::Range;
117121
/// # Panics
118122
///
119123
/// It would panic if the range start is not smaller than it's end.
124+
#[instrument(err)]
120125
pub fn check(cookie: &Cookie, fingerprint: u64, valid_range: Range<f64>) -> Result<f64, Error> {
121126
assert!(valid_range.start <= valid_range.end, "range start is larger than range end");
122127

@@ -126,20 +131,20 @@ pub fn check(cookie: &Cookie, fingerprint: u64, valid_range: Range<f64>) -> Resu
126131
let issue_time = disassemble(fingerprint, cookie_bytes);
127132

128133
if !issue_time.is_normal() {
129-
return Err(Error::ConnectionIdNotNormal {
134+
return Err(Error::CookieValueNotNormal {
130135
not_normal_value: issue_time,
131136
});
132137
}
133138

134139
if issue_time < valid_range.start {
135-
return Err(Error::ConnectionIdExpired {
140+
return Err(Error::CookieValueExpired {
136141
expired_value: issue_time,
137142
min_value: valid_range.start,
138143
});
139144
}
140145

141146
if issue_time > valid_range.end {
142-
return Err(Error::ConnectionIdFromFuture {
147+
return Err(Error::CookieValueFromFuture {
143148
future_value: issue_time,
144149
max_value: valid_range.end,
145150
});
@@ -150,15 +155,15 @@ pub fn check(cookie: &Cookie, fingerprint: u64, valid_range: Range<f64>) -> Resu
150155

151156
mod cookie_builder {
152157
use cipher::{BlockDecrypt, BlockEncrypt};
153-
use tracing::{instrument, Level};
158+
use tracing::instrument;
154159
use zerocopy::{byteorder, AsBytes as _, NativeEndian};
155160

156161
pub type CookiePlainText = CipherArrayBlowfish;
157162
pub type CookieCipherText = CipherArrayBlowfish;
158163

159164
use crate::shared::crypto::keys::{CipherArrayBlowfish, Current, Keeper};
160165

161-
#[instrument(ret(level = Level::TRACE))]
166+
#[instrument()]
162167
pub(super) fn assemble(fingerprint: u64, issue_at: f64) -> CookiePlainText {
163168
let issue_at: byteorder::I64<NativeEndian> =
164169
*zerocopy::FromBytes::ref_from(&issue_at.to_ne_bytes()).expect("it should be aligned");
@@ -172,7 +177,7 @@ mod cookie_builder {
172177
*CipherArrayBlowfish::from_slice(cookie.as_bytes())
173178
}
174179

175-
#[instrument(ret(level = Level::TRACE))]
180+
#[instrument()]
176181
pub(super) fn disassemble(fingerprint: u64, cookie: CookiePlainText) -> f64 {
177182
let fingerprint: byteorder::I64<NativeEndian> =
178183
*zerocopy::FromBytes::ref_from(&fingerprint.to_ne_bytes()).expect("it should be aligned");
@@ -189,7 +194,7 @@ mod cookie_builder {
189194
issue_time.get()
190195
}
191196

192-
#[instrument(ret(level = Level::TRACE))]
197+
#[instrument()]
193198
pub(super) fn encode(mut cookie: CookiePlainText) -> CookieCipherText {
194199
let cipher = Current::get_cipher_blowfish();
195200

@@ -198,7 +203,7 @@ mod cookie_builder {
198203
cookie
199204
}
200205

201-
#[instrument(ret(level = Level::TRACE))]
206+
#[instrument()]
202207
pub(super) fn decode(mut cookie: CookieCipherText) -> CookiePlainText {
203208
let cipher = Current::get_cipher_blowfish();
204209

@@ -282,7 +287,7 @@ mod tests {
282287
let result = check(&cookie, fingerprint, min..max).unwrap_err();
283288

284289
match result {
285-
Error::ConnectionIdExpired { .. } => {} // Expected error
290+
Error::CookieValueExpired { .. } => {} // Expected error
286291
_ => panic!("Expected ConnectionIdExpired error"),
287292
}
288293
}
@@ -300,7 +305,7 @@ mod tests {
300305
let result = check(&cookie, fingerprint, min..max).unwrap_err();
301306

302307
match result {
303-
Error::ConnectionIdFromFuture { .. } => {} // Expected error
308+
Error::CookieValueFromFuture { .. } => {} // Expected error
304309
_ => panic!("Expected ConnectionIdFromFuture error"),
305310
}
306311
}

src/servers/udp/error.rs

+15-9
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Error types for the UDP server.
22
use std::panic::Location;
33

4-
use aquatic_udp_protocol::ConnectionId;
4+
use aquatic_udp_protocol::{ConnectionId, RequestParseError};
55
use derive_more::derive::Display;
66
use thiserror::Error;
77
use torrust_tracker_located_error::LocatedError;
@@ -13,17 +13,17 @@ pub struct ConnectionCookie(pub ConnectionId);
1313
/// Error returned by the UDP server.
1414
#[derive(Error, Debug)]
1515
pub enum Error {
16-
#[error("the issue time should be a normal floating point number")]
17-
InvalidCookieIssueTime { invalid_value: f64 },
16+
#[error("cookie value is not normal: {not_normal_value}")]
17+
CookieValueNotNormal { not_normal_value: f64 },
1818

19-
#[error("connection id did not produce a normal value")]
20-
ConnectionIdNotNormal { not_normal_value: f64 },
19+
#[error("cookie value is expired: {expired_value}, expected > {min_value}")]
20+
CookieValueExpired { expired_value: f64, min_value: f64 },
2121

22-
#[error("connection id produced an expired value")]
23-
ConnectionIdExpired { expired_value: f64, min_value: f64 },
22+
#[error("cookie value is from future: {future_value}, expected < {max_value}")]
23+
CookieValueFromFuture { future_value: f64, max_value: f64 },
2424

25-
#[error("connection id produces a future value")]
26-
ConnectionIdFromFuture { future_value: f64, max_value: f64 },
25+
#[error("error when phrasing request: {request_parse_error:?}")]
26+
RequestParseError { request_parse_error: RequestParseError },
2727

2828
/// Error returned when the domain tracker returns an error.
2929
#[error("tracker server error: {source}")]
@@ -48,3 +48,9 @@ pub enum Error {
4848
#[error("domain tracker requires authentication but is not supported in current UDP implementation. Location: {location}")]
4949
TrackerAuthenticationRequired { location: &'static Location<'static> },
5050
}
51+
52+
impl From<RequestParseError> for Error {
53+
fn from(request_parse_error: RequestParseError) -> Self {
54+
Self::RequestParseError { request_parse_error }
55+
}
56+
}

0 commit comments

Comments
 (0)