Add HasLocalAddress for querying a socket's address, and a test.
This commit is contained in:
@@ -168,6 +168,10 @@ impl SOCKSv5Address {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait HasLocalAddress {
|
||||||
|
fn local_addr(&self) -> (SOCKSv5Address, u16);
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
impl Arbitrary for SOCKSv5Address {
|
impl Arbitrary for SOCKSv5Address {
|
||||||
fn arbitrary(g: &mut Gen) -> Self {
|
fn arbitrary(g: &mut Gen) -> Self {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use crate::network::address::SOCKSv5Address;
|
use crate::network::address::{HasLocalAddress, SOCKSv5Address};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait Datagramlike: Send + Sync {
|
pub trait Datagramlike: Send + Sync + HasLocalAddress {
|
||||||
type Error;
|
type Error;
|
||||||
|
|
||||||
async fn send_to(
|
async fn send_to(
|
||||||
@@ -35,3 +35,9 @@ impl<E> Datagramlike for GenericDatagramSocket<E> {
|
|||||||
Ok(self.internal.recv_from(buf).await?)
|
Ok(self.internal.recv_from(buf).await?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<E> HasLocalAddress for GenericDatagramSocket<E> {
|
||||||
|
fn local_addr(&self) -> (SOCKSv5Address, u16) {
|
||||||
|
self.internal.local_addr()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
use crate::network::address::SOCKSv5Address;
|
use crate::network::address::{HasLocalAddress, SOCKSv5Address};
|
||||||
use crate::network::stream::GenericStream;
|
use crate::network::stream::GenericStream;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait Listenerlike: Send + Sync {
|
pub trait Listenerlike: Send + Sync + HasLocalAddress {
|
||||||
type Error;
|
type Error;
|
||||||
|
|
||||||
async fn accept(&self) -> Result<(GenericStream, SOCKSv5Address, u16), Self::Error>;
|
async fn accept(&self) -> Result<(GenericStream, SOCKSv5Address, u16), Self::Error>;
|
||||||
fn info(&self) -> (SOCKSv5Address, u16);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct GenericListener<E> {
|
pub struct GenericListener<E> {
|
||||||
@@ -21,8 +20,10 @@ impl<E> Listenerlike for GenericListener<E> {
|
|||||||
async fn accept(&self) -> Result<(GenericStream, SOCKSv5Address, u16), Self::Error> {
|
async fn accept(&self) -> Result<(GenericStream, SOCKSv5Address, u16), Self::Error> {
|
||||||
Ok(self.internal.accept().await?)
|
Ok(self.internal.accept().await?)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn info(&self) -> (SOCKSv5Address, u16) {
|
impl<E> HasLocalAddress for GenericListener<E> {
|
||||||
self.internal.info()
|
fn local_addr(&self) -> (SOCKSv5Address, u16) {
|
||||||
|
self.internal.local_addr()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,17 @@
|
|||||||
use crate::messages::ServerResponseStatus;
|
use crate::messages::ServerResponseStatus;
|
||||||
use crate::network::address::SOCKSv5Address;
|
use crate::network::address::{HasLocalAddress, 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};
|
||||||
use crate::network::stream::{GenericStream, Streamlike};
|
use crate::network::stream::{GenericStream, Streamlike};
|
||||||
use async_std::io;
|
use async_std::io;
|
||||||
|
#[cfg(test)]
|
||||||
|
use async_std::io::ReadExt;
|
||||||
use async_std::net::{TcpListener, TcpStream, UdpSocket};
|
use async_std::net::{TcpListener, TcpStream, UdpSocket};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
#[cfg(test)]
|
||||||
|
use futures::AsyncWriteExt;
|
||||||
use log::error;
|
use log::error;
|
||||||
use std::net::Ipv4Addr;
|
|
||||||
|
|
||||||
pub struct Builtin {}
|
pub struct Builtin {}
|
||||||
|
|
||||||
@@ -18,6 +21,27 @@ impl Builtin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! local_address_impl {
|
||||||
|
($t: ty) => {
|
||||||
|
impl HasLocalAddress for $t {
|
||||||
|
fn local_addr(&self) -> (SOCKSv5Address, u16) {
|
||||||
|
match self.local_addr() {
|
||||||
|
Ok(a) =>
|
||||||
|
(SOCKSv5Address::from(a.ip()), a.port()),
|
||||||
|
Err(e) => {
|
||||||
|
error!("Couldn't translate (Streamlike) local address to SOCKS local address: {}", e);
|
||||||
|
(SOCKSv5Address::from("localhost"), 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
local_address_impl!(TcpStream);
|
||||||
|
local_address_impl!(TcpListener);
|
||||||
|
local_address_impl!(UdpSocket);
|
||||||
|
|
||||||
impl Streamlike for TcpStream {}
|
impl Streamlike for TcpStream {}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
@@ -28,21 +52,7 @@ impl Listenerlike for TcpListener {
|
|||||||
let (base, addrport) = self.accept().await?;
|
let (base, addrport) = self.accept().await?;
|
||||||
let addr = addrport.ip();
|
let addr = addrport.ip();
|
||||||
let port = addrport.port();
|
let port = addrport.port();
|
||||||
Ok((GenericStream::from(base), SOCKSv5Address::from(addr), port))
|
Ok((GenericStream::new(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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,7 +98,7 @@ impl Networklike for Builtin {
|
|||||||
SOCKSv5Address::Name(n) => TcpStream::connect((n.as_str(), port)).await?,
|
SOCKSv5Address::Name(n) => TcpStream::connect((n.as_str(), port)).await?,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(GenericStream::from(base_stream))
|
Ok(GenericStream::new(base_stream))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn listen<A: Send + Into<SOCKSv5Address>>(
|
async fn listen<A: Send + Into<SOCKSv5Address>>(
|
||||||
@@ -128,14 +138,59 @@ impl Networklike for Builtin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub struct StandardNetworking {}
|
#[test]
|
||||||
//
|
fn check_sanity() {
|
||||||
// impl StandardNetworking {
|
async_std::task::block_on(async {
|
||||||
// pub fn new() -> StandardNetworking {
|
// Technically, this is UDP, and UDP is lossy. We're going to assume we're not
|
||||||
// StandardNetworking {}
|
// going to get any dropped data along here ... which is a very questionable
|
||||||
// }
|
// assumption, morally speaking, but probably fine for most purposes.
|
||||||
// }
|
let mut network = Builtin::new();
|
||||||
//
|
let receiver = network.bind("localhost", 0).await.expect("Failed to bind receiver socket.");
|
||||||
|
let sender = network.bind("localhost", 0).await.expect("Failed to bind sender socket.");
|
||||||
|
let buffer = [0xde, 0xea, 0xbe, 0xef];
|
||||||
|
let (receiver_addr, receiver_port) = receiver.local_addr();
|
||||||
|
sender.send_to(&buffer, receiver_addr, receiver_port).await.expect("Failure sending datagram!");
|
||||||
|
let mut recvbuffer = [0; 4];
|
||||||
|
let (s, f, p) = receiver.recv_from(&mut recvbuffer).await.expect("Didn't receive UDP message?");
|
||||||
|
let (sender_addr, sender_port) = sender.local_addr();
|
||||||
|
assert_eq!(s, 4);
|
||||||
|
assert_eq!(f, sender_addr);
|
||||||
|
assert_eq!(p, sender_port);
|
||||||
|
assert_eq!(recvbuffer, buffer);
|
||||||
|
});
|
||||||
|
|
||||||
|
// This whole block should be pretty solid, though, unless the system we're
|
||||||
|
// on is in a pretty weird place.
|
||||||
|
let mut network = Builtin::new();
|
||||||
|
|
||||||
|
let listener = async_std::task::block_on(network.listen("localhost", 0)).expect("Couldn't set up listener on localhost");
|
||||||
|
let (listener_address, listener_port) = listener.local_addr();
|
||||||
|
|
||||||
|
let listener_task_handle = async_std::task::spawn(async move {
|
||||||
|
let (mut stream, addr, port) = listener.accept().await.expect("Didn't get connection");
|
||||||
|
let mut result_buffer = [0u8; 4];
|
||||||
|
println!("Starting read!");
|
||||||
|
stream.read_exact(&mut result_buffer).await.expect("Read failure in TCP test");
|
||||||
|
(result_buffer, addr, port)
|
||||||
|
});
|
||||||
|
|
||||||
|
let sender_task_handle = async_std::task::spawn(async move {
|
||||||
|
let mut sender = network.connect(listener_address, listener_port).await.expect("Coudln't connect to listener?");
|
||||||
|
let (sender_address, sender_port) = sender.local_addr();
|
||||||
|
let send_buffer = [0xa, 0xff, 0xab, 0x1e];
|
||||||
|
sender.write_all(&send_buffer).await.expect("Couldn't send the write buffer");
|
||||||
|
(sender_address, sender_port)
|
||||||
|
});
|
||||||
|
|
||||||
|
async_std::task::block_on(async {
|
||||||
|
let (result, result_from, result_from_port) = listener_task_handle.await;
|
||||||
|
assert_eq!(result, [0xa, 0xff, 0xab, 0x1e]);
|
||||||
|
let (sender_address, sender_port) = sender_task_handle.await;
|
||||||
|
assert_eq!(result_from, sender_address);
|
||||||
|
assert_eq!(result_from_port, sender_port);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
impl From<io::Error> for ServerResponseStatus {
|
impl From<io::Error> for ServerResponseStatus {
|
||||||
fn from(e: io::Error) -> ServerResponseStatus {
|
fn from(e: io::Error) -> ServerResponseStatus {
|
||||||
match e.kind() {
|
match e.kind() {
|
||||||
@@ -145,70 +200,3 @@ impl From<io::Error> for ServerResponseStatus {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//
|
|
||||||
// #[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.into();
|
|
||||||
//
|
|
||||||
// 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.into();
|
|
||||||
// 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.into();
|
|
||||||
// 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())),
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
use async_std::task::{Context, Poll};
|
use async_std::task::{Context, Poll};
|
||||||
use futures::io;
|
use futures::io;
|
||||||
|
use crate::network::SOCKSv5Address;
|
||||||
use futures::io::{AsyncRead, AsyncWrite};
|
use futures::io::{AsyncRead, AsyncWrite};
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
pub trait Streamlike: AsyncRead + AsyncWrite + Send + Sync + Unpin {}
|
use super::address::HasLocalAddress;
|
||||||
|
|
||||||
|
pub trait Streamlike: AsyncRead + AsyncWrite + HasLocalAddress + Send + Sync + Unpin {}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct GenericStream {
|
pub struct GenericStream {
|
||||||
@@ -19,6 +22,11 @@ impl GenericStream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl HasLocalAddress for GenericStream {
|
||||||
|
fn local_addr(&self) -> (SOCKSv5Address, u16) {
|
||||||
|
let item = self.internal.lock().unwrap();
|
||||||
|
item.local_addr()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsyncRead for GenericStream {
|
impl AsyncRead for GenericStream {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ use crate::messages::{
|
|||||||
AuthenticationMethod, ClientConnectionCommand, ClientConnectionRequest, ClientGreeting,
|
AuthenticationMethod, ClientConnectionCommand, ClientConnectionRequest, ClientGreeting,
|
||||||
ClientUsernamePassword, ServerChoice, ServerResponse, ServerResponseStatus,
|
ClientUsernamePassword, ServerChoice, ServerResponse, ServerResponseStatus,
|
||||||
};
|
};
|
||||||
|
use crate::network::address::HasLocalAddress;
|
||||||
use crate::network::generic::Networklike;
|
use crate::network::generic::Networklike;
|
||||||
use crate::network::listener::{GenericListener, Listenerlike};
|
use crate::network::listener::{GenericListener, Listenerlike};
|
||||||
use crate::network::stream::GenericStream;
|
use crate::network::stream::GenericStream;
|
||||||
@@ -45,7 +46,7 @@ impl<N: Networklike + Send + 'static> SOCKSv5Server<N> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run(self) -> Result<(), N::Error> {
|
pub async fn run(self) -> Result<(), N::Error> {
|
||||||
let (my_addr, my_port) = self.listener.info();
|
let (my_addr, my_port) = self.listener.local_addr();
|
||||||
info!("Starting SOCKSv5 server on {}:{}", my_addr, my_port);
|
info!("Starting SOCKSv5 server on {}:{}", my_addr, my_port);
|
||||||
let locked_network = Arc::new(Mutex::new(self.network));
|
let locked_network = Arc::new(Mutex::new(self.network));
|
||||||
|
|
||||||
@@ -241,7 +242,7 @@ where
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let (bound_address, bound_port) = incoming_listener.info();
|
let (bound_address, bound_port) = incoming_listener.local_addr();
|
||||||
trace!(
|
trace!(
|
||||||
"Set up {}:{} to address request for {}:{}",
|
"Set up {}:{} to address request for {}:{}",
|
||||||
bound_address,
|
bound_address,
|
||||||
|
|||||||
Reference in New Issue
Block a user