checkpoint

This commit is contained in:
Adam Wick
2021-06-24 19:18:16 -07:00
commit 1bf6f62d4e
16 changed files with 1789 additions and 0 deletions

151
src/network/address.rs Normal file
View File

@@ -0,0 +1,151 @@
use crate::errors::{DeserializationError, SerializationError};
#[cfg(test)]
use crate::messages::arbitrary_socks_string;
use crate::serialize::{read_amt, read_string, write_string};
use futures::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
#[cfg(test)]
use quickcheck::{Arbitrary, Gen};
use std::fmt;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use std::pin::Pin;
pub trait ToSOCKSAddress: Send {
fn to_socks_address(&self) -> SOCKSv5Address;
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum SOCKSv5Address {
IP4(Ipv4Addr),
IP6(Ipv6Addr),
Name(String),
}
impl ToSOCKSAddress for SOCKSv5Address {
fn to_socks_address(&self) -> SOCKSv5Address {
self.clone()
}
}
impl ToSOCKSAddress for IpAddr {
fn to_socks_address(&self) -> SOCKSv5Address {
match self {
IpAddr::V4(a) => SOCKSv5Address::IP4(*a),
IpAddr::V6(a) => SOCKSv5Address::IP6(*a),
}
}
}
impl ToSOCKSAddress for Ipv4Addr {
fn to_socks_address(&self) -> SOCKSv5Address {
SOCKSv5Address::IP4(*self)
}
}
impl ToSOCKSAddress for Ipv6Addr {
fn to_socks_address(&self) -> SOCKSv5Address {
SOCKSv5Address::IP6(*self)
}
}
impl ToSOCKSAddress for String {
fn to_socks_address(&self) -> SOCKSv5Address {
SOCKSv5Address::Name(self.clone())
}
}
impl<'a> ToSOCKSAddress for &'a str {
fn to_socks_address(&self) -> SOCKSv5Address {
SOCKSv5Address::Name(self.to_string())
}
}
impl fmt::Display for SOCKSv5Address {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
SOCKSv5Address::IP4(a) => write!(f, "{}", a),
SOCKSv5Address::IP6(a) => write!(f, "{}", a),
SOCKSv5Address::Name(a) => write!(f, "{}", a),
}
}
}
impl From<IpAddr> for SOCKSv5Address {
fn from(addr: IpAddr) -> SOCKSv5Address {
match addr {
IpAddr::V4(a) => SOCKSv5Address::IP4(a),
IpAddr::V6(a) => SOCKSv5Address::IP6(a),
}
}
}
impl SOCKSv5Address {
pub async fn read<R: AsyncRead + Send + Unpin>(
mut r: Pin<&mut R>,
) -> Result<Self, DeserializationError> {
let mut byte_buffer = [0u8; 1];
let amount_read = r.read(&mut byte_buffer).await?;
if amount_read == 0 {
return Err(DeserializationError::NotEnoughData);
}
match byte_buffer[0] {
1 => {
let mut addr_buffer = [0; 4];
read_amt(r, 4, &mut addr_buffer).await?;
Ok(SOCKSv5Address::IP4(Ipv4Addr::from(addr_buffer)))
}
3 => {
let mut addr_buffer = [0; 16];
read_amt(r, 16, &mut addr_buffer).await?;
Ok(SOCKSv5Address::IP6(Ipv6Addr::from(addr_buffer)))
}
4 => {
let name = read_string(r).await?;
Ok(SOCKSv5Address::Name(name))
}
x => Err(DeserializationError::InvalidAddressType(x)),
}
}
pub async fn write<W: AsyncWrite + Send + Unpin>(
&self,
w: &mut W,
) -> Result<(), SerializationError> {
match self {
SOCKSv5Address::IP4(x) => {
w.write_all(&[1]).await?;
w.write_all(&x.octets())
.await
.map_err(SerializationError::IOError)
}
SOCKSv5Address::IP6(x) => {
w.write_all(&[3]).await?;
w.write_all(&x.octets())
.await
.map_err(SerializationError::IOError)
}
SOCKSv5Address::Name(x) => {
w.write_all(&[4]).await?;
write_string(x, w).await
}
}
}
}
#[cfg(test)]
impl Arbitrary for SOCKSv5Address {
fn arbitrary(g: &mut Gen) -> Self {
let ip4 = Ipv4Addr::arbitrary(g);
let ip6 = Ipv6Addr::arbitrary(g);
let nm = arbitrary_socks_string(g);
g.choose(&[
SOCKSv5Address::IP4(ip4),
SOCKSv5Address::IP6(ip6),
SOCKSv5Address::Name(nm),
])
.unwrap()
.clone()
}
}

