2024-01-07 15:51:55 +00:00
|
|
|
use crate::socks5_udp::Socks5UdpStream;
|
|
|
|
use crate::{socks5_udp, LocalProtocol};
|
2023-10-16 17:26:32 +00:00
|
|
|
use anyhow::Context;
|
|
|
|
use fast_socks5::server::{Config, DenyAuthentication, Socks5Server};
|
|
|
|
use fast_socks5::util::target_addr::TargetAddr;
|
2023-10-16 22:00:45 +00:00
|
|
|
use fast_socks5::{consts, ReplyError};
|
2023-10-16 17:26:32 +00:00
|
|
|
use futures_util::{stream, Stream, StreamExt};
|
2024-01-06 19:10:03 +00:00
|
|
|
use std::io::{Error, IoSlice};
|
2023-10-16 22:00:45 +00:00
|
|
|
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
2023-10-16 17:26:32 +00:00
|
|
|
use std::pin::Pin;
|
|
|
|
use std::task::Poll;
|
2024-01-07 15:51:55 +00:00
|
|
|
use std::time::Duration;
|
|
|
|
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt, ReadBuf};
|
2023-10-16 17:26:32 +00:00
|
|
|
use tokio::net::TcpStream;
|
2024-01-07 15:51:55 +00:00
|
|
|
use tokio::select;
|
2023-10-16 17:26:32 +00:00
|
|
|
use tracing::{info, warn};
|
|
|
|
use url::Host;
|
|
|
|
|
2023-10-21 14:49:24 +00:00
|
|
|
#[allow(clippy::type_complexity)]
|
2023-10-16 17:26:32 +00:00
|
|
|
pub struct Socks5Listener {
|
2024-01-07 15:51:55 +00:00
|
|
|
socks_server: Pin<Box<dyn Stream<Item = anyhow::Result<(Socks5Stream, (Host, u16))>> + Send>>,
|
2023-10-16 17:26:32 +00:00
|
|
|
}
|
|
|
|
|
2024-01-07 15:51:55 +00:00
|
|
|
pub enum Socks5Stream {
|
2024-01-06 19:10:03 +00:00
|
|
|
Tcp(TcpStream),
|
2024-01-07 15:51:55 +00:00
|
|
|
Udp(Socks5UdpStream),
|
2024-01-06 19:10:03 +00:00
|
|
|
}
|
2024-01-07 15:51:55 +00:00
|
|
|
|
|
|
|
impl Socks5Stream {
|
|
|
|
pub fn local_protocol(&self) -> LocalProtocol {
|
|
|
|
match self {
|
|
|
|
Socks5Stream::Tcp(_) => LocalProtocol::Tcp,
|
|
|
|
Socks5Stream::Udp(s) => LocalProtocol::Udp {
|
|
|
|
timeout: s.watchdog_deadline.as_ref().map(|x| x.period()),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-16 17:26:32 +00:00
|
|
|
impl Stream for Socks5Listener {
|
2024-01-07 15:51:55 +00:00
|
|
|
type Item = anyhow::Result<(Socks5Stream, (Host, u16))>;
|
2023-10-16 17:26:32 +00:00
|
|
|
|
2023-10-30 07:13:38 +00:00
|
|
|
fn poll_next(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Option<Self::Item>> {
|
2024-01-07 15:51:55 +00:00
|
|
|
unsafe { self.map_unchecked_mut(|x| &mut x.socks_server) }.poll_next(cx)
|
2023-10-16 17:26:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-07 15:51:55 +00:00
|
|
|
pub async fn run_server(bind: SocketAddr, timeout: Option<Duration>) -> Result<Socks5Listener, anyhow::Error> {
|
2023-10-16 22:00:45 +00:00
|
|
|
info!("Starting SOCKS5 server listening cnx on {}", bind);
|
2023-10-16 17:26:32 +00:00
|
|
|
|
|
|
|
let server = Socks5Server::<DenyAuthentication>::bind(bind)
|
|
|
|
.await
|
|
|
|
.with_context(|| format!("Cannot create socks5 server {:?}", bind))?;
|
|
|
|
|
|
|
|
let mut cfg = Config::<DenyAuthentication>::default();
|
|
|
|
cfg.set_allow_no_auth(true);
|
|
|
|
cfg.set_dns_resolve(false);
|
|
|
|
cfg.set_execute_command(false);
|
2024-01-06 19:10:03 +00:00
|
|
|
cfg.set_udp_support(true);
|
2023-10-16 17:26:32 +00:00
|
|
|
|
2024-01-07 15:51:55 +00:00
|
|
|
let udp_server = socks5_udp::run_server(bind, timeout, |_| Ok(()), |s| Ok(s.clone())).await?;
|
2023-10-16 17:26:32 +00:00
|
|
|
let server = server.with_config(cfg);
|
2024-01-07 15:51:55 +00:00
|
|
|
let stream = stream::unfold((server, Box::pin(udp_server)), move |(server, mut udp_server)| async move {
|
2023-10-16 17:26:32 +00:00
|
|
|
let mut acceptor = server.incoming();
|
|
|
|
loop {
|
2024-01-07 15:51:55 +00:00
|
|
|
let cnx = select! {
|
|
|
|
biased;
|
|
|
|
|
|
|
|
cnx = acceptor.next() => match cnx {
|
|
|
|
None => return None,
|
|
|
|
Some(Err(err)) => {
|
|
|
|
drop(acceptor);
|
|
|
|
return Some((Err(anyhow::Error::new(err)), (server, udp_server)));
|
|
|
|
}
|
|
|
|
Some(Ok(cnx)) => cnx,
|
|
|
|
},
|
|
|
|
|
|
|
|
// new incoming udp stream
|
|
|
|
udp_conn = udp_server.next() => {
|
2023-10-16 17:26:32 +00:00
|
|
|
drop(acceptor);
|
2024-01-07 15:51:55 +00:00
|
|
|
return match udp_conn {
|
|
|
|
Some(Ok(stream)) => {
|
|
|
|
let dest = stream.destination();
|
|
|
|
Some((Ok((Socks5Stream::Udp(stream), dest)), (server, udp_server)))
|
|
|
|
}
|
|
|
|
Some(Err(err)) => {
|
|
|
|
Some((Err(anyhow::Error::new(err)), (server, udp_server)))
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
};
|
2023-10-16 17:26:32 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let cnx = match cnx.upgrade_to_socks5().await {
|
|
|
|
Ok(cnx) => cnx,
|
|
|
|
Err(err) => {
|
|
|
|
warn!("Rejecting socks5 cnx: {}", err);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let Some(target) = cnx.target_addr() else {
|
|
|
|
warn!("Rejecting socks5 cnx: no target addr");
|
|
|
|
continue;
|
|
|
|
};
|
|
|
|
|
|
|
|
let (host, port) = match target {
|
|
|
|
TargetAddr::Ip(SocketAddr::V4(ip)) => (Host::Ipv4(*ip.ip()), ip.port()),
|
|
|
|
TargetAddr::Ip(SocketAddr::V6(ip)) => (Host::Ipv6(*ip.ip()), ip.port()),
|
|
|
|
TargetAddr::Domain(host, port) => (Host::Domain(host.clone()), *port),
|
|
|
|
};
|
2023-10-16 22:00:45 +00:00
|
|
|
|
2024-01-07 15:51:55 +00:00
|
|
|
// Special case for UDP Associate where we return the bind addr of the udp server
|
|
|
|
if let Some(fast_socks5::Socks5Command::UDPAssociate) = cnx.cmd() {
|
|
|
|
let mut cnx = cnx.into_inner();
|
|
|
|
let ret = cnx.write_all(&new_reply(&ReplyError::Succeeded, bind)).await;
|
|
|
|
|
|
|
|
if let Err(err) = ret {
|
|
|
|
warn!("Cannot reply to socks5 udp client: {}", err);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
tokio::spawn(async move {
|
|
|
|
let mut buf = [0u8; 8];
|
|
|
|
loop {
|
|
|
|
match cnx.read(&mut buf).await {
|
|
|
|
Ok(0) => return,
|
|
|
|
Err(_) => return,
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
continue;
|
|
|
|
};
|
|
|
|
|
2023-10-16 22:00:45 +00:00
|
|
|
let mut cnx = cnx.into_inner();
|
|
|
|
let ret = cnx
|
|
|
|
.write_all(&new_reply(
|
|
|
|
&ReplyError::Succeeded,
|
|
|
|
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 0),
|
|
|
|
))
|
|
|
|
.await;
|
|
|
|
|
|
|
|
if let Err(err) = ret {
|
|
|
|
warn!("Cannot reply to socks5 client: {}", err);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-10-16 17:26:32 +00:00
|
|
|
drop(acceptor);
|
2024-01-07 15:51:55 +00:00
|
|
|
return Some((Ok((Socks5Stream::Tcp(cnx), (host, port))), (server, udp_server)));
|
2023-10-16 17:26:32 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
let listener = Socks5Listener {
|
2024-01-07 15:51:55 +00:00
|
|
|
socks_server: Box::pin(stream),
|
2023-10-16 17:26:32 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
Ok(listener)
|
|
|
|
}
|
|
|
|
|
2023-10-27 19:11:24 +00:00
|
|
|
fn new_reply(error: &ReplyError, sock_addr: SocketAddr) -> Vec<u8> {
|
2023-10-16 22:00:45 +00:00
|
|
|
let (addr_type, mut ip_oct, mut port) = match sock_addr {
|
|
|
|
SocketAddr::V4(sock) => (
|
|
|
|
consts::SOCKS5_ADDR_TYPE_IPV4,
|
|
|
|
sock.ip().octets().to_vec(),
|
|
|
|
sock.port().to_be_bytes().to_vec(),
|
|
|
|
),
|
|
|
|
SocketAddr::V6(sock) => (
|
|
|
|
consts::SOCKS5_ADDR_TYPE_IPV6,
|
|
|
|
sock.ip().octets().to_vec(),
|
|
|
|
sock.port().to_be_bytes().to_vec(),
|
|
|
|
),
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut reply = vec![
|
|
|
|
consts::SOCKS5_VERSION,
|
|
|
|
error.as_u8(), // transform the error into byte code
|
|
|
|
0x00, // reserved
|
|
|
|
addr_type, // address type (ipv4, v6, domain)
|
|
|
|
];
|
|
|
|
reply.append(&mut ip_oct);
|
|
|
|
reply.append(&mut port);
|
|
|
|
|
|
|
|
reply
|
|
|
|
}
|
|
|
|
|
2024-01-07 15:51:55 +00:00
|
|
|
impl Unpin for Socks5Stream {}
|
|
|
|
impl AsyncRead for Socks5Stream {
|
2024-01-06 19:10:03 +00:00
|
|
|
fn poll_read(
|
|
|
|
self: Pin<&mut Self>,
|
|
|
|
cx: &mut std::task::Context<'_>,
|
|
|
|
buf: &mut ReadBuf<'_>,
|
|
|
|
) -> Poll<std::io::Result<()>> {
|
|
|
|
match self.get_mut() {
|
2024-01-07 15:51:55 +00:00
|
|
|
Socks5Stream::Tcp(s) => unsafe { Pin::new_unchecked(s) }.poll_read(cx, buf),
|
|
|
|
Socks5Stream::Udp(s) => unsafe { Pin::new_unchecked(s) }.poll_read(cx, buf),
|
2024-01-06 19:10:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-07 15:51:55 +00:00
|
|
|
impl AsyncWrite for Socks5Stream {
|
2024-01-06 19:10:03 +00:00
|
|
|
fn poll_write(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>, buf: &[u8]) -> Poll<Result<usize, Error>> {
|
|
|
|
match self.get_mut() {
|
2024-01-07 15:51:55 +00:00
|
|
|
Socks5Stream::Tcp(s) => unsafe { Pin::new_unchecked(s) }.poll_write(cx, buf),
|
|
|
|
Socks5Stream::Udp(s) => unsafe { Pin::new_unchecked(s) }.poll_write(cx, buf),
|
2024-01-06 19:10:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn poll_flush(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Result<(), Error>> {
|
|
|
|
match self.get_mut() {
|
2024-01-07 15:51:55 +00:00
|
|
|
Socks5Stream::Tcp(s) => unsafe { Pin::new_unchecked(s) }.poll_flush(cx),
|
|
|
|
Socks5Stream::Udp(s) => unsafe { Pin::new_unchecked(s) }.poll_flush(cx),
|
2024-01-06 19:10:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn poll_shutdown(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Result<(), Error>> {
|
|
|
|
match self.get_mut() {
|
2024-01-07 15:51:55 +00:00
|
|
|
Socks5Stream::Tcp(s) => unsafe { Pin::new_unchecked(s) }.poll_shutdown(cx),
|
|
|
|
Socks5Stream::Udp(s) => unsafe { Pin::new_unchecked(s) }.poll_shutdown(cx),
|
2024-01-06 19:10:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn poll_write_vectored(
|
|
|
|
self: Pin<&mut Self>,
|
|
|
|
cx: &mut std::task::Context<'_>,
|
|
|
|
bufs: &[IoSlice<'_>],
|
|
|
|
) -> Poll<Result<usize, Error>> {
|
|
|
|
match self.get_mut() {
|
2024-01-07 15:51:55 +00:00
|
|
|
Socks5Stream::Tcp(s) => unsafe { Pin::new_unchecked(s) }.poll_write_vectored(cx, bufs),
|
|
|
|
Socks5Stream::Udp(s) => unsafe { Pin::new_unchecked(s) }.poll_write_vectored(cx, bufs),
|
2024-01-06 19:10:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn is_write_vectored(&self) -> bool {
|
|
|
|
match self {
|
2024-01-07 15:51:55 +00:00
|
|
|
Socks5Stream::Tcp(s) => s.is_write_vectored(),
|
|
|
|
Socks5Stream::Udp(s) => s.is_write_vectored(),
|
2024-01-06 19:10:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-27 19:02:12 +00:00
|
|
|
//#[cfg(test)]
|
|
|
|
//mod test {
|
|
|
|
// use super::*;
|
|
|
|
// use futures_util::StreamExt;
|
|
|
|
// use std::str::FromStr;
|
|
|
|
//
|
|
|
|
// #[tokio::test]
|
|
|
|
// async fn socks5_server() {
|
|
|
|
// let mut x = run_server(SocketAddr::from_str("[::]:4343").unwrap())
|
|
|
|
// .await
|
|
|
|
// .unwrap();
|
|
|
|
//
|
|
|
|
// loop {
|
|
|
|
// let cnx = x.next().await.unwrap().unwrap();
|
|
|
|
// eprintln!("{:?}", cnx);
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
//}
|