From eb88596f2830905a45dc58e02a6e8283aa810e8f Mon Sep 17 00:00:00 2001 From: Anmol Bhatia Date: Sat, 30 Sep 2023 21:55:05 +0200 Subject: [PATCH] Changes based on PR[https://github.com/epi-project/socksx/pull/1] --- Dockerfile | 2 +- Dockerfile.counter | 4 +-- Dockerfile.encrypt-decrypt | 2 +- docker-compose-extensive.yml | 9 +++++++ examples/client/client.rs | 3 +++ socksx/examples/client.rs | 3 +++ socksx/examples/functions.rs | 3 +++ socksx/examples/redirector.rs | 3 +++ socksx/src/common/addresses.rs | 2 +- socksx/src/common/util.rs | 44 +++++++++++++++++++++++++++++++++ socksx/src/lib.rs | 8 ++++-- socksx/src/main.rs | 7 ++++++ socksx/src/socks5/s5_handler.rs | 2 +- socksx/src/socks6/chain.rs | 4 ++- socksx/src/socks6/mod.rs | 44 ++++++++++++++++++++++++++++++++- socksx/src/socks6/options.rs | 14 +++++------ 16 files changed, 137 insertions(+), 17 deletions(-) diff --git a/Dockerfile b/Dockerfile index 02f6c43..669bc7b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,7 +15,7 @@ WORKDIR /socksx RUN cargo build --release # Define final image -FROM ubuntu:23.10 +FROM ubuntu:22.04 RUN apt-get update && apt-get install -y \ libssl3 \ diff --git a/Dockerfile.counter b/Dockerfile.counter index 381fa29..a71b7f2 100644 --- a/Dockerfile.counter +++ b/Dockerfile.counter @@ -1,6 +1,6 @@ # This Dockerfile is supposed to create a socks proxy server that mimics a firewall. -# This won't build on Mac OS X. Try on Linux or Windows. -FROM ubuntu:20.04 +# This won't build on apple silicon based macs. Try on Linux or Windows or intel based macs. +FROM ubuntu:22.04 RUN apt-get update && apt-get install -y \ python3 \ diff --git a/Dockerfile.encrypt-decrypt b/Dockerfile.encrypt-decrypt index ddedce6..ef41d76 100644 --- a/Dockerfile.encrypt-decrypt +++ b/Dockerfile.encrypt-decrypt @@ -16,7 +16,7 @@ WORKDIR /socksx RUN cargo build --example functions --release # Define final image -FROM ubuntu:23.10 +FROM ubuntu:22.04 RUN apt-get update && apt-get install -y \ libssl3 \ diff --git a/docker-compose-extensive.yml b/docker-compose-extensive.yml index 2a4d647..f9820e7 100644 --- a/docker-compose-extensive.yml +++ b/docker-compose-extensive.yml @@ -14,6 +14,10 @@ services: ports: - "1080:1080" command: "--host 0.0.0.0 --port 1080 --chain socks6://counter-1:1080 --chain socks6://encrypt:1080 --chain socks6://proxy-other:1080" + depends_on: + - counter-1 + - encrypt + - proxy-other networks: net: ipv4_address: 172.16.238.2 @@ -45,6 +49,9 @@ services: ports: - "1081:1080" command: "--host 0.0.0.0 --port 1080 --chain socks6://decrypt:1080 --chain socks6://counter-2:1080" + depends_on: + - counter-2 + - decrypt networks: net: ipv4_address: 172.16.238.5 @@ -79,6 +86,8 @@ services: net: ipv4_address: 172.16.238.8 +# The reason to create a virtual network is to be able to assign static IP addresses to the destination container +# in this case, netcat. We can use this ip address from the client to connect to the destination. networks: net: ipam: diff --git a/examples/client/client.rs b/examples/client/client.rs index b4c7b3e..9f12713 100644 --- a/examples/client/client.rs +++ b/examples/client/client.rs @@ -1,3 +1,6 @@ +/// A simple SOCKS client that connects to a destination server through a proxy. +/// This serves as an example of how to use the socksx crate. +/// This also serves as a test to ensure that the crate works as expected. use anyhow::Result; use clap::{App, Arg}; use socksx::{Socks5Client, Socks6Client}; diff --git a/socksx/examples/client.rs b/socksx/examples/client.rs index b4c7b3e..9f12713 100644 --- a/socksx/examples/client.rs +++ b/socksx/examples/client.rs @@ -1,3 +1,6 @@ +/// A simple SOCKS client that connects to a destination server through a proxy. +/// This serves as an example of how to use the socksx crate. +/// This also serves as a test to ensure that the crate works as expected. use anyhow::Result; use clap::{App, Arg}; use socksx::{Socks5Client, Socks6Client}; diff --git a/socksx/examples/functions.rs b/socksx/examples/functions.rs index f0f8b8b..6db7da6 100644 --- a/socksx/examples/functions.rs +++ b/socksx/examples/functions.rs @@ -1,3 +1,6 @@ +/// This example demonstrates how to apply a function to ingress traffic through the socks proxy. +/// This example uses ChaCha20 encryption/decryption as the function. +/// We can have other functions such as compression, decompression, firewall, VPN, annonimization, etc. use std::pin::Pin; use std::sync::Arc; use std::task::{Context, Poll}; diff --git a/socksx/examples/redirector.rs b/socksx/examples/redirector.rs index 2fff868..3629f94 100644 --- a/socksx/examples/redirector.rs +++ b/socksx/examples/redirector.rs @@ -1,3 +1,6 @@ +/// This is a simple redirector that redirects all incoming TCP connections through a SOCKS proxy to +/// a different destination. This is useful for redirecting traffic from a specific application +/// through a proxy. use anyhow::Result; use clap::{App, Arg}; use tokio::net::{TcpListener, TcpStream}; diff --git a/socksx/src/common/addresses.rs b/socksx/src/common/addresses.rs index c51ec61..910de43 100644 --- a/socksx/src/common/addresses.rs +++ b/socksx/src/common/addresses.rs @@ -88,7 +88,7 @@ impl TryFrom for ProxyAddress { } /// Represents a network address, which could be either a domain name or an IP address. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] pub enum Address { /// An address represented by a domain name. Domainname { host: String, port: u16 }, diff --git a/socksx/src/common/util.rs b/socksx/src/common/util.rs index f112667..af6c81d 100644 --- a/socksx/src/common/util.rs +++ b/socksx/src/common/util.rs @@ -107,3 +107,47 @@ pub async fn try_read_initial_data(stream: &mut TcpStream) -> Result Self { + Self { + addr: addr.to_string(), + } + } + } + + impl Into for MockSocketAddr { + fn into(self) -> String { + self.addr + } + } + + // Test resolve_addr function + #[tokio::test] + async fn test_resolve_addr() { + // Test with valid IP address + let mock_addr = MockSocketAddr::new("127.0.0.1:8080"); + let result = resolve_addr(mock_addr).await; + assert!(result.is_ok()); + assert_eq!(result.unwrap().to_string(), "127.0.0.1:8080"); + + // Test with invalid IP address + let mock_addr = MockSocketAddr::new("300.300.300.300:8080"); + let result = resolve_addr(mock_addr).await; + assert!(result.is_err()); + + // Test with domain name (this will fail if domain cannot be resolved) + let mock_addr = MockSocketAddr::new("localhost:8080"); + let result = resolve_addr(mock_addr).await; + assert!(result.is_ok()); + } +} diff --git a/socksx/src/lib.rs b/socksx/src/lib.rs index 2559936..47252e8 100644 --- a/socksx/src/lib.rs +++ b/socksx/src/lib.rs @@ -3,9 +3,13 @@ //! While the crate is still in development, it is already usable. //! //! ## Chaining Features -//! For SOCKS version 5, chaining is not supported yet. It will be added in the future. Eg. Client -> Socks5 -> Destination -//! For SOCKS version 6, chaining is supported. It means that you can chain multiple SOCKS6 proxies together. Eg. Client -> Socks6 -> Socks6 -> Destination //! +//! For `SOCKS version 5`, chaining is not supported yet. It will be added in the future. +//! Hence, it works in the following way: Client -> Socks5 -> Destination +//! +//! For `SOCKS version 6`, chaining is supported. It means that you can chain multiple SOCKS6 proxies together. +//! Apart from working like version 5, it can also be used to do this - Eg. Client -> Socks6 -> Socks6 -> Destination + diff --git a/socksx/src/main.rs b/socksx/src/main.rs index 5378d34..556e816 100644 --- a/socksx/src/main.rs +++ b/socksx/src/main.rs @@ -1,3 +1,10 @@ +/// This is the main entry point for the SOCKSX proxy server. +/// It is responsible for parsing CLI arguments, setting up logging, and +/// spawning the main event loop. +/// The main event loop is responsible for accepting incoming connections and +/// spawning a new task for each connection. +/// Each task is responsible for handling the SOCKS handshake and proxying +/// data between the client and the destination server. #[macro_use] extern crate human_panic; diff --git a/socksx/src/socks5/s5_handler.rs b/socksx/src/socks5/s5_handler.rs index d4ee885..77cd7ed 100644 --- a/socksx/src/socks5/s5_handler.rs +++ b/socksx/src/socks5/s5_handler.rs @@ -31,7 +31,7 @@ impl Socks5Handler { /// # Returns /// /// A new `Socks5Handler` instance. - pub fn new(chain: Vec) -> Self { + pub fn new(_chain: Vec) -> Self { Socks5Handler { credentials: None, //chain, diff --git a/socksx/src/socks6/chain.rs b/socksx/src/socks6/chain.rs index 5005025..e4d11b6 100644 --- a/socksx/src/socks6/chain.rs +++ b/socksx/src/socks6/chain.rs @@ -138,7 +138,9 @@ mod tests { pub fn test_detour_empty_chain() { let mut chain = SocksChain::default(); chain.detour(&[ProxyAddress::new(6, String::from("localhost"), 1, None)]); - assert_eq!(chain.links.len(), 2); // Should include root and the new link + assert_eq!(chain.index, 0); + assert_eq!(chain.links[0], ProxyAddress::root()); + assert_eq!(chain.links[1], ProxyAddress::new(6, String::from("localhost"), 1, None)); } // Tests the `detour` method by checking the order of ports after insertion. diff --git a/socksx/src/socks6/mod.rs b/socksx/src/socks6/mod.rs index 3449ef1..d0c1b5d 100644 --- a/socksx/src/socks6/mod.rs +++ b/socksx/src/socks6/mod.rs @@ -147,7 +147,7 @@ where for option in &options { match option { SocksOption::AuthMethodAdvertisement(advertisement) => { - // Make note of initial data length for convience. + // Make note of initial data length for convenience. initial_data_length = advertisement.initial_data_length; } SocksOption::Metadata(key_value) => { @@ -328,3 +328,45 @@ where Ok((binding, options)) } + +#[cfg(test)] +mod tests { + use super::*; + + // Test creation of a new Socks6Request. + #[test] + fn test_new_socks6_request() { + let request = Socks6Request::new( + Socks6Command::Connect as u8, + Address::new("192.168.1.1", 80), + 0, + vec![], + None, + ); + + // Ensure the fields are correctly set. + assert_eq!(request.command, Socks6Command::Connect); + assert_eq!( + request.destination, + Address::new("192.168.1.1", 80), + ); + assert_eq!(request.initial_data_length, 0); + assert_eq!(request.options.len(), 0); + assert_eq!(request.metadata.len(), 0); + } + + // Test conversion of Socks6Request into a byte sequence. + #[test] + fn test_into_socks_bytes() { + let request = Socks6Request::new( + Socks6Command::Connect as u8, + Address::new("192.168.1.1", 80), + 0, + vec![], + None, + ); + let result = request.into_socks_bytes(); + let expected_result: Vec = vec![6, 1, 1, 192, 168, 1, 1, 0, 80, 0, 0, 0]; + assert_eq!(result, expected_result); + } +} \ No newline at end of file diff --git a/socksx/src/socks6/options.rs b/socksx/src/socks6/options.rs index e77d1f6..180dc19 100644 --- a/socksx/src/socks6/options.rs +++ b/socksx/src/socks6/options.rs @@ -257,11 +257,11 @@ mod tests { } // Test the from_socks_bytes function for AuthMethodAdvertisementOption - // #[test] - // fn test_from_socks_bytes_auth_method_advertisement() { - // let bytes = vec![/* Populate this vector with some example bytes */]; - // let result = AuthMethodAdvertisementOption::from_socks_bytes(bytes); - // // Verify the result according to your expectations - // assert!(result.is_ok()); - // } + #[test] + fn test_from_socks_bytes_auth_method_advertisement() { + let bytes = vec![0x00, 0x02, 0x00, 0x01, 0x02]; + let result = AuthMethodAdvertisementOption::from_socks_bytes(bytes); + // Verify the result according to your expectations + assert!(result.is_ok()); + } } \ No newline at end of file