mod router;
mod services;
#[cfg(test)]
mod tests;
use std::sync::Arc;
use anyhow::Result;
use pingora_core::{
listeners::tls::TlsSettings,
services::listening::Service,
server::Server as PingoraServer,
};
use tracing::info;
use crate::{
RunContext, certificates::{
CertificateRuntime, handler::CertHandler,
}, config::{AcmeChallenge, TlsAcmeConfig, TlsConfig}, proxy::services::{
CleartextHandler, Vicarian
}
};
pub fn run_indefinitely(cert_runtime: Arc<CertificateRuntime>, context: Arc<RunContext>) -> Result<()> {
info!("Starting Proxy");
let mut pingora_server = PingoraServer::new(None)?;
pingora_server.bootstrap();
let addrs = context.config.listen.addrs()?;
let tls_proxy = {
let vicarian = Vicarian::new(cert_runtime.certstore().clone(), context.clone());
let mut pingora_proxy = pingora_proxy::http_proxy_service(
&pingora_server.configuration,
vicarian);
for addr in &addrs {
let cert_handler = CertHandler::new(cert_runtime.certstore().clone());
let mut tls_settings = TlsSettings::with_callbacks(Box::new(cert_handler))?;
tls_settings.enable_h2();
let mut addr_port = *addr;
addr_port.set_port(context.config.listen.tls_port);
let addr_port = addr_port.to_string();
info!("Binding to {addr_port}");
pingora_proxy.add_tls_with_settings(&addr_port, None, tls_settings);
}
pingora_proxy
};
pingora_server.add_service(tls_proxy);
let has_http01 = context.config.vhosts.iter()
.any(|vh| matches!(vh.tls, TlsConfig::Acme(
TlsAcmeConfig { challenge: AcmeChallenge::Http01, .. })));
if has_http01 || context.config.listen.insecure_port.is_some() {
let insecure_port = context.config.listen.insecure_port
.unwrap_or(80);
let redirector = CleartextHandler::new(cert_runtime.acme().clone(), context.config.listen.tls_port);
let mut service = Service::new("HTTP->HTTPS Redirector".to_string(), redirector);
for addr in &addrs {
let mut addr_port = *addr;
addr_port.set_port(insecure_port);
let addr_port = addr_port.to_string();
info!("Binding to {addr_port}");
service.add_tcp(&addr_port);
}
pingora_server.add_service(service);
};
pingora_server.run(pingora_core::server::RunArgs::default());
Ok(())
}
fn rewrite_port(host: &str, newport: &str) -> String {
let port_i = if let Some(i) = host.rfind(':') {
i
} else {
return host.to_string();
};
if host[port_i + 1..].parse::<u16>().is_err() {
return host.to_string();
}
let host_only = &host[0..port_i];
format!("{host_only}:{newport}")
}
fn strip_port(host_header: &str) -> &str {
if let Some(i) = host_header.rfind(':') {
&host_header[0..i]
} else {
host_header
}
}