#![allow(dead_code)]
use std::net::SocketAddr;
use std::sync::Arc;
use alksocks::egress::{
BindAccept, BindAcceptError, BindAcceptFactory, BindTargetHandle, DialFn, Egress, EgressError,
EgressFactory, SocksDialError, TargetHandle,
};
use alksocks::rfc1928::consts;
use alksocks::rfc1928::util::target_addr::TargetAddr;
use alksocks::rfc1928::Socks5Command;
use bytes::Bytes;
use futures::future::BoxFuture;
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
use tokio::sync::Mutex;
pub fn echo_dial_witnessed(targets: Arc<Mutex<Vec<TargetAddr>>>) -> DialFn {
Arc::new(move |target: TargetAddr| {
let targets = Arc::clone(&targets);
Box::pin(async move {
targets.lock().await.push(target);
let (mut echo_end, target_end) = tokio::io::duplex(64 * 1024);
tokio::spawn(async move {
loop {
let mut buf = vec![0u8; 4096];
match echo_end.read(&mut buf).await {
Ok(0) | Err(_) => return,
Ok(n) => {
if echo_end.write_all(&buf[..n]).await.is_err() {
return;
}
}
}
}
});
let (read_half, write_half) = tokio::io::split(target_end);
Ok(TargetHandle {
read: Box::new(read_half) as Box<dyn AsyncRead + Send + Sync + Unpin>,
write: Box::new(write_half) as Box<dyn AsyncWrite + Send + Sync + Unpin>,
})
})
})
}
pub fn echo_dial() -> DialFn {
echo_dial_witnessed(Arc::new(Mutex::new(Vec::new())))
}
pub fn refusing_dial(err: SocksDialError) -> DialFn {
Arc::new(move |_target: TargetAddr| {
let err = match &err {
SocksDialError::Refused(m) => SocksDialError::Refused(m.clone()),
SocksDialError::NetworkUnreachable(m) => SocksDialError::NetworkUnreachable(m.clone()),
SocksDialError::HostUnreachable(m) => SocksDialError::HostUnreachable(m.clone()),
SocksDialError::NotAllowed(m) => SocksDialError::NotAllowed(m.clone()),
SocksDialError::General(m) => SocksDialError::General(m.clone()),
};
Box::pin(async move { Err(err) })
})
}
pub struct QueueEgress {
pub inbound: tokio::sync::mpsc::UnboundedSender<Bytes>,
pub outbound: Mutex<tokio::sync::mpsc::UnboundedReceiver<Bytes>>,
}
impl Egress for QueueEgress {
fn send(&mut self, addr: TargetAddr, payload: Bytes) -> BoxFuture<'_, Result<(), EgressError>> {
Box::pin(async move {
let mut inner = addr
.to_be_bytes()
.map_err(|e| EgressError::General(format!("addr encode: {e}")))?;
inner.extend_from_slice(&payload);
self.inbound
.send(Bytes::from(inner))
.map_err(|_| EgressError::General("egress closed".into()))
})
}
fn next_reply(&mut self) -> BoxFuture<'_, Result<Option<Bytes>, EgressError>> {
Box::pin(async move {
match self.outbound.lock().await.recv().await {
Some(inner) => Ok(Some(inner)),
None => Err(EgressError::General("egress closed".into())),
}
})
}
}
pub fn echo_egress_factory() -> EgressFactory {
alksocks::egress::egress_factory(|| {
let (inbound, outbound) = tokio::sync::mpsc::unbounded_channel::<Bytes>();
Ok(Box::new(QueueEgress {
inbound,
outbound: Mutex::new(outbound),
}) as Box<dyn Egress + Send>)
})
}
pub fn doubled_echo_egress_factory() -> EgressFactory {
alksocks::egress::egress_factory(|| {
let (inbound, outbound) = tokio::sync::mpsc::unbounded_channel::<Bytes>();
Ok(Box::new(DoubledEchoEgress {
inbound,
outbound: Mutex::new(outbound),
}) as Box<dyn Egress + Send>)
})
}
pub struct DoubledEchoEgress {
pub inbound: tokio::sync::mpsc::UnboundedSender<Bytes>,
pub outbound: Mutex<tokio::sync::mpsc::UnboundedReceiver<Bytes>>,
}
impl Egress for DoubledEchoEgress {
fn send(&mut self, addr: TargetAddr, payload: Bytes) -> BoxFuture<'_, Result<(), EgressError>> {
Box::pin(async move {
let mut inner = addr
.to_be_bytes()
.map_err(|e| EgressError::General(format!("addr encode: {e}")))?;
inner.extend_from_slice(&payload);
let inner = Bytes::from(inner);
self.inbound
.send(inner.clone())
.map_err(|_| EgressError::General("egress closed".into()))?;
self.inbound
.send(inner)
.map_err(|_| EgressError::General("egress closed".into()))
})
}
fn next_reply(&mut self) -> BoxFuture<'_, Result<Option<Bytes>, EgressError>> {
Box::pin(async move {
match self.outbound.lock().await.recv().await {
Some(inner) => Ok(Some(inner)),
None => Err(EgressError::General("egress closed".into())),
}
})
}
}
pub fn refusing_egress(err: EgressError) -> EgressFactory {
Arc::new(move || {
let err = match &err {
EgressError::Refused(m) => EgressError::Refused(m.clone()),
EgressError::Unreachable(m) => EgressError::Unreachable(m.clone()),
EgressError::General(m) => EgressError::General(m.clone()),
};
Box::pin(async move { Err(err) })
})
}
pub fn parked_accept_factory() -> BindAcceptFactory {
Arc::new(move |_target: TargetAddr| {
Box::pin(async move {
Ok(BindAccept::new(
SocketAddr::from(([127, 0, 0, 1], 2121)),
std::future::pending::<Result<BindTargetHandle, BindAcceptError>>(),
))
})
})
}
pub async fn raw_greet<S>(stream: &mut S) -> Result<u8, std::io::Error>
where
S: AsyncRead + AsyncWrite + Unpin,
{
stream.write_all(&[0x05, 0x01, 0x00]).await?;
let mut chosen = [0u8; 2];
stream.read_exact(&mut chosen).await?;
assert_eq!(
chosen[0],
consts::SOCKS5_VERSION,
"the method-selection reply is version 5"
);
Ok(chosen[1])
}
pub async fn raw_request<S>(
stream: &mut S,
cmd: &Socks5Command,
target: &TargetAddr,
) -> Result<(), std::io::Error>
where
S: AsyncRead + AsyncWrite + Unpin,
{
let addr = target
.to_be_bytes()
.map_err(|e| std::io::Error::other(format!("target encode: {e}")))?;
let mut req = vec![consts::SOCKS5_VERSION, cmd.as_u8(), 0x00];
req.extend_from_slice(&addr);
stream.write_all(&req).await?;
stream.flush().await
}
pub async fn raw_read_reply<S>(stream: &mut S) -> Result<(u8, u8, Vec<u8>), std::io::Error>
where
S: AsyncRead + AsyncWrite + Unpin,
{
let mut head = [0u8; 4];
stream.read_exact(&mut head).await?;
assert_eq!(head[0], consts::SOCKS5_VERSION, "the reply is version 5");
let addr_bytes: Vec<u8> = match head[3] {
consts::SOCKS5_ADDR_TYPE_IPV4 => {
let mut a = [0u8; 6];
stream.read_exact(&mut a).await?;
a.to_vec()
}
consts::SOCKS5_ADDR_TYPE_IPV6 => {
let mut a = [0u8; 18];
stream.read_exact(&mut a).await?;
a.to_vec()
}
consts::SOCKS5_ADDR_TYPE_DOMAIN_NAME => {
let mut len = [0u8; 1];
stream.read_exact(&mut len).await?;
let mut a = vec![0u8; len[0] as usize + 2];
stream.read_exact(&mut a).await?;
let mut full = vec![len[0]];
full.extend_from_slice(&a);
full
}
other => {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
format!("unknown address type {other}"),
))
}
};
Ok((head[1], head[3], addr_bytes))
}
pub async fn greet<S>(client: &mut S)
where
S: AsyncRead + AsyncWrite + Unpin,
{
let method = raw_greet(client).await.unwrap();
assert_eq!(method, consts::SOCKS5_AUTH_METHOD_NONE);
}
pub async fn write_request<S>(client: &mut S, cmd: &Socks5Command, target: &TargetAddr)
where
S: AsyncRead + AsyncWrite + Unpin,
{
raw_request(client, cmd, target).await.unwrap();
}
pub async fn read_reply_v4<S>(client: &mut S) -> (u8, [u8; 6])
where
S: AsyncRead + AsyncWrite + Unpin,
{
let (code, atyp, addr) = raw_read_reply(client).await.unwrap();
assert_eq!(atyp, consts::SOCKS5_ADDR_TYPE_IPV4, "tests use v4 BND.ADDR");
let mut out = [0u8; 6];
out.copy_from_slice(&addr);
(code, out)
}
pub fn datagram_frame(addr: &TargetAddr, payload: &[u8]) -> Vec<u8> {
alksocks::wire::frame(addr, payload)
.expect("frame")
.to_vec()
}
pub fn decode_datagram(wire: &[u8]) -> (TargetAddr, Bytes) {
let mut reader = alksocks::wire::DatagramReader::new();
let mut got = None;
for dg in reader.feed(wire) {
got = Some(dg);
}
got.expect("one datagram decoded").expect("frame decodes")
}