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};
|
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;
|
2023-10-16 22:00:45 +00:00
|
|
|
use tokio::io::AsyncWriteExt;
|
2023-10-16 17:26:32 +00:00
|
|
|
use tokio::net::TcpStream;
|
|
|
|
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 {
|
2023-10-16 22:00:45 +00:00
|
|
|
stream: Pin<Box<dyn Stream<Item = anyhow::Result<(TcpStream, (Host, u16))>> + Send>>,
|
2023-10-16 17:26:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Stream for Socks5Listener {
|
2023-10-16 22:00:45 +00:00
|
|
|
type Item = anyhow::Result<(TcpStream, (Host, u16))>;
|
2023-10-16 17:26:32 +00:00
|
|
|
|
|
|
|
fn poll_next(
|
|
|
|
self: Pin<&mut Self>,
|
|
|
|
cx: &mut std::task::Context<'_>,
|
|
|
|
) -> Poll<Option<Self::Item>> {
|
|
|
|
unsafe { self.map_unchecked_mut(|x| &mut x.stream) }.poll_next(cx)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn run_server(bind: SocketAddr) -> 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);
|
|
|
|
|
|
|
|
let server = server.with_config(cfg);
|
|
|
|
let stream = stream::unfold(server, move |server| async {
|
|
|
|
let mut acceptor = server.incoming();
|
|
|
|
loop {
|
|
|
|
let cnx = match acceptor.next().await {
|
|
|
|
None => return None,
|
|
|
|
Some(Err(err)) => {
|
|
|
|
drop(acceptor);
|
|
|
|
return Some((Err(anyhow::Error::new(err)), server));
|
|
|
|
}
|
|
|
|
Some(Ok(cnx)) => cnx,
|
|
|
|
};
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
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);
|
2023-10-16 22:00:45 +00:00
|
|
|
return Some((Ok((cnx, (host, port))), server));
|
2023-10-16 17:26:32 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
let listener = Socks5Listener {
|
|
|
|
stream: Box::pin(stream),
|
|
|
|
};
|
|
|
|
|
|
|
|
Ok(listener)
|
|
|
|
}
|
|
|
|
|
2023-10-16 22:00:45 +00:00
|
|
|
pub fn new_reply(error: &ReplyError, sock_addr: SocketAddr) -> Vec<u8> {
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
//}
|