瀏覽代碼

net/transport: Add SOCKS5 dialer

parazyd 1 年之前
父節點
當前提交
f508a4a8d4
共有 2 個文件被更改,包括 63 次插入1 次删除
  1. 16 0
      src/net/transport/mod.rs
  2. 47 1
      src/net/transport/socks5.rs

+ 16 - 0
src/net/transport/mod.rs

@@ -73,6 +73,9 @@ pub enum DialerVariant {
 
     /// Unix socket
     Unix(unix::UnixDialer),
+
+    /// SOCKS5 proxy
+    Socks5(socks5::Socks5Dialer),
 }
 
 /// Listener variants
@@ -184,6 +187,14 @@ impl Dialer {
                 Ok(Self { endpoint, variant })
             }
 
+            "socks5" => {
+                // Build a SOCKS5 dialer
+                enforce_hostport!(endpoint);
+                let variant = socks5::Socks5Dialer::new(&endpoint).await?;
+                let variant = DialerVariant::Socks5(variant);
+                Ok(Self { endpoint, variant })
+            }
+
             x => {
                 error!("[P2P] Requested unsupported transport: {}", x);
                 Err(io::Error::from_raw_os_error(libc::ENETUNREACH))
@@ -249,6 +260,11 @@ impl Dialer {
                 let stream = dialer.do_dial(path).await?;
                 Ok(Box::new(stream))
             }
+
+            DialerVariant::Socks5(dialer) => {
+                let stream = dialer.do_dial().await?;
+                Ok(Box::new(stream))
+            }
         }
     }
 

+ 47 - 1
src/net/transport/socks5.rs

@@ -25,8 +25,54 @@ use std::{
 use futures::{AsyncReadExt, AsyncWriteExt};
 use log::debug;
 use smol::net::TcpStream;
+use url::Url;
+
+/// SOCKS5 dialer
+#[derive(Clone, Debug)]
+pub struct Socks5Dialer {
+    client: Socks5Client,
+    endpoint: AddrKind,
+}
+
+impl Socks5Dialer {
+    /// Instantiate a new [`Socks5Dialer`] with given URI
+    pub(crate) async fn new(uri: &Url) -> io::Result<Self> {
+        // URIs in the form of: socks5://user:pass@proxy:port/destination:port
+        /*
+        let auth_user = uri.username();
+        let auth_pass = uri.password();
+        */
+
+        // Parse destination
+        let mut dest = uri.path().strip_prefix("/").unwrap().split(':');
+
+        let Some(dest_host) = dest.next() else { return Err(io::ErrorKind::InvalidInput.into()) };
+        let Some(dest_port) = dest.next() else { return Err(io::ErrorKind::InvalidInput.into()) };
+
+        let dest_port: u16 = match dest_port.parse() {
+            Ok(v) => v,
+            Err(_) => return Err(io::ErrorKind::InvalidData.into()),
+        };
+
+        let client = Socks5Client::new(uri.host_str().unwrap(), uri.port().unwrap());
+        let endpoint: AddrKind = (dest_host, dest_port).into();
+
+        Ok(Self { client, endpoint })
+    }
+
+    /// Internal dial function
+    pub(crate) async fn do_dial(&self) -> io::Result<TcpStream> {
+        debug!(
+            target: "net::socks5::do_dial",
+            "Dialing {:?} with SOCKS5...", self.endpoint,
+        );
+
+        self.client.connect(self.endpoint.clone()).await
+    }
+}
 
 /// SOCKS5 proxy client
+#[derive(Clone, Debug)]
 pub struct Socks5Client {
     /// SOCKS5 server host
     host: String,
@@ -191,7 +237,7 @@ impl Socks5Client {
     }
 }
 
-#[derive(Debug)]
+#[derive(Clone, Debug)]
 pub enum AddrKind {
     Ip(SocketAddr),
     Domain(String, u16),