Skip to content

yaanno/simple-proxy

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

16 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SimpleProxy

System Design

Rust HTTP/HTTPS Forward Proxy with Path-Aware Blacklisting

Project Goal:
Build a user-space forward proxy in Rust that can accept HTTP and HTTPS (via CONNECT) requests, forward them to the destination server, and optionally block requests based on a configurable blacklist. The blacklist now supports both domain-level and path-level blocking (e.g., block example.com/subfolder but allow example.com).


1. Core Functionality

  • HTTP Proxy: Handles standard HTTP methods (GET, POST, etc.). Parses requests, forwards them, and relays responses.
  • HTTPS Proxy (CONNECT method): Handles CONNECT requests to establish a raw TCP tunnel between the client and the destination.
  • Blacklisting: Blocks connections to specific domains, IP addresses, or specific paths under a domain.
  • Logging: Provides detailed logs for debugging and operational insight.

2. Key Components & Modules

main.rs (Entry Point)

  • Initializes the tokio runtime and logging.
  • Parses command-line arguments (proxy listen address/port, path to blacklist file).
  • Loads the initial blacklist.
  • Creates and starts the ProxyServer.

proxy_server Module

  • ProxyServer struct: Holds configuration (listen address, port, reference to BlacklistManager).
  • run() method:
    • Binds a tokio::net::TcpListener to the configured address/port.
    • Accepts incoming client connections in an async loop.
    • Spawns a new tokio::task for each connection, calling handle_client.

connection_handler Module

  • handle_client(mut client_stream: TcpStream, blacklist_manager: Arc<BlacklistManager>) async function:
    • Reads and parses the HTTP request from the client.
    • Extracts the HTTP method, URI, headers, and path.
    • Blacklist Check:
      • Extracts the target host and path from the request.
      • Calls blacklist_manager.is_blocked(target_host, path).
      • If blocked: Logs the block, returns a "403 Forbidden" HTTP response (for HTTP) or closes the connection (for HTTPS CONNECT), and returns.
    • Establishes Upstream Connection:
      • If not blocked, connects to the target server using tokio::net::TcpStream::connect().
    • Forwarding Logic:
      • CONNECT Method (HTTPS Tunnel):
        • Sends "HTTP/1.1 200 Connection Established\r\n\r\n" to the client.
        • Uses tokio::io::copy() to shuttle bytes between client_stream and upstream_stream in both directions, creating a raw TCP tunnel.
      • Other HTTP Methods:
        • Forwards the original client request bytes to the upstream_stream.
        • Reads the response from upstream_stream.
        • Forwards the response bytes back to client_stream.
        • Handles connection closing after one request/response cycle for simplicity.

blacklist_manager Module

  • BlacklistManager struct:

    • Holds two data structures:
      • blocked_domains: HashSet<String> for domain/IP blocking.
      • blocked_paths: HashSet<(String, String)> for domain+path blocking.
    • Thread-safe via RwLock.
  • new(path: &str) method: Loads rules from a specified file.

  • is_blocked(host: &str, path: &str) method:
    Checks if the given host (domain or IP string) or host+path matches any rule in the blacklist.

    • Supports:
      • Domain/IP blocking (e.g., example.com)
      • Path-based blocking (e.g., example.com/subfolder)
      • Subdomain matching (e.g., blocking example.com also blocks sub.example.com)
  • Blacklist File Format:

    • Each line is either a domain/IP or a domain+path (e.g., example.com/subfolder).

    • Lines starting with # are comments.

    • Examples:

      # Block all of example.com
      example.com
      
      # Block only /subfolder on example.com
      example.com/subfolder
      
      # Block an IP
      192.168.1.100
      

3. Libraries/Crates Used

  • tokio: Asynchronous runtime for non-blocking I/O and task spawning.
  • httparse: Efficient, low-level parsing of HTTP requests from raw bytes.
  • log & env_logger: Logging.
  • clap: Command-line argument parsing.
  • anyhow / thiserror: Ergonomic error handling.
  • url: URL parsing and manipulation.
  • trust-dns-resolver: (Optional) For IP-based blacklist checks.
  • tokio-rustls: (Optional) For advanced HTTPS handling (not required for basic CONNECT tunneling).

4. Error Handling

  • Custom ProxyError enum covers:
    • I/O errors
    • HTTP request parse errors
    • Bad HTTP requests
    • Upstream connection errors
    • Blacklist errors
    • Invalid URIs
  • All fallible functions return Result<T, ProxyError>.
  • Errors are logged with context.

5. Getting Started

  1. Cargo.toml Setup:
    Add dependencies: tokio, httparse, log, env_logger, clap, anyhow, url.

  2. Blacklist File:
    Create a blacklist file (e.g., blacklist.txt) with entries as described above.

  3. Run the Proxy:

    cargo run -- --listen 127.0.0.1:8080 --blacklist blacklist.txt
  4. Configure Your Browser or HTTP Client:
    Set the proxy to 127.0.0.1:8080.

  5. Test Blacklisting:

    • Requests to blacklisted domains or paths will be blocked with a 403 (HTTP) or closed tunnel (HTTPS).
    • All other requests will be forwarded.

6. Example Blacklist Usage

  • To block all of example.com:
    example.com
    
  • To block only example.com/subfolder but allow the rest of example.com:
    example.com/subfolder
    
  • To block an IP:
    192.168.1.100
    

7. Extending

  • Add support for wildcards or regex in blacklist rules.
  • Implement dynamic blacklist updates (add/remove rules at runtime).
  • Add metrics or a web UI for monitoring.

8. Security Note

This proxy does not decrypt HTTPS traffic (no MITM). It only tunnels encrypted bytes for HTTPS via the CONNECT method.


9. License

MIT or Apache-2.0 (choose your preferred license).


About

networking exercise in rust

Topics

Resources

License

Stars

Watchers

Forks

Languages