diff --git a/Cargo.lock b/Cargo.lock index e297475..66da4cc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -472,6 +472,12 @@ dependencies = [ "wasi", ] +[[package]] +name = "glob" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" + [[package]] name = "h2" version = "0.1.26" @@ -1880,6 +1886,7 @@ dependencies = [ "envy", "futures 0.3.18", "futures-util", + "glob", "http 0.2.5", "hyper 0.14.15", "hyper-reverse-proxy", diff --git a/Cargo.toml b/Cargo.toml index 5c6cb2c..bd40fe6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,3 +31,4 @@ hyper-reverse-proxy = "0.4" unicase = "2" lazy_static = "1.4" structopt = "0.3" +glob = "0.3" diff --git a/src/cert_store.rs b/src/cert_store.rs index f1b7d2b..8d45df4 100644 --- a/src/cert_store.rs +++ b/src/cert_store.rs @@ -14,7 +14,7 @@ use rustls::sign::CertifiedKey; use crate::cert::{Cert, CertSer}; use crate::consul::*; -use crate::proxy_config::ProxyConfig; +use crate::proxy_config::*; pub struct CertStore { consul: Consul, @@ -39,11 +39,13 @@ impl CertStore { let proxy_config: Arc = rx_proxy_config.borrow().clone(); for ent in proxy_config.entries.iter() { - domains.insert(ent.host.clone()); + if let HostDescription::Hostname(domain) = &ent.host { + domains.insert(domain.clone()); + } } - info!("Ensuring we have certs for domains: {:?}", domains); for dom in domains.iter() { + info!("Ensuring we have certs for domains: {:?}", domains); if let Err(e) = self.get_cert(dom).await { warn!("Error get_cert {}: {}", dom, e); } @@ -58,7 +60,7 @@ impl CertStore { .borrow() .entries .iter() - .any(|ent| ent.host == domain) + .any(|ent| ent.host.matches(domain)) { bail!("Domain {} should not have a TLS certificate.", domain); } diff --git a/src/https.rs b/src/https.rs index 3621e4f..2d97476 100644 --- a/src/https.rs +++ b/src/https.rs @@ -93,7 +93,7 @@ async fn handle( .entries .iter() .filter(|ent| { - ent.host == host + ent.host.matches(host) && ent .path_prefix .as_ref() diff --git a/src/proxy_config.rs b/src/proxy_config.rs index d4fe039..9092b59 100644 --- a/src/proxy_config.rs +++ b/src/proxy_config.rs @@ -15,11 +15,34 @@ use crate::consul::*; // ---- Extract proxy config from Consul catalog ---- +#[derive(Debug)] +pub enum HostDescription { + Hostname(String), + Pattern(glob::Pattern), +} + +impl HostDescription { + fn new(desc: &str) -> Result { + if desc.chars().any(|x| matches!(x, '*' | '?' | '[' | ']')) { + Ok(Self::Pattern(glob::Pattern::new(desc)?)) + } else { + Ok(Self::Hostname(desc.to_string())) + } + } + + pub fn matches(&self, v: &str) -> bool { + match self { + Self::Pattern(p) => p.matches(v), + Self::Hostname(s) => s == v, + } + } +} + #[derive(Debug)] pub struct ProxyEntry { pub target_addr: SocketAddr, - pub host: String, + pub host: HostDescription, pub path_prefix: Option, pub priority: u32, pub add_headers: Vec<(String, String)>, @@ -65,9 +88,17 @@ fn parse_tricot_tag( _ => 100, }; + let host = match HostDescription::new(host) { + Ok(h) => h, + Err(e) => { + warn!("Invalid hostname pattern {}: {}", host, e); + return None; + } + }; + Some(ProxyEntry { target_addr, - host: host.to_string(), + host, path_prefix, priority, add_headers: add_headers.to_vec(),