Skip to main content

socks5_impl/server/
auth.rs

1use crate::{
2    AsyncStreamOperation, UserKey,
3    protocol::{AuthMethod, handshake::password_method},
4};
5use std::sync::Arc;
6use tokio::net::TcpStream;
7
8/// This trait is for defining the socks5 authentication method.
9///
10/// Pre-defined authentication methods can be found in the [`auth`](crate::server::auth) module.
11///
12/// You can create your own authentication method by implementing this trait. Since GAT is not stabled yet,
13/// [async_trait](https://docs.rs/async-trait/latest/async_trait/index.html) needs to be used.
14///
15/// # Example
16/// ```rust
17/// use socks5_impl::protocol::AuthMethod;
18/// use socks5_impl::server::AuthExecutor;
19/// use tokio::net::TcpStream;
20///
21/// pub struct MyAuth;
22///
23/// #[async_trait::async_trait]
24/// impl AuthExecutor for MyAuth {
25///     fn auth_method(&self) -> AuthMethod {
26///         AuthMethod::from(0x80)
27///     }
28///
29///     async fn execute(&self, stream: &mut TcpStream) -> std::io::Result<bool> {
30///         // do something
31///         Ok(true)
32///     }
33/// }
34/// ```
35#[async_trait::async_trait]
36pub trait AuthExecutor {
37    fn auth_method(&self) -> AuthMethod;
38    async fn execute(&self, stream: &mut TcpStream) -> std::io::Result<bool>;
39}
40
41pub type AuthAdaptor = Arc<dyn AuthExecutor + Send + Sync>;
42
43/// No authentication as the socks5 handshake method.
44#[derive(Debug, Default)]
45pub struct NoAuth;
46
47#[async_trait::async_trait]
48impl AuthExecutor for NoAuth {
49    fn auth_method(&self) -> AuthMethod {
50        AuthMethod::NoAuth
51    }
52
53    async fn execute(&self, _: &mut TcpStream) -> std::io::Result<bool> {
54        Ok(true)
55    }
56}
57
58/// Username and password as the socks5 handshake method.
59#[derive(Debug, Clone)]
60pub struct UserKeyAuth {
61    user_key: UserKey,
62}
63
64impl From<UserKey> for UserKeyAuth {
65    fn from(user_key: UserKey) -> Self {
66        Self { user_key }
67    }
68}
69
70impl From<&UserKey> for UserKeyAuth {
71    fn from(value: &UserKey) -> Self {
72        Self { user_key: value.clone() }
73    }
74}
75
76impl From<(&str, &str)> for UserKeyAuth {
77    fn from(value: (&str, &str)) -> Self {
78        Self::new(value.0, value.1)
79    }
80}
81
82impl UserKeyAuth {
83    pub fn new(username: &str, password: &str) -> Self {
84        let user_key = UserKey::new(username, password);
85        Self { user_key }
86    }
87}
88
89#[async_trait::async_trait]
90impl AuthExecutor for UserKeyAuth {
91    fn auth_method(&self) -> AuthMethod {
92        AuthMethod::UserPass
93    }
94
95    async fn execute(&self, stream: &mut TcpStream) -> std::io::Result<bool> {
96        use password_method::{Request, Response, Status::*};
97        let req = Request::retrieve_from_async_stream(stream).await?;
98
99        let is_equal = req.user_key == self.user_key;
100        let resp = Response::new(if is_equal { Succeeded } else { Failed });
101        resp.write_to_async_stream(stream).await?;
102        if is_equal {
103            Ok(true)
104        } else {
105            Err(std::io::Error::other("username or password is incorrect"))
106        }
107    }
108}