fast-socks5

repository·master·Indexed 20 days ago

https://github.com/dizda/fast-socks5

An ultra-lightweight, scalable, and async SOCKS5, SOCKS4, and SOCKS4a client/server library for Rust built on the Tokio runtime. It supports TCP and UDP proxying, custom authentication via the Authentication trait, and provides a typestate-based server API for high extensibility. Version 1.0.0.

Tokens
7.8K
Snippets
33
Records
35
Agent score
70%

What's inside fast-socks5

  1. Extending the SOCKS5 server

    master

    The library provides an explicit server API based on typestates for safety, allowing for high extensibility:

    • Custom Authentication: Implement the AuthMethod trait to support custom authentication methods. You can support multiple methods with runtime negotiation using the auth_method_enums macro for fast static dispatch.
    • Custom Request Handling: You can control the request handling flow. For example, you can skip DNS resolution or skip the authentication/handshake process for private use to reduce round-trips.
    • Custom Proxying/Routing: Instead of using run_tcp_proxy for in-process proxying, you can swap it out for custom logic to build a router or use accelerated proxying methods.

    Supported built-in authentication methods include No-Auth (0x00) and Username/Password (0x02).

  2. How Socks5Stream works with AsyncRead and AsyncWrite

    master
    The Socks5Stream<S> struct implements both tokio::io::AsyncRead and tokio::io::AsyncWrite. Once the SOCKS5 handshake and the connection request are successful, you can treat the Socks5Stream as a standard asynchronous stream for reading from and writing to the remote target.
  3. Use Socks4Stream to connect to a SOCKS4 proxy

    master

    The Socks4Stream struct provides a SOCKS4/SOCKS4a client implementation. It wraps an underlying asynchronous stream (like TcpStream) and implements AsyncRead and AsyncWrite, allowing you to use it like any other standard asynchronous socket.

    You can create a Socks4Stream in two ways:

    1. Directly from a TcpStream: Use Socks4Stream::connect to establish a connection to the proxy server and immediately perform the SOCKS4 handshake.
    2. Wrapping an existing stream: Use Socks4Stream::use_stream if you have already established a connection to the proxy server and want to upgrade it to a SOCKS4 session.
    // Option 1: Connect directly to a proxy server
    let mut socks = Socks4Stream::connect(
        "proxy_address:port", // socks_server
        "target_domain.com".to_string(), // target_addr
        80, // target_port
        true, // resolve_locally
    ).await?;
    
    // Option 2: Wrap an existing TcpStream
    let tcp_stream = TcpStream::connect("proxy_address:port").await?;
    let mut socks = Socks4Stream::use_stream(tcp_stream)?;
    
    // Perform the SOCKS4 request manually if using use_stream
    let target = TargetAddr::Domain("target_domain.com".to_string(), 80);
    socks.request(Socks4Command::Connect, target, true).await?;
  4. Run the fast-socks5 client example

    master

    You can run the provided client example using cargo run. Use the --socks-server flag to specify the proxy address, --username and --password for authentication, and -a (address) and -p (port) for the target destination.

    RUST_LOG=debug cargo run --example client -- --socks-server 127.0.0.1:1337 --username admin --password password -a perdu.com -p 80
  5. Test the proxy with cURL

    master

    Verify your SOCKS5 server is working correctly by using curl with the --proxy flag. The format for the proxy URL is socks5://username:password@host:port.

    curl -v --proxy socks5://admin:password@127.0.0.1:1337 https://ipapi.co/json/
  6. Run the fast-socks5 server example

    master

    Run the provided server example using cargo run. Use the --listen-addr flag to specify the proxy's listening address. The example also accepts a password and user credentials via -u and -p flags.

    RUST_LOG=debug cargo run --example server -- --listen-addr 127.0.0.1:1337 password -u admin -p password
  7. Configure the SOCKS5 server with `Config`

    master

    The Config<A> struct allows you to customize the behavior of the SOCKS5 server. You can control timeouts, authentication requirements, DNS resolution, and protocol features like UDP support. Use the builder-style methods to configure the server before binding.

    let mut config = Config::default()
        .set_request_timeout(Duration::from_secs(30))
        .set_dns_resolve(true)
        .set_udp_support(true);
    
    // To enable authentication, use with_authentication
    let config = config.with_authentication(SimpleUserPassword {
        username: "admin".to_string(),
        password: "secret".to_string(),
    });
  8. Configure the SOCKS5 client with Config

    master

    The Config struct allows you to customize the behavior of the SOCKS5 client. You can set a connection timeout for the initial socket connection and toggle whether to skip the authentication handshake (useful if the server is already configured to skip auth, to avoid unnecessary roundtrips).

    use std::time::Duration;
    use fast_socks5::client::Config;
    
    let mut config = Config::default();
    config.set_connect_timeout(Duration::from_secs(5));
    config.set_skip_auth(true);
  9. Use `SimpleUserPassword` for basic authentication

    master

    The crate provides a built-in SimpleUserPassword implementation for standard SOCKS5 username/password authentication. If authentication succeeds, it returns an AuthSucceeded struct containing the username.

    let auth = SimpleUserPassword {
        username: "user123".to_string(),
        password: "password123".to_string(),
    };
    
    let config = Config::default().with_authentication(auth);
  10. Handle SOCKS4 reply errors with ReplyError

    master

    The ReplyError enum represents the status returned by a SOCKS4 server. It implements Error for easy integration with Rust error handling. Use from_u8(code) to parse a response byte from the wire and as_u8() to convert an error variant back into its protocol byte.

    // Parsing a response from the server
    let response_byte = 0x5a; // Succeeded
    let error = ReplyError::from_u8(response_byte);
    
    // Checking error types
    match error {
        ReplyError::Succeeded => println!("Connection successful"),
        ReplyError::HostUnreachable => println!("Host is down"),
        ReplyError::UnknownResponse(code) => println!("Received unknown code: {}", code),
        _ => println!("Other error occurred"),
    }
    
    // Converting error to byte for protocol compliance
    let byte = ReplyError::GeneralFailure.as_u8(); // 0x5b
  11. Connect to a target via SOCKS5 TCP proxy

    master

    To establish a TCP connection through a SOCKS5 proxy, use the connect or connect_with_password methods on Socks5Stream<TcpStream>. These methods handle the initial TCP connection to the proxy, the SOCKS5 handshake, and the request to connect to the target address/port.

    use tokio::net::TcpStream;
    use fast_socks5::client::{Socks5Stream, Config};
    
    // Basic connection
    let stream = Socks5Stream::connect(
        "127.0.0.1:1080", // Proxy server address
        "example.com".to_string(),
        443,
        Config::default()
    ).await?;
    
    // Connection with username/password
    let stream = Socks5Stream::connect_with_password(
        "127.0.0.1:1080",
        "example.com".to_string(),
        443,
        "my_user".to_string(),
        "my_password".to_string(),
        Config::default()
    ).await?;