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实现的原因:
- 需要支持Tor SOCKS扩展
- 需要访问其他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("写入失败");
}
}
}
}
}
注意事项
- 上述示例实现了基本的SOCKS5代理功能,包括认证支持
- 实际生产环境需要更完善的错误处理和日志记录
- 要连接到Tor网络,需要配置实际的Tor客户端或中继
- 此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(())
}
示例说明
- 连接阶段:首先建立到本地Tor代理(9050端口)的TCP连接
- 目标地址:使用
.onion
地址作为目标,这是Tor网络的特色 - SOCKS握手:通过
AsyncSocksConnection
完成SOCKS协议握手 - 数据传输:连接建立后,可以像普通TCP连接一样读写数据
- 错误处理:每个步骤都有详细的错误处理
注意事项
- 运行前确保Tor服务已启动并监听9050端口
- 示例中的
example.onion
需要替换为真实的.onion地址 - 实际生产环境需要添加超时处理
- 对于长时间连接,建议实现心跳机制
这个完整示例展示了从建立连接到实际通信的全过程,包含了在实际项目中需要考虑的主要因素。