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
use crate::protocol::{
handshake::password::{Request as PasswordRequest, Response as PasswordResponse},
HandshakeMethod,
};
use async_trait::async_trait;
use std::io::{Error, ErrorKind, Result};
use tokio::net::TcpStream;
/// This trait is for defining the socks5 authentication method.
///
/// Pre-defined authentication methods can be found in the [`auth`](https://docs.rs/socks5-impl/latest/socks5_impl/server/auth/index.html) module.
///
/// You can create your own authentication method by implementing this trait. Since GAT is not stabled yet, [async_trait](https://docs.rs/async-trait/latest/async_trait/index.html) needs to be used.
///
/// # Example
/// ```rust
/// use async_trait::async_trait;
/// use std::io::Result;
/// use socks5_impl::protocol::HandshakeMethod;
/// use socks5_impl::server::Auth;
/// use tokio::net::TcpStream;
///
/// pub struct MyAuth;
///
/// #[async_trait]
/// impl Auth for MyAuth {
/// fn as_handshake_method(&self) -> HandshakeMethod {
/// HandshakeMethod(0x80)
/// }
///
/// async fn execute(&self, stream: &mut TcpStream) -> Result<()> {
/// // do something
/// Ok(())
/// }
/// }
/// ```
#[async_trait]
pub trait Auth {
fn as_handshake_method(&self) -> HandshakeMethod;
async fn execute(&self, stream: &mut TcpStream) -> Result<()>;
}
/// No authentication as the socks5 handshake method.
pub struct NoAuth;
impl NoAuth {
pub fn new() -> Self {
Self
}
}
#[async_trait]
impl Auth for NoAuth {
fn as_handshake_method(&self) -> HandshakeMethod {
HandshakeMethod::None
}
async fn execute(&self, _: &mut TcpStream) -> Result<()> {
Ok(())
}
}
impl Default for NoAuth {
fn default() -> Self {
Self::new()
}
}
/// Username and password as the socks5 handshake method.
pub struct Password {
username: Vec<u8>,
password: Vec<u8>,
}
impl Password {
pub fn new(username: Vec<u8>, password: Vec<u8>) -> Self {
Self { username, password }
}
}
#[async_trait]
impl Auth for Password {
fn as_handshake_method(&self) -> HandshakeMethod {
HandshakeMethod::Password
}
async fn execute(&self, stream: &mut TcpStream) -> Result<()> {
let req = PasswordRequest::from_stream(stream).await?;
if (&req.username, &req.password) == (&self.username, &self.password) {
let resp = PasswordResponse::new(true);
resp.write_to(stream).await?;
Ok(())
} else {
let resp = PasswordResponse::new(false);
resp.write_to(stream).await?;
Err(Error::new(
ErrorKind::InvalidData,
"SOCKS5 username / password authentication failed",
))
}
}
}