| Crates.io | real |
| lib.rs | real |
| version | 0.1.4 |
| created_at | 2025-09-04 13:18:37.005029+00 |
| updated_at | 2025-09-04 13:18:37.005029+00 |
| description | A 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 | |
| repository | https://github.com/canmi21/real |
| max_upload_size | |
| id | 1824195 |
| size | 57,113 |
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.
X-Real-IP, X-Forwarded-For, CF-Connecting-IP, etc.)X-Forwarded-For chain parsing (first or last IP)axum feature)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"] }
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()));
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()));
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
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()));
The repository includes two examples:
demo.rs: Demonstrates various IP extraction scenarios using the library's core functionality.
Run with:
cargo run --example demo
axum.rs: Shows how to use the library with Axum middleware and extractors.
Run with:
cargo run --example axum --features="axum"
The IpExtractor struct allows customization of:
192.168.x.x) from headers are trusted.X-Forwarded-For chain.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"),
}
Run the test suite with:
cargo test
The library includes comprehensive tests for IP extraction, header parsing, and Axum integration.
This project is licensed under the MIT License. See the LICENSE file for details.
Contributions are welcome! Please submit issues or pull requests to the GitHub repository.