real 0.1.4

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.
Documentation
# 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`:

```toml
[dependencies]
real = "0.1"
```

For Axum integration, enable the `axum` feature:

```toml
[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:

```rust
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:

```rust
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:

```rust
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:

```bash
cargo run --example axum
```

Then test with curl:

```bash
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:

```rust
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:
   ```bash
   cargo run --example demo
   ```

2. **`axum.rs`**: Shows how to use the library with Axum middleware and extractors.
   Run with:
   ```bash
   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:

```rust
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:

```bash
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](LICENSE) file for details.

## Contributing

Contributions are welcome! Please submit issues or pull requests to the [GitHub repository](https://github.com/canmi21/real).