Handle HTTPS targets

This commit is contained in:
Alex 2021-12-08 22:58:19 +01:00
parent 55f57df82e
commit ca8c5aad23
No known key found for this signature in database
GPG key ID: EDABF9711E244EB1
5 changed files with 74 additions and 10 deletions

28
Cargo.lock generated
View file

@ -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",

View file

@ -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"

View file

@ -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)

View file

@ -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,

View file

@ -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)
}