1mod acme;
2mod config;
3mod handler;
4mod listener_handler_communication;
5mod listeners;
6mod request_handler;
7mod runtime;
8mod tls_util;
9mod util;
10
11use std::collections::{HashMap, HashSet};
12use std::error::Error;
13use std::net::{IpAddr, Ipv6Addr, SocketAddr};
14use std::path::{Path, PathBuf};
15use std::str::FromStr;
16use std::sync::{Arc, LazyLock, Mutex};
17use std::thread;
18use std::time::Duration;
19
20use async_channel::{Receiver, Sender};
21use base64::Engine;
22use clap::{Arg, ArgAction, ArgMatches, Command};
23use ferron_common::logging::{ErrorLogger, LogMessage};
24use ferron_common::{get_entry, get_value, get_values};
25use ferron_load_modules::{get_dns_provider, obtain_module_loaders, obtain_observability_backend_loaders};
26use human_panic::{setup_panic, Metadata};
27use instant_acme::{ChallengeType, ExternalAccountKey, LetsEncrypt};
28use mimalloc::MiMalloc;
29use rustls::client::WebPkiServerVerifier;
30use rustls::crypto::aws_lc_rs::cipher_suite::*;
31use rustls::crypto::aws_lc_rs::default_provider;
32use rustls::crypto::aws_lc_rs::kx_group::*;
33use rustls::server::{ResolvesServerCert, WebPkiClientVerifier};
34use rustls::sign::CertifiedKey;
35use rustls::version::{TLS12, TLS13};
36use rustls::{ClientConfig, RootCertStore, ServerConfig};
37use rustls_native_certs::load_native_certs;
38use rustls_platform_verifier::BuilderVerifierExt;
39use shadow_rs::shadow;
40use tokio_util::sync::CancellationToken;
41use xxhash_rust::xxh3::xxh3_128;
42
43use crate::acme::{
44 add_domain_to_cache, check_certificate_validity_or_install_cached, convert_on_demand_config, get_cached_domains,
45 provision_certificate, AcmeCache, AcmeConfig, AcmeOnDemandConfig, AcmeResolver, TlsAlpn01Resolver,
46 ACME_TLS_ALPN_NAME,
47};
48use crate::config::adapters::ConfigurationAdapter;
49use crate::config::processing::{
50 load_modules, merge_duplicates, premerge_configuration, remove_and_add_global_configuration,
51};
52use crate::config::ServerConfigurations;
53use crate::handler::create_http_handler;
54use crate::listener_handler_communication::ConnectionData;
55use crate::listeners::{create_quic_listener, create_tcp_listener};
56use crate::tls_util::{load_certs, load_private_key, CustomSniResolver, OneCertifiedKeyResolver};
57use crate::util::{is_localhost, match_hostname, NoServerVerifier};
58
59#[global_allocator]
61static GLOBAL: MiMalloc = MiMalloc;
62
63shadow!(build);
64
65static LISTENER_HANDLER_CHANNEL: LazyLock<Arc<(Sender<ConnectionData>, Receiver<ConnectionData>)>> =
66 LazyLock::new(|| Arc::new(async_channel::unbounded()));
67#[allow(clippy::type_complexity)]
68static TCP_LISTENERS: LazyLock<Arc<Mutex<HashMap<SocketAddr, CancellationToken>>>> =
69 LazyLock::new(|| Arc::new(Mutex::new(HashMap::new())));
70#[allow(clippy::type_complexity)]
71static QUIC_LISTENERS: LazyLock<Arc<Mutex<HashMap<SocketAddr, (CancellationToken, Sender<Arc<ServerConfig>>)>>>> =
72 LazyLock::new(|| Arc::new(Mutex::new(HashMap::new())));
73static URING_ENABLED: LazyLock<Arc<Mutex<bool>>> = LazyLock::new(|| Arc::new(Mutex::new(true)));
74static LISTENER_LOGGING_CHANNEL: LazyLock<Arc<(Sender<LogMessage>, Receiver<LogMessage>)>> =
75 LazyLock::new(|| Arc::new(async_channel::unbounded()));
76
77fn handle_shutdown_signals(runtime: &tokio::runtime::Runtime) -> bool {
79 runtime.block_on(async move {
80 let (continue_tx, continue_rx) = async_channel::unbounded::<bool>();
81 let cancel_token = tokio_util::sync::CancellationToken::new();
82
83 #[cfg(unix)]
84 {
85 let cancel_token_clone = cancel_token.clone();
86 let continue_tx_clone = continue_tx.clone();
87 tokio::spawn(async move {
88 if let Ok(mut signal) = tokio::signal::unix::signal(tokio::signal::unix::SignalKind::hangup()) {
89 tokio::select! {
90 _ = signal.recv() => {
91 continue_tx_clone.send(true).await.unwrap_or_default();
92 }
93 _ = cancel_token_clone.cancelled() => {}
94 }
95 }
96 });
97 }
98
99 let cancel_token_clone = cancel_token.clone();
100 tokio::spawn(async move {
101 tokio::select! {
102 result = tokio::signal::ctrl_c() => {
103 if result.is_ok() {
104 continue_tx.send(false).await.unwrap_or_default();
105 }
106 }
107 _ = cancel_token_clone.cancelled() => {}
108 }
109 });
110
111 let continue_running = continue_rx.recv().await.unwrap_or(false);
112 cancel_token.cancel();
113 continue_running
114 })
115}
116
117fn before_starting_server(
119 args: ArgMatches,
120 configuration_adapters: HashMap<String, Box<dyn ConfigurationAdapter + Send + Sync>>,
121) -> Result<(), Box<dyn Error + Send + Sync>> {
122 let configuration_path: &Path = args
124 .get_one::<PathBuf>("config")
125 .ok_or(anyhow::anyhow!("Cannot obtain the configuration path"))?
126 .as_path();
127 let configuration_adapter: &str = args
128 .get_one::<String>("config-adapter")
129 .map_or(determine_default_configuration_adapter(configuration_path), |s| {
130 s as &str
131 });
132
133 let mut old_runtime: Option<(Vec<CancellationToken>, tokio::runtime::Runtime)> = None;
135
136 let configuration_adapter = configuration_adapters
138 .get(configuration_adapter)
139 .ok_or(anyhow::anyhow!(
140 "The \"{}\" configuration adapter isn't supported",
141 configuration_adapter
142 ))?;
143
144 let available_parallelism = thread::available_parallelism()?.get();
146
147 let mut first_startup = true;
149
150 loop {
151 let mut module_loaders = obtain_module_loaders();
153
154 let mut observability_backend_loaders = obtain_observability_backend_loaders();
156
157 let secondary_runtime = tokio::runtime::Builder::new_multi_thread()
159 .worker_threads(match available_parallelism / 2 {
160 0 => 1,
161 non_zero => non_zero,
162 })
163 .thread_name("Secondary runtime")
164 .enable_all()
165 .build()?;
166
167 let configs_to_process = configuration_adapter.load_configuration(configuration_path)?;
169
170 let configs_to_process = merge_duplicates(configs_to_process);
172 let configs_to_process = remove_and_add_global_configuration(configs_to_process);
173 let configs_to_process = premerge_configuration(configs_to_process);
174 let (configs_to_process, first_module_error, unused_properties) = load_modules(
175 configs_to_process,
176 &mut module_loaders,
177 &mut observability_backend_loaders,
178 &secondary_runtime,
179 );
180
181 let server_configurations = Arc::new(ServerConfigurations::new(configs_to_process));
183
184 let global_configuration = server_configurations.find_global_configuration();
185 let global_configuration_clone = global_configuration.clone();
186
187 let secondary_runtime_ref = &secondary_runtime;
189
190 let old_runtime_ref = &mut old_runtime;
192
193 let execute_rest = move || {
195 if let Some(first_module_error) = first_module_error {
196 Err(first_module_error)?;
198 }
199
200 for unused_property in unused_properties {
202 for logging_tx in global_configuration
203 .as_ref()
204 .map_or(&vec![], |c| &c.observability.log_channels)
205 {
206 logging_tx
207 .send_blocking(LogMessage::new(
208 format!("Unused configuration property detected: \"{unused_property}\""),
209 true,
210 ))
211 .unwrap_or_default();
212 }
213 }
214
215 let mut crypto_provider = default_provider();
217
218 let cipher_suite: Vec<&config::ServerConfigurationValue> = global_configuration
220 .as_deref()
221 .map_or(vec![], |c| get_values!("tls_cipher_suite", c));
222 if !cipher_suite.is_empty() {
223 let mut cipher_suites = Vec::new();
224 let cipher_suite_iter = cipher_suite.iter();
225 for cipher_suite_config in cipher_suite_iter {
226 if let Some(cipher_suite) = cipher_suite_config.as_str() {
227 let cipher_suite_to_add = match cipher_suite {
228 "TLS_AES_128_GCM_SHA256" => TLS13_AES_128_GCM_SHA256,
229 "TLS_AES_256_GCM_SHA384" => TLS13_AES_256_GCM_SHA384,
230 "TLS_CHACHA20_POLY1305_SHA256" => TLS13_CHACHA20_POLY1305_SHA256,
231 "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" => TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
232 "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384" => TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
233 "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256" => TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
234 "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" => TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
235 "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384" => TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
236 "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256" => TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
237 _ => Err(anyhow::anyhow!(
238 "The \"{}\" cipher suite is not supported",
239 cipher_suite
240 ))?,
241 };
242 cipher_suites.push(cipher_suite_to_add);
243 }
244 }
245 crypto_provider.cipher_suites = cipher_suites;
246 }
247
248 let ecdh_curves = global_configuration
250 .as_deref()
251 .map_or(vec![], |c| get_values!("tls_ecdh_curve", c));
252 if !ecdh_curves.is_empty() {
253 let mut kx_groups = Vec::new();
254 let ecdh_curves_iter = ecdh_curves.iter();
255 for ecdh_curve_config in ecdh_curves_iter {
256 if let Some(ecdh_curve) = ecdh_curve_config.as_str() {
257 let kx_group_to_add = match ecdh_curve {
258 "secp256r1" => SECP256R1,
259 "secp384r1" => SECP384R1,
260 "x25519" => X25519,
261 "x25519mklem768" => X25519MLKEM768,
262 "mklem768" => MLKEM768,
263 _ => Err(anyhow::anyhow!("The \"{}\" ECDH curve is not supported", ecdh_curve))?,
264 };
265 kx_groups.push(kx_group_to_add);
266 }
267 }
268 crypto_provider.kx_groups = kx_groups;
269 }
270
271 if crypto_provider.clone().install_default().is_err() && first_startup {
273 Err(anyhow::anyhow!("Cannot install a process-wide cryptography provider"))?;
274 }
275
276 let crypto_provider = Arc::new(crypto_provider);
277
278 let tls_config_builder_wants_versions = ServerConfig::builder_with_provider(crypto_provider.clone());
280
281 let min_tls_version_option = global_configuration
282 .as_deref()
283 .and_then(|c| get_value!("tls_min_version", c))
284 .and_then(|v| v.as_str());
285 let max_tls_version_option = global_configuration
286 .as_deref()
287 .and_then(|c| get_value!("tls_max_version", c))
288 .and_then(|v| v.as_str());
289
290 let tls_config_builder_wants_verifier = if min_tls_version_option.is_none() && max_tls_version_option.is_none() {
291 tls_config_builder_wants_versions.with_safe_default_protocol_versions()?
292 } else {
293 let tls_versions = [("TLSv1.2", &TLS12), ("TLSv1.3", &TLS13)];
294 let min_tls_version_index = min_tls_version_option
295 .map_or(Some(0), |v| tls_versions.iter().position(|p| p.0 == v))
296 .ok_or(anyhow::anyhow!("Invalid minimum TLS version"))?;
297 let max_tls_version_index = max_tls_version_option
298 .map_or(Some(tls_versions.len() - 1), |v| {
299 tls_versions.iter().position(|p| p.0 == v)
300 })
301 .ok_or(anyhow::anyhow!("Invalid maximum TLS version"))?;
302 if max_tls_version_index < min_tls_version_index {
303 Err(anyhow::anyhow!("Maximum TLS version is older than minimum TLS version"))?
304 }
305 tls_config_builder_wants_versions.with_protocol_versions(
306 &tls_versions[min_tls_version_index..=max_tls_version_index]
307 .iter()
308 .map(|p| p.1)
309 .collect::<Vec<_>>(),
310 )?
311 };
312
313 let tls_config_builder_wants_server_cert = if let Some(client_cert_path) = global_configuration
314 .as_deref()
315 .and_then(|c| get_value!("tls_client_certificate", c))
316 .and_then(|v| v.as_str())
317 {
318 let mut roots = RootCertStore::empty();
319 let client_certificate_cas = load_certs(client_cert_path)?;
320 for cert in client_certificate_cas {
321 roots.add(cert)?;
322 }
323 tls_config_builder_wants_verifier
324 .with_client_cert_verifier(WebPkiClientVerifier::builder(Arc::new(roots)).build()?)
325 } else if global_configuration
326 .as_deref()
327 .and_then(|c| get_value!("tls_client_certificate", c))
328 .and_then(|v| v.as_bool())
329 .unwrap_or(false)
330 {
331 let roots = (|| {
332 let certs_result = load_native_certs();
333 if !certs_result.errors.is_empty() {
334 return None;
335 }
336 let certs = certs_result.certs;
337
338 let mut roots = RootCertStore::empty();
339 for cert in certs {
340 if roots.add(cert).is_err() {
341 return None;
342 }
343 }
344
345 Some(roots)
346 })()
347 .unwrap_or(RootCertStore {
348 roots: webpki_roots::TLS_SERVER_ROOTS.to_vec(),
349 });
350
351 tls_config_builder_wants_verifier
352 .with_client_cert_verifier(WebPkiClientVerifier::builder(Arc::new(roots)).build()?)
353 } else {
354 tls_config_builder_wants_verifier.with_no_client_auth()
355 };
356
357 let enable_proxy_protocol = global_configuration
358 .as_ref()
359 .and_then(|c| get_value!("protocol_proxy", c))
360 .and_then(|v| v.as_bool())
361 .unwrap_or(false);
362 let protocols = global_configuration
363 .as_ref()
364 .and_then(|c| get_entry!("protocols", c))
365 .map(|e| e.values.iter().filter_map(|v| v.as_str()).collect::<Vec<_>>())
366 .unwrap_or(vec!["h1", "h2"]);
367
368 if enable_proxy_protocol && protocols.contains(&"h3") {
369 Err(anyhow::anyhow!("PROXY protocol isn't supported with HTTP/3"))?
370 }
371
372 let default_http_port = global_configuration
373 .as_deref()
374 .and_then(|c| get_entry!("default_http_port", c))
375 .and_then(|e| e.values.first())
376 .map_or(Some(80), |v| {
377 if v.is_null() {
378 None
379 } else {
380 Some(v.as_i128().unwrap_or(80) as u16)
381 }
382 });
383 let default_https_port = global_configuration
384 .as_deref()
385 .and_then(|c| get_entry!("default_https_port", c))
386 .and_then(|e| e.values.first())
387 .map_or(Some(443), |v| {
388 if v.is_null() {
389 None
390 } else {
391 Some(v.as_i128().unwrap_or(443) as u16)
392 }
393 });
394
395 let mut tls_ports: HashMap<u16, CustomSniResolver> = HashMap::new();
396 #[allow(clippy::type_complexity)]
397 let mut tls_port_locks: HashMap<u16, Arc<tokio::sync::RwLock<Vec<(String, Arc<dyn ResolvesServerCert>)>>>> =
398 HashMap::new();
399 let mut nonencrypted_ports = HashSet::new();
400 let mut certified_keys_to_preload: HashMap<u16, Vec<Arc<CertifiedKey>>> = HashMap::new();
401 let mut used_sni_hostnames = HashSet::new();
402 let mut automatic_tls_used_sni_hostnames = HashSet::new();
403 let mut acme_tls_alpn_01_resolvers: HashMap<u16, TlsAlpn01Resolver> = HashMap::new();
404 let mut acme_tls_alpn_01_resolver_locks: HashMap<
405 u16,
406 Arc<tokio::sync::RwLock<Vec<crate::acme::TlsAlpn01DataLock>>>,
407 > = HashMap::new();
408 let acme_http_01_resolvers: Arc<tokio::sync::RwLock<Vec<crate::acme::Http01DataLock>>> =
409 Arc::new(tokio::sync::RwLock::new(Vec::new()));
410 let acme_default_directory = dirs::data_local_dir().and_then(|mut p| {
411 p.push("ferron-acme");
412 p.into_os_string().into_string().ok()
413 });
414 let memory_acme_account_cache_data = Arc::new(tokio::sync::RwLock::new(HashMap::new()));
415 let mut acme_configs = Vec::new();
416 let mut acme_on_demand_configs = Vec::new();
417 let (acme_on_demand_tx, acme_on_demand_rx) = async_channel::unbounded();
418 let on_demand_tls_ask_endpoint = match global_configuration
419 .as_ref()
420 .and_then(|c| get_value!("auto_tls_on_demand_ask", c))
421 .and_then(|v| v.as_str())
422 .map(|u| u.parse::<hyper::Uri>())
423 {
424 Some(Ok(uri)) => Some(uri),
425 Some(Err(err)) => Err(anyhow::anyhow!(
426 "Failed to parse automatic TLS on demand asking endpoint URI: {}",
427 err
428 ))?,
429 None => None,
430 };
431 let on_demand_tls_ask_endpoint_verify = !global_configuration
432 .as_ref()
433 .and_then(|c| get_value!("auto_tls_on_demand_ask_no_verification", c))
434 .and_then(|v| v.as_bool())
435 .unwrap_or(false);
436
437 for server_configuration in &server_configurations.inner {
439 if server_configuration.filters.is_global_non_host()
440 || (server_configuration.filters.is_global() && server_configuration.entries.is_empty())
441 {
442 continue;
444 }
445
446 let on_demand_tls = get_value!("auto_tls_on_demand", server_configuration)
447 .and_then(|v| v.as_bool())
448 .unwrap_or(false);
449
450 let https_port = server_configuration.filters.port.or(default_https_port);
451
452 let sni_hostname = server_configuration.filters.hostname.clone().or_else(|| {
453 match server_configuration.filters.ip {
455 Some(IpAddr::V4(address)) => Some(address.to_string()),
456 Some(IpAddr::V6(address)) => Some(format!("[{address}]")),
457 _ => None,
458 }
459 });
460
461 let is_sni_hostname_used = !https_port.is_none_or(|p| {
462 !used_sni_hostnames.contains(&(p, sni_hostname.clone()))
463 && !automatic_tls_used_sni_hostnames.contains(&(p, sni_hostname.clone()))
464 });
465 let is_auto_tls_sni_hostname_used =
466 https_port.is_some_and(|p| automatic_tls_used_sni_hostnames.contains(&(p, sni_hostname.clone())));
467
468 let mut automatic_tls_port = None;
469 if server_configuration.filters.port.is_none() {
470 if get_value!("auto_tls", server_configuration)
471 .and_then(|v| v.as_bool())
472 .unwrap_or(!is_localhost(
473 server_configuration.filters.ip.as_ref(),
474 server_configuration.filters.hostname.as_deref(),
475 ))
476 {
477 automatic_tls_port = default_https_port;
478 }
479 if let Some(http_port) = default_http_port {
480 nonencrypted_ports.insert(http_port);
481 }
482 }
483
484 if get_value!("auto_tls", server_configuration)
485 .and_then(|v| v.as_bool())
486 .unwrap_or(false)
487 {
488 automatic_tls_port = https_port;
489 } else if let Some(tls_entry) = get_entry!("tls", server_configuration) {
490 if let Some(https_port) = https_port {
491 if tls_entry.values.len() == 2 {
492 if let Some(cert_path) = tls_entry.values[0].as_str() {
493 if let Some(key_path) = tls_entry.values[1].as_str() {
494 automatic_tls_port = None;
495
496 if !is_sni_hostname_used {
497 let certs = match load_certs(cert_path) {
498 Ok(certs) => certs,
499 Err(err) => Err(anyhow::anyhow!(
500 "Cannot load the \"{}\" TLS certificate: {}",
501 cert_path,
502 err
503 ))?,
504 };
505 let key = match load_private_key(key_path) {
506 Ok(key) => key,
507 Err(err) => Err(anyhow::anyhow!("Cannot load the \"{}\" private key: {}", key_path, err))?,
508 };
509 let signing_key = match crypto_provider.key_provider.load_private_key(key) {
510 Ok(key) => key,
511 Err(err) => Err(anyhow::anyhow!("Cannot load the \"{}\" private key: {}", key_path, err))?,
512 };
513 let certified_key = Arc::new(CertifiedKey::new(certs, signing_key));
514 if let Some(certified_keys) = certified_keys_to_preload.get_mut(&https_port) {
515 certified_keys.push(certified_key.clone());
516 } else {
517 certified_keys_to_preload.insert(https_port, vec![certified_key.clone()]);
518 }
519 let resolver = Arc::new(OneCertifiedKeyResolver::new(certified_key));
520 if let Some(sni_resolver) = tls_ports.get_mut(&https_port) {
521 if let Some(sni_hostname) = &sni_hostname {
522 sni_resolver.load_host_resolver(sni_hostname, resolver);
523 } else {
524 sni_resolver.load_fallback_resolver(resolver);
525 }
526 } else {
527 let sni_resolver_list = Arc::new(tokio::sync::RwLock::new(Vec::new()));
528 tls_port_locks.insert(https_port, sni_resolver_list.clone());
529 let mut sni_resolver = CustomSniResolver::with_resolvers(sni_resolver_list);
530 if let Some(sni_hostname) = &sni_hostname {
531 sni_resolver.load_host_resolver(sni_hostname, resolver);
532 } else {
533 sni_resolver.load_fallback_resolver(resolver);
534 }
535 tls_ports.insert(https_port, sni_resolver);
536 }
537 used_sni_hostnames.insert((https_port, sni_hostname.clone()));
538 }
539 }
540 }
541 }
542 }
543 } else if let Some(http_port) = server_configuration.filters.port.or(default_http_port) {
544 nonencrypted_ports.insert(http_port);
545 }
546 if let Some(automatic_tls_port) = automatic_tls_port {
547 if !is_auto_tls_sni_hostname_used {
548 if sni_hostname.is_some() || on_demand_tls {
549 let is_wildcard_domain = sni_hostname.as_ref().is_some_and(|s| s.starts_with("*."));
550 let challenge_type_entry = get_entry!("auto_tls_challenge", server_configuration);
551 let challenge_type_str = challenge_type_entry
552 .and_then(|e| e.values.first())
553 .and_then(|v| v.as_str())
554 .unwrap_or("tls-alpn-01");
555 let challenge_params = challenge_type_entry
556 .and_then(|e| {
557 let mut props_str = HashMap::new();
558 for (prop_name, prop_value) in e.props.iter() {
559 if let Some(prop_value) = prop_value.as_str() {
560 props_str.insert(prop_name.to_string(), prop_value.to_string());
561 }
562 }
563 if props_str.is_empty() {
564 None
565 } else {
566 Some(props_str)
567 }
568 })
569 .unwrap_or(HashMap::new());
570 if let Some(sni_hostname) = &sni_hostname {
571 if sni_hostname.parse::<IpAddr>().is_ok() {
572 for logging_tx in global_configuration
573 .as_ref()
574 .map_or(&vec![], |c| &c.observability.log_channels)
575 {
576 logging_tx
577 .send_blocking(LogMessage::new(
578 format!("Ferron's automatic TLS functionality doesn't support IP address-based identifiers, skipping SNI host \"{sni_hostname}\"..."),
579 true,
580 ))
581 .unwrap_or_default();
582 }
583 continue;
584 }
585 }
586 let challenge_type = match &*challenge_type_str.to_uppercase() {
587 "HTTP-01" => {
588 if let Some(sni_hostname) = &sni_hostname {
589 if is_wildcard_domain && !on_demand_tls {
590 for logging_tx in global_configuration
591 .as_ref()
592 .map_or(&vec![], |c| &c.observability.log_channels)
593 {
594 logging_tx
595 .send_blocking(LogMessage::new(
596 format!("HTTP-01 ACME challenge doesn't support wildcard hostnames, skipping SNI host \"{sni_hostname}\"..."),
597 true,
598 ))
599 .unwrap_or_default();
600 }
601 continue;
602 }
603 }
604 ChallengeType::Http01
605 }
606 "TLS-ALPN-01" => {
607 if let Some(sni_hostname) = &sni_hostname {
608 if is_wildcard_domain && !on_demand_tls {
609 for logging_tx in global_configuration
610 .as_ref()
611 .map_or(&vec![], |c| &c.observability.log_channels)
612 {
613 logging_tx
614 .send_blocking(LogMessage::new(
615 format!("TLS-ALPN-01 ACME challenge doesn't support wildcard hostnames, skipping SNI host \"{sni_hostname}\"..."),
616 true,
617 ))
618 .unwrap_or_default();
619 }
620 continue;
621 }
622 }
623 ChallengeType::TlsAlpn01
624 }
625 "DNS-01" => ChallengeType::Dns01,
626 unsupported => Err(anyhow::anyhow!("Unsupported ACME challenge type: {}", unsupported))?,
627 };
628 let dns_provider: Option<Arc<dyn ferron_common::dns::DnsProvider + Send + Sync>> =
629 if &*challenge_type_str.to_uppercase() != "DNS-01" {
630 None
631 } else {
632 let provider_name = challenge_params
633 .get("provider")
634 .ok_or(anyhow::anyhow!("No DNS provider specified"))?;
635 Some(get_dns_provider(provider_name, &challenge_params)?)
636 };
637 let acme_cache_path_option = get_value!("auto_tls_cache", server_configuration)
638 .map_or(acme_default_directory.as_deref(), |v| {
639 if v.is_null() {
640 None
641 } else if let Some(v) = v.as_str() {
642 Some(v)
643 } else {
644 acme_default_directory.as_deref()
645 }
646 })
647 .map(|path| path.to_owned());
648 let rustls_client_config = (if get_value!("auto_tls_no_verification", server_configuration)
649 .and_then(|v| v.as_bool())
650 .unwrap_or(false)
651 {
652 ClientConfig::builder_with_provider(crypto_provider.clone())
653 .with_safe_default_protocol_versions()?
654 .dangerous()
655 .with_custom_certificate_verifier(Arc::new(NoServerVerifier::new()))
656 } else if let Ok(client_config) = BuilderVerifierExt::with_platform_verifier(
657 ClientConfig::builder_with_provider(crypto_provider.clone()).with_safe_default_protocol_versions()?,
658 ) {
659 client_config
660 } else {
661 ClientConfig::builder_with_provider(crypto_provider.clone())
662 .with_safe_default_protocol_versions()?
663 .with_webpki_verifier(
664 WebPkiServerVerifier::builder(Arc::new(rustls::RootCertStore {
665 roots: webpki_roots::TLS_SERVER_ROOTS.to_vec(),
666 }))
667 .build()?,
668 )
669 })
670 .with_no_client_auth();
671 if on_demand_tls {
672 if &*challenge_type_str.to_uppercase() == "TLS-ALPN-01" {
673 let sni_resolver_list = Arc::new(tokio::sync::RwLock::new(Vec::new()));
675 acme_tls_alpn_01_resolver_locks.insert(automatic_tls_port, sni_resolver_list.clone());
676 let sni_resolver = TlsAlpn01Resolver::with_resolvers(sni_resolver_list);
677 acme_tls_alpn_01_resolvers.insert(automatic_tls_port, sni_resolver);
678 }
679
680 if let Some(sni_resolver) = tls_ports.get_mut(&automatic_tls_port) {
681 sni_resolver.load_fallback_sender(acme_on_demand_tx.clone(), automatic_tls_port);
682 } else {
683 let sni_resolver_list = Arc::new(tokio::sync::RwLock::new(Vec::new()));
684 tls_port_locks.insert(automatic_tls_port, sni_resolver_list.clone());
685 let mut sni_resolver = CustomSniResolver::with_resolvers(sni_resolver_list);
686 sni_resolver.load_fallback_sender(acme_on_demand_tx.clone(), automatic_tls_port);
687 tls_ports.insert(automatic_tls_port, sni_resolver);
688 }
689
690 let acme_on_demand_config = AcmeOnDemandConfig {
691 rustls_client_config,
692 challenge_type,
693 contact: if let Some(contact) =
694 get_value!("auto_tls_contact", server_configuration).and_then(|v| v.as_str())
695 {
696 vec![format!("mailto:{}", contact.to_string())]
697 } else {
698 vec![]
699 },
700 directory: if let Some(directory) =
701 get_value!("auto_tls_directory", server_configuration).and_then(|v| v.as_str())
702 {
703 directory.to_string()
704 } else if get_value!("auto_tls_letsencrypt_production", server_configuration)
705 .and_then(|v| v.as_bool())
706 .unwrap_or(true)
707 {
708 LetsEncrypt::Production.url().to_string()
709 } else {
710 LetsEncrypt::Staging.url().to_string()
711 },
712 eab_key: if let Some(eab_key_entry) = get_entry!("auto_tls_eab", server_configuration) {
713 if let Some(eab_key_id) = eab_key_entry.values.first().and_then(|v| v.as_str()) {
714 if let Some(eab_key_hmac) = eab_key_entry.values.get(1).and_then(|v| v.as_str()) {
715 match base64::engine::general_purpose::URL_SAFE_NO_PAD
716 .decode(eab_key_hmac.trim_end_matches('='))
717 {
718 Ok(decoded_key) => {
719 Some(Arc::new(ExternalAccountKey::new(eab_key_id.to_string(), &decoded_key)))
720 }
721 Err(err) => Err(anyhow::anyhow!("Failed to decode EAB key HMAC: {}", err))?,
722 }
723 } else {
724 None
725 }
726 } else {
727 None
728 }
729 } else {
730 None
731 },
732 profile: get_value!("auto_tls_profile", server_configuration)
733 .and_then(|v| v.as_str().map(|s| s.to_string())),
734 cache_path: if let Some(acme_cache_path) = acme_cache_path_option.as_ref() {
735 Some(PathBuf::from_str(acme_cache_path).map_err(|_| anyhow::anyhow!("Invalid ACME cache path"))?)
736 } else {
737 None
738 },
739 sni_resolver_lock: tls_port_locks
740 .get(&automatic_tls_port)
741 .cloned()
742 .unwrap_or(Arc::new(tokio::sync::RwLock::new(Vec::new()))),
743 tls_alpn_01_resolver_lock: acme_tls_alpn_01_resolver_locks
744 .get(&automatic_tls_port)
745 .cloned()
746 .unwrap_or(Arc::new(tokio::sync::RwLock::new(Vec::new()))),
747 http_01_resolver_lock: acme_http_01_resolvers.clone(),
748 dns_provider,
749 sni_hostname: sni_hostname.clone(),
750 port: automatic_tls_port,
751 };
752 acme_on_demand_configs.push(acme_on_demand_config);
753 automatic_tls_used_sni_hostnames.insert((automatic_tls_port, sni_hostname));
754 } else if let Some(sni_hostname) = sni_hostname {
755 let (account_cache_path, cert_cache_path) =
756 if let Some(acme_cache_path) = acme_cache_path_option.as_deref() {
757 let mut pathbuf =
758 PathBuf::from_str(acme_cache_path).map_err(|_| anyhow::anyhow!("Invalid ACME cache path"))?;
759 let base_pathbuf = pathbuf.clone();
760 let append_hash = base64::engine::general_purpose::URL_SAFE_NO_PAD
761 .encode(xxh3_128(format!("{automatic_tls_port}-{sni_hostname}").as_bytes()).to_be_bytes());
762 pathbuf.push(append_hash);
763 (Some(base_pathbuf), Some(pathbuf))
764 } else {
765 (None, None)
766 };
767 let certified_key_lock = Arc::new(tokio::sync::RwLock::new(None));
768 let tls_alpn_01_data_lock = Arc::new(tokio::sync::RwLock::new(None));
769 let http_01_data_lock = Arc::new(tokio::sync::RwLock::new(None));
770 let acme_config = AcmeConfig {
771 rustls_client_config,
772 domains: vec![sni_hostname.clone()],
773 challenge_type,
774 contact: if let Some(contact) =
775 get_value!("auto_tls_contact", server_configuration).and_then(|v| v.as_str())
776 {
777 vec![format!("mailto:{}", contact.to_string())]
778 } else {
779 vec![]
780 },
781 directory: if let Some(directory) =
782 get_value!("auto_tls_directory", server_configuration).and_then(|v| v.as_str())
783 {
784 directory.to_string()
785 } else if get_value!("auto_tls_letsencrypt_production", server_configuration)
786 .and_then(|v| v.as_bool())
787 .unwrap_or(true)
788 {
789 LetsEncrypt::Production.url().to_string()
790 } else {
791 LetsEncrypt::Staging.url().to_string()
792 },
793 eab_key: if let Some(eab_key_entry) = get_entry!("auto_tls_eab", server_configuration) {
794 if let Some(eab_key_id) = eab_key_entry.values.first().and_then(|v| v.as_str()) {
795 if let Some(eab_key_hmac) = eab_key_entry.values.get(1).and_then(|v| v.as_str()) {
796 Some(Arc::new(ExternalAccountKey::new(
797 eab_key_id.to_string(),
798 &base64::engine::general_purpose::URL_SAFE_NO_PAD
799 .decode(eab_key_hmac.trim_end_matches('='))
800 .map_err(|err| anyhow::anyhow!("Failed to decode EAB key HMAC: {}", err))?,
801 )))
802 } else {
803 None
804 }
805 } else {
806 None
807 }
808 } else {
809 None
810 },
811 profile: get_value!("auto_tls_profile", server_configuration)
812 .and_then(|v| v.as_str().map(|s| s.to_string())),
813 account_cache: if let Some(account_cache_path) = account_cache_path {
814 AcmeCache::File(account_cache_path)
815 } else {
816 AcmeCache::Memory(memory_acme_account_cache_data.clone())
817 },
818 certificate_cache: if let Some(cert_cache_path) = cert_cache_path {
819 AcmeCache::File(cert_cache_path)
820 } else {
821 AcmeCache::Memory(Arc::new(tokio::sync::RwLock::new(HashMap::new())))
822 },
823 certified_key_lock: certified_key_lock.clone(),
824 tls_alpn_01_data_lock: tls_alpn_01_data_lock.clone(),
825 http_01_data_lock: http_01_data_lock.clone(),
826 dns_provider,
827 renewal_info: None,
828 account: None,
829 };
830 let acme_resolver = Arc::new(AcmeResolver::new(certified_key_lock));
831 acme_configs.push(acme_config);
832 match &*challenge_type_str.to_uppercase() {
833 "HTTP-01" => {
834 acme_http_01_resolvers.blocking_write().push(http_01_data_lock);
835 }
836 "TLS-ALPN-01" => {
837 if let Some(sni_resolver) = acme_tls_alpn_01_resolvers.get_mut(&automatic_tls_port) {
838 sni_resolver.load_resolver(tls_alpn_01_data_lock);
839 } else {
840 let sni_resolver_list = Arc::new(tokio::sync::RwLock::new(Vec::new()));
841 acme_tls_alpn_01_resolver_locks.insert(automatic_tls_port, sni_resolver_list.clone());
842 let sni_resolver = TlsAlpn01Resolver::with_resolvers(sni_resolver_list);
843 sni_resolver.load_resolver(tls_alpn_01_data_lock);
844 acme_tls_alpn_01_resolvers.insert(automatic_tls_port, sni_resolver);
845 }
846 }
847 _ => (),
848 }
849 if let Some(sni_resolver) = tls_ports.get_mut(&automatic_tls_port) {
850 sni_resolver.load_host_resolver(&sni_hostname, acme_resolver);
851 } else {
852 let sni_resolver_list = Arc::new(tokio::sync::RwLock::new(Vec::new()));
853 tls_port_locks.insert(automatic_tls_port, sni_resolver_list.clone());
854 let mut sni_resolver = CustomSniResolver::with_resolvers(sni_resolver_list);
855 sni_resolver.load_host_resolver(&sni_hostname, acme_resolver);
856 tls_ports.insert(automatic_tls_port, sni_resolver);
857 }
858 automatic_tls_used_sni_hostnames.insert((automatic_tls_port, Some(sni_hostname)));
859 }
860 } else if !server_configuration.filters.is_global() && !server_configuration.filters.is_global_non_host() {
861 for logging_tx in global_configuration
862 .as_ref()
863 .map_or(&vec![], |c| &c.observability.log_channels)
864 {
865 logging_tx
866 .send_blocking(LogMessage::new(
867 "Skipping automatic TLS for a host without a SNI hostname...".to_string(),
868 true,
869 ))
870 .unwrap_or_default();
871 }
872 }
873 }
874 }
875 }
876
877 if let Some((handler_shutdown_channels, secondary_runtime)) = old_runtime_ref.take() {
879 for shutdown in handler_shutdown_channels {
880 shutdown.cancel();
881 }
882 drop(secondary_runtime);
883 }
884
885 if !acme_configs.is_empty() || !acme_on_demand_configs.is_empty() {
886 let global_configuration_clone = global_configuration.clone();
889 secondary_runtime_ref.spawn(async move {
890 for acme_config in &mut acme_configs {
891 check_certificate_validity_or_install_cached(acme_config, None)
893 .await
894 .unwrap_or_default();
895 }
896
897 let mut existing_combinations = HashSet::new();
898 for acme_on_demand_config in &mut acme_on_demand_configs {
899 for cached_domain in get_cached_domains(acme_on_demand_config).await {
900 let mut acme_config = convert_on_demand_config(
901 acme_on_demand_config,
902 cached_domain.clone(),
903 memory_acme_account_cache_data.clone(),
904 )
905 .await;
906
907 existing_combinations.insert((cached_domain, acme_on_demand_config.port));
908
909 check_certificate_validity_or_install_cached(&mut acme_config, None)
911 .await
912 .unwrap_or_default();
913
914 acme_configs.push(acme_config);
915 }
916 }
917
918 let acme_configs_mutex = Arc::new(tokio::sync::Mutex::new(acme_configs));
920
921 let prevent_file_race_conditions_mutex = Arc::new(tokio::sync::Mutex::new(()));
922
923 if !acme_on_demand_configs.is_empty() {
924 let acme_configs_mutex = acme_configs_mutex.clone();
926 let acme_on_demand_configs = Arc::new(acme_on_demand_configs);
927 let global_configuration_clone = global_configuration_clone.clone();
928 tokio::spawn(async move {
929 let mut existing_combinations = existing_combinations;
930 while let Ok(received_data) = acme_on_demand_rx.recv().await {
931 let on_demand_tls_ask_endpoint = on_demand_tls_ask_endpoint.clone();
932 if let Some(on_demand_tls_ask_endpoint) = on_demand_tls_ask_endpoint {
933 let mut url_parts = on_demand_tls_ask_endpoint.into_parts();
934 if let Some(path_and_query) = url_parts.path_and_query {
935 let query = path_and_query.query();
936 let query = if let Some(query) = query {
937 format!("{}&domain={}", query, urlencoding::encode(&received_data.0))
938 } else {
939 format!("domain={}", urlencoding::encode(&received_data.0))
940 };
941 url_parts.path_and_query = Some(match format!("{}?{}", path_and_query.path(), query).parse() {
942 Ok(parsed) => parsed,
943 Err(err) => {
944 for acme_logger in global_configuration_clone
945 .as_ref()
946 .map_or(&vec![], |c| &c.observability.log_channels)
947 {
948 acme_logger
949 .send(LogMessage::new(
950 format!("Error while formatting the URL for on-demand TLS request: {err}"),
951 true,
952 ))
953 .await
954 .unwrap_or_default();
955 }
956 continue;
957 }
958 });
959 } else {
960 url_parts.path_and_query = Some(
961 match format!("/?domain={}", urlencoding::encode(&received_data.0)).parse() {
962 Ok(parsed) => parsed,
963 Err(err) => {
964 for acme_logger in global_configuration_clone
965 .as_ref()
966 .map_or(&vec![], |c| &c.observability.log_channels)
967 {
968 acme_logger
969 .send(LogMessage::new(
970 format!("Error while formatting the URL for on-demand TLS request: {err}"),
971 true,
972 ))
973 .await
974 .unwrap_or_default();
975 }
976 continue;
977 }
978 },
979 );
980 }
981 let endpoint_url = match hyper::Uri::from_parts(url_parts) {
982 Ok(parsed) => parsed,
983 Err(err) => {
984 for acme_logger in global_configuration_clone
985 .as_ref()
986 .map_or(&vec![], |c| &c.observability.log_channels)
987 {
988 acme_logger
989 .send(LogMessage::new(
990 format!("Error while formatting the URL for on-demand TLS request: {err}"),
991 true,
992 ))
993 .await
994 .unwrap_or_default();
995 }
996 continue;
997 }
998 };
999 let ask_closure = async {
1000 let client = hyper_util::client::legacy::Client::builder(hyper_util::rt::TokioExecutor::new())
1001 .build::<_, http_body_util::Empty<hyper::body::Bytes>>(
1002 hyper_rustls::HttpsConnectorBuilder::new()
1003 .with_tls_config(
1004 (if !on_demand_tls_ask_endpoint_verify {
1005 ClientConfig::builder_with_provider(crypto_provider.clone())
1006 .with_safe_default_protocol_versions()?
1007 .dangerous()
1008 .with_custom_certificate_verifier(Arc::new(NoServerVerifier::new()))
1009 } else if let Ok(client_config) = BuilderVerifierExt::with_platform_verifier(
1010 ClientConfig::builder_with_provider(crypto_provider.clone())
1011 .with_safe_default_protocol_versions()?,
1012 ) {
1013 client_config
1014 } else {
1015 ClientConfig::builder_with_provider(crypto_provider.clone())
1016 .with_safe_default_protocol_versions()?
1017 .with_webpki_verifier(
1018 WebPkiServerVerifier::builder(Arc::new(rustls::RootCertStore {
1019 roots: webpki_roots::TLS_SERVER_ROOTS.to_vec(),
1020 }))
1021 .build()?,
1022 )
1023 })
1024 .with_no_client_auth(),
1025 )
1026 .https_or_http()
1027 .enable_http1()
1028 .enable_http2()
1029 .build(),
1030 );
1031 let request = hyper::Request::builder()
1032 .method(hyper::Method::GET)
1033 .uri(endpoint_url)
1034 .body(http_body_util::Empty::<hyper::body::Bytes>::new())?;
1035 let response = client.request(request).await?;
1036
1037 Ok::<_, Box<dyn Error + Send + Sync>>(response.status().is_success())
1038 };
1039 match ask_closure.await {
1040 Ok(true) => (),
1041 Ok(false) => {
1042 for acme_logger in global_configuration_clone
1043 .as_ref()
1044 .map_or(&vec![], |c| &c.observability.log_channels)
1045 {
1046 acme_logger
1047 .send(LogMessage::new(
1048 format!(
1049 "The TLS certificate cannot be issued for \"{}\" hostname",
1050 &received_data.0
1051 ),
1052 true,
1053 ))
1054 .await
1055 .unwrap_or_default();
1056 }
1057 continue;
1058 }
1059 Err(err) => {
1060 for acme_logger in global_configuration_clone
1061 .as_ref()
1062 .map_or(&vec![], |c| &c.observability.log_channels)
1063 {
1064 acme_logger
1065 .send(LogMessage::new(
1066 format!(
1067 "Error while determining if the TLS certificate can be issued for \"{}\" hostname: {err}",
1068 &received_data.0
1069 ),
1070 true,
1071 ))
1072 .await
1073 .unwrap_or_default();
1074 }
1075 continue;
1076 }
1077 }
1078 }
1079 if existing_combinations.contains(&received_data) {
1080 continue;
1081 } else {
1082 existing_combinations.insert(received_data.clone());
1083 }
1084 let (sni_hostname, port) = received_data;
1085 let acme_configs_mutex = acme_configs_mutex.clone();
1086 let acme_on_demand_configs = acme_on_demand_configs.clone();
1087 let memory_acme_account_cache_data = memory_acme_account_cache_data.clone();
1088 let prevent_file_race_conditions_mutex = prevent_file_race_conditions_mutex.clone();
1089 tokio::spawn(async move {
1090 for acme_on_demand_config in acme_on_demand_configs.iter() {
1091 if match_hostname(acme_on_demand_config.sni_hostname.as_deref(), Some(&sni_hostname))
1092 && acme_on_demand_config.port == port
1093 {
1094 let mutex_guard = prevent_file_race_conditions_mutex.lock().await;
1095 add_domain_to_cache(acme_on_demand_config, &sni_hostname)
1096 .await
1097 .unwrap_or_default();
1098 drop(mutex_guard);
1099
1100 acme_configs_mutex.lock().await.push(
1101 convert_on_demand_config(
1102 acme_on_demand_config,
1103 sni_hostname.clone(),
1104 memory_acme_account_cache_data,
1105 )
1106 .await,
1107 );
1108 break;
1109 }
1110 }
1111 });
1112 }
1113 });
1114 }
1115
1116 let error_logger = ErrorLogger::new_multiple(
1117 global_configuration_clone
1118 .as_ref()
1119 .map_or(vec![], |c| c.observability.log_channels.clone()),
1120 );
1121 loop {
1122 for acme_config in &mut *acme_configs_mutex.lock().await {
1123 if let Err(acme_error) = provision_certificate(acme_config, &error_logger).await {
1124 error_logger
1125 .log(&format!("Error while obtaining a TLS certificate: {acme_error}"))
1126 .await
1127 }
1128 }
1129 tokio::time::sleep(Duration::from_secs(10)).await;
1130 }
1131 });
1132 }
1133
1134 if !protocols.contains(&"h1") {
1136 nonencrypted_ports.clear();
1137 }
1138
1139 for tls_port in tls_ports.keys() {
1140 if nonencrypted_ports.contains(tls_port) {
1141 nonencrypted_ports.remove(tls_port);
1142 }
1143 }
1144
1145 let mut quic_tls_configs = HashMap::new();
1147 let mut tls_configs = HashMap::new();
1148 let mut acme_tls_alpn_01_configs = HashMap::new();
1149 for (tls_port, sni_resolver) in tls_ports.into_iter() {
1150 let enable_ocsp_stapling = global_configuration
1151 .as_ref()
1152 .and_then(|c| get_value!("ocsp_stapling", c))
1153 .and_then(|v| v.as_bool())
1154 .unwrap_or(true);
1155 let resolver: Arc<dyn ResolvesServerCert> = if enable_ocsp_stapling {
1156 let stapler =
1159 secondary_runtime_ref.block_on(async move { ocsp_stapler::Stapler::new(Arc::new(sni_resolver)) });
1160 if let Some(certified_keys_to_preload) = certified_keys_to_preload.get(&tls_port) {
1161 for certified_key in certified_keys_to_preload {
1162 stapler.preload(certified_key.clone());
1163 }
1164 }
1165 Arc::new(stapler)
1166 } else {
1167 Arc::new(sni_resolver)
1168 };
1169 let mut tls_config = tls_config_builder_wants_server_cert
1170 .clone()
1171 .with_cert_resolver(resolver);
1172 if protocols.contains(&"h3") {
1173 let mut quic_tls_config = tls_config.clone();
1175 quic_tls_config.max_early_data_size = u32::MAX;
1176 quic_tls_config.alpn_protocols.insert(0, b"h3-29".to_vec());
1177 quic_tls_config.alpn_protocols.insert(0, b"h3".to_vec());
1178 quic_tls_configs.insert(tls_port, Arc::new(quic_tls_config));
1179 }
1180 if protocols.contains(&"h1") {
1181 tls_config.alpn_protocols.insert(0, b"http/1.0".to_vec());
1182 tls_config.alpn_protocols.insert(0, b"http/1.1".to_vec());
1183 }
1184 if protocols.contains(&"h2") {
1185 tls_config.alpn_protocols.insert(0, b"h2".to_vec());
1186 }
1187 tls_configs.insert(tls_port, Arc::new(tls_config));
1188 }
1189 for (tls_port, sni_resolver) in acme_tls_alpn_01_resolvers.into_iter() {
1190 let mut tls_config = tls_config_builder_wants_server_cert
1191 .clone()
1192 .with_cert_resolver(Arc::new(sni_resolver));
1193 tls_config.alpn_protocols = vec![ACME_TLS_ALPN_NAME.to_vec()];
1194 acme_tls_alpn_01_configs.insert(tls_port, Arc::new(tls_config));
1195 }
1196
1197 #[cfg(any(target_os = "linux", target_os = "android"))]
1199 if let Some(metrics_channels) = global_configuration
1200 .as_ref()
1201 .map(|c| &c.observability.metric_channels)
1202 .cloned()
1203 {
1204 secondary_runtime_ref.spawn(async move {
1205 use ferron_common::observability::{Metric, MetricAttributeValue, MetricType, MetricValue};
1206
1207 let mut previous_instant = std::time::Instant::now();
1208 let mut previous_cpu_user_time = 0.0;
1209 let mut previous_cpu_system_time = 0.0;
1210 let mut previous_rss = 0;
1211 let mut previous_vms = 0;
1212 loop {
1213 tokio::time::sleep(Duration::from_secs(1)).await;
1215
1216 if let Ok(Ok(stat)) =
1217 tokio::task::spawn_blocking(|| procfs::process::Process::myself().and_then(|p| p.stat())).await
1218 {
1219 let cpu_user_time = stat.utime as f64 / procfs::ticks_per_second() as f64;
1220 let cpu_system_time = stat.stime as f64 / procfs::ticks_per_second() as f64;
1221 let cpu_user_time_increase = cpu_user_time - previous_cpu_user_time;
1222 let cpu_system_time_increase = cpu_system_time - previous_cpu_system_time;
1223 previous_cpu_user_time = cpu_user_time;
1224 previous_cpu_system_time = cpu_system_time;
1225
1226 let rss = stat.rss * procfs::page_size();
1227 let rss_diff = rss as i64 - previous_rss as i64;
1228 let vms_diff = stat.vsize as i64 - previous_vms as i64;
1229 previous_rss = rss;
1230 previous_vms = stat.vsize;
1231
1232 let elapsed = previous_instant.elapsed().as_secs_f64();
1233 previous_instant = std::time::Instant::now();
1234
1235 let cpu_user_utilization = cpu_user_time_increase / (elapsed * available_parallelism as f64);
1236 let cpu_system_utilization = cpu_system_time_increase / (elapsed * available_parallelism as f64);
1237
1238 for metrics_sender in &metrics_channels {
1239 metrics_sender
1240 .send(Metric::new(
1241 "process.cpu.time",
1242 vec![("cpu.mode", MetricAttributeValue::String("user".to_string()))],
1243 MetricType::Counter,
1244 MetricValue::F64(cpu_user_time_increase),
1245 Some("s"),
1246 Some("Total CPU seconds broken down by different states."),
1247 ))
1248 .await
1249 .unwrap_or_default();
1250
1251 metrics_sender
1252 .send(Metric::new(
1253 "process.cpu.time",
1254 vec![("cpu.mode", MetricAttributeValue::String("system".to_string()))],
1255 MetricType::Counter,
1256 MetricValue::F64(cpu_system_time_increase),
1257 Some("s"),
1258 Some("Total CPU seconds broken down by different states."),
1259 ))
1260 .await
1261 .unwrap_or_default();
1262
1263 metrics_sender
1264 .send(Metric::new(
1265 "process.cpu.utilization",
1266 vec![("cpu.mode", MetricAttributeValue::String("user".to_string()))],
1267 MetricType::Gauge,
1268 MetricValue::F64(cpu_user_utilization),
1269 Some("1"),
1270 Some(
1271 "Difference in process.cpu.time since the last measurement, \
1272 divided by the elapsed time and number of CPUs available to the process.",
1273 ),
1274 ))
1275 .await
1276 .unwrap_or_default();
1277
1278 metrics_sender
1279 .send(Metric::new(
1280 "process.cpu.utilization",
1281 vec![("cpu.mode", MetricAttributeValue::String("system".to_string()))],
1282 MetricType::Gauge,
1283 MetricValue::F64(cpu_system_utilization),
1284 Some("1"),
1285 Some(
1286 "Difference in process.cpu.time since the last measurement, \
1287 divided by the elapsed time and number of CPUs available to the process.",
1288 ),
1289 ))
1290 .await
1291 .unwrap_or_default();
1292
1293 metrics_sender
1294 .send(Metric::new(
1295 "process.memory.usage",
1296 vec![],
1297 MetricType::UpDownCounter,
1298 MetricValue::I64(rss_diff),
1299 Some("By"),
1300 Some("The amount of physical memory in use."),
1301 ))
1302 .await
1303 .unwrap_or_default();
1304
1305 metrics_sender
1306 .send(Metric::new(
1307 "process.memory.virtual",
1308 vec![],
1309 MetricType::UpDownCounter,
1310 MetricValue::I64(vms_diff),
1311 Some("By"),
1312 Some("The amount of committed virtual memory."),
1313 ))
1314 .await
1315 .unwrap_or_default();
1316 }
1317 }
1318 }
1319 });
1320 }
1321
1322 let (listener_handler_tx, listener_handler_rx) = &**LISTENER_HANDLER_CHANNEL;
1323 let mut tcp_listeners = TCP_LISTENERS
1324 .lock()
1325 .map_err(|_| anyhow::anyhow!("Can't access the TCP listeners"))?;
1326 let mut quic_listeners = QUIC_LISTENERS
1327 .lock()
1328 .map_err(|_| anyhow::anyhow!("Can't access the QUIC listeners"))?;
1329 let mut listened_socket_addresses = Vec::new();
1330 let mut quic_listened_socket_addresses = Vec::new();
1331 let listen_ip_addr = global_configuration
1332 .as_deref()
1333 .and_then(|c| get_value!("listen_ip", c))
1334 .and_then(|v| v.as_str())
1335 .map_or(Ok(IpAddr::V6(Ipv6Addr::UNSPECIFIED)), |a| a.parse())
1336 .map_err(|_| anyhow::anyhow!("Invalid IP address to listen to"))?;
1337 for (tcp_port, encrypted) in nonencrypted_ports
1338 .iter()
1339 .map(|p| (*p, false))
1340 .chain(tls_configs.keys().map(|p| (*p, true)))
1341 {
1342 let socket_address = SocketAddr::new(listen_ip_addr, tcp_port);
1343 listened_socket_addresses.push((socket_address, encrypted));
1344 }
1345 for (quic_port, quic_tls_config) in quic_tls_configs.into_iter() {
1346 let socket_address = SocketAddr::new(listen_ip_addr, quic_port);
1347 quic_listened_socket_addresses.push((socket_address, quic_tls_config));
1348 }
1349
1350 let enable_uring = global_configuration
1351 .as_deref()
1352 .and_then(|c| get_value!("io_uring", c))
1353 .and_then(|v| v.as_bool())
1354 .unwrap_or(true);
1355 let mut uring_enabled_locked = URING_ENABLED
1356 .lock()
1357 .map_err(|_| anyhow::anyhow!("Can't access the enabled `io_uring` option"))?;
1358 let mut tcp_listener_socketaddrs_to_remove = Vec::new();
1359 let mut quic_listener_socketaddrs_to_remove = Vec::new();
1360 for (key, value) in &*tcp_listeners {
1361 if enable_uring != *uring_enabled_locked
1362 || (!listened_socket_addresses.contains(&(*key, true)) && !listened_socket_addresses.contains(&(*key, false)))
1363 {
1364 value.cancel();
1366
1367 tcp_listener_socketaddrs_to_remove.push(*key);
1369 }
1370 }
1371 for (key, value) in &*quic_listeners {
1372 let mut contains = false;
1373 for key2 in &quic_listened_socket_addresses {
1374 if key2.0 == *key {
1375 contains = true;
1376 break;
1377 }
1378 }
1379 if !contains {
1380 value.0.cancel();
1382
1383 quic_listener_socketaddrs_to_remove.push(*key);
1385 }
1386 }
1387 *uring_enabled_locked = enable_uring;
1388 drop(uring_enabled_locked);
1389
1390 for key_to_remove in tcp_listener_socketaddrs_to_remove {
1391 tcp_listeners.remove(&key_to_remove);
1393 }
1394
1395 for key_to_remove in quic_listener_socketaddrs_to_remove {
1396 quic_listeners.remove(&key_to_remove);
1398 }
1399
1400 let (global_logging_tx, global_logging_rx) = &**LISTENER_LOGGING_CHANNEL;
1402 let global_logger = if global_configuration
1403 .as_ref()
1404 .is_none_or(|c| c.observability.log_channels.is_empty())
1405 {
1406 None
1407 } else {
1408 let global_configuration_clone = global_configuration.clone();
1409 secondary_runtime_ref.spawn(async move {
1410 while let Ok(log_message) = global_logging_rx.recv().await {
1411 for logging_tx in global_configuration_clone
1412 .as_ref()
1413 .map_or(&vec![], |c| &c.observability.log_channels)
1414 {
1415 logging_tx.send(log_message.clone()).await.unwrap_or_default();
1416 }
1417 }
1418 });
1419 Some(global_logging_tx.clone())
1420 };
1421
1422 let mut handler_shutdown_channels = Vec::new();
1424 for _ in 0..available_parallelism {
1425 handler_shutdown_channels.push(create_http_handler(
1426 server_configurations.clone(),
1427 listener_handler_rx.clone(),
1428 enable_uring,
1429 tls_configs.clone(),
1430 !quic_listened_socket_addresses.is_empty(),
1431 acme_tls_alpn_01_configs.clone(),
1432 acme_http_01_resolvers.clone(),
1433 enable_proxy_protocol,
1434 )?);
1435 }
1436
1437 if listened_socket_addresses.is_empty() && quic_listened_socket_addresses.is_empty() {
1439 Err(anyhow::anyhow!("The server is configured to listen to no port"))?
1440 }
1441
1442 let tcp_send_buffer_size = global_configuration
1443 .as_deref()
1444 .and_then(|c| get_value!("tcp_send_buffer", c))
1445 .and_then(|v| v.as_i128())
1446 .map(|v| v as usize);
1447 let tcp_recv_buffer_size = global_configuration
1448 .as_deref()
1449 .and_then(|c| get_value!("tcp_recv_buffer", c))
1450 .and_then(|v| v.as_i128())
1451 .map(|v| v as usize);
1452 for (socket_address, encrypted) in listened_socket_addresses {
1453 if let std::collections::hash_map::Entry::Vacant(e) = tcp_listeners.entry(socket_address) {
1454 e.insert(create_tcp_listener(
1456 socket_address,
1457 encrypted,
1458 listener_handler_tx.clone(),
1459 enable_uring,
1460 global_logger.clone(),
1461 first_startup,
1462 (tcp_send_buffer_size, tcp_recv_buffer_size),
1463 )?);
1464 }
1465 }
1466
1467 drop(tcp_listeners);
1469
1470 for (socket_address, tls_config) in quic_listened_socket_addresses {
1471 if let Some(quic_listener_entry) = quic_listeners.get(&socket_address) {
1472 let (_, tls_quic_listener) = quic_listener_entry;
1474 tls_quic_listener.send_blocking(tls_config).unwrap_or_default();
1475 } else {
1476 quic_listeners.insert(
1478 socket_address,
1479 create_quic_listener(
1480 socket_address,
1481 tls_config,
1482 listener_handler_tx.clone(),
1483 global_logger.clone(),
1484 first_startup,
1485 )?,
1486 );
1487 }
1488 }
1489
1490 drop(quic_listeners);
1492
1493 let shutdown_result = handle_shutdown_signals(secondary_runtime_ref);
1494
1495 Ok::<_, Box<dyn Error + Send + Sync>>((shutdown_result, handler_shutdown_channels))
1496 };
1497
1498 match execute_rest() {
1499 Ok((to_restart, handler_shutdown_channels)) => {
1500 if to_restart {
1501 old_runtime = Some((handler_shutdown_channels, secondary_runtime));
1502 first_startup = false;
1503 println!("Reloading the server configuration...");
1504 } else {
1505 for shutdown in handler_shutdown_channels {
1506 shutdown.cancel();
1507 }
1508 drop(secondary_runtime);
1509 break;
1510 }
1511 }
1512 Err(err) => {
1513 for logging_tx in global_configuration_clone
1514 .as_ref()
1515 .map_or(&vec![], |c| &c.observability.log_channels)
1516 {
1517 logging_tx
1518 .send_blocking(LogMessage::new(err.to_string(), true))
1519 .unwrap_or_default();
1520 }
1521 std::thread::sleep(Duration::from_millis(100));
1522 Err(err)?
1523 }
1524 }
1525 }
1526 Ok(())
1527}
1528
1529fn obtain_configuration_adapters() -> (
1530 HashMap<String, Box<dyn ConfigurationAdapter + Send + Sync>>,
1531 Vec<&'static str>,
1532) {
1533 let mut configuration_adapters: HashMap<String, Box<dyn ConfigurationAdapter + Send + Sync>> = HashMap::new();
1535 let mut all_adapters = Vec::new();
1536
1537 macro_rules! register_configuration_adapter {
1539 ($name:literal, $adapter:expr) => {
1540 configuration_adapters.insert($name.to_string(), Box::new($adapter));
1541 all_adapters.push($name);
1542 };
1543 }
1544
1545 register_configuration_adapter!("kdl", config::adapters::kdl::KdlConfigurationAdapter::new());
1547 #[cfg(feature = "config-yaml-legacy")]
1548 register_configuration_adapter!(
1549 "yaml-legacy",
1550 config::adapters::yaml_legacy::YamlLegacyConfigurationAdapter::new()
1551 );
1552 #[cfg(feature = "config-docker-auto")]
1553 register_configuration_adapter!(
1554 "docker-auto",
1555 config::adapters::docker_auto::DockerAutoConfigurationAdapter::new()
1556 );
1557
1558 (configuration_adapters, all_adapters)
1559}
1560
1561#[cfg(feature = "config-yaml-legacy")]
1563fn determine_default_configuration_adapter(path: &Path) -> &'static str {
1564 match path
1565 .extension()
1566 .and_then(|s| s.to_str())
1567 .map(|s| s.to_lowercase())
1568 .as_deref()
1569 {
1570 Some("yaml") | Some("yml") => "yaml-legacy",
1571 _ => "kdl",
1572 }
1573}
1574
1575#[cfg(not(feature = "config-yaml-legacy"))]
1577fn determine_default_configuration_adapter(_path: &Path) -> &'static str {
1578 "kdl"
1579}
1580
1581fn parse_arguments(all_adapters: Vec<&'static str>) -> ArgMatches {
1583 Command::new("Ferron")
1584 .about("A fast, memory-safe web server written in Rust")
1585 .arg(
1586 Arg::new("config")
1587 .long("config")
1588 .short('c')
1589 .help("The path to the server configuration file")
1590 .action(ArgAction::Set)
1591 .default_value("./ferron.kdl")
1592 .value_parser(PathBuf::from_str),
1593 )
1594 .arg(
1595 Arg::new("config-adapter")
1596 .long("config-adapter")
1597 .help("The configuration adapter to use")
1598 .action(ArgAction::Set)
1599 .required(false)
1600 .value_parser(all_adapters),
1601 )
1602 .arg(
1603 Arg::new("module-config")
1604 .long("module-config")
1605 .help("Prints the used compile-time module configuration (`ferron-build.yaml` or `ferron-build-override.yaml` in the Ferron source) and exits")
1606 .action(ArgAction::SetTrue)
1607 )
1608 .arg(
1609 Arg::new("version")
1610 .long("version")
1611 .short('V')
1612 .help("Print version and build information")
1613 .action(ArgAction::SetTrue)
1614 )
1615 .get_matches()
1616}
1617
1618fn main() {
1620 setup_panic!(Metadata::new("Ferron", env!("CARGO_PKG_VERSION"))
1622 .homepage("https://ferron.sh")
1623 .support("- Send an email message to hello@ferron.sh"));
1624
1625 let (configuration_adapters, all_adapters) = obtain_configuration_adapters();
1627
1628 let args = parse_arguments(all_adapters);
1630
1631 if args.get_flag("module-config") {
1632 println!("{}", ferron_load_modules::FERRON_BUILD_YAML);
1634 return;
1635 } else if args.get_flag("version") {
1636 println!("Ferron {}", build::PKG_VERSION);
1638 println!(" Compiled on: {}", build::BUILD_TIME);
1639 println!(" Git commit: {}", build::COMMIT_HASH);
1640 println!(" Build target: {}", build::BUILD_TARGET);
1641 println!(" Rust version: {}", build::RUST_VERSION);
1642 println!(" Build host: {}", build::BUILD_OS);
1643 if shadow_rs::is_debug() {
1644 println!("WARNING: This is a debug build. It is not recommended for production use.");
1645 }
1646 return;
1647 }
1648
1649 match before_starting_server(args, configuration_adapters) {
1651 Ok(_) => (),
1652 Err(err) => {
1653 eprintln!("Error while running a server: {err}");
1654 std::process::exit(1);
1655 }
1656 };
1657}