37
src/network/datagram.rs Normal file
View File

@@ -0,0 +1,37 @@
use crate::network::address::SOCKSv5Address;
use async_trait::async_trait;
#[async_trait]
pub trait Datagramlike: Send + Sync {
type Error;
async fn send_to(
&self,
buf: &[u8],
addr: SOCKSv5Address,
port: u16,
) -> Result<usize, Self::Error>;
async fn recv_from(&self, buf: &mut [u8]) -> Result<(usize, SOCKSv5Address, u16), Self::Error>;
}
pub struct GenericDatagramSocket<E> {
pub internal: Box<dyn Datagramlike<Error = E>>,
}
#[async_trait]
impl<E> Datagramlike for GenericDatagramSocket<E> {
type Error = E;
async fn send_to(
&self,
buf: &[u8],
addr: SOCKSv5Address,
port: u16,
) -> Result<usize, Self::Error> {
Ok(self.internal.send_to(buf, addr, port).await?)
}
async fn recv_from(&self, buf: &mut [u8]) -> Result<(usize, SOCKSv5Address, u16), Self::Error> {
Ok(self.internal.recv_from(buf).await?)
}
}

48
src/network/generic.rs Normal file
View File

@@ -0,0 +1,48 @@
use crate::messages::ServerResponseStatus;
use crate::network::address::ToSOCKSAddress;
use crate::network::datagram::GenericDatagramSocket;
use crate::network::listener::GenericListener;
use crate::network::stream::GenericStream;
use async_trait::async_trait;
use std::fmt::Display;
#[async_trait]
pub trait Networklike {
/// The error type for things that fail on this network. Apologies in advance
/// for using only one; if you have a use case for separating your errors,
/// please shoot the author(s) and email to split this into multiple types, one
/// for each trait function.
type Error: Display + Into<ServerResponseStatus> + Send;
/// Connect to the given address and port, over this kind of network. The
/// underlying stream should behave somewhat like a TCP stream ... which
/// may be exactly what you're using. However, in order to support tunnelling
/// scenarios (i.e., using another proxy, going through Tor or SSH, etc.) we
/// work generically over any stream-like object.
async fn connect<A: ToSOCKSAddress>(
&mut self,
addr: A,
port: u16,
) -> Result<GenericStream, Self::Error>;
/// Listen for connections on the given address and port, returning a generic
/// listener socket to use in the future.
async fn listen<A: ToSOCKSAddress>(
&mut self,
addr: A,
port: u16,
) -> Result<GenericListener<Self::Error>, Self::Error>;
/// Bind a socket for the purposes of doing some datagram communication. NOTE!
/// this is only for UDP-like communication, not for generic connecting or
/// listening! Maybe obvious from the types, but POSIX has overtrained many
/// of us.
///
/// Recall when using these functions that datagram protocols allow for packet
/// loss and out-of-order delivery. So ... be warned.
async fn bind<A: ToSOCKSAddress>(
&mut self,
addr: A,
port: u16,
) -> Result<GenericDatagramSocket<Self::Error>, Self::Error>;
}

28
src/network/listener.rs Normal file
View File

@@ -0,0 +1,28 @@
use crate::network::address::SOCKSv5Address;
use crate::network::stream::GenericStream;
use async_trait::async_trait;
#[async_trait]
pub trait Listenerlike: Send + Sync {
type Error;
async fn accept(&self) -> Result<(GenericStream, SOCKSv5Address, u16), Self::Error>;
fn info(&self) -> (SOCKSv5Address, u16);
}
pub struct GenericListener<E> {
pub internal: Box<dyn Listenerlike<Error = E>>,
}
#[async_trait]
impl<E> Listenerlike for GenericListener<E> {
type Error = E;
async fn accept(&self) -> Result<(GenericStream, SOCKSv5Address, u16), Self::Error> {
Ok(self.internal.accept().await?)
}
fn info(&self) -> (SOCKSv5Address, u16) {
self.internal.info()
}
}

