mirror of
https://github.com/YGGverse/aquatic.git
synced 2026-03-31 17:55:36 +00:00
udp: add ConnectionValidator.update_elapsed, call regularly
This is faster than doing it for each request
This commit is contained in:
parent
94247b8e35
commit
680da048b8
4 changed files with 25 additions and 17 deletions
3
TODO.md
3
TODO.md
|
|
@ -2,9 +2,6 @@
|
|||
|
||||
## High priority
|
||||
|
||||
* udp
|
||||
* make ConnectionValidator faster by avoiding calling time functions so often
|
||||
|
||||
## Medium priority
|
||||
|
||||
* stagger cleaning tasks?
|
||||
|
|
|
|||
|
|
@ -98,6 +98,8 @@ impl SocketWorker {
|
|||
}
|
||||
|
||||
if iter_counter % 256 == 0 {
|
||||
self.validator.update_elapsed();
|
||||
|
||||
self.peer_valid_until = ValidUntil::new(
|
||||
self.shared_state.server_start_instant,
|
||||
self.config.cleaning.max_peer_age,
|
||||
|
|
|
|||
|
|
@ -134,9 +134,10 @@ impl SocketWorker {
|
|||
|
||||
let recv_sqe = recv_helper.create_entry(buf_ring.bgid());
|
||||
|
||||
// This timeout enables regular updates of peer_valid_until
|
||||
// This timeout enables regular updates of ConnectionValidator and
|
||||
// peer_valid_until
|
||||
let pulse_timeout_sqe = {
|
||||
let timespec_ptr = Box::into_raw(Box::new(Timespec::new().sec(1))) as *const _;
|
||||
let timespec_ptr = Box::into_raw(Box::new(Timespec::new().sec(5))) as *const _;
|
||||
|
||||
Timeout::new(timespec_ptr)
|
||||
.build()
|
||||
|
|
@ -238,6 +239,8 @@ impl SocketWorker {
|
|||
}
|
||||
}
|
||||
USER_DATA_PULSE_TIMEOUT => {
|
||||
self.validator.update_elapsed();
|
||||
|
||||
self.peer_valid_until = ValidUntil::new(
|
||||
self.shared_state.server_start_instant,
|
||||
self.config.cleaning.max_peer_age,
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ use crate::config::Config;
|
|||
|
||||
/// HMAC (BLAKE3) based ConnectionId creator and validator
|
||||
///
|
||||
/// Method update_elapsed must be called at least once a minute.
|
||||
///
|
||||
/// The purpose of using ConnectionIds is to make IP spoofing costly, mainly to
|
||||
/// prevent the tracker from being used as an amplification vector for DDoS
|
||||
/// attacks. By including 32 bits of BLAKE3 keyed hash output in the Ids, an
|
||||
|
|
@ -32,6 +34,7 @@ pub struct ConnectionValidator {
|
|||
start_time: Instant,
|
||||
max_connection_age: u64,
|
||||
keyed_hasher: blake3::Hasher,
|
||||
seconds_since_start: u32,
|
||||
}
|
||||
|
||||
impl ConnectionValidator {
|
||||
|
|
@ -49,11 +52,12 @@ impl ConnectionValidator {
|
|||
keyed_hasher,
|
||||
start_time: Instant::now(),
|
||||
max_connection_age: config.cleaning.max_connection_age.into(),
|
||||
seconds_since_start: 0,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn create_connection_id(&mut self, source_addr: CanonicalSocketAddr) -> ConnectionId {
|
||||
let elapsed = (self.start_time.elapsed().as_secs() as u32).to_ne_bytes();
|
||||
let elapsed = (self.seconds_since_start).to_ne_bytes();
|
||||
|
||||
let hash = self.hash(elapsed, source_addr.get().ip());
|
||||
|
||||
|
|
@ -78,16 +82,23 @@ impl ConnectionValidator {
|
|||
return false;
|
||||
}
|
||||
|
||||
let tracker_elapsed = self.start_time.elapsed().as_secs();
|
||||
let seconds_since_start = self.seconds_since_start as u64;
|
||||
let client_elapsed = u64::from(u32::from_ne_bytes(elapsed));
|
||||
let client_expiration_time = client_elapsed + self.max_connection_age;
|
||||
|
||||
// In addition to checking if the client connection is expired,
|
||||
// disallow client_elapsed values that are in future and thus could not
|
||||
// have been sent by the tracker. This prevents brute forcing with
|
||||
// `u32::MAX` as 'elapsed' part of ConnectionId to find a hash that
|
||||
// disallow client_elapsed values that are too far in future and thus
|
||||
// could not have been sent by the tracker. This prevents brute forcing
|
||||
// with `u32::MAX` as 'elapsed' part of ConnectionId to find a hash that
|
||||
// works until the tracker is restarted.
|
||||
(client_expiration_time > tracker_elapsed) & (client_elapsed <= tracker_elapsed)
|
||||
let client_not_expired = client_expiration_time > seconds_since_start;
|
||||
let client_elapsed_not_in_far_future = client_elapsed <= (seconds_since_start + 60);
|
||||
|
||||
client_not_expired & client_elapsed_not_in_far_future
|
||||
}
|
||||
|
||||
pub fn update_elapsed(&mut self) {
|
||||
self.seconds_since_start = self.start_time.elapsed().as_secs() as u32;
|
||||
}
|
||||
|
||||
fn hash(&mut self, elapsed: [u8; 4], ip_addr: IpAddr) -> [u8; 4] {
|
||||
|
|
@ -145,11 +156,6 @@ mod tests {
|
|||
return quickcheck::TestResult::failed();
|
||||
}
|
||||
|
||||
if max_connection_age == 0 {
|
||||
quickcheck::TestResult::from_bool(!original_valid)
|
||||
} else {
|
||||
// Note: depends on that running this test takes less than a second
|
||||
quickcheck::TestResult::from_bool(original_valid)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue