From 1a4736d40bcd5aa26d86e3d66cd64ec1bdcd055e Mon Sep 17 00:00:00 2001 From: Jason Volk Date: Sun, 2 Jun 2024 22:36:00 +0000 Subject: [PATCH] support configuring multiple bind hosts; default to dual localhost. Signed-off-by: Jason Volk --- src/core/config/check.rs | 69 +++++++++++++++++++--------------------- src/core/config/mod.rs | 52 +++++++++++++++++++----------- 2 files changed, 67 insertions(+), 54 deletions(-) diff --git a/src/core/config/check.rs b/src/core/config/check.rs index a631c4f8..403aa27c 100644 --- a/src/core/config/check.rs +++ b/src/core/config/check.rs @@ -27,46 +27,43 @@ pub fn check(config: &Config) -> Result<(), Error> { )); } - if config.address.is_loopback() && cfg!(unix) { - debug!( - "Found loopback listening address {}, running checks if we're in a container.", - config.address - ); + config.get_bind_addrs().iter().for_each(|addr| { + if addr.ip().is_loopback() && cfg!(unix) { + debug!("Found loopback listening address {addr}, running checks if we're in a container.",); - #[cfg(unix)] - if Path::new("/proc/vz").exists() /* Guest */ && !Path::new("/proc/bz").exists() - /* Host */ - { - error!( - "You are detected using OpenVZ with a loopback/localhost listening address of {}. If you are using \ - OpenVZ for containers and you use NAT-based networking to communicate with the host and guest, this \ - will NOT work. Please change this to \"0.0.0.0\". If this is expected, you can ignore.", - config.address - ); - } + #[cfg(unix)] + if Path::new("/proc/vz").exists() /* Guest */ && !Path::new("/proc/bz").exists() + /* Host */ + { + error!( + "You are detected using OpenVZ with a loopback/localhost listening address of {addr}. If you are \ + using OpenVZ for containers and you use NAT-based networking to communicate with the host and \ + guest, this will NOT work. Please change this to \"0.0.0.0\". If this is expected, you can \ + ignore.", + ); + } - #[cfg(unix)] - if Path::new("/.dockerenv").exists() { - error!( - "You are detected using Docker with a loopback/localhost listening address of {}. If you are using a \ - reverse proxy on the host and require communication to conduwuit in the Docker container via \ - NAT-based networking, this will NOT work. Please change this to \"0.0.0.0\". If this is expected, \ - you can ignore.", - config.address - ); - } + #[cfg(unix)] + if Path::new("/.dockerenv").exists() { + error!( + "You are detected using Docker with a loopback/localhost listening address of {addr}. If you are \ + using a reverse proxy on the host and require communication to conduwuit in the Docker container \ + via NAT-based networking, this will NOT work. Please change this to \"0.0.0.0\". If this is \ + expected, you can ignore.", + ); + } - #[cfg(unix)] - if Path::new("/run/.containerenv").exists() { - error!( - "You are detected using Podman with a loopback/localhost listening address of {}. If you are using a \ - reverse proxy on the host and require communication to conduwuit in the Podman container via \ - NAT-based networking, this will NOT work. Please change this to \"0.0.0.0\". If this is expected, \ - you can ignore.", - config.address - ); + #[cfg(unix)] + if Path::new("/run/.containerenv").exists() { + error!( + "You are detected using Podman with a loopback/localhost listening address of {addr}. If you are \ + using a reverse proxy on the host and require communication to conduwuit in the Podman container \ + via NAT-based networking, this will NOT work. Please change this to \"0.0.0.0\". If this is \ + expected, you can ignore.", + ); + } } - } + }); // rocksdb does not allow max_log_files to be 0 if config.rocksdb_max_log_files == 0 && cfg!(feature = "rocksdb") { diff --git a/src/core/config/mod.rs b/src/core/config/mod.rs index bb13923b..67b83975 100644 --- a/src/core/config/mod.rs +++ b/src/core/config/mod.rs @@ -1,7 +1,7 @@ use std::{ collections::BTreeMap, fmt::{self, Write as _}, - net::{IpAddr, Ipv6Addr, SocketAddr}, + net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}, path::PathBuf, }; @@ -36,13 +36,20 @@ struct ListeningPort { ports: Either>, } +#[derive(Deserialize, Clone, Debug)] +#[serde(transparent)] +struct ListeningAddr { + #[serde(with = "either::serde_untagged")] + addrs: Either>, +} + /// all the config options for conduwuit #[derive(Clone, Debug, Deserialize)] #[allow(clippy::struct_excessive_bools)] pub struct Config { /// [`IpAddr`] conduwuit will listen on (can be IPv4 or IPv6) #[serde(default = "default_address")] - pub address: IpAddr, + address: ListeningAddr, /// default TCP port(s) conduwuit will listen on #[serde(default = "default_port")] port: ListeningPort, @@ -471,22 +478,27 @@ impl Config { #[must_use] pub fn get_bind_addrs(&self) -> Vec { - match &self.port.ports { - Left(port) => { - // Left is only 1 value, so make a vec with 1 value only - let port_vec = [port]; + let mut addrs = Vec::new(); + for host in &self.get_bind_hosts() { + for port in &self.get_bind_ports() { + addrs.push(SocketAddr::new(*host, *port)); + } + } - port_vec - .iter() - .copied() - .map(|port| SocketAddr::from((self.address, *port))) - .collect::>() - }, - Right(ports) => ports - .iter() - .copied() - .map(|port| SocketAddr::from((self.address, port))) - .collect::>(), + addrs + } + + fn get_bind_hosts(&self) -> Vec { + match &self.address.addrs { + Left(addr) => vec![*addr], + Right(addrs) => addrs.clone(), + } + } + + fn get_bind_ports(&self) -> Vec { + match &self.port.ports { + Left(port) => vec![*port], + Right(ports) => ports.clone(), } } @@ -875,7 +887,11 @@ impl fmt::Display for Config { fn true_fn() -> bool { true } -fn default_address() -> IpAddr { Ipv6Addr::LOCALHOST.into() } +fn default_address() -> ListeningAddr { + ListeningAddr { + addrs: Right(vec![Ipv4Addr::LOCALHOST.into(), Ipv6Addr::LOCALHOST.into()]), + } +} fn default_port() -> ListeningPort { ListeningPort {