Files
async-socks5/src/messages/client_command.rs
Adam Wick 0d35f1cdb3 Remove a bunch of (hopefully) unnecessary Pins.
I believe these were introduced previously to solve a problem that we're
no longer dealing with; specifically, if I remember correctly, we
introduced these to deal with how we were going to implement a trait.
However, they don't appear to be necessary any more, so we're going to
get rid of them, so we won't need to deal with them any longer.
2021-10-09 15:22:10 -07:00

163 lines
4.9 KiB
Rust

use crate::errors::{DeserializationError, SerializationError};
use crate::network::SOCKSv5Address;
use crate::serialize::read_amt;
use crate::standard_roundtrip;
#[cfg(test)]
use async_std::io::ErrorKind;
#[cfg(test)]
use async_std::task;
#[cfg(test)]
use futures::io::Cursor;
use futures::io::{AsyncRead, AsyncWrite, AsyncWriteExt};
#[cfg(test)]
use quickcheck::{quickcheck, Arbitrary, Gen};
#[cfg(test)]
use std::net::Ipv4Addr;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ClientConnectionCommand {
EstablishTCPStream,
EstablishTCPPortBinding,
AssociateUDPPort,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ClientConnectionRequest {
pub command_code: ClientConnectionCommand,
pub destination_address: SOCKSv5Address,
pub destination_port: u16,
}
impl ClientConnectionRequest {
pub async fn read<R: AsyncRead + Send + Unpin>(
r: &mut R,
) -> Result<Self, DeserializationError> {
let mut buffer = [0; 2];
read_amt(r, 2, &mut buffer).await?;
if buffer[0] != 5 {
return Err(DeserializationError::InvalidVersion(5, buffer[0]));
}
let command_code = match buffer[1] {
0x01 => ClientConnectionCommand::EstablishTCPStream,
0x02 => ClientConnectionCommand::EstablishTCPPortBinding,
0x03 => ClientConnectionCommand::AssociateUDPPort,
x => return Err(DeserializationError::InvalidClientCommand(x)),
};
let destination_address = SOCKSv5Address::read(r).await?;
read_amt(r, 2, &mut buffer).await?;
let destination_port = ((buffer[0] as u16) << 8) + (buffer[1] as u16);
Ok(ClientConnectionRequest {
command_code,
destination_address,
destination_port,
})
}
pub async fn write<W: AsyncWrite + Send + Unpin>(
&self,
w: &mut W,
) -> Result<(), SerializationError> {
let command = match self.command_code {
ClientConnectionCommand::EstablishTCPStream => 1,
ClientConnectionCommand::EstablishTCPPortBinding => 2,
ClientConnectionCommand::AssociateUDPPort => 3,
};
w.write_all(&[5, command]).await?;
self.destination_address.write(w).await?;
w.write_all(&[
(self.destination_port >> 8) as u8,
(self.destination_port & 0xffu16) as u8,
])
.await
.map_err(SerializationError::IOError)
}
}
#[cfg(test)]
impl Arbitrary for ClientConnectionCommand {
fn arbitrary(g: &mut Gen) -> ClientConnectionCommand {
let options = [
ClientConnectionCommand::EstablishTCPStream,
ClientConnectionCommand::EstablishTCPPortBinding,
ClientConnectionCommand::AssociateUDPPort,
];
g.choose(&options).unwrap().clone()
}
}
#[cfg(test)]
impl Arbitrary for ClientConnectionRequest {
fn arbitrary(g: &mut Gen) -> Self {
let command_code = ClientConnectionCommand::arbitrary(g);
let destination_address = SOCKSv5Address::arbitrary(g);
let destination_port = u16::arbitrary(g);
ClientConnectionRequest {
command_code,
destination_address,
destination_port,
}
}
}
standard_roundtrip!(client_request_roundtrips, ClientConnectionRequest);
#[test]
fn check_short_reads() {
let empty = vec![];
let mut cursor = Cursor::new(empty);
let ys = ClientConnectionRequest::read(&mut cursor);
assert_eq!(Err(DeserializationError::NotEnoughData), task::block_on(ys));
let no_len = vec![5, 1];
let mut cursor = Cursor::new(no_len);
let ys = ClientConnectionRequest::read(&mut cursor);
assert_eq!(Err(DeserializationError::NotEnoughData), task::block_on(ys));
}
#[test]
fn check_bad_version() {
let bad_ver = vec![6, 1, 1];
let mut cursor = Cursor::new(bad_ver);
let ys = ClientConnectionRequest::read(&mut cursor);
assert_eq!(
Err(DeserializationError::InvalidVersion(5, 6)),
task::block_on(ys)
);
}
#[test]
fn check_bad_command() {
let bad_cmd = vec![5, 32, 1];
let mut cursor = Cursor::new(bad_cmd);
let ys = ClientConnectionRequest::read(&mut cursor);
assert_eq!(
Err(DeserializationError::InvalidClientCommand(32)),
task::block_on(ys)
);
}
#[test]
fn short_write_fails_right() {
let mut buffer = [0u8; 2];
let cmd = ClientConnectionRequest {
command_code: ClientConnectionCommand::AssociateUDPPort,
destination_address: SOCKSv5Address::IP4(Ipv4Addr::from(0)),
destination_port: 22,
};
let mut cursor = Cursor::new(&mut buffer as &mut [u8]);
let result = task::block_on(cmd.write(&mut cursor));
match result {
Ok(_) => assert!(false, "Mysteriously able to fit > 2 bytes in 2 bytes."),
Err(SerializationError::IOError(x)) => assert_eq!(ErrorKind::WriteZero, x.kind()),
Err(e) => assert!(false, "Got the wrong error writing too much data: {}", e),
}
}