real

Crates.ioreal
lib.rsreal
version0.1.4
created_at2025-09-04 13:18:37.005029+00
updated_at2025-09-04 13:18:37.005029+00
descriptionA lightweight library for extracting the real client IP address from HTTP requests, supporting common forwarding headers such as X-Real-IP and X-Forwarded-For, with a fallback to the remote socket address.
homepage
repositoryhttps://github.com/canmi21/real
max_upload_size
id1824195
size57,113
Canmi (canmi21)

documentation

README

Real IP Extractor

A lightweight Rust library for extracting the real client IP address from HTTP requests, supporting common forwarding headers such as X-Real-IP and X-Forwarded-For, with a fallback to the remote socket address.

Features

  • Extract real IP from various HTTP headers (X-Real-IP, X-Forwarded-For, CF-Connecting-IP, etc.)
  • Configurable header priority and IP validation rules
  • Optional trust for private IPs from headers
  • Support for X-Forwarded-For chain parsing (first or last IP)
  • Fallback to remote socket address
  • Optional Axum middleware and extractor integration (via the axum feature)
  • Lightweight and dependency-minimal
  • Comprehensive test suite

Installation

Add the following to your Cargo.toml:

[dependencies]
real = "0.1"

For Axum integration, enable the axum feature:

[dependencies]
real = { version = "0.1", features = ["axum"] }

Usage

Basic Usage

Extract the real IP address from HTTP headers with a fallback to the remote socket address:

use real::{extract_real_ip, HeaderMap};
use std::collections::HashMap;

let mut headers = HashMap::new();
headers.insert("x-real-ip".to_string(), "203.0.113.45".to_string());

let ip = extract_real_ip(&headers, Some("127.0.0.1".to_string()));
assert_eq!(ip, Some("203.0.113.45".parse().unwrap()));

Custom Configuration

Create a custom IpExtractor with specific settings:

use real::{IpExtractor, HeaderMap};
use std::collections::HashMap;

let mut headers = HashMap::new();
headers.insert("custom-real-ip".to_string(), "203.0.113.200".to_string());

let extractor = IpExtractor::new()
    .with_headers(vec!["custom-real-ip".to_string()])
    .trust_private_ips(false)
    .use_first_forwarded(true);

let ip = extractor.extract(&headers, None);
assert_eq!(ip, Some("203.0.113.200".parse().unwrap()));

Axum Integration

Use the RealIpLayer middleware to automatically extract the real IP and make it available in your handlers:

use axum::{Router, routing::get, extract::ConnectInfo};
use real::{RealIp, RealIpLayer};
use std::net::SocketAddr;

async fn handler(real_ip: RealIp) -> String {
    format!("Your real IP is: {}", real_ip.ip())
}

#[tokio::main]
async fn main() {
    let app = Router::new()
        .route("/", get(handler))
        .layer(RealIpLayer::default());

    let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
    axum::serve(listener, app.into_make_service_with_connect_info::<SocketAddr>())
        .await
        .unwrap();
}

Run the Axum example with:

cargo run --example axum

Then test with curl:

curl -H "X-Real-IP: 203.0.113.42" http://localhost:3000

Strict Mode

Use extract_real_ip_strict to reject private IPs from headers:

use real::{extract_real_ip_strict, HeaderMap};
use std::collections::HashMap;

let mut headers = HashMap::new();
headers.insert("x-real-ip".to_string(), "192.168.1.100".to_string());

let ip = extract_real_ip_strict(&headers, Some("203.0.113.50".to_string()));
assert_eq!(ip, Some("203.0.113.50".parse().unwrap()));

Examples

The repository includes two examples:

  1. demo.rs: Demonstrates various IP extraction scenarios using the library's core functionality. Run with:

    cargo run --example demo
    
  2. axum.rs: Shows how to use the library with Axum middleware and extractors. Run with:

    cargo run --example axum --features="axum"
    

Configuration Options

The IpExtractor struct allows customization of:

  • Header Priority: Specify which headers to check and in what order.
  • Private IP Trust: Control whether private IPs (e.g., 192.168.x.x) from headers are trusted.
  • X-Forwarded-For Behavior: Choose whether to use the first or last IP in the X-Forwarded-For chain.

Error Handling

The library defines a RealIpError enum for handling errors:

use real::{Result, RealIpError};

match extract_real_ip(&headers, None) {
    Ok(Some(ip)) => println!("Extracted IP: {}", ip),
    Ok(None) => println!("No valid IP found"),
    Err(RealIpError::InvalidIpFormat(err)) => println!("Invalid IP format: {}", err),
    Err(RealIpError::NoValidIp) => println!("No valid IP address found"),
}

Testing

Run the test suite with:

cargo test

The library includes comprehensive tests for IP extraction, header parsing, and Axum integration.

License

This project is licensed under the MIT License. See the LICENSE file for details.

Contributing

Contributions are welcome! Please submit issues or pull requests to the GitHub repository.

Commit count: 32

cargo fmt