Rust网络编程库client-ip的使用:轻松获取客户端真实IP地址的高效工具
以下是关于Rust网络编程库client-ip的使用介绍和完整示例:
Rust网络编程库client-ip的使用:轻松获取客户端真实IP地址的高效工具
client-ip
是一个从http::HeaderMap
中安全提取客户端IP的Rust库。该代码最初是从axum-client-ip
crate中提取出来的,用于非axum的使用场景。
支持的提取器
以下表格列出了当前支持的IP提取器及其对应的HTTP头:
提取器 | 使用的头 | 典型的代理/服务 |
---|---|---|
cf_connecting_ip |
CF-Connecting-IP |
Cloudflare |
cloudfront_viewer_address |
CloudFront-Viewer-Address |
AWS CloudFront |
fly_client_ip |
Fly-Client-IP |
Fly.io |
rightmost_forwarded |
Forwarded |
支持RFC 7239的代理(提取最右边的for= ) |
rightmost_x_forwarded_for |
X-Forwarded-For |
Nginx, Apache, HAProxy, CDNs, LBs |
true_client_ip |
True-Client-IP |
Cloudflare, Akamai |
x_real_ip |
X-Real-Ip |
Nginx |
安装
在项目目录中运行以下Cargo命令:
cargo add client-ip
或者在Cargo.toml中添加以下行:
client-ip = "0.1.1"
使用示例
下面是内容中提供的示例代码:
use client_ip::*;
use http::HeaderMap;
fn main() {
// 创建模拟的HTTP请求头
let mut headers = HeaderMap::new();
// 添加各种可能的IP头
headers.insert("CF-Connecting-IP", "203.0.113.1".parse().unwrap());
headers.insert("X-Forwarded-For", "203.0.113.2, 198.51.100.1".parse().unwrap());
headers.insert("X-Real-Ip", "203.0.113.3".parse().unwrap());
// 尝试从不同头中提取IP
let ip_from_cloudflare = cf_connecting_ip(&headers);
let ip_from_x_forwarded = rightmost_x_forwarded_for(&headers);
let ip_from_x_real = x_real_ip(&headers);
println!("IP from Cloudflare header: {:?}", ip_from_cloudflare);
println!("IP from X-Forwarded-For: {:?}", ip_from_x_forwarded);
println!("IP from X-Real-Ip: {:?}", ip_from_x_real);
// 优先使用特定代理的头,然后尝试其他头
let client_ip = cf_connecting_ip(&headers)
.or_else(|| rightmost_x_forwarded_for(&headers))
.or_else(|| x_real_ip(&headers))
.unwrap_or_else(|| std::net::IpAddr::from([0, 0, 0, 0]));
println!("最终确定的客户端IP: {}", client_ip);
}
完整示例demo
以下是一个更完整的示例,展示如何在Web服务器中使用client-ip:
use client_ip::*;
use http::{HeaderMap, Request, Response};
use hyper::Body;
async fn handle_request(req: Request<Body>) -> Result<Response<Body>, hyper::Error> {
// 从请求中获取头信息
let headers = req.headers();
// 尝试从不同头中提取客户端IP
let client_ip = cf_connecting_ip(&headers)
.or_else(|| rightmost_x_forwarded_for(&headers))
.or_else(|| x_real_ip(&headers))
.unwrap_or_else(|| std::net::IpAddr::from([0, 0, 0, 0]));
println!("客户端IP: {}", client_ip);
// 创建响应
let response = Response::builder()
.status(200)
.body(Body::from(format!("你的IP地址是: {}", client_ip)))
.unwrap();
Ok(response)
}
#[tokio::main]
async fn main() {
// 创建模拟请求
let mut request = Request::builder()
.uri("http://example.com")
.body(Body::empty())
.unwrap();
// 添加测试头
request.headers_mut().insert(
"X-Forwarded-For",
"203.0.113.1, 198.51.100.1".parse().unwrap()
);
// 处理请求
let response = handle_request(request).await.unwrap();
// 打印响应体
let body = hyper::body::to_bytes(response.into_body()).await.unwrap();
println!("服务器响应: {}", String::from_utf8(body.to_vec()).unwrap());
}
贡献
如果你维护其他基于http
框架的客户端IP提取功能,可以考虑使用这个crate,这样我们就可以在一个地方处理安全敏感的代码。
许可证
该项目采用MIT许可证。
1 回复
Rust网络编程库client-ip使用指南
client-ip
是一个用于获取客户端真实IP地址的Rust库,特别适合在反向代理或负载均衡环境下使用。
功能特点
- 支持从多种HTTP头中提取客户端IP
- 自动处理X-Forwarded-For、Forwarded等标准头部
- 提供灵活的配置选项
- 高性能,零成本抽象
基本使用方法
添加依赖
首先在Cargo.toml中添加依赖:
[dependencies]
client-ip = "0.2"
基本示例
use client_ip::ClientIp;
use std::net::SocketAddr;
fn main() {
// 模拟从请求中获取的信息
let headers = vec![
("x-forwarded-for", "203.0.113.45, 198.51.100.67"),
("forwarded", "for=192.0.2.43;proto=http"),
];
let remote_addr: SocketAddr = "198.51.100.67:12345".parse().unwrap();
// 获取客户端IP
let client_ip = ClientIp::new(&headers, Some(&remote_addr)).get_ip();
println!("客户端真实IP: {}", client_ip.unwrap());
// 输出: 203.0.113.45
}
高级配置
自定义信任代理
use client_ip::{ClientIp, ClientIpConfig};
use std::net::{IpAddr, Ipv4Addr};
fn main() {
let config = ClientIpConfig::new()
.trust_proxy(vec![
IpAddr::V4(Ipv4Addr::new(198, 51, 100, 0)),
IpAddr::V4(Ipv4Addr::new(203, 0, 113, 0)),
])
.enable_forwarded_header(true);
let headers = vec![
("x-forwarded-for", "203.0.113.45, 198.51.100.67"),
];
let remote_addr: SocketAddr = "198.51.100.67:12345".parse().unwrap();
let client_ip = ClientIp::with_config(&headers, Some(&remote_addr), config)
.get_ip();
println!("客户端真实IP: {}", client_ip.unwrap());
}
与Web框架集成示例
使用Actix-web
use actix_web::{web, App, HttpServer, HttpRequest, Responder};
use client_ip::ClientIp;
async fn index(req: HttpRequest) -> impl Responder {
let headers: Vec<_> = req.headers()
.iter()
.map(|(name, value)| (name.as_str(), value.to_str().unwrap()))
.collect();
let remote_addr = req.peer_addr();
let client_ip = ClientIp::new(&headers, remote_addr.as_ref())
.get_ip()
.unwrap_or_else(|| "未知IP".to_string());
format!("你的IP地址是: {}", client_ip)
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new().route("/", web::get().to(index))
})
.bind("127.0.0.1:8080")?
.run()
.await
}
使用Warp框架
use warp::Filter;
use client_ip::ClientIp;
use std::net::SocketAddr;
async fn get_ip(headers: Vec<(&str, &str)>, remote_addr: Option<SocketAddr>) -> String {
let client_ip = ClientIp::new(&headers, remote_addr.as_ref())
.get_ip()
.unwrap_or_else(|| "未知IP".to_string());
format!("你的IP地址是: {}", client_ip)
}
#[tokio::main]
async fn main() {
let route = warp::any()
.and(warp::header::headers_cloned())
.and(warp::addr::remote())
.then(|headers: warp::http::HeaderMap, addr: Option<SocketAddr>| async move {
let headers: Vec<_> = headers.iter()
.map(|(name, value)| (name.as_str(), value.to_str().unwrap()))
.collect();
get_ip(headers, addr).await
});
warp::serve(route).run(([127, 0, 0, 1], 3030)).await;
}
注意事项
- 在反向代理环境下,确保代理服务器正确设置了X-Forwarded-For等头部
- 对于安全敏感应用,应该配置信任的代理IP列表
- 该库不会验证IP地址的真实性,只是按规则提取
- 在生产环境中,建议结合其他安全措施使用
client-ip
库通过简洁的API提供了强大的客户端IP提取功能,是处理复杂网络环境下客户端识别的理想选择。
完整示例Demo
下面是一个结合Axum框架的完整示例:
use axum::{
routing::get,
Router,
http::{HeaderMap, StatusCode},
response::IntoResponse,
};
use client_ip::ClientIp;
use std::net::SocketAddr;
async fn ip_handler(headers: HeaderMap, remote_addr: Option<SocketAddr>) -> impl IntoResponse {
// 转换HeaderMap为client-ip所需的格式
let headers: Vec<_> = headers.iter()
.map(|(name, value)| (name.as_str(), value.to_str().unwrap()))
.collect();
// 获取客户端IP
let client_ip = ClientIp::new(&headers, remote_addr.as_ref())
.get_ip()
.unwrap_or_else(|| "未知IP".to_string());
(StatusCode::OK, format!("你的IP地址是: {}", client_ip))
}
#[tokio::main]
async fn main() {
// 构建路由
let app = Router::new()
.route("/", get(ip_handler));
// 启动服务器
let listener = tokio::net::TcpListener::bind("127.0.0.1:3000").await.unwrap();
println!("服务器运行在 http://127.0.0.1:3000");
axum::serve(listener, app).await.unwrap();
}
这个示例展示了如何:
- 创建一个简单的Axum Web服务器
- 处理HTTP请求中的headers
- 使用client-ip库提取客户端真实IP
- 返回包含IP地址的响应
要运行这个示例,需要在Cargo.toml中添加以下依赖:
[dependencies]
axum = "0.6"
client-ip = "0.2"
tokio = { version = "1.0", features = ["full"] }