1 个不稳定版本
0.5.2-dev | 2022 年 8 月 1 日 |
---|
在 #reverse-proxy 中排名第 70
27KB
332 行
hyper-reverse-proxy
一个简单的反向代理,用于与 Hyper 一起使用。
实现确保了在双向正确地剥离 跳步头,并将客户端的 IP 地址添加到 X-Forwarded-For
头中用逗号和空格分隔的转发地址列表中。
实现基于 Go 的 httputil.ReverseProxy
。
示例
将这些依赖项添加到您的 Cargo.toml
文件中。
[dependencies]
hyper-reverse-proxy = "?"
hyper = { version = "?", features = ["full"] }
tokio = { version = "?", features = ["full"] }
lazy_static = "?"
hyper-trust-dns = { version = "?", features = [
"rustls-http2",
"dnssec-ring",
"dns-over-https-rustls",
"rustls-webpki",
"https-only"
] }
以下示例将在 127.0.0.1:13900
上设置一个反向代理,并将代理这些调用
-
"/target/first"
将被代理到http://127.0.0.1:13901
-
"/target/second"
将被代理到http://127.0.0.1:13902
-
所有其他 URL 都将由
debug_request
函数处理,该函数将显示请求信息。
use hyper::server::conn::AddrStream;
use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Request, Response, Server, StatusCode};
use hyper_reverse_proxy::ReverseProxy;
use hyper_trust_dns::{RustlsHttpsConnector, TrustDnsResolver};
use std::net::IpAddr;
use std::{convert::Infallible, net::SocketAddr};
lazy_static::lazy_static! {
static ref PROXY_CLIENT: ReverseProxy<RustlsHttpsConnector> = {
ReverseProxy::new(
hyper::Client::builder().build::<_, hyper::Body>(TrustDnsResolver::default().into_rustls_webpki_https_connector()),
)
};
}
fn debug_request(req: &Request<Body>) -> Result<Response<Body>, Infallible> {
let body_str = format!("{:?}", req);
Ok(Response::new(Body::from(body_str)))
}
async fn handle(client_ip: IpAddr, req: Request<Body>) -> Result<Response<Body>, Infallible> {
if req.uri().path().starts_with("/target/first") {
match PROXY_CLIENT.call(client_ip, "http://127.0.0.1:13901", req)
.await
{
Ok(response) => {
Ok(response)
},
Err(_error) => {
Ok(Response::builder()
.status(StatusCode::INTERNAL_SERVER_ERROR)
.body(Body::empty())
.unwrap())},
}
} else if req.uri().path().starts_with("/target/second") {
match PROXY_CLIENT.call(client_ip, "http://127.0.0.1:13902", req)
.await
{
Ok(response) => Ok(response),
Err(_error) => Ok(Response::builder()
.status(StatusCode::INTERNAL_SERVER_ERROR)
.body(Body::empty())
.unwrap()),
}
} else {
debug_request(&req)
}
}
#[tokio::main]
async fn main() {
let bind_addr = "127.0.0.1:8000";
let addr: SocketAddr = bind_addr.parse().expect("Could not parse ip:port.");
let make_svc = make_service_fn(|conn: &AddrStream| {
let remote_addr = conn.remote_addr().ip();
async move { Ok::<_, Infallible>(service_fn(move |req| handle(remote_addr, req))) }
});
let server = Server::bind(&addr).serve(make_svc);
println!("Running server on {:?}", addr);
if let Err(e) = server.await {
eprintln!("server error: {}", e);
}
}
关于安全性的说明
处理出站请求可能会成为一个安全问题。此包不控制出站请求的客户,因为它需要提供给代理调用。以下章节可能为您提供如何使用 hyper-trust-dns
包来保护客户的概述。
您可以在示例中看到它们的使用。
HTTPS
您应该使用安全的传输来了解您正在与谁交谈,并且可以信任连接。默认情况下,hyper-trust-dns
启用了功能标志https-only
,如果您提供的是不是https
的传输方案,则会引发恐慌。这是一个健康的默认设置,因为它不仅需要您信任源,还需要其他人看到不安全连接上的内容。
注意:如果您在您的证书存储中添加了证书的主机上运行,请确保定期审核它们,以确保您的客户端不会将旧证书或恶意证书视为有效。
TLS 1.2
默认情况下,为了防止许多部分被认为对攻击友好,禁用了tls 1.2
,转而使用tls 1.3
。由于并非所有服务都支持它,可以通过rustls-tls-12
功能启用tls 1.2
。
注意:请确保定期审核您连接到的服务
DNSSEC
从安全角度来看,由于DNS查询和条目默认不可信。 DNSSEC
添加了一个新的加密层用于验证。要启用它,请使用dnssec-ring
功能。
HTTP/2
默认情况下,仅启用rustlss的http1
功能用于DNS查询。虽然http/3
可能就在转角处。可以通过rustls-http2
功能启用http/2
支持。
DoT & DoH
DoT和DoH为您提供在您和您的DNS之间的安全传输。
默认情况下,它们都没有启用。如果您想启用它们,可以使用功能doh
和dot
。
建议
- 如果您需要监控与访问端口相关的网络活动,请使用带有
dns-over-rustls
功能标志的DoT - 如果您在野外,没有基于端口的监控需求,请使用带有
dns-over-https-rustls
功能标志的DoH,因为它将与其他https
流量融合
强烈建议使用其中之一。
目前仅包括DNS查询作为
esni
或ech
仍处于ietf
的草案状态
依赖项
~4.5–6.5MB
~109K SLoC