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}