From 9556579de0fd9fdcf871a84b9ed9c01c410243ac Mon Sep 17 00:00:00 2001 From: Johann150 Date: Thu, 14 Oct 2021 23:10:04 +0200 Subject: [PATCH] try to detect dual stack address in use error If multiple unspecified addresses are used, issue a warning if listening to it after the first time fails because the system probably already listens in dual stack mode. Assumes that IPv6 and IPv4 are used. If such addresses are passed in manually, thats the admins problem for setting up something stupid in case it goes wrong. --- src/main.rs | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/src/main.rs b/src/main.rs index a2868d9..3e4b2fa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,7 +16,7 @@ use { fmt::Write, fs::{self, File}, io::Write as _, - net::SocketAddr, + net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}, path::{self, Component, Path, PathBuf}, sync::Arc, }, @@ -46,12 +46,28 @@ fn main() { ); let mimetypes = Arc::new(Mutex::new(FileOptions::new(default))); + // some systems automatically listen in dual stack if the IPv6 unspecified + // address is used, so don't fail if the second unspecified address gets + // an error when trying to start + let mut listening_unspecified = false; + let handles = ARGS.addrs.iter().map(|addr| { let arc = mimetypes.clone(); - tokio::spawn(async move { - let listener = TcpListener::bind(addr) - .await - .unwrap_or_else(|e| panic!("Failed to listen on {}: {}", addr, e)); + let was_listening_unspecified = listening_unspecified; + let handle = tokio::spawn(async move { + let listener = match TcpListener::bind(addr).await { + Err(e) => { + if !(addr.ip().is_unspecified() && was_listening_unspecified) { + panic!("Failed to listen on {}: {}", addr, e) + } else { + // already listening on the other unspecified address + log::warn!("Could not start listener on {}, but already listening on another unspecified address. Probably your system automatically listens in dual stack?", addr); + return; + } + } + Ok(listener) => listener, + }; + log::info!("Started listener on {}", addr); loop { let (stream, _) = listener.accept().await.unwrap_or_else(|e| { @@ -70,7 +86,9 @@ fn main() { } }); } - }) + }); + listening_unspecified |= addr.ip().is_unspecified(); + handle }); futures_util::future::join_all(handles).await; @@ -268,8 +286,8 @@ fn args() -> Result { } if addrs.is_empty() { addrs = vec![ - "[::]:1965".parse().unwrap(), - "0.0.0.0:1965".parse().unwrap(), + SocketAddr::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), 1965), + SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 1965), ]; }