Handle HTTPS targets
This commit is contained in:
parent
55f57df82e
commit
ca8c5aad23
5 changed files with 74 additions and 10 deletions
28
Cargo.lock
generated
28
Cargo.lock
generated
|
@ -671,6 +671,21 @@ dependencies = [
|
||||||
"unicase",
|
"unicase",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hyper-rustls"
|
||||||
|
version = "0.23.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d87c48c02e0dc5e3b849a2041db3029fd066650f8f717c07bf8ed78ccb895cac"
|
||||||
|
dependencies = [
|
||||||
|
"http 0.2.5",
|
||||||
|
"hyper 0.14.15",
|
||||||
|
"log",
|
||||||
|
"rustls 0.20.2",
|
||||||
|
"rustls-native-certs",
|
||||||
|
"tokio 1.14.0",
|
||||||
|
"tokio-rustls",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper-tls"
|
name = "hyper-tls"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
|
@ -1294,6 +1309,18 @@ dependencies = [
|
||||||
"webpki 0.22.0",
|
"webpki 0.22.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls-native-certs"
|
||||||
|
version = "0.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5ca9ebdfa27d3fc180e42879037b5338ab1c040c06affd00d8338598e7800943"
|
||||||
|
dependencies = [
|
||||||
|
"openssl-probe",
|
||||||
|
"rustls-pemfile",
|
||||||
|
"schannel",
|
||||||
|
"security-framework",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls-pemfile"
|
name = "rustls-pemfile"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
|
@ -1913,6 +1940,7 @@ dependencies = [
|
||||||
"http 0.2.5",
|
"http 0.2.5",
|
||||||
"hyper 0.14.15",
|
"hyper 0.14.15",
|
||||||
"hyper-reverse-proxy",
|
"hyper-reverse-proxy",
|
||||||
|
"hyper-rustls",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"log",
|
"log",
|
||||||
"pretty_env_logger",
|
"pretty_env_logger",
|
||||||
|
|
|
@ -25,7 +25,7 @@ chrono = { version = "0.4", features = [ "serde" ] }
|
||||||
hyper = { version = "0.14", features = [ "full" ] }
|
hyper = { version = "0.14", features = [ "full" ] }
|
||||||
futures-util = "0.3"
|
futures-util = "0.3"
|
||||||
tokio-rustls = "0.23"
|
tokio-rustls = "0.23"
|
||||||
#hyper-rustls = "0.23"
|
hyper-rustls = "0.23"
|
||||||
http = "0.2"
|
http = "0.2"
|
||||||
hyper-reverse-proxy = "0.4"
|
hyper-reverse-proxy = "0.4"
|
||||||
unicase = "2"
|
unicase = "2"
|
||||||
|
|
23
src/https.rs
23
src/https.rs
|
@ -79,6 +79,9 @@ async fn handle(
|
||||||
req: Request<Body>,
|
req: Request<Body>,
|
||||||
proxy_config: Arc<ProxyConfig>,
|
proxy_config: Arc<ProxyConfig>,
|
||||||
) -> Result<Response<Body>, anyhow::Error> {
|
) -> Result<Response<Body>, anyhow::Error> {
|
||||||
|
let method = req.method().clone();
|
||||||
|
let uri = req.uri().to_string();
|
||||||
|
|
||||||
let host = if let Some(auth) = req.uri().authority() {
|
let host = if let Some(auth) = req.uri().authority() {
|
||||||
auth.as_str()
|
auth.as_str()
|
||||||
} else {
|
} else {
|
||||||
|
@ -89,7 +92,7 @@ async fn handle(
|
||||||
};
|
};
|
||||||
let path = req.uri().path();
|
let path = req.uri().path();
|
||||||
|
|
||||||
let ent = proxy_config
|
let best_match = proxy_config
|
||||||
.entries
|
.entries
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|ent| {
|
.filter(|ent| {
|
||||||
|
@ -111,17 +114,20 @@ async fn handle(
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Some(proxy_to) = ent {
|
|
||||||
|
if let Some(proxy_to) = best_match {
|
||||||
proxy_to.calls.fetch_add(1, Ordering::SeqCst);
|
proxy_to.calls.fetch_add(1, Ordering::SeqCst);
|
||||||
|
|
||||||
let to_addr = format!("http://{}", proxy_to.target_addr);
|
|
||||||
let method = req.method().clone();
|
|
||||||
|
|
||||||
let uri = req.uri().to_string();
|
|
||||||
debug!("{}{} -> {}", host, path, proxy_to);
|
debug!("{}{} -> {}", host, path, proxy_to);
|
||||||
trace!("Request: {:?}", req);
|
trace!("Request: {:?}", req);
|
||||||
|
|
||||||
let mut response = reverse_proxy::call(remote_addr.ip(), &to_addr, req).await?;
|
let mut response = if proxy_to.https_target {
|
||||||
|
let to_addr = format!("https://{}", proxy_to.target_addr);
|
||||||
|
reverse_proxy::call_https(remote_addr.ip(), &to_addr, req).await?
|
||||||
|
} else {
|
||||||
|
let to_addr = format!("http://{}", proxy_to.target_addr);
|
||||||
|
reverse_proxy::call(remote_addr.ip(), &to_addr, req).await?
|
||||||
|
};
|
||||||
|
|
||||||
for (header, value) in proxy_to.add_headers.iter() {
|
for (header, value) in proxy_to.add_headers.iter() {
|
||||||
response.headers_mut().insert(
|
response.headers_mut().insert(
|
||||||
|
@ -134,7 +140,8 @@ async fn handle(
|
||||||
|
|
||||||
Ok(response)
|
Ok(response)
|
||||||
} else {
|
} else {
|
||||||
info!("Proxying {} {} -> NOT FOUND", host, path);
|
debug!("{}{} -> NOT FOUND", host, path);
|
||||||
|
info!("{} 404 {}", method, uri);
|
||||||
|
|
||||||
Ok(Response::builder()
|
Ok(Response::builder()
|
||||||
.status(StatusCode::NOT_FOUND)
|
.status(StatusCode::NOT_FOUND)
|
||||||
|
|
|
@ -41,6 +41,7 @@ impl HostDescription {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ProxyEntry {
|
pub struct ProxyEntry {
|
||||||
pub target_addr: SocketAddr,
|
pub target_addr: SocketAddr,
|
||||||
|
pub https_target: bool,
|
||||||
|
|
||||||
pub host: HostDescription,
|
pub host: HostDescription,
|
||||||
pub path_prefix: Option<String>,
|
pub path_prefix: Option<String>,
|
||||||
|
@ -55,6 +56,9 @@ pub struct ProxyEntry {
|
||||||
|
|
||||||
impl std::fmt::Display for ProxyEntry {
|
impl std::fmt::Display for ProxyEntry {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
if self.https_target {
|
||||||
|
write!(f, "https://")?;
|
||||||
|
}
|
||||||
write!(f, "{} ", self.target_addr)?;
|
write!(f, "{} ", self.target_addr)?;
|
||||||
match &self.host {
|
match &self.host {
|
||||||
HostDescription::Hostname(h) => write!(f, "{}", h)?,
|
HostDescription::Hostname(h) => write!(f, "{}", h)?,
|
||||||
|
@ -94,7 +98,8 @@ fn parse_tricot_tag(
|
||||||
add_headers: &[(String, String)],
|
add_headers: &[(String, String)],
|
||||||
) -> Option<ProxyEntry> {
|
) -> Option<ProxyEntry> {
|
||||||
let splits = tag.split(' ').collect::<Vec<_>>();
|
let splits = tag.split(' ').collect::<Vec<_>>();
|
||||||
if (splits.len() != 2 && splits.len() != 3) || splits[0] != "tricot" {
|
if (splits.len() != 2 && splits.len() != 3)
|
||||||
|
|| (splits[0] != "tricot" && splits[0] != "tricot-https") {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,6 +126,7 @@ fn parse_tricot_tag(
|
||||||
|
|
||||||
Some(ProxyEntry {
|
Some(ProxyEntry {
|
||||||
target_addr,
|
target_addr,
|
||||||
|
https_target: (splits[0] == "tricot-https"),
|
||||||
host,
|
host,
|
||||||
path_prefix,
|
path_prefix,
|
||||||
priority,
|
priority,
|
||||||
|
|
|
@ -139,3 +139,26 @@ pub async fn call(
|
||||||
let proxied_response = create_proxied_response(response);
|
let proxied_response = create_proxied_response(response);
|
||||||
Ok(proxied_response)
|
Ok(proxied_response)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn call_https(
|
||||||
|
client_ip: IpAddr,
|
||||||
|
forward_uri: &str,
|
||||||
|
request: Request<Body>,
|
||||||
|
) -> Result<Response<Body>> {
|
||||||
|
let proxied_request = create_proxied_request(client_ip, &forward_uri, request)?;
|
||||||
|
|
||||||
|
trace!("Proxied request (HTTPS): {:?}", proxied_request);
|
||||||
|
|
||||||
|
let https = hyper_rustls::HttpsConnectorBuilder::new()
|
||||||
|
.with_native_roots()
|
||||||
|
.https_only()
|
||||||
|
.enable_http1()
|
||||||
|
.build();
|
||||||
|
let client: Client<_, hyper::Body> = Client::builder().build(https);
|
||||||
|
let response = client.request(proxied_request).await?;
|
||||||
|
|
||||||
|
trace!("Inner response (HTTPS): {:?}", response);
|
||||||
|
|
||||||
|
let proxied_response = create_proxied_response(response);
|
||||||
|
Ok(proxied_response)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue