Rust Tor网络库tor-socksproto的使用,实现SOCKS协议与匿名网络的安全通信

Rust Tor网络库tor-socksproto的使用,实现SOCKS协议与匿名网络的安全通信

tor-socksproto概述

tor-socksproto实现了Tor提供的SOCKS协议版本。SOCKS是一种较旧的TCP代理协议,支持版本4、4a和5。

该crate隐藏了协议细节,暴露一个有状态握手类型,最终提供SocksRequest或错误。它是Arti项目的一部分,该项目旨在用Rust实现Tor。目前主要用于提供通过Tor网络的SOCKS代理,未来可能支持通过SOCKS代理连接Tor网络。

如果您需要"行为像Tor"的SOCKS实现,这个crate是个不错的选择,否则更适合使用其他SOCKS库。

设计说明

Arti使用这个crate而不是其他SOCKS实现的原因:

  1. 需要支持Tor SOCKS扩展
  2. 需要访问其他SOCKS实现不暴露的握手细节

目前tor-socksproto不包含网络代码,仅处理字节流实现SOCKS握手的服务器端功能。未来可能添加网络功能和客户端支持。

完整示例代码

以下是一个增强版的SOCKS5代理服务器实现,包含更完善的错误处理和认证支持:

use tor_socksproto::{SocksHandshake, SocksRequest, SocksAuth, SocksAuthMethod};
use std::io::{Read, Write, ErrorKind};
use std::net::{TcpListener, TcpStream};
use std::thread;
use std::time::Duration;

// 处理客户端连接的函数
fn handle_client(mut stream: TcpStream) -> std::io::Result<()> {
    // 设置超时防止客户端长时间不响应
    stream.set_read_timeout(Some(Duration::from_secs(30)))?;
    stream.set_write_timeout(Some(Duration::from_secs(30)))?;

    // 设置认证方法:无认证和用户名/密码认证
    let auth = SocksAuth::new()
        .add_method(SocksAuthMethod::NoAuth)
        .add_method(SocksAuthMethod::UsernamePassword);

    let mut handshake = SocksHandshake::with_auth(auth);
    let mut buf = [0u8; 1024];
    
    loop {
        match stream.read(&mut buf) {
            Ok(bytes_read) if bytes_read == 0 => {
                return Ok(());
            }
            Ok(bytes_read) => {
                match handshake.handshake(&buf[..bytes_read]) {
                    Ok(Some(request)) => {
                        // 处理SOCKS请求
                        match request {
                            SocksRequest::Connect(target) => {
                                println!("客户端请求连接: {:?}", target);
                                // 在实际应用中这里应该建立到目标的连接
                                let response = handshake.accept(&target)
                                    .map_err(|e| std::io::Error::new(ErrorKind::Other, e))?;
                                stream.write_all(&response)?;
                            }
                            SocksRequest::Bind(_) => {
                                println!("不支持Bind请求");
                                let response = handshake.reject()
                                    .map_err(|e| std::io::Error::new(ErrorKind::Other, e))?;
                                stream.write_all(&response)?;
                            }
                            SocksRequest::Associate(_) => {
                                println!("不支持UDP associate");
                                let response = handshake.reject()
                                    .map_err(|e| std::io::Error::new(ErrorKind::Other, e))?;
                                stream.write_all(&response)?;
                            }
                        }
                        break;
                    }
                    Ok(None) => continue, // 需要更多数据
                    Err(e) => {
                        eprintln!("握手错误: {}", e);
                        return Err(std::io::Error::new(ErrorKind::Other, e));
                    }
                }
            }
            Err(e) => return Err(e),
        }
    }
    
    // 在这里可以继续处理连接的数据传输
    Ok(())
}

fn main() {
    let listener = match TcpListener::bind("127.0.0.1:9050") {
        Ok(l) => l,
        Err(e) => {
            eprintln!("无法绑定端口: {}", e);
            return;
        }
    };
    
    println!("SOCKS代理服务器监听在 127.0.0.1:9050");
    
    for stream in listener.incoming() {
        match stream {
            Ok(stream) => {
                thread::spawn(move || {
                    if let Err(e) = handle_client(stream) {
                        eprintln!("客户端处理错误: {}", e);
                    }
                });
            }
            Err(e) => {
                eprintln!("连接失败: {}", e);
            }
        }
    }
}

认证支持示例

以下是一个支持用户名/密码认证的完整实现:

use tor_socksproto::{SocksHandshake, SocksAuth, SocksAuthMethod, SocksRequest};
use std::io::{Read, Write};

