#hyper #reverse-proxy #http #header #client #tokio #async

未维护 httproxide-hyper-reverse-proxy

hyper-reverse-proxy 的临时分支

1 个不稳定版本

0.5.2-dev2022 年 8 月 1 日

#reverse-proxy 中排名第 70

Apache-2.0

27KB
332

hyper-reverse-proxy

License CI docs version

一个简单的反向代理,用于与 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之间的安全传输。

默认情况下,它们都没有启用。如果您想启用它们,可以使用功能dohdot

建议

  • 如果您需要监控与访问端口相关的网络活动,请使用带有dns-over-rustls功能标志的DoT
  • 如果您在野外,没有基于端口的监控需求,请使用带有dns-over-https-rustls功能标志的DoH,因为它将与其他https流量融合

强烈建议使用其中之一。

目前仅包括DNS查询作为esniech仍处于ietf的草案状态

依赖项

~4.5–6.5MB
~109K SLoC