214
src/network/standard.rs Normal file
View File

@@ -0,0 +1,214 @@
use crate::messages::ServerResponseStatus;
use crate::network::address::{SOCKSv5Address, ToSOCKSAddress};
use crate::network::datagram::{Datagramlike, GenericDatagramSocket};
use crate::network::generic::Networklike;
use crate::network::listener::{GenericListener, Listenerlike};
use crate::network::stream::{GenericStream, Streamlike};
use async_std::io;
use async_std::net::{TcpListener, TcpStream, UdpSocket};
use async_trait::async_trait;
use log::error;
use std::net::Ipv4Addr;
pub struct Builtin {}
impl Builtin {
pub fn new() -> Builtin {
Builtin {}
}
}
impl Streamlike for TcpStream {}
#[async_trait]
impl Listenerlike for TcpListener {
type Error = io::Error;
async fn accept(&self) -> Result<(GenericStream, SOCKSv5Address, u16), Self::Error> {
let (base, addrport) = self.accept().await?;
let addr = addrport.ip();
let port = addrport.port();
Ok((GenericStream::from(base), SOCKSv5Address::from(addr), port))
}
fn info(&self) -> (SOCKSv5Address, u16) {
match self.local_addr() {
Ok(x) => {
let addr = SOCKSv5Address::from(x.ip());
let port = x.port();
(addr, port)
}
Err(e) => {
error!("Someone asked for a listener address, and we got an error ({}); returning 0.0.0.0:0", e);
(SOCKSv5Address::IP4(Ipv4Addr::from(0)), 0)
}
}
}
}
#[async_trait]
impl Datagramlike for UdpSocket {
type Error = io::Error;
async fn send_to(
&self,
buf: &[u8],
addr: SOCKSv5Address,
port: u16,
) -> Result<usize, Self::Error> {
match addr {
SOCKSv5Address::IP4(a) => self.send_to(buf, (a, port)).await,
SOCKSv5Address::IP6(a) => self.send_to(buf, (a, port)).await,
SOCKSv5Address::Name(n) => self.send_to(buf, (n.as_str(), port)).await,
}
}
async fn recv_from(&self, buf: &mut [u8]) -> Result<(usize, SOCKSv5Address, u16), Self::Error> {
let (amt, addrport) = self.recv_from(buf).await?;
let addr = addrport.ip();
let port = addrport.port();
Ok((amt, SOCKSv5Address::from(addr), port))
}
}
#[async_trait]
impl Networklike for Builtin {
type Error = io::Error;
async fn connect<A: ToSOCKSAddress>(
&mut self,
addr: A,
port: u16,
) -> Result<GenericStream, Self::Error> {
let target = addr.to_socks_address();
let base_stream = match target {
SOCKSv5Address::IP4(a) => TcpStream::connect((a, port)).await?,
SOCKSv5Address::IP6(a) => TcpStream::connect((a, port)).await?,
SOCKSv5Address::Name(n) => TcpStream::connect((n.as_str(), port)).await?,
};
Ok(GenericStream::from(base_stream))
}
async fn listen<A: ToSOCKSAddress>(
&mut self,
addr: A,
port: u16,
) -> Result<GenericListener<Self::Error>, Self::Error> {
let target = addr.to_socks_address();
let base_stream = match target {
SOCKSv5Address::IP4(a) => TcpListener::bind((a, port)).await?,
SOCKSv5Address::IP6(a) => TcpListener::bind((a, port)).await?,
SOCKSv5Address::Name(n) => TcpListener::bind((n.as_str(), port)).await?,
};
Ok(GenericListener {
internal: Box::new(base_stream),
})
}
async fn bind<A: ToSOCKSAddress>(
&mut self,
addr: A,
port: u16,
) -> Result<GenericDatagramSocket<Self::Error>, Self::Error> {
let target = addr.to_socks_address();
let base_socket = match target {
SOCKSv5Address::IP4(a) => UdpSocket::bind((a, port)).await?,
SOCKSv5Address::IP6(a) => UdpSocket::bind((a, port)).await?,
SOCKSv5Address::Name(n) => UdpSocket::bind((n.as_str(), port)).await?,
};
Ok(GenericDatagramSocket {
internal: Box::new(base_socket),
})
}
}
// pub struct StandardNetworking {}
//
// impl StandardNetworking {
// pub fn new() -> StandardNetworking {
// StandardNetworking {}
// }
// }
//
impl From<io::Error> for ServerResponseStatus {
fn from(e: io::Error) -> ServerResponseStatus {
match e.kind() {
io::ErrorKind::ConnectionRefused => ServerResponseStatus::ConnectionRefused,
io::ErrorKind::NotFound => ServerResponseStatus::HostUnreachable,
_ => ServerResponseStatus::GeneralFailure,
}
}
}
//
// #[async_trait]
// impl Network for StandardNetworking {
// type Stream = TcpStream;
// type Listener = TcpListener;
// type UdpSocket = UdpSocket;
// type Error = io::Error;
//
// async fn connect<A: ToSOCKSAddress>(
// &mut self,
// addr: A,
// port: u16,
// ) -> Result<Self::Stream, Self::Error> {
// let target = addr.to_socks_address();
//
// match target {
// SOCKSv5Address::IP4(a) => TcpStream::connect((a, port)).await,
// SOCKSv5Address::IP6(a) => TcpStream::connect((a, port)).await,
// SOCKSv5Address::Name(n) => TcpStream::connect((n.as_str(), port)).await,
// }
// }
//
// async fn udp_socket<A: ToSOCKSAddress>(
// &mut self,
// addr: A,
// port: Option<u16>,
// ) -> Result<Self::UdpSocket, Self::Error> {
// let me = addr.to_socks_address();
// let real_port = port.unwrap_or(0);
//
// match me {
// SOCKSv5Address::IP4(a) => UdpSocket::bind((a, real_port)).await,
// SOCKSv5Address::IP6(a) => UdpSocket::bind((a, real_port)).await,
// SOCKSv5Address::Name(n) => UdpSocket::bind((n.as_str(), real_port)).await,
// }
// }
//
// async fn listen<A: ToSOCKSAddress>(
// &mut self,
// addr: A,
// port: Option<u16>,
// ) -> Result<Self::Listener, Self::Error> {
// let me = addr.to_socks_address();
// let real_port = port.unwrap_or(0);
//
// match me {
// SOCKSv5Address::IP4(a) => TcpListener::bind((a, real_port)).await,
// SOCKSv5Address::IP6(a) => TcpListener::bind((a, real_port)).await,
// SOCKSv5Address::Name(n) => TcpListener::bind((n.as_str(), real_port)).await,
// }
// }
// }
//
// #[async_trait]
// impl SingleShotListener<TcpStream, io::Error> for TcpListener {
// async fn accept(self) -> Result<TcpStream, io::Error> {
// self.accept().await
// }
//
// fn info(&self) -> Result<(SOCKSv5Address, u16), io::Error> {
// match self.local_addr()? {
// SocketAddr::V4(a) => Ok((SOCKSv5Address::IP4(*a.ip()), a.port())),
// SocketAddr::V6(a) => Ok((SOCKSv5Address::IP6(*a.ip()), a.port())),
// }
// }
// }
//

52
src/network/stream.rs Normal file
View File

@@ -0,0 +1,52 @@
use async_std::task::{Context, Poll};
use futures::io;
use futures::io::{AsyncRead, AsyncWrite};
use std::pin::Pin;
use std::sync::Arc;
pub trait Streamlike: AsyncRead + AsyncWrite + Send + Sync + Unpin {}
#[derive(Clone)]
pub struct GenericStream {
internal: Arc<Box<dyn Streamlike>>,
}
impl AsyncRead for GenericStream {
fn poll_read(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
let base = Pin::into_inner(self);
Pin::new(base).poll_read(cx, buf)
}
}
impl AsyncWrite for GenericStream {
fn poll_write(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
let base = Pin::into_inner(self);
Pin::new(base).poll_write(cx, buf)
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
let base = Pin::into_inner(self);
Pin::new(base).poll_flush(cx)
}
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
let base = Pin::into_inner(self);
Pin::new(base).poll_close(cx)
}
}
impl<T: Streamlike + 'static> From<T> for GenericStream {
fn from(x: T) -> GenericStream {
GenericStream {
internal: Arc::new(Box::new(x)),
}
}
}