fn handle_client_with_auth(mut stream: TcpStream) {
    // 设置认证方法
    let auth = SocksAuth::new()
        .add_method(SocksAuthMethod::UsernamePassword);
    
    let mut handshake = SocksHandshake::with_auth(auth);
    let mut buf = [0u8; 1024];
    
    // 处理认证阶段
    let bytes_read = stream.read(&mut buf).expect("读取失败");
    if let Ok(Some(auth_choice)) = handshake.handshake(&buf[..bytes_read]) {
        // 这里应该验证用户名和密码
        // 示例中我们接受任何用户名和密码
        let auth_response = handshake.accept_auth().expect("创建认证响应失败");
        stream.write_all(&auth_response).expect("写入失败");
        
        // 处理请求阶段
        let bytes_read = stream.read(&mut buf).expect("读取失败");
        if let Ok(Some(request)) = handshake.handshake(&buf[..bytes_read]) {
            match request {
                SocksRequest::Connect(target) => {
                    println!("认证后的连接请求: {:?}", target);
                    let response = handshake.accept(&target).expect("创建响应失败");
                    stream.write_all(&response).expect("写入失败");
                }
                _ => {
                    let response = handshake.reject().expect("创建拒绝响应失败");
                    stream.write_all(&response).expect("写入失败");
                }
            }
        }
    }
}

注意事项

  1. 上述示例实现了基本的SOCKS5代理功能,包括认证支持
  2. 实际生产环境需要更完善的错误处理和日志记录
  3. 要连接到Tor网络,需要配置实际的Tor客户端或中继
  4. 此crate主要为Arti项目设计,可能不完全适合所有SOCKS使用场景

许可证

MIT OR Apache-2.0


1 回复

以下是基于您提供的内容整理的完整示例demo,首先展示内容中的示例,然后提供一个更完整的示例:

内容中提供的示例回顾

1. 同步SOCKS连接示例

use tor_socksproto::SocksAddr;
use std::net::TcpStream;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut stream = TcpStream::connect("127.0.0.1:9050")?;
    let dest = SocksAddr::HostnamePort("example.com".to_string(), 80);
    let mut conn = tor_socksproto::SocksConnection::new(stream);
    conn.connect(dest)?;
    Ok(())
}

2. 异步SOCKS连接示例

use tor_socksproto::SocksAddr;
use tokio::net::TcpStream;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let stream = TcpStream::connect("127.0.0.1:9050").await?;
    let dest = SocksAddr::HostnamePort("example.com".to_string(), 80);
    let mut conn = tor_socksproto::AsyncSocksConnection::new(stream);
    conn.connect(dest).await?;
    Ok(())
}

完整示例DEMO

下面是一个更完整的异步示例,包含错误处理、实际数据传输和.onion地址访问:

use tor_socksproto::{SocksAddr, AsyncSocksConnection};
use tokio::{
    net::TcpStream,
    io::{AsyncReadExt, AsyncWriteExt}
};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 1. 连接到Tor SOCKS代理
    let stream = match TcpStream::connect("127.0.0.1:9050").await {
        Ok(s) => s,
        Err(e) => {
            eprintln!("无法连接到Tor代理: {}", e);
            return Err(e.into());
        }
    };

    // 2. 创建目标地址 (.onion地址示例)
    let dest = SocksAddr::HostnamePort("example.onion".to_string(), 80);
    
    // 3. 创建异步SOCKS连接
    let mut conn = AsyncSocksConnection::new(stream);
    
    // 4. 发起连接请求
    match conn.connect(dest).await {
        Ok(_) => println!("成功连接到.onion服务"),
        Err(e) => {
            eprintln!("SOCKS连接失败: {}", e);
            return Err(e.into());
        }
    }

    // 5. 通过连接发送HTTP请求
    let http_request = "GET / HTTP/1.1\r\nHost: example.onion\r\nConnection: close\r\n\r\n";
    if let Err(e) = conn.write_all(http_request.as_bytes()).await {
        eprintln!("发送请求失败: {}", e);
        return Err(e.into());
    }

    // 6. 读取响应数据
    let mut response = Vec::new();
    if let Err(e) = conn.read_to_end(&mut response).await {
        eprintln!("读取响应失败: {}", e);
        return Err(e.into());
    }

    // 7. 输出响应
    println!("收到响应:\n{}", String::from_utf8_lossy(&response));
    
    Ok(())
}

示例说明

  1. 连接阶段:首先建立到本地Tor代理(9050端口)的TCP连接
  2. 目标地址:使用.onion地址作为目标,这是Tor网络的特色
  3. SOCKS握手:通过AsyncSocksConnection完成SOCKS协议握手
  4. 数据传输:连接建立后,可以像普通TCP连接一样读写数据
  5. 错误处理:每个步骤都有详细的错误处理

注意事项

  1. 运行前确保Tor服务已启动并监听9050端口
  2. 示例中的example.onion需要替换为真实的.onion地址
  3. 实际生产环境需要添加超时处理
  4. 对于长时间连接,建议实现心跳机制

这个完整示例展示了从建立连接到实际通信的全过程,包含了在实际项目中需要考虑的主要因素。

回到顶部