From c651bea903c89673682959a2d89ebdf3c9a3d30c Mon Sep 17 00:00:00 2001 From: houseme Date: Sun, 13 Apr 2025 12:55:56 +0800 Subject: [PATCH] Fix/fix domain server (#319) * fix: server_domain and improve code for tls * add log * add tracing * test * improve config and tls * Update rustfs/src/console.rs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- deploy/certs/README.md | 10 +---- rustfs/src/config/mod.rs | 24 +++++------ rustfs/src/console.rs | 92 +++++++++++++++++++++++++--------------- rustfs/src/main.rs | 1 + scripts/run.sh | 2 + 5 files changed, 74 insertions(+), 55 deletions(-) diff --git a/deploy/certs/README.md b/deploy/certs/README.md index ce3dbe75..84b733e7 100644 --- a/deploy/certs/README.md +++ b/deploy/certs/README.md @@ -32,13 +32,7 @@ openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -node ### TLS File ```text + rustfs_public.crt #api cert.pem - rustfs_tls_cert.pem api cert.pem - - rustfs_tls_key.pem api key.pem - - rustfs_console_tls_cert.pem console cert.pem - - rustfs_console_tls_key.pem console key.pem - + rustfs_private.key #api key.pem ``` \ No newline at end of file diff --git a/rustfs/src/config/mod.rs b/rustfs/src/config/mod.rs index 54dbc8d0..f53bc095 100644 --- a/rustfs/src/config/mod.rs +++ b/rustfs/src/config/mod.rs @@ -29,11 +29,11 @@ pub const DEFAULT_OBS_CONFIG: &str = "config/obs.toml"; /// Default TLS key for rustfs /// This is the default key for TLS. -pub(crate) const RUSTFS_TLS_KEY: &str = "rustfs_tls_key.pem"; +pub(crate) const RUSTFS_TLS_KEY: &str = "rustfs_private.key"; /// Default TLS cert for rustfs /// This is the default cert for TLS. -pub(crate) const RUSTFS_TLS_CERT: &str = "rustfs_tls_cert.pem"; +pub(crate) const RUSTFS_TLS_CERT: &str = "rustfs_public.crt"; #[allow(clippy::const_is_empty)] const SHORT_VERSION: &str = { @@ -47,16 +47,16 @@ const SHORT_VERSION: &str = { }; const LONG_VERSION: &str = concat!( - concat!(SHORT_VERSION, "\n"), - concat!("build time : ", build::BUILD_TIME, "\n"), - concat!("build profile: ", build::BUILD_RUST_CHANNEL, "\n"), - concat!("build os : ", build::BUILD_OS, "\n"), - concat!("rust version : ", build::RUST_VERSION, "\n"), - concat!("rust channel : ", build::RUST_CHANNEL, "\n"), - concat!("git branch : ", build::BRANCH, "\n"), - concat!("git commit : ", build::COMMIT_HASH, "\n"), - concat!("git tag : ", build::TAG, "\n"), - concat!("git status :\n", build::GIT_STATUS_FILE), +concat!(SHORT_VERSION, "\n"), +concat!("build time : ", build::BUILD_TIME, "\n"), +concat!("build profile: ", build::BUILD_RUST_CHANNEL, "\n"), +concat!("build os : ", build::BUILD_OS, "\n"), +concat!("rust version : ", build::RUST_VERSION, "\n"), +concat!("rust channel : ", build::RUST_CHANNEL, "\n"), +concat!("git branch : ", build::BRANCH, "\n"), +concat!("git commit : ", build::COMMIT_HASH, "\n"), +concat!("git tag : ", build::TAG, "\n"), +concat!("git status :\n", build::GIT_STATUS_FILE), ); #[derive(Debug, Parser, Clone)] diff --git a/rustfs/src/console.rs b/rustfs/src/console.rs index 1eff0e90..8ed25f57 100644 --- a/rustfs/src/console.rs +++ b/rustfs/src/console.rs @@ -1,3 +1,4 @@ +use crate::config::{RUSTFS_TLS_CERT, RUSTFS_TLS_KEY}; use crate::license::get_license; use axum::{ body::Body, @@ -16,15 +17,12 @@ use std::net::{Ipv4Addr, SocketAddr, ToSocketAddrs}; use std::sync::OnceLock; use std::time::Duration; use tokio::signal; -use tracing::{debug, error, info}; +use tracing::{debug, error, info, instrument}; shadow!(build); const RUSTFS_ADMIN_PREFIX: &str = "/rustfs/admin/v3"; -const RUSTFS_CONSOLE_TLS_KEY: &str = "rustfs_console_tls_key.pem"; -const RUSTFS_CONSOLE_TLS_CERT: &str = "rustfs_console_tls_cert.pem"; - #[derive(RustEmbed)] #[folder = "$CARGO_MANIFEST_DIR/static"] struct StaticFiles; @@ -169,32 +167,56 @@ async fn license_handler() -> impl IntoResponse { .unwrap() } +fn is_private_ip(ip: std::net::IpAddr) -> bool { + match ip { + std::net::IpAddr::V4(ip) => { + let octets = ip.octets(); + // 10.0.0.0/8 + octets[0] == 10 || + // 172.16.0.0/12 + (octets[0] == 172 && (octets[1] >= 16 && octets[1] <= 31)) || + // 192.168.0.0/16 + (octets[0] == 192 && octets[1] == 168) + } + std::net::IpAddr::V6(_) => false, + } +} + #[allow(clippy::const_is_empty)] +#[instrument(fields(host))] async fn config_handler(Host(host): Host) -> impl IntoResponse { - let host_with_port = if host.contains(':') { host } else { format!("{}:80", host) }; - - let is_addr = host_with_port - .to_socket_addrs() - .map(|addrs| { - addrs.into_iter().find(|v| { - if let SocketAddr::V4(ipv4) = v { - !ipv4.ip().is_private() && !ipv4.ip().is_loopback() && !ipv4.ip().is_unspecified() - } else { - false - } - }) - }) - .unwrap_or_default(); - - let mut cfg = CONSOLE_CONFIG.get().unwrap().clone(); - - let url = if let Some(addr) = is_addr { - format!("http://{}:{}", addr.ip(), cfg.port) + let host_with_port = if host.contains(':') { + host.clone() } else { - let (host, _) = host_with_port.split_once(':').unwrap_or_default(); - format!("http://{}:{}", host, cfg.port) + format!("{}:80", host) }; + // 将当前配置复制一份 + let mut cfg = CONSOLE_CONFIG.get().unwrap().clone(); + + // 尝试解析为 socket address,但不强制要求一定要是 IP 地址 + let socket_addr = host_with_port.to_socket_addrs().ok().and_then(|mut addrs| addrs.next()); + debug!("axum Using host with port: {}, Socket address: {:?}", host_with_port, socket_addr); + let url = match socket_addr { + Some(addr) if addr.ip().is_ipv4() => { + let ipv4 = addr.ip().to_string(); + // 如果是私有 IP、环回地址或未指定地址,保留原始域名 + if is_private_ip(addr.ip()) || addr.ip().is_loopback() || addr.ip().is_unspecified() { + let (host, _) = host_with_port.split_once(':').unwrap_or((&host, "80")); + debug!("axum Using private IPv4 address: {}", host); + format!("http://{}:{}", host, cfg.port) + } else { + debug!("axum Using public IPv4 address"); + format!("http://{}:{}", ipv4, cfg.port) + } + } + _ => { + // 如果不是有效的 IPv4 地址,保留原始域名 + let (host, _) = host_with_port.split_once(':').unwrap_or((&host, "80")); + debug!("axum Using domain address: {}", host); + format!("http://{}:{}", host, cfg.port) + } + }; cfg.api.base_url = format!("{}{}", url, RUSTFS_ADMIN_PREFIX); cfg.s3.endpoint = url; @@ -222,21 +244,21 @@ pub async fn start_static_file_server( info!(" RootUser: {}", access_key); info!(" RootPass: {}", secret_key); - let tls_path = tls_path.unwrap_or_default(); - let key_path = format!("{}/{}", tls_path, RUSTFS_CONSOLE_TLS_KEY); - let cert_path = format!("{}/{}", tls_path, RUSTFS_CONSOLE_TLS_CERT); // Check and start the HTTPS/HTTP server - match start_server(addrs, local_addr, &key_path, &cert_path, app.clone()).await { + match start_server(addrs, local_addr, tls_path, app.clone()).await { Ok(_) => info!("Server shutdown gracefully"), Err(e) => error!("Server error: {}", e), } } -async fn start_server(addrs: &str, local_addr: SocketAddr, key_path: &str, cert_path: &str, app: Router) -> std::io::Result<()> { - let has_tls_certs = tokio::try_join!(tokio::fs::metadata(key_path), tokio::fs::metadata(cert_path)).is_ok(); - +async fn start_server(addrs: &str, local_addr: SocketAddr, tls_path: Option, app: Router) -> std::io::Result<()> { + let tls_path = tls_path.unwrap_or_default(); + let key_path = format!("{}/{}", tls_path, RUSTFS_TLS_KEY); + let cert_path = format!("{}/{}", tls_path, RUSTFS_TLS_CERT); + let has_tls_certs = tokio::try_join!(tokio::fs::metadata(&key_path), tokio::fs::metadata(&cert_path)).is_ok(); + debug!("Console TLS certs: {:?}", has_tls_certs); if has_tls_certs { debug!("Found TLS certificates, starting with HTTPS"); - match tokio::try_join!(tokio::fs::read(key_path), tokio::fs::read(cert_path)) { + match tokio::try_join!(tokio::fs::read(&key_path), tokio::fs::read(&cert_path)) { Ok((key_data, cert_data)) => { match RustlsConfig::from_pem(cert_data, key_data).await { Ok(config) => { @@ -247,7 +269,7 @@ async fn start_server(addrs: &str, local_addr: SocketAddr, key_path: &str, cert_ shutdown_signal().await; handle_clone.graceful_shutdown(Some(Duration::from_secs(10))); }); - debug!("Starting HTTPS server..."); + info!("Starting HTTPS server..."); axum_server::bind_rustls(local_addr, config) .handle(handle.clone()) .serve(app.into_make_service()) @@ -275,7 +297,7 @@ async fn start_server(addrs: &str, local_addr: SocketAddr, key_path: &str, cert_ async fn start_http_server(addrs: &str, app: Router) -> std::io::Result<()> { debug!("Starting HTTP server..."); - let listener = tokio::net::TcpListener::bind(addrs).await.unwrap(); + let listener = tokio::net::TcpListener::bind(addrs).await?; axum::serve(listener, app) .with_graceful_shutdown(shutdown_signal()) .await diff --git a/rustfs/src/main.rs b/rustfs/src/main.rs index c0ca3499..d3f89994 100644 --- a/rustfs/src/main.rs +++ b/rustfs/src/main.rs @@ -226,6 +226,7 @@ async fn run(opt: config::Opt) -> Result<()> { let key_path = format!("{}/{}", tls_path, RUSTFS_TLS_KEY); let cert_path = format!("{}/{}", tls_path, RUSTFS_TLS_CERT); let has_tls_certs = tokio::try_join!(tokio::fs::metadata(key_path.clone()), tokio::fs::metadata(cert_path.clone())).is_ok(); + debug!("Main TLS certs: {:?}", has_tls_certs); let tls_acceptor = if has_tls_certs { debug!("Found TLS certificates, starting with HTTPS"); let _ = rustls::crypto::aws_lc_rs::default_provider().install_default(); diff --git a/scripts/run.sh b/scripts/run.sh index b2cb5c80..61f82aa8 100755 --- a/scripts/run.sh +++ b/scripts/run.sh @@ -32,6 +32,8 @@ export RUSTFS_ADDRESS="0.0.0.0:9000" export RUSTFS_CONSOLE_ENABLE=true export RUSTFS_CONSOLE_ADDRESS="0.0.0.0:9002" # export RUSTFS_SERVER_DOMAINS="localhost:9000" +# HTTPS 证书目录 +# export RUSTFS_TLS_PATH="./deploy/certs" # 具体路径修改为配置文件真实路径,obs.example.toml 仅供参考 其中`RUSTFS_OBS_CONFIG` 和下面变量二选一 export RUSTFS_OBS_CONFIG="./deploy/config/obs.example.toml"