mirror of
https://github.com/YGGverse/aquatic.git
synced 2026-03-31 17:55:36 +00:00
udp: start work on HMAC connection ID generation and validation
This commit is contained in:
parent
26e2e87437
commit
dc4523ede5
4 changed files with 124 additions and 13 deletions
37
Cargo.lock
generated
37
Cargo.lock
generated
|
|
@ -209,8 +209,10 @@ dependencies = [
|
|||
"aquatic_common",
|
||||
"aquatic_toml_config",
|
||||
"aquatic_udp_protocol",
|
||||
"blake3",
|
||||
"cfg-if",
|
||||
"crossbeam-channel",
|
||||
"getrandom",
|
||||
"hex",
|
||||
"log",
|
||||
"mimalloc",
|
||||
|
|
@ -350,6 +352,12 @@ version = "1.5.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c5d78ce20460b82d3fa150275ed9d55e21064fc7951177baacf86a145c4a4b1f"
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.4.12"
|
||||
|
|
@ -359,6 +367,12 @@ dependencies = [
|
|||
"nodrop",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.53"
|
||||
|
|
@ -524,6 +538,20 @@ version = "3.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "303cec55cd9c5fde944b061b902f142b52a8bb5438cc822481ea1e3ebc96bbcb"
|
||||
|
||||
[[package]]
|
||||
name = "blake3"
|
||||
version = "1.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a08e53fc5a564bb15bfe6fae56bd71522205f1f91893f9c0116edad6496c183f"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"arrayvec 0.7.2",
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"constant_time_eq",
|
||||
"digest 0.10.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.9.0"
|
||||
|
|
@ -655,6 +683,12 @@ version = "0.6.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d6f2aa4d0537bcc1c74df8755072bd31c1ef1a3a1b85a68e8404a8c353b7b8b"
|
||||
|
||||
[[package]]
|
||||
name = "constant_time_eq"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.2"
|
||||
|
|
@ -854,6 +888,7 @@ checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506"
|
|||
dependencies = [
|
||||
"block-buffer 0.10.2",
|
||||
"crypto-common",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1756,7 +1791,7 @@ version = "0.4.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bafe4179722c2894288ee77a9f044f02811c86af699344c498b0840c698a2465"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"arrayvec 0.4.12",
|
||||
"itoa 0.4.8",
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -24,8 +24,10 @@ aquatic_toml_config = { version = "0.2.0", path = "../aquatic_toml_config" }
|
|||
aquatic_udp_protocol = { version = "0.2.0", path = "../aquatic_udp_protocol" }
|
||||
|
||||
anyhow = "1"
|
||||
blake3 = { version = "1", features = ["traits-preview"] }
|
||||
cfg-if = "1"
|
||||
crossbeam-channel = "0.5"
|
||||
getrandom = "0.2"
|
||||
hex = "0.4"
|
||||
log = "0.4"
|
||||
mimalloc = { version = "0.1", default-features = false }
|
||||
|
|
|
|||
|
|
@ -1,19 +1,94 @@
|
|||
use std::collections::BTreeMap;
|
||||
use std::hash::Hash;
|
||||
use std::net::{Ipv4Addr, Ipv6Addr};
|
||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
|
||||
use std::sync::atomic::AtomicUsize;
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use aquatic_common::CanonicalSocketAddr;
|
||||
use crossbeam_channel::{Sender, TrySendError};
|
||||
use getrandom::getrandom;
|
||||
|
||||
use aquatic_common::access_list::AccessListArcSwap;
|
||||
use aquatic_common::CanonicalSocketAddr;
|
||||
use aquatic_udp_protocol::*;
|
||||
|
||||
use crate::config::Config;
|
||||
|
||||
pub const MAX_PACKET_SIZE: usize = 8192;
|
||||
|
||||
pub struct ConnectionIdHandler {
|
||||
start_time: Instant,
|
||||
max_connection_age: Duration,
|
||||
hmac: blake3::Hasher,
|
||||
}
|
||||
|
||||
impl ConnectionIdHandler {
|
||||
pub fn new(config: &Config) -> anyhow::Result<Self> {
|
||||
let mut key = [0; 32];
|
||||
|
||||
getrandom(&mut key)?;
|
||||
|
||||
let hmac = blake3::Hasher::new_keyed(&key);
|
||||
|
||||
let start_time = Instant::now();
|
||||
let max_connection_age = Duration::from_secs(config.cleaning.max_connection_age);
|
||||
|
||||
Ok(Self {
|
||||
hmac,
|
||||
start_time,
|
||||
max_connection_age,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn create_connection_id(&mut self, source_ip: IpAddr) -> ConnectionId {
|
||||
// Seconds elapsed since server start, as bytes
|
||||
let elapsed_time_bytes = (self.start_time.elapsed().as_secs() as u32).to_ne_bytes();
|
||||
|
||||
self.create_connection_id_inner(elapsed_time_bytes, source_ip)
|
||||
}
|
||||
|
||||
pub fn connection_id_valid(&mut self, source_ip: IpAddr, connection_id: ConnectionId) -> bool {
|
||||
let elapsed_time_bytes = connection_id.0.to_ne_bytes()[..4].try_into().unwrap();
|
||||
|
||||
// i64 comparison should be constant-time
|
||||
let hmac_valid =
|
||||
connection_id == self.create_connection_id_inner(elapsed_time_bytes, source_ip);
|
||||
|
||||
if !hmac_valid {
|
||||
return false;
|
||||
}
|
||||
|
||||
let connection_elapsed_since_start =
|
||||
Duration::from_secs(u32::from_ne_bytes(elapsed_time_bytes) as u64);
|
||||
|
||||
connection_elapsed_since_start + self.max_connection_age > self.start_time.elapsed()
|
||||
}
|
||||
|
||||
fn create_connection_id_inner(
|
||||
&mut self,
|
||||
elapsed_time_bytes: [u8; 4],
|
||||
source_ip: IpAddr,
|
||||
) -> ConnectionId {
|
||||
// The first 4 bytes is the elapsed time since server start in seconds. The last 4 is a
|
||||
// truncated message authentication code.
|
||||
let mut connection_id_bytes = [0u8; 8];
|
||||
|
||||
(&mut connection_id_bytes[..4]).copy_from_slice(&elapsed_time_bytes);
|
||||
|
||||
self.hmac.update(&elapsed_time_bytes);
|
||||
|
||||
match source_ip {
|
||||
IpAddr::V4(ip) => self.hmac.update(&ip.octets()),
|
||||
IpAddr::V6(ip) => self.hmac.update(&ip.octets()),
|
||||
};
|
||||
|
||||
self.hmac.finalize_xof().fill(&mut connection_id_bytes[4..]);
|
||||
self.hmac.reset();
|
||||
|
||||
ConnectionId(i64::from_ne_bytes(connection_id_bytes))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PendingScrapeRequest {
|
||||
pub slab_key: usize,
|
||||
|
|
|
|||
|
|
@ -2,25 +2,24 @@ pub mod common;
|
|||
pub mod config;
|
||||
pub mod workers;
|
||||
|
||||
use aquatic_common::PanicSentinelWatcher;
|
||||
use config::Config;
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::thread::Builder;
|
||||
|
||||
use anyhow::Context;
|
||||
#[cfg(feature = "cpu-pinning")]
|
||||
use aquatic_common::cpu_pinning::{pin_current_if_configured_to, WorkerIndex};
|
||||
use aquatic_common::privileges::PrivilegeDropper;
|
||||
use crossbeam_channel::{bounded, unbounded};
|
||||
|
||||
use aquatic_common::access_list::update_access_list;
|
||||
use signal_hook::consts::{SIGTERM, SIGUSR1};
|
||||
use signal_hook::iterator::Signals;
|
||||
|
||||
use common::{ConnectedRequestSender, ConnectedResponseSender, SocketWorkerIndex, State};
|
||||
use aquatic_common::access_list::update_access_list;
|
||||
#[cfg(feature = "cpu-pinning")]
|
||||
use aquatic_common::cpu_pinning::{pin_current_if_configured_to, WorkerIndex};
|
||||
use aquatic_common::privileges::PrivilegeDropper;
|
||||
use aquatic_common::PanicSentinelWatcher;
|
||||
|
||||
use crate::common::RequestWorkerIndex;
|
||||
use common::{
|
||||
ConnectedRequestSender, ConnectedResponseSender, RequestWorkerIndex, SocketWorkerIndex, State,
|
||||
};
|
||||
use config::Config;
|
||||
|
||||
pub const APP_NAME: &str = "aquatic_udp: UDP BitTorrent tracker";
|
||||
pub const APP_VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue