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