implement new auth method for server
This commit is contained in:
parent
2c1f8e1a64
commit
8c4171ba14
@ -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 = { version = "0.20.8", default-features = false, features = ["quic"] }
|
||||||
rustls-pemfile = { version = "1.0.2", default-features = false }
|
rustls-pemfile = { version = "1.0.2", default-features = false }
|
||||||
serde = { version = "1.0.152", default-features = false, features = ["derive", "std"] }
|
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 }
|
socket2 = { version = "0.4.7", default-features = false }
|
||||||
thiserror = { version = "1.0.38", 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 = { 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"] }
|
tokio-util = { version = "0.7.4", default-features = false, features = ["compat"] }
|
||||||
tuic = { path = "../tuic", default-features = false }
|
tuic = { version = "5.0.0-pre-alpha6", default-features = false }
|
||||||
tuic-quinn = { path = "../tuic-quinn", 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"] }
|
||||||
|
@ -3,10 +3,11 @@ use lexopt::{Arg, Error as ArgumentError, Parser};
|
|||||||
use serde::{de::Error as DeError, Deserialize, Deserializer};
|
use serde::{de::Error as DeError, Deserialize, Deserializer};
|
||||||
use serde_json::Error as SerdeError;
|
use serde_json::Error as SerdeError;
|
||||||
use std::{
|
use std::{
|
||||||
env::ArgsOs, fmt::Display, fs::File, io::Error as IoError, net::SocketAddr, path::PathBuf,
|
collections::HashMap, env::ArgsOs, fmt::Display, fs::File, io::Error as IoError,
|
||||||
str::FromStr, time::Duration,
|
net::SocketAddr, path::PathBuf, str::FromStr, time::Duration,
|
||||||
};
|
};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
const HELP_MSG: &str = r#"
|
const HELP_MSG: &str = r#"
|
||||||
Usage tuic-server [arguments]
|
Usage tuic-server [arguments]
|
||||||
@ -21,7 +22,8 @@ Arguments:
|
|||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub server: SocketAddr,
|
pub server: SocketAddr,
|
||||||
pub token: String,
|
#[serde(deserialize_with = "deserialize_users")]
|
||||||
|
pub users: HashMap<Uuid, String>,
|
||||||
pub certificate: PathBuf,
|
pub certificate: PathBuf,
|
||||||
pub private_key: PathBuf,
|
pub private_key: PathBuf,
|
||||||
#[serde(
|
#[serde(
|
||||||
@ -130,6 +132,19 @@ where
|
|||||||
T::from_str(&s).map_err(DeError::custom)
|
T::from_str(&s).map_err(DeError::custom)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn deserialize_users<'de, D>(deserializer: D) -> Result<HashMap<Uuid, String>, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let map = HashMap::<Uuid, String>::deserialize(deserializer)?;
|
||||||
|
|
||||||
|
if map.is_empty() {
|
||||||
|
return Err(DeError::custom("users cannot be empty"));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(map)
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum ConfigError {
|
pub enum ConfigError {
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
|
@ -8,6 +8,7 @@ use std::{env, io::Error as IoError, net::SocketAddr, process};
|
|||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use tuic::Address;
|
use tuic::Address;
|
||||||
use tuic_quinn::Error as ModelError;
|
use tuic_quinn::Error as ModelError;
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
mod config;
|
mod config;
|
||||||
mod server;
|
mod server;
|
||||||
@ -52,8 +53,8 @@ pub enum Error {
|
|||||||
DuplicatedAuth,
|
DuplicatedAuth,
|
||||||
#[error("token length too short")]
|
#[error("token length too short")]
|
||||||
ExportKeyingMaterial,
|
ExportKeyingMaterial,
|
||||||
#[error("authentication failed")]
|
#[error("authentication failed: {0}")]
|
||||||
AuthFailed,
|
AuthFailed(Uuid),
|
||||||
#[error("received packet from unexpected source")]
|
#[error("received packet from unexpected source")]
|
||||||
UnexpectedPacketSource,
|
UnexpectedPacketSource,
|
||||||
#[error("{0} resolved to {1} but IPv6 UDP relay disabled")]
|
#[error("{0} resolved to {1} but IPv6 UDP relay disabled")]
|
||||||
|
@ -39,12 +39,13 @@ use tokio::{
|
|||||||
use tokio_util::compat::FuturesAsyncReadCompatExt;
|
use tokio_util::compat::FuturesAsyncReadCompatExt;
|
||||||
use tuic::Address;
|
use tuic::Address;
|
||||||
use tuic_quinn::{side, Connect, Connection as Model, Packet, Task};
|
use tuic_quinn::{side, Connect, Connection as Model, Packet, Task};
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
const DEFAULT_CONCURRENT_STREAMS: usize = 32;
|
const DEFAULT_CONCURRENT_STREAMS: usize = 32;
|
||||||
|
|
||||||
pub struct Server {
|
pub struct Server {
|
||||||
ep: Endpoint,
|
ep: Endpoint,
|
||||||
token: Arc<[u8]>,
|
users: Arc<HashMap<Uuid, Vec<u8>>>,
|
||||||
udp_relay_ipv6: bool,
|
udp_relay_ipv6: bool,
|
||||||
zero_rtt_handshake: bool,
|
zero_rtt_handshake: bool,
|
||||||
auth_timeout: Duration,
|
auth_timeout: Duration,
|
||||||
@ -115,9 +116,15 @@ impl Server {
|
|||||||
TokioRuntime,
|
TokioRuntime,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
let users = cfg
|
||||||
|
.users
|
||||||
|
.into_iter()
|
||||||
|
.map(|(uuid, password)| (uuid, password.into_bytes()))
|
||||||
|
.collect();
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
ep,
|
ep,
|
||||||
token: Arc::from(cfg.token.into_bytes().into_boxed_slice()),
|
users: Arc::new(users),
|
||||||
udp_relay_ipv6: cfg.udp_relay_ipv6,
|
udp_relay_ipv6: cfg.udp_relay_ipv6,
|
||||||
zero_rtt_handshake: cfg.zero_rtt_handshake,
|
zero_rtt_handshake: cfg.zero_rtt_handshake,
|
||||||
auth_timeout: cfg.auth_timeout,
|
auth_timeout: cfg.auth_timeout,
|
||||||
@ -133,7 +140,7 @@ impl Server {
|
|||||||
|
|
||||||
tokio::spawn(Connection::handle(
|
tokio::spawn(Connection::handle(
|
||||||
conn,
|
conn,
|
||||||
self.token.clone(),
|
self.users.clone(),
|
||||||
self.udp_relay_ipv6,
|
self.udp_relay_ipv6,
|
||||||
self.zero_rtt_handshake,
|
self.zero_rtt_handshake,
|
||||||
self.auth_timeout,
|
self.auth_timeout,
|
||||||
@ -149,7 +156,7 @@ impl Server {
|
|||||||
struct Connection {
|
struct Connection {
|
||||||
inner: QuinnConnection,
|
inner: QuinnConnection,
|
||||||
model: Model<side::Server>,
|
model: Model<side::Server>,
|
||||||
token: Arc<[u8]>,
|
users: Arc<HashMap<Uuid, Vec<u8>>>,
|
||||||
udp_relay_ipv6: bool,
|
udp_relay_ipv6: bool,
|
||||||
is_authed: IsAuthed,
|
is_authed: IsAuthed,
|
||||||
udp_sessions: Arc<AsyncMutex<HashMap<u16, UdpSession>>>,
|
udp_sessions: Arc<AsyncMutex<HashMap<u16, UdpSession>>>,
|
||||||
@ -165,7 +172,7 @@ struct Connection {
|
|||||||
impl Connection {
|
impl Connection {
|
||||||
async fn handle(
|
async fn handle(
|
||||||
conn: Connecting,
|
conn: Connecting,
|
||||||
token: Arc<[u8]>,
|
users: Arc<HashMap<Uuid, Vec<u8>>>,
|
||||||
udp_relay_ipv6: bool,
|
udp_relay_ipv6: bool,
|
||||||
zero_rtt_handshake: bool,
|
zero_rtt_handshake: bool,
|
||||||
auth_timeout: Duration,
|
auth_timeout: Duration,
|
||||||
@ -175,7 +182,7 @@ impl Connection {
|
|||||||
) {
|
) {
|
||||||
match Self::init(
|
match Self::init(
|
||||||
conn,
|
conn,
|
||||||
token,
|
users,
|
||||||
udp_relay_ipv6,
|
udp_relay_ipv6,
|
||||||
zero_rtt_handshake,
|
zero_rtt_handshake,
|
||||||
max_external_pkt_size,
|
max_external_pkt_size,
|
||||||
@ -203,7 +210,7 @@ impl Connection {
|
|||||||
|
|
||||||
async fn init(
|
async fn init(
|
||||||
conn: Connecting,
|
conn: Connecting,
|
||||||
token: Arc<[u8]>,
|
users: Arc<HashMap<Uuid, Vec<u8>>>,
|
||||||
udp_relay_ipv6: bool,
|
udp_relay_ipv6: bool,
|
||||||
zero_rtt_handshake: bool,
|
zero_rtt_handshake: bool,
|
||||||
max_external_pkt_size: usize,
|
max_external_pkt_size: usize,
|
||||||
@ -223,7 +230,7 @@ impl Connection {
|
|||||||
Ok(Self {
|
Ok(Self {
|
||||||
inner: conn.clone(),
|
inner: conn.clone(),
|
||||||
model: Model::<side::Server>::new(conn),
|
model: Model::<side::Server>::new(conn),
|
||||||
token,
|
users,
|
||||||
udp_relay_ipv6,
|
udp_relay_ipv6,
|
||||||
is_authed: IsAuthed::new(),
|
is_authed: IsAuthed::new(),
|
||||||
udp_sessions: Arc::new(AsyncMutex::new(HashMap::new())),
|
udp_sessions: Arc::new(AsyncMutex::new(HashMap::new())),
|
||||||
@ -263,21 +270,17 @@ impl Connection {
|
|||||||
async fn pre_process(conn: &Connection, recv: RecvStream) -> Result<Task, Error> {
|
async fn pre_process(conn: &Connection, recv: RecvStream) -> Result<Task, Error> {
|
||||||
let task = conn.model.accept_uni_stream(recv).await?;
|
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() {
|
if conn.is_authed() {
|
||||||
return Err(Error::DuplicatedAuth);
|
return Err(Error::DuplicatedAuth);
|
||||||
} else {
|
} else if conn
|
||||||
let mut buf = [0; 32];
|
.users
|
||||||
|
.get(&auth.uuid())
|
||||||
conn.inner
|
.map_or(false, |password| auth.validate(password))
|
||||||
.export_keying_material(&mut buf, &conn.token, &conn.token)
|
{
|
||||||
.map_err(|_| Error::ExportKeyingMaterial)?;
|
|
||||||
|
|
||||||
if token == &buf {
|
|
||||||
conn.set_authed();
|
conn.set_authed();
|
||||||
} else {
|
} else {
|
||||||
return Err(Error::AuthFailed);
|
return Err(Error::AuthFailed(auth.uuid()));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -296,6 +299,7 @@ impl Connection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
match pre_process(&self, recv).await {
|
match pre_process(&self, recv).await {
|
||||||
|
Ok(Task::Authenticate(_)) => {}
|
||||||
Ok(Task::Packet(pkt)) => {
|
Ok(Task::Packet(pkt)) => {
|
||||||
self.set_udp_relay_mode(UdpRelayMode::Quic);
|
self.set_udp_relay_mode(UdpRelayMode::Quic);
|
||||||
match self.handle_packet(pkt).await {
|
match self.handle_packet(pkt).await {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user