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