Skip to content

Power2All/udp-simple-proxy-protocol

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

NGINX Simple Proxy Protocol (SPP) UDP Proxy

A Rust implementation of Cloudflare's Simple Proxy Protocol for UDP traffic. This proxy prepends SPP headers to UDP packets, preserving the original client IP address when forwarding traffic to upstream servers.

Features

  • Simple Proxy Protocol (SPP) support as specified by Cloudflare
  • Header detection: Automatically detects if a packet already has an SPP header and preserves it
  • Multiple proxy instances: Configure multiple listen/upstream pairs
  • Session management: Efficient handling of client sessions with configurable timeouts
  • IPv4 and IPv6 support (IPv4 addresses are mapped to IPv6 format per RFC 4291)
  • Allowed Proxy: Use CIDR IP format to allow IP ranges to be allowed to apply the header, or drop the request

Simple Proxy Protocol Format

The SPP header is a fixed 38-byte structure prepended to each UDP datagram:

Field Size Description
Magic 2 bytes 0x56EC - Protocol identifier
Client Address 16 bytes Client's IP in IPv6 format
Proxy Address 16 bytes Proxy's IP in IPv6 format
Client Port 2 bytes Client's source port (big-endian)
Proxy Port 2 bytes Proxy's destination port (big-endian)

For more details, see Cloudflare's documentation.

Building

Prerequisites

  • Rust 1.70 or later
  • Cargo

Build

# Debug build
cargo build

# Release build (optimized)
cargo build --release

The binary will be at target/release/nginx-spp-proxy (or target/debug/nginx-spp-proxy).

Usage

Using a Configuration File

# Copy and edit the example config
cp config.example.toml config.toml
# Edit config.toml as needed

# Run the proxy
./nginx-spp-proxy -c config.toml

Using Environment Variables

export SPP_LISTEN_ADDR="0.0.0.0:5000"
export SPP_UPSTREAM_ADDR="127.0.0.1:25565"
export SPP_SESSION_TIMEOUT=60  # optional
export SPP_LOG_LEVEL=info      # optional

./nginx-spp-proxy

Command Line Options

USAGE:
    nginx-spp-proxy [OPTIONS]

OPTIONS:
    -c, --config <FILE>    Path to configuration file (TOML)
    -h, --help             Print help message
    -V, --version          Print version information

Configuration

Configuration File (TOML)

[logging]
level = "info"    # trace, debug, info, warn, error
json = false      # Enable JSON logging

[[proxies]]
listen_addr = "0.0.0.0:25565"
upstream_addr = "127.0.0.1:25566"
session_timeout_secs = 120

# Add more [[proxies]] sections for multiple proxies

Environment Variables

Variable Description Required
SPP_LISTEN_ADDR Address to listen on (e.g., 0.0.0.0:5000) Yes
SPP_UPSTREAM_ADDR Upstream server address (e.g., 127.0.0.1:25565) Yes
SPP_SESSION_TIMEOUT Session timeout in seconds No (default: 60)
SPP_LOG_LEVEL Log level No (default: info)
SPP_LOG_JSON Set to enable JSON logging No

Integration with NGINX

This proxy is designed to work alongside NGINX for UDP traffic. A typical setup:

Client -> This Proxy (adds SPP header) -> NGINX Stream (UDP) -> Backend

NGINX Stream Configuration

stream {
    upstream backend {
        server 127.0.0.1:25566;
    }

    server {
        listen 25565 udp;
        proxy_pass backend;
        proxy_timeout 10s;
        proxy_responses 1;
    }
}

Library Usage

This crate can also be used as a library:

use nginx_simple_proxy_protocol::spp::SppHeader;
use std::net::SocketAddr;

// Create an SPP header
let client: SocketAddr = "192.168.1.100:12345".parse().unwrap();
let proxy: SocketAddr = "10.0.0.1:8080".parse().unwrap();
let header = SppHeader::new(client, proxy);

// Prepend to payload
let payload = b"Hello, World!";
let packet = header.prepend_to(payload);

// Check if a packet has SPP header
if SppHeader::is_spp_packet(&packet) {
    let (header, payload) = SppHeader::parse(&packet).unwrap();
    println!("Client: {}", header.client_socket_addr());
}

How It Works

  1. Incoming packets: The proxy listens for UDP packets on the configured address
  2. Header detection: Each packet is checked for an existing SPP header (magic number 0x56EC)
  3. Header handling:
    • If the packet already has an SPP header, it's forwarded unchanged
    • If not, an SPP header is prepended with the client's original IP/port
  4. Forwarding: The packet is sent to the upstream server
  5. Responses: Responses from upstream are sent back to the original client

Testing

# Run tests
cargo test

# Run with verbose output
cargo test -- --nocapture

License

MIT License - See LICENSE file for details.

References

About

A implementation of UDP Simple Proxy Protocol to forward UDP packets with a IP/Port header attached

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages