checkpoint
This commit is contained in:
151
src/network/address.rs
Normal file
151
src/network/address.rs
Normal 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
37
src/network/datagram.rs
Normal 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
48
src/network/generic.rs
Normal 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
28
src/network/listener.rs
Normal 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
214
src/network/standard.rs
Normal 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
52
src/network/stream.rs
Normal 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)),
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user