#传输 #可插拔 #tor #审查

ptrs

支持可插拔传输实现的接口和实用程序

1 个不稳定版本

0.1.0 2024年5月4日

#1349 in 网络编程

MIT/Apache

105KB
2K SLoC

Rust中的可插拔传输(PTRS)

License: MIT/Apache 2.0

PTRS是一个用于在Rust中编写可插拔传输的库。

⚠️ 🚧 警告:此crate仍在建设中 🚧 ⚠️

  • 接口可能会随时更改
  • 未准备好用于生产
    • 不要将此用于任何安全关键的应用程序

库使用

(目前)此库围绕连接的抽象,将任何实现tokio::io:AsyncRead + tokio::io::AsyncWrite + Unpin + Send + Sync的特质视为任何东西。这允许我们将可插拔传输的预期共享行为定义为这些Stream的转换。

/// Future containing a generic result. We use this for functions that take
/// and/or return futures that will produce Read/Write tunnels once awaited.
pub type FutureResult<T, E> = Box<dyn Future<Output = Result<T, E>> + Send>;

/// Future containing a generic result, shorthand for ['FutureResult']. We use
/// this for functions that take and/or return futures that will produce
/// Read/Write tunnels once awaited.
pub(crate) type F<T, E> = FutureResult<T, E>;


/// Client Transport
pub trait ClientTransport<InRW, InErr>
where
    InRW: AsyncRead + AsyncWrite + Send + Sync + Unpin + 'static,
{
    type OutRW: AsyncRead + AsyncWrite + Send + Unpin;
    type OutErr: std::error::Error + Send + Sync;
    type Builder: ClientBuilder<InRW>;

    /// Create a pluggable transport connection given a future that will return
    /// a Read/Write object that can be used as the underlying socket for the
    /// connection.
    fn establish(self, input: Pin<F<InRW, InErr>>) -> Pin<F<Self::OutRW, Self::OutErr>>;

    /// Create a connection for the pluggable transport client using the provided
    /// (pre-existing/pre-connected) Read/Write object as the underlying socket.
    fn wrap(self, io: InRW) -> Pin<F<Self::OutRW, Self::OutErr>>;

    /// Returns a string identifier for this transport
    fn method_name() -> String;
}

/// Server Transport
pub trait ServerTransport<InRW>
where
    InRW: AsyncRead + AsyncWrite + Send + Sync + Unpin + 'static,
{
    type OutRW: AsyncRead + AsyncWrite + Send + Unpin;
    type OutErr: std::error::Error + Send + Sync;
    type Builder: ServerBuilder<InRW>;

    /// Create/accept a connection for the pluggable transport client using the
    /// provided (pre-existing/pre-connected) Read/Write object as the
    /// underlying socket.
    fn reveal(self, io: InRW) -> Pin<F<Self::OutRW, Self::OutErr>>;

    /// Returns a string identifier for this transport
    fn method_name() -> String;
}

ptrs传输集成

有了这个抽象,将传输集成到异步Rust应用程序中变得相对简单,例如,集成标识传输(执行直接复制而不进行实际转换)可以这样做

/// TODO

客户端侧的集成也类似简单。

/// TODO

有关更深入的集成示例,请参阅lyrebird crate中的二进制示例。

配置和状态

可以使用各自的构建器接口实现配置传输,这些接口需要options(...)statedir(...)函数。有关示例实现,请参阅obfs4 transport

组合

由于ptrs接口封装了实现连接特性对象的对象,并返回实现相同抽象的特性和对象,因此可以在多个传输层之上进行封装。这样做的一个原因可能是为了有独立的可靠性、混淆和填充策略,这些策略可以相互组合。

let listener = tokio::net::TcpListener::bind("127.0.0.1:8009")
    .await
    .unwrap();

let (tcp_sock, _) = listener.accept().await.unwrap();

let pb: &BuilderS = &<Passthrough as PluggableTransport<TcpStream>>::server_builder();

let client1 = <BuilderS as ServerBuilder<TcpStream>>::build(pb);
let conn1 = client1.reveal(tcp_sock).await.unwrap();

let client2 = <BuilderS as ServerBuilder<TcpStream>>::build(pb);
let conn2 = client2.reveal(conn1).await.unwrap();

let client3 = <BuilderS as ServerBuilder<TcpStream>>::build(pb);
let mut sock = client3.reveal(conn2).await.unwrap();

let (mut r, mut w) = tokio::io::split(&mut sock);
_ = tokio::io::copy(&mut r, &mut w).await;

在客户端

let pb: &BuilderC = &<Passthrough as PluggableTransport<TcpStream>>::client_builder();
let client = <BuilderC as ClientBuilder<TcpStream>>::build(pb);
let conn_fut1 = client.establish(Box::pin(tcp_dial_fut));
let client = <BuilderC as ClientBuilder<TcpStream>>::build(pb);
let conn_fut2 = client.establish(Box::pin(conn_fut1));
let client = <BuilderC as ClientBuilder<TcpStream>>::build(pb);
let conn_fut3 = client.establish(Box::pin(conn_fut2));
let mut conn = conn_fut3.await?;

let msg = b"a man a plan a canal panama";
_ = conn.write(&msg[..]).await?;

实现传输

可以使用几种构建可插拔传输的结构,部分原因是没有任何一种结构在证明上优于其他结构。

obfs4传输是使用tokio_util::codec模型实现的。

注释/资源

虽然这与Tor可插拔传输系统相关并受到其启发,但本存储库的主要关注点是创建一个一致且有用的抽象,用于构建可插拔传输。有关Tor相关可插拔传输的更多信息,请参阅以下资源。

开源许可证

MIT和Apache-2.0双重授权是Rust语言社区目前接受的规范,自编译器和许多公共库以来一直被使用(见为什么是双重MIT/ASL2许可证?)。为了符合社区标准,ptrs使用双重MIT+Apache-2.0许可证。

贡献

欢迎贡献者、问题和拉取请求

依赖项

~5–12MB
~151K SLoC