socks5_impl/server/
auth.rs

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