Ditch ToSocksAddress for the standard From/TryFrom.
This induces an added `Send` in the Network trait and its implementations, but provides us the ability to use standard functions with obvious extensions. So that's nice. I've also added some additional testing to sanity check the conversions.
This commit is contained in:
@@ -6,7 +6,7 @@ pub mod standard;
|
|||||||
pub mod stream;
|
pub mod stream;
|
||||||
|
|
||||||
use crate::messages::ServerResponseStatus;
|
use crate::messages::ServerResponseStatus;
|
||||||
pub use crate::network::address::{SOCKSv5Address, ToSOCKSAddress};
|
pub use crate::network::address::SOCKSv5Address;
|
||||||
pub use crate::network::standard::Builtin;
|
pub use crate::network::standard::Builtin;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use futures::{AsyncRead, AsyncWrite};
|
use futures::{AsyncRead, AsyncWrite};
|
||||||
@@ -19,17 +19,17 @@ pub trait Network {
|
|||||||
type UdpSocket;
|
type UdpSocket;
|
||||||
type Error: fmt::Debug + fmt::Display + Into<ServerResponseStatus>;
|
type Error: fmt::Debug + fmt::Display + Into<ServerResponseStatus>;
|
||||||
|
|
||||||
async fn connect<A: ToSOCKSAddress>(
|
async fn connect<A: Into<SOCKSv5Address>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
addr: A,
|
addr: A,
|
||||||
port: u16,
|
port: u16,
|
||||||
) -> Result<Self::Stream, Self::Error>;
|
) -> Result<Self::Stream, Self::Error>;
|
||||||
async fn udp_socket<A: ToSOCKSAddress>(
|
async fn udp_socket<A: Into<SOCKSv5Address>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
addr: A,
|
addr: A,
|
||||||
port: Option<u16>,
|
port: Option<u16>,
|
||||||
) -> Result<Self::UdpSocket, Self::Error>;
|
) -> Result<Self::UdpSocket, Self::Error>;
|
||||||
async fn listen<A: ToSOCKSAddress>(
|
async fn listen<A: Into<SOCKSv5Address>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
addr: A,
|
addr: A,
|
||||||
port: Option<u16>,
|
port: Option<u16>,
|
||||||
|
|||||||
@@ -10,13 +10,11 @@ use futures::io::Cursor;
|
|||||||
use futures::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
|
use futures::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use quickcheck::{quickcheck, Arbitrary, Gen};
|
use quickcheck::{quickcheck, Arbitrary, Gen};
|
||||||
|
use std::convert::TryFrom;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
|
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
use thiserror::Error;
|
||||||
pub trait ToSOCKSAddress: Send {
|
|
||||||
fn to_socks_address(&self) -> SOCKSv5Address;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub enum SOCKSv5Address {
|
pub enum SOCKSv5Address {
|
||||||
@@ -25,42 +23,83 @@ pub enum SOCKSv5Address {
|
|||||||
Name(String),
|
Name(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToSOCKSAddress for SOCKSv5Address {
|
#[derive(Error, Debug, PartialEq)]
|
||||||
fn to_socks_address(&self) -> SOCKSv5Address {
|
pub enum AddressConversionError {
|
||||||
self.clone()
|
#[error("Couldn't convert IPv4 address into destination type")]
|
||||||
}
|
CouldntConvertIP4,
|
||||||
|
#[error("Couldn't convert IPv6 address into destination type")]
|
||||||
|
CouldntConvertIP6,
|
||||||
|
#[error("Couldn't convert name into destination type")]
|
||||||
|
CouldntConvertName,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToSOCKSAddress for IpAddr {
|
|
||||||
fn to_socks_address(&self) -> SOCKSv5Address {
|
impl From<IpAddr> for SOCKSv5Address {
|
||||||
match self {
|
fn from(x: IpAddr) -> SOCKSv5Address {
|
||||||
IpAddr::V4(a) => SOCKSv5Address::IP4(*a),
|
match x {
|
||||||
IpAddr::V6(a) => SOCKSv5Address::IP6(*a),
|
IpAddr::V4(a) => SOCKSv5Address::IP4(a),
|
||||||
|
IpAddr::V6(a) => SOCKSv5Address::IP6(a),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToSOCKSAddress for Ipv4Addr {
|
impl TryFrom<SOCKSv5Address> for IpAddr {
|
||||||
fn to_socks_address(&self) -> SOCKSv5Address {
|
type Error = AddressConversionError;
|
||||||
SOCKSv5Address::IP4(*self)
|
|
||||||
|
fn try_from(value: SOCKSv5Address) -> Result<Self, Self::Error> {
|
||||||
|
match value {
|
||||||
|
SOCKSv5Address::IP4(a) => Ok(IpAddr::V4(a)),
|
||||||
|
SOCKSv5Address::IP6(a) => Ok(IpAddr::V6(a)),
|
||||||
|
SOCKSv5Address::Name(_) => Err(AddressConversionError::CouldntConvertName),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToSOCKSAddress for Ipv6Addr {
|
impl From<Ipv4Addr> for SOCKSv5Address {
|
||||||
fn to_socks_address(&self) -> SOCKSv5Address {
|
fn from(x: Ipv4Addr) -> Self {
|
||||||
SOCKSv5Address::IP6(*self)
|
SOCKSv5Address::IP4(x)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToSOCKSAddress for String {
|
impl TryFrom<SOCKSv5Address> for Ipv4Addr {
|
||||||
fn to_socks_address(&self) -> SOCKSv5Address {
|
type Error = AddressConversionError;
|
||||||
SOCKSv5Address::Name(self.clone())
|
|
||||||
|
fn try_from(value: SOCKSv5Address) -> Result<Self, Self::Error> {
|
||||||
|
match value {
|
||||||
|
SOCKSv5Address::IP4(a) => Ok(a),
|
||||||
|
SOCKSv5Address::IP6(_) => Err(AddressConversionError::CouldntConvertIP6),
|
||||||
|
SOCKSv5Address::Name(_) => Err(AddressConversionError::CouldntConvertName),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ToSOCKSAddress for &'a str {
|
impl From<Ipv6Addr> for SOCKSv5Address {
|
||||||
fn to_socks_address(&self) -> SOCKSv5Address {
|
fn from(x: Ipv6Addr) -> Self {
|
||||||
SOCKSv5Address::Name(self.to_string())
|
SOCKSv5Address::IP6(x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<SOCKSv5Address> for Ipv6Addr {
|
||||||
|
type Error = AddressConversionError;
|
||||||
|
|
||||||
|
fn try_from(value: SOCKSv5Address) -> Result<Self, Self::Error> {
|
||||||
|
match value {
|
||||||
|
SOCKSv5Address::IP4(_) => Err(AddressConversionError::CouldntConvertIP4),
|
||||||
|
SOCKSv5Address::IP6(a) => Ok(a),
|
||||||
|
SOCKSv5Address::Name(_) => Err(AddressConversionError::CouldntConvertName),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<String> for SOCKSv5Address {
|
||||||
|
fn from(x: String) -> Self {
|
||||||
|
SOCKSv5Address::Name(x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a str> for SOCKSv5Address {
|
||||||
|
fn from(x: &str) -> SOCKSv5Address {
|
||||||
|
SOCKSv5Address::Name(x.to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,15 +113,6 @@ impl fmt::Display for SOCKSv5Address {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
impl SOCKSv5Address {
|
||||||
pub async fn read<R: AsyncRead + Send + Unpin>(
|
pub async fn read<R: AsyncRead + Send + Unpin>(
|
||||||
mut r: Pin<&mut R>,
|
mut r: Pin<&mut R>,
|
||||||
@@ -156,3 +186,65 @@ impl Arbitrary for SOCKSv5Address {
|
|||||||
}
|
}
|
||||||
|
|
||||||
standard_roundtrip!(address_roundtrips, SOCKSv5Address);
|
standard_roundtrip!(address_roundtrips, SOCKSv5Address);
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
quickcheck! {
|
||||||
|
fn ip_conversion(x: IpAddr) -> bool {
|
||||||
|
match x {
|
||||||
|
IpAddr::V4(ref a) =>
|
||||||
|
assert_eq!(Err(AddressConversionError::CouldntConvertIP4),
|
||||||
|
Ipv6Addr::try_from(SOCKSv5Address::from(a.clone()))),
|
||||||
|
IpAddr::V6(ref a) =>
|
||||||
|
assert_eq!(Err(AddressConversionError::CouldntConvertIP6),
|
||||||
|
Ipv4Addr::try_from(SOCKSv5Address::from(a.clone()))),
|
||||||
|
}
|
||||||
|
x == IpAddr::try_from(SOCKSv5Address::from(x.clone())).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ip4_conversion(x: Ipv4Addr) -> bool {
|
||||||
|
x == Ipv4Addr::try_from(SOCKSv5Address::from(x.clone())).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ip6_conversion(x: Ipv6Addr) -> bool {
|
||||||
|
x == Ipv6Addr::try_from(SOCKSv5Address::from(x.clone())).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn display_matches(x: SOCKSv5Address) -> bool {
|
||||||
|
match x {
|
||||||
|
SOCKSv5Address::IP4(a) => format!("{}", a) == format!("{}", x),
|
||||||
|
SOCKSv5Address::IP6(a) => format!("{}", a) == format!("{}", x),
|
||||||
|
SOCKSv5Address::Name(ref a) => format!("{}", a) == format!("{}", x),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bad_read_key(x: u8) -> bool {
|
||||||
|
match x {
|
||||||
|
1 => true,
|
||||||
|
3 => true,
|
||||||
|
4 => true,
|
||||||
|
_ => {
|
||||||
|
let buffer = [x, 0, 1, 2, 9, 10];
|
||||||
|
let mut cursor = Cursor::new(buffer);
|
||||||
|
let meh = SOCKSv5Address::read(Pin::new(&mut cursor));
|
||||||
|
Err(DeserializationError::InvalidAddressType(x)) == task::block_on(meh)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn domain_name_sanity() {
|
||||||
|
let name = "uhsure.com";
|
||||||
|
let strname = name.to_string();
|
||||||
|
|
||||||
|
let addr1 = SOCKSv5Address::from(name);
|
||||||
|
let addr2 = SOCKSv5Address::from(strname);
|
||||||
|
|
||||||
|
assert_eq!(addr1, addr2);
|
||||||
|
assert_eq!(Err(AddressConversionError::CouldntConvertName),
|
||||||
|
IpAddr::try_from(addr1.clone()));
|
||||||
|
assert_eq!(Err(AddressConversionError::CouldntConvertName),
|
||||||
|
Ipv4Addr::try_from(addr1.clone()));
|
||||||
|
assert_eq!(Err(AddressConversionError::CouldntConvertName),
|
||||||
|
Ipv6Addr::try_from(addr1.clone()));
|
||||||
|
}
|
||||||
@@ -1,11 +1,12 @@
|
|||||||
use crate::messages::ServerResponseStatus;
|
use crate::messages::ServerResponseStatus;
|
||||||
use crate::network::address::ToSOCKSAddress;
|
use crate::network::address::SOCKSv5Address;
|
||||||
use crate::network::datagram::GenericDatagramSocket;
|
use crate::network::datagram::GenericDatagramSocket;
|
||||||
use crate::network::listener::GenericListener;
|
use crate::network::listener::GenericListener;
|
||||||
use crate::network::stream::GenericStream;
|
use crate::network::stream::GenericStream;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait Networklike {
|
pub trait Networklike {
|
||||||
/// The error type for things that fail on this network. Apologies in advance
|
/// The error type for things that fail on this network. Apologies in advance
|
||||||
@@ -19,7 +20,7 @@ pub trait Networklike {
|
|||||||
/// may be exactly what you're using. However, in order to support tunnelling
|
/// 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
|
/// scenarios (i.e., using another proxy, going through Tor or SSH, etc.) we
|
||||||
/// work generically over any stream-like object.
|
/// work generically over any stream-like object.
|
||||||
async fn connect<A: ToSOCKSAddress>(
|
async fn connect<A: Send + Into<SOCKSv5Address>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
addr: A,
|
addr: A,
|
||||||
port: u16,
|
port: u16,
|
||||||
@@ -27,7 +28,7 @@ pub trait Networklike {
|
|||||||
|
|
||||||
/// Listen for connections on the given address and port, returning a generic
|
/// Listen for connections on the given address and port, returning a generic
|
||||||
/// listener socket to use in the future.
|
/// listener socket to use in the future.
|
||||||
async fn listen<A: ToSOCKSAddress>(
|
async fn listen<A: Send + Into<SOCKSv5Address>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
addr: A,
|
addr: A,
|
||||||
port: u16,
|
port: u16,
|
||||||
@@ -40,7 +41,7 @@ pub trait Networklike {
|
|||||||
///
|
///
|
||||||
/// Recall when using these functions that datagram protocols allow for packet
|
/// Recall when using these functions that datagram protocols allow for packet
|
||||||
/// loss and out-of-order delivery. So ... be warned.
|
/// loss and out-of-order delivery. So ... be warned.
|
||||||
async fn bind<A: ToSOCKSAddress>(
|
async fn bind<A: Send + Into<SOCKSv5Address>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
addr: A,
|
addr: A,
|
||||||
port: u16,
|
port: u16,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::messages::ServerResponseStatus;
|
use crate::messages::ServerResponseStatus;
|
||||||
use crate::network::address::{SOCKSv5Address, ToSOCKSAddress};
|
use crate::network::address::SOCKSv5Address;
|
||||||
use crate::network::datagram::{Datagramlike, GenericDatagramSocket};
|
use crate::network::datagram::{Datagramlike, GenericDatagramSocket};
|
||||||
use crate::network::generic::Networklike;
|
use crate::network::generic::Networklike;
|
||||||
use crate::network::listener::{GenericListener, Listenerlike};
|
use crate::network::listener::{GenericListener, Listenerlike};
|
||||||
@@ -75,12 +75,12 @@ impl Datagramlike for UdpSocket {
|
|||||||
impl Networklike for Builtin {
|
impl Networklike for Builtin {
|
||||||
type Error = io::Error;
|
type Error = io::Error;
|
||||||
|
|
||||||
async fn connect<A: ToSOCKSAddress>(
|
async fn connect<A: Send + Into<SOCKSv5Address>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
addr: A,
|
addr: A,
|
||||||
port: u16,
|
port: u16,
|
||||||
) -> Result<GenericStream, Self::Error> {
|
) -> Result<GenericStream, Self::Error> {
|
||||||
let target = addr.to_socks_address();
|
let target = addr.into();
|
||||||
|
|
||||||
let base_stream = match target {
|
let base_stream = match target {
|
||||||
SOCKSv5Address::IP4(a) => TcpStream::connect((a, port)).await?,
|
SOCKSv5Address::IP4(a) => TcpStream::connect((a, port)).await?,
|
||||||
@@ -91,12 +91,12 @@ impl Networklike for Builtin {
|
|||||||
Ok(GenericStream::from(base_stream))
|
Ok(GenericStream::from(base_stream))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn listen<A: ToSOCKSAddress>(
|
async fn listen<A: Send + Into<SOCKSv5Address>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
addr: A,
|
addr: A,
|
||||||
port: u16,
|
port: u16,
|
||||||
) -> Result<GenericListener<Self::Error>, Self::Error> {
|
) -> Result<GenericListener<Self::Error>, Self::Error> {
|
||||||
let target = addr.to_socks_address();
|
let target = addr.into();
|
||||||
|
|
||||||
let base_stream = match target {
|
let base_stream = match target {
|
||||||
SOCKSv5Address::IP4(a) => TcpListener::bind((a, port)).await?,
|
SOCKSv5Address::IP4(a) => TcpListener::bind((a, port)).await?,
|
||||||
@@ -109,12 +109,12 @@ impl Networklike for Builtin {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn bind<A: ToSOCKSAddress>(
|
async fn bind<A: Send + Into<SOCKSv5Address>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
addr: A,
|
addr: A,
|
||||||
port: u16,
|
port: u16,
|
||||||
) -> Result<GenericDatagramSocket<Self::Error>, Self::Error> {
|
) -> Result<GenericDatagramSocket<Self::Error>, Self::Error> {
|
||||||
let target = addr.to_socks_address();
|
let target = addr.into();
|
||||||
|
|
||||||
let base_socket = match target {
|
let base_socket = match target {
|
||||||
SOCKSv5Address::IP4(a) => UdpSocket::bind((a, port)).await?,
|
SOCKSv5Address::IP4(a) => UdpSocket::bind((a, port)).await?,
|
||||||
@@ -158,7 +158,7 @@ impl From<io::Error> for ServerResponseStatus {
|
|||||||
// addr: A,
|
// addr: A,
|
||||||
// port: u16,
|
// port: u16,
|
||||||
// ) -> Result<Self::Stream, Self::Error> {
|
// ) -> Result<Self::Stream, Self::Error> {
|
||||||
// let target = addr.to_socks_address();
|
// let target = addr.into();
|
||||||
//
|
//
|
||||||
// match target {
|
// match target {
|
||||||
// SOCKSv5Address::IP4(a) => TcpStream::connect((a, port)).await,
|
// SOCKSv5Address::IP4(a) => TcpStream::connect((a, port)).await,
|
||||||
@@ -172,7 +172,7 @@ impl From<io::Error> for ServerResponseStatus {
|
|||||||
// addr: A,
|
// addr: A,
|
||||||
// port: Option<u16>,
|
// port: Option<u16>,
|
||||||
// ) -> Result<Self::UdpSocket, Self::Error> {
|
// ) -> Result<Self::UdpSocket, Self::Error> {
|
||||||
// let me = addr.to_socks_address();
|
// let me = addr.into();
|
||||||
// let real_port = port.unwrap_or(0);
|
// let real_port = port.unwrap_or(0);
|
||||||
//
|
//
|
||||||
// match me {
|
// match me {
|
||||||
@@ -187,7 +187,7 @@ impl From<io::Error> for ServerResponseStatus {
|
|||||||
// addr: A,
|
// addr: A,
|
||||||
// port: Option<u16>,
|
// port: Option<u16>,
|
||||||
// ) -> Result<Self::Listener, Self::Error> {
|
// ) -> Result<Self::Listener, Self::Error> {
|
||||||
// let me = addr.to_socks_address();
|
// let me = addr.into();
|
||||||
// let real_port = port.unwrap_or(0);
|
// let real_port = port.unwrap_or(0);
|
||||||
//
|
//
|
||||||
// match me {
|
// match me {
|
||||||
|
|||||||
Reference in New Issue
Block a user