socks5_server/
auth.rs

1//! This module defines trait [`Auth`] and some pre-defined authentication adaptors.
2//!
3//! The process of SOCKS5 authentication can be customized by implementing [`Auth`] trait on your own types.
4
5use async_trait::async_trait;
6use socks5_proto::handshake::{
7    password::{Error as PasswordError, Request as PasswordRequest, Response as PasswordResponse},
8    Method,
9};
10use tokio::net::TcpStream;
11
12/// This trait is for defining the customized process of SOCKS5 authentication.
13///
14/// You can create your own authentication method by implementing this trait. Associate type `Output` indicates the result of authenticating. Note that this library will not implicitly close any connection even if the authentication failed.
15///
16/// # Example
17/// ```rust
18/// use async_trait::async_trait;
19/// use std::io::Result;
20/// use socks5_proto::handshake::Method;
21/// use socks5_server::Auth;
22/// use tokio::net::TcpStream;
23///
24/// pub struct MyAuth;
25///
26/// #[async_trait]
27/// impl Auth for MyAuth {
28///     type Output = Result<usize>;
29///
30///     fn as_handshake_method(&self) -> Method {
31///         Method(0xfe)
32///     }
33///
34///     async fn execute(&self, stream: &mut TcpStream) -> Self::Output {
35///         // do something on stream
36///         Ok(1145141919810)
37///     }
38/// }
39/// ```
40#[async_trait]
41pub trait Auth {
42    type Output;
43
44    fn as_handshake_method(&self) -> Method;
45    async fn execute(&self, stream: &mut TcpStream) -> Self::Output;
46}
47
48/// Not authenticate at all.
49#[derive(Clone, Copy, Debug, Default)]
50pub struct NoAuth;
51
52impl NoAuth {
53    #[allow(clippy::new_without_default)]
54    pub fn new() -> Self {
55        Self
56    }
57}
58
59#[async_trait]
60impl Auth for NoAuth {
61    type Output = ();
62
63    fn as_handshake_method(&self) -> Method {
64        Method::NONE
65    }
66
67    async fn execute(&self, _: &mut TcpStream) -> Self::Output {}
68}
69
70/// Using username and password to authenticate.
71///
72/// The boolean value in associate type `Auth::Output` indicates whether the authentication is successful.
73#[derive(Clone, Debug)]
74pub struct Password {
75    pub username: Vec<u8>,
76    pub password: Vec<u8>,
77}
78
79impl Password {
80    /// Create a new `Password` authentication adaptor.
81    pub fn new(username: Vec<u8>, password: Vec<u8>) -> Self {
82        Self { username, password }
83    }
84}
85
86#[async_trait]
87impl Auth for Password {
88    type Output = Result<bool, PasswordError>;
89
90    fn as_handshake_method(&self) -> Method {
91        Method::PASSWORD
92    }
93
94    async fn execute(&self, stream: &mut TcpStream) -> Self::Output {
95        let req = PasswordRequest::read_from(stream).await?;
96
97        if (&req.username, &req.password) == (&self.username, &self.password) {
98            let resp = PasswordResponse::new(true);
99            resp.write_to(stream).await?;
100            Ok(true)
101        } else {
102            let resp = PasswordResponse::new(false);
103            resp.write_to(stream).await?;
104            Ok(false)
105        }
106    }
107}