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