From 8c4171ba143b882f1c964c78433fd28f8a61ecdd Mon Sep 17 00:00:00 2001 From: EAimTY Date: Sun, 5 Feb 2023 22:26:31 +0900 Subject: [PATCH] implement new auth method for server --- tuic-server/Cargo.toml | 7 ++++--- tuic-server/src/config.rs | 21 ++++++++++++++++--- tuic-server/src/main.rs | 5 +++-- tuic-server/src/server.rs | 44 +++++++++++++++++++++------------------ 4 files changed, 49 insertions(+), 28 deletions(-) diff --git a/tuic-server/Cargo.toml b/tuic-server/Cargo.toml index b244f8a..6b1dc5e 100644 --- a/tuic-server/Cargo.toml +++ b/tuic-server/Cargo.toml @@ -13,10 +13,11 @@ register-count = { version = "0.1.0", default-features = false, features = ["std rustls = { version = "0.20.8", default-features = false, features = ["quic"] } rustls-pemfile = { version = "1.0.2", default-features = false } serde = { version = "1.0.152", default-features = false, features = ["derive", "std"] } -serde_json = { version = "1.0.91", default-features = false, features = ["std"] } +serde_json = { version = "1.0.92", default-features = false, features = ["std"] } socket2 = { version = "0.4.7", default-features = false } thiserror = { version = "1.0.38", default-features = false } tokio = { version = "1.25.0", default-features = false, features = ["macros", "net", "parking_lot", "rt-multi-thread", "time"] } tokio-util = { version = "0.7.4", default-features = false, features = ["compat"] } -tuic = { path = "../tuic", default-features = false } -tuic-quinn = { path = "../tuic-quinn", default-features = false } \ No newline at end of file +tuic = { version = "5.0.0-pre-alpha6", default-features = false } +tuic-quinn = { version = "0.1.0-pre-alpha2", default-features = false } +uuid = { version = "1.3.0", default-features = false, features = ["serde", "std"] } diff --git a/tuic-server/src/config.rs b/tuic-server/src/config.rs index 89ff4e1..d08c1a2 100644 --- a/tuic-server/src/config.rs +++ b/tuic-server/src/config.rs @@ -3,10 +3,11 @@ use lexopt::{Arg, Error as ArgumentError, Parser}; use serde::{de::Error as DeError, Deserialize, Deserializer}; use serde_json::Error as SerdeError; use std::{ - env::ArgsOs, fmt::Display, fs::File, io::Error as IoError, net::SocketAddr, path::PathBuf, - str::FromStr, time::Duration, + collections::HashMap, env::ArgsOs, fmt::Display, fs::File, io::Error as IoError, + net::SocketAddr, path::PathBuf, str::FromStr, time::Duration, }; use thiserror::Error; +use uuid::Uuid; const HELP_MSG: &str = r#" Usage tuic-server [arguments] @@ -21,7 +22,8 @@ Arguments: #[serde(deny_unknown_fields)] pub struct Config { pub server: SocketAddr, - pub token: String, + #[serde(deserialize_with = "deserialize_users")] + pub users: HashMap, pub certificate: PathBuf, pub private_key: PathBuf, #[serde( @@ -130,6 +132,19 @@ where T::from_str(&s).map_err(DeError::custom) } +pub fn deserialize_users<'de, D>(deserializer: D) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + let map = HashMap::::deserialize(deserializer)?; + + if map.is_empty() { + return Err(DeError::custom("users cannot be empty")); + } + + Ok(map) +} + #[derive(Debug, Error)] pub enum ConfigError { #[error(transparent)] diff --git a/tuic-server/src/main.rs b/tuic-server/src/main.rs index 31745c2..2021912 100644 --- a/tuic-server/src/main.rs +++ b/tuic-server/src/main.rs @@ -8,6 +8,7 @@ use std::{env, io::Error as IoError, net::SocketAddr, process}; use thiserror::Error; use tuic::Address; use tuic_quinn::Error as ModelError; +use uuid::Uuid; mod config; mod server; @@ -52,8 +53,8 @@ pub enum Error { DuplicatedAuth, #[error("token length too short")] ExportKeyingMaterial, - #[error("authentication failed")] - AuthFailed, + #[error("authentication failed: {0}")] + AuthFailed(Uuid), #[error("received packet from unexpected source")] UnexpectedPacketSource, #[error("{0} resolved to {1} but IPv6 UDP relay disabled")] diff --git a/tuic-server/src/server.rs b/tuic-server/src/server.rs index 8847248..1f35e56 100644 --- a/tuic-server/src/server.rs +++ b/tuic-server/src/server.rs @@ -39,12 +39,13 @@ use tokio::{ use tokio_util::compat::FuturesAsyncReadCompatExt; use tuic::Address; use tuic_quinn::{side, Connect, Connection as Model, Packet, Task}; +use uuid::Uuid; const DEFAULT_CONCURRENT_STREAMS: usize = 32; pub struct Server { ep: Endpoint, - token: Arc<[u8]>, + users: Arc>>, udp_relay_ipv6: bool, zero_rtt_handshake: bool, auth_timeout: Duration, @@ -115,9 +116,15 @@ impl Server { TokioRuntime, )?; + let users = cfg + .users + .into_iter() + .map(|(uuid, password)| (uuid, password.into_bytes())) + .collect(); + Ok(Self { ep, - token: Arc::from(cfg.token.into_bytes().into_boxed_slice()), + users: Arc::new(users), udp_relay_ipv6: cfg.udp_relay_ipv6, zero_rtt_handshake: cfg.zero_rtt_handshake, auth_timeout: cfg.auth_timeout, @@ -133,7 +140,7 @@ impl Server { tokio::spawn(Connection::handle( conn, - self.token.clone(), + self.users.clone(), self.udp_relay_ipv6, self.zero_rtt_handshake, self.auth_timeout, @@ -149,7 +156,7 @@ impl Server { struct Connection { inner: QuinnConnection, model: Model, - token: Arc<[u8]>, + users: Arc>>, udp_relay_ipv6: bool, is_authed: IsAuthed, udp_sessions: Arc>>, @@ -165,7 +172,7 @@ struct Connection { impl Connection { async fn handle( conn: Connecting, - token: Arc<[u8]>, + users: Arc>>, udp_relay_ipv6: bool, zero_rtt_handshake: bool, auth_timeout: Duration, @@ -175,7 +182,7 @@ impl Connection { ) { match Self::init( conn, - token, + users, udp_relay_ipv6, zero_rtt_handshake, max_external_pkt_size, @@ -203,7 +210,7 @@ impl Connection { async fn init( conn: Connecting, - token: Arc<[u8]>, + users: Arc>>, udp_relay_ipv6: bool, zero_rtt_handshake: bool, max_external_pkt_size: usize, @@ -223,7 +230,7 @@ impl Connection { Ok(Self { inner: conn.clone(), model: Model::::new(conn), - token, + users, udp_relay_ipv6, is_authed: IsAuthed::new(), udp_sessions: Arc::new(AsyncMutex::new(HashMap::new())), @@ -263,21 +270,17 @@ impl Connection { async fn pre_process(conn: &Connection, recv: RecvStream) -> Result { let task = conn.model.accept_uni_stream(recv).await?; - if let Task::Authenticate(token) = &task { + if let Task::Authenticate(auth) = &task { if conn.is_authed() { return Err(Error::DuplicatedAuth); + } else if conn + .users + .get(&auth.uuid()) + .map_or(false, |password| auth.validate(password)) + { + conn.set_authed(); } else { - let mut buf = [0; 32]; - - conn.inner - .export_keying_material(&mut buf, &conn.token, &conn.token) - .map_err(|_| Error::ExportKeyingMaterial)?; - - if token == &buf { - conn.set_authed(); - } else { - return Err(Error::AuthFailed); - } + return Err(Error::AuthFailed(auth.uuid())); } } @@ -296,6 +299,7 @@ impl Connection { } match pre_process(&self, recv).await { + Ok(Task::Authenticate(_)) => {} Ok(Task::Packet(pkt)) => { self.set_udp_relay_mode(UdpRelayMode::Quic); match self.handle_packet(pkt).await {